diff --git a/Components/5380/ncr5380.cpp b/Components/5380/ncr5380.cpp index 3da7fabb0..2bfb20aa1 100644 --- a/Components/5380/ncr5380.cpp +++ b/Components/5380/ncr5380.cpp @@ -55,17 +55,24 @@ void NCR5380::write(int address, uint8_t value) { // bit 2: 1 = generate an interrupt and reset low 6 bits of register 1 if an unexpected loss of Line::Busy occurs // bit 1: 1 = use DMA mode // bit 0: 1 = begin arbitration mode (device ID should be in register 0) + arbitration_in_progress_ = false; + switch(mode_ & 0x3) { + case 0x0: + bus_output_ &= ~SCSI::Line::Busy; + dma_request_ = false; + set_execution_state(ExecutionState::None); + break; - if(mode_ & 1) { - arbitration_in_progress_ = true; - if(state_ == ExecutionState::None) { + case 0x1: + arbitration_in_progress_ = true; set_execution_state(ExecutionState::WatchingBusy); lost_arbitration_ = false; - } - } else { - arbitration_in_progress_ = false; - bus_output_ &= ~SCSI::Line::Busy; - set_execution_state(ExecutionState::None); + break; + + default: + assert_data_bus_ = false; // TODO: proper logic for this. + set_execution_state(ExecutionState::PerformingDMA); + break; } break; @@ -115,7 +122,13 @@ uint8_t NCR5380::read(int address) { using SCSI::Line; switch(address & 7) { case 0: - LOG("[SCSI 0] Get current SCSI bus state"); + 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_request_ = false; + bus_.set_device_output(device_id_, bus_output_); + } return uint8_t(bus_.get_state()); case 1: @@ -166,7 +179,12 @@ uint8_t NCR5380::read(int address) { (bus_state & (Line::Message | Line::Control | Line::Input)); const uint8_t result = + /* b7 = end of DMA */ + ((dma_request_ && state_ == ExecutionState::PerformingDMA) ? 0x40 : 0x00) | + /* b5 = parity error */ + /* b4 = IRQ active */ (phase_matches ? 0x08 : 0x00) | + /* b2 = busy error */ ((bus_state & Line::Attention) ? 0x02 : 0x00) | ((bus_state & Line::Acknowledge) ? 0x01 : 0x00); LOG("[SCSI 5] Get bus and status: " << PADHEX(2) << int(result)); @@ -187,6 +205,7 @@ uint8_t NCR5380::read(int address) { void NCR5380::run_for(Cycles cycles) { if(state_ == ExecutionState::None) return; + const auto bus_state = bus_.get_state(); ++time_in_state_; switch(state_) { default: break; @@ -213,7 +232,7 @@ void NCR5380::run_for(Cycles cycles) { */ case ExecutionState::WatchingBusy: - if(bus_.get_state() & SCSI::Line::Busy) { + if(bus_state & SCSI::Line::Busy) { // Arbitration is lost only if a non-busy state had previously been observed. if(time_in_state_ > 1) { lost_arbitration_ = true; @@ -236,6 +255,30 @@ void NCR5380::run_for(Cycles cycles) { set_execution_state(ExecutionState::None); } } + + /* TODO: there's a bug here, given that the dropping of Busy isn't communicated onward. */ + break; + + case ExecutionState::PerformingDMA: + // Signal a DMA request if the request line is active, i.e. meaningful data is + // on the bus, and this device hasn't yet acknowledged it. + switch(bus_state & (SCSI::Line::Request | SCSI::Line::Acknowledge)) { + case 0: + dma_request_ = false; + break; + case SCSI::Line::Request: + dma_request_ = true; + break; + case SCSI::Line::Request | SCSI::Line::Acknowledge: + dma_request_ = false; + break; + case SCSI::Line::Acknowledge: + bus_output_ &= ~SCSI::Line::Acknowledge; + dma_request_ = false; + break; + } + + bus_.set_device_output(device_id_, bus_output_); break; } } @@ -250,5 +293,5 @@ ClockingHint::Preference NCR5380::preferred_clocking() { // Request real-time clocking if any sort of timed bus watching is ongoing, // given that there's no knowledge in here as to what clocking other devices // on the SCSI bus might be enjoying. - return (state_ == ExecutionState::None) ? ClockingHint::Preference::None : ClockingHint::Preference::RealTime; + return (state_ < ExecutionState::WatchingBusy) ? ClockingHint::Preference::None : ClockingHint::Preference::RealTime; } diff --git a/Components/5380/ncr5380.hpp b/Components/5380/ncr5380.hpp index a1630e7eb..6652d4487 100644 --- a/Components/5380/ncr5380.hpp +++ b/Components/5380/ncr5380.hpp @@ -67,11 +67,13 @@ class NCR5380 final: public ClockingHint::Source { uint8_t data_bus_ = 0xff; bool test_mode_ = false; bool assert_data_bus_ = false; + bool dma_request_ = false; enum class ExecutionState { None, WatchingBusy, + PerformingDMA, } state_ = ExecutionState::None; int time_in_state_ = 0; bool lost_arbitration_ = false, arbitration_in_progress_ = false; diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index 88b0f9456..77658bfa8 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -12,6 +12,9 @@ using namespace SCSI; bool DirectAccessDevice::read(const Target::CommandState &state, Target::Responder &responder) { std::vector data(512); + for(size_t c = 0; c < 512; ++c) { + data[c] = uint8_t(c); + } responder.send_data(std::move(data), [] (const Target::CommandState &state, Target::Responder &responder) { responder.end_command(); diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 568c1ee5e..24200dd5e 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -103,6 +103,7 @@ template void Target::scsi_bus_did_change(Bus *, B bus_state_ &= ~(Line::Request | 0xff); ++data_pointer_; + printf("DP: %zu\n", data_pointer_); if(data_pointer_ == data_.size()) { next_function_(CommandState(command_), *this); } @@ -111,6 +112,7 @@ template void Target::scsi_bus_did_change(Bus *, B case 0: bus_state_ |= Line::Request; bus_state_ = (bus_state_ & ~0xff) | data_[data_pointer_]; + printf("Lower bus: %02x\n", bus_state_ & 0xff); break; } bus_.set_device_output(scsi_bus_device_id_, bus_state_);