Merge branch 'master' into dynarec

# Conflicts:
#	.github/workflows/build.yml
#	src/CMakeLists.txt
#	src/frontend/imgui/Window.cpp
#	src/n64/Core.cpp
#	src/n64/core/interpreter/cop/cop1instructions.cpp
#	src/n64/core/interpreter/decode.cpp
#	src/n64/core/registers/Cop1.cpp
This commit is contained in:
CocoSimone
2022-12-16 23:23:27 +01:00
267 changed files with 50552 additions and 281 deletions

View File

@@ -13,10 +13,15 @@ find_package(fmt REQUIRED)
find_package(SDL2 REQUIRED)
find_package(nlohmann_json REQUIRED)
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF)
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF)
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF)
add_subdirectory(../external/capstone capstone)
add_subdirectory(../external/parallel-rdp prdp)
add_subdirectory(../external/imgui imgui)
add_subdirectory(../external/nativefiledialog-extended nfd)
add_subdirectory(../external/discord-rpc discord-rpc)
add_executable(gadolinium
${CORE_SOURCES}
@@ -25,7 +30,9 @@ add_executable(gadolinium
${FRONTEND_HEADERS}
main.cpp
common.hpp
util.hpp)
util.hpp
n64/Scheduler.cpp
n64/Scheduler.hpp)
target_include_directories(gadolinium PRIVATE
.
@@ -43,6 +50,7 @@ target_include_directories(gadolinium PRIVATE
../external/parallel-rdp/
../external/nativefiledialog-extended/src/include
../external/capstone/include
../external/discord-rpc/include
${SDL2_INCLUDE_DIR}
)
@@ -57,4 +65,21 @@ if(WIN32)
target_compile_options(gadolinium PUBLIC /EHa)
endif()
target_link_libraries(gadolinium PRIVATE SDL2::SDL2main SDL2::SDL2 capstone-static nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json)
if(${CMAKE_BUILD_TYPE} MATCHES Release)
set_property(TARGET gadolinium PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
if(WIN32)
add_compile_options(/O2)
else()
add_compile_options(-O3)
endif()
else()
if(WIN32)
add_compile_options(/Od)
else()
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
add_compile_options(-g)
endif()
endif()
target_link_libraries(gadolinium PRIVATE discord-rpc SDL2::SDL2main SDL2::SDL2 capstone-static nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json)

View File

@@ -1,6 +1,12 @@
#include <App.hpp>
#include <nfd.hpp>
App::App() : window(core) {
DiscordEventHandlers handlers{};
Discord_Initialize("1049669178124148806", &handlers, 1, nullptr);
util::UpdateRPC(util::Idling);
}
void App::Run() {
const u8* state = SDL_GetKeyboardState(nullptr);
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
@@ -50,4 +56,4 @@ void App::Run() {
}
}
}
}
}

View File

