N64 MMIO integration complete
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <MMIO.hpp>
|
||||
#include <n64/core/MMIO.hpp>
|
||||
#include <util.hpp>
|
||||
#include <n64/core/Mem.hpp>
|
||||
#include <n64/core/cpu/Registers.hpp>
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include <n64/core/mmio/VI.hpp>
|
||||
#include <n64/core/mmio/MI.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/RDP.hpp>
|
||||
|
||||
@@ -14,6 +17,9 @@ struct MMIO {
|
||||
VI vi;
|
||||
MI mi;
|
||||
AI ai;
|
||||
PI pi;
|
||||
RI ri;
|
||||
SI si;
|
||||
RSP rsp;
|
||||
RDP rdp;
|
||||
|
||||
|
||||
@@ -17,13 +17,16 @@ struct Mem {
|
||||
T Read(Registers&, u32, s64);
|
||||
template <class T, bool tlb = true>
|
||||
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<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]{};
|
||||
size_t romMask;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <Cop0.hpp>
|
||||
#include <n64/core/cpu/registers/Cop0.hpp>
|
||||
|
||||
namespace natsukashii::n64::core {
|
||||
struct Registers {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <MI.hpp>
|
||||
#include <n64/core/mmio/MI.hpp>
|
||||
#include <n64/core/cpu/Registers.hpp>
|
||||
#include <util.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
#include <n64/core/mmio/Interrupt.hpp>
|
||||
|
||||
#define MI_VERSION_REG 0x02020102
|
||||
|
||||
|
||||
75
src/core/n64/core/mmio/PI.cpp
Normal file
75
src/core/n64/core/mmio/PI.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
19
src/core/n64/core/mmio/PI.hpp
Normal file
19
src/core/n64/core/mmio/PI.hpp
Normal 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]{};
|
||||
};
|
||||
}
|
||||
71
src/core/n64/core/mmio/PIF.cpp
Normal file
71
src/core/n64/core/mmio/PIF.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
19
src/core/n64/core/mmio/PIF.hpp
Normal file
19
src/core/n64/core/mmio/PIF.hpp
Normal 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&);
|
||||
}
|
||||
25
src/core/n64/core/mmio/RI.cpp
Normal file
25
src/core/n64/core/mmio/RI.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
13
src/core/n64/core/mmio/RI.hpp
Normal file
13
src/core/n64/core/mmio/RI.hpp
Normal 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);
|
||||
};
|
||||
|
||||
}
|
||||
55
src/core/n64/core/mmio/SI.cpp
Normal file
55
src/core/n64/core/mmio/SI.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
32
src/core/n64/core/mmio/SI.hpp
Normal file
32
src/core/n64/core/mmio/SI.hpp
Normal 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);
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <VI.hpp>
|
||||
#include <n64/core/mmio/VI.hpp>
|
||||
#include <util.hpp>
|
||||
#include <n64/core/cpu/Registers.hpp>
|
||||
#include <MI.hpp>
|
||||
#include <n64/core/mmio/MI.hpp>
|
||||
#include <n64/core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace natsukashii::n64::core {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "ParallelRDPWrapper.hpp"
|
||||
#include "n64/core/RDP.hpp"
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
#include <n64/core/RDP.hpp>
|
||||
#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_vulkan.h>
|
||||
#include "util.hpp"
|
||||
#include <util.hpp>
|
||||
|
||||
using namespace natsukashii::n64;
|
||||
using namespace natsukashii::core;
|
||||
|
||||
@@ -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)
|
||||
@@ -3,12 +3,9 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <util.hpp>
|
||||
|
||||
namespace natsukashii::frontend {
|
||||
using namespace natsukashii::core;
|
||||
|
||||
struct App {
|
||||
~App();
|
||||
App(const std::string&, const std::string&);
|
||||
|
||||
Reference in New Issue
Block a user