initial TRAPA support

This commit is contained in:
Anthony Pesch 2017-07-28 17:43:41 -04:00
parent 98997e6551
commit d2fc3d4f48
10 changed files with 104 additions and 86 deletions

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) \

View File

@ -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() {

View File

@ -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 */

View File

@ -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 */

View File

@ -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;