mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-10-31 05:16:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			128 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| //  DiskII.hpp
 | |
| //  Clock Signal
 | |
| //
 | |
| //  Created by Thomas Harte on 20/04/2018.
 | |
| //  Copyright 2018 Thomas Harte. All rights reserved.
 | |
| //
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #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() const;
 | |
| 	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;
 | |
| };
 | |
| 
 | |
| }
 |