mirror of
https://github.com/SourMesen/Mesen.git
synced 2025-04-02 10:52:48 -04:00
Namco 129/163/175/340 (Mapper 19 & 210) support (including audio)
This commit is contained in:
parent
76600d31a9
commit
d04551b0ae
13 changed files with 532 additions and 19 deletions
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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<uint8_t*> _prgPages;
|
||||
vector<uint8_t*> _chrPages;
|
||||
|
@ -67,7 +74,7 @@ private:
|
|||
vector<uint8_t> _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);
|
||||
|
||||
|
|
|
@ -439,6 +439,8 @@
|
|||
<ClInclude Include="MMC3_52.h" />
|
||||
<ClInclude Include="MMC3_ChrRam.h" />
|
||||
<ClInclude Include="ModChannel.h" />
|
||||
<ClInclude Include="Namco163.h" />
|
||||
<ClInclude Include="Namco163Audio.h" />
|
||||
<ClInclude Include="PlayerListMessage.h" />
|
||||
<ClInclude Include="ReverbFilter.h" />
|
||||
<ClInclude Include="RomData.h" />
|
||||
|
|
|
@ -598,6 +598,12 @@
|
|||
<ClInclude Include="Vrc6Saw.h">
|
||||
<Filter>Nes\Mappers\VRC</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco163.h">
|
||||
<Filter>Nes\Mappers\Namco</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco163Audio.h">
|
||||
<Filter>Nes\Mappers\Namco</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
enum class MemoryOperation
|
||||
{
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
Any = 3
|
||||
};
|
||||
|
||||
class MemoryRanges
|
||||
|
|
|
@ -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();
|
||||
|
|
237
Core/Namco163.h
Normal file
237
Core/Namco163.h
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
};
|
185
Core/Namco163Audio.h
Normal file
185
Core/Namco163Audio.h
Normal file
|
@ -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<uint8_t> internalRam{ _internalRam, 0x80 };
|
||||
ArrayInfo<int16_t> 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;
|
||||
}
|
||||
};
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
|
||||
class Snapshotable;
|
||||
|
||||
template<typename T>
|
||||
struct ArrayInfo
|
||||
{
|
||||
|
@ -16,6 +18,11 @@ struct ValueInfo
|
|||
T DefaultValue;
|
||||
};
|
||||
|
||||
struct SnapshotInfo
|
||||
{
|
||||
Snapshotable* Entity;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct EmptyInfo
|
||||
{
|
||||
|
@ -103,6 +110,12 @@ private:
|
|||
StreamElement<T>(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
void InternalStream(SnapshotInfo &info)
|
||||
{
|
||||
Stream(info.Entity);
|
||||
}
|
||||
|
||||
void RecursiveStream()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,24 @@
|
|||
#include "../Utilities/CRC32.h"
|
||||
#include "MessageManager.h"
|
||||
|
||||
std::unordered_map<uint32_t, uint8_t> 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<uint32_t, uint8_t> iNesLoader::_submapperByCrc = {
|
||||
//MC-ACC Games (MMC3 variant) - Mapper 4, SubMapper 3
|
||||
{ 0xC527C297, 3 }, //Alien 3
|
||||
|
@ -27,6 +45,22 @@ std::unordered_map<uint32_t, uint8_t> 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<uint8_t>& romFile)
|
||||
|
@ -58,11 +92,19 @@ RomData iNesLoader::LoadRom(vector<uint8_t>& 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
class iNesLoader
|
||||
{
|
||||
private:
|
||||
static std::unordered_map<uint32_t, uint8_t> _mapperByCrc;
|
||||
static std::unordered_map<uint32_t, uint8_t> _submapperByCrc;
|
||||
|
||||
public:
|
||||
|
|
1
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
1
GUI.NET/Forms/Config/frmAudioConfig.Designer.cs
generated
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue