From d9016909edbd341a0c3dce7c97e94c62778bc11a Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Sun, 14 Aug 2016 13:33:20 -0400
Subject: [PATCH] Added some wiring for PAL/NTSC mode switching on the Vic,
 making an attempt to simplify the whole loop of having different clock rates.

---
 Machines/Atari2600/Atari2600.cpp    | 11 ++++-------
 Machines/Atari2600/Atari2600.hpp    |  1 -
 Machines/CRTMachine.hpp             | 17 ++++++++++++++---
 Machines/Commodore/Vic-20/Vic20.cpp | 20 +++++++++++++++++++-
 Machines/Commodore/Vic-20/Vic20.hpp | 10 +++++++++-
 Machines/Electron/Electron.cpp      |  1 +
 Machines/Electron/Electron.hpp      |  1 -
 7 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp
index 9260e22e5..6d76cdadb 100644
--- a/Machines/Atari2600/Atari2600.cpp
+++ b/Machines/Atari2600/Atari2600.cpp
@@ -13,6 +13,8 @@
 using namespace Atari2600;
 namespace {
 	static const unsigned int horizontalTimerPeriod = 228;
+	static const double NTSC_clock_rate = 1194720;
+	static const double PAL_clock_rate = 1182298;
 }
 
 Machine::Machine() :
@@ -52,6 +54,7 @@ Machine::Machine() :
 			_stateByExtendTime[vbextend][c] = state;
 		}
 	}
+	set_clock_rate(NTSC_clock_rate);
 }
 
 void Machine::setup_output(float aspect_ratio)
@@ -94,8 +97,7 @@ void Machine::switch_region()
 
 	_is_pal_region = true;
 	_speaker->set_input_rate((float)(get_clock_rate() / 38.0));
-
-	if(delegate) delegate->machine_did_change_clock_rate(this);
+	set_clock_rate(PAL_clock_rate);
 }
 
 void Machine::close_output()
@@ -109,11 +111,6 @@ Machine::~Machine()
 	close_output();
 }
 
-double Machine::get_clock_rate()
-{
-	return _is_pal_region ? 1182298 : 1194720;
-}
-
 void Machine::update_timers(int mask)
 {
 	unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;
diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp
index 4a1778b14..3b9fa0131 100644
--- a/Machines/Atari2600/Atari2600.hpp
+++ b/Machines/Atari2600/Atari2600.hpp
@@ -94,7 +94,6 @@ class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {
 		virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }
 		virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; }
 		virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
-		virtual double get_clock_rate();
 		// TODO: different rate for PAL
 
 	private:
diff --git a/Machines/CRTMachine.hpp b/Machines/CRTMachine.hpp
index c193199c4..6e00b482f 100644
--- a/Machines/CRTMachine.hpp
+++ b/Machines/CRTMachine.hpp
@@ -30,15 +30,26 @@ class Machine {
 		virtual void run_for_cycles(int number_of_cycles) = 0;
 
 		// TODO: sever the clock-rate stuff.
-		virtual double get_clock_rate() = 0;
+		double get_clock_rate() {
+			return clock_rate_;
+		}
 		class Delegate {
 			public:
 				virtual void machine_did_change_clock_rate(Machine *machine) = 0;
 		};
-		void set_delegate(Delegate *delegate) { this->delegate = delegate; }
+		void set_delegate(Delegate *delegate) { this->delegate_ = delegate; }
 
 	protected:
-		Delegate *delegate;
+		double clock_rate_;
+		void set_clock_rate(double clock_rate) {
+			if(clock_rate_ != clock_rate) {
+				clock_rate_ = clock_rate;
+				if(delegate_) delegate_->machine_did_change_clock_rate(this);
+			}
+		}
+
+	private:
+		Delegate *delegate_;
 };
 
 }
diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp
index 3050216e8..664277c44 100644
--- a/Machines/Commodore/Vic-20/Vic20.cpp
+++ b/Machines/Commodore/Vic-20/Vic20.cpp
@@ -37,6 +37,8 @@ Machine::Machine() :
 	// establish the memory maps
 	set_memory_size(MemorySize::Default);
 
