1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-29 12:50:28 +00:00

Started turning the 1540 into an actual disk drive.

This commit is contained in:
Thomas Harte 2016-07-29 11:03:09 -04:00
parent 6532b3a8c8
commit 89a1881fef
13 changed files with 104 additions and 33 deletions

View File

@ -7,11 +7,14 @@
// //
#include "C1540.hpp" #include "C1540.hpp"
#include <string.h> #include <string>
#include "../../../Storage/Disk/Encodings/CommodoreGCR.hpp"
using namespace Commodore::C1540; 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 // create a serial port and a VIA to run it
_serialPortVIA.reset(new SerialPortVIA); _serialPortVIA.reset(new SerialPortVIA);
@ -24,6 +27,9 @@ Machine::Machine()
// set this instance as the delegate to receive interrupt requests from both VIAs // set this instance as the delegate to receive interrupt requests from both VIAs
_serialPortVIA->set_delegate(this); _serialPortVIA->set_delegate(this);
_driveVIA.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) 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)); memcpy(_rom, rom, sizeof(_rom));
} }
void Machine::set_disk(std::shared_ptr<Storage::Disk> disk) void Machine::run_for_cycles(int number_of_cycles)
{ {
_disk = disk; CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
Storage::DiskDrive::run_for_cycles(number_of_cycles);
} }
#pragma mark - 6522 delegate #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 // both VIAs are connected to the IRQ line
set_irq_line(_serialPortVIA->get_interrupt_line() || _driveVIA.get_interrupt_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() {}

View File

@ -15,6 +15,7 @@
#include "../SerialBus.hpp" #include "../SerialBus.hpp"
#include "../../../Storage/Disk/Disk.hpp" #include "../../../Storage/Disk/Disk.hpp"
#include "../../../Storage/Disk/DiskDrive.hpp"
namespace Commodore { namespace Commodore {
namespace C1540 { namespace C1540 {
@ -161,7 +162,8 @@ class SerialPort : public ::Commodore::Serial::Port {
*/ */
class Machine: class Machine:
public CPU6502::Processor<Machine>, public CPU6502::Processor<Machine>,
public MOS::MOS6522IRQDelegate::Delegate { public MOS::MOS6522IRQDelegate::Delegate,
public Storage::DiskDrive {
public: public:
Machine(); Machine();
@ -179,7 +181,9 @@ class Machine:
/*! /*!
Sets the disk from which this 1540 is reading data. Sets the disk from which this 1540 is reading data.
*/ */
void set_disk(std::shared_ptr<Storage::Disk> disk); // void set_disk(std::shared_ptr<Storage::Disk> disk);
void run_for_cycles(int number_of_cycles);
// to satisfy CPU6502::Processor // to satisfy CPU6502::Processor
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
@ -196,6 +200,10 @@ class Machine:
DriveVIA _driveVIA; DriveVIA _driveVIA;
std::shared_ptr<Storage::Disk> _disk; std::shared_ptr<Storage::Disk> _disk;
int _shift_register;
virtual void process_input_bit(int value, unsigned int cycles_since_index_hole);
virtual void process_index_hole();
}; };
} }

View File

@ -316,6 +316,7 @@
4BB299F91B587D8400A49093 /* tyan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298ED1B587D8400A49093 /* tyan */; }; 4BB299F91B587D8400A49093 /* tyan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298ED1B587D8400A49093 /* tyan */; };
4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C51D4B558F00248BDF /* Factors.cpp */; }; 4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C51D4B558F00248BDF /* Factors.cpp */; };
4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.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 */; }; 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; };
4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EA51B587A5100552FC2 /* Atari2600Document.xib */; }; 4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EA51B587A5100552FC2 /* Atari2600Document.xib */; };
4BB73EA91B587A5100552FC2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4BB73EA81B587A5100552FC2 /* Assets.xcassets */; }; 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 = "<group>"; }; 4BB697C61D4B558F00248BDF /* Factors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Factors.hpp; path = ../../NumberTheory/Factors.hpp; sourceTree = "<group>"; };
4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = "<group>"; }; 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = "<group>"; };
4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = "<group>"; }; 4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = "<group>"; };
4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommodoreGCR.cpp; path = Encodings/CommodoreGCR.cpp; sourceTree = "<group>"; };
4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CommodoreGCR.hpp; path = Encodings/CommodoreGCR.hpp; sourceTree = "<group>"; };
4BB73E9E1B587A5100552FC2 /* Clock Signal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Clock Signal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 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 = "<group>"; }; 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
4BB73EA61B587A5100552FC2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Atari2600Document.xib; sourceTree = "<group>"; }; 4BB73EA61B587A5100552FC2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Atari2600Document.xib; sourceTree = "<group>"; };
@ -1005,15 +1008,16 @@
4BAB62AA1D3272D200DF5BA0 /* Disk */ = { 4BAB62AA1D3272D200DF5BA0 /* Disk */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4BAB62B21D327F7E00DF5BA0 /* Formats */,
4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */,
4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */,
4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */,
4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */,
4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */, 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */,
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */, 4BAB62AB1D3272D200DF5BA0 /* Disk.cpp */,
4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */, 4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */,
4BAB62B61D3302CA00DF5BA0 /* PCMTrack.cpp */,
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */,
4BAB62AC1D3272D200DF5BA0 /* Disk.hpp */,
4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */, 4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */,
4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */,
4BB697CF1D4BA44900248BDF /* Encodings */,
4BAB62B21D327F7E00DF5BA0 /* Formats */,
); );
path = Disk; path = Disk;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1308,6 +1312,15 @@
name = NumberTheory; name = NumberTheory;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4BB697CF1D4BA44900248BDF /* Encodings */ = {
isa = PBXGroup;
children = (
4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */,
4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */,
);
name = Encodings;
sourceTree = "<group>";
};
4BB73E951B587A5100552FC2 = { 4BB73E951B587A5100552FC2 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -1892,6 +1905,7 @@
files = ( files = (
4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */, 4BAB62AD1D3272D200DF5BA0 /* Disk.cpp in Sources */,
4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */,
4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */,
4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */,
4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */,
4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */, 4BB697C71D4B558F00248BDF /* Factors.cpp in Sources */,

View File

@ -57,7 +57,7 @@ void DiskDrive::set_track()
get_next_event(); 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()) if(has_disk())
{ {

View File

@ -24,7 +24,7 @@ class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop
void set_disk(std::shared_ptr<Disk> disk); void set_disk(std::shared_ptr<Disk> disk);
bool has_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(); bool get_is_track_zero();
void step(int direction); void step(int direction);

View File

@ -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;
}

View File

@ -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 */

View File

@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "../PCMTrack.hpp" #include "../PCMTrack.hpp"
#include "../Encodings/CommodoreGCR.hpp"
using namespace Storage; using namespace Storage;
@ -117,14 +118,14 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
unsigned int start_byte_in_current_speed = 0; unsigned int start_byte_in_current_speed = 0;
for(unsigned int byte = 0; byte < track_length; byte ++) 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)) if(byte_speed != current_speed || byte == (track_length-1))
{ {
unsigned int number_of_bytes = byte - start_byte_in_current_speed; unsigned int number_of_bytes = byte - start_byte_in_current_speed;
PCMSegment segment; PCMSegment segment;
segment.number_of_bits = number_of_bytes * 8; 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]); segment.data.reset(new uint8_t[number_of_bytes]);
memcpy(segment.data.get(), &track_contents.get()[start_byte_in_current_speed], number_of_bytes); memcpy(segment.data.get(), &track_contents.get()[start_byte_in_current_speed], number_of_bytes);
segments.push_back(std::move(segment)); segments.push_back(std::move(segment));
@ -140,7 +141,7 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
{ {
PCMSegment segment; PCMSegment segment;
segment.number_of_bits = track_length * 8; 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); segment.data = std::move(track_contents);
resulting_track.reset(new PCMTrack(std::move(segment))); resulting_track.reset(new PCMTrack(std::move(segment)));
@ -151,12 +152,3 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
return resulting_track; 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;
}

View File

@ -31,8 +31,6 @@ class G64: public Disk {
uint8_t _number_of_tracks; uint8_t _number_of_tracks;
uint16_t _maximum_track_size; uint16_t _maximum_track_size;
Time length_of_a_bit_in_time_zone(unsigned int time_zone);
}; };
}; };

View File

@ -47,7 +47,7 @@ void TapePlayer::get_next_pulse()
set_next_event_time_interval(_current_pulse.length); 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()) if(has_tape())
{ {

View File

@ -54,7 +54,7 @@ class TapePlayer: public TimedEventLoop {
void set_tape(std::shared_ptr<Storage::Tape> tape); void set_tape(std::shared_ptr<Storage::Tape> tape);
bool has_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(); void run_for_input_pulse();
protected: protected:

View File

@ -14,9 +14,9 @@ using namespace Storage;
TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) : TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) :
_input_clock_rate(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) while(_time_into_interval >= _event_interval.length)
{ {
process_next_event(); process_next_event();

View File

@ -19,7 +19,7 @@ namespace Storage {
class TimedEventLoop { class TimedEventLoop {
public: public:
TimedEventLoop(unsigned int input_clock_rate); TimedEventLoop(unsigned int input_clock_rate);
void run_for_cycles(unsigned int number_of_cycles); void run_for_cycles(int number_of_cycles);
protected: protected:
void reset_timer(); void reset_timer();