Work/Save ram general improvements.

-Added support for work ram size field in NES 2.0
-Updated DB to list both work ram & save ram sizes
-Fixed MMC1/MMC3 implementation (and implemented the wram/sram protection bits)
Holy Diver tests now all pass (except a minor IRQ timing issue for FME7)
This commit is contained in:
Souryo 2016-07-26 19:19:28 -04:00
parent dffe4cb26e
commit 062d22ae80
10 changed files with 3248 additions and 3082 deletions

View File

@ -49,7 +49,7 @@ void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16
break;
case PrgMemoryType::WorkRam:
source = _workRam;
pageCount = GetWorkRamSize() / GetWorkRamPageSize();
pageCount = _workRamSize / GetWorkRamPageSize();
pageSize = GetWorkRamPageSize();
defaultAccessType |= MemoryAccessType::Write;
break;
@ -57,6 +57,13 @@ void BaseMapper::SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16
throw new std::runtime_error("Invalid parameter");
}
if(pageCount == 0) {
#ifdef _DEBUG
MessageManager::DisplayMessage("Debug", "Tried to map undefined save/work ram.");
#endif
return;
}
if(pageNumber < 0) {
//Can't use modulo for negative number because pageCount is sometimes not a power of 2. (Fixes some Mapper 191 games)
pageNumber = pageCount + pageNumber;
@ -247,12 +254,14 @@ void BaseMapper::LoadBattery()
void BaseMapper::SaveBattery()
{
ofstream batteryFile(_batteryFilename, ios::out | ios::binary);
if(HasBattery()) {
ofstream batteryFile(_batteryFilename, ios::out | ios::binary);
if(batteryFile) {
batteryFile.write((char*)_saveRam, _saveRamSize);
if(batteryFile) {
batteryFile.write((char*)_saveRam, _saveRamSize);
batteryFile.close();
batteryFile.close();
}
}
}
@ -318,7 +327,7 @@ void BaseMapper::RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr, Memor
void BaseMapper::StreamState(bool saving)
{
ArrayInfo<uint8_t> chrRam = { _chrRam, _chrRamSize };
ArrayInfo<uint8_t> workRam = { _workRam, GetWorkRamSize() };
ArrayInfo<uint8_t> workRam = { _workRam, _workRamSize };
ArrayInfo<uint8_t> saveRam = { _saveRam, _saveRamSize };
ArrayInfo<uint32_t> prgPageNumbers = { _prgPageNumbers, 64 };
ArrayInfo<uint32_t> chrPageNumbers = { _chrPageNumbers, 64 };
@ -349,10 +358,23 @@ void BaseMapper::Initialize(RomData &romData)
_mapperID = romData.MapperID;
_subMapperID = romData.SubMapperID;
_databaseInfo = romData.DatabaseInfo;
_romName = romData.RomName;
_romFilename = romData.Filename;
_batteryFilename = GetBatteryFilename();
_saveRamSize = GetSaveRamSize(); //Needed because we need to call SaveBattery() in the destructor (and calling virtual functions in the destructor doesn't work correctly)
if(romData.SaveRamSize == -1) {
_saveRamSize = GetSaveRamSize(); //Needed because we need to call SaveBattery() in the destructor (and calling virtual functions in the destructor doesn't work correctly)
} else {
_saveRamSize = romData.SaveRamSize;
}
if(romData.WorkRamSize == -1) {
_workRamSize = GetWorkRamSize();
} else {
_workRamSize = romData.WorkRamSize;
}
_allowRegisterRead = AllowRegisterRead();
@ -382,11 +404,11 @@ void BaseMapper::Initialize(RomData &romData)
_hasBusConflicts = HasBusConflicts();
_saveRam = new uint8_t[_saveRamSize];
_workRam = new uint8_t[GetWorkRamSize()];
_workRam = new uint8_t[_workRamSize];
memset(_saveRam, 0, _saveRamSize);
memset(_workRam, 0, GetWorkRamSize());
if(romData.HasTrainer && GetWorkRamSize() >= 0x2000) {
memset(_workRam, 0, _workRamSize);
if(romData.HasTrainer && _workRamSize >= 0x2000) {
memcpy(_workRam + 0x1000, romData.TrainerData.data(), 512);
}
@ -424,7 +446,11 @@ void BaseMapper::Initialize(RomData &romData)
}
//Setup a default work/save ram in 0x6000-0x7FFF space
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam);
if(HasBattery() && _saveRamSize > 0) {
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, PrgMemoryType::SaveRam);
} else if(_workRamSize > 0) {
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, PrgMemoryType::WorkRam);
}
InitMapper();
InitMapper(romData);
@ -436,9 +462,8 @@ void BaseMapper::Initialize(RomData &romData)
BaseMapper::~BaseMapper()
{
if(HasBattery()) {
SaveBattery();
}
SaveBattery();
delete[] _chrRam;
delete[] _chrRom;
delete[] _prgRom;
@ -623,6 +648,11 @@ void BaseMapper::NotifyVRAMAddressChange(uint16_t addr)
//Used by MMC3/MMC5/etc
}
bool BaseMapper::IsNes20()
{
return _nesHeader.GetRomHeaderVersion() == RomHeaderVersion::Nes2_0;
}
//Debugger Helper Functions
uint8_t* BaseMapper::GetPrgRom()
{
@ -642,7 +672,7 @@ void BaseMapper::GetPrgCopy(uint8_t **buffer)
uint32_t BaseMapper::GetPrgSize(bool getWorkRamSize)
{
return getWorkRamSize ? GetWorkRamSize() : _prgSize;
return getWorkRamSize ? _workRamSize : _prgSize;
}
void BaseMapper::GetChrRomCopy(uint8_t **buffer)
@ -674,7 +704,7 @@ int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
int32_t BaseMapper::ToAbsoluteRamAddress(uint16_t addr)
{
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF);
if(prgRamAddr >= _workRam && prgRamAddr < _workRam + GetWorkRamSize()) {
if(prgRamAddr >= _workRam && prgRamAddr < _workRam + _workRamSize) {
return (uint32_t)(prgRamAddr - _workRam);
}
return -1;

View File

@ -77,6 +77,8 @@ private:
protected:
NESHeader _nesHeader;
GameInfo _databaseInfo;
uint16_t _mapperID;
uint8_t _subMapperID;
GameSystem _gameSystem;
@ -90,6 +92,7 @@ protected:
uint8_t* _saveRam = nullptr;
uint32_t _saveRamSize = 0;
uint32_t _workRamSize = 0;
uint8_t* _workRam = nullptr;
bool _hasBattery = false;
@ -98,6 +101,8 @@ protected:
virtual uint16_t GetPRGPageSize() = 0;
virtual uint16_t GetCHRPageSize() = 0;
bool IsNes20();
virtual uint16_t GetChrRamPageSize() { return 0x2000; }
//Save ram is battery backed and saved to disk
@ -139,7 +144,6 @@ protected:
bool HasBattery();
void LoadBattery();
void SaveBattery();
string GetBatteryFilename();
uint32_t GetPRGPageCount();
@ -163,6 +167,7 @@ protected:
public:
void Initialize(RomData &romData);
virtual ~BaseMapper();
virtual void Reset(bool softReset);
@ -173,6 +178,7 @@ public:
virtual void GetMemoryRanges(MemoryRanges &ranges);
void ApplyCheats();
void SaveBattery();
virtual void SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB);

View File

@ -42,6 +42,11 @@ void Console::Initialize(string romFilename, stringstream *filestream, string ip
{
SoundMixer::StopAudio();
if(_mapper) {
//Ensure we save any battery file before loading a new game
_mapper->SaveBattery();
}
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFilename, filestream, ipsFilename, archiveFileIndex);

View File

@ -39,7 +39,7 @@ void GameDatabase::InitDatabase()
continue;
}
vector<string> values = split(lineContent, ',');
if(values.size() >= 12) {
if(values.size() >= 13) {
GameInfo gameInfo{
(uint32_t)std::stoll(values[0], nullptr, 16),
values[1],
@ -51,9 +51,10 @@ void GameDatabase::InitDatabase()
ToInt<uint32_t>(values[7]),
ToInt<uint32_t>(values[8]),
ToInt<uint32_t>(values[9]),
ToInt<uint32_t>(values[10]) == 0 ? false : true,
values[11],
values.size() > 12 ? values[12] : ""
ToInt<uint32_t>(values[10]),
ToInt<uint32_t>(values[11]) == 0 ? false : true,
values[12],
values.size() > 13 ? values[13] : ""
};
_gameDatabase[gameInfo.Crc] = gameInfo;
}
@ -126,6 +127,15 @@ void GameDatabase::InitializeInputDevices(string inputType, GameSystem system)
uint8_t GameDatabase::GetSubMapper(GameInfo &info)
{
switch(info.MapperID) {
case 1:
if(info.Board.find("SEROM") != string::npos ||
info.Board.find("SHROM") != string::npos ||
info.Board.find("SH1ROM") != string::npos) {
//SEROM, SHROM, SH1ROM have fixed PRG banking
return 5;
}
break;
case 3:
if(info.Board.compare("NES-CNROM") == 0) {
//Enable bus conflicts for CNROM games
@ -136,6 +146,8 @@ uint8_t GameDatabase::GetSubMapper(GameInfo &info)
case 4:
if(info.Board.compare("ACCLAIM-MC-ACC") == 0) {
return 3; //Acclaim MC-ACC (MMC3 clone)
} else if(info.Chip.compare("MMC6B") == 0) {
return 1; //MMC6 (Star Tropics)
}
break;
@ -192,30 +204,24 @@ uint8_t GameDatabase::GetSubMapper(GameInfo &info)
return 0;
}
void GameDatabase::UpdateRomData(uint32_t romCrc, RomData &romData)
void GameDatabase::SetGameInfo(uint32_t romCrc, RomData &romData, bool updateRomData)
{
GameInfo info = {};
InitDatabase();
auto result = _gameDatabase.find(romCrc);
if(result != _gameDatabase.end()) {
MessageManager::Log("[DB] Game found in database");
GameInfo info = result->second;
info = result->second;
romData.MapperID = info.MapperID;
romData.System = GetGameSystem(info.System);
romData.SubMapperID = GetSubMapper(info);
if(info.ChrRamSize > 0) {
romData.ChrRamSize = info.ChrRamSize * 1024;
}
romData.HasBattery |= info.HasBattery;
if(!info.Mirroring.empty()) {
romData.MirroringType = info.Mirroring.compare("h") == 0 ? MirroringType::Horizontal : MirroringType::Vertical;
}
MessageManager::Log("[DB] Mapper: " + std::to_string(romData.MapperID) + " Sub: " + std::to_string(romData.SubMapperID));
MessageManager::Log("[DB] Mapper: " + std::to_string(info.MapperID) + " Sub: " + std::to_string(GetSubMapper(info)));
MessageManager::Log("[DB] System : " + info.System);
MessageManager::Log("[DB] Board: " + info.Board);
MessageManager::Log("[DB] Chip: " + info.Chip);
if(!info.Mirroring.empty()) {
MessageManager::Log("[DB] Mirroring: " + string(info.Mirroring.compare("h") == 0 ? "Horizontal" : "Vertical"));
}
@ -224,19 +230,51 @@ void GameDatabase::UpdateRomData(uint32_t romCrc, RomData &romData)
if(info.ChrRamSize > 0) {
MessageManager::Log("[DB] CHR RAM: " + std::to_string(info.ChrRamSize) + " KB");
}
if(info.WorkRamSize > 0) {
MessageManager::Log("[DB] Work RAM: " + std::to_string(info.WorkRamSize) + " KB");
}
if(info.SaveRamSize > 0) {
MessageManager::Log("[DB] Save RAM: " + std::to_string(info.SaveRamSize) + " KB");
}
MessageManager::Log("[DB] Battery: " + string(info.HasBattery ? "Yes" : "No"));
if(EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
InitializeInputDevices(info.InputType, romData.System);
if(updateRomData) {
MessageManager::Log("[DB] Database info will be used instead of file header.");
UpdateRomData(info, romData);
}
#ifdef _DEBUG
#ifdef _DEBUG
MessageManager::DisplayMessage("DB", "Mapper: " + std::to_string(romData.MapperID) + " Sub: " + std::to_string(romData.SubMapperID) + " System: " + info.System);
#endif
#endif
} else {
MessageManager::Log("[DB] Game not found in database");
if(EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
InitializeInputDevices("", romData.System);
}
}
if(EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
InitializeInputDevices(info.InputType, romData.System);
}
romData.DatabaseInfo = info;
}
void GameDatabase::UpdateRomData(GameInfo &info, RomData &romData)
{
romData.MapperID = info.MapperID;
romData.System = GetGameSystem(info.System);
romData.SubMapperID = GetSubMapper(info);
if(info.ChrRamSize > 0) {
romData.ChrRamSize = info.ChrRamSize * 1024;
}
if(info.WorkRamSize > 0) {
romData.WorkRamSize = info.WorkRamSize * 1024;
}
if(info.SaveRamSize > 0) {
romData.SaveRamSize = info.SaveRamSize * 1024;
}
romData.HasBattery |= info.HasBattery;
if(!info.Mirroring.empty()) {
romData.MirroringType = info.Mirroring.compare("h") == 0 ? MirroringType::Horizontal : MirroringType::Vertical;
}
}

View File

@ -1,23 +1,7 @@
#pragma once
#include "stdafx.h"
#include <unordered_map>
struct GameInfo
{
uint32_t Crc;
string System;
string Board;
string Pcb;
string Chip;
uint8_t MapperID;
uint32_t PrgRomSize;
uint32_t ChrRomSize;
uint32_t ChrRamSize;
uint32_t WorkRamSize;
bool HasBattery;
string Mirroring;
string InputType;
};
#include "RomData.h"
class GameDatabase
{
@ -32,7 +16,8 @@ private:
static void InitializeInputDevices(string inputType, GameSystem system);
static void InitDatabase();
static void UpdateRomData(GameInfo &info, RomData &romData);
public:
static void UpdateRomData(uint32_t romCrc, RomData &romData);
static void SetGameInfo(uint32_t romCrc, RomData &romData, bool updateRomData);
};

View File

@ -46,6 +46,9 @@ class MMC1 : public BaseMapper
int32_t _lastWriteCycle = -1;
bool _forceWramOn;
MMC1Registers _lastChrReg;
private:
bool HasResetFlag(uint8_t value)
{
@ -107,24 +110,48 @@ class MMC1 : public BaseMapper
_chrReg1 = _state.RegC000 & 0x1F;
_prgReg = _state.RegE000 & 0x0F;
uint8_t extraReg = _lastChrReg == MMC1Registers::RegC000 && _chrMode == ChrMode::_4k ? _chrReg1 : _chrReg0;
uint8_t prgBankSelect = 0;
if(_prgSize == 0x80000) {
//512kb carts use bit 7 of $A000/$C000 to select page
//This is used for SUROM (Dragon Warrior 3/4, Dragon Quest 4)
prgBankSelect = extraReg & 0x10;
}
if(_wramDisable && !_forceWramOn) {
RemoveCpuMemoryMapping(0x6000, 0x7FFF);
} else {
if(_saveRamSize + _workRamSize > 0x4000) {
//SXROM, 32kb of save ram
SetCpuMemoryMapping(0x6000, 0x7FFF, (extraReg >> 2) & 0x03, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam);
} else if(_saveRamSize + _workRamSize > 0x2000) {
if(_saveRamSize == 0x2000 && _workRamSize == 0x2000) {
//SOROM, half of the 16kb ram is battery backed
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, (extraReg >> 3) & 0x01 ? PrgMemoryType::WorkRam : PrgMemoryType::SaveRam);
} else {
//Unknown, shouldn't happen
SetCpuMemoryMapping(0x6000, 0x7FFF, (extraReg >> 2) & 0x01, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam);
}
} else {
//Everything else - 8kb of work or save ram
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam);
}
}
if(_subMapperID == 5) {
//SubMapper 5
//"001: 5 Fixed PRG SEROM, SHROM, SH1ROM use a fixed 32k PRG ROM with no banking support.
SelectPrgPage2x(0, 0);
} else {
//This is used for SUROM (Dragon Warrior 3/4, Dragon Quest 4)
uint8_t prgPageAdjust = (_state.RegA000 & 0x10);
if(_prgMode == PrgMode::_32k) {
SelectPRGPage(0, _prgReg + prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust + 1);
SelectPrgPage2x(0, (_prgReg & 0xFE) | prgBankSelect);
} else if(_prgMode == PrgMode::_16k) {
if(_slotSelect == SlotSelect::x8000) {
SelectPRGPage(0, _prgReg + prgPageAdjust);
SelectPRGPage(1, 0xF + prgPageAdjust);
SelectPRGPage(0, _prgReg | prgBankSelect);
SelectPRGPage(1, 0x0F | prgBankSelect);
} else if(_slotSelect == SlotSelect::xC000) {
SelectPRGPage(0, prgPageAdjust);
SelectPRGPage(1, _prgReg + prgPageAdjust);
SelectPRGPage(0, 0 | prgBankSelect);
SelectPRGPage(1, _prgReg | prgBankSelect);
}
}
}
@ -141,7 +168,10 @@ class MMC1 : public BaseMapper
void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream(_state.Reg8000, _state.RegA000, _state.RegC000, _state.RegE000, _writeBuffer, _shiftCount, _lastWriteCycle);
Stream(_state.Reg8000, _state.RegA000, _state.RegC000, _state.RegE000, _writeBuffer, _shiftCount, _lastWriteCycle, _lastChrReg);
if(!saving) {
UpdateState();
}
}
virtual uint16_t GetPRGPageSize() { return 0x4000; }
@ -149,12 +179,15 @@ class MMC1 : public BaseMapper
void InitMapper()
{
_state.Reg8000 = 0x0C; //On powerup: bits 2,3 of $8000 are set
_state.Reg8000 = 0x0C; //On powerup: bits 2,3 of $8000 are set (this ensures the $8000 is bank 0, and $C000 is the last bank - needed for SEROM/SHROM/SH1ROM which do no support banking)
_state.RegA000 = 0x00;
_state.RegC000 = 0x00;
_state.RegE000 = 0x10; //WRAM Disable: assume it's enabled at startup
_state.RegE000 = (_databaseInfo.Board.find("MMC1B") != string::npos ? 0x10 : 0x00); //WRAM Disable: enabled by default for MMC1B
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam);
//"MMC1A: PRG RAM is always enabled" - Normally these roms should be classified as mapper 155
_forceWramOn = (_databaseInfo.Board.compare("MMC1A") == 0);
_lastChrReg = MMC1Registers::RegA000;
UpdateState();
}
@ -168,8 +201,16 @@ class MMC1 : public BaseMapper
if(IsBufferFull(value)) {
switch((MMC1Registers)((addr & 0x6000) >> 13)) {
case MMC1Registers::Reg8000: _state.Reg8000 = _writeBuffer; break;
case MMC1Registers::RegA000: _state.RegA000 = _writeBuffer; break;
case MMC1Registers::RegC000: _state.RegC000 = _writeBuffer; break;
case MMC1Registers::RegA000:
_lastChrReg = MMC1Registers::RegA000;
_state.RegA000 = _writeBuffer;
break;
case MMC1Registers::RegC000:
_lastChrReg = MMC1Registers::RegC000;
_state.RegC000 = _writeBuffer;
break;
case MMC1Registers::RegE000: _state.RegE000 = _writeBuffer; break;
}

View File

@ -145,8 +145,29 @@ class MMC3 : public BaseMapper
UpdateMirroring();
_wramEnabled = (_state.RegA001 & 0x80) == 0x80;
_wramWriteProtected = (_state.RegA001 & 0x40) == 0x40;
if(_subMapperID == 1) {
bool wramEnabled = (_state.Reg8000 & 0x20) == 0x20;
RemoveCpuMemoryMapping(0x6000, 0x7000);
uint8_t firstBankAccess = (_state.RegA001 & 0x10 ? MemoryAccessType::Write : 0) | (_state.RegA001 & 0x20 ? MemoryAccessType::Read : 0);
uint8_t lastBankAccess = (_state.RegA001 & 0x40 ? MemoryAccessType::Write : 0) | (_state.RegA001 & 0x80 ? MemoryAccessType::Read : 0);
for(int i = 0; i < 4; i++) {
SetCpuMemoryMapping(0x7000 + i * 0x400, 0x71FF + i * 0x400, 0, PrgMemoryType::SaveRam, firstBankAccess);
SetCpuMemoryMapping(0x7200 + i * 0x400, 0x73FF + i * 0x400, 1, PrgMemoryType::SaveRam, lastBankAccess);
}
} else {
_wramEnabled = (_state.RegA001 & 0x80) == 0x80;
_wramWriteProtected = (_state.RegA001 & 0x40) == 0x40;
if(IsNes20() && _subMapperID == 0) {
if(_wramEnabled) {
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam, CanWriteToWorkRam() ? MemoryAccessType::ReadWrite : MemoryAccessType::Read);
} else {
RemoveCpuMemoryMapping(0x6000, 0x7FFF);
}
}
}
UpdatePrgMapping();
UpdateChrMapping();
@ -163,6 +184,8 @@ class MMC3 : public BaseMapper
virtual uint16_t GetPRGPageSize() { return 0x2000; }
virtual uint16_t GetCHRPageSize() { return 0x0400; }
virtual uint32_t GetSaveRamPageSize() { return _subMapperID == 1 ? 0x200 : 0x2000; }
virtual uint32_t GetSaveRamSize() { return _subMapperID == 1 ? 0x400 : 0x2000; }
virtual void InitMapper()
{

View File

@ -146,14 +146,22 @@ struct NESHeader
uint32_t GetWorkRamSize()
{
uint8_t value = Byte10 & 0x0F;
return value == 0 ? 0 : 128 * (uint32_t)std::pow(2, value);
if(GetRomHeaderVersion() == RomHeaderVersion::Nes2_0) {
uint8_t value = Byte10 & 0x0F;
return value == 0 ? 0 : 128 * (uint32_t)std::pow(2, value);
} else {
return -1;
}
}
uint32_t GetSaveRamSize()
{
uint8_t value = (Byte10 & 0xF0) >> 4;
return value == 0 ? 0 : 128 * (uint32_t)std::pow(2, value);
if(GetRomHeaderVersion() == RomHeaderVersion::Nes2_0) {
uint8_t value = (Byte10 & 0xF0) >> 4;
return value == 0 ? 0 : 128 * (uint32_t)std::pow(2, value);
} else {
return -1;
}
}
int32_t GetChrRamSize()
@ -232,6 +240,25 @@ struct NsfHeader
int32_t TrackFade[256];
};
struct GameInfo
{
uint32_t Crc;
string System;
string Board;
string Pcb;
string Chip;
uint8_t MapperID;
uint32_t PrgRomSize;
uint32_t ChrRomSize;
uint32_t ChrRamSize;
uint32_t WorkRamSize;
uint32_t SaveRamSize;
bool HasBattery;
string Mirroring;
string InputType;
bool Valid;
};
struct RomData
{
string RomName;
@ -243,7 +270,10 @@ struct RomData
bool HasBattery = false;
bool HasTrainer = false;
MirroringType MirroringType = MirroringType::Horizontal;
int32_t ChrRamSize = -1;
int32_t SaveRamSize = -1;
int32_t WorkRamSize = -1;
bool IsNes20Header = false;
@ -260,4 +290,5 @@ struct RomData
NESHeader NesHeader;
NsfHeader NsfHeader;
GameInfo DatabaseInfo;
};

View File

@ -29,6 +29,8 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& romFile)
}
romData.HasTrainer = header.HasTrainer();
romData.ChrRamSize = header.GetChrRamSize();
romData.WorkRamSize = header.GetWorkRamSize();
romData.SaveRamSize = header.GetSaveRamSize();
romData.NesHeader = header;
if(romData.HasTrainer) {
@ -54,20 +56,25 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& romFile)
MessageManager::Log("[iNes] Mapper: " + std::to_string(romData.MapperID) + " Sub:" + std::to_string(romData.SubMapperID));
MessageManager::Log("[iNes] PRG ROM: " + std::to_string(romData.PrgRom.size()/1024) + " KB");
MessageManager::Log("[iNes] CHR ROM: " + std::to_string(romData.ChrRom.size()/1024) + " KB");
if(romData.ChrRamSize > 0) {
MessageManager::Log("[iNes] CHR RAM: " + std::to_string(romData.ChrRamSize) + " KB");
if(romData.ChrRamSize > 0 || romData.IsNes20Header) {
MessageManager::Log("[iNes] CHR RAM: " + std::to_string(romData.ChrRamSize / 1024) + " KB");
} else if(romData.ChrRom.size() == 0) {
MessageManager::Log("[iNes] CHR RAM: 8 KB");
}
if(romData.WorkRamSize > 0 || romData.IsNes20Header) {
MessageManager::Log("[iNes] Work RAM: " + std::to_string(romData.WorkRamSize / 1024) + " KB");
}
if(romData.SaveRamSize > 0 || romData.IsNes20Header) {
MessageManager::Log("[iNes] Save RAM: " + std::to_string(romData.SaveRamSize / 1024) + " KB");
}
MessageManager::Log("[iNes] Mirroring: " + string(romData.MirroringType == MirroringType::Horizontal ? "Horizontal" : romData.MirroringType == MirroringType::Vertical ? "Vertical" : "Four Screens"));
MessageManager::Log("[iNes] Battery: " + string(romData.HasBattery ? "Yes" : "No"));
if(romData.HasTrainer) {
MessageManager::Log("[iNes] Trainer: Yes");
}
if(!EmulationSettings::CheckFlag(EmulationFlags::DisableGameDatabase) && header.GetRomHeaderVersion() != RomHeaderVersion::Nes2_0) {
GameDatabase::UpdateRomData(romCrc, romData);
}
GameDatabase::SetGameInfo(romCrc, romData, !EmulationSettings::CheckFlag(EmulationFlags::DisableGameDatabase) && header.GetRomHeaderVersion() != RomHeaderVersion::Nes2_0);
return romData;
}

File diff suppressed because it is too large Load Diff