TLBWR + Scheduler (SI DMA delay)

This commit is contained in:
Simone Coco
2022-10-21 16:49:52 +02:00
parent a8fda9770c
commit eadb4594f5
25 changed files with 167 additions and 131 deletions

View File

@@ -23,11 +23,10 @@ add_executable(natsukashii
${FRONTEND_SOURCES} ${FRONTEND_SOURCES}
${FRONTEND_HEADERS} ${FRONTEND_HEADERS}
main.cpp main.cpp
Scheduler.cpp
Scheduler.hpp
common.hpp common.hpp
util.hpp util.hpp
) n64/Scheduler.cpp
n64/Scheduler.hpp)
target_include_directories(natsukashii PRIVATE target_include_directories(natsukashii PRIVATE
. .
@@ -65,4 +64,4 @@ file(REMOVE
${PROJECT_BINARY_DIR}/resources/shader.frag ${PROJECT_BINARY_DIR}/resources/shader.frag
${PROJECT_BINARY_DIR}/resources/shader.vert) ${PROJECT_BINARY_DIR}/resources/shader.vert)
target_link_libraries(natsukashii PRIVATE ${LIBRARIES} SDL2 capstone-static nfd parallel-rdp imgui fmt::fmt nlohmann_json::nlohmann_json) target_link_libraries(natsukashii PRIVATE ${LIBRARIES} ${SDL2_LIBRARIES} capstone-static nfd parallel-rdp imgui fmt::fmt nlohmann_json::nlohmann_json)

View File

@@ -1,20 +0,0 @@
#include <Scheduler.hpp>
#include <algorithm>
#include <Mem.hpp>
#include <Registers.hpp>
namespace n64 {
void Scheduler::enqueue(const Event &event) {
events.push_back({event.time + ticks, event.func});
}
void Scheduler::handleEvents(u64 tick, Mem &mem, Registers &regs) {
ticks += tick;
for (int i = 0; i < events.size(); i++) {
if (ticks >= events[i].time) {
events[i].func(mem, regs);
events.erase(events.begin() + i);
}
}
}
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include <vector>
#include <common.hpp>
namespace n64 {
struct Mem;
struct Registers;
struct Event {
u64 time;
void (*func)(Mem&, Registers& regs);
};
enum {
SI_DMA_COMPLETE
};
struct Scheduler {
void enqueue(const Event&);
void handleEvents(u64 tick, Mem& mem, Registers& regs);
u64 ticks = 0;
std::vector<Event> events;
};
}

View File

@@ -1,13 +1,10 @@
#include <App.hpp> #include <App.hpp>
#include <parallel-rdp/ParallelRDPWrapper.hpp>
#include <nfd.hpp> #include <nfd.hpp>
#include "m64.hpp"
void App::Run() { void App::Run() {
// Main loop
const u8* state = SDL_GetKeyboardState(nullptr); const u8* state = SDL_GetKeyboardState(nullptr);
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
static int count = 0;
while (!core.done) { while (!core.done) {
core.Run(window, window.volumeL, window.volumeR); core.Run(window, window.volumeL, window.volumeR);
core.UpdateController(state); core.UpdateController(state);

View File

@@ -3,6 +3,7 @@
#include <Window.hpp> #include <Window.hpp>
#include <algorithm> #include <algorithm>
#include "m64.hpp" #include "m64.hpp"
#include <Scheduler.hpp>
namespace n64 { namespace n64 {
Core::Core() { Core::Core() {
@@ -62,7 +63,7 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
} }
mmio.ai.Step(mem, cpu.regs, 1, volumeL, volumeR); mmio.ai.Step(mem, cpu.regs, 1, volumeL, volumeR);
mem.scheduler.handleEvents(1, mem, cpu.regs); scheduler.tick(1, mem, cpu.regs);
} }
cycles -= mmio.vi.cyclesPerHalfline; cycles -= mmio.vi.cyclesPerHalfline;
@@ -172,9 +173,5 @@ void Core::UpdateController(const u8* state) {
controller.joy_y = 0; controller.joy_y = 0;
} }
} }
if(tas_movie_loaded()) {
controller = tas_next_inputs();
}
} }
} }

