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. // in/out address in r0, trashes all temp regs
  16. static void CheckPc(void)
  17. {
  18. #if USE_CHECKPC_CALLBACK
  19.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  20.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  21.  #else
  22.   ot(";@ Check Memory Base+pc\n");
  23.   ot("  mov lr,pc\n");
  24.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  25.   ot("\n");
  26.  #endif
  27. #endif
  28. }
  29.  
  30. // Push 32-bit value in r1 - trashes r0-r3,r12,lr
  31. void OpPush32()
  32. {
  33.   ot(";@ Push r1 onto stack\n");
  34.   ot("  ldr r0,[r7,#0x3c]\n");
  35.   ot("  sub r0,r0,#4 ;@ Predecrement A7\n");
  36.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  37.   MemHandler(1,2);
  38.   ot("\n");
  39. }
  40.  
  41. // Push SR - trashes r0-r3,r12,lr
  42. void OpPushSr(int high)
  43. {
  44.   ot(";@ Push SR:\n");
  45.   OpFlagsToReg(high);
  46.   ot("  ldr r0,[r7,#0x3c]\n");
  47.   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
  48.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  49.   MemHandler(1,1);
  50.   ot("\n");
  51. }
  52.  
  53. // Pop SR - trashes r0-r3
  54. static void PopSr(int high)
  55. {
  56.   ot(";@ Pop SR:\n");
  57.   ot("  ldr r0,[r7,#0x3c]\n");
  58.   ot("  add r1,r0,#2 ;@ Postincrement A7\n");
  59.   ot("  str r1,[r7,#0x3c] ;@ Save A7\n");
  60.   MemHandler(0,1);
  61.   ot("\n");
  62.   OpRegToFlags(high);
  63. }
  64.  
  65. // Pop PC - trashes r0-r3
  66. static void PopPc()
  67. {
  68.   ot(";@ Pop PC:\n");
  69.   ot("  ldr r0,[r7,#0x3c]\n");
  70.   ot("  add r1,r0,#4 ;@ Postincrement A7\n");
  71.   ot("  str r1,[r7,#0x3c] ;@ Save A7\n");
  72.   MemHandler(0,2);
  73.   ot("  ldr r1,[r7,#0x60] ;@ Get Memory base\n");
  74.   ot("  add r0,r0,r1 ;@ Memory Base+PC\n");
  75.   ot("\n");
  76.   CheckPc();
  77. #if EMULATE_ADDRESS_ERRORS_JUMP
  78.   ot("  mov r4,r0\n");
  79. #else
  80.   ot("  bic r4,r0,#1\n");
  81. #endif
  82. }
  83.  
  84. int OpTrap(int op)
  85. {
  86.   int use=0;
  87.  
  88.   use=op&~0xf;
  89.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  90.  
  91.   OpStart(op,0x10);
  92.   ot("  and r0,r8,#0xf ;@ Get trap number\n");
  93.   ot("  orr r0,r0,#0x20 ;@ 32+n\n");
  94.   ot("  bl Exception\n");
  95.   ot("\n");
  96.  
  97.   Cycles=38; OpEnd(0x10);
  98.  
  99.   return 0;
  100. }
  101.  
  102. // --------------------- Opcodes 0x4e50+ ---------------------
  103. int OpLink(int op)
  104. {
  105.   int use=0,reg;
  106.  
  107.   use=op&~7;
  108.   reg=op&7;
  109.   if (reg==7) use=op;
  110.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  111.  
  112.   OpStart(op,0x10);
  113.  
  114.   if(reg!=7) {
  115.     ot(";@ Get An\n");
  116.     EaCalc(11, 7, 8, 2, 1);
  117.     EaRead(11, 1, 8, 2, 7, 1);
  118.   }
  119.  
  120.   ot("  ldr r0,[r7,#0x3c] ;@ Get A7\n");
  121.   ot("  sub r0,r0,#4 ;@ A7-=4\n");
  122.   ot("  mov r8,r0 ;@ abuse r8\n");
  123.   if(reg==7) ot("  mov r1,r0\n");
  124.   ot("\n");
  125.  
  126.   ot(";@ Write An to Stack\n");
  127.   MemHandler(1,2);
  128.  
  129.   ot(";@ Save to An\n");
  130.   if(reg!=7)
  131.     EaWrite(11,8, 8, 2, 7, 1);
  132.  
  133.   ot(";@ Get offset:\n");
  134.   EaCalc(0,0,0x3c,1);    // abused r8 is ok because of imm EA
  135.   EaRead(0,0,0x3c,1,0);
  136.  
  137.   ot("  add r8,r8,r0 ;@ Add offset to A7\n");
  138.   ot("  str r8,[r7,#0x3c]\n");
  139.   ot("\n");
  140.  
  141.   Cycles=16;
  142.   OpEnd(0x10);
  143.   return 0;
  144. }
  145.  
  146. // --------------------- Opcodes 0x4e58+ ---------------------
  147. int OpUnlk(int op)
  148. {
  149.   int use=0;
  150.  
  151.   use=op&~7;
  152.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  153.  
  154.   OpStart(op,0x10);
  155.  
  156.   ot(";@ Get An\n");
  157.   EaCalc(11, 0xf, 8, 2,   1);
  158.   EaRead(11,   0, 8, 2, 0xf, 1);
  159.  
  160.   ot("  add r8,r0,#4 ;@ A7+=4, abuse r8\n");
  161.   ot("\n");
  162.   ot(";@ Pop An from stack:\n");
  163.   MemHandler(0,2);
  164.   ot("\n");
  165.   ot("  str r8,[r7,#0x3c] ;@ Save A7\n");
  166.   ot("\n");
  167.   ot(";@ An = value from stack:\n");
  168.   EaWrite(11, 0, 8, 2, 7, 1);
  169.  
  170.   Cycles=12;
  171.   OpEnd(0x10);
  172.   return 0;
  173. }
  174.  
  175. // --------------------- Opcodes 0x4e70+ ---------------------
  176. // 01001110 01110ttt
  177. int Op4E70(int op)
  178. {
  179.   int type=0;
  180.  
  181.   type=op&7; // reset/nop/stop/rte/rtd/rts/trapv/rtr
  182.  
  183.   switch (type)
  184.   {
  185.     case 1:  // nop
  186.     OpStart(op);
  187.     Cycles=4;
  188.     OpEnd();
  189.     return 0;
  190.  
  191.     case 3: // rte
  192.     OpStart(op,0x10,0,0,1); Cycles=20;
  193.     PopSr(1);
  194.     PopPc();
  195.     ot("  ldr r1,[r7,#0x44] ;@ reload SR high\n");
  196.     SuperChange(op,1);
  197. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO || EMULATE_HALT
  198.     ot("  ldr r1,[r7,#0x58]\n");
  199.     ot("  bic r1,r1,#0x0c ;@ clear 'not processing instruction' and 'doing addr error' bits\n");
  200.     ot("  str r1,[r7,#0x58]\n");
  201. #endif
  202. #if EMULATE_ADDRESS_ERRORS_JUMP
  203.     ot("  tst r4,#1 ;@ address error?\n");
  204.     ot("  bne ExceptionAddressError_r_prg_r4\n");
  205. #endif
  206.     opend_check_interrupt = 1;
  207.     opend_check_trace = 1;
  208.     OpEnd(0x10,0);
  209.     return 0;
  210.  
  211.     case 5: // rts
  212.     OpStart(op,0x10); Cycles=16;
  213.     PopPc();
  214. #if EMULATE_ADDRESS_ERRORS_JUMP
  215.     ot("  tst r4,#1 ;@ address error?\n");
  216.     ot("  bne ExceptionAddressError_r_prg_r4\n");
  217. #endif
  218.     OpEnd(0x10);
  219.     return 0;
  220.  
  221.     case 6: // trapv
  222.     OpStart(op,0x10,0,1); Cycles=4;
  223.     ot("  tst r10,#0x10000000\n");
  224.     ot("  subne r5,r5,#%i\n",34);
  225.     ot("  movne r0,#7 ;@ TRAPV exception\n");
  226.     ot("  blne Exception\n");
  227.     opend_op_changes_cycles = 1;
  228.     OpEnd(0x10,0);
  229.     return 0;
  230.  
  231.     case 7: // rtr
  232.     OpStart(op,0x10); Cycles=20;
  233.     PopSr(0);
  234.     PopPc();
  235. #if EMULATE_ADDRESS_ERRORS_JUMP
  236.     ot("  tst r4,#1 ;@ address error?\n");
  237.     ot("  bne ExceptionAddressError_r_prg_r4\n");
  238. #endif
  239.     OpEnd(0x10);
  240.     return 0;
  241.  
  242.     default:
  243.     return 1;
  244.   }
  245. }
  246.  
  247. // --------------------- Opcodes 0x4e80+ ---------------------
  248. // Emit a Jsr/Jmp opcode, 01001110 1meeeeee
  249. int OpJsr(int op)
  250. {
  251.   int use=0;
  252.   int sea=0;
  253.  
  254.   sea=op&0x003f;
  255.  
  256.   // See if we can do this opcode:
  257.   if (EaCanRead(sea,-1)==0) return 1;
  258.  
  259.   use=OpBase(op,0);
  260.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  261.  
  262.   OpStart(op,(op&0x40)?0:0x10);
  263.  
  264.   ot("  ldr r11,[r7,#0x60] ;@ Get Memory base\n");
  265.   ot("\n");
  266.   EaCalc(12,0x003f,sea,0);
  267.  
  268.   ot(";@ Jump - Get new PC from r12\n");
  269.   ot("  add r0,r12,r11 ;@ Memory Base + New PC\n");
  270.   ot("\n");
  271.   CheckPc();
  272.   if (!(op&0x40))
  273.   {
  274.     ot("  ldr r2,[r7,#0x3c]\n");
  275.     ot("  sub r1,r4,r11 ;@ r1 = Old PC\n");
  276.   }
  277. #if EMULATE_ADDRESS_ERRORS_JUMP
  278.   // jsr prefetches next instruction before pushing old PC,
  279.   // according to http://pasti.fxatari.com/68kdocs/68kPrefetch.html
  280.   ot("  mov r4,r0\n");
  281.   ot("  tst r4,#1 ;@ address error?\n");
  282.   ot("  bne ExceptionAddressError_r_prg_r4\n");
  283. #else
  284.   ot("  bic r4,r0,#1\n");
  285. #endif
  286.  
  287.   if (!(op&0x40))
  288.   {
  289.     ot(";@ Push old PC onto stack\n");
  290.     ot("  sub r0,r2,#4 ;@ Predecrement A7\n");
  291.     ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  292.     MemHandler(1,2);
  293.   }
  294.  
  295.   Cycles=(op&0x40) ? 4 : 12;
  296.   Cycles+=Ea_add_ns((op&0x40) ? g_jmp_cycle_table : g_jsr_cycle_table, sea);
  297.  
  298.   OpEnd((op&0x40)?0:0x10);
  299.  
  300.   return 0;
  301. }
  302.  
  303. // --------------------- Opcodes 0x50c8+ ---------------------
  304.  
  305. // ARM version of 68000 condition codes:
  306. static const char * const Cond[16]=
  307. {
  308.   "",  "",  "hi","ls","cc","cs","ne","eq",
  309.   "vc","vs","pl","mi","ge","lt","gt","le"
  310. };
  311.  
  312. // Emit a Dbra opcode, 0101cccc 11001nnn vv
  313. int OpDbra(int op)
  314. {
  315.   int use=0;
  316.   int cc=0;
  317.  
  318.   use=op&~7; // Use same handler
  319.   cc=(op>>8)&15;
  320.  
  321.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  322.   OpStart(op);
  323.  
  324.   switch (cc)
  325.   {
  326.     case 0: // T
  327.     case 1: // F
  328.       break;
  329.     case 2: // hi
  330.       ot("  tst r10,#0x60000000 ;@ hi: !C && !Z\n");
  331.       ot("  beq DbraTrue\n\n");
  332.       break;
  333.     case 3: // ls
  334.       ot("  tst r10,#0x60000000 ;@ ls: C || Z\n");
  335.       ot("  bne DbraTrue\n\n");
  336.       break;
  337.     default:
  338.       ot(";@ Is the condition true?\n");
  339.       ot("  msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n");
  340.       ot(";@ If so, don't dbra\n");
  341.       ot("  b%s DbraTrue\n\n",Cond[cc]);
  342.       break;
  343.   }
  344.  
  345.   if (cc!=0)
  346.   {
  347.     ot(";@ Decrement Dn.w\n");
  348.     ot("  and r1,r8,#0x0007\n");
  349.     ot("  mov r1,r1,lsl #2\n");
  350.     ot("  ldrsh r0,[r7,r1]\n");
  351.     ot("  sub r0,r0,#1\n");
  352.     ot("  strh r0,[r7,r1]\n");
  353.     ot("\n");
  354.  
  355.     ot(";@ Check if Dn.w is -1\n");
  356.     ot("  cmn r0,#1\n");
  357.  
  358. #if (USE_CHECKPC_CALLBACK && USE_CHECKPC_DBRA) || EMULATE_ADDRESS_ERRORS_JUMP
  359.     ot("  beq DbraMin1\n");
  360.     ot("\n");
  361.  
  362.     ot(";@ Get Branch offset:\n");
  363.     ot("  ldrsh r0,[r4]\n");
  364.     ot("  add r0,r4,r0 ;@ r0 = New PC\n");
  365.     CheckPc();
  366. #if EMULATE_ADDRESS_ERRORS_JUMP
  367.     ot("  mov r4,r0\n");
  368.     ot("  tst r4,#1 ;@ address error?\n");
  369.     ot("  bne ExceptionAddressError_r_prg_r4\n");
  370. #else
  371.     ot("  bic r4,r0,#1\n");
  372. #endif
  373. #else
  374.     ot("\n");
  375.     ot(";@ Get Branch offset:\n");
  376.     ot("  ldrnesh r0,[r4]\n");
  377.     ot("  addeq r4,r4,#2 ;@ Skip branch offset\n");
  378.     ot("  subeq r5,r5,#4 ;@ additional cycles\n");
  379.     ot("  addne r4,r4,r0 ;@ r4 = New PC\n");
  380.     ot("  bic r4,r4,#1\n"); // we do not emulate address errors
  381.     ot("\n");
  382. #endif
  383.     Cycles=12-2;
  384.     OpEnd();
  385.   }
  386.  
  387.   //if (cc==0||cc>=2)
  388.   if (op==0x50c8)
  389.   {
  390.     ot(";@ condition true:\n");
  391.     ot("DbraTrue%s\n", ms?"":":");
  392.     ot("  add r4,r4,#2 ;@ Skip branch offset\n");
  393.     ot("\n");
  394.     Cycles=12;
  395.     OpEnd();
  396.   }
  397.  
  398. #if (USE_CHECKPC_CALLBACK && USE_CHECKPC_DBRA) || EMULATE_ADDRESS_ERRORS_JUMP
  399.   if (op==0x51c8)
  400.   {
  401.     ot(";@ Dn.w is -1:\n");
  402.     ot("DbraMin1%s\n", ms?"":":");
  403.     ot("  add r4,r4,#2 ;@ Skip branch offset\n");
  404.     ot("\n");
  405.     Cycles=12+2;
  406.     OpEnd();
  407.   }
  408. #endif
  409.  
  410.   return 0;
  411. }
  412.  
  413. // --------------------- Opcodes 0x6000+ ---------------------
  414. // Emit a Branch opcode 0110cccc nn  (cccc=condition)
  415. int OpBranch(int op)
  416. {
  417.   int size=0,use=0,checkpc=0;
  418.   int offset=0;
  419.   int cc=0;
  420.   const char *asr_r11="";
  421.  
  422.   offset=(char)(op&0xff);
  423.   cc=(op>>8)&15;
  424.  
  425.   // Special offsets:
  426.   if (offset==0)  size=1;
  427.   if (offset==-1) size=2;
  428.  
  429.   if (size==2) size=0; // 000 model does not support long displacement
  430.   if (size) use=op; // 16-bit or 32-bit
  431.   else use=(op&0xff00)+1; // Use same opcode for all 8-bit branches
  432.  
  433.   if (op!=use) { OpUse(op,use); return 0; } // Use existing handler
  434.   OpStart(op,size?0x10:0);
  435.   Cycles=10; // Assume branch taken
  436.  
  437.   switch (cc)
  438.   {
  439.     case 0: // T
  440.     case 1: // F
  441.       break;
  442.     case 2: // hi
  443.       ot("  tst r10,#0x60000000 ;@ hi: !C && !Z\n");
  444.       ot("  bne BccDontBranch%i\n\n",8<<size);
  445.       break;
  446.     case 3: // ls
  447.       ot("  tst r10,#0x60000000 ;@ ls: C || Z\n");
  448.       ot("  beq BccDontBranch%i\n\n",8<<size);
  449.       break;
  450.     default:
  451.       ot(";@ Is the condition true?\n");
  452.       ot("  msr cpsr_flg,r10 ;@ ARM flags = 68000 flags\n");
  453.       ot("  b%s BccDontBranch%i\n\n",Cond[cc^1],8<<size);
  454.       break;
  455.   }
  456.  
  457.   if (size)
  458.   {
  459.     if (size<2)
  460.     {
  461.       ot("  ldrsh r11,[r4] ;@ Fetch Branch offset\n");
  462.     }
  463.     else
  464.     {
  465.       ot("  ldrh r2,[r4] ;@ Fetch Branch offset\n");
  466.       ot("  ldrh r11,[r4,#2]\n");
  467.       ot("  orr r11,r11,r2,lsl #16\n");
  468.     }
  469.   }
  470.   else
  471.   {
  472.     ot("  mov r11,r8,asl #24 ;@ Shift 8-bit signed offset up...\n\n");
  473.     asr_r11=",asr #24";
  474.   }
  475.  
  476.   ot(";@ Branch taken - Add on r0 to PC\n");
  477.  
  478.   if (cc==1)
  479.   {
  480.     ot(";@ Bsr - remember old PC\n");
  481.     ot("  ldr r12,[r7,#0x60] ;@ Get Memory base\n");
  482.     ot("  ldr r2,[r7,#0x3c]\n");
  483.     ot("  sub r1,r4,r12 ;@ r1 = Old PC\n");
  484.     if (size) ot("  add r1,r1,#%d\n",1<<size);
  485.     ot("\n");
  486.     ot(";@ Push r1 onto stack\n");
  487.     ot("  sub r0,r2,#4 ;@ Predecrement A7\n");
  488.     ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  489.     MemHandler(1,2);
  490.     ot("\n");
  491.     Cycles=18; // always 18
  492.   }
  493.  
  494.   ot("  add r0,r4,r11%s ;@ r4 = New PC\n",asr_r11);
  495.  
  496. #if USE_CHECKPC_CALLBACK && USE_CHECKPC_OFFSETBITS_8
  497.   if (offset!=0 && offset!=-1) checkpc=1;
  498. #endif
  499. #if USE_CHECKPC_CALLBACK && USE_CHECKPC_OFFSETBITS_16
  500.   if (offset==0)  checkpc=1;
  501. #endif
  502. #if USE_CHECKPC_CALLBACK
  503.   if (offset==-1) checkpc=1;
  504. #endif
  505.   if (checkpc) CheckPc();
  506. #if EMULATE_ADDRESS_ERRORS_JUMP
  507.   ot("  mov r4,r0\n");
  508.   ot("  tst r4,#1 ;@ address error?\n");
  509.   ot("  bne ExceptionAddressError_r_prg_r4\n");
  510. #else
  511.   ot("  bic r4,r0,#1\n");
  512. #endif
  513.   ot("\n");
  514.  
  515.   OpEnd(size?0x10:0);
  516.  
  517.   // since all "DontBranch" code is same for every size, output only once
  518.   if (cc>=2&&(op&0xff00)==0x6700)
  519.   {
  520.     ot("BccDontBranch%i%s\n", 8<<size, ms?"":":");
  521.     if (size) ot("  add r4,r4,#%d\n",1<<size);
  522.     Cycles+=(size==1) ? 2 : -2; // Branch not taken
  523.     OpEnd(0);
  524.   }
  525.  
  526.   return 0;
  527. }
  528.  
  529.