1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-02-22 15:18:16 +00:00

IBM360: FP mostly working, some edge cases to fix.

This commit is contained in:
Richard Cornwell
2019-01-30 22:31:01 -05:00
parent f31e3b17e2
commit 3b6ef4935c

View File

@@ -23,7 +23,6 @@
#include "ibm360_defs.h" /* simulator defns */
#define FEAT_PROT (1 << (UNIT_V_UF + 8)) /* Storage protection feature */
#define FEAT_DEC (1 << (UNIT_V_UF + 9)) /* Decimal instruction set */
#define FEAT_FLOAT (1 << (UNIT_V_UF + 10)) /* Floating point instruction set */
@@ -125,6 +124,8 @@ uint32 execp_error; /* Translation error */
#define MMASK 0x00ffffff /* Mantissa mask */
#define EMASK 0x7f000000 /* Exponent mask */
#define XMASK 0x0fffffff /* Working FP mask */
#define HMASK 0x7fffffff /* Working FP mask */
#define FMASK 0xffffffff /* Working FP mask */
#define CMASK 0x10000000 /* Carry mask */
#define NMASK 0x00f00000 /* Normalize mask */
@@ -164,6 +165,23 @@ struct InstHistory
uint8 cc;
};
#if 0
#include <math.h>
double cnvt_float(uint32 l, uint32 h) {
t_uint64 t64;
double d;
int e;
e = ((l >> 24) & 0x7f) - 64;
t64 = ((t_uint64)l & MMASK) << 32LL | h;
d = (double)t64;
d *= exp2(-56 + 4*e);
if (l & MSIGN)
d *= -1.0;
return d;
}
#endif
struct InstHistory *hst = NULL;
/* Forward and external declarations */
@@ -202,6 +220,10 @@ UNIT cpu_unit = { UDATA (&rtc_srv, UNIT_BINK, MAXMEMSIZE) };
REG cpu_reg[] = {
{ HRDATA (PC, PC, 24) },
{ HRDATA (CC, cc, 2) },
{ HRDATA (PMASK, pmsk, 4) },
{ HRDATA (FLAGS, flags, 4) },
{ HRDATA (KEY, st_key, 4) },
{ HRDATA (R0, regs[00], 32) },
{ HRDATA (R1, regs[01], 32) },
{ HRDATA (R2, regs[02], 32) },
@@ -724,6 +746,7 @@ sim_instr(void)
t_uint64 t64;
t_uint64 t64a;
uint16 ops[3];
//double a, b, c;
reason = SCPE_OK;
ilc = 0;
@@ -880,7 +903,10 @@ opr:
}
/* Load operands */
src1 = fpregs[reg1];
src1h = fpregs[reg1|1];
if ((op & 0x10) == 0)
src1h = fpregs[reg1|1];
else
src1h = 0;
if (op & 0x40) {
if ((op & 0x10) != 0 && (addr1 & 0x3) != 0) {
//fprintf(stderr, "Spec FP Op=%0x Op=%x\n\r", op, addr1);
@@ -2219,7 +2245,9 @@ save_dbl:
storepsw(OPPSW, IRC_OPR);
goto supress;
}
//fprintf(stderr, "FP + Op=%0x src1=%08x %08x, src2=%08x %08x\n\r", op, src1, src1h, src2, src2h);
// a = cnvt_float(src1, src1h);
// b = cnvt_float(src2, src2h);
//fprintf(stderr, "FP + Op=%0x src1=%08x %08x, src2=%08x %08x %e %e %e\n\r", op, src1, src1h, src2, src2h, a, b, a+b);
/* Extract numbers and adjust */
e1 = (src1 & EMASK) >> 24;
e2 = (src2 & EMASK) >> 24;
@@ -2228,26 +2256,37 @@ save_dbl:
fill |= 2;
if (src2 & MSIGN)
fill |= 1;
src2 &= MMASK;
src1 &= MMASK;
temp = e1 - e2;
if (temp > 0) {
/* Shift src2 right if src1 larger expo - expo */
while (temp-- != 0) {
src2h >>= 4;
src2h |= (src2 & 0xf) << 28;
src2 >>= 4;
e2 ++;
//fprintf(stderr, "FP +2 Op=%0x src1=%08x %08x, src2=%08x %08x %e %e %e\n\r", op, src1, src1h, src2, src2h, a, b, a+b);
}
} else if (temp < 0) {
/* Shift src1 right if src2 larger expo - expo */
while (temp++ != 0) {
src1h >>= 4;
src1h |= (src1 & 0xf) << 28;
src1 >>= 4;
e1 ++;
//fprintf(stderr, "FP +1 Op=%0x src1=%08x %08x, src2=%08x %08x %e %e %e\n\r", op, src1, src1h, src2, src2h, a, b, a+b);
}
}
/* Exponents should be equal now. */
/* Create guard digit by shifting left 4 bits */
src1 = ((src1 & MMASK) << 4) | ((src1h >> 28) & 0xf);
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src1h &= XMASK;
src2h &= XMASK;
/* Shift src2 right if src1 larger expo - expo */
while (e1 > e2) {
src2h |= (src2 & 0xf) << 28;
src2h >>= 4;
src2 >>= 4;
e2 ++;
}
/* Shift src1 right if src2 larger expo - expo */
while (e2 > e1) {
src1h |= (src1 & 0xf) << 28;
src1h >>= 4;
src1 >>= 4;
e1 ++;
}
/* Exponents should be equal now. */
/* Add results */
if (fill == 2 || fill == 1) {
/* Different signs do subtract */
@@ -2265,13 +2304,13 @@ save_dbl:
desth &= XMASK;
}
if (dest & CMASK)
dest ^= CMASK;
dest &= XMASK;
else {
fill ^= 2;
dest ^= XMASK;
desth ^= XMASK;
desth++;
if (dest & CMASK) {
if (desth & CMASK) {
dest++;
desth &= XMASK;
}
@@ -2285,43 +2324,48 @@ save_dbl:
}
}
/* If src1 not normal shift left + expo */
//fprintf(stderr, "FP +n res=%08x %08x %d\n\r", dest, desth, cc);
if (dest & CMASK) {
desth >>= 4;
desth |= (dest & 0xf) << 28;
dest >>= 4;
e1 ++;
if (e1 >= 128) {
storepsw(OPPSW, IRC_EXPOVR);
// fprintf(stderr, "FP ov\n\r");
}
desth >>= 4;
desth |= (dest & 0xf) << 28;
dest >>= 4;
e1 ++;
if (e1 >= 128) {
storepsw(OPPSW, IRC_EXPOVR);
// fprintf(stderr, "FP ov %d\n\r", e1);
}
}
/* Compute sign of result */
/* Set condition codes */
cc = 0;
if ((desth | dest) != 0)
cc = (fill & 2) ? 1 : 2;
//fprintf(stderr, "FP +p res=%08x %08x %d\n\r", dest, desth, cc);
/* Set condition codes */
/* If (op & 0xF) == 0x9, compare */
if ((op & 0xF) == 0x9) /* Compare operator */
/* If compare operator, we are done */
if ((op & 0xF) == 0x9) {
//fprintf(stderr, "FP = %d\n\r", cc);
break; /* All done */
}
/* Remove DP Guard bit */
desth |= (dest & 0xf) << 28;
dest >>= 4;
/* Check signifigance exception */
if (cc == 0 && pmsk & SIGMSK) {
storepsw(OPPSW, IRC_EXPOVR);
// fprintf(stderr, "FP under\n\r");
// fprintf(stderr, "FP Signifigance\n\r");
goto fpstore;
}
/* If (op & 0xE) != 0xE, normalize */
if ((op & 0xE) != 0xE) { /* Normalize operator */
if (cc != 0) {
while ((dest & EMASK) == 0 && e1 > 0) {
/* Check if we are normalized addition */
if ((op & 0xE) != 0xE) {
if (cc != 0) { /* Only if non-zero result */
while ((dest & NMASK) == 0 && e1 > 0) {
//fprintf(stderr, "FP +n res=%08x %08x %x\n\r", dest, desth, e1);
dest = (dest << 4) | ((desth >> 24) & 0xf);
dest = (dest << 4) | ((desth >> 28) & 0xf);
desth <<= 4;
desth &= XMASK;
e1 --;
}
/* Check if underflow */
@@ -2335,20 +2379,19 @@ save_dbl:
}
}
} else {
e1 = 0; /* Return true zero */
fill = e1 = 0; /* Return true zero */
}
}
fpstore:
/* Store result */
desth = (desth >> 4) | ((dest & 0xf) << 28);
dest >>= 4;
dest |= (e1 << 24) & EMASK;
if (cc != 0 && fill & 2)
dest |= MSIGN;
if ((op & 0x10) == 0)
fpregs[reg1|1] = desth;
fpregs[reg1] = dest;
//fprintf(stderr, "FP + res=%08x %08x %d\n\r", dest, desth, cc);
//fprintf(stderr, "FP + res=%08x %08x %d %e\n\r", dest, desth, cc, cnvt_float(dest,desth));
break;
/* Multiply */
@@ -2361,53 +2404,67 @@ fpstore:
goto supress;
}
//fprintf(stderr, "FP * Op=%0x src1=%08x %08x, src2=%08x %08x\n\r", op, src1, src1h, src2, src2h);
// a = cnvt_float(src1, src1h);
// b = cnvt_float(src2, src2h);
//fprintf(stderr, "FP * Op=%0x src1=%08x %08x, src2=%08x %08x %e %e %e\n\r", op, src1, src1h, src2, src2h, a, b, a*b);
/* Extract numbers and adjust */
e1 = (src1 & EMASK) >> 24;
e2 = (src2 & EMASK) >> 24;
e1 = e1 + e2 - 64;
fill = 0;
if ((src1 & MSIGN) != (src2 & MSIGN))
fill = 2;
/* If Prenomalize src2 and src1 */
while ((src2 | src2h) != 0 && (src2 & NMASK) == 0) {
src2 = ((src2 & MMASK) << 4) | ((src2h >> 24) & 0xf);
src2h <<= 4;
e1 --;
}
/* Create guard digit */
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src2h &= XMASK;
fill = 1;
src1 &= MMASK;
src2 &= MMASK;
/* Pre-nomalize src2 and src1 */
while ((src2 | src2h) != 0 && (src2 & NMASK) == 0) {
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src2h <<= 4;
e2 --;
}
while ((src1 | src1h) != 0 && (src1 & NMASK) == 0) {
src1 = ((src1 & MMASK) << 4) | ((src1h >> 28) & 0xf);
src1h <<= 4;
e1 --;
}
e1 = e1 + e2 - 64;
/* Create guard bit */
src2 <<= 1;
if (src2h & MSIGN) {
src2 |= 1;
src2h & HMASK;
}
dest = desth = 0;
/* Do multiply */
for (temp = 0; temp < 56; temp++) {
//fprintf(stderr, "FP *s src1=%08x %08x, src2=%08x %08x dest=%08x %08x %d\n\r", src1, src1h, src2, src2h, dest, desth, temp);
/* Add if we need too */
if (src1h & 1) {
desth += src2h;
dest += src2;
if (desth & CMASK) {
dest ++;
desth &= XMASK;
/* Add if we need too */
if (src1h & 1) {
desth += src2h;
dest += src2;
if (desth & MSIGN) {
dest ++;
desth &= HMASK;
}
}
}
/* Shift right by one */
src1h >>= 1;
if (src1 & 1)
src1h |= MSIGN;
src1 >>= 1;
if (dest & 1)
desth |= CMASK;
desth >>= 1;
dest >>= 1;
/* Shift right by one */
src1h >>= 1;
if (src1 & 1)
src1h |= MSIGN;
src1 >>= 1;
if (dest & 1)
desth |= MSIGN;
desth >>= 1;
dest >>= 1;
}
fpnorm:
/* Remove guard but */
if (dest & 1) {
desth |= MSIGN;
}
dest >>= 1;
/* If src1 not normal shift left + expo */
if (dest & CMASK) {
desth >>= 4;
@@ -2421,38 +2478,32 @@ fpnorm:
}
/* Align the results */
if ((dest | desth) != 0) {
while ((dest & EMASK) == 0 && e1 > 0) {
while ((dest & NMASK) == 0 && e1 > 0) {
//fprintf(stderr, "FP *n res=%08x %08x %x\n\r", dest, desth, e1);
dest = (dest << 4) | ((desth >> 24) & 0xf);
desth <<= 4;
desth &= XMASK;
e1 --;
dest = (dest << 4) | ((desth >> 28) & 0xf);
desth <<= 4;
e1 --;
}
/* Check if underflow */
if (e1 < 0) {
if (pmsk & EXPUND) {
storepsw(OPPSW, IRC_EXPUND);
storepsw(OPPSW, IRC_EXPUND);
// fprintf(stderr, "FP un\n\r");
} else {
desth = dest = 0;
fill = e1 = 0;
desth = dest = 0;
fill = e1 = 0;
}
}
}
goto fpstore;
#if 0
/* Store result */
desth = (desth >> 4) | ((dest & 0xf) << 28);
dest >>= 4;
} else
fill = 0;
dest |= (e1 << 24) & EMASK;
fprintf(stderr, "FP * res=%08x %08x\n\r", dest, desth);
if (fill)
dest |= MSIGN;
if ((op & 0x10) == 0)
fpregs[reg1|1] = desth;
fpregs[reg1] = dest;
//fprintf(stderr, "FP * res=%08x %08x %d %e\n\r", dest, desth, cc, cnvt_float(dest,desth));
break;
#endif
/* Divide */
case OP_DER:
@@ -2463,120 +2514,109 @@ fprintf(stderr, "FP * res=%08x %08x\n\r", dest, desth);
storepsw(OPPSW, IRC_OPR);
goto supress;
}
//fprintf(stderr, "FP / Op=%0x src1=%08x %08x, src2=%08x %08x\n\r", op, src1, src1h, src2, src2h);
// a = cnvt_float(src1, src1h);
// b = cnvt_float(src2, src2h);
//fprintf(stderr, "FP / Op=%0x src1=%08x %08x, src2=%08x %08x %e %e %e\n\r", op, src1, src1h, src2, src2h, a, b, a/b);
/* Extract numbers and adjust */
e1 = (src1 & EMASK) >> 24;
e2 = (src2 & EMASK) >> 24;
e1 = e1 - e2 + 64;
fill = 0;
if (src1 & MSIGN)
fill = 0;
if ((src1 & MSIGN) != (src2 & MSIGN))
fill = 1;
if (src2 & MSIGN)
fill = !fill;
/* If Prenomalize src2 and src1 */
while ((src2 | src2h) != 0 && (src2 & NMASK) == 0) {
src2 = ((src2 & MMASK) << 4) | ((src2h >> 24) & 0xf);
src2h <<= 4;
e1 --;
}
while ((src1 | src1h) != 0 && (src1 & NMASK) == 0) {
src1 = ((src1 & MMASK) << 4) | ((src1h >> 24) & 0xf);
src1h <<= 4;
e1 --;
}
/* Create guard digit */
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src2h &= XMASK;
src1 &= MMASK;
src2 &= MMASK;
if ((src2 | src2h) == 0) {
storepsw(OPPSW, IRC_FPDIV);
break;
}
/* Pre-nomalize src2 and src1 */
while ((src2 | src2h) != 0 && (src2 & NMASK) == 0) {
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src2h <<= 4;
e2 --;
}
while ((src1 | src1h) != 0 && (src1 & NMASK) == 0) {
src1 = ((src1 & MMASK) << 4) | ((src1h >> 28) & 0xf);
src1h <<= 4;
e1 --;
}
e1 = e1 - e2 + 64;
/* Shift numbers up 4 bits so as not to lose precision below */
src2 = ((src2 & MMASK) << 4) | ((src2h >> 28) & 0xf);
src2h <<= 4;
src1 = ((src1 & MMASK) << 4) | ((src1h >> 28) & 0xf);
src1h &= XMASK;
dest = desth = 0;
if ((src1 | src1h) == 0) {
e1 = fill = 0;
goto fpstore;
src1h <<= 4;
/* Expand for DP math */
src2 <<= 1;
if (src2h & MSIGN) {
src2 |= 1;
src2h & HMASK;
}
src1 <<= 1;
if (src1h & MSIGN) {
src1 |= 1;
src1h & HMASK;
}
/* Check if we need to adjust divsor it larger then dividend */
if (src1 > src2) {
//fprintf(stderr, "FP /o src1=%08x %08x, src2=%08x %08x dest=%08x %08x\n\r", src1, src1h, src2, src2h, dest, desth);
src1h >>= 4;
src1h |= (src1 & 0xf) <<27;
src1 >>= 4;
e1++;
}
/* Change sign of src2 so we can add */
src2 ^= XMASK;
src2h ^= XMASK;
src2 ^= HMASK /*0x3fffffff*/;
src2h ^= HMASK;
src2h++;
if (src2h & CMASK) {
src2++;
src2h &= XMASK;
if (src2h & MSIGN) {
src2++;
src2h &= HMASK;
}
dest = desth = 0;
/* Do divide */
for (temp = 0; temp < 56; temp++) {
uint32 tlow, thigh;
for (temp = 56; temp > 0; temp--) {
uint32 tlow, thigh;
//fprintf(stderr, "FP /s src1=%08x %08x, src2=%08x %08x dest=%08x %08x %d\n\r", src1, src1h, src2, src2h, dest, desth, temp);
/* Shift left by one */
src1 <<= 1;
src1h <<= 1;
if (src1h & CMASK) {
src1 |= 1;
src1h &= XMASK;
}
thigh = src1h + src2h;
tlow = src1 + src2;
if (thigh & CMASK) {
tlow ++;
thigh &= XMASK;
}
dest <<= 1;
desth <<= 1;
if (desth & CMASK) {
dest |= 1;
desth &= XMASK;
}
if ((tlow & CMASK) != 0) {
src1 = tlow;
src1h = thigh;
desth |= 1;
}
/* Shift left by one */
src1 <<= 1;
src1h <<= 1;
if (src1h & MSIGN) {
src1 |= 1;
src1h & HMASK;
}
/* Subtract remainder to dividend */
thigh = src1h + src2h;
tlow = src1 + src2;
if (thigh & MSIGN) {
tlow ++;
thigh &= HMASK;
}
/* Shift quotent left one bit */
dest <<= 1;
desth <<= 1;
if (desth & MSIGN) {
dest |= 1;
desth &= HMASK;
}
/* If remainder larger then divisor replace */
if ((tlow & MSIGN/*0x40000000*/) != 0) {
src1 = tlow;
src1h = thigh;
desth |= 1;
}
}
goto fpnorm;
#if 0
/* If src1 not normal shift left + expo */
if (dest & CMASK) {
desth >>= 4;
desth |= (dest & 0xf) << 28;
dest >>= 4;
e1 ++;
if (e1 >= 128)
storepsw(OPPSW, IRC_EXPOVR);
}
goto fpnorm;
/* Normalize result */
if ((dest | desth) != 0) {
while ((dest & EMASK) == 0 && e1 > 0) {
fprintf(stderr, "FP /n res=%08x %08x %x\n\r", dest, desth, e1);
dest = (dest << 4) | ((desth >> 28) & 0xf);
desth <<= 4;
e1 --;
}
/* Check if underflow */
if (e1 < 0) {
if (pmsk & EXPUND)
storepsw(OPPSW, IRC_EXPUND);
else {
desth = dest = 0;
fill = e1 = 0;
}
}
}
/* Store result */
dest |= (e1 << 24) & EMASK;
fprintf(stderr, "FP / res=%08x %08x\n\r", dest, desth);
if (fill)
dest |= MSIGN;
if ((op & 0x10) == 0)
fpregs[reg1|1] = desth;
fpregs[reg1] = dest;
break;
#endif
/* Decimal operations */
case OP_CP: /* 1001 */
@@ -2624,6 +2664,7 @@ fprintf(stderr, "FP / res=%08x %08x\n\r", dest, desth);
hst[hst_p].cc = cc;
}
if ((op & 0xA0) == 0x20) {
sim_debug(DEBUG_INST, &cpu_dev,
"GR00=%08x GR01=%08x GR02=%08x GR03=%08x\n",
regs[0], regs[1], regs[2], regs[3]);
@@ -2644,6 +2685,7 @@ fprintf(stderr, "FP / res=%08x %08x\n\r", dest, desth);
"FP04=%08x FP05=%08x FP06=%08x FP07=%08x\n",
fpregs[4], fpregs[5], fpregs[6], fpregs[7]);
}
}
if (irqaddr != 0) {
supress:
@@ -2798,9 +2840,9 @@ dec_add(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2)
cy = addsub;
zero = 1;
/* Add numbers together */
for (i = 1; i <= len; i++) {
acc = a[i] + ((op)? (0x9 - b[i]):b[i]) + cy;
if ((acc & 0xf) > 0x9)
for (i = 1; i < len; i++) {
acc = a[i] + ((addsub)? (0x9 - b[i]):b[i]) + cy;
if (acc > 0x9)
acc += 0x6;
a[i] = acc & 0xf;
cy = (acc >> 4) & 0xf;
@@ -2815,11 +2857,12 @@ dec_add(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2)
} else {
if (addsub) {
/* We need to recomplent the result */
sa = !sa;
cy = 1;
zero = 1;
for (i = 1; i <= len; i++) {
for (i = 1; i < len; i++) {
acc = (0x9 - a[i]) + cy;
if ((acc & 0xf) > 0x9)
if (acc > 0x9)
acc += 0x6;
a[i] = acc & 0xf;
cy = (acc >> 4) & 0xf;
@@ -2828,6 +2871,8 @@ dec_add(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2)
}
}
}
if (zero && !ov)
sa = 0;
cc = 0;
if (zero) /* Really not zero */
cc = (sa)? 2: 1;
@@ -2842,10 +2887,10 @@ dec_add(int op, uint32 addr1, uint8 len1, uint32 addr2, uint8 len2)
}
}
dec_store(a, addr1, (int)len1, sa);
if (ov && pmsk & DECOVR)
storepsw(OPPSW, IRC_DECOVR);
if (ov)
cc = 3;
if (ov && pmsk & DECOVR)
storepsw(OPPSW, IRC_DECOVR);
}
}
@@ -2892,7 +2937,7 @@ fprintf(stderr, "Spec DecMP len=%x len=%x\n\r", len1, len2);
cy = 0;
for (i = j, k = 1; i <= len1; i++, k--) {
acc = a[i] + b[k] + cy;
if ((acc & 0xf) > 0x9)
if (acc > 0x9)
acc += 0x6;
a[i] = acc & 0xf;
cy = (acc >> 4) & 0xf;
@@ -2930,7 +2975,7 @@ fprintf(stderr, "Spec DecDP len=%x len=%x\n\r", len1, len2);
/* Add numbers together */
for (i = 1; i <= len; i++) {
acc = a[i] + ((op)? (0x9 - b[i]):b[i]) + cy;
if ((acc & 0xf) > 0x9)
if (acc > 0x9)
acc += 0x6;
a[i] = acc & 0xf;
cy = (acc >> 4) & 0xf;
@@ -2944,7 +2989,7 @@ fprintf(stderr, "Spec DecDP len=%x len=%x\n\r", len1, len2);
for (i = j, k = 1; i <= len1; i++, k--) {
c[i] = a[i]; /* Save if we divide too far */
acc = a[i] + (0x9 - b[k]) + cy;
if ((acc & 0xf) > 0x9)
if (acc > 0x9)
acc += 0x6;
a[i] = acc & 0xf;
cy = (acc >> 4) & 0xf;