1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

This appears to be sufficient for the Electron to _read_ SCSI.

So that's step one.
This commit is contained in:
Thomas Harte 2021-01-31 18:36:29 -05:00
parent f1ba040dd8
commit 906b6ccdb7
5 changed files with 108 additions and 21 deletions

View File

@ -146,6 +146,9 @@ Analyser::Static::TargetList Analyser::Static::Acorn::GetTargets(const Media &me
if(!media.mass_storage_devices.empty()) {
target->has_pres_adfs = false;
target->has_acorn_adfs = true;
// TODO: validate an ADFS catalogue, at least.
target->media.mass_storage_devices = media.mass_storage_devices;
}
TargetList targets;

View File

@ -17,6 +17,9 @@
#include "../../Configurable/StandardOptions.hpp"
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
#include "../../Processors/6502/6502.hpp"
#include "../../Storage/MassStorage/SCSI/SCSI.hpp"
#include "../../Storage/MassStorage/SCSI/DirectAccessDevice.hpp"
#include "../../Storage/Tape/Tape.hpp"
#include "../Utility/Typer.hpp"
@ -31,7 +34,7 @@
namespace Electron {
class ConcreteMachine:
template <bool has_scsi_bus> class ConcreteMachine:
public Machine,
public MachineTypes::TimedMachine,
public MachineTypes::ScanProducer,
@ -46,6 +49,9 @@ class ConcreteMachine:
public:
ConcreteMachine(const Analyser::Static::Acorn::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
m6502_(*this),
scsi_bus_(4'000'000),
hard_drive_(scsi_bus_, 0),
scsi_device_(scsi_bus_.add_device()),
video_output_(ram_),
sound_generator_(audio_queue_),
speaker_(sound_generator_) {
@ -202,7 +208,12 @@ class ConcreteMachine:
set_rom(slot, cartridge->get_segments().front().data, false);
}
return !media.tapes.empty() || !media.disks.empty() || !media.cartridges.empty();
// TODO: allow this only at machine startup?
if(!media.mass_storage_devices.empty()) {
hard_drive_->set_storage(media.mass_storage_devices.front());
}
return !media.empty();
}
forceinline Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) {
@ -307,7 +318,6 @@ class ConcreteMachine:
break;
case 0xfc04: case 0xfc05: case 0xfc06: case 0xfc07:
printf("%04x %s %02x\n", address, isReadOperation(operation) ? "->" : "<-", *value);
if(plus3_ && (address&0x00f0) == 0x00c0) {
if(is_holding_shift_ && address == 0xfcc4) {
is_holding_shift_ = false;
@ -320,15 +330,62 @@ class ConcreteMachine:
}
break;
case 0xfc00:
printf("%04x %s %02x\n", address, isReadOperation(operation) ? "->" : "<-", *value);
if(plus3_ && (address&0x00f0) == 0x00c0) {
if(!isReadOperation(operation)) {
plus3_->set_control_register(*value);
} else *value = 1;
}
if(has_scsi_bus && (address&0x00f0) == 0x0040) {
scsi_acknowledge_ = true;
if(!isReadOperation(operation)) {
scsi_data_ = *value;
push_scsi_output();
} else {
*value = SCSI::data_lines(scsi_bus_.get_state());
push_scsi_output();
}
}
break;
case 0xfc03:
printf("%04x %s %02x\n", address, isReadOperation(operation) ? "->" : "<-", *value);
if(has_scsi_bus && (address&0x00f0) == 0x0040) {
printf("SCSI IRQ: %s %02x\n", isReadOperation(operation) ? "->" : "<-", *value);
}
break;
case 0xfc01:
if(has_scsi_bus && (address&0x00f0) == 0x0040 && isReadOperation(operation)) {
// Status byte is:
//
// b7: SCSI C/D
// b6: SCSI I/O
// b5: SCSI REQ
// b4: interrupt flag
// b3: 0
// b2: 0
// b1: SCSI BSY
// b0: SCSI MSG
const auto state = scsi_bus_.get_state();
*value =
(state & SCSI::Line::Control ? 0x80 : 0x00) |
(state & SCSI::Line::Input ? 0x40 : 0x00) |
(state & SCSI::Line::Request ? 0x20 : 0x00) |
(state & SCSI::Line::Busy ? 0x02 : 0x00) |
(state & SCSI::Line::Message ? 0x01 : 0x00);
// TODO: interrupt flag.
// Empirical guess: this is also the trigger to affect busy/request/acknowledge
// signalling. Maybe?
if(scsi_select_ && scsi_bus_.get_state() & SCSI::Line::Busy) {
scsi_select_ = false;
push_scsi_output();
}
}
break;
case 0xfc02:
if(has_scsi_bus && (address&0x00f0) == 0x0040) {
scsi_select_ = true;
push_scsi_output();
}
break;
// SCSI locations:
@ -338,16 +395,6 @@ class ConcreteMachine:
// fc42: select write
// fc43: interrupt latch
//
// Status byte is:
//
// b7: SCSI C/D
// b6: SCSI I/O
// b5: SCSI REQ
// b4: interrupt flag
// b3: 0
// b2: 0
// b1: SCSI BSY
// b0: SCSI MSG
//
// Interrupt latch is:
//
@ -451,6 +498,16 @@ class ConcreteMachine:
}
}
// TODO: clock/change observe.
if(has_scsi_bus) {
scsi_bus_.run_for(Cycles(int(cycles)));
if(scsi_acknowledge_ && !(scsi_bus_.get_state() & SCSI::Line::Request)) {
scsi_acknowledge_ = false;
push_scsi_output();
}
}
return Cycles(int(cycles));
}
@ -681,6 +738,21 @@ class ConcreteMachine:
bool is_holding_shift_ = false;
int shift_restart_counter_ = 0;
// Hard drive.
SCSI::Bus scsi_bus_;
SCSI::Target::Target<SCSI::DirectAccessDevice> hard_drive_;
const size_t scsi_device_ = 0;
uint8_t scsi_data_ = 0;
bool scsi_select_ = false;
bool scsi_acknowledge_ = false;
void push_scsi_output() {
scsi_bus_.set_device_output(scsi_device_,
scsi_data_ |
(scsi_select_ ? SCSI::Line::SelectTarget : 0) |
(scsi_acknowledge_ ? SCSI::Line::Acknowledge : 0)
);
}
// Outputs
VideoOutput video_output_;
@ -703,7 +775,12 @@ using namespace Electron;
Machine *Machine::Electron(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
using Target = Analyser::Static::Acorn::Target;
const Target *const acorn_target = dynamic_cast<const Target *>(target);
return new Electron::ConcreteMachine(*acorn_target, rom_fetcher);
if(acorn_target->media.mass_storage_devices.empty()) {
return new Electron::ConcreteMachine<false>(*acorn_target, rom_fetcher);
} else {
return new Electron::ConcreteMachine<true>(*acorn_target, rom_fetcher);
}
}
Machine::~Machine() {}

View File

@ -6,8 +6,8 @@
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#ifndef AcornADF_hpp
#define AcornADF_hpp
#ifndef MassStorage_AcornADF_hpp
#define MassStorage_AcornADF_hpp
#include "../MassStorageDevice.hpp"
#include "../../FileHolder.hpp"
@ -36,4 +36,4 @@ class AcornADF: public MassStorageDevice {
}
}
#endif /* AcornADF_hpp */
#endif /* MassStorage_AcornADF_hpp */

View File

@ -90,6 +90,13 @@ constexpr double DeskewDelay = ns(45.0);
/// any two devices.
constexpr double CableSkew = ns(10.0);
/*!
@returns The value of the data lines per @c state.
*/
constexpr uint8_t data_lines(BusState state) {
return uint8_t(state & 0xff);
}
#undef ns
#undef us

View File

@ -17,8 +17,8 @@ template <typename Executor> void Target<Executor>::scsi_bus_did_change(Bus *, B
/*
"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."
are false. It then asserts the signal within a selection
abort time."
*/
// Wait for deskew, at the very least.