1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-13 22:32:03 +00:00

Introduces real hard disk images to the nascent world of SCSI.

This commit is contained in:
Thomas Harte 2019-08-25 17:03:41 -04:00
parent 30cef1ee22
commit ca08716c52
8 changed files with 74 additions and 46 deletions

View File

@ -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();
}

View File

@ -12,7 +12,6 @@
#include <cstdint>
#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<SCSI::DirectAccessDevice> device_;
SCSI::Bus &bus_;
const int clock_rate_;
size_t device_id_;

View File

@ -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 <Analyser::Static::Macintosh::Target::Model model> 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 <Analyser::Static::Macintosh::Target::Model model> 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 <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
VIAPortHandler via_port_handler_;
Zilog::SCC::z8530 scc_;
SCSI::Bus scsi_bus_;
NCR::NCR5380::NCR5380 scsi_;
SCSI::Target::Target<SCSI::DirectAccessDevice> hard_drive_;
bool scsi_is_clocked_ = false;
HalfCycles via_clock_;

View File

@ -10,13 +10,15 @@
using namespace SCSI;
bool DirectAccessDevice::read(const Target::CommandState &state, Target::Responder &responder) {
std::vector<uint8_t> 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<Storage::MassStorage::MassStorageDevice> &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();
});

View File

@ -10,12 +10,25 @@
#define SCSI_DirectAccessDevice_hpp
#include "Target.hpp"
#include "../MassStorageDevice.hpp"
#include <memory>
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<Storage::MassStorage::MassStorageDevice> &device);
/* SCSI commands. */
bool read(const Target::CommandState &, Target::Responder &);
private:
std::shared_ptr<Storage::MassStorage::MassStorageDevice> device_;
};
}

View File

@ -12,7 +12,7 @@ using namespace SCSI::Target;
CommandState::CommandState(const std::vector<uint8_t> &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:

View File

@ -24,8 +24,8 @@ class CommandState {
public:
CommandState(const std::vector<uint8_t> &data);
uint32_t address();
uint16_t number_of_blocks();
uint32_t address() const;
uint16_t number_of_blocks() const;
private:
const std::vector<uint8_t> &data_;
@ -134,9 +134,13 @@ template <typename Executor> 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;

View File

@ -147,29 +147,29 @@ template <typename Executor> bool Target<Executor>::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