diff --git a/Components/5380/ncr5380.cpp b/Components/5380/ncr5380.cpp index cfead1238..46ed3388f 100644 --- a/Components/5380/ncr5380.cpp +++ b/Components/5380/ncr5380.cpp @@ -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; } } diff --git a/Components/5380/ncr5380.hpp b/Components/5380/ncr5380.hpp index 8314eeea7..7a04ee3d9 100644 --- a/Components/5380/ncr5380.hpp +++ b/Components/5380/ncr5380.hpp @@ -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(); }; } diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index a7d37d024..193b02860 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -141,6 +141,7 @@ template 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. diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 98d1b24ad..29cc8616e 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -30,12 +30,12 @@ template void Target::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 void Target::send_data(std::vector void Target::send_data(std::vector void Target::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 void Target::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 void Target::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_); }