Fix parallel-rdp integration and reset whole state upon loading rom

This commit is contained in:
CocoSimone
2022-08-13 11:44:35 +02:00
parent ed34d9c9ba
commit e2313c212c
41 changed files with 250 additions and 92 deletions

View File

@@ -92,11 +92,11 @@ public:
}
uint32_t get_surface_width() override {
return 800;
return 640;
}
uint32_t get_surface_height() override {
return 600;
return 480;
}
bool alive(Vulkan::WSI &wsi_) override {
@@ -106,6 +106,15 @@ public:
void poll_input() override { }
void event_frame_tick(double frame, double elapsed) override { }
const VkApplicationInfo *get_application_info() override {
return &appInfo;
}
VkApplicationInfo appInfo {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.apiVersion = VK_API_VERSION_1_1
};
};
Program* fullscreen_quad_program;

View File

@@ -1,5 +1,4 @@
#pragma once
#define VULKAN_DEBUG
#include <Core.hpp>
#include <wsi.hpp>
#include <SDL2/SDL.h>
@@ -26,7 +25,6 @@ class SDLParallelRdpWindowInfo : public ParallelRdpWindowInfo {
}
};
static u32 windowID;
VkQueue GetGraphicsQueue();
VkInstance GetVkInstance();
VkPhysicalDevice GetVkPhysicalDevice();

View File

@@ -3,6 +3,8 @@ project(natsukashii)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED true)
add_compile_definitions(VULKAN_DEBUG)
add_subdirectory(n64)
add_subdirectory(frontend)
@@ -12,3 +14,4 @@ add_executable(natsukashii main.cpp)
target_link_libraries(natsukashii PUBLIC frontend n64 fmt)
target_include_directories(natsukashii PUBLIC . ../external)
target_compile_options(natsukashii PUBLIC -Wpedantic -Wimplicit-fallthrough -Wextra -Wall)

View File

@@ -9,35 +9,35 @@ void App::Run() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
//ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
done = true;
if (window.gotClosed(event))
done = true;
if(event.type == SDL_KEYDOWN) {
switch(event.key.keysym.sym) {
case SDLK_o: {
nfdchar_t* outpath;
const nfdu8filteritem_t filter {"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if(result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
switch(event.type) {
case SDL_QUIT: done = true; break;
case SDL_WINDOWEVENT:
done = window.gotClosed(event);
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_o: {
nfdchar_t* outpath;
const nfdu8filteritem_t filter {"Nintendo 64 roms", "n64,z64,v64,N64,Z64,V64"};
nfdresult_t result = NFD_OpenDialog(&outpath, &filter, 1, nullptr);
if(result == NFD_OKAY) {
core.LoadROM(outpath);
NFD_FreePath(outpath);
}
} break;
} break;
}
}
core.PollInputs(event);
}
if(core.romLoaded)
core.Run();
if(core.romLoaded)
if(core.romLoaded) {
core.Run(window);
UpdateScreenParallelRdp(window, core.GetVI());
else
} else {
UpdateScreenParallelRdpNoGame(window);
}
SDL_Delay(16);
SDL_Delay(1);
}
}

View File

