TLBWR + Scheduler (SI DMA delay)
This commit is contained in:
@@ -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)
|
||||||
@@ -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 ®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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
23
src/n64/Scheduler.cpp
Normal 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
27
src/n64/Scheduler.hpp
Normal 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;
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,15 +87,19 @@ u8 Mem::Read8(n64::Registers ®s, 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 ®s, 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 ®s, 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 ®s, 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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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]{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 ®s, 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user