idle skipping works!
This commit is contained in:
+10
-30
@@ -96,49 +96,37 @@ void Core::StepRSP(const u32 cpuCycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::MaybeIdleSkip() {
|
||||||
|
if (GetRegs().nextPC == GetRegs().pc)
|
||||||
|
Scheduler::GetInstance().SkipToNext();
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Run(const float volumeL, const float volumeR) {
|
void Core::Run(const float volumeL, const float volumeR) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
bool broken = false;
|
bool broken = false;
|
||||||
for (int field = 0; field < mmio.vi.numFields; field++) {
|
for (int field = 0; field < mmio.vi.numFields; field++) {
|
||||||
|
Scheduler::GetInstance().HandleEvents();
|
||||||
u32 frameCycles = 0;
|
u32 frameCycles = 0;
|
||||||
for (int i = 0; i < mmio.vi.numHalflines; i++) {
|
for (int halfline = 0; halfline < mmio.vi.numHalflines; halfline++) {
|
||||||
mmio.vi.current = (i << 1) + field;
|
mmio.vi.current = (halfline << 1) + field;
|
||||||
|
|
||||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||||
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cycles < mem->mmio.vi.cyclesPerHalfline) {
|
for (int cycles = 0; cycles < mem->mmio.vi.cyclesPerHalfline;) {
|
||||||
if (IsAnythingSkippable()) {
|
Scheduler::GetInstance().HandleEvents();
|
||||||
const u32 taken = Scheduler::GetInstance().events.top().time - Scheduler::GetInstance().ticks;
|
|
||||||
cycles += taken;
|
|
||||||
frameCycles += taken;
|
|
||||||
Scheduler::GetInstance().Tick(taken);
|
|
||||||
isReadingAnyIO = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 taken = StepCPU();
|
const u32 taken = StepCPU();
|
||||||
cycles += taken;
|
cycles += taken;
|
||||||
|
|
||||||
if ((broken = breakpoints.contains(regs.nextPC)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
StepRSP(taken);
|
StepRSP(taken);
|
||||||
frameCycles += taken;
|
frameCycles += taken;
|
||||||
Scheduler::GetInstance().Tick(taken);
|
Scheduler::GetInstance().Tick(taken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (broken)
|
|
||||||
break;
|
|
||||||
|
|
||||||
cycles -= mmio.vi.cyclesPerHalfline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (broken)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||||
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
||||||
}
|
}
|
||||||
@@ -146,13 +134,5 @@ void Core::Run(const float volumeL, const float volumeR) {
|
|||||||
mmio.ai.Step(frameCycles, volumeL, volumeR);
|
mmio.ai.Step(frameCycles, volumeL, volumeR);
|
||||||
Scheduler::GetInstance().Tick(frameCycles);
|
Scheduler::GetInstance().Tick(frameCycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (broken)
|
|
||||||
pause = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Core::IsAnythingSkippable() {
|
|
||||||
MMIO &mmio = mem->mmio;
|
|
||||||
return (mmio.si.status.dmaBusy || mmio.pi.dmaBusy || mmio.pi.ioBusy) && isReadingAnyIO;
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ struct Core {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetIdleSkippingStatus(bool v) { GetInstance().isReadingAnyIO = v; }
|
static void MaybeIdleSkip();
|
||||||
|
|
||||||
static Registers &GetRegs() { return GetInstance().regs; }
|
static Registers &GetRegs() { return GetInstance().regs; }
|
||||||
|
|
||||||
static Mem &GetMem() { return *GetInstance().mem; }
|
static Mem &GetMem() { return *GetInstance().mem; }
|
||||||
@@ -45,7 +44,6 @@ struct Core {
|
|||||||
bool pause = true;
|
bool pause = true;
|
||||||
bool romLoaded = false;
|
bool romLoaded = false;
|
||||||
int slot = 0;
|
int slot = 0;
|
||||||
u32 cycles = 0;
|
|
||||||
size_t memSize{}, cpuSize{}, verSize{};
|
size_t memSize{}, cpuSize{}, verSize{};
|
||||||
std::string rom;
|
std::string rom;
|
||||||
std::set<s64> breakpoints{};
|
std::set<s64> breakpoints{};
|
||||||
@@ -59,8 +57,5 @@ struct Core {
|
|||||||
#endif
|
#endif
|
||||||
Interpreter interpreter;
|
Interpreter interpreter;
|
||||||
ParallelRDP parallel;
|
ParallelRDP parallel;
|
||||||
|
|
||||||
bool isReadingAnyIO = false;
|
|
||||||
bool IsAnythingSkippable();
|
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -27,9 +27,16 @@ u64 Scheduler::Remove(const EventType eventType) const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scheduler::SkipToNext() {
|
||||||
|
ticks = events.top().time;
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::Tick(const u64 t) {
|
void Scheduler::Tick(const u64 t) {
|
||||||
n64::Mem &mem = n64::Core::GetMem();
|
|
||||||
ticks += t;
|
ticks += t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::HandleEvents() {
|
||||||
|
n64::Mem &mem = n64::Core::GetMem();
|
||||||
n64::MI &mi = mem.mmio.mi;
|
n64::MI &mi = mem.mmio.mi;
|
||||||
n64::SI &si = mem.mmio.si;
|
n64::SI &si = mem.mmio.si;
|
||||||
n64::PI &pi = mem.mmio.pi;
|
n64::PI &pi = mem.mmio.pi;
|
||||||
|
|||||||
@@ -35,11 +35,13 @@ struct Scheduler {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandleEvents();
|
||||||
void EnqueueRelative(u64, EventType);
|
void EnqueueRelative(u64, EventType);
|
||||||
void EnqueueAbsolute(u64, EventType);
|
void EnqueueAbsolute(u64, EventType);
|
||||||
[[nodiscard]] u64 Remove(EventType) const;
|
[[nodiscard]] u64 Remove(EventType) const;
|
||||||
[[nodiscard]] Event *Find(EventType) const;
|
[[nodiscard]] Event *Find(EventType) const;
|
||||||
void Tick(u64 t);
|
void Tick(u64 t);
|
||||||
|
void SkipToNext();
|
||||||
|
|
||||||
u8 index = 0;
|
u8 index = 0;
|
||||||
u64 ticks = 0;
|
u64 ticks = 0;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ void Interpreter::branch(const bool cond, const s64 address) {
|
|||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
if (cond) {
|
if (cond) {
|
||||||
regs.nextPC = address;
|
regs.nextPC = address;
|
||||||
|
Core::MaybeIdleSkip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +148,7 @@ void Interpreter::branch_likely(const bool cond, const s64 address) {
|
|||||||
if (cond) {
|
if (cond) {
|
||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
regs.nextPC = address;
|
regs.nextPC = address;
|
||||||
|
Core::MaybeIdleSkip();
|
||||||
} else {
|
} else {
|
||||||
regs.SetPC64(regs.nextPC);
|
regs.SetPC64(regs.nextPC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,7 +425,6 @@ auto PI::Read(u32 addr) const -> u32 {
|
|||||||
return wrLen;
|
return wrLen;
|
||||||
case 0x04600010:
|
case 0x04600010:
|
||||||
{
|
{
|
||||||
Core::SetIdleSkippingStatus(true);
|
|
||||||
u32 value = 0;
|
u32 value = 0;
|
||||||
value |= (dmaBusy << 0); // Is PI DMA active?
|
value |= (dmaBusy << 0); // Is PI DMA active?
|
||||||
value |= (ioBusy << 1); // Is PI IO busy?
|
value |= (ioBusy << 1); // Is PI IO busy?
|
||||||
@@ -433,6 +432,7 @@ auto PI::Read(u32 addr) const -> u32 {
|
|||||||
value |= (mem.mmio.mi.intr.pi << 3); // PI interrupt?
|
value |= (mem.mmio.mi.intr.pi << 3); // PI interrupt?
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
case 0x04600034:
|
||||||
case 0x04600014:
|
case 0x04600014:
|
||||||
return piBsdDom1Lat;
|
return piBsdDom1Lat;
|
||||||
case 0x04600018:
|
case 0x04600018:
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ auto SI::Read(u32 addr) const -> u32 {
|
|||||||
return 0;
|
return 0;
|
||||||
case 0x04800018:
|
case 0x04800018:
|
||||||
{
|
{
|
||||||
Core::SetIdleSkippingStatus(true);
|
|
||||||
u32 val = 0;
|
u32 val = 0;
|
||||||
val |= status.dmaBusy;
|
val |= status.dmaBusy;
|
||||||
val |= (0 << 1);
|
val |= (0 << 1);
|
||||||
|
|||||||
@@ -442,7 +442,7 @@ void KaizenGui::run() {
|
|||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
minimized = false;
|
minimized = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default: break;
|
||||||
}
|
}
|
||||||
QueryDevices(e);
|
QueryDevices(e);
|
||||||
HandleInput(e);
|
HandleInput(e);
|
||||||
@@ -457,4 +457,4 @@ void KaizenGui::run() {
|
|||||||
|
|
||||||
void KaizenGui::LoadTAS(const std::string &path) noexcept {
|
void KaizenGui::LoadTAS(const std::string &path) noexcept {
|
||||||
n64::Core::GetInstance().LoadTAS(fs::path(path));
|
n64::Core::GetInstance().LoadTAS(fs::path(path));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user