From b79c8694151e82699fd7ada8da412bee5c9bfe45 Mon Sep 17 00:00:00 2001 From: CocoSimone Date: Sat, 1 Oct 2022 14:45:43 +0200 Subject: [PATCH] Add support for different CIC chips --- src/frontend/imgui/Window.cpp | 4 +- src/n64/Core.cpp | 8 +- src/n64/Core.hpp | 3 +- src/n64/core/Mem.cpp | 14 +- src/n64/core/Mem.hpp | 50 +++++++- src/n64/core/cpu/Registers.cpp | 8 -- src/n64/core/mmio/MI.cpp | 2 +- src/n64/core/mmio/PIF.cpp | 205 ++++++++++++++++++++++++++++++ src/n64/core/mmio/PIF.hpp | 24 ++++ src/n64/core/rsp/instructions.cpp | 20 ++- src/util.hpp | 6 +- 11 files changed, 317 insertions(+), 27 deletions(-) diff --git a/src/frontend/imgui/Window.cpp b/src/frontend/imgui/Window.cpp index c0c3ba1c..3fcedf89 100644 --- a/src/frontend/imgui/Window.cpp +++ b/src/frontend/imgui/Window.cpp @@ -148,10 +148,10 @@ ImDrawData* Window::Present(n64::Core& core) { void Window::LoadROM(n64::Core& core, const std::string &path) { if(!path.empty()) { - u32 crc = core.LoadROM(path); + n64::CartInfo cartInfo = core.LoadROM(path); std::ifstream gameDbFile("resources/game_db.json"); json gameDb = json::parse(gameDbFile); - auto entry = gameDb[fmt::format("{:08x}", crc)]["name"]; + auto entry = gameDb[fmt::format("{:08x}", cartInfo.crc)]["name"]; std::string name{}; if(!entry.empty()) { name = entry.get(); diff --git a/src/n64/Core.cpp b/src/n64/Core.cpp index 9db00409..09d3ddf8 100644 --- a/src/n64/Core.cpp +++ b/src/n64/Core.cpp @@ -16,13 +16,17 @@ void Core::Stop() { romLoaded = false; } -u32 Core::LoadROM(const std::string& rom_) { +CartInfo Core::LoadROM(const std::string& rom_) { rom = rom_; cpu.Reset(); mem.Reset(); pause = false; romLoaded = true; - return mem.LoadROM(rom); + + CartInfo cartInfo = mem.LoadROM(rom); + DoPIFHLE(mem, cpu.regs, cartInfo); + + return cartInfo; } void Core::Run(Window& window, float volumeL, float volumeR) { diff --git a/src/n64/Core.hpp b/src/n64/Core.hpp index a09b5568..734acf97 100644 --- a/src/n64/Core.hpp +++ b/src/n64/Core.hpp @@ -5,12 +5,13 @@ #include struct Window; + namespace n64 { struct Core { ~Core() { Stop(); } Core(); void Stop(); - u32 LoadROM(const std::string&); + CartInfo LoadROM(const std::string&); void Run(Window&, float volumeL, float volumeR); void UpdateController(const u8*); void TogglePause() { pause = !pause; } diff --git a/src/n64/core/Mem.cpp b/src/n64/core/Mem.cpp index 3a9739a4..2ab02fef 100644 --- a/src/n64/core/Mem.cpp +++ b/src/n64/core/Mem.cpp @@ -16,7 +16,7 @@ void Mem::Reset() { mmio.Reset(); } -u32 Mem::LoadROM(const std::string& filename) { +CartInfo Mem::LoadROM(const std::string& filename) { std::ifstream file(filename, std::ios::binary); file.unsetf(std::ios::skipws); @@ -36,14 +36,16 @@ u32 Mem::LoadROM(const std::string& filename) { file.close(); - u32 crc = 0; - util::SwapN64Rom(crc, sizeAdjusted, cart.data()); + CartInfo result{}; + + u32 cicChecksum; + util::SwapN64Rom(sizeAdjusted, cart.data(), result.crc, cicChecksum); memcpy(mmio.rsp.dmem, cart.data(), 0x1000); - u32 rdram_size = RDRAM_SIZE; - memcpy(&mmio.rdp.dram[0x318], &rdram_size, sizeof(u32)); + SetCICType(result.cicType, cicChecksum); + result.isPAL = IsROMPAL(); - return crc; + return result; } template diff --git a/src/n64/core/Mem.hpp b/src/n64/core/Mem.hpp index 127c2855..9fa71591 100644 --- a/src/n64/core/Mem.hpp +++ b/src/n64/core/Mem.hpp @@ -7,11 +7,18 @@ namespace n64 { struct Registers; + +struct CartInfo { + bool isPAL; + u32 cicType; + u32 crc; +}; + struct Mem { ~Mem() = default; Mem(); void Reset(); - u32 LoadROM(const std::string&); + CartInfo LoadROM(const std::string&); [[nodiscard]] auto GetRDRAM() -> u8* { return mmio.rdp.dram.data(); } @@ -46,6 +53,47 @@ private: u8 pifBootrom[PIF_BOOTROM_SIZE]{}; u8 isviewer[ISVIEWER_SIZE]{}; size_t romMask; + + void SetCICType(u32& cicType, u32 checksum) { + switch(checksum) { + case 0xEC8B1325: // 7102 + cicType = CIC_NUS_7102; + case 0x1DEB51A9: // 6101 + cicType = CIC_NUS_6101; + break; + + case 0xC08E5BD6: + cicType = CIC_NUS_6102_7101; + break; + + case 0x03B8376A: + cicType = CIC_NUS_6103_7103; + break; + + case 0xCF7F41DC: + cicType = CIC_NUS_6105_7105; + break; + + case 0xD1059C6A: + cicType = CIC_NUS_6106_7106; + break; + + default: + util::warn("Could not determine CIC TYPE! Checksum: {:08X} is unknown!\n", checksum); + cicType = UNKNOWN_CIC_TYPE; + break; + } + } + + bool IsROMPAL() { + static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'}; + for (int i = 0; i < 8; i++) { + if (cart[0x3e] == pal_codes[i]) { + return true; + } + } + return false; + } }; template diff --git a/src/n64/core/cpu/Registers.cpp b/src/n64/core/cpu/Registers.cpp index f880c7f8..83a49f76 100644 --- a/src/n64/core/cpu/Registers.cpp +++ b/src/n64/core/cpu/Registers.cpp @@ -12,14 +12,6 @@ void Registers::Reset() { oldPC = (s64)0xFFFFFFFFA4000040; pc = oldPC; nextPC = pc + 4; - lo = 0; - hi = 0; - gpr[11] = (s64)0xFFFFFFFFA4000040; - gpr[20] = 0x0000000000000001; - gpr[22] = 0x000000000000003F; - gpr[29] = (s64)0xFFFFFFFFA4001FF0; - cop0.Reset(); - cop1.Reset(); } void Registers::SetPC(s64 val) { diff --git a/src/n64/core/mmio/MI.cpp b/src/n64/core/mmio/MI.cpp index 8eb85ac1..1ed347e7 100644 --- a/src/n64/core/mmio/MI.cpp +++ b/src/n64/core/mmio/MI.cpp @@ -3,7 +3,7 @@ #include #include -#define MI_VERSION_REG 0x02020102 +#define MI_VERSION_REG 0x01010101 namespace n64 { MI::MI() { diff --git a/src/n64/core/mmio/PIF.cpp b/src/n64/core/mmio/PIF.cpp index 8e8ed849..c7fd429b 100644 --- a/src/n64/core/mmio/PIF.cpp +++ b/src/n64/core/mmio/PIF.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace n64 { @@ -65,4 +66,208 @@ void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) { } } +void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { + u32 cicType = cartInfo.cicType; + bool pal = cartInfo.isPAL; + mem.Write32(regs, 0x1FC007E4, cicSeeds[cicType], regs.pc); + + switch(cicType) { + case CIC_NUS_6101: + mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + regs.gpr[2] = (s64)0xFFFFFFFFDF6445CC; + regs.gpr[3] = (s64)0xFFFFFFFFDF6445CC; + regs.gpr[4] = 0x45CC; + regs.gpr[5] = 0x73EE317A; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0xC0; + regs.gpr[10] = 0x40; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = (s64)0xFFFFFFFFC7601FAC; + regs.gpr[13] = (s64)0xFFFFFFFFC7601FAC; + regs.gpr[14] = (s64)0xFFFFFFFFB48E2ED6; + regs.gpr[15] = (s64)0xFFFFFFFFBA1A7D4B; + regs.gpr[20] = 0x0000000000000001; + regs.gpr[22] = 0x000000000000003F; + regs.gpr[23] = 0x0000000000000001; + regs.gpr[24] = 0x0000000000000002; + regs.gpr[25] = (s64)0xFFFFFFFF905F4718; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[31] = (s64)0xFFFFFFFFA4001550; + regs.lo = (s64)0xFFFFFFFFBA1A7D4B; + regs.hi = (s64)0xFFFFFFFF997EC317; + break; + case CIC_NUS_7102: + mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + regs.gpr[1] = 0x0000000000000001; + regs.gpr[2] = 0x000000001E324416; + regs.gpr[3] = 0x000000001E324416; + regs.gpr[4] = 0x0000000000004416; + regs.gpr[5] = 0x000000000EC5D9AF; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0x00000000000000C0; + regs.gpr[10] = 0x0000000000000040; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = 0x00000000495D3D7B; + regs.gpr[13] = (s64)0xFFFFFFFF8B3DFA1E; + regs.gpr[14] = 0x000000004798E4D4; + regs.gpr[15] = (s64)0xFFFFFFFFF1D30682; + regs.gpr[22] = 0x000000000000003F; + regs.gpr[23] = 0x0000000000000007; + regs.gpr[25] = 0x0000000013D05CAB; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[31] = (s64)0xFFFFFFFFA4001554; + + regs.lo = (s64)0xFFFFFFFFF1D30682; + regs.hi = 0x0000000010054A98; + break; + case CIC_NUS_6102_7101: + mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + regs.gpr[1] = 0x0000000000000001; + regs.gpr[2] = 0x000000000EBDA536; + regs.gpr[3] = 0x000000000EBDA536; + regs.gpr[4] = 0x000000000000A536; + regs.gpr[5] = (s64)0xFFFFFFFFC0F1D859; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0x00000000000000C0; + regs.gpr[10] = 0x0000000000000040; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = (s64)0xFFFFFFFFED10D0B3; + regs.gpr[13] = 0x000000001402A4CC; + regs.gpr[14] = 0x000000002DE108EA; + regs.gpr[15] = 0x000000003103E121; + regs.gpr[20] = 0x0000000000000001; + regs.gpr[25] = (s64)0xFFFFFFFF9DEBB54F; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[31] = (s64)0xFFFFFFFFA4001550; + + regs.hi = 0x000000003FC18657; + regs.lo = 0x000000003103E121; + + if (pal) { + regs.gpr[20] = 0x0000000000000000; + regs.gpr[23] = 0x0000000000000006; + regs.gpr[31] = (s64)0xFFFFFFFFA4001554; + } + break; + case CIC_NUS_6103_7103: + mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + regs.gpr[0] = 0x0000000000000000; + regs.gpr[1] = 0x0000000000000001; + regs.gpr[2] = 0x0000000049A5EE96; + regs.gpr[3] = 0x0000000049A5EE96; + regs.gpr[4] = 0x000000000000EE96; + regs.gpr[5] = (s64)0xFFFFFFFFD4646273; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0x00000000000000C0; + regs.gpr[9] = 0x0000000000000000; + regs.gpr[10] = 0x0000000000000040; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = (s64)0xFFFFFFFFCE9DFBF7; + regs.gpr[13] = (s64)0xFFFFFFFFCE9DFBF7; + 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] = (s64)0xFFFFFFFF825B21C9; + regs.gpr[26] = 0x0000000000000000; + regs.gpr[27] = 0x0000000000000000; + regs.gpr[28] = 0x0000000000000000; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[30] = 0x0000000000000000; + regs.gpr[31] = (s64)0xFFFFFFFFA4001550; + + regs.lo = 0x0000000018B63D28; + regs.hi = 0x00000000625C2BBE; + + if (pal) { + regs.gpr[20] = 0x0000000000000000; + regs.gpr[23] = 0x0000000000000006; + regs.gpr[31] = (s64)0xFFFFFFFFA4001554; + } + break; + case CIC_NUS_6105_7105: + mem.Write32(regs, 0x3F0, RDRAM_SIZE, regs.pc); + regs.gpr[2] = (s64)0xFFFFFFFFF58B0FBF; + regs.gpr[3] = (s64)0xFFFFFFFFF58B0FBF; + regs.gpr[4] = 0x0000000000000FBF; + regs.gpr[5] = (s64)0xFFFFFFFFDECAAAD1; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0x00000000000000C0; + regs.gpr[10] = 0x0000000000000040; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = (s64)0xFFFFFFFF9651F81E; + regs.gpr[13] = 0x000000002D42AAC5; + regs.gpr[14] = 0x00000000489B52CF; + regs.gpr[15] = 0x0000000056584D60; + regs.gpr[20] = 0x0000000000000001; + regs.gpr[24] = 0x0000000000000002; + regs.gpr[25] = (s64)0xFFFFFFFFCDCE565F; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[31] = (s64)0xFFFFFFFFA4001550; + + regs.lo = 0x0000000056584D60; + regs.hi = 0x000000004BE35D1F; + + if (pal) { + regs.gpr[20] = 0x0000000000000000; + regs.gpr[23] = 0x0000000000000006; + regs.gpr[31] = (s64)0xFFFFFFFFA4001554; + } + + mem.Write32(regs, 0x04001000, 0x3C0DBFC0, regs.pc); + mem.Write32(regs, 0x04001004, 0x8DA807FC, regs.pc); + mem.Write32(regs, 0x04001008, 0x25AD07C0, regs.pc); + mem.Write32(regs, 0x0400100C, 0x31080080, regs.pc); + mem.Write32(regs, 0x04001000, 0x5500FFFC, regs.pc); + mem.Write32(regs, 0x04001004, 0x3C0DBFC0, regs.pc); + mem.Write32(regs, 0x04001008, 0x8DA80024, regs.pc); + mem.Write32(regs, 0x0400100C, 0x3C0BB000, regs.pc); + break; + case CIC_NUS_6106_7106: + regs.gpr[2] = (s64)0xFFFFFFFFA95930A4; + regs.gpr[3] = (s64)0xFFFFFFFFA95930A4; + regs.gpr[4] = 0x00000000000030A4; + regs.gpr[5] = (s64)0xFFFFFFFFB04DC903; + regs.gpr[6] = (s64)0xFFFFFFFFA4001F0C; + regs.gpr[7] = (s64)0xFFFFFFFFA4001F08; + regs.gpr[8] = 0x00000000000000C0; + regs.gpr[10] = 0x0000000000000040; + regs.gpr[11] = (s64)0xFFFFFFFFA4000040; + regs.gpr[12] = (s64)0xFFFFFFFFBCB59510; + regs.gpr[13] = (s64)0xFFFFFFFFBCB59510; + regs.gpr[14] = 0x000000000CF85C13; + regs.gpr[15] = 0x000000007A3C07F4; + regs.gpr[20] = 0x0000000000000001; + regs.gpr[24] = 0x0000000000000002; + regs.gpr[25] = 0x00000000465E3F72; + regs.gpr[29] = (s64)0xFFFFFFFFA4001FF0; + regs.gpr[30] = 0x0000000000000000; + regs.gpr[31] = (s64)0xFFFFFFFFA4001550; + + regs.lo = 0x000000007A3C07F4; + regs.hi = 0x0000000023953898; + + if (pal) { + regs.gpr[20] = 0x0000000000000000; + regs.gpr[23] = 0x0000000000000006; + regs.gpr[31] = (s64)0xFFFFFFFFA4001554; + } + break; + } + + regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF; + regs.cop0.Reset(); +} + } \ No newline at end of file diff --git a/src/n64/core/mmio/PIF.hpp b/src/n64/core/mmio/PIF.hpp index 9673bbb3..200492c7 100644 --- a/src/n64/core/mmio/PIF.hpp +++ b/src/n64/core/mmio/PIF.hpp @@ -14,6 +14,30 @@ union Controller { static_assert(sizeof(Controller) == 4); struct Mem; +struct Registers; + +const u32 cicSeeds[] = { + 0x0, + 0x00043F3F, // CIC_NUS_6101 + 0x00043F3F, // CIC_NUS_7102 + 0x00003F3F, // CIC_NUS_6102_7101 + 0x0000783F, // CIC_NUS_6103_7103 + 0x0000913F, // CIC_NUS_6105_7105 + 0x0000853F, // CIC_NUS_6106_7106 +}; + +enum CICType { + UNKNOWN_CIC_TYPE, + CIC_NUS_6101, + CIC_NUS_7102, + CIC_NUS_6102_7101, + CIC_NUS_6103_7103, + CIC_NUS_6105_7105, + CIC_NUS_6106_7106 +}; + +struct CartInfo; void ProcessPIFCommands(u8*, Controller&, Mem&); +void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo); } \ No newline at end of file diff --git a/src/n64/core/rsp/instructions.cpp b/src/n64/core/rsp/instructions.cpp index 71221997..818395ac 100644 --- a/src/n64/core/rsp/instructions.cpp +++ b/src/n64/core/rsp/instructions.cpp @@ -103,9 +103,9 @@ inline VPR GetVTE(VPR vt, u8 e) { vte = Broadcast(vt, e - 4, e - 4, e - 4, e - 4, e, e, e, e); break; case 8 ... 15: { - int index = e - 8; - for (u16& i : vte.element) { - i = vt.element[index]; + int index = ELEMENT_INDEX(e - 8); + for (u16& vteE : vte.element) { + vteE = vt.element[index]; } } break; } @@ -407,7 +407,19 @@ void RSP::vabs(u32 instr) { } void RSP::vadd(u32 instr) { - util::panic("VADD!\n"); + VPR& vs = vpr[VS(instr)]; + VPR& vd = vpr[VD(instr)]; + VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); + + for(int i = 0; i < 8; i++) { + s16 vsE = vs.selement[i]; + s16 vteE = vte.selement[i]; + s32 result = vsE + vteE + (vco.l.element[i] != 0); + acc.l.element[i] = result; + vd.element[i] = clamp_signed(result); + vco.l.element[i] = 0; + vco.h.element[i] = 0; + } } void RSP::vmov(u32 instr) { diff --git a/src/util.hpp b/src/util.hpp index c88ac093..0dabbe9b 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -169,7 +169,7 @@ enum RomTypes { V64 = 0x37804012 }; -inline void SwapN64Rom(u32& crc, size_t size, u8* rom) { +inline void SwapN64Rom(size_t size, u8* rom, u32& crc, u32& cicChecksum) { RomTypes endianness; memcpy(&endianness, rom, 4); endianness = static_cast(be32toh(endianness)); @@ -180,8 +180,8 @@ inline void SwapN64Rom(u32& crc, size_t size, u8* rom) { memcpy(temp, rom, size); SwapBuffer16(size, temp); crc = crc32(0, temp, size); + cicChecksum = crc32(0, &temp[0x40], 0x9c0); free(temp); - SwapBuffer32(size, rom); SwapBuffer16(size, rom); } break; @@ -190,10 +190,12 @@ inline void SwapN64Rom(u32& crc, size_t size, u8* rom) { memcpy(temp, rom, size); SwapBuffer32(size, temp); crc = crc32(0, temp, size); + cicChecksum = crc32(0, &temp[0x40], 0x9c0); free(temp); } break; case RomTypes::Z64: crc = crc32(0, rom, size); + cicChecksum = crc32(0, &rom[0x40], 0x9c0); SwapBuffer32(size, rom); break; default: