From 9799250f2cce12315b2da0011f969697adf143ce Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 21:54:37 -0500 Subject: [PATCH 01/17] Updates to mention the Jasmin's ROM and list the BD-DOS. --- ROMImages/Oric/readme.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ROMImages/Oric/readme.txt b/ROMImages/Oric/readme.txt index de4b46be1..a8a8453f5 100644 --- a/ROMImages/Oric/readme.txt +++ b/ROMImages/Oric/readme.txt @@ -5,6 +5,11 @@ Expected files: basic10.rom basic11.rom colour.rom -microdisc.rom -8dos.rom -pravetz.rom \ No newline at end of file +pravetz.rom + +Also potentially required: + +* microdisc.rom, for loading Microdisc software; +* 8dos.rom, for loading Pravetz 8-DOS software; +* jasmin.rom, for loading Jasmin disk interface software; and +* bd500.rom, for loading Byte Drive 500 software. \ No newline at end of file From 1cbcd5355fba1460faf7f5a6083cf56515e51e7b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 21:55:04 -0500 Subject: [PATCH 02/17] Adds a detector and enumerated Byte Drive 500 disk interface type. --- Analyser/Static/Oric/StaticAnalyser.cpp | 59 ++++++++++++++++--------- Analyser/Static/Oric/Target.hpp | 1 + 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/Analyser/Static/Oric/StaticAnalyser.cpp b/Analyser/Static/Oric/StaticAnalyser.cpp index a22e51ffe..cc5d07ee8 100644 --- a/Analyser/Static/Oric/StaticAnalyser.cpp +++ b/Analyser/Static/Oric/StaticAnalyser.cpp @@ -20,7 +20,9 @@ using namespace Analyser::Static::Oric; -static int Score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::set &rom_functions, const std::set &variable_locations) { +namespace { + +int score(const Analyser::Static::MOS6502::Disassembly &disassembly, const std::set &rom_functions, const std::set &variable_locations) { int score = 0; for(const auto address : disassembly.outward_calls) score += (rom_functions.find(address) != rom_functions.end()) ? 1 : -1; @@ -30,7 +32,7 @@ static int Score(const Analyser::Static::MOS6502::Disassembly &disassembly, cons return score; } -static int Basic10Score(const Analyser::Static::MOS6502::Disassembly &disassembly) { +int basic10_score(const Analyser::Static::MOS6502::Disassembly &disassembly) { const std::set rom_functions = { 0x0228, 0x022b, 0xc3ca, 0xc3f8, 0xc448, 0xc47c, 0xc4b5, 0xc4e3, 0xc4e0, 0xc524, 0xc56f, 0xc5a2, 0xc5f8, 0xc60a, 0xc6a5, 0xc6de, 0xc719, 0xc738, @@ -51,10 +53,10 @@ static int Basic10Score(const Analyser::Static::MOS6502::Disassembly &disassembl 0x0228, 0x0229, 0x022a, 0x022b, 0x022c, 0x022d, 0x0230 }; - return Score(disassembly, rom_functions, variable_locations); + return score(disassembly, rom_functions, variable_locations); } -static int Basic11Score(const Analyser::Static::MOS6502::Disassembly &disassembly) { +int basic11_score(const Analyser::Static::MOS6502::Disassembly &disassembly) { const std::set rom_functions = { 0x0238, 0x023b, 0x023e, 0x0241, 0x0244, 0x0247, 0xc3c6, 0xc3f4, 0xc444, 0xc47c, 0xc4a8, 0xc4d3, 0xc4e0, 0xc524, 0xc55f, 0xc592, 0xc5e8, 0xc5fa, 0xc692, 0xc6b3, 0xc6ee, 0xc70d, @@ -76,10 +78,10 @@ static int Basic11Score(const Analyser::Static::MOS6502::Disassembly &disassembl 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, 0x024c }; - return Score(disassembly, rom_functions, variable_locations); + return score(disassembly, rom_functions, variable_locations); } -static bool IsMicrodisc(Storage::Encodings::MFM::Parser &parser) { +bool is_microdisc(Storage::Encodings::MFM::Parser &parser) { /* The Microdisc boot sector is sector 2 of track 0 and contains a 23-byte signature. */ @@ -100,17 +102,22 @@ static bool IsMicrodisc(Storage::Encodings::MFM::Parser &parser) { return !std::memcmp(signature, first_sample.data(), sizeof(signature)); } -static bool IsJasmin(Storage::Encodings::MFM::Parser &parser) { +bool is_400_loader(Storage::Encodings::MFM::Parser &parser, uint16_t range_start, uint16_t range_end) { /* - The Jasmin boot sector is sector 1 of track 0 and is loaded at $400; - disassemble it to test it for validity. + Both the Jasmin and BD-DOS boot sectors are sector 1 of track 0 and are loaded at $400; + use disassembly to test for likely matches. */ + Storage::Encodings::MFM::Sector *sector = parser.get_sector(0, 0, 1); if(!sector) return false; if(sector->samples.empty()) return false; - const std::vector &first_sample = sector->samples[0]; - if(first_sample.size() != 256) return false; + // Take a copy of the first sampling, and keep only the final 256 bytes (assuming at least that many were found). + std::vector first_sample = sector->samples[0]; + if(first_sample.size() < 256) return false; + if(first_sample.size() > 256) { + first_sample.erase(first_sample.end() - 256, first_sample.end()); + } // Grab a disassembly. const auto disassembly = @@ -120,14 +127,24 @@ static bool IsJasmin(Storage::Encodings::MFM::Parser &parser) { int register_hits = 0; for(auto list : {disassembly.external_stores, disassembly.external_loads, disassembly.external_modifies}) { for(auto address : list) { - register_hits += (address >= 0x3f4 && address <= 0x3ff); + register_hits += (address >= range_start && address <= range_end); } } - // Arbitrary, sure, but as long as at least two accesses to Jasmin registers are found, accept this. + // Arbitrary, sure, but as long as at least two accesses to the requested register range are found, accept this. return register_hits >= 2; } +bool is_jasmin(Storage::Encodings::MFM::Parser &parser) { + return is_400_loader(parser, 0x3f4, 0x3ff); +} + +bool is_bd500(Storage::Encodings::MFM::Parser &parser) { + return is_400_loader(parser, 0x310, 0x323); +} + +} + Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &media, const std::string &file_name, TargetPlatform::IntType potential_platforms) { auto target = std::make_unique(); target->machine = Machine::Oric; @@ -146,9 +163,7 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med const Analyser::Static::MOS6502::Disassembly disassembly = Analyser::Static::MOS6502::Disassemble(file.data, Analyser::Static::Disassembler::OffsetMapper(file.starting_address), entry_points); - int basic10_score = Basic10Score(disassembly); - int basic11_score = Basic11Score(disassembly); - if(basic10_score > basic11_score) basic10_votes++; else basic11_votes++; + if(basic10_score(disassembly) > basic11_score(disassembly)) ++basic10_votes; else ++basic11_votes; } } @@ -158,17 +173,21 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med } if(!media.disks.empty()) { - // 8-DOS is recognised by a dedicated Disk II analyser, so check only for Microdisc and - // Jasmin formats here. + // 8-DOS is recognised by a dedicated Disk II analyser, so check only for Microdisc, + // Jasmin and BD-DOS formats here. for(auto &disk: media.disks) { Storage::Encodings::MFM::Parser parser(true, disk); - if(IsMicrodisc(parser)) { + + if(is_microdisc(parser)) { target->disk_interface = Target::DiskInterface::Microdisc; target->media.disks.push_back(disk); - } else if(IsJasmin(parser)) { + } else if(is_jasmin(parser)) { target->disk_interface = Target::DiskInterface::Jasmin; target->should_start_jasmin = true; target->media.disks.push_back(disk); + } else if(is_bd500(parser)) { + target->disk_interface = Target::DiskInterface::BD500; + target->media.disks.push_back(disk); } } } diff --git a/Analyser/Static/Oric/Target.hpp b/Analyser/Static/Oric/Target.hpp index 49c51dad5..24a5d1371 100644 --- a/Analyser/Static/Oric/Target.hpp +++ b/Analyser/Static/Oric/Target.hpp @@ -27,6 +27,7 @@ struct Target: public ::Analyser::Static::Target { Microdisc, Pravetz, Jasmin, + BD500, None }; From 5dd8c677f1c8979b2f916acbd9f72ab8c783eacf Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 22:23:00 -0500 Subject: [PATCH 03/17] Factors out from the Jasmin the stuff that I'm going to need to repeat for the BD-500. --- Machines/Oric/BD500.cpp | 12 +++ Machines/Oric/BD500.hpp | 23 ++++++ Machines/Oric/DiskController.hpp | 78 +++++++++++++++++++ Machines/Oric/Jasmin.cpp | 26 ++----- Machines/Oric/Jasmin.hpp | 29 +------ Machines/Oric/Microdisc.hpp | 1 + Machines/Oric/Oric.cpp | 62 ++++++++------- .../Clock Signal.xcodeproj/project.pbxproj | 8 ++ 8 files changed, 165 insertions(+), 74 deletions(-) create mode 100644 Machines/Oric/BD500.cpp create mode 100644 Machines/Oric/BD500.hpp create mode 100644 Machines/Oric/DiskController.hpp diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp new file mode 100644 index 000000000..ee4bc8f0c --- /dev/null +++ b/Machines/Oric/BD500.cpp @@ -0,0 +1,12 @@ +// +// Jasmin.cpp +// Clock Signal +// +// Created by Thomas Harte on 05/01/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#include "Jasmin.hpp" + +using namespace Oric; + diff --git a/Machines/Oric/BD500.hpp b/Machines/Oric/BD500.hpp new file mode 100644 index 000000000..a1f3cc0b4 --- /dev/null +++ b/Machines/Oric/BD500.hpp @@ -0,0 +1,23 @@ +// +// BD500.hpp +// Clock Signal +// +// Created by Thomas Harte on 14/01/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef BD500_hpp +#define BD500_hpp + +#include "../../Components/1770/1770.hpp" +#include "../../Activity/Observer.hpp" +#include "DiskController.hpp" + +#include +#include + +namespace Oric { + +}; + +#endif /* BD500_hpp */ diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp new file mode 100644 index 000000000..420a6f3ee --- /dev/null +++ b/Machines/Oric/DiskController.hpp @@ -0,0 +1,78 @@ +// +// DiskController.hpp +// Clock Signal +// +// Created by Thomas Harte on 14/01/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef DiskController_h +#define DiskController_h + +namespace Oric { + +class DiskController: public WD::WD1770 { + public: + DiskController(WD::WD1770::Personality personality, int clock_rate) : + WD::WD1770(personality), clock_rate_(clock_rate) {} + + void set_disk(std::shared_ptr disk, int d) { + const size_t drive = size_t(d); + if(!drives_[drive]) { + drives_[drive] = std::make_unique(clock_rate_, 300, 2); + if(drive == selected_drive_) set_drive(drives_[drive]); + } + drives_[drive]->set_disk(disk); + } + + enum PagingFlags { + /// Indicates that overlay RAM is enabled, implying no ROM is visible. + OverlayRAMEnable = (1 << 0), + + /// Indicates that the BASIC ROM is disabled, implying that the disk + /// controller's ROM fills its space. + BASICDisable = (1 << 1) + }; + + struct Delegate: public WD1770::Delegate { + virtual void disk_controller_did_change_paging_flags(DiskController *controller) = 0; + }; + inline void set_delegate(Delegate *delegate) { + delegate_ = delegate; + WD1770::set_delegate(delegate); + if(delegate) delegate->disk_controller_did_change_paging_flags(this); + } + inline int get_paging_flags() { + return paging_flags_; + } + + protected: + inline void set_paging_flags(int new_flags) { + if(paging_flags_ == new_flags) return; + paging_flags_ = new_flags; + if(delegate_) { + delegate_->disk_controller_did_change_paging_flags(this); + } + } + + std::array, 4> drives_; + size_t selected_drive_; + void select_drive(size_t drive) { + if(drive != selected_drive_) { + selected_drive_ = drive; + set_drive(drives_[selected_drive_]); + } + } + + private: + int paging_flags_ = 0; + Delegate *delegate_ = nullptr; + int clock_rate_; + +}; + + +}; + + +#endif /* DiskController_h */ diff --git a/Machines/Oric/Jasmin.cpp b/Machines/Oric/Jasmin.cpp index 60220f685..3aee0aab7 100644 --- a/Machines/Oric/Jasmin.cpp +++ b/Machines/Oric/Jasmin.cpp @@ -12,19 +12,10 @@ using namespace Oric; // NB: there's some controversy here on WD1770 versus WD1772, but between those two I think // the only difference is stepping rates, and it says 1770 on the schematic I'm looking at. -Jasmin::Jasmin() : WD1770(P1770) { +Jasmin::Jasmin() : DiskController(P1770, 8000000) { set_is_double_density(true); } -void Jasmin::set_disk(std::shared_ptr disk, int d) { - const size_t drive = size_t(d); - if(!drives_[drive]) { - drives_[drive] = std::make_unique(8000000, 300, 2); - if(drive == selected_drive_) set_drive(drives_[drive]); - } - drives_[drive]->set_disk(disk); -} - void Jasmin::write(int address, uint8_t value) { switch(address) { // Set side. @@ -40,23 +31,18 @@ void Jasmin::write(int address, uint8_t value) { case 0x3fa: { // If b0, enable overlay RAM. - posit_paging_flags((paging_flags_ & BASICDisable) | ((value & 1) ? OverlayRAMEnable : 0)); + set_paging_flags((get_paging_flags() & BASICDisable) | ((value & 1) ? OverlayRAMEnable : 0)); } break; case 0x3fb: // If b0, disable BASIC ROM. - posit_paging_flags((paging_flags_ & OverlayRAMEnable) | ((value & 1) ? BASICDisable : 0)); + set_paging_flags((get_paging_flags() & OverlayRAMEnable) | ((value & 1) ? BASICDisable : 0)); break; case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: { - const size_t new_selected_drive = size_t(address - 0x3fc); - - if(new_selected_drive != selected_drive_) { - if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(false); - selected_drive_ = new_selected_drive; - set_drive(drives_[selected_drive_]); - if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_); - } + if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(false); + select_drive(size_t(address - 0x3fc)); + if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_); } break; default: diff --git a/Machines/Oric/Jasmin.hpp b/Machines/Oric/Jasmin.hpp index 8b171a5a1..ecfc991e4 100644 --- a/Machines/Oric/Jasmin.hpp +++ b/Machines/Oric/Jasmin.hpp @@ -11,45 +11,20 @@ #include "../../Components/1770/1770.hpp" #include "../../Activity/Observer.hpp" +#include "DiskController.hpp" #include #include namespace Oric { -class Jasmin: public WD::WD1770 { +class Jasmin: public DiskController { public: Jasmin(); - void set_disk(std::shared_ptr disk, int drive); void write(int address, uint8_t value); - enum PagingFlags { - /// Indicates that overlay RAM is enabled, implying no ROM is visible. - OverlayRAMEnable = (1 << 0), - - /// Indicates that the BASIC ROM is disabled, implying that the JASMIN ROM - /// fills its space. - BASICDisable = (1 << 1) - }; - struct Delegate: public WD1770::Delegate { - virtual void jasmin_did_change_paging_flags(Jasmin *jasmin) = 0; - }; - inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); } - inline int get_paging_flags() { return paging_flags_; } - private: - std::array, 4> drives_; - size_t selected_drive_; - int paging_flags_ = 0; - Delegate *delegate_ = nullptr; - - void posit_paging_flags(int new_flags) { - if(new_flags != paging_flags_) { - paging_flags_ = new_flags; - if(delegate_) delegate_->jasmin_did_change_paging_flags(this); - } - } void set_motor_on(bool on) final; bool motor_on_ = false; diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index b72e4cefc..9a5414f74 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -13,6 +13,7 @@ #include "../../Activity/Observer.hpp" #include +#include "DiskController.hpp" namespace Oric { diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index e53a1fe6b..4df2dec69 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -224,7 +224,7 @@ template class Co public Utility::TypeRecipient, public Storage::Tape::BinaryTapePlayer::Delegate, public Microdisc::Delegate, - public Jasmin::Delegate, + public DiskController::Delegate, public ClockingHint::Observer, public Activity::Source, public Machine, @@ -266,6 +266,9 @@ template class Co size_t diskii_state_machine_index = 0; switch(disk_interface) { default: break; + case DiskInterface::BD500: + rom_names.emplace_back(machine_name, "the ORIC Byte Drive 500 ROM", "bd500.rom", 8*1024, 0x61952e34); + break; case DiskInterface::Jasmin: rom_names.emplace_back(machine_name, "the ORIC Jasmin ROM", "jasmin.rom", 2*1024, 0x37220e89); break; @@ -293,13 +296,17 @@ template class Co switch(disk_interface) { default: break; + case DiskInterface::BD500: + disk_rom_ = std::move(*roms[2]); + disk_rom_.resize(8192); + break; case DiskInterface::Jasmin: - jasmin_rom_ = std::move(*roms[2]); - jasmin_rom_.resize(2048); + disk_rom_ = std::move(*roms[2]); + disk_rom_.resize(2048); break; case DiskInterface::Microdisc: - microdisc_rom_ = std::move(*roms[2]); - microdisc_rom_.resize(8192); + disk_rom_ = std::move(*roms[2]); + disk_rom_.resize(8192); break; case DiskInterface::Pravetz: { pravetz_rom_ = std::move(*roms[2]); @@ -319,7 +326,6 @@ template class Co microdisc_.set_delegate(this); break; case DiskInterface::Jasmin: - jasmin_did_change_paging_flags(&jasmin_); jasmin_.set_delegate(this); break; } @@ -353,7 +359,7 @@ template class Co audio_queue_.flush(); } - void set_key_state(uint16_t key, bool is_pressed) override final { + void set_key_state(uint16_t key, bool is_pressed) final { if(key == KeyNMI) { m6502_.set_nmi_line(is_pressed); } else { @@ -361,7 +367,7 @@ template class Co } } - void clear_all_keys() override final { + void clear_all_keys() final { keyboard_.clear_all_keys(); } @@ -380,7 +386,7 @@ template class Co return true; } - bool insert_media(const Analyser::Static::Media &media) override final { + bool insert_media(const Analyser::Static::Media &media) final { bool inserted = false; if(!media.tapes.empty()) { @@ -534,40 +540,40 @@ template class Co } // to satisfy CRTMachine::Machine - void set_scan_target(Outputs::Display::ScanTarget *scan_target) override final { + void set_scan_target(Outputs::Display::ScanTarget *scan_target) final { video_output_.set_scan_target(scan_target); } - void set_display_type(Outputs::Display::DisplayType display_type) override { + void set_display_type(Outputs::Display::DisplayType display_type) final { video_output_.set_display_type(display_type); } - Outputs::Speaker::Speaker *get_speaker() override final { + Outputs::Speaker::Speaker *get_speaker() final { return &speaker_; } - void run_for(const Cycles cycles) override final { + void run_for(const Cycles cycles) final { m6502_.run_for(cycles); } // to satisfy MOS::MOS6522IRQDelegate::Delegate - void mos6522_did_change_interrupt_status(void *mos6522) override final { + void mos6522_did_change_interrupt_status(void *mos6522) final { set_interrupt_line(); } // to satisfy Storage::Tape::BinaryTapePlayer::Delegate - void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) override final { + void tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) final { // set CB1 via_.set_control_line_input(MOS::MOS6522::Port::B, MOS::MOS6522::Line::One, !tape_player->get_input()); } // for Utility::TypeRecipient::Delegate - void type_string(const std::string &string) override final { + void type_string(const std::string &string) final { string_serialiser_ = std::make_unique(string, true); } // for Microdisc::Delegate - void microdisc_did_change_paging_flags(class Microdisc *microdisc) override final { + void microdisc_did_change_paging_flags(class Microdisc *microdisc) final { const int flags = microdisc->get_paging_flags(); if(!(flags&Microdisc::PagingFlags::BASICDisable)) { ram_top_ = basic_visible_ram_top_; @@ -577,14 +583,15 @@ template class Co ram_top_ = basic_invisible_ram_top_; } else { ram_top_ = 0xdfff; - paged_rom_ = microdisc_rom_.data(); + paged_rom_ = disk_rom_.data(); } } } - // Jasmin::Delegate - void jasmin_did_change_paging_flags(Jasmin *jasmin) override final { - const int flags = jasmin->get_paging_flags(); + // DiskController::Delegate + void disk_controller_did_change_paging_flags(DiskController *controller) final { + const int flags = controller->get_paging_flags(); + switch(flags) { // BASIC enabled, overlay disabled. default: @@ -593,15 +600,15 @@ template class Co break; // Overlay RAM enabled, with or without BASIC. - case Jasmin::OverlayRAMEnable: - case Jasmin::OverlayRAMEnable | Jasmin::BASICDisable: + case DiskController::OverlayRAMEnable: + case DiskController::OverlayRAMEnable | DiskController::BASICDisable: ram_top_ = basic_invisible_ram_top_; break; // BASIC disabled, overlay disabled. - case Jasmin::BASICDisable: - ram_top_ = 0xf7ff; - paged_rom_ = jasmin_rom_.data(); + case DiskController::BASICDisable: + ram_top_ = uint16_t(0xffff - disk_rom_.size()); + paged_rom_ = disk_rom_.data(); break; } } @@ -669,7 +676,7 @@ template class Co CPU::MOS6502::Processor m6502_; // RAM and ROM - std::vector rom_, microdisc_rom_, jasmin_rom_; + std::vector rom_, disk_rom_; uint8_t ram_[65536]; Cycles cycles_since_video_update_; inline void update_video() { @@ -771,6 +778,7 @@ Machine *Machine::Oric(const Analyser::Static::Target *target_hint, const ROMMac case DiskInterface::Microdisc: return new ConcreteMachine(*oric_target, rom_fetcher); case DiskInterface::Pravetz: return new ConcreteMachine(*oric_target, rom_fetcher); case DiskInterface::Jasmin: return new ConcreteMachine(*oric_target, rom_fetcher); + case DiskInterface::BD500: return new ConcreteMachine(*oric_target, rom_fetcher); } } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 47dd05872..24b9bb098 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -369,6 +369,7 @@ 4B7BA03023C2B19C00B98D9E /* Jasmin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */; }; 4B7BA03123C2B19C00B98D9E /* Jasmin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */; }; 4B7BA03423C58B1F00B98D9E /* STX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03323C58B1E00B98D9E /* STX.cpp */; }; + 4B7BA03723CEB86000B98D9E /* BD500.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BA03523CEB86000B98D9E /* BD500.cpp */; }; 4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */; }; 4B7F188E2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; }; 4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; }; @@ -1181,6 +1182,9 @@ 4B7BA02F23C2B19B00B98D9E /* Jasmin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Jasmin.hpp; path = Oric/Jasmin.hpp; sourceTree = ""; }; 4B7BA03223C58B1E00B98D9E /* STX.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = STX.hpp; sourceTree = ""; }; 4B7BA03323C58B1E00B98D9E /* STX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = STX.cpp; sourceTree = ""; }; + 4B7BA03523CEB86000B98D9E /* BD500.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BD500.cpp; path = Oric/BD500.cpp; sourceTree = ""; }; + 4B7BA03623CEB86000B98D9E /* BD500.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BD500.hpp; path = Oric/BD500.hpp; sourceTree = ""; }; + 4B7BA03823CEB8D200B98D9E /* DiskController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DiskController.hpp; path = Oric/DiskController.hpp; sourceTree = ""; }; 4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = ""; }; 4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = ""; }; 4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = ""; }; @@ -3533,16 +3537,19 @@ 4BCF1FA51DADC3E10039D2E7 /* Oric */ = { isa = PBXGroup; children = ( + 4B7BA03523CEB86000B98D9E /* BD500.cpp */, 4B7BA02E23C2B19B00B98D9E /* Jasmin.cpp */, 4B54C0BD1F8D8F450050900F /* Keyboard.cpp */, 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */, 4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */, 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */, + 4B7BA03623CEB86000B98D9E /* BD500.hpp */, 4B7BA02F23C2B19B00B98D9E /* Jasmin.hpp */, 4B54C0BE1F8D8F450050900F /* Keyboard.hpp */, 4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */, 4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */, 4B2BFDB11DAEF5FF001A68B8 /* Video.hpp */, + 4B7BA03823CEB8D200B98D9E /* DiskController.hpp */, ); name = Oric; sourceTree = ""; @@ -4455,6 +4462,7 @@ 4B89452E201967B4007DE474 /* StaticAnalyser.cpp in Sources */, 4BD5D2682199148100DDF17D /* ScanTargetGLSLFragments.cpp in Sources */, 4BC890D3230F86020025A55A /* DirectAccessDevice.cpp in Sources */, + 4B7BA03723CEB86000B98D9E /* BD500.cpp in Sources */, 4B38F3481F2EC11D00D9235D /* AmstradCPC.cpp in Sources */, 4B8FE2221DA19FB20090D3CE /* MachinePanel.swift in Sources */, 4B4518A41F75FD1C00926311 /* OricMFMDSK.cpp in Sources */, From 6b84ae309556c73d1699b3fb28310d1c28eea2ce Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 22:53:27 -0500 Subject: [PATCH 04/17] Makes the Microdisc also a DiskController, and simplifies delegate interface. --- Machines/Oric/DiskController.hpp | 31 +++++++++++++---------------- Machines/Oric/Jasmin.cpp | 15 ++++++++++++-- Machines/Oric/Jasmin.hpp | 4 ++++ Machines/Oric/Microdisc.cpp | 23 ++++++--------------- Machines/Oric/Microdisc.hpp | 34 ++++++-------------------------- Machines/Oric/Oric.cpp | 27 +++++++++++-------------- 6 files changed, 54 insertions(+), 80 deletions(-) diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp index 420a6f3ee..f76db889f 100644 --- a/Machines/Oric/DiskController.hpp +++ b/Machines/Oric/DiskController.hpp @@ -25,33 +25,30 @@ class DiskController: public WD::WD1770 { drives_[drive]->set_disk(disk); } - enum PagingFlags { - /// Indicates that overlay RAM is enabled, implying no ROM is visible. - OverlayRAMEnable = (1 << 0), - - /// Indicates that the BASIC ROM is disabled, implying that the disk - /// controller's ROM fills its space. - BASICDisable = (1 << 1) + enum class PagedItem { + DiskROM, + BASIC, + RAM }; struct Delegate: public WD1770::Delegate { - virtual void disk_controller_did_change_paging_flags(DiskController *controller) = 0; + virtual void disk_controller_did_change_paged_item(DiskController *controller) = 0; }; inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); - if(delegate) delegate->disk_controller_did_change_paging_flags(this); + if(delegate) delegate->disk_controller_did_change_paged_item(this); } - inline int get_paging_flags() { - return paging_flags_; + inline PagedItem get_paged_item() { + return paged_item_; } protected: - inline void set_paging_flags(int new_flags) { - if(paging_flags_ == new_flags) return; - paging_flags_ = new_flags; + inline void set_paged_item(PagedItem item) { + if(paged_item_ == item) return; + paged_item_ = item; if(delegate_) { - delegate_->disk_controller_did_change_paging_flags(this); + delegate_->disk_controller_did_change_paged_item(this); } } @@ -63,10 +60,10 @@ class DiskController: public WD::WD1770 { set_drive(drives_[selected_drive_]); } } + Delegate *delegate_ = nullptr; private: - int paging_flags_ = 0; - Delegate *delegate_ = nullptr; + PagedItem paged_item_ = PagedItem::DiskROM; int clock_rate_; }; diff --git a/Machines/Oric/Jasmin.cpp b/Machines/Oric/Jasmin.cpp index 3aee0aab7..ec6017068 100644 --- a/Machines/Oric/Jasmin.cpp +++ b/Machines/Oric/Jasmin.cpp @@ -14,6 +14,7 @@ using namespace Oric; // the only difference is stepping rates, and it says 1770 on the schematic I'm looking at. Jasmin::Jasmin() : DiskController(P1770, 8000000) { set_is_double_density(true); + select_paged_item(); } void Jasmin::write(int address, uint8_t value) { @@ -31,12 +32,14 @@ void Jasmin::write(int address, uint8_t value) { case 0x3fa: { // If b0, enable overlay RAM. - set_paging_flags((get_paging_flags() & BASICDisable) | ((value & 1) ? OverlayRAMEnable : 0)); + enable_overlay_ram_ = value & 1; + select_paged_item(); } break; case 0x3fb: // If b0, disable BASIC ROM. - set_paging_flags((get_paging_flags() & OverlayRAMEnable) | ((value & 1) ? BASICDisable : 0)); + disable_basic_rom_ = value & 1; + select_paged_item(); break; case 0x3fc: case 0x3fd: case 0x3fe: case 0x3ff: { @@ -50,6 +53,14 @@ void Jasmin::write(int address, uint8_t value) { } } +void Jasmin::select_paged_item() { + PagedItem item = PagedItem::RAM; + if(!enable_overlay_ram_) { + item = disable_basic_rom_ ? PagedItem::DiskROM : PagedItem::BASIC; + } + set_paged_item(item); +} + void Jasmin::set_motor_on(bool on) { motor_on_ = on; if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_); diff --git a/Machines/Oric/Jasmin.hpp b/Machines/Oric/Jasmin.hpp index ecfc991e4..eaaa8a383 100644 --- a/Machines/Oric/Jasmin.hpp +++ b/Machines/Oric/Jasmin.hpp @@ -28,6 +28,10 @@ class Jasmin: public DiskController { void set_motor_on(bool on) final; bool motor_on_ = false; + + bool enable_overlay_ram_ = false; + bool disable_basic_rom_ = false; + void select_paged_item(); }; }; diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 19d2c143d..ef4245a55 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -18,20 +18,10 @@ namespace { const Cycles::IntType head_load_request_counter_target = 7653333; } -Microdisc::Microdisc() : WD1770(P1793) { +Microdisc::Microdisc() : DiskController(P1793, 8000000) { set_control_register(last_control_, 0xff); } -void Microdisc::set_disk(std::shared_ptr disk, int d) { - const size_t drive = size_t(d); - if(!drives_[drive]) { - drives_[drive] = std::make_unique(8000000, 300, 2); - if(drive == selected_drive_) set_drive(drives_[drive]); - drives_[drive]->set_activity_observer(observer_, drive_name(drive), false); - } - drives_[drive]->set_disk(disk); -} - void Microdisc::set_control_register(uint8_t control) { const uint8_t changes = last_control_ ^ control; last_control_ = control; @@ -73,8 +63,11 @@ void Microdisc::set_control_register(uint8_t control, uint8_t changes) { // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) if(changes & 0x82) { - paging_flags_ = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? MicrodiscDisable : 0); - if(delegate_) delegate_->microdisc_did_change_paging_flags(this); + PagedItem item = PagedItem::RAM; + if(!(control & 0x80)) { + item = (control & 0x02) ? PagedItem::BASIC : PagedItem::DiskROM; + } + set_paged_item(item); } } @@ -121,10 +114,6 @@ void Microdisc::run_for(const Cycles cycles) { WD::WD1770::run_for(cycles); } -bool Microdisc::get_drive_is_ready() { - return true; -} - void Microdisc::set_activity_observer(Activity::Observer *observer) { observer_ = observer; if(observer) { diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index 9a5414f74..bc4f5da33 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -17,11 +17,10 @@ namespace Oric { -class Microdisc: public WD::WD1770 { +class Microdisc: public DiskController { public: Microdisc(); - void set_disk(std::shared_ptr disk, int drive); void set_control_register(uint8_t control); uint8_t get_interrupt_request_register(); uint8_t get_data_request_register(); @@ -30,39 +29,18 @@ class Microdisc: public WD::WD1770 { void run_for(const Cycles cycles); - enum PagingFlags { - /// Indicates that the BASIC ROM should be disabled; if this is set then either - /// the Microdisc ROM or overlay RAM will be visible. If it is not set, BASIC - /// should be visible. - BASICDisable = (1 << 0), - - /// Indicates that the Microdisc ROM is disabled. If BASIC is disabled and the Microdisc - /// is also disabled, overlay RAM should be visible. - MicrodiscDisable = (1 << 1) - }; - - class Delegate: public WD1770::Delegate { - public: - virtual void microdisc_did_change_paging_flags(Microdisc *microdisc) = 0; - }; - inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); } - inline int get_paging_flags() { return paging_flags_; } - void set_activity_observer(Activity::Observer *observer); private: - void set_control_register(uint8_t control, uint8_t changes); - void set_head_load_request(bool head_load) override; - bool get_drive_is_ready(); + void set_head_load_request(bool head_load) final; - std::array, 4> drives_; - size_t selected_drive_; + void set_control_register(uint8_t control, uint8_t changes); + uint8_t last_control_ = 0; bool irq_enable_ = false; - int paging_flags_ = BASICDisable; + Cycles::IntType head_load_request_counter_ = -1; bool head_load_request_ = false; - Delegate *delegate_ = nullptr; - uint8_t last_control_ = 0; + Activity::Observer *observer_ = nullptr; std::string drive_name(size_t index); diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 4df2dec69..ada43bc4f 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -223,7 +223,6 @@ template class Co public MOS::MOS6522::IRQDelegatePortHandler::Delegate, public Utility::TypeRecipient, public Storage::Tape::BinaryTapePlayer::Delegate, - public Microdisc::Delegate, public DiskController::Delegate, public ClockingHint::Observer, public Activity::Source, @@ -321,13 +320,15 @@ template class Co switch(target.disk_interface) { default: break; - case DiskInterface::Microdisc: - microdisc_did_change_paging_flags(µdisc_); - microdisc_.set_delegate(this); + case DiskInterface::BD500: +// jasmin_.set_delegate(this); break; case DiskInterface::Jasmin: jasmin_.set_delegate(this); break; + case DiskInterface::Microdisc: + microdisc_.set_delegate(this); + break; } if(!target.loading_command.empty()) { @@ -573,7 +574,7 @@ template class Co } // for Microdisc::Delegate - void microdisc_did_change_paging_flags(class Microdisc *microdisc) final { +/* void microdisc_did_change_paging_flags(class Microdisc *microdisc) final { const int flags = microdisc->get_paging_flags(); if(!(flags&Microdisc::PagingFlags::BASICDisable)) { ram_top_ = basic_visible_ram_top_; @@ -586,27 +587,21 @@ template class Co paged_rom_ = disk_rom_.data(); } } - } + }*/ // DiskController::Delegate - void disk_controller_did_change_paging_flags(DiskController *controller) final { - const int flags = controller->get_paging_flags(); - - switch(flags) { - // BASIC enabled, overlay disabled. + void disk_controller_did_change_paged_item(DiskController *controller) final { + switch(controller->get_paged_item()) { default: ram_top_ = basic_visible_ram_top_; paged_rom_ = rom_.data(); break; - // Overlay RAM enabled, with or without BASIC. - case DiskController::OverlayRAMEnable: - case DiskController::OverlayRAMEnable | DiskController::BASICDisable: + case DiskController::PagedItem::RAM: ram_top_ = basic_invisible_ram_top_; break; - // BASIC disabled, overlay disabled. - case DiskController::BASICDisable: + case DiskController::PagedItem::DiskROM: ram_top_ = uint16_t(0xffff - disk_rom_.size()); paged_rom_ = disk_rom_.data(); break; From f258fc2971add789be636ceca2142f4a1e157109 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 23:15:27 -0500 Subject: [PATCH 05/17] Adds enough of a BD500 for the boot sector seemingly to load. --- Machines/Oric/BD500.cpp | 35 ++++++++++++++++++++++++++++++--- Machines/Oric/BD500.hpp | 11 +++++++++++ Machines/Oric/Oric.cpp | 43 +++++++++++++++-------------------------- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index ee4bc8f0c..efe52693c 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -1,12 +1,41 @@ // -// Jasmin.cpp +// BD500.cpp // Clock Signal // -// Created by Thomas Harte on 05/01/2020. +// Created by Thomas Harte on 14/01/2020. // Copyright © 2020 Thomas Harte. All rights reserved. // -#include "Jasmin.hpp" +#include "BD500.hpp" using namespace Oric; +BD500::BD500() : DiskController(P1793, 9000000) { + set_paged_item(PagedItem::DiskROM); + set_is_double_density(true); +} + +void BD500::write(int address, uint8_t value) { + switch(address) { + case 0x0320: case 0x0321: case 0x0322: case 0x0323: + WD::WD1770::write(address, value); + break; + } +} + +uint8_t BD500::read(int address) { + switch(address) { + case 0x0320: case 0x0321: case 0x0322: case 0x0323: + return WD::WD1770::read(address); + } + + return 0xff; +} + +void BD500::set_head_load_request(bool head_load) { + // Turn all motors on or off, and load the head instantly. + for(auto &drive : drives_) { + if(drive) drive->set_motor_on(head_load); + } + set_head_loaded(head_load); +} diff --git a/Machines/Oric/BD500.hpp b/Machines/Oric/BD500.hpp index a1f3cc0b4..6e664e212 100644 --- a/Machines/Oric/BD500.hpp +++ b/Machines/Oric/BD500.hpp @@ -18,6 +18,17 @@ namespace Oric { +class BD500: public DiskController { + public: + BD500(); + + void write(int address, uint8_t value); + uint8_t read(int address); + + private: + void set_head_load_request(bool head_load) final; +}; + }; #endif /* BD500_hpp */ diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index ada43bc4f..5016c76c7 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -8,6 +8,7 @@ #include "Oric.hpp" +#include "BD500.hpp" #include "Jasmin.hpp" #include "Keyboard.hpp" #include "Microdisc.hpp" @@ -321,7 +322,7 @@ template class Co switch(target.disk_interface) { default: break; case DiskInterface::BD500: -// jasmin_.set_delegate(this); + bd500_.set_delegate(this); break; case DiskInterface::Jasmin: jasmin_.set_delegate(this); @@ -397,16 +398,10 @@ template class Co if(!media.disks.empty()) { switch(disk_interface) { - case DiskInterface::Jasmin: - inserted |= insert_disks(media, jasmin_, 4); - break; - case DiskInterface::Microdisc: { - inserted |= insert_disks(media, microdisc_, 4); - } break; - case DiskInterface::Pravetz: { - inserted |= insert_disks(media, diskii_, 2); - } break; - + case DiskInterface::BD500: inserted |= insert_disks(media, bd500_, 4); break; + case DiskInterface::Jasmin: inserted |= insert_disks(media, jasmin_, 4); break; + case DiskInterface::Microdisc: inserted |= insert_disks(media, microdisc_, 4); break; + case DiskInterface::Pravetz: inserted |= insert_disks(media, diskii_, 2); break; default: break; } } @@ -441,6 +436,10 @@ template class Co } else { switch(disk_interface) { default: break; + case DiskInterface::BD500: + if(isReadOperation(operation)) *value = bd500_.read(address); + else bd500_.write(address, *value); + break; case DiskInterface::Jasmin: if(address >= 0x3f4) { if(isReadOperation(operation)) *value = jasmin_.read(address); @@ -504,6 +503,9 @@ template class Co tape_player_.run_for(Cycles(1)); switch(disk_interface) { default: break; + case DiskInterface::BD500: + bd500_.run_for(Cycles(8)); + break; case DiskInterface::Jasmin: jasmin_.run_for(Cycles(8)); @@ -573,22 +575,6 @@ template class Co string_serialiser_ = std::make_unique(string, true); } - // for Microdisc::Delegate -/* void microdisc_did_change_paging_flags(class Microdisc *microdisc) final { - const int flags = microdisc->get_paging_flags(); - if(!(flags&Microdisc::PagingFlags::BASICDisable)) { - ram_top_ = basic_visible_ram_top_; - paged_rom_ = rom_.data(); - } else { - if(flags&Microdisc::PagingFlags::MicrodiscDisable) { - ram_top_ = basic_invisible_ram_top_; - } else { - ram_top_ = 0xdfff; - paged_rom_ = disk_rom_.data(); - } - } - }*/ - // DiskController::Delegate void disk_controller_did_change_paged_item(DiskController *controller) final { switch(controller->get_paged_item()) { @@ -707,6 +693,9 @@ template class Co Jasmin jasmin_; int jasmin_reset_counter_ = 0; + // the BD-500, if in use. + BD500 bd500_; + // the Pravetz/Disk II, if in use. Apple::DiskII diskii_; Cycles cycles_since_diskii_update_; From 6b08239199c09b05459bc74a622152eaec00ea56 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 23:16:06 -0500 Subject: [PATCH 06/17] Adapts slightly; it would seem that BD-DOS disks really fill up space. --- Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp b/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp index ae043887a..3983f4376 100644 --- a/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp @@ -77,7 +77,7 @@ std::shared_ptr OricMFMDSK::get_track_at_position(Track::Address address) for(int byte = 0; byte < 6; byte++) { last_header[byte] = file_.get8(); encoder->add_byte(last_header[byte]); - track_offset++; + ++track_offset; if(track_offset == 6250) break; } break; @@ -85,8 +85,12 @@ std::shared_ptr OricMFMDSK::get_track_at_position(Track::Address address) case 0xfb: for(int byte = 0; byte < (128 << last_header[3]) + 2; byte++) { encoder->add_byte(file_.get8()); - track_offset++; - if(track_offset == 6250) break; + ++track_offset; + // Special exception: don't interrupt a sector body if it seems to + // be about to run over the end of the track. It seems like BD-500 + // disks break the usual 6250-byte rule, pushing out to just less + // than 6400 bytes total. + if(track_offset == 6400) break; } break; } From 62c3720c97b50a7fd588aefe3f8748d86e11aa28 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 23:24:11 -0500 Subject: [PATCH 07/17] Adds status register and shout-outs on other address access. --- Machines/Oric/BD500.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index efe52693c..7ed562f35 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -20,6 +20,10 @@ void BD500::write(int address, uint8_t value) { case 0x0320: case 0x0321: case 0x0322: case 0x0323: WD::WD1770::write(address, value); break; + + default: + printf("Write to %04x?\n", address); + break; } } @@ -27,6 +31,12 @@ uint8_t BD500::read(int address) { switch(address) { case 0x0320: case 0x0321: case 0x0322: case 0x0323: return WD::WD1770::read(address); + + case 0x312: return (get_data_request_line() ? 0x80 : 0x00) | (get_interrupt_request_line() ? 0x40 : 0x00); + + default: + printf("Read from %04x?\n", address); + break; } return 0xff; From 98f76621858be075f563129521c402fa9642dedb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 23:33:52 -0500 Subject: [PATCH 08/17] Force BASIC 1.0 for the BD-500. --- Analyser/Static/Oric/StaticAnalyser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Analyser/Static/Oric/StaticAnalyser.cpp b/Analyser/Static/Oric/StaticAnalyser.cpp index cc5d07ee8..3a39c4eb4 100644 --- a/Analyser/Static/Oric/StaticAnalyser.cpp +++ b/Analyser/Static/Oric/StaticAnalyser.cpp @@ -188,6 +188,7 @@ Analyser::Static::TargetList Analyser::Static::Oric::GetTargets(const Media &med } else if(is_bd500(parser)) { target->disk_interface = Target::DiskInterface::BD500; target->media.disks.push_back(disk); + target->rom = Target::ROM::BASIC10; } } } From f5c194386c53cd752678edefb846fa5eb19bdbfd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jan 2020 23:45:36 -0500 Subject: [PATCH 09/17] Ties head load to ready. BD-DOS no longer perpetually retries. --- Machines/Oric/BD500.cpp | 14 +++++++++++++- Machines/Oric/BD500.hpp | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index 7ed562f35..fc5d6d210 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -44,8 +44,20 @@ uint8_t BD500::read(int address) { void BD500::set_head_load_request(bool head_load) { // Turn all motors on or off, and load the head instantly. + is_loading_head_ |= head_load; for(auto &drive : drives_) { if(drive) drive->set_motor_on(head_load); } - set_head_loaded(head_load); + if(!head_load) set_head_loaded(false); +} + +void BD500::run_for(const Cycles cycles) { + // If a head load is in progress and the selected drive is now ready, + // declare head loaded. + if(is_loading_head_ && drives_[selected_drive_] && drives_[selected_drive_]->get_is_ready()) { + set_head_loaded(true); + is_loading_head_ = false; + } + + WD::WD1770::run_for(cycles); } diff --git a/Machines/Oric/BD500.hpp b/Machines/Oric/BD500.hpp index 6e664e212..52c501258 100644 --- a/Machines/Oric/BD500.hpp +++ b/Machines/Oric/BD500.hpp @@ -25,8 +25,11 @@ class BD500: public DiskController { void write(int address, uint8_t value); uint8_t read(int address); + void run_for(const Cycles cycles); + private: void set_head_load_request(bool head_load) final; + bool is_loading_head_ = false; }; }; From 91fae86e7320d55ed81299f059dc500a0e3f589a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:15:39 -0500 Subject: [PATCH 10/17] Factors out paging, implements a bit more of the BD500. That is, enough seemingly fully to work, if I force the drive to report ready. --- Machines/Oric/BD500.cpp | 90 ++++++++++++++++--- Machines/Oric/BD500.hpp | 2 + Machines/Oric/DiskController.hpp | 10 +++ Machines/Oric/Jasmin.cpp | 8 -- Machines/Oric/Jasmin.hpp | 5 -- Machines/Oric/Microdisc.cpp | 8 +- Machines/Oric/Oric.cpp | 8 +- .../xcschemes/Clock Signal.xcscheme | 2 +- 8 files changed, 99 insertions(+), 34 deletions(-) diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index fc5d6d210..2a719f14e 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -11,39 +11,107 @@ using namespace Oric; BD500::BD500() : DiskController(P1793, 9000000) { - set_paged_item(PagedItem::DiskROM); + disable_basic_rom_ = true; + select_paged_item(); set_is_double_density(true); } void BD500::write(int address, uint8_t value) { - switch(address) { - case 0x0320: case 0x0321: case 0x0322: case 0x0323: - WD::WD1770::write(address, value); - break; + access(address); - default: - printf("Write to %04x?\n", address); - break; + if(address >= 0x0320 && address <= 0x0323) { + if(address == 0x320) printf("Command %02x\n", value); + WD::WD1770::write(address, value); } } uint8_t BD500::read(int address) { + access(address); + switch(address) { + default: return 0xff; + case 0x0320: case 0x0321: case 0x0322: case 0x0323: return WD::WD1770::read(address); case 0x312: return (get_data_request_line() ? 0x80 : 0x00) | (get_interrupt_request_line() ? 0x40 : 0x00); + } +} + +void BD500::access(int address) { + // Determine whether to perform a command. + switch(address) { + case 0x0320: case 0x0321: case 0x0322: case 0x0323: case 0x0312: + return; + + case 0x310: enable_overlay_ram_ = true; break; + case 0x313: enable_overlay_ram_ = false; break; + case 0x317: disable_basic_rom_ = false; break; // Could be 0x311. default: - printf("Read from %04x?\n", address); + printf("Switch %04x???\n", address); break; } - return 0xff; + select_paged_item(); } +/* + The following was used when trying to find appropriate soft switch locations. It is preserved + as the values I have above are unlikely to be wholly correct and further research might be + desirable. + +void BD500::access(int address) { + // 0,1,4,5,10,11 -> 64kb Atmos + // 2,3,9 -> 56kb Atmos. + // Broken: 6, 7, 8 + + int order = 5; + int commands[4]; + std::vector available_commands = {0, 1, 2, 3}; + const int modulos[] = {6, 2, 1, 1}; + + for(int c = 0; c < 4; ++c) { + const int index = order / modulos[c]; + commands[c] = available_commands[size_t(index)]; + available_commands.erase(available_commands.begin() + index); + order %= modulos[c]; + } + + + // Determine whether to perform a command. + int index = -1; + switch(address) { + case 0x0320: case 0x0321: case 0x0322: case 0x0323: case 0x0312: + return; + + case 0x310: index = 0; break; + case 0x313: index = 1; break; + case 0x314: index = 2; break; + case 0x317: index = 3; break; + + default: + printf("Switch %04x???\n", address); + break; + } + + select_paged_item(); + + if(index >= 0) { + switch(commands[index]) { + case 0: enable_overlay_ram_ = true; break; // +RAM + case 1: disable_basic_rom_ = false; break; // -rom + case 2: disable_basic_rom_ = true; break; // +rom + case 3: enable_overlay_ram_ = false; break; // -RAM + + } + select_paged_item(); + } +} +*/ + void BD500::set_head_load_request(bool head_load) { - // Turn all motors on or off, and load the head instantly. + // Turn all motors on or off; if off then unload the head instantly. is_loading_head_ |= head_load; for(auto &drive : drives_) { if(drive) drive->set_motor_on(head_load); diff --git a/Machines/Oric/BD500.hpp b/Machines/Oric/BD500.hpp index 52c501258..ff0cdeea0 100644 --- a/Machines/Oric/BD500.hpp +++ b/Machines/Oric/BD500.hpp @@ -30,6 +30,8 @@ class BD500: public DiskController { private: void set_head_load_request(bool head_load) final; bool is_loading_head_ = false; + + void access(int address); }; }; diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp index f76db889f..06dd4cec2 100644 --- a/Machines/Oric/DiskController.hpp +++ b/Machines/Oric/DiskController.hpp @@ -62,6 +62,16 @@ class DiskController: public WD::WD1770 { } Delegate *delegate_ = nullptr; + bool enable_overlay_ram_ = false; + bool disable_basic_rom_ = false; + void select_paged_item() { + PagedItem item = PagedItem::RAM; + if(!enable_overlay_ram_) { + item = disable_basic_rom_ ? PagedItem::DiskROM : PagedItem::BASIC; + } + set_paged_item(item); + } + private: PagedItem paged_item_ = PagedItem::DiskROM; int clock_rate_; diff --git a/Machines/Oric/Jasmin.cpp b/Machines/Oric/Jasmin.cpp index ec6017068..3a3a5675d 100644 --- a/Machines/Oric/Jasmin.cpp +++ b/Machines/Oric/Jasmin.cpp @@ -53,14 +53,6 @@ void Jasmin::write(int address, uint8_t value) { } } -void Jasmin::select_paged_item() { - PagedItem item = PagedItem::RAM; - if(!enable_overlay_ram_) { - item = disable_basic_rom_ ? PagedItem::DiskROM : PagedItem::BASIC; - } - set_paged_item(item); -} - void Jasmin::set_motor_on(bool on) { motor_on_ = on; if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_); diff --git a/Machines/Oric/Jasmin.hpp b/Machines/Oric/Jasmin.hpp index eaaa8a383..5717c4ab4 100644 --- a/Machines/Oric/Jasmin.hpp +++ b/Machines/Oric/Jasmin.hpp @@ -25,13 +25,8 @@ class Jasmin: public DiskController { void write(int address, uint8_t value); private: - void set_motor_on(bool on) final; bool motor_on_ = false; - - bool enable_overlay_ram_ = false; - bool disable_basic_rom_ = false; - void select_paged_item(); }; }; diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index ef4245a55..7b538751c 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -63,11 +63,9 @@ void Microdisc::set_control_register(uint8_t control, uint8_t changes) { // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) if(changes & 0x82) { - PagedItem item = PagedItem::RAM; - if(!(control & 0x80)) { - item = (control & 0x02) ? PagedItem::BASIC : PagedItem::DiskROM; - } - set_paged_item(item); + enable_overlay_ram_ = control & 0x80; + disable_basic_rom_ = !(control & 0x02); + select_paged_item(); } } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 5016c76c7..2e6edd152 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -504,10 +504,10 @@ template class Co switch(disk_interface) { default: break; case DiskInterface::BD500: - bd500_.run_for(Cycles(8)); + bd500_.run_for(Cycles(9)); // i.e. effective clock rate of 9Mhz. break; case DiskInterface::Jasmin: - jasmin_.run_for(Cycles(8)); + jasmin_.run_for(Cycles(8));; // i.e. effective clock rate of 8Mhz. // Jasmin autostart hack: wait for a period, then trigger a reset, having forced // the Jasmin to page its ROM in first. I assume the latter being what the Jasmin's @@ -520,12 +520,12 @@ template class Co } break; case DiskInterface::Microdisc: - microdisc_.run_for(Cycles(8)); + microdisc_.run_for(Cycles(8));; // i.e. effective clock rate of 8Mhz. break; case DiskInterface::Pravetz: if(diskii_clocking_preference_ == ClockingHint::Preference::RealTime) { diskii_.set_data_input(*value); - diskii_.run_for(Cycles(2)); + diskii_.run_for(Cycles(2));; // i.e. effective clock rate of 2Mhz. } else { cycles_since_diskii_update_ += Cycles(2); } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 1465a4f62..47f9c7286 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -67,7 +67,7 @@ Date: Wed, 15 Jan 2020 23:16:25 -0500 Subject: [PATCH 11/17] Renames motor_is_on_ to motor_input_is_on_ to start to disambiguate the two things. --- Storage/Disk/Drive.cpp | 18 +++++++++--------- Storage/Disk/Drive.hpp | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index be90395ba..a281c3a06 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -68,7 +68,7 @@ bool Drive::has_disk() const { } ClockingHint::Preference Drive::preferred_clocking() { - return (!motor_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime; + return (!motor_input_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime; } bool Drive::get_is_track_zero() const { @@ -146,13 +146,13 @@ bool Drive::get_is_ready() const { } void Drive::set_motor_on(bool motor_is_on) { - if(motor_is_on_ != motor_is_on) { - motor_is_on_ = motor_is_on; + if(motor_input_is_on_ != motor_is_on) { + motor_input_is_on_ = motor_is_on; if(observer_) { - observer_->set_drive_motor_status(drive_name_, motor_is_on_); + observer_->set_drive_motor_status(drive_name_, motor_input_is_on_); if(announce_motor_led_) { - observer_->set_led_status(drive_name_, motor_is_on_); + observer_->set_led_status(drive_name_, motor_input_is_on_); } } @@ -165,7 +165,7 @@ void Drive::set_motor_on(bool motor_is_on) { } bool Drive::get_motor_on() const { - return motor_is_on_; + return motor_input_is_on_; } bool Drive::get_index_pulse() const { @@ -185,7 +185,7 @@ void Drive::run_for(const Cycles cycles) { // Assumed: the index pulse pulses even if the drive has stopped spinning. index_pulse_remaining_ = std::max(index_pulse_remaining_ - cycles, Cycles(0)); - if(motor_is_on_) { + if(motor_input_is_on_) { if(has_disk_) { Time zero(0); @@ -407,11 +407,11 @@ void Drive::set_activity_observer(Activity::Observer *observer, const std::strin drive_name_ = name; observer->register_drive(drive_name_); - observer->set_drive_motor_status(drive_name_, motor_is_on_); + observer->set_drive_motor_status(drive_name_, motor_input_is_on_); if(add_motor_led) { observer->register_led(drive_name_); - observer->set_led_status(drive_name_, motor_is_on_); + observer->set_led_status(drive_name_, motor_input_is_on_); } } } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 330cdd734..d2b3f8a81 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -75,7 +75,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { void set_motor_on(bool); /*! - @returns @c true if the motor is on; @c false otherwise. + @returns @c true if the motor on input is active; @c false otherwise. This does not necessarily indicate whether the drive is spinning, due to momentum. */ bool get_motor_on() const; @@ -213,7 +213,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { int available_heads_ = 0; // Motor control state. - bool motor_is_on_ = false; + bool motor_input_is_on_ = false; // Current state of the index pulse output. Cycles index_pulse_remaining_; From 99122efbbc81a3da886a962d3812e5b340a67d11 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:29:52 -0500 Subject: [PATCH 12/17] Adds a slight cool-down period on end-of-rotation. Along with the corresponding inactive transition of the ready signal. --- Storage/Disk/Drive.cpp | 69 +++++++++++++++++++++++++++++++----------- Storage/Disk/Drive.hpp | 3 ++ 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index a281c3a06..261ba711d 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -68,7 +68,7 @@ bool Drive::has_disk() const { } ClockingHint::Preference Drive::preferred_clocking() { - return (!motor_input_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime; + return (!has_disk_ || (time_until_motor_transition == Cycles(0) && !disk_is_rotating_)) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime; } bool Drive::get_is_track_zero() const { @@ -146,22 +146,29 @@ bool Drive::get_is_ready() const { } void Drive::set_motor_on(bool motor_is_on) { - if(motor_input_is_on_ != motor_is_on) { - motor_input_is_on_ = motor_is_on; + // Do nothing if the input hasn't changed. + if(motor_input_is_on_ == motor_is_on) return; + motor_input_is_on_ = motor_is_on; - if(observer_) { - observer_->set_drive_motor_status(drive_name_, motor_input_is_on_); - if(announce_motor_led_) { - observer_->set_led_status(drive_name_, motor_input_is_on_); - } - } - - if(!motor_is_on) { - ready_index_count_ = 0; - if(disk_) disk_->flush_tracks(); - } - update_clocking_observer(); + // If this now means that the input and the actual state are in harmony, + // cancel any planned change and stop. + if(disk_is_rotating_ == motor_is_on) { + time_until_motor_transition = Cycles(0); + return; } + + // If this is a transition to on, start immediately. + // TODO: spin-up? + // TODO: momentum. + if(motor_is_on) { + set_disk_is_rotating(true); + return; + } + + // This is a transition from on to off. Simulate momentum (ha!) + // by delaying the time until complete standstill. + if(time_until_motor_transition == Cycles(0)) + time_until_motor_transition = get_input_clock_rate(); } bool Drive::get_motor_on() const { @@ -185,7 +192,16 @@ void Drive::run_for(const Cycles cycles) { // Assumed: the index pulse pulses even if the drive has stopped spinning. index_pulse_remaining_ = std::max(index_pulse_remaining_ - cycles, Cycles(0)); - if(motor_input_is_on_) { + if(time_until_motor_transition > Cycles(0)) { + if(time_until_motor_transition > cycles) { + time_until_motor_transition -= cycles; + } else { + time_until_motor_transition = Cycles(0); + set_disk_is_rotating(!disk_is_rotating_); + } + } + + if(disk_is_rotating_) { if(has_disk_) { Time zero(0); @@ -400,6 +416,23 @@ bool Drive::is_writing() const { return !is_reading_; } +void Drive::set_disk_is_rotating(bool is_rotating) { + disk_is_rotating_ = is_rotating; + + if(observer_) { + observer_->set_drive_motor_status(drive_name_, motor_input_is_on_); + if(announce_motor_led_) { + observer_->set_led_status(drive_name_, motor_input_is_on_); + } + } + + if(!is_rotating) { + ready_index_count_ = 0; + if(disk_) disk_->flush_tracks(); + } + update_clocking_observer(); +} + void Drive::set_activity_observer(Activity::Observer *observer, const std::string &name, bool add_motor_led) { observer_ = observer; announce_motor_led_ = add_motor_led; @@ -407,11 +440,11 @@ void Drive::set_activity_observer(Activity::Observer *observer, const std::strin drive_name_ = name; observer->register_drive(drive_name_); - observer->set_drive_motor_status(drive_name_, motor_input_is_on_); + observer->set_drive_motor_status(drive_name_, disk_is_rotating_); if(add_motor_led) { observer->register_led(drive_name_); - observer->set_led_status(drive_name_, motor_input_is_on_); + observer->set_led_status(drive_name_, disk_is_rotating_); } } } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index d2b3f8a81..c568a399f 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -214,6 +214,9 @@ class Drive: public ClockingHint::Source, public TimedEventLoop { // Motor control state. bool motor_input_is_on_ = false; + bool disk_is_rotating_ = false; + Cycles time_until_motor_transition; + void set_disk_is_rotating(bool); // Current state of the index pulse output. Cycles index_pulse_remaining_; From aac3d27c103560c1a8476a794daf3903ddb4317c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:39:15 -0500 Subject: [PATCH 13/17] Adds activity indicators for the BD-500 and Jasmin. Also slightly cleans up DiskController a little further. --- Components/1770/1770.cpp | 4 ++++ Components/1770/1770.hpp | 3 +++ Machines/Oric/BD500.cpp | 15 +++++++++++++++ Machines/Oric/BD500.hpp | 4 ++++ Machines/Oric/DiskController.hpp | 15 +++++++-------- Machines/Oric/Jasmin.cpp | 11 +++++++++++ Machines/Oric/Jasmin.hpp | 7 ++++--- Machines/Oric/Microdisc.cpp | 9 --------- Machines/Oric/Microdisc.hpp | 4 ---- Machines/Oric/Oric.cpp | 6 ++++++ 10 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index aa76f635b..00aa5711f 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -824,6 +824,10 @@ void WD1770::set_head_loaded(bool head_loaded) { if(head_loaded) posit_event(int(Event1770::HeadLoad)); } +bool WD1770::get_head_loaded() { + return head_is_loaded_; +} + ClockingHint::Preference WD1770::preferred_clocking() { if(status_.busy) return ClockingHint::Preference::RealTime; return Storage::Disk::MFMController::preferred_clocking(); diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index 5b8ebd092..59bfac712 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -80,6 +80,9 @@ class WD1770: public Storage::Disk::MFMController { virtual void set_motor_on(bool motor_on); void set_head_loaded(bool head_loaded); + /// @returns The last value posted to @c set_head_loaded. + bool get_head_loaded(); + private: Personality personality_; inline bool has_motor_on_line() { return (personality_ != P1793 ) && (personality_ != P1773); } diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index 2a719f14e..777aa4d7a 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -129,3 +129,18 @@ void BD500::run_for(const Cycles cycles) { WD::WD1770::run_for(cycles); } + +void BD500::set_activity_observer(Activity::Observer *observer) { + observer_ = observer; + if(observer) { + observer->register_led("BD-500"); + observer_->set_led_status("BD-500", get_head_loaded()); + } +} + +void BD500::set_head_loaded(bool loaded) { + WD::WD1770::set_head_loaded(loaded); + if(observer_) { + observer_->set_led_status("BD-500", loaded); + } +} diff --git a/Machines/Oric/BD500.hpp b/Machines/Oric/BD500.hpp index ff0cdeea0..f371dd506 100644 --- a/Machines/Oric/BD500.hpp +++ b/Machines/Oric/BD500.hpp @@ -27,11 +27,15 @@ class BD500: public DiskController { void run_for(const Cycles cycles); + void set_activity_observer(Activity::Observer *observer); + private: void set_head_load_request(bool head_load) final; bool is_loading_head_ = false; + Activity::Observer *observer_ = nullptr; void access(int address); + void set_head_loaded(bool loaded); }; }; diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp index 06dd4cec2..6e2b4b0a3 100644 --- a/Machines/Oric/DiskController.hpp +++ b/Machines/Oric/DiskController.hpp @@ -44,14 +44,6 @@ class DiskController: public WD::WD1770 { } protected: - inline void set_paged_item(PagedItem item) { - if(paged_item_ == item) return; - paged_item_ = item; - if(delegate_) { - delegate_->disk_controller_did_change_paged_item(this); - } - } - std::array, 4> drives_; size_t selected_drive_; void select_drive(size_t drive) { @@ -76,6 +68,13 @@ class DiskController: public WD::WD1770 { PagedItem paged_item_ = PagedItem::DiskROM; int clock_rate_; + inline void set_paged_item(PagedItem item) { + if(paged_item_ == item) return; + paged_item_ = item; + if(delegate_) { + delegate_->disk_controller_did_change_paged_item(this); + } + } }; diff --git a/Machines/Oric/Jasmin.cpp b/Machines/Oric/Jasmin.cpp index 3a3a5675d..502953364 100644 --- a/Machines/Oric/Jasmin.cpp +++ b/Machines/Oric/Jasmin.cpp @@ -56,4 +56,15 @@ void Jasmin::write(int address, uint8_t value) { void Jasmin::set_motor_on(bool on) { motor_on_ = on; if(drives_[selected_drive_]) drives_[selected_drive_]->set_motor_on(motor_on_); + if(observer_) { + observer_->set_led_status("Microdisc", on); + } +} + +void Jasmin::set_activity_observer(Activity::Observer *observer) { + observer_ = observer; + if(observer) { + observer->register_led("Jasmin"); + observer_->set_led_status("Jasmin", motor_on_); + } } diff --git a/Machines/Oric/Jasmin.hpp b/Machines/Oric/Jasmin.hpp index 5717c4ab4..7b3eb2b35 100644 --- a/Machines/Oric/Jasmin.hpp +++ b/Machines/Oric/Jasmin.hpp @@ -13,9 +13,6 @@ #include "../../Activity/Observer.hpp" #include "DiskController.hpp" -#include -#include - namespace Oric { class Jasmin: public DiskController { @@ -24,9 +21,13 @@ class Jasmin: public DiskController { void write(int address, uint8_t value); + void set_activity_observer(Activity::Observer *observer); + private: void set_motor_on(bool on) final; bool motor_on_ = false; + + Activity::Observer *observer_ = nullptr; }; }; diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 7b538751c..02ba46e4e 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -118,13 +118,4 @@ void Microdisc::set_activity_observer(Activity::Observer *observer) { observer->register_led("Microdisc"); observer_->set_led_status("Microdisc", head_load_request_); } - size_t c = 0; - for(auto &drive : drives_) { - if(drive) drive->set_activity_observer(observer, drive_name(c), false); - ++c; - } -} - -std::string Microdisc::drive_name(size_t index) { - return "Drive " + std::to_string(index); } diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index bc4f5da33..ee80de1dc 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -11,8 +11,6 @@ #include "../../Components/1770/1770.hpp" #include "../../Activity/Observer.hpp" - -#include #include "DiskController.hpp" namespace Oric { @@ -42,8 +40,6 @@ class Microdisc: public DiskController { bool head_load_request_ = false; Activity::Observer *observer_ = nullptr; - - std::string drive_name(size_t index); }; } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 2e6edd152..ba04c4a3f 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -637,6 +637,12 @@ template class Co void set_activity_observer(Activity::Observer *observer) override { switch(disk_interface) { default: break; + case DiskInterface::BD500: + bd500_.set_activity_observer(observer); + break; + case DiskInterface::Jasmin: + jasmin_.set_activity_observer(observer); + break; case DiskInterface::Microdisc: microdisc_.set_activity_observer(observer); break; From 93cecf0882d13b19c73f438ee49d111c237dfdf7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:47:45 -0500 Subject: [PATCH 14/17] Ensures no possible initial NTSC, removes printfs. --- Machines/Oric/BD500.cpp | 4 ++-- Machines/Oric/Oric.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Machines/Oric/BD500.cpp b/Machines/Oric/BD500.cpp index 777aa4d7a..e8c3df0b7 100644 --- a/Machines/Oric/BD500.cpp +++ b/Machines/Oric/BD500.cpp @@ -20,7 +20,7 @@ void BD500::write(int address, uint8_t value) { access(address); if(address >= 0x0320 && address <= 0x0323) { - if(address == 0x320) printf("Command %02x\n", value); +// if(address == 0x320) printf("Command %02x\n", value); WD::WD1770::write(address, value); } } @@ -49,7 +49,7 @@ void BD500::access(int address) { case 0x317: disable_basic_rom_ = false; break; // Could be 0x311. default: - printf("Switch %04x???\n", address); +// printf("Switch %04x???\n", address); break; } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index ba04c4a3f..7f6323d2c 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -244,7 +244,16 @@ template class Co speaker_.set_input_rate(1000000.0f); via_port_handler_.set_interrupt_delegate(this); tape_player_.set_delegate(this); + + // Slight hack here: I'm unclear what RAM should look like at startup. + // Actually, I think completely random might be right since the Microdisc + // sort of assumes it, but also the BD-500 never explicitly sets PAL mode + // so I can't have any switch-to-NTSC bytes in the display area. Hence: + // disallow all atributes. Memory::Fuzz(ram_, sizeof(ram_)); + for(size_t c = 0; c < sizeof(ram_); ++c) { + ram_[c] &= ~0x40; + } if constexpr (disk_interface == DiskInterface::Pravetz) { diskii_.set_clocking_hint_observer(this); From c606931c93a2114bba7f329d948595bc1adb14c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:56:44 -0500 Subject: [PATCH 15/17] Ensures a safe default-selected drive. --- Machines/Oric/DiskController.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp index 6e2b4b0a3..7ffa2614b 100644 --- a/Machines/Oric/DiskController.hpp +++ b/Machines/Oric/DiskController.hpp @@ -45,7 +45,7 @@ class DiskController: public WD::WD1770 { protected: std::array, 4> drives_; - size_t selected_drive_; + size_t selected_drive_ = 0; void select_drive(size_t drive) { if(drive != selected_drive_) { selected_drive_ = drive; From 6a185a574aa8396ab8f41d8c88be60bf94cd66f6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jan 2020 23:56:56 -0500 Subject: [PATCH 16/17] Adds the BD-500 to the Mac GUI. --- .../Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h | 3 ++- .../Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm | 1 + .../Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib | 3 ++- OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h index 0903d3d79..e15df8de6 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.h @@ -50,7 +50,8 @@ typedef NS_ENUM(NSInteger, CSMachineOricDiskInterface) { CSMachineOricDiskInterfaceNone, CSMachineOricDiskInterfaceMicrodisc, CSMachineOricDiskInterfacePravetz, - CSMachineOricDiskInterfaceJasmin + CSMachineOricDiskInterfaceJasmin, + CSMachineOricDiskInterfaceBD500 }; typedef NS_ENUM(NSInteger, CSMachineVic20Region) { diff --git a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm index 05573be49..160ae61fd 100644 --- a/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm +++ b/OSBindings/Mac/Clock Signal/Machine/StaticAnalyser/CSStaticAnalyser.mm @@ -103,6 +103,7 @@ case CSMachineOricDiskInterfaceMicrodisc: target->disk_interface = Target::DiskInterface::Microdisc; break; case CSMachineOricDiskInterfacePravetz: target->disk_interface = Target::DiskInterface::Pravetz; break; case CSMachineOricDiskInterfaceJasmin: target->disk_interface = Target::DiskInterface::Jasmin; break; + case CSMachineOricDiskInterfaceBD500: target->disk_interface = Target::DiskInterface::BD500; break; } _targets.push_back(std::move(target)); } diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib index 186f3f21d..17a8a49e4 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib +++ b/OSBindings/Mac/Clock Signal/MachinePicker/Base.lproj/MachinePicker.xib @@ -331,7 +331,7 @@ Gw - + @@ -341,6 +341,7 @@ Gw + diff --git a/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift b/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift index f63ddc5c4..30977db28 100644 --- a/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift +++ b/OSBindings/Mac/Clock Signal/MachinePicker/MachinePicker.swift @@ -196,6 +196,7 @@ class MachinePicker: NSObject { case 1: diskInterface = .microdisc case 2: diskInterface = .pravetz case 3: diskInterface = .jasmin + case 4: diskInterface = .BD500 default: break; } From 1972ca00a4a16d472a65dbb0c5a6e8cc2af0559d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 16 Jan 2020 00:01:16 -0500 Subject: [PATCH 17/17] Fixes quick-NTSC-avoidance fix. I suspect this is very temporary, but here it is. --- Machines/Oric/Oric.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 7f6323d2c..53eee6691 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -252,7 +252,7 @@ template class Co // disallow all atributes. Memory::Fuzz(ram_, sizeof(ram_)); for(size_t c = 0; c < sizeof(ram_); ++c) { - ram_[c] &= ~0x40; + ram_[c] |= 0x40; } if constexpr (disk_interface == DiskInterface::Pravetz) {