From 6bf32c0687e835eff81a0ae8fd7f49b22b4e1c9e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 26 Mar 2015 12:49:19 -0700 Subject: [PATCH] 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. --- I1620/i1620_cpu.c | 129 +++++++++++++++++++++++++++++++++------------- I1620/i1620_fp.c | 7 +-- 2 files changed, 97 insertions(+), 39 deletions(-) diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index 0c6fd9d4..eb294b77 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -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) diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c index 2b82a0fc..6e27ab10 100644 --- a/I1620/i1620_fp.c +++ b/I1620/i1620_fp.c @@ -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 */