diff --git a/Components/5380/ncr5380.cpp b/Components/5380/ncr5380.cpp index 2bfb20aa1..cfead1238 100644 --- a/Components/5380/ncr5380.cpp +++ b/Components/5380/ncr5380.cpp @@ -12,8 +12,8 @@ using namespace NCR::NCR5380; -NCR5380::NCR5380(int clock_rate) : - device_(bus_, 6), +NCR5380::NCR5380(SCSI::Bus &bus, int clock_rate) : + bus_(bus), clock_rate_(clock_rate) { device_id_ = bus_.add_device(); } diff --git a/Components/5380/ncr5380.hpp b/Components/5380/ncr5380.hpp index 6652d4487..8314eeea7 100644 --- a/Components/5380/ncr5380.hpp +++ b/Components/5380/ncr5380.hpp @@ -12,7 +12,6 @@ #include #include "../../Storage/MassStorage/SCSI/SCSI.hpp" -#include "../../Storage/MassStorage/SCSI/DirectAccessDevice.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" #include "../../ClockReceiver/ClockingHintSource.hpp" @@ -25,7 +24,7 @@ namespace NCR5380 { */ class NCR5380 final: public ClockingHint::Source { public: - NCR5380(int clock_rate); + NCR5380(SCSI::Bus &bus, int clock_rate); /*! Writes @c value to @c address. */ void write(int address, uint8_t value); @@ -53,10 +52,7 @@ class NCR5380 final: public ClockingHint::Source { ClockingHint::Preference preferred_clocking() final; private: - // TEMPORARY. For development expediency, the 5380 owns its own - // SCSI bus and target. These will be moved out. - SCSI::Bus bus_; - SCSI::Target::Target device_; + SCSI::Bus &bus_; const int clock_rate_; size_t device_id_; diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index e84689238..b81786d85 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -37,6 +37,9 @@ #include "../../../Components/DiskII/MacintoshDoubleDensityDrive.hpp" #include "../../../Processors/68000/68000.hpp" +#include "../../../Storage/MassStorage/SCSI/SCSI.hpp" +#include "../../../Storage/MassStorage/SCSI/DirectAccessDevice.hpp" + #include "../../../Analyser/Static/Macintosh/Target.hpp" #include "../../Utility/MemoryPacker.hpp" @@ -71,7 +74,8 @@ template class ConcreteMachin video_(audio_, drive_speed_accumulator_), via_(via_port_handler_), via_port_handler_(*this, clock_, keyboard_, video_, audio_, iwm_, mouse_), - scsi_(CLOCK_RATE * 2), + scsi_(scsi_bus_, CLOCK_RATE * 2), + hard_drive_(scsi_bus_, 6 /* SCSI ID */), drives_{ {CLOCK_RATE, model >= Analyser::Static::Macintosh::Target::Model::Mac512ke}, {CLOCK_RATE, model >= Analyser::Static::Macintosh::Target::Model::Mac512ke} @@ -435,16 +439,23 @@ template class ConcreteMachin } bool insert_media(const Analyser::Static::Media &media) override { - if(media.disks.empty()) + if(media.disks.empty() && media.mass_storage_devices.empty()) return false; // TODO: shouldn't allow disks to be replaced like this, as the Mac // uses software eject. Will need to expand messaging ability of // insert_media. - if(drives_[0].has_disk()) - drives_[1].set_disk(media.disks[0]); - else - drives_[0].set_disk(media.disks[0]); + if(!media.disks.empty()) { + if(drives_[0].has_disk()) + drives_[1].set_disk(media.disks[0]); + else + drives_[0].set_disk(media.disks[0]); + } + + // TODO: allow this only at machine startup. + if(!media.mass_storage_devices.empty()) { + hard_drive_->set_storage(media.mass_storage_devices.front()); + } return true; } @@ -720,7 +731,9 @@ template class ConcreteMachin VIAPortHandler via_port_handler_; Zilog::SCC::z8530 scc_; + SCSI::Bus scsi_bus_; NCR::NCR5380::NCR5380 scsi_; + SCSI::Target::Target hard_drive_; bool scsi_is_clocked_ = false; HalfCycles via_clock_; diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp index 77658bfa8..5194056ce 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.cpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.cpp @@ -10,13 +10,15 @@ 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) { +void DirectAccessDevice::set_storage(const std::shared_ptr &device) { + device_ = device; +} + +bool DirectAccessDevice::read(const Target::CommandState &state, Target::Responder &responder) { + if(!device_) return false; + + responder.send_data(device_->get_block(state.address()), [] (const Target::CommandState &state, Target::Responder &responder) { responder.end_command(); }); diff --git a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp index 72915acb9..e3f18575f 100644 --- a/Storage/MassStorage/SCSI/DirectAccessDevice.hpp +++ b/Storage/MassStorage/SCSI/DirectAccessDevice.hpp @@ -10,12 +10,25 @@ #define SCSI_DirectAccessDevice_hpp #include "Target.hpp" +#include "../MassStorageDevice.hpp" + +#include namespace SCSI { class DirectAccessDevice: public Target::Executor { public: + + /*! + Sets the backing storage exposed by this direct-access device. + */ + void set_storage(const std::shared_ptr &device); + + /* SCSI commands. */ bool read(const Target::CommandState &, Target::Responder &); + + private: + std::shared_ptr device_; }; } diff --git a/Storage/MassStorage/SCSI/Target.cpp b/Storage/MassStorage/SCSI/Target.cpp index 0b97a5ccd..dc0520e87 100644 --- a/Storage/MassStorage/SCSI/Target.cpp +++ b/Storage/MassStorage/SCSI/Target.cpp @@ -12,7 +12,7 @@ using namespace SCSI::Target; CommandState::CommandState(const std::vector &data) : data_(data) {} -uint32_t CommandState::address() { +uint32_t CommandState::address() const { switch(data_.size()) { default: return 0; case 6: @@ -30,7 +30,7 @@ uint32_t CommandState::address() { } } -uint16_t CommandState::number_of_blocks() { +uint16_t CommandState::number_of_blocks() const { switch(data_.size()) { default: return 0; case 6: diff --git a/Storage/MassStorage/SCSI/Target.hpp b/Storage/MassStorage/SCSI/Target.hpp index 150b8d162..4878b657a 100644 --- a/Storage/MassStorage/SCSI/Target.hpp +++ b/Storage/MassStorage/SCSI/Target.hpp @@ -24,8 +24,8 @@ class CommandState { public: CommandState(const std::vector &data); - uint32_t address(); - uint16_t number_of_blocks(); + uint32_t address() const; + uint16_t number_of_blocks() const; private: const std::vector &data_; @@ -134,9 +134,13 @@ template class Target: public Bus::Observer, public Responde */ Target(Bus &bus, int scsi_id); - Executor executor; + inline Executor *operator->() { + return &executor_; + } private: + Executor executor_; + // Bus::Observer. void scsi_bus_did_change(Bus *, BusState new_state) final; diff --git a/Storage/MassStorage/SCSI/TargetImplementation.hpp b/Storage/MassStorage/SCSI/TargetImplementation.hpp index 24200dd5e..96f11d64d 100644 --- a/Storage/MassStorage/SCSI/TargetImplementation.hpp +++ b/Storage/MassStorage/SCSI/TargetImplementation.hpp @@ -147,29 +147,29 @@ template bool Target::dispatch_command() { switch(command_[0]) { default: return false; - case G0(0x00): return executor.test_unit_ready(arguments, *this); - case G0(0x01): return executor.rezero_unit(arguments, *this); - case G0(0x03): return executor.request_sense(arguments, *this); - case G0(0x04): return executor.format_unit(arguments, *this); - case G0(0x08): return executor.read(arguments, *this); - case G0(0x0a): return executor.write(arguments, *this); - case G0(0x0b): return executor.seek(arguments, *this); - case G0(0x16): return executor.reserve_unit(arguments, *this); - case G0(0x17): return executor.release_unit(arguments, *this); - case G0(0x1c): return executor.read_diagnostic(arguments, *this); - case G0(0x1d): return executor.write_diagnostic(arguments, *this); - case G0(0x12): return executor.inquiry(arguments, *this); + case G0(0x00): return executor_.test_unit_ready(arguments, *this); + case G0(0x01): return executor_.rezero_unit(arguments, *this); + case G0(0x03): return executor_.request_sense(arguments, *this); + case G0(0x04): return executor_.format_unit(arguments, *this); + case G0(0x08): return executor_.read(arguments, *this); + case G0(0x0a): return executor_.write(arguments, *this); + case G0(0x0b): return executor_.seek(arguments, *this); + case G0(0x16): return executor_.reserve_unit(arguments, *this); + case G0(0x17): return executor_.release_unit(arguments, *this); + case G0(0x1c): return executor_.read_diagnostic(arguments, *this); + case G0(0x1d): return executor_.write_diagnostic(arguments, *this); + case G0(0x12): return executor_.inquiry(arguments, *this); - case G1(0x05): return executor.read_capacity(arguments, *this); - case G1(0x08): return executor.read(arguments, *this); - case G1(0x0a): return executor.write(arguments, *this); - case G1(0x0e): return executor.write_and_verify(arguments, *this); - case G1(0x0f): return executor.verify(arguments, *this); - case G1(0x11): return executor.search_data_equal(arguments, *this); - case G1(0x10): return executor.search_data_high(arguments, *this); - case G1(0x12): return executor.search_data_low(arguments, *this); + case G1(0x05): return executor_.read_capacity(arguments, *this); + case G1(0x08): return executor_.read(arguments, *this); + case G1(0x0a): return executor_.write(arguments, *this); + case G1(0x0e): return executor_.write_and_verify(arguments, *this); + case G1(0x0f): return executor_.verify(arguments, *this); + case G1(0x11): return executor_.search_data_equal(arguments, *this); + case G1(0x10): return executor_.search_data_high(arguments, *this); + case G1(0x12): return executor_.search_data_low(arguments, *this); - case G5(0x09): return executor.set_block_limits(arguments, *this); + case G5(0x09): return executor_.set_block_limits(arguments, *this); } #undef G0