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 0x240a
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,
493 // -----------------------------------------------------
495 static unsigned char iram_context_map[] =
497 0, 0, 0, 0, 1, 0, 0, 0, // 04
498 0, 0, 0, 0, 0, 0, 2, 0, // 0e
499 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
500 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
501 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
502 0, 0, 0, 0, 0, 0, 0, 0,
503 0, 0,11, 0, 0,12, 0, 0, // 32 35
504 13,14, 0, 0, 0, 0, 0, 0 // 38 39
507 static int get_iram_context(void)
509 unsigned char *ir = (unsigned char *)svp->iram_rom;
510 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
511 val1 = iram_context_map[(val>>1)&0x3f];
514 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
515 //debug_dump2file(name, svp->iram_rom, 0x800);
518 // elprintf(EL_ANOMALY, "iram_context: %02i", val1);
522 // -----------------------------------------------------
525 SSP_GR0, SSP_X, SSP_Y, SSP_A,
526 SSP_ST, SSP_STACK, SSP_PC, SSP_P,
527 SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
528 SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
531 /* regs with known values */
538 #define KRREG_X (1 << SSP_X)
539 #define KRREG_Y (1 << SSP_Y)
540 #define KRREG_A (1 << SSP_A) /* AH only */
541 #define KRREG_ST (1 << SSP_ST)
542 #define KRREG_STACK (1 << SSP_STACK)
543 #define KRREG_PC (1 << SSP_PC)
544 #define KRREG_P (1 << SSP_P)
545 #define KRREG_PR0 (1 << 8)
546 #define KRREG_PR4 (1 << 12)
547 #define KRREG_AL (1 << 16)
549 /* bitfield of known register values */
550 static u32 known_regb = 0;
552 /* known vals, which need to be flushed
553 * (only ST, P, r0-r7)
554 * ST means flags are being held in ARM PSR
556 static u32 dirty_regb = 0;
558 /* known values of host regs.
560 * 000000-00ffff - 16bit value
561 * 100000-10ffff - base reg (r7) + 16bit val
562 * 0r0000 - means reg (low) eq gr[r].h
564 static int hostreg_r[4];
566 static void hostreg_clear(void)
569 for (i = 0; i < 4; i++)
574 /*static*/ void hostreg_ah_changed(void)
577 for (i = 0; i < 4; i++)
578 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
582 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
584 /* update P, if needed. Trashes r1 */
585 static void tr_flush_dirty_P(void)
588 if (!(dirty_regb & KRREG_P)) return;
589 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
590 EOP_MOV_REG_LSL( 1, 4, 16); // mov r1, r4, lsl #16
591 EOP_MOV_REG_ASR( 1, 1, 15); // mov r1, r1, asr #15
592 EOP_MUL(10, 1, 10); // mul r10, r1, r10
593 dirty_regb &= ~KRREG_P;
596 /* write dirty r0-r7 to host regs. Nothing is trashed */
597 static void tr_flush_dirty_pr(void)
600 int dirty = dirty_regb >> 8;
602 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
604 if (!(dirty&1)) continue;
606 case 0: ror = 0; break;
607 case 1: ror = 24/2; break;
608 case 2: ror = 16/2; break;
610 reg = (i < 4) ? 8 : 9;
611 EOP_BIC_IMM(reg,reg,ror,0xff);
612 if (known_regs.r[i] != 0)
613 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
615 dirty_regb &= ~0xff00;
618 /* fush ARM PSR to r6. Trashes r0 */
619 static void tr_flush_dirty_ST(void)
621 if (!(dirty_regb & KRREG_ST)) return;
622 EOP_BIC_IMM(6,6,0,0x0f);
624 EOP_ORR_REG_LSR(6,6,0,28);
625 dirty_regb &= ~KRREG_ST;
629 /* load 16bit val into host reg r0-r3. Nothing is trashed */
630 static void tr_mov16(int r, int val)
632 if (hostreg_r[r] != val) {
633 emit_mov_const(A_COND_AL, r, val);
638 static void tr_mov16_cond(int cond, int r, int val)
640 emit_mov_const(cond, r, val);
644 /* read bank word to r0. Thrashes r1. */
645 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
649 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
650 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
651 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
655 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
659 /* write r0 to bank. Trashes r1. */
660 static void tr_bank_write(int addr)
664 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
665 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
666 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
670 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
673 /* handle RAM bank pointer modifiers. Nothing is trashed. */
674 static void tr_ptrr_mod(int r, int mod, int need_modulo)
676 int modulo_shift = -1; /* unknown */
678 if (mod == 0) return;
680 if (!need_modulo || mod == 1) // +!
682 else if (need_modulo && (known_regb & KRREG_ST)) {
683 modulo_shift = known_regs.gr[SSP_ST].h & 7;
684 if (modulo_shift == 0) modulo_shift = 8;
687 if (mod > 1 && modulo_shift == -1) {
689 int reg = (r < 4) ? 8 : 9;
690 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
691 EOP_MOV_REG_ROR(reg,reg,ror);
692 // {add|sub} reg, reg, #1<<shift
693 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
694 EOP_MOV_REG_ROR(reg,reg,32-ror);
697 printf("need var modulo\n"); exit(1);
699 else if (known_regb & (1 << (r + 8)))
701 int modulo = (1 << modulo_shift) - 1;
703 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - 1) & modulo);
704 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + 1) & modulo);
708 int reg = (r < 4) ? 8 : 9;
709 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
710 EOP_MOV_REG_ROR(reg,reg,ror);
711 // {add|sub} reg, reg, #1<<shift
712 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
713 EOP_MOV_REG_ROR(reg,reg,32-ror);
717 /* handle writes r0 to (rX). Trashes r1.
718 * fortunately we can ignore modulo increment modes for writes. */
719 static void tr_rX_write1(int op)
723 int mod = (op>>2) & 3; // direct addressing
724 tr_bank_write((op & 0x100) + mod);
728 int r = (op&3) | ((op>>6)&4);
729 if (known_regb & (1 << (r + 8))) {
730 tr_bank_write((op&0x100) | known_regs.r[r]);
732 int reg = (r < 4) ? 8 : 9;
733 int ror = ((4 - (r&3))*8) & 0x1f;
734 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
736 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
737 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
738 else EOP_ADD_REG_LSL(1,7,1,1);
739 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
742 tr_ptrr_mod(r, (op>>2) & 3, 0);
746 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
747 static int tr_cond_check(int op)
751 case 0x00: return A_COND_AL; /* always true */
752 case 0x50: /* Z matches f(?) bit */
753 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
754 EOP_TST_IMM(6, 0, 4);
755 return f ? A_COND_NE : A_COND_EQ;
756 case 0x70: /* N matches f(?) bit */
757 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
758 EOP_TST_IMM(6, 0, 8);
759 return f ? A_COND_NE : A_COND_EQ;
761 printf("unimplemented cond?\n");
767 static int tr_neg_cond(int cond)
770 case A_COND_AL: printf("neg for AL?\n"); exit(1);
771 case A_COND_EQ: return A_COND_NE;
772 case A_COND_NE: return A_COND_EQ;
773 case A_COND_MI: return A_COND_PL;
774 case A_COND_PL: return A_COND_MI;
775 default: printf("bad cond for neg\n"); exit(1);
780 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
781 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
784 //@ r6: STACK and emu flags
788 // read general reg to r0. Trashes r1
789 static void tr_GR0_to_r0(void)
794 static void tr_X_to_r0(void)
796 if (hostreg_r[0] != (SSP_X<<16)) {
797 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
798 hostreg_r[0] = SSP_X<<16;
802 static void tr_Y_to_r0(void)
805 if (hostreg_r[0] != (SSP_Y<<16)) {
806 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
807 hostreg_r[0] = SSP_Y<<16;
811 static void tr_A_to_r0(void)
813 if (hostreg_r[0] != (SSP_A<<16)) {
814 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
815 hostreg_r[0] = SSP_A<<16;
819 static void tr_ST_to_r0(void)
821 // VR doesn't need much accuracy here..
822 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
823 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
827 static void tr_STACK_to_r0(void)
830 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
831 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
832 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
833 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
834 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
835 hostreg_r[0] = hostreg_r[1] = -1;
838 static void tr_PC_to_r0(void)
840 tr_mov16(0, known_regs.gr[SSP_PC].h);
843 static void tr_P_to_r0(void)
846 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
850 typedef void (tr_read_func)(void);
852 static tr_read_func *tr_read_funcs[8] =
865 // write r0 to general reg handlers. Trashes r1
866 static void tr_unhandled(void)
868 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
872 static void tr_r0_to_GR0(void)
877 static void tr_r0_to_X(void)
879 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
880 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
881 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
882 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
883 hostreg_r[0] = SSP_X<<16;
886 static void tr_r0_to_Y(void)
888 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
889 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
890 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
891 dirty_regb |= KRREG_P;
892 hostreg_r[0] = SSP_Y<<16;
895 static void tr_r0_to_A(void)
897 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
898 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
899 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
900 hostreg_r[0] = SSP_A<<16;
903 static void tr_r0_to_ST(void)
905 // VR doesn't need much accuracy here..
906 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
907 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
908 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
912 static void tr_r0_to_STACK(void)
915 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
916 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
917 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
918 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
919 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
923 static void tr_r0_to_PC(void)
925 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
926 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
930 typedef void (tr_write_func)(void);
932 static tr_write_func *tr_write_funcs[8] =
945 static int translate_op(unsigned int op, int *pc, int imm)
949 known_regs.gr[SSP_PC].h = *pc;
955 if (op == 0) { ret++; break; } // nop
956 tmpv = op & 0xf; // src
957 tmpv2 = (op >> 4) & 0xf; // dst
958 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
959 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
961 EOP_MOV_REG_SIMPLE(5, 10);
962 known_regb &= ~(KRREG_A|KRREG_AL);
965 tr_read_funcs[tmpv]();
966 tr_write_funcs[tmpv2]();
967 if (known_regb & (1 << tmpv)) {
968 known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h;
969 known_regb |= 1 << tmpv2;
971 known_regb &= ~(1 << tmpv2);
975 //case 0x01: tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
979 tmpv = (op >> 4) & 0xf; // src
980 if (tmpv >= 8) return -1; // TODO
981 tr_read_funcs[tmpv]();
987 tr_bank_read(op&0x1ff);
989 known_regb &= ~KRREG_A;
990 hostreg_r[0] = SSP_A<<16;
995 tmpv = (op & 0xf0) >> 4;
999 tr_write_funcs[tmpv]();
1000 known_regs.gr[tmpv].h = imm;
1001 known_regb |= 1 << tmpv;
1004 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1006 // programming PMC..
1008 tmpv = imm | (PROGRAM((*pc)++) << 16);
1010 emit_mov_const(A_COND_AL, 0, tmpv);
1011 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
1012 EOP_STR_IMM(0,7,0x400+14*4); // PMC
1013 // reads on fe06, fe08; next op is ld -,
1014 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1016 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1017 tr_flush_dirty_ST();
1018 EOP_LDR_IMM(0,7,0x490); // dram_ptr
1019 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
1020 EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8]
1021 EOP_TST_REG_SIMPLE(0,0);
1022 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1023 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1025 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
1026 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1027 hostreg_r[0] = hostreg_r[1] = -1;
1031 return -1; /* TODO.. */
1036 r = (op&3) | ((op>>6)&4); // src
1037 tmpv2 = (op >> 4) & 0xf; // dst
1038 if (tmpv2 >= 8) return -1; // TODO
1041 tr_bank_read((op&0x100) | ((op>>2)&3));
1042 } else if (known_regb & (1 << (r+8))) {
1043 tr_bank_read((op&0x100) | known_regs.r[r]);
1045 int reg = (r < 4) ? 8 : 9;
1046 int ror = ((4 - (r&3))*8) & 0x1f;
1047 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
1049 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
1050 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
1051 else EOP_ADD_REG_LSL(1,7,1,1);
1052 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
1054 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
1055 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
1056 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
1058 tr_bank_write((op&0x100) | ((op>>2)&3));
1059 } else if (known_regb & (1 << (r+8))) {
1060 tr_bank_write((op&0x100) | known_regs.r[r]);
1062 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1065 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r0]
1066 hostreg_r[0] = hostreg_r[2] = -1;
1067 known_regb &= ~(1 << tmpv2);
1068 tr_write_funcs[tmpv2]();
1069 ret += 3; break; /* should certainly take > 1 */
1080 if (hostreg_r[0] != (SSP_A<<16)) {
1081 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
1082 hostreg_r[0] = SSP_A<<16;
1084 tr_bank_write(op&0x1ff);
1090 r = (op&3) | ((op>>6)&4); // src
1091 tmpv2 = (op >> 4) & 0xf; // dst
1092 if (tmpv2 >= 8) tr_unhandled();
1093 if ((r&3) == 3) tr_unhandled();
1095 if (known_regb & (1 << (r+8))) {
1096 tr_mov16(0, known_regs.r[r]);
1097 known_regs.gr[tmpv2].h = known_regs.r[r];
1098 known_regb |= 1 << tmpv2;
1100 int reg = (r < 4) ? 8 : 9;
1101 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1102 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1104 known_regb &= ~(1 << tmpv2);
1106 tr_write_funcs[tmpv2]();
1113 r = (op&3) | ((op>>6)&4); // dst
1114 tmpv = (op >> 4) & 0xf; // src
1115 if (tmpv >= 8) tr_unhandled();
1116 if ((r&3) == 3) tr_unhandled();
1118 if (known_regb & (1 << tmpv)) {
1119 known_regs.r[r] = known_regs.gr[tmpv].h;
1120 known_regb |= 1 << (r + 8);
1121 dirty_regb |= 1 << (r + 8);
1123 int reg = (r < 4) ? 8 : 9;
1124 int ror = ((4 - (r&3))*8) & 0x1f;
1125 tr_read_funcs[tmpv]();
1126 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1127 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1128 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1130 known_regb &= ~(1 << (r+8));
1131 dirty_regb &= ~(1 << (r+8));
1139 known_regs.r[tmpv] = op;
1140 known_regb |= 1 << (tmpv + 8);
1141 dirty_regb |= 1 << (tmpv + 8);
1148 tmpv = tr_cond_check(op);
1149 tr_mov16_cond(tmpv, 0, imm);
1150 if (tmpv != A_COND_AL) {
1151 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1158 tmpv2 = (op >> 4) & 0xf; // dst
1159 if (tmpv2 >= 8) return -1; // TODO
1162 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1163 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1164 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1165 hostreg_r[0] = hostreg_r[1] = -1;
1166 known_regb &= ~(1 << tmpv2);
1167 tr_write_funcs[tmpv2]();
1172 tmpv = tr_cond_check(op);
1173 tr_mov16_cond(tmpv, 0, imm);
1174 if (tmpv != A_COND_AL) {
1175 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1184 read_P(); // update P
1185 rA32 -= rP.v; // maybe only upper word?
1186 UPD_ACC_ZN // there checking flags after this
1187 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1188 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1191 // mpya (rj), (ri), b
1193 read_P(); // update P
1194 rA32 += rP.v; // confirmed to be 32bit
1196 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1197 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1200 // mld (rj), (ri), b
1202 EOP_MOV_IMM(5, 0, 0); // mov r5, #0
1203 known_regs.r[SSP_A].v = 0;
1204 known_regb |= (KRREG_A|KRREG_AL);
1205 EOP_BIC_IMM(6, 6, 0, 0x0f); // bic r6, r6, 0xf // flags
1206 EOP_BIC_IMM(6, 6, 0, 0x04); // bic r6, r6, 4 // set Z
1215 static void *translate_block(int pc)
1217 unsigned int op, op1, imm, ccount = 0;
1218 unsigned int *block_start;
1219 int ret, ret_prev = -1;
1222 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
1224 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1225 block_start = tcache_ptr;
1227 dirty_regb = KRREG_P;
1230 emit_block_prologue();
1232 for (; ccount < 100;)
1234 //printf(" insn #%i\n", icount);
1239 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1240 imm = PROGRAM(pc++); // immediate
1242 ret = translate_op(op, &pc, imm);
1245 tr_flush_dirty_pr();
1247 emit_mov_const(A_COND_AL, 0, op);
1251 emit_mov_const(A_COND_AL, 1, imm);
1256 if (ret_prev > 0) emit_call(regfile_store);
1257 emit_call(in_funcs[op1]);
1258 emit_call(regfile_load);
1260 if (in_funcs[op1] == NULL) {
1261 printf("NULL func! op=%08x (%02x)\n", op, op1);
1266 dirty_regb |= KRREG_P;
1272 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1273 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1274 (op & 0xf0) == 0x60)) { // ld PC
1280 tr_flush_dirty_pr();
1281 emit_block_epilogue(ccount + 1);
1282 *tcache_ptr++ = 0xffffffff; // end of block
1283 //printf(" %i inst\n", icount);
1285 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1286 printf("tcache overflow!\n");
1294 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1295 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1299 FILE *f = fopen("tcache.bin", "wb");
1300 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1313 // -----------------------------------------------------
1315 int ssp1601_dyn_startup(void)
1317 memset(tcache, 0, TCACHE_SIZE);
1318 memset(block_table, 0, sizeof(block_table));
1319 memset(block_table_iram, 0, sizeof(block_table_iram));
1320 tcache_ptr = tcache;
1321 *tcache_ptr++ = 0xffffffff;
1327 void ssp1601_dyn_reset(ssp1601_t *ssp)
1329 ssp1601_reset_local(ssp);
1330 ssp->ptr_rom = (unsigned int) Pico.rom;
1331 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1332 ssp->ptr_dram = (unsigned int) svp->dram;
1335 void ssp1601_dyn_run(int cycles)
1337 if (ssp->emu_status & SSP_WAIT_MASK) return;
1338 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1339 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1342 rPC = DUMP_BLOCK >> 1;
1346 int (*trans_entry)(void);
1350 iram_context = get_iram_context();
1353 if (block_table_iram[iram_context][rPC] == NULL)
1354 block_table_iram[iram_context][rPC] = translate_block(rPC);
1355 trans_entry = (void *) block_table_iram[iram_context][rPC];
1359 if (block_table[rPC] == NULL)
1360 block_table[rPC] = translate_block(rPC);
1361 trans_entry = (void *) block_table[rPC];
1364 //printf("enter %04x\n", rPC<<1);
1365 cycles -= trans_entry();
1366 //printf("leave %04x\n", rPC<<1);
1368 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);