Skip to content

Commit

Permalink
NES: Added EPSM support
Browse files Browse the repository at this point in the history
  • Loading branch information
SourMesen committed Oct 1, 2024
1 parent 029fae2 commit 7ed5fd5
Show file tree
Hide file tree
Showing 75 changed files with 8,426 additions and 6 deletions.
3 changes: 3 additions & 0 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="NES\Epsm.h" />
<ClInclude Include="NES\OpnInterface.h" />
<ClInclude Include="SMS\Input\ColecoVisionController.h" />
<ClInclude Include="Debugger\AddressInfo.h" />
<ClInclude Include="Debugger\Base6502Assembler.h" />
Expand Down Expand Up @@ -834,6 +836,7 @@
<ClCompile Include="NES\Debugger\NesAssembler.cpp" />
<ClCompile Include="NES\Debugger\NesEventManager.cpp" />
<ClCompile Include="NES\Debugger\NesTraceLogger.cpp" />
<ClCompile Include="NES\Epsm.cpp" />
<ClCompile Include="NES\HdPacks\HdAudioDevice.cpp" />
<ClCompile Include="NES\HdPacks\HdNesPack.cpp" />
<ClCompile Include="NES\HdPacks\HdNesPpu.cpp" />
Expand Down
9 changes: 9 additions & 0 deletions Core/Core.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -2922,6 +2922,12 @@
<ClInclude Include="WS\WsSerial.h">
<Filter>WS</Filter>
</ClInclude>
<ClInclude Include="NES\Epsm.h">
<Filter>NES</Filter>
</ClInclude>
<ClInclude Include="NES\OpnInterface.h">
<Filter>NES</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Shared\Video\RotateFilter.cpp">
Expand Down Expand Up @@ -3257,6 +3263,9 @@
<ClCompile Include="WS\WsEeprom.cpp">
<Filter>WS</Filter>
</ClCompile>
<ClCompile Include="NES\Epsm.cpp">
<Filter>NES</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="PCE">
Expand Down
36 changes: 36 additions & 0 deletions Core/NES/BaseMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "NES/NesTypes.h"
#include "NES/NesMemoryManager.h"
#include "NES/RomData.h"
#include "NES/Epsm.h"
#include "Debugger/DebugTypes.h"
#include "Shared/MessageManager.h"
#include "Shared/CheatManager.h"
Expand All @@ -17,6 +18,7 @@
#include "Utilities/Serializer.h"
#include "Shared/MemoryType.h"
#include "Shared/MemoryOperationType.h"
#include "Shared/FirmwareHelper.h"

void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
Expand Down Expand Up @@ -543,6 +545,10 @@ void BaseMapper::Serialize(Serializer& s)

SV(_mirroringType);

if(_epsm) {
SV(_epsm);
}

if(!s.IsSaving()) {
RestorePrgChrState();
}
Expand Down Expand Up @@ -696,6 +702,13 @@ void BaseMapper::Initialize(NesConsole* console, RomData& romData)
LoadBattery();

_romInfo.HasChrRam = HasChrRam();

if(_romInfo.HasEpsm) {
vector<uint8_t> adpcmRom;
FirmwareHelper::LoadYmf288AdpcmRom(_emu, adpcmRom);
_epsm.reset(new Epsm(_emu, _console, adpcmRom));
_hasCpuClockHook = true;
}
}

void BaseMapper::InitSpecificMapper(RomData& romData)
Expand All @@ -704,6 +717,10 @@ void BaseMapper::InitSpecificMapper(RomData& romData)
InitMapper(romData);
}

BaseMapper::BaseMapper()
{
}

BaseMapper::~BaseMapper()
{
delete[] _chrRam;
Expand Down Expand Up @@ -866,6 +883,25 @@ void BaseMapper::WritePrgRam(uint16_t addr, uint8_t value)
}
}

void BaseMapper::SetRegion(ConsoleRegion region)
{
if(_epsm) {
_epsm->OnRegionChanged();
}
}

void BaseMapper::BaseProcessCpuClock()
{
if(_epsm) {
_epsm->Exec();
}
}

void BaseMapper::ProcessCpuClock()
{
BaseProcessCpuClock();
}

