mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
129 lines
3.4 KiB
C++
129 lines
3.4 KiB
C++
//
|
|
// Shifter.cpp
|
|
// Clock Signal
|
|
//
|
|
// Created by Thomas Harte on 24/09/2017.
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
|
//
|
|
|
|
#include "Shifter.hpp"
|
|
#include "Constants.hpp"
|
|
|
|
#include "../../../../Numeric/BitSpread.hpp"
|
|
|
|
using namespace Storage::Encodings::MFM;
|
|
|
|
Shifter::Shifter() : owned_crc_generator_(new CRC::CCITT()), crc_generator_(owned_crc_generator_.get()) {}
|
|
Shifter::Shifter(CRC::CCITT *crc_generator) : crc_generator_(crc_generator) {}
|
|
|
|
void Shifter::set_is_mfm(bool is_mfm) {
|
|
is_mfm_ = is_mfm;
|
|
if(!is_mfm) is_awaiting_marker_value_ = false;
|
|
}
|
|
|
|
void Shifter::set_should_obey_syncs(bool should_obey_syncs) {
|
|
should_obey_syncs_ = should_obey_syncs;
|
|
}
|
|
|
|
void Shifter::add_input_bit(int value) {
|
|
shift_register_ = (shift_register_ << 1) | unsigned(value);
|
|
++bits_since_token_;
|
|
|
|
token_ = Token::None;
|
|
if(should_obey_syncs_) {
|
|
if(!is_mfm_) {
|
|
switch(shift_register_ & 0xffff) {
|
|
case Storage::Encodings::MFM::FMIndexAddressMark:
|
|
token_ = Token::Index;
|
|
crc_generator_->reset();
|
|
crc_generator_->add(Storage::Encodings::MFM::IndexAddressByte);
|
|
break;
|
|
case Storage::Encodings::MFM::FMIDAddressMark:
|
|
token_ = Token::ID;
|
|
crc_generator_->reset();
|
|
crc_generator_->add(Storage::Encodings::MFM::IDAddressByte);
|
|
break;
|
|
case Storage::Encodings::MFM::FMDataAddressMark:
|
|
token_ = Token::Data;
|
|
crc_generator_->reset();
|
|
crc_generator_->add(Storage::Encodings::MFM::DataAddressByte);
|
|
break;
|
|
case Storage::Encodings::MFM::FMDeletedDataAddressMark:
|
|
token_ = Token::DeletedData;
|
|
crc_generator_->reset();
|
|
crc_generator_->add(Storage::Encodings::MFM::DeletedDataAddressByte);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch(shift_register_ & 0xffff) {
|
|
case Storage::Encodings::MFM::MFMIndexSync:
|
|
// This models a bit of slightly weird WD behaviour;
|
|
// if an index sync was detected where it wasn't expected,
|
|
// the WD will resync but also may return the clock bits
|
|
// rather than data bits as the next byte read, depending
|
|
// on framing.
|
|
//
|
|
// TODO: make this optional, if ever a Shifter with
|
|
// well-defined non-WD behaviour is needed.
|
|
//
|
|
// TODO: Verify WD behaviour.
|
|
if(bits_since_token_&1) {
|
|
shift_register_ >>= 1;
|
|
}
|
|
|
|
bits_since_token_ = 0;
|
|
is_awaiting_marker_value_ = true;
|
|
|
|
token_ = Token::Sync;
|
|
break;
|
|
case Storage::Encodings::MFM::MFMSync:
|
|
bits_since_token_ = 0;
|
|
is_awaiting_marker_value_ = true;
|
|
crc_generator_->set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
|
|
|
|
token_ = Token::Sync;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(token_ != Token::None) {
|
|
bits_since_token_ = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(bits_since_token_ == 16) {
|
|
token_ = Token::Byte;
|
|
bits_since_token_ = 0;
|
|
|
|
if(is_awaiting_marker_value_ && is_mfm_) {
|
|
is_awaiting_marker_value_ = false;
|
|
switch(get_byte()) {
|
|
case Storage::Encodings::MFM::IndexAddressByte:
|
|
token_ = Token::Index;
|
|
break;
|
|
case Storage::Encodings::MFM::IDAddressByte:
|
|
token_ = Token::ID;
|
|
break;
|
|
case Storage::Encodings::MFM::DataAddressByte:
|
|
token_ = Token::Data;
|
|
break;
|
|
case Storage::Encodings::MFM::DeletedDataAddressByte:
|
|
token_ = Token::DeletedData;
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
crc_generator_->add(get_byte());
|
|
}
|
|
}
|
|
|
|
uint8_t Shifter::get_byte() const {
|
|
return Numeric::unspread_bits(uint16_t(shift_register_));
|
|
}
|