mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-29 16:29:08 +00:00
Takes a first bash at implementing the new SCSI::Bus timing infrastructure.
This commit is contained in:
parent
310c722cc0
commit
2f8e31bc8b
@ -75,6 +75,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
|||||||
video_(audio_, drive_speed_accumulator_),
|
video_(audio_, drive_speed_accumulator_),
|
||||||
via_(via_port_handler_),
|
via_(via_port_handler_),
|
||||||
via_port_handler_(*this, clock_, keyboard_, video_, audio_, iwm_, mouse_),
|
via_port_handler_(*this, clock_, keyboard_, video_, audio_, iwm_, mouse_),
|
||||||
|
scsi_bus_(CLOCK_RATE * 2),
|
||||||
scsi_(scsi_bus_, CLOCK_RATE * 2),
|
scsi_(scsi_bus_, CLOCK_RATE * 2),
|
||||||
hard_drive_(scsi_bus_, 6 /* SCSI ID */),
|
hard_drive_(scsi_bus_, 6 /* SCSI ID */),
|
||||||
drives_{
|
drives_{
|
||||||
|
@ -10,6 +10,23 @@
|
|||||||
|
|
||||||
using namespace SCSI;
|
using namespace SCSI;
|
||||||
|
|
||||||
|
Bus::Bus(HalfCycles clock_rate) {
|
||||||
|
cycles_to_time_ = 1.0 / double(clock_rate.as_int());
|
||||||
|
|
||||||
|
// NB: note that the dispatch times below are **ORDERED**
|
||||||
|
// from least to greatest. Each box should contain the number
|
||||||
|
// of whole clock periods it will take to get the the first
|
||||||
|
// discrete moment after the required delay interval has been met.
|
||||||
|
dispatch_times_[0] = 1 + int(CableSkew / cycles_to_time_);
|
||||||
|
dispatch_times_[1] = 1 + int(DeskewDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[2] = 1 + int(BusFreeDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[3] = 1 + int(BusSettleDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[4] = 1 + int(BusClearDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[5] = 1 + int(BusSetDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[6] = 1 + int(ArbitrationDelay / cycles_to_time_);
|
||||||
|
dispatch_times_[7] = 1 + int(ResetHoldTime / cycles_to_time_);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Bus::add_device() {
|
size_t Bus::add_device() {
|
||||||
const auto slot = device_states_.size();
|
const auto slot = device_states_.size();
|
||||||
device_states_.push_back(DefaultBusState);
|
device_states_.push_back(DefaultBusState);
|
||||||
@ -41,9 +58,10 @@ void Bus::set_device_output(size_t device, BusState output) {
|
|||||||
(state_ & Line::Request) ? 'q' : '-'
|
(state_ & Line::Request) ? 'q' : '-'
|
||||||
);
|
);
|
||||||
|
|
||||||
for(auto &observer: observers_) {
|
bool was_asleep = preferred_clocking() == ClockingHint::Preference::None;
|
||||||
observer->scsi_bus_did_change(this, state_, 0.0);
|
dispatch_index_ = 0;
|
||||||
}
|
time_in_state_ = HalfCycles(0);
|
||||||
|
if(was_asleep) update_clocking_observer();
|
||||||
}
|
}
|
||||||
|
|
||||||
BusState Bus::get_state() {
|
BusState Bus::get_state() {
|
||||||
@ -53,3 +71,29 @@ BusState Bus::get_state() {
|
|||||||
void Bus::add_observer(Observer *observer) {
|
void Bus::add_observer(Observer *observer) {
|
||||||
observers_.push_back(observer);
|
observers_.push_back(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClockingHint::Preference Bus::preferred_clocking() {
|
||||||
|
return (dispatch_index_ < sizeof(dispatch_times_)) ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bus::run_for(HalfCycles time) {
|
||||||
|
if(dispatch_index_ < sizeof(dispatch_times_)) {
|
||||||
|
time_in_state_ += time;
|
||||||
|
|
||||||
|
const auto old_index = dispatch_index_;
|
||||||
|
const auto time_as_int = time_in_state_.as_int();
|
||||||
|
while(time_as_int >= dispatch_times_[dispatch_index_] && dispatch_index_ < sizeof(dispatch_times_)) {
|
||||||
|
++dispatch_index_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dispatch_index_ != old_index) {
|
||||||
|
for(auto &observer: observers_) {
|
||||||
|
observer->scsi_bus_did_change(this, state_, double(time_as_int) * cycles_to_time_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(preferred_clocking() == ClockingHint::Preference::None) {
|
||||||
|
update_clocking_observer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -57,6 +57,9 @@ enum Line: BusState {
|
|||||||
#define us(x) (x) / 1000000.0
|
#define us(x) (x) / 1000000.0
|
||||||
#define ns(x) (x) / 1000000000.0
|
#define ns(x) (x) / 1000000000.0
|
||||||
|
|
||||||
|
/// The minimum amount of time that reset must be held for.
|
||||||
|
constexpr double ResetHoldTime = us(25.0);
|
||||||
|
|
||||||
/// The minimum amount of time a SCSI device must wait after asserting ::Busy
|
/// The minimum amount of time a SCSI device must wait after asserting ::Busy
|
||||||
/// until the data bus can be inspected to see whether arbitration has been won.
|
/// until the data bus can be inspected to see whether arbitration has been won.
|
||||||
constexpr double ArbitrationDelay = us(1.7);
|
constexpr double ArbitrationDelay = us(1.7);
|
||||||
@ -81,9 +84,6 @@ constexpr double BusFreeDelay = ns(100.0);
|
|||||||
/// The minimum amount of time required for deskew of "certain signals". TODO: which?
|
/// The minimum amount of time required for deskew of "certain signals". TODO: which?
|
||||||
constexpr double DeskewDelay = ns(45.0);
|
constexpr double DeskewDelay = ns(45.0);
|
||||||
|
|
||||||
/// The minimum amount of time that reset must be held for.
|
|
||||||
constexpr double ResetHoldTime = us(25.0);
|
|
||||||
|
|
||||||
/// The maximum amount of time that propagation of a SCSI bus signal can take between
|
/// The maximum amount of time that propagation of a SCSI bus signal can take between
|
||||||
/// any two devices.
|
/// any two devices.
|
||||||
constexpr double CableSkew = ns(10.0);
|
constexpr double CableSkew = ns(10.0);
|
||||||
@ -91,8 +91,9 @@ constexpr double CableSkew = ns(10.0);
|
|||||||
#undef ns
|
#undef ns
|
||||||
#undef us
|
#undef us
|
||||||
|
|
||||||
class Bus {
|
class Bus: public ClockingHint::Source {
|
||||||
public:
|
public:
|
||||||
|
Bus(HalfCycles clock_rate);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Adds a device to the bus, returning the index it should use
|
Adds a device to the bus, returning the index it should use
|
||||||
@ -123,7 +124,22 @@ class Bus {
|
|||||||
*/
|
*/
|
||||||
void add_observer(Observer *);
|
void add_observer(Observer *);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
SCSI buses don't have a clock. But devices on the bus are concerned with time-based factors,
|
||||||
|
and `run_for` is the way that time propagates within this emulator. So please permit this
|
||||||
|
fiction.
|
||||||
|
*/
|
||||||
|
void run_for(HalfCycles);
|
||||||
|
|
||||||
|
/// As per ClockingHint::Source.
|
||||||
|
ClockingHint::Preference preferred_clocking() final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
HalfCycles time_in_state_;
|
||||||
|
double cycles_to_time_ = 1.0;
|
||||||
|
size_t dispatch_index_ = 0;
|
||||||
|
int dispatch_times_[8];
|
||||||
|
|
||||||
std::vector<BusState> device_states_;
|
std::vector<BusState> device_states_;
|
||||||
BusState state_ = DefaultBusState;
|
BusState state_ = DefaultBusState;
|
||||||
std::vector<Observer *> observers_;
|
std::vector<Observer *> observers_;
|
||||||
|
Loading…
Reference in New Issue
Block a user