mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-23 09:09:45 +00:00
Core: Rewrite DMC/OAM DMA, tweak PPU timings, add option to simulate PPU/CPU alignments
This commit is contained in:
parent
bc335e104d
commit
a72acc9f1a
24
Core/APU.cpp
24
Core/APU.cpp
@ -171,7 +171,7 @@ void APU::SetNeedToRun()
|
||||
|
||||
bool APU::NeedToRun(uint32_t currentCycle)
|
||||
{
|
||||
if(_needToRun || _deltaModulationChannel->NeedToRun()) {
|
||||
if(_deltaModulationChannel->NeedToRun() || _needToRun) {
|
||||
//Need to run whenever we alter the length counters
|
||||
//Need to run every cycle when DMC is running to get accurate emulation (CPU stalling, interaction with sprite DMA, etc.)
|
||||
_needToRun = false;
|
||||
@ -210,22 +210,13 @@ void APU::EndFrame()
|
||||
void APU::ProcessCpuClock()
|
||||
{
|
||||
if(_apuEnabled) {
|
||||
if(_settings->GetOverclockRate() == 100 || !_settings->GetOverclockAdjustApu()) {
|
||||
Exec();
|
||||
} else {
|
||||
_cyclesNeeded += 1.0 / ((double)_settings->GetOverclockRate() / 100.0);
|
||||
while(_cyclesNeeded >= 1.0) {
|
||||
Exec();
|
||||
_cyclesNeeded--;
|
||||
}
|
||||
}
|
||||
Exec();
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Reset(bool softReset)
|
||||
{
|
||||
_apuEnabled = true;
|
||||
_cyclesNeeded = 0;
|
||||
_currentCycle = 0;
|
||||
_previousCycle = 0;
|
||||
_squareChannel[0]->Reset(softReset);
|
||||
@ -253,7 +244,7 @@ void APU::StreamState(bool saving)
|
||||
SnapshotInfo deltaModulationChannel{ _deltaModulationChannel.get() };
|
||||
SnapshotInfo frameCounter{ _frameCounter.get() };
|
||||
SnapshotInfo mixer{ _mixer.get() };
|
||||
Stream(_nesModel, squareChannel0, squareChannel1, triangleChannel, noiseChannel, deltaModulationChannel, frameCounter, mixer, _cyclesNeeded);
|
||||
Stream(_nesModel, squareChannel0, squareChannel1, triangleChannel, noiseChannel, deltaModulationChannel, frameCounter, mixer);
|
||||
}
|
||||
|
||||
void APU::AddExpansionAudioDelta(AudioChannel channel, int16_t delta)
|
||||
@ -275,9 +266,14 @@ bool APU::IsApuEnabled()
|
||||
return _apuEnabled;
|
||||
}
|
||||
|
||||
void APU::FillDmcReadBuffer()
|
||||
uint16_t APU::GetDmcReadAddress()
|
||||
{
|
||||
_deltaModulationChannel->FillReadBuffer();
|
||||
return _deltaModulationChannel->GetDmcReadAddress();
|
||||
}
|
||||
|
||||
void APU::SetDmcReadBuffer(uint8_t value)
|
||||
{
|
||||
_deltaModulationChannel->SetDmcReadBuffer(value);
|
||||
}
|
||||
|
||||
ApuState APU::GetState()
|
||||
|
@ -40,8 +40,6 @@ class APU : public Snapshotable, public IMemoryHandler
|
||||
|
||||
NesModel _nesModel;
|
||||
|
||||
double _cyclesNeeded;
|
||||
|
||||
private:
|
||||
__forceinline bool NeedToRun(uint32_t currentCycle);
|
||||
|
||||
@ -73,6 +71,7 @@ class APU : public Snapshotable, public IMemoryHandler
|
||||
void AddExpansionAudioDelta(AudioChannel channel, int16_t delta);
|
||||
void SetApuStatus(bool enabled);
|
||||
bool IsApuEnabled();
|
||||
void FillDmcReadBuffer();
|
||||
uint16_t GetDmcReadAddress();
|
||||
void SetDmcReadBuffer(uint8_t value);
|
||||
void SetNeedToRun();
|
||||
};
|
@ -64,8 +64,7 @@ public:
|
||||
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
int32_t unusednextIrqCycle = 0;
|
||||
Stream(unusednextIrqCycle, _previousCycle, _currentStep, _stepMode, _inhibitIRQ, _nesModel, _blockFrameCounterTick, _writeDelayCounter, _newValue);
|
||||
Stream(_previousCycle, _currentStep, _stepMode, _inhibitIRQ, _nesModel, _blockFrameCounterTick, _writeDelayCounter, _newValue);
|
||||
|
||||
if(!saving) {
|
||||
SetNesModel(_nesModel);
|
||||
@ -185,11 +184,11 @@ public:
|
||||
|
||||
//Reset sequence after $4017 is written to
|
||||
if(_console->GetCpu()->GetCycleCount() & 0x01) {
|
||||
//"If the write occurs during an APU cycle, the effects occur 3 CPU cycles after the $4017 write cycle"
|
||||
_writeDelayCounter = 3;
|
||||
} else {
|
||||
//"If the write occurs between APU cycles, the effects occur 4 CPU cycles after the write cycle. "
|
||||
_writeDelayCounter = 4;
|
||||
} else {
|
||||
//"If the write occurs during an APU cycle, the effects occur 3 CPU cycles after the $4017 write cycle"
|
||||
_writeDelayCounter = 3;
|
||||
}
|
||||
|
||||
_inhibitIRQ = (value & 0x40) == 0x40;
|
||||
|
@ -10,20 +10,11 @@ BaseExpansionAudio::BaseExpansionAudio(shared_ptr<Console> console)
|
||||
|
||||
void BaseExpansionAudio::StreamState(bool saving)
|
||||
{
|
||||
Stream(_clocksNeeded);
|
||||
}
|
||||
|
||||
void BaseExpansionAudio::Clock()
|
||||
{
|
||||
if(_console->GetApu()->IsApuEnabled()) {
|
||||
if(_console->GetSettings()->GetOverclockRate() == 100 || !_console->GetSettings()->GetOverclockAdjustApu()) {
|
||||
ClockAudio();
|
||||
} else {
|
||||
_clocksNeeded += 1.0 / ((double)_console->GetSettings()->GetOverclockRate() / 100);
|
||||
while(_clocksNeeded >= 1.0) {
|
||||
ClockAudio();
|
||||
_clocksNeeded--;
|
||||
}
|
||||
}
|
||||
ClockAudio();
|
||||
}
|
||||
}
|
@ -7,9 +7,6 @@ class MemoryManager;
|
||||
|
||||
class BaseExpansionAudio : public Snapshotable
|
||||
{
|
||||
private:
|
||||
double _clocksNeeded = 0;
|
||||
|
||||
protected:
|
||||
shared_ptr<Console> _console = nullptr;
|
||||
|
||||
|
278
Core/CPU.cpp
278
Core/CPU.cpp
@ -1,4 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include <random>
|
||||
#include <assert.h>
|
||||
#include "CPU.h"
|
||||
#include "PPU.h"
|
||||
#include "APU.h"
|
||||
@ -60,12 +62,15 @@ CPU::CPU(shared_ptr<Console> console)
|
||||
_state = {};
|
||||
_cycleCount = 0;
|
||||
_operand = 0;
|
||||
_spriteDmaCounter = 0;
|
||||
_spriteDmaTransfer = false;
|
||||
_dmcCounter = 0;
|
||||
_spriteDmaOffset = 0;
|
||||
_needHalt = false;
|
||||
_ppuOffset = 0;
|
||||
_startClockCount = 6;
|
||||
_endClockCount = 6;
|
||||
_masterClock = 0;
|
||||
_dmcDmaRunning = false;
|
||||
_cpuWrite = false;
|
||||
_writeAddr = 0;
|
||||
_irqMask = 0;
|
||||
_state = {};
|
||||
_prevRunIrq = false;
|
||||
@ -76,12 +81,10 @@ void CPU::Reset(bool softReset, NesModel model)
|
||||
{
|
||||
_state.NMIFlag = false;
|
||||
_state.IRQFlag = 0;
|
||||
_cycleCount = -1;
|
||||
|
||||
_spriteDmaTransfer = false;
|
||||
_spriteDmaCounter = 0;
|
||||
|
||||
_dmcCounter = -1;
|
||||
_spriteDmaOffset = 0;
|
||||
_needHalt = false;
|
||||
_dmcDmaRunning = false;
|
||||
_warnOnCrash = true;
|
||||
|
||||
@ -106,13 +109,50 @@ void CPU::Reset(bool softReset, NesModel model)
|
||||
_runIrq = false;
|
||||
}
|
||||
|
||||
//The CPU takes some cycles before starting its execution after a reset/power up
|
||||
for(int i = 0; i < (model == NesModel::NTSC ? 28 : 30); i++) {
|
||||
_console->GetPpu()->Exec();
|
||||
if(!softReset) {
|
||||
uint8_t ppuDivider;
|
||||
uint8_t cpuDivider;
|
||||
switch(model) {
|
||||
default:
|
||||
case NesModel::NTSC:
|
||||
ppuDivider = 4;
|
||||
cpuDivider = 12;
|
||||
break;
|
||||
|
||||
case NesModel::PAL:
|
||||
ppuDivider = 5;
|
||||
cpuDivider = 16;
|
||||
break;
|
||||
|
||||
case NesModel::Dendy:
|
||||
ppuDivider = 5;
|
||||
cpuDivider = 15;
|
||||
break;
|
||||
}
|
||||
|
||||
_cycleCount = -1;
|
||||
_masterClock = 0;
|
||||
|
||||
uint8_t cpuOffset = 0;
|
||||
if(_console->GetSettings()->CheckFlag(EmulationFlags::RandomizeCpuPpuAlignment)) {
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
std::uniform_int_distribution<> distPpu(0, ppuDivider - 1);
|
||||
std::uniform_int_distribution<> distCpu(0, cpuDivider - 1);
|
||||
_ppuOffset = distPpu(mt);
|
||||
cpuOffset += distCpu(mt);
|
||||
} else {
|
||||
_ppuOffset = 2;
|
||||
cpuOffset = 0;
|
||||
}
|
||||
|
||||
_masterClock += cpuDivider + cpuOffset;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
_console->GetApu()->ProcessCpuClock();
|
||||
//The CPU takes 8 cycles before it starts executing the ROM's code after a reset/power up
|
||||
for(int i = 0; i < 8; i++) {
|
||||
StartCpuCycle(true);
|
||||
EndCpuCycle(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,19 +240,10 @@ void CPU::MemoryWrite(uint16_t addr, uint8_t value, MemoryOperationType operatio
|
||||
_writeCounter++;
|
||||
}
|
||||
#else
|
||||
_cpuWrite = true;;
|
||||
_writeAddr = addr;
|
||||
IncCycleCount();
|
||||
while(_dmcDmaRunning) {
|
||||
IncCycleCount();
|
||||
}
|
||||
|
||||
_cpuWrite = true;
|
||||
StartCpuCycle(false);
|
||||
_memoryManager->Write(addr, value, operationType);
|
||||
|
||||
//DMA DMC might have started after a write to $4015, stall CPU if needed
|
||||
while(_dmcDmaRunning) {
|
||||
IncCycleCount();
|
||||
}
|
||||
EndCpuCycle(false);
|
||||
_cpuWrite = false;
|
||||
#endif
|
||||
}
|
||||
@ -228,20 +259,11 @@ uint8_t CPU::MemoryRead(uint16_t addr, MemoryOperationType operationType) {
|
||||
}
|
||||
return value;
|
||||
#else
|
||||
IncCycleCount();
|
||||
while(_dmcDmaRunning) {
|
||||
//Stall CPU until we can process a DMC read
|
||||
if((addr != 0x4016 && addr != 0x4017 && (_cycleCount & 0x01)) || _dmcCounter == 1) {
|
||||
//While the CPU is stalled, reads are performed on the current address
|
||||
//Reads are only performed every other cycle? This fixes "dma_2007_read" test
|
||||
//This behavior causes the $4016/7 data corruption when a DMC is running.
|
||||
//When reading $4016/7, only the last read counts (because this only occurs to low-to-high transitions, i.e once in this case)
|
||||
_memoryManager->Read(addr);
|
||||
}
|
||||
IncCycleCount();
|
||||
}
|
||||
ProcessPendingDma(addr);
|
||||
|
||||
StartCpuCycle(true);
|
||||
uint8_t value = _memoryManager->Read(addr, operationType);
|
||||
EndCpuCycle(true);
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
@ -292,90 +314,112 @@ uint16_t CPU::FetchOperand()
|
||||
|
||||
}
|
||||
|
||||
void CPU::IncCycleCount()
|
||||
void CPU::EndCpuCycle(bool forRead)
|
||||
{
|
||||
_cycleCount++;
|
||||
_masterClock += forRead ? (_endClockCount + 1) : (_endClockCount - 1);
|
||||
_console->GetPpu()->Run(_masterClock - _ppuOffset);
|
||||
|
||||
if(_dmcDmaRunning) {
|
||||
//CPU is being stalled by the DMC's DMA transfer
|
||||
_dmcCounter--;
|
||||
if(_dmcCounter == 0) {
|
||||
//Update the DMC buffer when the stall period is completed
|
||||
_dmcDmaRunning = false;
|
||||
#ifndef DUMMYCPU
|
||||
_console->GetApu()->FillDmcReadBuffer();
|
||||
_console->DebugAddTrace("DMC DMA End");
|
||||
#endif
|
||||
}
|
||||
//"it's really the status of the interrupt lines at the end of the second-to-last cycle that matters."
|
||||
//Keep the irq lines values from the previous cycle. The before-to-last cycle's values will be used
|
||||
_prevRunIrq = _runIrq;
|
||||
_runIrq = _state.NMIFlag || ((_state.IRQFlag & _irqMask) > 0 && !CheckFlag(PSFlags::Interrupt));
|
||||
}
|
||||
|
||||
void CPU::StartCpuCycle(bool forRead)
|
||||
{
|
||||
_masterClock += forRead ? (_startClockCount - 1) : (_startClockCount + 1);
|
||||
_cycleCount++;
|
||||
_console->GetPpu()->Run(_masterClock - _ppuOffset);
|
||||
_console->ProcessCpuClock();
|
||||
}
|
||||
|
||||
void CPU::ProcessPendingDma(uint16_t readAddress)
|
||||
{
|
||||
if(!_needHalt) {
|
||||
return;
|
||||
}
|
||||
|
||||
_console->ProcessCpuClock();
|
||||
//"If this cycle is a read, hijack the read, discard the value, and prevent all other actions that occur on this cycle (PC not incremented, etc)"
|
||||
StartCpuCycle(true);
|
||||
_memoryManager->Read(readAddress, MemoryOperationType::DummyRead);
|
||||
EndCpuCycle(true);
|
||||
_needHalt = false;
|
||||
|
||||
if(!_spriteDmaTransfer && !_dmcDmaRunning) {
|
||||
//IRQ flags are ignored during Sprite DMA - fixes irq_and_dma
|
||||
uint16_t spriteDmaCounter = 0;
|
||||
uint8_t spriteReadAddr = 0;
|
||||
uint8_t readValue = 0;
|
||||
bool skipDummyReads = (readAddress == 0x4016 || readAddress == 0x4017);
|
||||
|
||||
//"it's really the status of the interrupt lines at the end of the second-to-last cycle that matters."
|
||||
//Keep the irq lines values from the previous cycle. The before-to-last cycle's values will be used
|
||||
_prevRunIrq = _runIrq;
|
||||
_runIrq = _state.NMIFlag || ((_state.IRQFlag & _irqMask) > 0 && !CheckFlag(PSFlags::Interrupt));
|
||||
auto processCycle = [this] {
|
||||
//Sprite DMA cycles count as halt/dummy cycles for the DMC DMA when both run at the same time
|
||||
if(_needHalt) {
|
||||
_needHalt = false;
|
||||
} else if(_needDummyRead) {
|
||||
_needDummyRead = false;
|
||||
}
|
||||
StartCpuCycle(true);
|
||||
};
|
||||
|
||||
while(_dmcDmaRunning || _spriteDmaTransfer) {
|
||||
bool getCycle = (_cycleCount & 0x01) == 0;
|
||||
if(getCycle) {
|
||||
if(_dmcDmaRunning && !_needHalt && !_needDummyRead) {
|
||||
//DMC DMA is ready to read a byte (both halt and dummy read cycles were performed before this)
|
||||
processCycle();
|
||||
readValue = _memoryManager->Read(_console->GetApu()->GetDmcReadAddress(), MemoryOperationType::DmcRead);
|
||||
EndCpuCycle(true);
|
||||
_console->GetApu()->SetDmcReadBuffer(readValue);
|
||||
_dmcDmaRunning = false;
|
||||
} else if(_spriteDmaTransfer) {
|
||||
//DMC DMA is not running, or not ready, run sprite DMA
|
||||
processCycle();
|
||||
readValue = _memoryManager->Read(_spriteDmaOffset * 0x100 + spriteReadAddr);
|
||||
EndCpuCycle(true);
|
||||
spriteReadAddr++;
|
||||
spriteDmaCounter++;
|
||||
} else {
|
||||
//DMC DMA is running, but not ready (need halt/dummy read) and sprite DMA isn't runnnig, perform a dummy read
|
||||
assert(_needHalt || _needDummyRead);
|
||||
processCycle();
|
||||
if(!skipDummyReads) {
|
||||
_memoryManager->Read(readAddress, MemoryOperationType::DummyRead);
|
||||
}
|
||||
EndCpuCycle(true);
|
||||
}
|
||||
} else {
|
||||
if(_spriteDmaTransfer && (spriteDmaCounter & 0x01)) {
|
||||
//Sprite DMA write cycle (only do this if a sprite dma read was performed last cycle)
|
||||
processCycle();
|
||||
_memoryManager->Write(0x2004, readValue, MemoryOperationType::Write);
|
||||
EndCpuCycle(true);
|
||||
spriteDmaCounter++;
|
||||
if(spriteDmaCounter == 0x200) {
|
||||
_spriteDmaTransfer = false;
|
||||
}
|
||||
} else {
|
||||
//Align to read cycle before starting sprite DMA (or align to perform DMC read)
|
||||
processCycle();
|
||||
if(!skipDummyReads) {
|
||||
_memoryManager->Read(readAddress, MemoryOperationType::DummyRead);
|
||||
}
|
||||
EndCpuCycle(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::RunDMATransfer(uint8_t offsetValue)
|
||||
{
|
||||
_console->DebugAddTrace("Sprite DMA Start");
|
||||
_spriteDmaTransfer = true;
|
||||
|
||||
//"The CPU is suspended during the transfer, which will take 513 or 514 cycles after the $4014 write tick."
|
||||
//"(1 dummy read cycle while waiting for writes to complete, +1 if on an odd CPU cycle, then 256 alternating read/write cycles.)"
|
||||
if(_cycleCount % 2 != 0) {
|
||||
DummyRead();
|
||||
}
|
||||
DummyRead();
|
||||
|
||||
_spriteDmaCounter = 256;
|
||||
|
||||
//DMA transfer starts at SpriteRamAddr and wraps around
|
||||
for(int i = 0; i < 0x100; i++) {
|
||||
//Read value
|
||||
uint8_t readValue = MemoryRead(offsetValue * 0x100 + i);
|
||||
|
||||
//Write to sprite ram via $2004 ("DMA is implemented in the 2A03/7 chip and works by repeatedly writing to OAMDATA")
|
||||
MemoryWrite(0x2004, readValue);
|
||||
|
||||
_spriteDmaCounter--;
|
||||
}
|
||||
|
||||
_spriteDmaTransfer = false;
|
||||
|
||||
_console->DebugAddTrace("Sprite DMA End");
|
||||
_spriteDmaOffset = offsetValue;
|
||||
_needHalt = true;
|
||||
}
|
||||
|
||||
void CPU::StartDmcTransfer()
|
||||
{
|
||||
//"DMC DMA adds 4 cycles normally, 2 if it lands on the $4014 write or during OAM DMA"
|
||||
//3 cycles if it lands on the last write cycle of any instruction
|
||||
_console->DebugAddTrace("DMC DMA Start");
|
||||
_dmcDmaRunning = true;
|
||||
if(_spriteDmaTransfer) {
|
||||
if(_spriteDmaCounter == 2) {
|
||||
_dmcCounter = 1;
|
||||
} else if(_spriteDmaCounter == 1) {
|
||||
_dmcCounter = 3;
|
||||
} else {
|
||||
_dmcCounter = 2;
|
||||
}
|
||||
} else {
|
||||
if(_cpuWrite) {
|
||||
if(_writeAddr == 0x4014) {
|
||||
_dmcCounter = 2;
|
||||
} else {
|
||||
_dmcCounter = 3;
|
||||
}
|
||||
} else {
|
||||
_dmcCounter = 4;
|
||||
}
|
||||
}
|
||||
_needDummyRead = true;
|
||||
_needHalt = true;
|
||||
}
|
||||
|
||||
uint32_t CPU::GetClockRate(NesModel model)
|
||||
@ -388,21 +432,39 @@ uint32_t CPU::GetClockRate(NesModel model)
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::SetMasterClockDivider(NesModel region)
|
||||
{
|
||||
switch(region) {
|
||||
case NesModel::NTSC:
|
||||
_startClockCount = 6;
|
||||
_endClockCount = 6;
|
||||
break;
|
||||
|
||||
case NesModel::PAL:
|
||||
_startClockCount = 8;
|
||||
_endClockCount = 8;
|
||||
break;
|
||||
|
||||
case NesModel::Dendy:
|
||||
_startClockCount = 7;
|
||||
_endClockCount = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::StreamState(bool saving)
|
||||
{
|
||||
EmulationSettings* settings = _console->GetSettings();
|
||||
uint32_t overclockRate = settings->GetOverclockRateSetting();
|
||||
bool overclockAdjustApu = settings->GetOverclockAdjustApu();
|
||||
uint32_t extraScanlinesBeforeNmi = settings->GetPpuExtraScanlinesBeforeNmi();
|
||||
uint32_t extraScanlinesAfterNmi = settings->GetPpuExtraScanlinesAfterNmi();
|
||||
uint32_t dipSwitches = _console->GetSettings()->GetDipSwitches();
|
||||
|
||||
Stream(_state.PC, _state.SP, _state.PS, _state.A, _state.X, _state.Y, _cycleCount, _state.NMIFlag,
|
||||
_state.IRQFlag, _dmcCounter, _dmcDmaRunning, _spriteDmaCounter, _spriteDmaTransfer,
|
||||
overclockRate, overclockAdjustApu, extraScanlinesBeforeNmi, extraScanlinesBeforeNmi, dipSwitches);
|
||||
_state.IRQFlag, _dmcDmaRunning, _spriteDmaTransfer,
|
||||
extraScanlinesBeforeNmi, extraScanlinesBeforeNmi, dipSwitches,
|
||||
_needDummyRead, _needHalt, _startClockCount, _endClockCount, _ppuOffset, _masterClock);
|
||||
|
||||
if(!saving) {
|
||||
settings->SetOverclockRate(overclockRate, overclockAdjustApu);
|
||||
settings->SetPpuNmiConfig(extraScanlinesBeforeNmi, extraScanlinesAfterNmi);
|
||||
settings->SetDipSwitches(dipSwitches);
|
||||
}
|
||||
|
27
Core/CPU.h
27
Core/CPU.h
@ -32,19 +32,23 @@ private:
|
||||
typedef void(CPU::*Func)();
|
||||
|
||||
uint64_t _cycleCount;
|
||||
uint64_t _masterClock;
|
||||
uint8_t _ppuOffset;
|
||||
uint8_t _startClockCount;
|
||||
uint8_t _endClockCount;
|
||||
uint16_t _operand;
|
||||
|
||||
Func _opTable[256];
|
||||
AddrMode _addrMode[256];
|
||||
AddrMode _instAddrMode;
|
||||
|
||||
uint16_t _spriteDmaCounter;
|
||||
bool _spriteDmaTransfer;
|
||||
bool _needHalt = false;
|
||||
bool _spriteDmaTransfer = false;
|
||||
bool _dmcDmaRunning = false;
|
||||
bool _needDummyRead = false;
|
||||
uint8_t _spriteDmaOffset;
|
||||
|
||||
int8_t _dmcCounter;
|
||||
bool _dmcDmaRunning;
|
||||
bool _cpuWrite = false;
|
||||
uint16_t _writeAddr = 0;
|
||||
|
||||
uint8_t _irqMask;
|
||||
|
||||
@ -69,8 +73,10 @@ private:
|
||||
bool _isDummyRead[10];
|
||||
#endif
|
||||
|
||||
void IncCycleCount();
|
||||
uint16_t FetchOperand();
|
||||
__forceinline void StartCpuCycle(bool forRead);
|
||||
__forceinline void ProcessPendingDma(uint16_t readAddress);
|
||||
__forceinline uint16_t FetchOperand();
|
||||
__forceinline void EndCpuCycle(bool forRead);
|
||||
void IRQ();
|
||||
|
||||
uint8_t GetOPCode()
|
||||
@ -778,6 +784,7 @@ public:
|
||||
CPU(shared_ptr<Console> console);
|
||||
|
||||
uint64_t GetCycleCount() { return _cycleCount; }
|
||||
void SetMasterClockDivider(NesModel region);
|
||||
void SetNmiFlag() { _state.NMIFlag = true; }
|
||||
void ClearNmiFlag() { _state.NMIFlag = false; }
|
||||
void SetIrqMask(uint8_t mask) { _irqMask = mask; }
|
||||
@ -832,11 +839,13 @@ public:
|
||||
|
||||
_cycleCount = c->_cycleCount;
|
||||
_operand = c->_operand;
|
||||
_spriteDmaCounter = c->_spriteDmaCounter;
|
||||
_spriteDmaTransfer = c->_spriteDmaTransfer;
|
||||
_dmcCounter = c->_dmcCounter;
|
||||
_needHalt = c->_needHalt;
|
||||
_dmcDmaRunning = c->_dmcDmaRunning;
|
||||
_cpuWrite = c->_cpuWrite;
|
||||
_needDummyRead = c->_needDummyRead;
|
||||
_needHalt = c->_needHalt;
|
||||
_spriteDmaOffset = c->_spriteDmaOffset;
|
||||
_irqMask = c->_irqMask;
|
||||
_prevRunIrq = c->_prevRunIrq;
|
||||
_runIrq = c->_runIrq;
|
||||
|
@ -421,9 +421,6 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
||||
string modelName = _model == NesModel::PAL ? "PAL" : (_model == NesModel::Dendy ? "Dendy" : "NTSC");
|
||||
string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")";
|
||||
MessageManager::DisplayMessage(messageTitle, FolderUtilities::GetFilename(GetRomInfo().RomName, false));
|
||||
if(_settings->GetOverclockRate() != 100) {
|
||||
MessageManager::DisplayMessage("ClockRate", std::to_string(_settings->GetOverclockRate()) + "%");
|
||||
}
|
||||
_settings->ClearFlags(EmulationFlags::ForceMaxSpeed);
|
||||
|
||||
if(_slave) {
|
||||
@ -451,7 +448,6 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
||||
void Console::ProcessCpuClock()
|
||||
{
|
||||
_mapper->ProcessCpuClock();
|
||||
_ppu->ProcessCpuClock();
|
||||
_apu->ProcessCpuClock();
|
||||
}
|
||||
|
||||
@ -967,6 +963,7 @@ void Console::UpdateNesModel(bool sendNotification)
|
||||
}
|
||||
}
|
||||
|
||||
_cpu->SetMasterClockDivider(model);
|
||||
_mapper->SetNesModel(model);
|
||||
_ppu->SetNesModel(model);
|
||||
_apu->SetNesModel(model);
|
||||
|
@ -58,10 +58,15 @@ void DeltaModulationChannel::StartDmcTransfer()
|
||||
}
|
||||
}
|
||||
|
||||
void DeltaModulationChannel::FillReadBuffer()
|
||||
uint16_t DeltaModulationChannel::GetDmcReadAddress()
|
||||
{
|
||||
return _currentAddr;
|
||||
}
|
||||
|
||||
void DeltaModulationChannel::SetDmcReadBuffer(uint8_t value)
|
||||
{
|
||||
if(_bytesRemaining > 0) {
|
||||
_readBuffer = _console->GetMemoryManager()->Read(_currentAddr, MemoryOperationType::DmcRead);
|
||||
_readBuffer = value;
|
||||
_bufferEmpty = false;
|
||||
|
||||
//"The address is incremented; if it exceeds $FFFF, it is wrapped around to $8000."
|
||||
@ -204,12 +209,16 @@ void DeltaModulationChannel::SetEnabled(bool enabled)
|
||||
_needToRun = false;
|
||||
} else if(_bytesRemaining == 0) {
|
||||
InitSample();
|
||||
StartDmcTransfer();
|
||||
_needInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeltaModulationChannel::NeedToRun()
|
||||
{
|
||||
if(_needInit && (_console->GetCpu()->GetCycleCount() & 0x01) == 0) {
|
||||
StartDmcTransfer();
|
||||
_needInit = false;
|
||||
}
|
||||
return _needToRun;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ private:
|
||||
uint8_t _bitsRemaining = 0;
|
||||
bool _silenceFlag = true;
|
||||
bool _needToRun = false;
|
||||
bool _needInit = false;
|
||||
|
||||
uint8_t _lastValue4011 = 0;
|
||||
|
||||
@ -47,7 +48,8 @@ public:
|
||||
|
||||
void SetEnabled(bool enabled);
|
||||
void StartDmcTransfer();
|
||||
void FillReadBuffer();
|
||||
uint16_t GetDmcReadAddress();
|
||||
void SetDmcReadBuffer(uint8_t value);
|
||||
|
||||
ApuDmcState GetState();
|
||||
};
|
@ -95,6 +95,8 @@ enum EmulationFlags : uint64_t
|
||||
VsDualMuteMaster = 0x200000000000000,
|
||||
VsDualMuteSlave = 0x400000000000000,
|
||||
|
||||
RandomizeCpuPpuAlignment = 0x800000000000000,
|
||||
|
||||
ForceMaxSpeed = 0x4000000000000000,
|
||||
ConsoleMode = 0x8000000000000000,
|
||||
};
|
||||
@ -648,13 +650,9 @@ private:
|
||||
|
||||
uint32_t _rewindBufferSize = 300;
|
||||
|
||||
bool _hasOverclock = false;
|
||||
uint32_t _overclockRate = 100;
|
||||
bool _overclockAdjustApu = true;
|
||||
bool _disableOverclocking = false;
|
||||
uint32_t _extraScanlinesBeforeNmi = 0;
|
||||
uint32_t _extraScanlinesAfterNmi = 0;
|
||||
double _effectiveOverclockRate = 100;
|
||||
|
||||
OverscanDimensions _overscan;
|
||||
VideoFilterType _videoFilterType = VideoFilterType::None;
|
||||
@ -1041,55 +1039,11 @@ public:
|
||||
}
|
||||
|
||||
uint32_t GetEmulationSpeed(bool ignoreTurbo = false);
|
||||
|
||||
void UpdateEffectiveOverclockRate()
|
||||
{
|
||||
if(_disableOverclocking) {
|
||||
_effectiveOverclockRate = 100;
|
||||
} else {
|
||||
_effectiveOverclockRate = _overclockRate;
|
||||
}
|
||||
_hasOverclock = _effectiveOverclockRate != 100;
|
||||
_audioSettingsChanged = true;
|
||||
}
|
||||
|
||||
|
||||
void DisableOverclocking(bool disabled)
|
||||
{
|
||||
if(_disableOverclocking != disabled) {
|
||||
_disableOverclocking = disabled;
|
||||
UpdateEffectiveOverclockRate();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetOverclockRateSetting()
|
||||
{
|
||||
return _overclockRate;
|
||||
}
|
||||
|
||||
bool HasOverclock()
|
||||
{
|
||||
return _hasOverclock;
|
||||
}
|
||||
|
||||
double GetOverclockRate()
|
||||
{
|
||||
return _effectiveOverclockRate;
|
||||
}
|
||||
|
||||
bool GetOverclockAdjustApu()
|
||||
{
|
||||
return _overclockAdjustApu;
|
||||
}
|
||||
|
||||
void SetOverclockRate(uint32_t overclockRate, bool adjustApu)
|
||||
{
|
||||
if(_overclockRate != overclockRate || _overclockAdjustApu != adjustApu) {
|
||||
_overclockRate = overclockRate;
|
||||
_overclockAdjustApu = adjustApu;
|
||||
|
||||
UpdateEffectiveOverclockRate();
|
||||
|
||||
MessageManager::DisplayMessage("ClockRate", std::to_string((uint32_t)GetOverclockRate()) + "%");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1112,8 +1066,6 @@ public:
|
||||
|
||||
_extraScanlinesBeforeNmi = extraScanlinesBeforeNmi;
|
||||
_extraScanlinesAfterNmi = extraScanlinesAfterNmi;
|
||||
|
||||
UpdateEffectiveOverclockRate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ void MemoryAccessCounter::GetNametableChangedData(bool ntChangedData[])
|
||||
uint64_t cpuCycle = _debugger->GetConsole()->GetCpu()->GetCycleCount();
|
||||
NesModel model = _debugger->GetConsole()->GetModel();
|
||||
double frameRate = model == NesModel::NTSC ? 60.1 : 50.01;
|
||||
double overclockRate = _debugger->GetConsole()->GetPpu()->GetOverclockRate() * (_debugger->GetConsole()->GetSettings()->GetOverclockRate() / 100);
|
||||
double overclockRate = _debugger->GetConsole()->GetPpu()->GetOverclockRate() * 100;
|
||||
int32_t cyclesPerFrame = (int32_t)(_debugger->GetConsole()->GetCpu()->GetClockRate(model) / frameRate * overclockRate);
|
||||
|
||||
for(int i = 0; i < 0x1000; i++) {
|
||||
|
@ -247,14 +247,6 @@ void MesenMovie::ApplySettings()
|
||||
|
||||
settings->SetZapperDetectionRadius(LoadInt(_settings, MovieKeys::ZapperDetectionRadius));
|
||||
|
||||
uint32_t cpuClockRate = LoadInt(_settings, MovieKeys::CpuClockRate);
|
||||
if(cpuClockRate != 100) {
|
||||
bool adjustApu = LoadBool(_settings, MovieKeys::OverclockAdjustApu);
|
||||
settings->SetOverclockRate(cpuClockRate, adjustApu);
|
||||
} else {
|
||||
settings->SetOverclockRate(100, true);
|
||||
}
|
||||
|
||||
settings->SetPpuNmiConfig(
|
||||
LoadInt(_settings, MovieKeys::ExtraScanlinesBeforeNmi),
|
||||
LoadInt(_settings, MovieKeys::ExtraScanlinesAfterNmi)
|
||||
|
@ -107,14 +107,10 @@ void MovieRecorder::GetGameSettings(stringstream &out)
|
||||
WriteString(out, MovieKeys::ExpansionDevice, ExpansionPortDeviceNames[(int)settings->GetExpansionDevice()]);
|
||||
}
|
||||
|
||||
WriteInt(out, MovieKeys::CpuClockRate, settings->GetOverclockRateSetting());
|
||||
WriteInt(out, MovieKeys::ExtraScanlinesBeforeNmi, settings->GetPpuExtraScanlinesBeforeNmi());
|
||||
WriteInt(out, MovieKeys::ExtraScanlinesAfterNmi, settings->GetPpuExtraScanlinesAfterNmi());
|
||||
WriteInt(out, MovieKeys::InputPollScanline, settings->GetInputPollScanline());
|
||||
|
||||
if(settings->GetOverclockRateSetting() != 100) {
|
||||
WriteBool(out, MovieKeys::OverclockAdjustApu, settings->GetOverclockAdjustApu());
|
||||
}
|
||||
WriteBool(out, MovieKeys::DisablePpu2004Reads, settings->CheckFlag(EmulationFlags::DisablePpu2004Reads));
|
||||
WriteBool(out, MovieKeys::DisablePaletteRead, settings->CheckFlag(EmulationFlags::DisablePaletteRead));
|
||||
WriteBool(out, MovieKeys::DisableOamAddrBug, settings->CheckFlag(EmulationFlags::DisableOamAddrBug));
|
||||
|
@ -71,10 +71,8 @@ namespace MovieKeys
|
||||
constexpr const char* Controller3 = "Controller3";
|
||||
constexpr const char* Controller4 = "Controller4";
|
||||
constexpr const char* ExpansionDevice = "ExpansionDevice";
|
||||
constexpr const char* CpuClockRate = "CpuClockRate";
|
||||
constexpr const char* ExtraScanlinesBeforeNmi = "ExtraScanlinesBeforeNmi";
|
||||
constexpr const char* ExtraScanlinesAfterNmi = "ExtraScanlinesAfterNmi";
|
||||
constexpr const char* OverclockAdjustApu = "OverclockAdjustApu";
|
||||
constexpr const char* DisablePpu2004Reads = "DisablePpu2004Reads";
|
||||
constexpr const char* DisablePaletteRead = "DisablePaletteRead";
|
||||
constexpr const char* DisableOamAddrBug = "DisableOamAddrBug";
|
||||
|
64
Core/PPU.cpp
64
Core/PPU.cpp
@ -15,6 +15,8 @@
|
||||
PPU::PPU(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_masterClock = 0;
|
||||
_masterClockDivider = 4;
|
||||
_settings = _console->GetSettings();
|
||||
|
||||
_outputBuffers[0] = new uint16_t[256 * 240];
|
||||
@ -42,7 +44,7 @@ PPU::~PPU()
|
||||
|
||||
void PPU::Reset()
|
||||
{
|
||||
_cyclesNeeded = 0;
|
||||
_preventVblFlag = false;
|
||||
|
||||
_needStateUpdate = false;
|
||||
_prevRenderingEnabled = false;
|
||||
@ -73,7 +75,6 @@ void PPU::Reset()
|
||||
_oamCopyDone = false;
|
||||
_renderingEnabled = false;
|
||||
_prevRenderingEnabled = false;
|
||||
_cyclesNeeded = 0.0;
|
||||
|
||||
memset(_hasSprite, 0, sizeof(_hasSprite));
|
||||
memset(_spriteTiles, 0, sizeof(_spriteTiles));
|
||||
@ -118,18 +119,21 @@ void PPU::SetNesModel(NesModel model)
|
||||
_vblankEnd = 260;
|
||||
_standardNmiScanline = 241;
|
||||
_standardVblankEnd = 260;
|
||||
_masterClockDivider = 4;
|
||||
break;
|
||||
case NesModel::PAL:
|
||||
_nmiScanline = 241;
|
||||
_vblankEnd = 310;
|
||||
_standardNmiScanline = 241;
|
||||
_standardVblankEnd = 310;
|
||||
_masterClockDivider = 5;
|
||||
break;
|
||||
case NesModel::Dendy:
|
||||
_nmiScanline = 291;
|
||||
_vblankEnd = 310;
|
||||
_standardNmiScanline = 291;
|
||||
_standardVblankEnd = 310;
|
||||
_masterClockDivider = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -561,8 +565,7 @@ void PPU::UpdateStatusFlag()
|
||||
_console->GetCpu()->ClearNmiFlag();
|
||||
|
||||
if(_cycle == 0) {
|
||||
//"Reading one PPU clock before reads it as clear and never sets the flag or generates NMI for that frame. "
|
||||
_state.Status = ((uint8_t)_statusFlags.SpriteOverflow << 5) | ((uint8_t)_statusFlags.Sprite0Hit << 6);
|
||||
_preventVblFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -639,8 +642,8 @@ void PPU::WriteVram(uint16_t addr, uint8_t value)
|
||||
void PPU::LoadTileInfo()
|
||||
{
|
||||
if(IsRenderingEnabled()) {
|
||||
switch((_cycle - 1) & 0x07) {
|
||||
case 0: {
|
||||
switch(_cycle & 0x07) {
|
||||
case 1: {
|
||||
_previousTile = _currentTile;
|
||||
_currentTile = _nextTile;
|
||||
|
||||
@ -653,18 +656,18 @@ void PPU::LoadTileInfo()
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
case 3: {
|
||||
uint8_t shift = ((_state.VideoRamAddr >> 4) & 0x04) | (_state.VideoRamAddr & 0x02);
|
||||
_nextTile.PaletteOffset = ((ReadVram(GetAttributeAddr()) >> shift) & 0x03) << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
case 5:
|
||||
_nextTile.LowByte = ReadVram(_nextTile.TileAddr);
|
||||
_nextTile.AbsoluteTileAddr = _console->GetMapper()->ToAbsoluteChrAddress(_nextTile.TileAddr);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 7:
|
||||
_nextTile.HighByte = ReadVram(_nextTile.TileAddr + 8);
|
||||
break;
|
||||
}
|
||||
@ -864,10 +867,10 @@ void PPU::UpdateGrayscaleAndIntensifyBits()
|
||||
int pixelNumber;
|
||||
if(_scanline >= 240) {
|
||||
pixelNumber = 61439;
|
||||
} else if(_cycle < 3) {
|
||||
} else if(_cycle < 4) {
|
||||
pixelNumber = (_scanline << 8) - 1;
|
||||
} else if(_cycle <= 258) {
|
||||
pixelNumber = (_scanline << 8) + _cycle - 3;
|
||||
pixelNumber = (_scanline << 8) + _cycle - 4;
|
||||
} else {
|
||||
pixelNumber = (_scanline << 8) + 255;
|
||||
}
|
||||
@ -932,7 +935,7 @@ void PPU::ProcessScanline()
|
||||
//"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)
|
||||
_state.SpriteRamAddr = 0;
|
||||
|
||||
if((_cycle - 260) % 8 == 0) {
|
||||
if((_cycle - 261) % 8 == 0) {
|
||||
//Cycle 260, 268, etc. This is an approximation (each tile is actually loaded in 8 steps (e.g from 257 to 264))
|
||||
LoadSpriteTileInfo();
|
||||
} else if((_cycle - 257) % 8 == 0) {
|
||||
@ -1157,7 +1160,6 @@ void PPU::BeginVBlank()
|
||||
|
||||
void PPU::TriggerNmi()
|
||||
{
|
||||
_statusFlags.VerticalBlank = true;
|
||||
if(_flags.VBlank) {
|
||||
_console->GetCpu()->SetNmiFlag();
|
||||
}
|
||||
@ -1222,7 +1224,6 @@ void PPU::Exec()
|
||||
SendFrame();
|
||||
_frameCount++;
|
||||
} else if(_scanline == _nmiScanline) {
|
||||
BeginVBlank();
|
||||
}
|
||||
} else {
|
||||
//Cycle > 0
|
||||
@ -1231,6 +1232,12 @@ void PPU::Exec()
|
||||
_console->DebugProcessPpuCycle();
|
||||
if(_scanline < 240) {
|
||||
ProcessScanline();
|
||||
} else if(_cycle == 1 && _scanline == _nmiScanline) {
|
||||
if(!_preventVblFlag) {
|
||||
_statusFlags.VerticalBlank = true;
|
||||
BeginVBlank();
|
||||
}
|
||||
_preventVblFlag = false;
|
||||
} else if(_nesModel == NesModel::PAL && _scanline >= _palSpriteEvalScanline) {
|
||||
//"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
|
||||
@ -1299,31 +1306,6 @@ void PPU::UpdateState()
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::ProcessCpuClock()
|
||||
{
|
||||
if(!_settings->HasOverclock()) {
|
||||
Exec();
|
||||
Exec();
|
||||
Exec();
|
||||
if(_nesModel == NesModel::PAL && _console->GetCpu()->GetCycleCount() % 5 == 0) {
|
||||
//PAL PPU runs 3.2 clocks for every CPU clock, so we need to run an extra clock every 5 CPU clocks
|
||||
Exec();
|
||||
}
|
||||
} else {
|
||||
if(_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
|
||||
_cyclesNeeded += 3.2 / (_settings->GetOverclockRate() / 100.0);
|
||||
} else {
|
||||
_cyclesNeeded += 3.0 / (_settings->GetOverclockRate() / 100.0);
|
||||
}
|
||||
|
||||
while(_cyclesNeeded >= 1.0) {
|
||||
Exec();
|
||||
_cyclesNeeded--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* PPU::GetSpriteRam()
|
||||
{
|
||||
//Used by debugger
|
||||
@ -1371,8 +1353,8 @@ void PPU::StreamState(bool saving)
|
||||
_nextTile.PaletteOffset, _nextTile.TileAddr, _previousTile.LowByte, _previousTile.HighByte, _previousTile.PaletteOffset, _spriteIndex, _spriteCount,
|
||||
_secondaryOAMAddr, _sprite0Visible, _oamCopybuffer, _spriteInRange, _sprite0Added, _spriteAddrH, _spriteAddrL, _oamCopyDone, _nesModel,
|
||||
_prevRenderingEnabled, _renderingEnabled, _openBus, _ignoreVramRead, paletteRam, spriteRam, secondarySpriteRam,
|
||||
openBusDecayStamp, _cyclesNeeded, disablePpu2004Reads, disablePaletteRead, disableOamAddrBug, _overflowBugCounter, _updateVramAddr, _updateVramAddrDelay,
|
||||
_needStateUpdate, _ppuBusAddress);
|
||||
openBusDecayStamp, disablePpu2004Reads, disablePaletteRead, disableOamAddrBug, _overflowBugCounter, _updateVramAddr, _updateVramAddrDelay,
|
||||
_needStateUpdate, _ppuBusAddress, _preventVblFlag, _masterClock);
|
||||
|
||||
for(int i = 0; i < 64; i++) {
|
||||
Stream(_spriteTiles[i].SpriteX, _spriteTiles[i].LowByte, _spriteTiles[i].HighByte, _spriteTiles[i].PaletteOffset, _spriteTiles[i].HorizontalMirror, _spriteTiles[i].BackgroundPriority);
|
||||
|
17
Core/PPU.h
17
Core/PPU.h
@ -36,6 +36,8 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
int32_t _scanline;
|
||||
uint32_t _cycle;
|
||||
uint32_t _frameCount;
|
||||
uint64_t _masterClock;
|
||||
uint8_t _masterClockDivider;
|
||||
uint8_t _memoryReadBuffer;
|
||||
|
||||
uint8_t _paletteRAM[0x20];
|
||||
@ -53,7 +55,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
uint16_t _vblankEnd;
|
||||
uint16_t _nmiScanline;
|
||||
uint16_t _palSpriteEvalScanline;
|
||||
|
||||
|
||||
PPUControlFlags _flags;
|
||||
PPUStatusFlags _statusFlags;
|
||||
|
||||
@ -91,8 +93,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
bool _needStateUpdate;
|
||||
bool _renderingEnabled;
|
||||
bool _prevRenderingEnabled;
|
||||
|
||||
double _cyclesNeeded;
|
||||
bool _preventVblFlag;
|
||||
|
||||
uint16_t _updateVramAddr;
|
||||
uint8_t _updateVramAddrDelay;
|
||||
@ -199,7 +200,7 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
double GetOverclockRate();
|
||||
|
||||
void Exec();
|
||||
void ProcessCpuClock();
|
||||
__forceinline void Run(uint64_t runTo);
|
||||
|
||||
uint32_t GetFrameCount()
|
||||
{
|
||||
@ -240,3 +241,11 @@ class PPU : public IMemoryHandler, public Snapshotable
|
||||
return _currentOutputBuffer[y << 8 | x];
|
||||
}
|
||||
};
|
||||
|
||||
void PPU::Run(uint64_t runTo)
|
||||
{
|
||||
while(_masterClock + _masterClockDivider <= runTo) {
|
||||
Exec();
|
||||
_masterClock += _masterClockDivider;
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ bool SaveStateManager::LoadState(istream &stream, bool hashCheckRequired)
|
||||
}
|
||||
|
||||
stream.read((char*)&fileFormatVersion, sizeof(fileFormatVersion));
|
||||
if(fileFormatVersion <= 10) {
|
||||
if(fileFormatVersion <= 11) {
|
||||
MessageManager::DisplayMessage("SaveStates", "SaveStateIncompatibleVersion");
|
||||
return false;
|
||||
} else {
|
||||
|
@ -14,7 +14,7 @@ private:
|
||||
string GetStateFilepath(int stateIndex);
|
||||
|
||||
public:
|
||||
static constexpr uint32_t FileFormatVersion = 11;
|
||||
static constexpr uint32_t FileFormatVersion = 12;
|
||||
|
||||
SaveStateManager(shared_ptr<Console> console);
|
||||
|
||||
|
@ -203,9 +203,6 @@ void SoundMixer::SetNesModel(NesModel model)
|
||||
void SoundMixer::UpdateRates(bool forceUpdate)
|
||||
{
|
||||
uint32_t newRate = _console->GetCpu()->GetClockRate(_model);
|
||||
if(!_settings->GetOverclockAdjustApu()) {
|
||||
newRate = (uint32_t)(newRate * (double)_settings->GetOverclockRate() / 100);
|
||||
}
|
||||
|
||||
if(_settings->CheckFlag(EmulationFlags::IntegerFpsMode)) {
|
||||
//Adjust sample rate when running at 60.0 fps instead of 60.1
|
||||
|
@ -22,12 +22,10 @@ namespace Mesen.GUI.Config
|
||||
public bool EnableOamDecay = false;
|
||||
public bool UseNes101Hvc101Behavior = false;
|
||||
public bool EnableMapperRandomPowerOnState = false;
|
||||
public bool RandomizeCpuPpuAlignment = false;
|
||||
|
||||
public bool UseAlternativeMmc3Irq = false;
|
||||
|
||||
[MinMax(1, 1000)] public UInt32 OverclockRate = 100;
|
||||
public bool OverclockAdjustApu = true;
|
||||
|
||||
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesBeforeNmi = 0;
|
||||
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesAfterNmi = 0;
|
||||
|
||||
@ -60,8 +58,8 @@ namespace Mesen.GUI.Config
|
||||
InteropEmu.SetFlag(EmulationFlags.EnableOamDecay, emulationInfo.EnableOamDecay);
|
||||
InteropEmu.SetFlag(EmulationFlags.UseNes101Hvc101Behavior, emulationInfo.UseNes101Hvc101Behavior);
|
||||
InteropEmu.SetFlag(EmulationFlags.RandomizeMapperPowerOnState, emulationInfo.EnableMapperRandomPowerOnState);
|
||||
InteropEmu.SetFlag(EmulationFlags.RandomizeCpuPpuAlignment, emulationInfo.RandomizeCpuPpuAlignment);
|
||||
|
||||
InteropEmu.SetOverclockRate(emulationInfo.OverclockRate, emulationInfo.OverclockAdjustApu);
|
||||
InteropEmu.SetPpuNmiConfig(emulationInfo.PpuExtraScanlinesBeforeNmi, emulationInfo.PpuExtraScanlinesAfterNmi);
|
||||
|
||||
InteropEmu.SetRamPowerOnState(emulationInfo.RamPowerOnState);
|
||||
|
@ -321,6 +321,7 @@
|
||||
<Control ID="chkDisablePpuReset">No reestableixis la PPU al reiniciar la consola (comportament de la Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Simula el comportament de la NES/HVC-101 (Top-loader / AV Famicom)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Randomize power-on state for mappers</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Forçament</Control>
|
||||
<Control ID="grpOverclocking">Forçament de CPU</Control>
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Do not reset PPU when resetting console (Famicom behavior)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Use NES/HVC-101 (Top-loader / AV Famicom) behavior</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Randomize power-on state for mappers</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Default power on state for RAM:</Control>
|
||||
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">No resetear la PPU al resetear la consola (Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Simular el comportamiento de NES/HVC-101 (Top-loader / AV Famicom)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Aleatorizar el estado de encendido para los mappers</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Overclocking</Control>
|
||||
<Control ID="grpOverclocking">Overclocking de CPU</Control>
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Ne pas faire un reset du PPU lors du reset de la console (Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Simuler le comportement du NES/HVC-101 (Top Loader / AV Famicom)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Démarrer le jeu avec le mapper dans un état aléatoire</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Démarrer le jeu avec un alignement CPU/PPU aléatoire</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">État initial de la mémoire au démarrage : </Control>
|
||||
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Non resettare la PPU quando resetti la console (Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Usa NES/HVC-101 (Top-loader / AV Famicom)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Valori casuali durante accensione per i mapper</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Stato di accensione predefinito per la RAM:</Control>
|
||||
|
||||
|
@ -318,7 +318,8 @@
|
||||
<Control ID="chkDisablePaletteRead">PPUのパレットラムを読み込み不可能にする</Control>
|
||||
<Control ID="chkDisablePpuReset">ゲーム機をリセットする時に、PPUをリセットしない (ファミコン同様)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">AV仕様ファミコン(HVC-101とNES-101)の仕様を使う</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">ランダムな状態でゲームを起動する</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">ランダムなMapper状態でゲームを起動する</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">ランダムなCPU/PPUアラインメントでゲームを起動する</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">起動時のメモリの状態 : </Control>
|
||||
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Não reiniciar a PPU ao reiniciar o console (Comportamento do Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Utilizar comportamento do NES/HVC-101 (Top-loader / AV Famicom)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Aleatorizar o estado de ativação para mapeadores</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">Estado inicial da RAM durante o início:</Control>
|
||||
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Do not reset PPU when resetting console (Famicom behavior)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Use NES/HVC-101 (Top-loader / AV Famicom) behavior</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Randomize power-on state for mappers</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Разгон</Control>
|
||||
<Control ID="grpOverclocking">Разгон CPU</Control>
|
||||
|
@ -320,6 +320,7 @@
|
||||
<Control ID="chkDisablePpuReset">Не перезавантажити PPU при скиданні консолі (Famicom)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">Імітувати поведінку NES/HVC-101 (Top-loader / AV Famicom) поведінку</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">Почати гру з маппером у випадковому стані</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="tpgOverclocking">Розгін</Control>
|
||||
<Control ID="grpOverclocking">Розгін CPU</Control>
|
||||
|
@ -346,6 +346,7 @@
|
||||
<Control ID="chkDisablePpuReset">PPU 不随主机重设 (FC 真机)</Control>
|
||||
<Control ID="chkUseNes101Hvc101Behavior">模拟 HVC-101/NES-101 (Top-Loader/带 AV 端子主机)</Control>
|
||||
<Control ID="chkMapperRandomPowerOnState">随机 Mapper 开机状态</Control>
|
||||
<Control ID="chkRandomizeCpuPpuAlignment">Randomize power-on CPU/PPU alignment</Control>
|
||||
|
||||
<Control ID="lblRamPowerOnState">默认开机 RAM 状态:</Control>
|
||||
<Control ID="tpgOverclocking">超频</Control>
|
||||
|
202
GUI.NET/Forms/Config/frmEmulationConfig.Designer.cs
generated
202
GUI.NET/Forms/Config/frmEmulationConfig.Designer.cs
generated
@ -48,6 +48,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.lblRewindSpeedHint = new System.Windows.Forms.Label();
|
||||
this.tpgAdvanced = new System.Windows.Forms.TabPage();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.chkRandomizeCpuPpuAlignment = new Mesen.GUI.Controls.ctrlRiskyOption();
|
||||
this.lblMiscSettings = new System.Windows.Forms.Label();
|
||||
this.chkMapperRandomPowerOnState = new Mesen.GUI.Controls.ctrlRiskyOption();
|
||||
this.chkEnableOamDecay = new Mesen.GUI.Controls.ctrlRiskyOption();
|
||||
@ -69,15 +70,9 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblEffectiveClockRateDendy = new System.Windows.Forms.Label();
|
||||
this.lblEffectiveClockRateValueDendy = new System.Windows.Forms.Label();
|
||||
this.chkOverclockAdjustApu = new System.Windows.Forms.CheckBox();
|
||||
this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.lblEffectiveClockRatePal = new System.Windows.Forms.Label();
|
||||
this.lblEffectiveClockRateValuePal = new System.Windows.Forms.Label();
|
||||
this.grpOverclocking = new System.Windows.Forms.GroupBox();
|
||||
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.lblClockRate = new System.Windows.Forms.Label();
|
||||
this.nudOverclockRate = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
this.lblClockRatePercent = new System.Windows.Forms.Label();
|
||||
this.grpPpuTiming = new System.Windows.Forms.GroupBox();
|
||||
this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.nudExtraScanlinesAfterNmi = new Mesen.GUI.Controls.MesenNumericUpDown();
|
||||
@ -105,8 +100,6 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.flowLayoutPanel4.SuspendLayout();
|
||||
this.flowLayoutPanel3.SuspendLayout();
|
||||
this.grpOverclocking.SuspendLayout();
|
||||
this.tableLayoutPanel2.SuspendLayout();
|
||||
this.grpPpuTiming.SuspendLayout();
|
||||
this.tableLayoutPanel5.SuspendLayout();
|
||||
this.flowLayoutPanel2.SuspendLayout();
|
||||
@ -115,7 +108,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
// baseConfigPanel
|
||||
//
|
||||
this.baseConfigPanel.Location = new System.Drawing.Point(0, 321);
|
||||
this.baseConfigPanel.Location = new System.Drawing.Point(0, 338);
|
||||
this.baseConfigPanel.Size = new System.Drawing.Size(533, 29);
|
||||
//
|
||||
// tabMain
|
||||
@ -127,7 +120,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tabMain.Location = new System.Drawing.Point(0, 0);
|
||||
this.tabMain.Name = "tabMain";
|
||||
this.tabMain.SelectedIndex = 0;
|
||||
this.tabMain.Size = new System.Drawing.Size(533, 321);
|
||||
this.tabMain.Size = new System.Drawing.Size(533, 338);
|
||||
this.tabMain.TabIndex = 2;
|
||||
//
|
||||
// tpgGeneral
|
||||
@ -136,7 +129,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tpgGeneral.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgGeneral.Name = "tpgGeneral";
|
||||
this.tpgGeneral.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgGeneral.Size = new System.Drawing.Size(525, 295);
|
||||
this.tpgGeneral.Size = new System.Drawing.Size(525, 312);
|
||||
this.tpgGeneral.TabIndex = 0;
|
||||
this.tpgGeneral.Text = "General";
|
||||
this.tpgGeneral.UseVisualStyleBackColor = true;
|
||||
@ -161,7 +154,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel4.Size = new System.Drawing.Size(519, 289);
|
||||
this.tableLayoutPanel4.Size = new System.Drawing.Size(519, 306);
|
||||
this.tableLayoutPanel4.TabIndex = 0;
|
||||
//
|
||||
// flowLayoutPanel9
|
||||
@ -356,7 +349,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgAdvanced.Name = "tpgAdvanced";
|
||||
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgAdvanced.Size = new System.Drawing.Size(525, 295);
|
||||
this.tpgAdvanced.Size = new System.Drawing.Size(525, 312);
|
||||
this.tpgAdvanced.TabIndex = 1;
|
||||
this.tpgAdvanced.Text = "Advanced";
|
||||
this.tpgAdvanced.UseVisualStyleBackColor = true;
|
||||
@ -365,25 +358,27 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
this.tableLayoutPanel1.ColumnCount = 1;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblMiscSettings, 0, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkRandomizeCpuPpuAlignment, 0, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblMiscSettings, 0, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkMapperRandomPowerOnState, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkEnableOamDecay, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel8, 0, 3);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePaletteRead, 0, 10);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisableOamAddrBug, 0, 8);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePpuReset, 0, 7);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePpu2004Reads, 0, 9);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkUseNes101Hvc101Behavior, 0, 6);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkAllowInvalidInput, 0, 11);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkUseAlternativeMmc3Irq, 0, 5);
|
||||
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel8, 0, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePaletteRead, 0, 11);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisableOamAddrBug, 0, 9);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePpuReset, 0, 8);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkDisablePpu2004Reads, 0, 10);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkUseNes101Hvc101Behavior, 0, 7);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkAllowInvalidInput, 0, 12);
|
||||
this.tableLayoutPanel1.Controls.Add(this.chkUseAlternativeMmc3Irq, 0, 6);
|
||||
this.tableLayoutPanel1.Controls.Add(this.lblDeveloperSettings, 0, 0);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 13;
|
||||
this.tableLayoutPanel1.RowCount = 14;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
@ -394,15 +389,28 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(519, 289);
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(519, 306);
|
||||
this.tableLayoutPanel1.TabIndex = 0;
|
||||
//
|
||||
// chkRandomizeCpuPpuAlignment
|
||||
//
|
||||
this.chkRandomizeCpuPpuAlignment.AutoSize = true;
|
||||
this.chkRandomizeCpuPpuAlignment.Checked = false;
|
||||
this.chkRandomizeCpuPpuAlignment.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkRandomizeCpuPpuAlignment.Location = new System.Drawing.Point(10, 66);
|
||||
this.chkRandomizeCpuPpuAlignment.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkRandomizeCpuPpuAlignment.MinimumSize = new System.Drawing.Size(0, 23);
|
||||
this.chkRandomizeCpuPpuAlignment.Name = "chkRandomizeCpuPpuAlignment";
|
||||
this.chkRandomizeCpuPpuAlignment.Size = new System.Drawing.Size(509, 23);
|
||||
this.chkRandomizeCpuPpuAlignment.TabIndex = 36;
|
||||
this.chkRandomizeCpuPpuAlignment.Text = "Randomize power-on CPU/PPU alignment";
|
||||
//
|
||||
// lblMiscSettings
|
||||
//
|
||||
this.lblMiscSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.lblMiscSettings.AutoSize = true;
|
||||
this.lblMiscSettings.ForeColor = System.Drawing.SystemColors.GrayText;
|
||||
this.lblMiscSettings.Location = new System.Drawing.Point(0, 98);
|
||||
this.lblMiscSettings.Location = new System.Drawing.Point(0, 118);
|
||||
this.lblMiscSettings.Margin = new System.Windows.Forms.Padding(0, 0, 3, 2);
|
||||
this.lblMiscSettings.Name = "lblMiscSettings";
|
||||
this.lblMiscSettings.Size = new System.Drawing.Size(115, 13);
|
||||
@ -439,7 +447,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.flowLayoutPanel8.Controls.Add(this.lblRamPowerOnState);
|
||||
this.flowLayoutPanel8.Controls.Add(this.cboRamPowerOnState);
|
||||
this.flowLayoutPanel8.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel8.Location = new System.Drawing.Point(7, 66);
|
||||
this.flowLayoutPanel8.Location = new System.Drawing.Point(7, 86);
|
||||
this.flowLayoutPanel8.Margin = new System.Windows.Forms.Padding(7, 0, 0, 0);
|
||||
this.flowLayoutPanel8.Name = "flowLayoutPanel8";
|
||||
this.flowLayoutPanel8.Size = new System.Drawing.Size(512, 27);
|
||||
@ -468,7 +476,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
this.chkDisablePaletteRead.Checked = false;
|
||||
this.chkDisablePaletteRead.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkDisablePaletteRead.Location = new System.Drawing.Point(10, 228);
|
||||
this.chkDisablePaletteRead.Location = new System.Drawing.Point(10, 248);
|
||||
this.chkDisablePaletteRead.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkDisablePaletteRead.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.chkDisablePaletteRead.Name = "chkDisablePaletteRead";
|
||||
@ -480,7 +488,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
this.chkDisableOamAddrBug.Checked = false;
|
||||
this.chkDisableOamAddrBug.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkDisableOamAddrBug.Location = new System.Drawing.Point(10, 182);
|
||||
this.chkDisableOamAddrBug.Location = new System.Drawing.Point(10, 202);
|
||||
this.chkDisableOamAddrBug.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkDisableOamAddrBug.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.chkDisableOamAddrBug.Name = "chkDisableOamAddrBug";
|
||||
@ -492,7 +500,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
this.chkDisablePpuReset.Checked = false;
|
||||
this.chkDisablePpuReset.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkDisablePpuReset.Location = new System.Drawing.Point(10, 159);
|
||||
this.chkDisablePpuReset.Location = new System.Drawing.Point(10, 179);
|
||||
this.chkDisablePpuReset.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkDisablePpuReset.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.chkDisablePpuReset.Name = "chkDisablePpuReset";
|
||||
@ -504,7 +512,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
//
|
||||
this.chkDisablePpu2004Reads.Checked = false;
|
||||
this.chkDisablePpu2004Reads.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkDisablePpu2004Reads.Location = new System.Drawing.Point(10, 205);
|
||||
this.chkDisablePpu2004Reads.Location = new System.Drawing.Point(10, 225);
|
||||
this.chkDisablePpu2004Reads.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkDisablePpu2004Reads.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.chkDisablePpu2004Reads.Name = "chkDisablePpu2004Reads";
|
||||
@ -515,7 +523,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
// chkUseNes101Hvc101Behavior
|
||||
//
|
||||
this.chkUseNes101Hvc101Behavior.AutoSize = true;
|
||||
this.chkUseNes101Hvc101Behavior.Location = new System.Drawing.Point(13, 139);
|
||||
this.chkUseNes101Hvc101Behavior.Location = new System.Drawing.Point(13, 159);
|
||||
this.chkUseNes101Hvc101Behavior.Margin = new System.Windows.Forms.Padding(13, 3, 3, 3);
|
||||
this.chkUseNes101Hvc101Behavior.Name = "chkUseNes101Hvc101Behavior";
|
||||
this.chkUseNes101Hvc101Behavior.Size = new System.Drawing.Size(292, 17);
|
||||
@ -528,7 +536,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.chkAllowInvalidInput.AutoSize = true;
|
||||
this.chkAllowInvalidInput.Checked = false;
|
||||
this.chkAllowInvalidInput.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.chkAllowInvalidInput.Location = new System.Drawing.Point(10, 251);
|
||||
this.chkAllowInvalidInput.Location = new System.Drawing.Point(10, 271);
|
||||
this.chkAllowInvalidInput.Margin = new System.Windows.Forms.Padding(10, 0, 0, 0);
|
||||
this.chkAllowInvalidInput.MinimumSize = new System.Drawing.Size(0, 23);
|
||||
this.chkAllowInvalidInput.Name = "chkAllowInvalidInput";
|
||||
@ -539,7 +547,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
// chkUseAlternativeMmc3Irq
|
||||
//
|
||||
this.chkUseAlternativeMmc3Irq.AutoSize = true;
|
||||
this.chkUseAlternativeMmc3Irq.Location = new System.Drawing.Point(13, 116);
|
||||
this.chkUseAlternativeMmc3Irq.Location = new System.Drawing.Point(13, 136);
|
||||
this.chkUseAlternativeMmc3Irq.Margin = new System.Windows.Forms.Padding(13, 3, 3, 3);
|
||||
this.chkUseAlternativeMmc3Irq.Name = "chkUseAlternativeMmc3Irq";
|
||||
this.chkUseAlternativeMmc3Irq.Size = new System.Drawing.Size(197, 17);
|
||||
@ -566,7 +574,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tpgOverclocking.Location = new System.Drawing.Point(4, 22);
|
||||
this.tpgOverclocking.Name = "tpgOverclocking";
|
||||
this.tpgOverclocking.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tpgOverclocking.Size = new System.Drawing.Size(525, 295);
|
||||
this.tpgOverclocking.Size = new System.Drawing.Size(525, 312);
|
||||
this.tpgOverclocking.TabIndex = 2;
|
||||
this.tpgOverclocking.Text = "Overclocking";
|
||||
this.tpgOverclocking.UseVisualStyleBackColor = true;
|
||||
@ -576,7 +584,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.picHint.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.picHint.BackgroundImage = global::Mesen.GUI.Properties.Resources.Help;
|
||||
this.picHint.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
|
||||
this.picHint.Location = new System.Drawing.Point(12, 15);
|
||||
this.picHint.Location = new System.Drawing.Point(12, 24);
|
||||
this.picHint.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
|
||||
this.picHint.Name = "picHint";
|
||||
this.picHint.Size = new System.Drawing.Size(16, 16);
|
||||
@ -591,9 +599,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.Controls.Add(this.lblOverclockHint, 0, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel4, 0, 5);
|
||||
this.tableLayoutPanel3.Controls.Add(this.chkOverclockAdjustApu, 0, 6);
|
||||
this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel3, 0, 4);
|
||||
this.tableLayoutPanel3.Controls.Add(this.grpOverclocking, 0, 2);
|
||||
this.tableLayoutPanel3.Controls.Add(this.grpPpuTiming, 0, 1);
|
||||
this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel2, 0, 3);
|
||||
this.tableLayoutPanel3.Controls.Add(this.flowLayoutPanel7, 0, 7);
|
||||
@ -609,7 +615,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(519, 289);
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(519, 306);
|
||||
this.tableLayoutPanel3.TabIndex = 0;
|
||||
//
|
||||
// lblOverclockHint
|
||||
@ -619,7 +625,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.lblOverclockHint.Location = new System.Drawing.Point(3, 0);
|
||||
this.lblOverclockHint.Name = "lblOverclockHint";
|
||||
this.lblOverclockHint.Padding = new System.Windows.Forms.Padding(25, 0, 0, 0);
|
||||
this.lblOverclockHint.Size = new System.Drawing.Size(513, 41);
|
||||
this.lblOverclockHint.Size = new System.Drawing.Size(517, 41);
|
||||
this.lblOverclockHint.TabIndex = 1;
|
||||
this.lblOverclockHint.Text = resources.GetString("lblOverclockHint.Text");
|
||||
//
|
||||
@ -628,7 +634,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.flowLayoutPanel4.Controls.Add(this.lblEffectiveClockRateDendy);
|
||||
this.flowLayoutPanel4.Controls.Add(this.lblEffectiveClockRateValueDendy);
|
||||
this.flowLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel4.Location = new System.Drawing.Point(0, 203);
|
||||
this.flowLayoutPanel4.Location = new System.Drawing.Point(0, 152);
|
||||
this.flowLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel4.Name = "flowLayoutPanel4";
|
||||
this.flowLayoutPanel4.Size = new System.Drawing.Size(519, 20);
|
||||
@ -653,22 +659,12 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.lblEffectiveClockRateValueDendy.TabIndex = 1;
|
||||
this.lblEffectiveClockRateValueDendy.Text = "100%";
|
||||
//
|
||||
// chkOverclockAdjustApu
|
||||
//
|
||||
this.chkOverclockAdjustApu.AutoSize = true;
|
||||
this.chkOverclockAdjustApu.Location = new System.Drawing.Point(3, 226);
|
||||
this.chkOverclockAdjustApu.Name = "chkOverclockAdjustApu";
|
||||
this.chkOverclockAdjustApu.Size = new System.Drawing.Size(401, 17);
|
||||
this.chkOverclockAdjustApu.TabIndex = 10;
|
||||
this.chkOverclockAdjustApu.Text = "Do not overclock APU (prevents sound pitch changes caused by overclocking)";
|
||||
this.chkOverclockAdjustApu.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// flowLayoutPanel3
|
||||
//
|
||||
this.flowLayoutPanel3.Controls.Add(this.lblEffectiveClockRatePal);
|
||||
this.flowLayoutPanel3.Controls.Add(this.lblEffectiveClockRateValuePal);
|
||||
this.flowLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel3.Location = new System.Drawing.Point(0, 186);
|
||||
this.flowLayoutPanel3.Location = new System.Drawing.Point(0, 135);
|
||||
this.flowLayoutPanel3.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel3.Name = "flowLayoutPanel3";
|
||||
this.flowLayoutPanel3.Size = new System.Drawing.Size(519, 17);
|
||||
@ -693,89 +689,6 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.lblEffectiveClockRateValuePal.TabIndex = 1;
|
||||
this.lblEffectiveClockRateValuePal.Text = "100%";
|
||||
//
|
||||
// grpOverclocking
|
||||
//
|
||||
this.grpOverclocking.Controls.Add(this.tableLayoutPanel2);
|
||||
this.grpOverclocking.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.grpOverclocking.Location = new System.Drawing.Point(3, 121);
|
||||
this.grpOverclocking.Name = "grpOverclocking";
|
||||
this.grpOverclocking.Size = new System.Drawing.Size(513, 45);
|
||||
this.grpOverclocking.TabIndex = 6;
|
||||
this.grpOverclocking.TabStop = false;
|
||||
this.grpOverclocking.Text = "Overclocking";
|
||||
//
|
||||
// tableLayoutPanel2
|
||||
//
|
||||
this.tableLayoutPanel2.ColumnCount = 4;
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
|
||||
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblClockRate, 0, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.nudOverclockRate, 1, 0);
|
||||
this.tableLayoutPanel2.Controls.Add(this.lblClockRatePercent, 2, 0);
|
||||
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
|
||||
this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
|
||||
this.tableLayoutPanel2.RowCount = 1;
|
||||
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
|
||||
this.tableLayoutPanel2.Size = new System.Drawing.Size(507, 26);
|
||||
this.tableLayoutPanel2.TabIndex = 0;
|
||||
//
|
||||
// lblClockRate
|
||||
//
|
||||
this.lblClockRate.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblClockRate.AutoSize = true;
|
||||
this.lblClockRate.Location = new System.Drawing.Point(3, 7);
|
||||
this.lblClockRate.Margin = new System.Windows.Forms.Padding(3, 0, 0, 0);
|
||||
this.lblClockRate.Name = "lblClockRate";
|
||||
this.lblClockRate.Size = new System.Drawing.Size(107, 13);
|
||||
this.lblClockRate.TabIndex = 1;
|
||||
this.lblClockRate.Text = "Clock Rate Multiplier:";
|
||||
//
|
||||
// nudOverclockRate
|
||||
//
|
||||
this.nudOverclockRate.DecimalPlaces = 0;
|
||||
this.nudOverclockRate.Increment = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudOverclockRate.Location = new System.Drawing.Point(110, 3);
|
||||
this.nudOverclockRate.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
|
||||
this.nudOverclockRate.Maximum = new decimal(new int[] {
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudOverclockRate.MaximumSize = new System.Drawing.Size(10000, 20);
|
||||
this.nudOverclockRate.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.nudOverclockRate.MinimumSize = new System.Drawing.Size(0, 21);
|
||||
this.nudOverclockRate.Name = "nudOverclockRate";
|
||||
this.nudOverclockRate.Size = new System.Drawing.Size(46, 21);
|
||||
this.nudOverclockRate.TabIndex = 1;
|
||||
this.nudOverclockRate.Value = new decimal(new int[] {
|
||||
100,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// lblClockRatePercent
|
||||
//
|
||||
this.lblClockRatePercent.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.lblClockRatePercent.AutoSize = true;
|
||||
this.lblClockRatePercent.Location = new System.Drawing.Point(156, 7);
|
||||
this.lblClockRatePercent.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0);
|
||||
this.lblClockRatePercent.Name = "lblClockRatePercent";
|
||||
this.lblClockRatePercent.Size = new System.Drawing.Size(90, 13);
|
||||
this.lblClockRatePercent.TabIndex = 1;
|
||||
this.lblClockRatePercent.Text = "% (Default: 100%)";
|
||||
//
|
||||
// grpPpuTiming
|
||||
//
|
||||
this.grpPpuTiming.Controls.Add(this.tableLayoutPanel5);
|
||||
@ -893,7 +806,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblEffectiveClockRate);
|
||||
this.flowLayoutPanel2.Controls.Add(this.lblEffectiveClockRateValue);
|
||||
this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel2.Location = new System.Drawing.Point(0, 169);
|
||||
this.flowLayoutPanel2.Location = new System.Drawing.Point(0, 118);
|
||||
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
|
||||
this.flowLayoutPanel2.Size = new System.Drawing.Size(519, 17);
|
||||
@ -923,10 +836,10 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.flowLayoutPanel7.Controls.Add(this.chkShowLagCounter);
|
||||
this.flowLayoutPanel7.Controls.Add(this.btnResetLagCounter);
|
||||
this.flowLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.flowLayoutPanel7.Location = new System.Drawing.Point(0, 246);
|
||||
this.flowLayoutPanel7.Location = new System.Drawing.Point(0, 172);
|
||||
this.flowLayoutPanel7.Margin = new System.Windows.Forms.Padding(0);
|
||||
this.flowLayoutPanel7.Name = "flowLayoutPanel7";
|
||||
this.flowLayoutPanel7.Size = new System.Drawing.Size(519, 43);
|
||||
this.flowLayoutPanel7.Size = new System.Drawing.Size(519, 134);
|
||||
this.flowLayoutPanel7.TabIndex = 12;
|
||||
//
|
||||
// chkShowLagCounter
|
||||
@ -961,12 +874,12 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.AutoSize = true;
|
||||
this.ClientSize = new System.Drawing.Size(533, 350);
|
||||
this.ClientSize = new System.Drawing.Size(533, 367);
|
||||
this.Controls.Add(this.tabMain);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.MinimumSize = new System.Drawing.Size(503, 322);
|
||||
this.MinimumSize = new System.Drawing.Size(503, 367);
|
||||
this.Name = "frmEmulationConfig";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||
this.Text = "Emulation Settings";
|
||||
@ -992,14 +905,10 @@ namespace Mesen.GUI.Forms.Config
|
||||
this.tpgOverclocking.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picHint)).EndInit();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel3.PerformLayout();
|
||||
this.flowLayoutPanel4.ResumeLayout(false);
|
||||
this.flowLayoutPanel4.PerformLayout();
|
||||
this.flowLayoutPanel3.ResumeLayout(false);
|
||||
this.flowLayoutPanel3.PerformLayout();
|
||||
this.grpOverclocking.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.ResumeLayout(false);
|
||||
this.tableLayoutPanel2.PerformLayout();
|
||||
this.grpPpuTiming.ResumeLayout(false);
|
||||
this.tableLayoutPanel5.ResumeLayout(false);
|
||||
this.tableLayoutPanel5.PerformLayout();
|
||||
@ -1020,11 +929,6 @@ namespace Mesen.GUI.Forms.Config
|
||||
private ctrlRiskyOption chkAllowInvalidInput;
|
||||
private System.Windows.Forms.TabPage tpgOverclocking;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.GroupBox grpOverclocking;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
|
||||
private System.Windows.Forms.Label lblClockRate;
|
||||
private MesenNumericUpDown nudOverclockRate;
|
||||
private System.Windows.Forms.Label lblClockRatePercent;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel6;
|
||||
private MesenNumericUpDown nudEmulationSpeed;
|
||||
@ -1042,7 +946,6 @@ namespace Mesen.GUI.Forms.Config
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3;
|
||||
private System.Windows.Forms.Label lblEffectiveClockRatePal;
|
||||
private System.Windows.Forms.Timer tmrUpdateClockRate;
|
||||
private System.Windows.Forms.CheckBox chkOverclockAdjustApu;
|
||||
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4;
|
||||
private System.Windows.Forms.Label lblEffectiveClockRateDendy;
|
||||
private System.Windows.Forms.Label lblEffectiveClockRateValueDendy;
|
||||
@ -1072,5 +975,6 @@ namespace Mesen.GUI.Forms.Config
|
||||
private System.Windows.Forms.CheckBox chkUseNes101Hvc101Behavior;
|
||||
private System.Windows.Forms.Label lblDeveloperSettings;
|
||||
private System.Windows.Forms.Label lblMiscSettings;
|
||||
private ctrlRiskyOption chkRandomizeCpuPpuAlignment;
|
||||
}
|
||||
}
|
@ -37,9 +37,7 @@ namespace Mesen.GUI.Forms.Config
|
||||
AddBinding("EnableOamDecay", chkEnableOamDecay);
|
||||
AddBinding("UseNes101Hvc101Behavior", chkUseNes101Hvc101Behavior);
|
||||
AddBinding("EnableMapperRandomPowerOnState", chkMapperRandomPowerOnState);
|
||||
|
||||
AddBinding("OverclockRate", nudOverclockRate);
|
||||
AddBinding("OverclockAdjustApu", chkOverclockAdjustApu);
|
||||
AddBinding("RandomizeCpuPpuAlignment", chkRandomizeCpuPpuAlignment);
|
||||
|
||||
AddBinding("PpuExtraScanlinesBeforeNmi", nudExtraScanlinesBeforeNmi);
|
||||
AddBinding("PpuExtraScanlinesAfterNmi", nudExtraScanlinesAfterNmi);
|
||||
@ -57,9 +55,9 @@ namespace Mesen.GUI.Forms.Config
|
||||
|
||||
private void tmrUpdateClockRate_Tick(object sender, EventArgs e)
|
||||
{
|
||||
decimal clockRateMultiplierNtsc = (nudOverclockRate.Value * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 262));
|
||||
decimal clockRateMultiplierPal = (nudOverclockRate.Value * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 312));
|
||||
decimal clockRateMultiplierDendy = (nudOverclockRate.Value * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 312));
|
||||
decimal clockRateMultiplierNtsc = (100 * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 262));
|
||||
decimal clockRateMultiplierPal = (100 * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 312));
|
||||
decimal clockRateMultiplierDendy = (100 * (1 + (nudExtraScanlinesAfterNmi.Value + nudExtraScanlinesBeforeNmi.Value) / 312));
|
||||
lblEffectiveClockRateValue.Text = (1789773 * clockRateMultiplierNtsc / 100000000).ToString("#.####") + " mhz (" + ((int)clockRateMultiplierNtsc).ToString() + "%)";
|
||||
lblEffectiveClockRateValuePal.Text = (1662607 * clockRateMultiplierPal / 100000000).ToString("#.####") + " mhz (" + ((int)clockRateMultiplierPal).ToString() + "%)";
|
||||
lblEffectiveClockRateValueDendy.Text = (1773448 * clockRateMultiplierDendy / 100000000).ToString("#.####") + " mhz (" + ((int)clockRateMultiplierDendy).ToString() + "%)";
|
||||
|
@ -201,7 +201,6 @@ namespace Mesen.GUI
|
||||
[DllImport(DLLPath)] public static extern void SetTurboRewindSpeed(UInt32 turboSpeed, UInt32 rewindSpeed);
|
||||
[DllImport(DLLPath)] public static extern void SetRewindBufferSize(UInt32 seconds);
|
||||
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsRewinding();
|
||||
[DllImport(DLLPath)] public static extern void SetOverclockRate(UInt32 overclockRate, [MarshalAs(UnmanagedType.I1)]bool adjustApu);
|
||||
[DllImport(DLLPath)] public static extern void SetPpuNmiConfig(UInt32 extraScanlinesBeforeNmi, UInt32 extraScanlineAfterNmi);
|
||||
[DllImport(DLLPath)] public static extern void SetOverscanDimensions(UInt32 left, UInt32 right, UInt32 top, UInt32 bottom);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoScale(double scale, ConsoleId consoleId = ConsoleId.Master);
|
||||
@ -1704,6 +1703,8 @@ namespace Mesen.GUI
|
||||
VsDualMuteMaster = 0x200000000000000,
|
||||
VsDualMuteSlave = 0x400000000000000,
|
||||
|
||||
RandomizeCpuPpuAlignment = 0x800000000000000,
|
||||
|
||||
ForceMaxSpeed = 0x4000000000000000,
|
||||
ConsoleMode = 0x8000000000000000,
|
||||
}
|
||||
|
@ -640,7 +640,6 @@ namespace InteropEmu {
|
||||
shared_ptr<RewindManager> rewindManager = _console->GetRewindManager();
|
||||
return rewindManager ? rewindManager->IsRewinding() : false;
|
||||
}
|
||||
DllExport void __stdcall SetOverclockRate(uint32_t overclockRate, bool adjustApu) { _settings->SetOverclockRate(overclockRate, adjustApu); }
|
||||
DllExport void __stdcall SetPpuNmiConfig(uint32_t extraScanlinesBeforeNmi, uint32_t extraScanlinesAfterNmi) { _settings->SetPpuNmiConfig(extraScanlinesBeforeNmi, extraScanlinesAfterNmi); }
|
||||
DllExport void __stdcall SetVideoScale(double scale, ConsoleId consoleId) { GetConsoleById(consoleId)->GetSettings()->SetVideoScale(scale); }
|
||||
DllExport void __stdcall SetScreenRotation(uint32_t angle) { _settings->SetScreenRotation(angle); }
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../Core/EmulationSettings.h"
|
||||
#include "../Core/CheatManager.h"
|
||||
#include "../Core/HdData.h"
|
||||
#include "../Core/SaveStateManager.h"
|
||||
#include "../Core/DebuggerTypes.h"
|
||||
#include "../Core/GameDatabase.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
@ -658,7 +659,7 @@ extern "C" {
|
||||
RETRO_API bool retro_serialize(void *data, size_t size)
|
||||
{
|
||||
std::stringstream ss;
|
||||
_console->SaveState(ss);
|
||||
_console->GetSaveStateManager()->SaveState(ss);
|
||||
|
||||
string saveStateData = ss.str();
|
||||
memset(data, 0, size);
|
||||
@ -669,8 +670,9 @@ extern "C" {
|
||||
|
||||
RETRO_API bool retro_unserialize(const void *data, size_t size)
|
||||
{
|
||||
_console->LoadState((uint8_t*)data, (uint32_t)size);
|
||||
return true;
|
||||
std::stringstream ss;
|
||||
ss.write((char*)data, size);
|
||||
return _console->GetSaveStateManager()->LoadState(ss, false);
|
||||
}
|
||||
|
||||
RETRO_API void retro_cheat_reset()
|
||||
@ -996,7 +998,7 @@ extern "C" {
|
||||
//Retroarch doesn't like this for netplay or rewinding - it requires the states to always be the exact same size
|
||||
//So we need to send a large enough size to Retroarch to ensure Mesen's state will always fit within that buffer.
|
||||
std::stringstream ss;
|
||||
_console->SaveState(ss);
|
||||
_console->GetSaveStateManager()->SaveState(ss);
|
||||
|
||||
//Round up to the next 1kb multiple
|
||||
_saveStateSize = ((ss.str().size() * 2) + 0x400) & ~0x3FF;
|
||||
|
Loading…
Reference in New Issue
Block a user