Merge branch 'dev' into jit
# Conflicts: # src/backend/core/registers/Registers.hpp
This commit is contained in:
@@ -12,7 +12,7 @@ void Core::Stop() {
|
||||
cpu->Reset();
|
||||
}
|
||||
|
||||
bool Core::LoadTAS(const fs::path &path) {
|
||||
bool Core::LoadTAS(const fs::path &path) const {
|
||||
return cpu->GetMem().mmio.si.pif.movie.Load(path);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ void Core::LoadROM(const std::string& rom_) {
|
||||
|
||||
cpu->GetMem().LoadROM(isArchive, rom);
|
||||
GameDB::match(cpu->GetMem());
|
||||
if(cpu->GetMem().rom.gameNameDB.empty()) {
|
||||
cpu->GetMem().rom.gameNameDB = fs::path(rom).stem();
|
||||
}
|
||||
cpu->GetMem().mmio.vi.isPal = cpu->GetMem().IsROMPAL();
|
||||
cpu->GetMem().mmio.si.pif.InitDevices(cpu->GetMem().saveType);
|
||||
cpu->GetMem().mmio.si.pif.mempakPath = rom;
|
||||
|
||||
@@ -11,7 +11,7 @@ struct Core {
|
||||
Core(ParallelRDP&);
|
||||
void Stop();
|
||||
void LoadROM(const std::string&);
|
||||
bool LoadTAS(const fs::path&);
|
||||
bool LoadTAS(const fs::path&) const;
|
||||
void Run(float volumeL, float volumeR);
|
||||
void Serialize();
|
||||
void Deserialize();
|
||||
|
||||
@@ -12,6 +12,7 @@ struct Interpreter : BaseCPU {
|
||||
void Reset() override {
|
||||
regs.Reset();
|
||||
mem.Reset();
|
||||
cop2Latch = {};
|
||||
}
|
||||
|
||||
Mem& GetMem() override {
|
||||
|
||||
@@ -15,7 +15,9 @@ struct Mem;
|
||||
struct Registers;
|
||||
|
||||
struct MMIO {
|
||||
MMIO(Mem& mem, Registers& regs, ParallelRDP& parallel) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) {}
|
||||
MMIO(Mem& mem, Registers& regs, ParallelRDP& parallel) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) {
|
||||
Reset();
|
||||
}
|
||||
void Reset();
|
||||
|
||||
VI vi;
|
||||
|
||||
@@ -9,16 +9,6 @@
|
||||
|
||||
namespace n64 {
|
||||
Mem::Mem(Registers& regs, ParallelRDP& parallel) : flash(saveData), mmio(*this, regs, parallel) {
|
||||
memset(readPages, 0, PAGE_COUNT);
|
||||
memset(writePages, 0, PAGE_COUNT);
|
||||
|
||||
for(u64 i = 0; i < RDRAM_SIZE / PAGE_SIZE; i++) {
|
||||
const auto addr = (i * PAGE_SIZE) & RDRAM_DSIZE;
|
||||
const auto pointer = (uintptr_t) &mmio.rdp.rdram[addr];
|
||||
readPages[i] = pointer;
|
||||
writePages[i] = pointer;
|
||||
}
|
||||
|
||||
rom.cart.resize(CART_SIZE);
|
||||
std::fill(rom.cart.begin(), rom.cart.end(), 0);
|
||||
}
|
||||
@@ -178,317 +168,261 @@ void Mem::LoadROM(bool isArchive, const std::string& filename) {
|
||||
}
|
||||
|
||||
template<> u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return ((u8*)pointer)[BYTE_ADDRESS(offset)];
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.rdram[BYTE_ADDRESS(paddr)];
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||
}
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u8, false>(paddr);
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04600000 ... 0x048FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF:
|
||||
Util::panic("MMIO Read<u8>!\n");
|
||||
case AI_REGION: {
|
||||
u32 w = mmio.ai.Read(paddr & ~3);
|
||||
int offs = 3 - (paddr & 3);
|
||||
return (w >> (offs * 8)) & 0xff;
|
||||
}
|
||||
case PIF_ROM_REGION:
|
||||
return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START];
|
||||
case PIF_RAM_REGION:
|
||||
return si.pif.ram[paddr - PIF_RAM_REGION_START];
|
||||
case 0x00800000 ... 0x03EFFFFF: // unused
|
||||
case 0x04200000 ... 0x042FFFFF: // unused
|
||||
case 0x04900000 ... 0x04FFFFFF: // unused
|
||||
case 0x1FC00800 ... 0xFFFFFFFF: // unused
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.ReadRDRAM<u8>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||
}
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u8, false>(paddr);
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04600000 ... 0x048FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF:
|
||||
Util::panic("MMIO Read<u8>!\n");
|
||||
case AI_REGION: {
|
||||
u32 w = mmio.ai.Read(paddr & ~3);
|
||||
int offs = 3 - (paddr & 3);
|
||||
return (w >> (offs * 8)) & 0xff;
|
||||
}
|
||||
case PIF_ROM_REGION:
|
||||
return si.pif.bootrom[BYTE_ADDRESS(paddr) - PIF_ROM_REGION_START];
|
||||
case PIF_RAM_REGION:
|
||||
return si.pif.ram[paddr - PIF_RAM_REGION_START];
|
||||
case 0x00800000 ... 0x03EFFFFF: // unused
|
||||
case 0x04200000 ... 0x042FFFFF: // unused
|
||||
case 0x04900000 ... 0x04FFFFFF: // unused
|
||||
case 0x1FC00800 ... 0xFFFFFFFF: // unused
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u16>((u8*)pointer, HALF_ADDRESS(offset));
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr));
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u16, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be16toh(Util::ReadAccess<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00800 ... 0xFFFFFFFF:
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.ReadRDRAM<u16>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u16, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u16>(si.pif.bootrom, HALF_ADDRESS(paddr) - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be16toh(Util::ReadAccess<u16>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00800 ... 0xFFFFFFFF:
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u32>((u8*)pointer, offset);
|
||||
} else {
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u32>(mmio.rdp.rdram, paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u32>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u32, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.ReadRDRAM<u32>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u32>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u32, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u32>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be32toh(Util::ReadAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF: case 0x1FC00800 ... 0xFFFFFFFF: return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> u64 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
return Util::ReadAccess<u64>((u8*)pointer, offset);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return Util::ReadAccess<u64>(mmio.rdp.rdram, paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u64>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u64, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be64toh(Util::ReadAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00800 ... 0xFFFFFFFF:
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
return mmio.rdp.ReadRDRAM<u64>(paddr);
|
||||
case RSP_MEM_REGION: {
|
||||
auto& src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u64>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
return mmio.Read(paddr);
|
||||
case REGION_CART:
|
||||
return mmio.pi.BusRead<u64, false>(paddr);
|
||||
case PIF_ROM_REGION:
|
||||
return Util::ReadAccess<u64>(si.pif.bootrom, paddr - PIF_ROM_REGION_START);
|
||||
case PIF_RAM_REGION:
|
||||
return be64toh(Util::ReadAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START));
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00800 ... 0xFFFFFFFF:
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})", paddr, (u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u8>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
((u8*)pointer)[BYTE_ADDRESS(offset)] = val;
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val;
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
paddr = (paddr & 0xFFF) & ~3;
|
||||
Util::WriteAccess<u32>(dest, paddr, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
||||
mmio.pi.BusWrite<u8, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u8>!");
|
||||
case PIF_RAM_REGION:
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.WriteRDRAM<u8>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
paddr = (paddr & 0xFFF) & ~3;
|
||||
Util::WriteAccess<u32>(dest, paddr, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:02X}", paddr, val);
|
||||
mmio.pi.BusWrite<u8, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u8>!");
|
||||
case PIF_RAM_REGION:
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
paddr = (paddr - PIF_RAM_REGION_START) & ~3;
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit write at address {:08X} with value {:02X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u16>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u16>((u8*)pointer, HALF_ADDRESS(offset), val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u16>(mmio.rdp.rdram, HALF_ADDRESS(paddr), val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (16 * !(paddr & 2));
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
paddr = (paddr & 0xFFF) & ~3;
|
||||
Util::WriteAccess<u32>(dest, paddr, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
||||
mmio.pi.BusWrite<u16, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u16>!");
|
||||
case PIF_RAM_REGION:
|
||||
val = val << (16 * !(paddr & 2));
|
||||
paddr &= ~3;
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.WriteRDRAM<u16>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
val = val << (16 * !(paddr & 2));
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
paddr = (paddr & 0xFFF) & ~3;
|
||||
Util::WriteAccess<u32>(dest, paddr, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:04X}", paddr, val);
|
||||
mmio.pi.BusWrite<u16, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write<u16>!");
|
||||
case PIF_RAM_REGION:
|
||||
val = val << (16 * !(paddr & 2));
|
||||
paddr &= ~3;
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit write at address {:08X} with value {:04X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void Mem::Write<u32>(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u32>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u32>(mmio.rdp.rdram, paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
||||
mmio.pi.BusWrite<u32, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
mmio.Write(paddr, val);
|
||||
break;
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||
}
|
||||
switch(paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.WriteRDRAM<u32>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:08X}", paddr, val);
|
||||
mmio.pi.BusWrite<u32, false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
mmio.Write(paddr, val);
|
||||
break;
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u32>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe32(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case PIF_ROM_REGION:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val, (u64)regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
void Mem::Write(Registers& regs, u32 paddr, u64 val) {
|
||||
const auto page = paddr >> 12;
|
||||
const auto offset = paddr & 0xFFF;
|
||||
const auto pointer = writePages[page];
|
||||
SI& si = mmio.si;
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u64>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
Util::WriteAccess<u64>(mmio.rdp.rdram, paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
val >>= 32;
|
||||
Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);
|
||||
mmio.pi.BusWrite<false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write!");
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe64(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00000 ... 0x1FC007BF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
default:
|
||||
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
switch (paddr) {
|
||||
case RDRAM_REGION:
|
||||
mmio.rdp.WriteRDRAM<u64>(paddr, val);
|
||||
break;
|
||||
case RSP_MEM_REGION: {
|
||||
auto& dest = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
val >>= 32;
|
||||
Util::WriteAccess<u32>(dest, paddr & 0xfff, val);
|
||||
} break;
|
||||
case REGION_CART:
|
||||
Util::trace("BusWrite<u8> @ {:08X} = {:016X}", paddr, val);
|
||||
mmio.pi.BusWrite<false>(paddr, val);
|
||||
break;
|
||||
case MMIO_REGION:
|
||||
Util::panic("MMIO Write!");
|
||||
case PIF_RAM_REGION:
|
||||
Util::WriteAccess<u64>(si.pif.ram, paddr - PIF_RAM_REGION_START, htobe64(val));
|
||||
si.pif.ProcessCommands(*this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03EFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x04900000 ... 0x04FFFFFF:
|
||||
case 0x1FC00000 ... 0x1FC007BF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
default:
|
||||
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,6 @@ struct Mem {
|
||||
Util::SwapBuffer32(temp);
|
||||
Util::WriteFileBinary(temp, "dmem.bin");
|
||||
}
|
||||
uintptr_t writePages[PAGE_COUNT]{}, readPages[PAGE_COUNT]{};
|
||||
ROM rom;
|
||||
SaveType saveType = SAVE_NONE;
|
||||
Flash flash;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <log.hpp>
|
||||
#include <core/RSP.hpp>
|
||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RDP::RDP(Mem& mem, ParallelRDP& parallel) : mem(mem), parallel(parallel) {
|
||||
@@ -13,11 +12,60 @@ RDP::RDP(Mem& mem, ParallelRDP& parallel) : mem(mem), parallel(parallel) {
|
||||
}
|
||||
|
||||
void RDP::Reset() {
|
||||
dpc = {};
|
||||
dpc.status.raw = 0x80;
|
||||
std::fill(rdram.begin(), rdram.end(), 0);
|
||||
memset(cmd_buf, 0, 0x100000);
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u8>(size_t idx, u8 v) {
|
||||
size_t real = BYTE_ADDRESS(idx);
|
||||
if(real < RDRAM_SIZE) {
|
||||
rdram[real] = v;
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u16>(size_t idx, u16 v) {
|
||||
size_t real = HALF_ADDRESS(idx);
|
||||
if(real < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u16>(rdram, real, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u32>(size_t idx, u32 v) {
|
||||
if(idx < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u32>(rdram, idx, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void RDP::WriteRDRAM<u64>(size_t idx, u64 v) {
|
||||
if(idx < RDRAM_SIZE) {
|
||||
Util::WriteAccess<u64>(rdram, idx, v);
|
||||
}
|
||||
}
|
||||
|
||||
template<> u8 RDP::ReadRDRAM<u8>(size_t idx) {
|
||||
size_t real = BYTE_ADDRESS(idx);
|
||||
if(real >= RDRAM_SIZE) return 0;
|
||||
return rdram[real];
|
||||
}
|
||||
|
||||
template<> u16 RDP::ReadRDRAM<u16>(size_t idx) {
|
||||
size_t real = HALF_ADDRESS(idx);
|
||||
if(real >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u16>(rdram, real);
|
||||
}
|
||||
|
||||
template<> u32 RDP::ReadRDRAM<u32>(size_t idx) {
|
||||
if(idx >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u32>(rdram, idx);
|
||||
}
|
||||
|
||||
template<> u64 RDP::ReadRDRAM<u64>(size_t idx) {
|
||||
if(idx >= RDRAM_SIZE) return 0;
|
||||
return Util::ReadAccess<u64>(rdram, idx);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -59,7 +59,6 @@ struct RDP {
|
||||
RDP(Mem&, ParallelRDP&);
|
||||
void Reset();
|
||||
|
||||
std::vector<u8> rdram{};
|
||||
[[nodiscard]] auto Read(u32 addr) const -> u32;
|
||||
void Write(u32 addr, u32 val);
|
||||
void WriteStatus(u32 val);
|
||||
@@ -81,7 +80,16 @@ struct RDP {
|
||||
}
|
||||
RunCommand();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void WriteRDRAM(size_t, T);
|
||||
template<typename T>
|
||||
T ReadRDRAM(size_t);
|
||||
private:
|
||||
friend struct Mem;
|
||||
friend struct MMIO;
|
||||
std::vector<u8> rdram{};
|
||||
|
||||
Mem& mem;
|
||||
ParallelRDP& parallel;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@ void RSP::Reset() {
|
||||
divIn = 0;
|
||||
divOut = 0;
|
||||
divInLoaded = false;
|
||||
steps = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -66,10 +67,10 @@ FORCE_INLINE void logRSP(const RSP& rsp, const u32 instr) {
|
||||
}
|
||||
*/
|
||||
|
||||
auto RSP::Read(u32 addr) -> u32{
|
||||
auto RSP::Read(u32 addr) -> u32 {
|
||||
switch (addr) {
|
||||
case 0x04040000: return lastSuccessfulSPAddr.raw & 0x1FF8;
|
||||
case 0x04040004: return lastSuccessfulDRAMAddr.raw & 0xFFFFF8;
|
||||
case 0x04040004: return lastSuccessfulDRAMAddr.raw & 0xFFFFFC;
|
||||
case 0x04040008:
|
||||
case 0x0404000C: return spDMALen.raw;
|
||||
case 0x04040010: return spStatus.raw;
|
||||
@@ -110,17 +111,79 @@ void RSP::WriteStatus(u32 value) {
|
||||
CLEAR_SET(spStatus.signal7, write.clearSignal7, write.setSignal7);
|
||||
}
|
||||
|
||||
template <> void RSP::DMA<true>() {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE>& src = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFFC;
|
||||
Util::trace("SP DMA from RSP to RDRAM (size: {} B, {:08X} to {:08X})", length, mem_address, dram_address);
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(BYTE_ADDRESS(dram_address + j), src[(mem_address + j) & DMEM_DSIZE]);
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFFC;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
Util::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
template <> void RSP::DMA<false>() {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE>& dst = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFFC;
|
||||
Util::trace("SP DMA from RDRAM to RSP (size: {} B, {:08X} to {:08X})", length, dram_address, mem_address);
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = mem.mmio.rdp.ReadRDRAM<u8>(BYTE_ADDRESS(dram_address + j));
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFFC;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
Util::trace("Addresses after: RSP: 0x{:08X}, Dram: 0x{:08X}", mem_address, dram_address);
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void RSP::Write(u32 addr, u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04040000: spDMASPAddr.raw = val & 0x1FF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFF8; break;
|
||||
case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFFC; break;
|
||||
case 0x04040008: {
|
||||
spDMALen.raw = val;
|
||||
DMAtoRSP(mem.GetRDRAM());
|
||||
DMA<false>();
|
||||
} break;
|
||||
case 0x0404000C: {
|
||||
spDMALen.raw = val;
|
||||
DMAtoRDRAM(mem.GetRDRAM());
|
||||
DMA<true>();
|
||||
} break;
|
||||
case 0x04040010: WriteStatus(val); break;
|
||||
case 0x0404001C: ReleaseSemaphore(); break;
|
||||
@@ -132,70 +195,4 @@ void RSP::Write(u32 addr, u32 val) {
|
||||
Util::panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
void RSP::DMAtoRDRAM(std::vector<u8>& rdram) {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::vector<u8>& dst = rdram;
|
||||
std::array<u8, DMEM_SIZE>& src = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
if((dram_address + j) < RDRAM_SIZE) {
|
||||
dst[dram_address + j] = src[(mem_address + j) & DMEM_DSIZE];
|
||||
}
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void RSP::DMAtoRSP(std::vector<u8>& rdram) {
|
||||
u32 length = spDMALen.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::vector<u8>& src = rdram;
|
||||
std::array<u8, DMEM_SIZE>& dst = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
|
||||
for (u32 i = 0; i < spDMALen.count + 1; i++) {
|
||||
for(u32 j = 0; j < length; j++) {
|
||||
if((dram_address + j) < RDRAM_SIZE) {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = src[dram_address + j];
|
||||
} else {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
|
||||
lastSuccessfulSPAddr.address = mem_address;
|
||||
lastSuccessfulSPAddr.bank = spDMASPAddr.bank;
|
||||
lastSuccessfulDRAMAddr.address = dram_address;
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <core/RDP.hpp>
|
||||
#include <MemoryRegions.hpp>
|
||||
#include <MemoryHelpers.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
#include <array>
|
||||
|
||||
#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
|
||||
@@ -358,8 +357,8 @@ struct RSP {
|
||||
void mfc2(u32 instr);
|
||||
void mtc2(u32 instr);
|
||||
|
||||
void DMAtoRDRAM(std::vector<u8>& rdram);
|
||||
void DMAtoRSP(std::vector<u8>& rdram);
|
||||
template <bool toRdram>
|
||||
void DMA();
|
||||
void WriteStatus(u32 value);
|
||||
private:
|
||||
Registers& regs;
|
||||
|
||||
@@ -51,12 +51,12 @@ void Interpreter::special(u32 instr) {
|
||||
case DADDU: daddu(instr); break;
|
||||
case DSUB: dsub(instr); break;
|
||||
case DSUBU: dsubu(instr); break;
|
||||
case TGE: trap(regs.gpr[RS(instr)] >= regs.gpr[RT(instr)]); break;
|
||||
case TGEU: trap((u64)regs.gpr[RS(instr)] >= (u64)regs.gpr[RT(instr)]); break;
|
||||
case TLT: trap(regs.gpr[RS(instr)] < regs.gpr[RT(instr)]); break;
|
||||
case TLTU: trap((u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]); break;
|
||||
case TEQ: trap(regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case TNE: trap(regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
||||
case TGE: trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr))); break;
|
||||
case TGEU: trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr))); break;
|
||||
case TLT: trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr))); break;
|
||||
case TLTU: trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr))); break;
|
||||
case TEQ: trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case TNE: trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case DSLL: dsll(instr); break;
|
||||
case DSRL: dsrl(instr); break;
|
||||
case DSRA: dsra(instr); break;
|
||||
@@ -72,20 +72,20 @@ void Interpreter::regimm(u32 instr) {
|
||||
u8 mask = ((instr >> 16) & 0x1F);
|
||||
// 000r_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
case BLTZ: b(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZ: b(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZL: bl(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZL: bl(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case TGEI: trap(regs.gpr[RS(instr)] >= s64(s16(instr))); break;
|
||||
case TGEIU: trap(u64(regs.gpr[RS(instr)]) >= u64(s64(s16(instr)))); break;
|
||||
case TLTI: trap(regs.gpr[RS(instr)] < s64(s16(instr))); break;
|
||||
case TLTIU: trap(u64(regs.gpr[RS(instr)]) < u64(s64(s16(instr)))); break;
|
||||
case TEQI: trap(regs.gpr[RS(instr)] == s64(s16(instr))); break;
|
||||
case TNEI: trap(regs.gpr[RS(instr)] != s64(s16(instr))); break;
|
||||
case BLTZAL: blink(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZAL: blink(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZALL: bllink(instr, regs.gpr[RS(instr)] < 0); break;
|
||||
case BGEZALL: bllink(instr, regs.gpr[RS(instr)] >= 0); break;
|
||||
case BLTZ: b(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZ: b(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case BLTZL: bl(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZL: bl(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case TGEI: trap(regs.Read<s64>(RS(instr)) >= s64(s16(instr))); break;
|
||||
case TGEIU: trap(regs.Read<u64>(RS(instr)) >= u64(s64(s16(instr)))); break;
|
||||
case TLTI: trap(regs.Read<s64>(RS(instr)) < s64(s16(instr))); break;
|
||||
case TLTIU: trap(regs.Read<u64>(RS(instr)) < u64(s64(s16(instr)))); break;
|
||||
case TEQI: trap(regs.Read<s64>(RS(instr)) == s64(s16(instr))); break;
|
||||
case TNEI: trap(regs.Read<s64>(RS(instr)) != s64(s16(instr))); break;
|
||||
case BLTZAL: blink(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZAL: blink(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
case BLTZALL: bllink(instr, regs.Read<s64>(RS(instr)) < 0); break;
|
||||
case BGEZALL: bllink(instr, regs.Read<s64>(RS(instr)) >= 0); break;
|
||||
default:
|
||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
@@ -116,13 +116,10 @@ void Interpreter::Exec(u32 instr) {
|
||||
case REGIMM: regimm(instr); break;
|
||||
case J: j(instr); break;
|
||||
case JAL: jal(instr); break;
|
||||
case BEQ: b(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case BNE: {
|
||||
//fmt::print("RS: {:016X}, RT: {:016X}", (u64)regs.gpr[RS(instr)], (u64)regs.gpr[RT(instr)]);
|
||||
b(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]);
|
||||
} break;
|
||||
case BLEZ: b(instr, regs.gpr[RS(instr)] <= 0); break;
|
||||
case BGTZ: b(instr, regs.gpr[RS(instr)] > 0); break;
|
||||
case BEQ: b(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case BNE: b(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case BLEZ: b(instr, regs.Read<s64>(RS(instr)) <= 0); break;
|
||||
case BGTZ: b(instr, regs.Read<s64>(RS(instr)) > 0); break;
|
||||
case ADDI: addi(instr); break;
|
||||
case ADDIU: addiu(instr); break;
|
||||
case SLTI: slti(instr); break;
|
||||
@@ -134,10 +131,10 @@ void Interpreter::Exec(u32 instr) {
|
||||
case COP0: regs.cop0.decode(*this, instr); break;
|
||||
case COP1: regs.cop1.decode(*this, instr); break;
|
||||
case COP2: cop2Decode(instr); break;
|
||||
case BEQL: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case BNEL: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
||||
case BLEZL: bl(instr, regs.gpr[RS(instr)] <= 0); break;
|
||||
case BGTZL: bl(instr, regs.gpr[RS(instr)] > 0); break;
|
||||
case BEQL: bl(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); break;
|
||||
case BNEL: bl(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); break;
|
||||
case BLEZL: bl(instr, regs.Read<s64>(RS(instr)) <= 0); break;
|
||||
case BGTZL: bl(instr, regs.Read<s64>(RS(instr)) > 0); break;
|
||||
case DADDI: daddi(instr); break;
|
||||
case DADDIU: daddiu(instr); break;
|
||||
case LDL: ldl(instr); break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,11 @@ Flash::Flash(mio::mmap_sink &saveData) : saveData(saveData) {}
|
||||
|
||||
void Flash::Reset() {
|
||||
state = FlashState::Idle;
|
||||
writeOffs = {};
|
||||
state = {};
|
||||
status = {};
|
||||
eraseOffs = {};
|
||||
writeBuf = {};
|
||||
}
|
||||
|
||||
void Flash::Load(SaveType saveType, const std::string& path) {
|
||||
|
||||
@@ -13,8 +13,8 @@ void AI::Reset() {
|
||||
dmaCount = 0;
|
||||
dmaAddrCarry = false;
|
||||
cycles = 0;
|
||||
memset(dmaLen, 0, 2);
|
||||
memset(dmaAddr, 0, 2);
|
||||
dmaLen = {};
|
||||
dmaAddr = {};
|
||||
dac = {44100, N64_CPU_FREQ / dac.freq, 16};
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ void AI::Step(u32 cpuCycles, float volumeL, float volumeR) {
|
||||
if(dmaLen[0] && dmaEnable) {
|
||||
u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF;
|
||||
dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF);
|
||||
u32 data = Util::ReadAccess<u32>(mem.mmio.rdp.rdram, dmaAddr[0] & RDRAM_DSIZE);
|
||||
u32 data = mem.mmio.rdp.ReadRDRAM<u32>(dmaAddr[0]);
|
||||
s16 l = s16(data >> 16);
|
||||
s16 r = s16(data);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/Audio.hpp>
|
||||
|
||||
namespace n64 {
|
||||
@@ -17,8 +16,8 @@ struct AI {
|
||||
u16 dacRate{};
|
||||
u8 bitrate{};
|
||||
int dmaCount{};
|
||||
u32 dmaLen[2]{};
|
||||
u32 dmaAddr[2]{};
|
||||
std::array<u32, 2> dmaLen{};
|
||||
std::array<u32, 2> dmaAddr{};
|
||||
bool dmaAddrCarry{};
|
||||
u32 cycles{};
|
||||
AudioDevice device;
|
||||
|
||||
@@ -11,19 +11,13 @@ namespace n64 {
|
||||
void audioCallback(void* user, Uint8* stream, int length) {
|
||||
auto audioDevice = (AudioDevice*)user;
|
||||
int gotten = 0, available = 0;
|
||||
|
||||
if (audioDevice) {
|
||||
audioDevice->LockMutex();
|
||||
}
|
||||
|
||||
if (audioDevice) {
|
||||
available = SDL_AudioStreamAvailable(audioDevice->GetStream().get());
|
||||
}
|
||||
|
||||
if (available > 0 && audioDevice) {
|
||||
gotten = SDL_AudioStreamGet(audioDevice->GetStream().get(), stream, length);
|
||||
}
|
||||
|
||||
if (audioDevice) {
|
||||
available = SDL_AudioStreamAvailable(audioDevice->GetStream());
|
||||
if (available > 0) {
|
||||
gotten = SDL_AudioStreamGet(audioDevice->GetStream(), stream, length);
|
||||
}
|
||||
audioDevice->UnlockMutex();
|
||||
}
|
||||
|
||||
@@ -37,11 +31,18 @@ void audioCallback(void* user, Uint8* stream, int length) {
|
||||
}
|
||||
}
|
||||
|
||||
AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream, SDL_FreeAudioStream, "audioStream", SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE),
|
||||
audioStreamMutex(SDL_CreateMutex, SDL_DestroyMutex, "audioStreamMutex") {
|
||||
AudioDevice::~AudioDevice() {
|
||||
LockMutex();
|
||||
SDL_FreeAudioStream(GetStream());
|
||||
UnlockMutex();
|
||||
SDL_DestroyMutex(audioStreamMutex);
|
||||
}
|
||||
|
||||
AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE)),
|
||||
audioStreamMutex(SDL_CreateMutex()) {
|
||||
SDL_InitSubSystem(SDL_INIT_AUDIO);
|
||||
|
||||
if(!audioStreamMutex.get()) {
|
||||
if(!audioStreamMutex) {
|
||||
Util::panic("Unable to initialize audio mutex: {}", SDL_GetError());
|
||||
}
|
||||
|
||||
@@ -66,15 +67,16 @@ void AudioDevice::PushSample(float left, float volumeL, float right, float volum
|
||||
float adjustedR = right * volumeR;
|
||||
float samples[2]{ adjustedL, adjustedR };
|
||||
|
||||
auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream.get());
|
||||
auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream);
|
||||
if(availableBytes <= BYTES_PER_HALF_SECOND) {
|
||||
SDL_AudioStreamPut(audioStream.get(), samples, 2 * sizeof(float));
|
||||
SDL_AudioStreamPut(audioStream, samples, 2 * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
||||
LockMutex();
|
||||
audioStream.Construct(SDL_NewAudioStream, SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
||||
SDL_FreeAudioStream(audioStream);
|
||||
audioStream = SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE);
|
||||
UnlockMutex();
|
||||
}
|
||||
}
|
||||
@@ -5,24 +5,23 @@
|
||||
namespace n64 {
|
||||
struct AudioDevice {
|
||||
AudioDevice();
|
||||
~AudioDevice();
|
||||
|
||||
void PushSample(float, float, float, float);
|
||||
void AdjustSampleRate(int);
|
||||
void LockMutex() {
|
||||
if(audioStreamMutex.get())
|
||||
SDL_LockMutex(audioStreamMutex.get());
|
||||
if(audioStreamMutex)
|
||||
SDL_LockMutex(audioStreamMutex);
|
||||
}
|
||||
void UnlockMutex() {
|
||||
if (audioStreamMutex.get())
|
||||
SDL_UnlockMutex(audioStreamMutex.get());
|
||||
if (audioStreamMutex)
|
||||
SDL_UnlockMutex(audioStreamMutex);
|
||||
}
|
||||
|
||||
Util::AutoRelease<SDL_AudioStream, const SDL_AudioFormat, const Uint8, const int, const SDL_AudioFormat,
|
||||
const Uint8, const int>& GetStream() { return audioStream; }
|
||||
SDL_AudioStream* GetStream() { return audioStream; }
|
||||
private:
|
||||
Util::AutoRelease<SDL_AudioStream, const SDL_AudioFormat, const Uint8, const int, const SDL_AudioFormat,
|
||||
const Uint8, const int> audioStream;
|
||||
Util::AutoRelease<SDL_mutex> audioStreamMutex;
|
||||
SDL_AudioStream* audioStream;
|
||||
SDL_mutex* audioStreamMutex;
|
||||
SDL_AudioSpec audioSpec{};
|
||||
SDL_AudioSpec request{};
|
||||
SDL_AudioDeviceID handle{};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
struct Registers;
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
#define MI_VERSION_REG 0x02020102
|
||||
|
||||
@@ -60,7 +59,7 @@ void MI::Write(u32 paddr, u32 val) {
|
||||
miMode |= 1 << 9;
|
||||
}
|
||||
break;
|
||||
case 0x4: break;
|
||||
case 0x4: case 0x8: break;
|
||||
case 0xC:
|
||||
for (int bit = 0; bit < 6; bit++) {
|
||||
int clearbit = bit << 1;
|
||||
|
||||
@@ -14,8 +14,6 @@ void PI::Reset() {
|
||||
latch = 0;
|
||||
dramAddr = 0;
|
||||
cartAddr = 0;
|
||||
dramAddrInternal = 0;
|
||||
cartAddrInternal = 0;
|
||||
rdLen = 0;
|
||||
wrLen = 0;
|
||||
piBsdDom1Lat = 0;
|
||||
@@ -271,7 +269,7 @@ template <> void PI::BusWrite<u32, false>(u32 addr, u32 val) {
|
||||
if (val < CART_ISVIEWER_SIZE) {
|
||||
std::string message(val + 1, 0);
|
||||
std::copy(mem.isviewer.begin(), mem.isviewer.begin() + val, message.begin());
|
||||
Util::always("{}", message);
|
||||
Util::print<Util::Always>("{}", message);
|
||||
} else {
|
||||
Util::panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", CART_ISVIEWER_SIZE, val);
|
||||
}
|
||||
@@ -353,8 +351,8 @@ template <> void PI::BusWrite<true>(u32 addr, u64 val) {
|
||||
|
||||
auto PI::Read(u32 addr) const -> u32 {
|
||||
switch(addr) {
|
||||
case 0x04600000: return dramAddr;
|
||||
case 0x04600004: return cartAddr;
|
||||
case 0x04600000: return dramAddr & 0x00FFFFFE;
|
||||
case 0x04600004: return cartAddr & 0xFFFFFFFE;
|
||||
case 0x04600008: return rdLen;
|
||||
case 0x0460000C: return wrLen;
|
||||
case 0x04600010: {
|
||||
@@ -425,57 +423,60 @@ u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
return cycles * 1.5; // Converting RCP clock speed to CPU clock speed
|
||||
}
|
||||
|
||||
// rdram -> cart
|
||||
template <> void PI::DMA<false>() {
|
||||
s32 len = rdLen + 1;
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) {
|
||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
BusWrite<u8, true>(cartAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
||||
}
|
||||
dramAddr += len;
|
||||
dramAddr = (dramAddr + 7) & ~7;
|
||||
cartAddr += len;
|
||||
if(cartAddr & 1) cartAddr += 1;
|
||||
|
||||
dmaBusy = true;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), rdLen), PI_DMA_COMPLETE);
|
||||
}
|
||||
|
||||
// cart -> rdram
|
||||
template <> void PI::DMA<true>() {
|
||||
s32 len = wrLen + 1;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) {
|
||||
cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1);
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < len; i++) {
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, BusRead<u8, true>(cartAddr + i));
|
||||
}
|
||||
dramAddr += len;
|
||||
dramAddr = (dramAddr + 7) & ~7;
|
||||
cartAddr += len;
|
||||
if(cartAddr & 1) cartAddr += 1;
|
||||
|
||||
dmaBusy = true;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
}
|
||||
|
||||
void PI::Write(u32 addr, u32 val) {
|
||||
MI& mi = mem.mmio.mi;
|
||||
switch(addr) {
|
||||
case 0x04600000: dramAddr = val & 0xFFFFFF; break;
|
||||
case 0x04600004: cartAddr = val; break;
|
||||
case 0x04600000: dramAddr = val & 0x00FFFFFE; break;
|
||||
case 0x04600004: cartAddr = val & 0xFFFFFFFE; break;
|
||||
case 0x04600008: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
cartAddrInternal = cartAddr & 0xFFFFFFFE;
|
||||
dramAddrInternal = dramAddr & 0x007FFFFE;
|
||||
if (dramAddrInternal & 0x7) {
|
||||
len -= dramAddrInternal & 0x7;
|
||||
}
|
||||
rdLen = len;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
u32 addr = BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE;
|
||||
if (addr < RDRAM_SIZE) {
|
||||
BusWrite<u8, true>(cartAddrInternal + i, mem.mmio.rdp.rdram[addr]);
|
||||
}
|
||||
else {
|
||||
BusWrite<u8, true>(cartAddrInternal + i, 0);
|
||||
}
|
||||
}
|
||||
Util::trace("PI DMA from RDRAM to CARTRIDGE (size: {} B, {:08X} to {:08X})", len, dramAddr, cartAddr);
|
||||
dmaBusy = true;
|
||||
toCart = true;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
rdLen = val & 0x00FFFFFF;
|
||||
DMA<false>();
|
||||
} break;
|
||||
case 0x0460000C: {
|
||||
u32 len = (val & 0x00FFFFFF) + 1;
|
||||
cartAddrInternal = cartAddr & 0xFFFFFFFE;
|
||||
dramAddrInternal = dramAddr & 0x007FFFFE;
|
||||
if (dramAddrInternal & 0x7) {
|
||||
len -= (dramAddrInternal & 0x7);
|
||||
}
|
||||
wrLen = len;
|
||||
|
||||
if(mem.saveType == SAVE_FLASH_1m && cartAddrInternal >= SREGION_PI_SRAM && cartAddrInternal < 0x08010000) {
|
||||
cartAddrInternal = SREGION_PI_SRAM | ((cartAddrInternal & 0xFFFFF) << 1);
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < len; i++) {
|
||||
u32 addr = BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE;
|
||||
if (addr < RDRAM_SIZE) {
|
||||
mem.mmio.rdp.rdram[addr] = BusRead<u8, true>(cartAddrInternal + i);
|
||||
}
|
||||
}
|
||||
dmaBusy = true;
|
||||
Util::trace("PI DMA from CARTRIDGE to RDRAM (size: {} B, {:08X} to {:08X})", len, cartAddr, dramAddr);
|
||||
toCart = false;
|
||||
scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE);
|
||||
wrLen = val & 0x00FFFFFF;
|
||||
DMA<true>();
|
||||
} break;
|
||||
case 0x04600010:
|
||||
if(val & 2) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
@@ -26,15 +25,18 @@ struct PI {
|
||||
|
||||
static u8 GetDomain(u32 address);
|
||||
[[nodiscard]] u32 AccessTiming(u8 domain, u32 length) const;
|
||||
bool dmaBusy{}, ioBusy{}, toCart{};
|
||||
bool dmaBusy{}, ioBusy{};
|
||||
u32 latch{};
|
||||
u32 dramAddr{}, cartAddr{}, dramAddrInternal{}, cartAddrInternal{};
|
||||
u32 dramAddr{}, cartAddr{};
|
||||
u32 rdLen{}, wrLen{};
|
||||
u32 piBsdDom1Lat{}, piBsdDom2Lat{};
|
||||
u32 piBsdDom1Pwd{}, piBsdDom2Pwd{};
|
||||
u32 piBsdDom1Pgs{}, piBsdDom2Pgs{};
|
||||
u32 piBsdDom1Rls{}, piBsdDom2Rls{};
|
||||
private:
|
||||
template <bool toDram>
|
||||
void DMA();
|
||||
|
||||
Mem& mem;
|
||||
Registers& regs;
|
||||
};
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
namespace n64 {
|
||||
void PIF::Reset() {
|
||||
memset(joybusDevices, 0, sizeof(JoybusDevice) * 6);
|
||||
memset(bootrom, 0, PIF_BOOTROM_SIZE);
|
||||
memset(ram, 0, PIF_RAM_SIZE);
|
||||
movie.Reset();
|
||||
joybusDevices = {};
|
||||
bootrom = {};
|
||||
ram = {};
|
||||
std::error_code error;
|
||||
if(mempak.is_mapped()) {
|
||||
mempak.sync(error);
|
||||
@@ -26,6 +27,7 @@ void PIF::Reset() {
|
||||
}
|
||||
|
||||
mempakOpen = false;
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
void PIF::MaybeLoadMempak() {
|
||||
@@ -341,202 +343,202 @@ void PIF::HLE(bool pal, CICType cicType) {
|
||||
Util::warn("Unknown CIC type!");
|
||||
break;
|
||||
case CIC_NUS_6101:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFDF6445CCll;
|
||||
regs.gpr[3] = 0xFFFFFFFFDF6445CCll;
|
||||
regs.gpr[4] = 0x00000000000045CC;
|
||||
regs.gpr[5] = 0x0000000073EE317A;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFC7601FACll;
|
||||
regs.gpr[13] = 0xFFFFFFFFC7601FACll;
|
||||
regs.gpr[14] = 0xFFFFFFFFB48E2ED6ll;
|
||||
regs.gpr[15] = 0xFFFFFFFFBA1A7D4Bll;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000001;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0xFFFFFFFF905F4718ll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFDF6445CC);
|
||||
regs.Write(3, 0xFFFFFFFFDF6445CC);
|
||||
regs.Write(4, 0x00000000000045CC);
|
||||
regs.Write(5, 0x0000000073EE317A);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFC7601FAC);
|
||||
regs.Write(13, 0xFFFFFFFFC7601FAC);
|
||||
regs.Write(14, 0xFFFFFFFFB48E2ED6);
|
||||
regs.Write(15, 0xFFFFFFFFBA1A7D4B);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000001);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0xFFFFFFFF905F4718);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0xFFFFFFFFBA1A7D4Bll;
|
||||
regs.hi = 0xFFFFFFFF997EC317ll;
|
||||
break;
|
||||
case CIC_NUS_7102:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000001E324416;
|
||||
regs.gpr[3] = 0x000000001E324416;
|
||||
regs.gpr[4] = 0x0000000000004416;
|
||||
regs.gpr[5] = 0x000000000EC5D9AF;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0x00000000495D3D7B;
|
||||
regs.gpr[13] = 0xFFFFFFFF8B3DFA1Ell;
|
||||
regs.gpr[14] = 0x000000004798E4D4;
|
||||
regs.gpr[15] = 0xFFFFFFFFF1D30682ll;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[22] = 0x000000000000003F;
|
||||
regs.gpr[23] = 0x0000000000000007;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0x0000000013D05CAB;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x000000001E324416);
|
||||
regs.Write(3, 0x000000001E324416);
|
||||
regs.Write(4, 0x0000000000004416);
|
||||
regs.Write(5, 0x000000000EC5D9AF);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0x00000000495D3D7B);
|
||||
regs.Write(13, 0xFFFFFFFF8B3DFA1E);
|
||||
regs.Write(14, 0x000000004798E4D4);
|
||||
regs.Write(15, 0xFFFFFFFFF1D30682);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(22, 0x000000000000003F);
|
||||
regs.Write(23, 0x0000000000000007);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0x0000000013D05CAB);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
|
||||
regs.lo = 0xFFFFFFFFF1D30682ll;
|
||||
regs.hi = 0x0000000010054A98;
|
||||
break;
|
||||
case CIC_NUS_6102_7101:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x000000000EBDA536;
|
||||
regs.gpr[3] = 0x000000000EBDA536;
|
||||
regs.gpr[4] = 0x000000000000A536;
|
||||
regs.gpr[5] = 0xFFFFFFFFC0F1D859ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFED10D0B3ll;
|
||||
regs.gpr[13] = 0x000000001402A4CC;
|
||||
regs.gpr[14] = 0x000000002DE108EA;
|
||||
regs.gpr[15] = 0x000000003103E121;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0xFFFFFFFF9DEBB54Fll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x000000000EBDA536);
|
||||
regs.Write(3, 0x000000000EBDA536);
|
||||
regs.Write(4, 0x000000000000A536);
|
||||
regs.Write(5, 0xFFFFFFFFC0F1D859);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFED10D0B3);
|
||||
regs.Write(13, 0x000000001402A4CC);
|
||||
regs.Write(14, 0x000000002DE108EA);
|
||||
regs.Write(15, 0x000000003103E121);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0xFFFFFFFF9DEBB54F);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.hi = 0x000000003FC18657;
|
||||
regs.lo = 0x000000003103E121;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6103_7103:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000001;
|
||||
regs.gpr[2] = 0x0000000049A5EE96;
|
||||
regs.gpr[3] = 0x0000000049A5EE96;
|
||||
regs.gpr[4] = 0x000000000000EE96;
|
||||
regs.gpr[5] = 0xFFFFFFFFD4646273ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFCE9DFBF7ll;
|
||||
regs.gpr[13] = 0xFFFFFFFFCE9DFBF7ll;
|
||||
regs.gpr[14] = 0x000000001AF99984;
|
||||
regs.gpr[15] = 0x0000000018B63D28;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000000;
|
||||
regs.gpr[25] = 0xFFFFFFFF825B21C9ll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000001);
|
||||
regs.Write(2, 0x0000000049A5EE96);
|
||||
regs.Write(3, 0x0000000049A5EE96);
|
||||
regs.Write(4, 0x000000000000EE96);
|
||||
regs.Write(5, 0xFFFFFFFFD4646273);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFCE9DFBF7);
|
||||
regs.Write(13, 0xFFFFFFFFCE9DFBF7);
|
||||
regs.Write(14, 0x000000001AF99984);
|
||||
regs.Write(15, 0x0000000018B63D28);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000000);
|
||||
regs.Write(25, 0xFFFFFFFF825B21C9);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0x0000000018B63D28;
|
||||
regs.hi = 0x00000000625C2BBE;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
case CIC_NUS_6105_7105:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFF58B0FBFll;
|
||||
regs.gpr[3] = 0xFFFFFFFFF58B0FBFll;
|
||||
regs.gpr[4] = 0x0000000000000FBF;
|
||||
regs.gpr[5] = 0xFFFFFFFFDECAAAD1ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFF9651F81Ell;
|
||||
regs.gpr[13] = 0x000000002D42AAC5;
|
||||
regs.gpr[14] = 0x00000000489B52CF;
|
||||
regs.gpr[15] = 0x0000000056584D60;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0xFFFFFFFFCDCE565Fll;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFF58B0FBF);
|
||||
regs.Write(3, 0xFFFFFFFFF58B0FBF);
|
||||
regs.Write(4, 0x0000000000000FBF);
|
||||
regs.Write(5, 0xFFFFFFFFDECAAAD1);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFF9651F81E);
|
||||
regs.Write(13, 0x000000002D42AAC5);
|
||||
regs.Write(14, 0x00000000489B52CF);
|
||||
regs.Write(15, 0x0000000056584D60);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0xFFFFFFFFCDCE565F);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
|
||||
regs.lo = 0x0000000056584D60;
|
||||
regs.hi = 0x000000004BE35D1F;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
|
||||
mem.Write<u32>(regs, IMEM_REGION_START + 0x00, 0x3C0DBFC0);
|
||||
@@ -549,49 +551,49 @@ void PIF::HLE(bool pal, CICType cicType) {
|
||||
mem.Write<u32>(regs, IMEM_REGION_START + 0x1C, 0x3C0BB000);
|
||||
break;
|
||||
case CIC_NUS_6106_7106:
|
||||
regs.gpr[0] = 0x0000000000000000;
|
||||
regs.gpr[1] = 0x0000000000000000;
|
||||
regs.gpr[2] = 0xFFFFFFFFA95930A4ll;
|
||||
regs.gpr[3] = 0xFFFFFFFFA95930A4ll;
|
||||
regs.gpr[4] = 0x00000000000030A4;
|
||||
regs.gpr[5] = 0xFFFFFFFFB04DC903ll;
|
||||
regs.gpr[6] = 0xFFFFFFFFA4001F0Cll;
|
||||
regs.gpr[7] = 0xFFFFFFFFA4001F08ll;
|
||||
regs.gpr[8] = 0x00000000000000C0;
|
||||
regs.gpr[9] = 0x0000000000000000;
|
||||
regs.gpr[10] = 0x0000000000000040;
|
||||
regs.gpr[11] = 0xFFFFFFFFA4000040ll;
|
||||
regs.gpr[12] = 0xFFFFFFFFBCB59510ll;
|
||||
regs.gpr[13] = 0xFFFFFFFFBCB59510ll;
|
||||
regs.gpr[14] = 0x000000000CF85C13;
|
||||
regs.gpr[15] = 0x000000007A3C07F4;
|
||||
regs.gpr[16] = 0x0000000000000000;
|
||||
regs.gpr[17] = 0x0000000000000000;
|
||||
regs.gpr[18] = 0x0000000000000000;
|
||||
regs.gpr[19] = 0x0000000000000000;
|
||||
regs.gpr[20] = 0x0000000000000001;
|
||||
regs.gpr[21] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000000;
|
||||
regs.gpr[24] = 0x0000000000000002;
|
||||
regs.gpr[25] = 0x00000000465E3F72;
|
||||
regs.gpr[26] = 0x0000000000000000;
|
||||
regs.gpr[27] = 0x0000000000000000;
|
||||
regs.gpr[28] = 0x0000000000000000;
|
||||
regs.gpr[29] = 0xFFFFFFFFA4001FF0ll;
|
||||
regs.gpr[30] = 0x0000000000000000;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001550ll;
|
||||
regs.Write(0, 0x0000000000000000);
|
||||
regs.Write(1, 0x0000000000000000);
|
||||
regs.Write(2, 0xFFFFFFFFA95930A4);
|
||||
regs.Write(3, 0xFFFFFFFFA95930A4);
|
||||
regs.Write(4, 0x00000000000030A4);
|
||||
regs.Write(5, 0xFFFFFFFFB04DC903);
|
||||
regs.Write(6, 0xFFFFFFFFA4001F0C);
|
||||
regs.Write(7, 0xFFFFFFFFA4001F08);
|
||||
regs.Write(8, 0x00000000000000C0);
|
||||
regs.Write(9, 0x0000000000000000);
|
||||
regs.Write(10, 0x0000000000000040);
|
||||
regs.Write(11, 0xFFFFFFFFA4000040);
|
||||
regs.Write(12, 0xFFFFFFFFBCB59510);
|
||||
regs.Write(13, 0xFFFFFFFFBCB59510);
|
||||
regs.Write(14, 0x000000000CF85C13);
|
||||
regs.Write(15, 0x000000007A3C07F4);
|
||||
regs.Write(16, 0x0000000000000000);
|
||||
regs.Write(17, 0x0000000000000000);
|
||||
regs.Write(18, 0x0000000000000000);
|
||||
regs.Write(19, 0x0000000000000000);
|
||||
regs.Write(20, 0x0000000000000001);
|
||||
regs.Write(21, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000000);
|
||||
regs.Write(24, 0x0000000000000002);
|
||||
regs.Write(25, 0x00000000465E3F72);
|
||||
regs.Write(26, 0x0000000000000000);
|
||||
regs.Write(27, 0x0000000000000000);
|
||||
regs.Write(28, 0x0000000000000000);
|
||||
regs.Write(29, 0xFFFFFFFFA4001FF0);
|
||||
regs.Write(30, 0x0000000000000000);
|
||||
regs.Write(31, 0xFFFFFFFFA4001550);
|
||||
regs.lo = 0x000000007A3C07F4;
|
||||
regs.hi = 0x0000000023953898;
|
||||
|
||||
if (pal) {
|
||||
regs.gpr[20] = 0x0000000000000000;
|
||||
regs.gpr[23] = 0x0000000000000006;
|
||||
regs.gpr[31] = 0xFFFFFFFFA4001554ll;
|
||||
regs.Write(20, 0x0000000000000000);
|
||||
regs.Write(23, 0x0000000000000006);
|
||||
regs.Write(31, 0xFFFFFFFFA4001554);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF;
|
||||
regs.Write(22, (cicSeeds[cicType] >> 8) & 0xFF);
|
||||
regs.cop0.Reset();
|
||||
mem.Write<u32>(regs, 0x04300004, 0x01010101);
|
||||
std::copy(mem.rom.cart.begin(), mem.rom.cart.begin() + 0x1000, mem.mmio.rsp.dmem.begin());
|
||||
@@ -630,11 +632,11 @@ std::vector<u8> PIF::Serialize() {
|
||||
sizeof(int));
|
||||
|
||||
u32 index = 0;
|
||||
memcpy(res.data() + index, joybusDevices, 6*sizeof(JoybusDevice));
|
||||
memcpy(res.data() + index, joybusDevices.data(), 6*sizeof(JoybusDevice));
|
||||
index += 6*sizeof(JoybusDevice);
|
||||
memcpy(res.data() + index, bootrom, PIF_BOOTROM_SIZE);
|
||||
memcpy(res.data() + index, bootrom.data(), PIF_BOOTROM_SIZE);
|
||||
index += PIF_BOOTROM_SIZE;
|
||||
memcpy(res.data() + index, ram, PIF_RAM_SIZE);
|
||||
memcpy(res.data() + index, ram.data(), PIF_RAM_SIZE);
|
||||
index += PIF_RAM_SIZE;
|
||||
memcpy(res.data() + index, mempak.data(), mempak.size());
|
||||
index += mempak.size();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <filesystem>
|
||||
#include <mio/mmap.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include "MupenMovie.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@@ -178,8 +179,9 @@ struct PIF {
|
||||
}
|
||||
|
||||
bool mempakOpen = false;
|
||||
JoybusDevice joybusDevices[6]{};
|
||||
u8 bootrom[PIF_BOOTROM_SIZE]{}, ram[PIF_RAM_SIZE]{};
|
||||
std::array<JoybusDevice, 6> joybusDevices{};
|
||||
std::array<u8, PIF_BOOTROM_SIZE> bootrom{};
|
||||
std::array<u8, PIF_RAM_SIZE> ram{};
|
||||
mio::mmap_sink mempak, eeprom;
|
||||
int channel = 0;
|
||||
std::string mempakPath{}, eepromPath{};
|
||||
|
||||
@@ -35,7 +35,7 @@ bool MupenMovie::Load(const fs::path &path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), loadedTasMovie.size());
|
||||
memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), sizeof(TASMovieHeader));
|
||||
|
||||
if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 || loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) {
|
||||
Util::error("Failed to load movie: incorrect signature. Are you sure this is a valid movie?");
|
||||
@@ -71,6 +71,12 @@ MupenMovie::MupenMovie(const fs::path &path) {
|
||||
}
|
||||
}
|
||||
|
||||
void MupenMovie::Reset() {
|
||||
if(!IsLoaded()) return;
|
||||
|
||||
loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header
|
||||
}
|
||||
|
||||
FORCE_INLINE void LogController(const n64::Controller& controller) {
|
||||
Util::debug("c_right: {}", controller.cRight);
|
||||
Util::debug("c_left: {}", controller.cLeft);
|
||||
|
||||
@@ -49,11 +49,10 @@ struct MupenMovie {
|
||||
MupenMovie() = default;
|
||||
MupenMovie(const fs::path&);
|
||||
bool Load(const fs::path&);
|
||||
void Reset();
|
||||
n64::Controller NextInputs();
|
||||
bool IsLoaded() const { return !loadedTasMovie.empty(); }
|
||||
private:
|
||||
std::string filename = "";
|
||||
std::string game = "";
|
||||
std::vector<u8> loadedTasMovie = {};
|
||||
TASMovieHeader loadedTasMovieHeader = {};
|
||||
uint32_t loadedTasMovieIndex = 0;
|
||||
|
||||
@@ -11,6 +11,7 @@ void SI::Reset() {
|
||||
status.raw = 0;
|
||||
dramAddr = 0;
|
||||
pifAddr = 0;
|
||||
toDram = false;
|
||||
pif.Reset();
|
||||
}
|
||||
|
||||
@@ -32,21 +33,27 @@ auto SI::Read(u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
// pif -> rdram
|
||||
template <> void SI::DMA<true>() {
|
||||
pif.ProcessCommands(mem);
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(dramAddr + i, pif.Read(pifAddr + i));
|
||||
}
|
||||
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
||||
}
|
||||
|
||||
// rdram -> pif
|
||||
template <> void SI::DMA<false>() {
|
||||
for(int i = 0; i < 64; i++) {
|
||||
pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM<u8>(dramAddr + i));
|
||||
}
|
||||
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
||||
}
|
||||
|
||||
void SI::DMA() {
|
||||
status.dmaBusy = false;
|
||||
if (toDram) {
|
||||
pif.ProcessCommands(mem);
|
||||
for(int i = 0; i < 64; i++) {
|
||||
mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)] = pif.Read(pifAddr + i);
|
||||
}
|
||||
Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr);
|
||||
} else {
|
||||
for(int i = 0; i < 64; i++) {
|
||||
pif.Write(pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddr + i)]);
|
||||
}
|
||||
Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr);
|
||||
pif.ProcessCommands(mem);
|
||||
}
|
||||
if (toDram) DMA<true>();
|
||||
else DMA<false>();
|
||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::SI);
|
||||
}
|
||||
|
||||
@@ -74,4 +81,4 @@ void SI::Write(u32 addr, u32 val) {
|
||||
Util::panic("Unhandled SI[{:08X}] write ({:08X})", addr, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/mmio/PIF.hpp>
|
||||
|
||||
@@ -30,6 +29,8 @@ struct SI {
|
||||
|
||||
auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
template <bool toDram>
|
||||
void DMA();
|
||||
void DMA();
|
||||
PIF pif;
|
||||
private:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Mem.hpp>
|
||||
#include <core/mmio/Interrupt.hpp>
|
||||
|
||||
namespace n64 {
|
||||
VI::VI (Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
||||
@@ -20,6 +19,11 @@ void VI::Reset() {
|
||||
numHalflines = 262;
|
||||
numFields = 1;
|
||||
cyclesPerHalfline = 1000;
|
||||
xscale = {}, yscale = {};
|
||||
hsyncLeap = {}, burst = {}, vburst = {};
|
||||
hstart = {}, vstart = {};
|
||||
isPal = false;
|
||||
swaps = {};
|
||||
}
|
||||
|
||||
u32 VI::Read(u32 paddr) const {
|
||||
|
||||
@@ -20,6 +20,29 @@ void Cop0::Reset() {
|
||||
wired = 0;
|
||||
index.raw = 63;
|
||||
badVaddr = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
kernelMode = {true};
|
||||
supervisorMode = {false};
|
||||
userMode = {false};
|
||||
is64BitAddressing = {false};
|
||||
llbit = {};
|
||||
|
||||
pageMask = {};
|
||||
entryHi = {};
|
||||
entryLo0 = {}, entryLo1 = {};
|
||||
context = {};
|
||||
wired = {}, r7 = {};
|
||||
count = {};
|
||||
compare = {};
|
||||
LLAddr = {}, WatchLo = {}, WatchHi = {};
|
||||
xcontext = {};
|
||||
r21 = {}, r22 = {}, r23 = {}, r24 = {}, r25 = {};
|
||||
ParityError = {}, CacheError = {}, TagLo = {}, TagHi = {};
|
||||
ErrorEPC = {};
|
||||
r31 = {};
|
||||
memset(tlb, 0, sizeof(TLBEntry)*32);
|
||||
tlbError = NONE;
|
||||
openbus = {};
|
||||
}
|
||||
|
||||
u32 Cop0::GetReg32(u8 addr) {
|
||||
|
||||
@@ -43,10 +43,10 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
||||
case 0x07: unimplemented(); break;
|
||||
case 0x08:
|
||||
switch(mask_branch) {
|
||||
case 0: CheckFPUUsable(); cpu.b(instr, !fcr31.compare); break;
|
||||
case 1: CheckFPUUsable(); cpu.b(instr, fcr31.compare); break;
|
||||
case 2: CheckFPUUsable(); cpu.bl(instr, !fcr31.compare); break;
|
||||
case 3: CheckFPUUsable(); cpu.bl(instr, fcr31.compare); break;
|
||||
case 0: if(!CheckFPUUsable()) return; cpu.b(instr, !fcr31.compare); break;
|
||||
case 1: if(!CheckFPUUsable()) return; cpu.b(instr, fcr31.compare); break;
|
||||
case 2: if(!CheckFPUUsable()) return; cpu.bl(instr, !fcr31.compare); break;
|
||||
case 3: if(!CheckFPUUsable()) return; cpu.bl(instr, fcr31.compare); break;
|
||||
default: Util::panic("Undefined BC COP1 {:02X}", mask_branch);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -9,46 +9,78 @@ union FCR31 {
|
||||
FCR31() = default;
|
||||
struct {
|
||||
unsigned rounding_mode:2;
|
||||
unsigned flag_inexact_operation:1;
|
||||
unsigned flag_underflow:1;
|
||||
unsigned flag_overflow:1;
|
||||
unsigned flag_division_by_zero:1;
|
||||
unsigned flag_invalid_operation:1;
|
||||
unsigned enable_inexact_operation:1;
|
||||
unsigned enable_underflow:1;
|
||||
unsigned enable_overflow:1;
|
||||
unsigned enable_division_by_zero:1;
|
||||
unsigned enable_invalid_operation:1;
|
||||
unsigned cause_inexact_operation:1;
|
||||
unsigned cause_underflow:1;
|
||||
unsigned cause_overflow:1;
|
||||
unsigned cause_division_by_zero:1;
|
||||
unsigned cause_invalid_operation:1;
|
||||
unsigned cause_unimplemented_operation:1;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
} flag;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
} enable;
|
||||
struct {
|
||||
unsigned inexact_operation:1;
|
||||
unsigned underflow:1;
|
||||
unsigned overflow:1;
|
||||
unsigned division_by_zero:1;
|
||||
unsigned invalid_operation:1;
|
||||
unsigned unimplemented_operation:1;
|
||||
} cause;
|
||||
unsigned:5;
|
||||
unsigned compare:1;
|
||||
unsigned fs:1;
|
||||
unsigned:7;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct {
|
||||
unsigned:2;
|
||||
unsigned flag:5;
|
||||
unsigned enable:5;
|
||||
unsigned cause:6;
|
||||
unsigned:14;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
[[nodiscard]] u32 read() const {
|
||||
return (fs << 24) | (compare << 23) | (cause << 12) | (enable << 7) | (flag << 2) | rounding_mode;
|
||||
u32 ret = 0;
|
||||
ret |= (u32(fs) << 24);
|
||||
ret |= (u32(compare) << 23);
|
||||
ret |= (u32(cause.unimplemented_operation) << 17);
|
||||
ret |= (u32(cause.invalid_operation) << 16);
|
||||
ret |= (u32(cause.division_by_zero) << 15);
|
||||
ret |= (u32(cause.overflow) << 14);
|
||||
ret |= (u32(cause.underflow) << 13);
|
||||
ret |= (u32(cause.inexact_operation) << 12);
|
||||
ret |= (u32(enable.invalid_operation) << 11);
|
||||
ret |= (u32(enable.division_by_zero) << 10);
|
||||
ret |= (u32(enable.overflow) << 9);
|
||||
ret |= (u32(enable.underflow) << 8);
|
||||
ret |= (u32(enable.inexact_operation) << 7);
|
||||
ret |= (u32(flag.invalid_operation) << 6);
|
||||
ret |= (u32(flag.division_by_zero) << 5);
|
||||
ret |= (u32(flag.overflow) << 4);
|
||||
ret |= (u32(flag.underflow) << 3);
|
||||
ret |= (u32(flag.inexact_operation) << 2);
|
||||
ret |= (u32(rounding_mode) & 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void write(u32 val) {
|
||||
fs = (val & 0x01000000) >> 24;
|
||||
compare = (val & 0x00800000) >> 23;
|
||||
cause = (val & 0x0003f000) >> 12;
|
||||
enable = (val & 0x00000f80) >> 7;
|
||||
flag = (val & 0x0000007c) >> 2;
|
||||
fs = val >> 24;
|
||||
compare = val >> 23;
|
||||
cause.unimplemented_operation = val >> 17;
|
||||
cause.invalid_operation = val >> 16;
|
||||
cause.division_by_zero = val >> 15;
|
||||
cause.overflow = val >> 14;
|
||||
cause.underflow = val >> 13;
|
||||
cause.inexact_operation = val >> 12;
|
||||
enable.invalid_operation = val >> 11;
|
||||
enable.division_by_zero = val >> 10;
|
||||
enable.overflow = val >> 9;
|
||||
enable.underflow = val >> 8;
|
||||
enable.inexact_operation = val >> 7;
|
||||
flag.invalid_operation = val >> 6;
|
||||
flag.division_by_zero = val >> 5;
|
||||
flag.overflow = val >> 4;
|
||||
flag.underflow = val >> 3;
|
||||
flag.inexact_operation = val >> 2;
|
||||
rounding_mode = val & 3;
|
||||
}
|
||||
};
|
||||
@@ -89,38 +121,50 @@ struct JIT;
|
||||
struct Registers;
|
||||
|
||||
struct Cop1 {
|
||||
#define CheckFPUUsable_PreserveCause() do { if(!regs.cop0.status.cu1) { regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); return; } } while(0)
|
||||
#define CheckFPUUsable() do { CheckFPUUsable_PreserveCause(); fcr31.cause = 0; } while(0)
|
||||
Cop1(Registers&);
|
||||
explicit Cop1(Registers&);
|
||||
u32 fcr0{};
|
||||
FCR31 fcr31{};
|
||||
FloatingPointReg fgr[32]{};
|
||||
|
||||
void Reset();
|
||||
template <class T> // either JIT or Interpreter
|
||||
void decode(T&, u32);
|
||||
friend struct Interpreter;
|
||||
|
||||
bool FireException();
|
||||
template <bool preserveCause = false>
|
||||
bool CheckFPUUsable();
|
||||
template <typename T>
|
||||
bool CheckResult(T&);
|
||||
template <typename T>
|
||||
bool CheckArg(T&);
|
||||
template <typename T>
|
||||
bool CheckArgs(T&, T&);
|
||||
template <typename T>
|
||||
bool isqnan(T);
|
||||
|
||||
template<typename T, bool quiet, bool cf>
|
||||
bool XORDERED(T fs, T ft);
|
||||
|
||||
template <typename T>
|
||||
void SetCauseOnResult(T& d);
|
||||
bool CheckCVTArg(float &f);
|
||||
template <typename T>
|
||||
void SetCauseByArg(T f);
|
||||
template <typename T>
|
||||
void SetCauseByArgLCVT(T f);
|
||||
template <typename T>
|
||||
void SetCauseByArgWCVT(T f);
|
||||
void SetCauseRaised(int);
|
||||
void SetCauseRaisedCVT(int);
|
||||
bool CheckCVTArg(double &f);
|
||||
|
||||
template <bool cvt = false>
|
||||
bool TestExceptions();
|
||||
void SetCauseUnimplemented();
|
||||
void SetCauseUnderflow();
|
||||
void SetCauseInexact();
|
||||
void SetCauseDivisionByZero();
|
||||
void SetCauseOverflow();
|
||||
void SetCauseInvalid();
|
||||
bool SetCauseUnderflow();
|
||||
bool SetCauseInexact();
|
||||
bool SetCauseDivisionByZero();
|
||||
bool SetCauseOverflow();
|
||||
bool SetCauseInvalid();
|
||||
private:
|
||||
template <typename T>
|
||||
auto FGR(Cop0Status&, u32) -> T&;
|
||||
auto FGR_T(Cop0Status&, u32) -> T&;
|
||||
template <typename T>
|
||||
auto FGR_S(Cop0Status&, u32) -> T&;
|
||||
template <typename T>
|
||||
auto FGR_D(Cop0Status&, u32) -> T&;
|
||||
void decodeInterp(Interpreter&, u32);
|
||||
void decodeJIT(JIT&, u32);
|
||||
void absd(u32 instr);
|
||||
@@ -133,7 +177,7 @@ private:
|
||||
void ceilws(u32 instr);
|
||||
void ceilld(u32 instr);
|
||||
void ceilwd(u32 instr);
|
||||
void cfc1(u32 instr) const;
|
||||
void cfc1(u32 instr);
|
||||
void ctc1(u32 instr);
|
||||
void unimplemented();
|
||||
void roundls(u32 instr);
|
||||
|
||||
@@ -11,6 +11,12 @@ void Registers::Reset() {
|
||||
delaySlot = false;
|
||||
prevDelaySlot = false;
|
||||
memset(gpr, 0, 32*sizeof(s64));
|
||||
|
||||
cop0.Reset();
|
||||
cop1.Reset();
|
||||
|
||||
steps = 0;
|
||||
extraCycles = 0;
|
||||
}
|
||||
|
||||
void Registers::SetPC64(s64 val) {
|
||||
@@ -24,4 +30,80 @@ void Registers::SetPC32(s32 val) {
|
||||
pc = s64(val);
|
||||
nextPC = pc + 4;
|
||||
}
|
||||
|
||||
template <> u64 Registers::Read<u64>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s64 Registers::Read<s64>(size_t idx) {
|
||||
return s64(Read<u64>(idx));
|
||||
}
|
||||
|
||||
template <> u32 Registers::Read<u32>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s32 Registers::Read<s32>(size_t idx) {
|
||||
return s32(Read<u32>(idx));
|
||||
}
|
||||
|
||||
template <> u16 Registers::Read<u16>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s16 Registers::Read<s16>(size_t idx) {
|
||||
return s16(Read<u16>(idx));
|
||||
}
|
||||
|
||||
template <> u8 Registers::Read<u8>(size_t idx) {
|
||||
return idx == 0 ? 0 : gpr[idx];
|
||||
}
|
||||
|
||||
template <> s8 Registers::Read<s8>(size_t idx) {
|
||||
return s8(Read<u8>(idx));
|
||||
}
|
||||
|
||||
template <> void Registers::Write<bool>(size_t idx, bool v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u64>(size_t idx, u64 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s64>(size_t idx, s64 v) {
|
||||
Write<u64>(idx, v);
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u32>(size_t idx, u32 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u32)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s32>(size_t idx, s32 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u16>(size_t idx, u16 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u16)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s16>(size_t idx, s16 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<u8>(size_t idx, u8 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = (u8)v;
|
||||
}
|
||||
|
||||
template <> void Registers::Write<s8>(size_t idx, s8 v) {
|
||||
if(idx == 0) return;
|
||||
gpr[idx] = v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ struct Registers {
|
||||
return IsRegConstant(first) && IsRegConstant(second);
|
||||
}
|
||||
|
||||
s64 gpr[32]{};
|
||||
bool gprIsConstant[32]{};
|
||||
bool loIsConstant = false, hiIsConstant = false;
|
||||
Cop0 cop0;
|
||||
@@ -37,5 +36,12 @@ struct Registers {
|
||||
extraCycles = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Read(size_t);
|
||||
template <typename T>
|
||||
void Write(size_t, T);
|
||||
private:
|
||||
s64 gpr[32]{};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
|
||||
namespace n64 {
|
||||
void Cop0::mtc0(u32 instr) {
|
||||
SetReg32(RD(instr), regs.gpr[RT(instr)]);
|
||||
SetReg32(RD(instr), regs.Read<u32>(RT(instr)));
|
||||
}
|
||||
|
||||
void Cop0::dmtc0(u32 instr) {
|
||||
SetReg64(RD(instr), regs.gpr[RT(instr)]);
|
||||
SetReg64(RD(instr), regs.Read<u64>(RT(instr)));
|
||||
}
|
||||
|
||||
void Cop0::mfc0(u32 instr) {
|
||||
regs.gpr[RT(instr)] = s32(GetReg32(RD(instr)));
|
||||
regs.Write(RT(instr), s32(GetReg32(RD(instr))));
|
||||
}
|
||||
|
||||
void Cop0::dmfc0(u32 instr) const {
|
||||
regs.gpr[RT(instr)] = s64(GetReg64(RD(instr)));
|
||||
regs.Write(RT(instr), s64(GetReg64(RD(instr))));
|
||||
}
|
||||
|
||||
void Cop0::eret() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
#include <core/RSP.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
#include <Mem.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
@@ -60,11 +60,11 @@ FORCE_INLINE void SetCop0Reg(Registers& regs, Mem& mem, u8 index, u32 val) {
|
||||
case 1: rsp.spDMADRAMAddr.raw = val; break;
|
||||
case 2:
|
||||
rsp.spDMALen.raw = val;
|
||||
rsp.DMAtoRSP(mem.GetRDRAM());
|
||||
rsp.DMA<false>();
|
||||
break;
|
||||
case 3:
|
||||
rsp.spDMALen.raw = val;
|
||||
rsp.DMAtoRDRAM(mem.GetRDRAM());
|
||||
rsp.DMA<true>();
|
||||
break;
|
||||
case 4: rsp.WriteStatus(val); break;
|
||||
case 7:
|
||||
|
||||
Reference in New Issue
Block a user