mirror of
				https://github.com/TomHarte/CLK.git
				synced 2025-11-04 00:16:26 +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;
 | 
						|
};
 | 
						|
 | 
						|
}
 |