N64 MMIO integration complete

This commit is contained in:
CocoSimone
2022-07-03 14:28:07 +02:00
parent 80e9bf67e5
commit e1600c9151
19 changed files with 364 additions and 22 deletions

View File

@@ -10,6 +10,8 @@ add_library(cores
Scheduler.cpp Scheduler.cpp
Scheduler.hpp Scheduler.hpp
common.hpp common.hpp
util.hpp Audio.hpp Audio.cpp) util.hpp
Audio.hpp
Audio.cpp)
target_include_directories(cores PUBLIC . ../../external) target_include_directories(cores PUBLIC . ../../external)
target_link_libraries(cores PUBLIC gb n64) target_link_libraries(cores PUBLIC n64)

View File

@@ -12,18 +12,28 @@ add_library(n64-core
Mem.hpp Mem.hpp
RDP.cpp RDP.cpp
RDP.hpp RDP.hpp
mmio/VI.cpp mmio/AI.cpp
mmio/VI.hpp mmio/AI.hpp
mmio/Interrupt.cpp
mmio/Interrupt.hpp mmio/Interrupt.hpp
mmio/MI.cpp mmio/MI.cpp
mmio/MI.hpp 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.cpp
MMIO.hpp MMIO.hpp
RSP.cpp RSP.cpp
RSP.hpp RSP.hpp
rsp/decode.cpp rsp/decode.cpp
rsp/instructions.cpp mmio/AI.cpp mmio/AI.hpp) rsp/instructions.cpp)
target_include_directories(n64-core PRIVATE . .. ../../ mmio) target_include_directories(n64-core PRIVATE . .. ../../ mmio)
target_link_libraries(n64-core PUBLIC n64-cpu parallel-rdp) target_link_libraries(n64-core PUBLIC n64-cpu parallel-rdp)

View File

@@ -1,4 +1,4 @@
#include <MMIO.hpp> #include <n64/core/MMIO.hpp>
#include <util.hpp> #include <util.hpp>
#include <n64/core/Mem.hpp> #include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp> #include <n64/core/cpu/Registers.hpp>

View File

@@ -2,6 +2,9 @@
#include <n64/core/mmio/VI.hpp> #include <n64/core/mmio/VI.hpp>
#include <n64/core/mmio/MI.hpp> #include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/AI.hpp> #include <n64/core/mmio/AI.hpp>
#include <n64/core/mmio/PI.hpp>
#include <n64/core/mmio/RI.hpp>
#include <n64/core/mmio/SI.hpp>
#include <n64/core/RSP.hpp> #include <n64/core/RSP.hpp>
#include <n64/core/RDP.hpp> #include <n64/core/RDP.hpp>
@@ -14,6 +17,9 @@ struct MMIO {
VI vi; VI vi;
MI mi; MI mi;
AI ai; AI ai;
PI pi;
RI ri;
SI si;
RSP rsp; RSP rsp;
RDP rdp; RDP rdp;

View File

@@ -17,13 +17,16 @@ struct Mem {
T Read(Registers&, u32, s64); T Read(Registers&, u32, s64);
template <class T, bool tlb = true> template <class T, bool tlb = true>
void Write(Registers&, u32, T, s64); void Write(Registers&, u32, T, s64);
u8 pifRam[PIF_RAM_SIZE]{};
private: private:
friend struct SI;
friend struct PI;
friend struct AI; friend struct AI;
friend struct Cpu; friend struct Cpu;
friend struct RSP; friend struct RSP;
MMIO mmio; MMIO mmio;
std::vector<u8> cart, rdram, sram; std::vector<u8> 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]{}; u8 pifBootrom[PIF_BOOTROM_SIZE]{};
size_t romMask; size_t romMask;
}; };

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include <Cop0.hpp> #include <n64/core/cpu/registers/Cop0.hpp>
namespace natsukashii::n64::core { namespace natsukashii::n64::core {
struct Registers { struct Registers {

View File

@@ -1,7 +1,7 @@
#include <MI.hpp> #include <n64/core/mmio/MI.hpp>
#include <n64/core/cpu/Registers.hpp> #include <n64/core/cpu/Registers.hpp>
#include <util.hpp> #include <util.hpp>
#include <Interrupt.hpp> #include <n64/core/mmio/Interrupt.hpp>
#define MI_VERSION_REG 0x02020102 #define MI_VERSION_REG 0x02020102

View File

@@ -0,0 +1,75 @@
#include <n64/core/mmio/PI.hpp>
#include <util.hpp>
#include <n64/core/Mem.hpp>
#include <n64/core/cpu/Registers.hpp>
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);
}
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <common.hpp>
#include <n64/core/mmio/Interrupt.hpp>
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]{};
};
}

View File

@@ -0,0 +1,71 @@
#include <n64/core/mmio/PIF.hpp>
#include <n64/core/Mem.hpp>
#include <util.hpp>
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;
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <common.hpp>
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&);
}

View File

@@ -0,0 +1,25 @@
#include <n64/core/mmio/RI.hpp>
#include <util.hpp>
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);
}
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <common.hpp>
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);
};
}

View File

@@ -0,0 +1,55 @@
#include <n64/core/mmio/SI.hpp>
#include <n64/core/Mem.hpp>
#include <util.hpp>
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);
}
}
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <common.hpp>
#include <n64/core/mmio/Interrupt.hpp>
#include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/PIF.hpp>
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);
};
}

View File

@@ -1,7 +1,7 @@
#include <VI.hpp> #include <n64/core/mmio/VI.hpp>
#include <util.hpp> #include <util.hpp>
#include <n64/core/cpu/Registers.hpp> #include <n64/core/cpu/Registers.hpp>
#include <MI.hpp> #include <n64/core/mmio/MI.hpp>
#include <n64/core/mmio/Interrupt.hpp> #include <n64/core/mmio/Interrupt.hpp>
namespace natsukashii::n64::core { namespace natsukashii::n64::core {

View File

@@ -1,10 +1,10 @@
#include "ParallelRDPWrapper.hpp" #include <ParallelRDPWrapper.hpp>
#include "n64/core/RDP.hpp" #include <n64/core/RDP.hpp>
#include <memory> #include <memory>
#include "parallel-rdp-standalone/parallel-rdp/rdp_device.hpp" #include <parallel-rdp-standalone/parallel-rdp/rdp_device.hpp>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <SDL2/SDL_vulkan.h> #include <SDL2/SDL_vulkan.h>
#include "util.hpp" #include <util.hpp>
using namespace natsukashii::n64; using namespace natsukashii::n64;
using namespace natsukashii::core; using namespace natsukashii::core;

View File

@@ -5,7 +5,12 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(SDL2 REQUIRED) 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) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
@@ -15,5 +20,15 @@ FetchContent_Declare(
) )
FetchContent_MakeAvailable(argparse) 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_link_libraries(natsukashii-sdl PRIVATE cores argparse::argparse SDL2)
target_compile_definitions(natsukashii-sdl PUBLIC GRANITE_VULKAN_MT)

View File

@@ -3,12 +3,9 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_vulkan.h> #include <SDL2/SDL_vulkan.h>
#include <string> #include <string>
#include <memory>
#include <util.hpp> #include <util.hpp>
namespace natsukashii::frontend { namespace natsukashii::frontend {
using namespace natsukashii::core;
struct App { struct App {
~App(); ~App();
App(const std::string&, const std::string&); App(const std::string&, const std::string&);