mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-26 15:32:04 +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() :
|
Machine::Machine() :
|
||||||
_shift_register(0),
|
_shift_register(0),
|
||||||
Storage::DiskDrive(1000000, 300)
|
Storage::DiskDrive(1000000, 16, 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);
|
||||||
@ -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)
|
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;
|
static int bitCount = 0;
|
||||||
bitCount++;
|
bitCount++;
|
||||||
|
@ -1008,7 +1008,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles)
|
|||||||
{
|
{
|
||||||
if(_is_running)
|
if(_is_running)
|
||||||
{
|
{
|
||||||
TapePlayer::run_for_cycles(number_of_cycles);
|
TapePlayer::run_for_cycles((int)number_of_cycles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -19,6 +19,9 @@ namespace SignalProcessing {
|
|||||||
clock to sample something with another.
|
clock to sample something with another.
|
||||||
|
|
||||||
Uses a Bresenham-like error term internally for full-integral storage with no drift.
|
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
|
class Stepper
|
||||||
{
|
{
|
||||||
@ -33,7 +36,7 @@ class Stepper
|
|||||||
of steps that should be taken at the @c output_rate.
|
of steps that should be taken at the @c output_rate.
|
||||||
*/
|
*/
|
||||||
Stepper(uint64_t output_rate, uint64_t input_rate) :
|
Stepper(uint64_t output_rate, uint64_t input_rate) :
|
||||||
accumulated_error_(0),
|
accumulated_error_(-((int64_t)input_rate << 1)),
|
||||||
input_rate_(input_rate),
|
input_rate_(input_rate),
|
||||||
output_rate_(output_rate),
|
output_rate_(output_rate),
|
||||||
whole_step_(output_rate / input_rate),
|
whole_step_(output_rate / input_rate),
|
||||||
|
@ -10,17 +10,19 @@
|
|||||||
|
|
||||||
using namespace Storage;
|
using namespace Storage;
|
||||||
|
|
||||||
DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int revolutions_per_minute) :
|
DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute) :
|
||||||
_clock_rate(clock_rate * 16),
|
_clock_rate(clock_rate * clock_rate_multiplier),
|
||||||
|
_clock_rate_multiplier(clock_rate_multiplier),
|
||||||
_revolutions_per_minute(revolutions_per_minute),
|
_revolutions_per_minute(revolutions_per_minute),
|
||||||
_head_position(0),
|
_head_position(0),
|
||||||
|
|
||||||
TimedEventLoop(clock_rate * 16)
|
TimedEventLoop(clock_rate * clock_rate_multiplier)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void DiskDrive::set_expected_bit_length(Time bit_length)
|
void DiskDrive::set_expected_bit_length(Time bit_length)
|
||||||
{
|
{
|
||||||
_bit_length = 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
|
// 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
|
// 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()
|
void DiskDrive::set_track()
|
||||||
{
|
{
|
||||||
_track = _disk->get_track_at_position((unsigned int)_head_position);
|
_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();
|
reset_timer();
|
||||||
get_next_event();
|
get_next_event();
|
||||||
}
|
}
|
||||||
@ -62,11 +86,13 @@ void DiskDrive::run_for_cycles(int number_of_cycles)
|
|||||||
{
|
{
|
||||||
if(has_disk())
|
if(has_disk())
|
||||||
{
|
{
|
||||||
_cycles_since_index_hole += (unsigned int)number_of_cycles;
|
number_of_cycles *= _clock_rate_multiplier;
|
||||||
|
while(number_of_cycles--)
|
||||||
number_of_cycles *= 16;
|
{
|
||||||
_pll->run_for_cycles(number_of_cycles);
|
_cycles_since_index_hole ++;
|
||||||
TimedEventLoop::run_for_cycles(number_of_cycles);
|
_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.clock_rate *= _revolutions_per_minute;
|
||||||
event_interval.simplify();
|
event_interval.simplify();
|
||||||
set_next_event_time_interval(event_interval);
|
set_next_event_time_interval(event_interval);
|
||||||
|
// printf("bit length: %0.4f\n", event_interval.get_float() * 1000.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskDrive::process_next_event()
|
void DiskDrive::process_next_event()
|
||||||
|
@ -17,7 +17,7 @@ namespace Storage {
|
|||||||
|
|
||||||
class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop {
|
class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop {
|
||||||
public:
|
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);
|
void set_expected_bit_length(Time bit_length);
|
||||||
|
|
||||||
@ -43,6 +43,7 @@ class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop
|
|||||||
private:
|
private:
|
||||||
Time _bit_length;
|
Time _bit_length;
|
||||||
unsigned int _clock_rate;
|
unsigned int _clock_rate;
|
||||||
|
unsigned int _clock_rate_multiplier;
|
||||||
unsigned int _revolutions_per_minute;
|
unsigned int _revolutions_per_minute;
|
||||||
|
|
||||||
std::shared_ptr<DigitalPhaseLockedLoop> _pll;
|
std::shared_ptr<DigitalPhaseLockedLoop> _pll;
|
||||||
|
@ -32,6 +32,8 @@ PCMTrack::Event PCMTrack::get_next_event()
|
|||||||
while(_segment_pointer < _segments.size())
|
while(_segment_pointer < _segments.size())
|
||||||
{
|
{
|
||||||
unsigned int clock_multiplier = _track_clock_rate / _segments[_segment_pointer].length_of_a_bit.clock_rate;
|
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();
|
const uint8_t *segment_data = _segments[_segment_pointer].data.get();
|
||||||
while(_bit_pointer < _segments[_segment_pointer].number_of_bits)
|
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?
|
// 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));
|
int bit = segment_data[_bit_pointer >> 3] & (0x80 >> (_bit_pointer&7));
|
||||||
_bit_pointer++;
|
_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;
|
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;
|
_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;
|
_segment_pointer = _bit_pointer = 0;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,11 @@ struct Time {
|
|||||||
length /= common_divisor;
|
length /= common_divisor;
|
||||||
clock_rate /= 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