mirror of https://github.com/inolen/redream.git
fixed bitrot in recc
removed armv3 software interrupt callback removed circular dependency between jit <-> x64_dispatch
This commit is contained in:
parent
89541723f7
commit
648041696f
|
@ -26,7 +26,7 @@ struct arm7 {
|
|||
|
||||
/* jit */
|
||||
struct jit *jit;
|
||||
struct armv3_guest *guest;
|
||||
struct jit_guest *guest;
|
||||
struct jit_frontend *frontend;
|
||||
struct jit_backend *backend;
|
||||
|
||||
|
@ -92,17 +92,6 @@ static void arm7_restore_mode(void *data) {
|
|||
arm7_update_pending_interrupts(arm);
|
||||
}
|
||||
|
||||
static void arm7_software_interrupt(void *data) {
|
||||
struct arm7 *arm = data;
|
||||
|
||||
uint32_t newsr = (arm->ctx.r[CPSR] & ~M_MASK);
|
||||
newsr |= I_MASK | MODE_SVC;
|
||||
|
||||
arm7_switch_mode(arm, newsr);
|
||||
arm->ctx.r[14] = arm->ctx.r[15] + 4;
|
||||
arm->ctx.r[15] = 0x08;
|
||||
}
|
||||
|
||||
static void arm7_update_pending_interrupts(struct arm7 *arm) {
|
||||
uint32_t interrupt_mask = 0;
|
||||
|
||||
|
@ -113,7 +102,7 @@ static void arm7_update_pending_interrupts(struct arm7 *arm) {
|
|||
arm->ctx.pending_interrupts = arm->requested_interrupts & interrupt_mask;
|
||||
}
|
||||
|
||||
void arm7_check_pending_interrupts(void *data) {
|
||||
static void arm7_check_interrupts(void *data) {
|
||||
struct arm7 *arm = data;
|
||||
|
||||
if (!arm->ctx.pending_interrupts) {
|
||||
|
@ -132,6 +121,14 @@ void arm7_check_pending_interrupts(void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
static void arm7_link_code(struct arm7 *arm, void *branch, uint32_t target) {
|
||||
jit_link_code(arm->jit, branch, target);
|
||||
}
|
||||
|
||||
static void arm7_compile_code(struct arm7 *arm, uint32_t addr) {
|
||||
jit_compile_code(arm->jit, addr);
|
||||
}
|
||||
|
||||
void arm7_raise_interrupt(struct arm7 *arm, enum arm7_interrupt intr) {
|
||||
arm->requested_interrupts |= intr;
|
||||
arm7_update_pending_interrupts(arm);
|
||||
|
@ -140,7 +137,7 @@ void arm7_raise_interrupt(struct arm7 *arm, enum arm7_interrupt intr) {
|
|||
void arm7_reset(struct arm7 *arm) {
|
||||
LOG_INFO("arm7_reset");
|
||||
|
||||
jit_free_blocks(arm->jit);
|
||||
jit_free_code(arm->jit);
|
||||
|
||||
/* reset context */
|
||||
memset(&arm->ctx, 0, sizeof(arm->ctx));
|
||||
|
@ -174,49 +171,58 @@ static void arm7_run(struct device *dev, int64_t ns) {
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void arm7_guest_destroy(struct jit_guest *guest) {
|
||||
free((struct armv3_guest *)guest);
|
||||
}
|
||||
|
||||
static struct jit_guest *arm7_guest_create(struct arm7 *arm) {
|
||||
struct armv3_guest *guest = calloc(1, sizeof(struct armv3_guest));
|
||||
|
||||
/* dispatch cache */
|
||||
guest->addr_mask = 0x001ffffc;
|
||||
|
||||
/* memory interface */
|
||||
guest->ctx = &arm->ctx;
|
||||
guest->mem = as_translate(arm->memory_if->space, 0x0);
|
||||
guest->space = arm->memory_if->space;
|
||||
guest->lookup = &as_lookup;
|
||||
guest->r8 = &as_read8;
|
||||
guest->r16 = &as_read16;
|
||||
guest->r32 = &as_read32;
|
||||
guest->w8 = &as_write8;
|
||||
guest->w16 = &as_write16;
|
||||
guest->w32 = &as_write32;
|
||||
|
||||
/* runtime interface */
|
||||
guest->data = arm;
|
||||
guest->offset_pc = (int)offsetof(struct armv3_context, r[15]);
|
||||
guest->offset_cycles = (int)offsetof(struct armv3_context, run_cycles);
|
||||
guest->offset_instrs = (int)offsetof(struct armv3_context, ran_instrs);
|
||||
guest->offset_interrupts =
|
||||
(int)offsetof(struct armv3_context, pending_interrupts);
|
||||
guest->compile_code = (jit_compile_cb)&arm7_compile_code;
|
||||
guest->link_code = (jit_link_cb)&arm7_link_code;
|
||||
guest->check_interrupts = (jit_interrupt_cb)&arm7_check_interrupts;
|
||||
guest->switch_mode = (armv3_switch_mode_cb)&arm7_switch_mode;
|
||||
guest->restore_mode = (armv3_restore_mode_cb)&arm7_restore_mode;
|
||||
|
||||
return (struct jit_guest *)guest;
|
||||
}
|
||||
|
||||
static int arm7_init(struct device *dev) {
|
||||
struct arm7 *arm = (struct arm7 *)dev;
|
||||
struct dreamcast *dc = arm->dc;
|
||||
|
||||
/* initialize jit and its interfaces */
|
||||
arm->frontend = armv3_frontend_create();
|
||||
|
||||
/* initialize jit */
|
||||
arm->guest = arm7_guest_create(arm);
|
||||
arm->frontend = armv3_frontend_create(arm->guest);
|
||||
#if ARCH_X64
|
||||
DEFINE_JIT_CODE_BUFFER(arm7_code);
|
||||
arm->backend = x64_backend_create(arm7_code, sizeof(arm7_code));
|
||||
arm->backend = x64_backend_create(arm->guest, arm7_code, sizeof(arm7_code));
|
||||
#else
|
||||
arm->backend = interp_backend_create();
|
||||
arm->backend = interp_backend_create(arm->guest, arm->frontend);
|
||||
#endif
|
||||
|
||||
{
|
||||
arm->guest = armv3_guest_create();
|
||||
|
||||
arm->guest->addr_mask = 0x001ffffc;
|
||||
arm->guest->offset_pc = (int)offsetof(struct armv3_context, r[15]);
|
||||
arm->guest->offset_cycles = (int)offsetof(struct armv3_context, run_cycles);
|
||||
arm->guest->offset_instrs = (int)offsetof(struct armv3_context, ran_instrs);
|
||||
arm->guest->offset_interrupts =
|
||||
(int)offsetof(struct armv3_context, pending_interrupts);
|
||||
arm->guest->data = arm;
|
||||
arm->guest->check_interrupts = &arm7_check_pending_interrupts;
|
||||
|
||||
arm->guest->ctx = &arm->ctx;
|
||||
arm->guest->mem = as_translate(arm->memory_if->space, 0x0);
|
||||
arm->guest->space = arm->memory_if->space;
|
||||
arm->guest->switch_mode = &arm7_switch_mode;
|
||||
arm->guest->restore_mode = &arm7_restore_mode;
|
||||
arm->guest->software_interrupt = &arm7_software_interrupt;
|
||||
arm->guest->lookup = &as_lookup;
|
||||
arm->guest->r8 = &as_read8;
|
||||
arm->guest->r16 = &as_read16;
|
||||
arm->guest->r32 = &as_read32;
|
||||
arm->guest->w8 = &as_write8;
|
||||
arm->guest->w16 = &as_write16;
|
||||
arm->guest->w32 = &as_write32;
|
||||
}
|
||||
|
||||
arm->jit = jit_create("arm7", arm->frontend, arm->backend,
|
||||
(struct jit_guest *)arm->guest);
|
||||
arm->jit = jit_create("arm7", arm->frontend, arm->backend);
|
||||
|
||||
arm->wave_ram = memory_translate(dc->memory, "aica wave ram", 0x0);
|
||||
|
||||
|
@ -225,7 +231,7 @@ static int arm7_init(struct device *dev) {
|
|||
|
||||
void arm7_destroy(struct arm7 *arm) {
|
||||
jit_destroy(arm->jit);
|
||||
armv3_guest_destroy(arm->guest);
|
||||
arm7_guest_destroy(arm->guest);
|
||||
arm->frontend->destroy(arm->frontend);
|
||||
arm->backend->destroy(arm->backend);
|
||||
|
||||
|
|
|
@ -153,6 +153,14 @@ static void sh4_check_interrupts(struct sh4 *sh4) {
|
|||
sh4_sr_updated(sh4, sh4->ctx.ssr);
|
||||
}
|
||||
|
||||
static void sh4_link_code(struct sh4 *sh4, void *branch, uint32_t target) {
|
||||
jit_link_code(sh4->jit, branch, target);
|
||||
}
|
||||
|
||||
static void sh4_compile_code(struct sh4 *sh4, uint32_t addr) {
|
||||
jit_compile_code(sh4->jit, addr);
|
||||
}
|
||||
|
||||
static void sh4_invalid_instr(struct sh4 *sh4) {
|
||||
sh4_exception(sh4, SH4_EXC_ILLINSTR);
|
||||
}
|
||||
|
@ -174,53 +182,62 @@ static void sh4_run(struct device *dev, int64_t ns) {
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void sh4_guest_destroy(struct jit_guest *guest) {
|
||||
free((struct sh4_guest *)guest);
|
||||
}
|
||||
|
||||
static struct jit_guest *sh4_guest_create(struct sh4 *sh4) {
|
||||
struct sh4_guest *guest = calloc(1, sizeof(struct sh4_guest));
|
||||
|
||||
/* dispatch cache */
|
||||
guest->addr_mask = 0x00fffffe;
|
||||
|
||||
/* memory interface */
|
||||
guest->ctx = &sh4->ctx;
|
||||
guest->mem = as_translate(sh4->memory_if->space, 0x0);
|
||||
guest->space = sh4->memory_if->space;
|
||||
guest->lookup = &as_lookup;
|
||||
guest->r8 = &as_read8;
|
||||
guest->r16 = &as_read16;
|
||||
guest->r32 = &as_read32;
|
||||
guest->w8 = &as_write8;
|
||||
guest->w16 = &as_write16;
|
||||
guest->w32 = &as_write32;
|
||||
|
||||
/* runtime interface */
|
||||
guest->data = sh4;
|
||||
guest->offset_pc = (int)offsetof(struct sh4_context, pc);
|
||||
guest->offset_cycles = (int)offsetof(struct sh4_context, run_cycles);
|
||||
guest->offset_instrs = (int)offsetof(struct sh4_context, ran_instrs);
|
||||
guest->offset_interrupts =
|
||||
(int)offsetof(struct sh4_context, pending_interrupts);
|
||||
guest->compile_code = (jit_compile_cb)&sh4_compile_code;
|
||||
guest->link_code = (jit_link_cb)&sh4_link_code;
|
||||
guest->check_interrupts = (jit_interrupt_cb)&sh4_check_interrupts;
|
||||
guest->invalid_instr = (sh4_invalid_instr_cb)&sh4_invalid_instr;
|
||||
guest->ltlb = (sh4_ltlb_cb)&sh4_mmu_ltlb;
|
||||
guest->pref = (sh4_pref_cb)&sh4_ccn_pref;
|
||||
guest->sleep = (sh4_sleep_cb)&sh4_sleep;
|
||||
guest->sr_updated = (sh4_sr_updated_cb)&sh4_sr_updated;
|
||||
guest->fpscr_updated = (sh4_fpscr_updated_cb)&sh4_fpscr_updated;
|
||||
|
||||
return (struct jit_guest *)guest;
|
||||
}
|
||||
|
||||
static int sh4_init(struct device *dev) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
/* initialize jit and its interfaces */
|
||||
sh4->frontend = sh4_frontend_create();
|
||||
|
||||
/* initialize jit */
|
||||
sh4->guest = sh4_guest_create(sh4);
|
||||
sh4->frontend = sh4_frontend_create(sh4->guest);
|
||||
#if ARCH_X64
|
||||
DEFINE_JIT_CODE_BUFFER(sh4_code);
|
||||
sh4->backend = x64_backend_create(sh4_code, sizeof(sh4_code));
|
||||
sh4->backend = x64_backend_create(sh4->guest, sh4_code, sizeof(sh4_code));
|
||||
#else
|
||||
sh4->backend = interp_backend_create();
|
||||
sh4->backend = interp_backend_create(sh4->guest, sh4->frontend);
|
||||
#endif
|
||||
|
||||
{
|
||||
sh4->guest = sh4_guest_create();
|
||||
|
||||
sh4->guest->addr_mask = 0x00fffffe;
|
||||
|
||||
sh4->guest->data = sh4;
|
||||
sh4->guest->offset_pc = (int)offsetof(struct sh4_context, pc);
|
||||
sh4->guest->offset_cycles = (int)offsetof(struct sh4_context, run_cycles);
|
||||
sh4->guest->offset_instrs = (int)offsetof(struct sh4_context, ran_instrs);
|
||||
sh4->guest->offset_interrupts =
|
||||
(int)offsetof(struct sh4_context, pending_interrupts);
|
||||
sh4->guest->check_interrupts = (jit_interrupt_cb)&sh4_check_interrupts;
|
||||
|
||||
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_cb)&sh4_invalid_instr;
|
||||
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;
|
||||
sh4->guest->r32 = &as_read32;
|
||||
sh4->guest->w8 = &as_write8;
|
||||
sh4->guest->w16 = &as_write16;
|
||||
sh4->guest->w32 = &as_write32;
|
||||
}
|
||||
|
||||
sh4->jit = jit_create("sh4", sh4->frontend, sh4->backend,
|
||||
(struct jit_guest *)sh4->guest);
|
||||
sh4->jit = jit_create("sh4", sh4->frontend, sh4->backend);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -242,7 +259,7 @@ void sh4_set_exception_handler(struct sh4 *sh4,
|
|||
}
|
||||
|
||||
void sh4_reset(struct sh4 *sh4, uint32_t pc) {
|
||||
jit_free_blocks(sh4->jit);
|
||||
jit_free_code(sh4->jit);
|
||||
|
||||
/* reset context */
|
||||
memset(&sh4->ctx, 0, sizeof(sh4->ctx));
|
||||
|
@ -276,17 +293,17 @@ void sh4_debug_menu(struct sh4 *sh4) {
|
|||
if (igBeginMainMenuBar()) {
|
||||
if (igBeginMenu("SH4", 1)) {
|
||||
if (igMenuItem("clear cache", NULL, 0, 1)) {
|
||||
jit_invalidate_blocks(sh4->jit);
|
||||
jit_invalidate_code(sh4->jit);
|
||||
}
|
||||
|
||||
if (!jit->dump_blocks) {
|
||||
if (igMenuItem("start dumping blocks", NULL, 0, 1)) {
|
||||
jit->dump_blocks = 1;
|
||||
jit_invalidate_blocks(jit);
|
||||
if (!jit->dump_code) {
|
||||
if (igMenuItem("start dumping code", NULL, 0, 1)) {
|
||||
jit->dump_code = 1;
|
||||
jit_invalidate_code(jit);
|
||||
}
|
||||
} else {
|
||||
if (igMenuItem("stop dumping blocks", NULL, 1, 1)) {
|
||||
jit->dump_blocks = 0;
|
||||
if (igMenuItem("stop dumping code", NULL, 1, 1)) {
|
||||
jit->dump_code = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ struct dreamcast;
|
|||
struct jit;
|
||||
struct jit_backend;
|
||||
struct jit_frontend;
|
||||
struct sh4_guest;
|
||||
struct jit_guest;
|
||||
|
||||
#define SH4_CLOCK_FREQ INT64_C(200000000)
|
||||
|
||||
|
@ -58,7 +58,7 @@ struct sh4 {
|
|||
|
||||
/* jit */
|
||||
struct jit *jit;
|
||||
struct sh4_guest *guest;
|
||||
struct jit_guest *guest;
|
||||
struct jit_frontend *frontend;
|
||||
struct jit_backend *backend;
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ static void sh4_ccn_reset(struct sh4 *sh4) {
|
|||
end the block */
|
||||
LOG_INFO("sh4_ccn_reset");
|
||||
|
||||
jit_invalidate_blocks(sh4->jit);
|
||||
jit_invalidate_code(sh4->jit);
|
||||
}
|
||||
|
||||
void sh4_ccn_pref(struct sh4 *sh4, uint32_t addr) {
|
||||
|
|
|
@ -111,7 +111,7 @@ void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr) {
|
|||
as_write16(sh4->memory_if->space, addr, bp->instr);
|
||||
|
||||
/* free code cache to remove block containing the invalid instruction */
|
||||
jit_free_blocks(sh4->jit);
|
||||
jit_free_code(sh4->jit);
|
||||
|
||||
destroy_breakpoint(sh4, bp);
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr) {
|
|||
as_write16(sh4->memory_if->space, addr, 0);
|
||||
|
||||
/* free code cache to remove block containing the original instruction */
|
||||
jit_free_blocks(sh4->jit);
|
||||
jit_free_code(sh4->jit);
|
||||
}
|
||||
|
||||
void sh4_dbg_step(struct device *dev) {
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
#include <stdlib.h>
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_backend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
#include "jit/jit_guest.h"
|
||||
|
||||
struct interp_backend {
|
||||
struct jit_backend;
|
||||
|
||||
/* used to resolve the fallback handler for each instruction */
|
||||
struct jit_frontend *frontend;
|
||||
};
|
||||
|
||||
static void interp_backend_run_code(struct jit_backend *base, int cycles) {
|
||||
struct interp_backend *backend = (struct interp_backend *)base;
|
||||
struct jit *jit = backend->jit;
|
||||
struct jit_guest *guest = jit->guest;
|
||||
struct jit_frontend *frontend = backend->frontend;
|
||||
struct jit_guest *guest = backend->guest;
|
||||
uint8_t *ctx = guest->ctx;
|
||||
uint32_t *pc = (uint32_t *)(ctx + guest->offset_pc);
|
||||
int32_t *run_cycles = (int32_t *)(ctx + guest->offset_cycles);
|
||||
|
@ -27,8 +31,7 @@ static void interp_backend_run_code(struct jit_backend *base, int cycles) {
|
|||
do {
|
||||
uint32_t addr = *pc;
|
||||
uint32_t data = guest->r32(guest->space, addr);
|
||||
const struct jit_opdef *def =
|
||||
jit->frontend->lookup_op(jit->frontend, &data);
|
||||
const struct jit_opdef *def = frontend->lookup_op(frontend, &data);
|
||||
def->fallback(guest, addr, data);
|
||||
cycles += def->cycles;
|
||||
instrs += 1;
|
||||
|
@ -57,14 +60,10 @@ static void interp_backend_destroy(struct jit_backend *base) {
|
|||
free(backend);
|
||||
}
|
||||
|
||||
static void interp_backend_init(struct jit_backend *base) {
|
||||
struct interp_backend *backend = (struct interp_backend *)base;
|
||||
}
|
||||
|
||||
struct jit_backend *interp_backend_create() {
|
||||
struct jit_backend *interp_backend_create(struct jit_frontend *frontend) {
|
||||
struct interp_backend *backend = calloc(1, sizeof(struct interp_backend));
|
||||
|
||||
backend->init = &interp_backend_init;
|
||||
backend->frontend = frontend;
|
||||
backend->destroy = &interp_backend_destroy;
|
||||
|
||||
/* compile interface */
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef INTERP_BACKEND_H
|
||||
#define INTERP_BACKEND_H
|
||||
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/jit_backend.h"
|
||||
|
||||
struct jit_backend *interp_backend_create();
|
||||
struct jit_frontend;
|
||||
|
||||
struct jit_backend *interp_backend_create(struct jit_frontend *frontend);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,11 +4,12 @@ extern "C" {
|
|||
#include "core/exception_handler.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/profiler.h"
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/backend/x64/x64_backend.h"
|
||||
#include "jit/backend/x64/x64_disassembler.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_backend.h"
|
||||
#include "jit/jit_guest.h"
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -309,8 +310,7 @@ static void x64_backend_emit_epilogue(struct x64_backend *backend,
|
|||
|
||||
static void x64_backend_emit_prologue(struct x64_backend *backend,
|
||||
struct jit_block *block) {
|
||||
struct jit *jit = backend->base.jit;
|
||||
struct jit_guest *guest = jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
auto &e = *backend->codegen;
|
||||
|
||||
|
@ -479,7 +479,7 @@ static void x64_backend_emit_constants(struct x64_backend *backend) {
|
|||
static int x64_backend_handle_exception(struct jit_backend *base,
|
||||
struct exception_state *ex) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
const uint8_t *data = (const uint8_t *)ex->thread_state.rip;
|
||||
|
||||
|
@ -631,27 +631,13 @@ static void x64_backend_destroy(struct jit_backend *base) {
|
|||
free(backend);
|
||||
}
|
||||
|
||||
static void x64_backend_init(struct jit_backend *base) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
x64_dispatch_init(backend);
|
||||
|
||||
/* emit thunks into a fixed amount of space to speed up resets */
|
||||
x64_dispatch_emit_thunks(backend);
|
||||
x64_backend_emit_thunks(backend);
|
||||
x64_backend_emit_constants(backend);
|
||||
CHECK_LT(backend->codegen->getSize(), X64_THUNK_SIZE);
|
||||
}
|
||||
|
||||
struct jit_backend *x64_backend_create(void *code, int code_size) {
|
||||
struct jit_backend *x64_backend_create(struct jit_guest *guest, void *code,
|
||||
int code_size) {
|
||||
struct x64_backend *backend =
|
||||
(struct x64_backend *)calloc(1, sizeof(struct x64_backend));
|
||||
Xbyak::util::Cpu cpu;
|
||||
|
||||
int r = protect_pages(code, code_size, ACC_READWRITEEXEC);
|
||||
CHECK(r);
|
||||
|
||||
backend->base.init = &x64_backend_init;
|
||||
backend->base.guest = guest;
|
||||
backend->base.destroy = &x64_backend_destroy;
|
||||
|
||||
/* compile interface */
|
||||
|
@ -672,11 +658,23 @@ struct jit_backend *x64_backend_create(void *code, int code_size) {
|
|||
backend->base.patch_edge = &x64_dispatch_patch_edge;
|
||||
backend->base.restore_edge = &x64_dispatch_restore_edge;
|
||||
|
||||
/* setup codegen buffer */
|
||||
int r = protect_pages(code, code_size, ACC_READWRITEEXEC);
|
||||
CHECK(r);
|
||||
|
||||
backend->codegen = new Xbyak::CodeGenerator(code_size, code);
|
||||
backend->use_avx = cpu.has(Xbyak::util::Cpu::tAVX2);
|
||||
|
||||
/* create disassembler */
|
||||
int res = cs_open(CS_ARCH_X86, CS_MODE_64, &backend->capstone_handle);
|
||||
CHECK_EQ(res, CS_ERR_OK);
|
||||
|
||||
/* emit initial thunks */
|
||||
x64_dispatch_init(backend);
|
||||
x64_dispatch_emit_thunks(backend);
|
||||
x64_backend_emit_thunks(backend);
|
||||
x64_backend_emit_constants(backend);
|
||||
CHECK_LT(backend->codegen->getSize(), X64_THUNK_SIZE);
|
||||
|
||||
return &backend->base;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#ifndef X64_BACKEND_H
|
||||
#define X64_BACKEND_H
|
||||
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/jit_backend.h"
|
||||
|
||||
struct jit_backend *x64_backend_create(void *code, int code_size);
|
||||
struct jit_guest;
|
||||
|
||||
struct jit_backend *x64_backend_create(struct jit_guest *guest, void *code,
|
||||
int code_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -4,6 +4,7 @@ extern "C" {
|
|||
#include "core/assert.h"
|
||||
#include "core/profiler.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_guest.h"
|
||||
}
|
||||
|
||||
DEFINE_COUNTER(edges_patched);
|
||||
|
@ -79,7 +80,7 @@ void x64_dispatch_run_code(struct jit_backend *base, int cycles) {
|
|||
}
|
||||
|
||||
void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
||||
struct jit *jit = backend->base.jit;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
auto &e = *backend->codegen;
|
||||
|
||||
|
@ -98,7 +99,7 @@ void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
|||
|
||||
/* invasively look into the jit's cache */
|
||||
e.mov(e.rax, (uint64_t)backend->cache);
|
||||
e.mov(e.ecx, e.dword[guestctx + jit->guest->offset_pc]);
|
||||
e.mov(e.ecx, e.dword[guestctx + guest->offset_pc]);
|
||||
e.and_(e.ecx, backend->cache_mask);
|
||||
e.jmp(e.qword[e.rax + e.rcx * (sizeof(void *) >> backend->cache_shift)]);
|
||||
}
|
||||
|
@ -115,11 +116,11 @@ void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
|||
backend->dispatch_static = e.getCurr<void *>();
|
||||
|
||||
#if LINK_STATIC_BRANCHES
|
||||
e.mov(arg0, (uint64_t)jit);
|
||||
e.mov(arg0, (uint64_t)guest->data);
|
||||
e.pop(arg1);
|
||||
e.sub(arg1, 5 /* sizeof jmp instr */);
|
||||
e.mov(arg2, e.qword[guestctx + jit->guest->offset_pc]);
|
||||
e.call(&jit_add_edge);
|
||||
e.mov(arg2, e.qword[guestctx + guest->offset_pc]);
|
||||
e.call(guest->link_code);
|
||||
#else
|
||||
e.pop(arg1);
|
||||
#endif
|
||||
|
@ -133,9 +134,9 @@ void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
|||
|
||||
backend->dispatch_compile = e.getCurr<void *>();
|
||||
|
||||
e.mov(arg0, (uint64_t)jit);
|
||||
e.mov(arg1, e.dword[guestctx + jit->guest->offset_pc]);
|
||||
e.call(&jit_compile_block);
|
||||
e.mov(arg0, (uint64_t)guest->data);
|
||||
e.mov(arg1, e.dword[guestctx + guest->offset_pc]);
|
||||
e.call(guest->compile_code);
|
||||
e.jmp(backend->dispatch_dynamic);
|
||||
}
|
||||
|
||||
|
@ -146,8 +147,8 @@ void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
|||
|
||||
backend->dispatch_interrupt = e.getCurr<void *>();
|
||||
|
||||
e.mov(arg0, (uint64_t)jit->guest->data);
|
||||
e.call(jit->guest->check_interrupts);
|
||||
e.mov(arg0, (uint64_t)guest->data);
|
||||
e.call(guest->check_interrupts);
|
||||
e.jmp(backend->dispatch_dynamic);
|
||||
}
|
||||
|
||||
|
@ -173,12 +174,12 @@ void x64_dispatch_emit_thunks(struct x64_backend *backend) {
|
|||
e.sub(e.rsp, X64_STACK_SIZE + 8);
|
||||
|
||||
/* assign fixed registers */
|
||||
e.mov(guestctx, (uint64_t)jit->guest->ctx);
|
||||
e.mov(guestmem, (uint64_t)jit->guest->mem);
|
||||
e.mov(guestctx, (uint64_t)guest->ctx);
|
||||
e.mov(guestmem, (uint64_t)guest->mem);
|
||||
|
||||
/* reset run state */
|
||||
e.mov(e.dword[guestctx + jit->guest->offset_cycles], arg0);
|
||||
e.mov(e.dword[guestctx + jit->guest->offset_instrs], 0);
|
||||
e.mov(e.dword[guestctx + guest->offset_cycles], arg0);
|
||||
e.mov(e.dword[guestctx + guest->offset_instrs], 0);
|
||||
|
||||
e.jmp(backend->dispatch_dynamic);
|
||||
}
|
||||
|
@ -216,11 +217,11 @@ void x64_dispatch_shutdown(struct x64_backend *backend) {
|
|||
}
|
||||
|
||||
void x64_dispatch_init(struct x64_backend *backend) {
|
||||
struct jit *jit = backend->base.jit;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
/* initialize code cache, one entry per possible block begin */
|
||||
backend->cache_mask = jit->guest->addr_mask;
|
||||
backend->cache_shift = ctz32(jit->guest->addr_mask);
|
||||
backend->cache_mask = guest->addr_mask;
|
||||
backend->cache_shift = ctz32(guest->addr_mask);
|
||||
backend->cache_size = (backend->cache_mask >> backend->cache_shift) + 1;
|
||||
backend->cache = (void **)malloc(backend->cache_size * sizeof(void *));
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
extern "C" {
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_guest.h"
|
||||
}
|
||||
|
||||
#define EMITTER(op, constraints) \
|
||||
|
@ -62,11 +63,13 @@ struct jit_emitter x64_emitters[IR_NUM_OPS];
|
|||
EMITTER(SOURCE_INFO, CONSTRAINTS(NONE, IMM_I32, IMM_I32)) {
|
||||
/*uint32_t addr = ARG0->i32;*/
|
||||
int index = ARG1->i32;
|
||||
block->source_map[index] = e.getCurr<void *>();
|
||||
if (block->source_map) {
|
||||
block->source_map[index] = e.getCurr<void *>();
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(FALLBACK, CONSTRAINTS(NONE, IMM_I64, IMM_I32, IMM_I32)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
void *fallback = (void *)ARG0->i64;
|
||||
uint32_t addr = ARG1->i32;
|
||||
uint32_t raw_instr = ARG2->i32;
|
||||
|
@ -92,7 +95,7 @@ EMITTER(STORE_HOST, CONSTRAINTS(NONE, REG_I64, VAL_ALL)) {
|
|||
}
|
||||
|
||||
EMITTER(LOAD_GUEST, CONSTRAINTS(REG_ALL, REG_I64 | IMM_I32)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
Xbyak::Reg dst = RES_REG;
|
||||
struct ir_value *addr = ARG0;
|
||||
|
||||
|
@ -149,7 +152,7 @@ EMITTER(LOAD_GUEST, CONSTRAINTS(REG_ALL, REG_I64 | IMM_I32)) {
|
|||
}
|
||||
|
||||
EMITTER(STORE_GUEST, CONSTRAINTS(NONE, REG_I64 | IMM_I32, VAL_ALL)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
struct ir_value *addr = ARG0;
|
||||
struct ir_value *data = ARG1;
|
||||
|
||||
|
@ -903,7 +906,7 @@ EMITTER(LSHD, CONSTRAINTS(REG_ARG0, REG_I64, REG_I64)) {
|
|||
}
|
||||
|
||||
EMITTER(BRANCH, CONSTRAINTS(NONE, REG_I64 | IMM_I32)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
if (ir_is_constant(ARG0)) {
|
||||
uint32_t addr = ARG0->i32;
|
||||
|
@ -917,7 +920,7 @@ EMITTER(BRANCH, CONSTRAINTS(NONE, REG_I64 | IMM_I32)) {
|
|||
}
|
||||
|
||||
EMITTER(BRANCH_FALSE, CONSTRAINTS(NONE, REG_I64 | IMM_I32, REG_I64)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
Xbyak::Reg cond = ARG1_REG;
|
||||
Xbyak::Label next;
|
||||
|
@ -938,7 +941,7 @@ EMITTER(BRANCH_FALSE, CONSTRAINTS(NONE, REG_I64 | IMM_I32, REG_I64)) {
|
|||
}
|
||||
|
||||
EMITTER(BRANCH_TRUE, CONSTRAINTS(NONE, REG_I64 | IMM_I32, REG_I64)) {
|
||||
struct jit_guest *guest = backend->base.jit->guest;
|
||||
struct jit_guest *guest = backend->base.guest;
|
||||
|
||||
Xbyak::Reg cond = ARG1_REG;
|
||||
Xbyak::Label next;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <xbyak/xbyak_util.h>
|
||||
|
||||
extern "C" {
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/jit_backend.h"
|
||||
}
|
||||
|
||||
enum xmm_constant {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define ARMV3_DISASM_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
|
||||
enum armv3_op_flag {
|
||||
FLAG_SET_PC = 0x1,
|
||||
|
|
|
@ -781,10 +781,15 @@ FALLBACK(SWP) {
|
|||
/*
|
||||
* software interrupt
|
||||
*/
|
||||
|
||||
FALLBACK(SWI) {
|
||||
CHECK_COND();
|
||||
|
||||
REG(15) = addr + 4;
|
||||
guest->software_interrupt(guest->data);
|
||||
uint32_t oldsr = REG(CPSR);
|
||||
uint32_t newsr = (oldsr & ~M_MASK) | I_MASK | MODE_SVC;
|
||||
|
||||
guest->switch_mode(guest->data, newsr);
|
||||
REG(14) = addr + 4;
|
||||
REG(15) = 0x8;
|
||||
|
||||
LOG_WARNING("SWI");
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "jit/frontend/armv3/armv3_guest.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_guest.h"
|
||||
|
||||
struct armv3_frontend {
|
||||
struct jit_frontend;
|
||||
|
@ -18,7 +19,7 @@ static const struct jit_opdef *armv3_frontend_lookup_op(
|
|||
static void armv3_frontend_dump_code(struct jit_frontend *base,
|
||||
const struct jit_block *block) {
|
||||
struct armv3_frontend *frontend = (struct armv3_frontend *)base;
|
||||
struct jit_guest *guest = frontend->jit->guest;
|
||||
struct jit_guest *guest = frontend->guest;
|
||||
|
||||
char buffer[128];
|
||||
|
||||
|
@ -37,7 +38,7 @@ static void armv3_frontend_translate_code(struct jit_frontend *base,
|
|||
struct jit_block *block,
|
||||
struct ir *ir) {
|
||||
struct armv3_frontend *frontend = (struct armv3_frontend *)base;
|
||||
struct armv3_guest *guest = (struct armv3_guest *)frontend->jit->guest;
|
||||
struct armv3_guest *guest = (struct armv3_guest *)frontend->guest;
|
||||
|
||||
for (int offset = 0; offset < block->guest_size; offset += 4) {
|
||||
uint32_t addr = block->guest_addr + offset;
|
||||
|
@ -52,7 +53,7 @@ static void armv3_frontend_translate_code(struct jit_frontend *base,
|
|||
static void armv3_frontend_analyze_code(struct jit_frontend *base,
|
||||
struct jit_block *block) {
|
||||
struct armv3_frontend *frontend = (struct armv3_frontend *)base;
|
||||
struct armv3_guest *guest = (struct armv3_guest *)frontend->jit->guest;
|
||||
struct armv3_guest *guest = (struct armv3_guest *)frontend->guest;
|
||||
uint32_t addr = block->guest_addr;
|
||||
|
||||
block->guest_size = 0;
|
||||
|
@ -91,12 +92,10 @@ void armv3_frontend_destroy(struct jit_frontend *base) {
|
|||
free(frontend);
|
||||
}
|
||||
|
||||
static void armv3_frontend_init(struct jit_frontend *frontend) {}
|
||||
|
||||
struct jit_frontend *armv3_frontend_create() {
|
||||
struct jit_frontend *armv3_frontend_create(struct jit_guest *guest) {
|
||||
struct armv3_frontend *frontend = calloc(1, sizeof(struct armv3_frontend));
|
||||
|
||||
frontend->init = &armv3_frontend_init;
|
||||
frontend->guest = guest;
|
||||
frontend->destroy = &armv3_frontend_destroy;
|
||||
frontend->analyze_code = &armv3_frontend_analyze_code;
|
||||
frontend->translate_code = &armv3_frontend_translate_code;
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#ifndef ARMV3_FRONTEND_H
|
||||
#define ARMV3_FRONTEND_H
|
||||
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
|
||||
struct jit_guest;
|
||||
|
||||
enum armv3_block_flags {
|
||||
PC_SET = 0x1,
|
||||
};
|
||||
|
||||
struct jit_frontend *armv3_frontend_create();
|
||||
struct jit_frontend *armv3_frontend_create(struct jit_guest *guest);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
#ifndef ARMV3_GUEST_H
|
||||
#define ARMV3_GUEST_H
|
||||
|
||||
#include "jit/jit.h"
|
||||
#include <stdlib.h>
|
||||
#include "jit/jit_guest.h"
|
||||
|
||||
typedef void (*armv3_switch_mode_cb)(void *, uint32_t);
|
||||
typedef void (*armv3_restore_mode_cb)(void *);
|
||||
|
||||
struct armv3_guest {
|
||||
struct jit_guest;
|
||||
|
||||
/* runtime interface */
|
||||
void (*switch_mode)(void *, uint32_t);
|
||||
void (*restore_mode)(void *);
|
||||
void (*software_interrupt)(void *);
|
||||
armv3_switch_mode_cb switch_mode;
|
||||
armv3_restore_mode_cb restore_mode;
|
||||
};
|
||||
|
||||
static inline struct armv3_guest *armv3_guest_create() {
|
||||
return calloc(1, sizeof(struct armv3_guest));
|
||||
}
|
||||
|
||||
static inline void armv3_guest_destroy(struct armv3_guest *guest) {
|
||||
free(guest);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define SH4_DISASM_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
|
||||
enum {
|
||||
SH4_FLAG_INVALID = 0x1,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include "jit/frontend/sh4/sh4_frontend.h"
|
||||
#include "core/profiler.h"
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/frontend/sh4/sh4_disasm.h"
|
||||
#include "jit/frontend/sh4/sh4_fallback.h"
|
||||
#include "jit/frontend/sh4/sh4_guest.h"
|
||||
#include "jit/frontend/sh4/sh4_translate.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
#include "jit/jit_guest.h"
|
||||
|
||||
/*
|
||||
* fsca estimate lookup table, used by the jit and interpreter
|
||||
|
@ -27,7 +28,7 @@ static const struct jit_opdef *sh4_frontend_lookup_op(struct jit_frontend *base,
|
|||
static void sh4_frontend_dump_code(struct jit_frontend *base,
|
||||
const struct jit_block *block) {
|
||||
struct sh4_frontend *frontend = (struct sh4_frontend *)base;
|
||||
struct jit_guest *guest = frontend->jit->guest;
|
||||
struct jit_guest *guest = frontend->guest;
|
||||
|
||||
char buffer[128];
|
||||
|
||||
|
@ -61,7 +62,7 @@ static void sh4_frontend_translate_code(struct jit_frontend *base,
|
|||
struct jit_block *block,
|
||||
struct ir *ir) {
|
||||
struct sh4_frontend *frontend = (struct sh4_frontend *)base;
|
||||
struct sh4_guest *guest = (struct sh4_guest *)frontend->jit->guest;
|
||||
struct sh4_guest *guest = (struct sh4_guest *)frontend->guest;
|
||||
struct sh4_context *ctx = (struct sh4_context *)guest->ctx;
|
||||
|
||||
PROF_ENTER("cpu", "sh4_frontend_translate_code");
|
||||
|
@ -156,7 +157,7 @@ static void sh4_frontend_translate_code(struct jit_frontend *base,
|
|||
static void sh4_frontend_analyze_code(struct jit_frontend *base,
|
||||
struct jit_block *block) {
|
||||
struct sh4_frontend *frontend = (struct sh4_frontend *)base;
|
||||
struct sh4_guest *guest = (struct sh4_guest *)frontend->jit->guest;
|
||||
struct sh4_guest *guest = (struct sh4_guest *)frontend->guest;
|
||||
|
||||
static int IDLE_MASK = SH4_FLAG_LOAD | SH4_FLAG_COND | SH4_FLAG_CMP;
|
||||
int idle_loop = 1;
|
||||
|
@ -294,12 +295,10 @@ static void sh4_frontend_destroy(struct jit_frontend *base) {
|
|||
free(frontend);
|
||||
}
|
||||
|
||||
static void sh4_frontend_init(struct jit_frontend *base) {}
|
||||
|
||||
struct jit_frontend *sh4_frontend_create() {
|
||||
struct jit_frontend *sh4_frontend_create(struct jit_guest *guest) {
|
||||
struct sh4_frontend *frontend = calloc(1, sizeof(struct sh4_frontend));
|
||||
|
||||
frontend->init = &sh4_frontend_init;
|
||||
frontend->guest = guest;
|
||||
frontend->destroy = &sh4_frontend_destroy;
|
||||
frontend->analyze_code = &sh4_frontend_analyze_code;
|
||||
frontend->translate_code = &sh4_frontend_translate_code;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef SH4_FRONTEND_H
|
||||
#define SH4_FRONTEND_H
|
||||
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
|
||||
struct jit_guest;
|
||||
|
||||
enum {
|
||||
SH4_DOUBLE_PR = 0x1,
|
||||
|
@ -10,6 +12,6 @@ enum {
|
|||
|
||||
extern uint32_t sh4_fsca_table[];
|
||||
|
||||
struct jit_frontend *sh4_frontend_create();
|
||||
struct jit_frontend *sh4_frontend_create(struct jit_guest *guest);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#define SH4_GUEST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "jit/jit.h"
|
||||
#include <stdlib.h>
|
||||
#include "jit/jit_guest.h"
|
||||
|
||||
/*
|
||||
* sh4 guest context
|
||||
|
@ -181,12 +182,4 @@ struct sh4_guest {
|
|||
sh4_fpscr_updated_cb fpscr_updated;
|
||||
};
|
||||
|
||||
static inline struct sh4_guest *sh4_guest_create() {
|
||||
return calloc(1, sizeof(struct sh4_guest));
|
||||
}
|
||||
|
||||
static inline void sh4_guest_destroy(struct sh4_guest *guest) {
|
||||
free(guest);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#include "core/filesystem.h"
|
||||
#include "core/option.h"
|
||||
#include "core/profiler.h"
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/frontend/jit_frontend.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit_backend.h"
|
||||
#include "jit/jit_frontend.h"
|
||||
#include "jit/passes/constant_propagation_pass.h"
|
||||
#include "jit/passes/dead_code_elimination_pass.h"
|
||||
#include "jit/passes/expression_simplification_pass.h"
|
||||
|
@ -203,7 +203,7 @@ static struct jit_block *jit_alloc_block(struct jit *jit) {
|
|||
return block;
|
||||
}
|
||||
|
||||
void jit_free_blocks(struct jit *jit) {
|
||||
void jit_free_code(struct jit *jit) {
|
||||
/* invalidate code pointers and remove block entries from lookup maps. this
|
||||
is only safe to use when no code is currently executing */
|
||||
struct rb_node *it = rb_first(&jit->blocks);
|
||||
|
@ -221,7 +221,7 @@ void jit_free_blocks(struct jit *jit) {
|
|||
jit->backend->reset(jit->backend);
|
||||
}
|
||||
|
||||
void jit_invalidate_blocks(struct jit *jit) {
|
||||
void jit_invalidate_code(struct jit *jit) {
|
||||
/* invalidate code pointers, but don't remove block entries from lookup maps.
|
||||
this is used when clearing the jit while code is currently executing */
|
||||
struct rb_node *it = rb_first(&jit->blocks);
|
||||
|
@ -238,7 +238,7 @@ void jit_invalidate_blocks(struct jit *jit) {
|
|||
/* don't reset backend code buffers, code is still running */
|
||||
}
|
||||
|
||||
void jit_add_edge(struct jit *jit, void *branch, uint32_t addr) {
|
||||
void jit_link_code(struct jit *jit, void *branch, uint32_t addr) {
|
||||
struct jit_block *src = jit_lookup_block_reverse(jit, branch);
|
||||
struct jit_block *dst = jit_get_block(jit, addr);
|
||||
|
||||
|
@ -274,7 +274,7 @@ static void jit_dump_block(struct jit *jit, uint32_t guest_addr,
|
|||
fclose(file);
|
||||
}
|
||||
|
||||
void jit_compile_block(struct jit *jit, uint32_t guest_addr) {
|
||||
void jit_compile_code(struct jit *jit, uint32_t guest_addr) {
|
||||
PROF_ENTER("cpu", "jit_compile_block");
|
||||
|
||||
#if 0
|
||||
|
@ -332,7 +332,7 @@ void jit_compile_block(struct jit *jit, uint32_t guest_addr) {
|
|||
#endif
|
||||
|
||||
/* dump unoptimized block */
|
||||
if (jit->dump_blocks) {
|
||||
if (jit->dump_code) {
|
||||
jit_dump_block(jit, guest_addr, &ir);
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,7 @@ void jit_compile_block(struct jit *jit, uint32_t guest_addr) {
|
|||
/* if the backend overflowed, completely free the cache and let dispatch
|
||||
try to compile again */
|
||||
LOG_INFO("backend overflow, resetting code cache");
|
||||
jit_free_blocks(jit);
|
||||
jit_free_code(jit);
|
||||
}
|
||||
|
||||
PROF_LEAVE();
|
||||
|
@ -420,7 +420,7 @@ void jit_destroy(struct jit *jit) {
|
|||
}
|
||||
|
||||
if (jit->backend) {
|
||||
jit_free_blocks(jit);
|
||||
jit_free_code(jit);
|
||||
}
|
||||
|
||||
if (jit->dce) {
|
||||
|
@ -447,23 +447,14 @@ void jit_destroy(struct jit *jit) {
|
|||
}
|
||||
|
||||
struct jit *jit_create(const char *tag, struct jit_frontend *frontend,
|
||||
struct jit_backend *backend, struct jit_guest *guest) {
|
||||
struct jit_backend *backend) {
|
||||
struct jit *jit = calloc(1, sizeof(struct jit));
|
||||
|
||||
strncpy(jit->tag, tag, sizeof(jit->tag));
|
||||
|
||||
jit->frontend = frontend;
|
||||
frontend->jit = jit;
|
||||
|
||||
jit->backend = backend;
|
||||
backend->jit = jit;
|
||||
|
||||
jit->guest = guest;
|
||||
|
||||
/* setup exception handler to deal with self-modifying code and fastmem
|
||||
related exceptions */
|
||||
jit->exc_handler = exception_handler_add(jit, &jit_handle_exception);
|
||||
|
||||
/* create optimization passes */
|
||||
jit->lse = lse_create();
|
||||
jit->cprop = cprop_create();
|
||||
jit->esimp = esimp_create();
|
||||
|
@ -471,6 +462,10 @@ struct jit *jit_create(const char *tag, struct jit_frontend *frontend,
|
|||
jit->ra = ra_create(jit->backend->registers, jit->backend->num_registers,
|
||||
jit->backend->emitters, jit->backend->num_emitters);
|
||||
|
||||
/* setup exception handler to deal with self-modifying code and fastmem
|
||||
related exceptions */
|
||||
jit->exc_handler = exception_handler_add(jit, &jit_handle_exception);
|
||||
|
||||
/* open perf map if enabled */
|
||||
if (OPTION_perf) {
|
||||
#if PLATFORM_DARWIN || PLATFORM_LINUX
|
||||
|
@ -482,8 +477,5 @@ struct jit *jit_create(const char *tag, struct jit_frontend *frontend,
|
|||
#endif
|
||||
}
|
||||
|
||||
jit->frontend->init(jit->frontend);
|
||||
jit->backend->init(jit->backend);
|
||||
|
||||
return jit;
|
||||
}
|
||||
|
|
|
@ -14,10 +14,6 @@ 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);
|
||||
|
||||
enum {
|
||||
JIT_BRANCH_STATIC,
|
||||
JIT_BRANCH_STATIC_TRUE,
|
||||
|
@ -90,41 +86,11 @@ struct jit_edge {
|
|||
struct list_node out_it;
|
||||
};
|
||||
|
||||
struct jit_guest {
|
||||
/* mask used to directly map each guest address to a block of code */
|
||||
uint32_t addr_mask;
|
||||
|
||||
/* runtime interface used by the backend when compiling each block's
|
||||
prologue / epilogue */
|
||||
void *data;
|
||||
int offset_pc;
|
||||
int offset_cycles;
|
||||
int offset_instrs;
|
||||
int offset_interrupts;
|
||||
jit_interrupt_cb check_interrupts;
|
||||
|
||||
/* memory interface */
|
||||
void *ctx;
|
||||
void *mem;
|
||||
struct address_space *space;
|
||||
void (*lookup)(struct address_space *, uint32_t, void **, void **,
|
||||
mem_read_cb *, mem_write_cb *, uint32_t *);
|
||||
uint8_t (*r8)(struct address_space *, uint32_t);
|
||||
uint16_t (*r16)(struct address_space *, uint32_t);
|
||||
uint32_t (*r32)(struct address_space *, uint32_t);
|
||||
uint64_t (*r64)(struct address_space *, uint32_t);
|
||||
void (*w8)(struct address_space *, uint32_t, uint8_t);
|
||||
void (*w16)(struct address_space *, uint32_t, uint16_t);
|
||||
void (*w32)(struct address_space *, uint32_t, uint32_t);
|
||||
void (*w64)(struct address_space *, uint32_t, uint64_t);
|
||||
};
|
||||
|
||||
struct jit {
|
||||
char tag[32];
|
||||
|
||||
struct jit_frontend *frontend;
|
||||
struct jit_backend *backend;
|
||||
struct jit_guest *guest;
|
||||
struct exception_handler *exc_handler;
|
||||
|
||||
/* passes */
|
||||
|
@ -146,19 +112,19 @@ struct jit {
|
|||
FILE *perf_map;
|
||||
|
||||
/* dump ir to application directory as blocks compile */
|
||||
int dump_blocks;
|
||||
int dump_code;
|
||||
};
|
||||
|
||||
struct jit *jit_create(const char *tag, struct jit_frontend *frontend,
|
||||
struct jit_backend *backend, struct jit_guest *guest);
|
||||
struct jit_backend *backend);
|
||||
void jit_destroy(struct jit *jit);
|
||||
|
||||
void jit_run(struct jit *jit, int cycles);
|
||||
|
||||
void jit_compile_block(struct jit *jit, uint32_t guest_addr);
|
||||
void jit_add_edge(struct jit *jit, void *code, uint32_t dst);
|
||||
void jit_compile_code(struct jit *jit, uint32_t guest_addr);
|
||||
void jit_link_code(struct jit *jit, void *code, uint32_t target);
|
||||
|
||||
void jit_invalidate_blocks(struct jit *jit);
|
||||
void jit_free_blocks(struct jit *jit);
|
||||
void jit_invalidate_code(struct jit *jit);
|
||||
void jit_free_code(struct jit *jit);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "jit/ir/ir.h"
|
||||
|
||||
struct exception_state;
|
||||
struct jit;
|
||||
struct jit_block;
|
||||
struct jit_guest;
|
||||
|
||||
/* macro to help declare a code buffer for the backends to use
|
||||
|
||||
|
@ -70,7 +70,7 @@ struct jit_emitter {
|
|||
};
|
||||
|
||||
struct jit_backend {
|
||||
struct jit *jit;
|
||||
struct jit_guest *guest;
|
||||
|
||||
const struct jit_register *registers;
|
||||
int num_registers;
|
||||
|
@ -78,7 +78,6 @@ struct jit_backend {
|
|||
const struct jit_emitter *emitters;
|
||||
int num_emitters;
|
||||
|
||||
void (*init)(struct jit_backend *);
|
||||
void (*destroy)(struct jit_backend *);
|
||||
|
||||
/* compile interface */
|
|
@ -4,7 +4,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
struct ir;
|
||||
struct jit;
|
||||
struct jit_block;
|
||||
struct jit_guest;
|
||||
struct jit_frontend;
|
||||
|
@ -22,9 +21,8 @@ struct jit_opdef {
|
|||
};
|
||||
|
||||
struct jit_frontend {
|
||||
struct jit *jit;
|
||||
struct jit_guest *guest;
|
||||
|
||||
void (*init)(struct jit_frontend *);
|
||||
void (*destroy)(struct jit_frontend *);
|
||||
|
||||
void (*analyze_code)(struct jit_frontend *, struct jit_block *);
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef JIT_GUEST_H
|
||||
#define JIT_GUEST_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint32_t (*mem_read_cb)(void *, uint32_t, uint32_t);
|
||||
typedef void (*mem_write_cb)(void *, uint32_t, uint32_t, uint32_t);
|
||||
|
||||
typedef void (*jit_compile_cb)(void *, uint32_t);
|
||||
typedef void (*jit_link_cb)(void *, uint32_t);
|
||||
typedef void (*jit_interrupt_cb)(void *);
|
||||
|
||||
struct address_space;
|
||||
|
||||
struct jit_guest {
|
||||
/* mask used to directly map each guest address to a block of code */
|
||||
uint32_t addr_mask;
|
||||
|
||||
/* memory interface used by both the frontend and backend */
|
||||
void *ctx;
|
||||
void *mem;
|
||||
struct address_space *space;
|
||||
void (*lookup)(struct address_space *, uint32_t, void **, void **,
|
||||
mem_read_cb *, mem_write_cb *, uint32_t *);
|
||||
uint8_t (*r8)(struct address_space *, uint32_t);
|
||||
uint16_t (*r16)(struct address_space *, uint32_t);
|
||||
uint32_t (*r32)(struct address_space *, uint32_t);
|
||||
uint64_t (*r64)(struct address_space *, uint32_t);
|
||||
void (*w8)(struct address_space *, uint32_t, uint8_t);
|
||||
void (*w16)(struct address_space *, uint32_t, uint16_t);
|
||||
void (*w32)(struct address_space *, uint32_t, uint32_t);
|
||||
void (*w64)(struct address_space *, uint32_t, uint64_t);
|
||||
|
||||
/* runtime interface used by the backend and dispatch */
|
||||
void *data;
|
||||
int offset_pc;
|
||||
int offset_cycles;
|
||||
int offset_instrs;
|
||||
int offset_interrupts;
|
||||
jit_compile_cb compile_code;
|
||||
jit_link_cb link_code;
|
||||
jit_interrupt_cb check_interrupts;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -15,7 +15,7 @@ void pass_stats_unregister(struct pass_stat *stat) {
|
|||
|
||||
void pass_stats_dump() {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("Pass stats");
|
||||
LOG_INFO("pass stats");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
|
||||
int w = 0;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include "jit/passes/register_allocation_pass.h"
|
||||
#include "core/list.h"
|
||||
#include "core/math.h"
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit_backend.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
/* second-chance binpacking register allocator based off of the paper "Quality
|
||||
|
|
|
@ -2,27 +2,24 @@
|
|||
#include "core/log.h"
|
||||
#include "core/option.h"
|
||||
#include "jit/backend/x64/x64_backend.h"
|
||||
#include "jit/frontend/sh4/sh4_disasm.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "jit/jit_guest.h"
|
||||
#include "jit/pass_stats.h"
|
||||
#include "jit/passes/constant_propagation_pass.h"
|
||||
#include "jit/passes/conversion_elimination_pass.h"
|
||||
#include "jit/passes/dead_code_elimination_pass.h"
|
||||
#include "jit/passes/expression_simplification_pass.h"
|
||||
#include "jit/passes/load_store_elimination_pass.h"
|
||||
#include "jit/passes/register_allocation_pass.h"
|
||||
|
||||
DEFINE_OPTION_INT(help, 0, "Show help");
|
||||
DEFINE_OPTION_STRING(pass, "lse,cprop,cve,esimp,dce,ra",
|
||||
DEFINE_OPTION_STRING(pass, "lse,cprop,esimp,dce,ra",
|
||||
"Comma-separated list of passes to run");
|
||||
|
||||
DEFINE_STAT(ir_instrs_total, "total ir instructions");
|
||||
DEFINE_STAT(ir_instrs_removed, "removed ir instructions");
|
||||
|
||||
DEFINE_JIT_CODE_BUFFER(code);
|
||||
static uint8_t ir_buffer[1024 * 1024];
|
||||
static uint8_t code[1024 * 1024];
|
||||
static int code_size = sizeof(code);
|
||||
|
||||
static int get_num_instrs(const struct ir *ir) {
|
||||
int n = 0;
|
||||
|
@ -54,7 +51,7 @@ static void sanitize_ir(struct ir *ir) {
|
|||
}
|
||||
}
|
||||
|
||||
static void process_file(struct jit *jit, const char *filename,
|
||||
static void process_file(struct jit_backend *backend, const char *filename,
|
||||
int disable_dumps) {
|
||||
struct ir ir = {0};
|
||||
ir.buffer = ir_buffer;
|
||||
|
@ -71,7 +68,7 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
sanitize_ir(&ir);
|
||||
|
||||
/* run optimization passes */
|
||||
char passes[MAX_OPTION_LENGTH];
|
||||
char passes[OPTION_MAX_LENGTH];
|
||||
strncpy(passes, OPTION_pass, sizeof(passes));
|
||||
|
||||
int num_instrs_before = get_num_instrs(&ir);
|
||||
|
@ -95,18 +92,18 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
esimp_run(esimp, &ir);
|
||||
esimp_destroy(esimp);
|
||||
} else if (!strcmp(name, "ra")) {
|
||||
struct ra *ra =
|
||||
ra_create(jit->backend->registers, jit->backend->num_registers);
|
||||
struct ra *ra = ra_create(backend->registers, backend->num_registers,
|
||||
backend->emitters, backend->num_emitters);
|
||||
ra_run(ra, &ir);
|
||||
ra_destroy(ra);
|
||||
} else {
|
||||
LOG_WARNING("Unknown pass %s", name);
|
||||
LOG_WARNING("unknown pass %s", name);
|
||||
}
|
||||
|
||||
/* print ir after each pass if requested */
|
||||
if (!disable_dumps) {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("IR after %s", name);
|
||||
LOG_INFO("ir after %s", name);
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
ir_write(&ir, stdout);
|
||||
LOG_INFO("");
|
||||
|
@ -118,17 +115,16 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
int num_instrs_after = get_num_instrs(&ir);
|
||||
|
||||
/* assemble backend code */
|
||||
struct jit_block block;
|
||||
|
||||
jit->backend->reset(jit->backend);
|
||||
int res = jit->backend->assemble_code(jit->backend, &block, &ir);
|
||||
struct jit_block block = {0};
|
||||
backend->reset(backend);
|
||||
int res = backend->assemble_code(backend, &block, &ir);
|
||||
CHECK(res);
|
||||
|
||||
if (!disable_dumps) {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("X64 code");
|
||||
LOG_INFO("x64 code");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
jit->backend->dump_code(jit->backend, block.host_addr, block.host_size);
|
||||
backend->dump_code(backend, &block);
|
||||
LOG_INFO("");
|
||||
}
|
||||
|
||||
|
@ -137,11 +133,11 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
STAT_ir_instrs_removed += num_instrs_before - num_instrs_after;
|
||||
}
|
||||
|
||||
static void process_dir(struct jit *jit, const char *path) {
|
||||
static void process_dir(struct jit_backend *backend, const char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
|
||||
if (!dir) {
|
||||
LOG_WARNING("Failed to open directory %s", path);
|
||||
LOG_WARNING("failed to open directory %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -156,48 +152,35 @@ static void process_dir(struct jit *jit, const char *path) {
|
|||
snprintf(filename, sizeof(filename), "%s" PATH_SEPARATOR "%s", path,
|
||||
ent->d_name);
|
||||
|
||||
LOG_INFO("Processing %s", filename);
|
||||
LOG_INFO("processing %s", filename);
|
||||
|
||||
process_file(jit, filename, 1);
|
||||
process_file(backend, filename, 1);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
options_parse(&argc, &argv);
|
||||
|
||||
if (OPTION_help) {
|
||||
options_print_help();
|
||||
return EXIT_SUCCESS;
|
||||
if (!options_parse(&argc, &argv)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const char *path = argv[1];
|
||||
|
||||
struct jit_guest guest = {0};
|
||||
guest.r8 = (void *)code;
|
||||
guest.r16 = (void *)code;
|
||||
guest.r32 = (void *)code;
|
||||
guest.w8 = (void *)code;
|
||||
guest.w16 = (void *)code;
|
||||
guest.w32 = (void *)code;
|
||||
guest.addr_mask = 0xff;
|
||||
|
||||
struct jit_backend *backend = x64_backend_create(code, code_size);
|
||||
|
||||
/* initailize jit, stubbing out guest interfaces that are used during
|
||||
assembly to a valid address */
|
||||
struct jit *jit = jit_create("recc", NULL, backend, &guest);
|
||||
struct jit_backend *backend = x64_backend_create(&guest, code, sizeof(code));
|
||||
|
||||
if (fs_isfile(path)) {
|
||||
process_file(jit, path, 0);
|
||||
process_file(backend, path, 0);
|
||||
} else {
|
||||
process_dir(jit, path);
|
||||
process_dir(backend, path);
|
||||
}
|
||||
|
||||
LOG_INFO("");
|
||||
pass_stats_dump();
|
||||
|
||||
jit_destroy(jit);
|
||||
backend->destroy(backend);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include <stdlib.h>
|
||||
#include "core/assert.h"
|
||||
#include "core/sort.h"
|
||||
#include "file/trace.h"
|
||||
#include "guest/pvr/tr.h"
|
||||
#include "guest/pvr/trace.h"
|
||||
|
||||
struct depth_entry {
|
||||
/* vertex index */
|
||||
|
|
Loading…
Reference in New Issue