--- /dev/null
+\r
+#include "app.h"\r
+\r
+// --------------------- Opcodes 0x1000+ ---------------------\r
+// Emit a Move opcode, 00xxdddd ddssssss\r
+int OpMove(int op)\r
+{\r
+ int sea=0,tea=0;\r
+ int size=0,use=0;\r
+ int movea=0;\r
+\r
+ // Get source and target EA\r
+ sea = op&0x003f;\r
+ tea =(op&0x01c0)>>3;\r
+ tea|=(op&0x0e00)>>9;\r
+\r
+ if (tea>=8 && tea<0x10) movea=1;\r
+\r
+ // Find size extension\r
+ switch (op&0x3000)\r
+ {\r
+ default: return 1;\r
+ case 0x1000: size=0; break;\r
+ case 0x3000: size=1; break;\r
+ case 0x2000: size=2; break;\r
+ }\r
+\r
+ if (movea && size<1) return 1; // movea.b is invalid\r
+\r
+ // See if we can do this opcode:\r
+ if (EaCanRead (sea,size)==0) return 1;\r
+ if (EaCanWrite(tea )==0) return 1;\r
+\r
+ use=OpBase(op);\r
+ if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7\r
+ \r
+ if (tea>=0x18 && tea<0x28 && (tea&7)==7) use|=0x0e00; // Specific handler for (a7)+ and -(a7)\r
+\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=4;\r
+\r
+ EaCalc(0,0x003f,sea,size);\r
+ EaRead(0, 0,sea,size);\r
+\r
+ ot(" adds r1,r0,#0 ;@ Defines NZ, clears CV\n");\r
+\r
+ if (movea==0) ot(" mrs r9,cpsr ;@ r9=NZCV flags\n");\r
+ ot("\n");\r
+\r
+ if (movea) size=2; // movea always expands to 32-bits\r
+\r
+ EaCalc (0,0x0e00,tea,size);\r
+ EaWrite(0, 1,tea,size);\r
+\r
+ OpEnd();\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x41c0+ ---------------------\r
+// Emit an Lea opcode, 0100nnn1 11aaaaaa\r
+int OpLea(int op)\r
+{\r
+ int use=0;\r
+ int sea=0,tea=0;\r
+\r
+ sea= op&0x003f;\r
+ tea=(op&0x0e00)>>9; tea|=8;\r
+\r
+ if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode:\r
+\r
+ use=OpBase(op);\r
+ use&=~0x0e00; // Also use 1 handler for target ?0-7\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=4;\r
+\r
+ EaCalc (1,0x003f,sea,0); // Lea\r
+ EaCalc (0,0x0e00,tea,2);\r
+ EaWrite(0, 1,tea,2);\r
+\r
+ if (Amatch)\r
+ {\r
+ // Correct?\r
+ if (sea< 0x18) Cycles+=4;\r
+ else if (sea==0x30) Cycles+=12;\r
+ else Cycles+=8;\r
+ }\r
+\r
+ OpEnd();\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x40c0+ ---------------------\r
+\r
+// Pack our flags into r1, in SR/CCR register format\r
+// trashes r0,r2\r
+void OpFlagsToReg(int high)\r
+{\r
+ ot(" mov r1,r9,lsr #28 ;@ ____NZCV\n");\r
+ ot(" eor r0,r1,r1,ror #1 ;@ Bit 0=C^V\n");\r
+ ot(" tst r0,#1 ;@ 1 if C!=V\n");\r
+ ot(" eorne r1,r1,#3 ;@ ____NZVC\n");\r
+ ot("\n");\r
+ ot(" ldrb r0,[r7,#0x45] ;@ X bit\n");\r
+ if (high) ot(" ldrb r2,[r7,#0x44] ;@ Include SR high\n");\r
+ ot(" and r0,r0,#0x02\n");\r
+ if (high) ot(" orr r1,r1,r2,lsl #8\n");\r
+ ot(" orr r1,r1,r0,lsl #3 ;@ ___XNZVC\n");\r
+ ot("\n");\r
+}\r
+\r
+// Convert SR/CRR register in r0 to our flags\r
+// trashes r0,r1\r
+void OpRegToFlags(int high)\r
+{\r
+ ot(" eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");\r
+ ot(" mov r2,r0,lsr #3 ;@ r2=___XN\n");\r
+ ot(" tst r1,#1 ;@ 1 if C!=V\n");\r
+ ot(" eorne r0,r0,#3 ;@ ___XNZCV\n");\r
+ ot(" strb r2,[r7,#0x45] ;@ Store X bit\n");\r
+ ot(" mov r9,r0,lsl #28 ;@ r9=NZCV...\n");\r
+\r
+ if (high)\r
+ {\r
+ ot(" mov r0,r0,ror #8\n");\r
+ ot(" strb r0,[r7,#0x44] ;@ Store SR high\n");\r
+ }\r
+ ot("\n");\r
+}\r
+\r
+static void SuperCheck(int op)\r
+{\r
+ ot(" ldrb r0,[r7,#0x44] ;@ Get SR high\n");\r
+ ot(" tst r0,#0x20 ;@ Check we are in supervisor mode\n");\r
+ ot(" beq WrongMode%.4x ;@ No\n",op);\r
+ ot("\n");\r
+}\r
+\r
+static void SuperEnd(int op)\r
+{\r
+ ot("WrongMode%.4x%s\n",op,ms?"":":");\r
+ ot(";@ todo - cause an exception\n");\r
+ OpEnd();\r
+}\r
+\r
+// Move SR opcode, 01000tt0 11aaaaaa move to SR\r
+int OpMoveSr(int op)\r
+{\r
+ int type=0,ea=0;\r
+ int use=0,size=1;\r
+\r
+ type=(op>>9)&3;\r
+ ea=op&0x3f;\r
+\r
+ switch(type)\r
+ {\r
+ case 0: case 1:\r
+ if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode:\r
+ break;\r
+\r
+ default: return 1; // todo\r
+\r
+ case 2: case 3:\r
+ if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode:\r
+ break;\r
+ }\r
+\r
+ use=OpBase(op);\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op);\r
+ if (type==0) Cycles=8;\r
+ else if (type==1) Cycles=6;\r
+ else Cycles=12;\r
+\r
+ if (Amatch && ea==0x3c) Cycles-=4; // Correct?\r
+\r
+ if (type==0 || type==3) SuperCheck(op);\r
+\r
+ if (type==0 || type==1)\r
+ {\r
+ OpFlagsToReg(type==0);\r
+ EaCalc (0,0x003f,ea,size);\r
+ EaWrite(0, 1,ea,size);\r
+ }\r
+\r
+ if (type==2 || type==3)\r
+ {\r
+ EaCalc(0,0x003f,ea,size);\r
+ EaRead(0, 0,ea,size);\r
+ OpRegToFlags(type==3);\r
+ if (type==3) CheckInterrupt();\r
+ }\r
+\r
+ OpEnd();\r
+\r
+ if (type==0 || type==3) SuperEnd(op);\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+// Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100\r
+int OpArithSr(int op)\r
+{\r
+ int type=0,ea=0;\r
+ int use=0,size=0;\r
+\r
+ type=(op>>9)&5; if (type==4) return 1;\r
+ size=(op>>6)&1;\r
+ ea=0x3c;\r
+\r
+ use=OpBase(op);\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=16;\r
+\r
+ SuperCheck(op);\r
+\r
+ EaCalc(0,0x003f,ea,size);\r
+ EaRead(0, 10,ea,size);\r
+\r
+ OpFlagsToReg(size);\r
+ if (type==0) ot(" orr r0,r1,r10\n");\r
+ if (type==1) ot(" and r0,r1,r10\n");\r
+ if (type==5) ot(" eor r0,r1,r10\n");\r
+ OpRegToFlags(size);\r
+ if (size) CheckInterrupt();\r
+\r
+ OpEnd();\r
+ SuperEnd(op);\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x4850+ ---------------------\r
+// Emit an Pea opcode, 01001000 01aaaaaa\r
+int OpPea(int op)\r
+{\r
+ int use=0;\r
+ int ea=0;\r
+\r
+ ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode\r
+ if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode:\r
+\r
+ use=OpBase(op);\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=20;\r
+\r
+ EaCalc (1,0x003f, ea,0);\r
+ ot("\n");\r
+ ot(" ldr r0,[r7,#0x3c]\n");\r
+ ot(" sub r0,r0,#4 ;@ Predecrement A7\n");\r
+ ot(" str r0,[r7,#0x3c] ;@ Save A7\n");\r
+ ot("\n");\r
+ MemHandler(1,2); // Write 32-bit\r
+ ot("\n");\r
+\r
+ OpEnd();\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x4880+ ---------------------\r
+// Emit a Movem opcode, 01001d00 1xeeeeee regmask\r
+int OpMovem(int op)\r
+{\r
+ int size=0,ea=0,cea=0,dir=0;\r
+ int use=0,decr=0,change=0;\r
+\r
+ size=((op>>6)&1)+1;\r
+ ea=op&0x003f;\r
+ dir=(op>>10)&1; // Direction\r
+\r
+ if (ea<0x10 || ea>0x39) return 1; // Invalid EA\r
+ if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1;\r
+ if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr\r
+\r
+ // See if we can do this opcode:\r
+ if (EaCanWrite(ea)==0) return 1;\r
+\r
+ cea=ea; if (change) cea=0x10;\r
+\r
+ use=OpBase(op);\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op);\r
+\r
+ ot(" stmdb sp!,{r9} ;@ Push r9\n");\r
+ ot(" ldrh r11,[r4],#2 ;@ r11=register mask\n");\r
+\r
+ ot("\n");\r
+ ot(";@ Get the address into r9:\n");\r
+ EaCalc(9,0x003f,cea,size);\r
+\r
+ ot(";@ r10=Register Index*4:\n");\r
+ if (decr) ot(" mov r10,#0x3c ;@ order reversed for -(An)\n");\r
+ else ot(" mov r10,#0\n");\r
+ \r
+ ot("\n");\r
+ ot("MoreReg%.4x%s\n",op, ms?"":":");\r
+\r
+ ot(" tst r11,#1\n");\r
+ ot(" beq SkipReg%.4x\n",op);\r
+ ot("\n");\r
+\r
+ if (decr) ot(" sub r9,r9,#%d ;@ Pre-decrement address\n",1<<size);\r
+\r
+ if (dir)\r
+ {\r
+ ot(" ;@ Copy memory to register:\n",1<<size);\r
+ EaRead (9,0,ea,size);\r
+ ot(" str r0,[r7,r10] ;@ Save value into Dn/An\n");\r
+ }\r
+ else\r
+ {\r
+ ot(" ;@ Copy register to memory:\n",1<<size);\r
+ ot(" ldr r1,[r7,r10] ;@ Load value from Dn/An\n");\r
+ EaWrite(9,1,ea,size);\r
+ }\r
+\r
+ if (decr==0) ot(" add r9,r9,#%d ;@ Post-increment address\n",1<<size);\r
+\r
+ ot(" sub r5,r5,#%d ;@ Take some cycles\n",2<<size);\r
+ ot("\n");\r
+ ot("SkipReg%.4x%s\n",op, ms?"":":");\r
+ ot(" movs r11,r11,lsr #1;@ Shift mask:\n");\r
+ ot(" add r10,r10,#%d ;@ r10=Next Register\n",decr?-4:4);\r
+ ot(" bne MoreReg%.4x\n",op);\r
+ ot("\n");\r
+\r
+ if (change)\r
+ {\r
+ ot(";@ Write back address:\n");\r
+ EaCalc (0,0x0007,8|(ea&7),2);\r
+ EaWrite(0, 9,8|(ea&7),2);\r
+ }\r
+\r
+ ot(" ldmia sp!,{r9} ;@ Pop r9\n");\r
+ ot("\n");\r
+\r
+ if (ea<0x10) { }\r
+ else if (ea<0x18) Cycles=16; // (a0)\r
+ else if (ea<0x20) Cycles= 0; // (a0)+ ?\r
+ else if (ea<0x28) Cycles= 8; //-(a0)\r
+ else if (ea<0x30) Cycles=24; // ($3333,a0)\r
+ else if (ea<0x38) Cycles=28; // ($33,a0,d3.w*2)\r
+ else if (ea<0x39) Cycles=24; // $3333.w\r
+ else if (ea<0x3a) Cycles=28; // $33333333.l\r
+\r
+ OpEnd();\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x4e60+ ---------------------\r
+// Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP\r
+int OpMoveUsp(int op)\r
+{\r
+ int use=0,dir=0;\r
+\r
+ dir=(op>>3)&1; // Direction\r
+ use=op&~0x0007; // Use same opcode for all An\r
+\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=4;\r
+\r
+ ot(" ldrb r0,[r7,#0x44] ;@ Get SR\n");\r
+ ot(" tst r0,#0x20 ;@ Check we are in supervisor mode\n");\r
+ ot(" beq WrongMode%.4x ;@ No\n",op);\r
+ ot("\n");\r
+\r
+ if (dir)\r
+ {\r
+ EaCalc (0,0x0007,8,2);\r
+ ot(" ldr r1,[r7,#0x48] ;@ Get from USP\n\n");\r
+ EaWrite(0, 1,8,2);\r
+ }\r
+ else\r
+ {\r
+ EaCalc (0,0x0007,8,2);\r
+ EaRead (0, 0,8,2);\r
+ ot(" str r0,[r7,#0x48] ;@ Put in USP\n\n");\r
+ }\r
+ \r
+ OpEnd();\r
+\r
+ ot("WrongMode%.4x%s\n",op,ms?"":":");\r
+ ot(";@ todo - cause an exception\n");\r
+ OpEnd();\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0x7000+ ---------------------\r
+// Emit a Move Quick opcode, 0111nnn0 dddddddd moveq #dd,Dn\r
+int OpMoveq(int op)\r
+{\r
+ int use=0;\r
+\r
+ use=op&0xf100; // Use same opcode for all values\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=4;\r
+\r
+ ot(" movs r0,r8,asl #24\n");\r
+ ot(" and r1,r8,#0x0e00\n");\r
+ ot(" mov r0,r0,asr #24 ;@ Sign extended Quick value\n");\r
+ ot(" mrs r9,cpsr ;@ r9=NZ flags\n");\r
+ ot(" str r0,[r7,r1,lsr #7] ;@ Store into Dn\n");\r
+ ot("\n");\r
+\r
+ OpEnd();\r
+\r
+ return 0;\r
+}\r
+\r
+// --------------------- Opcodes 0xc140+ ---------------------\r
+// Emit a Exchange opcode:\r
+// 1100ttt1 01000sss exg ds,dt\r
+// 1100ttt1 01001sss exg as,at\r
+// 1100ttt1 10001sss exg as,dt\r
+int OpExg(int op)\r
+{\r
+ int use=0,type=0;\r
+\r
+ type=op&0xf8;\r
+\r
+ if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode\r
+\r
+ use=op&0xf1f8; // Use same opcode for all values\r
+ if (op!=use) { OpUse(op,use); return 0; } // Use existing handler\r
+\r
+ OpStart(op); Cycles=6;\r
+\r
+ ot(" and r10,r8,#0x0e00 ;@ Find T register\n");\r
+ ot(" and r11,r8,#0x000f ;@ Find S register\n");\r
+ if (type==0x48) ot(" orr r10,r10,#0x1000 ;@ T is an address register\n");\r
+ ot("\n");\r
+ ot(" ldr r0,[r7,r10,lsr #7] ;@ Get T\n");\r
+ ot(" ldr r1,[r7,r11,lsl #2] ;@ Get S\n");\r
+ ot("\n");\r
+ ot(" str r0,[r7,r11,lsl #2] ;@ T->S\n");\r
+ ot(" str r1,[r7,r10,lsr #7] ;@ S->T\n"); \r
+ ot("\n");\r
+\r
+ OpEnd();\r
+ \r
+ return 0;\r
+}\r