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:
Mark Pizzolato 2015-03-26 12:49:19 -07:00
parent 569cfaf591
commit 6bf32c0687
2 changed files with 97 additions and 39 deletions

View file

@ -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);
@ -535,7 +538,7 @@ while (reason == 0) { /* loop until halted */
break; break;
} }
} }
else if (flags & IF_IMM) /* immediate? */ else if (flags & IF_IMM) /* immediate? */
QAR = qla; QAR = qla;
if (hst_lnt) { /* history enabled? */ if (hst_lnt) { /* history enabled? */
@ -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,16 +1384,14 @@ 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 */ res = add_one_digit (0, dst, &cry); /* "add" */
res = add_one_digit (0, dst, &cry); /* "add" */ M[dp] = (M[dp] & FLAG) | res; /* store */
M[dp] = (M[dp] & FLAG) | res; /* store */ 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)

View file

@ -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 */