From d04551b0ae54c320605e25fa26682730ea439916 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sat, 11 Jun 2016 13:18:47 -0400 Subject: [PATCH] Namco 129/163/175/340 (Mapper 19 & 210) support (including audio) --- Core/BaseMapper.cpp | 35 ++- Core/BaseMapper.h | 15 +- Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/IMemoryHandler.h | 5 +- Core/MapperFactory.cpp | 4 +- Core/Namco163.h | 237 ++++++++++++++++++ Core/Namco163Audio.h | 185 ++++++++++++++ Core/Snapshotable.h | 13 + Core/SoundMixer.cpp | 1 + Core/iNesLoader.cpp | 46 +++- Core/iNesLoader.h | 1 + .../Forms/Config/frmAudioConfig.Designer.cs | 1 - 13 files changed, 532 insertions(+), 19 deletions(-) create mode 100644 Core/Namco163.h create mode 100644 Core/Namco163Audio.h diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 467dc92a..b851fdcb 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -199,7 +199,13 @@ void BaseMapper::SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memor uint16_t startAddr = slot * InternalGetChrPageSize(); uint16_t endAddr = startAddr + InternalGetChrPageSize() - 1; - SetPpuMemoryMapping(startAddr, endAddr, page, memoryType); + if(page == ChrSpecialPage::NametableA) { + SetPpuMemoryMapping(startAddr, endAddr, GetNametable(0)); + } else if(page == ChrSpecialPage::NametableB) { + SetPpuMemoryMapping(startAddr, endAddr, GetNametable(1)); + } else { + SetPpuMemoryMapping(startAddr, endAddr, page, memoryType); + } } bool BaseMapper::HasBattery() @@ -261,17 +267,27 @@ void BaseMapper::InitializeChrRam() } } -void BaseMapper::AddRegisterRange(uint16_t startAddr, uint16_t endAddr) +void BaseMapper::AddRegisterRange(uint16_t startAddr, uint16_t endAddr, MemoryOperation operation) { for(int i = startAddr; i <= endAddr; i++) { - _isRegisterAddr[i] = true; + if((int)operation & (int)MemoryOperation::Read) { + _isReadRegisterAddr[i] = true; + } + if((int)operation & (int)MemoryOperation::Write) { + _isWriteRegisterAddr[i] = true; + } } } -void BaseMapper::RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr) +void BaseMapper::RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr, MemoryOperation operation) { for(int i = startAddr; i <= endAddr; i++) { - _isRegisterAddr[i] = false; + if((int)operation & (int)MemoryOperation::Read) { + _isReadRegisterAddr[i] = false; + } + if((int)operation & (int)MemoryOperation::Write) { + _isWriteRegisterAddr[i] = false; + } } } @@ -315,8 +331,9 @@ void BaseMapper::Initialize(RomData &romData) _allowRegisterRead = AllowRegisterRead(); - memset(_isRegisterAddr, 0, sizeof(_isRegisterAddr)); - AddRegisterRange(RegisterStartAddress(), RegisterEndAddress()); + memset(_isReadRegisterAddr, 0, sizeof(_isReadRegisterAddr)); + memset(_isWriteRegisterAddr, 0, sizeof(_isWriteRegisterAddr)); + AddRegisterRange(RegisterStartAddress(), RegisterEndAddress(), MemoryOperation::Any); _mirroringType = romData.MirroringType; @@ -513,7 +530,7 @@ MirroringType BaseMapper::GetMirroringType() uint8_t BaseMapper::ReadRAM(uint16_t addr) { - if(_allowRegisterRead && _isRegisterAddr[addr]) { + if(_allowRegisterRead && _isReadRegisterAddr[addr]) { return ReadRegister(addr); } else if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) { return _prgPages[addr >> 8][addr & 0xFF]; @@ -525,7 +542,7 @@ uint8_t BaseMapper::ReadRAM(uint16_t addr) void BaseMapper::WriteRAM(uint16_t addr, uint8_t value) { - if(_isRegisterAddr[addr]) { + if(_isWriteRegisterAddr[addr]) { if(_hasBusConflicts) { value &= _prgPages[addr >> 8][addr & 0xFF]; } diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index 818b8cc5..a75e3d23 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -29,6 +29,12 @@ enum MemoryAccessType ReadWrite = 0x03 }; +enum ChrSpecialPage +{ + NametableA = 0x7000, + NametableB = 0x7001 +}; + class BaseMapper : public IMemoryHandler, public Snapshotable, public INotificationListener { private: @@ -52,7 +58,8 @@ private: string _romFilename; bool _allowRegisterRead = false; - uint8_t _isRegisterAddr[0x10000]; + uint8_t _isReadRegisterAddr[0x10000]; + uint8_t _isWriteRegisterAddr[0x10000]; vector _prgPages; vector _chrPages; @@ -67,7 +74,7 @@ private: vector _originalPrgRom; protected: - uint8_t _mapperID; + uint16_t _mapperID; uint8_t _subMapperID; uint8_t* _prgRom = nullptr; @@ -135,8 +142,8 @@ protected: void RestoreOriginalPrgRam(); void InitializeChrRam(); - void AddRegisterRange(uint16_t startAddr, uint16_t endAddr); - void RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr); + void AddRegisterRange(uint16_t startAddr, uint16_t endAddr, MemoryOperation operation = MemoryOperation::Any); + void RemoveRegisterRange(uint16_t startAddr, uint16_t endAddr, MemoryOperation operation = MemoryOperation::Any); virtual void StreamState(bool saving); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index f80b6074..b359f9bc 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -439,6 +439,8 @@ + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 9f35d72e..bc1eee58 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -598,6 +598,12 @@ Nes\Mappers\VRC + + Nes\Mappers\Namco + + + Nes\Mappers\Namco + diff --git a/Core/IMemoryHandler.h b/Core/IMemoryHandler.h index 56823625..7444a536 100644 --- a/Core/IMemoryHandler.h +++ b/Core/IMemoryHandler.h @@ -4,8 +4,9 @@ enum class MemoryOperation { - Read = 0, - Write = 1, + Read = 1, + Write = 2, + Any = 3 }; class MemoryRanges diff --git a/Core/MapperFactory.cpp b/Core/MapperFactory.cpp index 72c9785b..421ded68 100644 --- a/Core/MapperFactory.cpp +++ b/Core/MapperFactory.cpp @@ -63,6 +63,7 @@ #include "Namco108_88.h" #include "Namco108_95.h" #include "Namco108_154.h" +#include "Namco163.h" #include "Nanjing.h" #include "Nina01.h" #include "Nina03_06.h" @@ -115,7 +116,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData) case 15: return new Mapper15(); case 16: break; //18 games case 18: return new JalecoSs88006(); - case 19: break; //16 games + case 19: return new Namco163(); case 21: return new VRC2_4(VRCVariant::VRC4a); //Conflicts: VRC4c case 22: return new VRC2_4(VRCVariant::VRC2a); case 23: return new VRC2_4(VRCVariant::VRC2b); //Conflicts: VRC4e @@ -203,6 +204,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData) case 205: return new MMC3_205(); case 206: return new Namco108(); case 207: return new TaitoX1005(true); + case 210: return new Namco163(); case 225: return new Mapper225(); case 226: return new Mapper226(); case 230: return new Mapper230(); diff --git a/Core/Namco163.h b/Core/Namco163.h new file mode 100644 index 00000000..4b4a8040 --- /dev/null +++ b/Core/Namco163.h @@ -0,0 +1,237 @@ +#pragma once +#include "stdafx.h" +#include "BaseMapper.h" +#include "Namco163Audio.h" + +enum class NamcoVariant +{ + Namco163, + Namco175, + Namco340, + Unknown, +}; + +class Namco163 : public BaseMapper +{ +private: + Namco163Audio _audio; + + NamcoVariant _variant; + bool _notNamco340; + bool _autoDetectVariant; + uint8_t _writeProtect; + bool _lowChrNtMode; + bool _highChrNtMode; + uint16_t _irqCounter; + + void SetVariant(NamcoVariant variant) + { + if(_autoDetectVariant) { + if(!_notNamco340 || variant != NamcoVariant::Namco340) { + _variant = variant; + } + } + } + + void UpdateSaveRamAccess() + { + PrgMemoryType memType = HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam; + if(_variant == NamcoVariant::Namco163) { + bool globalWriteEnable = (_writeProtect & 0x40) == 0x40; + SetCpuMemoryMapping(0x6000, 0x67FF, 0, memType, globalWriteEnable && (_writeProtect & 0x01) == 0x00 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); + SetCpuMemoryMapping(0x6800, 0x6FFF, 1, memType, globalWriteEnable && (_writeProtect & 0x02) == 0x00 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); + SetCpuMemoryMapping(0x7000, 0x77FF, 2, memType, globalWriteEnable && (_writeProtect & 0x04) == 0x00 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); + SetCpuMemoryMapping(0x7800, 0x7FFF, 3, memType, globalWriteEnable && (_writeProtect & 0x08) == 0x00 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); + } else if(_variant == NamcoVariant::Namco175) { + SetCpuMemoryMapping(0x6000, 0x7FFF, 0, memType, (_writeProtect & 0x01) == 0x01 ? MemoryAccessType::ReadWrite : MemoryAccessType::Read); + } else { + SetCpuMemoryMapping(0x6000, 0x7FFF, 0, memType, MemoryAccessType::NoAccess); + } + } + +protected: + virtual uint16_t GetPRGPageSize() { return 0x2000; } + virtual uint16_t GetCHRPageSize() { return 0x400; } + virtual uint32_t GetSaveRamPageSize() { return 0x800; } + virtual bool AllowRegisterRead() { return true; } + + void InitMapper() + { + switch(_mapperID) { + case 19: _variant = NamcoVariant::Namco163; _autoDetectVariant = true; break; + case 210: + switch(_subMapperID) { + case 0: _variant = NamcoVariant::Unknown; _autoDetectVariant = true; break; + case 1: _variant = NamcoVariant::Namco175; _autoDetectVariant = false; break; + case 2: _variant = NamcoVariant::Namco340; _autoDetectVariant = false; break; + } + break; + } + + _notNamco340 = false; + + _writeProtect = 0; + _lowChrNtMode = false; + _highChrNtMode = false; + _irqCounter = 0; + + AddRegisterRange(0x4800, 0x5FFF, MemoryOperation::Any); + RemoveRegisterRange(0x6000, 0xFFFF, MemoryOperation::Read); + + SelectPRGPage(3, -1); + UpdateSaveRamAccess(); + } + + void StreamState(bool saving) + { + BaseMapper::StreamState(saving); + + SnapshotInfo audio{ &_audio }; + Stream(_variant, _notNamco340, _autoDetectVariant, _writeProtect, _lowChrNtMode, _highChrNtMode, _irqCounter, audio); + if(!saving) { + UpdateSaveRamAccess(); + } + } + + void ProcessCpuClock() + { + if(_irqCounter & 0x8000 && (_irqCounter & 0x7FFF) != 0x7FFF) { + _irqCounter++; + if((_irqCounter & 0x7FFF) == 0x7FFF) { + CPU::SetIRQSource(IRQSource::External); + } + } + + if(_variant == NamcoVariant::Namco163) { + _audio.ProcessCpuClock(); + } + } + + void WriteRAM(uint16_t addr, uint8_t value) + { + if(addr >= 0x6000 && addr <= 0x7FFF) { + _notNamco340 = true; + if(_variant == NamcoVariant::Namco340) { + SetVariant(NamcoVariant::Unknown); + } + } + BaseMapper::WriteRAM(addr, value); + } + + uint8_t ReadRegister(uint16_t addr) + { + switch(addr & 0xF800) { + case 0x4800: return _audio.ReadRegister(addr); + case 0x5000: return _irqCounter & 0xFF; + case 0x5800: return (_irqCounter >> 8); + default: return BaseMapper::ReadRegister(addr); + } + } + + void WriteRegister(uint16_t addr, uint8_t value) + { + addr &= 0xF800; + + switch(addr) { + case 0x4800: + SetVariant(NamcoVariant::Namco163); + _audio.WriteRegister(addr, value); + break; + + case 0x5000: + SetVariant(NamcoVariant::Namco163); + _irqCounter = (_irqCounter & 0xFF00) | value; + CPU::ClearIRQSource(IRQSource::External); + break; + + case 0x5800: + SetVariant(NamcoVariant::Namco163); + _irqCounter = (_irqCounter & 0x00FF) | (value << 8); + CPU::ClearIRQSource(IRQSource::External); + break; + + case 0x8000: case 0x8800: case 0x9000: case 0x9800: { + uint8_t bankNumber = (addr - 0x8000) >> 11; + if(!_lowChrNtMode && value >= 0xE0 && _variant == NamcoVariant::Namco163) { + SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + } else { + SelectCHRPage(bankNumber, value); + } + break; + } + + case 0xA000: case 0xA800: case 0xB000: case 0xB800: { + uint8_t bankNumber = ((addr - 0xA000) >> 11) + 4; + if(!_highChrNtMode && value >= 0xE0 && _variant == NamcoVariant::Namco163) { + SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + } else { + SelectCHRPage(bankNumber, value); + } + break; + } + + case 0xC000: case 0xC800: case 0xD000: case 0xD800: + if(addr >= 0xC8000) { + SetVariant(NamcoVariant::Namco163); + } else if(_variant != NamcoVariant::Namco163) { + SetVariant(NamcoVariant::Namco175); + } + + if(_variant == NamcoVariant::Namco175) { + _writeProtect = value; + UpdateSaveRamAccess(); + } else { + uint8_t bankNumber = ((addr - 0xC000) >> 11) + 8; + if(value >= 0xE0) { + SelectCHRPage(bankNumber, (value & 0x01) == 0x01 ? ChrSpecialPage::NametableB : ChrSpecialPage::NametableA); + } else { + SelectCHRPage(bankNumber, value); + } + } + break; + + case 0xE000: + if((value & 0x80) == 0x80) { + SetVariant(NamcoVariant::Namco340); + } else if((value & 0x40) == 0x40 && _variant != NamcoVariant::Namco163) { + SetVariant(NamcoVariant::Namco340); + } + + SelectPRGPage(0, value & 0x3F); + + if(_variant == NamcoVariant::Namco340) { + switch((value & 0xC0) >> 6) { + case 0: SetMirroringType(MirroringType::ScreenAOnly); break; + case 1: SetMirroringType(MirroringType::Vertical); break; + case 2: SetMirroringType(MirroringType::Horizontal); break; + case 3: SetMirroringType(MirroringType::ScreenBOnly); break; + } + } else if(_variant == NamcoVariant::Namco163) { + _audio.WriteRegister(addr, value); + } + break; + + case 0xE800: + SelectPRGPage(1, value & 0x3F); + if(_variant == NamcoVariant::Namco163) { + _lowChrNtMode = (value & 0x40) == 0x40; + _highChrNtMode = (value & 0x80) == 0x80; + } + break; + + case 0xF000: + SelectPRGPage(2, value & 0x3F); + break; + + case 0xF800: + SetVariant(NamcoVariant::Namco163); + if(_variant == NamcoVariant::Namco163) { + _writeProtect = value; + UpdateSaveRamAccess(); + + _audio.WriteRegister(addr, value); + } + break; + } + } +}; \ No newline at end of file diff --git a/Core/Namco163Audio.h b/Core/Namco163Audio.h new file mode 100644 index 00000000..be4ca0a1 --- /dev/null +++ b/Core/Namco163Audio.h @@ -0,0 +1,185 @@ +#pragma once +#include "stdafx.h" +#include "Snapshotable.h" +#include "APU.h" + +class Namco163Audio : public Snapshotable +{ +private: + uint8_t _internalRam[0x80]; + int16_t _channelOutput[8]; + uint8_t _ramPosition; + bool _autoIncrement; + uint8_t _updateCounter; + int8_t _currentChannel; + int16_t _lastOutput; + bool _disableSound; + + enum SoundReg + { + FrequencyLow = 0x00, + PhaseLow = 0x01, + FrequencyMid = 0x02, + PhaseMid = 0x03, + FrequencyHigh = 0x04, + WaveLength = 0x04, + PhaseHigh = 0x05, + WaveAddress = 0x06, + Volume = 0x07 + }; + + uint32_t GetFrequency(int channel) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + return ((_internalRam[baseAddr + SoundReg::FrequencyHigh] & 0x03) << 16) | (_internalRam[baseAddr + SoundReg::FrequencyMid] << 8) | _internalRam[baseAddr + SoundReg::FrequencyLow]; + } + + uint32_t GetPhase(int channel) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + return (_internalRam[baseAddr + SoundReg::PhaseHigh] << 16) | (_internalRam[baseAddr + SoundReg::PhaseMid] << 8) | _internalRam[baseAddr + SoundReg::PhaseLow]; + } + + void SetPhase(int channel, uint32_t phase) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + _internalRam[baseAddr + SoundReg::PhaseHigh] = (phase >> 16) & 0xFF; + _internalRam[baseAddr + SoundReg::PhaseMid] = (phase >> 8) & 0xFF; + _internalRam[baseAddr + SoundReg::PhaseLow] = phase & 0xFF; + } + + uint8_t GetWaveAddress(int channel) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + return _internalRam[baseAddr + SoundReg::WaveAddress]; + } + + uint8_t GetWaveLength(int channel) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + return 256 - (_internalRam[baseAddr + SoundReg::WaveLength] & 0xFC); + } + + uint8_t GetVolume(int channel) + { + uint8_t baseAddr = 0x40 + channel * 0x08; + return _internalRam[baseAddr + SoundReg::Volume] & 0x0F; + } + + uint8_t GetNumberOfChannels() + { + return (_internalRam[0x7F] >> 4) & 0x07; + } + + void UpdateChannel(int channel) + { + uint32_t phase = GetPhase(channel); + uint32_t freq = GetFrequency(channel); + uint8_t length = GetWaveLength(channel); + uint8_t offset = GetWaveAddress(channel); + uint8_t volume = GetVolume(channel); + + if(length == 0) { + phase = 0; + } else { + phase = (phase + freq) % (length << 16); + } + + uint8_t samplePosition = ((phase >> 16) + offset) & 0xFF; + int8_t sample; + if((samplePosition & 0x01)) { + sample = _internalRam[samplePosition / 2] >> 4; + } else { + sample = _internalRam[samplePosition / 2] & 0x0F; + } + + _channelOutput[channel] = (sample - 8) * volume; + UpdateOutputLevel(); + SetPhase(channel, phase); + } + + void UpdateOutputLevel() + { + int16_t summedOutput = 0; + for(int i = 7, min = 7 - GetNumberOfChannels(); i >= min; i--) { + summedOutput += _channelOutput[i]; + } + summedOutput /= GetNumberOfChannels(); + + APU::AddExpansionAudioDelta(AudioChannel::Namco163, summedOutput - _lastOutput); + _lastOutput = summedOutput; + } + +protected: + void StreamState(bool saving) + { + ArrayInfo internalRam{ _internalRam, 0x80 }; + ArrayInfo channelOutput{ _channelOutput, 8 }; + Stream(internalRam, channelOutput, _ramPosition, _autoIncrement, _updateCounter, _currentChannel, _lastOutput); + } + +public: + Namco163Audio() + { + memset(_internalRam, 0, sizeof(_internalRam)); + memset(_channelOutput, 0, sizeof(_channelOutput)); + _ramPosition = 0; + _autoIncrement = false; + _updateCounter = 0; + _currentChannel = 7; + _lastOutput = 0; + _disableSound = false; + } + + void ProcessCpuClock() + { + if(!_disableSound && GetNumberOfChannels()) { + _updateCounter++; + if(_updateCounter == 15) { + UpdateChannel(_currentChannel); + + _updateCounter = 0; + _currentChannel--; + if(_currentChannel < 7 - GetNumberOfChannels()) { + _currentChannel = 7; + } + } + } + } + + void WriteRegister(uint16_t addr, uint8_t value) + { + switch(addr & 0xF800) { + case 0x4800: + _internalRam[_ramPosition] = value; + if(_autoIncrement) { + _ramPosition = (_ramPosition + 1) & 0x7F; + } + break; + case 0xE000: + _disableSound = (value & 0x40) == 0x40; + break; + case 0xF800: + _ramPosition = value & 0x7F; + _autoIncrement = (value & 0x80) == 0x80; + break; + + } + } + + uint8_t ReadRegister(uint16_t addr) + { + uint8_t value = 0; + switch(addr & 0xF800) { + case 0x4800: { + value = _internalRam[_ramPosition]; + if(_autoIncrement) { + _ramPosition = (_ramPosition + 1) & 0x7F; + } + break; + } + } + + return value; + } +}; \ No newline at end of file diff --git a/Core/Snapshotable.h b/Core/Snapshotable.h index 8abcff6e..2a282bc2 100644 --- a/Core/Snapshotable.h +++ b/Core/Snapshotable.h @@ -2,6 +2,8 @@ #include "stdafx.h" +class Snapshotable; + template struct ArrayInfo { @@ -16,6 +18,11 @@ struct ValueInfo T DefaultValue; }; +struct SnapshotInfo +{ + Snapshotable* Entity; +}; + template struct EmptyInfo { @@ -103,6 +110,12 @@ private: StreamElement(value); } + template<> + void InternalStream(SnapshotInfo &info) + { + Stream(info.Entity); + } + void RecursiveStream() { } diff --git a/Core/SoundMixer.cpp b/Core/SoundMixer.cpp index ea916781..7a90ab1b 100644 --- a/Core/SoundMixer.cpp +++ b/Core/SoundMixer.cpp @@ -152,6 +152,7 @@ int16_t SoundMixer::GetOutputVolume() switch(_expansionAudioType) { case AudioChannel::FDS: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break; case AudioChannel::VRC6: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 75); break; + case AudioChannel::Namco163: expansionOutput = (int16_t)(_currentOutput[ExpansionAudioIndex] * _volumes[ExpansionAudioIndex] * 20); break; } return squareVolume + tndVolume + expansionOutput; } diff --git a/Core/iNesLoader.cpp b/Core/iNesLoader.cpp index 3d82ba56..a5012552 100644 --- a/Core/iNesLoader.cpp +++ b/Core/iNesLoader.cpp @@ -3,6 +3,24 @@ #include "../Utilities/CRC32.h" #include "MessageManager.h" +std::unordered_map iNesLoader::_mapperByCrc = { + //Namco 175 games that are marked as mapper 19 but should be 210, submapper 1 + { 0x0C47946D, 210 }, //Chibi Maruko-chan: Uki Uki Shopping + { 0x808606F0, 210 }, //Famista 91' + { 0x81B7F1A8, 210 }, //Heisei Tensai Bakabon + { 0x46FD7843, 210 }, //Splatterhouse: Wanpaku Graffiti + { 0x1DC0F740, 210 }, //Wagyan Land 2 + + //Namco 340 games that are marked as mapper 19 but should be 210, submapper 2 + { 0xBD523011, 210 }, //Dream Master + { 0xC247CC80, 210 }, //Family Circuit '91 + { 0x6EC51DE5, 210 }, //Famista '92 + { 0xADFFD64F, 210 }, //Famista '93 + { 0x429103C9, 210 }, //Famista '94 + { 0x2447E03B, 210 }, //Top Striker + { 0xD323B806, 210 }, //Wagnyan Land 3 +}; + std::unordered_map iNesLoader::_submapperByCrc = { //MC-ACC Games (MMC3 variant) - Mapper 4, SubMapper 3 { 0xC527C297, 3 }, //Alien 3 @@ -27,6 +45,22 @@ std::unordered_map iNesLoader::_submapperByCrc = { //CAMERICA-BF9097 - Mapper 71, SubMapper 1 { 0x1BC686A8, 1 }, //Fire Hawk + + //Namco 175 games that are marked as mapper 19 but should be 210, submapper 1 + { 0x0C47946D, 1 }, //Chibi Maruko-chan: Uki Uki Shopping + { 0x808606F0, 1 }, //Famista 91' + { 0x81B7F1A8, 1 }, //Heisei Tensai Bakabon + { 0x46FD7843, 1 }, //Splatterhouse: Wanpaku Graffiti + { 0x1DC0F740, 1 }, //Wagyan Land 2 + + //Namco 340 games that are marked as mapper 19 but should be 210, submapper 2 + { 0xBD523011, 2 }, //Dream Master + { 0xC247CC80, 2 }, //Family Circuit '91 + { 0x6EC51DE5, 2 }, //Famista '92 + { 0xADFFD64F, 2 }, //Famista '93 + { 0x429103C9, 2 }, //Famista '94 + { 0x2447E03B, 2 }, //Top Striker + { 0xD323B806, 2 }, //Wagnyan Land 3 }; RomData iNesLoader::LoadRom(vector& romFile) @@ -58,11 +92,19 @@ RomData iNesLoader::LoadRom(vector& romFile) if(header.GetRomHeaderVersion() != RomHeaderVersion::Nes2_0) { //Check rom CRC to set submapper as needed uint32_t romCrc = CRC32::GetCRC(buffer, header.GetPrgSize() + header.GetChrSize()); - auto crcCheckResult = _submapperByCrc.find(romCrc); + auto crcCheckResult = _mapperByCrc.find(romCrc); + if(crcCheckResult != _mapperByCrc.end()) { + romData.MapperID = crcCheckResult->second; + #ifdef _DEBUG + MessageManager::DisplayMessage("GameInfo", "Mapper number corrected."); + #endif + } + + crcCheckResult = _submapperByCrc.find(romCrc); if(crcCheckResult != _submapperByCrc.end()) { romData.SubMapperID = crcCheckResult->second; #ifdef _DEBUG - MessageManager::DisplayMessage("GameInfo", "Header information corrected."); + MessageManager::DisplayMessage("GameInfo", "Submapper number corrected."); #endif } } diff --git a/Core/iNesLoader.h b/Core/iNesLoader.h index 9261393e..a2766482 100644 --- a/Core/iNesLoader.h +++ b/Core/iNesLoader.h @@ -6,6 +6,7 @@ class iNesLoader { private: + static std::unordered_map _mapperByCrc; static std::unordered_map _submapperByCrc; public: diff --git a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs index 24bb3263..134767bf 100644 --- a/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs +++ b/GUI.NET/Forms/Config/frmAudioConfig.Designer.cs @@ -298,7 +298,6 @@ // trkNamco163Vol // this.trkNamco163Vol.Anchor = System.Windows.Forms.AnchorStyles.Top; - this.trkNamco163Vol.Enabled = false; this.trkNamco163Vol.Location = new System.Drawing.Point(306, 160); this.trkNamco163Vol.Margin = new System.Windows.Forms.Padding(0); this.trkNamco163Vol.Maximum = 100;