mirror of https://github.com/inolen/redream.git
initial TRAPA support
This commit is contained in:
parent
98997e6551
commit
d2fc3d4f48
|
@ -46,8 +46,7 @@ static void sh4_swap_fpr_bank(struct sh4 *sh4) {
|
|||
}
|
||||
}
|
||||
|
||||
void sh4_sr_updated(void *data, uint32_t old_sr) {
|
||||
struct sh4 *sh4 = data;
|
||||
void sh4_sr_updated(struct sh4 *sh4, uint32_t old_sr) {
|
||||
struct sh4_context *ctx = &sh4->ctx;
|
||||
|
||||
prof_counter_add(COUNTER_sh4_sr_updates, 1);
|
||||
|
@ -62,8 +61,7 @@ void sh4_sr_updated(void *data, uint32_t old_sr) {
|
|||
}
|
||||
}
|
||||
|
||||
void sh4_fpscr_updated(void *data, uint32_t old_fpscr) {
|
||||
struct sh4 *sh4 = data;
|
||||
void sh4_fpscr_updated(struct sh4 *sh4, uint32_t old_fpscr) {
|
||||
struct sh4_context *ctx = &sh4->ctx;
|
||||
|
||||
if ((ctx->fpscr & FR_MASK) != (old_fpscr & FR_MASK)) {
|
||||
|
@ -159,17 +157,18 @@ static int sh4_init(struct device *dev) {
|
|||
sh4->guest->offset_instrs = (int)offsetof(struct sh4_context, ran_instrs);
|
||||
sh4->guest->offset_interrupts =
|
||||
(int)offsetof(struct sh4_context, pending_interrupts);
|
||||
sh4->guest->interrupt_check = &sh4_intc_check_pending;
|
||||
sh4->guest->interrupt_check = (jit_interrupt_cb)&sh4_intc_check_pending;
|
||||
|
||||
sh4->guest->ctx = &sh4->ctx;
|
||||
sh4->guest->mem = as_translate(sh4->memory_if->space, 0x0);
|
||||
sh4->guest->space = sh4->memory_if->space;
|
||||
sh4->guest->invalid_instr = &sh4_invalid_instr;
|
||||
sh4->guest->load_tlb = &sh4_mmu_load_tlb;
|
||||
sh4->guest->sq_prefetch = &sh4_ccn_sq_prefetch;
|
||||
sh4->guest->sleep = &sh4_sleep;
|
||||
sh4->guest->sr_updated = &sh4_sr_updated;
|
||||
sh4->guest->fpscr_updated = &sh4_fpscr_updated;
|
||||
sh4->guest->invalid_instr = (sh4_invalid_instr_cb)&sh4_invalid_instr;
|
||||
sh4->guest->trap = (sh4_trap_cb)&sh4_intc_trap;
|
||||
sh4->guest->ltlb = (sh4_ltlb_cb)&sh4_mmu_ltlb;
|
||||
sh4->guest->pref = (sh4_pref_cb)&sh4_ccn_pref;
|
||||
sh4->guest->sleep = (sh4_sleep_cb)&sh4_sleep;
|
||||
sh4->guest->sr_updated = (sh4_sr_updated_cb)&sh4_sr_updated;
|
||||
sh4->guest->fpscr_updated = (sh4_fpscr_updated_cb)&sh4_fpscr_updated;
|
||||
sh4->guest->lookup = &as_lookup;
|
||||
sh4->guest->r8 = &as_read8;
|
||||
sh4->guest->r16 = &as_read16;
|
||||
|
|
|
@ -81,7 +81,7 @@ DECLARE_COUNTER(sh4_instrs);
|
|||
AM_DECLARE(sh4_data_map);
|
||||
|
||||
/* ccn */
|
||||
void sh4_ccn_sq_prefetch(void *data, uint32_t addr);
|
||||
void sh4_ccn_pref(struct sh4 *sh4, uint32_t addr);
|
||||
uint32_t sh4_ccn_cache_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
|
||||
void sh4_ccn_cache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
||||
uint32_t data_mask);
|
||||
|
@ -112,11 +112,12 @@ void sh4_dmac_ddt(struct sh4 *sh, struct sh4_dtr *dtr);
|
|||
|
||||
/* intc */
|
||||
void sh4_intc_update_pending(struct sh4 *sh4);
|
||||
void sh4_intc_check_pending(void *data);
|
||||
void sh4_intc_check_pending(struct sh4 *sh4);
|
||||
void sh4_intc_reprioritize(struct sh4 *sh4);
|
||||
void sh4_intc_trap(struct sh4 *sh4, uint32_t num);
|
||||
|
||||
/* mmu */
|
||||
void sh4_mmu_load_tlb(void *data);
|
||||
void sh4_mmu_ltlb(struct sh4 *sh4);
|
||||
uint32_t sh4_mmu_itlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
|
||||
uint32_t sh4_mmu_utlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
|
||||
void sh4_mmu_itlb_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
||||
|
@ -130,7 +131,7 @@ void sh4_debug_menu(struct sh4 *sh4);
|
|||
void sh4_reset(struct sh4 *sh4, uint32_t pc);
|
||||
void sh4_raise_interrupt(struct sh4 *sh4, enum sh4_interrupt intr);
|
||||
void sh4_clear_interrupt(struct sh4 *sh4, enum sh4_interrupt intr);
|
||||
void sh4_sr_updated(void *data, uint32_t old_sr);
|
||||
void sh4_fpscr_updated(void *data, uint32_t old_fpscr);
|
||||
void sh4_sr_updated(struct sh4 *sh4, uint32_t old_sr);
|
||||
void sh4_fpscr_updated(struct sh4 *sh4, uint32_t old_fpscr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -28,14 +28,12 @@ static void sh4_ccn_reset(struct sh4 *sh4) {
|
|||
jit_invalidate_blocks(sh4->jit);
|
||||
}
|
||||
|
||||
void sh4_ccn_sq_prefetch(void *data, uint32_t addr) {
|
||||
PROF_ENTER("cpu", "sh4_ccn_sq_prefetch");
|
||||
void sh4_ccn_pref(struct sh4 *sh4, uint32_t addr) {
|
||||
PROF_ENTER("cpu", "sh4_ccn_pref");
|
||||
|
||||
/* make sure this is a sq related prefetch */
|
||||
DCHECK(addr >= 0xe0000000 && addr <= 0xe3ffffff);
|
||||
|
||||
struct sh4 *sh4 = data;
|
||||
|
||||
uint32_t dst = 0x0;
|
||||
uint32_t sqi = (addr & 0x20) >> 5;
|
||||
|
||||
|
|
|
@ -11,47 +11,8 @@ static struct sh4_interrupt_info sh4_interrupts[NUM_SH_INTERRUPTS] = {
|
|||
#undef SH4_INT
|
||||
};
|
||||
|
||||
void sh4_intc_update_pending(struct sh4 *sh4) {
|
||||
int min_priority = (sh4->ctx.sr & I_MASK) >> I_BIT;
|
||||
uint64_t mask = ~sh4->priority_mask[min_priority];
|
||||
int block = (sh4->ctx.sr & BL_MASK) == BL_MASK;
|
||||
|
||||
/* ignore block bit when sleeping */
|
||||
if (sh4->ctx.sleep_mode) {
|
||||
block = 0;
|
||||
}
|
||||
|
||||
/* mask all interrupts if interrupt block bit is set */
|
||||
if (block) {
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
sh4->ctx.pending_interrupts = sh4->requested_interrupts & mask;
|
||||
}
|
||||
|
||||
void sh4_intc_check_pending(void *data) {
|
||||
struct sh4 *sh4 = data;
|
||||
|
||||
if (!sh4->ctx.pending_interrupts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* process the highest priority in the pending vector */
|
||||
int n = 63 - clz64(sh4->ctx.pending_interrupts);
|
||||
enum sh4_interrupt intr = sh4->sorted_interrupts[n];
|
||||
struct sh4_interrupt_info *int_info = &sh4_interrupts[intr];
|
||||
|
||||
/* ensure sr is up to date */
|
||||
sh4_implode_sr(&sh4->ctx);
|
||||
|
||||
*sh4->INTEVT = int_info->intevt;
|
||||
sh4->ctx.ssr = sh4->ctx.sr;
|
||||
sh4->ctx.spc = sh4->ctx.pc;
|
||||
sh4->ctx.sgr = sh4->ctx.r[15];
|
||||
sh4->ctx.sr |= (BL_MASK | MD_MASK | RB_MASK);
|
||||
sh4->ctx.pc = sh4->ctx.vbr + 0x600;
|
||||
sh4->ctx.sleep_mode = 0;
|
||||
sh4_sr_updated(sh4, sh4->ctx.ssr);
|
||||
void sh4_intc_trap(struct sh4 *sh4, uint32_t num) {
|
||||
LOG_FATAL("sh4_intc_trap %d", num);
|
||||
}
|
||||
|
||||
/* generate a sorted set of interrupts based on their priority. these sorted
|
||||
|
@ -100,6 +61,47 @@ void sh4_intc_reprioritize(struct sh4 *sh4) {
|
|||
sh4_intc_update_pending(sh4);
|
||||
}
|
||||
|
||||
void sh4_intc_check_pending(struct sh4 *sh4) {
|
||||
if (!sh4->ctx.pending_interrupts) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* process the highest priority in the pending vector */
|
||||
int n = 63 - clz64(sh4->ctx.pending_interrupts);
|
||||
enum sh4_interrupt intr = sh4->sorted_interrupts[n];
|
||||
struct sh4_interrupt_info *int_info = &sh4_interrupts[intr];
|
||||
|
||||
/* ensure sr is up to date */
|
||||
sh4_implode_sr(&sh4->ctx);
|
||||
|
||||
*sh4->INTEVT = int_info->intevt;
|
||||
sh4->ctx.ssr = sh4->ctx.sr;
|
||||
sh4->ctx.spc = sh4->ctx.pc;
|
||||
sh4->ctx.sgr = sh4->ctx.r[15];
|
||||
sh4->ctx.sr |= (BL_MASK | MD_MASK | RB_MASK);
|
||||
sh4->ctx.pc = sh4->ctx.vbr + 0x600;
|
||||
sh4->ctx.sleep_mode = 0;
|
||||
sh4_sr_updated(sh4, sh4->ctx.ssr);
|
||||
}
|
||||
|
||||
void sh4_intc_update_pending(struct sh4 *sh4) {
|
||||
int min_priority = (sh4->ctx.sr & I_MASK) >> I_BIT;
|
||||
uint64_t mask = ~sh4->priority_mask[min_priority];
|
||||
int block = (sh4->ctx.sr & BL_MASK) == BL_MASK;
|
||||
|
||||
/* ignore block bit when sleeping */
|
||||
if (sh4->ctx.sleep_mode) {
|
||||
block = 0;
|
||||
}
|
||||
|
||||
/* mask all interrupts if interrupt block bit is set */
|
||||
if (block) {
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
sh4->ctx.pending_interrupts = sh4->requested_interrupts & mask;
|
||||
}
|
||||
|
||||
REG_W32(sh4_cb, IPRA) {
|
||||
struct sh4 *sh4 = dc->sh4;
|
||||
*sh4->IPRA = value;
|
||||
|
|
|
@ -37,9 +37,7 @@ static void sh4_mmu_utlb_sync(struct sh4 *sh4, struct sh4_tlb_entry *entry) {
|
|||
|
||||
static void sh4_mmu_translate(struct sh4 *sh4, uint32_t addr) {}
|
||||
|
||||
void sh4_mmu_load_tlb(void *data) {
|
||||
struct sh4 *sh4 = data;
|
||||
|
||||
void sh4_mmu_ltlb(struct sh4 *sh4) {
|
||||
uint32_t n = sh4->MMUCR->URC;
|
||||
struct sh4_tlb_entry *entry = &sh4->utlb[n];
|
||||
entry->lo = *sh4->PTEL;
|
||||
|
|
|
@ -383,12 +383,14 @@ typedef int32_t int128_t[4];
|
|||
|
||||
#define INVALID_INSTR() guest->invalid_instr(guest->data)
|
||||
|
||||
#define PREF_SQ_COND(c, addr) if (c) { guest->sq_prefetch(guest->data, addr); }
|
||||
#define TRAP(num) guest->trap(guest->data, num)
|
||||
|
||||
#define LDTLB() guest->ltlb(guest->data)
|
||||
|
||||
#define PREF_COND(c, addr) if (c) { guest->pref(guest->data, addr); }
|
||||
|
||||
#define SLEEP() guest->sleep(guest->data)
|
||||
|
||||
#define LDTLB() guest->load_tlb(guest->data)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
#define INSTR(name) \
|
||||
|
|
|
@ -3,16 +3,25 @@
|
|||
|
||||
#include "jit/jit.h"
|
||||
|
||||
typedef void (*sh4_invalid_instr_cb)(void *);
|
||||
typedef void (*sh4_trap_cb)(void *, uint32_t);
|
||||
typedef void (*sh4_ltlb_cb)(void *);
|
||||
typedef void (*sh4_pref_cb)(void *, uint32_t);
|
||||
typedef void (*sh4_sleep_cb)(void *);
|
||||
typedef void (*sh4_sr_updated_cb)(void *, uint32_t);
|
||||
typedef void (*sh4_fpscr_updated_cb)(void *, uint32_t);
|
||||
|
||||
struct sh4_guest {
|
||||
struct jit_guest;
|
||||
|
||||
/* runtime interface */
|
||||
void (*invalid_instr)(void *);
|
||||
void (*load_tlb)(void *);
|
||||
void (*sq_prefetch)(void *, uint32_t);
|
||||
void (*sleep)(void *);
|
||||
void (*sr_updated)(void *, uint32_t);
|
||||
void (*fpscr_updated)(void *, uint32_t);
|
||||
sh4_invalid_instr_cb invalid_instr;
|
||||
sh4_trap_cb trap;
|
||||
sh4_ltlb_cb ltlb;
|
||||
sh4_pref_cb pref;
|
||||
sh4_sleep_cb sleep;
|
||||
sh4_sr_updated_cb sr_updated;
|
||||
sh4_fpscr_updated_cb fpscr_updated;
|
||||
};
|
||||
|
||||
static inline struct sh4_guest *sh4_guest_create() {
|
||||
|
|
|
@ -1354,7 +1354,7 @@ INSTR(PREF) {
|
|||
/* check that the address is between 0xe0000000 and 0xe3ffffff */
|
||||
I32 ea = LOAD_GPR_I32(i.def.rn);
|
||||
I32 cond = CMPEQ_IMM_I32(LSHR_IMM_I32(ea, 26), 0x38);
|
||||
PREF_SQ_COND(cond, ea);
|
||||
PREF_COND(cond, ea);
|
||||
NEXT_INSTR();
|
||||
}
|
||||
|
||||
|
@ -1575,7 +1575,7 @@ INSTR(STSMPR) {
|
|||
|
||||
/* TRAPA #imm */
|
||||
INSTR(TRAPA) {
|
||||
LOG_FATAL("TRAPA not implemented");
|
||||
TRAP(i.imm.imm);
|
||||
}
|
||||
|
||||
/* FLDI0 FRn 1111nnnn10001101 */
|
||||
|
|
|
@ -427,10 +427,24 @@ static void store_fpscr(struct sh4_guest *guest, struct ir *ir,
|
|||
ir_call_1(ir, invalid_instr, data); \
|
||||
}
|
||||
|
||||
#define PREF_SQ_COND(c, addr) { \
|
||||
struct ir_value *sq_prefetch = ir_alloc_i64(ir, (uint64_t)guest->sq_prefetch); \
|
||||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
ir_call_cond_2(ir, c, sq_prefetch, data, addr); \
|
||||
#define TRAP(num) { \
|
||||
struct ir_value *trap = ir_alloc_i64(ir, (uint64_t)guest->trap); \
|
||||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
struct ir_value *imm = ir_alloc_i32(ir, num); \
|
||||
ir_call_2(ir, trap, data, imm); \
|
||||
}
|
||||
|
||||
#define LDTLB() { \
|
||||
struct ir_value *ltlb = ir_alloc_i64(ir, (uint64_t)guest->ltlb); \
|
||||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
ir_call_1(ir, ltlb, data); \
|
||||
}
|
||||
|
||||
|
||||
#define PREF_COND(c, addr) { \
|
||||
struct ir_value *pref = ir_alloc_i64(ir, (uint64_t)guest->pref); \
|
||||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
ir_call_cond_2(ir, c, pref, data, addr); \
|
||||
}
|
||||
|
||||
#define SLEEP() { \
|
||||
|
@ -438,12 +452,6 @@ static void store_fpscr(struct sh4_guest *guest, struct ir *ir,
|
|||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
ir_call_1(ir, sleep, data); \
|
||||
}
|
||||
|
||||
#define LDTLB() { \
|
||||
struct ir_value *load_tlb = ir_alloc_i64(ir, (uint64_t)guest->load_tlb); \
|
||||
struct ir_value *data = ir_alloc_i64(ir, (uint64_t)guest->data); \
|
||||
ir_call_1(ir, load_tlb, data); \
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ struct lse;
|
|||
struct ra;
|
||||
struct val;
|
||||
|
||||
typedef void (*jit_interrupt_cb)(void *);
|
||||
typedef uint32_t (*mem_read_cb)(void *, uint32_t, uint32_t);
|
||||
typedef void (*mem_write_cb)(void *, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
|
@ -100,7 +101,7 @@ struct jit_guest {
|
|||
int offset_cycles;
|
||||
int offset_instrs;
|
||||
int offset_interrupts;
|
||||
void (*interrupt_check)(void *);
|
||||
jit_interrupt_cb interrupt_check;
|
||||
|
||||
/* memory interface */
|
||||
void *ctx;
|
||||
|
|
Loading…
Reference in New Issue