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 0x0000+ ---------------------
  16. // Emit an Ori/And/Sub/Add/Eor/Cmp Immediate opcode, 0000ttt0 ssaaaaaa
  17. int OpArith(int op)
  18. {
  19.   int type=0,size=0;
  20.   int sea=0,tea=0;
  21.   int use=0;
  22.   const char *shiftstr="";
  23.  
  24.   // Get source and target EA
  25.   type=(op>>9)&7; if (type==4 || type>=7) return 1;
  26.   size=(op>>6)&3; if (size>=3) return 1;
  27.   sea=   0x003c;
  28.   tea=op&0x003f;
  29.  
  30.   // See if we can do this opcode:
  31.   if (EaCanRead(tea,size)==0) return 1;
  32.   if (EaCanWrite(tea)==0 || EaAn(tea)) return 1;
  33.  
  34.   use=OpBase(op,size);
  35.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  36.  
  37.   OpStart(op, sea, tea); Cycles=4;
  38.  
  39.   // imm must be read first
  40.   EaCalcReadNoSE(-1,10,sea,size,0);
  41.   EaCalcReadNoSE((type!=6)?11:-1,0,tea,size,0x003f);
  42.  
  43.   if (size<2) shiftstr=(char *)(size?",asl #16":",asl #24");
  44.   if (size<2) ot("  mov r10,r10,asl #%i\n",size?16:24);
  45.  
  46.   ot(";@ Do arithmetic:\n");
  47.  
  48.   if (type==0) ot("  orr r1,r10,r0%s\n",shiftstr);
  49.   if (type==1) ot("  and r1,r10,r0%s\n",shiftstr);
  50.   if (type==2||type==6)
  51.                ot("  rsbs r1,r10,r0%s ;@ Defines NZCV\n",shiftstr);
  52.   if (type==3) ot("  adds r1,r10,r0%s ;@ Defines NZCV\n",shiftstr);
  53.   if (type==5) ot("  eor r1,r10,r0%s\n",shiftstr);
  54.  
  55.   if (type<2 || type==5) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n"); // 0,1,5
  56.  
  57.   if (type< 2) OpGetFlags(0,0); // Ori/And
  58.   if (type==2) OpGetFlags(1,1); // Sub: Subtract/X-bit
  59.   if (type==3) OpGetFlags(0,1); // Add: X-bit
  60.   if (type==5) OpGetFlags(0,0); // Eor
  61.   if (type==6) OpGetFlags(1,0); // Cmp: Subtract
  62.   ot("\n");
  63.  
  64.   if (type!=6)
  65.   {
  66.     EaWrite(11, 1, tea,size,0x003f,1);
  67.   }
  68.  
  69.   // Correct cycles:
  70.   if (type==6)
  71.   {
  72.     if (size>=2 && tea<0x10) Cycles+=2;
  73.   }
  74.   else
  75.   {
  76.     if (size>=2) Cycles+=4;
  77.     if (tea>=8)  Cycles+=4;
  78.     if (type==1 && size>=2 && tea<8) Cycles-=2;
  79.   }
  80.  
  81.   OpEnd(sea,tea);
  82.  
  83.   return 0;
  84. }
  85.  
  86. // --------------------- Opcodes 0x5000+ ---------------------
  87. int OpAddq(int op)
  88. {
  89.   // 0101nnnt xxeeeeee (nnn=#8,1-7 t=addq/subq xx=size, eeeeee=EA)
  90.   int num=0,type=0,size=0,ea=0;
  91.   int use=0;
  92.   char count[16]="";
  93.   int shift=0;
  94.  
  95.   num =(op>>9)&7; if (num==0) num=8;
  96.   type=(op>>8)&1;
  97.   size=(op>>6)&3; if (size>=3) return 1;
  98.   ea  = op&0x3f;
  99.  
  100.   // See if we can do this opcode:
  101.   if (EaCanRead (ea,size)==0) return 1;
  102.   if (EaCanWrite(ea)     ==0) return 1;
  103.   if (size == 0 && EaAn(ea) ) return 1;
  104.  
  105.   use=OpBase(op,size,1);
  106.  
  107.   if (num!=8) use|=0x0e00; // If num is not 8, use same handler
  108.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  109.  
  110.   OpStart(op,ea);
  111.   Cycles=ea<8?4:8;
  112.   if(type==0&&size==1) Cycles=ea<0x10?4:8;
  113.   if(size>=2) Cycles=ea<0x10?8:12;
  114.  
  115.   if (size>0 && (ea&0x38)==0x08) size=2; // addq.w #n,An is also 32-bit
  116.  
  117.   EaCalcReadNoSE(11,0,ea,size,0x003f);
  118.  
  119.   shift=32-(8<<size);
  120.  
  121.   if (num!=8)
  122.   {
  123.     int lsr=9-shift;
  124.  
  125.     ot("  and r2,r8,#0x0e00 ;@ Get quick value\n");
  126.  
  127.     if (lsr>=0) sprintf(count,"r2,lsr #%d",  lsr);
  128.     else        sprintf(count,"r2,lsl #%d", -lsr);
  129.  
  130.     ot("\n");
  131.   }
  132.   else
  133.   {
  134.     sprintf(count,"#0x%.4x",8<<shift);
  135.   }
  136.  
  137.   if (size<2)  ot("  mov r0,r0,asl #%d\n\n",size?16:24);
  138.  
  139.   if (type==0) ot("  adds r1,r0,%s\n",count);
  140.   if (type==1) ot("  subs r1,r0,%s\n",count);
  141.  
  142.   if ((ea&0x38)!=0x08) OpGetFlags(type,1);
  143.   ot("\n");
  144.  
  145.   EaWrite(11,     1, ea,size,0x003f,1);
  146.  
  147.   OpEnd(ea);
  148.  
  149.   return 0;
  150. }
  151.  
  152. // --------------------- Opcodes 0x8000+ ---------------------
  153. // 1t0tnnnd xxeeeeee (tt=type:or/sub/and/add xx=size, eeeeee=EA)
  154. int OpArithReg(int op)
  155. {
  156.   int use=0;
  157.   int type=0,size=0,dir=0,rea=0,ea=0;
  158.   const char *asl="";
  159.   const char *strop=0;
  160.  
  161.   type=(op>>12)&5;
  162.   rea =(op>> 9)&7;
  163.   dir =(op>> 8)&1; // er,re
  164.   size=(op>> 6)&3; if (size>=3) return 1;
  165.   ea  = op&0x3f;
  166.  
  167.   if (dir && ea<0x10) return 1; // addx/subx opcode
  168.  
  169.   // See if we can do this opcode:
  170.   if (dir==0 && EaCanRead (ea,size)==0) return 1;
  171.   if (dir    && EaCanWrite(ea)==0)      return 1;
  172.   if ((size==0||!(type&1))&&EaAn(ea))   return 1;
  173.  
  174.   use=OpBase(op,size);
  175.   use&=~0x0e00; // Use same opcode for Dn
  176.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  177.  
  178.   OpStart(op,ea); Cycles=4;
  179.  
  180.   EaCalcReadNoSE(dir?11:-1,0,ea,size,0x003f);
  181.  
  182.   EaCalcReadNoSE(dir?-1:11,1,rea,size,0x0e00);
  183.  
  184.   ot(";@ Do arithmetic:\n");
  185.   if (type==0) strop = "orr";
  186.   if (type==1) strop = (char *) (dir ? "subs" : "rsbs");
  187.   if (type==4) strop = "and";
  188.   if (type==5) strop = "adds";
  189.  
  190.   if (size==0) asl=",asl #24";
  191.   if (size==1) asl=",asl #16";
  192.  
  193.   if (size<2) ot("  mov r0,r0%s\n",asl);
  194.   ot("  %s r1,r0,r1%s\n",strop,asl);
  195.  
  196.   if ((type&1)==0) ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  197.  
  198.   OpGetFlags(type==1,type&1); // 1==subtract
  199.   ot("\n");
  200.  
  201.   ot(";@ Save result:\n");
  202.   if (size<2) ot("  mov r1,r1,asr #%d\n",size?16:24);
  203.   if (dir) EaWrite(11, 1, ea,size,0x003f,0,0);
  204.   else     EaWrite(11, 1,rea,size,0x0e00,0,0);
  205.  
  206.   if(rea==ea) {
  207.     if(ea<8) Cycles=(size>=2)?8:4; else Cycles+=(size>=2)?26:14;
  208.   } else if(dir) {
  209.     Cycles+=4;
  210.     if(size>=2) Cycles+=4;
  211.   } else {
  212.     if(size>=2) {
  213.       Cycles+=2;
  214.       if(ea<0x10||ea==0x3c) Cycles+=2;
  215.     }
  216.   }
  217.  
  218.   OpEnd(ea);
  219.  
  220.   return 0;
  221. }
  222.  
  223. // --------------------- Opcodes 0x80c0+ ---------------------
  224. int OpMul(int op)
  225. {
  226.   // Div/Mul: 1m00nnns 11eeeeee (m=Mul, nnn=Register Dn, s=signed, eeeeee=EA)
  227.   int type=0,rea=0,sign=0,ea=0;
  228.   int use=0;
  229.  
  230.   type=(op>>14)&1; // div/mul
  231.   rea =(op>> 9)&7;
  232.   sign=(op>> 8)&1;
  233.   ea  = op&0x3f;
  234.  
  235.   // See if we can do this opcode:
  236.   if (EaCanRead(ea,1)==0||EaAn(ea)) return 1;
  237.  
  238.   use=OpBase(op,1);
  239.   use&=~0x0e00; // Use same for all registers
  240.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  241.  
  242.   OpStart(op,ea);
  243.   if(type) Cycles=54;
  244.   else     Cycles=sign?158:140;
  245.  
  246.   EaCalcReadNoSE(-1,0,ea,1,0x003f);
  247.  
  248.   EaCalc(11,0x0e00,rea, 2);
  249.   EaRead(11,     2,rea, 2,0x0e00);
  250.  
  251.   ot("  movs r1,r0,asl #16\n");
  252.  
  253.   if (type==0) // div
  254.   {
  255.     // the manual says C is always cleared, but neither Musashi nor FAME do that
  256.     //ot("  bic r10,r10,#0x20000000 ;@ always clear C\n");
  257.     ot("  beq divzero%.4x ;@ division by zero\n",op);
  258.     ot("\n");
  259.    
  260.     if (sign)
  261.     {
  262.       ot("  mov r12,#0 ;@ r12 = 1 or 2 if the result is negative\n");
  263.       ot("  tst r2,r2\n");
  264.       ot("  orrmi r12,r12,#2\n");
  265.       ot("  rsbmi r2,r2,#0 ;@ Make r2 positive\n");
  266.       ot("\n");
  267.       ot("  movs r0,r1,asr #16\n");
  268.       ot("  orrmi r12,r12,#1\n");
  269.       ot("  rsbmi r0,r0,#0 ;@ Make r0 positive\n");
  270.       ot("\n");
  271.       ot(";@ detect the nasty 0x80000000 / -1 situation\n");
  272.       ot("  mov r3,r2,asr #31\n");
  273.       ot("  eors r3,r3,r1,asr #16\n");
  274.       ot("  beq wrendofop%.4x\n",op);
  275.     }
  276.     else
  277.     {
  278.       ot("  mov r0,r1,lsr #16 ;@ use only 16 bits of divisor\n");
  279.     }
  280.  
  281.     ot("\n");
  282.     ot(";@ Divide r2 by r0\n");
  283.     ot("  mov r3,#0\n");
  284.     ot("  mov r1,r0\n");
  285.     ot("\n");
  286.     ot(";@ Shift up divisor till it's just less than numerator\n");
  287.     ot("Shift%.4x%s\n",op,ms?"":":");
  288.     ot("  cmp r1,r2,lsr #1\n");
  289.     ot("  movls r1,r1,lsl #1\n");
  290.     ot("  bcc Shift%.4x\n",op);
  291.     ot("\n");
  292.  
  293.     ot("Divide%.4x%s\n",op,ms?"":":");
  294.     ot("  cmp r2,r1\n");
  295.     ot("  adc r3,r3,r3 ;@ Double r3 and add 1 if carry set\n");
  296.     ot("  subcs r2,r2,r1\n");
  297.     ot("  teq r1,r0\n");
  298.     ot("  movne r1,r1,lsr #1\n");
  299.     ot("  bne Divide%.4x\n",op);
  300.     ot("\n");
  301.     ot(";@r3==quotient,r2==remainder\n");
  302.  
  303.     if (sign)
  304.     {
  305.       // sign correction
  306.       ot("  and r1,r12,#1\n");
  307.       ot("  teq r1,r12,lsr #1\n");
  308.       ot("  rsbne r3,r3,#0 ;@ negate if quotient is negative\n");
  309.       ot("  tst r12,#2\n");
  310.       ot("  rsbne r2,r2,#0 ;@ negate the remainder if divident was negative\n");
  311.       ot("\n");
  312.  
  313.       // signed overflow check
  314.       ot("  mov r1,r3,asl #16\n");
  315.       ot("  cmp r3,r1,asr #16 ;@ signed overflow?\n");
  316.       ot("  orrne r10,r10,#0x10000000 ;@ set overflow flag\n");
  317.       ot("  bne endofop%.4x ;@ overflow!\n",op);
  318.       ot("\n");
  319.       ot("wrendofop%.4x%s\n",op,ms?"":":");
  320.     }
  321.     else
  322.     {
  323.       // overflow check
  324.       ot("  movs r1,r3,lsr #16 ;@ check for overflow condition\n");
  325.       ot("  orrne r10,r10,#0x10000000 ;@ set overflow flag\n");
  326.       ot("  bne endofop%.4x ;@ overflow!\n",op);
  327.       ot("\n");
  328.     }
  329.  
  330.     ot("  mov r1,r3,lsl #16 ;@ Clip to 16-bits\n");
  331.     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  332.     OpGetFlags(0,0);
  333.  
  334.     ot("  mov r1,r1,lsr #16\n");
  335.     ot("  orr r1,r1,r2,lsl #16 ;@ Insert remainder\n");
  336.   }
  337.  
  338.   if (type==1)
  339.   {
  340.     ot(";@ Get 16-bit signs right:\n");
  341.     ot("  mov r0,r1,%s #16\n",sign?"asr":"lsr");
  342.     ot("  mov r2,r2,lsl #16\n");
  343.     ot("  mov r2,r2,%s #16\n",sign?"asr":"lsr");
  344.     ot("\n");
  345.  
  346.     ot("  mul r1,r2,r0\n");
  347.     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  348.     OpGetFlags(0,0);
  349.   }
  350.   ot("\n");
  351.  
  352.   EaWrite(11,    1,rea, 2,0x0e00,1);
  353.  
  354.   if (type==0) ot("endofop%.4x%s\n",op,ms?"":":");
  355.   OpEnd(ea);
  356.  
  357.   if (type==0) // div
  358.   {
  359.     ot("divzero%.4x%s\n",op,ms?"":":");
  360.     ot("  mov r0,#5 ;@ Divide by zero\n");
  361.     ot("  bl Exception\n");
  362.     Cycles+=38;
  363.     OpEnd(ea);
  364.     ot("\n");
  365.   }
  366.  
  367.   return 0;
  368. }
  369.  
  370. // Get X Bit into carry - trashes r2
  371. int GetXBit(int subtract)
  372. {
  373.   ot(";@ Get X bit:\n");
  374.   ot("  ldr r2,[r7,#0x4c]\n");
  375.   if (subtract) ot("  mvn r2,r2 ;@ Invert it\n");
  376.   ot("  msr cpsr_flg,r2 ;@ Get into Carry\n");
  377.   ot("\n");
  378.   return 0;
  379. }
  380.  
  381. // --------------------- Opcodes 0x8100+ ---------------------
  382. // 1t00ddd1 0000asss - sbcd/abcd Ds,Dd or -(As),-(Ad)
  383. int OpAbcd(int op)
  384. {
  385.   int use=0;
  386.   int type=0,sea=0,mem=0,dea=0;
  387.  
  388.   type=(op>>14)&1; // sbcd/abcd
  389.   dea =(op>> 9)&7;
  390.   mem =(op>> 3)&1;
  391.   sea = op     &7;
  392.  
  393.   if (mem) { sea|=0x20; dea|=0x20; }
  394.  
  395.   use=op&~0x0e07; // Use same opcode for all registers..
  396.   if (sea==0x27) use|=0x0007; // ___x.b -(a7)
  397.   if (dea==0x27) use|=0x0e00; // ___x.b -(a7)
  398.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  399.  
  400.   OpStart(op,sea,dea); Cycles=6;
  401.  
  402.   if (mem)
  403.   {
  404.     ot(";@ Get src/dest EA vals\n");
  405.     EaCalc (0,0x000f, sea,0,1);
  406.     EaRead (0,     6, sea,0,0x000f,1);
  407.     EaCalcReadNoSE(11,0,dea,0,0x0e00);
  408.   }
  409.   else
  410.   {
  411.     ot(";@ Get src/dest reg vals\n");
  412.     EaCalcReadNoSE(-1,6,sea,0,0x0007);
  413.     EaCalcReadNoSE(11,0,dea,0,0x0e00);
  414.     ot("  mov r6,r6,asl #24\n");
  415.   }
  416.   ot("  mov r1,r0,asl #24\n\n");
  417.  
  418.   ot("  bic r10,r10,#0xb1000000 ;@ clear all flags except old Z\n");
  419.  
  420.   if (type)
  421.   {
  422.     ot("  ldr r0,[r7,#0x4c] ;@ Get X bit\n");
  423.     ot("  mov r3,#0x00f00000\n");
  424.     ot("  and r2,r3,r1,lsr #4\n");
  425.     ot("  tst r0,#0x20000000\n");
  426.     ot("  and r0,r3,r6,lsr #4\n");
  427.     ot("  add r0,r0,r2\n");
  428.     ot("  addne r0,r0,#0x00100000\n");
  429. //    ot("  tst r0,#0x00800000\n");
  430. //    ot("  orreq r10,r10,#0x01000000 ;@ Undefined V behavior\n");
  431.     ot("  cmp r0,#0x00900000\n");
  432.     ot("  addhi r0,r0,#0x00600000 ;@ Decimal adjust units\n");
  433.  
  434.     ot("  mov r2,r1,lsr #28\n");
  435.     ot("  add r0,r0,r2,lsl #24\n");
  436.     ot("  mov r2,r6,lsr #28\n");
  437.     ot("  add r0,r0,r2,lsl #24\n");
  438.     ot("  cmp r0,#0x09900000\n");
  439.     ot("  orrhi r10,r10,#0x20000000 ;@ C\n");
  440.     ot("  subhi r0,r0,#0x0a000000\n");
  441. //    ot("  and r3,r10,r0,lsr #3 ;@ Undefined V behavior part II\n");
  442. //    ot("  orr r10,r10,r3,lsl #4 ;@ V\n");
  443.     ot("  movs r0,r0,lsl #4\n");
  444.     ot("  orrmi r10,r10,#0x90000000 ;@ Undefined N+V behavior\n"); // this is what Musashi really does
  445.     ot("  bicne r10,r10,#0x40000000 ;@ Z flag\n");
  446.   }
  447.   else
  448.   {
  449.     ot("  ldr r0,[r7,#0x4c] ;@ Get X bit\n");
  450.     ot("  mov r3,#0x00f00000\n");
  451.     ot("  and r2,r3,r6,lsr #4\n");
  452.     ot("  tst r0,#0x20000000\n");
  453.     ot("  and r0,r3,r1,lsr #4\n");
  454.     ot("  sub r0,r0,r2\n");
  455.     ot("  subne r0,r0,#0x00100000\n");
  456. //    ot("  tst r0,#0x00800000\n");
  457. //    ot("  orreq r10,r10,#0x01000000 ;@ Undefined V behavior\n");
  458.     ot("  cmp r0,#0x00900000\n");
  459.     ot("  subhi r0,r0,#0x00600000 ;@ Decimal adjust units\n");
  460.  
  461.     ot("  mov r2,r1,lsr #28\n");
  462.     ot("  add r0,r0,r2,lsl #24\n");
  463.     ot("  mov r2,r6,lsr #28\n");
  464.     ot("  sub r0,r0,r2,lsl #24\n");
  465.     ot("  cmp r0,#0x09900000\n");
  466.     ot("  orrhi r10,r10,#0xa0000000 ;@ N and C\n");
  467.     ot("  addhi r0,r0,#0x0a000000\n");
  468. //    ot("  and r3,r10,r0,lsr #3 ;@ Undefined V behavior part II\n");
  469. //    ot("  orr r10,r10,r3,lsl #4 ;@ V\n");
  470.     ot("  movs r0,r0,lsl #4\n");
  471. //    ot("  orrmi r10,r10,#0x80000000 ;@ Undefined N behavior\n");
  472.     ot("  bicne r10,r10,#0x40000000 ;@ Z flag\n");
  473.   }
  474.  
  475.   ot("  str r10,[r7,#0x4c] ;@ Save X bit\n");
  476.   ot("\n");
  477.  
  478.   EaWrite(11,     0, dea,0,0x0e00,1);
  479.  
  480.   ot("  ldr r6,[r7,#0x54]\n");
  481.   OpEnd(sea,dea);
  482.  
  483.   return 0;
  484. }
  485.  
  486. // 01001000 00eeeeee - nbcd <ea>
  487. int OpNbcd(int op)
  488. {
  489.   int use=0;
  490.   int ea=0;
  491.  
  492.   ea=op&0x3f;
  493.  
  494.   if(EaCanWrite(ea)==0||EaAn(ea)) return 1;
  495.  
  496.   use=OpBase(op,0);
  497.   if(op!=use) { OpUse(op,use); return 0; } // Use existing handler
  498.  
  499.   OpStart(op,ea); Cycles=6;
  500.   if(ea >= 8)  Cycles+=2;
  501.  
  502.   EaCalcReadNoSE(6,0,ea,0,0x003f);
  503.  
  504.   // this is rewrite of Musashi's code
  505.   ot("  ldr r2,[r7,#0x4c]\n");
  506.   ot("  bic r10,r10,#0xb0000000 ;@ clear all flags, except Z\n");
  507.   ot("  mov r0,r0,asl #24\n");
  508.   ot("  and r2,r2,#0x20000000\n");
  509.   ot("  add r2,r0,r2,lsr #5 ;@ add X\n");
  510.   ot("  rsb r11,r2,#0x9a000000 ;@ do arithmetic\n");
  511.  
  512.   ot("  cmp r11,#0x9a000000\n");
  513.   ot("  beq finish%.4x\n",op);
  514.   ot("\n");
  515.  
  516.   ot("  mvn r3,r11,lsr #31 ;@ Undefined V behavior\n",op);
  517.   ot("  and r2,r11,#0x0f000000\n");
  518.   ot("  cmp r2,#0x0a000000\n");
  519.   ot("  andeq r11,r11,#0xf0000000\n");
  520.   ot("  addeq r11,r11,#0x10000000\n");
  521.   ot("  and r3,r3,r11,lsr #31 ;@ Undefined V behavior part II\n",op);
  522.   ot("  movs r1,r11,asr #24\n");
  523.   ot("  bicne r10,r10,#0x40000000 ;@ Z\n");
  524.   ot("  orr r10,r10,r3,lsl #28 ;@ save V\n",op);
  525.   ot("  orr r10,r10,#0x20000000 ;@ C\n");
  526.   ot("\n");
  527.  
  528.   EaWrite(6, 1, ea,0,0x3f,0,0);
  529.  
  530.   ot("finish%.4x%s\n",op,ms?"":":");
  531.   ot("  tst r11,r11\n");
  532.   ot("  orrmi r10,r10,#0x80000000 ;@ N\n");
  533.   ot("  str r10,[r7,#0x4c] ;@ Save X\n");
  534.   ot("\n");
  535.  
  536.   ot("  ldr r6,[r7,#0x54]\n");
  537.   OpEnd(ea);
  538.  
  539.   return 0;
  540. }
  541.  
  542. // --------------------- Opcodes 0x90c0+ ---------------------
  543. // Suba/Cmpa/Adda 1tt1nnnx 11eeeeee (tt=type, x=size, eeeeee=Source EA)
  544. int OpAritha(int op)
  545. {
  546.   int use=0;
  547.   int type=0,size=0,sea=0,dea=0;
  548.   const char *asr="";
  549.  
  550.   // Suba/Cmpa/Adda/(invalid):
  551.   type=(op>>13)&3; if (type>=3) return 1;
  552.  
  553.   size=(op>>8)&1; size++;
  554.   dea=(op>>9)&7; dea|=8; // Dest=An
  555.   sea=op&0x003f; // Source
  556.  
  557.   // See if we can do this opcode:
  558.   if (EaCanRead(sea,size)==0) return 1;
  559.  
  560.   use=OpBase(op,size);
  561.   use&=~0x0e00; // Use same opcode for An
  562.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  563.  
  564.   OpStart(op,sea); Cycles=(size==2)?6:8;
  565.   if(size==2&&(sea<0x10||sea==0x3c)) Cycles+=2;
  566.   if(type==1) Cycles=6;
  567.  
  568.   // EA calculation order defines how situations like  suba.w (A0)+, A0 get handled.
  569.   // different emus act differently in this situation, I couldn't fugure which is right behaviour.
  570.   //if (type == 1)
  571.   {
  572.     EaCalcReadNoSE(-1,0,sea,size,0x003f);
  573.     EaCalcReadNoSE(type!=1?11:-1,1,dea,2,0x0e00);
  574.   }
  575. #if 0
  576.   else
  577.   {
  578.     EaCalcReadNoSE(type!=1?11:-1,1,dea,2,0x0e00);
  579.     EaCalcReadNoSE(-1,0,sea,size,0x003f);
  580.   }
  581. #endif
  582.  
  583.   if (size<2) ot("  mov r0,r0,asl #%d\n\n",size?16:24);
  584.   if (size<2) asr=(char *)(size?",asr #16":",asr #24");
  585.  
  586.   if (type==0) ot("  sub r1,r1,r0%s\n",asr);
  587.   if (type==1) ot("  cmp r1,r0%s ;@ Defines NZCV\n",asr);
  588.   if (type==1) OpGetFlags(1,0); // Get Cmp flags
  589.   if (type==2) ot("  add r1,r1,r0%s\n",asr);
  590.   ot("\n");
  591.  
  592.   if (type!=1) EaWrite(11, 1, dea,2,0x0e00);
  593.  
  594.   OpEnd(sea);
  595.  
  596.   return 0;
  597. }
  598.  
  599. // --------------------- Opcodes 0x9100+ ---------------------
  600. // Emit a Subx/Addx opcode, 1t01ddd1 zz00rsss addx.z Ds,Dd
  601. int OpAddx(int op)
  602. {
  603.   int use=0;
  604.   int type=0,size=0,dea=0,sea=0,mem=0;
  605.   const char *asl="";
  606.  
  607.   type=(op>>14)&1;
  608.   dea =(op>> 9)&7;
  609.   size=(op>> 6)&3; if (size>=3) return 1;
  610.   sea = op&7;
  611.   mem =(op>> 3)&1;
  612.  
  613.   // See if we can do this opcode:
  614.   if (EaCanRead(sea,size)==0) return 1;
  615.   if (EaCanWrite(dea)==0) return 1;
  616.  
  617.   if (mem) { sea+=0x20; dea+=0x20; }
  618.  
  619.   use=op&~0x0e07; // Use same opcode for Dn
  620.   if (size==0&&sea==0x27) use|=0x0007; // ___x.b -(a7)
  621.   if (size==0&&dea==0x27) use|=0x0e00; // ___x.b -(a7)
  622.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  623.  
  624.   OpStart(op,sea,dea); Cycles=4;
  625.   if(size>=2)   Cycles+=4;
  626.   if(sea>=0x10) Cycles+=2;
  627.  
  628.   if (mem)
  629.   {
  630.     ot(";@ Get src/dest EA vals\n");
  631.     EaCalc (0,0x000f, sea,size,1);
  632.     EaRead (0,     6, sea,size,0x000f,1);
  633.     EaCalcReadNoSE(11,0,dea,size,0x0e00);
  634.   }
  635.   else
  636.   {
  637.     ot(";@ Get src/dest reg vals\n");
  638.     EaCalcReadNoSE(-1,6,sea,size,0x0007);
  639.     EaCalcReadNoSE(11,0,dea,size,0x0e00);
  640.     if (size<2) ot("  mov r6,r6,asl #%d\n\n",size?16:24);
  641.   }
  642.  
  643.   if (size<2) asl=(char *)(size?",asl #16":",asl #24");
  644.  
  645.   ot(";@ Do arithmetic:\n");
  646.   GetXBit(type==0);
  647.  
  648.   if (type==1 && size<2)
  649.   {
  650.     ot(";@ Make sure the carry bit will tip the balance:\n");
  651.     ot("  mvn r2,#0\n");
  652.     ot("  orr r6,r6,r2,lsr #%i\n",(size==0)?8:16);
  653.     ot("\n");
  654.   }
  655.  
  656.   if (type==0) ot("  rscs r1,r6,r0%s\n",asl);
  657.   if (type==1) ot("  adcs r1,r6,r0%s\n",asl);
  658.   ot("  orr r3,r10,#0xb0000000 ;@ for old Z\n");
  659.   OpGetFlags(type==0,1,0); // subtract
  660.   if (size<2) {
  661.     ot("  movs r2,r1,lsr #%i\n", size?16:24);
  662.     ot("  orreq r10,r10,#0x40000000 ;@ add potentially missed Z\n");
  663.   }
  664.   ot("  andeq r10,r10,r3 ;@ fix Z\n");
  665.   ot("\n");
  666.  
  667.   ot(";@ Save result:\n");
  668.   EaWrite(11, 1, dea,size,0x0e00,1);
  669.  
  670.   ot("  ldr r6,[r7,#0x54]\n");
  671.   OpEnd(sea,dea);
  672.  
  673.   return 0;
  674. }
  675.  
  676. // --------------------- Opcodes 0xb000+ ---------------------
  677. // Emit a Cmp/Eor opcode, 1011rrrt xxeeeeee (rrr=Dn, t=cmp/eor, xx=size extension, eeeeee=ea)
  678. int OpCmpEor(int op)
  679. {
  680.   int rea=0,eor=0;
  681.   int size=0,ea=0,use=0;
  682.   const char *asl="";
  683.  
  684.   // Get EA and register EA
  685.   rea=(op>>9)&7;
  686.   eor=(op>>8)&1;
  687.   size=(op>>6)&3; if (size>=3) return 1;
  688.   ea=op&0x3f;
  689.  
  690.   if (eor && (ea>>3) == 1) return 1; // not a valid mode for eor
  691.  
  692.   // See if we can do this opcode:
  693.   if (EaCanRead(ea,size)==0) return 1;
  694.   if (eor && EaCanWrite(ea)==0) return 1;
  695.   if (EaAn(ea)&&(eor||size==0)) return 1;
  696.  
  697.   use=OpBase(op,size);
  698.   use&=~0x0e00; // Use 1 handler for register d0-7
  699.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  700.  
  701.   OpStart(op,ea); Cycles=4;
  702.   if(eor) {
  703.     if(ea>8)     Cycles+=4;
  704.     if(size>=2)  Cycles+=4;
  705.   } else {
  706.     if(size>=2)  Cycles+=2;
  707.   }
  708.  
  709.   ot(";@ Get EA into r11 and value into r0:\n");
  710.   EaCalcReadNoSE(eor?11:-1,0,ea,size,0x003f);
  711.  
  712.   ot(";@ Get register operand into r1:\n");
  713.   EaCalcReadNoSE(-1,1,rea,size,0x0e00);
  714.  
  715.   if (size<2) ot("  mov r0,r0,asl #%d\n\n",size?16:24);
  716.   if (size<2) asl=(char *)(size?",asl #16":",asl #24");
  717.  
  718.   ot(";@ Do arithmetic:\n");
  719.   if (eor==0) ot("  rsbs r1,r0,r1%s\n",asl);
  720.   if (eor)
  721.   {
  722.     ot("  eor r1,r0,r1%s\n",asl);
  723.     ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  724.   }
  725.  
  726.   OpGetFlags(eor==0,0); // Cmp like subtract
  727.   ot("\n");
  728.  
  729.   if (eor) EaWrite(11, 1,ea,size,0x003f,1);
  730.  
  731.   OpEnd(ea);
  732.   return 0;
  733. }
  734.  
  735. // Emit a Cmpm opcode, 1011ddd1 xx001sss (rrr=Adst, xx=size extension, sss=Asrc)
  736. int OpCmpm(int op)
  737. {
  738.   int size=0,sea=0,dea=0,use=0;
  739.   const char *asl="";
  740.  
  741.   // get size, get EAs
  742.   size=(op>>6)&3; if (size>=3) return 1;
  743.   sea=(op&7)|0x18;
  744.   dea=(op>>9)&0x3f;
  745.  
  746.   use=op&~0x0e07; // Use 1 handler for all registers..
  747.   if (size==0&&sea==0x1f) use|=0x0007; // ..except (a7)+
  748.   if (size==0&&dea==0x1f) use|=0x0e00;
  749.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  750.  
  751.   OpStart(op,sea); Cycles=4;
  752.  
  753.   ot(";@ Get src operand into r11:\n");
  754.   EaCalc (0,0x0007, sea,size,1);
  755.   EaRead (0,    11, sea,size,0x0007,1);
  756.  
  757.   ot(";@ Get dst operand into r0:\n");
  758.   EaCalcReadNoSE(-1,0,dea,size,0x0e00);
  759.  
  760.   if (size<2) asl=(char *)(size?",asl #16":",asl #24");
  761.  
  762.   ot("  rsbs r0,r11,r0%s\n",asl);
  763.   OpGetFlags(1,0); // Cmp like subtract
  764.   ot("\n");
  765.  
  766.   OpEnd(sea);
  767.   return 0;
  768. }
  769.  
  770.  
  771. // Emit a Chk opcode, 0100ddd1 x0eeeeee (rrr=Dn, x=size extension, eeeeee=ea)
  772. int OpChk(int op)
  773. {
  774.   int rea=0;
  775.   int size=0,ea=0,use=0;
  776.  
  777.   // Get EA and register EA
  778.   rea=(op>>9)&7;
  779.   if((op>>7)&1)
  780.        size=1; // word operation
  781.   else size=2; // long
  782.   ea=op&0x3f;
  783.  
  784.   if (EaAn(ea)) return 1; // not a valid mode
  785.   if (size!=1)  return 1; // 000 variant only supports word
  786.  
  787.   // See if we can do this opcode:
  788.   if (EaCanRead(ea,size)==0) return 1;
  789.  
  790.   use=OpBase(op,size);
  791.   use&=~0x0e00; // Use 1 handler for register d0-7
  792.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  793.  
  794.   OpStart(op,ea); Cycles=10;
  795.  
  796.   ot(";@ Get value into r0:\n");
  797.   EaCalcReadNoSE(-1,0,ea,size,0x003f);
  798.  
  799.   ot(";@ Get register operand into r1:\n");
  800.   EaCalcReadNoSE(-1,1,rea,size,0x0e00);
  801.  
  802.   if (size<2) ot("  mov r0,r0,asl #%d\n",size?16:24);
  803.   if (size<2) ot("  mov r1,r1,asl #%d\n\n",size?16:24);
  804.  
  805.   ot(";@ get flags, including undocumented ones\n");
  806.   ot("  and r3,r10,#0x80000000\n");
  807.   ot("  adds r1,r1,#0 ;@ Defines NZ, clears CV\n");
  808.   OpGetFlags(0,0);
  809.  
  810.   ot(";@ is reg negative?\n");
  811.   ot("  bmi chktrap%.4x\n",op);
  812.  
  813.   ot(";@ Do arithmetic:\n");
  814.   ot("  bic r10,r10,#0x80000000 ;@ N\n");
  815.   ot("  cmp r1,r0\n");
  816.   ot("  bgt chktrap%.4x\n",op);
  817.  
  818.   ot(";@ old N remains\n");
  819.   ot("  orr r10,r10,r3\n");
  820.   OpEnd(ea);
  821.  
  822.   ot("chktrap%.4x%s ;@ CHK exception:\n",op,ms?"":":");
  823.   ot("  mov r0,#6\n");
  824.   ot("  bl Exception\n");
  825.   Cycles+=40;
  826.   OpEnd(ea);
  827.  
  828.   return 0;
  829. }
  830.  
  831.