1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-07 08:28:57 +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 */; };
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; };
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 */; };
4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; };
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>"; };
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; };
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>"; };
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>"; };
@ -1001,6 +1004,8 @@
4BAB62B71D3302CA00DF5BA0 /* PCMTrack.hpp */,
4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */,
4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */,
4B6C73BB1D387AE500AFCFCA /* DiskDrive.cpp */,
4B6C73BC1D387AE500AFCFCA /* DiskDrive.hpp */,
);
path = Disk;
sourceTree = "<group>";
@ -1885,6 +1890,7 @@
4BAB62B51D327F7E00DF5BA0 /* G64.cpp in Sources */,
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
4B6C73BD1D387AE500AFCFCA /* DiskDrive.cpp in Sources */,
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */,
4B1E85751D170228001EF87D /* Typer.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) << 8;
get_track_at_position(0);
// for(size_t c = 0; c < _number_of_tracks; c++)
// get_track_at_position(c);
}
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;
PCMSegment segment;
segment.duration.length = 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.number_of_bits = number_of_bytes * 8;
segment.length_of_a_bit = 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));
@ -138,8 +139,8 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
else
{
PCMSegment segment;
segment.duration.length = track_length * 8;
segment.duration.clock_rate = 1; // this is arbitrary; if supplying only one PCMSegment then it'll naturally fill the track
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.data = std::move(track_contents);
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;
}
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;
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;
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();
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
// 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()
{
// 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++)
{
_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;
for(size_t c = 0; c < _segments.size(); c++)
{
unsigned int multiplier = _track_clock_rate / _segments[c].duration.clock_rate;
_next_event.length.clock_rate += _segments[c].duration.length * multiplier;
unsigned int multiplier = _track_clock_rate / _segments[c].length_of_a_bit.clock_rate;
_next_event.length.clock_rate += _segments[c].length_of_a_bit.length * _segments[c].number_of_bits * multiplier;
}
_segment_pointer = _bit_pointer = 0;

View File

@ -15,22 +15,13 @@
namespace Storage {
/*!
A segment of PCM-sampled data. The clock rate in the duration is taken to be relative to all other
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.
A segment of PCM-sampled data.
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 {
Time duration;
Time length_of_a_bit;
unsigned int number_of_bits;
std::unique_ptr<uint8_t> data;
};