diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 96db03aeb..6c5d43834 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -25,29 +25,16 @@ WD1770::Status::Status() : busy(false) {} WD1770::WD1770(Personality p) : - Storage::Disk::Controller(8000000, 16, 300), - crc_generator_(0x1021, 0xffff), - interesting_event_mask_(Event::Command), + Storage::Disk::MFMController(8000000, 16, 300), + interesting_event_mask_((int)Event1770::Command), resume_point_(0), delay_time_(0), index_hole_count_target_(-1), - is_awaiting_marker_value_(false), - data_mode_(DataMode::Scanning), delegate_(nullptr), personality_(p), head_is_loaded_(false) { set_is_double_density(false); - posit_event(Event::Command); -} - -void WD1770::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; + posit_event((int)Event1770::Command); } void WD1770::set_register(int address, uint8_t value) { @@ -60,7 +47,7 @@ void WD1770::set_register(int address, uint8_t value) { }); } else { command_ = value; - posit_event(Event::Command); + posit_event((int)Event1770::Command); } } break; @@ -131,148 +118,24 @@ void WD1770::run_for(const Cycles cycles) { unsigned int number_of_cycles = (unsigned int)cycles.as_int(); if(delay_time_ <= number_of_cycles) { delay_time_ = 0; - posit_event(Event::Timer); + posit_event((int)Event1770::Timer); } else { delay_time_ -= number_of_cycles; } } } -void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole) { - 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(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(Event::Token); - return; - } -} - -void WD1770::process_index_hole() { - index_hole_count_++; - posit_event(Event::IndexHole); - if(index_hole_count_target_ == index_hole_count_) { - posit_event(Event::IndexHoleTarget); - index_hole_count_target_ = -1; - } - - // motor power-down - if(index_hole_count_ == 9 && !status_.busy && has_motor_on_line()) { - set_motor_on(false); - } - - // head unload - if(index_hole_count_ == 15 && !status_.busy && has_head_load_line()) { - set_head_load_request(false); - } -} - -void WD1770::process_write_completed() { - posit_event(Event::DataWritten); -} - -#define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = mask; return; case __LINE__: -#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = Event::Timer; delay_time_ = ms * 8000; case __LINE__: if(delay_time_) return; -#define WAIT_FOR_BYTES(count) resume_point_ = __LINE__; interesting_event_mask_ = Event::Token; distance_into_section_ = 0; return; case __LINE__: if(latest_token_.type == Token::Byte) distance_into_section_++; if(distance_into_section_ < count) { interesting_event_mask_ = Event::Token; return; } +#define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = (int)mask; return; case __LINE__: +#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; delay_time_ = ms * 8000; WAIT_FOR_EVENT(Event1770::Timer); +#define WAIT_FOR_BYTES(count) resume_point_ = __LINE__; distance_into_section_ = 0; WAIT_FOR_EVENT(Event::Token); if(get_latest_token().type == Token::Byte) distance_into_section_++; if(distance_into_section_ < count) { interesting_event_mask_ = (int)Event::Token; return; } #define BEGIN_SECTION() switch(resume_point_) { default: #define END_SECTION() 0; } #define READ_ID() \ - if(new_event_type == Event::Token) { \ - if(!distance_into_section_ && latest_token_.type == Token::ID) {data_mode_ = DataMode::Reading; distance_into_section_++; } \ - else if(distance_into_section_ && distance_into_section_ < 7 && latest_token_.type == Token::Byte) { \ - header_[distance_into_section_ - 1] = latest_token_.byte_value; \ + if(new_event_type == (int)Event::Token) { \ + if(!distance_into_section_ && get_latest_token().type == Token::ID) {set_data_mode(DataMode::Reading); distance_into_section_++; } \ + else if(distance_into_section_ && distance_into_section_ < 7 && get_latest_token().type == Token::Byte) { \ + header_[distance_into_section_ - 1] = get_latest_token().byte_value; \ distance_into_section_++; \ } \ } @@ -285,7 +148,7 @@ void WD1770::process_write_completed() { set_motor_on(true); \ index_hole_count_ = 0; \ index_hole_count_target_ = 6; \ - WAIT_FOR_EVENT(Event::IndexHoleTarget); \ + WAIT_FOR_EVENT(Event1770::IndexHoleTarget); \ status_.spin_up = true; // +--------+----------+-------------------------+ @@ -305,7 +168,25 @@ void WD1770::process_write_completed() { // ! 4 ! Forc int ! 1 1 0 1 i3 i2 i1 i0 ! // +--------+----------+-------------------------+ -void WD1770::posit_event(Event new_event_type) { +void WD1770::posit_event(int new_event_type) { + if(new_event_type == (int)Event::IndexHole) { + index_hole_count_++; + if(index_hole_count_target_ == index_hole_count_) { + posit_event((int)Event1770::IndexHoleTarget); + index_hole_count_target_ = -1; + } + + // motor power-down + if(index_hole_count_ == 9 && !status_.busy && has_motor_on_line()) { + set_motor_on(false); + } + + // head unload + if(index_hole_count_ == 15 && !status_.busy && has_head_load_line()) { + set_head_load_request(false); + } + } + if(!(interesting_event_mask_ & (int)new_event_type)) return; interesting_event_mask_ &= ~new_event_type; @@ -315,7 +196,7 @@ void WD1770::posit_event(Event new_event_type) { // Wait for a new command, branch to the appropriate handler. wait_for_command: printf("Idle...\n"); - data_mode_ = DataMode::Scanning; + set_data_mode(DataMode::Scanning); index_hole_count_ = 0; update_status([] (Status &status) { @@ -323,7 +204,7 @@ void WD1770::posit_event(Event new_event_type) { status.interrupt_request = true; }); - WAIT_FOR_EVENT(Event::Command); + WAIT_FOR_EVENT(Event1770::Command); update_status([] (Status &status) { status.busy = true; @@ -372,7 +253,7 @@ void WD1770::posit_event(Event new_event_type) { } set_head_load_request(true); if(head_is_loaded_) goto test_type1_type; - WAIT_FOR_EVENT(Event::HeadLoad); + WAIT_FOR_EVENT(Event1770::HeadLoad); goto test_type1_type; begin_type1_spin_up: @@ -429,7 +310,7 @@ void WD1770::posit_event(Event new_event_type) { distance_into_section_ = 0; verify_read_data: - WAIT_FOR_EVENT(Event::IndexHole | Event::Token); + WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token); READ_ID(); if(index_hole_count_ == 6) { @@ -439,8 +320,8 @@ void WD1770::posit_event(Event new_event_type) { goto wait_for_command; } if(distance_into_section_ == 7) { - data_mode_ = DataMode::Scanning; - if(crc_generator_.get_value()) { + set_data_mode(DataMode::Scanning); + if(get_crc_generator().get_value()) { update_status([] (Status &status) { status.crc_error = true; }); @@ -491,7 +372,7 @@ void WD1770::posit_event(Event new_event_type) { begin_type2_load_head: set_head_load_request(true); if(head_is_loaded_) goto test_type2_delay; - WAIT_FOR_EVENT(Event::HeadLoad); + WAIT_FOR_EVENT(Event1770::HeadLoad); goto test_type2_delay; begin_type2_spin_up: @@ -513,7 +394,7 @@ void WD1770::posit_event(Event new_event_type) { } type2_get_header: - WAIT_FOR_EVENT(Event::IndexHole | Event::Token); + WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token); READ_ID(); if(index_hole_count_ == 5) { @@ -525,11 +406,11 @@ void WD1770::posit_event(Event new_event_type) { } if(distance_into_section_ == 7) { printf("Considering %d/%d\n", header_[0], header_[2]); - data_mode_ = DataMode::Scanning; + set_data_mode(DataMode::Scanning); if( header_[0] == track_ && header_[2] == sector_ && (has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) { printf("Found %d/%d\n", header_[0], header_[2]); - if(crc_generator_.get_value()) { + if(get_crc_generator().get_value()) { printf("CRC error; back to searching\n"); update_status([] (Status &status) { status.crc_error = true; @@ -554,20 +435,20 @@ void WD1770::posit_event(Event new_event_type) { type2_read_data: WAIT_FOR_EVENT(Event::Token); // TODO: timeout - if(latest_token_.type == Token::Data || latest_token_.type == Token::DeletedData) { + if(get_latest_token().type == Token::Data || get_latest_token().type == Token::DeletedData) { update_status([this] (Status &status) { - status.record_type = (latest_token_.type == Token::DeletedData); + status.record_type = (get_latest_token().type == Token::DeletedData); }); distance_into_section_ = 0; - data_mode_ = DataMode::Reading; + set_data_mode(DataMode::Reading); goto type2_read_byte; } goto type2_read_data; type2_read_byte: WAIT_FOR_EVENT(Event::Token); - if(latest_token_.type != Token::Byte) goto type2_read_byte; - data_ = latest_token_.byte_value; + if(get_latest_token().type != Token::Byte) goto type2_read_byte; + data_ = get_latest_token().byte_value; update_status([] (Status &status) { status.lost_data |= status.data_request; status.data_request = true; @@ -581,11 +462,11 @@ void WD1770::posit_event(Event new_event_type) { type2_check_crc: WAIT_FOR_EVENT(Event::Token); - if(latest_token_.type != Token::Byte) goto type2_read_byte; - header_[distance_into_section_] = latest_token_.byte_value; + if(get_latest_token().type != Token::Byte) goto type2_read_byte; + header_[distance_into_section_] = get_latest_token().byte_value; distance_into_section_++; if(distance_into_section_ == 2) { - if(crc_generator_.get_value()) { + if(get_crc_generator().get_value()) { printf("CRC error; terminating\n"); update_status([this] (Status &status) { status.crc_error = true; @@ -616,24 +497,24 @@ void WD1770::posit_event(Event new_event_type) { goto wait_for_command; } WAIT_FOR_BYTES(1); - if(is_double_density_) { + if(get_is_double_density()) { WAIT_FOR_BYTES(11); } - data_mode_ = DataMode::Writing; + set_data_mode(DataMode::Writing); begin_writing(); - for(int c = 0; c < (is_double_density_ ? 12 : 6); c++) { + for(int c = 0; c < (get_is_double_density() ? 12 : 6); c++) { write_byte(0); } WAIT_FOR_EVENT(Event::DataWritten); - if(is_double_density_) { - crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue); + if(get_is_double_density()) { + get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue); for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync); write_byte((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte); } else { - crc_generator_.reset(); - crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte); + get_crc_generator().reset(); + get_crc_generator().add((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte); write_raw_short((command_&0x01) ? Storage::Encodings::MFM::FMDeletedDataAddressMark : Storage::Encodings::MFM::FMDataAddressMark); } @@ -669,11 +550,8 @@ void WD1770::posit_event(Event new_event_type) { goto type2_write_loop; - type2_write_crc: { - uint16_t crc = crc_generator_.get_value(); - write_byte(crc >> 8); - write_byte(crc & 0xff); - } + type2_write_crc: + write_crc(); write_byte(0xff); WAIT_FOR_EVENT(Event::DataWritten); end_writing(); @@ -712,7 +590,7 @@ void WD1770::posit_event(Event new_event_type) { begin_type3_load_head: set_head_load_request(true); if(head_is_loaded_) goto type3_test_delay; - WAIT_FOR_EVENT(Event::HeadLoad); + WAIT_FOR_EVENT(Event1770::HeadLoad); goto type3_test_delay; begin_type3_spin_up: @@ -733,17 +611,17 @@ void WD1770::posit_event(Event new_event_type) { distance_into_section_ = 0; read_address_get_header: - WAIT_FOR_EVENT(Event::IndexHole | Event::Token); - if(new_event_type == Event::Token) { - if(!distance_into_section_ && latest_token_.type == Token::ID) {data_mode_ = DataMode::Reading; distance_into_section_++; } - else if(distance_into_section_ && distance_into_section_ < 7 && latest_token_.type == Token::Byte) { + WAIT_FOR_EVENT((int)Event::IndexHole | (int)Event::Token); + if(new_event_type == (int)Event::Token) { + if(!distance_into_section_ && get_latest_token().type == Token::ID) {set_data_mode(DataMode::Reading); distance_into_section_++; } + else if(distance_into_section_ && distance_into_section_ < 7 && get_latest_token().type == Token::Byte) { if(status_.data_request) { update_status([] (Status &status) { status.lost_data = true; }); goto wait_for_command; } - header_[distance_into_section_ - 1] = data_ = latest_token_.byte_value; + header_[distance_into_section_ - 1] = data_ = get_latest_token().byte_value; track_ = header_[0]; update_status([] (Status &status) { status.data_request = true; @@ -751,7 +629,7 @@ void WD1770::posit_event(Event new_event_type) { distance_into_section_++; if(distance_into_section_ == 7) { - if(crc_generator_.get_value()) { + if(get_crc_generator().get_value()) { update_status([] (Status &status) { status.crc_error = true; }); @@ -774,7 +652,7 @@ void WD1770::posit_event(Event new_event_type) { index_hole_count_ = 0; read_track_read_byte: - WAIT_FOR_EVENT(Event::Token | Event::IndexHole); + WAIT_FOR_EVENT((int)Event::Token | (int)Event::IndexHole); if(index_hole_count_) { goto wait_for_command; } @@ -784,7 +662,7 @@ void WD1770::posit_event(Event new_event_type) { }); goto wait_for_command; } - data_ = latest_token_.byte_value; + data_ = get_latest_token().byte_value; update_status([] (Status &status) { status.data_request = true; }); @@ -815,25 +693,23 @@ void WD1770::posit_event(Event new_event_type) { goto wait_for_command; } - WAIT_FOR_EVENT(Event::IndexHoleTarget); + WAIT_FOR_EVENT(Event1770::IndexHoleTarget); begin_writing(); index_hole_count_ = 0; write_track_write_loop: - if(is_double_density_) { + if(get_is_double_density()) { switch(data_) { case 0xf5: write_raw_short(Storage::Encodings::MFM::MFMSync); - crc_generator_.set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue); + get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue); break; case 0xf6: write_raw_short(Storage::Encodings::MFM::MFMIndexSync); break; - case 0xff: { - uint16_t crc = crc_generator_.get_value(); - write_byte(crc >> 8); - write_byte(crc & 0xff); - } break; + case 0xff: + write_crc(); + break; default: write_byte(data_); break; @@ -856,17 +732,15 @@ void WD1770::posit_event(Event new_event_type) { (data_ & 0x01) ) ); - crc_generator_.reset(); - crc_generator_.add(data_); + get_crc_generator().reset(); + get_crc_generator().add(data_); break; case 0xfc: write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark); break; - case 0xf7: { - uint16_t crc = crc_generator_.get_value(); - write_byte(crc >> 8); - write_byte(crc & 0xff); - } break; + case 0xf7: + write_crc(); + break; default: write_byte(data_); break; @@ -910,27 +784,5 @@ void WD1770::set_head_load_request(bool head_load) {} void WD1770::set_head_loaded(bool head_loaded) { head_is_loaded_ = head_loaded; - if(head_loaded) posit_event(Event::HeadLoad); -} - -void WD1770::write_bit(int bit) { - if(is_double_density_) { - Controller::write_bit(!bit && !last_bit_); - Controller::write_bit(!!bit); - last_bit_ = bit; - } else { - Controller::write_bit(true); - Controller::write_bit(!!bit); - } -} - -void WD1770::write_byte(uint8_t byte) { - for(int c = 0; c < 8; c++) write_bit((byte << c)&0x80); - crc_generator_.add(byte); -} - -void WD1770::write_raw_short(uint16_t value) { - for(int c = 0; c < 16; c++) { - Controller::write_bit(!!((value << c)&0x8000)); - } + if(head_loaded) posit_event((int)Event1770::HeadLoad); } diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index bcb13a05b..9d3f46617 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -9,8 +9,7 @@ #ifndef _770_hpp #define _770_hpp -#include "../../Storage/Disk/DiskController.hpp" -#include "../../NumberTheory/CRC.hpp" +#include "../../Storage/Disk/MFMDiskController.hpp" namespace WD { @@ -18,7 +17,7 @@ namespace WD { Provides an emulation of various Western Digital drive controllers, including the WD1770, WD1772, FDC1773 and FDC1793. */ -class WD1770: public Storage::Disk::Controller { +class WD1770: public Storage::Disk::MFMController { public: enum Personality { P1770, // implies automatic motor-on management, with Type 2 commands offering a spin-up disable @@ -34,7 +33,7 @@ class WD1770: public Storage::Disk::Controller { WD1770(Personality p); /// Sets the value of the double-density input; when @c is_double_density is @c true, reads and writes double-density format data. - void set_is_double_density(bool is_double_density); + using Storage::Disk::MFMController::set_is_double_density; /// Writes @c value to the register at @c address. Only the low two bits of the address are decoded. void set_register(int address, uint8_t value); @@ -107,66 +106,31 @@ class WD1770: public Storage::Disk::Controller { int index_hole_count_; int index_hole_count_target_; - int bits_since_token_; int distance_into_section_; - bool is_awaiting_marker_value_; int step_direction_; void update_status(std::function updater); - // Tokeniser - enum DataMode { - Scanning, - Reading, - Writing - } data_mode_; - bool is_double_density_; - int shift_register_; - struct Token { - enum Type { - Index, ID, Data, DeletedData, Sync, Byte - } type; - uint8_t byte_value; - } latest_token_; - // Events - enum Event: int { - Command = (1 << 0), // Indicates receipt of a new command. - Token = (1 << 1), // Indicates recognition of a new token in the flux stream. Interrogate latest_token_ for details. - IndexHole = (1 << 2), // Indicates the passing of a physical index hole. - HeadLoad = (1 << 3), // Indicates the head has been loaded (1973 only). - DataWritten = (1 << 4), // Indicates that all queued bits have been written - + enum Event1770: int { + Command = (1 << 3), // Indicates receipt of a new command. + HeadLoad = (1 << 4), // Indicates the head has been loaded (1973 only). Timer = (1 << 5), // Indicates that the delay_time_-powered timer has timed out. IndexHoleTarget = (1 << 6) // Indicates that index_hole_count_ has reached index_hole_count_target_. }; - void posit_event(Event type); + void posit_event(int type); int interesting_event_mask_; int resume_point_; unsigned int delay_time_; - // Output - int last_bit_; - void write_bit(int bit); - void write_byte(uint8_t byte); - void write_raw_short(uint16_t value); - // ID buffer uint8_t header_[6]; - // CRC generator - NumberTheory::CRC16 crc_generator_; - // 1793 head-loading logic bool head_is_loaded_; // delegate Delegate *delegate_; - - // Storage::Disk::Controller - virtual void process_input_bit(int value, unsigned int cycles_since_index_hole); - virtual void process_index_hole(); - virtual void process_write_completed(); }; } diff --git a/Components/8272/i8272.cpp b/Components/8272/i8272.cpp index eb23cf694..567de01d7 100644 --- a/Components/8272/i8272.cpp +++ b/Components/8272/i8272.cpp @@ -427,39 +427,11 @@ void i8272::posit_event(int event_type) { write_data_found_header: begin_writing(); - if(get_is_double_density()) { - for(int c = 0; c < 50; c++) { - write_byte(0x4e); - } - for(int c = 0; c < 12; c++) { - write_byte(0x00); - } - } else { - for(int c = 0; c < 11; c++) { - write_byte(0xff); - } - for(int c = 0; c < 6; c++) { - write_byte(0x00); - } - } - - WAIT_FOR_EVENT(Event::DataWritten); - - { - bool is_deleted = (command_[0] & 0x1f) == 0x09; - if(get_is_double_density()) { - get_crc_generator().set_value(Storage::Encodings::MFM::MFMPostSyncCRCValue); - for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMSync); - write_byte(is_deleted ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte); - } else { - 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); - } - } + write_id_data_joiner((command_[0] & 0x1f) == 0x09); SetDataDirectionFromProcessor(); SetDataRequest(); + WAIT_FOR_EVENT(Event::DataWritten); expects_input_ = true; distance_into_section_ = 0; @@ -571,32 +543,12 @@ void i8272::posit_event(int event_type) { begin_writing(); // Write start-of-track. - if(get_is_double_density()) { - for(int c = 0; c < 80; c++) write_byte(0x4e); - for(int c = 0; c < 12; c++) write_byte(0x00); - for(int c = 0; c < 3; c++) write_raw_short(Storage::Encodings::MFM::MFMIndexSync); - write_byte(Storage::Encodings::MFM::IndexAddressByte); - for(int c = 0; c < 50; c++) write_byte(0x4e); - } else { - for(int c = 0; c < 40; c++) write_byte(0xff); - for(int c = 0; c < 6; c++) write_byte(0x00); - write_raw_short(Storage::Encodings::MFM::FMIndexAddressMark); - for(int c = 0; c < 26; c++) write_byte(0xff); - } + write_start_of_track(); WAIT_FOR_EVENT(Event::DataWritten); sector_ = 0; format_track_write_sector: - if(get_is_double_density()) { - for(int c = 0; c < 12; c++) write_byte(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 { - for(int c = 0; c < 6; c++) write_byte(0x00); - get_crc_generator().reset(); - write_raw_short(Storage::Encodings::MFM::FMIDAddressMark); - } + write_id_joiner(); // Write the sector header, obtaining its contents // from the processor. @@ -618,29 +570,12 @@ void i8272::posit_event(int event_type) { write_crc(); // Write the sector body. - if(get_is_double_density()) { - for(int c = 0; c < 22; c++) write_byte(0x4e); - for(int c = 0; c < 12; c++) write_byte(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::DataAddressByte); - } else { - for(int c = 0; c < 11; c++) write_byte(0xff); - for(int c = 0; c < 6; c++) write_byte(0x00); - get_crc_generator().reset(); - write_raw_short(Storage::Encodings::MFM::FMDataAddressMark); - } - for(int c = 0; c < (128 << command_[2]); c++) { - write_byte(command_[5]); - } + write_id_data_joiner(false); + write_n_bytes(128 << command_[2], command_[5]); write_crc(); // Write the prescribed gap. - if(get_is_double_density()) { - for(int c = 0; c < command_[4]; c++) write_byte(0x4e); - } else { - for(int c = 0; c < command_[4]; c++) write_byte(0xff); - } + write_n_bytes(command_[4], get_is_double_density() ? 0x4e : 0xff); // Consider repeating. sector_++; diff --git a/Components/8272/i8272.hpp b/Components/8272/i8272.hpp index 61729874a..deae4e56c 100644 --- a/Components/8272/i8272.hpp +++ b/Components/8272/i8272.hpp @@ -10,7 +10,6 @@ #define i8272_hpp #include "../../Storage/Disk/MFMDiskController.hpp" -#include "../../Storage/Disk/Drive.hpp" #include #include diff --git a/Storage/Disk/MFMDiskController.cpp b/Storage/Disk/MFMDiskController.cpp index 51f4ac3b2..4b30c8ff6 100644 --- a/Storage/Disk/MFMDiskController.cpp +++ b/Storage/Disk/MFMDiskController.cpp @@ -181,3 +181,59 @@ void MFMController::write_crc() { 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) { + if(get_is_double_density()) { + 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 { + 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); + } +} diff --git a/Storage/Disk/MFMDiskController.hpp b/Storage/Disk/MFMDiskController.hpp index 4ace6665e..b5bef5bd2 100644 --- a/Storage/Disk/MFMDiskController.hpp +++ b/Storage/Disk/MFMDiskController.hpp @@ -113,6 +113,36 @@ class MFMController: public Controller { */ void write_crc(); + /*! + Calls @c write_byte with @c value, @c quantity times. + */ + void write_n_bytes(int quantity, uint8_t value); + + /*! + Writes everything that should, per the spec, appear prior to the address contained + in an ID mark — proper gaps and the ID mark — and appropriate seeds the CRC generator. + */ + void write_id_joiner(); + + /*! + Writes everything that should, per the spec, appear after the ID's CRC, up to and + including the mark that indicates the beginning of data, appropriately seeding + the CRC generator. + */ + void write_id_data_joiner(bool is_deleted); + + /*! + Writes the gap expected after a sector's data CRC and before the beginning of the + next ID joiner. + */ + void write_post_data_gap(); + + /*! + Writes everything that should, per the spec, following the index hole and prior + to any sectors. + */ + void write_start_of_track(); + private: // Storage::Disk::Controller virtual void process_input_bit(int value, unsigned int cycles_since_index_hole);