void BaseMapper::NotifyVramAddressChange(uint16_t addr)
{
//This is called when the VRAM addr on the PPU memory bus changes
Expand Down
14 changes: 11 additions & 3 deletions Core/NES/BaseMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
#include "Utilities/ISerializable.h"

class NesConsole;
class Epsm;
enum class MemoryType;
struct MapperStateEntry;

class BaseMapper : public INesMemoryHandler, public ISerializable
{
private:
unique_ptr<Epsm> _epsm;

MirroringType _mirroringType = {};
string _batteryFilename;

Expand Down Expand Up @@ -157,6 +160,8 @@ class BaseMapper : public INesMemoryHandler, public ISerializable

void RestorePrgChrState();

void BaseProcessCpuClock();

uint8_t* GetNametable(uint8_t nametableIndex);
void SetNametable(uint8_t index, uint8_t nametableIndex);
void SetNametables(uint8_t nametable1Index, uint8_t nametable2Index, uint8_t nametable3Index, uint8_t nametable4Index);
Expand All @@ -181,19 +186,22 @@ class BaseMapper : public INesMemoryHandler, public ISerializable
void Initialize(NesConsole* console, RomData &romData);
void InitSpecificMapper(RomData& romData);

BaseMapper();
virtual ~BaseMapper();
virtual void Reset(bool softReset);
virtual void OnAfterResetPowerOn() {}

GameSystem GetGameSystem();
PpuModel GetPpuModel();

Epsm* GetEpsm() { return _epsm.get(); }

bool HasDefaultWorkRam();

virtual void SetRegion(ConsoleRegion region) { }
void SetRegion(ConsoleRegion region);

__forceinline bool HasCpuClockHook() { return _hasCpuClockHook; }
virtual void ProcessCpuClock() { }
virtual void ProcessCpuClock();

__forceinline bool HasVramAddressHook() { return _hasVramAddressHook; }
virtual void NotifyVramAddressChange(uint16_t addr);
Expand Down
106 changes: 106 additions & 0 deletions Core/NES/Epsm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "pch.h"
#include "NES/NesConsole.h"
#include "Shared/Emulator.h"
#include "NES/INesMemoryHandler.h"
#include "NES/Epsm.h"
#include "Utilities/Serializer.h"

Epsm::Epsm(Emulator* emu, NesConsole* console, vector<uint8_t>& adpcmRom) : _opn(console, adpcmRom)
{
_console = console;
_emu = emu;
_masterClockRate = _console->GetMasterClockRate();
_emu->GetSoundMixer()->RegisterAudioProvider(this);
}

Epsm::~Epsm()
{
_emu->GetSoundMixer()->UnregisterAudioProvider(this);
}

void Epsm::Write(uint8_t value)
{
//4016 writes
bool isHigh = (value & 0x02);
bool wasHigh = (_prevValue & 0x02);

if(isHigh && !wasHigh) {
//rising edge
_data = (value & 0xF0) | (_data & 0x0F);
_addr = ((value & 0x04) >> 1) | ((value & 0x08) >> 3);
} else if(!isHigh && wasHigh) {
//falling edge
_data = (_data & 0xF0) | ((value & 0xF0) >> 4);
_opn.Write(_addr, _data);
}

_prevValue = value;
}

void Epsm::WriteRam(uint16_t addr, uint8_t value)
{
//401C-401F writes
_opn.Write(addr, value);
}

void Epsm::OnRegionChanged()
{
uint64_t masterClockRate = _console->GetMasterClockRate();
if(_masterClockRate != masterClockRate) {
//Reset alignment between cpu & epsm clocks if the region changes (e.g pal to ntsc, etc.)
_masterClockRate = masterClockRate;
_clockCounter = GetTargetClock();
}
}

uint64_t Epsm::GetTargetClock()
{
uint64_t masterClock = _console->GetMasterClock();
double clockRatio = (double)OpnInterface::ClockRate / _masterClockRate;
return masterClock * clockRatio;
}

void Epsm::Exec()
{
constexpr int clocksPerSample = 16;

uint64_t targetClock = GetTargetClock();

while(_clockCounter < targetClock) {
_clockCounter++;
_opn.Exec();

if((_clockCounter & (clocksPerSample - 1)) == 0) {
_opn.GenerateSamples(_samples);
}
}
}

void Epsm::MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sampleRate)
{
_resampler.SetVolume(_console->GetNesConfig().EpsmVolume / 100.0);
_resampler.SetSampleRates(_opn.GetSampleRate(), sampleRate);
_resampler.Resample<true>(_samples.data(), (uint32_t)_samples.size() / 2, out, sampleCount, true);
_samples.clear();
}

void Epsm::GetMemoryRanges(MemoryRanges& ranges)
{
ranges.AddHandler(MemoryOperation::Write, 0x401C, 0x401F);
}

uint8_t Epsm::ReadRam(uint16_t addr)
{
return 0;
}

void Epsm::Serialize(Serializer& s)
{
SV(_clockCounter);
SV(_prevValue);
SV(_addr);
SV(_data);
SV(_masterClockRate);

SV(_opn);
}
46 changes: 46 additions & 0 deletions Core/NES/Epsm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once
#include "NES/OpnInterface.h"
#include "Shared/Audio/SoundMixer.h"
#include "Shared/Interfaces/IAudioProvider.h"
#include "Utilities/Audio/HermiteResampler.h"
#include "Utilities/ISerializable.h"

class Emulator;
class NesConsole;

class Epsm : public IAudioProvider, public INesMemoryHandler, public ISerializable
{
private:
Emulator* _emu = nullptr;
NesConsole* _console = nullptr;

OpnInterface _opn;

vector<int16_t> _samples;
HermiteResampler _resampler;

uint64_t _masterClockRate = 0;
uint64_t _clockCounter = 0;
uint8_t _prevValue = 0;
uint8_t _data = 0;
uint8_t _addr = 0;

uint64_t GetTargetClock();

public:
Epsm(Emulator* emu, NesConsole* console, vector<uint8_t>& adpcmRom);
~Epsm();

void Write(uint8_t value);
void WriteRam(uint16_t addr, uint8_t value) override;
void Exec();

void OnRegionChanged();

void MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sampleRate) override;

void GetMemoryRanges(MemoryRanges& ranges) override;
uint8_t ReadRam(uint16_t addr) override;

void Serialize(Serializer& s) override;
};
4 changes: 4 additions & 0 deletions Core/NES/Loaders/iNesLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void iNesLoader::LoadRom(RomData& romData, vector<uint8_t>& romFile, NesHeader *
romData.Info.SubMapperID = header.GetSubMapper();
romData.Info.Mirroring = header.GetMirroringType();
romData.Info.HasBattery = header.HasBattery();
romData.Info.HasEpsm = header.HasEpsm();
romData.Info.System = header.GetGameSystem();
romData.Info.VsType = header.GetVsSystemType();
romData.Info.VsPpuModel = header.GetVsSystemPpuModel();
Expand Down Expand Up @@ -137,6 +138,9 @@ void iNesLoader::LoadRom(RomData& romData, vector<uint8_t>& romFile, NesHeader *
if(romData.Info.HasTrainer) {
Log("[iNes] Trainer: Yes");
}
if(romData.Info.HasEpsm) {
Log("[iNes] EPSM: Yes");
}

if(!_checkOnly && !romData.Info.IsNes20Header) {
GameDatabase::SetGameInfo(romData.Info.Hash.PrgChrCrc32, romData, databaseEnabled, preloadedHeader != nullptr);
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/Bandai/BandaiFcg.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ class BandaiFcg : public BaseMapper

void ProcessCpuClock() override
{
BaseProcessCpuClock();

if(_irqEnabled) {
//Checking counter before decrementing seems to be the only way to get both
//Famicom Jump II - Saikyou no 7 Nin (J) and Magical Taruruuto-kun 2 - Mahou Daibouken (J)
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/FDS/Fds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ void Fds::ProcessAutoDiskInsert()

void Fds::ProcessCpuClock()
{
BaseProcessCpuClock();

if(_settings->FdsFastForwardOnLoad) {
_emu->GetSettings()->SetFlagState(EmulationFlags::MaximumSpeed, _scanningDisk || !_gameStarted);
} else {
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/Homebrew/UnlDripGame.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class UnlDripGame : public BaseMapper

void ProcessCpuClock() override
{
BaseProcessCpuClock();

if(_irqEnabled) {
if(_irqCounter > 0) {
_irqCounter--;
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/Irem/IremH3001.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class IremH3001 : public BaseMapper

void ProcessCpuClock() override
{
BaseProcessCpuClock();

if(_irqEnabled) {
_irqCounter--;
if(_irqCounter == 0) {
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/Jaleco/JalecoSs88006.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class JalecoSs88006 : public BaseMapper

virtual void ProcessCpuClock() override
{
BaseProcessCpuClock();

//Clock irq counter every memory read/write (each cpu cycle either reads or writes memory)
ClockIrqCounter();
}
Expand Down
2 changes: 2 additions & 0 deletions Core/NES/Mappers/JyCompany/JyCompany.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ class JyCompany : public BaseMapper

void ProcessCpuClock() override
{
BaseProcessCpuClock();

if(_irqSource == JyIrqSource::CpuClock || (_irqSource == JyIrqSource::CpuWrite && _console->GetCpu()->IsCpuWrite())) {
TickIrqCounter();
}
Expand Down
Loading

0 comments on commit 7ed5fd5

Please sign in to comment.