Emulation: Added option to randomize power on state for the PPU (for homebrew/romhacking purposes)

This commit is contained in:
Sour 2019-12-11 21:44:42 -05:00
parent 0eb5264da3
commit b94ca9b728
8 changed files with 168 additions and 40 deletions

View file

@ -13,6 +13,9 @@ EmuSettings::EmuSettings(Console* console)
_flags = 0;
_debuggerFlags = 0;
_inputConfigVersion = 0;
std::random_device rd;
_mt = std::mt19937(rd());
}
uint32_t EmuSettings::GetVersion()
@ -287,16 +290,25 @@ void EmuSettings::InitializeRam(void* data, uint32_t length)
case RamState::AllZeros: memset(data, 0, length); break;
case RamState::AllOnes: memset(data, 0xFF, length); break;
case RamState::Random:
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<> dist(0, 255);
for(uint32_t i = 0; i < length; i++) {
((uint8_t*)data)[i] = dist(mt);
((uint8_t*)data)[i] = dist(_mt);
}
break;
}
}
int EmuSettings::GetRandomValue(int maxValue)
{
std::uniform_int_distribution<> dist(0, maxValue);
return dist(_mt);
}
bool EmuSettings::GetRandomBool()
{
return GetRandomValue(1) == 1;
}
bool EmuSettings::IsInputEnabled()
{
return !CheckFlag(EmulationFlags::InBackground) || _preferences.AllowBackgroundInput;

View file

@ -1,6 +1,7 @@
#pragma once
#include "stdafx.h"
#include "SettingTypes.h"
#include <random>
class Console;
@ -8,6 +9,7 @@ class EmuSettings
{
private:
Console* _console;
std::mt19937 _mt;
VideoConfig _video;
AudioConfig _audio;
@ -71,6 +73,9 @@ public:
void SetDebuggerFlag(DebuggerFlags flag, bool enabled);
bool CheckDebuggerFlag(DebuggerFlags flags);
int GetRandomValue(int maxValue);
bool GetRandomBool();
void InitializeRam(void* data, uint32_t length);
bool IsInputEnabled();

View file

@ -49,10 +49,6 @@ Ppu::~Ppu()
void Ppu::PowerOn()
{
//Boot up PPU in deterministic state (for now, need to randomize this)
_state = {};
_state.ForcedVblank = true;
_skipRender = false;
_regs = _console->GetInternalRegisters().get();
_settings = _console->GetSettings().get();
@ -60,25 +56,20 @@ void Ppu::PowerOn()
_memoryManager = _console->GetMemoryManager().get();
_currentBuffer = _outputBuffers[0];
_state.Layers[0] = {};
_state.Layers[1] = {};
_state.Layers[2] = {};
_state.Layers[3] = {};
_state.CgramAddress = 0;
_state = {};
_state.ForcedVblank = true;
_state.VramIncrementValue = 1;
if(_settings->GetEmulationConfig().EnableRandomPowerOnState) {
RandomizeState();
}
_settings->InitializeRam(_vram, Ppu::VideoRamSize);
_settings->InitializeRam(_cgram, Ppu::CgRamSize);
_settings->InitializeRam(_oamRam, Ppu::SpriteRamSize);
memset(_spriteIndexes, 0xFF, sizeof(_spriteIndexes));
_state.VramAddress = 0;
_state.VramIncrementValue = 1;
_state.VramAddressRemapping = 0;
_state.VramAddrIncrementOnSecondReg = false;
UpdateNmiScanline();
}
@ -2211,6 +2202,101 @@ void Ppu::Serialize(Serializer &s)
s.Stream(_hOffset, _vOffset, _fetchBgStart, _fetchBgEnd, _fetchSpriteStart, _fetchSpriteEnd);
}
void Ppu::RandomizeState()
{
_state.ScreenBrightness = _settings->GetRandomValue(0x0F);
_state.Mode7.CenterX = _settings->GetRandomValue(0xFFFF);
_state.Mode7.CenterY = _settings->GetRandomValue(0xFFFF);
_state.Mode7.FillWithTile0 = _settings->GetRandomBool();
_state.Mode7.HorizontalMirroring = _settings->GetRandomBool();
_state.Mode7.HScroll = _settings->GetRandomValue(0x1FFF);
_state.Mode7.HScrollLatch = _settings->GetRandomValue(0x1FFF);
_state.Mode7.LargeMap = _settings->GetRandomBool();
_state.Mode7.Matrix[0] = _settings->GetRandomValue(0xFFFF);
_state.Mode7.Matrix[1] = _settings->GetRandomValue(0xFFFF);
_state.Mode7.Matrix[2] = _settings->GetRandomValue(0xFFFF);
_state.Mode7.Matrix[3] = _settings->GetRandomValue(0xFFFF);
_state.Mode7.ValueLatch = _settings->GetRandomValue(0xFF);
_state.Mode7.VerticalMirroring = _settings->GetRandomBool();
_state.Mode7.VScroll = _settings->GetRandomValue(0x1FFF);
_state.Mode7.VScrollLatch = _settings->GetRandomValue(0x1FFF);
_state.BgMode = _settings->GetRandomValue(7);
_state.Mode1Bg3Priority = _settings->GetRandomBool();
_state.MainScreenLayers = _settings->GetRandomValue(0x1F);
_state.SubScreenLayers = _settings->GetRandomValue(0x1F);
for(int i = 0; i < 4; i++) {
_state.Layers[i].TilemapAddress = _settings->GetRandomValue(0x1F) << 10;
_state.Layers[i].ChrAddress = _settings->GetRandomValue(0x07) << 12;
_state.Layers[i].HScroll = _settings->GetRandomValue(0x1FFF);
_state.Layers[i].VScroll = _settings->GetRandomValue(0x1FFF);
_state.Layers[i].DoubleWidth = _settings->GetRandomBool();
_state.Layers[i].DoubleHeight = _settings->GetRandomBool();
_state.Layers[i].LargeTiles = _settings->GetRandomBool();
}
for(int i = 0; i < 2; i++) {
_state.Window[i].Left = _settings->GetRandomValue(0xFF);
_state.Window[i].Right = _settings->GetRandomValue(0xFF);
for(int j = 0; j < 6; j++) {
_state.Window[i].ActiveLayers[j] = _settings->GetRandomBool();
_state.Window[i].InvertedLayers[j] = _settings->GetRandomBool();
}
}
for(int i = 0; i < 6; i++) {
_state.MaskLogic[i] = (WindowMaskLogic)_settings->GetRandomValue(3);
}
for(int i = 0; i < 5; i++) {
_state.WindowMaskMain[i] = _settings->GetRandomBool();
_state.WindowMaskSub[i] = _settings->GetRandomBool();
}
_state.VramAddress = _settings->GetRandomValue(0x7FFF);
switch(_settings->GetRandomValue(0x03)) {
case 0: _state.VramIncrementValue = 1; break;
case 1: _state.VramIncrementValue = 32; break;
case 2: case 3: _state.VramIncrementValue = 128; break;
}
_state.VramAddressRemapping = _settings->GetRandomValue(0x03);
_state.VramAddrIncrementOnSecondReg = _settings->GetRandomBool();
_state.VramReadBuffer = _settings->GetRandomValue(0xFFFF);
_state.Ppu1OpenBus = _settings->GetRandomValue(0xFF);
_state.Ppu2OpenBus = _settings->GetRandomValue(0xFF);
_state.CgramAddress = _settings->GetRandomValue(0xFF);
_state.CgramWriteBuffer = _settings->GetRandomValue(0xFF);
_state.CgramAddressLatch = _settings->GetRandomBool();
_state.MosaicSize = _settings->GetRandomValue(0x0F) + 1;
_state.MosaicEnabled = _settings->GetRandomValue(0x0F);
_state.OamRamAddress = _settings->GetRandomValue(0x1FF);
_state.OamMode = _settings->GetRandomValue(0x07);
_state.OamBaseAddress = _settings->GetRandomValue(0x07) << 13;
_state.OamAddressOffset = (_settings->GetRandomValue(0x03) + 1) << 12;
_state.EnableOamPriority = _settings->GetRandomBool();
_state.ExtBgEnabled = _settings->GetRandomBool();
_state.HiResMode = _settings->GetRandomBool();
_state.ScreenInterlace = _settings->GetRandomBool();
_state.ObjInterlace = _settings->GetRandomBool();
_state.OverscanMode = _settings->GetRandomBool();
_state.DirectColorMode = _settings->GetRandomBool();
_state.ColorMathClipMode = (ColorWindowMode)_settings->GetRandomValue(3);
_state.ColorMathPreventMode = (ColorWindowMode)_settings->GetRandomValue(3);
_state.ColorMathAddSubscreen = _settings->GetRandomBool();
_state.ColorMathEnabled = _settings->GetRandomValue(0x3F);
_state.ColorMathSubstractMode = _settings->GetRandomBool();
_state.ColorMathHalveResult = _settings->GetRandomBool();
_state.FixedColor = _settings->GetRandomValue(0x7FFF);
}
/* Everything below this point is used to select the proper arguments for templates */
template<uint8_t layerIndex, uint8_t bpp, bool processHighPriority, uint16_t basePaletteOffset, bool hiResMode, bool applyMosaic>
void Ppu::RenderTilemap()

View file

@ -201,6 +201,8 @@ private:
void UpdateOamAddress();
uint16_t GetOamAddress();
void RandomizeState();
public:
Ppu(Console* console);

View file

@ -273,7 +273,6 @@ struct EmulationConfig
ConsoleRegion Region = ConsoleRegion::Auto;
bool AllowInvalidInput = false;
bool EnableRandomPowerOnState = false;
uint32_t PpuExtraScanlinesBeforeNmi = 0;

View file

@ -16,8 +16,7 @@ namespace Mesen.GUI.Config
public ConsoleRegion Region = ConsoleRegion.Auto;
[MarshalAs(UnmanagedType.I1)] public bool AllowInvalidInput = false;
[MarshalAs(UnmanagedType.I1)] public bool EnableMapperRandomPowerOnState = false;
[MarshalAs(UnmanagedType.I1)] public bool EnableRandomPowerOnState = false;
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesBeforeNmi = 0;
[MinMax(0, 1000)] public UInt32 PpuExtraScanlinesAfterNmi = 0;

View file

@ -46,7 +46,6 @@
this.lblRewindSpeedHint = new System.Windows.Forms.Label();
this.cboRegion = new System.Windows.Forms.ComboBox();
this.tpgAdvanced = new System.Windows.Forms.TabPage();
this.flowLayoutPanel8 = new System.Windows.Forms.FlowLayoutPanel();
this.lblRamPowerOnState = new System.Windows.Forms.Label();
this.cboRamPowerOnState = new System.Windows.Forms.ComboBox();
this.tpgOverclocking = new System.Windows.Forms.TabPage();
@ -62,6 +61,8 @@
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.nudGsuClockSpeed = new Mesen.GUI.Controls.MesenNumericUpDown();
this.lblGsuClockSpeed = new System.Windows.Forms.Label();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.chkEnableRandomPowerOnState = new Mesen.GUI.Controls.ctrlRiskyOption();
this.tabMain.SuspendLayout();
this.tpgGeneral.SuspendLayout();
this.tableLayoutPanel4.SuspendLayout();
@ -69,13 +70,13 @@
this.flowLayoutPanel6.SuspendLayout();
this.flowLayoutPanel10.SuspendLayout();
this.tpgAdvanced.SuspendLayout();
this.flowLayoutPanel8.SuspendLayout();
this.tpgOverclocking.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picHint)).BeginInit();
this.tableLayoutPanel3.SuspendLayout();
this.grpPpuTiming.SuspendLayout();
this.tableLayoutPanel5.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.SuspendLayout();
//
// baseConfigPanel
@ -163,6 +164,7 @@
0,
0,
0});
this.nudTurboSpeed.IsHex = false;
this.nudTurboSpeed.Location = new System.Drawing.Point(3, 3);
this.nudTurboSpeed.Maximum = new decimal(new int[] {
5000,
@ -225,6 +227,7 @@
0,
0,
0});
this.nudEmulationSpeed.IsHex = false;
this.nudEmulationSpeed.Location = new System.Drawing.Point(3, 3);
this.nudEmulationSpeed.Maximum = new decimal(new int[] {
5000,
@ -297,6 +300,7 @@
0,
0,
0});
this.nudRewindSpeed.IsHex = false;
this.nudRewindSpeed.Location = new System.Drawing.Point(3, 3);
this.nudRewindSpeed.Maximum = new decimal(new int[] {
5000,
@ -340,7 +344,7 @@
//
// tpgAdvanced
//
this.tpgAdvanced.Controls.Add(this.flowLayoutPanel8);
this.tpgAdvanced.Controls.Add(this.tableLayoutPanel2);
this.tpgAdvanced.Location = new System.Drawing.Point(4, 22);
this.tpgAdvanced.Name = "tpgAdvanced";
this.tpgAdvanced.Padding = new System.Windows.Forms.Padding(3);
@ -349,17 +353,6 @@
this.tpgAdvanced.Text = "Advanced";
this.tpgAdvanced.UseVisualStyleBackColor = true;
//
// flowLayoutPanel8
//
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(3, 3);
this.flowLayoutPanel8.Margin = new System.Windows.Forms.Padding(7, 0, 0, 0);
this.flowLayoutPanel8.Name = "flowLayoutPanel8";
this.flowLayoutPanel8.Size = new System.Drawing.Size(400, 258);
this.flowLayoutPanel8.TabIndex = 4;
//
// lblRamPowerOnState
//
this.lblRamPowerOnState.Anchor = System.Windows.Forms.AnchorStyles.Left;
@ -469,6 +462,7 @@
0,
0,
0});
this.nudExtraScanlinesAfterNmi.IsHex = false;
this.nudExtraScanlinesAfterNmi.Location = new System.Drawing.Point(165, 30);
this.nudExtraScanlinesAfterNmi.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.nudExtraScanlinesAfterNmi.Maximum = new decimal(new int[] {
@ -500,6 +494,7 @@
0,
0,
0});
this.nudExtraScanlinesBeforeNmi.IsHex = false;
this.nudExtraScanlinesBeforeNmi.Location = new System.Drawing.Point(165, 3);
this.nudExtraScanlinesBeforeNmi.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.nudExtraScanlinesBeforeNmi.Maximum = new decimal(new int[] {
@ -567,6 +562,7 @@
0,
0,
0});
this.nudGsuClockSpeed.IsHex = false;
this.nudGsuClockSpeed.Location = new System.Drawing.Point(138, 3);
this.nudGsuClockSpeed.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
this.nudGsuClockSpeed.Maximum = new decimal(new int[] {
@ -601,6 +597,33 @@
this.lblGsuClockSpeed.TabIndex = 0;
this.lblGsuClockSpeed.Text = "Super FX clock speed (%):";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 2;
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.chkEnableRandomPowerOnState, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.cboRamPowerOnState, 1, 0);
this.tableLayoutPanel2.Controls.Add(this.lblRamPowerOnState, 0, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 3);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 2;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(400, 258);
this.tableLayoutPanel2.TabIndex = 5;
//
// chkEnableRandomPowerOnState
//
this.chkEnableRandomPowerOnState.Checked = false;
this.tableLayoutPanel2.SetColumnSpan(this.chkEnableRandomPowerOnState, 2);
this.chkEnableRandomPowerOnState.Location = new System.Drawing.Point(0, 27);
this.chkEnableRandomPowerOnState.Name = "chkEnableRandomPowerOnState";
this.chkEnableRandomPowerOnState.Size = new System.Drawing.Size(273, 24);
this.chkEnableRandomPowerOnState.TabIndex = 6;
this.chkEnableRandomPowerOnState.Text = "Randomize power-on state";
//
// frmEmulationConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -627,8 +650,6 @@
this.flowLayoutPanel10.ResumeLayout(false);
this.flowLayoutPanel10.PerformLayout();
this.tpgAdvanced.ResumeLayout(false);
this.flowLayoutPanel8.ResumeLayout(false);
this.flowLayoutPanel8.PerformLayout();
this.tpgOverclocking.ResumeLayout(false);
this.tpgOverclocking.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picHint)).EndInit();
@ -638,6 +659,8 @@
this.tableLayoutPanel5.PerformLayout();
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.tableLayoutPanel2.ResumeLayout(false);
this.tableLayoutPanel2.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -663,7 +686,6 @@
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox cboRegion;
private System.Windows.Forms.TabPage tpgAdvanced;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel8;
private System.Windows.Forms.Label lblRamPowerOnState;
private System.Windows.Forms.ComboBox cboRamPowerOnState;
private System.Windows.Forms.TabPage tpgOverclocking;
@ -679,5 +701,7 @@
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private Controls.MesenNumericUpDown nudGsuClockSpeed;
private System.Windows.Forms.Label lblGsuClockSpeed;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private Controls.ctrlRiskyOption chkEnableRandomPowerOnState;
}
}

View file

@ -28,6 +28,7 @@ namespace Mesen.GUI.Forms.Config
AddBinding(nameof(EmulationConfig.Region), cboRegion);
AddBinding(nameof(EmulationConfig.RamPowerOnState), cboRamPowerOnState);
AddBinding(nameof(EmulationConfig.EnableRandomPowerOnState), chkEnableRandomPowerOnState);
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesBeforeNmi), nudExtraScanlinesBeforeNmi);
AddBinding(nameof(EmulationConfig.PpuExtraScanlinesAfterNmi), nudExtraScanlinesAfterNmi);