OpBranch.cpp 12 KB

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