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 0x341e
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, r != AL
565 static int hostreg_r[4];
567 static void hostreg_clear(void)
570 for (i = 0; i < 4; i++)
574 static void hostreg_sspreg_changed(int sspreg)
577 for (i = 0; i < 4; i++)
578 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
582 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
584 static void tr_unhandled(void)
586 FILE *f = fopen("tcache.bin", "wb");
587 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
589 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
593 /* update P, if needed. Trashes r1 */
594 static void tr_flush_dirty_P(void)
597 if (!(dirty_regb & KRREG_P)) return;
598 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
599 EOP_MOV_REG_LSL( 1, 4, 16); // mov r1, r4, lsl #16
600 EOP_MOV_REG_ASR( 1, 1, 15); // mov r1, r1, asr #15
601 EOP_MUL(10, 1, 10); // mul r10, r1, r10
602 dirty_regb &= ~KRREG_P;
605 /* write dirty pr to host reg. Nothing is trashed */
606 static void tr_flush_dirty_pr(int r)
610 if (!(dirty_regb & (1 << (r+8)))) return;
613 case 0: ror = 0; break;
614 case 1: ror = 24/2; break;
615 case 2: ror = 16/2; break;
617 reg = (r < 4) ? 8 : 9;
618 EOP_BIC_IMM(reg,reg,ror,0xff);
619 if (known_regs.r[r] != 0)
620 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
621 dirty_regb &= ~(1 << (r+8));
624 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
625 static void tr_flush_dirty_prs(void)
628 int dirty = dirty_regb >> 8;
630 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
632 if (!(dirty&1)) continue;
634 case 0: ror = 0; break;
635 case 1: ror = 24/2; break;
636 case 2: ror = 16/2; break;
638 reg = (i < 4) ? 8 : 9;
639 EOP_BIC_IMM(reg,reg,ror,0xff);
640 if (known_regs.r[i] != 0)
641 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
643 dirty_regb &= ~0xff00;
646 /* write dirty pr and "forget" it. Nothing is trashed. */
647 static void tr_release_pr(int r)
649 tr_flush_dirty_pr(r);
650 known_regb &= ~(1 << (r+8));
653 /* fush ARM PSR to r6. Trashes r1 */
654 static void tr_flush_dirty_ST(void)
656 if (!(dirty_regb & KRREG_ST)) return;
657 EOP_BIC_IMM(6,6,0,0x0f);
659 EOP_ORR_REG_LSR(6,6,1,28);
660 dirty_regb &= ~KRREG_ST;
664 /* inverse of above. Trashes r1 */
665 static void tr_make_dirty_ST(void)
667 if (dirty_regb & KRREG_ST) return;
668 if (known_regb & KRREG_ST) {
670 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
671 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
672 EOP_MSR_IMM(4/2, flags);
674 EOP_MOV_REG_LSL(1, 6, 28);
678 dirty_regb |= KRREG_ST;
681 /* load 16bit val into host reg r0-r3. Nothing is trashed */
682 static void tr_mov16(int r, int val)
684 if (hostreg_r[r] != val) {
685 emit_mov_const(A_COND_AL, r, val);
690 static void tr_mov16_cond(int cond, int r, int val)
692 emit_mov_const(cond, r, val);
696 /* read bank word to r0. Thrashes r1. */
697 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
701 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
702 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
703 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
707 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
711 /* write r0 to bank. Trashes r1. */
712 static void tr_bank_write(int addr)
716 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
717 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
718 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
722 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
725 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
726 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
728 int modulo_shift = -1; /* unknown */
730 if (mod == 0) return;
732 if (!need_modulo || mod == 1) // +!
734 else if (need_modulo && (known_regb & KRREG_ST)) {
735 modulo_shift = known_regs.gr[SSP_ST].h & 7;
736 if (modulo_shift == 0) modulo_shift = 8;
739 if (modulo_shift == -1)
741 int reg = (r < 4) ? 8 : 9;
744 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
745 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
746 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
747 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
748 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
750 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
751 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
753 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
754 else EOP_ADD_REG2_LSL(reg,reg,3,2);
755 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
756 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
757 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
759 else if (known_regb & (1 << (r + 8)))
761 int modulo = (1 << modulo_shift) - 1;
763 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
764 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
768 int reg = (r < 4) ? 8 : 9;
769 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
770 EOP_MOV_REG_ROR(reg,reg,ror);
771 // {add|sub} reg, reg, #1<<shift
772 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
773 EOP_MOV_REG_ROR(reg,reg,32-ror);
777 /* handle writes r0 to (rX). Trashes r1.
778 * fortunately we can ignore modulo increment modes for writes. */
779 static void tr_rX_write1(int op)
783 int mod = (op>>2) & 3; // direct addressing
784 tr_bank_write((op & 0x100) + mod);
788 int r = (op&3) | ((op>>6)&4);
789 if (known_regb & (1 << (r + 8))) {
790 tr_bank_write((op&0x100) | known_regs.r[r]);
792 int reg = (r < 4) ? 8 : 9;
793 int ror = ((4 - (r&3))*8) & 0x1f;
794 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
796 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
797 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
798 else EOP_ADD_REG_LSL(1,7,1,1);
799 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
802 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
806 /* read (rX) to r0. Trashes r1-r3. */
807 static void tr_rX_read(int r, int mod)
811 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
815 if (known_regb & (1 << (r + 8))) {
816 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
818 int reg = (r < 4) ? 8 : 9;
819 int ror = ((4 - (r&3))*8) & 0x1f;
820 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
822 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
823 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
824 else EOP_ADD_REG_LSL(1,7,1,1);
825 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
828 tr_ptrr_mod(r, mod, 1, 1);
833 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
834 static int tr_cond_check(int op)
836 int f = (op & 0x100) >> 8;
838 case 0x00: return A_COND_AL; /* always true */
839 case 0x50: /* Z matches f(?) bit */
840 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
841 EOP_TST_IMM(6, 0, 4);
842 return f ? A_COND_NE : A_COND_EQ;
843 case 0x70: /* N matches f(?) bit */
844 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
845 EOP_TST_IMM(6, 0, 8);
846 return f ? A_COND_NE : A_COND_EQ;
848 printf("unimplemented cond?\n");
854 static int tr_neg_cond(int cond)
857 case A_COND_AL: printf("neg for AL?\n"); exit(1);
858 case A_COND_EQ: return A_COND_NE;
859 case A_COND_NE: return A_COND_EQ;
860 case A_COND_MI: return A_COND_PL;
861 case A_COND_PL: return A_COND_MI;
862 default: printf("bad cond for neg\n"); exit(1);
867 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
868 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
871 //@ r6: STACK and emu flags
875 // read general reg to r0. Trashes r1
876 static void tr_GR0_to_r0(void)
881 static void tr_X_to_r0(void)
883 if (hostreg_r[0] != (SSP_X<<16)) {
884 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
885 hostreg_r[0] = SSP_X<<16;
889 static void tr_Y_to_r0(void)
892 if (hostreg_r[0] != (SSP_Y<<16)) {
893 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
894 hostreg_r[0] = SSP_Y<<16;
898 static void tr_A_to_r0(void)
900 if (hostreg_r[0] != (SSP_A<<16)) {
901 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
902 hostreg_r[0] = SSP_A<<16;
906 static void tr_ST_to_r0(void)
908 // VR doesn't need much accuracy here..
909 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
910 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
914 static void tr_STACK_to_r0(void)
917 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
918 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
919 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
920 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
921 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
922 hostreg_r[0] = hostreg_r[1] = -1;
925 static void tr_PC_to_r0(void)
927 tr_mov16(0, known_regs.gr[SSP_PC].h);
930 static void tr_P_to_r0(void)
933 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
937 typedef void (tr_read_func)(void);
939 static tr_read_func *tr_read_funcs[8] =
952 // write r0 to general reg handlers. Trashes r1
953 #define TR_WRITE_R0_TO_REG(reg) \
955 hostreg_sspreg_changed(reg); \
956 hostreg_r[0] = (reg)<<16; \
957 if (const_val != -1) { \
958 known_regs.gr[reg].h = const_val; \
959 known_regb |= 1 << (reg); \
961 known_regb &= ~(1 << (reg)); \
965 static void tr_r0_to_GR0(int const_val)
970 static void tr_r0_to_X(int const_val)
972 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
973 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
974 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
975 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
976 TR_WRITE_R0_TO_REG(SSP_X);
979 static void tr_r0_to_Y(int const_val)
981 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
982 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
983 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
984 dirty_regb |= KRREG_P;
985 TR_WRITE_R0_TO_REG(SSP_Y);
988 static void tr_r0_to_A(int const_val)
990 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
991 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
992 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
993 TR_WRITE_R0_TO_REG(SSP_A);
996 static void tr_r0_to_ST(int const_val)
998 // VR doesn't need much accuracy here..
999 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1000 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1001 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1002 TR_WRITE_R0_TO_REG(SSP_ST);
1004 dirty_regb &= ~KRREG_ST;
1007 static void tr_r0_to_STACK(int const_val)
1010 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1011 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1012 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1013 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1014 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1018 static void tr_r0_to_PC(int const_val)
1020 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1021 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1025 typedef void (tr_write_func)(int const_val);
1027 static tr_write_func *tr_write_funcs[8] =
1036 (tr_write_func *)tr_unhandled
1040 static int translate_op(unsigned int op, int *pc, int imm)
1044 known_regs.gr[SSP_PC].h = *pc;
1050 if (op == 0) { ret++; break; } // nop
1051 tmpv = op & 0xf; // src
1052 tmpv2 = (op >> 4) & 0xf; // dst
1053 if (tmpv >= 8 || tmpv2 >= 8) return -1; // TODO
1054 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1056 EOP_MOV_REG_SIMPLE(5, 10);
1057 hostreg_sspreg_changed(SSP_A); \
1058 known_regb &= ~(KRREG_A|KRREG_AL);
1061 tr_read_funcs[tmpv]();
1062 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1067 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1068 int r = (op&3) | ((op>>6)&4);
1069 int mod = (op>>2)&3;
1070 tmpv = (op >> 4) & 0xf; // dst
1071 if (tmpv >= 8) return -1; // TODO
1074 else tr_ptrr_mod(r, mod, 1, 1);
1075 tr_write_funcs[tmpv](-1);
1081 tmpv = (op >> 4) & 0xf; // src
1082 if (tmpv >= 8) return -1; // TODO
1083 tr_read_funcs[tmpv]();
1089 tr_bank_read(op&0x1ff);
1095 tmpv = (op & 0xf0) >> 4;
1099 tr_write_funcs[tmpv](imm);
1102 else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4)
1104 // programming PMC..
1106 tmpv = imm | (PROGRAM((*pc)++) << 16);
1108 emit_mov_const(A_COND_AL, 0, tmpv);
1109 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1110 EOP_STR_IMM(0,7,0x400+14*4); // PMC
1111 // reads on fe06, fe08; next op is ld -,
1112 if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0)
1114 int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1115 tr_flush_dirty_ST();
1116 EOP_LDR_IMM(0,7,0x490); // dram_ptr
1117 EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00
1118 EOP_LDRH_IMM(0,0,(tmpv == 0x187f03) ? 6 : 8); // ldrh r0, [r0, #8]
1119 EOP_TST_REG_SIMPLE(0,0);
1120 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1121 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1123 EOP_ORR_IMM(1,1,0,SSP_PMC_SET); // orr r1, r1, #SSP_PMC_SET
1124 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1125 hostreg_r[0] = hostreg_r[1] = -1;
1129 return -1; /* TODO.. */
1134 r = (op&3) | ((op>>6)&4); // src
1135 tmpv2 = (op >> 4) & 0xf; // dst
1136 if (tmpv2 >= 8) return -1; // TODO
1139 tr_bank_read((op&0x100) | ((op>>2)&3));
1140 } else if (known_regb & (1 << (r+8))) {
1141 tr_bank_read((op&0x100) | known_regs.r[r]);
1143 int reg = (r < 4) ? 8 : 9;
1144 int ror = ((4 - (r&3))*8) & 0x1f;
1145 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
1147 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
1148 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
1149 else EOP_ADD_REG_LSL(1,7,1,1);
1150 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
1152 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
1153 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
1154 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
1156 tr_bank_write((op&0x100) | ((op>>2)&3));
1157 } else if (known_regb & (1 << (r+8))) {
1158 tr_bank_write((op&0x100) | known_regs.r[r]);
1160 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
1163 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
1164 hostreg_r[0] = hostreg_r[2] = -1;
1165 tr_write_funcs[tmpv2](-1);
1166 ret += 3; break; /* should certainly take > 1 */
1178 tr_bank_write(op&0x1ff);
1184 r = (op&3) | ((op>>6)&4); // src
1185 tmpv2 = (op >> 4) & 0xf; // dst
1186 if (tmpv2 >= 8) tr_unhandled();
1187 if ((r&3) == 3) tr_unhandled();
1189 if (known_regb & (1 << (r+8))) {
1190 tr_mov16(0, known_regs.r[r]);
1191 tr_write_funcs[tmpv2](known_regs.r[r]);
1193 int reg = (r < 4) ? 8 : 9;
1194 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1195 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1197 tr_write_funcs[tmpv2](-1);
1205 r = (op&3) | ((op>>6)&4); // dst
1206 tmpv = (op >> 4) & 0xf; // src
1207 if (tmpv >= 8) tr_unhandled();
1208 if ((r&3) == 3) tr_unhandled();
1210 if (known_regb & (1 << tmpv)) {
1211 known_regs.r[r] = known_regs.gr[tmpv].h;
1212 known_regb |= 1 << (r + 8);
1213 dirty_regb |= 1 << (r + 8);
1215 int reg = (r < 4) ? 8 : 9;
1216 int ror = ((4 - (r&3))*8) & 0x1f;
1217 tr_read_funcs[tmpv]();
1218 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1219 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1220 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1222 known_regb &= ~(1 << (r+8));
1223 dirty_regb &= ~(1 << (r+8));
1231 known_regs.r[tmpv] = op;
1232 known_regb |= 1 << (tmpv + 8);
1233 dirty_regb |= 1 << (tmpv + 8);
1238 u32 *jump_op = NULL;
1239 tmpv = tr_cond_check(op);
1240 if (tmpv != A_COND_AL) {
1241 jump_op = tcache_ptr;
1242 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1245 tr_r0_to_STACK(*pc);
1246 if (tmpv != A_COND_AL) {
1247 u32 *real_ptr = tcache_ptr;
1248 tcache_ptr = jump_op;
1249 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1250 tcache_ptr = real_ptr;
1252 tr_mov16_cond(tmpv, 0, imm);
1253 if (tmpv != A_COND_AL) {
1254 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1256 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1262 tmpv2 = (op >> 4) & 0xf; // dst
1263 if (tmpv2 >= 8) return -1; // TODO
1266 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1267 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1268 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1269 hostreg_r[0] = hostreg_r[1] = -1;
1270 tr_write_funcs[tmpv2](-1);
1275 tmpv = tr_cond_check(op);
1276 tr_mov16_cond(tmpv, 0, imm);
1277 if (tmpv != A_COND_AL) {
1278 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1280 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1285 // check for repeats of this op
1287 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1290 if ((op&0xf0) != 0) // !always
1293 tmpv2 = tr_cond_check(op);
1295 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1296 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1297 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1298 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
1299 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1300 hostreg_r[1] = -1; break; // abs
1301 default: tr_unhandled();
1304 hostreg_sspreg_changed(SSP_A);
1305 dirty_regb |= KRREG_ST;
1306 known_regb &= ~KRREG_ST;
1307 known_regb &= ~(KRREG_A|KRREG_AL);
1313 read_P(); // update P
1314 rA32 -= rP.v; // maybe only upper word?
1315 UPD_ACC_ZN // there checking flags after this
1316 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1317 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1320 // mpya (rj), (ri), b
1322 read_P(); // update P
1323 rA32 += rP.v; // confirmed to be 32bit
1325 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
1326 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
1329 // mld (rj), (ri), b
1331 EOP_MOV_IMM(5, 0, 0); // mov r5, #0
1332 known_regs.r[SSP_A].v = 0;
1333 known_regb |= (KRREG_A|KRREG_AL);
1334 EOP_BIC_IMM(6, 6, 0, 0x0f); // bic r6, r6, 0xf // flags
1335 EOP_BIC_IMM(6, 6, 0, 0x04); // bic r6, r6, 4 // set Z
1344 static void *translate_block(int pc)
1346 unsigned int op, op1, imm, ccount = 0;
1347 unsigned int *block_start;
1348 int ret, ret_prev = -1;
1351 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
1353 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1354 block_start = tcache_ptr;
1356 dirty_regb = KRREG_P;
1359 emit_block_prologue();
1361 for (; ccount < 100;)
1363 //printf(" insn #%i\n", icount);
1368 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1369 imm = PROGRAM(pc++); // immediate
1371 ret = translate_op(op, &pc, imm);
1374 tr_flush_dirty_prs();
1375 tr_flush_dirty_ST();
1377 emit_mov_const(A_COND_AL, 0, op);
1381 emit_mov_const(A_COND_AL, 1, imm);
1386 if (ret_prev > 0) emit_call(regfile_store);
1387 emit_call(in_funcs[op1]);
1388 emit_call(regfile_load);
1390 if (in_funcs[op1] == NULL) {
1391 printf("NULL func! op=%08x (%02x)\n", op, op1);
1396 dirty_regb |= KRREG_P;
1402 if (op1 == 0x24 || op1 == 0x26 || // call, bra
1403 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
1404 (op & 0xf0) == 0x60)) { // ld PC
1410 tr_flush_dirty_prs();
1411 tr_flush_dirty_ST();
1412 emit_block_epilogue(ccount + 1);
1413 *tcache_ptr++ = 0xffffffff; // end of block
1414 //printf(" %i inst\n", icount);
1416 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1417 printf("tcache overflow!\n");
1425 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1426 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1430 FILE *f = fopen("tcache.bin", "wb");
1431 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1444 // -----------------------------------------------------
1446 int ssp1601_dyn_startup(void)
1448 memset(tcache, 0, TCACHE_SIZE);
1449 memset(block_table, 0, sizeof(block_table));
1450 memset(block_table_iram, 0, sizeof(block_table_iram));
1451 tcache_ptr = tcache;
1452 *tcache_ptr++ = 0xffffffff;
1456 static unsigned short dummy = 0;
1463 void ssp1601_dyn_reset(ssp1601_t *ssp)
1465 ssp1601_reset_local(ssp);
1466 ssp->ptr_rom = (unsigned int) Pico.rom;
1467 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1468 ssp->ptr_dram = (unsigned int) svp->dram;
1471 void ssp1601_dyn_run(int cycles)
1473 if (ssp->emu_status & SSP_WAIT_MASK) return;
1474 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1475 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1478 rPC = DUMP_BLOCK >> 1;
1482 int (*trans_entry)(void);
1486 iram_context = get_iram_context();
1489 if (block_table_iram[iram_context][rPC] == NULL)
1490 block_table_iram[iram_context][rPC] = translate_block(rPC);
1491 trans_entry = (void *) block_table_iram[iram_context][rPC];
1495 if (block_table[rPC] == NULL)
1496 block_table[rPC] = translate_block(rPC);
1497 trans_entry = (void *) block_table[rPC];
1500 //printf("enter %04x\n", rPC<<1);
1501 cycles -= trans_entry();
1502 //printf("leave %04x\n", rPC<<1);
1504 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);