@@ -1,9 +1,10 @@
#pragma once
#include <imgui/Window.hpp>
#include <util.hpp>
struct App {
App() : window(core) {};
~App() = default;
App();
~App() { util::ClearRPC(); }
void Run();
inline void LoadROM(const std::string& path) {
window.LoadROM(core, path);

View File

@@ -2,10 +2,12 @@
#include <nfd.hpp>
#include <Core.hpp>
#include <Audio.hpp>
#include <nlohmann/json.hpp>
#include <filesystem>
#include <SDL.h>
VkInstance instance{};
using json = nlohmann::json;
Window::Window(n64::Core& core) {
InitSDL();
@@ -57,7 +59,7 @@ void Window::InitSDL() {
"Gadolinium",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
800, 600,
1024, 768,
SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
);
@@ -143,6 +145,17 @@ void Window::InitImgui() {
uiFont = io.Fonts->AddFontFromFileTTF("resources/OpenSans.ttf", 15.f);
codeFont = io.Fonts->AddFontFromFileTTF("resources/Sweet16.ttf", 15.f);
int displayIndex = SDL_GetWindowDisplayIndex(window);
float ddpi, hdpi, vdpi;
SDL_GetDisplayDPI(displayIndex, &ddpi, &hdpi, &vdpi);
ddpi /= 96.f;
uiFont = io.Fonts->AddFontFromFileTTF("resources/OpenSans.ttf", 16.f * ddpi);
codeFont = io.Fonts->AddFontFromFileTTF("resources/Sweet16.ttf", 16.f * ddpi);
ImGui::GetStyle().ScaleAllSizes(ddpi);
{
VkCommandBuffer commandBuffer = GetVkCommandBuffer();
ImGui_ImplVulkan_CreateFontsTexture(commandBuffer);
@@ -178,14 +191,14 @@ void Window::LoadROM(n64::Core& core, const std::string &path) {
std::ifstream gameDbFile("resources/game_db.json");
json gameDb = json::parse(gameDbFile);
auto entry = gameDb[fmt::format("{:08x}", cartInfo.crc)]["name"];
std::string name{};
if(!entry.empty()) {
name = entry.get<std::string>();
gameName = entry.get<std::string>();
} else {
name = std::filesystem::path(path).stem().string();
gameName = std::filesystem::path(path).stem().string();
}
windowTitle = "Gadolinium - " + name;
windowTitle = "Gadolinium - " + gameName;
shadowWindowTitle = windowTitle;
SDL_SetWindowTitle(window, windowTitle.c_str());
@@ -215,6 +228,7 @@ void Window::Render(n64::Core& core) {
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if (result == NFD_OKAY) {
LoadROM(core, outpath);
util::UpdateRPC(util::Playing, gameName);
NFD_FreePath(outpath);
}
}
@@ -238,6 +252,8 @@ void Window::Render(n64::Core& core) {
}
if (ImGui::MenuItem("Stop")) {
windowTitle = "Gadolinium";
core.rom.clear();
util::UpdateRPC(util::Idling);
SDL_SetWindowTitle(window, windowTitle.c_str());
core.Stop();
}
@@ -246,8 +262,10 @@ void Window::Render(n64::Core& core) {
if(core.pause) {
shadowWindowTitle = windowTitle;
windowTitle += " | Paused";
util::UpdateRPC(util::Paused, gameName);
} else {
windowTitle = shadowWindowTitle;
util::UpdateRPC(util::Playing, gameName);
}
SDL_SetWindowTitle(window, windowTitle.c_str());
}

View File

@@ -18,15 +18,16 @@ struct Window {
[[nodiscard]] bool gotClosed(SDL_Event event);
ImFont *uiFont{}, *codeFont{};
u32 windowID{};
float volumeL = 0.1, volumeR = 0.1;
float volumeL = 0.0, volumeR = 0.0;
void LoadROM(n64::Core& core, const std::string& path);
private:
json settings;
std::fstream settingsFile;
bool lockVolume = true;
SDL_Window* window{};
std::string windowTitle;
std::string shadowWindowTitle;
std::string windowTitle{"Gadolinium"};
std::string shadowWindowTitle{windowTitle};
std::string gameName{};
void InitSDL();
void InitImgui();
void Render(n64::Core& core);

View File

@@ -33,7 +33,7 @@ CartInfo Core::LoadROM(const std::string& rom_) {
void Core::Run(Window& window, float volumeL, float volumeR) {
MMIO& mmio = mem.mmio;
Controller& controller = mmio.si.controller;
int cpuSteps = 0;
for(int field = 0; field < mmio.vi.numFields; field++) {
int frameCycles = 0;
if(!pause && romLoaded) {
@@ -46,14 +46,11 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
CpuStep(mem);
cpuSteps++;
if(mmio.rsp.spStatus.halt) {
mmio.rsp.steps = 0;
cpuSteps = 0;
} else {
if(cpuSteps > 2) {
if(!mmio.rsp.spStatus.halt) {
cpu.regs.steps++;
if(cpu.regs.steps > 2) {
mmio.rsp.steps += 2;
cpuSteps -= 3;
cpu.regs.steps -= 3;
}
while(mmio.rsp.steps > 0) {

View File

@@ -20,7 +20,7 @@ void Scheduler::enqueueAbsolute(const Event& event) {
void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) {
ticks += t;
if(ticks >= events.top().time) {
while(ticks >= events.top().time) {
events.top().event_cb(mem, regs);
events.pop();
}

View File

@@ -53,13 +53,13 @@ void Interpreter::Step(Mem& mem) {
regs.prevDelaySlot = regs.delaySlot;
regs.delaySlot = false;
u32 instruction = mem.Read32(regs, regs.pc, regs.pc);
if(ShouldServiceInterrupt(regs)) {
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc);
return;
}
u32 instruction = mem.Read32(regs, regs.pc, regs.pc);
regs.oldPC = regs.pc;
regs.pc = regs.nextPC;
regs.nextPC += 4;

View File

@@ -20,11 +20,13 @@ struct Interpreter {
void Step(Mem&);
Registers regs;
private:
u64 cop2Latch{};
csh handle;
void disassembly(u32 instr);
friend struct Cop1;
void cop2Decode(u32);
void special(Mem&, u32);
void regimm(u32);
void Exec(Mem&, u32);
@@ -113,5 +115,12 @@ private:
void ori(u32);
void xor_(u32);
void xori(u32);
void mtc2(u32);
void mfc2(u32);
void dmtc2(u32);
void dmfc2(u32);
void ctc2(u32);
void cfc2(u32);
};
}

View File

@@ -10,6 +10,23 @@ Mem::Mem() {
}
void Mem::Reset() {
readPages.resize(PAGE_COUNT);
writePages.resize(PAGE_COUNT);
std::fill(readPages.begin(), readPages.end(), 0);
std::fill(writePages.begin(), writePages.end(), 0);
for(int i = 0; i < 2048; i++) {
const auto addr = (i * PAGE_SIZE) & RDRAM_DSIZE;
const auto pointer = (uintptr_t) &mmio.rdp.rdram[addr];
readPages[i] = pointer;
writePages[i] = pointer;
}
readPages[0x4000] = (uintptr_t) &mmio.rsp.dmem[0];
readPages[0x4001] = (uintptr_t) &mmio.rsp.imem[0];
writePages[0x4000] = (uintptr_t) &mmio.rsp.dmem[0];
writePages[0x4001] = (uintptr_t) &mmio.rsp.imem[0];
sram.resize(SRAM_SIZE);
std::fill(sram.begin(), sram.end(), 0);
romMask = 0;
@@ -73,132 +90,182 @@ template bool MapVAddr<false>(Registers& regs, TLBAccessType accessType, u64 vad
template <bool tlb>
u8 Mem::Read8(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return mmio.rdp.dram[BYTE_ADDRESS(paddr)];
case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1)
return mmio.rsp.imem[BYTE_ADDRESS(paddr) & IMEM_DSIZE];
else
return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE];
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
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;
const auto page = paddr >> 12;
const auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
return ((u8*)pointer)[BYTE_ADDRESS(offset)];
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
return mmio.rdp.rdram[BYTE_ADDRESS(paddr)];
case 0x04000000 ... 0x0403FFFF:
if ((paddr >> 12) & 1)
return mmio.rsp.imem[BYTE_ADDRESS(paddr) & IMEM_DSIZE];
else
return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE];
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
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) - 0x1FC00000];
case 0x1FC007C0 ... 0x1FC007FF:
return pifRam[paddr - 0x1FC007C0];
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF:
case 0x1FC00800 ... 0xFFFFFFFF:
return 0;
default:
util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64) regs.pc);
}
case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~2;
return cart[BYTE_ADDRESS(paddr) & romMask];
case 0x1FC00000 ... 0x1FC007BF:
return pifBootrom[BYTE_ADDRESS(paddr) - 0x1FC00000];
case 0x1FC007C0 ... 0x1FC007FF:
return pifRam[paddr - 0x1FC007C0];
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x0FFFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
default:
util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
}
}
template <bool tlb>
u16 Mem::Read16(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u16>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr));
case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1)
return util::ReadAccess<u16>(mmio.rsp.imem, HALF_ADDRESS(paddr) & IMEM_DSIZE);
else
return util::ReadAccess<u16>(mmio.rsp.dmem, HALF_ADDRESS(paddr) & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~3;
return util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be16toh(util::ReadAccess<u16>(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);
const auto page = paddr >> 12;
const auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
return util::ReadAccess<u16>((u8*)pointer, HALF_ADDRESS(offset));
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u16>(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr));
case 0x04000000 ... 0x0403FFFF:
if ((paddr >> 12) & 1)
return util::ReadAccess<u16>(mmio.rsp.imem, HALF_ADDRESS(paddr) & IMEM_DSIZE);
else
return util::ReadAccess<u16>(mmio.rsp.dmem, HALF_ADDRESS(paddr) & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF:
case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~3;
return util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be16toh(util::ReadAccess<u16>(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);
}
}
}
template <bool tlb>
u32 Mem::Read32(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u32>(mmio.rdp.dram.data(), paddr);
case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1)
return util::ReadAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u32>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u32>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be32toh(util::ReadAccess<u32>(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);
const auto page = paddr >> 12;
const auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
return util::ReadAccess<u32>((u8*)pointer, offset);
} else {
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u32>(mmio.rdp.rdram.data(), paddr);
case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1)
return util::ReadAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u32>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u32>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be32toh(util::ReadAccess<u32>(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);
}
}
}
template <bool tlb>
u64 Mem::Read64(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u64>(mmio.rdp.dram.data(), paddr);
case 0x04000000 ... 0x0403FFFF:
if((paddr >> 12) & 1)
return util::ReadAccess<u64>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u64>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u64>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u64>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be64toh(util::ReadAccess<u64>(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);
const auto page = paddr >> 12;
const auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
return util::ReadAccess<u64>((u8*)pointer, offset);
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u64>(mmio.rdp.rdram.data(), paddr);
case 0x04000000 ... 0x0403FFFF:
if ((paddr >> 12) & 1)
return util::ReadAccess<u64>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u64>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF:
case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u64>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u64>(pifBootrom, paddr - 0x1FC00000);
case 0x1FC007C0 ... 0x1FC007FF:
return be64toh(util::ReadAccess<u64>(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);
}
}
}
@@ -214,73 +281,118 @@ template u64 Mem::Read64<true>(n64::Registers &regs, u64 vaddr, s64 pc);
template <bool tlb>
void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
mmio.rdp.dram[BYTE_ADDRESS(paddr)] = val;
break;
case 0x04000000 ... 0x0403FFFF:
const auto page = paddr >> 12;
auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr & DMEM_DSIZE) & ~3;
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write8!\n");
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr - 0x1FC007C0) & ~3;
util::WriteAccess<u32>(pifRam, paddr, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default:
util::panic("Unimplemented 8-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
offset = (offset & DMEM_DSIZE) & ~3;
}
((u8*)pointer)[BYTE_ADDRESS(offset)] = val;
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val;
break;
case 0x04000000 ... 0x0403FFFF:
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr & DMEM_DSIZE) & ~3;
if (paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF:
case 0x04500000 ... 0x048FFFFF:
util::panic("MMIO Write8!\n");
case 0x10000000 ... 0x13FFFFFF:
break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr - 0x1FC007C0) & ~3;
util::WriteAccess<u32>(pifRam, paddr, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;
default:
util::panic("Unimplemented 8-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
(u64) regs.pc);
}
}
}
template <bool tlb>
void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
if (!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u16>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr), val);
break;
case 0x04000000 ... 0x0403FFFF:
const auto page = paddr >> 12;
auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
val = val << (16 * !(paddr & 2));
paddr &= ~3;
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write16!\n");
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 16-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
offset &= ~3;
}
util::WriteAccess<u16>((u8*)pointer, HALF_ADDRESS(offset), val);
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u16>(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val);
break;
case 0x04000000 ... 0x0403FFFF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
if (paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF:
case 0x04500000 ... 0x048FFFFF:
util::panic("MMIO Write16!\n");
case 0x10000000 ... 0x13FFFFFF:
break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;
default:
util::panic("Unimplemented 16-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
(u64) regs.pc);
}
}
}
@@ -292,38 +404,46 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u32>(mmio.rdp.dram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FF0013: break;
case 0x13FF0014: {
if(val < ISVIEWER_SIZE) {
char* message = (char*)calloc(val + 1, 1);
memcpy(message, isviewer, val);
fmt::print("{}", message);
free(message);
}
} break;
case 0x13FF0020 ... 0x13FFFFFF:
util::WriteAccess<u32>(isviewer, paddr - 0x13FF0020, htobe32(val));
break;
case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
const auto page = paddr >> 12;
auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
util::WriteAccess<u32>((u8*)pointer, offset, val);
} else {
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u32>(mmio.rdp.rdram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FF0013: break;
case 0x13FF0014: {
if(val < ISVIEWER_SIZE) {
char* message = (char*)calloc(val + 1, 1);
memcpy(message, isviewer, val);
fmt::print("{}", message);
free(message);
}
} break;
case 0x13FF0020 ... 0x13FFFFFF:
util::WriteAccess<u32>(isviewer, paddr - 0x13FF0020, htobe32(val));
break;
case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
}
}
}
@@ -335,28 +455,49 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u64>(mmio.rdp.dram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
const auto page = paddr >> 12;
auto offset = paddr & 0xFFF;
const auto pointer = readPages[page];
if(pointer) {
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
val >>= 32;
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write64!\n");
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u64>(pifRam, paddr - 0x1FC007C0, htobe64(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
}
util::WriteAccess<u64>((u8*)pointer, offset, val);
} else {
switch (paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u64>(mmio.rdp.rdram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
val >>= 32;
if (paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF:
case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF:
case 0x04500000 ... 0x048FFFFF:
util::panic("MMIO Write64!\n");
case 0x10000000 ... 0x13FFFFFF:
break;
case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u64>(pifRam, paddr - 0x1FC007C0, htobe64(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;
default:
util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
(u64) regs.pc);
}
}
}

View File

@@ -20,7 +20,7 @@ struct Mem {
void Reset();
CartInfo LoadROM(const std::string&);
[[nodiscard]] auto GetRDRAM() -> u8* {
return mmio.rdp.dram.data();
return mmio.rdp.rdram.data();
}
template <bool tlb = true>
@@ -46,7 +46,7 @@ struct Mem {
inline void DumpRDRAM() const {
FILE *fp = fopen("rdram.dump", "wb");
u8 *temp = (u8*)calloc(RDRAM_SIZE, 1);
memcpy(temp, mmio.rdp.dram.data(), RDRAM_SIZE);
memcpy(temp, mmio.rdp.rdram.data(), RDRAM_SIZE);
util::SwapBuffer32(RDRAM_SIZE, temp);
fwrite(temp, 1, RDRAM_SIZE, fp);
free(temp);
@@ -72,6 +72,7 @@ struct Mem {
free(temp);
fclose(fp);
}
std::vector<uintptr_t> writePages, readPages;
private:
friend struct SI;
friend struct PI;

View File

@@ -11,8 +11,8 @@ RDP::RDP() {
void RDP::Reset() {
dpc.status.raw = 0x80;
dram.resize(RDRAM_SIZE);
std::fill(dram.begin(), dram.end(), 0);
rdram.resize(RDRAM_SIZE);
std::fill(rdram.begin(), rdram.end(), 0);
memset(cmd_buf, 0, 0x100000);
}
@@ -144,7 +144,7 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) {
return;
}
for (int i = 0; i < len; i += 4) {
u32 cmd = util::ReadAccess<u32>(dram.data(), current + i);
u32 cmd = util::ReadAccess<u32>(rdram.data(), current + i);
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
}
}

View File

@@ -57,7 +57,7 @@ struct RDP {
RDP();
void Reset();
std::vector<u8> dram;
std::vector<u8> rdram;
[[nodiscard]] auto Read(u32 addr) const -> u32;
void Write(MI& mi, Registers& regs, RSP& rsp, u32 addr, u32 val);
void WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val);

View File

@@ -1,6 +1,7 @@
#include <n64/core/RSP.hpp>
#include <util.hpp>
#include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp>
namespace n64 {
RSP::RSP() {
@@ -90,6 +91,32 @@ auto RSP::Read(u32 addr) -> u32{
}
}
void RSP::WriteStatus(MI& mi, Registers& regs, u32 value) {
auto write = SPStatusWrite{.raw = value};
if(write.clearHalt && !write.setHalt) {
spStatus.halt = false;
}
if(write.setHalt && !write.clearHalt) {
regs.steps = 0;
spStatus.halt = true;
}
if(write.clearBroke) spStatus.broke = false;
if(write.clearIntr && !write.setIntr)
InterruptLower(mi, regs, Interrupt::SP);
if(write.setIntr && !write.clearIntr)
InterruptRaise(mi, regs, Interrupt::SP);
CLEAR_SET(spStatus.singleStep, write.clearSstep, write.setSstep);
CLEAR_SET(spStatus.interruptOnBreak, write.clearIntrOnBreak, write.setIntrOnBreak);
CLEAR_SET(spStatus.signal0, write.clearSignal0, write.setSignal0);
CLEAR_SET(spStatus.signal1, write.clearSignal1, write.setSignal1);
CLEAR_SET(spStatus.signal2, write.clearSignal2, write.setSignal2);
CLEAR_SET(spStatus.signal3, write.clearSignal3, write.setSignal3);
CLEAR_SET(spStatus.signal4, write.clearSignal4, write.setSignal4);
CLEAR_SET(spStatus.signal5, write.clearSignal5, write.setSignal5);
CLEAR_SET(spStatus.signal6, write.clearSignal6, write.setSignal6);
CLEAR_SET(spStatus.signal7, write.clearSignal7, write.setSignal7);
}
void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) {
MI& mi = mem.mmio.mi;
switch (addr) {

View File

@@ -194,31 +194,6 @@ struct RSP {
return value;
}
inline void WriteStatus(MI& mi, Registers& regs, u32 value) {
auto write = SPStatusWrite{.raw = value};
if(write.clearHalt && !write.setHalt) {
spStatus.halt = false;
}
if(write.setHalt && !write.clearHalt) {
spStatus.halt = true;
}
if(write.clearBroke) spStatus.broke = false;
if(write.clearIntr && !write.setIntr)
InterruptLower(mi, regs, Interrupt::SP);
if(write.setIntr && !write.clearIntr)
InterruptRaise(mi, regs, Interrupt::SP);
CLEAR_SET(spStatus.singleStep, write.clearSstep, write.setSstep);
CLEAR_SET(spStatus.interruptOnBreak, write.clearIntrOnBreak, write.setIntrOnBreak);
CLEAR_SET(spStatus.signal0, write.clearSignal0, write.setSignal0);
CLEAR_SET(spStatus.signal1, write.clearSignal1, write.setSignal1);
CLEAR_SET(spStatus.signal2, write.clearSignal2, write.setSignal2);
CLEAR_SET(spStatus.signal3, write.clearSignal3, write.setSignal3);
CLEAR_SET(spStatus.signal4, write.clearSignal4, write.setSignal4);
CLEAR_SET(spStatus.signal5, write.clearSignal5, write.setSignal5);
CLEAR_SET(spStatus.signal6, write.clearSignal6, write.setSignal6);
CLEAR_SET(spStatus.signal7, write.clearSignal7, write.setSignal7);
}
inline u32 ReadWord(u32 addr) {
addr &= 0xfff;
return GET_RSP_WORD(addr);
@@ -400,6 +375,8 @@ struct RSP {
rsp.lastSuccessfulDRAMAddr.address = dram_address;
rsp.spDMALen.raw = 0xFF8 | (rsp.spDMALen.skip << 20);
}
void WriteStatus(MI& mi, Registers& regs, u32 value);
private:
inline void branch(u16 address, bool cond) {
if(cond) {

View File

@@ -90,6 +90,23 @@ void Interpreter::regimm(u32 instr) {
}
}
void Interpreter::cop2Decode(u32 instr) {
if(!regs.cop0.status.cu2) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
return;
}
switch(RS(instr)) {
case 0x00: mfc2(instr); break;
case 0x01: dmfc2(instr); break;
case 0x02: cfc2(instr); break;
case 0x04: mtc2(instr); break;
case 0x05: dmtc2(instr); break;
case 0x06: ctc2(instr); break;
default:
FireException(regs, ExceptionCode::ReservedInstruction, 2, regs.oldPC);
}
}
void Interpreter::Exec(Mem& mem, u32 instr) {
u8 mask = (instr >> 26) & 0x3f;
// 00rr_rccc
@@ -115,9 +132,7 @@ void Interpreter::Exec(Mem& mem, u32 instr) {
case 0x0F: lui(instr); break;
case 0x10: regs.cop0.decode(regs, mem, instr); break;
case 0x11: regs.cop1.decode(*this, instr); break;
case 0x12:
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
break;
case 0x12: cop2Decode(instr); break;
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break;

View File

@@ -777,4 +777,30 @@ void Interpreter::trap(bool cond) {
FireException(regs, ExceptionCode::Trap, 0, regs.oldPC);
}
}
void Cpu::mtc2(u32 instr) {
cop2Latch = regs.gpr[RT(instr)];
}
void Cpu::mfc2(u32 instr) {
s32 value = cop2Latch;
regs.gpr[RT(instr)] = value;
}
void Cpu::dmtc2(u32 instr) {
cop2Latch = regs.gpr[RT(instr)];
}
void Cpu::dmfc2(u32 instr) {
regs.gpr[RT(instr)] = cop2Latch;
}
void Cpu::ctc2(u32) {
}
void Cpu::cfc2(u32) {
}
}

View File

@@ -44,7 +44,7 @@ void AI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
case 0x04500004: {
u32 len = (val & 0x3FFFF) & ~7;
if((dmaCount < 2) && len) {
if(dmaCount == 0) InterruptRaise(mem.mmio.mi, regs, Interrupt::AI);
// if(dmaCount == 0) InterruptRaise(mem.mmio.mi, regs, Interrupt::AI);
dmaLen[dmaCount] = len;
dmaCount++;
}
@@ -81,17 +81,19 @@ void AI::Step(Mem& mem, Registers& regs, int cpuCycles, float volumeL, float vol
}
if(dmaLen[0] && dmaEnable) {
u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF;
dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF);
u32 data = util::ReadAccess<u32>(mem.mmio.rdp.dram.data(), dmaAddr[0] & RDRAM_DSIZE);
s16 l = s16(data >> 16);
s16 r = s16(data);
if(volumeR > 0 && volumeL > 0) {
u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF;
dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF);
u32 data = util::ReadAccess<u32>(mem.mmio.rdp.rdram.data(), dmaAddr[0] & RDRAM_DSIZE);
s16 l = s16(data >> 16);
s16 r = s16(data);
PushSample((float)l / INT16_MAX, volumeL, (float)r / INT16_MAX, volumeR);
PushSample((float) l / INT16_MAX, volumeL, (float) r / INT16_MAX, volumeR);
u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF;
dmaAddr[0] = (dmaAddr[0] & ~0x1FFF) | addrLo;
dmaAddrCarry = addrLo == 0;
u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF;
dmaAddr[0] = (dmaAddr[0] & ~0x1FFF) | addrLo;
dmaAddrCarry = addrLo == 0;
}
dmaLen[0] -= 4;
}

View File

@@ -52,7 +52,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
}
rdLen = len;
for(int i = 0; i < len; i++) {
mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask] = mem.mmio.rdp.dram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
}
dramAddr = dram_addr + len;
cartAddr = cart_addr + len;
@@ -68,7 +68,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
}
wrLen = len;
for(int i = 0; i < len; i++) {
mem.mmio.rdp.dram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask];
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask];
}
dramAddr = dram_addr + len;
cartAddr = cart_addr + len;

View File

@@ -36,17 +36,14 @@ 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++) {
mem.mmio.rdp.dram[BYTE_ADDRESS(si.dramAddr + i)] = mem.pifRam[i];
mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = mem.pifRam[i];
}
} else {
for(int i = 0; i < 64; i++) {
mem.pifRam[i] = mem.mmio.rdp.dram[BYTE_ADDRESS(si.dramAddr + i)];
mem.pifRam[i] = mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)];
}
util::logdebug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})\n", si.pifAddr, si.dramAddr);
ProcessPIFCommands(mem.pifRam, si.controller, mem);

