1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-11 08:23:43 +00:00

Switched to specifying bit length as a quotient for the purposes of a PCMSegment and verified that I had the logic for picking a Commodore time zone backwards: bigger numbers are faster, not slower.

Started sketching out a DiskDrive class.
This commit is contained in:
Thomas Harte 2016-07-15 06:51:11 -04:00
parent 74817f6664
commit 0aa90b943b
7 changed files with 77 additions and 24 deletions

View File

@ -40,6 +40,7 @@
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; }; 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; };
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; };
4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; };
4B6C73BD1D387AE500AFCFCA /* DiskDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */; };
4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; }; 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; };
4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; };
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; }; 4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
@ -420,6 +421,8 @@
4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapeUEF.cpp; sourceTree = "<group>"; }; 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapeUEF.cpp; sourceTree = "<group>"; };
4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TapeUEF.hpp; sourceTree = "<group>"; }; 4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TapeUEF.hpp; sourceTree = "<group>"; };
4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; 4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskDrive.cpp; sourceTree = "<group>"; };
4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskDrive.hpp; sourceTree = "<group>"; };
4B73C7191D036BD90074D992 /* Vic20Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20Document.swift; sourceTree = "<group>"; }; 4B73C7191D036BD90074D992 /* Vic20Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20Document.swift; sourceTree = "<group>"; };
4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; }; 4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; };
4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; }; 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
@ -1001,6 +1004,8 @@
4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */, 4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */,
4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */, 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */,
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */, 4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */,
4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */,
4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */,
); );
path = Disk; path = Disk;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1885,6 +1890,7 @@
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */, 4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */, 4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */, 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
4B6C73BD1D387AE500AFCFCA /* DiskDrive.cpp in Sources */,
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */, 4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */,
4B1E85751D170228001EF87D /* Typer.cpp in Sources */, 4B1E85751D170228001EF87D /* Typer.cpp in Sources */,
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */, 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,

View File

@ -0,0 +1,9 @@
//
// DiskDrive.cpp
// Clock Signal
//
// Created by Thomas Harte on 14/07/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "DiskDrive.hpp"

View File

@ -0,0 +1,35 @@
//
// DiskDrive.hpp
// Clock Signal
//
// Created by Thomas Harte on 14/07/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef DiskDrive_hpp
#define DiskDrive_hpp
#include "Disk.hpp"
namespace Storage {
class DiskDrive {
public:
DiskDrive(unsigned int clock_rate);
void set_disk(std::shared_ptr<Disk> disk);
bool has_disk();
void run_for_cycles(unsigned int number_of_cycles);
bool get_is_track_zero();
void step(int direction);
void set_motor_on(bool motor_on);
protected:
virtual void process_input_event(Track::Event event) = 0;
};
}
#endif /* DiskDrive_hpp */

View File

