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 0x29a0
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);
643 /* read bank word to r0. Thrashes r1. */
644 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
648 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
649 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
650 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
654 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
658 /* write r0 to bank. Trashes r1. */
659 static void tr_bank_write(int addr)
663 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
664 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
665 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
669 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
672 /* handle RAM bank pointer modifiers. Nothing is trashed. */
673 static void tr_ptrr_mod(int r, int mod, int need_modulo)
675 int modulo = -1, modulo_shift = -1; /* unknown */
677 if (mod == 0) return;
679 if (!need_modulo || mod == 1) // +!
681 else if (need_modulo && (known_regb & KRREG_ST)) {
682 modulo_shift = known_regs.gr[SSP_ST].h & 7;
683 if (modulo_shift == 0) modulo_shift = 8;
686 if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
687 modulo = (1 << modulo_shift) - 1;
689 if (known_regb & (1 << (r + 8))) {
691 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - 1) & modulo);
692 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + 1) & modulo);
694 int reg = (r < 4) ? 8 : 9;
695 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
696 EOP_MOV_REG_ROR(reg,reg,ror);
697 // {add|sub} reg, reg, #1<<shift
698 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
699 EOP_MOV_REG_ROR(reg,reg,32-ror);
703 /* handle writes r0 to (rX). Trashes r1.
704 * fortunately we can ignore modulo increment modes for writes. */
705 static void tr_rX_write1(int op)
709 int mod = (op>>2) & 3; // direct addressing
710 tr_bank_write((op & 0x100) + mod);
714 int r = (op&3) | ((op>>6)&4);
715 if (known_regb & (1 << (r + 8))) {
716 tr_bank_write((op&0x100) | known_regs.r[r]);
718 int reg = (r < 4) ? 8 : 9;
719 int ror = ((4 - (r&3))*8) & 0x1f;
720 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
722 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
723 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
724 else EOP_ADD_REG_LSL(1,7,1,1);
725 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
728 tr_ptrr_mod(r, (op>>2) & 3, 0);
732 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
733 static int tr_cond_check(int op)
737 case 0x00: return A_COND_AL; /* always true */
738 case 0x50: /* Z matches f(?) bit */
739 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
740 EOP_TST_IMM(6, 0, 4);
741 return f ? A_COND_NE : A_COND_EQ;
742 case 0x70: /* N matches f(?) bit */
743 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
744 EOP_TST_IMM(6, 0, 8);
745 return f ? A_COND_NE : A_COND_EQ;
747 printf("unimplemented cond?\n");
753 static int tr_neg_cond(int cond)
756 case A_COND_AL: printf("neg for AL?\n"); exit(1);
757 case A_COND_EQ: return A_COND_NE;
758 case A_COND_NE: return A_COND_EQ;
759 case A_COND_MI: return A_COND_PL;
760 case A_COND_PL: return A_COND_MI;
761 default: printf("bad cond for neg\n"); exit(1);
766 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
767 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
770 //@ r6: STACK and emu flags
774 // read general reg to r0. Trashes r1
775 static void tr_GR0_to_r0(void)
780 static void tr_X_to_r0(void)
782 if (hostreg_r[0] != (SSP_X<<16)) {
783 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
784 hostreg_r[0] = SSP_X<<16;
788 static void tr_Y_to_r0(void)
791 if (hostreg_r[0] != (SSP_Y<<16)) {
792 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
793 hostreg_r[0] = SSP_Y<<16;
797 static void tr_A_to_r0(void)
799 if (hostreg_r[0] != (SSP_A<<16)) {
800 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
801 hostreg_r[0] = SSP_A<<16;
805 static void tr_ST_to_r0(void)
807 // VR doesn't need much accuracy here..
808 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
809 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
813 static void tr_STACK_to_r0(void)
816 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
817 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
818 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
819 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
820 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
821 hostreg_r[0] = hostreg_r[1] = -1;
824 static void tr_PC_to_r0(void)
826 tr_mov16(0, known_regs.gr[SSP_PC].h);
829 static void tr_P_to_r0(void)
832 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
836 typedef void (tr_read_func)(void);
838 static tr_read_func *tr_read_funcs[8] =
851 // write r0 to general reg handlers. Trashes r1
852 static void tr_unhandled(void)
854 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
858 static void tr_r0_to_GR0(void)
863 static void tr_r0_to_X(void)
865 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
866 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
867 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
868 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
869 hostreg_r[0] = SSP_X<<16;
872 static void tr_r0_to_Y(void)
874 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
875 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
876 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
877 dirty_regb |= KRREG_P;
878 hostreg_r[0] = SSP_Y<<16;
881 static void tr_r0_to_A(void)
883 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
884 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
885 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
886 hostreg_r[0] = SSP_A<<16;
889 static void tr_r0_to_ST(void)
891 // VR doesn't need much accuracy here..
892 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
893 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
894 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
898 static void tr_r0_to_STACK(void)
901 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
902 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
903 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
904 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
905 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
909 static void tr_r0_to_PC(void)
911 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
912 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
916 typedef void (tr_write_func)(void);
918 static tr_write_func *tr_write_funcs[8] =
931 static int translate_op(unsigned int op, int *pc, int imm)
935 known_regs.gr[SSP_PC].h = *pc;
941 if (op == 0) { ret++; break; } // nop
942 tmpv = op & 0xf; // src
943 tmpv2 = (op >> 4) & 0xf; // dst
944 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
945 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
947 EOP_MOV_REG_SIMPLE(5, 10);
948 known_regb &= ~(KRREG_A|KRREG_AL);
951 tr_read_funcs[tmpv]();
952 tr_write_funcs[tmpv2]();
953 if (known_regb & (1 << tmpv)) {
954 known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h;
955 known_regb |= 1 << tmpv2;
957 known_regb &= ~(1 << tmpv2);
961 //case 0x01: tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
965 tmpv = (op >> 4) & 0xf; // src
966 if (tmpv >= 8) return -1; // TODO
967 tr_read_funcs[tmpv]();
973 tr_bank_read(op&0x1ff);
975 known_regb &= ~KRREG_A;
976 hostreg_r[0] = SSP_A<<16;
981 tmpv = (op & 0xf0) >> 4;
985 tr_write_funcs[tmpv]();
986 known_regs.gr[tmpv].h = imm;
987 known_regb |= 1 << tmpv;
990 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
994 tmpv = imm | (PROGRAM((*pc)++) << 16);
995 emit_mov_const(A_COND_AL, 0, tmpv);
996 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
997 EOP_STR_IMM(0,7,0x400+14*4); // PMC
998 // reads on fe06, fe08; next op is ld -,
999 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1001 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1002 tr_flush_dirty_ST();
1003 EOP_LDR_IMM(0,7,0x490); // dram_ptr
1004 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
1005 EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8]
1006 EOP_TST_REG_SIMPLE(0,0);
1007 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1008 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1010 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
1011 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1012 hostreg_r[0] = hostreg_r[1] = -1;
1016 return -1; /* TODO.. */
1021 r = (op&3) | ((op>>6)&4); // src
1022 tmpv2 = (op >> 4) & 0xf; // dst
1023 if (tmpv2 >= 8) return -1; // TODO
1026 tr_bank_read((op&0x100) | ((op>>2)&3));
1027 } else if (known_regb & (1 << (r+8))) {
1028 tr_bank_read((op&0x100) | known_regs.r[r]);
1030 int reg = (r < 4) ? 8 : 9;
1031 int ror = ((4 - (r&3))*8) & 0x1f;
1032 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
1034 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
1035 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
1036 else EOP_ADD_REG_LSL(1,7,1,1);
1037 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
1039 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
1040 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
1041 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
1043 tr_bank_write((op&0x100) | ((op>>2)&3));
1044 } else if (known_regb & (1 << (r+8))) {
1045 tr_bank_write((op&0x100) | known_regs.r[r]);
1047 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1050 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r0]
1051 hostreg_r[0] = hostreg_r[2] = -1;
1052 tr_write_funcs[tmpv2]();
1053 ret += 2; break; /* should certainly take > 1 */
1064 if (hostreg_r[0] != (SSP_A<<16)) {
1065 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
1066 hostreg_r[0] = SSP_A<<16;
1068 tr_bank_write(op&0x1ff);
1074 r = (op&3) | ((op>>6)&4); // src
1075 tmpv2 = (op >> 4) & 0xf; // dst
1076 if (tmpv2 >= 8) tr_unhandled();
1077 if ((r&3) == 3) tr_unhandled();
1079 if (known_regb & (1 << (r+8))) {
1080 tr_mov16(0, known_regs.r[r]);
1081 known_regs.gr[tmpv2].h = known_regs.r[r];
1082 known_regb |= 1 << tmpv2;
1084 int reg = (r < 4) ? 8 : 9;
1085 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1086 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1088 known_regb &= ~(1 << tmpv2);
1090 tr_write_funcs[tmpv2]();
1097 r = (op&3) | ((op>>6)&4); // dst
1098 tmpv = (op >> 4) & 0xf; // src
1099 if (tmpv >= 8) tr_unhandled();
1100 if ((r&3) == 3) tr_unhandled();
1102 if (known_regb & (1 << tmpv)) {
1103 known_regs.r[r] = known_regs.gr[tmpv].h;
1104 known_regb |= 1 << (r + 8);
1105 dirty_regb |= 1 << (r + 8);
1107 int reg = (r < 4) ? 8 : 9;
1108 int ror = ((4 - (r&3))*8) & 0x1f;
1109 tr_read_funcs[tmpv]();
1110 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1111 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1112 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1114 known_regb &= ~(1 << (r+8));
1115 dirty_regb &= ~(1 << (r+8));
1123 known_regs.r[tmpv] = op;
1124 known_regb |= 1 << (tmpv + 8);
1125 dirty_regb |= 1 << (tmpv + 8);
1130 // tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1131 tmpv2 = (op >> 4) & 0xf; // dst
1132 if (tmpv2 >= 8) return -1; // TODO
1134 tr_read_funcs[SSP_A]();
1135 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1136 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1137 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1138 hostreg_r[0] = hostreg_r[1] = -1;
1139 tr_write_funcs[tmpv2]();
1140 ret += 2; break; /* should certainly take > 1 */
1144 tmpv = tr_cond_check(op);
1145 tr_mov16_cond(tmpv, 0, imm);
1146 if (tmpv != A_COND_AL) {
1147 EOP_C_DOP_IMM(tmpv, A_OP_ADD, 0, 11, 11, 0, 1); // add 1 to cycles if we jump
1148 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1151 ret++; // always jump */
1152 tr_write_funcs[SSP_PC]();
1160 read_P(); // update P
1161 rA32 -= rP.v; // maybe only upper word?
1162 UPD_ACC_ZN // there checking flags after this
1163 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1164 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1167 // mpya (rj), (ri), b
1169 read_P(); // update P
1170 rA32 += rP.v; // confirmed to be 32bit
1172 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1173 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1176 // mld (rj), (ri), b
1178 EOP_MOV_IMM(5, 0, 0); // mov r5, #0
1179 known_regs.r[SSP_A].v = 0;
1180 known_regb |= (KRREG_A|KRREG_AL);
1181 EOP_BIC_IMM(6, 6, 0, 0x0f); // bic r6, r6, 0xf // flags
1190 static void *translate_block(int pc)
1192 unsigned int op, op1, imm, ccount = 0;
1193 unsigned int *block_start;
1194 int ret, ret_prev = -1;
1197 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
1199 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1200 block_start = tcache_ptr;
1202 dirty_regb = KRREG_P;
1205 emit_block_prologue();
1207 for (; ccount < 100;)
1209 //printf(" insn #%i\n", icount);
1214 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1215 imm = PROGRAM(pc++); // immediate
1217 ret = translate_op(op, &pc, imm);
1220 tr_flush_dirty_pr();
1222 emit_mov_const(A_COND_AL, 0, op);
1226 emit_mov_const(A_COND_AL, 1, imm);
1231 if (ret_prev > 0) emit_call(regfile_store);
1232 emit_call(in_funcs[op1]);
1233 emit_call(regfile_load);
1235 if (in_funcs[op1] == NULL) {
1236 printf("NULL func! op=%08x (%02x)\n", op, op1);
1241 dirty_regb |= KRREG_P;
1247 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1248 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1249 (op & 0xf0) == 0x60)) { // ld PC
1255 tr_flush_dirty_pr();
1256 emit_block_epilogue(ccount + 1);
1257 *tcache_ptr++ = 0xffffffff; // end of block
1258 //printf(" %i inst\n", icount);
1260 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1261 printf("tcache overflow!\n");
1269 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1270 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1274 FILE *f = fopen("tcache.bin", "wb");
1275 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1288 // -----------------------------------------------------
1290 int ssp1601_dyn_startup(void)
1292 memset(tcache, 0, TCACHE_SIZE);
1293 memset(block_table, 0, sizeof(block_table));
1294 memset(block_table_iram, 0, sizeof(block_table_iram));
1295 tcache_ptr = tcache;
1296 *tcache_ptr++ = 0xffffffff;
1302 void ssp1601_dyn_reset(ssp1601_t *ssp)
1304 ssp1601_reset_local(ssp);
1305 ssp->ptr_rom = (unsigned int) Pico.rom;
1306 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1307 ssp->ptr_dram = (unsigned int) svp->dram;
1310 void ssp1601_dyn_run(int cycles)
1312 if (ssp->emu_status & SSP_WAIT_MASK) return;
1313 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1314 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1317 rPC = DUMP_BLOCK >> 1;
1321 int (*trans_entry)(void);
1325 iram_context = get_iram_context();
1328 if (block_table_iram[iram_context][rPC] == NULL)
1329 block_table_iram[iram_context][rPC] = translate_block(rPC);
1330 trans_entry = (void *) block_table_iram[iram_context][rPC];
1334 if (block_table[rPC] == NULL)
1335 block_table[rPC] = translate_block(rPC);
1336 trans_entry = (void *) block_table[rPC];
1339 //printf("enter %04x\n", rPC<<1);
1340 cycles -= trans_entry();
1341 //printf("leave %04x\n", rPC<<1);
1343 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);