diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 15833c4e..70f7a0c3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -10,6 +10,8 @@ add_library(cores Scheduler.cpp Scheduler.hpp common.hpp - util.hpp Audio.hpp Audio.cpp) + util.hpp + Audio.hpp + Audio.cpp) target_include_directories(cores PUBLIC . ../../external) -target_link_libraries(cores PUBLIC gb n64) +target_link_libraries(cores PUBLIC n64) diff --git a/src/core/n64/core/CMakeLists.txt b/src/core/n64/core/CMakeLists.txt index d1444a9c..59a81450 100644 --- a/src/core/n64/core/CMakeLists.txt +++ b/src/core/n64/core/CMakeLists.txt @@ -12,18 +12,28 @@ add_library(n64-core Mem.hpp RDP.cpp RDP.hpp - mmio/VI.cpp - mmio/VI.hpp + mmio/AI.cpp + mmio/AI.hpp + mmio/Interrupt.cpp mmio/Interrupt.hpp mmio/MI.cpp mmio/MI.hpp - mmio/Interrupt.cpp + mmio/PI.cpp + mmio/PI.hpp + mmio/PIF.cpp + mmio/PIF.hpp + mmio/RI.cpp + mmio/RI.hpp + mmio/SI.cpp + mmio/SI.hpp + mmio/VI.cpp + mmio/VI.hpp MMIO.cpp MMIO.hpp RSP.cpp RSP.hpp rsp/decode.cpp - rsp/instructions.cpp mmio/AI.cpp mmio/AI.hpp) + rsp/instructions.cpp) target_include_directories(n64-core PRIVATE . .. ../../ mmio) target_link_libraries(n64-core PUBLIC n64-cpu parallel-rdp) diff --git a/src/core/n64/core/MMIO.cpp b/src/core/n64/core/MMIO.cpp index 35c48186..663d1e8a 100644 --- a/src/core/n64/core/MMIO.cpp +++ b/src/core/n64/core/MMIO.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/src/core/n64/core/MMIO.hpp b/src/core/n64/core/MMIO.hpp index 38a7de86..efad7101 100644 --- a/src/core/n64/core/MMIO.hpp +++ b/src/core/n64/core/MMIO.hpp @@ -2,6 +2,9 @@ #include #include #include +#include +#include +#include #include #include @@ -14,6 +17,9 @@ struct MMIO { VI vi; MI mi; AI ai; + PI pi; + RI ri; + SI si; RSP rsp; RDP rdp; diff --git a/src/core/n64/core/Mem.hpp b/src/core/n64/core/Mem.hpp index 988037f2..e07d2f09 100644 --- a/src/core/n64/core/Mem.hpp +++ b/src/core/n64/core/Mem.hpp @@ -17,13 +17,16 @@ struct Mem { T Read(Registers&, u32, s64); template void Write(Registers&, u32, T, s64); + u8 pifRam[PIF_RAM_SIZE]{}; private: + friend struct SI; + friend struct PI; friend struct AI; friend struct Cpu; friend struct RSP; MMIO mmio; std::vector cart, rdram, sram; - u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}, pifRam[PIF_RAM_SIZE]{}; + u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}; u8 pifBootrom[PIF_BOOTROM_SIZE]{}; size_t romMask; }; diff --git a/src/core/n64/core/cpu/Registers.hpp b/src/core/n64/core/cpu/Registers.hpp index 578d6cc0..39ee0446 100644 --- a/src/core/n64/core/cpu/Registers.hpp +++ b/src/core/n64/core/cpu/Registers.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include namespace natsukashii::n64::core { struct Registers { diff --git a/src/core/n64/core/mmio/MI.cpp b/src/core/n64/core/mmio/MI.cpp index 4e3b2363..3980ef6d 100644 --- a/src/core/n64/core/mmio/MI.cpp +++ b/src/core/n64/core/mmio/MI.cpp @@ -1,7 +1,7 @@ -#include +#include #include #include -#include +#include #define MI_VERSION_REG 0x02020102 diff --git a/src/core/n64/core/mmio/PI.cpp b/src/core/n64/core/mmio/PI.cpp new file mode 100644 index 00000000..4c73bc6b --- /dev/null +++ b/src/core/n64/core/mmio/PI.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +namespace natsukashii::n64::core { +auto PI::Read(MI& mi, u32 addr) const -> u32 { + switch(addr) { + case 0x04600000: return dramAddr; + case 0x04600004: return cartAddr; + case 0x04600008: return rdLen; + case 0x0460000C: return wrLen; + case 0x04600010: { + u32 value = 0; + value |= (status & 1); // Is PI DMA active? + value |= (0 << 1); // Is PI IO busy? + value |= (0 << 2); // PI IO error? + value |= (mi.miIntr.pi << 3); // PI interrupt? + return value; + } + case 0x04600014: case 0x04600018: case 0x0460001C: case 0x04600020: + case 0x04600024: case 0x04600028: case 0x0460002C: case 0x04600030: + return stub[(addr & 0xff) - 5]; + default: util::panic("Unhandled PI[{:08X}] read\n", addr); return 0; + } +} + +void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { + MI& mi = mem.mmio.mi; + switch(addr) { + case 0x04600000: dramAddr = val; break; + case 0x04600004: cartAddr = val; break; + case 0x04600008: { + u32 len = (val & 0x00FFFFFF) + 1; + u32 cart_addr = cartAddr & 0xFFFFFFFE; + u32 dram_addr = dramAddr & 0x007FFFFE; + if (dram_addr & 0x7) { + len -= dram_addr & 0x7; + } + rdLen = len; + memcpy(&mem.cart[cart_addr & mem.romMask], &mem.rdram[dram_addr & RDRAM_DSIZE], len); + dramAddr = dram_addr + len; + cartAddr = cart_addr + len; + InterruptRaise(mi, regs, Interrupt::PI); + status = status & 0xFFFFFFFE; + util::info("PI DMA from rdram to cart (size: {:.2f} MiB)\n", (float)len / 1048576); + } 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; + } + wrLen = len; + memcpy(&mem.rdram[dram_addr & RDRAM_DSIZE], &mem.cart[cart_addr & mem.romMask], len); + dramAddr = dram_addr + len; + cartAddr = cart_addr + len; + InterruptRaise(mi, regs, Interrupt::PI); + status = status & 0xFFFFFFFE; + util::info("PI DMA from cart to rdram (size: {:.2f} MiB)\n", (float)len / 1048576); + } break; + case 0x04600010: + if(val & 2) { + InterruptLower(mi, regs, Interrupt::PI); + } break; + case 0x04600014: case 0x04600018: case 0x0460001C: case 0x04600020: + case 0x04600024: case 0x04600028: case 0x0460002C: case 0x04600030: + stub[(addr & 0xff) - 5] = val & 0xff; + break; + default: util::panic("Unhandled PI[{:08X}] write ({:08X})\n", val, addr); + } +} + +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/PI.hpp b/src/core/n64/core/mmio/PI.hpp new file mode 100644 index 00000000..16b2daa5 --- /dev/null +++ b/src/core/n64/core/mmio/PI.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace natsukashii::n64::core { + +struct Mem; +struct Registers; + +struct PI { + PI() = default; + auto Read(MI&, u32) const -> u32; + void Write(Mem&, Registers&, u32, u32); + u32 dramAddr{}, cartAddr{}; + u32 rdLen{}, wrLen{}; + u32 status{}; + u32 stub[8]{}; +}; +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/PIF.cpp b/src/core/n64/core/mmio/PIF.cpp new file mode 100644 index 00000000..03ba89bf --- /dev/null +++ b/src/core/n64/core/mmio/PIF.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +namespace natsukashii::n64::core { +static int channel = 0; + +void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) { + u8 control = pifRam[63]; + + if(control & 1) { + channel = 0; + for(int i = 0; i < 63;) { + u8* cmd = &pifRam[i++]; + u8 t = cmd[0] & 0x3f; + + if(t == 0 || t == 0x3D) { + channel++; + } else if (t == 0x3E) { + break; + } else if (t == 0x3F) { + continue; + } else { + u8 r = pifRam[i++]; + r |= (1 << 7); + if(r == 0xFE) { + break; + } + + u8 rlen = r & 0x3F; + u8* res = &pifRam[i + t]; + switch(cmd[2]) { + case 0xff: + res[0] = 0x05; + res[1] = 0x00; + res[2] = 0x01; + channel++; + break; + case 0: + res[0] = 0x05; + res[1] = 0x00; + res[2] = 0x01; + break; + case 1: + res[0] = controller.b1; + res[1] = controller.b2; + res[2] = controller.b3; + res[3] = controller.b4; + break; + case 2: case 3: break; + default: util::panic("Unimplemented PIF command {}", cmd[2]); + } + + i += t + rlen; + channel++; + } + } + } + + if(control & 8) { + pifRam[63] &= ~8; + } + + if(control & 48) { + pifRam[63] = 128; + } + + //mem->pif_ram[63] &= ~1; +} + +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/PIF.hpp b/src/core/n64/core/mmio/PIF.hpp new file mode 100644 index 00000000..2aa764bd --- /dev/null +++ b/src/core/n64/core/mmio/PIF.hpp @@ -0,0 +1,19 @@ +#pragma once +#include + +namespace natsukashii::n64::core { + +union Controller { + struct { + u8 b1, b2; + s8 b3, b4; + } __attribute__((__packed__)); + u32 raw; +}; + +static_assert(sizeof(Controller) == 4); + +struct Mem; + +void ProcessPIFCommands(u8*, Controller&, Mem&); +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/RI.cpp b/src/core/n64/core/mmio/RI.cpp new file mode 100644 index 00000000..82184bb3 --- /dev/null +++ b/src/core/n64/core/mmio/RI.cpp @@ -0,0 +1,25 @@ +#include +#include + +namespace natsukashii::n64::core { +auto RI::Read(u32 addr) const -> u32 { + switch(addr) { + case 0x04700000: return mode; + case 0x04700004: return config; + case 0x0470000C: return select; + case 0x04700010: return refresh; + default: util::panic("Unhandled RI[{:08X}] read\n", addr); return 0; + } +} + +void RI::Write(u32 addr, u32 val) { + switch(addr) { + case 0x04700000: mode = val; break; + case 0x04700004: config = val; break; + case 0x0470000C: select = val; break; + case 0x04700010: refresh = val; break; + default: util::panic("Unhandled RI[{:08X}] read\n", addr); + } +} + +} diff --git a/src/core/n64/core/mmio/RI.hpp b/src/core/n64/core/mmio/RI.hpp new file mode 100644 index 00000000..b46bd663 --- /dev/null +++ b/src/core/n64/core/mmio/RI.hpp @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace natsukashii::n64::core { + +struct RI { + RI() = default; + u32 mode{0xE}, config{0x40}, select{0x14}, refresh{0x63634}; + auto Read(u32) const -> u32; + void Write(u32, u32); +}; + +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/SI.cpp b/src/core/n64/core/mmio/SI.cpp new file mode 100644 index 00000000..0cbbd7f7 --- /dev/null +++ b/src/core/n64/core/mmio/SI.cpp @@ -0,0 +1,55 @@ +#include +#include +#include + +namespace natsukashii::n64::core { + +auto SI::Read(MI& mi, u32 addr) const -> u32 { + switch(addr) { + case 0x04800000: return dramAddr; + case 0x04800018: { + u32 val = 0; + val |= status.dmaBusy; + val |= (0 << 1); + val |= (0 << 3); + val |= (status.intr << 12); + return val; + } + default: return 0; + } +} + +void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { + switch(addr) { + case 0x04800000: + dramAddr = val; + break; + case 0x04800004: { + // if(!(status.raw & 3)) { + ProcessPIFCommands(mem.pifRam, controller, mem); + + u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; + memcpy(&mem.rdram[dramAddr & RDRAM_DSIZE], + &mem.pifRam[pifAddr], 64); + InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); + status.intr = 1; + } break; + case 0x04800010: { + //if(!(status.raw & 3)) { + u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; + memcpy(&mem.pifRam[pifAddr], + &mem.rdram[dramAddr & RDRAM_DSIZE], 64); + + ProcessPIFCommands(mem.pifRam, controller, mem); + InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); + status.intr = 1; + } break; + case 0x04800018: + InterruptLower(mem.mmio.mi, regs, Interrupt::SI); + status.intr = 0; + break; + default: util::panic("Unhandled SI[%08X] write (%08X)\n", addr, val); + } +} + +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/SI.hpp b/src/core/n64/core/mmio/SI.hpp new file mode 100644 index 00000000..18ac6302 --- /dev/null +++ b/src/core/n64/core/mmio/SI.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +namespace natsukashii::n64::core { + +union SIStatus { + u32 raw{}; + struct { + unsigned dmaBusy:1; + unsigned ioBusy:1; + unsigned reserved:1; + unsigned dmaErr:1; + unsigned:8; + unsigned intr:1; + }; +}; + +struct Mem; + +struct SI { + SI() = default; + SIStatus status{}; + u32 dramAddr{}; + Controller controller{}; + + auto Read(MI&, u32) const -> u32; + void Write(Mem&, Registers&, u32, u32); +}; +} \ No newline at end of file diff --git a/src/core/n64/core/mmio/VI.cpp b/src/core/n64/core/mmio/VI.cpp index a7afa0b1..cf3f9b6a 100644 --- a/src/core/n64/core/mmio/VI.cpp +++ b/src/core/n64/core/mmio/VI.cpp @@ -1,7 +1,7 @@ -#include +#include #include #include -#include +#include #include namespace natsukashii::n64::core { diff --git a/src/frontend/ParallelRDPWrapper.cpp b/src/frontend/ParallelRDPWrapper.cpp index 6ef5313f..7e38c7ab 100644 --- a/src/frontend/ParallelRDPWrapper.cpp +++ b/src/frontend/ParallelRDPWrapper.cpp @@ -1,10 +1,10 @@ -#include "ParallelRDPWrapper.hpp" -#include "n64/core/RDP.hpp" +#include +#include #include -#include "parallel-rdp-standalone/parallel-rdp/rdp_device.hpp" +#include #include #include -#include "util.hpp" +#include using namespace natsukashii::n64; using namespace natsukashii::core; diff --git a/src/frontend/sdl/CMakeLists.txt b/src/frontend/sdl/CMakeLists.txt index 91217e3f..2acf62fe 100644 --- a/src/frontend/sdl/CMakeLists.txt +++ b/src/frontend/sdl/CMakeLists.txt @@ -5,7 +5,12 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(SDL2 REQUIRED) -add_executable(natsukashii-sdl Frontend.cpp Frontend.hpp main.cpp ../ParallelRDPWrapper.cpp ../ParallelRDPWrapper.hpp) +add_executable(natsukashii-sdl + Frontend.cpp + Frontend.hpp + main.cpp + ../ParallelRDPWrapper.cpp + ../ParallelRDPWrapper.hpp) include(FetchContent) FetchContent_Declare( @@ -15,5 +20,15 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(argparse) -target_include_directories(natsukashii-sdl PRIVATE . ../../core) +target_include_directories(natsukashii-sdl PRIVATE + . + .. + ../../core + ../../../external/parallel-rdp-standalone/parallel-rdp + ../../../external/parallel-rdp-standalone/volk + ../../../external/parallel-rdp-standalone/spirv-cross + ../../../external/parallel-rdp-standalone/vulkan + ../../../external/parallel-rdp-standalone/vulkan-headers/include + ../../../external/parallel-rdp-standalone/util) target_link_libraries(natsukashii-sdl PRIVATE cores argparse::argparse SDL2) +target_compile_definitions(natsukashii-sdl PUBLIC GRANITE_VULKAN_MT) \ No newline at end of file diff --git a/src/frontend/sdl/Frontend.hpp b/src/frontend/sdl/Frontend.hpp index a32282c8..6b9ddf6f 100644 --- a/src/frontend/sdl/Frontend.hpp +++ b/src/frontend/sdl/Frontend.hpp @@ -3,12 +3,9 @@ #include #include #include -#include #include namespace natsukashii::frontend { -using namespace natsukashii::core; - struct App { ~App(); App(const std::string&, const std::string&);