@@ -1,5 +1,4 @@
#pragma once
#include <Core.hpp>
#include <imgui/Window.hpp>
struct App {

View File

@@ -12,8 +12,7 @@ Window::Window(n64::Core& core) {
}
[[nodiscard]] bool Window::gotClosed(SDL_Event event) {
return event.type == SDL_WINDOWEVENT
&& event.window.event == SDL_WINDOWEVENT_CLOSE
return event.window.event == SDL_WINDOWEVENT_CLOSE
&& event.window.windowID == SDL_GetWindowID(window);
}
@@ -177,18 +176,18 @@ Window::~Window() {
vkDestroyInstance(instance, nullptr);
}
ImDrawData* Window::Present() {
ImDrawData* Window::Present(n64::Core& core) {
//ImGui_ImplVulkan_NewFrame();
//ImGui_ImplSDL2_NewFrame(window);
//ImGui::NewFrame();
//
Render();
Render(core);
//ImGui::Render();
return ImGui::GetDrawData();
}
void Window::Render() {
void Window::Render(n64::Core& core) {
ImGui::BeginMainMenuBar();
if(ImGui::BeginMenu("File")) {
if(ImGui::BeginMenu("Open")) {

View File

@@ -10,15 +10,14 @@
struct Window {
explicit Window(n64::Core& core);
~Window();
ImDrawData* Present();
ImDrawData* Present(n64::Core& core);
[[nodiscard]] bool gotClosed(SDL_Event event);
private:
SDL_Window* window;
n64::Core core;
void InitSDL();
void InitImgui();
void Render();
void Render(n64::Core& core);
VkInstance instance{};
VkPhysicalDevice physicalDevice{};

View File

@@ -1,8 +1,8 @@
#define SDL_MAIN_HANDLED
#include <frontend/App.hpp>
int main() {
App* app = new App;
app->Run();
int main(int argc, char* argv[]) {
App app;
app.Run();
return 0;
}

View File

@@ -12,6 +12,7 @@ target_link_libraries(n64 PUBLIC core)
target_include_directories(n64 PUBLIC
.
..
../frontend/imgui
../../external
../../external/imgui/imgui
../../external/imgui/imgui/backends

View File

@@ -1,15 +1,28 @@
#include <Core.hpp>
#include <ParallelRDPWrapper.hpp>
#include <Window.hpp>
namespace n64 {
Core::Core() {
Reset();
}
void Core::Reset() {
cpu.Reset();
mem.Reset();
romLoaded = false;
}
void Core::LoadROM(const std::string& rom) {
Reset();
mem.LoadROM(rom);
romLoaded = true;
}
void Core::Run() {
void Core::Run(Window& window) {
MMIO& mmio = mem.mmio;
for(mmio.vi.current = 0; mmio.vi.current < 262; mmio.vi.current++) {
for(int i = 0; i < 6000; i++) {
for (int i = 0; i < 6000; i++) {
cpu.Step(mem);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
@@ -17,7 +30,7 @@ void Core::Run() {
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
}
if((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
InterruptRaise(mmio.mi, cpu.regs, Interrupt::VI);
}
}

View File

@@ -4,12 +4,14 @@
#include <Mem.hpp>
#include <string>
struct Window;
namespace n64 {
struct Core {
~Core() = default;
Core() = default;
Core();
void Reset();
void LoadROM(const std::string&);
void Run();
void Run(Window&);
void PollInputs(SDL_Event);
VI& GetVI() { return mem.mmio.vi; }
u8* GetRDRAM() { return mem.rdram.data(); }

View File

@@ -4,18 +4,18 @@
#include <util.hpp>
namespace n64 {
void Cpu::Reset() {
regs.Reset();
}
Cpu::Cpu() {
#ifndef NDEBUG
if (cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64, &handle)) {
util::panic("Could not initialize capstone!\n");
}
#endif
}
Cpu::~Cpu() {
#ifndef NDEBUG
cs_close(&handle);
#endif
}
inline bool ShouldServiceInterrupt(Registers& regs) {
@@ -99,21 +99,16 @@ inline void HandleInterrupt(Registers& regs) {
}
void Cpu::LogInstruction(u32 instruction) {
#ifndef NDEBUG
/*u8 code[4]{};
u32 bswapped = be32toh(instruction);
memcpy(code, &instruction, 4);
count = cs_disasm(handle, code, 4, regs.pc, 0, &insn);
count = cs_disasm(handle, reinterpret_cast<u8*>(&instruction), 4, regs.pc, 0, &insn);
if (count > 0) {
for(auto j = 0; j < count; j++) {
printf("%016lX:\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
util::logdebug("0x{:016X}:\t{}\t\t{}\n", insn[j].address, insn[j].mnemonic, insn[j].op_str);
}
cs_free(insn, count);
} else {
util::panic("Failed to disassemble {:08X}!", instruction);
}*/
#endif
util::logdebug("Failed to disassemble 0x{:08X}!", instruction);
}
}
void Cpu::Step(Mem& mem) {
@@ -123,8 +118,14 @@ void Cpu::Step(Mem& mem) {
CheckCompareInterrupt(mem.mmio.mi, regs);
static int count = 0;
if(regs.gpr[30] == -1 && count < 1) {
util::logdebug("Test passed!\n");
count++;
}
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
LogInstruction(instruction);
//LogInstruction(instruction);
HandleInterrupt(regs);

View File

@@ -1,22 +1,19 @@
#pragma once
#include <Registers.hpp>
#include <Mem.hpp>
#ifndef NDEBUG
#include <capstone/capstone.h>
#endif
namespace n64 {
struct Cpu {
Cpu();
~Cpu();
void Reset();
void Step(Mem&);
Registers regs;
private:
#ifndef NDEBUG
csh handle{};
cs_insn *insn = nullptr;
size_t count{};
#endif
friend struct Cop1;
void LogInstruction(u32);

View File

@@ -4,6 +4,21 @@
#include <n64/core/cpu/Registers.hpp>
namespace n64 {
MMIO::MMIO () {
Reset();
}
void MMIO::Reset() {
rsp.Reset();
rdp.Reset();
mi.Reset();
vi.Reset();
ai.Reset();
pi.Reset();
ri.Reset();
si.Reset();
}
u32 MMIO::Read(u32 addr) {
switch (addr) {
case 0x04040000 ... 0x040FFFFF: return rsp.Read(addr);

View File

@@ -13,7 +13,8 @@ struct Mem;
struct Registers;
struct MMIO {
MMIO() = default;
MMIO();
void Reset();
VI vi;
MI mi;
AI ai;

View File

@@ -7,8 +7,16 @@
namespace n64 {
Mem::Mem() {
Reset();
}
void Mem::Reset() {
rdram.resize(RDRAM_SIZE);
sram.resize(SRAM_SIZE);
std::fill(rdram.begin(), rdram.end(), 0);
std::fill(sram.begin(), sram.end(), 0);
romMask = 0;
mmio.Reset();
}
void Mem::LoadROM(const std::string& filename) {
@@ -21,12 +29,13 @@ void Mem::LoadROM(const std::string& filename) {
file.seekg(0, std::ios::end);
auto size = file.tellg();
auto size_adjusted = util::NextPow2(size);
romMask = size_adjusted - 1;
auto sizeAdjusted = util::NextPow2(size);
romMask = sizeAdjusted - 1;
file.seekg(0, std::ios::beg);
cart.resize(size_adjusted);
file.read(reinterpret_cast<char*>(cart.data()), size);
std::fill(cart.begin(), cart.end(), 0);
cart.resize(sizeAdjusted);
cart.insert(cart.begin(), std::istream_iterator<u8>(file), std::istream_iterator<u8>());
file.close();
util::SwapN64Rom(size, cart.data());
@@ -107,8 +116,6 @@ void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) {
case 0x04001000 ... 0x04001FFF: util::WriteAccess<T>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x1FBFFFFF: util::WriteAccess<T>(cart.data(), paddr & romMask, val); break;
case 0x1FC00000 ... 0x1FC007BF: util::WriteAccess<T>(pifBootrom, paddr & PIF_BOOTROM_DSIZE, val); break;
case 0x1FC007C0 ... 0x1FC007FF: util::WriteAccess<T>(pifRam, paddr & PIF_RAM_DSIZE, val); break;
case 0x00800000 ... 0x03FFFFFF: case 0x04002000 ... 0x0403FFFF:
case 0x04200000 ... 0x042FFFFF:

View File

@@ -9,6 +9,7 @@ struct Registers;
struct Mem {
~Mem() = default;
Mem();
void Reset();
void LoadROM(const std::string&);
[[nodiscard]] auto GetRDRAM() -> u8* {
return rdram.data();

View File

@@ -5,6 +5,15 @@
#include <n64/core/mmio/Interrupt.hpp>
namespace n64 {
RDP::RDP() {
Reset();
}
void RDP::Reset() {
dpc.status.raw = 0x80;
memset(cmd_buf, 0, 0x100000);
}
static const int cmd_lens[64] = {
2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,

View File

@@ -48,10 +48,11 @@ struct DPC {
};
struct RDP {
DPC dpc{.status{.raw = 0x80}};
DPC dpc;
u32 cmd_buf[0xFFFFF]{};
RDP() = default;
RDP();
void Reset();
auto Read(u32 addr) const -> u32;
void Write(u32 addr, u32 val);

View File

@@ -4,6 +4,31 @@
#include <n64/core/mmio/Interrupt.hpp>
namespace n64 {
RSP::RSP() {
Reset();
}
void RSP::Reset() {
spStatus.raw = 0;
spStatus.halt = true;
oldPC = 0;
pc = 0;
nextPC = 0;
spDMASPAddr.raw = 0;
spDMADRAMAddr.raw = 0;
spDMARDLen.raw = 0;
spDMAWRLen.raw = 0;
memset(dmem, 0, DMEM_SIZE);
memset(imem, 0, IMEM_SIZE);
memset(vpr, 0, 32 * sizeof(VPR));
memset(gpr, 0, 32);
vce = 0;
acc = {.h={}, .m={}, .l={}};
vcc = {.l = {}, .h = {}};
vco = {.l = {}, .h = {}};
semaphore = false;
}
void RSP::Step(MI& mi, Registers& regs, RDP& rdp) {
if(!spStatus.halt) {
gpr[0] = 0;

View File

@@ -105,12 +105,13 @@ struct Registers;
} while(0)
struct RSP {
RSP() = default;
RSP();
void Reset();
void Step(MI& mi, Registers& regs, RDP& rdp);
auto Read(u32 addr) const -> u32;
void Write(Mem& mem, Registers& regs, u32 addr, u32 value);
void Exec(MI& mi, Registers& regs, RDP& rdp, u32 instr);
SPStatus spStatus{.raw = 1};
SPStatus spStatus;
u16 oldPC{}, pc{}, nextPC = 4;
SPDMASPAddr spDMASPAddr{};
SPDMADRAMAddr spDMADRAMAddr{};

View File

@@ -2,6 +2,10 @@
namespace n64 {
Registers::Registers() {
Reset();
}
void Registers::Reset() {
delaySlot = false;
prevDelaySlot = false;
memset(gpr, 0, 32*sizeof(s64));
@@ -14,6 +18,8 @@ Registers::Registers() {
gpr[20] = 0x0000000000000001;
gpr[22] = 0x000000000000003F;
gpr[29] = (s64)0xFFFFFFFFA4001FF0;
cop0.Reset();
cop1.Reset();
}
void Registers::SetPC(s64 val) {

View File

@@ -5,6 +5,7 @@
namespace n64 {
struct Registers {
Registers();
void Reset();
void SetPC(s64);
s64 gpr[32];
Cop0 cop0;

View File

@@ -169,7 +169,7 @@ void Cpu::bllink(u32 instr, bool cond) {
void Cpu::lui(u32 instr) {
s64 val = (s16)instr;
val *= 65536;
val <<= 16;
regs.gpr[RT(instr)] = val;
}

View File

@@ -5,12 +5,16 @@
namespace n64 {
Cop0::Cop0() {
Reset();
}
void Cop0::Reset() {
cause.raw = 0xB000007C;
random = 0x0000001F;
status.raw = 0x241000E0;
wired = 64;
index = 64;
PRId = 0x00000B00;
PRId = 0x00000B22;
Config = 0x7006E463;
EPC = 0xFFFFFFFFFFFFFFFF;
ErrorEPC = 0xFFFFFFFFFFFFFFFF;

View File

@@ -159,6 +159,8 @@ struct Cop0 {
template<class T>
void SetReg(u8, T);
void Reset();
PageMask pageMask{};
EntryHi entryHi{};
EntryLo entryLo0{}, entryLo1{};

View File

@@ -4,6 +4,16 @@
#include <util.hpp>
namespace n64 {
Cop1::Cop1() {
Reset();
}
void Cop1::Reset() {
fcr0 = 0xa00;
fcr31.raw = 0;
memset(fgr, 0, 32 * sizeof(FGR));
}
void Cop1::decode(Cpu& cpu, u32 instr) {
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {

View File

@@ -50,9 +50,11 @@ struct Cpu;
struct Registers;
struct Cop1 {
u32 fcr0;
FCR31 fcr31;
FGR fgr[32];
Cop1();
u32 fcr0{};
FCR31 fcr31{};
FGR fgr[32]{};
void Reset();
void decode(Cpu&, u32);
friend struct Cpu;
private:

View File

@@ -5,6 +5,18 @@
#include <n64/core/Audio.hpp>
namespace n64 {
void AI::Reset() {
dmaEnable = 0;
dacRate = 0;
bitrate = 0;
dmaCount = 0;
memset(dmaLen, 0, 2);
memset(dmaAddr, 0, 2);
dmaAddrCarry = false;
cycles = 0;
dac = {44100, N64_CPU_FREQ / dac.freq, 16};
}
auto AI::Read(u32 addr) const -> u32 {
switch(addr) {
case 0x04500004: return dmaLen[0];

View File

@@ -8,6 +8,7 @@ struct Registers;
struct AI {
AI() = default;
void Reset();
auto Read(u32) const -> u32;
void Write(Mem&, Registers&, u32, u32);
void Step(Mem&, Registers&, int);

View File

@@ -7,6 +7,10 @@
namespace n64 {
MI::MI() {
Reset();
}
void MI::Reset() {
miIntrMask.raw = 0;
miIntr.raw = 0;
miMode = 0;

View File

@@ -20,6 +20,7 @@ struct Registers;
struct MI {
MI();
void Reset();
[[nodiscard]] auto Read(u32) const -> u32;
void Write(Registers& regs, u32, u32);

View File

@@ -4,6 +4,19 @@
#include <n64/core/cpu/Registers.hpp>
namespace n64 {
PI::PI() {
Reset();
}
void PI::Reset() {
dramAddr = 0;
cartAddr = 0;
rdLen = 0;
wrLen = 0;
status = 0;
memset(stub, 0, 8);
}
auto PI::Read(MI& mi, u32 addr) const -> u32 {
switch(addr) {
case 0x04600000: return dramAddr;

View File

@@ -8,7 +8,8 @@ struct Mem;
struct Registers;
struct PI {
PI() = default;
PI();
void Reset();
auto Read(MI&, u32) const -> u32;
void Write(Mem&, Registers&, u32, u32);
u32 dramAddr{}, cartAddr{};

View File

@@ -2,6 +2,17 @@
#include <util.hpp>
namespace n64 {
RI::RI() {
Reset();
}
void RI::Reset() {
mode = 0xE;
config = 0x40;
select = 0x14;
refresh = 0x63634;
}
auto RI::Read(u32 addr) const -> u32 {
switch(addr) {
case 0x04700000: return mode;

View File

@@ -4,7 +4,8 @@
namespace n64 {
struct RI {
RI() = default;
RI();
void Reset();
u32 mode{0xE}, config{0x40}, select{0x14}, refresh{0x63634};
auto Read(u32) const -> u32;
void Write(u32, u32);

View File

@@ -3,6 +3,15 @@
#include <util.hpp>
namespace n64 {
SI::SI() {
Reset();
}
void SI::Reset() {
status.raw = 0;
dramAddr = 0;
controller.raw = 0;
}
auto SI::Read(MI& mi, u32 addr) const -> u32 {
switch(addr) {

View File

@@ -21,7 +21,8 @@ union SIStatus {
struct Mem;
struct SI {
SI() = default;
SI();
void Reset();
SIStatus status{};
u32 dramAddr{};
Controller controller{};

View File

@@ -6,13 +6,11 @@
namespace n64 {
VI::VI () {
status.raw = 0xF;
Reset();
}
void VI::Reset() {
intr = 256;
origin = 0;
width = 320;
current = 0;
vsync = 0;
hsync = 0;
numHalflines = 262;
numFields = 1;
cyclesPerHalfline = 1000;
@@ -29,8 +27,8 @@ u32 VI::Read(u32 paddr) const {
case 0x04400018: return vsync;
case 0x0440001C: return hsync;
case 0x04400020: return hsyncLeap.raw;
case 0x04400024: return hvideo.raw;
case 0x04400028: return vvideo.raw;
case 0x04400024: return hstart.raw;
case 0x04400028: return vstart.raw;
case 0x0440002C: return vburst;
case 0x04400030: return xscale.raw;
case 0x04400034: return yscale.raw;
@@ -72,8 +70,8 @@ void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
hsync = val & 0x3FF;
} break;
case 0x04400020: hsyncLeap.raw = val; break;
case 0x04400024: hvideo.raw = val; break;
case 0x04400028: vvideo.raw = val; break;
case 0x04400024: hstart.raw = val; break;
case 0x04400028: vstart.raw = val; break;
case 0x0440002C: vburst = val; break;
case 0x04400030: xscale.raw = val; break;
case 0x04400034: yscale.raw = val; break;

View File

@@ -87,10 +87,10 @@ struct Registers;
struct VI {
VI();
void Reset();
[[nodiscard]] u32 Read(u32) const;
void Write(MI&, Registers&, u32, u32);
AxisScale xscale{}, yscale{};
VIVideo hvideo{}, vvideo{};
VIHsyncLeap hsyncLeap{};
VIStatus status{};
VIBurst burst{};

View File

@@ -8,7 +8,7 @@
namespace util {
enum MessageType : u8 {
Info, Warn, Error, Debug
Info, Warn, Error
};
template <MessageType messageType = Info, typename ...Args>
@@ -18,7 +18,7 @@ constexpr void print(const std::string& fmt, Args... args) {
exit(-1);
} else if constexpr(messageType == Warn) {
fmt::print(fg(fmt::color::yellow), fmt, args...);
} else if constexpr(messageType == Info || messageType == Debug) {
} else if constexpr(messageType == Info) {
fmt::print(fmt, args...);
}
}