From e253627890e144d4ce0ae01893b8d64a4b8919bf Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Tue, 27 Aug 2024 21:35:07 +0200 Subject: [PATCH] Run clangformat everywhere --- src/Discord.hpp | 42 +- src/backend/Core.cpp | 45 +- src/backend/Core.hpp | 10 +- src/backend/GameDB.cpp | 15 +- src/backend/GameDB.hpp | 374 +++--- src/backend/MemoryRegions.hpp | 70 +- src/backend/Netplay.cpp | 5 +- src/backend/Netplay.hpp | 3 +- src/backend/RomHelpers.hpp | 40 +- src/backend/Scheduler.cpp | 60 +- src/backend/Scheduler.hpp | 35 +- src/backend/core/MMIO.hpp | 15 +- src/backend/core/RCP.hpp | 70 +- src/backend/core/RDP.cpp | 122 +- src/backend/core/RDP.hpp | 59 +- src/backend/core/RSP.cpp | 8 +- src/backend/core/RSP.hpp | 163 +-- src/backend/core/RSQ.hpp | 70 +- src/backend/core/interpreter/decode.cpp | 535 ++++++--- src/backend/core/interpreter/instructions.cpp | 134 +-- src/backend/core/jit/helpers.hpp | 40 +- src/backend/core/jit/instructions.cpp | 1047 ++++++++--------- src/backend/core/mem/Flash.cpp | 171 +-- src/backend/core/mmio/AI.cpp | 77 +- src/backend/core/mmio/AI.hpp | 9 +- src/backend/core/mmio/Audio.cpp | 26 +- src/backend/core/mmio/Audio.hpp | 11 +- src/backend/core/mmio/Interrupt.cpp | 78 +- src/backend/core/mmio/MI.cpp | 120 +- src/backend/core/mmio/MI.hpp | 24 +- src/backend/core/mmio/PI.cpp | 578 +++++---- src/backend/core/mmio/PI.hpp | 15 +- src/backend/core/mmio/PIF.cpp | 759 ++++++------ src/backend/core/mmio/PIF.hpp | 152 ++- src/backend/core/mmio/PIF/Device.cpp | 156 +-- src/backend/core/mmio/PIF/MupenMovie.cpp | 45 +- src/backend/core/mmio/PIF/MupenMovie.hpp | 7 +- src/backend/core/mmio/RI.cpp | 46 +- src/backend/core/mmio/RI.hpp | 2 +- src/backend/core/mmio/SI.cpp | 99 +- src/backend/core/mmio/SI.hpp | 21 +- src/backend/core/mmio/VI.cpp | 144 ++- src/backend/core/mmio/VI.hpp | 60 +- src/backend/core/registers/Cop0.cpp | 642 ++++++---- src/backend/core/registers/Cop0.hpp | 198 ++-- src/backend/core/registers/Cop1.cpp | 418 +++++-- src/backend/core/registers/Cop1.hpp | 116 +- .../core/registers/cop/cop0instructions.cpp | 28 +- .../core/registers/cop/cop1instructions.cpp | 838 ++++++++----- src/backend/core/rsp/decode.cpp | 627 +++++++--- src/backend/core/rsp/instructions.cpp | 816 +++++++------ src/common.hpp | 12 +- src/frontend/AudioSettings.cpp | 14 +- src/frontend/AudioSettings.hpp | 16 +- src/frontend/CPUSettings.cpp | 14 +- src/frontend/CPUSettings.hpp | 12 +- src/frontend/EmuThread.cpp | 76 +- src/frontend/EmuThread.hpp | 28 +- src/frontend/InputSettings.cpp | 13 +- src/frontend/InputSettings.hpp | 18 +- src/frontend/JSONUtils.hpp | 13 +- src/frontend/KaizenQt.cpp | 25 +- src/frontend/KaizenQt.hpp | 23 +- src/frontend/MainWindow.cpp | 38 +- src/frontend/MainWindow.hpp | 14 +- src/frontend/RenderWidget.cpp | 11 +- src/frontend/RenderWidget.hpp | 65 +- src/frontend/SettingsWindow.cpp | 26 +- src/frontend/SettingsWindow.hpp | 32 +- src/frontend/main.cpp | 11 +- src/utils/File.hpp | 8 +- src/utils/FloatingPoint.hpp | 12 +- src/utils/MemoryHelpers.hpp | 98 +- src/utils/log.hpp | 70 +- 74 files changed, 5536 insertions(+), 4358 deletions(-) diff --git a/src/Discord.hpp b/src/Discord.hpp index 1148ddf5..434e3a41 100644 --- a/src/Discord.hpp +++ b/src/Discord.hpp @@ -1,31 +1,37 @@ #pragma once +#include +#include #include #include -#include namespace Util { enum State { Idling, Playing, - Paused + MovieReplay, + Paused, }; -FORCE_INLINE void UpdateRPC(State state, const std::string& game = "") { +FORCE_INLINE void UpdateRPC(State state, const std::string &game = "", const std::string &movieName = "") { DiscordRichPresence presence{}; std::string textState, textDetails; - switch(state) { - case Idling: - textDetails = "Idling"; - break; - case Playing: - textDetails = "In-game"; - textState = "Playing \"" + game + "\""; - break; - case Paused: - textDetails = "In-game"; - textState = "Playing \"" + game + "\" (Paused)"; - break; + switch (state) { + case Idling: + textDetails = "Idling"; + break; + case Playing: + textDetails = "In-game"; + textState = "Playing \"" + game + "\""; + break; + case MovieReplay: + textDetails = "In-game"; + textState = "Replaying movie \"" + movieName + "\" in \"" + game + "\""; + break; + case Paused: + textDetails = "In-game"; + textState = "Playing \"" + game + "\" (Paused)"; + break; } presence.details = textDetails.c_str(); @@ -36,7 +42,5 @@ FORCE_INLINE void UpdateRPC(State state, const std::string& game = "") { Discord_UpdatePresence(&presence); } -FORCE_INLINE void ClearRPC() { - Discord_ClearPresence(); -} -} \ No newline at end of file +FORCE_INLINE void ClearRPC() { Discord_ClearPresence(); } +} // namespace Util diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index be7018a5..b938b1de 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -1,9 +1,9 @@ #include -#include #include +#include namespace n64 { -Core::Core(ParallelRDP& parallel) : cpu(std::make_unique(parallel)) {} +Core::Core(ParallelRDP ¶llel) : cpu(std::make_unique(parallel)) {} void Core::Stop() { render = false; @@ -12,26 +12,23 @@ void Core::Stop() { cpu->Reset(); } -bool Core::LoadTAS(const fs::path &path) const { - return cpu->GetMem().mmio.si.pif.movie.Load(path); -} +bool Core::LoadTAS(const fs::path &path) const { return cpu->GetMem().mmio.si.pif.movie.Load(path); } -void Core::LoadROM(const std::string& rom_) { +void Core::LoadROM(const std::string &rom_) { pause = true; rom = rom_; cpu->Reset(); romLoaded = true; - std::string archive_types[] = {".zip",".7z",".rar",".tar"}; + std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"}; auto extension = fs::path(rom).extension().string(); - bool isArchive = std::any_of(std::begin(archive_types), std::end(archive_types), [&extension](const auto& e) { - return e == extension; - }); + bool isArchive = std::any_of(std::begin(archive_types), std::end(archive_types), + [&extension](const auto &e) { return e == extension; }); cpu->GetMem().LoadROM(isArchive, rom); GameDB::match(cpu->GetMem()); - if(cpu->GetMem().rom.gameNameDB.empty()) { + if (cpu->GetMem().rom.gameNameDB.empty()) { cpu->GetMem().rom.gameNameDB = fs::path(rom).stem(); } cpu->GetMem().mmio.vi.isPal = cpu->GetMem().IsROMPAL(); @@ -46,9 +43,9 @@ void Core::LoadROM(const std::string& rom_) { } void Core::Run(float volumeL, float volumeR) { - Mem& mem = cpu->GetMem(); - MMIO& mmio = mem.mmio; - Registers& regs = cpu->GetRegs(); + Mem &mem = cpu->GetMem(); + MMIO &mmio = mem.mmio; + Registers ®s = cpu->GetRegs(); for (int field = 0; field < mmio.vi.numFields; field++) { u32 frameCycles = 0; @@ -59,21 +56,21 @@ void Core::Run(float volumeL, float volumeR) { mmio.mi.InterruptRaise(MI::Interrupt::VI); } - for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { + for (; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { u32 taken = cpu->Step(); taken += regs.PopStalledCycles(); regs.steps += taken; - if(mmio.rsp.spStatus.halt) { + if (mmio.rsp.spStatus.halt) { regs.steps = 0; mmio.rsp.steps = 0; } else { - while(regs.steps > 2) { + while (regs.steps > 2) { mmio.rsp.steps += 2; regs.steps -= 3; } - while(mmio.rsp.steps > 0) { + while (mmio.rsp.steps > 0) { mmio.rsp.steps--; mmio.rsp.Step(); } @@ -110,14 +107,14 @@ void Core::Serialize() { void Core::Deserialize() { std::vector dVER(serialized[slot].begin(), serialized[slot].begin() + verSize); - if(dVER[0] != (KAIZEN_VERSION >> 8) - || dVER[1] != (KAIZEN_VERSION >> 4) - || dVER[2] != (KAIZEN_VERSION & 0xFF)) { + if (dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) { Util::panic("PROBLEMI!"); } - cpu->GetMem().Deserialize(std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize)); - cpu->Deserialize(std::vector(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize)); + cpu->GetMem().Deserialize( + std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize)); + cpu->Deserialize(std::vector(serialized[slot].begin() + verSize + memSize, + serialized[slot].begin() + verSize + memSize + cpuSize)); serialized[slot].erase(serialized[slot].begin(), serialized[slot].end()); } -} +} // namespace n64 diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index 52394ab8..10851087 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -8,15 +8,15 @@ struct Event; namespace n64 { struct Core { - Core(ParallelRDP&); + Core(ParallelRDP &); void Stop(); - void LoadROM(const std::string&); - bool LoadTAS(const fs::path&) const; + void LoadROM(const std::string &); + bool LoadTAS(const fs::path &) const; void Run(float volumeL, float volumeR); void Serialize(); void Deserialize(); void TogglePause() { pause = !pause; } - [[nodiscard]] VI& GetVI() const { return cpu->GetMem().mmio.vi; } + [[nodiscard]] VI &GetVI() const { return cpu->GetMem().mmio.vi; } u32 breakpoint = 0; @@ -30,4 +30,4 @@ struct Core { size_t memSize{}, cpuSize{}, verSize{}; int slot = 0; }; -} +} // namespace n64 diff --git a/src/backend/GameDB.cpp b/src/backend/GameDB.cpp index a8cde05d..4759c1d6 100644 --- a/src/backend/GameDB.cpp +++ b/src/backend/GameDB.cpp @@ -4,10 +4,10 @@ #include namespace n64 { -void GameDB::match(Mem& mem) { - ROM& rom = mem.rom; +void GameDB::match(Mem &mem) { + ROM &rom = mem.rom; bool found = false; - std::for_each(std::execution::par, std::begin(gamedb), std::end(gamedb), [&](const auto& i) { + std::for_each(std::execution::par, std::begin(gamedb), std::end(gamedb), [&](const auto &i) { bool matches_code = i.code == rom.code; bool matches_region = false; @@ -24,8 +24,9 @@ void GameDB::match(Mem& mem) { mem.rom.gameNameDB = i.name; return; } else { - Util::warn("Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has region {}", - i.name, i.regions, rom.header.countryCode[0]); + Util::warn( + "Matched code for {}, but not region! Game supposedly exists in regions [{}] but this image has region {}", + i.name, i.regions, rom.header.countryCode[0]); mem.saveType = i.saveType; mem.rom.gameNameDB = i.name; return; @@ -33,11 +34,11 @@ void GameDB::match(Mem& mem) { } }); - if(!found) { + if (!found) { Util::debug("Did not match any Game DB entries. Code: {} Region: {}", mem.rom.code, mem.rom.header.countryCode[0]); mem.rom.gameNameDB = ""; mem.saveType = SAVE_NONE; } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/GameDB.hpp b/src/backend/GameDB.hpp index 75870fa0..76a4b3b4 100644 --- a/src/backend/GameDB.hpp +++ b/src/backend/GameDB.hpp @@ -2,13 +2,7 @@ #include namespace n64 { -enum SaveType { - SAVE_NONE, - SAVE_EEPROM_4k, - SAVE_EEPROM_16k, - SAVE_FLASH_1m, - SAVE_SRAM_256k -}; +enum SaveType { SAVE_NONE, SAVE_EEPROM_4k, SAVE_EEPROM_16k, SAVE_FLASH_1m, SAVE_SRAM_256k }; struct Mem; struct GameDBEntry { @@ -19,192 +13,192 @@ struct GameDBEntry { }; namespace GameDB { -void match(Mem &mem); + void match(Mem &mem); } static const GameDBEntry gamedb[] = { - {"NNM", "E", SAVE_NONE, "Namco Museum 64"}, - {"NDM", "E", SAVE_NONE, "Doom 64"}, - {"NGN", "E", SAVE_EEPROM_4k, "GoldenEye 007"}, + {"NNM", "E", SAVE_NONE, "Namco Museum 64"}, + {"NDM", "E", SAVE_NONE, "Doom 64"}, + {"NGN", "E", SAVE_EEPROM_4k, "GoldenEye 007"}, // Copied from CEN64 with small edits: https://github.com/n64dev/cen64/blob/master/device/cart_db.c - {"CFZ", "EJ", SAVE_SRAM_256k, "F-Zero X (NTSC)"}, - {"CLB", "EJ", SAVE_EEPROM_4k, "Mario Party (NTSC)"}, - {"CP2", "J", SAVE_FLASH_1m, "Pokémon Stadium 2 (Japan)"}, - {"CPS", "J", SAVE_SRAM_256k, "Pokémon Stadium (Japan)"}, - {"CZL", "EJ", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (NTSC)"}, - {"N3D", "J", SAVE_EEPROM_16k, "Doraemon 3: Nobita no Machi SOS!"}, - {"N3H", "J", SAVE_SRAM_256k, "Ganbare! Nippon! Olympics 2000"}, - {"NA2", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 2"}, - {"NAB", "JP", SAVE_EEPROM_4k, "Air Boarder 64"}, - {"NAD", "E", SAVE_EEPROM_4k, "Worms Armageddon (USA)"}, - {"NAF", "J", SAVE_FLASH_1m, "Doubutsu no Mori"}, - {"NAG", "EJP", SAVE_EEPROM_4k, "AeroGauge"}, - {"NAL", "EJPU", SAVE_SRAM_256k, "Super Smash Bros"}, - {"NB5", "J", SAVE_SRAM_256k, "Biohazard 2"}, - {"NB6", "J", SAVE_EEPROM_4k, "Super B-Daman: Battle Phoenix 64"}, - {"NB7", "EJPU", SAVE_EEPROM_16k, "Banjo-Tooie"}, - {"NBC", "EJP", SAVE_EEPROM_4k, "Blast Corps"}, - {"NBD", "EJP", SAVE_EEPROM_4k, "Bomberman Hero"}, - {"NBH", "EP", SAVE_EEPROM_4k, "Body Harvest"}, - {"NBK", "EJP", SAVE_EEPROM_4k, "Banjo-Kazooie"}, - {"NBM", "EJP", SAVE_EEPROM_4k, "Bomberman 64"}, - {"NBN", "J", SAVE_EEPROM_4k, "Bakuretsu Muteki Bangaioh"}, - {"NBV", "EJ", SAVE_EEPROM_4k, "Bomberman 64: The Second Attack!"}, - {"NCC", "DEP", SAVE_FLASH_1m, "Command & Conquer"}, - {"NCG", "J", SAVE_EEPROM_4k, "Choro Q 64 2: Hacha-Mecha Grand Prix Race"}, - {"NCH", "EP", SAVE_EEPROM_4k, "Chopper Attack"}, - {"NCK", "E", SAVE_FLASH_1m, "NBA Courtside 2"}, - {"NCR", "EJP", SAVE_EEPROM_4k, "Penny Racers"}, - {"NCT", "EJP", SAVE_EEPROM_4k, "Chameleon Twist"}, - {"NCU", "EP", SAVE_EEPROM_4k, "Cruis'n USA"}, - {"NCW", "EP", SAVE_EEPROM_16k, "Cruis'n World"}, - {"NCX", "J", SAVE_EEPROM_4k, "Custom Robo"}, - {"NCZ", "J", SAVE_EEPROM_16k, "Custom Robo V2"}, - {"ND2", "J", SAVE_EEPROM_16k, "Doraemon 2: Nobita to Hikari no Shinden"}, - {"ND3", "J", SAVE_EEPROM_16k, "Akumajou Dracula Mokushiroku"}, - {"ND4", "J", SAVE_EEPROM_16k, "Akumajou Dracula Mokushiroku Gaiden: Legend of Cornell"}, - {"ND6", "J", SAVE_EEPROM_16k, "Densha de Go! 64"}, - {"NDA", "J", SAVE_FLASH_1m, "Derby Stallion 64"}, - {"NDK", "J", SAVE_EEPROM_4k, "Space Dynamites"}, - {"NDO", "EJP", SAVE_EEPROM_16k, "Donkey Kong 64"}, - {"NDP", "E", SAVE_FLASH_1m, "Dinosaur Planet"}, - {"NDR", "J", SAVE_EEPROM_4k, "Doraemon: Nobita to 3tsu no Seireiseki"}, - {"NDU", "EP", SAVE_EEPROM_4k, "Duck Dodgers"}, - {"NDY", "EJP", SAVE_EEPROM_4k, "Diddy Kong Racing"}, - {"NEA", "EP", SAVE_EEPROM_4k, "PGA European Tour"}, - {"NEP", "EJP", SAVE_EEPROM_16k, "Star Wars Episode I: Racer"}, - {"NER", "E", SAVE_EEPROM_4k, "AeroFighters Assault (USA)"}, - {"NEV", "J", SAVE_EEPROM_16k, "Neon Genesis Evangelion"}, - {"NF2", "P", SAVE_EEPROM_4k, "F-1 World Grand Prix II"}, - {"NFG", "E", SAVE_EEPROM_4k, "Fighter Destiny 2"}, - {"NFH", "EP", SAVE_EEPROM_4k, "Bass Hunter 64"}, - {"NFU", "EP", SAVE_EEPROM_16k, "Conker's Bad Fur Day"}, - {"NFW", "DEFJP", SAVE_EEPROM_4k, "F-1 World Grand Prix"}, - {"NFX", "EJPU", SAVE_EEPROM_4k, "Star Fox 64"}, - {"NFY", "J", SAVE_EEPROM_4k, "Kakutou Denshou: F-Cup Maniax"}, - {"NFZ", "P", SAVE_SRAM_256k, "F-Zero X (PAL)"}, - {"NG6", "J", SAVE_SRAM_256k, "Ganbare Goemon: Dero Dero Douchuu Obake Tenkomori"}, - {"NGC", "EP", SAVE_EEPROM_16k, "GT 64: Championship Edition"}, - {"NGE", "EJP", SAVE_EEPROM_4k, "GoldenEye 007"}, - {"NGL", "J", SAVE_EEPROM_4k, "Getter Love!!"}, - {"NGP", "J", SAVE_SRAM_256k, "Goemon: Mononoke Sugoroku"}, - {"NGT", "J", SAVE_EEPROM_16k, "City-Tour GP: Zen-Nihon GT Senshuken"}, - {"NGU", "J", SAVE_EEPROM_4k, "Tsumi to Batsu: Hoshi no Keishousha"}, - {"NGV", "EP", SAVE_EEPROM_4k, "Glover"}, - {"NHA", "J", SAVE_EEPROM_4k, "Bomber Man 64 (Japan)"}, - {"NHF", "J", SAVE_EEPROM_4k, "64 Hanafuda: Tenshi no Yakusoku"}, - {"NHP", "J", SAVE_EEPROM_4k, "Heiwa Pachinko World 64"}, - {"NHY", "J", SAVE_SRAM_256k, "Hybrid Heaven (Japan)"}, - {"NIB", "J", SAVE_SRAM_256k, "Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!"}, - {"NIC", "E", SAVE_EEPROM_4k, "Indy Racing 2000"}, - {"NIJ", "EP", SAVE_EEPROM_4k, "Indiana Jones and the Infernal Machine"}, - {"NIM", "J", SAVE_EEPROM_16k, "Ide Yosuke no Mahjong Juku"}, - {"NIR", "J", SAVE_EEPROM_4k, "Utchan Nanchan no Hono no Challenger: Denryuu Ira Ira Bou"}, - {"NJ5", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 5"}, - {"NJD", "E", SAVE_FLASH_1m, "Jet Force Gemini (Kiosk Demo)"}, - {"NJF", "EJP", SAVE_FLASH_1m, "Jet Force Gemini"}, - {"NJG", "J", SAVE_SRAM_256k, "Jinsei Game 64"}, - {"NJM", "EP", SAVE_EEPROM_4k, "Earthworm Jim 3D"}, - {"NK2", "EJP", SAVE_EEPROM_4k, "Snowboard Kids 2"}, - {"NK4", "EJP", SAVE_EEPROM_16k, "Kirby 64: The Crystal Shards"}, - {"NKA", "DEFJP", SAVE_EEPROM_4k, "Fighters Destiny"}, - {"NKG", "EP", SAVE_SRAM_256k, "MLB featuring Ken Griffey Jr."}, - {"NKI", "EP", SAVE_EEPROM_4k, "Killer Instinct Gold"}, - {"NKJ", "E", SAVE_FLASH_1m, "Ken Griffey Jr.'s Slugfest"}, - {"NKT", "EJP", SAVE_EEPROM_4k, "Mario Kart 64"}, - {"NLB", "P", SAVE_EEPROM_4k, "Mario Party (PAL)"}, - {"NLL", "J", SAVE_EEPROM_4k, "Last Legion UX"}, - {"NLR", "EJP", SAVE_EEPROM_4k, "Lode Runner 3D"}, - {"NM6", "E", SAVE_FLASH_1m, "Mega Man 64"}, - {"NM8", "EJP", SAVE_EEPROM_16k, "Mario Tennis"}, - {"NMF", "EJP", SAVE_SRAM_256k, "Mario Golf"}, - {"NMG", "DEP", SAVE_EEPROM_4k, "Monaco Grand Prix"}, - {"NMI", "DEFIPS", SAVE_EEPROM_4k, "Mission: Impossible"}, - {"NML", "EJP", SAVE_EEPROM_4k, "Mickey's Speedway USA"}, - {"NMO", "E", SAVE_EEPROM_4k, "Monopoly"}, - {"NMQ", "EJP", SAVE_FLASH_1m, "Paper Mario"}, - {"NMR", "EJP", SAVE_EEPROM_4k, "Multi Racing Championship"}, - {"NMS", "J", SAVE_EEPROM_4k, "Morita Shougi 64"}, - {"NMU", "E", SAVE_EEPROM_4k, "Big Mountain 2000"}, - {"NMV", "EJP", SAVE_EEPROM_16k, "Mario Party 3"}, - {"NMW", "EJP", SAVE_EEPROM_4k, "Mario Party 2"}, - {"NMX", "EJP", SAVE_EEPROM_16k, "Excitebike 64"}, - {"NN6", "E", SAVE_EEPROM_4k, "Dr. Mario 64"}, - {"NNA", "EP", SAVE_EEPROM_4k, "Star Wars Episode I: Battle for Naboo"}, - {"NNB", "EP", SAVE_EEPROM_16k, "Kobe Bryant in NBA Courtside"}, - {"NOB", "EJ", SAVE_SRAM_256k, "Ogre Battle 64: Person of Lordly Caliber"}, - {"NOS", "J", SAVE_EEPROM_4k, "64 Oozumou"}, - {"NP2", "J", SAVE_EEPROM_4k, "Chou Kuukan Nighter Pro Yakyuu King 2"}, - {"NP3", "DEFIJPS", SAVE_FLASH_1m, "Pokémon Stadium 2"}, - {"NP6", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 6"}, - {"NPA", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 2000"}, - {"NPD", "EJP", SAVE_EEPROM_16k, "Perfect Dark"}, - {"NPE", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu Basic Ban 2001"}, - {"NPF", "DEFIJPSU", SAVE_FLASH_1m, "Pokémon Snap"}, - {"NPG", "EJ", SAVE_EEPROM_4k, "Hey You, Pikachu!"}, - {"NPH", "E", SAVE_FLASH_1m, "Pokémon Snap Station (Kiosk Demo)"}, - {"NPM", "P", SAVE_SRAM_256k, "Premier Manager 64"}, - {"NPN", "DEFP", SAVE_FLASH_1m, "Pokémon Puzzle League"}, - {"NPO", "DEFIPS", SAVE_FLASH_1m, "Pokémon Stadium (USA, PAL)"}, - {"NPP", "J", SAVE_EEPROM_16k, "Parlor! Pro 64: Pachinko Jikki Simulation Game"}, - {"NPS", "J", SAVE_SRAM_256k, "Jikkyou J.League 1999: Perfect Striker 2"}, - {"NPT", "J", SAVE_EEPROM_4k, "Puyo Puyon Party"}, - {"NPW", "EJP", SAVE_EEPROM_4k, "Pilotwings 64"}, - {"NPY", "J", SAVE_EEPROM_4k, "Puyo Puyo Sun 64"}, - {"NR7", "J", SAVE_EEPROM_16k, "Robot Poncots 64: 7tsu no Umi no Caramel"}, - {"NRA", "J", SAVE_EEPROM_4k, "Rally '99"}, - {"NRC", "EJP", SAVE_EEPROM_4k, "Top Gear Overdrive"}, - {"NRE", "EP", SAVE_SRAM_256k, "Resident Evil 2"}, - {"NRH", "J", SAVE_FLASH_1m, "Rockman Dash"}, - {"NRI", "EP", SAVE_SRAM_256k, "The New Tetris"}, - {"NRS", "EJP", SAVE_EEPROM_4k, "Star Wars: Rogue Squadron"}, - {"NRZ", "EP", SAVE_EEPROM_16k, "Ridge Racer 64"}, - {"NS4", "J", SAVE_SRAM_256k, "Super Robot Taisen 64"}, - {"NS6", "EJ", SAVE_EEPROM_4k, "Star Soldier: Vanishing Earth"}, - {"NSA", "JP", SAVE_EEPROM_4k, "AeroFighters Assault (PAL, Japan)"}, - {"NSC", "EP", SAVE_EEPROM_4k, "Starshot: Space Circus Fever"}, - {"NSI", "J", SAVE_SRAM_256k, "Fushigi no Dungeon: Fuurai no Shiren 2"}, - {"NSM", "EJP", SAVE_EEPROM_4k, "Super Mario 64"}, - {"NSN", "J", SAVE_EEPROM_4k, "Snow Speeder"}, - {"NSQ", "EP", SAVE_FLASH_1m, "StarCraft 64"}, - {"NSS", "J", SAVE_EEPROM_4k, "Super Robot Spirits"}, - {"NSU", "EP", SAVE_EEPROM_4k, "Rocket: Robot on Wheels"}, - {"NSV", "EP", SAVE_EEPROM_4k, "SpaceStation Silicon Valley"}, - {"NSW", "EJP", SAVE_EEPROM_4k, "Star Wars: Shadows of the Empire"}, - {"NT3", "J", SAVE_SRAM_256k, "Toukon Road 2"}, - {"NT6", "J", SAVE_EEPROM_4k, "Tetris 64"}, - {"NT9", "EP", SAVE_FLASH_1m, "Tigger's Honey Hunt"}, - {"NTB", "J", SAVE_EEPROM_4k, "Transformers: Beast Wars Metals 64"}, - {"NTC", "J", SAVE_EEPROM_4k, "64 Trump Collection"}, - {"NTE", "AP", SAVE_SRAM_256k, "1080 Snowboarding"}, - {"NTJ", "EP", SAVE_EEPROM_4k, "Tom and Jerry in Fists of Furry"}, - {"NTM", "EJP", SAVE_EEPROM_4k, "Mischief Makers"}, - {"NTN", "EP", SAVE_EEPROM_4k, "All-Star Tennis 99"}, - {"NTP", "EP", SAVE_EEPROM_4k, "Tetrisphere"}, - {"NTR", "JP", SAVE_EEPROM_4k, "Top Gear Rally (PAL, Japan)"}, - {"NTW", "J", SAVE_EEPROM_4k, "64 de Hakken!! Tamagotchi"}, - {"NTX", "EP", SAVE_EEPROM_4k, "Taz Express"}, - {"NUB", "J", SAVE_EEPROM_16k, "PD Ultraman Battle Collection 64"}, - {"NUM", "J", SAVE_SRAM_256k, "Nushi Zuri 64: Shiokaze ni Notte"}, - {"NUT", "J", SAVE_SRAM_256k, "Nushi Zuri 64"}, - {"NVB", "J", SAVE_SRAM_256k, "Bass Rush: ECOGEAR PowerWorm Championship"}, - {"NVL", "EP", SAVE_EEPROM_4k, "V-Rally 99 (USA, PAL)"}, - {"NVP", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 64"}, - {"NVY", "J", SAVE_EEPROM_4k, "V-Rally 99 (Japan)"}, - {"NW2", "EP", SAVE_SRAM_256k, "WCW/nWo Revenge"}, - {"NW4", "EP", SAVE_FLASH_1m, "WWF No Mercy"}, - {"NWC", "J", SAVE_EEPROM_4k, "Wild Choppers"}, - {"NWL", "EP", SAVE_SRAM_256k, "Waialae Country Club: True Golf Classics"}, - {"NWQ", "E", SAVE_EEPROM_4k, "Rally Challenge 2000"}, - {"NWR", "EJP", SAVE_EEPROM_4k, "Wave Race 64"}, - {"NWT", "J", SAVE_EEPROM_4k, "Wetrix (Japan)"}, - {"NWU", "P", SAVE_EEPROM_4k, "Worms Armageddon (PAL)"}, - {"NWX", "EJP", SAVE_SRAM_256k, "WWF WrestleMania 2000"}, - {"NXO", "E", SAVE_EEPROM_4k, "Cruis'n Exotica"}, - {"NYK", "J", SAVE_EEPROM_4k, "Yakouchuu II: Satsujin Kouro"}, - {"NYS", "EJP", SAVE_EEPROM_16k, "Yoshi's Story"}, - {"NYW", "EJ", SAVE_SRAM_256k, "Harvest Moon 64"}, - {"NZL", "P", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (PAL)"}, - {"NZS", "EJP", SAVE_FLASH_1m, "Legend of Zelda: Majora's Mask"}, + {"CFZ", "EJ", SAVE_SRAM_256k, "F-Zero X (NTSC)"}, + {"CLB", "EJ", SAVE_EEPROM_4k, "Mario Party (NTSC)"}, + {"CP2", "J", SAVE_FLASH_1m, "Pokémon Stadium 2 (Japan)"}, + {"CPS", "J", SAVE_SRAM_256k, "Pokémon Stadium (Japan)"}, + {"CZL", "EJ", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (NTSC)"}, + {"N3D", "J", SAVE_EEPROM_16k, "Doraemon 3: Nobita no Machi SOS!"}, + {"N3H", "J", SAVE_SRAM_256k, "Ganbare! Nippon! Olympics 2000"}, + {"NA2", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 2"}, + {"NAB", "JP", SAVE_EEPROM_4k, "Air Boarder 64"}, + {"NAD", "E", SAVE_EEPROM_4k, "Worms Armageddon (USA)"}, + {"NAF", "J", SAVE_FLASH_1m, "Doubutsu no Mori"}, + {"NAG", "EJP", SAVE_EEPROM_4k, "AeroGauge"}, + {"NAL", "EJPU", SAVE_SRAM_256k, "Super Smash Bros"}, + {"NB5", "J", SAVE_SRAM_256k, "Biohazard 2"}, + {"NB6", "J", SAVE_EEPROM_4k, "Super B-Daman: Battle Phoenix 64"}, + {"NB7", "EJPU", SAVE_EEPROM_16k, "Banjo-Tooie"}, + {"NBC", "EJP", SAVE_EEPROM_4k, "Blast Corps"}, + {"NBD", "EJP", SAVE_EEPROM_4k, "Bomberman Hero"}, + {"NBH", "EP", SAVE_EEPROM_4k, "Body Harvest"}, + {"NBK", "EJP", SAVE_EEPROM_4k, "Banjo-Kazooie"}, + {"NBM", "EJP", SAVE_EEPROM_4k, "Bomberman 64"}, + {"NBN", "J", SAVE_EEPROM_4k, "Bakuretsu Muteki Bangaioh"}, + {"NBV", "EJ", SAVE_EEPROM_4k, "Bomberman 64: The Second Attack!"}, + {"NCC", "DEP", SAVE_FLASH_1m, "Command & Conquer"}, + {"NCG", "J", SAVE_EEPROM_4k, "Choro Q 64 2: Hacha-Mecha Grand Prix Race"}, + {"NCH", "EP", SAVE_EEPROM_4k, "Chopper Attack"}, + {"NCK", "E", SAVE_FLASH_1m, "NBA Courtside 2"}, + {"NCR", "EJP", SAVE_EEPROM_4k, "Penny Racers"}, + {"NCT", "EJP", SAVE_EEPROM_4k, "Chameleon Twist"}, + {"NCU", "EP", SAVE_EEPROM_4k, "Cruis'n USA"}, + {"NCW", "EP", SAVE_EEPROM_16k, "Cruis'n World"}, + {"NCX", "J", SAVE_EEPROM_4k, "Custom Robo"}, + {"NCZ", "J", SAVE_EEPROM_16k, "Custom Robo V2"}, + {"ND2", "J", SAVE_EEPROM_16k, "Doraemon 2: Nobita to Hikari no Shinden"}, + {"ND3", "J", SAVE_EEPROM_16k, "Akumajou Dracula Mokushiroku"}, + {"ND4", "J", SAVE_EEPROM_16k, "Akumajou Dracula Mokushiroku Gaiden: Legend of Cornell"}, + {"ND6", "J", SAVE_EEPROM_16k, "Densha de Go! 64"}, + {"NDA", "J", SAVE_FLASH_1m, "Derby Stallion 64"}, + {"NDK", "J", SAVE_EEPROM_4k, "Space Dynamites"}, + {"NDO", "EJP", SAVE_EEPROM_16k, "Donkey Kong 64"}, + {"NDP", "E", SAVE_FLASH_1m, "Dinosaur Planet"}, + {"NDR", "J", SAVE_EEPROM_4k, "Doraemon: Nobita to 3tsu no Seireiseki"}, + {"NDU", "EP", SAVE_EEPROM_4k, "Duck Dodgers"}, + {"NDY", "EJP", SAVE_EEPROM_4k, "Diddy Kong Racing"}, + {"NEA", "EP", SAVE_EEPROM_4k, "PGA European Tour"}, + {"NEP", "EJP", SAVE_EEPROM_16k, "Star Wars Episode I: Racer"}, + {"NER", "E", SAVE_EEPROM_4k, "AeroFighters Assault (USA)"}, + {"NEV", "J", SAVE_EEPROM_16k, "Neon Genesis Evangelion"}, + {"NF2", "P", SAVE_EEPROM_4k, "F-1 World Grand Prix II"}, + {"NFG", "E", SAVE_EEPROM_4k, "Fighter Destiny 2"}, + {"NFH", "EP", SAVE_EEPROM_4k, "Bass Hunter 64"}, + {"NFU", "EP", SAVE_EEPROM_16k, "Conker's Bad Fur Day"}, + {"NFW", "DEFJP", SAVE_EEPROM_4k, "F-1 World Grand Prix"}, + {"NFX", "EJPU", SAVE_EEPROM_4k, "Star Fox 64"}, + {"NFY", "J", SAVE_EEPROM_4k, "Kakutou Denshou: F-Cup Maniax"}, + {"NFZ", "P", SAVE_SRAM_256k, "F-Zero X (PAL)"}, + {"NG6", "J", SAVE_SRAM_256k, "Ganbare Goemon: Dero Dero Douchuu Obake Tenkomori"}, + {"NGC", "EP", SAVE_EEPROM_16k, "GT 64: Championship Edition"}, + {"NGE", "EJP", SAVE_EEPROM_4k, "GoldenEye 007"}, + {"NGL", "J", SAVE_EEPROM_4k, "Getter Love!!"}, + {"NGP", "J", SAVE_SRAM_256k, "Goemon: Mononoke Sugoroku"}, + {"NGT", "J", SAVE_EEPROM_16k, "City-Tour GP: Zen-Nihon GT Senshuken"}, + {"NGU", "J", SAVE_EEPROM_4k, "Tsumi to Batsu: Hoshi no Keishousha"}, + {"NGV", "EP", SAVE_EEPROM_4k, "Glover"}, + {"NHA", "J", SAVE_EEPROM_4k, "Bomber Man 64 (Japan)"}, + {"NHF", "J", SAVE_EEPROM_4k, "64 Hanafuda: Tenshi no Yakusoku"}, + {"NHP", "J", SAVE_EEPROM_4k, "Heiwa Pachinko World 64"}, + {"NHY", "J", SAVE_SRAM_256k, "Hybrid Heaven (Japan)"}, + {"NIB", "J", SAVE_SRAM_256k, "Itoi Shigesato no Bass Tsuri No. 1 Kettei Ban!"}, + {"NIC", "E", SAVE_EEPROM_4k, "Indy Racing 2000"}, + {"NIJ", "EP", SAVE_EEPROM_4k, "Indiana Jones and the Infernal Machine"}, + {"NIM", "J", SAVE_EEPROM_16k, "Ide Yosuke no Mahjong Juku"}, + {"NIR", "J", SAVE_EEPROM_4k, "Utchan Nanchan no Hono no Challenger: Denryuu Ira Ira Bou"}, + {"NJ5", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 5"}, + {"NJD", "E", SAVE_FLASH_1m, "Jet Force Gemini (Kiosk Demo)"}, + {"NJF", "EJP", SAVE_FLASH_1m, "Jet Force Gemini"}, + {"NJG", "J", SAVE_SRAM_256k, "Jinsei Game 64"}, + {"NJM", "EP", SAVE_EEPROM_4k, "Earthworm Jim 3D"}, + {"NK2", "EJP", SAVE_EEPROM_4k, "Snowboard Kids 2"}, + {"NK4", "EJP", SAVE_EEPROM_16k, "Kirby 64: The Crystal Shards"}, + {"NKA", "DEFJP", SAVE_EEPROM_4k, "Fighters Destiny"}, + {"NKG", "EP", SAVE_SRAM_256k, "MLB featuring Ken Griffey Jr."}, + {"NKI", "EP", SAVE_EEPROM_4k, "Killer Instinct Gold"}, + {"NKJ", "E", SAVE_FLASH_1m, "Ken Griffey Jr.'s Slugfest"}, + {"NKT", "EJP", SAVE_EEPROM_4k, "Mario Kart 64"}, + {"NLB", "P", SAVE_EEPROM_4k, "Mario Party (PAL)"}, + {"NLL", "J", SAVE_EEPROM_4k, "Last Legion UX"}, + {"NLR", "EJP", SAVE_EEPROM_4k, "Lode Runner 3D"}, + {"NM6", "E", SAVE_FLASH_1m, "Mega Man 64"}, + {"NM8", "EJP", SAVE_EEPROM_16k, "Mario Tennis"}, + {"NMF", "EJP", SAVE_SRAM_256k, "Mario Golf"}, + {"NMG", "DEP", SAVE_EEPROM_4k, "Monaco Grand Prix"}, + {"NMI", "DEFIPS", SAVE_EEPROM_4k, "Mission: Impossible"}, + {"NML", "EJP", SAVE_EEPROM_4k, "Mickey's Speedway USA"}, + {"NMO", "E", SAVE_EEPROM_4k, "Monopoly"}, + {"NMQ", "EJP", SAVE_FLASH_1m, "Paper Mario"}, + {"NMR", "EJP", SAVE_EEPROM_4k, "Multi Racing Championship"}, + {"NMS", "J", SAVE_EEPROM_4k, "Morita Shougi 64"}, + {"NMU", "E", SAVE_EEPROM_4k, "Big Mountain 2000"}, + {"NMV", "EJP", SAVE_EEPROM_16k, "Mario Party 3"}, + {"NMW", "EJP", SAVE_EEPROM_4k, "Mario Party 2"}, + {"NMX", "EJP", SAVE_EEPROM_16k, "Excitebike 64"}, + {"NN6", "E", SAVE_EEPROM_4k, "Dr. Mario 64"}, + {"NNA", "EP", SAVE_EEPROM_4k, "Star Wars Episode I: Battle for Naboo"}, + {"NNB", "EP", SAVE_EEPROM_16k, "Kobe Bryant in NBA Courtside"}, + {"NOB", "EJ", SAVE_SRAM_256k, "Ogre Battle 64: Person of Lordly Caliber"}, + {"NOS", "J", SAVE_EEPROM_4k, "64 Oozumou"}, + {"NP2", "J", SAVE_EEPROM_4k, "Chou Kuukan Nighter Pro Yakyuu King 2"}, + {"NP3", "DEFIJPS", SAVE_FLASH_1m, "Pokémon Stadium 2"}, + {"NP6", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 6"}, + {"NPA", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu 2000"}, + {"NPD", "EJP", SAVE_EEPROM_16k, "Perfect Dark"}, + {"NPE", "J", SAVE_SRAM_256k, "Jikkyou Powerful Pro Yakyuu Basic Ban 2001"}, + {"NPF", "DEFIJPSU", SAVE_FLASH_1m, "Pokémon Snap"}, + {"NPG", "EJ", SAVE_EEPROM_4k, "Hey You, Pikachu!"}, + {"NPH", "E", SAVE_FLASH_1m, "Pokémon Snap Station (Kiosk Demo)"}, + {"NPM", "P", SAVE_SRAM_256k, "Premier Manager 64"}, + {"NPN", "DEFP", SAVE_FLASH_1m, "Pokémon Puzzle League"}, + {"NPO", "DEFIPS", SAVE_FLASH_1m, "Pokémon Stadium (USA, PAL)"}, + {"NPP", "J", SAVE_EEPROM_16k, "Parlor! Pro 64: Pachinko Jikki Simulation Game"}, + {"NPS", "J", SAVE_SRAM_256k, "Jikkyou J.League 1999: Perfect Striker 2"}, + {"NPT", "J", SAVE_EEPROM_4k, "Puyo Puyon Party"}, + {"NPW", "EJP", SAVE_EEPROM_4k, "Pilotwings 64"}, + {"NPY", "J", SAVE_EEPROM_4k, "Puyo Puyo Sun 64"}, + {"NR7", "J", SAVE_EEPROM_16k, "Robot Poncots 64: 7tsu no Umi no Caramel"}, + {"NRA", "J", SAVE_EEPROM_4k, "Rally '99"}, + {"NRC", "EJP", SAVE_EEPROM_4k, "Top Gear Overdrive"}, + {"NRE", "EP", SAVE_SRAM_256k, "Resident Evil 2"}, + {"NRH", "J", SAVE_FLASH_1m, "Rockman Dash"}, + {"NRI", "EP", SAVE_SRAM_256k, "The New Tetris"}, + {"NRS", "EJP", SAVE_EEPROM_4k, "Star Wars: Rogue Squadron"}, + {"NRZ", "EP", SAVE_EEPROM_16k, "Ridge Racer 64"}, + {"NS4", "J", SAVE_SRAM_256k, "Super Robot Taisen 64"}, + {"NS6", "EJ", SAVE_EEPROM_4k, "Star Soldier: Vanishing Earth"}, + {"NSA", "JP", SAVE_EEPROM_4k, "AeroFighters Assault (PAL, Japan)"}, + {"NSC", "EP", SAVE_EEPROM_4k, "Starshot: Space Circus Fever"}, + {"NSI", "J", SAVE_SRAM_256k, "Fushigi no Dungeon: Fuurai no Shiren 2"}, + {"NSM", "EJP", SAVE_EEPROM_4k, "Super Mario 64"}, + {"NSN", "J", SAVE_EEPROM_4k, "Snow Speeder"}, + {"NSQ", "EP", SAVE_FLASH_1m, "StarCraft 64"}, + {"NSS", "J", SAVE_EEPROM_4k, "Super Robot Spirits"}, + {"NSU", "EP", SAVE_EEPROM_4k, "Rocket: Robot on Wheels"}, + {"NSV", "EP", SAVE_EEPROM_4k, "SpaceStation Silicon Valley"}, + {"NSW", "EJP", SAVE_EEPROM_4k, "Star Wars: Shadows of the Empire"}, + {"NT3", "J", SAVE_SRAM_256k, "Toukon Road 2"}, + {"NT6", "J", SAVE_EEPROM_4k, "Tetris 64"}, + {"NT9", "EP", SAVE_FLASH_1m, "Tigger's Honey Hunt"}, + {"NTB", "J", SAVE_EEPROM_4k, "Transformers: Beast Wars Metals 64"}, + {"NTC", "J", SAVE_EEPROM_4k, "64 Trump Collection"}, + {"NTE", "AP", SAVE_SRAM_256k, "1080 Snowboarding"}, + {"NTJ", "EP", SAVE_EEPROM_4k, "Tom and Jerry in Fists of Furry"}, + {"NTM", "EJP", SAVE_EEPROM_4k, "Mischief Makers"}, + {"NTN", "EP", SAVE_EEPROM_4k, "All-Star Tennis 99"}, + {"NTP", "EP", SAVE_EEPROM_4k, "Tetrisphere"}, + {"NTR", "JP", SAVE_EEPROM_4k, "Top Gear Rally (PAL, Japan)"}, + {"NTW", "J", SAVE_EEPROM_4k, "64 de Hakken!! Tamagotchi"}, + {"NTX", "EP", SAVE_EEPROM_4k, "Taz Express"}, + {"NUB", "J", SAVE_EEPROM_16k, "PD Ultraman Battle Collection 64"}, + {"NUM", "J", SAVE_SRAM_256k, "Nushi Zuri 64: Shiokaze ni Notte"}, + {"NUT", "J", SAVE_SRAM_256k, "Nushi Zuri 64"}, + {"NVB", "J", SAVE_SRAM_256k, "Bass Rush: ECOGEAR PowerWorm Championship"}, + {"NVL", "EP", SAVE_EEPROM_4k, "V-Rally 99 (USA, PAL)"}, + {"NVP", "J", SAVE_SRAM_256k, "Virtual Pro Wrestling 64"}, + {"NVY", "J", SAVE_EEPROM_4k, "V-Rally 99 (Japan)"}, + {"NW2", "EP", SAVE_SRAM_256k, "WCW/nWo Revenge"}, + {"NW4", "EP", SAVE_FLASH_1m, "WWF No Mercy"}, + {"NWC", "J", SAVE_EEPROM_4k, "Wild Choppers"}, + {"NWL", "EP", SAVE_SRAM_256k, "Waialae Country Club: True Golf Classics"}, + {"NWQ", "E", SAVE_EEPROM_4k, "Rally Challenge 2000"}, + {"NWR", "EJP", SAVE_EEPROM_4k, "Wave Race 64"}, + {"NWT", "J", SAVE_EEPROM_4k, "Wetrix (Japan)"}, + {"NWU", "P", SAVE_EEPROM_4k, "Worms Armageddon (PAL)"}, + {"NWX", "EJP", SAVE_SRAM_256k, "WWF WrestleMania 2000"}, + {"NXO", "E", SAVE_EEPROM_4k, "Cruis'n Exotica"}, + {"NYK", "J", SAVE_EEPROM_4k, "Yakouchuu II: Satsujin Kouro"}, + {"NYS", "EJP", SAVE_EEPROM_16k, "Yoshi's Story"}, + {"NYW", "EJ", SAVE_SRAM_256k, "Harvest Moon 64"}, + {"NZL", "P", SAVE_SRAM_256k, "Legend of Zelda: Ocarina of Time (PAL)"}, + {"NZS", "EJP", SAVE_FLASH_1m, "Legend of Zelda: Majora's Mask"}, }; } \ No newline at end of file diff --git a/src/backend/MemoryRegions.hpp b/src/backend/MemoryRegions.hpp index 680df821..d82ff612 100644 --- a/src/backend/MemoryRegions.hpp +++ b/src/backend/MemoryRegions.hpp @@ -37,9 +37,9 @@ #define CART_REGION_END_2_1 0x05FFFFFF #define CART_REGION_END_2_2 0x0FFFFFFF -#define RDRAM_REGION RDRAM_REGION_START ... RDRAM_REGION_END -#define RSP_MEM_REGION DMEM_REGION_START ... 0x0403FFFF -#define MMIO_REGION 0x04040000 ... 0x041FFFFF: case 0x04300000 ... 0x048FFFFF +#define RDRAM_REGION RDRAM_REGION_START... RDRAM_REGION_END +#define RSP_MEM_REGION DMEM_REGION_START... 0x0403FFFF +#define MMIO_REGION 0x04040000 ... 0x041FFFFF : case 0x04300000 ... 0x048FFFFF #define SP_REGION 0x04040000 ... 0x040FFFFF #define DP_CMD_REGION 0x04100000 ... 0x041FFFFF #define RSP_REGION 0x04040000 ... 0x040FFFFF @@ -51,9 +51,9 @@ #define PI_REGION 0x04600000 ... 0x046FFFFF #define RI_REGION 0x04700000 ... 0x047FFFFF #define SI_REGION 0x04800000 ... 0x048FFFFF -#define REGION_CART CART_REGION_START_2_1 ... CART_REGION_END_1_2 -#define PIF_ROM_REGION PIF_ROM_REGION_START ... PIF_ROM_REGION_END -#define PIF_RAM_REGION PIF_RAM_REGION_START ... PIF_RAM_REGION_END +#define REGION_CART CART_REGION_START_2_1... CART_REGION_END_1_2 +#define PIF_ROM_REGION PIF_ROM_REGION_START... PIF_ROM_REGION_END +#define PIF_RAM_REGION PIF_RAM_REGION_START... PIF_RAM_REGION_END #define START_VREGION_KUSEG 0x00000000 #define START_VREGION_KSEG0 0x80000000 @@ -67,62 +67,56 @@ #define END_VREGION_KSSEG 0xDFFFFFFF #define END_VREGION_KSEG3 0xFFFFFFFF -#define VREGION_KUSEG START_VREGION_KUSEG ... END_VREGION_KUSEG -#define VREGION_KSEG0 START_VREGION_KSEG0 ... END_VREGION_KSEG0 -#define VREGION_KSEG1 START_VREGION_KSEG1 ... END_VREGION_KSEG1 -#define VREGION_KSSEG START_VREGION_KSSEG ... END_VREGION_KSSEG -#define VREGION_KSEG3 START_VREGION_KSEG3 ... END_VREGION_KSEG3 +#define VREGION_KUSEG START_VREGION_KUSEG... END_VREGION_KUSEG +#define VREGION_KSEG0 START_VREGION_KSEG0... END_VREGION_KSEG0 +#define VREGION_KSEG1 START_VREGION_KSEG1... END_VREGION_KSEG1 +#define VREGION_KSSEG START_VREGION_KSSEG... END_VREGION_KSSEG +#define VREGION_KSEG3 START_VREGION_KSEG3... END_VREGION_KSEG3 #define DIRECT_MAP_MASK 0x1FFFFFFF #define VREGION_XKUSEG 0x0000000000000000 ... 0x000000FFFFFFFFFF -#define VREGION_XBAD1 0x0000010000000000 ... 0x3FFFFFFFFFFFFFFF +#define VREGION_XBAD1 0x0000010000000000 ... 0x3FFFFFFFFFFFFFFF #define VREGION_XKSSEG 0x4000000000000000 ... 0x400000FFFFFFFFFF -#define VREGION_XBAD2 0x4000010000000000 ... 0x7FFFFFFFFFFFFFFF +#define VREGION_XBAD2 0x4000010000000000 ... 0x7FFFFFFFFFFFFFFF #define VREGION_XKPHYS 0x8000000000000000 ... 0xBFFFFFFFFFFFFFFF -#define VREGION_XKSEG 0xC000000000000000 ... 0xC00000FF7FFFFFFF -#define VREGION_XBAD3 0xC00000FF80000000 ... 0xFFFFFFFF7FFFFFFF +#define VREGION_XKSEG 0xC000000000000000 ... 0xC00000FF7FFFFFFF +#define VREGION_XBAD3 0xC00000FF80000000 ... 0xFFFFFFFF7FFFFFFF #define VREGION_CKSEG0 0xFFFFFFFF80000000 ... 0xFFFFFFFF9FFFFFFF #define VREGION_CKSEG1 0xFFFFFFFFA0000000 ... 0xFFFFFFFFBFFFFFFF #define VREGION_CKSSEG 0xFFFFFFFFC0000000 ... 0xFFFFFFFFDFFFFFFF #define VREGION_CKSEG3 0xFFFFFFFFE0000000 ... 0xFFFFFFFFFFFFFFFF -#define SREGION_PI_UNKNOWN 0x00000000 +#define SREGION_PI_UNKNOWN 0x00000000 #define SREGION_PI_64DD_REG 0x05000000 #define SREGION_PI_64DD_ROM 0x06000000 -#define SREGION_PI_SRAM 0x08000000 -#define SREGION_PI_ROM 0x10000000 +#define SREGION_PI_SRAM 0x08000000 +#define SREGION_PI_ROM 0x10000000 -#define EREGION_PI_UNKNOWN 0x04FFFFFF +#define EREGION_PI_UNKNOWN 0x04FFFFFF #define EREGION_PI_64DD_REG 0x05FFFFFF #define EREGION_PI_64DD_ROM 0x07FFFFFF -#define EREGION_PI_SRAM 0x0FFFFFFF -#define EREGION_PI_ROM 0xFFFFFFFF +#define EREGION_PI_SRAM 0x0FFFFFFF +#define EREGION_PI_ROM 0xFFFFFFFF -#define REGION_PI_UNKNOWN SREGION_PI_UNKNOWN ... EREGION_PI_UNKNOWN -#define REGION_PI_64DD_REG SREGION_PI_64DD_REG ... EREGION_PI_64DD_REG -#define REGION_PI_64DD_ROM SREGION_PI_64DD_ROM ... EREGION_PI_64DD_ROM -#define REGION_PI_SRAM SREGION_PI_SRAM ... EREGION_PI_SRAM -#define REGION_PI_ROM SREGION_PI_ROM ... EREGION_PI_ROM +#define REGION_PI_UNKNOWN SREGION_PI_UNKNOWN... EREGION_PI_UNKNOWN +#define REGION_PI_64DD_REG SREGION_PI_64DD_REG... EREGION_PI_64DD_REG +#define REGION_PI_64DD_ROM SREGION_PI_64DD_ROM... EREGION_PI_64DD_ROM +#define REGION_PI_SRAM SREGION_PI_SRAM... EREGION_PI_SRAM +#define REGION_PI_ROM SREGION_PI_ROM... EREGION_PI_ROM -#define CART_ISVIEWER_FLUSH 0x13FF0014 +#define CART_ISVIEWER_FLUSH 0x13FF0014 #define SREGION_CART_ISVIEWER_BUFFER 0x13FF0020 #define EREGION_CART_ISVIEWER_BUFFER 0x13FFFFFF #define CART_ISVIEWER_SIZE (EREGION_CART_ISVIEWER_BUFFER - SREGION_CART_ISVIEWER_BUFFER) -#define REGION_CART_ISVIEWER_BUFFER SREGION_CART_ISVIEWER_BUFFER ... EREGION_CART_ISVIEWER_BUFFER +#define REGION_CART_ISVIEWER_BUFFER SREGION_CART_ISVIEWER_BUFFER... EREGION_CART_ISVIEWER_BUFFER -constexpr u64 operator""_kb(unsigned long long int x) { - return 1024ULL * x; -} +constexpr u64 operator""_kb(unsigned long long int x) { return 1024ULL * x; } -constexpr u64 operator""_mb(unsigned long long int x) { - return 1024_kb * x; -} +constexpr u64 operator""_mb(unsigned long long int x) { return 1024_kb * x; } -constexpr u64 operator""_gb(unsigned long long int x) { - return 1024_mb * x; -} +constexpr u64 operator""_gb(unsigned long long int x) { return 1024_mb * x; } #define ADDRESS_RANGE_SIZE 0x80000000ull #define PAGE_SIZE 4_kb -#define PAGE_COUNT ((ADDRESS_RANGE_SIZE) / (PAGE_SIZE)) \ No newline at end of file +#define PAGE_COUNT ((ADDRESS_RANGE_SIZE) / (PAGE_SIZE)) diff --git a/src/backend/Netplay.cpp b/src/backend/Netplay.cpp index be03d750..9ef2f8d2 100644 --- a/src/backend/Netplay.cpp +++ b/src/backend/Netplay.cpp @@ -1,7 +1,6 @@ #include -#include #include #include +#include -namespace Netplay { -} \ No newline at end of file +namespace Netplay {} diff --git a/src/backend/Netplay.hpp b/src/backend/Netplay.hpp index c52477aa..e33c91d6 100644 --- a/src/backend/Netplay.hpp +++ b/src/backend/Netplay.hpp @@ -1,5 +1,4 @@ #pragma once #include -namespace Netplay { -} \ No newline at end of file +namespace Netplay {} diff --git a/src/backend/RomHelpers.hpp b/src/backend/RomHelpers.hpp index ebae39a2..8e4e6c95 100644 --- a/src/backend/RomHelpers.hpp +++ b/src/backend/RomHelpers.hpp @@ -1,6 +1,6 @@ #pragma once -#include #include +#include namespace Util { #define Z64 0x80371200 @@ -10,9 +10,9 @@ namespace Util { template FORCE_INLINE void SwapN64Rom(std::vector &rom, u32 endianness) { u8 altByteShift = 0; - if((endianness >> 24) != 0x80) { - if((endianness & 0xFF) != 0x80) { - if(((endianness >> 16) & 0xff) != 0x80) { + if ((endianness >> 24) != 0x80) { + if ((endianness & 0xFF) != 0x80) { + if (((endianness >> 16) & 0xff) != 0x80) { Util::panic("TODO: Unrecognized rom endianness. Ideally, this should be more robust"); } else { altByteShift = 12; @@ -27,21 +27,21 @@ FORCE_INLINE void SwapN64Rom(std::vector &rom, u32 endianness) { endianness &= ~(0xFF << altByteShift); switch (endianness) { - case V64: - SwapBuffer16(rom); - if constexpr(!toBE) - SwapBuffer32(rom); - break; - case N64: - if constexpr(toBE) - SwapBuffer32(rom); - break; - case Z64: - if constexpr(!toBE) - SwapBuffer32(rom); - break; - default: - panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!"); + case V64: + SwapBuffer16(rom); + if constexpr (!toBE) + SwapBuffer32(rom); + break; + case N64: + if constexpr (toBE) + SwapBuffer32(rom); + break; + case Z64: + if constexpr (!toBE) + SwapBuffer32(rom); + break; + default: + panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!"); } } -} \ No newline at end of file +} // namespace Util diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index f9664ff1..b3ea0307 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -1,20 +1,16 @@ #include -#include #include +#include Scheduler scheduler; -void Scheduler::EnqueueRelative(u64 t, const EventType type) { - EnqueueAbsolute(t + ticks, type); -} +void Scheduler::EnqueueRelative(u64 t, const EventType type) { EnqueueAbsolute(t + ticks, type); } -void Scheduler::EnqueueAbsolute(u64 t, const EventType type) { - events.push({t, type}); -} +void Scheduler::EnqueueAbsolute(u64 t, const EventType type) { events.push({t, type}); } u64 Scheduler::Remove(EventType type) { - for (auto& e : events) { - if(e.type == type) { + for (auto &e : events) { + if (e.type == type) { u64 ret = e.time - ticks; e.type = NONE; e.time = ticks; @@ -25,31 +21,31 @@ u64 Scheduler::Remove(EventType type) { return 0; } -void Scheduler::Tick(u64 t, n64::Mem& mem) { +void Scheduler::Tick(u64 t, n64::Mem &mem) { ticks += t; - n64::MI& mi = mem.mmio.mi; - n64::SI& si = mem.mmio.si; - n64::PI& pi = mem.mmio.pi; + n64::MI &mi = mem.mmio.mi; + n64::SI &si = mem.mmio.si; + n64::PI &pi = mem.mmio.pi; - while(ticks >= events.top().time) { - switch(auto type = events.top().type) { - case SI_DMA: - si.DMA(); - break; - case PI_DMA_COMPLETE: - mi.InterruptRaise(n64::MI::Interrupt::PI); - pi.dmaBusy = false; - break; - case PI_BUS_WRITE_COMPLETE: - pi.ioBusy = false; - break; - case NONE: - break; - case IMPOSSIBLE: - Util::panic("Congratulations on keeping the emulator on for about 5 billion years, I guess, nerd."); - default: - Util::panic("Unknown scheduler event type {}", static_cast(type)); + while (ticks >= events.top().time) { + switch (auto type = events.top().type) { + case SI_DMA: + si.DMA(); + break; + case PI_DMA_COMPLETE: + mi.InterruptRaise(n64::MI::Interrupt::PI); + pi.dmaBusy = false; + break; + case PI_BUS_WRITE_COMPLETE: + pi.ioBusy = false; + break; + case NONE: + break; + case IMPOSSIBLE: + Util::panic("Congratulations on keeping the emulator on for about 5 billion years, I guess, nerd."); + default: + Util::panic("Unknown scheduler event type {}", static_cast(type)); } events.pop(); } -} \ No newline at end of file +} diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index d0565d4d..ac95073b 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -1,63 +1,50 @@ #pragma once -#include #include #include #include +#include namespace n64 { struct Mem; struct Registers; -} +} // namespace n64 -enum EventType { - NONE, - PI_BUS_WRITE_COMPLETE, - PI_DMA_COMPLETE, - SI_DMA, - IMPOSSIBLE -}; +enum EventType { NONE, PI_BUS_WRITE_COMPLETE, PI_DMA_COMPLETE, SI_DMA, IMPOSSIBLE }; struct Event { u64 time; EventType type; - friend bool operator<(const Event& rhs, const Event& lhs) { - return rhs.time < lhs.time; - } + friend bool operator<(const Event &rhs, const Event &lhs) { return rhs.time < lhs.time; } - friend bool operator>(const Event& rhs, const Event& lhs) { - return rhs.time > lhs.time; - } + friend bool operator>(const Event &rhs, const Event &lhs) { return rhs.time > lhs.time; } - friend bool operator>=(const Event& rhs, const Event& lhs) { - return rhs.time >= lhs.time; - } + friend bool operator>=(const Event &rhs, const Event &lhs) { return rhs.time >= lhs.time; } }; struct IterableEvents { std::priority_queue, std::greater<>> events; + public: explicit IterableEvents() = default; [[nodiscard]] auto top() const { return events.top(); } auto pop() { events.pop(); } - [[nodiscard]] auto begin() const { return (Event*)(&events.top()); } + [[nodiscard]] auto begin() const { return (Event *)(&events.top()); } [[nodiscard]] auto end() const { return begin() + events.size(); } auto push(Event e) { events.push(e); } }; struct Scheduler { - Scheduler() { - EnqueueAbsolute(std::numeric_limits::max(), IMPOSSIBLE); - } + Scheduler() { EnqueueAbsolute(std::numeric_limits::max(), IMPOSSIBLE); } void EnqueueRelative(u64, EventType); void EnqueueAbsolute(u64, EventType); u64 Remove(EventType); - void Tick(u64 t, n64::Mem&); + void Tick(u64 t, n64::Mem &); IterableEvents events; u64 ticks = 0; u8 index = 0; }; -extern Scheduler scheduler; \ No newline at end of file +extern Scheduler scheduler; diff --git a/src/backend/core/MMIO.hpp b/src/backend/core/MMIO.hpp index ccb00339..b61629fc 100644 --- a/src/backend/core/MMIO.hpp +++ b/src/backend/core/MMIO.hpp @@ -1,12 +1,12 @@ #pragma once -#include -#include +#include +#include #include +#include #include #include #include -#include -#include +#include class ParallelRDP; @@ -15,7 +15,8 @@ struct Mem; struct Registers; struct MMIO { - MMIO(Mem& mem, Registers& regs, ParallelRDP& parallel) : vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) { + MMIO(Mem &mem, Registers ®s, ParallelRDP ¶llel) : + vi(mem, regs), mi(regs), ai(mem, regs), pi(mem, regs), si(mem, regs), rsp(mem, regs), rdp(mem, parallel) { Reset(); } void Reset(); @@ -32,6 +33,6 @@ struct MMIO { u32 Read(u32); void Write(u32, u32); std::vector Serialize(); - void Deserialize(const std::vector&); + void Deserialize(const std::vector &); }; -} +} // namespace n64 diff --git a/src/backend/core/RCP.hpp b/src/backend/core/RCP.hpp index 3eb6965b..f985875b 100644 --- a/src/backend/core/RCP.hpp +++ b/src/backend/core/RCP.hpp @@ -2,36 +2,40 @@ #include static constexpr u16 rcpRom[] = { - 0xffff, 0xff00, 0xfe01, 0xfd04, 0xfc07, 0xfb0c, 0xfa11, 0xf918, 0xf81f, 0xf727, 0xf631, 0xf53b, 0xf446, 0xf352, 0xf25f, 0xf16d, - 0xf07c, 0xef8b, 0xee9c, 0xedae, 0xecc0, 0xebd3, 0xeae8, 0xe9fd, 0xe913, 0xe829, 0xe741, 0xe65a, 0xe573, 0xe48d, 0xe3a9, 0xe2c5, - 0xe1e1, 0xe0ff, 0xe01e, 0xdf3d, 0xde5d, 0xdd7e, 0xdca0, 0xdbc2, 0xdae6, 0xda0a, 0xd92f, 0xd854, 0xd77b, 0xd6a2, 0xd5ca, 0xd4f3, - 0xd41d, 0xd347, 0xd272, 0xd19e, 0xd0cb, 0xcff8, 0xcf26, 0xce55, 0xcd85, 0xccb5, 0xcbe6, 0xcb18, 0xca4b, 0xc97e, 0xc8b2, 0xc7e7, - 0xc71c, 0xc652, 0xc589, 0xc4c0, 0xc3f8, 0xc331, 0xc26b, 0xc1a5, 0xc0e0, 0xc01c, 0xbf58, 0xbe95, 0xbdd2, 0xbd10, 0xbc4f, 0xbb8f, - 0xbacf, 0xba10, 0xb951, 0xb894, 0xb7d6, 0xb71a, 0xb65e, 0xb5a2, 0xb4e8, 0xb42e, 0xb374, 0xb2bb, 0xb203, 0xb14b, 0xb094, 0xafde, - 0xaf28, 0xae73, 0xadbe, 0xad0a, 0xac57, 0xaba4, 0xaaf1, 0xaa40, 0xa98e, 0xa8de, 0xa82e, 0xa77e, 0xa6d0, 0xa621, 0xa574, 0xa4c6, - 0xa41a, 0xa36e, 0xa2c2, 0xa217, 0xa16d, 0xa0c3, 0xa01a, 0x9f71, 0x9ec8, 0x9e21, 0x9d79, 0x9cd3, 0x9c2d, 0x9b87, 0x9ae2, 0x9a3d, - 0x9999, 0x98f6, 0x9852, 0x97b0, 0x970e, 0x966c, 0x95cb, 0x952b, 0x948b, 0x93eb, 0x934c, 0x92ad, 0x920f, 0x9172, 0x90d4, 0x9038, - 0x8f9c, 0x8f00, 0x8e65, 0x8dca, 0x8d30, 0x8c96, 0x8bfc, 0x8b64, 0x8acb, 0x8a33, 0x899c, 0x8904, 0x886e, 0x87d8, 0x8742, 0x86ad, - 0x8618, 0x8583, 0x84f0, 0x845c, 0x83c9, 0x8336, 0x82a4, 0x8212, 0x8181, 0x80f0, 0x8060, 0x7fd0, 0x7f40, 0x7eb1, 0x7e22, 0x7d93, - 0x7d05, 0x7c78, 0x7beb, 0x7b5e, 0x7ad2, 0x7a46, 0x79ba, 0x792f, 0x78a4, 0x781a, 0x7790, 0x7706, 0x767d, 0x75f5, 0x756c, 0x74e4, - 0x745d, 0x73d5, 0x734f, 0x72c8, 0x7242, 0x71bc, 0x7137, 0x70b2, 0x702e, 0x6fa9, 0x6f26, 0x6ea2, 0x6e1f, 0x6d9c, 0x6d1a, 0x6c98, - 0x6c16, 0x6b95, 0x6b14, 0x6a94, 0x6a13, 0x6993, 0x6914, 0x6895, 0x6816, 0x6798, 0x6719, 0x669c, 0x661e, 0x65a1, 0x6524, 0x64a8, - 0x642c, 0x63b0, 0x6335, 0x62ba, 0x623f, 0x61c5, 0x614b, 0x60d1, 0x6058, 0x5fdf, 0x5f66, 0x5eed, 0x5e75, 0x5dfd, 0x5d86, 0x5d0f, - 0x5c98, 0x5c22, 0x5bab, 0x5b35, 0x5ac0, 0x5a4b, 0x59d6, 0x5961, 0x58ed, 0x5879, 0x5805, 0x5791, 0x571e, 0x56ac, 0x5639, 0x55c7, - 0x5555, 0x54e3, 0x5472, 0x5401, 0x5390, 0x5320, 0x52af, 0x5240, 0x51d0, 0x5161, 0x50f2, 0x5083, 0x5015, 0x4fa6, 0x4f38, 0x4ecb, - 0x4e5e, 0x4df1, 0x4d84, 0x4d17, 0x4cab, 0x4c3f, 0x4bd3, 0x4b68, 0x4afd, 0x4a92, 0x4a27, 0x49bd, 0x4953, 0x48e9, 0x4880, 0x4817, - 0x47ae, 0x4745, 0x46dc, 0x4674, 0x460c, 0x45a5, 0x453d, 0x44d6, 0x446f, 0x4408, 0x43a2, 0x433c, 0x42d6, 0x4270, 0x420b, 0x41a6, - 0x4141, 0x40dc, 0x4078, 0x4014, 0x3fb0, 0x3f4c, 0x3ee8, 0x3e85, 0x3e22, 0x3dc0, 0x3d5d, 0x3cfb, 0x3c99, 0x3c37, 0x3bd6, 0x3b74, - 0x3b13, 0x3ab2, 0x3a52, 0x39f1, 0x3991, 0x3931, 0x38d2, 0x3872, 0x3813, 0x37b4, 0x3755, 0x36f7, 0x3698, 0x363a, 0x35dc, 0x357f, - 0x3521, 0x34c4, 0x3467, 0x340a, 0x33ae, 0x3351, 0x32f5, 0x3299, 0x323e, 0x31e2, 0x3187, 0x312c, 0x30d1, 0x3076, 0x301c, 0x2fc2, - 0x2f68, 0x2f0e, 0x2eb4, 0x2e5b, 0x2e02, 0x2da9, 0x2d50, 0x2cf8, 0x2c9f, 0x2c47, 0x2bef, 0x2b97, 0x2b40, 0x2ae8, 0x2a91, 0x2a3a, - 0x29e4, 0x298d, 0x2937, 0x28e0, 0x288b, 0x2835, 0x27df, 0x278a, 0x2735, 0x26e0, 0x268b, 0x2636, 0x25e2, 0x258d, 0x2539, 0x24e5, - 0x2492, 0x243e, 0x23eb, 0x2398, 0x2345, 0x22f2, 0x22a0, 0x224d, 0x21fb, 0x21a9, 0x2157, 0x2105, 0x20b4, 0x2063, 0x2012, 0x1fc1, - 0x1f70, 0x1f1f, 0x1ecf, 0x1e7f, 0x1e2e, 0x1ddf, 0x1d8f, 0x1d3f, 0x1cf0, 0x1ca1, 0x1c52, 0x1c03, 0x1bb4, 0x1b66, 0x1b17, 0x1ac9, - 0x1a7b, 0x1a2d, 0x19e0, 0x1992, 0x1945, 0x18f8, 0x18ab, 0x185e, 0x1811, 0x17c4, 0x1778, 0x172c, 0x16e0, 0x1694, 0x1648, 0x15fd, - 0x15b1, 0x1566, 0x151b, 0x14d0, 0x1485, 0x143b, 0x13f0, 0x13a6, 0x135c, 0x1312, 0x12c8, 0x127f, 0x1235, 0x11ec, 0x11a3, 0x1159, - 0x1111, 0x10c8, 0x107f, 0x1037, 0x0fef, 0x0fa6, 0x0f5e, 0x0f17, 0x0ecf, 0x0e87, 0x0e40, 0x0df9, 0x0db2, 0x0d6b, 0x0d24, 0x0cdd, - 0x0c97, 0x0c50, 0x0c0a, 0x0bc4, 0x0b7e, 0x0b38, 0x0af2, 0x0aad, 0x0a68, 0x0a22, 0x09dd, 0x0998, 0x0953, 0x090f, 0x08ca, 0x0886, - 0x0842, 0x07fd, 0x07b9, 0x0776, 0x0732, 0x06ee, 0x06ab, 0x0668, 0x0624, 0x05e1, 0x059e, 0x055c, 0x0519, 0x04d6, 0x0494, 0x0452, - 0x0410, 0x03ce, 0x038c, 0x034a, 0x0309, 0x02c7, 0x0286, 0x0245, 0x0204, 0x01c3, 0x0182, 0x0141, 0x0101, 0x00c0, 0x0080, 0x0040 -}; \ No newline at end of file + 0xffff, 0xff00, 0xfe01, 0xfd04, 0xfc07, 0xfb0c, 0xfa11, 0xf918, 0xf81f, 0xf727, 0xf631, 0xf53b, 0xf446, 0xf352, + 0xf25f, 0xf16d, 0xf07c, 0xef8b, 0xee9c, 0xedae, 0xecc0, 0xebd3, 0xeae8, 0xe9fd, 0xe913, 0xe829, 0xe741, 0xe65a, + 0xe573, 0xe48d, 0xe3a9, 0xe2c5, 0xe1e1, 0xe0ff, 0xe01e, 0xdf3d, 0xde5d, 0xdd7e, 0xdca0, 0xdbc2, 0xdae6, 0xda0a, + 0xd92f, 0xd854, 0xd77b, 0xd6a2, 0xd5ca, 0xd4f3, 0xd41d, 0xd347, 0xd272, 0xd19e, 0xd0cb, 0xcff8, 0xcf26, 0xce55, + 0xcd85, 0xccb5, 0xcbe6, 0xcb18, 0xca4b, 0xc97e, 0xc8b2, 0xc7e7, 0xc71c, 0xc652, 0xc589, 0xc4c0, 0xc3f8, 0xc331, + 0xc26b, 0xc1a5, 0xc0e0, 0xc01c, 0xbf58, 0xbe95, 0xbdd2, 0xbd10, 0xbc4f, 0xbb8f, 0xbacf, 0xba10, 0xb951, 0xb894, + 0xb7d6, 0xb71a, 0xb65e, 0xb5a2, 0xb4e8, 0xb42e, 0xb374, 0xb2bb, 0xb203, 0xb14b, 0xb094, 0xafde, 0xaf28, 0xae73, + 0xadbe, 0xad0a, 0xac57, 0xaba4, 0xaaf1, 0xaa40, 0xa98e, 0xa8de, 0xa82e, 0xa77e, 0xa6d0, 0xa621, 0xa574, 0xa4c6, + 0xa41a, 0xa36e, 0xa2c2, 0xa217, 0xa16d, 0xa0c3, 0xa01a, 0x9f71, 0x9ec8, 0x9e21, 0x9d79, 0x9cd3, 0x9c2d, 0x9b87, + 0x9ae2, 0x9a3d, 0x9999, 0x98f6, 0x9852, 0x97b0, 0x970e, 0x966c, 0x95cb, 0x952b, 0x948b, 0x93eb, 0x934c, 0x92ad, + 0x920f, 0x9172, 0x90d4, 0x9038, 0x8f9c, 0x8f00, 0x8e65, 0x8dca, 0x8d30, 0x8c96, 0x8bfc, 0x8b64, 0x8acb, 0x8a33, + 0x899c, 0x8904, 0x886e, 0x87d8, 0x8742, 0x86ad, 0x8618, 0x8583, 0x84f0, 0x845c, 0x83c9, 0x8336, 0x82a4, 0x8212, + 0x8181, 0x80f0, 0x8060, 0x7fd0, 0x7f40, 0x7eb1, 0x7e22, 0x7d93, 0x7d05, 0x7c78, 0x7beb, 0x7b5e, 0x7ad2, 0x7a46, + 0x79ba, 0x792f, 0x78a4, 0x781a, 0x7790, 0x7706, 0x767d, 0x75f5, 0x756c, 0x74e4, 0x745d, 0x73d5, 0x734f, 0x72c8, + 0x7242, 0x71bc, 0x7137, 0x70b2, 0x702e, 0x6fa9, 0x6f26, 0x6ea2, 0x6e1f, 0x6d9c, 0x6d1a, 0x6c98, 0x6c16, 0x6b95, + 0x6b14, 0x6a94, 0x6a13, 0x6993, 0x6914, 0x6895, 0x6816, 0x6798, 0x6719, 0x669c, 0x661e, 0x65a1, 0x6524, 0x64a8, + 0x642c, 0x63b0, 0x6335, 0x62ba, 0x623f, 0x61c5, 0x614b, 0x60d1, 0x6058, 0x5fdf, 0x5f66, 0x5eed, 0x5e75, 0x5dfd, + 0x5d86, 0x5d0f, 0x5c98, 0x5c22, 0x5bab, 0x5b35, 0x5ac0, 0x5a4b, 0x59d6, 0x5961, 0x58ed, 0x5879, 0x5805, 0x5791, + 0x571e, 0x56ac, 0x5639, 0x55c7, 0x5555, 0x54e3, 0x5472, 0x5401, 0x5390, 0x5320, 0x52af, 0x5240, 0x51d0, 0x5161, + 0x50f2, 0x5083, 0x5015, 0x4fa6, 0x4f38, 0x4ecb, 0x4e5e, 0x4df1, 0x4d84, 0x4d17, 0x4cab, 0x4c3f, 0x4bd3, 0x4b68, + 0x4afd, 0x4a92, 0x4a27, 0x49bd, 0x4953, 0x48e9, 0x4880, 0x4817, 0x47ae, 0x4745, 0x46dc, 0x4674, 0x460c, 0x45a5, + 0x453d, 0x44d6, 0x446f, 0x4408, 0x43a2, 0x433c, 0x42d6, 0x4270, 0x420b, 0x41a6, 0x4141, 0x40dc, 0x4078, 0x4014, + 0x3fb0, 0x3f4c, 0x3ee8, 0x3e85, 0x3e22, 0x3dc0, 0x3d5d, 0x3cfb, 0x3c99, 0x3c37, 0x3bd6, 0x3b74, 0x3b13, 0x3ab2, + 0x3a52, 0x39f1, 0x3991, 0x3931, 0x38d2, 0x3872, 0x3813, 0x37b4, 0x3755, 0x36f7, 0x3698, 0x363a, 0x35dc, 0x357f, + 0x3521, 0x34c4, 0x3467, 0x340a, 0x33ae, 0x3351, 0x32f5, 0x3299, 0x323e, 0x31e2, 0x3187, 0x312c, 0x30d1, 0x3076, + 0x301c, 0x2fc2, 0x2f68, 0x2f0e, 0x2eb4, 0x2e5b, 0x2e02, 0x2da9, 0x2d50, 0x2cf8, 0x2c9f, 0x2c47, 0x2bef, 0x2b97, + 0x2b40, 0x2ae8, 0x2a91, 0x2a3a, 0x29e4, 0x298d, 0x2937, 0x28e0, 0x288b, 0x2835, 0x27df, 0x278a, 0x2735, 0x26e0, + 0x268b, 0x2636, 0x25e2, 0x258d, 0x2539, 0x24e5, 0x2492, 0x243e, 0x23eb, 0x2398, 0x2345, 0x22f2, 0x22a0, 0x224d, + 0x21fb, 0x21a9, 0x2157, 0x2105, 0x20b4, 0x2063, 0x2012, 0x1fc1, 0x1f70, 0x1f1f, 0x1ecf, 0x1e7f, 0x1e2e, 0x1ddf, + 0x1d8f, 0x1d3f, 0x1cf0, 0x1ca1, 0x1c52, 0x1c03, 0x1bb4, 0x1b66, 0x1b17, 0x1ac9, 0x1a7b, 0x1a2d, 0x19e0, 0x1992, + 0x1945, 0x18f8, 0x18ab, 0x185e, 0x1811, 0x17c4, 0x1778, 0x172c, 0x16e0, 0x1694, 0x1648, 0x15fd, 0x15b1, 0x1566, + 0x151b, 0x14d0, 0x1485, 0x143b, 0x13f0, 0x13a6, 0x135c, 0x1312, 0x12c8, 0x127f, 0x1235, 0x11ec, 0x11a3, 0x1159, + 0x1111, 0x10c8, 0x107f, 0x1037, 0x0fef, 0x0fa6, 0x0f5e, 0x0f17, 0x0ecf, 0x0e87, 0x0e40, 0x0df9, 0x0db2, 0x0d6b, + 0x0d24, 0x0cdd, 0x0c97, 0x0c50, 0x0c0a, 0x0bc4, 0x0b7e, 0x0b38, 0x0af2, 0x0aad, 0x0a68, 0x0a22, 0x09dd, 0x0998, + 0x0953, 0x090f, 0x08ca, 0x0886, 0x0842, 0x07fd, 0x07b9, 0x0776, 0x0732, 0x06ee, 0x06ab, 0x0668, 0x0624, 0x05e1, + 0x059e, 0x055c, 0x0519, 0x04d6, 0x0494, 0x0452, 0x0410, 0x03ce, 0x038c, 0x034a, 0x0309, 0x02c7, 0x0286, 0x0245, + 0x0204, 0x01c3, 0x0182, 0x0141, 0x0101, 0x00c0, 0x0080, 0x0040}; diff --git a/src/backend/core/RDP.cpp b/src/backend/core/RDP.cpp index b3c7406f..0c365cfd 100644 --- a/src/backend/core/RDP.cpp +++ b/src/backend/core/RDP.cpp @@ -1,10 +1,10 @@ #include -#include #include +#include #include namespace n64 { -RDP::RDP(Mem& mem, ParallelRDP& parallel) : mem(mem), parallel(parallel) { +RDP::RDP(Mem &mem, ParallelRDP ¶llel) : mem(mem), parallel(parallel) { rdram.resize(RDRAM_SIZE); std::fill(rdram.begin(), rdram.end(), 0); memset(cmd_buf, 0, 0x100000); @@ -18,84 +18,106 @@ void RDP::Reset() { memset(cmd_buf, 0, 0x100000); } -template<> void RDP::WriteRDRAM(size_t idx, u8 v) { +template <> +void RDP::WriteRDRAM(size_t idx, u8 v) { size_t real = BYTE_ADDRESS(idx); - if(real < RDRAM_SIZE) { + if (real < RDRAM_SIZE) { rdram[real] = v; } } -template<> void RDP::WriteRDRAM(size_t idx, u16 v) { +template <> +void RDP::WriteRDRAM(size_t idx, u16 v) { size_t real = HALF_ADDRESS(idx); - if(real < RDRAM_SIZE) { + if (real < RDRAM_SIZE) { Util::WriteAccess(rdram, real, v); } } -template<> void RDP::WriteRDRAM(size_t idx, u32 v) { - if(idx < RDRAM_SIZE) { +template <> +void RDP::WriteRDRAM(size_t idx, u32 v) { + if (idx < RDRAM_SIZE) { Util::WriteAccess(rdram, idx, v); } } -template<> void RDP::WriteRDRAM(size_t idx, u64 v) { - if(idx < RDRAM_SIZE) { +template <> +void RDP::WriteRDRAM(size_t idx, u64 v) { + if (idx < RDRAM_SIZE) { Util::WriteAccess(rdram, idx, v); } } -template<> u8 RDP::ReadRDRAM(size_t idx) { +template <> +u8 RDP::ReadRDRAM(size_t idx) { size_t real = BYTE_ADDRESS(idx); - if(real >= RDRAM_SIZE) return 0; + if (real >= RDRAM_SIZE) + return 0; return rdram[real]; } -template<> u16 RDP::ReadRDRAM(size_t idx) { +template <> +u16 RDP::ReadRDRAM(size_t idx) { size_t real = HALF_ADDRESS(idx); - if(real >= RDRAM_SIZE) return 0; + if (real >= RDRAM_SIZE) + return 0; return Util::ReadAccess(rdram, real); } -template<> u32 RDP::ReadRDRAM(size_t idx) { - if(idx >= RDRAM_SIZE) return 0; +template <> +u32 RDP::ReadRDRAM(size_t idx) { + if (idx >= RDRAM_SIZE) + return 0; return Util::ReadAccess(rdram, idx); } -template<> u64 RDP::ReadRDRAM(size_t idx) { - if(idx >= RDRAM_SIZE) return 0; +template <> +u64 RDP::ReadRDRAM(size_t idx) { + if (idx >= RDRAM_SIZE) + return 0; return Util::ReadAccess(rdram, idx); } -static const int cmd_lens[64] = { - 2, 2, 2, 2, 2, 2, 2, 2, 8, 12, 24, 28, 24, 28, 40, 44, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 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 -}; +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 { - switch(addr) { - case 0x04100000: return dpc.start; - case 0x04100004: return dpc.end; - case 0x04100008: return dpc.current; - case 0x0410000C: - return dpc.status.raw; - case 0x04100010: return dpc.clock; - case 0x04100014: return dpc.status.cmdBusy; - case 0x04100018: return dpc.status.pipeBusy; - case 0x0410001C: return dpc.tmem; - default: - Util::panic("Unhandled DP Command Registers read (addr: {:08X})", addr); + switch (addr) { + case 0x04100000: + return dpc.start; + case 0x04100004: + return dpc.end; + case 0x04100008: + return dpc.current; + case 0x0410000C: + return dpc.status.raw; + case 0x04100010: + return dpc.clock; + case 0x04100014: + return dpc.status.cmdBusy; + case 0x04100018: + return dpc.status.pipeBusy; + case 0x0410001C: + return dpc.tmem; + default: + Util::panic("Unhandled DP Command Registers read (addr: {:08X})", addr); } } void RDP::Write(u32 addr, u32 val) { - switch(addr) { - case 0x04100000: WriteStart(val); break; - case 0x04100004: WriteEnd(val); break; - case 0x0410000C: WriteStatus(val); break; - default: - Util::panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val); + switch (addr) { + case 0x04100000: + WriteStart(val); + break; + case 0x04100004: + WriteEnd(val); + break; + case 0x0410000C: + WriteStatus(val); + break; + default: + Util::panic("Unhandled DP Command Registers write (addr: {:08X}, val: {:08X})", addr, val); } } @@ -104,20 +126,21 @@ void RDP::WriteStatus(u32 val) { temp.raw = val; CLEAR_SET(dpc.status.xbusDmemDma, temp.clearXbusDmemDma, temp.setXbusDmemDma); - if(temp.clearFreeze) { + if (temp.clearFreeze) { dpc.status.freeze = false; } - if(temp.setFreeze) { + if (temp.setFreeze) { dpc.status.freeze = true; } CLEAR_SET(dpc.status.flush, temp.clearFlush, temp.setFlush); CLEAR_SET(dpc.status.cmdBusy, temp.clearCmd, false); - if(temp.clearClock) dpc.clock = 0; + if (temp.clearClock) + dpc.clock = 0; CLEAR_SET(dpc.status.pipeBusy, temp.clearPipe, false); CLEAR_SET(dpc.status.tmemBusy, temp.clearTmem, false); - if(!dpc.status.freeze) { + if (!dpc.status.freeze) { RunCommand(); } } @@ -169,7 +192,7 @@ void RDP::RunCommand() { } dpc.status.pipeBusy = true; dpc.status.startGclk = true; - if(dpc.end > dpc.current) { + if (dpc.end > dpc.current) { dpc.status.freeze = true; static int remaining_cmds = 0; @@ -178,7 +201,8 @@ void RDP::RunCommand() { const u32 end = dpc.end & 0xFFFFF8; int len = end - current; - if (len <= 0) return; + if (len <= 0) + return; if (len + (remaining_cmds * 4) > 0xFFFFF) { Util::panic("Too many RDP commands"); @@ -255,4 +279,4 @@ void RDP::OnFullSync() { dpc.status.cbufReady = false; mem.mmio.mi.InterruptRaise(MI::Interrupt::DP); } -} +} // namespace n64 diff --git a/src/backend/core/RDP.hpp b/src/backend/core/RDP.hpp index e3f56dd7..03b2873c 100644 --- a/src/backend/core/RDP.hpp +++ b/src/backend/core/RDP.hpp @@ -13,32 +13,32 @@ struct Registers; union DPCStatusWrite { u32 raw; struct { - unsigned clearXbusDmemDma:1; - unsigned setXbusDmemDma:1; - unsigned clearFreeze:1; - unsigned setFreeze:1; - unsigned clearFlush:1; - unsigned setFlush:1; - unsigned clearTmem:1; - unsigned clearPipe:1; - unsigned clearCmd:1; - unsigned clearClock:1; + unsigned clearXbusDmemDma : 1; + unsigned setXbusDmemDma : 1; + unsigned clearFreeze : 1; + unsigned setFreeze : 1; + unsigned clearFlush : 1; + unsigned setFlush : 1; + unsigned clearTmem : 1; + unsigned clearPipe : 1; + unsigned clearCmd : 1; + unsigned clearClock : 1; }; }; union DPCStatus { struct { - unsigned xbusDmemDma:1; - unsigned freeze:1; - unsigned flush:1; - unsigned startGclk:1; - unsigned tmemBusy:1; - unsigned pipeBusy:1; - unsigned cmdBusy:1; - unsigned cbufReady:1; - unsigned dmaBusy:1; - unsigned endValid:1; - unsigned startValid:1; + unsigned xbusDmemDma : 1; + unsigned freeze : 1; + unsigned flush : 1; + unsigned startGclk : 1; + unsigned tmemBusy : 1; + unsigned pipeBusy : 1; + unsigned cmdBusy : 1; + unsigned cbufReady : 1; + unsigned dmaBusy : 1; + unsigned endValid : 1; + unsigned startValid : 1; }; u32 raw; }; @@ -56,7 +56,7 @@ struct RDP { DPC dpc{}; u32 cmd_buf[0xFFFFF]{}; - RDP(Mem&, ParallelRDP&); + RDP(Mem &, ParallelRDP &); void Reset(); [[nodiscard]] auto Read(u32 addr) const -> u32; @@ -66,7 +66,7 @@ struct RDP { void OnFullSync(); FORCE_INLINE void WriteStart(u32 val) { - if(!dpc.status.startValid) { + if (!dpc.status.startValid) { dpc.start = val & 0xFFFFF8; } dpc.status.startValid = true; @@ -74,23 +74,24 @@ struct RDP { FORCE_INLINE void WriteEnd(u32 val) { dpc.end = val & 0xFFFFF8; - if(dpc.status.startValid) { + if (dpc.status.startValid) { dpc.current = dpc.start; dpc.status.startValid = false; } RunCommand(); } - template + template void WriteRDRAM(size_t, T); - template + template T ReadRDRAM(size_t); + private: friend struct Mem; friend struct MMIO; std::vector rdram{}; - Mem& mem; - ParallelRDP& parallel; + Mem &mem; + ParallelRDP ∥ }; -} // backend +} // namespace n64 diff --git a/src/backend/core/RSP.cpp b/src/backend/core/RSP.cpp index e70a4f39..d24d06b6 100644 --- a/src/backend/core/RSP.cpp +++ b/src/backend/core/RSP.cpp @@ -177,14 +177,14 @@ void RSP::Write(u32 addr, u32 val) { switch (addr) { case 0x04040000: spDMASPAddr.raw = val & 0x1FF8; break; case 0x04040004: spDMADRAMAddr.raw = val & 0xFFFFFC; break; - case 0x04040008: { + case 0x04040008: spDMALen.raw = val; DMA(); - } break; - case 0x0404000C: { + break; + case 0x0404000C: spDMALen.raw = val; DMA(); - } break; + break; case 0x04040010: WriteStatus(val); break; case 0x0404001C: ReleaseSemaphore(); break; case 0x04080000: diff --git a/src/backend/core/RSP.hpp b/src/backend/core/RSP.hpp index 692d8f0f..04566227 100644 --- a/src/backend/core/RSP.hpp +++ b/src/backend/core/RSP.hpp @@ -1,93 +1,103 @@ #pragma once -#include -#include -#include #include +#include #include +#include +#include #define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF]) #define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) -#define SET_RSP_HALF(addr, value) do { RSP_BYTE(addr) = ((value) >> 8) & 0xFF; RSP_BYTE((addr) + 1) = (value) & 0xFF;} while(0) +#define SET_RSP_HALF(addr, value) \ + do { \ + RSP_BYTE(addr) = ((value) >> 8) & 0xFF; \ + RSP_BYTE((addr) + 1) = (value) & 0xFF; \ + } \ + while (0) #define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2)) -#define SET_RSP_WORD(addr, value) do { SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); SET_RSP_HALF((addr) + 2, (value) & 0xFFFF);} while(0) +#define SET_RSP_WORD(addr, value) \ + do { \ + SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); \ + SET_RSP_HALF((addr) + 2, (value) & 0xFFFF); \ + } \ + while (0) namespace n64 { union SPStatus { u32 raw; struct { - unsigned halt:1; - unsigned broke:1; - unsigned dmaBusy:1; - unsigned dmaFull:1; - unsigned ioFull:1; - unsigned singleStep:1; - unsigned interruptOnBreak:1; - unsigned signal0:1; - unsigned signal1:1; - unsigned signal2:1; - unsigned signal3:1; - unsigned signal4:1; - unsigned signal5:1; - unsigned signal6:1; - unsigned signal7:1; - unsigned:17; + unsigned halt : 1; + unsigned broke : 1; + unsigned dmaBusy : 1; + unsigned dmaFull : 1; + unsigned ioFull : 1; + unsigned singleStep : 1; + unsigned interruptOnBreak : 1; + unsigned signal0 : 1; + unsigned signal1 : 1; + unsigned signal2 : 1; + unsigned signal3 : 1; + unsigned signal4 : 1; + unsigned signal5 : 1; + unsigned signal6 : 1; + unsigned signal7 : 1; + unsigned : 17; }; }; union SPStatusWrite { u32 raw; struct { - unsigned clearHalt:1; - unsigned setHalt:1; - unsigned clearBroke:1; - unsigned clearIntr:1; - unsigned setIntr:1; - unsigned clearSstep:1; - unsigned setSstep:1; - unsigned clearIntrOnBreak:1; - unsigned setIntrOnBreak:1; - unsigned clearSignal0:1; - unsigned setSignal0:1; - unsigned clearSignal1:1; - unsigned setSignal1:1; - unsigned clearSignal2:1; - unsigned setSignal2:1; - unsigned clearSignal3:1; - unsigned setSignal3:1; - unsigned clearSignal4:1; - unsigned setSignal4:1; - unsigned clearSignal5:1; - unsigned setSignal5:1; - unsigned clearSignal6:1; - unsigned setSignal6:1; - unsigned clearSignal7:1; - unsigned setSignal7:1; - unsigned:7; + unsigned clearHalt : 1; + unsigned setHalt : 1; + unsigned clearBroke : 1; + unsigned clearIntr : 1; + unsigned setIntr : 1; + unsigned clearSstep : 1; + unsigned setSstep : 1; + unsigned clearIntrOnBreak : 1; + unsigned setIntrOnBreak : 1; + unsigned clearSignal0 : 1; + unsigned setSignal0 : 1; + unsigned clearSignal1 : 1; + unsigned setSignal1 : 1; + unsigned clearSignal2 : 1; + unsigned setSignal2 : 1; + unsigned clearSignal3 : 1; + unsigned setSignal3 : 1; + unsigned clearSignal4 : 1; + unsigned setSignal4 : 1; + unsigned clearSignal5 : 1; + unsigned setSignal5 : 1; + unsigned clearSignal6 : 1; + unsigned setSignal6 : 1; + unsigned clearSignal7 : 1; + unsigned setSignal7 : 1; + unsigned : 7; }; }; union SPDMALen { struct { - unsigned len:12; - unsigned count:8; - unsigned skip:12; + unsigned len : 12; + unsigned count : 8; + unsigned skip : 12; }; u32 raw; }; union SPDMASPAddr { struct { - unsigned address:12; - unsigned bank:1; - unsigned: 19; + unsigned address : 12; + unsigned bank : 1; + unsigned : 19; }; u32 raw; }; union SPDMADRAMAddr { struct { - unsigned address:24; - unsigned:8; + unsigned address : 24; + unsigned : 8; }; u32 raw; }; @@ -106,13 +116,17 @@ struct Mem; struct Registers; #define DE(x) (((x) >> 11) & 0x1F) -#define CLEAR_SET(val, clear, set) do { \ - if(clear && !set) (val) = 0; \ - if(set && !clear) (val) = 1; \ -} while(0) +#define CLEAR_SET(val, clear, set) \ + do { \ + if (clear && !set) \ + (val) = 0; \ + if (set && !clear) \ + (val) = 1; \ + } \ + while (0) struct RSP { - RSP(Mem&, Registers&); + RSP(Mem &, Registers &); void Reset(); FORCE_INLINE void Step() { @@ -161,10 +175,10 @@ struct RSP { FORCE_INLINE s64 GetACC(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; - if((val & 0x0000800000000000) != 0) { - val |= 0xFFFF000000000000; + val |= u64(acc.m.element[e]) << 16; + val |= u64(acc.l.element[e]) << 00; + if ((val & 0x0000800000000000) != 0) { + val |= 0xFFFF000000000000; } return val; } @@ -199,7 +213,7 @@ struct RSP { FORCE_INLINE u8 GetVCE() const { u8 value = 0; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { bool l = vce.element[ELEMENT_INDEX(i)] != 0; value |= (l << i); } @@ -237,7 +251,7 @@ struct RSP { } FORCE_INLINE bool AcquireSemaphore() { - if(semaphore) { + if (semaphore) { return true; } else { semaphore = true; @@ -245,9 +259,7 @@ struct RSP { } } - FORCE_INLINE void ReleaseSemaphore() { - semaphore = false; - } + FORCE_INLINE void ReleaseSemaphore() { semaphore = false; } void add(u32 instr); void addi(u32 instr); @@ -352,7 +364,7 @@ struct RSP { void vor(u32 instr); void vnor(u32 instr); void vzero(u32 instr); - void mfc0(RDP& rdp, u32 instr); + void mfc0(RDP &rdp, u32 instr); void mtc0(u32 instr); void mfc2(u32 instr); void mtc2(u32 instr); @@ -360,17 +372,18 @@ struct RSP { template void DMA(); void WriteStatus(u32 value); + private: - Registers& regs; - Mem& mem; + Registers ®s; + Mem &mem; FORCE_INLINE void branch(u16 address, bool cond) { - if(cond) { + if (cond) { nextPC = address & 0xFFC; } } FORCE_INLINE void branch_likely(u16 address, bool cond) { - if(cond) { + if (cond) { nextPC = address & 0xFFC; } else { pc = nextPC & 0xFFC; @@ -378,4 +391,4 @@ private: } } }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/RSQ.hpp b/src/backend/core/RSQ.hpp index 73ebe0bb..dfbcb781 100644 --- a/src/backend/core/RSQ.hpp +++ b/src/backend/core/RSQ.hpp @@ -2,36 +2,40 @@ #include static constexpr u16 rsqRom[] = { - 0xffff, 0xff00, 0xfe02, 0xfd06, 0xfc0b, 0xfb12, 0xfa1a, 0xf923, 0xf82e, 0xf73b, 0xf648, 0xf557, 0xf467, 0xf379, 0xf28c, 0xf1a0, - 0xf0b6, 0xefcd, 0xeee5, 0xedff, 0xed19, 0xec35, 0xeb52, 0xea71, 0xe990, 0xe8b1, 0xe7d3, 0xe6f6, 0xe61b, 0xe540, 0xe467, 0xe38e, - 0xe2b7, 0xe1e1, 0xe10d, 0xe039, 0xdf66, 0xde94, 0xddc4, 0xdcf4, 0xdc26, 0xdb59, 0xda8c, 0xd9c1, 0xd8f7, 0xd82d, 0xd765, 0xd69e, - 0xd5d7, 0xd512, 0xd44e, 0xd38a, 0xd2c8, 0xd206, 0xd146, 0xd086, 0xcfc7, 0xcf0a, 0xce4d, 0xcd91, 0xccd6, 0xcc1b, 0xcb62, 0xcaa9, - 0xc9f2, 0xc93b, 0xc885, 0xc7d0, 0xc71c, 0xc669, 0xc5b6, 0xc504, 0xc453, 0xc3a3, 0xc2f4, 0xc245, 0xc198, 0xc0eb, 0xc03f, 0xbf93, - 0xbee9, 0xbe3f, 0xbd96, 0xbced, 0xbc46, 0xbb9f, 0xbaf8, 0xba53, 0xb9ae, 0xb90a, 0xb867, 0xb7c5, 0xb723, 0xb681, 0xb5e1, 0xb541, - 0xb4a2, 0xb404, 0xb366, 0xb2c9, 0xb22c, 0xb191, 0xb0f5, 0xb05b, 0xafc1, 0xaf28, 0xae8f, 0xadf7, 0xad60, 0xacc9, 0xac33, 0xab9e, - 0xab09, 0xaa75, 0xa9e1, 0xa94e, 0xa8bc, 0xa82a, 0xa799, 0xa708, 0xa678, 0xa5e8, 0xa559, 0xa4cb, 0xa43d, 0xa3b0, 0xa323, 0xa297, - 0xa20b, 0xa180, 0xa0f6, 0xa06c, 0x9fe2, 0x9f59, 0x9ed1, 0x9e49, 0x9dc2, 0x9d3b, 0x9cb4, 0x9c2f, 0x9ba9, 0x9b25, 0x9aa0, 0x9a1c, - 0x9999, 0x9916, 0x9894, 0x9812, 0x9791, 0x9710, 0x968f, 0x960f, 0x9590, 0x9511, 0x9492, 0x9414, 0x9397, 0x931a, 0x929d, 0x9221, - 0x91a5, 0x9129, 0x90af, 0x9034, 0x8fba, 0x8f40, 0x8ec7, 0x8e4f, 0x8dd6, 0x8d5e, 0x8ce7, 0x8c70, 0x8bf9, 0x8b83, 0x8b0d, 0x8a98, - 0x8a23, 0x89ae, 0x893a, 0x88c6, 0x8853, 0x87e0, 0x876d, 0x86fb, 0x8689, 0x8618, 0x85a7, 0x8536, 0x84c6, 0x8456, 0x83e7, 0x8377, - 0x8309, 0x829a, 0x822c, 0x81bf, 0x8151, 0x80e4, 0x8078, 0x800c, 0x7fa0, 0x7f34, 0x7ec9, 0x7e5e, 0x7df4, 0x7d8a, 0x7d20, 0x7cb6, - 0x7c4d, 0x7be5, 0x7b7c, 0x7b14, 0x7aac, 0x7a45, 0x79de, 0x7977, 0x7911, 0x78ab, 0x7845, 0x77df, 0x777a, 0x7715, 0x76b1, 0x764d, - 0x75e9, 0x7585, 0x7522, 0x74bf, 0x745d, 0x73fa, 0x7398, 0x7337, 0x72d5, 0x7274, 0x7213, 0x71b3, 0x7152, 0x70f2, 0x7093, 0x7033, - 0x6fd4, 0x6f76, 0x6f17, 0x6eb9, 0x6e5b, 0x6dfd, 0x6da0, 0x6d43, 0x6ce6, 0x6c8a, 0x6c2d, 0x6bd1, 0x6b76, 0x6b1a, 0x6abf, 0x6a64, - 0x6a09, 0x6955, 0x68a1, 0x67ef, 0x673e, 0x668d, 0x65de, 0x6530, 0x6482, 0x63d6, 0x632b, 0x6280, 0x61d7, 0x612e, 0x6087, 0x5fe0, - 0x5f3a, 0x5e95, 0x5df1, 0x5d4e, 0x5cac, 0x5c0b, 0x5b6b, 0x5acb, 0x5a2c, 0x598f, 0x58f2, 0x5855, 0x57ba, 0x5720, 0x5686, 0x55ed, - 0x5555, 0x54be, 0x5427, 0x5391, 0x52fc, 0x5268, 0x51d5, 0x5142, 0x50b0, 0x501f, 0x4f8e, 0x4efe, 0x4e6f, 0x4de1, 0x4d53, 0x4cc6, - 0x4c3a, 0x4baf, 0x4b24, 0x4a9a, 0x4a10, 0x4987, 0x48ff, 0x4878, 0x47f1, 0x476b, 0x46e5, 0x4660, 0x45dc, 0x4558, 0x44d5, 0x4453, - 0x43d1, 0x434f, 0x42cf, 0x424f, 0x41cf, 0x4151, 0x40d2, 0x4055, 0x3fd8, 0x3f5b, 0x3edf, 0x3e64, 0x3de9, 0x3d6e, 0x3cf5, 0x3c7c, - 0x3c03, 0x3b8b, 0x3b13, 0x3a9c, 0x3a26, 0x39b0, 0x393a, 0x38c5, 0x3851, 0x37dd, 0x3769, 0x36f6, 0x3684, 0x3612, 0x35a0, 0x352f, - 0x34bf, 0x344f, 0x33df, 0x3370, 0x3302, 0x3293, 0x3226, 0x31b9, 0x314c, 0x30df, 0x3074, 0x3008, 0x2f9d, 0x2f33, 0x2ec8, 0x2e5f, - 0x2df6, 0x2d8d, 0x2d24, 0x2cbc, 0x2c55, 0x2bee, 0x2b87, 0x2b21, 0x2abb, 0x2a55, 0x29f0, 0x298b, 0x2927, 0x28c3, 0x2860, 0x27fd, - 0x279a, 0x2738, 0x26d6, 0x2674, 0x2613, 0x25b2, 0x2552, 0x24f2, 0x2492, 0x2432, 0x23d3, 0x2375, 0x2317, 0x22b9, 0x225b, 0x21fe, - 0x21a1, 0x2145, 0x20e8, 0x208d, 0x2031, 0x1fd6, 0x1f7b, 0x1f21, 0x1ec7, 0x1e6d, 0x1e13, 0x1dba, 0x1d61, 0x1d09, 0x1cb1, 0x1c59, - 0x1c01, 0x1baa, 0x1b53, 0x1afc, 0x1aa6, 0x1a50, 0x19fa, 0x19a5, 0x1950, 0x18fb, 0x18a7, 0x1853, 0x17ff, 0x17ab, 0x1758, 0x1705, - 0x16b2, 0x1660, 0x160d, 0x15bc, 0x156a, 0x1519, 0x14c8, 0x1477, 0x1426, 0x13d6, 0x1386, 0x1337, 0x12e7, 0x1298, 0x1249, 0x11fb, - 0x11ac, 0x115e, 0x1111, 0x10c3, 0x1076, 0x1029, 0x0fdc, 0x0f8f, 0x0f43, 0x0ef7, 0x0eab, 0x0e60, 0x0e15, 0x0dca, 0x0d7f, 0x0d34, - 0x0cea, 0x0ca0, 0x0c56, 0x0c0c, 0x0bc3, 0x0b7a, 0x0b31, 0x0ae8, 0x0aa0, 0x0a58, 0x0a10, 0x09c8, 0x0981, 0x0939, 0x08f2, 0x08ab, - 0x0865, 0x081e, 0x07d8, 0x0792, 0x074d, 0x0707, 0x06c2, 0x067d, 0x0638, 0x05f3, 0x05af, 0x056a, 0x0526, 0x04e2, 0x049f, 0x045b, - 0x0418, 0x03d5, 0x0392, 0x0350, 0x030d, 0x02cb, 0x0289, 0x0247, 0x0206, 0x01c4, 0x0183, 0x0142, 0x0101, 0x00c0, 0x0080, 0x0040 -}; \ No newline at end of file + 0xffff, 0xff00, 0xfe02, 0xfd06, 0xfc0b, 0xfb12, 0xfa1a, 0xf923, 0xf82e, 0xf73b, 0xf648, 0xf557, 0xf467, 0xf379, + 0xf28c, 0xf1a0, 0xf0b6, 0xefcd, 0xeee5, 0xedff, 0xed19, 0xec35, 0xeb52, 0xea71, 0xe990, 0xe8b1, 0xe7d3, 0xe6f6, + 0xe61b, 0xe540, 0xe467, 0xe38e, 0xe2b7, 0xe1e1, 0xe10d, 0xe039, 0xdf66, 0xde94, 0xddc4, 0xdcf4, 0xdc26, 0xdb59, + 0xda8c, 0xd9c1, 0xd8f7, 0xd82d, 0xd765, 0xd69e, 0xd5d7, 0xd512, 0xd44e, 0xd38a, 0xd2c8, 0xd206, 0xd146, 0xd086, + 0xcfc7, 0xcf0a, 0xce4d, 0xcd91, 0xccd6, 0xcc1b, 0xcb62, 0xcaa9, 0xc9f2, 0xc93b, 0xc885, 0xc7d0, 0xc71c, 0xc669, + 0xc5b6, 0xc504, 0xc453, 0xc3a3, 0xc2f4, 0xc245, 0xc198, 0xc0eb, 0xc03f, 0xbf93, 0xbee9, 0xbe3f, 0xbd96, 0xbced, + 0xbc46, 0xbb9f, 0xbaf8, 0xba53, 0xb9ae, 0xb90a, 0xb867, 0xb7c5, 0xb723, 0xb681, 0xb5e1, 0xb541, 0xb4a2, 0xb404, + 0xb366, 0xb2c9, 0xb22c, 0xb191, 0xb0f5, 0xb05b, 0xafc1, 0xaf28, 0xae8f, 0xadf7, 0xad60, 0xacc9, 0xac33, 0xab9e, + 0xab09, 0xaa75, 0xa9e1, 0xa94e, 0xa8bc, 0xa82a, 0xa799, 0xa708, 0xa678, 0xa5e8, 0xa559, 0xa4cb, 0xa43d, 0xa3b0, + 0xa323, 0xa297, 0xa20b, 0xa180, 0xa0f6, 0xa06c, 0x9fe2, 0x9f59, 0x9ed1, 0x9e49, 0x9dc2, 0x9d3b, 0x9cb4, 0x9c2f, + 0x9ba9, 0x9b25, 0x9aa0, 0x9a1c, 0x9999, 0x9916, 0x9894, 0x9812, 0x9791, 0x9710, 0x968f, 0x960f, 0x9590, 0x9511, + 0x9492, 0x9414, 0x9397, 0x931a, 0x929d, 0x9221, 0x91a5, 0x9129, 0x90af, 0x9034, 0x8fba, 0x8f40, 0x8ec7, 0x8e4f, + 0x8dd6, 0x8d5e, 0x8ce7, 0x8c70, 0x8bf9, 0x8b83, 0x8b0d, 0x8a98, 0x8a23, 0x89ae, 0x893a, 0x88c6, 0x8853, 0x87e0, + 0x876d, 0x86fb, 0x8689, 0x8618, 0x85a7, 0x8536, 0x84c6, 0x8456, 0x83e7, 0x8377, 0x8309, 0x829a, 0x822c, 0x81bf, + 0x8151, 0x80e4, 0x8078, 0x800c, 0x7fa0, 0x7f34, 0x7ec9, 0x7e5e, 0x7df4, 0x7d8a, 0x7d20, 0x7cb6, 0x7c4d, 0x7be5, + 0x7b7c, 0x7b14, 0x7aac, 0x7a45, 0x79de, 0x7977, 0x7911, 0x78ab, 0x7845, 0x77df, 0x777a, 0x7715, 0x76b1, 0x764d, + 0x75e9, 0x7585, 0x7522, 0x74bf, 0x745d, 0x73fa, 0x7398, 0x7337, 0x72d5, 0x7274, 0x7213, 0x71b3, 0x7152, 0x70f2, + 0x7093, 0x7033, 0x6fd4, 0x6f76, 0x6f17, 0x6eb9, 0x6e5b, 0x6dfd, 0x6da0, 0x6d43, 0x6ce6, 0x6c8a, 0x6c2d, 0x6bd1, + 0x6b76, 0x6b1a, 0x6abf, 0x6a64, 0x6a09, 0x6955, 0x68a1, 0x67ef, 0x673e, 0x668d, 0x65de, 0x6530, 0x6482, 0x63d6, + 0x632b, 0x6280, 0x61d7, 0x612e, 0x6087, 0x5fe0, 0x5f3a, 0x5e95, 0x5df1, 0x5d4e, 0x5cac, 0x5c0b, 0x5b6b, 0x5acb, + 0x5a2c, 0x598f, 0x58f2, 0x5855, 0x57ba, 0x5720, 0x5686, 0x55ed, 0x5555, 0x54be, 0x5427, 0x5391, 0x52fc, 0x5268, + 0x51d5, 0x5142, 0x50b0, 0x501f, 0x4f8e, 0x4efe, 0x4e6f, 0x4de1, 0x4d53, 0x4cc6, 0x4c3a, 0x4baf, 0x4b24, 0x4a9a, + 0x4a10, 0x4987, 0x48ff, 0x4878, 0x47f1, 0x476b, 0x46e5, 0x4660, 0x45dc, 0x4558, 0x44d5, 0x4453, 0x43d1, 0x434f, + 0x42cf, 0x424f, 0x41cf, 0x4151, 0x40d2, 0x4055, 0x3fd8, 0x3f5b, 0x3edf, 0x3e64, 0x3de9, 0x3d6e, 0x3cf5, 0x3c7c, + 0x3c03, 0x3b8b, 0x3b13, 0x3a9c, 0x3a26, 0x39b0, 0x393a, 0x38c5, 0x3851, 0x37dd, 0x3769, 0x36f6, 0x3684, 0x3612, + 0x35a0, 0x352f, 0x34bf, 0x344f, 0x33df, 0x3370, 0x3302, 0x3293, 0x3226, 0x31b9, 0x314c, 0x30df, 0x3074, 0x3008, + 0x2f9d, 0x2f33, 0x2ec8, 0x2e5f, 0x2df6, 0x2d8d, 0x2d24, 0x2cbc, 0x2c55, 0x2bee, 0x2b87, 0x2b21, 0x2abb, 0x2a55, + 0x29f0, 0x298b, 0x2927, 0x28c3, 0x2860, 0x27fd, 0x279a, 0x2738, 0x26d6, 0x2674, 0x2613, 0x25b2, 0x2552, 0x24f2, + 0x2492, 0x2432, 0x23d3, 0x2375, 0x2317, 0x22b9, 0x225b, 0x21fe, 0x21a1, 0x2145, 0x20e8, 0x208d, 0x2031, 0x1fd6, + 0x1f7b, 0x1f21, 0x1ec7, 0x1e6d, 0x1e13, 0x1dba, 0x1d61, 0x1d09, 0x1cb1, 0x1c59, 0x1c01, 0x1baa, 0x1b53, 0x1afc, + 0x1aa6, 0x1a50, 0x19fa, 0x19a5, 0x1950, 0x18fb, 0x18a7, 0x1853, 0x17ff, 0x17ab, 0x1758, 0x1705, 0x16b2, 0x1660, + 0x160d, 0x15bc, 0x156a, 0x1519, 0x14c8, 0x1477, 0x1426, 0x13d6, 0x1386, 0x1337, 0x12e7, 0x1298, 0x1249, 0x11fb, + 0x11ac, 0x115e, 0x1111, 0x10c3, 0x1076, 0x1029, 0x0fdc, 0x0f8f, 0x0f43, 0x0ef7, 0x0eab, 0x0e60, 0x0e15, 0x0dca, + 0x0d7f, 0x0d34, 0x0cea, 0x0ca0, 0x0c56, 0x0c0c, 0x0bc3, 0x0b7a, 0x0b31, 0x0ae8, 0x0aa0, 0x0a58, 0x0a10, 0x09c8, + 0x0981, 0x0939, 0x08f2, 0x08ab, 0x0865, 0x081e, 0x07d8, 0x0792, 0x074d, 0x0707, 0x06c2, 0x067d, 0x0638, 0x05f3, + 0x05af, 0x056a, 0x0526, 0x04e2, 0x049f, 0x045b, 0x0418, 0x03d5, 0x0392, 0x0350, 0x030d, 0x02cb, 0x0289, 0x0247, + 0x0206, 0x01c4, 0x0183, 0x0142, 0x0101, 0x00c0, 0x0080, 0x0040}; diff --git a/src/backend/core/interpreter/decode.cpp b/src/backend/core/interpreter/decode.cpp index 878c18ba..11ea44ed 100644 --- a/src/backend/core/interpreter/decode.cpp +++ b/src/backend/core/interpreter/decode.cpp @@ -1,70 +1,172 @@ +#include #include #include -#include namespace n64 { void Interpreter::special(u32 instr) { u8 mask = (instr & 0x3F); // 00rr_rccc switch (mask) { // TODO: named constants for clearer code - case SLL: - if (instr != 0) { - sll(instr); - } - break; - case SRL: srl(instr); break; - case SRA: sra(instr); break; - case SLLV: sllv(instr); break; - case SRLV: srlv(instr); break; - case SRAV: srav(instr); break; - case JR: jr(instr); break; - case JALR: jalr(instr); break; - case SYSCALL: regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); break; - case BREAK: regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); break; - case SYNC: break; // SYNC - case MFHI: mfhi(instr); break; - case MTHI: mthi(instr); break; - case MFLO: mflo(instr); break; - case MTLO: mtlo(instr); break; - case DSLLV: dsllv(instr); break; - case DSRLV: dsrlv(instr); break; - case DSRAV: dsrav(instr); break; - case MULT: mult(instr); break; - case MULTU: multu(instr); break; - case DIV: div(instr); break; - case DIVU: divu(instr); break; - case DMULT: dmult(instr); break; - case DMULTU: dmultu(instr); break; - case DDIV: ddiv(instr); break; - case DDIVU: ddivu(instr); break; - case ADD: add(instr); break; - case ADDU: addu(instr); break; - case SUB: sub(instr); break; - case SUBU: subu(instr); break; - case AND: and_(instr); break; - case OR: or_(instr); break; - case XOR: xor_(instr); break; - case NOR: nor(instr); break; - case SLT: slt(instr); break; - case SLTU: sltu(instr); break; - case DADD: dadd(instr); break; - case DADDU: daddu(instr); break; - case DSUB: dsub(instr); break; - case DSUBU: dsubu(instr); break; - case TGE: trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); break; - case TGEU: trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); break; - case TLT: trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); break; - case TLTU: trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); break; - case TEQ: trap(regs.Read(RS(instr)) == regs.Read(RT(instr))); break; - case TNE: trap(regs.Read(RS(instr)) != regs.Read(RT(instr))); break; - case DSLL: dsll(instr); break; - case DSRL: dsrl(instr); break; - case DSRA: dsra(instr); break; - case DSLL32: dsll32(instr); break; - case DSRL32: dsrl32(instr); break; - case DSRA32: dsra32(instr); break; - default: - Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC); + case SLL: + if (instr != 0) { + sll(instr); + } + break; + case SRL: + srl(instr); + break; + case SRA: + sra(instr); + break; + case SLLV: + sllv(instr); + break; + case SRLV: + srlv(instr); + break; + case SRAV: + srav(instr); + break; + case JR: + jr(instr); + break; + case JALR: + jalr(instr); + break; + case SYSCALL: + regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); + break; + case BREAK: + regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); + break; + case SYNC: + break; // SYNC + case MFHI: + mfhi(instr); + break; + case MTHI: + mthi(instr); + break; + case MFLO: + mflo(instr); + break; + case MTLO: + mtlo(instr); + break; + case DSLLV: + dsllv(instr); + break; + case DSRLV: + dsrlv(instr); + break; + case DSRAV: + dsrav(instr); + break; + case MULT: + mult(instr); + break; + case MULTU: + multu(instr); + break; + case DIV: + div(instr); + break; + case DIVU: + divu(instr); + break; + case DMULT: + dmult(instr); + break; + case DMULTU: + dmultu(instr); + break; + case DDIV: + ddiv(instr); + break; + case DDIVU: + ddivu(instr); + break; + case ADD: + add(instr); + break; + case ADDU: + addu(instr); + break; + case SUB: + sub(instr); + break; + case SUBU: + subu(instr); + break; + case AND: + and_(instr); + break; + case OR: + or_(instr); + break; + case XOR: + xor_(instr); + break; + case NOR: + nor(instr); + break; + case SLT: + slt(instr); + break; + case SLTU: + sltu(instr); + break; + case DADD: + dadd(instr); + break; + case DADDU: + daddu(instr); + break; + case DSUB: + dsub(instr); + break; + case DSUBU: + dsubu(instr); + break; + case TGE: + trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); + break; + case TGEU: + trap(regs.Read(RS(instr)) >= regs.Read(RT(instr))); + break; + case TLT: + trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); + break; + case TLTU: + trap(regs.Read(RS(instr)) < regs.Read(RT(instr))); + break; + case TEQ: + trap(regs.Read(RS(instr)) == regs.Read(RT(instr))); + break; + case TNE: + trap(regs.Read(RS(instr)) != regs.Read(RT(instr))); + break; + case DSLL: + dsll(instr); + break; + case DSRL: + dsrl(instr); + break; + case DSRA: + dsra(instr); + break; + case DSLL32: + dsll32(instr); + break; + case DSRL32: + dsrl32(instr); + break; + case DSRA32: + dsra32(instr); + break; + default: + Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr, + (u64)regs.oldPC); } } @@ -72,102 +174,249 @@ void Interpreter::regimm(u32 instr) { u8 mask = ((instr >> 16) & 0x1F); // 000r_rccc switch (mask) { // TODO: named constants for clearer code - case BLTZ: b(instr, regs.Read(RS(instr)) < 0); break; - case BGEZ: b(instr, regs.Read(RS(instr)) >= 0); break; - case BLTZL: bl(instr, regs.Read(RS(instr)) < 0); break; - case BGEZL: bl(instr, regs.Read(RS(instr)) >= 0); break; - case TGEI: trap(regs.Read(RS(instr)) >= s64(s16(instr))); break; - case TGEIU: trap(regs.Read(RS(instr)) >= u64(s64(s16(instr)))); break; - case TLTI: trap(regs.Read(RS(instr)) < s64(s16(instr))); break; - case TLTIU: trap(regs.Read(RS(instr)) < u64(s64(s16(instr)))); break; - case TEQI: trap(regs.Read(RS(instr)) == s64(s16(instr))); break; - case TNEI: trap(regs.Read(RS(instr)) != s64(s16(instr))); break; - case BLTZAL: blink(instr, regs.Read(RS(instr)) < 0); break; - case BGEZAL: blink(instr, regs.Read(RS(instr)) >= 0); break; - case BLTZALL: bllink(instr, regs.Read(RS(instr)) < 0); break; - case BGEZALL: bllink(instr, regs.Read(RS(instr)) >= 0); break; - default: - Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC); + case BLTZ: + b(instr, regs.Read(RS(instr)) < 0); + break; + case BGEZ: + b(instr, regs.Read(RS(instr)) >= 0); + break; + case BLTZL: + bl(instr, regs.Read(RS(instr)) < 0); + break; + case BGEZL: + bl(instr, regs.Read(RS(instr)) >= 0); + break; + case TGEI: + trap(regs.Read(RS(instr)) >= s64(s16(instr))); + break; + case TGEIU: + trap(regs.Read(RS(instr)) >= u64(s64(s16(instr)))); + break; + case TLTI: + trap(regs.Read(RS(instr)) < s64(s16(instr))); + break; + case TLTIU: + trap(regs.Read(RS(instr)) < u64(s64(s16(instr)))); + break; + case TEQI: + trap(regs.Read(RS(instr)) == s64(s16(instr))); + break; + case TNEI: + trap(regs.Read(RS(instr)) != s64(s16(instr))); + break; + case BLTZAL: + blink(instr, regs.Read(RS(instr)) < 0); + break; + case BGEZAL: + blink(instr, regs.Read(RS(instr)) >= 0); + break; + case BLTZALL: + bllink(instr, regs.Read(RS(instr)) < 0); + break; + case BGEZALL: + bllink(instr, regs.Read(RS(instr)) >= 0); + break; + default: + Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC); } } void Interpreter::cop2Decode(u32 instr) { - if(!regs.cop0.status.cu2) { + if (!regs.cop0.status.cu2) { regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC); return; } - switch(RS(instr)) { - case 0x00: mfc2(instr); break; - case 0x01: dmfc2(instr); break; - case 0x02: cfc2(instr); break; - case 0x04: mtc2(instr); break; - case 0x05: dmtc2(instr); break; - case 0x06: ctc2(instr); break; - default: - regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC); + switch (RS(instr)) { + case 0x00: + mfc2(instr); + break; + case 0x01: + dmfc2(instr); + break; + case 0x02: + cfc2(instr); + break; + case 0x04: + mtc2(instr); + break; + case 0x05: + dmtc2(instr); + break; + case 0x06: + ctc2(instr); + break; + default: + regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC); } } void Interpreter::Exec(u32 instr) { u8 mask = (instr >> 26) & 0x3f; // 00rr_rccc - switch(mask) { // TODO: named constants for clearer code - case SPECIAL: special(instr); break; - case REGIMM: regimm(instr); break; - case J: j(instr); break; - case JAL: jal(instr); break; - case BEQ: b(instr, regs.Read(RS(instr)) == regs.Read(RT(instr))); break; - case BNE: b(instr, regs.Read(RS(instr)) != regs.Read(RT(instr))); break; - case BLEZ: b(instr, regs.Read(RS(instr)) <= 0); break; - case BGTZ: b(instr, regs.Read(RS(instr)) > 0); break; - case ADDI: addi(instr); break; - case ADDIU: addiu(instr); break; - case SLTI: slti(instr); break; - case SLTIU: sltiu(instr); break; - case ANDI: andi(instr); break; - case ORI: ori(instr); break; - case XORI: xori(instr); break; - case LUI: lui(instr); break; - case COP0: regs.cop0.decode(*this, instr); break; - case COP1: regs.cop1.decode(*this, instr); break; - case COP2: cop2Decode(instr); break; - case BEQL: bl(instr, regs.Read(RS(instr)) == regs.Read(RT(instr))); break; - case BNEL: bl(instr, regs.Read(RS(instr)) != regs.Read(RT(instr))); break; - case BLEZL: bl(instr, regs.Read(RS(instr)) <= 0); break; - case BGTZL: bl(instr, regs.Read(RS(instr)) > 0); break; - case DADDI: daddi(instr); break; - case DADDIU: daddiu(instr); break; - case LDL: ldl(instr); break; - case LDR: ldr(instr); break; - case 0x1F: regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); break; - case LB: lb(instr); break; - case LH: lh(instr); break; - case LWL: lwl(instr); break; - case LW: lw(instr); break; - case LBU: lbu(instr); break; - case LHU: lhu(instr); break; - case LWR: lwr(instr); break; - case LWU: lwu(instr); break; - case SB: sb(instr); break; - case SH: sh(instr); break; - case SWL: swl(instr); break; - case SW: sw(instr); break; - case SDL: sdl(instr); break; - case SDR: sdr(instr); break; - case SWR: swr(instr); break; - case CACHE: break; // CACHE - case LL: ll(instr); break; - case LWC1: regs.cop1.lwc1(*this, mem, instr); break; - case LLD: lld(instr); break; - case LDC1: regs.cop1.ldc1(*this, mem, instr); break; - case LD: ld(instr); break; - case SC: sc(instr); break; - case SWC1: regs.cop1.swc1(*this, mem, instr); break; - case SCD: scd(instr); break; - case SDC1: regs.cop1.sdc1(*this, mem, instr); break; - case SD: sd(instr); break; - default: - Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, (u64)regs.oldPC); + switch (mask) { // TODO: named constants for clearer code + case SPECIAL: + special(instr); + break; + case REGIMM: + regimm(instr); + break; + case J: + j(instr); + break; + case JAL: + jal(instr); + break; + case BEQ: + b(instr, regs.Read(RS(instr)) == regs.Read(RT(instr))); + break; + case BNE: + b(instr, regs.Read(RS(instr)) != regs.Read(RT(instr))); + break; + case BLEZ: + b(instr, regs.Read(RS(instr)) <= 0); + break; + case BGTZ: + b(instr, regs.Read(RS(instr)) > 0); + break; + case ADDI: + addi(instr); + break; + case ADDIU: + addiu(instr); + break; + case SLTI: + slti(instr); + break; + case SLTIU: + sltiu(instr); + break; + case ANDI: + andi(instr); + break; + case ORI: + ori(instr); + break; + case XORI: + xori(instr); + break; + case LUI: + lui(instr); + break; + case COP0: + regs.cop0.decode(*this, instr); + break; + case COP1: + regs.cop1.decode(*this, instr); + break; + case COP2: + cop2Decode(instr); + break; + case BEQL: + bl(instr, regs.Read(RS(instr)) == regs.Read(RT(instr))); + break; + case BNEL: + bl(instr, regs.Read(RS(instr)) != regs.Read(RT(instr))); + break; + case BLEZL: + bl(instr, regs.Read(RS(instr)) <= 0); + break; + case BGTZL: + bl(instr, regs.Read(RS(instr)) > 0); + break; + case DADDI: + daddi(instr); + break; + case DADDIU: + daddiu(instr); + break; + case LDL: + ldl(instr); + break; + case LDR: + ldr(instr); + break; + case 0x1F: + regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); + break; + case LB: + lb(instr); + break; + case LH: + lh(instr); + break; + case LWL: + lwl(instr); + break; + case LW: + lw(instr); + break; + case LBU: + lbu(instr); + break; + case LHU: + lhu(instr); + break; + case LWR: + lwr(instr); + break; + case LWU: + lwu(instr); + break; + case SB: + sb(instr); + break; + case SH: + sh(instr); + break; + case SWL: + swl(instr); + break; + case SW: + sw(instr); + break; + case SDL: + sdl(instr); + break; + case SDR: + sdr(instr); + break; + case SWR: + swr(instr); + break; + case CACHE: + break; // CACHE + case LL: + ll(instr); + break; + case LWC1: + regs.cop1.lwc1(*this, mem, instr); + break; + case LLD: + lld(instr); + break; + case LDC1: + regs.cop1.ldc1(*this, mem, instr); + break; + case LD: + ld(instr); + break; + case SC: + sc(instr); + break; + case SWC1: + regs.cop1.swc1(*this, mem, instr); + break; + case SCD: + scd(instr); + break; + case SDC1: + regs.cop1.sdc1(*this, mem, instr); + break; + case SD: + sd(instr); + break; + default: + Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, (u64)regs.oldPC); } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index b31a2272..d2a65c8e 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -8,7 +8,7 @@ void Interpreter::add(u32 instr) { u32 rs = regs.Read(RS(instr)); u32 rt = regs.Read(RT(instr)); u32 result = rs + rt; - if(check_signed_overflow(rs, rt, result)) { + if (check_signed_overflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RD(instr), s32(result)); @@ -26,7 +26,7 @@ void Interpreter::addi(u32 instr) { u32 rs = regs.Read(RS(instr)); u32 imm = s32(s16(instr)); u32 result = rs + imm; - if(check_signed_overflow(rs, imm, result)) { + if (check_signed_overflow(rs, imm, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RT(instr), s32(result)); @@ -44,7 +44,7 @@ void Interpreter::dadd(u32 instr) { u64 rs = regs.Read(RS(instr)); u64 rt = regs.Read(RT(instr)); u64 result = rt + rs; - if(check_signed_overflow(rs, rt, result)) { + if (check_signed_overflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RD(instr), result); @@ -61,7 +61,7 @@ void Interpreter::daddi(u32 instr) { u64 imm = s64(s16(instr)); u64 rs = regs.Read(RS(instr)); u64 result = imm + rs; - if(check_signed_overflow(rs, imm, result)) { + if (check_signed_overflow(rs, imm, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RT(instr), result); @@ -78,9 +78,9 @@ void Interpreter::div(u32 instr) { s64 dividend = regs.Read(RS(instr)); s64 divisor = regs.Read(RT(instr)); - if(divisor == 0) { + if (divisor == 0) { regs.hi = dividend; - if(dividend >= 0) { + if (dividend >= 0) { regs.lo = s64(-1); } else { regs.lo = s64(1); @@ -96,7 +96,7 @@ void Interpreter::div(u32 instr) { void Interpreter::divu(u32 instr) { u32 dividend = regs.Read(RS(instr)); u32 divisor = regs.Read(RT(instr)); - if(divisor == 0) { + if (divisor == 0) { regs.lo = -1; regs.hi = (s32)dividend; } else { @@ -113,9 +113,9 @@ void Interpreter::ddiv(u32 instr) { if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { regs.lo = dividend; regs.hi = 0; - } else if(divisor == 0) { + } else if (divisor == 0) { regs.hi = dividend; - if(dividend >= 0) { + if (dividend >= 0) { regs.lo = -1; } else { regs.lo = 1; @@ -131,7 +131,7 @@ void Interpreter::ddiv(u32 instr) { void Interpreter::ddivu(u32 instr) { u64 dividend = regs.Read(RS(instr)); u64 divisor = regs.Read(RT(instr)); - if(divisor == 0) { + if (divisor == 0) { regs.lo = -1; regs.hi = (s64)dividend; } else { @@ -197,11 +197,11 @@ void Interpreter::lui(u32 instr) { void Interpreter::lb(u32 instr) { u64 address = regs.Read(RS(instr)) + (s16)instr; u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { - regs.Write(RT(instr), (s8) mem.Read(regs, paddr)); + regs.Write(RT(instr), (s8)mem.Read(regs, paddr)); } } @@ -214,11 +214,11 @@ void Interpreter::lh(u32 instr) { } u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { - regs.Write(RT(instr), (s16) mem.Read(regs, paddr)); + regs.Write(RT(instr), (s16)mem.Read(regs, paddr)); } } @@ -236,7 +236,7 @@ void Interpreter::lw(u32 instr) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { - regs.Write(RT(instr), (s32) mem.Read(regs, physical)); + regs.Write(RT(instr), (s32)mem.Read(regs, physical)); } } @@ -252,7 +252,7 @@ void Interpreter::ll(u32 instr) { regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC); return; } - + regs.Write(RT(instr), result); regs.cop0.llbit = true; @@ -263,7 +263,7 @@ void Interpreter::ll(u32 instr) { void Interpreter::lwl(u32 instr) { u64 address = regs.Read(RS(instr)) + (s16)instr; u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { @@ -278,7 +278,7 @@ void Interpreter::lwl(u32 instr) { void Interpreter::lwr(u32 instr) { u64 address = regs.Read(RS(instr)) + (s16)instr; u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { @@ -299,7 +299,7 @@ void Interpreter::ld(u32 instr) { } u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { @@ -340,7 +340,7 @@ void Interpreter::ldl(u32 instr) { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 data = mem.Read(regs, paddr & ~7); - s64 result = (s64) ((regs.Read(RT(instr)) & ~mask) | (data << shift)); + s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data << shift)); regs.Write(RT(instr), result); } } @@ -355,7 +355,7 @@ void Interpreter::ldr(u32 instr) { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 data = mem.Read(regs, paddr & ~7); - s64 result = (s64) ((regs.Read(RT(instr)) & ~mask) | (data >> shift)); + s64 result = (s64)((regs.Read(RT(instr)) & ~mask) | (data >> shift)); regs.Write(RT(instr), result); } } @@ -421,7 +421,7 @@ void Interpreter::sb(u32 instr) { void Interpreter::sc(u32 instr) { u64 address = regs.Read(RS(instr)) + (s16)instr; - if(regs.cop0.llbit) { + if (regs.cop0.llbit) { regs.cop0.llbit = false; if (check_address_error(0b11, address)) { @@ -432,7 +432,7 @@ void Interpreter::sc(u32 instr) { } u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.Write(RT(instr), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); @@ -453,7 +453,7 @@ void Interpreter::scd(u32 instr) { s64 address = regs.Read(RS(instr)) + (s16)instr; - if(regs.cop0.llbit) { + if (regs.cop0.llbit) { regs.cop0.llbit = false; if (check_address_error(0b111, address)) { @@ -464,7 +464,7 @@ void Interpreter::scd(u32 instr) { } u32 paddr = 0; - if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) { regs.Write(RT(instr), 0); regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); @@ -481,7 +481,7 @@ void Interpreter::sh(u32 instr) { s64 address = regs.Read(RS(instr)) + (s16)instr; u32 physical; - if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { @@ -499,7 +499,7 @@ void Interpreter::sw(u32 instr) { } u32 physical; - if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { @@ -516,7 +516,7 @@ void Interpreter::sd(u32 instr) { } u32 physical; - if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) { regs.cop0.HandleTLBException(address); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { @@ -590,13 +590,9 @@ void Interpreter::ori(u32 instr) { regs.Write(RT(instr), result); } -void Interpreter::or_(u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr))); -} +void Interpreter::or_(u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) | regs.Read(RT(instr))); } -void Interpreter::nor(u32 instr) { - regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); -} +void Interpreter::nor(u32 instr) { regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); } void Interpreter::j(u32 instr) { s32 target = (instr & 0x3ffffff) << 2; @@ -632,43 +628,35 @@ void Interpreter::sltiu(u32 instr) { regs.Write(RT(instr), regs.Read(RS(instr)) < imm); } -void Interpreter::slt(u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); -} +void Interpreter::slt(u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); } -void Interpreter::sltu(u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); -} +void Interpreter::sltu(u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); } void Interpreter::xori(u32 instr) { s64 imm = (u16)instr; regs.Write(RT(instr), regs.Read(RS(instr)) ^ imm); } -void Interpreter::xor_(u32 instr) { - regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr))); -} +void Interpreter::xor_(u32 instr) { regs.Write(RD(instr), regs.Read(RT(instr)) ^ regs.Read(RS(instr))); } void Interpreter::andi(u32 instr) { s64 imm = (u16)instr; regs.Write(RT(instr), regs.Read(RS(instr)) & imm); } -void Interpreter::and_(u32 instr) { - regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); -} +void Interpreter::and_(u32 instr) { regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); } void Interpreter::sll(u32 instr) { u8 sa = ((instr >> 6) & 0x1f); s32 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), (s64) result); + regs.Write(RD(instr), (s64)result); } void Interpreter::sllv(u32 instr) { u8 sa = (regs.Read(RS(instr))) & 0x1F; u32 rt = regs.Read(RT(instr)); s32 result = rt << sa; - regs.Write(RD(instr), (s64) result); + regs.Write(RD(instr), (s64)result); } void Interpreter::dsll32(u32 instr) { @@ -693,14 +681,14 @@ void Interpreter::srl(u32 instr) { u32 rt = regs.Read(RT(instr)); u8 sa = ((instr >> 6) & 0x1f); u32 result = rt >> sa; - regs.Write(RD(instr), (s32) result); + regs.Write(RD(instr), (s32)result); } void Interpreter::srlv(u32 instr) { u8 sa = (regs.Read(RS(instr)) & 0x1F); u32 rt = regs.Read(RT(instr)); s32 result = rt >> sa; - regs.Write(RD(instr), (s64) result); + regs.Write(RD(instr), (s64)result); } void Interpreter::dsrl(u32 instr) { @@ -765,7 +753,7 @@ void Interpreter::dsub(u32 instr) { s64 rt = regs.Read(RT(instr)); s64 rs = regs.Read(RS(instr)); s64 result = rs - rt; - if(check_signed_underflow(rs, rt, result)) { + if (check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RD(instr), result); @@ -783,7 +771,7 @@ void Interpreter::sub(u32 instr) { s32 rt = regs.Read(RT(instr)); s32 rs = regs.Read(RS(instr)); s32 result = rs - rt; - if(check_signed_underflow(rs, rt, result)) { + if (check_signed_underflow(rs, rt, result)) { regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); } else { regs.Write(RD(instr), result); @@ -794,7 +782,7 @@ void Interpreter::subu(u32 instr) { u32 rt = regs.Read(RT(instr)); u32 rs = regs.Read(RS(instr)); u32 result = rs - rt; - regs.Write(RD(instr), (s64) ((s32) result)); + regs.Write(RD(instr), (s64)((s32)result)); } void Interpreter::dmultu(u32 instr) { @@ -829,50 +817,32 @@ void Interpreter::mult(u32 instr) { regs.hi = (s64)((s32)(result >> 32)); } -void Interpreter::mflo(u32 instr) { - regs.Write(RD(instr), regs.lo); -} +void Interpreter::mflo(u32 instr) { regs.Write(RD(instr), regs.lo); } -void Interpreter::mfhi(u32 instr) { - regs.Write(RD(instr), regs.hi); -} +void Interpreter::mfhi(u32 instr) { regs.Write(RD(instr), regs.hi); } -void Interpreter::mtlo(u32 instr) { - regs.lo = regs.Read(RS(instr)); -} +void Interpreter::mtlo(u32 instr) { regs.lo = regs.Read(RS(instr)); } -void Interpreter::mthi(u32 instr) { - regs.hi = regs.Read(RS(instr)); -} +void Interpreter::mthi(u32 instr) { regs.hi = regs.Read(RS(instr)); } void Interpreter::trap(bool cond) { - if(cond) { + if (cond) { regs.cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC); } } -void Interpreter::mtc2(u32 instr) { - cop2Latch = regs.Read(RT(instr)); -} +void Interpreter::mtc2(u32 instr) { cop2Latch = regs.Read(RT(instr)); } void Interpreter::mfc2(u32 instr) { s32 value = cop2Latch; regs.Write(RT(instr), value); } -void Interpreter::dmtc2(u32 instr) { - cop2Latch = regs.Read(RT(instr)); -} +void Interpreter::dmtc2(u32 instr) { cop2Latch = regs.Read(RT(instr)); } -void Interpreter::dmfc2(u32 instr) { - regs.Write(RT(instr), cop2Latch); -} +void Interpreter::dmfc2(u32 instr) { regs.Write(RT(instr), cop2Latch); } -void Interpreter::ctc2(u32) { +void Interpreter::ctc2(u32) {} -} - -void Interpreter::cfc2(u32) { - -} -} \ No newline at end of file +void Interpreter::cfc2(u32) {} +} // namespace n64 diff --git a/src/backend/core/jit/helpers.hpp b/src/backend/core/jit/helpers.hpp index c7ed09f3..a74f4880 100644 --- a/src/backend/core/jit/helpers.hpp +++ b/src/backend/core/jit/helpers.hpp @@ -4,21 +4,41 @@ namespace n64 { static inline bool SpecialEndsBlock(u32 instr) { u8 mask = instr & 0x3F; switch (mask) { - case JR: case JALR: case SYSCALL: case BREAK: - case TGE: case TGEU: case TLT: case TLTU: - case TEQ: case TNE: return true; - default: return false; + case JR: + case JALR: + case SYSCALL: + case BREAK: + case TGE: + case TGEU: + case TLT: + case TLTU: + case TEQ: + case TNE: + return true; + default: + return false; } } static inline bool InstrEndsBlock(u32 instr) { u8 mask = (instr >> 26) & 0x3f; switch (mask) { - case SPECIAL: return SpecialEndsBlock(instr); - case REGIMM: case J: case JAL: case BEQ: - case BNE: case BLEZ: case BGTZ: case BEQL: - case BNEL: case BLEZL: case BGTZL: return true; - default: return false; + case SPECIAL: + return SpecialEndsBlock(instr); + case REGIMM: + case J: + case JAL: + case BEQ: + case BNE: + case BLEZ: + case BGTZ: + case BEQL: + case BNEL: + case BLEZL: + case BGTZL: + return true; + default: + return false; } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/jit/instructions.cpp b/src/backend/core/jit/instructions.cpp index 35187f8c..b2d404a9 100644 --- a/src/backend/core/jit/instructions.cpp +++ b/src/backend/core/jit/instructions.cpp @@ -3,541 +3,520 @@ #define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) -namespace n64 -{ - void JIT::lui(u32 instr) { - u64 val = s64((s16)instr); - val <<= 16; - regs.Write(RT(instr), val); - } +namespace n64 { +void JIT::lui(u32 instr) { + u64 val = s64((s16)instr); + val <<= 16; + regs.Write(RT(instr), val); +} - void JIT::add(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - u32 rs = regs.Read(RS(instr)); - u32 rt = regs.Read(RT(instr)); - u32 result = rs + rt; - if (check_signed_overflow(rs, rt, result)) { - //regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); - Util::panic("[JIT]: Unhandled Overflow exception in ADD!"); - } - regs.Write(RD(instr), s32(result)); - } else { - Util::panic("[JIT]: Implement non constant ADD"); +void JIT::add(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + u32 rs = regs.Read(RS(instr)); + u32 rt = regs.Read(RT(instr)); + u32 result = rs + rt; + if (check_signed_overflow(rs, rt, result)) { + // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); + Util::panic("[JIT]: Unhandled Overflow exception in ADD!"); } - } - - void JIT::addu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - s32 rs = regs.Read(RS(instr)); - s32 rt = regs.Read(RT(instr)); - s32 result = rs + rt; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant ADDI"); - } - } - - void JIT::addi(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); - u32 imm = s32(s16(instr)); - u32 result = rs + imm; - if (check_signed_overflow(rs, imm, result)) { - Util::panic("[JIT]: Unhandled Overflow exception in ADDI!"); - } else { - regs.Write(RT(instr), s32(result)); - } - } else { - Util::panic("[JIT]: Implement non constant ADDI!"); - } - } - - void JIT::addiu(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - auto rs = regs.Read(RS(instr)); - u32 imm = s32(s16(instr)); - u32 result = rs + imm; - regs.Write(RT(instr), s32(result)); - } else { - Util::panic("[JIT]: Implement non constant ADDIU!"); - } - } - - void JIT::andi(u32 instr) { - s64 imm = (u16)instr; - if (regs.IsRegConstant(RS(instr))) { - regs.Write(RT(instr), regs.Read(RS(instr)) & imm); - } else { - Util::panic("[JIT]: Implement non constant ANDI!"); - } - } - - void JIT::and_(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); - } else { - Util::panic("[JIT]: Implement non constant AND!"); - } - } - - void JIT::dadd(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto rs = regs.Read(RS(instr)); - auto rt = regs.Read(RT(instr)); - u64 result = rt + rs; - if (check_signed_overflow(rs, rt, result)) { - //regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); - Util::panic("[JIT]: Unhandled Overflow exception in DADD!"); - } - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DADD!"); - } - } - - void JIT::daddu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto rs = regs.Read(RS(instr)); - auto rt = regs.Read(RT(instr)); - regs.Write(RD(instr), rt + rs); - } else { - Util::panic("[JIT]: Implement non constant DADD!"); - } - } - - void JIT::daddi(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - u64 imm = s64(s16(instr)); - auto rs = regs.Read(RS(instr)); - u64 result = imm + rs; - if (check_signed_overflow(rs, imm, result)) { - //regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); - Util::panic("[JIT]: Unhandled Overflow exception in DADDI!"); - } - regs.Write(RT(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DADDI!"); - } - } - - void JIT::daddiu(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - s16 imm = s16(instr); - auto rs = regs.Read(RS(instr)); - regs.Write(RT(instr), imm + rs); - } else { - Util::panic("[JIT]: Implement non constant DADDI!"); - } - } - - void JIT::ddiv(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); - if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { - regs.lo = dividend; - regs.hi = 0; - } else if (divisor == 0) { - regs.hi = dividend; - if (dividend >= 0) { - regs.lo = -1; - } else { - regs.lo = 1; - } - } else { - s64 quotient = dividend / divisor; - s64 remainder = dividend % divisor; - regs.lo = quotient; - regs.hi = remainder; - } - - regs.loIsConstant = true; - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DDIV!"); - } - } - - void JIT::ddivu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); - if (divisor == 0) { - regs.lo = -1; - regs.hi = (s64)dividend; - } else { - u64 quotient = dividend / divisor; - u64 remainder = dividend % divisor; - regs.lo = (s64)quotient; - regs.hi = (s64)remainder; - } - - regs.loIsConstant = true; - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DDIVU!"); - } - } - - void JIT::div(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - s64 dividend = regs.Read(RS(instr)); - s64 divisor = regs.Read(RT(instr)); - - if (divisor == 0) { - regs.hi = dividend; - if (dividend >= 0) { - regs.lo = s64(-1); - } else { - regs.lo = s64(1); - } - } else { - s32 quotient = dividend / divisor; - s32 remainder = dividend % divisor; - regs.lo = quotient; - regs.hi = remainder; - } - - regs.loIsConstant = true; - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DIV!"); - } - } - - void JIT::divu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - auto dividend = regs.Read(RS(instr)); - auto divisor = regs.Read(RT(instr)); - if (divisor == 0) { - regs.lo = -1; - regs.hi = (s32)dividend; - } else { - s32 quotient = (s32)(dividend / divisor); - s32 remainder = (s32)(dividend % divisor); - regs.lo = quotient; - regs.hi = remainder; - } - - regs.loIsConstant = true; - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DIVU!"); - } - } - - void JIT::dmult(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - s128 result = (s128)rt * (s128)rs; - regs.lo = result & 0xFFFFFFFFFFFFFFFF; - regs.hi = result >> 64; - regs.hiIsConstant = true; - regs.loIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DMULT!"); - } - } - - void JIT::dmultu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - u128 result = (u128)rt * (u128)rs; - regs.lo = s64(result & 0xFFFFFFFFFFFFFFFF); - regs.hi = s64(result >> 64); - regs.hiIsConstant = true; - regs.loIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant DMULT!"); - } - } - - void JIT::dsll(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - u8 sa = ((instr >> 6) & 0x1f); - auto result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSLL!"); - } - } - - void JIT::dsllv(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto sa = regs.Read(RS(instr)) & 63; - auto result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSLLV!"); - } - } - - void JIT::dsll32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - u8 sa = ((instr >> 6) & 0x1f); - auto result = regs.Read(RT(instr)) << (sa + 32); - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSLL32!"); - } - } - - void JIT::dsra(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); - u8 sa = ((instr >> 6) & 0x1f); - s64 result = rt >> sa; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSRA!"); - } - } - - void JIT::dsrav(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - s64 sa = rs & 63; - s64 result = rt >> sa; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSRAV!"); - } - } - - void JIT::dsra32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); - u8 sa = ((instr >> 6) & 0x1f); - s64 result = rt >> (sa + 32); - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSRA32!"); - } - } - - void JIT::dsrl(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); - u8 sa = ((instr >> 6) & 0x1f); - u64 result = rt >> sa; - regs.Write(RD(instr), s64(result)); - } else { - Util::panic("[JIT]: Implement non constant DSRL!"); - } - } - - void JIT::dsrlv(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - u8 amount = regs.Read(RS(instr)) & 63; - auto rt = regs.Read(RT(instr)); - u64 result = rt >> amount; - regs.Write(RD(instr), s64(result)); - } else { - Util::panic("[JIT]: Implement non constant DSRLV!"); - } - } - - void JIT::dsrl32(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - auto rt = regs.Read(RT(instr)); - u8 sa = ((instr >> 6) & 0x1f); - u64 result = rt >> (sa + 32); - regs.Write(RD(instr), s64(result)); - } else { - Util::panic("[JIT]: Implement non constant DSRL32!"); - } - } - - void JIT::dsub(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - s64 result = rs - rt; - if (check_signed_underflow(rs, rt, result)) { - // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); - Util::panic("[JIT]: Unhandled Overflow exception in DSUB!"); - } else { - regs.Write(RD(instr), result); - } - } else { - Util::panic("[JIT]: Implement non constant DSUB!"); - } - } - - void JIT::dsubu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - s64 result = rs - rt; - regs.Write(RD(instr), result); - } else { - Util::panic("[JIT]: Implement non constant DSUBU!"); - } - } - - void JIT::mfhi(u32 instr) { - if (regs.hiIsConstant) { - regs.Write(RD(instr), regs.hi); - } else { - Util::panic("[JIT]: Implement non constant MFHI!"); - } - } - - void JIT::mflo(u32 instr) { - if (regs.loIsConstant) { - regs.Write(RD(instr), regs.lo); - } else { - Util::panic("[JIT]: Implement non constant MFLO!"); - } - } - - void JIT::mult(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - s64 result = (s64)rt * (s64)rs; - regs.lo = (s64)((s32)result); - regs.loIsConstant = true; - regs.hi = (s64)((s32)(result >> 32)); - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant MULT!"); - } - } - - void JIT::multu(u32 instr) { - if (regs.IsRegConstant(RT(instr), RS(instr))) { - auto rt = regs.Read(RT(instr)); - auto rs = regs.Read(RS(instr)); - u64 result = (u64)rt * (u64)rs; - regs.lo = (s64)((s32)result); - regs.loIsConstant = true; - regs.hi = (s64)((s32)(result >> 32)); - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant MULTU!"); - } - } - - void JIT::mthi(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - regs.hi = regs.Read(RS(instr)); - regs.hiIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant MTHI!"); - } - } - - void JIT::mtlo(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - regs.lo = regs.Read(RS(instr)); - regs.loIsConstant = true; - } else { - Util::panic("[JIT]: Implement non constant MTLO!"); - } - } - - void JIT::nor(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); - } else { - Util::panic("[JIT]: Implement non constant NOR!"); - } - } - - void JIT::slti(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); - } else { - Util::panic("[JIT]: Implement non constant SLTI!"); - } - } - - void JIT::sltiu(u32 instr) { - if (regs.IsRegConstant(RS(instr))) { - s16 imm = instr; - regs.Write(RT(instr), regs.Read(RS(instr)) < imm); - } else { - Util::panic("[JIT]: Implement non constant SLTIU!"); - } - } - - void JIT::slt(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); - } else { - Util::panic("[JIT]: Implement non constant SLT!"); - } - } - - void JIT::sltu(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); - } else { - Util::panic("[JIT]: Implement non constant SLT!"); - } - } - - void JIT::sll(u32 instr) { - if (regs.IsRegConstant(RT(instr))) { - u8 sa = ((instr >> 6) & 0x1f); - s32 result = regs.Read(RT(instr)) << sa; - regs.Write(RD(instr), (s64)result); - } else { - Util::panic("[JIT]: Implement non constant SLL!"); - } - } - - void JIT::sllv(u32 instr) { - if (regs.IsRegConstant(RS(instr), RT(instr))) { - u8 sa = (regs.Read(RS(instr))) & 0x1F; - u32 rt = regs.Read(RT(instr)); - s32 result = rt << sa; - regs.Write(RD(instr), (s64)result); - } - } - - void JIT::sub(u32) { - - } - - void JIT::subu(u32) { - - } - - void JIT::sra(u32) { - - } - - void JIT::srav(u32) { - - } - - void JIT::srl(u32) { - - } - - void JIT::srlv(u32) { - - } - - void JIT::or_(u32) { - - } - - void JIT::ori(u32) { - - } - - void JIT::xor_(u32) { - - } - - void JIT::xori(u32) { - + regs.Write(RD(instr), s32(result)); + } else { + Util::panic("[JIT]: Implement non constant ADD"); } } + +void JIT::addu(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + s32 rs = regs.Read(RS(instr)); + s32 rt = regs.Read(RT(instr)); + s32 result = rs + rt; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant ADDI"); + } +} + +void JIT::addi(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + auto rs = regs.Read(RS(instr)); + u32 imm = s32(s16(instr)); + u32 result = rs + imm; + if (check_signed_overflow(rs, imm, result)) { + Util::panic("[JIT]: Unhandled Overflow exception in ADDI!"); + } else { + regs.Write(RT(instr), s32(result)); + } + } else { + Util::panic("[JIT]: Implement non constant ADDI!"); + } +} + +void JIT::addiu(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + auto rs = regs.Read(RS(instr)); + u32 imm = s32(s16(instr)); + u32 result = rs + imm; + regs.Write(RT(instr), s32(result)); + } else { + Util::panic("[JIT]: Implement non constant ADDIU!"); + } +} + +void JIT::andi(u32 instr) { + s64 imm = (u16)instr; + if (regs.IsRegConstant(RS(instr))) { + regs.Write(RT(instr), regs.Read(RS(instr)) & imm); + } else { + Util::panic("[JIT]: Implement non constant ANDI!"); + } +} + +void JIT::and_(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + regs.Write(RD(instr), regs.Read(RS(instr)) & regs.Read(RT(instr))); + } else { + Util::panic("[JIT]: Implement non constant AND!"); + } +} + +void JIT::dadd(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + auto rs = regs.Read(RS(instr)); + auto rt = regs.Read(RT(instr)); + u64 result = rt + rs; + if (check_signed_overflow(rs, rt, result)) { + // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); + Util::panic("[JIT]: Unhandled Overflow exception in DADD!"); + } + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DADD!"); + } +} + +void JIT::daddu(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + auto rs = regs.Read(RS(instr)); + auto rt = regs.Read(RT(instr)); + regs.Write(RD(instr), rt + rs); + } else { + Util::panic("[JIT]: Implement non constant DADD!"); + } +} + +void JIT::daddi(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + u64 imm = s64(s16(instr)); + auto rs = regs.Read(RS(instr)); + u64 result = imm + rs; + if (check_signed_overflow(rs, imm, result)) { + // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); + Util::panic("[JIT]: Unhandled Overflow exception in DADDI!"); + } + regs.Write(RT(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DADDI!"); + } +} + +void JIT::daddiu(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + s16 imm = s16(instr); + auto rs = regs.Read(RS(instr)); + regs.Write(RT(instr), imm + rs); + } else { + Util::panic("[JIT]: Implement non constant DADDI!"); + } +} + +void JIT::ddiv(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + auto dividend = regs.Read(RS(instr)); + auto divisor = regs.Read(RT(instr)); + if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { + regs.lo = dividend; + regs.hi = 0; + } else if (divisor == 0) { + regs.hi = dividend; + if (dividend >= 0) { + regs.lo = -1; + } else { + regs.lo = 1; + } + } else { + s64 quotient = dividend / divisor; + s64 remainder = dividend % divisor; + regs.lo = quotient; + regs.hi = remainder; + } + + regs.loIsConstant = true; + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DDIV!"); + } +} + +void JIT::ddivu(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + auto dividend = regs.Read(RS(instr)); + auto divisor = regs.Read(RT(instr)); + if (divisor == 0) { + regs.lo = -1; + regs.hi = (s64)dividend; + } else { + u64 quotient = dividend / divisor; + u64 remainder = dividend % divisor; + regs.lo = (s64)quotient; + regs.hi = (s64)remainder; + } + + regs.loIsConstant = true; + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DDIVU!"); + } +} + +void JIT::div(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + s64 dividend = regs.Read(RS(instr)); + s64 divisor = regs.Read(RT(instr)); + + if (divisor == 0) { + regs.hi = dividend; + if (dividend >= 0) { + regs.lo = s64(-1); + } else { + regs.lo = s64(1); + } + } else { + s32 quotient = dividend / divisor; + s32 remainder = dividend % divisor; + regs.lo = quotient; + regs.hi = remainder; + } + + regs.loIsConstant = true; + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DIV!"); + } +} + +void JIT::divu(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + auto dividend = regs.Read(RS(instr)); + auto divisor = regs.Read(RT(instr)); + if (divisor == 0) { + regs.lo = -1; + regs.hi = (s32)dividend; + } else { + s32 quotient = (s32)(dividend / divisor); + s32 remainder = (s32)(dividend % divisor); + regs.lo = quotient; + regs.hi = remainder; + } + + regs.loIsConstant = true; + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DIVU!"); + } +} + +void JIT::dmult(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + s128 result = (s128)rt * (s128)rs; + regs.lo = result & 0xFFFFFFFFFFFFFFFF; + regs.hi = result >> 64; + regs.hiIsConstant = true; + regs.loIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DMULT!"); + } +} + +void JIT::dmultu(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + u128 result = (u128)rt * (u128)rs; + regs.lo = s64(result & 0xFFFFFFFFFFFFFFFF); + regs.hi = s64(result >> 64); + regs.hiIsConstant = true; + regs.loIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant DMULT!"); + } +} + +void JIT::dsll(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + u8 sa = ((instr >> 6) & 0x1f); + auto result = regs.Read(RT(instr)) << sa; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSLL!"); + } +} + +void JIT::dsllv(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto sa = regs.Read(RS(instr)) & 63; + auto result = regs.Read(RT(instr)) << sa; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSLLV!"); + } +} + +void JIT::dsll32(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + u8 sa = ((instr >> 6) & 0x1f); + auto result = regs.Read(RT(instr)) << (sa + 32); + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSLL32!"); + } +} + +void JIT::dsra(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + auto rt = regs.Read(RT(instr)); + u8 sa = ((instr >> 6) & 0x1f); + s64 result = rt >> sa; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSRA!"); + } +} + +void JIT::dsrav(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + s64 sa = rs & 63; + s64 result = rt >> sa; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSRAV!"); + } +} + +void JIT::dsra32(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + auto rt = regs.Read(RT(instr)); + u8 sa = ((instr >> 6) & 0x1f); + s64 result = rt >> (sa + 32); + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSRA32!"); + } +} + +void JIT::dsrl(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + auto rt = regs.Read(RT(instr)); + u8 sa = ((instr >> 6) & 0x1f); + u64 result = rt >> sa; + regs.Write(RD(instr), s64(result)); + } else { + Util::panic("[JIT]: Implement non constant DSRL!"); + } +} + +void JIT::dsrlv(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + u8 amount = regs.Read(RS(instr)) & 63; + auto rt = regs.Read(RT(instr)); + u64 result = rt >> amount; + regs.Write(RD(instr), s64(result)); + } else { + Util::panic("[JIT]: Implement non constant DSRLV!"); + } +} + +void JIT::dsrl32(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + auto rt = regs.Read(RT(instr)); + u8 sa = ((instr >> 6) & 0x1f); + u64 result = rt >> (sa + 32); + regs.Write(RD(instr), s64(result)); + } else { + Util::panic("[JIT]: Implement non constant DSRL32!"); + } +} + +void JIT::dsub(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + s64 result = rs - rt; + if (check_signed_underflow(rs, rt, result)) { + // regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC); + Util::panic("[JIT]: Unhandled Overflow exception in DSUB!"); + } else { + regs.Write(RD(instr), result); + } + } else { + Util::panic("[JIT]: Implement non constant DSUB!"); + } +} + +void JIT::dsubu(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + s64 result = rs - rt; + regs.Write(RD(instr), result); + } else { + Util::panic("[JIT]: Implement non constant DSUBU!"); + } +} + +void JIT::mfhi(u32 instr) { + if (regs.hiIsConstant) { + regs.Write(RD(instr), regs.hi); + } else { + Util::panic("[JIT]: Implement non constant MFHI!"); + } +} + +void JIT::mflo(u32 instr) { + if (regs.loIsConstant) { + regs.Write(RD(instr), regs.lo); + } else { + Util::panic("[JIT]: Implement non constant MFLO!"); + } +} + +void JIT::mult(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + s64 result = (s64)rt * (s64)rs; + regs.lo = (s64)((s32)result); + regs.loIsConstant = true; + regs.hi = (s64)((s32)(result >> 32)); + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant MULT!"); + } +} + +void JIT::multu(u32 instr) { + if (regs.IsRegConstant(RT(instr), RS(instr))) { + auto rt = regs.Read(RT(instr)); + auto rs = regs.Read(RS(instr)); + u64 result = (u64)rt * (u64)rs; + regs.lo = (s64)((s32)result); + regs.loIsConstant = true; + regs.hi = (s64)((s32)(result >> 32)); + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant MULTU!"); + } +} + +void JIT::mthi(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + regs.hi = regs.Read(RS(instr)); + regs.hiIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant MTHI!"); + } +} + +void JIT::mtlo(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + regs.lo = regs.Read(RS(instr)); + regs.loIsConstant = true; + } else { + Util::panic("[JIT]: Implement non constant MTLO!"); + } +} + +void JIT::nor(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + regs.Write(RD(instr), ~(regs.Read(RS(instr)) | regs.Read(RT(instr)))); + } else { + Util::panic("[JIT]: Implement non constant NOR!"); + } +} + +void JIT::slti(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + s16 imm = instr; + regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + } else { + Util::panic("[JIT]: Implement non constant SLTI!"); + } +} + +void JIT::sltiu(u32 instr) { + if (regs.IsRegConstant(RS(instr))) { + s16 imm = instr; + regs.Write(RT(instr), regs.Read(RS(instr)) < imm); + } else { + Util::panic("[JIT]: Implement non constant SLTIU!"); + } +} + +void JIT::slt(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); + } else { + Util::panic("[JIT]: Implement non constant SLT!"); + } +} + +void JIT::sltu(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + regs.Write(RD(instr), regs.Read(RS(instr)) < regs.Read(RT(instr))); + } else { + Util::panic("[JIT]: Implement non constant SLT!"); + } +} + +void JIT::sll(u32 instr) { + if (regs.IsRegConstant(RT(instr))) { + u8 sa = ((instr >> 6) & 0x1f); + s32 result = regs.Read(RT(instr)) << sa; + regs.Write(RD(instr), (s64)result); + } else { + Util::panic("[JIT]: Implement non constant SLL!"); + } +} + +void JIT::sllv(u32 instr) { + if (regs.IsRegConstant(RS(instr), RT(instr))) { + u8 sa = (regs.Read(RS(instr))) & 0x1F; + u32 rt = regs.Read(RT(instr)); + s32 result = rt << sa; + regs.Write(RD(instr), (s64)result); + } +} + +void JIT::sub(u32) {} + +void JIT::subu(u32) {} + +void JIT::sra(u32) {} + +void JIT::srav(u32) {} + +void JIT::srl(u32) {} + +void JIT::srlv(u32) {} + +void JIT::or_(u32) {} + +void JIT::ori(u32) {} + +void JIT::xor_(u32) {} + +void JIT::xori(u32) {} +} // namespace n64 diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index 30590496..a8b4913d 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -15,8 +15,8 @@ void Flash::Reset() { writeBuf = {}; } -void Flash::Load(SaveType saveType, const std::string& path) { - if(saveType == SAVE_FLASH_1m) { +void Flash::Load(SaveType saveType, const std::string &path) { + if (saveType == SAVE_FLASH_1m) { fs::path flashPath_ = path; if (!savePath.empty()) { flashPath_ = savePath / flashPath_.filename(); @@ -25,12 +25,14 @@ void Flash::Load(SaveType saveType, const std::string& path) { std::error_code error; if (saveData.is_mapped()) { saveData.sync(error); - if (error) { Util::panic("Could not sync {}", flashPath); } + if (error) { + Util::panic("Could not sync {}", flashPath); + } saveData.unmap(); } auto flashVec = Util::ReadFileBinary(flashPath); - if(flashVec.empty()) { + if (flashVec.empty()) { std::vector dummy{}; dummy.resize(FLASH_SIZE); Util::WriteFileBinary(dummy, flashPath); @@ -41,40 +43,41 @@ void Flash::Load(SaveType saveType, const std::string& path) { Util::panic("Corrupt SRAM!"); } - saveData = mio::make_mmap_sink( - flashPath, 0, mio::map_entire_file, error); - if (error) { Util::panic("Could not make mmap {}", flashPath); } + saveData = mio::make_mmap_sink(flashPath, 0, mio::map_entire_file, error); + if (error) { + Util::panic("Could not make mmap {}", flashPath); + } } } void Flash::CommandExecute() { Util::trace("Flash::CommandExecute"); switch (state) { - case FlashState::Idle: - break; - case FlashState::Erase: - if(saveData.is_mapped()) { - for (int i = 0; i < 128; i++) { - saveData[eraseOffs + i] = 0xFF; - } - } else { - Util::panic("Accessing flash when not mapped!"); + case FlashState::Idle: + break; + case FlashState::Erase: + if (saveData.is_mapped()) { + for (int i = 0; i < 128; i++) { + saveData[eraseOffs + i] = 0xFF; } - break; - case FlashState::Write: - if(saveData.is_mapped()) { - for (int i = 0; i < 128; i++) { - saveData[writeOffs + i] = writeBuf[i]; - } - } else { - Util::panic("Accessing flash when not mapped!"); + } else { + Util::panic("Accessing flash when not mapped!"); + } + break; + case FlashState::Write: + if (saveData.is_mapped()) { + for (int i = 0; i < 128; i++) { + saveData[writeOffs + i] = writeBuf[i]; } - break; - case FlashState::Read: - Util::panic("Execute command when flash in read state"); - break; - case FlashState::Status: - break; + } else { + Util::panic("Accessing flash when not mapped!"); + } + break; + case FlashState::Read: + Util::panic("Execute command when flash in read state"); + break; + case FlashState::Status: + break; } } @@ -83,9 +86,7 @@ void Flash::CommandStatus() { status = 0x1111800100C20000; } -void Flash::CommandSetEraseOffs(u32 val) { - eraseOffs = (val & 0xffff) << 7; -} +void Flash::CommandSetEraseOffs(u32 val) { eraseOffs = (val & 0xffff) << 7; } void Flash::CommandErase() { state = FlashState::Erase; @@ -97,9 +98,7 @@ void Flash::CommandSetWriteOffs(u32 val) { status = 0x1111800400C20000LL; } -void Flash::CommandWrite() { - state = FlashState::Write; -} +void Flash::CommandWrite() { state = FlashState::Write; } void Flash::CommandRead() { state = FlashState::Read; @@ -109,12 +108,7 @@ void Flash::CommandRead() { std::vector Flash::Serialize() { std::vector res{}; - res.resize( - sizeof(state) + - sizeof(status) + - sizeof(eraseOffs) + - sizeof(writeOffs) + - 128); + res.resize(sizeof(state) + sizeof(status) + sizeof(eraseOffs) + sizeof(writeOffs) + 128); u32 index = 0; memcpy(res.data() + index, &state, sizeof(state)); @@ -130,7 +124,7 @@ std::vector Flash::Serialize() { return res; } -void Flash::Deserialize(const std::vector& data) { +void Flash::Deserialize(const std::vector &data) { u32 index = 0; memcpy(&state, data.data() + index, sizeof(state)); index += sizeof(state); @@ -143,44 +137,70 @@ void Flash::Deserialize(const std::vector& data) { std::copy(data.begin() + index, data.begin() + index + 128, writeBuf.begin()); } -template <> void Flash::Write(u32 index, u32 val) { - if(index > 0) { +template <> +void Flash::Write(u32 index, u32 val) { + if (index > 0) { u8 cmd = val >> 24; - switch(cmd) { - case FLASH_COMMAND_EXECUTE: CommandExecute(); break; - case FLASH_COMMAND_STATUS: CommandStatus(); break; - case FLASH_COMMAND_SET_ERASE_OFFSET: CommandSetEraseOffs(val); break; - case FLASH_COMMAND_ERASE: CommandErase(); break; - case FLASH_COMMAND_SET_WRITE_OFFSET: CommandSetWriteOffs(val); break; - case FLASH_COMMAND_WRITE: CommandWrite(); break; - case FLASH_COMMAND_READ: CommandRead(); break; - default: Util::warn("Invalid flash command: {:02X}", cmd); + switch (cmd) { + case FLASH_COMMAND_EXECUTE: + CommandExecute(); + break; + case FLASH_COMMAND_STATUS: + CommandStatus(); + break; + case FLASH_COMMAND_SET_ERASE_OFFSET: + CommandSetEraseOffs(val); + break; + case FLASH_COMMAND_ERASE: + CommandErase(); + break; + case FLASH_COMMAND_SET_WRITE_OFFSET: + CommandSetWriteOffs(val); + break; + case FLASH_COMMAND_WRITE: + CommandWrite(); + break; + case FLASH_COMMAND_READ: + CommandRead(); + break; + default: + Util::warn("Invalid flash command: {:02X}", cmd); } } else { Util::warn("Flash Write of {:08X} @ {:08X}", val, index); } } -template <> void Flash::Write(u32 index, u8 val) { - switch(state) { - case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write"); - case FlashState::Status: Util::panic("Invalid FlashState::Status with Write"); - case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write"); - case FlashState::Read: Util::panic("Invalid FlashState::Read with Write"); - case FlashState::Write: - assert(index <= 0x7F && "Out of range flash Write8"); - writeBuf[index] = val; - break; - default: Util::warn("Invalid flash state on Write: {:02X}", static_cast(state)); +template <> +void Flash::Write(u32 index, u8 val) { + switch (state) { + case FlashState::Idle: + Util::panic("Invalid FlashState::Idle with Write"); + case FlashState::Status: + Util::panic("Invalid FlashState::Status with Write"); + case FlashState::Erase: + Util::panic("Invalid FlashState::Erase with Write"); + case FlashState::Read: + Util::panic("Invalid FlashState::Read with Write"); + case FlashState::Write: + assert(index <= 0x7F && "Out of range flash Write8"); + writeBuf[index] = val; + break; + default: + Util::warn("Invalid flash state on Write: {:02X}", static_cast(state)); } } -template <> u8 Flash::Read(u32 index) const { +template <> +u8 Flash::Read(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()) { + 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; @@ -188,17 +208,20 @@ template <> u8 Flash::Read(u32 index) const { Util::panic("Accessing flash when not mapped!"); } } - case FlashState::Status: { + case FlashState::Status: + { u32 offset = (7 - (index % 8)) * 8; 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"); + default: + Util::panic("Flash read byte while in unknown state"); } } -template <> u32 Flash::Read(u32) const { +template <> +u32 Flash::Read(u32) const { return status >> 32; } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/AI.cpp b/src/backend/core/mmio/AI.cpp index dd977d3b..591b2805 100644 --- a/src/backend/core/mmio/AI.cpp +++ b/src/backend/core/mmio/AI.cpp @@ -1,10 +1,10 @@ -#include -#include #include +#include #include +#include namespace n64 { -AI::AI(Mem &mem, Registers ®s) : mem(mem), regs(regs) { } +AI::AI(Mem &mem, Registers ®s) : mem(mem), regs(regs) {} void AI::Reset() { dmaEnable = false; @@ -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 { - if(addr == 0x0450000C) { + if (addr == 0x0450000C) { u32 val = 0; val |= (dmaCount > 1); val |= 1 << 20; @@ -36,60 +36,65 @@ auto AI::Read(u32 addr) const -> u32 { } void AI::Write(u32 addr, u32 val) { - switch(addr) { - case 0x04500000: - if(dmaCount < 2) { - dmaAddr[dmaCount] = val & 0xFFFFFF & ~7; - } - break; - case 0x04500004: { + switch (addr) { + case 0x04500000: + if (dmaCount < 2) { + dmaAddr[dmaCount] = val & 0xFFFFFF & ~7; + } + break; + case 0x04500004: + { u32 len = (val & 0x3FFFF) & ~7; - if(dmaCount < 2) { - if(dmaCount == 0) mem.mmio.mi.InterruptRaise(MI::Interrupt::AI); + if (dmaCount < 2) { + if (dmaCount == 0) + mem.mmio.mi.InterruptRaise(MI::Interrupt::AI); dmaLen[dmaCount] = len; dmaCount++; } - } break; - case 0x04500008: - dmaEnable = val & 1; - break; - case 0x0450000C: - mem.mmio.mi.InterruptLower(MI::Interrupt::AI); - break; - case 0x04500010: { + } + break; + case 0x04500008: + dmaEnable = val & 1; + break; + case 0x0450000C: + mem.mmio.mi.InterruptLower(MI::Interrupt::AI); + break; + case 0x04500010: + { 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; - if(oldDacFreq != dac.freq) { + if (oldDacFreq != dac.freq) { device.AdjustSampleRate(dac.freq); } - } break; - case 0x04500014: - bitrate = val & 0xF; - dac.precision = bitrate + 1; - break; - default: - Util::panic("Unhandled AI write at addr {:08X} with val {:08X}", addr, val); + } + break; + case 0x04500014: + bitrate = val & 0xF; + dac.precision = bitrate + 1; + break; + default: + Util::panic("Unhandled AI write at addr {:08X} with val {:08X}", addr, val); } } void AI::Step(u32 cpuCycles, float volumeL, float volumeR) { cycles += cpuCycles; - while(cycles > dac.period) { + while (cycles > dac.period) { if (dmaCount == 0) { return; } - if(dmaLen[0] && dmaEnable) { + if (dmaLen[0] && dmaEnable) { u32 addrHi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7FF; dmaAddr[0] = (addrHi << 13) | (dmaAddr[0] & 0x1FFF); u32 data = mem.mmio.rdp.ReadRDRAM(dmaAddr[0]); s16 l = s16(data >> 16); s16 r = s16(data); - if(volumeR > 0 && volumeL > 0) { - device.PushSample((float) l / INT16_MAX, volumeL, (float) r / INT16_MAX, volumeR); + if (volumeR > 0 && volumeL > 0) { + device.PushSample((float)l / INT16_MAX, volumeL, (float)r / INT16_MAX, volumeR); } u32 addrLo = (dmaAddr[0] + 4) & 0x1FFF; @@ -98,8 +103,8 @@ void AI::Step(u32 cpuCycles, float volumeL, float volumeR) { dmaLen[0] -= 4; } - if(!dmaLen[0]) { - if(--dmaCount > 0) { + if (!dmaLen[0]) { + if (--dmaCount > 0) { mem.mmio.mi.InterruptRaise(MI::Interrupt::AI); dmaAddr[0] = dmaAddr[1]; dmaLen[0] = dmaLen[1]; @@ -110,4 +115,4 @@ void AI::Step(u32 cpuCycles, float volumeL, float volumeR) { } } -} +} // namespace n64 diff --git a/src/backend/core/mmio/AI.hpp b/src/backend/core/mmio/AI.hpp index e441a2ed..2ac3abec 100644 --- a/src/backend/core/mmio/AI.hpp +++ b/src/backend/core/mmio/AI.hpp @@ -7,7 +7,7 @@ struct Mem; struct Registers; struct AI { - AI(Mem&, Registers& regs); + AI(Mem &, Registers ®s); void Reset(); auto Read(u32) const -> u32; void Write(u32, u32); @@ -27,8 +27,9 @@ struct AI { u32 period{N64_CPU_FREQ / freq}; u32 precision{16}; } dac; + private: - Mem& mem; - Registers& regs; + Mem &mem; + Registers ®s; }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/Audio.cpp b/src/backend/core/mmio/Audio.cpp index 215ff80d..32a48b76 100644 --- a/src/backend/core/mmio/Audio.cpp +++ b/src/backend/core/mmio/Audio.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include namespace n64 { #define AUDIO_SAMPLE_RATE 44100 @@ -8,8 +8,8 @@ namespace n64 { #define SYSTEM_SAMPLE_SIZE 4 #define BYTES_PER_HALF_SECOND (((float)AUDIO_SAMPLE_RATE / 2) * SYSTEM_SAMPLE_SIZE) -void audioCallback(void* user, Uint8* stream, int length) { - auto audioDevice = (AudioDevice*)user; +void audioCallback(void *user, Uint8 *stream, int length) { + auto audioDevice = (AudioDevice *)user; int gotten = 0, available = 0; if (audioDevice) { @@ -22,7 +22,7 @@ void audioCallback(void* user, Uint8* stream, int length) { } int gottenSamples = (int)(gotten / sizeof(float)); - auto* out = (float*)stream; + auto *out = (float *)stream; out += gottenSamples; for (int i = gottenSamples; i < length / sizeof(float); i++) { @@ -38,11 +38,13 @@ AudioDevice::~AudioDevice() { SDL_DestroyMutex(audioStreamMutex); } -AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE)), - audioStreamMutex(SDL_CreateMutex()) { +AudioDevice::AudioDevice() : + audioStream( + SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE)), + audioStreamMutex(SDL_CreateMutex()) { SDL_InitSubSystem(SDL_INIT_AUDIO); - if(!audioStreamMutex) { + if (!audioStreamMutex) { Util::panic("Unable to initialize audio mutex: {}", SDL_GetError()); } @@ -51,11 +53,11 @@ AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT request.channels = 2; request.samples = 1024; request.callback = audioCallback; - request.userdata = (void*)this; + request.userdata = (void *)this; handle = SDL_OpenAudioDevice(nullptr, 0, &request, &audioSpec, 0); - if(!handle) { + if (!handle) { Util::panic("Failed to initialize SDL Audio: {}", SDL_GetError()); } @@ -65,10 +67,10 @@ AudioDevice::AudioDevice() : audioStream(SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT void AudioDevice::PushSample(float left, float volumeL, float right, float volumeR) { float adjustedL = left * volumeL; float adjustedR = right * volumeR; - float samples[2]{ adjustedL, adjustedR }; + float samples[2]{adjustedL, adjustedR}; auto availableBytes = (float)SDL_AudioStreamAvailable(audioStream); - if(availableBytes <= BYTES_PER_HALF_SECOND) { + if (availableBytes <= BYTES_PER_HALF_SECOND) { SDL_AudioStreamPut(audioStream, samples, 2 * sizeof(float)); } } @@ -79,4 +81,4 @@ void AudioDevice::AdjustSampleRate(int sampleRate) { audioStream = SDL_NewAudioStream(SYSTEM_SAMPLE_FORMAT, 2, sampleRate, SYSTEM_SAMPLE_FORMAT, 2, AUDIO_SAMPLE_RATE); UnlockMutex(); } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/Audio.hpp b/src/backend/core/mmio/Audio.hpp index 53868557..9fdbd6f4 100644 --- a/src/backend/core/mmio/Audio.hpp +++ b/src/backend/core/mmio/Audio.hpp @@ -10,7 +10,7 @@ struct AudioDevice { void PushSample(float, float, float, float); void AdjustSampleRate(int); void LockMutex() { - if(audioStreamMutex) + if (audioStreamMutex) SDL_LockMutex(audioStreamMutex); } void UnlockMutex() { @@ -18,13 +18,14 @@ struct AudioDevice { SDL_UnlockMutex(audioStreamMutex); } - SDL_AudioStream* GetStream() { return audioStream; } + SDL_AudioStream *GetStream() { return audioStream; } + private: - SDL_AudioStream* audioStream; - SDL_mutex* audioStreamMutex; + SDL_AudioStream *audioStream; + SDL_mutex *audioStreamMutex; SDL_AudioSpec audioSpec{}; SDL_AudioSpec request{}; SDL_AudioDeviceID handle{}; }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/Interrupt.cpp b/src/backend/core/mmio/Interrupt.cpp index 4ea044c2..9ca45158 100644 --- a/src/backend/core/mmio/Interrupt.cpp +++ b/src/backend/core/mmio/Interrupt.cpp @@ -3,50 +3,50 @@ namespace n64 { void MI::InterruptRaise(Interrupt intr) { - switch(intr) { - case Interrupt::VI: - miIntr.vi = true; - break; - case Interrupt::SI: - miIntr.si = true; - break; - case Interrupt::PI: - miIntr.pi = true; - break; - case Interrupt::AI: - miIntr.ai = true; - break; - case Interrupt::DP: - miIntr.dp = true; - break; - case Interrupt::SP: - miIntr.sp = true; - break; + switch (intr) { + case Interrupt::VI: + miIntr.vi = true; + break; + case Interrupt::SI: + miIntr.si = true; + break; + case Interrupt::PI: + miIntr.pi = true; + break; + case Interrupt::AI: + miIntr.ai = true; + break; + case Interrupt::DP: + miIntr.dp = true; + break; + case Interrupt::SP: + miIntr.sp = true; + break; } UpdateInterrupt(); } void MI::InterruptLower(Interrupt intr) { - switch(intr) { - case Interrupt::VI: - miIntr.vi = false; - break; - case Interrupt::SI: - miIntr.si = false; - break; - case Interrupt::PI: - miIntr.pi = false; - break; - case Interrupt::AI: - miIntr.ai = false; - break; - case Interrupt::DP: - miIntr.dp = false; - break; - case Interrupt::SP: - miIntr.sp = false; - break; + switch (intr) { + case Interrupt::VI: + miIntr.vi = false; + break; + case Interrupt::SI: + miIntr.si = false; + break; + case Interrupt::PI: + miIntr.pi = false; + break; + case Interrupt::AI: + miIntr.ai = false; + break; + case Interrupt::DP: + miIntr.dp = false; + break; + case Interrupt::SP: + miIntr.sp = false; + break; } UpdateInterrupt(); @@ -56,4 +56,4 @@ void MI::UpdateInterrupt() { bool interrupt = miIntr.raw & miIntrMask.raw; regs.cop0.cause.ip2 = interrupt; } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/MI.cpp b/src/backend/core/mmio/MI.cpp index bd819bb5..c75ef73e 100644 --- a/src/backend/core/mmio/MI.cpp +++ b/src/backend/core/mmio/MI.cpp @@ -5,9 +5,7 @@ #define MI_VERSION_REG 0x02020102 namespace n64 { -MI::MI(Registers& regs) : regs(regs) { - Reset(); -} +MI::MI(Registers ®s) : regs(regs) { Reset(); } void MI::Reset() { miIntrMask.raw = 0; @@ -16,68 +14,74 @@ void MI::Reset() { } auto MI::Read(u32 paddr) const -> u32 { - switch(paddr & 0xF) { - case 0x0: return miMode & 0x3FF; - case 0x4: return MI_VERSION_REG; - case 0x8: return miIntr.raw & 0x3F; - case 0xC: return miIntrMask.raw & 0x3F; - default: - Util::panic("Unhandled MI[{:08X}] read", paddr); + switch (paddr & 0xF) { + case 0x0: + return miMode & 0x3FF; + case 0x4: + return MI_VERSION_REG; + case 0x8: + return miIntr.raw & 0x3F; + case 0xC: + return miIntrMask.raw & 0x3F; + default: + Util::panic("Unhandled MI[{:08X}] read", paddr); } } void MI::Write(u32 paddr, u32 val) { - switch(paddr & 0xF) { - case 0x0: - miMode &= 0xFFFFFF80; - miMode |= val & 0x7F; - if (val & (1 << 7)) { - miMode &= ~(1 << 7); + switch (paddr & 0xF) { + case 0x0: + miMode &= 0xFFFFFF80; + miMode |= val & 0x7F; + if (val & (1 << 7)) { + miMode &= ~(1 << 7); + } + + if (val & (1 << 8)) { + miMode |= 1 << 7; + } + + if (val & (1 << 9)) { + miMode &= ~(1 << 8); + } + + if (val & (1 << 10)) { + miMode |= 1 << 8; + } + + if (val & (1 << 11)) { + InterruptLower(Interrupt::DP); + } + + if (val & (1 << 12)) { + miMode &= ~(1 << 9); + } + + if (val & (1 << 13)) { + miMode |= 1 << 9; + } + break; + case 0x4: + case 0x8: + break; + case 0xC: + for (int bit = 0; bit < 6; bit++) { + int clearbit = bit << 1; + int setbit = (bit << 1) + 1; + + if (val & (1 << clearbit)) { + miIntrMask.raw &= ~(1 << bit); } - if (val & (1 << 8)) { - miMode |= 1 << 7; + if (val & (1 << setbit)) { + miIntrMask.raw |= 1 << bit; } + } - if (val & (1 << 9)) { - miMode &= ~(1 << 8); - } - - if (val & (1 << 10)) { - miMode |= 1 << 8; - } - - if (val & (1 << 11)) { - InterruptLower(Interrupt::DP); - } - - if (val & (1 << 12)) { - miMode &= ~(1 << 9); - } - - if (val & (1 << 13)) { - miMode |= 1 << 9; - } - break; - case 0x4: case 0x8: break; - case 0xC: - for (int bit = 0; bit < 6; bit++) { - int clearbit = bit << 1; - int setbit = (bit << 1) + 1; - - if (val & (1 << clearbit)) { - miIntrMask.raw &= ~(1 << bit); - } - - if (val & (1 << setbit)) { - miIntrMask.raw |= 1 << bit; - } - } - - UpdateInterrupt(); - break; - default: - Util::panic_trace("Unhandled MI write @ 0x{:08X} with value 0x{:08X}", paddr, val); + UpdateInterrupt(); + break; + default: + Util::panic_trace("Unhandled MI write @ 0x{:08X} with value 0x{:08X}", paddr, val); } } -} +} // namespace n64 diff --git a/src/backend/core/mmio/MI.hpp b/src/backend/core/mmio/MI.hpp index cc6f398d..e5bf8a1e 100644 --- a/src/backend/core/mmio/MI.hpp +++ b/src/backend/core/mmio/MI.hpp @@ -5,13 +5,13 @@ namespace n64 { union MIIntr { struct { - unsigned sp: 1; - unsigned si: 1; - unsigned ai: 1; - unsigned vi: 1; - unsigned pi: 1; - unsigned dp: 1; - unsigned: 26; + unsigned sp : 1; + unsigned si : 1; + unsigned ai : 1; + unsigned vi : 1; + unsigned pi : 1; + unsigned dp : 1; + unsigned : 26; }; u32 raw; }; @@ -19,11 +19,9 @@ union MIIntr { struct Registers; struct MI { - enum class Interrupt : u8 { - VI, SI, PI, AI, DP, SP - }; + enum class Interrupt : u8 { VI, SI, PI, AI, DP, SP }; - MI(Registers&); + MI(Registers &); void Reset(); [[nodiscard]] auto Read(u32) const -> u32; void Write(u32, u32); @@ -33,6 +31,6 @@ struct MI { u32 miMode{}; MIIntr miIntr{}, miIntrMask{}; - Registers& regs; + Registers ®s; }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index fb115c1d..eb16ea90 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -1,12 +1,10 @@ -#include -#include #include #include +#include +#include namespace n64 { -PI::PI(Mem& mem, Registers& regs) : mem(mem), regs(regs) { - Reset(); -} +PI::PI(Mem &mem, Registers ®s) : mem(mem), regs(regs) { Reset(); } void PI::Reset() { dmaBusy = false; @@ -46,86 +44,107 @@ bool PI::ReadLatch() { return true; } -template<> auto PI::BusRead(u32 addr) -> u8 { +template <> +auto PI::BusRead(u32 addr) -> u8 { switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_REG: - Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_ROM: - Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr); - return 0xFF; - case REGION_PI_SRAM: - return mem.BackupRead(addr - SREGION_PI_SRAM); - case REGION_PI_ROM: { + case REGION_PI_UNKNOWN: + Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_REG: + Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_ROM: + Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, " + "returning FF because it is not emulated", + addr); + return 0xFF; + case REGION_PI_SRAM: + return mem.BackupRead(addr - SREGION_PI_SRAM); + case REGION_PI_ROM: + { // round to nearest 4 byte boundary, keeping old LSB 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()); + Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, + index, index, mem.rom.cart.size(), mem.rom.cart.size()); return 0xFF; } return mem.rom.cart[index]; } - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template<> auto PI::BusRead(u32 addr) -> u8 { +template <> +auto PI::BusRead(u32 addr) -> u8 { if (!ReadLatch()) [[unlikely]] { return latch >> 24; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_REG: - Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_ROM: - Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr); - return 0xFF; - case REGION_PI_SRAM: - return mem.BackupRead(addr - SREGION_PI_SRAM); - case REGION_PI_ROM: { + case REGION_PI_UNKNOWN: + Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_REG: + Util::panic("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_ROM: + Util::warn("Reading byte from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, " + "returning FF because it is not emulated", + addr); + return 0xFF; + case REGION_PI_SRAM: + return mem.BackupRead(addr - SREGION_PI_SRAM); + case REGION_PI_ROM: + { addr = (addr + 2) & ~2; // round to nearest 4 byte boundary, keeping old LSB 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()); + Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, + index, index, mem.rom.cart.size(), mem.rom.cart.size()); return 0xFF; } return mem.rom.cart[index]; } - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template<> void PI::BusWrite(u32 addr, u32 val) { +template <> +void PI::BusWrite(u32 addr, u32 val) { switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - if (addr == 0x05000020) { - fprintf(stderr, "%c", val); - } else { - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); - } - break; - case REGION_PI_64DD_ROM: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - mem.BackupWrite(addr - SREGION_PI_SRAM, val); - break; - case REGION_PI_ROM: - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + case REGION_PI_UNKNOWN: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + if (addr == 0x05000020) { + fprintf(stderr, "%c", val); + } else { + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", + val, addr); + } + break; + case REGION_PI_64DD_ROM: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + mem.BackupWrite(addr - SREGION_PI_SRAM, val); + break; + case REGION_PI_ROM: + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template<> void PI::BusWrite(u32 addr, u32 val) { +template <> +void PI::BusWrite(u32 addr, u32 val) { u8 latch_shift = 24 - (addr & 1) * 8; if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { @@ -135,21 +154,29 @@ template<> void PI::BusWrite(u32 addr, u32 val) { BusWrite(addr, val); } -template <> auto PI::BusRead(u32 addr) -> u16 { +template <> +auto PI::BusRead(u32 addr) -> u16 { if (!ReadLatch()) [[unlikely]] { return latch >> 16; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_REG: - Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_64DD_ROM: - Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr); - case REGION_PI_SRAM: - Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); - case REGION_PI_ROM: { + case REGION_PI_UNKNOWN: + Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_REG: + Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_64DD_ROM: + Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, " + "returning FF because it is not emulated", + addr); + case REGION_PI_SRAM: + Util::panic("Reading half from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); + case REGION_PI_ROM: + { addr = (addr + 2) & ~3; u32 index = HALF_ADDRESS(addr) - SREGION_PI_ROM; if (index > mem.rom.cart.size() - 1) { @@ -157,67 +184,80 @@ template <> auto PI::BusRead(u32 addr) -> u16 { } return Util::ReadAccess(mem.rom.cart, index); } - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template <> auto PI::BusRead(u32 addr) -> u16 { +template <> +auto PI::BusRead(u32 addr) -> u16 { return BusRead(addr); } -template <> void PI::BusWrite(u32 addr, u32 val) { +template <> +void PI::BusWrite(u32 addr, u32 val) { if (!WriteLatch(val << 16)) [[unlikely]] { return; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - Util::panic("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); - case REGION_PI_64DD_ROM: - Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); - case REGION_PI_ROM: - Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + case REGION_PI_UNKNOWN: + Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + Util::panic("Writing half 0x{:04X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", + val, addr); + case REGION_PI_64DD_ROM: + Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + Util::panic("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); + case REGION_PI_ROM: + Util::warn("Writing half 0x{:04X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template <> void PI::BusWrite(u32 addr, u32 val) { +template <> +void PI::BusWrite(u32 addr, u32 val) { BusWrite(addr, val); } -template <> auto PI::BusRead(u32 addr) -> u32 { +template <> +auto PI::BusRead(u32 addr) -> u32 { if (!ReadLatch()) [[unlikely]] { return latch; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, returning FF because it is not emulated", addr); - return 0xFF; - case REGION_PI_64DD_REG: - Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, returning FF because it is not emulated", addr); - return 0xFF; - case REGION_PI_64DD_ROM: - Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, returning FF because it is not emulated", addr); - return 0xFF; - case REGION_PI_SRAM: - return mem.BackupRead(addr); - case REGION_PI_ROM: { + case REGION_PI_UNKNOWN: + Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN - This is the N64DD, " + "returning FF because it is not emulated", + addr); + return 0xFF; + case REGION_PI_64DD_REG: + Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG - This is the N64DD, " + "returning FF because it is not emulated", + addr); + return 0xFF; + case REGION_PI_64DD_ROM: + Util::warn("Reading word from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM - This is the N64DD, " + "returning FF because it is not emulated", + addr); + return 0xFF; + case REGION_PI_SRAM: + return mem.BackupRead(addr); + case REGION_PI_ROM: + { u32 index = addr - SREGION_PI_ROM; if (index > mem.rom.cart.size() - 3) { // -3 because we're reading an entire word switch (addr) { - case REGION_CART_ISVIEWER_BUFFER: - return htobe32(Util::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); - case CART_ISVIEWER_FLUSH: - Util::panic("Read from ISViewer flush!"); - default: break; + case REGION_CART_ISVIEWER_BUFFER: + return htobe32(Util::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); + case CART_ISVIEWER_FLUSH: + Util::panic("Read from ISViewer flush!"); + default: + break; } Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); return 0; @@ -225,66 +265,71 @@ template <> auto PI::BusRead(u32 addr) -> u32 { return Util::ReadAccess(mem.rom.cart, index); } } - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template <> auto PI::BusRead(u32 addr) -> u32 { +template <> +auto PI::BusRead(u32 addr) -> u32 { return BusRead(addr); } -template <> void PI::BusWrite(u32 addr, u32 val) { +template <> +void PI::BusWrite(u32 addr, u32 val) { switch (addr) { - case REGION_PI_UNKNOWN: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_UNKNOWN: + if (!WriteLatch(val)) [[unlikely]] { return; - case REGION_PI_64DD_REG: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - Util::warn("Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); + } + Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + return; + case REGION_PI_64DD_REG: + if (!WriteLatch(val)) [[unlikely]] { return; - case REGION_PI_64DD_ROM: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + } + Util::warn("Writing word 0x{:08X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", + val, addr); + return; + case REGION_PI_64DD_ROM: + if (!WriteLatch(val)) [[unlikely]] { return; - case REGION_PI_SRAM: - if (!WriteLatch(val)) [[unlikely]] { - return; - } - mem.BackupWrite(addr - SREGION_PI_SRAM, val); + } + Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + return; + case REGION_PI_SRAM: + if (!WriteLatch(val)) [[unlikely]] { return; - case REGION_PI_ROM: - switch (addr) { - case REGION_CART_ISVIEWER_BUFFER: - Util::WriteAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, be32toh(val)); - break; - case CART_ISVIEWER_FLUSH: { - if (val < CART_ISVIEWER_SIZE) { - std::string message(val + 1, 0); - std::copy(mem.isviewer.begin(), mem.isviewer.begin() + val, message.begin()); - Util::print("{}", message); - } else { - Util::panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", CART_ISVIEWER_SIZE, val); - } - break; + } + mem.BackupWrite(addr - SREGION_PI_SRAM, val); + return; + case REGION_PI_ROM: + switch (addr) { + case REGION_CART_ISVIEWER_BUFFER: + Util::WriteAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER, be32toh(val)); + break; + case CART_ISVIEWER_FLUSH: + { + if (val < CART_ISVIEWER_SIZE) { + std::string message(val + 1, 0); + std::copy(mem.isviewer.begin(), mem.isviewer.begin() + val, message.begin()); + Util::print("{}", message); + } else { + Util::panic("ISViewer buffer size is emulated at {} bytes, but received a flush command for {} bytes!", + CART_ISVIEWER_SIZE, val); } - default: - if (!WriteLatch(val)) [[unlikely]] { - Util::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); - return; - } - Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; } - return; default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + if (!WriteLatch(val)) [[unlikely]] { + Util::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); + return; + } + Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + } + return; + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } @@ -293,69 +338,79 @@ void PI::BusWrite(u32 addr, u32 val) { BusWrite(addr, val); } -template <> auto PI::BusRead(u32 addr) -> u64 { +template <> +auto PI::BusRead(u32 addr) -> u64 { if (!ReadLatch()) [[unlikely]] { return (u64)latch << 32; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr); - case REGION_PI_64DD_REG: - Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr); - case REGION_PI_64DD_ROM: - Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr); - case REGION_PI_SRAM: - Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_SRAM", addr); - case REGION_PI_ROM: { + case REGION_PI_UNKNOWN: + Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", addr); + case REGION_PI_64DD_REG: + Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", addr); + case REGION_PI_64DD_ROM: + Util::panic("Reading dword from address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", addr); + case REGION_PI_SRAM: + 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; 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); } return Util::ReadAccess(mem.rom.cart, index); } - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template <> auto PI::BusRead(u32 addr) -> u64 { +template <> +auto PI::BusRead(u32 addr) -> u64 { return BusRead(addr); } -template <> void PI::BusWrite(u32 addr, u64 val) { +template <> +void PI::BusWrite(u32 addr, u64 val) { if (!WriteLatch(val >> 32)) [[unlikely]] { return; } switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val, addr); - case REGION_PI_64DD_ROM: - Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); - case REGION_PI_ROM: - Util::warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - break; - default: - Util::panic("Should never end up here! Access to address %08X which did not match any PI bus regions!", addr); + case REGION_PI_UNKNOWN: + Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_REG", val, addr); + case REGION_PI_64DD_ROM: + Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + Util::panic("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_SRAM", val, addr); + case REGION_PI_ROM: + Util::warn("Writing dword 0x{:016X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + Util::panic("Should never end up here! Access to address %08X which did not match any PI bus regions!", addr); } } -template <> void PI::BusWrite(u32 addr, u64 val) { +template <> +void PI::BusWrite(u32 addr, u64 val) { BusWrite(addr, val); } auto PI::Read(u32 addr) const -> u32 { - switch(addr) { - case 0x04600000: return dramAddr & 0x00FFFFFE; - case 0x04600004: return cartAddr & 0xFFFFFFFE; - case 0x04600008: return rdLen; - case 0x0460000C: return wrLen; - case 0x04600010: { + switch (addr) { + case 0x04600000: + return dramAddr & 0x00FFFFFE; + case 0x04600004: + return cartAddr & 0xFFFFFFFE; + case 0x04600008: + return rdLen; + case 0x0460000C: + return wrLen; + case 0x04600010: + { u32 value = 0; value |= (dmaBusy << 0); // Is PI DMA active? No, because it's instant value |= (ioBusy << 1); // Is PI IO busy? No, because it's instant @@ -363,30 +418,38 @@ auto PI::Read(u32 addr) const -> u32 { value |= (mem.mmio.mi.miIntr.pi << 3); // PI interrupt? return value; } - case 0x04600014: return piBsdDom1Lat; - case 0x04600018: return piBsdDom1Pwd; - case 0x0460001C: return piBsdDom1Pgs; - case 0x04600020: return piBsdDom1Rls; - case 0x04600024: return piBsdDom2Lat; - case 0x04600028: return piBsdDom2Pwd; - case 0x0460002C: return piBsdDom2Pgs; - case 0x04600030: return piBsdDom2Rls; - default: - Util::panic("Unhandled PI[{:08X}] read", addr); + case 0x04600014: + return piBsdDom1Lat; + case 0x04600018: + return piBsdDom1Pwd; + case 0x0460001C: + return piBsdDom1Pgs; + case 0x04600020: + return piBsdDom1Rls; + case 0x04600024: + return piBsdDom2Lat; + case 0x04600028: + return piBsdDom2Pwd; + case 0x0460002C: + return piBsdDom2Pgs; + case 0x04600030: + return piBsdDom2Rls; + default: + Util::panic("Unhandled PI[{:08X}] read", addr); } } u8 PI::GetDomain(u32 address) { switch (address) { - case REGION_PI_UNKNOWN: - case REGION_PI_64DD_ROM: - case REGION_PI_ROM: - return 1; - case REGION_PI_64DD_REG: - case REGION_PI_SRAM: - return 2; - default: - Util::panic("Unknown PI domain for address {:08X}!", address); + case REGION_PI_UNKNOWN: + case REGION_PI_64DD_ROM: + case REGION_PI_ROM: + return 1; + case REGION_PI_64DD_REG: + case REGION_PI_SRAM: + return 2; + default: + Util::panic("Unknown PI domain for address {:08X}!", address); } } @@ -399,20 +462,20 @@ u32 PI::AccessTiming(u8 domain, u32 length) const { uint32_t pages; switch (domain) { - case 1: - latency = piBsdDom1Lat + 1; - pulse_width = piBsdDom1Pwd + 1; - release = piBsdDom1Rls + 1; - page_size = std::pow(2, (piBsdDom1Pgs + 2)); - break; - case 2: - latency = piBsdDom2Lat + 1; - pulse_width = piBsdDom2Pwd + 1; - release = piBsdDom2Rls + 1; - page_size = std::pow(2, (piBsdDom2Pgs + 2)); - break; - default: - Util::panic("Unknown PI domain: {}\n", domain); + case 1: + latency = piBsdDom1Lat + 1; + pulse_width = piBsdDom1Pwd + 1; + release = piBsdDom1Rls + 1; + page_size = std::pow(2, (piBsdDom1Pgs + 2)); + break; + case 2: + latency = piBsdDom2Lat + 1; + pulse_width = piBsdDom2Pwd + 1; + release = piBsdDom2Rls + 1; + page_size = std::pow(2, (piBsdDom2Pgs + 2)); + break; + default: + Util::panic("Unknown PI domain: {}\n", domain); } pages = ceil((double)length / page_size); @@ -424,11 +487,12 @@ u32 PI::AccessTiming(u8 domain, u32 length) const { } // rdram -> cart -template <> void PI::DMA() { +template <> +void PI::DMA() { 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) { + if (mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) { cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1); } @@ -438,60 +502,88 @@ template <> void PI::DMA() { dramAddr += len; dramAddr = (dramAddr + 7) & ~7; cartAddr += len; - if(cartAddr & 1) cartAddr += 1; + if (cartAddr & 1) + cartAddr += 1; dmaBusy = true; scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), rdLen), PI_DMA_COMPLETE); } // cart -> rdram -template <> void PI::DMA() { +template <> +void PI::DMA() { 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) { + if (mem.saveType == SAVE_FLASH_1m && cartAddr >= SREGION_PI_SRAM && cartAddr < 0x08010000) { cartAddr = SREGION_PI_SRAM | ((cartAddr & 0xFFFFF) << 1); } - for(u32 i = 0; i < len; i++) { + for (u32 i = 0; i < len; i++) { mem.mmio.rdp.WriteRDRAM(dramAddr + i, BusRead(cartAddr + i)); } dramAddr += len; dramAddr = (dramAddr + 7) & ~7; cartAddr += len; - if(cartAddr & 1) cartAddr += 1; + if (cartAddr & 1) + cartAddr += 1; dmaBusy = true; scheduler.EnqueueRelative(AccessTiming(GetDomain(cartAddr), len), PI_DMA_COMPLETE); } void PI::Write(u32 addr, u32 val) { - MI& mi = mem.mmio.mi; - switch(addr) { - case 0x04600000: dramAddr = val & 0x00FFFFFE; break; - case 0x04600004: cartAddr = val & 0xFFFFFFFE; break; - case 0x04600008: { + MI &mi = mem.mmio.mi; + switch (addr) { + case 0x04600000: + dramAddr = val & 0x00FFFFFE; + break; + case 0x04600004: + cartAddr = val & 0xFFFFFFFE; + break; + case 0x04600008: + { rdLen = val & 0x00FFFFFF; DMA(); - } break; - case 0x0460000C: { + } + break; + case 0x0460000C: + { wrLen = val & 0x00FFFFFF; DMA(); - } break; - case 0x04600010: - if(val & 2) { - mi.InterruptLower(MI::Interrupt::PI); - } break; - case 0x04600014: piBsdDom1Lat = val & 0xff; break; - case 0x04600018: piBsdDom1Pwd = val & 0xff; break; - case 0x0460001C: piBsdDom1Pgs = val & 0xff; break; - case 0x04600020: piBsdDom1Rls = val & 0xff; break; - case 0x04600024: piBsdDom2Lat = val & 0xff; break; - case 0x04600028: piBsdDom2Pwd = val & 0xff; break; - case 0x0460002C: piBsdDom2Pgs = val & 0xff; break; - case 0x04600030: piBsdDom2Rls = val & 0xff; break; - default: - Util::panic("Unhandled PI[{:08X}] write ({:08X})", val, addr); + } + break; + case 0x04600010: + if (val & 2) { + mi.InterruptLower(MI::Interrupt::PI); + } + break; + case 0x04600014: + piBsdDom1Lat = val & 0xff; + break; + case 0x04600018: + piBsdDom1Pwd = val & 0xff; + break; + case 0x0460001C: + piBsdDom1Pgs = val & 0xff; + break; + case 0x04600020: + piBsdDom1Rls = val & 0xff; + break; + case 0x04600024: + piBsdDom2Lat = val & 0xff; + break; + case 0x04600028: + piBsdDom2Pwd = val & 0xff; + break; + case 0x0460002C: + piBsdDom2Pgs = val & 0xff; + break; + case 0x04600030: + piBsdDom2Rls = val & 0xff; + break; + default: + Util::panic("Unhandled PI[{:08X}] write ({:08X})", val, addr); } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PI.hpp b/src/backend/core/mmio/PI.hpp index d39b9b2e..44944e7b 100644 --- a/src/backend/core/mmio/PI.hpp +++ b/src/backend/core/mmio/PI.hpp @@ -7,17 +7,17 @@ struct Mem; struct Registers; struct PI { - PI(Mem&, Registers&); + PI(Mem &, Registers &); void Reset(); auto Read(u32) const -> u32; void Write(u32, u32); - template + template void BusWrite(u32, u32); - template + template void BusWrite(u32, u64); - template + template auto BusRead(u32) -> T; bool ReadLatch(); @@ -33,11 +33,12 @@ struct PI { u32 piBsdDom1Pwd{}, piBsdDom2Pwd{}; u32 piBsdDom1Pgs{}, piBsdDom2Pgs{}; u32 piBsdDom1Rls{}, piBsdDom2Rls{}; + private: template void DMA(); - Mem& mem; - Registers& regs; + Mem &mem; + Registers ®s; }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PIF.cpp b/src/backend/core/mmio/PIF.cpp index fae33f99..68da81e4 100644 --- a/src/backend/core/mmio/PIF.cpp +++ b/src/backend/core/mmio/PIF.cpp @@ -1,10 +1,10 @@ -#include +#include +#include +#include #include +#include #include #include -#include -#include -#include #define MEMPAK_SIZE 32768 @@ -15,14 +15,18 @@ void PIF::Reset() { bootrom = {}; ram = {}; std::error_code error; - if(mempak.is_mapped()) { + if (mempak.is_mapped()) { mempak.sync(error); - if (error) { Util::panic("Could not sync {}", mempakPath); } + if (error) { + Util::panic("Could not sync {}", mempakPath); + } mempak.unmap(); } - if(eeprom.is_mapped()) { + if (eeprom.is_mapped()) { eeprom.sync(error); - if (error) { Util::panic("Could not sync {}", eepromPath); } + if (error) { + Util::panic("Could not sync {}", eepromPath); + } eeprom.unmap(); } @@ -31,7 +35,7 @@ void PIF::Reset() { } void PIF::MaybeLoadMempak() { - if(!mempakOpen) { + if (!mempakOpen) { fs::path mempakPath_ = mempakPath; if (!savePath.empty()) { mempakPath_ = savePath / mempakPath_.filename(); @@ -40,12 +44,14 @@ void PIF::MaybeLoadMempak() { std::error_code error; if (mempak.is_mapped()) { mempak.sync(error); - if (error) { Util::panic("Could not sync {}", mempakPath); } + if (error) { + Util::panic("Could not sync {}", mempakPath); + } mempak.unmap(); } auto mempakVec = Util::ReadFileBinary(mempakPath); - if(mempak.empty()) { + if (mempak.empty()) { Util::WriteFileBinary(std::array{}, mempakPath); mempakVec = Util::ReadFileBinary(mempakPath); } @@ -54,32 +60,33 @@ void PIF::MaybeLoadMempak() { Util::panic("Corrupt mempak!"); } - mempak = mio::make_mmap_sink( - mempakPath, 0, mio::map_entire_file, error); - if (error) { Util::panic("Could not open {}", mempakPath); } + mempak = mio::make_mmap_sink(mempakPath, 0, mio::map_entire_file, error); + if (error) { + Util::panic("Could not open {}", mempakPath); + } mempakOpen = true; } } FORCE_INLINE size_t GetSaveSize(SaveType saveType) { switch (saveType) { - case SAVE_NONE: - return 0; - case SAVE_EEPROM_4k: - return 512; - case SAVE_EEPROM_16k: - return 2048; - case SAVE_SRAM_256k: - return 32768; - case SAVE_FLASH_1m: - return 131072; - default: - Util::panic("Unknown save type!"); + case SAVE_NONE: + return 0; + case SAVE_EEPROM_4k: + return 512; + case SAVE_EEPROM_16k: + return 2048; + case SAVE_SRAM_256k: + return 32768; + case SAVE_FLASH_1m: + return 131072; + default: + Util::panic("Unknown save type!"); } } -void PIF::LoadEeprom(SaveType saveType, const std::string& path) { - if(saveType == SAVE_EEPROM_16k || saveType == SAVE_EEPROM_4k) { +void PIF::LoadEeprom(SaveType saveType, const std::string &path) { + if (saveType == SAVE_EEPROM_16k || saveType == SAVE_EEPROM_4k) { fs::path eepromPath_ = path; if (!savePath.empty()) { eepromPath_ = savePath / eepromPath_.filename(); @@ -88,14 +95,16 @@ void PIF::LoadEeprom(SaveType saveType, const std::string& path) { std::error_code error; if (eeprom.is_mapped()) { eeprom.sync(error); - if (error) { Util::panic("Could not sync {}", eepromPath); } + if (error) { + Util::panic("Could not sync {}", eepromPath); + } eeprom.unmap(); } eepromSize = GetSaveSize(saveType); auto eepromVec = Util::ReadFileBinary(eepromPath); - if(eepromVec.empty()) { + if (eepromVec.empty()) { std::vector dummy{}; dummy.resize(GetSaveSize(saveType)); Util::WriteFileBinary(dummy, eepromPath); @@ -106,18 +115,14 @@ void PIF::LoadEeprom(SaveType saveType, const std::string& path) { Util::panic("Corrupt eeprom!"); } - eeprom = mio::make_mmap_sink( - eepromPath, 0, mio::map_entire_file, error); - if (error) { Util::panic("Could not open {}", eepromPath); } + eeprom = mio::make_mmap_sink(eepromPath, 0, mio::map_entire_file, error); + if (error) { + Util::panic("Could not open {}", eepromPath); + } } } -enum CMDIndexes { - CMD_LEN = 0, - CMD_RES_LEN, - CMD_IDX, - CMD_START -}; +enum CMDIndexes { CMD_LEN = 0, CMD_RES_LEN, CMD_IDX, CMD_START }; void PIF::CICChallenge() { u8 challenge[30]; @@ -129,14 +134,14 @@ 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((char *)challenge, (char *)response, CHL_LEN - 2); for (int i = 0; i < 15; i++) { ram[0x30 + i] = (response[i * 2] << 4) + response[i * 2 + 1]; } } -FORCE_INLINE u8 DataCRC(const u8* data) { +FORCE_INLINE u8 DataCRC(const u8 *data) { u8 crc = 0; for (int i = 0; i <= 32; i++) { for (int j = 7; j >= 0; j--) { @@ -165,7 +170,7 @@ void PIF::ProcessCommands(Mem &mem) { channel = 0; int i = 0; while (i < 63) { - u8* cmd = &ram[i++]; + u8 *cmd = &ram[i++]; u8 cmdlen = cmd[CMD_LEN] & 0x3F; if (cmdlen == 0 || cmdlen == 0x3D) { @@ -180,58 +185,65 @@ void PIF::ProcessCommands(Mem &mem) { break; } u8 reslen = r & 0x3F; - u8* res = &ram[i + cmdlen]; + u8 *res = &ram[i + cmdlen]; switch (cmd[CMD_IDX]) { - case 0: case 0xff: - ControllerID(res); - channel++; - break; + case 0: + case 0xff: + ControllerID(res); + channel++; + break; + case 1: + if (!ReadButtons(res)) { + cmd[1] |= 0x80; + } + channel++; + break; + case 2: + MempakRead(cmd, res); + break; + case 3: + MempakWrite(cmd, res); + break; + case 4: + EepromRead(cmd, res, mem); + break; + case 5: + EepromWrite(cmd, res, mem); + break; + case 6: + res[0] = 0x00; + res[1] = 0x10; + res[2] = 0x80; + break; + case 7: + switch (cmd[CMD_START]) { + case 0: case 1: - if(!ReadButtons(res)) { - cmd[1] |= 0x80; - } - channel++; + case 3: break; case 2: - MempakRead(cmd, res); - break; - case 3: - MempakWrite(cmd, res); - break; - case 4: - EepromRead(cmd, res, mem); - break; - case 5: - EepromWrite(cmd, res, mem); - break; - case 6: - res[0] = 0x00; - res[1] = 0x10; - res[2] = 0x80; - break; - case 7: - switch(cmd[CMD_START]) { - case 0: case 1: case 3: - break; - case 2: { - auto now = std::time(nullptr); - 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; - res[3] = BCD_ENCODE(gmtm->tm_mday); - res[4] = BCD_ENCODE(gmtm->tm_wday); - res[5] = BCD_ENCODE(gmtm->tm_mon); - res[6] = BCD_ENCODE(gmtm->tm_year); - res[7] = (gmtm->tm_year - 1900) >= 100 ? 1 : 0; - } break; - default: Util::panic("Invalid read RTC block {}", cmd[CMD_START]); + { + auto now = std::time(nullptr); + 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; + res[3] = BCD_ENCODE(gmtm->tm_mday); + res[4] = BCD_ENCODE(gmtm->tm_wday); + res[5] = BCD_ENCODE(gmtm->tm_mon); + res[6] = BCD_ENCODE(gmtm->tm_year); + res[7] = (gmtm->tm_year - 1900) >= 100 ? 1 : 0; } break; - case 8: break; default: - Util::panic("Invalid PIF command: {:X}", cmd[2]); + Util::panic("Invalid read RTC block {}", cmd[CMD_START]); + } + break; + case 8: + break; + default: + Util::panic("Invalid PIF command: {:X}", cmd[2]); } i += cmdlen + reslen; @@ -253,59 +265,60 @@ void PIF::ProcessCommands(Mem &mem) { } } -void PIF::MempakRead(const u8* cmd, u8* res) { +void PIF::MempakRead(const u8 *cmd, u8 *res) { MaybeLoadMempak(); u16 offset = cmd[3] << 8; offset |= cmd[4]; // low 5 bits are the CRC - //byte crc = offset & 0x1F; + // byte crc = offset & 0x1F; // offset must be 32-byte aligned offset &= ~0x1F; switch (GetAccessoryType()) { - case ACCESSORY_NONE: - break; - case ACCESSORY_MEMPACK: - if (offset <= MEMPAK_SIZE - 0x20) { - std::copy_n(mempak.begin() + offset, 32, res); - } - break; - case ACCESSORY_RUMBLE_PACK: - memset(res, 0x80, 32); - break; + case ACCESSORY_NONE: + break; + case ACCESSORY_MEMPACK: + if (offset <= MEMPAK_SIZE - 0x20) { + std::copy_n(mempak.begin() + offset, 32, res); + } + break; + case ACCESSORY_RUMBLE_PACK: + memset(res, 0x80, 32); + break; } // CRC byte res[32] = DataCRC(res); } -void PIF::MempakWrite(u8* cmd, u8* res) { +void PIF::MempakWrite(u8 *cmd, u8 *res) { MaybeLoadMempak(); // First two bytes in the command are the offset u16 offset = cmd[3] << 8; offset |= cmd[4]; // low 5 bits are the CRC - //byte crc = offset & 0x1F; + // byte crc = offset & 0x1F; // offset must be 32-byte aligned offset &= ~0x1F; switch (GetAccessoryType()) { - case ACCESSORY_NONE: - break; - case ACCESSORY_MEMPACK: - if (offset <= MEMPAK_SIZE - 0x20) { - std::copy_n(cmd + 5, 32, mempak.begin() + offset); - } - break; - case ACCESSORY_RUMBLE_PACK: break; + case ACCESSORY_NONE: + break; + case ACCESSORY_MEMPACK: + if (offset <= MEMPAK_SIZE - 0x20) { + std::copy_n(cmd + 5, 32, mempak.begin() + offset); + } + break; + case ACCESSORY_RUMBLE_PACK: + break; } // CRC byte res[0] = DataCRC(&cmd[5]); } -void PIF::EepromRead(const u8* cmd, u8* res, const Mem& mem) const { +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]; @@ -319,7 +332,7 @@ void PIF::EepromRead(const u8* cmd, u8* res, const Mem& mem) const { } } -void PIF::EepromWrite(const u8* cmd, u8* res, const Mem& mem) { +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]; @@ -338,259 +351,259 @@ void PIF::EepromWrite(const u8* cmd, u8* res, const Mem& mem) { void PIF::HLE(bool pal, CICType cicType) { mem.Write(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]); - switch(cicType) { - case UNKNOWN_CIC_TYPE: - Util::warn("Unknown CIC type!"); - break; - case CIC_NUS_6101: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000000); - regs.Write(2, 0xFFFFFFFFDF6445CC); - regs.Write(3, 0xFFFFFFFFDF6445CC); - regs.Write(4, 0x00000000000045CC); - regs.Write(5, 0x0000000073EE317A); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0xFFFFFFFFC7601FAC); - regs.Write(13, 0xFFFFFFFFC7601FAC); - regs.Write(14, 0xFFFFFFFFB48E2ED6); - regs.Write(15, 0xFFFFFFFFBA1A7D4B); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); - regs.Write(20, 0x0000000000000001); - regs.Write(21, 0x0000000000000000); - regs.Write(23, 0x0000000000000001); - regs.Write(24, 0x0000000000000002); - regs.Write(25, 0xFFFFFFFF905F4718); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); - regs.Write(31, 0xFFFFFFFFA4001550); + switch (cicType) { + case UNKNOWN_CIC_TYPE: + Util::warn("Unknown CIC type!"); + break; + case CIC_NUS_6101: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000000); + regs.Write(2, 0xFFFFFFFFDF6445CC); + regs.Write(3, 0xFFFFFFFFDF6445CC); + regs.Write(4, 0x00000000000045CC); + regs.Write(5, 0x0000000073EE317A); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0xFFFFFFFFC7601FAC); + regs.Write(13, 0xFFFFFFFFC7601FAC); + regs.Write(14, 0xFFFFFFFFB48E2ED6); + regs.Write(15, 0xFFFFFFFFBA1A7D4B); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000001); + regs.Write(21, 0x0000000000000000); + regs.Write(23, 0x0000000000000001); + regs.Write(24, 0x0000000000000002); + regs.Write(25, 0xFFFFFFFF905F4718); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001550); - regs.lo = 0xFFFFFFFFBA1A7D4Bll; - regs.hi = 0xFFFFFFFF997EC317ll; - break; - case CIC_NUS_7102: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000001); - regs.Write(2, 0x000000001E324416); - regs.Write(3, 0x000000001E324416); - regs.Write(4, 0x0000000000004416); - regs.Write(5, 0x000000000EC5D9AF); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0x00000000495D3D7B); - regs.Write(13, 0xFFFFFFFF8B3DFA1E); - regs.Write(14, 0x000000004798E4D4); - regs.Write(15, 0xFFFFFFFFF1D30682); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); + regs.lo = 0xFFFFFFFFBA1A7D4Bll; + regs.hi = 0xFFFFFFFF997EC317ll; + break; + case CIC_NUS_7102: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000001); + regs.Write(2, 0x000000001E324416); + regs.Write(3, 0x000000001E324416); + regs.Write(4, 0x0000000000004416); + regs.Write(5, 0x000000000EC5D9AF); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0x00000000495D3D7B); + regs.Write(13, 0xFFFFFFFF8B3DFA1E); + regs.Write(14, 0x000000004798E4D4); + regs.Write(15, 0xFFFFFFFFF1D30682); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000000); + regs.Write(21, 0x0000000000000000); + regs.Write(22, 0x000000000000003F); + regs.Write(23, 0x0000000000000007); + regs.Write(24, 0x0000000000000000); + regs.Write(25, 0x0000000013D05CAB); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001554); + + regs.lo = 0xFFFFFFFFF1D30682ll; + regs.hi = 0x0000000010054A98; + break; + case CIC_NUS_6102_7101: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000001); + regs.Write(2, 0x000000000EBDA536); + regs.Write(3, 0x000000000EBDA536); + regs.Write(4, 0x000000000000A536); + regs.Write(5, 0xFFFFFFFFC0F1D859); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0xFFFFFFFFED10D0B3); + regs.Write(13, 0x000000001402A4CC); + regs.Write(14, 0x000000002DE108EA); + regs.Write(15, 0x000000003103E121); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000001); + regs.Write(21, 0x0000000000000000); + regs.Write(23, 0x0000000000000000); + regs.Write(24, 0x0000000000000000); + regs.Write(25, 0xFFFFFFFF9DEBB54F); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001550); + + regs.hi = 0x000000003FC18657; + regs.lo = 0x000000003103E121; + + if (pal) { regs.Write(20, 0x0000000000000000); - regs.Write(21, 0x0000000000000000); - regs.Write(22, 0x000000000000003F); - regs.Write(23, 0x0000000000000007); - regs.Write(24, 0x0000000000000000); - regs.Write(25, 0x0000000013D05CAB); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); + regs.Write(23, 0x0000000000000006); regs.Write(31, 0xFFFFFFFFA4001554); + } + break; + case CIC_NUS_6103_7103: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000001); + regs.Write(2, 0x0000000049A5EE96); + regs.Write(3, 0x0000000049A5EE96); + regs.Write(4, 0x000000000000EE96); + regs.Write(5, 0xFFFFFFFFD4646273); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0xFFFFFFFFCE9DFBF7); + regs.Write(13, 0xFFFFFFFFCE9DFBF7); + regs.Write(14, 0x000000001AF99984); + regs.Write(15, 0x0000000018B63D28); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000001); + regs.Write(21, 0x0000000000000000); + regs.Write(23, 0x0000000000000000); + regs.Write(24, 0x0000000000000000); + regs.Write(25, 0xFFFFFFFF825B21C9); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001550); - regs.lo = 0xFFFFFFFFF1D30682ll; - regs.hi = 0x0000000010054A98; - break; - case CIC_NUS_6102_7101: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000001); - regs.Write(2, 0x000000000EBDA536); - regs.Write(3, 0x000000000EBDA536); - regs.Write(4, 0x000000000000A536); - regs.Write(5, 0xFFFFFFFFC0F1D859); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0xFFFFFFFFED10D0B3); - regs.Write(13, 0x000000001402A4CC); - regs.Write(14, 0x000000002DE108EA); - regs.Write(15, 0x000000003103E121); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); - regs.Write(20, 0x0000000000000001); - regs.Write(21, 0x0000000000000000); - regs.Write(23, 0x0000000000000000); - regs.Write(24, 0x0000000000000000); - regs.Write(25, 0xFFFFFFFF9DEBB54F); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); - regs.Write(31, 0xFFFFFFFFA4001550); + regs.lo = 0x0000000018B63D28; + regs.hi = 0x00000000625C2BBE; - regs.hi = 0x000000003FC18657; - regs.lo = 0x000000003103E121; + if (pal) { + regs.Write(20, 0x0000000000000000); + regs.Write(23, 0x0000000000000006); + regs.Write(31, 0xFFFFFFFFA4001554); + } + break; + case CIC_NUS_6105_7105: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000000); + regs.Write(2, 0xFFFFFFFFF58B0FBF); + regs.Write(3, 0xFFFFFFFFF58B0FBF); + regs.Write(4, 0x0000000000000FBF); + regs.Write(5, 0xFFFFFFFFDECAAAD1); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0xFFFFFFFF9651F81E); + regs.Write(13, 0x000000002D42AAC5); + regs.Write(14, 0x00000000489B52CF); + regs.Write(15, 0x0000000056584D60); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000001); + regs.Write(21, 0x0000000000000000); + regs.Write(23, 0x0000000000000000); + regs.Write(24, 0x0000000000000002); + regs.Write(25, 0xFFFFFFFFCDCE565F); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001550); - if (pal) { - regs.Write(20, 0x0000000000000000); - regs.Write(23, 0x0000000000000006); - regs.Write(31, 0xFFFFFFFFA4001554); - } - break; - case CIC_NUS_6103_7103: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000001); - regs.Write(2, 0x0000000049A5EE96); - regs.Write(3, 0x0000000049A5EE96); - regs.Write(4, 0x000000000000EE96); - regs.Write(5, 0xFFFFFFFFD4646273); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0xFFFFFFFFCE9DFBF7); - regs.Write(13, 0xFFFFFFFFCE9DFBF7); - regs.Write(14, 0x000000001AF99984); - regs.Write(15, 0x0000000018B63D28); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); - regs.Write(20, 0x0000000000000001); - regs.Write(21, 0x0000000000000000); - regs.Write(23, 0x0000000000000000); - regs.Write(24, 0x0000000000000000); - regs.Write(25, 0xFFFFFFFF825B21C9); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); - regs.Write(31, 0xFFFFFFFFA4001550); + regs.lo = 0x0000000056584D60; + regs.hi = 0x000000004BE35D1F; - regs.lo = 0x0000000018B63D28; - regs.hi = 0x00000000625C2BBE; + if (pal) { + regs.Write(20, 0x0000000000000000); + regs.Write(23, 0x0000000000000006); + regs.Write(31, 0xFFFFFFFFA4001554); + } - if (pal) { - regs.Write(20, 0x0000000000000000); - regs.Write(23, 0x0000000000000006); - regs.Write(31, 0xFFFFFFFFA4001554); - } - break; - case CIC_NUS_6105_7105: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000000); - regs.Write(2, 0xFFFFFFFFF58B0FBF); - regs.Write(3, 0xFFFFFFFFF58B0FBF); - regs.Write(4, 0x0000000000000FBF); - regs.Write(5, 0xFFFFFFFFDECAAAD1); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0xFFFFFFFF9651F81E); - regs.Write(13, 0x000000002D42AAC5); - regs.Write(14, 0x00000000489B52CF); - regs.Write(15, 0x0000000056584D60); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); - regs.Write(20, 0x0000000000000001); - regs.Write(21, 0x0000000000000000); - regs.Write(23, 0x0000000000000000); - regs.Write(24, 0x0000000000000002); - regs.Write(25, 0xFFFFFFFFCDCE565F); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); - regs.Write(31, 0xFFFFFFFFA4001550); + mem.Write(regs, IMEM_REGION_START + 0x00, 0x3C0DBFC0); + mem.Write(regs, IMEM_REGION_START + 0x04, 0x8DA807FC); + mem.Write(regs, IMEM_REGION_START + 0x08, 0x25AD07C0); + mem.Write(regs, IMEM_REGION_START + 0x0C, 0x31080080); + mem.Write(regs, IMEM_REGION_START + 0x10, 0x5500FFFC); + mem.Write(regs, IMEM_REGION_START + 0x14, 0x3C0DBFC0); + mem.Write(regs, IMEM_REGION_START + 0x18, 0x8DA80024); + mem.Write(regs, IMEM_REGION_START + 0x1C, 0x3C0BB000); + break; + case CIC_NUS_6106_7106: + regs.Write(0, 0x0000000000000000); + regs.Write(1, 0x0000000000000000); + regs.Write(2, 0xFFFFFFFFA95930A4); + regs.Write(3, 0xFFFFFFFFA95930A4); + regs.Write(4, 0x00000000000030A4); + regs.Write(5, 0xFFFFFFFFB04DC903); + regs.Write(6, 0xFFFFFFFFA4001F0C); + regs.Write(7, 0xFFFFFFFFA4001F08); + regs.Write(8, 0x00000000000000C0); + regs.Write(9, 0x0000000000000000); + regs.Write(10, 0x0000000000000040); + regs.Write(11, 0xFFFFFFFFA4000040); + regs.Write(12, 0xFFFFFFFFBCB59510); + regs.Write(13, 0xFFFFFFFFBCB59510); + regs.Write(14, 0x000000000CF85C13); + regs.Write(15, 0x000000007A3C07F4); + regs.Write(16, 0x0000000000000000); + regs.Write(17, 0x0000000000000000); + regs.Write(18, 0x0000000000000000); + regs.Write(19, 0x0000000000000000); + regs.Write(20, 0x0000000000000001); + regs.Write(21, 0x0000000000000000); + regs.Write(23, 0x0000000000000000); + regs.Write(24, 0x0000000000000002); + regs.Write(25, 0x00000000465E3F72); + regs.Write(26, 0x0000000000000000); + regs.Write(27, 0x0000000000000000); + regs.Write(28, 0x0000000000000000); + regs.Write(29, 0xFFFFFFFFA4001FF0); + regs.Write(30, 0x0000000000000000); + regs.Write(31, 0xFFFFFFFFA4001550); + regs.lo = 0x000000007A3C07F4; + regs.hi = 0x0000000023953898; - regs.lo = 0x0000000056584D60; - regs.hi = 0x000000004BE35D1F; - - if (pal) { - regs.Write(20, 0x0000000000000000); - regs.Write(23, 0x0000000000000006); - regs.Write(31, 0xFFFFFFFFA4001554); - } - - mem.Write(regs, IMEM_REGION_START + 0x00, 0x3C0DBFC0); - mem.Write(regs, IMEM_REGION_START + 0x04, 0x8DA807FC); - mem.Write(regs, IMEM_REGION_START + 0x08, 0x25AD07C0); - mem.Write(regs, IMEM_REGION_START + 0x0C, 0x31080080); - mem.Write(regs, IMEM_REGION_START + 0x10, 0x5500FFFC); - mem.Write(regs, IMEM_REGION_START + 0x14, 0x3C0DBFC0); - mem.Write(regs, IMEM_REGION_START + 0x18, 0x8DA80024); - mem.Write(regs, IMEM_REGION_START + 0x1C, 0x3C0BB000); - break; - case CIC_NUS_6106_7106: - regs.Write(0, 0x0000000000000000); - regs.Write(1, 0x0000000000000000); - regs.Write(2, 0xFFFFFFFFA95930A4); - regs.Write(3, 0xFFFFFFFFA95930A4); - regs.Write(4, 0x00000000000030A4); - regs.Write(5, 0xFFFFFFFFB04DC903); - regs.Write(6, 0xFFFFFFFFA4001F0C); - regs.Write(7, 0xFFFFFFFFA4001F08); - regs.Write(8, 0x00000000000000C0); - regs.Write(9, 0x0000000000000000); - regs.Write(10, 0x0000000000000040); - regs.Write(11, 0xFFFFFFFFA4000040); - regs.Write(12, 0xFFFFFFFFBCB59510); - regs.Write(13, 0xFFFFFFFFBCB59510); - regs.Write(14, 0x000000000CF85C13); - regs.Write(15, 0x000000007A3C07F4); - regs.Write(16, 0x0000000000000000); - regs.Write(17, 0x0000000000000000); - regs.Write(18, 0x0000000000000000); - regs.Write(19, 0x0000000000000000); - regs.Write(20, 0x0000000000000001); - regs.Write(21, 0x0000000000000000); - regs.Write(23, 0x0000000000000000); - regs.Write(24, 0x0000000000000002); - regs.Write(25, 0x00000000465E3F72); - regs.Write(26, 0x0000000000000000); - regs.Write(27, 0x0000000000000000); - regs.Write(28, 0x0000000000000000); - regs.Write(29, 0xFFFFFFFFA4001FF0); - regs.Write(30, 0x0000000000000000); - regs.Write(31, 0xFFFFFFFFA4001550); - regs.lo = 0x000000007A3C07F4; - regs.hi = 0x0000000023953898; - - if (pal) { - regs.Write(20, 0x0000000000000000); - regs.Write(23, 0x0000000000000006); - regs.Write(31, 0xFFFFFFFFA4001554); - } - break; + if (pal) { + regs.Write(20, 0x0000000000000000); + regs.Write(23, 0x0000000000000006); + regs.Write(31, 0xFFFFFFFFA4001554); + } + break; } regs.Write(22, (cicSeeds[cicType] >> 8) & 0xFF); @@ -604,18 +617,18 @@ void PIF::Execute() { CICType cicType = mem.rom.cicType; bool pal = mem.rom.pal; mem.Write(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]); - switch(cicType) { - case UNKNOWN_CIC_TYPE: - Util::warn("Unknown CIC type!"); - break; - case CIC_NUS_6101 ... CIC_NUS_6103_7103: - mem.Write(regs, 0x318, RDRAM_SIZE); - break; - case CIC_NUS_6105_7105: - mem.Write(regs, 0x3F0, RDRAM_SIZE); - break; - case CIC_NUS_6106_7106: - break; + switch (cicType) { + case UNKNOWN_CIC_TYPE: + Util::warn("Unknown CIC type!"); + break; + case CIC_NUS_6101 ... CIC_NUS_6103_7103: + mem.Write(regs, 0x318, RDRAM_SIZE); + break; + case CIC_NUS_6105_7105: + mem.Write(regs, 0x3F0, RDRAM_SIZE); + break; + case CIC_NUS_6106_7106: + break; } HLE(pal, cicType); @@ -623,17 +636,11 @@ void PIF::Execute() { std::vector PIF::Serialize() { std::vector res{}; - res.resize( - 6*sizeof(JoybusDevice) + - PIF_BOOTROM_SIZE + - PIF_RAM_SIZE + - mempak.size() + - eeprom.size() + - sizeof(int)); + res.resize(6 * sizeof(JoybusDevice) + PIF_BOOTROM_SIZE + PIF_RAM_SIZE + mempak.size() + eeprom.size() + sizeof(int)); u32 index = 0; - memcpy(res.data() + index, joybusDevices.data(), 6*sizeof(JoybusDevice)); - index += 6*sizeof(JoybusDevice); + memcpy(res.data() + index, joybusDevices.data(), 6 * sizeof(JoybusDevice)); + index += 6 * sizeof(JoybusDevice); memcpy(res.data() + index, bootrom.data(), PIF_BOOTROM_SIZE); index += PIF_BOOTROM_SIZE; memcpy(res.data() + index, ram.data(), PIF_RAM_SIZE); @@ -646,4 +653,4 @@ std::vector PIF::Serialize() { return res; } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PIF.hpp b/src/backend/core/mmio/PIF.hpp index 0833e8bc..1ddfcdea 100644 --- a/src/backend/core/mmio/PIF.hpp +++ b/src/backend/core/mmio/PIF.hpp @@ -1,21 +1,17 @@ #pragma once -#include #include +#include +#include #include #include #include -#include #include "MupenMovie.hpp" namespace fs = std::filesystem; namespace n64 { -enum AccessoryType : u8 { - ACCESSORY_NONE, - ACCESSORY_MEMPACK, - ACCESSORY_RUMBLE_PACK -}; +enum AccessoryType : u8 { ACCESSORY_NONE, ACCESSORY_MEMPACK, ACCESSORY_RUMBLE_PACK }; struct Controller { union { @@ -23,27 +19,27 @@ struct Controller { union { u8 byte1; struct { - bool dpRight: 1; - bool dpLeft: 1; - bool dpDown: 1; - bool dpUp: 1; - bool start: 1; - bool z: 1; - bool b: 1; - bool a: 1; + bool dpRight : 1; + bool dpLeft : 1; + bool dpDown : 1; + bool dpUp : 1; + bool start : 1; + bool z : 1; + bool b : 1; + bool a : 1; }; }; union { u8 byte2; struct { - bool cRight: 1; - bool cLeft: 1; - bool cDown: 1; - bool cUp: 1; - bool r: 1; - bool l: 1; - bool zero: 1; - bool joyReset: 1; + bool cRight : 1; + bool cLeft : 1; + bool cDown : 1; + bool cUp : 1; + bool r : 1; + bool l : 1; + bool zero : 1; + bool joyReset : 1; }; }; @@ -53,7 +49,7 @@ struct Controller { u32 raw; }; - Controller& operator=(const Controller& other) { + Controller &operator=(const Controller &other) { byte1 = other.byte1; byte2 = other.byte2; joyX = other.joyX; @@ -62,40 +58,70 @@ struct Controller { return *this; } - enum Key { - A, B, Z, Start, DUp, DDown, DLeft, DRight, CUp, CDown, CLeft, CRight, LT, RT - }; + enum Key { A, B, Z, Start, DUp, DDown, DLeft, DRight, CUp, CDown, CLeft, CRight, LT, RT }; enum Axis { X, Y }; Controller() = default; void UpdateButton(Key k, bool state) { - switch(k) { - case A: a = state; break; - case B: b = state; break; - case Z: z = state; break; - case Start: start = state; break; - case DUp: dpUp = state; break; - case DDown: dpDown = state; break; - case DLeft: dpLeft = state; break; - case DRight: dpRight = state; break; - case CUp: cUp = state; break; - case CDown: cDown = state; break; - case CLeft: cLeft = state; break; - case CRight: cRight = state; break; - case LT: l = state; break; - case RT: r = state; break; + switch (k) { + case A: + a = state; + break; + case B: + b = state; + break; + case Z: + z = state; + break; + case Start: + start = state; + break; + case DUp: + dpUp = state; + break; + case DDown: + dpDown = state; + break; + case DLeft: + dpLeft = state; + break; + case DRight: + dpRight = state; + break; + case CUp: + cUp = state; + break; + case CDown: + cDown = state; + break; + case CLeft: + cLeft = state; + break; + case CRight: + cRight = state; + break; + case LT: + l = state; + break; + case RT: + r = state; + break; } } void UpdateAxis(Axis a, s8 state) { - switch(a) { - case X: joyX = state; break; - case Y: joyY = state; break; + switch (a) { + case X: + joyX = state; + break; + case Y: + joyY = state; + break; } } - Controller& operator=(u32 v) { + Controller &operator=(u32 v) { joyY = v & 0xff; joyX = v >> 8; byte2 = v >> 16; @@ -153,30 +179,28 @@ enum CICType { }; struct PIF { - PIF(Mem& mem, Registers& regs) : mem(mem), regs(regs) {} + PIF(Mem &mem, Registers ®s) : mem(mem), regs(regs) {} ~PIF() = default; void Reset(); void MaybeLoadMempak(); - void LoadEeprom(SaveType, const std::string&); - void ProcessCommands(Mem&); + void LoadEeprom(SaveType, const std::string &); + void ProcessCommands(Mem &); void InitDevices(SaveType); void CICChallenge(); void Execute(); void HLE(bool pal, CICType cicType); - bool ReadButtons(u8*); - void ControllerID(u8*) const; - void MempakRead(const u8*, u8*); - void MempakWrite(u8*, u8*); - void EepromRead(const u8*, u8*, const Mem&) const; - void EepromWrite(const u8*, u8*, const Mem&); + bool ReadButtons(u8 *); + void ControllerID(u8 *) const; + void MempakRead(const u8 *, u8 *); + void MempakWrite(u8 *, u8 *); + void EepromRead(const u8 *, u8 *, const Mem &) const; + void EepromWrite(const u8 *, u8 *, const Mem &); std::vector Serialize(); void UpdateButton(int index, Controller::Key k, bool state) { joybusDevices[index].controller.UpdateButton(k, state); } - void UpdateAxis(int index, Controller::Axis a, s8 state) { - joybusDevices[index].controller.UpdateAxis(a, state); - } + void UpdateAxis(int index, Controller::Axis a, s8 state) { joybusDevices[index].controller.UpdateAxis(a, state); } bool mempakOpen = false; std::array joybusDevices{}; @@ -187,18 +211,20 @@ struct PIF { std::string mempakPath{}, eepromPath{}; size_t eepromSize{}; MupenMovie movie; - Mem& mem; - Registers& regs; + Mem &mem; + Registers ®s; FORCE_INLINE u8 Read(u32 addr) { addr &= 0x7FF; - if(addr < 0x7c0) return bootrom[addr]; + if (addr < 0x7c0) + return bootrom[addr]; return ram[addr & PIF_RAM_DSIZE]; } FORCE_INLINE void Write(u32 addr, u8 val) { addr &= 0x7FF; - if(addr < 0x7c0) return; + if (addr < 0x7c0) + return; ram[addr & PIF_RAM_DSIZE] = val; } @@ -210,4 +236,4 @@ struct PIF { } } }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PIF/Device.cpp b/src/backend/core/mmio/PIF/Device.cpp index 441108be..ab0236b2 100644 --- a/src/backend/core/mmio/PIF/Device.cpp +++ b/src/backend/core/mmio/PIF/Device.cpp @@ -1,13 +1,13 @@ +#include #include #include -#include #include namespace n64 { void PIF::InitDevices(SaveType saveType) { joybusDevices[0].type = JOYBUS_CONTROLLER; joybusDevices[0].accessoryType = ACCESSORY_MEMPACK; - for (int i = 1; i < 4; i++) { //TODO: make this configurable + for (int i = 1; i < 4; i++) { // TODO: make this configurable joybusDevices[i].type = JOYBUS_NONE; joybusDevices[i].accessoryType = ACCESSORY_NONE; } @@ -25,59 +25,59 @@ void PIF::InitDevices(SaveType saveType) { void PIF::ControllerID(u8 *res) const { if (channel < 6) { switch (joybusDevices[channel].type) { - case JOYBUS_NONE: - res[0] = 0x00; - res[1] = 0x00; - res[2] = 0x00; - break; - case JOYBUS_CONTROLLER: - res[0] = 0x05; - res[1] = 0x00; - res[2] = joybusDevices[channel].accessoryType != ACCESSORY_NONE ? 0x01 : 0x02; - break; - case JOYBUS_DANCEPAD: - res[0] = 0x05; - res[1] = 0x00; - res[2] = 0x00; - break; - case JOYBUS_VRU: - res[0] = 0x00; - res[1] = 0x01; - res[2] = 0x00; - break; - case JOYBUS_MOUSE: - res[0] = 0x02; - res[1] = 0x00; - res[2] = 0x00; - break; - case JOYBUS_RANDNET_KEYBOARD: - res[0] = 0x00; - res[1] = 0x02; - res[2] = 0x00; - break; - case JOYBUS_DENSHA_DE_GO: - res[0] = 0x20; - res[1] = 0x04; - res[2] = 0x00; - break; - case JOYBUS_4KB_EEPROM: - res[0] = 0x00; - res[1] = 0x80; - res[2] = 0x00; - break; - case JOYBUS_16KB_EEPROM: - res[0] = 0x00; - res[1] = 0xC0; - res[2] = 0x00; - break; + case JOYBUS_NONE: + res[0] = 0x00; + res[1] = 0x00; + res[2] = 0x00; + break; + case JOYBUS_CONTROLLER: + res[0] = 0x05; + res[1] = 0x00; + res[2] = joybusDevices[channel].accessoryType != ACCESSORY_NONE ? 0x01 : 0x02; + break; + case JOYBUS_DANCEPAD: + res[0] = 0x05; + res[1] = 0x00; + res[2] = 0x00; + break; + case JOYBUS_VRU: + res[0] = 0x00; + res[1] = 0x01; + res[2] = 0x00; + break; + case JOYBUS_MOUSE: + res[0] = 0x02; + res[1] = 0x00; + res[2] = 0x00; + break; + case JOYBUS_RANDNET_KEYBOARD: + res[0] = 0x00; + res[1] = 0x02; + res[2] = 0x00; + break; + case JOYBUS_DENSHA_DE_GO: + res[0] = 0x20; + res[1] = 0x04; + res[2] = 0x00; + break; + case JOYBUS_4KB_EEPROM: + res[0] = 0x00; + res[1] = 0x80; + res[2] = 0x00; + break; + case JOYBUS_16KB_EEPROM: + res[0] = 0x00; + res[1] = 0xC0; + res[2] = 0x00; + break; } } else { Util::panic("Device ID on unknown channel {}", channel); } } -bool PIF::ReadButtons(u8* res) { - if(channel >= 6) { +bool PIF::ReadButtons(u8 *res) { + if (channel >= 6) { res[0] = 0; res[1] = 0; res[2] = 0; @@ -86,36 +86,36 @@ bool PIF::ReadButtons(u8* res) { } switch (joybusDevices[channel].type) { - case JOYBUS_NONE: - res[0] = 0x00; - res[1] = 0x00; - res[2] = 0x00; - res[3] = 0x00; - return false; // Device not present - case JOYBUS_4KB_EEPROM: - case JOYBUS_16KB_EEPROM: - case JOYBUS_CONTROLLER: - if (movie.IsLoaded()) { - Controller controller = movie.NextInputs(); - res[0] = controller.byte1; - res[1] = controller.byte2; - res[2] = controller.joyX; - res[3] = controller.joyY; - } else { - res[0] = joybusDevices[channel].controller.byte1; - res[1] = joybusDevices[channel].controller.byte2; - res[2] = joybusDevices[channel].controller.joyX; - res[3] = joybusDevices[channel].controller.joyY; - } - return true; - case JOYBUS_DANCEPAD: - case JOYBUS_VRU: - case JOYBUS_MOUSE: - case JOYBUS_RANDNET_KEYBOARD: - case JOYBUS_DENSHA_DE_GO: - return false; + case JOYBUS_NONE: + res[0] = 0x00; + res[1] = 0x00; + res[2] = 0x00; + res[3] = 0x00; + return false; // Device not present + case JOYBUS_4KB_EEPROM: + case JOYBUS_16KB_EEPROM: + case JOYBUS_CONTROLLER: + if (movie.IsLoaded()) { + Controller controller = movie.NextInputs(); + res[0] = controller.byte1; + res[1] = controller.byte2; + res[2] = controller.joyX; + res[3] = controller.joyY; + } else { + res[0] = joybusDevices[channel].controller.byte1; + res[1] = joybusDevices[channel].controller.byte2; + res[2] = joybusDevices[channel].controller.joyX; + res[3] = joybusDevices[channel].controller.joyY; + } + return true; + case JOYBUS_DANCEPAD: + case JOYBUS_VRU: + case JOYBUS_MOUSE: + case JOYBUS_RANDNET_KEYBOARD: + case JOYBUS_DENSHA_DE_GO: + return false; } return true; } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/PIF/MupenMovie.cpp b/src/backend/core/mmio/PIF/MupenMovie.cpp index fa9ce1ae..1ecf9e00 100644 --- a/src/backend/core/mmio/PIF/MupenMovie.cpp +++ b/src/backend/core/mmio/PIF/MupenMovie.cpp @@ -5,20 +5,20 @@ union TASMovieControllerData { struct { - unsigned dpadRight: 1; - unsigned dpadLeft: 1; - unsigned dpadDown: 1; - unsigned dpadUp: 1; - unsigned start: 1; - unsigned z: 1; - unsigned b: 1; - unsigned a: 1; - unsigned cRight: 1; - unsigned cLeft: 1; - unsigned cDown: 1; - unsigned cUp: 1; - unsigned r: 1; - unsigned l: 1; + unsigned dpadRight : 1; + unsigned dpadLeft : 1; + unsigned dpadDown : 1; + unsigned dpadUp : 1; + unsigned start : 1; + unsigned z : 1; + unsigned b : 1; + unsigned a : 1; + unsigned cRight : 1; + unsigned cLeft : 1; + unsigned cDown : 1; + unsigned cUp : 1; + unsigned r : 1; + unsigned l : 1; unsigned : 2; signed analogX : 8; signed analogY : 8; @@ -30,14 +30,15 @@ static_assert(sizeof(TASMovieControllerData) == 4); bool MupenMovie::Load(const fs::path &path) { loadedTasMovie = Util::ReadFileBinary(path.string()); - if(!IsLoaded()) { + if (!IsLoaded()) { Util::error("Error loading movie!"); return false; } memcpy(&loadedTasMovieHeader, loadedTasMovie.data(), sizeof(TASMovieHeader)); - if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 || loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) { + if (loadedTasMovieHeader.signature[0] != 0x4D || loadedTasMovieHeader.signature[1] != 0x36 || + loadedTasMovieHeader.signature[2] != 0x34 || loadedTasMovieHeader.signature[3] != 0x1A) { Util::error("Failed to load movie: incorrect signature. Are you sure this is a valid movie?"); return false; } @@ -48,7 +49,8 @@ bool MupenMovie::Load(const fs::path &path) { } if (loadedTasMovieHeader.startType != 2) { - Util::error("Movie start type is {} - only movies with a start type of 2 are supported (start at power on)", loadedTasMovieHeader.startType); + Util::error("Movie start type is {} - only movies with a start type of 2 are supported (start at power on)", + loadedTasMovieHeader.startType); return false; } @@ -66,18 +68,19 @@ bool MupenMovie::Load(const fs::path &path) { } MupenMovie::MupenMovie(const fs::path &path) { - if(!Load(path)) { + if (!Load(path)) { Util::panic(""); } } void MupenMovie::Reset() { - if(!IsLoaded()) return; + if (!IsLoaded()) + return; loadedTasMovieIndex = sizeof(TASMovieHeader) - 4; // skip header } -FORCE_INLINE void LogController(const n64::Controller& controller) { +FORCE_INLINE void LogController(const n64::Controller &controller) { Util::debug("c_right: {}", controller.cRight); Util::debug("c_left: {}", controller.cLeft); Util::debug("c_down: {}", controller.cDown); @@ -133,4 +136,4 @@ n64::Controller MupenMovie::NextInputs() { LogController(controller); return controller; -} \ No newline at end of file +} diff --git a/src/backend/core/mmio/PIF/MupenMovie.hpp b/src/backend/core/mmio/PIF/MupenMovie.hpp index 9cbcc9b5..ac2cc5d4 100644 --- a/src/backend/core/mmio/PIF/MupenMovie.hpp +++ b/src/backend/core/mmio/PIF/MupenMovie.hpp @@ -47,13 +47,14 @@ static_assert(sizeof(TASMovieHeader) == 1024); struct MupenMovie { MupenMovie() = default; - MupenMovie(const fs::path&); - bool Load(const fs::path&); + MupenMovie(const fs::path &); + bool Load(const fs::path &); void Reset(); n64::Controller NextInputs(); bool IsLoaded() const { return !loadedTasMovie.empty(); } + private: std::vector loadedTasMovie = {}; TASMovieHeader loadedTasMovieHeader = {}; uint32_t loadedTasMovieIndex = 0; -}; \ No newline at end of file +}; diff --git a/src/backend/core/mmio/RI.cpp b/src/backend/core/mmio/RI.cpp index 0955c4a5..31ab4c7f 100644 --- a/src/backend/core/mmio/RI.cpp +++ b/src/backend/core/mmio/RI.cpp @@ -2,9 +2,7 @@ #include namespace n64 { -RI::RI() { - Reset(); -} +RI::RI() { Reset(); } void RI::Reset() { mode = 0xE; @@ -14,24 +12,36 @@ void RI::Reset() { } auto RI::Read(u32 addr) const -> u32 { - switch(addr) { - case 0x04700000: return mode; - case 0x04700004: return config; - case 0x0470000C: return select; - case 0x04700010: return refresh; - default: - Util::panic("Unhandled RI[{:08X}] read", addr); + switch (addr) { + case 0x04700000: + return mode; + case 0x04700004: + return config; + case 0x0470000C: + return select; + case 0x04700010: + return refresh; + default: + Util::panic("Unhandled RI[{:08X}] read", addr); } } void RI::Write(u32 addr, u32 val) { - switch(addr) { - case 0x04700000: mode = val; break; - case 0x04700004: config = val; break; - case 0x0470000C: select = val; break; - case 0x04700010: refresh = val; break; - default: - Util::panic("Unhandled RI[{:08X}] write with val {:08X}", addr, val); + switch (addr) { + case 0x04700000: + mode = val; + break; + case 0x04700004: + config = val; + break; + case 0x0470000C: + select = val; + break; + case 0x04700010: + refresh = val; + break; + default: + Util::panic("Unhandled RI[{:08X}] write with val {:08X}", addr, val); } } -} +} // namespace n64 diff --git a/src/backend/core/mmio/RI.hpp b/src/backend/core/mmio/RI.hpp index 36cd4ee7..a874ccf9 100644 --- a/src/backend/core/mmio/RI.hpp +++ b/src/backend/core/mmio/RI.hpp @@ -11,4 +11,4 @@ struct RI { u32 mode{0xE}, config{0x40}, select{0x14}, refresh{0x63634}; }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index 8ad33b9b..f72a41f8 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -1,11 +1,9 @@ -#include -#include #include +#include +#include namespace n64 { -SI::SI(Mem& mem, Registers& regs) : mem(mem), regs(regs), pif(mem, regs) { - Reset(); -} +SI::SI(Mem &mem, Registers ®s) : mem(mem), regs(regs), pif(mem, regs) { Reset(); } void SI::Reset() { status.raw = 0; @@ -16,35 +14,40 @@ void SI::Reset() { } auto SI::Read(u32 addr) const -> u32 { - switch(addr) { - case 0x04800000: return dramAddr; - case 0x04800004: case 0x04800010: return pifAddr; - case 0x0480000C: return 0; - case 0x04800018: { - u32 val = 0; - val |= status.dmaBusy; - val |= (0 << 1); - val |= (0 << 3); - val |= (mem.mmio.mi.miIntr.si << 12); - return val; - } - default: - Util::panic("Unhandled SI[{:08X}] read", addr); + switch (addr) { + case 0x04800000: + return dramAddr; + case 0x04800004: + case 0x04800010: + return pifAddr; + case 0x0480000C: + return 0; + case 0x04800018: + u32 val = 0; + val |= status.dmaBusy; + val |= (0 << 1); + val |= (0 << 3); + val |= (mem.mmio.mi.miIntr.si << 12); + return val; + default: + Util::panic("Unhandled SI[{:08X}] read", addr); } } // pif -> rdram -template <> void SI::DMA() { +template <> +void SI::DMA() { pif.ProcessCommands(mem); - for(int i = 0; i < 64; i++) { + for (int i = 0; i < 64; i++) { mem.mmio.rdp.WriteRDRAM(dramAddr + i, pif.Read(pifAddr + i)); } Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", pifAddr, dramAddr); } // rdram -> pif -template <> void SI::DMA() { - for(int i = 0; i < 64; i++) { +template <> +void SI::DMA() { + for (int i = 0; i < 64; i++) { pif.Write(pifAddr + i, mem.mmio.rdp.ReadRDRAM(dramAddr + i)); } Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", dramAddr, pifAddr); @@ -52,33 +55,35 @@ template <> void SI::DMA() { void SI::DMA() { status.dmaBusy = false; - if (toDram) DMA(); - else DMA(); + if (toDram) + DMA(); + else + DMA(); mem.mmio.mi.InterruptRaise(MI::Interrupt::SI); } void SI::Write(u32 addr, u32 val) { - switch(addr) { - case 0x04800000: - dramAddr = val & RDRAM_DSIZE; - break; - case 0x04800004: { - pifAddr = val & 0x1FFFFFFF; - status.dmaBusy = true; - toDram = true; - scheduler.EnqueueRelative(SI_DMA_DELAY, SI_DMA); - } break; - case 0x04800010: { - pifAddr = val & 0x1FFFFFFF; - status.dmaBusy = true; - toDram = false; - scheduler.EnqueueRelative(SI_DMA_DELAY, SI_DMA); - } break; - case 0x04800018: - mem.mmio.mi.InterruptLower(MI::Interrupt::SI); - break; - default: - Util::panic("Unhandled SI[{:08X}] write ({:08X})", addr, val); + switch (addr) { + case 0x04800000: + dramAddr = val & RDRAM_DSIZE; + break; + case 0x04800004: + pifAddr = val & 0x1FFFFFFF; + status.dmaBusy = true; + toDram = true; + scheduler.EnqueueRelative(SI_DMA_DELAY, SI_DMA); + break; + case 0x04800010: + pifAddr = val & 0x1FFFFFFF; + status.dmaBusy = true; + toDram = false; + scheduler.EnqueueRelative(SI_DMA_DELAY, SI_DMA); + break; + case 0x04800018: + mem.mmio.mi.InterruptLower(MI::Interrupt::SI); + break; + default: + Util::panic("Unhandled SI[{:08X}] write ({:08X})", addr, val); } } -} +} // namespace n64 diff --git a/src/backend/core/mmio/SI.hpp b/src/backend/core/mmio/SI.hpp index d0d82a23..cbd0a3da 100644 --- a/src/backend/core/mmio/SI.hpp +++ b/src/backend/core/mmio/SI.hpp @@ -8,19 +8,19 @@ namespace n64 { union SIStatus { u32 raw{}; struct { - unsigned dmaBusy:1; - unsigned ioBusy:1; - unsigned reserved:1; - unsigned dmaErr:1; - unsigned:8; - unsigned intr:1; + unsigned dmaBusy : 1; + unsigned ioBusy : 1; + unsigned reserved : 1; + unsigned dmaErr : 1; + unsigned : 8; + unsigned intr : 1; }; }; struct Mem; struct SI { - SI(Mem&, Registers&); + SI(Mem &, Registers &); void Reset(); SIStatus status{}; u32 dramAddr{}; @@ -33,10 +33,11 @@ struct SI { void DMA(); void DMA(); PIF pif; + private: - Mem& mem; - Registers& regs; + Mem &mem; + Registers ®s; }; #define SI_DMA_DELAY (65536 * 2) -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/VI.cpp b/src/backend/core/mmio/VI.cpp index 47dc3b60..f5e369ab 100644 --- a/src/backend/core/mmio/VI.cpp +++ b/src/backend/core/mmio/VI.cpp @@ -1,12 +1,10 @@ -#include -#include -#include #include +#include +#include +#include namespace n64 { -VI::VI (Mem& mem, Registers& regs) : mem(mem), regs(regs) { - Reset(); -} +VI::VI(Mem &mem, Registers ®s) : mem(mem), regs(regs) { Reset(); } void VI::Reset() { status.raw = 0xF; @@ -27,65 +25,95 @@ void VI::Reset() { } u32 VI::Read(u32 paddr) const { - switch(paddr) { - case 0x04400000: return status.raw; - case 0x04400004: return origin; - case 0x04400008: return width; - case 0x0440000C: return intr; - case 0x04400010: return current << 1; - case 0x04400014: return burst.raw; - case 0x04400018: return vsync; - case 0x0440001C: return hsync; - case 0x04400020: return hsyncLeap.raw; - case 0x04400024: return hstart.raw; - case 0x04400028: return vstart.raw; - case 0x0440002C: return vburst; - case 0x04400030: return xscale.raw; - case 0x04400034: return yscale.raw; - default: - Util::panic("Unimplemented VI[%08X] read", paddr); + switch (paddr) { + case 0x04400000: + return status.raw; + case 0x04400004: + return origin; + case 0x04400008: + return width; + case 0x0440000C: + return intr; + case 0x04400010: + return current << 1; + case 0x04400014: + return burst.raw; + case 0x04400018: + return vsync; + case 0x0440001C: + return hsync; + case 0x04400020: + return hsyncLeap.raw; + case 0x04400024: + return hstart.raw; + case 0x04400028: + return vstart.raw; + case 0x0440002C: + return vburst; + case 0x04400030: + return xscale.raw; + case 0x04400034: + return yscale.raw; + default: + Util::panic("Unimplemented VI[%08X] read", paddr); } } void VI::Write(u32 paddr, u32 val) { - switch(paddr) { - case 0x04400000: - status.raw = val; - numFields = status.serrate ? 2 : 1; - break; - case 0x04400004: { + switch (paddr) { + case 0x04400000: + status.raw = val; + numFields = status.serrate ? 2 : 1; + break; + case 0x04400004: + { u32 masked = val & 0xFFFFFF; - if(origin != masked) { + if (origin != masked) { swaps++; } origin = masked; - } break; - case 0x04400008: { - width = val & 0x7FF; - } break; - case 0x0440000C: { - intr = val & 0x3FF; - } break; - case 0x04400010: - mem.mmio.mi.InterruptLower(MI::Interrupt::VI); - break; - case 0x04400014: burst.raw = val; break; - case 0x04400018: { - vsync = val & 0x3FF; - numHalflines = vsync >> 1; - cyclesPerHalfline = GetCyclesPerFrame(isPal) / numHalflines; - } break; - case 0x0440001C: { - hsync = val & 0x3FF; - } break; - case 0x04400020: hsyncLeap.raw = val; break; - case 0x04400024: hstart.raw = val; break; - case 0x04400028: vstart.raw = val; break; - case 0x0440002C: vburst = val; break; - case 0x04400030: xscale.raw = val; break; - case 0x04400034: yscale.raw = val; break; - default: - Util::panic("Unimplemented VI[%08X] write (%08X)", paddr, val); + } + break; + case 0x04400008: + width = val & 0x7FF; + break; + case 0x0440000C: + intr = val & 0x3FF; + break; + case 0x04400010: + mem.mmio.mi.InterruptLower(MI::Interrupt::VI); + break; + case 0x04400014: + burst.raw = val; + break; + case 0x04400018: + vsync = val & 0x3FF; + numHalflines = vsync >> 1; + cyclesPerHalfline = GetCyclesPerFrame(isPal) / numHalflines; + break; + case 0x0440001C: + hsync = val & 0x3FF; + break; + case 0x04400020: + hsyncLeap.raw = val; + break; + case 0x04400024: + hstart.raw = val; + break; + case 0x04400028: + vstart.raw = val; + break; + case 0x0440002C: + vburst = val; + break; + case 0x04400030: + xscale.raw = val; + break; + case 0x04400034: + yscale.raw = val; + break; + default: + Util::panic("Unimplemented VI[%08X] write (%08X)", paddr, val); } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/mmio/VI.hpp b/src/backend/core/mmio/VI.hpp index c08170a1..02faa470 100644 --- a/src/backend/core/mmio/VI.hpp +++ b/src/backend/core/mmio/VI.hpp @@ -21,42 +21,37 @@ union VIHsyncLeap { unsigned:6; };*/ u32 raw; -} ; +}; union AxisScale { u32 raw; struct { - unsigned scaleDecimal:10; - unsigned scaleInteger:2; - unsigned subpixelOffsetDecimal:10; - unsigned subpixelOffsetInteger:2; - unsigned:4; + unsigned scaleDecimal : 10; + unsigned scaleInteger : 2; + unsigned subpixelOffsetDecimal : 10; + unsigned subpixelOffsetInteger : 2; + unsigned : 4; }; struct { - unsigned scale:12; - unsigned subpixelOffset:12; - unsigned:4; + unsigned scale : 12; + unsigned subpixelOffset : 12; + unsigned : 4; }; }; -enum VIFormat { - blank = 0, - reserved = 1, - f5553 = 2, - f8888 = 3 -}; +enum VIFormat { blank = 0, reserved = 1, f5553 = 2, f8888 = 3 }; union VIStatus { struct { - u8 type:2; - bool gamma_dither_enable:1; - bool gamma_enable:1; - bool divot_enable:1; - bool reserved_always_off:1; - bool serrate:1; - bool reserved_diagnostics_only:1; - unsigned antialias_mode:3; - unsigned:21; + u8 type : 2; + bool gamma_dither_enable : 1; + bool gamma_enable : 1; + bool divot_enable : 1; + bool reserved_always_off : 1; + bool serrate : 1; + bool reserved_diagnostics_only : 1; + unsigned antialias_mode : 3; + unsigned : 21; }; u32 raw; @@ -65,10 +60,10 @@ union VIStatus { union AxisStart { u32 raw; struct { - unsigned end:10; - unsigned:6; - unsigned start:10; - unsigned:6; + unsigned end : 10; + unsigned : 6; + unsigned start : 10; + unsigned : 6; }; }; @@ -76,7 +71,7 @@ struct Mem; struct Registers; struct VI { - VI(Mem&, Registers&); + VI(Mem &, Registers &); void Reset(); [[nodiscard]] u32 Read(u32) const; void Write(u32, u32); @@ -93,8 +88,9 @@ struct VI { int numHalflines{}; int numFields{}; int cyclesPerHalfline{}; + private: - Mem& mem; - Registers& regs; + Mem &mem; + Registers ®s; }; -} // backend +} // namespace n64 diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 5023da95..188d808f 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -1,11 +1,9 @@ -#include -#include #include +#include +#include namespace n64 { -Cop0::Cop0(Registers& regs) : regs(regs) { - Reset(); -} +Cop0::Cop0(Registers ®s) : regs(regs) { Reset(); } void Cop0::Reset() { cause.raw = 0xB000007C; @@ -40,155 +38,251 @@ void Cop0::Reset() { ParityError = {}, CacheError = {}, TagLo = {}, TagHi = {}; ErrorEPC = {}; r31 = {}; - memset(tlb, 0, sizeof(TLBEntry)*32); + memset(tlb, 0, sizeof(TLBEntry) * 32); tlbError = NONE; openbus = {}; } u32 Cop0::GetReg32(u8 addr) { - switch(addr) { - case COP0_REG_INDEX: return index.raw & INDEX_MASK; - case COP0_REG_RANDOM: return GetRandom(); - case COP0_REG_ENTRYLO0: return entryLo0.raw; - case COP0_REG_ENTRYLO1: return entryLo1.raw; - case COP0_REG_CONTEXT: return context.raw; - case COP0_REG_PAGEMASK: return pageMask.raw; - case COP0_REG_WIRED: return wired; - case COP0_REG_BADVADDR: return badVaddr; - case COP0_REG_COUNT: return GetCount(); - case COP0_REG_ENTRYHI: return entryHi.raw; - case COP0_REG_COMPARE: return compare; - case COP0_REG_STATUS: return status.raw; - case COP0_REG_CAUSE: return cause.raw; - case COP0_REG_EPC: return EPC; - case COP0_REG_PRID: return PRId; - case COP0_REG_CONFIG: return Config; - case COP0_REG_LLADDR: return LLAddr; - case COP0_REG_WATCHLO: return WatchLo; - case COP0_REG_WATCHHI: return WatchHi; - case COP0_REG_XCONTEXT: return xcontext.raw; - case COP0_REG_PARITY_ERR: return ParityError; - case COP0_REG_CACHE_ERR: return CacheError; - case COP0_REG_TAGLO: return TagLo; - case COP0_REG_TAGHI: return TagHi; - case COP0_REG_ERROREPC: return ErrorEPC; - case 7: case 21: case 22: - case 23: case 24: case 25: - case 31: return openbus; - default: - Util::panic("Unsupported word read from COP0 register {}", addr); + switch (addr) { + case COP0_REG_INDEX: + return index.raw & INDEX_MASK; + case COP0_REG_RANDOM: + return GetRandom(); + case COP0_REG_ENTRYLO0: + return entryLo0.raw; + case COP0_REG_ENTRYLO1: + return entryLo1.raw; + case COP0_REG_CONTEXT: + return context.raw; + case COP0_REG_PAGEMASK: + return pageMask.raw; + case COP0_REG_WIRED: + return wired; + case COP0_REG_BADVADDR: + return badVaddr; + case COP0_REG_COUNT: + return GetCount(); + case COP0_REG_ENTRYHI: + return entryHi.raw; + case COP0_REG_COMPARE: + return compare; + case COP0_REG_STATUS: + return status.raw; + case COP0_REG_CAUSE: + return cause.raw; + case COP0_REG_EPC: + return EPC; + case COP0_REG_PRID: + return PRId; + case COP0_REG_CONFIG: + return Config; + case COP0_REG_LLADDR: + return LLAddr; + case COP0_REG_WATCHLO: + return WatchLo; + case COP0_REG_WATCHHI: + return WatchHi; + case COP0_REG_XCONTEXT: + return xcontext.raw; + case COP0_REG_PARITY_ERR: + return ParityError; + case COP0_REG_CACHE_ERR: + return CacheError; + case COP0_REG_TAGLO: + return TagLo; + case COP0_REG_TAGHI: + return TagHi; + case COP0_REG_ERROREPC: + return ErrorEPC; + case 7: + case 21: + case 22: + case 23: + case 24: + case 25: + case 31: + return openbus; + default: + Util::panic("Unsupported word read from COP0 register {}", addr); } } u64 Cop0::GetReg64(u8 addr) const { - switch(addr) { - case COP0_REG_ENTRYLO0: return entryLo0.raw; - case COP0_REG_ENTRYLO1: return entryLo1.raw; - case COP0_REG_CONTEXT: return context.raw; - case COP0_REG_BADVADDR: return badVaddr; - case COP0_REG_ENTRYHI: return entryHi.raw; - case COP0_REG_STATUS: return status.raw; - case COP0_REG_EPC: return EPC; - case COP0_REG_PRID: return PRId; - case COP0_REG_LLADDR: return LLAddr; - case COP0_REG_XCONTEXT: return xcontext.raw & 0xFFFFFFFFFFFFFFF0; - case COP0_REG_ERROREPC: return ErrorEPC; - case 7: case 21: case 22: - case 23: case 24: case 25: - case 31: return openbus; - default: - Util::panic("Unsupported dword read from COP0 register {}", addr); + switch (addr) { + case COP0_REG_ENTRYLO0: + return entryLo0.raw; + case COP0_REG_ENTRYLO1: + return entryLo1.raw; + case COP0_REG_CONTEXT: + return context.raw; + case COP0_REG_BADVADDR: + return badVaddr; + case COP0_REG_ENTRYHI: + return entryHi.raw; + case COP0_REG_STATUS: + return status.raw; + case COP0_REG_EPC: + return EPC; + case COP0_REG_PRID: + return PRId; + case COP0_REG_LLADDR: + return LLAddr; + case COP0_REG_XCONTEXT: + return xcontext.raw & 0xFFFFFFFFFFFFFFF0; + case COP0_REG_ERROREPC: + return ErrorEPC; + case 7: + case 21: + case 22: + case 23: + case 24: + case 25: + case 31: + return openbus; + default: + Util::panic("Unsupported dword read from COP0 register {}", addr); } } void Cop0::SetReg32(u8 addr, u32 value) { openbus = value & 0xFFFFFFFF; - switch(addr) { - case COP0_REG_INDEX: index.raw = value & INDEX_MASK; break; - case COP0_REG_RANDOM: break; - case COP0_REG_ENTRYLO0: - entryLo0.raw = value & ENTRY_LO_MASK; - break; - case COP0_REG_ENTRYLO1: - entryLo1.raw = value & ENTRY_LO_MASK; - break; - case COP0_REG_CONTEXT: - context.raw = (s64(s32(value)) & 0xFFFFFFFFFF800000) | (context.raw & 0x7FFFFF); - break; - case COP0_REG_PAGEMASK: pageMask.raw = value & PAGEMASK_MASK; break; - case COP0_REG_WIRED: wired = value & 63; break; - case COP0_REG_BADVADDR: break; - case COP0_REG_COUNT: count = (u64)value << 1; break; - case COP0_REG_ENTRYHI: - entryHi.raw = s64(s32(value)) & ENTRY_HI_MASK; - break; - case COP0_REG_COMPARE: - compare = value; - cause.ip7 = false; - break; - case COP0_REG_STATUS: - status.raw &= ~STATUS_MASK; - status.raw |= (value & STATUS_MASK); - Update(); - break; - case COP0_REG_CAUSE: { + switch (addr) { + case COP0_REG_INDEX: + index.raw = value & INDEX_MASK; + break; + case COP0_REG_RANDOM: + break; + case COP0_REG_ENTRYLO0: + entryLo0.raw = value & ENTRY_LO_MASK; + break; + case COP0_REG_ENTRYLO1: + entryLo1.raw = value & ENTRY_LO_MASK; + break; + case COP0_REG_CONTEXT: + context.raw = (s64(s32(value)) & 0xFFFFFFFFFF800000) | (context.raw & 0x7FFFFF); + break; + case COP0_REG_PAGEMASK: + pageMask.raw = value & PAGEMASK_MASK; + break; + case COP0_REG_WIRED: + wired = value & 63; + break; + case COP0_REG_BADVADDR: + break; + case COP0_REG_COUNT: + count = (u64)value << 1; + break; + case COP0_REG_ENTRYHI: + entryHi.raw = s64(s32(value)) & ENTRY_HI_MASK; + break; + case COP0_REG_COMPARE: + compare = value; + cause.ip7 = false; + break; + case COP0_REG_STATUS: + status.raw &= ~STATUS_MASK; + status.raw |= (value & STATUS_MASK); + Update(); + break; + case COP0_REG_CAUSE: + { Cop0Cause tmp{}; tmp.raw = value; cause.ip0 = tmp.ip0; cause.ip1 = tmp.ip1; - } break; - case COP0_REG_EPC: - EPC = s64(s32(value)); - break; - case COP0_REG_PRID: break; - case COP0_REG_CONFIG: { - Config &= ~CONFIG_MASK; - Config |= (value & CONFIG_MASK); - } break; - case COP0_REG_LLADDR: LLAddr = value; break; - case COP0_REG_WATCHLO: WatchLo = value; break; - case COP0_REG_WATCHHI: WatchHi = value; break; - case COP0_REG_XCONTEXT: - xcontext.raw = (s64(s32(value)) & 0xFFFFFFFE00000000) | (xcontext.raw & 0x1FFFFFFFF); - break; - case COP0_REG_PARITY_ERR: ParityError = value & 0xff; break; - case COP0_REG_CACHE_ERR: break; - case COP0_REG_TAGLO: TagLo = value; break; - case COP0_REG_TAGHI: TagHi = value; break; - case COP0_REG_ERROREPC: ErrorEPC = s64(s32(value)); break; - case 7: case 21: case 22: - case 23: case 24: case 25: - case 31: break; - default: - Util::panic("Unsupported word write from COP0 register {}", addr); + } + break; + case COP0_REG_EPC: + EPC = s64(s32(value)); + break; + case COP0_REG_PRID: + break; + case COP0_REG_CONFIG: + Config &= ~CONFIG_MASK; + Config |= (value & CONFIG_MASK); + break; + case COP0_REG_LLADDR: + LLAddr = value; + break; + case COP0_REG_WATCHLO: + WatchLo = value; + break; + case COP0_REG_WATCHHI: + WatchHi = value; + break; + case COP0_REG_XCONTEXT: + xcontext.raw = (s64(s32(value)) & 0xFFFFFFFE00000000) | (xcontext.raw & 0x1FFFFFFFF); + break; + case COP0_REG_PARITY_ERR: + ParityError = value & 0xff; + break; + case COP0_REG_CACHE_ERR: + break; + case COP0_REG_TAGLO: + TagLo = value; + break; + case COP0_REG_TAGHI: + TagHi = value; + break; + case COP0_REG_ERROREPC: + ErrorEPC = s64(s32(value)); + break; + case 7: + case 21: + case 22: + case 23: + case 24: + case 25: + case 31: + break; + default: + Util::panic("Unsupported word write from COP0 register {}", addr); } } void Cop0::SetReg64(u8 addr, u64 value) { openbus = value; - switch(addr) { - case COP0_REG_ENTRYLO0: entryLo0.raw = value & ENTRY_LO_MASK; break; - case COP0_REG_ENTRYLO1: entryLo1.raw = value & ENTRY_LO_MASK; break; - case COP0_REG_CONTEXT: - context.raw = (value & 0xFFFFFFFFFF800000) | (context.raw & 0x7FFFFF); - break; - case COP0_REG_XCONTEXT: - xcontext.raw = (value & 0xFFFFFFFE00000000) | (xcontext.raw & 0x1FFFFFFFF); - break; - case COP0_REG_ENTRYHI: entryHi.raw = value & ENTRY_HI_MASK; break; - case COP0_REG_STATUS: status.raw = value; break; - case COP0_REG_CAUSE: { + switch (addr) { + case COP0_REG_ENTRYLO0: + entryLo0.raw = value & ENTRY_LO_MASK; + break; + case COP0_REG_ENTRYLO1: + entryLo1.raw = value & ENTRY_LO_MASK; + break; + case COP0_REG_CONTEXT: + context.raw = (value & 0xFFFFFFFFFF800000) | (context.raw & 0x7FFFFF); + break; + case COP0_REG_XCONTEXT: + xcontext.raw = (value & 0xFFFFFFFE00000000) | (xcontext.raw & 0x1FFFFFFFF); + break; + case COP0_REG_ENTRYHI: + entryHi.raw = value & ENTRY_HI_MASK; + break; + case COP0_REG_STATUS: + status.raw = value; + break; + case COP0_REG_CAUSE: + { Cop0Cause tmp{}; tmp.raw = value; cause.ip0 = tmp.ip0; cause.ip1 = tmp.ip1; - } break; - case COP0_REG_BADVADDR: break; - case COP0_REG_EPC: EPC = (s64)value; break; - case COP0_REG_LLADDR: LLAddr = value; break; - case COP0_REG_ERROREPC: ErrorEPC = (s64)value; break; - default: - Util::panic("Unsupported dword write to COP0 register {}", addr); + } + break; + case COP0_REG_BADVADDR: + break; + case COP0_REG_EPC: + EPC = (s64)value; + break; + case COP0_REG_LLADDR: + LLAddr = value; + break; + case COP0_REG_ERROREPC: + ErrorEPC = (s64)value; + break; + default: + Util::panic("Unsupported dword write to COP0 register {}", addr); } } @@ -199,10 +293,10 @@ static FORCE_INLINE u64 getVPN(u64 addr, u64 pageMask) { return vpn & ~mask; } -TLBEntry* Cop0::TLBTryMatch(u64 vaddr, int* match) { - for(int i = 0; i < 32; i++) { +TLBEntry *Cop0::TLBTryMatch(u64 vaddr, int *match) { + for (int i = 0; i < 32; i++) { TLBEntry *entry = ®s.cop0.tlb[i]; - if(entry->initialized) { + if (entry->initialized) { u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw); u64 vaddr_vpn = getVPN(vaddr, entry->pageMask.raw); @@ -221,9 +315,9 @@ 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); - if(!entry) { +bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match) { + TLBEntry *entry = TLBTryMatch(vaddr, match); + if (!entry) { regs.cop0.tlbError = MISS; return false; } @@ -232,25 +326,25 @@ bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match u32 odd = vaddr & (mask + 1); u32 pfn; - if(!odd) { - if(!entry->entryLo0.v) { + if (!odd) { + if (!entry->entryLo0.v) { regs.cop0.tlbError = INVALID; return false; } - if(access_type == STORE && !entry->entryLo0.d) { + if (access_type == STORE && !entry->entryLo0.d) { regs.cop0.tlbError = MODIFICATION; return false; } pfn = entry->entryLo0.pfn; } else { - if(!entry->entryLo1.v) { + if (!entry->entryLo1.v) { regs.cop0.tlbError = INVALID; return false; } - if(access_type == STORE && !entry->entryLo1.d) { + if (access_type == STORE && !entry->entryLo1.d) { regs.cop0.tlbError = MODIFICATION; return false; } @@ -263,21 +357,25 @@ bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match return true; } -FORCE_INLINE bool Is64BitAddressing(Cop0& cp0, u64 addr) { +FORCE_INLINE bool Is64BitAddressing(Cop0 &cp0, u64 addr) { u8 region = (addr >> 62) & 3; - switch(region) { - case 0b00: return cp0.status.ux; - case 0b01: return cp0.status.sx; - case 0b11: return cp0.status.kx; - default: return false; + switch (region) { + case 0b00: + return cp0.status.ux; + case 0b01: + return cp0.status.sx; + case 0b11: + return cp0.status.kx; + default: + return false; } } void Cop0::FireException(ExceptionCode code, int cop, s64 pc) { bool old_exl = regs.cop0.status.exl; - if(!regs.cop0.status.exl) { - if((regs.cop0.cause.branchDelay = regs.prevDelaySlot)) { + if (!regs.cop0.status.exl) { + if ((regs.cop0.cause.branchDelay = regs.prevDelaySlot)) { pc -= 4; } @@ -288,29 +386,38 @@ void Cop0::FireException(ExceptionCode code, int cop, s64 pc) { regs.cop0.cause.copError = cop; regs.cop0.cause.exceptionCode = static_cast(code); - if(regs.cop0.status.bev) { + if (regs.cop0.status.bev) { Util::panic("BEV bit set!"); } else { - switch(code) { - case ExceptionCode::Interrupt: case ExceptionCode::TLBModification: - case ExceptionCode::AddressErrorLoad: case ExceptionCode::AddressErrorStore: - case ExceptionCode::InstructionBusError: case ExceptionCode::DataBusError: - case ExceptionCode::Syscall: case ExceptionCode::Breakpoint: - case ExceptionCode::ReservedInstruction: case ExceptionCode::CoprocessorUnusable: - case ExceptionCode::Overflow: case ExceptionCode::Trap: - case ExceptionCode::FloatingPointError: case ExceptionCode::Watch: + switch (code) { + case ExceptionCode::Interrupt: + case ExceptionCode::TLBModification: + case ExceptionCode::AddressErrorLoad: + case ExceptionCode::AddressErrorStore: + case ExceptionCode::InstructionBusError: + case ExceptionCode::DataBusError: + case ExceptionCode::Syscall: + case ExceptionCode::Breakpoint: + case ExceptionCode::ReservedInstruction: + case ExceptionCode::CoprocessorUnusable: + case ExceptionCode::Overflow: + case ExceptionCode::Trap: + case ExceptionCode::FloatingPointError: + case ExceptionCode::Watch: + regs.SetPC32(s32(0x80000180)); + break; + case ExceptionCode::TLBLoad: + case ExceptionCode::TLBStore: + if (old_exl || regs.cop0.tlbError == INVALID) { regs.SetPC32(s32(0x80000180)); - break; - case ExceptionCode::TLBLoad: case ExceptionCode::TLBStore: - if(old_exl || regs.cop0.tlbError == INVALID) { - regs.SetPC32(s32(0x80000180)); - } else if(Is64BitAddressing(regs.cop0, regs.cop0.badVaddr)) { - regs.SetPC32(s32(0x80000080)); - } else { - regs.SetPC32(s32(0x80000000)); - } - break; - default: Util::panic("Unhandled exception! {}", static_cast(code)); + } else if (Is64BitAddressing(regs.cop0, regs.cop0.badVaddr)) { + regs.SetPC32(s32(0x80000080)); + } else { + regs.SetPC32(s32(0x80000000)); + } + break; + default: + Util::panic("Unhandled exception! {}", static_cast(code)); } } @@ -329,63 +436,82 @@ void Cop0::HandleTLBException(u64 vaddr) { } ExceptionCode Cop0::GetTLBExceptionCode(TLBError error, TLBAccessType accessType) { - switch(error) { - case NONE: Util::panic("Getting TLB exception with error NONE"); - case INVALID: case MISS: - return accessType == LOAD ? - ExceptionCode::TLBLoad : ExceptionCode::TLBStore; - case MODIFICATION: - return ExceptionCode::TLBModification; - case DISALLOWED_ADDRESS: - return accessType == LOAD ? - ExceptionCode::AddressErrorLoad : ExceptionCode::AddressErrorStore; - default: - Util::panic("Getting TLB exception for unknown error code! ({})", static_cast(error)); + switch (error) { + case NONE: + Util::panic("Getting TLB exception with error NONE"); + case INVALID: + case MISS: + return accessType == LOAD ? ExceptionCode::TLBLoad : ExceptionCode::TLBStore; + case MODIFICATION: + return ExceptionCode::TLBModification; + case DISALLOWED_ADDRESS: + return accessType == LOAD ? ExceptionCode::AddressErrorLoad : ExceptionCode::AddressErrorStore; + default: + Util::panic("Getting TLB exception for unknown error code! ({})", static_cast(error)); } } -template -void Cop0::decode(T& cpu, u32 instr) { - if constexpr (std::is_same_v) { +template +void Cop0::decode(T &cpu, u32 instr) { + if constexpr (std::is_same_v) { decodeInterp(instr); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { decodeJIT(cpu, instr); } else { Util::panic("What the fuck did you just give me?!!"); } } -template void Cop0::decode(Interpreter&, u32); -template void Cop0::decode(JIT&, u32); +template void Cop0::decode(Interpreter &, u32); +template void Cop0::decode(JIT &, u32); -void Cop0::decodeJIT(JIT& cpu, u32 instr) { - -} +void Cop0::decodeJIT(JIT &cpu, u32 instr) {} void Cop0::decodeInterp(u32 instr) { u8 mask_cop = (instr >> 21) & 0x1F; u8 mask_cop2 = instr & 0x3F; - switch(mask_cop) { - case 0x00: mfc0(instr); break; - case 0x01: dmfc0(instr); break; - case 0x04: mtc0(instr); break; - case 0x05: dmtc0(instr); break; - case 0x10 ... 0x1F: - switch(mask_cop2) { - case 0x01: tlbr(); break; - case 0x02: tlbw(index.i); break; - case 0x06: tlbw(GetRandom()); break; - case 0x08: tlbp(); break; - case 0x18: eret(); break; - default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC); - } + switch (mask_cop) { + case 0x00: + mfc0(instr); + break; + case 0x01: + dmfc0(instr); + break; + case 0x04: + mtc0(instr); + break; + case 0x05: + dmtc0(instr); + break; + case 0x10 ... 0x1F: + switch (mask_cop2) { + case 0x01: + tlbr(); break; - default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); + case 0x02: + tlbw(index.i); + break; + case 0x06: + tlbw(GetRandom()); + break; + case 0x08: + tlbp(); + break; + case 0x18: + eret(); + break; + default: + Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, + regs.oldPC); + } + break; + default: + Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); } } -bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32& paddr) { - if(regs.cop0.is64BitAddressing) [[unlikely]] { +bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr) { + if (regs.cop0.is64BitAddressing) [[unlikely]] { if (regs.cop0.kernelMode) [[likely]] { return MapVAddr64(accessType, vaddr, paddr); } else if (regs.cop0.userMode) { @@ -408,46 +534,50 @@ bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32& paddr) { } } -bool Cop0::UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr) { +bool Cop0::UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) { switch (vaddr) { - case VREGION_KUSEG: - return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); - default: - regs.cop0.tlbError = DISALLOWED_ADDRESS; - return false; + case VREGION_KUSEG: + return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); + default: + regs.cop0.tlbError = DISALLOWED_ADDRESS; + return false; } } -bool Cop0::MapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr) { - switch((u32(vaddr) >> 29) & 7) { - case 0 ... 3: case 7: - return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); - case 4 ... 5: - paddr = vaddr & 0x1FFFFFFF; - return true; - case 6: Util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr); - default: - Util::panic("Should never end up in default case in map_vaddr! ({:08X})", vaddr); +bool Cop0::MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) { + switch ((u32(vaddr) >> 29) & 7) { + case 0 ... 3: + case 7: + return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); + case 4 ... 5: + paddr = vaddr & 0x1FFFFFFF; + return true; + case 6: + Util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr); + default: + Util::panic("Should never end up in default case in map_vaddr! ({:08X})", vaddr); } return false; } -bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) { +bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) { switch (vaddr) { - case VREGION_XKUSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); - default: - regs.cop0.tlbError = DISALLOWED_ADDRESS; - return false; + case VREGION_XKUSEG: + return ProbeTLB(accessType, vaddr, paddr, nullptr); + default: + regs.cop0.tlbError = DISALLOWED_ADDRESS; + return false; } } -bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) { +bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) { switch (vaddr) { - case VREGION_XKUSEG: case VREGION_XKSSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); - case VREGION_XKPHYS: { + case VREGION_XKUSEG: + case VREGION_XKSSEG: + return ProbeTLB(accessType, vaddr, paddr, nullptr); + case VREGION_XKPHYS: + { if (!regs.cop0.kernelMode) { Util::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr); } @@ -466,33 +596,33 @@ bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) { paddr = vaddr & 0xFFFFFFFF; return true; } - case VREGION_XKSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); - case VREGION_CKSEG0: - // Identical to kseg0 in 32 bit mode. - // Unmapped translation. Subtract the base address of the space to get the physical address. - paddr = vaddr - START_VREGION_KSEG0; // Implies cutting off the high 32 bits - Util::trace("CKSEG0: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr); - return true; - case VREGION_CKSEG1: - // Identical to kseg1 in 32 bit mode. - // Unmapped translation. Subtract the base address of the space to get the physical address. - paddr = vaddr - START_VREGION_KSEG1; // Implies cutting off the high 32 bits - Util::trace("KSEG1: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr); - return true; - case VREGION_CKSSEG: - Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr); - case VREGION_CKSEG3: - return ProbeTLB(accessType, vaddr, paddr, nullptr); - case VREGION_XBAD1: - case VREGION_XBAD2: - case VREGION_XBAD3: - regs.cop0.tlbError = DISALLOWED_ADDRESS; - return false; - default: - Util::panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr); + case VREGION_XKSEG: + return ProbeTLB(accessType, vaddr, paddr, nullptr); + case VREGION_CKSEG0: + // Identical to kseg0 in 32 bit mode. + // Unmapped translation. Subtract the base address of the space to get the physical address. + paddr = vaddr - START_VREGION_KSEG0; // Implies cutting off the high 32 bits + Util::trace("CKSEG0: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr); + return true; + case VREGION_CKSEG1: + // Identical to kseg1 in 32 bit mode. + // Unmapped translation. Subtract the base address of the space to get the physical address. + paddr = vaddr - START_VREGION_KSEG1; // Implies cutting off the high 32 bits + Util::trace("KSEG1: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr); + return true; + case VREGION_CKSSEG: + Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr); + case VREGION_CKSEG3: + return ProbeTLB(accessType, vaddr, paddr, nullptr); + case VREGION_XBAD1: + case VREGION_XBAD2: + case VREGION_XBAD3: + regs.cop0.tlbError = DISALLOWED_ADDRESS; + return false; + default: + Util::panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr); } return false; } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 1807126c..c01d556a 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -44,60 +44,60 @@ struct Mem; union Cop0Cause { u32 raw; struct { - unsigned: 8; - unsigned interruptPending: 8; - unsigned: 16; + unsigned : 8; + unsigned interruptPending : 8; + unsigned : 16; } __attribute__((__packed__)); struct { - unsigned: 2; - unsigned exceptionCode: 5; - unsigned: 1; - unsigned ip0: 1; - unsigned ip1: 1; - unsigned ip2: 1; - unsigned ip3: 1; - unsigned ip4: 1; - unsigned ip5: 1; - unsigned ip6: 1; - unsigned ip7: 1; - unsigned: 12; - unsigned copError: 2; - unsigned: 1; - unsigned branchDelay: 1; + unsigned : 2; + unsigned exceptionCode : 5; + unsigned : 1; + unsigned ip0 : 1; + unsigned ip1 : 1; + unsigned ip2 : 1; + unsigned ip3 : 1; + unsigned ip4 : 1; + unsigned ip5 : 1; + unsigned ip6 : 1; + unsigned ip7 : 1; + unsigned : 12; + unsigned copError : 2; + unsigned : 1; + unsigned branchDelay : 1; } __attribute__((__packed__)); }; union Cop0Status { struct { - unsigned ie: 1; - unsigned exl: 1; - unsigned erl: 1; - unsigned ksu: 2; - unsigned ux: 1; - unsigned sx: 1; - unsigned kx: 1; - unsigned im: 8; - unsigned ds: 9; - unsigned re: 1; - unsigned fr: 1; - unsigned rp: 1; - unsigned cu0: 1; - unsigned cu1: 1; - unsigned cu2: 1; - unsigned cu3: 1; + unsigned ie : 1; + unsigned exl : 1; + unsigned erl : 1; + unsigned ksu : 2; + unsigned ux : 1; + unsigned sx : 1; + unsigned kx : 1; + unsigned im : 8; + unsigned ds : 9; + unsigned re : 1; + unsigned fr : 1; + unsigned rp : 1; + unsigned cu0 : 1; + unsigned cu1 : 1; + unsigned cu2 : 1; + unsigned cu3 : 1; } __attribute__((__packed__)); struct { - unsigned: 16; - unsigned de: 1; - unsigned ce: 1; - unsigned ch: 1; - unsigned: 1; - unsigned sr: 1; - unsigned ts: 1; - unsigned bev: 1; - unsigned: 1; - unsigned its: 1; - unsigned: 7; + unsigned : 16; + unsigned de : 1; + unsigned ce : 1; + unsigned ch : 1; + unsigned : 1; + unsigned sr : 1; + unsigned ts : 1; + unsigned bev : 1; + unsigned : 1; + unsigned its : 1; + unsigned : 7; } __attribute__((__packed__)); u32 raw; } __attribute__((__packed__)); @@ -105,41 +105,41 @@ union Cop0Status { union EntryLo { u32 raw; struct { - unsigned g:1; - unsigned v:1; - unsigned d:1; - unsigned c:3; - unsigned pfn:20; - unsigned:6; + unsigned g : 1; + unsigned v : 1; + unsigned d : 1; + unsigned c : 3; + unsigned pfn : 20; + unsigned : 6; }; }; union EntryHi { u64 raw; struct { - u64 asid:8; - u64:5; - u64 vpn2:27; - u64 fill:22; - u64 r:2; + u64 asid : 8; + u64 : 5; + u64 vpn2 : 27; + u64 fill : 22; + u64 r : 2; } __attribute__((__packed__)); }; union PageMask { u32 raw; struct { - unsigned: 13; - unsigned mask: 12; - unsigned: 7; + unsigned : 13; + unsigned mask : 12; + unsigned : 7; }; }; union Index { u32 raw; struct { - unsigned i:6; - unsigned:25; - unsigned p:1; + unsigned i : 6; + unsigned : 25; + unsigned p : 1; }; }; @@ -148,12 +148,12 @@ struct TLBEntry { union { u32 raw; struct { - unsigned:1; - unsigned v:1; - unsigned d:1; - unsigned c:3; - unsigned pfn:20; - unsigned:6; + unsigned : 1; + unsigned v : 1; + unsigned d : 1; + unsigned c : 3; + unsigned pfn : 20; + unsigned : 6; }; } entryLo0, entryLo1; EntryHi entryHi; @@ -162,13 +162,7 @@ struct TLBEntry { bool global; }; -enum TLBError : u8 { - NONE, - MISS, - INVALID, - MODIFICATION, - DISALLOWED_ADDRESS -}; +enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS }; enum class ExceptionCode : u8 { Interrupt = 0, @@ -192,24 +186,24 @@ enum class ExceptionCode : u8 { union Cop0Context { u64 raw; struct { - u64: 4; - u64 badvpn2: 19; - u64 ptebase: 41; + u64 : 4; + u64 badvpn2 : 19; + u64 ptebase : 41; }; }; union Cop0XContext { u64 raw; struct { - u64: 4; - u64 badvpn2: 27; - u64 r: 2; - u64 ptebase: 31; + u64 : 4; + u64 badvpn2 : 27; + u64 r : 2; + u64 ptebase : 31; } __attribute__((__packed__)); }; struct Cop0 { - Cop0(Registers&); + Cop0(Registers &); u32 GetReg32(u8); [[nodiscard]] u64 GetReg64(u8) const; @@ -245,12 +239,12 @@ struct Cop0 { TLBError tlbError = NONE; s64 openbus{}; template - void decode(T&, u32); + void decode(T &, u32); FORCE_INLINE u32 GetRandom() { u32 val = rand(); auto wired_ = GetWired(); u32 lower, upper; - if(wired_ > 31) { + if (wired_ > 31) { lower = 0; upper = 64; } else { @@ -265,37 +259,33 @@ struct Cop0 { FORCE_INLINE void Update() { bool exception = status.exl || status.erl; - kernelMode = exception || status.ksu == 0; + kernelMode = exception || status.ksu == 0; supervisorMode = !exception && status.ksu == 1; - userMode = !exception && status.ksu == 2; - is64BitAddressing = - (kernelMode && status.kx) - || (supervisorMode && status.sx) - || (userMode && status.ux); + userMode = !exception && status.ksu == 2; + is64BitAddressing = (kernelMode && status.kx) || (supervisorMode && status.sx) || (userMode && status.ux); } - enum TLBAccessType { - LOAD, STORE - }; + enum TLBAccessType { LOAD, STORE }; - bool ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match); + bool ProbeTLB(TLBAccessType access_type, u64 vaddr, u32 &paddr, int *match); void FireException(ExceptionCode code, int cop, s64 pc); - 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 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); - TLBEntry* TLBTryMatch(u64 vaddr, int* match); + TLBEntry *TLBTryMatch(u64 vaddr, int *match); void HandleTLBException(u64 vaddr); ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType access_type); + private: - Registers& regs; + Registers ®s; [[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; } [[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); } void decodeInterp(u32); - void decodeJIT(JIT&, u32); + void decodeJIT(JIT &, u32); void mtc0(u32); void dmtc0(u32); void mfc0(u32); @@ -306,4 +296,4 @@ private: void tlbw(int); void tlbp(); }; -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/registers/Cop1.cpp b/src/backend/core/registers/Cop1.cpp index 89ffc166..1285ac1b 100644 --- a/src/backend/core/registers/Cop1.cpp +++ b/src/backend/core/registers/Cop1.cpp @@ -1,12 +1,10 @@ +#include #include #include -#include #include namespace n64 { -Cop1::Cop1(Registers& regs) : regs(regs) { - Reset(); -} +Cop1::Cop1(Registers ®s) : regs(regs) { Reset(); } void Cop1::Reset() { fcr0 = 0xa00; @@ -15,136 +13,322 @@ void Cop1::Reset() { } template -void Cop1::decode(T& cpu, u32 instr) { - if constexpr (std::is_same_v) { +void Cop1::decode(T &cpu, u32 instr) { + if constexpr (std::is_same_v) { decodeInterp(cpu, instr); } else { Util::panic("What the fuck did you just give me?!"); } } -template void Cop1::decode(Interpreter&, u32); -template void Cop1::decode(JIT&, u32); +template void Cop1::decode(Interpreter &, u32); +template void Cop1::decode(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; - switch(mask_sub) { - // 000r_rccc - case 0x00: mfc1(instr); break; - case 0x01: dmfc1(instr); break; - case 0x02: cfc1(instr); break; - case 0x03: unimplemented(); break; - case 0x04: mtc1(instr); break; - case 0x05: dmtc1(instr); break; - case 0x06: ctc1(instr); break; - case 0x07: unimplemented(); break; + switch (mask_sub) { + // 000r_rccc + case 0x00: + mfc1(instr); + break; + case 0x01: + dmfc1(instr); + break; + case 0x02: + cfc1(instr); + break; + case 0x03: + unimplemented(); + break; + case 0x04: + mtc1(instr); + break; + case 0x05: + dmtc1(instr); + break; + case 0x06: + ctc1(instr); + break; + case 0x07: + unimplemented(); + break; + case 0x08: + switch (mask_branch) { + case 0: + if (!CheckFPUUsable()) + return; + cpu.b(instr, !fcr31.compare); + break; + case 1: + if (!CheckFPUUsable()) + return; + cpu.b(instr, fcr31.compare); + break; + case 2: + if (!CheckFPUUsable()) + return; + cpu.bl(instr, !fcr31.compare); + break; + case 3: + if (!CheckFPUUsable()) + return; + cpu.bl(instr, fcr31.compare); + break; + default: + Util::panic("Undefined BC COP1 {:02X}", mask_branch); + } + break; + case 0x10: // s + switch (mask_fun) { + case 0x00: + adds(instr); + break; + case 0x01: + subs(instr); + break; + case 0x02: + muls(instr); + break; + case 0x03: + divs(instr); + break; + case 0x04: + sqrts(instr); + break; + case 0x05: + abss(instr); + break; + case 0x06: + movs(instr); + break; + case 0x07: + negs(instr); + break; case 0x08: - switch(mask_branch) { - case 0: if(!CheckFPUUsable()) return; cpu.b(instr, !fcr31.compare); break; - case 1: if(!CheckFPUUsable()) return; cpu.b(instr, fcr31.compare); break; - case 2: if(!CheckFPUUsable()) return; cpu.bl(instr, !fcr31.compare); break; - case 3: if(!CheckFPUUsable()) return; cpu.bl(instr, fcr31.compare); break; - default: Util::panic("Undefined BC COP1 {:02X}", mask_branch); - } + roundls(instr); break; - case 0x10: // s - switch(mask_fun) { - case 0x00: adds(instr); break; - case 0x01: subs(instr); break; - case 0x02: muls(instr); break; - case 0x03: divs(instr); break; - case 0x04: sqrts(instr); break; - case 0x05: abss(instr); break; - case 0x06: movs(instr); break; - case 0x07: negs(instr); break; - case 0x08: roundls(instr); break; - case 0x09: truncls(instr); break; - case 0x0A: ceills(instr); break; - case 0x0B: floorls(instr); break; - case 0x0C: roundws(instr); break; - case 0x0D: truncws(instr); break; - case 0x0E: ceilws(instr); break; - case 0x0F: floorws(instr); break; - case 0x21: cvtds(instr); break; - case 0x24: cvtws(instr); break; - case 0x25: cvtls(instr); break; - case 0x30: cf(instr); break; - case 0x31: cun(instr); break; - case 0x32: ceq(instr); break; - case 0x33: cueq(instr); break; - case 0x34: colt(instr); break; - case 0x35: cult(instr); break; - case 0x36: cole(instr); break; - case 0x37: cule(instr); break; - case 0x38: csf(instr); break; - case 0x39: cngle(instr); break; - case 0x3A: cseq(instr); break; - case 0x3B: cngl(instr); break; - case 0x3C: clt(instr); break; - case 0x3D: cnge(instr); break; - case 0x3E: cle(instr); break; - case 0x3F: cngt(instr); break; - default: unimplemented(); - } + case 0x09: + truncls(instr); break; - case 0x11: // d - switch(mask_fun) { - case 0x00: addd(instr); break; - case 0x01: subd(instr); break; - case 0x02: muld(instr); break; - case 0x03: divd(instr); break; - case 0x04: sqrtd(instr); break; - case 0x05: absd(instr); break; - case 0x06: movd(instr); break; - case 0x07: negd(instr); break; - case 0x08: roundld(instr); break; - case 0x09: truncld(instr); break; - case 0x0A: ceilld(instr); break; - case 0x0B: floorld(instr); break; - case 0x0C: roundwd(instr); break; - case 0x0D: truncwd(instr); break; - case 0x0E: ceilwd(instr); break; - case 0x0F: floorwd(instr); break; - case 0x20: cvtsd(instr); break; - case 0x24: cvtwd(instr); break; - case 0x25: cvtld(instr); break; - case 0x30: cf(instr); break; - case 0x31: cun(instr); break; - case 0x32: ceq(instr); break; - case 0x33: cueq(instr); break; - case 0x34: colt(instr); break; - case 0x35: cult(instr); break; - case 0x36: cole(instr); break; - case 0x37: cule(instr); break; - case 0x38: csf(instr); break; - case 0x39: cngle(instr); break; - case 0x3A: cseq(instr); break; - case 0x3B: cngl(instr); break; - case 0x3C: clt(instr); break; - case 0x3D: cnge(instr); break; - case 0x3E: cle(instr); break; - case 0x3F: cngt(instr); break; - default: unimplemented(); - } + case 0x0A: + ceills(instr); break; - case 0x14: // w - switch(mask_fun) { - case 0x20: cvtsw(instr); break; - case 0x21: cvtdw(instr); break; - default: unimplemented(); - } + case 0x0B: + floorls(instr); break; - case 0x15: // l - switch(mask_fun) { - case 0x20: cvtsl(instr); break; - case 0x21: cvtdl(instr); break; - default: unimplemented(); - } + case 0x0C: + roundws(instr); break; - default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7); + case 0x0D: + truncws(instr); + break; + case 0x0E: + ceilws(instr); + break; + case 0x0F: + floorws(instr); + break; + case 0x21: + cvtds(instr); + break; + case 0x24: + cvtws(instr); + break; + case 0x25: + cvtls(instr); + break; + case 0x30: + cf(instr); + break; + case 0x31: + cun(instr); + break; + case 0x32: + ceq(instr); + break; + case 0x33: + cueq(instr); + break; + case 0x34: + colt(instr); + break; + case 0x35: + cult(instr); + break; + case 0x36: + cole(instr); + break; + case 0x37: + cule(instr); + break; + case 0x38: + csf(instr); + break; + case 0x39: + cngle(instr); + break; + case 0x3A: + cseq(instr); + break; + case 0x3B: + cngl(instr); + break; + case 0x3C: + clt(instr); + break; + case 0x3D: + cnge(instr); + break; + case 0x3E: + cle(instr); + break; + case 0x3F: + cngt(instr); + break; + default: + unimplemented(); + } + break; + case 0x11: // d + switch (mask_fun) { + case 0x00: + addd(instr); + break; + case 0x01: + subd(instr); + break; + case 0x02: + muld(instr); + break; + case 0x03: + divd(instr); + break; + case 0x04: + sqrtd(instr); + break; + case 0x05: + absd(instr); + break; + case 0x06: + movd(instr); + break; + case 0x07: + negd(instr); + break; + case 0x08: + roundld(instr); + break; + case 0x09: + truncld(instr); + break; + case 0x0A: + ceilld(instr); + break; + case 0x0B: + floorld(instr); + break; + case 0x0C: + roundwd(instr); + break; + case 0x0D: + truncwd(instr); + break; + case 0x0E: + ceilwd(instr); + break; + case 0x0F: + floorwd(instr); + break; + case 0x20: + cvtsd(instr); + break; + case 0x24: + cvtwd(instr); + break; + case 0x25: + cvtld(instr); + break; + case 0x30: + cf(instr); + break; + case 0x31: + cun(instr); + break; + case 0x32: + ceq(instr); + break; + case 0x33: + cueq(instr); + break; + case 0x34: + colt(instr); + break; + case 0x35: + cult(instr); + break; + case 0x36: + cole(instr); + break; + case 0x37: + cule(instr); + break; + case 0x38: + csf(instr); + break; + case 0x39: + cngle(instr); + break; + case 0x3A: + cseq(instr); + break; + case 0x3B: + cngl(instr); + break; + case 0x3C: + clt(instr); + break; + case 0x3D: + cnge(instr); + break; + case 0x3E: + cle(instr); + break; + case 0x3F: + cngt(instr); + break; + default: + unimplemented(); + } + break; + case 0x14: // w + switch (mask_fun) { + case 0x20: + cvtsw(instr); + break; + case 0x21: + cvtdw(instr); + break; + default: + unimplemented(); + } + break; + case 0x15: // l + switch (mask_fun) { + case 0x20: + cvtsl(instr); + break; + case 0x21: + cvtdl(instr); + break; + default: + unimplemented(); + } + break; + default: + Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7); } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index f5ef8c6e..0dcb7f5d 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -8,33 +8,33 @@ struct Cop1; union FCR31 { FCR31() = default; struct { - unsigned rounding_mode:2; + unsigned rounding_mode : 2; struct { - unsigned inexact_operation:1; - unsigned underflow:1; - unsigned overflow:1; - unsigned division_by_zero:1; - unsigned invalid_operation:1; + unsigned inexact_operation : 1; + unsigned underflow : 1; + unsigned overflow : 1; + unsigned division_by_zero : 1; + unsigned invalid_operation : 1; } flag; struct { - unsigned inexact_operation:1; - unsigned underflow:1; - unsigned overflow:1; - unsigned division_by_zero:1; - unsigned invalid_operation:1; + unsigned inexact_operation : 1; + unsigned underflow : 1; + unsigned overflow : 1; + unsigned division_by_zero : 1; + unsigned invalid_operation : 1; } enable; struct { - unsigned inexact_operation:1; - unsigned underflow:1; - unsigned overflow:1; - unsigned division_by_zero:1; - unsigned invalid_operation:1; - unsigned unimplemented_operation:1; + unsigned inexact_operation : 1; + unsigned underflow : 1; + unsigned overflow : 1; + unsigned division_by_zero : 1; + unsigned invalid_operation : 1; + unsigned unimplemented_operation : 1; } cause; - unsigned:5; - unsigned compare:1; - unsigned fs:1; - unsigned:7; + unsigned : 5; + unsigned compare : 1; + unsigned fs : 1; + unsigned : 7; } __attribute__((__packed__)); [[nodiscard]] u32 read() const { @@ -85,12 +85,7 @@ union FCR31 { } }; -enum CompConds { - F, UN, EQ, UEQ, - OLT, ULT, OLE, ULE, - SF, NGLE, SEQ, NGL, - LT, NGE, LE, NGT -}; +enum CompConds { F, UN, EQ, UEQ, OLT, ULT, OLE, ULE, SF, NGLE, SEQ, NGL, LT, NGE, LE, NGT }; union FloatingPointReg { struct { @@ -121,28 +116,28 @@ struct JIT; struct Registers; struct Cop1 { - explicit Cop1(Registers&); + explicit Cop1(Registers &); u32 fcr0{}; FCR31 fcr31{}; FloatingPointReg fgr[32]{}; void Reset(); template // either JIT or Interpreter - void decode(T&, u32); + void decode(T &, u32); friend struct Interpreter; template bool CheckFPUUsable(); template - bool CheckResult(T&); + bool CheckResult(T &); template - bool CheckArg(T&); + bool CheckArg(T &); template - bool CheckArgs(T&, T&); + bool CheckArgs(T &, T &); template bool isqnan(T); - template + template bool XORDERED(T fs, T ft); template @@ -158,15 +153,16 @@ struct Cop1 { bool SetCauseDivisionByZero(); bool SetCauseOverflow(); bool SetCauseInvalid(); + private: template - auto FGR_T(Cop0Status&, u32) -> T&; + auto FGR_T(Cop0Status &, u32) -> T &; template - auto FGR_S(Cop0Status&, u32) -> T&; + auto FGR_S(Cop0Status &, u32) -> T &; template - auto FGR_D(Cop0Status&, u32) -> T&; - void decodeInterp(Interpreter&, u32); - void decodeJIT(JIT&, u32); + auto FGR_D(Cop0Status &, u32) -> T &; + void decodeInterp(Interpreter &, u32); + void decodeJIT(JIT &, u32); void absd(u32 instr); void abss(u32 instr); void adds(u32 instr); @@ -240,31 +236,23 @@ private: void negd(u32 instr); void sqrts(u32 instr); void sqrtd(u32 instr); - template - void lwc1(T&, Mem&, u32); - template - void swc1(T&, Mem&, u32); - template - void ldc1(T&, Mem&, u32); - template - void sdc1(T&, Mem&, u32); + template + void lwc1(T &, Mem &, u32); + template + void swc1(T &, Mem &, u32); + template + void ldc1(T &, Mem &, u32); + template + void sdc1(T &, Mem &, u32); - void lwc1Interp(Mem&, u32); - void swc1Interp(Mem&, u32); - void ldc1Interp(Mem&, u32); - void sdc1Interp(Mem&, u32); - void lwc1JIT(JIT&, Mem&, u32) { - Util::panic("[JIT]: lwc1 not implemented!"); - } - void swc1JIT(JIT&, Mem&, u32) { - Util::panic("[JIT]: swc1 not implemented!"); - } - void ldc1JIT(JIT&, Mem&, u32) { - Util::panic("[JIT]: ldc1 not implemented!"); - } - void sdc1JIT(JIT&, Mem&, u32) { - Util::panic("[JIT]: sdc1 not implemented!"); - } + void lwc1Interp(Mem &, u32); + void swc1Interp(Mem &, u32); + void ldc1Interp(Mem &, u32); + void sdc1Interp(Mem &, u32); + void lwc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: lwc1 not implemented!"); } + void swc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: swc1 not implemented!"); } + void ldc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: ldc1 not implemented!"); } + void sdc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: sdc1 not implemented!"); } void mfc1(u32 instr); void dmfc1(u32 instr); void mtc1(u32 instr); @@ -274,6 +262,6 @@ private: void truncls(u32 instr); void truncld(u32 instr); - Registers& regs; + Registers ®s; }; -} +} // namespace n64 diff --git a/src/backend/core/registers/cop/cop0instructions.cpp b/src/backend/core/registers/cop/cop0instructions.cpp index ee0fb578..04eb9013 100644 --- a/src/backend/core/registers/cop/cop0instructions.cpp +++ b/src/backend/core/registers/cop/cop0instructions.cpp @@ -3,24 +3,16 @@ #include namespace n64 { -void Cop0::mtc0(u32 instr) { - SetReg32(RD(instr), regs.Read(RT(instr))); -} +void Cop0::mtc0(u32 instr) { SetReg32(RD(instr), regs.Read(RT(instr))); } -void Cop0::dmtc0(u32 instr) { - SetReg64(RD(instr), regs.Read(RT(instr))); -} +void Cop0::dmtc0(u32 instr) { SetReg64(RD(instr), regs.Read(RT(instr))); } -void Cop0::mfc0(u32 instr) { - regs.Write(RT(instr), s32(GetReg32(RD(instr)))); -} +void Cop0::mfc0(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(u32 instr) const { regs.Write(RT(instr), s64(GetReg64(RD(instr)))); } void Cop0::eret() { - if(status.erl) { + if (status.erl) { regs.SetPC64(ErrorEPC); status.erl = false; } else { @@ -54,11 +46,11 @@ void Cop0::tlbw(int index_) { u32 top = page_mask.mask & 0xAAA; page_mask.mask = top | (top >> 1); - if(index_ >= 32) { + if (index_ >= 32) { Util::panic("TLBWI with TLB index {}", index_); } - tlb[index_].entryHi.raw = entryHi.raw; + tlb[index_].entryHi.raw = entryHi.raw; tlb[index_].entryHi.vpn2 &= ~page_mask.mask; tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; @@ -71,8 +63,8 @@ void Cop0::tlbw(int index_) { void Cop0::tlbp() { int match = -1; - TLBEntry* entry = TLBTryMatch(entryHi.raw, &match); - if(entry && match >= 0) { + TLBEntry *entry = TLBTryMatch(entryHi.raw, &match); + if (entry && match >= 0) { index.raw = match; } else { index.raw = 0; @@ -80,4 +72,4 @@ void Cop0::tlbp() { } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index bbe584d3..5c23c824 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -1,12 +1,13 @@ +#include +#include +#include #include #include -#include -#include -#include #include namespace n64 { -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s32& { +template <> +auto Cop1::FGR_T(Cop0Status &status, u32 index) -> s32 & { if (status.fr) { return fgr[index].int32; } else if (index & 1) { @@ -16,15 +17,18 @@ template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s32& { } } -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR_T(status, index); +template <> +auto Cop1::FGR_T(Cop0Status &status, u32 index) -> u32 & { + return (u32 &)FGR_T(status, index); } -template<> auto Cop1::FGR_T(Cop0Status&, u32 index) -> float& { +template <> +auto Cop1::FGR_T(Cop0Status &, u32 index) -> float & { return fgr[index].float32; } -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s64& { +template <> +auto Cop1::FGR_T(Cop0Status &status, u32 index) -> s64 & { if (status.fr) { return fgr[index].int64; } else { @@ -32,15 +36,18 @@ template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s64& { } } -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR_T(status, index); +template <> +auto Cop1::FGR_T(Cop0Status &status, u32 index) -> u64 & { + return (u64 &)FGR_T(status, index); } -template<> auto Cop1::FGR_T(Cop0Status&, u32 index) -> double& { +template <> +auto Cop1::FGR_T(Cop0Status &, u32 index) -> double & { return fgr[index].float64; } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s32& { +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> s32 & { if (status.fr) { return fgr[index].int32; } else { @@ -48,11 +55,13 @@ template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s32& { } } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR_S(status, index); +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> u32 & { + return (u32 &)FGR_S(status, index); } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> float& { +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> float & { if (status.fr) { return fgr[index].float32; } else { @@ -60,15 +69,18 @@ template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> float& { } } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s64& { +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> s64 & { return FGR_T(status, index); } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR_S(status, index); +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> u64 & { + return (u64 &)FGR_S(status, index); } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> double& { +template <> +auto Cop1::FGR_S(Cop0Status &status, u32 index) -> double & { if (status.fr) { return fgr[index].float64; } else { @@ -76,29 +88,35 @@ template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> double& { } } -template<> auto Cop1::FGR_D(Cop0Status&, u32 index) -> s32& { +template <> +auto Cop1::FGR_D(Cop0Status &, u32 index) -> s32 & { fgr[index].int32h = 0; return fgr[index].int32; } -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR_D(status, index); +template <> +auto Cop1::FGR_D(Cop0Status &status, u32 index) -> u32 & { + return (u32 &)FGR_D(status, index); } -template<> auto Cop1::FGR_D(Cop0Status&, u32 index) -> float& { +template <> +auto Cop1::FGR_D(Cop0Status &, u32 index) -> float & { fgr[index].float32h = 0; return fgr[index].float32; } -template<> auto Cop1::FGR_D(Cop0Status&, u32 index) -> s64& { +template <> +auto Cop1::FGR_D(Cop0Status &, u32 index) -> s64 & { return fgr[index].int64; } -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR_D(status, index); +template <> +auto Cop1::FGR_D(Cop0Status &status, u32 index) -> u64 & { + return (u64 &)FGR_D(status, index); } -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> double& { +template <> +auto Cop1::FGR_D(Cop0Status &status, u32 index) -> double & { return FGR_T(status, index); } @@ -114,23 +132,28 @@ u64 doubleIntegerCast(double f) { return v; } -template<> bool Cop1::isqnan(float f) { +template <> +bool Cop1::isqnan(float f) { return (floatIntegerCast(f) >> 22) & 1; } -template<> bool Cop1::isqnan(double f) { +template <> +bool Cop1::isqnan(double f) { return (doubleIntegerCast(f) >> 51) & 1; } -template <> bool Cop1::CheckCVTArg(float& f) { +template <> +bool Cop1::CheckCVTArg(float &f) { switch (fpclassify(f)) { - case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: + case FP_SUBNORMAL: + case FP_INFINITE: + case FP_NAN: SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if(f >= 0x1p+31f || f < -0x1p+31f) { + if (f >= 0x1p+31f || f < -0x1p+31f) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; @@ -139,15 +162,18 @@ template <> bool Cop1::CheckCVTArg(float& f) { return true; } -template <> bool Cop1::CheckCVTArg(double& f) { +template <> +bool Cop1::CheckCVTArg(double &f) { switch (fpclassify(f)) { - case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: + case FP_SUBNORMAL: + case FP_INFINITE: + case FP_NAN: SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if((f >= 0x1p+31 || f < -0x1p+31)) { + if ((f >= 0x1p+31 || f < -0x1p+31)) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; @@ -156,15 +182,18 @@ template <> bool Cop1::CheckCVTArg(double& f) { return true; } -template <> bool Cop1::CheckCVTArg(float& f) { +template <> +bool Cop1::CheckCVTArg(float &f) { switch (fpclassify(f)) { - case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: + case FP_SUBNORMAL: + case FP_INFINITE: + case FP_NAN: SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if((f >= 0x1p+53f || f <= -0x1p+53f)) { + if ((f >= 0x1p+53f || f <= -0x1p+53f)) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; @@ -173,15 +202,18 @@ template <> bool Cop1::CheckCVTArg(float& f) { return true; } -template <> bool Cop1::CheckCVTArg(double& f) { +template <> +bool Cop1::CheckCVTArg(double &f) { switch (fpclassify(f)) { - case FP_SUBNORMAL: case FP_INFINITE: case FP_NAN: + case FP_SUBNORMAL: + case FP_INFINITE: + case FP_NAN: SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if((f >= 0x1p+53 || f <= -0x1p+53)) { + if ((f >= 0x1p+53 || f <= -0x1p+53)) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; @@ -191,39 +223,39 @@ template <> bool Cop1::CheckCVTArg(double& f) { } template -bool Cop1::CheckArg(T& f) { - switch(fpclassify(f)) { - case FP_SUBNORMAL: - SetCauseUnimplemented(); +bool Cop1::CheckArg(T &f) { + switch (fpclassify(f)) { + case FP_SUBNORMAL: + SetCauseUnimplemented(); + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + return false; + case FP_NAN: + if (isqnan(f) ? SetCauseInvalid() : (SetCauseUnimplemented(), true)) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; - case FP_NAN: - if(isqnan(f) ? SetCauseInvalid() : (SetCauseUnimplemented(), true)) { - regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - return false; - } - return true; + } + return true; } return true; } template -bool Cop1::CheckArgs(T& f1, T& f2) { +bool Cop1::CheckArgs(T &f1, T &f2) { auto class1 = std::fpclassify(f1), class2 = std::fpclassify(f2); - if((class1 == FP_NAN && !isqnan(f1)) || (class2 == FP_NAN && !isqnan(f2))) { + if ((class1 == FP_NAN && !isqnan(f1)) || (class2 == FP_NAN && !isqnan(f2))) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if(class1 == FP_SUBNORMAL || class2 == FP_SUBNORMAL) { + if (class1 == FP_SUBNORMAL || class2 == FP_SUBNORMAL) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if((class1 == FP_NAN && isqnan(f1)) || (class2 == FP_NAN && isqnan(f2))) { - if(SetCauseInvalid()) { + if ((class1 == FP_NAN && isqnan(f1)) || (class2 == FP_NAN && isqnan(f2))) { + if (SetCauseInvalid()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } @@ -235,12 +267,13 @@ bool Cop1::CheckArgs(T& f1, T& f2) { template bool Cop1::CheckFPUUsable() { if constexpr (preserveCause) { - if(!regs.cop0.status.cu1) { + if (!regs.cop0.status.cu1) { regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); return false; } } else { - if(!CheckFPUUsable()) return false; + if (!CheckFPUUsable()) + return false; fcr31.cause = {}; } @@ -253,28 +286,33 @@ template bool Cop1::CheckFPUUsable(); template FORCE_INLINE T FlushResult(T f, u32 round) { switch (round) { - case FE_TONEAREST: case FE_TOWARDZERO: return std::copysign(T(), f); - case FE_UPWARD: return std::signbit(f) ? -T() : std::numeric_limits::min(); - case FE_DOWNWARD: return std::signbit(f) ? -std::numeric_limits::min() : T(); + case FE_TONEAREST: + case FE_TOWARDZERO: + return std::copysign(T(), f); + case FE_UPWARD: + return std::signbit(f) ? -T() : std::numeric_limits::min(); + case FE_DOWNWARD: + return std::signbit(f) ? -std::numeric_limits::min() : T(); default: __builtin_unreachable(); } } template <> -bool Cop1::CheckResult(float& f) { +bool Cop1::CheckResult(float &f) { switch (std::fpclassify(f)) { - case FP_SUBNORMAL: - if(!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { - SetCauseUnimplemented(); - regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - return false; - } - SetCauseUnderflow(); - SetCauseInexact(); - f = FlushResult(f, std::fegetround()); - return true; - case FP_NAN: { + case FP_SUBNORMAL: + if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { + SetCauseUnimplemented(); + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + return false; + } + SetCauseUnderflow(); + SetCauseInexact(); + f = FlushResult(f, std::fegetround()); + return true; + case FP_NAN: + { uint32_t v = 0x7fbf'ffff; memcpy(&f, &v, 4); return true; @@ -284,19 +322,20 @@ bool Cop1::CheckResult(float& f) { } template <> -bool Cop1::CheckResult(double& f) { +bool Cop1::CheckResult(double &f) { switch (std::fpclassify(f)) { - case FP_SUBNORMAL: - if(!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { - SetCauseUnimplemented(); - regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - return false; - } - SetCauseUnderflow(); - SetCauseInexact(); - f = FlushResult(f, fegetround()); - return true; - case FP_NAN: { + case FP_SUBNORMAL: + if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { + SetCauseUnimplemented(); + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + return false; + } + SetCauseUnderflow(); + SetCauseInexact(); + f = FlushResult(f, fegetround()); + return true; + case FP_NAN: + { uint64_t v = 0x7ff7'ffff'ffff'ffff; memcpy(&f, &v, 8); return true; @@ -309,18 +348,19 @@ template bool Cop1::TestExceptions() { u32 exc = std::fetestexcept(FE_ALL_EXCEPT); - if(!exc) return false; + if (!exc) + return false; if constexpr (cvt) { - if(exc & FE_INVALID) { + if (exc & FE_INVALID) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return true; } } - if(exc & FE_UNDERFLOW) { - if(!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { + if (exc & FE_UNDERFLOW) { + if (!fcr31.fs || fcr31.enable.underflow || fcr31.enable.inexact_operation) { SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return true; @@ -328,208 +368,269 @@ bool Cop1::TestExceptions() { } bool raise = false; - if(exc & FE_DIVBYZERO) raise |= SetCauseDivisionByZero(); - if(exc & FE_INEXACT) { + if (exc & FE_DIVBYZERO) + raise |= SetCauseDivisionByZero(); + if (exc & FE_INEXACT) { raise |= SetCauseInexact(); } - if(exc & FE_UNDERFLOW) raise |= SetCauseUnderflow(); - if(exc & FE_OVERFLOW) raise |= SetCauseOverflow(); - if(exc & FE_INVALID) raise |= SetCauseInvalid(); - if(raise) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (exc & FE_UNDERFLOW) + raise |= SetCauseUnderflow(); + if (exc & FE_OVERFLOW) + raise |= SetCauseOverflow(); + if (exc & FE_INVALID) + raise |= SetCauseInvalid(); + if (raise) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return raise; } template bool Cop1::TestExceptions(); template bool Cop1::TestExceptions(); -void Cop1::SetCauseUnimplemented() { - fcr31.cause.unimplemented_operation = true; -} +void Cop1::SetCauseUnimplemented() { fcr31.cause.unimplemented_operation = true; } bool Cop1::SetCauseUnderflow() { fcr31.cause.underflow = true; - if(fcr31.enable.underflow) return true; + if (fcr31.enable.underflow) + return true; fcr31.flag.underflow = true; return false; } bool Cop1::SetCauseInexact() { fcr31.cause.inexact_operation = true; - if(fcr31.enable.inexact_operation) return true; + if (fcr31.enable.inexact_operation) + return true; fcr31.flag.inexact_operation = true; return false; } bool Cop1::SetCauseDivisionByZero() { fcr31.cause.division_by_zero = true; - if(fcr31.enable.division_by_zero) return true; + if (fcr31.enable.division_by_zero) + return true; fcr31.flag.division_by_zero = true; return false; } bool Cop1::SetCauseOverflow() { fcr31.cause.overflow = true; - if(fcr31.enable.overflow) return true; + if (fcr31.enable.overflow) + return true; fcr31.flag.overflow = true; return false; } bool Cop1::SetCauseInvalid() { fcr31.cause.invalid_operation = true; - if(fcr31.enable.invalid_operation) return true; + if (fcr31.enable.invalid_operation) + return true; fcr31.flag.invalid_operation = true; return false; } -#define CHECK_FPE_IMPL(type, res, operation, convert) \ - feclearexcept(FE_ALL_EXCEPT); \ - volatile type v##res = [&]() -> type { return operation; }(); \ - if (TestExceptions()) return; \ +#define CHECK_FPE_IMPL(type, res, operation, convert) \ + feclearexcept(FE_ALL_EXCEPT); \ + volatile type v##res = [&]() -> type { return operation; }(); \ + if (TestExceptions()) \ + return; \ type res = v##res; -#define CHECK_FPE(type, res, operation) CHECK_FPE_IMPL(type, res, operation, false) +#define CHECK_FPE(type, res, operation) CHECK_FPE_IMPL(type, res, operation, false) #define CHECK_FPE_CONV(type, res, operation) CHECK_FPE_IMPL(type, res, operation, true) void Cop1::absd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; auto fd = std::abs(fs); - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::abss(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; auto fd = std::abs(fs); - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::adds(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(float, fd, fs + ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::addd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(double, fd, fs + ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::ceills(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundCeil(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::ceilld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundCeil(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::ceilws(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundCeil(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::ceilwd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundCeil(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cfc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; u8 fd = RD(instr); s32 val = 0; - switch(fd) { - case 0: val = fcr0; break; - case 31: - val = fcr31.read(); - break; - default: Util::panic("Undefined CFC1 with rd != 0 or 31"); + switch (fd) { + case 0: + val = fcr0; + break; + case 31: + val = fcr31.read(); + break; + default: + Util::panic("Undefined CFC1 with rd != 0 or 31"); } regs.Write(RT(instr), val); } void Cop1::ctc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; u8 fs = RD(instr); u32 val = regs.Read(RT(instr)); - switch(fs) { - case 0: break; - case 31: { + switch (fs) { + case 0: + break; + case 31: + { u32 prevRound = fcr31.rounding_mode; fcr31.write(val); if (prevRound != fcr31.rounding_mode) { switch (fcr31.rounding_mode) { - case 0: fesetround(FE_TONEAREST); break; - case 1: fesetround(FE_TOWARDZERO); break; - case 2: fesetround(FE_UPWARD); break; - case 3: fesetround(FE_DOWNWARD); break; + case 0: + fesetround(FE_TONEAREST); + break; + case 1: + fesetround(FE_TOWARDZERO); + break; + case 2: + fesetround(FE_UPWARD); + break; + case 3: + fesetround(FE_DOWNWARD); + break; } } - if(fcr31.cause.inexact_operation && fcr31.enable.inexact_operation) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - if(fcr31.cause.underflow && fcr31.enable.underflow) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - if(fcr31.cause.overflow && fcr31.enable.overflow) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - if(fcr31.cause.division_by_zero && fcr31.enable.division_by_zero) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - if(fcr31.cause.invalid_operation && fcr31.enable.invalid_operation) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - if(fcr31.cause.unimplemented_operation) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); - } break; - default: Util::panic("Undefined CTC1 with rd != 0 or 31"); + if (fcr31.cause.inexact_operation && fcr31.enable.inexact_operation) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (fcr31.cause.underflow && fcr31.enable.underflow) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (fcr31.cause.overflow && fcr31.enable.overflow) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (fcr31.cause.division_by_zero && fcr31.enable.division_by_zero) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (fcr31.cause.invalid_operation && fcr31.enable.invalid_operation) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + if (fcr31.cause.unimplemented_operation) + regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); + } + break; + default: + Util::panic("Undefined CTC1 with rd != 0 or 31"); } } void Cop1::cvtds(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(double, fd, fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtsd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(float, fd, (float)fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtsw(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); CHECK_FPE(float, fd, fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtsl(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { SetCauseUnimplemented(); @@ -537,44 +638,54 @@ void Cop1::cvtsl(u32 instr) { return; } CHECK_FPE(float, fd, fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtwd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundCurrent(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtws(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundCurrent(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtls(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundCurrent(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtdw(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); CHECK_FPE(double, fd, fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtdl(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { @@ -583,26 +694,29 @@ void Cop1::cvtdl(u32 instr) { return; } CHECK_FPE(double, fd, fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::cvtld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundCurrent(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } -template +template bool Cop1::XORDERED(T fs, T ft) { - if(std::isnan(fs) || std::isnan(ft)) { - if(std::isnan(fs) && (!quiet || isqnan(fs)) && SetCauseInvalid()) { + if (std::isnan(fs) || std::isnan(ft)) { + if (std::isnan(fs) && (!quiet || isqnan(fs)) && SetCauseInvalid()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } - if(std::isnan(ft) && (!quiet || isqnan(ft)) && SetCauseInvalid()) { + if (std::isnan(ft) && (!quiet || isqnan(ft)) && SetCauseInvalid()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return false; } @@ -618,145 +732,177 @@ bool Cop1::XORDERED(T fs, T ft) { template void Cop1::cf(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 0)(fs, ft)) return; + if (!UNORDERED(T, 0)(fs, ft)) + return; fcr31.compare = 0; } template void Cop1::cun(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 1)(fs, ft)) return; + if (!UNORDERED(T, 1)(fs, ft)) + return; fcr31.compare = 0; } template void Cop1::ceq(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 0)(fs, ft)) return; + if (!UNORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs == ft; } template void Cop1::cueq(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 1)(fs, ft)) return; + if (!UNORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs == ft; } template void Cop1::colt(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 0)(fs, ft)) return; + if (!UNORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs < ft; } template void Cop1::cult(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 1)(fs, ft)) return; + if (!UNORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs < ft; } template void Cop1::cole(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 0)(fs, ft)) return; + if (!UNORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs <= ft; } template void Cop1::cule(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!UNORDERED(T, 1)(fs, ft)) return; + if (!UNORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs <= ft; } template void Cop1::csf(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 0)(fs, ft)) return; + if (!ORDERED(T, 0)(fs, ft)) + return; fcr31.compare = 0; } template void Cop1::cngle(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 1)(fs, ft)) return; + if (!ORDERED(T, 1)(fs, ft)) + return; fcr31.compare = 0; } template void Cop1::cseq(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 0)(fs, ft)) return; + if (!ORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs == ft; } template void Cop1::cngl(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 1)(fs, ft)) return; + if (!ORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs == ft; } template void Cop1::clt(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 0)(fs, ft)) return; + if (!ORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs < ft; } template void Cop1::cnge(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 1)(fs, ft)) return; + if (!ORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs < ft; } template void Cop1::cle(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 0)(fs, ft)) return; + if (!ORDERED(T, 0)(fs, ft)) + return; fcr31.compare = fs <= ft; } template void Cop1::cngt(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; T fs = FGR_S(regs.cop0.status, FS(instr)); T ft = FGR_T(regs.cop0.status, FT(instr)); - if(!ORDERED(T, 1)(fs, ft)) return; + if (!ORDERED(T, 1)(fs, ft)) + return; fcr31.compare = fs <= ft; } @@ -794,116 +940,147 @@ template void Cop1::cle(u32 instr); template void Cop1::cngt(u32 instr); void Cop1::divs(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(float, fd, fs / ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::divd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(double, fd, fs / ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::muls(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; - CHECK_FPE(float, fd, fs * ft) - if(!CheckResult(fd)) return; + if (!CheckArgs(fs, ft)) + return; + CHECK_FPE(float, fd, fs *ft) + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::muld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; - CHECK_FPE(double, fd, fs * ft) - if(!CheckResult(fd)) return; + if (!CheckArgs(fs, ft)) + return; + CHECK_FPE(double, fd, fs *ft) + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::subs(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(float, fd, fs - ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::subd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); auto ft = FGR_T(regs.cop0.status, FT(instr)); - if(!CheckArgs(fs, ft)) return; + if (!CheckArgs(fs, ft)) + return; CHECK_FPE(double, fd, fs - ft) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } -void Cop1::movs(u32 instr) { - movd(instr); -} +void Cop1::movs(u32 instr) { movd(instr); } void Cop1::movd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; FGR_D(regs.cop0.status, FD(instr)) = FGR_S(regs.cop0.status, FS(instr)); } void Cop1::negs(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(float, fd, -fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::negd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(double, fd, -fs) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::sqrts(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(float, fd, sqrtf(fs)) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::sqrtd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckArg(fs)) return; + if (!CheckArg(fs)) + return; CHECK_FPE(double, fd, sqrt(fs)) - if(!CheckResult(fd)) return; + if (!CheckResult(fd)) + return; FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::roundls(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundNearest(fs)) - if(fd != fs && SetCauseInexact()) { + if (fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -911,11 +1088,13 @@ void Cop1::roundls(u32 instr) { } void Cop1::roundld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundNearest(fs)) - if(fd != fs && SetCauseInexact()) { + if (fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -923,11 +1102,13 @@ void Cop1::roundld(u32 instr) { } void Cop1::roundws(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundNearest(fs)) - if(fd != fs && SetCauseInexact()) { + if (fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -935,11 +1116,13 @@ void Cop1::roundws(u32 instr) { } void Cop1::roundwd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundNearest(fs)) - if(fd != fs && SetCauseInexact()) { + if (fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -947,43 +1130,53 @@ void Cop1::roundwd(u32 instr) { } void Cop1::floorls(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundFloor(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::floorld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundFloor(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::floorws(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundFloor(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::floorwd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundFloor(fs)) FGR_D(regs.cop0.status, FD(instr)) = fd; } void Cop1::truncws(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundTrunc(fs)) - if((float)fd != fs && SetCauseInexact()) { + if ((float)fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -991,11 +1184,13 @@ void Cop1::truncws(u32 instr) { } void Cop1::truncwd(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE_CONV(s32, fd, Util::roundTrunc(fs)) - if((double)fd != fs && SetCauseInexact()) { + if ((double)fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -1003,11 +1198,13 @@ void Cop1::truncwd(u32 instr) { } void Cop1::truncls(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundTrunc(fs)) - if((float)fd != fs && SetCauseInexact()) { + if ((float)fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } @@ -1015,82 +1212,88 @@ void Cop1::truncls(u32 instr) { } void Cop1::truncld(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; auto fs = FGR_S(regs.cop0.status, FS(instr)); - if(!CheckCVTArg(fs)) return; + if (!CheckCVTArg(fs)) + return; CHECK_FPE(s64, fd, Util::roundTrunc(fs)) - if((double)fd != fs && SetCauseInexact()) { + if ((double)fd != fs && SetCauseInexact()) { regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); return; } FGR_D(regs.cop0.status, FD(instr)) = fd; } -template +template void Cop1::lwc1(T &cpu, Mem &mem, u32 instr) { - if constexpr(std::is_same_v) { - if(!CheckFPUUsable()) return; + if constexpr (std::is_same_v) { + if (!CheckFPUUsable()) + return; lwc1Interp(mem, instr); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { lwc1JIT(cpu, mem, instr); } else { Util::panic("What the fuck did you just give me?!!"); } } -template void Cop1::lwc1(Interpreter&, Mem&, u32); -template void Cop1::lwc1(JIT&, Mem&, u32); +template void Cop1::lwc1(Interpreter &, Mem &, u32); +template void Cop1::lwc1(JIT &, Mem &, u32); -template +template void Cop1::swc1(T &cpu, Mem &mem, u32 instr) { - if constexpr(std::is_same_v) { - if(!CheckFPUUsable()) return; + if constexpr (std::is_same_v) { + if (!CheckFPUUsable()) + return; swc1Interp(mem, instr); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { swc1JIT(cpu, mem, instr); } else { Util::panic("What the fuck did you just give me?!!"); } } -template void Cop1::swc1(Interpreter&, Mem&, u32); -template void Cop1::swc1(JIT&, Mem&, u32); +template void Cop1::swc1(Interpreter &, Mem &, u32); +template void Cop1::swc1(JIT &, Mem &, u32); -template +template void Cop1::ldc1(T &cpu, Mem &mem, u32 instr) { - if constexpr(std::is_same_v) { - if(!CheckFPUUsable()) return; + if constexpr (std::is_same_v) { + if (!CheckFPUUsable()) + return; ldc1Interp(mem, instr); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { ldc1JIT(cpu, mem, instr); } else { Util::panic("What the fuck did you just give me?!!"); } } -template void Cop1::ldc1(Interpreter&, Mem&, u32); -template void Cop1::ldc1(JIT&, Mem&, u32); +template void Cop1::ldc1(Interpreter &, Mem &, u32); +template void Cop1::ldc1(JIT &, Mem &, u32); -template +template void Cop1::sdc1(T &cpu, Mem &mem, u32 instr) { - if constexpr(std::is_same_v) { - if(!CheckFPUUsable()) return; + if constexpr (std::is_same_v) { + if (!CheckFPUUsable()) + return; sdc1Interp(mem, instr); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { sdc1JIT(cpu, mem, instr); } else { Util::panic("What the fuck did you just give me?!!"); } } -template void Cop1::sdc1(Interpreter&, Mem&, u32); -template void Cop1::sdc1(JIT&, Mem&, u32); +template void Cop1::sdc1(Interpreter &, Mem &, u32); +template void Cop1::sdc1(JIT &, Mem &, u32); -void Cop1::lwc1Interp(Mem& mem, u32 instr) { +void Cop1::lwc1Interp(Mem &mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.Read(BASE(instr)); u32 physical; - if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { @@ -1099,11 +1302,11 @@ void Cop1::lwc1Interp(Mem& mem, u32 instr) { } } -void Cop1::swc1Interp(Mem& mem, u32 instr) { +void Cop1::swc1Interp(Mem &mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.Read(BASE(instr)); u32 physical; - if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { @@ -1112,16 +1315,17 @@ void Cop1::swc1Interp(Mem& mem, u32 instr) { } void Cop1::unimplemented() { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; SetCauseUnimplemented(); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC); } -void Cop1::ldc1Interp(Mem& mem, u32 instr) { +void Cop1::ldc1Interp(Mem &mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.Read(BASE(instr)); u32 physical; - if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { + if (!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC); } else { @@ -1130,11 +1334,11 @@ void Cop1::ldc1Interp(Mem& mem, u32 instr) { } } -void Cop1::sdc1Interp(Mem& mem, u32 instr) { +void Cop1::sdc1Interp(Mem &mem, u32 instr) { u64 addr = (s64)(s16)instr + regs.Read(BASE(instr)); u32 physical; - if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { + if (!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) { regs.cop0.HandleTLBException(addr); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC); } else { @@ -1143,22 +1347,26 @@ void Cop1::sdc1Interp(Mem& mem, u32 instr) { } void Cop1::mfc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; regs.Write(RT(instr), FGR_T(regs.cop0.status, FS(instr))); } void Cop1::dmfc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; regs.Write(RT(instr), FGR_S(regs.cop0.status, FS(instr))); } void Cop1::mtc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; FGR_T(regs.cop0.status, FS(instr)) = regs.Read(RT(instr)); } void Cop1::dmtc1(u32 instr) { - if(!CheckFPUUsable()) return; + if (!CheckFPUUsable()) + return; FGR_S(regs.cop0.status, FS(instr)) = regs.Read(RT(instr)); } -} +} // namespace n64 diff --git a/src/backend/core/rsp/decode.cpp b/src/backend/core/rsp/decode.cpp index 737da901..91c2b984 100644 --- a/src/backend/core/rsp/decode.cpp +++ b/src/backend/core/rsp/decode.cpp @@ -1,183 +1,376 @@ -#include -#include -#include #include +#include +#include +#include namespace n64 { -FORCE_INLINE void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) { +FORCE_INLINE void special(MI &mi, Registers ®s, RSP &rsp, u32 instr) { u8 mask = instr & 0x3f; - //Util::print("rsp special {:02X}", mask); - switch(mask) { - case 0x00: - if(instr != 0) { - rsp.sll(instr); - } - break; - case 0x02: rsp.srl(instr); break; - case 0x03: rsp.sra(instr); break; - case 0x04: rsp.sllv(instr); break; - case 0x06: rsp.srlv(instr); break; - case 0x07: rsp.srav(instr); break; - case 0x08: rsp.jr(instr); break; - case 0x09: rsp.jalr(instr); break; - case 0x0D: - rsp.spStatus.halt = true; - rsp.steps = 0; - rsp.spStatus.broke = true; - if(rsp.spStatus.interruptOnBreak) { - mi.InterruptRaise(MI::Interrupt::SP); - } - break; - case 0x20: case 0x21: - rsp.add(instr); - break; - case 0x22: case 0x23: - rsp.sub(instr); - break; - case 0x24: rsp.and_(instr); break; - case 0x25: rsp.or_(instr); break; - case 0x26: rsp.xor_(instr); break; - case 0x27: rsp.nor(instr); break; - case 0x2A: rsp.slt(instr); break; - case 0x2B: rsp.sltu(instr); break; - default: Util::panic("Unhandled RSP special instruction ({:06b})", mask); + // Util::print("rsp special {:02X}", mask); + switch (mask) { + case 0x00: + if (instr != 0) { + rsp.sll(instr); + } + break; + case 0x02: + rsp.srl(instr); + break; + case 0x03: + rsp.sra(instr); + break; + case 0x04: + rsp.sllv(instr); + break; + case 0x06: + rsp.srlv(instr); + break; + case 0x07: + rsp.srav(instr); + break; + case 0x08: + rsp.jr(instr); + break; + case 0x09: + rsp.jalr(instr); + break; + case 0x0D: + rsp.spStatus.halt = true; + rsp.steps = 0; + rsp.spStatus.broke = true; + if (rsp.spStatus.interruptOnBreak) { + mi.InterruptRaise(MI::Interrupt::SP); + } + break; + case 0x20: + case 0x21: + rsp.add(instr); + break; + case 0x22: + case 0x23: + rsp.sub(instr); + break; + case 0x24: + rsp.and_(instr); + break; + case 0x25: + rsp.or_(instr); + break; + case 0x26: + rsp.xor_(instr); + break; + case 0x27: + rsp.nor(instr); + break; + case 0x2A: + rsp.slt(instr); + break; + case 0x2B: + rsp.sltu(instr); + break; + default: + Util::panic("Unhandled RSP special instruction ({:06b})", mask); } } -FORCE_INLINE void regimm(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) { - case 0x00: rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); break; - case 0x01: rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); break; - case 0x10: rsp.blink(instr, (s32)rsp.gpr[RS(instr)] < 0); break; - case 0x11: rsp.blink(instr, (s32)rsp.gpr[RS(instr)] >= 0); break; - default: Util::panic("Unhandled RSP regimm instruction ({:05b})", mask); + // Util::print("rsp regimm {:02X}", mask); + switch (mask) { + case 0x00: + rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); + break; + case 0x01: + rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); + break; + case 0x10: + rsp.blink(instr, (s32)rsp.gpr[RS(instr)] < 0); + break; + case 0x11: + rsp.blink(instr, (s32)rsp.gpr[RS(instr)] >= 0); + break; + default: + Util::panic("Unhandled RSP regimm instruction ({:05b})", mask); } } -FORCE_INLINE void lwc2(RSP& rsp, u32 instr) { +FORCE_INLINE void lwc2(RSP &rsp, u32 instr) { u8 mask = (instr >> 11) & 0x1F; - //Util::print("lwc2 {:02X}", mask); - switch(mask) { - case 0x00: rsp.lbv(instr); break; - case 0x01: rsp.lsv(instr); break; - case 0x02: rsp.llv(instr); break; - case 0x03: rsp.ldv(instr); break; - case 0x04: rsp.lqv(instr); break; - case 0x05: rsp.lrv(instr); break; - case 0x06: rsp.lpv(instr); break; - case 0x07: rsp.luv(instr); break; - case 0x08: rsp.lhv(instr); break; - case 0x09: rsp.lfv(instr); break; - case 0x0A: break; - case 0x0B: rsp.ltv(instr); break; - default: Util::panic("Unhandled RSP LWC2 {:05b}", mask); + // Util::print("lwc2 {:02X}", mask); + switch (mask) { + case 0x00: + rsp.lbv(instr); + break; + case 0x01: + rsp.lsv(instr); + break; + case 0x02: + rsp.llv(instr); + break; + case 0x03: + rsp.ldv(instr); + break; + case 0x04: + rsp.lqv(instr); + break; + case 0x05: + rsp.lrv(instr); + break; + case 0x06: + rsp.lpv(instr); + break; + case 0x07: + rsp.luv(instr); + break; + case 0x08: + rsp.lhv(instr); + break; + case 0x09: + rsp.lfv(instr); + break; + case 0x0A: + break; + case 0x0B: + rsp.ltv(instr); + break; + default: + Util::panic("Unhandled RSP LWC2 {:05b}", mask); } } -FORCE_INLINE void swc2(RSP& rsp, u32 instr) { +FORCE_INLINE void swc2(RSP &rsp, u32 instr) { u8 mask = (instr >> 11) & 0x1F; - //Util::print("swc2 {:02X}", mask); - switch(mask) { - case 0x00: rsp.sbv(instr); break; - case 0x01: rsp.ssv(instr); break; - case 0x02: rsp.slv(instr); break; - case 0x03: rsp.sdv(instr); break; - case 0x04: rsp.sqv(instr); break; - case 0x05: rsp.srv(instr); break; - case 0x06: rsp.spv(instr); break; - case 0x07: rsp.suv(instr); break; - case 0x08: rsp.shv(instr); break; - case 0x09: rsp.sfv(instr); break; - case 0x0A: rsp.swv(instr); break; - case 0x0B: rsp.stv(instr); break; - default: Util::panic("Unhandled RSP SWC2 {:05b}", mask); + // Util::print("swc2 {:02X}", mask); + switch (mask) { + case 0x00: + rsp.sbv(instr); + break; + case 0x01: + rsp.ssv(instr); + break; + case 0x02: + rsp.slv(instr); + break; + case 0x03: + rsp.sdv(instr); + break; + case 0x04: + rsp.sqv(instr); + break; + case 0x05: + rsp.srv(instr); + break; + case 0x06: + rsp.spv(instr); + break; + case 0x07: + rsp.suv(instr); + break; + case 0x08: + rsp.shv(instr); + break; + case 0x09: + rsp.sfv(instr); + break; + case 0x0A: + rsp.swv(instr); + break; + case 0x0B: + rsp.stv(instr); + break; + default: + Util::panic("Unhandled RSP SWC2 {:05b}", mask); } } -FORCE_INLINE void cop2(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) { - case 0x00: - if((instr >> 25) & 1) { - rsp.vmulf(instr); - } else { - switch (mask_sub) { - case 0x00: rsp.mfc2(instr); break; - case 0x02: rsp.cfc2(instr); break; - case 0x04: rsp.mtc2(instr); break; - case 0x06: rsp.ctc2(instr); break; - default: Util::panic("Unhandled RSP COP2 sub ({:05b})", mask_sub); - } + // Util::print("Cop2 {:02X}", mask); + switch (mask) { + case 0x00: + if ((instr >> 25) & 1) { + rsp.vmulf(instr); + } else { + switch (mask_sub) { + case 0x00: + rsp.mfc2(instr); + break; + case 0x02: + rsp.cfc2(instr); + break; + case 0x04: + rsp.mtc2(instr); + break; + case 0x06: + rsp.ctc2(instr); + break; + default: + Util::panic("Unhandled RSP COP2 sub ({:05b})", mask_sub); } - break; - case 0x01: rsp.vmulu(instr); break; - case 0x02: rsp.vrndp(instr); break; - case 0x03: rsp.vmulq(instr); break; - case 0x04: rsp.vmudl(instr); break; - case 0x05: rsp.vmudm(instr); break; - case 0x06: rsp.vmudn(instr); break; - case 0x07: rsp.vmudh(instr); break; - case 0x08: rsp.vmacf(instr); break; - case 0x09: rsp.vmacu(instr); break; - case 0x0A: rsp.vrndn(instr); break; - case 0x0B: rsp.vmacq(instr); break; - case 0x0C: rsp.vmadl(instr); break; - case 0x0D: rsp.vmadm(instr); break; - case 0x0E: rsp.vmadn(instr); break; - case 0x0F: rsp.vmadh(instr); break; - case 0x10: rsp.vadd(instr); break; - case 0x11: rsp.vsub(instr); break; - case 0x12: rsp.vzero(instr); break; - case 0x13: rsp.vabs(instr); break; - case 0x14: rsp.vaddc(instr); break; - case 0x15: rsp.vsubc(instr); break; - case 0x16 ... 0x1C: case 0x1E: case 0x1F: case 0x2E: case 0x2F: - rsp.vzero(instr); - break; - case 0x1D: rsp.vsar(instr); break; - case 0x20: rsp.vlt(instr); break; - case 0x21: rsp.veq(instr); break; - case 0x22: rsp.vne(instr); break; - case 0x23: rsp.vge(instr); break; - case 0x24: rsp.vcl(instr); break; - case 0x25: rsp.vch(instr); break; - case 0x26: rsp.vcr(instr); break; - case 0x27: rsp.vmrg(instr); break; - case 0x28: rsp.vand(instr); break; - case 0x29: rsp.vnand(instr); break; - case 0x2A: rsp.vor(instr); break; - case 0x2B: rsp.vnor(instr); break; - case 0x2C: rsp.vxor(instr); break; - case 0x2D: rsp.vnxor(instr); break; - case 0x31: rsp.vrcpl(instr); break; - case 0x35: rsp.vrsql(instr); break; - case 0x32: case 0x36: - rsp.vrcph(instr); - break; - case 0x30: rsp.vrcp(instr); break; - case 0x33: rsp.vmov(instr); break; - case 0x34: rsp.vrsq(instr); break; - case 0x38 ... 0x3E: rsp.vzero(instr); break; - case 0x37: case 0x3F: break; - default: Util::panic("Unhandled RSP COP2 ({:06b})", mask); + } + break; + case 0x01: + rsp.vmulu(instr); + break; + case 0x02: + rsp.vrndp(instr); + break; + case 0x03: + rsp.vmulq(instr); + break; + case 0x04: + rsp.vmudl(instr); + break; + case 0x05: + rsp.vmudm(instr); + break; + case 0x06: + rsp.vmudn(instr); + break; + case 0x07: + rsp.vmudh(instr); + break; + case 0x08: + rsp.vmacf(instr); + break; + case 0x09: + rsp.vmacu(instr); + break; + case 0x0A: + rsp.vrndn(instr); + break; + case 0x0B: + rsp.vmacq(instr); + break; + case 0x0C: + rsp.vmadl(instr); + break; + case 0x0D: + rsp.vmadm(instr); + break; + case 0x0E: + rsp.vmadn(instr); + break; + case 0x0F: + rsp.vmadh(instr); + break; + case 0x10: + rsp.vadd(instr); + break; + case 0x11: + rsp.vsub(instr); + break; + case 0x12: + rsp.vzero(instr); + break; + case 0x13: + rsp.vabs(instr); + break; + case 0x14: + rsp.vaddc(instr); + break; + case 0x15: + rsp.vsubc(instr); + break; + case 0x16 ... 0x1C: + case 0x1E: + case 0x1F: + case 0x2E: + case 0x2F: + rsp.vzero(instr); + break; + case 0x1D: + rsp.vsar(instr); + break; + case 0x20: + rsp.vlt(instr); + break; + case 0x21: + rsp.veq(instr); + break; + case 0x22: + rsp.vne(instr); + break; + case 0x23: + rsp.vge(instr); + break; + case 0x24: + rsp.vcl(instr); + break; + case 0x25: + rsp.vch(instr); + break; + case 0x26: + rsp.vcr(instr); + break; + case 0x27: + rsp.vmrg(instr); + break; + case 0x28: + rsp.vand(instr); + break; + case 0x29: + rsp.vnand(instr); + break; + case 0x2A: + rsp.vor(instr); + break; + case 0x2B: + rsp.vnor(instr); + break; + case 0x2C: + rsp.vxor(instr); + break; + case 0x2D: + rsp.vnxor(instr); + break; + case 0x31: + rsp.vrcpl(instr); + break; + case 0x35: + rsp.vrsql(instr); + break; + case 0x32: + case 0x36: + rsp.vrcph(instr); + break; + case 0x30: + rsp.vrcp(instr); + break; + case 0x33: + rsp.vmov(instr); + break; + case 0x34: + rsp.vrsq(instr); + break; + case 0x38 ... 0x3E: + rsp.vzero(instr); + break; + case 0x37: + case 0x3F: + break; + default: + Util::panic("Unhandled RSP COP2 ({:06b})", mask); } } -FORCE_INLINE void cop0(Registers& regs, Mem& mem, u32 instr) { +FORCE_INLINE void cop0(Registers ®s, Mem &mem, u32 instr) { u8 mask = (instr >> 21) & 0x1F; - MMIO& mmio = mem.mmio; - RSP& rsp = mmio.rsp; - RDP& rdp = mmio.rdp; - //Util::print("Cop0 {:02X}", mask); - if((instr & 0x7FF) == 0) { + MMIO &mmio = mem.mmio; + RSP &rsp = mmio.rsp; + RDP &rdp = mmio.rdp; + // Util::print("Cop0 {:02X}", mask); + if ((instr & 0x7FF) == 0) { switch (mask) { - case 0x00: rsp.mfc0(rdp, instr); break; - case 0x04: rsp.mtc0(instr); break; - default: Util::panic("Unhandled RSP COP0 ({:05b})", mask); + case 0x00: + rsp.mfc0(rdp, instr); + break; + case 0x04: + rsp.mtc0(instr); + break; + default: + Util::panic("Unhandled RSP COP0 ({:05b})", mask); } } else { Util::panic("RSP COP0 unknown {:08X}", instr); @@ -186,42 +379,96 @@ FORCE_INLINE void cop0(Registers& regs, Mem& mem, u32 instr) { void RSP::Exec(u32 instr) { u8 mask = (instr >> 26) & 0x3F; - MMIO& mmio = mem.mmio; - MI& mi = mmio.mi; - //Util::print("RSP {:02X}", mask); - switch(mask) { - case 0x00: special(mi, regs, *this, instr); break; - case 0x01: regimm(*this, instr); break; - case 0x02: j(instr); break; - case 0x03: jal(instr); break; - case 0x04: b(instr, (s32)gpr[RT(instr)] == (s32)gpr[RS(instr)]); break; - case 0x05: b(instr, (s32)gpr[RT(instr)] != (s32)gpr[RS(instr)]); break; - case 0x06: b(instr, (s32)gpr[RS(instr)] <= 0); break; - case 0x07: b(instr, (s32)gpr[RS(instr)] > 0); break; - case 0x08: case 0x09: addi(instr); break; - case 0x0A: slti(instr); break; - case 0x0B: sltiu(instr); break; - case 0x0C: andi(instr); break; - case 0x0D: ori(instr); break; - case 0x0E: xori(instr); break; - case 0x0F: lui(instr); break; - case 0x10: cop0(regs, mem, instr); break; - case 0x12: cop2(*this, instr); break; - case 0x20: lb(instr); break; - case 0x21: lh(instr); break; - case 0x23: case 0x27: - lw(instr); - break; - case 0x24: lbu(instr); break; - case 0x25: lhu(instr); break; - case 0x28: sb(instr); break; - case 0x29: sh(instr); break; - case 0x2B: sw(instr); break; - case 0x32: lwc2(*this, instr); break; - case 0x3A: swc2(*this, instr); break; - default: - mem.DumpIMEM(); - Util::panic("Unhandled RSP instruction ({:06b}, {:04X})", mask, oldPC); + MMIO &mmio = mem.mmio; + MI &mi = mmio.mi; + // Util::print("RSP {:02X}", mask); + switch (mask) { + case 0x00: + special(mi, regs, *this, instr); + break; + case 0x01: + regimm(*this, instr); + break; + case 0x02: + j(instr); + break; + case 0x03: + jal(instr); + break; + case 0x04: + b(instr, (s32)gpr[RT(instr)] == (s32)gpr[RS(instr)]); + break; + case 0x05: + b(instr, (s32)gpr[RT(instr)] != (s32)gpr[RS(instr)]); + break; + case 0x06: + b(instr, (s32)gpr[RS(instr)] <= 0); + break; + case 0x07: + b(instr, (s32)gpr[RS(instr)] > 0); + break; + case 0x08: + case 0x09: + addi(instr); + break; + case 0x0A: + slti(instr); + break; + case 0x0B: + sltiu(instr); + break; + case 0x0C: + andi(instr); + break; + case 0x0D: + ori(instr); + break; + case 0x0E: + xori(instr); + break; + case 0x0F: + lui(instr); + break; + case 0x10: + cop0(regs, mem, instr); + break; + case 0x12: + cop2(*this, instr); + break; + case 0x20: + lb(instr); + break; + case 0x21: + lh(instr); + break; + case 0x23: + case 0x27: + lw(instr); + break; + case 0x24: + lbu(instr); + break; + case 0x25: + lhu(instr); + break; + case 0x28: + sb(instr); + break; + case 0x29: + sh(instr); + break; + case 0x2B: + sw(instr); + break; + case 0x32: + lwc2(*this, instr); + break; + case 0x3A: + swc2(*this, instr); + break; + default: + mem.DumpIMEM(); + Util::panic("Unhandled RSP instruction ({:06b}, {:04X})", mask, oldPC); } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/backend/core/rsp/instructions.cpp b/src/backend/core/rsp/instructions.cpp index f69623d7..4c4ce188 100644 --- a/src/backend/core/rsp/instructions.cpp +++ b/src/backend/core/rsp/instructions.cpp @@ -1,14 +1,14 @@ -#include -#include -#include #include #include +#include #include +#include #include +#include namespace n64 { -FORCE_INLINE bool AcquireSemaphore(RSP& rsp) { - if(rsp.semaphore) { +FORCE_INLINE bool AcquireSemaphore(RSP &rsp) { + if (rsp.semaphore) { return true; } else { rsp.semaphore = true; @@ -16,9 +16,7 @@ FORCE_INLINE bool AcquireSemaphore(RSP& rsp) { } } -FORCE_INLINE void ReleaseSemaphore(RSP& rsp) { - rsp.semaphore = false; -} +FORCE_INLINE void ReleaseSemaphore(RSP &rsp) { rsp.semaphore = false; } FORCE_INLINE int SignExt7bit(u8 val, int sa) { s8 sval = ((val << 1) & 0x80) | val; @@ -28,60 +26,89 @@ FORCE_INLINE int SignExt7bit(u8 val, int sa) { return val32 << sa; } -FORCE_INLINE auto GetCop0Reg(RSP& rsp, RDP& rdp, u8 index) -> u32{ - switch(index) { - case 0: return rsp.lastSuccessfulSPAddr.raw; - case 1: return rsp.lastSuccessfulDRAMAddr.raw; - case 2: - case 3: return rsp.spDMALen.raw; - case 4: return rsp.spStatus.raw; - case 5: return rsp.spStatus.dmaFull; - case 6: return rsp.spStatus.dmaBusy; - case 7: return AcquireSemaphore(rsp); - case 8: return rdp.dpc.start; - case 9: return rdp.dpc.end; - case 10: return rdp.dpc.current; - case 11: return rdp.dpc.status.raw; - case 12: return rdp.dpc.clock; - case 13: return rdp.dpc.status.cmdBusy; - case 14: return rdp.dpc.status.pipeBusy; - case 15: return rdp.dpc.status.tmemBusy; - default: Util::panic("Unhandled RSP COP0 register read at index {}", index); +FORCE_INLINE auto GetCop0Reg(RSP &rsp, RDP &rdp, u8 index) -> u32 { + switch (index) { + case 0: + return rsp.lastSuccessfulSPAddr.raw; + case 1: + return rsp.lastSuccessfulDRAMAddr.raw; + case 2: + case 3: + return rsp.spDMALen.raw; + case 4: + return rsp.spStatus.raw; + case 5: + return rsp.spStatus.dmaFull; + case 6: + return rsp.spStatus.dmaBusy; + case 7: + return AcquireSemaphore(rsp); + case 8: + return rdp.dpc.start; + case 9: + return rdp.dpc.end; + case 10: + return rdp.dpc.current; + case 11: + return rdp.dpc.status.raw; + case 12: + return rdp.dpc.clock; + case 13: + return rdp.dpc.status.cmdBusy; + case 14: + return rdp.dpc.status.pipeBusy; + case 15: + return rdp.dpc.status.tmemBusy; + default: + Util::panic("Unhandled RSP COP0 register read at index {}", index); } } -FORCE_INLINE void SetCop0Reg(Registers& regs, Mem& mem, u8 index, u32 val) { - MMIO& mmio = mem.mmio; - RSP& rsp = mmio.rsp; - RDP& rdp = mmio.rdp; - MI& mi = mmio.mi; - switch(index) { - case 0: rsp.spDMASPAddr.raw = val; break; - case 1: rsp.spDMADRAMAddr.raw = val; break; - case 2: - rsp.spDMALen.raw = val; - rsp.DMA(); - break; - case 3: - rsp.spDMALen.raw = val; - rsp.DMA(); - break; - case 4: rsp.WriteStatus(val); break; - case 7: - if(val == 0) { - ReleaseSemaphore(rsp); - } else { - Util::panic("Write with non-zero value to RSP_COP0_RESERVED ({})", val); - } - break; - case 8: rdp.WriteStart(val); break; - case 9: rdp.WriteEnd(val); break; - case 11: rdp.WriteStatus(val); break; - default: Util::panic("Unhandled RSP COP0 register write at index {}", index); +FORCE_INLINE void SetCop0Reg(Registers ®s, Mem &mem, u8 index, u32 val) { + MMIO &mmio = mem.mmio; + RSP &rsp = mmio.rsp; + RDP &rdp = mmio.rdp; + MI &mi = mmio.mi; + switch (index) { + case 0: + rsp.spDMASPAddr.raw = val; + break; + case 1: + rsp.spDMADRAMAddr.raw = val; + break; + case 2: + rsp.spDMALen.raw = val; + rsp.DMA(); + break; + case 3: + rsp.spDMALen.raw = val; + rsp.DMA(); + break; + case 4: + rsp.WriteStatus(val); + break; + case 7: + if (val == 0) { + ReleaseSemaphore(rsp); + } else { + Util::panic("Write with non-zero value to RSP_COP0_RESERVED ({})", val); + } + break; + case 8: + rdp.WriteStart(val); + break; + case 9: + rdp.WriteEnd(val); + break; + case 11: + rdp.WriteStatus(val); + break; + default: + Util::panic("Unhandled RSP COP0 register write at index {}", index); } } -FORCE_INLINE VPR Broadcast(const VPR& vt, int l0, int l1, int l2, int l3, int l4, int l5, int l6, int l7) { +FORCE_INLINE VPR Broadcast(const VPR &vt, int l0, int l1, int l2, int l3, int l4, int l5, int l6, int l7) { VPR vte{}; vte.element[ELEMENT_INDEX(0)] = vt.element[ELEMENT_INDEX(l0)]; vte.element[ELEMENT_INDEX(1)] = vt.element[ELEMENT_INDEX(l1)]; @@ -95,50 +122,66 @@ FORCE_INLINE VPR Broadcast(const VPR& vt, int l0, int l1, int l2, int l3, int l4 } #ifdef SIMD_SUPPORT -FORCE_INLINE VPR GetVTE(const VPR& vt, u8 e) { +FORCE_INLINE VPR GetVTE(const VPR &vt, u8 e) { VPR vte{}; e &= 0xf; - switch(e & 0xf) { - case 0 ... 1: return vt; - case 2: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xF5), 0xF5); break; - case 3: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xA0), 0xA0); break; - case 4: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xFF), 0xFF); break; - case 5: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xAA), 0xAA); break; - case 6: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0x55), 0x55); break; - case 7: vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0x00), 0x00); break; - case 8 ... 15: { + switch (e & 0xf) { + case 0 ... 1: + return vt; + case 2: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xF5), 0xF5); + break; + case 3: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xA0), 0xA0); + break; + case 4: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xFF), 0xFF); + break; + case 5: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0xAA), 0xAA); + break; + case 6: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0x55), 0x55); + break; + case 7: + vte.single = _mm_shufflehi_epi16(_mm_shufflelo_epi16(vt.single, 0x00), 0x00); + break; + case 8 ... 15: + { int index = ELEMENT_INDEX(e - 8); vte.single = _mm_set1_epi16(vt.element[index]); - } break; + } + break; } return vte; } #else -FORCE_INLINE VPR GetVTE(const VPR& vt, u8 e) { +FORCE_INLINE VPR GetVTE(const VPR &vt, u8 e) { VPR vte{}; e &= 0xf; - switch(e) { - case 0 ... 1: return vt; - case 2 ... 3: - vte = Broadcast(vt, e - 2, e - 2, e, e, e + 2, e + 2, e + 4, e + 4); - break; - case 4 ... 7: - vte = Broadcast(vt, e - 4, e - 4, e - 4, e - 4, e, e, e, e); - break; - case 8 ... 15: { + switch (e) { + case 0 ... 1: + return vt; + case 2 ... 3: + vte = Broadcast(vt, e - 2, e - 2, e, e, e + 2, e + 2, e + 4, e + 4); + break; + case 4 ... 7: + vte = Broadcast(vt, e - 4, e - 4, e - 4, e - 4, e, e, e, e); + break; + case 8 ... 15: + { int index = ELEMENT_INDEX(e - 8); for (int i = 0; i < 8; i++) { vte.element[i] = vt.element[index]; } - } break; + } + break; } return vte; } #endif -void RSP::add(u32 instr) { - gpr[RD(instr)] = gpr[RS(instr)] + gpr[RT(instr)]; -} +void RSP::add(u32 instr) { gpr[RD(instr)] = gpr[RS(instr)] + gpr[RT(instr)]; } void RSP::addi(u32 instr) { s32 op1 = gpr[RS(instr)]; @@ -147,20 +190,22 @@ void RSP::addi(u32 instr) { gpr[RT(instr)] = result; } -void RSP::and_(u32 instr) { - gpr[RD(instr)] = gpr[RT(instr)] & gpr[RS(instr)]; -} +void RSP::and_(u32 instr) { gpr[RD(instr)] = gpr[RT(instr)] & gpr[RS(instr)]; } -void RSP::andi(u32 instr) { - gpr[RT(instr)] = gpr[RS(instr)] & (u16)instr; -} +void RSP::andi(u32 instr) { gpr[RT(instr)] = gpr[RS(instr)] & (u16)instr; } void RSP::cfc2(u32 instr) { s16 value = 0; - switch(RD(instr) & 3) { - case 0: value = GetVCO(); break; - case 1: value = GetVCC(); break; - case 2 ... 3: value = GetVCE(); break; + switch (RD(instr) & 3) { + case 0: + value = GetVCO(); + break; + case 1: + value = GetVCC(); + break; + case 2 ... 3: + value = GetVCE(); + break; } gpr[RT(instr)] = value; @@ -168,24 +213,25 @@ void RSP::cfc2(u32 instr) { void RSP::ctc2(u32 instr) { u16 value = gpr[RT(instr)]; - switch(RD(instr) & 3) { - case 0: - for(int i = 0; i < 8; i++) { - vco.h.element[ELEMENT_INDEX(i)] = ((value >> (i + 8)) & 1) == 1 ? 0xFFFF : 0; - vco.l.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; - } - break; - case 1: - for(int i = 0; i < 8; i++) { - vcc.h.element[ELEMENT_INDEX(i)] = ((value >> (i + 8)) & 1) == 1 ? 0xFFFF : 0; - vcc.l.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; - } - break; - case 2: case 3: - for(int i = 0; i < 8; i++) { - vce.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; - } - break; + switch (RD(instr) & 3) { + case 0: + for (int i = 0; i < 8; i++) { + vco.h.element[ELEMENT_INDEX(i)] = ((value >> (i + 8)) & 1) == 1 ? 0xFFFF : 0; + vco.l.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; + } + break; + case 1: + for (int i = 0; i < 8; i++) { + vcc.h.element[ELEMENT_INDEX(i)] = ((value >> (i + 8)) & 1) == 1 ? 0xFFFF : 0; + vcc.l.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; + } + break; + case 2: + case 3: + for (int i = 0; i < 8; i++) { + vce.element[ELEMENT_INDEX(i)] = ((value >> i) & 1) == 1 ? 0xFFFF : 0; + } + break; } } @@ -236,7 +282,7 @@ void RSP::lqv(u32 instr) { u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 4); u32 end = ((addr & ~15) + 15); - for(int i = 0; addr + i <= end && i + e < 16; i++) { + for (int i = 0; addr + i <= end && i + e < 16; i++) { vpr[VT(instr)].byte[BYTE_INDEX(i + e)] = ReadByte(addr + i); } } @@ -248,7 +294,7 @@ void RSP::lpv(u32 instr) { int addrOffset = addr & 7; addr &= ~7; - for(int elem = 0; elem < 8; elem++) { + for (int elem = 0; elem < 8; elem++) { int elemOffset = (16 - e + (elem + addrOffset)) & 0xF; u16 value = ReadByte(addr + elemOffset); @@ -281,7 +327,7 @@ void RSP::suv(u32 instr) { int end = start + 8; for (int offset = start; offset < end; offset++) { - if((offset & 15) < 8) { + if ((offset & 15) < 8) { WriteByte(addr++, vpr[VT(instr)].element[ELEMENT_INDEX(offset & 7)] >> 7); } else { WriteByte(addr++, vpr[VT(instr)].byte[BYTE_INDEX((offset & 7) << 1)]); @@ -294,7 +340,7 @@ void RSP::ldv(u32 instr) { u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 3); u32 end = e + 8 > 16 ? 16 : e + 8; - for(int i = e; i < end; i++) { + for (int i = e; i < end; i++) { vpr[VT(instr)].byte[BYTE_INDEX(i)] = ReadByte(addr); addr++; } @@ -305,7 +351,7 @@ void RSP::lsv(u32 instr) { u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 1); u16 val = ReadHalf(addr); vpr[VT(instr)].byte[BYTE_INDEX(e)] = val >> 8; - if(e < 15) { + if (e < 15) { vpr[VT(instr)].byte[BYTE_INDEX(e + 1)] = val; } } @@ -319,9 +365,9 @@ void RSP::llv(u32 instr) { int e = E1(instr); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 2); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { int elem = i + e; - if(elem > 15) { + if (elem > 15) { break; } @@ -339,18 +385,14 @@ void RSP::jal(u32 instr) { gpr[31] = pc + 4; } -void RSP::jr(u32 instr) { - nextPC = gpr[RS(instr)]; -} +void RSP::jr(u32 instr) { nextPC = gpr[RS(instr)]; } void RSP::jalr(u32 instr) { jr(instr); gpr[RD(instr)] = pc + 4; } -void RSP::nor(u32 instr) { - gpr[RD(instr)] = ~(gpr[RT(instr)] | gpr[RS(instr)]); -} +void RSP::nor(u32 instr) { gpr[RD(instr)] = ~(gpr[RT(instr)] | gpr[RS(instr)]); } void RSP::ori(u32 instr) { s32 op1 = gpr[RS(instr)]; @@ -366,13 +408,9 @@ void RSP::xori(u32 instr) { gpr[RT(instr)] = result; } -void RSP::or_(u32 instr) { - gpr[RD(instr)] = gpr[RT(instr)] | gpr[RS(instr)]; -} +void RSP::or_(u32 instr) { gpr[RD(instr)] = gpr[RT(instr)] | gpr[RS(instr)]; } -void RSP::xor_(u32 instr) { - gpr[RD(instr)] = gpr[RT(instr)] ^ gpr[RS(instr)]; -} +void RSP::xor_(u32 instr) { gpr[RD(instr)] = gpr[RT(instr)] ^ gpr[RS(instr)]; } void RSP::sb(u32 instr) { u32 address = gpr[BASE(instr)] + (s16)instr; @@ -395,22 +433,20 @@ void RSP::swv(u32 instr) { int base = address & 7; address &= ~7; - for(int i = E1(instr); i < E1(instr) + 16; i++) { + for (int i = E1(instr); i < E1(instr) + 16; i++) { WriteByte(address + (base & 15), vpr[VT(instr)].byte[BYTE_INDEX(i & 15)]); base++; } } -void RSP::sub(u32 instr) { - gpr[RD(instr)] = gpr[RS(instr)] - gpr[RT(instr)]; -} +void RSP::sub(u32 instr) { gpr[RD(instr)] = gpr[RS(instr)] - gpr[RT(instr)]; } void RSP::sqv(u32 instr) { int e = E1(instr); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 4); u32 end = ((addr & ~15) + 15); - for(int i = 0; addr + i <= end; i++) { + for (int i = 0; addr + i <= end; i++) { WriteByte(addr + i, vpr[VT(instr)].byte[BYTE_INDEX((i + e) & 15)]); } } @@ -422,8 +458,8 @@ void RSP::spv(u32 instr) { int start = e; int end = start + 8; - for(int offset = start; offset < end; offset++) { - if((offset & 15) < 8) { + for (int offset = start; offset < end; offset++) { + if ((offset & 15) < 8) { WriteByte(addr++, vpr[VT(instr)].byte[BYTE_INDEX((offset & 7) << 1)]); } else { WriteByte(addr++, vpr[VT(instr)].element[ELEMENT_INDEX(offset & 7)] >> 7); @@ -437,7 +473,7 @@ void RSP::srv(u32 instr) { int end = start + (address & 15); int base = 16 - (address & 15); address &= ~15; - for(int i = start; i < end; i++) { + for (int i = start; i < end; i++) { WriteByte(address++, vpr[VT(instr)].byte[BYTE_INDEX((i + base) & 0xF)]); } } @@ -478,7 +514,7 @@ void RSP::lhv(u32 instr) { } void RSP::lfv(u32 instr) { - VPR& vt = vpr[VT(instr)]; + VPR &vt = vpr[VT(instr)]; int start = E1(instr); u32 address = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 4); u32 base = (address & 7) - start; @@ -504,13 +540,13 @@ void RSP::lrv(u32 instr) { int start = 16 - ((address & 15) - e); address &= ~15; - for(int i = start; i < 16; i++) { + for (int i = start; i < 16; i++) { vpr[VT(instr)].byte[BYTE_INDEX(i & 0xF)] = ReadByte(address++); } } void RSP::sfv(u32 instr) { - VPR& vt = vpr[VT(instr)]; + VPR &vt = vpr[VT(instr)]; u32 address = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 4); int base = address & 7; address &= ~7; @@ -519,51 +555,51 @@ void RSP::sfv(u32 instr) { u8 values[4] = {0, 0, 0, 0}; switch (e) { - case 0: - case 15: - values[0] = vt.element[ELEMENT_INDEX(0)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(1)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(2)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(3)] >> 7; - break; - case 1: - values[0] = vt.element[ELEMENT_INDEX(6)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(7)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(4)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(5)] >> 7; - break; - case 4: - values[0] = vt.element[ELEMENT_INDEX(1)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(2)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(3)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(0)] >> 7; - break; - case 5: - values[0] = vt.element[ELEMENT_INDEX(7)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(4)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(5)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(6)] >> 7; - break; - case 8: - values[0] = vt.element[ELEMENT_INDEX(4)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(5)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(6)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(7)] >> 7; - break; - case 11: - values[0] = vt.element[ELEMENT_INDEX(3)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(0)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(1)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(2)] >> 7; - break; - case 12: - values[0] = vt.element[ELEMENT_INDEX(5)] >> 7; - values[1] = vt.element[ELEMENT_INDEX(6)] >> 7; - values[2] = vt.element[ELEMENT_INDEX(7)] >> 7; - values[3] = vt.element[ELEMENT_INDEX(4)] >> 7; - break; - default: - break; + case 0: + case 15: + values[0] = vt.element[ELEMENT_INDEX(0)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(1)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(2)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(3)] >> 7; + break; + case 1: + values[0] = vt.element[ELEMENT_INDEX(6)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(7)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(4)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(5)] >> 7; + break; + case 4: + values[0] = vt.element[ELEMENT_INDEX(1)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(2)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(3)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(0)] >> 7; + break; + case 5: + values[0] = vt.element[ELEMENT_INDEX(7)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(4)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(5)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(6)] >> 7; + break; + case 8: + values[0] = vt.element[ELEMENT_INDEX(4)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(5)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(6)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(7)] >> 7; + break; + case 11: + values[0] = vt.element[ELEMENT_INDEX(3)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(0)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(1)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(2)] >> 7; + break; + case 12: + values[0] = vt.element[ELEMENT_INDEX(5)] >> 7; + values[1] = vt.element[ELEMENT_INDEX(6)] >> 7; + values[2] = vt.element[ELEMENT_INDEX(7)] >> 7; + values[3] = vt.element[ELEMENT_INDEX(4)] >> 7; + break; + default: + break; } for (int i = 0; i < 4; i++) { @@ -582,7 +618,7 @@ void RSP::sdv(u32 instr) { int e = E1(instr); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 3); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { WriteByte(addr + i, vpr[VT(instr)].byte[BYTE_INDEX((i + e) & 0xF)]); } } @@ -602,7 +638,7 @@ void RSP::slv(u32 instr) { int e = E1(instr); u32 addr = gpr[BASE(instr)] + SignExt7bit(OFFSET(instr), 2); - for(int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { WriteByte(addr + i, vpr[VT(instr)].byte[BYTE_INDEX((i + e) & 0xF)]); } } @@ -684,13 +720,9 @@ void RSP::sra(u32 instr) { gpr[RD(instr)] = gpr[RT(instr)] >> sa; } -void RSP::slt(u32 instr) { - gpr[RD(instr)] = gpr[RS(instr)] < gpr[RT(instr)]; -} +void RSP::slt(u32 instr) { gpr[RD(instr)] = gpr[RS(instr)] < gpr[RT(instr)]; } -void RSP::sltu(u32 instr) { - gpr[RD(instr)] = (u32)gpr[RS(instr)] < (u32)gpr[RT(instr)]; -} +void RSP::sltu(u32 instr) { gpr[RD(instr)] = (u32)gpr[RS(instr)] < (u32)gpr[RT(instr)]; } void RSP::slti(u32 instr) { s32 imm = (s16)instr; @@ -703,21 +735,25 @@ void RSP::sltiu(u32 instr) { } FORCE_INLINE s16 signedClamp(s64 val) { - if(val < -32768) return -32768; - if(val > 32767) return 32767; + if (val < -32768) + return -32768; + if (val > 32767) + return 32767; return val; } FORCE_INLINE u16 unsignedClamp(s64 val) { - if(val < 0) return 0; - if(val > 32767) return 65535; + if (val < 0) + return 0; + if (val > 32767) + return 65535; return val; } #ifdef SIMD_SUPPORT void RSP::vabs(u32 instr) { - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); m128i isZero = _mm_cmpeq_epi16(vs.single, m128i{}); @@ -729,13 +765,13 @@ void RSP::vabs(u32 instr) { } #else void RSP::vabs(u32 instr) { - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + 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++) { - if(vs.selement[i] < 0) { - if(vte.element[i] == 0x8000) { + for (int i = 0; i < 8; i++) { + if (vs.selement[i] < 0) { + if (vte.element[i] == 0x8000) { vd.element[i] = 0x7FFF; acc.l.element[i] = 0x8000; } else { @@ -754,11 +790,11 @@ void RSP::vabs(u32 instr) { #endif void RSP::vadd(u32 instr) { - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + 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++) { + for (int i = 0; i < 8; i++) { s32 result = vs.selement[i] + vte.selement[i] + (vco.l.selement[i] != 0); acc.l.element[i] = result; vd.element[i] = (u16)signedClamp(result); @@ -768,11 +804,11 @@ void RSP::vadd(u32 instr) { } void RSP::vaddc(u32 instr) { - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + 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++) { + for (int i = 0; i < 8; i++) { u32 result = vs.element[i] + vte.element[i]; acc.l.element[i] = result; vd.element[i] = result; @@ -783,16 +819,16 @@ void RSP::vaddc(u32 instr) { void RSP::vch(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 vsElem = vs.selement[i]; s16 vteElem = vte.selement[i]; vco.l.element[i] = ((vsElem ^ vteElem) < 0) ? 0xffff : 0; - if(vco.l.element[i]) { + if (vco.l.element[i]) { s16 result = vsElem + vteElem; acc.l.selement[i] = (result <= 0) ? -vteElem : vsElem; @@ -815,11 +851,11 @@ void RSP::vch(u32 instr) { void RSP::vcr(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { u16 vsE = vs.element[i]; u16 vteE = vte.element[i]; @@ -847,19 +883,19 @@ void RSP::vcr(u32 instr) { void RSP::vcl(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); for (int i = 0; i < 8; i++) { u16 vs_element = vs.element[i]; u16 vte_element = vte.element[i]; - if(vco.l.element[i]) { - if(!vco.h.element[i]) { + if (vco.l.element[i]) { + if (!vco.h.element[i]) { u16 clamped_sum = vs_element + vte_element; bool overflow = (vs_element + vte_element) != clamped_sum; - if(vce.element[i]) { + if (vce.element[i]) { vcc.l.element[i] = (!clamped_sum || !overflow) ? 0xffff : 0; } else { vcc.l.element[i] = (!clamped_sum && !overflow) ? 0xffff : 0; @@ -867,7 +903,7 @@ void RSP::vcl(u32 instr) { } acc.l.element[i] = vcc.l.element[i] ? -vte_element : vs_element; } else { - if(!vco.h.element[i]) { + if (!vco.h.element[i]) { vcc.h.element[i] = ((s32)vs_element - (s32)vte_element >= 0) ? 0xffff : 0; } acc.l.element[i] = vcc.h.element[i] ? vte_element : vs_element; @@ -881,25 +917,25 @@ void RSP::vcl(u32 instr) { } void RSP::vmov(u32 instr) { u8 e = E2(instr), vs = VS(instr) & 7; - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); u8 se; - switch(e) { - case 0 ... 1: - se = (e & 0b000) | (vs & 0b111); - break; - case 2 ... 3: - se = (e & 0b001) | (vs & 0b110); - break; - case 4 ... 7: - se = (e & 0b011) | (vs & 0b100); - break; - case 8 ... 15: - se = (e & 0b111) | (vs & 0b000); - break; - default: - Util::panic("VMOV: This should be unreachable!"); + switch (e) { + case 0 ... 1: + se = (e & 0b000) | (vs & 0b111); + break; + case 2 ... 3: + se = (e & 0b001) | (vs & 0b110); + break; + case 4 ... 7: + se = (e & 0b011) | (vs & 0b100); + break; + case 8 ... 15: + se = (e & 0b111) | (vs & 0b000); + break; + default: + Util::panic("VMOV: This should be unreachable!"); } u8 de = vs & 7; @@ -908,7 +944,7 @@ void RSP::vmov(u32 instr) { #ifdef SIMD_SUPPORT acc.l.single = vte.single; #else - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vte.element[i]; } #endif @@ -925,11 +961,11 @@ FORCE_INLINE bool IsSignExtension(s16 hi, s16 lo) { void RSP::vmulf(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; s16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -945,13 +981,13 @@ void RSP::vmulf(u32 instr) { } void RSP::vmulq(u32 instr) { - VPR& vs = vpr[VS(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 product = vs.selement[i] * vte.selement[i]; - if(product < 0) { + if (product < 0) { product += 31; } @@ -964,11 +1000,11 @@ void RSP::vmulq(u32 instr) { void RSP::vmulu(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; s16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -985,10 +1021,10 @@ void RSP::vmulu(u32 instr) { void RSP::vmudl(u32 instr) { u8 e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { u64 op1 = vte.element[i]; u64 op2 = vs.element[i]; u64 prod = op1 * op2; @@ -997,7 +1033,7 @@ void RSP::vmudl(u32 instr) { SetACC(i, accum); u16 result; - if(IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { + if (IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { result = acc.l.element[i]; } else if (acc.h.selement[i] < 0) { result = 0; @@ -1011,10 +1047,10 @@ void RSP::vmudl(u32 instr) { void RSP::vmudh(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 prod = vs.selement[i] * vte.selement[i]; s64 accum = prod; @@ -1029,10 +1065,10 @@ void RSP::vmudh(u32 instr) { void RSP::vmudm(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 prod = vs.selement[i] * vte.element[i]; s64 accum = prod; @@ -1045,10 +1081,10 @@ void RSP::vmudm(u32 instr) { void RSP::vmudn(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; u16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -1056,9 +1092,9 @@ void RSP::vmudn(u32 instr) { SetACC(i, accum); u16 result; - if(IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { + if (IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { result = acc.l.element[i]; - } else if(acc.h.selement[i] < 0) { + } else if (acc.h.selement[i] < 0) { result = 0; } else { result = 0xffff; @@ -1071,8 +1107,8 @@ void RSP::vmudn(u32 instr) { #ifdef SIMD_SUPPORT void RSP::vmadh(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); m128i lo, hi, omask; lo = _mm_mullo_epi16(vs.single, vte.single); @@ -1090,10 +1126,10 @@ void RSP::vmadh(u32 instr) { #else void RSP::vmadh(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; s16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -1113,11 +1149,11 @@ void RSP::vmadh(u32 instr) { void RSP::vmadl(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { u64 op1 = vte.element[i]; u64 op2 = vs.element[i]; u64 prod = op1 * op2; @@ -1127,7 +1163,7 @@ void RSP::vmadl(u32 instr) { SetACC(i, accum); u16 result; - if(IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { + if (IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { result = acc.l.element[i]; } else if (acc.h.selement[i] < 0) { result = 0; @@ -1141,8 +1177,8 @@ void RSP::vmadl(u32 instr) { #ifdef SIMD_SUPPORT void RSP::vmadm(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); m128i lo, hi, sign, vta, omask; @@ -1170,8 +1206,8 @@ void RSP::vmadm(u32 instr) { void RSP::vmadn(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); m128i lo, hi, sign, vsa, omask, nhi, nmd, shi, smd, cmask, cval; @@ -1203,11 +1239,11 @@ void RSP::vmadn(u32 instr) { #else void RSP::vmadm(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 prod = vs.selement[i] * vte.element[i]; s64 accum = GetACC(i); accum += prod; @@ -1222,18 +1258,18 @@ void RSP::vmadm(u32 instr) { void RSP::vmadn(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 prod = vs.element[i] * vte.selement[i]; s64 accum = GetACC(i) + prod; SetACC(i, accum); u16 result; - if(IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { + if (IsSignExtension(acc.h.selement[i], acc.m.selement[i])) { result = acc.l.element[i]; } else if (acc.h.selement[i] < 0) { result = 0; @@ -1247,11 +1283,11 @@ void RSP::vmadn(u32 instr) { #endif void RSP::vmacf(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; s16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -1268,11 +1304,11 @@ void RSP::vmacf(u32 instr) { } void RSP::vmacu(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s16 op1 = vte.element[i]; s16 op2 = vs.element[i]; s32 prod = op1 * op2; @@ -1288,13 +1324,13 @@ void RSP::vmacu(u32 instr) { } void RSP::vmacq(u32 instr) { - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 product = acc.h.element[i] << 16 | acc.m.element[i]; - if(product < 0 && !(product & 1 << 5)) { + if (product < 0 && !(product & 1 << 5)) { product += 32; - } else if(product >= 32 && !(product & 1 << 5)) { + } else if (product >= 32 && !(product & 1 << 5)) { product -= 32; } acc.h.element[i] = product >> 16; @@ -1306,11 +1342,11 @@ void RSP::vmacq(u32 instr) { void RSP::veq(u32 instr) { int e = E2(instr); - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { vcc.l.element[i] = (vco.h.element[i] == 0) && (vs.element[i] == vte.element[i]) ? 0xffff : 0; acc.l.element[i] = vcc.l.element[i] ? vs.element[i] : vte.element[i]; vd.element[i] = acc.l.element[i]; @@ -1320,11 +1356,11 @@ void RSP::veq(u32 instr) { void RSP::vne(u32 instr) { int e = E2(instr); - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { vcc.l.element[i] = vco.h.element[i] || (vs.element[i] != vte.element[i]) ? 0xffff : 0; acc.l.element[i] = vcc.l.element[i] ? vs.element[i] : vte.element[i]; vd.element[i] = acc.l.element[i]; @@ -1334,11 +1370,11 @@ void RSP::vne(u32 instr) { void RSP::vge(u32 instr) { int e = E2(instr); - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { bool eql = vs.selement[i] == vte.selement[i]; bool neg = !(vco.h.element[i] && vco.l.element[i]) && eql; vcc.l.element[i] = (neg || (vs.selement[i] > vte.selement[i])) ? 0xffff : 0; @@ -1350,11 +1386,11 @@ void RSP::vge(u32 instr) { void RSP::vlt(u32 instr) { int e = E2(instr); - VPR& vd = vpr[VD(instr)]; - VPR& vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { bool eql = vs.element[i] == vte.element[i]; bool neg = vco.h.element[i] && vco.l.element[i] && eql; vcc.l.element[i] = (neg || (vs.selement[i] < vte.selement[i])) ? 0xffff : 0; @@ -1410,14 +1446,14 @@ FORCE_INLINE u32 rsq(u32 input) { } void RSP::vrcpl(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vt = vpr[VT(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vt = vpr[VT(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); int e = E2(instr) & 7; int de = DE(instr) & 7; s32 input; - if(divInLoaded) { + if (divInLoaded) { input = (s32(divIn) << 16) | vt.element[ELEMENT_INDEX(e)]; } else { input = vt.selement[ELEMENT_INDEX(e)]; @@ -1440,8 +1476,8 @@ void RSP::vrcpl(u32 instr) { } void RSP::vrcp(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vt = vpr[VT(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vt = vpr[VT(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); int e = E2(instr) & 7; int de = DE(instr) & 7; @@ -1461,8 +1497,8 @@ void RSP::vrcp(u32 instr) { } void RSP::vrsq(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vt = vpr[VT(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vt = vpr[VT(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); int e = E2(instr) & 7; int de = VS(instr) & 7; @@ -1489,13 +1525,13 @@ static FORCE_INLINE s64 sclip(s64 x, u32 bits) { } void RSP::vrndn(u32 instr) { - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 product = (s16)vte.selement[i]; - if(VS(instr) & 1) { + if (VS(instr) & 1) { product <<= 16; } @@ -1508,25 +1544,25 @@ void RSP::vrndn(u32 instr) { accum <<= 16; accum >>= 16; - if(accum < 0) { + if (accum < 0) { accum = sclip(accum + product, 48); } acc.h.element[i] = accum >> 32; acc.m.element[i] = accum >> 16; - acc.l.element[i] = accum >> 0; + acc.l.element[i] = accum >> 0; vd.element[i] = signedClamp(accum >> 16); } } void RSP::vrndp(u32 instr) { - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 product = (s16)vte.selement[i]; - if(VS(instr) & 1) { + if (VS(instr) & 1) { product <<= 16; } @@ -1539,26 +1575,26 @@ void RSP::vrndp(u32 instr) { accum <<= 16; accum >>= 16; - if(accum >= 0) { + if (accum >= 0) { accum = sclip(accum + product, 48); } acc.h.element[i] = accum >> 32; acc.m.element[i] = accum >> 16; - acc.l.element[i] = accum >> 0; + acc.l.element[i] = accum >> 0; vd.element[i] = signedClamp(accum >> 16); } } void RSP::vrsql(u32 instr) { - VPR& vd = vpr[VD(instr)]; - VPR& vt = vpr[VT(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vt = vpr[VT(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); int e = E2(instr) & 7; int de = DE(instr) & 7; s32 input; - if(divInLoaded) { + if (divInLoaded) { input = (divIn << 16) | vt.element[ELEMENT_INDEX(e)]; } else { input = vt.selement[ELEMENT_INDEX(e)]; @@ -1582,8 +1618,8 @@ void RSP::vrsql(u32 instr) { void RSP::vrcph(u32 instr) { int e = E2(instr) & 7; int de = DE(instr) & 7; - VPR& vd = vpr[VD(instr)]; - VPR& vt = vpr[VT(instr)]; + VPR &vd = vpr[VD(instr)]; + VPR &vt = vpr[VT(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); #ifdef SIMD_SUPPORT @@ -1601,54 +1637,54 @@ void RSP::vrcph(u32 instr) { void RSP::vsar(u32 instr) { u8 e = E2(instr); - VPR& vd = vpr[VD(instr)]; - switch(e) { - case 0x8: + VPR &vd = vpr[VD(instr)]; + switch (e) { + case 0x8: #ifdef SIMD_SUPPORT - vd.single = acc.h.single; + vd.single = acc.h.single; #else - for(int i = 0; i < 8; i++) { - vd.element[i] = acc.h.element[i]; - } + for (int i = 0; i < 8; i++) { + vd.element[i] = acc.h.element[i]; + } #endif - break; - case 0x9: + break; + case 0x9: #ifdef SIMD_SUPPORT - vd.single = acc.m.single; + vd.single = acc.m.single; #else - for(int i = 0; i < 8; i++) { - vd.element[i] = acc.m.element[i]; - } + for (int i = 0; i < 8; i++) { + vd.element[i] = acc.m.element[i]; + } #endif - break; - case 0xA: + break; + case 0xA: #ifdef SIMD_SUPPORT - vd.single = acc.l.single; + vd.single = acc.l.single; #else - for(int i = 0; i < 8; i++) { - vd.element[i] = acc.l.element[i]; - } + for (int i = 0; i < 8; i++) { + vd.element[i] = acc.l.element[i]; + } #endif - break; - default: + break; + default: #ifdef SIMD_SUPPORT - vd.single = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); + vd.single = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0); #else - for(int i = 0; i < 8; i++) { - vd.element[i] = 0; - } + for (int i = 0; i < 8; i++) { + vd.element[i] = 0; + } #endif - break; + break; } } void RSP::vsubc(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { u32 result = vs.element[i] - vte.element[i]; acc.l.element[i] = result; vd.element[i] = result; @@ -1660,11 +1696,11 @@ void RSP::vsubc(u32 instr) { void RSP::vsub(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { s32 result = vs.selement[i] - vte.selement[i] - (vco.l.element[i] != 0); acc.l.element[i] = result; vd.element[i] = signedClamp(result); @@ -1676,11 +1712,11 @@ void RSP::vsub(u32 instr) { void RSP::vmrg(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vcc.l.element[i] ? vs.element[i] : vte.element[i]; vd.element[i] = acc.l.element[i]; @@ -1690,11 +1726,11 @@ void RSP::vmrg(u32 instr) { void RSP::vxor(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vte.element[i] ^ vs.element[i]; vd.element[i] = acc.l.element[i]; } @@ -1702,11 +1738,11 @@ void RSP::vxor(u32 instr) { void RSP::vnxor(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = ~(vte.element[i] ^ vs.element[i]); vd.element[i] = acc.l.element[i]; } @@ -1714,11 +1750,11 @@ void RSP::vnxor(u32 instr) { void RSP::vand(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vte.element[i] & vs.element[i]; vd.element[i] = acc.l.element[i]; } @@ -1726,11 +1762,11 @@ void RSP::vand(u32 instr) { void RSP::vnand(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = ~(vte.element[i] & vs.element[i]); vd.element[i] = acc.l.element[i]; } @@ -1738,11 +1774,11 @@ void RSP::vnand(u32 instr) { void RSP::vnor(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = ~(vte.element[i] | vs.element[i]); vd.element[i] = acc.l.element[i]; } @@ -1750,35 +1786,31 @@ void RSP::vnor(u32 instr) { void RSP::vor(u32 instr) { int e = E2(instr); - VPR& vs = vpr[VS(instr)]; - VPR& vd = vpr[VD(instr)]; + VPR &vs = vpr[VS(instr)]; + VPR &vd = vpr[VD(instr)]; VPR vte = GetVTE(vpr[VT(instr)], e); - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vte.element[i] | vs.element[i]; vd.element[i] = acc.l.element[i]; } } void RSP::vzero(u32 instr) { - VPR& vs = vpr[VS(instr)]; + VPR &vs = vpr[VS(instr)]; VPR vte = GetVTE(vpr[VT(instr)], E2(instr)); - VPR& vd = vpr[VD(instr)]; + VPR &vd = vpr[VD(instr)]; - for(int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) { acc.l.element[i] = vte.element[i] + vs.element[i]; } memset(&vd, 0, sizeof(VPR)); } -void RSP::mfc0(RDP& rdp, u32 instr) { - gpr[RT(instr)] = GetCop0Reg(*this, rdp, RD(instr)); -} +void RSP::mfc0(RDP &rdp, u32 instr) { gpr[RT(instr)] = GetCop0Reg(*this, rdp, RD(instr)); } -void RSP::mtc0(u32 instr) { - SetCop0Reg(regs, mem, RD(instr), gpr[RT(instr)]); -} +void RSP::mtc0(u32 instr) { SetCop0Reg(regs, mem, RD(instr), gpr[RT(instr)]); } void RSP::mfc2(u32 instr) { u8 hi = vpr[RD(instr)].byte[BYTE_INDEX(E1(instr))]; @@ -1792,8 +1824,8 @@ void RSP::mtc2(u32 instr) { u8 lo = element; u8 hi = element >> 8; vpr[RD(instr)].byte[BYTE_INDEX(E1(instr))] = hi; - if(E1(instr) < 15) { + if (E1(instr) < 15) { vpr[RD(instr)].byte[BYTE_INDEX(E1(instr) + 1)] = lo; } } -} \ No newline at end of file +} // namespace n64 diff --git a/src/common.hpp b/src/common.hpp index d0aa2b46..23295f30 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -1,6 +1,6 @@ #pragma once -#include #include +#include #include using u8 = uint8_t; @@ -43,20 +43,20 @@ static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) { #define RD(x) (((x) >> 11) & 0x1F) #define RT(x) (((x) >> 16) & 0x1F) #define RS(x) (((x) >> 21) & 0x1F) -#define FD(x) (((x) >> 6) & 0x1F) +#define FD(x) (((x) >> 6) & 0x1F) #define FT(x) RT(x) #define FS(x) RD(x) #define BASE(x) RS(x) #define VT(x) (((x) >> 16) & 0x1F) #define VS(x) (((x) >> 11) & 0x1F) -#define VD(x) (((x) >> 6) & 0x1F) -#define E1(x) (((x) >> 7) & 0x0F) +#define VD(x) (((x) >> 6) & 0x1F) +#define E1(x) (((x) >> 7) & 0x0F) #define E2(x) (((x) >> 21) & 0x0F) #define ELEMENT_INDEX(i) (7 - (i)) -#define BYTE_INDEX(i) (15 - (i)) +#define BYTE_INDEX(i) (15 - (i)) #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) #define ABI_WINDOWS #else #define ABI_UNIX -#endif \ No newline at end of file +#endif diff --git a/src/frontend/AudioSettings.cpp b/src/frontend/AudioSettings.cpp index d75a4691..bcf6632a 100644 --- a/src/frontend/AudioSettings.cpp +++ b/src/frontend/AudioSettings.cpp @@ -2,7 +2,7 @@ #include #include -AudioSettings::AudioSettings(nlohmann::json& settings) : settings(settings), QWidget(nullptr) { +AudioSettings::AudioSettings(nlohmann::json &settings) : settings(settings), QWidget(nullptr) { lockChannels->setChecked(JSONGetField(settings, "audio", "lock")); volumeL->setValue(JSONGetField(settings, "audio", "volumeL") * 100); volumeR->setValue(JSONGetField(settings, "audio", "volumeR") * 100); @@ -34,12 +34,12 @@ AudioSettings::AudioSettings(nlohmann::json& settings) : settings(settings), QWi emit modified(); }); - QLabel* labelLock = new QLabel("Lock channels:"); - QLabel* labelL = new QLabel("Volume L"); - QLabel* labelR = new QLabel("Volume R"); + auto labelLock = new QLabel("Lock channels:"); + auto labelL = new QLabel("Volume L"); + auto labelR = new QLabel("Volume R"); - QVBoxLayout* mainLayout = new QVBoxLayout; - QHBoxLayout* volLayout = new QHBoxLayout; + auto mainLayout = new QVBoxLayout; + auto volLayout = new QHBoxLayout; mainLayout->addWidget(labelLock); mainLayout->addWidget(lockChannels); volLayout->addWidget(labelL); @@ -49,4 +49,4 @@ AudioSettings::AudioSettings(nlohmann::json& settings) : settings(settings), QWi mainLayout->addLayout(volLayout); mainLayout->addStretch(); setLayout(mainLayout); -} \ No newline at end of file +} diff --git a/src/frontend/AudioSettings.hpp b/src/frontend/AudioSettings.hpp index 84a7eee6..0adf663d 100644 --- a/src/frontend/AudioSettings.hpp +++ b/src/frontend/AudioSettings.hpp @@ -1,16 +1,16 @@ #pragma once -#include -#include -#include #include +#include +#include +#include class AudioSettings : public QWidget { - QCheckBox* lockChannels = new QCheckBox; + QCheckBox *lockChannels = new QCheckBox; Q_OBJECT public: - QSlider* volumeL = new QSlider(Qt::Horizontal), * volumeR = new QSlider(Qt::Horizontal); - AudioSettings(nlohmann::json&); - nlohmann::json& settings; + QSlider *volumeL = new QSlider(Qt::Horizontal), *volumeR = new QSlider(Qt::Horizontal); + AudioSettings(nlohmann::json &); + nlohmann::json &settings; Q_SIGNALS: void modified(); -}; \ No newline at end of file +}; diff --git a/src/frontend/CPUSettings.cpp b/src/frontend/CPUSettings.cpp index a34e43c2..bde18659 100644 --- a/src/frontend/CPUSettings.cpp +++ b/src/frontend/CPUSettings.cpp @@ -1,11 +1,11 @@ #include -#include -#include #include +#include +#include #include -CPUSettings::CPUSettings(nlohmann::json& settings) : settings(settings), QWidget(nullptr) { - cpuTypes->addItems({ "Interpreter", "Dynamic Recompiler" }); +CPUSettings::CPUSettings(nlohmann::json &settings) : settings(settings), QWidget(nullptr) { + cpuTypes->addItems({"Interpreter", "Dynamic Recompiler"}); if (JSONGetField(settings, "cpu", "type") == "jit") { cpuTypes->setCurrentIndex(1); @@ -25,11 +25,11 @@ CPUSettings::CPUSettings(nlohmann::json& settings) : settings(settings), QWidget emit modified(); }); - QLabel* label = new QLabel("CPU type:"); + auto label = new QLabel("CPU type:"); - QVBoxLayout* mainLayout = new QVBoxLayout; + auto mainLayout = new QVBoxLayout; mainLayout->addWidget(label); mainLayout->addWidget(cpuTypes); mainLayout->addStretch(); setLayout(mainLayout); -} \ No newline at end of file +} diff --git a/src/frontend/CPUSettings.hpp b/src/frontend/CPUSettings.hpp index 664511aa..39b009cb 100644 --- a/src/frontend/CPUSettings.hpp +++ b/src/frontend/CPUSettings.hpp @@ -1,14 +1,14 @@ #pragma once -#include -#include #include +#include +#include class CPUSettings : public QWidget { - QComboBox* cpuTypes = new QComboBox; + QComboBox *cpuTypes = new QComboBox; Q_OBJECT public: - CPUSettings(nlohmann::json&); - nlohmann::json& settings; + CPUSettings(nlohmann::json &); + nlohmann::json &settings; Q_SIGNALS: void modified(); -}; \ No newline at end of file +}; diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index f05af38e..945c5e2f 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -1,25 +1,26 @@ #include #include -EmuThread::EmuThread(const std::shared_ptr& instance_, const std::shared_ptr& wsiPlatform_, const std::shared_ptr& windowInfo_, SettingsWindow& settings) noexcept - : instance(instance_), wsiPlatform(wsiPlatform_), - windowInfo(windowInfo_), - core(parallel), settings(settings) {} +EmuThread::EmuThread(const std::shared_ptr &instance_, + const std::shared_ptr &wsiPlatform_, + const std::shared_ptr &windowInfo_, SettingsWindow &settings) noexcept : + instance(instance_), wsiPlatform(wsiPlatform_), windowInfo(windowInfo_), core(parallel), settings(settings) {} [[noreturn]] void EmuThread::run() noexcept { parallel.Init(instance, wsiPlatform, windowInfo, core.cpu->GetMem().GetRDRAMPtr()); SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); bool controllerConnected = false; - if(SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { + if (SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { Util::warn("[SDL] Could not load game controller DB"); } auto pollEvents = [&]() { SDL_Event e; - while(SDL_PollEvent(&e)) { - switch(e.type) { - case SDL_CONTROLLERDEVICEADDED: { + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_CONTROLLERDEVICEADDED: + { const int index = e.cdevice.which; controller = SDL_GameControllerOpen(index); Util::info("Found controller!"); @@ -30,11 +31,14 @@ EmuThread::EmuThread(const std::shared_ptr& instance_, const Util::info("\tSerial: {}", serial ? serial : "Not available"); Util::info("\tPath: {}", path ? path : "Not available"); controllerConnected = true; - } break; - case SDL_CONTROLLERDEVICEREMOVED: { + } + break; + case SDL_CONTROLLERDEVICEREMOVED: + { controllerConnected = false; SDL_GameControllerClose(controller); - } break; + } + break; } } }; @@ -42,36 +46,48 @@ EmuThread::EmuThread(const std::shared_ptr& instance_, const while (true) { if (!core.pause) { core.Run(settings.getVolumeL(), settings.getVolumeR()); - if(core.render) { + if (core.render) { parallel.UpdateScreen(core.cpu->GetMem().mmio.vi); } } else { - if(core.render) { + if (core.render) { parallel.UpdateScreen(core.cpu->GetMem().mmio.vi, true); } } pollEvents(); - if(controllerConnected) { - n64::PIF& pif = core.cpu->GetMem().mmio.si.pif; + if (controllerConnected) { + n64::PIF &pif = core.cpu->GetMem().mmio.si.pif; pif.UpdateButton(0, n64::Controller::Key::A, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_A)); pif.UpdateButton(0, n64::Controller::Key::B, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_X)); - pif.UpdateButton(0, n64::Controller::Key::Z, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX); - pif.UpdateButton(0, n64::Controller::Key::Start, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)); - pif.UpdateButton(0, n64::Controller::Key::DUp, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)); - pif.UpdateButton(0, n64::Controller::Key::DDown, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)); - pif.UpdateButton(0, n64::Controller::Key::DLeft, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)); - pif.UpdateButton(0, n64::Controller::Key::DRight, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)); - pif.UpdateButton(0, n64::Controller::Key::LT, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::RT, SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)); - pif.UpdateButton(0, n64::Controller::Key::CUp, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CDown, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) >= 127); - pif.UpdateButton(0, n64::Controller::Key::CLeft, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) <= -127); - pif.UpdateButton(0, n64::Controller::Key::CRight, SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) >= 127); + pif.UpdateButton(0, n64::Controller::Key::Z, + SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) == SDL_JOYSTICK_AXIS_MAX); + pif.UpdateButton(0, n64::Controller::Key::Start, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_START)); + pif.UpdateButton(0, n64::Controller::Key::DUp, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_UP)); + pif.UpdateButton(0, n64::Controller::Key::DDown, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_DOWN)); + pif.UpdateButton(0, n64::Controller::Key::DLeft, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_LEFT)); + pif.UpdateButton(0, n64::Controller::Key::DRight, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_DPAD_RIGHT)); + pif.UpdateButton(0, n64::Controller::Key::LT, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::RT, + SDL_GameControllerGetButton(controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)); + pif.UpdateButton(0, n64::Controller::Key::CUp, + SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CDown, + SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY) >= 127); + pif.UpdateButton(0, n64::Controller::Key::CLeft, + SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) <= -127); + pif.UpdateButton(0, n64::Controller::Key::CRight, + SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX) >= 127); float xclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); - if(xclamped < 0) { + if (xclamped < 0) { xclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); } else { xclamped /= SDL_JOYSTICK_AXIS_MAX; @@ -80,7 +96,7 @@ EmuThread::EmuThread(const std::shared_ptr& instance_, const xclamped *= 86; float yclamped = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); - if(yclamped < 0) { + if (yclamped < 0) { yclamped /= float(std::abs(SDL_JOYSTICK_AXIS_MIN)); } else { yclamped /= SDL_JOYSTICK_AXIS_MAX; @@ -92,4 +108,4 @@ EmuThread::EmuThread(const std::shared_ptr& instance_, const pif.UpdateAxis(0, n64::Controller::Axis::X, xclamped); } } -} \ No newline at end of file +} diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 99c3b700..1eb08ce3 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -1,34 +1,32 @@ #pragma once -#include -#include #include +#include +#include +#include #include #include -#include -class EmuThread : public QThread -{ +class EmuThread : public QThread { Q_OBJECT std::shared_ptr instance; std::shared_ptr wsiPlatform; std::shared_ptr windowInfo; + public: - explicit EmuThread(const std::shared_ptr& instance, const std::shared_ptr& wsiPlatform, const std::shared_ptr& windowInfo, SettingsWindow&) noexcept; + explicit EmuThread(const std::shared_ptr &instance, + const std::shared_ptr &wsiPlatform, + const std::shared_ptr &windowInfo, SettingsWindow &) noexcept; [[noreturn]] void run() noexcept override; - SDL_GameController* controller = nullptr; + SDL_GameController *controller = nullptr; ParallelRDP parallel; n64::Core core; - SettingsWindow& settings; + SettingsWindow &settings; - void TogglePause() { - core.pause = !core.pause; - } + void TogglePause() { core.pause = !core.pause; } - void SetRender(bool v) { - core.render = v; - } + void SetRender(bool v) { core.render = v; } void Reset() { core.pause = true; @@ -42,4 +40,4 @@ public: core.pause = true; core.Stop(); } -}; \ No newline at end of file +}; diff --git a/src/frontend/InputSettings.cpp b/src/frontend/InputSettings.cpp index ef46ad09..16492e03 100644 --- a/src/frontend/InputSettings.cpp +++ b/src/frontend/InputSettings.cpp @@ -1,9 +1,9 @@ #include -#include #include +#include #include -InputSettings::InputSettings(nlohmann::json& settings) : settings(settings), QWidget(nullptr) { +InputSettings::InputSettings(nlohmann::json &settings) : settings(settings), QWidget(nullptr) { n64_button_labels[0] = new QLabel("A"); n64_button_labels[1] = new QLabel("B"); n64_button_labels[2] = new QLabel("Z"); @@ -22,7 +22,7 @@ InputSettings::InputSettings(nlohmann::json& settings) : settings(settings), QWi n64_button_labels[15] = new QLabel("Analog Down"); n64_button_labels[16] = new QLabel("Analog Left"); n64_button_labels[17] = new QLabel("Analog Right"); - + auto str = JSONGetField(settings, "input", "A"); kb_buttons[0] = new QPushButton(str.c_str()); str = JSONGetField(settings, "input", "B"); @@ -132,10 +132,11 @@ InputSettings::InputSettings(nlohmann::json& settings) : settings(settings), QWi } -void InputSettings::keyPressEvent(QKeyEvent* e) { +void InputSettings::keyPressEvent(QKeyEvent *e) { if (grabbing) { auto k = QKeySequence(e->key()).toString(); - JSONSetField(settings, "input", n64_button_labels[which_grabbing]->text().toStdString(), k.toStdString()); + JSONSetField(settings, "input", n64_button_labels[which_grabbing]->text().toStdString(), + k.toStdString()); kb_buttons[which_grabbing]->setText(k); grabbing = false; which_grabbing = -1; @@ -155,4 +156,4 @@ std::array InputSettings::GetMappedKeys() { } return ret; -} \ No newline at end of file +} diff --git a/src/frontend/InputSettings.hpp b/src/frontend/InputSettings.hpp index d000af1a..3aa21e16 100644 --- a/src/frontend/InputSettings.hpp +++ b/src/frontend/InputSettings.hpp @@ -1,20 +1,20 @@ #pragma once -#include -#include -#include #include +#include +#include +#include class InputSettings : public QWidget { bool grabbing = false; int which_grabbing = -1; - QPushButton* kb_buttons[18]; - QLabel* n64_button_labels[18]; + QPushButton *kb_buttons[18]; + QLabel *n64_button_labels[18]; Q_OBJECT public: - InputSettings(nlohmann::json&); - nlohmann::json& settings; - void keyPressEvent(QKeyEvent*) override; + InputSettings(nlohmann::json &); + nlohmann::json &settings; + void keyPressEvent(QKeyEvent *) override; std::array GetMappedKeys(); Q_SIGNALS: void modified(); -}; \ No newline at end of file +}; diff --git a/src/frontend/JSONUtils.hpp b/src/frontend/JSONUtils.hpp index 875eea93..79e3c332 100644 --- a/src/frontend/JSONUtils.hpp +++ b/src/frontend/JSONUtils.hpp @@ -1,13 +1,13 @@ #pragma once -#include #include #include +#include namespace fs = std::filesystem; -static inline nlohmann::json JSONOpenOrCreate(const std::string& path) { +static inline nlohmann::json JSONOpenOrCreate(const std::string &path) { auto fileExists = fs::exists(path); - + if (fileExists) { auto file = std::fstream(path, std::fstream::in | std::fstream::out); auto json = nlohmann::json::parse(file); @@ -50,11 +50,12 @@ static inline nlohmann::json JSONOpenOrCreate(const std::string& path) { } template -static inline void JSONSetField(nlohmann::json& json, const std::string& field1, const std::string& field2, const T& value) { +static inline void JSONSetField(nlohmann::json &json, const std::string &field1, const std::string &field2, + const T &value) { json[field1][field2] = value; } template -static inline T JSONGetField(nlohmann::json& json, const std::string& field1, const std::string& field2) { +static inline T JSONGetField(nlohmann::json &json, const std::string &field1, const std::string &field2) { return json[field1][field2].get(); -} \ No newline at end of file +} diff --git a/src/frontend/KaizenQt.cpp b/src/frontend/KaizenQt.cpp index f18e9064..245c7607 100644 --- a/src/frontend/KaizenQt.cpp +++ b/src/frontend/KaizenQt.cpp @@ -1,21 +1,18 @@ #include -#include #include #include +#include #include #include namespace fs = std::filesystem; -KaizenQt::KaizenQt() noexcept : - QWidget(nullptr) { +KaizenQt::KaizenQt() noexcept : QWidget(nullptr) { mainWindow = std::make_unique(); settingsWindow = std::make_unique(); - emuThread = std::make_unique( - std::move(mainWindow->view.vulkanWidget->instance), - std::move(mainWindow->view.vulkanWidget->wsiPlatform), - std::move(mainWindow->view.vulkanWidget->windowInfo), - *settingsWindow); + emuThread = std::make_unique(std::move(mainWindow->view.vulkanWidget->instance), + std::move(mainWindow->view.vulkanWidget->wsiPlatform), + std::move(mainWindow->view.vulkanWidget->windowInfo), *settingsWindow); ConnectMainWindowSignalsToSlots(); @@ -25,22 +22,16 @@ KaizenQt::KaizenQt() noexcept : grabKeyboard(); mainWindow->show(); settingsWindow->hide(); - connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&]() { - grabKeyboard(); - }); + connect(settingsWindow.get(), &SettingsWindow::regrabKeyboard, this, [&]() { grabKeyboard(); }); } void KaizenQt::ConnectMainWindowSignalsToSlots() noexcept { - connect(mainWindow.get(), &MainWindowController::OpenSettings, this, [this]() { - settingsWindow->show(); - }); + connect(mainWindow.get(), &MainWindowController::OpenSettings, this, [this]() { settingsWindow->show(); }); connect(mainWindow.get(), &MainWindowController::OpenROM, this, &KaizenQt::LoadROM); connect(mainWindow.get(), &MainWindowController::Exit, this, &KaizenQt::Quit); connect(mainWindow.get(), &MainWindowController::Reset, emuThread.get(), &EmuThread::Reset); connect(mainWindow.get(), &MainWindowController::Stop, emuThread.get(), &EmuThread::Stop); - connect(mainWindow.get(), &MainWindowController::Stop, this, [this]() { - mainWindow->setWindowTitle("Kaizen"); - }); + connect(mainWindow.get(), &MainWindowController::Stop, this, [this]() { mainWindow->setWindowTitle("Kaizen"); }); connect(mainWindow.get(), &MainWindowController::Pause, emuThread.get(), &EmuThread::TogglePause); } diff --git a/src/frontend/KaizenQt.hpp b/src/frontend/KaizenQt.hpp index 23c129a9..8f9765a5 100644 --- a/src/frontend/KaizenQt.hpp +++ b/src/frontend/KaizenQt.hpp @@ -1,11 +1,10 @@ #pragma once +#include #include #include #include -enum class CompositorCategory { - Windows, MacOS, XCB, Wayland -}; +enum class CompositorCategory { Windows, MacOS, XCB, Wayland }; static inline CompositorCategory GetOSCompositorCategory() { const QString platform_name = QGuiApplication::platformName(); @@ -13,8 +12,7 @@ static inline CompositorCategory GetOSCompositorCategory() { return CompositorCategory::Windows; else if (platform_name == QStringLiteral("xcb")) return CompositorCategory::XCB; - else if (platform_name == QStringLiteral("wayland") || - platform_name == QStringLiteral("wayland-egl")) + else if (platform_name == QStringLiteral("wayland") || platform_name == QStringLiteral("wayland-egl")) return CompositorCategory::Wayland; else if (platform_name == QStringLiteral("cocoa") || platform_name == QStringLiteral("ios")) return CompositorCategory::MacOS; @@ -27,16 +25,17 @@ class KaizenQt : public QWidget { Q_OBJECT public: KaizenQt() noexcept; - void LoadTAS(const QString& path) const noexcept; - void LoadROM(const QString& path) noexcept; - void dropEvent(QDropEvent*) override; - void dragEnterEvent(QDragEnterEvent*) override; - void keyPressEvent(QKeyEvent*) override; - void keyReleaseEvent(QKeyEvent*) override; + void LoadTAS(const QString &path) const noexcept; + void LoadROM(const QString &path) noexcept; + void dropEvent(QDropEvent *) override; + void dragEnterEvent(QDragEnterEvent *) override; + void keyPressEvent(QKeyEvent *) override; + void keyReleaseEvent(QKeyEvent *) override; + private: void Quit() noexcept; void ConnectMainWindowSignalsToSlots() noexcept; std::unique_ptr mainWindow; std::unique_ptr settingsWindow; std::unique_ptr emuThread; -}; \ No newline at end of file +}; diff --git a/src/frontend/MainWindow.cpp b/src/frontend/MainWindow.cpp index b4588467..1be86ffe 100644 --- a/src/frontend/MainWindow.cpp +++ b/src/frontend/MainWindow.cpp @@ -1,7 +1,7 @@ -#include -#include -#include #include +#include +#include +#include #include MainWindowController::MainWindowController() noexcept { @@ -15,7 +15,8 @@ MainWindowController::MainWindowController() noexcept { void MainWindowController::ConnectSignalsToSlots() noexcept { connect(view.actionOpen, &QAction::triggered, this, [this]() { - QString file_name = QFileDialog::getOpenFileName(this, "Nintendo 64 executable", QString(), + QString file_name = QFileDialog::getOpenFileName( + this, "Nintendo 64 executable", QString(), "All supported types (*.zip *.ZIP *.7z *.7Z *.rar *.RAR *.tar *.TAR *.n64 *.N64 *.v64 *.V64 *.z64 *.Z64)"); if (!file_name.isEmpty()) { @@ -24,17 +25,11 @@ void MainWindowController::ConnectSignalsToSlots() noexcept { } }); - connect(view.actionExit, &QAction::triggered, this, [this]() { - emit Exit(); - }); + connect(view.actionExit, &QAction::triggered, this, [this]() { emit Exit(); }); - connect(this, &MainWindowController::destroyed, this, [this]() { - emit Exit(); - }); + connect(this, &MainWindowController::destroyed, this, [this]() { emit Exit(); }); - connect(view.actionReset, &QAction::triggered, this, [this]() { - emit Reset(); - }); + connect(view.actionReset, &QAction::triggered, this, [this]() { emit Reset(); }); connect(view.actionStop, &QAction::triggered, this, [this]() { view.vulkanWidget->hide(); @@ -51,15 +46,12 @@ void MainWindowController::ConnectSignalsToSlots() noexcept { }); connect(view.actionAbout, &QAction::triggered, this, [this]() { - QMessageBox::about( - this, tr("About Kaizen"), - tr("Kaizen is a Nintendo 64 emulator that strives to offer a friendly user " - "experience and great compatibility.\n" - "Kaizen is licensed under the BSD 3-clause license.\n" - "Nintendo 64 is a registered trademarks of Nintendo Co., Ltd.")); + QMessageBox::about(this, tr("About Kaizen"), + tr("Kaizen is a Nintendo 64 emulator that strives to offer a friendly user " + "experience and great compatibility.\n" + "Kaizen is licensed under the BSD 3-clause license.\n" + "Nintendo 64 is a registered trademarks of Nintendo Co., Ltd.")); }); - connect(view.actionSettings, &QAction::triggered, this, [this]() { - emit OpenSettings(); - }); -} \ No newline at end of file + connect(view.actionSettings, &QAction::triggered, this, [this]() { emit OpenSettings(); }); +} diff --git a/src/frontend/MainWindow.hpp b/src/frontend/MainWindow.hpp index 2aaaf981..65cd6ef9 100644 --- a/src/frontend/MainWindow.hpp +++ b/src/frontend/MainWindow.hpp @@ -1,17 +1,17 @@ #pragma once -#include "ui_mainwindow.h" -#include -#include #include +#include +#include +#include "ui_mainwindow.h" -class MainWindowController : public QMainWindow -{ +class MainWindowController : public QMainWindow { Q_OBJECT public: MainWindowController() noexcept; Ui::MainWindow view; + private: void ConnectSignalsToSlots() noexcept; @@ -19,9 +19,9 @@ private: Q_SIGNALS: void OpenSettings(); - void OpenROM(const QString& rom_file); + void OpenROM(const QString &rom_file); void Exit(); void Reset(); void Stop(); void Pause(); -}; \ No newline at end of file +}; diff --git a/src/frontend/RenderWidget.cpp b/src/frontend/RenderWidget.cpp index d1e20026..f6321236 100644 --- a/src/frontend/RenderWidget.cpp +++ b/src/frontend/RenderWidget.cpp @@ -1,7 +1,7 @@ -#include #include +#include -RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) { +RenderWidget::RenderWidget(QWidget *parent) : QWidget(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); if (GetOSCompositorCategory() == CompositorCategory::Wayland) { @@ -10,12 +10,11 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) { if (GetOSCompositorCategory() == CompositorCategory::MacOS) { windowHandle()->setSurfaceType(QWindow::MetalSurface); - } - else { + } else { windowHandle()->setSurfaceType(QWindow::VulkanSurface); } - if(!Vulkan::Context::init_loader(nullptr)) { + if (!Vulkan::Context::init_loader(nullptr)) { Util::panic("Could not initialize Vulkan ICD"); } @@ -25,4 +24,4 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent) { wsiPlatform = std::make_unique(windowHandle()); windowInfo = std::make_unique(windowHandle()); -} \ No newline at end of file +} diff --git a/src/frontend/RenderWidget.hpp b/src/frontend/RenderWidget.hpp index 543a5ab9..978a1b2e 100644 --- a/src/frontend/RenderWidget.hpp +++ b/src/frontend/RenderWidget.hpp @@ -1,25 +1,25 @@ #pragma once #undef signals #include -#include -#include #include #include +#include +#include struct QtInstanceFactory : Vulkan::InstanceFactory { VkInstance create_instance(const VkInstanceCreateInfo *info) override { - qVkInstance.setApiVersion({1,3,0}); + qVkInstance.setApiVersion({1, 3, 0}); QByteArrayList exts; - for(int i = 0; i < info->enabledExtensionCount; i++) { + for (int i = 0; i < info->enabledExtensionCount; i++) { exts.push_back(QByteArray::fromStdString(info->ppEnabledExtensionNames[i])); } QByteArrayList layers; - for(int i = 0; i < info->enabledLayerCount; i++) { + for (int i = 0; i < info->enabledLayerCount; i++) { layers.push_back(QByteArray::fromStdString(info->ppEnabledLayerNames[i])); } qVkInstance.setExtensions(exts); qVkInstance.setLayers(layers); - qVkInstance.setApiVersion({1,3,0}); + qVkInstance.setApiVersion({1, 3, 0}); qVkInstance.create(); return qVkInstance.vkInstance(); @@ -30,22 +30,23 @@ struct QtInstanceFactory : Vulkan::InstanceFactory { class QtParallelRdpWindowInfo : public ParallelRDP::WindowInfo { public: - explicit QtParallelRdpWindowInfo(QWindow* window) : window(window) {} + explicit QtParallelRdpWindowInfo(QWindow *window) : window(window) {} CoordinatePair get_window_size() override { - return CoordinatePair{ static_cast(window->width()), static_cast(window->height()) }; + return CoordinatePair{static_cast(window->width()), static_cast(window->height())}; } + private: - QWindow* window; + QWindow *window; }; class QtWSIPlatform final : public Vulkan::WSIPlatform { public: - explicit QtWSIPlatform(QWindow* window) : window(window) {} + explicit QtWSIPlatform(QWindow *window) : window(window) {} - std::vector get_instance_extensions() override { - auto vec = std::vector(); + std::vector get_instance_extensions() override { + auto vec = std::vector(); - for (const auto& ext : window->vulkanInstance()->supportedExtensions()) { + for (const auto &ext : window->vulkanInstance()->supportedExtensions()) { vec.push_back(ext.name); } @@ -57,44 +58,32 @@ public: return QVulkanInstance::surfaceForWindow(window); } - void destroy_surface(VkInstance, VkSurfaceKHR) override { } + void destroy_surface(VkInstance, VkSurfaceKHR) override {} - uint32_t get_surface_width() override { - return 640; - } + uint32_t get_surface_width() override { return 640; } - uint32_t get_surface_height() override { - return 480; - } + uint32_t get_surface_height() override { return 480; } - bool alive(Vulkan::WSI&) override { - return true; - } + bool alive(Vulkan::WSI &) override { return true; } void poll_input() override {} - void poll_input_async(Granite::InputTrackerHandler* handler) override {} + void poll_input_async(Granite::InputTrackerHandler *handler) override {} - void event_frame_tick(double frame, double elapsed) override { } + void event_frame_tick(double frame, double elapsed) override {} - const VkApplicationInfo* get_application_info() override { - return &appInfo; - } + const VkApplicationInfo *get_application_info() override { return &appInfo; } + + VkApplicationInfo appInfo{.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_3}; - VkApplicationInfo appInfo{ - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .apiVersion = VK_API_VERSION_1_3 - }; private: - QWindow* window; + QWindow *window; }; class RenderWidget : public QWidget { public: - explicit RenderWidget(QWidget* parent); + explicit RenderWidget(QWidget *parent); - [[nodiscard]] QPaintEngine* paintEngine() const override { - return nullptr; - } + [[nodiscard]] QPaintEngine *paintEngine() const override { return nullptr; } std::unique_ptr windowInfo; std::unique_ptr wsiPlatform; @@ -102,4 +91,4 @@ public: Q_SIGNALS: void Show() { show(); } void Hide() { hide(); } -}; \ No newline at end of file +}; diff --git a/src/frontend/SettingsWindow.cpp b/src/frontend/SettingsWindow.cpp index 411f8efe..2d62a9df 100644 --- a/src/frontend/SettingsWindow.cpp +++ b/src/frontend/SettingsWindow.cpp @@ -1,8 +1,8 @@ -#include -#include -#include #include #include +#include +#include +#include #include std::string savePath = ""; @@ -44,7 +44,7 @@ SettingsWindow::SettingsWindow() : QWidget(nullptr) { generalLayoutV->addStretch(); generalSettings->setLayout(generalLayoutV); - auto* tabs = new QTabWidget; + auto *tabs = new QTabWidget; tabs->addTab(generalSettings, tr("General")); tabs->addTab(cpuSettings, tr("CPU")); tabs->addTab(audioSettings, tr("Audio")); @@ -52,17 +52,11 @@ SettingsWindow::SettingsWindow() : QWidget(nullptr) { apply->setEnabled(false); - connect(cpuSettings, &CPUSettings::modified, this, [&]() { - apply->setEnabled(true); - }); + connect(cpuSettings, &CPUSettings::modified, this, [&]() { apply->setEnabled(true); }); - connect(audioSettings, &AudioSettings::modified, this, [&]() { - apply->setEnabled(true); - }); + connect(audioSettings, &AudioSettings::modified, this, [&]() { apply->setEnabled(true); }); - connect(inputSettings, &InputSettings::modified, this, [&]() { - apply->setEnabled(true); - }); + connect(inputSettings, &InputSettings::modified, this, [&]() { apply->setEnabled(true); }); connect(apply, &QPushButton::pressed, this, [&]() { auto newMap = inputSettings->GetMappedKeys(); @@ -78,11 +72,11 @@ SettingsWindow::SettingsWindow() : QWidget(nullptr) { connect(cancel, &QPushButton::pressed, this, &QWidget::hide); - QVBoxLayout* mainLayout = new QVBoxLayout; - QHBoxLayout* buttonsLayout = new QHBoxLayout; + QVBoxLayout *mainLayout = new QVBoxLayout; + QHBoxLayout *buttonsLayout = new QHBoxLayout; buttonsLayout->addWidget(apply); buttonsLayout->addWidget(cancel); mainLayout->addWidget(tabs); mainLayout->addLayout(buttonsLayout); setLayout(mainLayout); -} \ No newline at end of file +} diff --git a/src/frontend/SettingsWindow.hpp b/src/frontend/SettingsWindow.hpp index 32c9c014..27a640c1 100644 --- a/src/frontend/SettingsWindow.hpp +++ b/src/frontend/SettingsWindow.hpp @@ -1,19 +1,19 @@ #pragma once -#include -#include -#include -#include -#include #include +#include #include +#include +#include +#include +#include class SettingsWindow : public QWidget { - QPushButton* cancel = new QPushButton("Cancel"); - QPushButton* apply = new QPushButton("Apply"); - QFileIconProvider* iconProv = new QFileIconProvider; - QPushButton* folderBtn = new QPushButton(iconProv->icon(QFileIconProvider::Folder), ""); - QLabel* folderLabelPrefix; - QLabel* folderLabel; + QPushButton *cancel = new QPushButton("Cancel"); + QPushButton *apply = new QPushButton("Apply"); + QFileIconProvider *iconProv = new QFileIconProvider; + QPushButton *folderBtn = new QPushButton(iconProv->icon(QFileIconProvider::Folder), ""); + QLabel *folderLabelPrefix; + QLabel *folderLabel; Q_OBJECT public: float getVolumeL() { return float(audioSettings->volumeL->value()) / 100.f; } @@ -21,10 +21,10 @@ public: std::array keyMap{}; SettingsWindow(); nlohmann::json settings; - CPUSettings* cpuSettings; - AudioSettings* audioSettings; - InputSettings* inputSettings; - QWidget* generalSettings; + CPUSettings *cpuSettings; + AudioSettings *audioSettings; + InputSettings *inputSettings; + QWidget *generalSettings; Q_SIGNALS: void regrabKeyboard(); -}; \ No newline at end of file +}; diff --git a/src/frontend/main.cpp b/src/frontend/main.cpp index ebec2993..19d38bca 100644 --- a/src/frontend/main.cpp +++ b/src/frontend/main.cpp @@ -2,7 +2,7 @@ #include #include -int main(int argc, char** argv) { +int main(int argc, char **argv) { QApplication app(argc, argv); app.setStyle("fusion"); QCoreApplication::setOrganizationName("kaizen"); @@ -10,12 +10,9 @@ int main(int argc, char** argv) { QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::applicationName()); parser.addHelpOption(); - parser.addOptions({ - {"rom", "Rom to launch from command-line", "path"}, - {"movie", "Mupen Movie to replay", "path"} - }); + parser.addOptions({{"rom", "Rom to launch from command-line", "path"}, {"movie", "Mupen Movie to replay", "path"}}); parser.process(app); - + KaizenQt kaizenQt; if (parser.isSet("rom")) { kaizenQt.LoadROM(parser.value("rom")); @@ -25,4 +22,4 @@ int main(int argc, char** argv) { } return app.exec(); -} \ No newline at end of file +} diff --git a/src/utils/File.hpp b/src/utils/File.hpp index 63bca37a..aee00212 100644 --- a/src/utils/File.hpp +++ b/src/utils/File.hpp @@ -3,18 +3,18 @@ #include namespace Util { -FORCE_INLINE std::vector ReadFileBinary(const std::string& path) { +FORCE_INLINE std::vector ReadFileBinary(const std::string &path) { std::ifstream file(path, std::ios::binary); return {std::istreambuf_iterator{file}, {}}; } -FORCE_INLINE void WriteFileBinary(const std::vector& data, const std::string& path) { +FORCE_INLINE void WriteFileBinary(const std::vector &data, const std::string &path) { std::ofstream file(path, std::ios::binary); std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file}); } template -FORCE_INLINE void WriteFileBinary(const std::array& data, const std::string& path) { +FORCE_INLINE void WriteFileBinary(const std::array &data, const std::string &path) { std::ofstream file(path, std::ios::binary); std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file}); } @@ -30,4 +30,4 @@ FORCE_INLINE size_t NextPow2(size_t num) { num |= num >> 16; return num + 1; } -} \ No newline at end of file +} // namespace Util diff --git a/src/utils/FloatingPoint.hpp b/src/utils/FloatingPoint.hpp index 078d2f4c..a56a4fde 100644 --- a/src/utils/FloatingPoint.hpp +++ b/src/utils/FloatingPoint.hpp @@ -3,8 +3,8 @@ // #pragma once -#include #include +#include #include namespace Util { @@ -52,7 +52,7 @@ static inline T roundNearest(double f) { #endif } -template +template static inline T roundCurrent(float f) { #ifdef SIMD_SUPPORT auto t = _mm_set_ss(f); @@ -63,7 +63,7 @@ static inline T roundCurrent(float f) { #endif } -template +template static inline T roundCurrent(double f) { #ifdef SIMD_SUPPORT auto t = _mm_set_sd(f); @@ -78,11 +78,11 @@ static inline T roundCurrent(double f) { template static inline T roundFloor(float f) { #ifdef SIMD_SUPPORT -__m128 t = _mm_set_ss(f); + __m128 t = _mm_set_ss(f); t = _mm_round_ss(t, t, _MM_FROUND_TO_NEG_INF); return _mm_cvtss_f32(t); #else -return floor(f); + return floor(f); #endif } @@ -118,4 +118,4 @@ static inline T roundTrunc(double f) { return trunc(f); #endif } -} \ No newline at end of file +} // namespace Util diff --git a/src/utils/MemoryHelpers.hpp b/src/utils/MemoryHelpers.hpp index 2fae7a09..833296b6 100644 --- a/src/utils/MemoryHelpers.hpp +++ b/src/utils/MemoryHelpers.hpp @@ -1,113 +1,113 @@ #pragma once #include #include -#include -#include #include +#include +#include namespace Util { -template -static FORCE_INLINE T ReadAccess(const u8* data, u32 index) { +template +static FORCE_INLINE T ReadAccess(const u8 *data, u32 index) { if constexpr (sizeof(T) == 8) { - u32 hi = *reinterpret_cast(&data[index + 0]); - u32 lo = *reinterpret_cast(&data[index + 4]); + u32 hi = *reinterpret_cast(&data[index + 0]); + u32 lo = *reinterpret_cast(&data[index + 4]); T result = ((T)hi << 32) | (T)lo; return result; } else { - return *reinterpret_cast(&data[index]); + return *reinterpret_cast(&data[index]); } } -template -static FORCE_INLINE T ReadAccess(const std::vector& data, u32 index) { +template +static FORCE_INLINE T ReadAccess(const std::vector &data, u32 index) { if constexpr (sizeof(T) == 8) { - u32 hi = *reinterpret_cast(&data[index + 0]); - u32 lo = *reinterpret_cast(&data[index + 4]); + u32 hi = *reinterpret_cast(&data[index + 0]); + u32 lo = *reinterpret_cast(&data[index + 4]); T result = ((T)hi << 32) | (T)lo; return result; } else { - return *reinterpret_cast(&data[index]); + return *reinterpret_cast(&data[index]); } } -template -static FORCE_INLINE T ReadAccess(const std::array& data, u32 index) { +template +static FORCE_INLINE T ReadAccess(const std::array &data, u32 index) { if constexpr (sizeof(T) == 8) { - u32 hi = *reinterpret_cast(&data[index + 0]); - u32 lo = *reinterpret_cast(&data[index + 4]); + u32 hi = *reinterpret_cast(&data[index + 0]); + u32 lo = *reinterpret_cast(&data[index + 4]); T result = ((T)hi << 32) | (T)lo; return result; } else { - return *reinterpret_cast(&data[index]); + return *reinterpret_cast(&data[index]); } } -template -static FORCE_INLINE void WriteAccess(std::array& data, u32 index, T val) { +template +static FORCE_INLINE void WriteAccess(std::array &data, u32 index, T val) { if constexpr (sizeof(T) == 8) { u32 hi = val >> 32; u32 lo = val; - *reinterpret_cast(&data[index + 0]) = hi; - *reinterpret_cast(&data[index + 4]) = lo; + *reinterpret_cast(&data[index + 0]) = hi; + *reinterpret_cast(&data[index + 4]) = lo; } else { - *reinterpret_cast(&data[index]) = val; + *reinterpret_cast(&data[index]) = val; } } -template -static FORCE_INLINE void WriteAccess(std::vector& data, u32 index, T val) { +template +static FORCE_INLINE void WriteAccess(std::vector &data, u32 index, T val) { if constexpr (sizeof(T) == 8) { u32 hi = val >> 32; u32 lo = val; - *reinterpret_cast(&data[index + 0]) = hi; - *reinterpret_cast(&data[index + 4]) = lo; + *reinterpret_cast(&data[index + 0]) = hi; + *reinterpret_cast(&data[index + 4]) = lo; } else { - *reinterpret_cast(&data[index]) = val; + *reinterpret_cast(&data[index]) = val; } } -template +template static FORCE_INLINE void WriteAccess(u8 *data, u32 index, T val) { if constexpr (sizeof(T) == 8) { u32 hi = val >> 32; u32 lo = val; - *reinterpret_cast(&data[index + 0]) = hi; - *reinterpret_cast(&data[index + 4]) = lo; + *reinterpret_cast(&data[index + 0]) = hi; + *reinterpret_cast(&data[index + 4]) = lo; } else { - *reinterpret_cast(&data[index]) = val; + *reinterpret_cast(&data[index]) = val; } } FORCE_INLINE void SwapBuffer32(std::vector &data) { for (size_t i = 0; i < data.size(); i += 4) { - u32 original = *(u32 *) &data[i]; - *(u32 *) &data[i] = bswap_32(original); + u32 original = *(u32 *)&data[i]; + *(u32 *)&data[i] = bswap_32(original); } } FORCE_INLINE void SwapBuffer16(std::vector &data) { for (size_t i = 0; i < data.size(); i += 2) { - u16 original = *(u16 *) &data[i]; - *(u16 *) &data[i] = bswap_16(original); + u16 original = *(u16 *)&data[i]; + *(u16 *)&data[i] = bswap_16(original); } } template FORCE_INLINE void SwapBuffer32(std::array &data) { for (size_t i = 0; i < Size; i += 4) { - u32 original = *(u32 *) &data[i]; - *(u32 *) &data[i] = bswap_32(original); + u32 original = *(u32 *)&data[i]; + *(u32 *)&data[i] = bswap_32(original); } } template FORCE_INLINE void SwapBuffer16(std::array &data) { for (size_t i = 0; i < Size; i += 2) { - u16 original = *(u16 *) &data[i]; - *(u16 *) &data[i] = bswap_16(original); + u16 original = *(u16 *)&data[i]; + *(u16 *)&data[i] = bswap_16(original); } } @@ -134,27 +134,19 @@ FORCE_INLINE u32 crc32(u32 crc, const u8 *buf, size_t len) { crc = ~crc; for (int i = 0; i < len; i++) { - octet = buf[i]; /* Cast to unsigned octet. */ + octet = buf[i]; /* Cast to unsigned octet. */ crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet]; } return ~crc; } #ifdef _WIN32 -FORCE_INLINE void* aligned_alloc(size_t alignment, size_t size) { - return _aligned_malloc(size, alignment); -} +FORCE_INLINE void *aligned_alloc(size_t alignment, size_t size) { return _aligned_malloc(size, alignment); } -FORCE_INLINE void aligned_free(void* ptr) { - _aligned_free(ptr); -} +FORCE_INLINE void aligned_free(void *ptr) { _aligned_free(ptr); } #else -FORCE_INLINE void* aligned_alloc(size_t alignment, size_t size) { - return std::aligned_alloc(alignment, size); -} +FORCE_INLINE void *aligned_alloc(size_t alignment, size_t size) { return std::aligned_alloc(alignment, size); } -FORCE_INLINE void aligned_free(void* ptr) { - std::free(ptr); -} +FORCE_INLINE void aligned_free(void *ptr) { std::free(ptr); } #endif -} \ No newline at end of file +} // namespace Util diff --git a/src/utils/log.hpp b/src/utils/log.hpp index f87f3c19..a038957b 100644 --- a/src/utils/log.hpp +++ b/src/utils/log.hpp @@ -1,16 +1,14 @@ #pragma once #include -#include #include +#include #include #if !defined(NDEBUG) && !defined(_WIN32) #include #endif namespace Util { -enum LogLevel : u8 { - Trace, Debug, Warn, Info, Error, Always -}; +enum LogLevel : u8 { Trace, Debug, Warn, Info, Error, Always }; #ifndef NDEBUG static constexpr auto globalLogLevel = Debug; @@ -18,23 +16,23 @@ static constexpr auto globalLogLevel = Debug; static constexpr auto globalLogLevel = Info; #endif -template -constexpr void print(const std::string& fmt, Args... args) { - if constexpr(messageType >= globalLogLevel) { +template +constexpr void print(const std::string &fmt, Args... args) { + if constexpr (messageType >= globalLogLevel) { #ifndef _WIN32 - if constexpr(messageType == Error) { + if constexpr (messageType == Error) { fmt::print(fmt::emphasis::bold | fg(fmt::color::red), fmt, args...); - } else if constexpr(messageType == Warn) { + } else if constexpr (messageType == Warn) { fmt::print(fg(fmt::color::yellow), fmt, args...); - } else if constexpr(messageType == Info || messageType == Trace || messageType == Always) { + } else if constexpr (messageType == Info || messageType == Trace || messageType == Always) { fmt::print(fmt, args...); - } else if constexpr(messageType == Debug) { + } else if constexpr (messageType == Debug) { #ifndef NDEBUG fmt::print(fmt, args...); #endif } #else - if constexpr(messageType == Debug) { + if constexpr (messageType == Debug) { #ifndef NDEBUG fmt::print(fmt, args...); #endif @@ -45,61 +43,61 @@ constexpr void print(const std::string& fmt, Args... args) { } } -template -constexpr void panic(const std::string& fmt, Args... args) { +template +constexpr void panic(const std::string &fmt, Args... args) { print("[FATAL] " + fmt + "\n", args...); exit(-1); } -template -constexpr void error(const std::string& fmt, Args... args) { +template +constexpr void error(const std::string &fmt, Args... args) { print("[ERROR] " + fmt + "\n", args...); } -template -constexpr void warn(const std::string& fmt, Args... args) { +template +constexpr void warn(const std::string &fmt, Args... args) { print("[WARN] " + fmt + "\n", args...); } -template -constexpr void info(const std::string& fmt, Args... args) { +template +constexpr void info(const std::string &fmt, Args... args) { print("[INFO] " + fmt + "\n", args...); } -template -constexpr void debug(const std::string& fmt, Args... args) { +template +constexpr void debug(const std::string &fmt, Args... args) { print("[DEBUG] " + fmt + "\n", args...); } -template -constexpr void trace(const std::string& fmt, Args... args) { +template +constexpr void trace(const std::string &fmt, Args... args) { print("[TRACE] " + fmt + "\n", args...); } -template -constexpr void always(const std::string& fmt, Args... args) { +template +constexpr void always(const std::string &fmt, Args... args) { print(fmt + "\n", args...); } -template -constexpr void panic_trace(const std::string& fmt, Args... args) { +template +constexpr void panic_trace(const std::string &fmt, Args... args) { #if !defined(NDEBUG) && !defined(_WIN32) Dl_info info; auto tmp = fmt::format(fmt + '\n', args...); tmp += "Called by:\n"; - if(dladdr(__builtin_return_address(0), &info)) + if (dladdr(__builtin_return_address(0), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(1), &info)) + if (dladdr(__builtin_return_address(1), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(2), &info)) + if (dladdr(__builtin_return_address(2), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(3), &info)) + if (dladdr(__builtin_return_address(3), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(4), &info)) + if (dladdr(__builtin_return_address(4), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(5), &info)) + if (dladdr(__builtin_return_address(5), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); - if(dladdr(__builtin_return_address(6), &info)) + if (dladdr(__builtin_return_address(6), &info)) tmp += fmt::format("\t-> {}\n", info.dli_sname); print("[FATAL TRACE] " + tmp); @@ -108,4 +106,4 @@ constexpr void panic_trace(const std::string& fmt, Args... args) { panic(fmt, args...); #endif } -} \ No newline at end of file +} // namespace Util