removed ir level branch from pref translation

This commit is contained in:
Anthony Pesch 2015-11-03 23:50:51 -08:00
parent d5001494a0
commit 55170120f0
8 changed files with 72 additions and 76 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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