1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-09 21:29:53 +00:00
CLK/Storage/Disk/MFMDiskController.cpp
Thomas Harte 96bf133924 Withdraws requirement for DiskController users to specify a PLL multiplier or to provide rotation speed.
In the latter case because it's no longer of any interest to the controller, and in the former because I'd rather it be picked automatically.
2017-09-10 22:56:05 -04:00

240 lines
6.9 KiB
C++

//
// MFMDiskController.cpp
// Clock Signal
//
// Created by Thomas Harte on 05/08/2017.
// Copyright © 2017 Thomas Harte. All rights reserved.
//
#include "MFMDiskController.hpp"
#include "../../Storage/Disk/Encodings/MFM.hpp"
using namespace Storage::Disk;
MFMController::MFMController(Cycles clock_rate) :
Storage::Disk::Controller(clock_rate),
crc_generator_(0x1021, 0xffff),
data_mode_(DataMode::Scanning),
is_awaiting_marker_value_(false) {
}
void MFMController::process_index_hole() {
posit_event((int)Event::IndexHole);
}
void MFMController::process_write_completed() {
posit_event((int)Event::DataWritten);
}
void MFMController::set_is_double_density(bool is_double_density) {
is_double_density_ = is_double_density;
Storage::Time bit_length;
bit_length.length = 1;
bit_length.clock_rate = is_double_density ? 500000 : 250000;
set_expected_bit_length(bit_length);
if(!is_double_density) is_awaiting_marker_value_ = false;
}
bool MFMController::get_is_double_density() {
return is_double_density_;
}
void MFMController::set_data_mode(DataMode mode) {
data_mode_ = mode;
}
MFMController::Token MFMController::get_latest_token() {
return latest_token_;
}
NumberTheory::CRC16 &MFMController::get_crc_generator() {
return crc_generator_;
}
void MFMController::process_input_bit(int value) {
if(data_mode_ == DataMode::Writing) return;
shift_register_ = (shift_register_ << 1) | value;
bits_since_token_++;
if(data_mode_ == DataMode::Scanning) {
Token::Type token_type = Token::Byte;
if(!is_double_density_) {
switch(shift_register_ & 0xffff) {
case Storage::Encodings::MFM::FMIndexAddressMark:
token_type = Token::Index;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::IndexAddressByte);
break;
case Storage::Encodings::MFM::FMIDAddressMark:
token_type = Token::ID;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::IDAddressByte);
break;
case Storage::Encodings::MFM::FMDataAddressMark:
token_type = Token::Data;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::DataAddressByte);
break;
case Storage::Encodings::MFM::FMDeletedDataAddressMark:
token_type = Token::DeletedData;
crc_generator_.reset();
crc_generator_.add(latest_token_.byte_value = Storage::Encodings::MFM::DeletedDataAddressByte);
break;
default:
break;
}
} else {
switch(shift_register_ & 0xffff) {
case Storage::Encodings::MFM::MFMIndexSync:
bits_since_token_ = 0;
is_awaiting_marker_value_ = true;
token_type = Token::Sync;
latest_token_.byte_value = Storage::Encodings::MFM::MFMIndexSyncByteValue;
break;
case Storage::Encodings::MFM::MFMSync:
bits_since_token_ = 0;
is_awaiting_marker_value_ = true;
crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
token_type = Token::Sync;
latest_token_.byte_value = Storage::Encodings::MFM::MFMSyncByteValue;
break;
default:
break;
}
}
if(token_type != Token::Byte) {
latest_token_.type = token_type;
bits_since_token_ = 0;
posit_event((int)Event::Token);
return;
}
}
if(bits_since_token_ == 16) {
latest_token_.type = Token::Byte;
latest_token_.byte_value = (uint8_t)(
((shift_register_ & 0x0001) >> 0) |
((shift_register_ & 0x0004) >> 1) |
((shift_register_ & 0x0010) >> 2) |
((shift_register_ & 0x0040) >> 3) |
((shift_register_ & 0x0100) >> 4) |
((shift_register_ & 0x0400) >> 5) |
((shift_register_ & 0x1000) >> 6) |
((shift_register_ & 0x4000) >> 7));
bits_since_token_ = 0;
if(is_awaiting_marker_value_ && is_double_density_) {
is_awaiting_marker_value_ = false;
switch(latest_token_.byte_value) {
case Storage::Encodings::MFM::IndexAddressByte:
latest_token_.type = Token::Index;
break;
case Storage::Encodings::MFM::IDAddressByte:
latest_token_.type = Token::ID;
break;
case Storage::Encodings::MFM::DataAddressByte:
latest_token_.type = Token::Data;
break;
case Storage::Encodings::MFM::DeletedDataAddressByte:
latest_token_.type = Token::DeletedData;
break;
default: break;
}
}
crc_generator_.add(latest_token_.byte_value);
posit_event((int)Event::Token);
return;
}
}
void MFMController::write_bit(int bit) {
if(is_double_density_) {
get_drive().write_bit(!bit && !last_bit_);
get_drive().write_bit(!!bit);
last_bit_ = bit;
} else {
get_drive().write_bit(true);
get_drive().write_bit(!!bit);
}
}
void MFMController::write_byte(uint8_t byte) {
for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80);
crc_generator_.add(byte);
}
void MFMController::write_raw_short(uint16_t value) {
for(int c = 0; c < 16; c++) {
get_drive().write_bit(!!((value << c)&0x8000));
}
}
void MFMController::write_crc() {
uint16_t crc = get_crc_generator().get_value();
write_byte(crc >> 8);
write_byte(crc & 0xff);
}
void MFMController::write_n_bytes(int quantity, uint8_t value) {
while(quantity--) write_byte(value);
}
void MFMController::write_id_joiner() {
if(get_is_double_density()) {
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(Storage::Encodings::MFM::IDAddressByte);
} else {
write_n_bytes(6, 0x00);
get_crc_generator().reset();
write_raw_short(Storage::Encodings::MFM::FMIDAddressMark);
}
}
void MFMController::write_id_data_joiner(bool is_deleted, bool skip_first_gap) {
if(get_is_double_density()) {
if(!skip_first_gap) write_n_bytes(22, 0x4e);
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync);
get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue);
write_byte(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
} else {
if(!skip_first_gap) write_n_bytes(11, 0xff);
write_n_bytes(6, 0x00);
get_crc_generator().reset();
get_crc_generator().add(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte);
write_raw_short(is_deleted ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark);
}
}
void MFMController::write_post_data_gap() {
if(get_is_double_density()) {
write_n_bytes(54, 0x4e);
} else {
write_n_bytes(27, 0xff);
}
}
void MFMController::write_start_of_track() {
if(get_is_double_density()) {
write_n_bytes(80, 0x4e);
write_n_bytes(12, 0x00);
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMIndexSync);
write_byte(Storage::Encodings::MFM::IndexAddressByte);
write_n_bytes(50, 0x4e);
} else {
write_n_bytes(40, 0xff);
write_n_bytes(6, 0x00);
write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark);
write_n_bytes(26, 0xff);
}
}