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 0x29d4
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;
570 rPMC.v = ssp->pmac_write[reg];
574 // -----------------------------------------------------
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 // -----------------------------------------------------
606 SSP_GR0, SSP_X, SSP_Y, SSP_A,
607 SSP_ST, SSP_STACK, SSP_PC, SSP_P,
608 SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
609 SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
612 /* regs with known values */
617 unsigned int pmac_read[5];
618 unsigned int pmac_write[5];
620 unsigned int emu_status;
623 #define KRREG_X (1 << SSP_X)
624 #define KRREG_Y (1 << SSP_Y)
625 #define KRREG_A (1 << SSP_A) /* AH only */
626 #define KRREG_ST (1 << SSP_ST)
627 #define KRREG_STACK (1 << SSP_STACK)
628 #define KRREG_PC (1 << SSP_PC)
629 #define KRREG_P (1 << SSP_P)
630 #define KRREG_PR0 (1 << 8)
631 #define KRREG_PR4 (1 << 12)
632 #define KRREG_AL (1 << 16)
633 #define KRREG_PMCM (1 << 18) /* only mode word of PMC */
634 #define KRREG_PMC (1 << 19)
635 #define KRREG_PM0R (1 << 20)
636 #define KRREG_PM1R (1 << 21)
637 #define KRREG_PM2R (1 << 22)
638 #define KRREG_PM3R (1 << 23)
639 #define KRREG_PM4R (1 << 24)
640 #define KRREG_PM0W (1 << 25)
641 #define KRREG_PM1W (1 << 26)
642 #define KRREG_PM2W (1 << 27)
643 #define KRREG_PM3W (1 << 28)
644 #define KRREG_PM4W (1 << 29)
646 /* bitfield of known register values */
647 static u32 known_regb = 0;
649 /* known vals, which need to be flushed
650 * (only ST, P, r0-r7, PMCx, PMxR, PMxW)
651 * ST means flags are being held in ARM PSR
652 * P means that it needs to be recalculated
654 static u32 dirty_regb = 0;
656 /* known values of host regs.
658 * 000000-00ffff - 16bit value
659 * 100000-10ffff - base reg (r7) + 16bit val
660 * 0r0000 - means reg (low) eq gr[r].h, r != AL
662 static int hostreg_r[4];
664 static void hostreg_clear(void)
667 for (i = 0; i < 4; i++)
671 static void hostreg_sspreg_changed(int sspreg)
674 for (i = 0; i < 4; i++)
675 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
679 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
680 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
682 static void tr_unhandled(void)
684 FILE *f = fopen("tcache.bin", "wb");
685 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
687 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
691 /* update P, if needed. Trashes r0 */
692 static void tr_flush_dirty_P(void)
695 if (!(dirty_regb & KRREG_P)) return;
696 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
697 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
698 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
699 EOP_MUL(10, 0, 10); // mul r10, r0, r10
700 dirty_regb &= ~KRREG_P;
704 /* write dirty pr to host reg. Nothing is trashed */
705 static void tr_flush_dirty_pr(int r)
709 if (!(dirty_regb & (1 << (r+8)))) return;
712 case 0: ror = 0; break;
713 case 1: ror = 24/2; break;
714 case 2: ror = 16/2; break;
716 reg = (r < 4) ? 8 : 9;
717 EOP_BIC_IMM(reg,reg,ror,0xff);
718 if (known_regs.r[r] != 0)
719 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
720 dirty_regb &= ~(1 << (r+8));
723 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
724 static void tr_flush_dirty_prs(void)
727 int dirty = dirty_regb >> 8;
729 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
731 if (!(dirty&1)) continue;
733 case 0: ror = 0; break;
734 case 1: ror = 24/2; break;
735 case 2: ror = 16/2; break;
737 reg = (i < 4) ? 8 : 9;
738 EOP_BIC_IMM(reg,reg,ror,0xff);
739 if (known_regs.r[i] != 0)
740 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
742 dirty_regb &= ~0xff00;
745 /* write dirty pr and "forget" it. Nothing is trashed. */
746 static void tr_release_pr(int r)
748 tr_flush_dirty_pr(r);
749 known_regb &= ~(1 << (r+8));
752 /* fush ARM PSR to r6. Trashes r1 */
753 static void tr_flush_dirty_ST(void)
755 if (!(dirty_regb & KRREG_ST)) return;
756 EOP_BIC_IMM(6,6,0,0x0f);
758 EOP_ORR_REG_LSR(6,6,1,28);
759 dirty_regb &= ~KRREG_ST;
763 /* inverse of above. Trashes r1 */
764 static void tr_make_dirty_ST(void)
766 if (dirty_regb & KRREG_ST) return;
767 if (known_regb & KRREG_ST) {
769 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
770 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
771 EOP_MSR_IMM(4/2, flags);
773 EOP_MOV_REG_LSL(1, 6, 28);
777 dirty_regb |= KRREG_ST;
780 /* load 16bit val into host reg r0-r3. Nothing is trashed */
781 static void tr_mov16(int r, int val)
783 if (hostreg_r[r] != val) {
784 emit_mov_const(A_COND_AL, r, val);
789 static void tr_mov16_cond(int cond, int r, int val)
791 emit_mov_const(cond, r, val);
796 static void tr_flush_dirty_pmcrs(void)
798 u32 i, val = (u32)-1;
799 if (!(dirty_regb & 0x3ff80000)) return;
801 if (dirty_regb & KRREG_PMC) {
802 val = known_regs.pmc.v;
803 emit_mov_const(A_COND_AL, 0, val);
804 EOP_STR_IMM(0,7,0x400+SSP_PMC*4);
806 if (known_regs.emu_status & (SSP_PMC_SET|SSP_PMC_HAVE_ADDR)) {
807 printf("!! SSP_PMC_SET|SSP_PMC_HAVE_ADDR set on flush\n");
811 for (i = 0; i < 5; i++)
813 if (dirty_regb & (1 << (20+i))) {
814 if (val != known_regs.pmac_read[i]) {
815 val = known_regs.pmac_read[i];
816 emit_mov_const(A_COND_AL, 0, val);
818 EOP_STR_IMM(0,7,0x454+i*4); // pmac_read
820 if (dirty_regb & (1 << (25+i))) {
821 if (val != known_regs.pmac_write[i]) {
822 val = known_regs.pmac_write[i];
823 emit_mov_const(A_COND_AL, 0, val);
825 EOP_STR_IMM(0,7,0x46c+i*4); // pmac_write
828 dirty_regb &= ~0x3ff80000;
832 /* read bank word to r0 (upper bits zero). Thrashes r1. */
833 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
837 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
838 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
839 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
843 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
847 /* write r0 to bank. Trashes r1. */
848 static void tr_bank_write(int addr)
852 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
853 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
854 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
858 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
861 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
862 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
864 int modulo_shift = -1; /* unknown */
866 if (mod == 0) return;
868 if (!need_modulo || mod == 1) // +!
870 else if (need_modulo && (known_regb & KRREG_ST)) {
871 modulo_shift = known_regs.gr[SSP_ST].h & 7;
872 if (modulo_shift == 0) modulo_shift = 8;
875 if (modulo_shift == -1)
877 int reg = (r < 4) ? 8 : 9;
879 if (dirty_regb & KRREG_ST) {
880 // avoid flushing ARM flags
881 EOP_AND_IMM(1, 6, 0, 0x70);
882 EOP_SUB_IMM(1, 1, 0, 0x10);
883 EOP_AND_IMM(1, 1, 0, 0x70);
884 EOP_ADD_IMM(1, 1, 0, 0x10);
886 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
887 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
889 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
890 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
891 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
893 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
894 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
896 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
897 else EOP_ADD_REG2_LSL(reg,reg,3,2);
898 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
899 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
900 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
902 else if (known_regb & (1 << (r + 8)))
904 int modulo = (1 << modulo_shift) - 1;
906 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
907 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
911 int reg = (r < 4) ? 8 : 9;
912 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
913 EOP_MOV_REG_ROR(reg,reg,ror);
914 // {add|sub} reg, reg, #1<<shift
915 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
916 EOP_MOV_REG_ROR(reg,reg,32-ror);
920 /* handle writes r0 to (rX). Trashes r1.
921 * fortunately we can ignore modulo increment modes for writes. */
922 static void tr_rX_write(int op)
926 int mod = (op>>2) & 3; // direct addressing
927 tr_bank_write((op & 0x100) + mod);
931 int r = (op&3) | ((op>>6)&4);
932 if (known_regb & (1 << (r + 8))) {
933 tr_bank_write((op&0x100) | known_regs.r[r]);
935 int reg = (r < 4) ? 8 : 9;
936 int ror = ((4 - (r&3))*8) & 0x1f;
937 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
939 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
940 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
941 else EOP_ADD_REG_LSL(1,7,1,1);
942 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
945 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
949 /* read (rX) to r0. Trashes r1-r3. */
950 static void tr_rX_read(int r, int mod)
954 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
958 if (known_regb & (1 << (r + 8))) {
959 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
961 int reg = (r < 4) ? 8 : 9;
962 int ror = ((4 - (r&3))*8) & 0x1f;
963 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
965 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
966 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
967 else EOP_ADD_REG_LSL(1,7,1,1);
968 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
969 hostreg_r[0] = hostreg_r[1] = -1;
971 tr_ptrr_mod(r, mod, 1, 1);
975 /* read ((rX)) to r0. Trashes r1,r2. */
976 static void tr_rX_read2(int op)
978 int r = (op&3) | ((op>>6)&4); // src
981 tr_bank_read((op&0x100) | ((op>>2)&3));
982 } else if (known_regb & (1 << (r+8))) {
983 tr_bank_read((op&0x100) | known_regs.r[r]);
985 int reg = (r < 4) ? 8 : 9;
986 int ror = ((4 - (r&3))*8) & 0x1f;
987 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
989 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
990 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
991 else EOP_ADD_REG_LSL(1,7,1,1);
992 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
994 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
995 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
996 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
998 tr_bank_write((op&0x100) | ((op>>2)&3));
999 } else if (known_regb & (1 << (r+8))) {
1000 tr_bank_write((op&0x100) | known_regs.r[r]);
1002 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1005 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
1006 hostreg_r[0] = hostreg_r[2] = -1;
1009 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
1010 static int tr_cond_check(int op)
1012 int f = (op & 0x100) >> 8;
1014 case 0x00: return A_COND_AL; /* always true */
1015 case 0x50: /* Z matches f(?) bit */
1016 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
1017 EOP_TST_IMM(6, 0, 4);
1018 return f ? A_COND_NE : A_COND_EQ;
1019 case 0x70: /* N matches f(?) bit */
1020 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
1021 EOP_TST_IMM(6, 0, 8);
1022 return f ? A_COND_NE : A_COND_EQ;
1024 printf("unimplemented cond?\n");
1030 static int tr_neg_cond(int cond)
1033 case A_COND_AL: printf("neg for AL?\n"); exit(1);
1034 case A_COND_EQ: return A_COND_NE;
1035 case A_COND_NE: return A_COND_EQ;
1036 case A_COND_MI: return A_COND_PL;
1037 case A_COND_PL: return A_COND_MI;
1038 default: printf("bad cond for neg\n"); exit(1);
1043 static int tr_aop_ssp2arm(int op)
1046 case 1: return A_OP_SUB;
1047 case 3: return A_OP_CMP;
1048 case 4: return A_OP_ADD;
1049 case 5: return A_OP_AND;
1050 case 6: return A_OP_ORR;
1051 case 7: return A_OP_EOR;
1058 // -----------------------------------------------------
1060 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
1061 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
1064 //@ r6: STACK and emu flags
1068 // read general reg to r0. Trashes r1
1069 static void tr_GR0_to_r0(int op)
1071 tr_mov16(0, 0xffff);
1074 static void tr_X_to_r0(int op)
1076 if (hostreg_r[0] != (SSP_X<<16)) {
1077 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
1078 hostreg_r[0] = SSP_X<<16;
1082 static void tr_Y_to_r0(int op)
1085 if (hostreg_r[0] != (SSP_Y<<16)) {
1086 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1087 hostreg_r[0] = SSP_Y<<16;
1091 static void tr_A_to_r0(int op)
1093 if (hostreg_r[0] != (SSP_A<<16)) {
1094 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1095 hostreg_r[0] = SSP_A<<16;
1099 static void tr_ST_to_r0(int op)
1101 // VR doesn't need much accuracy here..
1102 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1103 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1107 static void tr_STACK_to_r0(int op)
1110 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1111 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1112 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1113 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1114 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1115 hostreg_r[0] = hostreg_r[1] = -1;
1118 static void tr_PC_to_r0(int op)
1120 tr_mov16(0, known_regs.gr[SSP_PC].h);
1123 static void tr_P_to_r0(int op)
1126 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1130 static void tr_AL_to_r0(int op)
1133 if (known_regb & KRREG_PMC) {
1134 known_regs.emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1136 EOP_LDR_IMM(0,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1137 EOP_BIC_IMM(0,0,0,SSP_PMC_SET|SSP_PMC_HAVE_ADDR);
1138 EOP_STR_IMM(0,7,0x484);
1142 if (hostreg_r[0] != (SSP_AL<<16)) {
1143 EOP_MOV_REG_SIMPLE(0, 5); // mov r0, r5
1144 hostreg_r[0] = SSP_AL<<16;
1148 static void tr_PMX_to_r0(int reg)
1150 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1152 known_regs.pmac_read[reg] = known_regs.pmc.v;
1153 known_regs.emu_status &= ~SSP_PMC_SET;
1154 known_regb |= 1 << (20+reg);
1155 dirty_regb |= 1 << (20+reg);
1159 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (20+reg))))
1161 u32 pmcv = known_regs.pmac_read[reg];
1162 int mode = pmcv>>16;
1163 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1165 if ((mode & 0xfff0) == 0x0800)
1167 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1168 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1169 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1170 known_regs.pmac_read[reg] += 1;
1172 else if ((mode & 0x47ff) == 0x0018) // DRAM
1174 int inc = get_inc(mode);
1175 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1176 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1177 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1178 if (reg == 4 && (pmcv == 0x187f03 || pmcv == 0x187f04)) // wait loop detection
1180 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1181 tr_flush_dirty_ST();
1182 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1183 EOP_TST_REG_SIMPLE(0,0);
1184 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1185 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orreq r1, r1, #SSP_WAIT_30FE08
1186 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1188 known_regs.pmac_read[reg] += inc;
1194 known_regs.pmc.v = known_regs.pmac_read[reg];
1195 //known_regb |= KRREG_PMC;
1196 dirty_regb |= KRREG_PMC;
1197 dirty_regb |= 1 << (20+reg);
1198 hostreg_r[0] = hostreg_r[1] = -1;
1202 known_regb &= ~KRREG_PMC;
1203 dirty_regb &= ~KRREG_PMC;
1204 known_regb &= ~(1 << (20+reg));
1205 dirty_regb &= ~(1 << (20+reg));
1207 // call the C code to handle this
1208 tr_flush_dirty_ST();
1209 //tr_flush_dirty_pmcrs();
1211 emit_call(ssp_pm_read);
1215 static void tr_PM0_to_r0(int op)
1220 static void tr_PM1_to_r0(int op)
1225 static void tr_PM2_to_r0(int op)
1230 static void tr_XST_to_r0(int op)
1232 EOP_ADD_IMM(0, 7, 24/2, 4); // add r0, r7, #0x400
1233 EOP_LDRH_IMM(0, 0, SSP_XST*4+2);
1236 static void tr_PM4_to_r0(int op)
1241 static void tr_PMC_to_r0(int op)
1243 if (known_regb & KRREG_PMC)
1245 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1246 known_regs.emu_status |= SSP_PMC_SET;
1247 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1248 // do nothing - this is handled elsewhere
1250 tr_mov16(0, known_regs.pmc.l);
1251 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1256 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1257 tr_flush_dirty_ST();
1259 EOP_LDR_IMM(0, 7, 0x400+SSP_PMC*4);
1260 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1261 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1262 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1263 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1264 EOP_STR_IMM(1,7,0x484);
1265 hostreg_r[0] = hostreg_r[1] = -1;
1270 typedef void (tr_read_func)(int op);
1272 static tr_read_func *tr_read_funcs[16] =
1287 (tr_read_func *)tr_unhandled,
1293 // write r0 to general reg handlers. Trashes r1
1294 #define TR_WRITE_R0_TO_REG(reg) \
1296 hostreg_sspreg_changed(reg); \
1297 hostreg_r[0] = (reg)<<16; \
1298 if (const_val != -1) { \
1299 known_regs.gr[reg].h = const_val; \
1300 known_regb |= 1 << (reg); \
1302 known_regb &= ~(1 << (reg)); \
1306 static void tr_r0_to_GR0(int const_val)
1311 static void tr_r0_to_X(int const_val)
1313 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1314 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1315 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1316 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1317 TR_WRITE_R0_TO_REG(SSP_X);
1320 static void tr_r0_to_Y(int const_val)
1322 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1323 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1324 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
1325 dirty_regb |= KRREG_P;
1326 TR_WRITE_R0_TO_REG(SSP_Y);
1329 static void tr_r0_to_A(int const_val)
1331 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1332 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1333 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1334 TR_WRITE_R0_TO_REG(SSP_A);
1337 static void tr_r0_to_ST(int const_val)
1339 // VR doesn't need much accuracy here..
1340 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1341 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1342 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1343 TR_WRITE_R0_TO_REG(SSP_ST);
1345 dirty_regb &= ~KRREG_ST;
1348 static void tr_r0_to_STACK(int const_val)
1351 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1352 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1353 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1354 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1355 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1359 static void tr_r0_to_PC(int const_val)
1361 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1362 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1366 static void tr_r0_to_AL(int const_val)
1368 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16
1369 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1370 EOP_MOV_REG_ROR(5, 5, 16); // mov r5, r5, ror #16
1371 hostreg_sspreg_changed(SSP_AL);
1372 if (const_val != -1) {
1373 known_regs.gr[SSP_A].l = const_val;
1374 known_regb |= 1 << SSP_AL;
1376 known_regb &= ~(1 << SSP_AL);
1379 static void tr_r0_to_PMX(int reg)
1382 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1384 known_regs.pmac_write[reg] = known_regs.pmc.v;
1385 known_regs.emu_status &= ~SSP_PMC_SET;
1386 known_regb |= 1 << (25+reg);
1387 dirty_regb |= 1 << (25+reg);
1392 if ((known_regb & KRREG_PMC) && (known_regb & (1 << (25+reg))))
1396 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1398 mode = known_regs.pmac_write[reg]>>16;
1399 addr = known_regs.pmac_write[reg]&0xffff;
1400 if ((mode & 0x43ff) == 0x0018) // DRAM
1402 int inc = get_inc(mode);
1403 if (mode & 0x0400) tr_unhandled();
1404 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1405 emit_mov_const(A_COND_AL, 2, addr<<1);
1406 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1407 known_regs.pmac_write[reg] += inc;
1409 else if ((mode & 0xfbff) == 0x4018) // DRAM, cell inc
1411 if (mode & 0x0400) tr_unhandled();
1412 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1413 emit_mov_const(A_COND_AL, 2, addr<<1);
1414 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1415 known_regs.pmac_write[reg] += (addr&1) ? 31 : 1;
1417 else if ((mode & 0x47ff) == 0x001c) // IRAM
1419 int inc = get_inc(mode);
1420 EOP_LDR_IMM(1,7,0x48c); // iram_ptr
1421 emit_mov_const(A_COND_AL, 2, (addr&0x3ff)<<1);
1422 EOP_STRH_REG(0,1,2); // strh r0, [r1, r2]
1423 known_regs.pmac_write[reg] += inc;
1428 known_regs.pmc.v = known_regs.pmac_write[reg];
1429 //known_regb |= KRREG_PMC;
1430 dirty_regb |= KRREG_PMC;
1431 dirty_regb |= 1 << (25+reg);
1432 hostreg_r[1] = hostreg_r[2] = -1;
1435 known_regb &= ~KRREG_PMC;
1436 dirty_regb &= ~KRREG_PMC;
1437 known_regb &= ~(1 << (25+reg));
1438 dirty_regb &= ~(1 << (25+reg));
1440 EOP_MOV_REG_SIMPLE(3,0);
1441 tr_flush_dirty_pmcrs();
1442 EOP_MOV_REG_SIMPLE(0,3);
1444 known_regb &= ~KRREG_PMC;
1445 dirty_regb &= ~KRREG_PMC;
1446 known_regb &= ~(1 << (25+reg));
1447 dirty_regb &= ~(1 << (25+reg));
1450 // call the C code to handle this
1451 tr_flush_dirty_ST();
1452 //tr_flush_dirty_pmcrs();
1454 emit_call(ssp_pm_write);
1458 static void tr_r0_to_PM0(int const_val)
1463 static void tr_r0_to_PM1(int const_val)
1468 static void tr_r0_to_PM2(int const_val)
1473 static void tr_r0_to_PM4(int const_val)
1478 static void tr_r0_to_PMC(int const_val)
1480 if ((known_regb & KRREG_PMC) && const_val != -1)
1482 if (known_regs.emu_status & SSP_PMC_HAVE_ADDR) {
1483 known_regs.emu_status |= SSP_PMC_SET;
1484 known_regs.emu_status &= ~SSP_PMC_HAVE_ADDR;
1485 known_regs.pmc.h = const_val;
1487 known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
1488 known_regs.pmc.l = const_val;
1493 tr_flush_dirty_ST();
1494 if (known_regb & KRREG_PMC) {
1495 emit_mov_const(A_COND_AL, 1, known_regs.pmc.v);
1496 EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
1497 known_regb &= ~KRREG_PMC;
1498 dirty_regb &= ~KRREG_PMC;
1500 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1501 EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
1502 EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
1503 EOP_C_AM3_IMM(A_COND_EQ,1,0,2,0,0,1,SSP_PMC*4); // strxx r0, [r2, #SSP_PMC]
1504 EOP_C_AM3_IMM(A_COND_NE,1,0,2,0,0,1,SSP_PMC*4+2);
1505 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // orreq r1, r1, #..
1506 EOP_C_DOP_IMM(A_COND_NE,A_OP_BIC,0, 1, 1, 0, SSP_PMC_HAVE_ADDR); // bicne r1, r1, #..
1507 EOP_C_DOP_IMM(A_COND_NE,A_OP_ORR,0, 1, 1, 0, SSP_PMC_SET); // orrne r1, r1, #..
1508 EOP_STR_IMM(1,7,0x484);
1509 hostreg_r[1] = hostreg_r[2] = -1;
1513 typedef void (tr_write_func)(int const_val);
1515 static tr_write_func *tr_write_funcs[16] =
1524 (tr_write_func *)tr_unhandled,
1528 (tr_write_func *)tr_unhandled,
1530 (tr_write_func *)tr_unhandled,
1535 static void tr_mac_load_XY(int op)
1537 tr_rX_read(op&3, (op>>2)&3); // X
1538 EOP_MOV_REG_LSL(4, 0, 16);
1539 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1540 EOP_ORR_REG_SIMPLE(4, 0);
1541 dirty_regb |= KRREG_P;
1542 hostreg_sspreg_changed(SSP_X);
1543 hostreg_sspreg_changed(SSP_Y);
1544 known_regb &= ~KRREG_X;
1545 known_regb &= ~KRREG_Y;
1548 // -----------------------------------------------------
1550 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1553 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1559 pmcv = imm | (PROGRAM((*pc)++) << 16);
1560 known_regs.pmc.v = pmcv;
1561 known_regb |= KRREG_PMC;
1562 dirty_regb |= KRREG_PMC;
1563 known_regs.emu_status |= SSP_PMC_SET;
1565 // check for possible reg programming
1566 tmpv = PROGRAM(*pc);
1567 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1569 int is_write = (tmpv & 0xff8f) == 0x80;
1570 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1571 if (reg > 4) tr_unhandled();
1572 if ((tmpv & 0x0f) != 0 && (tmpv & 0xf0) != 0) tr_unhandled();
1573 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1574 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1575 dirty_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1576 known_regs.emu_status &= ~SSP_PMC_SET;
1585 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1587 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1594 if (op != 0x0840 || imm != 0) return 0;
1595 pp = PROGRAM_P(*pc);
1596 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1598 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1599 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1600 hostreg_sspreg_changed(SSP_ST);
1601 known_regs.gr[SSP_ST].h = 0x60;
1602 known_regb |= 1 << SSP_ST;
1603 dirty_regb &= ~KRREG_ST;
1608 static int tr_detect_rotate(unsigned int op, int *pc, int imm)
1614 if (op != 0x02e3 || PROGRAM(*pc) != 0x04e3 || PROGRAM(*pc + 1) != 0x000f) return 0;
1617 EOP_MOV_REG_LSL(0, 0, 4);
1618 EOP_ORR_REG_LSR(0, 0, 0, 16);
1624 // -----------------------------------------------------
1626 static int translate_op(unsigned int op, int *pc, int imm)
1628 u32 tmpv, tmpv2, tmpv3;
1630 known_regs.gr[SSP_PC].h = *pc;
1636 if (op == 0) { ret++; break; } // nop
1637 tmpv = op & 0xf; // src
1638 tmpv2 = (op >> 4) & 0xf; // dst
1639 if (tmpv2 >= 8) return -1; // TODO
1640 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1642 EOP_MOV_REG_SIMPLE(5, 10);
1643 hostreg_sspreg_changed(SSP_A);
1644 known_regb &= ~(KRREG_A|KRREG_AL);
1647 tr_read_funcs[tmpv](op);
1648 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1649 if (tmpv2 == SSP_PC) ret |= 0x10000;
1654 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1655 int r = (op&3) | ((op>>6)&4);
1656 int mod = (op>>2)&3;
1657 tmpv = (op >> 4) & 0xf; // dst
1658 ret = tr_detect_rotate(op, pc, imm);
1660 if (tmpv >= 8) return -1; // TODO
1663 else tr_ptrr_mod(r, mod, 1, 1);
1664 tr_write_funcs[tmpv](-1);
1665 if (tmpv == SSP_PC) ret |= 0x10000;
1671 tmpv = (op >> 4) & 0xf; // src
1672 tr_read_funcs[tmpv](op);
1678 tr_bank_read(op&0x1ff);
1684 tmpv = (op & 0xf0) >> 4; // dst
1685 ret = tr_detect_pm0_block(op, pc, imm);
1690 tr_write_funcs[tmpv](imm);
1693 ret = tr_detect_set_pm(op, pc, imm);
1695 if (tmpv == SSP_PC) ret |= 0x10000;
1696 return -1; /* TODO.. */
1700 tmpv2 = (op >> 4) & 0xf; // dst
1701 if (tmpv2 >= 8) return -1; // TODO
1703 tr_write_funcs[tmpv2](-1);
1704 if (tmpv2 == SSP_PC) ret |= 0x10000;
1716 tr_bank_write(op&0x1ff);
1722 r = (op&3) | ((op>>6)&4); // src
1723 tmpv2 = (op >> 4) & 0xf; // dst
1724 if (tmpv2 >= 8) tr_unhandled();
1725 if ((r&3) == 3) tr_unhandled();
1727 if (known_regb & (1 << (r+8))) {
1728 tr_mov16(0, known_regs.r[r]);
1729 tr_write_funcs[tmpv2](known_regs.r[r]);
1731 int reg = (r < 4) ? 8 : 9;
1732 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1733 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1735 tr_write_funcs[tmpv2](-1);
1743 r = (op&3) | ((op>>6)&4); // dst
1744 tmpv = (op >> 4) & 0xf; // src
1745 if ((r&3) == 3) tr_unhandled();
1747 if (known_regb & (1 << tmpv)) {
1748 known_regs.r[r] = known_regs.gr[tmpv].h;
1749 known_regb |= 1 << (r + 8);
1750 dirty_regb |= 1 << (r + 8);
1752 int reg = (r < 4) ? 8 : 9;
1753 int ror = ((4 - (r&3))*8) & 0x1f;
1754 tr_read_funcs[tmpv](op);
1755 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1756 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1757 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1759 known_regb &= ~(1 << (r+8));
1760 dirty_regb &= ~(1 << (r+8));
1768 known_regs.r[tmpv] = op;
1769 known_regb |= 1 << (tmpv + 8);
1770 dirty_regb |= 1 << (tmpv + 8);
1775 u32 *jump_op = NULL;
1776 tmpv = tr_cond_check(op);
1777 if (tmpv != A_COND_AL) {
1778 jump_op = tcache_ptr;
1779 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1782 tr_r0_to_STACK(*pc);
1783 if (tmpv != A_COND_AL) {
1784 u32 *real_ptr = tcache_ptr;
1785 tcache_ptr = jump_op;
1786 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1787 tcache_ptr = real_ptr;
1789 tr_mov16_cond(tmpv, 0, imm);
1790 if (tmpv != A_COND_AL) {
1791 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1793 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1800 tmpv2 = (op >> 4) & 0xf; // dst
1801 if (tmpv2 >= 8) return -1; // TODO
1804 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1805 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1806 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1807 hostreg_r[0] = hostreg_r[1] = -1;
1808 tr_write_funcs[tmpv2](-1);
1809 if (tmpv2 == SSP_PC) ret |= 0x10000;
1814 tmpv = tr_cond_check(op);
1815 tr_mov16_cond(tmpv, 0, imm);
1816 if (tmpv != A_COND_AL) {
1817 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1819 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1825 // check for repeats of this op
1827 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1830 if ((op&0xf0) != 0) // !always
1833 tmpv2 = tr_cond_check(op);
1835 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1836 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1837 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1838 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
1839 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1840 hostreg_r[1] = -1; break; // abs
1841 default: tr_unhandled();
1844 hostreg_sspreg_changed(SSP_A);
1845 dirty_regb |= KRREG_ST;
1846 known_regb &= ~KRREG_ST;
1847 known_regb &= ~(KRREG_A|KRREG_AL);
1856 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1857 hostreg_sspreg_changed(SSP_A);
1858 known_regb &= ~(KRREG_A|KRREG_AL);
1859 dirty_regb |= KRREG_ST;
1862 // mpya (rj), (ri), b
1867 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1868 hostreg_sspreg_changed(SSP_A);
1869 known_regb &= ~(KRREG_A|KRREG_AL);
1870 dirty_regb |= KRREG_ST;
1873 // mld (rj), (ri), b
1875 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1876 hostreg_sspreg_changed(SSP_A);
1877 known_regs.gr[SSP_A].v = 0;
1878 known_regb |= (KRREG_A|KRREG_AL);
1879 dirty_regb |= KRREG_ST;
1890 tmpv = op & 0xf; // src
1891 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1892 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1893 if (tmpv == SSP_P) {
1895 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1896 } else if (tmpv == SSP_A) {
1897 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1899 tr_read_funcs[tmpv](op);
1900 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1902 hostreg_sspreg_changed(SSP_A);
1903 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1904 dirty_regb |= KRREG_ST;
1914 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1915 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1916 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1917 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1918 hostreg_sspreg_changed(SSP_A);
1919 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1920 dirty_regb |= KRREG_ST;
1930 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1931 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1932 tr_bank_read(op&0x1ff);
1933 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1934 hostreg_sspreg_changed(SSP_A);
1935 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1936 dirty_regb |= KRREG_ST;
1946 tmpv = (op & 0xf0) >> 4;
1947 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1948 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1950 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1951 hostreg_sspreg_changed(SSP_A);
1952 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1953 dirty_regb |= KRREG_ST;
1963 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1964 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1966 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1967 hostreg_sspreg_changed(SSP_A);
1968 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1969 dirty_regb |= KRREG_ST;
1980 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1981 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1982 r = (op&3) | ((op>>6)&4); // src
1983 if ((r&3) == 3) tr_unhandled();
1985 if (known_regb & (1 << (r+8))) {
1986 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1988 int reg = (r < 4) ? 8 : 9;
1989 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1990 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1991 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1994 hostreg_sspreg_changed(SSP_A);
1995 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1996 dirty_regb |= KRREG_ST;
2007 tmpv2 = tr_aop_ssp2arm(op>>13); // op
2008 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
2009 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
2010 hostreg_sspreg_changed(SSP_A);
2011 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
2012 dirty_regb |= KRREG_ST;
2019 static void *translate_block(int pc)
2021 unsigned int op, op1, imm, ccount = 0;
2022 unsigned int *block_start;
2023 int ret, ret_prev = -1, tpc;
2026 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
2028 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
2029 block_start = tcache_ptr;
2031 dirty_regb = KRREG_P;
2032 known_regs.emu_status = 0;
2035 emit_block_prologue();
2037 for (; ccount < 100;)
2039 //printf(" insn #%i\n", icount);
2044 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
2045 imm = PROGRAM(pc++); // immediate
2048 ret = translate_op(op, &pc, imm);
2051 tr_flush_dirty_prs();
2052 tr_flush_dirty_ST();
2053 tr_flush_dirty_pmcrs();
2054 known_regs.emu_status = 0;
2056 emit_mov_const(A_COND_AL, 0, op);
2060 emit_mov_const(A_COND_AL, 1, imm);
2065 if (ret_prev > 0) emit_call(regfile_store);
2066 emit_call(in_funcs[op1]);
2067 emit_call(regfile_load);
2069 if (in_funcs[op1] == NULL) {
2070 printf("NULL func! op=%08x (%02x)\n", op, op1);
2075 dirty_regb |= KRREG_P;
2080 ccount += ret & 0xffff;
2081 if (ret & 0x10000) break;
2087 tr_flush_dirty_prs();
2088 tr_flush_dirty_ST();
2089 tr_flush_dirty_pmcrs();
2090 emit_block_epilogue(ccount + 1);
2091 *tcache_ptr++ = 0xffffffff; // end of block
2092 //printf(" %i inst\n", icount);
2094 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
2095 printf("tcache overflow!\n");
2103 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
2104 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
2108 FILE *f = fopen("tcache.bin", "wb");
2109 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
2122 // -----------------------------------------------------
2124 int ssp1601_dyn_startup(void)
2126 memset(tcache, 0, TCACHE_SIZE);
2127 memset(block_table, 0, sizeof(block_table));
2128 memset(block_table_iram, 0, sizeof(block_table_iram));
2129 tcache_ptr = tcache;
2130 *tcache_ptr++ = 0xffffffff;
2134 block_table[0x400] = (void *) ssp_hle_800;
2139 static unsigned short dummy = 0;
2146 void ssp1601_dyn_reset(ssp1601_t *ssp)
2148 ssp1601_reset_local(ssp);
2149 ssp->ptr_rom = (unsigned int) Pico.rom;
2150 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
2151 ssp->ptr_dram = (unsigned int) svp->dram;
2154 void ssp1601_dyn_run(int cycles)
2156 if (ssp->emu_status & SSP_WAIT_MASK) return;
2157 //{ printf("%i wait\n", Pico.m.frame_count); return; }
2158 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
2161 rPC = DUMP_BLOCK >> 1;
2165 int (*trans_entry)(void);
2169 iram_context = get_iram_context();
2172 if (block_table_iram[iram_context][rPC] == NULL)
2173 block_table_iram[iram_context][rPC] = translate_block(rPC);
2174 trans_entry = (void *) block_table_iram[iram_context][rPC];
2178 if (block_table[rPC] == NULL)
2179 block_table[rPC] = translate_block(rPC);
2180 trans_entry = (void *) block_table[rPC];
2183 //printf("enter %04x\n", rPC<<1);
2184 cycles -= trans_entry();
2185 //printf("leave %04x\n", rPC<<1);
2187 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);