1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Fixes control line modification by the 5380 and SCSI target command chaining.

So now I'm back to trying to guess how a SCSI command terminates re: the relative meanings of a message phase and a status phase.
This commit is contained in:
Thomas Harte 2019-09-02 23:14:37 -04:00
parent 318cdb41ea
commit 1c7e0f3c9d
4 changed files with 58 additions and 24 deletions

View File

@ -11,6 +11,7 @@
#include "../../Outputs/Log.hpp"
using namespace NCR::NCR5380;
using SCSI::Line;
NCR5380::NCR5380(SCSI::Bus &bus, int clock_rate) :
bus_(bus),
@ -19,7 +20,6 @@ NCR5380::NCR5380(SCSI::Bus &bus, int clock_rate) :
}
void NCR5380::write(int address, uint8_t value) {
using SCSI::Line;
switch(address & 7) {
case 0:
LOG("[SCSI 0] Set current SCSI bus state to " << PADHEX(2) << int(value));
@ -32,15 +32,14 @@ void NCR5380::write(int address, uint8_t value) {
bus_output_ &= ~(Line::Reset | Line::Acknowledge | Line::Busy | Line::SelectTarget | Line::Attention);
if(value & 0x80) bus_output_ |= Line::Reset;
if(value & 0x10) bus_output_ |= Line::Acknowledge;
if(value & 0x08) bus_output_ |= Line::Busy;
if(value & 0x04) bus_output_ |= Line::SelectTarget;
if(value & 0x02) bus_output_ |= Line::Attention;
/* bit 5 = differential enable if this were a 5381 */
test_mode_ = value & 0x40;
assert_data_bus_ = value & 0x01;
update_control_output();
} break;
case 2:
@ -74,15 +73,13 @@ void NCR5380::write(int address, uint8_t value) {
set_execution_state(ExecutionState::PerformingDMA);
break;
}
update_control_output();
break;
case 3: {
LOG("[SCSI 3] Set target command: " << PADHEX(2) << int(value));
bus_output_ &= ~(Line::Request | Line::Message | Line::Control | Line::Input);
if(value & 0x08) bus_output_ |= Line::Request;
if(value & 0x04) bus_output_ |= Line::Message;
if(value & 0x02) bus_output_ |= Line::Control;
if(value & 0x01) bus_output_ |= Line::Input;
target_command_ = value;
update_control_output();
} break;
case 4:
@ -119,14 +116,14 @@ void NCR5380::write(int address, uint8_t value) {
}
uint8_t NCR5380::read(int address) {
using SCSI::Line;
switch(address & 7) {
case 0:
LOG("[SCSI 0] Get current SCSI bus state: " << PADHEX(2) << (bus_.get_state() & 0xff));
if(dma_request_ && state_ == ExecutionState::PerformingDMA) {
bus_output_ |= SCSI::Line::Acknowledge;
dma_acknowledge_ = true;
dma_request_ = false;
update_control_output();
bus_.set_device_output(device_id_, bus_output_);
}
return uint8_t(bus_.get_state());
@ -147,15 +144,9 @@ uint8_t NCR5380::read(int address) {
LOG("[SCSI 2] Get mode");
return mode_;
case 3: {
case 3:
LOG("[SCSI 3] Get target command");
const auto bus_state = bus_.get_state();
return
((bus_state & SCSI::Line::Request) ? 0x08 : 0x00) |
((bus_state & SCSI::Line::Message) ? 0x04 : 0x00) |
((bus_state & SCSI::Line::Control) ? 0x02 : 0x00) |
((bus_state & SCSI::Line::Input) ? 0x01 : 0x00);
}
return target_command_;
case 4: {
const auto bus_state = bus_.get_state();
@ -175,7 +166,7 @@ uint8_t NCR5380::read(int address) {
case 5: {
const auto bus_state = bus_.get_state();
const bool phase_matches =
(bus_output_ & (Line::Message | Line::Control | Line::Input)) ==
(target_output() & (Line::Message | Line::Control | Line::Input)) ==
(bus_state & (Line::Message | Line::Control | Line::Input));
const uint8_t result =
@ -202,6 +193,30 @@ uint8_t NCR5380::read(int address) {
return 0;
}
SCSI::BusState NCR5380::target_output() {
SCSI::BusState output = SCSI::DefaultBusState;
if(target_command_ & 0x08) output |= Line::Request;
if(target_command_ & 0x04) output |= Line::Message;
if(target_command_ & 0x02) output |= Line::Control;
if(target_command_ & 0x01) output |= Line::Input;
return output;
}
void NCR5380::update_control_output() {
bus_output_ &= ~(Line::Request | Line::Message | Line::Control | Line::Input | Line::Acknowledge | Line::Attention);
if(mode_ & 0x40) {
// This is a target; C/D, I/O, /MSG and /REQ are signalled on the bus.
bus_output_ |= target_output();
} else {
// This is an initiator; /ATN and /ACK are signalled on the bus.
if(
(initiator_command_ & 0x10) ||
(state_ == ExecutionState::PerformingDMA && dma_acknowledge_)
) bus_output_ |= Line::Acknowledge;
if(initiator_command_ & 0x02) bus_output_ |= Line::Attention;
}
}
void NCR5380::run_for(Cycles cycles) {
if(state_ == ExecutionState::None) return;
@ -273,12 +288,12 @@ void NCR5380::run_for(Cycles cycles) {
dma_request_ = false;
break;
case SCSI::Line::Acknowledge:
bus_output_ &= ~SCSI::Line::Acknowledge;
dma_acknowledge_ = false;
dma_request_ = false;
update_control_output();
bus_.set_device_output(device_id_, bus_output_);
break;
}
bus_.set_device_output(device_id_, bus_output_);
break;
}
}

View File

@ -58,12 +58,15 @@ class NCR5380 final: public ClockingHint::Source {
size_t device_id_;
SCSI::BusState bus_output_ = SCSI::DefaultBusState;
SCSI::BusState expected_phase_ = SCSI::DefaultBusState;
uint8_t mode_ = 0xff;
uint8_t initiator_command_ = 0xff;
uint8_t data_bus_ = 0xff;
uint8_t target_command_ = 0xff;
bool test_mode_ = false;
bool assert_data_bus_ = false;
bool dma_request_ = false;
bool dma_acknowledge_ = false;
enum class ExecutionState {
None,
@ -75,6 +78,9 @@ class NCR5380 final: public ClockingHint::Source {
bool lost_arbitration_ = false, arbitration_in_progress_ = false;
void set_execution_state(ExecutionState state);
SCSI::BusState target_output();
void update_control_output();
};
}

View File

@ -141,6 +141,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
// Also watch for changes in clocking requirement from the SCSI chip.
if(model == Analyser::Static::Macintosh::Target::Model::MacPlus) {
scsi_.set_clocking_hint_observer(this);
scsi_bus_.set_clocking_hint_observer(this);
}
// The Mac runs at 7.8336mHz.

View File

@ -30,12 +30,12 @@ template <typename Executor> void Target<Executor>::scsi_bus_did_change(Bus *, B
}
// Check for an unexpected change of SCSI state.
/* if((phase_ > Phase::Command) && (new_state & (Line::Control | Line::Input | Line::Message)) != expected_control_state_) {
if((phase_ > Phase::Command) && (new_state & (Line::Control | Line::Input | Line::Message)) != expected_control_state_) {
phase_ = Phase::AwaitingSelection;
bus_state_ = DefaultBusState;
set_device_output(bus_state_);
return;
}*/
}
switch(phase_) {
/*
@ -203,8 +203,11 @@ template <typename Executor> void Target<Executor>::send_data(std::vector<uint8_
// Data out phase: control and message all reset, input set.
bus_state_ &= ~(Line::Control | Line::Input | Line::Message);
bus_state_ |= Line::Input;
phase_ = Phase::SendingData;
next_function_ = next;
data_ = std::move(data);
data_pointer_ = 0;
set_device_output(bus_state_);
}
@ -212,8 +215,11 @@ template <typename Executor> void Target<Executor>::send_data(std::vector<uint8_
template <typename Executor> void Target<Executor>::receive_data(size_t length, continuation next) {
// Data out phase: control, input and message all reset.
bus_state_ &= ~(Line::Control | Line::Input | Line::Message);
phase_ = Phase::ReceivingData;
next_function_ = next;
data_.resize(length);
data_pointer_ = 0;
set_device_output(bus_state_);
}
@ -222,7 +228,10 @@ template <typename Executor> void Target<Executor>::send_status(Status, continua
// Status phase: message reset, control and input set.
bus_state_ &= ~(Line::Control | Line::Input | Line::Message);
bus_state_ |= Line::Input | Line::Control;
phase_ = Phase::SendingStatus;
next_function_ = next;
set_device_output(bus_state_);
}
@ -230,7 +239,10 @@ template <typename Executor> void Target<Executor>::send_message(Message, contin
// Message out phase: message and control set, input reset.
bus_state_ &= ~(Line::Control | Line::Input | Line::Message);
bus_state_ |= Line::Message | Line::Control;
phase_ = Phase::SendingMessage;
next_function_ = next;
set_device_output(bus_state_);
}