2 #include "../../PicoInt.h"
5 static unsigned int *block_table[0x5090/2];
6 static unsigned int *block_table_iram[15][0x800/2];
7 static unsigned int *tcache_ptr = NULL;
9 static int nblocks = 0;
10 static int iram_context = 0;
13 #define DUMP_BLOCK 0x0c9a
14 unsigned int tcache[512*1024];
15 void regfile_load(void){}
16 void regfile_store(void){}
19 #define EMBED_INTERPRETER
20 #define ssp1601_reset ssp1601_reset_local
21 #define ssp1601_run ssp1601_run_local
24 #define GET_PPC_OFFS() (GET_PC()*2 - 2)
25 #define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
26 //#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
27 //#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
28 //#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
33 // -----------------------------------------------------
36 static void op00(unsigned int op, unsigned int imm)
39 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
40 if (op == 0) return; // nop
41 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
42 // not sure. MAME claims that only hi word is transfered.
48 tmpv = REG_READ(op & 0x0f);
49 REG_WRITE((op & 0xf0) >> 4, tmpv);
54 static void op01(unsigned int op, unsigned int imm)
57 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
61 static void op02(unsigned int op, unsigned int imm)
64 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
68 static void op04(unsigned int op, unsigned int imm)
70 REG_WRITE((op & 0xf0) >> 4, imm);
74 static void op05(unsigned int op, unsigned int imm)
77 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
81 static void op06(unsigned int op, unsigned int imm)
87 static void op07(unsigned int op, unsigned int imm)
89 ssp->RAM[op & 0x1ff] = rA;
93 static void op09(unsigned int op, unsigned int imm)
96 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
100 static void op0a(unsigned int op, unsigned int imm)
102 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
105 // ldi ri, simm (also op0d op0e op0f)
106 static void op0c(unsigned int op, unsigned int imm)
112 static void op24(unsigned int op, unsigned int imm)
117 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
123 static void op25(unsigned int op, unsigned int imm)
126 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
130 static void op26(unsigned int op, unsigned int imm)
136 if (cond) SET_PC(imm);
142 static void op48(unsigned int op, unsigned int imm)
150 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
151 case 3: rA32 <<= 1; break; // shl
152 case 6: rA32 = -(signed int)rA32; break; // neg
153 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
154 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
155 op&7, GET_PPC_OFFS());
164 static void op1b(unsigned int op, unsigned int imm)
166 read_P(); // update P
167 rA32 -= rP.v; // maybe only upper word?
168 UPD_ACC_ZN // there checking flags after this
169 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
170 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
173 // mpya (rj), (ri), b
174 static void op4b(unsigned int op, unsigned int imm)
176 read_P(); // update P
177 rA32 += rP.v; // confirmed to be 32bit
179 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
180 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
184 static void op5b(unsigned int op, unsigned int imm)
188 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
189 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
193 static void op10(unsigned int op, unsigned int imm)
198 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
203 static void op30(unsigned int op, unsigned int imm)
208 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
213 static void op40(unsigned int op, unsigned int imm)
218 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
223 static void op50(unsigned int op, unsigned int imm)
228 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
233 static void op60(unsigned int op, unsigned int imm)
238 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
243 static void op70(unsigned int op, unsigned int imm)
248 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
254 static void op11(unsigned int op, unsigned int imm)
257 tmpv = ptr1_read(op); OP_SUBA(tmpv);
260 static void op31(unsigned int op, unsigned int imm)
263 tmpv = ptr1_read(op); OP_CMPA(tmpv);
266 static void op41(unsigned int op, unsigned int imm)
269 tmpv = ptr1_read(op); OP_ADDA(tmpv);
272 static void op51(unsigned int op, unsigned int imm)
275 tmpv = ptr1_read(op); OP_ANDA(tmpv);
278 static void op61(unsigned int op, unsigned int imm)
281 tmpv = ptr1_read(op); OP_ORA (tmpv);
284 static void op71(unsigned int op, unsigned int imm)
287 tmpv = ptr1_read(op); OP_EORA(tmpv);
291 static void op03(unsigned int op, unsigned int imm)
294 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
297 static void op13(unsigned int op, unsigned int imm)
300 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
303 static void op33(unsigned int op, unsigned int imm)
306 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
309 static void op43(unsigned int op, unsigned int imm)
312 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
315 static void op53(unsigned int op, unsigned int imm)
318 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
321 static void op63(unsigned int op, unsigned int imm)
324 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
327 static void op73(unsigned int op, unsigned int imm)
330 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
334 static void op14(unsigned int op, unsigned int imm)
339 static void op34(unsigned int op, unsigned int imm)
344 static void op44(unsigned int op, unsigned int imm)
349 static void op54(unsigned int op, unsigned int imm)
354 static void op64(unsigned int op, unsigned int imm)
359 static void op74(unsigned int op, unsigned int imm)
365 static void op15(unsigned int op, unsigned int imm)
368 tmpv = ptr2_read(op); OP_SUBA(tmpv);
371 static void op35(unsigned int op, unsigned int imm)
374 tmpv = ptr2_read(op); OP_CMPA(tmpv);
377 static void op45(unsigned int op, unsigned int imm)
380 tmpv = ptr2_read(op); OP_ADDA(tmpv);
383 static void op55(unsigned int op, unsigned int imm)
386 tmpv = ptr2_read(op); OP_ANDA(tmpv);
389 static void op65(unsigned int op, unsigned int imm)
392 tmpv = ptr2_read(op); OP_ORA (tmpv);
395 static void op75(unsigned int op, unsigned int imm)
398 tmpv = ptr2_read(op); OP_EORA(tmpv);
402 static void op19(unsigned int op, unsigned int imm)
405 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
408 static void op39(unsigned int op, unsigned int imm)
411 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
414 static void op49(unsigned int op, unsigned int imm)
417 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
420 static void op59(unsigned int op, unsigned int imm)
423 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
426 static void op69(unsigned int op, unsigned int imm)
429 tmpv = rIJ[IJind]; OP_ORA (tmpv);
432 static void op79(unsigned int op, unsigned int imm)
435 tmpv = rIJ[IJind]; OP_EORA(tmpv);
439 static void op1c(unsigned int op, unsigned int imm)
444 static void op3c(unsigned int op, unsigned int imm)
449 static void op4c(unsigned int op, unsigned int imm)
454 static void op5c(unsigned int op, unsigned int imm)
459 static void op6c(unsigned int op, unsigned int imm)
464 static void op7c(unsigned int op, unsigned int imm)
469 typedef void (in_func)(unsigned int op, unsigned int imm);
471 static in_func *in_funcs[0x80] =
473 op00, op01, op02, op03, op04, op05, op06, op07,
474 NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
475 op10, op11, NULL, op13, op14, op15, NULL, NULL,
476 NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
477 NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
478 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
479 op30, op31, NULL, op33, op34, op35, NULL, NULL,
480 NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
481 op40, op41, NULL, op43, op44, op45, NULL, NULL,
482 op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
483 op50, op51, NULL, op53, op54, op55, NULL, NULL,
484 NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
485 op60, op61, NULL, op63, op64, op65, NULL, NULL,
486 NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
487 op70, op71, NULL, op73, op74, op75, NULL, NULL,
488 NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
492 static u32 ssp_pm_read(int reg)
496 if (ssp->emu_status & SSP_PMC_SET)
498 ssp->pmac_read[reg] = rPMC.v;
499 ssp->emu_status &= ~SSP_PMC_SET;
504 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
506 mode = ssp->pmac_read[reg]>>16;
507 if ((mode & 0xfff0) == 0x0800) // ROM
509 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
510 ssp->pmac_read[reg] += 1;
512 else if ((mode & 0x47ff) == 0x0018) // DRAM
514 unsigned short *dram = (unsigned short *)svp->dram;
515 int inc = get_inc(mode);
516 d = dram[ssp->pmac_read[reg]&0xffff];
517 ssp->pmac_read[reg] += inc;
520 // PMC value corresponds to last PMR accessed
521 rPMC.v = ssp->pmac_read[reg];
526 static void ssp_pm_write(u32 d, int reg)
528 unsigned short *dram;
531 if (ssp->emu_status & SSP_PMC_SET)
533 ssp->pmac_write[reg] = rPMC.v;
534 ssp->emu_status &= ~SSP_PMC_SET;
539 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
541 dram = (unsigned short *)svp->dram;
542 mode = ssp->pmac_write[reg]>>16;
543 addr = ssp->pmac_write[reg]&0xffff;
544 if ((mode & 0x43ff) == 0x0018) // DRAM
546 int inc = get_inc(mode);
548 overwrite_write(dram[addr], d);
549 } else dram[addr] = d;
550 ssp->pmac_write[reg] += inc;
552 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
555 overwrite_write(dram[addr], d);
556 } else dram[addr] = d;
557 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
559 else if ((mode & 0x47ff) == 0x001c) // IRAM
561 int inc = get_inc(mode);
562 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
563 ssp->pmac_write[reg] += inc;
564 ssp->drc.iram_dirty = 1;
567 rPMC.v = ssp->pmac_write[reg];
571 // -----------------------------------------------------
574 static unsigned char iram_context_map[] =
576 0, 0, 0, 0, 1, 0, 0, 0, // 04
577 0, 0, 0, 0, 0, 0, 2, 0, // 0e
578 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
579 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
580 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
581 0, 0, 0, 0, 0, 0, 0, 0,
582 0, 0,11, 0, 0,12, 0, 0, // 32 35
583 13,14, 0, 0, 0, 0, 0, 0 // 38 39
586 static int get_iram_context(void)
588 unsigned char *ir = (unsigned char *)svp->iram_rom;
589 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
590 val1 = iram_context_map[(val>>1)&0x3f];
593 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
594 //debug_dump2file(name, svp->iram_rom, 0x800);
597 // elprintf(EL_ANOMALY, "iram_context: %02i", val1);
601 // -----------------------------------------------------
603 /* regs with known values */
608 unsigned int pmac_read[5];
609 unsigned int pmac_write[5];
611 unsigned int emu_status;
614 #define KRREG_X (1 << SSP_X)
615 #define KRREG_Y (1 << SSP_Y)
616 #define KRREG_A (1 << SSP_A) /* AH only */
617 #define KRREG_ST (1 << SSP_ST)
618 #define KRREG_STACK (1 << SSP_STACK)
619 #define KRREG_PC (1 << SSP_PC)
620 #define KRREG_P (1 << SSP_P)
621 #define KRREG_PR0 (1 << 8)
622 #define KRREG_PR4 (1 << 12)
623 #define KRREG_AL (1 << 16)
624 #define KRREG_PMCM (1 << 18) /* only mode word of PMC */
625 #define KRREG_PMC (1 << 19)
626 #define KRREG_PM0R (1 << 20)
627 #define KRREG_PM1R (1 << 21)
628 #define KRREG_PM2R (1 << 22)
629 #define KRREG_PM3R (1 << 23)
630 #define KRREG_PM4R (1 << 24)
631 #define KRREG_PM0W (1 << 25)
632 #define KRREG_PM1W (1 << 26)
633 #define KRREG_PM2W (1 << 27)
634 #define KRREG_PM3W (1 << 28)
635 #define KRREG_PM4W (1 << 29)
637 /* bitfield of known register values */
638 static u32 known_regb = 0;
640 /* known vals, which need to be flushed
641 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
642 * ST means flags are being held in ARM PSR
643 * P means that it needs to be recalculated
645 static u32 dirty_regb = 0;
647 /* known values of host regs.
649 * 000000-00ffff - 16bit value
650 * 100000-10ffff - base reg (r7) + 16bit val
651 * 0r0000 - means reg (low) eq gr[r].h, r != AL
653 static int hostreg_r[4];
655 static void hostreg_clear(void)
658 for (i = 0; i < 4; i++)
662 static void hostreg_sspreg_changed(int sspreg)
665 for (i = 0; i < 4; i++)
666 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
670 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
671 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
673 static void tr_unhandled(void)
675 FILE *f = fopen("tcache.bin", "wb");
676 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
678 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
682 /* update P, if needed. Trashes r0 */
683 static void tr_flush_dirty_P(void)
686 if (!(dirty_regb & KRREG_P)) return;
687 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
688 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
689 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
690 EOP_MUL(10, 0, 10); // mul r10, r0, r10
691 dirty_regb &= ~KRREG_P;
695 /* write dirty pr to host reg. Nothing is trashed */
696 static void tr_flush_dirty_pr(int r)
700 if (!(dirty_regb & (1 << (r+8)))) return;
703 case 0: ror = 0; break;
704 case 1: ror = 24/2; break;
705 case 2: ror = 16/2; break;
707 reg = (r < 4) ? 8 : 9;
708 EOP_BIC_IMM(reg,reg,ror,0xff);
709 if (known_regs.r[r] != 0)
710 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
711 dirty_regb &= ~(1 << (r+8));
714 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
715 static void tr_flush_dirty_prs(void)
718 int dirty = dirty_regb >> 8;
720 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
722 if (!(dirty&1)) continue;
724 case 0: ror = 0; break;
725 case 1: ror = 24/2; break;
726 case 2: ror = 16/2; break;
728 reg = (i < 4) ? 8 : 9;
729 EOP_BIC_IMM(reg,reg,ror,0xff);
730 if (known_regs.r[i] != 0)
731 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
733 dirty_regb &= ~0xff00;
736 /* write dirty pr and "forget" it. Nothing is trashed. */
737 static void tr_release_pr(int r)
739 tr_flush_dirty_pr(r);
740 known_regb &= ~(1 << (r+8));
743 /* fush ARM PSR to r6. Trashes r1 */
744 static void tr_flush_dirty_ST(void)
746 if (!(dirty_regb & KRREG_ST)) return;
747 EOP_BIC_IMM(6,6,0,0x0f);
749 EOP_ORR_REG_LSR(6,6,1,28);
750 dirty_regb &= ~KRREG_ST;
754 /* inverse of above. Trashes r1 */
755 static void tr_make_dirty_ST(void)
757 if (dirty_regb & KRREG_ST) return;
758 if (known_regb & KRREG_ST) {
760 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
761 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
762 EOP_MSR_IMM(4/2, flags);
764 EOP_MOV_REG_LSL(1, 6, 28);
768 dirty_regb |= KRREG_ST;
771 /* load 16bit val into host reg r0-r3. Nothing is trashed */
772 static void tr_mov16(int r, int val)
774 if (hostreg_r[r] != val) {
775 emit_mov_const(A_COND_AL, r, val);
780 static void tr_mov16_cond(int cond, int r, int val)
782 emit_mov_const(cond, r, val);
787 static void tr_flush_dirty_pmcrs(void)
789 u32 i, val = (u32)-1;
790 if (!(dirty_regb & 0x3ff80000)) return;
792 if (dirty_regb & KRREG_PMC) {
793 val = known_regs.pmc.v;
794 emit_mov_const(A_COND_AL, 1, val);
795 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
797 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
798 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
802 for (i = 0; i < 5; i++)
804 if (dirty_regb & (1 << (20+i))) {
805 if (val != known_regs.pmac_read[i]) {
806 val = known_regs.pmac_read[i];
807 emit_mov_const(A_COND_AL, 1, val);
809 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
811 if (dirty_regb & (1 << (25+i))) {
812 if (val != known_regs.pmac_write[i]) {
813 val = known_regs.pmac_write[i];
814 emit_mov_const(A_COND_AL, 1, val);
816 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
819 dirty_regb &= ~0x3ff80000;
823 /* read bank word to r0 (upper bits zero). Thrashes r1. */
824 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
828 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
829 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
830 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
834 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
838 /* write r0 to bank. Trashes r1. */
839 static void tr_bank_write(int addr)
843 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
844 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
845 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
849 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
852 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
853 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
855 int modulo_shift = -1; /* unknown */
857 if (mod == 0) return;
859 if (!need_modulo || mod == 1) // +!
861 else if (need_modulo && (known_regb & KRREG_ST)) {
862 modulo_shift = known_regs.gr[SSP_ST].h & 7;
863 if (modulo_shift == 0) modulo_shift = 8;
866 if (modulo_shift == -1)
868 int reg = (r < 4) ? 8 : 9;
870 if (dirty_regb & KRREG_ST) {
871 // avoid flushing ARM flags
872 EOP_AND_IMM(1, 6, 0, 0x70);
873 EOP_SUB_IMM(1, 1, 0, 0x10);
874 EOP_AND_IMM(1, 1, 0, 0x70);
875 EOP_ADD_IMM(1, 1, 0, 0x10);
877 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
878 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
880 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
881 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
882 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
884 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
885 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
887 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
888 else EOP_ADD_REG2_LSL(reg,reg,3,2);
889 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
890 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
891 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
893 else if (known_regb & (1 << (r + 8)))
895 int modulo = (1 << modulo_shift) - 1;
897 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
898 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
902 int reg = (r < 4) ? 8 : 9;
903 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
904 EOP_MOV_REG_ROR(reg,reg,ror);
905 // {add|sub} reg, reg, #1<<shift
906 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
907 EOP_MOV_REG_ROR(reg,reg,32-ror);
911 /* handle writes r0 to (rX). Trashes r1.
912 * fortunately we can ignore modulo increment modes for writes. */
913 static void tr_rX_write(int op)
917 int mod = (op>>2) & 3; // direct addressing
918 tr_bank_write((op & 0x100) + mod);
922 int r = (op&3) | ((op>>6)&4);
923 if (known_regb & (1 << (r + 8))) {
924 tr_bank_write((op&0x100) | known_regs.r[r]);
926 int reg = (r < 4) ? 8 : 9;
927 int ror = ((4 - (r&3))*8) & 0x1f;
928 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
930 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
931 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
932 else EOP_ADD_REG_LSL(1,7,1,1);
933 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
936 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
940 /* read (rX) to r0. Trashes r1-r3. */
941 static void tr_rX_read(int r, int mod)
945 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
949 if (known_regb & (1 << (r + 8))) {
950 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
952 int reg = (r < 4) ? 8 : 9;
953 int ror = ((4 - (r&3))*8) & 0x1f;
954 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
956 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
957 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
958 else EOP_ADD_REG_LSL(1,7,1,1);
959 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
960 hostreg_r[0] = hostreg_r[1] = -1;
962 tr_ptrr_mod(r, mod, 1, 1);
966 /* read ((rX)) to r0. Trashes r1,r2. */
967 static void tr_rX_read2(int op)
969 int r = (op&3) | ((op>>6)&4); // src
972 tr_bank_read((op&0x100) | ((op>>2)&3));
973 } else if (known_regb & (1 << (r+8))) {
974 tr_bank_read((op&0x100) | known_regs.r[r]);
976 int reg = (r < 4) ? 8 : 9;
977 int ror = ((4 - (r&3))*8) & 0x1f;
978 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
980 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
981 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
982 else EOP_ADD_REG_LSL(1,7,1,1);
983 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
985 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
986 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
987 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
989 tr_bank_write((op&0x100) | ((op>>2)&3));
990 } else if (known_regb & (1 << (r+8))) {
991 tr_bank_write((op&0x100) | known_regs.r[r]);
993 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
996 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
997 hostreg_r[0] = hostreg_r[2] = -1;
1000 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1001 static int tr_cond_check(int op)
1003 int f = (op & 0x100) >> 8;
1005 case 0x00: return A_COND_AL; /* always true */
1006 case 0x50: /* Z matches f(?) bit */
1007 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1008 EOP_TST_IMM(6, 0, 4);
1009 return f ? A_COND_NE : A_COND_EQ;
1010 case 0x70: /* N matches f(?) bit */
1011 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1012 EOP_TST_IMM(6, 0, 8);
1013 return f ? A_COND_NE : A_COND_EQ;
1015 printf("unimplemented cond?\n");
1021 static int tr_neg_cond(int cond)
1024 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1025 case A_COND_EQ: return A_COND_NE;
1026 case A_COND_NE: return A_COND_EQ;
1027 case A_COND_MI: return A_COND_PL;
1028 case A_COND_PL: return A_COND_MI;
1029 default: printf("bad cond for neg\n"); exit(1);
1034 static int tr_aop_ssp2arm(int op)
1037 case 1: return A_OP_SUB;
1038 case 3: return A_OP_CMP;
1039 case 4: return A_OP_ADD;
1040 case 5: return A_OP_AND;
1041 case 6: return A_OP_ORR;
1042 case 7: return A_OP_EOR;
1049 // -----------------------------------------------------
1053 //@ r6: STACK and emu flags
1057 // read general reg to r0. Trashes r1
1058 static void tr_GR0_to_r0(int op)
1060 tr_mov16(0, 0xffff);
1063 static void tr_X_to_r0(int op)
1065 if (hostreg_r[0] != (SSP_X<<16)) {
1066 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1067 hostreg_r[0] = SSP_X<<16;
1071 static void tr_Y_to_r0(int op)
1073 if (hostreg_r[0] != (SSP_Y<<16)) {
1074 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1075 hostreg_r[0] = SSP_Y<<16;
1079 static void tr_A_to_r0(int op)
1081 if (hostreg_r[0] != (SSP_A<<16)) {
1082 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1083 hostreg_r[0] = SSP_A<<16;
1087 static void tr_ST_to_r0(int op)
1089 // VR doesn't need much accuracy here..
1090 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1091 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1095 static void tr_STACK_to_r0(int op)
1098 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1099 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1100 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1101 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1102 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1103 hostreg_r[0] = hostreg_r[1] = -1;
1106 static void tr_PC_to_r0(int op)
1108 tr_mov16(0, known_regs.gr[SSP_PC].h);
1111 static void tr_P_to_r0(int op)
1114 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1118 static void tr_AL_to_r0(int op)
1121 if (known_regb & KRREG_PMC) {
1122 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1124 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1125 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1126 EOP_STR_IMM(0,7,0x484);
1130 if (hostreg_r[0] != (SSP_AL<<16)) {
1131 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1132 hostreg_r[0] = SSP_AL<<16;
1136 static void tr_PMX_to_r0(int reg)
1138 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1140 known_regs.pmac_read[reg] = known_regs.pmc.v;
1141 known_regs.emu_status &= ~SSP_PMC_SET;
1142 known_regb |= 1 << (20+reg);
1143 dirty_regb |= 1 << (20+reg);
1147 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1149 u32 pmcv = known_regs.pmac_read[reg];
1150 int mode = pmcv>>16;
1151 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1153 if ((mode & 0xfff0) == 0x0800)
1155 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1156 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1157 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1158 known_regs.pmac_read[reg] += 1;
1160 else if ((mode & 0x47ff) == 0x0018) // DRAM
1162 int inc = get_inc(mode);
1163 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1164 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1165 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1166 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1168 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1169 tr_flush_dirty_ST();
1170 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1171 EOP_TST_REG_SIMPLE(0,0);
1172 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1173 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1174 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1176 known_regs.pmac_read[reg] += inc;
1182 known_regs.pmc.v = known_regs.pmac_read[reg];
1183 //known_regb |= KRREG_PMC;
1184 dirty_regb |= KRREG_PMC;
1185 dirty_regb |= 1 << (20+reg);
1186 hostreg_r[0] = hostreg_r[1] = -1;
1190 known_regb &= ~KRREG_PMC;
1191 dirty_regb &= ~KRREG_PMC;
1192 known_regb &= ~(1 << (20+reg));
1193 dirty_regb &= ~(1 << (20+reg));
1195 // call the C code to handle this
1196 tr_flush_dirty_ST();
1197 //tr_flush_dirty_pmcrs();
1199 emit_call(ssp_pm_read);
1203 static void tr_PM0_to_r0(int op)
1208 static void tr_PM1_to_r0(int op)
1213 static void tr_PM2_to_r0(int op)
1218 static void tr_XST_to_r0(int op)
1220 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1221 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1224 static void tr_PM4_to_r0(int op)
1229 static void tr_PMC_to_r0(int op)
1231 if (known_regb & KRREG_PMC)
1233 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1234 known_regs.emu_status |= SSP_PMC_SET;
1235 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1236 // do nothing - this is handled elsewhere
1238 tr_mov16(0, known_regs.pmc.l);
1239 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1244 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1245 tr_flush_dirty_ST();
1247 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1248 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1249 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1250 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1251 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1252 EOP_STR_IMM(1,7,0x484);
1253 hostreg_r[0] = hostreg_r[1] = -1;
1258 typedef void (tr_read_func)(int op);
1260 static tr_read_func *tr_read_funcs[16] =
1275 (tr_read_func *)tr_unhandled,
1281 // write r0 to general reg handlers. Trashes r1
1282 #define TR_WRITE_R0_TO_REG(reg) \
1284 hostreg_sspreg_changed(reg); \
1285 hostreg_r[0] = (reg)<<16; \
1286 if (const_val != -1) { \
1287 known_regs.gr[reg].h = const_val; \
1288 known_regb |= 1 << (reg); \
1290 known_regb &= ~(1 << (reg)); \
1294 static void tr_r0_to_GR0(int const_val)
1299 static void tr_r0_to_X(int const_val)
1301 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1302 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1303 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1304 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1305 TR_WRITE_R0_TO_REG(SSP_X);
1308 static void tr_r0_to_Y(int const_val)
1310 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1311 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1312 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
1313 dirty_regb |= KRREG_P;
1314 TR_WRITE_R0_TO_REG(SSP_Y);
1317 static void tr_r0_to_A(int const_val)
1319 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1320 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1321 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1322 TR_WRITE_R0_TO_REG(SSP_A);
1325 static void tr_r0_to_ST(int const_val)
1327 // VR doesn't need much accuracy here..
1328 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1329 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1330 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1331 TR_WRITE_R0_TO_REG(SSP_ST);
1333 dirty_regb &= ~KRREG_ST;
1336 static void tr_r0_to_STACK(int const_val)
1339 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1340 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1341 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1342 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1343 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1347 static void tr_r0_to_PC(int const_val)
1349 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1350 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1354 static void tr_r0_to_AL(int const_val)
1356 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1357 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1358 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1359 hostreg_sspreg_changed(SSP_AL);
1360 if (const_val != -1) {
1361 known_regs.gr[SSP_A].l = const_val;
1362 known_regb |= 1 << SSP_AL;
1364 known_regb &= ~(1 << SSP_AL);
1367 static void tr_r0_to_PMX(int reg)
1369 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1371 known_regs.pmac_write[reg] = known_regs.pmc.v;
1372 known_regs.emu_status &= ~SSP_PMC_SET;
1373 known_regb |= 1 << (25+reg);
1374 dirty_regb |= 1 << (25+reg);
1378 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1382 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1384 mode = known_regs.pmac_write[reg]>>16;
1385 addr = known_regs.pmac_write[reg]&0xffff;
1386 if ((mode & 0x43ff) == 0x0018) // DRAM
1388 int inc = get_inc(mode);
1389 if (mode & 0x0400) tr_unhandled();
1390 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1391 emit_mov_const(A_COND_AL, 2, addr<<1);
1392 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1393 known_regs.pmac_write[reg] += inc;
1395 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1397 if (mode & 0x0400) tr_unhandled();
1398 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1399 emit_mov_const(A_COND_AL, 2, addr<<1);
1400 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1401 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1403 else if ((mode & 0x47ff) == 0x001c) // IRAM
1405 int inc = get_inc(mode);
1406 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1407 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1408 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1410 EOP_STR_IMM(1,7,0x494); // iram_dirty
1411 known_regs.pmac_write[reg] += inc;
1416 known_regs.pmc.v = known_regs.pmac_write[reg];
1417 //known_regb |= KRREG_PMC;
1418 dirty_regb |= KRREG_PMC;
1419 dirty_regb |= 1 << (25+reg);
1420 hostreg_r[1] = hostreg_r[2] = -1;
1424 known_regb &= ~KRREG_PMC;
1425 dirty_regb &= ~KRREG_PMC;
1426 known_regb &= ~(1 << (25+reg));
1427 dirty_regb &= ~(1 << (25+reg));
1429 // call the C code to handle this
1430 tr_flush_dirty_ST();
1431 //tr_flush_dirty_pmcrs();
1433 emit_call(ssp_pm_write);
1437 static void tr_r0_to_PM0(int const_val)
1442 static void tr_r0_to_PM1(int const_val)
1447 static void tr_r0_to_PM2(int const_val)
1452 static void tr_r0_to_PM4(int const_val)
1457 static void tr_r0_to_PMC(int const_val)
1459 if ((known_regb & KRREG_PMC) && const_val != -1)
1461 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1462 known_regs.emu_status |= SSP_PMC_SET;
1463 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1464 known_regs.pmc.h = const_val;
1466 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1467 known_regs.pmc.l = const_val;
1472 tr_flush_dirty_ST();
1473 if (known_regb & KRREG_PMC) {
1474 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1475 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1476 known_regb &= ~KRREG_PMC;
1477 dirty_regb &= ~KRREG_PMC;
1479 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1480 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1481 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1482 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1483 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1484 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1485 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1486 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1487 EOP_STR_IMM(1,7,0x484);
1488 hostreg_r[1] = hostreg_r[2] = -1;
1492 typedef void (tr_write_func)(int const_val);
1494 static tr_write_func *tr_write_funcs[16] =
1503 (tr_write_func *)tr_unhandled,
1507 (tr_write_func *)tr_unhandled,
1509 (tr_write_func *)tr_unhandled,
1514 static void tr_mac_load_XY(int op)
1516 tr_rX_read(op&3, (op>>2)&3); // X
1517 EOP_MOV_REG_LSL(4, 0, 16);
1518 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1519 EOP_ORR_REG_SIMPLE(4, 0);
1520 dirty_regb |= KRREG_P;
1521 hostreg_sspreg_changed(SSP_X);
1522 hostreg_sspreg_changed(SSP_Y);
1523 known_regb &= ~KRREG_X;
1524 known_regb &= ~KRREG_Y;
1527 // -----------------------------------------------------
1529 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1532 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1538 pmcv = imm | (PROGRAM((*pc)++) << 16);
1539 known_regs.pmc.v = pmcv;
1540 known_regb |= KRREG_PMC;
1541 dirty_regb |= KRREG_PMC;
1542 known_regs.emu_status |= SSP_PMC_SET;
1544 // check for possible reg programming
1545 tmpv = PROGRAM(*pc);
1546 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1548 int is_write = (tmpv & 0xff8f) == 0x80;
1549 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1550 if (reg > 4) tr_unhandled();
1551 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1552 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1553 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1554 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1555 known_regs.emu_status &= ~SSP_PMC_SET;
1564 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1566 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1573 if (op != 0x0840 || imm != 0) return 0;
1574 pp = PROGRAM_P(*pc);
1575 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1577 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1578 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1579 hostreg_sspreg_changed(SSP_ST);
1580 known_regs.gr[SSP_ST].h = 0x60;
1581 known_regb |= 1 << SSP_ST;
1582 dirty_regb &= ~KRREG_ST;
1587 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1593 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1596 EOP_MOV_REG_LSL(0, 0, 4);
1597 EOP_ORR_REG_LSR(0, 0, 0, 16);
1603 // -----------------------------------------------------
1605 static int translate_op(unsigned int op, int *pc, int imm)
1607 u32 tmpv, tmpv2, tmpv3;
1609 known_regs.gr[SSP_PC].h = *pc;
1615 if (op == 0) { ret++; break; } // nop
1616 tmpv = op & 0xf; // src
1617 tmpv2 = (op >> 4) & 0xf; // dst
1618 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1620 EOP_MOV_REG_SIMPLE(5, 10);
1621 hostreg_sspreg_changed(SSP_A);
1622 known_regb &= ~(KRREG_A|KRREG_AL);
1625 tr_read_funcs[tmpv](op);
1626 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1627 if (tmpv2 == SSP_PC) ret |= 0x10000;
1632 int r = (op&3) | ((op>>6)&4);
1633 int mod = (op>>2)&3;
1634 tmpv = (op >> 4) & 0xf; // dst
1635 ret = tr_detect_rotate(op, pc, imm);
1639 else tr_ptrr_mod(r, mod, 1, 1);
1640 tr_write_funcs[tmpv](-1);
1641 if (tmpv == SSP_PC) ret |= 0x10000;
1647 tmpv = (op >> 4) & 0xf; // src
1648 tr_read_funcs[tmpv](op);
1654 tr_bank_read(op&0x1ff);
1660 tmpv = (op & 0xf0) >> 4; // dst
1661 ret = tr_detect_pm0_block(op, pc, imm);
1663 ret = tr_detect_set_pm(op, pc, imm);
1666 tr_write_funcs[tmpv](imm);
1667 if (tmpv == SSP_PC) ret |= 0x10000;
1672 tmpv2 = (op >> 4) & 0xf; // dst
1674 tr_write_funcs[tmpv2](-1);
1675 if (tmpv2 == SSP_PC) ret |= 0x10000;
1687 tr_bank_write(op&0x1ff);
1693 r = (op&3) | ((op>>6)&4); // src
1694 tmpv2 = (op >> 4) & 0xf; // dst
1695 if ((r&3) == 3) tr_unhandled();
1697 if (known_regb & (1 << (r+8))) {
1698 tr_mov16(0, known_regs.r[r]);
1699 tr_write_funcs[tmpv2](known_regs.r[r]);
1701 int reg = (r < 4) ? 8 : 9;
1702 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1703 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1705 tr_write_funcs[tmpv2](-1);
1713 r = (op&3) | ((op>>6)&4); // dst
1714 tmpv = (op >> 4) & 0xf; // src
1715 if ((r&3) == 3) tr_unhandled();
1717 if (known_regb & (1 << tmpv)) {
1718 known_regs.r[r] = known_regs.gr[tmpv].h;
1719 known_regb |= 1 << (r + 8);
1720 dirty_regb |= 1 << (r + 8);
1722 int reg = (r < 4) ? 8 : 9;
1723 int ror = ((4 - (r&3))*8) & 0x1f;
1724 tr_read_funcs[tmpv](op);
1725 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1726 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1727 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1729 known_regb &= ~(1 << (r+8));
1730 dirty_regb &= ~(1 << (r+8));
1738 known_regs.r[tmpv] = op;
1739 known_regb |= 1 << (tmpv + 8);
1740 dirty_regb |= 1 << (tmpv + 8);
1745 u32 *jump_op = NULL;
1746 tmpv = tr_cond_check(op);
1747 if (tmpv != A_COND_AL) {
1748 jump_op = tcache_ptr;
1749 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1752 tr_r0_to_STACK(*pc);
1753 if (tmpv != A_COND_AL) {
1754 u32 *real_ptr = tcache_ptr;
1755 tcache_ptr = jump_op;
1756 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1757 tcache_ptr = real_ptr;
1759 tr_mov16_cond(tmpv, 0, imm);
1760 if (tmpv != A_COND_AL) {
1761 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1763 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1770 tmpv2 = (op >> 4) & 0xf; // dst
1772 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1773 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1774 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1775 hostreg_r[0] = hostreg_r[1] = -1;
1776 tr_write_funcs[tmpv2](-1);
1777 if (tmpv2 == SSP_PC) ret |= 0x10000;
1782 tmpv = tr_cond_check(op);
1783 tr_mov16_cond(tmpv, 0, imm);
1784 if (tmpv != A_COND_AL) {
1785 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1787 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1793 // check for repeats of this op
1795 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1798 if ((op&0xf0) != 0) // !always
1801 tmpv2 = tr_cond_check(op);
1803 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1804 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1805 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1806 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
1807 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1808 hostreg_r[1] = -1; break; // abs
1809 default: tr_unhandled();
1812 hostreg_sspreg_changed(SSP_A);
1813 dirty_regb |= KRREG_ST;
1814 known_regb &= ~KRREG_ST;
1815 known_regb &= ~(KRREG_A|KRREG_AL);
1824 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1825 hostreg_sspreg_changed(SSP_A);
1826 known_regb &= ~(KRREG_A|KRREG_AL);
1827 dirty_regb |= KRREG_ST;
1830 // mpya (rj), (ri), b
1835 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1836 hostreg_sspreg_changed(SSP_A);
1837 known_regb &= ~(KRREG_A|KRREG_AL);
1838 dirty_regb |= KRREG_ST;
1841 // mld (rj), (ri), b
1843 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1844 hostreg_sspreg_changed(SSP_A);
1845 known_regs.gr[SSP_A].v = 0;
1846 known_regb |= (KRREG_A|KRREG_AL);
1847 dirty_regb |= KRREG_ST;
1858 tmpv = op & 0xf; // src
1859 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1860 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1861 if (tmpv == SSP_P) {
1863 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1864 } else if (tmpv == SSP_A) {
1865 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1867 tr_read_funcs[tmpv](op);
1868 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1870 hostreg_sspreg_changed(SSP_A);
1871 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1872 dirty_regb |= KRREG_ST;
1882 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1883 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1884 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1885 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1886 hostreg_sspreg_changed(SSP_A);
1887 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1888 dirty_regb |= KRREG_ST;
1898 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1899 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1900 tr_bank_read(op&0x1ff);
1901 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1902 hostreg_sspreg_changed(SSP_A);
1903 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1904 dirty_regb |= KRREG_ST;
1914 tmpv = (op & 0xf0) >> 4;
1915 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1916 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1918 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1919 hostreg_sspreg_changed(SSP_A);
1920 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1921 dirty_regb |= KRREG_ST;
1931 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1932 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1934 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1935 hostreg_sspreg_changed(SSP_A);
1936 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1937 dirty_regb |= KRREG_ST;
1948 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1949 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1950 r = (op&3) | ((op>>6)&4); // src
1951 if ((r&3) == 3) tr_unhandled();
1953 if (known_regb & (1 << (r+8))) {
1954 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1956 int reg = (r < 4) ? 8 : 9;
1957 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1958 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1959 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_sspreg_changed(SSP_A);
1963 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1964 dirty_regb |= KRREG_ST;
1975 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1976 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1977 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1978 hostreg_sspreg_changed(SSP_A);
1979 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1980 dirty_regb |= KRREG_ST;
1987 static void *translate_block(int pc)
1989 unsigned int op, op1, imm, ccount = 0;
1990 unsigned int *block_start;
1991 int ret, ret_prev = -1, tpc;
1993 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1994 block_start = tcache_ptr;
1996 dirty_regb = KRREG_P;
1997 known_regs.emu_status = 0;
2000 emit_block_prologue();
2002 for (; ccount < 100;)
2008 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2009 imm = PROGRAM(pc++); // immediate
2012 ret = translate_op(op, &pc, imm);
2015 tr_flush_dirty_prs();
2016 tr_flush_dirty_ST();
2017 tr_flush_dirty_pmcrs();
2018 known_regs.emu_status = 0;
2020 emit_mov_const(A_COND_AL, 0, op);
2024 emit_mov_const(A_COND_AL, 1, imm);
2029 if (ret_prev > 0) emit_call(regfile_store);
2030 emit_call(in_funcs[op1]);
2031 emit_call(regfile_load);
2033 if (in_funcs[op1] == NULL) {
2034 printf("NULL func! op=%08x (%02x)\n", op, op1);
2039 dirty_regb |= KRREG_P;
2044 ccount += ret & 0xffff;
2045 if (ret & 0x10000) break;
2054 tr_flush_dirty_prs();
2055 tr_flush_dirty_ST();
2056 tr_flush_dirty_pmcrs();
2057 emit_block_epilogue(ccount + 1);
2058 *tcache_ptr++ = 0xffffffff; // end of block
2060 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2061 printf("tcache overflow!\n");
2068 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2072 FILE *f = fopen("tcache.bin", "wb");
2073 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2086 // -----------------------------------------------------
2088 int ssp1601_dyn_startup(void)
2090 memset(tcache, 0, TCACHE_SIZE);
2091 memset(block_table, 0, sizeof(block_table));
2092 memset(block_table_iram, 0, sizeof(block_table_iram));
2093 tcache_ptr = tcache;
2094 *tcache_ptr++ = 0xffffffff;
2098 block_table[0x400] = (void *) ssp_hle_800;
2103 static unsigned short dummy = 0;
2110 void ssp1601_dyn_reset(ssp1601_t *ssp)
2112 ssp1601_reset_local(ssp);
2113 ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2114 ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2115 ssp->drc.ptr_dram = (unsigned int) svp->dram;
2116 ssp->drc.iram_dirty = 0;
2119 void ssp1601_dyn_run(int cycles)
2121 if (ssp->emu_status & SSP_WAIT_MASK) return;
2124 rPC = DUMP_BLOCK >> 1;
2128 int (*trans_entry)(void);
2131 if (ssp->drc.iram_dirty) {
2132 iram_context = get_iram_context();
2133 ssp->drc.iram_dirty--;
2135 if (block_table_iram[iram_context][rPC] == NULL)
2136 block_table_iram[iram_context][rPC] = translate_block(rPC);
2137 trans_entry = (void *) block_table_iram[iram_context][rPC];
2141 if (block_table[rPC] == NULL)
2142 block_table[rPC] = translate_block(rPC);
2143 trans_entry = (void *) block_table[rPC];
2146 cycles -= trans_entry();