diff --git a/Core/Console.cpp b/Core/Console.cpp index d82a8b2..db1b99b 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -186,7 +186,6 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) _memoryManager->Initialize(shared_from_this()); _cpu.reset(new Cpu(this)); - _memoryManager->IncrementMasterClockValue<170>(); _rewindManager.reset(new RewindManager(shared_from_this())); _notificationManager->RegisterNotificationListener(_rewindManager); @@ -199,6 +198,9 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile) //_debugger.reset(); //GetDebugger(); //} + + UpdateRegion(); + _memoryManager->IncrementMasterClockValue<170>(); _paused = false; _notificationManager->SendNotification(ConsoleNotificationType::GameLoaded); @@ -215,6 +217,38 @@ RomInfo Console::GetRomInfo() } } +uint32_t Console::GetMasterClockRate() +{ + return _masterClockRate; +} + +ConsoleRegion Console::GetRegion() +{ + return _region; +} + +void Console::UpdateRegion() +{ + switch(_settings->GetEmulationConfig().Region) { + case ConsoleRegion::Auto: + { + uint8_t destCode = _cart->GetRomInfo().Header.DestinationCode; + if((destCode >= 0x02 && destCode <= 0x0C) || destCode == 0x11) { + _region = ConsoleRegion::Pal; + } else { + _region = ConsoleRegion::Ntsc; + } + break; + } + + default: + case ConsoleRegion::Ntsc: _region = ConsoleRegion::Ntsc; break; + case ConsoleRegion::Pal: _region = ConsoleRegion::Pal; break; + } + + _masterClockRate = _region == ConsoleRegion::Pal ? 21281370 : 21477270; +} + double Console::GetFrameDelay() { uint32_t emulationSpeed = _settings->GetEmulationSpeed(); @@ -222,7 +256,12 @@ double Console::GetFrameDelay() if(emulationSpeed == 0) { frameDelay = 0; } else { - frameDelay = 16.63926405550947 / (emulationSpeed / 100.0); + UpdateRegion(); + switch(_region) { + case ConsoleRegion::Ntsc: frameDelay = 16.63926405550947; break; + case ConsoleRegion::Pal: frameDelay = 19.99720882631146; break; + } + frameDelay /= (emulationSpeed / 100.0); } return frameDelay; } diff --git a/Core/Console.h b/Core/Console.h index e2a073d..00066cf 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -25,6 +25,7 @@ class RewindManager; enum class MemoryOperationType; enum class SnesMemoryType; enum class EventType; +enum class ConsoleRegion; class Console : public std::enable_shared_from_this { @@ -58,7 +59,11 @@ private: atomic _stopFlag; atomic _paused; + ConsoleRegion _region; + uint32_t _masterClockRate; + double GetFrameDelay(); + void UpdateRegion(); void WaitForLock(); void WaitForPauseEnd(); @@ -77,6 +82,8 @@ public: void LoadRom(VirtualFile romFile, VirtualFile patchFile); RomInfo GetRomInfo(); + uint32_t GetMasterClockRate(); + ConsoleRegion GetRegion(); ConsoleLock AcquireLock(); void Lock(); diff --git a/Core/Ppu.cpp b/Core/Ppu.cpp index 27fca8b..bde095e 100644 --- a/Core/Ppu.cpp +++ b/Core/Ppu.cpp @@ -117,7 +117,10 @@ void Ppu::Exec() } else if(_scanline == 240 && _frameCount & 0x01 && !_screenInterlace) { //"In non-interlace mode scanline 240 of every other frame (those with $213f.7=1) is only 1360 cycles." _cycle++; - } else if((_scanline == 262 && (!_screenInterlace || (_frameCount & 0x01))) || _scanline == 263) { + } else if( + (_console->GetRegion() == ConsoleRegion::Ntsc && ((_scanline == 262 && (!_screenInterlace || (_frameCount & 0x01))) || _scanline == 263)) || + (_console->GetRegion() == ConsoleRegion::Pal && ((_scanline == 312 && (!_screenInterlace || (_frameCount & 0x01))) || _scanline == 313)) + ) { //"Frames are 262 scanlines in non-interlace mode, while in interlace mode frames with $213f.7=0 are 263 scanlines" _regs->SetNmiFlag(false); _scanline = 0; @@ -1257,7 +1260,7 @@ uint8_t Ppu::Read(uint16_t addr) ((_frameCount & 0x01) ? 0x80 : 0) | (_locationLatched ? 0x40 : 0) | (_ppu2OpenBus & 0x20) | - //TODO (_isPal ? 0x10 : 0) + (_console->GetRegion() == ConsoleRegion::Pal ? 0x10 : 0) | 0x02 //PPU (5c78) chip version ); diff --git a/Core/SettingTypes.h b/Core/SettingTypes.h index acc512d..cf94af4 100644 --- a/Core/SettingTypes.h +++ b/Core/SettingTypes.h @@ -228,12 +228,21 @@ enum class RamPowerOnState Random = 2 }; +enum class ConsoleRegion +{ + Auto = 0, + Ntsc = 1, + Pal = 2 +}; + struct EmulationConfig { uint32_t EmulationSpeed = 100; uint32_t TurboSpeed = 300; uint32_t RewindSpeed = 100; + ConsoleRegion Region = ConsoleRegion::Auto; + bool AllowInvalidInput = false; bool EnableRandomPowerOnState = false; diff --git a/Core/Spc.cpp b/Core/Spc.cpp index 1899e2e..46161ef 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -32,7 +32,7 @@ int Spc::GetSpcTime() { uint64_t currentClock = _console->GetMemoryManager()->GetMasterClock(); uint64_t elapsedClocks = currentClock - _startFrameMasterClock; - return (int)(elapsedClocks * 1024000 / 21477000); + return (int)(elapsedClocks * 1024000 / _console->GetMasterClockRate()); } uint8_t Spc::Read(uint16_t addr) @@ -53,7 +53,7 @@ void Spc::ProcessEndFrame() _console->GetSoundMixer()->PlayAudioBuffer(_soundBuffer, sampleCount / 2); _spc->set_output(_soundBuffer, Spc::SampleBufferSize >> 1); - uint64_t remainder = (_console->GetMemoryManager()->GetMasterClock() - _startFrameMasterClock) * 1024000 % 21477000 / 1024000; + uint64_t remainder = (_console->GetMemoryManager()->GetMasterClock() - _startFrameMasterClock) * 1024000 % _console->GetMasterClockRate() / 1024000; _startFrameMasterClock = _console->GetMemoryManager()->GetMasterClock() - remainder; } diff --git a/UI/Config/EmulationConfig.cs b/UI/Config/EmulationConfig.cs index c3609d5..1938dc8 100644 --- a/UI/Config/EmulationConfig.cs +++ b/UI/Config/EmulationConfig.cs @@ -14,6 +14,8 @@ namespace Mesen.GUI.Config [MinMax(0, 5000)] public UInt32 TurboSpeed = 300; [MinMax(0, 5000)] public UInt32 RewindSpeed = 100; + public ConsoleRegion Region = ConsoleRegion.Auto; + [MarshalAs(UnmanagedType.I1)] public bool AllowInvalidInput = false; [MarshalAs(UnmanagedType.I1)] public bool EnableMapperRandomPowerOnState = false; @@ -28,6 +30,13 @@ namespace Mesen.GUI.Config } } + public enum ConsoleRegion + { + Auto = 0, + Ntsc = 1, + Pal = 2 + } + public enum RamPowerOnState { AllZeros = 0, diff --git a/UI/Emulation/ShortcutHandler.cs b/UI/Emulation/ShortcutHandler.cs index 91a298d..a562dee 100644 --- a/UI/Emulation/ShortcutHandler.cs +++ b/UI/Emulation/ShortcutHandler.cs @@ -143,7 +143,14 @@ namespace Mesen.GUI.Emulation } } } - + + public void SetRegion(ConsoleRegion region) + { + ConfigManager.Config.Emulation.Region = region; + ConfigManager.Config.Emulation.ApplyConfig(); + ConfigManager.ApplyChanges(); + } + public void SetVideoFilter(VideoFilterType filter) { ConfigManager.Config.Video.VideoFilter = filter; diff --git a/UI/Forms/Config/frmEmulationConfig.Designer.cs b/UI/Forms/Config/frmEmulationConfig.Designer.cs index d1591bf..f8b3a44 100644 --- a/UI/Forms/Config/frmEmulationConfig.Designer.cs +++ b/UI/Forms/Config/frmEmulationConfig.Designer.cs @@ -42,6 +42,8 @@ this.flowLayoutPanel10 = new System.Windows.Forms.FlowLayoutPanel(); this.nudRewindSpeed = new Mesen.GUI.Controls.MesenNumericUpDown(); this.lblRewindSpeedHint = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.cboRegion = new System.Windows.Forms.ComboBox(); this.tabMain.SuspendLayout(); this.tpgGeneral.SuspendLayout(); this.tableLayoutPanel4.SuspendLayout(); @@ -82,16 +84,19 @@ this.tableLayoutPanel4.ColumnCount = 2; this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Controls.Add(this.label1, 0, 3); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel9, 1, 1); this.tableLayoutPanel4.Controls.Add(this.lblTurboSpeed, 0, 1); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel6, 1, 0); this.tableLayoutPanel4.Controls.Add(this.lblEmulationSpeed, 0, 0); this.tableLayoutPanel4.Controls.Add(this.lblRewindSpeed, 0, 2); this.tableLayoutPanel4.Controls.Add(this.flowLayoutPanel10, 1, 2); + this.tableLayoutPanel4.Controls.Add(this.cboRegion, 1, 3); this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); this.tableLayoutPanel4.Name = "tableLayoutPanel4"; - this.tableLayoutPanel4.RowCount = 4; + this.tableLayoutPanel4.RowCount = 5; + 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()); this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); @@ -285,6 +290,25 @@ this.lblRewindSpeedHint.TabIndex = 2; this.lblRewindSpeedHint.Text = "% (0 = Maximum speed)"; // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(3, 88); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(44, 13); + this.label1.TabIndex = 17; + this.label1.Text = "Region:"; + // + // cboRegion + // + this.cboRegion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboRegion.FormattingEnabled = true; + this.cboRegion.Location = new System.Drawing.Point(114, 84); + this.cboRegion.Name = "cboRegion"; + this.cboRegion.Size = new System.Drawing.Size(121, 21); + this.cboRegion.TabIndex = 18; + // // frmEmulationConfig // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -331,5 +355,7 @@ private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel10; private Controls.MesenNumericUpDown nudRewindSpeed; private System.Windows.Forms.Label lblRewindSpeedHint; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ComboBox cboRegion; } } \ No newline at end of file diff --git a/UI/Forms/Config/frmEmulationConfig.cs b/UI/Forms/Config/frmEmulationConfig.cs index 938b852..da5bc51 100644 --- a/UI/Forms/Config/frmEmulationConfig.cs +++ b/UI/Forms/Config/frmEmulationConfig.cs @@ -25,6 +25,7 @@ namespace Mesen.GUI.Forms.Config AddBinding(nameof(EmulationConfig.EmulationSpeed), nudEmulationSpeed); AddBinding(nameof(EmulationConfig.TurboSpeed), nudTurboSpeed); AddBinding(nameof(EmulationConfig.RewindSpeed), nudRewindSpeed); + AddBinding(nameof(EmulationConfig.Region), cboRegion); } protected override void OnApply() diff --git a/UI/Forms/frmMain.Designer.cs b/UI/Forms/frmMain.Designer.cs index 966e1e3..9e7276f 100644 --- a/UI/Forms/frmMain.Designer.cs +++ b/UI/Forms/frmMain.Designer.cs @@ -122,6 +122,11 @@ this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripSeparator(); this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem(); this.pnlRenderer = new System.Windows.Forms.Panel(); + this.mnuRegion = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegionAuto = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegionNtsc = new System.Windows.Forms.ToolStripMenuItem(); + this.mnuRegionPal = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); this.mnuMain.SuspendLayout(); this.pnlRenderer.SuspendLayout(); this.SuspendLayout(); @@ -271,6 +276,7 @@ this.mnuEmulationSpeed, this.mnuVideoScale, this.mnuVideoFilter, + this.mnuRegion, this.toolStripMenuItem4, this.mnuAudioConfig, this.mnuInputConfig, @@ -299,7 +305,7 @@ this.mnuShowFPS}); this.mnuEmulationSpeed.Image = global::Mesen.GUI.Properties.Resources.Speed; this.mnuEmulationSpeed.Name = "mnuEmulationSpeed"; - this.mnuEmulationSpeed.Size = new System.Drawing.Size(135, 22); + this.mnuEmulationSpeed.Size = new System.Drawing.Size(152, 22); this.mnuEmulationSpeed.Text = "Speed"; this.mnuEmulationSpeed.DropDownOpening += new System.EventHandler(this.mnuEmulationSpeed_DropDownOpening); // @@ -387,7 +393,7 @@ this.mnuFullscreen}); this.mnuVideoScale.Image = global::Mesen.GUI.Properties.Resources.Fullscreen; this.mnuVideoScale.Name = "mnuVideoScale"; - this.mnuVideoScale.Size = new System.Drawing.Size(135, 22); + this.mnuVideoScale.Size = new System.Drawing.Size(152, 22); this.mnuVideoScale.Text = "Video Size"; this.mnuVideoScale.DropDownOpening += new System.EventHandler(this.mnuVideoScale_DropDownOpening); // @@ -473,7 +479,7 @@ this.mnuBilinearInterpolation}); this.mnuVideoFilter.Image = global::Mesen.GUI.Properties.Resources.VideoFilter; this.mnuVideoFilter.Name = "mnuVideoFilter"; - this.mnuVideoFilter.Size = new System.Drawing.Size(135, 22); + this.mnuVideoFilter.Size = new System.Drawing.Size(152, 22); this.mnuVideoFilter.Text = "Video Filter"; this.mnuVideoFilter.DropDownOpening += new System.EventHandler(this.mnuVideoFilter_DropDownOpening); // @@ -654,13 +660,13 @@ // toolStripMenuItem4 // this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - this.toolStripMenuItem4.Size = new System.Drawing.Size(132, 6); + this.toolStripMenuItem4.Size = new System.Drawing.Size(149, 6); // // mnuAudioConfig // this.mnuAudioConfig.Image = global::Mesen.GUI.Properties.Resources.Audio; this.mnuAudioConfig.Name = "mnuAudioConfig"; - this.mnuAudioConfig.Size = new System.Drawing.Size(135, 22); + this.mnuAudioConfig.Size = new System.Drawing.Size(152, 22); this.mnuAudioConfig.Text = "Audio"; this.mnuAudioConfig.Click += new System.EventHandler(this.mnuAudioConfig_Click); // @@ -668,7 +674,7 @@ // this.mnuInputConfig.Image = global::Mesen.GUI.Properties.Resources.Controller; this.mnuInputConfig.Name = "mnuInputConfig"; - this.mnuInputConfig.Size = new System.Drawing.Size(135, 22); + this.mnuInputConfig.Size = new System.Drawing.Size(152, 22); this.mnuInputConfig.Text = "Input"; this.mnuInputConfig.Click += new System.EventHandler(this.mnuInputConfig_Click); // @@ -676,7 +682,7 @@ // this.mnuVideoConfig.Image = global::Mesen.GUI.Properties.Resources.VideoOptions; this.mnuVideoConfig.Name = "mnuVideoConfig"; - this.mnuVideoConfig.Size = new System.Drawing.Size(135, 22); + this.mnuVideoConfig.Size = new System.Drawing.Size(152, 22); this.mnuVideoConfig.Text = "Video"; this.mnuVideoConfig.Click += new System.EventHandler(this.mnuVideoConfig_Click); // @@ -684,20 +690,20 @@ // this.mnuEmulationConfig.Image = global::Mesen.GUI.Properties.Resources.DipSwitches; this.mnuEmulationConfig.Name = "mnuEmulationConfig"; - this.mnuEmulationConfig.Size = new System.Drawing.Size(135, 22); + this.mnuEmulationConfig.Size = new System.Drawing.Size(152, 22); this.mnuEmulationConfig.Text = "Emulation"; this.mnuEmulationConfig.Click += new System.EventHandler(this.mnuEmulationConfig_Click); // // toolStripMenuItem3 // this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - this.toolStripMenuItem3.Size = new System.Drawing.Size(132, 6); + this.toolStripMenuItem3.Size = new System.Drawing.Size(149, 6); // // mnuPreferences // this.mnuPreferences.Image = global::Mesen.GUI.Properties.Resources.Settings; this.mnuPreferences.Name = "mnuPreferences"; - this.mnuPreferences.Size = new System.Drawing.Size(135, 22); + this.mnuPreferences.Size = new System.Drawing.Size(152, 22); this.mnuPreferences.Text = "Preferences"; this.mnuPreferences.Click += new System.EventHandler(this.mnuPreferences_Click); // @@ -797,6 +803,7 @@ // // mnuCheckForUpdates // + this.mnuCheckForUpdates.Image = global::Mesen.GUI.Properties.Resources.Update; this.mnuCheckForUpdates.Name = "mnuCheckForUpdates"; this.mnuCheckForUpdates.Size = new System.Drawing.Size(170, 22); this.mnuCheckForUpdates.Text = "Check for updates"; @@ -838,6 +845,42 @@ this.pnlRenderer.Size = new System.Drawing.Size(512, 448); this.pnlRenderer.TabIndex = 2; // + // mnuRegion + // + this.mnuRegion.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuRegionAuto, + this.toolStripMenuItem1, + this.mnuRegionNtsc, + this.mnuRegionPal}); + this.mnuRegion.Image = global::Mesen.GUI.Properties.Resources.WebBrowser; + this.mnuRegion.Name = "mnuRegion"; + this.mnuRegion.Size = new System.Drawing.Size(152, 22); + this.mnuRegion.Text = "Region"; + this.mnuRegion.DropDownOpening += new System.EventHandler(this.mnuRegion_DropDownOpening); + // + // mnuRegionAuto + // + this.mnuRegionAuto.Name = "mnuRegionAuto"; + this.mnuRegionAuto.Size = new System.Drawing.Size(152, 22); + this.mnuRegionAuto.Text = "Auto"; + // + // mnuRegionNtsc + // + this.mnuRegionNtsc.Name = "mnuRegionNtsc"; + this.mnuRegionNtsc.Size = new System.Drawing.Size(152, 22); + this.mnuRegionNtsc.Text = "NTSC"; + // + // mnuRegionPal + // + this.mnuRegionPal.Name = "mnuRegionPal"; + this.mnuRegionPal.Size = new System.Drawing.Size(152, 22); + this.mnuRegionPal.Text = "PAL"; + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(149, 6); + // // frmMain // this.AllowDrop = true; @@ -954,5 +997,10 @@ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem10; private System.Windows.Forms.ToolStripMenuItem mnuEmulationConfig; private System.Windows.Forms.ToolStripMenuItem mnuInputConfig; + private System.Windows.Forms.ToolStripMenuItem mnuRegion; + private System.Windows.Forms.ToolStripMenuItem mnuRegionAuto; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem mnuRegionNtsc; + private System.Windows.Forms.ToolStripMenuItem mnuRegionPal; } } \ No newline at end of file diff --git a/UI/Forms/frmMain.cs b/UI/Forms/frmMain.cs index 21cda40..6d785a3 100644 --- a/UI/Forms/frmMain.cs +++ b/UI/Forms/frmMain.cs @@ -157,6 +157,10 @@ namespace Mesen.GUI.Forms mnuXBRZ6xFilter.Click += (s, e) => { _shortcuts.SetVideoFilter(VideoFilterType.xBRZ6x); }; mnuBilinearInterpolation.Click += (s, e) => { _shortcuts.ToggleBilinearInterpolation(); }; + + mnuRegionAuto.Click += (s, e) => { _shortcuts.SetRegion(ConsoleRegion.Auto); }; + mnuRegionNtsc.Click += (s, e) => { _shortcuts.SetRegion(ConsoleRegion.Ntsc); }; + mnuRegionPal.Click += (s, e) => { _shortcuts.SetRegion(ConsoleRegion.Pal); }; } private void UpdateViewerSize(ScreenSize screenSize) @@ -368,5 +372,12 @@ namespace Mesen.GUI.Forms { SaveStateManager.UpdateStateMenu(mnuSaveState, true); } + + private void mnuRegion_DropDownOpening(object sender, EventArgs e) + { + mnuRegionAuto.Checked = ConfigManager.Config.Emulation.Region == ConsoleRegion.Auto; + mnuRegionNtsc.Checked = ConfigManager.Config.Emulation.Region == ConsoleRegion.Ntsc; + mnuRegionPal.Checked = ConfigManager.Config.Emulation.Region == ConsoleRegion.Pal; + } } }