2017-08-06 02:26:15 +00:00
|
|
|
//
|
|
|
|
// MFMDiskController.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 05/08/2017.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
2017-08-06 02:26:15 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "MFMDiskController.hpp"
|
|
|
|
|
2017-09-25 01:40:43 +00:00
|
|
|
#include "../Encodings/MFM/Constants.hpp"
|
2017-08-06 02:26:15 +00:00
|
|
|
|
|
|
|
using namespace Storage::Disk;
|
|
|
|
|
2017-09-11 02:56:05 +00:00
|
|
|
MFMController::MFMController(Cycles clock_rate) :
|
|
|
|
Storage::Disk::Controller(clock_rate),
|
2018-05-24 02:21:57 +00:00
|
|
|
shifter_(&crc_generator_) {
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MFMController::process_index_hole() {
|
2020-05-10 03:00:39 +00:00
|
|
|
posit_event(int(Event::IndexHole));
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MFMController::process_write_completed() {
|
2020-05-10 03:00:39 +00:00
|
|
|
posit_event(int(Event::DataWritten));
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-09-25 00:07:56 +00:00
|
|
|
shifter_.set_is_double_density(is_double_density);
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MFMController::get_is_double_density() {
|
|
|
|
return is_double_density_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MFMController::set_data_mode(DataMode mode) {
|
|
|
|
data_mode_ = mode;
|
2017-09-25 00:07:56 +00:00
|
|
|
shifter_.set_should_obey_syncs(mode == DataMode::Scanning);
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MFMController::Token MFMController::get_latest_token() {
|
|
|
|
return latest_token_;
|
|
|
|
}
|
|
|
|
|
2018-05-24 02:21:57 +00:00
|
|
|
CRC::CCITT &MFMController::get_crc_generator() {
|
2017-08-07 16:37:22 +00:00
|
|
|
return crc_generator_;
|
|
|
|
}
|
|
|
|
|
2017-09-10 23:23:23 +00:00
|
|
|
void MFMController::process_input_bit(int value) {
|
2017-08-06 02:26:15 +00:00
|
|
|
if(data_mode_ == DataMode::Writing) return;
|
|
|
|
|
2017-09-25 00:07:56 +00:00
|
|
|
shifter_.add_input_bit(value);
|
|
|
|
switch(shifter_.get_token()) {
|
|
|
|
case Encodings::MFM::Shifter::Token::None:
|
2017-08-06 02:26:15 +00:00
|
|
|
return;
|
2017-09-25 00:07:56 +00:00
|
|
|
|
|
|
|
case Encodings::MFM::Shifter::Token::Index:
|
|
|
|
latest_token_.type = Token::Index;
|
|
|
|
break;
|
|
|
|
case Encodings::MFM::Shifter::Token::ID:
|
|
|
|
latest_token_.type = Token::ID;
|
|
|
|
break;
|
|
|
|
case Encodings::MFM::Shifter::Token::Data:
|
|
|
|
latest_token_.type = Token::Data;
|
|
|
|
break;
|
|
|
|
case Encodings::MFM::Shifter::Token::DeletedData:
|
|
|
|
latest_token_.type = Token::DeletedData;
|
|
|
|
break;
|
|
|
|
case Encodings::MFM::Shifter::Token::Sync:
|
|
|
|
latest_token_.type = Token::Sync;
|
|
|
|
break;
|
|
|
|
case Encodings::MFM::Shifter::Token::Byte:
|
|
|
|
latest_token_.type = Token::Byte;
|
|
|
|
break;
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
2017-09-25 00:07:56 +00:00
|
|
|
latest_token_.byte_value = shifter_.get_byte();
|
2019-12-22 22:56:59 +00:00
|
|
|
posit_event(int(Event::Token));
|
2017-08-06 02:26:15 +00:00
|
|
|
}
|
2017-08-13 16:50:07 +00:00
|
|
|
|
|
|
|
void MFMController::write_bit(int bit) {
|
|
|
|
if(is_double_density_) {
|
2017-09-10 23:23:23 +00:00
|
|
|
get_drive().write_bit(!bit && !last_bit_);
|
|
|
|
get_drive().write_bit(!!bit);
|
2017-08-13 16:50:07 +00:00
|
|
|
last_bit_ = bit;
|
|
|
|
} else {
|
2017-09-10 23:23:23 +00:00
|
|
|
get_drive().write_bit(true);
|
|
|
|
get_drive().write_bit(!!bit);
|
2017-08-13 16:50:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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++) {
|
2017-09-10 23:23:23 +00:00
|
|
|
get_drive().write_bit(!!((value << c)&0x8000));
|
2017-08-13 16:50:07 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-13 22:05:19 +00:00
|
|
|
|
|
|
|
void MFMController::write_crc() {
|
|
|
|
uint16_t crc = get_crc_generator().get_value();
|
|
|
|
write_byte(crc >> 8);
|
|
|
|
write_byte(crc & 0xff);
|
|
|
|
}
|
2017-08-14 19:50:36 +00:00
|
|
|
|
|
|
|
void MFMController::write_n_bytes(int quantity, uint8_t value) {
|
|
|
|
while(quantity--) write_byte(value);
|
|
|
|
}
|
2017-08-14 20:03:35 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-15 19:29:23 +00:00
|
|
|
void MFMController::write_id_data_joiner(bool is_deleted, bool skip_first_gap) {
|
2017-08-14 20:03:35 +00:00
|
|
|
if(get_is_double_density()) {
|
2017-08-15 19:29:23 +00:00
|
|
|
if(!skip_first_gap) write_n_bytes(22, 0x4e);
|
2017-08-14 20:03:35 +00:00
|
|
|
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 {
|
2017-08-15 19:29:23 +00:00
|
|
|
if(!skip_first_gap) write_n_bytes(11, 0xff);
|
2017-08-14 20:03:35 +00:00
|
|
|
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);
|
2017-08-15 19:29:23 +00:00
|
|
|
for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMIndexSync);
|
2017-08-14 20:03:35 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|