From adf39a13f9f62629d767f1f7f73f4f41fc590219 Mon Sep 17 00:00:00 2001 From: kub Date: Wed, 22 May 2019 21:04:59 +0200 Subject: [PATCH] sh2 drc, register cache optimisations --- cpu/sh2/compiler.c | 317 ++++++++++++++++++++++++--------------------- pico/32x/memory.c | 26 ++++ pico/pico_int.h | 1 + 3 files changed, 195 insertions(+), 149 deletions(-) diff --git a/cpu/sh2/compiler.c b/cpu/sh2/compiler.c index 2e6aa7c9..9160c90c 100644 --- a/cpu/sh2/compiler.c +++ b/cpu/sh2/compiler.c @@ -138,10 +138,11 @@ enum op_types { OP_MOVE, // register move OP_LOAD_CONST,// load const to register OP_LOAD_POOL, // literal pool load, imm is address - OP_MOVA, - OP_SLEEP, - OP_RTE, - OP_TRAPA, + OP_MOVA, // MOVA instruction + OP_SLEEP, // SLEEP instruction + OP_RTE, // RTE instruction + OP_TRAPA, // TRAPA instruction + OP_LDC, // LDC instruction OP_UNDEFINED, }; @@ -552,31 +553,25 @@ static int dr_is_rom(u32 a) return (a & 0xc6000000) == 0x02000000 && (a & 0x3f0000) < 0x3e0000; } -static int dr_ctx_get_mem_ptr(u32 a, u32 *mask) +static int dr_ctx_get_mem_ptr(SH2 *sh2, u32 a, u32 *mask) { + void *memptr; int poffs = -1; - if ((a & ~0x7ff) == 0) { - // BIOS + // check if region is mapped memory + memptr = p32x_sh2_get_mem_ptr(a, mask, sh2); + if (memptr == NULL /*|| (a & ((1 << SH2_READ_SHIFT)-1) & ~*mask) != 0*/) + return poffs; + + if (memptr == sh2->p_bios) // BIOS poffs = offsetof(SH2, p_bios); - *mask = 0x7ff; - } - else if ((a & 0xfffff000) == 0xc0000000) { - // data array + else if (memptr == sh2->p_da) // data array // FIXME: access sh2->data_array instead poffs = offsetof(SH2, p_da); - *mask = 0xfff; - } - else if ((a & 0xc6000000) == 0x06000000) { - // SDRAM + else if (memptr == sh2->p_sdram) // SDRAM poffs = offsetof(SH2, p_sdram); - *mask = 0x03ffff; - } - else if ((a & 0xc6000000) == 0x02000000) { - // ROM + else if (memptr == sh2->p_rom) // ROM poffs = offsetof(SH2, p_rom); - *mask = 0x3fffff; - } return poffs; } @@ -1365,6 +1360,7 @@ static u32 rcache_locked; static u32 rcache_hint_soon; static u32 rcache_hint_late; static u32 rcache_hint_write; +static u32 rcache_hint_clean; #define rcache_hint (rcache_hint_soon|rcache_hint_late) static void rcache_unmap_vreg(int x) @@ -1396,16 +1392,19 @@ static void rcache_clean_vreg(int x) emith_move_r_r(cache_regs[guest_regs[r].sreg].hreg, cache_regs[guest_regs[r].vreg].hreg); rcache_remove_vreg_alias(x, r); rcache_add_vreg_alias(guest_regs[r].sreg, r); + cache_regs[guest_regs[r].sreg].flags |= HRF_DIRTY; } else { // must evict since sreg is locked emith_ctx_write(cache_regs[x].hreg, r * 4); + guest_regs[r].flags &= ~GRF_DIRTY; guest_regs[r].vreg = -1; } } - } else + } else if (~rcache_hint_write & (1 << r)) { emith_ctx_write(cache_regs[x].hreg, r * 4); - } - guest_regs[r].flags &= ~GRF_DIRTY;) + guest_regs[r].flags &= ~GRF_DIRTY; + } + }) } } @@ -1654,7 +1653,7 @@ static int rcache_get_reg_(sh2_reg_e r, rc_gr_mode mode, int do_locking, int *hr (cache_regs[i].flags & HRF_LOCKED) || (cache_regs[i].type == HR_STATIC && !(guest_regs[r].flags & GRF_STATIC))) { // need to split up. take reg out here to avoid unnecessary writebacks - cache_regs[i].gregs &= ~(1 << r); + rcache_remove_vreg_alias(i, r); split = i; } else { // aliases not needed anytime soon, remove them @@ -1809,7 +1808,8 @@ static int rcache_get_reg_arg(int arg, sh2_reg_e r, int *hr) // r is needed later on anyway srcr = rcache_get_reg_(r, RC_GR_READ, 0, NULL); is_cached = (cache_regs[reg_map_host[srcr]].type == HR_CACHED); - } else if ((guest_regs[r].flags & GRF_CDIRTY) && gconst_get(r, &val)) { + } else if (!(rcache_hint_clean & (1 << r)) && + (guest_regs[r].flags & GRF_CDIRTY) && gconst_get(r, &val)) { // r has an uncomitted const - load into arg, but keep constant uncomitted srcr = dstr; is_const = 1; @@ -1822,7 +1822,7 @@ static int rcache_get_reg_arg(int arg, sh2_reg_e r, int *hr) srcr = dstr; if (rcache_static & (1 << r)) srcr = rcache_get_reg_(r, RC_GR_READ, 0, NULL); - else if (gconst_try_read(guest_regs[r].vreg, r)) + else if (gconst_try_read(dstid, r)) dirty = 1; else emith_ctx_read(srcr, r * 4); @@ -1856,14 +1856,18 @@ static int rcache_get_reg_arg(int arg, sh2_reg_e r, int *hr) } else if (hr != NULL) { // caller will modify arg, so it will soon be out of sync with r if (dirty || src_dirty) { - emith_ctx_write(dstr, r * 4); // must clean since arg will be modified - guest_regs[r].flags &= ~GRF_DIRTY; + if (~rcache_hint_write & (1 << r)) { + emith_ctx_write(dstr, r * 4); // must clean since arg will be modified + guest_regs[r].flags &= ~GRF_DIRTY; + } } - } else if (guest_regs[r].vreg < 0) { + } else { // keep arg as vreg for r cache_regs[dstid].type = HR_CACHED; - cache_regs[dstid].gregs = 1 << r; - guest_regs[r].vreg = dstid; + if (guest_regs[r].vreg < 0) { + cache_regs[dstid].gregs = 1 << r; + guest_regs[r].vreg = dstid; + } if (dirty || src_dirty) { // mark as modifed for cleaning later on cache_regs[dstid].flags |= HRF_DIRTY; guest_regs[r].flags |= GRF_DIRTY; @@ -2057,9 +2061,9 @@ static void rcache_clean_mask(u32 mask) { int i; - // XXX consider gconst? - if (!(mask &= ~rcache_static & ~gconst_dirty_mask())) + if (!(mask &= ~rcache_static)) return; + rcache_hint_clean |= mask; // clean only vregs where all aliases are covered by the mask for (i = 0; i < ARRAY_SIZE(cache_regs); i++) @@ -2120,7 +2124,7 @@ static void rcache_invalidate(void) } rcache_counter = 0; - rcache_hint_soon = rcache_hint_late = rcache_hint_write = 0; + rcache_hint_soon = rcache_hint_late = rcache_hint_write = rcache_hint_clean = 0; gconst_invalidate(); } @@ -2164,48 +2168,76 @@ static void rcache_init(void) // --------------------------------------------------------------- -static int emit_get_rbase_and_offs(SH2 *sh2, u32 a, u32 *offs) +// NB may return either REG or TEMP +static int emit_get_rbase_and_offs(SH2 *sh2, sh2_reg_e r, int rmod, u32 *offs) { - u32 omask = 0xff; // offset mask, XXX: ARM oriented.. + uptr omask = 0xff; // offset mask, XXX: ARM oriented.. u32 mask = 0; + u32 a; int poffs; - int hr; - unsigned long la; + int hr, hr2; + uptr la; - poffs = dr_ctx_get_mem_ptr(a, &mask); + // is r constant and points to a memory region? + if (! gconst_get(r, &a)) + return -1; + poffs = dr_ctx_get_mem_ptr(sh2, a, &mask); if (poffs == -1) return -1; - hr = rcache_get_tmp(); if (mask < 0x1000) { - // can't access data array or BIOS directly from ROM or SDRAM, - // since code may run on both SH2s (tcache_id of translation block needed)) + // data array or BIOS, can't safely access directly since translated code + // may run on both SH2s + hr = rcache_get_tmp(); emith_ctx_read_ptr(hr, poffs); + a += *offs; if (a & mask & ~omask) emith_add_r_r_ptr_imm(hr, hr, a & mask & ~omask); *offs = a & omask; + return hr; + } + + la = (uptr)*(void **)((char *)sh2 + poffs); + // accessing ROM or SDRAM, code location doesn't matter. The host address + // for these should be mmapped to be equal to the SH2 address. + // if r is in rcache or needed soon anyway, and offs is relative to region + // use rcached const to avoid loading a literal on ARM + if ((guest_regs[r].vreg >= 0 || ((guest_regs[r].flags & GRF_CDIRTY) && + ((rcache_hint_soon|rcache_hint_clean) & (1 << r)))) && !(*offs & ~mask)) { + u32 odd = a & 1; // need to fix odd address for correct byte addressing + la -= (s32)((a & ~mask) - *offs - odd); // diff between reg and memory + // if reg is modified later on, allocate it RMW to remove aliases here + // else the aliases vreg stays locked and a vreg shortage may occur. + hr = hr2 = rcache_get_reg(r, rmod ? RC_GR_RMW : RC_GR_READ, NULL); + if ((la & ~omask) - odd) { + hr = rcache_get_tmp(); + emith_add_r_r_ptr_imm(hr, hr2, (la & ~omask) - odd); + } + *offs = (la & omask); } else { // known fixed host address - la = (unsigned long)*(void **)((char *)sh2 + poffs) + (a & mask); - *offs = la & omask; + la += (a + *offs) & mask; + hr = rcache_get_tmp(); emith_move_r_ptr_imm(hr, la & ~omask); + *offs = la & omask; } return hr; } // read const data from const ROM address -static int emit_get_rom_data(sh2_reg_e r, u32 offs, int size, u32 *val) +static int emit_get_rom_data(SH2 *sh2, sh2_reg_e r, u32 offs, int size, u32 *val) { - u32 tmp; + u32 a, mask; *val = 0; - if (gconst_get(r, &tmp)) { - tmp += offs; - if (dr_is_rom(tmp)) { + if (gconst_get(r, &a)) { + a += offs; + // check if rom is memory mapped (not bank switched), and address is in rom + if (dr_is_rom(a) && p32x_sh2_get_mem_ptr(a, &mask, sh2)) { switch (size & MF_SIZEMASK) { - case 0: *val = (s8)p32x_sh2_read8(tmp, sh2s); break; // 8 - case 1: *val = (s16)p32x_sh2_read16(tmp, sh2s); break; // 16 - case 2: *val = p32x_sh2_read32(tmp, sh2s); break; // 32 + case 0: *val = (s8)p32x_sh2_read8(a, sh2s); break; // 8 + case 1: *val = (s16)p32x_sh2_read16(a, sh2s); break; // 16 + case 2: *val = p32x_sh2_read32(a, sh2s); break; // 32 } return 1; } @@ -2315,10 +2347,10 @@ static void emit_memhandler_write(int size) static int emit_memhandler_read_rr(SH2 *sh2, sh2_reg_e rd, sh2_reg_e rs, u32 offs, int size) { int hr, hr2; - u32 val, offs2; + u32 val; #if PROPAGATE_CONSTANTS - if (emit_get_rom_data(rs, offs, size, &val)) { + if (emit_get_rom_data(sh2, rs, offs, size, &val)) { if (rd == SHR_TMP) { hr2 = rcache_get_tmp(); emith_move_r_imm(hr2, val); @@ -2331,47 +2363,49 @@ static int emit_memhandler_read_rr(SH2 *sh2, sh2_reg_e rd, sh2_reg_e rs, u32 off return hr2; } - if (gconst_get(rs, &val)) { - hr = emit_get_rbase_and_offs(sh2, val + offs, &offs2); - if (hr != -1) { - if (rd == SHR_TMP) - hr2 = rcache_get_tmp(); - else - hr2 = rcache_get_reg(rd, RC_GR_WRITE, NULL); - switch (size & MF_SIZEMASK) { - case 0: // 8 - emith_read8s_r_r_offs(hr2, hr, offs2 ^ 1); - break; - case 1: // 16 - emith_read16s_r_r_offs(hr2, hr, offs2); - break; - case 2: // 32 - emith_read_r_r_offs(hr2, hr, offs2); - emith_ror(hr2, hr2, 16); - break; - } + hr = emit_get_rbase_and_offs(sh2, rs, size & MF_POSTINCR, &offs); + if (hr != -1) { + if (rd == SHR_TMP) + hr2 = rcache_get_tmp(); + else + hr2 = rcache_get_reg(rd, RC_GR_WRITE, NULL); + switch (size & MF_SIZEMASK) { + case 0: emith_read8s_r_r_offs(hr2, hr, offs ^ 1); break; // 8 + case 1: emith_read16s_r_r_offs(hr2, hr, offs); break; // 16 + case 2: emith_read_r_r_offs(hr2, hr, offs); emith_ror(hr2, hr2, 16); break; + } + if (cache_regs[reg_map_host[hr]].type == HR_TEMP) // may also return REG rcache_free_tmp(hr); - if (size & MF_POSTINCR) + if (size & MF_POSTINCR) { + int isgc = gconst_get(rs, &val); + if (!isgc || guest_regs[rs].vreg >= 0) { + // already loaded + hr = rcache_get_reg(rs, RC_GR_RMW, NULL); + emith_add_r_r_imm(hr, hr, 1 << (size & MF_SIZEMASK)); + if (isgc) + gconst_set(rs, val + (1 << (size & MF_SIZEMASK))); + } else gconst_new(rs, val + (1 << (size & MF_SIZEMASK))); - return hr2; } + return hr2; } #endif - if (gconst_get(rs, &val) && (!(size & MF_POSTINCR) /*|| !(rcache_hint_soon & (1 << rs))*/)) { + + if (gconst_get(rs, &val) && guest_regs[rs].vreg < 0 && !(rcache_hint_soon & (1 << rs))) { hr = rcache_get_tmp_arg(0); emith_move_r_imm(hr, val + offs); if (size & MF_POSTINCR) gconst_new(rs, val + (1 << (size & MF_SIZEMASK))); - } else if (offs || (size & MF_POSTINCR)) { + } else if (size & MF_POSTINCR) { + hr = rcache_get_tmp_arg(0); + hr2 = rcache_get_reg(rs, RC_GR_RMW, NULL); + emith_add_r_r_imm(hr, hr2, offs); + emith_add_r_imm(hr2, 1 << (size & MF_SIZEMASK)); + } else { hr = rcache_get_reg_arg(0, rs, &hr2); if (offs || hr != hr2) emith_add_r_r_imm(hr, hr2, offs); - if (size & MF_POSTINCR) { - hr = rcache_get_reg(rs, RC_GR_WRITE, NULL); - emith_add_r_r_imm(hr, hr2, 1 << (size & MF_SIZEMASK)); - } - } else - rcache_get_reg_arg(0, rs, NULL); + } hr = emit_memhandler_read(size); size &= MF_SIZEMASK; @@ -2405,7 +2439,7 @@ static void emit_memhandler_write_rr(SH2 *sh2, sh2_reg_e rd, sh2_reg_e rs, u32 o } else hr2 = rcache_get_reg_arg(1, rd, NULL); - if (gconst_get(rs, &val) && (!(size & MF_PREDECR) /*|| !(rcache_hint_soon & (1 << rs))*/)) { + if (gconst_get(rs, &val) && guest_regs[rs].vreg < 0 && !(rcache_hint_soon & (1 << rs))) { if (size & MF_PREDECR) { val -= 1 << (size & MF_SIZEMASK); gconst_new(rs, val); @@ -2551,7 +2585,7 @@ static void emit_block_entry(void) cycles = 0; \ } -static void *dr_get_pc_base(u32 pc, int is_slave); +static void *dr_get_pc_base(u32 pc, SH2 *sh2); static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) { @@ -2591,7 +2625,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) base_pc = sh2->pc; // get base/validate PC - dr_pc_base = dr_get_pc_base(base_pc, sh2->is_slave); + dr_pc_base = dr_get_pc_base(base_pc, sh2); if (dr_pc_base == (void *)-1) { printf("invalid PC, aborting: %08x\n", base_pc); // FIXME: be less destructive @@ -2637,6 +2671,8 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) op_flags[i] &= ~OF_BTARGET; if (op_flags[i] & OF_BTARGET) ADD_TO_ARRAY(branch_target_pc, branch_target_count, pc, ); + if (ops[i].op == OP_LDC && (ops[i].dest & BITMASK1(SHR_SR)) && pc+2 < end_pc) + op_flags[i+1] |= OF_BTARGET; // RTE entrypoint in case of SR(IMASK) change #if LOOP_DETECTION // loop types detected: // 1. target: ... BRA target -> idle loop @@ -2930,7 +2966,8 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) u32 late = 0; // regs read by future ops u32 write = 0; // regs written to (to detect write before read) u32 soon = 0; // regs read soon - tmp = OP_ISBRANCH(opd[0].op); // branch insn detected + tmp = (OP_ISBRANCH(opd[0].op) || opd[0].op == OP_RTE || // branching insns + opd[0].op == OP_TRAPA || opd[0].op == OP_UNDEFINED); for (v = 1; v <= 9; v++) { // no sense in looking any further than the next rcache flush if (pc + 2*v < end_pc && !(op_flags[i+v] & OF_BTARGET) && @@ -2944,7 +2981,6 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) rcache_clean_mask(rcache_dirty_mask() & ~tmp2); break; } - // XXX must also include test-irq locations! tmp |= (OP_ISBRANCH(opd[v].op) || opd[v].op == OP_RTE || opd[v].op == OP_TRAPA || opd[v].op == OP_UNDEFINED); // regs needed in the next few instructions @@ -2953,7 +2989,8 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) } rcache_set_hint_soon(late); // insns 1-3 rcache_set_hint_late(late & ~soon); // insns 4-9 - rcache_set_hint_write(write & ~(late|soon)); // next access is write + rcache_set_hint_write(write & ~(late|soon) & ~opd[0].source); + // overwritten without being used } rcache_set_locked(opd[0].source); // try not to evict src regs for this op @@ -2973,32 +3010,22 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) case OP_BRANCH_R: if (opd->dest & BITMASK1(SHR_PR)) emit_move_r_imm32(SHR_PR, pc + 2); - if (gconst_get(opd->rm, &u)) { - opd->imm = u; - drcf.pending_branch_direct = 1; - } else { - emit_move_r_r(SHR_PC, opd->rm); - drcf.pending_branch_indirect = 1; - } + emit_move_r_r(SHR_PC, opd->rm); + drcf.pending_branch_indirect = 1; goto end_op; case OP_BRANCH_RF: - if (gconst_get(GET_Rn(), &u)) { - if (opd->dest & BITMASK1(SHR_PR)) - emit_move_r_imm32(SHR_PR, pc + 2); - opd->imm = pc + 2 + u; - drcf.pending_branch_direct = 1; - } else { - tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ, NULL); - tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE, NULL); - emith_move_r_imm(tmp, pc + 2); - if (opd->dest & BITMASK1(SHR_PR)) { - tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE, NULL); - emith_move_r_r(tmp3, tmp); - } - emith_add_r_r(tmp, tmp2); - drcf.pending_branch_indirect = 1; + tmp2 = rcache_get_reg(GET_Rn(), RC_GR_READ, NULL); + tmp = rcache_get_reg(SHR_PC, RC_GR_WRITE, NULL); + emith_move_r_imm(tmp, pc + 2); + if (opd->dest & BITMASK1(SHR_PR)) { + tmp3 = rcache_get_reg(SHR_PR, RC_GR_WRITE, NULL); + emith_move_r_r(tmp3, tmp); } + emith_add_r_r(tmp, tmp2); + if (gconst_get(GET_Rn(), &u)) + gconst_set(SHR_PC, pc + 2 + u); + drcf.pending_branch_indirect = 1; goto end_op; case OP_SLEEP: // SLEEP 0000000000011011 @@ -3041,10 +3068,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) // obtain new PC emit_memhandler_read_rr(sh2, SHR_PC, SHR_VBR, opd->imm * 4, 2); // indirect jump -> back to dispatcher - sr = rcache_get_reg(SHR_SR, RC_GR_RMW, NULL); - FLUSH_CYCLES(sr); - rcache_flush(); - emith_jump(sh2_drc_dispatcher); + drcf.pending_branch_indirect = 1; goto end_op; case OP_LOAD_POOL: @@ -3483,7 +3507,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) if (drcf.delay_reg == -1) drcf.delay_reg = GET_Rn(); else - drcf.loop_type = 0; + drcf.polling = drcf.loop_type = 0; } #endif emith_bic_r_imm(sr, T); @@ -3925,8 +3949,6 @@ end_op: emit_move_r_imm32(SHR_PC, pc); rcache_flush(); emith_call(sh2_drc_test_irq); - if (pc < end_pc) // mark next insns as entry point for RTE - op_flags[i+1] |= OF_BTARGET; drcf.test_irq = 0; } @@ -3950,7 +3972,7 @@ end_op: { // idle or delay loop emith_sh2_delay_loop(cycles, drcf.delay_reg); - drcf.loop_type = 0; + drcf.polling = drcf.loop_type = 0; } #endif @@ -4011,15 +4033,30 @@ end_op: drcf.pending_branch_direct = 0; if (target_pc >= base_pc && target_pc < pc) - drcf.loop_type = 0; + drcf.polling = drcf.loop_type = 0; } else if (drcf.pending_branch_indirect) { + struct op_data *opd_b = + (op_flags[i] & OF_DELAY_OP) ? opd-1 : opd; + void *target; + u32 target_pc; + sr = rcache_get_reg(SHR_SR, RC_GR_RMW, NULL); FLUSH_CYCLES(sr); - rcache_flush(); - emith_jump(sh2_drc_dispatcher); + rcache_clean(); + if (gconst_get(SHR_PC, &target_pc)) { + // JMP const, treat like unconditional direct branch + target = dr_prepare_ext_branch(block->entryp, target_pc, sh2->is_slave, tcache_id); + if (target == NULL) + return NULL; + emith_jump_patchable(target); + } else { + // JMP + emith_jump(sh2_drc_dispatcher); + } + rcache_invalidate(); drcf.pending_branch_indirect = 0; - drcf.loop_type = 0; + drcf.polling = drcf.loop_type = 0; } do_host_disasm(tcache_id); @@ -4836,33 +4873,12 @@ void sh2_drc_finish(SH2 *sh2) #endif /* DRC_SH2 */ -static void *dr_get_pc_base(u32 pc, int is_slave) +static void *dr_get_pc_base(u32 pc, SH2 *sh2) { void *ret = NULL; u32 mask = 0; - if ((pc & ~0x7ff) == 0) { - // BIOS - ret = is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w; - mask = 0x7ff; - } - else if ((pc & 0xfffff000) == 0xc0000000) { - // data array - ret = sh2s[is_slave].data_array; - mask = 0xfff; - } - else if ((pc & 0xc6000000) == 0x06000000) { - // SDRAM - ret = Pico32xMem->sdram; - mask = 0x03ffff; - } - else if ((pc & 0xc6000000) == 0x02000000) { - // ROM - if ((pc & 0x3fffff) < Pico.romsize) - ret = Pico.rom; - mask = 0x3fffff; - } - + ret = p32x_sh2_get_mem_ptr(pc, &mask, sh2); if (ret == NULL) return (void *)-1; // NULL is valid value @@ -4889,7 +4905,7 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out, memset(op_flags, 0, sizeof(*op_flags) * BLOCK_INSN_LIMIT); op_flags[0] |= OF_BTARGET; // block start is always a target - dr_pc_base = dr_get_pc_base(base_pc, is_slave); + dr_pc_base = dr_get_pc_base(base_pc, &sh2s[!!is_slave]); // 1st pass: disassemble for (i = 0, pc = base_pc; ; i++, pc += 2) { @@ -5274,14 +5290,17 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out, break; case 0x07: // LDC.L @Rm+,SR 0100mmmm00000111 tmp = SHR_SR; + opd->op = OP_LDC; opd->cycles = 3; break; case 0x17: // LDC.L @Rm+,GBR 0100mmmm00010111 tmp = SHR_GBR; + opd->op = OP_LDC; opd->cycles = 3; break; case 0x27: // LDC.L @Rm+,VBR 0100mmmm00100111 tmp = SHR_VBR; + opd->op = OP_LDC; opd->cycles = 3; break; default: @@ -5372,7 +5391,7 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out, default: goto undefined; } - opd->op = OP_MOVE; + opd->op = OP_LDC; opd->source = BITMASK1(GET_Rn()); opd->dest = BITMASK1(tmp); break; diff --git a/pico/32x/memory.c b/pico/32x/memory.c index c385d141..578c72f8 100644 --- a/pico/32x/memory.c +++ b/pico/32x/memory.c @@ -1730,6 +1730,32 @@ void REGPARM(3) p32x_sh2_write32(u32 a, u32 d, SH2 *sh2) wh(a, d, sh2); } +void *p32x_sh2_get_mem_ptr(u32 a, u32 *mask, SH2 *sh2) +{ + const sh2_memmap *mm = sh2->read8_map; + void *ret = (void *)-1; + u32 am; + + mm += a >> SH2_READ_SHIFT; + am = a & ((1 << SH2_READ_SHIFT)-1); + if (!map_flag_set(mm->addr) && !(am & ~mm->mask)) { + // directly mapped memory (SDRAM, ROM, data array) + ret = (void *)(mm->addr << 1); + *mask = mm->mask; + } else if ((a & ~0x7ff) == 0) { + // BIOS, has handler function since it shares its segment with I/O + ret = sh2->is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w; + *mask = 0x7ff; + } else if ((a & 0xc6000000) == 0x02000000) { + // banked ROM. Return bank address + u32 bank = carthw_ssf2_banks[(a >> 19) & 7] << 19; + ret = sh2->p_rom + bank; + *mask = 0x07ffff; + } + + return ret; +} + // ----------------------------------------------------------------- static void z80_md_bank_write_32x(unsigned int a, unsigned char d) diff --git a/pico/pico_int.h b/pico/pico_int.h index 2c55c941..4139e816 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -933,6 +933,7 @@ void Pico32xMemStateLoaded(void); void p32x_update_banks(void); void p32x_m68k_poll_event(unsigned int flags); void p32x_sh2_poll_memory(unsigned int a, SH2 *sh2); +void *p32x_sh2_get_mem_ptr(unsigned int a, unsigned int *mask, SH2 *sh2); void p32x_sh2_poll_event(SH2 *sh2, unsigned int flags, unsigned int m68k_cycles); // 32x/draw.c -- 2.39.5