mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-04 23:07:46 -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
|
@ -20,6 +20,9 @@
|
||||||
#define STATIC_SH2_REGS { SHR_SR,22 , SHR_R0,21 , SHR_R0+1,20 }
|
#define STATIC_SH2_REGS { SHR_SR,22 , SHR_R0,21 , SHR_R0+1,20 }
|
||||||
|
|
||||||
// NB: the ubiquitous JZ74[46]0 uses MIPS32 Release 1, a slight MIPS II superset
|
// NB: the ubiquitous JZ74[46]0 uses MIPS32 Release 1, a slight MIPS II superset
|
||||||
|
#ifndef __mips_isa_rev
|
||||||
|
#define __mips_isa_rev 1 // surprisingly not always defined
|
||||||
|
#endif
|
||||||
|
|
||||||
// registers usable for user code: r1-r25, others reserved or special
|
// registers usable for user code: r1-r25, others reserved or special
|
||||||
#define Z0 0 // zero register
|
#define Z0 0 // zero register
|
||||||
|
@ -333,32 +336,49 @@ static int emith_is_b(u32 op) // B
|
||||||
{ return ((op>>26) & 074) == OP_BEQ ||
|
{ return ((op>>26) & 074) == OP_BEQ ||
|
||||||
((op>>26) == OP__RT && ((op>>16) & 036) == RT_BLTZ); }
|
((op>>26) == OP__RT && ((op>>16) & 036) == RT_BLTZ); }
|
||||||
// register usage for dependency evaluation XXX better do this as in emit_arm?
|
// register usage for dependency evaluation XXX better do this as in emit_arm?
|
||||||
static uint64_t emith_has_rs[3] = // OP__FN, OP__RT, others
|
static uint64_t emith_has_rs[5] = // OP__FN1-3, OP__RT, others
|
||||||
{ 0x00fffffffffa0ff0ULL, 0x000fff0fUL, 0xffffffff0f007ff0ULL };
|
{ 0x005ffcffffda0fd2ULL, 0x0000003300000037ULL, 0x00000000000000ffULL,
|
||||||
static uint64_t emith_has_rt[3] = // OP__FN, OP__RT, others
|
0x800f5f0fUL, 0xf7ffffff0ff07ff0ULL };
|
||||||
{ 0xff00fffffff00cffULL, 0x00000000UL, 0x8000ff0000000030ULL };
|
static uint64_t emith_has_rt[5] = // OP__FN1-3, OP__RT, others
|
||||||
static uint64_t emith_has_rd[3] = // OP__FN, OP__RT, others (rt instead of rd)
|
{ 0xdd5ffcffffd00cddULL, 0x0000000000000037ULL, 0x0000001100000000ULL,
|
||||||
{ 0xff00fffffff50fffULL, 0x00000000UL, 0x119100ff0f00ff00ULL };
|
0x00000000UL, 0x80007f440c300030ULL };
|
||||||
|
static uint64_t emith_has_rd[5] = // OP__FN1-3, OP__RT, others(rt instead of rd)
|
||||||
|
{ 0xdd00fcff00d50edfULL, 0x0000003300000004ULL, 0x08000011000000ffULL,
|
||||||
|
0x00000000UL, 0x119100ff0f00ff00ULL };
|
||||||
#define emith_has_(rx,ix,op,sa,m) \
|
#define emith_has_(rx,ix,op,sa,m) \
|
||||||
(emith_has_##rx[ix] & (1ULL << (((op)>>(sa)) & (m))))
|
(emith_has_##rx[ix] & (1ULL << (((op)>>(sa)) & (m))))
|
||||||
static int emith_rs(u32 op)
|
static int emith_rs(u32 op)
|
||||||
{ if ((op>>26) == OP__FN)
|
{ if ((op>>26) == OP__FN)
|
||||||
return emith_has_(rs,0,op, 0,0x3f) ? (op>>21)&0x1f : 0;
|
return emith_has_(rs,0,op, 0,0x3f) ? (op>>21)&0x1f : 0;
|
||||||
|
if ((op>>26) == OP__FN2)
|
||||||
|
return emith_has_(rs,1,op, 0,0x3f) ? (op>>21)&0x1f : 0;
|
||||||
|
if ((op>>26) == OP__FN3)
|
||||||
|
return emith_has_(rs,2,op, 0,0x3f) ? (op>>21)&0x1f : 0;
|
||||||
if ((op>>26) == OP__RT)
|
if ((op>>26) == OP__RT)
|
||||||
return emith_has_(rs,1,op,16,0x1f) ? (op>>21)&0x1f : 0;
|
return emith_has_(rs,3,op,16,0x1f) ? (op>>21)&0x1f : 0;
|
||||||
return emith_has_(rs,2,op,26,0x3f) ? (op>>21)&0x1f : 0;
|
return emith_has_(rs,4,op,26,0x3f) ? (op>>21)&0x1f : 0;
|
||||||
}
|
}
|
||||||
static int emith_rt(u32 op)
|
static int emith_rt(u32 op)
|
||||||
{ if ((op>>26) == OP__FN)
|
{ if ((op>>26) == OP__FN)
|
||||||
return emith_has_(rt,0,op, 0,0x3f) ? (op>>16)&0x1f : 0;
|
return emith_has_(rt,0,op, 0,0x3f) ? (op>>16)&0x1f : 0;
|
||||||
|
if ((op>>26) == OP__FN2)
|
||||||
|
return emith_has_(rt,1,op, 0,0x3f) ? (op>>16)&0x1f : 0;
|
||||||
|
if ((op>>26) == OP__FN3)
|
||||||
|
return emith_has_(rt,2,op, 0,0x3f) ? (op>>16)&0x1f : 0;
|
||||||
if ((op>>26) == OP__RT)
|
if ((op>>26) == OP__RT)
|
||||||
return 0;
|
return 0;
|
||||||
return emith_has_(rt,2,op,26,0x3f) ? (op>>16)&0x1f : 0;
|
return emith_has_(rt,4,op,26,0x3f) ? (op>>16)&0x1f : 0;
|
||||||
}
|
}
|
||||||
static int emith_rd(u32 op)
|
static int emith_rd(u32 op)
|
||||||
{ int ret = emith_has_(rd,2,op,26,0x3f) ? (op>>16)&0x1f :-1;
|
{ int ret = emith_has_(rd,4,op,26,0x3f) ? (op>>16)&0x1f :-1;
|
||||||
if ((op>>26) == OP__FN)
|
if ((op>>26) == OP__FN)
|
||||||
ret = emith_has_(rd,0,op, 0,0x3f) ? (op>>11)&0x1f :-1;
|
ret = emith_has_(rd,0,op, 0,0x3f) ? (op>>11)&0x1f :-1;
|
||||||
|
if ((op>>26) == OP__FN2)
|
||||||
|
ret = emith_has_(rd,1,op, 0,0x3f) ? (op>>11)&0x1f :-1;
|
||||||
|
if ((op>>26) == OP__FN3 && (op&0x3f) == FN3_BSHFL)
|
||||||
|
ret = emith_has_(rd,2,op, 0,0x3f) ? (op>>11)&0x1f :-1;
|
||||||
|
if ((op>>26) == OP__FN3 && (op&0x3f) != FN3_BSHFL)
|
||||||
|
ret = emith_has_(rd,2,op, 0,0x3f) ? (op>>16)&0x1f :-1;
|
||||||
if ((op>>26) == OP__RT)
|
if ((op>>26) == OP__RT)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
return (ret ?: -1); // Z0 doesn't have dependencies
|
return (ret ?: -1); // Z0 doesn't have dependencies
|
||||||
|
@ -970,29 +990,23 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
|
||||||
#define emith_asr(d, s, cnt) \
|
#define emith_asr(d, s, cnt) \
|
||||||
EMIT(MIPS_ASR_IMM(d, s, cnt))
|
EMIT(MIPS_ASR_IMM(d, s, cnt))
|
||||||
|
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_ror(d, s, cnt) \
|
|
||||||
EMIT(MIPS_ROR_IMM(d, s, cnt))
|
|
||||||
#else
|
|
||||||
#define emith_ror(d, s, cnt) do { \
|
#define emith_ror(d, s, cnt) do { \
|
||||||
EMIT(MIPS_LSL_IMM(AT, s, 32-(cnt))); \
|
if (__mips_isa_rev < 2) { \
|
||||||
EMIT(MIPS_LSR_IMM(d, s, cnt)); \
|
EMIT(MIPS_LSL_IMM(AT, s, 32-(cnt))); \
|
||||||
EMIT(MIPS_OR_REG(d, d, AT)); \
|
EMIT(MIPS_LSR_IMM(d, s, cnt)); \
|
||||||
|
EMIT(MIPS_OR_REG(d, d, AT)); \
|
||||||
|
} else EMIT(MIPS_ROR_IMM(d, s, cnt)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
#define emith_ror_c(cond, d, s, cnt) \
|
#define emith_ror_c(cond, d, s, cnt) \
|
||||||
emith_ror(d, s, cnt)
|
emith_ror(d, s, cnt)
|
||||||
|
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_rol(d, s, cnt) \
|
|
||||||
EMIT(MIPS_ROR_IMM(d, s, 32-(cnt)))
|
|
||||||
#else
|
|
||||||
#define emith_rol(d, s, cnt) do { \
|
#define emith_rol(d, s, cnt) do { \
|
||||||
EMIT(MIPS_LSR_IMM(AT, s, 32-(cnt))); \
|
if (__mips_isa_rev < 2) { \
|
||||||
EMIT(MIPS_LSL_IMM(d, s, cnt)); \
|
EMIT(MIPS_LSR_IMM(AT, s, 32-(cnt))); \
|
||||||
EMIT(MIPS_OR_REG(d, d, AT)); \
|
EMIT(MIPS_LSL_IMM(d, s, cnt)); \
|
||||||
|
EMIT(MIPS_OR_REG(d, d, AT)); \
|
||||||
|
} else EMIT(MIPS_ROR_IMM(d, s, 32-(cnt))); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define emith_rorc(d) do { \
|
#define emith_rorc(d) do { \
|
||||||
emith_lsr(d, d, 1); \
|
emith_lsr(d, d, 1); \
|
||||||
|
@ -1082,13 +1096,11 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// signed/unsigned extend
|
// signed/unsigned extend
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_clear_msb(d, s, count) /* bits to clear */ \
|
|
||||||
EMIT(MIPS_EXT_IMM(d, s, 0, 32-(count)))
|
|
||||||
#else
|
|
||||||
#define emith_clear_msb(d, s, count) /* bits to clear */ do { \
|
#define emith_clear_msb(d, s, count) /* bits to clear */ do { \
|
||||||
u32 t; \
|
u32 t; \
|
||||||
if ((count) >= 16) { \
|
if (__mips_isa_rev >= 2) \
|
||||||
|
EMIT(MIPS_EXT_IMM(d, s, 0, 32-(count))); \
|
||||||
|
else if ((count) >= 16) { \
|
||||||
t = (count) - 16; \
|
t = (count) - 16; \
|
||||||
t = 0xffff >> t; \
|
t = 0xffff >> t; \
|
||||||
emith_and_r_r_imm(d, s, t); \
|
emith_and_r_r_imm(d, s, t); \
|
||||||
|
@ -1097,27 +1109,19 @@ static void emith_log_imm(int op, int rd, int rs, u32 imm)
|
||||||
emith_lsr(d, d, count); \
|
emith_lsr(d, d, count); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
#define emith_clear_msb_c(cond, d, s, count) \
|
#define emith_clear_msb_c(cond, d, s, count) \
|
||||||
emith_clear_msb(d, s, count)
|
emith_clear_msb(d, s, count)
|
||||||
|
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_sext(d, s, count) /* bits to keep */ do { \
|
#define emith_sext(d, s, count) /* bits to keep */ do { \
|
||||||
if (count == 8) \
|
if (__mips_isa_rev >= 2 && count == 8) \
|
||||||
EMIT(MIPS_SEB_REG(d, s)); \
|
EMIT(MIPS_SEB_REG(d, s)); \
|
||||||
else if (count == 16) \
|
else if (__mips_isa_rev >= 2 && count == 16) \
|
||||||
EMIT(MIPS_SEH_REG(d, s)); \
|
EMIT(MIPS_SEH_REG(d, s)); \
|
||||||
else { \
|
else { \
|
||||||
emith_lsl(d, s, 32-(count)); \
|
emith_lsl(d, s, 32-(count)); \
|
||||||
emith_asr(d, d, 32-(count)); \
|
emith_asr(d, d, 32-(count)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
|
||||||
#define emith_sext(d, s, count) /* bits to keep */ do { \
|
|
||||||
emith_lsl(d, s, 32-(count)); \
|
|
||||||
emith_asr(d, d, 32-(count)); \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// multiply Rd = Rn*Rm (+ Ra); NB: next 2 insns after MFLO/MFHI mustn't be MULT
|
// multiply Rd = Rn*Rm (+ Ra); NB: next 2 insns after MFLO/MFHI mustn't be MULT
|
||||||
static u8 *last_lohi;
|
static u8 *last_lohi;
|
||||||
|
@ -1716,26 +1720,20 @@ static int emith_cond_check(int cond, int *r)
|
||||||
EMITH_SJMP_END(DCOND_EQ); \
|
EMITH_SJMP_END(DCOND_EQ); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_write_sr(sr, srcr) \
|
|
||||||
EMIT(MIPS_INS_IMM(sr, srcr, 0, 10))
|
|
||||||
#else
|
|
||||||
#define emith_write_sr(sr, srcr) do { \
|
#define emith_write_sr(sr, srcr) do { \
|
||||||
emith_lsr(sr, sr , 10); emith_lsl(sr, sr, 10); \
|
if (__mips_isa_rev < 2) { \
|
||||||
emith_lsl(AT, srcr, 22); emith_lsr(AT, AT, 22); \
|
emith_lsr(sr, sr , 10); emith_lsl(sr, sr, 10); \
|
||||||
emith_or_r_r(sr, AT); \
|
emith_lsl(AT, srcr, 22); emith_lsr(AT, AT, 22); \
|
||||||
|
emith_or_r_r(sr, AT); \
|
||||||
|
} else EMIT(MIPS_INS_IMM(sr, srcr, 0, 10)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__mips_isa_rev) && __mips_isa_rev >= 2
|
|
||||||
#define emith_carry_to_t(sr, is_sub) \
|
|
||||||
EMIT(MIPS_INS_IMM(sr, FC, 0, 1))
|
|
||||||
#else
|
|
||||||
#define emith_carry_to_t(sr, is_sub) do { \
|
#define emith_carry_to_t(sr, is_sub) do { \
|
||||||
emith_and_r_imm(sr, 0xfffffffe); \
|
if (__mips_isa_rev < 2) { \
|
||||||
emith_or_r_r(sr, FC); \
|
emith_and_r_imm(sr, 0xfffffffe); \
|
||||||
|
emith_or_r_r(sr, FC); \
|
||||||
|
} else EMIT(MIPS_INS_IMM(sr, FC, 0, 1)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
|
||||||
|
|
||||||
#define emith_t_to_carry(sr, is_sub) do { \
|
#define emith_t_to_carry(sr, is_sub) do { \
|
||||||
emith_and_r_r_imm(FC, sr, 1); \
|
emith_and_r_r_imm(FC, sr, 1); \
|
||||||
|
|
|
@ -440,7 +440,7 @@ static int rcache_get_tmp(void);
|
||||||
static void rcache_free_tmp(int hr);
|
static void rcache_free_tmp(int hr);
|
||||||
|
|
||||||
// Note: Register assignment goes by ABI convention. Caller save registers are
|
// 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
|
// 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).
|
// 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.
|
// 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_write16)(u32 a, u32 d);
|
||||||
static void REGPARM(2) (*sh2_drc_write32)(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
|
// flags for memory access
|
||||||
#define MF_SIZEMASK 0x03 // size of access
|
#define MF_SIZEMASK 0x03 // size of access
|
||||||
#define MF_POSTINCR 0x10 // post increment (for read_rr)
|
#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,
|
FOR_ALL_BITS_SET_DO(cache_regs[x].gregs, i,
|
||||||
if (guest_regs[i].flags & GRF_DIRTY) {
|
if (guest_regs[i].flags & GRF_DIRTY) {
|
||||||
// if a dirty reg is unmapped save its value to context
|
// 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);
|
emith_ctx_write(cache_regs[x].hreg, i * 4);
|
||||||
guest_regs[i].flags &= ~GRF_DIRTY;
|
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
|
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
|
// 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].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 (ops[i].dest & BITMASK1(SHR_T)) ops[i].dest |= BITMASK1(SHR_SR);
|
||||||
#if LOOP_DETECTION
|
#if LOOP_DETECTION
|
||||||
// loop types detected:
|
// loop types detected:
|
||||||
|
@ -5028,7 +5034,6 @@ static void sh2_generate_utils(void)
|
||||||
emith_move_r_r_ptr(arg0, CONTEXT_REG);
|
emith_move_r_r_ptr(arg0, CONTEXT_REG);
|
||||||
emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
|
emith_ctx_read(arg1, offsetof(SH2, drc_tmp)); // tcache_id
|
||||||
emith_call(sh2_translate);
|
emith_call(sh2_translate);
|
||||||
/* just after lookup function, jump to address returned */
|
|
||||||
emith_tst_r_r_ptr(RET_REG, RET_REG);
|
emith_tst_r_r_ptr(RET_REG, RET_REG);
|
||||||
EMITH_SJMP_START(DCOND_EQ);
|
EMITH_SJMP_START(DCOND_EQ);
|
||||||
emith_jump_reg_c(DCOND_NE, RET_REG);
|
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_ctx_read(arg2, offsetof(SH2, rts_cache_idx));
|
||||||
emith_add_r_r_r_lsl_ptr(arg1, CONTEXT_REG, arg2, 0);
|
emith_add_r_r_r_lsl_ptr(arg1, CONTEXT_REG, arg2, 0);
|
||||||
emith_read_r_r_offs(arg3, arg1, offsetof(SH2, rts_cache));
|
emith_read_r_r_offs(arg3, arg1, offsetof(SH2, rts_cache));
|
||||||
#if (DRC_DEBUG & 128)
|
|
||||||
emith_cmp_r_r(arg0, arg3);
|
emith_cmp_r_r(arg0, arg3);
|
||||||
|
#if (DRC_DEBUG & 128)
|
||||||
EMITH_SJMP_START(DCOND_EQ);
|
EMITH_SJMP_START(DCOND_EQ);
|
||||||
emith_move_r_ptr_imm(arg3, (uptr)&rcmiss);
|
emith_move_r_ptr_imm(arg3, (uptr)&rcmiss);
|
||||||
emith_read_r_r_offs_c(DCOND_NE, arg1, arg3, 0);
|
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_jump_cond(DCOND_NE, sh2_drc_dispatcher);
|
||||||
EMITH_SJMP_END(DCOND_EQ);
|
EMITH_SJMP_END(DCOND_EQ);
|
||||||
#else
|
#else
|
||||||
emith_cmp_r_r(arg0, arg3);
|
|
||||||
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
|
emith_jump_cond(DCOND_NE, sh2_drc_dispatcher);
|
||||||
#endif
|
#endif
|
||||||
emith_read_r_r_offs_ptr(arg0, arg1, offsetof(SH2, rts_cache) + sizeof(void *));
|
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?
|
emith_call(p32x_sh2_write32); // XXX: use sh2_drc_write32?
|
||||||
// push PC
|
// push PC
|
||||||
rcache_get_reg_arg(0, SHR_SP, NULL);
|
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);
|
emith_move_r_r_ptr(arg2, CONTEXT_REG);
|
||||||
rcache_invalidate_tmp();
|
rcache_invalidate_tmp();
|
||||||
emith_call(p32x_sh2_write32);
|
emith_call(p32x_sh2_write32);
|
||||||
|
@ -5143,6 +5147,24 @@ static void sh2_generate_utils(void)
|
||||||
emith_jump(sh2_drc_dispatcher);
|
emith_jump(sh2_drc_dispatcher);
|
||||||
emith_flush();
|
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
|
#ifdef PDB_NET
|
||||||
// debug
|
// debug
|
||||||
#define MAKE_READ_WRAPPER(func) { \
|
#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_read8_poll);
|
||||||
host_dasm_new_symbol(sh2_drc_read16_poll);
|
host_dasm_new_symbol(sh2_drc_read16_poll);
|
||||||
host_dasm_new_symbol(sh2_drc_read32_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
|
#endif
|
||||||
|
|
||||||
#if DRC_DEBUG
|
#if DRC_DEBUG
|
||||||
|
@ -5273,12 +5299,12 @@ static void sh2_smc_rm_blocks(u32 a, int len, int tcache_id, u32 shift)
|
||||||
#endif
|
#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);
|
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);
|
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);
|
sh2_drc_entry(sh2c);
|
||||||
|
|
||||||
// TODO: irq cycles
|
// TODO: irq cycles
|
||||||
ret_cycles = (signed int)sh2c->sr >> 12;
|
ret_cycles = (int32_t)sh2c->sr >> 12;
|
||||||
if (ret_cycles > 0)
|
if (ret_cycles > 0)
|
||||||
dbg(1, "warning: drc returned with cycles: %d", ret_cycles);
|
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;
|
break;
|
||||||
case 1: // DIV0U 0000000000011001
|
case 1: // DIV0U 0000000000011001
|
||||||
CHECK_UNHANDLED_BITS(0xf00, undefined);
|
CHECK_UNHANDLED_BITS(0xf00, undefined);
|
||||||
|
opd->source = BITMASK1(SHR_SR);
|
||||||
opd->dest = BITMASK2(SHR_SR, SHR_T);
|
opd->dest = BITMASK2(SHR_SR, SHR_T);
|
||||||
break;
|
break;
|
||||||
case 2: // MOVT Rn 0000nnnn00101001
|
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);
|
opd->dest = BITMASK2(GET_Rn(), SHR_MEM);
|
||||||
break;
|
break;
|
||||||
case 0x07: // DIV0S Rm,Rn 0010nnnnmmmm0111
|
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);
|
opd->dest = BITMASK2(SHR_SR, SHR_T);
|
||||||
break;
|
break;
|
||||||
case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
|
case 0x08: // TST Rm,Rn 0010nnnnmmmm1000
|
||||||
|
@ -6470,6 +6497,9 @@ end:
|
||||||
last_btarget = 0;
|
last_btarget = 0;
|
||||||
op = 0; // delay/poll insns counter
|
op = 0; // delay/poll insns counter
|
||||||
for (i = 0, pc = base_pc; i < i_end; i++, pc += 2) {
|
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];
|
opd = &ops[i];
|
||||||
crc += FETCH_OP(pc);
|
crc += FETCH_OP(pc);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
int sh2_drc_init(SH2 *sh2);
|
int sh2_drc_init(SH2 *sh2);
|
||||||
void sh2_drc_finish(SH2 *sh2);
|
void sh2_drc_finish(SH2 *sh2);
|
||||||
void sh2_drc_wcheck_ram(unsigned int a, unsigned len, SH2 *sh2);
|
void sh2_drc_wcheck_ram(uint32_t a, unsigned len, SH2 *sh2);
|
||||||
void sh2_drc_wcheck_da(unsigned int a, unsigned len, SH2 *sh2);
|
void sh2_drc_wcheck_da(uint32_t a, unsigned len, SH2 *sh2);
|
||||||
|
|
||||||
#ifdef DRC_SH2
|
#ifdef DRC_SH2
|
||||||
void sh2_drc_mem_setup(SH2 *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_DELAY_LOOP (2 << 2)
|
||||||
#define OF_POLL_LOOP (3 << 2)
|
#define OF_POLL_LOOP (3 << 2)
|
||||||
|
|
||||||
unsigned short scan_block(unsigned int base_pc, int is_slave,
|
unsigned short scan_block(uint32_t base_pc, int is_slave,
|
||||||
unsigned char *op_flags, unsigned int *end_pc,
|
unsigned char *op_flags, uint32_t *end_pc,
|
||||||
unsigned int *base_literals, unsigned int *end_literals);
|
uint32_t *base_literals, uint32_t *end_literals);
|
||||||
|
|
||||||
#if defined(DRC_SH2)
|
#if defined(DRC_SH2) && defined(__GNUC__)
|
||||||
// direct access to some host CPU registers used by the DRC
|
// direct access to some host CPU registers used by the DRC
|
||||||
// XXX MUST match definitions for SHR_SR in cpu/sh2/compiler.c
|
// XXX MUST match definitions for SHR_SR in cpu/drc/emit_*.c
|
||||||
#if defined(__arm__)
|
#if defined(__arm__)
|
||||||
#define DRC_SR_REG "r10"
|
#define DRC_SR_REG "r10"
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
@ -47,19 +47,20 @@ unsigned short scan_block(unsigned int base_pc, int is_slave,
|
||||||
#define DRC_SR_REG "edi"
|
#define DRC_SR_REG "edi"
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
#define DRC_SR_REG "ebx"
|
#define DRC_SR_REG "ebx"
|
||||||
#else
|
|
||||||
#warning "direct DRC register access not available for this host"
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DRC_SR_REG
|
#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) \
|
#define DRC_SAVE_SR(sh2) \
|
||||||
if ((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN) \
|
if (likely((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN)) \
|
||||||
sh2->sr = sh2_sr;
|
sh2_drc_save_sr(sh2)
|
||||||
#define DRC_RESTORE_SR(sh2) \
|
#define DRC_RESTORE_SR(sh2) \
|
||||||
if ((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN) \
|
if (likely((sh2->state & (SH2_STATE_RUN|SH2_STATE_SLEEP)) == SH2_STATE_RUN)) \
|
||||||
sh2_sr = sh2->sr;
|
sh2_drc_restore_sr(sh2)
|
||||||
#else
|
#else
|
||||||
#define DRC_DECLARE_SR
|
#define DRC_DECLARE_SR
|
||||||
#define DRC_SAVE_SR(sh2)
|
#define DRC_SAVE_SR(sh2)
|
||||||
|
|
|
@ -14,13 +14,13 @@ typedef enum {
|
||||||
typedef struct SH2_
|
typedef struct SH2_
|
||||||
{
|
{
|
||||||
// registers. this MUST correlate with enum sh2_reg_e.
|
// registers. this MUST correlate with enum sh2_reg_e.
|
||||||
unsigned int r[16] ALIGNED(32);
|
uint32_t r[16] ALIGNED(32);
|
||||||
unsigned int pc; // 40
|
uint32_t pc; // 40
|
||||||
unsigned int ppc;
|
uint32_t ppc;
|
||||||
unsigned int pr;
|
uint32_t pr;
|
||||||
unsigned int sr;
|
uint32_t sr;
|
||||||
unsigned int gbr, vbr; // 50
|
uint32_t gbr, vbr; // 50
|
||||||
unsigned int mach, macl; // 58
|
uint32_t mach, macl; // 58
|
||||||
|
|
||||||
// common
|
// common
|
||||||
const void *read8_map;
|
const void *read8_map;
|
||||||
|
@ -48,14 +48,14 @@ typedef struct SH2_
|
||||||
#define SH2_STATE_VPOLL (1 << 3) // polling VDP
|
#define SH2_STATE_VPOLL (1 << 3) // polling VDP
|
||||||
#define SH2_STATE_RPOLL (1 << 4) // polling address in SDRAM
|
#define SH2_STATE_RPOLL (1 << 4) // polling address in SDRAM
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
unsigned int poll_addr;
|
uint32_t poll_addr;
|
||||||
int poll_cycles;
|
int poll_cycles;
|
||||||
int poll_cnt;
|
int poll_cnt;
|
||||||
|
|
||||||
// DRC branch cache. size must be 2^n and <=128
|
// DRC branch cache. size must be 2^n and <=128
|
||||||
int rts_cache_idx;
|
int rts_cache_idx;
|
||||||
struct { unsigned int pc; void *code; } rts_cache[16];
|
struct { uint32_t pc; void *code; } rts_cache[16];
|
||||||
struct { unsigned int pc; void *code; } branch_cache[128];
|
struct { uint32_t pc; void *code; } branch_cache[128];
|
||||||
|
|
||||||
// interpreter stuff
|
// interpreter stuff
|
||||||
int icount; // cycles left in current timeslice
|
int icount; // cycles left in current timeslice
|
||||||
|
@ -79,15 +79,15 @@ typedef struct SH2_
|
||||||
unsigned int mult_m68k_to_sh2;
|
unsigned int mult_m68k_to_sh2;
|
||||||
unsigned int mult_sh2_to_m68k;
|
unsigned int mult_sh2_to_m68k;
|
||||||
|
|
||||||
unsigned char data_array[0x1000]; // cache (can be used as RAM)
|
uint8_t data_array[0x1000]; // cache (can be used as RAM)
|
||||||
unsigned int peri_regs[0x200/4]; // periphereal regs
|
uint32_t peri_regs[0x200/4]; // periphereal regs
|
||||||
} SH2;
|
} SH2;
|
||||||
|
|
||||||
#define CYCLE_MULT_SHIFT 10
|
#define CYCLE_MULT_SHIFT 10
|
||||||
#define C_M68K_TO_SH2(xsh2, c) \
|
#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) \
|
#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);
|
int sh2_init(SH2 *sh2, int is_slave, SH2 *other_sh2);
|
||||||
void sh2_finish(SH2 *sh2);
|
void sh2_finish(SH2 *sh2);
|
||||||
|
|
|
@ -60,9 +60,8 @@
|
||||||
|
|
||||||
// load data address (LDR) either via literal pool or via GOT
|
// load data address (LDR) either via literal pool or via GOT
|
||||||
#ifdef __PIC__
|
#ifdef __PIC__
|
||||||
// can't use pool loads since ldr= only allows symbol or constants, not expr :-(
|
// can't use pool loads since ldr= only allows a symbol or a constant expr :-(
|
||||||
#define PIC_LDR_INIT() \
|
#define PIC_LDR_INIT() \
|
||||||
.ifndef PIC_LDR_DEF; PIC_LDR_DEF=1; \
|
|
||||||
.macro pic_ldr r t a; \
|
.macro pic_ldr r t a; \
|
||||||
ldr \r, [pc, $.LD\@-.-8]; \
|
ldr \r, [pc, $.LD\@-.-8]; \
|
||||||
ldr \t, [pc, $.LD\@-.-4]; \
|
ldr \t, [pc, $.LD\@-.-4]; \
|
||||||
|
@ -71,14 +70,11 @@
|
||||||
add pc, $4; \
|
add pc, $4; \
|
||||||
.LD\@:.word _GLOBAL_OFFSET_TABLE_-.LP\@-8; \
|
.LD\@:.word _GLOBAL_OFFSET_TABLE_-.LP\@-8; \
|
||||||
.word \a(GOT); \
|
.word \a(GOT); \
|
||||||
.endm; \
|
.endm;
|
||||||
.endif;
|
#define PIC_LDR(r,t,a) pic_ldr r, t, a
|
||||||
#define PIC_LDR(r,t,a) \
|
|
||||||
pic_ldr r, t, a
|
|
||||||
#else
|
#else
|
||||||
#define PIC_LDR_INIT()
|
#define PIC_LDR_INIT()
|
||||||
#define PIC_LDR(r,t,a) \
|
#define PIC_LDR(r,t,a) ldr r, =a
|
||||||
ldr r, =a
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __ARM_FEATURES_H__ */
|
#endif /* __ARM_FEATURES_H__ */
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
#define NOINLINE __attribute__((noinline))
|
#define NOINLINE __attribute__((noinline))
|
||||||
#define ALIGNED(n) __attribute__((aligned(n)))
|
#define ALIGNED(n) __attribute__((aligned(n)))
|
||||||
#define unlikely(x) __builtin_expect((x), 0)
|
#define unlikely(x) __builtin_expect((x), 0)
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
#else
|
#else
|
||||||
#define NOINLINE
|
#define NOINLINE
|
||||||
#define ALIGNED(n)
|
#define ALIGNED(n)
|
||||||
#define unlikely(x) (x)
|
#define unlikely(x) (x)
|
||||||
|
#define likely(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
|
@ -435,7 +435,7 @@ static int software_interrupt(unsigned int pc, unsigned int insn, char *buf, siz
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, uintptr_t *addr)
|
int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, unsigned long *addr)
|
||||||
{
|
{
|
||||||
*addr = 0;
|
*addr = 0;
|
||||||
|
|
||||||
|
@ -467,7 +467,7 @@ int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, uintptr_t *ad
|
||||||
return block_data_transfer(pc, insn, buf, buf_len);
|
return block_data_transfer(pc, insn, buf, buf_len);
|
||||||
|
|
||||||
if ((insn & 0x0e000000) == 0x0a000000) {
|
if ((insn & 0x0e000000) == 0x0a000000) {
|
||||||
*addr = (long)pc + 8 + ((long)(insn << 8) >> 6);
|
*addr = (unsigned long)pc+8 + ((unsigned long)(insn << 8) >> 6);
|
||||||
return branch(pc, insn, buf, buf_len);
|
return branch(pc, insn, buf, buf_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,6 @@
|
||||||
#ifndef DISARM_H
|
#ifndef DISARM_H
|
||||||
#define DISARM_H
|
#define DISARM_H
|
||||||
|
|
||||||
int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, uintptr_t *sym);
|
int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, unsigned long *sym);
|
||||||
|
|
||||||
#endif /* DISARM_H */
|
#endif /* DISARM_H */
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
* See COPYING file in the top-level directory.
|
* See COPYING file in the top-level directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// XXX unimplemented: SYSCALL, BREAK, SYNC, SDBBP, T*, CACHE, PREF,
|
// unimplemented insns: MOV[FT], SYSCALL, BREAK, SYNC, SYNCI, T*, SDBBP, RDHWR,
|
||||||
// MOVF/MOVT, LWC*/LDC*, SWC*/SDC*, COP*.
|
// CACHE, PREF, LWC*/LDC*, SWC*/SDC*, and all of COP* (fpu, mmu, irq, exc, ...)
|
||||||
|
// unimplemented variants of insns: EHB, SSNOP (both SLL zero), JALR.HB, JR.HB
|
||||||
// however, it's certainly good enough for anything picodrive DRC throws at it.
|
// however, it's certainly good enough for anything picodrive DRC throws at it.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -79,6 +80,7 @@ struct insn {
|
||||||
#define OP_SPECIAL 0x00
|
#define OP_SPECIAL 0x00
|
||||||
static const struct insn special_insns[] = {
|
static const struct insn special_insns[] = {
|
||||||
{0x00, S_IMM_DT, "sll"},
|
{0x00, S_IMM_DT, "sll"},
|
||||||
|
// {0x01, , "movf\0movt"},
|
||||||
{0x02, S_IMM_DT|SR_BIT, "srl\0rotr"},
|
{0x02, S_IMM_DT|SR_BIT, "srl\0rotr"},
|
||||||
{0x03, S_IMM_DT, "sra"},
|
{0x03, S_IMM_DT, "sra"},
|
||||||
{0x04, REG_DTS, "sllv"},
|
{0x04, REG_DTS, "sllv"},
|
||||||
|
@ -146,6 +148,7 @@ static const struct insn special2_insns[] = {
|
||||||
{0x21, REG_DS, "clo" },
|
{0x21, REG_DS, "clo" },
|
||||||
{0x24, REG_DS, "dclz" },
|
{0x24, REG_DS, "dclz" },
|
||||||
{0x25, REG_DS, "dclo" },
|
{0x25, REG_DS, "dclo" },
|
||||||
|
// {0x37, , "sdbbp" },
|
||||||
};
|
};
|
||||||
|
|
||||||
// instructions with opcode SPECIAL3 (R-type)
|
// instructions with opcode SPECIAL3 (R-type)
|
||||||
|
@ -159,6 +162,7 @@ static const struct insn special3_insns[] = {
|
||||||
{0x05, F_IMM_TS, "dinsm" },
|
{0x05, F_IMM_TS, "dinsm" },
|
||||||
{0x06, F_IMM_TS, "dinsu" },
|
{0x06, F_IMM_TS, "dinsu" },
|
||||||
{0x07, F_IMM_TS, "dins" },
|
{0x07, F_IMM_TS, "dins" },
|
||||||
|
// {0x3b, , "rdhwr" },
|
||||||
};
|
};
|
||||||
|
|
||||||
// instruction with opcode SPECIAL3 and function *BSHFL
|
// instruction with opcode SPECIAL3 and function *BSHFL
|
||||||
|
@ -192,6 +196,7 @@ static const struct insn regimm_insns[] = {
|
||||||
{0x12, B_IMM_S, "bltzall"},
|
{0x12, B_IMM_S, "bltzall"},
|
||||||
{0x13, B_IMM_S, "bgezall"},
|
{0x13, B_IMM_S, "bgezall"},
|
||||||
{0x13, B_IMM_S, "bgezall"},
|
{0x13, B_IMM_S, "bgezall"},
|
||||||
|
// {0x1f, , "synci" },
|
||||||
};
|
};
|
||||||
|
|
||||||
// instructions with other opcodes (I-type)
|
// instructions with other opcodes (I-type)
|
||||||
|
@ -316,7 +321,7 @@ static unsigned long j_target(unsigned long pc, uint32_t insn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// main disassembler function
|
// main disassembler function
|
||||||
int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, uintptr_t *sym)
|
int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buflen, unsigned long *sym)
|
||||||
{
|
{
|
||||||
const struct insn *pi = decode_insn(insn);
|
const struct insn *pi = decode_insn(insn);
|
||||||
char *rs = register_names[(insn >> 21) & 0x1f];
|
char *rs = register_names[(insn >> 21) & 0x1f];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef DISMIPS_H
|
#ifndef DISMIPS_H
|
||||||
#define DISMIPS_H
|
#define DISMIPS_H
|
||||||
|
|
||||||
int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, uintptr_t *sym);
|
int dismips(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len, unsigned long *sym);
|
||||||
|
|
||||||
#endif /* DISMIPS_H */
|
#endif /* DISMIPS_H */
|
||||||
|
|
|
@ -37,14 +37,14 @@ void host_dasm(void *addr, int len)
|
||||||
void *end = (char *)addr + len;
|
void *end = (char *)addr + len;
|
||||||
const char *name;
|
const char *name;
|
||||||
char buf[64];
|
char buf[64];
|
||||||
long insn, symaddr;
|
unsigned long insn, symaddr;
|
||||||
|
|
||||||
while (addr < end) {
|
while (addr < end) {
|
||||||
name = lookup_name(addr);
|
name = lookup_name(addr);
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
printf("%s:\n", name);
|
printf("%s:\n", name);
|
||||||
|
|
||||||
insn = *(long *)addr;
|
insn = *(unsigned long *)addr;
|
||||||
printf(" %08lx %08lx ", (long)addr, insn);
|
printf(" %08lx %08lx ", (long)addr, insn);
|
||||||
if(disasm((unsigned)addr, insn, buf, sizeof(buf), &symaddr))
|
if(disasm((unsigned)addr, insn, buf, sizeof(buf), &symaddr))
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,15 +12,12 @@ ENDIAN=
|
||||||
compile_rodata ()
|
compile_rodata ()
|
||||||
{
|
{
|
||||||
$CC $CFLAGS -I .. -c /tmp/getoffs.c -o /tmp/getoffs.o || exit 1
|
$CC $CFLAGS -I .. -c /tmp/getoffs.c -o /tmp/getoffs.o || exit 1
|
||||||
# echo 'void dummy(void) { asm(""::"r" (&val)); }' >> /tmp/getoffs.c
|
|
||||||
# $CC $CFLAGS -I .. -nostdlib -Wl,-edummy /tmp/getoffs.c \
|
|
||||||
# -o /tmp/getoffs.o || exit 1
|
|
||||||
# find the name of the .rodata section (in case -fdata-sections is used)
|
# find the name of the .rodata section (in case -fdata-sections is used)
|
||||||
rosect=$(readelf -S /tmp/getoffs.o | grep '\.rodata\|\.sdata' |
|
rosect=$(readelf -S /tmp/getoffs.o | grep '\.rodata\|\.sdata' |
|
||||||
sed 's/^[^.]*././;s/ .*//')
|
sed 's/^[^.]*././;s/ .*//')
|
||||||
# read out .rodata section as hex string (should be only 4 or 8 bytes)
|
# read out .rodata section as hex string (should be only 4 bytes)
|
||||||
ro=$(readelf -x $rosect /tmp/getoffs.o | grep '0x' | cut -c14-48 |
|
ro=$(readelf -x $rosect /tmp/getoffs.o | grep '0x' | cut -c14-48 |
|
||||||
tr -d ' \n')
|
tr -d ' \n' | cut -c1-8)
|
||||||
if [ "$ENDIAN" = "le" ]; then
|
if [ "$ENDIAN" = "le" ]; then
|
||||||
# swap needed for le target
|
# swap needed for le target
|
||||||
hex=""
|
hex=""
|
||||||
|
@ -41,16 +38,18 @@ get_define () # prefix struct member member...
|
||||||
struct=$1; shift
|
struct=$1; shift
|
||||||
field=$(echo $* | sed 's/ /./g')
|
field=$(echo $* | sed 's/ /./g')
|
||||||
name=$(echo $* | sed 's/ /_/g')
|
name=$(echo $* | sed 's/ /_/g')
|
||||||
echo '#include "pico/pico_int.h"' > /tmp/getoffs.c
|
echo '#include <stdint.h>' > /tmp/getoffs.c
|
||||||
|
echo '#include "pico/pico_int.h"' >> /tmp/getoffs.c
|
||||||
echo "static const struct $struct p;" >> /tmp/getoffs.c
|
echo "static const struct $struct p;" >> /tmp/getoffs.c
|
||||||
echo "const int val = (char *)&p.$field - (char*)&p;" >>/tmp/getoffs.c
|
echo "const int32_t val = (char *)&p.$field - (char*)&p;" >>/tmp/getoffs.c
|
||||||
compile_rodata
|
compile_rodata
|
||||||
line=$(printf "#define %-20s 0x%04x" $prefix$name $rodata)
|
line=$(printf "#define %-20s 0x%04x" $prefix$name $rodata)
|
||||||
}
|
}
|
||||||
|
|
||||||
if echo $CFLAGS | grep -qe -flto; then CFLAGS="$CFLAGS -fno-lto"; fi
|
if echo $CFLAGS | grep -qe -flto; then CFLAGS="$CFLAGS -fno-lto"; fi
|
||||||
# determine endianess
|
# determine endianess
|
||||||
echo "const int val = 1;" >/tmp/getoffs.c
|
echo '#include <stdint.h>' >/tmp/getoffs.c
|
||||||
|
echo "const int32_t val = 1;" >>/tmp/getoffs.c
|
||||||
compile_rodata
|
compile_rodata
|
||||||
ENDIAN=$(if [ "$rodata" -eq 1 ]; then echo be; else echo le; fi)
|
ENDIAN=$(if [ "$rodata" -eq 1 ]; then echo be; else echo le; fi)
|
||||||
# output header
|
# output header
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue