Fixed endianness for parallel-rdp

This commit is contained in:
CocoSimone
2022-08-16 11:48:12 +02:00
parent e2313c212c
commit 701c0de18a
13 changed files with 172 additions and 60 deletions

View File

@@ -26,3 +26,5 @@ using m128 = __m128i;
#define GiB ((MiB) * 1024) #define GiB ((MiB) * 1024)
#define N64_CPU_FREQ 93750000 #define N64_CPU_FREQ 93750000
#define N64_CYCLES_PER_FRAME ((N64_CPU_FREQ) / 60) #define N64_CYCLES_PER_FRAME ((N64_CPU_FREQ) / 60)
#define HALF_ADDRESS(addr) ((addr) ^ 2)
#define BYTE_ADDRESS(addr) ((addr) ^ 3)

View File

@@ -4,6 +4,9 @@
struct App { struct App {
App() : window(core) {}; App() : window(core) {};
void Run(); void Run();
inline void LoadROM(const std::string& path) {
core.LoadROM(path);
}
private: private:
n64::Core core; n64::Core core;
Window window; Window window;

View File

@@ -6,7 +6,7 @@
Window::Window(n64::Core& core) { Window::Window(n64::Core& core) {
InitSDL(); InitSDL();
InitParallelRDP(core.GetRDRAM(), window); InitParallelRDP(core.mem.GetRDRAM(), window);
//InitImgui(); //InitImgui();
NFD::Init(); NFD::Init();
} }

View File

@@ -3,6 +3,9 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
App app; App app;
if(argc > 1) {
app.LoadROM(argv[1]);
}
app.Run(); app.Run();
return 0; return 0;
} }

View File

@@ -14,9 +14,9 @@ struct Core {
void Run(Window&); void Run(Window&);
void PollInputs(SDL_Event); void PollInputs(SDL_Event);
VI& GetVI() { return mem.mmio.vi; } VI& GetVI() { return mem.mmio.vi; }
u8* GetRDRAM() { return mem.rdram.data(); }
bool romLoaded = false; bool romLoaded = false;
private: private:
friend struct ::Window;
Mem mem; Mem mem;
Cpu cpu; Cpu cpu;
}; };

View File

@@ -118,14 +118,8 @@ void Cpu::Step(Mem& mem) {
CheckCompareInterrupt(mem.mmio.mi, regs); 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); u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
//LogInstruction(instruction); LogInstruction(instruction);
HandleInterrupt(regs); HandleInterrupt(regs);

View File