23
src/n64/Scheduler.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include <Scheduler.hpp>
#include <Mem.hpp>
#include <Registers.hpp>
Scheduler scheduler;
Scheduler::Scheduler() {
events.push({UINT64_MAX, [](n64::Mem&, n64::Registers&){
util::panic("How the fuck did we get here?!\n");
}});
}
void Scheduler::enqueue(const Event& event) {
events.push({event.time + ticks, event.event_cb});
}
void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
ticks += t;
while(ticks >= events.top().time) {
events.top().event_cb(mem, regs);
events.pop();
}
}

27
src/n64/Scheduler.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <common.hpp>
#include <queue>
namespace n64 {
struct Mem;
struct Registers;
}
struct Event {
u64 time = UINT64_MAX;
void(*event_cb)(n64::Mem&, n64::Registers&);
friend bool operator<(const Event& rhs, const Event& lhs) {
return lhs.time < rhs.time;
}
};
struct Scheduler {
Scheduler();
void enqueue(const Event&);
void tick(u64, n64::Mem&, n64::Registers&);
std::priority_queue<Event> events;
u64 ticks = 0;
};
extern Scheduler scheduler;

View File

@@ -1,6 +1,4 @@
#include <n64/core/Cpu.hpp> #include <n64/core/Cpu.hpp>
#include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/Interrupt.hpp>
#include <util.hpp> #include <util.hpp>
namespace n64 { namespace n64 {

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <Registers.hpp> #include <Registers.hpp>
#include <Mem.hpp> #include <Mem.hpp>
#include <util.hpp>
#include <capstone/capstone.h> #include <capstone/capstone.h>
#include <vector> #include <vector>

View File

@@ -34,7 +34,7 @@ u32 MMIO::Read(u32 addr) {
} }
} }
void MMIO::Write(Scheduler& scheduler, Mem& mem, Registers& regs, u32 addr, u32 val) { void MMIO::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
switch (addr) { switch (addr) {
case 0x04040000 ... 0x040FFFFF: rsp.Write(mem, regs, addr, val); break; case 0x04040000 ... 0x040FFFFF: rsp.Write(mem, regs, addr, val); break;
case 0x04100000 ... 0x041FFFFF: rdp.Write(mi, regs, rsp, addr, val); break; case 0x04100000 ... 0x041FFFFF: rdp.Write(mi, regs, rsp, addr, val); break;
@@ -43,7 +43,7 @@ void MMIO::Write(Scheduler& scheduler, Mem& mem, Registers& regs, u32 addr, u32
case 0x04500000 ... 0x045FFFFF: ai.Write(mem, regs, addr, val); break; case 0x04500000 ... 0x045FFFFF: ai.Write(mem, regs, addr, val); break;
case 0x04600000 ... 0x046FFFFF: pi.Write(mem, regs, addr, val); break; case 0x04600000 ... 0x046FFFFF: pi.Write(mem, regs, addr, val); break;
case 0x04700000 ... 0x047FFFFF: ri.Write(addr, val); break; case 0x04700000 ... 0x047FFFFF: ri.Write(addr, val); break;
case 0x04800000 ... 0x048FFFFF: si.Write(scheduler, mem, regs, addr, val); break; case 0x04800000 ... 0x048FFFFF: si.Write(mem, regs, addr, val); break;
default: default:
util::panic("Unhandled mmio write at addr {:08X} with val {:08X}\n", addr, val); util::panic("Unhandled mmio write at addr {:08X} with val {:08X}\n", addr, val);
} }

View File

@@ -25,6 +25,6 @@ struct MMIO {
RDP rdp; RDP rdp;
u32 Read(u32); u32 Read(u32);
void Write(Scheduler&, Mem&, Registers&, u32, u32); void Write(Mem&, Registers&, u32, u32);
}; };
} }

