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
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
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
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)
Fixed handling of P field in K instruction (Bob Armstrong)
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_tns (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);
t_stat mul_field (uint32 mpc, uint32 mpy);
t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last);
@ -535,7 +538,7 @@ while (reason == 0) { /* loop until halted */
break;
}
}
else if (flags & IF_IMM) /* immediate? */
else if (flags & IF_IMM) /* immediate? */
QAR = qla;
if (hst_lnt) { /* history enabled? */
@ -688,7 +691,7 @@ while (reason == 0) { /* loop until halted */
case OP_A:
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 */
ind[IN_OVF] = 1;
if (ar_stop && ind[IN_OVF])
@ -697,7 +700,7 @@ while (reason == 0) { /* loop until halted */
case OP_S:
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 */
ind[IN_OVF] = 1;
if (ar_stop && ind[IN_OVF])
@ -709,7 +712,7 @@ while (reason == 0) { /* loop until halted */
case OP_C:
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])
reason = STOP_OVERFL;
break;
@ -849,7 +852,7 @@ while (reason == 0) { /* loop until halted */
reason = STOP_INVIDX; /* stop */
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])
reason = STOP_OVERFL;
BRANCH (PAR); /* branch to P */
@ -861,7 +864,7 @@ while (reason == 0) { /* loop until halted */
reason = STOP_INVIDX; /* stop */
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])
reason = STOP_OVERFL;
BRANCH (PAR); /* branch to P */
@ -875,7 +878,7 @@ while (reason == 0) { /* loop until halted */
reason = STOP_INVIDX; /* stop */
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])
reason = STOP_OVERFL;
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 */
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])
reason = STOP_OVERFL;
if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */
@ -1323,18 +1326,17 @@ return SCPE_OK;
Output:
return = status
sta = ADD_NOCRY: no carry out, no sign change
ADD_SCHNG: sign change
ADD_SIGNC: sign change
ADD_CARRY: carry out
Reference Manual: "When the sum is zero, the sign of the P field
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, t_bool sto, uint32 skp, int32 *sta)
t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta)
{
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 */
dsv = d; /* save dst */
@ -1345,29 +1347,20 @@ ind[IN_EZ] = 1; /* assume zero */
dst = M[d] & DIGIT; /* 1st digits */
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? */
return STOP_INVDIG;
if (comp) /* complement? */
src = 10 - src;
res = add_one_digit (dst, src, &cry); /* add */
if (sto) /* store */
M[d] = (M[d] & FLAG) | res;
M[d] = (M[d] & FLAG) | res; /* store */
MM (d); MM (s); /* decr mem addrs */
do {
dst = M[d] & DIGIT; /* get dst digit */
if (dst == REC_MARK)
dst = 0;
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 (src == REC_MARK)
src = 0;
if (cnt >= skp) /* get src flag */
src_f = M[s] & FLAG;
MM (s); /* decr src addr */
@ -1377,8 +1370,7 @@ do {
if (comp) /* complement? */
src = 9 - src;
res = add_one_digit (dst, src, &cry); /* add */
if (sto) /* store */
M[d] = dst_f | res;
M[d] = dst_f | res; /* store */
MM (d); /* decr dst addr */
if (cnt++ >= MEMSIZE) /* (stop runaway) */
return STOP_FWRAP;
@ -1392,16 +1384,14 @@ if (!src_f) /* !src done? ovf */
if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */
ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */
if (sto) { /* storing? */
for (cry = 0, dp = dsv; dp != d; ) { /* rescan */
dst = M[dp] & DIGIT; /* get dst digit */
dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */
res = add_one_digit (0, dst, &cry); /* "add" */
M[dp] = (M[dp] & FLAG) | res; /* store */
MM (dp); /* decr dst addr */
}
M[dsv] = M[dsv] ^ FLAG; /* compl sign */
for (cry = 0, dp = dsv; dp != d; ) { /* rescan */
dst = M[dp] & DIGIT; /* get dst digit */
dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */
res = add_one_digit (0, dst, &cry); /* "add" */
M[dp] = (M[dp] & FLAG) | res; /* store */
MM (dp); /* decr dst addr */
}
M[dsv] = M[dsv] ^ FLAG; /* compl sign */
*sta = ADD_SIGNC; /* sign changed */
return SCPE_OK;
} /* end if recomp */
@ -1412,6 +1402,73 @@ if (!comp && cry) /* set status */
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) */
uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry)

View file

@ -1,6 +1,6 @@
/* 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
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.
26-Mar-2015 RMS Removed "store" parameter from add_field
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);
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 xmt_divd (uint32 d, uint32 s);
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 */
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? */
sad = sfp.addr; /* restore src from */
for (i = 0; i < sfp.lnt; i++) { /* save area */