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 0x084a
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 */
536 unsigned int pmac_read[5];
537 unsigned int pmac_write[5];
539 unsigned int emu_status;
542 #define KRREG_X (1 << SSP_X)
543 #define KRREG_Y (1 << SSP_Y)
544 #define KRREG_A (1 << SSP_A) /* AH only */
545 #define KRREG_ST (1 << SSP_ST)
546 #define KRREG_STACK (1 << SSP_STACK)
547 #define KRREG_PC (1 << SSP_PC)
548 #define KRREG_P (1 << SSP_P)
549 #define KRREG_PR0 (1 << 8)
550 #define KRREG_PR4 (1 << 12)
551 #define KRREG_AL (1 << 16)
552 #define KRREG_PMC (1 << 19) /* PMx are always dirty */
553 #define KRREG_PM0R (1 << 20)
554 #define KRREG_PM1R (1 << 21)
555 #define KRREG_PM2R (1 << 22)
556 #define KRREG_PM3R (1 << 23)
557 #define KRREG_PM4R (1 << 24)
558 #define KRREG_PM0W (1 << 25)
559 #define KRREG_PM1W (1 << 26)
560 #define KRREG_PM2W (1 << 27)
561 #define KRREG_PM3W (1 << 28)
562 #define KRREG_PM4W (1 << 29)
564 /* bitfield of known register values */
565 static u32 known_regb = 0;
567 /* known vals, which need to be flushed
568 * (only ST, P, r0-r7, PMxR, PMxW)
569 * ST means flags are being held in ARM PSR
570 * P means that it needs to be recalculated
572 static u32 dirty_regb = 0;
574 /* known values of host regs.
576 * 000000-00ffff - 16bit value
577 * 100000-10ffff - base reg (r7) + 16bit val
578 * 0r0000 - means reg (low) eq gr[r].h, r != AL
580 static int hostreg_r[4];
582 static void hostreg_clear(void)
585 for (i = 0; i < 4; i++)
589 static void hostreg_sspreg_changed(int sspreg)
592 for (i = 0; i < 4; i++)
593 if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1;
597 #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x]
598 #define PROGRAM_P(x) ((unsigned short *)svp->iram_rom + (x))
600 static void tr_unhandled(void)
602 FILE *f = fopen("tcache.bin", "wb");
603 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
605 printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1);
609 /* update P, if needed. Trashes r0 */
610 static void tr_flush_dirty_P(void)
613 if (!(dirty_regb & KRREG_P)) return;
614 EOP_MOV_REG_ASR(10, 4, 16); // mov r10, r4, asr #16
615 EOP_MOV_REG_LSL( 0, 4, 16); // mov r0, r4, lsl #16
616 EOP_MOV_REG_ASR( 0, 0, 15); // mov r0, r0, asr #15
617 EOP_MUL(10, 0, 10); // mul r10, r0, r10
618 dirty_regb &= ~KRREG_P;
622 /* write dirty pr to host reg. Nothing is trashed */
623 static void tr_flush_dirty_pr(int r)
627 if (!(dirty_regb & (1 << (r+8)))) return;
630 case 0: ror = 0; break;
631 case 1: ror = 24/2; break;
632 case 2: ror = 16/2; break;
634 reg = (r < 4) ? 8 : 9;
635 EOP_BIC_IMM(reg,reg,ror,0xff);
636 if (known_regs.r[r] != 0)
637 EOP_ORR_IMM(reg,reg,ror,known_regs.r[r]);
638 dirty_regb &= ~(1 << (r+8));
641 /* write all dirty pr0-pr7 to host regs. Nothing is trashed */
642 static void tr_flush_dirty_prs(void)
645 int dirty = dirty_regb >> 8;
647 for (i = 0; dirty && i < 8; i++, dirty >>= 1)
649 if (!(dirty&1)) continue;
651 case 0: ror = 0; break;
652 case 1: ror = 24/2; break;
653 case 2: ror = 16/2; break;
655 reg = (i < 4) ? 8 : 9;
656 EOP_BIC_IMM(reg,reg,ror,0xff);
657 if (known_regs.r[i] != 0)
658 EOP_ORR_IMM(reg,reg,ror,known_regs.r[i]);
660 dirty_regb &= ~0xff00;
663 /* write dirty pr and "forget" it. Nothing is trashed. */
664 static void tr_release_pr(int r)
666 tr_flush_dirty_pr(r);
667 known_regb &= ~(1 << (r+8));
670 /* fush ARM PSR to r6. Trashes r1 */
671 static void tr_flush_dirty_ST(void)
673 if (!(dirty_regb & KRREG_ST)) return;
674 EOP_BIC_IMM(6,6,0,0x0f);
676 EOP_ORR_REG_LSR(6,6,1,28);
677 dirty_regb &= ~KRREG_ST;
681 /* inverse of above. Trashes r1 */
682 static void tr_make_dirty_ST(void)
684 if (dirty_regb & KRREG_ST) return;
685 if (known_regb & KRREG_ST) {
687 if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8;
688 if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4;
689 EOP_MSR_IMM(4/2, flags);
691 EOP_MOV_REG_LSL(1, 6, 28);
695 dirty_regb |= KRREG_ST;
698 /* load 16bit val into host reg r0-r3. Nothing is trashed */
699 static void tr_mov16(int r, int val)
701 if (hostreg_r[r] != val) {
702 emit_mov_const(A_COND_AL, r, val);
707 static void tr_mov16_cond(int cond, int r, int val)
709 emit_mov_const(cond, r, val);
714 static void tr_flush_dirty_pmcrs(void)
716 u32 i, val = (u32)-1;
717 if (!(known_regb & 0x3ff80000)) return;
719 if (known_regb & KRREG_PMC) {
720 val = known_regs.pmc;
721 emit_mov_const(A_COND_AL, 0, val);
722 EOP_STR_IMM(0,7,0x400+SSP_PMC*4);
724 if (known_regs.emu_status & SSP_PMC_SET)
725 printf("!! SSP_PMC_SET set on flush\n");
727 for (i = 0; i < 5; i++)
729 if (known_regb & (1 << (20+i))) {
730 if (val != known_regs.pmac_read[i]) {
731 val = known_regs.pmac_read[i];
732 emit_mov_const(A_COND_AL, 0, val);
734 EOP_STR_IMM(0,7,0x454+i*4); // pmac_read
736 if (known_regb & (1 << (25+i))) {
737 if (val != known_regs.pmac_write[i]) {
738 val = known_regs.pmac_write[i];
739 emit_mov_const(A_COND_AL, 0, val);
741 EOP_STR_IMM(0,7,0x46c+i*4); // pmac_write
747 /* read bank word to r0 (upper bits zero). Thrashes r1. */
748 static void tr_bank_read(int addr) /* word addr 0-0x1ff */
752 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
753 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
754 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
758 EOP_LDRH_IMM(0,breg,(addr&0x7f)<<1); // ldrh r0, [r1, (op&0x7f)<<1]
762 /* write r0 to bank. Trashes r1. */
763 static void tr_bank_write(int addr)
767 if (hostreg_r[1] != (0x100000|((addr&0x180)<<1))) {
768 EOP_ADD_IMM(1,7,30/2,(addr&0x180)>>1); // add r1, r7, ((op&0x180)<<1)
769 hostreg_r[1] = 0x100000|((addr&0x180)<<1);
773 EOP_STRH_IMM(0,breg,(addr&0x7f)<<1); // strh r0, [r1, (op&0x7f)<<1]
776 /* handle RAM bank pointer modifiers. if need_modulo, trash r1-r3, else nothing */
777 static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
779 int modulo_shift = -1; /* unknown */
781 if (mod == 0) return;
783 if (!need_modulo || mod == 1) // +!
785 else if (need_modulo && (known_regb & KRREG_ST)) {
786 modulo_shift = known_regs.gr[SSP_ST].h & 7;
787 if (modulo_shift == 0) modulo_shift = 8;
790 if (modulo_shift == -1)
792 int reg = (r < 4) ? 8 : 9;
794 if (dirty_regb & KRREG_ST) {
795 // avoid flushing ARM flags
796 EOP_AND_IMM(1, 6, 0, 0x70);
797 EOP_SUB_IMM(1, 1, 0, 0x10);
798 EOP_AND_IMM(1, 1, 0, 0x70);
799 EOP_ADD_IMM(1, 1, 0, 0x10);
801 EOP_C_DOP_IMM(A_COND_AL,A_OP_AND,1,6,1,0,0x70); // ands r1, r6, #0x70
802 EOP_C_DOP_IMM(A_COND_EQ,A_OP_MOV,0,0,1,0,0x80); // moveq r1, #0x80
804 EOP_MOV_REG_LSR(1, 1, 4); // mov r1, r1, lsr #4
805 EOP_RSB_IMM(2, 1, 0, 8); // rsb r1, r1, #8
806 EOP_MOV_IMM(3, 8/2, count); // mov r3, #0x01000000
808 EOP_ADD_IMM(1, 1, 0, (r&3)*8); // add r1, r1, #(r&3)*8
809 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
811 EOP_SUB_REG2_LSL(reg,reg,3,2); // sub reg, reg, #0x01000000 << r2
812 else EOP_ADD_REG2_LSL(reg,reg,3,2);
813 EOP_RSB_IMM(1, 1, 0, 32); // rsb r1, r1, #32
814 EOP_MOV_REG2_ROR(reg,reg,1); // mov reg, reg, ror r1
815 hostreg_r[1] = hostreg_r[2] = hostreg_r[3] = -1;
817 else if (known_regb & (1 << (r + 8)))
819 int modulo = (1 << modulo_shift) - 1;
821 known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
822 else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
826 int reg = (r < 4) ? 8 : 9;
827 int ror = ((r&3) + 1)*8 - (8 - modulo_shift);
828 EOP_MOV_REG_ROR(reg,reg,ror);
829 // {add|sub} reg, reg, #1<<shift
830 EOP_C_DOP_IMM(A_COND_AL,(mod==2)?A_OP_SUB:A_OP_ADD,0,reg,reg, 8/2, count << (8 - modulo_shift));
831 EOP_MOV_REG_ROR(reg,reg,32-ror);
835 /* handle writes r0 to (rX). Trashes r1.
836 * fortunately we can ignore modulo increment modes for writes. */
837 static void tr_rX_write(int op)
841 int mod = (op>>2) & 3; // direct addressing
842 tr_bank_write((op & 0x100) + mod);
846 int r = (op&3) | ((op>>6)&4);
847 if (known_regb & (1 << (r + 8))) {
848 tr_bank_write((op&0x100) | known_regs.r[r]);
850 int reg = (r < 4) ? 8 : 9;
851 int ror = ((4 - (r&3))*8) & 0x1f;
852 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
854 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
855 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
856 else EOP_ADD_REG_LSL(1,7,1,1);
857 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
860 tr_ptrr_mod(r, (op>>2) & 3, 0, 1);
864 /* read (rX) to r0. Trashes r1-r3. */
865 static void tr_rX_read(int r, int mod)
869 tr_bank_read(((r << 6) & 0x100) + mod); // direct addressing
873 if (known_regb & (1 << (r + 8))) {
874 tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]);
876 int reg = (r < 4) ? 8 : 9;
877 int ror = ((4 - (r&3))*8) & 0x1f;
878 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
880 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
881 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
882 else EOP_ADD_REG_LSL(1,7,1,1);
883 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
884 hostreg_r[0] = hostreg_r[1] = -1;
886 tr_ptrr_mod(r, mod, 1, 1);
890 /* read ((rX)) to r0. Trashes r1,r2. */
891 static void tr_rX_read2(int op)
893 int r = (op&3) | ((op>>6)&4); // src
896 tr_bank_read((op&0x100) | ((op>>2)&3));
897 } else if (known_regb & (1 << (r+8))) {
898 tr_bank_read((op&0x100) | known_regs.r[r]);
900 int reg = (r < 4) ? 8 : 9;
901 int ror = ((4 - (r&3))*8) & 0x1f;
902 EOP_AND_IMM(1,reg,ror/2,0xff); // and r1, r{7,8}, <mask>
904 EOP_ORR_IMM(1,1,((ror-8)&0x1f)/2,1); // orr r1, r1, 1<<shift
905 if (r&3) EOP_ADD_REG_LSR(1,7,1, (r&3)*8-1); // add r1, r7, r1, lsr #lsr
906 else EOP_ADD_REG_LSL(1,7,1,1);
907 EOP_LDRH_SIMPLE(0,1); // ldrh r0, [r1]
909 EOP_LDR_IMM(2,7,0x48c); // ptr_iram_rom
910 EOP_ADD_REG_LSL(2,2,0,1); // add r2, r2, r0, lsl #1
911 EOP_ADD_IMM(0,0,0,1); // add r0, r0, #1
913 tr_bank_write((op&0x100) | ((op>>2)&3));
914 } else if (known_regb & (1 << (r+8))) {
915 tr_bank_write((op&0x100) | known_regs.r[r]);
917 EOP_STRH_SIMPLE(0,1); // strh r0, [r1]
920 EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2]
921 hostreg_r[0] = hostreg_r[2] = -1;
924 /* get ARM cond which would mean that SSP cond is satisfied. No trash. */
925 static int tr_cond_check(int op)
927 int f = (op & 0x100) >> 8;
929 case 0x00: return A_COND_AL; /* always true */
930 case 0x50: /* Z matches f(?) bit */
931 if (dirty_regb & KRREG_ST) return f ? A_COND_EQ : A_COND_NE;
932 EOP_TST_IMM(6, 0, 4);
933 return f ? A_COND_NE : A_COND_EQ;
934 case 0x70: /* N matches f(?) bit */
935 if (dirty_regb & KRREG_ST) return f ? A_COND_MI : A_COND_PL;
936 EOP_TST_IMM(6, 0, 8);
937 return f ? A_COND_NE : A_COND_EQ;
939 printf("unimplemented cond?\n");
945 static int tr_neg_cond(int cond)
948 case A_COND_AL: printf("neg for AL?\n"); exit(1);
949 case A_COND_EQ: return A_COND_NE;
950 case A_COND_NE: return A_COND_EQ;
951 case A_COND_MI: return A_COND_PL;
952 case A_COND_PL: return A_COND_MI;
953 default: printf("bad cond for neg\n"); exit(1);
958 static int tr_aop_ssp2arm(int op)
961 case 1: return A_OP_SUB;
962 case 3: return A_OP_CMP;
963 case 4: return A_OP_ADD;
964 case 5: return A_OP_AND;
965 case 6: return A_OP_ORR;
966 case 7: return A_OP_EOR;
973 // -----------------------------------------------------
975 // SSP_GR0, SSP_X, SSP_Y, SSP_A,
976 // SSP_ST, SSP_STACK, SSP_PC, SSP_P,
979 //@ r6: STACK and emu flags
983 // read general reg to r0. Trashes r1
984 static void tr_GR0_to_r0(void)
989 static void tr_X_to_r0(void)
991 if (hostreg_r[0] != (SSP_X<<16)) {
992 EOP_MOV_REG_LSR(0, 4, 16); // mov r0, r4, lsr #16
993 hostreg_r[0] = SSP_X<<16;
997 static void tr_Y_to_r0(void)
1000 if (hostreg_r[0] != (SSP_Y<<16)) {
1001 EOP_MOV_REG_SIMPLE(0, 4); // mov r0, r4
1002 hostreg_r[0] = SSP_Y<<16;
1006 static void tr_A_to_r0(void)
1008 if (hostreg_r[0] != (SSP_A<<16)) {
1009 EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ AH
1010 hostreg_r[0] = SSP_A<<16;
1014 static void tr_ST_to_r0(void)
1016 // VR doesn't need much accuracy here..
1017 EOP_MOV_REG_LSR(0, 6, 4); // mov r0, r6, lsr #4
1018 EOP_AND_IMM(0, 0, 0, 0x67); // and r0, r0, #0x67
1022 static void tr_STACK_to_r0(void)
1025 EOP_SUB_IMM(6, 6, 8/2, 0x20); // sub r6, r6, #1<<29
1026 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1027 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1028 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1029 EOP_LDRH_SIMPLE(0, 1); // ldrh r0, [r1]
1030 hostreg_r[0] = hostreg_r[1] = -1;
1033 static void tr_PC_to_r0(void)
1035 tr_mov16(0, known_regs.gr[SSP_PC].h);
1038 static void tr_P_to_r0(void)
1041 EOP_MOV_REG_LSR(0, 10, 16); // mov r0, r10, lsr #16
1045 static void tr_PM0_to_r0(void)
1050 static int tr_PM4_to_r0(void)
1053 u32 pmcv = known_regs.pmac_read[reg];
1055 if ((known_regb & KRREG_PMC) && (known_regs.emu_status & SSP_PMC_SET))
1057 known_regs.pmac_read[reg] = known_regs.pmc;
1058 known_regs.emu_status &= ~SSP_PMC_SET;
1059 known_regb |= 1 << (20+reg);
1063 if (known_regb & (1 << (20+reg)))
1065 int mode = known_regs.pmac_read[reg]>>16;
1066 if ((mode & 0xfff0) == 0x0800)
1068 known_regs.pmac_read[reg] += 1;
1069 EOP_LDR_IMM(1,7,0x488); // rom_ptr
1070 emit_mov_const(A_COND_AL, 0, (pmcv&0xfffff)<<1);
1071 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1072 hostreg_r[0] = hostreg_r[1] = -1;
1074 else if ((mode & 0x47ff) == 0x0018) // DRAM
1076 int inc = get_inc(mode);
1077 ssp->pmac_read[reg] += inc;
1078 EOP_LDR_IMM(1,7,0x490); // dram_ptr
1079 emit_mov_const(A_COND_AL, 0, (pmcv&0xffff)<<1);
1080 EOP_LDRH_REG(0,1,0); // ldrh r0, [r1, r0]
1081 if (pmcv == 0x187f03 || pmcv == 0x187f04) // wait loop detection
1083 int flag = (pmcv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08;
1084 tr_flush_dirty_ST();
1085 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1086 EOP_TST_REG_SIMPLE(0,0);
1087 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024
1088 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08
1089 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1091 hostreg_r[0] = hostreg_r[1] = -1;
1097 known_regs.pmc = known_regs.pmac_read[reg];
1098 known_regb |= KRREG_PMC;
1106 typedef void (tr_read_func)(void);
1108 static tr_read_func *tr_read_funcs[8] =
1121 // write r0 to general reg handlers. Trashes r1
1122 #define TR_WRITE_R0_TO_REG(reg) \
1124 hostreg_sspreg_changed(reg); \
1125 hostreg_r[0] = (reg)<<16; \
1126 if (const_val != -1) { \
1127 known_regs.gr[reg].h = const_val; \
1128 known_regb |= 1 << (reg); \
1130 known_regb &= ~(1 << (reg)); \
1134 static void tr_r0_to_GR0(int const_val)
1139 static void tr_r0_to_X(int const_val)
1141 EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16
1142 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1143 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1144 dirty_regb |= KRREG_P; // touching X or Y makes P dirty.
1145 TR_WRITE_R0_TO_REG(SSP_X);
1148 static void tr_r0_to_Y(int const_val)
1150 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16
1151 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16
1152 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16
1153 dirty_regb |= KRREG_P;
1154 TR_WRITE_R0_TO_REG(SSP_Y);
1157 static void tr_r0_to_A(int const_val)
1159 EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16
1160 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL
1161 EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16
1162 TR_WRITE_R0_TO_REG(SSP_A);
1165 static void tr_r0_to_ST(int const_val)
1167 // VR doesn't need much accuracy here..
1168 EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67
1169 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1170 EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
1171 TR_WRITE_R0_TO_REG(SSP_ST);
1173 dirty_regb &= ~KRREG_ST;
1176 static void tr_r0_to_STACK(int const_val)
1179 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400
1180 EOP_ADD_IMM(1, 1, 0, 0x48); // add r1, r1, 0x048
1181 EOP_ADD_REG_LSR(1, 1, 6, 28); // add r1, r1, r6, lsr #28
1182 EOP_STRH_SIMPLE(0, 1); // strh r0, [r1]
1183 EOP_ADD_IMM(6, 6, 8/2, 0x20); // add r6, r6, #1<<29
1187 static void tr_r0_to_PC(int const_val)
1189 EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16
1190 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)]
1194 typedef void (tr_write_func)(int const_val);
1196 static tr_write_func *tr_write_funcs[8] =
1205 (tr_write_func *)tr_unhandled
1208 static void tr_mac_load_XY(int op)
1210 tr_rX_read(op&3, (op>>2)&3); // X
1211 EOP_MOV_REG_LSL(4, 0, 16);
1212 tr_rX_read(((op>>4)&3)|4, (op>>6)&3); // Y
1213 EOP_ORR_REG_SIMPLE(4, 0);
1214 dirty_regb |= KRREG_P;
1215 hostreg_sspreg_changed(SSP_X);
1216 hostreg_sspreg_changed(SSP_Y);
1217 known_regb &= ~KRREG_X;
1218 known_regb &= ~KRREG_Y;
1221 // -----------------------------------------------------
1223 static const short startup_seq[] = { 0xb802, 0x4d50, 0x400 };
1225 static int tr_detect_startup(unsigned int op, int *pc, int imm)
1229 // bra z=1, gloc_0800
1231 if (op != 0x38) return 0;
1232 pp = PROGRAM_P(*pc);
1233 if (memcmp(pp, startup_seq, sizeof(startup_seq)) != 0) return 0;
1234 // the only place when we GPO bits are set in ST is the startup code
1235 // (excluding memtest, which we do not support).
1236 EOP_LDR_IMM(0,7,0x400+SSP_PM0*4);
1237 EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
1238 EOP_TST_IMM(0,16/2,2);
1239 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,SSP_WAIT_PM0>>8); // orreq r1, r1, #SSP_WAIT_PM0
1240 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // addeq r11, r11, #1024
1241 EOP_STR_IMM(1,7,0x484); // str r1, [r7, #0x484] // emu_status
1242 tr_mov16_cond(A_COND_NE, 0, 0x04040000);
1243 EOP_C_AM2_IMM(A_COND_NE,1,0,0,7,0,0x400+SSP_PC*4);
1244 hostreg_r[0] = hostreg_r[1] = -1;
1249 static int tr_detect_set_pm(unsigned int op, int *pc, int imm)
1252 if (!((op&0xfef0) == 0x08e0 && (PROGRAM(*pc)&0xfef0) == 0x08e0)) return 0;
1258 pmcv = imm | (PROGRAM((*pc)++) << 16);
1259 known_regs.pmc = pmcv;
1260 known_regb |= KRREG_PMC;
1261 known_regs.emu_status |= SSP_PMC_SET;
1263 // check for possible reg programming
1264 tmpv = PROGRAM(*pc);
1265 if ((tmpv & 0xfff8) == 0x08 || (tmpv & 0xff8f) == 0x80)
1267 int is_write = (tmpv & 0xff8f) == 0x80;
1268 int reg = is_write ? ((tmpv>>4)&0x7) : (tmpv&0x7);
1269 if (reg > 4) tr_unhandled();
1270 known_regs.pmac_read[is_write ? reg + 5 : reg] = pmcv;
1271 known_regb |= is_write ? (1 << (reg+25)) : (1 << (reg+20));
1272 known_regs.emu_status &= ~SSP_PMC_SET;
1280 static const short pm0_block_seq[] = { 0x0880, 0, 0x0880, 0, 0x0840, 0x60 };
1282 static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
1289 if (op != 0x0840 || imm != 0) return 0;
1290 pp = PROGRAM_P(*pc);
1291 if (memcmp(pp, pm0_block_seq, sizeof(pm0_block_seq)) != 0) return 0;
1293 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK
1294 EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
1295 hostreg_sspreg_changed(SSP_ST);
1296 known_regs.gr[SSP_ST].h = 0x60;
1297 known_regb |= 1 << SSP_ST;
1298 dirty_regb &= ~KRREG_ST;
1303 // -----------------------------------------------------
1305 static int translate_op(unsigned int op, int *pc, int imm)
1307 u32 tmpv, tmpv2, tmpv3;
1309 known_regs.gr[SSP_PC].h = *pc;
1310 known_regs.emu_status = 0;
1316 if (op == 0) { ret++; break; } // nop
1317 tmpv = op & 0xf; // src
1318 tmpv2 = (op >> 4) & 0xf; // dst
1319 ret = tr_detect_startup(op, pc, imm);
1321 if (tmpv != 0xc && (tmpv >= 8 || tmpv2 >= 8)) return -1; // TODO
1322 if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P
1324 EOP_MOV_REG_SIMPLE(5, 10);
1325 hostreg_sspreg_changed(SSP_A); \
1326 known_regb &= ~(KRREG_A|KRREG_AL);
1330 ret = tr_PM4_to_r0();
1331 if (ret != 0) return -1;
1333 else tr_read_funcs[tmpv](); // TODO
1334 tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1);
1335 if (tmpv2 == SSP_PC) ret |= 0x10000;
1340 // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break;
1341 int r = (op&3) | ((op>>6)&4);
1342 int mod = (op>>2)&3;
1343 tmpv = (op >> 4) & 0xf; // dst
1344 if (tmpv >= 8) return -1; // TODO
1347 else tr_ptrr_mod(r, mod, 1, 1);
1348 tr_write_funcs[tmpv](-1);
1349 if (tmpv == SSP_PC) ret |= 0x10000;
1355 tmpv = (op >> 4) & 0xf; // src
1356 if (tmpv >= 8) return -1; // TODO
1357 tr_read_funcs[tmpv]();
1363 tr_bank_read(op&0x1ff);
1369 tmpv = (op & 0xf0) >> 4; // dst
1370 ret = tr_detect_pm0_block(op, pc, imm);
1375 tr_write_funcs[tmpv](imm);
1378 ret = tr_detect_set_pm(op, pc, imm);
1380 if (tmpv == SSP_PC) ret |= 0x10000;
1381 return -1; /* TODO.. */
1385 tmpv2 = (op >> 4) & 0xf; // dst
1386 if (tmpv2 >= 8) return -1; // TODO
1388 tr_write_funcs[tmpv2](-1);
1389 if (tmpv2 == SSP_PC) ret |= 0x10000;
1401 tr_bank_write(op&0x1ff);
1407 r = (op&3) | ((op>>6)&4); // src
1408 tmpv2 = (op >> 4) & 0xf; // dst
1409 if (tmpv2 >= 8) tr_unhandled();
1410 if ((r&3) == 3) tr_unhandled();
1412 if (known_regb & (1 << (r+8))) {
1413 tr_mov16(0, known_regs.r[r]);
1414 tr_write_funcs[tmpv2](known_regs.r[r]);
1416 int reg = (r < 4) ? 8 : 9;
1417 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1418 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1420 tr_write_funcs[tmpv2](-1);
1428 r = (op&3) | ((op>>6)&4); // dst
1429 tmpv = (op >> 4) & 0xf; // src
1430 if (tmpv >= 8) tr_unhandled();
1431 if ((r&3) == 3) tr_unhandled();
1433 if (known_regb & (1 << tmpv)) {
1434 known_regs.r[r] = known_regs.gr[tmpv].h;
1435 known_regb |= 1 << (r + 8);
1436 dirty_regb |= 1 << (r + 8);
1438 int reg = (r < 4) ? 8 : 9;
1439 int ror = ((4 - (r&3))*8) & 0x1f;
1440 tr_read_funcs[tmpv]();
1441 EOP_BIC_IMM(reg, reg, ror/2, 0xff); // bic r{7,8}, r{7,8}, <mask>
1442 EOP_AND_IMM(0, 0, 0, 0xff); // and r0, r0, 0xff
1443 EOP_ORR_REG_LSL(reg, reg, 0, (r&3)*8); // orr r{7,8}, r{7,8}, r0, lsl #lsl
1445 known_regb &= ~(1 << (r+8));
1446 dirty_regb &= ~(1 << (r+8));
1454 known_regs.r[tmpv] = op;
1455 known_regb |= 1 << (tmpv + 8);
1456 dirty_regb |= 1 << (tmpv + 8);
1461 u32 *jump_op = NULL;
1462 tmpv = tr_cond_check(op);
1463 if (tmpv != A_COND_AL) {
1464 jump_op = tcache_ptr;
1465 EOP_MOV_IMM(0, 0, 0); // placeholder for branch
1468 tr_r0_to_STACK(*pc);
1469 if (tmpv != A_COND_AL) {
1470 u32 *real_ptr = tcache_ptr;
1471 tcache_ptr = jump_op;
1472 EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
1473 tcache_ptr = real_ptr;
1475 tr_mov16_cond(tmpv, 0, imm);
1476 if (tmpv != A_COND_AL) {
1477 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1479 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1486 tmpv2 = (op >> 4) & 0xf; // dst
1487 if (tmpv2 >= 8) return -1; // TODO
1490 EOP_LDR_IMM(1,7,0x48c); // ptr_iram_rom
1491 EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1
1492 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0]
1493 hostreg_r[0] = hostreg_r[1] = -1;
1494 tr_write_funcs[tmpv2](-1);
1495 if (tmpv2 == SSP_PC) ret |= 0x10000;
1500 tmpv = tr_cond_check(op);
1501 tr_mov16_cond(tmpv, 0, imm);
1502 if (tmpv != A_COND_AL) {
1503 tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
1505 tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1);
1511 // check for repeats of this op
1513 while (PROGRAM(*pc) == op && (op & 7) != 6) {
1516 if ((op&0xf0) != 0) // !always
1519 tmpv2 = tr_cond_check(op);
1521 case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic)
1522 case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl
1523 case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg
1524 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
1525 EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31
1526 hostreg_r[1] = -1; break; // abs
1527 default: tr_unhandled();
1530 hostreg_sspreg_changed(SSP_A);
1531 dirty_regb |= KRREG_ST;
1532 known_regb &= ~KRREG_ST;
1533 known_regb &= ~(KRREG_A|KRREG_AL);
1542 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
1543 hostreg_sspreg_changed(SSP_A);
1544 known_regb &= ~(KRREG_A|KRREG_AL);
1545 dirty_regb |= KRREG_ST;
1548 // mpya (rj), (ri), b
1553 EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
1554 hostreg_sspreg_changed(SSP_A);
1555 known_regb &= ~(KRREG_A|KRREG_AL);
1556 dirty_regb |= KRREG_ST;
1559 // mld (rj), (ri), b
1561 EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
1562 hostreg_sspreg_changed(SSP_A);
1563 known_regs.gr[SSP_A].v = 0;
1564 known_regb |= (KRREG_A|KRREG_AL);
1565 dirty_regb |= KRREG_ST;
1576 tmpv = op & 0xf; // src
1577 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1578 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1579 if (tmpv >= 8) return -1; // TODO
1580 if (tmpv == SSP_P) {
1582 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL,10); // OPs r5, r5, r10
1583 } else if (tmpv == SSP_A) {
1584 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3, 0,A_AM1_LSL, 5); // OPs r5, r5, r5
1586 tr_read_funcs[tmpv]();
1587 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL, 0); // OPs r5, r5, r0, lsl #16
1589 hostreg_sspreg_changed(SSP_A);
1590 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1591 dirty_regb |= KRREG_ST;
1601 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1602 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1603 tr_rX_read((op&3)|((op>>6)&4), (op>>2)&3);
1604 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1605 hostreg_sspreg_changed(SSP_A);
1606 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1607 dirty_regb |= KRREG_ST;
1617 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1618 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1619 tr_bank_read(op&0x1ff);
1620 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1621 hostreg_sspreg_changed(SSP_A);
1622 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1623 dirty_regb |= KRREG_ST;
1633 tmpv = (op & 0xf0) >> 4;
1634 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1635 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1637 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1638 hostreg_sspreg_changed(SSP_A);
1639 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1640 dirty_regb |= KRREG_ST;
1650 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1651 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1653 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1654 hostreg_sspreg_changed(SSP_A);
1655 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1656 dirty_regb |= KRREG_ST;
1667 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1668 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1669 r = (op&3) | ((op>>6)&4); // src
1670 if ((r&3) == 3) tr_unhandled();
1672 if (known_regb & (1 << (r+8))) {
1673 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,known_regs.r[r]); // OPs r5, r5, #val<<16
1675 int reg = (r < 4) ? 8 : 9;
1676 if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr
1677 EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, <mask>
1678 EOP_C_DOP_REG_XIMM(A_COND_AL,tmpv2,1,5,tmpv3,16,A_AM1_LSL,0); // OPs r5, r5, r0, lsl #16
1681 hostreg_sspreg_changed(SSP_A);
1682 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1683 dirty_regb |= KRREG_ST;
1694 tmpv2 = tr_aop_ssp2arm(op>>13); // op
1695 tmpv3 = (tmpv2 == A_OP_CMP) ? 0 : 5;
1696 EOP_C_DOP_IMM(A_COND_AL,tmpv2,1,5,tmpv3,16/2,op & 0xff); // OPs r5, r5, #val<<16
1697 hostreg_sspreg_changed(SSP_A);
1698 known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
1699 dirty_regb |= KRREG_ST;
1706 static void *translate_block(int pc)
1708 unsigned int op, op1, imm, ccount = 0;
1709 unsigned int *block_start;
1710 int ret, ret_prev = -1, tpc;
1713 //*tcache_ptr++ = (u32) in_funcs; // -1 func pool
1715 printf("translate %04x -> %04x\n", pc<<1, (tcache_ptr-tcache)<<2);
1716 block_start = tcache_ptr;
1718 dirty_regb = KRREG_P;
1721 emit_block_prologue();
1723 for (; ccount < 100;)
1725 //printf(" insn #%i\n", icount);
1730 if ((op1 & 0xf) == 4 || (op1 & 0xf) == 6)
1731 imm = PROGRAM(pc++); // immediate
1734 ret = translate_op(op, &pc, imm);
1737 tr_flush_dirty_prs();
1738 tr_flush_dirty_ST();
1739 tr_flush_dirty_pmcrs();
1741 emit_mov_const(A_COND_AL, 0, op);
1745 emit_mov_const(A_COND_AL, 1, imm);
1750 if (ret_prev > 0) emit_call(regfile_store);
1751 emit_call(in_funcs[op1]);
1752 emit_call(regfile_load);
1754 if (in_funcs[op1] == NULL) {
1755 printf("NULL func! op=%08x (%02x)\n", op, op1);
1760 dirty_regb |= KRREG_P;
1765 ccount += ret & 0xffff;
1766 if (ret & 0x10000) break;
1772 tr_flush_dirty_prs();
1773 tr_flush_dirty_ST();
1774 tr_flush_dirty_pmcrs();
1775 emit_block_epilogue(ccount + 1);
1776 *tcache_ptr++ = 0xffffffff; // end of block
1777 //printf(" %i inst\n", icount);
1779 if (tcache_ptr - tcache > TCACHE_SIZE/4) {
1780 printf("tcache overflow!\n");
1788 printf("%i blocks, %i bytes\n", nblocks, (tcache_ptr - tcache)*4);
1789 //printf("%p %p\n", tcache_ptr, emit_block_epilogue);
1793 FILE *f = fopen("tcache.bin", "wb");
1794 fwrite(tcache, 1, (tcache_ptr - tcache)*4, f);
1807 // -----------------------------------------------------
1809 int ssp1601_dyn_startup(void)
1811 memset(tcache, 0, TCACHE_SIZE);
1812 memset(block_table, 0, sizeof(block_table));
1813 memset(block_table_iram, 0, sizeof(block_table_iram));
1814 tcache_ptr = tcache;
1815 *tcache_ptr++ = 0xffffffff;
1819 static unsigned short dummy = 0;
1826 void ssp1601_dyn_reset(ssp1601_t *ssp)
1828 ssp1601_reset_local(ssp);
1829 ssp->ptr_rom = (unsigned int) Pico.rom;
1830 ssp->ptr_iram_rom = (unsigned int) svp->iram_rom;
1831 ssp->ptr_dram = (unsigned int) svp->dram;
1834 void ssp1601_dyn_run(int cycles)
1836 if (ssp->emu_status & SSP_WAIT_MASK) return;
1837 //{ printf("%i wait\n", Pico.m.frame_count); return; }
1838 //printf("%i %04x\n", Pico.m.frame_count, rPC<<1);
1841 rPC = DUMP_BLOCK >> 1;
1845 int (*trans_entry)(void);
1849 iram_context = get_iram_context();
1852 if (block_table_iram[iram_context][rPC] == NULL)
1853 block_table_iram[iram_context][rPC] = translate_block(rPC);
1854 trans_entry = (void *) block_table_iram[iram_context][rPC];
1858 if (block_table[rPC] == NULL)
1859 block_table[rPC] = translate_block(rPC);
1860 trans_entry = (void *) block_table[rPC];
1863 //printf("enter %04x\n", rPC<<1);
1864 cycles -= trans_entry();
1865 //printf("leave %04x\n", rPC<<1);
1867 // debug_dump2file("tcache.bin", tcache, (tcache_ptr - tcache) << 1);