diff --git a/em.c b/em.c index ffe3cae..39b74e7 100644 --- a/em.c +++ b/em.c @@ -121,52 +121,75 @@ typedef unsigned int pa_t; /* physical address */ #define RPH regs.u16[14] #define RPL regs.u16[15] +/* condition code macros */ + +#define CLEARCC crs[KEYS] &= ~0300 +#define SETEQ crs[KEYS] |= 0100 +#define SETLT crs[KEYS] |= 0200 + +/* set condition codes based on a 16-bit signed value */ + #define SETCC_16(val16) \ - crs[KEYS] &= ~0300; \ + CLEARCC; \ if ((val16) == 0) \ - crs[KEYS] |= 0100; \ + SETEQ; \ else if (*(short *)(&(val16)) < 0) \ - crs[KEYS] |= 0200; + SETLT; + +/* set condition codes based on A register (16-bit signed) */ #define SETCC_A SETCC_16(crs[A]) +/* set condition codes based on a 32-bit signed value */ + #define SETCC_32(val32) \ - crs[KEYS] &= ~0300; \ + CLEARCC; \ if ((val32) == 0) \ - crs[KEYS] |= 0100; \ + SETEQ; \ else if (*(int *)(&(val32)) < 0) \ - crs[KEYS] |= 0200; + SETLT; + +/* set condition codes based on L register (32-bit signed) */ #define SETCC_L SETCC_32(crsl[2]) -/* NOTE: in previous versions, exponent must be zero for 0.0, but DIAG - test CPU.FLOAT.V considers a zero fraction and non-zero exponent to - also be 0.0 (this is a "dirty zero") */ +/* set condition codes based on V-mode FP accumulator + + NOTES: + + -Prime considers anything with a zero fraction to be zero, + even if the exponent is non-zero (this is a "dirty zero") + + - Prime only tested 32 bits of the fraction, even for double + precision. It expected DP floats to be normalized, or mostly + normalized. +*/ #define SETCC_F \ - crs[KEYS] &= ~0300; \ - if (*(short *)(crs+FLTH) < 0) \ + CLEARCC; \ + if (*(int *)(crs+FLTH) < 0) \ crs[KEYS] |= 0200; \ else if (*(int *)(crs+FLTH) == 0) \ crs[KEYS] |= 0100; -/* NOTE: Prime only tested 32 bits of the fraction, even for double - precision. It expected DP floats to be normalized, or mostly - normalized. */ - #define SETCC_D SETCC_F + +/* macros for handling the C-bit (overflow) and L-bit (carry out) */ + #define EXPC(onoff) \ if ((onoff)) crs[KEYS] |= 0100000; \ else crs[KEYS] &= 077777 -/* XEXPC is a dummy to indicate that the C-bit may not be set correctly */ - -#define XEXPC(onoff) EXPC(onoff) - #define SETC crs[KEYS] |= 0100000 #define CLEARC crs[KEYS] &= 077777 +/* XEXPC, XSETC, XCLEARC are stuubs to indicate that the C-bit may not be set correctly */ + +#define XEXPC EXPC +#define XCLEARC CLEARC +#define XSETC SETC + /* EXPCL sets both the C and L bits for shift instructions NOTE: unlike EXPC, this doesn't clear anything - bits must be cleared @@ -1536,17 +1559,22 @@ ea_t apea(unsigned short *bitarg) { Always sets the C-bit. */ -#define FC_SFP_OFLOW 0400 -#define FC_SFP_ZDIV 0401 -#define FC_SFP_STORE 0402 -#define FC_SFP_INT 0403 -#define FC_DFP_OFLOW 01000 -#define FC_DFP_ZDIV 01001 -#define FC_INT_OFLOW 01400 -#define FC_INT_ZDIV 01401 -#define FC_DEC_OFLOW 03400 -#define FC_DEC_ZDIV 03401 -#define FC_DEC_CONV 03402 +#define FC_SFP_OFLOW 0400 /* 0x100 */ +#define FC_SFP_ZDIV 0401 /* 0x101 */ +#define FC_SFP_STORE 0402 /* 0x102 */ +#define FC_INT_CONV 0403 /* 0x103 */ +#define FC_DFP_OFLOW 01000 /* 0x200 */ +#define FC_DFP_ZDIV 01001 /* 0x201 */ +#define FC_INT_OFLOW 01400 /* 0x300 */ +#define FC_INT_ZDIV 01401 /* 0x301 */ +#define FC_FUNC_EXC 03000 /* 0x600 */ +#define FC_DEC_OFLOW 03400 /* 0x700 */ +#define FC_DEC_ZDIV 03401 /* 0x701 */ +#define FC_DEC_CONV 03402 /* 0x702 */ +#define FC_QFP_OFLOW 04000 /* 0x800 */ +#define FC_QFP_ZDIV 04001 /* 0x801 */ +#define FC_QFP_QINQ 04003 /* 0x803 */ + mathexception(unsigned char extype, unsigned short fcode, ea_t faddr) { @@ -1570,7 +1598,7 @@ mathexception(unsigned char extype, unsigned short fcode, ea_t faddr) } } - +#include "fp.h" memdump(int start, int end) { int ea; @@ -3497,7 +3525,9 @@ main (int argc, char **argv) { unsigned short access; unsigned long immu32; unsigned long long immu64; - + short fcode; + long long frac64; + int exp32; unsigned short zresult, zclen1, zclen2, zaccess; unsigned int zlen1, zlen2; ea_t zea1, zea2; @@ -5640,35 +5670,17 @@ a1a: TRACE(T_FLOW, " FLOT\n"); templ = *(short *)(crs+A); templ = (templ<<15) | crs[B]; - tempf = templ; - tempf1 = tempf; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - crs[FLTD] = 0; - TRACE(T_INST, " A|B=%d, conv=%f, FEXP=%d (dec), FLTH='%o, FLTL='%o\n", templ, tempf1, crs[FEXP], crs[FLTH], crs[FLTL]); + *(double *)(crs+FLTH) = fltl(templ); continue; case 0140534: TRACE(T_FLOW, " FRN\n"); + frn(crsl+FAC1); continue; case 0140574: TRACE(T_FLOW, " DFCM\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - *(double *)tempda = -(*(double *)tempda); - ieeepr8(tempda); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; - XEXPC(0); + dfcm(crs+FLTH); continue; case 0141000: @@ -5678,15 +5690,7 @@ a1a: case 0140530: TRACE(T_FLOW, " FCM\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - tempf = -tempf; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - XEXPC(0); + dfcm(crs+FLTH); continue; case 0140510: @@ -5727,68 +5731,44 @@ a1a: case 0140554: TRACE(T_FLOW, " INT\n"); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - TRACE(T_INST, " DFAC value=%f, FEXP=%d (dec), FLTH='%o, FLTL='%o, fltd='%o\n", *(double *)tempda, crs[FEXP], crs[FLTH], crs[FLTL], crs[FLTD]); - templ = *(double *)tempda; - TRACE(T_INST, " INT value=%d\n", templ); - crs[B] = templ & 0x7FFF; - crs[A] = templ >> 15; - if (*(double *)tempda > 1073741823.0 || *(double *)tempda < -1073741824.0) - mathexception('f', FC_DFP_OFLOW, ea); - else + /* XXX: do -1073741824.5 and 1073741823.5 work on Prime, or overflow? */ + if (prieee8(crs+FLTH, &tempd) && -1073741824.0 <= tempd && tempd <= 1073741823.0) { + templ = tempd; + crs[B] = templ & 0x7FFF; + crs[A] = templ >> 15; CLEARC; + } else + mathexception('f', FC_INT_CONV, ea); continue; case 0140531: TRACE(T_FLOW, " INTA\n"); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - if (*(double *)tempda > 32767.0 || *(double *)tempda < -32768.0) - mathexception('f', FC_DFP_OFLOW, ea); - else + /* XXX: do 32767.5 and -32768.5 work on Prime, or overflow? */ + if (prieee8(crs+FLTH, &tempd) && -32768.0 <= tempd && tempd <= 32767.0) { + *(short *)(crs+A) = tempd; CLEARC; - *(short *)(crs+A) = *(double *)tempda; + } else + mathexception('f', FC_INT_CONV, ea); continue; case 0140532: TRACE(T_FLOW, " FLTA\n"); - tempf = *(short *)(crs+A); - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - crs[FLTD] = 0; + tempd = *(short *)(crs+A); + *(double *)(crs+FLTH) = ieeepr8(tempd); continue; case 0140533: TRACE(T_FLOW, " INTL\n"); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - if (*(double *)tempda > 2147483647.0 || *(double *)tempda < -2147483648.0) - mathexception('f', FC_DFP_OFLOW, ea); - else + if (prieee8(crs+FLTH, &tempd) && -2147483648.0 <= tempd && tempd <= 2147483647.0) { + *(int *)(crs+L) = tempd; CLEARC; - *(int *)(crs+L) = *(double *)tempda; + } else + mathexception('f', FC_INT_CONV, ea); continue; case 0140535: TRACE(T_FLOW, " FLTL\n"); - tempf = *(int *)(crs+L); - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - crs[FLTD] = 0; + *(double *)(crs+FLTH) = fltl(crsl[GR2]); continue; case 0141711: @@ -5842,6 +5822,16 @@ a1a: *(int *)(crs+E) = templ; continue; + /* these next 4 are V/I-mode */ + + case 0140570: /* QFCM - quad complement */ + case 0140571: /* DRNM - round minus Q to D */ + case 0140572: /* QINQ - trucate Q fraction */ + case 0140573: /* QIQR - round and remove Q fraction */ + TRACE(T_FLOW, " QFCM DRNM QINQ QIQR UII\n"); + fault(UIIFAULT, RPL, RP); + continue; + /* queue instructions */ case 0141714: @@ -5902,150 +5892,150 @@ a1a: } } + /* this is a bit weird here: the shift group is really only for + V-mode instructions, but Prime put some I-mode generics in + the same instruction space. Not sure, but I think a real + Prime would probably take an illegal instruction fault on + something like LRL executed in I-mode, but the emulator will + just do it. */ if (class == 1) { - if ((crs[KEYS] & 0016000) == 0010000) { /* I-mode Generic */ + TRACE(T_INST, " shift group\n"); + scount = -inst & 077; + if (scount == 0) + scount = 0100; + switch (inst & 01700) { + + case 00000: /* LRL */ + TRACE(T_FLOW, " LRL %d\n", scount); + crsl[GR2] = lrl(crsl[GR2], scount); + break; + + case 00100: /* LRS (different in R & V modes) */ + TRACE(T_FLOW, " LRS %d\n", scount); + if (crs[KEYS] & 010000) { /* V/I mode */ + crsl[GR2] = lrs(crsl[GR2], scount); + } else { + CLEARCL; + utempa = crs[B] & 0x8000; /* save B bit 1 */ + if (scount <= 31) { + templ = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1); + EXPCL(templ & bitmask32[32-scount]); + templ = templ >> (scount+1); + crs[A] = templ >> 15; + crs[B] = (templ & 0x7FFF) | utempa; + } else if (crs[A] & 0x8000) { + *(int *)(crs+A) = 0xFFFF7FFF | utempa; + SETCL; + } else { + *(int *)(crs+A) = utempa; + } + } + break; + + case 00200: /* LRR */ + TRACE(T_FLOW, " LRR %d\n", scount); + crsl[GR2] = lrr(crsl[GR2], scount); + break; + + case 00300: switch (inst) { - case 0040300: /* DRN */ - warn("IXX I-mode Generic 040300"); - break; - case 0040301: /* DRNP */ - warn("IXX I-mode Generic 040301"); - break; - case 0040302: /* DRNZ */ - warn("IXX I-mode Generic 040302"); - break; + case 0040310: /* SSSN */ sssn(); break; + + case 0040300: /* DRN */ + case 0040301: /* DRNP */ + case 0040302: /* DRNZ */ + case 0040303: /* FRNP */ + case 0040320: /* FRNM */ + case 0040321: /* FRNZ */ + TRACE(T_FLOW, " DRNx/FRNx(V) UII\n"); + fault(UIIFAULT, RPL, RP); + break; + default: - TRACE(T_FLOW, " unrecognized I-mode generic class 1 instruction!\n"); - printf(" unrecognized I-mode generic class 1 instruction %o!\n", inst); - fatal(NULL); - } - } else { - TRACE(T_INST, " shift group\n"); - scount = -inst & 077; - if (scount == 0) - scount = 0100; - switch (inst & 01700) { - - case 00000: /* LRL */ - TRACE(T_FLOW, " LRL %d\n", scount); - crsl[GR2] = lrl(crsl[GR2], scount); - break; - - case 00100: /* LRS (different in R & V modes) */ - TRACE(T_FLOW, " LRS %d\n", scount); - if (crs[KEYS] & 010000) { /* V/I mode */ - crsl[GR2] = lrs(crsl[GR2], scount); - } else { - CLEARCL; - utempa = crs[B] & 0x8000; /* save B bit 1 */ - if (scount <= 31) { - templ = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1); - EXPCL(templ & bitmask32[32-scount]); - templ = templ >> (scount+1); - crs[A] = templ >> 15; - crs[B] = (templ & 0x7FFF) | utempa; - } else if (crs[A] & 0x8000) { - *(int *)(crs+A) = 0xFFFF7FFF | utempa; - SETCL; - } else { - *(int *)(crs+A) = utempa; - } - } - break; - - case 00200: /* LRR */ - TRACE(T_FLOW, " LRR %d\n", scount); - crsl[GR2] = lrr(crsl[GR2], scount); - break; - - case 00300: - if (inst == 040310) { - sssn(); - break; - } goto badshift; - - case 00400: /* ARL */ - TRACE(T_FLOW, " ARL %d\n", scount); - crs[A] = arl(crs[A], scount); - break; - - case 00500: /* ARS */ - TRACE(T_FLOW, " ARS %d\n", scount); - crs[A] = ars(crs[A], scount); - break; - - case 00600: /* ARR */ - TRACE(T_FLOW, " ARR %d\n", scount); - crs[A] = arr(crs[A], scount); - break; - - case 01000: /* LLL */ - TRACE(T_FLOW, " LLL %d\n", scount); - crsl[GR2] = lll(crsl[GR2], scount); - break; - - case 01100: /* LLS (different in R/V modes) */ - TRACE(T_FLOW, " LLS %d\n", scount); - if (crs[KEYS] & 010000) /* V/I mode */ - crsl[GR2] = lls(crsl[GR2], scount); - else { - CLEARCL; - utempa = crs[B] & 0x8000; /* save B bit 1 */ - if (scount < 31) { - utempl = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1); - templ2 = 0x80000000; - templ2 = templ2 >> scount; /* create mask */ - templ2 = templ2 & utempl; /* grab bits */ - templ2 = templ2 >> (31-scount); /* sign extend them */ - EXPCL(!(templ2 == -1 || templ2 == 0)); - //printf(" before: A=%x, B=%x, utempl=%x, ", crs[A], crs[B], utempl); - utempl = utempl << scount; - crs[A] = utempl >> 16; - crs[B] = ((utempl >> 1) & 0x7FFF) | utempa; - //printf(" after: A=%x, B=%x, utempl=%x\n", crs[A], crs[B], utempl); - } else { - EXPCL(*(unsigned int *)(crs+A) != 0); - *(unsigned int *)(crs+A) = utempa; - } - } - if ((crs[KEYS] & 0100400) == 0100400) - mathexception('i', FC_INT_OFLOW, 0); - break; - - case 01200: /* LLR */ - TRACE(T_FLOW, " LLR %d\n", scount); - crsl[GR2] = llr(crsl[GR2], scount); - break; - - case 01400: /* ALL */ - TRACE(T_FLOW, " ALL %d\n", scount); - crs[A] = all(crs[A], scount); - break; - - case 01500: /* ALS */ - TRACE(T_FLOW, " ALS %d\n", scount); - crs[A] = als(crs[A], scount); - if ((crs[KEYS] & 0100400) == 0100400) - mathexception('i', FC_INT_OFLOW, 0); - break; - - case 01600: /* ALR */ - TRACE(T_FLOW, " ALR %d\n", scount); - crs[A] = alr(crs[A], scount); - break; - - default: -badshift: - printf("emulator warning: unrecognized shift instruction %o at %o/%o\n", inst, RPH, RPL); - TRACE(T_FLOW, " unrecognized shift instruction!: %o\n", inst); } + break; + + case 00400: /* ARL */ + TRACE(T_FLOW, " ARL %d\n", scount); + crs[A] = arl(crs[A], scount); + break; + + case 00500: /* ARS */ + TRACE(T_FLOW, " ARS %d\n", scount); + crs[A] = ars(crs[A], scount); + break; + + case 00600: /* ARR */ + TRACE(T_FLOW, " ARR %d\n", scount); + crs[A] = arr(crs[A], scount); + break; + + case 01000: /* LLL */ + TRACE(T_FLOW, " LLL %d\n", scount); + crsl[GR2] = lll(crsl[GR2], scount); + break; + + case 01100: /* LLS (different in R/V modes) */ + TRACE(T_FLOW, " LLS %d\n", scount); + if (crs[KEYS] & 010000) /* V/I mode */ + crsl[GR2] = lls(crsl[GR2], scount); + else { + CLEARCL; + utempa = crs[B] & 0x8000; /* save B bit 1 */ + if (scount < 31) { + utempl = (crs[A]<<16) | ((crs[B] & 0x7FFF)<<1); + templ2 = 0x80000000; + templ2 = templ2 >> scount; /* create mask */ + templ2 = templ2 & utempl; /* grab bits */ + templ2 = templ2 >> (31-scount); /* sign extend them */ + EXPCL(!(templ2 == -1 || templ2 == 0)); + //printf(" before: A=%x, B=%x, utempl=%x, ", crs[A], crs[B], utempl); + utempl = utempl << scount; + crs[A] = utempl >> 16; + crs[B] = ((utempl >> 1) & 0x7FFF) | utempa; + //printf(" after: A=%x, B=%x, utempl=%x\n", crs[A], crs[B], utempl); + } else { + EXPCL(*(unsigned int *)(crs+A) != 0); + *(unsigned int *)(crs+A) = utempa; + } + } + if ((crs[KEYS] & 0100400) == 0100400) + mathexception('i', FC_INT_OFLOW, 0); + break; + + case 01200: /* LLR */ + TRACE(T_FLOW, " LLR %d\n", scount); + crsl[GR2] = llr(crsl[GR2], scount); + break; + + case 01400: /* ALL */ + TRACE(T_FLOW, " ALL %d\n", scount); + crs[A] = all(crs[A], scount); + break; + + case 01500: /* ALS */ + TRACE(T_FLOW, " ALS %d\n", scount); + crs[A] = als(crs[A], scount); + if ((crs[KEYS] & 0100400) == 0100400) + mathexception('i', FC_INT_OFLOW, 0); + break; + + case 01600: /* ALR */ + TRACE(T_FLOW, " ALR %d\n", scount); + crs[A] = alr(crs[A], scount); + break; + + default: +badshift: + printf("emulator warning: unrecognized shift/generic instruction %06o at %o/%o\n", inst, RPH, RPL); + TRACE(T_FLOW, " unrecognized shift instruction!: %o\n", inst); } - continue; + continue; } if (class == 2) { @@ -6507,7 +6497,7 @@ keys = 14200, modals=100177 case 0106: TRACE(T_FLOW, " DBLE\n"); - crsl[FAC0+dr+1] &= 0xFFFF0000; + crsl[FAC0+dr+1] &= 0x0000FFFF; break; case 0160: @@ -6525,7 +6515,7 @@ keys = 14200, modals=100177 case 0144: TRACE(T_FLOW, " DFCM\n"); - warn("IXX DFCM"); + dfcm(crsl+FAC0+dr); break; case 0130: @@ -6550,47 +6540,39 @@ keys = 14200, modals=100177 case 0100: TRACE(T_FLOW, " FCM\n"); - warn("IXX FCM"); + dfcm(crsl+FAC0+dr); break; case 0105: TRACE(T_FLOW, " FLT 0\n"); - warn("IXX FLT0"); + *(double *)(crsl+FAC0) = fltl(crsl[dr]); break; case 0115: TRACE(T_FLOW, " FLT 1\n"); - warn("IXX FLT1"); + *(double *)(crsl+FAC1) = fltl(crsl[dr]); break; case 0102: TRACE(T_FLOW, " FLTH 0\n"); - warn("IXX FLTH0"); + *(double *)(crsl+FAC0) = fltl(*(short *)(crs+dr*2)); break; case 0112: TRACE(T_FLOW, " FLTH 1\n"); - warn("IXX FLTH1"); + *(double *)(crsl+FAC1) = fltl(*(short *)(crs+dr*2)); break; case 0107: TRACE(T_FLOW, " FRN\n"); - warn("IXX FRN"); + frn(crsl+FAC0+dr); break; - case 0146: - TRACE(T_FLOW, " FRNM\n"); - warn("IXX FRNM"); - break; - - case 0145: - TRACE(T_FLOW, " FRNP\n"); - warn("IXX FRNP"); - break; - - case 0147: - TRACE(T_FLOW, " FRNZ\n"); - warn("IXX FRNZ"); + case 0146: /* I-mode FRNM */ + case 0145: /* I-mode FRNP */ + case 0147: /* I-mode FRNZ */ + TRACE(T_FLOW, " FRNx(I) UII\n"); + fault(UIIFAULT, RPL, RP); break; case 0065: @@ -6643,22 +6625,38 @@ keys = 14200, modals=100177 case 0103: TRACE(T_FLOW, " INT 0\n"); - warn("IXX INT0"); + if (prieee8(crsl+FAC0, &tempd) && -2147483648.0 <= tempd && tempd <= 2147483647.0) { + *(int *)(crsl+dr) = tempd; + CLEARC; + } else + mathexception('f', FC_INT_CONV, ea); break; case 0113: TRACE(T_FLOW, " INT 1\n"); - warn("IXX INT1"); + if (prieee8(crsl+FAC1, &tempd) && -2147483648.0 <= tempd && tempd <= 2147483647.0) { + *(int *)(crsl+dr) = tempd; + CLEARC; + } else + mathexception('f', FC_INT_CONV, ea); break; case 0101: TRACE(T_FLOW, " INTH 0\n"); - warn("IXX INTH0"); + if (prieee8(crsl+FAC0, &tempd) && -327688.0 <= tempd && tempd <= 327677.0) { + *(short *)(crs+dr*2) = tempd; + CLEARC; + } else + mathexception('f', FC_INT_CONV, ea); break; case 0111: TRACE(T_FLOW, " INTH 1\n"); - warn("IXX INTH1"); + if (prieee8(crsl+FAC1, &tempd) && -327688.0 <= tempd && tempd <= 32767.0) { + *(short *)(crs+dr*2) = tempd; + CLEARC; + } else + mathexception('f', FC_INT_CONV, ea); break; case 0122: @@ -7152,18 +7150,25 @@ keys = 14200, modals=100177 crs[dr*2] = arl(crs[dr*2], scount); break; default: - fatal("I-mode SHL switch?"); + warn("I-mode SHL switch?"); + fault(ILLINSTFAULT, RPL, RP); } continue; case 006: /* Special MR FP format */ - /* DFC, DFL, FC, FL */ + /* FL, DFL, FC, DFC */ switch (dr) { case 0: case 2: dr &= 2; TRACE(T_INST, " FL\n"); - warn("IXX 006 FL"); + if (*(int *)&ea < 0) + *(double *)(crsl+FAC0+dr) = *(double *)&immu64; + else { + utempl = get32(ea); + crsl[FAC0+dr] = utempl & 0xFFFFFF00; + crsl[FAC0+dr+1] = utempl & 0x000000FF; + } break; case 1: @@ -7180,18 +7185,46 @@ keys = 14200, modals=100177 case 6: dr &= 2; TRACE(T_INST, " FC\n"); - warn("IXX 006 FC"); + CLEARCC; + if (*(int *)&ea < 0) { + if (!prieee8(&immu64, &tempd2)) + mathexception('f', FC_SFP_OFLOW, ea); + } else + tempd2 = prieee4(get32(ea)); + if (prieee8(crsl+FAC0+dr, &tempd1)) + if (tempd1 == tempd2) + SETEQ; + else if (tempd1 < tempd2) + SETLT; + else + ; + else + mathexception('f', FC_SFP_OFLOW, ea); break; case 5: case 7: dr &= 2; TRACE(T_INST, " DFC\n"); - warn("IXX 006 DFC"); + CLEARCC; + if (*(int *)&ea < 0) + tempd2 = *(double *)&immu64; + else + tempd2 = get64(ea); + if (prieee8(crsl+FAC0+dr, &tempd1) && prieee8(&tempd2, &tempd2)) + if (tempd1 == tempd2) + SETEQ; + else if (tempd1 < tempd2) + SETLT; + else + ; + else + mathexception('f', FC_DFP_OFLOW, ea); break; default: - fatal("I-mode 006 switch?"); + warn("I-mode 006 switch?"); + fault(ILLINSTFAULT, RPL, RP); } continue; @@ -7271,7 +7304,17 @@ keys = 14200, modals=100177 case 2: dr &= 2; TRACE(T_INST, " FST\n"); - warn("IXX 016 FST"); + if (*(int *)&ea >= 0) + if ((crsl[FAC0+dr+1] & 0xFF00) == 0) { + /* XXX: round here if enabled in keys */ + put32((crsl[FAC0+dr] & 0xFFFFFF00) | (crsl[FAC0+dr+1] & 0xFF), ea); + CLEARC; + } else + mathexception('f', FC_SFP_STORE, ea); + else { + warn("I-mode immediate FST?"); + fault(ILLINSTFAULT, RPL, RP); + } break; case 1: @@ -7290,18 +7333,36 @@ keys = 14200, modals=100177 case 6: dr &= 2; TRACE(T_INST, " FA\n"); - warn("IXX 016 FA"); + if (*(int *)&ea < 0) { + if (!prieee8(&immu64, &tempd2)) + mathexception('f', FC_SFP_OFLOW, ea); + } else + tempd2 = prieee4(get32(ea)); + if (prieee8(crsl+FAC0+dr, &tempd1)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1+tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); break; case 5: case 7: dr &= 2; TRACE(T_INST, " DFA\n"); - warn("IXX 016 DFA"); + if (*(int *)&ea < 0) + tempd2 = *(double *)&immu64; + else + tempd2 = get64(ea); + if (prieee8(crsl+FAC0+dr, &tempd1) && prieee8(&tempd2, &tempd2)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1+tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); break; default: - fatal("I-mode 016 switch?"); + warn("I-mode 016 switch?"); + fault(ILLINSTFAULT, RPL, RP); } continue; @@ -7357,7 +7418,8 @@ keys = 14200, modals=100177 crs[dr*2] = arr(crs[dr*2], scount); break; default: - fatal("I-mode ROT switch?"); + warn("I-mode ROT switch?"); + fault(ILLINSTFAULT, RPL, RP); } continue; @@ -7366,8 +7428,74 @@ keys = 14200, modals=100177 fault(ILLINSTFAULT, RPL, RP); case 026: /* Special MR FP format */ - /* DFM, DFS, FM, FS */ - warn("IXX 026"); + /* FS, DFS, FM, DFM */ + switch (dr) { + case 0: + case 2: + dr &= 2; + TRACE(T_INST, " FS\n"); + if (*(int *)&ea < 0) { + if (!prieee8(&immu64, &tempd2)) + mathexception('f', FC_SFP_OFLOW, ea); + } else + tempd2 = prieee4(get32(ea)); + if (prieee8(crsl+FAC0+dr, &tempd1)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1-tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); + break; + + case 1: + case 3: + dr &= 2; + TRACE(T_INST, " DFS\n"); + if (*(int *)&ea < 0) + tempd2 = *(double *)&immu64; + else + tempd2 = get64(ea); + if (prieee8(crsl+FAC0+dr, &tempd1) && prieee8(&tempd2, &tempd2)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1-tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); + break; + + case 4: + case 6: + dr &= 2; + TRACE(T_INST, " FM\n"); + if (*(int *)&ea < 0) { + if (!prieee8(&immu64, &tempd2)) + mathexception('f', FC_SFP_OFLOW, ea); + } else + tempd2 = prieee4(get32(ea)); + if (prieee8(crsl+FAC0+dr, &tempd1)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1*tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); + break; + + case 5: + case 7: + dr &= 2; + TRACE(T_INST, " DFM\n"); + if (*(int *)&ea < 0) + tempd2 = *(double *)&immu64; + else + tempd2 = get64(ea); + if (prieee8(crsl+FAC0+dr, &tempd1) && prieee8(&tempd2, &tempd2)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1*tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); + break; + + default: + warn("I-mode 026 switch?"); + fault(ILLINSTFAULT, RPL, RP); + } continue; case 027: @@ -7417,8 +7545,55 @@ keys = 14200, modals=100177 continue; case 036: /* Special MR FP format */ - /* DFD, FD, QFAD, QFLD, QFSB, QFST */ - warn("IXX 036"); + /* FD, DFD, QFLD, QFST, QFSB, QFAD */ + switch (dr) { + case 0: + case 2: + dr &= 2; + TRACE(T_INST, " FD\n"); + if (*(int *)&ea < 0) { + if (!prieee8(&immu64, &tempd2)) + mathexception('f', FC_SFP_OFLOW, ea); + } else + tempd2 = prieee4(get32(ea)); + if (tempd2 != 0.0) + if (prieee8(crsl+FAC0+dr, &tempd1)) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1/tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); + else + mathexception('f', FC_SFP_ZDIV, ea); + break; + + case 1: + case 3: + dr &= 2; + TRACE(T_INST, " DFD\n"); + if (*(int *)&ea < 0) + tempd2 = *(double *)&immu64; + else + tempd2 = get64(ea); + if (prieee8(crsl+FAC0+dr, &tempd1) && prieee8(&tempd2, &tempd2)) + if (tempd2 != 0.0) { + *(double *)(crsl+FAC0+dr) = ieeepr8(tempd1/tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); + else + mathexception('f', FC_DFP_ZDIV, ea); + break; + + case 4: /* QFLD */ + case 5: /* QFST */ + case 6: /* QFSB */ + case 7: /* QFAD */ + fault(UIIFAULT, RPL, RP); + + default: + warn("I-mode 036 switch?"); + fault(ILLINSTFAULT, RPL, RP); + } continue; case 037: @@ -7499,12 +7674,12 @@ keys = 14200, modals=100177 TRACE(T_FLOW, " IM\n"); templ = get32(ea); put32(templ+1, ea); - crs[KEYS] &= ~0300; + CLEARCC; /* NOTE: test pre-incremented values to get true LT (overflow) */ if (templ == -1) - crs[KEYS] |= 0100; + SETEQ; else if (templ < 0) - crs[KEYS] |= 0200; + SETLT; break; /* NOTE: V-mode PCL may jump here! */ @@ -7543,20 +7718,24 @@ imodepcl: case 5: TRACE(T_FLOW, " QFMP\n"); - warn("IXX QFMP"); + fault(UIIFAULT, RPL, RP); + //warn("IXX QFMP"); break; case 6: TRACE(T_FLOW, " QFDV\n"); - warn("IXX QFDV"); + fault(UIIFAULT, RPL, RP); + //warn("IXX QFDV"); break; case 7: TRACE(T_FLOW, " QFC\n"); - warn("IXX QFC"); + fault(UIIFAULT, RPL, RP); + //warn("IXX QFC"); break; default: + warn("I-mode 006 switch?"); fault(ILLINSTFAULT, RPL, RP); } continue; @@ -7629,11 +7808,11 @@ imodepcl: TRACE(T_FLOW, " IMH\n"); tempa = get16(ea); put16(tempa+1, ea); - crs[KEYS] &= ~0300; + CLEARCC; if (tempa == -1) - crs[KEYS] |= 0100; + SETEQ; else if (tempa < 0) - crs[KEYS] |= 0200; + SETLT; break; case 1: @@ -7676,14 +7855,14 @@ imodepcl: utempl = immu32; else utempl = get32(ea); - crs[KEYS] &= ~020300; + crs[KEYS] &= ~020300; /* clear L, EQ LT */ utempll = crsl[dr]; if ((utempll + (~utempl & 0xFFFFFFFF) + 1) & 0x100000000LL) crs[KEYS] |= 020000; if (crsl[dr] == utempl) - crs[KEYS] |= 0100; + SETEQ; else if (*(int *)(crsl+dr) < *(int *)&utempl) - crs[KEYS] |= 0200; + SETLT; continue; case 062: @@ -7722,6 +7901,8 @@ imodepcl: continue; case 065: + /* XXX: DIAG test CPU.AMGRR for cpuid=26 indicates IP needs to + be weakened */ TRACE(T_FLOW, " LIP\n"); utempl = get32(ea); if (utempl & 0x80000000) @@ -7736,11 +7917,11 @@ imodepcl: templ = get32(ea); put32(templ-1, ea); /* NOTE: test pre-decremented values to get true LT (overflow) */ - crs[KEYS] &= ~0300; + CLEARCC; if (templ == 1) - crs[KEYS] |= 0100; + SETEQ; else if (templ <= 0) - crs[KEYS] |= 0200; + SETLT; break; case 1: @@ -7773,9 +7954,9 @@ imodepcl: if ((utempl + (~utempa & 0xFFFF) + 1) & 0x10000) crs[KEYS] |= 020000; if (crs[dr*2] == utempa) - crs[KEYS] |= 0100; + SETEQ; else if (*(short *)(crs+dr*2) < *(short *)&utempa) - crs[KEYS] |= 0200; + SETLT; continue; case 072: @@ -7826,21 +8007,21 @@ imodepcl: TRACE(T_FLOW, " DMH\n"); tempa = get16(ea); put16(tempa-1, ea); - crs[KEYS] &= ~0300; + CLEARCC; /* NOTE: test pre-decremented values to get true LT (overflow) */ if (tempa == 1) - crs[KEYS] |= 0100; + SETEQ; else if (tempa <= 0) - crs[KEYS] |= 0200; + SETLT; break; case 6: TRACE(T_FLOW, " TCNP\n"); if (*(int *)&ea > 0) if ((get32(ea) & 0x1FFFFFFF) == 0) - crs[KEYS] |= 0100; + SETEQ; else - crs[KEYS] &= ~0100; + crs[KEYS] &= ~0100; /* clear EQ */ else fault(UIIFAULT, RPL, RP); break; @@ -7986,13 +8167,13 @@ nonimode: crs[KEYS] |= 020000; /* NOTE: this EQ test prevents reusing the ADD code :( */ if (*(int *)(crs+L) == 0) /* set EQ? */ - crs[KEYS] |= 0100; + SETEQ; if (((~utempa ^ m) & (utempa ^ crs[A])) & 0x8000) { if (*(int *)(crs+L) >= 0) - crs[KEYS] |= 0200; + SETLT; mathexception('i', FC_INT_OFLOW, 0); } else if (*(int *)(crs+L) < 0) - crs[KEYS] |= 0200; + SETLT; } continue; @@ -8017,13 +8198,13 @@ nonimode: if (utempl & 0x10000) /* set L-bit if carry */ crs[KEYS] |= 020000; if (*(int *)(crs+L) == 0) /* set EQ? */ - crs[KEYS] |= 0100; + SETEQ; if (((utempa ^ m) & (utempa ^ crs[A])) & 0x8000) { if (*(int *)(crs+L) >= 0) - crs[KEYS] |= 0200; + SETLT; mathexception('i', FC_INT_OFLOW, 0); } else if (*(int *)(crs+L) < 0) - crs[KEYS] |= 0200; + SETLT; } continue; @@ -8076,25 +8257,25 @@ nonimode: if (utempl & 0x10000) /* set L-bit if carry */ crs[KEYS] |= 020000; if (crs[A] == 0) /* set EQ? */ - crs[KEYS] |= 0100; + SETEQ; if (((utempa ^ m) & (utempa ^ crs[A])) & 0x8000) { if (*(short *)(crs+A) >= 0) - crs[KEYS] |= 0200; + SETLT; } else if (*(short *)(crs+A) < 0) - crs[KEYS] |= 0200; + SETLT; crs[A] = utempa; /* restore A reg */ if (crs[A] == m) RPL++; else if (*(short *)(crs+A) < *(short *)&m) RPL += 2; #else - crs[KEYS] &= ~0300; + CLEARCC; if (crs[A] == m) { RPL++; - crs[KEYS] |= 0100; + SETEQ; } else if (*(short *)(crs+A) < *(short *)&m) { RPL += 2; - crs[KEYS] |= 0200; + SETLT; } XSETL(0); #endif @@ -8370,137 +8551,108 @@ nonimode: case 00601: TRACE(T_FLOW, " FAD\n"); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - TRACE(T_INST, " FAC value=%f, FEXP=%d (dec), FLTH='%o, FLTL='%o\n", tempf, crs[FEXP], crs[FLTH], crs[FLTL]); - *(int *)&tempf1 = get32(ea); - prieee4(&tempf1); - TRACE(T_INST, " ea value=%f, EXP=%d (dec), ea H='%o, ea L='%o\n", tempf1, get16(ea+1) & 0xFF, get16(ea), get16(ea+1) & 0xFF00); - tempf += tempf1; - tempf1 = tempf; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - TRACE(T_INST, " FAC value=%f, FEXP=%d (dec), FLTH='%o, FLTL='%o\n", tempf1, crs[FEXP], crs[FLTH], crs[FLTL]); - XEXPC(0); + tempd2 = prieee4(get32(ea)); + if (prieee8(crs+FLTH, &tempd1)) { + *(double *)(crs+FLTH) = ieeepr8(tempd1+tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); continue; /* this is implemented as a subtract on some models */ case 01101: TRACE(T_FLOW, " FCS\n"); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - TRACE(T_INST, " FAC value=%f, FEXP=%d (dec), FLTH='%o, FLTL='%o\n", tempf, crs[FEXP], crs[FLTH], crs[FLTL]); - *(int *)&tempf1 = get32(ea); - prieee4(&tempf1); - TRACE(T_INST, " ea value=%f, EXP=%d (dec), ea H='%o, ea L='%o\n", tempf1, get16(ea+1) & 0xFF, get16(ea), get16(ea+1) & 0xFF00); - crs[KEYS] &= ~0300; - if (tempf == tempf1) { - RPL++; - crs[KEYS] |= 0100; - } else if (tempf < tempf1) { - RPL += 2; - crs[KEYS] |= 0200; - } + CLEARCC; + tempd2 = prieee4(get32(ea)); + if (prieee8(crs+FLTH, &tempd1)) { + if (tempd1 == tempd2) { + RPL++; + SETEQ; + } else if (tempd1 < tempd2) { + RPL += 2; + SETLT; + } + } else + mathexception('f', FC_SFP_OFLOW, ea); continue; case 01701: TRACE(T_FLOW, " FDV\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - *(int *)&tempf1 = get32(ea); - prieee4(&tempf1); - tempf /= tempf1; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - XEXPC(0); + tempd2 = prieee4(get32(ea)); + if (prieee8(crs+FLTH, &tempd1)) + if (tempd2 != 0.0) { + *(double *)(crs+FLTH) = ieeepr8(tempd1/tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_ZDIV, ea); + else + mathexception('f', FC_SFP_OFLOW, ea); continue; case 0201: TRACE(T_FLOW, " FLD\n"); utempl = get32(ea); -#if 1 - crs[FLTH] = utempl >> 16; - crs[FLTL] = utempl & 0xFF00; - crs[FEXP] = utempl & 0xFF; - crs[FLTD] = 0; -#else crsl[FAC1] = utempl & 0xFFFFFF00; - crsl[FAC1+1] = (utempl & 0xFF) << 16; -#endif - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); + crsl[FAC1+1] = utempl & 0x00FF; continue; case 01601: TRACE(T_FLOW, " FMP\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - *(int *)&tempf1 = get32(ea); - prieee4(&tempf1); - tempf *= tempf1; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - XEXPC(0); + tempd2 = prieee4(get32(ea)); + if (prieee8(crs+FLTH, &tempd1)) { + *(double *)(crs+FLTH) = ieeepr8(tempd1*tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); continue; case 00701: TRACE(T_FLOW, " FSB\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - *(int *)&tempf = (crs[FLTH]<<16) | (crs[FLTL] & 0xFF00) | (crs[FEXP] & 0xFF); - prieee4(&tempf); - *(int *)&tempf1 = get32(ea); - prieee4(&tempf1); - tempf -= tempf1; - ieeepr4(&tempf); - crs[FLTH] = (*(unsigned int *)&tempf) >> 16; - crs[FLTL] = (*(unsigned int *)&tempf) & 0xFF00; - crs[FEXP] = (*(unsigned int *)&tempf) & 0xFF; - XEXPC(0); + tempd2 = prieee4(get32(ea)); + if (prieee8(crs+FLTH, &tempd1)) { + *(double *)(crs+FLTH) = ieeepr8(tempd1-tempd2); + XCLEARC; + } else + mathexception('f', FC_SFP_OFLOW, ea); continue; case 0401: TRACE(T_FLOW, " FST\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - if (crs[FEXP] & 0xFF00) + if ((crsl[FAC1+1] & 0xFF00) == 0) { + /* XXX: round here if enabled in keys */ + put32((crsl[FAC1] & 0xFFFFFF00) | (crsl[FAC1+1] & 0xFF), ea); + CLEARC; + } else mathexception('f', FC_SFP_STORE, ea); - put16(crs[FLTH],ea); - put16((crs[FLTL] & 0xFF00) | crs[FEXP],ea+1); - CLEARC; continue; case 0602: TRACE(T_FLOW, " DFAD\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - tempd = get64(ea); - prieee8(&tempd); - *(double *)tempda += tempd; - ieeepr8(tempda); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; - XEXPC(0); + XCLEARC; + tempd2 = get64(ea); + if (prieee8(crs+FLTH, &tempd1) && prieee8(&tempd2, &tempd2)) + *(double *)(crs+FLTH) = ieeepr8(tempd1+tempd2); + else + mathexception('f', FC_DFP_OFLOW, ea); continue; case 01102: TRACE(T_FLOW, " DFCS\n"); + CLEARCC; +#if 1 + tempd2 = get64(ea); + if (prieee8(crs+FLTH, &tempd1) && prieee8(&tempd2, &tempd2)) { + if (tempd1 == tempd2) { + RPL++; + SETEQ; + } else if (tempd1 < tempd2) { + RPL += 2; + SETLT; + } + } else + mathexception('f', FC_DFP_OFLOW, ea); +#else m = get16(ea); if ((crs[FLTH] & 0x8000) == (m & 0x8000)) { m1 = get16(INCVA(ea,3)); @@ -8509,6 +8661,7 @@ nonimode: utempl = get32(INCVA(ea,1)); if ((unsigned int)((crs[FLTL]<<16) | crs[FLTD]) == utempl) RPL += 1; + /* XXX: does this next test need to be reversed for negative numbers? */ else if ((unsigned int)((crs[FLTL]<<16) | crs[FLTD]) < utempl) RPL += 2; } else if (crs[FLTH] < m) @@ -8517,104 +8670,50 @@ nonimode: RPL += 2; } else if (crs[FLTH] & 0x8000) /* DAC < mem */ RPL += 2; - -#if 0 - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - printf(" FLTH=%x FLTL=%x FLTD=%x FEXP=%x, value=%e\n", crs[FLTH], crs[FLTL], crs[FLTD], crs[FEXP], *(double *)tempda); - tempd = get64(ea); - prieee8(&tempd); - printf(" ea H=%x ea L=%x ea D=%x ea X=%x, value=%e\n", get16(ea), get16(ea+1), get16(ea+2), get16(ea+3), tempd); - crs[KEYS] &= ~0300; - if (*(double *)tempda == tempd) { - RPL++; - crs[KEYS] |= 0100; - } else if (*(double *)tempda < tempd) { - RPL += 2; - crs[KEYS] |= 0200; - } #endif continue; case 01702: TRACE(T_FLOW, " DFDV\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - tempd = get64(ea); - prieee8(&tempd); - *(double *)tempda /= tempd; - ieeepr8(tempda); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; - XEXPC(0); + tempd2 = get64(ea); + if (prieee8(crs+FLTH, &tempd1) && prieee8(&tempd2, &tempd2)) + if (tempd2 != 0.0) { + *(double *)(crs+FLTH) = ieeepr8(tempd1/tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_ZDIV, ea); + else + mathexception('f', FC_DFP_OFLOW, ea); continue; case 0202: TRACE(T_FLOW, " DFLD\n"); - *(double *)tempda = get64(ea); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; + *(double *)(crs+FLTH) = get64(ea); continue; case 01602: TRACE(T_FLOW, " DFMP\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - tempd = get64(ea); - prieee8(&tempd); - *(double *)tempda *= tempd; - ieeepr8(tempda); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; - XEXPC(0); + tempd2 = get64(ea); + if (prieee8(crs+FLTH, &tempd1) && prieee8(&tempd2, &tempd2)) { + *(double *)(crs+FLTH) = ieeepr8(tempd1*tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); continue; case 0702: TRACE(T_FLOW, " DFSB\n"); - TRACE(T_INST, " FEXP=%d (dec), FLTH='%o, FLTL='%o\n", crs[FEXP], crs[FLTH], crs[FLTL]); - //TRACE(T_INST, " ea EXP=%d (dec), ea H='%o, ea L='%o\n", (mem[ea+1] & 0xFF), mem[ea], (mem[ea+1] & 0xFF00)); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - prieee8(tempda); - tempd = get64(ea); - prieee8(&tempd); - *(double *)tempda -= tempd; - ieeepr8(tempda); - crs[FLTH] = tempda[0]; - crs[FLTL] = tempda[1]; - crs[FLTD] = tempda[2]; - crs[FEXP] = tempda[3]; - XEXPC(0); + tempd2 = get64(ea); + if (prieee8(crs+FLTH, &tempd1) && prieee8(&tempd2, &tempd2)) { + *(double *)(crs+FLTH) = ieeepr8(tempd1-tempd2); + XCLEARC; + } else + mathexception('f', FC_DFP_OFLOW, ea); continue; case 0402: TRACE(T_FLOW, " DFST\n"); - tempda[0] = crs[FLTH]; - tempda[1] = crs[FLTL]; - tempda[2] = crs[FLTD]; - tempda[3] = crs[FEXP]; - put64(*(double *)tempda, ea); + put64(*(double *)(crs+FLTH), ea); continue; case 01302: diff --git a/fp.c b/fp.c deleted file mode 100644 index 79551e3..0000000 --- a/fp.c +++ /dev/null @@ -1,304 +0,0 @@ -/* ** general conversion doc here, or (referenced) above. ***************** */ -/* doc exponent details here: (-1 & bin pt. placement by prieee) vs. - vs. (-2 by ieeepr()): note that - IEEE denormalized bin pxxxxxxx prime (relative to the 23 bits); - in ieeepr the trick is to treat normalized #'s as the special case. */ - - -void prieee4(xlongp) /* ****** convert from Prime to IEEE. ****** */ - long *xlongp; -{ - long xlong; - long sign; /* sign */ - long mant; /* mantissa: note this is signed: mant = -mant below */ - long exp; /* exponent */ - -/* note: when converting form Prime to IEEE, we need to check for exponent - underflow, but not for overflow. */ - - xlong = *xlongp; - mant = xlong & 0xffffff00; /* 24 bits: includes sign bit */ - sign = mant & 0x80000000; - mant >>= 8; /* ok to trash upper byte, which will get masked out. */ - if (sign) - mant = - mant; - /* now have 24 bit # w/ leading 0. */ - - exp = (xlong & 0x000000ff) - 1; /* exp now in excess 127 (IEEE) form. */ - - if (exp < 0) { - mant >>= 1; /* tiny tiny #; will get shifted once more below. */ - ++exp; /* Bring exp back up to 0. */ - } - else /* *** normalize the mantissa. If input Prime mantissa was already - noramalized, this loop will still execute once, unless input # - was -(2**n) in which case it will execute 0 times. This is - because Prime mantissas are 2's compliment, and powers of 2 - normalize differently when negated. Note no loop for 0 exp. */ - while (exp && !(mant & 0x00800000)) { - mant <<= 1; - --exp; - } - - /* we now have a 24 bit unsigned # w/ a leading 1. If the exponent is > 0, - we are all set: the resulting IEEE number will be normalized. This - leading (hidden) IEEE 1 will be masked out below. */ - if ( ! exp) /* result must be denormalized: shift 1 further to */ - mant >>= 1; /* include IEEE leading bit, which may be 0 or 1. */ - - mant &= 0x007fffff; - exp <<= 23; - *xlongp = sign | exp | mant; -} - - -void ieeepr4(xlongp) /* ****** convert from IEEE to Prime. ****** */ - long *xlongp; -{ - long xlong; - long sign; /* sign */ - long mant; /* mantissa: note this is signed: mant = -mant below */ - long exp; /* exponent */ - long templ; - -/* note: when converting form Prime to IEEE, we need to check for exponent - overflow, but not for underflow. */ - xlong = *xlongp; - - if ( ! (xlong & 0x7fffffff)) - *xlongp = 0; /* +0 or -0 */ - else { - sign = xlong & 0x80000000; - mant = (xlong & 0x007fffff) << 8; /* assume denormalized, adjust below */ - exp = (xlong & 0x7f800000) >> 23; /* still in excess 127 (IEEE) form. */ - if (exp == 0xff) { /* NaN (not a number) or +/- infinity? */ - if (mant == 0) { - /* +/- infinity. */ - if (sign == 0) - *xlongp = 0x7fffffff; /* largest Prime # in for +infinity. */ - else /* note: 0x800000ff cant be negated; */ - *xlongp = 0x800001ff; /* use - 0x7fffffff for -infinity. */ - } - else { - /* NaN (not a number) */ - if (sign == 0) - *xlongp = 0x539733ff; /* use 1.11111e+38 for NaN, since */ - else /* it stands out if printed. */ - *xlongp = 0xac68cdff; /* use -1.11111e+38 for -NaN. */ - } - } - else { /* actual number */ - if (exp != 0) { - if(mant != 0x7fffff00)/* Special case of mantissa value of all 1s*/ - mant = (mant >> 1) + 0x40000080; /* ieee normalized number: */ - /* shift to make room for */ - /* hidden leading 1 bit, 'or'*/ - /* it in and round truncated */ - /* LSBit up. */ - mant &= 0xffffff00; - } - exp += 2; /* exp now in excess 128 (Prime) form. */ - - if (sign != 0) /* sign bit of mant will be 0 at this point. */ - mant = - mant; - /* mant is now a 24 bit signed mantissa (shifted to Prime position) */ - - /* *** normalize the number. In most cases, the number will already - be normalized. Negative powers of 2 will be shifted once, since - they normalize differently. IEEE denormalized numbers can be - adjusted at most 2 bits, due to the excess 127 vs. 128 exponent and - binary point position differences (cant negate exponent). *** */ - while (exp && ((~(mant^(mant<<1))) & 0x80000000)) { - mant <<= 1; /* sign and next most significant */ - --exp; /* bit are equal: normalize. */ - } - if (exp > 0xff) { - if ( ! sign) - *xlongp = 0x7fffffff; /* largest Prime # in for +infinity. */ - else /* note: 0x800000ff cant be negated; */ - *xlongp = 0x800001ff; /* use - 0x7fffffff for -infinity. */ - } - else - *xlongp = mant | exp; /* mant is signed; */ - } - } -} - - -#define l1 0 -#define l0 1 - -/* ** general conversion doc here, or (referenced) above. ***************** */ -/* doc exponent details here: (-1 & bin pt. placement by prieee) vs. - vs. (-2 by ieeepr()): note that - IEEE denormalized bin pxxxxxxx prime (relative to the 23 bits); - in ieeepr the trick is to treat normalized #'s as the special case. */ - - -void prieee8(xlongp) /* ****** convert from Prime to IEEE. ****** */ - long *xlongp; -{ - long xlong1,xlong0; - long mant1,mant0; /* mantissa: these are signed: mant = -mant below */ - long sign; /* sign */ - long exp; /* exponent */ - -/* note: when converting REAL*8 form Prime to IEEE, we need to check for both - exponent underflow, and overflow. */ - - xlong1 = xlongp[l1]; /* high 4 bytes */ - xlong0 = xlongp[l0]; /* low 4 bytes */ - sign = xlong1 & 0x80000000; - mant1 = xlong1 >> 11; /* 48 bits, includes */ - mant0 = (xlong1 << 21) | ((xlong0 >> 11) & 0xfffe0); /* includes sign bit */ - - if ( ! mant0 && ! mant1) { /* zero (dirty or otherwise)? */ - xlongp[l1] = xlongp[l0] = 0; - return; /* return ****** */ - } - if (sign) { /* 2's comp mant1/mant0 pair */ - mant0 = - mant0; - mant1 = ~ mant1; - if ( ! mant0) - ++ mant1; /* mant0==0: have a carry fr. mant0 to mant1. */ - } - - /* now have 48 bit # w/ leading 0. */ - - exp = (xlong0 & 0xffff) - 0x80; /* convert 16 bit */ - if (exp & 0x8000) /* Prime exponent */ - exp |= 0xffff0000; /* from "excess 128" */ - else /* form to 2's */ - exp &= 0x0000ffff; /* complement form. */ - exp += 0x3ff; /* exp now in excess 1023 (IEEE) form. */ - - if (exp < -50) { /* Prime exp too small? */ - xlongp[l1] = xlongp[l0] = 0; /* closest IEEE is 0. */ - return; /* return ****** */ - } - - if (exp < 0) { - /* note: can still get 0, iff have leading (non sign bit) 0's */ - mant0 = (mant1 << 32+exp) | (mant0 >> -exp); /* mant >>= -exp; */ - mant1 >>= -exp; /* tiny tiny #; will get shifted once more below. */ - ++mant0; /* lsb will get lost below, since # is denormalized; round */ - if ( ! mant0) - ++mant1; - exp = 0; /* exp += -exp. */ - } - else /* *** normalize the mantissa. */ - while (exp && !(mant1 & 0x00100000)) { - mant1 <<= 1; - if (mant0 & 0x80000000) - mant1 |= 1; - mant0 <<= 1; - --exp; - } - - if (exp > 0x7fe) { - xlongp[l1] = sign | 0x7fefffff; /* Prime exp too big; closest */ - xlongp[l0] = 0xffffffff; /* closest IEEE is (+/-) max. */ - } - else { - /* we now have a 48 bit unsigned # w/ a leading 1. If the exponent is - > 0, we are all set: the resulting IEEE number will be normalized. - This leading (hidden) IEEE 1 will be masked out below. */ - if ( ! exp) { /* result must be denormalized: shift 1 further to */ - mant0 >>= 1; /* include IEEE leading bit, which may be 0 or 1. */ - if (mant1 & 1) - mant0 |= 0x80000000; - mant1 >>= 1; - } - mant1 &= 0x000fffff; - exp <<= 20; - xlongp[l1] = sign | exp | mant1; - xlongp[l0] = mant0; - } -} - - -void ieeepr8(xlongp) /* ****** convert from IEEE to Prime. ****** */ - long *xlongp; -{ - long xlong1,xlong0; - long mant1,mant0; /* mantissa: these are signed: mant = -mant below */ - long sign; /* sign */ - long exp; /* exponent */ - -/* note: when converting REAL*8 form Prime to IEEE, we dont need to check for - exponent overflow, or underflow. */ - xlong1 = xlongp[l1]; /* high 4 bytes */ - xlong0 = xlongp[l0]; /* low 4 bytes */ - - if ((xlong1 & 0x7fffffff) == 0 && xlong0 == 0) { - xlongp[l1] = xlongp[l0] = 0; /* +0 or -0 */ - return; /* return ****** */ - } - sign = xlong1 & 0x80000000; - exp = (xlong1 & 0x7ff00000) >> 20; /* still in excess 1023 (IEEE) form. */ - mant1 = ((xlong1 & 0xfffff) << 11) | ((xlong0 >> 21) & 0x7ff); - mant0 = xlong0 << 11; /* assume denormalized, adjust below */ - if (exp == 0x7ff) { /* NaN (not a number) or +/- infinity? */ - if (mant1 == 0 && mant0 == 0) { - /* +/- infinity. */ - if (sign == 0) { - xlongp[l1] = 0x7fffffff; /* largest Prime # in for +infinity. */ - xlongp[l0] = 0xffffffff; - } - else { /* note: 0x80000000 0000ffff cant be */ - xlongp[l1] = 0x80000000; /* negated, use -0x7fffffff ffffffff */ - xlongp[l0] = 0x0001ffff; /* -infinity. */ - } - } - else { - /* NaN (not a number) */ - if (sign == 0) { - xlongp[l1] = 0x7fffffff; /* For now, use +/- infinity values */ - xlongp[l0] = 0xffffffff; /* for +/- NaN. */ - } - else { - xlongp[l1] = 0x80000000; - xlongp[l0] = 0x0001ffff; - } - } - } - else { /* actual number */ - if (exp != 0) { - /* ieee normalized number: shift mantissa to make room for hidden */ - mant0 >>= 1; /* leading 1 bit and 'or' it in. */ - if (mant1 & 1) - mant0 |= 0x80000000; - else - mant0 &= 0x7fffffff; - mant1 >>= 1; - mant1 |= 0x40000000; - } - exp -= 894; /* exp now in 'excess 128' (Prime) form. */ - - mant0 &= 0xffff0000; - if (sign) { /* sign bit of mant will be 0 at this point. */ - mant0 |= 0xffff; /* 2's comp mant1/mant0 pair */ - mant0 = - mant0; - mant1 = ~ mant1; - if ( ! mant0) - ++ mant1; /* mant0==0: have a carry fr. mant0 to mant1. */ - } - /* mant is now a 48 bit signed mantissa (shifted to Prime position) */ - - /* *** normalize the number. In most cases, the number will already - be normalized. Negative powers of 2 will be shifted once, since - they normalize differently. IEEE denormalized numbers can be - adjusted at most 2 bits, due to the excess 127 vs. 128 exponent and - binary point position differences (cant negate exponent). *** */ - while (exp && ((~(mant1^(mant1<<1))) & 0x80000000)) { - mant1 <<= 1; /* sign and next most significant */ - if (mant0 & 0x80000000) /* bit are equal: normalize. */ - mant1 |= 1; - mant0 <<= 1; - --exp; - } - mant0 &= 0xffff0000; - xlongp[l1] = mant1; /* mant is signed; no sign to 'or' in. */ - xlongp[l0] = mant0 | exp; - } -} diff --git a/fp.h b/fp.h new file mode 100644 index 0000000..ef05d75 --- /dev/null +++ b/fp.h @@ -0,0 +1,367 @@ +/* fp.h, Jim Wilcoxson, June 2007 + Floating point conversion and helper routines for the Prime emulator. + + Prime DPFP format: + - 48 mantissa bits stored in 2's complement format + - 16 exponent bits stored in 2's complement with a bias of 128 + - exponent follows the mantissa in both memory and registers + - some early Primes store the exponent in the 3rd halfword + - the leading "1" bit in the mantissa is only suppressed for negative + powers of 2 + - Prime treats zero mantissa as 0.0, even if exponent is non-zero + - all FP operations are carried out in double precision + + IEEE DPFP format: + - 1 sign bit + - 11 exponent bits with a bias of 1023 + - 52 mantissa bits (sign-magnitude format) + - leading bit of mantissa has a suppressed "1" (except subnormal) + - if exponent is zero: + - and frac = 0 => positive or negative zero, depending on sign + - and frac non-zero => subnormal (aka denormal, unnormalized) + - subnormals have an implied leading "0" bit (XXX: true??) +*/ + + +/* getdp unpacks a Prime DPFP into 48-bit sign + mantissa (left + justified in 64 bits) and a 32-bit signed exponent */ + +inline getdp (void *p, long long *frac64, int *exp32) { + + *frac64 = *(long long *)p & 0xFFFFFFFFFFFF0000LL; /* unpack fraction */ + *exp32 = *((short *)p+3); /* unpack SIGNED exponent */ +} + +inline putdp (void *p, long long frac64, int exp32) { + + *(long long *)p = (frac64 & 0xFFFFFFFFFFFF0000LL) | (exp32 & 0xFFFF); +} + + +/* Conversion from Prime DPFP to IEEE DPFP + Returns true if conversion succeeded, false if it failed. + Conversions may fail because Prime exponents are 16 bits whereas + IEEE DPFP exponents are only 11 bits. +*/ + +int prieee8(void *dp, double *d) { + long long frac64, sign; + int exp32; + + /* unpack Prime DPFP */ + + getdp (dp, &frac64, &exp32); + + /* if negative, change to sign-magnitude */ + + sign = 0; + if (frac64 < 0) { + + /* special case: negative power of 2 */ + + if (frac64 == 0x8000000000000000LL) { + exp32 += (1023-128); + if (exp32 < 0 || exp32 > 0x3ff) + return 0; + frac64 |= ((long long)exp32 << 52); + *d = *(double *)&frac64; + return 1; + } else { + sign = 0x8000000000000000LL; + frac64 = -frac64; + } + + /* special case: zero */ + + } else if (frac64 == 0) { + *d = 0.0; + return 1; + } + + /* normalize positive fraction until bit 2 is 1 */ + + while ((*(int *)&frac64 & 0x40000000) == 0) { + frac64 = frac64 << 1; + exp32--; + } + + /* adjust exponent bias and check range */ + + exp32 += (1023-128) - 1; + if (exp32 < 0 || exp32 > 0x7ff) + return 0; + + /* pack into an IEEE DPFP, losing the leading 1 bit in the process */ + + frac64 = sign | ((long long)exp32 << 52) | ((frac64 >> 10) & 0xfffffffffffffLL); + *d = *(double *)&frac64; + return 1; +} + +/* Conversion from Prime SPFP to IEEE DPFP */ + +double prieee4(unsigned int sp) { + int frac32, sign; + long long frac64; + int exp32; + + /* unpack Prime SPFP */ + + frac32 = sp & 0xFFFFFF00; + exp32 = sp & 0xFF; + + /* if negative, change to sign-magnitude */ + + sign = 0; + if (frac32 < 0) { + + /* special case: negative power of 2 */ + + if (frac32 == 0x80000000) { + exp32--; + frac64 = 0x8000000000000000LL | ((long long)exp32 << 52); + return *(double *)&frac64; + } else { + sign = 0x80000000; + frac32 = -frac32; + } + + /* special case: zero */ + + } else if (frac32 == 0) + return 0.0; + + /* normalize positive fraction until bit 2 is 1 */ + + while ((frac32 & 0x40000000) == 0) { + frac32 = frac32 << 1; + exp32--; + } + + /* adjust exponent bias and check range */ + + exp32 += (1023-128) - 1; + + /* pack into an IEEE DPFP, losing the leading 1 bit in the process */ + + frac64 = (long long)sign | ((long long)exp32 << 52) | (((long long)frac32 << 22) & 0xfffffffffffffLL); + return *(double *)&frac64; +} + + +/* conversion from IEEE back to Prime. Prime exponents are larger, so + this conversion cannot overflow/underflow, but precision is lost */ + +double ieeepr8(double d) { + long long frac64; + int exp32, neg; + + /* unpack IEEE DPFP */ + + *(double *)&frac64 = d; + neg = frac64 < 0; + exp32 = (frac64 >> 52) & 0x7ff; + frac64 &= 0xfffffffffffffLL; + //printf("dp=%llx, neg=%d, frac64=%llx, exp32=%d, \n", *(long long *)dp, neg, frac64, exp32); + + /* special case: NaN & +-infinity (these shouldn't happen!) */ + + if (exp32 == 0x7ff) { + if (frac64 == 0) + if (neg) + printf("em: +infinity in ieeepr8\n"); + else + printf("em: -infinity in ieeepr8\n"); + else + printf("em: NaN in ieeepr8\n"); + return 0.0; + } + + /* add back the hidden "1" bit except for the special cases +-0.0 + and subnormal */ + + if (exp32 != 0) /* typical IEEE normalized */ + frac64 |= 0x10000000000000LL; + else if (frac64 == 0) /* IEEE +-0.0 (zero exp+frac) */ + return 0.0; /* IEEE and Prime zero are the same */ + else + ; /* subnormal: no hidden 1 bit */ + + /* adjust exponent, change sign-magnitude to 2's complement, + and shift fraction into Prime placement (high 48 bits) */ + + exp32 -= (1023-128) - 1; + if (neg) + frac64 = -frac64; + frac64 <<= 10; + + /* normalize Prime DPFP */ + + while ((frac64 ^ (frac64 << 1)) >= 0) { + frac64 = frac64 << 1; + exp32--; + } + +#if 0 + if (exp32 > 32767 || exp32 < -32768) { + printf("em: exponent = %d in ieeepr8\n", exp32); + return 0.0; + } +#endif + + /* round the fraction to 48 bits, ensuring no overflow */ + + if ((frac64 & 0x8000) && ((frac64 & 0x7fffffffffff0000LL) != 0x7fffffffffff0000LL)) + /* XXX: should this be a subtract for negative numbers? */ + frac64 += 0x10000; + + frac64 = (frac64 & 0xffffffffffff0000LL) | (exp32 & 0xffff); + return *(double *)&frac64; +} + + +/* 32-bit signed integer to Prime DPFP conversion */ + +double fltl (int int32) { + long long frac64; + int exp32, sign32; + + /* have to special case zero, or we end up with + a "dirty zero" (zero fraction, exponent of 128) */ + + if (int32 == 0) + return 0.0; + + exp32 = 128+31; + sign32 = int32 & 0x80000000; + if ((int32 & 0xFFFF8000) == sign32>>16) { + int32 = int32<<16; + exp32 -= 16; + } + if ((int32 & 0xFF800000) == sign32>>8) { + int32 = int32<<8; + exp32 -= 8; + } + if ((int32 & 0xF8000000) == sign32>>4) { + int32 = int32<<4; + exp32 -= 4; + } + if ((int32 & 0xE0000000) == sign32>>2) { + int32 = int32<<2; + exp32 -= 2; + } + if ((int32 & 0xC0000000) == sign32>>1) { + int32 = int32<<1; + exp32 -= 1; + } + frac64 = ((long long)int32 << 32) | exp32; + return *(double *)&frac64; +} + + +/* Prime DPFP complement */ + +dfcm (void *dp) { + long long frac64; + int exp32; + + CLEARC; + getdp(dp, &frac64, &exp32); + if (frac64 != 0) { /* can't normalize zero */ + if (frac64 == 0x8000000000000000LL) { /* overflow case? */ + frac64 = 0x4000000000000000LL; /* complement power of 2 */ + exp32 += 1; + } else { + frac64 = -frac64; /* complement fraction */ + while ((frac64 ^ (frac64 << 1)) >= 0) { + frac64 = frac64 << 1; /* normalize */ + exp32--; + } + } + if (exp32 > 32767 || exp32 < -32768) + mathexception('f', FC_DFP_OFLOW, 0); + else + putdp(dp, frac64, exp32); + } +} + + +/* double precision floating point normalize + + Passed a pointer to a Prime double precision variable and updates + it in place. May set the C-bit or cause a floating point + exception. */ + +void norm(void *dp) { + long long frac64; + int exp32; + + getdp(dp, &frac64, &exp32); + while ((frac64 ^ (frac64 << 1)) >= 0) { + frac64 = frac64 << 1; + exp32--; + } + + putdp(dp, frac64, exp32); + if (exp32 > 32767 || exp32 < -32768) + mathexception('f', FC_DFP_OFLOW, 0); +} + + +/* double->single floating point round (FRN) instruction. + + Passed a pointer to a Prime double precision variable, one of the + FACC's, and updates it in place. May also take an arithmetic fault + if overflow occurs. For faults, the ea is zero because FACC's + don't have an effective address. */ + +void frn(void *dp) { + long long frac64; + int exp32; + int origsign, newsign; + + CLEARC; + getdp(dp, &frac64, &exp32); + if (frac64 == 0) + *(long long *)dp = 0; + else { + origsign = (frac64 < 0); + if ((frac64 & 0x18000000000LL) + | ((frac64 & 0x8000000000LL) && (frac64 & 0x7FFFFF0000LL))) { + frac64 += 0x10000000000LL; + frac64 &= 0xFFFFFF0000000000LL; + norm(&frac64); + *(long long *)dp = frac64; + newsign = (frac64 < 0); + if (newsign != origsign) + /* XXX: is this fault code right? */ + mathexception('f', FC_DFP_OFLOW, 0); + } + } +} + +#if 0 + +/* Prime DPFP multiply */ + +dfmp(void *dp1, void *dp2, ea_t ea) { + long long frac64, frac641, frac642; + int exp32, exp321, exp322; + short fcode; + + fcode = 0; + CLEARC; + getdp(dp1, &frac641, &exp321); + getdp(dp2, &frac642, &exp322); + exp32 = exp321 + exp322; + /* XXX: need to get 128-bit result to test for overflow? */ + frac64 = frac641 * frac642; + if (exp32 > 32767 || exp32 < -32768) + fcode = FC_DFP_OFLOW; + /* insert (optional) rounding code here */ + if (fcode == 0) + putdp(dp1, frac64, exp32); + else + mathexception('f', fcode, ea); +} +#endif