dynarec: WinCE support WIP
Only for the x64 dynarec atm Bugs remaining
This commit is contained in:
parent
cae22b9fbb
commit
ef43883fb5
|
@ -18,6 +18,7 @@
|
||||||
//#include "../intc.h"
|
//#include "../intc.h"
|
||||||
//#include "../tmu.h"
|
//#include "../tmu.h"
|
||||||
#include "hw/sh4/sh4_mem.h"
|
#include "hw/sh4/sh4_mem.h"
|
||||||
|
#include "hw/sh4/sh4_sched.h"
|
||||||
|
|
||||||
|
|
||||||
#if HOST_OS==OS_LINUX && defined(DYNA_OPROF)
|
#if HOST_OS==OS_LINUX && defined(DYNA_OPROF)
|
||||||
|
@ -86,6 +87,7 @@ u32 bm_gc_luc,bm_gcf_luc;
|
||||||
|
|
||||||
#define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
|
#define FPCA(x) ((DynarecCodeEntryPtr&)sh4rcb.fpcb[(x>>1)&FPCB_MASK])
|
||||||
|
|
||||||
|
// addr must be a physical address
|
||||||
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
|
DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
|
||||||
{
|
{
|
||||||
//rdv_FailedToFindBlock_pc=addr;
|
//rdv_FailedToFindBlock_pc=addr;
|
||||||
|
@ -94,11 +96,51 @@ DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
|
||||||
return (DynarecCodeEntryPtr)rv;
|
return (DynarecCodeEntryPtr)rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addr must be a virtual address
|
||||||
DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr)
|
DynarecCodeEntryPtr DYNACALL bm_GetCode2(u32 addr)
|
||||||
{
|
{
|
||||||
return (DynarecCodeEntryPtr)bm_GetCode(addr);
|
#ifndef NO_MMU
|
||||||
|
if (!mmu_enabled())
|
||||||
|
#endif
|
||||||
|
return (DynarecCodeEntryPtr)bm_GetCode(addr);
|
||||||
|
#ifndef NO_MMU
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (addr & 1)
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0xfffffde7: // GetTickCount
|
||||||
|
// This should make this syscall faster
|
||||||
|
r[0] = sh4_sched_now64() * 1000 / SH4_MAIN_CLOCK;
|
||||||
|
next_pc = pr;
|
||||||
|
addr = next_pc;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Do_Exception(addr, 0xE0, 0x100);
|
||||||
|
addr = next_pc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
u32 paddr;
|
||||||
|
bool shared;
|
||||||
|
mmu_instruction_translation(addr, paddr, shared);
|
||||||
|
|
||||||
|
return (DynarecCodeEntryPtr)bm_GetCode(paddr);
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
Do_Exception(addr, ex.expEvn, ex.callVect);
|
||||||
|
u32 paddr;
|
||||||
|
bool shared;
|
||||||
|
mmu_instruction_translation(next_pc, paddr, shared);
|
||||||
|
return (DynarecCodeEntryPtr)bm_GetCode(paddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addr must be a physical address
|
||||||
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr)
|
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr)
|
||||||
{
|
{
|
||||||
DynarecCodeEntryPtr cde=bm_GetCode(addr);
|
DynarecCodeEntryPtr cde=bm_GetCode(addr);
|
||||||
|
@ -165,6 +207,22 @@ void bm_AddBlock(RuntimeBlockInfo* blk)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bm_RemoveBlock(RuntimeBlockInfo* block)
|
||||||
|
{
|
||||||
|
verify((void*)bm_GetCode(block->addr) != (void*)ngen_FailedToFindBlock);
|
||||||
|
FPCA(block->addr) = ngen_FailedToFindBlock;
|
||||||
|
auto it = blkmap.find(block);
|
||||||
|
if (it != blkmap.end())
|
||||||
|
blkmap.erase(it);
|
||||||
|
for (auto it = all_blocks.begin(); it != all_blocks.end(); it++)
|
||||||
|
if (*it == block)
|
||||||
|
{
|
||||||
|
all_blocks.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete block;
|
||||||
|
}
|
||||||
|
|
||||||
bool UDgreaterX ( RuntimeBlockInfo* elem1, RuntimeBlockInfo* elem2 )
|
bool UDgreaterX ( RuntimeBlockInfo* elem1, RuntimeBlockInfo* elem2 )
|
||||||
{
|
{
|
||||||
return elem1->runs > elem2->runs;
|
return elem1->runs > elem2->runs;
|
||||||
|
@ -594,7 +652,8 @@ void print_blocks()
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
fprintf(f,"block: %p\n",blk);
|
fprintf(f,"block: %p\n",blk);
|
||||||
fprintf(f,"addr: %08X\n",blk->addr);
|
fprintf(f,"vaddr: %08X\n",blk->vaddr);
|
||||||
|
fprintf(f,"paddr: %08X\n",blk->addr);
|
||||||
fprintf(f,"hash: %s\n",blk->hash());
|
fprintf(f,"hash: %s\n",blk->hash());
|
||||||
fprintf(f,"hash_rloc: %s\n",blk->hash(false,true));
|
fprintf(f,"hash_rloc: %s\n",blk->hash(false,true));
|
||||||
fprintf(f,"code: %p\n",blk->code);
|
fprintf(f,"code: %p\n",blk->code);
|
||||||
|
@ -624,17 +683,21 @@ void print_blocks()
|
||||||
if (gcode!=op->guest_offs)
|
if (gcode!=op->guest_offs)
|
||||||
{
|
{
|
||||||
gcode=op->guest_offs;
|
gcode=op->guest_offs;
|
||||||
u32 rpc=blk->addr+gcode;
|
u32 rpc=blk->vaddr+gcode;
|
||||||
u16 op=ReadMem16(rpc);
|
try {
|
||||||
|
u16 op=IReadMem16(rpc);
|
||||||
|
|
||||||
char temp[128];
|
char temp[128];
|
||||||
OpDesc[op]->Disassemble(temp,rpc,op);
|
OpDesc[op]->Disassemble(temp,rpc,op);
|
||||||
|
|
||||||
fprintf(f,"//g:%s\n",temp);
|
fprintf(f,"//g: %04X %s\n", op, temp);
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
fprintf(f,"//g: ???? (page fault)\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string s=op->dissasm();
|
string s=op->dissasm();
|
||||||
fprintf(f,"//il:%d:%d:%s\n",op->guest_offs,op->host_offs,s.c_str());
|
fprintf(f,"//il:%d:%d: %s\n",op->guest_offs,op->host_offs,s.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
fprint_hex(f,"//h:",pucode,hcode,blk->host_code_size);
|
fprint_hex(f,"//h:",pucode,hcode,blk->host_code_size);
|
||||||
|
|
|
@ -20,6 +20,8 @@ struct RuntimeBlockInfo: RuntimeBlockInfo_Core
|
||||||
void Setup(u32 pc,fpscr_t fpu_cfg);
|
void Setup(u32 pc,fpscr_t fpu_cfg);
|
||||||
const char* hash(bool full=true, bool reloc=false);
|
const char* hash(bool full=true, bool reloc=false);
|
||||||
|
|
||||||
|
u32 vaddr;
|
||||||
|
|
||||||
u32 host_code_size; //in bytes
|
u32 host_code_size; //in bytes
|
||||||
u32 sh4_code_size; //in bytes
|
u32 sh4_code_size; //in bytes
|
||||||
|
|
||||||
|
@ -33,7 +35,8 @@ struct RuntimeBlockInfo: RuntimeBlockInfo_Core
|
||||||
u32 guest_cycles;
|
u32 guest_cycles;
|
||||||
u32 guest_opcodes;
|
u32 guest_opcodes;
|
||||||
u32 host_opcodes;
|
u32 host_opcodes;
|
||||||
|
bool has_fpu_op;
|
||||||
|
u32 asid; // if not 0xFFFFFFFF then private page belonging to this id
|
||||||
|
|
||||||
u32 BranchBlock; //if not 0xFFFFFFFF then jump target
|
u32 BranchBlock; //if not 0xFFFFFFFF then jump target
|
||||||
u32 NextBlock; //if not 0xFFFFFFFF then next block (by position)
|
u32 NextBlock; //if not 0xFFFFFFFF then next block (by position)
|
||||||
|
@ -94,6 +97,7 @@ RuntimeBlockInfo* bm_GetStaleBlock(void* dynarec_code);
|
||||||
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr);
|
RuntimeBlockInfo* DYNACALL bm_GetBlock(u32 addr);
|
||||||
|
|
||||||
void bm_AddBlock(RuntimeBlockInfo* blk);
|
void bm_AddBlock(RuntimeBlockInfo* blk);
|
||||||
|
void bm_RemoveBlock(RuntimeBlockInfo* block);
|
||||||
void bm_Reset();
|
void bm_Reset();
|
||||||
void bm_Periodical_1s();
|
void bm_Periodical_1s();
|
||||||
void bm_Periodical_14k();
|
void bm_Periodical_14k();
|
||||||
|
|
|
@ -82,7 +82,8 @@ void Emit(shilop op,shil_param rd=shil_param(),shil_param rs1=shil_param(),shil_
|
||||||
sp.rs1=(rs1);
|
sp.rs1=(rs1);
|
||||||
sp.rs2=(rs2);
|
sp.rs2=(rs2);
|
||||||
sp.rs3=(rs3);
|
sp.rs3=(rs3);
|
||||||
sp.guest_offs=state.cpu.rpc-blk->addr;
|
sp.guest_offs = state.cpu.rpc - blk->vaddr;
|
||||||
|
sp.delay_slot = state.cpu.is_delayslot;
|
||||||
|
|
||||||
blk->oplist.push_back(sp);
|
blk->oplist.push_back(sp);
|
||||||
}
|
}
|
||||||
|
@ -96,22 +97,14 @@ void dec_fallback(u32 op)
|
||||||
|
|
||||||
opcd.rs2=shil_param(FMT_IMM,state.cpu.rpc+2);
|
opcd.rs2=shil_param(FMT_IMM,state.cpu.rpc+2);
|
||||||
opcd.rs3=shil_param(FMT_IMM,op);
|
opcd.rs3=shil_param(FMT_IMM,op);
|
||||||
|
|
||||||
|
opcd.guest_offs = state.cpu.rpc - blk->vaddr;
|
||||||
|
opcd.delay_slot = state.cpu.is_delayslot;
|
||||||
blk->oplist.push_back(opcd);
|
blk->oplist.push_back(opcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
#define FMT_I32 ERROR!WRONG++!!
|
|
||||||
#define FMT_F32 ERROR!WRONG++!!
|
|
||||||
#define FMT_F32 ERROR!WRONG++!!
|
|
||||||
#define FMT_TYPE ERROR!WRONG++!!
|
|
||||||
|
|
||||||
#define FMT_REG ERROR!WRONG++!!
|
|
||||||
#define FMT_IMM ERROR!WRONG++!!
|
|
||||||
|
|
||||||
#define FMT_PARAM ERROR!WRONG++!!
|
|
||||||
#define FMT_MASK ERROR!WRONG++!!
|
|
||||||
|
|
||||||
void dec_DynamicSet(u32 regbase,u32 offs=0)
|
void dec_DynamicSet(u32 regbase,u32 offs=0)
|
||||||
{
|
{
|
||||||
if (offs==0)
|
if (offs==0)
|
||||||
|
@ -277,6 +270,7 @@ sh4dec(i0000_0000_0001_1011)
|
||||||
}
|
}
|
||||||
|
|
||||||
//ldc.l @<REG_N>+,SR
|
//ldc.l @<REG_N>+,SR
|
||||||
|
/*
|
||||||
sh4dec(i0100_nnnn_0000_0111)
|
sh4dec(i0100_nnnn_0000_0111)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -290,9 +284,10 @@ sh4dec(i0100_nnnn_0000_0111)
|
||||||
{
|
{
|
||||||
//FIXME only if interrupts got on .. :P
|
//FIXME only if interrupts got on .. :P
|
||||||
UpdateINTC();
|
UpdateINTC();
|
||||||
}*/
|
}* /
|
||||||
dec_End(0xFFFFFFFF,BET_StaticIntr,false);
|
dec_End(0xFFFFFFFF,BET_StaticIntr,false);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//ldc <REG_N>,SR
|
//ldc <REG_N>,SR
|
||||||
sh4dec(i0100_nnnn_0000_1110)
|
sh4dec(i0100_nnnn_0000_1110)
|
||||||
|
@ -309,6 +304,7 @@ sh4dec(i0000_0000_0000_1001)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fschg
|
||||||
sh4dec(i1111_0011_1111_1101)
|
sh4dec(i1111_0011_1111_1101)
|
||||||
{
|
{
|
||||||
//fpscr.SZ is bit 20
|
//fpscr.SZ is bit 20
|
||||||
|
@ -594,7 +590,7 @@ u32 MatchDiv32(u32 pc , Sh4RegType ®1,Sh4RegType ®2 , Sh4RegType ®3)
|
||||||
u32 match=1;
|
u32 match=1;
|
||||||
for (int i=0;i<32;i++)
|
for (int i=0;i<32;i++)
|
||||||
{
|
{
|
||||||
u16 opcode=ReadMem16(v_pc);
|
u16 opcode=IReadMem16(v_pc);
|
||||||
v_pc+=2;
|
v_pc+=2;
|
||||||
if ((opcode&MASK_N)==ROTCL_KEY)
|
if ((opcode&MASK_N)==ROTCL_KEY)
|
||||||
{
|
{
|
||||||
|
@ -610,7 +606,7 @@ u32 MatchDiv32(u32 pc , Sh4RegType ®1,Sh4RegType ®2 , Sh4RegType ®3)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
opcode=ReadMem16(v_pc);
|
opcode=IReadMem16(v_pc);
|
||||||
v_pc+=2;
|
v_pc+=2;
|
||||||
if ((opcode&MASK_N_M)==DIV1_KEY)
|
if ((opcode&MASK_N_M)==DIV1_KEY)
|
||||||
{
|
{
|
||||||
|
@ -684,11 +680,11 @@ bool MatchDiv32s(u32 op,u32 pc)
|
||||||
else //no match ...
|
else //no match ...
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
printf("%04X\n",ReadMem16(pc-2));
|
printf("%04X\n",IReadMem16(pc-2));
|
||||||
printf("%04X\n",ReadMem16(pc-0));
|
printf("%04X\n",IReadMem16(pc-0));
|
||||||
printf("%04X\n",ReadMem16(pc+2));
|
printf("%04X\n",IReadMem16(pc+2));
|
||||||
printf("%04X\n",ReadMem16(pc+4));
|
printf("%04X\n",IReadMem16(pc+4));
|
||||||
printf("%04X\n",ReadMem16(pc+6));*/
|
printf("%04X\n",IReadMem16(pc+6));*/
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,11 +693,11 @@ bool MatchDiv32s(u32 op,u32 pc)
|
||||||
//This ended up too rare (and too hard to match)
|
//This ended up too rare (and too hard to match)
|
||||||
bool MatchDiv0S_0(u32 pc)
|
bool MatchDiv0S_0(u32 pc)
|
||||||
{
|
{
|
||||||
if (ReadMem16(pc+0)==0x233A && //XOR r3,r3
|
if (IReadMem16(pc+0)==0x233A && //XOR r3,r3
|
||||||
ReadMem16(pc+2)==0x2137 && //DIV0S r3,r1
|
IReadMem16(pc+2)==0x2137 && //DIV0S r3,r1
|
||||||
ReadMem16(pc+4)==0x322A && //SUBC r2,r2
|
IReadMem16(pc+4)==0x322A && //SUBC r2,r2
|
||||||
ReadMem16(pc+6)==0x313A && //SUBC r3,r1
|
IReadMem16(pc+6)==0x313A && //SUBC r3,r1
|
||||||
(ReadMem16(pc+8)&0xF00F)==0x2007) //DIV0S x,x
|
(IReadMem16(pc+8)&0xF00F)==0x2007) //DIV0S x,x
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
@ -829,7 +825,7 @@ bool dec_generic(u32 op)
|
||||||
bool update_after=false;
|
bool update_after=false;
|
||||||
if ((s32)e<0)
|
if ((s32)e<0)
|
||||||
{
|
{
|
||||||
if (rs1._reg!=rs2._reg) //reg shouldn't be updated if its written
|
if (rs1._reg!=rs2._reg && !mmu_enabled()) //reg shouldn't be updated if its written
|
||||||
{
|
{
|
||||||
Emit(shop_sub,rs1,rs1,mk_imm(-e));
|
Emit(shop_sub,rs1,rs1,mk_imm(-e));
|
||||||
}
|
}
|
||||||
|
@ -998,7 +994,7 @@ void state_Setup(u32 rpc,fpscr_t fpu_cfg)
|
||||||
state.cpu.FPR64=fpu_cfg.PR;
|
state.cpu.FPR64=fpu_cfg.PR;
|
||||||
state.cpu.FSZ64=fpu_cfg.SZ;
|
state.cpu.FSZ64=fpu_cfg.SZ;
|
||||||
state.cpu.RoundToZero=fpu_cfg.RM==1;
|
state.cpu.RoundToZero=fpu_cfg.RM==1;
|
||||||
verify(fpu_cfg.RM<2);
|
//verify(fpu_cfg.RM<2); // Happens with many wince games (set to 3)
|
||||||
//what about fp/fs ?
|
//what about fp/fs ?
|
||||||
|
|
||||||
state.NextOp=NDO_NextOp;
|
state.NextOp=NDO_NextOp;
|
||||||
|
@ -1014,7 +1010,7 @@ void state_Setup(u32 rpc,fpscr_t fpu_cfg)
|
||||||
void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
|
void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
|
||||||
{
|
{
|
||||||
blk=rbi;
|
blk=rbi;
|
||||||
state_Setup(blk->addr,blk->fpu_cfg);
|
state_Setup(blk->vaddr, blk->fpu_cfg);
|
||||||
ngen_GetFeatures(&state.ngen);
|
ngen_GetFeatures(&state.ngen);
|
||||||
|
|
||||||
blk->guest_opcodes=0;
|
blk->guest_opcodes=0;
|
||||||
|
@ -1057,7 +1053,7 @@ void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
u32 op=ReadMem16(state.cpu.rpc);
|
u32 op=IReadMem16(state.cpu.rpc);
|
||||||
if (op==0 && state.cpu.is_delayslot)
|
if (op==0 && state.cpu.is_delayslot)
|
||||||
{
|
{
|
||||||
printf("Delayslot 0 hack!\n");
|
printf("Delayslot 0 hack!\n");
|
||||||
|
@ -1069,6 +1065,8 @@ void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
|
||||||
blk->guest_cycles+=0;
|
blk->guest_cycles+=0;
|
||||||
else
|
else
|
||||||
blk->guest_cycles+=CPU_RATIO;
|
blk->guest_cycles+=CPU_RATIO;
|
||||||
|
if (OpDesc[op]->IsFloatingPoint())
|
||||||
|
blk->has_fpu_op = true;
|
||||||
|
|
||||||
verify(!(state.cpu.is_delayslot && OpDesc[op]->SetPC()));
|
verify(!(state.cpu.is_delayslot && OpDesc[op]->SetPC()));
|
||||||
if (state.ngen.OnlyDynamicEnds || !OpDesc[op]->rec_oph)
|
if (state.ngen.OnlyDynamicEnds || !OpDesc[op]->rec_oph)
|
||||||
|
@ -1116,7 +1114,7 @@ void dec_DecodeBlock(RuntimeBlockInfo* rbi,u32 max_cycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
_end:
|
_end:
|
||||||
blk->sh4_code_size=state.cpu.rpc-blk->addr;
|
blk->sh4_code_size=state.cpu.rpc-blk->vaddr;
|
||||||
blk->NextBlock=state.NextAddr;
|
blk->NextBlock=state.NextAddr;
|
||||||
blk->BranchBlock=state.JumpAddr;
|
blk->BranchBlock=state.JumpAddr;
|
||||||
blk->BlockType=state.BlockType;
|
blk->BlockType=state.BlockType;
|
||||||
|
@ -1150,12 +1148,12 @@ _end:
|
||||||
//Small-n-simple idle loop detector :p
|
//Small-n-simple idle loop detector :p
|
||||||
if (state.info.has_readm && !state.info.has_writem && !state.info.has_fpu && blk->guest_opcodes<6)
|
if (state.info.has_readm && !state.info.has_writem && !state.info.has_fpu && blk->guest_opcodes<6)
|
||||||
{
|
{
|
||||||
if (blk->BlockType==BET_Cond_0 || (blk->BlockType==BET_Cond_1 && blk->BranchBlock<=blk->addr))
|
if (blk->BlockType==BET_Cond_0 || (blk->BlockType==BET_Cond_1 && blk->BranchBlock<=blk->vaddr))
|
||||||
{
|
{
|
||||||
blk->guest_cycles*=3;
|
blk->guest_cycles*=3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blk->BranchBlock==blk->addr)
|
if (blk->BranchBlock==blk->vaddr)
|
||||||
{
|
{
|
||||||
blk->guest_cycles*=10;
|
blk->guest_cycles*=10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "hw/sh4/sh4_interrupts.h"
|
#include "hw/sh4/sh4_interrupts.h"
|
||||||
|
|
||||||
#include "hw/sh4/sh4_mem.h"
|
#include "hw/sh4/sh4_mem.h"
|
||||||
|
#include "hw/sh4/modules/mmu.h"
|
||||||
#include "hw/pvr/pvr_mem.h"
|
#include "hw/pvr/pvr_mem.h"
|
||||||
#include "hw/aica/aica_if.h"
|
#include "hw/aica/aica_if.h"
|
||||||
#include "hw/gdrom/gdrom_if.h"
|
#include "hw/gdrom/gdrom_if.h"
|
||||||
|
@ -118,7 +119,7 @@ u32 emit_FreeSpace()
|
||||||
return CODE_SIZE-LastAddr;
|
return CODE_SIZE-LastAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pc must be a physical address
|
||||||
bool DoCheck(u32 pc)
|
bool DoCheck(u32 pc)
|
||||||
{
|
{
|
||||||
if (IsOnRam(pc))
|
if (IsOnRam(pc))
|
||||||
|
@ -202,8 +203,19 @@ void RuntimeBlockInfo::Setup(u32 rpc,fpscr_t rfpu_cfg)
|
||||||
has_jcond=false;
|
has_jcond=false;
|
||||||
BranchBlock=NextBlock=csc_RetCache=0xFFFFFFFF;
|
BranchBlock=NextBlock=csc_RetCache=0xFFFFFFFF;
|
||||||
BlockType=BET_SCL_Intr;
|
BlockType=BET_SCL_Intr;
|
||||||
|
has_fpu_op = false;
|
||||||
|
asid = 0xFFFFFFFF;
|
||||||
|
|
||||||
addr=rpc;
|
vaddr = rpc;
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
bool shared;
|
||||||
|
mmu_instruction_translation(vaddr, addr, shared);
|
||||||
|
if (addr != vaddr && !shared)
|
||||||
|
asid = CCN_PTEH.ASID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
addr = vaddr;
|
||||||
fpu_cfg=rfpu_cfg;
|
fpu_cfg=rfpu_cfg;
|
||||||
|
|
||||||
oplist.clear();
|
oplist.clear();
|
||||||
|
@ -219,37 +231,44 @@ DynarecCodeEntryPtr rdv_CompilePC()
|
||||||
if (emit_FreeSpace()<16*1024 || pc==0x8c0000e0 || pc==0xac010000 || pc==0xac008300)
|
if (emit_FreeSpace()<16*1024 || pc==0x8c0000e0 || pc==0xac010000 || pc==0xac008300)
|
||||||
recSh4_ClearCache();
|
recSh4_ClearCache();
|
||||||
|
|
||||||
RuntimeBlockInfo* rv=0;
|
RuntimeBlockInfo* rbi = ngen_AllocateBlock();
|
||||||
do
|
#ifndef NO_MMU
|
||||||
{
|
try {
|
||||||
RuntimeBlockInfo* rbi = ngen_AllocateBlock();
|
#endif
|
||||||
if (rv==0) rv=rbi;
|
|
||||||
|
|
||||||
rbi->Setup(pc,fpscr);
|
rbi->Setup(pc,fpscr);
|
||||||
|
|
||||||
|
|
||||||
bool do_opts=((rbi->addr&0x3FFFFFFF)>0x0C010100);
|
bool do_opts=((rbi->addr&0x3FFFFFFF)>0x0C010100);
|
||||||
rbi->staging_runs=do_opts?100:-100;
|
rbi->staging_runs=do_opts?100:-100;
|
||||||
ngen_Compile(rbi,DoCheck(rbi->addr),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts);
|
ngen_Compile(rbi,DoCheck(rbi->addr),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts);
|
||||||
verify(rbi->code!=0);
|
verify(rbi->code!=0);
|
||||||
|
|
||||||
bm_AddBlock(rbi);
|
bm_AddBlock(rbi);
|
||||||
|
#ifndef NO_MMU
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
delete rbi;
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (rbi->BlockType==BET_Cond_0 || rbi->BlockType==BET_Cond_1)
|
return rbi->code;
|
||||||
pc=rbi->NextBlock;
|
|
||||||
else
|
|
||||||
pc=0;
|
|
||||||
} while(false && pc);
|
|
||||||
|
|
||||||
return rv->code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
|
DynarecCodeEntryPtr DYNACALL rdv_FailedToFindBlock(u32 pc)
|
||||||
{
|
{
|
||||||
//printf("rdv_FailedToFindBlock ~ %08X\n",pc);
|
//printf("rdv_FailedToFindBlock ~ %08X\n",pc);
|
||||||
next_pc=pc;
|
#ifndef NO_MMU
|
||||||
|
try {
|
||||||
|
#endif
|
||||||
|
next_pc=pc;
|
||||||
|
|
||||||
return rdv_CompilePC();
|
return rdv_CompilePC();
|
||||||
|
#ifndef NO_MMU
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
Do_Exception(pc, ex.expEvn, ex.callVect);
|
||||||
|
return bm_GetCode2(next_pc);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ngen_FailedToFindBlock_internal() {
|
static void ngen_FailedToFindBlock_internal() {
|
||||||
|
@ -258,9 +277,6 @@ static void ngen_FailedToFindBlock_internal() {
|
||||||
|
|
||||||
void (*ngen_FailedToFindBlock)() = &ngen_FailedToFindBlock_internal;
|
void (*ngen_FailedToFindBlock)() = &ngen_FailedToFindBlock_internal;
|
||||||
|
|
||||||
extern u32 rebuild_counter;
|
|
||||||
|
|
||||||
|
|
||||||
u32 DYNACALL rdv_DoInterrupts_pc(u32 pc) {
|
u32 DYNACALL rdv_DoInterrupts_pc(u32 pc) {
|
||||||
next_pc = pc;
|
next_pc = pc;
|
||||||
UpdateINTC();
|
UpdateINTC();
|
||||||
|
@ -268,37 +284,39 @@ u32 DYNACALL rdv_DoInterrupts_pc(u32 pc) {
|
||||||
//We can only safely relocate/etc stuff here, as in other generic update cases
|
//We can only safely relocate/etc stuff here, as in other generic update cases
|
||||||
//There's a RET, meaning the code can't move around
|
//There's a RET, meaning the code can't move around
|
||||||
//Interrupts happen at least 50 times/second, so its not a problem ..
|
//Interrupts happen at least 50 times/second, so its not a problem ..
|
||||||
|
/*
|
||||||
if (rebuild_counter == 0)
|
if (rebuild_counter == 0)
|
||||||
{
|
{
|
||||||
// TODO: Why is this commented, etc.
|
// TODO: Why is this commented, etc.
|
||||||
//bm_Rebuild();
|
//bm_Rebuild();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return next_pc;
|
return next_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bm_Rebuild();
|
|
||||||
u32 DYNACALL rdv_DoInterrupts(void* block_cpde)
|
u32 DYNACALL rdv_DoInterrupts(void* block_cpde)
|
||||||
{
|
{
|
||||||
RuntimeBlockInfo* rbi = bm_GetBlock(block_cpde);
|
RuntimeBlockInfo* rbi = bm_GetBlock(block_cpde);
|
||||||
return rdv_DoInterrupts_pc(rbi->addr);
|
return rdv_DoInterrupts_pc(rbi->vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 pc)
|
// addr must be the physical address of the start of the block
|
||||||
|
DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 addr)
|
||||||
{
|
{
|
||||||
next_pc=pc;
|
RuntimeBlockInfo *block = bm_GetBlock(addr);
|
||||||
recSh4_ClearCache();
|
bm_RemoveBlock(block);
|
||||||
return rdv_CompilePC();
|
return rdv_CompilePC();
|
||||||
}
|
}
|
||||||
|
|
||||||
DynarecCodeEntryPtr rdv_FindCode()
|
//DynarecCodeEntryPtr rdv_FindCode()
|
||||||
{
|
//{
|
||||||
DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
|
// DynarecCodeEntryPtr rv=bm_GetCode(next_pc);
|
||||||
if (rv==ngen_FailedToFindBlock)
|
// if (rv==ngen_FailedToFindBlock)
|
||||||
return 0;
|
// return 0;
|
||||||
|
//
|
||||||
return rv;
|
// return rv;
|
||||||
}
|
//}
|
||||||
|
|
||||||
DynarecCodeEntryPtr rdv_FindOrCompile()
|
DynarecCodeEntryPtr rdv_FindOrCompile()
|
||||||
{
|
{
|
||||||
|
|
|
@ -70,7 +70,7 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 pc);
|
||||||
//Called to compile code @pc
|
//Called to compile code @pc
|
||||||
DynarecCodeEntryPtr rdv_CompilePC();
|
DynarecCodeEntryPtr rdv_CompilePC();
|
||||||
//Returns 0 if there is no code @pc, code ptr otherwise
|
//Returns 0 if there is no code @pc, code ptr otherwise
|
||||||
DynarecCodeEntryPtr rdv_FindCode();
|
//DynarecCodeEntryPtr rdv_FindCode();
|
||||||
//Finds or compiles code @pc
|
//Finds or compiles code @pc
|
||||||
DynarecCodeEntryPtr rdv_FindOrCompile();
|
DynarecCodeEntryPtr rdv_FindOrCompile();
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,8 @@ struct RegAlloc
|
||||||
verify(opid>=0 && opid<block->oplist.size());
|
verify(opid>=0 && opid<block->oplist.size());
|
||||||
shil_opcode* op=&block->oplist[opid];
|
shil_opcode* op=&block->oplist[opid];
|
||||||
|
|
||||||
return op->op == shop_sync_fpscr || op->op == shop_sync_sr || op->op == shop_ifb;
|
return op->op == shop_sync_fpscr || op->op == shop_sync_sr || op->op == shop_ifb
|
||||||
|
|| (mmu_enabled() && (op->op == shop_readm || op->op == shop_writem || op->op == shop_pref));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRegWallOp(RuntimeBlockInfo* block, int opid, bool is_fpr)
|
bool IsRegWallOp(RuntimeBlockInfo* block, int opid, bool is_fpr)
|
||||||
|
@ -496,6 +497,12 @@ struct RegAlloc
|
||||||
{
|
{
|
||||||
fp=true;
|
fp=true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
all = true;
|
||||||
|
fp = true;
|
||||||
|
gpr_b = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (all)
|
if (all)
|
||||||
{
|
{
|
||||||
|
@ -1119,6 +1126,30 @@ struct RegAlloc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BailOut(u32 opid)
|
||||||
|
{
|
||||||
|
for (u32 sid = 0; sid < all_spans.size(); sid++)
|
||||||
|
{
|
||||||
|
RegSpan* spn = all_spans[sid];
|
||||||
|
|
||||||
|
if (spn->end >= opid && spn->start < opid && spn->writeback)
|
||||||
|
{
|
||||||
|
if (spn->fpr)
|
||||||
|
{
|
||||||
|
//printf("Op %d: Writing back f%d from %d\n",current_opid,spn->regstart,spn->nregf);
|
||||||
|
writeback_fpu++;
|
||||||
|
Writeback_FPU(spn->regstart,spn->nregf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//printf("Op %d: Writing back r%d from %d\n",current_opid,spn->regstart,spn->nreg);
|
||||||
|
writeback_gpr++;
|
||||||
|
Writeback(spn->regstart,spn->nreg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Cleanup()
|
void Cleanup()
|
||||||
{
|
{
|
||||||
writeback_gpr=writeback_fpu=0;
|
writeback_gpr=writeback_fpu=0;
|
||||||
|
|
|
@ -151,6 +151,7 @@ struct shil_opcode
|
||||||
|
|
||||||
u16 host_offs;
|
u16 host_offs;
|
||||||
u16 guest_offs;
|
u16 guest_offs;
|
||||||
|
bool delay_slot;
|
||||||
|
|
||||||
string dissasm();
|
string dissasm();
|
||||||
};
|
};
|
||||||
|
|
|
@ -173,11 +173,7 @@ void ExecuteDelayslot()
|
||||||
#if !defined(NO_MMU)
|
#if !defined(NO_MMU)
|
||||||
}
|
}
|
||||||
catch (SH4ThrownException& ex) {
|
catch (SH4ThrownException& ex) {
|
||||||
ex.epc -= 2;
|
AdjustDelaySlotException(ex);
|
||||||
if (ex.expEvn == 0x800) // FPU disable exception
|
|
||||||
ex.expEvn = 0x820; // Slot FPU disable exception
|
|
||||||
else if (ex.expEvn == 0x180) // Illegal instruction exception
|
|
||||||
ex.expEvn = 0x1A0; // Slot illegal instruction exception
|
|
||||||
//printf("Delay slot exception\n");
|
//printf("Delay slot exception\n");
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,11 +50,8 @@ void CCN_MMUCR_write(u32 addr, u32 value)
|
||||||
|
|
||||||
if (temp.TI != 0)
|
if (temp.TI != 0)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 4; i++)
|
//sh4_cpu.ResetCache();
|
||||||
ITLB[i].Data.V = 0;
|
mmu_flush_table();
|
||||||
|
|
||||||
for (u32 i = 0; i < 64; i++)
|
|
||||||
UTLB[i].Data.V = 0;
|
|
||||||
|
|
||||||
temp.TI = 0;
|
temp.TI = 0;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +60,7 @@ void CCN_MMUCR_write(u32 addr, u32 value)
|
||||||
if (mmu_changed_state)
|
if (mmu_changed_state)
|
||||||
{
|
{
|
||||||
//printf("<*******>MMU Enabled , ONLY SQ remaps work<*******>\n");
|
//printf("<*******>MMU Enabled , ONLY SQ remaps work<*******>\n");
|
||||||
|
sh4_cpu.ResetCache();
|
||||||
mmu_set_state();
|
mmu_set_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,7 +201,7 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TLB Multyhit
|
//TLB Multihit
|
||||||
case MMU_ERROR_TLB_MHIT:
|
case MMU_ERROR_TLB_MHIT:
|
||||||
printf("MMU_ERROR_TLB_MHIT @ 0x%X\n", address);
|
printf("MMU_ERROR_TLB_MHIT @ 0x%X\n", address);
|
||||||
break;
|
break;
|
||||||
|
@ -239,19 +239,10 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
||||||
else //IADDERR - Instruction Address Error
|
else //IADDERR - Instruction Address Error
|
||||||
{
|
{
|
||||||
#ifdef TRACE_WINCE_SYSCALLS
|
#ifdef TRACE_WINCE_SYSCALLS
|
||||||
bool skip_exception = false;
|
if (!print_wince_syscall(address))
|
||||||
if (!print_wince_syscall(address, skip_exception))
|
|
||||||
printf_mmu("MMU_ERROR_BADADDR(i) 0x%X\n", address);
|
|
||||||
//if (!skip_exception)
|
|
||||||
RaiseException(0xE0, 0x100);
|
|
||||||
//else {
|
|
||||||
// SH4ThrownException ex = { 0, 0, 0 };
|
|
||||||
// throw ex;
|
|
||||||
//}
|
|
||||||
#else
|
|
||||||
printf_mmu("MMU_ERROR_BADADDR(i) 0x%X\n", address);
|
|
||||||
RaiseException(0xE0, 0x100);
|
|
||||||
#endif
|
#endif
|
||||||
|
printf_mmu("MMU_ERROR_BADADDR(i) 0x%X\n", address);
|
||||||
|
RaiseException(0xE0, 0x100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf_mmu("MMU_ERROR_BADADDR(d) 0x%X, handled\n", address);
|
printf_mmu("MMU_ERROR_BADADDR(d) 0x%X, handled\n", address);
|
||||||
|
@ -291,9 +282,10 @@ bool mmu_match(u32 va, CCN_PTEH_type Address, CCN_PTEL_type Data)
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Do a full lookup on the UTLB entry's
|
//Do a full lookup on the UTLB entry's
|
||||||
template<bool internal>
|
template<bool internal>
|
||||||
u32 mmu_full_lookup(u32 va, u32& idx, u32& rv)
|
u32 mmu_full_lookup(u32 va, const TLB_Entry** tlb_entry_ret, u32& rv)
|
||||||
{
|
{
|
||||||
if (!internal)
|
if (!internal)
|
||||||
{
|
{
|
||||||
|
@ -302,21 +294,21 @@ u32 mmu_full_lookup(u32 va, u32& idx, u32& rv)
|
||||||
CCN_MMUCR.URC = 0;
|
CCN_MMUCR.URC = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 entry = 0;
|
u32 entry = -1;
|
||||||
u32 nom = 0;
|
u32 nom = 0;
|
||||||
|
|
||||||
|
|
||||||
for (u32 i = 0; i<64; i++)
|
for (u32 i = 0; i<64; i++)
|
||||||
{
|
{
|
||||||
//verify(sz!=0);
|
//verify(sz!=0);
|
||||||
if (mmu_match(va, UTLB[i].Address, UTLB[i].Data))
|
TLB_Entry *tlb_entry = &UTLB[i];
|
||||||
|
if (mmu_match(va, tlb_entry->Address, tlb_entry->Data))
|
||||||
{
|
{
|
||||||
entry = i;
|
entry = i;
|
||||||
nom++;
|
nom++;
|
||||||
u32 sz = UTLB[i].Data.SZ1 * 2 + UTLB[i].Data.SZ0;
|
u32 sz = tlb_entry->Data.SZ1 * 2 + tlb_entry->Data.SZ0;
|
||||||
u32 mask = mmu_mask[sz];
|
u32 mask = mmu_mask[sz];
|
||||||
//VPN->PPN | low bits
|
//VPN->PPN | low bits
|
||||||
rv = ((UTLB[i].Data.PPN << 10)&mask) | (va&(~mask));
|
rv = ((tlb_entry->Data.PPN << 10) & mask) | (va & (~mask));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +324,7 @@ u32 mmu_full_lookup(u32 va, u32& idx, u32& rv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
idx = entry;
|
*tlb_entry_ret = &UTLB[entry];
|
||||||
|
|
||||||
return MMU_ERROR_NONE;
|
return MMU_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
@ -364,15 +356,15 @@ u32 mmu_full_SQ(u32 va, u32& rv)
|
||||||
{
|
{
|
||||||
//Address=Dest&0xFFFFFFE0;
|
//Address=Dest&0xFFFFFFE0;
|
||||||
|
|
||||||
u32 entry;
|
const TLB_Entry *entry;
|
||||||
u32 lookup = mmu_full_lookup(va, entry, rv);
|
u32 lookup = mmu_full_lookup(va, &entry, rv);
|
||||||
|
|
||||||
rv &= ~31;//lower 5 bits are forced to 0
|
rv &= ~31;//lower 5 bits are forced to 0
|
||||||
|
|
||||||
if (lookup != MMU_ERROR_NONE)
|
if (lookup != MMU_ERROR_NONE)
|
||||||
return lookup;
|
return lookup;
|
||||||
|
|
||||||
u32 md = UTLB[entry].Data.PR >> 1;
|
u32 md = entry->Data.PR >> 1;
|
||||||
|
|
||||||
//Priv mode protection
|
//Priv mode protection
|
||||||
if ((md == 0) && sr.MD == 0)
|
if ((md == 0) && sr.MD == 0)
|
||||||
|
@ -383,9 +375,9 @@ u32 mmu_full_SQ(u32 va, u32& rv)
|
||||||
//Write Protection (Lock or FW)
|
//Write Protection (Lock or FW)
|
||||||
if (translation_type == MMU_TT_DWRITE)
|
if (translation_type == MMU_TT_DWRITE)
|
||||||
{
|
{
|
||||||
if ((UTLB[entry].Data.PR & 1) == 0)
|
if ((entry->Data.PR & 1) == 0)
|
||||||
return MMU_ERROR_PROTECTED;
|
return MMU_ERROR_PROTECTED;
|
||||||
else if (UTLB[entry].Data.D == 0)
|
else if (entry->Data.D == 0)
|
||||||
return MMU_ERROR_FIRSTWRITE;
|
return MMU_ERROR_FIRSTWRITE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,48 +387,50 @@ u32 mmu_full_SQ(u32 va, u32& rv)
|
||||||
}
|
}
|
||||||
return MMU_ERROR_NONE;
|
return MMU_ERROR_NONE;
|
||||||
}
|
}
|
||||||
template<u32 translation_type>
|
template<u32 translation_type, typename T>
|
||||||
u32 mmu_data_translation(u32 va, u32& rv)
|
void mmu_data_translation(u32 va, u32& rv)
|
||||||
{
|
{
|
||||||
//*opt notice* this could be only checked for writes, as reads are invalid
|
if (va & (sizeof(T) - 1))
|
||||||
if ((va & 0xFC000000) == 0xE0000000)
|
mmu_raise_exception(MMU_ERROR_BADADDR, va, translation_type);
|
||||||
|
|
||||||
|
if (translation_type == MMU_TT_DWRITE)
|
||||||
{
|
{
|
||||||
u32 lookup = mmu_full_SQ<translation_type>(va, rv);
|
if ((va & 0xFC000000) == 0xE0000000)
|
||||||
if (lookup != MMU_ERROR_NONE)
|
{
|
||||||
return lookup;
|
u32 lookup = mmu_full_SQ<translation_type>(va, rv);
|
||||||
rv = va; //SQ writes are not translated, only write backs are.
|
if (lookup != MMU_ERROR_NONE)
|
||||||
return MMU_ERROR_NONE;
|
mmu_raise_exception(lookup, va, translation_type);
|
||||||
|
|
||||||
|
rv = va; //SQ writes are not translated, only write backs are.
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sr.MD == 0) && (va & 0x80000000) != 0)
|
if ((sr.MD == 0) && (va & 0x80000000) != 0)
|
||||||
{
|
{
|
||||||
//if on kernel, and not SQ addr -> error
|
//if on kernel, and not SQ addr -> error
|
||||||
return MMU_ERROR_BADADDR;
|
mmu_raise_exception(MMU_ERROR_BADADDR, va, translation_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sr.MD == 1 && ((va & 0xFC000000) == 0x7C000000))
|
if (sr.MD == 1 && ((va & 0xFC000000) == 0x7C000000))
|
||||||
{
|
{
|
||||||
rv = va;
|
rv = va;
|
||||||
return MMU_ERROR_NONE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((CCN_MMUCR.AT == 0) || (fast_reg_lut[va >> 29] != 0))
|
// Not called if CCN_MMUCR.AT == 0
|
||||||
|
//if ((CCN_MMUCR.AT == 0) || (fast_reg_lut[va >> 29] != 0))
|
||||||
|
if (fast_reg_lut[va >> 29] != 0)
|
||||||
{
|
{
|
||||||
rv = va;
|
rv = va;
|
||||||
return MMU_ERROR_NONE;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if ( CCN_CCR.ORA && ((va&0xFC000000)==0x7C000000))
|
const TLB_Entry *entry;
|
||||||
{
|
u32 lookup = mmu_full_lookup(va, &entry, rv);
|
||||||
verify(false);
|
|
||||||
return va;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
u32 entry;
|
|
||||||
u32 lookup = mmu_full_lookup(va, entry, rv);
|
|
||||||
|
|
||||||
if (lookup != MMU_ERROR_NONE)
|
if (lookup != MMU_ERROR_NONE)
|
||||||
return lookup;
|
mmu_raise_exception(lookup, va, translation_type);
|
||||||
|
|
||||||
#ifdef TRACE_WINCE_SYSCALLS
|
#ifdef TRACE_WINCE_SYSCALLS
|
||||||
if (unresolved_unicode_string != 0)
|
if (unresolved_unicode_string != 0)
|
||||||
|
@ -449,13 +443,13 @@ u32 mmu_data_translation(u32 va, u32& rv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u32 md = UTLB[entry].Data.PR >> 1;
|
u32 md = entry->Data.PR >> 1;
|
||||||
|
|
||||||
//0X & User mode-> protection violation
|
//0X & User mode-> protection violation
|
||||||
//Priv mode protection
|
//Priv mode protection
|
||||||
if ((md == 0) && sr.MD == 0)
|
if ((md == 0) && sr.MD == 0)
|
||||||
{
|
{
|
||||||
return MMU_ERROR_PROTECTED;
|
mmu_raise_exception(MMU_ERROR_PROTECTED, va, translation_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
//X0 -> read olny
|
//X0 -> read olny
|
||||||
|
@ -464,27 +458,33 @@ u32 mmu_data_translation(u32 va, u32& rv)
|
||||||
//Write Protection (Lock or FW)
|
//Write Protection (Lock or FW)
|
||||||
if (translation_type == MMU_TT_DWRITE)
|
if (translation_type == MMU_TT_DWRITE)
|
||||||
{
|
{
|
||||||
if ((UTLB[entry].Data.PR & 1) == 0)
|
if ((entry->Data.PR & 1) == 0)
|
||||||
return MMU_ERROR_PROTECTED;
|
mmu_raise_exception(MMU_ERROR_PROTECTED, va, translation_type);
|
||||||
else if (UTLB[entry].Data.D == 0)
|
else if (entry->Data.D == 0)
|
||||||
return MMU_ERROR_FIRSTWRITE;
|
mmu_raise_exception(MMU_ERROR_FIRSTWRITE, va, translation_type);
|
||||||
}
|
}
|
||||||
return MMU_ERROR_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 mmu_instruction_translation(u32 va, u32& rv)
|
template void mmu_data_translation<MMU_TT_DREAD, u16>(u32 va, u32& rv);
|
||||||
|
template void mmu_data_translation<MMU_TT_DREAD, u32>(u32 va, u32& rv);
|
||||||
|
|
||||||
|
void mmu_instruction_translation(u32 va, u32& rv, bool& shared)
|
||||||
{
|
{
|
||||||
|
if (va & 1)
|
||||||
|
{
|
||||||
|
mmu_raise_exception(MMU_ERROR_BADADDR, va, MMU_TT_IREAD);
|
||||||
|
}
|
||||||
if ((sr.MD == 0) && (va & 0x80000000) != 0)
|
if ((sr.MD == 0) && (va & 0x80000000) != 0)
|
||||||
{
|
{
|
||||||
//if SQ disabled , or if if SQ on but out of SQ mem then BAD ADDR ;)
|
//if SQ disabled , or if if SQ on but out of SQ mem then BAD ADDR ;)
|
||||||
if (va >= 0xE0000000)
|
if (va >= 0xE0000000)
|
||||||
return MMU_ERROR_BADADDR;
|
mmu_raise_exception(MMU_ERROR_BADADDR, va, MMU_TT_IREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((CCN_MMUCR.AT == 0) || (fast_reg_lut[va >> 29] != 0))
|
if ((CCN_MMUCR.AT == 0) || (fast_reg_lut[va >> 29] != 0))
|
||||||
{
|
{
|
||||||
rv = va;
|
rv = va;
|
||||||
return MMU_ERROR_NONE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mmach = false;
|
bool mmach = false;
|
||||||
|
@ -509,6 +509,7 @@ retry_ITLB_Match:
|
||||||
nom++;
|
nom++;
|
||||||
//VPN->PPN | low bits
|
//VPN->PPN | low bits
|
||||||
rv = ((ITLB[i].Data.PPN << 10)&mask) | (va&(~mask));
|
rv = ((ITLB[i].Data.PPN << 10)&mask) | (va&(~mask));
|
||||||
|
shared = ITLB[i].Data.SH == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -516,13 +517,15 @@ retry_ITLB_Match:
|
||||||
if (entry == 4)
|
if (entry == 4)
|
||||||
{
|
{
|
||||||
verify(mmach == false);
|
verify(mmach == false);
|
||||||
u32 lookup = mmu_full_lookup(va, entry, rv);
|
const TLB_Entry *tlb_entry;
|
||||||
|
u32 lookup = mmu_full_lookup(va, &tlb_entry, rv);
|
||||||
|
|
||||||
if (lookup != MMU_ERROR_NONE)
|
if (lookup != MMU_ERROR_NONE)
|
||||||
return lookup;
|
mmu_raise_exception(lookup, va, MMU_TT_IREAD);
|
||||||
|
|
||||||
u32 replace_index = ITLB_LRU_USE[CCN_MMUCR.LRUI];
|
u32 replace_index = ITLB_LRU_USE[CCN_MMUCR.LRUI];
|
||||||
verify(replace_index != 0xFFFFFFFF);
|
verify(replace_index != 0xFFFFFFFF);
|
||||||
ITLB[replace_index] = UTLB[entry];
|
ITLB[replace_index] = *tlb_entry;
|
||||||
entry = replace_index;
|
entry = replace_index;
|
||||||
ITLB_Sync(entry);
|
ITLB_Sync(entry);
|
||||||
mmach = true;
|
mmach = true;
|
||||||
|
@ -532,11 +535,11 @@ retry_ITLB_Match:
|
||||||
{
|
{
|
||||||
if (nom)
|
if (nom)
|
||||||
{
|
{
|
||||||
return MMU_ERROR_TLB_MHIT;
|
mmu_raise_exception(MMU_ERROR_TLB_MHIT, va, MMU_TT_IREAD);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return MMU_ERROR_TLB_MISS;
|
mmu_raise_exception(MMU_ERROR_TLB_MISS, va, MMU_TT_IREAD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,10 +552,8 @@ retry_ITLB_Match:
|
||||||
//Priv mode protection
|
//Priv mode protection
|
||||||
if ((md == 0) && sr.MD == 0)
|
if ((md == 0) && sr.MD == 0)
|
||||||
{
|
{
|
||||||
return MMU_ERROR_PROTECTED;
|
mmu_raise_exception(MMU_ERROR_PROTECTED, va, MMU_TT_IREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MMU_ERROR_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmu_set_state()
|
void mmu_set_state()
|
||||||
|
@ -570,6 +571,7 @@ void mmu_set_state()
|
||||||
WriteMem16 = &mmu_WriteMem16;
|
WriteMem16 = &mmu_WriteMem16;
|
||||||
WriteMem32 = &mmu_WriteMem32;
|
WriteMem32 = &mmu_WriteMem32;
|
||||||
WriteMem64 = &mmu_WriteMem64;
|
WriteMem64 = &mmu_WriteMem64;
|
||||||
|
mmu_flush_table();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -617,149 +619,77 @@ void MMU_term()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mmu_flush_table()
|
||||||
|
{
|
||||||
|
//printf("MMU tables flushed\n");
|
||||||
|
|
||||||
|
ITLB[0].Data.V = 0;
|
||||||
|
ITLB[1].Data.V = 0;
|
||||||
|
ITLB[2].Data.V = 0;
|
||||||
|
ITLB[3].Data.V = 0;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 64; i++)
|
||||||
|
UTLB[i].Data.V = 0;
|
||||||
|
}
|
||||||
|
|
||||||
u8 DYNACALL mmu_ReadMem8(u32 adr)
|
u8 DYNACALL mmu_ReadMem8(u32 adr)
|
||||||
{
|
{
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DREAD>(adr, addr);
|
mmu_data_translation<MMU_TT_DREAD, u8>(adr, addr);
|
||||||
if (tv == 0)
|
return _vmem_ReadMem8(addr);
|
||||||
return _vmem_ReadMem8(addr);
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 DYNACALL mmu_ReadMem16(u32 adr)
|
u16 DYNACALL mmu_ReadMem16(u32 adr)
|
||||||
{
|
{
|
||||||
if (adr & 1)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DREAD>(adr, addr);
|
mmu_data_translation<MMU_TT_DREAD, u16>(adr, addr);
|
||||||
if (tv == 0)
|
return _vmem_ReadMem16(addr);
|
||||||
return _vmem_ReadMem16(addr);
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
u16 DYNACALL mmu_IReadMem16(u32 adr)
|
u16 DYNACALL mmu_IReadMem16(u32 vaddr)
|
||||||
{
|
{
|
||||||
if (adr & 1)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_IREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_instruction_translation(adr, addr);
|
bool shared;
|
||||||
if (tv == 0)
|
mmu_instruction_translation(vaddr, addr, shared);
|
||||||
return _vmem_ReadMem16(addr);
|
return _vmem_ReadMem16(addr);
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_IREAD);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 DYNACALL mmu_ReadMem32(u32 adr)
|
u32 DYNACALL mmu_ReadMem32(u32 adr)
|
||||||
{
|
{
|
||||||
if (adr & 3)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DREAD>(adr, addr);
|
mmu_data_translation<MMU_TT_DREAD, u32>(adr, addr);
|
||||||
if (tv == 0)
|
return _vmem_ReadMem32(addr);
|
||||||
return _vmem_ReadMem32(addr);
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
u64 DYNACALL mmu_ReadMem64(u32 adr)
|
u64 DYNACALL mmu_ReadMem64(u32 adr)
|
||||||
{
|
{
|
||||||
if (adr & 7)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DREAD>(adr, addr);
|
mmu_data_translation<MMU_TT_DREAD, u64>(adr, addr);
|
||||||
if (tv == 0)
|
return _vmem_ReadMem64(addr);
|
||||||
{
|
|
||||||
return _vmem_ReadMem64(addr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DYNACALL mmu_WriteMem8(u32 adr, u8 data)
|
void DYNACALL mmu_WriteMem8(u32 adr, u8 data)
|
||||||
{
|
{
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DWRITE>(adr, addr);
|
mmu_data_translation<MMU_TT_DWRITE, u8>(adr, addr);
|
||||||
if (tv == 0)
|
_vmem_WriteMem8(addr, data);
|
||||||
{
|
|
||||||
_vmem_WriteMem8(addr, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DYNACALL mmu_WriteMem16(u32 adr, u16 data)
|
void DYNACALL mmu_WriteMem16(u32 adr, u16 data)
|
||||||
{
|
{
|
||||||
if (adr & 1)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DWRITE>(adr, addr);
|
mmu_data_translation<MMU_TT_DWRITE, u16>(adr, addr);
|
||||||
if (tv == 0)
|
_vmem_WriteMem16(addr, data);
|
||||||
{
|
|
||||||
_vmem_WriteMem16(addr, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
|
|
||||||
}
|
}
|
||||||
void DYNACALL mmu_WriteMem32(u32 adr, u32 data)
|
void DYNACALL mmu_WriteMem32(u32 adr, u32 data)
|
||||||
{
|
{
|
||||||
if (adr & 3)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DWRITE>(adr, addr);
|
mmu_data_translation<MMU_TT_DWRITE, u32>(adr, addr);
|
||||||
if (tv == 0)
|
_vmem_WriteMem32(addr, data);
|
||||||
{
|
|
||||||
_vmem_WriteMem32(addr, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
|
|
||||||
}
|
}
|
||||||
void DYNACALL mmu_WriteMem64(u32 adr, u64 data)
|
void DYNACALL mmu_WriteMem64(u32 adr, u64 data)
|
||||||
{
|
{
|
||||||
if (adr & 7)
|
|
||||||
{
|
|
||||||
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 tv = mmu_data_translation<MMU_TT_DWRITE>(adr, addr);
|
mmu_data_translation<MMU_TT_DWRITE, u64>(adr, addr);
|
||||||
if (tv == 0)
|
_vmem_WriteMem64(addr, data);
|
||||||
{
|
|
||||||
_vmem_WriteMem64(addr, data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mmu_TranslateSQW(u32 adr, u32* out)
|
bool mmu_TranslateSQW(u32 adr, u32* out)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define MMU_ERROR_NONE 0
|
#define MMU_ERROR_NONE 0
|
||||||
//TLB miss
|
//TLB miss
|
||||||
#define MMU_ERROR_TLB_MISS 1
|
#define MMU_ERROR_TLB_MISS 1
|
||||||
//TLB Multyhit
|
//TLB Multihit
|
||||||
#define MMU_ERROR_TLB_MHIT 2
|
#define MMU_ERROR_TLB_MHIT 2
|
||||||
//Mem is read/write protected (depends on translation type)
|
//Mem is read/write protected (depends on translation type)
|
||||||
#define MMU_ERROR_PROTECTED 3
|
#define MMU_ERROR_PROTECTED 3
|
||||||
|
@ -21,15 +21,6 @@
|
||||||
//Can't Execute
|
//Can't Execute
|
||||||
#define MMU_ERROR_EXECPROT 6
|
#define MMU_ERROR_EXECPROT 6
|
||||||
|
|
||||||
//Translation Types
|
|
||||||
//Opcode read
|
|
||||||
#define MMU_TT_IREAD 0
|
|
||||||
//Data write
|
|
||||||
#define MMU_TT_DWRITE 1
|
|
||||||
//Data write
|
|
||||||
#define MMU_TT_DREAD 2
|
|
||||||
//Do an mmu lookup for va , returns translation status , if MMU_ERROR_NONE , rv is set to translated index
|
|
||||||
|
|
||||||
extern u32 mmu_error_TT;
|
extern u32 mmu_error_TT;
|
||||||
|
|
||||||
void MMU_Init();
|
void MMU_Init();
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
#define SH_CURTHREAD 1
|
#define SH_CURTHREAD 1
|
||||||
#define SH_CURPROC 2
|
#define SH_CURPROC 2
|
||||||
|
|
||||||
|
extern const u32 mmu_mask[4];
|
||||||
|
|
||||||
static bool read_mem32(u32 addr, u32& data)
|
static bool read_mem32(u32 addr, u32& data)
|
||||||
{
|
{
|
||||||
u32 pa;
|
u32 pa;
|
||||||
u32 idx;
|
const TLB_Entry *entry;
|
||||||
if (mmu_full_lookup<true>(addr, idx, pa) != MMU_ERROR_NONE)
|
if (mmu_full_lookup<true>(addr, &entry, pa) != MMU_ERROR_NONE)
|
||||||
return false;
|
return false;
|
||||||
data = ReadMem32_nommu(pa);
|
data = ReadMem32_nommu(pa);
|
||||||
return true;
|
return true;
|
||||||
|
@ -20,8 +22,8 @@ static bool read_mem32(u32 addr, u32& data)
|
||||||
static bool read_mem16(u32 addr, u16& data)
|
static bool read_mem16(u32 addr, u16& data)
|
||||||
{
|
{
|
||||||
u32 pa;
|
u32 pa;
|
||||||
u32 idx;
|
const TLB_Entry *entry;
|
||||||
if (mmu_full_lookup<true>(addr, idx, pa) != MMU_ERROR_NONE)
|
if (mmu_full_lookup<true>(addr, &entry, pa) != MMU_ERROR_NONE)
|
||||||
return false;
|
return false;
|
||||||
data = ReadMem16_nommu(pa);
|
data = ReadMem16_nommu(pa);
|
||||||
return true;
|
return true;
|
||||||
|
@ -30,8 +32,8 @@ static bool read_mem16(u32 addr, u16& data)
|
||||||
static bool read_mem8(u32 addr, u8& data)
|
static bool read_mem8(u32 addr, u8& data)
|
||||||
{
|
{
|
||||||
u32 pa;
|
u32 pa;
|
||||||
u32 idx;
|
const TLB_Entry *entry;
|
||||||
if (mmu_full_lookup<true>(addr, idx, pa) != MMU_ERROR_NONE)
|
if (mmu_full_lookup<true>(addr, &entry, pa) != MMU_ERROR_NONE)
|
||||||
return false;
|
return false;
|
||||||
data = ReadMem8_nommu(pa);
|
data = ReadMem8_nommu(pa);
|
||||||
return true;
|
return true;
|
||||||
|
@ -246,9 +248,8 @@ std::string get_ascii_string(u32 addr)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool print_wince_syscall(u32 address, bool &skip_exception)
|
static bool print_wince_syscall(u32 address)
|
||||||
{
|
{
|
||||||
skip_exception = false;
|
|
||||||
if (address & 1)
|
if (address & 1)
|
||||||
{
|
{
|
||||||
if (address == 0xfffffd5d || address == 0xfffffd05) // Sleep, QueryPerformanceCounter
|
if (address == 0xfffffd5d || address == 0xfffffd05) // Sleep, QueryPerformanceCounter
|
||||||
|
@ -329,3 +330,59 @@ static bool print_wince_syscall(u32 address, bool &skip_exception)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool wince_resolve_address(u32 va, TLB_Entry &entry)
|
||||||
|
{
|
||||||
|
// WinCE hack
|
||||||
|
if ((va & 0x80000000) == 0)
|
||||||
|
{
|
||||||
|
u32 page_group = ReadMem32_nommu(CCN_TTB + ((va >> 25) << 2));
|
||||||
|
u32 page = ((va >> 16) & 0x1ff) << 2;
|
||||||
|
u32 paddr = ReadMem32_nommu(page_group + page);
|
||||||
|
if (paddr & 0x80000000)
|
||||||
|
{
|
||||||
|
u32 whatever = ReadMem32_nommu(r_bank[4] + 0x14);
|
||||||
|
if (whatever != ReadMem32_nommu(paddr))
|
||||||
|
{
|
||||||
|
paddr += 12;
|
||||||
|
u32 ptel = ReadMem32_nommu(paddr + ((va >> 10) & 0x3c));
|
||||||
|
//FIXME CCN_PTEA = paddr >> 29;
|
||||||
|
if (ptel != 0)
|
||||||
|
{
|
||||||
|
entry.Data.reg_data = ptel - 1;
|
||||||
|
entry.Address.ASID = CCN_PTEH.ASID;
|
||||||
|
entry.Assistance.reg_data = 0;
|
||||||
|
u32 sz = entry.Data.SZ1 * 2 + entry.Data.SZ0;
|
||||||
|
entry.Address.VPN = (va & mmu_mask[sz]) >> 10;
|
||||||
|
|
||||||
|
true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// SQ
|
||||||
|
if (((va >> 26) & 0x3F) == 0x38)
|
||||||
|
{
|
||||||
|
u32 r1 = (va - 0xe0000000) & 0xfff00000;
|
||||||
|
//r1 &= 0xfff00000;
|
||||||
|
//u32 r0 = ReadMem32_nommu(0x8C01258C); // FIXME
|
||||||
|
//u32 r0 = 0x8c138b14;
|
||||||
|
//r0 = ReadMem32_nommu(r0); // 0xE0001F5
|
||||||
|
u32 r0 = 0xe0001f5;
|
||||||
|
r0 += r1;
|
||||||
|
entry.Data.reg_data = r0 - 1;
|
||||||
|
entry.Assistance.reg_data = r0 >> 29;
|
||||||
|
entry.Address.ASID = CCN_PTEH.ASID;
|
||||||
|
u32 sz = entry.Data.SZ1 * 2 + entry.Data.SZ0;
|
||||||
|
entry.Address.VPN = (va & mmu_mask[sz]) >> 10;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,15 @@ static INLINE void RaiseFPUDisableException()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INLINE void AdjustDelaySlotException(SH4ThrownException& ex)
|
||||||
|
{
|
||||||
|
ex.epc -= 2;
|
||||||
|
if (ex.expEvn == 0x800) // FPU disable exception
|
||||||
|
ex.expEvn = 0x820; // Slot FPU disable exception
|
||||||
|
else if (ex.expEvn == 0x180) // Illegal instruction exception
|
||||||
|
ex.expEvn = 0x1A0; // Slot illegal instruction exception
|
||||||
|
}
|
||||||
|
|
||||||
// The SH4 sets the signaling bit to 0 for qNaN (unlike all recent CPUs). Some games relies on this.
|
// The SH4 sets the signaling bit to 0 for qNaN (unlike all recent CPUs). Some games relies on this.
|
||||||
static INLINE f32 fixNaN(f32 f)
|
static INLINE f32 fixNaN(f32 f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "hw/sh4/sh4_opcode_list.h"
|
#include "hw/sh4/sh4_opcode_list.h"
|
||||||
#include "hw/sh4/dyna/ngen.h"
|
#include "hw/sh4/dyna/ngen.h"
|
||||||
#include "hw/sh4/modules/ccn.h"
|
#include "hw/sh4/modules/ccn.h"
|
||||||
|
#include "hw/sh4/modules/mmu.h"
|
||||||
#include "hw/sh4/sh4_interrupts.h"
|
#include "hw/sh4/sh4_interrupts.h"
|
||||||
|
|
||||||
#include "hw/sh4/sh4_core.h"
|
#include "hw/sh4/sh4_core.h"
|
||||||
|
@ -206,6 +207,99 @@ static void ngen_blockcheckfail(u32 pc) {
|
||||||
rdv_BlockCheckFail(pc);
|
rdv_BlockCheckFail(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 exception_raised;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static T ReadMemNoEx(u32 addr, u32 pc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
exception_raised = 0;
|
||||||
|
if (sizeof(T) == 1)
|
||||||
|
return ReadMem8(addr);
|
||||||
|
else if (sizeof(T) == 2)
|
||||||
|
return ReadMem16(addr);
|
||||||
|
else if (sizeof(T) == 4)
|
||||||
|
return ReadMem32(addr);
|
||||||
|
else if (sizeof(T) == 8)
|
||||||
|
return ReadMem64(addr);
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
if (pc & 1)
|
||||||
|
{
|
||||||
|
// Delay slot
|
||||||
|
AdjustDelaySlotException(ex);
|
||||||
|
pc--;
|
||||||
|
}
|
||||||
|
Do_Exception(pc, ex.expEvn, ex.callVect);
|
||||||
|
exception_raised = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void WriteMemNoEx(u32 addr, T data, u32 pc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (sizeof(T) == 1)
|
||||||
|
WriteMem8(addr, data);
|
||||||
|
else if (sizeof(T) == 2)
|
||||||
|
WriteMem16(addr, data);
|
||||||
|
else if (sizeof(T) == 4)
|
||||||
|
WriteMem32(addr, data);
|
||||||
|
else if (sizeof(T) == 8)
|
||||||
|
WriteMem64(addr, data);
|
||||||
|
exception_raised = 0;
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
if (pc & 1)
|
||||||
|
{
|
||||||
|
// Delay slot
|
||||||
|
AdjustDelaySlotException(ex);
|
||||||
|
pc--;
|
||||||
|
}
|
||||||
|
Do_Exception(pc, ex.expEvn, ex.callVect);
|
||||||
|
exception_raised = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void interpreter_fallback(u16 op, u32 pc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
OpDesc[op]->oph(op);
|
||||||
|
exception_raised = 0;
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
printf("HOLY SHIT! interpreter_fallback exception pc %08x evn %x vect %x\n", pc, ex.expEvn, ex.callVect);
|
||||||
|
if (pc & 1)
|
||||||
|
{
|
||||||
|
// Delay slot
|
||||||
|
AdjustDelaySlotException(ex);
|
||||||
|
pc--;
|
||||||
|
}
|
||||||
|
Do_Exception(pc, ex.expEvn, ex.callVect);
|
||||||
|
exception_raised = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_sqw_mmu_no_ex(u32 addr, u32 pc)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
do_sqw_mmu(addr);
|
||||||
|
exception_raised = 0;
|
||||||
|
} catch (SH4ThrownException& ex) {
|
||||||
|
if (pc & 1)
|
||||||
|
{
|
||||||
|
// Delay slot
|
||||||
|
AdjustDelaySlotException(ex);
|
||||||
|
pc--;
|
||||||
|
}
|
||||||
|
Do_Exception(pc, ex.expEvn, ex.callVect);
|
||||||
|
exception_raised = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_sqw_nommu_local(u32 addr, u8* sqb)
|
||||||
|
{
|
||||||
|
do_sqw_nommu(addr, sqb);
|
||||||
|
}
|
||||||
|
|
||||||
class BlockCompiler : public Xbyak::CodeGenerator
|
class BlockCompiler : public Xbyak::CodeGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -258,25 +352,55 @@ public:
|
||||||
#else
|
#else
|
||||||
sub(rsp, 0x8); // align stack
|
sub(rsp, 0x8); // align stack
|
||||||
#endif
|
#endif
|
||||||
|
Xbyak::Label exit_block;
|
||||||
|
|
||||||
for (size_t i = 0; i < block->oplist.size(); i++)
|
if (mmu_enabled() && block->has_fpu_op)
|
||||||
{
|
{
|
||||||
shil_opcode& op = block->oplist[i];
|
Xbyak::Label fpu_enabled;
|
||||||
|
mov(rax, (uintptr_t)&sr);
|
||||||
|
mov(eax, dword[rax]);
|
||||||
|
and_(eax, 0x8000); // test SR.FD bit
|
||||||
|
jz(fpu_enabled);
|
||||||
|
mov(call_regs[0], block->vaddr); // pc
|
||||||
|
mov(call_regs[1], 0x800); // event
|
||||||
|
mov(call_regs[2], 0x100); // vector
|
||||||
|
GenCall(Do_Exception);
|
||||||
|
jmp(exit_block, T_NEAR);
|
||||||
|
L(fpu_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
regalloc.OpBegin(&op, i);
|
for (current_opid = 0; current_opid < block->oplist.size(); current_opid++)
|
||||||
|
{
|
||||||
|
shil_opcode& op = block->oplist[current_opid];
|
||||||
|
|
||||||
|
regalloc.OpBegin(&op, current_opid);
|
||||||
|
|
||||||
switch (op.op) {
|
switch (op.op) {
|
||||||
|
|
||||||
case shop_ifb:
|
case shop_ifb:
|
||||||
if (op.rs1._imm)
|
|
||||||
{
|
{
|
||||||
mov(rax, (size_t)&next_pc);
|
if (op.rs1._imm)
|
||||||
mov(dword[rax], op.rs2._imm);
|
{
|
||||||
|
mov(rax, (size_t)&next_pc);
|
||||||
|
mov(dword[rax], op.rs2._imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
mov(call_regs[0], op.rs3._imm);
|
||||||
|
|
||||||
|
if (!mmu_enabled())
|
||||||
|
{
|
||||||
|
GenCall(OpDesc[op.rs3._imm]->oph);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(call_regs[1], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
|
||||||
|
|
||||||
|
GenCall(interpreter_fallback);
|
||||||
|
|
||||||
|
test(dword[(void *)&exception_raised], 1);
|
||||||
|
jnz(exit_block, T_NEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mov(call_regs[0], op.rs3._imm);
|
|
||||||
|
|
||||||
GenCall(OpDesc[op.rs3._imm]->oph);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case shop_jcond:
|
case shop_jcond:
|
||||||
|
@ -325,11 +449,28 @@ public:
|
||||||
case shop_readm:
|
case shop_readm:
|
||||||
{
|
{
|
||||||
u32 size = op.flags & 0x7f;
|
u32 size = op.flags & 0x7f;
|
||||||
|
bool immediate_address = op.rs1.is_imm();
|
||||||
if (op.rs1.is_imm())
|
if (immediate_address && mmu_enabled() && (op.rs1._imm >> 12) != (block->vaddr >> 12))
|
||||||
{
|
{
|
||||||
|
// When full mmu is on, only consider addresses in the same 4k page
|
||||||
|
immediate_address = false;
|
||||||
|
}
|
||||||
|
if (immediate_address)
|
||||||
|
{
|
||||||
|
u32 addr = op.rs1._imm;
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
u32 paddr;
|
||||||
|
if (size == 2)
|
||||||
|
mmu_data_translation<MMU_TT_DREAD, u16>(addr, paddr);
|
||||||
|
else if (size == 4)
|
||||||
|
mmu_data_translation<MMU_TT_DREAD, u32>(addr, paddr);
|
||||||
|
else
|
||||||
|
die("Invalid immediate size");
|
||||||
|
addr = paddr;
|
||||||
|
}
|
||||||
bool isram = false;
|
bool isram = false;
|
||||||
void* ptr = _vmem_read_const(op.rs1._imm, isram, size);
|
void* ptr = _vmem_read_const(addr, isram, size);
|
||||||
|
|
||||||
if (isram)
|
if (isram)
|
||||||
{
|
{
|
||||||
|
@ -338,14 +479,27 @@ public:
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
movsx(regalloc.MapRegister(op.rd), word[rax]);
|
if (regalloc.IsAllocg(op.rd))
|
||||||
|
movsx(regalloc.MapRegister(op.rd), word[rax]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
movsx(eax, word[rax]);
|
||||||
|
mov(rcx, (uintptr_t)op.rd.reg_ptr());
|
||||||
|
mov(dword[rcx], eax);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
if (regalloc.IsAllocg(op.rd))
|
if (regalloc.IsAllocg(op.rd))
|
||||||
mov(regalloc.MapRegister(op.rd), dword[rax]);
|
mov(regalloc.MapRegister(op.rd), dword[rax]);
|
||||||
else
|
else if (regalloc.IsAllocf(op.rd))
|
||||||
movd(regalloc.MapXRegister(op.rd), dword[rax]);
|
movd(regalloc.MapXRegister(op.rd), dword[rax]);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(eax, dword[rax]);
|
||||||
|
mov(rcx, (uintptr_t)op.rd.reg_ptr());
|
||||||
|
mov(dword[rcx], eax);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -356,7 +510,7 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Not RAM: the returned pointer is a memory handler
|
// Not RAM: the returned pointer is a memory handler
|
||||||
mov(call_regs[0], op.rs1._imm);
|
mov(call_regs[0], addr);
|
||||||
|
|
||||||
switch(size)
|
switch(size)
|
||||||
{
|
{
|
||||||
|
@ -385,42 +539,71 @@ public:
|
||||||
{
|
{
|
||||||
if (op.rs3.is_imm())
|
if (op.rs3.is_imm())
|
||||||
add(call_regs[0], op.rs3._imm);
|
add(call_regs[0], op.rs3._imm);
|
||||||
else
|
else if (regalloc.IsAllocg(op.rs3))
|
||||||
add(call_regs[0], regalloc.MapRegister(op.rs3));
|
add(call_regs[0], regalloc.MapRegister(op.rs3));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)op.rs3.reg_ptr());
|
||||||
|
add(call_regs[0], dword[rax]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (mmu_enabled())
|
||||||
|
mov(call_regs[1], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
|
||||||
|
|
||||||
if (size == 1) {
|
if (size == 1) {
|
||||||
GenCall(ReadMem8);
|
if (!mmu_enabled())
|
||||||
|
GenCall(ReadMem8);
|
||||||
|
else
|
||||||
|
GenCall(ReadMemNoEx<u8>);
|
||||||
movsx(ecx, al);
|
movsx(ecx, al);
|
||||||
}
|
}
|
||||||
else if (size == 2) {
|
else if (size == 2) {
|
||||||
GenCall(ReadMem16);
|
if (!mmu_enabled())
|
||||||
|
GenCall(ReadMem16);
|
||||||
|
else
|
||||||
|
GenCall(ReadMemNoEx<u16>);
|
||||||
movsx(ecx, ax);
|
movsx(ecx, ax);
|
||||||
}
|
}
|
||||||
else if (size == 4) {
|
else if (size == 4) {
|
||||||
GenCall(ReadMem32);
|
if (!mmu_enabled())
|
||||||
|
GenCall(ReadMem32);
|
||||||
|
else
|
||||||
|
GenCall(ReadMemNoEx<u32>);
|
||||||
mov(ecx, eax);
|
mov(ecx, eax);
|
||||||
}
|
}
|
||||||
else if (size == 8) {
|
else if (size == 8) {
|
||||||
GenCall(ReadMem64);
|
if (!mmu_enabled())
|
||||||
|
GenCall(ReadMem64);
|
||||||
|
else
|
||||||
|
GenCall(ReadMemNoEx<u64>);
|
||||||
mov(rcx, rax);
|
mov(rcx, rax);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
die("1..8 bytes");
|
die("1..8 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
test(dword[(void *)&exception_raised], 1);
|
||||||
|
jnz(exit_block, T_NEAR);
|
||||||
|
}
|
||||||
|
|
||||||
if (size != 8)
|
if (size != 8)
|
||||||
host_reg_to_shil_param(op.rd, ecx);
|
host_reg_to_shil_param(op.rd, ecx);
|
||||||
else {
|
else {
|
||||||
#ifdef EXPLODE_SPANS
|
#ifdef EXPLODE_SPANS
|
||||||
verify(op.rd.count() == 2 && regalloc.IsAllocf(op.rd, 0) && regalloc.IsAllocf(op.rd, 1));
|
if (op.rd.count() == 2 && regalloc.IsAllocf(op.rd, 0) && regalloc.IsAllocf(op.rd, 1))
|
||||||
movd(regalloc.MapXRegister(op.rd, 0), ecx);
|
{
|
||||||
shr(rcx, 32);
|
movd(regalloc.MapXRegister(op.rd, 0), ecx);
|
||||||
movd(regalloc.MapXRegister(op.rd, 1), ecx);
|
shr(rcx, 32);
|
||||||
#else
|
movd(regalloc.MapXRegister(op.rd, 1), ecx);
|
||||||
mov(rax, (uintptr_t)op.rd.reg_ptr());
|
}
|
||||||
mov(qword[rax], rcx);
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)op.rd.reg_ptr());
|
||||||
|
mov(qword[rax], rcx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -434,36 +617,69 @@ public:
|
||||||
{
|
{
|
||||||
if (op.rs3.is_imm())
|
if (op.rs3.is_imm())
|
||||||
add(call_regs[0], op.rs3._imm);
|
add(call_regs[0], op.rs3._imm);
|
||||||
else
|
else if (regalloc.IsAllocg(op.rs3))
|
||||||
add(call_regs[0], regalloc.MapRegister(op.rs3));
|
add(call_regs[0], regalloc.MapRegister(op.rs3));
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)op.rs3.reg_ptr());
|
||||||
|
add(call_regs[0], dword[rax]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != 8)
|
if (size != 8)
|
||||||
shil_param_to_host_reg(op.rs2, call_regs[1]);
|
shil_param_to_host_reg(op.rs2, call_regs[1]);
|
||||||
else {
|
else {
|
||||||
#ifdef EXPLODE_SPANS
|
#ifdef EXPLODE_SPANS
|
||||||
verify(op.rs2.count() == 2 && regalloc.IsAllocf(op.rs2, 0) && regalloc.IsAllocf(op.rs2, 1));
|
if (op.rs2.count() == 2 && regalloc.IsAllocf(op.rs2, 0) && regalloc.IsAllocf(op.rs2, 1))
|
||||||
movd(call_regs[1], regalloc.MapXRegister(op.rs2, 1));
|
{
|
||||||
shl(call_regs64[1], 32);
|
movd(call_regs[1], regalloc.MapXRegister(op.rs2, 1));
|
||||||
movd(eax, regalloc.MapXRegister(op.rs2, 0));
|
shl(call_regs64[1], 32);
|
||||||
or_(call_regs64[1], rax);
|
movd(eax, regalloc.MapXRegister(op.rs2, 0));
|
||||||
#else
|
or_(call_regs64[1], rax);
|
||||||
mov(rax, (uintptr_t)op.rs2.reg_ptr());
|
}
|
||||||
mov(call_regs64[1], qword[rax]);
|
else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)op.rs2.reg_ptr());
|
||||||
|
mov(call_regs64[1], qword[rax]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (mmu_enabled())
|
||||||
|
mov(call_regs[2], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
|
||||||
|
|
||||||
if (size == 1)
|
if (size == 1) {
|
||||||
GenCall(WriteMem8);
|
if (!mmu_enabled())
|
||||||
else if (size == 2)
|
GenCall(WriteMem8);
|
||||||
GenCall(WriteMem16);
|
else
|
||||||
else if (size == 4)
|
GenCall(WriteMemNoEx<u8>);
|
||||||
GenCall(WriteMem32);
|
}
|
||||||
else if (size == 8)
|
else if (size == 2) {
|
||||||
GenCall(WriteMem64);
|
if (!mmu_enabled())
|
||||||
|
GenCall(WriteMem16);
|
||||||
|
else
|
||||||
|
GenCall(WriteMemNoEx<u16>);
|
||||||
|
}
|
||||||
|
else if (size == 4) {
|
||||||
|
if (!mmu_enabled())
|
||||||
|
GenCall(WriteMem32);
|
||||||
|
else
|
||||||
|
GenCall(WriteMemNoEx<u32>);
|
||||||
|
}
|
||||||
|
else if (size == 8) {
|
||||||
|
if (!mmu_enabled())
|
||||||
|
GenCall(WriteMem64);
|
||||||
|
else
|
||||||
|
GenCall(WriteMemNoEx<u64>);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
die("1..8 bytes");
|
die("1..8 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
test(dword[(void *)&exception_raised], 1);
|
||||||
|
jnz(exit_block, T_NEAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -683,11 +899,52 @@ public:
|
||||||
shr(rax, 32);
|
shr(rax, 32);
|
||||||
mov(regalloc.MapRegister(op.rd2), eax);
|
mov(regalloc.MapRegister(op.rd2), eax);
|
||||||
break;
|
break;
|
||||||
/*
|
|
||||||
case shop_pref:
|
case shop_pref:
|
||||||
// TODO
|
{
|
||||||
|
Xbyak::Reg32 rn;
|
||||||
|
if (regalloc.IsAllocg(op.rs1))
|
||||||
|
{
|
||||||
|
rn = regalloc.MapRegister(op.rs1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)op.rs1.reg_ptr());
|
||||||
|
mov(eax, dword[rax]);
|
||||||
|
rn = eax;
|
||||||
|
}
|
||||||
|
mov(ecx, rn);
|
||||||
|
shr(ecx, 26);
|
||||||
|
cmp(ecx, 0x38);
|
||||||
|
Xbyak::Label no_sqw;
|
||||||
|
jne(no_sqw);
|
||||||
|
|
||||||
|
mov(call_regs[0], rn);
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
mov(call_regs[1], block->vaddr + op.guest_offs - (op.delay_slot ? 1 : 0)); // pc
|
||||||
|
|
||||||
|
GenCall(do_sqw_mmu_no_ex);
|
||||||
|
|
||||||
|
test(dword[(void *)&exception_raised], 1);
|
||||||
|
jnz(exit_block, T_NEAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CCN_MMUCR.AT == 1)
|
||||||
|
{
|
||||||
|
GenCall(do_sqw_mmu);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(call_regs64[1], (uintptr_t)sq_both);
|
||||||
|
GenCall(&do_sqw_nommu_local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
L(no_sqw);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
*/
|
|
||||||
case shop_ext_s8:
|
case shop_ext_s8:
|
||||||
mov(eax, regalloc.MapRegister(op.rs1));
|
mov(eax, regalloc.MapRegister(op.rs1));
|
||||||
movsx(regalloc.MapRegister(op.rd), al);
|
movsx(regalloc.MapRegister(op.rd), al);
|
||||||
|
@ -968,6 +1225,7 @@ public:
|
||||||
die("Invalid block end type");
|
die("Invalid block end type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
L(exit_block);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
add(rsp, 0x28);
|
add(rsp, 0x28);
|
||||||
#else
|
#else
|
||||||
|
@ -978,6 +1236,7 @@ public:
|
||||||
ready();
|
ready();
|
||||||
|
|
||||||
block->code = (DynarecCodeEntryPtr)getCode();
|
block->code = (DynarecCodeEntryPtr)getCode();
|
||||||
|
block->host_code_size = getSize();
|
||||||
|
|
||||||
emit_Skip(getSize());
|
emit_Skip(getSize());
|
||||||
}
|
}
|
||||||
|
@ -1089,6 +1348,19 @@ private:
|
||||||
void CheckBlock(RuntimeBlockInfo* block) {
|
void CheckBlock(RuntimeBlockInfo* block) {
|
||||||
mov(call_regs[0], block->addr);
|
mov(call_regs[0], block->addr);
|
||||||
|
|
||||||
|
// if (mmu_enabled() && block->asid != 0xFFFFFFFF)
|
||||||
|
// {
|
||||||
|
// mov(rax, (uintptr_t)&CCN_PTEH.reg_data);
|
||||||
|
// cmp(byte[rax], block->asid);
|
||||||
|
// jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
|
||||||
|
// }
|
||||||
|
if (mmu_enabled())
|
||||||
|
{
|
||||||
|
mov(rax, (uintptr_t)&next_pc);
|
||||||
|
cmp(dword[rax], block->vaddr);
|
||||||
|
jne(reinterpret_cast<const void*>(&ngen_blockcheckfail));
|
||||||
|
}
|
||||||
|
|
||||||
s32 sz=block->sh4_code_size;
|
s32 sz=block->sh4_code_size;
|
||||||
u32 sa=block->addr;
|
u32 sa=block->addr;
|
||||||
|
|
||||||
|
@ -1147,22 +1419,66 @@ private:
|
||||||
void GenCall(Ret(*function)(Params...))
|
void GenCall(Ret(*function)(Params...))
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
bool xmm8_mapped = regalloc.IsMapped(xmm8, current_opid);
|
||||||
|
bool xmm9_mapped = regalloc.IsMapped(xmm9, current_opid);
|
||||||
|
bool xmm10_mapped = regalloc.IsMapped(xmm10, current_opid);
|
||||||
|
bool xmm11_mapped = regalloc.IsMapped(xmm11, current_opid);
|
||||||
|
|
||||||
// Need to save xmm registers as they are not preserved in linux/mach
|
// Need to save xmm registers as they are not preserved in linux/mach
|
||||||
sub(rsp, 16);
|
int offset = 0;
|
||||||
movd(ptr[rsp + 0], xmm8);
|
if (xmm8_mapped || xmm9_mapped || xmm10_mapped || xmm11_mapped)
|
||||||
movd(ptr[rsp + 4], xmm9);
|
{
|
||||||
movd(ptr[rsp + 8], xmm10);
|
sub(rsp, 4 * (xmm8_mapped + xmm9_mapped + xmm10_mapped + xmm11_mapped));
|
||||||
movd(ptr[rsp + 12], xmm11);
|
if (xmm8_mapped)
|
||||||
|
{
|
||||||
|
movd(ptr[rsp + offset], xmm8);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
if (xmm9_mapped)
|
||||||
|
{
|
||||||
|
movd(ptr[rsp + offset], xmm9);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
if (xmm10_mapped)
|
||||||
|
{
|
||||||
|
movd(ptr[rsp + offset], xmm10);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
if (xmm11_mapped)
|
||||||
|
{
|
||||||
|
movd(ptr[rsp + offset], xmm11);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
call(function);
|
call(function);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
movd(xmm8, ptr[rsp + 0]);
|
if (xmm8_mapped || xmm9_mapped || xmm10_mapped || xmm11_mapped)
|
||||||
movd(xmm9, ptr[rsp + 4]);
|
{
|
||||||
movd(xmm10, ptr[rsp + 8]);
|
if (xmm11_mapped)
|
||||||
movd(xmm11, ptr[rsp + 12]);
|
{
|
||||||
add(rsp, 16);
|
offset -= 4;
|
||||||
|
movd(xmm11, ptr[rsp + offset]);
|
||||||
|
}
|
||||||
|
if (xmm10_mapped)
|
||||||
|
{
|
||||||
|
offset -= 4;
|
||||||
|
movd(xmm10, ptr[rsp + offset]);
|
||||||
|
}
|
||||||
|
if (xmm9_mapped)
|
||||||
|
{
|
||||||
|
offset -= 4;
|
||||||
|
movd(xmm9, ptr[rsp + offset]);
|
||||||
|
}
|
||||||
|
if (xmm8_mapped)
|
||||||
|
{
|
||||||
|
offset -= 4;
|
||||||
|
movd(xmm8, ptr[rsp + offset]);
|
||||||
|
}
|
||||||
|
add(rsp, 4 * (xmm8_mapped + xmm9_mapped + xmm10_mapped + xmm11_mapped));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,17 +1499,36 @@ private:
|
||||||
{
|
{
|
||||||
if (param.is_r32f())
|
if (param.is_r32f())
|
||||||
{
|
{
|
||||||
if (!reg.isXMM())
|
if (regalloc.IsAllocf(param))
|
||||||
movd((const Xbyak::Reg32 &)reg, regalloc.MapXRegister(param));
|
{
|
||||||
|
if (!reg.isXMM())
|
||||||
|
movd((const Xbyak::Reg32 &)reg, regalloc.MapXRegister(param));
|
||||||
|
else
|
||||||
|
movss((const Xbyak::Xmm &)reg, regalloc.MapXRegister(param));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
movss((const Xbyak::Xmm &)reg, regalloc.MapXRegister(param));
|
{
|
||||||
|
mov(rax, (size_t)param.reg_ptr());
|
||||||
|
mov((const Xbyak::Reg32 &)reg, dword[rax]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!reg.isXMM())
|
if (regalloc.IsAllocg(param))
|
||||||
mov((const Xbyak::Reg32 &)reg, regalloc.MapRegister(param));
|
{
|
||||||
|
if (!reg.isXMM())
|
||||||
|
mov((const Xbyak::Reg32 &)reg, regalloc.MapRegister(param));
|
||||||
|
else
|
||||||
|
movd((const Xbyak::Xmm &)reg, regalloc.MapRegister(param));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
movd((const Xbyak::Xmm &)reg, regalloc.MapRegister(param));
|
{
|
||||||
|
mov(rax, (size_t)param.reg_ptr());
|
||||||
|
if (!reg.isXMM())
|
||||||
|
mov((const Xbyak::Reg32 &)reg, dword[rax]);
|
||||||
|
else
|
||||||
|
movss((const Xbyak::Xmm &)reg, dword[rax]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1212,13 +1547,21 @@ private:
|
||||||
else
|
else
|
||||||
movd(regalloc.MapRegister(param), (const Xbyak::Xmm &)reg);
|
movd(regalloc.MapRegister(param), (const Xbyak::Xmm &)reg);
|
||||||
}
|
}
|
||||||
else
|
else if (regalloc.IsAllocf(param))
|
||||||
{
|
{
|
||||||
if (!reg.isXMM())
|
if (!reg.isXMM())
|
||||||
movd(regalloc.MapXRegister(param), (const Xbyak::Reg32 &)reg);
|
movd(regalloc.MapXRegister(param), (const Xbyak::Reg32 &)reg);
|
||||||
else
|
else
|
||||||
movss(regalloc.MapXRegister(param), (const Xbyak::Xmm &)reg);
|
movss(regalloc.MapXRegister(param), (const Xbyak::Xmm &)reg);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mov(rax, (size_t)param.reg_ptr());
|
||||||
|
if (!reg.isXMM())
|
||||||
|
mov(dword[rax], (const Xbyak::Reg32 &)reg);
|
||||||
|
else
|
||||||
|
movss(dword[rax], (const Xbyak::Xmm &)reg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Xbyak::Reg32> call_regs;
|
vector<Xbyak::Reg32> call_regs;
|
||||||
|
@ -1234,6 +1577,7 @@ private:
|
||||||
|
|
||||||
X64RegAlloc regalloc;
|
X64RegAlloc regalloc;
|
||||||
Xbyak::util::Cpu cpu;
|
Xbyak::util::Cpu cpu;
|
||||||
|
size_t current_opid;
|
||||||
static const u32 float_sign_mask;
|
static const u32 float_sign_mask;
|
||||||
static const u32 float_abs_mask;
|
static const u32 float_abs_mask;
|
||||||
static const f32 cvtf2i_pos_saturation;
|
static const f32 cvtf2i_pos_saturation;
|
||||||
|
|
|
@ -71,6 +71,16 @@ struct X64RegAlloc : RegAlloc<Xbyak::Operand::Code, s8,
|
||||||
return Xbyak::Xmm(ereg);
|
return Xbyak::Xmm(ereg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsMapped(const Xbyak::Xmm &xmm, size_t opid)
|
||||||
|
{
|
||||||
|
for (size_t sid = 0; sid < all_spans.size(); sid++)
|
||||||
|
{
|
||||||
|
if (all_spans[sid]->nregf == xmm.getIdx() && all_spans[sid]->contains(opid))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BlockCompiler *compiler;
|
BlockCompiler *compiler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue