#define MAX_LITERALS (BLOCK_INSN_LIMIT / 4)
#define MAX_LOCAL_BRANCHES 32
-static int literal_disabled_frames;
-
// debug stuff
// 1 - warnings/errors
// 2 - block info/smc
#ifdef DRC_SH2
+static int literal_disabled_frames;
+
#if (DRC_DEBUG & 4)
static u8 *tcache_dsm_ptrs[3];
static char sh2dasm_buff[64];
#ifdef __arm__
#include "../drc/emit_arm.c"
+#ifndef __MACH__
+
static const int reg_map_g2h[] = {
4, 5, 6, 7,
8, -1, -1, -1,
-1, -1, -1, -1, // SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
};
+#else
+
+// no r9..
+static const int reg_map_g2h[] = {
+ 4, 5, 6, 7,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ -1, -1, -1, 8, // r12 .. sp
+ -1, -1, -1, 10, // SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
+ -1, -1, -1, -1, // SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
+};
+
+#endif
+
static temp_reg_t reg_temp[] = {
{ 0, },
{ 1, },
static u32 REGPARM(2) (*sh2_drc_read32)(u32 a, SH2 *sh2);
static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
-static int REGPARM(3) (*sh2_drc_write32)(u32 a, u32 d, SH2 *sh2);
+static void REGPARM(3) (*sh2_drc_write32)(u32 a, u32 d, SH2 *sh2);
// address space stuff
static int dr_ctx_get_mem_ptr(u32 a, u32 *mask)
}
else if ((a & 0xfffff000) == 0xc0000000) {
// data array
+ // FIXME: access sh2->data_array instead
poffs = offsetof(SH2, p_da);
*mask = 0xfff;
}
// reg cache must be clean before call
static int emit_memhandler_read_(int size, int ram_check)
{
- int arg0, arg1;
+ int arg1;
+#if 0
+ int arg0;
host_arg2reg(arg0, 0);
+#endif
rcache_clean();
return hr2;
}
-static void emit_memhandler_write(int size, u32 pc)
+static void emit_memhandler_write(int size)
{
int ctxr;
host_arg2reg(ctxr, 2);
if (delay_dep_bk & BITMASK1(SHR_PC)) {
if (opd->op != OP_LOAD_POOL && opd->op != OP_MOVA) {
// can only be those 2 really..
- elprintf(EL_ANOMALY, "%csh2 drc: illegal slot insn %04x @ %08x?",
- sh2->is_slave ? 's' : 'm', op, pc - 2);
+ elprintf_sh2(sh2, EL_ANOMALY,
+ "drc: illegal slot insn %04x @ %08x?", op, pc - 2);
}
if (opd->imm != 0)
; // addr already resolved somehow
tmp2 = rcache_get_reg_arg(0, SHR_R0);
tmp3 = rcache_get_reg(GET_Rn(), RC_GR_READ);
emith_add_r_r(tmp2, tmp3);
- emit_memhandler_write(op & 3, pc);
+ emit_memhandler_write(op & 3);
goto end_op;
case 0x07:
// MUL.L Rm,Rn 0000nnnnmmmm0111
tmp2 = rcache_get_reg_arg(1, GET_Rm());
if (op & 0x0f)
emith_add_r_imm(tmp, (op & 0x0f) * 4);
- emit_memhandler_write(2, pc);
+ emit_memhandler_write(2);
goto end_op;
case 0x02:
rcache_clean();
rcache_get_reg_arg(0, GET_Rn());
rcache_get_reg_arg(1, GET_Rm());
- emit_memhandler_write(op & 3, pc);
+ emit_memhandler_write(op & 3);
goto end_op;
case 0x04: // MOV.B Rm,@-Rn 0010nnnnmmmm0100
case 0x05: // MOV.W Rm,@-Rn 0010nnnnmmmm0101
emith_sub_r_imm(tmp, (1 << (op & 3)));
rcache_clean();
rcache_get_reg_arg(0, GET_Rn());
- emit_memhandler_write(op & 3, pc);
+ emit_memhandler_write(op & 3);
goto end_op;
case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
sr = rcache_get_reg(SHR_SR, RC_GR_RMW);
tmp3 = rcache_get_reg_arg(1, tmp);
if (tmp == SHR_SR)
emith_clear_msb(tmp3, tmp3, 22); // reserved bits defined by ISA as 0
- emit_memhandler_write(2, pc);
+ emit_memhandler_write(2);
goto end_op;
case 0x04:
case 0x05:
emith_move_r_r(tmp2, tmp);
rcache_free_tmp(tmp);
rcache_get_reg_arg(0, GET_Rn());
- emit_memhandler_write(0, pc);
+ emit_memhandler_write(0);
break;
default:
goto default_;
tmp3 = (op & 0x100) >> 8;
if (op & 0x0f)
emith_add_r_imm(tmp, (op & 0x0f) << tmp3);
- emit_memhandler_write(tmp3, pc);
+ emit_memhandler_write(tmp3);
goto end_op;
case 0x0400: // MOV.B @(disp,Rm),R0 10000100mmmmdddd
case 0x0500: // MOV.W @(disp,Rm),R0 10000101mmmmdddd
tmp2 = rcache_get_reg_arg(1, SHR_R0);
tmp3 = (op & 0x300) >> 8;
emith_add_r_imm(tmp, (op & 0xff) << tmp3);
- emit_memhandler_write(tmp3, pc);
+ emit_memhandler_write(tmp3);
goto end_op;
case 0x0400: // MOV.B @(disp,GBR),R0 11000100dddddddd
case 0x0500: // MOV.W @(disp,GBR),R0 11000101dddddddd
emith_add_r_imm(tmp, 4);
tmp = rcache_get_reg_arg(1, SHR_SR);
emith_clear_msb(tmp, tmp, 22);
- emit_memhandler_write(2, pc);
+ emit_memhandler_write(2);
// push PC
rcache_get_reg_arg(0, SHR_SP);
tmp = rcache_get_tmp_arg(1);
emith_move_r_imm(tmp, pc);
- emit_memhandler_write(2, pc);
+ emit_memhandler_write(2);
// obtain new PC
emit_memhandler_read_rr(SHR_PC, SHR_VBR, (op & 0xff) * 4, 2);
// indirect jump -> back to dispatcher
tmp3 = rcache_get_reg_arg(0, SHR_GBR);
tmp4 = rcache_get_reg(SHR_R0, RC_GR_READ);
emith_add_r_r(tmp3, tmp4);
- emit_memhandler_write(0, pc);
+ emit_memhandler_write(0);
goto end_op;
}
goto default_;
default:
default_:
- elprintf(EL_ANOMALY, "%csh2 drc: unhandled op %04x @ %08x",
- sh2->is_slave ? 's' : 'm', op, pc - 2);
+ if (!(op_flags[i] & OF_B_IN_DS))
+ elprintf_sh2(sh2, EL_ANOMALY,
+ "drc: illegal op %04x @ %08x", op, pc - 2);
+
+ tmp = rcache_get_reg(SHR_SP, RC_GR_RMW);
+ emith_sub_r_imm(tmp, 4*2);
+ // push SR
+ tmp = rcache_get_reg_arg(0, SHR_SP);
+ emith_add_r_imm(tmp, 4);
+ tmp = rcache_get_reg_arg(1, SHR_SR);
+ emith_clear_msb(tmp, tmp, 22);
+ emit_memhandler_write(2);
+ // push PC
+ rcache_get_reg_arg(0, SHR_SP);
+ tmp = rcache_get_tmp_arg(1);
+ 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
+ v = (op_flags[i] & OF_B_IN_DS) ? 6 : 4;
+ emit_memhandler_read_rr(SHR_PC, SHR_VBR, v * 4, 2);
+ // indirect jump -> back to dispatcher
+ rcache_flush();
+ emith_jump(sh2_drc_dispatcher);
break;
}
1 + cpuid, SH2_DRCBLK_DA_SHIFT, 0xfff);
}
-int sh2_execute(SH2 *sh2c, int cycles)
+int sh2_execute_drc(SH2 *sh2c, int cycles)
{
int ret_cycles;
- sh2c->cycles_timeslice = cycles;
-
// cycles are kept in SHR_SR unused bits (upper 20)
// bit11 contains T saved for delay slot
// others are usual SH2 flags
if (ret_cycles > 0)
dbg(1, "warning: drc returned with cycles: %d", ret_cycles);
- return sh2c->cycles_timeslice - ret_cycles;
+ sh2c->sr &= 0x3f3;
+ return ret_cycles;
}
#if (DRC_DEBUG & 2)
void sh2_drc_mem_setup(SH2 *sh2)
{
// fill the convenience pointers
- sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
- sh2->p_da = Pico32xMem->data_array[sh2->is_slave];
+ sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
+ sh2->p_da = sh2->data_array;
sh2->p_sdram = Pico32xMem->sdram;
sh2->p_rom = Pico.rom;
}
if ((pc & ~0x7ff) == 0) {
// BIOS
- ret = is_slave ? Pico32xMem->sh2_rom_s : Pico32xMem->sh2_rom_m;
+ ret = is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
mask = 0x7ff;
}
else if ((pc & 0xfffff000) == 0xc0000000) {
// data array
- ret = Pico32xMem->data_array[is_slave];
+ ret = sh2s[is_slave].data_array;
mask = 0xfff;
}
else if ((pc & 0xc6000000) == 0x06000000) {
}
else if ((pc & 0xc6000000) == 0x02000000) {
// ROM
- ret = Pico.rom;
+ if ((pc & 0x3fffff) < Pico.romsize)
+ ret = Pico.rom;
mask = 0x3fffff;
}
u16 *dr_pc_base;
u32 pc, op, tmp;
u32 end_pc, end_literals = 0;
+ u32 lowest_mova = 0;
struct op_data *opd;
int next_is_delay = 0;
int end_block = 0;
tmp = 0;
}
opd->dest = BITMASK1(SHR_R0);
- if (tmp)
+ if (tmp) {
opd->imm = (tmp + 2 + (op & 0xff) * 4) & ~3;
+ if (opd->imm >= base_pc) {
+ if (lowest_mova == 0 || opd->imm < lowest_mova)
+ lowest_mova = opd->imm;
+ }
+ }
break;
case 0x0800: // TST #imm,R0 11001000iiiiiiii
opd->source = BITMASK1(SHR_R0);
is_slave ? 's' : 'm', op, pc);
break;
}
+
+ if (op_flags[i] & OF_DELAY_OP) {
+ switch (opd->op) {
+ case OP_BRANCH:
+ 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;
+ op_flags[i] |= OF_B_IN_DS;
+ next_is_delay = 0;
+ break;
+ }
+ }
}
i_end = i;
end_pc = pc;
if (end_literals < end_pc)
end_literals = end_pc;
+ // end_literals is used to decide to inline a literal or not
+ // XXX: need better detection if this actually is used in write
+ if (lowest_mova >= base_pc) {
+ if (lowest_mova < end_literals) {
+ dbg(1, "mova for %08x, block %08x", lowest_mova, base_pc);
+ end_literals = end_pc;
+ }
+ if (lowest_mova < end_pc) {
+ dbg(1, "warning: mova inside of blk for %08x, block %08x",
+ lowest_mova, base_pc);
+ end_literals = end_pc;
+ }
+ }
+
*end_pc_out = end_pc;
if (end_literals_out != NULL)
*end_literals_out = end_literals;