+	// set the NTSC clock rate
+	set_region(NTSC);
 //	_debugPort.reset(new ::Commodore::Serial::DebugPort);
 //	_debugPort->set_serial_bus(_serialBus);
 //	_serialBus->add_port(_debugPort);
@@ -60,7 +62,6 @@ void Machine::set_memory_size(MemorySize size)
 		break;
 	}
 
-
 	// install the ROMs and VIC-visible memory
 	write_to_map(_processorReadMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory));
 	write_to_map(_processorReadMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory));
@@ -161,9 +162,26 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522)
 
 #pragma mark - Setup
 
+void Machine::set_region(Commodore::Vic20::Region region)
+{
+	_region = region;
+	switch(region)
+	{
+		case PAL:
+			set_clock_rate(1108404);
+			if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
+		break;
+		case NTSC:
+			set_clock_rate(1022727);
+			if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
+		break;
+	}
+}
+
 void Machine::setup_output(float aspect_ratio)
 {
 	_mos6560.reset(new Vic6560());
+	set_region(_region);
 
 	memset(_mos6560->_videoMemoryMap, 0, sizeof(_mos6560->_videoMemoryMap));
 	write_to_map(_mos6560->_videoMemoryMap, _characterROM, 0x0000, sizeof(_characterROM));
diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp
index e1b4b8a3c..e4fb58386 100644
--- a/Machines/Commodore/Vic-20/Vic20.hpp
+++ b/Machines/Commodore/Vic-20/Vic20.hpp
@@ -38,6 +38,11 @@ enum MemorySize {
 	ThirtyTwoKB
 };
 
+enum Region {
+	NTSC,
+	PAL
+};
+
 #define key(line, mask) (((mask) << 3) | (line))
 
 enum Key: uint16_t {
@@ -265,7 +270,9 @@ class Machine:
 			_userPortVIA->set_joystick_state(input, isPressed);
 			_keyboardVIA->set_joystick_state(input, isPressed);
 		}
+
 		void set_memory_size(MemorySize size);
+		void set_region(Region region);
 
 		inline void set_use_fast_tape_hack(bool activate) { _use_fast_tape_hack = activate; }
 		inline void set_should_automatically_load_media(bool activate) { _should_automatically_load_media = activate; }
@@ -280,7 +287,6 @@ class Machine:
 		virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _mos6560->get_crt(); }
 		virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _mos6560->get_speaker(); }
 		virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
-		virtual double get_clock_rate() { return 1022727; }
 		// TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt
 
 		// to satisfy MOS::MOS6522::Delegate
@@ -313,6 +319,8 @@ class Machine:
 		uint8_t *_processorWriteMemoryMap[64];
 		void write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length);
 
+		Region _region;
+
 		std::unique_ptr<Vic6560> _mos6560;
 		std::shared_ptr<UserPortVIA> _userPortVIA;
 		std::shared_ptr<KeyboardVIA> _keyboardVIA;
diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp
index bf07f869d..30c9a0ad4 100644
--- a/Machines/Electron/Electron.cpp
+++ b/Machines/Electron/Electron.cpp
@@ -55,6 +55,7 @@ Machine::Machine() :
 		memset(_roms[c], 0xff, 16384);
 
 	_tape.set_delegate(this);
+	set_clock_rate(2000000);
 }
 
 void Machine::setup_output(float aspect_ratio)
diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp
index d5f593e1a..6ec7b81a2 100644
--- a/Machines/Electron/Electron.hpp
+++ b/Machines/Electron/Electron.hpp
@@ -162,7 +162,6 @@ class Machine:
 		virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }
 		virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; }
 		virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
-		virtual double get_clock_rate() { return 2000000; }
 
 		// to satisfy Tape::Delegate
 		virtual void tape_did_change_interrupt_status(Tape *tape);