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. int earead_check_addrerr = 1, eawrite_check_addrerr = 0;
  16.  
  17. // some ops use non-standard cycle counts for EAs, so are listed here.
  18. // all constants borrowed from the MUSASHI core by Karl Stenerud.
  19.  
  20. /* Extra cycles for JMP instruction (000, 010) */
  21. int g_jmp_cycle_table[8] =
  22. {
  23.          4, /* EA_MODE_AI   */
  24.          6, /* EA_MODE_DI   */
  25.         10, /* EA_MODE_IX   */
  26.          6, /* EA_MODE_AW   */
  27.          8, /* EA_MODE_AL   */
  28.          6, /* EA_MODE_PCDI */
  29.         10, /* EA_MODE_PCIX */
  30.          0, /* EA_MODE_I    */
  31. };
  32.  
  33. /* Extra cycles for JSR instruction (000, 010) */
  34. int g_jsr_cycle_table[8] =
  35. {
  36.          4, /* EA_MODE_AI   */
  37.          6, /* EA_MODE_DI   */
  38.         10, /* EA_MODE_IX   */
  39.          6, /* EA_MODE_AW   */
  40.          8, /* EA_MODE_AL   */
  41.          6, /* EA_MODE_PCDI */
  42.         10, /* EA_MODE_PCIX */
  43.          0, /* EA_MODE_I    */
  44. };
  45.  
  46. /* Extra cycles for LEA instruction (000, 010) */
  47. int g_lea_cycle_table[8] =
  48. {
  49.          4, /* EA_MODE_AI   */
  50.          8, /* EA_MODE_DI   */
  51.         12, /* EA_MODE_IX   */
  52.          8, /* EA_MODE_AW   */
  53.         12, /* EA_MODE_AL   */
  54.          8, /* EA_MODE_PCDI */
  55.         12, /* EA_MODE_PCIX */
  56.          0, /* EA_MODE_I    */
  57. };
  58.  
  59. /* Extra cycles for PEA instruction (000, 010) */
  60. int g_pea_cycle_table[8] =
  61. {
  62.          6, /* EA_MODE_AI   */
  63.         10, /* EA_MODE_DI   */
  64.         14, /* EA_MODE_IX   */
  65.         10, /* EA_MODE_AW   */
  66.         14, /* EA_MODE_AL   */
  67.         10, /* EA_MODE_PCDI */
  68.         14, /* EA_MODE_PCIX */
  69.          0, /* EA_MODE_I    */
  70. };
  71.  
  72. /* Extra cycles for MOVEM instruction (000, 010) */
  73. int g_movem_cycle_table[8] =
  74. {
  75.          0, /* EA_MODE_AI   */
  76.          4, /* EA_MODE_DI   */
  77.          6, /* EA_MODE_IX   */
  78.          4, /* EA_MODE_AW   */
  79.          8, /* EA_MODE_AL   */
  80.          0, /* EA_MODE_PCDI */
  81.          0, /* EA_MODE_PCIX */
  82.          0, /* EA_MODE_I    */
  83. };
  84.  
  85. // add nonstandard EA
  86. int Ea_add_ns(int *tab, int ea)
  87. {
  88.     if(ea<0x10)         return 0;
  89.     if((ea&0x38)==0x10) return tab[0]; // (An) (ai)
  90.     if(ea<0x28)         return 0;
  91.     if(ea<0x30)         return tab[1]; // ($nn,An) (di)
  92.     if(ea<0x38)         return tab[2]; // ($nn,An,Rn) (ix)
  93.     if(ea==0x38)        return tab[3]; // (aw)
  94.     if(ea==0x39)        return tab[4]; // (al)
  95.     if(ea==0x3a)        return tab[5]; // ($nn,PC) (pcdi)
  96.     if(ea==0x3b)        return tab[6]; // ($nn,pc,Rn) (pcix)
  97.     if(ea==0x3c)        return tab[7]; // #$nnnn (i)
  98.     return 0;
  99. }
  100.  
  101.  
  102. // ---------------------------------------------------------------------------
  103. // Gets the offset of a register for an ea, and puts it in 'r'
  104. // Shifted left by 'shift'
  105. // Doesn't trash anything
  106. static int EaCalcReg(int r,int ea,int mask,int forceor,int shift,int noshift=0)
  107. {
  108.   int i=0,low=0,needor=0;
  109.   int lsl=0;
  110.  
  111.   for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is
  112.   mask&=0xf<<low; // This is the max we can do
  113.  
  114.   if (ea>=8)
  115.   {
  116.     needor=1; // Need to OR to access A0-7
  117.     if ((g_op>>low)&8) { needor=0; mask|=8<<low; } // Ah - no we don't actually need to or, since the bit is high in r8
  118.     if (forceor) needor=1; // Special case for 0x30-0x38 EAs ;)
  119.   }
  120.  
  121.   ot("  and r%d,r8,#0x%.4x\n",r,mask);
  122.   if (needor) ot("  orr r%d,r%d,#0x%x ;@ A0-7\n",r,r,8<<low);
  123.  
  124.   // Find out amount to shift left:
  125.   lsl=shift-low;
  126.  
  127.   if (lsl&&!noshift)
  128.   {
  129.     ot("  mov r%d,r%d,",r,r);
  130.     if (lsl>0) ot("lsl #%d\n", lsl);
  131.     else       ot("lsr #%d\n",-lsl);
  132.   }
  133.  
  134.   return 0;
  135. }
  136.  
  137. // EaCalc - ARM Register 'a' = Effective Address
  138. // If ea>=0x10, trashes r0,r2 and r3, else nothing
  139. // size values 0, 1, 2 ~ byte, word, long
  140. // mask shows usable bits in r8
  141. int EaCalc(int a,int mask,int ea,int size,int top,int sign_extend)
  142. {
  143.   char text[32]="";
  144.   int func=0;
  145.  
  146.   DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
  147.   func=0x68+(size<<2); // Get correct read handler
  148.   (void)func;
  149.  
  150.   if (ea<0x10)
  151.   {
  152.     int noshift=0;
  153.     if (size>=2||(size==0&&(top||!sign_extend))) noshift=1; // Saves one opcode
  154.  
  155.     ot(";@ EaCalc : Get register index into r%d:\n",a);
  156.  
  157.     EaCalcReg(a,ea,mask,0,2,noshift);
  158.     return 0;
  159.   }
  160.  
  161.   ot(";@ EaCalc : Get '%s' into r%d:\n",text,a);
  162.   // (An), (An)+, -(An)
  163.   if (ea<0x28)
  164.   {
  165.     int step=1<<size, strr=a;
  166.     int low=0,lsl=0,i;
  167.  
  168.     if ((ea&7)==7 && step<2) step=2; // move.b (a7)+ or -(a7) steps by 2 not 1
  169.  
  170.     if (ea==0x1f||ea==0x27) // A7 handlers are always separate
  171.     {
  172.       ot("  ldr r%d,[r7,#0x3c] ;@ A7\n",a);
  173.     }
  174.     else
  175.     {
  176.       EaCalcReg(2,ea,mask,0,0,1);
  177.       if(mask)
  178.         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is
  179.       lsl=2-low; // Having a lsl #x here saves one opcode
  180.       if      (lsl>=0) ot("  ldr r%d,[r7,r2,lsl #%i]\n",a,lsl);
  181.       else if (lsl<0)  ot("  ldr r%d,[r7,r2,lsr #%i]\n",a,-lsl);
  182.     }
  183.  
  184.     if ((ea&0x38)==0x18) // (An)+
  185.     {
  186.       ot("  add r3,r%d,#%d ;@ Post-increment An\n",a,step);
  187.       strr=3;
  188.     }
  189.  
  190.     if ((ea&0x38)==0x20) // -(An)
  191.       ot("  sub r%d,r%d,#%d ;@ Pre-decrement An\n",a,a,step);
  192.  
  193.     if ((ea&0x38)==0x18||(ea&0x38)==0x20)
  194.     {
  195.       if (ea==0x1f||ea==0x27)
  196.       {
  197.         ot("  str r%d,[r7,#0x3c] ;@ A7\n",strr);
  198.       }
  199.       else
  200.       {
  201.         if      (lsl>=0) ot("  str r%d,[r7,r2,lsl #%i]\n",strr,lsl);
  202.         else if (lsl<0)  ot("  str r%d,[r7,r2,lsr #%i]\n",strr,-lsl);
  203.       }
  204.     }
  205.  
  206.     if ((ea&0x38)==0x20) Cycles+=size<2 ? 6:10; // -(An) Extra cycles
  207.     else                 Cycles+=size<2 ? 4:8;  // (An),(An)+ Extra cycles
  208.     return 0;
  209.   }
  210.  
  211.   if (ea<0x30) // ($nn,An) (di)
  212.   {
  213.     ot("  ldrsh r0,[r4],#2 ;@ Fetch offset\n"); pc_dirty=1;
  214.     EaCalcReg(2,8,mask,0,0);
  215.     ot("  ldr r2,[r7,r2,lsl #2]\n");
  216.     ot("  add r%d,r0,r2 ;@ Add on offset\n",a);
  217.     Cycles+=size<2 ? 8:12; // Extra cycles
  218.     return 0;
  219.   }
  220.  
  221.   if (ea<0x38) // ($nn,An,Rn) (ix)
  222.   {
  223.     ot(";@ Get extension word into r3:\n");
  224.     ot("  ldrh r3,[r4],#2 ;@ ($Disp,PC,Rn)\n"); pc_dirty=1;
  225.     ot("  mov r2,r3,lsr #10\n");
  226.     ot("  tst r3,#0x0800 ;@ Is Rn Word or Long\n");
  227.     ot("  and r2,r2,#0x3c ;@ r2=Index of Rn\n");
  228.     ot("  ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");
  229.     ot("  ldrne   r2,[r7,r2] ;@ r2=Rn.l\n");
  230.     ot("  mov r0,r3,asl #24 ;@ r0=Get 8-bit signed Disp\n");
  231.     ot("  add r3,r2,r0,asr #24 ;@ r3=Disp+Rn\n");
  232.  
  233.     EaCalcReg(2,8,mask,1,0);
  234.     ot("  ldr r2,[r7,r2,lsl #2]\n");
  235.     ot("  add r%d,r2,r3 ;@ r%d=Disp+An+Rn\n",a,a);
  236.     Cycles+=size<2 ? 10:14; // Extra cycles
  237.     return 0;
  238.   }
  239.  
  240.   if (ea==0x38) // (aw)
  241.   {
  242.     ot("  ldrsh r%d,[r4],#2 ;@ Fetch Absolute Short address\n",a); pc_dirty=1;
  243.     Cycles+=size<2 ? 8:12; // Extra cycles
  244.     return 0;
  245.   }
  246.  
  247.   if (ea==0x39) // (al)
  248.   {
  249.     ot("  ldrh r2,[r4],#2 ;@ Fetch Absolute Long address\n");
  250.     ot("  ldrh r0,[r4],#2\n"); pc_dirty=1;
  251.     ot("  orr r%d,r0,r2,lsl #16\n",a);
  252.     Cycles+=size<2 ? 12:16; // Extra cycles
  253.     return 0;
  254.   }
  255.  
  256.   if (ea==0x3a) // ($nn,PC) (pcdi)
  257.   {
  258.     ot("  ldr r0,[r7,#0x60] ;@ Get Memory base\n");
  259.     ot("  sub r0,r4,r0 ;@ Real PC\n");
  260.     ot("  ldrsh r2,[r4],#2 ;@ Fetch extension\n"); pc_dirty=1;
  261.     ot("  mov r0,r0,lsl #8\n");
  262.     ot("  add r%d,r2,r0,asr #8 ;@ ($nn,PC)\n",a);
  263.     Cycles+=size<2 ? 8:12; // Extra cycles
  264.     return 0;
  265.   }
  266.  
  267.   if (ea==0x3b) // ($nn,pc,Rn) (pcix)
  268.   {
  269.     ot("  ldr r0,[r7,#0x60] ;@ Get Memory base\n");
  270.     ot("  ldrh r3,[r4] ;@ Get extension word\n");
  271.     ot("  sub r0,r4,r0 ;@ r0=PC\n");
  272.     ot("  add r4,r4,#2\n"); pc_dirty=1;
  273.     ot("  mov r0,r0,asl #8 ;@ use only 24bits of PC\n");
  274.     ot("  mov r2,r3,lsr #10\n");
  275.     ot("  tst r3,#0x0800 ;@ Is Rn Word or Long\n");
  276.     ot("  and r2,r2,#0x3c ;@ r2=Index of Rn\n");
  277.     ot("  ldreqsh r2,[r7,r2] ;@ r2=Rn.w\n");
  278.     ot("  ldrne   r2,[r7,r2] ;@ r2=Rn.l\n");
  279.     ot("  mov r3,r3,asl #24 ;@ r3=Get 8-bit signed Disp\n");
  280.     ot("  add r2,r2,r3,asr #24 ;@ r2=Disp+Rn\n");
  281.     ot("  add r%d,r2,r0,asr #8 ;@ r%d=Disp+PC+Rn\n",a,a);
  282.     Cycles+=size<2 ? 10:14; // Extra cycles
  283.     return 0;
  284.   }
  285.  
  286.   if (ea==0x3c) // #$nnnn (i)
  287.   {
  288.     if (size<2)
  289.     {
  290.       ot("  ldr%s r%d,[r4],#2 ;@ Fetch immediate value\n",Sarm[size&3],a); pc_dirty=1;
  291.       Cycles+=4; // Extra cycles
  292.       return 0;
  293.     }
  294.  
  295.     ot("  ldrh r2,[r4],#2 ;@ Fetch immediate value\n");
  296.     ot("  ldrh r3,[r4],#2\n"); pc_dirty=1;
  297.     ot("  orr r%d,r3,r2,lsl #16\n",a);
  298.     Cycles+=8; // Extra cycles
  299.     return 0;
  300.   }
  301.  
  302.   return 1;
  303. }
  304.  
  305. // ---------------------------------------------------------------------------
  306. // Read effective address in (ARM Register 'a') to ARM register 'v'
  307. // 'a' and 'v' can be anything but 0 is generally best (for both)
  308. // If (ea<0x10) nothing is trashed, else r0-r3 is trashed
  309. // If 'top' is given, the ARM register v shifted to the top, e.g. 0xc000 -> 0xc0000000
  310. // If top is 0 and sign_extend is not, then ARM register v is sign extended,
  311. // e.g. 0xc000 -> 0xffffc000 (else it may or may not be sign extended)
  312.  
  313. int EaRead(int a,int v,int ea,int size,int mask,int top,int sign_extend)
  314. {
  315.   char text[32]="";
  316.   int shift=0;
  317.  
  318.   shift=32-(8<<size);
  319.  
  320.   DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
  321.  
  322.   if (ea<0x10)
  323.   {
  324.     int lsl=0,low=0,nsarm=size&3,i;
  325.     if (size>=2||(size==0&&(top||!sign_extend))) {
  326.       if(mask)
  327.         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is
  328.       lsl=2-low; // Having a lsl #2 here saves one opcode
  329.     }
  330.  
  331.     if (top||!sign_extend) nsarm=3;
  332.  
  333.     ot(";@ EaRead : Read register[r%d] into r%d:\n",a,v);
  334.  
  335.     if      (lsl>0) ot("  ldr%s r%d,[r7,r%d,lsl #%i]\n",Narm[nsarm],v,a,lsl);
  336.     else if (lsl<0) ot("  ldr%s r%d,[r7,r%d,lsr #%i]\n",Narm[nsarm],v,a,-lsl);
  337.     else            ot("  ldr%s r%d,[r7,r%d]\n",Sarm[nsarm],v,a);
  338.  
  339.     if (top&&shift) ot("  mov r%d,r%d,asl #%d\n",v,v,shift);
  340.  
  341.     ot("\n"); return 0;
  342.   }
  343.  
  344.   ot(";@ EaRead : Read '%s' (address in r%d) into r%d:\n",text,a,v);
  345.  
  346.   if (ea==0x3c)
  347.   {
  348.     int asl=0;
  349.  
  350.     if (top) asl=shift;
  351.  
  352.     if (asl) ot("  mov r%d,r%d,asl #%d\n",v,a,asl);
  353.     else if (v!=a) ot("  mov r%d,r%d\n",v,a);
  354.     ot("\n"); return 0;
  355.   }
  356.  
  357.   if (ea>=0x3a && ea<=0x3b) MemHandler(2,size,a,earead_check_addrerr); // Fetch
  358.   else                      MemHandler(0,size,a,earead_check_addrerr); // Read
  359.  
  360.   // defaults to 1, as most things begins with a read
  361.   earead_check_addrerr=1;
  362.  
  363.   if (sign_extend)
  364.   {
  365.     int d_reg=0;
  366.     if (shift) {
  367.       ot("  mov r%d,r%d,asl #%d\n",v,d_reg,shift);
  368.       d_reg=v;
  369.     }
  370.     if (!top && shift) {
  371.       ot("  mov r%d,r%d,asr #%d\n",v,d_reg,shift);
  372.       d_reg=v;
  373.     }
  374.     if (d_reg != v)
  375.       ot("  mov r%d,r%d\n",v,d_reg);
  376.   }
  377.   else
  378.   {
  379.     if (top && shift)
  380.       ot("  mov r%d,r0,asl #%d\n",v,shift);
  381.     else if (v!=0)
  382.       ot("  mov r%d,r0\n",v);
  383.   }
  384.  
  385.   ot("\n"); return 0;
  386. }
  387.  
  388. // calculate EA and  read
  389. // if (ea  < 0x10) nothing is trashed
  390. // if (ea == 0x3c) r2 and r3 are trashed
  391. // else r0-r3 are trashed
  392. // size values 0, 1, 2 ~ byte, word, long
  393. // r_ea is reg to store ea in (-1 means ea is not needed), r is dst reg
  394. // if sign_extend is 0, non-32bit values will have MS bits undefined
  395. int EaCalcRead(int r_ea,int r,int ea,int size,int mask,int sign_extend)
  396. {
  397.   if (ea<0x10)
  398.   {
  399.     if (r_ea==-1)
  400.     {
  401.       r_ea=r;
  402.       if (!sign_extend) size=2;
  403.     }
  404.   }
  405.   else if (ea==0x3c) // #imm
  406.   {
  407.     r_ea=r;
  408.   }
  409.   else
  410.   {
  411.     if (r_ea==-1) r_ea=0;
  412.   }
  413.  
  414.   EaCalc (r_ea,mask,ea,size,0,sign_extend);
  415.   EaRead (r_ea,   r,ea,size,mask,0,sign_extend);
  416.  
  417.   return 0;
  418. }
  419.  
  420. int EaCalcReadNoSE(int r_ea,int r,int ea,int size,int mask)
  421. {
  422.   return EaCalcRead(r_ea,r,ea,size,mask,0);
  423. }
  424.  
  425. // Return 1 if we can read this ea
  426. int EaCanRead(int ea,int size)
  427. {
  428.   if (size<0)
  429.   {
  430.     // LEA:
  431.     // These don't make sense?:
  432.     if (ea< 0x10) return 0; // Register
  433.     if (ea==0x3c) return 0; // Immediate
  434.     if (ea>=0x18 && ea<0x28) return 0; // Pre/Post inc/dec An
  435.   }
  436.  
  437.   if (ea<=0x3c) return 1;
  438.   return 0;
  439. }
  440.  
  441. // ---------------------------------------------------------------------------
  442. // Write effective address (ARM Register 'a') with ARM register 'v'
  443. // Trashes r0-r3,r12,lr; 'a' can be 0 or 2+, 'v' can be 1 or higher
  444. // If a==0 and v==1 it's faster though.
  445. int EaWrite(int a,int v,int ea,int size,int mask,int top,int sign_extend_ea)
  446. {
  447.   char text[32]="";
  448.   int shift=0;
  449.  
  450.   if(a == 1) { printf("Error! EaWrite a==1 !\n"); return 1; }
  451.  
  452.   if (top) shift=32-(8<<size);
  453.  
  454.   DisaPc=2; DisaGetEa(text,ea,size); // Get text version of the effective address
  455.  
  456.   if (ea<0x10)
  457.   {
  458.     int lsl=0,low=0,i;
  459.     if (size>=2||(size==0&&(top||!sign_extend_ea))) {
  460.       if(mask)
  461.         for (i=mask|0x8000; (i&1)==0; i>>=1) low++; // Find out how high up the EA mask is
  462.       lsl=2-low; // Having a lsl #x here saves one opcode
  463.     }
  464.  
  465.     ot(";@ EaWrite: r%d into register[r%d]:\n",v,a);
  466.     if (shift)  ot("  mov r%d,r%d,asr #%d\n",v,v,shift);
  467.  
  468.     if      (lsl>0) ot("  str%s r%d,[r7,r%d,lsl #%i]\n",Narm[size&3],v,a,lsl);
  469.     else if (lsl<0) ot("  str%s r%d,[r7,r%d,lsr #%i]\n",Narm[size&3],v,a,-lsl);
  470.     else            ot("  str%s r%d,[r7,r%d]\n",Narm[size&3],v,a);
  471.  
  472.     ot("\n"); return 0;
  473.   }
  474.  
  475.   ot(";@ EaWrite: Write r%d into '%s' (address in r%d):\n",v,text,a);
  476.  
  477.   if (ea==0x3c) { ot("Error! Write EA=0x%x\n\n",ea); return 1; }
  478.  
  479.   if (shift)     ot("  mov r1,r%d,asr #%d\n",v,shift);
  480.   else if (v!=1) ot("  mov r1,r%d\n",v);
  481.  
  482.   MemHandler(1,size,a,eawrite_check_addrerr); // Call write handler
  483.  
  484.   // not check by default, because most cases are rmw and
  485.   // address was already checked before reading
  486.   eawrite_check_addrerr = 0;
  487.  
  488.   ot("\n"); return 0;
  489. }
  490.  
  491. // Return 1 if we can write this ea
  492. int EaCanWrite(int ea)
  493. {
  494.   if (ea<=0x39) return 1; // 3b?
  495.   return 0;
  496. }
  497. // ---------------------------------------------------------------------------
  498.  
  499. // Return 1 if EA is An reg
  500. int EaAn(int ea)
  501. {
  502.   if((ea&0x38)==8) return 1;
  503.   return 0;
  504. }
  505.  
  506.