2017-08-05 23:45:52 +00:00
|
|
|
//
|
|
|
|
// i8272.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 05/08/2017.
|
|
|
|
// Copyright © 2017 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef i8272_hpp
|
|
|
|
#define i8272_hpp
|
|
|
|
|
2017-09-23 02:39:23 +00:00
|
|
|
#include "../../Storage/Disk/Controller/MFMDiskController.hpp"
|
2017-08-06 13:45:16 +00:00
|
|
|
|
2017-08-05 23:45:52 +00:00
|
|
|
#include <cstdint>
|
2017-08-14 12:38:00 +00:00
|
|
|
#include <memory>
|
2017-08-06 02:26:59 +00:00
|
|
|
#include <vector>
|
2017-08-05 23:45:52 +00:00
|
|
|
|
|
|
|
namespace Intel {
|
2017-08-14 12:38:00 +00:00
|
|
|
namespace i8272 {
|
|
|
|
|
|
|
|
class BusHandler {
|
|
|
|
public:
|
|
|
|
virtual void set_dma_data_request(bool drq) {}
|
|
|
|
virtual void set_interrupt(bool irq) {}
|
|
|
|
};
|
2017-08-05 23:45:52 +00:00
|
|
|
|
2017-08-06 13:45:16 +00:00
|
|
|
class i8272: public Storage::Disk::MFMController {
|
2017-08-05 23:45:52 +00:00
|
|
|
public:
|
2017-09-11 02:56:05 +00:00
|
|
|
i8272(BusHandler &bus_handler, Cycles clock_rate);
|
2017-08-06 13:45:16 +00:00
|
|
|
|
|
|
|
void run_for(Cycles);
|
|
|
|
|
2017-08-14 13:04:22 +00:00
|
|
|
void set_data_input(uint8_t value);
|
|
|
|
uint8_t get_data_output();
|
|
|
|
|
2017-08-05 23:45:52 +00:00
|
|
|
void set_register(int address, uint8_t value);
|
|
|
|
uint8_t get_register(int address);
|
2017-08-06 02:26:59 +00:00
|
|
|
|
2017-08-14 12:38:00 +00:00
|
|
|
void set_dma_acknowledge(bool dack);
|
|
|
|
void set_terminal_count(bool tc);
|
|
|
|
|
2017-08-20 16:05:00 +00:00
|
|
|
bool is_sleeping();
|
|
|
|
|
2017-09-12 01:25:26 +00:00
|
|
|
protected:
|
|
|
|
virtual void select_drive(int number) = 0;
|
|
|
|
|
2017-08-06 02:26:59 +00:00
|
|
|
private:
|
2017-08-14 12:38:00 +00:00
|
|
|
// The bus handler, for interrupt and DMA-driven usage.
|
|
|
|
BusHandler &bus_handler_;
|
|
|
|
std::unique_ptr<BusHandler> allocated_bus_handler_;
|
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Status registers.
|
2017-08-06 16:55:57 +00:00
|
|
|
uint8_t main_status_;
|
2017-08-12 16:52:36 +00:00
|
|
|
uint8_t status_[3];
|
2017-08-06 16:55:57 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// A buffer for accumulating the incoming command, and one for accumulating the result.
|
2017-08-06 02:26:59 +00:00
|
|
|
std::vector<uint8_t> command_;
|
2017-08-07 00:17:12 +00:00
|
|
|
std::vector<uint8_t> result_stack_;
|
2017-08-13 16:50:07 +00:00
|
|
|
uint8_t input_;
|
|
|
|
bool has_input_;
|
|
|
|
bool expects_input_;
|
2017-08-06 16:36:18 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Event stream: the 8272-specific events, plus the current event state.
|
2017-08-06 16:36:18 +00:00
|
|
|
enum class Event8272: int {
|
|
|
|
CommandByte = (1 << 3),
|
|
|
|
Timer = (1 << 4),
|
2017-08-06 16:55:57 +00:00
|
|
|
ResultEmpty = (1 << 5),
|
2017-09-16 00:26:41 +00:00
|
|
|
NoLongerReady = (1 << 6)
|
2017-08-06 16:36:18 +00:00
|
|
|
};
|
2017-08-12 16:52:36 +00:00
|
|
|
void posit_event(int type);
|
2017-08-06 16:36:18 +00:00
|
|
|
int interesting_event_mask_;
|
|
|
|
int resume_point_;
|
2017-08-16 01:49:10 +00:00
|
|
|
bool is_access_command_;
|
2017-08-06 16:36:18 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// The counter used for ::Timer events.
|
|
|
|
int delay_time_;
|
2017-08-06 16:55:57 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// The connected drives.
|
2017-08-06 19:22:07 +00:00
|
|
|
struct Drive {
|
|
|
|
uint8_t head_position;
|
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Seeking: persistent state.
|
2017-08-06 19:22:07 +00:00
|
|
|
enum Phase {
|
|
|
|
NotSeeking,
|
|
|
|
Seeking,
|
|
|
|
CompletedSeeking
|
|
|
|
} phase;
|
2017-08-14 13:45:39 +00:00
|
|
|
bool did_seek;
|
2017-08-12 16:52:36 +00:00
|
|
|
bool seek_failed;
|
|
|
|
|
|
|
|
// Seeking: transient state.
|
2017-08-06 19:22:07 +00:00
|
|
|
int step_rate_counter;
|
2017-08-07 01:52:52 +00:00
|
|
|
int steps_taken;
|
2017-08-06 19:22:07 +00:00
|
|
|
int target_head_position; // either an actual number, or -1 to indicate to step until track zero
|
|
|
|
|
2017-08-12 13:36:21 +00:00
|
|
|
// Head state.
|
|
|
|
int head_unload_delay[2];
|
|
|
|
bool head_is_loaded[2];
|
|
|
|
|
|
|
|
Drive() :
|
|
|
|
head_position(0), phase(NotSeeking),
|
2017-08-20 02:06:56 +00:00
|
|
|
head_is_loaded{false, false},
|
|
|
|
head_unload_delay{0, 0} {};
|
2017-08-06 19:22:07 +00:00
|
|
|
} drives_[4];
|
2017-08-14 13:45:39 +00:00
|
|
|
int drives_seeking_;
|
2017-08-12 16:52:36 +00:00
|
|
|
|
2017-09-12 01:25:26 +00:00
|
|
|
/// @returns @c true if the selected drive, which is number @c drive, can stop seeking.
|
|
|
|
bool seek_is_satisfied(int drive);
|
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// User-supplied parameters; as per the specify command.
|
2017-09-16 00:26:41 +00:00
|
|
|
int step_rate_time_ = 1;
|
|
|
|
int head_unload_time_ = 1;
|
|
|
|
int head_load_time_ = 1;
|
|
|
|
bool dma_mode_ = false;
|
|
|
|
bool is_executing_ = false;
|
2017-08-12 16:52:36 +00:00
|
|
|
|
|
|
|
// A count of head unload timers currently running.
|
2017-08-12 13:36:21 +00:00
|
|
|
int head_timers_running_;
|
2017-08-06 22:06:20 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Transient storage and counters used while reading the disk.
|
2017-08-06 22:06:20 +00:00
|
|
|
uint8_t header_[6];
|
2017-08-07 00:40:29 +00:00
|
|
|
int distance_into_section_;
|
2017-08-15 20:05:10 +00:00
|
|
|
int index_hole_count_, index_hole_limit_;
|
2017-08-06 23:57:34 +00:00
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Keeps track of the drive and head in use during commands.
|
2017-08-12 13:36:21 +00:00
|
|
|
int active_drive_;
|
|
|
|
int active_head_;
|
|
|
|
|
2017-08-12 16:52:36 +00:00
|
|
|
// Internal registers.
|
2017-08-06 23:57:34 +00:00
|
|
|
uint8_t cylinder_, head_, sector_, size_;
|
2017-08-07 14:31:32 +00:00
|
|
|
|
2017-08-20 14:43:53 +00:00
|
|
|
// Master switch on not performing any work.
|
|
|
|
bool is_sleeping_;
|
2017-08-05 23:45:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
2017-08-14 12:38:00 +00:00
|
|
|
}
|
2017-08-05 23:45:52 +00:00
|
|
|
|
|
|
|
#endif /* i8272_hpp */
|