Refactor Memory

This commit is contained in:
SimoneN64
2024-05-13 20:22:16 +02:00
committed by Simone
parent c3ac6476c8
commit e07f4880e6
16 changed files with 212 additions and 165 deletions

View File

@@ -8,7 +8,7 @@ namespace Util {
#define V64 0x37800012 #define V64 0x37800012
template <bool toBE = false> template <bool toBE = false>
FORCE_INLINE void SwapN64Rom(size_t size, u8 *rom, u32 endianness) { FORCE_INLINE void SwapN64Rom(std::vector<u8> &rom, u32 endianness) {
u8 altByteShift = 0; u8 altByteShift = 0;
if((endianness >> 24) != 0x80) { if((endianness >> 24) != 0x80) {
if((endianness & 0xFF) != 0x80) { if((endianness & 0xFF) != 0x80) {
@@ -28,17 +28,17 @@ FORCE_INLINE void SwapN64Rom(size_t size, u8 *rom, u32 endianness) {
switch (endianness) { switch (endianness) {
case V64: case V64:
SwapBuffer16(size, rom); SwapBuffer16(rom);
if constexpr(!toBE) if constexpr(!toBE)
SwapBuffer32(size, rom); SwapBuffer32(rom);
break; break;
case N64: case N64:
if constexpr(toBE) if constexpr(toBE)
SwapBuffer32(size, rom); SwapBuffer32(rom);
break; break;
case Z64: case Z64:
if constexpr(!toBE) if constexpr(!toBE)
SwapBuffer32(size, rom); SwapBuffer32(rom);
break; break;
default: default:
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!"); panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!");

View File

@@ -71,7 +71,7 @@ std::vector<u8> MMIO::Serialize() {
index += sizeof(DPC); index += sizeof(DPC);
memcpy(res.data() + index, rdp.cmd_buf, 0xFFFFF); memcpy(res.data() + index, rdp.cmd_buf, 0xFFFFF);
index += 0xFFFFF; index += 0xFFFFF;
memcpy(res.data() + index, rdp.rdram, RDRAM_SIZE); std::copy(rdp.rdram.begin(), rdp.rdram.end(), res.begin() + index);
index += RDRAM_SIZE; index += RDRAM_SIZE;
memcpy(res.data() + index, &mi, sizeof(MI)); memcpy(res.data() + index, &mi, sizeof(MI));
index += sizeof(MI); index += sizeof(MI);
@@ -102,7 +102,7 @@ void MMIO::Deserialize(const std::vector<u8> &data) {
index += sizeof(DPC); index += sizeof(DPC);
memcpy(rdp.cmd_buf, data.data() + index, 0xFFFFF); memcpy(rdp.cmd_buf, data.data() + index, 0xFFFFF);
index += 0xFFFFF; index += 0xFFFFF;
memcpy(rdp.rdram, data.data() + index, RDRAM_SIZE); std::copy(data.begin() + index, data.begin() + index + RDRAM_SIZE, rdp.rdram.begin());
index += RDRAM_SIZE; index += RDRAM_SIZE;
memcpy(&mi, data.data() + index, sizeof(MI)); memcpy(&mi, data.data() + index, sizeof(MI));
index += sizeof(MI); index += sizeof(MI);

View File

@@ -19,11 +19,12 @@ Mem::Mem(Registers& regs) : flash(saveData), mmio(*this, regs) {
writePages[i] = pointer; writePages[i] = pointer;
} }
rom.cart = (u8*)calloc(CART_SIZE, 1); rom.cart.resize(CART_SIZE);
std::fill(rom.cart.begin(), rom.cart.end(), 0);
} }
void Mem::Reset() { void Mem::Reset() {
memset(rom.cart, 0, CART_SIZE); std::fill(rom.cart.begin(), rom.cart.end(), 0);
flash.Reset(); flash.Reset();
if (saveData.is_mapped()) { if (saveData.is_mapped()) {
std::error_code error; std::error_code error;
@@ -46,9 +47,7 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) {
FILE *f = fopen(sramPath.c_str(), "rb"); FILE *f = fopen(sramPath.c_str(), "rb");
if (!f) { if (!f) {
f = fopen(sramPath.c_str(), "wb"); Util::panic("Could not open {}", sramPath);
u8* dummy = (u8*)calloc(SRAM_SIZE, 1);
fwrite(dummy, 1, SRAM_SIZE, f);
} }
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
@@ -60,7 +59,7 @@ void Mem::LoadSRAM(SaveType save_type, fs::path path) {
fclose(f); fclose(f);
saveData = mio::make_mmap_sink( saveData = mio::make_mmap_sink(
sramPath, 0, mio::map_entire_file, error); sramPath, 0, mio::map_entire_file, error);
if (error) { Util::panic("Could not open {}", sramPath); } if (error) { Util::panic("Could not mmap {}", sramPath); }
} }
} }
@@ -99,13 +98,13 @@ std::vector<u8> Mem::OpenArchive(const std::string &path, size_t& sizeAdjusted)
std::vector<u8> buf{}; std::vector<u8> buf{};
std::string rom_exts[] = {".n64",".z64",".v64",".N64",".Z64",".V64"}; std::vector<std::string> rom_exts{".n64",".z64",".v64",".N64",".Z64",".V64"};
while(ar_parse_entry(archive)) { while(ar_parse_entry(archive)) {
auto filename = ar_entry_get_name(archive); auto filename = ar_entry_get_name(archive);
auto extension = fs::path(filename).extension(); auto extension = fs::path(filename).extension();
if(std::any_of(std::begin(rom_exts), std::end(rom_exts), [&](auto x) { if(std::any_of(rom_exts.begin(), rom_exts.end(), [&](auto x) {
return extension == x; return extension == x;
})) { })) {
auto size = ar_entry_get_size(archive); auto size = ar_entry_get_size(archive);
@@ -133,28 +132,24 @@ std::vector<u8> Mem::OpenROM(const std::string& filename, size_t& sizeAdjusted)
void Mem::LoadROM(bool isArchive, const std::string& filename) { void Mem::LoadROM(bool isArchive, const std::string& filename) {
size_t sizeAdjusted; size_t sizeAdjusted;
u8* buf; u32 endianness;
std::vector<u8> temp{}; {
if(isArchive) { std::vector<u8> buf{};
temp = OpenArchive(filename, sizeAdjusted); if (isArchive) {
buf = OpenArchive(filename, sizeAdjusted);
} else { } else {
temp = OpenROM(filename, sizeAdjusted); buf = OpenROM(filename, sizeAdjusted);
} }
buf = (u8*)calloc(sizeAdjusted, 1); endianness = be32toh(*reinterpret_cast<u32*>(buf.data()));
std::copy(temp.begin(), temp.end(), buf); Util::SwapN64Rom<true>(buf, endianness);
u32 endianness = be32toh(*reinterpret_cast<u32*>(buf)); std::copy(buf.begin(), buf.end(), rom.cart.begin());
Util::SwapN64Rom<true>(sizeAdjusted, buf, endianness);
memcpy(rom.cart, buf, sizeAdjusted);
rom.size = sizeAdjusted;
rom.mask = sizeAdjusted - 1; rom.mask = sizeAdjusted - 1;
memcpy(&rom.header, buf, sizeof(ROMHeader)); memcpy(&rom.header, buf.data(), sizeof(ROMHeader));
}
memcpy(rom.gameNameCart, rom.header.imageName, sizeof(rom.header.imageName)); memcpy(rom.gameNameCart, rom.header.imageName, sizeof(rom.header.imageName));
free(buf);
rom.header.clockRate = be32toh(rom.header.clockRate); rom.header.clockRate = be32toh(rom.header.clockRate);
rom.header.programCounter = be32toh(rom.header.programCounter); rom.header.programCounter = be32toh(rom.header.programCounter);
rom.header.release = be32toh(rom.header.release); rom.header.release = be32toh(rom.header.release);
@@ -176,8 +171,8 @@ void Mem::LoadROM(bool isArchive, const std::string& filename) {
u32 checksum = Util::crc32(0, &rom.cart[0x40], 0x9c0); u32 checksum = Util::crc32(0, &rom.cart[0x40], 0x9c0);
SetROMCIC(checksum, rom); SetROMCIC(checksum, rom);
endianness = be32toh(*reinterpret_cast<u32*>(rom.cart)); endianness = be32toh(*reinterpret_cast<u32*>(rom.cart.data()));
Util::SwapN64Rom(sizeAdjusted, rom.cart, endianness); Util::SwapN64Rom(rom.cart, endianness);
rom.pal = IsROMPAL(); rom.pal = IsROMPAL();
} }
@@ -194,13 +189,8 @@ template<> u8 Mem::Read(n64::Registers &regs, u32 paddr) {
case RDRAM_REGION: case RDRAM_REGION:
return mmio.rdp.rdram[BYTE_ADDRESS(paddr)]; return mmio.rdp.rdram[BYTE_ADDRESS(paddr)];
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
if(mirrAddr & 0x1000) { return src[BYTE_ADDRESS(paddr & 0xfff)];
mirrAddr -= 0x1000;
return mmio.rsp.imem[BYTE_ADDRESS(mirrAddr)];
} else {
return mmio.rsp.dmem[BYTE_ADDRESS(mirrAddr)];
}
} }
case REGION_CART: case REGION_CART:
return mmio.pi.BusRead<u8, false>(*this, paddr); return mmio.pi.BusRead<u8, false>(*this, paddr);
@@ -242,13 +232,8 @@ template<> u16 Mem::Read(n64::Registers &regs, u32 paddr) {
case RDRAM_REGION: case RDRAM_REGION:
return Util::ReadAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr)); return Util::ReadAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr));
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
if(mirrAddr & 0x1000) { return Util::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
mirrAddr -= 0x1000;
return Util::ReadAccess<u16>(mmio.rsp.imem, HALF_ADDRESS(mirrAddr));
} else {
return Util::ReadAccess<u16>(mmio.rsp.dmem, HALF_ADDRESS(mirrAddr));
}
} }
case MMIO_REGION: case MMIO_REGION:
return mmio.Read(paddr); return mmio.Read(paddr);
@@ -282,13 +267,8 @@ template<> u32 Mem::Read(n64::Registers &regs, u32 paddr) {
case RDRAM_REGION: case RDRAM_REGION:
return Util::ReadAccess<u32>(mmio.rdp.rdram, paddr); return Util::ReadAccess<u32>(mmio.rdp.rdram, paddr);
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
if(mirrAddr & 0x1000) { return Util::ReadAccess<u32>(src, paddr & 0xfff);
mirrAddr -= 0x1000;
return Util::ReadAccess<u32>(mmio.rsp.imem, mirrAddr);
} else {
return Util::ReadAccess<u32>(mmio.rsp.dmem, mirrAddr);
}
} }
case MMIO_REGION: case MMIO_REGION:
return mmio.Read(paddr); return mmio.Read(paddr);
@@ -319,13 +299,8 @@ template<> u64 Mem::Read(n64::Registers &regs, u32 paddr) {
case RDRAM_REGION: case RDRAM_REGION:
return Util::ReadAccess<u64>(mmio.rdp.rdram, paddr); return Util::ReadAccess<u64>(mmio.rdp.rdram, paddr);
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
if(mirrAddr & 0x1000) { return Util::ReadAccess<u64>(src, paddr & 0xfff);
mirrAddr -= 0x1000;
return Util::ReadAccess<u64>(mmio.rsp.imem, mirrAddr);
} else {
return Util::ReadAccess<u64>(mmio.rsp.dmem, mirrAddr);
}
} }
case MMIO_REGION: case MMIO_REGION:
return mmio.Read(paddr); return mmio.Read(paddr);
@@ -360,14 +335,10 @@ template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val; mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val;
break; break;
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; val = val << (8 * (3 - (paddr & 3)));
val = val << (8 * (3 - (mirrAddr & 3))); auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
mirrAddr = (mirrAddr & 0xFFF) & ~3; paddr = (paddr & 0xFFF) & ~3;
if(mirrAddr & 0x1000) { Util::WriteAccess<u32>(dest, paddr, val);
Util::WriteAccess<u32>(mmio.rsp.imem, mirrAddr, val);
} else {
Util::WriteAccess<u32>(mmio.rsp.dmem, mirrAddr, val);
}
} break; } break;
case REGION_CART: case REGION_CART:
Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val); Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
@@ -409,14 +380,10 @@ template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
Util::WriteAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr), val); Util::WriteAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr), val);
break; break;
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; val = val << (16 * !(paddr & 2));
val = val << (16 * !(mirrAddr & 2)); auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
mirrAddr = (mirrAddr & 0xFFF) & ~3; paddr = (paddr & 0xFFF) & ~3;
if(mirrAddr & 0x1000) { Util::WriteAccess<u32>(dest, paddr, val);
Util::WriteAccess<u32>(mmio.rsp.imem, mirrAddr, val);
} else {
Util::WriteAccess<u32>(mmio.rsp.dmem, mirrAddr, val);
}
} break; } break;
case REGION_CART: case REGION_CART:
Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val); Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
@@ -458,12 +425,8 @@ template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
Util::WriteAccess<u32>(mmio.rdp.rdram, paddr, val); Util::WriteAccess<u32>(mmio.rdp.rdram, paddr, val);
break; break;
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
if(mirrAddr & 0x1000) { Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
} else {
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
}
} break; } break;
case REGION_CART: case REGION_CART:
Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val); Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
@@ -501,13 +464,9 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) {
Util::WriteAccess<u64>(mmio.rdp.rdram, paddr, val); Util::WriteAccess<u64>(mmio.rdp.rdram, paddr, val);
break; break;
case RSP_MEM_REGION: { case RSP_MEM_REGION: {
u32 mirrAddr = paddr & 0x1FFF; auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
val >>= 32; val >>= 32;
if(mirrAddr & 0x1000) { Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
} else {
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
}
} break; } break;
case REGION_CART: case REGION_CART:
Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val); Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);

