/* This file is in the public domain. */ #include /* Floating-point instructions are in finstrs.c */ #include "pdp11.h" #include "driver.h" #include "instrs.h" #define BYTEVERSION 0100000 #define REG(n) (*regs[(n)]) extern int intrq_pri; /* Auxiliaries */ static word op_w; static byte op_b; static void I_adc_b(void *vp) { byte b; if (psw & PSW_C) { b = (*(byte *)vp + 1) & 0xff; if (b == 0) SET_C(); else CLR_C(); if (b == 0x80) SET_V(); else CLR_V(); } else { b = *(byte *)vp; CLR_C(); CLR_V(); } if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); *(byte *)vp = b; } static void I_adc_w(void *vp) { word w; if (psw & PSW_C) { w = (*(word *)vp + 1) & 0xffff; if (w == 0) SET_C(); else CLR_C(); if (w == 0x8000) SET_V(); else CLR_V(); } else { w = *(word *)vp; CLR_C(); CLR_V(); } if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); *(word *)vp = w; } static void I_add_(void *vp) { int w1; int w2; word sum; int isum; w1 = 0xffff & (int)*(word *)vp; w2 = 0xffff & (int)op_w; isum = w1 + w2; sum = isum & 0xffff; if (sum == 0) SET_Z(); else CLR_Z(); if (sum & 0x8000) SET_N(); else CLR_N(); if (((w1^w2) & 0x8000) || !((w1^sum) & 0x8000)) CLR_V(); else SET_V(); if (isum & 0x10000) SET_C(); else CLR_C(); *(word *)vp = sum; } static void I_ash_(int rno, int sc) { word r; r = REG(rno); CLR_V(); if (sc & 040) /* -ve: right */ { sc = 0100 - sc; if (sc > 15) { r = (r & 0x8000) ? 0xffff : 0; if (r) SET_C(); else CLR_C(); } else { if (r & (1 << (sc-1))) SET_C(); else CLR_C(); if (r & 0x8000) { r = (r | 0xffff0000) >> sc; } else { r >>= sc; } } } else if (sc) /* +ve: left */ { if (sc > 15) { if ((sc == 16) && (r & 1)) SET_C(); else CLR_C(); if (r) SET_V(); else CLR_V(); r = 0; } else { for (;sc>0;sc--) { if (r & 0x8000) SET_C(); else CLR_C(); if ("\0\1\1\0"[r>>14]) SET_V(); r <<= 1; } } } else { CLR_C(); } REG(rno) = r; if (r == 0) SET_Z(); else CLR_Z(); if (r & 0x8000) SET_N(); else CLR_N(); } static void I_asl_b(void *vp) { int i; byte b; i = (0xff&(int)*(byte *)vp) << 1; b = i & 0xff; if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); if (i & 0x100) SET_C(); else CLR_C(); if ("\0\1\1\0"[i>>7]) SET_V(); else CLR_V(); *(byte *)vp = b; } static void I_asl_w(void *vp) { int i; word w; i = (0xffff&(int)*(word *)vp) << 1; w = i & 0xffff; if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); if (i & 0x10000) SET_C(); else CLR_C(); if ("\0\1\1\0"[i>>15]) SET_V(); else CLR_V(); *(word *)vp = w; } static void I_asr_b(void *vp) { byte b; b = *(byte *)vp; if (b & 1) SET_C(); else CLR_C(); if ((b & 1) == ((b >> 7) & 1)) CLR_V(); else SET_V(); b = (b >> 1) | (b & 0x80); if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); *(byte *)vp = b; } static void I_asr_w(void *vp) { word w; w = *(word *)vp; if (w & 1) SET_C(); else CLR_C(); if ((w & 1) == ((w >> 15) & 1)) CLR_V(); else SET_V(); w = (w >> 1) | (w & 0x8000); if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); *(word *)vp = w; } static void I_bic_b(void *vp) { byte bs; byte bd; byte res; bs = op_b; bd = *(byte *)vp; res = bd & ~bs; if (res == 0) SET_Z(); else CLR_Z(); if (res & 0x80) SET_N(); else CLR_N(); CLR_V(); *(byte *)vp = res; } static void I_bic_w(void *vp) { word ws; word wd; word res; ws = op_w; wd = *(word *)vp; res = wd & ~ ws; if (res == 0) SET_Z(); else CLR_Z(); if (res & 0x8000) SET_N(); else CLR_N(); CLR_V(); *(word *)vp = res; } static void I_bis_b(void *vp) { byte bs; byte bd; byte res; bs = op_b; bd = *(byte *)vp; res = bd | bs; if (res == 0) SET_Z(); else CLR_Z(); if (res & 0x80) SET_N(); else CLR_N(); CLR_V(); *(byte *)vp = res; } static void I_bis_w(void *vp) { word ws; word wd; word res; ws = op_w; wd = *(word *)vp; res = wd | ws; if (res == 0) SET_Z(); else CLR_Z(); if (res & 0x8000) SET_N(); else CLR_N(); CLR_V(); *(word *)vp = res; } static void I_com_b(void *vp) { byte b; b = 0xff ^ *(byte *)vp; if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); CLR_V(); SET_C(); *(byte *)vp = b; } static void I_com_w(void *vp) { word w; w = 0xffff ^ *(word *)vp; if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); CLR_V(); SET_C(); *(word *)vp = w; } static void I_dec_b(void *vp) { byte b; b = (*(byte *)vp - 1) & 0xff; if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); if (b == 0x7f) SET_V(); else CLR_V(); *(byte *)vp = b; } static void I_dec_w(void *vp) { word w; w = (*(word *)vp - 1) & 0xffff; if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0x7fff) SET_V(); else CLR_V(); *(word *)vp = w; } static void I_inc_b(void *vp) { byte b; b = (*(byte *)vp + 1) & 0xff; if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); if (b == 0x80) SET_V(); else CLR_V(); *(byte *)vp = b; } static void I_inc_w(void *vp) { word w; w = (*(word *)vp + 1) & 0xffff; if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0x8000) SET_V(); else CLR_V(); *(word *)vp = w; } static void I_neg_b(void *vp) { byte b; b = (- *(byte *)vp) & 0xff; if (b == 0) { SET_Z(); CLR_C(); } else { CLR_Z(); SET_C(); } if (b & 0x80) SET_N(); else CLR_N(); if (b == 0x80) SET_V(); else CLR_V(); *(byte *)vp = b; } static void I_neg_w(void *vp) { word w; w = (- *(word *)vp) & 0xffff; if (w == 0) { SET_Z(); CLR_C(); } else { CLR_Z(); SET_C(); } if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0x8000) SET_V(); else CLR_V(); *(word *)vp = w; } static void I_rol_b(void *vp) { int i; i = (0xff&(int)*(byte *)vp) << 1; if (psw & PSW_C) i ++; if (i & 0x100) SET_C(); else CLR_C(); if ("\0\1\1\0"[i>>7]) SET_V(); else CLR_V(); if (i & 0x80) SET_N(); else CLR_N(); if ((i&0xff) == 0) SET_Z(); else CLR_Z(); *(byte *)vp = i & 0xff; } static void I_rol_w(void *vp) { int i; i = (0xffff&(int)*(word *)vp) << 1; if (psw & PSW_C) i ++; if (i & 0x10000) SET_C(); else CLR_C(); if ("\0\1\1\0"[i>>15]) SET_V(); else CLR_V(); if (i & 0x8000) SET_N(); else CLR_N(); if ((i&0xffff) == 0) SET_Z(); else CLR_Z(); *(word *)vp = i & 0xffff; } static void I_ror_b(void *vp) { int i; i = 0xff & (int)*(byte *)vp; if (psw & PSW_C) i |= 0x100; if (i & 1) SET_C(); else CLR_C(); if ((i & 1) == (i >> 8)) CLR_V(); else SET_V(); if (i & 0x100) SET_N(); else CLR_N(); if ((i&0x1fe) == 0) SET_Z(); else CLR_Z(); *(byte *)vp = i >> 1; } static void I_ror_w(void *vp) { int i; i = 0xffff & (int)*(word *)vp; if (psw & PSW_C) i |= 0x10000; if (i & 1) SET_C(); else CLR_C(); if ((i & 1) == (i >> 16)) CLR_V(); else SET_V(); if (i & 0x10000) SET_N(); else CLR_N(); if ((i&0x1fffe) == 0) SET_Z(); else CLR_Z(); *(word *)vp = i >> 1; } static void I_sbc_b(void *vp) { byte b; if (psw & PSW_C) { b = (*(byte *)vp - 1) & 0xff; if (b == 0xff) SET_C(); else CLR_C(); if (b == 0x7f) SET_V(); else CLR_V(); } else { b = *(byte *)vp; CLR_C(); if (b == 0x80) SET_V(); else CLR_V(); } if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); *(byte *)vp = b; } static void I_sbc_w(void *vp) { word w; if (psw & PSW_C) { w = (*(word *)vp - 1) & 0xffff; if (w == 0xffff) SET_C(); else CLR_C(); if (w == 0x7fff) SET_V(); else CLR_V(); } else { w = *(word *)vp; CLR_C(); if (w == 0x8000) SET_V(); else CLR_V(); } if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); *(word *)vp = w; } static void I_sub_(void *vp) { int w1; int w2; word sum; int isum; w1 = 0xffff & (int)*(word *)vp; w2 = 0xffff & (int)op_w; isum = w1 - w2; sum = isum & 0xffff; if (sum == 0) SET_Z(); else CLR_Z(); if (sum & 0x8000) SET_N(); else CLR_N(); if (!((w1^w2) & 0x8000) || ((w2^sum) & 0x8000)) CLR_V(); else SET_V(); if (isum >= 0) CLR_C(); else SET_C(); *(word *)vp = sum; } static void I_swab_(void *vp) { word w; w = *(word *)vp; if (w & 0x8000) SET_N(); else CLR_N(); if (w & 0xff00) CLR_Z(); else SET_Z(); CLR_V(); CLR_C(); *(word *)vp = (w >> 8) | ((w << 8) & 0xffff); } static void I_tstset_(void *vp) { word w; w = *(word *)vp; r0 = w; *(word *)vp = w | 1; } static void I_xor_(void *vp) { word w; w = *(word *)vp ^ op_w; if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); CLR_V(); *(word *)vp = w; } /* Principals */ INST(adc) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_adc_b); } else { rmw_operand_w(inst,I_adc_w); } } INST(add) { op_w = get_operand_w(inst>>6); rmw_operand_w(inst,I_add_); } INST(ash) { I_ash_((inst>>6)&7,get_operand_w(inst)&077); } INST(ashc) { int sc; int rno; sc = get_operand_w(inst) & 077; rno = (inst >> 6) & 7; if (rno & 1) { word r; if (sc & 040) /* -ve: right */ { sc = (0100 - sc) & 15; r = REG(rno); r = (r | (r << 16)) >> sc; } else { I_ash_(rno,sc); return; } r &= 0xffff; REG(rno) = r; if (r == 0) SET_Z(); else CLR_Z(); if (r & 0x8000) SET_N(); else CLR_N(); } else { unsigned long int r; CLR_V(); r = (REG(rno) << 16) | REG(rno+1); if (sc & 040) /* -ve: right */ { sc = 0100 - sc; if (r & (1 << (sc-1))) SET_C(); else CLR_C(); if (sc == 32) { r = (r & 0x80000000) ? ~0 : 0; } else { if (r & 0x80000000) { r = (r >> sc) | ((~0) << (32-sc)); } else { r >>= sc; } } } else if (sc) /* +ve: left */ { int bits; bits = 0; for (;sc>0;sc--) { if (r & 0x80000000) bits |= 1; else bits &= ~1; if ("\0\1\1\0"[r>>30]) bits |= 2; r <<= 1; } if (bits & 1) SET_C(); else CLR_C(); if (bits & 2) SET_V(); } else { CLR_C(); } if (r == 0) SET_Z(); else CLR_Z(); if (r & 0x80000000) SET_N(); else CLR_N(); REG(rno) = r >> 16; REG(rno+1) = r & 0xffff; } } INST(asl) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_asl_b); } else { rmw_operand_w(inst,I_asl_w); } } INST(asr) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_asr_b); } else { rmw_operand_w(inst,I_asr_w); } } INST(bic) { if (inst & BYTEVERSION) { op_b = get_operand_b(inst>>6); rmw_operand_b(inst,I_bic_b); } else { op_w = get_operand_w(inst>>6); rmw_operand_w(inst,I_bic_w); } } INST(bis) { if (inst & BYTEVERSION) { op_b = get_operand_b(inst>>6); rmw_operand_b(inst,I_bis_b); } else { op_w = get_operand_w(inst>>6); rmw_operand_w(inst,I_bis_w); } } INST(bit) { if (inst & BYTEVERSION) { byte b; b = get_operand_b(inst>>6); /* do this one first */ b &= get_operand_b(inst); if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); CLR_V(); } else { word w; w = get_operand_w(inst>>6); /* do this one first */ w &= get_operand_w(inst); if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); CLR_V(); } } INST(bpt) { trapto(014); } INST(cbranch) { int takeit; switch (inst & 0103000) { case 0000000: /* (not a cbranch), br */ takeit = 1; break; case 0001000: /* bne, beq */ takeit = psw & PSW_Z; break; case 0002000: /* bge, blt */ takeit = (psw & PSW_N) ? (psw & PSW_V) ? 0 : 1 : (psw & PSW_V) ? 1 : 0; break; case 0003000: /* bgt, ble */ takeit = (psw & PSW_Z) ? 1 : (psw & PSW_N) ? (psw & PSW_V) ? 0 : 1 : (psw & PSW_V) ? 1 : 0; break; case 0100000: /* bpl, bmi */ takeit = psw & PSW_N; break; case 0101000: /* bhi, blos */ takeit = psw & (PSW_C|PSW_Z); break; case 0102000: /* bvc, bvs */ takeit = psw & PSW_V; break; case 0103000: /* bcc/bhis, bcs/blo */ takeit = psw & PSW_C; break; } if ((inst & 0400) == 0) takeit = ! takeit; if (takeit) { word off; off = inst & 0377; if (off & 0200) off |= 0177400; pc += off << 1; } } INST(cfcc) { #if (FPS_FN == PSW_N) && (FPS_FZ == PSW_Z) && (FPS_FV == PSW_V) && (FPS_FC == PSW_C) psw = (psw & ~PSW_CC) | (fps & FPS_CC); #else if (fps & FPS_FN) SET_N(); else CLR_N(); if (fps & FPS_FZ) SET_Z(); else CLR_Z(); if (fps & FPS_FV) SET_V(); else CLR_V(); if (fps & FPS_FC) SET_C(); else CLR_C(); #endif } INST(clr) { CLR_N(); SET_Z(); CLR_V(); CLR_C(); if (inst & BYTEVERSION) { set_operand_b(inst,0); } else { set_operand_w(inst,0); } } INST(cmp) { if (inst & BYTEVERSION) { byte bs; byte bd; int res; bs = get_operand_b(inst>>6); bd = get_operand_b(inst); res = bs + 0x100 - bd; if (bs == bd) SET_Z(); else CLR_Z(); if (res & 0x80) SET_N(); else CLR_N(); if (((bs^bd) & 0x80) && !((bd^res) & 0x80)) SET_V(); else CLR_V(); if (res & 0x100) CLR_C(); else SET_C(); } else { word ws; word wd; int res; ws = get_operand_w(inst>>6); wd = get_operand_w(inst); res = ws + 0x10000 - wd; if (ws == wd) SET_Z(); else CLR_Z(); if (res & 0x8000) SET_N(); else CLR_N(); if (((ws^wd) & 0x8000) && !((wd^res) & 0x8000)) SET_V(); else CLR_V(); if (res & 0x10000) CLR_C(); else SET_C(); } } INST(com) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_com_b); } else { rmw_operand_w(inst,I_com_w); } } INST(condcode) { /* convenient how the bits in the instruction precisely match the in the psw... */ if (inst & 0000020) { psw |= inst & PSW_CC; } else { psw &= ~ (inst & PSW_CC); } } INST(csm) { if (mmr3 & MMR3_CSM_ENB) { word tmp; word dst; if (KERNELMODE()) trapto(010); dst = get_operand_w(inst); /* XXX should I do dst = fetchword(dst,MMAN_DSPACE) here? */ sps[MODE_S] = sp; tmp = psw & ~PSW_CC; psw = (psw & ~(PSW_CM|PSW_PM|PSW_T)) | (MODE_S << PSW_CM_SHIFT) | (pswc_cm << PSW_PM_SHIFT); checkpsw(); sp_push(tmp); sp_push(pc); sp_push(dst); pc = fetchword(010,MMAN_DSPACE); } else { unimpl(); } } INST(dec) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_dec_b); } else { rmw_operand_w(inst,I_dec_w); } } /* I wish I had a precise statement of the supposed semantics of this instruction. The DEC diagnostics test for precise results from various error conditions, thus depending on the details of the implementation. ghaaa. */ /* ekbbc1 tests: (cc=nzvc) neg:qr 4 / 0 -> 00 cc=0111 * 11176 cc=0010 11210 cc!=0010 (leftover) / 2 -> 00 q=2 r=0 cc=0000 * 11272 q=2 r=0 cc!=0000 11316 q=2 r=-2 11330 q=2 r=4 11334 q=2 r=none(0,-2,4) 11370 q=020 11402 q=0x7fff 11414 q=-1 11426 q=none(2,020,0x7fff,-1,0) 11450 q=0 r=0155776 11462 q=0 r=none(0155776,4) 11506 q=0 r=4 c=1 11512 q=0 r=4 c=0 6 / 2 -> 00 r!=2 * 11542 r=2 4 / -2 -> 10 q=-2 r=0 cc=1000 * 11624 q=0x2fff 11640 q=none(-2,0x2fff) 11662 q=-2 r!=0 11712 q=-2 r=0 cc!=1000 cc=1101 0x20000 / 1 -> 00 q=2 cc=0010 * 11756 q!=2 12006 q=2 cc!=0010 0x20000 / -2 -> 10 q=2 * 12042 q!=2 cc=0100 0x80000000 / 1 -> 11 q=0x8000 cc=1110 * 12106 q!=0x8000 12136 q=0x8000 cc!=1110 -0x10001 / -1 -> 01 q=1 r=1 * 12230 q!=1 and/or r!=1 -5 / 2 -> 11 r=-1 q=-2 * 12312 r!=-1 12324 r=-1 q!=-2 -5 / -2 -> 01 q=2 r=-1 * 12406 q!=2 12420 q=2 r!=-1 -0x20000 / 0x4000 -> 11 q=-010 r=0 * 12476 q!=-010 12510 q=-010 r!=0 0x00400080 / -0x7f -> 10 cc=0010 * 12574 cc!=0010 */ INST(div) { word divr; int rno; unsigned long int divd; unsigned long int quo; unsigned long int rem; int negq; int negr; divr = get_operand_w(inst); if (divr == 0) { CLR_N(); SET_Z(); SET_V(); SET_C(); return; } rno = (inst >> 6) & 6; /* "must be even", or would be ... & 7 */ if (rno & 1) { I_emhalt(0); return; } CLR_C(); CLR_V(); divd = ((REG(rno) << 16) | REG(rno+1)); negq = 0; negr = 0; if (divd & 0x80000000) { if (divr & 0x8000) { divd = (- divd) & 0xffffffff; divr = (- divr) & 0xffff; negr = 1; } else { divd = (- divd) & 0xffffffff; negq = 1; negr = 1; } } else { if (divr & 0x8000) { divr = (- divr) & 0xffff; negq = 1; } } quo = divd / divr; rem = divd % divr; if ((quo&0x7fffffff) == 0) SET_Z(); else CLR_Z(); if (negq) SET_N(); else CLR_N(); if (quo & 0xffff8000) { /* the code inside this if is not supposed to make sense; it's just supposed to keep ekbbc1 happy. */ SET_V(); quo >>= 16; if (negq && !negr) quo ++; if (negr && !negq) rem ++; negq = 0; negr = 0; if (quo & 0x8000) SET_N(); else CLR_N(); /* is this right? */ } if (negq) quo = (- quo) & 0xffffffff; if (negr) rem = (- rem) & 0xffff; REG(rno) = quo & 0xffff; REG(rno+1) = rem; } #if 0 /* derived by pgd from microcode flowcharts and suchlike */ INST(div) { int divr; int rno; long int divd; long int quo; word rem; int divd_sign; int divr_sign; divr = sxw(get_operand_w(inst)); if (divr == 0) { SET_C(); SET_Z(); SET_V(); CLR_N(); return; } CLR_C(); rno = (inst >> 6) & 6; divd = ((sxw(REG(rno)) << 16) | REG(rno|1)); divd_sign = divd; if (divd < 0) { if (divd == 0x80000000) { SET_V(); SET_N(); SET_Z(); return; } divd = - divd; } divr_sign = divr; if (divr < 0) divr = -divr; quo = divd / divr; rem = divd % divr; if (quo >= 0x8000) { SET_V(); quo = divd >> 16; rem = divd & 0xffff; divr_sign = 0; divd_sign = 0; } else { CLR_V(); } if (divd_sign) { rem = - rem; } if (divr_sign != divd_sign) { if (quo == 0100000) { SET_V(); quo = 0100000; } else { quo = - quo; } } REG(rno) = quo & 0xffff; REG(rno|1) = rem; if (quo == 0) SET_Z(); else CLR_Z(); if (quo & 0x8000) SET_N(); else CLR_N(); } #endif INST(emhalt) { /* debugging aid: causes emulator to halt, regardless of current mode */ /* also backs up pc so it doesn't need bashing after restoring previous instruction */ pc -= 2; halted = 1; } INST(emt) { trapto(030); } #if 0 INST(fadd(){} INST(fdiv(){} INST(fmul(){} INST(fsub(){} #endif INST(halt) { if (KERNELMODE()) { halted = 1; } else { cpu_error |= CPUERR_ILL_HALT; trapto(4); } } INST(inc) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_inc_b); } else { rmw_operand_w(inst,I_inc_w); } } INST(iot) { trapto(020); } INST(jmp) { pc = get_operand_a(inst); } INST(jsr) { word tmp; int rno; tmp = get_operand_a(inst); rno = (inst >> 6) & 7; sp_push(REG(rno)); REG(rno) = pc; pc = tmp; } INST(ldfps) { fps = get_operand_w(inst) & ~FPS_MBZ; } INST(mark) { sp = pc + ((inst & 077) << 1); pc = r5; r5 = sp_pop(); } INST(mfpd) { word savepsw; word w; if ((inst & 070) == 0) { if ((inst & 7) == 6) { if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { w = sp; } else { w = sps[(psw&PSW_PM)>>PSW_PM_SHIFT]; } } else { w = REG(inst&7); } } else if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { w = get_operand_w(inst); } else { word a; a = get_operand_a(inst); savepsw = psw; psw = (psw & ~PSW_CM) | (((psw & PSW_PM) >> PSW_PM_SHIFT) << PSW_CM_SHIFT); checkpsw(); w = fetchword(a,MMAN_DSPACE); psw = savepsw; checkpsw(); } sp_push(w); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0) SET_Z(); else CLR_Z(); CLR_V(); } INST(mfpi) { word savepsw; word w; if ((inst & 070) == 0) { if ((inst & 7) == 6) { if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { w = sp; } else { w = sps[(psw&PSW_PM)>>PSW_PM_SHIFT]; } } else { w = REG(inst&7); } } else { word a; a = get_operand_a(inst); savepsw = psw; if (((psw & PSW_PM) >> PSW_PM_SHIFT) >= pswc_cm) { psw = (psw & ~PSW_CM) | (((psw & PSW_PM) >> PSW_PM_SHIFT) << PSW_CM_SHIFT); checkpsw(); } w = fetchword(a,((savepsw&(PSW_PM|PSW_CM))==((MODE_U<>6); CLR_V(); if (b == 0) SET_Z(); else CLR_Z(); if (b & 0x80) SET_N(); else CLR_N(); if ((inst & 070) == 0) /* special case: movb to sign-extends */ { set_operand_w(inst,(b&0x80)?(b|0xff00):b); } else { set_operand_b(inst,b); } } else { word w; w = get_operand_w(inst>>6); CLR_V(); if (w == 0) SET_Z(); else CLR_Z(); if (w & 0x8000) SET_N(); else CLR_N(); set_operand_w(inst,w); } } INST(mtpd) { word savepsw; word w; w = sp_pop(); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0) SET_Z(); else CLR_Z(); CLR_V(); if ((inst & 070) == 0) { if ((inst & 7) == 6) { if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { sp = w; } else { sps[(psw&PSW_PM)>>PSW_PM_SHIFT] = w; } } else { REG(inst&7) = w; } } else if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { set_operand_w(inst,w); } else { word a; a = get_operand_a(inst); savepsw = psw; psw = (psw & ~PSW_CM) | (((psw & PSW_PM) >> PSW_PM_SHIFT) << PSW_CM_SHIFT); checkpsw(); storeword(a,MMAN_DSPACE,w); psw = savepsw; checkpsw(); } } INST(mtpi) { word savepsw; word w; w = sp_pop(); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0) SET_Z(); else CLR_Z(); CLR_V(); if ((inst & 070) == 0) { if ((inst & 7) == 6) { if (((psw & PSW_PM) >> PSW_PM_SHIFT) < pswc_cm) { sp = w; } else { sps[(psw&PSW_PM)>>PSW_PM_SHIFT] = w; } } else { REG(inst&7) = w; } } else { word a; a = get_operand_a(inst); savepsw = psw; if (((psw & PSW_PM) >> PSW_PM_SHIFT) >= pswc_cm) { psw = (psw & ~PSW_CM) | (((psw & PSW_PM) >> PSW_PM_SHIFT) << PSW_CM_SHIFT); checkpsw(); } storeword(a,((savepsw&(PSW_PM|PSW_CM))==((MODE_U<> 6) & 7; f2 = REG(rno); prod = sxw(f1) * sxw(f2); if (prod == 0) SET_Z(); else CLR_Z(); if (prod < 0) SET_N(); else CLR_N(); if ((prod < -32768) || (prod > 32767)) SET_C(); else CLR_C(); REG(rno) = (prod >> 16) & 0xffff; REG(rno|1) = prod & 0xffff; CLR_V(); } INST(neg) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_neg_b); } else { rmw_operand_w(inst,I_neg_w); } } INST(nop) { /* real easy */ } INST(reset) { if (KERNELMODE()) { busreset(); } } INST(rol) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_rol_b); } else { rmw_operand_w(inst,I_rol_w); } } INST(ror) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_ror_b); } else { rmw_operand_w(inst,I_ror_w); } } /* the logic in this code is due to pgd's examination of the schematics; it would perhaps be clearer if it were written in terms of MODE_x values and complicated ifs.... */ INST(rti) { word newpsw; pc = sp_pop(); newpsw = sp_pop() & ~PSW_MBZ; if ((pswc_cm != MODE_K) || ((newpsw & PSW_CM) != (MODE_K << PSW_CM_SHIFT))) newpsw |= psw & (PSW_CM|PSW_PM|PSW_RS); /* if ((psw & PSW_CM) > (newpsw & PSW_CM)) newpsw = (newpsw & ~PSW_CM) | (psw & PSW_CM); if ((psw & PSW_PM) > (newpsw & PSW_PM)) newpsw = (newpsw & ~PSW_PM) | (psw & PSW_PM); if (psw & PSW_RS) newpsw |= PSW_RS; */ if (pswc_cm != MODE_K) newpsw = (newpsw & ~PSW_PRI) | (psw & PSW_PRI); psw = newpsw; checkpsw(); if (psw & PSW_T) pending |= PEND_TRACE; else pending &= ~PEND_TRACE; } INST(rts) { int rno; rno = inst & 7; pc = REG(rno); REG(rno) = sp_pop(); } INST(rtt) { I_rti(inst); pending &= ~PEND_TRACE; } INST(sbc) { if (inst & BYTEVERSION) { rmw_operand_b(inst,I_sbc_b); } else { rmw_operand_w(inst,I_sbc_w); } } INST(setd) { fps |= FPS_FD; } INST(setf) { fps &= ~FPS_FD; } INST(seti) { fps &= ~FPS_FL; } INST(setl) { fps |= FPS_FL; } INST(sob) { int rno; word rv; rno = (inst >> 6) & 7; rv = (REG(rno) - 1) & 0xffff; REG(rno) = rv; if (rv) pc -= (inst & 077) << 1; } INST(spl) { if (KERNELMODE()) { psw = (psw & ~PSW_PRI) | ((inst & 7) << PSW_PRI_SHIFT); checkpsw(); } } INST(stfps) { set_operand_w(inst,fps); } INST(stst) { if ((inst & 070) == 0) { REG(inst&7) = fec; } else { word a; a = get_operand_a(inst); storeword(a,MMAN_DSPACE,fec); storeword((a+2)&0xffff,MMAN_DSPACE,fea); } } INST(sub) { op_w = get_operand_w(inst>>6); rmw_operand_w(inst,I_sub_); } INST(swab) { rmw_operand_w(inst,I_swab_); } INST(sxt) { CLR_V(); if (psw & PSW_N) { CLR_Z(); set_operand_w(inst,~0); } else { SET_Z(); set_operand_w(inst,0); } } INST(trap) { trapto(034); } INST(tst) { if (inst & BYTEVERSION) { byte b; b = get_operand_b(inst); if (b & 0x80) SET_N(); else CLR_N(); if (b == 0) SET_Z(); else CLR_Z(); } else { word w; w = get_operand_w(inst); if (w & 0x8000) SET_N(); else CLR_N(); if (w == 0) SET_Z(); else CLR_Z(); } CLR_V(); CLR_C(); } INST(tstset) { dma_inhibit = 1; rmw_operand_w(inst,I_tstset_); dma_inhibit = 0; } INST(wait) { /* The KDJ11-A book says that if not in kernel mode, nop. I see no reason to do that, though. */ /* if (! KERNELMODE()) return; */ if (intrq_pri <= pswc_pri) sigpause(0); } INST(wrtlck) { if ((inst & 070) == 0) trapto(010); dma_inhibit = 1; set_operand_w(inst,r0); dma_inhibit = 0; } INST(xor) { op_w = REG((inst>>6)&7); rmw_operand_w(inst,I_xor_); }