svp compiler: some fixes
[picodrive.git] / Pico / carthw / svp / compiler.c
CommitLineData
726bbb3e 1// 187 blocks, 12072 bytes
2// 14 IRAM blocks
3
4#include "../../PicoInt.h"
e807ac75 5#include "compiler.h"
726bbb3e 6
892b1dd2 7static unsigned int *block_table[0x5090/2];
8static unsigned int *block_table_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
e122fae6 15#define DUMP_BLOCK 0x2018
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;
502 //elprintf("set PM%i %08x", ssp->pmac_read[reg]);
503 return 0;
504 }
505
506 //elprintf("rd PM%i %08x", ssp->pmac_read[reg]);
507 // just in case
508 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
509
510 mode = ssp->pmac_read[reg]>>16;
511 if ((mode & 0xfff0) == 0x0800) // ROM
512 {
513 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
514 ssp->pmac_read[reg] += 1;
515 }
516 else if ((mode & 0x47ff) == 0x0018) // DRAM
517 {
518 unsigned short *dram = (unsigned short *)svp->dram;
519 int inc = get_inc(mode);
520 d = dram[ssp->pmac_read[reg]&0xffff];
521 ssp->pmac_read[reg] += inc;
522 }
523
524 // PMC value corresponds to last PMR accessed
525 rPMC.v = ssp->pmac_read[reg];
526
527 return d;
528}
529
530static void ssp_pm_write(u32 d, int reg)
531{
532 unsigned short *dram;
533 int mode, addr;
534
535 if (ssp->emu_status & SSP_PMC_SET)
536 {
537 ssp->pmac_write[reg] = rPMC.v;
538 ssp->emu_status &= ~SSP_PMC_SET;
539 return;
540 }
541
542 // just in case
543 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
544
545 dram = (unsigned short *)svp->dram;
546 mode = ssp->pmac_write[reg]>>16;
547 addr = ssp->pmac_write[reg]&0xffff;
548 if ((mode & 0x43ff) == 0x0018) // DRAM
549 {
550 int inc = get_inc(mode);
551 if (mode & 0x0400) {
552 overwrite_write(dram[addr], d);
553 } else dram[addr] = d;
554 ssp->pmac_write[reg] += inc;
555 }
556 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
557 {
558 if (mode & 0x0400) {
559 overwrite_write(dram[addr], d);
560 } else dram[addr] = d;
561 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
562 }
563 else if ((mode & 0x47ff) == 0x001c) // IRAM
564 {
565 int inc = get_inc(mode);
566 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
567 ssp->pmac_write[reg] += inc;
e122fae6 568 ssp->drc.iram_dirty = 1;
d5276282 569 }
570
571 rPMC.v = ssp->pmac_write[reg];
572}
573
574
892b1dd2 575// -----------------------------------------------------
576
df143b36 577static unsigned char iram_context_map[] =
578{
579 0, 0, 0, 0, 1, 0, 0, 0, // 04
580 0, 0, 0, 0, 0, 0, 2, 0, // 0e
581 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
582 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
583 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
584 0, 0, 0, 0, 0, 0, 0, 0,
585 0, 0,11, 0, 0,12, 0, 0, // 32 35
586 13,14, 0, 0, 0, 0, 0, 0 // 38 39
587};
588
df143b36 589static int get_iram_context(void)
590{
591 unsigned char *ir = (unsigned char *)svp->iram_rom;
592 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
df143b36 593 val1 = iram_context_map[(val>>1)&0x3f];
594
5c129565 595 if (val1 == 0) {
df143b36 596 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
df143b36 597 //debug_dump2file(name, svp->iram_rom, 0x800);
598 exit(1);
599 }
5c129565 600// elprintf(EL_ANOMALY, "iram_context: %02i", val1);
df143b36 601 return val1;
602}
603
5d817c91 604// -----------------------------------------------------
605/*
606enum {
607 SSP_GR0, SSP_X, SSP_Y, SSP_A,
608 SSP_ST, SSP_STACK, SSP_PC, SSP_P,
609 SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
610 SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
611};
612*/
613/* regs with known values */
614static struct
615{
616 ssp_reg_t gr[8];
617 unsigned char r[8];
ede7220f 618 unsigned int pmac_read[5];
619 unsigned int pmac_write[5];
d5276282 620 ssp_reg_t pmc;
ede7220f 621 unsigned int emu_status;
bad5731d 622} known_regs;
623
624#define KRREG_X (1 << SSP_X)
625#define KRREG_Y (1 << SSP_Y)
626#define KRREG_A (1 << SSP_A) /* AH only */
627#define KRREG_ST (1 << SSP_ST)
628#define KRREG_STACK (1 << SSP_STACK)
629#define KRREG_PC (1 << SSP_PC)
630#define KRREG_P (1 << SSP_P)
631#define KRREG_PR0 (1 << 8)
632#define KRREG_PR4 (1 << 12)
633#define KRREG_AL (1 << 16)
d5276282 634#define KRREG_PMCM (1 << 18) /* only mode word of PMC */
635#define KRREG_PMC (1 << 19)
ede7220f 636#define KRREG_PM0R (1 << 20)
637#define KRREG_PM1R (1 << 21)
638#define KRREG_PM2R (1 << 22)
639#define KRREG_PM3R (1 << 23)
640#define KRREG_PM4R (1 << 24)
641#define KRREG_PM0W (1 << 25)
642#define KRREG_PM1W (1 << 26)
643#define KRREG_PM2W (1 << 27)
644#define KRREG_PM3W (1 << 28)
645#define KRREG_PM4W (1 << 29)
bad5731d 646
647/* bitfield of known register values */
648static u32 known_regb = 0;
649
650/* known vals, which need to be flushed
d5276282 651 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
bad5731d 652 * ST means flags are being held in ARM PSR
89fea1e9 653 * P means that it needs to be recalculated
bad5731d 654 */
655static u32 dirty_regb = 0;
5d817c91 656
657/* known values of host regs.
d274c33b 658 * -1 - unknown
659 * 000000-00ffff - 16bit value
660 * 100000-10ffff - base reg (r7) + 16bit val
6e39239f 661 * 0r0000 - means reg (low) eq gr[r].h, r != AL
5d817c91 662 */
663static int hostreg_r[4];
664
665static void hostreg_clear(void)
666{
667 int i;
668 for (i = 0; i < 4; i++)
669 hostreg_r[i] = -1;
670}
671
6e39239f 672static void hostreg_sspreg_changed(int sspreg)
5d817c91 673{
674 int i;
675 for (i = 0; i < 4; i++)
6e39239f 676 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
5d817c91 677}
678
726bbb3e 679
ede7220f 680#define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
681#define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
726bbb3e 682
6e39239f 683static void tr_unhandled(void)
684{
685 FILE *f = fopen("tcache.bin", "wb");
686 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
687 fclose(f);
688 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
689 exit(1);
690}
691
0e4d7ba5 692/* update P, if needed. Trashes r0 */
d274c33b 693static void tr_flush_dirty_P(void)
694{
695 // TODO: const regs
bad5731d 696 if (!(dirty_regb & KRREG_P)) return;
d274c33b 697 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
0e4d7ba5 698 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
699 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
700 EOP_MUL(10, 0, 10); // mul r10, r0, r10
bad5731d 701 dirty_regb &= ~KRREG_P;
0e4d7ba5 702 hostreg_r[0] = -1;
d274c33b 703}
704
89fea1e9 705/* write dirty pr to host reg. Nothing is trashed */
706static void tr_flush_dirty_pr(int r)
707{
708 int ror = 0, reg;
6e39239f 709
89fea1e9 710 if (!(dirty_regb & (1 << (r+8)))) return;
711
712 switch (r&3) {
713 case 0: ror = 0; break;
714 case 1: ror = 24/2; break;
715 case 2: ror = 16/2; break;
716 }
717 reg = (r < 4) ? 8 : 9;
718 EOP_BIC_IMM(reg,reg,ror,0xff);
719 if (known_regs.r[r] != 0)
720 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
721 dirty_regb &= ~(1 << (r+8));
722}
723
724/* write all dirty pr0-pr7 to host regs. Nothing is trashed */
725static void tr_flush_dirty_prs(void)
5d817c91 726{
727 int i, ror = 0, reg;
bad5731d 728 int dirty = dirty_regb >> 8;
5d817c91 729 /* r0-r7 */
bad5731d 730 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
5d817c91 731 {
bad5731d 732 if (!(dirty&1)) continue;
5d817c91 733 switch (i&3) {
734 case 0: ror = 0; break;
735 case 1: ror = 24/2; break;
736 case 2: ror = 16/2; break;
737 }
738 reg = (i < 4) ? 8 : 9;
739 EOP_BIC_IMM(reg,reg,ror,0xff);
bad5731d 740 if (known_regs.r[i] != 0)
741 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
5d817c91 742 }
bad5731d 743 dirty_regb &= ~0xff00;
744}
745
89fea1e9 746/* write dirty pr and "forget" it. Nothing is trashed. */
747static void tr_release_pr(int r)
748{
749 tr_flush_dirty_pr(r);
750 known_regb &= ~(1 << (r+8));
751}
752
6e39239f 753/* fush ARM PSR to r6. Trashes r1 */
bad5731d 754static void tr_flush_dirty_ST(void)
755{
756 if (!(dirty_regb & KRREG_ST)) return;
757 EOP_BIC_IMM(6,6,0,0x0f);
6e39239f 758 EOP_MRS(1);
759 EOP_ORR_REG_LSR(6,6,1,28);
bad5731d 760 dirty_regb &= ~KRREG_ST;
6e39239f 761 hostreg_r[1] = -1;
762}
763
764/* inverse of above. Trashes r1 */
765static void tr_make_dirty_ST(void)
766{
767 if (dirty_regb & KRREG_ST) return;
768 if (known_regb & KRREG_ST) {
769 int flags = 0;
770 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
771 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
772 EOP_MSR_IMM(4/2, flags);
773 } else {
774 EOP_MOV_REG_LSL(1, 6, 28);
775 EOP_MSR_REG(1);
776 hostreg_r[1] = -1;
777 }
778 dirty_regb |= KRREG_ST;
bad5731d 779}
780
781/* load 16bit val into host reg r0-r3. Nothing is trashed */
782static void tr_mov16(int r, int val)
783{
784 if (hostreg_r[r] != val) {
785 emit_mov_const(A_COND_AL, r, val);
786 hostreg_r[r] = val;
787 }
788}
789
790static void tr_mov16_cond(int cond, int r, int val)
791{
792 emit_mov_const(cond, r, val);
a6fb500b 793 hostreg_r[r] = -1;
5d817c91 794}
795
ede7220f 796/* trashes r0 */
797static void tr_flush_dirty_pmcrs(void)
798{
799 u32 i, val = (u32)-1;
d5276282 800 if (!(dirty_regb & 0x3ff80000)) return;
ede7220f 801
d5276282 802 if (dirty_regb & KRREG_PMC) {
803 val = known_regs.pmc.v;
e122fae6 804 emit_mov_const(A_COND_AL, 1, val);
805 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
ede7220f 806
d5276282 807 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
808 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
809 tr_unhandled();
810 }
ede7220f 811 }
812 for (i = 0; i < 5; i++)
813 {
d5276282 814 if (dirty_regb & (1 << (20+i))) {
ede7220f 815 if (val != known_regs.pmac_read[i]) {
816 val = known_regs.pmac_read[i];
e122fae6 817 emit_mov_const(A_COND_AL, 1, val);
ede7220f 818 }
e122fae6 819 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
ede7220f 820 }
d5276282 821 if (dirty_regb & (1 << (25+i))) {
ede7220f 822 if (val != known_regs.pmac_write[i]) {
823 val = known_regs.pmac_write[i];
e122fae6 824 emit_mov_const(A_COND_AL, 1, val);
ede7220f 825 }
e122fae6 826 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
ede7220f 827 }
828 }
d5276282 829 dirty_regb &= ~0x3ff80000;
e122fae6 830 hostreg_r[1] = -1;
ede7220f 831}
832
0e4d7ba5 833/* read bank word to r0 (upper bits zero). Thrashes r1. */
5d817c91 834static void tr_bank_read(int addr) /* word addr 0-0x1ff */
835{
bad5731d 836 int breg = 7;
837 if (addr > 0x7f) {
838 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
839 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
840 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 841 }
bad5731d 842 breg = 1;
5d817c91 843 }
bad5731d 844 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
5d817c91 845 hostreg_r[0] = -1;
846}
847
848/* write r0 to bank. Trashes r1. */
849static void tr_bank_write(int addr)
850{
851 int breg = 7;
852 if (addr > 0x7f) {
d274c33b 853 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
5d817c91 854 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
d274c33b 855 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
5d817c91 856 }
857 breg = 1;
858 }
b9c1d012 859 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
5d817c91 860}
861
89fea1e9 862/* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
863static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
5d817c91 864{
a6fb500b 865 int modulo_shift = -1; /* unknown */
5d817c91 866
867 if (mod == 0) return;
868
869 if (!need_modulo || mod == 1) // +!
870 modulo_shift = 8;
bad5731d 871 else if (need_modulo && (known_regb & KRREG_ST)) {
872 modulo_shift = known_regs.gr[SSP_ST].h & 7;
5d817c91 873 if (modulo_shift == 0) modulo_shift = 8;
874 }
875
89fea1e9 876 if (modulo_shift == -1)
877 {
a6fb500b 878 int reg = (r < 4) ? 8 : 9;
89fea1e9 879 tr_release_pr(r);
0e4d7ba5 880 if (dirty_regb & KRREG_ST) {
881 // avoid flushing ARM flags
882 EOP_AND_IMM(1, 6, 0, 0x70);
883 EOP_SUB_IMM(1, 1, 0, 0x10);
884 EOP_AND_IMM(1, 1, 0, 0x70);
885 EOP_ADD_IMM(1, 1, 0, 0x10);
886 } else {
887 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
888 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
889 }
89fea1e9 890 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
891 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
892 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
893 if (r&3)
894 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
895 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
896 if (mod == 2)
897 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
898 else EOP_ADD_REG2_LSL(reg,reg,3,2);
899 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
900 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
901 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
a6fb500b 902 }
903 else if (known_regb & (1 << (r + 8)))
904 {
905 int modulo = (1 << modulo_shift) - 1;
5d817c91 906 if (mod == 2)
89fea1e9 907 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
908 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
a6fb500b 909 }
910 else
911 {
5d817c91 912 int reg = (r < 4) ? 8 : 9;
913 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
914 EOP_MOV_REG_ROR(reg,reg,ror);
915 // {add|sub} reg, reg, #1<<shift
89fea1e9 916 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 917 EOP_MOV_REG_ROR(reg,reg,32-ror);
918 }
919}
920
bad5731d 921/* handle writes r0 to (rX). Trashes r1.
922 * fortunately we can ignore modulo increment modes for writes. */
0e4d7ba5 923static void tr_rX_write(int op)
bad5731d 924{
925 if ((op&3) == 3)
926 {
927 int mod = (op>>2) & 3; // direct addressing
928 tr_bank_write((op & 0x100) + mod);
929 }
930 else
931 {
932 int r = (op&3) | ((op>>6)&4);
933 if (known_regb & (1 << (r + 8))) {
934 tr_bank_write((op&0x100) | known_regs.r[r]);
935 } else {
936 int reg = (r < 4) ? 8 : 9;
937 int ror = ((4 - (r&3))*8) & 0x1f;
938 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
939 if (r >= 4)
940 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
941 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
942 else EOP_ADD_REG_LSL(1,7,1,1);
943 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
944 hostreg_r[1] = -1;
945 }
89fea1e9 946 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
947 }
948}
949
950/* read (rX) to r0. Trashes r1-r3. */
951static void tr_rX_read(int r, int mod)
952{
953 if ((r&3) == 3)
954 {
955 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
956 }
957 else
958 {
959 if (known_regb & (1 << (r + 8))) {
6e39239f 960 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
89fea1e9 961 } else {
962 int reg = (r < 4) ? 8 : 9;
963 int ror = ((4 - (r&3))*8) & 0x1f;
964 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
965 if (r >= 4)
966 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
967 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
968 else EOP_ADD_REG_LSL(1,7,1,1);
969 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
0e4d7ba5 970 hostreg_r[0] = hostreg_r[1] = -1;
89fea1e9 971 }
972 tr_ptrr_mod(r, mod, 1, 1);
bad5731d 973 }
974}
975
0e4d7ba5 976/* read ((rX)) to r0. Trashes r1,r2. */
977static void tr_rX_read2(int op)
978{
979 int r = (op&3) | ((op>>6)&4); // src
980
981 if ((r&3) == 3) {
982 tr_bank_read((op&0x100) | ((op>>2)&3));
983 } else if (known_regb & (1 << (r+8))) {
984 tr_bank_read((op&0x100) | known_regs.r[r]);
985 } else {
986 int reg = (r < 4) ? 8 : 9;
987 int ror = ((4 - (r&3))*8) & 0x1f;
988 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
989 if (r >= 4)
990 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
991 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
992 else EOP_ADD_REG_LSL(1,7,1,1);
993 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
994 }
995 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
996 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
997 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
998 if ((r&3) == 3) {
999 tr_bank_write((op&0x100) | ((op>>2)&3));
1000 } else if (known_regb & (1 << (r+8))) {
1001 tr_bank_write((op&0x100) | known_regs.r[r]);
1002 } else {
1003 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1004 hostreg_r[1] = -1;
1005 }
1006 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
1007 hostreg_r[0] = hostreg_r[2] = -1;
1008}
89fea1e9 1009
bad5731d 1010/* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1011static int tr_cond_check(int op)
1012{
6e39239f 1013 int f = (op & 0x100) >> 8;
bad5731d 1014 switch (op&0xf0) {
1015 case 0x00: return A_COND_AL; /* always true */
1016 case 0x50: /* Z matches f(?) bit */
1017 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1018 EOP_TST_IMM(6, 0, 4);
1019 return f ? A_COND_NE : A_COND_EQ;
1020 case 0x70: /* N matches f(?) bit */
1021 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1022 EOP_TST_IMM(6, 0, 8);
1023 return f ? A_COND_NE : A_COND_EQ;
1024 default:
1025 printf("unimplemented cond?\n");
6e39239f 1026 tr_unhandled();
bad5731d 1027 return 0;
1028 }
1029}
1030
1031static int tr_neg_cond(int cond)
1032{
1033 switch (cond) {
1034 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1035 case A_COND_EQ: return A_COND_NE;
1036 case A_COND_NE: return A_COND_EQ;
1037 case A_COND_MI: return A_COND_PL;
1038 case A_COND_PL: return A_COND_MI;
1039 default: printf("bad cond for neg\n"); exit(1);
1040 }
1041 return 0;
1042}
1043
ede7220f 1044static int tr_aop_ssp2arm(int op)
1045{
1046 switch (op) {
1047 case 1: return A_OP_SUB;
1048 case 3: return A_OP_CMP;
1049 case 4: return A_OP_ADD;
1050 case 5: return A_OP_AND;
1051 case 6: return A_OP_ORR;
1052 case 7: return A_OP_EOR;
1053 }
1054
1055 tr_unhandled();
1056 return 0;
1057}
1058
1059// -----------------------------------------------------
1060
b9c1d012 1061// SSP_GR0, SSP_X, SSP_Y, SSP_A,
1062// SSP_ST, SSP_STACK, SSP_PC, SSP_P,
1063//@ r4: XXYY
1064//@ r5: A
1065//@ r6: STACK and emu flags
1066//@ r7: SSP context
1067//@ r10: P
1068
bad5731d 1069// read general reg to r0. Trashes r1
d5276282 1070static void tr_GR0_to_r0(int op)
d274c33b 1071{
1072 tr_mov16(0, 0xffff);
1073}
1074
d5276282 1075static void tr_X_to_r0(int op)
d274c33b 1076{
1077 if (hostreg_r[0] != (SSP_X<<16)) {
1078 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1079 hostreg_r[0] = SSP_X<<16;
1080 }
1081}
1082
d5276282 1083static void tr_Y_to_r0(int op)
d274c33b 1084{
1085 // TODO..
1086 if (hostreg_r[0] != (SSP_Y<<16)) {
1087 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1088 hostreg_r[0] = SSP_Y<<16;
1089 }
1090}
1091
d5276282 1092static void tr_A_to_r0(int op)
d274c33b 1093{
1094 if (hostreg_r[0] != (SSP_A<<16)) {
1095 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1096 hostreg_r[0] = SSP_A<<16;
1097 }
1098}
1099
d5276282 1100static void tr_ST_to_r0(int op)
d274c33b 1101{
1102 // VR doesn't need much accuracy here..
1103 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1104 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1105 hostreg_r[0] = -1;
1106}
1107
d5276282 1108static void tr_STACK_to_r0(int op)
d274c33b 1109{
1110 // 448
1111 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1112 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1113 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1114 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1115 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1116 hostreg_r[0] = hostreg_r[1] = -1;
1117}
1118
d5276282 1119static void tr_PC_to_r0(int op)
d274c33b 1120{
bad5731d 1121 tr_mov16(0, known_regs.gr[SSP_PC].h);
d274c33b 1122}
1123
d5276282 1124static void tr_P_to_r0(int op)
d274c33b 1125{
1126 tr_flush_dirty_P();
1127 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1128 hostreg_r[0] = -1;
1129}
d5276282 1130
1131static void tr_AL_to_r0(int op)
ede7220f 1132{
d5276282 1133 if (op == 0x000f) {
1134 if (known_regb & KRREG_PMC) {
1135 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1136 } else {
1137 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1138 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1139 EOP_STR_IMM(0,7,0x484);
1140 }
1141 }
1142
1143 if (hostreg_r[0] != (SSP_AL<<16)) {
1144 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1145 hostreg_r[0] = SSP_AL<<16;
1146 }
ede7220f 1147}
ede7220f 1148
d5276282 1149static void tr_PMX_to_r0(int reg)
ede7220f 1150{
ede7220f 1151 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1152 {
d5276282 1153 known_regs.pmac_read[reg] = known_regs.pmc.v;
ede7220f 1154 known_regs.emu_status &= ~SSP_PMC_SET;
0336d643 1155 known_regb |= 1 << (20+reg);
d5276282 1156 dirty_regb |= 1 << (20+reg);
1157 return;
ede7220f 1158 }
1159
d5276282 1160 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
ede7220f 1161 {
d5276282 1162 u32 pmcv = known_regs.pmac_read[reg];
1163 int mode = pmcv>>16;
1164 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1165
ede7220f 1166 if ((mode & 0xfff0) == 0x0800)
1167 {
ede7220f 1168 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1169 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1170 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
d5276282 1171 known_regs.pmac_read[reg] += 1;
ede7220f 1172 }
1173 else if ((mode & 0x47ff) == 0x0018) // DRAM
1174 {
1175 int inc = get_inc(mode);
ede7220f 1176 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1177 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1178 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
d5276282 1179 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
ede7220f 1180 {
1181 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1182 tr_flush_dirty_ST();
1183 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1184 EOP_TST_REG_SIMPLE(0,0);
d5276282 1185 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1186 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
ede7220f 1187 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1188 }
d5276282 1189 known_regs.pmac_read[reg] += inc;
ede7220f 1190 }
1191 else
1192 {
1193 tr_unhandled();
1194 }
d5276282 1195 known_regs.pmc.v = known_regs.pmac_read[reg];
1196 //known_regb |= KRREG_PMC;
1197 dirty_regb |= KRREG_PMC;
1198 dirty_regb |= 1 << (20+reg);
1199 hostreg_r[0] = hostreg_r[1] = -1;
1200 return;
1201 }
ede7220f 1202
d5276282 1203 known_regb &= ~KRREG_PMC;
1204 dirty_regb &= ~KRREG_PMC;
1205 known_regb &= ~(1 << (20+reg));
1206 dirty_regb &= ~(1 << (20+reg));
1207
1208 // call the C code to handle this
1209 tr_flush_dirty_ST();
1210 //tr_flush_dirty_pmcrs();
1211 tr_mov16(0, reg);
1212 emit_call(ssp_pm_read);
1213 hostreg_clear();
1214}
1215
1216static void tr_PM0_to_r0(int op)
1217{
1218 tr_PMX_to_r0(0);
1219}
1220
1221static void tr_PM1_to_r0(int op)
1222{
1223 tr_PMX_to_r0(1);
1224}
1225
1226static void tr_PM2_to_r0(int op)
1227{
1228 tr_PMX_to_r0(2);
1229}
1230
1231static void tr_XST_to_r0(int op)
1232{
1233 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1234 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1235}
1236
1237static void tr_PM4_to_r0(int op)
1238{
1239 tr_PMX_to_r0(4);
1240}
1241
1242static void tr_PMC_to_r0(int op)
1243{
1244 if (known_regb & KRREG_PMC)
1245 {
1246 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1247 known_regs.emu_status |= SSP_PMC_SET;
1248 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1249 // do nothing - this is handled elsewhere
1250 } else {
1251 tr_mov16(0, known_regs.pmc.l);
1252 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1253 }
1254 }
1255 else
1256 {
1257 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1258 tr_flush_dirty_ST();
1259 if (op != 0x000e)
1260 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1261 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1262 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1263 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1264 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1265 EOP_STR_IMM(1,7,0x484);
1266 hostreg_r[0] = hostreg_r[1] = -1;
ede7220f 1267 }
ede7220f 1268}
1269
d274c33b 1270
d5276282 1271typedef void (tr_read_func)(int op);
d274c33b 1272
d5276282 1273static tr_read_func *tr_read_funcs[16] =
d274c33b 1274{
1275 tr_GR0_to_r0,
1276 tr_X_to_r0,
1277 tr_Y_to_r0,
1278 tr_A_to_r0,
1279 tr_ST_to_r0,
1280 tr_STACK_to_r0,
1281 tr_PC_to_r0,
d5276282 1282 tr_P_to_r0,
1283 tr_PM0_to_r0,
1284 tr_PM1_to_r0,
1285 tr_PM2_to_r0,
1286 tr_XST_to_r0,
1287 tr_PM4_to_r0,
1288 (tr_read_func *)tr_unhandled,
1289 tr_PMC_to_r0,
1290 tr_AL_to_r0
d274c33b 1291};
1292
1293
b9c1d012 1294// write r0 to general reg handlers. Trashes r1
6e39239f 1295#define TR_WRITE_R0_TO_REG(reg) \
1296{ \
1297 hostreg_sspreg_changed(reg); \
1298 hostreg_r[0] = (reg)<<16; \
1299 if (const_val != -1) { \
1300 known_regs.gr[reg].h = const_val; \
1301 known_regb |= 1 << (reg); \
1302 } else { \
1303 known_regb &= ~(1 << (reg)); \
1304 } \
b9c1d012 1305}
1306
6e39239f 1307static void tr_r0_to_GR0(int const_val)
b9c1d012 1308{
1309 // do nothing
1310}
1311
6e39239f 1312static void tr_r0_to_X(int const_val)
b9c1d012 1313{
1314 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1315 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1316 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
6e39239f 1317 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1318 TR_WRITE_R0_TO_REG(SSP_X);
b9c1d012 1319}
1320
6e39239f 1321static void tr_r0_to_Y(int const_val)
b9c1d012 1322{
1323 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1324 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1325 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
bad5731d 1326 dirty_regb |= KRREG_P;
6e39239f 1327 TR_WRITE_R0_TO_REG(SSP_Y);
b9c1d012 1328}
1329
6e39239f 1330static void tr_r0_to_A(int const_val)
b9c1d012 1331{
1332 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
d274c33b 1333 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
b9c1d012 1334 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
6e39239f 1335 TR_WRITE_R0_TO_REG(SSP_A);
b9c1d012 1336}
1337
6e39239f 1338static void tr_r0_to_ST(int const_val)
b9c1d012 1339{
1340 // VR doesn't need much accuracy here..
1341 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1342 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1343 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
6e39239f 1344 TR_WRITE_R0_TO_REG(SSP_ST);
b9c1d012 1345 hostreg_r[1] = -1;
6e39239f 1346 dirty_regb &= ~KRREG_ST;
b9c1d012 1347}
1348
6e39239f 1349static void tr_r0_to_STACK(int const_val)
b9c1d012 1350{
1351 // 448
1352 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1353 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
d274c33b 1354 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
b9c1d012 1355 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
d274c33b 1356 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
b9c1d012 1357 hostreg_r[1] = -1;
1358}
1359
6e39239f 1360static void tr_r0_to_PC(int const_val)
b9c1d012 1361{
1362 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
d274c33b 1363 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
b9c1d012 1364 hostreg_r[1] = -1;
1365}
1366
d5276282 1367static void tr_r0_to_AL(int const_val)
1368{
1369 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1370 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1371 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1372 hostreg_sspreg_changed(SSP_AL);
1373 if (const_val != -1) {
1374 known_regs.gr[SSP_A].l = const_val;
1375 known_regb |= 1 << SSP_AL;
1376 } else
1377 known_regb &= ~(1 << SSP_AL);
1378}
1379
1380static void tr_r0_to_PMX(int reg)
1381{
e122fae6 1382#if 1
d5276282 1383 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1384 {
1385 known_regs.pmac_write[reg] = known_regs.pmc.v;
1386 known_regs.emu_status &= ~SSP_PMC_SET;
1387 known_regb |= 1 << (25+reg);
1388 dirty_regb |= 1 << (25+reg);
1389 return;
1390 }
1391#endif
e122fae6 1392#if 1
d5276282 1393 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1394 {
1395 int mode, addr;
1396
1397 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1398
1399 mode = known_regs.pmac_write[reg]>>16;
1400 addr = known_regs.pmac_write[reg]&0xffff;
1401 if ((mode & 0x43ff) == 0x0018) // DRAM
1402 {
1403 int inc = get_inc(mode);
1404 if (mode & 0x0400) tr_unhandled();
1405 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1406 emit_mov_const(A_COND_AL, 2, addr<<1);
1407 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1408 known_regs.pmac_write[reg] += inc;
1409 }
1410 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1411 {
1412 if (mode & 0x0400) tr_unhandled();
1413 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1414 emit_mov_const(A_COND_AL, 2, addr<<1);
1415 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1416 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1417 }
1418 else if ((mode & 0x47ff) == 0x001c) // IRAM
1419 {
1420 int inc = get_inc(mode);
1421 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1422 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1423 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
e122fae6 1424 EOP_MOV_IMM(1,0,1);
1425 EOP_STR_IMM(1,7,0x494); // iram_dirty
d5276282 1426 known_regs.pmac_write[reg] += inc;
1427 }
1428 else
1429 tr_unhandled();
1430
1431 known_regs.pmc.v = known_regs.pmac_write[reg];
1432 //known_regb |= KRREG_PMC;
1433 dirty_regb |= KRREG_PMC;
1434 dirty_regb |= 1 << (25+reg);
1435 hostreg_r[1] = hostreg_r[2] = -1;
e122fae6 1436 return;
d5276282 1437 }
1438
1439 known_regb &= ~KRREG_PMC;
1440 dirty_regb &= ~KRREG_PMC;
1441 known_regb &= ~(1 << (25+reg));
1442 dirty_regb &= ~(1 << (25+reg));
e122fae6 1443#else
d5276282 1444tr_flush_dirty_pmcrs();
d5276282 1445hostreg_clear();
1446known_regb &= ~KRREG_PMC;
1447dirty_regb &= ~KRREG_PMC;
1448known_regb &= ~(1 << (25+reg));
1449dirty_regb &= ~(1 << (25+reg));
e122fae6 1450#endif
d5276282 1451
1452
1453 // call the C code to handle this
1454 tr_flush_dirty_ST();
1455 //tr_flush_dirty_pmcrs();
1456 tr_mov16(1, reg);
1457 emit_call(ssp_pm_write);
1458 hostreg_clear();
1459}
1460
1461static void tr_r0_to_PM0(int const_val)
1462{
1463 tr_r0_to_PMX(0);
1464}
1465
1466static void tr_r0_to_PM1(int const_val)
1467{
1468 tr_r0_to_PMX(1);
1469}
1470
1471static void tr_r0_to_PM2(int const_val)
1472{
1473 tr_r0_to_PMX(2);
1474}
1475
1476static void tr_r0_to_PM4(int const_val)
1477{
1478 tr_r0_to_PMX(4);
1479}
1480
1481static void tr_r0_to_PMC(int const_val)
1482{
1483 if ((known_regb & KRREG_PMC) && const_val != -1)
1484 {
1485 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1486 known_regs.emu_status |= SSP_PMC_SET;
1487 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1488 known_regs.pmc.h = const_val;
1489 } else {
1490 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1491 known_regs.pmc.l = const_val;
1492 }
1493 }
1494 else
1495 {
1496 tr_flush_dirty_ST();
1497 if (known_regb & KRREG_PMC) {
1498 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1499 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1500 known_regb &= ~KRREG_PMC;
1501 dirty_regb &= ~KRREG_PMC;
1502 }
1503 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1504 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1505 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1506 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1507 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1508 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1509 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1510 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1511 EOP_STR_IMM(1,7,0x484);
1512 hostreg_r[1] = hostreg_r[2] = -1;
1513 }
1514}
1515
6e39239f 1516typedef void (tr_write_func)(int const_val);
b9c1d012 1517
d5276282 1518static tr_write_func *tr_write_funcs[16] =
b9c1d012 1519{
1520 tr_r0_to_GR0,
1521 tr_r0_to_X,
1522 tr_r0_to_Y,
1523 tr_r0_to_A,
1524 tr_r0_to_ST,
1525 tr_r0_to_STACK,
1526 tr_r0_to_PC,
d5276282 1527 (tr_write_func *)tr_unhandled,
1528 tr_r0_to_PM0,
1529 tr_r0_to_PM1,
1530 tr_r0_to_PM2,
1531 (tr_write_func *)tr_unhandled,
1532 tr_r0_to_PM4,
1533 (tr_write_func *)tr_unhandled,
1534 tr_r0_to_PMC,
1535 tr_r0_to_AL
b9c1d012 1536};
1537
0e4d7ba5 1538static void tr_mac_load_XY(int op)
1539{
1540 tr_rX_read(op&3, (op>>2)&3); // X
1541 EOP_MOV_REG_LSL(4, 0, 16);
1542 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1543 EOP_ORR_REG_SIMPLE(4, 0);
1544 dirty_regb |= KRREG_P;
1545 hostreg_sspreg_changed(SSP_X);
1546 hostreg_sspreg_changed(SSP_Y);
1547 known_regb &= ~KRREG_X;
1548 known_regb &= ~KRREG_Y;
1549}
1550
ede7220f 1551// -----------------------------------------------------
1552
ede7220f 1553static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
0e4d7ba5 1554{
ede7220f 1555 u32 pmcv, tmpv;
1556 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1557
1558 // programming PMC:
1559 // ldi PMC, imm1
1560 // ldi PMC, imm2
1561 (*pc)++;
1562 pmcv = imm | (PROGRAM((*pc)++) << 16);
d5276282 1563 known_regs.pmc.v = pmcv;
ede7220f 1564 known_regb |= KRREG_PMC;
d5276282 1565 dirty_regb |= KRREG_PMC;
ede7220f 1566 known_regs.emu_status |= SSP_PMC_SET;
1567
1568 // check for possible reg programming
1569 tmpv = PROGRAM(*pc);
1570 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1571 {
1572 int is_write = (tmpv & 0xff8f) == 0x80;
1573 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1574 if (reg > 4) tr_unhandled();
d5276282 1575 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
ede7220f 1576 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1577 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
d5276282 1578 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
ede7220f 1579 known_regs.emu_status &= ~SSP_PMC_SET;
1580 (*pc)++;
1581 return 5;
0e4d7ba5 1582 }
1583
d5276282 1584 tr_unhandled();
ede7220f 1585 return 4;
1586}
1587
1588static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1589
1590static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1591{
1592 // ldi ST, 0
1593 // ldi PM0, 0
1594 // ldi PM0, 0
1595 // ldi ST, 60h
1596 unsigned short *pp;
1597 if (op != 0x0840 || imm != 0) return 0;
1598 pp = PROGRAM_P(*pc);
1599 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1600
1601 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1602 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1603 hostreg_sspreg_changed(SSP_ST);
1604 known_regs.gr[SSP_ST].h = 0x60;
1605 known_regb |= 1 << SSP_ST;
1606 dirty_regb &= ~KRREG_ST;
1607 (*pc) += 3*2;
1608 return 4*2;
0e4d7ba5 1609}
5d817c91 1610
d5276282 1611static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1612{
1613 // @ 3DA2 and 426A
1614 // ld PMC, (r3|00)
1615 // ld (r3|00), PMC
1616 // ld -, AL
1617 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1618
1619 tr_bank_read(0);
1620 EOP_MOV_REG_LSL(0, 0, 4);
1621 EOP_ORR_REG_LSR(0, 0, 0, 16);
1622 tr_bank_write(0);
1623 (*pc) += 2;
1624 return 3;
1625}
1626
ede7220f 1627// -----------------------------------------------------
1628
5d817c91 1629static int translate_op(unsigned int op, int *pc, int imm)
1630{
0e4d7ba5 1631 u32 tmpv, tmpv2, tmpv3;
5d817c91 1632 int ret = 0;
bad5731d 1633 known_regs.gr[SSP_PC].h = *pc;
5d817c91 1634
e807ac75 1635 switch (op >> 9)
1636 {
1637 // ld d, s
f48f5e3b 1638 case 0x00:
5d817c91 1639 if (op == 0) { ret++; break; } // nop
d274c33b 1640 tmpv = op & 0xf; // src
1641 tmpv2 = (op >> 4) & 0xf; // dst
e122fae6 1642 //if (tmpv2 >= 8) return -1; // TODO
d274c33b 1643 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1644 tr_flush_dirty_P();
1645 EOP_MOV_REG_SIMPLE(5, 10);
d5276282 1646 hostreg_sspreg_changed(SSP_A);
bad5731d 1647 known_regb &= ~(KRREG_A|KRREG_AL);
d274c33b 1648 ret++; break;
1649 }
d5276282 1650 tr_read_funcs[tmpv](op);
6e39239f 1651 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
ede7220f 1652 if (tmpv2 == SSP_PC) ret |= 0x10000;
bad5731d 1653 ret++; break;
1654
1655 // ld d, (ri)
89fea1e9 1656 case 0x01: {
1657 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1658 int r = (op&3) | ((op>>6)&4);
1659 int mod = (op>>2)&3;
1660 tmpv = (op >> 4) & 0xf; // dst
d5276282 1661 ret = tr_detect_rotate(op, pc, imm);
1662 if (ret > 0) break;
89fea1e9 1663 if (tmpv >= 8) return -1; // TODO
1664 if (tmpv != 0)
1665 tr_rX_read(r, mod);
1666 else tr_ptrr_mod(r, mod, 1, 1);
6e39239f 1667 tr_write_funcs[tmpv](-1);
ede7220f 1668 if (tmpv == SSP_PC) ret |= 0x10000;
89fea1e9 1669 ret++; break;
1670 }
bad5731d 1671
1672 // ld (ri), s
1673 case 0x02:
1674 tmpv = (op >> 4) & 0xf; // src
d5276282 1675 tr_read_funcs[tmpv](op);
0e4d7ba5 1676 tr_rX_write(op);
d274c33b 1677 ret++; break;
f48f5e3b 1678
1679 // ld a, adr
1680 case 0x03:
5d817c91 1681 tr_bank_read(op&0x1ff);
6e39239f 1682 tr_r0_to_A(-1);
5d817c91 1683 ret++; break;
1684
b9c1d012 1685 // ldi d, imm
1686 case 0x04:
ede7220f 1687 tmpv = (op & 0xf0) >> 4; // dst
1688 ret = tr_detect_pm0_block(op, pc, imm);
1689 if (ret > 0) break;
b9c1d012 1690 if (tmpv < 8)
1691 {
1692 tr_mov16(0, imm);
6e39239f 1693 tr_write_funcs[tmpv](imm);
a6fb500b 1694 ret += 2; break;
b9c1d012 1695 }
ede7220f 1696 ret = tr_detect_set_pm(op, pc, imm);
1697 if (ret > 0) break;
1698 if (tmpv == SSP_PC) ret |= 0x10000;
1699 return -1; /* TODO.. */
b9c1d012 1700
bad5731d 1701 // ld d, ((ri))
0e4d7ba5 1702 case 0x05:
bad5731d 1703 tmpv2 = (op >> 4) & 0xf; // dst
1704 if (tmpv2 >= 8) return -1; // TODO
0e4d7ba5 1705 tr_rX_read2(op);
6e39239f 1706 tr_write_funcs[tmpv2](-1);
ede7220f 1707 if (tmpv2 == SSP_PC) ret |= 0x10000;
0e4d7ba5 1708 ret += 3; break;
b9c1d012 1709
5d817c91 1710 // ldi (ri), imm
1711 case 0x06:
5d817c91 1712 tr_mov16(0, imm);
0e4d7ba5 1713 tr_rX_write(op);
a6fb500b 1714 ret += 2; break;
f48f5e3b 1715
1716 // ld adr, a
1717 case 0x07:
d5276282 1718 tr_A_to_r0(op);
5d817c91 1719 tr_bank_write(op&0x1ff);
1720 ret++; break;
1721
d274c33b 1722 // ld d, ri
1723 case 0x09: {
bad5731d 1724 int r;
d274c33b 1725 r = (op&3) | ((op>>6)&4); // src
bad5731d 1726 tmpv2 = (op >> 4) & 0xf; // dst
d274c33b 1727 if (tmpv2 >= 8) tr_unhandled();
bad5731d 1728 if ((r&3) == 3) tr_unhandled();
d274c33b 1729
bad5731d 1730 if (known_regb & (1 << (r+8))) {
1731 tr_mov16(0, known_regs.r[r]);
6e39239f 1732 tr_write_funcs[tmpv2](known_regs.r[r]);
d274c33b 1733 } else {
bad5731d 1734 int reg = (r < 4) ? 8 : 9;
d274c33b 1735 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1736 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1737 hostreg_r[0] = -1;
6e39239f 1738 tr_write_funcs[tmpv2](-1);
d274c33b 1739 }
d274c33b 1740 ret++; break;
1741 }
1742
bad5731d 1743 // ld ri, s
1744 case 0x0a: {
1745 int r;
1746 r = (op&3) | ((op>>6)&4); // dst
1747 tmpv = (op >> 4) & 0xf; // src
bad5731d 1748 if ((r&3) == 3) tr_unhandled();
1749
1750 if (known_regb & (1 << tmpv)) {
1751 known_regs.r[r] = known_regs.gr[tmpv].h;
1752 known_regb |= 1 << (r + 8);
1753 dirty_regb |= 1 << (r + 8);
1754 } else {
1755 int reg = (r < 4) ? 8 : 9;
1756 int ror = ((4 - (r&3))*8) & 0x1f;
d5276282 1757 tr_read_funcs[tmpv](op);
bad5731d 1758 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1759 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1760 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1761 hostreg_r[0] = -1;
1762 known_regb &= ~(1 << (r+8));
1763 dirty_regb &= ~(1 << (r+8));
1764 }
1765 ret++; break;
1766 }
1767
5d817c91 1768 // ldi ri, simm
1769 case 0x0c ... 0x0f:
1770 tmpv = (op>>8)&7;
bad5731d 1771 known_regs.r[tmpv] = op;
1772 known_regb |= 1 << (tmpv + 8);
5d817c91 1773 dirty_regb |= 1 << (tmpv + 8);
1774 ret++; break;
bad5731d 1775
a6fb500b 1776 // call cond, addr
6e39239f 1777 case 0x24: {
1778 u32 *jump_op = NULL;
a6fb500b 1779 tmpv = tr_cond_check(op);
6e39239f 1780 if (tmpv != A_COND_AL) {
1781 jump_op = tcache_ptr;
1782 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1783 }
1784 tr_mov16(0, *pc);
1785 tr_r0_to_STACK(*pc);
1786 if (tmpv != A_COND_AL) {
1787 u32 *real_ptr = tcache_ptr;
1788 tcache_ptr = jump_op;
1789 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1790 tcache_ptr = real_ptr;
1791 }
a6fb500b 1792 tr_mov16_cond(tmpv, 0, imm);
1793 if (tmpv != A_COND_AL) {
1794 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1795 }
6e39239f 1796 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1797 ret |= 0x10000;
a6fb500b 1798 ret += 2; break;
6e39239f 1799 }
a6fb500b 1800
bad5731d 1801 // ld d, (a)
1802 case 0x25:
bad5731d 1803 tmpv2 = (op >> 4) & 0xf; // dst
1804 if (tmpv2 >= 8) return -1; // TODO
1805
d5276282 1806 tr_A_to_r0(op);
bad5731d 1807 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1808 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1809 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1810 hostreg_r[0] = hostreg_r[1] = -1;
6e39239f 1811 tr_write_funcs[tmpv2](-1);
ede7220f 1812 if (tmpv2 == SSP_PC) ret |= 0x10000;
a6fb500b 1813 ret += 3; break;
bad5731d 1814
1815 // bra cond, addr
a6fb500b 1816 case 0x26:
bad5731d 1817 tmpv = tr_cond_check(op);
1818 tr_mov16_cond(tmpv, 0, imm);
1819 if (tmpv != A_COND_AL) {
bad5731d 1820 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1821 }
6e39239f 1822 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
ede7220f 1823 ret |= 0x10000;
a6fb500b 1824 ret += 2; break;
bad5731d 1825
89fea1e9 1826 // mod cond, op
89fea1e9 1827 case 0x48: {
1828 // check for repeats of this op
1829 tmpv = 1; // count
1830 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1831 (*pc)++; tmpv++;
1832 }
6e39239f 1833 if ((op&0xf0) != 0) // !always
1834 tr_make_dirty_ST();
1835
89fea1e9 1836 tmpv2 = tr_cond_check(op);
1837 switch (op & 7) {
1838 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1839 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1840 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
6e39239f 1841 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
1842 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
89fea1e9 1843 hostreg_r[1] = -1; break; // abs
1844 default: tr_unhandled();
1845 }
6e39239f 1846
1847 hostreg_sspreg_changed(SSP_A);
1848 dirty_regb |= KRREG_ST;
1849 known_regb &= ~KRREG_ST;
1850 known_regb &= ~(KRREG_A|KRREG_AL);
89fea1e9 1851 ret += tmpv; break;
1852 }
0e4d7ba5 1853
bad5731d 1854 // mpys?
1855 case 0x1b:
0e4d7ba5 1856 tr_flush_dirty_P();
1857 tr_mac_load_XY(op);
1858 tr_make_dirty_ST();
1859 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1860 hostreg_sspreg_changed(SSP_A);
1861 known_regb &= ~(KRREG_A|KRREG_AL);
1862 dirty_regb |= KRREG_ST;
1863 ret++; break;
bad5731d 1864
1865 // mpya (rj), (ri), b
1866 case 0x4b:
0e4d7ba5 1867 tr_flush_dirty_P();
1868 tr_mac_load_XY(op);
1869 tr_make_dirty_ST();
1870 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1871 hostreg_sspreg_changed(SSP_A);
1872 known_regb &= ~(KRREG_A|KRREG_AL);
1873 dirty_regb |= KRREG_ST;
1874 ret++; break;
bad5731d 1875
1876 // mld (rj), (ri), b
1877 case 0x5b:
0e4d7ba5 1878 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1879 hostreg_sspreg_changed(SSP_A);
1880 known_regs.gr[SSP_A].v = 0;
bad5731d 1881 known_regb |= (KRREG_A|KRREG_AL);
0e4d7ba5 1882 dirty_regb |= KRREG_ST;
1883 tr_mac_load_XY(op);
1884 ret++; break;
1885
1886 // OP a, s
1887 case 0x10:
1888 case 0x30:
1889 case 0x40:
1890 case 0x50:
1891 case 0x60:
1892 case 0x70:
1893 tmpv = op & 0xf; // src
1894 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1895 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
0e4d7ba5 1896 if (tmpv == SSP_P) {
1897 tr_flush_dirty_P();
1898 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1899 } else if (tmpv == SSP_A) {
1900 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1901 } else {
d5276282 1902 tr_read_funcs[tmpv](op);
0e4d7ba5 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 }
1905 hostreg_sspreg_changed(SSP_A);
1906 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1907 dirty_regb |= KRREG_ST;
1908 ret++; break;
1909
1910 // OP a, (ri)
1911 case 0x11:
1912 case 0x31:
1913 case 0x41:
1914 case 0x51:
1915 case 0x61:
1916 case 0x71:
1917 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1918 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1919 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
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++; break;
1925
1926 // OP a, adr
1927 case 0x13:
1928 case 0x33:
1929 case 0x43:
1930 case 0x53:
1931 case 0x63:
1932 case 0x73:
1933 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1934 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1935 tr_bank_read(op&0x1ff);
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++; break;
1941
1942 // OP a, imm
1943 case 0x14:
1944 case 0x34:
1945 case 0x44:
1946 case 0x54:
1947 case 0x64:
1948 case 0x74:
1949 tmpv = (op & 0xf0) >> 4;
1950 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1951 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1952 tr_mov16(0, imm);
1953 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1954 hostreg_sspreg_changed(SSP_A);
1955 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1956 dirty_regb |= KRREG_ST;
1957 ret += 2; break;
1958
1959 // OP a, ((ri))
1960 case 0x15:
1961 case 0x35:
1962 case 0x45:
1963 case 0x55:
1964 case 0x65:
1965 case 0x75:
1966 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1967 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1968 tr_rX_read2(op);
1969 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1970 hostreg_sspreg_changed(SSP_A);
1971 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1972 dirty_regb |= KRREG_ST;
1973 ret += 3; break;
1974
1975 // OP a, ri
1976 case 0x19:
1977 case 0x39:
1978 case 0x49:
1979 case 0x59:
1980 case 0x69:
1981 case 0x79: {
1982 int r;
1983 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1984 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1985 r = (op&3) | ((op>>6)&4); // src
1986 if ((r&3) == 3) tr_unhandled();
1987
1988 if (known_regb & (1 << (r+8))) {
1989 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1990 } else {
1991 int reg = (r < 4) ? 8 : 9;
1992 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1993 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1994 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1995 hostreg_r[0] = -1;
1996 }
1997 hostreg_sspreg_changed(SSP_A);
1998 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1999 dirty_regb |= KRREG_ST;
2000 ret++; break;
2001 }
2002
2003 // OP simm
2004 case 0x1c:
2005 case 0x3c:
2006 case 0x4c:
2007 case 0x5c:
2008 case 0x6c:
2009 case 0x7c:
2010 tmpv2 = tr_aop_ssp2arm(op>>13); // op
2011 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
2012 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
2013 hostreg_sspreg_changed(SSP_A);
2014 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
2015 dirty_regb |= KRREG_ST;
bad5731d 2016 ret++; break;
e807ac75 2017 }
2018
5d817c91 2019 return ret;
e807ac75 2020}
2021
df143b36 2022static void *translate_block(int pc)
726bbb3e 2023{
e807ac75 2024 unsigned int op, op1, imm, ccount = 0;
5c129565 2025 unsigned int *block_start;
ede7220f 2026 int ret, ret_prev = -1, tpc;
5c129565 2027
2028 // create .pool
e807ac75 2029 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
726bbb3e 2030
259ed0ea 2031 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
5c129565 2032 block_start = tcache_ptr;
bad5731d 2033 known_regb = 0;
2034 dirty_regb = KRREG_P;
d5276282 2035 known_regs.emu_status = 0;
5d817c91 2036 hostreg_clear();
5c129565 2037
2038 emit_block_prologue();
726bbb3e 2039
e807ac75 2040 for (; ccount < 100;)
726bbb3e 2041 {
259ed0ea 2042 //printf(" insn #%i\n", icount);
726bbb3e 2043 op = PROGRAM(pc++);
2044 op1 = op >> 9;
e807ac75 2045 imm = (u32)-1;
5c129565 2046
e807ac75 2047 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2048 imm = PROGRAM(pc++); // immediate
ede7220f 2049 tpc = pc;
5c129565 2050
5d817c91 2051 ret = translate_op(op, &pc, imm);
e807ac75 2052 if (ret <= 0)
2053 {
89fea1e9 2054 tr_flush_dirty_prs();
2055 tr_flush_dirty_ST();
ede7220f 2056 tr_flush_dirty_pmcrs();
d5276282 2057 known_regs.emu_status = 0;
5d817c91 2058
bad5731d 2059 emit_mov_const(A_COND_AL, 0, op);
5c129565 2060
e807ac75 2061 // need immediate?
2062 if (imm != (u32)-1)
bad5731d 2063 emit_mov_const(A_COND_AL, 1, imm);
5c129565 2064
e807ac75 2065 // dump PC
2066 emit_pc_dump(pc);
5c129565 2067
d274c33b 2068 if (ret_prev > 0) emit_call(regfile_store);
2069 emit_call(in_funcs[op1]);
2070 emit_call(regfile_load);
e807ac75 2071
2072 if (in_funcs[op1] == NULL) {
2073 printf("NULL func! op=%08x (%02x)\n", op, op1);
2074 exit(1);
2075 }
2076 ccount++;
5d817c91 2077 hostreg_clear();
bad5731d 2078 dirty_regb |= KRREG_P;
2079 known_regb = 0;
892b1dd2 2080 }
e807ac75 2081 else
ede7220f 2082 {
2083 ccount += ret & 0xffff;
2084 if (ret & 0x10000) break;
726bbb3e 2085 }
ede7220f 2086
d274c33b 2087 ret_prev = ret;
726bbb3e 2088 }
5c129565 2089
89fea1e9 2090 tr_flush_dirty_prs();
2091 tr_flush_dirty_ST();
ede7220f 2092 tr_flush_dirty_pmcrs();
e807ac75 2093 emit_block_epilogue(ccount + 1);
5c129565 2094 *tcache_ptr++ = 0xffffffff; // end of block
726bbb3e 2095 //printf(" %i inst\n", icount);
2096
892b1dd2 2097 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
726bbb3e 2098 printf("tcache overflow!\n");
2099 fflush(stdout);
2100 exit(1);
2101 }
2102
2103 // stats
2104 nblocks++;
df143b36 2105 //if (pc >= 0x400)
892b1dd2 2106 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
259ed0ea 2107 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
df143b36 2108
5d817c91 2109#ifdef DUMP_BLOCK
5c129565 2110 {
2111 FILE *f = fopen("tcache.bin", "wb");
2112 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2113 fclose(f);
2114 }
2115 exit(0);
2116#endif
259ed0ea 2117
2118 handle_caches();
2119
5c129565 2120 return block_start;
726bbb3e 2121}
2122
2123
2124
2125// -----------------------------------------------------
2126
e807ac75 2127int ssp1601_dyn_startup(void)
726bbb3e 2128{
e807ac75 2129 memset(tcache, 0, TCACHE_SIZE);
726bbb3e 2130 memset(block_table, 0, sizeof(block_table));
df143b36 2131 memset(block_table_iram, 0, sizeof(block_table_iram));
e807ac75 2132 tcache_ptr = tcache;
5c129565 2133 *tcache_ptr++ = 0xffffffff;
726bbb3e 2134
d5276282 2135#ifdef ARM
2136 // hle'd blocks
2137 block_table[0x400] = (void *) ssp_hle_800;
2138#endif
2139
6e39239f 2140// TODO: rm
2141{
2142static unsigned short dummy = 0;
2143PC = &dummy;
2144}
726bbb3e 2145 return 0;
2146}
2147
2148
2149void ssp1601_dyn_reset(ssp1601_t *ssp)
2150{
2151 ssp1601_reset_local(ssp);
e122fae6 2152 ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2153 ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2154 ssp->drc.ptr_dram = (unsigned int) svp->dram;
2155 ssp->drc.iram_dirty = 0;
726bbb3e 2156}
2157
726bbb3e 2158void ssp1601_dyn_run(int cycles)
2159{
b9c1d012 2160 if (ssp->emu_status & SSP_WAIT_MASK) return;
2161 //{ printf("%i wait\n", Pico.m.frame_count); return; }
2162 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
2163
5d817c91 2164#ifdef DUMP_BLOCK
2165 rPC = DUMP_BLOCK >> 1;
2166#endif
726bbb3e 2167 while (cycles > 0)
2168 {
e807ac75 2169 int (*trans_entry)(void);
df143b36 2170 if (rPC < 0x800/2)
2171 {
e122fae6 2172 if (ssp->drc.iram_dirty) {
df143b36 2173 iram_context = get_iram_context();
e122fae6 2174 ssp->drc.iram_dirty--;
df143b36 2175 }
2176 if (block_table_iram[iram_context][rPC] == NULL)
2177 block_table_iram[iram_context][rPC] = translate_block(rPC);
5c129565 2178 trans_entry = (void *) block_table_iram[iram_context][rPC];
df143b36 2179 }
2180 else
2181 {
2182 if (block_table[rPC] == NULL)
2183 block_table[rPC] = translate_block(rPC);
5c129565 2184 trans_entry = (void *) block_table[rPC];
df143b36 2185 }
726bbb3e 2186
e807ac75 2187 //printf("enter %04x\n", rPC<<1);
2188 cycles -= trans_entry();
2189 //printf("leave %04x\n", rPC<<1);
726bbb3e 2190 }
2191// debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);
2192// exit(1);
2193}
2194