@ -40,7 +40,8 @@ G64::G64(const char *file_name)
_maximum_track_size = (uint16_t)fgetc(_file); _maximum_track_size = (uint16_t)fgetc(_file);
_maximum_track_size |= (uint16_t)fgetc(_file) << 8; _maximum_track_size |= (uint16_t)fgetc(_file) << 8;
get_track_at_position(0); // for(size_t c = 0; c < _number_of_tracks; c++)
// get_track_at_position(c);
} }
G64::~G64() G64::~G64()
@ -122,8 +123,8 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
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.duration.length = number_of_bytes * 8; segment.number_of_bits = number_of_bytes * 8;
segment.duration.clock_rate = 4000000 / (13 + current_speed); // the speed zone divides a 4Mhz clock by 13, 14, 15 or 16; TODO: is this the right way around? Is zone 3 the fastest or the slowest? segment.length_of_a_bit = 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));
@ -138,8 +139,8 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
else else
{ {
PCMSegment segment; PCMSegment segment;
segment.duration.length = track_length * 8; segment.number_of_bits = track_length * 8;
segment.duration.clock_rate = 1; // this is arbitrary; if supplying only one PCMSegment then it'll naturally fill the track segment.length_of_a_bit = 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)));
@ -150,3 +151,12 @@ 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,6 +31,8 @@ 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

@ -55,9 +55,9 @@ PCMTrack::Event PCMTrack::get_next_event()
_next_event.length.length = 0; _next_event.length.length = 0;
while(_segment_pointer < _segments.size()) while(_segment_pointer < _segments.size())
{ {
unsigned int clock_multiplier = _track_clock_rate / _segments[_segment_pointer].duration.clock_rate; unsigned int clock_multiplier = _track_clock_rate / _segments[_segment_pointer].length_of_a_bit.clock_rate;
const uint8_t *segment_data = _segments[_segment_pointer].data.get(); const uint8_t *segment_data = _segments[_segment_pointer].data.get();
while(_bit_pointer < _segments[_segment_pointer].duration.length) while(_bit_pointer < _segments[_segment_pointer].length_of_a_bit.length)
{ {
// for timing simplicity, bits are modelled as happening at the end of their window // for timing simplicity, bits are modelled as happening at the end of their window
// TODO: should I account for the converse bit ordering? Or can I assume MSB first? // TODO: should I account for the converse bit ordering? Or can I assume MSB first?
@ -84,18 +84,18 @@ PCMTrack::Event PCMTrack::get_next_event()
void PCMTrack::fix_length() void PCMTrack::fix_length()
{ {
// find the least common multiple of all segment clock rates // find the least common multiple of all segment clock rates
_track_clock_rate = _segments[0].duration.clock_rate; _track_clock_rate = _segments[0].length_of_a_bit.clock_rate;
for(size_t c = 1; c < _segments.size(); c++) for(size_t c = 1; c < _segments.size(); c++)
{ {
_track_clock_rate = least_common_multiple(_track_clock_rate, _segments[c].duration.clock_rate); _track_clock_rate = least_common_multiple(_track_clock_rate, _segments[c].length_of_a_bit.clock_rate);
} }
// therby determine the total length, storing it to next_event as the divisor // therby determine the total length, storing it to next_event as the track-total divisor
_next_event.length.clock_rate = 0; _next_event.length.clock_rate = 0;
for(size_t c = 0; c < _segments.size(); c++) for(size_t c = 0; c < _segments.size(); c++)
{ {
unsigned int multiplier = _track_clock_rate / _segments[c].duration.clock_rate; unsigned int multiplier = _track_clock_rate / _segments[c].length_of_a_bit.clock_rate;
_next_event.length.clock_rate += _segments[c].duration.length * multiplier; _next_event.length.clock_rate += _segments[c].length_of_a_bit.length * _segments[c].number_of_bits * multiplier;
} }
_segment_pointer = _bit_pointer = 0; _segment_pointer = _bit_pointer = 0;

View File

@ -15,22 +15,13 @@
namespace Storage { namespace Storage {
/*! /*!
A segment of PCM-sampled data. The clock rate in the duration is taken to be relative to all other A segment of PCM-sampled data.
segments that comprise a track rather than absolute, and the length is taken to be the number of
bits from @c data that are actually present.
Bits from each byte are taken MSB to LSB. Bits from each byte are taken MSB to LSB.
Actual segment lengths will be calculated such that all segments that comprise a track exactly fill the track.
So the segment for a track with only a single segment may supply any clock rate other than 0. It will exactly
fill the track, so if it has 7 samples then there will be at most a flux transition every 1/7th of a rotation.
If a track consists of two segments, one with clock rate 1 and one with clock rate 2, the second will be
clocked twice as fast as the first.
*/ */
struct PCMSegment { struct PCMSegment {
Time duration; Time length_of_a_bit;
unsigned int number_of_bits;
std::unique_ptr<uint8_t> data; std::unique_ptr<uint8_t> data;
}; };