svp compiler: block ref counter version
[picodrive.git] / Pico / carthw / svp / compiler.c
CommitLineData
726bbb3e 1
2#include "../../PicoInt.h"
e807ac75 3#include "compiler.h"
726bbb3e 4
892b1dd2 5static unsigned int *block_table[0x5090/2];
6static unsigned int *block_table_iram[15][0x800/2];
13aba3fe 7static unsigned int block_ref[0x5090/2];
8static unsigned int block_ref_iram[15][0x800/2];
892b1dd2 9static unsigned int *tcache_ptr = NULL;
726bbb3e 10
726bbb3e 11static int nblocks = 0;
df143b36 12static int iram_context = 0;
726bbb3e 13
5d817c91 14#ifndef ARM
0b5e8296 15#define DUMP_BLOCK 0x0c9a
5d817c91 16unsigned int tcache[512*1024];
17void regfile_load(void){}
18void regfile_store(void){}
19#endif
20
726bbb3e 21#define EMBED_INTERPRETER
22#define ssp1601_reset ssp1601_reset_local
23#define ssp1601_run ssp1601_run_local
24
5c129565 25#define GET_PC() rPC
26#define GET_PPC_OFFS() (GET_PC()*2 - 2)
d274c33b 27#define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
726bbb3e 28//#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
29//#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
30//#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
31
32#include "ssp16.c"
5c129565 33#include "gen_arm.c"
726bbb3e 34
35// -----------------------------------------------------
36
892b1dd2 37// ld d, s
38static void op00(unsigned int op, unsigned int imm)
39{
40 unsigned int tmpv;
259ed0ea 41 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
892b1dd2 42 if (op == 0) return; // nop
43 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
44 // not sure. MAME claims that only hi word is transfered.
45 read_P(); // update P
46 rA32 = rP.v;
47 }
48 else
49 {
50 tmpv = REG_READ(op & 0x0f);
51 REG_WRITE((op & 0xf0) >> 4, tmpv);
52 }
53}
54
55// ld d, (ri)
56static void op01(unsigned int op, unsigned int imm)
57{
58 unsigned int tmpv;
59 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
60}
61
62// ld (ri), s
63static void op02(unsigned int op, unsigned int imm)
64{
65 unsigned int tmpv;
66 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
67}
68
69// ldi d, imm
70static void op04(unsigned int op, unsigned int imm)
71{
72 REG_WRITE((op & 0xf0) >> 4, imm);
73}
74
75// ld d, ((ri))
76static void op05(unsigned int op, unsigned int imm)
77{
78 unsigned int tmpv;
79 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
80}
81
82// ldi (ri), imm
83static void op06(unsigned int op, unsigned int imm)
84{
85 ptr1_write(op, imm);
86}
87
88// ld adr, a
89static void op07(unsigned int op, unsigned int imm)
90{
91 ssp->RAM[op & 0x1ff] = rA;
92}
93
94// ld d, ri
95static void op09(unsigned int op, unsigned int imm)
96{
97 unsigned int tmpv;
98 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
99}
100
101// ld ri, s
102static void op0a(unsigned int op, unsigned int imm)
103{
104 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
105}
106
107// ldi ri, simm (also op0d op0e op0f)
108static void op0c(unsigned int op, unsigned int imm)
109{
110 rIJ[(op>>8)&7] = op;
111}
112
113// call cond, addr
114static void op24(unsigned int op, unsigned int imm)
115{
116 int cond = 0;
117 do {
118 COND_CHECK
259ed0ea 119 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
892b1dd2 120 }
121 while (0);
122}
123
124// ld d, (a)
125static void op25(unsigned int op, unsigned int imm)
126{
127 unsigned int tmpv;
128 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
129}
130
131// bra cond, addr
132static void op26(unsigned int op, unsigned int imm)
133{
134 do
135 {
136 int cond = 0;
137 COND_CHECK
259ed0ea 138 if (cond) SET_PC(imm);
892b1dd2 139 }
259ed0ea 140 while (0);
892b1dd2 141}
142
143// mod cond, op
144static void op48(unsigned int op, unsigned int imm)
145{
146 do
147 {
148 int cond = 0;
149 COND_CHECK
150 if (cond) {
151 switch (op & 7) {
152 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
153 case 3: rA32 <<= 1; break; // shl
154 case 6: rA32 = -(signed int)rA32; break; // neg
155 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
156 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
157 op&7, GET_PPC_OFFS());
158 }
159 UPD_ACC_ZN // ?
160 }
161 }
162 while(0);
163}
164
165// mpys?
166static void op1b(unsigned int op, unsigned int imm)
167{
168 read_P(); // update P
169 rA32 -= rP.v; // maybe only upper word?
170 UPD_ACC_ZN // there checking flags after this
171 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
172 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
173}
174
175// mpya (rj), (ri), b
176static void op4b(unsigned int op, unsigned int imm)
177{
178 read_P(); // update P
179 rA32 += rP.v; // confirmed to be 32bit
180 UPD_ACC_ZN // ?
181 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
182 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
183}
184
185// mld (rj), (ri), b
186static void op5b(unsigned int op, unsigned int imm)
187{
188 rA32 = 0;
189 rST &= 0x0fff; // ?
190 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
191 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
192}
193
194// OP a, s
195static void op10(unsigned int op, unsigned int imm)
196{
197 do
198 {
199 unsigned int tmpv;
200 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
201 }
202 while(0);
203}
204
205static void op30(unsigned int op, unsigned int imm)
206{
207 do
208 {
209 unsigned int tmpv;
210 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
211 }
212 while(0);
213}
214
215static void op40(unsigned int op, unsigned int imm)
216{
217 do
218 {
219 unsigned int tmpv;
220 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
221 }
222 while(0);
223}
224
225static void op50(unsigned int op, unsigned int imm)
226{
227 do
228 {
229 unsigned int tmpv;
230 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
231 }
232 while(0);
233}
234
235static void op60(unsigned int op, unsigned int imm)
236{
237 do
238 {
239 unsigned int tmpv;
240 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
241 }
242 while(0);
243}
244
245static void op70(unsigned int op, unsigned int imm)
246{
247 do
248 {
249 unsigned int tmpv;
250 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
251 }
252 while(0);
253}
254
255// OP a, (ri)
256static void op11(unsigned int op, unsigned int imm)
257{
258 unsigned int tmpv;
259 tmpv = ptr1_read(op); OP_SUBA(tmpv);
260}
261
262static void op31(unsigned int op, unsigned int imm)
263{
264 unsigned int tmpv;
265 tmpv = ptr1_read(op); OP_CMPA(tmpv);
266}
267
268static void op41(unsigned int op, unsigned int imm)
269{
270 unsigned int tmpv;
271 tmpv = ptr1_read(op); OP_ADDA(tmpv);
272}
273
274static void op51(unsigned int op, unsigned int imm)
275{
276 unsigned int tmpv;
277 tmpv = ptr1_read(op); OP_ANDA(tmpv);
278}
279
280static void op61(unsigned int op, unsigned int imm)
281{
282 unsigned int tmpv;
283 tmpv = ptr1_read(op); OP_ORA (tmpv);
284}
285
286static void op71(unsigned int op, unsigned int imm)
287{
288 unsigned int tmpv;
289 tmpv = ptr1_read(op); OP_EORA(tmpv);
290}
291
292// OP a, adr
293static void op03(unsigned int op, unsigned int imm)
294{
295 unsigned int tmpv;
296 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
297}
298
299static void op13(unsigned int op, unsigned int imm)
300{
301 unsigned int tmpv;
302 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
303}
304
305static void op33(unsigned int op, unsigned int imm)
306{
307 unsigned int tmpv;
308 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
309}
310
311static void op43(unsigned int op, unsigned int imm)
312{
313 unsigned int tmpv;
314 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
315}
316
317static void op53(unsigned int op, unsigned int imm)
318{
319 unsigned int tmpv;
320 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
321}
322
323static void op63(unsigned int op, unsigned int imm)
324{
325 unsigned int tmpv;
326 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
327}
328
329static void op73(unsigned int op, unsigned int imm)
330{
331 unsigned int tmpv;
332 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
333}
334
335// OP a, imm
336static void op14(unsigned int op, unsigned int imm)
337{
338 OP_SUBA(imm);
339}
340
341static void op34(unsigned int op, unsigned int imm)
342{
343 OP_CMPA(imm);
344}
345
346static void op44(unsigned int op, unsigned int imm)
347{
348 OP_ADDA(imm);
349}
350
351static void op54(unsigned int op, unsigned int imm)
352{
353 OP_ANDA(imm);
354}
355
356static void op64(unsigned int op, unsigned int imm)
357{
358 OP_ORA (imm);
359}
360
361static void op74(unsigned int op, unsigned int imm)
362{
363 OP_EORA(imm);
364}
365
366// OP a, ((ri))
367static void op15(unsigned int op, unsigned int imm)
368{
369 unsigned int tmpv;
370 tmpv = ptr2_read(op); OP_SUBA(tmpv);
371}
372
373static void op35(unsigned int op, unsigned int imm)
374{
375 unsigned int tmpv;
376 tmpv = ptr2_read(op); OP_CMPA(tmpv);
377}
378
379static void op45(unsigned int op, unsigned int imm)
380{
381 unsigned int tmpv;
382 tmpv = ptr2_read(op); OP_ADDA(tmpv);
383}
384
385static void op55(unsigned int op, unsigned int imm)
386{
387 unsigned int tmpv;
388 tmpv = ptr2_read(op); OP_ANDA(tmpv);
389}
390
391static void op65(unsigned int op, unsigned int imm)
392{
393 unsigned int tmpv;
394 tmpv = ptr2_read(op); OP_ORA (tmpv);
395}
396
397static void op75(unsigned int op, unsigned int imm)
398{
399 unsigned int tmpv;
400 tmpv = ptr2_read(op); OP_EORA(tmpv);
401}
402
403// OP a, ri
404static void op19(unsigned int op, unsigned int imm)
405{
406 unsigned int tmpv;
407 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
408}
409
410static void op39(unsigned int op, unsigned int imm)
411{
412 unsigned int tmpv;
413 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
414}
415
416static void op49(unsigned int op, unsigned int imm)
417{
418 unsigned int tmpv;
419 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
420}
421
422static void op59(unsigned int op, unsigned int imm)
423{
424 unsigned int tmpv;
425 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
426}
427
428static void op69(unsigned int op, unsigned int imm)
429{
430 unsigned int tmpv;
431 tmpv = rIJ[IJind]; OP_ORA (tmpv);
432}
433
434static void op79(unsigned int op, unsigned int imm)
435{
436 unsigned int tmpv;
437 tmpv = rIJ[IJind]; OP_EORA(tmpv);
438}
439
440// OP simm
441static void op1c(unsigned int op, unsigned int imm)
442{
443 OP_SUBA(op & 0xff);
444}
445
446static void op3c(unsigned int op, unsigned int imm)
447{
448 OP_CMPA(op & 0xff);
449}
450
451static void op4c(unsigned int op, unsigned int imm)
452{
453 OP_ADDA(op & 0xff);
454}
455
456static void op5c(unsigned int op, unsigned int imm)
457{
458 OP_ANDA(op & 0xff);
459}
460
461static void op6c(unsigned int op, unsigned int imm)
462{
463 OP_ORA (op & 0xff);
464}
465
466static void op7c(unsigned int op, unsigned int imm)
467{
468 OP_EORA(op & 0xff);
469}
470
471typedef void (in_func)(unsigned int op, unsigned int imm);
472
473static in_func *in_funcs[0x80] =
474{
475 op00, op01, op02, op03, op04, op05, op06, op07,
476 NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
477 op10, op11, NULL, op13, op14, op15, NULL, NULL,
478 NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
479 NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
480 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
481 op30, op31, NULL, op33, op34, op35, NULL, NULL,
482 NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
483 op40, op41, NULL, op43, op44, op45, NULL, NULL,
484 op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
485 op50, op51, NULL, op53, op54, op55, NULL, NULL,
486 NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
487 op60, op61, NULL, op63, op64, op65, NULL, NULL,
488 NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
489 op70, op71, NULL, op73, op74, op75, NULL, NULL,
490 NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
491};
492
d5276282 493
494static u32 ssp_pm_read(int reg)
495{
496 u32 d = 0, mode;
497
498 if (ssp->emu_status & SSP_PMC_SET)
499 {
500 ssp->pmac_read[reg] = rPMC.v;
501 ssp->emu_status &= ~SSP_PMC_SET;
d5276282 502 return 0;
503 }
504
d5276282 505 // just in case
506 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
507
508 mode = ssp->pmac_read[reg]>>16;
509 if ((mode & 0xfff0) == 0x0800) // ROM
510 {
511 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
512 ssp->pmac_read[reg] += 1;
513 }
514 else if ((mode & 0x47ff) == 0x0018) // DRAM
515 {
516 unsigned short *dram = (unsigned short *)svp->dram;
517 int inc = get_inc(mode);
518 d = dram[ssp->pmac_read[reg]&0xffff];
519 ssp->pmac_read[reg] += inc;
520 }
521
522 // PMC value corresponds to last PMR accessed
523 rPMC.v = ssp->pmac_read[reg];
524
525 return d;
526}
527
528static void ssp_pm_write(u32 d, int reg)
529{
530 unsigned short *dram;
531 int mode, addr;
532
533 if (ssp->emu_status & SSP_PMC_SET)
534 {
535 ssp->pmac_write[reg] = rPMC.v;
536 ssp->emu_status &= ~SSP_PMC_SET;
537 return;
538 }
539
540 // just in case
541 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
542
543 dram = (unsigned short *)svp->dram;
544 mode = ssp->pmac_write[reg]>>16;
545 addr = ssp->pmac_write[reg]&0xffff;
546 if ((mode & 0x43ff) == 0x0018) // DRAM
547 {
548 int inc = get_inc(mode);
549 if (mode & 0x0400) {
550 overwrite_write(dram[addr], d);
551 } else dram[addr] = d;
552 ssp->pmac_write[reg] += inc;
553 }
554 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
555 {
556 if (mode & 0x0400) {
557 overwrite_write(dram[addr], d);
558 } else dram[addr] = d;
559 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
560 }
561 else if ((mode & 0x47ff) == 0x001c) // IRAM
562 {
563 int inc = get_inc(mode);
564 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
565 ssp->pmac_write[reg] += inc;
e122fae6 566 ssp->drc.iram_dirty = 1;
d5276282 567 }
568
569 rPMC.v = ssp->pmac_write[reg];
570}
571
572
892b1dd2 573// -----------------------------------------------------
574
0b5e8296 575// 14 IRAM blocks
df143b36 576static unsigned char iram_context_map[] =
577{
578 0, 0, 0, 0, 1, 0, 0, 0, // 04
579 0, 0, 0, 0, 0, 0, 2, 0, // 0e
580 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
581 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
582 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
583 0, 0, 0, 0, 0, 0, 0, 0,
584 0, 0,11, 0, 0,12, 0, 0, // 32 35
585 13,14, 0, 0, 0, 0, 0, 0 // 38 39
586};
587
df143b36 588static int get_iram_context(void)
589{
590 unsigned char *ir = (unsigned char *)svp->iram_rom;
591 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
df143b36 592 val1 = iram_context_map[(val>>1)&0x3f];
593
5c129565 594 if (val1 == 0) {
df143b36 595 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
df143b36 596 //debug_dump2file(name, svp->iram_rom, 0x800);
597 exit(1);
598 }
5c129565 599// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
df143b36 600 return val1;
601}
602
5d817c91 603// -----------------------------------------------------
0b5e8296 604
5d817c91 605/* regs with known values */
606static struct
607{
608 ssp_reg_t gr[8];
609 unsigned char r[8];
ede7220f 610 unsigned int pmac_read[5];
611 unsigned int pmac_write[5];
d5276282 612 ssp_reg_t pmc;
ede7220f 613 unsigned int emu_status;
bad5731d 614} known_regs;
615
616#define KRREG_X (1 << SSP_X)
617#define KRREG_Y (1 << SSP_Y)
618#define KRREG_A (1 << SSP_A) /* AH only */
619#define KRREG_ST (1 << SSP_ST)
620#define KRREG_STACK (1 << SSP_STACK)
621#define KRREG_PC (1 << SSP_PC)
622#define KRREG_P (1 << SSP_P)
623#define KRREG_PR0 (1 << 8)
624#define KRREG_PR4 (1 << 12)
625#define KRREG_AL (1 << 16)
d5276282 626#define KRREG_PMCM (1 << 18) /* only mode word of PMC */
627#define KRREG_PMC (1 << 19)
ede7220f 628#define KRREG_PM0R (1 << 20)
629#define KRREG_PM1R (1 << 21)
630#define KRREG_PM2R (1 << 22)
631#define KRREG_PM3R (1 << 23)
632#define KRREG_PM4R (1 << 24)
633#define KRREG_PM0W (1 << 25)
634#define KRREG_PM1W (1 << 26)
635#define KRREG_PM2W (1 << 27)
636#define KRREG_PM3W (1 << 28)
637#define KRREG_PM4W (1 << 29)
bad5731d 638
639/* bitfield of known register values */
640static u32 known_regb = 0;
641
642/* known vals, which need to be flushed
d5276282 643 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
bad5731d 644 * ST means flags are being held in ARM PSR
89fea1e9 645 * P means that it needs to be recalculated
bad5731d 646 */
647static u32 dirty_regb = 0;
5d817c91 648
649/* known values of host regs.
d274c33b 650 * -1 - unknown
651 * 000000-00ffff - 16bit value
652 * 100000-10ffff - base reg (r7) + 16bit val
6e39239f 653 * 0r0000 - means reg (low) eq gr[r].h, r != AL
5d817c91 654 */
655static int hostreg_r[4];
656
657static void hostreg_clear(void)
658{
659 int i;
660 for (i = 0; i < 4; i++)
661 hostreg_r[i] = -1;
662}
663
6e39239f 664static void hostreg_sspreg_changed(int sspreg)
5d817c91 665{
666 int i;
667 for (i = 0; i < 4; i++)
6e39239f 668 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
5d817c91 669}
670
726bbb3e 671
ede7220f 672#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
673#define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
726bbb3e 674
6e39239f 675static void tr_unhandled(void)
676{
677 FILE *f = fopen("tcache.bin", "wb");
678 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
679 fclose(f);
680 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
681 exit(1);
682}
683
0e4d7ba5 684/* update P, if needed. Trashes r0 */
d274c33b 685static void tr_flush_dirty_P(void)
686{
687 // TODO: const regs
bad5731d 688 if (!(dirty_regb & KRREG_P)) return;
d274c33b 689 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
0e4d7ba5 690 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
691 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
692 EOP_MUL(10, 0, 10); // mul r10, r0, r10
bad5731d 693 dirty_regb &= ~KRREG_P;
0e4d7ba5 694 hostreg_r[0] = -1;
d274c33b 695}
696
89fea1e9 697/* write dirty pr to host reg. Nothing is trashed */
698static void tr_flush_dirty_pr(int r)
699{
700 int ror = 0, reg;
6e39239f 701
89fea1e9 702 if (!(dirty_regb & (1 << (r+8)))) return;
703
704 switch (r&3) {
705 case 0: ror = 0; break;
706 case 1: ror = 24/2; break;
707 case 2: ror = 16/2; break;
708 }
709 reg = (r < 4) ? 8 : 9;
710 EOP_BIC_IMM(reg,reg,ror,0xff);
711 if (known_regs.r[r] != 0)
712 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
713 dirty_regb &= ~(1 << (r+8));
714}
715
716/* write all dirty pr0-pr7 to host regs. Nothing is trashed */
717static void tr_flush_dirty_prs(void)
5d817c91 718{
719 int i, ror = 0, reg;
bad5731d 720 int dirty = dirty_regb >> 8;
5d817c91 721 /* r0-r7 */
bad5731d 722 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
5d817c91 723 {
bad5731d 724 if (!(dirty&1)) continue;
5d817c91 725 switch (i&3) {
726 case 0: ror = 0; break;
727 case 1: ror = 24/2; break;
728 case 2: ror = 16/2; break;
729 }
730 reg = (i < 4) ? 8 : 9;
731 EOP_BIC_IMM(reg,reg,ror,0xff);
bad5731d 732 if (known_regs.r[i] != 0)
733 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
5d817c91 734 }
bad5731d 735 dirty_regb &= ~0xff00;
736}
737
89fea1e9 738/* write dirty pr and "forget" it. Nothing is trashed. */
739static void tr_release_pr(int r)
740{
741 tr_flush_dirty_pr(r);
742 known_regb &= ~(1 << (r+8));
743}
744
6e39239f 745/* fush ARM PSR to r6. Trashes r1 */
bad5731d 746static void tr_flush_dirty_ST(void)
747{
748 if (!(dirty_regb & KRREG_ST)) return;
749 EOP_BIC_IMM(6,6,0,0x0f);
6e39239f 750 EOP_MRS(1);
751 EOP_ORR_REG_LSR(6,6,1,28);
bad5731d 752 dirty_regb &= ~KRREG_ST;
6e39239f 753 hostreg_r[1] = -1;
754}
755
756/* inverse of above. Trashes r1 */
757static void tr_make_dirty_ST(void)
758{
759 if (dirty_regb & KRREG_ST) return;
760 if (known_regb & KRREG_ST) {
761 int flags = 0;
762 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
763 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
764 EOP_MSR_IMM(4/2, flags);
765 } else {
766 EOP_MOV_REG_LSL(1, 6, 28);
767 EOP_MSR_REG(1);
768 hostreg_r[1] = -1;
769 }
770 dirty_regb |= KRREG_ST;
bad5731d 771}
772
773/* load 16bit val into host reg r0-r3. Nothing is trashed */
774static void tr_mov16(int r, int val)
775{
776 if (hostreg_r[r] != val) {
777 emit_mov_const(A_COND_AL, r, val);
778 hostreg_r[r] = val;
779 }
780}
781
782static void tr_mov16_cond(int cond, int r, int val)
783{
784 emit_mov_const(cond, r, val);
a6fb500b 785 hostreg_r[r] = -1;
5d817c91 786}
787
ede7220f 788/* trashes r0 */
789static void tr_flush_dirty_pmcrs(void)
790{
791 u32 i, val = (u32)-1;
d5276282 792 if (!(dirty_regb & 0x3ff80000)) return;
ede7220f 793
d5276282 794 if (dirty_regb & KRREG_PMC) {
795 val = known_regs.pmc.v;
e122fae6 796 emit_mov_const(A_COND_AL, 1, val);
797 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
ede7220f 798
d5276282 799 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
800 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
801 tr_unhandled();
802 }
ede7220f 803 }
804 for (i = 0; i < 5; i++)
805 {
d5276282 806 if (dirty_regb & (1 << (20+i))) {
ede7220f 807 if (val != known_regs.pmac_read[i]) {
808 val = known_regs.pmac_read[i];
e122fae6 809 emit_mov_const(A_COND_AL, 1, val);
ede7220f 810 }
e122fae6 811 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
ede7220f 812 }
d5276282 813 if (dirty_regb & (1 << (25+i))) {
ede7220f 814 if (val != known_regs.pmac_write[i]) {
815 val = known_regs.pmac_write[i];
e122fae6 816 emit_mov_const(A_COND_AL, 1, val);
ede7220f 817 }
e122fae6 818 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
ede7220f 819 }
820 }
d5276282 821 dirty_regb &= ~0x3ff80000;
e122fae6 822 hostreg_r[1] = -1;
ede7220f 823}
824
0e4d7ba5 825/* read bank word to r0 (upper bits zero). Thrashes r1. */
5d817c91 826static void tr_bank_read(int addr) /* word addr 0-0x1ff */
827{
bad5731d 828 int breg = 7;
829 if (addr > 0x7f) {
830 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
831 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
832 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 833 }
bad5731d 834 breg = 1;
5d817c91 835 }
bad5731d 836 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
5d817c91 837 hostreg_r[0] = -1;
838}
839
840/* write r0 to bank. Trashes r1. */
841static void tr_bank_write(int addr)
842{
843 int breg = 7;
844 if (addr > 0x7f) {
d274c33b 845 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 846 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 847 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 848 }
849 breg = 1;
850 }
b9c1d012 851 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 852}
853
89fea1e9 854/* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
855static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
5d817c91 856{
a6fb500b 857 int modulo_shift = -1; /* unknown */
5d817c91 858
859 if (mod == 0) return;
860
861 if (!need_modulo || mod == 1) // +!
862 modulo_shift = 8;
bad5731d 863 else if (need_modulo && (known_regb & KRREG_ST)) {
864 modulo_shift = known_regs.gr[SSP_ST].h & 7;
5d817c91 865 if (modulo_shift == 0) modulo_shift = 8;
866 }
867
89fea1e9 868 if (modulo_shift == -1)
869 {
a6fb500b 870 int reg = (r < 4) ? 8 : 9;
89fea1e9 871 tr_release_pr(r);
0e4d7ba5 872 if (dirty_regb & KRREG_ST) {
873 // avoid flushing ARM flags
874 EOP_AND_IMM(1, 6, 0, 0x70);
875 EOP_SUB_IMM(1, 1, 0, 0x10);
876 EOP_AND_IMM(1, 1, 0, 0x70);
877 EOP_ADD_IMM(1, 1, 0, 0x10);
878 } else {
879 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
880 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
881 }
89fea1e9 882 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
883 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
884 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
885 if (r&3)
886 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
887 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
888 if (mod == 2)
889 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
890 else EOP_ADD_REG2_LSL(reg,reg,3,2);
891 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
892 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
893 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
a6fb500b 894 }
895 else if (known_regb & (1 << (r + 8)))
896 {
897 int modulo = (1 << modulo_shift) - 1;
5d817c91 898 if (mod == 2)
89fea1e9 899 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
900 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
a6fb500b 901 }
902 else
903 {
5d817c91 904 int reg = (r < 4) ? 8 : 9;
905 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
906 EOP_MOV_REG_ROR(reg,reg,ror);
907 // {add|sub} reg, reg, #1<<shift
89fea1e9 908 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
5d817c91 909 EOP_MOV_REG_ROR(reg,reg,32-ror);
910 }
911}
912
bad5731d 913/* handle writes r0 to (rX). Trashes r1.
914 * fortunately we can ignore modulo increment modes for writes. */
0e4d7ba5 915static void tr_rX_write(int op)
bad5731d 916{
917 if ((op&3) == 3)
918 {
919 int mod = (op>>2) & 3; // direct addressing
920 tr_bank_write((op & 0x100) + mod);
921 }
922 else
923 {
924 int r = (op&3) | ((op>>6)&4);
925 if (known_regb & (1 << (r + 8))) {
926 tr_bank_write((op&0x100) | known_regs.r[r]);
927 } else {
928 int reg = (r < 4) ? 8 : 9;
929 int ror = ((4 - (r&3))*8) & 0x1f;
930 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
931 if (r >= 4)
932 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
933 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
934 else EOP_ADD_REG_LSL(1,7,1,1);
935 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
936 hostreg_r[1] = -1;
937 }
89fea1e9 938 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
939 }
940}
941
942/* read (rX) to r0. Trashes r1-r3. */
943static void tr_rX_read(int r, int mod)
944{
945 if ((r&3) == 3)
946 {
947 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
948 }
949 else
950 {
951 if (known_regb & (1 << (r + 8))) {
6e39239f 952 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
89fea1e9 953 } else {
954 int reg = (r < 4) ? 8 : 9;
955 int ror = ((4 - (r&3))*8) & 0x1f;
956 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
957 if (r >= 4)
958 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
959 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
960 else EOP_ADD_REG_LSL(1,7,1,1);
961 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
0e4d7ba5 962 hostreg_r[0] = hostreg_r[1] = -1;
89fea1e9 963 }
964 tr_ptrr_mod(r, mod, 1, 1);
bad5731d 965 }
966}
967
0e4d7ba5 968/* read ((rX)) to r0. Trashes r1,r2. */
969static void tr_rX_read2(int op)
970{
971 int r = (op&3) | ((op>>6)&4); // src
972
973 if ((r&3) == 3) {
974 tr_bank_read((op&0x100) | ((op>>2)&3));
975 } else if (known_regb & (1 << (r+8))) {
976 tr_bank_read((op&0x100) | known_regs.r[r]);
977 } else {
978 int reg = (r < 4) ? 8 : 9;
979 int ror = ((4 - (r&3))*8) & 0x1f;
980 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
981 if (r >= 4)
982 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
983 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
984 else EOP_ADD_REG_LSL(1,7,1,1);
985 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
986 }
987 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
988 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
989 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
990 if ((r&3) == 3) {
991 tr_bank_write((op&0x100) | ((op>>2)&3));
992 } else if (known_regb & (1 << (r+8))) {
993 tr_bank_write((op&0x100) | known_regs.r[r]);
994 } else {
995 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
996 hostreg_r[1] = -1;
997 }
998 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
999 hostreg_r[0] = hostreg_r[2] = -1;
1000}
89fea1e9 1001
bad5731d 1002/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1003static int tr_cond_check(int op)
1004{
6e39239f 1005 int f = (op & 0x100) >> 8;
bad5731d 1006 switch (op&0xf0) {
1007 case 0x00: return A_COND_AL; /* always true */
1008 case 0x50: /* Z matches f(?) bit */
1009 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1010 EOP_TST_IMM(6, 0, 4);
1011 return f ? A_COND_NE : A_COND_EQ;
1012 case 0x70: /* N matches f(?) bit */
1013 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1014 EOP_TST_IMM(6, 0, 8);
1015 return f ? A_COND_NE : A_COND_EQ;
1016 default:
1017 printf("unimplemented cond?\n");
6e39239f 1018 tr_unhandled();
bad5731d 1019 return 0;
1020 }
1021}
1022
1023static int tr_neg_cond(int cond)
1024{
1025 switch (cond) {
1026 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1027 case A_COND_EQ: return A_COND_NE;
1028 case A_COND_NE: return A_COND_EQ;
1029 case A_COND_MI: return A_COND_PL;
1030 case A_COND_PL: return A_COND_MI;
1031 default: printf("bad cond for neg\n"); exit(1);
1032 }
1033 return 0;
1034}
1035
ede7220f 1036static int tr_aop_ssp2arm(int op)
1037{
1038 switch (op) {
1039 case 1: return A_OP_SUB;
1040 case 3: return A_OP_CMP;
1041 case 4: return A_OP_ADD;
1042 case 5: return A_OP_AND;
1043 case 6: return A_OP_ORR;
1044 case 7: return A_OP_EOR;
1045 }
1046
1047 tr_unhandled();
1048 return 0;
1049}
1050
1051// -----------------------------------------------------
1052
b9c1d012 1053//@ r4: XXYY
1054//@ r5: A
1055//@ r6: STACK and emu flags
1056//@ r7: SSP context
1057//@ r10: P
1058
bad5731d 1059// read general reg to r0. Trashes r1
d5276282 1060static void tr_GR0_to_r0(int op)
d274c33b 1061{
1062 tr_mov16(0, 0xffff);
1063}
1064
d5276282 1065static void tr_X_to_r0(int op)
d274c33b 1066{
1067 if (hostreg_r[0] != (SSP_X<<16)) {
1068 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1069 hostreg_r[0] = SSP_X<<16;
1070 }
1071}
1072
d5276282 1073static void tr_Y_to_r0(int op)
d274c33b 1074{
d274c33b 1075 if (hostreg_r[0] != (SSP_Y<<16)) {
1076 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1077 hostreg_r[0] = SSP_Y<<16;
1078 }
1079}
1080
d5276282 1081static void tr_A_to_r0(int op)
d274c33b 1082{
1083 if (hostreg_r[0] != (SSP_A<<16)) {
1084 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1085 hostreg_r[0] = SSP_A<<16;
1086 }
1087}
1088
d5276282 1089static void tr_ST_to_r0(int op)
d274c33b 1090{
1091 // VR doesn't need much accuracy here..
1092 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1093 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1094 hostreg_r[0] = -1;
1095}
1096
d5276282 1097static void tr_STACK_to_r0(int op)
d274c33b 1098{
1099 // 448
1100 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1101 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1102 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1103 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1104 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1105 hostreg_r[0] = hostreg_r[1] = -1;
1106}
1107
d5276282 1108static void tr_PC_to_r0(int op)
d274c33b 1109{
bad5731d 1110 tr_mov16(0, known_regs.gr[SSP_PC].h);
d274c33b 1111}
1112
d5276282 1113static void tr_P_to_r0(int op)
d274c33b 1114{
1115 tr_flush_dirty_P();
1116 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1117 hostreg_r[0] = -1;
1118}
d5276282 1119
1120static void tr_AL_to_r0(int op)
ede7220f 1121{
d5276282 1122 if (op == 0x000f) {
1123 if (known_regb & KRREG_PMC) {
1124 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1125 } else {
1126 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1127 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1128 EOP_STR_IMM(0,7,0x484);
1129 }
1130 }
1131
1132 if (hostreg_r[0] != (SSP_AL<<16)) {
1133 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1134 hostreg_r[0] = SSP_AL<<16;
1135 }
ede7220f 1136}
ede7220f 1137
d5276282 1138static void tr_PMX_to_r0(int reg)
ede7220f 1139{
ede7220f 1140 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1141 {
d5276282 1142 known_regs.pmac_read[reg] = known_regs.pmc.v;
ede7220f 1143 known_regs.emu_status &= ~SSP_PMC_SET;
0336d643 1144 known_regb |= 1 << (20+reg);
d5276282 1145 dirty_regb |= 1 << (20+reg);
1146 return;
ede7220f 1147 }
1148
d5276282 1149 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
ede7220f 1150 {
d5276282 1151 u32 pmcv = known_regs.pmac_read[reg];
1152 int mode = pmcv>>16;
1153 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1154
ede7220f 1155 if ((mode & 0xfff0) == 0x0800)
1156 {
ede7220f 1157 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1158 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1159 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
d5276282 1160 known_regs.pmac_read[reg] += 1;
ede7220f 1161 }
1162 else if ((mode & 0x47ff) == 0x0018) // DRAM
1163 {
1164 int inc = get_inc(mode);
ede7220f 1165 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1166 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1167 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
d5276282 1168 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
ede7220f 1169 {
1170 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1171 tr_flush_dirty_ST();
1172 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1173 EOP_TST_REG_SIMPLE(0,0);
d5276282 1174 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1175 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
ede7220f 1176 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1177 }
d5276282 1178 known_regs.pmac_read[reg] += inc;
ede7220f 1179 }
1180 else
1181 {
1182 tr_unhandled();
1183 }
d5276282 1184 known_regs.pmc.v = known_regs.pmac_read[reg];
1185 //known_regb |= KRREG_PMC;
1186 dirty_regb |= KRREG_PMC;
1187 dirty_regb |= 1 << (20+reg);
1188 hostreg_r[0] = hostreg_r[1] = -1;
1189 return;
1190 }
ede7220f 1191
d5276282 1192 known_regb &= ~KRREG_PMC;
1193 dirty_regb &= ~KRREG_PMC;
1194 known_regb &= ~(1 << (20+reg));
1195 dirty_regb &= ~(1 << (20+reg));
1196
1197 // call the C code to handle this
1198 tr_flush_dirty_ST();
1199 //tr_flush_dirty_pmcrs();
1200 tr_mov16(0, reg);
1201 emit_call(ssp_pm_read);
1202 hostreg_clear();
1203}
1204
1205static void tr_PM0_to_r0(int op)
1206{
1207 tr_PMX_to_r0(0);
1208}
1209
1210static void tr_PM1_to_r0(int op)
1211{
1212 tr_PMX_to_r0(1);
1213}
1214
1215static void tr_PM2_to_r0(int op)
1216{
1217 tr_PMX_to_r0(2);
1218}
1219
1220static void tr_XST_to_r0(int op)
1221{
1222 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1223 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1224}
1225
1226static void tr_PM4_to_r0(int op)
1227{
1228 tr_PMX_to_r0(4);
1229}
1230
1231static void tr_PMC_to_r0(int op)
1232{
1233 if (known_regb & KRREG_PMC)
1234 {
1235 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1236 known_regs.emu_status |= SSP_PMC_SET;
1237 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1238 // do nothing - this is handled elsewhere
1239 } else {
1240 tr_mov16(0, known_regs.pmc.l);
1241 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1242 }
1243 }
1244 else
1245 {
1246 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1247 tr_flush_dirty_ST();
1248 if (op != 0x000e)
1249 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1250 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1251 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1252 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1253 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1254 EOP_STR_IMM(1,7,0x484);
1255 hostreg_r[0] = hostreg_r[1] = -1;
ede7220f 1256 }
ede7220f 1257}
1258
d274c33b 1259
d5276282 1260typedef void (tr_read_func)(int op);
d274c33b 1261
d5276282 1262static tr_read_func *tr_read_funcs[16] =
d274c33b 1263{
1264 tr_GR0_to_r0,
1265 tr_X_to_r0,
1266 tr_Y_to_r0,
1267 tr_A_to_r0,
1268 tr_ST_to_r0,
1269 tr_STACK_to_r0,
1270 tr_PC_to_r0,
d5276282 1271 tr_P_to_r0,
1272 tr_PM0_to_r0,
1273 tr_PM1_to_r0,
1274 tr_PM2_to_r0,
1275 tr_XST_to_r0,
1276 tr_PM4_to_r0,
1277 (tr_read_func *)tr_unhandled,
1278 tr_PMC_to_r0,
1279 tr_AL_to_r0
d274c33b 1280};
1281
1282
b9c1d012 1283// write r0 to general reg handlers. Trashes r1
6e39239f 1284#define TR_WRITE_R0_TO_REG(reg) \
1285{ \
1286 hostreg_sspreg_changed(reg); \
1287 hostreg_r[0] = (reg)<<16; \
1288 if (const_val != -1) { \
1289 known_regs.gr[reg].h = const_val; \
1290 known_regb |= 1 << (reg); \
1291 } else { \
1292 known_regb &= ~(1 << (reg)); \
1293 } \
b9c1d012 1294}
1295
6e39239f 1296static void tr_r0_to_GR0(int const_val)
b9c1d012 1297{
1298 // do nothing
1299}
1300
6e39239f 1301static void tr_r0_to_X(int const_val)
b9c1d012 1302{
1303 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1304 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1305 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
6e39239f 1306 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1307 TR_WRITE_R0_TO_REG(SSP_X);
b9c1d012 1308}
1309
6e39239f 1310static void tr_r0_to_Y(int const_val)
b9c1d012 1311{
1312 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1313 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1314 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
bad5731d 1315 dirty_regb |= KRREG_P;
6e39239f 1316 TR_WRITE_R0_TO_REG(SSP_Y);
b9c1d012 1317}
1318
6e39239f 1319static void tr_r0_to_A(int const_val)
b9c1d012 1320{
1321 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 1322 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 1323 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
6e39239f 1324 TR_WRITE_R0_TO_REG(SSP_A);
b9c1d012 1325}
1326
6e39239f 1327static void tr_r0_to_ST(int const_val)
b9c1d012 1328{
1329 // VR doesn't need much accuracy here..
1330 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1331 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1332 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
6e39239f 1333 TR_WRITE_R0_TO_REG(SSP_ST);
b9c1d012 1334 hostreg_r[1] = -1;
6e39239f 1335 dirty_regb &= ~KRREG_ST;
b9c1d012 1336}
1337
6e39239f 1338static void tr_r0_to_STACK(int const_val)
b9c1d012 1339{
1340 // 448
1341 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1342 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
d274c33b 1343 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 1344 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 1345 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 1346 hostreg_r[1] = -1;
1347}
1348
6e39239f 1349static void tr_r0_to_PC(int const_val)
b9c1d012 1350{
1351 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 1352 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 1353 hostreg_r[1] = -1;
1354}
1355
d5276282 1356static void tr_r0_to_AL(int const_val)
1357{
1358 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1359 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1360 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1361 hostreg_sspreg_changed(SSP_AL);
1362 if (const_val != -1) {
1363 known_regs.gr[SSP_A].l = const_val;
1364 known_regb |= 1 << SSP_AL;
1365 } else
1366 known_regb &= ~(1 << SSP_AL);
1367}
1368
1369static void tr_r0_to_PMX(int reg)
1370{
d5276282 1371 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1372 {
1373 known_regs.pmac_write[reg] = known_regs.pmc.v;
1374 known_regs.emu_status &= ~SSP_PMC_SET;
1375 known_regb |= 1 << (25+reg);
1376 dirty_regb |= 1 << (25+reg);
1377 return;
1378 }
0b5e8296 1379
d5276282 1380 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1381 {
1382 int mode, addr;
1383
1384 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1385
1386 mode = known_regs.pmac_write[reg]>>16;
1387 addr = known_regs.pmac_write[reg]&0xffff;
1388 if ((mode & 0x43ff) == 0x0018) // DRAM
1389 {
1390 int inc = get_inc(mode);
1391 if (mode & 0x0400) tr_unhandled();
1392 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1393 emit_mov_const(A_COND_AL, 2, addr<<1);
1394 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1395 known_regs.pmac_write[reg] += inc;
1396 }
1397 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1398 {
1399 if (mode & 0x0400) tr_unhandled();
1400 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1401 emit_mov_const(A_COND_AL, 2, addr<<1);
1402 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1403 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1404 }
1405 else if ((mode & 0x47ff) == 0x001c) // IRAM
1406 {
1407 int inc = get_inc(mode);
1408 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1409 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1410 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
e122fae6 1411 EOP_MOV_IMM(1,0,1);
1412 EOP_STR_IMM(1,7,0x494); // iram_dirty
d5276282 1413 known_regs.pmac_write[reg] += inc;
1414 }
1415 else
1416 tr_unhandled();
1417
1418 known_regs.pmc.v = known_regs.pmac_write[reg];
1419 //known_regb |= KRREG_PMC;
1420 dirty_regb |= KRREG_PMC;
1421 dirty_regb |= 1 << (25+reg);
1422 hostreg_r[1] = hostreg_r[2] = -1;
e122fae6 1423 return;
d5276282 1424 }
1425
1426 known_regb &= ~KRREG_PMC;
1427 dirty_regb &= ~KRREG_PMC;
1428 known_regb &= ~(1 << (25+reg));
1429 dirty_regb &= ~(1 << (25+reg));
d5276282 1430
1431 // call the C code to handle this
1432 tr_flush_dirty_ST();
1433 //tr_flush_dirty_pmcrs();
1434 tr_mov16(1, reg);
1435 emit_call(ssp_pm_write);
1436 hostreg_clear();
1437}
1438
1439static void tr_r0_to_PM0(int const_val)
1440{
1441 tr_r0_to_PMX(0);
1442}
1443
1444static void tr_r0_to_PM1(int const_val)
1445{
1446 tr_r0_to_PMX(1);
1447}
1448
1449static void tr_r0_to_PM2(int const_val)
1450{
1451 tr_r0_to_PMX(2);
1452}
1453
1454static void tr_r0_to_PM4(int const_val)
1455{
1456 tr_r0_to_PMX(4);
1457}
1458
1459static void tr_r0_to_PMC(int const_val)
1460{
1461 if ((known_regb & KRREG_PMC) && const_val != -1)
1462 {
1463 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1464 known_regs.emu_status |= SSP_PMC_SET;
1465 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1466 known_regs.pmc.h = const_val;
1467 } else {
1468 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1469 known_regs.pmc.l = const_val;
1470 }
1471 }
1472 else
1473 {
1474 tr_flush_dirty_ST();
1475 if (known_regb & KRREG_PMC) {
1476 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1477 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1478 known_regb &= ~KRREG_PMC;
1479 dirty_regb &= ~KRREG_PMC;
1480 }
1481 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1482 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1483 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1484 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1485 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1486 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1487 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1488 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1489 EOP_STR_IMM(1,7,0x484);
1490 hostreg_r[1] = hostreg_r[2] = -1;
1491 }
1492}
1493
6e39239f 1494typedef void (tr_write_func)(int const_val);
b9c1d012 1495
d5276282 1496static tr_write_func *tr_write_funcs[16] =
b9c1d012 1497{
1498 tr_r0_to_GR0,
1499 tr_r0_to_X,
1500 tr_r0_to_Y,
1501 tr_r0_to_A,
1502 tr_r0_to_ST,
1503 tr_r0_to_STACK,
1504 tr_r0_to_PC,
d5276282 1505 (tr_write_func *)tr_unhandled,
1506 tr_r0_to_PM0,
1507 tr_r0_to_PM1,
1508 tr_r0_to_PM2,
1509 (tr_write_func *)tr_unhandled,
1510 tr_r0_to_PM4,
1511 (tr_write_func *)tr_unhandled,
1512 tr_r0_to_PMC,
1513 tr_r0_to_AL
b9c1d012 1514};
1515
0e4d7ba5 1516static void tr_mac_load_XY(int op)
1517{
1518 tr_rX_read(op&3, (op>>2)&3); // X
1519 EOP_MOV_REG_LSL(4, 0, 16);
1520 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1521 EOP_ORR_REG_SIMPLE(4, 0);
1522 dirty_regb |= KRREG_P;
1523 hostreg_sspreg_changed(SSP_X);
1524 hostreg_sspreg_changed(SSP_Y);
1525 known_regb &= ~KRREG_X;
1526 known_regb &= ~KRREG_Y;
1527}
1528
ede7220f 1529// -----------------------------------------------------
1530
ede7220f 1531static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
0e4d7ba5 1532{
ede7220f 1533 u32 pmcv, tmpv;
1534 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1535
1536 // programming PMC:
1537 // ldi PMC, imm1
1538 // ldi PMC, imm2
1539 (*pc)++;
1540 pmcv = imm | (PROGRAM((*pc)++) << 16);
d5276282 1541 known_regs.pmc.v = pmcv;
ede7220f 1542 known_regb |= KRREG_PMC;
d5276282 1543 dirty_regb |= KRREG_PMC;
ede7220f 1544 known_regs.emu_status |= SSP_PMC_SET;
1545
1546 // check for possible reg programming
1547 tmpv = PROGRAM(*pc);
1548 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1549 {
1550 int is_write = (tmpv & 0xff8f) == 0x80;
1551 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1552 if (reg > 4) tr_unhandled();
d5276282 1553 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
ede7220f 1554 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1555 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
d5276282 1556 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
ede7220f 1557 known_regs.emu_status &= ~SSP_PMC_SET;
1558 (*pc)++;
1559 return 5;
0e4d7ba5 1560 }
1561
d5276282 1562 tr_unhandled();
ede7220f 1563 return 4;
1564}
1565
1566static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1567
1568static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1569{
1570 // ldi ST, 0
1571 // ldi PM0, 0
1572 // ldi PM0, 0
1573 // ldi ST, 60h
1574 unsigned short *pp;
1575 if (op != 0x0840 || imm != 0) return 0;
1576 pp = PROGRAM_P(*pc);
1577 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1578
1579 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1580 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1581 hostreg_sspreg_changed(SSP_ST);
1582 known_regs.gr[SSP_ST].h = 0x60;
1583 known_regb |= 1 << SSP_ST;
1584 dirty_regb &= ~KRREG_ST;
1585 (*pc) += 3*2;
1586 return 4*2;
0e4d7ba5 1587}
5d817c91 1588
d5276282 1589static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1590{
1591 // @ 3DA2 and 426A
1592 // ld PMC, (r3|00)
1593 // ld (r3|00), PMC
1594 // ld -, AL
1595 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1596
1597 tr_bank_read(0);
1598 EOP_MOV_REG_LSL(0, 0, 4);
1599 EOP_ORR_REG_LSR(0, 0, 0, 16);
1600 tr_bank_write(0);
1601 (*pc) += 2;
1602 return 3;
1603}
1604
ede7220f 1605// -----------------------------------------------------
1606
5d817c91 1607static int translate_op(unsigned int op, int *pc, int imm)
1608{
0e4d7ba5 1609 u32 tmpv, tmpv2, tmpv3;
5d817c91 1610 int ret = 0;
bad5731d 1611 known_regs.gr[SSP_PC].h = *pc;
5d817c91 1612
e807ac75 1613 switch (op >> 9)
1614 {
1615 // ld d, s
f48f5e3b 1616 case 0x00:
5d817c91 1617 if (op == 0) { ret++; break; } // nop
d274c33b 1618 tmpv = op & 0xf; // src
1619 tmpv2 = (op >> 4) & 0xf; // dst
d274c33b 1620 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1621 tr_flush_dirty_P();
1622 EOP_MOV_REG_SIMPLE(5, 10);
d5276282 1623 hostreg_sspreg_changed(SSP_A);
bad5731d 1624 known_regb &= ~(KRREG_A|KRREG_AL);
d274c33b 1625 ret++; break;
1626 }
d5276282 1627 tr_read_funcs[tmpv](op);
6e39239f 1628 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
ede7220f 1629 if (tmpv2 == SSP_PC) ret |= 0x10000;
bad5731d 1630 ret++; break;
1631
1632 // ld d, (ri)
89fea1e9 1633 case 0x01: {
89fea1e9 1634 int r = (op&3) | ((op>>6)&4);
1635 int mod = (op>>2)&3;
1636 tmpv = (op >> 4) & 0xf; // dst
d5276282 1637 ret = tr_detect_rotate(op, pc, imm);
1638 if (ret > 0) break;
89fea1e9 1639 if (tmpv != 0)
1640 tr_rX_read(r, mod);
1641 else tr_ptrr_mod(r, mod, 1, 1);
6e39239f 1642 tr_write_funcs[tmpv](-1);
ede7220f 1643 if (tmpv == SSP_PC) ret |= 0x10000;
89fea1e9 1644 ret++; break;
1645 }
bad5731d 1646
1647 // ld (ri), s
1648 case 0x02:
1649 tmpv = (op >> 4) & 0xf; // src
d5276282 1650 tr_read_funcs[tmpv](op);
0e4d7ba5 1651 tr_rX_write(op);
d274c33b 1652 ret++; break;
f48f5e3b 1653
1654 // ld a, adr
1655 case 0x03:
5d817c91 1656 tr_bank_read(op&0x1ff);
6e39239f 1657 tr_r0_to_A(-1);
5d817c91 1658 ret++; break;
1659
b9c1d012 1660 // ldi d, imm
1661 case 0x04:
ede7220f 1662 tmpv = (op & 0xf0) >> 4; // dst
1663 ret = tr_detect_pm0_block(op, pc, imm);
1664 if (ret > 0) break;
ede7220f 1665 ret = tr_detect_set_pm(op, pc, imm);
1666 if (ret > 0) break;
0b5e8296 1667 tr_mov16(0, imm);
1668 tr_write_funcs[tmpv](imm);
ede7220f 1669 if (tmpv == SSP_PC) ret |= 0x10000;
0b5e8296 1670 ret += 2; break;
b9c1d012 1671
bad5731d 1672 // ld d, ((ri))
0e4d7ba5 1673 case 0x05:
bad5731d 1674 tmpv2 = (op >> 4) & 0xf; // dst
0e4d7ba5 1675 tr_rX_read2(op);
6e39239f 1676 tr_write_funcs[tmpv2](-1);
ede7220f 1677 if (tmpv2 == SSP_PC) ret |= 0x10000;
0e4d7ba5 1678 ret += 3; break;
b9c1d012 1679
5d817c91 1680 // ldi (ri), imm
1681 case 0x06:
5d817c91 1682 tr_mov16(0, imm);
0e4d7ba5 1683 tr_rX_write(op);
a6fb500b 1684 ret += 2; break;
f48f5e3b 1685
1686 // ld adr, a
1687 case 0x07:
d5276282 1688 tr_A_to_r0(op);
5d817c91 1689 tr_bank_write(op&0x1ff);
1690 ret++; break;
1691
d274c33b 1692 // ld d, ri
1693 case 0x09: {
bad5731d 1694 int r;
d274c33b 1695 r = (op&3) | ((op>>6)&4); // src
bad5731d 1696 tmpv2 = (op >> 4) & 0xf; // dst
bad5731d 1697 if ((r&3) == 3) tr_unhandled();
d274c33b 1698
bad5731d 1699 if (known_regb & (1 << (r+8))) {
1700 tr_mov16(0, known_regs.r[r]);
6e39239f 1701 tr_write_funcs[tmpv2](known_regs.r[r]);
d274c33b 1702 } else {
bad5731d 1703 int reg = (r < 4) ? 8 : 9;
d274c33b 1704 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1705 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1706 hostreg_r[0] = -1;
6e39239f 1707 tr_write_funcs[tmpv2](-1);
d274c33b 1708 }
d274c33b 1709 ret++; break;
1710 }
1711
bad5731d 1712 // ld ri, s
1713 case 0x0a: {
1714 int r;
1715 r = (op&3) | ((op>>6)&4); // dst
1716 tmpv = (op >> 4) & 0xf; // src
bad5731d 1717 if ((r&3) == 3) tr_unhandled();
1718
1719 if (known_regb & (1 << tmpv)) {
1720 known_regs.r[r] = known_regs.gr[tmpv].h;
1721 known_regb |= 1 << (r + 8);
1722 dirty_regb |= 1 << (r + 8);
1723 } else {
1724 int reg = (r < 4) ? 8 : 9;
1725 int ror = ((4 - (r&3))*8) & 0x1f;
d5276282 1726 tr_read_funcs[tmpv](op);
bad5731d 1727 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1728 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1729 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1730 hostreg_r[0] = -1;
1731 known_regb &= ~(1 << (r+8));
1732 dirty_regb &= ~(1 << (r+8));
1733 }
1734 ret++; break;
1735 }
1736
5d817c91 1737 // ldi ri, simm
1738 case 0x0c ... 0x0f:
1739 tmpv = (op>>8)&7;
bad5731d 1740 known_regs.r[tmpv] = op;
1741 known_regb |= 1 << (tmpv + 8);
5d817c91 1742 dirty_regb |= 1 << (tmpv + 8);
1743 ret++; break;
bad5731d 1744
a6fb500b 1745 // call cond, addr
6e39239f 1746 case 0x24: {
1747 u32 *jump_op = NULL;
a6fb500b 1748 tmpv = tr_cond_check(op);
6e39239f 1749 if (tmpv != A_COND_AL) {
1750 jump_op = tcache_ptr;
1751 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1752 }
1753 tr_mov16(0, *pc);
1754 tr_r0_to_STACK(*pc);
1755 if (tmpv != A_COND_AL) {
1756 u32 *real_ptr = tcache_ptr;
1757 tcache_ptr = jump_op;
1758 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1759 tcache_ptr = real_ptr;
1760 }
a6fb500b 1761 tr_mov16_cond(tmpv, 0, imm);
1762 if (tmpv != A_COND_AL) {
1763 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1764 }
6e39239f 1765 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1766 ret |= 0x10000;
a6fb500b 1767 ret += 2; break;
6e39239f 1768 }
a6fb500b 1769
bad5731d 1770 // ld d, (a)
1771 case 0x25:
bad5731d 1772 tmpv2 = (op >> 4) & 0xf; // dst
d5276282 1773 tr_A_to_r0(op);
bad5731d 1774 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1775 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1776 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1777 hostreg_r[0] = hostreg_r[1] = -1;
6e39239f 1778 tr_write_funcs[tmpv2](-1);
ede7220f 1779 if (tmpv2 == SSP_PC) ret |= 0x10000;
a6fb500b 1780 ret += 3; break;
bad5731d 1781
1782 // bra cond, addr
a6fb500b 1783 case 0x26:
bad5731d 1784 tmpv = tr_cond_check(op);
1785 tr_mov16_cond(tmpv, 0, imm);
1786 if (tmpv != A_COND_AL) {
bad5731d 1787 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1788 }
6e39239f 1789 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1790 ret |= 0x10000;
a6fb500b 1791 ret += 2; break;
bad5731d 1792
89fea1e9 1793 // mod cond, op
89fea1e9 1794 case 0x48: {
1795 // check for repeats of this op
1796 tmpv = 1; // count
1797 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1798 (*pc)++; tmpv++;
1799 }
6e39239f 1800 if ((op&0xf0) != 0) // !always
1801 tr_make_dirty_ST();
1802
89fea1e9 1803 tmpv2 = tr_cond_check(op);
1804 switch (op & 7) {
1805 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1806 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1807 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
6e39239f 1808 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
1809 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
89fea1e9 1810 hostreg_r[1] = -1; break; // abs
1811 default: tr_unhandled();
1812 }
6e39239f 1813
1814 hostreg_sspreg_changed(SSP_A);
1815 dirty_regb |= KRREG_ST;
1816 known_regb &= ~KRREG_ST;
1817 known_regb &= ~(KRREG_A|KRREG_AL);
89fea1e9 1818 ret += tmpv; break;
1819 }
0e4d7ba5 1820
bad5731d 1821 // mpys?
1822 case 0x1b:
0e4d7ba5 1823 tr_flush_dirty_P();
1824 tr_mac_load_XY(op);
1825 tr_make_dirty_ST();
1826 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1827 hostreg_sspreg_changed(SSP_A);
1828 known_regb &= ~(KRREG_A|KRREG_AL);
1829 dirty_regb |= KRREG_ST;
1830 ret++; break;
bad5731d 1831
1832 // mpya (rj), (ri), b
1833 case 0x4b:
0e4d7ba5 1834 tr_flush_dirty_P();
1835 tr_mac_load_XY(op);
1836 tr_make_dirty_ST();
1837 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1838 hostreg_sspreg_changed(SSP_A);
1839 known_regb &= ~(KRREG_A|KRREG_AL);
1840 dirty_regb |= KRREG_ST;
1841 ret++; break;
bad5731d 1842
1843 // mld (rj), (ri), b
1844 case 0x5b:
0e4d7ba5 1845 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1846 hostreg_sspreg_changed(SSP_A);
1847 known_regs.gr[SSP_A].v = 0;
bad5731d 1848 known_regb |= (KRREG_A|KRREG_AL);
0e4d7ba5 1849 dirty_regb |= KRREG_ST;
1850 tr_mac_load_XY(op);
1851 ret++; break;
1852
1853 // OP a, s
1854 case 0x10:
1855 case 0x30:
1856 case 0x40:
1857 case 0x50:
1858 case 0x60:
1859 case 0x70:
1860 tmpv = op & 0xf; // src
1861 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1862 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
0e4d7ba5 1863 if (tmpv == SSP_P) {
1864 tr_flush_dirty_P();
1865 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1866 } else if (tmpv == SSP_A) {
1867 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1868 } else {
d5276282 1869 tr_read_funcs[tmpv](op);
0e4d7ba5 1870 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1871 }
1872 hostreg_sspreg_changed(SSP_A);
1873 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1874 dirty_regb |= KRREG_ST;
1875 ret++; break;
1876
1877 // OP a, (ri)
1878 case 0x11:
1879 case 0x31:
1880 case 0x41:
1881 case 0x51:
1882 case 0x61:
1883 case 0x71:
1884 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1885 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1886 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1887 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1888 hostreg_sspreg_changed(SSP_A);
1889 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1890 dirty_regb |= KRREG_ST;
1891 ret++; break;
1892
1893 // OP a, adr
1894 case 0x13:
1895 case 0x33:
1896 case 0x43:
1897 case 0x53:
1898 case 0x63:
1899 case 0x73:
1900 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1901 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1902 tr_bank_read(op&0x1ff);
1903 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1904 hostreg_sspreg_changed(SSP_A);
1905 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1906 dirty_regb |= KRREG_ST;
1907 ret++; break;
1908
1909 // OP a, imm
1910 case 0x14:
1911 case 0x34:
1912 case 0x44:
1913 case 0x54:
1914 case 0x64:
1915 case 0x74:
1916 tmpv = (op & 0xf0) >> 4;
1917 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1918 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1919 tr_mov16(0, imm);
1920 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1921 hostreg_sspreg_changed(SSP_A);
1922 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1923 dirty_regb |= KRREG_ST;
1924 ret += 2; break;
1925
1926 // OP a, ((ri))
1927 case 0x15:
1928 case 0x35:
1929 case 0x45:
1930 case 0x55:
1931 case 0x65:
1932 case 0x75:
1933 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1934 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1935 tr_rX_read2(op);
1936 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1937 hostreg_sspreg_changed(SSP_A);
1938 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1939 dirty_regb |= KRREG_ST;
1940 ret += 3; break;
1941
1942 // OP a, ri
1943 case 0x19:
1944 case 0x39:
1945 case 0x49:
1946 case 0x59:
1947 case 0x69:
1948 case 0x79: {
1949 int r;
1950 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1951 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1952 r = (op&3) | ((op>>6)&4); // src
1953 if ((r&3) == 3) tr_unhandled();
1954
1955 if (known_regb & (1 << (r+8))) {
1956 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1957 } else {
1958 int reg = (r < 4) ? 8 : 9;
1959 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1960 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1961 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1962 hostreg_r[0] = -1;
1963 }
1964 hostreg_sspreg_changed(SSP_A);
1965 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1966 dirty_regb |= KRREG_ST;
1967 ret++; break;
1968 }
1969
1970 // OP simm
1971 case 0x1c:
1972 case 0x3c:
1973 case 0x4c:
1974 case 0x5c:
1975 case 0x6c:
1976 case 0x7c:
1977 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1978 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1979 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1980 hostreg_sspreg_changed(SSP_A);
1981 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1982 dirty_regb |= KRREG_ST;
bad5731d 1983 ret++; break;
e807ac75 1984 }
1985
5d817c91 1986 return ret;
e807ac75 1987}
1988
df143b36 1989static void *translate_block(int pc)
726bbb3e 1990{
e807ac75 1991 unsigned int op, op1, imm, ccount = 0;
5c129565 1992 unsigned int *block_start;
ede7220f 1993 int ret, ret_prev = -1, tpc;
5c129565 1994
259ed0ea 1995 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 1996 block_start = tcache_ptr;
bad5731d 1997 known_regb = 0;
1998 dirty_regb = KRREG_P;
d5276282 1999 known_regs.emu_status = 0;
5d817c91 2000 hostreg_clear();
5c129565 2001
2002 emit_block_prologue();
726bbb3e 2003
e807ac75 2004 for (; ccount < 100;)
726bbb3e 2005 {
2006 op = PROGRAM(pc++);
2007 op1 = op >> 9;
e807ac75 2008 imm = (u32)-1;
5c129565 2009
e807ac75 2010 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2011 imm = PROGRAM(pc++); // immediate
ede7220f 2012 tpc = pc;
5c129565 2013
5d817c91 2014 ret = translate_op(op, &pc, imm);
e807ac75 2015 if (ret <= 0)
2016 {
89fea1e9 2017 tr_flush_dirty_prs();
2018 tr_flush_dirty_ST();
ede7220f 2019 tr_flush_dirty_pmcrs();
d5276282 2020 known_regs.emu_status = 0;
5d817c91 2021
bad5731d 2022 emit_mov_const(A_COND_AL, 0, op);
5c129565 2023
e807ac75 2024 // need immediate?
2025 if (imm != (u32)-1)
bad5731d 2026 emit_mov_const(A_COND_AL, 1, imm);
5c129565 2027
e807ac75 2028 // dump PC
2029 emit_pc_dump(pc);
5c129565 2030
d274c33b 2031 if (ret_prev > 0) emit_call(regfile_store);
2032 emit_call(in_funcs[op1]);
2033 emit_call(regfile_load);
e807ac75 2034
2035 if (in_funcs[op1] == NULL) {
2036 printf("NULL func! op=%08x (%02x)\n", op, op1);
2037 exit(1);
2038 }
2039 ccount++;
5d817c91 2040 hostreg_clear();
bad5731d 2041 dirty_regb |= KRREG_P;
2042 known_regb = 0;
892b1dd2 2043 }
e807ac75 2044 else
ede7220f 2045 {
2046 ccount += ret & 0xffff;
2047 if (ret & 0x10000) break;
726bbb3e 2048 }
ede7220f 2049
d274c33b 2050 ret_prev = ret;
726bbb3e 2051 }
5c129565 2052
0b5e8296 2053 if (ccount >= 100)
2054 emit_pc_dump(pc);
2055
89fea1e9 2056 tr_flush_dirty_prs();
2057 tr_flush_dirty_ST();
ede7220f 2058 tr_flush_dirty_pmcrs();
e807ac75 2059 emit_block_epilogue(ccount + 1);
5c129565 2060 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 2061
892b1dd2 2062 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 2063 printf("tcache overflow!\n");
2064 fflush(stdout);
2065 exit(1);
2066 }
2067
2068 // stats
2069 nblocks++;
892b1dd2 2070 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
df143b36 2071
5d817c91 2072#ifdef DUMP_BLOCK
5c129565 2073 {
2074 FILE *f = fopen("tcache.bin", "wb");
2075 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2076 fclose(f);
2077 }
2078 exit(0);
2079#endif
259ed0ea 2080
2081 handle_caches();
2082
5c129565 2083 return block_start;
726bbb3e 2084}
2085
2086
2087
2088// -----------------------------------------------------
2089
e807ac75 2090int ssp1601_dyn_startup(void)
726bbb3e 2091{
e807ac75 2092 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 2093 memset(block_table, 0, sizeof(block_table));
df143b36 2094 memset(block_table_iram, 0, sizeof(block_table_iram));
13aba3fe 2095 memset(block_ref, 0, sizeof(block_ref));
2096 memset(block_ref_iram, 0, sizeof(block_ref_iram));
e807ac75 2097 tcache_ptr = tcache;
5c129565 2098 *tcache_ptr++ = 0xffffffff;
726bbb3e 2099
d5276282 2100#ifdef ARM
2101 // hle'd blocks
2102 block_table[0x400] = (void *) ssp_hle_800;
2103#endif
2104
6e39239f 2105// TODO: rm
2106{
2107static unsigned short dummy = 0;
2108PC = &dummy;
2109}
726bbb3e 2110 return 0;
2111}
2112
2113
2114void ssp1601_dyn_reset(ssp1601_t *ssp)
2115{
13aba3fe 2116 int i, u, total = 0;
2117 for (i = 0; i < 0x5090/2; i++)
2118 total += block_ref[i];
2119 for (u = 1; u < 15; u++)
2120 for (i = 0; i < 0x800/2; i++)
2121 total += block_ref_iram[u][i];
2122
2123 printf("total: %i\n", total);
2124 for (i = 0; i < 0x5090/2; i++)
2125 if (block_ref[i])
2126 printf("%07i %2.3f%% __:%04x\n", block_ref[i], (double)block_ref[i] / (double)total * 100.0, i<<1);
2127 for (u = 1; u < 15; u++)
2128 for (i = 0; i < 0x800/2; i++)
2129 if (block_ref_iram[u][i])
2130 printf("%07i %2.3f%% %02i:%04x\n", block_ref_iram[u][i],
2131 (double)block_ref_iram[u][i] / (double)total * 100.0, u, i<<1);
2132
2133
726bbb3e 2134 ssp1601_reset_local(ssp);
e122fae6 2135 ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2136 ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2137 ssp->drc.ptr_dram = (unsigned int) svp->dram;
2138 ssp->drc.iram_dirty = 0;
726bbb3e 2139}
2140
726bbb3e 2141void ssp1601_dyn_run(int cycles)
2142{
b9c1d012 2143 if (ssp->emu_status & SSP_WAIT_MASK) return;
b9c1d012 2144
5d817c91 2145#ifdef DUMP_BLOCK
2146 rPC = DUMP_BLOCK >> 1;
2147#endif
726bbb3e 2148 while (cycles > 0)
2149 {
e807ac75 2150 int (*trans_entry)(void);
df143b36 2151 if (rPC < 0x800/2)
2152 {
e122fae6 2153 if (ssp->drc.iram_dirty) {
df143b36 2154 iram_context = get_iram_context();
e122fae6 2155 ssp->drc.iram_dirty--;
df143b36 2156 }
2157 if (block_table_iram[iram_context][rPC] == NULL)
2158 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 2159 trans_entry = (void *) block_table_iram[iram_context][rPC];
13aba3fe 2160 block_ref_iram[iram_context][rPC]++;
df143b36 2161 }
2162 else
2163 {
2164 if (block_table[rPC] == NULL)
2165 block_table[rPC] = translate_block(rPC);
5c129565 2166 trans_entry = (void *) block_table[rPC];
13aba3fe 2167 block_ref[rPC]++;
df143b36 2168 }
726bbb3e 2169
e807ac75 2170 cycles -= trans_entry();
726bbb3e 2171 }
726bbb3e 2172}
2173