// Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee int OpAsrEa(int op) { int use=0,type=0,dir=0,ea=0,size=1; type=(op>>9)&3; dir =(op>>8)&1; ea = op&0x3f; if (ea<0x10) return 1; // See if we can do this opcode: if (EaCanRead(ea,0)==0) return 1; if (EaCanWrite(ea)==0) return 1; use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,ea); Cycles=6; // EmitAsr() will add 2 EaCalc (11,0x003f,ea,size,earwt_shifted_up); EaRead (11, 0,ea,size,0x003f,earwt_shifted_up); EmitAsr(op,type,dir,1,size,0); EaWrite(11, 0,ea,size,0x003f,earwt_shifted_up); OpEnd(ea); return 0; }
// --------------------- Opcodes 0x4880+ --------------------- // Emit an Ext opcode, 01001000 1x000nnn int OpExt(int op) { int ea=0; int size=0,use=0; int shift=0; ea=op&0x0007; size=(op>>6)&1; shift=32-(8<<size); use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op); Cycles=4; EaCalc (11,0x0007,ea,size+1,earwt_msb_dont_care); EaRead (11, 0,ea,size+1,0x0007,earwt_msb_dont_care); ot(" movs r0,r0,asl #%d\n",shift); OpGetFlagsNZ(0); ot(" mov r1,r0,asr #%d\n",shift); ot("\n"); EaWrite(11, 1,ea,size+1,0x0007,earwt_msb_dont_care); OpEnd(); return 0; }
// --------------------- Opcodes 0x4880+ --------------------- // Emit an Ext opcode, 01001000 1x000nnn int OpExt(int op) { int ea=0; int size=0,use=0; int shift=0; ea=op&0x0007; size=(op>>6)&1; shift=32-(8<<size); use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op); Cycles=4; EaCalc (11,0x0007,ea,size+1,0,0); EaRead (11, 0,ea,size+1,0x0007,0,0); ot(" mov r0,r0,asl #%d\n",shift); ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n"); ot(" mrs r10,cpsr ;@ r10=flags\n"); ot(" mov r1,r0,asr #%d\n",shift); ot("\n"); EaWrite(11, 1,ea,size+1,0x0007,0,0); OpEnd(); return 0; }
// --------------------- Opcodes 0x4a00+ --------------------- // Emit a Tst opcode, 01001010 xxeeeeee int OpTst(int op) { int sea=0; int size=0,use=0; sea=op&0x003f; size=(op>>6)&3; if (size>=3) return 1; // See if we can do this opcode: if (EaCanWrite(sea)==0||EaAn(sea)) return 1; use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,sea); Cycles=4; EaCalc (0,0x003f,sea,size,earwt_shifted_up); EaRead (0, 0,sea,size,0x003f,earwt_shifted_up,1); OpGetFlagsNZ(0); ot("\n"); OpEnd(sea); return 0; }
// --------------------- Opcodes 0x4a00+ --------------------- // Emit a Tst opcode, 01001010 xxeeeeee int OpTst(int op) { int sea=0; int size=0,use=0; sea=op&0x003f; size=(op>>6)&3; if (size>=3) return 1; // See if we can do this opcode: if (EaCanWrite(sea)==0||EaAn(sea)) return 1; use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,sea); Cycles=4; EaCalc ( 0,0x003f,sea,size,1); EaRead ( 0, 0,sea,size,0x003f,1); ot(" adds r0,r0,#0 ;@ Defines NZ, clears CV\n"); ot(" mrs r10,cpsr ;@ r10=flags\n"); ot("\n"); OpEnd(sea); return 0; }
int OpTas(int op, int gen_special) { int ea=0; int use=0; ea=op&0x003f; // See if we can do this opcode: if (EaCanWrite(ea)==0 || EaAn(ea)) return 1; use=OpBase(op,0); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler if (!gen_special) OpStart(op,ea); else ot("Op%.4x_%s\n", op, ms?"":":"); Cycles=4; if(ea>=8) Cycles+=10; EaCalc (11,0x003f,ea,0,1); EaRead (11, 1,ea,0,0x003f,1); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); ot("\n"); #if CYCLONE_FOR_GENESIS // the original Sega hardware ignores write-back phase (to memory only) if (ea < 0x10 || gen_special) { #endif ot(" orr r1,r1,#0x80000000 ;@ set bit7\n"); EaWrite(11, 1,ea,0,0x003f,1); #if CYCLONE_FOR_GENESIS } #endif OpEnd(ea); #if (CYCLONE_FOR_GENESIS == 2) if (!gen_special && ea >= 0x10) { OpTas(op, 1); } #endif return 0; }
// Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn // (ccc=count, d=direction(r,l) xx=size extension, u=use reg for count, tt=type, nnn=register Dn) int OpAsr(int op) { int ea=0,use=0; int count=0,dir=0; int size=0,usereg=0,type=0; count =(op>>9)&7; dir =(op>>8)&1; size =(op>>6)&3; if (size>=3) return 1; // use OpAsrEa() usereg=(op>>5)&1; type =(op>>3)&3; if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8 // Use the same opcode for target registers: use=op&~0x0007; // As long as count is not 8, use the same opcode for all shift counts: if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; } if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,ea,0,count<0); Cycles=size<2?6:8; EaCalc(11,0x0007, ea,size,earwt_shifted_up); EaRead(11, 0, ea,size,0x0007,earwt_shifted_up); EmitAsr(op,type,dir,count, size,usereg); EaWrite(11, 0, ea,size,0x0007,earwt_shifted_up); opend_op_changes_cycles = (count<0); OpEnd(ea,0); return 0; }
// --------------------- Opcodes 0x4840+ --------------------- // Swap, 01001000 01000nnn swap Dn int OpSwap(int op) { int ea=0,use=0; ea=op&7; use=op&~0x0007; // Use same opcode for all An if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op); Cycles=4; EaCalc (11,0x0007,ea,2,earwt_shifted_up); EaRead (11, 0,ea,2,0x0007,earwt_shifted_up); ot(" movs r1,r0,ror #16\n"); OpGetFlagsNZ(1); EaWrite(11, 1,8,2,0x0007,earwt_shifted_up); OpEnd(); return 0; }
// --------------------- Opcodes 0x4840+ --------------------- // Swap, 01001000 01000nnn swap Dn int OpSwap(int op) { int ea=0,use=0; ea=op&7; use=op&~0x0007; // Use same opcode for all An if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op); Cycles=4; EaCalc (11,0x0007,ea,2,1); EaRead (11, 0,ea,2,0x0007,1); ot(" mov r1,r0,ror #16\n"); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); EaWrite(11, 1,8,2,0x0007,1); OpEnd(); return 0; }
// --------------------- Opcodes 0x4000+ --------------------- int OpNeg(int op) { // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA) int type=0,size=0,ea=0,use=0; type=(op>>9)&3; ea =op&0x003f; size=(op>>6)&3; if (size>=3) return 1; // See if we can do this opcode: if (EaCanRead (ea,size)==0||EaAn(ea)) return 1; if (EaCanWrite(ea )==0) return 1; use=OpBase(op,size); if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,ea); Cycles=size<2?4:6; if(ea >= 0x10) Cycles*=2; EaCalc (11,0x003f,ea,size,earwt_msb_dont_care); if (type!=1) EaRead (11,0,ea,size,0x003f,earwt_msb_dont_care); // Don't need to read for 'clr' (or do we, for a dummy read?) if (type==1) ot("\n"); if (type==0) { ot(";@ Negx:\n"); GetXBit(1); if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); ot(" rscs r1,r0,#0 ;@ do arithmetic\n"); ot(" orr r3,r10,#0xb0000000 ;@ for old Z\n"); OpGetFlags(1,1,0); if(size!=2) { ot(" movs r1,r1,asr #%i\n",size?16:24); ot(" orreq r10,r10,#0x40000000 ;@ possily missed Z\n"); } ot(" andeq r10,r10,r3 ;@ fix Z\n"); ot("\n"); } if (type==1) { ot(";@ Clear:\n"); ot(" mov r1,#0\n"); ot(" mov r10,#0x40000000 ;@ NZCV=0100\n"); ot("\n"); } if (type==2) { ot(";@ Neg:\n"); if(size!=2) ot(" mov r0,r0,asl #%i\n",size?16:24); ot(" rsbs r1,r0,#0\n"); OpGetFlags(1,1); if(size!=2) ot(" mov r1,r1,asr #%i\n",size?16:24); ot("\n"); } if (type==3) { ot(";@ Not:\n"); if(size!=2) { ot(" mov r0,r0,asl #%i\n",size?16:24); ot(" mvns r1,r0,asr #%i\n",size?16:24); } else ot(" mvns r1,r0\n"); OpGetFlagsNZ(1); ot("\n"); } if (type==1) eawrite_check_addrerr=1; EaWrite(11, 1,ea,size,0x003f,earwt_msb_dont_care); OpEnd(ea); return 0; }
// --------------------- Opcodes 0x8100+ --------------------- // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad) int OpAbcd(int op) { int use=0; int type=0,sea=0,mem=0,dea=0; type=(op>>14)&1; // sbcd/abcd dea =(op>> 9)&7; mem =(op>> 3)&1; sea = op &7; if (mem) { sea|=0x20; dea|=0x20; } use=op&~0x0e07; // Use same opcode for all registers.. if (sea==0x27) use|=0x0007; // ___x.b -(a7) if (dea==0x27) use|=0x0e00; // ___x.b -(a7) if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,sea,dea); Cycles=6; if (mem) { ot(";@ Get src/dest EA vals\n"); EaCalc (0,0x000f, sea,0,1); EaRead (0, 10, sea,0,0x000f,1); EaCalcReadNoSE(11,0,dea,0,0x0e00); } else { ot(";@ Get src/dest reg vals\n"); EaCalcReadNoSE(-1,10,sea,0,0x0007); EaCalcReadNoSE(11,0,dea,0,0x0e00); ot(" mov r10,r10,asl #24\n"); } ot(" mov r1,r0,asl #24\n\n"); ot(" bic r9,r9,#0xb1000000 ;@ clear all flags except old Z\n"); if (type) { ot(" ldr r0,[r7,#0x4c] ;@ Get X bit\n"); ot(" mov r3,#0x00f00000\n"); ot(" and r2,r3,r1,lsr #4\n"); ot(" tst r0,#0x20000000\n"); ot(" and r0,r3,r10,lsr #4\n"); ot(" add r0,r0,r2\n"); ot(" addne r0,r0,#0x00100000\n"); // ot(" tst r0,#0x00800000\n"); // ot(" orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n"); ot(" cmp r0,#0x00900000\n"); ot(" addhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); ot(" mov r2,r1,lsr #28\n"); ot(" add r0,r0,r2,lsl #24\n"); ot(" mov r2,r10,lsr #28\n"); ot(" add r0,r0,r2,lsl #24\n"); ot(" cmp r0,#0x09900000\n"); ot(" orrhi r9,r9,#0x20000000 ;@ C\n"); ot(" subhi r0,r0,#0x0a000000\n"); // ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n"); // ot(" orr r9,r9,r3,lsl #4 ;@ V\n"); ot(" movs r0,r0,lsl #4\n"); ot(" orrmi r9,r9,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n"); } else { ot(" ldr r0,[r7,#0x4c] ;@ Get X bit\n"); ot(" mov r3,#0x00f00000\n"); ot(" and r2,r3,r10,lsr #4\n"); ot(" tst r0,#0x20000000\n"); ot(" and r0,r3,r1,lsr #4\n"); ot(" sub r0,r0,r2\n"); ot(" subne r0,r0,#0x00100000\n"); // ot(" tst r0,#0x00800000\n"); // ot(" orreq r9,r9,#0x01000000 ;@ Undefined V behavior\n"); ot(" cmp r0,#0x00900000\n"); ot(" subhi r0,r0,#0x00600000 ;@ Decimal adjust units\n"); ot(" mov r2,r1,lsr #28\n"); ot(" add r0,r0,r2,lsl #24\n"); ot(" mov r2,r10,lsr #28\n"); ot(" sub r0,r0,r2,lsl #24\n"); ot(" cmp r0,#0x09900000\n"); ot(" orrhi r9,r9,#0xa0000000 ;@ N and C\n"); ot(" addhi r0,r0,#0x0a000000\n"); // ot(" and r3,r9,r0,lsr #3 ;@ Undefined V behavior part II\n"); // ot(" orr r9,r9,r3,lsl #4 ;@ V\n"); ot(" movs r0,r0,lsl #4\n"); // ot(" orrmi r9,r9,#0x80000000 ;@ Undefined N behavior\n"); ot(" bicne r9,r9,#0x40000000 ;@ Z flag\n"); } ot(" str r9,[r7,#0x4c] ;@ Save X bit\n"); ot("\n"); EaWrite(11, 0, dea,0,0x0e00,1); OpEnd(sea,dea); return 0; }
// --------------------- Opcodes 0x80c0+ --------------------- int OpMul(int op) { // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA) int type=0,rea=0,sign=0,ea=0; int use=0; type=(op>>14)&1; // div/mul rea =(op>> 9)&7; sign=(op>> 8)&1; ea = op&0x3f; // See if we can do this opcode: if (EaCanRead(ea,1)==0||EaAn(ea)) return 1; use=OpBase(op,1); use&=~0x0e00; // Use same for all registers if (op!=use) { OpUse(op,use); return 0; } // Use existing handler OpStart(op,ea); if(type) Cycles=54; else Cycles=sign?158:140; EaCalcReadNoSE(-1,0,ea,1,0x003f); EaCalc(10,0x0e00,rea, 2); EaRead(10, 2,rea, 2,0x0e00); ot(" movs r1,r0,asl #16\n"); if (type==0) // div { // the manual says C is always cleared, but neither Musashi nor FAME do that //ot(" bic r9,r9,#0x20000000 ;@ always clear C\n"); ot(" beq divzero%.4x ;@ division by zero\n",op); ot("\n"); if (sign) { ot(" mov r11,#0 ;@ r11 = 1 or 2 if the result is negative\n"); ot(" tst r2,r2\n"); ot(" orrmi r11,r11,#2\n"); ot(" rsbmi r2,r2,#0 ;@ Make r2 positive\n"); ot("\n"); ot(" movs r0,r1,asr #16\n"); ot(" orrmi r11,r11,#1\n"); ot(" rsbmi r0,r0,#0 ;@ Make r0 positive\n"); ot("\n"); ot(";@ detect the nasty 0x80000000 / -1 situation\n"); ot(" mov r3,r2,asr #31\n"); ot(" eors r3,r3,r1,asr #16\n"); ot(" beq wrendofop%.4x\n",op); } else { ot(" mov r0,r1,lsr #16 ;@ use only 16 bits of divisor\n"); } ot("\n"); ot(";@ Divide r2 by r0\n"); ot(" mov r3,#0\n"); ot(" mov r1,r0\n"); ot("\n"); ot(";@ Shift up divisor till it's just less than numerator\n"); ot("Shift%.4x%s\n",op,ms?"":":"); ot(" cmp r1,r2,lsr #1\n"); ot(" movls r1,r1,lsl #1\n"); ot(" bcc Shift%.4x\n",op); ot("\n"); ot("Divide%.4x%s\n",op,ms?"":":"); ot(" cmp r2,r1\n"); ot(" adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n"); ot(" subcs r2,r2,r1\n"); ot(" teq r1,r0\n"); ot(" movne r1,r1,lsr #1\n"); ot(" bne Divide%.4x\n",op); ot("\n"); ot(";@r3==quotient,r2==remainder\n"); if (sign) { // sign correction ot(" and r1,r11,#1\n"); ot(" teq r1,r11,lsr #1\n"); ot(" rsbne r3,r3,#0 ;@ negate if quotient is negative\n"); ot(" tst r11,#2\n"); ot(" rsbne r2,r2,#0 ;@ negate the remainder if divident was negative\n"); ot("\n"); // signed overflow check ot(" mov r1,r3,asl #16\n"); ot(" cmp r3,r1,asr #16 ;@ signed overflow?\n"); ot(" orrne r9,r9,#0x10000000 ;@ set overflow flag\n"); ot(" bne endofop%.4x ;@ overflow!\n",op); ot("\n"); ot("wrendofop%.4x%s\n",op,ms?"":":"); } else { // overflow check ot(" movs r1,r3,lsr #16 ;@ check for overflow condition\n"); ot(" orrne r9,r9,#0x10000000 ;@ set overflow flag\n"); ot(" bne endofop%.4x ;@ overflow!\n",op); ot("\n"); } ot(" mov r1,r3,lsl #16 ;@ Clip to 16-bits\n"); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); ot(" mov r1,r1,lsr #16\n"); ot(" orr r1,r1,r2,lsl #16 ;@ Insert remainder\n"); } if (type==1) { ot(";@ Get 16-bit signs right:\n"); ot(" mov r0,r1,%s #16\n",sign?"asr":"lsr"); ot(" mov r2,r2,lsl #16\n"); ot(" mov r2,r2,%s #16\n",sign?"asr":"lsr"); ot("\n"); ot(" mul r1,r2,r0\n"); ot(" adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); OpGetFlags(0,0); } ot("\n"); EaWrite(10, 1,rea, 2,0x0e00,1); if (type==0) ot("endofop%.4x%s\n",op,ms?"":":"); OpEnd(ea); if (type==0) // div { ot("divzero%.4x%s\n",op,ms?"":":"); ot(" mov r0,#5 ;@ Divide by zero\n"); ot(" bl Exception\n"); Cycles+=38; OpEnd(ea); ot("\n"); } return 0; }