I1620: Separated compare from add/sub flows (Tom McBride) Removed ADD_SIGNC return from add/sub flows. From Bob Supnik - Fix #172
The FP is "collateral damage" from simplifying the add_field routine. This version runs CU01 without the record mark test.
This commit is contained in:
parent
569cfaf591
commit
6bf32c0687
2 changed files with 97 additions and 39 deletions
|
@ -1,6 +1,6 @@
|
||||||
/* i1620_cpu.c: IBM 1620 CPU simulator
|
/* i1620_cpu.c: IBM 1620 CPU simulator
|
||||||
|
|
||||||
Copyright (c) 2002-2013, Robert M. Supnik
|
Copyright (c) 2002-2015, Robert M. Supnik
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -26,6 +26,8 @@
|
||||||
This CPU module incorporates code and comments from the 1620 simulator by
|
This CPU module incorporates code and comments from the 1620 simulator by
|
||||||
Geoff Kuenning, with his permission.
|
Geoff Kuenning, with his permission.
|
||||||
|
|
||||||
|
26-Mar-15 RMS Separated compare from add/sub flows (Tom McBride)
|
||||||
|
Removed ADD_SIGNC return from add/sub flows
|
||||||
10-Dec-13 RMS Fixed several bugs in add and compare (Bob Armstrong)
|
10-Dec-13 RMS Fixed several bugs in add and compare (Bob Armstrong)
|
||||||
Fixed handling of P field in K instruction (Bob Armstrong)
|
Fixed handling of P field in K instruction (Bob Armstrong)
|
||||||
28-May-06 RMS Fixed bug in cpu history (Peter Schorn)
|
28-May-06 RMS Fixed bug in cpu history (Peter Schorn)
|
||||||
|
@ -155,7 +157,8 @@ t_stat xmt_index (uint32 d, uint32 s);
|
||||||
t_stat xmt_divd (uint32 d, uint32 s);
|
t_stat xmt_divd (uint32 d, uint32 s);
|
||||||
t_stat xmt_tns (uint32 d, uint32 s);
|
t_stat xmt_tns (uint32 d, uint32 s);
|
||||||
t_stat xmt_tnf (uint32 d, uint32 s);
|
t_stat xmt_tnf (uint32 d, uint32 s);
|
||||||
t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta);
|
t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta);
|
||||||
|
t_stat cmp_field (uint32 d, uint32 s);
|
||||||
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry);
|
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry);
|
||||||
t_stat mul_field (uint32 mpc, uint32 mpy);
|
t_stat mul_field (uint32 mpc, uint32 mpy);
|
||||||
t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last);
|
t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last);
|
||||||
|
@ -688,7 +691,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
|
|
||||||
case OP_A:
|
case OP_A:
|
||||||
case OP_AM:
|
case OP_AM:
|
||||||
reason = add_field (PAR, QAR, FALSE, TRUE, 0, &sta); /* add, store */
|
reason = add_field (PAR, QAR, FALSE, 0, &sta); /* add */
|
||||||
if (sta == ADD_CARRY) /* cout => ovflo */
|
if (sta == ADD_CARRY) /* cout => ovflo */
|
||||||
ind[IN_OVF] = 1;
|
ind[IN_OVF] = 1;
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
|
@ -697,7 +700,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
|
|
||||||
case OP_S:
|
case OP_S:
|
||||||
case OP_SM:
|
case OP_SM:
|
||||||
reason = add_field (PAR, QAR, TRUE, TRUE, 0, &sta); /* sub, store */
|
reason = add_field (PAR, QAR, TRUE, 0, &sta); /* sub, store */
|
||||||
if (sta == ADD_CARRY) /* cout => ovflo */
|
if (sta == ADD_CARRY) /* cout => ovflo */
|
||||||
ind[IN_OVF] = 1;
|
ind[IN_OVF] = 1;
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
|
@ -709,7 +712,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
|
|
||||||
case OP_C:
|
case OP_C:
|
||||||
case OP_CM:
|
case OP_CM:
|
||||||
reason = add_field (PAR, QAR, TRUE, FALSE, 0, &sta); /* sub, nostore */
|
reason = cmp_field (PAR, QAR); /* compare */
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
reason = STOP_OVERFL;
|
reason = STOP_OVERFL;
|
||||||
break;
|
break;
|
||||||
|
@ -849,7 +852,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
reason = STOP_INVIDX; /* stop */
|
reason = STOP_INVIDX; /* stop */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 0, &sta);
|
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 0, &sta);
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
reason = STOP_OVERFL;
|
reason = STOP_OVERFL;
|
||||||
BRANCH (PAR); /* branch to P */
|
BRANCH (PAR); /* branch to P */
|
||||||
|
@ -861,7 +864,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
reason = STOP_INVIDX; /* stop */
|
reason = STOP_INVIDX; /* stop */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 3, &sta);
|
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 3, &sta);
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
reason = STOP_OVERFL;
|
reason = STOP_OVERFL;
|
||||||
BRANCH (PAR); /* branch to P */
|
BRANCH (PAR); /* branch to P */
|
||||||
|
@ -875,7 +878,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
reason = STOP_INVIDX; /* stop */
|
reason = STOP_INVIDX; /* stop */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 0, &sta);
|
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 0, &sta);
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
reason = STOP_OVERFL;
|
reason = STOP_OVERFL;
|
||||||
if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */
|
if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */
|
||||||
|
@ -889,7 +892,7 @@ while (reason == 0) { /* loop until halted */
|
||||||
reason = STOP_INVIDX; /* stop */
|
reason = STOP_INVIDX; /* stop */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, 3, &sta);
|
reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 3, &sta);
|
||||||
if (ar_stop && ind[IN_OVF])
|
if (ar_stop && ind[IN_OVF])
|
||||||
reason = STOP_OVERFL;
|
reason = STOP_OVERFL;
|
||||||
if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */
|
if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */
|
||||||
|
@ -1323,18 +1326,17 @@ return SCPE_OK;
|
||||||
Output:
|
Output:
|
||||||
return = status
|
return = status
|
||||||
sta = ADD_NOCRY: no carry out, no sign change
|
sta = ADD_NOCRY: no carry out, no sign change
|
||||||
ADD_SCHNG: sign change
|
ADD_SIGNC: sign change
|
||||||
ADD_CARRY: carry out
|
ADD_CARRY: carry out
|
||||||
|
|
||||||
Reference Manual: "When the sum is zero, the sign of the P field
|
Reference Manual: "When the sum is zero, the sign of the P field
|
||||||
is retained."
|
is retained."
|
||||||
|
*/
|
||||||
|
|
||||||
Bob Armstrong: record marks are treated by add as though they were zero */
|
t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta)
|
||||||
|
|
||||||
t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta)
|
|
||||||
{
|
{
|
||||||
uint32 cry, src, dst, res, comp, dp, dsv;
|
uint32 cry, src, dst, res, comp, dp, dsv;
|
||||||
uint32 src_f = 0, cnt = 0, dst_f;
|
uint32 src_f = 0, cnt = 0, dst_f = 0;
|
||||||
|
|
||||||
*sta = ADD_NOCRY; /* assume no cry */
|
*sta = ADD_NOCRY; /* assume no cry */
|
||||||
dsv = d; /* save dst */
|
dsv = d; /* save dst */
|
||||||
|
@ -1345,29 +1347,20 @@ ind[IN_EZ] = 1; /* assume zero */
|
||||||
|
|
||||||
dst = M[d] & DIGIT; /* 1st digits */
|
dst = M[d] & DIGIT; /* 1st digits */
|
||||||
src = M[s] & DIGIT;
|
src = M[s] & DIGIT;
|
||||||
if (dst == REC_MARK) /* chk for rec mark */
|
|
||||||
dst = 0;
|
|
||||||
if (src == REC_MARK)
|
|
||||||
src = 0;
|
|
||||||
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
|
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
|
||||||
return STOP_INVDIG;
|
return STOP_INVDIG;
|
||||||
if (comp) /* complement? */
|
if (comp) /* complement? */
|
||||||
src = 10 - src;
|
src = 10 - src;
|
||||||
res = add_one_digit (dst, src, &cry); /* add */
|
res = add_one_digit (dst, src, &cry); /* add */
|
||||||
if (sto) /* store */
|
M[d] = (M[d] & FLAG) | res; /* store */
|
||||||
M[d] = (M[d] & FLAG) | res;
|
|
||||||
MM (d); MM (s); /* decr mem addrs */
|
MM (d); MM (s); /* decr mem addrs */
|
||||||
do {
|
do {
|
||||||
dst = M[d] & DIGIT; /* get dst digit */
|
dst = M[d] & DIGIT; /* get dst digit */
|
||||||
if (dst == REC_MARK)
|
|
||||||
dst = 0;
|
|
||||||
dst_f = M[d] & FLAG; /* get dst flag */
|
dst_f = M[d] & FLAG; /* get dst flag */
|
||||||
if (src_f) /* src done? src = 0 */
|
if (src_f) /* src done? src = 0 */
|
||||||
src = 0;
|
src = 0;
|
||||||
else {
|
else {
|
||||||
src = M[s] & DIGIT; /* get src digit */
|
src = M[s] & DIGIT; /* get src digit */
|
||||||
if (src == REC_MARK)
|
|
||||||
src = 0;
|
|
||||||
if (cnt >= skp) /* get src flag */
|
if (cnt >= skp) /* get src flag */
|
||||||
src_f = M[s] & FLAG;
|
src_f = M[s] & FLAG;
|
||||||
MM (s); /* decr src addr */
|
MM (s); /* decr src addr */
|
||||||
|
@ -1377,8 +1370,7 @@ do {
|
||||||
if (comp) /* complement? */
|
if (comp) /* complement? */
|
||||||
src = 9 - src;
|
src = 9 - src;
|
||||||
res = add_one_digit (dst, src, &cry); /* add */
|
res = add_one_digit (dst, src, &cry); /* add */
|
||||||
if (sto) /* store */
|
M[d] = dst_f | res; /* store */
|
||||||
M[d] = dst_f | res;
|
|
||||||
MM (d); /* decr dst addr */
|
MM (d); /* decr dst addr */
|
||||||
if (cnt++ >= MEMSIZE) /* (stop runaway) */
|
if (cnt++ >= MEMSIZE) /* (stop runaway) */
|
||||||
return STOP_FWRAP;
|
return STOP_FWRAP;
|
||||||
|
@ -1392,7 +1384,6 @@ if (!src_f) /* !src done? ovf */
|
||||||
|
|
||||||
if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */
|
if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */
|
||||||
ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */
|
ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */
|
||||||
if (sto) { /* storing? */
|
|
||||||
for (cry = 0, dp = dsv; dp != d; ) { /* rescan */
|
for (cry = 0, dp = dsv; dp != d; ) { /* rescan */
|
||||||
dst = M[dp] & DIGIT; /* get dst digit */
|
dst = M[dp] & DIGIT; /* get dst digit */
|
||||||
dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */
|
dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */
|
||||||
|
@ -1401,7 +1392,6 @@ if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */
|
||||||
MM (dp); /* decr dst addr */
|
MM (dp); /* decr dst addr */
|
||||||
}
|
}
|
||||||
M[dsv] = M[dsv] ^ FLAG; /* compl sign */
|
M[dsv] = M[dsv] ^ FLAG; /* compl sign */
|
||||||
}
|
|
||||||
*sta = ADD_SIGNC; /* sign changed */
|
*sta = ADD_SIGNC; /* sign changed */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
} /* end if recomp */
|
} /* end if recomp */
|
||||||
|
@ -1412,6 +1402,73 @@ if (!comp && cry) /* set status */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compare routine
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
d = destination field low (P)
|
||||||
|
s = source field low (Q)
|
||||||
|
Output:
|
||||||
|
return = status
|
||||||
|
|
||||||
|
In the unlike signs case, the compare is abandoned as soon as a non-zero
|
||||||
|
digit is seen; zeroes go through the normal flows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
t_stat cmp_field (uint32 d, uint32 s)
|
||||||
|
{
|
||||||
|
uint32 cry, src, dst, unlike, dsv;
|
||||||
|
uint32 src_f = 0, cnt = 0, dst_f = 0;
|
||||||
|
|
||||||
|
dsv = d; /* save dst */
|
||||||
|
cry = 0; /* clr carry */
|
||||||
|
unlike = (M[d] ^ M[s]) & FLAG; /* set unlike signs flag */
|
||||||
|
ind[IN_HP] = ((M[d] & FLAG) == 0); /* set sign from res */
|
||||||
|
ind[IN_EZ] = 1; /* assume zero */
|
||||||
|
|
||||||
|
do {
|
||||||
|
dst = M[d] & DIGIT; /* get dst digit */
|
||||||
|
if (d != dsv) /* if not first digit, */
|
||||||
|
dst_f = M[d] & FLAG; /* get dst flag */
|
||||||
|
if (src_f) /* src done? src = 0 */
|
||||||
|
src = 0;
|
||||||
|
else {
|
||||||
|
src = M[s] & DIGIT; /* get src digit */
|
||||||
|
if (d != dsv) /* if not first digit, */
|
||||||
|
src_f = M[s] & FLAG; /* get src flag */
|
||||||
|
MM (s); /* decr src addr */
|
||||||
|
}
|
||||||
|
if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */
|
||||||
|
return STOP_INVDIG;
|
||||||
|
if (unlike && ((dst | src) != 0)) { /* unlike signs, digit? */
|
||||||
|
ind[IN_EZ] = 0; /* not equal */
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
src = (d != dsv)? 9 - src: 10 - src; /* complement */
|
||||||
|
add_one_digit (dst, src, &cry); /* throw away result */
|
||||||
|
MM (d); /* decr dst addr */
|
||||||
|
if (cnt++ >= MEMSIZE) /* (stop runaway) */
|
||||||
|
return STOP_FWRAP;
|
||||||
|
} while (dst_f == 0); /* until dst done */
|
||||||
|
if (!src_f) /* !src done? ovf */
|
||||||
|
ind[IN_OVF] = 1;
|
||||||
|
|
||||||
|
/* At this point, we have three possible cases:
|
||||||
|
- Fields are equal, signs irrelevant: ind[IN_EZ] is still set
|
||||||
|
- Fields are unequal, signs are the same, carry out:
|
||||||
|
|p| > |q|, ind[IN_HP] is correct
|
||||||
|
- Fields are unequal, signs are the same, no carry out:
|
||||||
|
|p| < |q, ind[IN_HP] must be inverted
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!cry && !ind[IN_EZ]) { /* recomp needed? */
|
||||||
|
ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */
|
||||||
|
return SCPE_OK;
|
||||||
|
} /* end if recomp */
|
||||||
|
if (ind[IN_EZ]) /* res = 0? clr HP */
|
||||||
|
ind[IN_HP] = 0;
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add one digit via table (Model 1) or "hardware" (Model 2) */
|
/* Add one digit via table (Model 1) or "hardware" (Model 2) */
|
||||||
|
|
||||||
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry)
|
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* i1620_fp.c: IBM 1620 floating point simulator
|
/* i1620_fp.c: IBM 1620 floating point simulator
|
||||||
|
|
||||||
Copyright (c) 2002-2008, Robert M. Supnik
|
Copyright (c) 2002-2015, Robert M. Supnik
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
where S represents flag bits if the mantissa or exponent are negative.
|
where S represents flag bits if the mantissa or exponent are negative.
|
||||||
|
|
||||||
|
26-Mar-2015 RMS Removed "store" parameter from add_field
|
||||||
31-May-2008 RMS Fixed add_field call (Peter Schorn)
|
31-May-2008 RMS Fixed add_field call (Peter Schorn)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro);
|
||||||
t_stat fp_zero (FPA *fp);
|
t_stat fp_zero (FPA *fp);
|
||||||
|
|
||||||
extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp);
|
extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp);
|
||||||
extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta);
|
extern t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta);
|
||||||
extern t_stat mul_field (uint32 d, uint32 s);
|
extern t_stat mul_field (uint32 d, uint32 s);
|
||||||
extern t_stat xmt_divd (uint32 d, uint32 s);
|
extern t_stat xmt_divd (uint32 d, uint32 s);
|
||||||
extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez);
|
extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez);
|
||||||
|
@ -278,7 +279,7 @@ else if (dif < 0) { /* dst exp < src exp? */
|
||||||
dfp.exp = sfp.exp; /* res exp = src exp */
|
dfp.exp = sfp.exp; /* res exp = src exp */
|
||||||
fp_rsh (&dfp, -dif); /* denormalize dst */
|
fp_rsh (&dfp, -dif); /* denormalize dst */
|
||||||
}
|
}
|
||||||
r = add_field (dfp.addr, sfp.addr, sub, TRUE, 0, &sta); /* add mant, set EZ, HP */
|
r = add_field (dfp.addr, sfp.addr, sub, 0, &sta); /* add mant, set EZ, HP */
|
||||||
if (dif > 0) { /* src denormalized? */
|
if (dif > 0) { /* src denormalized? */
|
||||||
sad = sfp.addr; /* restore src from */
|
sad = sfp.addr; /* restore src from */
|
||||||
for (i = 0; i < sfp.lnt; i++) { /* save area */
|
for (i = 0; i < sfp.lnt; i++) { /* save area */
|
||||||
|
|
Loading…
Add table
Reference in a new issue