mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 00:30:29 +00:00
Formalised clock-rate multiplication within disk drives, discovered that the stepper didn't have ideal behaviour for my timed event loop and hence nailed down the semantics a ilttle more.
(obiter: the 1540 now appears to discern the correct sequence of bits. Framing is off in my test printfs but that's neither here nor there).
This commit is contained in:
parent
6ee784a893
commit
2332f72875
@ -14,7 +14,7 @@ using namespace Commodore::C1540;
|
||||
|
||||
Machine::Machine() :
|
||||
_shift_register(0),
|
||||
Storage::DiskDrive(1000000, 300)
|
||||
Storage::DiskDrive(1000000, 16, 300)
|
||||
{
|
||||
// create a serial port and a VIA to run it
|
||||
_serialPortVIA.reset(new SerialPortVIA);
|
||||
@ -115,7 +115,7 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522)
|
||||
|
||||
void Machine::process_input_bit(int value, unsigned int cycles_since_index_hole)
|
||||
{
|
||||
_shift_register = (_shift_register >> 1) | (value << 10);
|
||||
_shift_register = (_shift_register << 1) | value;
|
||||
|
||||
static int bitCount = 0;
|
||||
bitCount++;
|
||||
|
@ -1008,7 +1008,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
||||
{
|
||||
if(_is_running)
|
||||
{
|
||||
TapePlayer::run_for_cycles(number_of_cycles);
|
||||
TapePlayer::run_for_cycles((int)number_of_cycles);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -19,6 +19,9 @@ namespace SignalProcessing {
|
||||
clock to sample something with another.
|
||||
|
||||
Uses a Bresenham-like error term internally for full-integral storage with no drift.
|
||||
|
||||
Pegs the beginning of both clocks to the time at which the stepper is created. So e.g. a stepper
|
||||
that converts from an input clock of 1200 to an output clock of 2 will first fire on cycle 600.
|
||||
*/
|
||||
class Stepper
|
||||
{
|
||||
@ -33,7 +36,7 @@ class Stepper
|
||||
of steps that should be taken at the @c output_rate.
|
||||
*/
|
||||
Stepper(uint64_t output_rate, uint64_t input_rate) :
|
||||
accumulated_error_(0),
|
||||
accumulated_error_(-((int64_t)input_rate << 1)),
|
||||
input_rate_(input_rate),
|
||||
output_rate_(output_rate),
|
||||
whole_step_(output_rate / input_rate),
|
||||
|
@ -10,17 +10,19 @@
|
||||
|
||||
using namespace Storage;
|
||||
|
||||
DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int revolutions_per_minute) :
|
||||
_clock_rate(clock_rate * 16),
|
||||
DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute) :
|
||||
_clock_rate(clock_rate * clock_rate_multiplier),
|
||||
_clock_rate_multiplier(clock_rate_multiplier),
|
||||
_revolutions_per_minute(revolutions_per_minute),
|
||||
_head_position(0),
|
||||
|
||||
TimedEventLoop(clock_rate * 16)
|
||||
TimedEventLoop(clock_rate * clock_rate_multiplier)
|
||||
{}
|
||||
|
||||
void DiskDrive::set_expected_bit_length(Time bit_length)
|
||||
{
|
||||
_bit_length = bit_length;
|
||||
printf("expected bit length: %0.4f\n", bit_length.get_float() * 1000.0);
|
||||
|
||||
// this conversion doesn't need to be exact because there's a lot of variation to be taken
|
||||
// account of in rotation speed, air turbulence, etc, so a direct conversion will do
|
||||
@ -54,6 +56,28 @@ void DiskDrive::step(int direction)
|
||||
void DiskDrive::set_track()
|
||||
{
|
||||
_track = _disk->get_track_at_position((unsigned int)_head_position);
|
||||
|
||||
// printf("***");
|
||||
// int calibration = -1;
|
||||
// int bit = 0, shift = 0;
|
||||
// while(1)
|
||||
// {
|
||||
// Track::Event event = _track->get_next_event();
|
||||
// if(event.type == Track::Event::IndexHole) break;
|
||||
// if(calibration < 0) calibration = event.length.length;
|
||||
//
|
||||
// int number_of_bits = event.length.length / calibration;
|
||||
// while(number_of_bits > 1)
|
||||
// {
|
||||
// shift = (shift << 1)&0xff;
|
||||
// number_of_bits--;
|
||||
// bit++; if(bit == 8) { printf("%02x.", shift); bit = 0; }
|
||||
// }
|
||||
// shift = ((shift << 1) | 0x01)&0xff;
|
||||
// bit++; if(bit == 8) { printf("%02x.", shift); bit = 0; }
|
||||
// }
|
||||
// printf("***\n");
|
||||
|
||||
reset_timer();
|
||||
get_next_event();
|
||||
}
|
||||
@ -62,11 +86,13 @@ void DiskDrive::run_for_cycles(int number_of_cycles)
|
||||
{
|
||||
if(has_disk())
|
||||
{
|
||||
_cycles_since_index_hole += (unsigned int)number_of_cycles;
|
||||
|
||||
number_of_cycles *= 16;
|
||||
_pll->run_for_cycles(number_of_cycles);
|
||||
TimedEventLoop::run_for_cycles(number_of_cycles);
|
||||
number_of_cycles *= _clock_rate_multiplier;
|
||||
while(number_of_cycles--)
|
||||
{
|
||||
_cycles_since_index_hole ++;
|
||||
_pll->run_for_cycles(1);
|
||||
TimedEventLoop::run_for_cycles(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +116,7 @@ void DiskDrive::get_next_event()
|
||||
event_interval.clock_rate *= _revolutions_per_minute;
|
||||
event_interval.simplify();
|
||||
set_next_event_time_interval(event_interval);
|
||||
// printf("bit length: %0.4f\n", event_interval.get_float() * 1000.0);
|
||||
}
|
||||
|
||||
void DiskDrive::process_next_event()
|
||||
|
@ -17,7 +17,7 @@ namespace Storage {
|
||||
|
||||
class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop {
|
||||
public:
|
||||
DiskDrive(unsigned int clock_rate, unsigned int revolutions_per_minute);
|
||||
DiskDrive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute);
|
||||
|
||||
void set_expected_bit_length(Time bit_length);
|
||||
|
||||
@ -43,6 +43,7 @@ class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop
|
||||
private:
|
||||
Time _bit_length;
|
||||
unsigned int _clock_rate;
|
||||
unsigned int _clock_rate_multiplier;
|
||||
unsigned int _revolutions_per_minute;
|
||||
|
||||
std::shared_ptr<DigitalPhaseLockedLoop> _pll;
|
||||
|
@ -32,6 +32,8 @@ PCMTrack::Event PCMTrack::get_next_event()
|
||||
while(_segment_pointer < _segments.size())
|
||||
{
|
||||
unsigned int clock_multiplier = _track_clock_rate / _segments[_segment_pointer].length_of_a_bit.clock_rate;
|
||||
unsigned int bit_length = clock_multiplier * _segments[_segment_pointer].length_of_a_bit.length;
|
||||
|
||||
const uint8_t *segment_data = _segments[_segment_pointer].data.get();
|
||||
while(_bit_pointer < _segments[_segment_pointer].number_of_bits)
|
||||
{
|
||||
@ -39,7 +41,7 @@ PCMTrack::Event PCMTrack::get_next_event()
|
||||
// TODO: should I account for the converse bit ordering? Or can I assume MSB first?
|
||||
int bit = segment_data[_bit_pointer >> 3] & (0x80 >> (_bit_pointer&7));
|
||||
_bit_pointer++;
|
||||
_next_event.length.length += clock_multiplier * _segments[_segment_pointer].length_of_a_bit.length;
|
||||
_next_event.length.length += bit_length;
|
||||
|
||||
if(bit) return _next_event;
|
||||
}
|
||||
@ -74,5 +76,12 @@ void PCMTrack::fix_length()
|
||||
_next_event.length.clock_rate += _segments[c].length_of_a_bit.length * _segments[c].number_of_bits * multiplier;
|
||||
}
|
||||
|
||||
uint8_t *data = _segments[0].data.get();
|
||||
for(int c = 0; c < _segments[0].number_of_bits >> 3; c++)
|
||||
{
|
||||
printf("%02x.", data[c]);
|
||||
}
|
||||
printf("===\n");
|
||||
|
||||
_segment_pointer = _bit_pointer = 0;
|
||||
}
|
||||
|
@ -22,6 +22,11 @@ struct Time {
|
||||
length /= common_divisor;
|
||||
clock_rate /= common_divisor;
|
||||
}
|
||||
|
||||
inline float get_float()
|
||||
{
|
||||
return (float)length / (float)clock_rate;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user