sh4: refactor interpreter and recompiler with Sh4Executor interface
This commit is contained in:
parent
52df0133f0
commit
93ae9d0375
|
@ -47,6 +47,8 @@
|
|||
#ifndef LIBRETRO
|
||||
#include "ui/gui.h"
|
||||
#endif
|
||||
#include "hw/sh4/sh4_interpreter.h"
|
||||
#include "hw/sh4/dyna/ngen.h"
|
||||
|
||||
settings_t settings;
|
||||
|
||||
|
@ -400,7 +402,7 @@ static void loadSpecialSettings()
|
|||
}
|
||||
}
|
||||
|
||||
void dc_reset(bool hard)
|
||||
void Emulator::dc_reset(bool hard)
|
||||
{
|
||||
if (hard)
|
||||
{
|
||||
|
@ -411,7 +413,7 @@ void dc_reset(bool hard)
|
|||
sh4_sched_reset(hard);
|
||||
pvr::reset(hard);
|
||||
aica::reset(hard);
|
||||
sh4_cpu.Reset(true);
|
||||
getSh4Executor()->Reset(true);
|
||||
mem_Reset(hard);
|
||||
}
|
||||
|
||||
|
@ -487,22 +489,28 @@ void Emulator::init()
|
|||
|
||||
// the recompiler may start generating code at this point and needs a fully configured machine
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
Get_Sh4Recompiler(&sh4_cpu);
|
||||
sh4_cpu.Init(); // Also initialize the interpreter
|
||||
recompiler = Get_Sh4Recompiler();
|
||||
recompiler->Init();
|
||||
if(config::DynarecEnabled)
|
||||
{
|
||||
INFO_LOG(DYNAREC, "Using Recompiler");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Get_Sh4Interpreter(&sh4_cpu);
|
||||
sh4_cpu.Init();
|
||||
INFO_LOG(INTERPRETER, "Using Interpreter");
|
||||
}
|
||||
interpreter = Get_Sh4Interpreter();
|
||||
interpreter->Init();
|
||||
state = Init;
|
||||
}
|
||||
|
||||
Sh4Executor *Emulator::getSh4Executor()
|
||||
{
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
if(config::DynarecEnabled)
|
||||
return recompiler;
|
||||
else
|
||||
#endif
|
||||
return interpreter;
|
||||
}
|
||||
|
||||
int getGamePlatform(const std::string& filename)
|
||||
{
|
||||
if (settings.naomi.slave)
|
||||
|
@ -671,13 +679,13 @@ void Emulator::runInternal()
|
|||
{
|
||||
if (singleStep)
|
||||
{
|
||||
sh4_cpu.Step();
|
||||
getSh4Executor()->Step();
|
||||
singleStep = false;
|
||||
}
|
||||
else if(stepRangeTo != 0)
|
||||
{
|
||||
while (Sh4cntx.pc >= stepRangeFrom && Sh4cntx.pc <= stepRangeTo)
|
||||
sh4_cpu.Step();
|
||||
getSh4Executor()->Step();
|
||||
|
||||
stepRangeFrom = 0;
|
||||
stepRangeTo = 0;
|
||||
|
@ -687,7 +695,7 @@ void Emulator::runInternal()
|
|||
do {
|
||||
resetRequested = false;
|
||||
|
||||
sh4_cpu.Run();
|
||||
getSh4Executor()->Run();
|
||||
|
||||
if (resetRequested)
|
||||
{
|
||||
|
@ -736,7 +744,18 @@ void Emulator::term()
|
|||
if (state == Init)
|
||||
{
|
||||
debugger::term();
|
||||
sh4_cpu.Term();
|
||||
if (interpreter != nullptr)
|
||||
{
|
||||
interpreter->Term();
|
||||
delete interpreter;
|
||||
interpreter = nullptr;
|
||||
}
|
||||
if (recompiler != nullptr)
|
||||
{
|
||||
recompiler->Term();
|
||||
delete recompiler;
|
||||
recompiler = nullptr;
|
||||
}
|
||||
custom_texture.Terminate(); // lr: avoid deadlock on exit (win32)
|
||||
reios_term();
|
||||
aica::term();
|
||||
|
@ -760,7 +779,7 @@ void Emulator::stop()
|
|||
const std::lock_guard<std::mutex> _(mutex);
|
||||
// must be updated after GGPO is stopped since it may run some rollback frames
|
||||
state = Loaded;
|
||||
sh4_cpu.Stop();
|
||||
getSh4Executor()->Stop();
|
||||
}
|
||||
if (config::ThreadedRendering)
|
||||
{
|
||||
|
@ -794,7 +813,7 @@ void Emulator::requestReset()
|
|||
resetRequested = true;
|
||||
if (config::GGPOEnable)
|
||||
NetworkHandshake::term();
|
||||
sh4_cpu.Stop();
|
||||
getSh4Executor()->Stop();
|
||||
}
|
||||
|
||||
void loadGameSpecificSettings()
|
||||
|
@ -841,7 +860,7 @@ void Emulator::stepRange(u32 from, u32 to)
|
|||
stop();
|
||||
}
|
||||
|
||||
void dc_loadstate(Deserializer& deser)
|
||||
void Emulator::loadstate(Deserializer& deser)
|
||||
{
|
||||
custom_texture.Terminate();
|
||||
#if FEAT_AREC == DYNAREC_JIT
|
||||
|
@ -857,7 +876,7 @@ void dc_loadstate(Deserializer& deser)
|
|||
dc_deserialize(deser);
|
||||
|
||||
mmu_set_state();
|
||||
sh4_cpu.ResetCache();
|
||||
getSh4Executor()->ResetCache();
|
||||
KillTex = true;
|
||||
}
|
||||
|
||||
|
@ -871,7 +890,7 @@ void Emulator::setNetworkState(bool online)
|
|||
&& config::Sh4Clock != 200)
|
||||
{
|
||||
config::Sh4Clock.override(200);
|
||||
sh4_cpu.ResetCache();
|
||||
getSh4Executor()->ResetCache();
|
||||
}
|
||||
EventManager::event(Event::Network);
|
||||
}
|
||||
|
@ -906,7 +925,7 @@ void Emulator::run()
|
|||
startTime = sh4_sched_now64();
|
||||
renderTimeout = false;
|
||||
if (!singleStep && stepRangeTo == 0)
|
||||
sh4_cpu.Start();
|
||||
getSh4Executor()->Start();
|
||||
try {
|
||||
runInternal();
|
||||
if (ggpo::active())
|
||||
|
@ -914,7 +933,7 @@ void Emulator::run()
|
|||
} catch (...) {
|
||||
setNetworkState(false);
|
||||
state = Error;
|
||||
sh4_cpu.Stop();
|
||||
getSh4Executor()->Stop();
|
||||
EventManager::event(Event::Pause);
|
||||
throw;
|
||||
}
|
||||
|
@ -930,18 +949,6 @@ void Emulator::start()
|
|||
if (config::GGPOEnable && config::ThreadedRendering)
|
||||
// Not supported with GGPO
|
||||
config::EmulateFramebuffer.override(false);
|
||||
#if FEAT_SHREC != DYNAREC_NONE
|
||||
if (config::DynarecEnabled)
|
||||
{
|
||||
Get_Sh4Recompiler(&sh4_cpu);
|
||||
INFO_LOG(DYNAREC, "Using Recompiler");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Get_Sh4Interpreter(&sh4_cpu);
|
||||
INFO_LOG(DYNAREC, "Using Interpreter");
|
||||
}
|
||||
setupPtyPipe();
|
||||
|
||||
memwatch::protect();
|
||||
|
@ -949,7 +956,7 @@ void Emulator::start()
|
|||
if (config::ThreadedRendering)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
sh4_cpu.Start();
|
||||
getSh4Executor()->Start();
|
||||
threadResult = std::async(std::launch::async, [this] {
|
||||
ThreadName _("Flycast-emu");
|
||||
InitAudio();
|
||||
|
@ -966,7 +973,7 @@ void Emulator::start()
|
|||
TermAudio();
|
||||
} catch (...) {
|
||||
setNetworkState(false);
|
||||
sh4_cpu.Stop();
|
||||
getSh4Executor()->Stop();
|
||||
TermAudio();
|
||||
throw;
|
||||
}
|
||||
|
@ -1044,7 +1051,7 @@ void Emulator::vblank()
|
|||
if (ggpo::active())
|
||||
ggpo::endOfFrame();
|
||||
else if (!config::ThreadedRendering)
|
||||
sh4_cpu.Stop();
|
||||
getSh4Executor()->Stop();
|
||||
}
|
||||
|
||||
bool Emulator::restartCpu()
|
||||
|
@ -1052,7 +1059,7 @@ bool Emulator::restartCpu()
|
|||
const std::lock_guard<std::mutex> _(mutex);
|
||||
if (state != Running)
|
||||
return false;
|
||||
sh4_cpu.Start();
|
||||
getSh4Executor()->Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,10 @@ void loadGameSpecificSettings();
|
|||
void SaveSettings();
|
||||
|
||||
int flycast_init(int argc, char* argv[]);
|
||||
void dc_reset(bool hard); // for tests only
|
||||
void flycast_term();
|
||||
void dc_exit();
|
||||
void dc_savestate(int index = 0, const u8 *pngData = nullptr, u32 pngSize = 0);
|
||||
void dc_loadstate(int index = 0);
|
||||
void dc_loadstate(Deserializer& deser);
|
||||
time_t dc_getStateCreationDate(int index);
|
||||
void dc_getStateScreenshot(int index, std::vector<u8>& pngData);
|
||||
|
||||
|
@ -98,6 +96,8 @@ struct LoadProgress
|
|||
std::atomic<float> progress;
|
||||
};
|
||||
|
||||
class Sh4Executor;
|
||||
|
||||
class Emulator
|
||||
{
|
||||
public:
|
||||
|
@ -170,6 +170,14 @@ public:
|
|||
* Returns true if the cpu was started
|
||||
*/
|
||||
bool restartCpu();
|
||||
/*
|
||||
* Load the machine state from the passed deserializer
|
||||
*/
|
||||
void loadstate(Deserializer& deser);
|
||||
|
||||
Sh4Executor *getSh4Executor();
|
||||
|
||||
void dc_reset(bool hard); // for tests only
|
||||
|
||||
private:
|
||||
bool checkStatus(bool wait = false);
|
||||
|
@ -193,6 +201,8 @@ private:
|
|||
u32 stepRangeTo = 0;
|
||||
bool stopRequested = false;
|
||||
std::mutex mutex;
|
||||
Sh4Executor *interpreter = nullptr;
|
||||
Sh4Executor *recompiler = nullptr;
|
||||
};
|
||||
extern Emulator emu;
|
||||
|
||||
|
|
|
@ -380,8 +380,6 @@ bool bm_lockedWrite(u8* address)
|
|||
|
||||
bool reserve()
|
||||
{
|
||||
static_assert((sizeof(Sh4RCB) % PAGE_SIZE) == 0, "sizeof(Sh4RCB) not multiple of PAGE_SIZE");
|
||||
|
||||
if (ram_base != nullptr)
|
||||
return true;
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ private:
|
|||
{
|
||||
presented = true;
|
||||
if (!config::ThreadedRendering && !ggpo::active())
|
||||
sh4_cpu.Stop();
|
||||
emu.getSh4Executor()->Stop();
|
||||
#ifdef LIBRETRO
|
||||
retro_rend_present();
|
||||
#endif
|
||||
|
@ -321,7 +321,7 @@ bool rend_init_renderer()
|
|||
rendererEnabled = true;
|
||||
if (renderer == nullptr)
|
||||
rend_create_renderer();
|
||||
bool success = renderer->Init();
|
||||
bool success = renderer != nullptr && renderer->Init();
|
||||
if (!success) {
|
||||
delete renderer;
|
||||
renderer = rend_norend();
|
||||
|
|
|
@ -40,9 +40,9 @@ ptrdiff_t cc_rx_offset;
|
|||
|
||||
static std::unordered_set<u32> smc_hotspots;
|
||||
|
||||
static sh4_if sh4Interp;
|
||||
static Sh4CodeBuffer codeBuffer;
|
||||
Sh4Dynarec *sh4Dynarec;
|
||||
Sh4Recompiler *Sh4Recompiler::Instance;
|
||||
|
||||
void *Sh4CodeBuffer::get()
|
||||
{
|
||||
|
@ -83,14 +83,14 @@ void Sh4CodeBuffer::reset(bool temporary)
|
|||
lastAddr = 0;
|
||||
}
|
||||
|
||||
static void clear_temp_cache(bool full)
|
||||
void Sh4Recompiler::clear_temp_cache(bool full)
|
||||
{
|
||||
//printf("recSh4:Temp Code Cache clear at %08X\n", curr_pc);
|
||||
codeBuffer.reset(true);
|
||||
bm_ResetTempCache(full);
|
||||
}
|
||||
|
||||
static void recSh4_ClearCache()
|
||||
void Sh4Recompiler::ResetCache()
|
||||
{
|
||||
INFO_LOG(DYNAREC, "recSh4:Dynarec Cache clear at %08X free space %d", next_pc, codeBuffer.getFreeSpace());
|
||||
codeBuffer.reset(false);
|
||||
|
@ -99,7 +99,7 @@ static void recSh4_ClearCache()
|
|||
clear_temp_cache(true);
|
||||
}
|
||||
|
||||
static void recSh4_Run()
|
||||
void Sh4Recompiler::Run()
|
||||
{
|
||||
RestoreHostRoundingMode();
|
||||
|
||||
|
@ -108,7 +108,7 @@ static void recSh4_Run()
|
|||
|
||||
sh4Dynarec->mainloop(sh4_dyna_rcb);
|
||||
|
||||
sh4_int_bCpuRun = false;
|
||||
ctx->CpuRunning = false;
|
||||
}
|
||||
|
||||
void AnalyseBlock(RuntimeBlockInfo* blk);
|
||||
|
@ -171,7 +171,7 @@ DynarecCodeEntryPtr rdv_CompilePC(u32 blockcheck_failures)
|
|||
const u32 pc = next_pc;
|
||||
|
||||
if (codeBuffer.getFreeSpace() < 32_KB || pc == 0x8c0000e0 || pc == 0xac010000 || pc == 0xac008300)
|
||||
recSh4_ClearCache();
|
||||
Sh4Recompiler::Instance->ResetCache();
|
||||
|
||||
RuntimeBlockInfo* rbi = sh4Dynarec->allocateBlock();
|
||||
|
||||
|
@ -185,7 +185,7 @@ DynarecCodeEntryPtr rdv_CompilePC(u32 blockcheck_failures)
|
|||
{
|
||||
codeBuffer.useTempBuffer(true);
|
||||
if (codeBuffer.getFreeSpace() < 32_KB)
|
||||
clear_temp_cache(false);
|
||||
Sh4Recompiler::Instance->clear_temp_cache(false);
|
||||
rbi->temp_block = true;
|
||||
if (rbi->read_only)
|
||||
INFO_LOG(DYNAREC, "WARNING: temp block %x (%x) is protected!", rbi->vaddr, rbi->addr);
|
||||
|
@ -248,7 +248,7 @@ DynarecCodeEntryPtr DYNACALL rdv_BlockCheckFail(u32 addr)
|
|||
else
|
||||
{
|
||||
next_pc = addr;
|
||||
recSh4_ClearCache();
|
||||
Sh4Recompiler::Instance->ResetCache();
|
||||
}
|
||||
return (DynarecCodeEntryPtr)CC_RW2RX(rdv_CompilePC(blockcheck_failures));
|
||||
}
|
||||
|
@ -340,34 +340,18 @@ void* DYNACALL rdv_LinkBlock(u8* code,u32 dpc)
|
|||
return (void*)rv;
|
||||
}
|
||||
|
||||
static void recSh4_Start()
|
||||
void Sh4Recompiler::Reset(bool hard)
|
||||
{
|
||||
sh4Interp.Start();
|
||||
}
|
||||
|
||||
static void recSh4_Stop()
|
||||
{
|
||||
sh4Interp.Stop();
|
||||
}
|
||||
|
||||
static void recSh4_Step()
|
||||
{
|
||||
sh4Interp.Step();
|
||||
}
|
||||
|
||||
static void recSh4_Reset(bool hard)
|
||||
{
|
||||
sh4Interp.Reset(hard);
|
||||
recSh4_ClearCache();
|
||||
super::Reset(hard);
|
||||
ResetCache();
|
||||
if (hard)
|
||||
bm_Reset();
|
||||
}
|
||||
|
||||
static void recSh4_Init()
|
||||
void Sh4Recompiler::Init()
|
||||
{
|
||||
INFO_LOG(DYNAREC, "recSh4 Init");
|
||||
Get_Sh4Interpreter(&sh4Interp);
|
||||
sh4Interp.Init();
|
||||
INFO_LOG(DYNAREC, "Sh4Recompiler::Init");
|
||||
super::Init();
|
||||
bm_Init();
|
||||
|
||||
if (addrspace::virtmemEnabled())
|
||||
|
@ -389,9 +373,9 @@ static void recSh4_Init()
|
|||
bm_ResetCache();
|
||||
}
|
||||
|
||||
static void recSh4_Term()
|
||||
void Sh4Recompiler::Term()
|
||||
{
|
||||
INFO_LOG(DYNAREC, "recSh4 Term");
|
||||
INFO_LOG(DYNAREC, "Sh4Recompiler::Term");
|
||||
#ifdef FEAT_NO_RWX_PAGES
|
||||
if (CodeCache != nullptr)
|
||||
virtmem::release_jit_block(CodeCache, (u8 *)CodeCache + cc_rx_offset, FULL_SIZE);
|
||||
|
@ -402,25 +386,12 @@ static void recSh4_Term()
|
|||
CodeCache = nullptr;
|
||||
TempCodeCache = nullptr;
|
||||
bm_Term();
|
||||
sh4Interp.Term();
|
||||
super::Term();
|
||||
}
|
||||
|
||||
static bool recSh4_IsCpuRunning()
|
||||
Sh4Executor *Get_Sh4Recompiler()
|
||||
{
|
||||
return sh4Interp.IsCpuRunning();
|
||||
}
|
||||
|
||||
void Get_Sh4Recompiler(sh4_if* cpu)
|
||||
{
|
||||
cpu->Run = recSh4_Run;
|
||||
cpu->Start = recSh4_Start;
|
||||
cpu->Stop = recSh4_Stop;
|
||||
cpu->Step = recSh4_Step;
|
||||
cpu->Reset = recSh4_Reset;
|
||||
cpu->Init = recSh4_Init;
|
||||
cpu->Term = recSh4_Term;
|
||||
cpu->IsCpuRunning = recSh4_IsCpuRunning;
|
||||
cpu->ResetCache = recSh4_ClearCache;
|
||||
return new Sh4Recompiler();
|
||||
}
|
||||
|
||||
static bool translateAddress(u32 addr, int size, u32 access, u32& outAddr, RuntimeBlockInfo* block)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#pragma once
|
||||
#include "blockmanager.h"
|
||||
#include "oslib/host_context.h"
|
||||
#include "../sh4_interpreter.h"
|
||||
|
||||
// When NO_RWX is enabled there's two address-spaces, one executable and
|
||||
// one writtable. The emitter and most of the code in rec-* will work with
|
||||
|
@ -121,3 +122,25 @@ public:
|
|||
};
|
||||
|
||||
extern Sh4Dynarec *sh4Dynarec;
|
||||
|
||||
class Sh4Recompiler : public Sh4Interpreter
|
||||
{
|
||||
using super = Sh4Interpreter;
|
||||
|
||||
public:
|
||||
Sh4Recompiler() {
|
||||
Instance = this;
|
||||
}
|
||||
~Sh4Recompiler() {
|
||||
Instance = nullptr;
|
||||
}
|
||||
void Run() override;
|
||||
void ResetCache() override;
|
||||
void Reset(bool hard) override;
|
||||
void Init() override;
|
||||
void Term() override;
|
||||
|
||||
void clear_temp_cache(bool full);
|
||||
|
||||
static Sh4Recompiler *Instance;
|
||||
};
|
||||
|
|
|
@ -14,38 +14,30 @@
|
|||
#include "debug/gdb_server.h"
|
||||
#include "../sh4_cycles.h"
|
||||
|
||||
// SH4 underclock factor when using the interpreter so that it's somewhat usable
|
||||
#ifdef STRICT_MODE
|
||||
constexpr int CPU_RATIO = 1;
|
||||
#else
|
||||
constexpr int CPU_RATIO = 8;
|
||||
#endif
|
||||
|
||||
Sh4ICache icache;
|
||||
Sh4OCache ocache;
|
||||
Sh4Cycles sh4cycles(CPU_RATIO);
|
||||
|
||||
static void ExecuteOpcode(u16 op)
|
||||
void Sh4Interpreter::ExecuteOpcode(u16 op)
|
||||
{
|
||||
if (sr.FD == 1 && OpDesc[op]->IsFloatingPoint())
|
||||
throw SH4ThrownException(next_pc - 2, Sh4Ex_FpuDisabled);
|
||||
throw SH4ThrownException(ctx->pc - 2, Sh4Ex_FpuDisabled);
|
||||
OpPtr[op](op);
|
||||
sh4cycles.executeCycles(op);
|
||||
}
|
||||
|
||||
static u16 ReadNexOp()
|
||||
u16 Sh4Interpreter::ReadNexOp()
|
||||
{
|
||||
if (!mmu_enabled() && (next_pc & 1))
|
||||
u32 addr = ctx->pc;
|
||||
if (!mmu_enabled() && (addr & 1))
|
||||
// address error
|
||||
throw SH4ThrownException(next_pc, Sh4Ex_AddressErrorRead);
|
||||
throw SH4ThrownException(addr, Sh4Ex_AddressErrorRead);
|
||||
|
||||
u32 addr = next_pc;
|
||||
next_pc += 2;
|
||||
ctx->pc = addr + 2;
|
||||
|
||||
return IReadMem16(addr);
|
||||
}
|
||||
|
||||
static void Sh4_int_Run()
|
||||
void Sh4Interpreter::Run()
|
||||
{
|
||||
RestoreHostRoundingMode();
|
||||
|
||||
|
@ -58,34 +50,34 @@ static void Sh4_int_Run()
|
|||
u32 op = ReadNexOp();
|
||||
|
||||
ExecuteOpcode(op);
|
||||
} while (p_sh4rcb->cntx.cycle_counter > 0);
|
||||
p_sh4rcb->cntx.cycle_counter += SH4_TIMESLICE;
|
||||
} while (ctx->cycle_counter > 0);
|
||||
ctx->cycle_counter += SH4_TIMESLICE;
|
||||
UpdateSystem_INTC();
|
||||
} catch (const SH4ThrownException& ex) {
|
||||
Do_Exception(ex.epc, ex.expEvn);
|
||||
// an exception requires the instruction pipeline to drain, so approx 5 cycles
|
||||
sh4cycles.addCycles(5 * CPU_RATIO);
|
||||
}
|
||||
} while (sh4_int_bCpuRun);
|
||||
} while (ctx->CpuRunning);
|
||||
} catch (const debugger::Stop&) {
|
||||
}
|
||||
|
||||
sh4_int_bCpuRun = false;
|
||||
ctx->CpuRunning = false;
|
||||
}
|
||||
|
||||
static void Sh4_int_Start()
|
||||
void Sh4Interpreter::Start()
|
||||
{
|
||||
sh4_int_bCpuRun = true;
|
||||
ctx->CpuRunning = true;
|
||||
}
|
||||
|
||||
static void Sh4_int_Stop()
|
||||
void Sh4Interpreter::Stop()
|
||||
{
|
||||
sh4_int_bCpuRun = false;
|
||||
ctx->CpuRunning = false;
|
||||
}
|
||||
|
||||
static void Sh4_int_Step()
|
||||
void Sh4Interpreter::Step()
|
||||
{
|
||||
verify(!sh4_int_bCpuRun);
|
||||
verify(!ctx->CpuRunning);
|
||||
|
||||
RestoreHostRoundingMode();
|
||||
try {
|
||||
|
@ -99,26 +91,26 @@ static void Sh4_int_Step()
|
|||
}
|
||||
}
|
||||
|
||||
static void Sh4_int_Reset(bool hard)
|
||||
void Sh4Interpreter::Reset(bool hard)
|
||||
{
|
||||
verify(!sh4_int_bCpuRun);
|
||||
verify(!ctx->CpuRunning);
|
||||
|
||||
if (hard)
|
||||
{
|
||||
int schedNext = p_sh4rcb->cntx.sh4_sched_next;
|
||||
memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx));
|
||||
p_sh4rcb->cntx.sh4_sched_next = schedNext;
|
||||
int schedNext = ctx->sh4_sched_next;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->sh4_sched_next = schedNext;
|
||||
}
|
||||
next_pc = 0xA0000000;
|
||||
ctx->pc = 0xA0000000;
|
||||
|
||||
memset(r,0,sizeof(r));
|
||||
memset(r_bank,0,sizeof(r_bank));
|
||||
memset(r, 0, sizeof(r));
|
||||
memset(r_bank, 0, sizeof(r_bank));
|
||||
|
||||
gbr=ssr=spc=sgr=dbr=vbr=0;
|
||||
mac.full=pr=fpul=0;
|
||||
gbr = ssr = spc = sgr = dbr = vbr = 0;
|
||||
mac.full = pr = fpul = 0;
|
||||
|
||||
sr.setFull(0x700000F0);
|
||||
old_sr.status=sr.status;
|
||||
old_sr.status = sr.status;
|
||||
UpdateSR();
|
||||
|
||||
fpscr.full = 0x00040001;
|
||||
|
@ -127,18 +119,18 @@ static void Sh4_int_Reset(bool hard)
|
|||
icache.Reset(hard);
|
||||
ocache.Reset(hard);
|
||||
sh4cycles.reset();
|
||||
p_sh4rcb->cntx.cycle_counter = SH4_TIMESLICE;
|
||||
ctx->cycle_counter = SH4_TIMESLICE;
|
||||
|
||||
INFO_LOG(INTERPRETER, "Sh4 Reset");
|
||||
}
|
||||
|
||||
static bool Sh4_int_IsCpuRunning()
|
||||
bool Sh4Interpreter::IsCpuRunning()
|
||||
{
|
||||
return sh4_int_bCpuRun;
|
||||
return ctx->CpuRunning;
|
||||
}
|
||||
|
||||
//TODO : Check for valid delayslot instruction
|
||||
void ExecuteDelayslot()
|
||||
void Sh4Interpreter::ExecuteDelayslot()
|
||||
{
|
||||
try {
|
||||
u32 op = ReadNexOp();
|
||||
|
@ -148,12 +140,12 @@ void ExecuteDelayslot()
|
|||
AdjustDelaySlotException(ex);
|
||||
throw ex;
|
||||
} catch (const debugger::Stop& e) {
|
||||
next_pc -= 2; // break on previous instruction
|
||||
ctx->pc -= 2; // break on previous instruction
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteDelayslot_RTE()
|
||||
void Sh4Interpreter::ExecuteDelayslot_RTE()
|
||||
{
|
||||
try {
|
||||
// In an RTE delay slot, status register (SR) bits are referenced as follows.
|
||||
|
@ -169,7 +161,7 @@ void ExecuteDelayslot_RTE()
|
|||
} catch (const SH4ThrownException&) {
|
||||
throw FlycastException("Fatal: SH4 exception in RTE delay slot");
|
||||
} catch (const debugger::Stop& e) {
|
||||
next_pc -= 2; // break on previous instruction
|
||||
ctx->pc -= 2; // break on previous instruction
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -186,30 +178,19 @@ int UpdateSystem_INTC()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void sh4_int_resetcache() {
|
||||
void Sh4Interpreter::Init()
|
||||
{
|
||||
ctx = &p_sh4rcb->cntx;
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
static void Sh4_int_Init()
|
||||
void Sh4Interpreter::Term()
|
||||
{
|
||||
memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx));
|
||||
}
|
||||
|
||||
static void Sh4_int_Term()
|
||||
{
|
||||
Sh4_int_Stop();
|
||||
Stop();
|
||||
INFO_LOG(INTERPRETER, "Sh4 Term");
|
||||
}
|
||||
|
||||
void Get_Sh4Interpreter(sh4_if* cpu)
|
||||
Sh4Executor *Get_Sh4Interpreter()
|
||||
{
|
||||
cpu->Start = Sh4_int_Start;
|
||||
cpu->Run = Sh4_int_Run;
|
||||
cpu->Stop = Sh4_int_Stop;
|
||||
cpu->Step = Sh4_int_Step;
|
||||
cpu->Reset = Sh4_int_Reset;
|
||||
cpu->Init = Sh4_int_Init;
|
||||
cpu->Term = Sh4_int_Term;
|
||||
cpu->IsCpuRunning = Sh4_int_IsCpuRunning;
|
||||
|
||||
cpu->ResetCache = sh4_int_resetcache;
|
||||
return new Sh4Interpreter();
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "hw/sh4/sh4_interrupts.h"
|
||||
#include "debug/gdb_server.h"
|
||||
#include "hw/sh4/dyna/decoder.h"
|
||||
#include "emulator.h"
|
||||
|
||||
#ifdef STRICT_MODE
|
||||
#include "hw/sh4/sh4_cache.h"
|
||||
|
@ -802,12 +803,16 @@ sh4op(i0000_0000_0010_1000)
|
|||
mac.full=0;
|
||||
}
|
||||
|
||||
static void executeDelaySlot() {
|
||||
static_cast<Sh4Interpreter *>(emu.getSh4Executor())->ExecuteDelayslot();
|
||||
}
|
||||
|
||||
//braf <REG_N>
|
||||
sh4op(i0000_nnnn_0010_0011)
|
||||
{
|
||||
u32 n = GetN(op);
|
||||
u32 newpc = r[n] + next_pc + 2;//
|
||||
ExecuteDelayslot(); //WARN : r[n] can change here
|
||||
executeDelaySlot(); //WARN : r[n] can change here
|
||||
next_pc = newpc;
|
||||
}
|
||||
//bsrf <REG_N>
|
||||
|
@ -817,7 +822,7 @@ sh4op(i0000_nnnn_0000_0011)
|
|||
u32 newpc = r[n] + next_pc +2;
|
||||
u32 newpr = next_pc + 2;
|
||||
|
||||
ExecuteDelayslot(); //WARN : pr and r[n] can change here
|
||||
executeDelaySlot(); //WARN : pr and r[n] can change here
|
||||
|
||||
pr = newpr;
|
||||
next_pc = newpc;
|
||||
|
@ -829,7 +834,7 @@ sh4op(i0000_nnnn_0000_0011)
|
|||
sh4op(i0000_0000_0010_1011)
|
||||
{
|
||||
u32 newpc = spc;
|
||||
ExecuteDelayslot_RTE();
|
||||
static_cast<Sh4Interpreter *>(emu.getSh4Executor())->ExecuteDelayslot_RTE();
|
||||
next_pc = newpc;
|
||||
if (UpdateSR())
|
||||
UpdateINTC();
|
||||
|
@ -841,7 +846,7 @@ sh4op(i0000_0000_0010_1011)
|
|||
sh4op(i0000_0000_0000_1011)
|
||||
{
|
||||
u32 newpc=pr;
|
||||
ExecuteDelayslot(); //WARN : pr can change here
|
||||
executeDelaySlot(); //WARN : pr can change here
|
||||
next_pc=newpc;
|
||||
debugger::subroutineReturn();
|
||||
}
|
||||
|
@ -868,7 +873,7 @@ sh4op(i1000_1111_iiii_iiii)
|
|||
{
|
||||
//delay 1 instruction
|
||||
u32 newpc=branch_target_s8(op);
|
||||
ExecuteDelayslot();
|
||||
executeDelaySlot();
|
||||
next_pc = newpc;
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +897,7 @@ sh4op(i1000_1101_iiii_iiii)
|
|||
{
|
||||
//delay 1 instruction
|
||||
u32 newpc=branch_target_s8(op);
|
||||
ExecuteDelayslot();
|
||||
executeDelaySlot();
|
||||
next_pc = newpc;
|
||||
}
|
||||
}
|
||||
|
@ -906,7 +911,7 @@ u32 branch_target_s12(u32 op)
|
|||
sh4op(i1010_iiii_iiii_iiii)
|
||||
{
|
||||
u32 newpc = branch_target_s12(op);
|
||||
ExecuteDelayslot();
|
||||
executeDelaySlot();
|
||||
next_pc=newpc;
|
||||
}
|
||||
|
||||
|
@ -915,7 +920,7 @@ sh4op(i1011_iiii_iiii_iiii)
|
|||
{
|
||||
u32 newpr = next_pc + 2; //return after delayslot
|
||||
u32 newpc = branch_target_s12(op);
|
||||
ExecuteDelayslot();
|
||||
executeDelaySlot();
|
||||
|
||||
pr = newpr;
|
||||
next_pc = newpc;
|
||||
|
@ -937,7 +942,7 @@ sh4op(i0100_nnnn_0010_1011)
|
|||
u32 n = GetN(op);
|
||||
|
||||
u32 newpc=r[n];
|
||||
ExecuteDelayslot(); //r[n] can change here
|
||||
executeDelaySlot(); //r[n] can change here
|
||||
next_pc=newpc;
|
||||
}
|
||||
|
||||
|
@ -948,7 +953,7 @@ sh4op(i0100_nnnn_0000_1011)
|
|||
|
||||
u32 newpr = next_pc + 2; //return after delayslot
|
||||
u32 newpc= r[n];
|
||||
ExecuteDelayslot(); //r[n]/pr can change here
|
||||
executeDelaySlot(); //r[n]/pr can change here
|
||||
|
||||
pr = newpr;
|
||||
next_pc = newpc;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "hw/sh4/sh4_core.h"
|
||||
#include "hw/sh4/sh4_cache.h"
|
||||
#include "cfg/option.h"
|
||||
#include "emulator.h"
|
||||
|
||||
CCNRegisters ccn;
|
||||
|
||||
|
@ -54,7 +55,7 @@ static void CCN_MMUCR_write(u32 addr, u32 value)
|
|||
{
|
||||
//printf("<*******>MMU Enabled , ONLY SQ remaps work<*******>\n");
|
||||
mmu_set_state();
|
||||
sh4_cpu.ResetCache();
|
||||
emu.getSh4Executor()->ResetCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,7 @@ private:
|
|||
}
|
||||
|
||||
std::array<cache_line, 256> lines;
|
||||
Sh4Cycles sh4cycles;
|
||||
};
|
||||
|
||||
extern Sh4ICache icache;
|
||||
|
@ -589,6 +590,7 @@ private:
|
|||
// TODO serialize
|
||||
u64 writeBackBufferCycles = 0;
|
||||
u64 writeThroughBufferCycles = 0;
|
||||
Sh4Cycles sh4cycles;
|
||||
};
|
||||
|
||||
extern Sh4OCache ocache;
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#define xf_hex ((u32*)xf)
|
||||
#define dr_hex ((u64*)fr)
|
||||
#define xd_hex ((u64*)xf)
|
||||
#define sh4_int_bCpuRun Sh4cntx.CpuRunning
|
||||
|
||||
void UpdateFPSCR();
|
||||
bool UpdateSR();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#endif
|
||||
|
||||
Sh4RCB* p_sh4rcb;
|
||||
sh4_if sh4_cpu;
|
||||
|
||||
static void ChangeGPR()
|
||||
{
|
||||
|
|
|
@ -17,6 +17,74 @@
|
|||
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "sh4_cycles.h"
|
||||
#include "modules/mmu.h"
|
||||
|
||||
int Sh4Cycles::countCycles(u16 op)
|
||||
{
|
||||
sh4_opcodelistentry *opcode = OpDesc[op];
|
||||
int cycles = 0;
|
||||
#ifndef STRICT_MODE
|
||||
static const bool isMemOp[45] {
|
||||
false,
|
||||
false,
|
||||
true, // all mem moves, ldtlb, sts.l FPUL/FPSCR, @-Rn, lds.l @Rn+,FPUL
|
||||
true, // gbr-based load/store
|
||||
false,
|
||||
true, // tst.b #<imm8>, @(R0,GBR)
|
||||
true, // and/or/xor.b #<imm8>, @(R0,GBR)
|
||||
true, // tas.b @Rn
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true, // movca.l R0, @Rn
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true, // ldc.l @Rn+, VBR/SPC/SSR/Rn_Bank/DBR
|
||||
true, // ldc.l @Rn+, GBR/SGR
|
||||
true, // ldc.l @Rn+, SR
|
||||
false,
|
||||
false,
|
||||
true, // stc.l DBR/SR/GBR/VBR/SSR/SPC/Rn_Bank, @-Rn
|
||||
true, // stc.l SGR, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+, PR
|
||||
false,
|
||||
true, // sts.l PR, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+, MACH/MACL
|
||||
false,
|
||||
true, // sts.l MACH/MACL, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+,FPSCR
|
||||
false,
|
||||
true, // mac.wl @Rm+,@Rn+
|
||||
};
|
||||
if (isMemOp[opcode->ex_type])
|
||||
{
|
||||
if (++memOps < 4)
|
||||
cycles = mmu_enabled() ? 5 : 2;
|
||||
}
|
||||
// TODO only for mem read?
|
||||
#endif
|
||||
|
||||
if (lastUnit == CO
|
||||
|| opcode->unit == CO
|
||||
|| (lastUnit == opcode->unit && lastUnit != MT))
|
||||
{
|
||||
// cannot run in parallel
|
||||
lastUnit = opcode->unit;
|
||||
cycles += opcode->IssueCycles;
|
||||
}
|
||||
else
|
||||
{
|
||||
// can run in parallel
|
||||
lastUnit = CO;
|
||||
}
|
||||
return cycles * cpuRatio;
|
||||
}
|
||||
|
||||
// TODO additional wait cycles depending on area?:
|
||||
// Area Wait cycles (not including external wait)
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "sh4_opcode_list.h"
|
||||
#include "sh4_if.h"
|
||||
#include "sh4_sched.h"
|
||||
#include "modules/mmu.h"
|
||||
|
||||
class Sh4Cycles
|
||||
{
|
||||
|
@ -48,72 +47,7 @@ public:
|
|||
Sh4cntx.cycle_counter -= writeAccessCycles(addr, size);
|
||||
}
|
||||
|
||||
int countCycles(u16 op)
|
||||
{
|
||||
sh4_opcodelistentry *opcode = OpDesc[op];
|
||||
int cycles = 0;
|
||||
#ifndef STRICT_MODE
|
||||
static const bool isMemOp[45] {
|
||||
false,
|
||||
false,
|
||||
true, // all mem moves, ldtlb, sts.l FPUL/FPSCR, @-Rn, lds.l @Rn+,FPUL
|
||||
true, // gbr-based load/store
|
||||
false,
|
||||
true, // tst.b #<imm8>, @(R0,GBR)
|
||||
true, // and/or/xor.b #<imm8>, @(R0,GBR)
|
||||
true, // tas.b @Rn
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true, // movca.l R0, @Rn
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true, // ldc.l @Rn+, VBR/SPC/SSR/Rn_Bank/DBR
|
||||
true, // ldc.l @Rn+, GBR/SGR
|
||||
true, // ldc.l @Rn+, SR
|
||||
false,
|
||||
false,
|
||||
true, // stc.l DBR/SR/GBR/VBR/SSR/SPC/Rn_Bank, @-Rn
|
||||
true, // stc.l SGR, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+, PR
|
||||
false,
|
||||
true, // sts.l PR, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+, MACH/MACL
|
||||
false,
|
||||
true, // sts.l MACH/MACL, @-Rn
|
||||
false,
|
||||
true, // lds.l @Rn+,FPSCR
|
||||
false,
|
||||
true, // mac.wl @Rm+,@Rn+
|
||||
};
|
||||
if (isMemOp[opcode->ex_type])
|
||||
{
|
||||
if (++memOps < 4)
|
||||
cycles = mmu_enabled() ? 5 : 2;
|
||||
}
|
||||
// TODO only for mem read?
|
||||
#endif
|
||||
|
||||
if (lastUnit == CO
|
||||
|| opcode->unit == CO
|
||||
|| (lastUnit == opcode->unit && lastUnit != MT))
|
||||
{
|
||||
// cannot run in parallel
|
||||
lastUnit = opcode->unit;
|
||||
cycles += opcode->IssueCycles;
|
||||
}
|
||||
else
|
||||
{
|
||||
// can run in parallel
|
||||
lastUnit = CO;
|
||||
}
|
||||
return cycles * cpuRatio;
|
||||
}
|
||||
int countCycles(u16 op);
|
||||
|
||||
void reset()
|
||||
{
|
||||
|
@ -143,5 +77,3 @@ private:
|
|||
const int cpuRatio;
|
||||
int memOps = 0;
|
||||
};
|
||||
|
||||
extern Sh4Cycles sh4cycles;
|
||||
|
|
|
@ -100,21 +100,21 @@ struct fpscr_t
|
|||
};
|
||||
|
||||
//sh4 interface
|
||||
struct sh4_if
|
||||
class Sh4Executor
|
||||
{
|
||||
void (*Start)();
|
||||
void (*Run)();
|
||||
void (*Stop)();
|
||||
void (*Step)();
|
||||
void (*Reset)(bool hard);
|
||||
void (*Init)();
|
||||
void (*Term)();
|
||||
void (*ResetCache)();
|
||||
bool (*IsCpuRunning)();
|
||||
public:
|
||||
virtual ~Sh4Executor() {}
|
||||
virtual void Run() = 0;
|
||||
virtual void Start() = 0;
|
||||
virtual void Stop() = 0;
|
||||
virtual void Step() = 0;
|
||||
virtual void Reset(bool hard) = 0;
|
||||
virtual void Init() = 0;
|
||||
virtual void Term() = 0;
|
||||
virtual void ResetCache() = 0;
|
||||
virtual bool IsCpuRunning() = 0;
|
||||
};
|
||||
|
||||
extern sh4_if sh4_cpu;
|
||||
|
||||
struct alignas(32) SQBuffer {
|
||||
u8 data[32];
|
||||
};
|
||||
|
@ -235,6 +235,7 @@ struct alignas(PAGE_SIZE) Sh4RCB
|
|||
SQWriteFunc *do_sqw_nommu;
|
||||
Sh4Context cntx;
|
||||
};
|
||||
static_assert((sizeof(Sh4RCB) % PAGE_SIZE) == 0, "sizeof(Sh4RCB) not multiple of PAGE_SIZE");
|
||||
|
||||
extern Sh4RCB* p_sh4rcb;
|
||||
|
||||
|
@ -244,8 +245,8 @@ extern Sh4RCB* p_sh4rcb;
|
|||
#define Sh4cntx (sh4rcb.cntx)
|
||||
|
||||
//Get an interface to sh4 interpreter
|
||||
void Get_Sh4Interpreter(sh4_if* cpu);
|
||||
void Get_Sh4Recompiler(sh4_if* cpu);
|
||||
Sh4Executor *Get_Sh4Interpreter();
|
||||
Sh4Executor *Get_Sh4Recompiler();
|
||||
|
||||
enum Sh4ExceptionCode : u16
|
||||
{
|
||||
|
|
|
@ -1,41 +1,37 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include "sh4_cycles.h"
|
||||
|
||||
#undef sh4op
|
||||
#define sh4op(str) void DYNACALL str (u32 op)
|
||||
typedef void (DYNACALL OpCallFP) (u32 op);
|
||||
|
||||
enum OpcodeType
|
||||
class Sh4Interpreter : public Sh4Executor
|
||||
{
|
||||
//basic
|
||||
Normal = 0, // Heh , nothing special :P
|
||||
ReadsPC = 1, // PC must be set upon calling it
|
||||
WritesPC = 2, // It will write PC (branch)
|
||||
Delayslot = 4, // Has a delayslot opcode , valid only when WritesPC is set
|
||||
public:
|
||||
void Run() override;
|
||||
void ResetCache() override {}
|
||||
void Start() override;
|
||||
void Stop() override;
|
||||
void Step() override;
|
||||
void Reset(bool hard) override;
|
||||
void Init() override;
|
||||
void Term() override;
|
||||
bool IsCpuRunning() override;
|
||||
void ExecuteDelayslot();
|
||||
void ExecuteDelayslot_RTE();
|
||||
Sh4Context *getContext() { return ctx; }
|
||||
|
||||
WritesSR = 8, // Writes to SR , and UpdateSR needs to be called
|
||||
WritesFPSCR = 16, // Writes to FPSCR , and UpdateSR needs to be called
|
||||
Invalid = 128, // Invalid
|
||||
protected:
|
||||
Sh4Context *ctx = nullptr;
|
||||
|
||||
UsesFPU = 2048, // Floating point op
|
||||
FWritesFPSCR = UsesFPU | WritesFPSCR,
|
||||
private:
|
||||
void ExecuteOpcode(u16 op);
|
||||
u16 ReadNexOp();
|
||||
|
||||
// Heh, not basic :P
|
||||
ReadWritePC = ReadsPC|WritesPC, // Read and writes pc :P
|
||||
WritesSRRWPC = WritesSR|ReadsPC|WritesPC,
|
||||
|
||||
// Branches (not delay slot):
|
||||
Branch_dir = ReadWritePC, // Direct (eg , pc=r[xx]) -- this one is ReadWritePC b/c the delayslot may use pc ;)
|
||||
Branch_rel = ReadWritePC, // Relative (rg pc+=10);
|
||||
|
||||
// Delay slot
|
||||
Branch_dir_d = Delayslot|Branch_dir, // Direct (eg , pc=r[xx])
|
||||
Branch_rel_d = Delayslot|Branch_rel, // Relative (rg pc+=10);
|
||||
Sh4Cycles sh4cycles{CPU_RATIO};
|
||||
// SH4 underclock factor when using the interpreter so that it's somewhat usable
|
||||
#ifdef STRICT_MODE
|
||||
static constexpr int CPU_RATIO = 1;
|
||||
#else
|
||||
static constexpr int CPU_RATIO = 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
void ExecuteDelayslot();
|
||||
void ExecuteDelayslot_RTE();
|
||||
|
||||
#define SH4_TIMESLICE 448 // at 112 Bangai-O doesn't start. 224 is ok
|
||||
|
||||
int UpdateSystem_INTC();
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include "sh4_interpreter.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#define sh4op(str) void DYNACALL str (u32 op)
|
||||
|
||||
typedef void (DYNACALL OpCallFP) (u32 op);
|
||||
extern OpCallFP* OpPtr[0x10000];
|
||||
|
||||
typedef void OpDissasmFP(char* out,const char* const FormatString,u32 pc,u16 opcode);
|
||||
|
@ -18,6 +19,34 @@ enum sh4_eu
|
|||
CO,
|
||||
};
|
||||
|
||||
enum OpcodeType
|
||||
{
|
||||
//basic
|
||||
Normal = 0, // Heh , nothing special :P
|
||||
ReadsPC = 1, // PC must be set upon calling it
|
||||
WritesPC = 2, // It will write PC (branch)
|
||||
Delayslot = 4, // Has a delayslot opcode , valid only when WritesPC is set
|
||||
|
||||
WritesSR = 8, // Writes to SR , and UpdateSR needs to be called
|
||||
WritesFPSCR = 16, // Writes to FPSCR , and UpdateSR needs to be called
|
||||
Invalid = 128, // Invalid
|
||||
|
||||
UsesFPU = 2048, // Floating point op
|
||||
FWritesFPSCR = UsesFPU | WritesFPSCR,
|
||||
|
||||
// Heh, not basic :P
|
||||
ReadWritePC = ReadsPC|WritesPC, // Read and writes pc :P
|
||||
WritesSRRWPC = WritesSR|ReadsPC|WritesPC,
|
||||
|
||||
// Branches (not delay slot):
|
||||
Branch_dir = ReadWritePC, // Direct (eg , pc=r[xx]) -- this one is ReadWritePC b/c the delayslot may use pc ;)
|
||||
Branch_rel = ReadWritePC, // Relative (rg pc+=10);
|
||||
|
||||
// Delay slot
|
||||
Branch_dir_d = Delayslot|Branch_dir, // Direct (eg , pc=r[xx])
|
||||
Branch_rel_d = Delayslot|Branch_rel, // Relative (rg pc+=10);
|
||||
};
|
||||
|
||||
std::string disassemble_op(const char* tx1, u32 pc, u16 opcode);
|
||||
|
||||
typedef void ( RecOpCallFP) (u32 op);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef SH4_SCHED_H
|
||||
#define SH4_SCHED_H
|
||||
|
||||
#pragma once
|
||||
#include "types.h"
|
||||
|
||||
#define SH4_TIMESLICE 448 // at 112 Bangai-O doesn't start. 224 is ok
|
||||
|
||||
/*
|
||||
tag, as passed on sh4_sched_register
|
||||
sch_cycles, the cycle duration that the callback requested (sh4_sched_request)
|
||||
|
@ -53,5 +53,3 @@ void sh4_sched_serialize(Serializer& ser);
|
|||
void sh4_sched_deserialize(Deserializer& deser);
|
||||
void sh4_sched_serialize(Serializer& ser, int id);
|
||||
void sh4_sched_deserialize(Deserializer& deser, int id);
|
||||
|
||||
#endif //SH4_SCHED_H
|
||||
|
|
|
@ -330,7 +330,7 @@ static bool load_game_state(unsigned char *buffer, int len)
|
|||
*/
|
||||
static bool save_game_state(unsigned char **buffer, int *len, int *checksum, int frame)
|
||||
{
|
||||
verify(!sh4_cpu.IsCpuRunning());
|
||||
verify(!emu.getSh4Executor()->IsCpuRunning());
|
||||
lastSavedFrame = frame;
|
||||
// TODO this is way too much memory
|
||||
size_t allocSize = settings.platform.isNaomi() ? 20_MB : 10_MB;
|
||||
|
@ -914,7 +914,7 @@ void endOfFrame()
|
|||
if (active())
|
||||
{
|
||||
_endOfFrame = true;
|
||||
sh4_cpu.Stop();
|
||||
emu.getSh4Executor()->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ void dc_loadstate(int index)
|
|||
|
||||
try {
|
||||
Deserializer deser(data, total_size);
|
||||
dc_loadstate(deser);
|
||||
emu.loadstate(deser);
|
||||
NOTICE_LOG(SAVESTATE, "Loaded state ver %d from %s size %d", deser.version(), filename.c_str(), total_size);
|
||||
if (deser.size() != total_size)
|
||||
// Note: this isn't true for RA savestates
|
||||
|
|
|
@ -2362,7 +2362,7 @@ bool retro_unserialize(const void * data, size_t size)
|
|||
|
||||
try {
|
||||
Deserializer deser(data, size);
|
||||
dc_loadstate(deser);
|
||||
emu.loadstate(deser);
|
||||
retro_audio_flush_buffer();
|
||||
if (!first_run)
|
||||
emu.start();
|
||||
|
|
|
@ -27,7 +27,7 @@ protected:
|
|||
if (!addrspace::reserve())
|
||||
die("addrspace::reserve failed");
|
||||
emu.init();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
Arm7Enabled = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -287,7 +287,7 @@ cheats = "2"
|
|||
mgr.reset("TESTSUB8");
|
||||
mgr.loadCheatFile("test.cht");
|
||||
mem_map_default();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
|
||||
mgr.enableCheat(0, true);
|
||||
WriteMem8_nommu(0x8c010000, 0xFA);
|
||||
|
|
|
@ -30,7 +30,7 @@ protected:
|
|||
if (!addrspace::reserve())
|
||||
die("addrspace::reserve failed");
|
||||
emu.init();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
CCN_MMUCR.AT = 1;
|
||||
MMU_reset();
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ protected:
|
|||
die("addrspace::reserve failed");
|
||||
emu.init();
|
||||
mem_map_default();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
ctx = &p_sh4rcb->cntx;
|
||||
Get_Sh4Interpreter(&sh4);
|
||||
sh4 = Get_Sh4Interpreter();
|
||||
}
|
||||
void PrepareOp(u16 op, u16 op2 = 0, u16 op3 = 0) override
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ protected:
|
|||
{
|
||||
ctx->pc = START_PC;
|
||||
for (int i = 0; i < numOp; i++)
|
||||
sh4.Step();
|
||||
sh4->Step();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ protected:
|
|||
if (!addrspace::reserve())
|
||||
die("addrspace::reserve failed");
|
||||
emu.init();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
}
|
||||
|
||||
void div32s(u32 n1, u32 n2, u32 n3)
|
||||
|
|
|
@ -13,7 +13,7 @@ protected:
|
|||
if (!addrspace::reserve())
|
||||
die("addrspace::reserve failed");
|
||||
emu.init();
|
||||
dc_reset(true);
|
||||
emu.dc_reset(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ protected:
|
|||
}
|
||||
|
||||
Sh4Context *ctx;
|
||||
sh4_if sh4;
|
||||
Sh4Executor *sh4;
|
||||
std::set<u32 *> checkedRegs;
|
||||
static constexpr u32 START_PC = 0xAC000000;
|
||||
|
||||
|
|
Loading…
Reference in New Issue