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 0x3516
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
555 * P means that it needs to be recalculated
557 static u32 dirty_regb = 0;
559 /* known values of host regs.
561 * 000000-00ffff - 16bit value
562 * 100000-10ffff - base reg (r7) + 16bit val
563 * 0r0000 - means reg (low) eq gr[r].h
565 static int hostreg_r[4];
567 static void hostreg_clear(void)
570 for (i = 0; i < 4; i++)
575 /*static*/ void hostreg_ah_changed(void)
578 for (i = 0; i < 4; i++)
579 if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1;
583 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
585 /* update P, if needed. Trashes r1 */
586 static void tr_flush_dirty_P(void)
589 if (!(dirty_regb & KRREG_P)) return;
590 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
591 EOP_MOV_REG_LSL( 1, 4, 16); // mov r1, r4, lsl #16
592 EOP_MOV_REG_ASR( 1, 1, 15); // mov r1, r1, asr #15
593 EOP_MUL(10, 1, 10); // mul r10, r1, r10
594 dirty_regb &= ~KRREG_P;
597 /* write dirty pr to host reg. Nothing is trashed */
598 static void tr_flush_dirty_pr(int r)
602 if (!(dirty_regb & (1 << (r+8)))) return;
605 case 0: ror = 0; break;
606 case 1: ror = 24/2; break;
607 case 2: ror = 16/2; break;
609 reg = (r < 4) ? 8 : 9;
610 EOP_BIC_IMM(reg,reg,ror,0xff);
611 if (known_regs.r[r] != 0)
612 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
613 dirty_regb &= ~(1 << (r+8));
616 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
617 static void tr_flush_dirty_prs(void)
620 int dirty = dirty_regb >> 8;
622 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
624 if (!(dirty&1)) continue;
626 case 0: ror = 0; break;
627 case 1: ror = 24/2; break;
628 case 2: ror = 16/2; break;
630 reg = (i < 4) ? 8 : 9;
631 EOP_BIC_IMM(reg,reg,ror,0xff);
632 if (known_regs.r[i] != 0)
633 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
635 dirty_regb &= ~0xff00;
638 /* write dirty pr and "forget" it. Nothing is trashed. */
639 static void tr_release_pr(int r)
641 tr_flush_dirty_pr(r);
642 known_regb &= ~(1 << (r+8));
645 /* fush ARM PSR to r6. Trashes r0 */
646 static void tr_flush_dirty_ST(void)
648 if (!(dirty_regb & KRREG_ST)) return;
649 EOP_BIC_IMM(6,6,0,0x0f);
651 EOP_ORR_REG_LSR(6,6,0,28);
652 dirty_regb &= ~KRREG_ST;
656 /* load 16bit val into host reg r0-r3. Nothing is trashed */
657 static void tr_mov16(int r, int val)
659 if (hostreg_r[r] != val) {
660 emit_mov_const(A_COND_AL, r, val);
665 static void tr_mov16_cond(int cond, int r, int val)
667 emit_mov_const(cond, r, val);
671 /* read bank word to r0. Thrashes r1. */
672 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
676 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
677 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
678 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
682 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
686 /* write r0 to bank. Trashes r1. */
687 static void tr_bank_write(int addr)
691 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
692 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
693 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
697 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
700 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
701 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
703 int modulo_shift = -1; /* unknown */
705 if (mod == 0) return;
707 if (!need_modulo || mod == 1) // +!
709 else if (need_modulo && (known_regb & KRREG_ST)) {
710 modulo_shift = known_regs.gr[SSP_ST].h & 7;
711 if (modulo_shift == 0) modulo_shift = 8;
714 if (modulo_shift == -1)
716 int reg = (r < 4) ? 8 : 9;
719 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
720 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
721 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
722 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
723 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
725 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
726 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
728 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
729 else EOP_ADD_REG2_LSL(reg,reg,3,2);
730 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
731 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
732 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
734 else if (known_regb & (1 << (r + 8)))
736 int modulo = (1 << modulo_shift) - 1;
738 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
739 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
743 int reg = (r < 4) ? 8 : 9;
744 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
745 EOP_MOV_REG_ROR(reg,reg,ror);
746 // {add|sub} reg, reg, #1<<shift
747 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
748 EOP_MOV_REG_ROR(reg,reg,32-ror);
752 /* handle writes r0 to (rX). Trashes r1.
753 * fortunately we can ignore modulo increment modes for writes. */
754 static void tr_rX_write1(int op)
758 int mod = (op>>2) & 3; // direct addressing
759 tr_bank_write((op & 0x100) + mod);
763 int r = (op&3) | ((op>>6)&4);
764 if (known_regb & (1 << (r + 8))) {
765 tr_bank_write((op&0x100) | known_regs.r[r]);
767 int reg = (r < 4) ? 8 : 9;
768 int ror = ((4 - (r&3))*8) & 0x1f;
769 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
771 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
772 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
773 else EOP_ADD_REG_LSL(1,7,1,1);
774 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
777 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
781 /* read (rX) to r0. Trashes r1-r3. */
782 static void tr_rX_read(int r, int mod)
786 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
790 if (known_regb & (1 << (r + 8))) {
791 tr_bank_write(((r << 6) & 0x100) | known_regs.r[r]);
793 int reg = (r < 4) ? 8 : 9;
794 int ror = ((4 - (r&3))*8) & 0x1f;
795 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
797 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
798 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
799 else EOP_ADD_REG_LSL(1,7,1,1);
800 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
803 tr_ptrr_mod(r, mod, 1, 1);
808 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
809 static int tr_cond_check(int op)
813 case 0x00: return A_COND_AL; /* always true */
814 case 0x50: /* Z matches f(?) bit */
815 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
816 EOP_TST_IMM(6, 0, 4);
817 return f ? A_COND_NE : A_COND_EQ;
818 case 0x70: /* N matches f(?) bit */
819 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
820 EOP_TST_IMM(6, 0, 8);
821 return f ? A_COND_NE : A_COND_EQ;
823 printf("unimplemented cond?\n");
829 static int tr_neg_cond(int cond)
832 case A_COND_AL: printf("neg for AL?\n"); exit(1);
833 case A_COND_EQ: return A_COND_NE;
834 case A_COND_NE: return A_COND_EQ;
835 case A_COND_MI: return A_COND_PL;
836 case A_COND_PL: return A_COND_MI;
837 default: printf("bad cond for neg\n"); exit(1);
842 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
843 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
846 //@ r6: STACK and emu flags
850 // read general reg to r0. Trashes r1
851 static void tr_GR0_to_r0(void)
856 static void tr_X_to_r0(void)
858 if (hostreg_r[0] != (SSP_X<<16)) {
859 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
860 hostreg_r[0] = SSP_X<<16;
864 static void tr_Y_to_r0(void)
867 if (hostreg_r[0] != (SSP_Y<<16)) {
868 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
869 hostreg_r[0] = SSP_Y<<16;
873 static void tr_A_to_r0(void)
875 if (hostreg_r[0] != (SSP_A<<16)) {
876 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
877 hostreg_r[0] = SSP_A<<16;
881 static void tr_ST_to_r0(void)
883 // VR doesn't need much accuracy here..
884 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
885 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
889 static void tr_STACK_to_r0(void)
892 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
893 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
894 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
895 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
896 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
897 hostreg_r[0] = hostreg_r[1] = -1;
900 static void tr_PC_to_r0(void)
902 tr_mov16(0, known_regs.gr[SSP_PC].h);
905 static void tr_P_to_r0(void)
908 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
912 typedef void (tr_read_func)(void);
914 static tr_read_func *tr_read_funcs[8] =
927 // write r0 to general reg handlers. Trashes r1
928 static void tr_unhandled(void)
930 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
934 static void tr_r0_to_GR0(void)
939 static void tr_r0_to_X(void)
941 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
942 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
943 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
944 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
945 hostreg_r[0] = SSP_X<<16;
948 static void tr_r0_to_Y(void)
950 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
951 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
952 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
953 dirty_regb |= KRREG_P;
954 hostreg_r[0] = SSP_Y<<16;
957 static void tr_r0_to_A(void)
959 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
960 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
961 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
962 hostreg_r[0] = SSP_A<<16;
965 static void tr_r0_to_ST(void)
967 // VR doesn't need much accuracy here..
968 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
969 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
970 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
974 static void tr_r0_to_STACK(void)
977 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
978 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
979 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
980 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
981 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
985 static void tr_r0_to_PC(void)
987 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
988 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
992 typedef void (tr_write_func)(void);
994 static tr_write_func *tr_write_funcs[8] =
1007 static int translate_op(unsigned int op, int *pc, int imm)
1011 known_regs.gr[SSP_PC].h = *pc;
1017 if (op == 0) { ret++; break; } // nop
1018 tmpv = op & 0xf; // src
1019 tmpv2 = (op >> 4) & 0xf; // dst
1020 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
1021 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1023 EOP_MOV_REG_SIMPLE(5, 10);
1024 known_regb &= ~(KRREG_A|KRREG_AL);
1027 tr_read_funcs[tmpv]();
1028 tr_write_funcs[tmpv2]();
1029 if (known_regb & (1 << tmpv)) {
1030 known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h;
1031 known_regb |= 1 << tmpv2;
1033 known_regb &= ~(1 << tmpv2);
1039 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1040 int r = (op&3) | ((op>>6)&4);
1041 int mod = (op>>2)&3;
1042 tmpv = (op >> 4) & 0xf; // dst
1043 if (tmpv >= 8) return -1; // TODO
1046 else tr_ptrr_mod(r, mod, 1, 1);
1047 tr_write_funcs[tmpv]();
1048 known_regb &= ~(1 << tmpv);
1054 tmpv = (op >> 4) & 0xf; // src
1055 if (tmpv >= 8) return -1; // TODO
1056 tr_read_funcs[tmpv]();
1062 tr_bank_read(op&0x1ff);
1064 known_regb &= ~KRREG_A;
1065 hostreg_r[0] = SSP_A<<16;
1070 tmpv = (op & 0xf0) >> 4;
1074 tr_write_funcs[tmpv]();
1075 known_regs.gr[tmpv].h = imm;
1076 known_regb |= 1 << tmpv;
1079 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1081 // programming PMC..
1083 tmpv = imm | (PROGRAM((*pc)++) << 16);
1085 emit_mov_const(A_COND_AL, 0, tmpv);
1086 EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status
1087 EOP_STR_IMM(0,7,0x400+14*4); // PMC
1088 // reads on fe06, fe08; next op is ld -,
1089 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1091 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1092 tr_flush_dirty_ST();
1093 EOP_LDR_IMM(0,7,0x490); // dram_ptr
1094 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
1095 EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8]
1096 EOP_TST_REG_SIMPLE(0,0);
1097 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1098 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1100 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
1101 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1102 hostreg_r[0] = hostreg_r[1] = -1;
1106 return -1; /* TODO.. */
1111 r = (op&3) | ((op>>6)&4); // src
1112 tmpv2 = (op >> 4) & 0xf; // dst
1113 if (tmpv2 >= 8) return -1; // TODO
1116 tr_bank_read((op&0x100) | ((op>>2)&3));
1117 } else if (known_regb & (1 << (r+8))) {
1118 tr_bank_read((op&0x100) | known_regs.r[r]);
1120 int reg = (r < 4) ? 8 : 9;
1121 int ror = ((4 - (r&3))*8) & 0x1f;
1122 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
1124 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
1125 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
1126 else EOP_ADD_REG_LSL(1,7,1,1);
1127 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
1129 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
1130 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
1131 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
1133 tr_bank_write((op&0x100) | ((op>>2)&3));
1134 } else if (known_regb & (1 << (r+8))) {
1135 tr_bank_write((op&0x100) | known_regs.r[r]);
1137 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1140 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r0]
1141 hostreg_r[0] = hostreg_r[2] = -1;
1142 known_regb &= ~(1 << tmpv2);
1143 tr_write_funcs[tmpv2]();
1144 ret += 3; break; /* should certainly take > 1 */
1155 if (hostreg_r[0] != (SSP_A<<16)) {
1156 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
1157 hostreg_r[0] = SSP_A<<16;
1159 tr_bank_write(op&0x1ff);
1165 r = (op&3) | ((op>>6)&4); // src
1166 tmpv2 = (op >> 4) & 0xf; // dst
1167 if (tmpv2 >= 8) tr_unhandled();
1168 if ((r&3) == 3) tr_unhandled();
1170 if (known_regb & (1 << (r+8))) {
1171 tr_mov16(0, known_regs.r[r]);
1172 known_regs.gr[tmpv2].h = known_regs.r[r];
1173 known_regb |= 1 << tmpv2;
1175 int reg = (r < 4) ? 8 : 9;
1176 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1177 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1179 known_regb &= ~(1 << tmpv2);
1181 tr_write_funcs[tmpv2]();
1188 r = (op&3) | ((op>>6)&4); // dst
1189 tmpv = (op >> 4) & 0xf; // src
1190 if (tmpv >= 8) tr_unhandled();
1191 if ((r&3) == 3) tr_unhandled();
1193 if (known_regb & (1 << tmpv)) {
1194 known_regs.r[r] = known_regs.gr[tmpv].h;
1195 known_regb |= 1 << (r + 8);
1196 dirty_regb |= 1 << (r + 8);
1198 int reg = (r < 4) ? 8 : 9;
1199 int ror = ((4 - (r&3))*8) & 0x1f;
1200 tr_read_funcs[tmpv]();
1201 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1202 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1203 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1205 known_regb &= ~(1 << (r+8));
1206 dirty_regb &= ~(1 << (r+8));
1214 known_regs.r[tmpv] = op;
1215 known_regb |= 1 << (tmpv + 8);
1216 dirty_regb |= 1 << (tmpv + 8);
1223 tmpv = tr_cond_check(op);
1224 tr_mov16_cond(tmpv, 0, imm);
1225 if (tmpv != A_COND_AL) {
1226 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1233 tmpv2 = (op >> 4) & 0xf; // dst
1234 if (tmpv2 >= 8) return -1; // TODO
1237 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1238 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1239 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1240 hostreg_r[0] = hostreg_r[1] = -1;
1241 known_regb &= ~(1 << tmpv2);
1242 tr_write_funcs[tmpv2]();
1247 tmpv = tr_cond_check(op);
1248 tr_mov16_cond(tmpv, 0, imm);
1249 if (tmpv != A_COND_AL) {
1250 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1258 // check for repeats of this op
1260 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1263 tmpv2 = tr_cond_check(op);
1265 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1266 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1267 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1268 case 7: EOP_C_DOP_IMM(tmpv2,A_OP_EOR,0,5,1,A_AM1_ASR,5); // eor r1, r5, r5, asr #31
1269 EOP_C_DOP_IMM(tmpv2,A_OP_ADD,1,1,5,A_AM1_LSR,5); // adds r5, r1, r5, lsr #1
1270 hostreg_r[1] = -1; break; // abs
1271 default: tr_unhandled();
1273 dirty_regb |= KRREG_ST;
1281 read_P(); // update P
1282 rA32 -= rP.v; // maybe only upper word?
1283 UPD_ACC_ZN // there checking flags after this
1284 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1285 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1288 // mpya (rj), (ri), b
1290 read_P(); // update P
1291 rA32 += rP.v; // confirmed to be 32bit
1293 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1294 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1297 // mld (rj), (ri), b
1299 EOP_MOV_IMM(5, 0, 0); // mov r5, #0
1300 known_regs.r[SSP_A].v = 0;
1301 known_regb |= (KRREG_A|KRREG_AL);
1302 EOP_BIC_IMM(6, 6, 0, 0x0f); // bic r6, r6, 0xf // flags
1303 EOP_BIC_IMM(6, 6, 0, 0x04); // bic r6, r6, 4 // set Z
1312 static void *translate_block(int pc)
1314 unsigned int op, op1, imm, ccount = 0;
1315 unsigned int *block_start;
1316 int ret, ret_prev = -1;
1319 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
1321 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1322 block_start = tcache_ptr;
1324 dirty_regb = KRREG_P;
1327 emit_block_prologue();
1329 for (; ccount < 100;)
1331 //printf(" insn #%i\n", icount);
1336 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1337 imm = PROGRAM(pc++); // immediate
1339 ret = translate_op(op, &pc, imm);
1342 tr_flush_dirty_prs();
1343 tr_flush_dirty_ST();
1345 emit_mov_const(A_COND_AL, 0, op);
1349 emit_mov_const(A_COND_AL, 1, imm);
1354 if (ret_prev > 0) emit_call(regfile_store);
1355 emit_call(in_funcs[op1]);
1356 emit_call(regfile_load);
1358 if (in_funcs[op1] == NULL) {
1359 printf("NULL func! op=%08x (%02x)\n", op, op1);
1364 dirty_regb |= KRREG_P;
1370 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1371 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1372 (op & 0xf0) == 0x60)) { // ld PC
1378 tr_flush_dirty_prs();
1379 tr_flush_dirty_ST();
1380 emit_block_epilogue(ccount + 1);
1381 *tcache_ptr++ = 0xffffffff; // end of block
1382 //printf(" %i inst\n", icount);
1384 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1385 printf("tcache overflow!\n");
1393 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1394 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1398 FILE *f = fopen("tcache.bin", "wb");
1399 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1412 // -----------------------------------------------------
1414 int ssp1601_dyn_startup(void)
1416 memset(tcache, 0, TCACHE_SIZE);
1417 memset(block_table, 0, sizeof(block_table));
1418 memset(block_table_iram, 0, sizeof(block_table_iram));
1419 tcache_ptr = tcache;
1420 *tcache_ptr++ = 0xffffffff;
1426 void ssp1601_dyn_reset(ssp1601_t *ssp)
1428 ssp1601_reset_local(ssp);
1429 ssp->ptr_rom = (unsigned int) Pico.rom;
1430 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1431 ssp->ptr_dram = (unsigned int) svp->dram;
1434 void ssp1601_dyn_run(int cycles)
1436 if (ssp->emu_status & SSP_WAIT_MASK) return;
1437 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1438 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1441 rPC = DUMP_BLOCK >> 1;
1445 int (*trans_entry)(void);
1449 iram_context = get_iram_context();
1452 if (block_table_iram[iram_context][rPC] == NULL)
1453 block_table_iram[iram_context][rPC] = translate_block(rPC);
1454 trans_entry = (void *) block_table_iram[iram_context][rPC];
1458 if (block_table[rPC] == NULL)
1459 block_table[rPC] = translate_block(rPC);
1460 trans_entry = (void *) block_table[rPC];
1463 //printf("enter %04x\n", rPC<<1);
1464 cycles -= trans_entry();
1465 //printf("leave %04x\n", rPC<<1);
1467 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);