Mesen-X/Core/BaseMapper.h
Persune a22b17b2c1 Add /A13 and /OE1 audio interference
In hardware, the audio from the 2A03 APU pins go through an inverted
preamp using one of the 74HCU04 inverter chips in the motherboard.
Though this may be cost-effective on Nintendo's part, the signals on the
hex inverter chip can interfere with one another, especially on the
audio. This can be heard as a buzz or a high pitched whine.

The only known signals to interfere with the audio so far is:
- /A13, the inverted signal of PPU A13 going into the cartridge
   connector.
- /OE1, Output enable for controller reads, though this is only found
   present on the RF Famicom.
2021-08-11 17:55:56 +08:00

256 lines
No EOL
8.8 KiB
C++

#pragma once
#include "stdafx.h"
#include "Snapshotable.h"
#include "IMemoryHandler.h"
#include "DebuggerTypes.h"
#include "Debugger.h"
#include "Types.h"
#include "IBattery.h"
#include "RomData.h"
#include "Console.h"
#include "CPU.h"
#include "EPSMAudio.h"
#include "InvA13Audio.h"
#include "InvOE1Audio.h"
class BaseControlDevice;
class BaseMapper : public IMemoryHandler, public Snapshotable, public IBattery
{
private:
MirroringType _mirroringType;
string _batteryFilename;
uint16_t InternalGetPrgPageSize();
uint16_t InternalGetSaveRamPageSize();
uint16_t InternalGetWorkRamPageSize();
uint16_t InternalGetChrPageSize();
uint16_t InternalGetChrRamPageSize();
bool ValidateAddressRange(uint16_t startAddr, uint16_t endAddr);
uint8_t *_nametableRam = nullptr;
uint8_t _nametableCount = 2;
bool _onlyChrRam = false;
bool _hasBusConflicts = false;
bool _allowRegisterRead = false;
bool _isReadRegisterAddr[0x10000];
bool _isWriteRegisterAddr[0x10000];
MemoryAccessType _prgMemoryAccess[0x100];
uint8_t* _prgPages[0x100];
MemoryAccessType _chrMemoryAccess[0x100];
uint8_t* _chrPages[0x100];
int32_t _prgMemoryOffset[0x100];
PrgMemoryType _prgMemoryType[0x100];
int32_t _chrMemoryOffset[0x100];
ChrMemoryType _chrMemoryType[0x100];
vector<uint8_t> _originalPrgRom;
vector<uint8_t> _originalChrRom;
protected:
RomInfo _romInfo;
shared_ptr<BaseControlDevice> _mapperControlDevice;
shared_ptr<Console> _console;
uint8_t* _prgRom = nullptr;
uint8_t* _chrRom = nullptr;
uint8_t* _chrRam = nullptr;
uint32_t _prgSize = 0;
uint32_t _chrRomSize = 0;
uint32_t _chrRamSize = 0;
uint8_t* _saveRam = nullptr;
uint32_t _saveRamSize = 0;
uint32_t _workRamSize = 0;
uint8_t* _workRam = nullptr;
bool _hasChrBattery = false;
int16_t _vramOpenBusValue = -1;
virtual void InitMapper() = 0;
virtual void InitMapper(RomData &romData);
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
virtual uint32_t GetSaveRamSize() { return HasBattery() ? 0x2000 : 0; }
virtual uint32_t GetSaveRamPageSize() { return 0x2000; }
virtual bool ForceChrBattery() { return false; }
virtual bool ForceSaveRamSize() { return false; }
virtual bool ForceWorkRamSize() { return false; }
virtual uint32_t GetChrRamSize() { return 0x0000; }
//Work ram is NOT saved - aka Expansion ram, etc.
virtual uint32_t GetWorkRamSize() { return HasBattery() ? 0 : 0x2000; }
virtual uint32_t GetWorkRamPageSize() { return 0x2000; }
virtual uint16_t RegisterStartAddress() { return 0x8000; }
virtual uint16_t RegisterEndAddress() { return 0xFFFF; }
virtual bool AllowRegisterRead() { return false; }
virtual uint32_t GetDipSwitchCount() { return 0; }
virtual bool HasBusConflicts() { return false; }
uint8_t InternalReadRam(uint16_t addr);
virtual void WriteRegister(uint16_t addr, uint8_t value);
virtual void WriteEPSM(uint16_t addr, uint8_t value);
virtual uint8_t ReadRegister(uint16_t addr);
void SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
void SelectPrgPage2x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16_t pageNumber, PrgMemoryType type, int8_t accessType = -1);
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, PrgMemoryType type, uint32_t sourceOffset, int8_t accessType);
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8_t *source, int8_t accessType = -1);
void RemoveCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr);
virtual void SelectChrPage8x(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
virtual void SelectChrPage4x(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
virtual void SelectChrPage2x(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
virtual void SelectCHRPage(uint16_t slot, uint16_t page, ChrMemoryType memoryType = ChrMemoryType::Default);
void SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint16_t pageNumber, ChrMemoryType type = ChrMemoryType::Default, int8_t accessType = -1);
void SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, ChrMemoryType type, uint32_t sourceOffset, int8_t accessType);
void SetPpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, uint8_t* sourceMemory, int8_t accessType = -1);
void RemovePpuMemoryMapping(uint16_t startAddr, uint16_t endAddr);
bool HasBattery();
virtual void LoadBattery();
string GetBatteryFilename();
uint32_t GetPRGPageCount();
uint32_t GetCHRPageCount();
uint8_t GetPowerOnByte(uint8_t defaultValue = 0);
uint32_t GetDipSwitches();
void SetupDefaultWorkRam();
void InitializeChrRam(int32_t chrRamSize = -1);
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) override;
void RestorePrgChrState();
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);
void SetMirroringType(MirroringType type);
MirroringType GetMirroringType();
uint8_t InternalReadVRAM(uint16_t addr);
public:
static constexpr uint32_t NametableCount = 0x10;
static constexpr uint32_t NametableSize = 0x400;
unique_ptr<EPSMAudio> _epsmaudio;
unique_ptr<InvA13Audio> _invA13Audio;
unique_ptr<InvOE1Audio> _invOE1Audio;
void Initialize(RomData &romData);
virtual ~BaseMapper();
virtual void Reset(bool softReset);
virtual ConsoleFeatures GetAvailableFeatures();
virtual void SetNesModel(NesModel model) { }
virtual void ProcessCpuClock() { }
void ProcessMiscClock()
{
_epsmaudio->Clock();
_invA13Audio->Clock();
_invOE1Audio->Clock();
}
virtual void NotifyVRAMAddressChange(uint16_t addr);
virtual void GetMemoryRanges(MemoryRanges &ranges) override;
virtual void SaveBattery() override;
void SetConsole(shared_ptr<Console> console);
shared_ptr<BaseControlDevice> GetMapperControlDevice();
RomInfo GetRomInfo();
uint32_t GetMapperDipSwitchCount();
virtual void ApplySamples(int16_t* buffer, size_t sampleCount, double volume) {}
uint8_t ReadRAM(uint16_t addr) override;
uint8_t PeekRAM(uint16_t addr) override;
uint8_t DebugReadRAM(uint16_t addr);
void WriteRAM(uint16_t addr, uint8_t value) override;
void DebugWriteRAM(uint16_t addr, uint8_t value);
void WritePrgRam(uint16_t addr, uint8_t value);
virtual uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType operationType);
__forceinline uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead)
{
uint8_t value = MapperReadVRAM(addr, type);
_console->DebugProcessVramReadOperation(type, addr, value);
return value;
}
void DebugWriteVRAM(uint16_t addr, uint8_t value, bool disableSideEffects = true);
void WriteVRAM(uint16_t addr, uint8_t value);
uint8_t DebugReadVRAM(uint16_t addr, bool disableSideEffects = true);
void CopyChrTile(uint32_t address, uint8_t *dest);
//Debugger Helper Functions
bool HasChrRam();
bool HasChrRom();
CartridgeState GetState();
uint8_t* GetPrgRom();
uint8_t* GetWorkRam();
uint8_t* GetSaveRam();
uint8_t GetMemoryValue(DebugMemoryType memoryType, uint32_t address);
void SetMemoryValue(DebugMemoryType memoryType, uint32_t address, uint8_t value);
uint32_t GetMemorySize(DebugMemoryType type);
uint32_t CopyMemory(DebugMemoryType type, uint8_t* buffer);
void WriteMemory(DebugMemoryType type, uint8_t* buffer, int32_t length);
void GetAbsoluteAddressAndType(uint32_t relativeAddr, AddressTypeInfo *info);
void GetPpuAbsoluteAddressAndType(uint32_t relativeAddr, PpuAddressTypeInfo *info);
int32_t ToAbsoluteAddress(uint16_t addr);
int32_t ToAbsoluteSaveRamAddress(uint16_t addr);
int32_t ToAbsoluteWorkRamAddress(uint16_t addr);
int32_t ToAbsoluteChrAddress(uint16_t addr);
int32_t ToAbsoluteChrRamAddress(uint16_t addr);
int32_t ToAbsoluteChrRomAddress(uint16_t addr);
int32_t FromAbsoluteChrAddress(uint32_t addr);
int32_t FromAbsoluteAddress(uint32_t addr, AddressType type = AddressType::PrgRom);
int32_t FromAbsolutePpuAddress(uint32_t addr, PpuAddressType type);
bool IsWriteRegister(uint16_t addr);
bool IsReadRegister(uint16_t addr);
void GetRomFileData(vector<uint8_t> &out, bool asIpsFile, uint8_t* header);
vector<uint8_t> GetPrgChrCopy();
void RestorePrgChrBackup(vector<uint8_t>& backupData);
void RevertPrgChrChanges();
bool HasPrgChrChanges();
void CopyPrgChrRom(shared_ptr<BaseMapper> mapper);
};