From 8eb21c67022d4582032d282c8643547fba9a3bf9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 31 Dec 2016 15:25:11 -0500 Subject: [PATCH 1/2] The "MFM...Byte"s aren't MFM-specific, they're relevant to both FM and MFM encoding. So renamed them. Also slimmed syntax within MFM.cpp mostly where emigration from the Acorn disk analyser had left a residue of lengthy namespace specification. --- Components/1770/1770.cpp | 20 ++++++------- Storage/Disk/Encodings/MFM.cpp | 54 +++++++++++++++++----------------- Storage/Disk/Encodings/MFM.hpp | 15 +++++----- 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 668fff112..70e23637c 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -175,22 +175,22 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole) case Storage::Encodings::MFM::FMIndexAddressMark: token_type = Token::Index; crc_generator_.reset(); - crc_generator_.add(Storage::Encodings::MFM::MFMIndexAddressByte); + crc_generator_.add(Storage::Encodings::MFM::IndexAddressByte); break; case Storage::Encodings::MFM::FMIDAddressMark: token_type = Token::ID; crc_generator_.reset(); - crc_generator_.add(Storage::Encodings::MFM::MFMIDAddressByte); + crc_generator_.add(Storage::Encodings::MFM::IDAddressByte); break; case Storage::Encodings::MFM::FMDataAddressMark: token_type = Token::Data; crc_generator_.reset(); - crc_generator_.add(Storage::Encodings::MFM::MFMDataAddressByte); + crc_generator_.add(Storage::Encodings::MFM::DataAddressByte); break; case Storage::Encodings::MFM::FMDeletedDataAddressMark: token_type = Token::DeletedData; crc_generator_.reset(); - crc_generator_.add(Storage::Encodings::MFM::MFMDeletedDataAddressByte); + crc_generator_.add(Storage::Encodings::MFM::DeletedDataAddressByte); break; default: break; @@ -242,16 +242,16 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole) is_awaiting_marker_value_ = false; switch(latest_token_.byte_value) { - case Storage::Encodings::MFM::MFMIndexAddressByte: + case Storage::Encodings::MFM::IndexAddressByte: latest_token_.type = Token::Index; break; - case Storage::Encodings::MFM::MFMIDAddressByte: + case Storage::Encodings::MFM::IDAddressByte: latest_token_.type = Token::ID; break; - case Storage::Encodings::MFM::MFMDataAddressByte: + case Storage::Encodings::MFM::DataAddressByte: latest_token_.type = Token::Data; break; - case Storage::Encodings::MFM::MFMDeletedDataAddressByte: + case Storage::Encodings::MFM::DeletedDataAddressByte: latest_token_.type = Token::DeletedData; break; default: break; @@ -662,12 +662,12 @@ void WD1770::posit_event(Event new_event_type) { 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::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte); + write_byte((command_&0x01) ? Storage::Encodings::MFM::DeletedDataAddressByte : Storage::Encodings::MFM::DataAddressByte); } else { crc_generator_.reset(); - crc_generator_.add((command_&0x01) ? Storage::Encodings::MFM::MFMDeletedDataAddressByte : Storage::Encodings::MFM::MFMDataAddressByte); + 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); } diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index 007fd0110..4b845f129 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -37,22 +37,22 @@ class MFMEncoder: public Encoder { void add_index_address_mark() { for(int c = 0; c < 3; c++) output_short(MFMIndexSync); - add_byte(MFMIndexAddressByte); + add_byte(IndexAddressByte); } void add_ID_address_mark() { output_sync(); - add_byte(MFMIDAddressByte); + add_byte(IDAddressByte); } void add_data_address_mark() { output_sync(); - add_byte(MFMDataAddressByte); + add_byte(DataAddressByte); } void add_deleted_data_address_mark() { output_sync(); - add_byte(MFMDeletedDataAddressByte); + add_byte(DeletedDataAddressByte); } private: @@ -92,28 +92,28 @@ class FMEncoder: public Encoder { void add_index_address_mark() { crc_generator_.reset(); - crc_generator_.add(MFMIndexAddressByte); + crc_generator_.add(IndexAddressByte); output_short(FMIndexAddressMark); } void add_ID_address_mark() { crc_generator_.reset(); - crc_generator_.add(MFMIDAddressByte); + crc_generator_.add(IDAddressByte); output_short(FMIDAddressMark); } void add_data_address_mark() { crc_generator_.reset(); - crc_generator_.add(MFMDataAddressByte); + crc_generator_.add(DataAddressByte); output_short(FMDataAddressMark); } void add_deleted_data_address_mark() { crc_generator_.reset(); - crc_generator_.add(MFMDeletedDataAddressByte); + crc_generator_.add(DeletedDataAddressByte); output_short(FMDeletedDataAddressMark); } }; @@ -282,7 +282,7 @@ void Parser::seek_to_track(uint8_t track) } } -std::shared_ptr Parser::get_sector(uint8_t track, uint8_t sector) +std::shared_ptr Parser::get_sector(uint8_t track, uint8_t sector) { seek_to_track(track); return get_sector(sector); @@ -408,9 +408,9 @@ std::vector Parser::get_track() { switch(byte_value) { - case MFMIDAddressByte: found_id = true; break; - case MFMDataAddressByte: - case MFMDeletedDataAddressByte: found_data = true; break; + case IDAddressByte: found_id = true; break; + case DataAddressByte: + case DeletedDataAddressByte: found_data = true; break; } } } @@ -431,9 +431,9 @@ std::vector Parser::get_track() } -std::shared_ptr Parser::get_next_sector() +std::shared_ptr Parser::get_next_sector() { - std::shared_ptr sector(new Storage::Encodings::MFM::Sector); + std::shared_ptr sector(new Sector); index_count_ = 0; while(index_count_ < 2) @@ -445,10 +445,10 @@ std::shared_ptr Parser::get_next_sector() run_for_cycles(1); if(is_mfm_) { - while(shift_register_ == Storage::Encodings::MFM::MFMSync) + while(shift_register_ == MFMSync) { uint8_t mark = get_next_byte(); - if(mark == Storage::Encodings::MFM::MFMIDAddressByte) + if(mark == IDAddressByte) { crc_generator_.set_value(MFMPostSyncCRCValue); id_found = true; @@ -458,7 +458,7 @@ std::shared_ptr Parser::get_next_sector() } else { - if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) + if(shift_register_ == FMIDAddressMark) { crc_generator_.reset(); id_found = true; @@ -467,7 +467,7 @@ std::shared_ptr Parser::get_next_sector() if(index_count_ >= 2) return nullptr; } - crc_generator_.add(MFMIDAddressByte); + crc_generator_.add(IDAddressByte); sector->track = get_next_byte(); sector->side = get_next_byte(); sector->sector = get_next_byte(); @@ -483,30 +483,30 @@ std::shared_ptr Parser::get_next_sector() run_for_cycles(1); if(is_mfm_) { - while(shift_register_ == Storage::Encodings::MFM::MFMSync) + while(shift_register_ == MFMSync) { uint8_t mark = get_next_byte(); - if(mark == Storage::Encodings::MFM::MFMDataAddressByte) + if(mark == DataAddressByte) { crc_generator_.set_value(MFMPostSyncCRCValue); data_found = true; break; } - if(mark == Storage::Encodings::MFM::MFMIDAddressByte) return nullptr; + if(mark == IDAddressByte) return nullptr; } } else { - if(shift_register_ == Storage::Encodings::MFM::FMDataAddressMark) + if(shift_register_ == FMDataAddressMark) { crc_generator_.reset(); data_found = true; } - if(shift_register_ == Storage::Encodings::MFM::FMIDAddressMark) return nullptr; + if(shift_register_ == FMIDAddressMark) return nullptr; } if(index_count_ >= 2) return nullptr; } - crc_generator_.add(MFMDataAddressByte); + crc_generator_.add(DataAddressByte); size_t data_size = (size_t)(128 << size); sector->data.reserve(data_size); @@ -524,9 +524,9 @@ std::shared_ptr Parser::get_next_sector() return nullptr; } -std::shared_ptr Parser::get_sector(uint8_t sector) +std::shared_ptr Parser::get_sector(uint8_t sector) { - std::shared_ptr first_sector; + std::shared_ptr first_sector; index_count_ = 0; while(!first_sector && index_count_ < 2) first_sector = get_next_sector(); if(!first_sector) return first_sector; @@ -534,7 +534,7 @@ std::shared_ptr Parser::get_sector(uint8_t sect while(1) { - std::shared_ptr next_sector = get_next_sector(); + std::shared_ptr next_sector = get_next_sector(); if(!next_sector) continue; if(next_sector->sector == first_sector->sector) return nullptr; if(next_sector->sector == sector) return next_sector; diff --git a/Storage/Disk/Encodings/MFM.hpp b/Storage/Disk/Encodings/MFM.hpp index c542f3154..ed63c02d4 100644 --- a/Storage/Disk/Encodings/MFM.hpp +++ b/Storage/Disk/Encodings/MFM.hpp @@ -19,18 +19,19 @@ namespace Storage { namespace Encodings { namespace MFM { +const uint8_t IndexAddressByte = 0xfc; +const uint8_t IDAddressByte = 0xfe; +const uint8_t DataAddressByte = 0xfb; +const uint8_t DeletedDataAddressByte = 0xf8; + const uint16_t FMIndexAddressMark = 0xf77a; // data 0xfc, with clock 0xd7 => 1111 1100 with clock 1101 0111 => 1111 0111 0111 1010 const uint16_t FMIDAddressMark = 0xf57e; // data 0xfe, with clock 0xc7 => 1111 1110 with clock 1100 0111 => 1111 0101 0111 1110 const uint16_t FMDataAddressMark = 0xf56f; // data 0xfb, with clock 0xc7 => 1111 1011 with clock 1100 0111 => 1111 0101 0110 1111 const uint16_t FMDeletedDataAddressMark = 0xf56a; // data 0xf8, with clock 0xc7 => 1111 1000 with clock 1100 0111 => 1111 0101 0110 1010 -const uint16_t MFMIndexSync = 0x5224; -const uint16_t MFMSync = 0x4489; -const uint8_t MFMIndexAddressByte = 0xfc; -const uint8_t MFMIDAddressByte = 0xfe; -const uint8_t MFMDataAddressByte = 0xfb; -const uint8_t MFMDeletedDataAddressByte = 0xf8; -const uint16_t MFMPostSyncCRCValue = 0xcdb4; +const uint16_t MFMIndexSync = 0x5224; // data 0xc2, with a missing clock at 0x0080 => 0101 0010 1010 0100 without 1000 0000 +const uint16_t MFMSync = 0x4489; // data 0xa1, with a missing clock at 0x0020 => 0100 0100 1010 1001 without 0010 0000 +const uint16_t MFMPostSyncCRCValue = 0xcdb4; // the value the CRC generator should have after encountering three 0xa1s struct Sector { uint8_t track, side, sector; From b3c33d993a6360f10382080398dbebcd6d6493db Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 31 Dec 2016 15:30:48 -0500 Subject: [PATCH 2/2] Made an attempt to explain the requirements placed upon `Disk` subclasses that wish to support writing. --- Storage/Disk/Disk.hpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp index f574f2c28..c1d97d115 100644 --- a/Storage/Disk/Disk.hpp +++ b/Storage/Disk/Disk.hpp @@ -115,13 +115,30 @@ class Disk { */ virtual std::shared_ptr get_uncached_track_at_position(unsigned int head, unsigned int position) = 0; + /*! + Subclasses that support writing should implement @c store_updated_track_at_position to determine which bytes + have to be written from @c track, then obtain @c file_access_mutex and write new data to their file to represent + the track underneath @c head at @c position. + The base class will ensure that calls are made to @c get_uncached_track_at_position only while it holds @c file_access_mutex; + that mutex therefore provides serialisation of file access. + + This method will be called asynchronously. Subclasses are responsible for any synchronisation other than that + provided automatically via @c file_access_mutex. + */ virtual void store_updated_track_at_position(unsigned int head, unsigned int position, const std::shared_ptr &track, std::mutex &file_access_mutex); + + /*! + Subclasses that support writing should call @c flush_updates during their destructor if there is anything they + do in @c store_updated_track_at_position that would not be valid after their destructor has completed but prior + to Disk's constructor running. + */ void flush_updates(); private: - std::map> cached_tracks_; int get_id_for_track_at_position(unsigned int head, unsigned int position); + std::map> cached_tracks_; + std::mutex file_access_mutex_; std::unique_ptr update_queue_; };