mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-22 14:30:29 +00:00
Starts attempting to introduce a direct access device.
Without having access to the SCSI-1 standard, a lot of this is guesswork.
This commit is contained in:
parent
7e001c1d03
commit
0e0c789b02
57
Components/5380/DirectAccessDevice.cpp
Normal file
57
Components/5380/DirectAccessDevice.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// DirectAccessDevice.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 17/08/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "DirectAccessDevice.hpp"
|
||||
|
||||
using namespace SCSI;
|
||||
|
||||
DirectAccessDevice::DirectAccessDevice(Bus &bus, int scsi_id) :
|
||||
bus_(bus),
|
||||
scsi_id_mask_(BusState(1 << scsi_id)),
|
||||
scsi_bus_device_id_(bus.add_device()) {
|
||||
bus.add_observer(this);
|
||||
}
|
||||
|
||||
void DirectAccessDevice::scsi_bus_did_change(Bus *, BusState new_state) {
|
||||
/*
|
||||
"The target determines that it is selected when the SEL# signal
|
||||
and its SCSI ID bit are active and the BSY# and I#/O signals
|
||||
are false. It then asserts the signal within a selection abort
|
||||
time."
|
||||
*/
|
||||
|
||||
switch(state_) {
|
||||
case State::Inactive:
|
||||
if(
|
||||
(new_state & scsi_id_mask_) &&
|
||||
((new_state & (Line::SelectTarget | Line::Busy | Line::Input)) == Line::SelectTarget)
|
||||
) {
|
||||
state_ = State::Selected;
|
||||
bus_state_ |= Line::Busy | Line::Request;
|
||||
bus_.set_device_output(scsi_bus_device_id_, bus_state_);
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Selected:
|
||||
switch(new_state & (Line::Request | Line::Acknowledge)) {
|
||||
case Line::Request | Line::Acknowledge:
|
||||
bus_state_ &= ~Line::Request;
|
||||
printf("Got %02x maybe?\n", bus_state_ & 0xff);
|
||||
break;
|
||||
|
||||
case Line::Acknowledge:
|
||||
case 0:
|
||||
bus_state_ |= Line::Request;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
bus_.set_device_output(scsi_bus_device_id_, bus_state_);
|
||||
break;
|
||||
}
|
||||
}
|
44
Components/5380/DirectAccessDevice.hpp
Normal file
44
Components/5380/DirectAccessDevice.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// DirectAccessDevice.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 17/08/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef DirectAccessDevice_hpp
|
||||
#define DirectAccessDevice_hpp
|
||||
|
||||
#include "SCSI.hpp"
|
||||
|
||||
namespace SCSI {
|
||||
|
||||
/*!
|
||||
Models a SCSI direct access device, ordinarily some sort of
|
||||
hard drive.
|
||||
*/
|
||||
class DirectAccessDevice: public Bus::Observer {
|
||||
public:
|
||||
/*!
|
||||
Instantiates a direct access device attached to @c bus,
|
||||
with SCSI ID @c scsi_id — a number in the range 0 to 7.
|
||||
*/
|
||||
DirectAccessDevice(Bus &bus, int scsi_id);
|
||||
|
||||
private:
|
||||
void scsi_bus_did_change(Bus *, BusState new_state) final;
|
||||
|
||||
Bus &bus_;
|
||||
const BusState scsi_id_mask_;
|
||||
const size_t scsi_bus_device_id_;
|
||||
|
||||
enum class State {
|
||||
Inactive,
|
||||
Selected
|
||||
} state_ = State::Inactive;
|
||||
BusState bus_state_ = DefaultBusState;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* DirectAccessDevice_hpp */
|
@ -17,19 +17,27 @@ size_t Bus::add_device() {
|
||||
}
|
||||
|
||||
void Bus::set_device_output(size_t device, BusState output) {
|
||||
printf("%08x output\n", output);
|
||||
if(device_states_[device] == output) return;
|
||||
device_states_[device] = output;
|
||||
state_is_valid_ = false;
|
||||
}
|
||||
|
||||
BusState Bus::get_state() {
|
||||
if(!state_is_valid_) return state_;
|
||||
|
||||
state_is_valid_ = true;
|
||||
const auto previous_state = state_;
|
||||
state_ = DefaultBusState;
|
||||
for(auto state: device_states_) {
|
||||
state_ |= state;
|
||||
}
|
||||
if(state_ == previous_state) return;
|
||||
|
||||
printf("SCSI bus: %08x\n", state_);
|
||||
|
||||
for(auto &observer: observers_) {
|
||||
observer->scsi_bus_did_change(this, state_);
|
||||
}
|
||||
}
|
||||
|
||||
BusState Bus::get_state() {
|
||||
return state_;
|
||||
}
|
||||
|
||||
void Bus::add_observer(Observer *observer) {
|
||||
observers_.push_back(observer);
|
||||
}
|
||||
|
@ -70,10 +70,18 @@ class Bus {
|
||||
*/
|
||||
BusState get_state();
|
||||
|
||||
struct Observer {
|
||||
virtual void scsi_bus_did_change(Bus *, BusState new_state) = 0;
|
||||
};
|
||||
/*!
|
||||
Adds an observer.
|
||||
*/
|
||||
void add_observer(Observer *);
|
||||
|
||||
private:
|
||||
std::vector<BusState> device_states_;
|
||||
BusState state_ = DefaultBusState;
|
||||
bool state_is_valid_ = false;
|
||||
std::vector<Observer *> observers_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
using namespace NCR::NCR5380;
|
||||
|
||||
NCR5380::NCR5380(int clock_rate) : clock_rate_(clock_rate) {
|
||||
NCR5380::NCR5380(int clock_rate) :
|
||||
device_(bus_, 6),
|
||||
clock_rate_(clock_rate) {
|
||||
device_id_ = bus_.add_device();
|
||||
}
|
||||
|
||||
@ -28,16 +30,17 @@ void NCR5380::write(int address, uint8_t value) {
|
||||
LOG("[SCSI 1] Initiator command register set: " << PADHEX(2) << int(value));
|
||||
initiator_command_ = value;
|
||||
|
||||
SCSI::BusState mask = SCSI::DefaultBusState;
|
||||
if(value & 0x80) mask |= Line::Reset;
|
||||
test_mode_ = value & 0x40;
|
||||
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 */
|
||||
if(value & 0x10) mask |= Line::Acknowledge;
|
||||
if(value & 0x08) mask |= Line::Busy;
|
||||
if(value & 0x04) mask |= Line::SelectTarget;
|
||||
if(value & 0x02) mask |= Line::Attention;
|
||||
|
||||
test_mode_ = value & 0x40;
|
||||
assert_data_bus_ = value & 0x01;
|
||||
bus_output_ = (bus_output_ & ~(Line::Reset | Line::Acknowledge | Line::Busy | Line::SelectTarget | Line::Attention)) | mask;
|
||||
} break;
|
||||
|
||||
case 2:
|
||||
@ -74,9 +77,14 @@ void NCR5380::write(int address, uint8_t value) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case 3: {
|
||||
LOG("[SCSI 3] Set target command: " << PADHEX(2) << int(value));
|
||||
break;
|
||||
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;
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
LOG("[SCSI 4] Set select enabled: " << PADHEX(2) << int(value));
|
||||
@ -133,9 +141,15 @@ uint8_t NCR5380::read(int address) {
|
||||
LOG("[SCSI 2] Get mode");
|
||||
return mode_;
|
||||
|
||||
case 3:
|
||||
case 3: {
|
||||
LOG("[SCSI 3] Get target command");
|
||||
return 0xff;
|
||||
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);
|
||||
}
|
||||
|
||||
case 4: {
|
||||
LOG("[SCSI 4] Get current bus state");
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "SCSI.hpp"
|
||||
#include "DirectAccessDevice.hpp"
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
#include "../../ClockReceiver/ClockingHintSource.hpp"
|
||||
|
||||
@ -52,8 +53,12 @@ class NCR5380 final: public ClockingHint::Source {
|
||||
ClockingHint::Preference preferred_clocking() final;
|
||||
|
||||
private:
|
||||
const int clock_rate_;
|
||||
// TEMPORARY. For development expediency, the 5380 owns its own
|
||||
// SCSI bus and direct access device. These will be moved out.
|
||||
SCSI::Bus bus_;
|
||||
SCSI::DirectAccessDevice device_;
|
||||
|
||||
const int clock_rate_;
|
||||
size_t device_id_;
|
||||
|
||||
SCSI::BusState bus_output_ = SCSI::DefaultBusState;
|
||||
|
@ -619,6 +619,7 @@
|
||||
4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EAA1B587A5100552FC2 /* MainMenu.xib */; };
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */; };
|
||||
4BB73EC21B587A5100552FC2 /* Clock_SignalUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EC11B587A5100552FC2 /* Clock_SignalUITests.swift */; };
|
||||
4BB8F5272308E5A50015C2A6 /* DirectAccessDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB8F5252308E5A50015C2A6 /* DirectAccessDevice.cpp */; };
|
||||
4BBB70A4202011C2002FE009 /* MultiMediaTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A3202011C2002FE009 /* MultiMediaTarget.cpp */; };
|
||||
4BBB70A5202011C2002FE009 /* MultiMediaTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A3202011C2002FE009 /* MultiMediaTarget.cpp */; };
|
||||
4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB70A6202014E2002FE009 /* MultiCRTMachine.cpp */; };
|
||||
@ -1407,6 +1408,8 @@
|
||||
4BB73EC11B587A5100552FC2 /* Clock_SignalUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clock_SignalUITests.swift; sourceTree = "<group>"; };
|
||||
4BB73EC31B587A5100552FC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
4BB73ECF1B587A6700552FC2 /* Clock Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "Clock Signal.entitlements"; sourceTree = "<group>"; };
|
||||
4BB8F5252308E5A50015C2A6 /* DirectAccessDevice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DirectAccessDevice.cpp; sourceTree = "<group>"; };
|
||||
4BB8F5262308E5A50015C2A6 /* DirectAccessDevice.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DirectAccessDevice.hpp; sourceTree = "<group>"; };
|
||||
4BBB709C2020109C002FE009 /* DynamicMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DynamicMachine.hpp; sourceTree = "<group>"; };
|
||||
4BBB70A2202011C2002FE009 /* MultiMediaTarget.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MultiMediaTarget.hpp; sourceTree = "<group>"; };
|
||||
4BBB70A3202011C2002FE009 /* MultiMediaTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MultiMediaTarget.cpp; sourceTree = "<group>"; };
|
||||
@ -3333,6 +3336,8 @@
|
||||
4BDACBEB22FFA5D20045EF7E /* ncr5380.hpp */,
|
||||
4B89BCFA23024BB500EA0782 /* SCSI.cpp */,
|
||||
4B89BCFB23024BB500EA0782 /* SCSI.hpp */,
|
||||
4BB8F5252308E5A50015C2A6 /* DirectAccessDevice.cpp */,
|
||||
4BB8F5262308E5A50015C2A6 /* DirectAccessDevice.hpp */,
|
||||
);
|
||||
path = 5380;
|
||||
sourceTree = "<group>";
|
||||
@ -4143,6 +4148,7 @@
|
||||
4BCE0060227D39AB000CA200 /* Video.cpp in Sources */,
|
||||
4B4518A51F75FD1C00926311 /* SSD.cpp in Sources */,
|
||||
4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */,
|
||||
4BB8F5272308E5A50015C2A6 /* DirectAccessDevice.cpp in Sources */,
|
||||
4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */,
|
||||
4B7913CC1DFCD80E00175A82 /* Video.cpp in Sources */,
|
||||
4BDA00E622E699B000AC3CD0 /* CSMachine.mm in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user