Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1.  
  2. // This file is part of the Cyclone 68000 Emulator
  3.  
  4. // Copyright (c) 2004,2011 FinalDave (emudave (at) gmail.com)
  5. // Copyright (c) 2005-2011 GraÅžvydas "notaz" Ignotas (notasas (at) gmail.com)
  6.  
  7. // This code is licensed under the GNU General Public License version 2.0 and the MAME License.
  8. // You can choose the license that has the most advantages for you.
  9.  
  10. // SVN repository can be found at http://code.google.com/p/cyclone68000/
  11.  
  12.  
  13. #include "app.h"
  14.  
  15. // Pack our flags into r1, in SR/CCR register format
  16. // trashes r0,r2
  17. void OpFlagsToReg(int high)
  18. {
  19.   ot("  ldr r0,[r7,#0x4c]   ;@ X bit\n");
  20.   ot("  mov r1,r10,lsr #28  ;@ ____NZCV\n");
  21.   ot("  eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n");
  22.   ot("  tst r2,#1           ;@ 1 if C!=V\n");
  23.   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");
  24.   ot("\n");
  25.   if (high) ot("  ldrb r2,[r7,#0x44]  ;@ Include SR high\n");
  26.   ot("  and r0,r0,#0x20000000\n");
  27.   ot("  orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n");
  28.   if (high) ot("  orr r1,r1,r2,lsl #8\n");
  29.   ot("\n");
  30. }
  31.  
  32. // Convert SR/CRR register in r0 to our flags
  33. // trashes r0,r1
  34. void OpRegToFlags(int high, int srh_reg)
  35. {
  36.   ot("  eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");
  37.   ot("  mov r2,r0,lsl #25\n");
  38.   ot("  tst r1,#1           ;@ 1 if C!=V\n");
  39.   ot("  eorne r0,r0,#3      ;@ ___XNZCV\n");
  40.   ot("  str r2,[r7,#0x4c]   ;@ Store X bit\n");
  41.   ot("  mov r10,r0,lsl #28  ;@ r10=NZCV...\n");
  42.  
  43.   if (high)
  44.   {
  45.     int mask=EMULATE_TRACE?0xa7:0x27;
  46.     ot("  mov r%i,r0,ror #8\n",srh_reg);
  47.     ot("  and r%i,r%i,#0x%02x ;@ only take defined bits\n",srh_reg,srh_reg,mask);
  48.     ot("  strb r%i,[r7,#0x44] ;@ Store SR high\n",srh_reg);
  49.   }
  50.   ot("\n");
  51. }
  52.  
  53. void SuperEnd(void)
  54. {
  55.   ot(";@ ----------\n");
  56.   ot(";@ tried execute privileged instruction in user mode\n");
  57.   ot("WrongPrivilegeMode%s\n",ms?"":":");
  58. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  59.   ot("  ldr r1,[r7,#0x58]\n");
  60.   ot("  sub r4,r4,#2 ;@ last opcode wasn't executed - go back\n");
  61.   ot("  orr r1,r1,#4 ;@ set activity bit: 'not processing instruction'\n");
  62.   ot("  str r1,[r7,#0x58]\n");
  63. #else
  64.   ot("  sub r4,r4,#2 ;@ last opcode wasn't executed - go back\n");
  65. #endif
  66.   ot("  mov r0,#8 ;@ privilege violation\n");
  67.   ot("  bl Exception\n");
  68.   Cycles=34;
  69.   OpEnd(0);
  70. }
  71.  
  72. // does OSP and A7 swapping if needed
  73. // new or old SR (not the one already in [r7,#0x44]) should be passed in r11
  74. // uses srh from srh_reg (loads if < 0), trashes r0,r11
  75. void SuperChange(int op,int srh_reg)
  76. {
  77.   ot(";@ A7 <-> OSP?\n");
  78.   if (srh_reg < 0) {
  79.     ot("  ldr r0,[r7,#0x44] ;@ Get other SR high\n");
  80.     srh_reg=0;
  81.   }
  82.   ot("  eor r0,r%i,r11\n",srh_reg);
  83.   ot("  tst r0,#0x20\n");
  84.   ot("  beq no_sp_swap%.4x\n",op);
  85.   ot(" ;@ swap OSP and A7:\n");
  86.   ot("  ldr r11,[r7,#0x3C] ;@ Get A7\n");
  87.   ot("  ldr r0, [r7,#0x48] ;@ Get OSP\n");
  88.   ot("  str r11,[r7,#0x48]\n");
  89.   ot("  str r0, [r7,#0x3C]\n");
  90.   ot("no_sp_swap%.4x%s\n", op, ms?"":":");
  91. }
  92.  
  93.  
  94.  
  95. // --------------------- Opcodes 0x1000+ ---------------------
  96. // Emit a Move opcode, 00xxdddd ddssssss
  97. int OpMove(int op)
  98. {
  99.   int sea=0,tea=0;
  100.   int size=0,use=0;
  101.   int movea=0;
  102.  
  103.   // Get source and target EA
  104.   sea = op&0x003f;
  105.   tea =(op&0x01c0)>>3;
  106.   tea|=(op&0x0e00)>>9;
  107.  
  108.   if (tea>=8 && tea<0x10) movea=1;
  109.  
  110.   // Find size extension
  111.   switch (op&0x3000)
  112.   {
  113.     default: return 1;
  114.     case 0x1000: size=0; break;
  115.     case 0x3000: size=1; break;
  116.     case 0x2000: size=2; break;
  117.   }
  118.  
  119.   if (size<1 && (movea || EaAn(sea))) return 1; // move.b An,* and movea.b * are invalid
  120.  
  121.   // See if we can do this opcode:
  122.   if (EaCanRead (sea,size)==0) return 1;
  123.   if (EaCanWrite(tea     )==0) return 1;
  124.  
  125.   use=OpBase(op,size);
  126.   if (tea<0x38) use&=~0x0e00; // Use same handler for register ?0-7
  127.  
  128.   if (tea==0x1f || tea==0x27) use|=0x0e00; // Specific handler for (a7)+ and -(a7)
  129.  
  130.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  131.  
  132.   OpStart(op,sea,tea); Cycles=4;
  133.  
  134.   if (movea==0)
  135.   {
  136.     EaCalcRead(-1,0,sea,size,0x003f);
  137.     ot("  adds r1,r0,#0 ;@ Defines NZ, clears CV\n");
  138.     ot("  mrs r10,cpsr ;@ r10=NZCV flags\n");
  139.     ot("\n");
  140.   }
  141.   else
  142.   {
  143.     EaCalcRead(-1,1,sea,size,0x003f);
  144.     size=2; // movea always expands to 32-bits
  145.   }
  146.  
  147.   eawrite_check_addrerr=1;
  148. #if SPLIT_MOVEL_PD
  149.   if ((tea&0x38)==0x20 && size==2) { // -(An)
  150.     EaCalc (8,0x0e00,tea,size,0,0);
  151.     ot("  mov r11,r1\n");
  152.     ot("  add r0,r8,#2\n");
  153.     EaWrite(0,     1,tea,1,0x0e00,0,0);
  154.     EaWrite(8,    11,tea,1,0x0e00,1);
  155.   }
  156.   else
  157. #endif
  158.   {
  159.     EaCalc (0,0x0e00,tea,size,0,0);
  160.     EaWrite(0,     1,tea,size,0x0e00,0,0);
  161.   }
  162.  
  163. #if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES
  164.   // this is a bit hacky (device handlers might modify cycles)
  165.   if (tea==0x39||((0x10<=tea&&tea<0x30)&&size>=1))
  166.     ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  167. #endif
  168.  
  169.   if((tea&0x38)==0x20) Cycles-=2; // less cycles when dest is -(An)
  170.  
  171.   OpEnd(sea,tea);
  172.   return 0;
  173. }
  174.  
  175. // --------------------- Opcodes 0x41c0+ ---------------------
  176. // Emit an Lea opcode, 0100nnn1 11aaaaaa
  177. int OpLea(int op)
  178. {
  179.   int use=0;
  180.   int sea=0,tea=0;
  181.  
  182.   sea= op&0x003f;
  183.   tea=(op&0x0e00)>>9; tea|=8;
  184.  
  185.   if (EaCanRead(sea,-1)==0) return 1; // See if we can do this opcode
  186.  
  187.   use=OpBase(op,0);
  188.   use&=~0x0e00; // Also use 1 handler for target ?0-7
  189.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  190.  
  191.   OpStart(op,sea,tea);
  192.  
  193.   eawrite_check_addrerr=1;
  194.   EaCalc (1,0x003f,sea,0); // Lea
  195.   EaCalc (0,0x0e00,tea,2);
  196.   EaWrite(0,     1,tea,2,0x0e00);
  197.  
  198.   Cycles=Ea_add_ns(g_lea_cycle_table,sea);
  199.  
  200.   OpEnd(sea,tea);
  201.  
  202.   return 0;
  203. }
  204.  
  205. // --------------------- Opcodes 0x40c0+ ---------------------
  206. // Move SR opcode, 01000tt0 11aaaaaa move SR
  207. int OpMoveSr(int op)
  208. {
  209.   int type=0,ea=0;
  210.   int use=0,size=1;
  211.  
  212.   type=(op>>9)&3; // from SR, from CCR, to CCR, to SR
  213.   ea=op&0x3f;
  214.  
  215.   if(EaAn(ea)) return 1; // can't use An regs
  216.  
  217.   switch(type)
  218.   {
  219.     case 0:
  220.       if (EaCanWrite(ea)==0) return 1; // See if we can do this opcode:
  221.       break;
  222.  
  223.     case 1:
  224.       return 1; // no such op in 68000
  225.  
  226.     case 2: case 3:
  227.       if (EaCanRead(ea,size)==0) return 1; // See if we can do this opcode:
  228.       break;
  229.   }
  230.  
  231.   use=OpBase(op,size);
  232.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  233.  
  234.   // 68000 model allows reading whole SR in user mode (but newer models don't)
  235.   OpStart(op,ea,0,0,type==3);
  236.   Cycles=12;
  237.   if (type==0) Cycles=(ea>=8)?8:6;
  238.  
  239.   if (type==0 || type==1)
  240.   {
  241.     eawrite_check_addrerr=1;
  242.     OpFlagsToReg(type==0);
  243.     EaCalc (0,0x003f,ea,size,0,0);
  244.     EaWrite(0,     1,ea,size,0x003f,0,0);
  245.   }
  246.  
  247.   if (type==2 || type==3)
  248.   {
  249.     EaCalcReadNoSE(-1,0,ea,size,0x003f);
  250.     OpRegToFlags(type==3,1);
  251.     if (type==3) {
  252.       SuperChange(op,1);
  253.       opend_check_interrupt = 1;
  254.       opend_check_trace = 1;
  255.       OpEnd(ea);
  256.       return 0;
  257.     }
  258.   }
  259.  
  260.   OpEnd(ea);
  261.  
  262.   return 0;
  263. }
  264.  
  265.  
  266. // Ori/Andi/Eori $nnnn,sr 0000t0t0 01111100
  267. int OpArithSr(int op)
  268. {
  269.   int type=0,ea=0;
  270.   int use=0,size=0;
  271.   int sr_mask=EMULATE_TRACE?0xa7:0x27;
  272.  
  273.   type=(op>>9)&5; if (type==4) return 1;
  274.   size=(op>>6)&1; // ccr or sr?
  275.   ea=0x3c;
  276.  
  277.   use=OpBase(op,size);
  278.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  279.  
  280.   OpStart(op,ea,0,0,size!=0); Cycles=16;
  281.  
  282.   EaCalcRead(-1,0,ea,size,0x003f);
  283.  
  284.   ot("  eor r1,r0,r0,ror #1 ;@ Bit 0=C^V\n");
  285.   ot("  tst r1,#1           ;@ 1 if C!=V\n");
  286.   ot("  eorne r0,r0,#3      ;@ ___XNZCV\n");
  287.   ot("  ldr r2,[r7,#0x4c]   ;@ Load old X bit\n");
  288.  
  289.   // note: old srh is already in r11 (done by OpStart)
  290.   if (type==0) {
  291.     ot("  orr r10,r10,r0,lsl #28\n");
  292.     ot("  orr r2,r2,r0,lsl #25 ;@ X bit\n");
  293.     if (size!=0) {
  294.       ot("  orr r1,r11,r0,lsr #8\n");
  295.       ot("  and r1,r1,#0x%02x ;@ mask-out unused bits\n",sr_mask);
  296.     }
  297.   }
  298.   if (type==1) {
  299.     ot("  and r10,r10,r0,lsl #28\n");
  300.     ot("  and r2,r2,r0,lsl #25 ;@ X bit\n");
  301.     if (size!=0)
  302.       ot("  and r1,r11,r0,lsr #8\n");
  303.   }
  304.   if (type==5) {
  305.     ot("  eor r10,r10,r0,lsl #28\n");
  306.     ot("  eor r2,r2,r0,lsl #25 ;@ X bit\n");
  307.     if (size!=0) {
  308.       ot("  eor r1,r11,r0,lsr #8\n");
  309.       ot("  and r1,r1,#0x%02x ;@ mask-out unused bits\n",sr_mask);
  310.     }
  311.   }
  312.  
  313.   ot("  str r2,[r7,#0x4c]   ;@ Save X bit\n");
  314.   if (size!=0)
  315.     ot("  strb r1,[r7,#0x44]\n");
  316.   ot("\n");
  317.  
  318.   // we can't enter supervisor mode, nor unmask irqs just by using OR
  319.   if (size!=0 && type!=0) {
  320.     SuperChange(op,1);
  321.     ot("\n");
  322.     opend_check_interrupt = 1;
  323.   }
  324.   // also can't set trace bit with AND
  325.   if (size!=0 && type!=1)
  326.     opend_check_trace = 1;
  327.  
  328.   OpEnd(ea);
  329.  
  330.   return 0;
  331. }
  332.  
  333. // --------------------- Opcodes 0x4850+ ---------------------
  334. // Emit an Pea opcode, 01001000 01aaaaaa
  335. int OpPea(int op)
  336. {
  337.   int use=0;
  338.   int ea=0;
  339.  
  340.   ea=op&0x003f; if (ea<0x10) return 1; // Swap opcode
  341.   if (EaCanRead(ea,-1)==0) return 1; // See if we can do this opcode:
  342.  
  343.   use=OpBase(op,0);
  344.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  345.  
  346.   OpStart(op,ea);
  347.  
  348.   ot("  ldr r11,[r7,#0x3c]\n");
  349.   EaCalc (1,0x003f, ea,0);
  350.   ot("\n");
  351.   ot("  sub r0,r11,#4 ;@ Predecrement A7\n");
  352.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  353.   ot("\n");
  354.   MemHandler(1,2); // Write 32-bit
  355.   ot("\n");
  356.  
  357.   Cycles=6+Ea_add_ns(g_pea_cycle_table,ea);
  358.  
  359.   OpEnd(ea);
  360.  
  361.   return 0;
  362. }
  363.  
  364. // --------------------- Opcodes 0x4880+ ---------------------
  365. // Emit a Movem opcode, 01001d00 1xeeeeee regmask
  366. int OpMovem(int op)
  367. {
  368.   int size=0,ea=0,cea=0,dir=0;
  369.   int use=0,decr=0,change=0;
  370.  
  371.   size=((op>>6)&1)+1; // word, long
  372.   ea=op&0x003f;
  373.   dir=(op>>10)&1; // Direction (1==ea2reg)
  374.  
  375.   if (dir) {
  376.     if (ea<0x10 || ea>0x3b || (ea&0x38)==0x20) return 1; // Invalid EA
  377.   } else {
  378.     if (ea<0x10 || ea>0x39 || (ea&0x38)==0x18) return 1;
  379.   }
  380.  
  381.   if ((ea&0x38)==0x18 || (ea&0x38)==0x20) change=1;
  382.   if ((ea&0x38)==0x20) decr=1; // -(An), bitfield is decr
  383.  
  384.   cea=ea; if (change) cea=0x10;
  385.  
  386.   use=OpBase(op,size);
  387.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  388.  
  389.   OpStart(op,ea,0,1);
  390.  
  391.   ot("  ldrh r11,[r4],#2 ;@ r11=register mask\n");
  392.   ot("\n");
  393.   ot(";@ Get the address into r6:\n");
  394.   EaCalc(6,0x003f,cea,size);
  395.  
  396. #if !MEMHANDLERS_NEED_PREV_PC
  397.   // must save PC, need a spare register
  398.   ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  399. #endif
  400.  
  401.   ot(";@ r4=Register Index*4:\n");
  402.   if (decr) ot("  mov r4,#0x40 ;@ order reversed for -(An)\n");
  403.   else      ot("  mov r4,#-4\n");
  404.  
  405.   ot("\n");
  406.   ot("  tst r11,r11\n");        // sanity check
  407.   ot("  beq NoRegs%.4x\n",op);
  408.  
  409. #if EMULATE_ADDRESS_ERRORS_IO
  410.   ot("\n");
  411.   ot("  tst r6,#1 ;@ address error?\n");
  412.   ot("  movne r0,r6\n");
  413.   ot("  bne ExceptionAddressError_%c_data\n",dir?'r':'w');
  414. #endif
  415.  
  416.   ot("\n");
  417.   ot("Movemloop%.4x%s\n",op, ms?"":":");
  418.   ot("  add r4,r4,#%d ;@ r4=Next Register\n",decr?-4:4);
  419.   ot("  movs r11,r11,lsr #1\n");
  420.   ot("  bcc Movemloop%.4x\n",op);
  421.   ot("\n");
  422.  
  423.   if (decr) ot("  sub r6,r6,#%d ;@ Pre-decrement address\n",1<<size);
  424.  
  425.   if (dir)
  426.   {
  427.     ot("  ;@ Copy memory to register:\n",1<<size);
  428.     earead_check_addrerr=0; // already checked
  429.     EaRead (6,0,ea,size,0x003f);
  430.     ot("  str r0,[r7,r4] ;@ Save value into Dn/An\n");
  431.   }
  432.   else
  433.   {
  434.     ot("  ;@ Copy register to memory:\n",1<<size);
  435.     ot("  ldr r1,[r7,r4] ;@ Load value from Dn/An\n");
  436. #if SPLIT_MOVEL_PD
  437.     if (decr && size==2) { // -(An)
  438.       ot("  add r0,r6,#2\n");
  439.       EaWrite(0,1,ea,1,0x003f,0,0);
  440.       ot("  ldr r1,[r7,r4] ;@ Load value from Dn/An\n");
  441.       ot("  mov r0,r6\n");
  442.       EaWrite(0,1,ea,1,0x003f,1);
  443.     }
  444.     else
  445. #endif
  446.     {
  447.       EaWrite(6,1,ea,size,0x003f);
  448.     }
  449.   }
  450.  
  451.   if (decr==0) ot("  add r6,r6,#%d ;@ Post-increment address\n",1<<size);
  452.  
  453.   ot("  sub r5,r5,#%d ;@ Take some cycles\n",2<<size);
  454.   ot("  tst r11,r11\n");
  455.   ot("  bne Movemloop%.4x\n",op);
  456.   ot("\n");
  457.  
  458.   if (change)
  459.   {
  460.     ot(";@ Write back address:\n");
  461.     EaCalc (0,0x0007,8|(ea&7),2);
  462.     EaWrite(0,     6,8|(ea&7),2,0x0007);
  463.   }
  464.  
  465.   ot("NoRegs%.4x%s\n",op, ms?"":":");
  466.   ot("  ldr r4,[r7,#0x40]\n");
  467.   ot("  ldr r6,[r7,#0x54] ;@ restore Opcode Jump table\n");
  468.   ot("\n");
  469.  
  470.   if(dir) { // er
  471.          if (ea==0x3a) Cycles=16; // ($nn,PC)
  472.     else if (ea==0x3b) Cycles=18; // ($nn,pc,Rn)
  473.     else Cycles=12;
  474.   } else {
  475.     Cycles=8;
  476.   }
  477.  
  478.   Cycles+=Ea_add_ns(g_movem_cycle_table,ea);
  479.  
  480.   opend_op_changes_cycles = 1;
  481.   OpEnd(ea);
  482.   ot("\n");
  483.  
  484.   return 0;
  485. }
  486.  
  487. // --------------------- Opcodes 0x4e60+ ---------------------
  488. // Emit a Move USP opcode, 01001110 0110dnnn move An to/from USP
  489. int OpMoveUsp(int op)
  490. {
  491.   int use=0,dir=0;
  492.  
  493.   dir=(op>>3)&1; // Direction
  494.   use=op&~0x0007; // Use same opcode for all An
  495.  
  496.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  497.  
  498.   OpStart(op,0,0,0,1); Cycles=4;
  499.  
  500.   if (dir)
  501.   {
  502.     eawrite_check_addrerr=1;
  503.     ot("  ldr r1,[r7,#0x48] ;@ Get from USP\n\n");
  504.     EaCalc (0,0x000f,8,2,1);
  505.     EaWrite(0,     1,8,2,0x000f,1);
  506.   }
  507.   else
  508.   {
  509.     EaCalc (0,0x000f,8,2,1);
  510.     EaRead (0,     0,8,2,0x000f,1);
  511.     ot("  str r0,[r7,#0x48] ;@ Put in USP\n\n");
  512.   }
  513.    
  514.   OpEnd();
  515.  
  516.   return 0;
  517. }
  518.  
  519. // --------------------- Opcodes 0x7000+ ---------------------
  520. // Emit a Move Quick opcode, 0111nnn0 dddddddd  moveq #dd,Dn
  521. int OpMoveq(int op)
  522. {
  523.   int use=0;
  524.  
  525.   use=op&0xf100; // Use same opcode for all values
  526.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  527.  
  528.   OpStart(op); Cycles=4;
  529.  
  530.   ot("  movs r0,r8,asl #24\n");
  531.   ot("  and r1,r8,#0x0e00\n");
  532.   ot("  mov r0,r0,asr #24 ;@ Sign extended Quick value\n");
  533.   ot("  mrs r10,cpsr ;@ r10=NZ flags\n");
  534.   ot("  str r0,[r7,r1,lsr #7] ;@ Store into Dn\n");
  535.   ot("\n");
  536.  
  537.   OpEnd();
  538.  
  539.   return 0;
  540. }
  541.  
  542. // --------------------- Opcodes 0xc140+ ---------------------
  543. // Emit a Exchange opcode:
  544. // 1100ttt1 01000sss  exg ds,dt
  545. // 1100ttt1 01001sss  exg as,at
  546. // 1100ttt1 10001sss  exg as,dt
  547. int OpExg(int op)
  548. {
  549.   int use=0,type=0;
  550.  
  551.   type=op&0xf8;
  552.  
  553.   if (type!=0x40 && type!=0x48 && type!=0x88) return 1; // Not an exg opcode
  554.  
  555.   use=op&0xf1f8; // Use same opcode for all values
  556.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  557.  
  558.   OpStart(op); Cycles=6;
  559.  
  560.   ot("  and r2,r8,#0x0e00 ;@ Find T register\n");
  561.   ot("  and r3,r8,#0x000f ;@ Find S register\n");
  562.   if (type==0x48) ot("  orr r2,r2,#0x1000 ;@ T is an address register\n");
  563.   ot("\n");
  564.   ot("  ldr r0,[r7,r2,lsr #7] ;@ Get T\n");
  565.   ot("  ldr r1,[r7,r3,lsl #2] ;@ Get S\n");
  566.   ot("\n");
  567.   ot("  str r0,[r7,r3,lsl #2] ;@ T->S\n");
  568.   ot("  str r1,[r7,r2,lsr #7] ;@ S->T\n");  
  569.   ot("\n");
  570.  
  571.   OpEnd();
  572.  
  573.   return 0;
  574. }
  575.  
  576. // ------------------------- movep -------------------------------
  577. // 0000ddd1 0z001sss
  578. // 0000sss1 1z001ddd (to mem)
  579. int OpMovep(int op)
  580. {
  581.   int ea=0,rea=0;
  582.   int size=1,use=0,dir,aadd=0;
  583.  
  584.   use=op&0xf1f8;
  585.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler (for all dests, srcs)
  586.  
  587.   // Get EA
  588.   ea = (op&0x0007)|0x28;
  589.   rea= (op&0x0e00)>>9;
  590.   dir = (op>>7)&1;
  591.  
  592.   // Find size extension
  593.   if(op&0x0040) size=2;
  594.  
  595.   OpStart(op,ea);
  596.  
  597.   if(dir) // reg to mem
  598.   {
  599.     EaCalcReadNoSE(-1,11,rea,size,0x0e00);
  600.  
  601.     EaCalc(8,0x000f,ea,size);
  602.     if(size==2) { // if operand is long
  603.       ot("  mov r1,r11,lsr #24 ;@ first byte\n");
  604.       EaWrite(8,1,ea,0,0x000f); // store first byte
  605.       ot("  add r0,r8,#%i\n",(aadd+=2));
  606.       ot("  mov r1,r11,lsr #16 ;@ second byte\n");
  607.       EaWrite(0,1,ea,0,0x000f); // store second byte
  608.       ot("  add r0,r8,#%i\n",(aadd+=2));
  609.     } else {
  610.       ot("  mov r0,r8\n");
  611.     }
  612.     ot("  mov r1,r11,lsr #8 ;@ first or third byte\n");
  613.     EaWrite(0,1,ea,0,0x000f);
  614.     ot("  add r0,r8,#%i\n",(aadd+=2));
  615.     ot("  and r1,r11,#0xff\n");
  616.     EaWrite(0,1,ea,0,0x000f);
  617.   }
  618.   else // mem to reg
  619.   {
  620.     EaCalc(6,0x000f,ea,size,1);
  621.     EaRead(6,11,ea,0,0x000f,1); // read first byte
  622.     ot("  add r0,r6,#2\n");
  623.     EaRead(0,1,ea,0,0x000f,1); // read second byte
  624.     if(size==2) { // if operand is long
  625.       ot("  orr r11,r11,r1,lsr #8 ;@ second byte\n");
  626.       ot("  add r0,r6,#4\n");
  627.       EaRead(0,1,ea,0,0x000f,1);
  628.       ot("  orr r11,r11,r1,lsr #16 ;@ third byte\n");
  629.       ot("  add r0,r6,#6\n");
  630.       EaRead(0,1,ea,0,0x000f,1);
  631.       ot("  orr r1,r11,r1,lsr #24 ;@ fourth byte\n");
  632.     } else {
  633.       ot("  orr r1,r11,r1,lsr #8 ;@ second byte\n");
  634.     }
  635.     // store the result
  636.     EaCalc(0,0x0e00,rea,size,1);
  637.     EaWrite(0,1,rea,size,0x0e00,1);
  638.     ot("  ldr r6,[r7,#0x54]\n");
  639.   }
  640.  
  641.   Cycles=(size==2)?24:16;
  642.   OpEnd(ea);
  643.  
  644.   return 0;
  645. }
  646.  
  647. // Emit a Stop/Reset opcodes, 01001110 011100t0 imm
  648. int OpStopReset(int op)
  649. {
  650.   int type=(op>>1)&1; // stop/reset
  651.  
  652.   OpStart(op,0,0,0,1);
  653.  
  654.   if(type) {
  655.     // copy immediate to SR, stop the CPU and eat all remaining cycles.
  656.     ot("  ldrh r0,[r4],#2 ;@ Fetch the immediate\n");
  657.     OpRegToFlags(1);
  658.     SuperChange(op,0);
  659.  
  660.     ot("\n");
  661.  
  662.     ot("  ldr r0,[r7,#0x58]\n");
  663.     ot("  mov r5,#0 ;@ eat cycles\n");
  664.     ot("  orr r0,r0,#1 ;@ stopped\n");
  665.     ot("  str r0,[r7,#0x58]\n");
  666.     ot("\n");
  667.  
  668.     Cycles = 4;
  669.     ot("\n");
  670.   }
  671.   else
  672.   {
  673.     Cycles = 132;
  674. #if USE_RESET_CALLBACK
  675.     ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  676.     ot("  mov r1,r10,lsr #28\n");
  677.     ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  678.     ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
  679.     ot("  ldr r11,[r7,#0x90] ;@ ResetCallback\n");
  680.     ot("  tst r11,r11\n");
  681.     ot("  movne lr,pc\n");
  682.     ot("  bxne r11 ;@ call ResetCallback if it is defined\n");
  683.     ot("  ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n");
  684.     ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  685.     ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");
  686.     ot("  mov r10,r10,lsl #28\n");
  687.     ot("\n");
  688. #endif
  689.   }
  690.  
  691.   OpEnd();
  692.  
  693.   return 0;
  694. }
  695.  
  696.