diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f66f172..be9e296a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update -qq - sudo apt-get install -y build-essential libgtk-3-dev libsdl2-dev libfmt-dev git ninja-build nlohmann-json3-dev + sudo apt-get install -y build-essential libgtk-3-dev libsdl2-dev git ninja-build nlohmann-json3-dev sudo apt-get install -y vulkan-tools libvulkan1 libvulkan-dev vulkan-validationlayers-dev spirv-tools - name: Build natsukashii run: | @@ -46,7 +46,7 @@ jobs: with: install: make git mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-SDL2 - mingw-w64-x86_64-vulkan-devel mingw-w64-x86_64-fmt mingw-w64-x86_64-ninja + mingw-w64-x86_64-vulkan-devel mingw-w64-x86_64-ninja mingw-w64-x86_64-nlohmann-json - name: Build natsukashii run: | diff --git a/.gitmodules b/.gitmodules index 0be770c5..924f0591 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "external/parallel-rdp/parallel-rdp-standalone"] path = external/parallel-rdp/parallel-rdp-standalone url = https://github.com/CocoSimone/parallel-rdp-standalone/ +[submodule "external/fmt"] + path = external/fmt + url = https://github.com/fmtlib/fmt diff --git a/external/fmt b/external/fmt new file mode 160000 index 00000000..80f8d344 --- /dev/null +++ b/external/fmt @@ -0,0 +1 @@ +Subproject commit 80f8d34427d40ec5e7ce3b10ededc46bd4bd5759 diff --git a/external/parallel-rdp/ParallelRDPWrapper.cpp b/external/parallel-rdp/ParallelRDPWrapper.cpp index 0be6baf1..acb86d3d 100644 --- a/external/parallel-rdp/ParallelRDPWrapper.cpp +++ b/external/parallel-rdp/ParallelRDPWrapper.cpp @@ -171,7 +171,7 @@ void LoadParallelRDP(const u8* rdram, SDL_Window* window) { aligned_rdram -= offset; } - CommandProcessorFlags flags = COMMAND_PROCESSOR_FLAG_UPSCALING_2X_BIT; + CommandProcessorFlags flags = 0; command_processor = new CommandProcessor(wsi->get_device(), reinterpret_cast(aligned_rdram), offset, 8 * 1024 * 1024, 4 * 1024 * 1024, flags); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78b1b1d8..bc87e1c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.20) project(natsukashii) set(BUILD_SHARED_LIBS OFF) +set(CMAKE_CXX_STANDARD 17) file(GLOB_RECURSE CORE_SOURCES n64/*.cpp) file(GLOB_RECURSE CORE_HEADERS n64/*.hpp) @@ -9,9 +10,11 @@ file(GLOB_RECURSE FRONTEND_SOURCES frontend/*.cpp) file(GLOB_RECURSE FRONTEND_HEADERS frontend/*.hpp) find_package(SDL2 REQUIRED) -find_package(fmt REQUIRED) find_package(nlohmann_json REQUIRED) +set(FMT_TEST BOOL "" FORCE OFF) + +add_subdirectory(../external/fmt fmt) add_subdirectory(../external/capstone capstone) add_subdirectory(../external/parallel-rdp prdp) add_subdirectory(../external/imgui imgui) @@ -64,4 +67,5 @@ file(REMOVE ${PROJECT_BINARY_DIR}/resources/shader.frag ${PROJECT_BINARY_DIR}/resources/shader.vert) -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 +target_link_libraries(natsukashii PRIVATE ${LIBRARIES} ${SDL2_LIBRARIES} capstone-static nfd parallel-rdp imgui fmt::fmt nlohmann_json::nlohmann_json) +target_compile_options(natsukashii PRIVATE -msse4.1) \ No newline at end of file diff --git a/src/common.hpp b/src/common.hpp index d936ba38..e21bf72c 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -40,7 +40,6 @@ using s128 = __int128_t; #define SI_DMA_DELAY (65536 * 2) - enum TLBAccessType { LOAD, STORE }; \ No newline at end of file diff --git a/src/n64/core/Mem.cpp b/src/n64/core/Mem.cpp index d0ce0f44..f55cd325 100644 --- a/src/n64/core/Mem.cpp +++ b/src/n64/core/Mem.cpp @@ -232,7 +232,7 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { util::WriteAccess(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: - case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: + case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write8!\n"); case 0x10000000 ... 0x13FFFFFF: break; case 0x1FC007C0 ... 0x1FC007FF: val = val << (8 * (3 - (paddr & 3))); @@ -269,7 +269,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { util::WriteAccess(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 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write16!\n"); case 0x10000000 ... 0x13FFFFFF: break; case 0x1FC007C0 ... 0x1FC007FF: val = val << (16 * !(paddr & 2)); @@ -347,7 +347,7 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { util::WriteAccess(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 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: util::panic("MMIO Write64!\n"); case 0x10000000 ... 0x13FFFFFF: break; case 0x1FC007C0 ... 0x1FC007FF: util::WriteAccess(pifRam, paddr - 0x1FC007C0, htobe64(val)); diff --git a/src/n64/core/RDP.cpp b/src/n64/core/RDP.cpp index 955e8cdf..98b23fbd 100644 --- a/src/n64/core/RDP.cpp +++ b/src/n64/core/RDP.cpp @@ -140,8 +140,7 @@ void RDP::RunCommand(MI& mi, Registers& regs, RSP& rsp) { cmd_buf[remaining_cmds + (i >> 2)] = cmd; } } else { - if (end > 0x7FFFFFF || current > 0x7FFFFFF) { - util::panic("Not running RDP commands past end of RDRAM\n"); + if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE) return; } for (int i = 0; i < len; i += 4) { diff --git a/src/n64/core/cpu/instructions.cpp b/src/n64/core/cpu/instructions.cpp index b04f31c3..595be6e5 100644 --- a/src/n64/core/cpu/instructions.cpp +++ b/src/n64/core/cpu/instructions.cpp @@ -203,19 +203,28 @@ void Cpu::lh(Mem& mem, u32 instr) { if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + return; } regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC); } void Cpu::lw(Mem& mem, u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; + s16 offset = instr; + u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + return; } - regs.gpr[RT(instr)] = (s32)mem.Read32(regs, address, regs.oldPC); + u32 physical; + if (!MapVAddr(regs, LOAD, address, physical)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + } else { + regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); + } } void Cpu::ll(Mem& mem, u32 instr) { @@ -223,7 +232,7 @@ void Cpu::ll(Mem& mem, u32 instr) { u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); } @@ -267,6 +276,7 @@ void Cpu::ld(Mem& mem, u32 instr) { if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + return; } s64 value = mem.Read64(regs, address, regs.oldPC); @@ -278,7 +288,7 @@ void Cpu::lld(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { regs.gpr[RT(instr)] = mem.Read64(regs, paddr, regs.oldPC); } @@ -292,7 +302,7 @@ void Cpu::ldl(Mem& mem, u32 instr) { u32 paddr = 0; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -307,7 +317,7 @@ void Cpu::ldr(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -328,6 +338,7 @@ void Cpu::lhu(Mem& mem, u32 instr) { if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + return; } u16 value = mem.Read16(regs, address, regs.oldPC); @@ -339,6 +350,7 @@ void Cpu::lwu(Mem& mem, u32 instr) { if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + return; } u32 value = mem.Read32(regs, address, regs.oldPC); @@ -370,6 +382,7 @@ void Cpu::scd(Mem& mem, u32 instr) { if (check_address_error(address, 0b111)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + return; } if(regs.cop0.llbit) { @@ -385,19 +398,34 @@ void Cpu::sh(Mem& mem, u32 instr) { if (check_address_error(address, 0b1)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + return; } - mem.Write16(regs, address, regs.gpr[RT(instr)], regs.oldPC); + u32 physical; + if(!MapVAddr(regs, STORE, address, physical)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + } else { + mem.Write16(regs, physical, regs.gpr[RT(instr)], regs.oldPC); + } } void Cpu::sw(Mem& mem, u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; + s16 offset = instr; + u64 address = regs.gpr[RS(instr)] + offset; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + return; } - mem.Write32(regs, address, regs.gpr[RT(instr)], regs.oldPC); + u32 physical; + if(!MapVAddr(regs, STORE, address, physical)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + } else { + mem.Write32(regs, physical, regs.gpr[RT(instr)], regs.oldPC); + } } void Cpu::sd(Mem& mem, u32 instr) { @@ -405,9 +433,17 @@ void Cpu::sd(Mem& mem, u32 instr) { if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + return; + } + + u32 physical; + if(!MapVAddr(regs, STORE, address, physical)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + } else { + mem.Write64(regs, physical, regs.gpr[RT(instr)], regs.oldPC); } - mem.Write64(regs, address, regs.gpr[RT(instr)], regs.oldPC); } void Cpu::sdl(Mem& mem, u32 instr) { @@ -415,7 +451,7 @@ void Cpu::sdl(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; @@ -430,7 +466,7 @@ void Cpu::sdr(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; @@ -445,7 +481,7 @@ void Cpu::swl(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF >> shift; @@ -460,7 +496,7 @@ void Cpu::swr(Mem& mem, u32 instr) { u32 paddr; if (!MapVAddr(regs, STORE, address, paddr)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF << shift; @@ -646,7 +682,7 @@ void Cpu::jr(u32 instr) { s64 address = regs.gpr[RS(instr)]; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); + FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); } branch(true, address); diff --git a/src/n64/core/cpu/registers/cop1instructions.cpp b/src/n64/core/cpu/registers/cop1instructions.cpp index d0a8cd3d..a79d398b 100644 --- a/src/n64/core/cpu/registers/cop1instructions.cpp +++ b/src/n64/core/cpu/registers/cop1instructions.cpp @@ -459,7 +459,7 @@ void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); } u32 physical; @@ -500,7 +500,7 @@ void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); + FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); } u32 physical; diff --git a/src/n64/core/mmio/PI.cpp b/src/n64/core/mmio/PI.cpp index 69582246..cc1a07d1 100644 --- a/src/n64/core/mmio/PI.cpp +++ b/src/n64/core/mmio/PI.cpp @@ -57,14 +57,14 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { dramAddr = dram_addr + len; cartAddr = cart_addr + len; InterruptRaise(mi, regs, Interrupt::PI); - util::logdebug("PI DMA from RDRAM to CARTRIDGE (size: {} KiB, {:08X} to {:08X})\n", len, dramAddr, cartAddr); + //util::print("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})\n", len, dramAddr, cartAddr); } break; case 0x0460000C: { u32 len = (val & 0x00FFFFFF) + 1; u32 cart_addr = cartAddr & 0xFFFFFFFE; u32 dram_addr = dramAddr & 0x007FFFFE; if (dram_addr & 0x7) { - len -= dram_addr & 0x7; + len -= (dram_addr & 0x7); } wrLen = len; for(int i = 0; i < len; i++) { @@ -73,7 +73,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { dramAddr = dram_addr + len; cartAddr = cart_addr + len; InterruptRaise(mi, regs, Interrupt::PI); - util::logdebug("PI DMA from CARTRIDGE to RDRAM (size: {} KiB, {:08X} to {:08X})\n", len, cart_addr, dram_addr); + //util::print("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})\n", len, cart_addr, dram_addr); } break; case 0x04600010: if(val & 2) { diff --git a/src/n64/core/rsp/instructions.cpp b/src/n64/core/rsp/instructions.cpp index ab46f004..d24e1ef0 100644 --- a/src/n64/core/rsp/instructions.cpp +++ b/src/n64/core/rsp/instructions.cpp @@ -94,7 +94,8 @@ inline VPR Broadcast(const VPR& vt, int l0, int l1, int l2, int l3, int l4, int inline VPR GetVTE(const VPR& vt, u8 e) { VPR vte{}; - switch(e & 0xf) { + e &= 0xf; + switch(e) { case 0 ... 1: return vt; case 2 ... 3: vte = Broadcast(vt, e - 2, e - 2, e, e, e + 2, e + 2, e + 4, e + 4);