compiler.c 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904
  1. /*
  2. * SSP1601 to ARM recompiler
  3. * (C) notaz, 2008,2009,2010
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #include "../../pico_int.h"
  9. #include "../../../cpu/drc/cmn.h"
  10. #include "compiler.h"
  11. // FIXME: asm has these hardcoded
  12. #define SSP_BLOCKTAB_ENTS (0x5090/2)
  13. #define SSP_BLOCKTAB_IRAM_ONE (0x800/2) // table entries
  14. #define SSP_BLOCKTAB_IRAM_ENTS (15*SSP_BLOCKTAB_IRAM_ONE)
  15. static u32 **ssp_block_table; // [0x5090/2];
  16. static u32 **ssp_block_table_iram; // [15][0x800/2];
  17. static u32 *tcache_ptr = NULL;
  18. static int nblocks = 0;
  19. static int n_in_ops = 0;
  20. extern ssp1601_t *ssp;
  21. #define rPC ssp->gr[SSP_PC].h
  22. #define rPMC ssp->gr[SSP_PMC]
  23. #define SSP_FLAG_Z (1<<0xd)
  24. #define SSP_FLAG_N (1<<0xf)
  25. #ifndef __arm__
  26. //#define DUMP_BLOCK 0x0c9a
  27. void ssp_drc_next(void){}
  28. void ssp_drc_next_patch(void){}
  29. void ssp_drc_end(void){}
  30. #endif
  31. #define COUNT_OP
  32. #include "../../../cpu/drc/emit_arm.c"
  33. // -----------------------------------------------------
  34. static int get_inc(int mode)
  35. {
  36. int inc = (mode >> 11) & 7;
  37. if (inc != 0) {
  38. if (inc != 7) inc--;
  39. inc = 1 << inc; // 0 1 2 4 8 16 32 128
  40. if (mode & 0x8000) inc = -inc; // decrement mode
  41. }
  42. return inc;
  43. }
  44. u32 ssp_pm_read(int reg)
  45. {
  46. u32 d = 0, mode;
  47. if (ssp->emu_status & SSP_PMC_SET)
  48. {
  49. ssp->pmac_read[reg] = rPMC.v;
  50. ssp->emu_status &= ~SSP_PMC_SET;
  51. return 0;
  52. }
  53. // just in case
  54. ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
  55. mode = ssp->pmac_read[reg]>>16;
  56. if ((mode & 0xfff0) == 0x0800) // ROM
  57. {
  58. d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
  59. ssp->pmac_read[reg] += 1;
  60. }
  61. else if ((mode & 0x47ff) == 0x0018) // DRAM
  62. {
  63. unsigned short *dram = (unsigned short *)svp->dram;
  64. int inc = get_inc(mode);
  65. d = dram[ssp->pmac_read[reg]&0xffff];
  66. ssp->pmac_read[reg] += inc;
  67. }
  68. // PMC value corresponds to last PMR accessed
  69. rPMC.v = ssp->pmac_read[reg];
  70. return d;
  71. }
  72. #define overwrite_write(dst, d) \
  73. { \
  74. if (d & 0xf000) { dst &= ~0xf000; dst |= d & 0xf000; } \
  75. if (d & 0x0f00) { dst &= ~0x0f00; dst |= d & 0x0f00; } \
  76. if (d & 0x00f0) { dst &= ~0x00f0; dst |= d & 0x00f0; } \
  77. if (d & 0x000f) { dst &= ~0x000f; dst |= d & 0x000f; } \
  78. }
  79. void ssp_pm_write(u32 d, int reg)
  80. {
  81. unsigned short *dram;
  82. int mode, addr;
  83. if (ssp->emu_status & SSP_PMC_SET)
  84. {
  85. ssp->pmac_write[reg] = rPMC.v;
  86. ssp->emu_status &= ~SSP_PMC_SET;
  87. return;
  88. }
  89. // just in case
  90. ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
  91. dram = (unsigned short *)svp->dram;
  92. mode = ssp->pmac_write[reg]>>16;
  93. addr = ssp->pmac_write[reg]&0xffff;
  94. if ((mode & 0x43ff) == 0x0018) // DRAM
  95. {
  96. int inc = get_inc(mode);
  97. if (mode & 0x0400) {
  98. overwrite_write(dram[addr], d);
  99. } else dram[addr] = d;
  100. ssp->pmac_write[reg] += inc;
  101. }
  102. else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
  103. {
  104. if (mode & 0x0400) {
  105. overwrite_write(dram[addr], d);
  106. } else dram[addr] = d;
  107. ssp->pmac_write[reg] += (addr&1) ? 0x1f : 1;
  108. }
  109. else if ((mode & 0x47ff) == 0x001c) // IRAM
  110. {
  111. int inc = get_inc(mode);
  112. ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
  113. ssp->pmac_write[reg] += inc;
  114. ssp->drc.iram_dirty = 1;
  115. }
  116. rPMC.v = ssp->pmac_write[reg];
  117. }
  118. // -----------------------------------------------------
  119. // 14 IRAM blocks
  120. static unsigned char iram_context_map[] =
  121. {
  122. 0, 0, 0, 0, 1, 0, 0, 0, // 04
  123. 0, 0, 0, 0, 0, 0, 2, 0, // 0e
  124. 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
  125. 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
  126. 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
  127. 0, 0, 0, 0, 0, 0, 0, 0,
  128. 0, 0,11, 0, 0,12, 0, 0, // 32 35
  129. 13,14, 0, 0, 0, 0, 0, 0 // 38 39
  130. };
  131. int ssp_get_iram_context(void)
  132. {
  133. unsigned char *ir = (unsigned char *)svp->iram_rom;
  134. int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
  135. val1 = iram_context_map[(val>>1)&0x3f];
  136. if (val1 == 0) {
  137. elprintf(EL_ANOMALY, "svp: iram ctx val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
  138. //debug_dump2file(name, svp->iram_rom, 0x800);
  139. //exit(1);
  140. }
  141. return val1;
  142. }
  143. // -----------------------------------------------------
  144. /* regs with known values */
  145. static struct
  146. {
  147. ssp_reg_t gr[8];
  148. unsigned char r[8];
  149. unsigned int pmac_read[5];
  150. unsigned int pmac_write[5];
  151. ssp_reg_t pmc;
  152. unsigned int emu_status;
  153. } known_regs;
  154. #define KRREG_X (1 << SSP_X)
  155. #define KRREG_Y (1 << SSP_Y)
  156. #define KRREG_A (1 << SSP_A) /* AH only */
  157. #define KRREG_ST (1 << SSP_ST)
  158. #define KRREG_STACK (1 << SSP_STACK)
  159. #define KRREG_PC (1 << SSP_PC)
  160. #define KRREG_P (1 << SSP_P)
  161. #define KRREG_PR0 (1 << 8)
  162. #define KRREG_PR4 (1 << 12)
  163. #define KRREG_AL (1 << 16)
  164. #define KRREG_PMCM (1 << 18) /* only mode word of PMC */
  165. #define KRREG_PMC (1 << 19)
  166. #define KRREG_PM0R (1 << 20)
  167. #define KRREG_PM1R (1 << 21)
  168. #define KRREG_PM2R (1 << 22)
  169. #define KRREG_PM3R (1 << 23)
  170. #define KRREG_PM4R (1 << 24)
  171. #define KRREG_PM0W (1 << 25)
  172. #define KRREG_PM1W (1 << 26)
  173. #define KRREG_PM2W (1 << 27)
  174. #define KRREG_PM3W (1 << 28)
  175. #define KRREG_PM4W (1 << 29)
  176. /* bitfield of known register values */
  177. static u32 known_regb = 0;
  178. /* known vals, which need to be flushed
  179. * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
  180. * ST means flags are being held in ARM PSR
  181. * P means that it needs to be recalculated
  182. */
  183. static u32 dirty_regb = 0;
  184. /* known values of host regs.
  185. * -1 - unknown
  186. * 000000-00ffff - 16bit value
  187. * 100000-10ffff - base reg (r7) + 16bit val
  188. * 0r0000 - means reg (low) eq gr[r].h, r != AL
  189. */
  190. static int hostreg_r[4];
  191. static void hostreg_clear(void)
  192. {
  193. int i;
  194. for (i = 0; i < 4; i++)
  195. hostreg_r[i] = -1;
  196. }
  197. static void hostreg_sspreg_changed(int sspreg)
  198. {
  199. int i;
  200. for (i = 0; i < 4; i++)
  201. if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
  202. }
  203. #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
  204. #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
  205. void tr_unhandled(void)
  206. {
  207. //FILE *f = fopen("tcache.bin", "wb");
  208. //fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
  209. //fclose(f);
  210. elprintf(EL_ANOMALY, "unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
  211. //exit(1);
  212. }
  213. /* update P, if needed. Trashes r0 */
  214. static void tr_flush_dirty_P(void)
  215. {
  216. // TODO: const regs
  217. if (!(dirty_regb & KRREG_P)) return;
  218. EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
  219. EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
  220. EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
  221. EOP_MUL(10, 0, 10); // mul r10, r0, r10
  222. dirty_regb &= ~KRREG_P;
  223. hostreg_r[0] = -1;
  224. }
  225. /* write dirty pr to host reg. Nothing is trashed */
  226. static void tr_flush_dirty_pr(int r)
  227. {
  228. int ror = 0, reg;
  229. if (!(dirty_regb & (1 << (r+8)))) return;
  230. switch (r&3) {
  231. case 0: ror = 0; break;
  232. case 1: ror = 24/2; break;
  233. case 2: ror = 16/2; break;
  234. }
  235. reg = (r < 4) ? 8 : 9;
  236. EOP_BIC_IMM(reg,reg,ror,0xff);
  237. if (known_regs.r[r] != 0)
  238. EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
  239. dirty_regb &= ~(1 << (r+8));
  240. }
  241. /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
  242. static void tr_flush_dirty_prs(void)
  243. {
  244. int i, ror = 0, reg;
  245. int dirty = dirty_regb >> 8;
  246. if ((dirty&7) == 7) {
  247. emith_move_r_imm(8, known_regs.r[0]|(known_regs.r[1]<<8)|(known_regs.r[2]<<16));
  248. dirty &= ~7;
  249. }
  250. if ((dirty&0x70) == 0x70) {
  251. emith_move_r_imm(9, known_regs.r[4]|(known_regs.r[5]<<8)|(known_regs.r[6]<<16));
  252. dirty &= ~0x70;
  253. }
  254. /* r0-r7 */
  255. for (i = 0; dirty && i < 8; i++, dirty >>= 1)
  256. {
  257. if (!(dirty&1)) continue;
  258. switch (i&3) {
  259. case 0: ror = 0; break;
  260. case 1: ror = 24/2; break;
  261. case 2: ror = 16/2; break;
  262. }
  263. reg = (i < 4) ? 8 : 9;
  264. EOP_BIC_IMM(reg,reg,ror,0xff);
  265. if (known_regs.r[i] != 0)
  266. EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
  267. }
  268. dirty_regb &= ~0xff00;
  269. }
  270. /* write dirty pr and "forget" it. Nothing is trashed. */
  271. static void tr_release_pr(int r)
  272. {
  273. tr_flush_dirty_pr(r);
  274. known_regb &= ~(1 << (r+8));
  275. }
  276. /* fush ARM PSR to r6. Trashes r1 */
  277. static void tr_flush_dirty_ST(void)
  278. {
  279. if (!(dirty_regb & KRREG_ST)) return;
  280. EOP_BIC_IMM(6,6,0,0x0f);
  281. EOP_MRS(1);
  282. EOP_ORR_REG_LSR(6,6,1,28);
  283. dirty_regb &= ~KRREG_ST;
  284. hostreg_r[1] = -1;
  285. }
  286. /* inverse of above. Trashes r1 */
  287. static void tr_make_dirty_ST(void)
  288. {
  289. if (dirty_regb & KRREG_ST) return;
  290. if (known_regb & KRREG_ST) {
  291. int flags = 0;
  292. if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
  293. if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
  294. EOP_MSR_IMM(4/2, flags);
  295. } else {
  296. EOP_MOV_REG_LSL(1, 6, 28);
  297. EOP_MSR_REG(1);
  298. hostreg_r[1] = -1;
  299. }
  300. dirty_regb |= KRREG_ST;
  301. }
  302. /* load 16bit val into host reg r0-r3. Nothing is trashed */
  303. static void tr_mov16(int r, int val)
  304. {
  305. if (hostreg_r[r] != val) {
  306. emith_move_r_imm(r, val);
  307. hostreg_r[r] = val;
  308. }
  309. }
  310. static void tr_mov16_cond(int cond, int r, int val)
  311. {
  312. emith_op_imm(cond, 0, A_OP_MOV, r, val);
  313. hostreg_r[r] = -1;
  314. }
  315. /* trashes r1 */
  316. static void tr_flush_dirty_pmcrs(void)
  317. {
  318. u32 i, val = (u32)-1;
  319. if (!(dirty_regb & 0x3ff80000)) return;
  320. if (dirty_regb & KRREG_PMC) {
  321. val = known_regs.pmc.v;
  322. emith_move_r_imm(1, val);
  323. EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
  324. if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
  325. elprintf(EL_ANOMALY, "!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
  326. tr_unhandled();
  327. }
  328. }
  329. for (i = 0; i < 5; i++)
  330. {
  331. if (dirty_regb & (1 << (20+i))) {
  332. if (val != known_regs.pmac_read[i]) {
  333. val = known_regs.pmac_read[i];
  334. emith_move_r_imm(1, val);
  335. }
  336. EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
  337. }
  338. if (dirty_regb & (1 << (25+i))) {
  339. if (val != known_regs.pmac_write[i]) {
  340. val = known_regs.pmac_write[i];
  341. emith_move_r_imm(1, val);
  342. }
  343. EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
  344. }
  345. }
  346. dirty_regb &= ~0x3ff80000;
  347. hostreg_r[1] = -1;
  348. }
  349. /* read bank word to r0 (upper bits zero). Thrashes r1. */
  350. static void tr_bank_read(int addr) /* word addr 0-0x1ff */
  351. {
  352. int breg = 7;
  353. if (addr > 0x7f) {
  354. if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
  355. EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
  356. hostreg_r[1] = 0x100000|((addr&0x180)<<1);
  357. }
  358. breg = 1;
  359. }
  360. EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
  361. hostreg_r[0] = -1;
  362. }
  363. /* write r0 to bank. Trashes r1. */
  364. static void tr_bank_write(int addr)
  365. {
  366. int breg = 7;
  367. if (addr > 0x7f) {
  368. if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
  369. EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
  370. hostreg_r[1] = 0x100000|((addr&0x180)<<1);
  371. }
  372. breg = 1;
  373. }
  374. EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
  375. }
  376. /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
  377. static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
  378. {
  379. int modulo_shift = -1; /* unknown */
  380. if (mod == 0) return;
  381. if (!need_modulo || mod == 1) // +!
  382. modulo_shift = 8;
  383. else if (need_modulo && (known_regb & KRREG_ST)) {
  384. modulo_shift = known_regs.gr[SSP_ST].h & 7;
  385. if (modulo_shift == 0) modulo_shift = 8;
  386. }
  387. if (modulo_shift == -1)
  388. {
  389. int reg = (r < 4) ? 8 : 9;
  390. tr_release_pr(r);
  391. if (dirty_regb & KRREG_ST) {
  392. // avoid flushing ARM flags
  393. EOP_AND_IMM(1, 6, 0, 0x70);
  394. EOP_SUB_IMM(1, 1, 0, 0x10);
  395. EOP_AND_IMM(1, 1, 0, 0x70);
  396. EOP_ADD_IMM(1, 1, 0, 0x10);
  397. } else {
  398. EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
  399. EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
  400. }
  401. EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
  402. EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
  403. EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
  404. if (r&3)
  405. EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
  406. EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
  407. if (mod == 2)
  408. EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
  409. else EOP_ADD_REG2_LSL(reg,reg,3,2);
  410. EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
  411. EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
  412. hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
  413. }
  414. else if (known_regb & (1 << (r + 8)))
  415. {
  416. int modulo = (1 << modulo_shift) - 1;
  417. if (mod == 2)
  418. known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
  419. else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
  420. }
  421. else
  422. {
  423. int reg = (r < 4) ? 8 : 9;
  424. int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
  425. EOP_MOV_REG_ROR(reg,reg,ror);
  426. // {add|sub} reg, reg, #1<<shift
  427. EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
  428. EOP_MOV_REG_ROR(reg,reg,32-ror);
  429. }
  430. }
  431. /* handle writes r0 to (rX). Trashes r1.
  432. * fortunately we can ignore modulo increment modes for writes. */
  433. static void tr_rX_write(int op)
  434. {
  435. if ((op&3) == 3)
  436. {
  437. int mod = (op>>2) & 3; // direct addressing
  438. tr_bank_write((op & 0x100) + mod);
  439. }
  440. else
  441. {
  442. int r = (op&3) | ((op>>6)&4);
  443. if (known_regb & (1 << (r + 8))) {
  444. tr_bank_write((op&0x100) | known_regs.r[r]);
  445. } else {
  446. int reg = (r < 4) ? 8 : 9;
  447. int ror = ((4 - (r&3))*8) & 0x1f;
  448. EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
  449. if (r >= 4)
  450. EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
  451. if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
  452. else EOP_ADD_REG_LSL(1,7,1,1);
  453. EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
  454. hostreg_r[1] = -1;
  455. }
  456. tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
  457. }
  458. }
  459. /* read (rX) to r0. Trashes r1-r3. */
  460. static void tr_rX_read(int r, int mod)
  461. {
  462. if ((r&3) == 3)
  463. {
  464. tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
  465. }
  466. else
  467. {
  468. if (known_regb & (1 << (r + 8))) {
  469. tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
  470. } else {
  471. int reg = (r < 4) ? 8 : 9;
  472. int ror = ((4 - (r&3))*8) & 0x1f;
  473. EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
  474. if (r >= 4)
  475. EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
  476. if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
  477. else EOP_ADD_REG_LSL(1,7,1,1);
  478. EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
  479. hostreg_r[0] = hostreg_r[1] = -1;
  480. }
  481. tr_ptrr_mod(r, mod, 1, 1);
  482. }
  483. }
  484. /* read ((rX)) to r0. Trashes r1,r2. */
  485. static void tr_rX_read2(int op)
  486. {
  487. int r = (op&3) | ((op>>6)&4); // src
  488. if ((r&3) == 3) {
  489. tr_bank_read((op&0x100) | ((op>>2)&3));
  490. } else if (known_regb & (1 << (r+8))) {
  491. tr_bank_read((op&0x100) | known_regs.r[r]);
  492. } else {
  493. int reg = (r < 4) ? 8 : 9;
  494. int ror = ((4 - (r&3))*8) & 0x1f;
  495. EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
  496. if (r >= 4)
  497. EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
  498. if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
  499. else EOP_ADD_REG_LSL(1,7,1,1);
  500. EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
  501. }
  502. EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
  503. EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
  504. EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
  505. if ((r&3) == 3) {
  506. tr_bank_write((op&0x100) | ((op>>2)&3));
  507. } else if (known_regb & (1 << (r+8))) {
  508. tr_bank_write((op&0x100) | known_regs.r[r]);
  509. } else {
  510. EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
  511. hostreg_r[1] = -1;
  512. }
  513. EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
  514. hostreg_r[0] = hostreg_r[2] = -1;
  515. }
  516. // check if AL is going to be used later in block
  517. static int tr_predict_al_need(void)
  518. {
  519. int tmpv, tmpv2, op, pc = known_regs.gr[SSP_PC].h;
  520. while (1)
  521. {
  522. op = PROGRAM(pc);
  523. switch (op >> 9)
  524. {
  525. // ld d, s
  526. case 0x00:
  527. tmpv2 = (op >> 4) & 0xf; // dst
  528. tmpv = op & 0xf; // src
  529. if ((tmpv2 == SSP_A && tmpv == SSP_P) || tmpv2 == SSP_AL) // ld A, P; ld AL, *
  530. return 0;
  531. break;
  532. // ld (ri), s
  533. case 0x02:
  534. // ld ri, s
  535. case 0x0a:
  536. // OP a, s
  537. case 0x10: case 0x30: case 0x40: case 0x60: case 0x70:
  538. tmpv = op & 0xf; // src
  539. if (tmpv == SSP_AL) // OP *, AL
  540. return 1;
  541. break;
  542. case 0x04:
  543. case 0x06:
  544. case 0x14:
  545. case 0x34:
  546. case 0x44:
  547. case 0x64:
  548. case 0x74: pc++; break;
  549. // call cond, addr
  550. case 0x24:
  551. // bra cond, addr
  552. case 0x26:
  553. // mod cond, op
  554. case 0x48:
  555. // mpys?
  556. case 0x1b:
  557. // mpya (rj), (ri), b
  558. case 0x4b: return 1;
  559. // mld (rj), (ri), b
  560. case 0x5b: return 0; // cleared anyway
  561. // and A, *
  562. case 0x50:
  563. tmpv = op & 0xf; // src
  564. if (tmpv == SSP_AL) return 1;
  565. case 0x51: case 0x53: case 0x54: case 0x55: case 0x59: case 0x5c:
  566. return 0;
  567. }
  568. pc++;
  569. }
  570. }
  571. /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
  572. static int tr_cond_check(int op)
  573. {
  574. int f = (op & 0x100) >> 8;
  575. switch (op&0xf0) {
  576. case 0x00: return A_COND_AL; /* always true */
  577. case 0x50: /* Z matches f(?) bit */
  578. if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
  579. EOP_TST_IMM(6, 0, 4);
  580. return f ? A_COND_NE : A_COND_EQ;
  581. case 0x70: /* N matches f(?) bit */
  582. if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
  583. EOP_TST_IMM(6, 0, 8);
  584. return f ? A_COND_NE : A_COND_EQ;
  585. default:
  586. elprintf(EL_ANOMALY, "unimplemented cond?\n");
  587. tr_unhandled();
  588. return 0;
  589. }
  590. }
  591. static int tr_neg_cond(int cond)
  592. {
  593. switch (cond) {
  594. case A_COND_AL: elprintf(EL_ANOMALY, "neg for AL?\n"); exit(1);
  595. case A_COND_EQ: return A_COND_NE;
  596. case A_COND_NE: return A_COND_EQ;
  597. case A_COND_MI: return A_COND_PL;
  598. case A_COND_PL: return A_COND_MI;
  599. default: elprintf(EL_ANOMALY, "bad cond for neg\n"); exit(1);
  600. }
  601. return 0;
  602. }
  603. static int tr_aop_ssp2arm(int op)
  604. {
  605. switch (op) {
  606. case 1: return A_OP_SUB;
  607. case 3: return A_OP_CMP;
  608. case 4: return A_OP_ADD;
  609. case 5: return A_OP_AND;
  610. case 6: return A_OP_ORR;
  611. case 7: return A_OP_EOR;
  612. }
  613. tr_unhandled();
  614. return 0;
  615. }
  616. #ifdef __MACH__
  617. /* spacial version of call for calling C needed on ios, since we use r9.. */
  618. static void emith_call_c_func(void *target)
  619. {
  620. EOP_STMFD_SP(M2(7,9));
  621. emith_call(target);
  622. EOP_LDMFD_SP(M2(7,9));
  623. }
  624. #else
  625. #define emith_call_c_func emith_call
  626. #endif
  627. // -----------------------------------------------------
  628. //@ r4: XXYY
  629. //@ r5: A
  630. //@ r6: STACK and emu flags
  631. //@ r7: SSP context
  632. //@ r10: P
  633. // read general reg to r0. Trashes r1
  634. static void tr_GR0_to_r0(int op)
  635. {
  636. tr_mov16(0, 0xffff);
  637. }
  638. static void tr_X_to_r0(int op)
  639. {
  640. if (hostreg_r[0] != (SSP_X<<16)) {
  641. EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
  642. hostreg_r[0] = SSP_X<<16;
  643. }
  644. }
  645. static void tr_Y_to_r0(int op)
  646. {
  647. if (hostreg_r[0] != (SSP_Y<<16)) {
  648. EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
  649. hostreg_r[0] = SSP_Y<<16;
  650. }
  651. }
  652. static void tr_A_to_r0(int op)
  653. {
  654. if (hostreg_r[0] != (SSP_A<<16)) {
  655. EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
  656. hostreg_r[0] = SSP_A<<16;
  657. }
  658. }
  659. static void tr_ST_to_r0(int op)
  660. {
  661. // VR doesn't need much accuracy here..
  662. EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
  663. EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
  664. hostreg_r[0] = -1;
  665. }
  666. static void tr_STACK_to_r0(int op)
  667. {
  668. // 448
  669. EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
  670. EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
  671. EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
  672. EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
  673. EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
  674. hostreg_r[0] = hostreg_r[1] = -1;
  675. }
  676. static void tr_PC_to_r0(int op)
  677. {
  678. tr_mov16(0, known_regs.gr[SSP_PC].h);
  679. }
  680. static void tr_P_to_r0(int op)
  681. {
  682. tr_flush_dirty_P();
  683. EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
  684. hostreg_r[0] = -1;
  685. }
  686. static void tr_AL_to_r0(int op)
  687. {
  688. if (op == 0x000f) {
  689. if (known_regb & KRREG_PMC) {
  690. known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
  691. } else {
  692. EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
  693. EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
  694. EOP_STR_IMM(0,7,0x484);
  695. }
  696. }
  697. if (hostreg_r[0] != (SSP_AL<<16)) {
  698. EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
  699. hostreg_r[0] = SSP_AL<<16;
  700. }
  701. }
  702. static void tr_PMX_to_r0(int reg)
  703. {
  704. if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
  705. {
  706. known_regs.pmac_read[reg] = known_regs.pmc.v;
  707. known_regs.emu_status &= ~SSP_PMC_SET;
  708. known_regb |= 1 << (20+reg);
  709. dirty_regb |= 1 << (20+reg);
  710. return;
  711. }
  712. if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
  713. {
  714. u32 pmcv = known_regs.pmac_read[reg];
  715. int mode = pmcv>>16;
  716. known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
  717. if ((mode & 0xfff0) == 0x0800)
  718. {
  719. EOP_LDR_IMM(1,7,0x488); // rom_ptr
  720. emith_move_r_imm(0, (pmcv&0xfffff)<<1);
  721. EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
  722. known_regs.pmac_read[reg] += 1;
  723. }
  724. else if ((mode & 0x47ff) == 0x0018) // DRAM
  725. {
  726. int inc = get_inc(mode);
  727. EOP_LDR_IMM(1,7,0x490); // dram_ptr
  728. emith_move_r_imm(0, (pmcv&0xffff)<<1);
  729. EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
  730. if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
  731. {
  732. int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
  733. tr_flush_dirty_ST();
  734. EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
  735. EOP_TST_REG_SIMPLE(0,0);
  736. EOP_C_DOP_IMM(A_COND_EQ,A_OP_SUB,0,11,11,22/2,1); // subeq r11, r11, #1024
  737. EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
  738. EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
  739. }
  740. known_regs.pmac_read[reg] += inc;
  741. }
  742. else
  743. {
  744. tr_unhandled();
  745. }
  746. known_regs.pmc.v = known_regs.pmac_read[reg];
  747. //known_regb |= KRREG_PMC;
  748. dirty_regb |= KRREG_PMC;
  749. dirty_regb |= 1 << (20+reg);
  750. hostreg_r[0] = hostreg_r[1] = -1;
  751. return;
  752. }
  753. known_regb &= ~KRREG_PMC;
  754. dirty_regb &= ~KRREG_PMC;
  755. known_regb &= ~(1 << (20+reg));
  756. dirty_regb &= ~(1 << (20+reg));
  757. // call the C code to handle this
  758. tr_flush_dirty_ST();
  759. //tr_flush_dirty_pmcrs();
  760. tr_mov16(0, reg);
  761. emith_call_c_func(ssp_pm_read);
  762. hostreg_clear();
  763. }
  764. static void tr_PM0_to_r0(int op)
  765. {
  766. tr_PMX_to_r0(0);
  767. }
  768. static void tr_PM1_to_r0(int op)
  769. {
  770. tr_PMX_to_r0(1);
  771. }
  772. static void tr_PM2_to_r0(int op)
  773. {
  774. tr_PMX_to_r0(2);
  775. }
  776. static void tr_XST_to_r0(int op)
  777. {
  778. EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
  779. EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
  780. }
  781. static void tr_PM4_to_r0(int op)
  782. {
  783. tr_PMX_to_r0(4);
  784. }
  785. static void tr_PMC_to_r0(int op)
  786. {
  787. if (known_regb & KRREG_PMC)
  788. {
  789. if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
  790. known_regs.emu_status |= SSP_PMC_SET;
  791. known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
  792. // do nothing - this is handled elsewhere
  793. } else {
  794. tr_mov16(0, known_regs.pmc.l);
  795. known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
  796. }
  797. }
  798. else
  799. {
  800. EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
  801. tr_flush_dirty_ST();
  802. if (op != 0x000e)
  803. EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
  804. EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
  805. EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
  806. EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
  807. EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
  808. EOP_STR_IMM(1,7,0x484);
  809. hostreg_r[0] = hostreg_r[1] = -1;
  810. }
  811. }
  812. typedef void (tr_read_func)(int op);
  813. static tr_read_func *tr_read_funcs[16] =
  814. {
  815. tr_GR0_to_r0,
  816. tr_X_to_r0,
  817. tr_Y_to_r0,
  818. tr_A_to_r0,
  819. tr_ST_to_r0,
  820. tr_STACK_to_r0,
  821. tr_PC_to_r0,
  822. tr_P_to_r0,
  823. tr_PM0_to_r0,
  824. tr_PM1_to_r0,
  825. tr_PM2_to_r0,
  826. tr_XST_to_r0,
  827. tr_PM4_to_r0,
  828. (tr_read_func *)tr_unhandled,
  829. tr_PMC_to_r0,
  830. tr_AL_to_r0
  831. };
  832. // write r0 to general reg handlers. Trashes r1
  833. #define TR_WRITE_R0_TO_REG(reg) \
  834. { \
  835. hostreg_sspreg_changed(reg); \
  836. hostreg_r[0] = (reg)<<16; \
  837. if (const_val != -1) { \
  838. known_regs.gr[reg].h = const_val; \
  839. known_regb |= 1 << (reg); \
  840. } else { \
  841. known_regb &= ~(1 << (reg)); \
  842. } \
  843. }
  844. static void tr_r0_to_GR0(int const_val)
  845. {
  846. // do nothing
  847. }
  848. static void tr_r0_to_X(int const_val)
  849. {
  850. EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
  851. EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
  852. EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
  853. dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
  854. TR_WRITE_R0_TO_REG(SSP_X);
  855. }
  856. static void tr_r0_to_Y(int const_val)
  857. {
  858. EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
  859. EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
  860. EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
  861. dirty_regb |= KRREG_P;
  862. TR_WRITE_R0_TO_REG(SSP_Y);
  863. }
  864. static void tr_r0_to_A(int const_val)
  865. {
  866. if (tr_predict_al_need()) {
  867. EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
  868. EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
  869. EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
  870. }
  871. else
  872. EOP_MOV_REG_LSL(5, 0, 16);
  873. TR_WRITE_R0_TO_REG(SSP_A);
  874. }
  875. static void tr_r0_to_ST(int const_val)
  876. {
  877. // VR doesn't need much accuracy here..
  878. EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
  879. EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
  880. EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
  881. TR_WRITE_R0_TO_REG(SSP_ST);
  882. hostreg_r[1] = -1;
  883. dirty_regb &= ~KRREG_ST;
  884. }
  885. static void tr_r0_to_STACK(int const_val)
  886. {
  887. // 448
  888. EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
  889. EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
  890. EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
  891. EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
  892. EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
  893. hostreg_r[1] = -1;
  894. }
  895. static void tr_r0_to_PC(int const_val)
  896. {
  897. /*
  898. * do nothing - dispatcher will take care of this
  899. EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
  900. EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
  901. hostreg_r[1] = -1;
  902. */
  903. }
  904. static void tr_r0_to_AL(int const_val)
  905. {
  906. EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
  907. EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
  908. EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
  909. hostreg_sspreg_changed(SSP_AL);
  910. if (const_val != -1) {
  911. known_regs.gr[SSP_A].l = const_val;
  912. known_regb |= 1 << SSP_AL;
  913. } else
  914. known_regb &= ~(1 << SSP_AL);
  915. }
  916. static void tr_r0_to_PMX(int reg)
  917. {
  918. if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
  919. {
  920. known_regs.pmac_write[reg] = known_regs.pmc.v;
  921. known_regs.emu_status &= ~SSP_PMC_SET;
  922. known_regb |= 1 << (25+reg);
  923. dirty_regb |= 1 << (25+reg);
  924. return;
  925. }
  926. if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
  927. {
  928. int mode, addr;
  929. known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
  930. mode = known_regs.pmac_write[reg]>>16;
  931. addr = known_regs.pmac_write[reg]&0xffff;
  932. if ((mode & 0x43ff) == 0x0018) // DRAM
  933. {
  934. int inc = get_inc(mode);
  935. if (mode & 0x0400) tr_unhandled();
  936. EOP_LDR_IMM(1,7,0x490); // dram_ptr
  937. emith_move_r_imm(2, addr << 1);
  938. EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
  939. known_regs.pmac_write[reg] += inc;
  940. }
  941. else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
  942. {
  943. if (mode & 0x0400) tr_unhandled();
  944. EOP_LDR_IMM(1,7,0x490); // dram_ptr
  945. emith_move_r_imm(2, addr << 1);
  946. EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
  947. known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
  948. }
  949. else if ((mode & 0x47ff) == 0x001c) // IRAM
  950. {
  951. int inc = get_inc(mode);
  952. EOP_LDR_IMM(1,7,0x48c); // iram_ptr
  953. emith_move_r_imm(2, (addr&0x3ff) << 1);
  954. EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
  955. EOP_MOV_IMM(1,0,1);
  956. EOP_STR_IMM(1,7,0x494); // iram_dirty
  957. known_regs.pmac_write[reg] += inc;
  958. }
  959. else
  960. tr_unhandled();
  961. known_regs.pmc.v = known_regs.pmac_write[reg];
  962. //known_regb |= KRREG_PMC;
  963. dirty_regb |= KRREG_PMC;
  964. dirty_regb |= 1 << (25+reg);
  965. hostreg_r[1] = hostreg_r[2] = -1;
  966. return;
  967. }
  968. known_regb &= ~KRREG_PMC;
  969. dirty_regb &= ~KRREG_PMC;
  970. known_regb &= ~(1 << (25+reg));
  971. dirty_regb &= ~(1 << (25+reg));
  972. // call the C code to handle this
  973. tr_flush_dirty_ST();
  974. //tr_flush_dirty_pmcrs();
  975. tr_mov16(1, reg);
  976. emith_call_c_func(ssp_pm_write);
  977. hostreg_clear();
  978. }
  979. static void tr_r0_to_PM0(int const_val)
  980. {
  981. tr_r0_to_PMX(0);
  982. }
  983. static void tr_r0_to_PM1(int const_val)
  984. {
  985. tr_r0_to_PMX(1);
  986. }
  987. static void tr_r0_to_PM2(int const_val)
  988. {
  989. tr_r0_to_PMX(2);
  990. }
  991. static void tr_r0_to_PM4(int const_val)
  992. {
  993. tr_r0_to_PMX(4);
  994. }
  995. static void tr_r0_to_PMC(int const_val)
  996. {
  997. if ((known_regb & KRREG_PMC) && const_val != -1)
  998. {
  999. if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
  1000. known_regs.emu_status |= SSP_PMC_SET;
  1001. known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
  1002. known_regs.pmc.h = const_val;
  1003. } else {
  1004. known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
  1005. known_regs.pmc.l = const_val;
  1006. }
  1007. }
  1008. else
  1009. {
  1010. tr_flush_dirty_ST();
  1011. if (known_regb & KRREG_PMC) {
  1012. emith_move_r_imm(1, known_regs.pmc.v);
  1013. EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
  1014. known_regb &= ~KRREG_PMC;
  1015. dirty_regb &= ~KRREG_PMC;
  1016. }
  1017. EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
  1018. EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
  1019. EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
  1020. EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
  1021. EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
  1022. EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
  1023. EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
  1024. EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
  1025. EOP_STR_IMM(1,7,0x484);
  1026. hostreg_r[1] = hostreg_r[2] = -1;
  1027. }
  1028. }
  1029. typedef void (tr_write_func)(int const_val);
  1030. static tr_write_func *tr_write_funcs[16] =
  1031. {
  1032. tr_r0_to_GR0,
  1033. tr_r0_to_X,
  1034. tr_r0_to_Y,
  1035. tr_r0_to_A,
  1036. tr_r0_to_ST,
  1037. tr_r0_to_STACK,
  1038. tr_r0_to_PC,
  1039. (tr_write_func *)tr_unhandled,
  1040. tr_r0_to_PM0,
  1041. tr_r0_to_PM1,
  1042. tr_r0_to_PM2,
  1043. (tr_write_func *)tr_unhandled,
  1044. tr_r0_to_PM4,
  1045. (tr_write_func *)tr_unhandled,
  1046. tr_r0_to_PMC,
  1047. tr_r0_to_AL
  1048. };
  1049. static void tr_mac_load_XY(int op)
  1050. {
  1051. tr_rX_read(op&3, (op>>2)&3); // X
  1052. EOP_MOV_REG_LSL(4, 0, 16);
  1053. tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
  1054. EOP_ORR_REG_SIMPLE(4, 0);
  1055. dirty_regb |= KRREG_P;
  1056. hostreg_sspreg_changed(SSP_X);
  1057. hostreg_sspreg_changed(SSP_Y);
  1058. known_regb &= ~KRREG_X;
  1059. known_regb &= ~KRREG_Y;
  1060. }
  1061. // -----------------------------------------------------
  1062. static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
  1063. {
  1064. u32 pmcv, tmpv;
  1065. if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
  1066. // programming PMC:
  1067. // ldi PMC, imm1
  1068. // ldi PMC, imm2
  1069. (*pc)++;
  1070. pmcv = imm | (PROGRAM((*pc)++) << 16);
  1071. known_regs.pmc.v = pmcv;
  1072. known_regb |= KRREG_PMC;
  1073. dirty_regb |= KRREG_PMC;
  1074. known_regs.emu_status |= SSP_PMC_SET;
  1075. n_in_ops++;
  1076. // check for possible reg programming
  1077. tmpv = PROGRAM(*pc);
  1078. if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
  1079. {
  1080. int is_write = (tmpv & 0xff8f) == 0x80;
  1081. int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
  1082. if (reg > 4) tr_unhandled();
  1083. if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
  1084. if (is_write)
  1085. known_regs.pmac_write[reg] = pmcv;
  1086. else
  1087. known_regs.pmac_read[reg] = pmcv;
  1088. known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
  1089. dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
  1090. known_regs.emu_status &= ~SSP_PMC_SET;
  1091. (*pc)++;
  1092. n_in_ops++;
  1093. return 5;
  1094. }
  1095. tr_unhandled();
  1096. return 4;
  1097. }
  1098. static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
  1099. static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
  1100. {
  1101. // ldi ST, 0
  1102. // ldi PM0, 0
  1103. // ldi PM0, 0
  1104. // ldi ST, 60h
  1105. unsigned short *pp;
  1106. if (op != 0x0840 || imm != 0) return 0;
  1107. pp = PROGRAM_P(*pc);
  1108. if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
  1109. EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
  1110. EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
  1111. hostreg_sspreg_changed(SSP_ST);
  1112. known_regs.gr[SSP_ST].h = 0x60;
  1113. known_regb |= 1 << SSP_ST;
  1114. dirty_regb &= ~KRREG_ST;
  1115. (*pc) += 3*2;
  1116. n_in_ops += 3;
  1117. return 4*2;
  1118. }
  1119. static int tr_detect_rotate(unsigned int op, int *pc, int imm)
  1120. {
  1121. // @ 3DA2 and 426A
  1122. // ld PMC, (r3|00)
  1123. // ld (r3|00), PMC
  1124. // ld -, AL
  1125. if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
  1126. tr_bank_read(0);
  1127. EOP_MOV_REG_LSL(0, 0, 4);
  1128. EOP_ORR_REG_LSR(0, 0, 0, 16);
  1129. tr_bank_write(0);
  1130. (*pc) += 2;
  1131. n_in_ops += 2;
  1132. return 3;
  1133. }
  1134. // -----------------------------------------------------
  1135. static int translate_op(unsigned int op, int *pc, int imm, int *end_cond, int *jump_pc)
  1136. {
  1137. u32 tmpv, tmpv2, tmpv3;
  1138. int ret = 0;
  1139. known_regs.gr[SSP_PC].h = *pc;
  1140. switch (op >> 9)
  1141. {
  1142. // ld d, s
  1143. case 0x00:
  1144. if (op == 0) { ret++; break; } // nop
  1145. tmpv = op & 0xf; // src
  1146. tmpv2 = (op >> 4) & 0xf; // dst
  1147. if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
  1148. tr_flush_dirty_P();
  1149. EOP_MOV_REG_SIMPLE(5, 10);
  1150. hostreg_sspreg_changed(SSP_A);
  1151. known_regb &= ~(KRREG_A|KRREG_AL);
  1152. ret++; break;
  1153. }
  1154. tr_read_funcs[tmpv](op);
  1155. tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
  1156. if (tmpv2 == SSP_PC) {
  1157. ret |= 0x10000;
  1158. *end_cond = -A_COND_AL;
  1159. }
  1160. ret++; break;
  1161. // ld d, (ri)
  1162. case 0x01: {
  1163. int r = (op&3) | ((op>>6)&4);
  1164. int mod = (op>>2)&3;
  1165. tmpv = (op >> 4) & 0xf; // dst
  1166. ret = tr_detect_rotate(op, pc, imm);
  1167. if (ret > 0) break;
  1168. if (tmpv != 0)
  1169. tr_rX_read(r, mod);
  1170. else {
  1171. int cnt = 1;
  1172. while (PROGRAM(*pc) == op) {
  1173. (*pc)++; cnt++; ret++;
  1174. n_in_ops++;
  1175. }
  1176. tr_ptrr_mod(r, mod, 1, cnt); // skip
  1177. }
  1178. tr_write_funcs[tmpv](-1);
  1179. if (tmpv == SSP_PC) {
  1180. ret |= 0x10000;
  1181. *end_cond = -A_COND_AL;
  1182. }
  1183. ret++; break;
  1184. }
  1185. // ld (ri), s
  1186. case 0x02:
  1187. tmpv = (op >> 4) & 0xf; // src
  1188. tr_read_funcs[tmpv](op);
  1189. tr_rX_write(op);
  1190. ret++; break;
  1191. // ld a, adr
  1192. case 0x03:
  1193. tr_bank_read(op&0x1ff);
  1194. tr_r0_to_A(-1);
  1195. ret++; break;
  1196. // ldi d, imm
  1197. case 0x04:
  1198. tmpv = (op & 0xf0) >> 4; // dst
  1199. ret = tr_detect_pm0_block(op, pc, imm);
  1200. if (ret > 0) break;
  1201. ret = tr_detect_set_pm(op, pc, imm);
  1202. if (ret > 0) break;
  1203. tr_mov16(0, imm);
  1204. tr_write_funcs[tmpv](imm);
  1205. if (tmpv == SSP_PC) {
  1206. ret |= 0x10000;
  1207. *jump_pc = imm;
  1208. }
  1209. ret += 2; break;
  1210. // ld d, ((ri))
  1211. case 0x05:
  1212. tmpv2 = (op >> 4) & 0xf; // dst
  1213. tr_rX_read2(op);
  1214. tr_write_funcs[tmpv2](-1);
  1215. if (tmpv2 == SSP_PC) {
  1216. ret |= 0x10000;
  1217. *end_cond = -A_COND_AL;
  1218. }
  1219. ret += 3; break;
  1220. // ldi (ri), imm
  1221. case 0x06:
  1222. tr_mov16(0, imm);
  1223. tr_rX_write(op);
  1224. ret += 2; break;
  1225. // ld adr, a
  1226. case 0x07:
  1227. tr_A_to_r0(op);
  1228. tr_bank_write(op&0x1ff);
  1229. ret++; break;
  1230. // ld d, ri
  1231. case 0x09: {
  1232. int r;
  1233. r = (op&3) | ((op>>6)&4); // src
  1234. tmpv2 = (op >> 4) & 0xf; // dst
  1235. if ((r&3) == 3) tr_unhandled();
  1236. if (known_regb & (1 << (r+8))) {
  1237. tr_mov16(0, known_regs.r[r]);
  1238. tr_write_funcs[tmpv2](known_regs.r[r]);
  1239. } else {
  1240. int reg = (r < 4) ? 8 : 9;
  1241. if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
  1242. EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
  1243. hostreg_r[0] = -1;
  1244. tr_write_funcs[tmpv2](-1);
  1245. }
  1246. ret++; break;
  1247. }
  1248. // ld ri, s
  1249. case 0x0a: {
  1250. int r;
  1251. r = (op&3) | ((op>>6)&4); // dst
  1252. tmpv = (op >> 4) & 0xf; // src
  1253. if ((r&3) == 3) tr_unhandled();
  1254. if (known_regb & (1 << tmpv)) {
  1255. known_regs.r[r] = known_regs.gr[tmpv].h;
  1256. known_regb |= 1 << (r + 8);
  1257. dirty_regb |= 1 << (r + 8);
  1258. } else {
  1259. int reg = (r < 4) ? 8 : 9;
  1260. int ror = ((4 - (r&3))*8) & 0x1f;
  1261. tr_read_funcs[tmpv](op);
  1262. EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
  1263. EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
  1264. EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
  1265. hostreg_r[0] = -1;
  1266. known_regb &= ~(1 << (r+8));
  1267. dirty_regb &= ~(1 << (r+8));
  1268. }
  1269. ret++; break;
  1270. }
  1271. // ldi ri, simm
  1272. case 0x0c: case 0x0d: case 0x0e: case 0x0f:
  1273. tmpv = (op>>8)&7;
  1274. known_regs.r[tmpv] = op;
  1275. known_regb |= 1 << (tmpv + 8);
  1276. dirty_regb |= 1 << (tmpv + 8);
  1277. ret++; break;
  1278. // call cond, addr
  1279. case 0x24: {
  1280. u32 *jump_op = NULL;
  1281. tmpv = tr_cond_check(op);
  1282. if (tmpv != A_COND_AL) {
  1283. jump_op = tcache_ptr;
  1284. EOP_MOV_IMM(0, 0, 0); // placeholder for branch
  1285. }
  1286. tr_mov16(0, *pc);
  1287. tr_r0_to_STACK(*pc);
  1288. if (tmpv != A_COND_AL)
  1289. EOP_C_B_PTR(jump_op, tr_neg_cond(tmpv), 0,
  1290. tcache_ptr - jump_op - 2);
  1291. tr_mov16_cond(tmpv, 0, imm);
  1292. if (tmpv != A_COND_AL)
  1293. tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
  1294. tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
  1295. ret |= 0x10000;
  1296. *end_cond = tmpv;
  1297. *jump_pc = imm;
  1298. ret += 2; break;
  1299. }
  1300. // ld d, (a)
  1301. case 0x25:
  1302. tmpv2 = (op >> 4) & 0xf; // dst
  1303. tr_A_to_r0(op);
  1304. EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
  1305. EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
  1306. EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
  1307. hostreg_r[0] = hostreg_r[1] = -1;
  1308. tr_write_funcs[tmpv2](-1);
  1309. if (tmpv2 == SSP_PC) {
  1310. ret |= 0x10000;
  1311. *end_cond = -A_COND_AL;
  1312. }
  1313. ret += 3; break;
  1314. // bra cond, addr
  1315. case 0x26:
  1316. tmpv = tr_cond_check(op);
  1317. tr_mov16_cond(tmpv, 0, imm);
  1318. if (tmpv != A_COND_AL)
  1319. tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
  1320. tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
  1321. ret |= 0x10000;
  1322. *end_cond = tmpv;
  1323. *jump_pc = imm;
  1324. ret += 2; break;
  1325. // mod cond, op
  1326. case 0x48: {
  1327. // check for repeats of this op
  1328. tmpv = 1; // count
  1329. while (PROGRAM(*pc) == op && (op & 7) != 6) {
  1330. (*pc)++; tmpv++;
  1331. n_in_ops++;
  1332. }
  1333. if ((op&0xf0) != 0) // !always
  1334. tr_make_dirty_ST();
  1335. tmpv2 = tr_cond_check(op);
  1336. switch (op & 7) {
  1337. case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
  1338. case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
  1339. case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
  1340. case 7: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_EOR,0,5,1,31,A_AM1_ASR,5); // eor r1, r5, r5, asr #31
  1341. EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
  1342. hostreg_r[1] = -1; break; // abs
  1343. default: tr_unhandled();
  1344. }
  1345. hostreg_sspreg_changed(SSP_A);
  1346. dirty_regb |= KRREG_ST;
  1347. known_regb &= ~KRREG_ST;
  1348. known_regb &= ~(KRREG_A|KRREG_AL);
  1349. ret += tmpv; break;
  1350. }
  1351. // mpys?
  1352. case 0x1b:
  1353. tr_flush_dirty_P();
  1354. tr_mac_load_XY(op);
  1355. tr_make_dirty_ST();
  1356. EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
  1357. hostreg_sspreg_changed(SSP_A);
  1358. known_regb &= ~(KRREG_A|KRREG_AL);
  1359. dirty_regb |= KRREG_ST;
  1360. ret++; break;
  1361. // mpya (rj), (ri), b
  1362. case 0x4b:
  1363. tr_flush_dirty_P();
  1364. tr_mac_load_XY(op);
  1365. tr_make_dirty_ST();
  1366. EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
  1367. hostreg_sspreg_changed(SSP_A);
  1368. known_regb &= ~(KRREG_A|KRREG_AL);
  1369. dirty_regb |= KRREG_ST;
  1370. ret++; break;
  1371. // mld (rj), (ri), b
  1372. case 0x5b:
  1373. EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
  1374. hostreg_sspreg_changed(SSP_A);
  1375. known_regs.gr[SSP_A].v = 0;
  1376. known_regb |= (KRREG_A|KRREG_AL);
  1377. dirty_regb |= KRREG_ST;
  1378. tr_mac_load_XY(op);
  1379. ret++; break;
  1380. // OP a, s
  1381. case 0x10:
  1382. case 0x30:
  1383. case 0x40:
  1384. case 0x50:
  1385. case 0x60:
  1386. case 0x70:
  1387. tmpv = op & 0xf; // src
  1388. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1389. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1390. if (tmpv == SSP_P) {
  1391. tr_flush_dirty_P();
  1392. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
  1393. } else if (tmpv == SSP_A) {
  1394. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
  1395. } else {
  1396. tr_read_funcs[tmpv](op);
  1397. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
  1398. }
  1399. hostreg_sspreg_changed(SSP_A);
  1400. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1401. dirty_regb |= KRREG_ST;
  1402. ret++; break;
  1403. // OP a, (ri)
  1404. case 0x11:
  1405. case 0x31:
  1406. case 0x41:
  1407. case 0x51:
  1408. case 0x61:
  1409. case 0x71:
  1410. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1411. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1412. tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
  1413. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
  1414. hostreg_sspreg_changed(SSP_A);
  1415. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1416. dirty_regb |= KRREG_ST;
  1417. ret++; break;
  1418. // OP a, adr
  1419. case 0x13:
  1420. case 0x33:
  1421. case 0x43:
  1422. case 0x53:
  1423. case 0x63:
  1424. case 0x73:
  1425. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1426. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1427. tr_bank_read(op&0x1ff);
  1428. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
  1429. hostreg_sspreg_changed(SSP_A);
  1430. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1431. dirty_regb |= KRREG_ST;
  1432. ret++; break;
  1433. // OP a, imm
  1434. case 0x14:
  1435. case 0x34:
  1436. case 0x44:
  1437. case 0x54:
  1438. case 0x64:
  1439. case 0x74:
  1440. tmpv = (op & 0xf0) >> 4;
  1441. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1442. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1443. tr_mov16(0, imm);
  1444. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
  1445. hostreg_sspreg_changed(SSP_A);
  1446. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1447. dirty_regb |= KRREG_ST;
  1448. ret += 2; break;
  1449. // OP a, ((ri))
  1450. case 0x15:
  1451. case 0x35:
  1452. case 0x45:
  1453. case 0x55:
  1454. case 0x65:
  1455. case 0x75:
  1456. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1457. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1458. tr_rX_read2(op);
  1459. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
  1460. hostreg_sspreg_changed(SSP_A);
  1461. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1462. dirty_regb |= KRREG_ST;
  1463. ret += 3; break;
  1464. // OP a, ri
  1465. case 0x19:
  1466. case 0x39:
  1467. case 0x49:
  1468. case 0x59:
  1469. case 0x69:
  1470. case 0x79: {
  1471. int r;
  1472. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1473. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1474. r = (op&3) | ((op>>6)&4); // src
  1475. if ((r&3) == 3) tr_unhandled();
  1476. if (known_regb & (1 << (r+8))) {
  1477. EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
  1478. } else {
  1479. int reg = (r < 4) ? 8 : 9;
  1480. if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
  1481. EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
  1482. EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
  1483. hostreg_r[0] = -1;
  1484. }
  1485. hostreg_sspreg_changed(SSP_A);
  1486. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1487. dirty_regb |= KRREG_ST;
  1488. ret++; break;
  1489. }
  1490. // OP simm
  1491. case 0x1c:
  1492. case 0x3c:
  1493. case 0x4c:
  1494. case 0x5c:
  1495. case 0x6c:
  1496. case 0x7c:
  1497. tmpv2 = tr_aop_ssp2arm(op>>13); // op
  1498. tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
  1499. EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
  1500. hostreg_sspreg_changed(SSP_A);
  1501. known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
  1502. dirty_regb |= KRREG_ST;
  1503. ret++; break;
  1504. }
  1505. n_in_ops++;
  1506. return ret;
  1507. }
  1508. static void emit_block_prologue(void)
  1509. {
  1510. // check if there are enough cycles..
  1511. // note: r0 must contain PC of current block
  1512. EOP_CMP_IMM(11,0,0); // cmp r11, #0
  1513. emith_jump_cond(A_COND_LE, ssp_drc_end);
  1514. }
  1515. /* cond:
  1516. * >0: direct (un)conditional jump
  1517. * <0: indirect jump
  1518. */
  1519. static void *emit_block_epilogue(int cycles, int cond, int pc, int end_pc)
  1520. {
  1521. void *end_ptr = NULL;
  1522. if (cycles > 0xff) {
  1523. elprintf(EL_ANOMALY, "large cycle count: %i\n", cycles);
  1524. cycles = 0xff;
  1525. }
  1526. EOP_SUB_IMM(11,11,0,cycles); // sub r11, r11, #cycles
  1527. if (cond < 0 || (end_pc >= 0x400 && pc < 0x400)) {
  1528. // indirect jump, or rom -> iram jump, must use dispatcher
  1529. emith_jump(ssp_drc_next);
  1530. }
  1531. else if (cond == A_COND_AL) {
  1532. u32 *target = (pc < 0x400) ?
  1533. ssp_block_table_iram[ssp->drc.iram_context * SSP_BLOCKTAB_IRAM_ONE + pc] :
  1534. ssp_block_table[pc];
  1535. if (target != NULL)
  1536. emith_jump(target);
  1537. else
  1538. emith_jump(ssp_drc_next);
  1539. }
  1540. else {
  1541. u32 *target1 = (pc < 0x400) ?
  1542. ssp_block_table_iram[ssp->drc.iram_context * SSP_BLOCKTAB_IRAM_ONE + pc] :
  1543. ssp_block_table[pc];
  1544. u32 *target2 = (end_pc < 0x400) ?
  1545. ssp_block_table_iram[ssp->drc.iram_context * SSP_BLOCKTAB_IRAM_ONE + end_pc] :
  1546. ssp_block_table[end_pc];
  1547. if (target1 != NULL)
  1548. emith_jump_cond(cond, target1);
  1549. if (target2 != NULL)
  1550. emith_jump_cond(tr_neg_cond(cond), target2); // neg_cond, to be able to swap jumps if needed
  1551. #ifndef __EPOC32__
  1552. // emit patchable branches
  1553. if (target1 == NULL)
  1554. emith_call_cond(cond, ssp_drc_next_patch);
  1555. if (target2 == NULL)
  1556. emith_call_cond(tr_neg_cond(cond), ssp_drc_next_patch);
  1557. #else
  1558. // won't patch indirect jumps
  1559. if (target1 == NULL || target2 == NULL)
  1560. emith_jump(ssp_drc_next);
  1561. #endif
  1562. }
  1563. if (end_ptr == NULL)
  1564. end_ptr = tcache_ptr;
  1565. return end_ptr;
  1566. }
  1567. void *ssp_translate_block(int pc)
  1568. {
  1569. unsigned int op, op1, imm, ccount = 0;
  1570. unsigned int *block_start, *block_end;
  1571. int ret, end_cond = A_COND_AL, jump_pc = -1;
  1572. //printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
  1573. block_start = tcache_ptr;
  1574. known_regb = 0;
  1575. dirty_regb = KRREG_P;
  1576. known_regs.emu_status = 0;
  1577. hostreg_clear();
  1578. emit_block_prologue();
  1579. for (; ccount < 100;)
  1580. {
  1581. op = PROGRAM(pc++);
  1582. op1 = op >> 9;
  1583. imm = (u32)-1;
  1584. if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
  1585. imm = PROGRAM(pc++); // immediate
  1586. ret = translate_op(op, &pc, imm, &end_cond, &jump_pc);
  1587. if (ret <= 0)
  1588. {
  1589. elprintf(EL_ANOMALY, "NULL func! op=%08x (%02x)\n", op, op1);
  1590. //exit(1);
  1591. }
  1592. ccount += ret & 0xffff;
  1593. if (ret & 0x10000) break;
  1594. }
  1595. if (ccount >= 100) {
  1596. end_cond = A_COND_AL;
  1597. jump_pc = pc;
  1598. emith_move_r_imm(0, pc);
  1599. }
  1600. tr_flush_dirty_prs();
  1601. tr_flush_dirty_ST();
  1602. tr_flush_dirty_pmcrs();
  1603. block_end = emit_block_epilogue(ccount, end_cond, jump_pc, pc);
  1604. emith_pool_commit(0);
  1605. emith_flush();
  1606. if (tcache_ptr - (u32 *)tcache > DRC_TCACHE_SIZE/4) {
  1607. elprintf(EL_ANOMALY|EL_STATUS|EL_SVP, "tcache overflow!\n");
  1608. fflush(stdout);
  1609. exit(1);
  1610. }
  1611. // stats
  1612. nblocks++;
  1613. //printf("%i blocks, %i bytes, k=%.3f\n", nblocks, (tcache_ptr - tcache)*4,
  1614. // (double)(tcache_ptr - tcache) / (double)n_in_ops);
  1615. #ifdef DUMP_BLOCK
  1616. {
  1617. FILE *f = fopen("tcache.bin", "wb");
  1618. fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
  1619. fclose(f);
  1620. }
  1621. printf("dumped tcache.bin\n");
  1622. exit(0);
  1623. #endif
  1624. #ifdef __arm__
  1625. cache_flush_d_inval_i(block_start, block_end);
  1626. #endif
  1627. return block_start;
  1628. }
  1629. // -----------------------------------------------------
  1630. static void ssp1601_state_load(void)
  1631. {
  1632. ssp->drc.iram_dirty = 1;
  1633. ssp->drc.iram_context = 0;
  1634. }
  1635. void ssp1601_dyn_exit(void)
  1636. {
  1637. free(ssp_block_table);
  1638. free(ssp_block_table_iram);
  1639. ssp_block_table = ssp_block_table_iram = NULL;
  1640. drc_cmn_cleanup();
  1641. }
  1642. int ssp1601_dyn_startup(void)
  1643. {
  1644. drc_cmn_init();
  1645. ssp_block_table = calloc(sizeof(ssp_block_table[0]), SSP_BLOCKTAB_ENTS);
  1646. if (ssp_block_table == NULL)
  1647. return -1;
  1648. ssp_block_table_iram = calloc(sizeof(ssp_block_table_iram[0]), SSP_BLOCKTAB_IRAM_ENTS);
  1649. if (ssp_block_table_iram == NULL) {
  1650. free(ssp_block_table);
  1651. return -1;
  1652. }
  1653. memset(tcache, 0, DRC_TCACHE_SIZE);
  1654. tcache_ptr = (void *)tcache;
  1655. PicoLoadStateHook = ssp1601_state_load;
  1656. n_in_ops = 0;
  1657. #ifdef __arm__
  1658. // hle'd blocks
  1659. ssp_block_table[0x800/2] = (void *) ssp_hle_800;
  1660. ssp_block_table[0x902/2] = (void *) ssp_hle_902;
  1661. ssp_block_table_iram[ 7 * SSP_BLOCKTAB_IRAM_ONE + 0x030/2] = (void *) ssp_hle_07_030;
  1662. ssp_block_table_iram[ 7 * SSP_BLOCKTAB_IRAM_ONE + 0x036/2] = (void *) ssp_hle_07_036;
  1663. ssp_block_table_iram[ 7 * SSP_BLOCKTAB_IRAM_ONE + 0x6d6/2] = (void *) ssp_hle_07_6d6;
  1664. ssp_block_table_iram[11 * SSP_BLOCKTAB_IRAM_ONE + 0x12c/2] = (void *) ssp_hle_11_12c;
  1665. ssp_block_table_iram[11 * SSP_BLOCKTAB_IRAM_ONE + 0x384/2] = (void *) ssp_hle_11_384;
  1666. ssp_block_table_iram[11 * SSP_BLOCKTAB_IRAM_ONE + 0x38a/2] = (void *) ssp_hle_11_38a;
  1667. #endif
  1668. return 0;
  1669. }
  1670. void ssp1601_dyn_reset(ssp1601_t *ssp)
  1671. {
  1672. ssp1601_reset(ssp);
  1673. ssp->drc.iram_dirty = 1;
  1674. ssp->drc.iram_context = 0;
  1675. // must do this here because ssp is not available @ startup()
  1676. ssp->drc.ptr_rom = (u32) Pico.rom;
  1677. ssp->drc.ptr_iram_rom = (u32) svp->iram_rom;
  1678. ssp->drc.ptr_dram = (u32) svp->dram;
  1679. ssp->drc.ptr_btable = (u32) ssp_block_table;
  1680. ssp->drc.ptr_btable_iram = (u32) ssp_block_table_iram;
  1681. // prevent new versions of IRAM from appearing
  1682. memset(svp->iram_rom, 0, 0x800);
  1683. }
  1684. void ssp1601_dyn_run(int cycles)
  1685. {
  1686. if (ssp->emu_status & SSP_WAIT_MASK) return;
  1687. #ifdef DUMP_BLOCK
  1688. ssp_translate_block(DUMP_BLOCK >> 1);
  1689. #endif
  1690. #ifdef __arm__
  1691. ssp_drc_entry(ssp, cycles);
  1692. #endif
  1693. }