View File

@@ -87,15 +87,19 @@ u8 Mem::Read8(n64::Registers &regs, u64 vaddr, s64 pc) {
else else
return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE]; return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE];
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: case 0x04600000 ... 0x048FFFFF: case 0x04300000 ... 0x044FFFFF: return 0xff;
return mmio.Read(paddr); case 0x04500000 ... 0x045FFFFF: {
u32 w = mmio.ai.Read(paddr & ~3);
int offs = 3 - (paddr & 3);
return (w >> (offs * 8)) & 0xff;
}
case 0x10000000 ... 0x1FBFFFFF: case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~2; paddr = (paddr + 2) & ~2;
return cart[BYTE_ADDRESS(paddr) & romMask]; return cart[BYTE_ADDRESS(paddr) & romMask];
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00000 ... 0x1FC007BF:
return pifBootrom[BYTE_ADDRESS(paddr) & PIF_BOOTROM_DSIZE]; return pifBootrom[BYTE_ADDRESS(paddr) - 0x1FC00000];
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
return pifRam[paddr & PIF_RAM_DSIZE]; return pifRam[paddr - 0x1FC007C0];
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default: default:
@@ -126,9 +130,9 @@ u16 Mem::Read16(n64::Registers &regs, u64 vaddr, s64 pc) {
paddr = (paddr + 2) & ~3; paddr = (paddr + 2) & ~3;
return util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask); return util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask);
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) & PIF_BOOTROM_DSIZE); return util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
return be16toh(util::ReadAccess<u16>(pifRam, paddr & PIF_RAM_DSIZE)); return be16toh(util::ReadAccess<u16>(pifRam, paddr - 0x1FC007C0));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default: util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc); default: util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
@@ -157,9 +161,9 @@ u32 Mem::Read32(n64::Registers &regs, u64 vaddr, s64 pc) {
case 0x10000000 ... 0x1FBFFFFF: case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u32>(cart.data(), paddr & romMask); return util::ReadAccess<u32>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u32>(pifBootrom, paddr & PIF_BOOTROM_DSIZE); return util::ReadAccess<u32>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
return be32toh(util::ReadAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE)); return be32toh(util::ReadAccess<u32>(pifRam, paddr - 0x1FC007C0));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default: default:
@@ -189,9 +193,9 @@ u64 Mem::Read64(n64::Registers &regs, u64 vaddr, s64 pc) {
case 0x10000000 ... 0x1FBFFFFF: case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u64>(cart.data(), paddr & romMask); return util::ReadAccess<u64>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u64>(pifBootrom, paddr & PIF_BOOTROM_DSIZE); return util::ReadAccess<u64>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
return be64toh(util::ReadAccess<u64>(pifRam, paddr & PIF_RAM_DSIZE)); return be64toh(util::ReadAccess<u64>(pifRam, paddr - 0x1FC007C0));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default: util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc); default: util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
@@ -222,18 +226,18 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
val = val << (8 * (3 - (paddr & 3))); val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr & DMEM_DSIZE) & ~3; paddr = (paddr & DMEM_DSIZE) & ~3;
if((paddr >> 12) & 1) if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break; break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(scheduler, *this, regs, paddr, val); break; case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
case 0x10000000 ... 0x13FFFFFF: break; case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
val = val << (8 * (3 - (paddr & 3))); val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr & PIF_RAM_DSIZE) & ~3; paddr = (paddr - 0x1FC007C0) & ~3;
util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); util::WriteAccess<u32>(pifRam, paddr, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this); ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break; break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
@@ -259,18 +263,18 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
val = val << (16 * !(paddr & 2)); val = val << (16 * !(paddr & 2));
paddr &= ~3; paddr &= ~3;
if((paddr >> 12) & 1) if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break; break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(scheduler, *this, regs, paddr, val); break; case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FFFFFF: break; case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
val = val << (16 * !(paddr & 2)); val = val << (16 * !(paddr & 2));
paddr &= ~3; paddr &= ~3;
util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this); ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break; break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
@@ -293,13 +297,13 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
util::WriteAccess<u32>(mmio.rdp.dram.data(), paddr, val); util::WriteAccess<u32>(mmio.rdp.dram.data(), paddr, val);
break; break;
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1) if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break; break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(scheduler, *this, regs, paddr, val); break; case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FF0013: break; case 0x10000000 ... 0x13FF0013: break;
case 0x13FF0014: { case 0x13FF0014: {
if(val < ISVIEWER_SIZE) { if(val < ISVIEWER_SIZE) {
@@ -313,7 +317,7 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
util::WriteAccess<u32>(isviewer, paddr - 0x13FF0020, htobe32(val)); util::WriteAccess<u32>(isviewer, paddr - 0x13FF0020, htobe32(val));
break; break;
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this); ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break; break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
@@ -337,16 +341,16 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
break; break;
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
val >>= 32; val >>= 32;
if((paddr >> 12) & 1) if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break; break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(scheduler, *this, regs, paddr, val); break; case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FFFFFF: break; case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u64>(pifRam, paddr & PIF_RAM_DSIZE, htobe64(val)); util::WriteAccess<u64>(pifRam, paddr - 0x1FC007C0, htobe64(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this); ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break; break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:

View File

@@ -42,7 +42,6 @@ struct Mem {
MMIO mmio; MMIO mmio;
u8 pifRam[PIF_RAM_SIZE]{}; u8 pifRam[PIF_RAM_SIZE]{};
Scheduler scheduler;
inline void DumpRDRAM() const { inline void DumpRDRAM() const {
FILE *fp = fopen("rdram.dump", "wb"); FILE *fp = fopen("rdram.dump", "wb");
@@ -55,7 +54,7 @@ struct Mem {
} }
inline void DumpIMEM() const { inline void DumpIMEM() const {
FILE *fp = fopen("imem.dump", "wb"); FILE *fp = fopen("imem.bin", "wb");
u8 *temp = (u8*)calloc(IMEM_SIZE, 1); u8 *temp = (u8*)calloc(IMEM_SIZE, 1);
memcpy(temp, mmio.rsp.imem, IMEM_SIZE); memcpy(temp, mmio.rsp.imem, IMEM_SIZE);
util::SwapBuffer32(IMEM_SIZE, temp); util::SwapBuffer32(IMEM_SIZE, temp);

View File

@@ -4,11 +4,11 @@
#include <n64/memory_regions.hpp> #include <n64/memory_regions.hpp>
#include <Interrupt.hpp> #include <Interrupt.hpp>
#define RSP_BYTE(addr, buf) (buf[BYTE_ADDRESS(addr) & 0xFFF]) #define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
#define GET_RSP_HALF(addr, buf) ((RSP_BYTE(addr, buf) << 8) | RSP_BYTE((addr) + 1, buf)) #define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1))
#define SET_RSP_HALF(addr, buf, value) do { RSP_BYTE(addr, buf) = ((value) >> 8) & 0xFF; RSP_BYTE((addr) + 1, buf) = (value) & 0xFF;} while(0) #define SET_RSP_HALF(addr, value) do { RSP_BYTE(addr) = ((value) >> 8) & 0xFF; RSP_BYTE((addr) + 1) = (value) & 0xFF;} while(0)
#define GET_RSP_WORD(addr, buf) ((GET_RSP_HALF(addr, buf) << 16) | GET_RSP_HALF((addr) + 2, buf)) #define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2))
#define SET_RSP_WORD(addr, buf, value) do { SET_RSP_HALF(addr, buf, ((value) >> 16) & 0xFFFF); SET_RSP_HALF((addr) + 2, buf, (value) & 0xFFFF);} while(0) #define SET_RSP_WORD(addr, value) do { SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); SET_RSP_HALF((addr) + 2, (value) & 0xFFFF);} while(0)
namespace n64 { namespace n64 {
union SPStatus { union SPStatus {
@@ -221,32 +221,32 @@ struct RSP {
inline u32 ReadWord(u32 addr) { inline u32 ReadWord(u32 addr) {
addr &= 0xfff; addr &= 0xfff;
return GET_RSP_WORD(addr, dmem); return GET_RSP_WORD(addr);
} }
inline void WriteWord(u32 addr, u32 val) { inline void WriteWord(u32 addr, u32 val) {
addr &= 0xfff; addr &= 0xfff;
SET_RSP_WORD(addr, dmem, val); SET_RSP_WORD(addr, val);
} }
inline u16 ReadHalf(u32 addr) { inline u16 ReadHalf(u32 addr) {
addr &= 0xfff; addr &= 0xfff;
return GET_RSP_HALF(addr, dmem); return GET_RSP_HALF(addr);
} }
inline void WriteHalf(u32 addr, u16 val) { inline void WriteHalf(u32 addr, u16 val) {
addr &= 0xfff; addr &= 0xfff;
SET_RSP_HALF(addr, dmem, val); SET_RSP_HALF(addr, val);
} }
inline u8 ReadByte(u32 addr) { inline u8 ReadByte(u32 addr) {
addr &= 0xfff; addr &= 0xfff;
return RSP_BYTE(addr, dmem); return RSP_BYTE(addr);
} }
inline void WriteByte(u32 addr, u8 val) { inline void WriteByte(u32 addr, u8 val) {
addr &= 0xfff; addr &= 0xfff;
RSP_BYTE(addr, dmem) = val; RSP_BYTE(addr) = val;
} }
inline bool AcquireSemaphore() { inline bool AcquireSemaphore() {
@@ -277,6 +277,7 @@ struct RSP {
void lhu(u32 instr); void lhu(u32 instr);
void lui(u32 instr); void lui(u32 instr);
void luv(u32 instr); void luv(u32 instr);
void lbv(u32 instr);
void ldv(u32 instr); void ldv(u32 instr);
void lsv(u32 instr); void lsv(u32 instr);
void llv(u32 instr); void llv(u32 instr);

View File

@@ -204,24 +204,24 @@ bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr,
u32 pfn; u32 pfn;
if(!odd) { if(!odd) {
if(!(entry->entryLo0.v)) { if(!entry->entryLo0.v) {
regs.cop0.tlbError = INVALID; regs.cop0.tlbError = INVALID;
return false; return false;
} }
if(access_type == STORE && !(entry->entryLo0.d)) { if(access_type == STORE && !entry->entryLo0.d) {
regs.cop0.tlbError = MODIFICATION; regs.cop0.tlbError = MODIFICATION;
return false; return false;
} }
pfn = entry->entryLo0.pfn; pfn = entry->entryLo0.pfn;
} else { } else {
if(!(entry->entryLo1.v)) { if(!entry->entryLo1.v) {
regs.cop0.tlbError = INVALID; regs.cop0.tlbError = INVALID;
return false; return false;
} }
if(access_type == STORE && !(entry->entryLo1.d)) { if(access_type == STORE && !entry->entryLo1.d) {
regs.cop0.tlbError = MODIFICATION; regs.cop0.tlbError = MODIFICATION;
return false; return false;
} }
@@ -327,7 +327,8 @@ void Cop0::decode(Registers& regs, Mem& mem, u32 instr) {
case 0x10 ... 0x1F: case 0x10 ... 0x1F:
switch(mask_cop2) { switch(mask_cop2) {
case 0x01: tlbr(regs); break; case 0x01: tlbr(regs); break;
case 0x02: tlbwi(regs); break; case 0x02: tlbw(index & 0x3F, regs); break;
case 0x06: tlbw(GetRandom(), regs); break;
case 0x08: tlbp(regs); break; case 0x08: tlbp(regs); break;
case 0x18: eret(regs); break; case 0x18: eret(regs); break;
default: util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC); default: util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);

View File

@@ -261,7 +261,7 @@ private:
void eret(Registers&); void eret(Registers&);
void tlbr(Registers&); void tlbr(Registers&);
void tlbwi(Registers&); void tlbw(int, Registers&);
void tlbp(Registers&); void tlbp(Registers&);
}; };

View File

@@ -32,7 +32,7 @@ void Cop0::eret(Registers& regs) {
void Cop0::tlbr(Registers& regs) { void Cop0::tlbr(Registers& regs) {
int Index = index & 0b111111; u8 Index = index & 0b111111;
if (Index >= 32) { if (Index >= 32) {
util::panic("TLBR with TLB index {}", index); util::panic("TLBR with TLB index {}", index);
} }
@@ -48,26 +48,25 @@ void Cop0::tlbr(Registers& regs) {
pageMask.raw = entry.pageMask.raw; pageMask.raw = entry.pageMask.raw;
} }
void Cop0::tlbwi(Registers& regs) { void Cop0::tlbw(int index_, Registers& regs) {
PageMask page_mask; PageMask page_mask{};
page_mask = pageMask; page_mask = pageMask;
u32 top = page_mask.mask & 0xAAA; u32 top = page_mask.mask & 0xAAA;
page_mask.mask = top | (top >> 1); page_mask.mask = top | (top >> 1);
int Index = index & 0x3F; if(index_ >= 32) {
if(Index >= 32) { util::panic("TLBWI with TLB index {}", index_);
util::panic("TLBWI with TLB index {}", Index);
} }
tlb[Index].entryHi.raw = entryHi.raw; tlb[index_].entryHi.raw = entryHi.raw;
tlb[Index].entryHi.vpn2 &= ~page_mask.mask; tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
tlb[Index].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE;
tlb[Index].entryLo1.raw = entryLo1.raw & 0x03FFFFFE; tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE;
tlb[Index].pageMask.raw = page_mask.raw; tlb[index_].pageMask.raw = page_mask.raw;
tlb[Index].global = entryLo0.g && entryLo1.g; tlb[index_].global = entryLo0.g && entryLo1.g;
tlb[Index].initialized = true; tlb[index_].initialized = true;
} }
void Cop0::tlbp(Registers& regs) { void Cop0::tlbp(Registers& regs) {

View File

@@ -13,7 +13,6 @@ void PI::Reset() {
cartAddr = 0; cartAddr = 0;
rdLen = 0; rdLen = 0;
wrLen = 0; wrLen = 0;
status = 0;
memset(stub, 0, 8); memset(stub, 0, 8);
} }
@@ -25,8 +24,8 @@ auto PI::Read(MI& mi, u32 addr) const -> u32 {
case 0x0460000C: return wrLen; case 0x0460000C: return wrLen;
case 0x04600010: { case 0x04600010: {
u32 value = 0; u32 value = 0;
value |= (status & 1); // Is PI DMA active? value |= (0 << 0); // Is PI DMA active? No, because it's instant
value |= (0 << 1); // Is PI IO busy? value |= (0 << 1); // Is PI IO busy? No, because it's instant
value |= (0 << 2); // PI IO error? value |= (0 << 2); // PI IO error?
value |= (mi.miIntr.pi << 3); // PI interrupt? value |= (mi.miIntr.pi << 3); // PI interrupt?
return value; return value;
@@ -74,7 +73,6 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
dramAddr = dram_addr + len; dramAddr = dram_addr + len;
cartAddr = cart_addr + len; cartAddr = cart_addr + len;
InterruptRaise(mi, regs, Interrupt::PI); InterruptRaise(mi, regs, Interrupt::PI);
status &= 0xFFFFFFFE;
util::logdebug("PI DMA from CARTRIDGE to RDRAM (size: {} KiB, {:08X} to {:08X})\n", len, cart_addr, dram_addr); util::logdebug("PI DMA from CARTRIDGE to RDRAM (size: {} KiB, {:08X} to {:08X})\n", len, cart_addr, dram_addr);
} break; } break;
case 0x04600010: case 0x04600010:

View File

@@ -14,7 +14,6 @@ struct PI {
void Write(Mem&, Registers&, u32, u32); void Write(Mem&, Registers&, u32, u32);
u32 dramAddr{}, cartAddr{}; u32 dramAddr{}, cartAddr{};
u32 rdLen{}, wrLen{}; u32 rdLen{}, wrLen{};
u32 status{};
u32 stub[8]{}; u32 stub[8]{};
}; };
} }

View File

@@ -44,6 +44,9 @@ void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) {
res[2] = 0x01; res[2] = 0x01;
break; break;
case 1: case 1:
if(tas_movie_loaded()) {
controller = tas_next_inputs();
}
res[0] = controller.byte1; res[0] = controller.byte1;
res[1] = controller.byte2; res[1] = controller.byte2;
res[2] = controller.joy_x; res[2] = controller.joy_x;

View File

@@ -1,5 +1,6 @@
#include <n64/core/mmio/SI.hpp> #include <n64/core/mmio/SI.hpp>
#include <n64/core/Mem.hpp> #include <n64/core/Mem.hpp>
#include "Scheduler.hpp"
namespace n64 { namespace n64 {
SI::SI() { SI::SI() {
@@ -33,6 +34,9 @@ void DMA(Mem& mem, Registers& regs) {
MMIO& mmio = mem.mmio; MMIO& mmio = mem.mmio;
SI& si = mmio.si; SI& si = mmio.si;
si.status.dmaBusy = false; si.status.dmaBusy = false;
if(si.status.dmaBusy) {
return;
}
if(si.toDram) { if(si.toDram) {
ProcessPIFCommands(mem.pifRam, si.controller, mem); ProcessPIFCommands(mem.pifRam, si.controller, mem);
for(int i = 0; i < 64; i++) { for(int i = 0; i < 64; i++) {
@@ -47,7 +51,7 @@ void DMA(Mem& mem, Registers& regs) {
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
} }
void SI::Write(Scheduler& scheduler, Mem& mem, Registers& regs, u32 addr, u32 val) { void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
switch(addr) { switch(addr) {
case 0x04800000: case 0x04800000:
dramAddr = val & RDRAM_DSIZE; dramAddr = val & RDRAM_DSIZE;

View File

@@ -3,7 +3,6 @@
#include <n64/core/mmio/Interrupt.hpp> #include <n64/core/mmio/Interrupt.hpp>
#include <n64/core/mmio/MI.hpp> #include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/PIF.hpp> #include <n64/core/mmio/PIF.hpp>
#include <Scheduler.hpp>
namespace n64 { namespace n64 {
@@ -31,7 +30,7 @@ struct SI {
bool toDram = false; bool toDram = false;
auto Read(MI&, u32) const -> u32; auto Read(MI&, u32) const -> u32;
void Write(Scheduler& scheduler, Mem&, Registers&, u32, u32); void Write(Mem&, Registers&, u32, u32);
}; };
static void DMA(Mem& mem, Registers& regs); static void DMA(Mem& mem, Registers& regs);

View File

@@ -61,6 +61,7 @@ inline void lwc2(RSP& rsp, u32 instr) {
u8 mask = (instr >> 11) & 0x1F; u8 mask = (instr >> 11) & 0x1F;
//util::print("lwc2 {:02X}\n", mask); //util::print("lwc2 {:02X}\n", mask);
switch(mask) { switch(mask) {
case 0x00: rsp.lbv(instr); break;
case 0x01: rsp.lsv(instr); break; case 0x01: rsp.lsv(instr); break;
case 0x02: rsp.llv(instr); break; case 0x02: rsp.llv(instr); break;
case 0x03: rsp.ldv(instr); break; case 0x03: rsp.ldv(instr); break;
@@ -206,7 +207,15 @@ void RSP::Exec(Registers &regs, Mem& mem, u32 instr) {
case 0x2B: sw(instr); break; case 0x2B: sw(instr); break;
case 0x32: lwc2(*this, instr); break; case 0x32: lwc2(*this, instr); break;
case 0x3A: swc2(*this, instr); break; case 0x3A: swc2(*this, instr); break;
default: util::panic("Unhandled RSP instruction ({:06b})\n", mask); default:
FILE *fp = fopen("imem.bin", "wb");
u8 *temp = (u8*)calloc(IMEM_SIZE, 1);
memcpy(temp, imem, IMEM_SIZE);
util::SwapBuffer32(IMEM_SIZE, temp);
fwrite(temp, 1, IMEM_SIZE, fp);
free(temp);
fclose(fp);
util::panic("Unhandled RSP instruction ({:06b})\n", mask);
} }
} }
} }

View File

@@ -297,6 +297,11 @@ void RSP::lsv(u32 instr) {
} }
} }
void RSP::lbv(u32 instr) {
u32 address = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 0);
vpr[VT(instr)].byte[BYTE_INDEX(E1(instr))] = ReadByte(address);
}
void RSP::llv(u32 instr) { void RSP::llv(u32 instr) {
int e = E1(instr); int e = E1(instr);
u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 2); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 2);
@@ -362,7 +367,8 @@ void RSP::sb(u32 instr) {
} }
void RSP::sh(u32 instr) { void RSP::sh(u32 instr) {
u32 address = gpr[BASE(instr)] + (s16)instr; s16 imm = s16(instr);
u32 address = gpr[RS(instr)] + imm;
WriteHalf(address, gpr[RT(instr)]); WriteHalf(address, gpr[RT(instr)]);
} }

View File

@@ -119,6 +119,25 @@ bool tas_movie_loaded() {
return loaded_tas_movie != nullptr; return loaded_tas_movie != nullptr;
} }
inline void LogController(const n64::Controller& controller) {
util::print("c_right: {}\n", controller.c_right);
util::print("c_left: {}\n", controller.c_left);
util::print("c_down: {}\n", controller.c_down);
util::print("c_up: {}\n", controller.c_up);
util::print("r: {}\n", controller.r);
util::print("l: {}\n", controller.l);
util::print("dp_right: {}\n", controller.dp_right);
util::print("dp_left: {}\n", controller.dp_left);
util::print("dp_down: {}\n", controller.dp_down);
util::print("dp_up: {}\n", controller.dp_up);
util::print("z: {}\n", controller.z);
util::print("b: {}\n", controller.b);
util::print("a: {}\n", controller.a);
util::print("start: {}\n", controller.start);
util::print("joy_x: {}\n", controller.joy_x);
util::print("joy_y: {}\n\n", controller.joy_y);
}
n64::Controller tas_next_inputs() { n64::Controller tas_next_inputs() {
if (loaded_tas_movie_index + sizeof(TASMovieControllerData) > loaded_tas_movie_size) { if (loaded_tas_movie_index + sizeof(TASMovieControllerData) > loaded_tas_movie_size) {
loaded_tas_movie = nullptr; loaded_tas_movie = nullptr;
@@ -150,13 +169,12 @@ n64::Controller tas_next_inputs() {
controller.z = movie_cdata.z; controller.z = movie_cdata.z;
controller.b = movie_cdata.b; controller.b = movie_cdata.b;
controller.a = movie_cdata.a; controller.a = movie_cdata.a;
if(movie_cdata.start) {
printf("\n");
}
controller.start = movie_cdata.start; controller.start = movie_cdata.start;
controller.joy_x = movie_cdata.analog_x; controller.joy_x = movie_cdata.analog_x;
controller.joy_y = movie_cdata.analog_y; controller.joy_y = movie_cdata.analog_y;
//LogController(controller);
return controller; return controller;
} }