first check-in of Cyclone 0.069 under GPLv2 and MAME License. Pico Disa.c/h included too
[cyclone68000.git] / Cyclone / OpMove.cpp
diff --git a/Cyclone/OpMove.cpp b/Cyclone/OpMove.cpp
new file mode 100644 (file)
index 0000000..2a1b5fe
--- /dev/null
@@ -0,0 +1,454 @@
+\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