1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-20 15:31:10 +00:00
CLK/Storage/MassStorage/SCSI/SCSI.cpp

100 lines
3.0 KiB
C++

//
// SCSI.cpp
// Clock Signal
//
// Created by Thomas Harte on 12/08/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#include "SCSI.hpp"
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() {
const auto slot = device_states_.size();
device_states_.push_back(DefaultBusState);
return slot;
}
void Bus::set_device_output(size_t device, BusState output) {
if(device_states_[device] == output) return;
device_states_[device] = output;
const auto previous_state = state_;
state_ = DefaultBusState;
for(auto state: device_states_) {
state_ |= state;
}
if(state_ == previous_state) return;
printf("SCSI bus: %02x %c%c%c%c%c%c%c%c%c%c\n",
state_ & 0xff,
(state_ & Line::Parity) ? 'p' : '-',
(state_ & Line::SelectTarget) ? 's' : '-',
(state_ & Line::Attention) ? 't' : '-',
(state_ & Line::Control) ? 'c' : '-',
(state_ & Line::Busy) ? 'b' : '-',
(state_ & Line::Acknowledge) ? 'a' : '-',
(state_ & Line::Reset) ? 'r' : '-',
(state_ & Line::Input) ? 'i' : '-',
(state_ & Line::Message) ? 'm' : '-',
(state_ & Line::Request) ? 'q' : '-'
);
bool was_asleep = preferred_clocking() == ClockingHint::Preference::None;
dispatch_index_ = 0;
time_in_state_ = HalfCycles(0);
if(was_asleep) update_clocking_observer();
}
BusState Bus::get_state() {
return state_;
}
void Bus::add_observer(Observer *observer) {
observers_.push_back(observer);
}
ClockingHint::Preference Bus::preferred_clocking() {
return (dispatch_index_ < dispatch_times_.size()) ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None;
}
void Bus::run_for(HalfCycles time) {
if(dispatch_index_ < dispatch_times_.size()) {
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_ < dispatch_times_.size()) {
++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();
}
}
}