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 block_ref[0x5090/2];
8 static unsigned int block_ref_iram[15][0x800/2];
9 static unsigned int *tcache_ptr = NULL;
11 static int nblocks = 0;
12 static int iram_context = 0;
15 #define DUMP_BLOCK 0x0c9a
16 unsigned int tcache[512*1024];
17 void regfile_load(void){}
18 void regfile_store(void){}
21 #define EMBED_INTERPRETER
22 #define ssp1601_reset ssp1601_reset_local
23 #define ssp1601_run ssp1601_run_local
26 #define GET_PPC_OFFS() (GET_PC()*2 - 2)
27 #define SET_PC(d) { rPC = d; } /* must return to dispatcher after this */
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
35 // -----------------------------------------------------
38 static void op00(unsigned int op, unsigned int imm)
41 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
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.
50 tmpv = REG_READ(op & 0x0f);
51 REG_WRITE((op & 0xf0) >> 4, tmpv);
56 static void op01(unsigned int op, unsigned int imm)
59 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
63 static void op02(unsigned int op, unsigned int imm)
66 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
70 static void op04(unsigned int op, unsigned int imm)
72 REG_WRITE((op & 0xf0) >> 4, imm);
76 static void op05(unsigned int op, unsigned int imm)
79 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
83 static void op06(unsigned int op, unsigned int imm)
89 static void op07(unsigned int op, unsigned int imm)
91 ssp->RAM[op & 0x1ff] = rA;
95 static void op09(unsigned int op, unsigned int imm)
98 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
102 static void op0a(unsigned int op, unsigned int imm)
104 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
107 // ldi ri, simm (also op0d op0e op0f)
108 static void op0c(unsigned int op, unsigned int imm)
114 static void op24(unsigned int op, unsigned int imm)
119 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
125 static void op25(unsigned int op, unsigned int imm)
128 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
132 static void op26(unsigned int op, unsigned int imm)
138 if (cond) SET_PC(imm);
144 static void op48(unsigned int op, unsigned int imm)
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());
166 static void op1b(unsigned int op, unsigned int imm)
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
175 // mpya (rj), (ri), b
176 static void op4b(unsigned int op, unsigned int imm)
178 read_P(); // update P
179 rA32 += rP.v; // confirmed to be 32bit
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
186 static void op5b(unsigned int op, unsigned int imm)
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
195 static void op10(unsigned int op, unsigned int imm)
200 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
205 static void op30(unsigned int op, unsigned int imm)
210 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
215 static void op40(unsigned int op, unsigned int imm)
220 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
225 static void op50(unsigned int op, unsigned int imm)
230 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
235 static void op60(unsigned int op, unsigned int imm)
240 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
245 static void op70(unsigned int op, unsigned int imm)
250 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
256 static void op11(unsigned int op, unsigned int imm)
259 tmpv = ptr1_read(op); OP_SUBA(tmpv);
262 static void op31(unsigned int op, unsigned int imm)
265 tmpv = ptr1_read(op); OP_CMPA(tmpv);
268 static void op41(unsigned int op, unsigned int imm)
271 tmpv = ptr1_read(op); OP_ADDA(tmpv);
274 static void op51(unsigned int op, unsigned int imm)
277 tmpv = ptr1_read(op); OP_ANDA(tmpv);
280 static void op61(unsigned int op, unsigned int imm)
283 tmpv = ptr1_read(op); OP_ORA (tmpv);
286 static void op71(unsigned int op, unsigned int imm)
289 tmpv = ptr1_read(op); OP_EORA(tmpv);
293 static void op03(unsigned int op, unsigned int imm)
296 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
299 static void op13(unsigned int op, unsigned int imm)
302 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
305 static void op33(unsigned int op, unsigned int imm)
308 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
311 static void op43(unsigned int op, unsigned int imm)
314 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
317 static void op53(unsigned int op, unsigned int imm)
320 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
323 static void op63(unsigned int op, unsigned int imm)
326 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
329 static void op73(unsigned int op, unsigned int imm)
332 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
336 static void op14(unsigned int op, unsigned int imm)
341 static void op34(unsigned int op, unsigned int imm)
346 static void op44(unsigned int op, unsigned int imm)
351 static void op54(unsigned int op, unsigned int imm)
356 static void op64(unsigned int op, unsigned int imm)
361 static void op74(unsigned int op, unsigned int imm)
367 static void op15(unsigned int op, unsigned int imm)
370 tmpv = ptr2_read(op); OP_SUBA(tmpv);
373 static void op35(unsigned int op, unsigned int imm)
376 tmpv = ptr2_read(op); OP_CMPA(tmpv);
379 static void op45(unsigned int op, unsigned int imm)
382 tmpv = ptr2_read(op); OP_ADDA(tmpv);
385 static void op55(unsigned int op, unsigned int imm)
388 tmpv = ptr2_read(op); OP_ANDA(tmpv);
391 static void op65(unsigned int op, unsigned int imm)
394 tmpv = ptr2_read(op); OP_ORA (tmpv);
397 static void op75(unsigned int op, unsigned int imm)
400 tmpv = ptr2_read(op); OP_EORA(tmpv);
404 static void op19(unsigned int op, unsigned int imm)
407 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
410 static void op39(unsigned int op, unsigned int imm)
413 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
416 static void op49(unsigned int op, unsigned int imm)
419 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
422 static void op59(unsigned int op, unsigned int imm)
425 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
428 static void op69(unsigned int op, unsigned int imm)
431 tmpv = rIJ[IJind]; OP_ORA (tmpv);
434 static void op79(unsigned int op, unsigned int imm)
437 tmpv = rIJ[IJind]; OP_EORA(tmpv);
441 static void op1c(unsigned int op, unsigned int imm)
446 static void op3c(unsigned int op, unsigned int imm)
451 static void op4c(unsigned int op, unsigned int imm)
456 static void op5c(unsigned int op, unsigned int imm)
461 static void op6c(unsigned int op, unsigned int imm)
466 static void op7c(unsigned int op, unsigned int imm)
471 typedef void (in_func)(unsigned int op, unsigned int imm);
473 static in_func *in_funcs[0x80] =
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,
494 static u32 ssp_pm_read(int reg)
498 if (ssp->emu_status & SSP_PMC_SET)
500 ssp->pmac_read[reg] = rPMC.v;
501 ssp->emu_status &= ~SSP_PMC_SET;
506 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
508 mode = ssp->pmac_read[reg]>>16;
509 if ((mode & 0xfff0) == 0x0800) // ROM
511 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
512 ssp->pmac_read[reg] += 1;
514 else if ((mode & 0x47ff) == 0x0018) // DRAM
516 unsigned short *dram = (unsigned short *)svp->dram;
517 int inc = get_inc(mode);
518 d = dram[ssp->pmac_read[reg]&0xffff];
519 ssp->pmac_read[reg] += inc;
522 // PMC value corresponds to last PMR accessed
523 rPMC.v = ssp->pmac_read[reg];
528 static void ssp_pm_write(u32 d, int reg)
530 unsigned short *dram;
533 if (ssp->emu_status & SSP_PMC_SET)
535 ssp->pmac_write[reg] = rPMC.v;
536 ssp->emu_status &= ~SSP_PMC_SET;
541 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
543 dram = (unsigned short *)svp->dram;
544 mode = ssp->pmac_write[reg]>>16;
545 addr = ssp->pmac_write[reg]&0xffff;
546 if ((mode & 0x43ff) == 0x0018) // DRAM
548 int inc = get_inc(mode);
550 overwrite_write(dram[addr], d);
551 } else dram[addr] = d;
552 ssp->pmac_write[reg] += inc;
554 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
557 overwrite_write(dram[addr], d);
558 } else dram[addr] = d;
559 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
561 else if ((mode & 0x47ff) == 0x001c) // IRAM
563 int inc = get_inc(mode);
564 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
565 ssp->pmac_write[reg] += inc;
566 ssp->drc.iram_dirty = 1;
569 rPMC.v = ssp->pmac_write[reg];
573 // -----------------------------------------------------
576 static unsigned char iram_context_map[] =
578 0, 0, 0, 0, 1, 0, 0, 0, // 04
579 0, 0, 0, 0, 0, 0, 2, 0, // 0e
580 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
581 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
582 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
583 0, 0, 0, 0, 0, 0, 0, 0,
584 0, 0,11, 0, 0,12, 0, 0, // 32 35
585 13,14, 0, 0, 0, 0, 0, 0 // 38 39
588 static int get_iram_context(void)
590 unsigned char *ir = (unsigned char *)svp->iram_rom;
591 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
592 val1 = iram_context_map[(val>>1)&0x3f];
595 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
596 //debug_dump2file(name, svp->iram_rom, 0x800);
599 // elprintf(EL_ANOMALY, "iram_context: %02i", val1);
603 // -----------------------------------------------------
605 /* regs with known values */
610 unsigned int pmac_read[5];
611 unsigned int pmac_write[5];
613 unsigned int emu_status;
616 #define KRREG_X (1 << SSP_X)
617 #define KRREG_Y (1 << SSP_Y)
618 #define KRREG_A (1 << SSP_A) /* AH only */
619 #define KRREG_ST (1 << SSP_ST)
620 #define KRREG_STACK (1 << SSP_STACK)
621 #define KRREG_PC (1 << SSP_PC)
622 #define KRREG_P (1 << SSP_P)
623 #define KRREG_PR0 (1 << 8)
624 #define KRREG_PR4 (1 << 12)
625 #define KRREG_AL (1 << 16)
626 #define KRREG_PMCM (1 << 18) /* only mode word of PMC */
627 #define KRREG_PMC (1 << 19)
628 #define KRREG_PM0R (1 << 20)
629 #define KRREG_PM1R (1 << 21)
630 #define KRREG_PM2R (1 << 22)
631 #define KRREG_PM3R (1 << 23)
632 #define KRREG_PM4R (1 << 24)
633 #define KRREG_PM0W (1 << 25)
634 #define KRREG_PM1W (1 << 26)
635 #define KRREG_PM2W (1 << 27)
636 #define KRREG_PM3W (1 << 28)
637 #define KRREG_PM4W (1 << 29)
639 /* bitfield of known register values */
640 static u32 known_regb = 0;
642 /* known vals, which need to be flushed
643 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
644 * ST means flags are being held in ARM PSR
645 * P means that it needs to be recalculated
647 static u32 dirty_regb = 0;
649 /* known values of host regs.
651 * 000000-00ffff - 16bit value
652 * 100000-10ffff - base reg (r7) + 16bit val
653 * 0r0000 - means reg (low) eq gr[r].h, r != AL
655 static int hostreg_r[4];
657 static void hostreg_clear(void)
660 for (i = 0; i < 4; i++)
664 static void hostreg_sspreg_changed(int sspreg)
667 for (i = 0; i < 4; i++)
668 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
672 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
673 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
675 static void tr_unhandled(void)
677 FILE *f = fopen("tcache.bin", "wb");
678 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
680 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
684 /* update P, if needed. Trashes r0 */
685 static void tr_flush_dirty_P(void)
688 if (!(dirty_regb & KRREG_P)) return;
689 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
690 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
691 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
692 EOP_MUL(10, 0, 10); // mul r10, r0, r10
693 dirty_regb &= ~KRREG_P;
697 /* write dirty pr to host reg. Nothing is trashed */
698 static void tr_flush_dirty_pr(int r)
702 if (!(dirty_regb & (1 << (r+8)))) return;
705 case 0: ror = 0; break;
706 case 1: ror = 24/2; break;
707 case 2: ror = 16/2; break;
709 reg = (r < 4) ? 8 : 9;
710 EOP_BIC_IMM(reg,reg,ror,0xff);
711 if (known_regs.r[r] != 0)
712 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
713 dirty_regb &= ~(1 << (r+8));
716 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
717 static void tr_flush_dirty_prs(void)
720 int dirty = dirty_regb >> 8;
722 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
724 if (!(dirty&1)) continue;
726 case 0: ror = 0; break;
727 case 1: ror = 24/2; break;
728 case 2: ror = 16/2; break;
730 reg = (i < 4) ? 8 : 9;
731 EOP_BIC_IMM(reg,reg,ror,0xff);
732 if (known_regs.r[i] != 0)
733 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
735 dirty_regb &= ~0xff00;
738 /* write dirty pr and "forget" it. Nothing is trashed. */
739 static void tr_release_pr(int r)
741 tr_flush_dirty_pr(r);
742 known_regb &= ~(1 << (r+8));
745 /* fush ARM PSR to r6. Trashes r1 */
746 static void tr_flush_dirty_ST(void)
748 if (!(dirty_regb & KRREG_ST)) return;
749 EOP_BIC_IMM(6,6,0,0x0f);
751 EOP_ORR_REG_LSR(6,6,1,28);
752 dirty_regb &= ~KRREG_ST;
756 /* inverse of above. Trashes r1 */
757 static void tr_make_dirty_ST(void)
759 if (dirty_regb & KRREG_ST) return;
760 if (known_regb & KRREG_ST) {
762 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
763 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
764 EOP_MSR_IMM(4/2, flags);
766 EOP_MOV_REG_LSL(1, 6, 28);
770 dirty_regb |= KRREG_ST;
773 /* load 16bit val into host reg r0-r3. Nothing is trashed */
774 static void tr_mov16(int r, int val)
776 if (hostreg_r[r] != val) {
777 emit_mov_const(A_COND_AL, r, val);
782 static void tr_mov16_cond(int cond, int r, int val)
784 emit_mov_const(cond, r, val);
789 static void tr_flush_dirty_pmcrs(void)
791 u32 i, val = (u32)-1;
792 if (!(dirty_regb & 0x3ff80000)) return;
794 if (dirty_regb & KRREG_PMC) {
795 val = known_regs.pmc.v;
796 emit_mov_const(A_COND_AL, 1, val);
797 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
799 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
800 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
804 for (i = 0; i < 5; i++)
806 if (dirty_regb & (1 << (20+i))) {
807 if (val != known_regs.pmac_read[i]) {
808 val = known_regs.pmac_read[i];
809 emit_mov_const(A_COND_AL, 1, val);
811 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
813 if (dirty_regb & (1 << (25+i))) {
814 if (val != known_regs.pmac_write[i]) {
815 val = known_regs.pmac_write[i];
816 emit_mov_const(A_COND_AL, 1, val);
818 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
821 dirty_regb &= ~0x3ff80000;
825 /* read bank word to r0 (upper bits zero). Thrashes r1. */
826 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
830 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
831 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
832 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
836 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
840 /* write r0 to bank. Trashes r1. */
841 static void tr_bank_write(int addr)
845 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
846 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
847 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
851 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
854 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
855 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
857 int modulo_shift = -1; /* unknown */
859 if (mod == 0) return;
861 if (!need_modulo || mod == 1) // +!
863 else if (need_modulo && (known_regb & KRREG_ST)) {
864 modulo_shift = known_regs.gr[SSP_ST].h & 7;
865 if (modulo_shift == 0) modulo_shift = 8;
868 if (modulo_shift == -1)
870 int reg = (r < 4) ? 8 : 9;
872 if (dirty_regb & KRREG_ST) {
873 // avoid flushing ARM flags
874 EOP_AND_IMM(1, 6, 0, 0x70);
875 EOP_SUB_IMM(1, 1, 0, 0x10);
876 EOP_AND_IMM(1, 1, 0, 0x70);
877 EOP_ADD_IMM(1, 1, 0, 0x10);
879 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
880 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
882 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
883 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
884 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
886 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
887 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
889 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
890 else EOP_ADD_REG2_LSL(reg,reg,3,2);
891 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
892 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
893 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
895 else if (known_regb & (1 << (r + 8)))
897 int modulo = (1 << modulo_shift) - 1;
899 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
900 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
904 int reg = (r < 4) ? 8 : 9;
905 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
906 EOP_MOV_REG_ROR(reg,reg,ror);
907 // {add|sub} reg, reg, #1<<shift
908 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
909 EOP_MOV_REG_ROR(reg,reg,32-ror);
913 /* handle writes r0 to (rX). Trashes r1.
914 * fortunately we can ignore modulo increment modes for writes. */
915 static void tr_rX_write(int op)
919 int mod = (op>>2) & 3; // direct addressing
920 tr_bank_write((op & 0x100) + mod);
924 int r = (op&3) | ((op>>6)&4);
925 if (known_regb & (1 << (r + 8))) {
926 tr_bank_write((op&0x100) | known_regs.r[r]);
928 int reg = (r < 4) ? 8 : 9;
929 int ror = ((4 - (r&3))*8) & 0x1f;
930 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
932 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
933 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
934 else EOP_ADD_REG_LSL(1,7,1,1);
935 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
938 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
942 /* read (rX) to r0. Trashes r1-r3. */
943 static void tr_rX_read(int r, int mod)
947 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
951 if (known_regb & (1 << (r + 8))) {
952 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
954 int reg = (r < 4) ? 8 : 9;
955 int ror = ((4 - (r&3))*8) & 0x1f;
956 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
958 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
959 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
960 else EOP_ADD_REG_LSL(1,7,1,1);
961 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
962 hostreg_r[0] = hostreg_r[1] = -1;
964 tr_ptrr_mod(r, mod, 1, 1);
968 /* read ((rX)) to r0. Trashes r1,r2. */
969 static void tr_rX_read2(int op)
971 int r = (op&3) | ((op>>6)&4); // src
974 tr_bank_read((op&0x100) | ((op>>2)&3));
975 } else if (known_regb & (1 << (r+8))) {
976 tr_bank_read((op&0x100) | known_regs.r[r]);
978 int reg = (r < 4) ? 8 : 9;
979 int ror = ((4 - (r&3))*8) & 0x1f;
980 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
982 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
983 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
984 else EOP_ADD_REG_LSL(1,7,1,1);
985 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
987 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
988 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
989 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
991 tr_bank_write((op&0x100) | ((op>>2)&3));
992 } else if (known_regb & (1 << (r+8))) {
993 tr_bank_write((op&0x100) | known_regs.r[r]);
995 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
998 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
999 hostreg_r[0] = hostreg_r[2] = -1;
1002 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1003 static int tr_cond_check(int op)
1005 int f = (op & 0x100) >> 8;
1007 case 0x00: return A_COND_AL; /* always true */
1008 case 0x50: /* Z matches f(?) bit */
1009 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1010 EOP_TST_IMM(6, 0, 4);
1011 return f ? A_COND_NE : A_COND_EQ;
1012 case 0x70: /* N matches f(?) bit */
1013 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1014 EOP_TST_IMM(6, 0, 8);
1015 return f ? A_COND_NE : A_COND_EQ;
1017 printf("unimplemented cond?\n");
1023 static int tr_neg_cond(int cond)
1026 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1027 case A_COND_EQ: return A_COND_NE;
1028 case A_COND_NE: return A_COND_EQ;
1029 case A_COND_MI: return A_COND_PL;
1030 case A_COND_PL: return A_COND_MI;
1031 default: printf("bad cond for neg\n"); exit(1);
1036 static int tr_aop_ssp2arm(int op)
1039 case 1: return A_OP_SUB;
1040 case 3: return A_OP_CMP;
1041 case 4: return A_OP_ADD;
1042 case 5: return A_OP_AND;
1043 case 6: return A_OP_ORR;
1044 case 7: return A_OP_EOR;
1051 // -----------------------------------------------------
1055 //@ r6: STACK and emu flags
1059 // read general reg to r0. Trashes r1
1060 static void tr_GR0_to_r0(int op)
1062 tr_mov16(0, 0xffff);
1065 static void tr_X_to_r0(int op)
1067 if (hostreg_r[0] != (SSP_X<<16)) {
1068 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1069 hostreg_r[0] = SSP_X<<16;
1073 static void tr_Y_to_r0(int op)
1075 if (hostreg_r[0] != (SSP_Y<<16)) {
1076 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1077 hostreg_r[0] = SSP_Y<<16;
1081 static void tr_A_to_r0(int op)
1083 if (hostreg_r[0] != (SSP_A<<16)) {
1084 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1085 hostreg_r[0] = SSP_A<<16;
1089 static void tr_ST_to_r0(int op)
1091 // VR doesn't need much accuracy here..
1092 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1093 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1097 static void tr_STACK_to_r0(int op)
1100 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1101 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1102 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1103 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1104 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1105 hostreg_r[0] = hostreg_r[1] = -1;
1108 static void tr_PC_to_r0(int op)
1110 tr_mov16(0, known_regs.gr[SSP_PC].h);
1113 static void tr_P_to_r0(int op)
1116 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1120 static void tr_AL_to_r0(int op)
1123 if (known_regb & KRREG_PMC) {
1124 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1126 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1127 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1128 EOP_STR_IMM(0,7,0x484);
1132 if (hostreg_r[0] != (SSP_AL<<16)) {
1133 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1134 hostreg_r[0] = SSP_AL<<16;
1138 static void tr_PMX_to_r0(int reg)
1140 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1142 known_regs.pmac_read[reg] = known_regs.pmc.v;
1143 known_regs.emu_status &= ~SSP_PMC_SET;
1144 known_regb |= 1 << (20+reg);
1145 dirty_regb |= 1 << (20+reg);
1149 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1151 u32 pmcv = known_regs.pmac_read[reg];
1152 int mode = pmcv>>16;
1153 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1155 if ((mode & 0xfff0) == 0x0800)
1157 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1158 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1159 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1160 known_regs.pmac_read[reg] += 1;
1162 else if ((mode & 0x47ff) == 0x0018) // DRAM
1164 int inc = get_inc(mode);
1165 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1166 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1167 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1168 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1170 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1171 tr_flush_dirty_ST();
1172 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1173 EOP_TST_REG_SIMPLE(0,0);
1174 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1175 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1176 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1178 known_regs.pmac_read[reg] += inc;
1184 known_regs.pmc.v = known_regs.pmac_read[reg];
1185 //known_regb |= KRREG_PMC;
1186 dirty_regb |= KRREG_PMC;
1187 dirty_regb |= 1 << (20+reg);
1188 hostreg_r[0] = hostreg_r[1] = -1;
1192 known_regb &= ~KRREG_PMC;
1193 dirty_regb &= ~KRREG_PMC;
1194 known_regb &= ~(1 << (20+reg));
1195 dirty_regb &= ~(1 << (20+reg));
1197 // call the C code to handle this
1198 tr_flush_dirty_ST();
1199 //tr_flush_dirty_pmcrs();
1201 emit_call(ssp_pm_read);
1205 static void tr_PM0_to_r0(int op)
1210 static void tr_PM1_to_r0(int op)
1215 static void tr_PM2_to_r0(int op)
1220 static void tr_XST_to_r0(int op)
1222 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1223 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1226 static void tr_PM4_to_r0(int op)
1231 static void tr_PMC_to_r0(int op)
1233 if (known_regb & KRREG_PMC)
1235 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1236 known_regs.emu_status |= SSP_PMC_SET;
1237 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1238 // do nothing - this is handled elsewhere
1240 tr_mov16(0, known_regs.pmc.l);
1241 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1246 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1247 tr_flush_dirty_ST();
1249 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1250 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1251 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1252 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1253 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1254 EOP_STR_IMM(1,7,0x484);
1255 hostreg_r[0] = hostreg_r[1] = -1;
1260 typedef void (tr_read_func)(int op);
1262 static tr_read_func *tr_read_funcs[16] =
1277 (tr_read_func *)tr_unhandled,
1283 // write r0 to general reg handlers. Trashes r1
1284 #define TR_WRITE_R0_TO_REG(reg) \
1286 hostreg_sspreg_changed(reg); \
1287 hostreg_r[0] = (reg)<<16; \
1288 if (const_val != -1) { \
1289 known_regs.gr[reg].h = const_val; \
1290 known_regb |= 1 << (reg); \
1292 known_regb &= ~(1 << (reg)); \
1296 static void tr_r0_to_GR0(int const_val)
1301 static void tr_r0_to_X(int const_val)
1303 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1304 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1305 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1306 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1307 TR_WRITE_R0_TO_REG(SSP_X);
1310 static void tr_r0_to_Y(int const_val)
1312 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1313 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1314 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
1315 dirty_regb |= KRREG_P;
1316 TR_WRITE_R0_TO_REG(SSP_Y);
1319 static void tr_r0_to_A(int const_val)
1321 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1322 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1323 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1324 TR_WRITE_R0_TO_REG(SSP_A);
1327 static void tr_r0_to_ST(int const_val)
1329 // VR doesn't need much accuracy here..
1330 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1331 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1332 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1333 TR_WRITE_R0_TO_REG(SSP_ST);
1335 dirty_regb &= ~KRREG_ST;
1338 static void tr_r0_to_STACK(int const_val)
1341 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1342 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1343 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1344 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1345 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1349 static void tr_r0_to_PC(int const_val)
1351 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1352 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1356 static void tr_r0_to_AL(int const_val)
1358 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1359 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1360 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1361 hostreg_sspreg_changed(SSP_AL);
1362 if (const_val != -1) {
1363 known_regs.gr[SSP_A].l = const_val;
1364 known_regb |= 1 << SSP_AL;
1366 known_regb &= ~(1 << SSP_AL);
1369 static void tr_r0_to_PMX(int reg)
1371 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1373 known_regs.pmac_write[reg] = known_regs.pmc.v;
1374 known_regs.emu_status &= ~SSP_PMC_SET;
1375 known_regb |= 1 << (25+reg);
1376 dirty_regb |= 1 << (25+reg);
1380 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1384 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1386 mode = known_regs.pmac_write[reg]>>16;
1387 addr = known_regs.pmac_write[reg]&0xffff;
1388 if ((mode & 0x43ff) == 0x0018) // DRAM
1390 int inc = get_inc(mode);
1391 if (mode & 0x0400) tr_unhandled();
1392 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1393 emit_mov_const(A_COND_AL, 2, addr<<1);
1394 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1395 known_regs.pmac_write[reg] += inc;
1397 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1399 if (mode & 0x0400) tr_unhandled();
1400 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1401 emit_mov_const(A_COND_AL, 2, addr<<1);
1402 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1403 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1405 else if ((mode & 0x47ff) == 0x001c) // IRAM
1407 int inc = get_inc(mode);
1408 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1409 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1410 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1412 EOP_STR_IMM(1,7,0x494); // iram_dirty
1413 known_regs.pmac_write[reg] += inc;
1418 known_regs.pmc.v = known_regs.pmac_write[reg];
1419 //known_regb |= KRREG_PMC;
1420 dirty_regb |= KRREG_PMC;
1421 dirty_regb |= 1 << (25+reg);
1422 hostreg_r[1] = hostreg_r[2] = -1;
1426 known_regb &= ~KRREG_PMC;
1427 dirty_regb &= ~KRREG_PMC;
1428 known_regb &= ~(1 << (25+reg));
1429 dirty_regb &= ~(1 << (25+reg));
1431 // call the C code to handle this
1432 tr_flush_dirty_ST();
1433 //tr_flush_dirty_pmcrs();
1435 emit_call(ssp_pm_write);
1439 static void tr_r0_to_PM0(int const_val)
1444 static void tr_r0_to_PM1(int const_val)
1449 static void tr_r0_to_PM2(int const_val)
1454 static void tr_r0_to_PM4(int const_val)
1459 static void tr_r0_to_PMC(int const_val)
1461 if ((known_regb & KRREG_PMC) && const_val != -1)
1463 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1464 known_regs.emu_status |= SSP_PMC_SET;
1465 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1466 known_regs.pmc.h = const_val;
1468 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1469 known_regs.pmc.l = const_val;
1474 tr_flush_dirty_ST();
1475 if (known_regb & KRREG_PMC) {
1476 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1477 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1478 known_regb &= ~KRREG_PMC;
1479 dirty_regb &= ~KRREG_PMC;
1481 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1482 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1483 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1484 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1485 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1486 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1487 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1488 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1489 EOP_STR_IMM(1,7,0x484);
1490 hostreg_r[1] = hostreg_r[2] = -1;
1494 typedef void (tr_write_func)(int const_val);
1496 static tr_write_func *tr_write_funcs[16] =
1505 (tr_write_func *)tr_unhandled,
1509 (tr_write_func *)tr_unhandled,
1511 (tr_write_func *)tr_unhandled,
1516 static void tr_mac_load_XY(int op)
1518 tr_rX_read(op&3, (op>>2)&3); // X
1519 EOP_MOV_REG_LSL(4, 0, 16);
1520 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1521 EOP_ORR_REG_SIMPLE(4, 0);
1522 dirty_regb |= KRREG_P;
1523 hostreg_sspreg_changed(SSP_X);
1524 hostreg_sspreg_changed(SSP_Y);
1525 known_regb &= ~KRREG_X;
1526 known_regb &= ~KRREG_Y;
1529 // -----------------------------------------------------
1531 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1534 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1540 pmcv = imm | (PROGRAM((*pc)++) << 16);
1541 known_regs.pmc.v = pmcv;
1542 known_regb |= KRREG_PMC;
1543 dirty_regb |= KRREG_PMC;
1544 known_regs.emu_status |= SSP_PMC_SET;
1546 // check for possible reg programming
1547 tmpv = PROGRAM(*pc);
1548 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1550 int is_write = (tmpv & 0xff8f) == 0x80;
1551 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1552 if (reg > 4) tr_unhandled();
1553 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1554 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1555 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1556 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1557 known_regs.emu_status &= ~SSP_PMC_SET;
1566 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1568 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1575 if (op != 0x0840 || imm != 0) return 0;
1576 pp = PROGRAM_P(*pc);
1577 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1579 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1580 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1581 hostreg_sspreg_changed(SSP_ST);
1582 known_regs.gr[SSP_ST].h = 0x60;
1583 known_regb |= 1 << SSP_ST;
1584 dirty_regb &= ~KRREG_ST;
1589 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1595 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1598 EOP_MOV_REG_LSL(0, 0, 4);
1599 EOP_ORR_REG_LSR(0, 0, 0, 16);
1605 // -----------------------------------------------------
1607 static int translate_op(unsigned int op, int *pc, int imm)
1609 u32 tmpv, tmpv2, tmpv3;
1611 known_regs.gr[SSP_PC].h = *pc;
1617 if (op == 0) { ret++; break; } // nop
1618 tmpv = op & 0xf; // src
1619 tmpv2 = (op >> 4) & 0xf; // dst
1620 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1622 EOP_MOV_REG_SIMPLE(5, 10);
1623 hostreg_sspreg_changed(SSP_A);
1624 known_regb &= ~(KRREG_A|KRREG_AL);
1627 tr_read_funcs[tmpv](op);
1628 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1629 if (tmpv2 == SSP_PC) ret |= 0x10000;
1634 int r = (op&3) | ((op>>6)&4);
1635 int mod = (op>>2)&3;
1636 tmpv = (op >> 4) & 0xf; // dst
1637 ret = tr_detect_rotate(op, pc, imm);
1641 else tr_ptrr_mod(r, mod, 1, 1);
1642 tr_write_funcs[tmpv](-1);
1643 if (tmpv == SSP_PC) ret |= 0x10000;
1649 tmpv = (op >> 4) & 0xf; // src
1650 tr_read_funcs[tmpv](op);
1656 tr_bank_read(op&0x1ff);
1662 tmpv = (op & 0xf0) >> 4; // dst
1663 ret = tr_detect_pm0_block(op, pc, imm);
1665 ret = tr_detect_set_pm(op, pc, imm);
1668 tr_write_funcs[tmpv](imm);
1669 if (tmpv == SSP_PC) ret |= 0x10000;
1674 tmpv2 = (op >> 4) & 0xf; // dst
1676 tr_write_funcs[tmpv2](-1);
1677 if (tmpv2 == SSP_PC) ret |= 0x10000;
1689 tr_bank_write(op&0x1ff);
1695 r = (op&3) | ((op>>6)&4); // src
1696 tmpv2 = (op >> 4) & 0xf; // dst
1697 if ((r&3) == 3) tr_unhandled();
1699 if (known_regb & (1 << (r+8))) {
1700 tr_mov16(0, known_regs.r[r]);
1701 tr_write_funcs[tmpv2](known_regs.r[r]);
1703 int reg = (r < 4) ? 8 : 9;
1704 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1705 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1707 tr_write_funcs[tmpv2](-1);
1715 r = (op&3) | ((op>>6)&4); // dst
1716 tmpv = (op >> 4) & 0xf; // src
1717 if ((r&3) == 3) tr_unhandled();
1719 if (known_regb & (1 << tmpv)) {
1720 known_regs.r[r] = known_regs.gr[tmpv].h;
1721 known_regb |= 1 << (r + 8);
1722 dirty_regb |= 1 << (r + 8);
1724 int reg = (r < 4) ? 8 : 9;
1725 int ror = ((4 - (r&3))*8) & 0x1f;
1726 tr_read_funcs[tmpv](op);
1727 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1728 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1729 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1731 known_regb &= ~(1 << (r+8));
1732 dirty_regb &= ~(1 << (r+8));
1740 known_regs.r[tmpv] = op;
1741 known_regb |= 1 << (tmpv + 8);
1742 dirty_regb |= 1 << (tmpv + 8);
1747 u32 *jump_op = NULL;
1748 tmpv = tr_cond_check(op);
1749 if (tmpv != A_COND_AL) {
1750 jump_op = tcache_ptr;
1751 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1754 tr_r0_to_STACK(*pc);
1755 if (tmpv != A_COND_AL) {
1756 u32 *real_ptr = tcache_ptr;
1757 tcache_ptr = jump_op;
1758 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1759 tcache_ptr = real_ptr;
1761 tr_mov16_cond(tmpv, 0, imm);
1762 if (tmpv != A_COND_AL) {
1763 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1765 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1772 tmpv2 = (op >> 4) & 0xf; // dst
1774 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1775 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1776 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1777 hostreg_r[0] = hostreg_r[1] = -1;
1778 tr_write_funcs[tmpv2](-1);
1779 if (tmpv2 == SSP_PC) ret |= 0x10000;
1784 tmpv = tr_cond_check(op);
1785 tr_mov16_cond(tmpv, 0, imm);
1786 if (tmpv != A_COND_AL) {
1787 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1789 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1795 // check for repeats of this op
1797 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1800 if ((op&0xf0) != 0) // !always
1803 tmpv2 = tr_cond_check(op);
1805 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1806 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1807 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1808 case 7: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_EOR,0,5,1,31,A_AM1_ASR,5); // eor r1, r5, r5, asr #31
1809 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1810 hostreg_r[1] = -1; break; // abs
1811 default: tr_unhandled();
1814 hostreg_sspreg_changed(SSP_A);
1815 dirty_regb |= KRREG_ST;
1816 known_regb &= ~KRREG_ST;
1817 known_regb &= ~(KRREG_A|KRREG_AL);
1826 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1827 hostreg_sspreg_changed(SSP_A);
1828 known_regb &= ~(KRREG_A|KRREG_AL);
1829 dirty_regb |= KRREG_ST;
1832 // mpya (rj), (ri), b
1837 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1838 hostreg_sspreg_changed(SSP_A);
1839 known_regb &= ~(KRREG_A|KRREG_AL);
1840 dirty_regb |= KRREG_ST;
1843 // mld (rj), (ri), b
1845 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1846 hostreg_sspreg_changed(SSP_A);
1847 known_regs.gr[SSP_A].v = 0;
1848 known_regb |= (KRREG_A|KRREG_AL);
1849 dirty_regb |= KRREG_ST;
1860 tmpv = op & 0xf; // src
1861 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1862 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1863 if (tmpv == SSP_P) {
1865 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1866 } else if (tmpv == SSP_A) {
1867 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1869 tr_read_funcs[tmpv](op);
1870 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1872 hostreg_sspreg_changed(SSP_A);
1873 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1874 dirty_regb |= KRREG_ST;
1884 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1885 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1886 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1887 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1888 hostreg_sspreg_changed(SSP_A);
1889 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1890 dirty_regb |= KRREG_ST;
1900 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1901 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1902 tr_bank_read(op&0x1ff);
1903 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1904 hostreg_sspreg_changed(SSP_A);
1905 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1906 dirty_regb |= KRREG_ST;
1916 tmpv = (op & 0xf0) >> 4;
1917 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1918 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
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;
1933 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1934 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
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;
1950 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1951 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1952 r = (op&3) | ((op>>6)&4); // src
1953 if ((r&3) == 3) tr_unhandled();
1955 if (known_regb & (1 << (r+8))) {
1956 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1958 int reg = (r < 4) ? 8 : 9;
1959 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1960 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1961 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1964 hostreg_sspreg_changed(SSP_A);
1965 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1966 dirty_regb |= KRREG_ST;
1977 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1978 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1979 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1980 hostreg_sspreg_changed(SSP_A);
1981 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1982 dirty_regb |= KRREG_ST;
1989 static void *translate_block(int pc)
1991 unsigned int op, op1, imm, ccount = 0;
1992 unsigned int *block_start;
1993 int ret, ret_prev = -1, tpc;
1995 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1996 block_start = tcache_ptr;
1998 dirty_regb = KRREG_P;
1999 known_regs.emu_status = 0;
2002 emit_block_prologue();
2004 for (; ccount < 100;)
2010 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2011 imm = PROGRAM(pc++); // immediate
2014 ret = translate_op(op, &pc, imm);
2017 tr_flush_dirty_prs();
2018 tr_flush_dirty_ST();
2019 tr_flush_dirty_pmcrs();
2020 known_regs.emu_status = 0;
2022 emit_mov_const(A_COND_AL, 0, op);
2026 emit_mov_const(A_COND_AL, 1, imm);
2031 if (ret_prev > 0) emit_call(regfile_store);
2032 emit_call(in_funcs[op1]);
2033 emit_call(regfile_load);
2035 if (in_funcs[op1] == NULL) {
2036 printf("NULL func! op=%08x (%02x)\n", op, op1);
2041 dirty_regb |= KRREG_P;
2046 ccount += ret & 0xffff;
2047 if (ret & 0x10000) break;
2056 tr_flush_dirty_prs();
2057 tr_flush_dirty_ST();
2058 tr_flush_dirty_pmcrs();
2059 emit_block_epilogue(ccount + 1);
2060 *tcache_ptr++ = 0xffffffff; // end of block
2062 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2063 printf("tcache overflow!\n");
2070 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2074 FILE *f = fopen("tcache.bin", "wb");
2075 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2088 // -----------------------------------------------------
2090 int ssp1601_dyn_startup(void)
2092 memset(tcache, 0, TCACHE_SIZE);
2093 memset(block_table, 0, sizeof(block_table));
2094 memset(block_table_iram, 0, sizeof(block_table_iram));
2095 memset(block_ref, 0, sizeof(block_ref));
2096 memset(block_ref_iram, 0, sizeof(block_ref_iram));
2097 tcache_ptr = tcache;
2098 *tcache_ptr++ = 0xffffffff;
2102 block_table[0x400] = (void *) ssp_hle_800;
2107 static unsigned short dummy = 0;
2114 void ssp1601_dyn_reset(ssp1601_t *ssp)
2116 int i, u, total = 0;
2117 for (i = 0; i < 0x5090/2; i++)
2118 total += block_ref[i];
2119 for (u = 1; u < 15; u++)
2120 for (i = 0; i < 0x800/2; i++)
2121 total += block_ref_iram[u][i];
2123 printf("total: %i\n", total);
2124 for (i = 0; i < 0x5090/2; i++)
2126 printf("%07i %2.3f%% __:%04x\n", block_ref[i], (double)block_ref[i] / (double)total * 100.0, i<<1);
2127 for (u = 1; u < 15; u++)
2128 for (i = 0; i < 0x800/2; i++)
2129 if (block_ref_iram[u][i])
2130 printf("%07i %2.3f%% %02i:%04x\n", block_ref_iram[u][i],
2131 (double)block_ref_iram[u][i] / (double)total * 100.0, u, i<<1);
2134 ssp1601_reset_local(ssp);
2135 ssp->drc.ptr_rom = (unsigned int) Pico.rom;
2136 ssp->drc.ptr_iram_rom = (unsigned int) svp->iram_rom;
2137 ssp->drc.ptr_dram = (unsigned int) svp->dram;
2138 ssp->drc.iram_dirty = 0;
2141 void ssp1601_dyn_run(int cycles)
2143 if (ssp->emu_status & SSP_WAIT_MASK) return;
2146 rPC = DUMP_BLOCK >> 1;
2150 int (*trans_entry)(void);
2153 if (ssp->drc.iram_dirty) {
2154 iram_context = get_iram_context();
2155 ssp->drc.iram_dirty--;
2157 if (block_table_iram[iram_context][rPC] == NULL)
2158 block_table_iram[iram_context][rPC] = translate_block(rPC);
2159 trans_entry = (void *) block_table_iram[iram_context][rPC];
2160 block_ref_iram[iram_context][rPC]++;
2164 if (block_table[rPC] == NULL)
2165 block_table[rPC] = translate_block(rPC);
2166 trans_entry = (void *) block_table[rPC];
2170 cycles -= trans_entry();