View File

@@ -7,6 +7,7 @@
#include <Registers.hpp> #include <Registers.hpp>
#include <algorithm> #include <algorithm>
#include <GameDB.hpp> #include <GameDB.hpp>
#include <File.hpp>
namespace n64 { namespace n64 {
struct ROMHeader { struct ROMHeader {
@@ -26,8 +27,7 @@ struct ROMHeader {
}; };
struct ROM { struct ROM {
u8* cart; std::vector<u8> cart;
size_t size;
size_t mask; size_t mask;
ROMHeader header; ROMHeader header;
CICType cicType; CICType cicType;
@@ -50,7 +50,7 @@ struct Flash {
u64 status{}; u64 status{};
size_t eraseOffs{}; size_t eraseOffs{};
size_t writeOffs{}; size_t writeOffs{};
u8 writeBuf[128]{}; std::array<u8, 128> writeBuf{};
std::string flashPath{}; std::string flashPath{};
mio::mmap_sink& saveData; mio::mmap_sink& saveData;
@@ -87,7 +87,11 @@ struct Mem {
static std::vector<u8> OpenROM(const std::string&, size_t&); static std::vector<u8> OpenROM(const std::string&, size_t&);
static std::vector<u8> OpenArchive(const std::string&, size_t&); static std::vector<u8> OpenArchive(const std::string&, size_t&);
void LoadROM(bool, const std::string&); void LoadROM(bool, const std::string&);
[[nodiscard]] auto GetRDRAM() const -> u8* { [[nodiscard]] auto GetRDRAMPtr() -> u8* {
return mmio.rdp.rdram.data();
}
[[nodiscard]] auto GetRDRAM() -> std::vector<u8>& {
return mmio.rdp.rdram; return mmio.rdp.rdram;
} }
@@ -108,33 +112,25 @@ struct Mem {
MMIO mmio; MMIO mmio;
FORCE_INLINE void DumpRDRAM() const { FORCE_INLINE void DumpRDRAM() const {
FILE *fp = fopen("rdram.dump", "wb"); std::vector<u8> temp{};
u8 *temp = (u8*)calloc(RDRAM_SIZE, 1); temp.resize(RDRAM_SIZE);
memcpy(temp, mmio.rdp.rdram, RDRAM_SIZE); std::copy(mmio.rdp.rdram.begin(), mmio.rdp.rdram.end(), temp.begin());
Util::SwapBuffer32(RDRAM_SIZE, temp); Util::SwapBuffer32(temp);
fwrite(temp, 1, RDRAM_SIZE, fp); Util::WriteFileBinary(temp, "rdram.bin");
free(temp);
fclose(fp);
} }
FORCE_INLINE void DumpIMEM() const { FORCE_INLINE void DumpIMEM() const {
FILE *fp = fopen("imem.bin", "wb"); std::array<u8, IMEM_SIZE> temp{};
u8 *temp = (u8*)calloc(IMEM_SIZE, 1); std::copy(mmio.rsp.imem.begin(), mmio.rsp.imem.end(), temp.begin());
memcpy(temp, mmio.rsp.imem, IMEM_SIZE); Util::SwapBuffer32(temp);
Util::SwapBuffer32(IMEM_SIZE, temp); Util::WriteFileBinary(temp, "imem.bin");
fwrite(temp, 1, IMEM_SIZE, fp);
free(temp);
fclose(fp);
} }
FORCE_INLINE void DumpDMEM() const { FORCE_INLINE void DumpDMEM() const {
FILE *fp = fopen("dmem.dump", "wb"); std::array<u8, DMEM_SIZE> temp{};
u8 *temp = (u8*)calloc(DMEM_SIZE, 1); std::copy(mmio.rsp.dmem.begin(), mmio.rsp.dmem.end(), temp.begin());
memcpy(temp, mmio.rsp.dmem, DMEM_SIZE); Util::SwapBuffer32(temp);
Util::SwapBuffer32(DMEM_SIZE, temp); Util::WriteFileBinary(temp, "dmem.bin");
fwrite(temp, 1, DMEM_SIZE, fp);
free(temp);
fclose(fp);
} }
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{}; uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
ROM rom; ROM rom;

View File

@@ -6,14 +6,14 @@
namespace n64 { namespace n64 {
RDP::RDP() { RDP::RDP() {
rdram = (u8*)calloc(RDRAM_SIZE, 1); rdram.resize(RDRAM_SIZE);
memset(cmd_buf, 0, 0x100000); memset(cmd_buf, 0, 0x100000);
dpc.status.raw = 0x80; dpc.status.raw = 0x80;
} }
void RDP::Reset() { void RDP::Reset() {
dpc.status.raw = 0x80; dpc.status.raw = 0x80;
memset(rdram, 0, RDRAM_SIZE); rdram = {};
memset(cmd_buf, 0, 0x100000); memset(cmd_buf, 0, 0x100000);
} }

View File

@@ -57,7 +57,7 @@ struct RDP {
RDP(); RDP();
void Reset(); void Reset();
u8* rdram = nullptr; std::vector<u8> rdram{};
[[nodiscard]] auto Read(u32 addr) const -> u32; [[nodiscard]] auto Read(u32 addr) const -> u32;
void Write(MI& mi, Registers& regs, RSP& rsp, u32 addr, u32 val); void Write(MI& mi, Registers& regs, RSP& rsp, u32 addr, u32 val);
void WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val); void WriteStatus(MI& mi, Registers& regs, RSP& rsp, u32 val);

View File

@@ -19,8 +19,8 @@ void RSP::Reset() {
spDMASPAddr.raw = 0; spDMASPAddr.raw = 0;
spDMADRAMAddr.raw = 0; spDMADRAMAddr.raw = 0;
spDMALen.raw = 0; spDMALen.raw = 0;
memset(dmem, 0, DMEM_SIZE); dmem = {};
memset(imem, 0, IMEM_SIZE); imem = {};
memset(vpr, 0, 32 * sizeof(VPR)); memset(vpr, 0, 32 * sizeof(VPR));
memset(gpr, 0, 32 * sizeof(u32)); memset(gpr, 0, 32 * sizeof(u32));
memset(&vce, 0, sizeof(VPR)); memset(&vce, 0, sizeof(VPR));
@@ -116,11 +116,11 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) {
case 0x04040004: spDMADRAMAddr.raw = value & 0xFFFFF8; break; case 0x04040004: spDMADRAMAddr.raw = value & 0xFFFFF8; break;
case 0x04040008: { case 0x04040008: {
spDMALen.raw = value; spDMALen.raw = value;
DMA<false>(spDMALen, mem.GetRDRAM(), *this, spDMASPAddr.bank); DMAtoRSP(spDMALen, mem.GetRDRAM(), *this, spDMASPAddr.bank);
} break; } break;
case 0x0404000C: { case 0x0404000C: {
spDMALen.raw = value; spDMALen.raw = value;
DMA<true>(spDMALen, mem.GetRDRAM(), *this, spDMASPAddr.bank); DMAtoRDRAM(spDMALen, mem.GetRDRAM(), *this, spDMASPAddr.bank);
} break; } break;
case 0x04040010: WriteStatus(mi, regs, value); break; case 0x04040010: WriteStatus(mi, regs, value); break;
case 0x0404001C: ReleaseSemaphore(); break; case 0x0404001C: ReleaseSemaphore(); break;

View File

@@ -4,6 +4,7 @@
#include <MemoryRegions.hpp> #include <MemoryRegions.hpp>
#include <MemoryHelpers.hpp> #include <MemoryHelpers.hpp>
#include <Interrupt.hpp> #include <Interrupt.hpp>
#include <array>
#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF]) #define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
#define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) #define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1))
@@ -134,7 +135,8 @@ struct RSP {
SPDMASPAddr lastSuccessfulSPAddr{}; SPDMASPAddr lastSuccessfulSPAddr{};
SPDMADRAMAddr lastSuccessfulDRAMAddr{}; SPDMADRAMAddr lastSuccessfulDRAMAddr{};
SPDMALen spDMALen{}; SPDMALen spDMALen{};
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}; std::array<u8, DMEM_SIZE> dmem{};
std::array<u8, IMEM_SIZE> imem{};
VPR vpr[32]{}; VPR vpr[32]{};
s32 gpr[32]{}; s32 gpr[32]{};
VPR vce{}; VPR vce{};
@@ -356,31 +358,50 @@ struct RSP {
void mfc2(u32 instr); void mfc2(u32 instr);
void mtc2(u32 instr); void mtc2(u32 instr);
template <bool isDRAMdest> FORCE_INLINE void DMAtoRDRAM(SPDMALen len, std::vector<u8>& rdram, RSP& rsp, bool bank) {
FORCE_INLINE void DMA(SPDMALen len, u8* rdram, RSP& rsp, bool bank) {
u32 length = len.len + 1; u32 length = len.len + 1;
length = (length + 0x7) & ~0x7; length = (length + 0x7) & ~0x7;
u8* dst, *src; std::vector<u8>& dst = rdram;
if constexpr (isDRAMdest) { std::array<u8, DMEM_SIZE>& src = bank ? rsp.imem : rsp.dmem;
dst = rdram;
src = bank ? rsp.imem : rsp.dmem;
} else {
src = rdram;
dst = bank ? rsp.imem : rsp.dmem;
}
u32 mem_address = rsp.spDMASPAddr.address & 0xFF8; u32 mem_address = rsp.spDMASPAddr.address & 0xFF8;
u32 dram_address = rsp.spDMADRAMAddr.address & 0xFFFFF8; u32 dram_address = rsp.spDMADRAMAddr.address & 0xFFFFF8;
for (u32 i = 0; i < len.count + 1; i++) { for (u32 i = 0; i < len.count + 1; i++) {
for(u32 j = 0; j < length; j++) { for(u32 j = 0; j < length; j++) {
if constexpr (isDRAMdest) {
dst[dram_address + j] = src[(mem_address + j) & 0xFFF]; dst[dram_address + j] = src[(mem_address + j) & 0xFFF];
} else {
dst[(mem_address + j) & 0xFFF] = src[dram_address + j];
} }
int skip = i == len.count ? 0 : len.skip;
dram_address += (length + skip);
dram_address &= 0xFFFFF8;
mem_address += length;
mem_address &= 0xFF8;
}
rsp.lastSuccessfulSPAddr.address = mem_address;
rsp.lastSuccessfulSPAddr.bank = bank;
rsp.lastSuccessfulDRAMAddr.address = dram_address;
rsp.spDMALen.raw = 0xFF8 | (rsp.spDMALen.skip << 20);
}
FORCE_INLINE void DMAtoRSP(SPDMALen len, std::vector<u8>& rdram, RSP& rsp, bool bank) {
u32 length = len.len + 1;
length = (length + 0x7) & ~0x7;
std::vector<u8>& src = rdram;
std::array<u8, DMEM_SIZE>& dst = bank ? rsp.imem : rsp.dmem;
u32 mem_address = rsp.spDMASPAddr.address & 0xFF8;
u32 dram_address = rsp.spDMADRAMAddr.address & 0xFFFFF8;
for (u32 i = 0; i < len.count + 1; i++) {
for(u32 j = 0; j < length; j++) {
dst[(mem_address + j) & 0xFFF] = src[dram_address + j];
} }
int skip = i == len.count ? 0 : len.skip; int skip = i == len.count ? 0 : len.skip;

View File

@@ -117,7 +117,7 @@ std::vector<u8> Flash::Serialize() {
index += sizeof(eraseOffs); index += sizeof(eraseOffs);
memcpy(res.data() + index, &writeOffs, sizeof(writeOffs)); memcpy(res.data() + index, &writeOffs, sizeof(writeOffs));
index += sizeof(writeOffs); index += sizeof(writeOffs);
memcpy(res.data() + index, writeBuf, 128); std::copy(writeBuf.begin(), writeBuf.end(), res.begin() + index);
return res; return res;
} }
@@ -132,7 +132,7 @@ void Flash::Deserialize(const std::vector<u8>& data) {
index += sizeof(eraseOffs); index += sizeof(eraseOffs);
memcpy(&writeOffs, data.data() + index, sizeof(writeOffs)); memcpy(&writeOffs, data.data() + index, sizeof(writeOffs));
index += sizeof(writeOffs); index += sizeof(writeOffs);
memcpy(writeBuf, data.data() + index, 128); std::copy(data.begin() + index, data.begin() + index + 128, writeBuf.begin());
} }
template <> void Flash::Write<u32>(u32 index, u32 val) { template <> void Flash::Write<u32>(u32 index, u32 val) {

View File

@@ -62,8 +62,8 @@ template<> auto PI::BusRead<u8, true>(Mem& mem, u32 addr) -> u8 {
case REGION_PI_ROM: { case REGION_PI_ROM: {
// round to nearest 4 byte boundary, keeping old LSB // round to nearest 4 byte boundary, keeping old LSB
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
if (index >= mem.rom.size) { if (index >= mem.rom.cart.size()) {
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size); Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.cart.size(), mem.rom.cart.size());
return 0xFF; return 0xFF;
} }
return mem.rom.cart[index]; return mem.rom.cart[index];
@@ -92,8 +92,8 @@ template<> auto PI::BusRead<u8, false>(Mem& mem, u32 addr) -> u8 {
addr = (addr + 2) & ~2; addr = (addr + 2) & ~2;
// round to nearest 4 byte boundary, keeping old LSB // round to nearest 4 byte boundary, keeping old LSB
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
if (index >= mem.rom.size) { if (index >= mem.rom.cart.size()) {
Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size); Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.cart.size(), mem.rom.cart.size());
return 0xFF; return 0xFF;
} }
return mem.rom.cart[index]; return mem.rom.cart[index];
@@ -154,7 +154,7 @@ template <> auto PI::BusRead<u16, false>(Mem& mem, u32 addr) -> u16 {
case REGION_PI_ROM: { case REGION_PI_ROM: {
addr = (addr + 2) & ~3; addr = (addr + 2) & ~3;
u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM; u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
if (index > mem.rom.size - 1) { if (index > mem.rom.cart.size() - 1) {
Util::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); Util::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
} }
return Util::ReadAccess<u16>(mem.rom.cart, index); return Util::ReadAccess<u16>(mem.rom.cart, index);
@@ -213,7 +213,7 @@ template <> auto PI::BusRead<u32, false>(Mem& mem, u32 addr) -> u32 {
return mem.BackupRead<u32>(addr); return mem.BackupRead<u32>(addr);
case REGION_PI_ROM: { case REGION_PI_ROM: {
u32 index = addr - SREGION_PI_ROM; u32 index = addr - SREGION_PI_ROM;
if (index > mem.rom.size - 3) { // -3 because we're reading an entire word if (index > mem.rom.cart.size() - 3) { // -3 because we're reading an entire word
switch (addr) { switch (addr) {
case REGION_CART_ISVIEWER_BUFFER: case REGION_CART_ISVIEWER_BUFFER:
return htobe32(Util::ReadAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); return htobe32(Util::ReadAccess<u32>(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER));
@@ -313,7 +313,7 @@ template <> auto PI::BusRead<u64, false>(Mem& mem, u32 addr) -> u64 {
Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
case REGION_PI_ROM: { case REGION_PI_ROM: {
u32 index = addr - SREGION_PI_ROM; u32 index = addr - SREGION_PI_ROM;
if (index > mem.rom.size - 7) { // -7 because we're reading an entire dword if (index > mem.rom.cart.size() - 7) { // -7 because we're reading an entire dword
Util::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); Util::panic("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index);
} }
return Util::ReadAccess<u64>(mem.rom.cart, index); return Util::ReadAccess<u64>(mem.rom.cart, index);

View File

@@ -593,7 +593,7 @@ void PIF::HLE(bool pal, CICType cicType) {
regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF; regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF;
regs.cop0.Reset(); regs.cop0.Reset();
mem.Write<u32>(regs, 0x04300004, 0x01010101); mem.Write<u32>(regs, 0x04300004, 0x01010101);
memcpy(mem.mmio.rsp.dmem, mem.rom.cart, 0x1000); std::copy(mem.rom.cart.begin(), mem.rom.cart.begin() + 0x1000, mem.mmio.rsp.dmem.begin());
regs.SetPC32(s32(0xA4000040)); regs.SetPC32(s32(0xA4000040));
} }

View File

@@ -221,13 +221,7 @@ void RSP::Exec(Registers &regs, Mem& mem, u32 instr) {
case 0x32: lwc2(*this, instr); break; case 0x32: lwc2(*this, instr); break;
case 0x3A: swc2(*this, instr); break; case 0x3A: swc2(*this, instr); break;
default: default:
FILE *fp = fopen("imem.bin", "wb"); mem.DumpIMEM();
u8 *temp = (u8*)calloc(IMEM_SIZE, 1);
memcpy(temp, imem, IMEM_SIZE);
Util::SwapBuffer32(IMEM_SIZE, temp);
fwrite(temp, 1, IMEM_SIZE, fp);
free(temp);
fclose(fp);
Util::panic("Unhandled RSP instruction ({:06b}, {:04X})", mask, oldPC); Util::panic("Unhandled RSP instruction ({:06b}, {:04X})", mask, oldPC);
} }
} }

View File

@@ -60,11 +60,11 @@ FORCE_INLINE void SetCop0Reg(Registers& regs, Mem& mem, u8 index, u32 val) {
case 1: rsp.spDMADRAMAddr.raw = val; break; case 1: rsp.spDMADRAMAddr.raw = val; break;
case 2: case 2:
rsp.spDMALen.raw = val; rsp.spDMALen.raw = val;
rsp.DMA<false>(rsp.spDMALen, mem.GetRDRAM(), rsp, rsp.spDMASPAddr.bank); rsp.DMAtoRSP(rsp.spDMALen, mem.GetRDRAM(), rsp, rsp.spDMASPAddr.bank);
break; break;
case 3: case 3:
rsp.spDMALen.raw = val; rsp.spDMALen.raw = val;
rsp.DMA<true>(rsp.spDMALen, mem.GetRDRAM(), rsp, rsp.spDMASPAddr.bank); rsp.DMAtoRDRAM(rsp.spDMALen, mem.GetRDRAM(), rsp, rsp.spDMASPAddr.bank);
break; break;
case 4: rsp.WriteStatus(mi, regs, val); break; case 4: rsp.WriteStatus(mi, regs, val); break;
case 7: case 7:

View File

@@ -8,7 +8,7 @@ EmuThread::EmuThread(std::unique_ptr<QtInstanceFactory>&& instance, std::unique_
[[noreturn]] void EmuThread::run() noexcept { [[noreturn]] void EmuThread::run() noexcept {
LoadWSIPlatform(instance.get(), std::move(wsiPlatform), std::move(windowInfo)); LoadWSIPlatform(instance.get(), std::move(wsiPlatform), std::move(windowInfo));
LoadParallelRDP(core->cpu->mem.GetRDRAM()); LoadParallelRDP(core->cpu->mem.GetRDRAMPtr());
while (true) { while (true) {
if (!core->pause) { if (!core->pause) {

View File

@@ -8,6 +8,17 @@ FORCE_INLINE std::vector<u8> ReadFileBinary(const std::string& path) {
return {std::istreambuf_iterator{file}, {}}; return {std::istreambuf_iterator{file}, {}};
} }
FORCE_INLINE void WriteFileBinary(const std::vector<u8>& data, const std::string& path) {
std::ofstream file(path, std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
}
template <size_t Size>
FORCE_INLINE void WriteFileBinary(const std::array<u8, Size>& data, const std::string& path) {
std::ofstream file(path, std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
}
FORCE_INLINE size_t NextPow2(size_t num) { FORCE_INLINE size_t NextPow2(size_t num) {
// Taken from "Bit Twiddling Hacks" by Sean Anderson: // Taken from "Bit Twiddling Hacks" by Sean Anderson:
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2

View File

@@ -6,7 +6,7 @@
namespace Util { namespace Util {
template<typename T> template<typename T>
static FORCE_INLINE T ReadAccess(const u8 *data, u32 index) { static FORCE_INLINE T ReadAccess(const u8* data, u32 index) {
if constexpr (sizeof(T) == 8) { if constexpr (sizeof(T) == 8) {
u32 hi = *reinterpret_cast<const u32*>(&data[index + 0]); u32 hi = *reinterpret_cast<const u32*>(&data[index + 0]);
u32 lo = *reinterpret_cast<const u32*>(&data[index + 4]); u32 lo = *reinterpret_cast<const u32*>(&data[index + 4]);
@@ -17,6 +17,56 @@ static FORCE_INLINE T ReadAccess(const u8 *data, u32 index) {
} }
} }
template<typename T>
static FORCE_INLINE T ReadAccess(const std::vector<u8>& data, u32 index) {
if constexpr (sizeof(T) == 8) {
u32 hi = *reinterpret_cast<const u32*>(&data[index + 0]);
u32 lo = *reinterpret_cast<const u32*>(&data[index + 4]);
T result = ((T)hi << 32) | (T)lo;
return result;
} else {
return *reinterpret_cast<const T*>(&data[index]);
}
}
template<typename T, size_t Size>
static FORCE_INLINE T ReadAccess(const std::array<u8, Size>& data, u32 index) {
if constexpr (sizeof(T) == 8) {
u32 hi = *reinterpret_cast<const u32*>(&data[index + 0]);
u32 lo = *reinterpret_cast<const u32*>(&data[index + 4]);
T result = ((T)hi << 32) | (T)lo;
return result;
} else {
return *reinterpret_cast<const T*>(&data[index]);
}
}
template<typename T, size_t Size>
static FORCE_INLINE void WriteAccess(std::array<u8, Size>& data, u32 index, T val) {
if constexpr (sizeof(T) == 8) {
u32 hi = val >> 32;
u32 lo = val;
*reinterpret_cast<u32*>(&data[index + 0]) = hi;
*reinterpret_cast<u32*>(&data[index + 4]) = lo;
} else {
*reinterpret_cast<T*>(&data[index]) = val;
}
}
template<typename T>
static FORCE_INLINE void WriteAccess(std::vector<u8>& data, u32 index, T val) {
if constexpr (sizeof(T) == 8) {
u32 hi = val >> 32;
u32 lo = val;
*reinterpret_cast<u32*>(&data[index + 0]) = hi;
*reinterpret_cast<u32*>(&data[index + 4]) = lo;
} else {
*reinterpret_cast<T*>(&data[index]) = val;
}
}
template<typename T> template<typename T>
static FORCE_INLINE void WriteAccess(u8 *data, u32 index, T val) { static FORCE_INLINE void WriteAccess(u8 *data, u32 index, T val) {
if constexpr (sizeof(T) == 8) { if constexpr (sizeof(T) == 8) {
@@ -30,15 +80,31 @@ static FORCE_INLINE void WriteAccess(u8 *data, u32 index, T val) {
} }
} }
FORCE_INLINE void SwapBuffer32(size_t size, u8 *data) { FORCE_INLINE void SwapBuffer32(std::vector<u8> &data) {
for (size_t i = 0; i < size; i += 4) { for (size_t i = 0; i < data.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);
} }
} }
FORCE_INLINE void SwapBuffer16(size_t size, u8 *data) { FORCE_INLINE void SwapBuffer16(std::vector<u8> &data) {
for (size_t i = 0; i < size; i += 2) { for (size_t i = 0; i < data.size(); i += 2) {
u16 original = *(u16 *) &data[i];
*(u16 *) &data[i] = bswap_16(original);
}
}
template <size_t Size>
FORCE_INLINE void SwapBuffer32(std::array<u8, Size> &data) {
for (size_t i = 0; i < Size; i += 4) {
u32 original = *(u32 *) &data[i];
*(u32 *) &data[i] = bswap_32(original);
}
}
template <size_t Size>
FORCE_INLINE void SwapBuffer16(std::array<u8, Size> &data) {
for (size_t i = 0; i < Size; i += 2) {
u16 original = *(u16 *) &data[i]; u16 original = *(u16 *) &data[i];
*(u16 *) &data[i] = bswap_16(original); *(u16 *) &data[i] = bswap_16(original);
} }