diff --git a/Analyser/Static/Oric/StaticAnalyser.cpp b/Analyser/Static/Oric/StaticAnalyser.cpp index a22e51ffe..3a39c4eb4 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,22 @@ 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); + target->rom = Target::ROM::BASIC10; } } } 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 }; 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 new file mode 100644 index 000000000..e8c3df0b7 --- /dev/null +++ b/Machines/Oric/BD500.cpp @@ -0,0 +1,146 @@ +// +// BD500.cpp +// Clock Signal +// +// Created by Thomas Harte on 14/01/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#include "BD500.hpp" + +using namespace Oric; + +BD500::BD500() : DiskController(P1793, 9000000) { + disable_basic_rom_ = true; + select_paged_item(); + set_is_double_density(true); +} + +void BD500::write(int address, uint8_t value) { + access(address); + + 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("Switch %04x???\n", address); + break; + } + + 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; if off then unload the head instantly. + is_loading_head_ |= head_load; + for(auto &drive : drives_) { + if(drive) drive->set_motor_on(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); +} + +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 new file mode 100644 index 000000000..f371dd506 --- /dev/null +++ b/Machines/Oric/BD500.hpp @@ -0,0 +1,43 @@ +// +// 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 { + +class BD500: public DiskController { + public: + BD500(); + + void write(int address, uint8_t value); + uint8_t read(int address); + + 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); +}; + +}; + +#endif /* BD500_hpp */ diff --git a/Machines/Oric/DiskController.hpp b/Machines/Oric/DiskController.hpp new file mode 100644 index 000000000..7ffa2614b --- /dev/null +++ b/Machines/Oric/DiskController.hpp @@ -0,0 +1,84 @@ +// +// 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 class PagedItem { + DiskROM, + BASIC, + RAM + }; + + struct Delegate: public WD1770::Delegate { + 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_paged_item(this); + } + inline PagedItem get_paged_item() { + return paged_item_; + } + + protected: + std::array, 4> drives_; + size_t selected_drive_ = 0; + void select_drive(size_t drive) { + if(drive != selected_drive_) { + selected_drive_ = drive; + set_drive(drives_[selected_drive_]); + } + } + 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_; + + 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); + } + } +}; + + +}; + + +#endif /* DiskController_h */ diff --git a/Machines/Oric/Jasmin.cpp b/Machines/Oric/Jasmin.cpp index 60220f685..502953364 100644 --- a/Machines/Oric/Jasmin.cpp +++ b/Machines/Oric/Jasmin.cpp @@ -12,17 +12,9 @@ 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); + select_paged_item(); } void Jasmin::write(int address, uint8_t value) { @@ -40,23 +32,20 @@ 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)); + enable_overlay_ram_ = value & 1; + select_paged_item(); } break; case 0x3fb: // If b0, disable BASIC ROM. - posit_paging_flags((paging_flags_ & OverlayRAMEnable) | ((value & 1) ? BASICDisable : 0)); + disable_basic_rom_ = value & 1; + select_paged_item(); 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: @@ -67,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 8b171a5a1..7b3eb2b35 100644 --- a/Machines/Oric/Jasmin.hpp +++ b/Machines/Oric/Jasmin.hpp @@ -11,48 +11,23 @@ #include "../../Components/1770/1770.hpp" #include "../../Activity/Observer.hpp" - -#include -#include +#include "DiskController.hpp" 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_; } + void set_activity_observer(Activity::Observer *observer); 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; + + Activity::Observer *observer_ = nullptr; }; }; diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 19d2c143d..02ba46e4e 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,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) { - paging_flags_ = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? MicrodiscDisable : 0); - if(delegate_) delegate_->microdisc_did_change_paging_flags(this); + enable_overlay_ram_ = control & 0x80; + disable_basic_rom_ = !(control & 0x02); + select_paged_item(); } } @@ -121,23 +112,10 @@ 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) { 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 b72e4cefc..ee80de1dc 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -11,16 +11,14 @@ #include "../../Components/1770/1770.hpp" #include "../../Activity/Observer.hpp" - -#include +#include "DiskController.hpp" 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(); @@ -29,42 +27,19 @@ 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); + Activity::Observer *observer_ = nullptr; }; } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index e53a1fe6b..53eee6691 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" @@ -223,8 +224,7 @@ template class Co public MOS::MOS6522::IRQDelegatePortHandler::Delegate, 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, @@ -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); @@ -266,6 +275,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 +305,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]); @@ -314,14 +330,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: + bd500_.set_delegate(this); break; case DiskInterface::Jasmin: - jasmin_did_change_paging_flags(&jasmin_); jasmin_.set_delegate(this); break; + case DiskInterface::Microdisc: + microdisc_.set_delegate(this); + break; } if(!target.loading_command.empty()) { @@ -353,7 +370,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 +378,7 @@ template class Co } } - void clear_all_keys() override final { + void clear_all_keys() final { keyboard_.clear_all_keys(); } @@ -380,7 +397,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()) { @@ -390,16 +407,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; } } @@ -434,6 +445,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); @@ -497,8 +512,11 @@ template class Co tape_player_.run_for(Cycles(1)); switch(disk_interface) { default: break; + case DiskInterface::BD500: + 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 @@ -511,12 +529,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); } @@ -534,74 +552,53 @@ 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 { - 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_ = microdisc_rom_.data(); - } - } - } - - // Jasmin::Delegate - void jasmin_did_change_paging_flags(Jasmin *jasmin) override final { - const int flags = jasmin->get_paging_flags(); - switch(flags) { - // BASIC enabled, overlay disabled. + // DiskController::Delegate + 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 Jasmin::OverlayRAMEnable: - case Jasmin::OverlayRAMEnable | Jasmin::BASICDisable: + case DiskController::PagedItem::RAM: ram_top_ = basic_invisible_ram_top_; break; - // BASIC disabled, overlay disabled. - case Jasmin::BASICDisable: - ram_top_ = 0xf7ff; - paged_rom_ = jasmin_rom_.data(); + case DiskController::PagedItem::DiskROM: + ram_top_ = uint16_t(0xffff - disk_rom_.size()); + paged_rom_ = disk_rom_.data(); break; } } @@ -649,6 +646,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; @@ -669,7 +672,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() { @@ -705,6 +708,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_; @@ -771,6 +777,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 */, 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 @@ 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; } 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 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; } diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index be90395ba..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_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,26 +146,33 @@ 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; + // 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_is_on_); - if(announce_motor_led_) { - observer_->set_led_status(drive_name_, motor_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 { - return motor_is_on_; + return motor_input_is_on_; } bool Drive::get_index_pulse() 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_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_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_is_on_); + observer->set_led_status(drive_name_, disk_is_rotating_); } } } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index 330cdd734..c568a399f 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,10 @@ 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; + 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_;