mirror of https://github.com/inolen/redream.git
removed ir level branch from pref translation
This commit is contained in:
parent
d5001494a0
commit
55170120f0
|
@ -27,8 +27,10 @@ SH4::SH4(Memory &memory, Runtime &runtime)
|
|||
pending_interrupts_(0) {}
|
||||
|
||||
bool SH4::Init() {
|
||||
// initialize context
|
||||
memset(&ctx_, 0, sizeof(ctx_));
|
||||
ctx_.priv = this;
|
||||
ctx_.sh4 = this;
|
||||
ctx_.Pref = &SH4::Pref;
|
||||
ctx_.SRUpdated = &SH4::SRUpdated;
|
||||
ctx_.FPSCRUpdated = &SH4::FPSCRUpdated;
|
||||
ctx_.pc = 0xa0000000;
|
||||
|
@ -36,6 +38,7 @@ bool SH4::Init() {
|
|||
ctx_.sr.full = ctx_.old_sr.full = 0x700000f0;
|
||||
ctx_.fpscr.full = ctx_.old_fpscr.full = 0x00040001;
|
||||
|
||||
// initialize registers
|
||||
memset(area7_, 0, sizeof(area7_));
|
||||
#define SH4_REG(addr, name, flags, default, reset, sleep, standby, type) \
|
||||
if (default != HELD) { \
|
||||
|
@ -44,8 +47,10 @@ bool SH4::Init() {
|
|||
#include "hw/sh4/sh4_regs.inc"
|
||||
#undef SH4_REG
|
||||
|
||||
// clear cache
|
||||
memset(cache_, 0, sizeof(cache_));
|
||||
|
||||
// reset interrupts
|
||||
ReprioritizeInterrupts();
|
||||
|
||||
return true;
|
||||
|
@ -222,15 +227,6 @@ void SH4::WriteRegister(void *ctx, uint32_t addr, T value) {
|
|||
}
|
||||
break;
|
||||
|
||||
// when a PREF instruction is encountered, the high order bits of the
|
||||
// address are filled in from the queue address control register
|
||||
case QACR0_OFFSET:
|
||||
self->ctx_.sq_ext_addr[0] = (value & 0x1c) << 24;
|
||||
break;
|
||||
case QACR1_OFFSET:
|
||||
self->ctx_.sq_ext_addr[1] = (value & 0x1c) << 24;
|
||||
break;
|
||||
|
||||
case IPRA_OFFSET:
|
||||
case IPRB_OFFSET:
|
||||
case IPRC_OFFSET:
|
||||
|
@ -287,12 +283,38 @@ template <typename T>
|
|||
void SH4::WriteSQ(void *ctx, uint32_t addr, T value) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx);
|
||||
uint32_t sqi = (addr & 0x20) >> 5;
|
||||
unsigned idx = (addr & 0x1c) >> 2;
|
||||
uint32_t idx = (addr & 0x1c) >> 2;
|
||||
self->ctx_.sq[sqi][idx] = static_cast<uint32_t>(value);
|
||||
}
|
||||
|
||||
void SH4::Pref(SH4Context *ctx, uint64_t arg0) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx->sh4);
|
||||
uint32_t addr = static_cast<uint32_t>(arg0);
|
||||
|
||||
// only concerned about SQ related prefetches
|
||||
if (addr < 0xe0000000 || addr > 0xe3ffffff) {
|
||||
return;
|
||||
}
|
||||
|
||||
// figure out the source and destination
|
||||
uint32_t dest = addr & 0x03ffffe0;
|
||||
uint32_t sqi = (addr & 0x20) >> 5;
|
||||
if (sqi) {
|
||||
dest |= (self->QACR1 & 0x1c) << 24;
|
||||
} else {
|
||||
dest |= (self->QACR0 & 0x1c) << 24;
|
||||
}
|
||||
|
||||
// perform the "burst" 32-byte copy
|
||||
Memory &memory = self->memory_;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
memory.W32(dest, ctx->sq[sqi][i]);
|
||||
dest += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void SH4::SRUpdated(SH4Context *ctx) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx->priv);
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx->sh4);
|
||||
|
||||
if (ctx->sr.RB != ctx->old_sr.RB) {
|
||||
self->SetRegisterBank(ctx->sr.RB ? 1 : 0);
|
||||
|
@ -306,7 +328,7 @@ void SH4::SRUpdated(SH4Context *ctx) {
|
|||
}
|
||||
|
||||
void SH4::FPSCRUpdated(SH4Context *ctx) {
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx->priv);
|
||||
SH4 *self = reinterpret_cast<SH4 *>(ctx->sh4);
|
||||
|
||||
if (ctx->fpscr.FR != ctx->old_fpscr.FR) {
|
||||
self->SwapFPRegisters();
|
||||
|
|
|
@ -147,6 +147,7 @@ class SH4 : public hw::Device {
|
|||
static void WriteSQ(void *ctx, uint32_t addr, T value);
|
||||
|
||||
private:
|
||||
static void Pref(jit::frontend::sh4::SH4Context *ctx, uint64_t addr);
|
||||
static void SRUpdated(jit::frontend::sh4::SH4Context *ctx);
|
||||
static void FPSCRUpdated(jit::frontend::sh4::SH4Context *ctx);
|
||||
|
||||
|
|
|
@ -894,13 +894,21 @@ REGISTER_INT_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I8);
|
|||
REGISTER_INT_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I16);
|
||||
REGISTER_INT_CALLBACK(BRANCH_COND, BRANCH_COND, V, I8, I32);
|
||||
|
||||
INT_CALLBACK(CALL_EXTERNAL) {
|
||||
INT_CALLBACK(CALL_EXTERNAL1) {
|
||||
A0 addr = LOAD_ARG0();
|
||||
void (*func)(void *) = reinterpret_cast<void (*)(void *)>(addr);
|
||||
func(guest_ctx);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
REGISTER_INT_CALLBACK(CALL_EXTERNAL, CALL_EXTERNAL, V, I64, V);
|
||||
INT_CALLBACK(CALL_EXTERNAL2) {
|
||||
A0 addr = LOAD_ARG0();
|
||||
A1 arg = LOAD_ARG1();
|
||||
void (*func)(void *, uint64_t) = reinterpret_cast<void (*)(void *, uint64_t)>(addr);
|
||||
func(guest_ctx, arg);
|
||||
return NEXT_INSTR;
|
||||
}
|
||||
REGISTER_INT_CALLBACK(CALL_EXTERNAL, CALL_EXTERNAL1, V, I64, V);
|
||||
REGISTER_INT_CALLBACK(CALL_EXTERNAL, CALL_EXTERNAL2, V, I64, I64);
|
||||
|
||||
//
|
||||
// lookup callback for ir instruction
|
||||
|
|
|
@ -1614,8 +1614,16 @@ EMITTER(BRANCH_COND) {
|
|||
}
|
||||
|
||||
EMITTER(CALL_EXTERNAL) {
|
||||
// copy guest context into arg0
|
||||
// copy guest context into the register for arg0
|
||||
e.mov(int_arg0, int_arg1);
|
||||
|
||||
// if an additional argument is specified, copy it into the register for arg1
|
||||
if (instr->arg1()) {
|
||||
const Xbyak::Reg &arg = e.GetRegister(instr->arg1());
|
||||
e.mov(int_arg1, arg);
|
||||
}
|
||||
|
||||
// call the external function
|
||||
e.CopyOperand(instr->arg0(), e.rax);
|
||||
e.call(e.rax);
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ void SH4Builder::StoreSR(Value *v) {
|
|||
StoreAndPreserveContext(offsetof(SH4Context, sr), v, IF_INVALIDATE_CONTEXT);
|
||||
|
||||
Value *sr_updated = LoadContext(offsetof(SH4Context, SRUpdated), VALUE_I64);
|
||||
CallExternal(sr_updated);
|
||||
CallExternal1(sr_updated);
|
||||
}
|
||||
|
||||
ir::Value *SH4Builder::LoadT() { return And(LoadSR(), AllocConstant(T)); }
|
||||
|
@ -171,7 +171,7 @@ void SH4Builder::StoreFPSCR(ir::Value *v) {
|
|||
|
||||
Value *fpscr_updated =
|
||||
LoadContext(offsetof(SH4Context, FPSCRUpdated), VALUE_I64);
|
||||
CallExternal(fpscr_updated);
|
||||
CallExternal1(fpscr_updated);
|
||||
}
|
||||
|
||||
ir::Value *SH4Builder::LoadPR() {
|
||||
|
@ -1482,58 +1482,10 @@ EMITTER(OCBP) {}
|
|||
EMITTER(OCBWB) {}
|
||||
|
||||
// PREF @Rn
|
||||
// FIXME this is painfully bad
|
||||
EMITTER(PREF) {
|
||||
Block *sq_block = b.AppendBlock();
|
||||
Block *sq1_block = b.AppendBlock();
|
||||
Block *sq0_block = b.AppendBlock();
|
||||
Block *end_block = b.AppendBlock();
|
||||
|
||||
{
|
||||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *is_sq_call = b.And(b.UGE(addr, b.AllocConstant(0xe0000000)),
|
||||
b.ULE(addr, b.AllocConstant(0xe3fffffc)));
|
||||
b.BranchCond(is_sq_call, sq_block, end_block);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
b.SetCurrentBlock(sq_block);
|
||||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *sq = b.And(addr, b.AllocConstant(0x20));
|
||||
b.BranchCond(sq, sq1_block, sq0_block);
|
||||
}
|
||||
|
||||
{
|
||||
b.SetCurrentBlock(sq1_block);
|
||||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *sq1_dest =
|
||||
b.Or(b.And(addr, b.AllocConstant(0x03ffffe0)),
|
||||
b.LoadContext(offsetof(SH4Context, sq_ext_addr[1]), VALUE_I32));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
b.Store(sq1_dest,
|
||||
b.LoadContext(offsetof(SH4Context, sq[1]) + i * 4, VALUE_I32));
|
||||
sq1_dest = b.Add(sq1_dest, b.AllocConstant(4));
|
||||
}
|
||||
b.Branch(end_block);
|
||||
}
|
||||
|
||||
{
|
||||
b.SetCurrentBlock(sq0_block);
|
||||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *sq0_dest =
|
||||
b.Or(b.And(addr, b.AllocConstant(0x03ffffe0)),
|
||||
b.LoadContext(offsetof(SH4Context, sq_ext_addr[0]), VALUE_I32));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
b.Store(sq0_dest,
|
||||
b.LoadContext(offsetof(SH4Context, sq[0]) + i * 4, VALUE_I32));
|
||||
sq0_dest = b.Add(sq0_dest, b.AllocConstant(4));
|
||||
}
|
||||
b.Branch(end_block);
|
||||
}
|
||||
}
|
||||
|
||||
b.SetCurrentBlock(end_block);
|
||||
Value *pref = b.LoadContext(offsetof(SH4Context, Pref), VALUE_I64);
|
||||
Value *addr = b.ZExt(b.LoadRegister(i.Rn, VALUE_I32), VALUE_I64);
|
||||
b.CallExternal2(pref, addr);
|
||||
}
|
||||
|
||||
// RTE
|
||||
|
|
|
@ -43,7 +43,8 @@ union FPSCR_T {
|
|||
};
|
||||
|
||||
struct SH4Context {
|
||||
void *priv;
|
||||
void *sh4;
|
||||
void (*Pref)(SH4Context *, uint64_t addr);
|
||||
void (*SRUpdated)(SH4Context *);
|
||||
void (*FPSCRUpdated)(SH4Context *);
|
||||
|
||||
|
@ -56,7 +57,6 @@ struct SH4Context {
|
|||
uint32_t fpul;
|
||||
uint32_t dbr;
|
||||
uint32_t sq[2][8];
|
||||
uint32_t sq_ext_addr[2];
|
||||
uint32_t preserve;
|
||||
uint32_t sr_qm;
|
||||
SR_T sr, ssr, old_sr;
|
||||
|
|
|
@ -756,15 +756,20 @@ void IRBuilder::BranchCond(Value *cond, Block *true_block, Block *false_block) {
|
|||
SetCurrentBlock(false_block);
|
||||
}
|
||||
|
||||
void IRBuilder::CallExternal(Value *addr) {
|
||||
void IRBuilder::CallExternal1(Value *addr) {
|
||||
CHECK_EQ(addr->type(), VALUE_I64);
|
||||
|
||||
Instr *instr = AppendInstr(OP_CALL_EXTERNAL, IF_INVALIDATE_CONTEXT);
|
||||
instr->set_arg0(addr);
|
||||
}
|
||||
|
||||
void IRBuilder::CallExternal(ExternalFn func) {
|
||||
CallExternal(AllocConstant((uint64_t)(intptr_t)func));
|
||||
void IRBuilder::CallExternal2(Value *addr, Value *arg0) {
|
||||
CHECK_EQ(addr->type(), VALUE_I64);
|
||||
CHECK_EQ(arg0->type(), VALUE_I64);
|
||||
|
||||
Instr *instr = AppendInstr(OP_CALL_EXTERNAL, IF_INVALIDATE_CONTEXT);
|
||||
instr->set_arg0(addr);
|
||||
instr->set_arg1(arg0);
|
||||
}
|
||||
|
||||
Value *IRBuilder::AllocConstant(uint8_t c) { return AllocConstant((int8_t)c); }
|
||||
|
|
|
@ -482,8 +482,8 @@ class IRBuilder {
|
|||
void BranchCond(Value *cond, Block *true_block, Block *false_block);
|
||||
|
||||
// calls
|
||||
void CallExternal(ExternalFn func);
|
||||
void CallExternal(Value *addr);
|
||||
void CallExternal1(Value *addr);
|
||||
void CallExternal2(Value *addr, Value *arg0);
|
||||
|
||||
// values
|
||||
Value *AllocConstant(uint8_t c);
|
||||
|
|
Loading…
Reference in New Issue