mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 15:39:08 +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:
parent
74817f6664
commit
0aa90b943b
@ -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 */,
|
||||
|
9
Storage/Disk/DiskDrive.cpp
Normal file
9
Storage/Disk/DiskDrive.cpp
Normal 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"
|
35
Storage/Disk/DiskDrive.hpp
Normal file
35
Storage/Disk/DiskDrive.hpp
Normal 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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user