View File

@@ -9,7 +9,7 @@ Cop1::Cop1() {
}
void Cop1::Reset() {
fcr0 = 0xa00;
fcr0 = 0;
fcr31.raw = 0;
memset(fgr, 0, 32 * sizeof(FGR));
}

View File

@@ -13,5 +13,6 @@ struct Registers {
s64 oldPC, pc, nextPC;
s64 hi, lo;
bool prevDelaySlot, delaySlot;
int steps = 0;
};
}

View File

@@ -215,7 +215,7 @@ void RSP::Exec(Registers &regs, Mem& mem, u32 instr) {
fwrite(temp, 1, IMEM_SIZE, fp);
free(temp);
fclose(fp);
util::panic("Unhandled RSP instruction ({:06b})\n", mask);
util::panic("Unhandled RSP instruction ({:06b}, {:04X})\n", mask, oldPC);
}
}
}

View File

@@ -29,4 +29,20 @@
#define SRAM_REGION 0x08000000 ... 0x0FFFFFFF
#define CART_REGION 0x10000000 ... 0x1FBFFFFF
#define PIF_ROM_REGION 0x1FC00000 ... 0x1FC007BF
#define PIF_RAM_REGION 0x1FC007C0 ... 0x1FC007FF
#define PIF_RAM_REGION 0x1FC007C0 ... 0x1FC007FF
constexpr size_t operator""_kb(unsigned long long int x) {
return 1024ULL * x;
}
constexpr size_t operator""_mb(unsigned long long int x) {
return 1024_kb * x;
}
constexpr size_t operator""_gb(unsigned long long int x) {
return 1024_mb * x;
}
#define ADDRESS_RANGE_SIZE 4_gb
#define PAGE_SIZE 4_kb
#define PAGE_COUNT ((ADDRESS_RANGE_SIZE) / (PAGE_SIZE))