@@ -11,9 +11,7 @@ Mem::Mem() {
} }
void Mem::Reset() { void Mem::Reset() {
rdram.resize(RDRAM_SIZE);
sram.resize(SRAM_SIZE); sram.resize(SRAM_SIZE);
std::fill(rdram.begin(), rdram.end(), 0);
std::fill(sram.begin(), sram.end(), 0); std::fill(sram.begin(), sram.end(), 0);
romMask = 0; romMask = 0;
mmio.Reset(); mmio.Reset();
@@ -38,7 +36,7 @@ void Mem::LoadROM(const std::string& filename) {
cart.insert(cart.begin(), std::istream_iterator<u8>(file), std::istream_iterator<u8>()); cart.insert(cart.begin(), std::istream_iterator<u8>(file), std::istream_iterator<u8>());
file.close(); file.close();
util::SwapN64Rom(size, cart.data()); util::SwapN64Rom(sizeAdjusted, cart.data());
memcpy(mmio.rsp.dmem, cart.data(), 0x1000); memcpy(mmio.rsp.dmem, cart.data(), 0x1000);
} }
@@ -68,14 +66,56 @@ T Mem::Read(Registers& regs, u32 vaddr, s64 pc) {
} }
switch(paddr) { switch(paddr) {
case 0x00000000 ... 0x007FFFFF: return util::ReadAccess<T>(rdram.data(), paddr & RDRAM_DSIZE); case 0x00000000 ... 0x007FFFFF:
case 0x04000000 ... 0x04000FFF: return util::ReadAccess<T>(mmio.rsp.dmem, paddr & DMEM_DSIZE); if constexpr (sizeof(T) == 1) {
case 0x04001000 ... 0x04001FFF: return util::ReadAccess<T>(mmio.rsp.imem, paddr & IMEM_DSIZE); return util::ReadAccess<T>(mmio.rdp.dram.data(), BYTE_ADDRESS(paddr) & RDRAM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE);
} else {
return util::ReadAccess<T>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE);
}
case 0x04000000 ... 0x04000FFF:
if constexpr (sizeof(T) == 1) {
return util::ReadAccess<T>(mmio.rsp.dmem, BYTE_ADDRESS(paddr) & DMEM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(mmio.rsp.dmem, HALF_ADDRESS(paddr) & DMEM_DSIZE);
} else {
return util::ReadAccess<T>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
}
case 0x04001000 ... 0x04001FFF:
if constexpr (sizeof(T) == 1) {
return util::ReadAccess<T>(mmio.rsp.imem, BYTE_ADDRESS(paddr) & IMEM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(mmio.rsp.imem, HALF_ADDRESS(paddr) & IMEM_DSIZE);
} else {
return util::ReadAccess<T>(mmio.rsp.imem, paddr & IMEM_DSIZE);
}
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: return mmio.Read(paddr); case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF: return util::ReadAccess<T>(cart.data(), paddr & romMask); case 0x10000000 ... 0x1FBFFFFF:
case 0x1FC00000 ... 0x1FC007BF: return util::ReadAccess<T>(pifBootrom, paddr & PIF_BOOTROM_DSIZE); if constexpr (sizeof(T) == 1) {
case 0x1FC007C0 ... 0x1FC007FF: return util::ReadAccess<T>(pifRam, paddr & PIF_RAM_DSIZE); return util::ReadAccess<T>(cart.data(), BYTE_ADDRESS(paddr) & romMask);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(cart.data(), HALF_ADDRESS(paddr) & romMask);
} else {
return util::ReadAccess<T>(cart.data(), paddr & romMask);
}
case 0x1FC00000 ... 0x1FC007BF:
if constexpr (sizeof(T) == 1) {
return util::ReadAccess<T>(pifBootrom, BYTE_ADDRESS(paddr) & PIF_BOOTROM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(pifBootrom, HALF_ADDRESS(paddr) & PIF_BOOTROM_DSIZE);
} else {
return util::ReadAccess<T>(pifBootrom, paddr & PIF_BOOTROM_DSIZE);
}
case 0x1FC007C0 ... 0x1FC007FF:
if constexpr (sizeof(T) == 1) {
return util::ReadAccess<T>(pifRam, BYTE_ADDRESS(paddr) & PIF_RAM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(pifRam, HALF_ADDRESS(paddr) & PIF_RAM_DSIZE);
} else {
return util::ReadAccess<T>(pifRam, paddr & PIF_RAM_DSIZE);
}
case 0x00800000 ... 0x03FFFFFF: case 0x04002000 ... 0x0403FFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04002000 ... 0x0403FFFF:
case 0x04200000 ... 0x042FFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:
@@ -111,12 +151,44 @@ void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) {
} }
switch(paddr) { switch(paddr) {
case 0x00000000 ... 0x007FFFFF: util::WriteAccess<T>(rdram.data(), paddr & RDRAM_DSIZE, val); break; case 0x00000000 ... 0x007FFFFF:
case 0x04000000 ... 0x04000FFF: util::WriteAccess<T>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val); break; if constexpr (sizeof(T) == 1) {
case 0x04001000 ... 0x04001FFF: util::WriteAccess<T>(mmio.rsp.imem, paddr & IMEM_DSIZE, val); break; util::WriteAccess<T>(mmio.rdp.dram.data(), BYTE_ADDRESS(paddr) & RDRAM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE, val);
} else {
util::WriteAccess<T>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE, val);
}
break;
case 0x04000000 ... 0x04000FFF:
if constexpr (sizeof(T) == 1) {
util::WriteAccess<T>(mmio.rsp.dmem, BYTE_ADDRESS(paddr) & DMEM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(mmio.rsp.dmem, HALF_ADDRESS(paddr) & DMEM_DSIZE, val);
} else {
util::WriteAccess<T>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
}
break;
case 0x04001000 ... 0x04001FFF:
if constexpr (sizeof(T) == 1) {
util::WriteAccess<T>(mmio.rsp.imem, BYTE_ADDRESS(paddr) & IMEM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(mmio.rsp.imem, HALF_ADDRESS(paddr) & IMEM_DSIZE, val);
} else {
util::WriteAccess<T>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
}
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: 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: mmio.Write(*this, regs, paddr, val); break;
case 0x1FC007C0 ... 0x1FC007FF: util::WriteAccess<T>(pifRam, paddr & PIF_RAM_DSIZE, val); break; case 0x1FC007C0 ... 0x1FC007FF:
if constexpr (sizeof(T) == 1) {
util::WriteAccess<T>(pifRam, BYTE_ADDRESS(paddr) & PIF_RAM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(pifRam, HALF_ADDRESS(paddr) & PIF_RAM_DSIZE, val);
} else {
util::WriteAccess<T>(pifRam, paddr & PIF_RAM_DSIZE, val);
}
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04002000 ... 0x0403FFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04002000 ... 0x0403FFFF:
case 0x04200000 ... 0x042FFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:

View File

@@ -12,7 +12,7 @@ struct Mem {
void Reset(); void Reset();
void LoadROM(const std::string&); void LoadROM(const std::string&);
[[nodiscard]] auto GetRDRAM() -> u8* { [[nodiscard]] auto GetRDRAM() -> u8* {
return rdram.data(); return mmio.rdp.dram.data();
} }
template <class T, bool tlb = true> template <class T, bool tlb = true>
T Read(Registers&, u32, s64); T Read(Registers&, u32, s64);
@@ -27,7 +27,7 @@ private:
friend struct RSP; friend struct RSP;
friend struct Core; friend struct Core;
MMIO mmio; MMIO mmio;
std::vector<u8> cart, rdram, sram; std::vector<u8> cart, sram;
u8 pifBootrom[PIF_BOOTROM_SIZE]{}; u8 pifBootrom[PIF_BOOTROM_SIZE]{};
size_t romMask; size_t romMask;
}; };

View File

@@ -11,6 +11,8 @@ RDP::RDP() {
void RDP::Reset() { void RDP::Reset() {
dpc.status.raw = 0x80; dpc.status.raw = 0x80;
dram.resize(RDRAM_SIZE);
std::fill(dram.begin(), dram.end(), 0);
memset(cmd_buf, 0, 0x100000); memset(cmd_buf, 0, 0x100000);
} }

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <common.hpp> #include <common.hpp>
#include <vector>
namespace n64 { namespace n64 {
@@ -54,7 +55,8 @@ struct RDP {
RDP(); RDP();
void Reset(); void Reset();
auto Read(u32 addr) const -> u32; std::vector<u8> dram;
[[nodiscard]] auto Read(u32 addr) const -> u32;
void Write(u32 addr, u32 val); void Write(u32 addr, u32 val);
void StatusWrite(u32 val); void StatusWrite(u32 val);
void RunCommand(MI& mi, Registers& regs, RSP& rsp); void RunCommand(MI& mi, Registers& regs, RSP& rsp);

View File

@@ -52,7 +52,9 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
len -= dram_addr & 0x7; len -= dram_addr & 0x7;
} }
rdLen = len; rdLen = len;
memcpy(&mem.cart[cart_addr & mem.romMask], &mem.rdram[dram_addr & RDRAM_DSIZE], len); for(int i = 0; i < len; i++) {
mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask] = mem.mmio.rdp.dram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
}
dramAddr = dram_addr + len; dramAddr = dram_addr + len;
cartAddr = cart_addr + len; cartAddr = cart_addr + len;
InterruptRaise(mi, regs, Interrupt::PI); InterruptRaise(mi, regs, Interrupt::PI);
@@ -67,7 +69,9 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
len -= dram_addr & 0x7; len -= dram_addr & 0x7;
} }
wrLen = len; wrLen = len;
memcpy(&mem.rdram[dram_addr & RDRAM_DSIZE], &mem.cart[cart_addr & mem.romMask], len); for(int i = 0; i < len; i++) {
mem.mmio.rdp.dram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask];
}
dramAddr = dram_addr + len; dramAddr = dram_addr + len;
cartAddr = cart_addr + len; cartAddr = cart_addr + len;
InterruptRaise(mi, regs, Interrupt::PI); InterruptRaise(mi, regs, Interrupt::PI);

View File

@@ -38,7 +38,7 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
ProcessPIFCommands(mem.pifRam, controller, mem); ProcessPIFCommands(mem.pifRam, controller, mem);
u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE;
memcpy(&mem.rdram[dramAddr & RDRAM_DSIZE], memcpy(&mem.mmio.rdp.dram[dramAddr & RDRAM_DSIZE],
&mem.pifRam[pifAddr], 64); &mem.pifRam[pifAddr], 64);
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
status.intr = 1; status.intr = 1;
@@ -47,8 +47,7 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
//if(!(status.raw & 3)) { //if(!(status.raw & 3)) {
u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE; u8 pifAddr = (val & 0x7FC) & PIF_RAM_DSIZE;
memcpy(&mem.pifRam[pifAddr], memcpy(&mem.pifRam[pifAddr],
&mem.rdram[dramAddr & RDRAM_DSIZE], 64); &mem.mmio.rdp.dram[dramAddr & RDRAM_DSIZE], 64);
ProcessPIFCommands(mem.pifRam, controller, mem); ProcessPIFCommands(mem.pifRam, controller, mem);
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
status.intr = 1; status.intr = 1;

View File

@@ -5,6 +5,7 @@
#include <portable_endian_bswap.h> #include <portable_endian_bswap.h>
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <array>
namespace util { namespace util {
enum MessageType : u8 { enum MessageType : u8 {
@@ -46,7 +47,7 @@ constexpr void logdebug(const std::string& fmt, Args... args) {
} }
template <typename T, bool HToBE = false> template <typename T, bool HToBE = false>
auto GetSwapFunc(T num) -> T { [[maybe_unused]] auto GetSwapFunc(T num) -> T {
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "GetSwapFunc used with invalid size!"); static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "GetSwapFunc used with invalid size!");
if constexpr(sizeof(T) == 2) { if constexpr(sizeof(T) == 2) {
if constexpr(HToBE) { if constexpr(HToBE) {
@@ -70,11 +71,18 @@ template <typename T>
inline T ReadAccess(u8* data, u32 index) { inline T ReadAccess(u8* data, u32 index) {
if constexpr(sizeof(T) == 1) { if constexpr(sizeof(T) == 1) {
return data[index]; return data[index];
} else { } else if constexpr (sizeof(T) == 2 || sizeof(T) == 4) {
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
T result = 0; T result = 0;
memcpy(&result, &data[index], sizeof(T)); memcpy(&result, &data[index], sizeof(T));
return GetSwapFunc<T>(result); return result;
} else {
static_assert(sizeof(T) == 8);
u32 hi = 0;
u32 lo = 0;
memcpy(&hi, &data[index + 0], sizeof(u32));
memcpy(&lo, &data[index + 4], sizeof(u32));
T result = ((T)hi << 32) | (T)lo;
return result;
} }
} }
@@ -83,35 +91,52 @@ inline void WriteAccess(u8* data, u32 index, T val) {
if constexpr(sizeof(T) == 1) { if constexpr(sizeof(T) == 1) {
data[index] = val; data[index] = val;
return; return;
} else if constexpr (sizeof(T) == 2 || sizeof(T) == 4){
memcpy(&data[index], &val, sizeof(T));
} else { } else {
static_assert(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8); static_assert(sizeof(T) == 8);
T temp = GetSwapFunc<T, true>(val); u32 hi = val >> 32;
memcpy(&data[index], &temp, sizeof(T)); u32 lo = val;
memcpy(&data[index + 0], &hi, sizeof(u32));
memcpy(&data[index + 4], &lo, sizeof(u32));
} }
} }
#define Z64 0x80371240 inline void SwapBuffer32(size_t size, u8* data) {
#define N64 0x40123780
#define V64 0x37804012
inline void SwapN64Rom(size_t size, u8* data) {
u32 endianness;
memcpy(&endianness, data, 4);
endianness = be32toh(endianness);
switch(endianness) {
case V64:
for(int i = 0; i < size; i += 2) {
u16 original = *(u16*)&data[i];
*(u16*)&data[i] = bswap_16(original);
}
break;
case N64:
for(int i = 0; i < size; i += 4) { for(int i = 0; i < size; i += 4) {
u32 original = *(u32*)&data[i]; u32 original = *(u32*)&data[i];
*(u32*)&data[i] = bswap_32(original); *(u32*)&data[i] = bswap_32(original);
} }
break; }
case Z64: break;
inline void SwapBuffer16(size_t size, u8* data) {
for(int i = 0; i < size; i += 2) {
u16 original = *(u16*)&data[i];
*(u16*)&data[i] = bswap_16(original);
}
}
enum RomTypes {
Z64 = 0x80371240,
N64 = 0x40123780,
V64 = 0x37804012
};
inline void SwapN64Rom(size_t size, u8* data) {
RomTypes endianness;
memcpy(&endianness, data, 4);
endianness = static_cast<RomTypes>(be32toh(endianness));
switch(endianness) {
case V64: {
u8* tmp = (u8*)calloc(size, 1);
for(int i = 0; i < size; i++) {
data[i] = tmp[i ^ 2];
}
free(tmp);
} break;
case N64: break;
case Z64:
SwapBuffer32(size, data); break;
default: default:
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!\n"); panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!\n");
} }
@@ -120,23 +145,29 @@ inline void SwapN64Rom(size_t size, u8* data) {
template <size_t size, typename T = u8> template <size_t size, typename T = u8>
struct CircularBuffer { struct CircularBuffer {
CircularBuffer() : head(0) { CircularBuffer() : head(0) {
memset(raw, 0, size * sizeof(T)); memset(raw.data(), 0, size * sizeof(T));
} }
void PushValue(T val) { void PushValue(T val) {
raw[head & mask] = val; raw[head] = val;
head &= mask;
head++; head++;
head &= mask;
} }
T PopValue() { T PopValue() {
head--; head--;
head &= mask; head &= mask;
return raw[head & mask]; return raw[head];
} }
T& operator[](const int index) {
return raw[index];
}
auto begin() { return raw.begin(); }
auto end() { return raw.end(); }
size_t GetHead() { return head; } size_t GetHead() { return head; }
private: private:
T raw[size]; std::array<T, size> raw;
size_t head; size_t head;
static constexpr size_t mask = size - 1; static constexpr size_t mask = size - 1;
}; };