From ea33a28695771c6f9bc8aeb83ee83e4e51410643 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 21 Nov 2016 20:59:25 +0800 Subject: [PATCH 01/40] Any Oric-format disks that are inserted now make it all the way to the Oric, along with a request to emulate the Microdisc. It has received a copy of the ROM. The ball is entirely in its court now. --- Machines/Oric/Oric.cpp | 7 ++++++- Machines/Oric/Oric.hpp | 4 ++-- OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm | 8 +++++--- StaticAnalyser/Oric/StaticAnalyser.cpp | 7 +++++++ StaticAnalyser/StaticAnalyser.hpp | 1 + 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index ee93adf30..68c0da7bd 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -60,7 +60,12 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) void Machine::set_rom(ROM rom, const std::vector &data) { - if(rom == BASIC11) _basic11 = std::move(data); else _basic10 = std::move(data); + switch(rom) + { + case BASIC11: _basic11 = std::move(data); break; + case BASIC10: _basic10 = std::move(data); break; + case Microdisc: _microdisc = std::move(data); break; + } } unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index f469d7fba..559e4914b 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -52,7 +52,7 @@ enum Key: uint16_t { }; enum ROM { - BASIC10, BASIC11 + BASIC10, BASIC11, Microdisc }; class Machine: @@ -97,7 +97,7 @@ class Machine: private: // RAM and ROM - std::vector _basic11, _basic10; + std::vector _basic11, _basic10, _microdisc; uint8_t _ram[65536], _rom[16384]; int _cycles_since_video_update; inline void update_video(); diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm index 5fb0d188a..6a565abb4 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSOric.mm @@ -26,10 +26,12 @@ if(self) { NSData *basic10 = [self rom:@"basic10"]; - NSData *basic11 = [self rom:@"basic11"]; // test108j + NSData *basic11 = [self rom:@"basic11"]; + NSData *microdisc = [self rom:@"microdisc"]; - if(basic10) _oric.set_rom(Oric::BASIC10, basic10.stdVector8); - if(basic11) _oric.set_rom(Oric::BASIC11, basic11.stdVector8); + if(basic10) _oric.set_rom(Oric::BASIC10, basic10.stdVector8); + if(basic11) _oric.set_rom(Oric::BASIC11, basic11.stdVector8); + if(microdisc) _oric.set_rom(Oric::Microdisc, microdisc.stdVector8); } return self; } diff --git a/StaticAnalyser/Oric/StaticAnalyser.cpp b/StaticAnalyser/Oric/StaticAnalyser.cpp index e21b16052..c26de6550 100644 --- a/StaticAnalyser/Oric/StaticAnalyser.cpp +++ b/StaticAnalyser/Oric/StaticAnalyser.cpp @@ -112,6 +112,13 @@ void StaticAnalyser::Oric::AddTargets( } } + // trust that any disk supplied can be handled by the Microdisc. TODO: check. + if(!disks.empty()) + { + target.oric.has_microdisc = true; + target.disks = disks; + } + // TODO: really this should add two targets if not all votes agree target.oric.use_atmos_rom = basic11_votes >= basic10_votes; diff --git a/StaticAnalyser/StaticAnalyser.hpp b/StaticAnalyser/StaticAnalyser.hpp index 59e4bd550..6a2d2e0e3 100644 --- a/StaticAnalyser/StaticAnalyser.hpp +++ b/StaticAnalyser/StaticAnalyser.hpp @@ -52,6 +52,7 @@ struct Target { struct { bool use_atmos_rom; + bool has_microdisc; } oric; }; From 09f965e6a9ffc512767ac1e433a20b0098ea12cc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 08:11:57 +0800 Subject: [PATCH 02/40] Fixed potential bug whereby inserting a disk into a drive that hadn't been lazily allocated yet but had already been selected wouldn't take effect. --- Machines/Electron/Plus3.cpp | 18 +++++++++++------- Machines/Electron/Plus3.hpp | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Machines/Electron/Plus3.cpp b/Machines/Electron/Plus3.cpp index 809846dcb..4c674e797 100644 --- a/Machines/Electron/Plus3.cpp +++ b/Machines/Electron/Plus3.cpp @@ -12,8 +12,12 @@ using namespace Electron; void Plus3::set_disk(std::shared_ptr disk, int drive) { - if(!_drives[drive]) _drives[drive].reset(new Storage::Disk::Drive); - _drives[drive]->set_disk(disk); + if(!drives_[drive]) + { + drives_[drive].reset(new Storage::Disk::Drive); + if(drive == selected_drive_) set_drive(drives_[drive]); + } + drives_[drive]->set_disk(disk); } void Plus3::set_control_register(uint8_t control) @@ -25,11 +29,11 @@ void Plus3::set_control_register(uint8_t control) // bit 3 => single density select switch(control&3) { - case 0: set_drive(nullptr); break; - default: set_drive(_drives[0]); break; - case 2: set_drive(_drives[1]); break; + case 0: selected_drive_ = -1; set_drive(nullptr); break; + default: selected_drive_ = 0; set_drive(drives_[0]); break; + case 2: selected_drive_ = 1; set_drive(drives_[1]); break; } - if(_drives[0]) _drives[0]->set_head((control & 0x04) ? 1 : 0); - if(_drives[1]) _drives[1]->set_head((control & 0x04) ? 1 : 0); + if(drives_[0]) drives_[0]->set_head((control & 0x04) ? 1 : 0); + if(drives_[1]) drives_[1]->set_head((control & 0x04) ? 1 : 0); set_is_double_density(!(control & 0x08)); } diff --git a/Machines/Electron/Plus3.hpp b/Machines/Electron/Plus3.hpp index e7613367b..d0e36a15c 100644 --- a/Machines/Electron/Plus3.hpp +++ b/Machines/Electron/Plus3.hpp @@ -19,7 +19,8 @@ class Plus3 : public WD::WD1770 { void set_control_register(uint8_t control); private: - std::shared_ptr _drives[2]; + std::shared_ptr drives_[2]; + int selected_drive_; }; } From 59e2a091079c738ea8c0d508c5e513ec7ca5bfcc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 08:12:24 +0800 Subject: [PATCH 03/40] Added assumption that Microdisc => BASIC 1.1. --- StaticAnalyser/Oric/StaticAnalyser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/StaticAnalyser/Oric/StaticAnalyser.cpp b/StaticAnalyser/Oric/StaticAnalyser.cpp index c26de6550..a4483efb0 100644 --- a/StaticAnalyser/Oric/StaticAnalyser.cpp +++ b/StaticAnalyser/Oric/StaticAnalyser.cpp @@ -121,6 +121,7 @@ void StaticAnalyser::Oric::AddTargets( // TODO: really this should add two targets if not all votes agree target.oric.use_atmos_rom = basic11_votes >= basic10_votes; + if(target.oric.has_microdisc) target.oric.use_atmos_rom = true; if(target.tapes.size() || target.disks.size() || target.cartridges.size()) destination.push_back(target); From 363db695e85d38fb9871f1f43e068b6899263358 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 08:12:53 +0800 Subject: [PATCH 04/40] Started implementation of the Microdisc selection logic. --- Machines/Oric/Microdisc.cpp | 62 +++++++++++++++++++ Machines/Oric/Microdisc.hpp | 35 +++++++++++ .../Clock Signal.xcodeproj/project.pbxproj | 6 ++ 3 files changed, 103 insertions(+) create mode 100644 Machines/Oric/Microdisc.cpp create mode 100644 Machines/Oric/Microdisc.hpp diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp new file mode 100644 index 000000000..00454cd19 --- /dev/null +++ b/Machines/Oric/Microdisc.cpp @@ -0,0 +1,62 @@ +// +// Microdisc.cpp +// Clock Signal +// +// Created by Thomas Harte on 22/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Microdisc.hpp" + +using namespace Oric; + +Microdisc::Microdisc() : irq_enable_(false) +{} + +void Microdisc::set_disk(std::shared_ptr disk, int drive) +{ + if(!drives_[drive]) + { + drives_[drive].reset(new Storage::Disk::Drive); + if(drive == selected_drive_) set_drive(drives_[drive]); + } + drives_[drive]->set_disk(disk); +} + +void Microdisc::set_control_register(uint8_t control) +{ + // b7: EPROM select (0 = select) + // b2: data separator clock rate select (1 = double) + // b1: ROM disable (0 = disable) + + // b65: drive select + selected_drive_ = (control >> 5)&3; + set_drive(drives_[selected_drive_]); + + // b4: side select + for(int c = 0; c < 4; c++) + { + if(drives_[c]) drives_[c]->set_head((control & 0x10) ? 1 : 0); + } + + // b3: double density select (0 = double) + set_is_double_density(!(control & 0x08)); + + // b0: IRQ enable + irq_enable_ = !(control & 0x01); +} + +bool Microdisc::get_interrupt_request_line() +{ + return irq_enable_ && WD1770::get_interrupt_request_line(); +} + +uint8_t Microdisc::get_interrupt_request_register() +{ + return get_interrupt_request_line() ? 0x00 : 0x80; +} + +uint8_t Microdisc::get_data_request_register() +{ + return get_data_request_line() ? 0x00 : 0x80; +} diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp new file mode 100644 index 000000000..ec728c48e --- /dev/null +++ b/Machines/Oric/Microdisc.hpp @@ -0,0 +1,35 @@ +// +// Microdisc.hpp +// Clock Signal +// +// Created by Thomas Harte on 22/11/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Microdisc_hpp +#define Microdisc_hpp + +#include "../../Components/1770/1770.hpp" + +namespace Oric { + +class Microdisc: public WD::WD1770 { + 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(); + + bool get_interrupt_request_line(); + + private: + std::shared_ptr drives_[4]; + int selected_drive_; + bool irq_enable_; +}; + +} + +#endif /* Microdisc_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 7d87faa4b..11eccdc41 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -55,6 +55,7 @@ 4B5A12571DD55862007A2231 /* Disassembler6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A12551DD55862007A2231 /* Disassembler6502.cpp */; }; 4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; }; 4B5FADBD1DE31D1500AEC565 /* OricMFMDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBB1DE31D1500AEC565 /* OricMFMDSK.cpp */; }; + 4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */; }; 4B643F3A1D77AD1900D431D6 /* CSStaticAnalyser.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */; }; 4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; }; 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; }; @@ -505,6 +506,8 @@ 4B5FADB91DE3151600AEC565 /* FileHolder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileHolder.hpp; sourceTree = ""; }; 4B5FADBB1DE31D1500AEC565 /* OricMFMDSK.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OricMFMDSK.cpp; sourceTree = ""; }; 4B5FADBC1DE31D1500AEC565 /* OricMFMDSK.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = OricMFMDSK.hpp; sourceTree = ""; }; + 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Microdisc.cpp; path = Oric/Microdisc.cpp; sourceTree = ""; }; + 4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Microdisc.hpp; path = Oric/Microdisc.hpp; sourceTree = ""; }; 4B643F381D77AD1900D431D6 /* CSStaticAnalyser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CSStaticAnalyser.h; path = StaticAnalyser/CSStaticAnalyser.h; sourceTree = ""; }; 4B643F391D77AD1900D431D6 /* CSStaticAnalyser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CSStaticAnalyser.mm; path = StaticAnalyser/CSStaticAnalyser.mm; sourceTree = ""; }; 4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Target.h"; sourceTree = ""; }; @@ -1791,6 +1794,8 @@ 4BCF1FA51DADC3E10039D2E7 /* Oric */ = { isa = PBXGroup; children = ( + 4B5FADBE1DE3BF2B00AEC565 /* Microdisc.cpp */, + 4B5FADBF1DE3BF2B00AEC565 /* Microdisc.hpp */, 4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */, 4BCF1FA31DADC3DD0039D2E7 /* Oric.hpp */, 4BC8A6291DCE4F2700DAC693 /* Typer.cpp */, @@ -2379,6 +2384,7 @@ 4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, 4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */, + 4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */, 4BEE0A701D72496600532C7B /* PRG.cpp in Sources */, 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */, 4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */, From 13a608a8c2f063cf18bc9867e4ebff52b02833d8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:09:52 +0800 Subject: [PATCH 05/40] Added what may be correct paging logic. --- Machines/Oric/Microdisc.cpp | 18 ++++++++++++++---- Machines/Oric/Microdisc.hpp | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 00454cd19..0a9ccb5d9 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -10,7 +10,10 @@ using namespace Oric; -Microdisc::Microdisc() : irq_enable_(false) +Microdisc::Microdisc() : + irq_enable_(false), + delegate_(nullptr), + paging_flags_(BASICDisable) {} void Microdisc::set_disk(std::shared_ptr disk, int drive) @@ -25,9 +28,7 @@ void Microdisc::set_disk(std::shared_ptr disk, int drive) void Microdisc::set_control_register(uint8_t control) { - // b7: EPROM select (0 = select) - // b2: data separator clock rate select (1 = double) - // b1: ROM disable (0 = disable) + // b2: data separator clock rate select (1 = double) [TODO] // b65: drive select selected_drive_ = (control >> 5)&3; @@ -44,6 +45,15 @@ void Microdisc::set_control_register(uint8_t control) // b0: IRQ enable irq_enable_ = !(control & 0x01); + + // b7: EPROM select (0 = select) + // b1: ROM disable (0 = disable) + int new_paging_flags = ((control & 0x01) ? BASICDisable : 0) | ((control & 0x80) ? 0 : MicrodscDisable); + if(new_paging_flags != paging_flags_) + { + paging_flags_ = new_paging_flags; + if(delegate_) delegate_->microdisc_did_change_paging_flags(this); + } } bool Microdisc::get_interrupt_request_line() diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index ec728c48e..fcbe21b1a 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -24,10 +24,24 @@ class Microdisc: public WD::WD1770 { bool get_interrupt_request_line(); + enum PagingFlags { + BASICDisable = (1 << 0), + MicrodscDisable = (1 << 1) + }; + + class Delegate { + public: + virtual void microdisc_did_change_paging_flags(Microdisc *microdisc) = 0; + }; + inline void set_microdisc_delegate(Delegate *delegate) { delegate_ = delegate; } + inline int get_paging_flags() { return paging_flags_; } + private: std::shared_ptr drives_[4]; int selected_drive_; bool irq_enable_; + int paging_flags_; + Delegate *delegate_; }; } From 03843bf934973795beec28e65601bb9853023536 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:11:11 +0800 Subject: [PATCH 06/40] Unified delegates. Let's keep it easy for the caller. --- Machines/Oric/Microdisc.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index fcbe21b1a..12533d3ff 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -29,12 +29,12 @@ class Microdisc: public WD::WD1770 { MicrodscDisable = (1 << 1) }; - class Delegate { + class Delegate: public WD1770::Delegate { public: virtual void microdisc_did_change_paging_flags(Microdisc *microdisc) = 0; }; - inline void set_microdisc_delegate(Delegate *delegate) { delegate_ = delegate; } - inline int get_paging_flags() { return paging_flags_; } + inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); } + inline int get_paging_flags() { return paging_flags_; } private: std::shared_ptr drives_[4]; From 0c3644f35088a70a3b9eff632707aebcc09e0d09 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:12:32 +0800 Subject: [PATCH 07/40] Made a second parse at logic. We'll see. --- Machines/Oric/Microdisc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 0a9ccb5d9..6612428aa 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -48,7 +48,7 @@ void Microdisc::set_control_register(uint8_t control) // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) - int new_paging_flags = ((control & 0x01) ? BASICDisable : 0) | ((control & 0x80) ? 0 : MicrodscDisable); + int new_paging_flags = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? 0 : MicrodscDisable); if(new_paging_flags != paging_flags_) { paging_flags_ = new_paging_flags; From 707763f80b089a8c0b6abe8ed78d868871088fc0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:22:00 +0800 Subject: [PATCH 08/40] Added Microdisc storage to the Oric class, switching all instance storage to postfix underscore while I'm here. --- Machines/Oric/Oric.cpp | 120 ++++++++++++++++++++--------------------- Machines/Oric/Oric.hpp | 33 +++++++----- 2 files changed, 79 insertions(+), 74 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 68c0da7bd..2e7cf0afc 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -12,25 +12,25 @@ using namespace Oric; Machine::Machine() : - _cycles_since_video_update(0), - _use_fast_tape_hack(false), - _typer_delay(2500000), - _keyboard_read_count(0) + cycles_since_video_update_(0), + use_fast_tape_hack_(false), + typer_delay_(2500000), + keyboard_read_count_(0), + keyboard_(new Keyboard) { set_clock_rate(1000000); - _via.set_interrupt_delegate(this); - _keyboard.reset(new Keyboard); - _via.keyboard = _keyboard; + via_.set_interrupt_delegate(this); + via_.keyboard = keyboard_; clear_all_keys(); - _via.tape->set_delegate(this); - Memory::Fuzz(_ram, sizeof(_ram)); + via_.tape->set_delegate(this); + Memory::Fuzz(ram_, sizeof(ram_)); } void Machine::configure_as_target(const StaticAnalyser::Target &target) { if(target.tapes.size()) { - _via.tape->set_tape(target.tapes.front()); + via_.tape->set_tape(target.tapes.front()); } if(target.loadingCommand.length()) // TODO: and automatic loading option enabled @@ -40,21 +40,21 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) if(target.oric.use_atmos_rom) { - memcpy(_rom, _basic11.data(), std::min(_basic11.size(), sizeof(_rom))); + memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_))); - _is_using_basic11 = true; - _tape_get_byte_address = 0xe6c9; - _scan_keyboard_address = 0xf495; - _tape_speed_address = 0x024d; + is_using_basic11_ = true; + tape_get_byte_address_ = 0xe6c9; + scan_keyboard_address_ = 0xf495; + tape_speed_address_ = 0x024d; } else { - memcpy(_rom, _basic10.data(), std::min(_basic10.size(), sizeof(_rom))); + memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_))); - _is_using_basic11 = false; - _tape_get_byte_address = 0xe630; - _scan_keyboard_address = 0xf43c; - _tape_speed_address = 0x67; + is_using_basic11_ = false; + tape_get_byte_address_ = 0xe630; + scan_keyboard_address_ = 0xf43c; + tape_speed_address_ = 0x67; } } @@ -62,9 +62,9 @@ void Machine::set_rom(ROM rom, const std::vector &data) { switch(rom) { - case BASIC11: _basic11 = std::move(data); break; - case BASIC10: _basic10 = std::move(data); break; - case Microdisc: _microdisc = std::move(data); break; + case BASIC11: basic11_rom_ = std::move(data); break; + case BASIC10: basic10_rom_ = std::move(data); break; + case Microdisc: microdisc_rom_ = std::move(data); break; } } @@ -72,13 +72,13 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if(address >= 0xc000) { - if(isReadOperation(operation)) *value = _rom[address&16383]; + if(isReadOperation(operation)) *value = rom_[address&16383]; // 024D = 0 => fast; otherwise slow // E6C9 = read byte: return byte in A - if(address == _tape_get_byte_address && _use_fast_tape_hack && operation == CPU6502::BusOperation::ReadOpcode && _via.tape->has_tape() && !_via.tape->get_tape()->is_at_end()) + if(address == tape_get_byte_address_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) { - uint8_t next_byte = _via.tape->get_next_byte(!_ram[_tape_speed_address]); + uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]); set_value_of_register(CPU6502::A, next_byte); set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero); *value = 0x60; // i.e. RTS @@ -88,26 +88,26 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if((address & 0xff00) == 0x0300) { - if(isReadOperation(operation)) *value = _via.get_register(address); - else _via.set_register(address, *value); + if(isReadOperation(operation)) *value = via_.get_register(address); + else via_.set_register(address, *value); } else { if(isReadOperation(operation)) - *value = _ram[address]; + *value = ram_[address]; else { - if(address >= 0x9800) { update_video(); _typer_delay = 0; } - _ram[address] = *value; + if(address >= 0x9800) { update_video(); typer_delay_ = 0; } + ram_[address] = *value; } } } - if(_typer && address == _scan_keyboard_address && operation == CPU6502::BusOperation::ReadOpcode) + if(_typer && address == scan_keyboard_address_ && operation == CPU6502::BusOperation::ReadOpcode) { // the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't // do anything until at least the second, regardless of machine - if(!_keyboard_read_count) _keyboard_read_count++; + if(!keyboard_read_count_) keyboard_read_count_++; else if(!_typer->type_next_character()) { clear_all_keys(); @@ -115,39 +115,39 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } } - _via.run_for_cycles(1); - _cycles_since_video_update++; + via_.run_for_cycles(1); + cycles_since_video_update_++; return 1; } void Machine::synchronise() { update_video(); - _via.synchronise(); + via_.synchronise(); } void Machine::update_video() { - _videoOutput->run_for_cycles(_cycles_since_video_update); - _cycles_since_video_update = 0; + video_output_->run_for_cycles(cycles_since_video_update_); + cycles_since_video_update_ = 0; } void Machine::setup_output(float aspect_ratio) { - _videoOutput.reset(new VideoOutput(_ram)); - _via.ay8910.reset(new GI::AY38910()); - _via.ay8910->set_clock_rate(1000000); + video_output_.reset(new VideoOutput(ram_)); + via_.ay8910.reset(new GI::AY38910()); + via_.ay8910->set_clock_rate(1000000); } void Machine::close_output() { - _videoOutput.reset(); - _via.ay8910.reset(); + video_output_.reset(); + via_.ay8910.reset(); } void Machine::mos6522_did_change_interrupt_status(void *mos6522) { - set_irq_line(_via.get_interrupt_line()); + set_irq_line(via_.get_interrupt_line()); } void Machine::set_key_state(uint16_t key, bool isPressed) @@ -159,36 +159,36 @@ void Machine::set_key_state(uint16_t key, bool isPressed) else { if(isPressed) - _keyboard->rows[key >> 8] |= (key & 0xff); + keyboard_->rows[key >> 8] |= (key & 0xff); else - _keyboard->rows[key >> 8] &= ~(key & 0xff); + keyboard_->rows[key >> 8] &= ~(key & 0xff); } } void Machine::clear_all_keys() { - memset(_keyboard->rows, 0, sizeof(_keyboard->rows)); + memset(keyboard_->rows, 0, sizeof(keyboard_->rows)); } void Machine::set_use_fast_tape_hack(bool activate) { - _use_fast_tape_hack = activate; + use_fast_tape_hack_ = activate; } void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player) { // set CB1 - _via.set_control_line_input(VIA::Port::B, VIA::Line::One, tape_player->get_input()); + via_.set_control_line_input(VIA::Port::B, VIA::Line::One, tape_player->get_input()); } std::shared_ptr Machine::get_crt() { - return _videoOutput->get_crt(); + return video_output_->get_crt(); } std::shared_ptr Machine::get_speaker() { - return _via.ay8910; + return via_.ay8910; } void Machine::run_for_cycles(int number_of_cycles) @@ -200,14 +200,14 @@ void Machine::run_for_cycles(int number_of_cycles) Machine::VIA::VIA() : MOS::MOS6522(), - _cycles_since_ay_update(0), + cycles_since_ay_update_(0), tape(new TapePlayer) {} void Machine::VIA::set_control_line_output(Port port, Line line, bool value) { if(line) { - if(port) _ay_bdir = value; else _ay_bc1 = value; + if(port) ay_bdir_ = value; else ay_bc1_ = value; update_ay(); } } @@ -240,23 +240,23 @@ uint8_t Machine::VIA::get_port_input(Port port) void Machine::VIA::synchronise() { - ay8910->run_for_cycles(_cycles_since_ay_update); + ay8910->run_for_cycles(cycles_since_ay_update_); ay8910->flush(); - _cycles_since_ay_update = 0; + cycles_since_ay_update_ = 0; } void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) { - _cycles_since_ay_update += number_of_cycles; + cycles_since_ay_update_ += number_of_cycles; MOS::MOS6522::run_for_cycles(number_of_cycles); tape->run_for_cycles((int)number_of_cycles); } void Machine::VIA::update_ay() { - ay8910->run_for_cycles(_cycles_since_ay_update); - _cycles_since_ay_update = 0; - ay8910->set_control_lines( (GI::AY38910::ControlLines)((_ay_bdir ? GI::AY38910::BCDIR : 0) | (_ay_bc1 ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2)); + ay8910->run_for_cycles(cycles_since_ay_update_); + cycles_since_ay_update_ = 0; + ay8910->set_control_lines( (GI::AY38910::ControlLines)((ay_bdir_ ? GI::AY38910::BCDIR : 0) | (ay_bc1_ ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2)); } #pragma mark - TapePlayer @@ -267,5 +267,5 @@ Machine::TapePlayer::TapePlayer() : uint8_t Machine::TapePlayer::get_next_byte(bool fast) { - return (uint8_t)_parser.get_next_byte(get_tape(), fast); + return (uint8_t)parser_.get_next_byte(get_tape(), fast); } diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 559e4914b..65780ddc5 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -19,6 +19,7 @@ #include "../../Storage/Tape/Parsers/Oric.hpp" #include "Video.hpp" +#include "Microdisc.hpp" #include "../../Storage/Tape/Tape.hpp" @@ -97,18 +98,18 @@ class Machine: private: // RAM and ROM - std::vector _basic11, _basic10, _microdisc; - uint8_t _ram[65536], _rom[16384]; - int _cycles_since_video_update; + std::vector basic11_rom_, basic10_rom_, microdisc_rom_; + uint8_t ram_[65536], rom_[16384]; + int cycles_since_video_update_; inline void update_video(); // ROM bookkeeping - bool _is_using_basic11; - uint16_t _tape_get_byte_address, _scan_keyboard_address, _tape_speed_address; - int _keyboard_read_count; + bool is_using_basic11_; + uint16_t tape_get_byte_address_, scan_keyboard_address_, tape_speed_address_; + int keyboard_read_count_; // Outputs - std::unique_ptr _videoOutput; + std::unique_ptr video_output_; // Keyboard class Keyboard { @@ -116,7 +117,7 @@ class Machine: uint8_t row; uint8_t rows[8]; }; - int _typer_delay; + int typer_delay_; // The tape class TapePlayer: public Storage::Tape::BinaryTapePlayer { @@ -125,9 +126,9 @@ class Machine: uint8_t get_next_byte(bool fast); private: - Storage::Tape::Oric::Parser _parser; + Storage::Tape::Oric::Parser parser_; }; - bool _use_fast_tape_hack; + bool use_fast_tape_hack_; // VIA (which owns the tape and the AY) class VIA: public MOS::MOS6522, public MOS::MOS6522IRQDelegate { @@ -148,11 +149,15 @@ class Machine: private: void update_ay(); - bool _ay_bdir, _ay_bc1; - unsigned int _cycles_since_ay_update; + bool ay_bdir_, ay_bc1_; + unsigned int cycles_since_ay_update_; }; - VIA _via; - std::shared_ptr _keyboard; + VIA via_; + std::shared_ptr keyboard_; + + // the Microdisc, if in use + class Microdisc microdisc_; + bool microdisc_is_enabled_; }; } From 5ebc1c63ff0872944fa7916f6290f8af4088fa17 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:28:45 +0800 Subject: [PATCH 09/40] Switched video to postfix underscores, for consistency. --- Machines/Oric/Video.cpp | 149 ++++++++++++++++++++-------------------- Machines/Oric/Video.hpp | 26 +++---- 2 files changed, 87 insertions(+), 88 deletions(-) diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index 5176aeee0..c4cac87d4 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -20,18 +20,17 @@ namespace { } VideoOutput::VideoOutput(uint8_t *memory) : - _ram(memory), - _frame_counter(0), _counter(0), - _is_graphics_mode(false), - _character_set_base_address(0xb400), - _phase(0), - _v_sync_start_position(PAL50VSyncStartPosition), _v_sync_end_position(PAL50VSyncEndPosition), - _counter_period(PAL50Period), _next_frame_is_sixty_hertz(false) + ram_(memory), + frame_counter_(0), counter_(0), + is_graphics_mode_(false), + character_set_base_address_(0xb400), + phase_(0), + v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition), + counter_period_(PAL50Period), next_frame_is_sixty_hertz_(false), + crt_(new Outputs::CRT::CRT(64*6, 6, Outputs::CRT::DisplayType::PAL50, 1)) { - _crt.reset(new Outputs::CRT::CRT(64*6, 6, Outputs::CRT::DisplayType::PAL50, 1)); - // TODO: this is a copy and paste from the Electron; factor out. - _crt->set_rgb_sampling_function( + crt_->set_rgb_sampling_function( "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "{" "uint texValue = texture(sampler, coordinate).r;" @@ -39,13 +38,13 @@ VideoOutput::VideoOutput(uint8_t *memory) : "return vec3( uvec3(texValue) & uvec3(4u, 2u, 1u));" "}"); - _crt->set_output_device(Outputs::CRT::Television); - _crt->set_visible_area(_crt->get_rect_for_area(50, 224, 16 * 6, 40 * 6, 4.0f / 3.0f)); + crt_->set_output_device(Outputs::CRT::Television); + crt_->set_visible_area(crt_->get_rect_for_area(50, 224, 16 * 6, 40 * 6, 4.0f / 3.0f)); } std::shared_ptr VideoOutput::get_crt() { - return _crt; + return crt_; } void VideoOutput::run_for_cycles(int number_of_cycles) @@ -58,58 +57,58 @@ void VideoOutput::run_for_cycles(int number_of_cycles) while(number_of_cycles) { - int h_counter =_counter & 63; + int h_counter = counter_ & 63; int cycles_run_for = 0; - if(_counter >= _v_sync_start_position && _counter < _v_sync_end_position) + if(counter_ >= v_sync_start_position_ && counter_ < v_sync_end_position_) { // this is a sync line - cycles_run_for = _v_sync_end_position - _counter; - clamp(_crt->output_sync((unsigned int)(_v_sync_end_position - _v_sync_start_position) * 6)); + cycles_run_for = v_sync_end_position_ - counter_; + clamp(crt_->output_sync((unsigned int)(v_sync_end_position_ - v_sync_start_position_) * 6)); } - else if(_counter < 224*64 && h_counter < 40) + else if(counter_ < 224*64 && h_counter < 40) { // this is a pixel line if(!h_counter) { - _ink = 0xff; - _paper = 0x00; - _use_alternative_character_set = _use_double_height_characters = _blink_text = false; + ink_ = 0xff; + paper_ = 0x00; + use_alternative_character_set_ = use_double_height_characters_ = blink_text_ = false; set_character_set_base_address(); - _phase += 64; - _pixel_target = _crt->allocate_write_area(120); + phase_ += 64; + pixel_target_ = crt_->allocate_write_area(120); - if(!_counter) + if(!counter_) { - _phase += 128; // TODO: incorporate all the lines that were missed - _frame_counter++; + phase_ += 128; // TODO: incorporate all the lines that were missed + frame_counter_++; - _v_sync_start_position = _next_frame_is_sixty_hertz ? PAL60VSyncStartPosition : PAL50VSyncStartPosition; - _v_sync_end_position = _next_frame_is_sixty_hertz ? PAL60VSyncEndPosition : PAL50VSyncEndPosition; - _counter_period = _next_frame_is_sixty_hertz ? PAL60Period : PAL50Period; + v_sync_start_position_ = next_frame_is_sixty_hertz_ ? PAL60VSyncStartPosition : PAL50VSyncStartPosition; + v_sync_end_position_ = next_frame_is_sixty_hertz_ ? PAL60VSyncEndPosition : PAL50VSyncEndPosition; + counter_period_ = next_frame_is_sixty_hertz_ ? PAL60Period : PAL50Period; } } cycles_run_for = std::min(40 - h_counter, number_of_cycles); int columns = cycles_run_for; - int pixel_base_address = 0xa000 + (_counter >> 6) * 40; - int character_base_address = 0xbb80 + (_counter >> 9) * 40; - uint8_t blink_mask = (_blink_text && (_frame_counter&32)) ? 0x00 : 0xff; + int pixel_base_address = 0xa000 + (counter_ >> 6) * 40; + int character_base_address = 0xbb80 + (counter_ >> 9) * 40; + uint8_t blink_mask = (blink_text_ && (frame_counter_&32)) ? 0x00 : 0xff; while(columns--) { uint8_t pixels, control_byte; - if(_is_graphics_mode && _counter < 200*64) + if(is_graphics_mode_ && counter_ < 200*64) { - control_byte = pixels = _ram[pixel_base_address + h_counter]; + control_byte = pixels = ram_[pixel_base_address + h_counter]; } else { int address = character_base_address + h_counter; - control_byte = _ram[address]; - int line = _use_double_height_characters ? ((_counter >> 7) & 7) : ((_counter >> 6) & 7); - pixels = _ram[_character_set_base_address + (control_byte&127) * 8 + line]; + control_byte = ram_[address]; + int line = use_double_height_characters_ ? ((counter_ >> 7) & 7) : ((counter_ >> 6) & 7); + pixels = ram_[character_set_base_address_ + (control_byte&127) * 8 + line]; } uint8_t inverse_mask = (control_byte & 0x80) ? 0x77 : 0x00; @@ -117,65 +116,65 @@ void VideoOutput::run_for_cycles(int number_of_cycles) if(control_byte & 0x60) { - if(_pixel_target) + if(pixel_target_) { uint8_t colours[2] = { - (uint8_t)(_paper ^ inverse_mask), - (uint8_t)(_ink ^ inverse_mask), + (uint8_t)(paper_ ^ inverse_mask), + (uint8_t)(ink_ ^ inverse_mask), }; - _pixel_target[0] = (colours[(pixels >> 4)&1] & 0x0f) | (colours[(pixels >> 5)&1] & 0xf0); - _pixel_target[1] = (colours[(pixels >> 2)&1] & 0x0f) | (colours[(pixels >> 3)&1] & 0xf0); - _pixel_target[2] = (colours[(pixels >> 0)&1] & 0x0f) | (colours[(pixels >> 1)&1] & 0xf0); + pixel_target_[0] = (colours[(pixels >> 4)&1] & 0x0f) | (colours[(pixels >> 5)&1] & 0xf0); + pixel_target_[1] = (colours[(pixels >> 2)&1] & 0x0f) | (colours[(pixels >> 3)&1] & 0xf0); + pixel_target_[2] = (colours[(pixels >> 0)&1] & 0x0f) | (colours[(pixels >> 1)&1] & 0xf0); } } else { switch(control_byte & 0x1f) { - case 0x00: _ink = 0x00; break; - case 0x01: _ink = 0x44; break; - case 0x02: _ink = 0x22; break; - case 0x03: _ink = 0x66; break; - case 0x04: _ink = 0x11; break; - case 0x05: _ink = 0x55; break; - case 0x06: _ink = 0x33; break; - case 0x07: _ink = 0x77; break; + case 0x00: ink_ = 0x00; break; + case 0x01: ink_ = 0x44; break; + case 0x02: ink_ = 0x22; break; + case 0x03: ink_ = 0x66; break; + case 0x04: ink_ = 0x11; break; + case 0x05: ink_ = 0x55; break; + case 0x06: ink_ = 0x33; break; + case 0x07: ink_ = 0x77; break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: - _use_alternative_character_set = (control_byte&1); - _use_double_height_characters = (control_byte&2); - _blink_text = (control_byte&4); + use_alternative_character_set_ = (control_byte&1); + use_double_height_characters_ = (control_byte&2); + blink_text_ = (control_byte&4); set_character_set_base_address(); break; - case 0x10: _paper = 0x00; break; - case 0x11: _paper = 0x44; break; - case 0x12: _paper = 0x22; break; - case 0x13: _paper = 0x66; break; - case 0x14: _paper = 0x11; break; - case 0x15: _paper = 0x55; break; - case 0x16: _paper = 0x33; break; - case 0x17: _paper = 0x77; break; + case 0x10: paper_ = 0x00; break; + case 0x11: paper_ = 0x44; break; + case 0x12: paper_ = 0x22; break; + case 0x13: paper_ = 0x66; break; + case 0x14: paper_ = 0x11; break; + case 0x15: paper_ = 0x55; break; + case 0x16: paper_ = 0x33; break; + case 0x17: paper_ = 0x77; break; case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: - _is_graphics_mode = (control_byte & 4); - _next_frame_is_sixty_hertz = !(control_byte & 2); + is_graphics_mode_ = (control_byte & 4); + next_frame_is_sixty_hertz_ = !(control_byte & 2); break; default: break; } - if(_pixel_target) _pixel_target[0] = _pixel_target[1] = _pixel_target[2] = (uint8_t)(_paper ^ inverse_mask); + if(pixel_target_) pixel_target_[0] = pixel_target_[1] = pixel_target_[2] = (uint8_t)(paper_ ^ inverse_mask); } - if(_pixel_target) _pixel_target += 3; + if(pixel_target_) pixel_target_ += 3; h_counter++; } if(h_counter == 40) { - _crt->output_data(40 * 6, 2); + crt_->output_data(40 * 6, 2); } } else @@ -185,34 +184,34 @@ void VideoOutput::run_for_cycles(int number_of_cycles) { cycles_run_for = 48 - h_counter; clamp( - int period = (_counter < 224*64) ? 8 : 48; - _crt->output_blank((unsigned int)period * 6); + int period = (counter_ < 224*64) ? 8 : 48; + crt_->output_blank((unsigned int)period * 6); ); } else if(h_counter < 54) { cycles_run_for = 54 - h_counter; - clamp(_crt->output_sync(6 * 6)); + clamp(crt_->output_sync(6 * 6)); } else if(h_counter < 56) { cycles_run_for = 56 - h_counter; - clamp(_crt->output_colour_burst(2 * 6, _phase, 128)); + clamp(crt_->output_colour_burst(2 * 6, phase_, 128)); } else { cycles_run_for = 64 - h_counter; - clamp(_crt->output_blank(8 * 6)); + clamp(crt_->output_blank(8 * 6)); } } - _counter = (_counter + cycles_run_for)%_counter_period; + counter_ = (counter_ + cycles_run_for)%counter_period_; number_of_cycles -= cycles_run_for; } } void VideoOutput::set_character_set_base_address() { - if(_is_graphics_mode) _character_set_base_address = _use_alternative_character_set ? 0x9c00 : 0x9800; - else _character_set_base_address = _use_alternative_character_set ? 0xb800 : 0xb400; + if(is_graphics_mode_) character_set_base_address_ = use_alternative_character_set_ ? 0x9c00 : 0x9800; + else character_set_base_address_ = use_alternative_character_set_ ? 0xb800 : 0xb400; } diff --git a/Machines/Oric/Video.hpp b/Machines/Oric/Video.hpp index 28d8661ec..2629d3ddd 100644 --- a/Machines/Oric/Video.hpp +++ b/Machines/Oric/Video.hpp @@ -20,29 +20,29 @@ class VideoOutput { void run_for_cycles(int number_of_cycles); private: - uint8_t *_ram; - std::shared_ptr _crt; + uint8_t *ram_; + std::shared_ptr crt_; // Counters and limits - int _counter, _frame_counter; - int _v_sync_start_position, _v_sync_end_position, _counter_period; + int counter_, frame_counter_; + int v_sync_start_position_, v_sync_end_position_, counter_period_; // Output target - uint8_t *_pixel_target; + uint8_t *pixel_target_; // Registers - uint8_t _ink, _paper; + uint8_t ink_, paper_; - int _character_set_base_address; + int character_set_base_address_; inline void set_character_set_base_address(); - bool _is_graphics_mode; - bool _next_frame_is_sixty_hertz; - bool _use_alternative_character_set; - bool _use_double_height_characters; - bool _blink_text; + bool is_graphics_mode_; + bool next_frame_is_sixty_hertz_; + bool use_alternative_character_set_; + bool use_double_height_characters_; + bool blink_text_; - uint8_t _phase; + uint8_t phase_; }; } From 7c2d9f3752c7d775ea8a65fb6216b06e50f8036c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 22 Nov 2016 22:35:43 +0800 Subject: [PATCH 10/40] This seems to be right, per http://wiki.defence-force.org/doku.php?id=oric:hardware:floppy_disk_controller_wd1793 --- Machines/Oric/Microdisc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 6612428aa..8aba1b4a8 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -48,7 +48,7 @@ void Microdisc::set_control_register(uint8_t control) // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) - int new_paging_flags = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? 0 : MicrodscDisable); + int new_paging_flags = ((control & 0x02) ? BASICDisable : 0) | ((control & 0x80) ? 0 : MicrodscDisable); if(new_paging_flags != paging_flags_) { paging_flags_ = new_paging_flags; From d33f3b9224b1a8e1e9dbe71203ea9b109c2899f6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 20:15:48 +0800 Subject: [PATCH 11/40] This is the broad strokes effort at enabling Microdisc emulation. --- Machines/Oric/Oric.cpp | 86 ++++++++++++++++++++++++++++++++++++++---- Machines/Oric/Oric.hpp | 12 +++++- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 2e7cf0afc..ed6bceb80 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -16,7 +16,9 @@ Machine::Machine() : use_fast_tape_hack_(false), typer_delay_(2500000), keyboard_read_count_(0), - keyboard_(new Keyboard) + keyboard_(new Keyboard), + ram_top_(0xbfff), + paged_rom_(rom_) { set_clock_rate(1000000); via_.set_interrupt_delegate(this); @@ -38,6 +40,13 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) set_typer_for_string(target.loadingCommand.c_str()); } + if(target.oric.has_microdisc) + { + microdisc_is_enabled_ = true; + microdisc_did_change_paging_flags(µdisc_); + microdisc_.set_delegate(this); + } + if(target.oric.use_atmos_rom) { memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_))); @@ -70,13 +79,13 @@ void Machine::set_rom(ROM rom, const std::vector &data) unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { - if(address >= 0xc000) + if(address > ram_top_) { - if(isReadOperation(operation)) *value = rom_[address&16383]; + if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1]; // 024D = 0 => fast; otherwise slow // E6C9 = read byte: return byte in A - if(address == tape_get_byte_address_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) + if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end()) { uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]); set_value_of_register(CPU6502::A, next_byte); @@ -88,8 +97,28 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { if((address & 0xff00) == 0x0300) { - if(isReadOperation(operation)) *value = via_.get_register(address); - else via_.set_register(address, *value); + if(microdisc_is_enabled_ && address >= 0x0310) + { + switch(address) + { + case 0x0310: case 0x0311: case 0x0312: case 0x0313: + if(isReadOperation(operation)) *value = microdisc_.get_register(address); + else microdisc_.set_register(address, *value); + break; + case 0x314: + if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register(); + else microdisc_.set_control_register(*value); + break; + case 0x318: + if(isReadOperation(operation)) *value = microdisc_.get_data_request_register(); + break; + } + } + else + { + if(isReadOperation(operation)) *value = via_.get_register(address); + else via_.set_register(address, *value); + } } else { @@ -97,7 +126,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin *value = ram_[address]; else { - if(address >= 0x9800) { update_video(); typer_delay_ = 0; } + if(address >= 0x9800 && address <= 0xc000) { update_video(); typer_delay_ = 0; } ram_[address] = *value; } } @@ -147,7 +176,7 @@ void Machine::close_output() void Machine::mos6522_did_change_interrupt_status(void *mos6522) { - set_irq_line(via_.get_interrupt_line()); + set_interrupt_line(); } void Machine::set_key_state(uint16_t key, bool isPressed) @@ -269,3 +298,44 @@ uint8_t Machine::TapePlayer::get_next_byte(bool fast) { return (uint8_t)parser_.get_next_byte(get_tape(), fast); } + +#pragma mark - Microdisc + +void Machine::microdisc_did_change_paging_flags(class Microdisc *microdisc) +{ + int flags = microdisc->get_paging_flags(); + if(!(flags&Microdisc::PagingFlags::BASICDisable)) + { + ram_top_ = 0xbfff; + paged_rom_ = rom_; + } + else + { + if(flags&Microdisc::PagingFlags::MicrodscDisable) + { + ram_top_ = 0xffff; + } + else + { + ram_top_ = 0xdfff; + paged_rom_ = microdisc_rom_.data(); + } + } +} + +void Machine::wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770) +{ + set_interrupt_line(); +} + +void Machine::wd1770_did_change_data_request_status(WD::WD1770 *wd1770) +{ + // Don't care. +} + +void Machine::set_interrupt_line() +{ + set_irq_line( + via_.get_interrupt_line() || + (microdisc_is_enabled_ && microdisc_.get_interrupt_request_line())); +} diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 65780ddc5..f5fa246c0 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -62,7 +62,8 @@ class Machine: public ConfigurationTarget::Machine, public MOS::MOS6522IRQDelegate::Delegate, public Utility::TypeRecipient, - public Storage::Tape::BinaryTapePlayer::Delegate { + public Storage::Tape::BinaryTapePlayer::Delegate, + public Microdisc::Delegate { public: Machine(); @@ -96,6 +97,11 @@ class Machine: // for Utility::TypeRecipient::Delegate uint16_t *sequence_for_character(Utility::Typer *typer, char character); + // for Microdisc::Delegate + void microdisc_did_change_paging_flags(class Microdisc *microdisc); + void wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770); + void wd1770_did_change_data_request_status(WD::WD1770 *wd1770); + private: // RAM and ROM std::vector basic11_rom_, basic10_rom_, microdisc_rom_; @@ -158,6 +164,10 @@ class Machine: // the Microdisc, if in use class Microdisc microdisc_; bool microdisc_is_enabled_; + uint16_t ram_top_; + uint8_t *paged_rom_; + + inline void set_interrupt_line(); }; } From 5be45c6c501336d444fda08c499d9cfc626ecdf7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 20:30:27 +0800 Subject: [PATCH 12/40] Ensured proper default behaviour. --- Machines/Oric/Oric.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index ed6bceb80..b23bb5f2e 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -18,7 +18,8 @@ Machine::Machine() : keyboard_read_count_(0), keyboard_(new Keyboard), ram_top_(0xbfff), - paged_rom_(rom_) + paged_rom_(rom_), + microdisc_is_enabled_(false) { set_clock_rate(1000000); via_.set_interrupt_delegate(this); From 5c019ad1c0c76df9bc1907f0d71f36db1ac34838 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 20:42:40 +0800 Subject: [PATCH 13/40] Okay, so it looks like both ROM paging flags are the opposite of what I previously had. --- Machines/Oric/Microdisc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 8aba1b4a8..743ef21a2 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -48,7 +48,7 @@ void Microdisc::set_control_register(uint8_t control) // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) - int new_paging_flags = ((control & 0x02) ? BASICDisable : 0) | ((control & 0x80) ? 0 : MicrodscDisable); + int new_paging_flags = ((control & 0x02) ? 0 : BASICDisable) | ((control & 0x80) ? MicrodscDisable : 0); if(new_paging_flags != paging_flags_) { paging_flags_ = new_paging_flags; From 4af678d2eddb25b8e4fa166283fc3566cc3fbc64 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 20:51:39 +0800 Subject: [PATCH 14/40] Gave the Microdisc a clock signal, added just enough of force interrupt to avoid a spurious belief that a type 3 command has started. --- Components/1770/1770.cpp | 16 ++++++++++++---- Machines/Oric/Oric.cpp | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 7bb70ee10..91724f2f2 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -1,4 +1,4 @@ -// + // // 1770.cpp // Clock Signal // @@ -44,9 +44,17 @@ void WD1770::set_register(int address, uint8_t value) switch(address&3) { case 0: - command_ = value; - posit_event(Event::Command); - // TODO: is this force interrupt? + { + if((value&0xf0) == 0xd0) + { + printf("!!!TODO: force interrupt!!!\n"); + } + else + { + command_ = value; + posit_event(Event::Command); + } + } break; case 1: track_ = value; break; case 2: sector_ = value; break; diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index b23bb5f2e..d14025735 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -146,6 +146,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } via_.run_for_cycles(1); + if(microdisc_is_enabled_) microdisc_.run_for_cycles(8); cycles_since_video_update_++; return 1; } From 8be81f6ebd61619c742fc2f8f3d3eb6705948ab7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 20:53:38 +0800 Subject: [PATCH 15/40] Supplied disks are given to the Microdisc. --- Machines/Oric/Oric.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index d14025735..9ecff5352 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -48,6 +48,13 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) microdisc_.set_delegate(this); } + int drive_index = 0; + for(auto disk : target.disks) + { + if(drive_index < 4) microdisc_.set_disk(disk, drive_index); + drive_index++; + } + if(target.oric.use_atmos_rom) { memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_))); From d5f9e0aa3b48a9137b15e247ad9b151856beb40e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 21:24:25 +0800 Subject: [PATCH 16/40] Ensured there's no such thing as a zero-cycle operation, even if i don't yet know exactly what I should be doing. --- Components/1770/1770.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 91724f2f2..cc11ec656 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -261,6 +261,7 @@ void WD1770::posit_event(Event new_event_type) status_ &= ~Flag::Busy; index_hole_count_ = 0; WAIT_FOR_EVENT(Event::Command); + WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? printf("Starting %02x\n", command_); status_ |= Flag::Busy; if(!(command_ & 0x80)) goto begin_type_1; From 54246c8f1aa8763e5b143de05bf6b6ce5719b855 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 21:24:59 +0800 Subject: [PATCH 17/40] Interrupt enabling works the other way around I think, and both registers with only one bit defined should probably return '1' in all other places? --- Machines/Oric/Microdisc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 743ef21a2..a4f784837 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -44,7 +44,7 @@ void Microdisc::set_control_register(uint8_t control) set_is_double_density(!(control & 0x08)); // b0: IRQ enable - irq_enable_ = !(control & 0x01); + irq_enable_ = !!(control & 0x01); // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) @@ -63,10 +63,10 @@ bool Microdisc::get_interrupt_request_line() uint8_t Microdisc::get_interrupt_request_register() { - return get_interrupt_request_line() ? 0x00 : 0x80; + return 0x7f | (get_interrupt_request_line() ? 0x00 : 0x80); } uint8_t Microdisc::get_data_request_register() { - return get_data_request_line() ? 0x00 : 0x80; + return 0x7f | (get_data_request_line() ? 0x00 : 0x80); } From 12956901d6953d00a247f3630bef4ec0c0164027 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 21:28:11 +0800 Subject: [PATCH 18/40] Filled in some register mirrors. --- Machines/Oric/Oric.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 9ecff5352..accbb8ec0 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -113,11 +113,11 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin if(isReadOperation(operation)) *value = microdisc_.get_register(address); else microdisc_.set_register(address, *value); break; - case 0x314: + case 0x314: case 0x315: case 0x316: case 0x317: if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register(); else microdisc_.set_control_register(*value); break; - case 0x318: + case 0x318: case 0x319: case 0x31a: 0x31b: if(isReadOperation(operation)) *value = microdisc_.get_data_request_register(); break; } From 73d30b9c00b97f0cd8149bd56340b1abb72fd089 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 25 Nov 2016 21:30:45 +0800 Subject: [PATCH 19/40] Corrected typo. --- 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 accbb8ec0..a80dfdb14 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -117,7 +117,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register(); else microdisc_.set_control_register(*value); break; - case 0x318: case 0x319: case 0x31a: 0x31b: + case 0x318: case 0x319: case 0x31a: case 0x31b: if(isReadOperation(operation)) *value = microdisc_.get_data_request_register(); break; } From e9d6566e9cbe7cddd12688c1c441e08bb2d445db Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 09:35:44 +0800 Subject: [PATCH 20/40] Of course, changing the IRQ enable may immediately change the IRQ line. Signal if so. --- Machines/Oric/Microdisc.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index a4f784837..2aa5f7690 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -44,7 +44,13 @@ void Microdisc::set_control_register(uint8_t control) set_is_double_density(!(control & 0x08)); // b0: IRQ enable + bool had_irq = get_interrupt_request_line(); irq_enable_ = !!(control & 0x01); + bool has_irq = get_interrupt_request_line(); + if(has_irq != had_irq && delegate_) + { + delegate_->wd1770_did_change_interrupt_request_status(this); + } // b7: EPROM select (0 = select) // b1: ROM disable (0 = disable) From b9677c99271141cebea42d63f3170025d3f3b024 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 09:41:53 +0800 Subject: [PATCH 21/40] Consolidated interrupt request setting. --- Components/1770/1770.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index cc11ec656..1939aa93a 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -260,8 +260,10 @@ void WD1770::posit_event(Event new_event_type) is_reading_data_ = false; status_ &= ~Flag::Busy; index_hole_count_ = 0; + set_interrupt_request(true); WAIT_FOR_EVENT(Event::Command); - WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? + set_interrupt_request(false); +// WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? printf("Starting %02x\n", command_); status_ |= Flag::Busy; if(!(command_ & 0x80)) goto begin_type_1; @@ -275,7 +277,6 @@ void WD1770::posit_event(Event new_event_type) begin_type_1: // Set initial flags, skip spin-up if possible. status_ &= ~Flag::SeekError; - set_interrupt_request(false); set_data_request(false); if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type1_type; @@ -330,7 +331,6 @@ void WD1770::posit_event(Event new_event_type) verify: if(!(command_ & 0x04)) { - set_interrupt_request(true); goto wait_for_command; } @@ -343,7 +343,6 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 6) { - set_interrupt_request(true); status_ |= Flag::SeekError; goto wait_for_command; } @@ -355,7 +354,6 @@ void WD1770::posit_event(Event new_event_type) { printf("Reached track %d\n", track_); status_ &= ~Flag::CRCError; - set_interrupt_request(true); goto wait_for_command; } @@ -369,7 +367,6 @@ void WD1770::posit_event(Event new_event_type) */ begin_type_2: status_ &= ~(Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType); - set_interrupt_request(false); set_data_request(false); distance_into_section_ = 0; if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay; @@ -385,7 +382,6 @@ void WD1770::posit_event(Event new_event_type) test_type2_write_protection: if(command_&0x20) // TODO:: && is_write_protected { - set_interrupt_request(true); status_ |= Flag::WriteProtect; goto wait_for_command; } @@ -396,7 +392,6 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 5) { - set_interrupt_request(true); status_ |= Flag::RecordNotFound; goto wait_for_command; } @@ -456,7 +451,6 @@ void WD1770::posit_event(Event new_event_type) sector_++; goto test_type2_write_protection; } - set_interrupt_request(true); printf("Read sector %d\n", sector_); goto wait_for_command; } From 7613755f94385c31f585e3e11b54af6bf04ffa2b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 10:13:12 +0800 Subject: [PATCH 22/40] Fixed addressing: types are 1 and 2, not 0 and 1. --- Storage/Disk/Formats/OricMFMDSK.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Storage/Disk/Formats/OricMFMDSK.cpp b/Storage/Disk/Formats/OricMFMDSK.cpp index 0a849fa6d..aa002fcc4 100644 --- a/Storage/Disk/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/Formats/OricMFMDSK.cpp @@ -21,7 +21,7 @@ OricMFMDSK::OricMFMDSK(const char *file_name) : track_count_ = fgetc32le(); geometry_type_ = fgetc32le(); - if(geometry_type_ > 1) + if(geometry_type_ < 1 || geometry_type_ > 2) throw ErrorNotOricMFMDSK; } @@ -40,10 +40,10 @@ std::shared_ptr OricMFMDSK::get_track_at_position(unsigned int head, unsi long offset = 0; switch(geometry_type_) { - case 0: + case 1: offset = (head * track_count_) + position; break; - case 1: + case 2: offset = (position * track_count_ * head_count_) + head; break; } From b180f04c877bcb87306c0d6e9337f26890dc092e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 10:19:10 +0800 Subject: [PATCH 23/40] Okay, so this file format wasn't what I hoped it was. It's another hack. Lots of work to do. --- Storage/Disk/Formats/OricMFMDSK.cpp | 4 ++++ Storage/Disk/Formats/OricMFMDSK.hpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Storage/Disk/Formats/OricMFMDSK.cpp b/Storage/Disk/Formats/OricMFMDSK.cpp index aa002fcc4..c522e092f 100644 --- a/Storage/Disk/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/Formats/OricMFMDSK.cpp @@ -49,6 +49,10 @@ std::shared_ptr OricMFMDSK::get_track_at_position(unsigned int head, unsi } fseek(file_, (offset * 6400) + 256, SEEK_SET); + // TODO: upon review, the file format actually seems to omit clock bits. So it's not an MFM capture. + // A consumer must contextually guess when an FB, FC, etc is meant to be a control mark. So turfing + // the data over directly as below isn't correct. + PCMSegment segment; segment.number_of_bits = 6250*8; segment.data.resize(6250); diff --git a/Storage/Disk/Formats/OricMFMDSK.hpp b/Storage/Disk/Formats/OricMFMDSK.hpp index 4cc8c9860..c87bd4d89 100644 --- a/Storage/Disk/Formats/OricMFMDSK.hpp +++ b/Storage/Disk/Formats/OricMFMDSK.hpp @@ -16,7 +16,7 @@ namespace Storage { namespace Disk { /*! - Provies a @c Disk containing an Oric MFM-stype disk image — an MFM bit stream. + Provies a @c Disk containing an Oric MFM-stype disk image — a stream of the MFM data bits with clocks omitted. */ class OricMFMDSK: public Disk, public Storage::FileHolder { public: From dcfdd73077325eae067eab2f1a3882d8ce1a3e2c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 13:39:20 +0800 Subject: [PATCH 24/40] Switched to more conventional runtime polymorphism, also now allowing encoders (shifters as were) to be obtained, as a slightly lower-level interface than vector-of-sectors. --- Storage/Disk/Encodings/MFM.cpp | 88 ++++++++++++++++------------------ Storage/Disk/Encodings/MFM.hpp | 20 +++++++- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index 949588528..8c864ff53 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -13,24 +13,10 @@ using namespace Storage::Encodings::MFM; -template class Shifter { +class MFMEncoder: public Encoder { public: - virtual void add_byte(uint8_t input) = 0; - virtual void add_index_address_mark() = 0; - virtual void add_ID_address_mark() = 0; - virtual void add_data_address_mark() = 0; - virtual void add_deleted_data_address_mark() = 0; + MFMEncoder(std::vector &target) : Encoder(target) {} - protected: - /*! - Intended to be overridden by subclasses; should write value out as PCM data, - MSB first. - */ - void output_short(uint16_t value); -}; - -template class MFMShifter: public Shifter { - public: void add_byte(uint8_t input) { uint16_t spread_value = (uint16_t)( @@ -45,26 +31,26 @@ template class MFMShifter: public Shifter { ); uint16_t or_bits = (uint16_t)((spread_value << 1) | (spread_value >> 1) | (output_ << 15)); output_ = spread_value | ((~or_bits) & 0xaaaa); - static_cast(this)->output_short(output_); + output_short(output_); } void add_index_address_mark() { - static_cast(this)->output_short(output_ = MFMIndexAddressMark); + output_short(output_ = MFMIndexAddressMark); add_byte(MFMIndexAddressByte); } void add_ID_address_mark() { - static_cast(this)->output_short(output_ = MFMAddressMark); + output_short(output_ = MFMAddressMark); add_byte(MFMIDAddressByte); } void add_data_address_mark() { - static_cast(this)->output_short(output_ = MFMAddressMark); + output_short(output_ = MFMAddressMark); add_byte(MFMDataAddressByte); } void add_deleted_data_address_mark() { - static_cast(this)->output_short(output_ = MFMAddressMark); + output_short(output_ = MFMAddressMark); add_byte(MFMDeletedDataAddressByte); } @@ -72,11 +58,13 @@ template class MFMShifter: public Shifter { uint16_t output_; }; -template class FMShifter: public Shifter { +class FMEncoder: public Encoder { // encodes each 16-bit part as clock, data, clock, data [...] public: + FMEncoder(std::vector &target) : Encoder(target) {} + void add_byte(uint8_t input) { - static_cast(this)->output_short( + output_short( (uint16_t)( ((input & 0x01) << 0) | ((input & 0x02) << 1) | @@ -90,10 +78,10 @@ template class FMShifter: public Shifter { )); } - void add_index_address_mark() { static_cast(this)->output_short(FMIndexAddressMark); } - void add_ID_address_mark() { static_cast(this)->output_short(FMIDAddressMark); } - void add_data_address_mark() { static_cast(this)->output_short(FMDataAddressMark); } - void add_deleted_data_address_mark() { static_cast(this)->output_short(FMDeletedDataAddressMark); } + void add_index_address_mark() { output_short(FMIndexAddressMark); } + void add_ID_address_mark() { output_short(FMIDAddressMark); } + void add_data_address_mark() { output_short(FMDataAddressMark); } + void add_deleted_data_address_mark() { output_short(FMDeletedDataAddressMark); } }; static uint8_t logarithmic_size_for_size(size_t size) @@ -118,7 +106,9 @@ template std::shared_ptr size_t inter_sector_gap, size_t expected_track_bytes) { - T shifter; + Storage::Disk::PCMSegment segment; + segment.data.reserve(expected_track_bytes); + T shifter(segment.data); NumberTheory::CRC16 crc_generator(0x1021, 0xffff); // output the index mark @@ -174,26 +164,25 @@ template std::shared_ptr for(int c = 0; c < inter_sector_gap; c++) shifter.add_byte(0x4e); } - while(shifter.segment.data.size() < expected_track_bytes) shifter.add_byte(0x00); + while(segment.data.size() < expected_track_bytes) shifter.add_byte(0x00); - shifter.segment.number_of_bits = (unsigned int)(shifter.segment.data.size() * 8); - return std::shared_ptr(new Storage::Disk::PCMTrack(std::move(shifter.segment))); + segment.number_of_bits = (unsigned int)(segment.data.size() * 8); + return std::shared_ptr(new Storage::Disk::PCMTrack(std::move(segment))); } -struct VectorReceiver { - void output_short(uint16_t value) { - segment.data.push_back(value >> 8); - segment.data.push_back(value & 0xff); - } - Storage::Disk::PCMSegment segment; -}; +Encoder::Encoder(std::vector &target) : + target_(target) +{} + +void Encoder::output_short(uint16_t value) +{ + target_.push_back(value >> 8); + target_.push_back(value & 0xff); +} std::shared_ptr Storage::Encodings::MFM::GetFMTrackWithSectors(const std::vector §ors) { - struct VectorShifter: public FMShifter, VectorReceiver { - using VectorReceiver::output_short; - }; - return GetTrackWithSectors( + return GetTrackWithSectors( sectors, 16, 0x00, 6, 0, @@ -204,10 +193,7 @@ std::shared_ptr Storage::Encodings::MFM::GetFMTrackWithSec std::shared_ptr Storage::Encodings::MFM::GetMFMTrackWithSectors(const std::vector §ors) { - struct VectorShifter: public MFMShifter, VectorReceiver { - using VectorReceiver::output_short; - }; - return GetTrackWithSectors( + return GetTrackWithSectors( sectors, 50, 0x4e, 12, 22, @@ -215,3 +201,13 @@ std::shared_ptr Storage::Encodings::MFM::GetMFMTrackWithSe 32, 12500); // unintelligently: double the single-density bytes/rotation (or: 500kps @ 300 rpm) } + +std::unique_ptr Storage::Encodings::MFM::GetMFMEncoder(std::vector &target) +{ + return std::unique_ptr(new MFMEncoder(target)); +} + +std::unique_ptr Storage::Encodings::MFM::GetFMEncoder(std::vector &target) +{ + return std::unique_ptr(new FMEncoder(target)); +} diff --git a/Storage/Disk/Encodings/MFM.hpp b/Storage/Disk/Encodings/MFM.hpp index affb2fb78..57e4b11da 100644 --- a/Storage/Disk/Encodings/MFM.hpp +++ b/Storage/Disk/Encodings/MFM.hpp @@ -29,7 +29,6 @@ const uint8_t MFMIDAddressByte = 0xfe; const uint8_t MFMDataAddressByte = 0xfb; const uint8_t MFMDeletedDataAddressByte = 0xf8; - struct Sector { uint8_t track, side, sector; std::vector data; @@ -38,6 +37,25 @@ struct Sector { std::shared_ptr GetMFMTrackWithSectors(const std::vector §ors); std::shared_ptr GetFMTrackWithSectors(const std::vector §ors); +class Encoder { + public: + Encoder(std::vector &target); + virtual void add_byte(uint8_t input) = 0; + virtual void add_index_address_mark() = 0; + virtual void add_ID_address_mark() = 0; + virtual void add_data_address_mark() = 0; + virtual void add_deleted_data_address_mark() = 0; + + protected: + void output_short(uint16_t value); + + private: + std::vector &target_; +}; + +std::unique_ptr GetMFMEncoder(std::vector &target); +std::unique_ptr GetFMEncoder(std::vector &target); + } } } From 2f86b07cfa2535c2e527f4a0d6b6577a9a5f1cc7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 13:40:10 +0800 Subject: [PATCH 25/40] Added a parser for Oric-format MFM disks. Causing my first disk to load! --- Storage/Disk/Formats/OricMFMDSK.cpp | 61 +++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/Storage/Disk/Formats/OricMFMDSK.cpp b/Storage/Disk/Formats/OricMFMDSK.cpp index c522e092f..59b4b2b10 100644 --- a/Storage/Disk/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/Formats/OricMFMDSK.cpp @@ -8,6 +8,7 @@ #include "OricMFMDSK.hpp" #include "../PCMTrack.hpp" +#include "../Encodings/MFM.hpp" using namespace Storage::Disk; @@ -37,26 +38,64 @@ unsigned int OricMFMDSK::get_head_count() std::shared_ptr OricMFMDSK::get_track_at_position(unsigned int head, unsigned int position) { - long offset = 0; + long seek_offset = 0; switch(geometry_type_) { case 1: - offset = (head * track_count_) + position; + seek_offset = (head * track_count_) + position; break; case 2: - offset = (position * track_count_ * head_count_) + head; + seek_offset = (position * track_count_ * head_count_) + head; break; } - fseek(file_, (offset * 6400) + 256, SEEK_SET); - - // TODO: upon review, the file format actually seems to omit clock bits. So it's not an MFM capture. - // A consumer must contextually guess when an FB, FC, etc is meant to be a control mark. So turfing - // the data over directly as below isn't correct. + fseek(file_, (seek_offset * 6400) + 256, SEEK_SET); PCMSegment segment; - segment.number_of_bits = 6250*8; - segment.data.resize(6250); - fread(segment.data.data(), 1, 6250, file_); + + // The file format omits clock bits. So it's not a genuine MFM capture. + // A consumer must contextually guess when an FB, FC, etc is meant to be a control mark. + size_t track_offset = 0; + uint8_t last_header[6]; + std::unique_ptr encoder = Encodings::MFM::GetMFMEncoder(segment.data); + while(track_offset < 6250) + { + uint8_t next_byte = (uint8_t)fgetc(file_); + track_offset++; + + switch(next_byte) + { + default: + encoder->add_byte(next_byte); + break; + + case 0xfe: // an ID synchronisation + { + encoder->add_ID_address_mark(); + + for(int byte = 0; byte < 6; byte++) + { + last_header[byte] = (uint8_t)fgetc(file_); + encoder->add_byte(last_header[byte]); + track_offset++; + if(track_offset == 6250) break; + } + } + break; + + case 0xfb: // a data synchronisation + encoder->add_data_address_mark(); + + for(int byte = 0; byte < (128 << last_header[3]) + 2; byte++) + { + encoder->add_byte((uint8_t)fgetc(file_)); + track_offset++; + if(track_offset == 6250) break; + } + break; + } + } + + segment.number_of_bits = (unsigned int)(segment.data.size() * 8); std::shared_ptr track(new PCMTrack(segment)); return track; From 5c8ecd3051a190a571b3e3999b2194b3a1608661 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 14:27:06 +0800 Subject: [PATCH 26/40] It probably needs a better name, but hastily implemented track caching at the Disk level. --- Storage/Disk/Disk.cpp | 13 +++++++++++++ Storage/Disk/Disk.hpp | 9 ++++++++- Storage/Disk/Formats/AcornADF.cpp | 2 +- Storage/Disk/Formats/AcornADF.hpp | 3 ++- Storage/Disk/Formats/D64.cpp | 2 +- Storage/Disk/Formats/D64.hpp | 2 +- Storage/Disk/Formats/G64.cpp | 2 +- Storage/Disk/Formats/G64.hpp | 2 +- Storage/Disk/Formats/OricMFMDSK.cpp | 2 +- Storage/Disk/Formats/OricMFMDSK.hpp | 2 +- Storage/Disk/Formats/SSD.cpp | 2 +- Storage/Disk/Formats/SSD.hpp | 2 +- 12 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Storage/Disk/Disk.cpp b/Storage/Disk/Disk.cpp index f431bba4d..aee00e39d 100644 --- a/Storage/Disk/Disk.cpp +++ b/Storage/Disk/Disk.cpp @@ -7,3 +7,16 @@ // #include "Disk.hpp" + +using namespace Storage::Disk; + +std::shared_ptr Disk::get_track_at_position(unsigned int head, unsigned int position) +{ + int address = (int)(position * get_head_count() + head); + std::map>::iterator cached_track = cached_tracks_.find(address); + if(cached_track != cached_tracks_.end()) return cached_track->second; + + std::shared_ptr track = virtual_get_track_at_position(head, position); + cached_tracks_[address] = track; + return track; +} diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp index 50466161e..2f974c2fb 100644 --- a/Storage/Disk/Disk.hpp +++ b/Storage/Disk/Disk.hpp @@ -10,6 +10,7 @@ #define Disk_hpp #include +#include #include "../Storage.hpp" namespace Storage { @@ -81,7 +82,13 @@ class Disk { /*! Returns the @c Track at @c position if there are any detectable events there; returns @c nullptr otherwise. */ - virtual std::shared_ptr get_track_at_position(unsigned int head, unsigned int position) = 0; + std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); + + protected: + virtual std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position) = 0; + + private: + std::map> cached_tracks_; }; } diff --git a/Storage/Disk/Formats/AcornADF.cpp b/Storage/Disk/Formats/AcornADF.cpp index 98779de80..b0ca1144a 100644 --- a/Storage/Disk/Formats/AcornADF.cpp +++ b/Storage/Disk/Formats/AcornADF.cpp @@ -47,7 +47,7 @@ unsigned int AcornADF::get_head_count() return 1; } -std::shared_ptr AcornADF::get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr AcornADF::virtual_get_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr track; diff --git a/Storage/Disk/Formats/AcornADF.hpp b/Storage/Disk/Formats/AcornADF.hpp index 17455e007..ccd2ea200 100644 --- a/Storage/Disk/Formats/AcornADF.hpp +++ b/Storage/Disk/Formats/AcornADF.hpp @@ -35,7 +35,8 @@ class AcornADF: public Disk, public Storage::FileHolder { // implemented to satisfy @c Disk unsigned int get_head_position_count(); unsigned int get_head_count(); - std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); + private: + std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); }; } diff --git a/Storage/Disk/Formats/D64.cpp b/Storage/Disk/Formats/D64.cpp index 50f54257b..75277d986 100644 --- a/Storage/Disk/Formats/D64.cpp +++ b/Storage/Disk/Formats/D64.cpp @@ -41,7 +41,7 @@ unsigned int D64::get_head_position_count() return number_of_tracks_*2; } -std::shared_ptr D64::get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr D64::virtual_get_track_at_position(unsigned int head, unsigned int position) { // every other track is missing, as is any head above 0 if(position&1 || head) diff --git a/Storage/Disk/Formats/D64.hpp b/Storage/Disk/Formats/D64.hpp index 83621faf1..afe0a16d8 100644 --- a/Storage/Disk/Formats/D64.hpp +++ b/Storage/Disk/Formats/D64.hpp @@ -34,9 +34,9 @@ class D64: public Disk, public Storage::FileHolder { // implemented to satisfy @c Disk unsigned int get_head_position_count(); - std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: + std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); unsigned int number_of_tracks_; uint16_t disk_id_; }; diff --git a/Storage/Disk/Formats/G64.cpp b/Storage/Disk/Formats/G64.cpp index f20598813..ddc3bf791 100644 --- a/Storage/Disk/Formats/G64.cpp +++ b/Storage/Disk/Formats/G64.cpp @@ -40,7 +40,7 @@ unsigned int G64::get_head_position_count() return number_of_tracks_ > 84 ? number_of_tracks_ : 84; } -std::shared_ptr G64::get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr G64::virtual_get_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr resulting_track; diff --git a/Storage/Disk/Formats/G64.hpp b/Storage/Disk/Formats/G64.hpp index 31ca5ca60..34ec84c13 100644 --- a/Storage/Disk/Formats/G64.hpp +++ b/Storage/Disk/Formats/G64.hpp @@ -37,9 +37,9 @@ class G64: public Disk, public Storage::FileHolder { // implemented to satisfy @c Disk unsigned int get_head_position_count(); - std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: + std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); uint8_t number_of_tracks_; uint16_t maximum_track_size_; }; diff --git a/Storage/Disk/Formats/OricMFMDSK.cpp b/Storage/Disk/Formats/OricMFMDSK.cpp index 59b4b2b10..a581985da 100644 --- a/Storage/Disk/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/Formats/OricMFMDSK.cpp @@ -36,7 +36,7 @@ unsigned int OricMFMDSK::get_head_count() return head_count_; } -std::shared_ptr OricMFMDSK::get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr OricMFMDSK::virtual_get_track_at_position(unsigned int head, unsigned int position) { long seek_offset = 0; switch(geometry_type_) diff --git a/Storage/Disk/Formats/OricMFMDSK.hpp b/Storage/Disk/Formats/OricMFMDSK.hpp index c87bd4d89..1f02ba36d 100644 --- a/Storage/Disk/Formats/OricMFMDSK.hpp +++ b/Storage/Disk/Formats/OricMFMDSK.hpp @@ -35,9 +35,9 @@ class OricMFMDSK: public Disk, public Storage::FileHolder { // implemented to satisfy @c Disk unsigned int get_head_position_count(); unsigned int get_head_count(); - std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: + std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); uint32_t head_count_; uint32_t track_count_; uint32_t geometry_type_; diff --git a/Storage/Disk/Formats/SSD.cpp b/Storage/Disk/Formats/SSD.cpp index aaa6e467a..07ddf242e 100644 --- a/Storage/Disk/Formats/SSD.cpp +++ b/Storage/Disk/Formats/SSD.cpp @@ -40,7 +40,7 @@ unsigned int SSD::get_head_count() return head_count_; } -std::shared_ptr SSD::get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr SSD::virtual_get_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr track; diff --git a/Storage/Disk/Formats/SSD.hpp b/Storage/Disk/Formats/SSD.hpp index 074f57af0..7d8ccf0df 100644 --- a/Storage/Disk/Formats/SSD.hpp +++ b/Storage/Disk/Formats/SSD.hpp @@ -35,9 +35,9 @@ class SSD: public Disk, public Storage::FileHolder { // implemented to satisfy @c Disk unsigned int get_head_position_count(); unsigned int get_head_count(); - std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); private: + std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); unsigned int head_count_; unsigned int track_count_; }; From d8ecc52de8edc0fc2e75499c980aa8104b3a2e94 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 22:27:20 +0800 Subject: [PATCH 27/40] Temporarily disabled spin-down as harmful to the status register if following anything other than a Type 1 command. --- Components/1770/1770.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 1939aa93a..83bec4d2f 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -196,11 +196,11 @@ void WD1770::process_index_hole() } // motor power-down - if(index_hole_count_ == 9 && !(status_&Flag::Busy)) - { - status_ &= ~Flag::MotorOn; - set_motor_on(false); - } +// if(index_hole_count_ == 9 && !(status_&Flag::Busy)) +// { +// status_ &= ~Flag::MotorOn; +// set_motor_on(false); +// } } // +------+----------+-------------------------+ @@ -266,6 +266,8 @@ void WD1770::posit_event(Event new_event_type) // WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? printf("Starting %02x\n", command_); status_ |= Flag::Busy; + if(command_ == 0x8c) + printf("."); if(!(command_ & 0x80)) goto begin_type_1; if(!(command_ & 0x40)) goto begin_type_2; goto begin_type_3; From 2f459690d4b0fe2eeb65e204cdb08250031643e4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 23:29:30 +0800 Subject: [PATCH 28/40] It would appear the 1770 and 1773 actually differ in relation to the (non-sensical) ability not to spin-up for a Type 2, and whether a side compare can occur. So the WD1770 class now requires a personality to be specified. Which it singly fails to honour. --- Components/1770/1770.cpp | 5 +++-- Components/1770/1770.hpp | 8 +++++++- Machines/Electron/Plus3.cpp | 2 ++ Machines/Electron/Plus3.hpp | 2 ++ Machines/Oric/Microdisc.cpp | 3 ++- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 83bec4d2f..a7d8c0efb 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -11,7 +11,7 @@ using namespace WD; -WD1770::WD1770() : +WD1770::WD1770(Personality p) : Storage::Disk::Controller(8000000, 16, 300), status_(0), interesting_event_mask_(Event::Command), @@ -22,7 +22,8 @@ WD1770::WD1770() : is_reading_data_(false), interrupt_request_line_(false), data_request_line_(false), - delegate_(nullptr) + delegate_(nullptr), + personality_(p) { set_is_double_density(false); posit_event(Event::Command); diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index 4272d14af..cc681b2f0 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -15,7 +15,11 @@ namespace WD { class WD1770: public Storage::Disk::Controller { public: - WD1770(); + enum Personality { + P1770, + P1773 + }; + WD1770(Personality p); void set_is_double_density(bool is_double_density); void set_register(int address, uint8_t value); @@ -48,6 +52,8 @@ class WD1770: public Storage::Disk::Controller { inline void set_delegate(Delegate *delegate) { delegate_ = delegate; } private: + Personality personality_; + uint8_t status_; uint8_t track_; uint8_t sector_; diff --git a/Machines/Electron/Plus3.cpp b/Machines/Electron/Plus3.cpp index 4c674e797..52035dd3d 100644 --- a/Machines/Electron/Plus3.cpp +++ b/Machines/Electron/Plus3.cpp @@ -10,6 +10,8 @@ using namespace Electron; +Plus3::Plus3() : WD1770(P1770) {} + void Plus3::set_disk(std::shared_ptr disk, int drive) { if(!drives_[drive]) diff --git a/Machines/Electron/Plus3.hpp b/Machines/Electron/Plus3.hpp index d0e36a15c..cd04b3877 100644 --- a/Machines/Electron/Plus3.hpp +++ b/Machines/Electron/Plus3.hpp @@ -15,6 +15,8 @@ namespace Electron { class Plus3 : public WD::WD1770 { public: + Plus3(); + void set_disk(std::shared_ptr disk, int drive); void set_control_register(uint8_t control); diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 2aa5f7690..ded159fa2 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -13,7 +13,8 @@ using namespace Oric; Microdisc::Microdisc() : irq_enable_(false), delegate_(nullptr), - paging_flags_(BASICDisable) + paging_flags_(BASICDisable), + WD1770(P1773) {} void Microdisc::set_disk(std::shared_ptr disk, int drive) From f44542c18c6d0d91814137baf7396e7b52ff6b93 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Nov 2016 23:35:11 +0800 Subject: [PATCH 29/40] Improved naming: this now explains what, not the mechanics of how. --- Storage/Disk/Disk.cpp | 2 +- Storage/Disk/Disk.hpp | 16 +++++++++++----- Storage/Disk/Formats/AcornADF.cpp | 2 +- Storage/Disk/Formats/AcornADF.hpp | 2 +- Storage/Disk/Formats/D64.cpp | 2 +- Storage/Disk/Formats/D64.hpp | 2 +- Storage/Disk/Formats/G64.cpp | 2 +- Storage/Disk/Formats/G64.hpp | 2 +- Storage/Disk/Formats/OricMFMDSK.cpp | 2 +- Storage/Disk/Formats/OricMFMDSK.hpp | 2 +- Storage/Disk/Formats/SSD.cpp | 2 +- Storage/Disk/Formats/SSD.hpp | 2 +- 12 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Storage/Disk/Disk.cpp b/Storage/Disk/Disk.cpp index aee00e39d..b2945ce3a 100644 --- a/Storage/Disk/Disk.cpp +++ b/Storage/Disk/Disk.cpp @@ -16,7 +16,7 @@ std::shared_ptr Disk::get_track_at_position(unsigned int head, unsigned i std::map>::iterator cached_track = cached_tracks_.find(address); if(cached_track != cached_tracks_.end()) return cached_track->second; - std::shared_ptr track = virtual_get_track_at_position(head, position); + std::shared_ptr track = get_uncached_track_at_position(head, position); cached_tracks_[address] = track; return track; } diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp index 2f974c2fb..937e2767c 100644 --- a/Storage/Disk/Disk.hpp +++ b/Storage/Disk/Disk.hpp @@ -67,25 +67,31 @@ class Disk { public: /*! - Returns the number of discrete positions that this disk uses to model its complete surface area. + @returns the number of discrete positions that this disk uses to model its complete surface area. This is not necessarily a track count. There is no implicit guarantee that every position will - return a distinct track, or — if the media is holeless — will return any track at all. + return a distinct track, or — e.g. if the media is holeless — will return any track at all. */ virtual unsigned int get_head_position_count() = 0; /*! - Returns the number of heads (and, therefore, impliedly surfaces) available on this disk. + @returns the number of heads (and, therefore, impliedly surfaces) available on this disk. */ virtual unsigned int get_head_count() { return 1; } /*! - Returns the @c Track at @c position if there are any detectable events there; returns @c nullptr otherwise. + @returns the @c Track at @c position underneath @c head if there are any detectable events there; + returns @c nullptr otherwise. */ std::shared_ptr get_track_at_position(unsigned int head, unsigned int position); protected: - virtual std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position) = 0; + /*! + Subclasses should implement this to return the @c Track at @c position underneath @c head. Returned tracks + are cached internally so subclasses shouldn't attempt to build their own caches or worry about preparing + for track accesses at file load time. Appropriate behaviour is to create them lazily, on demand. + */ + virtual std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position) = 0; private: std::map> cached_tracks_; diff --git a/Storage/Disk/Formats/AcornADF.cpp b/Storage/Disk/Formats/AcornADF.cpp index b0ca1144a..5eb7d7dce 100644 --- a/Storage/Disk/Formats/AcornADF.cpp +++ b/Storage/Disk/Formats/AcornADF.cpp @@ -47,7 +47,7 @@ unsigned int AcornADF::get_head_count() return 1; } -std::shared_ptr AcornADF::virtual_get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr AcornADF::get_uncached_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr track; diff --git a/Storage/Disk/Formats/AcornADF.hpp b/Storage/Disk/Formats/AcornADF.hpp index ccd2ea200..11109d5ea 100644 --- a/Storage/Disk/Formats/AcornADF.hpp +++ b/Storage/Disk/Formats/AcornADF.hpp @@ -36,7 +36,7 @@ class AcornADF: public Disk, public Storage::FileHolder { unsigned int get_head_position_count(); unsigned int get_head_count(); private: - std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); }; } diff --git a/Storage/Disk/Formats/D64.cpp b/Storage/Disk/Formats/D64.cpp index 75277d986..6c991bf89 100644 --- a/Storage/Disk/Formats/D64.cpp +++ b/Storage/Disk/Formats/D64.cpp @@ -41,7 +41,7 @@ unsigned int D64::get_head_position_count() return number_of_tracks_*2; } -std::shared_ptr D64::virtual_get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr D64::get_uncached_track_at_position(unsigned int head, unsigned int position) { // every other track is missing, as is any head above 0 if(position&1 || head) diff --git a/Storage/Disk/Formats/D64.hpp b/Storage/Disk/Formats/D64.hpp index afe0a16d8..6280331d9 100644 --- a/Storage/Disk/Formats/D64.hpp +++ b/Storage/Disk/Formats/D64.hpp @@ -36,7 +36,7 @@ class D64: public Disk, public Storage::FileHolder { unsigned int get_head_position_count(); private: - std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); unsigned int number_of_tracks_; uint16_t disk_id_; }; diff --git a/Storage/Disk/Formats/G64.cpp b/Storage/Disk/Formats/G64.cpp index ddc3bf791..68aeb4ed9 100644 --- a/Storage/Disk/Formats/G64.cpp +++ b/Storage/Disk/Formats/G64.cpp @@ -40,7 +40,7 @@ unsigned int G64::get_head_position_count() return number_of_tracks_ > 84 ? number_of_tracks_ : 84; } -std::shared_ptr G64::virtual_get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr G64::get_uncached_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr resulting_track; diff --git a/Storage/Disk/Formats/G64.hpp b/Storage/Disk/Formats/G64.hpp index 34ec84c13..825851f19 100644 --- a/Storage/Disk/Formats/G64.hpp +++ b/Storage/Disk/Formats/G64.hpp @@ -39,7 +39,7 @@ class G64: public Disk, public Storage::FileHolder { unsigned int get_head_position_count(); private: - std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); uint8_t number_of_tracks_; uint16_t maximum_track_size_; }; diff --git a/Storage/Disk/Formats/OricMFMDSK.cpp b/Storage/Disk/Formats/OricMFMDSK.cpp index a581985da..7ab373bd7 100644 --- a/Storage/Disk/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/Formats/OricMFMDSK.cpp @@ -36,7 +36,7 @@ unsigned int OricMFMDSK::get_head_count() return head_count_; } -std::shared_ptr OricMFMDSK::virtual_get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr OricMFMDSK::get_uncached_track_at_position(unsigned int head, unsigned int position) { long seek_offset = 0; switch(geometry_type_) diff --git a/Storage/Disk/Formats/OricMFMDSK.hpp b/Storage/Disk/Formats/OricMFMDSK.hpp index 1f02ba36d..f4d944a4b 100644 --- a/Storage/Disk/Formats/OricMFMDSK.hpp +++ b/Storage/Disk/Formats/OricMFMDSK.hpp @@ -37,7 +37,7 @@ class OricMFMDSK: public Disk, public Storage::FileHolder { unsigned int get_head_count(); private: - std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); uint32_t head_count_; uint32_t track_count_; uint32_t geometry_type_; diff --git a/Storage/Disk/Formats/SSD.cpp b/Storage/Disk/Formats/SSD.cpp index 07ddf242e..af4661dc1 100644 --- a/Storage/Disk/Formats/SSD.cpp +++ b/Storage/Disk/Formats/SSD.cpp @@ -40,7 +40,7 @@ unsigned int SSD::get_head_count() return head_count_; } -std::shared_ptr SSD::virtual_get_track_at_position(unsigned int head, unsigned int position) +std::shared_ptr SSD::get_uncached_track_at_position(unsigned int head, unsigned int position) { std::shared_ptr track; diff --git a/Storage/Disk/Formats/SSD.hpp b/Storage/Disk/Formats/SSD.hpp index 7d8ccf0df..d75475370 100644 --- a/Storage/Disk/Formats/SSD.hpp +++ b/Storage/Disk/Formats/SSD.hpp @@ -37,7 +37,7 @@ class SSD: public Disk, public Storage::FileHolder { unsigned int get_head_count(); private: - std::shared_ptr virtual_get_track_at_position(unsigned int head, unsigned int position); + std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position); unsigned int head_count_; unsigned int track_count_; }; From 2c01f9dbed86f514e1bba30824744106471d7c54 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 27 Nov 2016 08:42:39 +0800 Subject: [PATCH 30/40] Added meaningful TODOs. --- Components/1770/1770.cpp | 2 ++ Components/1770/1770.hpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index a7d8c0efb..f60a12f6c 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -372,6 +372,7 @@ void WD1770::posit_event(Event new_event_type) status_ &= ~(Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType); set_data_request(false); distance_into_section_ = 0; + // TODO: this bit doesn't mean this if the personality is 1773. if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay; // Perform spin up. @@ -401,6 +402,7 @@ void WD1770::posit_event(Event new_event_type) if(distance_into_section_ == 7) { is_reading_data_ = false; + // TODO: check the side too, if this is a 1773 and we've been asked to. if(header_[0] == track_ && header_[2] == sector_) { // TODO: test CRC diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index cc681b2f0..a1b9ea948 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -54,7 +54,8 @@ class WD1770: public Storage::Disk::Controller { private: Personality personality_; - uint8_t status_; + uint8_t status_; // TODO: to ensure correctness, this probably needs either to be a different value per command type, + // or — probably more easily — to be an ordinary struct of flags with the value put together upon request. uint8_t track_; uint8_t sector_; uint8_t data_; From 02ba1f220f2df48585e451f9e5a41496e6697baf Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 27 Nov 2016 21:06:17 +0800 Subject: [PATCH 31/40] The '72 seems to be a '70 with altered timing. So worth differentiating. --- Components/1770/1770.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index a1b9ea948..1a7114de5 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -17,6 +17,7 @@ class WD1770: public Storage::Disk::Controller { public: enum Personality { P1770, + P1772, P1773 }; WD1770(Personality p); From 84cb07613d4af65bfa22c25a505e650d07a91d4e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 27 Nov 2016 20:39:08 -0800 Subject: [PATCH 32/40] Checked some documentation more thoroughly; the 1793 has quite different spin-up (/head load) semantics. So it's another distinct personality. Grrr. --- Components/1770/1770.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index 1a7114de5..cc61f8302 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -16,9 +16,10 @@ namespace WD { class WD1770: public Storage::Disk::Controller { public: enum Personality { - P1770, - P1772, - P1773 + P1770, // implies automatic motor-on management with Type 2 commands offering a spin-up disable + P1772, // as per the 1770, with different stepping rates + P1773, // implements the side number-testing logic of the 1793; omits spin-up/loading logic + P1793 // implies Type 2 commands use side number testing logic; spin-up/loading is by HLD and HLT }; WD1770(Personality p); From 9b6c5e814a9130ec0520e24ce79231411ab1a00d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 28 Nov 2016 16:22:35 -0500 Subject: [PATCH 33/40] Now that it can be more explicit, this should admit that it's '93-based, not '73. --- Machines/Oric/Microdisc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index ded159fa2..564d904e7 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -14,7 +14,7 @@ Microdisc::Microdisc() : irq_enable_(false), delegate_(nullptr), paging_flags_(BASICDisable), - WD1770(P1773) + WD1770(P1793) {} void Microdisc::set_disk(std::shared_ptr disk, int drive) From 2222cb65d6048c9475693e5a535811424abd0270 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 30 Nov 2016 22:26:02 -0500 Subject: [PATCH 34/40] Split the status up into flags, assembled into a register upon demand. Attempted to implement some of the differences between the 1770/1772 and 1773/1793. Albeit with a motor fix still in place. --- Components/1770/1770.cpp | 104 ++++++++++++++++++++++---------- Components/1770/1770.hpp | 17 +++++- Storage/Disk/DiskController.cpp | 5 ++ Storage/Disk/DiskController.hpp | 5 ++ 4 files changed, 98 insertions(+), 33 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index f60a12f6c..6b811c5ab 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -13,7 +13,6 @@ using namespace WD; WD1770::WD1770(Personality p) : Storage::Disk::Controller(8000000, 16, 300), - status_(0), interesting_event_mask_(Event::Command), resume_point_(0), delay_time_(0), @@ -49,6 +48,7 @@ void WD1770::set_register(int address, uint8_t value) if((value&0xf0) == 0xd0) { printf("!!!TODO: force interrupt!!!\n"); + status_.type = Status::One; } else { @@ -67,7 +67,44 @@ uint8_t WD1770::get_register(int address) { switch(address&3) { - default: return status_ | (data_request_line_ ? Flag::DataRequest : 0); + default: + { + uint8_t status = + (status_.write_protect ? Flag::WriteProtect : 0) | + (status_.crc_error ? Flag::CRCError : 0) | + (status_.busy ? Flag::Busy : 0); + switch(status_.type) + { + case Status::One: + status |= + (get_is_track_zero() ? Flag::TrackZero : 0) | + (status_.seek_error ? Flag::SeekError : 0); + // TODO: index hole + break; + + case Status::Two: + case Status::Three: + status |= + (status_.record_type ? Flag::RecordType : 0) | + (status_.lost_data ? Flag::LostData : 0) | + (status_.data_request ? Flag::DataRequest : 0) | + (status_.record_not_found ? Flag::RecordNotFound : 0); + break; + } + + if(is_73()) + { + // TODO: sample ready line for bit 7 + // TODO: report head loaded if reporting a Type 1 status + } + else + { + status |= (get_motor_on() ? Flag::MotorOn : 0); + if(status_.type == Status::One) + status |= (status_.spin_up ? Flag::SpinUp : 0); + } + return status; + } case 1: return track_; case 2: return sector_; case 3: set_data_request(false); return data_; @@ -197,11 +234,10 @@ void WD1770::process_index_hole() } // motor power-down -// if(index_hole_count_ == 9 && !(status_&Flag::Busy)) -// { -// status_ &= ~Flag::MotorOn; -// set_motor_on(false); -// } + if(index_hole_count_ == 9 && !status_.busy && !is_73()) + { + set_motor_on(false); + } } // +------+----------+-------------------------+ @@ -242,11 +278,11 @@ void WD1770::process_index_hole() #define LINE_LABEL INDIRECT_CONCATENATE(label, __LINE__) #define SPIN_UP() \ - status_ |= Flag::MotorOn; \ set_motor_on(true); \ index_hole_count_ = 0; \ index_hole_count_target_ = 6; \ - WAIT_FOR_EVENT(Event::IndexHoleTarget); + WAIT_FOR_EVENT(Event::IndexHoleTarget); \ + status_.spin_up = true; void WD1770::posit_event(Event new_event_type) { @@ -259,16 +295,21 @@ void WD1770::posit_event(Event new_event_type) wait_for_command: printf("Idle...\n"); is_reading_data_ = false; - status_ &= ~Flag::Busy; + status_.busy = false; index_hole_count_ = 0; set_interrupt_request(true); WAIT_FOR_EVENT(Event::Command); set_interrupt_request(false); // WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? printf("Starting %02x\n", command_); - status_ |= Flag::Busy; - if(command_ == 0x8c) - printf("."); + + if(is_73()) + { + // TODO: set HDL, wait for HDT + set_motor_on(true); + } + + status_.busy = true; if(!(command_ & 0x80)) goto begin_type_1; if(!(command_ & 0x40)) goto begin_type_2; goto begin_type_3; @@ -279,13 +320,14 @@ void WD1770::posit_event(Event new_event_type) */ begin_type_1: // Set initial flags, skip spin-up if possible. - status_ &= ~Flag::SeekError; + status_.seek_error = false; + status_.crc_error = false; set_data_request(false); - if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type1_type; + + if((command_&0x08) || get_motor_on() || is_73()) goto test_type1_type; // Perform spin up. SPIN_UP(); - status_ |= Flag::SpinUp; test_type1_type: // Set step direction if this is a step in or out. @@ -318,10 +360,10 @@ void WD1770::posit_event(Event new_event_type) switch(command_ & 3) { default: - case 0: time_to_wait = 6; break; // 2 on a 1772 - case 1: time_to_wait = 12; break; // 3 on a 1772 - case 2: time_to_wait = 20; break; // 5 on a 1772 - case 3: time_to_wait = 30; break; // 6 on a 1772 + case 0: time_to_wait = 6; break; + case 1: time_to_wait = 12; break; + case 2: time_to_wait = (personality_ == P1772) ? 2 : 20; break; + case 3: time_to_wait = (personality_ == P1772) ? 3 : 30; break; } WAIT_FOR_TIME(time_to_wait); if(command_ >> 5) goto verify; @@ -346,7 +388,7 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 6) { - status_ |= Flag::SeekError; + status_.seek_error = true; goto wait_for_command; } if(distance_into_section_ == 7) @@ -356,7 +398,7 @@ void WD1770::posit_event(Event new_event_type) if(header_[0] == track_) { printf("Reached track %d\n", track_); - status_ &= ~Flag::CRCError; + status_.crc_error = false; goto wait_for_command; } @@ -369,11 +411,11 @@ void WD1770::posit_event(Event new_event_type) Type 2 entry point. */ begin_type_2: - status_ &= ~(Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType); + status_.lost_data = status_.record_not_found = status_.write_protect = status_.record_type = false; set_data_request(false); distance_into_section_ = 0; - // TODO: this bit doesn't mean this if the personality is 1773. - if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay; + + if((command_&0x08) || get_motor_on() || is_73()) goto test_type2_delay; // Perform spin up. SPIN_UP(); @@ -386,7 +428,7 @@ void WD1770::posit_event(Event new_event_type) test_type2_write_protection: if(command_&0x20) // TODO:: && is_write_protected { - status_ |= Flag::WriteProtect; + status_.write_protect = true; goto wait_for_command; } @@ -396,14 +438,14 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 5) { - status_ |= Flag::RecordNotFound; + status_.record_not_found = true; goto wait_for_command; } if(distance_into_section_ == 7) { is_reading_data_ = false; - // TODO: check the side too, if this is a 1773 and we've been asked to. - if(header_[0] == track_ && header_[2] == sector_) + if(header_[0] == track_ && header_[2] == sector_ && + (!is_73() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) { // TODO: test CRC goto type2_read_or_write_data; @@ -422,7 +464,7 @@ void WD1770::posit_event(Event new_event_type) // TODO: timeout if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData) { - status_ |= (latest_token_.type == Token::DeletedData) ? Flag::RecordType : 0; + status_.record_type = (latest_token_.type == Token::DeletedData); distance_into_section_ = 0; is_reading_data_ = true; goto type2_read_byte; @@ -432,7 +474,7 @@ void WD1770::posit_event(Event new_event_type) type2_read_byte: WAIT_FOR_EVENT(Event::Token); if(latest_token_.type != Token::Byte) goto type2_read_byte; - if(data_request_line_) status_ |= Flag::LostData; + status_.lost_data |= data_request_line_; data_ = latest_token_.byte_value; set_data_request(true); distance_into_section_++; diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index cc61f8302..c20a965a6 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -55,9 +55,22 @@ class WD1770: public Storage::Disk::Controller { private: Personality personality_; + inline bool is_73() { return (personality_ == P1793 ) || (personality_ == P1773); } - uint8_t status_; // TODO: to ensure correctness, this probably needs either to be a different value per command type, - // or — probably more easily — to be an ordinary struct of flags with the value put together upon request. + struct Status { + bool write_protect; + bool record_type; + bool spin_up; + bool record_not_found; + bool crc_error; + bool seek_error; + bool lost_data; + bool data_request; + bool busy; + enum { + One, Two, Three + } type; + } status_; uint8_t track_; uint8_t sector_; uint8_t data_; diff --git a/Storage/Disk/DiskController.cpp b/Storage/Disk/DiskController.cpp index d8302e605..f9eea6e7a 100644 --- a/Storage/Disk/DiskController.cpp +++ b/Storage/Disk/DiskController.cpp @@ -139,6 +139,11 @@ void Controller::set_motor_on(bool motor_on) _motor_is_on = motor_on; } +bool Controller::get_motor_on() +{ + return _motor_is_on; +} + void Controller::set_drive(std::shared_ptr drive) { _drive = drive; diff --git a/Storage/Disk/DiskController.hpp b/Storage/Disk/DiskController.hpp index b83165c98..e1371e96b 100644 --- a/Storage/Disk/DiskController.hpp +++ b/Storage/Disk/DiskController.hpp @@ -54,6 +54,11 @@ class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop */ void set_motor_on(bool motor_on); + /*! + @returns @c true if the motor is on; @c false otherwise. + */ + bool get_motor_on(); + /*! Should be implemented by subclasses; communicates each bit that the PLL recognises, also specifying the amount of time since the index hole was last seen. From b31fd11470f07246b6edcc1b945802eb81ac48df Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 30 Nov 2016 22:39:55 -0500 Subject: [PATCH 35/40] Fixed reporting of data request line, initial status values. --- Components/1770/1770.cpp | 26 ++++++++++++++++++++++++-- Components/1770/1770.hpp | 3 ++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 6b811c5ab..f3cf10cc5 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -11,6 +11,19 @@ using namespace WD; +WD1770::Status::Status() : + type(Status::One), + write_protect(false), + record_type(false), + spin_up(false), + record_not_found(false), + crc_error(false), + seek_error(false), + lost_data(false), +// data_request(false), + busy(false) +{} + WD1770::WD1770(Personality p) : Storage::Disk::Controller(8000000, 16, 300), interesting_event_mask_(Event::Command), @@ -87,7 +100,7 @@ uint8_t WD1770::get_register(int address) status |= (status_.record_type ? Flag::RecordType : 0) | (status_.lost_data ? Flag::LostData : 0) | - (status_.data_request ? Flag::DataRequest : 0) | + (data_request_line_ ? Flag::DataRequest : 0) | (status_.record_not_found ? Flag::RecordNotFound : 0); break; } @@ -297,10 +310,16 @@ void WD1770::posit_event(Event new_event_type) is_reading_data_ = false; status_.busy = false; index_hole_count_ = 0; + + if(is_73()) + { + // TODO: ??? + set_motor_on(false); + } + set_interrupt_request(true); WAIT_FOR_EVENT(Event::Command); set_interrupt_request(false); -// WAIT_FOR_TIME(1); // TODO: what should the time cost here really be? printf("Starting %02x\n", command_); if(is_73()) @@ -320,6 +339,7 @@ void WD1770::posit_event(Event new_event_type) */ begin_type_1: // Set initial flags, skip spin-up if possible. + status_.type = Status::One; status_.seek_error = false; status_.crc_error = false; set_data_request(false); @@ -411,6 +431,7 @@ void WD1770::posit_event(Event new_event_type) Type 2 entry point. */ begin_type_2: + status_.type = Status::Two; status_.lost_data = status_.record_not_found = status_.write_protect = status_.record_type = false; set_data_request(false); distance_into_section_ = 0; @@ -508,6 +529,7 @@ void WD1770::posit_event(Event new_event_type) printf("!!!TODO: data portion of sector!!!\n"); begin_type_3: + status_.type = Status::Three; printf("!!!TODO: type 3 commands!!!\n"); diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index c20a965a6..c6aa77241 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -58,6 +58,7 @@ class WD1770: public Storage::Disk::Controller { inline bool is_73() { return (personality_ == P1793 ) || (personality_ == P1773); } struct Status { + Status(); bool write_protect; bool record_type; bool spin_up; @@ -65,7 +66,7 @@ class WD1770: public Storage::Disk::Controller { bool crc_error; bool seek_error; bool lost_data; - bool data_request; +// bool data_request; // TODO: pick between this and data_request_line_ bool busy; enum { One, Two, Three From 82899f2f476e8a9a2443410d44faa9c6b7fc5531 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 1 Dec 2016 07:41:52 -0500 Subject: [PATCH 36/40] Ensured flag setting is atomic, removed duplication of interrupt request versus busy, found better names for the personality testers, unified delegate protocol. --- Components/1770/1770.cpp | 119 ++++++++++++++++++++++-------------- Components/1770/1770.hpp | 17 +++--- Machines/Oric/Microdisc.cpp | 2 +- Machines/Oric/Oric.cpp | 7 +-- Machines/Oric/Oric.hpp | 3 +- 5 files changed, 83 insertions(+), 65 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index f3cf10cc5..61e3a67e1 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -1,4 +1,4 @@ - // +// // 1770.cpp // Clock Signal // @@ -20,7 +20,7 @@ WD1770::Status::Status() : crc_error(false), seek_error(false), lost_data(false), -// data_request(false), + data_request(false), busy(false) {} @@ -32,8 +32,6 @@ WD1770::WD1770(Personality p) : index_hole_count_target_(-1), is_awaiting_marker_value_(false), is_reading_data_(false), - interrupt_request_line_(false), - data_request_line_(false), delegate_(nullptr), personality_(p) { @@ -61,7 +59,9 @@ void WD1770::set_register(int address, uint8_t value) if((value&0xf0) == 0xd0) { printf("!!!TODO: force interrupt!!!\n"); - status_.type = Status::One; + update_status([] (Status &status) { + status.type = Status::One; + }); } else { @@ -100,12 +100,12 @@ uint8_t WD1770::get_register(int address) status |= (status_.record_type ? Flag::RecordType : 0) | (status_.lost_data ? Flag::LostData : 0) | - (data_request_line_ ? Flag::DataRequest : 0) | + (status_.data_request ? Flag::DataRequest : 0) | (status_.record_not_found ? Flag::RecordNotFound : 0); break; } - if(is_73()) + if(!has_motor_on_line()) { // TODO: sample ready line for bit 7 // TODO: report head loaded if reporting a Type 1 status @@ -120,7 +120,11 @@ uint8_t WD1770::get_register(int address) } case 1: return track_; case 2: return sector_; - case 3: set_data_request(false); return data_; + case 3: + update_status([] (Status &status) { + status.data_request = false; + }); + return data_; } } @@ -247,7 +251,7 @@ void WD1770::process_index_hole() } // motor power-down - if(index_hole_count_ == 9 && !status_.busy && !is_73()) + if(index_hole_count_ == 9 && !status_.busy && has_motor_on_line()) { set_motor_on(false); } @@ -302,33 +306,39 @@ void WD1770::posit_event(Event new_event_type) if(!(interesting_event_mask_ & (int)new_event_type)) return; interesting_event_mask_ &= ~new_event_type; + Status new_status; BEGIN_SECTION() // Wait for a new command, branch to the appropriate handler. wait_for_command: printf("Idle...\n"); is_reading_data_ = false; - status_.busy = false; index_hole_count_ = 0; - if(is_73()) + if(!has_motor_on_line()) { // TODO: ??? set_motor_on(false); } - set_interrupt_request(true); + update_status([] (Status &status) { + status.busy = false; + }); + WAIT_FOR_EVENT(Event::Command); - set_interrupt_request(false); + + update_status([] (Status &status) { + status.busy = true; + }); + printf("Starting %02x\n", command_); - if(is_73()) + if(!has_motor_on_line()) { // TODO: set HDL, wait for HDT set_motor_on(true); } - status_.busy = true; if(!(command_ & 0x80)) goto begin_type_1; if(!(command_ & 0x40)) goto begin_type_2; goto begin_type_3; @@ -339,12 +349,14 @@ void WD1770::posit_event(Event new_event_type) */ begin_type_1: // Set initial flags, skip spin-up if possible. - status_.type = Status::One; - status_.seek_error = false; - status_.crc_error = false; - set_data_request(false); + update_status([] (Status &status) { + status.type = Status::One; + status.seek_error = false; + status.crc_error = false; + status.data_request = false; + }); - if((command_&0x08) || get_motor_on() || is_73()) goto test_type1_type; + if((command_&0x08) || get_motor_on() || !has_motor_on_line()) goto test_type1_type; // Perform spin up. SPIN_UP(); @@ -408,7 +420,9 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 6) { - status_.seek_error = true; + update_status([] (Status &status) { + status.seek_error = true; + }); goto wait_for_command; } if(distance_into_section_ == 7) @@ -418,7 +432,9 @@ void WD1770::posit_event(Event new_event_type) if(header_[0] == track_) { printf("Reached track %d\n", track_); - status_.crc_error = false; + update_status([] (Status &status) { + status.crc_error = false; + }); goto wait_for_command; } @@ -431,12 +447,17 @@ void WD1770::posit_event(Event new_event_type) Type 2 entry point. */ begin_type_2: - status_.type = Status::Two; - status_.lost_data = status_.record_not_found = status_.write_protect = status_.record_type = false; - set_data_request(false); + update_status([] (Status &status) { + status.type = Status::Two; + status.lost_data = false; + status.record_not_found = false; + status.write_protect = false; + status.record_type = false; + status.data_request = false; + }); distance_into_section_ = 0; - if((command_&0x08) || get_motor_on() || is_73()) goto test_type2_delay; + if((command_&0x08) || get_motor_on() || !has_motor_on_line()) goto test_type2_delay; // Perform spin up. SPIN_UP(); @@ -449,7 +470,9 @@ void WD1770::posit_event(Event new_event_type) test_type2_write_protection: if(command_&0x20) // TODO:: && is_write_protected { - status_.write_protect = true; + update_status([] (Status &status) { + status.write_protect = true; + }); goto wait_for_command; } @@ -459,14 +482,16 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 5) { - status_.record_not_found = true; + update_status([] (Status &status) { + status.record_not_found = true; + }); goto wait_for_command; } if(distance_into_section_ == 7) { is_reading_data_ = false; if(header_[0] == track_ && header_[2] == sector_ && - (!is_73() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) + (has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) { // TODO: test CRC goto type2_read_or_write_data; @@ -485,7 +510,9 @@ void WD1770::posit_event(Event new_event_type) // TODO: timeout if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData) { - status_.record_type = (latest_token_.type == Token::DeletedData); + update_status([this] (Status &status) { + status.record_type = (latest_token_.type == Token::DeletedData); + }); distance_into_section_ = 0; is_reading_data_ = true; goto type2_read_byte; @@ -495,9 +522,11 @@ void WD1770::posit_event(Event new_event_type) type2_read_byte: WAIT_FOR_EVENT(Event::Token); if(latest_token_.type != Token::Byte) goto type2_read_byte; - status_.lost_data |= data_request_line_; data_ = latest_token_.byte_value; - set_data_request(true); + update_status([] (Status &status) { + status.lost_data |= status.data_request; + status.data_request = true; + }); distance_into_section_++; if(distance_into_section_ == 128 << header_[3]) { @@ -529,27 +558,25 @@ void WD1770::posit_event(Event new_event_type) printf("!!!TODO: data portion of sector!!!\n"); begin_type_3: - status_.type = Status::Three; + update_status([] (Status &status) { + status.type = Status::Three; + }); printf("!!!TODO: type 3 commands!!!\n"); END_SECTION() } -void WD1770::set_interrupt_request(bool interrupt_request) +void WD1770::update_status(std::function updater) { - if(interrupt_request_line_ != interrupt_request) + if(delegate_) { - interrupt_request_line_ = interrupt_request; - if(delegate_) delegate_->wd1770_did_change_interrupt_request_status(this); - } -} - -void WD1770::set_data_request(bool data_request) -{ - if(data_request_line_ != data_request) - { - data_request_line_ = data_request; - if(delegate_) delegate_->wd1770_did_change_data_request_status(this); + Status old_status = status_; + updater(status_); + bool did_change = + (status_.busy != old_status.busy) || + (status_.data_request != old_status.data_request); + if(did_change) delegate_->wd1770_did_change_output(this); } + else updater(status_); } diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index c6aa77241..d9e012bf5 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -44,18 +44,18 @@ class WD1770: public Storage::Disk::Controller { Busy = 0x01 }; - inline bool get_interrupt_request_line() { return interrupt_request_line_; } - inline bool get_data_request_line() { return data_request_line_; } + inline bool get_interrupt_request_line() { return !status_.busy; } + inline bool get_data_request_line() { return status_.data_request; } class Delegate { public: - virtual void wd1770_did_change_interrupt_request_status(WD1770 *wd1770) = 0; - virtual void wd1770_did_change_data_request_status(WD1770 *wd1770) = 0; + virtual void wd1770_did_change_output(WD1770 *wd1770) = 0; }; inline void set_delegate(Delegate *delegate) { delegate_ = delegate; } private: Personality personality_; - inline bool is_73() { return (personality_ == P1793 ) || (personality_ == P1773); } + inline bool has_motor_on_line() { return (personality_ != P1793 ) && (personality_ != P1773); } + inline bool has_head_load_line() { return (personality_ == P1793 ); } struct Status { Status(); @@ -66,7 +66,7 @@ class WD1770: public Storage::Disk::Controller { bool crc_error; bool seek_error; bool lost_data; -// bool data_request; // TODO: pick between this and data_request_line_ + bool data_request; bool busy; enum { One, Two, Three @@ -84,8 +84,7 @@ class WD1770: public Storage::Disk::Controller { bool is_awaiting_marker_value_; int step_direction_; - void set_interrupt_request(bool interrupt_request); - void set_data_request(bool interrupt_request); + void update_status(std::function updater); // Tokeniser bool is_reading_data_; @@ -116,8 +115,6 @@ class WD1770: public Storage::Disk::Controller { uint8_t header_[6]; // output line statuses - bool interrupt_request_line_; - bool data_request_line_; Delegate *delegate_; // Storage::Disk::Controller diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 564d904e7..5c74829e4 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -50,7 +50,7 @@ void Microdisc::set_control_register(uint8_t control) bool has_irq = get_interrupt_request_line(); if(has_irq != had_irq && delegate_) { - delegate_->wd1770_did_change_interrupt_request_status(this); + delegate_->wd1770_did_change_output(this); } // b7: EPROM select (0 = select) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index a80dfdb14..724563faa 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -332,16 +332,11 @@ void Machine::microdisc_did_change_paging_flags(class Microdisc *microdisc) } } -void Machine::wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770) +void Machine::wd1770_did_change_output(WD::WD1770 *wd1770) { set_interrupt_line(); } -void Machine::wd1770_did_change_data_request_status(WD::WD1770 *wd1770) -{ - // Don't care. -} - void Machine::set_interrupt_line() { set_irq_line( diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index f5fa246c0..a069d7edc 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -99,8 +99,7 @@ class Machine: // for Microdisc::Delegate void microdisc_did_change_paging_flags(class Microdisc *microdisc); - void wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770); - void wd1770_did_change_data_request_status(WD::WD1770 *wd1770); + void wd1770_did_change_output(WD::WD1770 *wd1770); private: // RAM and ROM From 442986ee2c81f52e3dd1afa6de5a1478e8d628b5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 1 Dec 2016 20:12:22 -0500 Subject: [PATCH 37/40] Introduced a head loading path for 1793 machines. --- Components/1770/1770.cpp | 51 ++++++++++++++++++++++++++++++++++--- Components/1770/1770.hpp | 14 +++++++--- Machines/Oric/Microdisc.cpp | 7 +++++ Machines/Oric/Microdisc.hpp | 1 + 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 61e3a67e1..cdc9bb54a 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -33,7 +33,8 @@ WD1770::WD1770(Personality p) : is_awaiting_marker_value_(false), is_reading_data_(false), delegate_(nullptr), - personality_(p) + personality_(p), + head_is_loaded_(false) { set_is_double_density(false); posit_event(Event::Command); @@ -255,6 +256,12 @@ void WD1770::process_index_hole() { set_motor_on(false); } + + // head unload + if(index_hole_count_ == 15 && !status_.busy && has_head_load_line()) + { + set_head_load_request(false); + } } // +------+----------+-------------------------+ @@ -301,6 +308,7 @@ void WD1770::process_index_hole() WAIT_FOR_EVENT(Event::IndexHoleTarget); \ status_.spin_up = true; + void WD1770::posit_event(Event new_event_type) { if(!(interesting_event_mask_ & (int)new_event_type)) return; @@ -356,9 +364,24 @@ void WD1770::posit_event(Event new_event_type) status.data_request = false; }); - if((command_&0x08) || get_motor_on() || !has_motor_on_line()) goto test_type1_type; + if(!has_motor_on_line() && !has_head_load_line()) goto test_type1_type; - // Perform spin up. + if(has_motor_on_line()) goto begin_type1_spin_up; + goto begin_type1_load_head; + + begin_type1_load_head: + if(!(command_&0x08)) + { + set_head_load_request(false); + goto test_type1_type; + } + set_head_load_request(true); + if(head_is_loaded_) goto test_type1_type; + WAIT_FOR_EVENT(Event::HeadLoaded); + goto test_type1_type; + + begin_type1_spin_up: + if((command_&0x08) || get_motor_on()) goto test_type1_type; SPIN_UP(); test_type1_type: @@ -457,8 +480,20 @@ void WD1770::posit_event(Event new_event_type) }); distance_into_section_ = 0; - if((command_&0x08) || get_motor_on() || !has_motor_on_line()) goto test_type2_delay; + if((command_&0x08) && has_motor_on_line()) goto test_type2_delay; + if(!has_motor_on_line() && !has_head_load_line()) goto test_type2_delay; + if(has_motor_on_line()) goto begin_type2_spin_up; + goto begin_type2_load_head; + + begin_type2_load_head: + set_head_load_request(true); + if(head_is_loaded_) goto test_type2_delay; + WAIT_FOR_EVENT(Event::HeadLoaded); + goto test_type2_delay; + + begin_type2_spin_up: + if(get_motor_on()) goto test_type2_delay; // Perform spin up. SPIN_UP(); @@ -580,3 +615,11 @@ void WD1770::update_status(std::function updater) } else updater(status_); } + +void WD1770::set_head_load_request(bool head_load) {} + +void WD1770::set_head_loaded(bool head_loaded) +{ + head_is_loaded_ = head_loaded; + if(head_loaded) posit_event(Event::HeadLoaded); +} diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index d9e012bf5..3ad6c72a2 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -52,6 +52,10 @@ class WD1770: public Storage::Disk::Controller { }; inline void set_delegate(Delegate *delegate) { delegate_ = delegate; } + protected: + virtual void set_head_load_request(bool head_load); + void set_head_loaded(bool head_loaded); + private: Personality personality_; inline bool has_motor_on_line() { return (personality_ != P1793 ) && (personality_ != P1773); } @@ -102,9 +106,10 @@ class WD1770: public Storage::Disk::Controller { Command = (1 << 0), // Indicates receipt of a new command. Token = (1 << 1), // Indicates recognition of a new token in the flux stream. Interrogate latest_token_ for details. IndexHole = (1 << 2), // Indicates the passing of a physical index hole. + HeadLoaded = (1 << 3), // Indicates the head has been loaded (1973 only). - Timer = (1 << 3), // Indicates that the delay_time_-powered timer has timed out. - IndexHoleTarget = (1 << 4) // Indicates that index_hole_count_ has reached index_hole_count_target_. + Timer = (1 << 4), // Indicates that the delay_time_-powered timer has timed out. + IndexHoleTarget = (1 << 5) // Indicates that index_hole_count_ has reached index_hole_count_target_. }; void posit_event(Event type); int interesting_event_mask_; @@ -114,7 +119,10 @@ class WD1770: public Storage::Disk::Controller { // ID buffer uint8_t header_[6]; - // output line statuses + // 1793 head-loading logic + bool head_is_loaded_; + + // delegate Delegate *delegate_; // Storage::Disk::Controller diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 5c74829e4..5ea84f3c7 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -77,3 +77,10 @@ uint8_t Microdisc::get_data_request_register() { return 0x7f | (get_data_request_line() ? 0x00 : 0x80); } + +void Microdisc::set_head_load_request(bool head_load) +{ + set_motor_on(head_load); + // TODO: delay + set_head_loaded(head_load); +} diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index 12533d3ff..4b460c215 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -37,6 +37,7 @@ class Microdisc: public WD::WD1770 { inline int get_paging_flags() { return paging_flags_; } private: + void set_head_load_request(bool head_load); std::shared_ptr drives_[4]; int selected_drive_; bool irq_enable_; From 0a0775c3bd435fab929526fbcf3cc9bbdf7dd8ff Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 1 Dec 2016 20:16:11 -0500 Subject: [PATCH 38/40] Removed earlier hacky solution. --- Components/1770/1770.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index cdc9bb54a..65491fcff 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -323,12 +323,6 @@ void WD1770::posit_event(Event new_event_type) is_reading_data_ = false; index_hole_count_ = 0; - if(!has_motor_on_line()) - { - // TODO: ??? - set_motor_on(false); - } - update_status([] (Status &status) { status.busy = false; }); @@ -341,12 +335,6 @@ void WD1770::posit_event(Event new_event_type) printf("Starting %02x\n", command_); - if(!has_motor_on_line()) - { - // TODO: set HDL, wait for HDT - set_motor_on(true); - } - if(!(command_ & 0x80)) goto begin_type_1; if(!(command_ & 0x40)) goto begin_type_2; goto begin_type_3; From 93c573bfa9efdc73d79202c22c485ac75ba8a560 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 1 Dec 2016 21:13:16 -0500 Subject: [PATCH 39/40] Implemented missing status bits (other than the index hole), and a head loading delay for the Microdisc. --- Components/1770/1770.cpp | 11 ++++++----- Components/1770/1770.hpp | 4 +++- Machines/Oric/Microdisc.cpp | 31 +++++++++++++++++++++++++++++-- Machines/Oric/Microdisc.hpp | 4 ++++ Storage/Disk/DiskController.cpp | 6 ++++++ Storage/Disk/DiskController.hpp | 1 + 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 65491fcff..609984826 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -108,8 +108,9 @@ uint8_t WD1770::get_register(int address) if(!has_motor_on_line()) { - // TODO: sample ready line for bit 7 - // TODO: report head loaded if reporting a Type 1 status + status |= get_drive_is_ready() ? 0 : Flag::NotReady; + if(status_.type == Status::One) + status |= (head_is_loaded_ ? Flag::HeadLoaded : 0); } else { @@ -365,7 +366,7 @@ void WD1770::posit_event(Event new_event_type) } set_head_load_request(true); if(head_is_loaded_) goto test_type1_type; - WAIT_FOR_EVENT(Event::HeadLoaded); + WAIT_FOR_EVENT(Event::HeadLoad); goto test_type1_type; begin_type1_spin_up: @@ -477,7 +478,7 @@ void WD1770::posit_event(Event new_event_type) begin_type2_load_head: set_head_load_request(true); if(head_is_loaded_) goto test_type2_delay; - WAIT_FOR_EVENT(Event::HeadLoaded); + WAIT_FOR_EVENT(Event::HeadLoad); goto test_type2_delay; begin_type2_spin_up: @@ -609,5 +610,5 @@ void WD1770::set_head_load_request(bool head_load) {} void WD1770::set_head_loaded(bool head_loaded) { head_is_loaded_ = head_loaded; - if(head_loaded) posit_event(Event::HeadLoaded); + if(head_loaded) posit_event(Event::HeadLoad); } diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index 3ad6c72a2..86bf87f7c 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -30,10 +30,12 @@ class WD1770: public Storage::Disk::Controller { void run_for_cycles(unsigned int number_of_cycles); enum Flag: uint8_t { + NotReady = 0x80, MotorOn = 0x80, WriteProtect = 0x40, RecordType = 0x20, SpinUp = 0x20, + HeadLoaded = 0x20, RecordNotFound = 0x10, SeekError = 0x10, CRCError = 0x08, @@ -106,7 +108,7 @@ class WD1770: public Storage::Disk::Controller { Command = (1 << 0), // Indicates receipt of a new command. Token = (1 << 1), // Indicates recognition of a new token in the flux stream. Interrogate latest_token_ for details. IndexHole = (1 << 2), // Indicates the passing of a physical index hole. - HeadLoaded = (1 << 3), // Indicates the head has been loaded (1973 only). + HeadLoad = (1 << 3), // Indicates the head has been loaded (1973 only). Timer = (1 << 4), // Indicates that the delay_time_-powered timer has timed out. IndexHoleTarget = (1 << 5) // Indicates that index_hole_count_ has reached index_hole_count_target_. diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 5ea84f3c7..8b32f6cca 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -10,10 +10,15 @@ using namespace Oric; +namespace { + const int head_load_request_counter_target = 7653333; +} + Microdisc::Microdisc() : irq_enable_(false), delegate_(nullptr), paging_flags_(BASICDisable), + head_load_request_counter_(-1), WD1770(P1793) {} @@ -81,6 +86,28 @@ uint8_t Microdisc::get_data_request_register() void Microdisc::set_head_load_request(bool head_load) { set_motor_on(head_load); - // TODO: delay - set_head_loaded(head_load); + if(head_load) + { + head_load_request_counter_ = 0; + } + else + { + head_load_request_counter_ = head_load_request_counter_target; + set_head_loaded(head_load); + } +} + +void Microdisc::run_for_cycles(unsigned int number_of_cycles) +{ + if(head_load_request_counter_ < head_load_request_counter_target) + { + head_load_request_counter_ += number_of_cycles; + if(head_load_request_counter_ >= head_load_request_counter_target) set_head_loaded(true); + } + WD::WD1770::run_for_cycles(number_of_cycles); +} + +bool Microdisc::get_drive_is_ready() +{ + return true; } diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index 4b460c215..521ab2e7e 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -24,6 +24,8 @@ class Microdisc: public WD::WD1770 { bool get_interrupt_request_line(); + void run_for_cycles(unsigned int number_of_cycles); + enum PagingFlags { BASICDisable = (1 << 0), MicrodscDisable = (1 << 1) @@ -38,10 +40,12 @@ class Microdisc: public WD::WD1770 { private: void set_head_load_request(bool head_load); + bool get_drive_is_ready(); std::shared_ptr drives_[4]; int selected_drive_; bool irq_enable_; int paging_flags_; + int head_load_request_counter_; Delegate *delegate_; }; diff --git a/Storage/Disk/DiskController.cpp b/Storage/Disk/DiskController.cpp index f9eea6e7a..896bd4579 100644 --- a/Storage/Disk/DiskController.cpp +++ b/Storage/Disk/DiskController.cpp @@ -128,6 +128,12 @@ bool Controller::get_is_track_zero() return _drive->get_is_track_zero(); } +bool Controller::get_drive_is_ready() +{ + if(!_drive) return false; + return _drive->has_disk(); +} + void Controller::step(int direction) { if(_drive) _drive->step(direction); diff --git a/Storage/Disk/DiskController.hpp b/Storage/Disk/DiskController.hpp index e1371e96b..67779c7e9 100644 --- a/Storage/Disk/DiskController.hpp +++ b/Storage/Disk/DiskController.hpp @@ -78,6 +78,7 @@ class Controller: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop bool get_is_track_zero(); void step(int direction); + virtual bool get_drive_is_ready(); private: Time _bit_length; From 81ee83453012d66fc67edca630d4516bab9a9c87 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 2 Dec 2016 18:36:47 -0500 Subject: [PATCH 40/40] As well as a bunch of logging, reinstated rotation position preservation across tracks. --- Components/1770/1770.cpp | 1 + Machines/Oric/Microdisc.cpp | 17 ++++++++++++++++- Storage/Disk/DiskController.cpp | 11 ++++------- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 609984826..024f3de7b 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -506,6 +506,7 @@ void WD1770::posit_event(Event new_event_type) if(index_hole_count_ == 5) { + printf("Failed to find sector %d\n", sector_); update_status([] (Status &status) { status.record_not_found = true; }); diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index 8b32f6cca..61d092662 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -11,6 +11,10 @@ using namespace Oric; namespace { + // The number below, in cycles against an 8Mhz clock, was arrived at fairly unscientifically, + // by comparing the amount of time this emulator took to show a directory versus a video of + // a real Oric. It therefore assumes all other timing measurements were correct on the day + // of the test. More work to do, I think. const int head_load_request_counter_target = 7653333; } @@ -34,6 +38,16 @@ void Microdisc::set_disk(std::shared_ptr disk, int drive) void Microdisc::set_control_register(uint8_t control) { + printf("control: %d%d%d%d%d%d%d%d\n", + (control >> 7)&1, + (control >> 6)&1, + (control >> 5)&1, + (control >> 4)&1, + (control >> 3)&1, + (control >> 2)&1, + (control >> 1)&1, + (control >> 0)&1); + // b2: data separator clock rate select (1 = double) [TODO] // b65: drive select @@ -41,9 +55,10 @@ void Microdisc::set_control_register(uint8_t control) set_drive(drives_[selected_drive_]); // b4: side select + unsigned int head = (control & 0x10) ? 1 : 0; for(int c = 0; c < 4; c++) { - if(drives_[c]) drives_[c]->set_head((control & 0x10) ? 1 : 0); + if(drives_[c]) drives_[c]->set_head(head); } // b3: double density select (0 = double) diff --git a/Storage/Disk/DiskController.cpp b/Storage/Disk/DiskController.cpp index 896bd4579..48fea4305 100644 --- a/Storage/Disk/DiskController.cpp +++ b/Storage/Disk/DiskController.cpp @@ -25,13 +25,11 @@ Controller::Controller(unsigned int clock_rate, unsigned int clock_rate_multipli set_expected_bit_length(one); } -void Controller::setup_track() // Time initial_offset +void Controller::setup_track() { _track = _drive->get_track(); -// _track = _disk->get_track_at_position(0, (unsigned int)_head_position); - // TODO: probably a better implementation of the empty track? -/* Time offset; + Time offset; if(_track && _time_into_track.length > 0) { Time time_found = _track->seek_to(_time_into_track).simplify(); @@ -42,11 +40,10 @@ void Controller::setup_track() // Time initial_offset { offset = _time_into_track; _time_into_track.set_zero(); - }*/ + } - reset_timer(); + reset_timer_to_offset(offset * _rotational_multiplier); get_next_event(); -// reset_timer_to_offset(offset * _rotational_multiplier); } void Controller::run_for_cycles(int number_of_cycles)