diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7866255..78b1b1d8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,11 +23,10 @@ add_executable(natsukashii ${FRONTEND_SOURCES} ${FRONTEND_HEADERS} main.cpp - Scheduler.cpp - Scheduler.hpp common.hpp util.hpp -) + n64/Scheduler.cpp + n64/Scheduler.hpp) target_include_directories(natsukashii PRIVATE . @@ -65,4 +64,4 @@ file(REMOVE ${PROJECT_BINARY_DIR}/resources/shader.frag ${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) \ No newline at end of file +target_link_libraries(natsukashii PRIVATE ${LIBRARIES} ${SDL2_LIBRARIES} capstone-static nfd parallel-rdp imgui fmt::fmt nlohmann_json::nlohmann_json) \ No newline at end of file diff --git a/src/Scheduler.cpp b/src/Scheduler.cpp deleted file mode 100644 index 4f53e42a..00000000 --- a/src/Scheduler.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include -#include - -namespace n64 { -void Scheduler::enqueue(const Event &event) { - events.push_back({event.time + ticks, event.func}); -} - -void Scheduler::handleEvents(u64 tick, Mem &mem, Registers ®s) { - 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); - } - } -} -} \ No newline at end of file diff --git a/src/Scheduler.hpp b/src/Scheduler.hpp deleted file mode 100644 index 89bf7aac..00000000 --- a/src/Scheduler.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include -#include - -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 events; -}; -} diff --git a/src/frontend/App.cpp b/src/frontend/App.cpp index 988521f1..45014c5b 100644 --- a/src/frontend/App.cpp +++ b/src/frontend/App.cpp @@ -1,13 +1,10 @@ #include -#include #include -#include "m64.hpp" void App::Run() { - // Main loop const u8* state = SDL_GetKeyboardState(nullptr); SDL_EventState(SDL_DROPFILE, SDL_ENABLE); - static int count = 0; + while (!core.done) { core.Run(window, window.volumeL, window.volumeR); core.UpdateController(state); diff --git a/src/n64/Core.cpp b/src/n64/Core.cpp index 35a8bb7f..a88949dc 100644 --- a/src/n64/Core.cpp +++ b/src/n64/Core.cpp @@ -3,6 +3,7 @@ #include #include #include "m64.hpp" +#include namespace n64 { Core::Core() { @@ -62,7 +63,7 @@ void Core::Run(Window& window, float volumeL, float 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; @@ -172,9 +173,5 @@ void Core::UpdateController(const u8* state) { controller.joy_y = 0; } } - - if(tas_movie_loaded()) { - controller = tas_next_inputs(); - } } } diff --git a/src/n64/Scheduler.cpp b/src/n64/Scheduler.cpp new file mode 100644 index 00000000..f33e8a05 --- /dev/null +++ b/src/n64/Scheduler.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +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(); + } +} diff --git a/src/n64/Scheduler.hpp b/src/n64/Scheduler.hpp new file mode 100644 index 00000000..2107e21d --- /dev/null +++ b/src/n64/Scheduler.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +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 events; + u64 ticks = 0; +}; + +extern Scheduler scheduler; \ No newline at end of file diff --git a/src/n64/core/Cpu.cpp b/src/n64/core/Cpu.cpp index a18cb247..8aebfc7f 100644 --- a/src/n64/core/Cpu.cpp +++ b/src/n64/core/Cpu.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include namespace n64 { diff --git a/src/n64/core/Cpu.hpp b/src/n64/core/Cpu.hpp index cf947175..134034c7 100644 --- a/src/n64/core/Cpu.hpp +++ b/src/n64/core/Cpu.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include #include #include diff --git a/src/n64/core/MMIO.cpp b/src/n64/core/MMIO.cpp index 9ebbc9b2..2563e0e8 100644 --- a/src/n64/core/MMIO.cpp +++ b/src/n64/core/MMIO.cpp @@ -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) { case 0x04040000 ... 0x040FFFFF: rsp.Write(mem, regs, 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 0x04600000 ... 0x046FFFFF: pi.Write(mem, regs, 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: util::panic("Unhandled mmio write at addr {:08X} with val {:08X}\n", addr, val); } diff --git a/src/n64/core/MMIO.hpp b/src/n64/core/MMIO.hpp index c8d20dbf..f102b324 100644 --- a/src/n64/core/MMIO.hpp +++ b/src/n64/core/MMIO.hpp @@ -25,6 +25,6 @@ struct MMIO { RDP rdp; u32 Read(u32); - void Write(Scheduler&, Mem&, Registers&, u32, u32); + void Write(Mem&, Registers&, u32, u32); }; } diff --git a/src/n64/core/Mem.cpp b/src/n64/core/Mem.cpp index e213afef..d0ce0f44 100644 --- a/src/n64/core/Mem.cpp +++ b/src/n64/core/Mem.cpp @@ -87,15 +87,19 @@ u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) { else return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE]; case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: - case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: - return mmio.Read(paddr); + case 0x04600000 ... 0x048FFFFF: case 0x04300000 ... 0x044FFFFF: return 0xff; + case 0x04500000 ... 0x045FFFFF: { + u32 w = mmio.ai.Read(paddr & ~3); + int offs = 3 - (paddr & 3); + return (w >> (offs * 8)) & 0xff; + } case 0x10000000 ... 0x1FBFFFFF: paddr = (paddr + 2) & ~2; return cart[BYTE_ADDRESS(paddr) & romMask]; case 0x1FC00000 ... 0x1FC007BF: - return pifBootrom[BYTE_ADDRESS(paddr) & PIF_BOOTROM_DSIZE]; + return pifBootrom[BYTE_ADDRESS(paddr) - 0x1FC00000]; case 0x1FC007C0 ... 0x1FC007FF: - return pifRam[paddr & PIF_RAM_DSIZE]; + return pifRam[paddr - 0x1FC007C0]; case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; default: @@ -126,9 +130,9 @@ u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) { paddr = (paddr + 2) & ~3; return util::ReadAccess(cart.data(), HALF_ADDRESS(paddr) & romMask); case 0x1FC00000 ... 0x1FC007BF: - return util::ReadAccess(pifBootrom, HALF_ADDRESS(paddr) & PIF_BOOTROM_DSIZE); + return util::ReadAccess(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000); case 0x1FC007C0 ... 0x1FC007FF: - return be16toh(util::ReadAccess(pifRam, paddr & PIF_RAM_DSIZE)); + return be16toh(util::ReadAccess(pifRam, paddr - 0x1FC007C0)); case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: 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); @@ -157,9 +161,9 @@ u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc) { case 0x10000000 ... 0x1FBFFFFF: return util::ReadAccess(cart.data(), paddr & romMask); case 0x1FC00000 ... 0x1FC007BF: - return util::ReadAccess(pifBootrom, paddr & PIF_BOOTROM_DSIZE); + return util::ReadAccess(pifBootrom, paddr - 0x1FC00000); case 0x1FC007C0 ... 0x1FC007FF: - return be32toh(util::ReadAccess(pifRam, paddr & PIF_RAM_DSIZE)); + return be32toh(util::ReadAccess(pifRam, paddr - 0x1FC007C0)); case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0; default: @@ -189,9 +193,9 @@ u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc) { case 0x10000000 ... 0x1FBFFFFF: return util::ReadAccess(cart.data(), paddr & romMask); case 0x1FC00000 ... 0x1FC007BF: - return util::ReadAccess(pifBootrom, paddr & PIF_BOOTROM_DSIZE); + return util::ReadAccess(pifBootrom, paddr - 0x1FC00000); case 0x1FC007C0 ... 0x1FC007FF: - return be64toh(util::ReadAccess(pifRam, paddr & PIF_RAM_DSIZE)); + return be64toh(util::ReadAccess(pifRam, paddr - 0x1FC007C0)); case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: 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); @@ -222,18 +226,18 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { case 0x04000000 ... 0x0403FFFF: val = val << (8 * (3 - (paddr & 3))); paddr = (paddr & DMEM_DSIZE) & ~3; - if((paddr >> 12) & 1) + if(paddr & 0x1000) util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else util::WriteAccess(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; 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 0x1FC007C0 ... 0x1FC007FF: val = val << (8 * (3 - (paddr & 3))); - paddr = (paddr & PIF_RAM_DSIZE) & ~3; - util::WriteAccess(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); + paddr = (paddr - 0x1FC007C0) & ~3; + util::WriteAccess(pifRam, paddr, htobe32(val)); ProcessPIFCommands(pifRam, mmio.si.controller, *this); break; case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: @@ -259,18 +263,18 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { case 0x04000000 ... 0x0403FFFF: val = val << (16 * !(paddr & 2)); paddr &= ~3; - if((paddr >> 12) & 1) + if(paddr & 0x1000) util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else util::WriteAccess(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; 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 0x1FC007C0 ... 0x1FC007FF: val = val << (16 * !(paddr & 2)); paddr &= ~3; - util::WriteAccess(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); + util::WriteAccess(pifRam, paddr - 0x1FC007C0, htobe32(val)); ProcessPIFCommands(pifRam, mmio.si.controller, *this); break; case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: @@ -293,13 +297,13 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) { util::WriteAccess(mmio.rdp.dram.data(), paddr, val); break; case 0x04000000 ... 0x0403FFFF: - if((paddr >> 12) & 1) + if(paddr & 0x1000) util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else util::WriteAccess(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; 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 0x13FF0014: { if(val < ISVIEWER_SIZE) { @@ -313,7 +317,7 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) { util::WriteAccess(isviewer, paddr - 0x13FF0020, htobe32(val)); break; case 0x1FC007C0 ... 0x1FC007FF: - util::WriteAccess(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val)); + util::WriteAccess(pifRam, paddr - 0x1FC007C0, htobe32(val)); ProcessPIFCommands(pifRam, mmio.si.controller, *this); break; case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: @@ -337,16 +341,16 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { break; case 0x04000000 ... 0x0403FFFF: val >>= 32; - if((paddr >> 12) & 1) + if(paddr & 0x1000) util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else util::WriteAccess(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; 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 0x1FC007C0 ... 0x1FC007FF: - util::WriteAccess(pifRam, paddr & PIF_RAM_DSIZE, htobe64(val)); + util::WriteAccess(pifRam, paddr - 0x1FC007C0, htobe64(val)); ProcessPIFCommands(pifRam, mmio.si.controller, *this); break; case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: diff --git a/src/n64/core/Mem.hpp b/src/n64/core/Mem.hpp index ded7039b..bc0885ee 100644 --- a/src/n64/core/Mem.hpp +++ b/src/n64/core/Mem.hpp @@ -42,7 +42,6 @@ struct Mem { MMIO mmio; u8 pifRam[PIF_RAM_SIZE]{}; - Scheduler scheduler; inline void DumpRDRAM() const { FILE *fp = fopen("rdram.dump", "wb"); @@ -55,7 +54,7 @@ struct Mem { } inline void DumpIMEM() const { - FILE *fp = fopen("imem.dump", "wb"); + FILE *fp = fopen("imem.bin", "wb"); u8 *temp = (u8*)calloc(IMEM_SIZE, 1); memcpy(temp, mmio.rsp.imem, IMEM_SIZE); util::SwapBuffer32(IMEM_SIZE, temp); diff --git a/src/n64/core/RSP.hpp b/src/n64/core/RSP.hpp index ccf1b790..37321f2a 100644 --- a/src/n64/core/RSP.hpp +++ b/src/n64/core/RSP.hpp @@ -4,11 +4,11 @@ #include #include -#define RSP_BYTE(addr, buf) (buf[BYTE_ADDRESS(addr) & 0xFFF]) -#define GET_RSP_HALF(addr, buf) ((RSP_BYTE(addr, buf) << 8) | RSP_BYTE((addr) + 1, buf)) -#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 GET_RSP_WORD(addr, buf) ((GET_RSP_HALF(addr, buf) << 16) | GET_RSP_HALF((addr) + 2, buf)) -#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 RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF]) +#define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) +#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) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2)) +#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 { union SPStatus { @@ -221,32 +221,32 @@ struct RSP { inline u32 ReadWord(u32 addr) { addr &= 0xfff; - return GET_RSP_WORD(addr, dmem); + return GET_RSP_WORD(addr); } inline void WriteWord(u32 addr, u32 val) { addr &= 0xfff; - SET_RSP_WORD(addr, dmem, val); + SET_RSP_WORD(addr, val); } inline u16 ReadHalf(u32 addr) { addr &= 0xfff; - return GET_RSP_HALF(addr, dmem); + return GET_RSP_HALF(addr); } inline void WriteHalf(u32 addr, u16 val) { addr &= 0xfff; - SET_RSP_HALF(addr, dmem, val); + SET_RSP_HALF(addr, val); } inline u8 ReadByte(u32 addr) { addr &= 0xfff; - return RSP_BYTE(addr, dmem); + return RSP_BYTE(addr); } inline void WriteByte(u32 addr, u8 val) { addr &= 0xfff; - RSP_BYTE(addr, dmem) = val; + RSP_BYTE(addr) = val; } inline bool AcquireSemaphore() { @@ -277,6 +277,7 @@ struct RSP { void lhu(u32 instr); void lui(u32 instr); void luv(u32 instr); + void lbv(u32 instr); void ldv(u32 instr); void lsv(u32 instr); void llv(u32 instr); diff --git a/src/n64/core/cpu/registers/Cop0.cpp b/src/n64/core/cpu/registers/Cop0.cpp index 3ad79ba3..b5c08f76 100644 --- a/src/n64/core/cpu/registers/Cop0.cpp +++ b/src/n64/core/cpu/registers/Cop0.cpp @@ -204,24 +204,24 @@ bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr, u32 pfn; if(!odd) { - if(!(entry->entryLo0.v)) { + if(!entry->entryLo0.v) { regs.cop0.tlbError = INVALID; return false; } - if(access_type == STORE && !(entry->entryLo0.d)) { + if(access_type == STORE && !entry->entryLo0.d) { regs.cop0.tlbError = MODIFICATION; return false; } pfn = entry->entryLo0.pfn; } else { - if(!(entry->entryLo1.v)) { + if(!entry->entryLo1.v) { regs.cop0.tlbError = INVALID; return false; } - if(access_type == STORE && !(entry->entryLo1.d)) { + if(access_type == STORE && !entry->entryLo1.d) { regs.cop0.tlbError = MODIFICATION; return false; } @@ -327,7 +327,8 @@ void Cop0::decode(Registers& regs, Mem& mem, u32 instr) { case 0x10 ... 0x1F: switch(mask_cop2) { 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 0x18: eret(regs); break; default: util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC); diff --git a/src/n64/core/cpu/registers/Cop0.hpp b/src/n64/core/cpu/registers/Cop0.hpp index 7c400e46..210492b8 100644 --- a/src/n64/core/cpu/registers/Cop0.hpp +++ b/src/n64/core/cpu/registers/Cop0.hpp @@ -261,7 +261,7 @@ private: void eret(Registers&); void tlbr(Registers&); - void tlbwi(Registers&); + void tlbw(int, Registers&); void tlbp(Registers&); }; diff --git a/src/n64/core/cpu/registers/cop0instructions.cpp b/src/n64/core/cpu/registers/cop0instructions.cpp index 60360e7e..0938ff33 100644 --- a/src/n64/core/cpu/registers/cop0instructions.cpp +++ b/src/n64/core/cpu/registers/cop0instructions.cpp @@ -32,7 +32,7 @@ void Cop0::eret(Registers& regs) { void Cop0::tlbr(Registers& regs) { - int Index = index & 0b111111; + u8 Index = index & 0b111111; if (Index >= 32) { util::panic("TLBR with TLB index {}", index); } @@ -48,26 +48,25 @@ void Cop0::tlbr(Registers& regs) { pageMask.raw = entry.pageMask.raw; } -void Cop0::tlbwi(Registers& regs) { - PageMask page_mask; +void Cop0::tlbw(int index_, Registers& regs) { + PageMask page_mask{}; page_mask = pageMask; u32 top = page_mask.mask & 0xAAA; page_mask.mask = top | (top >> 1); - int Index = index & 0x3F; - if(Index >= 32) { - util::panic("TLBWI with TLB index {}", Index); + if(index_ >= 32) { + util::panic("TLBWI with TLB index {}", index_); } - tlb[Index].entryHi.raw = entryHi.raw; - tlb[Index].entryHi.vpn2 &= ~page_mask.mask; + tlb[index_].entryHi.raw = entryHi.raw; + tlb[index_].entryHi.vpn2 &= ~page_mask.mask; - tlb[Index].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; - tlb[Index].entryLo1.raw = entryLo1.raw & 0x03FFFFFE; - tlb[Index].pageMask.raw = page_mask.raw; + tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; + tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE; + tlb[index_].pageMask.raw = page_mask.raw; - tlb[Index].global = entryLo0.g && entryLo1.g; - tlb[Index].initialized = true; + tlb[index_].global = entryLo0.g && entryLo1.g; + tlb[index_].initialized = true; } void Cop0::tlbp(Registers& regs) { diff --git a/src/n64/core/mmio/PI.cpp b/src/n64/core/mmio/PI.cpp index e2753d7f..69582246 100644 --- a/src/n64/core/mmio/PI.cpp +++ b/src/n64/core/mmio/PI.cpp @@ -13,7 +13,6 @@ void PI::Reset() { cartAddr = 0; rdLen = 0; wrLen = 0; - status = 0; memset(stub, 0, 8); } @@ -25,8 +24,8 @@ auto PI::Read(MI& mi, u32 addr) const -> u32 { case 0x0460000C: return wrLen; case 0x04600010: { u32 value = 0; - value |= (status & 1); // Is PI DMA active? - value |= (0 << 1); // Is PI IO busy? + value |= (0 << 0); // Is PI DMA active? No, because it's instant + value |= (0 << 1); // Is PI IO busy? No, because it's instant value |= (0 << 2); // PI IO error? value |= (mi.miIntr.pi << 3); // PI interrupt? return value; @@ -74,7 +73,6 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { dramAddr = dram_addr + len; cartAddr = cart_addr + len; 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); } break; case 0x04600010: diff --git a/src/n64/core/mmio/PI.hpp b/src/n64/core/mmio/PI.hpp index 49ac8617..969b9c4a 100644 --- a/src/n64/core/mmio/PI.hpp +++ b/src/n64/core/mmio/PI.hpp @@ -14,7 +14,6 @@ struct PI { void Write(Mem&, Registers&, u32, u32); u32 dramAddr{}, cartAddr{}; u32 rdLen{}, wrLen{}; - u32 status{}; u32 stub[8]{}; }; } \ No newline at end of file diff --git a/src/n64/core/mmio/PIF.cpp b/src/n64/core/mmio/PIF.cpp index 668ba9b5..5c4fe983 100644 --- a/src/n64/core/mmio/PIF.cpp +++ b/src/n64/core/mmio/PIF.cpp @@ -44,6 +44,9 @@ void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) { res[2] = 0x01; break; case 1: + if(tas_movie_loaded()) { + controller = tas_next_inputs(); + } res[0] = controller.byte1; res[1] = controller.byte2; res[2] = controller.joy_x; diff --git a/src/n64/core/mmio/SI.cpp b/src/n64/core/mmio/SI.cpp index a0074f66..5b9b935d 100644 --- a/src/n64/core/mmio/SI.cpp +++ b/src/n64/core/mmio/SI.cpp @@ -1,5 +1,6 @@ #include #include +#include "Scheduler.hpp" namespace n64 { SI::SI() { @@ -33,6 +34,9 @@ void DMA(Mem& mem, Registers& regs) { MMIO& mmio = mem.mmio; SI& si = mmio.si; si.status.dmaBusy = false; + if(si.status.dmaBusy) { + return; + } if(si.toDram) { ProcessPIFCommands(mem.pifRam, si.controller, mem); for(int i = 0; i < 64; i++) { @@ -47,7 +51,7 @@ void DMA(Mem& mem, Registers& regs) { 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) { case 0x04800000: dramAddr = val & RDRAM_DSIZE; diff --git a/src/n64/core/mmio/SI.hpp b/src/n64/core/mmio/SI.hpp index 6194d15b..24546e7b 100644 --- a/src/n64/core/mmio/SI.hpp +++ b/src/n64/core/mmio/SI.hpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace n64 { @@ -31,7 +30,7 @@ struct SI { bool toDram = false; 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); diff --git a/src/n64/core/rsp/decode.cpp b/src/n64/core/rsp/decode.cpp index 6518baf9..af539901 100644 --- a/src/n64/core/rsp/decode.cpp +++ b/src/n64/core/rsp/decode.cpp @@ -61,6 +61,7 @@ inline void lwc2(RSP& rsp, u32 instr) { u8 mask = (instr >> 11) & 0x1F; //util::print("lwc2 {:02X}\n", mask); switch(mask) { + case 0x00: rsp.lbv(instr); break; case 0x01: rsp.lsv(instr); break; case 0x02: rsp.llv(instr); break; case 0x03: rsp.ldv(instr); break; @@ -206,7 +207,15 @@ void RSP::Exec(Registers ®s, Mem& mem, u32 instr) { case 0x2B: sw(instr); break; case 0x32: lwc2(*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); } } } \ No newline at end of file diff --git a/src/n64/core/rsp/instructions.cpp b/src/n64/core/rsp/instructions.cpp index 2589aeb0..ab46f004 100644 --- a/src/n64/core/rsp/instructions.cpp +++ b/src/n64/core/rsp/instructions.cpp @@ -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) { int e = E1(instr); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 2); @@ -362,7 +367,8 @@ void RSP::sb(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)]); } diff --git a/src/n64/m64.cpp b/src/n64/m64.cpp index b3e59fac..baaca584 100644 --- a/src/n64/m64.cpp +++ b/src/n64/m64.cpp @@ -119,6 +119,25 @@ bool tas_movie_loaded() { 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() { if (loaded_tas_movie_index + sizeof(TASMovieControllerData) > loaded_tas_movie_size) { loaded_tas_movie = nullptr; @@ -150,13 +169,12 @@ n64::Controller tas_next_inputs() { controller.z = movie_cdata.z; controller.b = movie_cdata.b; controller.a = movie_cdata.a; - if(movie_cdata.start) { - printf("\n"); - } controller.start = movie_cdata.start; controller.joy_x = movie_cdata.analog_x; controller.joy_y = movie_cdata.analog_y; + //LogController(controller); + return controller; } \ No newline at end of file