From 6a5b1b362ecf78ce2925068a5d938d319ff583a3 Mon Sep 17 00:00:00 2001 From: notaz Date: Fri, 18 Aug 2017 03:44:25 +0300 Subject: [PATCH] sh2: handle some branch exceptions --- cpu/sh2/compiler.c | 31 +++++++++++++++++++++++++++---- cpu/sh2/compiler.h | 1 + cpu/sh2/mame/sh2pico.c | 12 ++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/cpu/sh2/compiler.c b/cpu/sh2/compiler.c index 25ba9d2f..3a2b708c 100644 --- a/cpu/sh2/compiler.c +++ b/cpu/sh2/compiler.c @@ -2590,8 +2590,9 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) default: default_: - elprintf_sh2(sh2, EL_ANOMALY, - "drc: illegal op %04x @ %08x", 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); @@ -2604,10 +2605,16 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id) // push PC rcache_get_reg_arg(0, SHR_SP); tmp = rcache_get_tmp_arg(1); - emith_move_r_imm(tmp, pc - 2); + 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, 4 * 4, 2); + 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); @@ -4062,6 +4069,22 @@ void scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out, 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; diff --git a/cpu/sh2/compiler.h b/cpu/sh2/compiler.h index ef1944b4..61d8d2da 100644 --- a/cpu/sh2/compiler.h +++ b/cpu/sh2/compiler.h @@ -20,6 +20,7 @@ void sh2_drc_frame(void); #define OF_BTARGET (1 << 1) #define OF_T_SET (1 << 2) // T is known to be set #define OF_T_CLEAR (1 << 3) // ... clear +#define OF_B_IN_DS (1 << 4) void scan_block(unsigned int base_pc, int is_slave, unsigned char *op_flags, unsigned int *end_pc, diff --git a/cpu/sh2/mame/sh2pico.c b/cpu/sh2/mame/sh2pico.c index a3ad9f47..174d4691 100644 --- a/cpu/sh2/mame/sh2pico.c +++ b/cpu/sh2/mame/sh2pico.c @@ -122,6 +122,18 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles) { sh2->ppc = sh2->delay; opcode = RW(sh2, sh2->delay); + + // TODO: more branch types + if ((opcode >> 13) == 5) { // BRA/BSR + sh2->r[15] -= 4; + WL(sh2, sh2->r[15], sh2->sr); + sh2->r[15] -= 4; + WL(sh2, sh2->r[15], sh2->pc); + sh2->pc = RL(sh2, sh2->vbr + 6 * 4); + sh2->icount -= 5; + opcode = 9; // NOP + } + sh2->pc -= 2; } else -- 2.39.5