// 04 - asm
// 08 - runtime block entry log
// 10 - smc self-check
+// 100 - write trace
+// 200 - compare trace
+// 400 - print block entry backtrace
// {
#ifndef DRC_DEBUG
#define DRC_DEBUG 0
#define dbg(...)
#endif
+
///
#define FETCH_OP(pc) \
dr_pc_base[(pc) / 2]
#define do_host_disasm(x)
#endif
-#if (DRC_DEBUG & 8) || defined(PDB)
+#if (DRC_DEBUG & (8|256|512|1024)) || defined(PDB)
+
+#define SH2_DUMP(sh2, reason) { \
+ char ms = (sh2)->is_slave ? 's' : 'm'; \
+ printf("%csh2 %s %08x\n", ms, reason, (sh2)->pc); \
+ printf("%csh2 r0-7 %08x %08x %08x %08x %08x %08x %08x %08x\n", ms, \
+ (sh2)->r[0], (sh2)->r[1], (sh2)->r[2], (sh2)->r[3], \
+ (sh2)->r[4], (sh2)->r[5], (sh2)->r[6], (sh2)->r[7]); \
+ printf("%csh2 r8-15 %08x %08x %08x %08x %08x %08x %08x %08x\n", ms, \
+ (sh2)->r[8], (sh2)->r[9], (sh2)->r[10], (sh2)->r[11], \
+ (sh2)->r[12], (sh2)->r[13], (sh2)->r[14], (sh2)->r[15]); \
+ printf("%csh2 pc-ml %08x %08x %08x %08x %08x %08x %08x %08x\n", ms, \
+ (sh2)->pc, (sh2)->ppc, (sh2)->pr, (sh2)->sr&0x3ff, \
+ (sh2)->gbr, (sh2)->vbr, (sh2)->mach, (sh2)->macl); \
+ printf("%csh2 tmp-p %08x %08x %08x %08x %08x %08x %08x %08x\n", ms, \
+ (sh2)->drc_tmp, (sh2)->irq_cycles, \
+ (sh2)->pdb_io_csum[0], (sh2)->pdb_io_csum[1], (sh2)->state, \
+ (sh2)->poll_addr, (sh2)->poll_cycles, (sh2)->poll_cnt); \
+}
+static SH2 csh2[2][4];
static void REGPARM(3) *sh2_drc_log_entry(void *block, SH2 *sh2, u32 sr)
{
if (block != NULL) {
dbg(8, "= %csh2 enter %08x %p, c=%d", sh2->is_slave ? 's' : 'm',
sh2->pc, block, (signed int)sr >> 12);
+#if defined PDB
pdb_step(sh2, sh2->pc);
+#elif (DRC_DEBUG & 256)
+ {
+ static FILE *trace[2];
+ int idx = sh2->is_slave;
+if (sh2 != &sh2s[0] && sh2 != &sh2s[1]) printf("sh2 %p?\n",sh2);
+ if (!trace[0]) {
+ truncate("pico.trace", 0);
+ trace[0] = fopen("pico.trace0", "wb");
+ trace[1] = fopen("pico.trace1", "wb");
+ }
+ if (csh2[idx][0].pc != sh2->pc) {
+ fwrite(sh2, offsetof(SH2, read8_map), 1, trace[idx]);
+ fwrite(&sh2->pdb_io_csum, sizeof(sh2->pdb_io_csum), 1, trace[idx]);
+ memcpy(&csh2[idx][0], sh2, offsetof(SH2, icount));
+ }
+ }
+#elif (DRC_DEBUG & 512)
+ {
+ static FILE *trace[2];
+ static SH2 fsh2;
+ int idx = sh2->is_slave;
+ if (!trace[0]) {
+ trace[0] = fopen("pico.trace0", "rb");
+ trace[1] = fopen("pico.trace1", "rb");
+ }
+ if (csh2[idx][0].pc != sh2->pc) {
+ if (!fread(&fsh2, offsetof(SH2, read8_map), 1, trace[idx]) ||
+ !fread(&fsh2.pdb_io_csum, sizeof(sh2->pdb_io_csum), 1, trace[idx])) {
+ printf("trace eof at %08lx\n",ftell(trace[idx]));
+ exit(1);
+ }
+ fsh2.sr = (fsh2.sr & 0xfff) | (sh2->sr & ~0xfff);
+ fsh2.is_slave = idx;
+ if (memcmp(&fsh2, sh2, offsetof(SH2, read8_map)) ||
+ 0)//memcmp(&fsh2.pdb_io_csum, &sh2->pdb_io_csum, sizeof(sh2->pdb_io_csum)))
+ {
+ printf("difference at %08lx!\n",ftell(trace[idx]));
+ SH2_DUMP(&fsh2, "file");
+ SH2_DUMP(sh2, "current");
+ SH2_DUMP(&csh2[idx][0], "previous");
+ exit(1);
+ }
+ csh2[idx][0] = fsh2;
+ }
+ }
+#elif (DRC_DEBUG & 1024)
+ {
+ int x = sh2->is_slave, i;
+ for (i = 0; i < ARRAY_SIZE(csh2[x]); i++)
+ memcpy(&csh2[x][i], &csh2[x][i+1], offsetof(SH2, icount));
+ memcpy(&csh2[x][3], sh2, offsetof(SH2, icount));
+ }
+#endif
}
return block;
}
static u32 dr_gcregs_dirty;
#if PROPAGATE_CONSTANTS
+static void gconst_set(sh2_reg_e r, u32 val)
+{
+ dr_gcregs_mask |= 1 << r;
+ dr_gcregs[r] = val;
+}
+
static void gconst_new(sh2_reg_e r, u32 val)
{
int i;
- dr_gcregs_mask |= 1 << r;
+ gconst_set(r, val);
dr_gcregs_dirty |= 1 << r;
- dr_gcregs[r] = val;
// throw away old r that we might have cached
for (i = ARRAY_SIZE(reg_temp) - 1; i >= 0; i--) {
dr_gcregs_dirty &= ~(1 << r);
}
+#if PROPAGATE_CONSTANTS
+static void gconst_copy(sh2_reg_e rd, sh2_reg_e rs)
+{
+ u32 val;
+
+ gconst_kill(rd);
+ if (gconst_get(rs, &val))
+ gconst_set(rd, val);
+}
+#endif
+
static void gconst_clean(void)
{
int i;
reg_temp[i].flags &= ~HRF_LOCKED;
}
-#ifdef DRC_CMP
+#if (DRC_DEBUG & (8|256|512|1024)) || defined(DRC_CMP)
static u32 rcache_used_hreg_mask(void)
{
u32 mask = 0;
static void emit_move_r_r(sh2_reg_e dst, sh2_reg_e src)
{
int hr_d, hr_s;
- u32 val;
+ hr_s = rcache_get_reg(src, RC_GR_READ);
+ hr_d = rcache_get_reg(dst, RC_GR_WRITE);
+ emith_move_r_r(hr_d, hr_s);
#if PROPAGATE_CONSTANTS
- if (gconst_get(src, &val))
- gconst_new(dst, val);
- else
+ gconst_copy(dst, src);
#endif
- {
- hr_s = rcache_get_reg(src, RC_GR_READ);
- hr_d = rcache_get_reg(dst, RC_GR_WRITE);
- emith_move_r_r(hr_d, hr_s);
- }
}
// T must be clear, and comparison done just before this
rcache_clean();
-#ifndef DCR_SR_REG
+#ifndef DRC_SR_REG
// must writeback cycles for poll detection stuff
if (reg_map_g2h[SHR_SR] != -1)
emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
case 2: emith_call(sh2_drc_read32); break; // 32
}
rcache_invalidate();
-#ifndef DCR_SR_REG
+#ifndef DRC_SR_REG
if (reg_map_g2h[SHR_SR] != -1)
emith_ctx_read(reg_map_g2h[SHR_SR], SHR_SR * 4);
#endif
static void emit_memhandler_write(int size)
{
int arg2;
-#ifndef DCR_SR_REG
+#ifndef DRC_SR_REG
if (reg_map_g2h[SHR_SR] != -1)
emith_ctx_write(reg_map_g2h[SHR_SR], SHR_SR * 4);
#endif
}
rcache_invalidate();
-#ifndef DCR_SR_REG
+#ifndef DRC_SR_REG
if (reg_map_g2h[SHR_SR] != -1)
emith_ctx_read(reg_map_g2h[SHR_SR], SHR_SR * 4);
#endif
hr2 = rcache_get_tmp();
emith_move_r_imm(hr2, val);
} else {
- gconst_new(rd, val);
- hr2 = rcache_get_reg(rd, RC_GR_RMW);
+ emit_move_r_imm32(rd, val);
+ hr2 = rcache_get_reg(rd, RC_GR_READ);
}
return hr2;
}
if (gconst_get(rs, &val)) {
hr = emit_get_rbase_and_offs(val + offs, &offs2);
if (hr != -1) {
- hr2 = rcache_get_reg(rd, RC_GR_WRITE);
+ if (rd == SHR_TMP)
+ hr2 = rcache_get_tmp();
+ else
+ hr2 = rcache_get_reg(rd, RC_GR_WRITE);
switch (size) {
case 0: // 8
emith_read8s_r_r_offs(hr2, hr, offs2 ^ 1);
emith_add_r_imm(hr, offs);
}
hr = emit_memhandler_read(size);
- hr2 = rcache_get_reg(rd, RC_GR_WRITE);
- if (size != 2) {
+ if (rd == SHR_TMP)
+ hr2 = hr;
+ else
+ hr2 = rcache_get_reg(rd, RC_GR_WRITE);
+
+ if (rd != SHR_TMP && size != 2) {
emith_sext(hr2, hr, (size == 1) ? 16 : 8);
- } else
+ } else if (hr != hr2)
emith_move_r_r(hr2, hr);
- rcache_free_tmp(hr);
+ if (hr != hr2)
+ rcache_free_tmp(hr);
return hr2;
}
int hr;
u32 val;
+ rcache_clean(); // XXX
rcache_get_reg_arg(1, rd);
if (gconst_get(rs, &val)) {
else
hr2 = hr;
- if (size != 2) { // 16, 8
+ if (rd != SHR_TMP && size != 2) { // 16, 8
emith_sext(hr2, hr, size ? 16 : 8);
} else if (hr != hr2) // 32
emith_move_r_r(hr2, hr);
if (gconst_get(rx, &offs))
return emit_memhandler_write_rr(rd, ry, offs, size);
#endif
+ rcache_clean(); // XXX
rcache_get_reg_arg(1, rd);
a0 = rcache_get_reg_arg(0, rx);
t = rcache_get_reg(ry, RC_GR_READ);
/* just after lookup function, jump to address returned */
static void emit_block_entry(void)
{
-#if (DRC_DEBUG & 8) || defined(PDB)
- int arg1, arg2;
- host_arg2reg(arg1, 1);
- host_arg2reg(arg2, 2);
-
- emit_do_static_regs(1, arg2);
- emith_move_r_r_ptr(arg1, CONTEXT_REG);
- emith_move_r_r(arg2, rcache_get_reg(SHR_SR, RC_GR_READ));
- emith_call(sh2_drc_log_entry);
- rcache_invalidate();
-#endif
emith_tst_r_r_ptr(RET_REG, RET_REG);
EMITH_SJMP_START(DCOND_EQ);
emith_jump_reg_c(DCOND_NE, RET_REG);
emith_jump_cond(DCOND_LE, sh2_drc_exit);
do_host_disasm(tcache_id);
rcache_unlock_all();
+
+#if (DRC_DEBUG & (8|256|512|1024))
+ emit_move_r_imm32(SHR_PC, pc);
+ sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
+ FLUSH_CYCLES(sr);
+ rcache_clean();
+ tmp = rcache_used_hreg_mask();
+ emith_save_caller_regs(tmp);
+ emit_do_static_regs(1, 0);
+ rcache_get_reg_arg(2, SHR_SR);
+ tmp2 = rcache_get_tmp_arg(0);
+ tmp3 = rcache_get_tmp_arg(1);
+ emith_move_r_imm(tmp2, (u32)tcache_ptr);
+ emith_move_r_r_ptr(tmp3,CONTEXT_REG);
+ emith_call(sh2_drc_log_entry);
+ emith_restore_caller_regs(tmp);
+ rcache_invalidate();
+#endif
}
#ifdef DRC_CMP
emith_move_r_imm(tmp, pc);
emith_tst_r_imm(sr, T);
tmp2 = ops[i-1].op == OP_BRANCH_CT ? DCOND_NE : DCOND_EQ;
+ tmp3 = ops[i-1].op == OP_BRANCH_CT ? DCOND_EQ : DCOND_NE;
+ EMITH_SJMP_START(tmp3);
emith_move_r_imm_c(tmp2, tmp, ops[i-1].imm);
+ EMITH_SJMP_END(tmp3);
break;
case OP_BRANCH_N:
emit_move_r_imm32(SHR_PC, pc);
drcf.pending_branch_direct = 1;
} else {
emit_move_r_r(SHR_PC, opd->rm);
- ops[i+1].source |= SHR_PC; // need PC for jump after delay slot
drcf.pending_branch_indirect = 1;
}
goto end_op;
emith_move_r_r(tmp3, tmp);
}
emith_add_r_r(tmp, tmp2);
- ops[i+1].source |= SHR_PC; // need PC for jump after delay slot
drcf.pending_branch_indirect = 1;
}
goto end_op;
case OP_UNDEFINED:
elprintf_sh2(sh2, EL_ANOMALY,
"drc: illegal op %04x @ %08x", op, pc - 2);
- opd->imm = 4;
+ opd->imm = (op_flags[i] & OF_B_IN_DS) ? 6 : 4;
// fallthrough
case OP_TRAPA:
tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
// push PC
rcache_get_reg_arg(0, SHR_SP);
tmp = rcache_get_tmp_arg(1);
- emith_move_r_imm(tmp, pc);
+ if (op == OP_TRAPA)
+ emith_move_r_imm(tmp, pc);
+ else if (drcf.pending_branch_indirect) {
+ tmp2 = rcache_get_reg(SHR_PC, RC_GR_READ);
+ emith_move_r_r(tmp, tmp2);
+ } else
+ emith_move_r_imm(tmp, pc - 2);
emit_memhandler_write(2);
// obtain new PC
emit_memhandler_read_rr(SHR_PC, SHR_VBR, opd->imm * 4, 2);
goto end_op;
case 0x0f: // MAC.L @Rm+,@Rn+ 0000nnnnmmmm1111
emit_indirect_read_double(&tmp, &tmp2, GET_Rn(), GET_Rm(), 2);
-
sr = rcache_get_reg(SHR_SR, RC_GR_READ);
tmp3 = rcache_get_reg(SHR_MACL, RC_GR_RMW);
tmp4 = rcache_get_reg(SHR_MACH, RC_GR_RMW);
case 0x0e: // MULU.W Rm,Rn 0010nnnnmmmm1110
case 0x0f: // MULS.W Rm,Rn 0010nnnnmmmm1111
tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ);
+ tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
tmp = rcache_get_reg(SHR_MACL, RC_GR_WRITE);
if (op & 1) {
emith_sext(tmp, tmp2, 16);
} else
emith_clear_msb(tmp, tmp2, 16);
- tmp3 = rcache_get_reg(GET_Rm(), RC_GR_READ);
tmp2 = rcache_get_tmp();
if (op & 1) {
emith_sext(tmp2, tmp3, 16);
}
tmp2 = rcache_get_reg(GET_Rn(), RC_GR_RMW);
emith_sub_r_imm(tmp2, 4);
- rcache_clean();
+ rcache_clean(); // XXX
rcache_get_reg_arg(0, GET_Rn());
tmp3 = rcache_get_reg_arg(1, tmp);
if (tmp == SHR_SR)
emith_bic_r_imm(sr, T);
emith_cmp_r_imm(tmp, 0);
emit_or_t_if_eq(sr);
+ rcache_clean(); // XXX
emith_or_r_imm(tmp, 0x80);
tmp2 = rcache_get_tmp_arg(1); // assuming it differs to tmp
emith_move_r_r(tmp2, tmp);
goto end_op;
case 0x0800: // CMP/EQ #imm,R0 10001000iiiiiiii
// XXX: could use cmn
- tmp2 = rcache_get_reg(0, RC_GR_READ);
+ tmp2 = rcache_get_reg(SHR_R0, RC_GR_READ);
sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
emith_bic_r_imm(sr, T);
emith_cmp_r_imm(tmp2, (s8)(op & 0xff));
default:
default_:
- if (!(op_flags[i] & OF_B_IN_DS))
+ if (!(op_flags[i] & OF_B_IN_DS)) {
elprintf_sh2(sh2, EL_ANOMALY,
"drc: illegal op %04x @ %08x", op, pc - 2);
exit(1);
+ }
}
end_op:
void sh2_drc_flush_all(void)
{
+#if (DRC_DEBUG & 1024)
+ int i;
+ printf("backtrace master:\n");
+ for (i = 0; i < ARRAY_SIZE(csh2[0]); i++)
+ SH2_DUMP(&csh2[0][i], "bt msh2");
+ printf("backtrace slave:\n");
+ for (i = 0; i < ARRAY_SIZE(csh2[1]); i++)
+ SH2_DUMP(&csh2[1][i], "bt ssh2");
+#endif
block_stats();
flush_tcache(0);
flush_tcache(1);
if (op_flags[i] & OF_DELAY_OP) {
switch (opd->op) {
case OP_BRANCH:
+ case OP_BRANCH_N:
case OP_BRANCH_CT:
case OP_BRANCH_CF:
case OP_BRANCH_R:
case OP_BRANCH_RF:
elprintf(EL_ANOMALY, "%csh2 drc: branch in DS @ %08x",
is_slave ? 's' : 'm', pc);
- opd->op = OP_UNHANDLED;
+ opd->op = OP_UNDEFINED;
op_flags[i] |= OF_B_IN_DS;
next_is_delay = 0;
break;