View File

@@ -8,6 +8,7 @@
#include <array>
#include <chrono>
#include <functional>
#include <discord_rpc.h>
namespace util {
using SteadyClock = std::chrono::steady_clock;
@@ -20,7 +21,7 @@ enum MessageType : u8 {
template <MessageType messageType = Info, typename ...Args>
constexpr void print(const std::string& fmt, Args... args) {
#ifndef __WIN32
#ifndef _WIN32
if constexpr(messageType == Error) {
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), fmt, args...);
exit(-1);
@@ -265,4 +266,40 @@ inline auto ReadFileBinary(const std::string& path, u32** buf) {
file.close();
return size;
}
enum State {
Idling,
Playing,
Paused
};
inline void UpdateRPC(State state, const std::string& game = "") {
DiscordRichPresence presence{};
std::string textState, textDetails;
switch(state) {
case Idling:
textDetails = "Idling";
break;
case Playing:
textDetails = "In-game";
textState = "Playing \"" + game + "\"";
break;
case Paused:
textDetails = "In-game";
textState = "Playing \"" + game + "\" (Paused)";
break;
}
presence.details = textDetails.c_str();
presence.state = textState.c_str();
presence.startTimestamp = time(nullptr);
presence.largeImageText = "Gadolinium";
presence.largeImageKey = "logo";
Discord_UpdatePresence(&presence);
}
inline void ClearRPC() {
Discord_ClearPresence();
}
}