From c2c81162a1da4ca3333219d8839a90888c24c3d4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 22 Aug 2022 16:48:51 -0400 Subject: [PATCH] Sketch out some of the easy stuff. --- Machines/Apple/AppleII/AppleII.cpp | 14 +++++++- Machines/Apple/AppleII/Card.hpp | 6 ++-- Machines/Apple/AppleII/SCSICard.cpp | 56 +++++++++++++++++++++++++++-- Machines/Apple/AppleII/SCSICard.hpp | 16 +++++++-- 4 files changed, 84 insertions(+), 8 deletions(-) diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index e6d986ea8..857c07503 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -24,6 +24,7 @@ #include "DiskIICard.hpp" #include "Joystick.hpp" #include "LanguageCardSwitches.hpp" +#include "SCSICard.hpp" #include "Video.hpp" #include "../../../Analyser/Static/AppleII/Target.hpp" @@ -460,10 +461,15 @@ template class ConcreteMachine: const bool has_disk_controller = target.disk_controller != Target::DiskController::None; const bool is_sixteen_sector = target.disk_controller == Target::DiskController::SixteenSector; if(has_disk_controller) { - // Apple recommended slot 6 for the (first) Disk II. request = request && DiskIICard::rom_request(is_sixteen_sector); } + // Add a SCSI card if requested. + const bool has_scsi_card = true; // TODO: obtain via the target. + if(has_scsi_card) { + request = request && SCSICard::rom_request(); + } + // Request, validate and install ROMs. auto roms = rom_fetcher(request); if(!request.validate(roms)) { @@ -471,9 +477,15 @@ template class ConcreteMachine: } if(has_disk_controller) { + // Apple recommended slot 6 for the (first) Disk II. install_card(6, new Apple::II::DiskIICard(roms, is_sixteen_sector)); } + if(has_scsi_card) { + // Install the SCSI card in slot 7, to one-up any connected Disk II. + install_card(7, new Apple::II::SCSICard(roms)); + } + rom_ = std::move(roms.find(system)->second); // The IIe and Enhanced IIe ROMs often distributed are oversized; trim if necessary. if(system == ROM::Name::AppleIIe || system == ROM::Name::AppleIIEnhancedE) { diff --git a/Machines/Apple/AppleII/Card.hpp b/Machines/Apple/AppleII/Card.hpp index 692de839e..3a3a784d7 100644 --- a/Machines/Apple/AppleII/Card.hpp +++ b/Machines/Apple/AppleII/Card.hpp @@ -42,9 +42,9 @@ class Card { public: virtual ~Card() {} enum Select: int { - None = 0, // No select line is active - IO = 1 << 0, // IO select is active - Device = 1 << 1, // Device select is active + None = 0, // No select line is active. + IO = 1 << 0, // IO select is active; i.e. access is in range $C0x0 to $C0xf. + Device = 1 << 1, // Device select is active; i.e. access is in range $Cx00 to $Cxff. }; /*! diff --git a/Machines/Apple/AppleII/SCSICard.cpp b/Machines/Apple/AppleII/SCSICard.cpp index b2cc40e79..42774dc02 100644 --- a/Machines/Apple/AppleII/SCSICard.cpp +++ b/Machines/Apple/AppleII/SCSICard.cpp @@ -8,8 +8,6 @@ #include "SCSICard.hpp" -#include "../../../Components/5380/ncr5380.hpp" - // Per the documentation around the GGLabs Apple II SCSI card clone: // // A 5380 is mapped to the first eight bytes of slot IO: @@ -50,3 +48,57 @@ // at $CC00-$CFFF. The boot code in the first 256 bytes of ROM // bank 0 is also mapped in the IOSEL space ($Cn00-$CnFF). // + +using namespace Apple::II; + +ROM::Request SCSICard::rom_request() { + return ROM::Request(ROM::Name::AppleIISCSICard); +} + +// TODO: accept and supply real clock rate. +SCSICard::SCSICard(ROM::Map &map) : scsi_bus_(1), ncr5380_(scsi_bus_, 1) { + // Grab a copy of the SCSI ROM. + const auto rom = map.find(ROM::Name::AppleIISCSICard); + if(rom == map.end()) { + throw ROMMachine::Error::MissingROMs; + } + memcpy(rom_.data(), rom->second.data(), rom_.size()); + + // Set up initial banking. + rom_pointer_ = rom_.data(); + ram_pointer_ = ram_.data(); +} + +void SCSICard::perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) { + // TODO. + switch(select) { + case Select::None: + break; + + case Select::Device: + if(is_read) { + *value = rom_[address & 255]; + } + break; + + case Select::IO: + address &= 0xf; + switch(address) { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + if(is_read) { + *value = ncr5380_.read(address); + } else { + ncr5380_.write(address, *value); + } + break; + + default: + printf("Unhandled: %04x %c %02x\n", address, is_read ? 'r' : 'w', *value); + break; + } + break; + } + + // TODO: is it extra-contractual to respond in 0xc800 to 0xd000? Clarify. +} diff --git a/Machines/Apple/AppleII/SCSICard.hpp b/Machines/Apple/AppleII/SCSICard.hpp index ca7de978f..2d45ebf02 100644 --- a/Machines/Apple/AppleII/SCSICard.hpp +++ b/Machines/Apple/AppleII/SCSICard.hpp @@ -12,6 +12,10 @@ #include "Card.hpp" #include "../../ROMMachine.hpp" +#include "../../../Components/5380/ncr5380.hpp" + +#include + namespace Apple { namespace II { @@ -21,10 +25,18 @@ class SCSICard: public Card { SCSICard(ROM::Map &); void perform_bus_operation(Select select, bool is_read, uint16_t address, uint8_t *value) final; - void run_for(Cycles cycles, int stretches) final; private: - // TODO. + uint8_t *ram_pointer_ = nullptr; + uint8_t *rom_pointer_ = nullptr; + + std::array ram_; + std::array rom_; + + SCSI::Bus scsi_bus_; + NCR::NCR5380::NCR5380 ncr5380_; + + // TODO: the rest of this. }; }