mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
sh2 drc: cleanup, fix for drc crash, for mips code emitter
This commit is contained in:
parent
9760505eaf
commit
90b1c9db91
12 changed files with 151 additions and 120 deletions
|
@ -440,7 +440,7 @@ static int rcache_get_tmp(void);
|
|||
static void rcache_free_tmp(int hr);
|
||||
|
||||
// Note: Register assignment goes by ABI convention. Caller save registers are
|
||||
// TEMPORARY, the others are PRESERVED. Unusable regs are omitted.
|
||||
// TEMPORARY, callee save registers are PRESERVED. Unusable regs are omitted.
|
||||
// there must be at least the free (not context or statically mapped) amount of
|
||||
// PRESERVED/TEMPORARY registers used by handlers in worst case (currently 4).
|
||||
// there must be at least 3 PARAM, and PARAM+TEMPORARY must be at least 4.
|
||||
|
@ -496,6 +496,11 @@ static void REGPARM(2) (*sh2_drc_write8)(u32 a, u32 d);
|
|||
static void REGPARM(2) (*sh2_drc_write16)(u32 a, u32 d);
|
||||
static void REGPARM(2) (*sh2_drc_write32)(u32 a, u32 d);
|
||||
|
||||
#ifdef DRC_SR_REG
|
||||
void REGPARM(1) (*sh2_drc_save_sr)(SH2 *sh2);
|
||||
void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2);
|
||||
#endif
|
||||
|
||||
// flags for memory access
|
||||
#define MF_SIZEMASK 0x03 // size of access
|
||||
#define MF_POSTINCR 0x10 // post increment (for read_rr)
|
||||
|
@ -1578,7 +1583,7 @@ static void rcache_unmap_vreg(int x)
|
|||
FOR_ALL_BITS_SET_DO(cache_regs[x].gregs, i,
|
||||
if (guest_regs[i].flags & GRF_DIRTY) {
|
||||
// if a dirty reg is unmapped save its value to context
|
||||
if ((~rcache_regs_discard | rcache_regs_now) & (1 << i))
|
||||
if (~rcache_regs_discard & (1 << i))
|
||||
emith_ctx_write(cache_regs[x].hreg, i * 4);
|
||||
guest_regs[i].flags &= ~GRF_DIRTY;
|
||||
}
|
||||
|
@ -3107,6 +3112,7 @@ static void REGPARM(2) *sh2_translate(SH2 *sh2, int tcache_id)
|
|||
op_flags[i+1] |= OF_BTARGET; // RTE entrypoint in case of SR.IMASK change
|
||||
// unify T and SR since rcache doesn't know about "virtual" guest regs
|
||||
if (ops[i].source & BITMASK1(SHR_T)) ops[i].source |= BITMASK1(SHR_SR);
|
||||
if (ops[i].dest & BITMASK1(SHR_T)) ops[i].source |= BITMASK1(SHR_SR);
|
||||
if (ops[i].dest & BITMASK1(SHR_T)) ops[i].dest |= BITMASK1(SHR_SR);
|
||||
#if LOOP_DETECTION
|
||||
// loop types detected:
|
||||
|
@ -5028,7 +5034,6 @@ static void sh2_generate_utils(void)
|
|||
emith_move_r_r_ptr(arg0, CONTEXT_REG);
|
||||
emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
|
||||
emith_call(sh2_translate);
|
||||
/* just after lookup function, jump to address returned */
|
||||
emith_tst_r_r_ptr(RET_REG, RET_REG);
|
||||
EMITH_SJMP_START(DCOND_EQ);
|
||||
emith_jump_reg_c(DCOND_NE, RET_REG);
|
||||
|
@ -5057,8 +5062,8 @@ static void sh2_generate_utils(void)
|
|||
emith_ctx_read(arg2, offsetof(SH2, rts_cache_idx));
|
||||
emith_add_r_r_r_lsl_ptr(arg1, CONTEXT_REG, arg2, 0);
|
||||
emith_read_r_r_offs(arg3, arg1, offsetof(SH2, rts_cache));
|
||||
#if (DRC_DEBUG & 128)
|
||||
emith_cmp_r_r(arg0, arg3);
|
||||
#if (DRC_DEBUG & 128)
|
||||
EMITH_SJMP_START(DCOND_EQ);
|
||||
emith_move_r_ptr_imm(arg3, (uptr)&rcmiss);
|
||||
emith_read_r_r_offs_c(DCOND_NE, arg1, arg3, 0);
|
||||
|
@ -5067,7 +5072,6 @@ static void sh2_generate_utils(void)
|
|||
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
|
||||
EMITH_SJMP_END(DCOND_EQ);
|
||||
#else
|
||||
emith_cmp_r_r(arg0, arg3);
|
||||
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
|
||||
#endif
|
||||
emith_read_r_r_offs_ptr(arg0, arg1, offsetof(SH2, rts_cache) + sizeof(void *));
|
||||
|
@ -5109,7 +5113,7 @@ static void sh2_generate_utils(void)
|
|||
emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
|
||||
// push PC
|
||||
rcache_get_reg_arg(0, SHR_SP, NULL);
|
||||
emith_ctx_read(arg1, SHR_PC * 4);
|
||||
rcache_get_reg_arg(1, SHR_PC, NULL);
|
||||
emith_move_r_r_ptr(arg2, CONTEXT_REG);
|
||||
rcache_invalidate_tmp();
|
||||
emith_call(p32x_sh2_write32);
|
||||
|
@ -5143,6 +5147,24 @@ static void sh2_generate_utils(void)
|
|||
emith_jump(sh2_drc_dispatcher);
|
||||
emith_flush();
|
||||
|
||||
#ifdef DRC_SR_REG
|
||||
// sh2_drc_save_sr(SH2 *sh2)
|
||||
sh2_drc_save_sr = (void *)tcache_ptr;
|
||||
tmp = rcache_get_reg(SHR_SR, RC_GR_READ, NULL);
|
||||
emith_write_r_r_offs(tmp, arg0, SHR_SR * 4);
|
||||
rcache_invalidate();
|
||||
emith_ret();
|
||||
emith_flush();
|
||||
|
||||
// sh2_drc_restore_sr(SH2 *sh2)
|
||||
sh2_drc_restore_sr = (void *)tcache_ptr;
|
||||
tmp = rcache_get_reg(SHR_SR, RC_GR_WRITE, NULL);
|
||||
emith_read_r_r_offs(tmp, arg0, SHR_SR * 4);
|
||||
rcache_flush();
|
||||
emith_ret();
|
||||
emith_flush();
|
||||
#endif
|
||||
|
||||
#ifdef PDB_NET
|
||||
// debug
|
||||
#define MAKE_READ_WRAPPER(func) { \
|
||||
|
@ -5204,6 +5226,10 @@ static void sh2_generate_utils(void)
|
|||
host_dasm_new_symbol(sh2_drc_read8_poll);
|
||||
host_dasm_new_symbol(sh2_drc_read16_poll);
|
||||
host_dasm_new_symbol(sh2_drc_read32_poll);
|
||||
#ifdef DRC_SR_REG
|
||||
host_dasm_new_symbol(sh2_drc_save_sr);
|
||||
host_dasm_new_symbol(sh2_drc_restore_sr);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if DRC_DEBUG
|
||||
|
@ -5273,12 +5299,12 @@ static void sh2_smc_rm_blocks(u32 a, int len, int tcache_id, u32 shift)
|
|||
#endif
|
||||
}
|
||||
|
||||
void sh2_drc_wcheck_ram(unsigned int a, unsigned len, SH2 *sh2)
|
||||
void sh2_drc_wcheck_ram(u32 a, unsigned len, SH2 *sh2)
|
||||
{
|
||||
sh2_smc_rm_blocks(a, len, 0, SH2_DRCBLK_RAM_SHIFT);
|
||||
}
|
||||
|
||||
void sh2_drc_wcheck_da(unsigned int a, unsigned len, SH2 *sh2)
|
||||
void sh2_drc_wcheck_da(u32 a, unsigned len, SH2 *sh2)
|
||||
{
|
||||
sh2_smc_rm_blocks(a, len, 1 + sh2->is_slave, SH2_DRCBLK_DA_SHIFT);
|
||||
}
|
||||
|
@ -5295,7 +5321,7 @@ int sh2_execute_drc(SH2 *sh2c, int cycles)
|
|||
sh2_drc_entry(sh2c);
|
||||
|
||||
// TODO: irq cycles
|
||||
ret_cycles = (signed int)sh2c->sr >> 12;
|
||||
ret_cycles = (int32_t)sh2c->sr >> 12;
|
||||
if (ret_cycles > 0)
|
||||
dbg(1, "warning: drc returned with cycles: %d", ret_cycles);
|
||||
|
||||
|
@ -5777,6 +5803,7 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out,
|
|||
break;
|
||||
case 1: // DIV0U 0000000000011001
|
||||
CHECK_UNHANDLED_BITS(0xf00, undefined);
|
||||
opd->source = BITMASK1(SHR_SR);
|
||||
opd->dest = BITMASK2(SHR_SR, SHR_T);
|
||||
break;
|
||||
case 2: // MOVT Rn 0000nnnn00101001
|
||||
|
@ -5877,7 +5904,7 @@ u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc_out,
|
|||
opd->dest = BITMASK2(GET_Rn(), SHR_MEM);
|
||||
break;
|
||||
case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
|
||||
opd->source = BITMASK2(GET_Rm(), GET_Rn());
|
||||
opd->source = BITMASK3(SHR_SR, GET_Rm(), GET_Rn());
|
||||
opd->dest = BITMASK2(SHR_SR, SHR_T);
|
||||
break;
|
||||
case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
|
||||
|
@ -6470,6 +6497,9 @@ end:
|
|||
last_btarget = 0;
|
||||
op = 0; // delay/poll insns counter
|
||||
for (i = 0, pc = base_pc; i < i_end; i++, pc += 2) {
|
||||
int null;
|
||||
if ((op_flags[i] & OF_BTARGET) && dr_get_entry(pc, is_slave, &null))
|
||||
break; // branch target already compiled
|
||||
opd = &ops[i];
|
||||
crc += FETCH_OP(pc);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
int sh2_drc_init(SH2 *sh2);
|
||||
void sh2_drc_finish(SH2 *sh2);
|
||||
void sh2_drc_wcheck_ram(unsigned int a, unsigned len, SH2 *sh2);
|
||||
void sh2_drc_wcheck_da(unsigned int a, unsigned len, SH2 *sh2);
|
||||
void sh2_drc_wcheck_ram(uint32_t a, unsigned len, SH2 *sh2);
|
||||
void sh2_drc_wcheck_da(uint32_t a, unsigned len, SH2 *sh2);
|
||||
|
||||
#ifdef DRC_SH2
|
||||
void sh2_drc_mem_setup(SH2 *sh2);
|
||||
|
@ -28,13 +28,13 @@ void sh2_drc_frame(void);
|
|||
#define OF_DELAY_LOOP (2 << 2)
|
||||
#define OF_POLL_LOOP (3 << 2)
|
||||
|
||||
unsigned short scan_block(unsigned int base_pc, int is_slave,
|
||||
unsigned char *op_flags, unsigned int *end_pc,
|
||||
unsigned int *base_literals, unsigned int *end_literals);
|
||||
unsigned short scan_block(uint32_t base_pc, int is_slave,
|
||||
unsigned char *op_flags, uint32_t *end_pc,
|
||||
uint32_t *base_literals, uint32_t *end_literals);
|
||||
|
||||
#if defined(DRC_SH2)
|
||||
// direct access to some host CPU registers used by the DRC
|
||||
// XXX MUST match definitions for SHR_SR in cpu/sh2/compiler.c
|
||||
#if defined(DRC_SH2) && defined(__GNUC__)
|
||||
// direct access to some host CPU registers used by the DRC
|
||||
// XXX MUST match definitions for SHR_SR in cpu/drc/emit_*.c
|
||||
#if defined(__arm__)
|
||||
#define DRC_SR_REG "r10"
|
||||
#elif defined(__aarch64__)
|
||||
|
@ -47,19 +47,20 @@ unsigned short scan_block(unsigned int base_pc, int is_slave,
|
|||
#define DRC_SR_REG "edi"
|
||||
#elif defined(__x86_64__)
|
||||
#define DRC_SR_REG "ebx"
|
||||
#else
|
||||
#warning "direct DRC register access not available for this host"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DRC_SR_REG
|
||||
#define DRC_DECLARE_SR register int sh2_sr asm(DRC_SR_REG)
|
||||
extern void REGPARM(1) (*sh2_drc_save_sr)(SH2 *sh2);
|
||||
extern void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2);
|
||||
|
||||
#define DRC_DECLARE_SR register int32_t sh2_sr asm(DRC_SR_REG)
|
||||
#define DRC_SAVE_SR(sh2) \
|
||||
if ((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN) \
|
||||
sh2->sr = sh2_sr;
|
||||
if (likely((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN)) \
|
||||
sh2_drc_save_sr(sh2)
|
||||
#define DRC_RESTORE_SR(sh2) \
|
||||
if ((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN) \
|
||||
sh2_sr = sh2->sr;
|
||||
if (likely((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN)) \
|
||||
sh2_drc_restore_sr(sh2)
|
||||
#else
|
||||
#define DRC_DECLARE_SR
|
||||
#define DRC_SAVE_SR(sh2)
|
||||
|
|
|
@ -14,13 +14,13 @@ typedef enum {
|
|||
typedef struct SH2_
|
||||
{
|
||||
// registers. this MUST correlate with enum sh2_reg_e.
|
||||
unsigned int r[16] ALIGNED(32);
|
||||
unsigned int pc; // 40
|
||||
unsigned int ppc;
|
||||
unsigned int pr;
|
||||
unsigned int sr;
|
||||
unsigned int gbr, vbr; // 50
|
||||
unsigned int mach, macl; // 58
|
||||
uint32_t r[16] ALIGNED(32);
|
||||
uint32_t pc; // 40
|
||||
uint32_t ppc;
|
||||
uint32_t pr;
|
||||
uint32_t sr;
|
||||
uint32_t gbr, vbr; // 50
|
||||
uint32_t mach, macl; // 58
|
||||
|
||||
// common
|
||||
const void *read8_map;
|
||||
|
@ -48,14 +48,14 @@ typedef struct SH2_
|
|||
#define SH2_STATE_VPOLL (1 << 3) // polling VDP
|
||||
#define SH2_STATE_RPOLL (1 << 4) // polling address in SDRAM
|
||||
unsigned int state;
|
||||
unsigned int poll_addr;
|
||||
uint32_t poll_addr;
|
||||
int poll_cycles;
|
||||
int poll_cnt;
|
||||
|
||||
// DRC branch cache. size must be 2^n and <=128
|
||||
int rts_cache_idx;
|
||||
struct { unsigned int pc; void *code; } rts_cache[16];
|
||||
struct { unsigned int pc; void *code; } branch_cache[128];
|
||||
struct { uint32_t pc; void *code; } rts_cache[16];
|
||||
struct { uint32_t pc; void *code; } branch_cache[128];
|
||||
|
||||
// interpreter stuff
|
||||
int icount; // cycles left in current timeslice
|
||||
|
@ -79,15 +79,15 @@ typedef struct SH2_
|
|||
unsigned int mult_m68k_to_sh2;
|
||||
unsigned int mult_sh2_to_m68k;
|
||||
|
||||
unsigned char data_array[0x1000]; // cache (can be used as RAM)
|
||||
unsigned int peri_regs[0x200/4]; // periphereal regs
|
||||
uint8_t data_array[0x1000]; // cache (can be used as RAM)
|
||||
uint32_t peri_regs[0x200/4]; // periphereal regs
|
||||
} SH2;
|
||||
|
||||
#define CYCLE_MULT_SHIFT 10
|
||||
#define C_M68K_TO_SH2(xsh2, c) \
|
||||
(int)(((unsigned long long)(c) * (xsh2)->mult_m68k_to_sh2) >> CYCLE_MULT_SHIFT)
|
||||
(int)(((uint64_t)(c) * (xsh2)->mult_m68k_to_sh2) >> CYCLE_MULT_SHIFT)
|
||||
#define C_SH2_TO_M68K(xsh2, c) \
|
||||
(int)(((unsigned long long)(c+3U) * (xsh2)->mult_sh2_to_m68k) >> CYCLE_MULT_SHIFT)
|
||||
(int)(((uint64_t)(c+3U) * (xsh2)->mult_sh2_to_m68k) >> CYCLE_MULT_SHIFT)
|
||||
|
||||
int sh2_init(SH2 *sh2, int is_slave, SH2 *other_sh2);
|
||||
void sh2_finish(SH2 *sh2);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue