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. // --------------------- Opcodes 0x0100+ ---------------------
  16. // Emit a Btst (Register) opcode 0000nnn1 ttaaaaaa
  17. int OpBtstReg(int op)
  18. {
  19.   int use=0;
  20.   int type=0,sea=0,tea=0;
  21.   int size=0;
  22.  
  23.   type=(op>>6)&3; // Btst/Bchg/Bclr/Bset
  24.   // Get source and target EA
  25.   sea=(op>>9)&7;
  26.   tea=op&0x003f;
  27.   if (tea<0x10) size=2; // For registers, 32-bits
  28.  
  29.   if ((tea&0x38)==0x08) return 1; // movep
  30.  
  31.   // See if we can do this opcode:
  32.   if (EaCanRead(tea,0)==0) return 1;
  33.   if (type>0)
  34.   {
  35.     if (EaCanWrite(tea)==0) return 1;
  36.   }
  37.  
  38.   use=OpBase(op,size);
  39.   use&=~0x0e00; // Use same handler for all registers
  40.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  41.  
  42.   OpStart(op,tea);
  43.  
  44.   if(type==1||type==3) {
  45.     Cycles=8;
  46.   } else {
  47.     Cycles=type?8:4;
  48.     if(size>=2) Cycles+=2;
  49.   }
  50.  
  51.   EaCalcReadNoSE(-1,11,sea,0,0x0e00);
  52.  
  53.   EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f);
  54.  
  55.   if (tea>=0x10)
  56.        ot("  and r11,r11,#7  ;@ mem - do mod 8\n");  // size always 0
  57.   else ot("  and r11,r11,#31 ;@ reg - do mod 32\n"); // size always 2
  58.   ot("\n");
  59.  
  60.   ot("  mov r1,#1\n");
  61.   ot("  tst r0,r1,lsl r11 ;@ Do arithmetic\n");
  62.   ot("  bicne r10,r10,#0x40000000\n");
  63.   ot("  orreq r10,r10,#0x40000000 ;@ Get Z flag\n");
  64.   ot("\n");
  65.  
  66.   if (type>0)
  67.   {
  68.     if (type==1) ot("  eor r1,r0,r1,lsl r11 ;@ Toggle bit\n");
  69.     if (type==2) ot("  bic r1,r0,r1,lsl r11 ;@ Clear bit\n");
  70.     if (type==3) ot("  orr r1,r0,r1,lsl r11 ;@ Set bit\n");
  71.     ot("\n");
  72.     EaWrite(8,1,tea,size,0x003f,0,0);
  73.   }
  74.   OpEnd(tea);
  75.  
  76.   return 0;
  77. }
  78.  
  79. // --------------------- Opcodes 0x0800+ ---------------------
  80. // Emit a Btst/Bchg/Bclr/Bset (Immediate) opcode 00001000 ttaaaaaa nn
  81. int OpBtstImm(int op)
  82. {
  83.   int type=0,sea=0,tea=0;
  84.   int use=0;
  85.   int size=0;
  86.  
  87.   type=(op>>6)&3;
  88.   // Get source and target EA
  89.   sea=   0x003c;
  90.   tea=op&0x003f;
  91.   if (tea<0x10) size=2; // For registers, 32-bits
  92.  
  93.   // See if we can do this opcode:
  94.   if (EaCanRead(tea,0)==0||EaAn(tea)||tea==0x3c) return 1;
  95.   if (type>0)
  96.   {
  97.     if (EaCanWrite(tea)==0) return 1;
  98.   }
  99.  
  100.   use=OpBase(op,size);
  101.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  102.  
  103.   OpStart(op,sea,tea);
  104.  
  105.   ot("\n");
  106.   EaCalcReadNoSE(-1,0,sea,0,0);
  107.   ot("  mov r11,#1\n");
  108.   ot("  bic r10,r10,#0x40000000 ;@ Blank Z flag\n");
  109.   if (tea>=0x10)
  110.        ot("  and r0,r0,#7    ;@ mem - do mod 8\n");  // size always 0
  111.   else ot("  and r0,r0,#0x1F ;@ reg - do mod 32\n"); // size always 2
  112.   ot("  mov r11,r11,lsl r0 ;@ Make bit mask\n");
  113.   ot("\n");
  114.  
  115.   if(type==1||type==3) {
  116.     Cycles=12;
  117.   } else {
  118.     Cycles=type?12:8;
  119.     if(size>=2) Cycles+=2;
  120.   }
  121.  
  122.   EaCalcReadNoSE((type>0)?8:-1,0,tea,size,0x003f);
  123.   ot("  tst r0,r11 ;@ Do arithmetic\n");
  124.   ot("  orreq r10,r10,#0x40000000 ;@ Get Z flag\n");
  125.   ot("\n");
  126.  
  127.   if (type>0)
  128.   {
  129.     if (type==1) ot("  eor r1,r0,r11 ;@ Toggle bit\n");
  130.     if (type==2) ot("  bic r1,r0,r11 ;@ Clear bit\n");
  131.     if (type==3) ot("  orr r1,r0,r11 ;@ Set bit\n");
  132.     ot("\n");
  133.     EaWrite(8,   1,tea,size,0x003f,0,0);
  134. #if CYCLONE_FOR_GENESIS && !MEMHANDLERS_CHANGE_CYCLES
  135.     // this is a bit hacky (device handlers might modify cycles)
  136.     if (tea==0x38||tea==0x39)
  137.       ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  138. #endif
  139.   }
  140.  
  141.   OpEnd(sea,tea);
  142.  
  143.   return 0;
  144. }
  145.  
  146. // --------------------- Opcodes 0x4000+ ---------------------
  147. int OpNeg(int op)
  148. {
  149.   // 01000tt0 xxeeeeee (tt=negx/clr/neg/not, xx=size, eeeeee=EA)
  150.   int type=0,size=0,ea=0,use=0;
  151.  
  152.   type=(op>>9)&3;
  153.   ea  =op&0x003f;
  154.   size=(op>>6)&3; if (size>=3) return 1;
  155.  
  156.   // See if we can do this opcode:
  157.   if (EaCanRead (ea,size)==0||EaAn(ea)) return 1;
  158.   if (EaCanWrite(ea     )==0) return 1;
  159.  
  160.   use=OpBase(op,size);
  161.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  162.  
  163.   OpStart(op,ea); Cycles=size<2?4:6;
  164.   if(ea >= 0x10)  Cycles*=2;
  165.  
  166.   EaCalc (11,0x003f,ea,size,0,0);
  167.  
  168.   if (type!=1) EaRead (11,0,ea,size,0x003f,0,0); // Don't need to read for 'clr' (or do we, for a dummy read?)
  169.   if (type==1) ot("\n");
  170.  
  171.   if (type==0)
  172.   {
  173.     ot(";@ Negx:\n");
  174.     GetXBit(1);
  175.     if(size!=2) ot("  mov r0,r0,asl #%i\n",size?16:24);
  176.     ot("  rscs r1,r0,#0 ;@ do arithmetic\n");
  177.     ot("  orr r3,r10,#0xb0000000 ;@ for old Z\n");
  178.     OpGetFlags(1,1,0);
  179.     if(size!=2) {
  180.       ot("  movs r1,r1,asr #%i\n",size?16:24);
  181.       ot("  orreq r10,r10,#0x40000000 ;@ possily missed Z\n");
  182.     }
  183.     ot("  andeq r10,r10,r3 ;@ fix Z\n");
  184.     ot("\n");
  185.   }
  186.  
  187.   if (type==1)
  188.   {
  189.     ot(";@ Clear:\n");
  190.     ot("  mov r1,#0\n");
  191.     ot("  mov r10,#0x40000000 ;@ NZCV=0100\n");
  192.     ot("\n");
  193.   }
  194.  
  195.   if (type==2)
  196.   {
  197.     ot(";@ Neg:\n");
  198.     if(size!=2) ot("  mov r0,r0,asl #%i\n",size?16:24);
  199.     ot("  rsbs r1,r0,#0\n");
  200.     OpGetFlags(1,1);
  201.     if(size!=2) ot("  mov r1,r1,asr #%i\n",size?16:24);
  202.     ot("\n");
  203.   }
  204.  
  205.   if (type==3)
  206.   {
  207.     ot(";@ Not:\n");
  208.     if(size!=2) {
  209.       ot("  mov r0,r0,asl #%i\n",size?16:24);
  210.       ot("  mvn r1,r0,asr #%i\n",size?16:24);
  211.     }
  212.     else
  213.       ot("  mvn r1,r0\n");
  214.     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  215.     OpGetFlags(0,0);
  216.     ot("\n");
  217.   }
  218.  
  219.   if (type==1) eawrite_check_addrerr=1;
  220.   EaWrite(11,     1,ea,size,0x003f,0,0);
  221.  
  222.   OpEnd(ea);
  223.  
  224.   return 0;
  225. }
  226.  
  227. // --------------------- Opcodes 0x4840+ ---------------------
  228. // Swap, 01001000 01000nnn swap Dn
  229. int OpSwap(int op)
  230. {
  231.   int ea=0,use=0;
  232.  
  233.   ea=op&7;
  234.   use=op&~0x0007; // Use same opcode for all An
  235.  
  236.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  237.  
  238.   OpStart(op); Cycles=4;
  239.  
  240.   EaCalc (11,0x0007,ea,2,1);
  241.   EaRead (11,     0,ea,2,0x0007,1);
  242.  
  243.   ot("  mov r1,r0,ror #16\n");
  244.   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  245.   OpGetFlags(0,0);
  246.  
  247.   EaWrite(11,     1,8,2,0x0007,1);
  248.  
  249.   OpEnd();
  250.  
  251.   return 0;
  252. }
  253.  
  254. // --------------------- Opcodes 0x4a00+ ---------------------
  255. // Emit a Tst opcode, 01001010 xxeeeeee
  256. int OpTst(int op)
  257. {
  258.   int sea=0;
  259.   int size=0,use=0;
  260.  
  261.   sea=op&0x003f;
  262.   size=(op>>6)&3; if (size>=3) return 1;
  263.  
  264.   // See if we can do this opcode:
  265.   if (EaCanWrite(sea)==0||EaAn(sea)) return 1;
  266.  
  267.   use=OpBase(op,size);
  268.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  269.  
  270.   OpStart(op,sea); Cycles=4;
  271.  
  272.   EaCalc ( 0,0x003f,sea,size,1);
  273.   EaRead ( 0,     0,sea,size,0x003f,1);
  274.  
  275.   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
  276.   ot("  mrs r10,cpsr ;@ r10=flags\n");
  277.   ot("\n");
  278.  
  279.   OpEnd(sea);
  280.   return 0;
  281. }
  282.  
  283. // --------------------- Opcodes 0x4880+ ---------------------
  284. // Emit an Ext opcode, 01001000 1x000nnn
  285. int OpExt(int op)
  286. {
  287.   int ea=0;
  288.   int size=0,use=0;
  289.   int shift=0;
  290.  
  291.   ea=op&0x0007;
  292.   size=(op>>6)&1;
  293.   shift=32-(8<<size);
  294.  
  295.   use=OpBase(op,size);
  296.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  297.  
  298.   OpStart(op); Cycles=4;
  299.  
  300.   EaCalc (11,0x0007,ea,size+1,0,0);
  301.   EaRead (11,     0,ea,size+1,0x0007,0,0);
  302.  
  303.   ot("  mov r0,r0,asl #%d\n",shift);
  304.   ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
  305.   ot("  mrs r10,cpsr ;@ r10=flags\n");
  306.   ot("  mov r1,r0,asr #%d\n",shift);
  307.   ot("\n");
  308.  
  309.   EaWrite(11,     1,ea,size+1,0x0007,0,0);
  310.  
  311.   OpEnd();
  312.   return 0;
  313. }
  314.  
  315. // --------------------- Opcodes 0x50c0+ ---------------------
  316. // Emit a Set cc opcode, 0101cccc 11eeeeee
  317. int OpSet(int op)
  318. {
  319.   int cc=0,ea=0;
  320.   int size=0,use=0,changed_cycles=0;
  321.   static const char * const cond[16]=
  322.   {
  323.     "al","", "hi","ls","cc","cs","ne","eq",
  324.     "vc","vs","pl","mi","ge","lt","gt","le"
  325.   };
  326.  
  327.   cc=(op>>8)&15;
  328.   ea=op&0x003f;
  329.  
  330.   if ((ea&0x38)==0x08) return 1; // dbra, not scc
  331.  
  332.   // See if we can do this opcode:
  333.   if (EaCanWrite(ea)==0) return 1;
  334.  
  335.   use=OpBase(op,size);
  336.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  337.  
  338.   changed_cycles=ea<8 && cc>=2;
  339.   OpStart(op,ea,0,changed_cycles); Cycles=8;
  340.   if (ea<8) Cycles=4;
  341.  
  342.   if (cc)
  343.     ot("  mov r1,#0\n");
  344.  
  345.   switch (cc)
  346.   {
  347.     case 0: // T
  348.       ot("  mvn r1,#0\n");
  349.       if (ea<8) Cycles+=2;
  350.       break;
  351.     case 1: // F
  352.       break;
  353.     case 2: // hi
  354.       ot("  tst r10,#0x60000000 ;@ hi: !C && !Z\n");
  355.       ot("  mvneq r1,r1\n");
  356.       if (ea<8) ot("  subeq r5,r5,#2 ;@ Extra cycles\n");
  357.       break;
  358.     case 3: // ls
  359.       ot("  tst r10,#0x60000000 ;@ ls: C || Z\n");
  360.       ot("  mvnne r1,r1\n");
  361.       if (ea<8) ot("  subne r5,r5,#2 ;@ Extra cycles\n");
  362.       break;
  363.     default:
  364.       ot(";@ Is the condition true?\n");
  365.       ot("  msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n");
  366.       ot("  mvn%s r1,r1\n",cond[cc]);
  367.       if (ea<8) ot("  sub%s r5,r5,#2 ;@ Extra cycles\n",cond[cc]);
  368.       break;
  369.   }
  370.  
  371.   ot("\n");
  372.  
  373.   eawrite_check_addrerr=1;
  374.   EaCalc (0,0x003f, ea,size,0,0);
  375.   EaWrite(0,     1, ea,size,0x003f,0,0);
  376.  
  377.   opend_op_changes_cycles=changed_cycles;
  378.   OpEnd(ea,0);
  379.   return 0;
  380. }
  381.  
  382. // Emit a Asr/Lsr/Roxr/Ror opcode
  383. static int EmitAsr(int op,int type,int dir,int count,int size,int usereg)
  384. {
  385.   char pct[8]=""; // count
  386.   int shift=32-(8<<size);
  387.  
  388.   if (count>=1) sprintf(pct,"#%d",count); // Fixed count
  389.  
  390.   if (usereg)
  391.   {
  392.     ot(";@ Use Dn for count:\n");
  393.     ot("  and r2,r8,#0x0e00\n");
  394.     ot("  ldr r2,[r7,r2,lsr #7]\n");
  395.     ot("  and r2,r2,#63\n");
  396.     ot("\n");
  397.     strcpy(pct,"r2");
  398.   }
  399.   else if (count<0)
  400.   {
  401.     ot("  mov r2,r8,lsr #9 ;@ Get 'n'\n");
  402.     ot("  and r2,r2,#7\n\n"); strcpy(pct,"r2");
  403.   }
  404.  
  405.   // Take 2*n cycles:
  406.   if (count<0) ot("  sub r5,r5,r2,asl #1 ;@ Take 2*n cycles\n\n");
  407.   else Cycles+=count<<1;
  408.  
  409.   if (type<2)
  410.   {
  411.     // Asr/Lsr
  412.     if (dir==0 && size<2)
  413.     {
  414.       ot(";@ For shift right, use loworder bits for the operation:\n");
  415.       ot("  mov r0,r0,%s #%d\n",type?"lsr":"asr",32-(8<<size));
  416.       ot("\n");
  417.     }
  418.  
  419.     if (type==0 && dir) ot("  adds r3,r0,#0 ;@ save old value for V flag calculation, also clear V\n");
  420.  
  421.     ot(";@ Shift register:\n");
  422.     if (type==0) ot("  movs r0,r0,%s %s\n",dir?"asl":"asr",pct);
  423.     if (type==1) ot("  movs r0,r0,%s %s\n",dir?"lsl":"lsr",pct);
  424.  
  425.     OpGetFlags(0,0);
  426.     if (usereg) { // store X only if count is not 0
  427.       ot("  cmp %s,#0 ;@ shifting by 0?\n",pct);
  428.       ot("  biceq r10,r10,#0x20000000 ;@ if so, clear carry\n");
  429.       ot("  strne r10,[r7,#0x4c] ;@ else Save X bit\n");
  430.     } else {
  431.       // count will never be 0 if we use immediate
  432.       ot("  str r10,[r7,#0x4c] ;@ Save X bit\n");
  433.     }
  434.     ot("\n");
  435.  
  436.     if (dir==0 && size<2)
  437.     {
  438.       ot(";@ restore after right shift:\n");
  439.       ot("  movs r0,r0,lsl #%d\n",32-(8<<size));
  440.       if (type)
  441.         ot("  orrmi r10,r10,#0x80000000 ;@ Potentially missed N flag\n");
  442.       ot("\n");
  443.     }
  444.  
  445.     if (type==0 && dir) {
  446.       ot(";@ calculate V flag (set if sign bit changes at anytime):\n");
  447.       ot("  mov r1,#0x80000000\n");
  448.       ot("  ands r3,r3,r1,asr %s\n", pct);
  449.       ot("  cmpne r3,r1,asr %s\n", pct);
  450.       ot("  eoreq r1,r0,r3\n"); // above check doesn't catch (-1)<<(32+), so we need this
  451.       ot("  tsteq r1,#0x80000000\n");
  452.       ot("  orrne r10,r10,#0x10000000\n");
  453.       ot("\n");
  454.     }
  455.   }
  456.  
  457.   // --------------------------------------
  458.   if (type==2)
  459.   {
  460.     int wide=8<<size;
  461.  
  462.     // Roxr
  463.     if(count == 1)
  464.     {
  465.       if(dir==0) {
  466.         if(size!=2) {
  467.           ot("  orr r0,r0,r0,lsr #%i\n", size?16:24);
  468.           ot("  bic r0,r0,#0x%x\n", 1<<(32-wide));
  469.         }
  470.         GetXBit(0);
  471.         ot("  movs r0,r0,rrx\n");
  472.         OpGetFlags(0,1);
  473.       } else {
  474.         ot("  ldr r3,[r7,#0x4c]\n");
  475.         ot("  movs r0,r0,lsl #1\n");
  476.         OpGetFlags(0,1);
  477.         ot("  tst r3,#0x20000000\n");
  478.         ot("  orrne r0,r0,#0x%x\n", 1<<(32-wide));
  479.         ot("  bicne r10,r10,#0x40000000 ;@ clear Z in case it got there\n");
  480.       }
  481.       ot("  bic r10,r10,#0x10000000 ;@ make suve V is clear\n");
  482.       return 0;
  483.     }
  484.  
  485.     if (usereg)
  486.     {
  487.       if (size==2)
  488.       {
  489.         ot("  subs r2,r2,#33\n");
  490.         ot("  addmis r2,r2,#33 ;@ Now r2=0-%d\n",wide);
  491.       }
  492.       else
  493.       {
  494.         ot(";@ Reduce r2 until <0:\n");
  495.         ot("Reduce_%.4x%s\n",op,ms?"":":");
  496.         ot("  subs r2,r2,#%d\n",wide+1);
  497.         ot("  bpl Reduce_%.4x\n",op);
  498.         ot("  adds r2,r2,#%d ;@ Now r2=0-%d\n",wide+1,wide);
  499.       }
  500.       ot("  beq norotx_%.4x\n",op);
  501.       ot("\n");
  502.     }
  503.  
  504.     if (usereg||count < 0)
  505.     {
  506.       if (dir) ot("  rsb r2,r2,#%d ;@ Reverse direction\n",wide+1);
  507.     }
  508.     else
  509.     {
  510.       if (dir) ot("  mov r2,#%d ;@ Reversed\n",wide+1-count);
  511.       else     ot("  mov r2,#%d\n",count);
  512.     }
  513.  
  514.     if (shift) ot("  mov r0,r0,lsr #%d ;@ Shift down\n",shift);
  515.  
  516.     ot("\n");
  517.     ot(";@ First get X bit (middle):\n");
  518.     ot("  ldr r3,[r7,#0x4c]\n");
  519.     ot("  rsb r1,r2,#%d\n",wide);
  520.     ot("  and r3,r3,#0x20000000\n");
  521.     ot("  mov r3,r3,lsr #29\n");
  522.     ot("  mov r3,r3,lsl r1\n");
  523.  
  524.     ot(";@ Rotate bits:\n");
  525.     ot("  orr r3,r3,r0,lsr r2 ;@ Orr right part\n");
  526.     ot("  rsbs r2,r2,#%d ;@ should also clear ARM V\n",wide+1);
  527.     ot("  orrs r0,r3,r0,lsl r2 ;@ Orr left part, set flags\n");
  528.     ot("\n");
  529.  
  530.     if (shift) ot("  movs r0,r0,lsl #%d ;@ Shift up and get correct NC flags\n",shift);
  531.     OpGetFlags(0,!usereg);
  532.     if (usereg) { // store X only if count is not 0
  533.       ot("  str r10,[r7,#0x4c] ;@ if not 0, Save X bit\n");
  534.       ot("  b nozerox%.4x\n",op);
  535.       ot("norotx_%.4x%s\n",op,ms?"":":");
  536.       ot("  ldr r2,[r7,#0x4c]\n");
  537.       ot("  adds r0,r0,#0 ;@ Defines NZ, clears CV\n");
  538.       OpGetFlags(0,0);
  539.       ot("  and r2,r2,#0x20000000\n");
  540.       ot("  orr r10,r10,r2 ;@ C = old_X\n");
  541.       ot("nozerox%.4x%s\n",op,ms?"":":");
  542.     }
  543.  
  544.     ot("\n");
  545.   }
  546.  
  547.   // --------------------------------------
  548.   if (type==3)
  549.   {
  550.     // Ror
  551.     if (size<2)
  552.     {
  553.       ot(";@ Mirror value in whole 32 bits:\n");
  554.       if (size<=0) ot("  orr r0,r0,r0,lsr #8\n");
  555.       if (size<=1) ot("  orr r0,r0,r0,lsr #16\n");
  556.       ot("\n");
  557.     }
  558.  
  559.     ot(";@ Rotate register:\n");
  560.     if (!dir) ot("  adds r0,r0,#0 ;@ first clear V and C\n"); // ARM does not clear C if rot count is 0
  561.     if (count<0)
  562.     {
  563.       if (dir) ot("  rsb %s,%s,#32\n",pct,pct);
  564.       ot("  movs r0,r0,ror %s\n",pct);
  565.     }
  566.     else
  567.     {
  568.       int ror=count;
  569.       if (dir) ror=32-ror;
  570.       if (ror&31) ot("  movs r0,r0,ror #%d\n",ror);
  571.     }
  572.  
  573.     OpGetFlags(0,0);
  574.     if (dir)
  575.     {
  576.       ot("  bic r10,r10,#0x30000000 ;@ clear CV\n");
  577.       ot(";@ Get carry bit from bit 0:\n");
  578.       if (usereg)
  579.       {
  580.         ot("  cmp %s,#32 ;@ rotating by 0?\n",pct);
  581.         ot("  tstne r0,#1 ;@ no, check bit 0\n");
  582.       }
  583.       else
  584.         ot("  tst r0,#1\n");
  585.       ot("  orrne r10,r10,#0x20000000\n");
  586.     }
  587.     ot("\n");
  588.  
  589.   }
  590.   // --------------------------------------
  591.  
  592.   return 0;
  593. }
  594.  
  595. // Emit a Asr/Lsr/Roxr/Ror opcode - 1110cccd xxuttnnn
  596. // (ccc=count, d=direction(r,l) xx=size extension, u=use reg for count, tt=type, nnn=register Dn)
  597. int OpAsr(int op)
  598. {
  599.   int ea=0,use=0;
  600.   int count=0,dir=0;
  601.   int size=0,usereg=0,type=0;
  602.  
  603.   count =(op>>9)&7;
  604.   dir   =(op>>8)&1;
  605.   size  =(op>>6)&3;
  606.   if (size>=3) return 1; // use OpAsrEa()
  607.   usereg=(op>>5)&1;
  608.   type  =(op>>3)&3;
  609.  
  610.   if (usereg==0) count=((count-1)&7)+1; // because ccc=000 means 8
  611.  
  612.   // Use the same opcode for target registers:
  613.   use=op&~0x0007;
  614.  
  615.   // As long as count is not 8, use the same opcode for all shift counts:
  616.   if (usereg==0 && count!=8 && !(count==1&&type==2)) { use|=0x0e00; count=-1; }
  617.   if (usereg) { use&=~0x0e00; count=-1; } // Use same opcode for all Dn
  618.  
  619.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  620.  
  621.   OpStart(op,ea,0,count<0); Cycles=size<2?6:8;
  622.  
  623.   EaCalc(11,0x0007, ea,size,1);
  624.   EaRead(11,     0, ea,size,0x0007,1);
  625.  
  626.   EmitAsr(op,type,dir,count, size,usereg);
  627.  
  628.   EaWrite(11,    0, ea,size,0x0007,1);
  629.  
  630.   opend_op_changes_cycles = (count<0);
  631.   OpEnd(ea,0);
  632.  
  633.   return 0;
  634. }
  635.  
  636. // Asr/Lsr/Roxr/Ror etc EA - 11100ttd 11eeeeee
  637. int OpAsrEa(int op)
  638. {
  639.   int use=0,type=0,dir=0,ea=0,size=1;
  640.  
  641.   type=(op>>9)&3;
  642.   dir =(op>>8)&1;
  643.   ea  = op&0x3f;
  644.  
  645.   if (ea<0x10) return 1;
  646.   // See if we can do this opcode:
  647.   if (EaCanRead(ea,0)==0) return 1;
  648.   if (EaCanWrite(ea)==0) return 1;
  649.  
  650.   use=OpBase(op,size);
  651.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  652.  
  653.   OpStart(op,ea); Cycles=6; // EmitAsr() will add 2
  654.  
  655.   EaCalc (11,0x003f,ea,size,1);
  656.   EaRead (11,     0,ea,size,0x003f,1);
  657.  
  658.   EmitAsr(op,type,dir,1,size,0);
  659.  
  660.   EaWrite(11,     0,ea,size,0x003f,1);
  661.  
  662.   OpEnd(ea);
  663.   return 0;
  664. }
  665.  
  666. int OpTas(int op, int gen_special)
  667. {
  668.   int ea=0;
  669.   int use=0;
  670.  
  671.   ea=op&0x003f;
  672.  
  673.   // See if we can do this opcode:
  674.   if (EaCanWrite(ea)==0 || EaAn(ea)) return 1;
  675.  
  676.   use=OpBase(op,0);
  677.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  678.  
  679.   if (!gen_special) OpStart(op,ea);
  680.   else
  681.     ot("Op%.4x_%s\n", op, ms?"":":");
  682.  
  683.   Cycles=4;
  684.   if(ea>=8) Cycles+=10;
  685.  
  686.   EaCalc (11,0x003f,ea,0,1);
  687.   EaRead (11,     1,ea,0,0x003f,1);
  688.  
  689.   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  690.   OpGetFlags(0,0);
  691.   ot("\n");
  692.  
  693. #if CYCLONE_FOR_GENESIS
  694.   // the original Sega hardware ignores write-back phase (to memory only)
  695.   if (ea < 0x10 || gen_special) {
  696. #endif
  697.     ot("  orr r1,r1,#0x80000000 ;@ set bit7\n");
  698.  
  699.     EaWrite(11,     1,ea,0,0x003f,1);
  700. #if CYCLONE_FOR_GENESIS
  701.   }
  702. #endif
  703.  
  704.   OpEnd(ea);
  705.  
  706. #if (CYCLONE_FOR_GENESIS == 2)
  707.   if (!gen_special && ea >= 0x10) {
  708.     OpTas(op, 1);
  709.   }
  710. #endif
  711.  
  712.   return 0;
  713. }
  714.  
  715.