mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-10-31 05:16:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| //  DiskII.hpp
 | |
| //  Clock Signal
 | |
| //
 | |
| //  Created by Thomas Harte on 20/04/2018.
 | |
| //  Copyright 2018 Thomas Harte. All rights reserved.
 | |
| //
 | |
| 
 | |
| #ifndef DiskII_hpp
 | |
| #define DiskII_hpp
 | |
| 
 | |
| #include "../../ClockReceiver/ClockReceiver.hpp"
 | |
| #include "../../ClockReceiver/ClockingHintSource.hpp"
 | |
| 
 | |
| #include "../../Storage/Disk/Disk.hpp"
 | |
| #include "../../Storage/Disk/Drive.hpp"
 | |
| 
 | |
| #include "../../Activity/Observer.hpp"
 | |
| 
 | |
| #include <array>
 | |
| #include <cstdint>
 | |
| #include <vector>
 | |
| 
 | |
| namespace Apple {
 | |
| 
 | |
| /*!
 | |
| 	Provides an emulation of the Apple Disk II.
 | |
| */
 | |
| class DiskII :
 | |
| 	public Storage::Disk::Drive::EventDelegate,
 | |
| 	public ClockingHint::Source,
 | |
| 	public ClockingHint::Observer {
 | |
| 	public:
 | |
| 		DiskII(int clock_rate);
 | |
| 
 | |
| 		/// Sets the current external value of the data bus.
 | |
| 		void set_data_input(uint8_t input);
 | |
| 
 | |
| 		/*!
 | |
| 			Submits an access to address @c address.
 | |
| 
 | |
| 			@returns The 8-bit value loaded to the data bus by the DiskII if any;
 | |
| 				@c DidNotLoad otherwise.
 | |
| 		*/
 | |
| 		int read_address(int address);
 | |
| 
 | |
| 		/*!
 | |
| 			The value returned by @c read_address if accessing that address
 | |
| 			didn't cause the disk II to place anything onto the bus.
 | |
| 		*/
 | |
| 		static constexpr int DidNotLoad = -1;
 | |
| 
 | |
| 		/// Advances the controller by @c cycles.
 | |
| 		void run_for(const Cycles cycles);
 | |
| 
 | |
| 		/*!
 | |
| 			Supplies the image of the state machine (i.e. P6) ROM,
 | |
| 			which dictates how the Disk II will respond to input.
 | |
| 
 | |
| 			To reduce processing costs, some assumptions are made by
 | |
| 			the implementation as to the content of this ROM.
 | |
| 			Including:
 | |
| 
 | |
| 			*	If Q6 is set and Q7 is reset, the controller is testing
 | |
| 				for write protect. If and when the shift register has
 | |
| 				become full with the state of the write protect value,
 | |
| 				no further processing is required.
 | |
| 
 | |
| 			*	If both Q6 and Q7 are reset, the drive motor is disabled,
 | |
| 				and the shift register is all zeroes, no further processing
 | |
| 				is required.
 | |
| 		*/
 | |
| 		void set_state_machine(const std::vector<uint8_t> &);
 | |
| 
 | |
| 		/// Inserts @c disk into the drive @c drive.
 | |
| 		void set_disk(const std::shared_ptr<Storage::Disk::Disk> &disk, int drive);
 | |
| 
 | |
| 		// As per Sleeper.
 | |
| 		ClockingHint::Preference preferred_clocking() const final;
 | |
| 
 | |
| 		// The Disk II functions as a potential target for @c Activity::Sources.
 | |
| 		void set_activity_observer(Activity::Observer *observer);
 | |
| 
 | |
| 		// Returns the Storage::Disk::Drive in use for drive @c index.
 | |
| 		// *NOT FOR HARDWARE EMULATION USAGE*.
 | |
| 		Storage::Disk::Drive &get_drive(int index);
 | |
| 
 | |
| 	private:
 | |
| 		enum class Control {
 | |
| 			P0, P1, P2, P3,
 | |
| 			Motor,
 | |
| 		};
 | |
| 		enum class Mode {
 | |
| 			Read, Write
 | |
| 		};
 | |
| 		void set_control(Control control, bool on);
 | |
| 		void set_mode(Mode mode);
 | |
| 		void select_drive(int drive);
 | |
| 
 | |
| 		uint8_t trigger_address(int address, uint8_t value);
 | |
| 		void process_event(const Storage::Disk::Drive::Event &event) final;
 | |
| 		void set_component_prefers_clocking(ClockingHint::Source *component, ClockingHint::Preference preference) final;
 | |
| 
 | |
| 		const Cycles::IntType clock_rate_ = 0;
 | |
| 
 | |
| 		uint8_t state_ = 0;
 | |
| 		uint8_t inputs_ = 0;
 | |
| 		uint8_t shift_register_ = 0;
 | |
| 
 | |
| 		int stepper_mask_ = 0;
 | |
| 		int stepper_position_ = 0;
 | |
| 		Cycles::IntType motor_off_time_ = -1;
 | |
| 
 | |
| 		bool is_write_protected();
 | |
| 		std::array<uint8_t, 256> state_machine_;
 | |
| 		Storage::Disk::Drive drives_[2];
 | |
| 		bool drive_is_sleeping_[2];
 | |
| 		int active_drive_ = 0;
 | |
| 		bool motor_is_enabled_ = false;
 | |
| 
 | |
| 		void decide_clocking_preference();
 | |
| 		ClockingHint::Preference clocking_preference_ = ClockingHint::Preference::RealTime;
 | |
| 
 | |
| 		uint8_t data_input_ = 0;
 | |
| 		int flux_duration_ = 0;
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif /* DiskII_hpp */
 |