2016-11-06 21:13:13 +00:00
|
|
|
//
|
|
|
|
// Acorn.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 06/11/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "Acorn.hpp"
|
|
|
|
|
|
|
|
using namespace Storage::Tape::Acorn;
|
|
|
|
|
2017-07-15 23:07:35 +00:00
|
|
|
namespace {
|
|
|
|
const int PLLClockRate = 1920000;
|
|
|
|
}
|
|
|
|
|
2017-07-16 23:24:01 +00:00
|
|
|
Parser::Parser() : crc_(0x1021, 0x0000) {
|
|
|
|
shifter_.set_delegate(this);
|
|
|
|
}
|
2016-11-06 21:13:13 +00:00
|
|
|
|
2017-07-14 01:26:05 +00:00
|
|
|
int Parser::get_next_bit(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2016-11-06 21:13:13 +00:00
|
|
|
SymbolType symbol = get_next_symbol(tape);
|
|
|
|
return (symbol == SymbolType::One) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2017-07-14 01:26:05 +00:00
|
|
|
int Parser::get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2016-11-06 21:13:13 +00:00
|
|
|
int value = 0;
|
|
|
|
int c = 8;
|
2017-07-14 01:26:05 +00:00
|
|
|
if(get_next_bit(tape)) {
|
2016-11-06 21:13:13 +00:00
|
|
|
set_error_flag();
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-14 01:26:05 +00:00
|
|
|
while(c--) {
|
2016-11-06 21:13:13 +00:00
|
|
|
value = (value >> 1) | (get_next_bit(tape) << 7);
|
|
|
|
}
|
2017-07-14 01:26:05 +00:00
|
|
|
if(!get_next_bit(tape)) {
|
2016-11-06 21:13:13 +00:00
|
|
|
set_error_flag();
|
|
|
|
return -1;
|
|
|
|
}
|
2016-12-03 17:05:19 +00:00
|
|
|
crc_.add((uint8_t)value);
|
2016-11-06 21:13:13 +00:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2017-07-14 01:26:05 +00:00
|
|
|
int Parser::get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2016-11-06 21:13:13 +00:00
|
|
|
int result = get_next_byte(tape);
|
|
|
|
result |= get_next_byte(tape) << 8;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-07-14 01:26:05 +00:00
|
|
|
int Parser::get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
2016-11-06 21:13:13 +00:00
|
|
|
int result = get_next_short(tape);
|
|
|
|
result |= get_next_short(tape) << 8;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-12-03 17:05:19 +00:00
|
|
|
void Parser::reset_crc() { crc_.reset(); }
|
|
|
|
uint16_t Parser::get_crc() { return crc_.get_value(); }
|
2016-11-06 21:13:13 +00:00
|
|
|
|
2017-07-16 23:24:01 +00:00
|
|
|
void Parser::acorn_shifter_output_bit(int value) {
|
|
|
|
push_symbol(value ? SymbolType::One : SymbolType::Zero);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
|
|
|
shifter_.process_pulse(pulse);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Shifter::Shifter() :
|
|
|
|
pll_(PLLClockRate / 4800, 15),
|
|
|
|
was_high_(false),
|
|
|
|
input_pattern_(0),
|
2017-08-01 11:07:43 +00:00
|
|
|
input_bit_counter_(0),
|
|
|
|
delegate_(nullptr) {
|
2017-07-16 23:24:01 +00:00
|
|
|
pll_.set_delegate(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
2017-07-25 01:04:47 +00:00
|
|
|
pll_.run_for(Cycles((int)((float)PLLClockRate * pulse.length.get_float())));
|
2017-07-16 23:24:01 +00:00
|
|
|
|
|
|
|
bool is_high = pulse.type == Storage::Tape::Tape::Pulse::High;
|
|
|
|
if(is_high != was_high_) {
|
|
|
|
pll_.add_pulse();
|
|
|
|
}
|
|
|
|
was_high_ = is_high;
|
|
|
|
}
|
2016-11-06 21:13:13 +00:00
|
|
|
|
2017-07-16 23:24:01 +00:00
|
|
|
void Shifter::digital_phase_locked_loop_output_bit(int value) {
|
|
|
|
input_pattern_ = ((input_pattern_ << 1) | (unsigned int)value) & 0xf;
|
|
|
|
switch(input_pattern_) {
|
|
|
|
case 0x5: delegate_->acorn_shifter_output_bit(0); input_pattern_ = 0; break;
|
|
|
|
case 0xf: delegate_->acorn_shifter_output_bit(1); input_pattern_ = 0; break;
|
|
|
|
default: break;;
|
2016-11-06 21:13:13 +00:00
|
|
|
}
|
|
|
|
}
|