mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Attempts to nudge the command phase further towards functioning.
This commit is contained in:
parent
8339e2044c
commit
955e909e61
@ -25,19 +25,36 @@ void DirectAccessDevice::scsi_bus_did_change(Bus *, BusState new_state) {
|
|||||||
time."
|
time."
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// A reset always takes precedence over anything else ongoing.
|
||||||
|
if(new_state & Line::Reset) {
|
||||||
|
phase_ = Phase::AwaitingSelection;
|
||||||
|
bus_state_ = DefaultBusState;
|
||||||
|
bus_.set_device_output(scsi_bus_device_id_, bus_state_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch(phase_) {
|
switch(phase_) {
|
||||||
case Phase::AwaitingSelection:
|
case Phase::AwaitingSelection:
|
||||||
if(
|
if(
|
||||||
(new_state & scsi_id_mask_) &&
|
(new_state & scsi_id_mask_) &&
|
||||||
((new_state & (Line::SelectTarget | Line::Busy | Line::Input)) == Line::SelectTarget)
|
((new_state & (Line::SelectTarget | Line::Busy | Line::Input)) == Line::SelectTarget)
|
||||||
) {
|
) {
|
||||||
|
printf("Selected\n");
|
||||||
phase_ = Phase::Command;
|
phase_ = Phase::Command;
|
||||||
bus_state_ |= Line::Busy | Line::Request | Line::Control; // Initiate the command phase: request a command byte.
|
bus_state_ |= Line::Busy; // Initiate the command phase: request a command byte.
|
||||||
bus_.set_device_output(scsi_bus_device_id_, bus_state_);
|
bus_.set_device_output(scsi_bus_device_id_, bus_state_);
|
||||||
|
} else {
|
||||||
|
if(!(new_state & scsi_id_mask_)) printf("No ID mask\n");
|
||||||
|
else printf("Not SEL|~BSY|~IO");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Phase::Command:
|
case Phase::Command:
|
||||||
|
// Wait for select to be disabled before beginning the control phase proper.
|
||||||
|
if((new_state & Line::SelectTarget)) return;
|
||||||
|
|
||||||
|
bus_state_ |= Line::Control;
|
||||||
|
|
||||||
switch(new_state & (Line::Request | Line::Acknowledge)) {
|
switch(new_state & (Line::Request | Line::Acknowledge)) {
|
||||||
// If request and acknowledge are both enabled, grab a byte and cancel the request.
|
// If request and acknowledge are both enabled, grab a byte and cancel the request.
|
||||||
case Line::Request | Line::Acknowledge:
|
case Line::Request | Line::Acknowledge:
|
||||||
|
@ -56,23 +56,15 @@ void NCR5380::write(int address, uint8_t value) {
|
|||||||
// bit 1: 1 = use DMA mode
|
// bit 1: 1 = use DMA mode
|
||||||
// bit 0: 1 = begin arbitration mode (device ID should be in register 0)
|
// bit 0: 1 = begin arbitration mode (device ID should be in register 0)
|
||||||
|
|
||||||
/*
|
|
||||||
Arbitration is accomplished using a bus-free filter to continuously monitor BSY.
|
|
||||||
If BSY remains inactive for at least 400 nsec then the SCSI bus is considered free
|
|
||||||
and arbitration may begin. Arbitration will begin if the bus is free, SEL is inactive
|
|
||||||
and the ARBITRATION bit (port 2, bit 0) is active. Once arbitration has begun
|
|
||||||
(BSY asserted), an arbitration delay of 2.2 /Lsec must elapse before the data bus
|
|
||||||
can be examined to deter- mine if arbitration has been won. This delay must be
|
|
||||||
implemented in the controlling software driver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(mode_ & 1) {
|
if(mode_ & 1) {
|
||||||
|
arbitration_in_progress_ = true;
|
||||||
if(state_ == ExecutionState::None) {
|
if(state_ == ExecutionState::None) {
|
||||||
set_execution_state(ExecutionState::WatchingBusy);
|
set_execution_state(ExecutionState::WatchingBusy);
|
||||||
arbitration_in_progress_ = true;
|
|
||||||
lost_arbitration_ = false;
|
lost_arbitration_ = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
arbitration_in_progress_ = false;
|
||||||
|
bus_output_ &= ~SCSI::Line::Busy;
|
||||||
set_execution_state(ExecutionState::None);
|
set_execution_state(ExecutionState::None);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -152,9 +144,8 @@ uint8_t NCR5380::read(int address) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 4: {
|
case 4: {
|
||||||
LOG("[SCSI 4] Get current bus state");
|
|
||||||
const auto bus_state = bus_.get_state();
|
const auto bus_state = bus_.get_state();
|
||||||
return
|
const uint8_t result =
|
||||||
((bus_state & SCSI::Line::Reset) ? 0x80 : 0x00) |
|
((bus_state & SCSI::Line::Reset) ? 0x80 : 0x00) |
|
||||||
((bus_state & SCSI::Line::Busy) ? 0x40 : 0x00) |
|
((bus_state & SCSI::Line::Busy) ? 0x40 : 0x00) |
|
||||||
((bus_state & SCSI::Line::Request) ? 0x20 : 0x00) |
|
((bus_state & SCSI::Line::Request) ? 0x20 : 0x00) |
|
||||||
@ -163,14 +154,17 @@ uint8_t NCR5380::read(int address) {
|
|||||||
((bus_state & SCSI::Line::Input) ? 0x04 : 0x00) |
|
((bus_state & SCSI::Line::Input) ? 0x04 : 0x00) |
|
||||||
((bus_state & SCSI::Line::SelectTarget) ? 0x02 : 0x00) |
|
((bus_state & SCSI::Line::SelectTarget) ? 0x02 : 0x00) |
|
||||||
((bus_state & SCSI::Line::Parity) ? 0x01 : 0x00);
|
((bus_state & SCSI::Line::Parity) ? 0x01 : 0x00);
|
||||||
|
LOG("[SCSI 4] Get current bus state: " << PADHEX(2) << int(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5: {
|
case 5: {
|
||||||
LOG("[SCSI 5] Get bus and status");
|
|
||||||
const auto bus_state = bus_.get_state();
|
const auto bus_state = bus_.get_state();
|
||||||
return
|
const uint8_t result =
|
||||||
((bus_state & SCSI::Line::Attention) ? 0x02 : 0x00) |
|
((bus_state & SCSI::Line::Attention) ? 0x02 : 0x00) |
|
||||||
((bus_state & SCSI::Line::Acknowledge) ? 0x01 : 0x00);
|
((bus_state & SCSI::Line::Acknowledge) ? 0x01 : 0x00);
|
||||||
|
LOG("[SCSI 5] Get bus and status: " << PADHEX(2) << int(result));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
@ -191,27 +185,48 @@ void NCR5380::run_for(Cycles cycles) {
|
|||||||
switch(state_) {
|
switch(state_) {
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case ExecutionState::WatchingBusy:
|
/*
|
||||||
/*
|
Official documentation:
|
||||||
|
|
||||||
Arbitration is accomplished using a bus-free filter to continuously monitor BSY.
|
Arbitration is accomplished using a bus-free filter to continuously monitor BSY.
|
||||||
If BSY remains inactive for at least 400 nsec then the SCSI bus is considered free
|
If BSY remains inactive for at least 400 nsec then the SCSI bus is considered free
|
||||||
and arbitration may begin. Arbitration will begin if the bus is free, SEL is inactive
|
and arbitration may begin. Arbitration will begin if the bus is free, SEL is inactive
|
||||||
and the ARBITRATION bit (port 2, bit 0) is active. Once arbitration has begun
|
and the ARBITRATION bit (port 2, bit 0) is active. Once arbitration has begun
|
||||||
(BSY asserted)...
|
(BSY asserted), an arbitration delay of 2.2 /Lsec must elapse before the data bus
|
||||||
*/
|
can be examined to deter- mine if arbitration has been won. This delay must be
|
||||||
if(bus_.get_state() & SCSI::Line::Busy) {
|
implemented in the controlling software driver.
|
||||||
lost_arbitration_ = true;
|
|
||||||
set_execution_state(ExecutionState::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for having hit the 400ns state.
|
Personal notes:
|
||||||
if(time_in_state_ == 400 * clock_rate_ / 1000000000) {
|
|
||||||
arbitration_in_progress_ = false;
|
I'm discounting that "arbitratation is accomplished" opening, and assuming that what needs
|
||||||
|
to happen is:
|
||||||
|
|
||||||
|
(i) wait for BSY to be inactive;
|
||||||
|
(ii) count 400 nsec;
|
||||||
|
(iii) check that BSY and SEL are inactive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
case ExecutionState::WatchingBusy:
|
||||||
|
if(bus_.get_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;
|
||||||
|
set_execution_state(ExecutionState::None);
|
||||||
|
} else {
|
||||||
|
time_in_state_ = 0;
|
||||||
|
}
|
||||||
|
} /* else {
|
||||||
|
arbitration_in_progress_ = true;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Check for having hit 400ns (more or less) since BSY was inactive.
|
||||||
|
if(!lost_arbitration_ && time_in_state_ == int(int64_t(400) * int64_t(clock_rate_) / int64_t(1000000000))) {
|
||||||
|
// arbitration_in_progress_ = false;
|
||||||
if(bus_.get_state() & SCSI::Line::SelectTarget) {
|
if(bus_.get_state() & SCSI::Line::SelectTarget) {
|
||||||
lost_arbitration_ = true;
|
lost_arbitration_ = true;
|
||||||
set_execution_state(ExecutionState::None);
|
set_execution_state(ExecutionState::None);
|
||||||
} else {
|
} else {
|
||||||
bus_output_ |= SCSI::Line::Busy;
|
bus_output_ &= ~SCSI::Line::Busy;
|
||||||
set_execution_state(ExecutionState::None);
|
set_execution_state(ExecutionState::None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,6 +236,7 @@ void NCR5380::run_for(Cycles cycles) {
|
|||||||
|
|
||||||
void NCR5380::set_execution_state(ExecutionState state) {
|
void NCR5380::set_execution_state(ExecutionState state) {
|
||||||
time_in_state_ = 0;
|
time_in_state_ = 0;
|
||||||
|
state_ = state;
|
||||||
update_clocking_observer();
|
update_clocking_observer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,5 +244,5 @@ ClockingHint::Preference NCR5380::preferred_clocking() {
|
|||||||
// Request real-time clocking if any sort of timed bus watching is ongoing,
|
// 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
|
// given that there's no knowledge in here as to what clocking other devices
|
||||||
// on the SCSI bus might be enjoying.
|
// on the SCSI bus might be enjoying.
|
||||||
return (state_ == ExecutionState::None) ? ClockingHint::Preference::RealTime : ClockingHint::Preference::None;
|
return (state_ == ExecutionState::None) ? ClockingHint::Preference::None : ClockingHint::Preference::RealTime;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user