mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-23 09:09:45 +00:00
Optimizations: Most games now run 15-20% faster
This commit is contained in:
parent
56ee77b73b
commit
bf979be756
@ -21,8 +21,8 @@ APU::APU(MemoryManager* memoryManager)
|
||||
|
||||
_mixer.reset(new SoundMixer());
|
||||
|
||||
_squareChannel.push_back(unique_ptr<SquareChannel>(new SquareChannel(AudioChannel::Square1, _mixer.get(), true)));
|
||||
_squareChannel.push_back(unique_ptr<SquareChannel>(new SquareChannel(AudioChannel::Square2, _mixer.get(), false)));
|
||||
_squareChannel[0].reset(new SquareChannel(AudioChannel::Square1, _mixer.get(), true));
|
||||
_squareChannel[1].reset(new SquareChannel(AudioChannel::Square2, _mixer.get(), false));
|
||||
_triangleChannel.reset(new TriangleChannel(AudioChannel::Triangle, _mixer.get()));
|
||||
_noiseChannel.reset(new NoiseChannel(AudioChannel::Noise, _mixer.get()));
|
||||
_deltaModulationChannel.reset(new DeltaModulationChannel(AudioChannel::DMC, _mixer.get(), _memoryManager));
|
||||
|
@ -24,7 +24,7 @@ class APU : public Snapshotable, public IMemoryHandler
|
||||
uint32_t _previousCycle;
|
||||
uint32_t _currentCycle;
|
||||
|
||||
vector<unique_ptr<SquareChannel>> _squareChannel;
|
||||
unique_ptr<SquareChannel> _squareChannel[2];
|
||||
unique_ptr<TriangleChannel> _triangleChannel;
|
||||
unique_ptr<NoiseChannel> _noiseChannel;
|
||||
unique_ptr<DeltaModulationChannel> _deltaModulationChannel;
|
||||
|
@ -14,14 +14,14 @@ enum class FrameType
|
||||
class ApuFrameCounter : public IMemoryHandler, public Snapshotable
|
||||
{
|
||||
private:
|
||||
const vector<vector<int32_t>> _stepCyclesNtsc = { { { 7457, 14913, 22371, 29828, 29829, 29830},
|
||||
{ 7457, 14913, 22371, 29829, 37281, 37282} } };
|
||||
const vector<vector<int32_t>> _stepCyclesPal = { { { 8313, 16627, 24939, 33252, 33253, 33254},
|
||||
{ 8313, 16627, 24939, 33253, 41565, 41566} } };
|
||||
const vector<vector<FrameType>> _frameType = { { { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None },
|
||||
{ FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None } } };
|
||||
const int32_t _stepCyclesNtsc[2][6] = { { 7457, 14913, 22371, 29828, 29829, 29830},
|
||||
{ 7457, 14913, 22371, 29829, 37281, 37282} };
|
||||
const int32_t _stepCyclesPal[2][6] = { { 8313, 16627, 24939, 33252, 33253, 33254},
|
||||
{ 8313, 16627, 24939, 33253, 41565, 41566} };
|
||||
const FrameType _frameType[2][6] = { { FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None },
|
||||
{ FrameType::QuarterFrame, FrameType::HalfFrame, FrameType::QuarterFrame, FrameType::None, FrameType::HalfFrame, FrameType::None } };
|
||||
|
||||
vector<vector<int32_t>> _stepCycles;
|
||||
int32_t _stepCycles[2][6];
|
||||
NesModel _nesModel;
|
||||
int32_t _nextIrqCycle;
|
||||
int32_t _previousCycle;
|
||||
@ -76,19 +76,16 @@ public:
|
||||
|
||||
void SetNesModel(NesModel model)
|
||||
{
|
||||
if(_nesModel != model || _stepCycles.size() == 0) {
|
||||
if(_nesModel != model) {
|
||||
_nesModel = model;
|
||||
_stepCycles.clear();
|
||||
switch(model) {
|
||||
case NesModel::NTSC:
|
||||
case NesModel::Dendy:
|
||||
_stepCycles.push_back(_stepCyclesNtsc[0]);
|
||||
_stepCycles.push_back(_stepCyclesNtsc[1]);
|
||||
memcpy(_stepCycles, _stepCyclesNtsc, sizeof(_stepCycles));
|
||||
break;
|
||||
|
||||
case NesModel::PAL:
|
||||
_stepCycles.push_back(_stepCyclesPal[0]);
|
||||
_stepCycles.push_back(_stepCyclesPal[1]);
|
||||
memcpy(_stepCycles, _stepCyclesPal, sizeof(_stepCycles));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
class ApuLengthCounter : public BaseApuChannel
|
||||
{
|
||||
private:
|
||||
const vector<uint8_t> _lcLookupTable = { { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 } };
|
||||
uint8_t _lcLookupTable[32] = { 10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, 12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30 };
|
||||
bool _enabled = false;
|
||||
bool _newHaltValue;
|
||||
static bool _needToRun;
|
||||
@ -43,7 +43,9 @@ public:
|
||||
|
||||
static bool NeedToRun()
|
||||
{
|
||||
return ApuLengthCounter::_needToRun;
|
||||
bool needToRun = ApuLengthCounter::_needToRun;
|
||||
ApuLengthCounter::_needToRun = false;
|
||||
return needToRun;
|
||||
}
|
||||
|
||||
virtual void Reset(bool softReset) override
|
||||
@ -83,14 +85,7 @@ public:
|
||||
{
|
||||
return _lengthCounter > 0;
|
||||
}
|
||||
|
||||
virtual void Run(uint32_t targetCycle) override
|
||||
{
|
||||
ApuLengthCounter::_needToRun = false;
|
||||
_lengthCounterHalt = _newHaltValue;
|
||||
BaseApuChannel::Run(targetCycle);
|
||||
}
|
||||
|
||||
|
||||
void ReloadCounter()
|
||||
{
|
||||
if(_lengthCounterReloadValue) {
|
||||
@ -99,6 +94,8 @@ public:
|
||||
}
|
||||
_lengthCounterReloadValue = 0;
|
||||
}
|
||||
|
||||
_lengthCounterHalt = _newHaltValue;
|
||||
}
|
||||
|
||||
void TickLengthCounter()
|
||||
|
@ -71,26 +71,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void Run(uint32_t targetCycle)
|
||||
void Run(uint32_t targetCycle)
|
||||
{
|
||||
while(_previousCycle < targetCycle) {
|
||||
if(_timer == 0) {
|
||||
Clock();
|
||||
_timer = _period;
|
||||
_previousCycle++;
|
||||
} else {
|
||||
uint32_t cyclesToRun = targetCycle - _previousCycle;
|
||||
uint16_t skipCount = _timer > cyclesToRun ? cyclesToRun : _timer;
|
||||
_timer -= skipCount;
|
||||
_previousCycle += skipCount;
|
||||
|
||||
if(cyclesToRun == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32_t cyclesToRun = targetCycle - _previousCycle;
|
||||
while(cyclesToRun > _timer) {
|
||||
cyclesToRun -= _timer + 1;
|
||||
_previousCycle += _timer + 1;
|
||||
Clock();
|
||||
_timer = _period;
|
||||
}
|
||||
|
||||
_timer -= cyclesToRun;
|
||||
_previousCycle = targetCycle;
|
||||
}
|
||||
|
||||
|
||||
uint8_t ReadRAM(uint16_t addr) override
|
||||
{
|
||||
return 0;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "CheatManager.h"
|
||||
#include "Debugger.h"
|
||||
#include "MemoryDumper.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
void BaseMapper::WriteRegister(uint16_t addr, uint8_t value) { }
|
||||
uint8_t BaseMapper::ReadRegister(uint16_t addr) { return 0; }
|
||||
@ -243,7 +243,7 @@ void BaseMapper::RemovePpuMemoryMapping(uint16_t startAddr, uint16_t endAddr)
|
||||
|
||||
uint8_t BaseMapper::InternalReadRam(uint16_t addr)
|
||||
{
|
||||
return _prgPages[addr >> 8] ? _prgPages[addr >> 8][addr & 0xFF] : 0;
|
||||
return _prgPages[addr >> 8] ? _prgPages[addr >> 8][(uint8_t)addr] : 0;
|
||||
}
|
||||
|
||||
void BaseMapper::SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType)
|
||||
@ -546,10 +546,10 @@ void BaseMapper::Initialize(RomData &romData)
|
||||
|
||||
for(int i = 0; i <= 0xFF; i++) {
|
||||
//Allow us to map a different page every 256 bytes
|
||||
_prgPages.push_back(nullptr);
|
||||
_prgPageAccessType.push_back(MemoryAccessType::NoAccess);
|
||||
_chrPages.push_back(nullptr);
|
||||
_chrPageAccessType.push_back(MemoryAccessType::NoAccess);
|
||||
_prgPages[i] = nullptr;
|
||||
_prgPageAccessType[i] = MemoryAccessType::NoAccess;
|
||||
_chrPages[i] = nullptr;
|
||||
_chrPageAccessType[i] = MemoryAccessType::NoAccess;
|
||||
}
|
||||
|
||||
if(_chrRomSize == 0) {
|
||||
@ -728,18 +728,18 @@ uint8_t BaseMapper::ReadRAM(uint16_t addr)
|
||||
if(_allowRegisterRead && _isReadRegisterAddr[addr]) {
|
||||
return ReadRegister(addr);
|
||||
} else if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Read) {
|
||||
return _prgPages[addr >> 8][addr & 0xFF];
|
||||
return _prgPages[addr >> 8][(uint8_t)addr];
|
||||
} else {
|
||||
//assert(false);
|
||||
}
|
||||
return (addr & 0xFF00) >> 8;
|
||||
return MemoryManager::GetOpenBus();
|
||||
}
|
||||
|
||||
void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_isWriteRegisterAddr[addr]) {
|
||||
if(_hasBusConflicts) {
|
||||
value &= _prgPages[addr >> 8][addr & 0xFF];
|
||||
value &= _prgPages[addr >> 8][(uint8_t)addr];
|
||||
}
|
||||
WriteRegister(addr, value);
|
||||
} else {
|
||||
@ -750,34 +750,17 @@ void BaseMapper::WriteRAM(uint16_t addr, uint8_t value)
|
||||
void BaseMapper::WritePrgRam(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_prgPageAccessType[addr >> 8] & MemoryAccessType::Write) {
|
||||
_prgPages[addr >> 8][addr & 0xFF] = value;
|
||||
_prgPages[addr >> 8][(uint8_t)addr] = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::InternalReadVRAM(uint16_t addr)
|
||||
void BaseMapper::ProcessVramAccess(uint16_t &addr)
|
||||
{
|
||||
if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Read) {
|
||||
return _chrPages[addr >> 8][addr & 0xFF];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BaseMapper::InternalWriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_chrPages[addr >> 8]) {
|
||||
_chrPages[addr >> 8][addr & 0xFF] = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::ReadVRAM(uint16_t addr, MemoryOperationType operationType)
|
||||
{
|
||||
return InternalReadVRAM(addr);
|
||||
}
|
||||
|
||||
void BaseMapper::WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) {
|
||||
_chrPages[addr >> 8][addr & 0xFF] = value;
|
||||
addr &= 0x3FFF;
|
||||
if(addr >= 0x3000) {
|
||||
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
|
||||
//Required for proper MMC3 IRQ timing in Burai Fighter
|
||||
addr -= 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,6 +770,43 @@ void BaseMapper::NotifyVRAMAddressChange(uint16_t addr)
|
||||
//Used by MMC3/MMC5/etc
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::InternalReadVRAM(uint16_t addr)
|
||||
{
|
||||
if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Read) {
|
||||
return _chrPages[addr >> 8][(uint8_t)addr];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::DebugReadVRAM(uint16_t addr)
|
||||
{
|
||||
ProcessVramAccess(addr);
|
||||
return InternalReadVRAM(addr);
|
||||
}
|
||||
|
||||
uint8_t BaseMapper::MapperReadVRAM(uint16_t addr, MemoryOperationType operationType)
|
||||
{
|
||||
return InternalReadVRAM(addr);
|
||||
}
|
||||
|
||||
void BaseMapper::InternalWriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(_chrPages[addr >> 8]) {
|
||||
_chrPages[addr >> 8][(uint8_t)addr] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseMapper::WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
ProcessVramAccess(addr);
|
||||
Debugger::ProcessVramOperation(MemoryOperationType::Write, addr, value);
|
||||
NotifyVRAMAddressChange(addr);
|
||||
|
||||
if(_chrPageAccessType[addr >> 8] & MemoryAccessType::Write) {
|
||||
_chrPages[addr >> 8][(uint8_t)addr] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseMapper::IsNes20()
|
||||
{
|
||||
return _nesHeader.GetRomHeaderVersion() == RomHeaderVersion::Nes2_0;
|
||||
@ -869,7 +889,7 @@ void BaseMapper::SetMemoryValue(DebugMemoryType memoryType, uint32_t address, ui
|
||||
|
||||
int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
|
||||
{
|
||||
uint8_t *prgAddr = _prgPages[addr >> 8] + (addr & 0xFF);
|
||||
uint8_t *prgAddr = _prgPages[addr >> 8] + (uint8_t)addr;
|
||||
if(prgAddr >= _prgRom && prgAddr < _prgRom + _prgSize) {
|
||||
return (uint32_t)(prgAddr - _prgRom);
|
||||
}
|
||||
@ -878,7 +898,7 @@ int32_t BaseMapper::ToAbsoluteAddress(uint16_t addr)
|
||||
|
||||
int32_t BaseMapper::ToAbsoluteWorkRamAddress(uint16_t addr)
|
||||
{
|
||||
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF);
|
||||
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (uint8_t)addr;
|
||||
if(prgRamAddr >= _workRam && prgRamAddr < _workRam + _workRamSize) {
|
||||
return (uint32_t)(prgRamAddr - _workRam);
|
||||
}
|
||||
@ -887,7 +907,7 @@ int32_t BaseMapper::ToAbsoluteWorkRamAddress(uint16_t addr)
|
||||
|
||||
int32_t BaseMapper::ToAbsoluteSaveRamAddress(uint16_t addr)
|
||||
{
|
||||
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (addr & 0xFF);
|
||||
uint8_t *prgRamAddr = _prgPages[addr >> 8] + (uint8_t)addr;
|
||||
if(prgRamAddr >= _saveRam && prgRamAddr < _saveRam + _saveRamSize) {
|
||||
return (uint32_t)(prgRamAddr - _saveRam);
|
||||
}
|
||||
@ -896,7 +916,7 @@ int32_t BaseMapper::ToAbsoluteSaveRamAddress(uint16_t addr)
|
||||
|
||||
int32_t BaseMapper::ToAbsoluteChrAddress(uint16_t addr)
|
||||
{
|
||||
uint8_t *chrAddr = _chrPages[addr >> 8] + (addr & 0xFF);
|
||||
uint8_t *chrAddr = _chrPages[addr >> 8] + (uint8_t)addr;
|
||||
if(chrAddr >= _chrRom && chrAddr < _chrRom + _chrRomSize) {
|
||||
return (uint32_t)(chrAddr - _chrRom);
|
||||
}
|
||||
|
@ -7,52 +7,8 @@
|
||||
#include "RomLoader.h"
|
||||
#include "EmulationSettings.h"
|
||||
#include "DebuggerTypes.h"
|
||||
|
||||
enum class DebugMemoryType;
|
||||
|
||||
enum class PrgMemoryType
|
||||
{
|
||||
PrgRom,
|
||||
SaveRam,
|
||||
WorkRam,
|
||||
};
|
||||
|
||||
enum class ChrMemoryType
|
||||
{
|
||||
Default,
|
||||
ChrRom,
|
||||
ChrRam
|
||||
};
|
||||
|
||||
enum MemoryAccessType
|
||||
{
|
||||
Unspecified = -1,
|
||||
NoAccess = 0x00,
|
||||
Read = 0x01,
|
||||
Write = 0x02,
|
||||
ReadWrite = 0x03
|
||||
};
|
||||
|
||||
enum ChrSpecialPage
|
||||
{
|
||||
NametableA = 0x7000,
|
||||
NametableB = 0x7001
|
||||
};
|
||||
|
||||
struct CartridgeState
|
||||
{
|
||||
uint32_t PrgRomSize;
|
||||
uint32_t ChrRomSize;
|
||||
uint32_t ChrRamSize;
|
||||
|
||||
uint32_t PrgPageCount;
|
||||
uint32_t PrgPageSize;
|
||||
uint32_t PrgSelectedPages[64];
|
||||
uint32_t ChrPageCount;
|
||||
uint32_t ChrPageSize;
|
||||
uint32_t ChrSelectedPages[64];
|
||||
uint32_t Nametables[8];
|
||||
};
|
||||
#include "Debugger.h"
|
||||
#include "Types.h"
|
||||
|
||||
class BaseMapper : public IMemoryHandler, public Snapshotable, public INotificationListener
|
||||
{
|
||||
@ -81,10 +37,10 @@ private:
|
||||
uint8_t _isReadRegisterAddr[0x10000];
|
||||
uint8_t _isWriteRegisterAddr[0x10000];
|
||||
|
||||
vector<uint8_t*> _prgPages;
|
||||
vector<uint8_t*> _chrPages;
|
||||
vector<uint8_t> _prgPageAccessType;
|
||||
vector<uint8_t> _chrPageAccessType;
|
||||
uint8_t* _prgPages[0x100];
|
||||
uint8_t* _chrPages[0x100];
|
||||
uint8_t _prgPageAccessType[0x100];
|
||||
uint8_t _chrPageAccessType[0x100];
|
||||
|
||||
uint32_t _prgPageNumbers[64];
|
||||
uint32_t _chrPageNumbers[64];
|
||||
@ -213,15 +169,29 @@ public:
|
||||
string GetRomName();
|
||||
RomFormat GetRomFormat();
|
||||
|
||||
uint8_t ReadRAM(uint16_t addr) override;
|
||||
__forceinline uint8_t ReadRAM(uint16_t addr) override;
|
||||
virtual void WriteRAM(uint16_t addr, uint8_t value) override;
|
||||
void WritePrgRam(uint16_t addr, uint8_t value);
|
||||
|
||||
uint8_t InternalReadVRAM(uint16_t addr);
|
||||
virtual uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type = MemoryOperationType::Read);
|
||||
__forceinline uint8_t InternalReadVRAM(uint16_t addr);
|
||||
__forceinline virtual uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType operationType);
|
||||
|
||||
__forceinline uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type = MemoryOperationType::PpuRenderingRead)
|
||||
{
|
||||
ProcessVramAccess(addr);
|
||||
NotifyVRAMAddressChange(addr);
|
||||
|
||||
uint8_t value = MapperReadVRAM(addr, type);
|
||||
Debugger::ProcessVramOperation(type, addr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void InternalWriteVRAM(uint16_t addr, uint8_t value);
|
||||
void WriteVRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
__forceinline void ProcessVramAccess(uint16_t &addr);
|
||||
uint8_t DebugReadVRAM(uint16_t addr);
|
||||
|
||||
static void InitializeRam(void* data, uint32_t length);
|
||||
|
||||
//Debugger Helper Functions
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "Snapshotable.h"
|
||||
#include "TraceLogger.h"
|
||||
#include "EmulationSettings.h"
|
||||
#include "CpuState.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace PSFlags
|
||||
{
|
||||
|
@ -64,12 +64,12 @@ void Console::Initialize(string romFilename, stringstream *filestream, string ip
|
||||
_memoryManager.reset(new MemoryManager(_mapper));
|
||||
_cpu.reset(new CPU(_memoryManager.get()));
|
||||
if(HdNesPack::HasHdPack(_romFilepath)) {
|
||||
_ppu.reset(new HdPpu(_memoryManager.get()));
|
||||
_ppu.reset(new HdPpu(_mapper.get()));
|
||||
} else if(NsfMapper::GetInstance()) {
|
||||
//Disable most of the PPU for NSFs
|
||||
_ppu.reset(new NsfPpu(_memoryManager.get()));
|
||||
_ppu.reset(new NsfPpu(_mapper.get()));
|
||||
} else {
|
||||
_ppu.reset(new PPU(_memoryManager.get()));
|
||||
_ppu.reset(new PPU(_mapper.get()));
|
||||
}
|
||||
_apu.reset(new APU(_memoryManager.get()));
|
||||
|
||||
|
@ -442,7 +442,6 @@
|
||||
<ClInclude Include="Cc21.h" />
|
||||
<ClInclude Include="CodeRunner.h" />
|
||||
<ClInclude Include="ColorDreams46.h" />
|
||||
<ClInclude Include="CpuState.h" />
|
||||
<ClInclude Include="CrossFeedFilter.h" />
|
||||
<ClInclude Include="DaouInfosys.h" />
|
||||
<ClInclude Include="DebugBreakHelper.h" />
|
||||
@ -452,7 +451,6 @@
|
||||
<ClInclude Include="MagicKidGooGoo.h" />
|
||||
<ClInclude Include="MemoryAccessCounter.h" />
|
||||
<ClInclude Include="MemoryDumper.h" />
|
||||
<ClInclude Include="DebugState.h" />
|
||||
<ClInclude Include="DefaultVideoFilter.h" />
|
||||
<ClInclude Include="DreamTech01.h" />
|
||||
<ClInclude Include="Edu2000.h" />
|
||||
@ -591,7 +589,6 @@
|
||||
<ClInclude Include="OekaKids.h" />
|
||||
<ClInclude Include="OekaKidsTablet.h" />
|
||||
<ClInclude Include="PlayerListMessage.h" />
|
||||
<ClInclude Include="PpuState.h" />
|
||||
<ClInclude Include="Profiler.h" />
|
||||
<ClInclude Include="Racermate.h" />
|
||||
<ClInclude Include="ReverbFilter.h" />
|
||||
@ -715,6 +712,7 @@
|
||||
<ClInclude Include="Txc22211B.h" />
|
||||
<ClInclude Include="Txc22211C.h" />
|
||||
<ClInclude Include="TxSRom.h" />
|
||||
<ClInclude Include="Types.h" />
|
||||
<ClInclude Include="UnifBoards.h" />
|
||||
<ClInclude Include="UnifLoader.h" />
|
||||
<ClInclude Include="Unl43272.h" />
|
||||
|
@ -277,9 +277,6 @@
|
||||
<ClInclude Include="TraceLogger.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DebugState.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SoundMixer.h">
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
@ -1117,18 +1114,15 @@
|
||||
<ClInclude Include="Eh8813A.h">
|
||||
<Filter>Nes\Mappers\Unif</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PpuState.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpuState.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Assembler.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CodeRunner.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Types.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
struct State
|
||||
{
|
||||
uint16_t PC = 0;
|
||||
uint8_t SP = 0;
|
||||
uint8_t A = 0;
|
||||
uint8_t X = 0;
|
||||
uint8_t Y = 0;
|
||||
uint8_t PS = 0;
|
||||
uint32_t IRQFlag = 0;
|
||||
int32_t CycleCount = 0;
|
||||
bool NMIFlag = false;
|
||||
|
||||
//Used by debugger
|
||||
uint16_t DebugPC = 0;
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "CPU.h"
|
||||
#include "PPU.h"
|
||||
#include "BaseMapper.h"
|
||||
|
||||
struct DebugState
|
||||
{
|
||||
State CPU;
|
||||
PPUDebugState PPU;
|
||||
CartridgeState Cartridge;
|
||||
};
|
@ -8,7 +8,6 @@ using std::atomic;
|
||||
using std::deque;
|
||||
using std::unordered_set;
|
||||
|
||||
#include "DebugState.h"
|
||||
#include "Breakpoint.h"
|
||||
#include "TraceLogger.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
@ -26,6 +25,7 @@ class MemoryDumper;
|
||||
class MemoryAccessCounter;
|
||||
class Profiler;
|
||||
class CodeRunner;
|
||||
class BaseMapper;
|
||||
|
||||
class Debugger
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Types.h"
|
||||
|
||||
enum class DebuggerFlags
|
||||
{
|
||||
@ -47,4 +48,21 @@ enum class CdlHighlightType
|
||||
None = 0,
|
||||
HighlightUsed = 1,
|
||||
HighlightUnused = 2,
|
||||
};
|
||||
|
||||
struct PPUDebugState
|
||||
{
|
||||
PPUControlFlags ControlFlags;
|
||||
PPUStatusFlags StatusFlags;
|
||||
PPUState State;
|
||||
int32_t Scanline;
|
||||
uint32_t Cycle;
|
||||
uint32_t FrameCount;
|
||||
};
|
||||
|
||||
struct DebugState
|
||||
{
|
||||
State CPU;
|
||||
PPUDebugState PPU;
|
||||
CartridgeState Cartridge;
|
||||
};
|
@ -8,8 +8,8 @@ class MemoryManager;
|
||||
class DeltaModulationChannel : public BaseApuChannel
|
||||
{
|
||||
private:
|
||||
const vector<uint16_t> _dmcPeriodLookupTableNtsc = { { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 } };
|
||||
const vector<uint16_t> _dmcPeriodLookupTablePal = { { 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50 } };
|
||||
const uint16_t _dmcPeriodLookupTableNtsc[16] = { 428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54 };
|
||||
const uint16_t _dmcPeriodLookupTablePal[16] = { 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50 };
|
||||
static DeltaModulationChannel *Instance;
|
||||
|
||||
MemoryManager *_memoryManager = nullptr;
|
||||
|
@ -29,6 +29,7 @@ PpuModel EmulationSettings::_ppuModel = PpuModel::Ppu2C02;
|
||||
uint32_t EmulationSettings::_emulationSpeed = 100;
|
||||
uint32_t EmulationSettings::_turboSpeed = 300;
|
||||
|
||||
bool EmulationSettings::_hasOverclock = false;
|
||||
uint32_t EmulationSettings::_overclockRate = 100;
|
||||
uint32_t EmulationSettings::_extraScanlinesBeforeNmi = 0;
|
||||
uint32_t EmulationSettings::_extraScanlinesAfterNmi = 0;
|
||||
|
@ -339,6 +339,7 @@ private:
|
||||
static uint32_t _emulationSpeed;
|
||||
static uint32_t _turboSpeed;
|
||||
|
||||
static bool _hasOverclock;
|
||||
static uint32_t _overclockRate;
|
||||
static bool _overclockAdjustApu;
|
||||
static bool _disableOverclocking;
|
||||
@ -589,6 +590,7 @@ public:
|
||||
_effectiveOverclockRateSound = _overclockRate * (double)(1 + (double)(_extraScanlinesBeforeNmi + _extraScanlinesAfterNmi) / _ppuScanlineCount);
|
||||
_effectiveOverclockRate = _overclockRate;
|
||||
}
|
||||
_hasOverclock = _effectiveOverclockRate != 100;
|
||||
}
|
||||
|
||||
static void SetPpuScanlineCount(uint32_t scanlineCount)
|
||||
@ -608,6 +610,11 @@ public:
|
||||
return _overclockRate;
|
||||
}
|
||||
|
||||
static bool HasOverclock()
|
||||
{
|
||||
return _hasOverclock;
|
||||
}
|
||||
|
||||
static double GetOverclockRate(bool forApu = false, bool forSoundMixer = false)
|
||||
{
|
||||
if(forApu && _overclockAdjustApu || forSoundMixer) {
|
||||
|
15
Core/HdPpu.h
15
Core/HdPpu.h
@ -18,17 +18,12 @@ protected:
|
||||
_lastSprite = nullptr;
|
||||
|
||||
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
||||
uint32_t paletteOffset;
|
||||
uint32_t color = GetPixelColor(paletteOffset);
|
||||
if(color == 0) {
|
||||
pixel = ReadPaletteRAM(0) | _intensifyColorBits;
|
||||
} else {
|
||||
pixel = ReadPaletteRAM(paletteOffset + color) | _intensifyColorBits;
|
||||
}
|
||||
uint32_t color = GetPixelColor();
|
||||
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
|
||||
|
||||
HdPpuPixelInfo &tileInfo = _screenTiles[bufferOffset];
|
||||
if(_lastSprite && _flags.SpritesEnabled) {
|
||||
tileInfo.Sprite.TileIndex = _memoryManager->ToAbsoluteChrAddress(_lastSprite->TileAddr) / 16;
|
||||
tileInfo.Sprite.TileIndex = _mapper->ToAbsoluteChrAddress(_lastSprite->TileAddr) / 16;
|
||||
tileInfo.Sprite.PaletteColors = ReadPaletteRAM(_lastSprite->PaletteOffset + 1) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 2) << 8) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 3) << 16);
|
||||
tileInfo.Sprite.OffsetY = _lastSprite->OffsetY;
|
||||
|
||||
@ -55,7 +50,7 @@ protected:
|
||||
|
||||
if(_flags.BackgroundEnabled) {
|
||||
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
|
||||
tileInfo.Tile.TileIndex = _memoryManager->ToAbsoluteChrAddress(lastTile->TileAddr) / 16;
|
||||
tileInfo.Tile.TileIndex = _mapper->ToAbsoluteChrAddress(lastTile->TileAddr) / 16;
|
||||
tileInfo.Tile.PaletteColors = ReadPaletteRAM(lastTile->PaletteOffset + 1) | (ReadPaletteRAM(lastTile->PaletteOffset + 2) << 8) | (ReadPaletteRAM(lastTile->PaletteOffset + 3) << 16);
|
||||
tileInfo.Tile.OffsetY = lastTile->OffsetY;
|
||||
tileInfo.Tile.BackgroundPriority = false;
|
||||
@ -76,7 +71,7 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
HdPpu(MemoryManager* memoryManager) : PPU(memoryManager)
|
||||
HdPpu(BaseMapper* mapper) : PPU(mapper)
|
||||
{
|
||||
_screenTileBuffers[0] = new HdPpuPixelInfo[256 * 240];
|
||||
_screenTileBuffers[1] = new HdPpuPixelInfo[256 * 240];
|
||||
|
@ -1,23 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
enum class MemoryOperation
|
||||
{
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
Any = 3
|
||||
};
|
||||
|
||||
enum class MemoryOperationType
|
||||
{
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
ExecOpCode = 2,
|
||||
ExecOperand = 3,
|
||||
PpuRenderingRead = 4,
|
||||
DummyRead = 5
|
||||
};
|
||||
#include "Types.h"
|
||||
|
||||
class MemoryRanges
|
||||
{
|
||||
|
@ -343,12 +343,12 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadVRAM(uint16_t addr, MemoryOperationType type) override
|
||||
uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType type) override
|
||||
{
|
||||
if(_irqSource == JyIrqSource::PpuRead && type == MemoryOperationType::PpuRenderingRead) {
|
||||
TickIrqCounter();
|
||||
}
|
||||
return BaseMapper::ReadVRAM(addr, type);
|
||||
return BaseMapper::MapperReadVRAM(addr, type);
|
||||
}
|
||||
|
||||
void NotifyVRAMAddressChange(uint16_t addr) override
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "LabelManager.h"
|
||||
#include "Debugger.h"
|
||||
#include "BaseMapper.h"
|
||||
|
||||
LabelManager::LabelManager(shared_ptr<BaseMapper> mapper)
|
||||
{
|
||||
|
@ -366,7 +366,7 @@ protected:
|
||||
BaseMapper::WriteRAM(addr, value);
|
||||
}
|
||||
|
||||
virtual uint8_t ReadVRAM(uint16_t addr, MemoryOperationType memoryOperationType) override
|
||||
virtual uint8_t MapperReadVRAM(uint16_t addr, MemoryOperationType memoryOperationType) override
|
||||
{
|
||||
if(_extendedRamMode <= 1 && _verticalSplitEnabled && memoryOperationType == MemoryOperationType::PpuRenderingRead) {
|
||||
uint32_t cycle = PPU::GetCurrentCycle();
|
||||
@ -446,7 +446,7 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
return BaseMapper::ReadVRAM(addr, memoryOperationType);
|
||||
return BaseMapper::MapperReadVRAM(addr, memoryOperationType);
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
|
@ -55,7 +55,7 @@ uint32_t MemoryDumper::GetMemoryState(DebugMemoryType type, uint8_t *buffer)
|
||||
|
||||
case DebugMemoryType::PpuMemory:
|
||||
for(int i = 0; i <= 0x3FFF; i++) {
|
||||
buffer[i] = _memoryManager->DebugReadVRAM(i);
|
||||
buffer[i] = _mapper->DebugReadVRAM(i);
|
||||
}
|
||||
return 0x4000;
|
||||
|
||||
|
@ -163,51 +163,11 @@ void MemoryManager::DebugWrite(uint16_t addr, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::ProcessVramAccess(uint16_t &addr)
|
||||
{
|
||||
addr &= 0x3FFF;
|
||||
if(addr >= 0x3000) {
|
||||
//Need to mirror 0x3000 writes to 0x2000, this appears to be how hardware behaves
|
||||
//Required for proper MMC3 IRQ timing in Burai Fighter
|
||||
addr -= 0x1000;
|
||||
}
|
||||
_mapper->NotifyVRAMAddressChange(addr);
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::DebugReadVRAM(uint16_t addr)
|
||||
{
|
||||
addr &= 0x3FFF;
|
||||
if(addr >= 0x3000) {
|
||||
addr -= 0x1000;
|
||||
}
|
||||
return _mapper->InternalReadVRAM(addr);
|
||||
}
|
||||
|
||||
uint8_t MemoryManager::ReadVRAM(uint16_t addr, MemoryOperationType operationType)
|
||||
{
|
||||
ProcessVramAccess(addr);
|
||||
uint8_t value = _mapper->ReadVRAM(addr, operationType);
|
||||
Debugger::ProcessVramOperation(operationType, addr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void MemoryManager::WriteVRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
Debugger::ProcessVramOperation(MemoryOperationType::Write, addr, value);
|
||||
ProcessVramAccess(addr);
|
||||
_mapper->WriteVRAM(addr, value);
|
||||
}
|
||||
|
||||
uint32_t MemoryManager::ToAbsolutePrgAddress(uint16_t ramAddr)
|
||||
{
|
||||
return _mapper->ToAbsoluteAddress(ramAddr);
|
||||
}
|
||||
|
||||
uint32_t MemoryManager::ToAbsoluteChrAddress(uint16_t vramAddr)
|
||||
{
|
||||
return _mapper->ToAbsoluteChrAddress(vramAddr);
|
||||
}
|
||||
|
||||
void MemoryManager::StreamState(bool saving)
|
||||
{
|
||||
ArrayInfo<uint8_t> internalRam = { _internalRAM, MemoryManager::InternalRAMSize };
|
||||
|
@ -41,7 +41,6 @@ class MemoryManager: public Snapshotable
|
||||
|
||||
uint8_t DebugRead(uint16_t addr, bool disableRegisterReads = true);
|
||||
uint16_t DebugReadWord(uint16_t addr);
|
||||
uint8_t DebugReadVRAM(uint16_t addr);
|
||||
void DebugWrite(uint16_t addr, uint8_t value);
|
||||
|
||||
uint8_t* GetInternalRAM();
|
||||
@ -51,12 +50,7 @@ class MemoryManager: public Snapshotable
|
||||
uint8_t Read(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::Read);
|
||||
void Write(uint16_t addr, uint8_t value);
|
||||
|
||||
void ProcessVramAccess(uint16_t &addr);
|
||||
uint8_t ReadVRAM(uint16_t addr, MemoryOperationType operationType = MemoryOperationType::PpuRenderingRead);
|
||||
void WriteVRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
uint32_t ToAbsolutePrgAddress(uint16_t ramAddr);
|
||||
uint32_t ToAbsoluteChrAddress(uint16_t vramAddr);
|
||||
|
||||
static uint8_t GetOpenBus(uint8_t mask = 0xFF);
|
||||
};
|
||||
|
@ -7,8 +7,8 @@
|
||||
class NoiseChannel : public ApuEnvelope
|
||||
{
|
||||
private:
|
||||
const vector<uint16_t> _noisePeriodLookupTableNtsc = { { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 } };
|
||||
const vector<uint16_t> _noisePeriodLookupTablePal = { { 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 } };
|
||||
const uint16_t _noisePeriodLookupTableNtsc[16] = { 4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 };
|
||||
const uint16_t _noisePeriodLookupTablePal[16] = { 4, 8, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 };
|
||||
|
||||
//On power-up, the shift register is loaded with the value 1.
|
||||
uint16_t _shiftRegister = 1;
|
||||
|
@ -15,8 +15,8 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
NsfPpu(MemoryManager* memoryManager) : PPU(memoryManager)
|
||||
NsfPpu(BaseMapper* mapper) : PPU(mapper)
|
||||
{
|
||||
_simpleMode = true;
|
||||
|
||||
}
|
||||
};
|
274
Core/PPU.cpp
274
Core/PPU.cpp
@ -8,13 +8,13 @@
|
||||
|
||||
PPU* PPU::Instance = nullptr;
|
||||
|
||||
PPU::PPU(MemoryManager *memoryManager)
|
||||
PPU::PPU(BaseMapper *mapper)
|
||||
{
|
||||
PPU::Instance = this;
|
||||
|
||||
EmulationSettings::SetPpuModel(PpuModel::Ppu2C02);
|
||||
|
||||
_memoryManager = memoryManager;
|
||||
_mapper = mapper;
|
||||
_outputBuffers[0] = new uint16_t[256 * 240];
|
||||
_outputBuffers[1] = new uint16_t[256 * 240];
|
||||
|
||||
@ -29,8 +29,6 @@ PPU::PPU(MemoryManager *memoryManager)
|
||||
BaseMapper::InitializeRam(_spriteRAM, 0x100);
|
||||
BaseMapper::InitializeRam(_secondarySpriteRAM, 0x20);
|
||||
|
||||
_simpleMode = false;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -55,6 +53,10 @@ void PPU::Reset()
|
||||
_flags = {};
|
||||
_statusFlags = {};
|
||||
|
||||
_previousTile = {};
|
||||
_currentTile = {};
|
||||
_nextTile = {};
|
||||
|
||||
_intensifyColorBits = 0;
|
||||
_paletteRamMask = 0;
|
||||
_lastSprite = nullptr;
|
||||
@ -67,7 +69,6 @@ void PPU::Reset()
|
||||
_renderingEnabled = false;
|
||||
_prevRenderingEnabled = false;
|
||||
_cyclesNeeded = 0.0;
|
||||
_simpleMode = false;
|
||||
|
||||
memset(_spriteTiles, 0, sizeof(SpriteInfo));
|
||||
_spriteCount = 0;
|
||||
@ -147,7 +148,7 @@ void PPU::UpdateVideoRamAddr()
|
||||
|
||||
//Trigger memory read when setting the vram address - needed by MMC3 IRQ counter
|
||||
//"Should be clocked when A12 changes to 1 via $2007 read/write"
|
||||
_memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
_mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
} else {
|
||||
//"During rendering (on the pre-render line and the visible lines 0-239, provided either background or sprite rendering is enabled), "
|
||||
//it will update v in an odd way, triggering a coarse X increment and a Y increment simultaneously"
|
||||
@ -183,7 +184,7 @@ void PPU::SetOpenBus(uint8_t mask, uint8_t value)
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
_openBus = openBus & 0xFF;
|
||||
_openBus = (uint8_t)openBus;
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,7 +242,7 @@ uint8_t PPU::ReadRAM(uint16_t addr)
|
||||
openBusMask = 0xFF;
|
||||
} else {
|
||||
returnValue = _memoryReadBuffer;
|
||||
_memoryReadBuffer = _memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
_memoryReadBuffer = _mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
|
||||
if((_state.VideoRamAddr & 0x3FFF) >= 0x3F00 && !EmulationSettings::CheckFlag(EmulationFlags::DisablePaletteRead)) {
|
||||
returnValue = ReadPaletteRAM(_state.VideoRamAddr) | (_openBus & 0xC0);
|
||||
@ -325,7 +326,7 @@ void PPU::WriteRAM(uint16_t addr, uint8_t value)
|
||||
if((_state.VideoRamAddr & 0x3FFF) >= 0x3F00) {
|
||||
WritePaletteRAM(_state.VideoRamAddr, value);
|
||||
} else {
|
||||
_memoryManager->WriteVRAM(_state.VideoRamAddr, value);
|
||||
_mapper->WriteVRAM(_state.VideoRamAddr, value);
|
||||
}
|
||||
UpdateVideoRamAddr();
|
||||
break;
|
||||
@ -343,16 +344,27 @@ uint8_t PPU::ReadPaletteRAM(uint16_t addr)
|
||||
if(addr == 0x10 || addr == 0x14 || addr == 0x18 || addr == 0x1C) {
|
||||
addr &= ~0x10;
|
||||
}
|
||||
return (_paletteRAM[addr] & _paletteRamMask);
|
||||
return _paletteRAM[addr];
|
||||
}
|
||||
|
||||
void PPU::WritePaletteRAM(uint16_t addr, uint8_t value)
|
||||
{
|
||||
addr &= 0x1F;
|
||||
if(addr == 0x10 || addr == 0x14 || addr == 0x18 || addr == 0x1C) {
|
||||
addr &= ~0x10;
|
||||
if(addr == 0x00 || addr == 0x10) {
|
||||
_paletteRAM[0x00] = value;
|
||||
_paletteRAM[0x10] = value;
|
||||
} else if(addr == 0x04 || addr == 0x14) {
|
||||
_paletteRAM[0x04] = value;
|
||||
_paletteRAM[0x14] = value;
|
||||
} else if(addr == 0x08 || addr == 0x18) {
|
||||
_paletteRAM[0x08] = value;
|
||||
_paletteRAM[0x18] = value;
|
||||
} else if(addr == 0x0C || addr == 0x1C) {
|
||||
_paletteRAM[0x0C] = value;
|
||||
_paletteRAM[0x1C] = value;
|
||||
} else {
|
||||
_paletteRAM[addr] = value;
|
||||
}
|
||||
_paletteRAM[addr] = value;
|
||||
}
|
||||
|
||||
bool PPU::IsRenderingEnabled()
|
||||
@ -491,9 +503,8 @@ uint16_t PPU::GetAttributeAddr()
|
||||
void PPU::LoadTileInfo()
|
||||
{
|
||||
if(IsRenderingEnabled()) {
|
||||
uint16_t tileIndex, shift;
|
||||
switch((_cycle - 1) & 0x07) {
|
||||
case 0:
|
||||
case 0: {
|
||||
_previousTile = _currentTile;
|
||||
_currentTile = _nextTile;
|
||||
|
||||
@ -501,22 +512,24 @@ void PPU::LoadTileInfo()
|
||||
LoadNextTile();
|
||||
}
|
||||
|
||||
tileIndex = _memoryManager->ReadVRAM(GetNameTableAddr());
|
||||
uint8_t tileIndex = _mapper->ReadVRAM(GetNameTableAddr());
|
||||
_nextTile.TileAddr = (tileIndex << 4) | (_state.VideoRamAddr >> 12) | _flags.BackgroundPatternAddr;
|
||||
_nextTile.OffsetY = _state.VideoRamAddr >> 12;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
shift = ((_state.VideoRamAddr >> 4) & 0x04) | (_state.VideoRamAddr & 0x02);
|
||||
_nextTile.PaletteOffset = ((_memoryManager->ReadVRAM(GetAttributeAddr()) >> shift) & 0x03) << 2;
|
||||
case 2: {
|
||||
uint8_t shift = ((_state.VideoRamAddr >> 4) & 0x04) | (_state.VideoRamAddr & 0x02);
|
||||
_nextTile.PaletteOffset = ((_mapper->ReadVRAM(GetAttributeAddr()) >> shift) & 0x03) << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
_nextTile.LowByte = _memoryManager->ReadVRAM(_nextTile.TileAddr);
|
||||
_nextTile.LowByte = _mapper->ReadVRAM(_nextTile.TileAddr);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
_nextTile.HighByte = _memoryManager->ReadVRAM(_nextTile.TileAddr + 8);
|
||||
_nextTile.HighByte = _mapper->ReadVRAM(_nextTile.TileAddr + 8);
|
||||
if(_cycle == 334) {
|
||||
InitializeShiftRegisters();
|
||||
}
|
||||
@ -547,22 +560,23 @@ void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uin
|
||||
|
||||
bool fetchLastSprite = true;
|
||||
if((_spriteIndex < _spriteCount || extraSprite) && spriteY < 240) {
|
||||
_spriteTiles[_spriteIndex].BackgroundPriority = backgroundPriority;
|
||||
_spriteTiles[_spriteIndex].HorizontalMirror = horizontalMirror;
|
||||
_spriteTiles[_spriteIndex].VerticalMirror = verticalMirror;
|
||||
_spriteTiles[_spriteIndex].PaletteOffset = ((attributes & 0x03) << 2) | 0x10;
|
||||
SpriteInfo &info = _spriteTiles[_spriteIndex];
|
||||
info.BackgroundPriority = backgroundPriority;
|
||||
info.HorizontalMirror = horizontalMirror;
|
||||
info.VerticalMirror = verticalMirror;
|
||||
info.PaletteOffset = ((attributes & 0x03) << 2) | 0x10;
|
||||
if(extraSprite) {
|
||||
//Use DebugReadVRAM for extra sprites to prevent side-effects.
|
||||
_spriteTiles[_spriteIndex].LowByte = _memoryManager->DebugReadVRAM(tileAddr);
|
||||
_spriteTiles[_spriteIndex].HighByte = _memoryManager->DebugReadVRAM(tileAddr + 8);
|
||||
info.LowByte = _mapper->DebugReadVRAM(tileAddr);
|
||||
info.HighByte = _mapper->DebugReadVRAM(tileAddr + 8);
|
||||
} else {
|
||||
fetchLastSprite = false;
|
||||
_spriteTiles[_spriteIndex].LowByte = _memoryManager->ReadVRAM(tileAddr);
|
||||
_spriteTiles[_spriteIndex].HighByte = _memoryManager->ReadVRAM(tileAddr + 8);
|
||||
info.LowByte = _mapper->ReadVRAM(tileAddr);
|
||||
info.HighByte = _mapper->ReadVRAM(tileAddr + 8);
|
||||
}
|
||||
_spriteTiles[_spriteIndex].TileAddr = tileAddr;
|
||||
_spriteTiles[_spriteIndex].OffsetY = lineOffset;
|
||||
_spriteTiles[_spriteIndex].SpriteX = spriteX;
|
||||
info.TileAddr = tileAddr;
|
||||
info.OffsetY = lineOffset;
|
||||
info.SpriteX = spriteX;
|
||||
}
|
||||
|
||||
if(fetchLastSprite) {
|
||||
@ -575,8 +589,8 @@ void PPU::LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uin
|
||||
tileAddr = ((tileIndex << 4) | _flags.SpritePatternAddr) + lineOffset;
|
||||
}
|
||||
|
||||
_memoryManager->ReadVRAM(tileAddr);
|
||||
_memoryManager->ReadVRAM(tileAddr + 8);
|
||||
_mapper->ReadVRAM(tileAddr);
|
||||
_mapper->ReadVRAM(tileAddr + 8);
|
||||
}
|
||||
|
||||
_spriteIndex++;
|
||||
@ -622,7 +636,7 @@ void PPU::ShiftTileRegisters()
|
||||
_state.HighBitShift <<= 1;
|
||||
}
|
||||
|
||||
uint32_t PPU::GetPixelColor(uint32_t &paletteOffset)
|
||||
uint32_t PPU::GetPixelColor()
|
||||
{
|
||||
uint8_t offset = _state.XScroll;
|
||||
uint32_t backgroundColor = 0;
|
||||
@ -661,60 +675,58 @@ uint32_t PPU::GetPixelColor(uint32_t &paletteOffset)
|
||||
|
||||
if(EmulationSettings::GetSpritesEnabled() && (backgroundColor == 0 || !_spriteTiles[i].BackgroundPriority)) {
|
||||
//Check sprite priority
|
||||
paletteOffset = _lastSprite->PaletteOffset;
|
||||
return spriteColor;
|
||||
return _lastSprite->PaletteOffset + spriteColor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
paletteOffset = ((offset + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile).PaletteOffset;
|
||||
return backgroundColor;
|
||||
return ((offset + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile).PaletteOffset + backgroundColor;
|
||||
}
|
||||
|
||||
void PPU::DrawPixel()
|
||||
{
|
||||
//This is called 3.7 million times per second - needs to be as fast as possible.
|
||||
uint16_t &pixel = _currentOutputBuffer[(_scanline << 8) + _cycle - 1];
|
||||
|
||||
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
||||
uint32_t paletteOffset;
|
||||
uint32_t color = GetPixelColor(paletteOffset);
|
||||
if(color == 0) {
|
||||
pixel = ReadPaletteRAM(0x3F00) | _intensifyColorBits;
|
||||
} else {
|
||||
pixel = ReadPaletteRAM(0x3F00 + paletteOffset + color) | _intensifyColorBits;
|
||||
}
|
||||
uint32_t color = GetPixelColor();
|
||||
_currentOutputBuffer[(_scanline << 8) + _cycle - 1] = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
|
||||
} else {
|
||||
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
|
||||
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
|
||||
_currentOutputBuffer[(_scanline << 8) + _cycle - 1] = (_paletteRAM[_state.VideoRamAddr & 0x1F] & _paletteRamMask) | _intensifyColorBits;
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ProcessPreVBlankScanline()
|
||||
void PPU::ProcessScanline()
|
||||
{
|
||||
//For pre-render scanline & all visible scanlines
|
||||
if(_prevRenderingEnabled) {
|
||||
//Use _prevRenderingEnabled to drive vert/horiz scrolling increments.
|
||||
//This delays the flag by an extra cycle. So if rendering is disabled at cycle 254,
|
||||
//the vertical scrolling increment will not be performed.
|
||||
//This appears to fix freezes in Battletoads (Level 2), but may be incorrect.
|
||||
if(_scanline == -1 && _cycle == 0) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
} else if(_cycle > 0 && _cycle <= 256) {
|
||||
LoadTileInfo();
|
||||
|
||||
//Update video ram address according to scrolling logic
|
||||
if((_cycle > 0 && _cycle < 256 && (_cycle & 0x07) == 0) || _cycle == 328 || _cycle == 336) {
|
||||
if(_prevRenderingEnabled && (_cycle & 0x07) == 0) {
|
||||
IncHorizontalScrolling();
|
||||
} else if(_cycle == 256) {
|
||||
IncVerticalScrolling();
|
||||
} else if(_cycle == 257) {
|
||||
//copy horizontal scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
|
||||
if(_cycle == 256) {
|
||||
IncVerticalScrolling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_cycle >= 257 && _cycle <= 320) {
|
||||
if(_scanline >= 0) {
|
||||
DrawPixel();
|
||||
ShiftTileRegisters();
|
||||
} else if(_cycle == 1) {
|
||||
_statusFlags.VerticalBlank = false;
|
||||
}
|
||||
|
||||
CopyOAMData();
|
||||
} else if(_cycle >= 257 && _cycle <= 320) {
|
||||
if(_cycle == 257) {
|
||||
_spriteIndex = 0;
|
||||
if(_prevRenderingEnabled) {
|
||||
//copy horizontal scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x041F) | (_state.TmpVideoRamAddr & 0x041F);
|
||||
}
|
||||
}
|
||||
if(IsRenderingEnabled()) {
|
||||
//"OAMADDR is set to 0 during each of ticks 257-320 (the sprite tile loading interval) of the pre-render and visible scanlines." (When rendering)
|
||||
@ -725,75 +737,45 @@ void PPU::ProcessPreVBlankScanline()
|
||||
LoadSpriteTileInfo();
|
||||
} else if((_cycle - 257) % 8 == 0) {
|
||||
//Garbage NT sprite fetch (257, 265, 273, etc.) - Required for proper MC-ACC IRQs (MMC3 clone)
|
||||
_memoryManager->ReadVRAM(GetNameTableAddr());
|
||||
_mapper->ReadVRAM(GetNameTableAddr());
|
||||
} else if((_cycle - 259) % 8 == 0) {
|
||||
//Garbage AT sprite fetch
|
||||
_memoryManager->ReadVRAM(GetAttributeAddr());
|
||||
_mapper->ReadVRAM(GetAttributeAddr());
|
||||
}
|
||||
|
||||
if(_scanline == -1 && _cycle >= 280 && _cycle <= 304) {
|
||||
//copy vertical scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BE0) | (_state.TmpVideoRamAddr & 0x7BE0);
|
||||
}
|
||||
}
|
||||
} else if(_cycle == 321 && IsRenderingEnabled()) {
|
||||
_oamCopybuffer = _secondarySpriteRAM[0];
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ProcessPrerenderScanline()
|
||||
{
|
||||
ProcessPreVBlankScanline();
|
||||
|
||||
if(_cycle == 0) {
|
||||
_statusFlags.SpriteOverflow = false;
|
||||
_statusFlags.Sprite0Hit = false;
|
||||
} else if(_cycle == 1) {
|
||||
_statusFlags.VerticalBlank = false;
|
||||
}
|
||||
|
||||
if(_cycle >= 1 && _cycle <= 256) {
|
||||
LoadTileInfo();
|
||||
CopyOAMData();
|
||||
} else if(_cycle >= 280 && _cycle <= 304) {
|
||||
if(IsRenderingEnabled()) {
|
||||
//copy vertical scrolling value from t
|
||||
_state.VideoRamAddr = (_state.VideoRamAddr & ~0x7BE0) | (_state.TmpVideoRamAddr & 0x7BE0);
|
||||
}
|
||||
} else if(_nesModel == NesModel::NTSC && _cycle == 339 && IsRenderingEnabled() && (_frameCount & 0x01)) {
|
||||
//This behavior is NTSC-specific - PAL frames are always the same number of cycles
|
||||
//"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340)
|
||||
_cycle = 340;
|
||||
} else if(_cycle >= 321 && _cycle <= 336) {
|
||||
LoadTileInfo();
|
||||
if(_cycle == 321) {
|
||||
Debugger::SetLastFramePpuScroll(
|
||||
((_state.VideoRamAddr & 0x1F) << 3) | _state.XScroll | ((_state.VideoRamAddr & 0x400) ? 0x100 : 0),
|
||||
(((_state.VideoRamAddr & 0x3E0) >> 2) | ((_state.VideoRamAddr & 0x7000) >> 12)) + ((_state.VideoRamAddr & 0x800) ? 240 : 0)
|
||||
);
|
||||
if(IsRenderingEnabled()) {
|
||||
_oamCopybuffer = _secondarySpriteRAM[0];
|
||||
}
|
||||
if(_scanline == -1) {
|
||||
Debugger::SetLastFramePpuScroll(
|
||||
((_state.VideoRamAddr & 0x1F) << 3) | _state.XScroll | ((_state.VideoRamAddr & 0x400) ? 0x100 : 0),
|
||||
(((_state.VideoRamAddr & 0x3E0) >> 2) | ((_state.VideoRamAddr & 0x7000) >> 12)) + ((_state.VideoRamAddr & 0x800) ? 240 : 0)
|
||||
);
|
||||
}
|
||||
} else if(_prevRenderingEnabled && (_cycle == 328 || _cycle == 336)) {
|
||||
IncHorizontalScrolling();
|
||||
}
|
||||
LoadTileInfo();
|
||||
} else if(_cycle == 337 || _cycle == 339) {
|
||||
if(IsRenderingEnabled()) {
|
||||
_memoryManager->ReadVRAM(GetNameTableAddr());
|
||||
_mapper->ReadVRAM(GetNameTableAddr());
|
||||
|
||||
if(_scanline == -1 && _nesModel == NesModel::NTSC && _cycle == 339 && (_frameCount & 0x01)) {
|
||||
//This behavior is NTSC-specific - PAL frames are always the same number of cycles
|
||||
//"With rendering enabled, each odd PPU frame is one PPU clock shorter than normal" (skip from 339 to 0, going over 340)
|
||||
_cycle = 340;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ProcessVisibleScanline()
|
||||
{
|
||||
if(_cycle > 0 && _cycle <= 256) {
|
||||
LoadTileInfo();
|
||||
|
||||
DrawPixel();
|
||||
ShiftTileRegisters();
|
||||
|
||||
CopyOAMData();
|
||||
} else if(_cycle >= 321 && _cycle <= 336) {
|
||||
LoadTileInfo();
|
||||
} else if(_cycle == 337 || _cycle == 339) {
|
||||
if(IsRenderingEnabled()) {
|
||||
_memoryManager->ReadVRAM(GetNameTableAddr());
|
||||
}
|
||||
}
|
||||
|
||||
ProcessPreVBlankScanline();
|
||||
}
|
||||
|
||||
void PPU::CopyOAMData()
|
||||
{
|
||||
if(_nesModel != NesModel::PAL && IsRenderingEnabled() || _nesModel == NesModel::PAL && (_scanline < 240 || _scanline > 260)) {
|
||||
@ -801,7 +783,7 @@ void PPU::CopyOAMData()
|
||||
if(_cycle < 9 && _state.SpriteRamAddr >= 0x08 && _scanline == -1 && !EmulationSettings::CheckFlag(EmulationFlags::DisableOamAddrBug)) {
|
||||
//This should only be done if rendering is enabled (otherwise oam_stress test fails immediately)
|
||||
//"If OAMADDR is not less than eight when rendering starts, the eight bytes starting at OAMADDR & 0xF8 are copied to the first eight bytes of OAM"
|
||||
_spriteRAM[_cycle - 1] = _spriteRAM[((_state.SpriteRamAddr & 0xF8) + _cycle - 1) & 0xFF];
|
||||
_spriteRAM[_cycle - 1] = _spriteRAM[(uint8_t)((_state.SpriteRamAddr & 0xF8) + _cycle - 1)];
|
||||
}
|
||||
|
||||
//Clear secondary OAM at between cycle 1 and 64
|
||||
@ -825,7 +807,7 @@ void PPU::CopyOAMData()
|
||||
|
||||
if(_cycle & 0x01) {
|
||||
//Read a byte from the primary OAM on odd cycles
|
||||
_oamCopybuffer = _spriteRAM[(_spriteAddrH << 2) + _spriteAddrL];
|
||||
_oamCopybuffer = _spriteRAM[(_spriteAddrH << 2) | _spriteAddrL];
|
||||
} else {
|
||||
if(_oamCopyDone) {
|
||||
_spriteAddrH = (_spriteAddrH + 1) & 0x3F;
|
||||
@ -962,34 +944,25 @@ void PPU::Exec()
|
||||
|
||||
Debugger::ProcessPpuCycle();
|
||||
|
||||
if(!_simpleMode) {
|
||||
if(_scanline != -1 && _scanline < 240) {
|
||||
ProcessVisibleScanline();
|
||||
} else if(_scanline == -1) {
|
||||
ProcessPrerenderScanline();
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_nesModel == NesModel::PAL && _scanline > _nmiScanline + 20) {
|
||||
//"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it
|
||||
//from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen
|
||||
//even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else
|
||||
//it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES."
|
||||
if(_cycle > 0 && _cycle <= 256) {
|
||||
CopyOAMData();
|
||||
} else if(_cycle >= 257 && _cycle < 320) {
|
||||
_state.SpriteRamAddr = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Used by NSF player to speed things up
|
||||
if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
if(_scanline < 240) {
|
||||
ProcessScanline();
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
} else if(_nesModel == NesModel::PAL && _scanline > _nmiScanline + 20) {
|
||||
//"On a PAL machine, because of its extended vertical blank, the PPU begins refreshing OAM roughly 21 scanlines after NMI[2], to prevent it
|
||||
//from decaying during the longer hiatus of rendering. Additionally, it will continue to refresh during the visible portion of the screen
|
||||
//even if rendering is disabled. Because of this, OAM DMA must be done near the beginning of vertical blank on PAL, and everywhere else
|
||||
//it is liable to conflict with the refresh. Since the refresh can't be disabled like on the NTSC hardware, OAM decay does not occur at all on the PAL NES."
|
||||
if(_cycle > 0 && _cycle <= 256) {
|
||||
CopyOAMData();
|
||||
} else if(_cycle >= 257 && _cycle < 320) {
|
||||
_state.SpriteRamAddr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Rendering enabled flag is apparently set with a 1 cycle delay (i.e setting it at cycle 5 will render cycle 6 like cycle 5 and then take the new settings for cycle 7)
|
||||
_prevRenderingEnabled = _renderingEnabled;
|
||||
_renderingEnabled = _flags.BackgroundEnabled || _flags.SpritesEnabled;
|
||||
_renderingEnabled = _flags.BackgroundEnabled | _flags.SpritesEnabled;
|
||||
|
||||
if(_updateVramAddrDelay > 0) {
|
||||
_updateVramAddrDelay--;
|
||||
@ -998,15 +971,14 @@ void PPU::Exec()
|
||||
|
||||
//Trigger memory read when setting the vram address - needed by MMC3 IRQ counter
|
||||
//"4) Should be clocked when A12 changes to 1 via $2006 write"
|
||||
_memoryManager->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
_mapper->ReadVRAM(_state.VideoRamAddr, MemoryOperationType::Read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ExecStatic()
|
||||
{
|
||||
double overclockRate = EmulationSettings::GetOverclockRate();
|
||||
if(overclockRate == 100) {
|
||||
if(!EmulationSettings::HasOverclock()) {
|
||||
PPU::Instance->Exec();
|
||||
PPU::Instance->Exec();
|
||||
PPU::Instance->Exec();
|
||||
@ -1017,9 +989,9 @@ void PPU::ExecStatic()
|
||||
} else {
|
||||
if(PPU::Instance->_nesModel == NesModel::PAL) {
|
||||
//PAL PPU runs 3.2 clocks for every CPU clock, so we need to run an extra clock every 5 CPU clocks
|
||||
Instance->_cyclesNeeded += 3.2 / (overclockRate / 100.0);
|
||||
Instance->_cyclesNeeded += 3.2 / (EmulationSettings::GetOverclockRate() / 100.0);
|
||||
} else {
|
||||
Instance->_cyclesNeeded += 3.0 / (overclockRate / 100.0);
|
||||
Instance->_cyclesNeeded += 3.0 / (EmulationSettings::GetOverclockRate() / 100.0);
|
||||
}
|
||||
|
||||
while(Instance->_cyclesNeeded >= 1.0) {
|
||||
|
30
Core/PPU.h
30
Core/PPU.h
@ -2,12 +2,15 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "EmulationSettings.h"
|
||||
#include "PpuState.h"
|
||||
#include "Types.h"
|
||||
#include "DebuggerTypes.h"
|
||||
#include "IMemoryHandler.h"
|
||||
|
||||
enum class NesModel;
|
||||
|
||||
class BaseMapper;
|
||||
|
||||
enum PPURegisters
|
||||
{
|
||||
Control = 0x00,
|
||||
@ -26,7 +29,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
protected:
|
||||
static PPU* Instance;
|
||||
|
||||
MemoryManager *_memoryManager;
|
||||
BaseMapper *_mapper;
|
||||
|
||||
PPUState _state;
|
||||
int32_t _scanline;
|
||||
@ -83,9 +86,6 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
|
||||
double _cyclesNeeded;
|
||||
|
||||
//Used by NSF player for higher performance
|
||||
bool _simpleMode;
|
||||
|
||||
uint16_t _updateVramAddr;
|
||||
uint8_t _updateVramAddrDelay;
|
||||
|
||||
@ -109,10 +109,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
uint16_t GetNameTableAddr();
|
||||
uint16_t GetAttributeAddr();
|
||||
|
||||
__forceinline void ProcessPreVBlankScanline();
|
||||
void ProcessPrerenderScanline();
|
||||
__forceinline void ProcessVisibleScanline();
|
||||
|
||||
__forceinline void ProcessScanline();
|
||||
__forceinline void CopyOAMData();
|
||||
|
||||
void BeginVBlank();
|
||||
@ -122,13 +119,13 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
void LoadSprite(uint8_t spriteY, uint8_t tileIndex, uint8_t attributes, uint8_t spriteX, bool extraSprite);
|
||||
void LoadSpriteTileInfo();
|
||||
void LoadExtraSprites();
|
||||
void ShiftTileRegisters();
|
||||
__forceinline void ShiftTileRegisters();
|
||||
void InitializeShiftRegisters();
|
||||
void LoadNextTile();
|
||||
|
||||
void UpdateMinimumDrawCycles();
|
||||
|
||||
__forceinline uint32_t GetPixelColor(uint32_t &paletteOffset);
|
||||
__forceinline uint32_t GetPixelColor();
|
||||
__forceinline virtual void DrawPixel();
|
||||
virtual void SendFrame();
|
||||
|
||||
@ -141,11 +138,6 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
}
|
||||
}
|
||||
|
||||
void SetSimpleMode()
|
||||
{
|
||||
_simpleMode = true;
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override;
|
||||
|
||||
public:
|
||||
@ -154,7 +146,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
static const uint32_t PixelCount = 256*240;
|
||||
static const uint32_t OutputBufferSize = 256*240*2;
|
||||
|
||||
PPU(MemoryManager *memoryManager);
|
||||
PPU(BaseMapper *mapper);
|
||||
virtual ~PPU();
|
||||
|
||||
void Reset();
|
||||
@ -170,7 +162,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
ranges.AddHandler(MemoryOperation::Write, 0x4014);
|
||||
}
|
||||
|
||||
uint8_t ReadPaletteRAM(uint16_t addr);
|
||||
__forceinline uint8_t ReadPaletteRAM(uint16_t addr);
|
||||
void WritePaletteRAM(uint16_t addr, uint8_t value);
|
||||
|
||||
uint8_t ReadRAM(uint16_t addr) override;
|
||||
|
@ -1,71 +0,0 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
struct PPUControlFlags
|
||||
{
|
||||
bool VerticalWrite;
|
||||
uint16_t SpritePatternAddr;
|
||||
uint16_t BackgroundPatternAddr;
|
||||
bool LargeSprites;
|
||||
bool VBlank;
|
||||
|
||||
bool Grayscale;
|
||||
bool BackgroundMask;
|
||||
bool SpriteMask;
|
||||
bool BackgroundEnabled;
|
||||
bool SpritesEnabled;
|
||||
bool IntensifyRed;
|
||||
bool IntensifyGreen;
|
||||
bool IntensifyBlue;
|
||||
};
|
||||
|
||||
struct PPUStatusFlags
|
||||
{
|
||||
bool SpriteOverflow;
|
||||
bool Sprite0Hit;
|
||||
bool VerticalBlank;
|
||||
};
|
||||
|
||||
struct PPUState
|
||||
{
|
||||
uint8_t Control;
|
||||
uint8_t Mask;
|
||||
uint8_t Status;
|
||||
uint32_t SpriteRamAddr;
|
||||
uint16_t VideoRamAddr;
|
||||
uint8_t XScroll;
|
||||
uint16_t TmpVideoRamAddr;
|
||||
bool WriteToggle;
|
||||
|
||||
uint16_t HighBitShift;
|
||||
uint16_t LowBitShift;
|
||||
};
|
||||
|
||||
struct TileInfo
|
||||
{
|
||||
uint8_t LowByte;
|
||||
uint8_t HighByte;
|
||||
uint32_t PaletteOffset;
|
||||
|
||||
uint16_t TileAddr; //used by HD ppu
|
||||
uint8_t OffsetY; //used by HD ppu
|
||||
};
|
||||
|
||||
struct SpriteInfo : TileInfo
|
||||
{
|
||||
bool HorizontalMirror;
|
||||
bool BackgroundPriority;
|
||||
uint8_t SpriteX;
|
||||
|
||||
bool VerticalMirror; //used by HD ppu
|
||||
};
|
||||
|
||||
struct PPUDebugState
|
||||
{
|
||||
PPUControlFlags ControlFlags;
|
||||
PPUStatusFlags StatusFlags;
|
||||
PPUState State;
|
||||
int32_t Scanline;
|
||||
uint32_t Cycle;
|
||||
uint32_t FrameCount;
|
||||
};
|
@ -7,12 +7,12 @@
|
||||
class SquareChannel : public ApuEnvelope
|
||||
{
|
||||
private:
|
||||
const vector<vector<uint8_t>> _dutySequences = { {
|
||||
const uint8_t _dutySequences[4][8] = {
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 1, 1 },
|
||||
{ 0, 0, 0, 0, 1, 1, 1, 1 },
|
||||
{ 1, 1, 1, 1, 1, 1, 0, 0 }
|
||||
} };
|
||||
};
|
||||
|
||||
bool _isChannel1 = false;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "TraceLogger.h"
|
||||
#include "DisassemblyInfo.h"
|
||||
#include "DebugState.h"
|
||||
#include "DebuggerTypes.h"
|
||||
#include "Console.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "LabelManager.h"
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "CpuState.h"
|
||||
#include "PpuState.h"
|
||||
#include "DebuggerTypes.h"
|
||||
|
||||
class DisassemblyInfo;
|
||||
class MemoryManager;
|
||||
|
@ -7,7 +7,7 @@
|
||||
class TriangleChannel : public ApuLengthCounter
|
||||
{
|
||||
private:
|
||||
const vector<uint8_t> _sequence = { { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } };
|
||||
const uint8_t _sequence[32] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
uint8_t _linearCounter = 0;
|
||||
uint8_t _linearCounterReload = 0;
|
||||
|
139
Core/Types.h
Normal file
139
Core/Types.h
Normal file
@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
enum class MemoryOperation
|
||||
{
|
||||
Read = 1,
|
||||
Write = 2,
|
||||
Any = 3
|
||||
};
|
||||
|
||||
enum class MemoryOperationType
|
||||
{
|
||||
Read = 0,
|
||||
Write = 1,
|
||||
ExecOpCode = 2,
|
||||
ExecOperand = 3,
|
||||
PpuRenderingRead = 4,
|
||||
DummyRead = 5
|
||||
};
|
||||
|
||||
struct State
|
||||
{
|
||||
uint16_t PC = 0;
|
||||
uint8_t SP = 0;
|
||||
uint8_t A = 0;
|
||||
uint8_t X = 0;
|
||||
uint8_t Y = 0;
|
||||
uint8_t PS = 0;
|
||||
uint32_t IRQFlag = 0;
|
||||
int32_t CycleCount = 0;
|
||||
bool NMIFlag = false;
|
||||
|
||||
//Used by debugger
|
||||
uint16_t DebugPC = 0;
|
||||
};
|
||||
|
||||
enum class PrgMemoryType
|
||||
{
|
||||
PrgRom,
|
||||
SaveRam,
|
||||
WorkRam,
|
||||
};
|
||||
|
||||
enum class ChrMemoryType
|
||||
{
|
||||
Default,
|
||||
ChrRom,
|
||||
ChrRam
|
||||
};
|
||||
|
||||
enum MemoryAccessType
|
||||
{
|
||||
Unspecified = -1,
|
||||
NoAccess = 0x00,
|
||||
Read = 0x01,
|
||||
Write = 0x02,
|
||||
ReadWrite = 0x03
|
||||
};
|
||||
|
||||
enum ChrSpecialPage
|
||||
{
|
||||
NametableA = 0x7000,
|
||||
NametableB = 0x7001
|
||||
};
|
||||
|
||||
struct CartridgeState
|
||||
{
|
||||
uint32_t PrgRomSize;
|
||||
uint32_t ChrRomSize;
|
||||
uint32_t ChrRamSize;
|
||||
|
||||
uint32_t PrgPageCount;
|
||||
uint32_t PrgPageSize;
|
||||
uint32_t PrgSelectedPages[64];
|
||||
uint32_t ChrPageCount;
|
||||
uint32_t ChrPageSize;
|
||||
uint32_t ChrSelectedPages[64];
|
||||
uint32_t Nametables[8];
|
||||
};
|
||||
|
||||
|
||||
struct PPUControlFlags
|
||||
{
|
||||
bool VerticalWrite;
|
||||
uint16_t SpritePatternAddr;
|
||||
uint16_t BackgroundPatternAddr;
|
||||
bool LargeSprites;
|
||||
bool VBlank;
|
||||
|
||||
bool Grayscale;
|
||||
bool BackgroundMask;
|
||||
bool SpriteMask;
|
||||
bool BackgroundEnabled;
|
||||
bool SpritesEnabled;
|
||||
bool IntensifyRed;
|
||||
bool IntensifyGreen;
|
||||
bool IntensifyBlue;
|
||||
};
|
||||
|
||||
struct PPUStatusFlags
|
||||
{
|
||||
bool SpriteOverflow;
|
||||
bool Sprite0Hit;
|
||||
bool VerticalBlank;
|
||||
};
|
||||
|
||||
struct PPUState
|
||||
{
|
||||
uint8_t Control;
|
||||
uint8_t Mask;
|
||||
uint8_t Status;
|
||||
uint32_t SpriteRamAddr;
|
||||
uint16_t VideoRamAddr;
|
||||
uint8_t XScroll;
|
||||
uint16_t TmpVideoRamAddr;
|
||||
bool WriteToggle;
|
||||
|
||||
uint16_t HighBitShift;
|
||||
uint16_t LowBitShift;
|
||||
};
|
||||
|
||||
struct TileInfo
|
||||
{
|
||||
uint8_t LowByte;
|
||||
uint8_t HighByte;
|
||||
uint32_t PaletteOffset;
|
||||
|
||||
uint16_t TileAddr; //used by HD ppu
|
||||
uint8_t OffsetY; //used by HD ppu
|
||||
};
|
||||
|
||||
struct SpriteInfo : TileInfo
|
||||
{
|
||||
bool HorizontalMirror;
|
||||
bool BackgroundPriority;
|
||||
uint8_t SpriteX;
|
||||
|
||||
bool VerticalMirror; //used by HD ppu
|
||||
};
|
Loading…
Reference in New Issue
Block a user