mirror of https://github.com/inolen/redream.git
removed RuntimeContext struct
This commit is contained in:
parent
c4b78cc565
commit
7258b89778
|
@ -63,6 +63,7 @@ set(DREAVM_SOURCES
|
|||
src/cpu/ir/pass_runner.cc
|
||||
src/cpu/ir/validate_block_pass.cc
|
||||
src/cpu/sh4.cc
|
||||
src/cpu/sh4_context.cc
|
||||
src/cpu/runtime.cc
|
||||
src/emu/disc.cc
|
||||
src/emu/emulator.cc
|
||||
|
@ -270,6 +271,7 @@ set(DREAVM_TEST_SOURCES
|
|||
src/cpu/ir/pass_runner.cc
|
||||
src/cpu/ir/validate_block_pass.cc
|
||||
src/cpu/sh4.cc
|
||||
src/cpu/sh4_context.cc
|
||||
src/cpu/runtime.cc
|
||||
src/emu/profiler.cc
|
||||
src/emu/scheduler.cc
|
||||
|
|
|
@ -12,8 +12,8 @@ namespace interpreter {
|
|||
|
||||
class InterpreterContext;
|
||||
|
||||
typedef uint32_t (*InstrFn)(RuntimeContext *runtime, Register *registers,
|
||||
Instr *instr, uint32_t idx);
|
||||
typedef uint32_t (*InstrFn)(emu::Memory *memory, void *guest_ctx,
|
||||
Register *registers, Instr *instr, uint32_t idx);
|
||||
|
||||
union Register {
|
||||
int8_t i8;
|
||||
|
|
|
@ -15,7 +15,7 @@ InterpreterBlock::InterpreterBlock(int guest_cycles, Instr *instrs,
|
|||
|
||||
InterpreterBlock::~InterpreterBlock() { free(instrs_); }
|
||||
|
||||
uint32_t InterpreterBlock::Call(RuntimeContext &runtime_ctx) {
|
||||
uint32_t InterpreterBlock::Call(emu::Memory *memory, void *guest_ctx) {
|
||||
Register *registers =
|
||||
reinterpret_cast<Register *>(alloca(sizeof(Register) * num_registers_));
|
||||
|
||||
|
@ -33,7 +33,7 @@ uint32_t InterpreterBlock::Call(RuntimeContext &runtime_ctx) {
|
|||
// 3. branch is a far, direct branch, absolute i32 address is returned
|
||||
// cases 2 or 3 will always occur as the last instruction of the block,
|
||||
// so the return can be assumed to be an i32 address then
|
||||
i = instr->fn(&runtime_ctx, registers, instr, i);
|
||||
i = instr->fn(memory, guest_ctx, registers, instr, i);
|
||||
}
|
||||
|
||||
return i;
|
||||
|
|
|
@ -19,7 +19,7 @@ class InterpreterBlock : public RuntimeBlock {
|
|||
int num_registers);
|
||||
~InterpreterBlock();
|
||||
|
||||
uint32_t Call(RuntimeContext &runtime_ctx);
|
||||
uint32_t Call(emu::Memory *memory, void *guest_ctx);
|
||||
|
||||
private:
|
||||
Instr *instrs_;
|
||||
|
|
|
@ -177,10 +177,10 @@ struct helper<T, ARG, IMM_MASK,
|
|||
}
|
||||
};
|
||||
|
||||
#define CALLBACK(name) \
|
||||
template <typename R = void, typename A0 = void, typename A1 = void, \
|
||||
int IMM_MASK = 0> \
|
||||
static uint32_t name(RuntimeContext *ctx, Register *r, Instr *i, \
|
||||
#define CALLBACK(name) \
|
||||
template <typename R = void, typename A0 = void, typename A1 = void, \
|
||||
int IMM_MASK = 0> \
|
||||
static uint32_t name(Memory *memory, void *guest_ctx, Register *r, Instr *i, \
|
||||
uint32_t idx)
|
||||
#define LOAD_ARG0() helper<A0, 0, IMM_MASK>::LoadArg(r, i)
|
||||
#define LOAD_ARG1() helper<A1, 1, IMM_MASK>::LoadArg(r, i)
|
||||
|
@ -203,8 +203,7 @@ CALLBACK(PRINTF) {
|
|||
|
||||
CALLBACK(LOAD_CONTEXT) {
|
||||
A0 offset = LOAD_ARG0();
|
||||
R v = *reinterpret_cast<R *>(reinterpret_cast<uint8_t *>(ctx->guest_ctx) +
|
||||
offset);
|
||||
R v = *reinterpret_cast<R *>(reinterpret_cast<uint8_t *>(guest_ctx) + offset);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
@ -212,49 +211,48 @@ CALLBACK(LOAD_CONTEXT) {
|
|||
CALLBACK(STORE_CONTEXT) {
|
||||
A0 offset = LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
*reinterpret_cast<A1 *>(reinterpret_cast<uint8_t *>(ctx->guest_ctx) +
|
||||
offset) = v;
|
||||
*reinterpret_cast<A1 *>(reinterpret_cast<uint8_t *>(guest_ctx) + offset) = v;
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_I8) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->R8(ctx, addr);
|
||||
R v = memory->R8(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_I16) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->R16(ctx, addr);
|
||||
R v = memory->R16(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_I32) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->R32(ctx, addr);
|
||||
R v = memory->R32(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_I64) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->R64(ctx, addr);
|
||||
R v = memory->R64(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_F32) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->RF32(ctx, addr);
|
||||
R v = memory->RF32(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(LOAD_F64) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
R v = ctx->RF64(ctx, addr);
|
||||
R v = memory->RF64(addr);
|
||||
STORE_RESULT(v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
@ -348,42 +346,42 @@ CALLBACK(LOAD_DYN_F64) {
|
|||
CALLBACK(STORE_I8) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->W8(ctx, addr, v);
|
||||
memory->W8(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(STORE_I16) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->W16(ctx, addr, v);
|
||||
memory->W16(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(STORE_I32) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->W32(ctx, addr, v);
|
||||
memory->W32(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(STORE_I64) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->W64(ctx, addr, v);
|
||||
memory->W64(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(STORE_F32) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->WF32(ctx, addr, v);
|
||||
memory->WF32(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
CALLBACK(STORE_F64) {
|
||||
uint32_t addr = (uint32_t)LOAD_ARG0();
|
||||
A1 v = LOAD_ARG1();
|
||||
ctx->WF64(ctx, addr, v);
|
||||
memory->WF64(addr, v);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
|
@ -757,7 +755,7 @@ CALLBACK(BRANCH_INDIRECT) {
|
|||
CALLBACK(CALL_EXTERNAL) {
|
||||
A0 addr = LOAD_ARG0();
|
||||
void (*func)(void *) = (void (*)(void *))(intptr_t)addr;
|
||||
func(ctx->guest_ctx);
|
||||
func(guest_ctx);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,4 +10,6 @@ X64Block::X64Block(int guest_cycles) : RuntimeBlock(guest_cycles) {}
|
|||
|
||||
X64Block::~X64Block() {}
|
||||
|
||||
uint32_t X64Block::Call(RuntimeContext &runtime_ctx) { return 0xdeadbeef; }
|
||||
uint32_t X64Block::Call(emu::Memory *memory, void *guest_ctx) {
|
||||
return 0xdeadbeef;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class X64Block : public RuntimeBlock {
|
|||
X64Block(int guest_cycles);
|
||||
~X64Block();
|
||||
|
||||
uint32_t Call(RuntimeContext &runtime_ctx);
|
||||
uint32_t Call(emu::Memory *memory, void *guest_ctx);
|
||||
|
||||
private:
|
||||
};
|
||||
|
|
|
@ -9,10 +9,6 @@ using namespace dreavm::cpu::frontend::sh4;
|
|||
using namespace dreavm::cpu::ir;
|
||||
using namespace dreavm::emu;
|
||||
|
||||
void SRUpdated(SH4Context *ctx) { ctx->SRUpdated(); }
|
||||
|
||||
void FPSCRUpdated(SH4Context *ctx) { ctx->FPSCRUpdated(); }
|
||||
|
||||
SH4Builder::SH4Builder(Memory &memory)
|
||||
: memory_(memory), has_delay_instr_(false), last_instr_(nullptr) {}
|
||||
|
||||
|
|
|
@ -13,54 +13,6 @@ using namespace dreavm::cpu;
|
|||
using namespace dreavm::cpu::ir;
|
||||
using namespace dreavm::emu;
|
||||
|
||||
static uint8_t R8(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().R8(addr);
|
||||
}
|
||||
|
||||
static uint16_t R16(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().R16(addr);
|
||||
}
|
||||
|
||||
static uint32_t R32(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().R32(addr);
|
||||
}
|
||||
|
||||
static uint64_t R64(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().R64(addr);
|
||||
}
|
||||
|
||||
static float RF32(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().RF32(addr);
|
||||
}
|
||||
|
||||
static double RF64(RuntimeContext *ctx, uint32_t addr) {
|
||||
return ctx->runtime->memory().RF64(addr);
|
||||
}
|
||||
|
||||
static void W8(RuntimeContext *ctx, uint32_t addr, uint8_t value) {
|
||||
ctx->runtime->memory().W8(addr, value);
|
||||
}
|
||||
|
||||
static void W16(RuntimeContext *ctx, uint32_t addr, uint16_t value) {
|
||||
ctx->runtime->memory().W16(addr, value);
|
||||
}
|
||||
|
||||
static void W32(RuntimeContext *ctx, uint32_t addr, uint32_t value) {
|
||||
ctx->runtime->memory().W32(addr, value);
|
||||
}
|
||||
|
||||
static void W64(RuntimeContext *ctx, uint32_t addr, uint64_t value) {
|
||||
ctx->runtime->memory().W64(addr, value);
|
||||
}
|
||||
|
||||
static void WF32(RuntimeContext *ctx, uint32_t addr, float value) {
|
||||
ctx->runtime->memory().WF32(addr, value);
|
||||
}
|
||||
|
||||
static void WF64(RuntimeContext *ctx, uint32_t addr, double value) {
|
||||
ctx->runtime->memory().WF64(addr, value);
|
||||
}
|
||||
|
||||
Runtime::Runtime(Memory &memory)
|
||||
: memory_(memory),
|
||||
frontend_(nullptr),
|
||||
|
@ -68,20 +20,6 @@ Runtime::Runtime(Memory &memory)
|
|||
pending_reset_(false) {
|
||||
blocks_ = new std::unique_ptr<RuntimeBlock>[MAX_BLOCKS];
|
||||
|
||||
runtime_ctx_.runtime = this;
|
||||
runtime_ctx_.R8 = &::R8;
|
||||
runtime_ctx_.R16 = &::R16;
|
||||
runtime_ctx_.R32 = &::R32;
|
||||
runtime_ctx_.R64 = &::R64;
|
||||
runtime_ctx_.RF32 = &::RF32;
|
||||
runtime_ctx_.RF64 = &::RF64;
|
||||
runtime_ctx_.W8 = &::W8;
|
||||
runtime_ctx_.W16 = &::W16;
|
||||
runtime_ctx_.W32 = &::W32;
|
||||
runtime_ctx_.W64 = &::W64;
|
||||
runtime_ctx_.WF32 = &::WF32;
|
||||
runtime_ctx_.WF64 = &::WF64;
|
||||
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new ValidateBlockPass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new ControlFlowAnalysisPass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new ContextPromotionPass()));
|
||||
|
|
|
@ -31,25 +31,6 @@ static inline uint32_t BlockOffset(uint32_t addr) {
|
|||
class Runtime;
|
||||
class RuntimeBlock;
|
||||
|
||||
struct RuntimeContext {
|
||||
RuntimeContext() : runtime(nullptr), guest_ctx(nullptr) {}
|
||||
|
||||
Runtime *runtime;
|
||||
void *guest_ctx;
|
||||
uint8_t (*R8)(RuntimeContext *, uint32_t);
|
||||
uint16_t (*R16)(RuntimeContext *, uint32_t);
|
||||
uint32_t (*R32)(RuntimeContext *, uint32_t);
|
||||
uint64_t (*R64)(RuntimeContext *, uint32_t);
|
||||
float (*RF32)(RuntimeContext *, uint32_t);
|
||||
double (*RF64)(RuntimeContext *, uint32_t);
|
||||
void (*W8)(RuntimeContext *, uint32_t, uint8_t);
|
||||
void (*W16)(RuntimeContext *, uint32_t, uint16_t);
|
||||
void (*W32)(RuntimeContext *, uint32_t, uint32_t);
|
||||
void (*W64)(RuntimeContext *, uint32_t, uint64_t);
|
||||
void (*WF32)(RuntimeContext *, uint32_t, float);
|
||||
void (*WF64)(RuntimeContext *, uint32_t, double);
|
||||
};
|
||||
|
||||
class RuntimeBlock {
|
||||
public:
|
||||
RuntimeBlock(int guest_cycles) : guest_cycles_(guest_cycles) {}
|
||||
|
@ -57,7 +38,7 @@ class RuntimeBlock {
|
|||
|
||||
int guest_cycles() { return guest_cycles_; }
|
||||
|
||||
virtual uint32_t Call(RuntimeContext &runtime_ctx) = 0;
|
||||
virtual uint32_t Call(emu::Memory *memory, void *guest_ctx) = 0;
|
||||
|
||||
private:
|
||||
int guest_cycles_;
|
||||
|
@ -69,7 +50,6 @@ class Runtime {
|
|||
~Runtime();
|
||||
|
||||
emu::Memory &memory() { return memory_; }
|
||||
RuntimeContext &ctx() { return runtime_ctx_; }
|
||||
|
||||
bool Init(frontend::Frontend *frontend, backend::Backend *backend);
|
||||
RuntimeBlock *ResolveBlock(uint32_t addr);
|
||||
|
@ -82,7 +62,6 @@ class Runtime {
|
|||
emu::Memory &memory_;
|
||||
frontend::Frontend *frontend_;
|
||||
backend::Backend *backend_;
|
||||
RuntimeContext runtime_ctx_;
|
||||
ir::PassRunner pass_runner_;
|
||||
// FIXME 64 mb, could cut down to 8 mb if indices were stored instead of
|
||||
// pointers
|
||||
|
|
|
@ -14,63 +14,6 @@ InterruptInfo interrupts[NUM_INTERRUPTS] = {
|
|||
#undef SH4_INT
|
||||
};
|
||||
|
||||
void SH4Context::SetRegisterBank(int bank) {
|
||||
if (bank == 0) {
|
||||
for (int s = 0; s < 8; s++) {
|
||||
rbnk[1][s] = r[s];
|
||||
r[s] = rbnk[0][s];
|
||||
}
|
||||
} else {
|
||||
for (int s = 0; s < 8; s++) {
|
||||
rbnk[0][s] = r[s];
|
||||
r[s] = rbnk[1][s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SH4Context::SwapFPRegisters() {
|
||||
unsigned s;
|
||||
uint32_t z;
|
||||
|
||||
for (s = 0; s <= 15; s++) {
|
||||
z = fr[s];
|
||||
fr[s] = xf[s];
|
||||
xf[s] = z;
|
||||
}
|
||||
}
|
||||
|
||||
void SH4Context::SwapFPCouples() {
|
||||
int s;
|
||||
uint32_t z;
|
||||
|
||||
for (s = 0; s <= 15; s = s + 2) {
|
||||
z = fr[s];
|
||||
fr[s] = fr[s + 1];
|
||||
fr[s + 1] = z;
|
||||
z = xf[s];
|
||||
xf[s] = xf[s + 1];
|
||||
xf[s + 1] = z;
|
||||
}
|
||||
}
|
||||
|
||||
void SH4Context::SRUpdated() {
|
||||
if (sr.RB != old_sr.RB) {
|
||||
SetRegisterBank(sr.RB ? 1 : 0);
|
||||
}
|
||||
old_sr = sr;
|
||||
sh4->UpdatePendingInterrupts();
|
||||
}
|
||||
|
||||
void SH4Context::FPSCRUpdated() {
|
||||
if (fpscr.FR != old_fpscr.FR) {
|
||||
SwapFPRegisters();
|
||||
}
|
||||
if (fpscr.PR != old_fpscr.PR) {
|
||||
SwapFPCouples();
|
||||
}
|
||||
old_fpscr = fpscr;
|
||||
}
|
||||
|
||||
SH4::SH4(emu::Scheduler &scheduler, Memory &memory)
|
||||
: scheduler_(scheduler), memory_(memory) {}
|
||||
|
||||
|
@ -78,9 +21,6 @@ SH4::~SH4() {}
|
|||
|
||||
bool SH4::Init(Runtime *runtime) {
|
||||
runtime_ = runtime;
|
||||
if (runtime_) {
|
||||
runtime_->ctx().guest_ctx = &ctx_;
|
||||
}
|
||||
|
||||
scheduler_.AddDevice(this);
|
||||
|
||||
|
@ -108,7 +48,7 @@ int64_t SH4::Execute(int64_t cycles) {
|
|||
RuntimeBlock *block = runtime_->ResolveBlock(ctx_.pc);
|
||||
CHECK(block);
|
||||
|
||||
uint32_t nextpc = block->Call(runtime_->ctx());
|
||||
uint32_t nextpc = block->Call(&memory_, &ctx_);
|
||||
remaining -= block->guest_cycles();
|
||||
ctx_.pc = nextpc;
|
||||
|
||||
|
@ -316,8 +256,8 @@ void SH4::InitMemory() {
|
|||
void SH4::InitContext() {
|
||||
memset(&ctx_, 0, sizeof(ctx_));
|
||||
ctx_.sh4 = this;
|
||||
// ctx_.pc = 0xa0000000;
|
||||
ctx_.pc = 0x0c010000;
|
||||
ctx_.pc = 0xa0000000;
|
||||
// ctx_.pc = 0x0c010000;
|
||||
ctx_.pr = 0xdeadbeef;
|
||||
#define SH4_REG(addr, name, flags, default, reset, sleep, standby, type) \
|
||||
if (default != HELD) { \
|
||||
|
@ -399,10 +339,7 @@ void SH4::CheckPendingInterrupts() {
|
|||
ctx_.sr.BL = 1;
|
||||
ctx_.sr.MD = 1;
|
||||
ctx_.sr.RB = 1;
|
||||
if (ctx_.old_sr.RB != ctx_.sr.RB) {
|
||||
ctx_.SetRegisterBank(1);
|
||||
}
|
||||
ctx_.old_sr = ctx_.sr;
|
||||
SRUpdated(&ctx_);
|
||||
ctx_.pc = ctx_.vbr + 0x600;
|
||||
if (ctx_.sleep_mode == 1) {
|
||||
ctx_.sleep_mode = 2;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef SH4_H
|
||||
#define SH4_H
|
||||
|
||||
#include "cpu/sh4_context.h"
|
||||
#include "emu/device.h"
|
||||
#include "emu/memory.h"
|
||||
#include "emu/scheduler.h"
|
||||
|
@ -12,8 +13,6 @@ namespace cpu {
|
|||
|
||||
class Runtime;
|
||||
|
||||
enum { MAX_FRAMES = 4096 };
|
||||
|
||||
// registers
|
||||
enum {
|
||||
UNDEFINED = 0x0,
|
||||
|
@ -48,40 +47,6 @@ union CCR_T {
|
|||
uint32_t full;
|
||||
};
|
||||
|
||||
union SR_T {
|
||||
struct {
|
||||
uint32_t T : 1;
|
||||
uint32_t S : 1;
|
||||
uint32_t reserved : 2;
|
||||
uint32_t IMASK : 4;
|
||||
uint32_t Q : 1;
|
||||
uint32_t M : 1;
|
||||
uint32_t reserved1 : 5;
|
||||
uint32_t FD : 1;
|
||||
uint32_t reserved2 : 12;
|
||||
uint32_t BL : 1;
|
||||
uint32_t RB : 1;
|
||||
uint32_t MD : 1;
|
||||
uint32_t reserved3 : 1;
|
||||
};
|
||||
uint32_t full;
|
||||
};
|
||||
|
||||
union FPSCR_T {
|
||||
struct {
|
||||
uint32_t RM : 2;
|
||||
uint32_t flag : 5;
|
||||
uint32_t enable : 5;
|
||||
uint32_t cause : 6;
|
||||
uint32_t DN : 1;
|
||||
uint32_t PR : 1;
|
||||
uint32_t SZ : 1;
|
||||
uint32_t FR : 1;
|
||||
uint32_t reserved : 10;
|
||||
};
|
||||
uint32_t full;
|
||||
};
|
||||
|
||||
union CHCR_T {
|
||||
struct {
|
||||
uint32_t DE : 1;
|
||||
|
@ -140,40 +105,8 @@ enum DDTRW { //
|
|||
DDT_W
|
||||
};
|
||||
|
||||
// SH4 state is split into the SH4Context class for the JIT to easily access
|
||||
class SH4;
|
||||
|
||||
class SH4Context {
|
||||
public:
|
||||
void SetRegisterBank(int bank);
|
||||
void SwapFPRegisters();
|
||||
void SwapFPCouples();
|
||||
|
||||
void SRUpdated();
|
||||
void FPSCRUpdated();
|
||||
|
||||
SH4 *sh4;
|
||||
uint32_t pc, spc;
|
||||
uint32_t pr;
|
||||
uint32_t gbr, vbr;
|
||||
uint32_t mach, macl;
|
||||
uint32_t r[16], rbnk[2][8], sgr;
|
||||
uint32_t fr[16], xf[16];
|
||||
uint32_t fpul;
|
||||
uint32_t dbr;
|
||||
uint32_t m[0x4000];
|
||||
uint32_t sq[2][8];
|
||||
uint8_t sleep_mode;
|
||||
|
||||
uint32_t ea;
|
||||
int64_t icount, nextcheck;
|
||||
|
||||
SR_T sr, ssr, old_sr;
|
||||
FPSCR_T fpscr, old_fpscr;
|
||||
};
|
||||
|
||||
class SH4 : public emu::Device {
|
||||
friend class SH4Context;
|
||||
friend void SRUpdated(SH4Context *ctx);
|
||||
friend void RunSH4Test(const SH4Test &);
|
||||
|
||||
public:
|
||||
|
@ -205,10 +138,10 @@ class SH4 : public emu::Device {
|
|||
void InitMemory();
|
||||
void InitContext();
|
||||
|
||||
SH4Context ctx_;
|
||||
emu::Scheduler &scheduler_;
|
||||
emu::Memory &memory_;
|
||||
Runtime *runtime_;
|
||||
SH4Context ctx_;
|
||||
#define SH4_REG(addr, name, flags, default, reset, sleep, standby, type) \
|
||||
type &name{reinterpret_cast<type &>(ctx_.m[name##_OFFSET])};
|
||||
#include "cpu/sh4_regs.inc"
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include "core/core.h"
|
||||
#include "cpu/sh4.h"
|
||||
#include "cpu/sh4_context.h"
|
||||
|
||||
namespace dreavm {
|
||||
namespace cpu {
|
||||
|
||||
static void SetRegisterBank(SH4Context *ctx, int bank) {
|
||||
if (bank == 0) {
|
||||
for (int s = 0; s < 8; s++) {
|
||||
ctx->rbnk[1][s] = ctx->r[s];
|
||||
ctx->r[s] = ctx->rbnk[0][s];
|
||||
}
|
||||
} else {
|
||||
for (int s = 0; s < 8; s++) {
|
||||
ctx->rbnk[0][s] = ctx->r[s];
|
||||
ctx->r[s] = ctx->rbnk[1][s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SwapFPRegisters(SH4Context *ctx) {
|
||||
unsigned s;
|
||||
uint32_t z;
|
||||
|
||||
for (s = 0; s <= 15; s++) {
|
||||
z = ctx->fr[s];
|
||||
ctx->fr[s] = ctx->xf[s];
|
||||
ctx->xf[s] = z;
|
||||
}
|
||||
}
|
||||
|
||||
static void SwapFPCouples(SH4Context *ctx) {
|
||||
int s;
|
||||
uint32_t z;
|
||||
|
||||
for (s = 0; s <= 15; s = s + 2) {
|
||||
z = ctx->fr[s];
|
||||
ctx->fr[s] = ctx->fr[s + 1];
|
||||
ctx->fr[s + 1] = z;
|
||||
z = ctx->xf[s];
|
||||
ctx->xf[s] = ctx->xf[s + 1];
|
||||
ctx->xf[s + 1] = z;
|
||||
}
|
||||
}
|
||||
|
||||
void SRUpdated(SH4Context *ctx) {
|
||||
if (ctx->sr.RB != ctx->old_sr.RB) {
|
||||
SetRegisterBank(ctx, ctx->sr.RB ? 1 : 0);
|
||||
}
|
||||
ctx->sh4->UpdatePendingInterrupts();
|
||||
ctx->old_sr = ctx->sr;
|
||||
}
|
||||
|
||||
void FPSCRUpdated(SH4Context *ctx) {
|
||||
if (ctx->fpscr.FR != ctx->old_fpscr.FR) {
|
||||
SwapFPRegisters(ctx);
|
||||
}
|
||||
if (ctx->fpscr.PR != ctx->old_fpscr.PR) {
|
||||
SwapFPCouples(ctx);
|
||||
}
|
||||
ctx->old_fpscr = ctx->fpscr;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef SH4_CONTEXT_H
|
||||
#define SH4_CONTEXT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace dreavm {
|
||||
namespace cpu {
|
||||
|
||||
union SR_T {
|
||||
struct {
|
||||
uint32_t T : 1;
|
||||
uint32_t S : 1;
|
||||
uint32_t reserved : 2;
|
||||
uint32_t IMASK : 4;
|
||||
uint32_t Q : 1;
|
||||
uint32_t M : 1;
|
||||
uint32_t reserved1 : 5;
|
||||
uint32_t FD : 1;
|
||||
uint32_t reserved2 : 12;
|
||||
uint32_t BL : 1;
|
||||
uint32_t RB : 1;
|
||||
uint32_t MD : 1;
|
||||
uint32_t reserved3 : 1;
|
||||
};
|
||||
uint32_t full;
|
||||
};
|
||||
|
||||
union FPSCR_T {
|
||||
struct {
|
||||
uint32_t RM : 2;
|
||||
uint32_t flag : 5;
|
||||
uint32_t enable : 5;
|
||||
uint32_t cause : 6;
|
||||
uint32_t DN : 1;
|
||||
uint32_t PR : 1;
|
||||
uint32_t SZ : 1;
|
||||
uint32_t FR : 1;
|
||||
uint32_t reserved : 10;
|
||||
};
|
||||
uint32_t full;
|
||||
};
|
||||
|
||||
class SH4;
|
||||
|
||||
struct SH4Context {
|
||||
SH4 *sh4;
|
||||
uint32_t pc, spc;
|
||||
uint32_t pr;
|
||||
uint32_t gbr, vbr;
|
||||
uint32_t mach, macl;
|
||||
uint32_t r[16], rbnk[2][8], sgr;
|
||||
uint32_t fr[16], xf[16];
|
||||
uint32_t fpul;
|
||||
uint32_t dbr;
|
||||
uint32_t m[0x4000];
|
||||
uint32_t sq[2][8];
|
||||
uint8_t sleep_mode;
|
||||
SR_T sr, ssr, old_sr;
|
||||
FPSCR_T fpscr, old_fpscr;
|
||||
};
|
||||
|
||||
void SRUpdated(SH4Context *ctx);
|
||||
void FPSCRUpdated(SH4Context *ctx);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -20,27 +20,20 @@ using namespace dreavm::system;
|
|||
|
||||
Emulator::Emulator(System &sys)
|
||||
: sys_(sys),
|
||||
scheduler_(new Scheduler()),
|
||||
memory_(new Memory()),
|
||||
rt_frontend_(new SH4Frontend(*memory_)),
|
||||
rt_backend_(new InterpreterBackend(*memory_)),
|
||||
// rt_backend_(new X64Backend(*memory_)),
|
||||
runtime_(new Runtime(*memory_)),
|
||||
processor_(new SH4(*scheduler_, *memory_)),
|
||||
holly_(new Holly(*scheduler_, *memory_, *processor_)) {
|
||||
runtime_(memory_),
|
||||
processor_(scheduler_, memory_),
|
||||
holly_(scheduler_, memory_, processor_) {
|
||||
rt_frontend_ = new SH4Frontend(memory_);
|
||||
rt_backend_ = new InterpreterBackend(memory_);
|
||||
// rt_backend_ = new X64Backend(*memory_);
|
||||
rb_ = new GLBackend(sys);
|
||||
}
|
||||
|
||||
Emulator::~Emulator() {
|
||||
Profiler::Shutdown();
|
||||
delete rb_;
|
||||
delete holly_;
|
||||
delete processor_;
|
||||
delete runtime_;
|
||||
delete rt_backend_;
|
||||
delete rt_frontend_;
|
||||
delete memory_;
|
||||
delete scheduler_;
|
||||
}
|
||||
|
||||
bool Emulator::Init() {
|
||||
|
@ -64,17 +57,17 @@ bool Emulator::Init() {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!runtime_->Init(rt_frontend_, rt_backend_)) {
|
||||
if (!runtime_.Init(rt_frontend_, rt_backend_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// order here is important, sh4 memory handlers need to override
|
||||
// some of the broader holly handlers
|
||||
if (!holly_->Init(rb_)) {
|
||||
if (!holly_.Init(rb_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!processor_->Init(runtime_)) {
|
||||
if (!processor_.Init(&runtime_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,7 +95,7 @@ bool Emulator::LaunchBIN(const char *path) {
|
|||
|
||||
// load to 0x0c010000 (area 3) which is where 1ST_READ.BIN is normally
|
||||
// loaded to
|
||||
memory_->Memcpy(0x0c010000, data, size);
|
||||
memory_.Memcpy(0x0c010000, data, size);
|
||||
free(data);
|
||||
return true;
|
||||
}
|
||||
|
@ -114,7 +107,7 @@ bool Emulator::LaunchGDI(const char *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
holly_->gdrom().SetDisc(std::move(gdi));
|
||||
holly_.gdrom().SetDisc(std::move(gdi));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -122,14 +115,14 @@ bool Emulator::LaunchGDI(const char *path) {
|
|||
void Emulator::Tick() {
|
||||
PumpEvents();
|
||||
|
||||
scheduler_->Tick();
|
||||
scheduler_.Tick();
|
||||
|
||||
RenderFrame();
|
||||
}
|
||||
|
||||
// for memory mapping notes, see 2.1 System Mapping in the hardware manual
|
||||
bool Emulator::MountRam() {
|
||||
memory_->Alloc(0x0, 0x1fffffff, 0xe0000000);
|
||||
memory_.Alloc(0x0, 0x1fffffff, 0xe0000000);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -164,7 +157,7 @@ bool Emulator::LoadBios(const char *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
memory_->Memcpy(BIOS_START, data, size);
|
||||
memory_.Memcpy(BIOS_START, data, size);
|
||||
free(data);
|
||||
return true;
|
||||
}
|
||||
|
@ -200,7 +193,7 @@ bool Emulator::LoadFlash(const char *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
memory_->Memcpy(FLASH_START, data, size);
|
||||
memory_.Memcpy(FLASH_START, data, size);
|
||||
free(data);
|
||||
return true;
|
||||
}
|
||||
|
@ -212,7 +205,7 @@ void Emulator::PumpEvents() {
|
|||
// let the profiler take a stab at the input first
|
||||
if (!Profiler::HandleInput(ev.key.code, ev.key.value)) {
|
||||
// else, forward to holly
|
||||
holly_->HandleInput(0, ev.key.code, ev.key.value);
|
||||
holly_.HandleInput(0, ev.key.code, ev.key.value);
|
||||
}
|
||||
} else if (ev.type == SE_MOUSEMOVE) {
|
||||
Profiler::HandleMouseMove(ev.mousemove.x, ev.mousemove.y);
|
||||
|
@ -231,7 +224,7 @@ void Emulator::RenderFrame() {
|
|||
// render stats
|
||||
char stats[512];
|
||||
snprintf(stats, sizeof(stats), "%.2f%%, %.2f fps, %.2f vbps",
|
||||
scheduler_->perf(), holly_->fps(), holly_->vbps());
|
||||
scheduler_.perf(), holly_.fps(), holly_.vbps());
|
||||
LOG_EVERY_N(INFO, 10) << stats;
|
||||
rb_->RenderText2D(0.0f, 0.0f, 12, 0xffffffff, stats);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "cpu/sh4.h"
|
||||
#include "cpu/backend/backend.h"
|
||||
#include "cpu/frontend/frontend.h"
|
||||
#include "cpu/runtime.h"
|
||||
#include "holly/holly.h"
|
||||
#include "holly/maple_controller.h"
|
||||
#include "renderer/backend.h"
|
||||
|
@ -31,13 +32,13 @@ class Emulator {
|
|||
void RenderFrame();
|
||||
|
||||
system::System &sys_;
|
||||
emu::Scheduler *scheduler_;
|
||||
emu::Memory *memory_;
|
||||
emu::Scheduler scheduler_;
|
||||
emu::Memory memory_;
|
||||
cpu::Runtime runtime_;
|
||||
cpu::SH4 processor_;
|
||||
holly::Holly holly_;
|
||||
cpu::frontend::Frontend *rt_frontend_;
|
||||
cpu::backend::Backend *rt_backend_;
|
||||
cpu::Runtime *runtime_;
|
||||
cpu::SH4 *processor_;
|
||||
holly::Holly *holly_;
|
||||
renderer::Backend *rb_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -45,11 +45,10 @@ int main(int argc, char **argv) {
|
|||
LOG(FATAL) << "Failed to load bin.";
|
||||
}
|
||||
|
||||
// if (!emu.LaunchGDI(
|
||||
// "../dreamcast/Crazy Taxi 2 v1.004 (2001)(Sega)(NTSC)(US)[!]/Crazy "
|
||||
// "Taxi 2 v1.004 (2001)(Sega)(NTSC)(US)[!].gdi")) {
|
||||
// LOG(FATAL) << "Failed to load GDI.";
|
||||
// }
|
||||
if (!emu.LaunchGDI(
|
||||
"../dreamcast/Crazy Taxi 2 v1.004 (2001)(Sega)(NTSC)(US)[!]/Crazy Taxi 2 v1.004 (2001)(Sega)(NTSC)(US)[!].gdi")) {
|
||||
LOG(FATAL) << "Failed to load GDI.";
|
||||
}
|
||||
|
||||
while (1) {
|
||||
sys.Tick();
|
||||
|
|
|
@ -20,7 +20,6 @@ namespace cpu {
|
|||
void RunSH4Test(const SH4Test &test) {
|
||||
Scheduler scheduler;
|
||||
Memory memory;
|
||||
SH4 sh4(scheduler, memory);
|
||||
|
||||
// initialize runtime
|
||||
frontend::sh4::SH4Frontend sh4_frontend(memory);
|
||||
|
@ -29,6 +28,7 @@ void RunSH4Test(const SH4Test &test) {
|
|||
ASSERT_TRUE(runtime.Init(&sh4_frontend, &int_backend));
|
||||
|
||||
// initialize device
|
||||
SH4 sh4(scheduler, memory);
|
||||
ASSERT_TRUE(sh4.Init(&runtime));
|
||||
|
||||
// mount the test binary and a small stack
|
||||
|
|
Loading…
Reference in New Issue