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 had_jump = 0;
12 static int nblocks = 0;
13 static int iram_context = 0;
16 #define DUMP_BLOCK 0x40b0
17 unsigned int tcache[512*1024];
18 void regfile_load(void){}
19 void regfile_store(void){}
22 #define EMBED_INTERPRETER
23 #define ssp1601_reset ssp1601_reset_local
24 #define ssp1601_run ssp1601_run_local
27 #define GET_PPC_OFFS() (GET_PC()*2 - 2)
28 #define SET_PC(d) { had_jump = 1; rPC = d; } /* must return to dispatcher after this */
29 //#define GET_PC() (PC - (unsigned short *)svp->iram_rom)
30 //#define GET_PPC_OFFS() ((unsigned int)PC - (unsigned int)svp->iram_rom - 2)
31 //#define SET_PC(d) PC = (unsigned short *)svp->iram_rom + d
36 // -----------------------------------------------------
39 static void op00(unsigned int op, unsigned int imm)
42 PC = ((unsigned short *)(void *)&op) + 1; /* FIXME: needed for interpreter */
43 if (op == 0) return; // nop
44 if (op == ((SSP_A<<4)|SSP_P)) { // A <- P
45 // not sure. MAME claims that only hi word is transfered.
51 tmpv = REG_READ(op & 0x0f);
52 REG_WRITE((op & 0xf0) >> 4, tmpv);
57 static void op01(unsigned int op, unsigned int imm)
60 tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
64 static void op02(unsigned int op, unsigned int imm)
67 tmpv = REG_READ((op & 0xf0) >> 4); ptr1_write(op, tmpv);
71 static void op04(unsigned int op, unsigned int imm)
73 REG_WRITE((op & 0xf0) >> 4, imm);
77 static void op05(unsigned int op, unsigned int imm)
80 tmpv = ptr2_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv);
84 static void op06(unsigned int op, unsigned int imm)
90 static void op07(unsigned int op, unsigned int imm)
92 ssp->RAM[op & 0x1ff] = rA;
96 static void op09(unsigned int op, unsigned int imm)
99 tmpv = rIJ[(op&3)|((op>>6)&4)]; REG_WRITE((op & 0xf0) >> 4, tmpv);
103 static void op0a(unsigned int op, unsigned int imm)
105 rIJ[(op&3)|((op>>6)&4)] = REG_READ((op & 0xf0) >> 4);
108 // ldi ri, simm (also op0d op0e op0f)
109 static void op0c(unsigned int op, unsigned int imm)
115 static void op24(unsigned int op, unsigned int imm)
120 if (cond) { int new_PC = imm; write_STACK(GET_PC()); SET_PC(new_PC); }
126 static void op25(unsigned int op, unsigned int imm)
129 tmpv = ((unsigned short *)svp->iram_rom)[rA]; REG_WRITE((op & 0xf0) >> 4, tmpv);
133 static void op26(unsigned int op, unsigned int imm)
139 if (cond) SET_PC(imm);
145 static void op48(unsigned int op, unsigned int imm)
153 case 2: rA32 = (signed int)rA32 >> 1; break; // shr (arithmetic)
154 case 3: rA32 <<= 1; break; // shl
155 case 6: rA32 = -(signed int)rA32; break; // neg
156 case 7: if ((int)rA32 < 0) rA32 = -(signed int)rA32; break; // abs
157 default: elprintf(EL_SVP|EL_ANOMALY, "ssp FIXME: unhandled mod %i @ %04x",
158 op&7, GET_PPC_OFFS());
167 static void op1b(unsigned int op, unsigned int imm)
169 read_P(); // update P
170 rA32 -= rP.v; // maybe only upper word?
171 UPD_ACC_ZN // there checking flags after this
172 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
173 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
176 // mpya (rj), (ri), b
177 static void op4b(unsigned int op, unsigned int imm)
179 read_P(); // update P
180 rA32 += rP.v; // confirmed to be 32bit
182 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
183 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
187 static void op5b(unsigned int op, unsigned int imm)
191 rX = ptr1_read_(op&3, 0, (op<<1)&0x18); // ri (maybe rj?)
192 rY = ptr1_read_((op>>4)&3, 4, (op>>3)&0x18); // rj
196 static void op10(unsigned int op, unsigned int imm)
201 OP_CHECK32(OP_SUBA32); tmpv = REG_READ(op & 0x0f); OP_SUBA(tmpv);
206 static void op30(unsigned int op, unsigned int imm)
211 OP_CHECK32(OP_CMPA32); tmpv = REG_READ(op & 0x0f); OP_CMPA(tmpv);
216 static void op40(unsigned int op, unsigned int imm)
221 OP_CHECK32(OP_ADDA32); tmpv = REG_READ(op & 0x0f); OP_ADDA(tmpv);
226 static void op50(unsigned int op, unsigned int imm)
231 OP_CHECK32(OP_ANDA32); tmpv = REG_READ(op & 0x0f); OP_ANDA(tmpv);
236 static void op60(unsigned int op, unsigned int imm)
241 OP_CHECK32(OP_ORA32 ); tmpv = REG_READ(op & 0x0f); OP_ORA (tmpv);
246 static void op70(unsigned int op, unsigned int imm)
251 OP_CHECK32(OP_EORA32); tmpv = REG_READ(op & 0x0f); OP_EORA(tmpv);
257 static void op11(unsigned int op, unsigned int imm)
260 tmpv = ptr1_read(op); OP_SUBA(tmpv);
263 static void op31(unsigned int op, unsigned int imm)
266 tmpv = ptr1_read(op); OP_CMPA(tmpv);
269 static void op41(unsigned int op, unsigned int imm)
272 tmpv = ptr1_read(op); OP_ADDA(tmpv);
275 static void op51(unsigned int op, unsigned int imm)
278 tmpv = ptr1_read(op); OP_ANDA(tmpv);
281 static void op61(unsigned int op, unsigned int imm)
284 tmpv = ptr1_read(op); OP_ORA (tmpv);
287 static void op71(unsigned int op, unsigned int imm)
290 tmpv = ptr1_read(op); OP_EORA(tmpv);
294 static void op03(unsigned int op, unsigned int imm)
297 tmpv = ssp->RAM[op & 0x1ff]; OP_LDA (tmpv);
300 static void op13(unsigned int op, unsigned int imm)
303 tmpv = ssp->RAM[op & 0x1ff]; OP_SUBA(tmpv);
306 static void op33(unsigned int op, unsigned int imm)
309 tmpv = ssp->RAM[op & 0x1ff]; OP_CMPA(tmpv);
312 static void op43(unsigned int op, unsigned int imm)
315 tmpv = ssp->RAM[op & 0x1ff]; OP_ADDA(tmpv);
318 static void op53(unsigned int op, unsigned int imm)
321 tmpv = ssp->RAM[op & 0x1ff]; OP_ANDA(tmpv);
324 static void op63(unsigned int op, unsigned int imm)
327 tmpv = ssp->RAM[op & 0x1ff]; OP_ORA (tmpv);
330 static void op73(unsigned int op, unsigned int imm)
333 tmpv = ssp->RAM[op & 0x1ff]; OP_EORA(tmpv);
337 static void op14(unsigned int op, unsigned int imm)
342 static void op34(unsigned int op, unsigned int imm)
347 static void op44(unsigned int op, unsigned int imm)
352 static void op54(unsigned int op, unsigned int imm)
357 static void op64(unsigned int op, unsigned int imm)
362 static void op74(unsigned int op, unsigned int imm)
368 static void op15(unsigned int op, unsigned int imm)
371 tmpv = ptr2_read(op); OP_SUBA(tmpv);
374 static void op35(unsigned int op, unsigned int imm)
377 tmpv = ptr2_read(op); OP_CMPA(tmpv);
380 static void op45(unsigned int op, unsigned int imm)
383 tmpv = ptr2_read(op); OP_ADDA(tmpv);
386 static void op55(unsigned int op, unsigned int imm)
389 tmpv = ptr2_read(op); OP_ANDA(tmpv);
392 static void op65(unsigned int op, unsigned int imm)
395 tmpv = ptr2_read(op); OP_ORA (tmpv);
398 static void op75(unsigned int op, unsigned int imm)
401 tmpv = ptr2_read(op); OP_EORA(tmpv);
405 static void op19(unsigned int op, unsigned int imm)
408 tmpv = rIJ[IJind]; OP_SUBA(tmpv);
411 static void op39(unsigned int op, unsigned int imm)
414 tmpv = rIJ[IJind]; OP_CMPA(tmpv);
417 static void op49(unsigned int op, unsigned int imm)
420 tmpv = rIJ[IJind]; OP_ADDA(tmpv);
423 static void op59(unsigned int op, unsigned int imm)
426 tmpv = rIJ[IJind]; OP_ANDA(tmpv);
429 static void op69(unsigned int op, unsigned int imm)
432 tmpv = rIJ[IJind]; OP_ORA (tmpv);
435 static void op79(unsigned int op, unsigned int imm)
438 tmpv = rIJ[IJind]; OP_EORA(tmpv);
442 static void op1c(unsigned int op, unsigned int imm)
447 static void op3c(unsigned int op, unsigned int imm)
452 static void op4c(unsigned int op, unsigned int imm)
457 static void op5c(unsigned int op, unsigned int imm)
462 static void op6c(unsigned int op, unsigned int imm)
467 static void op7c(unsigned int op, unsigned int imm)
472 typedef void (in_func)(unsigned int op, unsigned int imm);
474 static in_func *in_funcs[0x80] =
476 op00, op01, op02, op03, op04, op05, op06, op07,
477 NULL, op09, op0a, NULL, op0c, op0c, op0c, op0c,
478 op10, op11, NULL, op13, op14, op15, NULL, NULL,
479 NULL, op19, NULL, op1b, op1c, NULL, NULL, NULL,
480 NULL, NULL, NULL, NULL, op24, op25, op26, NULL,
481 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
482 op30, op31, NULL, op33, op34, op35, NULL, NULL,
483 NULL, op39, NULL, NULL, op3c, NULL, NULL, NULL,
484 op40, op41, NULL, op43, op44, op45, NULL, NULL,
485 op48, op49, NULL, op4b, op4c, NULL, NULL, NULL,
486 op50, op51, NULL, op53, op54, op55, NULL, NULL,
487 NULL, op59, NULL, op5b, op5c, NULL, NULL, NULL,
488 op60, op61, NULL, op63, op64, op65, NULL, NULL,
489 NULL, op69, NULL, NULL, op6c, NULL, NULL, NULL,
490 op70, op71, NULL, op73, op74, op75, NULL, NULL,
491 NULL, op79, NULL, NULL, op7c, NULL, NULL, NULL,
494 // -----------------------------------------------------
496 static unsigned char iram_context_map[] =
498 0, 0, 0, 0, 1, 0, 0, 0, // 04
499 0, 0, 0, 0, 0, 0, 2, 0, // 0e
500 0, 0, 0, 0, 0, 3, 0, 4, // 15 17
501 5, 0, 0, 6, 0, 7, 0, 0, // 18 1b 1d
502 8, 9, 0, 0, 0,10, 0, 0, // 20 21 25
503 0, 0, 0, 0, 0, 0, 0, 0,
504 0, 0,11, 0, 0,12, 0, 0, // 32 35
505 13,14, 0, 0, 0, 0, 0, 0 // 38 39
508 static int get_iram_context(void)
510 unsigned char *ir = (unsigned char *)svp->iram_rom;
511 int val1, val = ir[0x083^1] + ir[0x4FA^1] + ir[0x5F7^1] + ir[0x47B^1];
512 val1 = iram_context_map[(val>>1)&0x3f];
515 printf("val: %02x PC=%04x\n", (val>>1)&0x3f, rPC);
516 //debug_dump2file(name, svp->iram_rom, 0x800);
519 // elprintf(EL_ANOMALY, "iram_context: %02i", val1);
523 // -----------------------------------------------------
526 SSP_GR0, SSP_X, SSP_Y, SSP_A,
527 SSP_ST, SSP_STACK, SSP_PC, SSP_P,
528 SSP_PM0, SSP_PM1, SSP_PM2, SSP_XST,
529 SSP_PM4, SSP_gr13, SSP_PMC, SSP_AL
532 /* regs with known values */
539 #define CRREG_X (1 << SSP_X)
540 #define CRREG_Y (1 << SSP_Y)
541 #define CRREG_A (1 << SSP_A) /* AH only */
542 #define CRREG_ST (1 << SSP_ST)
543 #define CRREG_STACK (1 << SSP_STACK)
544 #define CRREG_PC (1 << SSP_PC)
545 #define CRREG_P (1 << SSP_P)
546 #define CRREG_PR0 (1 << 8)
547 #define CRREG_PR4 (1 << 12)
548 #define CRREG_AL (1 << 16)
550 static u32 const_regb = 0; /* bitfield of known register values */
551 static u32 dirty_regb = 0; /* known vals, which need to be flushed (only r0-r7) */
553 /* known values of host regs.
555 * 00000-0ffff - 16bit value
556 * 10000-1ffff - base reg (r7) + 16bit val
557 * 20000 - means reg (low) eq AH
559 static int hostreg_r[4];
561 static void hostreg_clear(void)
564 for (i = 0; i < 4; i++)
568 /*static*/ void hostreg_ah_changed(void)
571 for (i = 0; i < 4; i++)
572 if (hostreg_r[i] == 0x20000) hostreg_r[i] = -1;
576 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
578 /* load 16bit val into host reg r0-r3. Nothing is trashed */
579 static void tr_mov16(int r, int val)
581 if (hostreg_r[r] != val) {
582 emit_mov_const(r, val);
587 /* write dirty r0-r7 to host regs. Nothing is trashed */
588 static void tr_flush_dirty(void)
593 for (i = 0; dirty_regb && i < 8; i++, dirty_regb >>= 1)
595 if (!(dirty_regb&1)) continue;
597 case 0: ror = 0; break;
598 case 1: ror = 24/2; break;
599 case 2: ror = 16/2; break;
601 reg = (i < 4) ? 8 : 9;
602 EOP_BIC_IMM(reg,reg,ror,0xff);
603 if (const_regs.r[i] != 0)
604 EOP_ORR_IMM(reg,reg,ror,const_regs.r[i]);
608 /* read bank word to r0 (MSW may contain trash). Thrashes r1. */
609 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
614 if (hostreg_r[1] != (0x10000|((addr&0x180)<<1))) {
615 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
616 hostreg_r[1] = 0x10000|((addr&0x180)<<1);
620 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
622 EOP_LDR_IMM(0,7,(addr&0x1ff)<<1); // ldr r0, [r1, (op&0x1ff)<<1]
627 /* write r0 to bank. Trashes r1. */
628 static void tr_bank_write(int addr)
632 if (hostreg_r[1] != (0x10000|((addr&0x180)<<1))) {
633 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
634 hostreg_r[1] = 0x10000|((addr&0x180)<<1);
638 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // str r0, [r1, (op&0x7f)<<1]
641 /* handle RAM bank pointer modifiers. Nothing is trashed. */
642 static void tr_ptrr_mod(int r, int mod, int need_modulo)
644 int modulo = -1, modulo_shift = -1; /* unknown */
646 if (mod == 0) return;
648 if (!need_modulo || mod == 1) // +!
650 else if (need_modulo && (const_regb & CRREG_ST)) {
651 modulo_shift = const_regs.gr[SSP_ST].h & 7;
652 if (modulo_shift == 0) modulo_shift = 8;
655 if (mod > 1 && modulo_shift == -1) { printf("need var modulo\n"); exit(1); }
656 modulo = (1 << modulo_shift) - 1;
658 if (const_regb & (1 << (r + 8))) {
660 const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] - 1) & modulo);
661 else const_regs.r[r] = (const_regs.r[r] & ~modulo) | ((const_regs.r[r] + 1) & modulo);
663 int reg = (r < 4) ? 8 : 9;
664 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
665 EOP_MOV_REG_ROR(reg,reg,ror);
666 // {add|sub} reg, reg, #1<<shift
667 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, 1<<(8 - modulo_shift));
668 EOP_MOV_REG_ROR(reg,reg,32-ror);
673 static int translate_op(unsigned int op, int *pc, int imm)
682 if (op == 0) { ret++; break; } // nop
687 tr_bank_read(op&0x1ff);
688 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
689 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsl #16 @ AL
690 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
691 const_regb &= ~CRREG_A;
692 hostreg_r[0] = 0x20000;
697 //tmpv = *PC++; ptr1_write(op, tmpv); break;
698 // int t = (op&3) | ((op>>6)&4) | ((op<<1)&0x18);
702 tmpv = (op>>2) & 3; // direct addressing
704 if (hostreg_r[1] != 0x10200) {
705 EOP_ADD_IMM(1,7,30/2,0x200>>2); // add r1, r7, 0x200
706 hostreg_r[1] = 0x10200;
708 EOP_STRH_IMM(0,1,tmpv<<1); // str r0, [r1, {0,2,4,6}]
710 EOP_STRH_IMM(0,7,tmpv<<1); // str r0, [r7, {0,2,4,6}]
715 int r = (op&3) | ((op>>6)&4);
716 if (const_regb & (1 << (r + 8))) {
717 tr_bank_write(const_regs.r[r] | ((r < 4) ? 0 : 0x100));
719 int reg = (r < 4) ? 8 : 9;
720 int ror = ((4 - (r&3))*8) & 0x1f;
721 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
723 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
724 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
725 else EOP_ADD_REG_LSL(1,7,1,1);
726 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
729 tr_ptrr_mod(r, (op>>2) & 3, 0);
735 if (hostreg_r[0] != 0x20000) {
736 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A
737 hostreg_r[0] = 0x20000;
739 tr_bank_write(op&0x1ff);
745 const_regs.r[tmpv] = op;
746 const_regb |= 1 << (tmpv + 8);
747 dirty_regb |= 1 << (tmpv + 8);
754 static void *translate_block(int pc)
756 unsigned int op, op1, imm, ccount = 0;
757 unsigned int *block_start;
761 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
763 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
764 block_start = tcache_ptr;
765 const_regb = dirty_regb = 0;
768 emit_block_prologue();
770 for (; ccount < 100;)
772 //printf(" insn #%i\n", icount);
777 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
778 imm = PROGRAM(pc++); // immediate
780 ret = translate_op(op, &pc, imm);
785 emit_mov_const(0, op);
789 emit_mov_const(1, imm);
794 emit_interpreter_call(in_funcs[op1]);
796 if (in_funcs[op1] == NULL) {
797 printf("NULL func! op=%08x (%02x)\n", op, op1);
806 if (op1 == 0x24 || op1 == 0x26 || // call, bra
807 ((op1 == 0 || op1 == 1 || op1 == 4 || op1 == 5 || op1 == 9 || op1 == 0x25) &&
808 (op & 0xf0) == 0x60)) { // ld PC
814 emit_block_epilogue(ccount + 1);
815 *tcache_ptr++ = 0xffffffff; // end of block
816 //printf(" %i inst\n", icount);
818 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
819 printf("tcache overflow!\n");
827 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
828 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
832 FILE *f = fopen("tcache.bin", "wb");
833 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
846 // -----------------------------------------------------
848 int ssp1601_dyn_startup(void)
850 memset(tcache, 0, TCACHE_SIZE);
851 memset(block_table, 0, sizeof(block_table));
852 memset(block_table_iram, 0, sizeof(block_table_iram));
854 *tcache_ptr++ = 0xffffffff;
860 void ssp1601_dyn_reset(ssp1601_t *ssp)
862 ssp1601_reset_local(ssp);
865 void ssp1601_dyn_run(int cycles)
868 rPC = DUMP_BLOCK >> 1;
872 int (*trans_entry)(void);
876 iram_context = get_iram_context();
879 if (block_table_iram[iram_context][rPC] == NULL)
880 block_table_iram[iram_context][rPC] = translate_block(rPC);
881 trans_entry = (void *) block_table_iram[iram_context][rPC];
885 if (block_table[rPC] == NULL)
886 block_table[rPC] = translate_block(rPC);
887 trans_entry = (void *) block_table[rPC];
892 //printf("enter %04x\n", rPC<<1);
893 cycles -= trans_entry();
894 //printf("leave %04x\n", rPC<<1);
896 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);