Minor nitpicks and smaller perf improvements (barely noticeable)
This commit is contained in:
@@ -8,12 +8,12 @@ struct BaseCPU {
|
||||
virtual ~BaseCPU() = default;
|
||||
virtual int Step() = 0;
|
||||
virtual void Reset() = 0;
|
||||
virtual bool ShouldServiceInterrupt() = 0;
|
||||
[[nodiscard]] virtual bool ShouldServiceInterrupt() const = 0;
|
||||
virtual void CheckCompareInterrupt() = 0;
|
||||
virtual std::vector<u8> Serialize() = 0;
|
||||
virtual void Deserialize(const std::vector<u8> &) = 0;
|
||||
virtual Mem &GetMem() = 0;
|
||||
virtual Registers &GetRegs() = 0;
|
||||
virtual Disassembler::DisassemblyResult Disassemble(u32, u32) const = 0;
|
||||
[[nodiscard]] virtual Disassembler::DisassemblyResult Disassemble(u32, u32) const = 0;
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <Disassembler.hpp>
|
||||
|
||||
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(u32 address, u32 instruction) {
|
||||
Disassembler::DisassemblyResult Disassembler::DisassembleSimple(const u32 address, const u32 instruction) const {
|
||||
cs_insn *insn;
|
||||
auto bytes = Util::IntegralToBuffer(instruction);
|
||||
auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||
const auto bytes = Util::IntegralToBuffer(instruction);
|
||||
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||
|
||||
if (count <= 0)
|
||||
return {};
|
||||
@@ -15,10 +15,10 @@ Disassembler::DisassemblyResult Disassembler::DisassembleSimple(u32 address, u32
|
||||
return result;
|
||||
}
|
||||
|
||||
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(u32 address, u32 instruction) {
|
||||
Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(const u32 address, const u32 instruction) const {
|
||||
cs_insn *insn;
|
||||
auto bytes = Util::IntegralToBuffer(instruction);
|
||||
auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||
const auto bytes = Util::IntegralToBuffer(instruction);
|
||||
const auto count = cs_disasm(handle, bytes.data(), bytes.size(), address, 0, &insn);
|
||||
|
||||
if (count <= 0)
|
||||
return {};
|
||||
@@ -27,10 +27,10 @@ Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(u32 address, u
|
||||
result.address = insn[0].address;
|
||||
result.mnemonic = insn[0].mnemonic;
|
||||
|
||||
result.full += result.address + ":\t";
|
||||
result.full += fmt::format("0x{:016X}", result.address) + ":\t";
|
||||
result.full += result.mnemonic + "\t";
|
||||
|
||||
cs_detail *details = insn[0].detail;
|
||||
const cs_detail *details = insn[0].detail;
|
||||
auto formatOperand = [&](const cs_mips_op &operand) {
|
||||
switch (operand.type) {
|
||||
case MIPS_OP_IMM:
|
||||
@@ -39,6 +39,8 @@ Disassembler::DisassemblyResult Disassembler::DisassembleDetailed(u32 address, u
|
||||
return fmt::format("{}(0x{:X})", cs_reg_name(handle, operand.mem.base), operand.mem.disp);
|
||||
case MIPS_OP_REG:
|
||||
return fmt::format("{}", cs_reg_name(handle, operand.reg));
|
||||
default:
|
||||
return std::string{""};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ struct Disassembler {
|
||||
~Disassembler() { cs_close(&handle); }
|
||||
|
||||
private:
|
||||
DisassemblyResult DisassembleDetailed(u32 address, u32 instruction);
|
||||
DisassemblyResult DisassembleSimple(u32 address, u32 instruction);
|
||||
DisassemblyResult DisassembleDetailed(u32 address, u32 instruction) const;
|
||||
DisassemblyResult DisassembleSimple(u32 address, u32 instruction) const;
|
||||
|
||||
explicit Disassembler(const bool rsp) : rsp(rsp) {
|
||||
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>((rsp ? CS_MODE_32 : CS_MODE_64) | CS_MODE_BIG_ENDIAN), &handle) !=
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
namespace n64 {
|
||||
Interpreter::Interpreter(ParallelRDP ¶llel) : mem(regs, parallel) {}
|
||||
|
||||
bool Interpreter::ShouldServiceInterrupt() {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
bool Interpreter::ShouldServiceInterrupt() const {
|
||||
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
const bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
const bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
const bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
|
||||
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
||||
}
|
||||
@@ -15,13 +15,13 @@ bool Interpreter::ShouldServiceInterrupt() {
|
||||
void Interpreter::CheckCompareInterrupt() {
|
||||
regs.cop0.count++;
|
||||
regs.cop0.count &= 0x1FFFFFFFF;
|
||||
if (regs.cop0.count == (u64)regs.cop0.compare << 1) {
|
||||
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
||||
regs.cop0.cause.ip7 = 1;
|
||||
mem.mmio.mi.UpdateInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
Disassembler::DisassemblyResult Interpreter::Disassemble(u32 address, u32 instruction) const {
|
||||
Disassembler::DisassemblyResult Interpreter::Disassemble(const u32 address, const u32 instruction) const {
|
||||
return Disassembler::instance().Disassemble(address, instruction);
|
||||
}
|
||||
|
||||
@@ -40,11 +40,11 @@ int Interpreter::Step() {
|
||||
u32 paddr = 0;
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 instruction = mem.Read<u32>(regs, paddr);
|
||||
const u32 instruction = mem.Read<u32>(regs, paddr);
|
||||
|
||||
if (ShouldServiceInterrupt()) {
|
||||
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
|
||||
|
||||
@@ -20,7 +20,7 @@ struct Interpreter : BaseCPU {
|
||||
Mem &GetMem() override { return mem; }
|
||||
|
||||
Registers &GetRegs() override { return regs; }
|
||||
Disassembler::DisassemblyResult Disassemble(u32, u32) const override;
|
||||
[[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32, u32) const override;
|
||||
|
||||
private:
|
||||
Registers regs;
|
||||
@@ -29,7 +29,7 @@ private:
|
||||
friend struct Cop1;
|
||||
#define check_address_error(mask, vaddr) \
|
||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||
bool ShouldServiceInterrupt() override;
|
||||
bool ShouldServiceInterrupt() const override;
|
||||
void CheckCompareInterrupt() override;
|
||||
std::vector<u8> Serialize() override;
|
||||
void Deserialize(const std::vector<u8> &) override;
|
||||
@@ -118,7 +118,7 @@ private:
|
||||
void srav(u32);
|
||||
void srl(u32);
|
||||
void srlv(u32);
|
||||
void trap(bool);
|
||||
void trap(bool) const;
|
||||
void or_(u32);
|
||||
void ori(u32);
|
||||
void xor_(u32);
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
namespace n64 {
|
||||
JIT::JIT(ParallelRDP ¶llel) : mem(regs, parallel) {}
|
||||
|
||||
bool JIT::ShouldServiceInterrupt() {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
bool JIT::ShouldServiceInterrupt() const {
|
||||
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
const bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
const bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
const bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
|
||||
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ bool JIT::ShouldServiceInterrupt() {
|
||||
void JIT::CheckCompareInterrupt() {
|
||||
regs.cop0.count++;
|
||||
regs.cop0.count &= 0x1FFFFFFFF;
|
||||
if (regs.cop0.count == (u64)regs.cop0.compare << 1) {
|
||||
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
||||
regs.cop0.cause.ip7 = 1;
|
||||
mem.mmio.mi.UpdateInterrupt();
|
||||
}
|
||||
@@ -41,10 +41,10 @@ int JIT::Step() {
|
||||
u32 paddr = 0;
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, pc, paddr)) {
|
||||
/*regs.cop0.HandleTLBException(pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, pc);
|
||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, pc);
|
||||
return 1;*/
|
||||
Util::panic("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
||||
static_cast<int>(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
||||
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
||||
}
|
||||
|
||||
instruction = mem.Read<u32>(regs, paddr);
|
||||
|
||||
@@ -20,7 +20,7 @@ struct JIT : BaseCPU {
|
||||
|
||||
Registers &GetRegs() override { return regs; }
|
||||
|
||||
Disassembler::DisassemblyResult Disassemble(u32, u32) const override { return {}; }
|
||||
[[nodiscard]] Disassembler::DisassemblyResult Disassemble(u32, u32) const override { return {}; }
|
||||
|
||||
private:
|
||||
Registers regs;
|
||||
@@ -29,7 +29,7 @@ private:
|
||||
friend struct Cop1;
|
||||
#define check_address_error(mask, vaddr) \
|
||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||
bool ShouldServiceInterrupt() override;
|
||||
bool ShouldServiceInterrupt() const override;
|
||||
void CheckCompareInterrupt() override;
|
||||
std::vector<u8> Serialize() override;
|
||||
void Deserialize(const std::vector<u8> &) override;
|
||||
|
||||
@@ -36,7 +36,7 @@ u32 MMIO::Read(u32 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
void MMIO::Write(u32 addr, u32 val) {
|
||||
void MMIO::Write(const u32 addr, const u32 val) {
|
||||
switch (addr) {
|
||||
case RSP_REGION:
|
||||
rsp.Write(addr, val);
|
||||
@@ -82,14 +82,30 @@ std::vector<u8> MMIO::Serialize() {
|
||||
index += sizeof(DPC);
|
||||
memcpy(res.data() + index, rdp.cmd_buf, 0xFFFFF);
|
||||
index += 0xFFFFF;
|
||||
std::copy(rdp.rdram.begin(), rdp.rdram.end(), res.begin() + index);
|
||||
std::ranges::copy(rdp.rdram, res.begin() + index);
|
||||
index += RDRAM_SIZE;
|
||||
memcpy(res.data() + index, &mi, sizeof(MI));
|
||||
index += sizeof(MI);
|
||||
memcpy(res.data() + index, &vi, sizeof(VI));
|
||||
index += sizeof(VI);
|
||||
memcpy(res.data() + index, &ai, sizeof(AI));
|
||||
index += sizeof(AI);
|
||||
memcpy(res.data() + index, &ai.dmaEnable, sizeof(ai.dmaEnable));
|
||||
index += sizeof(ai.dmaEnable);
|
||||
memcpy(res.data() + index, &ai.dacRate, sizeof(ai.dacRate));
|
||||
index += sizeof(ai.dacRate);
|
||||
memcpy(res.data() + index, &ai.bitrate, sizeof(ai.bitrate));
|
||||
index += sizeof(ai.bitrate);
|
||||
memcpy(res.data() + index, &ai.dmaCount, sizeof(ai.dmaCount));
|
||||
index += sizeof(ai.dmaCount);
|
||||
memcpy(res.data() + index, &ai.dmaLen, sizeof(ai.dmaLen));
|
||||
index += sizeof(ai.dmaLen);
|
||||
memcpy(res.data() + index, &ai.dmaAddr, sizeof(ai.dmaAddr));
|
||||
index += sizeof(ai.dmaAddr);
|
||||
memcpy(res.data() + index, &ai.dmaAddrCarry, sizeof(ai.dmaAddrCarry));
|
||||
index += sizeof(ai.dmaAddrCarry);
|
||||
memcpy(res.data() + index, &ai.cycles, sizeof(ai.cycles));
|
||||
index += sizeof(ai.cycles);
|
||||
memcpy(res.data() + index, &ai.dac, sizeof(ai.dac));
|
||||
index += sizeof(ai.dac);
|
||||
memcpy(res.data() + index, &pi, sizeof(PI));
|
||||
index += sizeof(PI);
|
||||
memcpy(res.data() + index, &ri, sizeof(RI));
|
||||
@@ -113,14 +129,30 @@ void MMIO::Deserialize(const std::vector<u8> &data) {
|
||||
index += sizeof(DPC);
|
||||
memcpy(rdp.cmd_buf, data.data() + index, 0xFFFFF);
|
||||
index += 0xFFFFF;
|
||||
std::copy(data.begin() + index, data.begin() + index + RDRAM_SIZE, rdp.rdram.begin());
|
||||
std::copy_n(data.begin() + index, RDRAM_SIZE, rdp.rdram.begin());
|
||||
index += RDRAM_SIZE;
|
||||
memcpy(&mi, data.data() + index, sizeof(MI));
|
||||
index += sizeof(MI);
|
||||
memcpy(&vi, data.data() + index, sizeof(VI));
|
||||
index += sizeof(VI);
|
||||
memcpy(&ai, data.data() + index, sizeof(AI));
|
||||
index += sizeof(AI);
|
||||
memcpy(&ai.dmaEnable, data.data() + index, sizeof(ai.dmaEnable));
|
||||
index += sizeof(ai.dmaEnable);
|
||||
memcpy(&ai.dacRate, data.data() + index, sizeof(ai.dacRate));
|
||||
index += sizeof(ai.dacRate);
|
||||
memcpy(&ai.bitrate, data.data() + index, sizeof(ai.bitrate));
|
||||
index += sizeof(ai.bitrate);
|
||||
memcpy(&ai.dmaCount, data.data() + index, sizeof(ai.dmaCount));
|
||||
index += sizeof(ai.dmaCount);
|
||||
memcpy(&ai.dmaLen, data.data() + index, sizeof(ai.dmaLen));
|
||||
index += sizeof(ai.dmaLen);
|
||||
memcpy(&ai.dmaAddr, data.data() + index, sizeof(ai.dmaAddr));
|
||||
index += sizeof(ai.dmaAddr);
|
||||
memcpy(&ai.dmaAddrCarry, data.data() + index, sizeof(ai.dmaAddrCarry));
|
||||
index += sizeof(ai.dmaAddrCarry);
|
||||
memcpy(&ai.cycles, data.data() + index, sizeof(ai.cycles));
|
||||
index += sizeof(ai.cycles);
|
||||
memcpy(&ai.dac, data.data() + index, sizeof(ai.dac));
|
||||
index += sizeof(ai.dac);
|
||||
memcpy(&pi, data.data() + index, sizeof(PI));
|
||||
index += sizeof(PI);
|
||||
memcpy(&ri, data.data() + index, sizeof(RI));
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
#include <unarr.h>
|
||||
|
||||
namespace n64 {
|
||||
Mem::Mem(Registers ®s, ParallelRDP ¶llel) : flash(saveData), mmio(*this, regs, parallel) {
|
||||
Mem::Mem(Registers ®s, ParallelRDP ¶llel) : mmio(*this, regs, parallel), flash(saveData) {
|
||||
rom.cart.resize(CART_SIZE);
|
||||
std::fill(rom.cart.begin(), rom.cart.end(), 0);
|
||||
std::ranges::fill(rom.cart, 0);
|
||||
}
|
||||
|
||||
void Mem::Reset() {
|
||||
std::fill(rom.cart.begin(), rom.cart.end(), 0);
|
||||
std::ranges::fill(rom.cart, 0);
|
||||
flash.Reset();
|
||||
if (saveData.is_mapped()) {
|
||||
std::error_code error;
|
||||
@@ -87,7 +87,7 @@ FORCE_INLINE void SetROMCIC(u32 checksum, ROM &rom) {
|
||||
}
|
||||
|
||||
std::vector<u8> Mem::OpenArchive(const std::string &path, size_t &sizeAdjusted) {
|
||||
auto stream = ar_open_file(fs::path(path).string().c_str());
|
||||
const auto stream = ar_open_file(fs::path(path).string().c_str());
|
||||
|
||||
if (!stream) {
|
||||
Util::panic("Could not open archive! Are you sure it's an archive?");
|
||||
@@ -115,17 +115,17 @@ std::vector<u8> Mem::OpenArchive(const std::string &path, size_t &sizeAdjusted)
|
||||
auto filename = ar_entry_get_name(archive);
|
||||
auto extension = fs::path(filename).extension();
|
||||
|
||||
if (std::any_of(rom_exts.begin(), rom_exts.end(), [&](auto x) { return extension == x; })) {
|
||||
auto size = ar_entry_get_size(archive);
|
||||
if (std::ranges::any_of(rom_exts, [&](const auto& x) { return extension == x; })) {
|
||||
const auto size = ar_entry_get_size(archive);
|
||||
sizeAdjusted = Util::NextPow2(size);
|
||||
buf.resize(sizeAdjusted);
|
||||
ar_entry_uncompress(archive, buf.data(), size);
|
||||
break;
|
||||
} else {
|
||||
ar_close_archive(archive);
|
||||
ar_close(stream);
|
||||
Util::panic("Could not find any rom image in the archive!");
|
||||
}
|
||||
|
||||
ar_close_archive(archive);
|
||||
ar_close(stream);
|
||||
Util::panic("Could not find any rom image in the archive!");
|
||||
}
|
||||
|
||||
ar_close_archive(archive);
|
||||
@@ -139,10 +139,10 @@ std::vector<u8> Mem::OpenROM(const std::string &filename, size_t &sizeAdjusted)
|
||||
return buf;
|
||||
}
|
||||
|
||||
void Mem::LoadROM(bool isArchive, const std::string &filename) {
|
||||
size_t sizeAdjusted;
|
||||
void Mem::LoadROM(const bool isArchive, const std::string &filename) {
|
||||
u32 endianness;
|
||||
{
|
||||
size_t sizeAdjusted;
|
||||
std::vector<u8> buf{};
|
||||
if (isArchive) {
|
||||
buf = OpenArchive(filename, sizeAdjusted);
|
||||
@@ -153,7 +153,7 @@ void Mem::LoadROM(bool isArchive, const std::string &filename) {
|
||||
endianness = bswap(*reinterpret_cast<u32 *>(buf.data()));
|
||||
Util::SwapN64Rom<true>(buf, endianness);
|
||||
|
||||
std::copy(buf.begin(), buf.end(), rom.cart.begin());
|
||||
std::ranges::copy(buf, rom.cart.begin());
|
||||
rom.mask = sizeAdjusted - 1;
|
||||
memcpy(&rom.header, buf.data(), sizeof(ROMHeader));
|
||||
}
|
||||
@@ -178,7 +178,7 @@ void Mem::LoadROM(bool isArchive, const std::string &filename) {
|
||||
rom.gameNameCart[i] = '\0';
|
||||
}
|
||||
|
||||
u32 checksum = Util::crc32(0, &rom.cart[0x40], 0x9c0);
|
||||
const u32 checksum = Util::crc32(0, &rom.cart[0x40], 0x9c0);
|
||||
SetROMCIC(checksum, rom);
|
||||
endianness = bswap(*reinterpret_cast<u32 *>(rom.cart.data()));
|
||||
Util::SwapN64Rom(rom.cart, endianness);
|
||||
@@ -186,15 +186,15 @@ void Mem::LoadROM(bool isArchive, const std::string &filename) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
SI &si = mmio.si;
|
||||
u8 Mem::Read(Registers ®s, const u32 paddr) {
|
||||
const SI &si = mmio.si;
|
||||
|
||||
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;
|
||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return src[BYTE_ADDRESS(paddr & 0xfff)];
|
||||
}
|
||||
case REGION_CART:
|
||||
@@ -206,9 +206,9 @@ u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
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;
|
||||
const u32 w = mmio.ai.Read(paddr & ~3);
|
||||
const 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];
|
||||
@@ -221,19 +221,20 @@ u8 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})", paddr, (u64)regs.pc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
SI &si = mmio.si;
|
||||
u16 Mem::Read(Registers ®s, const u32 paddr) {
|
||||
const SI &si = mmio.si;
|
||||
|
||||
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;
|
||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u16>(src, HALF_ADDRESS(paddr & 0xfff));
|
||||
}
|
||||
case MMIO_REGION:
|
||||
@@ -251,19 +252,20 @@ u16 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
return 0;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})", paddr, (u64)regs.pc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
SI &si = mmio.si;
|
||||
u32 Mem::Read(Registers ®s, const u32 paddr) {
|
||||
const SI &si = mmio.si;
|
||||
|
||||
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;
|
||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u32>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
@@ -285,15 +287,15 @@ u32 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u64 Mem::Read(n64::Registers ®s, u32 paddr) {
|
||||
SI &si = mmio.si;
|
||||
u64 Mem::Read(Registers ®s, const u32 paddr) {
|
||||
const SI &si = mmio.si;
|
||||
|
||||
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;
|
||||
const auto &src = paddr & 0x1000 ? mmio.rsp.imem : mmio.rsp.dmem;
|
||||
return Util::ReadAccess<u64>(src, paddr & 0xfff);
|
||||
}
|
||||
case MMIO_REGION:
|
||||
@@ -397,7 +399,7 @@ void Mem::Write<u16>(Registers ®s, u32 paddr, u32 val) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void Mem::Write<u32>(Registers ®s, u32 paddr, u32 val) {
|
||||
void Mem::Write<u32>(Registers ®s, const u32 paddr, const u32 val) {
|
||||
SI &si = mmio.si;
|
||||
|
||||
switch (paddr) {
|
||||
@@ -434,7 +436,7 @@ void Mem::Write<u32>(Registers ®s, u32 paddr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mem::Write(Registers ®s, u32 paddr, u64 val) {
|
||||
void Mem::Write(const Registers ®s, const u32 paddr, u64 val) {
|
||||
SI &si = mmio.si;
|
||||
|
||||
switch (paddr) {
|
||||
@@ -472,7 +474,7 @@ void Mem::Write(Registers ®s, u32 paddr, u64 val) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u32 Mem::BackupRead<u32>(u32 addr) {
|
||||
u32 Mem::BackupRead<u32>(const u32 addr) {
|
||||
switch (saveType) {
|
||||
case SAVE_NONE:
|
||||
return 0;
|
||||
@@ -490,7 +492,7 @@ u32 Mem::BackupRead<u32>(u32 addr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u8 Mem::BackupRead<u8>(u32 addr) {
|
||||
u8 Mem::BackupRead<u8>(const u32 addr) {
|
||||
switch (saveType) {
|
||||
case SAVE_NONE:
|
||||
return 0;
|
||||
@@ -513,7 +515,7 @@ u8 Mem::BackupRead<u8>(u32 addr) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void Mem::BackupWrite<u32>(u32 addr, u32 val) {
|
||||
void Mem::BackupWrite<u32>(const u32 addr, const u32 val) {
|
||||
switch (saveType) {
|
||||
case SAVE_NONE:
|
||||
Util::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||
@@ -532,7 +534,7 @@ void Mem::BackupWrite<u32>(u32 addr, u32 val) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void Mem::BackupWrite<u8>(u32 addr, u8 val) {
|
||||
void Mem::BackupWrite<u8>(const u32 addr, const u8 val) {
|
||||
switch (saveType) {
|
||||
case SAVE_NONE:
|
||||
Util::warn("Accessing cartridge with save type SAVE_NONE in write word");
|
||||
@@ -572,8 +574,8 @@ std::vector<u8> Mem::Serialize() {
|
||||
}
|
||||
|
||||
void Mem::Deserialize(const std::vector<u8> &data) {
|
||||
mmio.Deserialize(std::vector<u8>(data.begin(), data.begin() + mmioSize));
|
||||
flash.Deserialize(std::vector<u8>(data.begin() + mmioSize, data.begin() + mmioSize + flashSize));
|
||||
mmio.Deserialize(std::vector(data.begin(), data.begin() + mmioSize));
|
||||
flash.Deserialize(std::vector(data.begin() + mmioSize, data.begin() + mmioSize + flashSize));
|
||||
memcpy(saveData.data(), data.data() + mmioSize + flashSize, saveData.size());
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
@@ -62,7 +62,7 @@ struct Flash {
|
||||
FLASH_COMMAND_READ = 0xF0,
|
||||
};
|
||||
|
||||
void CommandExecute();
|
||||
void CommandExecute() const;
|
||||
void CommandStatus();
|
||||
void CommandSetEraseOffs(u32);
|
||||
void CommandErase();
|
||||
@@ -96,7 +96,7 @@ struct Mem {
|
||||
T Read(Registers &, u32);
|
||||
template <typename T>
|
||||
void Write(Registers &, u32, u32);
|
||||
void Write(Registers &, u32, u64);
|
||||
void Write(const Registers &, u32, u64);
|
||||
|
||||
template <typename T>
|
||||
T BackupRead(u32);
|
||||
@@ -108,21 +108,21 @@ struct Mem {
|
||||
FORCE_INLINE void DumpRDRAM() const {
|
||||
std::vector<u8> temp{};
|
||||
temp.resize(RDRAM_SIZE);
|
||||
std::copy(mmio.rdp.rdram.begin(), mmio.rdp.rdram.end(), temp.begin());
|
||||
std::ranges::copy(mmio.rdp.rdram, temp.begin());
|
||||
Util::SwapBuffer<u32>(temp);
|
||||
Util::WriteFileBinary(temp, "rdram.bin");
|
||||
}
|
||||
|
||||
FORCE_INLINE void DumpIMEM() const {
|
||||
std::array<u8, IMEM_SIZE> temp{};
|
||||
std::copy(mmio.rsp.imem.begin(), mmio.rsp.imem.end(), temp.begin());
|
||||
std::ranges::copy(mmio.rsp.imem, temp.begin());
|
||||
Util::SwapBuffer<u32>(temp);
|
||||
Util::WriteFileBinary(temp, "imem.bin");
|
||||
}
|
||||
|
||||
FORCE_INLINE void DumpDMEM() const {
|
||||
std::array<u8, DMEM_SIZE> temp{};
|
||||
std::copy(mmio.rsp.dmem.begin(), mmio.rsp.dmem.end(), temp.begin());
|
||||
std::ranges::copy(mmio.rsp.dmem, temp.begin());
|
||||
Util::SwapBuffer<u32>(temp);
|
||||
Util::WriteFileBinary(temp, "dmem.bin");
|
||||
}
|
||||
@@ -141,9 +141,9 @@ private:
|
||||
mio::mmap_sink saveData{};
|
||||
int mmioSize{}, flashSize{};
|
||||
|
||||
FORCE_INLINE bool IsROMPAL() {
|
||||
static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
|
||||
return std::any_of(std::begin(pal_codes), std::end(pal_codes), [this](char a) { return rom.cart[0x3d] == a; });
|
||||
[[nodiscard]] FORCE_INLINE bool IsROMPAL() const {
|
||||
static constexpr char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
|
||||
return std::ranges::any_of(pal_codes, [this](char a) { return rom.cart[0x3d] == a; });
|
||||
}
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace n64 {
|
||||
RDP::RDP(Mem &mem, ParallelRDP ¶llel) : mem(mem), parallel(parallel) {
|
||||
rdram.resize(RDRAM_SIZE);
|
||||
std::fill(rdram.begin(), rdram.end(), 0);
|
||||
std::ranges::fill(rdram, 0);
|
||||
memset(cmd_buf, 0, 0x100000);
|
||||
dpc.status.raw = 0x80;
|
||||
}
|
||||
@@ -15,75 +15,75 @@ RDP::RDP(Mem &mem, ParallelRDP ¶llel) : mem(mem), parallel(parallel) {
|
||||
void RDP::Reset() {
|
||||
dpc = {};
|
||||
dpc.status.raw = 0x80;
|
||||
std::fill(rdram.begin(), rdram.end(), 0);
|
||||
std::ranges::fill(rdram, 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) {
|
||||
void RDP::WriteRDRAM<u8>(const size_t idx, const u8 v) {
|
||||
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
||||
rdram[real] = v;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void RDP::WriteRDRAM<u16>(size_t idx, u16 v) {
|
||||
size_t real = HALF_ADDRESS(idx);
|
||||
if (real < RDRAM_SIZE) {
|
||||
void RDP::WriteRDRAM<u16>(const size_t idx, const u16 v) {
|
||||
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]] {
|
||||
Util::WriteAccess<u16>(rdram, real, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void RDP::WriteRDRAM<u32>(size_t idx, u32 v) {
|
||||
if (idx < RDRAM_SIZE) {
|
||||
void RDP::WriteRDRAM<u32>(const size_t idx, const u32 v) {
|
||||
if (idx < RDRAM_SIZE) [[likely]] {
|
||||
Util::WriteAccess<u32>(rdram, idx, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void RDP::WriteRDRAM<u64>(size_t idx, u64 v) {
|
||||
if (idx < RDRAM_SIZE) {
|
||||
void RDP::WriteRDRAM<u64>(const size_t idx, const u64 v) {
|
||||
if (idx < RDRAM_SIZE) [[likely]] {
|
||||
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];
|
||||
u8 RDP::ReadRDRAM<u8>(const size_t idx) {
|
||||
if (const size_t real = BYTE_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
||||
return rdram[real];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
u16 RDP::ReadRDRAM<u16>(const size_t idx) {
|
||||
if (const size_t real = HALF_ADDRESS(idx); real < RDRAM_SIZE) [[likely]]
|
||||
return Util::ReadAccess<u16>(rdram, real);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
u32 RDP::ReadRDRAM<u32>(size_t idx) {
|
||||
if (idx >= RDRAM_SIZE)
|
||||
return 0;
|
||||
return Util::ReadAccess<u32>(rdram, idx);
|
||||
u32 RDP::ReadRDRAM<u32>(const size_t idx) {
|
||||
if (idx < RDRAM_SIZE) [[likely]]
|
||||
return Util::ReadAccess<u32>(rdram, idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <>
|
||||
u64 RDP::ReadRDRAM<u64>(size_t idx) {
|
||||
if (idx >= RDRAM_SIZE)
|
||||
return 0;
|
||||
return Util::ReadAccess<u64>(rdram, idx);
|
||||
u64 RDP::ReadRDRAM<u64>(const size_t idx) {
|
||||
if (idx < RDRAM_SIZE) [[likely]]
|
||||
return Util::ReadAccess<u64>(rdram, idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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, 2, 2, 2, 2, 4, 4, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
|
||||
|
||||
auto RDP::Read(u32 addr) const -> u32 {
|
||||
auto RDP::Read(const u32 addr) const -> u32 {
|
||||
switch (addr) {
|
||||
case 0x04100000:
|
||||
return dpc.start;
|
||||
@@ -104,9 +104,11 @@ auto RDP::Read(u32 addr) const -> u32 {
|
||||
default:
|
||||
Util::panic("Unhandled DP Command Registers read (addr: {:08X})", addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RDP::Write(u32 addr, u32 val) {
|
||||
void RDP::Write(const u32 addr, const u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04100000:
|
||||
WriteStart(val);
|
||||
@@ -122,7 +124,7 @@ void RDP::Write(u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
void RDP::WriteStatus(u32 val) {
|
||||
void RDP::WriteStatus(const u32 val) {
|
||||
DPCStatusWrite temp{};
|
||||
temp.raw = val;
|
||||
|
||||
@@ -201,39 +203,40 @@ void RDP::RunCommand() {
|
||||
const u32 current = dpc.current & 0xFFFFF8;
|
||||
const u32 end = dpc.end & 0xFFFFF8;
|
||||
|
||||
int len = end - current;
|
||||
const auto len = static_cast<s32>(end) - static_cast<s32>(current);
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
if (len + (remaining_cmds * 4) > 0xFFFFF) {
|
||||
if (len + remaining_cmds * 4 > 0xFFFFF) {
|
||||
Util::panic("Too many RDP commands");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dpc.status.xbusDmemDma) {
|
||||
for (int i = 0; i < len; i += 4) {
|
||||
u32 cmd = Util::ReadAccess<u32>(mem.mmio.rsp.dmem, (current + i) & 0xFFF);
|
||||
const u32 cmd = Util::ReadAccess<u32>(mem.mmio.rsp.dmem, (current + i) & 0xFFF);
|
||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||
}
|
||||
} else {
|
||||
if (end > 0x7FFFFFF || current > 0x7FFFFFF) { // if (end > RDRAM_DSIZE || current > RDRAM_DSIZE)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i += 4) {
|
||||
u32 cmd = Util::ReadAccess<u32>(rdram, current + i);
|
||||
const u32 cmd = Util::ReadAccess<u32>(rdram, current + i);
|
||||
cmd_buf[remaining_cmds + (i >> 2)] = cmd;
|
||||
}
|
||||
}
|
||||
|
||||
int word_len = (len >> 2) + remaining_cmds;
|
||||
const int word_len = (len >> 2) + remaining_cmds;
|
||||
int buf_index = 0;
|
||||
|
||||
bool processed_all = true;
|
||||
|
||||
while (buf_index < word_len) {
|
||||
u8 cmd = (cmd_buf[buf_index] >> 24) & 0x3F;
|
||||
const u8 cmd = (cmd_buf[buf_index] >> 24) & 0x3F;
|
||||
|
||||
int cmd_len = cmd_lens[cmd];
|
||||
const int cmd_len = cmd_lens[cmd];
|
||||
if ((buf_index + cmd_len) * 4 > len + (remaining_cmds * 4)) {
|
||||
remaining_cmds = word_len - buf_index;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
RSP::RSP(Mem &mem, Registers ®s) : mem(mem), regs(regs) { Reset(); }
|
||||
RSP::RSP(Mem &mem, Registers ®s) : regs(regs), mem(mem) { Reset(); }
|
||||
|
||||
void RSP::Reset() {
|
||||
lastSuccessfulSPAddr.raw = 0;
|
||||
@@ -65,7 +65,7 @@ FORCE_INLINE void logRSP(const RSP& rsp, const u32 instr) {
|
||||
}
|
||||
*/
|
||||
|
||||
auto RSP::Read(u32 addr) -> u32 {
|
||||
auto RSP::Read(const u32 addr) -> u32 {
|
||||
switch (addr) {
|
||||
case 0x04040000:
|
||||
return lastSuccessfulSPAddr.raw & 0x1FF8;
|
||||
@@ -89,9 +89,9 @@ auto RSP::Read(u32 addr) -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
void RSP::WriteStatus(u32 value) {
|
||||
void RSP::WriteStatus(const u32 value) {
|
||||
MI &mi = mem.mmio.mi;
|
||||
auto write = SPStatusWrite{.raw = value};
|
||||
const auto write = SPStatusWrite{.raw = value};
|
||||
if (write.clearHalt && !write.setHalt) {
|
||||
spStatus.halt = false;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ void RSP::DMA<true>() {
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE> &src = spDMASPAddr.bank ? imem : dmem;
|
||||
const auto &src = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
@@ -134,7 +134,7 @@ void RSP::DMA<true>() {
|
||||
mem.mmio.rdp.WriteRDRAM<u8>(BYTE_ADDRESS(dram_address + j), src[(mem_address + j) & DMEM_DSIZE]);
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
const int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
@@ -155,7 +155,7 @@ void RSP::DMA<false>() {
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
std::array<u8, DMEM_SIZE> &dst = spDMASPAddr.bank ? imem : dmem;
|
||||
auto &dst = spDMASPAddr.bank ? imem : dmem;
|
||||
|
||||
u32 mem_address = spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = spDMADRAMAddr.address & 0xFFFFF8;
|
||||
@@ -166,7 +166,7 @@ void RSP::DMA<false>() {
|
||||
dst[(mem_address + j) & DMEM_DSIZE] = mem.mmio.rdp.ReadRDRAM<u8>(BYTE_ADDRESS(dram_address + j));
|
||||
}
|
||||
|
||||
int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
const int skip = i == spDMALen.count ? 0 : spDMALen.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
@@ -181,7 +181,7 @@ void RSP::DMA<false>() {
|
||||
spDMALen.raw = 0xFF8 | (spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void RSP::Write(u32 addr, u32 val) {
|
||||
void RSP::Write(const u32 addr, const u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04040000:
|
||||
spDMASPAddr.raw = val & 0x1FF8;
|
||||
|
||||
@@ -118,9 +118,9 @@ struct Registers;
|
||||
#define DE(x) (((x) >> 11) & 0x1F)
|
||||
#define CLEAR_SET(val, clear, set) \
|
||||
do { \
|
||||
if (clear && !set) \
|
||||
if ((clear) && !(set)) \
|
||||
(val) = 0; \
|
||||
if (set && !clear) \
|
||||
if ((set) && !(clear)) \
|
||||
(val) = 1; \
|
||||
} \
|
||||
while (0)
|
||||
@@ -131,13 +131,15 @@ struct RSP {
|
||||
|
||||
FORCE_INLINE void Step() {
|
||||
gpr[0] = 0;
|
||||
u32 instr = Util::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
|
||||
const u32 instr = Util::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
|
||||
oldPC = pc & 0xFFC;
|
||||
pc = nextPC & 0xFFC;
|
||||
nextPC += 4;
|
||||
|
||||
Exec(instr);
|
||||
}
|
||||
|
||||
void SetVTE(const VPR &vt, u8 e);
|
||||
auto Read(u32 addr) -> u32;
|
||||
void Write(u32 addr, u32 val);
|
||||
void Exec(u32 instr);
|
||||
@@ -151,6 +153,7 @@ struct RSP {
|
||||
std::array<u8, DMEM_SIZE> dmem{};
|
||||
std::array<u8, IMEM_SIZE> imem{};
|
||||
VPR vpr[32]{};
|
||||
VPR vte{};
|
||||
s32 gpr[32]{};
|
||||
VPR vce{};
|
||||
s16 divIn{}, divOut{};
|
||||
@@ -167,13 +170,13 @@ struct RSP {
|
||||
|
||||
bool semaphore = false;
|
||||
|
||||
FORCE_INLINE void SetPC(u16 val) {
|
||||
FORCE_INLINE void SetPC(const u16 val) {
|
||||
oldPC = pc & 0xFFC;
|
||||
pc = val & 0xFFC;
|
||||
nextPC = pc + 4;
|
||||
}
|
||||
|
||||
FORCE_INLINE s64 GetACC(int e) const {
|
||||
[[nodiscard]] FORCE_INLINE s64 GetACC(const int e) const {
|
||||
s64 val = u64(acc.h.element[e]) << 32;
|
||||
val |= u64(acc.m.element[e]) << 16;
|
||||
val |= u64(acc.l.element[e]) << 00;
|
||||
@@ -183,69 +186,69 @@ struct RSP {
|
||||
return val;
|
||||
}
|
||||
|
||||
FORCE_INLINE void SetACC(int e, s64 val) {
|
||||
FORCE_INLINE void SetACC(const int e, const s64 val) {
|
||||
acc.h.element[e] = val >> 32;
|
||||
acc.m.element[e] = val >> 16;
|
||||
acc.l.element[e] = val;
|
||||
}
|
||||
|
||||
FORCE_INLINE u16 GetVCO() const {
|
||||
[[nodiscard]] FORCE_INLINE u16 GetVCO() const {
|
||||
u16 value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool h = vco.h.element[7 - i] != 0;
|
||||
bool l = vco.l.element[7 - i] != 0;
|
||||
u32 mask = (l << i) | (h << (i + 8));
|
||||
const bool h = vco.h.element[7 - i] != 0;
|
||||
const bool l = vco.l.element[7 - i] != 0;
|
||||
const u32 mask = (l << i) | (h << (i + 8));
|
||||
value |= mask;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
FORCE_INLINE u16 GetVCC() const {
|
||||
[[nodiscard]] FORCE_INLINE u16 GetVCC() const {
|
||||
u16 value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool h = vcc.h.element[7 - i] != 0;
|
||||
bool l = vcc.l.element[7 - i] != 0;
|
||||
u32 mask = (l << i) | (h << (i + 8));
|
||||
const bool h = vcc.h.element[7 - i] != 0;
|
||||
const bool l = vcc.l.element[7 - i] != 0;
|
||||
const u32 mask = (l << i) | (h << (i + 8));
|
||||
value |= mask;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
FORCE_INLINE u8 GetVCE() const {
|
||||
[[nodiscard]] FORCE_INLINE u8 GetVCE() const {
|
||||
u8 value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool l = vce.element[ELEMENT_INDEX(i)] != 0;
|
||||
const bool l = vce.element[ELEMENT_INDEX(i)] != 0;
|
||||
value |= (l << i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
FORCE_INLINE u32 ReadWord(u32 addr) {
|
||||
[[nodiscard]] FORCE_INLINE u32 ReadWord(u32 addr) const {
|
||||
addr &= 0xfff;
|
||||
return GET_RSP_WORD(addr);
|
||||
}
|
||||
|
||||
FORCE_INLINE void WriteWord(u32 addr, u32 val) {
|
||||
FORCE_INLINE void WriteWord(u32 addr, const u32 val) {
|
||||
addr &= 0xfff;
|
||||
SET_RSP_WORD(addr, val);
|
||||
}
|
||||
|
||||
FORCE_INLINE u16 ReadHalf(u32 addr) {
|
||||
[[nodiscard]] FORCE_INLINE u16 ReadHalf(u32 addr) const {
|
||||
addr &= 0xfff;
|
||||
return GET_RSP_HALF(addr);
|
||||
}
|
||||
|
||||
FORCE_INLINE void WriteHalf(u32 addr, u16 val) {
|
||||
FORCE_INLINE void WriteHalf(u32 addr, const u16 val) {
|
||||
addr &= 0xfff;
|
||||
SET_RSP_HALF(addr, val);
|
||||
}
|
||||
|
||||
FORCE_INLINE u8 ReadByte(u32 addr) {
|
||||
[[nodiscard]] FORCE_INLINE u8 ReadByte(u32 addr) const {
|
||||
addr &= 0xfff;
|
||||
return RSP_BYTE(addr);
|
||||
}
|
||||
|
||||
FORCE_INLINE void WriteByte(u32 addr, u8 val) {
|
||||
FORCE_INLINE void WriteByte(u32 addr, const u8 val) {
|
||||
addr &= 0xfff;
|
||||
RSP_BYTE(addr) = val;
|
||||
}
|
||||
@@ -364,8 +367,8 @@ struct RSP {
|
||||
void vor(u32 instr);
|
||||
void vnor(u32 instr);
|
||||
void vzero(u32 instr);
|
||||
void mfc0(RDP &rdp, u32 instr);
|
||||
void mtc0(u32 instr);
|
||||
void mfc0(const RDP &rdp, u32 instr);
|
||||
void mtc0(u32 instr) const;
|
||||
void mfc2(u32 instr);
|
||||
void mtc2(u32 instr);
|
||||
|
||||
@@ -376,13 +379,13 @@ struct RSP {
|
||||
private:
|
||||
Registers ®s;
|
||||
Mem &mem;
|
||||
FORCE_INLINE void branch(u16 address, bool cond) {
|
||||
FORCE_INLINE void branch(const u16 address, const bool cond) {
|
||||
if (cond) {
|
||||
nextPC = address & 0xFFC;
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void branch_likely(u16 address, bool cond) {
|
||||
FORCE_INLINE void branch_likely(const u16 address, const bool cond) {
|
||||
if (cond) {
|
||||
nextPC = address & 0xFFC;
|
||||
} else {
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void Interpreter::special(u32 instr) {
|
||||
u8 mask = (instr & 0x3F);
|
||||
void Interpreter::special(const u32 instr) {
|
||||
// 00rr_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
switch (const u8 mask = instr & 0x3F) {
|
||||
case SLL:
|
||||
if (instr != 0) {
|
||||
sll(instr);
|
||||
@@ -166,14 +165,13 @@ void Interpreter::special(u32 instr) {
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr,
|
||||
(u64)regs.oldPC);
|
||||
static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::regimm(u32 instr) {
|
||||
u8 mask = ((instr >> 16) & 0x1F);
|
||||
void Interpreter::regimm(const u32 instr) {
|
||||
// 000r_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
switch (const u8 mask = instr >> 16 & 0x1F) {
|
||||
case BLTZ:
|
||||
b(instr, regs.Read<s64>(RS(instr)) < 0);
|
||||
break;
|
||||
@@ -187,22 +185,22 @@ void Interpreter::regimm(u32 instr) {
|
||||
bl(instr, regs.Read<s64>(RS(instr)) >= 0);
|
||||
break;
|
||||
case TGEI:
|
||||
trap(regs.Read<s64>(RS(instr)) >= s64(s16(instr)));
|
||||
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TGEIU:
|
||||
trap(regs.Read<u64>(RS(instr)) >= u64(s64(s16(instr))));
|
||||
trap(regs.Read<u64>(RS(instr)) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||
break;
|
||||
case TLTI:
|
||||
trap(regs.Read<s64>(RS(instr)) < s64(s16(instr)));
|
||||
trap(regs.Read<s64>(RS(instr)) < static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TLTIU:
|
||||
trap(regs.Read<u64>(RS(instr)) < u64(s64(s16(instr))));
|
||||
trap(regs.Read<u64>(RS(instr)) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||
break;
|
||||
case TEQI:
|
||||
trap(regs.Read<s64>(RS(instr)) == s64(s16(instr)));
|
||||
trap(regs.Read<s64>(RS(instr)) == static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TNEI:
|
||||
trap(regs.Read<s64>(RS(instr)) != s64(s16(instr)));
|
||||
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case BLTZAL:
|
||||
blink(instr, regs.Read<s64>(RS(instr)) < 0);
|
||||
@@ -217,11 +215,12 @@ void Interpreter::regimm(u32 instr) {
|
||||
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);
|
||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr,
|
||||
static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::cop2Decode(u32 instr) {
|
||||
void Interpreter::cop2Decode(const u32 instr) {
|
||||
if (!regs.cop0.status.cu2) {
|
||||
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
return;
|
||||
@@ -250,10 +249,9 @@ void Interpreter::cop2Decode(u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::Exec(u32 instr) {
|
||||
u8 mask = (instr >> 26) & 0x3f;
|
||||
void Interpreter::Exec(const u32 instr) {
|
||||
// 00rr_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
switch (const u8 mask = instr >> 26 & 0x3f) {
|
||||
case SPECIAL:
|
||||
special(instr);
|
||||
break;
|
||||
@@ -416,7 +414,7 @@ void Interpreter::Exec(u32 instr) {
|
||||
sd(instr);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, (u64)regs.oldPC);
|
||||
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ void Flash::Load(SaveType saveType, const std::string &path) {
|
||||
}
|
||||
}
|
||||
|
||||
void Flash::CommandExecute() {
|
||||
void Flash::CommandExecute() const {
|
||||
Util::trace("Flash::CommandExecute");
|
||||
switch (state) {
|
||||
case FlashState::Idle:
|
||||
@@ -119,7 +119,7 @@ std::vector<u8> Flash::Serialize() {
|
||||
index += sizeof(eraseOffs);
|
||||
memcpy(res.data() + index, &writeOffs, sizeof(writeOffs));
|
||||
index += sizeof(writeOffs);
|
||||
std::copy(writeBuf.begin(), writeBuf.end(), res.begin() + index);
|
||||
std::ranges::copy(writeBuf, res.begin() + index);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -192,31 +192,31 @@ void Flash::Write<u8>(u32 index, u8 val) {
|
||||
}
|
||||
|
||||
template <>
|
||||
u8 Flash::Read<u8>(u32 index) const {
|
||||
u8 Flash::Read<u8>(const u32 index) const {
|
||||
switch (state) {
|
||||
case FlashState::Idle:
|
||||
Util::panic("Flash read byte while in state FLASH_STATE_IDLE");
|
||||
case FlashState::Write:
|
||||
Util::panic("Flash read byte while in state FLASH_STATE_WRITE");
|
||||
case FlashState::Read:
|
||||
{
|
||||
if (saveData.is_mapped()) {
|
||||
u8 value = saveData[index];
|
||||
Util::trace("Flash read byte in state read: index {:08X} = {:02X}", index, value);
|
||||
return value;
|
||||
} else {
|
||||
Util::panic("Accessing flash when not mapped!");
|
||||
}
|
||||
if (saveData.is_mapped()) {
|
||||
const u8 value = saveData[index];
|
||||
Util::trace("Flash read byte in state read: index {:08X} = {:02X}", index, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
Util::panic("Accessing flash when not mapped!");
|
||||
|
||||
case FlashState::Status:
|
||||
{
|
||||
u32 offset = (7 - (index % 8)) * 8;
|
||||
u8 value = (status >> offset) & 0xFF;
|
||||
const u32 offset = (7 - (index % 8)) * 8;
|
||||
const u8 value = (status >> offset) & 0xFF;
|
||||
Util::trace("Flash read byte in state status: index {:08X} = {:02X}", index, value);
|
||||
return value;
|
||||
}
|
||||
default:
|
||||
Util::panic("Flash read byte while in unknown state");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ void AI::Reset() {
|
||||
|
||||
// https://github.com/ares-emulator/ares/blob/master/ares/n64/ai/io.cpp
|
||||
// https://github.com/ares-emulator/ares/blob/master/LICENSE
|
||||
auto AI::Read(u32 addr) const -> u32 {
|
||||
auto AI::Read(const u32 addr) const -> u32 {
|
||||
if (addr == 0x0450000C) {
|
||||
u32 val = 0;
|
||||
val |= (dmaCount > 1);
|
||||
@@ -36,7 +36,7 @@ auto AI::Read(u32 addr) const -> u32 {
|
||||
return dmaLen[0];
|
||||
}
|
||||
|
||||
void AI::Write(u32 addr, u32 val) {
|
||||
void AI::Write(const u32 addr, const u32 val) {
|
||||
switch (addr) {
|
||||
case 0x04500000:
|
||||
if (dmaCount < 2) {
|
||||
@@ -45,7 +45,7 @@ void AI::Write(u32 addr, u32 val) {
|
||||
break;
|
||||
case 0x04500004:
|
||||
{
|
||||
u32 len = (val & 0x3FFFF) & ~7;
|
||||
const u32 len = (val & 0x3FFFF) & ~7;
|
||||
if (dmaCount < 2) {
|
||||
if (dmaCount == 0)
|
||||
mem.mmio.mi.InterruptRaise(MI::Interrupt::AI);
|
||||
@@ -62,7 +62,7 @@ void AI::Write(u32 addr, u32 val) {
|
||||
break;
|
||||
case 0x04500010:
|
||||
{
|
||||
u32 oldDacFreq = dac.freq;
|
||||
const u32 oldDacFreq = dac.freq;
|
||||
dacRate = val & 0x3FFF;
|
||||
dac.freq = std::max(1.f, (float)GetVideoFrequency(mem.IsROMPAL()) / (dacRate + 1)) * 1.037;
|
||||
dac.period = N64_CPU_FREQ / dac.freq;
|
||||
@@ -80,7 +80,7 @@ void AI::Write(u32 addr, u32 val) {
|
||||
}
|
||||
}
|
||||
|
||||
void AI::Step(u32 cpuCycles, float volumeL, float volumeR) {
|
||||
void AI::Step(const u32 cpuCycles, const float volumeL, const float volumeR) {
|
||||
cycles += cpuCycles;
|
||||
while (cycles > dac.period) {
|
||||
if (dmaCount == 0) {
|
||||
@@ -88,18 +88,18 @@ 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 = mem.mmio.rdp.ReadRDRAM<u32>(dmaAddr[0]);
|
||||
s16 l = s16(data >> 16);
|
||||
s16 r = s16(data);
|
||||
const u32 addrHi = (dmaAddr[0] >> 13) + dmaAddrCarry & 0x7FF;
|
||||
dmaAddr[0] = addrHi << 13 | dmaAddr[0] & 0x1FFF;
|
||||
const u32 data = mem.mmio.rdp.ReadRDRAM<u32>(dmaAddr[0]);
|
||||
const s16 l = s16(data >> 16);
|
||||
const s16 r = s16(data);
|
||||
|
||||
if (volumeR > 0 && volumeL > 0) {
|
||||
device.PushSample((float)l / INT16_MAX, volumeL, (float)r / INT16_MAX, volumeR);
|
||||
}
|
||||
|
||||
u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF;
|
||||
dmaAddr[0] = (dmaAddr[0] & ~0x1FFF) | addrLo;
|
||||
const u32 addrLo = dmaAddr[0] + 4 & 0x1FFF;
|
||||
dmaAddr[0] = dmaAddr[0] & ~0x1FFF | addrLo;
|
||||
dmaAddrCarry = addrLo == 0;
|
||||
dmaLen[0] -= 4;
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ AudioDevice::AudioDevice() {
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDevice::PushSample(float left, float volumeL, float right, float volumeR) {
|
||||
float adjustedL = left * volumeL;
|
||||
float adjustedR = right * volumeR;
|
||||
float samples[]{adjustedL, adjustedR};
|
||||
void AudioDevice::PushSample(const float left, const float volumeL, const float right, const float volumeR) {
|
||||
const float adjustedL = left * volumeL;
|
||||
const float adjustedR = right * volumeR;
|
||||
const float samples[]{adjustedL, adjustedR};
|
||||
|
||||
auto availableBytes = (float)SDL_GetAudioStreamAvailable(audioStream);
|
||||
if (availableBytes <= BYTES_PER_HALF_SECOND) {
|
||||
if (const auto availableBytes = static_cast<float>(SDL_GetAudioStreamAvailable(audioStream));
|
||||
availableBytes <= BYTES_PER_HALF_SECOND) {
|
||||
SDL_PutAudioStreamData(audioStream, samples, 2 * sizeof(float));
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ void AudioDevice::PushSample(float left, float volumeL, float right, float volum
|
||||
}
|
||||
}
|
||||
|
||||
void AudioDevice::AdjustSampleRate(int sampleRate) {
|
||||
void AudioDevice::AdjustSampleRate(const int sampleRate) {
|
||||
LockMutex();
|
||||
SDL_DestroyAudioStream(audioStream);
|
||||
|
||||
|
||||
@@ -11,16 +11,16 @@ struct AudioDevice {
|
||||
|
||||
void PushSample(float, float, float, float);
|
||||
void AdjustSampleRate(int);
|
||||
void LockMutex() {
|
||||
void LockMutex() const {
|
||||
if (audioStreamMutex)
|
||||
SDL_LockMutex(audioStreamMutex);
|
||||
}
|
||||
void UnlockMutex() {
|
||||
void UnlockMutex() const {
|
||||
if (audioStreamMutex)
|
||||
SDL_UnlockMutex(audioStreamMutex);
|
||||
}
|
||||
|
||||
SDL_AudioStream *GetStream() { return audioStream; }
|
||||
SDL_AudioStream *GetStream() const { return audioStream; }
|
||||
|
||||
private:
|
||||
SDL_AudioStream *audioStream;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void MI::InterruptRaise(Interrupt intr) {
|
||||
void MI::InterruptRaise(const Interrupt intr) {
|
||||
switch (intr) {
|
||||
case Interrupt::VI:
|
||||
miIntr.vi = true;
|
||||
@@ -27,7 +27,7 @@ void MI::InterruptRaise(Interrupt intr) {
|
||||
UpdateInterrupt();
|
||||
}
|
||||
|
||||
void MI::InterruptLower(Interrupt intr) {
|
||||
void MI::InterruptLower(const Interrupt intr) {
|
||||
switch (intr) {
|
||||
case Interrupt::VI:
|
||||
miIntr.vi = false;
|
||||
@@ -52,8 +52,8 @@ void MI::InterruptLower(Interrupt intr) {
|
||||
UpdateInterrupt();
|
||||
}
|
||||
|
||||
void MI::UpdateInterrupt() {
|
||||
bool interrupt = miIntr.raw & miIntrMask.raw;
|
||||
void MI::UpdateInterrupt() const {
|
||||
const bool interrupt = miIntr.raw & miIntrMask.raw;
|
||||
regs.cop0.cause.ip2 = interrupt;
|
||||
}
|
||||
} // namespace n64
|
||||
|
||||
@@ -66,8 +66,8 @@ void MI::Write(u32 paddr, u32 val) {
|
||||
break;
|
||||
case 0xC:
|
||||
for (int bit = 0; bit < 6; bit++) {
|
||||
int clearbit = bit << 1;
|
||||
int setbit = (bit << 1) + 1;
|
||||
const int clearbit = bit << 1;
|
||||
const int setbit = (bit << 1) + 1;
|
||||
|
||||
if (val & (1 << clearbit)) {
|
||||
miIntrMask.raw &= ~(1 << bit);
|
||||
|
||||
@@ -21,13 +21,13 @@ struct Registers;
|
||||
struct MI {
|
||||
enum class Interrupt : u8 { VI, SI, PI, AI, DP, SP };
|
||||
|
||||
MI(Registers &);
|
||||
explicit MI(Registers &);
|
||||
void Reset();
|
||||
[[nodiscard]] auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
void InterruptRaise(Interrupt intr);
|
||||
void InterruptLower(Interrupt intr);
|
||||
void UpdateInterrupt();
|
||||
void UpdateInterrupt() const;
|
||||
|
||||
u32 miMode{};
|
||||
MIIntr miIntr{}, miIntrMask{};
|
||||
|
||||
@@ -65,7 +65,7 @@ auto PI::BusRead<u8, true>(u32 addr) -> u8 {
|
||||
case REGION_PI_ROM:
|
||||
{
|
||||
// round to nearest 4 byte boundary, keeping old LSB
|
||||
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
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.cart.size(), mem.rom.cart.size());
|
||||
@@ -104,7 +104,7 @@ auto PI::BusRead<u8, false>(u32 addr) -> u8 {
|
||||
{
|
||||
addr = (addr + 2) & ~2;
|
||||
// round to nearest 4 byte boundary, keeping old LSB
|
||||
u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
const u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
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.cart.size(), mem.rom.cart.size());
|
||||
@@ -178,7 +178,7 @@ auto PI::BusRead<u16, false>(u32 addr) -> u16 {
|
||||
case REGION_PI_ROM:
|
||||
{
|
||||
addr = (addr + 2) & ~3;
|
||||
u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
const u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM;
|
||||
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);
|
||||
}
|
||||
@@ -312,7 +312,7 @@ 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());
|
||||
std::copy_n(mem.isviewer.begin(), val, message.begin());
|
||||
Util::print<Util::Always>("{}", message);
|
||||
} else {
|
||||
Util::panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!",
|
||||
@@ -355,7 +355,7 @@ auto PI::BusRead<u64, false>(u32 addr) -> u64 {
|
||||
Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr);
|
||||
case REGION_PI_ROM:
|
||||
{
|
||||
u32 index = addr - SREGION_PI_ROM;
|
||||
const u32 index = addr - SREGION_PI_ROM;
|
||||
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);
|
||||
}
|
||||
@@ -439,7 +439,7 @@ auto PI::Read(u32 addr) const -> u32 {
|
||||
}
|
||||
}
|
||||
|
||||
u8 PI::GetDomain(u32 address) {
|
||||
u8 PI::GetDomain(const u32 address) {
|
||||
switch (address) {
|
||||
case REGION_PI_UNKNOWN:
|
||||
case REGION_PI_64DD_ROM:
|
||||
@@ -453,13 +453,12 @@ u8 PI::GetDomain(u32 address) {
|
||||
}
|
||||
}
|
||||
|
||||
u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
u32 PI::AccessTiming(const u8 domain, const u32 length) const {
|
||||
uint32_t cycles = 0;
|
||||
uint32_t latency = 0;
|
||||
uint32_t pulse_width = 0;
|
||||
uint32_t release = 0;
|
||||
uint32_t page_size = 0;
|
||||
uint32_t pages;
|
||||
|
||||
switch (domain) {
|
||||
case 1:
|
||||
@@ -478,7 +477,7 @@ u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
Util::panic("Unknown PI domain: {}\n", domain);
|
||||
}
|
||||
|
||||
pages = ceil((double)length / page_size);
|
||||
const uint32_t pages = ceil((double)length / page_size);
|
||||
|
||||
cycles += (14 + latency) * pages;
|
||||
cycles += (pulse_width + release) * (length / 2);
|
||||
@@ -489,7 +488,7 @@ u32 PI::AccessTiming(u8 domain, u32 length) const {
|
||||
// rdram -> cart
|
||||
template <>
|
||||
void PI::DMA<false>() {
|
||||
s32 len = rdLen + 1;
|
||||
const 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) {
|
||||
@@ -512,7 +511,7 @@ void PI::DMA<false>() {
|
||||
// cart -> rdram
|
||||
template <>
|
||||
void PI::DMA<true>() {
|
||||
s32 len = wrLen + 1;
|
||||
const 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) {
|
||||
|
||||
@@ -9,7 +9,7 @@ struct Registers;
|
||||
struct PI {
|
||||
PI(Mem &, Registers &);
|
||||
void Reset();
|
||||
auto Read(u32) const -> u32;
|
||||
[[nodiscard]] auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
|
||||
template <typename T, bool isDma>
|
||||
|
||||
@@ -85,7 +85,7 @@ FORCE_INLINE size_t GetSaveSize(SaveType saveType) {
|
||||
}
|
||||
}
|
||||
|
||||
void PIF::LoadEeprom(SaveType saveType, const std::string &path) {
|
||||
void PIF::LoadEeprom(const SaveType saveType, const std::string &path) {
|
||||
if (saveType == SAVE_EEPROM_16k || saveType == SAVE_EEPROM_4k) {
|
||||
fs::path eepromPath_ = path;
|
||||
if (!savePath.empty()) {
|
||||
@@ -134,7 +134,7 @@ void PIF::CICChallenge() {
|
||||
challenge[i * 2 + 1] = (ram[0x30 + i] >> 0) & 0x0F;
|
||||
}
|
||||
|
||||
n64_cic_nus_6105((char *)challenge, (char *)response, CHL_LEN - 2);
|
||||
n64_cic_nus_6105(reinterpret_cast<char *>(challenge), reinterpret_cast<char *>(response), CHL_LEN - 2);
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
ram[0x30 + i] = (response[i * 2] << 4) + response[i * 2 + 1];
|
||||
@@ -145,7 +145,7 @@ FORCE_INLINE u8 DataCRC(const u8 *data) {
|
||||
u8 crc = 0;
|
||||
for (int i = 0; i <= 32; i++) {
|
||||
for (int j = 7; j >= 0; j--) {
|
||||
u8 xorVal = ((crc & 0x80) != 0) ? 0x85 : 0x00;
|
||||
const u8 xorVal = ((crc & 0x80) != 0) ? 0x85 : 0x00;
|
||||
|
||||
crc <<= 1;
|
||||
if (i < 32) {
|
||||
@@ -164,27 +164,25 @@ FORCE_INLINE u8 DataCRC(const u8 *data) {
|
||||
#define BCD_ENCODE(x) (((x) / 10) << 4 | ((x) % 10))
|
||||
#define BCD_DECODE(x) (((x) >> 4) * 10 + ((x) & 15))
|
||||
|
||||
void PIF::ProcessCommands(Mem &mem) {
|
||||
u8 control = ram[63];
|
||||
void PIF::ProcessCommands(const Mem &mem) {
|
||||
const u8 control = ram[63];
|
||||
if (control & 1) {
|
||||
channel = 0;
|
||||
int i = 0;
|
||||
while (i < 63) {
|
||||
u8 *cmd = &ram[i++];
|
||||
u8 cmdlen = cmd[CMD_LEN] & 0x3F;
|
||||
|
||||
if (cmdlen == 0 || cmdlen == 0x3D) {
|
||||
if (const u8 cmdlen = cmd[CMD_LEN] & 0x3F; cmdlen == 0 || cmdlen == 0x3D) {
|
||||
channel++;
|
||||
} else if (cmdlen == 0x3E) {
|
||||
break;
|
||||
} else if (cmdlen == 0x3F) {
|
||||
continue;
|
||||
} else {
|
||||
u8 r = ram[i++];
|
||||
const u8 r = ram[i++];
|
||||
if (r == 0xFE) {
|
||||
break;
|
||||
}
|
||||
u8 reslen = r & 0x3F;
|
||||
const u8 reslen = r & 0x3F;
|
||||
u8 *res = &ram[i + cmdlen];
|
||||
|
||||
switch (cmd[CMD_IDX]) {
|
||||
@@ -225,7 +223,7 @@ void PIF::ProcessCommands(Mem &mem) {
|
||||
case 2:
|
||||
{
|
||||
auto now = std::time(nullptr);
|
||||
auto *gmtm = gmtime(&now);
|
||||
const auto *gmtm = gmtime(&now);
|
||||
res[0] = BCD_ENCODE(gmtm->tm_sec);
|
||||
res[1] = BCD_ENCODE(gmtm->tm_min);
|
||||
res[2] = BCD_ENCODE(gmtm->tm_hour) + 0x80;
|
||||
@@ -321,7 +319,7 @@ void PIF::MempakWrite(u8 *cmd, u8 *res) {
|
||||
void PIF::EepromRead(const u8 *cmd, u8 *res, const Mem &mem) const {
|
||||
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
|
||||
if (channel == 4) {
|
||||
u8 offset = cmd[3];
|
||||
const u8 offset = cmd[3];
|
||||
if ((offset * 8) >= GetSaveSize(mem.saveType)) {
|
||||
Util::panic("Out of range EEPROM read! offset: {:02X}", offset);
|
||||
}
|
||||
@@ -335,7 +333,7 @@ void PIF::EepromRead(const u8 *cmd, u8 *res, const Mem &mem) const {
|
||||
void PIF::EepromWrite(const u8 *cmd, u8 *res, const Mem &mem) {
|
||||
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
|
||||
if (channel == 4) {
|
||||
u8 offset = cmd[3];
|
||||
const u8 offset = cmd[3];
|
||||
if ((offset * 8) >= GetSaveSize(mem.saveType)) {
|
||||
Util::panic("Out of range EEPROM write! offset: {:02X}", offset);
|
||||
}
|
||||
@@ -348,7 +346,7 @@ void PIF::EepromWrite(const u8 *cmd, u8 *res, const Mem &mem) {
|
||||
}
|
||||
}
|
||||
|
||||
void PIF::HLE(bool pal, CICType cicType) {
|
||||
void PIF::HLE(const bool pal, const CICType cicType) const {
|
||||
mem.Write<u32>(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
|
||||
|
||||
switch (cicType) {
|
||||
@@ -609,13 +607,13 @@ void PIF::HLE(bool pal, CICType cicType) {
|
||||
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());
|
||||
regs.SetPC32(s32(0xA4000040));
|
||||
std::copy_n(mem.rom.cart.begin(), 0x1000, mem.mmio.rsp.dmem.begin());
|
||||
regs.SetPC32(static_cast<s32>(0xA4000040));
|
||||
}
|
||||
|
||||
void PIF::Execute() {
|
||||
CICType cicType = mem.rom.cicType;
|
||||
bool pal = mem.rom.pal;
|
||||
void PIF::Execute() const {
|
||||
const CICType cicType = mem.rom.cicType;
|
||||
const bool pal = mem.rom.pal;
|
||||
mem.Write<u32>(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
|
||||
switch (cicType) {
|
||||
case UNKNOWN_CIC_TYPE:
|
||||
|
||||
@@ -184,11 +184,11 @@ struct PIF {
|
||||
void Reset();
|
||||
void MaybeLoadMempak();
|
||||
void LoadEeprom(SaveType, const std::string &);
|
||||
void ProcessCommands(Mem &);
|
||||
void ProcessCommands(const Mem &);
|
||||
void InitDevices(SaveType);
|
||||
void CICChallenge();
|
||||
void Execute();
|
||||
void HLE(bool pal, CICType cicType);
|
||||
void Execute() const;
|
||||
void HLE(bool pal, CICType cicType) const;
|
||||
bool ReadButtons(u8 *);
|
||||
void ControllerID(u8 *) const;
|
||||
void MempakRead(const u8 *, u8 *);
|
||||
@@ -214,26 +214,26 @@ struct PIF {
|
||||
Mem &mem;
|
||||
Registers ®s;
|
||||
|
||||
FORCE_INLINE u8 Read(u32 addr) {
|
||||
[[nodiscard]] FORCE_INLINE u8 Read(u32 addr) const {
|
||||
addr &= 0x7FF;
|
||||
if (addr < 0x7c0)
|
||||
return bootrom[addr];
|
||||
return ram[addr & PIF_RAM_DSIZE];
|
||||
}
|
||||
|
||||
FORCE_INLINE void Write(u32 addr, u8 val) {
|
||||
FORCE_INLINE void Write(u32 addr, const u8 val) {
|
||||
addr &= 0x7FF;
|
||||
if (addr < 0x7c0)
|
||||
return;
|
||||
ram[addr & PIF_RAM_DSIZE] = val;
|
||||
}
|
||||
|
||||
FORCE_INLINE AccessoryType GetAccessoryType() const {
|
||||
[[nodiscard]] FORCE_INLINE AccessoryType GetAccessoryType() const {
|
||||
if (channel >= 4 || joybusDevices[channel].type != JOYBUS_CONTROLLER) {
|
||||
return ACCESSORY_NONE;
|
||||
} else {
|
||||
return joybusDevices[channel].accessoryType;
|
||||
}
|
||||
|
||||
return joybusDevices[channel].accessoryType;
|
||||
}
|
||||
};
|
||||
} // namespace n64
|
||||
|
||||
@@ -96,7 +96,7 @@ bool PIF::ReadButtons(u8 *res) {
|
||||
case JOYBUS_16KB_EEPROM:
|
||||
case JOYBUS_CONTROLLER:
|
||||
if (movie.IsLoaded()) {
|
||||
Controller controller = movie.NextInputs();
|
||||
const Controller controller = movie.NextInputs();
|
||||
res[0] = controller.byte1;
|
||||
res[1] = controller.byte2;
|
||||
res[2] = controller.joyX;
|
||||
|
||||
@@ -47,7 +47,7 @@ static_assert(sizeof(TASMovieHeader) == 1024);
|
||||
|
||||
struct MupenMovie {
|
||||
MupenMovie() = default;
|
||||
MupenMovie(const fs::path &);
|
||||
explicit MupenMovie(const fs::path &);
|
||||
bool Load(const fs::path &);
|
||||
void Reset();
|
||||
n64::Controller NextInputs();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <core/mmio/SI.hpp>
|
||||
|
||||
namespace n64 {
|
||||
SI::SI(Mem &mem, Registers ®s) : mem(mem), regs(regs), pif(mem, regs) { Reset(); }
|
||||
SI::SI(Mem &mem, Registers ®s) : pif(mem, regs), mem(mem), regs(regs) { Reset(); }
|
||||
|
||||
void SI::Reset() {
|
||||
status.raw = 0;
|
||||
|
||||
@@ -27,7 +27,7 @@ struct SI {
|
||||
u32 pifAddr{};
|
||||
bool toDram = false;
|
||||
|
||||
auto Read(u32) const -> u32;
|
||||
[[nodiscard]] auto Read(u32) const -> u32;
|
||||
void Write(u32, u32);
|
||||
template <bool toDram>
|
||||
void DMA();
|
||||
|
||||
@@ -24,7 +24,7 @@ void VI::Reset() {
|
||||
swaps = {};
|
||||
}
|
||||
|
||||
u32 VI::Read(u32 paddr) const {
|
||||
u32 VI::Read(const u32 paddr) const {
|
||||
switch (paddr) {
|
||||
case 0x04400000:
|
||||
return status.raw;
|
||||
@@ -59,7 +59,7 @@ u32 VI::Read(u32 paddr) const {
|
||||
}
|
||||
}
|
||||
|
||||
void VI::Write(u32 paddr, u32 val) {
|
||||
void VI::Write(const u32 paddr, const u32 val) {
|
||||
switch (paddr) {
|
||||
case 0x04400000:
|
||||
status.raw = val;
|
||||
@@ -67,7 +67,7 @@ void VI::Write(u32 paddr, u32 val) {
|
||||
break;
|
||||
case 0x04400004:
|
||||
{
|
||||
u32 masked = val & 0xFFFFFF;
|
||||
const u32 masked = val & 0xFFFFFF;
|
||||
if (origin != masked) {
|
||||
swaps++;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ void Cop0::Reset() {
|
||||
openbus = {};
|
||||
}
|
||||
|
||||
u32 Cop0::GetReg32(u8 addr) {
|
||||
u32 Cop0::GetReg32(const u8 addr) {
|
||||
switch (addr) {
|
||||
case COP0_REG_INDEX:
|
||||
return index.raw & INDEX_MASK;
|
||||
@@ -108,7 +108,7 @@ u32 Cop0::GetReg32(u8 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
u64 Cop0::GetReg64(u8 addr) const {
|
||||
u64 Cop0::GetReg64(const u8 addr) const {
|
||||
switch (addr) {
|
||||
case COP0_REG_ENTRYLO0:
|
||||
return entryLo0.raw;
|
||||
@@ -145,7 +145,7 @@ u64 Cop0::GetReg64(u8 addr) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Cop0::SetReg32(u8 addr, u32 value) {
|
||||
void Cop0::SetReg32(const u8 addr, const u32 value) {
|
||||
openbus = value & 0xFFFFFFFF;
|
||||
switch (addr) {
|
||||
case COP0_REG_INDEX:
|
||||
@@ -241,7 +241,7 @@ void Cop0::SetReg32(u8 addr, u32 value) {
|
||||
}
|
||||
}
|
||||
|
||||
void Cop0::SetReg64(u8 addr, u64 value) {
|
||||
void Cop0::SetReg64(const u8 addr, const u64 value) {
|
||||
openbus = value;
|
||||
switch (addr) {
|
||||
case COP0_REG_ENTRYLO0:
|
||||
@@ -286,24 +286,23 @@ void Cop0::SetReg64(u8 addr, u64 value) {
|
||||
}
|
||||
}
|
||||
|
||||
static FORCE_INLINE u64 getVPN(u64 addr, u64 pageMask) {
|
||||
u64 mask = pageMask | 0x1fff;
|
||||
u64 vpn = (addr & 0xFFFFFFFFFF) | ((addr >> 22) & 0x30000000000);
|
||||
static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) {
|
||||
const u64 mask = pageMask | 0x1fff;
|
||||
const u64 vpn = addr & 0xFFFFFFFFFF | addr >> 22 & 0x30000000000;
|
||||
|
||||
return vpn & ~mask;
|
||||
}
|
||||
|
||||
TLBEntry *Cop0::TLBTryMatch(u64 vaddr, int *match) {
|
||||
TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int *match) const {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
TLBEntry *entry = ®s.cop0.tlb[i];
|
||||
if (entry->initialized) {
|
||||
u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw);
|
||||
u64 vaddr_vpn = getVPN(vaddr, entry->pageMask.raw);
|
||||
if (TLBEntry *entry = ®s.cop0.tlb[i]; entry->initialized) {
|
||||
const u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw);
|
||||
const u64 vaddr_vpn = getVPN(vaddr, entry->pageMask.raw);
|
||||
|
||||
bool vpn_match = entry_vpn == vaddr_vpn;
|
||||
bool asid_match = entry->global || (regs.cop0.entryHi.asid == entry->entryHi.asid);
|
||||
const bool vpn_match = entry_vpn == vaddr_vpn;
|
||||
|
||||
if (vpn_match && asid_match) {
|
||||
if (const bool asid_match = entry->global || regs.cop0.entryHi.asid == entry->entryHi.asid;
|
||||
vpn_match && asid_match) {
|
||||
if (match) {
|
||||
*match = i;
|
||||
}
|
||||
@@ -315,15 +314,15 @@ TLBEntry *Cop0::TLBTryMatch(u64 vaddr, int *match) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match) {
|
||||
TLBEntry *entry = TLBTryMatch(vaddr, match);
|
||||
bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr, int *match) const {
|
||||
const TLBEntry *entry = TLBTryMatch(vaddr, match);
|
||||
if (!entry) {
|
||||
regs.cop0.tlbError = MISS;
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 mask = (entry->pageMask.mask << 12) | 0xFFF;
|
||||
u32 odd = vaddr & (mask + 1);
|
||||
const u32 mask = entry->pageMask.mask << 12 | 0xFFF;
|
||||
const u32 odd = vaddr & (mask + 1);
|
||||
u32 pfn;
|
||||
|
||||
if (!odd) {
|
||||
@@ -332,7 +331,7 @@ bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match
|
||||
return false;
|
||||
}
|
||||
|
||||
if (access_type == STORE && !entry->entryLo0.d) {
|
||||
if (accessType == STORE && !entry->entryLo0.d) {
|
||||
regs.cop0.tlbError = MODIFICATION;
|
||||
return false;
|
||||
}
|
||||
@@ -344,7 +343,7 @@ bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match
|
||||
return false;
|
||||
}
|
||||
|
||||
if (access_type == STORE && !entry->entryLo1.d) {
|
||||
if (accessType == STORE && !entry->entryLo1.d) {
|
||||
regs.cop0.tlbError = MODIFICATION;
|
||||
return false;
|
||||
}
|
||||
@@ -352,14 +351,13 @@ bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match
|
||||
pfn = entry->entryLo1.pfn;
|
||||
}
|
||||
|
||||
paddr = (pfn << 12) | (vaddr & mask);
|
||||
paddr = pfn << 12 | vaddr & mask;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool Is64BitAddressing(Cop0 &cp0, u64 addr) {
|
||||
u8 region = (addr >> 62) & 3;
|
||||
switch (region) {
|
||||
FORCE_INLINE bool Is64BitAddressing(const Cop0 &cp0, const u64 addr) {
|
||||
switch (addr >> 62 & 3) {
|
||||
case 0b00:
|
||||
return cp0.status.ux;
|
||||
case 0b01:
|
||||
@@ -371,8 +369,8 @@ FORCE_INLINE bool Is64BitAddressing(Cop0 &cp0, u64 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
void Cop0::FireException(ExceptionCode code, int cop, s64 pc) {
|
||||
bool old_exl = regs.cop0.status.exl;
|
||||
void Cop0::FireException(const ExceptionCode code, const int cop, s64 pc) const {
|
||||
const bool old_exl = regs.cop0.status.exl;
|
||||
|
||||
if (!regs.cop0.status.exl) {
|
||||
if ((regs.cop0.cause.branchDelay = regs.prevDelaySlot)) {
|
||||
@@ -424,18 +422,18 @@ void Cop0::FireException(ExceptionCode code, int cop, s64 pc) {
|
||||
regs.cop0.Update();
|
||||
}
|
||||
|
||||
void Cop0::HandleTLBException(u64 vaddr) {
|
||||
u64 vpn2 = (vaddr >> 13) & 0x7FFFF;
|
||||
u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF;
|
||||
void Cop0::HandleTLBException(const u64 vaddr) const {
|
||||
const u64 vpn2 = vaddr >> 13 & 0x7FFFF;
|
||||
const u64 xvpn2 = vaddr >> 13 & 0x7FFFFFF;
|
||||
regs.cop0.badVaddr = vaddr;
|
||||
regs.cop0.context.badvpn2 = vpn2;
|
||||
regs.cop0.xcontext.badvpn2 = xvpn2;
|
||||
regs.cop0.xcontext.r = (vaddr >> 62) & 3;
|
||||
regs.cop0.xcontext.r = vaddr >> 62 & 3;
|
||||
regs.cop0.entryHi.vpn2 = xvpn2;
|
||||
regs.cop0.entryHi.r = (vaddr >> 62) & 3;
|
||||
regs.cop0.entryHi.r = vaddr >> 62 & 3;
|
||||
}
|
||||
|
||||
ExceptionCode Cop0::GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
|
||||
ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessType accessType) {
|
||||
switch (error) {
|
||||
case NONE:
|
||||
Util::panic("Getting TLB exception with error NONE");
|
||||
@@ -448,6 +446,7 @@ ExceptionCode Cop0::GetTLBExceptionCode(TLBError error, TLBAccessType accessType
|
||||
return accessType == LOAD ? ExceptionCode::AddressErrorLoad : ExceptionCode::AddressErrorStore;
|
||||
default:
|
||||
Util::panic("Getting TLB exception for unknown error code! ({})", static_cast<u8>(error));
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,9 +466,9 @@ template void Cop0::decode<JIT>(JIT &, u32);
|
||||
|
||||
void Cop0::decodeJIT(JIT &cpu, u32 instr) {}
|
||||
|
||||
void Cop0::decodeInterp(u32 instr) {
|
||||
u8 mask_cop = (instr >> 21) & 0x1F;
|
||||
u8 mask_cop2 = instr & 0x3F;
|
||||
void Cop0::decodeInterp(const u32 instr) {
|
||||
const u8 mask_cop = instr >> 21 & 0x1F;
|
||||
const u8 mask_cop2 = instr & 0x3F;
|
||||
switch (mask_cop) {
|
||||
case 0x00:
|
||||
mfc0(instr);
|
||||
@@ -510,13 +509,17 @@ void Cop0::decodeInterp(u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
|
||||
if (regs.cop0.is64BitAddressing) [[unlikely]] {
|
||||
if (regs.cop0.kernelMode) [[likely]] {
|
||||
return MapVAddr64(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.userMode) {
|
||||
}
|
||||
|
||||
if (regs.cop0.userMode) {
|
||||
return UserMapVAddr64(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisorMode) {
|
||||
}
|
||||
|
||||
if (regs.cop0.supervisorMode) {
|
||||
Util::panic("Supervisor mode memory access, 64 bit mode");
|
||||
} else {
|
||||
Util::panic("Unknown mode! This should never happen!");
|
||||
@@ -524,9 +527,13 @@ bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
} else {
|
||||
if (regs.cop0.kernelMode) [[likely]] {
|
||||
return MapVAddr32(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.userMode) {
|
||||
}
|
||||
|
||||
if (regs.cop0.userMode) {
|
||||
return UserMapVAddr32(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisorMode) {
|
||||
}
|
||||
|
||||
if (regs.cop0.supervisorMode) {
|
||||
Util::panic("Supervisor mode memory access, 32 bit mode");
|
||||
} else {
|
||||
Util::panic("Unknown mode! This should never happen!");
|
||||
@@ -534,7 +541,7 @@ bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Cop0::UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const {
|
||||
switch (vaddr) {
|
||||
case VREGION_KUSEG:
|
||||
return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
@@ -544,8 +551,8 @@ bool Cop0::UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Cop0::MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
switch ((u32(vaddr) >> 29) & 7) {
|
||||
bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const {
|
||||
switch (u32(vaddr) >> 29 & 7) {
|
||||
case 0 ... 3:
|
||||
case 7:
|
||||
return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
@@ -561,7 +568,7 @@ bool Cop0::MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG:
|
||||
return ProbeTLB(accessType, vaddr, paddr, nullptr);
|
||||
@@ -571,7 +578,7 @@ bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG:
|
||||
case VREGION_XKSSEG:
|
||||
@@ -581,15 +588,13 @@ bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) {
|
||||
if (!regs.cop0.kernelMode) {
|
||||
Util::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
|
||||
}
|
||||
u8 high_two_bits = (vaddr >> 62) & 0b11;
|
||||
if (high_two_bits != 0b10) {
|
||||
if (const u8 high_two_bits = (vaddr >> 62) & 0b11; high_two_bits != 0b10) {
|
||||
Util::panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
|
||||
}
|
||||
u8 subsegment = (vaddr >> 59) & 0b11;
|
||||
const u8 subsegment = (vaddr >> 59) & 0b11;
|
||||
bool cached = subsegment != 2; // do something with this eventually
|
||||
// If any bits in the range of 58:32 are set, the address is invalid.
|
||||
bool valid = (vaddr & 0x07FFFFFF00000000) == 0;
|
||||
if (!valid) {
|
||||
if (const bool valid = (vaddr & 0x07FFFFFF00000000) == 0; !valid) {
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -240,9 +240,9 @@ struct Cop0 {
|
||||
s64 openbus{};
|
||||
template <class T>
|
||||
void decode(T &, u32);
|
||||
FORCE_INLINE u32 GetRandom() {
|
||||
[[nodiscard]] FORCE_INLINE u32 GetRandom() const {
|
||||
u32 val = rand();
|
||||
auto wired_ = GetWired();
|
||||
const auto wired_ = GetWired();
|
||||
u32 lower, upper;
|
||||
if (wired_ > 31) {
|
||||
lower = 0;
|
||||
@@ -257,7 +257,7 @@ struct Cop0 {
|
||||
}
|
||||
|
||||
FORCE_INLINE void Update() {
|
||||
bool exception = status.exl || status.erl;
|
||||
const bool exception = status.exl || status.erl;
|
||||
|
||||
kernelMode = exception || status.ksu == 0;
|
||||
supervisorMode = !exception && status.ksu == 1;
|
||||
@@ -267,17 +267,17 @@ struct Cop0 {
|
||||
|
||||
enum TLBAccessType { LOAD, STORE };
|
||||
|
||||
bool ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match);
|
||||
void FireException(ExceptionCode code, int cop, s64 pc);
|
||||
bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr, int *match) const;
|
||||
void FireException(ExceptionCode code, int cop, s64 pc) const;
|
||||
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
|
||||
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const;
|
||||
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const;
|
||||
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const;
|
||||
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const;
|
||||
|
||||
TLBEntry *TLBTryMatch(u64 vaddr, int *match);
|
||||
void HandleTLBException(u64 vaddr);
|
||||
ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType access_type);
|
||||
TLBEntry *TLBTryMatch(u64 vaddr, int *match) const;
|
||||
void HandleTLBException(u64 vaddr) const;
|
||||
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);
|
||||
|
||||
private:
|
||||
Registers ®s;
|
||||
|
||||
@@ -26,9 +26,9 @@ template void Cop1::decode<JIT>(JIT &, u32);
|
||||
|
||||
void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
||||
|
||||
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||
u8 mask_fun = instr & 0x3F;
|
||||
u8 mask_branch = (instr >> 16) & 0x1F;
|
||||
const u8 mask_sub = (instr >> 21) & 0x1F;
|
||||
const u8 mask_fun = instr & 0x3F;
|
||||
const u8 mask_branch = (instr >> 16) & 0x1F;
|
||||
switch (mask_sub) {
|
||||
// 000r_rccc
|
||||
case 0x00:
|
||||
|
||||
@@ -131,9 +131,9 @@ struct Cop1 {
|
||||
template <typename T>
|
||||
bool CheckResult(T &);
|
||||
template <typename T>
|
||||
bool CheckArg(T &);
|
||||
bool CheckArg(T);
|
||||
template <typename T>
|
||||
bool CheckArgs(T &, T &);
|
||||
bool CheckArgs(T, T);
|
||||
template <typename T>
|
||||
bool isqnan(T);
|
||||
|
||||
@@ -141,9 +141,9 @@ struct Cop1 {
|
||||
bool XORDERED(T fs, T ft);
|
||||
|
||||
template <typename T>
|
||||
bool CheckCVTArg(float &f);
|
||||
bool CheckCVTArg(float f);
|
||||
template <typename T>
|
||||
bool CheckCVTArg(double &f);
|
||||
bool CheckCVTArg(double f);
|
||||
|
||||
template <bool cvt = false>
|
||||
bool TestExceptions();
|
||||
@@ -156,11 +156,11 @@ struct Cop1 {
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
auto FGR_T(Cop0Status &, u32) -> T &;
|
||||
auto FGR_T(const Cop0Status &, u32) -> T &;
|
||||
template <typename T>
|
||||
auto FGR_S(Cop0Status &, u32) -> T &;
|
||||
auto FGR_S(const Cop0Status &, u32) -> T &;
|
||||
template <typename T>
|
||||
auto FGR_D(Cop0Status &, u32) -> T &;
|
||||
auto FGR_D(const Cop0Status &, u32) -> T &;
|
||||
void decodeInterp(Interpreter &, u32);
|
||||
void decodeJIT(JIT &, u32);
|
||||
void absd(u32 instr);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void Cop0::mtc0(u32 instr) { SetReg32(RD(instr), regs.Read<u32>(RT(instr))); }
|
||||
void Cop0::mtc0(const u32 instr) { SetReg32(RD(instr), regs.Read<u32>(RT(instr))); }
|
||||
|
||||
void Cop0::dmtc0(u32 instr) { SetReg64(RD(instr), regs.Read<u64>(RT(instr))); }
|
||||
void Cop0::dmtc0(const u32 instr) { SetReg64(RD(instr), regs.Read<u64>(RT(instr))); }
|
||||
|
||||
void Cop0::mfc0(u32 instr) { regs.Write(RT(instr), s32(GetReg32(RD(instr)))); }
|
||||
void Cop0::mfc0(const u32 instr) { regs.Write(RT(instr), s32(GetReg32(RD(instr)))); }
|
||||
|
||||
void Cop0::dmfc0(u32 instr) const { regs.Write(RT(instr), s64(GetReg64(RD(instr)))); }
|
||||
void Cop0::dmfc0(const u32 instr) const { regs.Write(RT(instr), s64(GetReg64(RD(instr)))); }
|
||||
|
||||
void Cop0::eret() {
|
||||
if (status.erl) {
|
||||
@@ -29,7 +29,7 @@ void Cop0::tlbr() {
|
||||
Util::panic("TLBR with TLB index {}", index.i);
|
||||
}
|
||||
|
||||
TLBEntry entry = tlb[index.i];
|
||||
const TLBEntry entry = tlb[index.i];
|
||||
|
||||
entryHi.raw = entry.entryHi.raw;
|
||||
entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
||||
@@ -40,10 +40,10 @@ void Cop0::tlbr() {
|
||||
pageMask.raw = entry.pageMask.raw;
|
||||
}
|
||||
|
||||
void Cop0::tlbw(int index_) {
|
||||
void Cop0::tlbw(const int index_) {
|
||||
PageMask page_mask{};
|
||||
page_mask = pageMask;
|
||||
u32 top = page_mask.mask & 0xAAA;
|
||||
const u32 top = page_mask.mask & 0xAAA;
|
||||
page_mask.mask = top | (top >> 1);
|
||||
|
||||
if (index_ >= 32) {
|
||||
@@ -63,8 +63,7 @@ void Cop0::tlbw(int index_) {
|
||||
|
||||
void Cop0::tlbp() {
|
||||
int match = -1;
|
||||
TLBEntry *entry = TLBTryMatch(entryHi.raw, &match);
|
||||
if (entry && match >= 0) {
|
||||
if (const TLBEntry *entry = TLBTryMatch(entryHi.raw, &match); entry && match >= 0) {
|
||||
index.raw = match;
|
||||
} else {
|
||||
index.raw = 0;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,10 +4,8 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
FORCE_INLINE void special(MI &mi, Registers ®s, RSP &rsp, u32 instr) {
|
||||
u8 mask = instr & 0x3f;
|
||||
// Util::print("rsp special {:02X}", mask);
|
||||
switch (mask) {
|
||||
FORCE_INLINE void special(MI &mi, RSP &rsp, const u32 instr) {
|
||||
switch (const u8 mask = instr & 0x3f) {
|
||||
case 0x00:
|
||||
if (instr != 0) {
|
||||
rsp.sll(instr);
|
||||
@@ -73,31 +71,27 @@ FORCE_INLINE void special(MI &mi, Registers ®s, RSP &rsp, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void regimm(RSP &rsp, u32 instr) {
|
||||
u8 mask = ((instr >> 16) & 0x1F);
|
||||
// Util::print("rsp regimm {:02X}", mask);
|
||||
switch (mask) {
|
||||
FORCE_INLINE void regimm(RSP &rsp, const u32 instr) {
|
||||
switch (const u8 mask = instr >> 16 & 0x1F) {
|
||||
case 0x00:
|
||||
rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0);
|
||||
rsp.b(instr, rsp.gpr[RS(instr)] < 0);
|
||||
break;
|
||||
case 0x01:
|
||||
rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0);
|
||||
rsp.b(instr, rsp.gpr[RS(instr)] >= 0);
|
||||
break;
|
||||
case 0x10:
|
||||
rsp.blink(instr, (s32)rsp.gpr[RS(instr)] < 0);
|
||||
rsp.blink(instr, rsp.gpr[RS(instr)] < 0);
|
||||
break;
|
||||
case 0x11:
|
||||
rsp.blink(instr, (s32)rsp.gpr[RS(instr)] >= 0);
|
||||
rsp.blink(instr, rsp.gpr[RS(instr)] >= 0);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unhandled RSP regimm instruction ({:05b})", mask);
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void lwc2(RSP &rsp, u32 instr) {
|
||||
u8 mask = (instr >> 11) & 0x1F;
|
||||
// Util::print("lwc2 {:02X}", mask);
|
||||
switch (mask) {
|
||||
FORCE_INLINE void lwc2(RSP &rsp, const u32 instr) {
|
||||
switch (const u8 mask = instr >> 11 & 0x1F) {
|
||||
case 0x00:
|
||||
rsp.lbv(instr);
|
||||
break;
|
||||
@@ -138,10 +132,8 @@ FORCE_INLINE void lwc2(RSP &rsp, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void swc2(RSP &rsp, u32 instr) {
|
||||
u8 mask = (instr >> 11) & 0x1F;
|
||||
// Util::print("swc2 {:02X}", mask);
|
||||
switch (mask) {
|
||||
FORCE_INLINE void swc2(RSP &rsp, const u32 instr) {
|
||||
switch (const u8 mask = instr >> 11 & 0x1F) {
|
||||
case 0x00:
|
||||
rsp.sbv(instr);
|
||||
break;
|
||||
@@ -183,13 +175,11 @@ FORCE_INLINE void swc2(RSP &rsp, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void cop2(RSP &rsp, u32 instr) {
|
||||
u8 mask = instr & 0x3F;
|
||||
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||
// Util::print("Cop2 {:02X}", mask);
|
||||
switch (mask) {
|
||||
FORCE_INLINE void cop2(RSP &rsp, const u32 instr) {
|
||||
const u8 mask_sub = instr >> 21 & 0x1F;
|
||||
switch (const u8 mask = instr & 0x3F) {
|
||||
case 0x00:
|
||||
if ((instr >> 25) & 1) {
|
||||
if (instr >> 25 & 1) {
|
||||
rsp.vmulf(instr);
|
||||
} else {
|
||||
switch (mask_sub) {
|
||||
@@ -355,14 +345,13 @@ FORCE_INLINE void cop2(RSP &rsp, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE void cop0(Registers ®s, Mem &mem, u32 instr) {
|
||||
u8 mask = (instr >> 21) & 0x1F;
|
||||
FORCE_INLINE void cop0(Mem &mem, const u32 instr) {
|
||||
MMIO &mmio = mem.mmio;
|
||||
RSP &rsp = mmio.rsp;
|
||||
RDP &rdp = mmio.rdp;
|
||||
// Util::print("Cop0 {:02X}", mask);
|
||||
|
||||
if ((instr & 0x7FF) == 0) {
|
||||
switch (mask) {
|
||||
switch (const u8 mask = instr >> 21 & 0x1F) {
|
||||
case 0x00:
|
||||
rsp.mfc0(rdp, instr);
|
||||
break;
|
||||
@@ -377,14 +366,12 @@ FORCE_INLINE void cop0(Registers ®s, Mem &mem, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
void RSP::Exec(u32 instr) {
|
||||
u8 mask = (instr >> 26) & 0x3F;
|
||||
void RSP::Exec(const u32 instr) {
|
||||
MMIO &mmio = mem.mmio;
|
||||
MI &mi = mmio.mi;
|
||||
// Util::print("RSP {:02X}", mask);
|
||||
switch (mask) {
|
||||
switch (const u8 mask = instr >> 26 & 0x3F) {
|
||||
case 0x00:
|
||||
special(mi, regs, *this, instr);
|
||||
special(mi, *this, instr);
|
||||
break;
|
||||
case 0x01:
|
||||
regimm(*this, instr);
|
||||
@@ -396,16 +383,16 @@ void RSP::Exec(u32 instr) {
|
||||
jal(instr);
|
||||
break;
|
||||
case 0x04:
|
||||
b(instr, (s32)gpr[RT(instr)] == (s32)gpr[RS(instr)]);
|
||||
b(instr, gpr[RT(instr)] == gpr[RS(instr)]);
|
||||
break;
|
||||
case 0x05:
|
||||
b(instr, (s32)gpr[RT(instr)] != (s32)gpr[RS(instr)]);
|
||||
b(instr, gpr[RT(instr)] != gpr[RS(instr)]);
|
||||
break;
|
||||
case 0x06:
|
||||
b(instr, (s32)gpr[RS(instr)] <= 0);
|
||||
b(instr, gpr[RS(instr)] <= 0);
|
||||
break;
|
||||
case 0x07:
|
||||
b(instr, (s32)gpr[RS(instr)] > 0);
|
||||
b(instr, gpr[RS(instr)] > 0);
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
@@ -430,7 +417,7 @@ void RSP::Exec(u32 instr) {
|
||||
lui(instr);
|
||||
break;
|
||||
case 0x10:
|
||||
cop0(regs, mem, instr);
|
||||
cop0(mem, instr);
|
||||
break;
|
||||
case 0x12:
|
||||
cop2(*this, instr);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user