From 89a1881fef9338de2fa09c0f7be96fe3c870581f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 29 Jul 2016 11:03:09 -0400 Subject: [PATCH] Started turning the 1540 into an actual disk drive. --- Machines/Commodore/1540/C1540.cpp | 25 +++++++++++++++--- Machines/Commodore/1540/C1540.hpp | 12 +++++++-- .../Clock Signal.xcodeproj/project.pbxproj | 26 ++++++++++++++----- Storage/Disk/DiskDrive.cpp | 2 +- Storage/Disk/DiskDrive.hpp | 2 +- Storage/Disk/Encodings/CommodoreGCR.cpp | 20 ++++++++++++++ Storage/Disk/Encodings/CommodoreGCR.hpp | 22 ++++++++++++++++ Storage/Disk/Formats/G64.cpp | 16 +++--------- Storage/Disk/Formats/G64.hpp | 2 -- Storage/Tape/Tape.cpp | 2 +- Storage/Tape/Tape.hpp | 2 +- Storage/TimedEventLoop.cpp | 4 +-- Storage/TimedEventLoop.hpp | 2 +- 13 files changed, 104 insertions(+), 33 deletions(-) create mode 100644 Storage/Disk/Encodings/CommodoreGCR.cpp create mode 100644 Storage/Disk/Encodings/CommodoreGCR.hpp diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp index 8724a2f2b..fe1f80bd6 100644 --- a/Machines/Commodore/1540/C1540.cpp +++ b/Machines/Commodore/1540/C1540.cpp @@ -7,11 +7,14 @@ // #include "C1540.hpp" -#include +#include +#include "../../../Storage/Disk/Encodings/CommodoreGCR.hpp" using namespace Commodore::C1540; -Machine::Machine() +Machine::Machine() : + _shift_register(0), + Storage::DiskDrive(1000000, 300) { // create a serial port and a VIA to run it _serialPortVIA.reset(new SerialPortVIA); @@ -24,6 +27,9 @@ Machine::Machine() // set this instance as the delegate to receive interrupt requests from both VIAs _serialPortVIA->set_delegate(this); _driveVIA.set_delegate(this); + + // set a bit rate + set_expected_bit_length(Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(3)); } void Machine::set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus) @@ -91,9 +97,10 @@ void Machine::set_rom(const uint8_t *rom) memcpy(_rom, rom, sizeof(_rom)); } -void Machine::set_disk(std::shared_ptr disk) +void Machine::run_for_cycles(int number_of_cycles) { - _disk = disk; + CPU6502::Processor::run_for_cycles(number_of_cycles); + Storage::DiskDrive::run_for_cycles(number_of_cycles); } #pragma mark - 6522 delegate @@ -103,3 +110,13 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522) // both VIAs are connected to the IRQ line set_irq_line(_serialPortVIA->get_interrupt_line() || _driveVIA.get_interrupt_line()); } + +#pragma mark - Disk drive + +void Machine::process_input_bit(int value, unsigned int cycles_since_index_hole) +{ + _shift_register = (_shift_register >> 1) | (value << 10); +} + +// the 1540 does not recognise index holes +void Machine::process_index_hole() {} diff --git a/Machines/Commodore/1540/C1540.hpp b/Machines/Commodore/1540/C1540.hpp index 1935b1e5d..844341baa 100644 --- a/Machines/Commodore/1540/C1540.hpp +++ b/Machines/Commodore/1540/C1540.hpp @@ -15,6 +15,7 @@ #include "../SerialBus.hpp" #include "../../../Storage/Disk/Disk.hpp" +#include "../../../Storage/Disk/DiskDrive.hpp" namespace Commodore { namespace C1540 { @@ -161,7 +162,8 @@ class SerialPort : public ::Commodore::Serial::Port { */ class Machine: public CPU6502::Processor, - public MOS::MOS6522IRQDelegate::Delegate { + public MOS::MOS6522IRQDelegate::Delegate, + public Storage::DiskDrive { public: Machine(); @@ -179,7 +181,9 @@ class Machine: /*! Sets the disk from which this 1540 is reading data. */ - void set_disk(std::shared_ptr disk); +// void set_disk(std::shared_ptr disk); + + void run_for_cycles(int number_of_cycles); // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); @@ -196,6 +200,10 @@ class Machine: DriveVIA _driveVIA; std::shared_ptr _disk; + + int _shift_register; + virtual void process_input_bit(int value, unsigned int cycles_since_index_hole); + virtual void process_index_hole(); }; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 84e134da4..124da7db1 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -316,6 +316,7 @@ 4BB299F91B587D8400A49093 /* tyan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298ED1B587D8400A49093 /* tyan */; }; 4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C51D4B558F00248BDF /* Factors.cpp */; }; 4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; }; + 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; }; 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; }; 4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EA51B587A5100552FC2 /* Atari2600Document.xib */; }; 4BB73EA91B587A5100552FC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EA81B587A5100552FC2 /* Assets.xcassets */; }; @@ -706,6 +707,8 @@ 4BB697C61D4B558F00248BDF /* Factors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Factors.hpp; path = ../../NumberTheory/Factors.hpp; sourceTree = ""; }; 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = ""; }; 4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = ""; }; + 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreGCR.cpp; path = Encodings/CommodoreGCR.cpp; sourceTree = ""; }; + 4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CommodoreGCR.hpp; path = Encodings/CommodoreGCR.hpp; sourceTree = ""; }; 4BB73E9E1B587A5100552FC2 /* Clock Signal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Clock Signal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 4BB73EA61B587A5100552FC2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Atari2600Document.xib; sourceTree = ""; }; @@ -1005,15 +1008,16 @@ 4BAB62AA1D3272D200DF5BA0 /* Disk */ = { isa = PBXGroup; children = ( - 4BAB62B21D327F7E00DF5BA0 /* Formats */, - 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */, - 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */, - 4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */, - 4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */, 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */, - 4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */, + 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */, 4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */, + 4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */, + 4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */, + 4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */, 4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */, + 4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */, + 4BB697CF1D4BA44900248BDF /* Encodings */, + 4BAB62B21D327F7E00DF5BA0 /* Formats */, ); path = Disk; sourceTree = ""; @@ -1308,6 +1312,15 @@ name = NumberTheory; sourceTree = ""; }; + 4BB697CF1D4BA44900248BDF /* Encodings */ = { + isa = PBXGroup; + children = ( + 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */, + 4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */, + ); + name = Encodings; + sourceTree = ""; + }; 4BB73E951B587A5100552FC2 = { isa = PBXGroup; children = ( @@ -1892,6 +1905,7 @@ files = ( 4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */, 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, + 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */, 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */, diff --git a/Storage/Disk/DiskDrive.cpp b/Storage/Disk/DiskDrive.cpp index 75ca88a05..1a98abe57 100644 --- a/Storage/Disk/DiskDrive.cpp +++ b/Storage/Disk/DiskDrive.cpp @@ -57,7 +57,7 @@ void DiskDrive::set_track() get_next_event(); } -void DiskDrive::run_for_cycles(unsigned int number_of_cycles) +void DiskDrive::run_for_cycles(int number_of_cycles) { if(has_disk()) { diff --git a/Storage/Disk/DiskDrive.hpp b/Storage/Disk/DiskDrive.hpp index 2e89fe3c6..2c2923927 100644 --- a/Storage/Disk/DiskDrive.hpp +++ b/Storage/Disk/DiskDrive.hpp @@ -24,7 +24,7 @@ class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop void set_disk(std::shared_ptr disk); bool has_disk(); - void run_for_cycles(unsigned int number_of_cycles); + void run_for_cycles(int number_of_cycles); bool get_is_track_zero(); void step(int direction); diff --git a/Storage/Disk/Encodings/CommodoreGCR.cpp b/Storage/Disk/Encodings/CommodoreGCR.cpp new file mode 100644 index 000000000..36667141d --- /dev/null +++ b/Storage/Disk/Encodings/CommodoreGCR.cpp @@ -0,0 +1,20 @@ +// +// CommodoreGCR.cpp +// Clock Signal +// +// Created by Thomas Harte on 29/07/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "CommodoreGCR.hpp" + +using namespace Storage; + +Time Storage::Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(unsigned int time_zone) +{ + Time duration; + // the speed zone divides a 4Mhz clock by 13, 14, 15 or 16, with higher-numbered zones being faster (i.e. each bit taking less time) + duration.length = 16 - time_zone; + duration.clock_rate = 4000000; + return duration; +} diff --git a/Storage/Disk/Encodings/CommodoreGCR.hpp b/Storage/Disk/Encodings/CommodoreGCR.hpp new file mode 100644 index 000000000..0617af963 --- /dev/null +++ b/Storage/Disk/Encodings/CommodoreGCR.hpp @@ -0,0 +1,22 @@ +// +// CommodoreGCR.hpp +// Clock Signal +// +// Created by Thomas Harte on 29/07/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef CommodoreGCR_hpp +#define CommodoreGCR_hpp + +#include "../../Storage.hpp" + +namespace Storage { +namespace Encodings { +namespace CommodoreGCR { + Time length_of_a_bit_in_time_zone(unsigned int time_zone); +} +} +} + +#endif /* CommodoreGCR_hpp */ diff --git a/Storage/Disk/Formats/G64.cpp b/Storage/Disk/Formats/G64.cpp index 68c358ae4..d68d8c299 100644 --- a/Storage/Disk/Formats/G64.cpp +++ b/Storage/Disk/Formats/G64.cpp @@ -10,6 +10,7 @@ #include #include "../PCMTrack.hpp" +#include "../Encodings/CommodoreGCR.hpp" using namespace Storage; @@ -117,14 +118,14 @@ std::shared_ptr G64::get_track_at_position(unsigned int position) unsigned int start_byte_in_current_speed = 0; for(unsigned int byte = 0; byte < track_length; byte ++) { - unsigned int byte_speed = speed_zone_contents[byte >> 2] >> (6 - (byte&3)*2); + unsigned int byte_speed = speed_zone_contents[byte >> 2] >> (6 - (byte&3)*2); if(byte_speed != current_speed || byte == (track_length-1)) { unsigned int number_of_bytes = byte - start_byte_in_current_speed; PCMSegment segment; segment.number_of_bits = number_of_bytes * 8; - segment.length_of_a_bit = length_of_a_bit_in_time_zone(current_speed); + segment.length_of_a_bit = Encodings::CommodoreGCR::length_of_a_bit_in_time_zone(current_speed); segment.data.reset(new uint8_t[number_of_bytes]); memcpy(segment.data.get(), &track_contents.get()[start_byte_in_current_speed], number_of_bytes); segments.push_back(std::move(segment)); @@ -140,7 +141,7 @@ std::shared_ptr G64::get_track_at_position(unsigned int position) { PCMSegment segment; segment.number_of_bits = track_length * 8; - segment.length_of_a_bit = length_of_a_bit_in_time_zone((unsigned int)speed_zone_offset); + segment.length_of_a_bit = Encodings::CommodoreGCR::length_of_a_bit_in_time_zone((unsigned int)speed_zone_offset); segment.data = std::move(track_contents); resulting_track.reset(new PCMTrack(std::move(segment))); @@ -151,12 +152,3 @@ std::shared_ptr G64::get_track_at_position(unsigned int position) return resulting_track; } - -Time G64::length_of_a_bit_in_time_zone(unsigned int time_zone) -{ - Time duration; - // the speed zone divides a 4Mhz clock by 13, 14, 15 or 16, with higher-numbered zones being faster (i.e. each bit taking less time) - duration.length = 16 - time_zone; - duration.clock_rate = 4000000; - return duration; -} diff --git a/Storage/Disk/Formats/G64.hpp b/Storage/Disk/Formats/G64.hpp index 802a7ffa2..406453039 100644 --- a/Storage/Disk/Formats/G64.hpp +++ b/Storage/Disk/Formats/G64.hpp @@ -31,8 +31,6 @@ class G64: public Disk { uint8_t _number_of_tracks; uint16_t _maximum_track_size; - - Time length_of_a_bit_in_time_zone(unsigned int time_zone); }; }; diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp index a2848dc13..8717a5ce4 100644 --- a/Storage/Tape/Tape.cpp +++ b/Storage/Tape/Tape.cpp @@ -47,7 +47,7 @@ void TapePlayer::get_next_pulse() set_next_event_time_interval(_current_pulse.length); } -void TapePlayer::run_for_cycles(unsigned int number_of_cycles) +void TapePlayer::run_for_cycles(int number_of_cycles) { if(has_tape()) { diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp index 3b9ad5e61..47ebea129 100644 --- a/Storage/Tape/Tape.hpp +++ b/Storage/Tape/Tape.hpp @@ -54,7 +54,7 @@ class TapePlayer: public TimedEventLoop { void set_tape(std::shared_ptr tape); bool has_tape(); - void run_for_cycles(unsigned int number_of_cycles); + void run_for_cycles(int number_of_cycles); void run_for_input_pulse(); protected: diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp index c90e9d558..b0851b7f8 100644 --- a/Storage/TimedEventLoop.cpp +++ b/Storage/TimedEventLoop.cpp @@ -14,9 +14,9 @@ using namespace Storage; TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) : _input_clock_rate(input_clock_rate) {} -void TimedEventLoop::run_for_cycles(unsigned int number_of_cycles) +void TimedEventLoop::run_for_cycles(int number_of_cycles) { - _time_into_interval += (unsigned int)_stepper->step(number_of_cycles); + _time_into_interval += (unsigned int)_stepper->step((uint64_t)number_of_cycles); while(_time_into_interval >= _event_interval.length) { process_next_event(); diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp index 6c64158c2..232ff8c6d 100644 --- a/Storage/TimedEventLoop.hpp +++ b/Storage/TimedEventLoop.hpp @@ -19,7 +19,7 @@ namespace Storage { class TimedEventLoop { public: TimedEventLoop(unsigned int input_clock_rate); - void run_for_cycles(unsigned int number_of_cycles); + void run_for_cycles(int number_of_cycles); protected: void reset_timer();