1 // 187 blocks, 12072 bytes
4 #include "../../PicoInt.h"
7 static unsigned int *block_table[0x5090/2];
8 static unsigned int *block_table_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 0x2018
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;
502 //elprintf("set PM%i %08x", ssp->pmac_read[reg]);
506 //elprintf("rd PM%i %08x", ssp->pmac_read[reg]);
508 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
510 mode = ssp->pmac_read[reg]>>16;
511 if ((mode & 0xfff0) == 0x0800) // ROM
513 d = ((unsigned short *)Pico.rom)[ssp->pmac_read[reg]&0xfffff];
514 ssp->pmac_read[reg] += 1;
516 else if ((mode & 0x47ff) == 0x0018) // DRAM
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;
524 // PMC value corresponds to last PMR accessed
525 rPMC.v = ssp->pmac_read[reg];
530 static void ssp_pm_write(u32 d, int reg)
532 unsigned short *dram;
535 if (ssp->emu_status & SSP_PMC_SET)
537 ssp->pmac_write[reg] = rPMC.v;
538 ssp->emu_status &= ~SSP_PMC_SET;
543 ssp->emu_status &= ~SSP_PMC_HAVE_ADDR;
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
550 int inc = get_inc(mode);
552 overwrite_write(dram[addr], d);
553 } else dram[addr] = d;
554 ssp->pmac_write[reg] += inc;
556 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
559 overwrite_write(dram[addr], d);
560 } else dram[addr] = d;
561 ssp->pmac_write[reg] += (addr&1) ? 31 : 1;
563 else if ((mode & 0x47ff) == 0x001c) // IRAM
565 int inc = get_inc(mode);
566 ((unsigned short *)svp->iram_rom)[addr&0x3ff] = d;
567 ssp->pmac_write[reg] += inc;
568 ssp->drc.iram_dirty = 1;
571 rPMC.v = ssp->pmac_write[reg];
575 // -----------------------------------------------------
577 static unsigned char iram_context_map[] =
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
589 static int get_iram_context(void)
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];
593 val1 = iram_context_map[(val>>1)&0x3f];
596 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
597 //debug_dump2file(name, svp->iram_rom, 0x800);
600 // elprintf(EL_ANOMALY, "iram_context: %02i", val1);
604 // -----------------------------------------------------
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
613 /* regs with known values */
618 unsigned int pmac_read[5];
619 unsigned int pmac_write[5];
621 unsigned int emu_status;
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)
634 #define KRREG_PMCM (1 << 18) /* only mode word of PMC */
635 #define KRREG_PMC (1 << 19)
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)
647 /* bitfield of known register values */
648 static u32 known_regb = 0;
650 /* known vals, which need to be flushed
651 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
652 * ST means flags are being held in ARM PSR
653 * P means that it needs to be recalculated
655 static u32 dirty_regb = 0;
657 /* known values of host regs.
659 * 000000-00ffff - 16bit value
660 * 100000-10ffff - base reg (r7) + 16bit val
661 * 0r0000 - means reg (low) eq gr[r].h, r != AL
663 static int hostreg_r[4];
665 static void hostreg_clear(void)
668 for (i = 0; i < 4; i++)
672 static void hostreg_sspreg_changed(int sspreg)
675 for (i = 0; i < 4; i++)
676 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
680 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
681 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
683 static void tr_unhandled(void)
685 FILE *f = fopen("tcache.bin", "wb");
686 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
688 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
692 /* update P, if needed. Trashes r0 */
693 static void tr_flush_dirty_P(void)
696 if (!(dirty_regb & KRREG_P)) return;
697 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
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
701 dirty_regb &= ~KRREG_P;
705 /* write dirty pr to host reg. Nothing is trashed */
706 static void tr_flush_dirty_pr(int r)
710 if (!(dirty_regb & (1 << (r+8)))) return;
713 case 0: ror = 0; break;
714 case 1: ror = 24/2; break;
715 case 2: ror = 16/2; break;
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));
724 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
725 static void tr_flush_dirty_prs(void)
728 int dirty = dirty_regb >> 8;
730 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
732 if (!(dirty&1)) continue;
734 case 0: ror = 0; break;
735 case 1: ror = 24/2; break;
736 case 2: ror = 16/2; break;
738 reg = (i < 4) ? 8 : 9;
739 EOP_BIC_IMM(reg,reg,ror,0xff);
740 if (known_regs.r[i] != 0)
741 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
743 dirty_regb &= ~0xff00;
746 /* write dirty pr and "forget" it. Nothing is trashed. */
747 static void tr_release_pr(int r)
749 tr_flush_dirty_pr(r);
750 known_regb &= ~(1 << (r+8));
753 /* fush ARM PSR to r6. Trashes r1 */
754 static void tr_flush_dirty_ST(void)
756 if (!(dirty_regb & KRREG_ST)) return;
757 EOP_BIC_IMM(6,6,0,0x0f);
759 EOP_ORR_REG_LSR(6,6,1,28);
760 dirty_regb &= ~KRREG_ST;
764 /* inverse of above. Trashes r1 */
765 static void tr_make_dirty_ST(void)
767 if (dirty_regb & KRREG_ST) return;
768 if (known_regb & KRREG_ST) {
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);
774 EOP_MOV_REG_LSL(1, 6, 28);
778 dirty_regb |= KRREG_ST;
781 /* load 16bit val into host reg r0-r3. Nothing is trashed */
782 static void tr_mov16(int r, int val)
784 if (hostreg_r[r] != val) {
785 emit_mov_const(A_COND_AL, r, val);
790 static void tr_mov16_cond(int cond, int r, int val)
792 emit_mov_const(cond, r, val);
797 static void tr_flush_dirty_pmcrs(void)
799 u32 i, val = (u32)-1;
800 if (!(dirty_regb & 0x3ff80000)) return;
802 if (dirty_regb & KRREG_PMC) {
803 val = known_regs.pmc.v;
804 emit_mov_const(A_COND_AL, 1, val);
805 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
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");
812 for (i = 0; i < 5; i++)
814 if (dirty_regb & (1 << (20+i))) {
815 if (val != known_regs.pmac_read[i]) {
816 val = known_regs.pmac_read[i];
817 emit_mov_const(A_COND_AL, 1, val);
819 EOP_STR_IMM(1,7,0x454+i*4); // pmac_read
821 if (dirty_regb & (1 << (25+i))) {
822 if (val != known_regs.pmac_write[i]) {
823 val = known_regs.pmac_write[i];
824 emit_mov_const(A_COND_AL, 1, val);
826 EOP_STR_IMM(1,7,0x46c+i*4); // pmac_write
829 dirty_regb &= ~0x3ff80000;
833 /* read bank word to r0 (upper bits zero). Thrashes r1. */
834 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
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);
844 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
848 /* write r0 to bank. Trashes r1. */
849 static void tr_bank_write(int addr)
853 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
854 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
855 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
859 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
862 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
863 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
865 int modulo_shift = -1; /* unknown */
867 if (mod == 0) return;
869 if (!need_modulo || mod == 1) // +!
871 else if (need_modulo && (known_regb & KRREG_ST)) {
872 modulo_shift = known_regs.gr[SSP_ST].h & 7;
873 if (modulo_shift == 0) modulo_shift = 8;
876 if (modulo_shift == -1)
878 int reg = (r < 4) ? 8 : 9;
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);
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
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
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
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;
903 else if (known_regb & (1 << (r + 8)))
905 int modulo = (1 << modulo_shift) - 1;
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);
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
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));
917 EOP_MOV_REG_ROR(reg,reg,32-ror);
921 /* handle writes r0 to (rX). Trashes r1.
922 * fortunately we can ignore modulo increment modes for writes. */
923 static void tr_rX_write(int op)
927 int mod = (op>>2) & 3; // direct addressing
928 tr_bank_write((op & 0x100) + mod);
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]);
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>
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]
946 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
950 /* read (rX) to r0. Trashes r1-r3. */
951 static void tr_rX_read(int r, int mod)
955 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
959 if (known_regb & (1 << (r + 8))) {
960 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
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>
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]
970 hostreg_r[0] = hostreg_r[1] = -1;
972 tr_ptrr_mod(r, mod, 1, 1);
976 /* read ((rX)) to r0. Trashes r1,r2. */
977 static void tr_rX_read2(int op)
979 int r = (op&3) | ((op>>6)&4); // src
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]);
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>
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]
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
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]);
1003 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1006 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
1007 hostreg_r[0] = hostreg_r[2] = -1;
1010 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1011 static int tr_cond_check(int op)
1013 int f = (op & 0x100) >> 8;
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;
1025 printf("unimplemented cond?\n");
1031 static int tr_neg_cond(int 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);
1044 static int tr_aop_ssp2arm(int 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;
1059 // -----------------------------------------------------
1061 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
1062 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
1065 //@ r6: STACK and emu flags
1069 // read general reg to r0. Trashes r1
1070 static void tr_GR0_to_r0(int op)
1072 tr_mov16(0, 0xffff);
1075 static void tr_X_to_r0(int op)
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;
1083 static void tr_Y_to_r0(int op)
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;
1092 static void tr_A_to_r0(int op)
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;
1100 static void tr_ST_to_r0(int op)
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
1108 static void tr_STACK_to_r0(int op)
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;
1119 static void tr_PC_to_r0(int op)
1121 tr_mov16(0, known_regs.gr[SSP_PC].h);
1124 static void tr_P_to_r0(int op)
1127 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1131 static void tr_AL_to_r0(int op)
1134 if (known_regb & KRREG_PMC) {
1135 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
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);
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;
1149 static void tr_PMX_to_r0(int reg)
1151 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1153 known_regs.pmac_read[reg] = known_regs.pmc.v;
1154 known_regs.emu_status &= ~SSP_PMC_SET;
1155 known_regb |= 1 << (20+reg);
1156 dirty_regb |= 1 << (20+reg);
1160 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1162 u32 pmcv = known_regs.pmac_read[reg];
1163 int mode = pmcv>>16;
1164 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1166 if ((mode & 0xfff0) == 0x0800)
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]
1171 known_regs.pmac_read[reg] += 1;
1173 else if ((mode & 0x47ff) == 0x0018) // DRAM
1175 int inc = get_inc(mode);
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]
1179 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
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);
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
1187 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1189 known_regs.pmac_read[reg] += inc;
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;
1203 known_regb &= ~KRREG_PMC;
1204 dirty_regb &= ~KRREG_PMC;
1205 known_regb &= ~(1 << (20+reg));
1206 dirty_regb &= ~(1 << (20+reg));
1208 // call the C code to handle this
1209 tr_flush_dirty_ST();
1210 //tr_flush_dirty_pmcrs();
1212 emit_call(ssp_pm_read);
1216 static void tr_PM0_to_r0(int op)
1221 static void tr_PM1_to_r0(int op)
1226 static void tr_PM2_to_r0(int op)
1231 static void tr_XST_to_r0(int op)
1233 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1234 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1237 static void tr_PM4_to_r0(int op)
1242 static void tr_PMC_to_r0(int op)
1244 if (known_regb & KRREG_PMC)
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
1251 tr_mov16(0, known_regs.pmc.l);
1252 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1257 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1258 tr_flush_dirty_ST();
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;
1271 typedef void (tr_read_func)(int op);
1273 static tr_read_func *tr_read_funcs[16] =
1288 (tr_read_func *)tr_unhandled,
1294 // write r0 to general reg handlers. Trashes r1
1295 #define TR_WRITE_R0_TO_REG(reg) \
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); \
1303 known_regb &= ~(1 << (reg)); \
1307 static void tr_r0_to_GR0(int const_val)
1312 static void tr_r0_to_X(int const_val)
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
1317 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1318 TR_WRITE_R0_TO_REG(SSP_X);
1321 static void tr_r0_to_Y(int const_val)
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
1326 dirty_regb |= KRREG_P;
1327 TR_WRITE_R0_TO_REG(SSP_Y);
1330 static void tr_r0_to_A(int const_val)
1332 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1333 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1334 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1335 TR_WRITE_R0_TO_REG(SSP_A);
1338 static void tr_r0_to_ST(int const_val)
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
1344 TR_WRITE_R0_TO_REG(SSP_ST);
1346 dirty_regb &= ~KRREG_ST;
1349 static void tr_r0_to_STACK(int const_val)
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
1354 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1355 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1356 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1360 static void tr_r0_to_PC(int const_val)
1362 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1363 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1367 static void tr_r0_to_AL(int const_val)
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;
1377 known_regb &= ~(1 << SSP_AL);
1380 static void tr_r0_to_PMX(int reg)
1383 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
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);
1393 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1397 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1399 mode = known_regs.pmac_write[reg]>>16;
1400 addr = known_regs.pmac_write[reg]&0xffff;
1401 if ((mode & 0x43ff) == 0x0018) // DRAM
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;
1410 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
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;
1418 else if ((mode & 0x47ff) == 0x001c) // IRAM
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]
1425 EOP_STR_IMM(1,7,0x494); // iram_dirty
1426 known_regs.pmac_write[reg] += inc;
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;
1439 known_regb &= ~KRREG_PMC;
1440 dirty_regb &= ~KRREG_PMC;
1441 known_regb &= ~(1 << (25+reg));
1442 dirty_regb &= ~(1 << (25+reg));
1444 tr_flush_dirty_pmcrs();
1446 known_regb &= ~KRREG_PMC;
1447 dirty_regb &= ~KRREG_PMC;
1448 known_regb &= ~(1 << (25+reg));
1449 dirty_regb &= ~(1 << (25+reg));
1453 // call the C code to handle this
1454 tr_flush_dirty_ST();
1455 //tr_flush_dirty_pmcrs();
1457 emit_call(ssp_pm_write);
1461 static void tr_r0_to_PM0(int const_val)
1466 static void tr_r0_to_PM1(int const_val)
1471 static void tr_r0_to_PM2(int const_val)
1476 static void tr_r0_to_PM4(int const_val)
1481 static void tr_r0_to_PMC(int const_val)
1483 if ((known_regb & KRREG_PMC) && const_val != -1)
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;
1490 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1491 known_regs.pmc.l = const_val;
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;
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;
1516 typedef void (tr_write_func)(int const_val);
1518 static tr_write_func *tr_write_funcs[16] =
1527 (tr_write_func *)tr_unhandled,
1531 (tr_write_func *)tr_unhandled,
1533 (tr_write_func *)tr_unhandled,
1538 static void tr_mac_load_XY(int op)
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;
1551 // -----------------------------------------------------
1553 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1556 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1562 pmcv = imm | (PROGRAM((*pc)++) << 16);
1563 known_regs.pmc.v = pmcv;
1564 known_regb |= KRREG_PMC;
1565 dirty_regb |= KRREG_PMC;
1566 known_regs.emu_status |= SSP_PMC_SET;
1568 // check for possible reg programming
1569 tmpv = PROGRAM(*pc);
1570 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1572 int is_write = (tmpv & 0xff8f) == 0x80;
1573 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1574 if (reg > 4) tr_unhandled();
1575 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1576 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1577 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1578 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1579 known_regs.emu_status &= ~SSP_PMC_SET;
1588 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1590 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
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;
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;
1611 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1617 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1620 EOP_MOV_REG_LSL(0, 0, 4);
1621 EOP_ORR_REG_LSR(0, 0, 0, 16);
1627 // -----------------------------------------------------
1629 static int translate_op(unsigned int op, int *pc, int imm)
1631 u32 tmpv, tmpv2, tmpv3;
1633 known_regs.gr[SSP_PC].h = *pc;
1639 if (op == 0) { ret++; break; } // nop
1640 tmpv = op & 0xf; // src
1641 tmpv2 = (op >> 4) & 0xf; // dst
1642 //if (tmpv2 >= 8) return -1; // TODO
1643 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1645 EOP_MOV_REG_SIMPLE(5, 10);
1646 hostreg_sspreg_changed(SSP_A);
1647 known_regb &= ~(KRREG_A|KRREG_AL);
1650 tr_read_funcs[tmpv](op);
1651 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1652 if (tmpv2 == SSP_PC) ret |= 0x10000;
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
1661 ret = tr_detect_rotate(op, pc, imm);
1663 if (tmpv >= 8) return -1; // TODO
1666 else tr_ptrr_mod(r, mod, 1, 1);
1667 tr_write_funcs[tmpv](-1);
1668 if (tmpv == SSP_PC) ret |= 0x10000;
1674 tmpv = (op >> 4) & 0xf; // src
1675 tr_read_funcs[tmpv](op);
1681 tr_bank_read(op&0x1ff);
1687 tmpv = (op & 0xf0) >> 4; // dst
1688 ret = tr_detect_pm0_block(op, pc, imm);
1693 tr_write_funcs[tmpv](imm);
1696 ret = tr_detect_set_pm(op, pc, imm);
1698 if (tmpv == SSP_PC) ret |= 0x10000;
1699 return -1; /* TODO.. */
1703 tmpv2 = (op >> 4) & 0xf; // dst
1704 if (tmpv2 >= 8) return -1; // TODO
1706 tr_write_funcs[tmpv2](-1);
1707 if (tmpv2 == SSP_PC) ret |= 0x10000;
1719 tr_bank_write(op&0x1ff);
1725 r = (op&3) | ((op>>6)&4); // src
1726 tmpv2 = (op >> 4) & 0xf; // dst
1727 if (tmpv2 >= 8) tr_unhandled();
1728 if ((r&3) == 3) tr_unhandled();
1730 if (known_regb & (1 << (r+8))) {
1731 tr_mov16(0, known_regs.r[r]);
1732 tr_write_funcs[tmpv2](known_regs.r[r]);
1734 int reg = (r < 4) ? 8 : 9;
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>
1738 tr_write_funcs[tmpv2](-1);
1746 r = (op&3) | ((op>>6)&4); // dst
1747 tmpv = (op >> 4) & 0xf; // src
1748 if ((r&3) == 3) tr_unhandled();
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);
1755 int reg = (r < 4) ? 8 : 9;
1756 int ror = ((4 - (r&3))*8) & 0x1f;
1757 tr_read_funcs[tmpv](op);
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
1762 known_regb &= ~(1 << (r+8));
1763 dirty_regb &= ~(1 << (r+8));
1771 known_regs.r[tmpv] = op;
1772 known_regb |= 1 << (tmpv + 8);
1773 dirty_regb |= 1 << (tmpv + 8);
1778 u32 *jump_op = NULL;
1779 tmpv = tr_cond_check(op);
1780 if (tmpv != A_COND_AL) {
1781 jump_op = tcache_ptr;
1782 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
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;
1792 tr_mov16_cond(tmpv, 0, imm);
1793 if (tmpv != A_COND_AL) {
1794 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1796 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1803 tmpv2 = (op >> 4) & 0xf; // dst
1804 if (tmpv2 >= 8) return -1; // TODO
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;
1811 tr_write_funcs[tmpv2](-1);
1812 if (tmpv2 == SSP_PC) ret |= 0x10000;
1817 tmpv = tr_cond_check(op);
1818 tr_mov16_cond(tmpv, 0, imm);
1819 if (tmpv != A_COND_AL) {
1820 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1822 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1828 // check for repeats of this op
1830 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1833 if ((op&0xf0) != 0) // !always
1836 tmpv2 = tr_cond_check(op);
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
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
1843 hostreg_r[1] = -1; break; // abs
1844 default: tr_unhandled();
1847 hostreg_sspreg_changed(SSP_A);
1848 dirty_regb |= KRREG_ST;
1849 known_regb &= ~KRREG_ST;
1850 known_regb &= ~(KRREG_A|KRREG_AL);
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;
1865 // mpya (rj), (ri), b
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;
1876 // mld (rj), (ri), b
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;
1881 known_regb |= (KRREG_A|KRREG_AL);
1882 dirty_regb |= KRREG_ST;
1893 tmpv = op & 0xf; // src
1894 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1895 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1896 if (tmpv == SSP_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
1902 tr_read_funcs[tmpv](op);
1903 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1905 hostreg_sspreg_changed(SSP_A);
1906 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1907 dirty_regb |= KRREG_ST;
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;
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;
1949 tmpv = (op & 0xf0) >> 4;
1950 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1951 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
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;
1966 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1967 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
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;
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();
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
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
1997 hostreg_sspreg_changed(SSP_A);
1998 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1999 dirty_regb |= KRREG_ST;
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;
2022 static void *translate_block(int pc)
2024 unsigned int op, op1, imm, ccount = 0;
2025 unsigned int *block_start;
2026 int ret, ret_prev = -1, tpc;
2029 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
2031 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
2032 block_start = tcache_ptr;
2034 dirty_regb = KRREG_P;
2035 known_regs.emu_status = 0;
2038 emit_block_prologue();
2040 for (; ccount < 100;)
2042 //printf(" insn #%i\n", icount);
2047 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2048 imm = PROGRAM(pc++); // immediate
2051 ret = translate_op(op, &pc, imm);
2054 tr_flush_dirty_prs();
2055 tr_flush_dirty_ST();
2056 tr_flush_dirty_pmcrs();
2057 known_regs.emu_status = 0;
2059 emit_mov_const(A_COND_AL, 0, op);
2063 emit_mov_const(A_COND_AL, 1, imm);
2068 if (ret_prev > 0) emit_call(regfile_store);
2069 emit_call(in_funcs[op1]);
2070 emit_call(regfile_load);
2072 if (in_funcs[op1] == NULL) {
2073 printf("NULL func! op=%08x (%02x)\n", op, op1);
2078 dirty_regb |= KRREG_P;
2083 ccount += ret & 0xffff;
2084 if (ret & 0x10000) break;
2090 tr_flush_dirty_prs();
2091 tr_flush_dirty_ST();
2092 tr_flush_dirty_pmcrs();
2093 emit_block_epilogue(ccount + 1);
2094 *tcache_ptr++ = 0xffffffff; // end of block
2095 //printf(" %i inst\n", icount);
2097 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2098 printf("tcache overflow!\n");
2106 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2107 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
2111 FILE *f = fopen("tcache.bin", "wb");
2112 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2125 // -----------------------------------------------------
2127 int ssp1601_dyn_startup(void)
2129 memset(tcache, 0, TCACHE_SIZE);
2130 memset(block_table, 0, sizeof(block_table));
2131 memset(block_table_iram, 0, sizeof(block_table_iram));
2132 tcache_ptr = tcache;
2133 *tcache_ptr++ = 0xffffffff;
2137 block_table[0x400] = (void *) ssp_hle_800;
2142 static unsigned short dummy = 0;
2149 void ssp1601_dyn_reset(ssp1601_t *ssp)
2151 ssp1601_reset_local(ssp);
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;
2158 void ssp1601_dyn_run(int cycles)
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);
2165 rPC = DUMP_BLOCK >> 1;
2169 int (*trans_entry)(void);
2172 if (ssp->drc.iram_dirty) {
2173 iram_context = get_iram_context();
2174 ssp->drc.iram_dirty--;
2176 if (block_table_iram[iram_context][rPC] == NULL)
2177 block_table_iram[iram_context][rPC] = translate_block(rPC);
2178 trans_entry = (void *) block_table_iram[iram_context][rPC];
2182 if (block_table[rPC] == NULL)
2183 block_table[rPC] = translate_block(rPC);
2184 trans_entry = (void *) block_table[rPC];
2187 //printf("enter %04x\n", rPC<<1);
2188 cycles -= trans_entry();
2189 //printf("leave %04x\n", rPC<<1);
2191 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);