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
|
||||
|
||||
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);
|
||||
|
@ -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,7 +1384,6 @@ 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 */
|
||||
|
@ -1401,7 +1392,6 @@ if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */
|
|||
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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue