From 6e39239fb9c95c8e556bdc3ab26307679c246436 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 8 Mar 2008 16:26:21 +0000 Subject: [PATCH] svp compiler: few ops, bugfixes, code seems to work git-svn-id: file:///home/notaz/opt/svn/PicoDrive@375 be3aeb3a-fb24-0410-a615-afba39da0efa --- Pico/carthw/svp/compiler.c | 181 ++++++++++++++++++++++--------------- Pico/carthw/svp/gen_arm.c | 10 +- Pico/carthw/svp/ssp16.c | 5 +- Pico/carthw/svp/ssp16.h | 2 +- 4 files changed, 121 insertions(+), 77 deletions(-) diff --git a/Pico/carthw/svp/compiler.c b/Pico/carthw/svp/compiler.c index cfaa8a7..527647e 100644 --- a/Pico/carthw/svp/compiler.c +++ b/Pico/carthw/svp/compiler.c @@ -12,7 +12,7 @@ static int nblocks = 0; static int iram_context = 0; #ifndef ARM -#define DUMP_BLOCK 0x3516 +#define DUMP_BLOCK 0x341e unsigned int tcache[512*1024]; void regfile_load(void){} void regfile_store(void){} @@ -560,7 +560,7 @@ static u32 dirty_regb = 0; * -1 - unknown * 000000-00ffff - 16bit value * 100000-10ffff - base reg (r7) + 16bit val - * 0r0000 - means reg (low) eq gr[r].h + * 0r0000 - means reg (low) eq gr[r].h, r != AL */ static int hostreg_r[4]; @@ -571,17 +571,25 @@ static void hostreg_clear(void) hostreg_r[i] = -1; } -// TODO -/*static*/ void hostreg_ah_changed(void) +static void hostreg_sspreg_changed(int sspreg) { int i; for (i = 0; i < 4; i++) - if (hostreg_r[i] == (SSP_A<<16)) hostreg_r[i] = -1; + if (hostreg_r[i] == (sspreg<<16)) hostreg_r[i] = -1; } #define PROGRAM(x) ((unsigned short *)svp->iram_rom)[x] +static void tr_unhandled(void) +{ + FILE *f = fopen("tcache.bin", "wb"); + fwrite(tcache, 1, (tcache_ptr - tcache)*4, f); + fclose(f); + printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1); + exit(1); +} + /* update P, if needed. Trashes r1 */ static void tr_flush_dirty_P(void) { @@ -598,7 +606,7 @@ static void tr_flush_dirty_P(void) static void tr_flush_dirty_pr(int r) { int ror = 0, reg; - + if (!(dirty_regb & (1 << (r+8)))) return; switch (r&3) { @@ -642,15 +650,32 @@ static void tr_release_pr(int r) known_regb &= ~(1 << (r+8)); } -/* fush ARM PSR to r6. Trashes r0 */ +/* fush ARM PSR to r6. Trashes r1 */ static void tr_flush_dirty_ST(void) { if (!(dirty_regb & KRREG_ST)) return; EOP_BIC_IMM(6,6,0,0x0f); - EOP_MRS(0); - EOP_ORR_REG_LSR(6,6,0,28); + EOP_MRS(1); + EOP_ORR_REG_LSR(6,6,1,28); dirty_regb &= ~KRREG_ST; - hostreg_r[0] = -1; + hostreg_r[1] = -1; +} + +/* inverse of above. Trashes r1 */ +static void tr_make_dirty_ST(void) +{ + if (dirty_regb & KRREG_ST) return; + if (known_regb & KRREG_ST) { + int flags = 0; + if (known_regs.gr[SSP_ST].h & SSP_FLAG_N) flags |= 8; + if (known_regs.gr[SSP_ST].h & SSP_FLAG_Z) flags |= 4; + EOP_MSR_IMM(4/2, flags); + } else { + EOP_MOV_REG_LSL(1, 6, 28); + EOP_MSR_REG(1); + hostreg_r[1] = -1; + } + dirty_regb |= KRREG_ST; } /* load 16bit val into host reg r0-r3. Nothing is trashed */ @@ -788,7 +813,7 @@ static void tr_rX_read(int r, int mod) else { if (known_regb & (1 << (r + 8))) { - tr_bank_write(((r << 6) & 0x100) | known_regs.r[r]); + tr_bank_read(((r << 6) & 0x100) | known_regs.r[r]); } else { int reg = (r < 4) ? 8 : 9; int ror = ((4 - (r&3))*8) & 0x1f; @@ -808,7 +833,7 @@ static void tr_rX_read(int r, int mod) /* get ARM cond which would mean that SSP cond is satisfied. No trash. */ static int tr_cond_check(int op) { - int f = op & 0x100; + int f = (op & 0x100) >> 8; switch (op&0xf0) { case 0x00: return A_COND_AL; /* always true */ case 0x50: /* Z matches f(?) bit */ @@ -821,7 +846,7 @@ static int tr_cond_check(int op) return f ? A_COND_NE : A_COND_EQ; default: printf("unimplemented cond?\n"); - exit(1); + tr_unhandled(); return 0; } } @@ -925,53 +950,61 @@ static tr_read_func *tr_read_funcs[8] = // write r0 to general reg handlers. Trashes r1 -static void tr_unhandled(void) -{ - printf("unhandled @ %04x\n", known_regs.gr[SSP_PC].h<<1); - exit(1); +#define TR_WRITE_R0_TO_REG(reg) \ +{ \ + hostreg_sspreg_changed(reg); \ + hostreg_r[0] = (reg)<<16; \ + if (const_val != -1) { \ + known_regs.gr[reg].h = const_val; \ + known_regb |= 1 << (reg); \ + } else { \ + known_regb &= ~(1 << (reg)); \ + } \ } -static void tr_r0_to_GR0(void) +static void tr_r0_to_GR0(int const_val) { // do nothing } -static void tr_r0_to_X(void) +static void tr_r0_to_X(int const_val) { EOP_MOV_REG_LSL(4, 4, 16); // mov r4, r4, lsl #16 EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16 - dirty_regb |= KRREG_P; // touching X or Y makes P dirty. - hostreg_r[0] = SSP_X<<16; + dirty_regb |= KRREG_P; // touching X or Y makes P dirty. + TR_WRITE_R0_TO_REG(SSP_X); } -static void tr_r0_to_Y(void) +static void tr_r0_to_Y(int const_val) { EOP_MOV_REG_LSR(4, 4, 16); // mov r4, r4, lsr #16 EOP_ORR_REG_LSL(4, 4, 0, 16); // orr r4, r4, r0, lsl #16 EOP_MOV_REG_ROR(4, 4, 16); // mov r4, r4, ror #16 dirty_regb |= KRREG_P; - hostreg_r[0] = SSP_Y<<16; + TR_WRITE_R0_TO_REG(SSP_Y); } -static void tr_r0_to_A(void) +static void tr_r0_to_A(int const_val) { EOP_MOV_REG_LSL(5, 5, 16); // mov r5, r5, lsl #16 EOP_MOV_REG_LSR(5, 5, 16); // mov r5, r5, lsr #16 @ AL EOP_ORR_REG_LSL(5, 5, 0, 16); // orr r5, r5, r0, lsl #16 - hostreg_r[0] = SSP_A<<16; + TR_WRITE_R0_TO_REG(SSP_A); } -static void tr_r0_to_ST(void) +static void tr_r0_to_ST(int const_val) { // VR doesn't need much accuracy here.. EOP_AND_IMM(1, 0, 0, 0x67); // and r1, r0, #0x67 EOP_AND_IMM(6, 6, 8/2, 0xe0); // and r6, r6, #7<<29 @ preserve STACK EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4 + TR_WRITE_R0_TO_REG(SSP_ST); hostreg_r[1] = -1; + dirty_regb &= ~KRREG_ST; } -static void tr_r0_to_STACK(void) +static void tr_r0_to_STACK(int const_val) { // 448 EOP_ADD_IMM(1, 7, 24/2, 0x04); // add r1, r7, 0x400 @@ -982,14 +1015,14 @@ static void tr_r0_to_STACK(void) hostreg_r[1] = -1; } -static void tr_r0_to_PC(void) +static void tr_r0_to_PC(int const_val) { EOP_MOV_REG_LSL(1, 0, 16); // mov r1, r0, lsl #16 EOP_STR_IMM(1,7,0x400+6*4); // str r1, [r7, #(0x400+6*8)] hostreg_r[1] = -1; } -typedef void (tr_write_func)(void); +typedef void (tr_write_func)(int const_val); static tr_write_func *tr_write_funcs[8] = { @@ -1000,7 +1033,7 @@ static tr_write_func *tr_write_funcs[8] = tr_r0_to_ST, tr_r0_to_STACK, tr_r0_to_PC, - tr_unhandled + (tr_write_func *)tr_unhandled }; @@ -1021,20 +1054,15 @@ static int translate_op(unsigned int op, int *pc, int imm) if (tmpv2 == SSP_A && tmpv == SSP_P) { // ld A, P tr_flush_dirty_P(); EOP_MOV_REG_SIMPLE(5, 10); + hostreg_sspreg_changed(SSP_A); \ known_regb &= ~(KRREG_A|KRREG_AL); ret++; break; } tr_read_funcs[tmpv](); - tr_write_funcs[tmpv2](); - if (known_regb & (1 << tmpv)) { - known_regs.gr[tmpv2].h = known_regs.gr[tmpv].h; - known_regb |= 1 << tmpv2; - } else - known_regb &= ~(1 << tmpv2); + tr_write_funcs[tmpv2]((known_regb & (1 << tmpv)) ? known_regs.gr[tmpv].h : -1); ret++; break; // ld d, (ri) - // TODO: test case 0x01: { // tmpv = ptr1_read(op); REG_WRITE((op & 0xf0) >> 4, tmpv); break; int r = (op&3) | ((op>>6)&4); @@ -1044,8 +1072,7 @@ static int translate_op(unsigned int op, int *pc, int imm) if (tmpv != 0) tr_rX_read(r, mod); else tr_ptrr_mod(r, mod, 1, 1); - tr_write_funcs[tmpv](); - known_regb &= ~(1 << tmpv); + tr_write_funcs[tmpv](-1); ret++; break; } @@ -1060,9 +1087,7 @@ static int translate_op(unsigned int op, int *pc, int imm) // ld a, adr case 0x03: tr_bank_read(op&0x1ff); - tr_r0_to_A(); - known_regb &= ~KRREG_A; - hostreg_r[0] = SSP_A<<16; + tr_r0_to_A(-1); ret++; break; // ldi d, imm @@ -1071,9 +1096,7 @@ static int translate_op(unsigned int op, int *pc, int imm) if (tmpv < 8) { tr_mov16(0, imm); - tr_write_funcs[tmpv](); - known_regs.gr[tmpv].h = imm; - known_regb |= 1 << tmpv; + tr_write_funcs[tmpv](imm); ret += 2; break; } else if (tmpv == 0xe && (PROGRAM(*pc) >> 9) == 4) @@ -1083,7 +1106,7 @@ static int translate_op(unsigned int op, int *pc, int imm) tmpv = imm | (PROGRAM((*pc)++) << 16); ret += 2; emit_mov_const(A_COND_AL, 0, tmpv); - EOP_LDR_IMM(1,7,0x484); // ldr r0, [r7, #0x484] // emu_status + EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status EOP_STR_IMM(0,7,0x400+14*4); // PMC // reads on fe06, fe08; next op is ld -, if ((tmpv == 0x187f03 || tmpv == 0x187f04) && (PROGRAM(*pc) & 0xfff0) == 0) @@ -1091,8 +1114,8 @@ static int translate_op(unsigned int op, int *pc, int imm) int flag = (tmpv == 0x187f03) ? SSP_WAIT_30FE06 : SSP_WAIT_30FE08; tr_flush_dirty_ST(); EOP_LDR_IMM(0,7,0x490); // dram_ptr - EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00 - EOP_LDRH_IMM(0,0,8); // ldrh r0, [r0, #8] + EOP_ADD_IMM(0,0,24/2,0xfe); // add r0, r0, #0xfe00 + EOP_LDRH_IMM(0,0,(tmpv == 0x187f03) ? 6 : 8); // ldrh r0, [r0, #8] EOP_TST_REG_SIMPLE(0,0); EOP_C_DOP_IMM(A_COND_EQ,A_OP_ADD,0,11,11,22/2,1); // add r11, r11, #1024 EOP_C_DOP_IMM(A_COND_EQ,A_OP_ORR,0, 1, 1,24/2,flag>>8); // orr r1, r1, #SSP_WAIT_30FE08 @@ -1137,10 +1160,9 @@ static int translate_op(unsigned int op, int *pc, int imm) EOP_STRH_SIMPLE(0,1); // strh r0, [r1] hostreg_r[1] = -1; } - EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r0] + EOP_LDRH_SIMPLE(0,2); // ldrh r0, [r2] hostreg_r[0] = hostreg_r[2] = -1; - known_regb &= ~(1 << tmpv2); - tr_write_funcs[tmpv2](); + tr_write_funcs[tmpv2](-1); ret += 3; break; /* should certainly take > 1 */ } @@ -1152,10 +1174,7 @@ static int translate_op(unsigned int op, int *pc, int imm) // ld adr, a case 0x07: - if (hostreg_r[0] != (SSP_A<<16)) { - EOP_MOV_REG_LSR(0, 5, 16); // mov r0, r5, lsr #16 @ A - hostreg_r[0] = SSP_A<<16; - } + tr_A_to_r0(); tr_bank_write(op&0x1ff); ret++; break; @@ -1169,16 +1188,14 @@ static int translate_op(unsigned int op, int *pc, int imm) if (known_regb & (1 << (r+8))) { tr_mov16(0, known_regs.r[r]); - known_regs.gr[tmpv2].h = known_regs.r[r]; - known_regb |= 1 << tmpv2; + tr_write_funcs[tmpv2](known_regs.r[r]); } else { int reg = (r < 4) ? 8 : 9; if (r&3) EOP_MOV_REG_LSR(0, reg, (r&3)*8); // mov r0, r{7,8}, lsr #lsr EOP_AND_IMM(0, (r&3)?0:reg, 0, 0xff); // and r0, r{7,8}, hostreg_r[0] = -1; - known_regb &= ~(1 << tmpv2); + tr_write_funcs[tmpv2](-1); } - tr_write_funcs[tmpv2](); ret++; break; } @@ -1217,16 +1234,28 @@ static int translate_op(unsigned int op, int *pc, int imm) ret++; break; // call cond, addr - case 0x24: - tr_mov16(0, *pc); - tr_r0_to_STACK(); + case 0x24: { + u32 *jump_op = NULL; tmpv = tr_cond_check(op); + if (tmpv != A_COND_AL) { + jump_op = tcache_ptr; + EOP_MOV_IMM(0, 0, 0); // placeholder for branch + } + tr_mov16(0, *pc); + tr_r0_to_STACK(*pc); + if (tmpv != A_COND_AL) { + u32 *real_ptr = tcache_ptr; + tcache_ptr = jump_op; + EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2); + tcache_ptr = real_ptr; + } tr_mov16_cond(tmpv, 0, imm); if (tmpv != A_COND_AL) { tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc); } - tr_r0_to_PC(); + tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1); ret += 2; break; + } // ld d, (a) case 0x25: @@ -1238,8 +1267,7 @@ static int translate_op(unsigned int op, int *pc, int imm) EOP_ADD_REG_LSL(0,1,0,1); // add r0, r1, r0, lsl #1 EOP_LDRH_SIMPLE(0,0); // ldrh r0, [r0] hostreg_r[0] = hostreg_r[1] = -1; - known_regb &= ~(1 << tmpv2); - tr_write_funcs[tmpv2](); + tr_write_funcs[tmpv2](-1); ret += 3; break; // bra cond, addr @@ -1249,32 +1277,36 @@ static int translate_op(unsigned int op, int *pc, int imm) if (tmpv != A_COND_AL) { tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc); } - tr_r0_to_PC(); + tr_r0_to_PC(tmpv == A_COND_AL ? imm : -1); ret += 2; break; // mod cond, op - // TODO: test case 0x48: { // check for repeats of this op tmpv = 1; // count while (PROGRAM(*pc) == op && (op & 7) != 6) { (*pc)++; tmpv++; } + if ((op&0xf0) != 0) // !always + tr_make_dirty_ST(); + tmpv2 = tr_cond_check(op); switch (op & 7) { case 2: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_ASR,5); break; // shr (arithmetic) case 3: EOP_C_DOP_REG_XIMM(tmpv2,A_OP_MOV,1,0,5,tmpv,A_AM1_LSL,5); break; // shl case 6: EOP_C_DOP_IMM(tmpv2,A_OP_RSB,1,5,5,0,0); break; // neg - case 7: EOP_C_DOP_IMM(tmpv2,A_OP_EOR,0,5,1,A_AM1_ASR,5); // eor r1, r5, r5, asr #31 - EOP_C_DOP_IMM(tmpv2,A_OP_ADD,1,1,5,A_AM1_LSR,5); // adds r5, r1, r5, lsr #1 + 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 + EOP_C_DOP_REG_XIMM(tmpv2,A_OP_ADD,1,1,5,31,A_AM1_LSR,5); // adds r5, r1, r5, lsr #31 hostreg_r[1] = -1; break; // abs default: tr_unhandled(); } - dirty_regb |= KRREG_ST; + + hostreg_sspreg_changed(SSP_A); + dirty_regb |= KRREG_ST; + known_regb &= ~KRREG_ST; + known_regb &= ~(KRREG_A|KRREG_AL); ret += tmpv; break; } - - /* // mpys? case 0x1b: @@ -1419,6 +1451,11 @@ int ssp1601_dyn_startup(void) tcache_ptr = tcache; *tcache_ptr++ = 0xffffffff; +// TODO: rm +{ +static unsigned short dummy = 0; +PC = &dummy; +} return 0; } diff --git a/Pico/carthw/svp/gen_arm.c b/Pico/carthw/svp/gen_arm.c index 5cd53c6..4e8f05b 100644 --- a/Pico/carthw/svp/gen_arm.c +++ b/Pico/carthw/svp/gen_arm.c @@ -134,7 +134,15 @@ #define EOP_C_MRS(cond,rd) \ EMIT(((cond)<<28) | 0x010f0000 | ((rd)<<12)) -#define EOP_MRS(rd) EOP_C_MRS(A_COND_AL,rd) +#define EOP_C_MSR_IMM(cond,ror2,imm) \ + EMIT(((cond)<<28) | 0x0328f000 | ((ror2)<<8) | (imm)) // cpsr_f + +#define EOP_C_MSR_REG(cond,rm) \ + EMIT(((cond)<<28) | 0x0128f000 | (rm)) // cpsr_f + +#define EOP_MRS(rd) EOP_C_MRS(A_COND_AL,rd) +#define EOP_MSR_IMM(ror2,imm) EOP_C_MSR_IMM(A_COND_AL,ror2,imm) +#define EOP_MSR_REG(rm) EOP_C_MSR_REG(A_COND_AL,rm) static void emit_mov_const(int cond, int d, unsigned int val) diff --git a/Pico/carthw/svp/ssp16.c b/Pico/carthw/svp/ssp16.c index c371492..c01bb1c 100644 --- a/Pico/carthw/svp/ssp16.c +++ b/Pico/carthw/svp/ssp16.c @@ -721,10 +721,9 @@ static void write_PMC(u32 d) // 15 static u32 read_AL(void) { - if (*(PC-1) == 0x000f) { + if (*(PC-1) == 0x000f) elprintf(EL_SVP, "ssp dummy PM assign %08x @ %04x", rPMC.v, GET_PPC_OFFS()); - ssp->emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR); // ? - } + ssp->emu_status &= ~(SSP_PMC_SET|SSP_PMC_HAVE_ADDR); // ? return rAL; } diff --git a/Pico/carthw/svp/ssp16.h b/Pico/carthw/svp/ssp16.h index 2ae06d6..481d4d3 100644 --- a/Pico/carthw/svp/ssp16.h +++ b/Pico/carthw/svp/ssp16.h @@ -48,7 +48,7 @@ typedef struct #define SSP_PMC_SET 0x0002 // PMAC is set #define SSP_WAIT_PM0 0x2000 // bit1 in PM0 #define SSP_WAIT_30FE06 0x4000 // ssp tight loops on 30FE06 to become non-zero - #define SSP_WAIT_30FE08 0x8000 // same for 30FE08 + #define SSP_WAIT_30FE08 0x8000 // same for 30FE06 #define SSP_WAIT_MASK 0xe000 unsigned int emu_status; // 484 /* used by recompiler only: */ -- 2.39.2