Update ImGui

This commit is contained in:
CocoSimone
2023-02-26 03:34:46 +01:00
parent d813aa0ef2
commit 27516afaca
29 changed files with 4487 additions and 13921 deletions

View File

@@ -1,7 +1,6 @@
#include <Core.hpp>
#include <ParallelRDPWrapper.hpp>
#include <Window.hpp>
#include <algorithm>
#include <Scheduler.hpp>
namespace n64 {
@@ -18,18 +17,17 @@ void Core::Stop() {
romLoaded = false;
}
CartInfo Core::LoadROM(const std::string& rom_) {
void Core::LoadROM(const std::string& rom_) {
rom = rom_;
cpu->Reset();
cpu->mem.Reset();
pause = false;
romLoaded = true;
CartInfo cartInfo = cpu->mem.LoadROM(rom);
isPAL = cartInfo.isPAL;
cpu->mem.mmio.si.pif.ExecutePIF(cpu->mem, cpu->regs, cartInfo);
return cartInfo;
cpu->mem.LoadROM(rom);
GameDB::match(cpu->mem);
isPAL = cpu->mem.IsROMPAL();
cpu->mem.mmio.si.pif.ExecutePIF(cpu->mem, cpu->regs);
}
void Core::Run(Window& window, float volumeL, float volumeR) {

View File

@@ -19,7 +19,7 @@ struct Core {
~Core() { Stop(); }
Core();
void Stop();
CartInfo LoadROM(const std::string&);
void LoadROM(const std::string&);
void Run(Window&, float volumeL, float volumeR);
void TogglePause() { pause = !pause; }
VI& GetVI() { return cpu->mem.mmio.vi; }

36
src/backend/GameDB.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include <GameDB.hpp>
#include <Mem.hpp>
namespace n64 {
void GameDB::match(Mem& mem) {
ROM& rom = mem.rom;
for (const auto & i : gamedb) {
bool matches_code = i.code == rom.code;
bool matches_region = false;
for (int j = 0; j < i.regions.size() && !matches_region; j++) {
if (i.regions[j] == rom.header.countryCode[0]) {
matches_region = true;
}
}
if (matches_code) {
if (matches_region) {
mem.saveType = i.saveType;
mem.rom.gameNameDB = i.name;
Util::debug("Loaded {}\n", i.name);
return;
} else {
Util::warn("Matched code for %s, but not region! Game supposedly exists in regions [{}] but this image has region {}\n",
i.name, i.regions, rom.header.countryCode[0]);
}
}
}
Util::debug("Did not match any Game DB entries. Code: {} Region: {}\n", mem.rom.code, mem.rom.header.countryCode[0]);
mem.rom.gameNameDB = "";
mem.saveType = SAVE_NONE;
}
}

210
src/backend/GameDB.hpp Normal file
View File

@@ -0,0 +1,210 @@
#pragma once
#include <string>
namespace n64 {
enum SaveType {
SAVE_NONE,
SAVE_EEPROM_4k,
SAVE_EEPROM_16k,
SAVE_FLASH_1m,
SAVE_SRAM_256k
};
struct Mem;
struct GameDBEntry {
std::string code;
std::string regions;
SaveType saveType;
const char *name;
};
namespace GameDB {
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"},
// 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"},
};
}

View File

@@ -3,66 +3,25 @@
#include <MemoryHelpers.hpp>
namespace Util {
enum RomTypes {
Z64 = 0x80371240,
N64 = 0x40123780,
V64 = 0x37804012
};
inline void GetRomCRC(size_t size, u8 *rom, u32 &crc) {
RomTypes endianness;
memcpy(&endianness, rom, 4);
endianness = static_cast<RomTypes>(be32toh(endianness));
#define Z64 0x80371240
#define N64 0x40123780
#define V64 0x37804012
template <bool toBE = false>
inline void SwapN64Rom(size_t size, u8 *rom, u32 endianness) {
switch (endianness) {
case RomTypes::V64: {
case V64:
SwapBuffer16(size, rom);
crc = crc32(0, rom, size);
}
if constexpr(!toBE)
SwapBuffer32(size, rom);
break;
case RomTypes::N64: {
SwapBuffer32(size, rom);
crc = crc32(0, rom, size);
}
case N64:
if constexpr(toBE)
SwapBuffer32(size, rom);
break;
case RomTypes::Z64:
crc = crc32(0, rom, size);
break;
default:
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!\n");
}
}
inline void SwapN64Rom(size_t size, u8 *rom, u32 &crc, u32 &cicChecksum) {
RomTypes endianness;
memcpy(&endianness, rom, 4);
endianness = static_cast<RomTypes>(be32toh(endianness));
switch (endianness) {
case RomTypes::V64: {
u8 *temp = (u8 *) calloc(size, 1);
memcpy(temp, rom, size);
SwapBuffer16(size, temp);
crc = crc32(0, temp, size);
cicChecksum = crc32(0, &temp[0x40], 0x9c0);
free(temp);
SwapBuffer32(size, rom);
SwapBuffer16(size, rom);
}
break;
case RomTypes::N64: {
u8 *temp = (u8 *) calloc(size, 1);
memcpy(temp, rom, size);
SwapBuffer32(size, temp);
crc = crc32(0, temp, size);
cicChecksum = crc32(0, &temp[0x40], 0x9c0);
free(temp);
}
break;
case RomTypes::Z64:
crc = crc32(0, rom, size);
cicChecksum = crc32(0, &rom[0x40], 0x9c0);
SwapBuffer32(size, rom);
case Z64:
if constexpr(!toBE)
SwapBuffer32(size, rom);
break;
default:
panic("Unrecognized rom format! Make sure this is a valid Nintendo 64 ROM dump!\n");

View File

@@ -8,7 +8,7 @@
namespace n64 {
Mem::Mem() {
cart = (u8*)calloc(CART_SIZE, 1);
rom.cart = (u8*)calloc(CART_SIZE, 1);
sram = (u8*)calloc(SRAM_SIZE, 1);
Reset();
}
@@ -24,12 +24,27 @@ void Mem::Reset() {
writePages[i] = pointer;
}
memset(cart, 0, CART_SIZE);
memset(rom.cart, 0, CART_SIZE);
memset(sram, 0, SRAM_SIZE);
mmio.Reset();
}
CartInfo Mem::LoadROM(const std::string& filename) {
inline void SetROMCIC(u32 checksum, ROM& rom) {
switch (checksum) {
case 0xEC8B1325: rom.cicType = CIC_NUS_7102; break; // 7102
case 0x1DEB51A9: rom.cicType = CIC_NUS_6101; break; // 6101
case 0xC08E5BD6: rom.cicType = CIC_NUS_6102_7101; break;
case 0x03B8376A: rom.cicType = CIC_NUS_6103_7103; break;
case 0xCF7F41DC: rom.cicType = CIC_NUS_6105_7105; break;
case 0xD1059C6A: rom.cicType = CIC_NUS_6106_7106; break;
default:
Util::warn("Could not determine CIC TYPE! Checksum: 0x{:08X} is unknown!\n", checksum);
rom.cicType = UNKNOWN_CIC_TYPE;
break;
}
}
void Mem::LoadROM(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
file.unsetf(std::ios::skipws);
@@ -39,24 +54,46 @@ CartInfo Mem::LoadROM(const std::string& filename) {
file.seekg(0, std::ios::end);
size_t size = file.tellg();
size_t sizeAdjusted = Util::NextPow2(size);
romMask = sizeAdjusted - 1;
file.seekg(0, std::ios::beg);
file.read(reinterpret_cast<char*>(cart), size);
size_t sizeAdjusted = Util::NextPow2(size);
rom.mask = sizeAdjusted - 1;
u8* buf = (u8*)malloc(sizeAdjusted);
file.read(reinterpret_cast<char*>(buf), size);
file.close();
CartInfo result{};
u32 endianness = be32toh(*reinterpret_cast<u32*>(buf));
Util::SwapN64Rom<true>(sizeAdjusted, buf, endianness);
u32 cicChecksum;
Util::SwapN64Rom(sizeAdjusted, cart, result.crc, cicChecksum);
memcpy(mmio.rsp.dmem, cart, 0x1000);
memcpy(rom.cart, buf, sizeAdjusted);
rom.size = sizeAdjusted;
memcpy(&rom.header, buf, sizeof(ROMHeader));
memcpy(rom.gameNameCart, rom.header.imageName, sizeof(rom.header.imageName));
SetCICType(result.cicType, cicChecksum);
result.isPAL = IsROMPAL();
rom.header.clockRate = be32toh(rom.header.clockRate);
rom.header.programCounter = be32toh(rom.header.programCounter);
rom.header.release = be32toh(rom.header.release);
rom.header.crc1 = be32toh(rom.header.crc1);
rom.header.crc2 = be32toh(rom.header.crc2);
rom.header.unknown = be64toh(rom.header.unknown);
rom.header.unknown2 = be32toh(rom.header.unknown2);
rom.header.manufacturerId = be32toh(rom.header.manufacturerId);
rom.header.cartridgeId = be16toh(rom.header.cartridgeId);
return result;
rom.code[0] = rom.header.manufacturerId & 0xFF;
rom.code[1] = (rom.header.cartridgeId >> 8) & 0xFF;
rom.code[2] = rom.header.cartridgeId & 0xFF;
rom.code[3] = '\0';
for (int i = sizeof(rom.header.imageName) - 1; rom.gameNameCart[i] == ' '; i--) {
rom.gameNameCart[i] = '\0';
}
u32 checksum = Util::crc32(0, &rom.cart[0x40], 0x9c0);
SetROMCIC(checksum, rom);
endianness = be32toh(*reinterpret_cast<u32*>(rom.cart));
Util::SwapN64Rom(sizeAdjusted, rom.cart, endianness);
rom.pal = IsROMPAL();
}
u8 Mem::Read8(n64::Registers &regs, u32 paddr) {
@@ -88,7 +125,7 @@ u8 Mem::Read8(n64::Registers &regs, u32 paddr) {
}
case CART_REGION:
paddr = (paddr + 2) & ~2;
return cart[BYTE_ADDRESS(paddr) & romMask];
return rom.cart[BYTE_ADDRESS(paddr) & rom.mask];
case 0x1FC00000 ... 0x1FC007BF:
return si.pif.pifBootrom[BYTE_ADDRESS(paddr) - 0x1FC00000];
case PIF_RAM_REGION:
@@ -128,7 +165,7 @@ u16 Mem::Read16(n64::Registers &regs, u32 paddr) {
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~3;
return Util::ReadAccess<u16>(cart, HALF_ADDRESS(paddr) & romMask);
return Util::ReadAccess<u16>(rom.cart, HALF_ADDRESS(paddr) & rom.mask);
case 0x1FC00000 ... 0x1FC007BF:
return Util::ReadAccess<u16>(si.pif.pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000);
case PIF_RAM_REGION:
@@ -165,7 +202,7 @@ u32 Mem::Read32(n64::Registers &regs, u32 paddr) {
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return Util::ReadAccess<u32>(cart, paddr & romMask);
return Util::ReadAccess<u32>(rom.cart, paddr & rom.mask);
case 0x1FC00000 ... 0x1FC007BF:
return Util::ReadAccess<u32>(si.pif.pifBootrom, paddr - 0x1FC00000);
case PIF_RAM_REGION:
@@ -201,7 +238,7 @@ u64 Mem::Read64(n64::Registers &regs, u32 paddr) {
case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return Util::ReadAccess<u64>(cart, paddr & romMask);
return Util::ReadAccess<u64>(rom.cart, paddr & rom.mask);
case 0x1FC00000 ... 0x1FC007BF:
return Util::ReadAccess<u64>(si.pif.pifBootrom, paddr - 0x1FC00000);
case PIF_RAM_REGION:
@@ -274,7 +311,10 @@ void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
case 0x00800000 ... 0x03FFFFFF:
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
Util::debug("SRAM 8 bit write {:02X}\n", val);
break;
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00000 ... 0x1FC007BF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;
@@ -323,6 +363,7 @@ void Mem::Write16(Registers& regs, u32 paddr, u32 val) {
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00000 ... 0x1FC007BF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;
@@ -373,7 +414,8 @@ void Mem::Write32(Registers& regs, u32 paddr, u32 val) {
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: break;
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
}
}
@@ -414,6 +456,7 @@ void Mem::Write64(Registers& regs, u32 paddr, u64 val) {
case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF:
case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00000 ... 0x1FC007BF:
case 0x1FC00800 ... 0x7FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF:
break;

View File

@@ -7,6 +7,7 @@
#include <log.hpp>
#include <Registers.hpp>
#include <algorithm>
#include <GameDB.hpp>
namespace n64 {
struct CartInfo {
@@ -17,13 +18,41 @@ struct CartInfo {
struct JIT;
struct ROMHeader {
u8 initialValues[4];
u32 clockRate;
u32 programCounter;
u32 release;
u32 crc1;
u32 crc2;
u64 unknown;
char imageName[20];
u32 unknown2;
u32 manufacturerId;
u16 cartridgeId;
char countryCode[2];
u8 bootCode[4032];
};
struct ROM {
u8* cart;
size_t size;
size_t mask;
ROMHeader header;
CICType cicType;
char gameNameCart[20];
std::string gameNameDB;
char code[4];
bool pal;
};
struct Mem {
~Mem() {
free(sram);
}
Mem();
void Reset();
CartInfo LoadROM(const std::string&);
void LoadROM(const std::string&);
[[nodiscard]] auto GetRDRAM() const -> u8* {
return mmio.rdp.rdram;
}
@@ -73,47 +102,21 @@ struct Mem {
fclose(fp);
}
uintptr_t writePages[PAGE_COUNT], readPages[PAGE_COUNT];
ROM rom;
SaveType saveType;
private:
friend struct SI;
friend struct PI;
friend struct AI;
friend struct RSP;
friend struct Core;
u8* sram, *cart;
u8* sram;
u8 isviewer[ISVIEWER_SIZE]{};
size_t romMask = 0;
static void SetCICType(u32& cicType, u32 checksum) {
switch(checksum) {
case 0xEC8B1325: // 7102
cicType = CIC_NUS_7102;
break;
case 0x1DEB51A9: // 6101
cicType = CIC_NUS_6101;
break;
case 0xC08E5BD6:
cicType = CIC_NUS_6102_7101;
break;
case 0x03B8376A:
cicType = CIC_NUS_6103_7103;
break;
case 0xCF7F41DC:
cicType = CIC_NUS_6105_7105;
break;
case 0xD1059C6A:
cicType = CIC_NUS_6106_7106;
break;
default:
Util::warn("Could not determine CIC TYPE! Checksum: {:08X} is unknown!\n", checksum);
cicType = UNKNOWN_CIC_TYPE;
break;
}
}
bool IsROMPAL() {
static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
return std::any_of(std::begin(pal_codes), std::end(pal_codes), [this](char a) {
return cart[0x3e] == a;
return rom.cart[0x3e] == a;
});
}
};

View File

@@ -52,7 +52,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
}
rdLen = len;
for(int i = 0; i < len; i++) {
mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask] = mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE];
}
dramAddr = dram_addr + len;
cartAddr = cart_addr + len;
@@ -68,7 +68,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
}
wrLen = len;
for(int i = 0; i < len; i++) {
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.cart[BYTE_ADDRESS(cart_addr + i) & mem.romMask];
mem.mmio.rdp.rdram[BYTE_ADDRESS(dram_addr + i) & RDRAM_DSIZE] = mem.rom.cart[BYTE_ADDRESS(cart_addr + i) & mem.rom.mask];
}
dramAddr = dram_addr + len;
cartAddr = cart_addr + len;

View File

@@ -55,7 +55,22 @@ void PIF::ProcessPIFCommands(Mem& mem) {
res[2] = controller.joy_x;
res[3] = controller.joy_y;
break;
case 2: case 3: res[0] = 0; break;
case 2:
Util::print("MEMPAK READ\n");
res[0] = 0;
break;
case 3:
Util::print("MEMPAK WRITE\n");
res[0] = 0;
break;
case 4:
Util::print("EEPROM READ\n");
res[0] = 0;
break;
case 5:
Util::print("EEPROM WRITE\n");
res[0] = 0;
break;
default: Util::panic("Unimplemented PIF command {}", cmd[2]);
}
@@ -163,9 +178,7 @@ void PIF::UpdateController() {
}
}
void PIF::DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) {
u32 cicType = cartInfo.cicType;
bool pal = cartInfo.isPAL;
void PIF::DoPIFHLE(Mem& mem, Registers& regs, bool pal, CICType cicType) {
mem.Write32(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
switch(cicType) {
@@ -426,12 +439,13 @@ void PIF::DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) {
regs.gpr[22] = (cicSeeds[cicType] >> 8) & 0xFF;
regs.cop0.Reset();
mem.Write32(regs, 0x04300004, 0x01010101);
memcpy(mem.mmio.rsp.dmem, mem.rom.cart, 0x1000);
regs.SetPC32(0xA4000040);
}
void PIF::ExecutePIF(Mem& mem, Registers& regs, CartInfo cartInfo) {
u32 cicType = cartInfo.cicType;
bool pal = cartInfo.isPAL;
void PIF::ExecutePIF(Mem& mem, Registers& regs) {
CICType cicType = mem.rom.cicType;
bool pal = mem.rom.pal;
mem.Write32(regs, PIF_RAM_REGION_START + 0x24, cicSeeds[cicType]);
switch(cicType) {
case UNKNOWN_CIC_TYPE:
@@ -447,6 +461,6 @@ void PIF::ExecutePIF(Mem& mem, Registers& regs, CartInfo cartInfo) {
break;
}
DoPIFHLE(mem, regs, cartInfo);
DoPIFHLE(mem, regs, pal, cicType);
}
}

View File

@@ -44,10 +44,10 @@ constexpr u32 cicSeeds[] = {
0x0,
0x00043F3F, // CIC_NUS_6101
0x00043F3F, // CIC_NUS_7102
0x00003F3F, // CIC_NUS_6102_7101
0x0000783F, // CIC_NUS_6103_7103
0x0000913F, // CIC_NUS_6105_7105
0x0000853F, // CIC_NUS_6106_7106
0x00043F3F, // CIC_NUS_6102_7101
0x00047878, // CIC_NUS_6103_7103
0x00049191, // CIC_NUS_6105_7105
0x00048585, // CIC_NUS_6106_7106
};
enum CICType {
@@ -64,12 +64,23 @@ struct CartInfo;
struct PIF {
void ProcessPIFCommands(Mem&);
void ExecutePIF(Mem& mem, Registers& regs, CartInfo cartInfo);
void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo);
void ExecutePIF(Mem& mem, Registers& regs);
void DoPIFHLE(Mem& mem, Registers& regs, bool pal, CICType cicType);
void UpdateController();
bool gamepadConnected = false;
SDL_GameController* gamepad;
Controller controller;
u8 pifBootrom[PIF_BOOTROM_SIZE]{}, pifRam[PIF_RAM_SIZE];
u8 Read(u32 addr) {
addr &= 0x7FF;
if(addr < 0x7c0) return pifBootrom[addr];
return pifRam[addr];
}
void Write(u32 addr, u8 val) {
addr &= 0x7FF;
if(addr < 0x7c0) return;
pifRam[addr] = val;
}
};
}

View File

@@ -44,7 +44,6 @@ void DMA(Mem& mem, Registers& regs) {
for(int i = 0; i < 64; i++) {
si.pif.pifRam[i] = mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)];
}
Util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})\n", si.pifAddr, si.dramAddr);
si.pif.ProcessPIFCommands(mem);
}
InterruptRaise(mem.mmio.mi, regs, Interrupt::SI);
@@ -66,7 +65,7 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
pifAddr = val & 0x1FFFFFFF;
status.dmaBusy = true;
toDram = false;
scheduler.enqueueRelative({SI_DMA_DELAY, DMA});
scheduler.enqueueRelative({4065*3, DMA});
Util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})\n", dramAddr, pifAddr);
} break;
case 0x04800018:

View File

@@ -151,22 +151,8 @@ ImDrawData* Window::Present(n64::Core& core) {
void Window::LoadROM(n64::Core& core, const std::string &path) {
if(!path.empty()) {
n64::CartInfo cartInfo = core.LoadROM(path);
std::ifstream gameDbFile("resources/db.json");
json gameDb = json::parse(gameDbFile);
gameName = "";
for(const auto& item : gameDb["items"]) {
auto crc = item["crc"];
if(!crc.empty()) {
if(crc.get<std::string>() == fmt::format("{:08X}", cartInfo.crc)) {
auto name = item["name"];
if(!name.empty()) {
gameName = name.get<std::string>();
}
}
}
};
core.LoadROM(path);
gameName = core.cpu->mem.rom.gameNameDB;
if(gameName.empty()) {
gameName = fs::path(path).stem().string();
@@ -177,7 +163,6 @@ void Window::LoadROM(n64::Core& core, const std::string &path) {
shadowWindowTitle = windowTitle;
SDL_SetWindowTitle(window, windowTitle.c_str());
gameDbFile.close();
}
}