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. static FILE *AsmFile=NULL;
  16.  
  17. static int CycloneVer=0x0099; // Version number of library
  18. int *CyJump=NULL; // Jump table
  19. int ms=USE_MS_SYNTAX; // If non-zero, output in Microsoft ARMASM format
  20. const char * const Narm[4]={ "b", "h","",""}; // Normal ARM Extensions for operand sizes 0,1,2
  21. const char * const Sarm[4]={"sb","sh","",""}; // Sign-extend ARM Extensions for operand sizes 0,1,2
  22. int Cycles; // Current cycles for opcode
  23. int pc_dirty; // something changed PC during processing
  24. int arm_op_count;
  25.  
  26. // opcodes often used by games
  27. static const unsigned short hot_opcodes[] = {
  28.   0x6701, // beq     $3
  29.   0x6601, // bne     $3
  30.   0x51c8, // dbra    Dn, $2
  31.   0x4a38, // tst.b   $0.w
  32.   0xd040, // add.w   Dn, Dn
  33.   0x4a79, // tst.w   $0.l
  34.   0x0240, // andi.w  #$0, D0
  35.   0x2038, // move.l  $0.w, D0
  36.   0xb0b8, // cmp.l   $0.w, D0
  37.   0x6001, // bra     $3
  38.   0x30c0, // move.w  D0, (A0)+
  39.   0x3028, // move.w  ($0,A0), D0
  40.   0x0c40, // cmpi.w  #$0, D0
  41.   0x0c79, // cmpi.w  #$0, $0.l
  42.   0x4e75, // rts
  43.   0x4e71, // nop
  44.   0x3000, // move.w  D0, D0
  45.   0x0839, // btst    #$0, $0.l
  46.   0x7000, // moveq   #$0, D0
  47.   0x3040, // movea.w D0, A0
  48.   0x0838, // btst    #$0, $0.w
  49.   0x4a39, // tst.b   $0.l
  50.   0x33d8, // move.w  (A0)+, $0.l
  51.   0x6700, // beq     $2
  52.   0xb038, // cmp.b   $0.w, D0
  53.   0x3039, // move.w  $0.l, D0
  54.   0x4840, // swap    D0
  55.   0x6101, // bsr     $3
  56.   0x6100, // bsr     $2
  57.   0x5e40, // addq.w  #7, D0
  58.   0x1039, // move.b  $0.l, D0
  59.   0x20c0, // move.l  D0, (A0)+
  60.   0x1018, // move.b  (A0)+, D0
  61.   0x30d0, // move.w  (A0), (A0)+
  62.   0x3080, // move.w  D0, (A0)
  63.   0x3018, // move.w  (A0)+, D0
  64.   0xc040, // and.w   D0, D0
  65.   0x3180, // move.w  D0, (A0,D0.w)
  66.   0x1198, // move.b  (A0)+, (A0,D0.w)
  67.   0x6501, // bcs     $3
  68.   0x6500, // bcs     $2
  69.   0x6401, // bcc     $3
  70.   0x6a01, // bpl     $3
  71.   0x41f0, // lea     (A0,D0.w), A0
  72.   0x4a28, // tst.b   ($0,A0)
  73.   0x0828, // btst    #$0, ($0,A0)
  74.   0x0640, // addi.w  #$0, D0
  75.   0x10c0, // move.b  D0, (A0)+
  76.   0x10d8, // move.b  (A0)+, (A0)+
  77. };
  78. #define hot_opcode_count (int)(sizeof(hot_opcodes) / sizeof(hot_opcodes[0]))
  79.  
  80. static int is_op_hot(int op)
  81. {
  82.   int i;
  83.   for (i = 0; i < hot_opcode_count; i++)
  84.     if (op == hot_opcodes[i])
  85.       return 1;
  86.   return 0;
  87. }
  88.  
  89. void ot(const char *format, ...)
  90. {
  91.   va_list valist;
  92.   int i, len;
  93.  
  94.   // notaz: stop me from leaving newlines in the middle of format string
  95.   // and generating bad code
  96.   for(i=0, len=strlen(format); i < len && format[i] != '\n'; i++);
  97.   if(i < len-1 && format[len-1] != '\n') printf("\nWARNING: possible improper newline placement:\n%s\n", format);
  98.  
  99.   if (format[0] == ' ' && format[1] == ' ' && format[2] != ' ' && format[2] != '.')
  100.     arm_op_count++;
  101.  
  102.   va_start(valist,format);
  103.   if (AsmFile) vfprintf(AsmFile,format,valist);
  104.   va_end(valist);
  105. }
  106.  
  107. void ltorg()
  108. {
  109.   if (ms) ot("  LTORG\n");
  110.   else    ot("  .ltorg\n");
  111. }
  112.  
  113. #if (CYCLONE_FOR_GENESIS == 2)
  114. // r12=ptr to tas in table, trashes r0,r1
  115. static void ChangeTAS(int norm)
  116. {
  117.   ot("  ldr r0,=Op4ad0%s\n",norm?"_":"");
  118.   ot("  mov r1,#8\n");
  119.   ot("setrtas_loop%i0%s ;@ 4ad0-4ad7\n",norm,ms?"":":");
  120.   ot("  subs r1,r1,#1\n");
  121.   ot("  str r0,[r12],#4\n");
  122.   ot("  bne setrtas_loop%i0\n",norm);
  123.   ot("  ldr r0,=Op4ad8%s\n",norm?"_":"");
  124.   ot("  mov r1,#7\n");
  125.   ot("setrtas_loop%i1%s ;@ 4ad8-4ade\n",norm,ms?"":":");
  126.   ot("  subs r1,r1,#1\n");
  127.   ot("  str r0,[r12],#4\n");
  128.   ot("  bne setrtas_loop%i1\n",norm);
  129.   ot("  ldr r0,=Op4adf%s\n",norm?"_":"");
  130.   ot("  str r0,[r12],#4\n");
  131.   ot("  ldr r0,=Op4ae0%s\n",norm?"_":"");
  132.   ot("  mov r1,#7\n");
  133.   ot("setrtas_loop%i2%s ;@ 4ae0-4ae6\n",norm,ms?"":":");
  134.   ot("  subs r1,r1,#1\n");
  135.   ot("  str r0,[r12],#4\n");
  136.   ot("  bne setrtas_loop%i2\n",norm);
  137.   ot("  ldr r0,=Op4ae7%s\n",norm?"_":"");
  138.   ot("  str r0,[r12],#4\n");
  139.   ot("  ldr r0,=Op4ae8%s\n",norm?"_":"");
  140.   ot("  mov r1,#8\n");
  141.   ot("setrtas_loop%i3%s ;@ 4ae8-4aef\n",norm,ms?"":":");
  142.   ot("  subs r1,r1,#1\n");
  143.   ot("  str r0,[r12],#4\n");
  144.   ot("  bne setrtas_loop%i3\n",norm);
  145.   ot("  ldr r0,=Op4af0%s\n",norm?"_":"");
  146.   ot("  mov r1,#8\n");
  147.   ot("setrtas_loop%i4%s ;@ 4af0-4af7\n",norm,ms?"":":");
  148.   ot("  subs r1,r1,#1\n");
  149.   ot("  str r0,[r12],#4\n");
  150.   ot("  bne setrtas_loop%i4\n",norm);
  151.   ot("  ldr r0,=Op4af8%s\n",norm?"_":"");
  152.   ot("  str r0,[r12],#4\n");
  153.   ot("  ldr r0,=Op4af9%s\n",norm?"_":"");
  154.   ot("  str r0,[r12],#4\n");
  155. }
  156. #endif
  157.  
  158. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  159. static void AddressErrorWrapper(char rw, const char *dataprg, int iw)
  160. {
  161.   ot("ExceptionAddressError_%c_%s%s\n", rw, dataprg, ms?"":":");
  162.   ot("  ldr r1,[r7,#0x44]\n");
  163.   ot("  mov r6,#0x%02x\n", iw);
  164.   ot("  mov r11,r0\n");
  165.   ot("  tst r1,#0x20\n");
  166.   ot("  orrne r6,r6,#4\n");
  167.   ot("  b ExceptionAddressError\n");
  168.   ot("\n");
  169. }
  170. #endif
  171.  
  172. void FlushPC(void)
  173. {
  174. #if MEMHANDLERS_NEED_PC
  175.   if (pc_dirty)
  176.     ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  177. #endif
  178.   pc_dirty = 0;
  179. }
  180.  
  181. static void PrintFramework()
  182. {
  183.   int state_flags_to_check = 1; // stopped
  184. #if EMULATE_TRACE
  185.   state_flags_to_check |= 2; // tracing
  186. #endif
  187. #if EMULATE_HALT
  188.   state_flags_to_check |= 0x10; // halted
  189. #endif
  190.  
  191.   ot(";@ --------------------------- Framework --------------------------\n");
  192.   if (ms) ot("CycloneRun\n");
  193.   else    ot("CycloneRun:\n");
  194.  
  195.   ot("  stmdb sp!,{r4-r8,r10,r11,lr}\n");
  196.  
  197.   ot("  mov r7,r0          ;@ r7 = Pointer to Cpu Context\n");
  198.   ot("                     ;@ r0-3 = Temporary registers\n");
  199.   ot("  ldrb r10,[r7,#0x46]    ;@ r10 = Flags (NZCV)\n");
  200.   ot("  ldr r6,=CycloneJumpTab ;@ r6 = Opcode Jump table\n");
  201.   ot("  ldr r5,[r7,#0x5c]  ;@ r5 = Cycles\n");
  202.   ot("  ldr r4,[r7,#0x40]  ;@ r4 = Current PC + Memory Base\n");
  203.   ot("                     ;@ r8 = Current Opcode\n");
  204.   ot("  ldr r1,[r7,#0x44]  ;@ Get SR high T_S__III and irq level\n");
  205.   ot("  mov r10,r10,lsl #28;@ r10 = Flags 0xf0000000, cpsr format\n");
  206.   ot("                     ;@ r11 = Source value / Memory Base\n");
  207.   ot("  str r6,[r7,#0x54]  ;@ make a copy to avoid literal pools\n");
  208.   ot("\n");
  209. #if (CYCLONE_FOR_GENESIS == 2) || EMULATE_TRACE
  210.   ot("  mov r2,#0\n");
  211.   ot("  str r2,[r7,#0x98]  ;@ clear custom CycloneEnd\n");
  212. #endif
  213.   ot(";@ CheckInterrupt:\n");
  214.   ot("  movs r0,r1,lsr #24 ;@ Get IRQ level\n"); // same as  ldrb r0,[r7,#0x47]
  215.   ot("  beq NoInts0\n");
  216.   ot("  cmp r0,#6 ;@ irq>6 ?\n");
  217.   ot("  andle r1,r1,#7 ;@ Get interrupt mask\n");
  218.   ot("  cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n");
  219.   ot("  bgt CycloneDoInterrupt\n");
  220.   ot("NoInts0%s\n", ms?"":":");
  221.   ot("\n");
  222.   ot(";@ Check if our processor is in special state\n");
  223.   ot(";@ and jump to opcode handler if not\n");
  224.   ot("  ldr r0,[r7,#0x58] ;@ state_flags\n");
  225.   ot("  ldrh r8,[r4],#2 ;@ Fetch first opcode\n");
  226.   ot("  tst r0,#0x%02x ;@ special state?\n", state_flags_to_check);
  227.   ot("  ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  228.   ot("\n");
  229.   ot("CycloneSpecial%s\n", ms?"":":");
  230. #if EMULATE_TRACE
  231.   ot("  tst r0,#2 ;@ tracing?\n");
  232.   ot("  bne CycloneDoTrace\n");
  233. #endif
  234.   ot(";@ stopped or halted\n");
  235.   ot("  mov r5,#0\n");
  236.   ot("  str r5,[r7,#0x5C]  ;@ eat all cycles\n");
  237.   ot("  ldmia sp!,{r4-r8,r10,r11,pc} ;@ we are stopped, do nothing!\n");
  238.   ot("\n");
  239.   ot("\n");
  240.  
  241.   ot(";@ We come back here after execution\n");
  242.   ot("CycloneEnd%s\n", ms?"":":");
  243.   ot("  sub r4,r4,#2\n");
  244.   ot("CycloneEndNoBack%s\n", ms?"":":");
  245. #if (CYCLONE_FOR_GENESIS == 2) || EMULATE_TRACE
  246.   ot("  ldr r1,[r7,#0x98]\n");
  247.   ot("  mov r10,r10,lsr #28\n");
  248.   ot("  tst r1,r1\n");
  249.   ot("  bxne r1            ;@ jump to alternative CycloneEnd\n");
  250. #else
  251.   ot("  mov r10,r10,lsr #28\n");
  252. #endif
  253.   ot("  str r4,[r7,#0x40]  ;@ Save Current PC + Memory Base\n");
  254.   ot("  str r5,[r7,#0x5c]  ;@ Save Cycles\n");
  255.   ot("  strb r10,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  256.   ot("  ldmia sp!,{r4-r8,r10,r11,pc}\n");
  257.   ltorg();
  258.   ot("\n");
  259.   ot("\n");
  260.  
  261.   ot("CycloneInit%s\n", ms?"":":");
  262. #if COMPRESS_JUMPTABLE
  263.   ot(";@ decompress jump table\n");
  264.   ot("  ldr r12,=CycloneJumpTab\n");
  265.   ot("  add r0,r12,#0xe000*4 ;@ ctrl code pointer\n");
  266.   ot("  ldr r1,[r0,#-4]\n");
  267.   ot("  tst r1,r1\n");
  268.   ot("  movne pc,lr ;@ already uncompressed\n");
  269.   ot("  add r3,r12,#0xa000*4 ;@ handler table pointer, r12=dest\n");
  270.   ot("unc_loop%s\n", ms?"":":");
  271.   ot("  ldrh r1,[r0],#2\n");
  272.   ot("  and r2,r1,#0xf\n");
  273.   ot("  bic r1,r1,#0xf\n");
  274.   ot("  ldr r1,[r3,r1,lsr #2] ;@ r1=handler\n");
  275.   ot("  cmp r2,#0xf\n");
  276.   ot("  addeq r2,r2,#1 ;@ 0xf is really 0x10\n");
  277.   ot("  tst r2,r2\n");
  278.   ot("  ldreqh r2,[r0],#2 ;@ counter is in next word\n");
  279.   ot("  tst r2,r2\n");
  280.   ot("  beq unc_finish ;@ done decompressing\n");
  281.   ot("  tst r1,r1\n");
  282.   ot("  addeq r12,r12,r2,lsl #2 ;@ 0 handler means we should skip those bytes\n");
  283.   ot("  beq unc_loop\n");
  284.   ot("unc_loop_in%s\n", ms?"":":");
  285.   ot("  subs r2,r2,#1\n");
  286.   ot("  str r1,[r12],#4\n");
  287.   ot("  bgt unc_loop_in\n");
  288.   ot("  b unc_loop\n");
  289.   ot("unc_finish%s\n", ms?"":":");
  290.   ot("  ldr r12,=CycloneJumpTab\n");
  291.   ot("  ;@ set a-line and f-line handlers\n");
  292.   ot("  add r0,r12,#0xa000*4\n");
  293.   ot("  ldr r1,[r0,#4] ;@ a-line handler\n");
  294.   ot("  ldr r3,[r0,#8] ;@ f-line handler\n");
  295.   ot("  mov r2,#0x1000\n");
  296.   ot("unc_fill3%s\n", ms?"":":");
  297.   ot("  subs r2,r2,#1\n");
  298.   ot("  str r1,[r0],#4\n");
  299.   ot("  bgt unc_fill3\n");
  300.   ot("  add r0,r12,#0xf000*4\n");
  301.   ot("  mov r2,#0x1000\n");
  302.   ot("unc_fill4%s\n", ms?"":":");
  303.   ot("  subs r2,r2,#1\n");
  304.   ot("  str r3,[r0],#4\n");
  305.   ot("  bgt unc_fill4\n");
  306.   ot("  bx lr\n");
  307.   ltorg();
  308. #else
  309.   ot(";@ do nothing\n");
  310.   ot("  bx lr\n");
  311. #endif
  312.   ot("\n");
  313.  
  314.   // --------------
  315.   ot("CycloneReset%s\n", ms?"":":");
  316.   ot("  stmfd sp!,{r7,lr}\n");
  317.   ot("  mov r7,r0\n");
  318.   ot("  mov r0,#0\n");
  319.   ot("  str r0,[r7,#0x58] ;@ state_flags\n");
  320.   ot("  str r0,[r7,#0x48] ;@ OSP\n");
  321.   ot("  mov r1,#0x27 ;@ Supervisor mode\n");
  322.   ot("  strb r1,[r7,#0x44] ;@ set SR high\n");
  323.   ot("  strb r0,[r7,#0x47] ;@ IRQ\n");
  324.   MemHandler(0,2);
  325.   ot("  str r0,[r7,#0x3c] ;@ Stack pointer\n");
  326.   ot("  mov r0,#0\n");
  327.   ot("  str r0,[r7,#0x60] ;@ Membase\n");
  328.   ot("  mov r0,#4\n");
  329.   MemHandler(0,2);
  330. #ifdef MEMHANDLERS_DIRECT_PREFIX
  331.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  332. #else
  333.   ot("  mov lr,pc\n");
  334.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  335. #endif
  336.   ot("  str r0,[r7,#0x40] ;@ PC + base\n");
  337.   ot("  ldmfd sp!,{r7,pc}\n");
  338.   ot("\n");
  339.  
  340.   // --------------
  341.   // 68k: XNZVC, ARM: NZCV
  342.   ot("CycloneSetSr%s\n", ms?"":":");
  343.   ot("  mov r2,r1,lsr #8\n");
  344. //  ot("  ldrb r3,[r0,#0x44] ;@ get SR high\n");
  345. //  ot("  eor r3,r3,r2\n");
  346. //  ot("  tst r3,#0x20\n");
  347. #if EMULATE_TRACE
  348.   ot("  and r2,r2,#0xa7 ;@ only defined bits\n");
  349. #else
  350.   ot("  and r2,r2,#0x27 ;@ only defined bits\n");
  351. #endif
  352.   ot("  strb r2,[r0,#0x44] ;@ set SR high\n");
  353.   ot("  mov r2,r1,lsl #25\n");
  354.   ot("  str r2,[r0,#0x4c] ;@ the X flag\n");
  355.   ot("  bic r2,r1,#0xf3\n");
  356.   ot("  tst r1,#1\n");
  357.   ot("  orrne r2,r2,#2\n");
  358.   ot("  tst r1,#2\n");
  359.   ot("  orrne r2,r2,#1\n");
  360.   ot("  strb r2,[r0,#0x46] ;@ flags\n");
  361.   ot("  bx lr\n");
  362.   ot("\n");
  363.  
  364.   // --------------
  365.   ot("CycloneGetSr%s\n", ms?"":":");
  366.   ot("  ldrb r1,[r0,#0x46] ;@ flags\n");
  367.   ot("  bic r2,r1,#0xf3\n");
  368.   ot("  tst r1,#1\n");
  369.   ot("  orrne r2,r2,#2\n");
  370.   ot("  tst r1,#2\n");
  371.   ot("  orrne r2,r2,#1\n");
  372.   ot("  ldr r1,[r0,#0x4c] ;@ the X flag\n");
  373.   ot("  tst r1,#0x20000000\n");
  374.   ot("  orrne r2,r2,#0x10\n");
  375.   ot("  ldrb r1,[r0,#0x44] ;@ the SR high\n");
  376.   ot("  orr r0,r2,r1,lsl #8\n");
  377.   ot("  bx lr\n");
  378.   ot("\n");
  379.  
  380.   // --------------
  381.   ot("CyclonePack%s\n", ms?"":":");
  382.   ot("  stmfd sp!,{r4,r5,lr}\n");
  383.   ot("  mov r4,r0\n");
  384.   ot("  mov r5,r1\n");
  385.   ot("  mov r3,#16\n");
  386.   ot(";@ 0x00-0x3f: DA registers\n");
  387.   ot("c_pack_loop%s\n",ms?"":":");
  388.   ot("  ldr r1,[r0],#4\n");
  389.   ot("  subs r3,r3,#1\n");
  390.   ot("  str r1,[r5],#4\n");
  391.   ot("  bne c_pack_loop\n");
  392.   ot(";@ 0x40: PC\n");
  393.   ot("  ldr r0,[r4,#0x40] ;@ PC + Memory Base\n");
  394.   ot("  ldr r1,[r4,#0x60] ;@ Memory base\n");
  395.   ot("  sub r0,r0,r1\n");
  396.   ot("  str r0,[r5],#4\n");
  397.   ot(";@ 0x44: SR\n");
  398.   ot("  mov r0,r4\n");
  399.   ot("  bl CycloneGetSr\n");
  400.   ot("  strh r0,[r5],#2\n");
  401.   ot(";@ 0x46: IRQ level\n");
  402.   ot("  ldrb r0,[r4,#0x47]\n");
  403.   ot("  strb r0,[r5],#2\n");
  404.   ot(";@ 0x48: other SP\n");
  405.   ot("  ldr r0,[r4,#0x48]\n");
  406.   ot("  str r0,[r5],#4\n");
  407.   ot(";@ 0x4c: CPU state flags\n");
  408.   ot("  ldr r0,[r4,#0x58]\n");
  409.   ot("  str r0,[r5],#4\n");
  410.   ot("  ldmfd sp!,{r4,r5,pc}\n");
  411.   ot("\n");
  412.  
  413.   // --------------
  414.   ot("CycloneUnpack%s\n", ms?"":":");
  415.   ot("  stmfd sp!,{r5,r7,lr}\n");
  416.   ot("  mov r7,r0\n");
  417.   ot("  movs r5,r1\n");
  418.   ot("  beq c_unpack_do_pc\n");
  419.   ot("  mov r3,#16\n");
  420.   ot(";@ 0x00-0x3f: DA registers\n");
  421.   ot("c_unpack_loop%s\n",ms?"":":");
  422.   ot("  ldr r1,[r5],#4\n");
  423.   ot("  subs r3,r3,#1\n");
  424.   ot("  str r1,[r0],#4\n");
  425.   ot("  bne c_unpack_loop\n");
  426.   ot(";@ 0x40: PC\n");
  427.   ot("  ldr r0,[r5],#4 ;@ PC\n");
  428.   ot("  str r0,[r7,#0x40] ;@ handle later\n");
  429.   ot(";@ 0x44: SR\n");
  430.   ot("  ldrh r1,[r5],#2\n");
  431.   ot("  mov r0,r7\n");
  432.   ot("  bl CycloneSetSr\n");
  433.   ot(";@ 0x46: IRQ level\n");
  434.   ot("  ldrb r0,[r5],#2\n");
  435.   ot("  strb r0,[r7,#0x47]\n");
  436.   ot(";@ 0x48: other SP\n");
  437.   ot("  ldr r0,[r5],#4\n");
  438.   ot("  str r0,[r7,#0x48]\n");
  439.   ot(";@ 0x4c: CPU state flags\n");
  440.   ot("  ldr r0,[r5],#4\n");
  441.   ot("  str r0,[r7,#0x58]\n");
  442.   ot("c_unpack_do_pc%s\n",ms?"":":");
  443.   ot("  ldr r0,[r7,#0x40] ;@ unbased PC\n");
  444. #if USE_CHECKPC_CALLBACK
  445.   ot("  mov r1,#0\n");
  446.   ot("  str r1,[r7,#0x60] ;@ Memory base\n");
  447.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  448.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  449.  #else
  450.   ot("  mov lr,pc\n");
  451.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  452.  #endif
  453. #else
  454.   ot("  ldr r1,[r7,#0x60] ;@ Memory base\n");
  455.   ot("  add r0,r0,r1 ;@ r0 = Memory Base + New PC\n");
  456. #endif
  457.   ot("  str r0,[r7,#0x40] ;@ PC + Memory Base\n");
  458.   ot("  ldmfd sp!,{r5,r7,pc}\n");
  459.   ot("\n");
  460.  
  461.   // --------------
  462.   ot("CycloneFlushIrq%s\n", ms?"":":");
  463.   ot("  ldr r1,[r0,#0x44]  ;@ Get SR high T_S__III and irq level\n");
  464.   ot("  mov r2,r1,lsr #24 ;@ Get IRQ level\n"); // same as  ldrb r0,[r7,#0x47]
  465.   ot("  cmp r2,#6 ;@ irq>6 ?\n");
  466.   ot("  andle r1,r1,#7 ;@ Get interrupt mask\n");
  467.   ot("  cmple r2,r1 ;@ irq<=6: Is irq<=mask ?\n");
  468.   ot("  movle r0,#0\n");
  469.   ot("  bxle lr ;@ no ints\n");
  470.   ot("\n");
  471.   ot("  stmdb sp!,{r4,r5,r7,r8,r10,r11,lr}\n");
  472.   ot("  mov r7,r0\n");
  473.   ot("  mov r0,r2\n");
  474.   ot("  ldrb r10,[r7,#0x46]  ;@ r10 = Flags (NZCV)\n");
  475.   ot("  mov r5,#0\n");
  476.   ot("  ldr r4,[r7,#0x40]    ;@ r4 = Current PC + Memory Base\n");
  477.   ot("  mov r10,r10,lsl #28  ;@ r10 = Flags 0xf0000000, cpsr format\n");
  478.   ot("  adr r2,CycloneFlushIrqEnd\n");
  479.   ot("  str r2,[r7,#0x98]  ;@ set custom CycloneEnd\n");
  480.   ot("  b CycloneDoInterrupt\n");
  481.   ot("\n");
  482.   ot("CycloneFlushIrqEnd%s\n", ms?"":":");
  483.   ot("  rsb r0,r5,#0\n");
  484.   ot("  str r4,[r7,#0x40]   ;@ Save Current PC + Memory Base\n");
  485.   ot("  strb r10,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  486.   ot("  ldmia sp!,{r4,r5,r7,r8,r10,r11,lr}\n");
  487.   ot("  bx lr\n");
  488.   ot("\n");
  489.   ot("\n");
  490.  
  491.   // --------------
  492.   ot("CycloneSetRealTAS%s\n", ms?"":":");
  493. #if (CYCLONE_FOR_GENESIS == 2)
  494.   ot("  ldr r12,=CycloneJumpTab\n");
  495.   ot("  tst r0,r0\n");
  496.   ot("  add r12,r12,#0x4a00*4\n");
  497.   ot("  add r12,r12,#0x00d0*4\n");
  498.   ot("  beq setrtas_off\n");
  499.   ChangeTAS(1);
  500.   ot("  bx lr\n");
  501.   ot("setrtas_off%s\n",ms?"":":");
  502.   ChangeTAS(0);
  503.   ot("  bx lr\n");
  504.   ltorg();
  505. #else
  506.   ot("  bx lr\n");
  507. #endif
  508.   ot("\n");
  509.  
  510.   // --------------
  511.   ot(";@ DoInterrupt - r0=IRQ level\n");
  512.   ot("CycloneDoInterruptGoBack%s\n", ms?"":":");
  513.   ot("  sub r4,r4,#2\n");
  514.   ot("CycloneDoInterrupt%s\n", ms?"":":");
  515.   ot("  bic r8,r8,#0xff000000\n");
  516.   ot("  orr r8,r8,r0,lsl #29 ;@ abuse r8\n");
  517.  
  518.   // Steps are from "M68000 8-/16-/32-BIT MICROPROCESSORS USER'S MANUAL", p. 6-4
  519.   // but their order is based on http://pasti.fxatari.com/68kdocs/68kPrefetch.html
  520.   // 1. Make a temporary copy of the status register and set the status register for exception processing.
  521.   ot("  ldr r2,[r7,#0x58] ;@ state flags\n");
  522.   ot("  and r0,r0,#7\n");
  523.   ot("  orr r3,r0,#0x20 ;@ Supervisor mode + IRQ level\n");
  524.   ot("  bic r2,r2,#3 ;@ clear stopped and trace states\n");
  525. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  526.   ot("  orr r2,r2,#4 ;@ set activity bit: 'not processing instruction'\n");
  527. #endif
  528.   ot("  str r2,[r7,#0x58]\n");
  529.   ot("  ldrb r6,[r7,#0x44] ;@ Get old SR high, abuse r6\n");
  530.   ot("  strb r3,[r7,#0x44] ;@ Put new SR high\n");
  531.   ot("\n");
  532.  
  533.   // 3. Save the current processor context.
  534.   ot("  ldr r1,[r7,#0x60] ;@ Get Memory base\n");
  535.   ot("  ldr r11,[r7,#0x3c] ;@ Get A7\n");
  536.   ot("  tst r6,#0x20\n");
  537.   ot(";@ get our SP:\n");
  538.   ot("  ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n");
  539.   ot("  streq r11,[r7,#0x48]\n");
  540.   ot("  moveq r11,r2\n");
  541.   ot(";@ Push old PC onto stack\n");
  542.   ot("  sub r0,r11,#4 ;@ Predecremented A7\n");
  543.   ot("  sub r1,r4,r1 ;@ r1 = Old PC\n");
  544.   MemHandler(1,2);
  545.   ot(";@ Push old SR:\n");
  546.   ot("  ldr r0,[r7,#0x4c]   ;@ X bit\n");
  547.   ot("  mov r1,r10,lsr #28  ;@ ____NZCV\n");
  548.   ot("  eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n");
  549.   ot("  tst r2,#1           ;@ 1 if C!=V\n");
  550.   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");
  551.   ot("  and r0,r0,#0x20000000\n");
  552.   ot("  orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n");
  553.   ot("  orr r1,r1,r6,lsl #8 ;@ Include old SR high\n");
  554.   ot("  sub r0,r11,#6 ;@ Predecrement A7\n");
  555.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  556.   MemHandler(1,1,0,0); // already checked for address error by prev MemHandler
  557.   ot("\n");
  558.  
  559.   // 2. Obtain the exception vector.
  560.   ot("  mov r11,r8,lsr #29\n");
  561.   ot("  mov r0,r11\n");
  562. #if USE_INT_ACK_CALLBACK
  563.   ot(";@ call IrqCallback if it is defined\n");
  564. #if INT_ACK_NEEDS_STUFF
  565.   ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  566.   ot("  mov r1,r10,lsr #28\n");
  567.   ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  568.   ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
  569. #endif
  570.   ot("  ldr r3,[r7,#0x8c] ;@ IrqCallback\n");
  571.   ot("  add lr,pc,#4*3\n");
  572.   ot("  tst r3,r3\n");
  573.   ot("  streqb r3,[r7,#0x47] ;@ just clear IRQ if there is no callback\n");
  574.   ot("  mvneq r0,#0 ;@ and simulate -1 return\n");
  575.   ot("  bxne r3\n");
  576. #if INT_ACK_CHANGES_CYCLES
  577.   ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  578. #endif
  579.   ot(";@ get IRQ vector address:\n");
  580.   ot("  cmn r0,#1 ;@ returned -1?\n");
  581.   ot("  addeq r0,r11,#0x18 ;@ use autovector then\n");
  582.   ot("  cmn r0,#2 ;@ returned -2?\n"); // should be safe as above add should never result in -2
  583.   ot("  moveq r0,#0x18 ;@ use spurious interrupt then\n");
  584. #else // !USE_INT_ACK_CALLBACK
  585.   ot(";@ Clear irq:\n");
  586.   ot("  mov r2,#0\n");
  587.   ot("  strb r2,[r7,#0x47]\n");
  588.   ot("  add r0,r0,#0x18 ;@ use autovector\n");
  589. #endif
  590.   ot("  mov r0,r0,lsl #2 ;@ get vector address\n");
  591.   ot("\n");
  592.   ot("  ldr r11,[r7,#0x60] ;@ Get Memory base\n");
  593.   ot(";@ Read IRQ Vector:\n");
  594.   MemHandler(0,2,0,0);
  595.   ot("  tst r0,r0 ;@ uninitialized int vector?\n");
  596.   ot("  moveq r0,#0x3c\n");
  597.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  598.   ot("  bleq %sread32 ;@ Call read32(r0) handler\n", MEMHANDLERS_DIRECT_PREFIX);
  599.  #else
  600.   ot("  moveq lr,pc\n");
  601.   ot("  ldreq pc,[r7,#0x70] ;@ Call read32(r0) handler\n");
  602.  #endif
  603. #if USE_CHECKPC_CALLBACK
  604.   ot("  add lr,pc,#4\n");
  605.   ot("  add r0,r0,r11 ;@ r0 = Memory Base + New PC\n");
  606.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  607.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  608.  #else
  609.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  610.  #endif
  611.  #if EMULATE_ADDRESS_ERRORS_JUMP
  612.   ot("  mov r4,r0\n");
  613.  #else
  614.   ot("  bic r4,r0,#1\n");
  615.  #endif
  616. #else
  617.   ot("  add r4,r0,r11 ;@ r4 = Memory Base + New PC\n");
  618.  #if EMULATE_ADDRESS_ERRORS_JUMP
  619.   ot("  bic r4,r4,#1\n");
  620.  #endif
  621. #endif
  622.   ot("\n");
  623.  
  624.   // 4. Obtain a new context and resume instruction processing.
  625.   // note: the obtain part was already done in previous steps
  626. #if EMULATE_ADDRESS_ERRORS_JUMP
  627.   ot("  tst r4,#1\n");
  628.   ot("  bne ExceptionAddressError_r_prg_r4\n");
  629. #endif
  630.   ot("  ldr r6,[r7,#0x54]\n");
  631.   ot("  ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
  632.   ot("  subs r5,r5,#44 ;@ Subtract cycles\n");
  633.   ot("  ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  634.   ot("  b CycloneEnd\n");
  635.   ot("\n");
  636.  
  637.   // --------------
  638.   // trashes all temp regs
  639.   ot("Exception%s\n", ms?"":":");
  640.   ot("  ;@ Cause an Exception - Vector number in r0\n");
  641.   ot("  mov r11,lr ;@ Preserve ARM return address\n");
  642.   ot("  bic r8,r8,#0xff000000\n");
  643.   ot("  orr r8,r8,r0,lsl #24 ;@ abuse r8\n");
  644.  
  645.   // 1. Make a temporary copy of the status register and set the status register for exception processing.
  646.   ot("  ldr r6,[r7,#0x44] ;@ Get old SR high, abuse r6\n");
  647.   ot("  ldr r2,[r7,#0x58] ;@ state flags\n");
  648.   ot("  and r3,r6,#0x27 ;@ clear trace and unused flags\n");
  649.   ot("  orr r3,r3,#0x20 ;@ set supervisor mode\n");
  650.   ot("  bic r2,r2,#3 ;@ clear stopped and trace states\n");
  651.   ot("  str r2,[r7,#0x58]\n");
  652.   ot("  strb r3,[r7,#0x44] ;@ Put new SR high\n");
  653.   ot("\n");
  654.  
  655.   // 3. Save the current processor context.
  656.   ot("  ldr r0,[r7,#0x3c] ;@ Get A7\n");
  657.   ot("  tst r6,#0x20\n");
  658.   ot(";@ get our SP:\n");
  659.   ot("  ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n");
  660.   ot("  streq r0,[r7,#0x48]\n");
  661.   ot("  moveq r0,r2\n");
  662.   ot(";@ Push old PC onto stack\n");
  663.   ot("  ldr r1,[r7,#0x60] ;@ Get Memory base\n");
  664.   ot("  sub r0,r0,#4 ;@ Predecremented A7\n");
  665.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  666.   ot("  sub r1,r4,r1 ;@ r1 = Old PC\n");
  667.   MemHandler(1,2);
  668.   ot(";@ Push old SR:\n");
  669.   ot("  ldr r0,[r7,#0x4c]   ;@ X bit\n");
  670.   ot("  mov r1,r10,lsr #28  ;@ ____NZCV\n");
  671.   ot("  eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n");
  672.   ot("  tst r2,#1           ;@ 1 if C!=V\n");
  673.   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");
  674.   ot("  and r0,r0,#0x20000000\n");
  675.   ot("  orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n");
  676.   ot("  ldr r0,[r7,#0x3c] ;@ A7\n");
  677.   ot("  orr r1,r1,r6,lsl #8 ;@ Include SR high\n");
  678.   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
  679.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  680.   MemHandler(1,1,0,0);
  681.   ot("\n");
  682.  
  683.   // 2. Obtain the exception vector
  684.   ot(";@ Read Exception Vector:\n");
  685.   ot("  mov r0,r8,lsr #24\n");
  686.   ot("  mov r0,r0,lsl #2\n");
  687.   MemHandler(0,2,0,0);
  688.   ot("  ldr r3,[r7,#0x60] ;@ Get Memory base\n");
  689. #if USE_CHECKPC_CALLBACK
  690.   ot("  add lr,pc,#4\n");
  691.   ot("  add r0,r0,r3 ;@ r0 = Memory Base + New PC\n");
  692.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  693.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  694.  #else
  695.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  696.  #endif
  697.  #if EMULATE_ADDRESS_ERRORS_JUMP
  698.   ot("  mov r4,r0\n");
  699.  #else
  700.   ot("  bic r4,r0,#1\n");
  701.  #endif
  702. #else
  703.   ot("  add r4,r0,r3 ;@ r4 = Memory Base + New PC\n");
  704.  #if EMULATE_ADDRESS_ERRORS_JUMP
  705.   ot("  bic r4,r4,#1\n");
  706.  #endif
  707. #endif
  708.   ot("\n");
  709.  
  710.   // 4. Resume execution.
  711. #if EMULATE_ADDRESS_ERRORS_JUMP
  712.   ot("  tst r4,#1\n");
  713.   ot("  bne ExceptionAddressError_r_prg_r4\n");
  714. #endif
  715.   ot("  ldr r6,[r7,#0x54]\n");
  716.   ot("  bx r11 ;@ Return\n");
  717.   ot("\n");
  718.  
  719.   // --------------
  720. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  721.   // first some wrappers: I see no point inlining this code,
  722.   // as it will be executed in really rare cases.
  723.   AddressErrorWrapper('r', "data", 0x11);
  724.   AddressErrorWrapper('r', "prg",  0x12);
  725.   AddressErrorWrapper('w', "data", 0x01);
  726.   // there are no program writes
  727.   // cpu space is only for bus errors?
  728.   ot("ExceptionAddressError_r_prg_r4%s\n", ms?"":":");
  729.   ot("  ldr r1,[r7,#0x44]\n");
  730.   ot("  ldr r3,[r7,#0x60] ;@ Get Memory base\n");
  731.   ot("  mov r6,#0x12\n");
  732.   ot("  sub r11,r4,r3\n");
  733.   ot("  tst r1,#0x20\n");
  734.   ot("  orrne r6,r6,#4\n");
  735.   ot("\n");
  736.  
  737.   ot("ExceptionAddressError%s\n", ms?"":":");
  738.   ot(";@ r6 - info word (without instruction/not bit), r11 - faulting address\n");
  739.  
  740.   // 1. Make a temporary copy of the status register and set the status register for exception processing.
  741.   ot("  ldrb r0,[r7,#0x44] ;@ Get old SR high\n");
  742.   ot("  ldr r2,[r7,#0x58] ;@ state flags\n");
  743.   ot("  and r3,r0,#0x27 ;@ clear trace and unused flags\n");
  744.   ot("  orr r3,r3,#0x20 ;@ set supervisor mode\n");
  745.   ot("  strb r3,[r7,#0x44] ;@ Put new SR high\n");
  746.   ot("  bic r2,r2,#3 ;@ clear stopped and trace states\n");
  747.   ot("  tst r2,#4\n");
  748.   ot("  orrne r6,r6,#8 ;@ complete info word\n");
  749.   ot("  orr r2,r2,#4 ;@ set activity bit: 'not processing instruction'\n");
  750. #if EMULATE_HALT
  751.   ot("  tst r2,#8\n");
  752.   ot("  orrne r2,r2,#0x10 ;@ HALT\n");
  753.   ot("  orr r2,r2,#8 ;@ processing address error\n");
  754.   ot("  str r2,[r7,#0x58]\n");
  755.   ot("  movne r5,#0\n");
  756.   ot("  bne CycloneEndNoBack ;@ bye bye\n");
  757. #else
  758.   ot("  str r2,[r7,#0x58]\n");
  759. #endif
  760.   ot("  and r10,r10,#0xf0000000\n");
  761.   ot("  orr r10,r10,r0,lsl #4 ;@ some preparations for SR push\n");
  762.   ot("\n");
  763.  
  764.   // 3. Save the current processor context + additional information.
  765.   ot("  ldr r0,[r7,#0x3c] ;@ Get A7\n");
  766.   ot("  tst r10,#0x200\n");
  767.   ot(";@ get our SP:\n");
  768.   ot("  ldreq r2,[r7,#0x48] ;@ ...or OSP as our stack pointer\n");
  769.   ot("  streq r0,[r7,#0x48]\n");
  770.   ot("  moveq r0,r2\n");
  771.   // PC
  772.   ot(";@ Push old PC onto stack\n");
  773.   ot("  ldr r1,[r7,#0x60] ;@ Get Memory base\n");
  774.   ot("  sub r0,r0,#4 ;@ Predecremented A7\n");
  775.   ot("  sub r1,r4,r1 ;@ r1 = Old PC\n");
  776.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  777.   MemHandler(1,2,0,EMULATE_HALT);
  778.   // SR
  779.   ot(";@ Push old SR:\n");
  780.   ot("  ldr r0,[r7,#0x4c]   ;@ X bit\n");
  781.   ot("  mov r1,r10,ror #28  ;@ ____NZCV\n");
  782.   ot("  eor r2,r1,r1,ror #1 ;@ Bit 0=C^V\n");
  783.   ot("  tst r2,#1           ;@ 1 if C!=V\n");
  784.   ot("  eorne r1,r1,#3      ;@ ____NZVC\n");
  785.   ot("  and r0,r0,#0x20000000\n");
  786.   ot("  orr r1,r1,r0,lsr #25 ;@ ___XNZVC\n");
  787.   ot("  ldr r0,[r7,#0x3c] ;@ A7\n");
  788.   ot("  and r10,r10,#0xf0000000\n");
  789.   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
  790.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  791.   MemHandler(1,1,0,0);
  792.   // IR (instruction register)
  793.   ot(";@ Push IR:\n");
  794.   ot("  ldr r0,[r7,#0x3c] ;@ A7\n");
  795.   ot("  mov r1,r8\n");
  796.   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
  797.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  798.   MemHandler(1,1,0,0);
  799.   // access address
  800.   ot(";@ Push address:\n");
  801.   ot("  ldr r0,[r7,#0x3c] ;@ A7\n");
  802.   ot("  mov r1,r11\n");
  803.   ot("  sub r0,r0,#4 ;@ Predecrement A7\n");
  804.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  805.   MemHandler(1,2,0,0);
  806.   // information word
  807.   ot(";@ Push info word:\n");
  808.   ot("  ldr r0,[r7,#0x3c] ;@ A7\n");
  809.   ot("  mov r1,r6\n");
  810.   ot("  sub r0,r0,#2 ;@ Predecrement A7\n");
  811.   ot("  str r0,[r7,#0x3c] ;@ Save A7\n");
  812.   MemHandler(1,1,0,0);
  813.   ot("\n");
  814.  
  815.   // 2. Obtain the exception vector
  816.   ot(";@ Read Exception Vector:\n");
  817.   ot("  mov r0,#0x0c\n");
  818.   MemHandler(0,2,0,0);
  819.   ot("  ldr r3,[r7,#0x60] ;@ Get Memory base\n");
  820. #if USE_CHECKPC_CALLBACK
  821.   ot("  add lr,pc,#4\n");
  822.   ot("  add r0,r0,r3 ;@ r0 = Memory Base + New PC\n");
  823.  #ifdef MEMHANDLERS_DIRECT_PREFIX
  824.   ot("  bl %scheckpc ;@ Call checkpc()\n", MEMHANDLERS_DIRECT_PREFIX);
  825.  #else
  826.   ot("  ldr pc,[r7,#0x64] ;@ Call checkpc()\n");
  827.  #endif
  828.   ot("  mov r4,r0\n");
  829. #else
  830.   ot("  add r4,r0,r3 ;@ r4 = Memory Base + New PC\n");
  831. #endif
  832.   ot("\n");
  833.  
  834. #if EMULATE_ADDRESS_ERRORS_JUMP && EMULATE_HALT
  835.   ot("  tst r4,#1\n");
  836.   ot("  bne ExceptionAddressError_r_prg_r4\n");
  837. #else
  838.   ot("  bic r4,r4,#1\n");
  839. #endif
  840.  
  841.   // 4. Resume execution.
  842.   ot("  ldr r6,[r7,#0x54]\n");
  843.   ot("  ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
  844.   ot("  subs r5,r5,#50 ;@ Subtract cycles\n");
  845.   ot("  ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  846.   ot("  b CycloneEnd\n");
  847.   ot("\n");
  848. #endif
  849.  
  850.   // --------------
  851. #if EMULATE_TRACE
  852.   // expects srh and irq level in r1, next opcode already fetched to r8
  853.   ot("CycloneDoTraceWithChecks%s\n", ms?"":":");
  854.   ot("  ldr r0,[r7,#0x58]\n");
  855.   ot("  cmp r5,#0\n");
  856.   ot("  orr r0,r0,#2 ;@ go to trace mode\n");
  857.   ot("  str r0,[r7,#0x58]\n");
  858.   ot("  blt CycloneEnd\n"); // should take care of situation where we come here when already tracing
  859.   ot(";@ CheckInterrupt:\n");
  860.   ot("  movs r0,r1,lsr #24 ;@ Get IRQ level\n");
  861.   ot("  beq CycloneDoTrace\n");
  862.   ot("  cmp r0,#6 ;@ irq>6 ?\n");
  863.   ot("  andle r1,r1,#7 ;@ Get interrupt mask\n");
  864.   ot("  cmple r0,r1 ;@ irq<=6: Is irq<=mask ?\n");
  865.   ot("  bgt CycloneDoInterruptGoBack\n");
  866.   ot("\n");
  867.  
  868.   // expects next opcode to be already fetched to r8
  869.   ot("CycloneDoTrace%s\n", ms?"":":");
  870.   ot("  str r5,[r7,#0x9c] ;@ save cycles\n");
  871.   ot("  ldr r1,[r7,#0x98]\n");
  872.   ot("  mov r5,#0\n");
  873.   ot("  str r1,[r7,#0xa0]\n");
  874.   ot("  adr r0,TraceEnd\n");
  875.   ot("  str r0,[r7,#0x98] ;@ store TraceEnd as CycloneEnd hadler\n");
  876.   ot("  ldr pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  877.   ot("\n");
  878.  
  879.   ot("TraceEnd%s\n", ms?"":":");
  880.   ot("  ldr r2,[r7,#0x58]\n");
  881.   ot("  ldr r0,[r7,#0x9c] ;@ restore cycles\n");
  882.   ot("  ldr r1,[r7,#0xa0] ;@ old CycloneEnd handler\n");
  883.   ot("  mov r10,r10,lsl #28\n");
  884.   ot("  add r5,r0,r5\n");
  885.   ot("  str r1,[r7,#0x98]\n");
  886.   ot(";@ still tracing?\n"); // exception might have happend
  887.   ot("  tst r2,#2\n");
  888.   ot("  beq TraceDisabled\n");
  889.   ot(";@ trace exception\n");
  890. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  891.   ot("  ldr r1,[r7,#0x58]\n");
  892.   ot("  mov r0,#9\n");
  893.   ot("  orr r1,r1,#4 ;@ set activity bit: 'not processing instruction'\n");
  894.   ot("  str r1,[r7,#0x58]\n");
  895. #else
  896.   ot("  mov r0,#9\n");
  897. #endif
  898.   ot("  bl Exception\n");
  899.   ot("  ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
  900.   ot("  subs r5,r5,#34 ;@ Subtract cycles\n");
  901.   ot("  ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  902.   ot("  b CycloneEnd\n");
  903.   ot("\n");
  904.   ot("TraceDisabled%s\n", ms?"":":");
  905.   ot("  ldrh r8,[r4],#2 ;@ Fetch next opcode\n");
  906.   ot("  cmp r5,#0\n");
  907.   ot("  ldrge pc,[r6,r8,asl #2] ;@ Jump to opcode handler\n");
  908.   ot("  b CycloneEnd\n");
  909.   ot("\n");
  910. #endif
  911. }
  912.  
  913. // ---------------------------------------------------------------------------
  914. // Call Read(r0), Write(r0,r1) or Fetch(r0)
  915. // Trashes r0-r3,r12,lr
  916. int MemHandler(int type,int size,int addrreg,int need_addrerr_check)
  917. {
  918.   int func=0x68+type*0xc+(size<<2); // Find correct offset
  919.   char what[32];
  920.  
  921. #if MEMHANDLERS_NEED_FLAGS
  922.   ot("  mov r3,r10,lsr #28\n");
  923.   ot("  strb r3,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  924. #endif
  925.   FlushPC();
  926.  
  927. #if (MEMHANDLERS_ADDR_MASK & 0xff000000)
  928.   ot("  bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0xff000000);
  929.   addrreg=0;
  930. #endif
  931. #if (MEMHANDLERS_ADDR_MASK & 0x00ff0000)
  932.   ot("  bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x00ff0000);
  933.   addrreg=0;
  934. #endif
  935. #if (MEMHANDLERS_ADDR_MASK & 0x0000ff00)
  936.   ot("  bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x0000ff00);
  937.   addrreg=0;
  938. #endif
  939. #if (MEMHANDLERS_ADDR_MASK & 0x000000ff)
  940.   ot("  bic r0,r%i,#0x%08x\n", addrreg, MEMHANDLERS_ADDR_MASK & 0x000000ff);
  941.   addrreg=0;
  942. #endif
  943.  
  944. #if EMULATE_ADDRESS_ERRORS_IO
  945.   if (size > 0 && need_addrerr_check)
  946.   {
  947.     ot("  add lr,pc,#4*%i\n", addrreg==0?2:3); // helps to prevent interlocks
  948.     if (addrreg != 0) ot("  mov r0,r%i\n", addrreg);
  949.     ot("  tst r0,#1 ;@ address error?\n");
  950.     switch (type) {
  951.       case 0: ot("  bne ExceptionAddressError_r_data\n"); break;
  952.       case 1: ot("  bne ExceptionAddressError_w_data\n"); break;
  953.       case 2: ot("  bne ExceptionAddressError_r_prg\n"); break;
  954.     }
  955.   }
  956.   else
  957. #else
  958.   (void)need_addrerr_check;
  959. #endif
  960.  
  961.   sprintf(what, "%s%d", type==0 ? "read" : (type==1 ? "write" : "fetch"), 8<<size);
  962. #ifdef MEMHANDLERS_DIRECT_PREFIX
  963.   if (addrreg != 0)
  964.     ot("  mov r0,r%i\n", addrreg);
  965.   ot("  bl %s%s ;@ Call ", MEMHANDLERS_DIRECT_PREFIX, what);
  966.   (void)func; // avoid warning
  967. #else
  968.   if (addrreg != 0)
  969.   {
  970.     ot("  add lr,pc,#4\n");
  971.     ot("  mov r0,r%i\n", addrreg);
  972.   }
  973.   else
  974.     ot("  mov lr,pc\n");
  975.   ot("  ldr pc,[r7,#0x%x] ;@ Call ",func);
  976. #endif
  977.  
  978.   // Document what we are calling:
  979.   if (type==1) ot("%s(r0,r1)",what);
  980.   else         ot("%s(r0)",   what);
  981.   ot(" handler\n");
  982.  
  983. #if MEMHANDLERS_CHANGE_FLAGS
  984.   ot("  ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n");
  985.   ot("  mov r10,r10,lsl #28\n");
  986. #endif
  987. #if MEMHANDLERS_CHANGE_PC
  988.   ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");
  989. #endif
  990.  
  991.   return 0;
  992. }
  993.  
  994. static void PrintOpcodes()
  995. {
  996.   int op=0;
  997.  
  998.   printf("Creating Opcodes: [");
  999.  
  1000.   ot(";@ ---------------------------- Opcodes ---------------------------\n");
  1001.  
  1002.   // Emit null opcode:
  1003.   ot("Op____%s ;@ Called if an opcode is not recognised\n", ms?"":":");
  1004. #if EMULATE_ADDRESS_ERRORS_JUMP || EMULATE_ADDRESS_ERRORS_IO
  1005.   ot("  ldr r1,[r7,#0x58]\n");
  1006.   ot("  sub r4,r4,#2\n");
  1007.   ot("  orr r1,r1,#4 ;@ set activity bit: 'not processing instruction'\n");
  1008.   ot("  str r1,[r7,#0x58]\n");
  1009. #else
  1010.   ot("  sub r4,r4,#2\n");
  1011. #endif
  1012. #if USE_UNRECOGNIZED_CALLBACK
  1013.   ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  1014.   ot("  mov r1,r10,lsr #28\n");
  1015.   ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  1016.   ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
  1017.   ot("  ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
  1018.   ot("  tst r11,r11\n");
  1019.   ot("  movne lr,pc\n");
  1020.   ot("  movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
  1021.   ot("  ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n");
  1022.   ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  1023.   ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");
  1024.   ot("  mov r10,r10,lsl #28\n");
  1025.   ot("  tst r0,r0\n");
  1026.   ot("  moveq r0,#4\n");
  1027.   ot("  bleq Exception\n");
  1028. #else
  1029.   ot("  mov r0,#4\n");
  1030.   ot("  bl Exception\n");
  1031. #endif
  1032.   ot("\n");
  1033.   Cycles=34;
  1034.   OpEnd();
  1035.  
  1036.   // Unrecognised a-line and f-line opcodes throw an exception:
  1037.   ot("Op__al%s ;@ Unrecognised a-line opcode\n", ms?"":":");
  1038.   ot("  sub r4,r4,#2\n");
  1039. #if USE_AFLINE_CALLBACK
  1040.   ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  1041.   ot("  mov r1,r10,lsr #28\n");
  1042.   ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  1043.   ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
  1044.   ot("  ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
  1045.   ot("  tst r11,r11\n");
  1046.   ot("  movne lr,pc\n");
  1047.   ot("  movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
  1048.   ot("  ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n");
  1049.   ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  1050.   ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");
  1051.   ot("  mov r10,r10,lsl #28\n");
  1052.   ot("  tst r0,r0\n");
  1053.   ot("  moveq r0,#0x0a\n");
  1054.   ot("  bleq Exception\n");
  1055. #else
  1056.   ot("  mov r0,#0x0a\n");
  1057.   ot("  bl Exception\n");
  1058. #endif
  1059.   ot("\n");
  1060.   Cycles=4;
  1061.   OpEnd();
  1062.  
  1063.   ot("Op__fl%s ;@ Unrecognised f-line opcode\n", ms?"":":");
  1064.   ot("  sub r4,r4,#2\n");
  1065. #if USE_AFLINE_CALLBACK
  1066.   ot("  str r4,[r7,#0x40] ;@ Save PC\n");
  1067.   ot("  mov r1,r10,lsr #28\n");
  1068.   ot("  strb r1,[r7,#0x46] ;@ Save Flags (NZCV)\n");
  1069.   ot("  str r5,[r7,#0x5c] ;@ Save Cycles\n");
  1070.   ot("  ldr r11,[r7,#0x94] ;@ UnrecognizedCallback\n");
  1071.   ot("  tst r11,r11\n");
  1072.   ot("  movne lr,pc\n");
  1073.   ot("  movne pc,r11 ;@ call UnrecognizedCallback if it is defined\n");
  1074.   ot("  ldrb r10,[r7,#0x46] ;@ r10 = Load Flags (NZCV)\n");
  1075.   ot("  ldr r5,[r7,#0x5c] ;@ Load Cycles\n");
  1076.   ot("  ldr r4,[r7,#0x40] ;@ Load PC\n");
  1077.   ot("  mov r10,r10,lsl #28\n");
  1078.   ot("  tst r0,r0\n");
  1079.   ot("  moveq r0,#0x0b\n");
  1080.   ot("  bleq Exception\n");
  1081. #else
  1082.   ot("  mov r0,#0x0b\n");
  1083.   ot("  bl Exception\n");
  1084. #endif
  1085.   ot("\n");
  1086.   Cycles=4;
  1087.   OpEnd();
  1088.  
  1089.  
  1090.   for (op=0;op<hot_opcode_count;op++)
  1091.     OpAny(hot_opcodes[op]);
  1092.  
  1093.   for (op=0;op<0x10000;op++)
  1094.   {
  1095.     if ((op&0xfff)==0) { printf("%x",op>>12); fflush(stdout); } // Update progress
  1096.  
  1097.     if (!is_op_hot(op))
  1098.       OpAny(op);
  1099.   }
  1100.  
  1101.   ot("\n");
  1102.  
  1103.   printf("]\n");
  1104. }
  1105.  
  1106. // helper
  1107. static void ott(const char *str, int par, const char *nl, int nlp, int counter, int size)
  1108. {
  1109.   switch(size) {
  1110.     case 0: if((counter&7)==0) ot(ms?"  dcb ":"  .byte ");  break;
  1111.     case 1: if((counter&7)==0) ot(ms?"  dcw ":"  .hword "); break;
  1112.     case 2: if((counter&7)==0) ot(ms?"  dcd ":"  .long ");  break;
  1113.   }
  1114.   ot(str, par);
  1115.   if((counter&7)==7) ot(nl,nlp); else ot(",");
  1116. }
  1117.  
  1118. static void PrintJumpTable()
  1119. {
  1120.   int i=0,op=0,len=0;
  1121.  
  1122.   ot(";@ -------------------------- Jump Table --------------------------\n");
  1123.  
  1124.   // space for decompressed table
  1125.   ot(ms?"  area |.data|, data\n":"  .data\n  .align 4\n\n");
  1126.  
  1127. #if COMPRESS_JUMPTABLE
  1128.     int handlers=0,reps=0,*indexes,ip,u,out;
  1129.     // use some weird compression on the jump table
  1130.     indexes=(int *)malloc(0x10000*4);
  1131.     if(!indexes) { printf("ERROR: out of memory\n"); exit(1); }
  1132.     len=0x10000;
  1133.  
  1134.     ot("CycloneJumpTab%s\n", ms?"":":");
  1135.     if(ms) {
  1136.       for(i = 0; i < 0xa000/8; i++)
  1137.         ot("  dcd 0,0,0,0,0,0,0,0\n");
  1138.     } else
  1139.       ot("  .rept 0x%x\n  .long 0,0,0,0,0,0,0,0\n  .endr\n", 0xa000/8);
  1140.  
  1141.     // hanlers live in "a-line" part of the table
  1142.     // first output nop,a-line,f-line handlers
  1143.     ot(ms?"  dcd Op____,Op__al,Op__fl,":"  .long Op____,Op__al,Op__fl,");
  1144.     handlers=3;
  1145.  
  1146.     for(i=0;i<len;i++)
  1147.     {
  1148.       op=CyJump[i];
  1149.  
  1150.       for(u=i-1; u>=0; u--) if(op == CyJump[u]) break; // already done with this op?
  1151.       if(u==-1 && op >= 0) {
  1152.         ott("Op%.4x",op," ;@ %.4x\n",i,handlers,2);
  1153.         indexes[op] = handlers;
  1154.         handlers++;
  1155.       }
  1156.     }
  1157.     if(handlers&7) {
  1158.       fseek(AsmFile, -1, SEEK_CUR); // remove last comma
  1159.       for(i = 8-(handlers&7); i > 0; i--)
  1160.         ot(",000000");
  1161.       ot("\n");
  1162.     }
  1163.     if(ms) {
  1164.       for(i = (0x4000-handlers)/8; i > 0; i--)
  1165.         ot("  dcd 0,0,0,0,0,0,0,0\n");
  1166.     } else {
  1167.       ot(ms?"":"  .rept 0x%x\n  .long 0,0,0,0,0,0,0,0\n  .endr\n", (0x4000-handlers)/8);
  1168.     }
  1169.     printf("total distinct hanlers: %i\n",handlers);
  1170.     // output data
  1171.     for(i=0,ip=0; i < 0xf000; i++, ip++) {
  1172.       op=CyJump[i];
  1173.       if(op == -2) {
  1174.         // it must skip a-line area, because we keep our data there
  1175.         ott("0x%.4x", handlers<<4, "\n",0,ip++,1);
  1176.         ott("0x%.4x", 0x1000, "\n",0,ip,1);
  1177.         i+=0xfff;
  1178.         continue;
  1179.       }
  1180.       for(reps=1; i < 0xf000; i++, reps++) if(op != CyJump[i+1]) break;
  1181.       if(op>=0) out=indexes[op]<<4; else out=0; // unrecognised
  1182.       if(reps <= 0xe || reps==0x10) {
  1183.         if(reps!=0x10) out|=reps; else out|=0xf; // 0xf means 0x10 (0xf appeared to be unused anyway)
  1184.         ott("0x%.4x", out, "\n",0,ip,1);
  1185.       } else {
  1186.         ott("0x%.4x", out, "\n",0,ip++,1);
  1187.         ott("0x%.4x", reps,"\n",0,ip,1);
  1188.       }
  1189.     }
  1190.     if(ip&1) ott("0x%.4x", 0, "\n",0,ip++,1);
  1191.     if(ip&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma
  1192.     if(ip&7) {
  1193.       for(i = 8-(ip&7); i > 0; i--)
  1194.         ot(",0x0000");
  1195.     }
  1196.     ot("\n");
  1197.     if(ms) {
  1198.       for(i = (0x2000-ip/2)/8+1; i > 0; i--)
  1199.         ot("  dcd 0,0,0,0,0,0,0,0\n");
  1200.     } else {
  1201.       ot("  .rept 0x%x\n  .long 0,0,0,0,0,0,0,0\n  .endr\n", (0x2000-ip/2)/8+1);
  1202.     }
  1203.     ot("\n");
  1204.     free(indexes);
  1205. #else
  1206.     ot("CycloneJumpTab%s\n", ms?"":":");
  1207.     len=0xfffe; // Hmmm, armasm 2.50.8684 messes up with a 0x10000 long jump table
  1208.                 // notaz: same thing with GNU as 2.9-psion-98r2 (reloc overflow)
  1209.                 // this is due to COFF objects using only 2 bytes for reloc count
  1210.  
  1211.     for (i=0;i<len;i++)
  1212.     {
  1213.       op=CyJump[i];
  1214.  
  1215.            if(op>=0)  ott("Op%.4x",op," ;@ %.4x\n",i-7,i,2);
  1216.       else if(op==-2) ott("Op__al",0, " ;@ %.4x\n",i-7,i,2);
  1217.       else if(op==-3) ott("Op__fl",0, " ;@ %.4x\n",i-7,i,2);
  1218.       else            ott("Op____",0, " ;@ %.4x\n",i-7,i,2);
  1219.     }
  1220.     if(i&7) fseek(AsmFile, -1, SEEK_CUR); // remove last comma
  1221.  
  1222.     ot("\n");
  1223.     ot(";@ notaz: we don't want to crash if we run into those 2 missing opcodes\n");
  1224.     ot(";@ so we leave this pattern to patch it later\n");
  1225.     ot("%s 0x78563412\n", ms?"  dcd":"  .long");
  1226.     ot("%s 0x56341290\n", ms?"  dcd":"  .long");
  1227. #endif
  1228. }
  1229.  
  1230. static int CycloneMake()
  1231. {
  1232.   int i;
  1233.   const char *name="Cyclone.s";
  1234.   const char *globl=ms?"export":".global";
  1235.  
  1236.   // Open the assembly file
  1237.   if (ms) name="Cyclone.asm";
  1238.   AsmFile=fopen(name,"wt"); if (AsmFile==NULL) return 1;
  1239.  
  1240.   printf("Making %s...\n",name);
  1241.  
  1242.   ot("\n;@ Cyclone 68000 Emulator v%x.%.3x - Assembler Output\n\n",CycloneVer>>12,CycloneVer&0xfff);
  1243.  
  1244.   ot(";@ Copyright (c) 2004,2011 FinalDave (emudave (at) gmail.com)\n");
  1245.   ot(";@ Copyright (c) 2005-2011 Gražvydas \"notaz\" Ignotas (notasas (at) gmail.com)\n\n");
  1246.  
  1247.   ot(";@ This code is licensed under the GNU General Public License version 2.0 and the MAME License.\n");
  1248.   ot(";@ You can choose the license that has the most advantages for you.\n\n");
  1249.   ot(";@ SVN repository can be found at http://code.google.com/p/cyclone68000/\n\n");
  1250.  
  1251.   CyJump=(int *)malloc(0x40000); if (CyJump==NULL) return 1;
  1252.   memset(CyJump,0xff,0x40000); // Init to -1
  1253.   for(i=0xa000; i<0xb000;  i++) CyJump[i] = -2; // a-line emulation
  1254.   for(i=0xf000; i<0x10000; i++) CyJump[i] = -3; // f-line emulation
  1255.  
  1256.   ot(ms?"  area |.text|, code\n":"  .text\n  .align 4\n\n");
  1257.   ot("  %s CycloneInit\n",globl);
  1258.   ot("  %s CycloneReset\n",globl);
  1259.   ot("  %s CycloneRun\n",globl);
  1260.   ot("  %s CycloneSetSr\n",globl);
  1261.   ot("  %s CycloneGetSr\n",globl);
  1262.   ot("  %s CycloneFlushIrq\n",globl);
  1263.   ot("  %s CyclonePack\n",globl);
  1264.   ot("  %s CycloneUnpack\n",globl);
  1265.   ot("  %s CycloneVer\n",globl);
  1266. #if (CYCLONE_FOR_GENESIS == 2)
  1267.   ot("  %s CycloneSetRealTAS\n",globl);
  1268.   ot("  %s CycloneDoInterrupt\n",globl);
  1269.   ot("  %s CycloneDoTrace\n",globl);
  1270.   ot("  %s CycloneJumpTab\n",globl);
  1271.   ot("  %s Op____\n",globl);
  1272.   ot("  %s Op6001\n",globl);
  1273.   ot("  %s Op6601\n",globl);
  1274.   ot("  %s Op6701\n",globl);
  1275. #endif
  1276.   ot("\n");
  1277.   ot(ms?"CycloneVer dcd 0x":"CycloneVer: .long 0x");
  1278.   ot("%.4x\n",CycloneVer);
  1279.   ot("\n");
  1280.  
  1281.   PrintFramework();
  1282.   arm_op_count = 0;
  1283.   PrintOpcodes();
  1284.   printf("~%i ARM instructions used for opcode handlers\n", arm_op_count);
  1285.   PrintJumpTable();
  1286.  
  1287.   if (ms) ot("  END\n");
  1288.  
  1289.   ot("\n\n;@ vim:filetype=armasm\n");
  1290.  
  1291.   fclose(AsmFile); AsmFile=NULL;
  1292.  
  1293. #if 0
  1294.   printf("Assembling...\n");
  1295.   // Assemble the file
  1296.   if (ms) system("armasm Cyclone.asm");
  1297.   else    system("as -o Cyclone.o Cyclone.s");
  1298.   printf("Done!\n\n");
  1299. #endif
  1300.  
  1301.   free(CyJump);
  1302.   return 0;
  1303. }
  1304.  
  1305. int main()
  1306. {
  1307.   printf("\n  Cyclone 68000 Emulator v%x.%.3x - Core Creator\n\n",CycloneVer>>12,CycloneVer&0xfff);
  1308.  
  1309.   // Make GAS or ARMASM version
  1310.   CycloneMake();
  1311.   return 0;
  1312. }
  1313.  
  1314.