diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 43f59df80..cbb1748fd 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -7,7 +7,7 @@ // #include "1770.hpp" -#include "../../Storage/Disk/Encodings/MFM.hpp" +#include "../../Storage/Disk/Encodings/MFM/MFM.hpp" using namespace WD; diff --git a/Components/8272/i8272.cpp b/Components/8272/i8272.cpp index e61b16f1b..fe14eb8f8 100644 --- a/Components/8272/i8272.cpp +++ b/Components/8272/i8272.cpp @@ -7,7 +7,7 @@ // #include "i8272.hpp" -#include "../../Storage/Disk/Encodings/MFM.hpp" +#include "../../Storage/Disk/Encodings/MFM/MFM.hpp" #include diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3e6372eab..c6b02dab1 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -94,6 +94,8 @@ 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; 4B6A4C991F58F09E00E3F787 /* 6502Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C951F58F09E00E3F787 /* 6502Base.cpp */; }; + 4B7136861F78724F008B8ED9 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136841F78724F008B8ED9 /* MFM.cpp */; }; + 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; }; 4B7913CC1DFCD80E00175A82 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7913CA1DFCD80E00175A82 /* Video.cpp */; }; 4B79E4441E3AF38600141F11 /* cassette.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B79E4411E3AF38600141F11 /* cassette.png */; }; 4B79E4451E3AF38600141F11 /* floppy35.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B79E4421E3AF38600141F11 /* floppy35.png */; }; @@ -448,7 +450,6 @@ 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AA91D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm */; }; 4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */; }; 4BF1354C1D6D2C300054B2EA /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF1354A1D6D2C300054B2EA /* StaticAnalyser.cpp */; }; - 4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295B1D8F048B001BAE39 /* MFM.cpp */; }; 4BF829661D8F732B001BAE39 /* Disk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF829641D8F732B001BAE39 /* Disk.cpp */; }; 4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */; }; 4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA1261ECBE33200AC40C1 /* TestMachineZ80.mm */; }; @@ -647,6 +648,11 @@ 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502AllRAM.cpp; sourceTree = ""; }; 4B6A4C921F58F09E00E3F787 /* 6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6502AllRAM.hpp; sourceTree = ""; }; 4B6A4C951F58F09E00E3F787 /* 6502Base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502Base.cpp; sourceTree = ""; }; + 4B7136841F78724F008B8ED9 /* MFM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MFM.cpp; sourceTree = ""; }; + 4B7136851F78724F008B8ED9 /* MFM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MFM.hpp; sourceTree = ""; }; + 4B7136871F78725F008B8ED9 /* Shifter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Shifter.cpp; sourceTree = ""; }; + 4B7136881F78725F008B8ED9 /* Shifter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Shifter.hpp; sourceTree = ""; }; + 4B71368A1F787349008B8ED9 /* Constants.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Constants.hpp; sourceTree = ""; }; 4B77069C1EC904570053B588 /* Z80.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Z80.hpp; path = Z80/Z80.hpp; sourceTree = ""; }; 4B7913CA1DFCD80E00175A82 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = Electron/Video.cpp; sourceTree = ""; }; 4B7913CB1DFCD80E00175A82 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = Electron/Video.hpp; sourceTree = ""; }; @@ -1094,8 +1100,6 @@ 4BF4A2D91F534DB300B171F4 /* TargetPlatforms.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TargetPlatforms.hpp; sourceTree = ""; }; 4BF4A2DA1F5365C600B171F4 /* CSZX8081+Instantiation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CSZX8081+Instantiation.h"; sourceTree = ""; }; 4BF6606A1F281573002CB053 /* ClockReceiver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ClockReceiver.hpp; sourceTree = ""; }; - 4BF8295B1D8F048B001BAE39 /* MFM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MFM.cpp; path = Encodings/MFM.cpp; sourceTree = ""; }; - 4BF8295C1D8F048B001BAE39 /* MFM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = MFM.hpp; path = Encodings/MFM.hpp; sourceTree = ""; }; 4BF8295F1D8F3C87001BAE39 /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRC.hpp; path = ../../NumberTheory/CRC.hpp; sourceTree = ""; }; 4BF829641D8F732B001BAE39 /* Disk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Disk.cpp; path = ../../StaticAnalyser/Acorn/Disk.cpp; sourceTree = ""; }; 4BF829651D8F732B001BAE39 /* Disk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Disk.hpp; path = ../../StaticAnalyser/Acorn/Disk.hpp; sourceTree = ""; }; @@ -1651,6 +1655,19 @@ path = Implementation; sourceTree = ""; }; + 4B7136831F78724F008B8ED9 /* MFM */ = { + isa = PBXGroup; + children = ( + 4B7136841F78724F008B8ED9 /* MFM.cpp */, + 4B7136851F78724F008B8ED9 /* MFM.hpp */, + 4B7136871F78725F008B8ED9 /* Shifter.cpp */, + 4B7136881F78725F008B8ED9 /* Shifter.hpp */, + 4B71368A1F787349008B8ED9 /* Constants.hpp */, + ); + name = MFM; + path = Encodings/MFM; + sourceTree = ""; + }; 4B77069E1EC9045B0053B588 /* Z80 */ = { isa = PBXGroup; children = ( @@ -2018,10 +2035,9 @@ 4BB697CF1D4BA44900248BDF /* Encodings */ = { isa = PBXGroup; children = ( + 4B7136831F78724F008B8ED9 /* MFM */, 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */, 4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */, - 4BF8295B1D8F048B001BAE39 /* MFM.cpp */, - 4BF8295C1D8F048B001BAE39 /* MFM.hpp */, ); name = Encodings; sourceTree = ""; @@ -2853,6 +2869,7 @@ 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, 4B59199C1DAC6C46005BB85C /* OricTAP.cpp in Sources */, 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */, + 4B7136861F78724F008B8ED9 /* MFM.cpp in Sources */, 4B448E841F1C4C480009ABD6 /* PulseQueuedTape.cpp in Sources */, 4BD14B111D74627C0088EAD6 /* StaticAnalyser.cpp in Sources */, 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, @@ -2908,7 +2925,6 @@ 4B8334841F5DA0360097E338 /* Z80Storage.cpp in Sources */, 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */, 4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */, - 4BF8295D1D8F048B001BAE39 /* MFM.cpp in Sources */, 4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */, 4B14978B1EE4AC5E00CE2596 /* StaticAnalyser.cpp in Sources */, 4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */, @@ -2955,6 +2971,7 @@ 4BEA52661DF3472B007E74F2 /* Speaker.cpp in Sources */, 4BBFBB6C1EE8401E00C01E7A /* ZX8081.cpp in Sources */, 4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */, + 4B7136891F78725F008B8ED9 /* Shifter.cpp in Sources */, 4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */, 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, diff --git a/StaticAnalyser/Acorn/Disk.cpp b/StaticAnalyser/Acorn/Disk.cpp index a7c262d59..9cbb215dd 100644 --- a/StaticAnalyser/Acorn/Disk.cpp +++ b/StaticAnalyser/Acorn/Disk.cpp @@ -8,7 +8,7 @@ #include "Disk.hpp" #include "../../Storage/Disk/Controller/DiskController.hpp" -#include "../../Storage/Disk/Encodings/MFM.hpp" +#include "../../Storage/Disk/Encodings/MFM/MFM.hpp" #include "../../NumberTheory/CRC.hpp" #include diff --git a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp index ea416d26a..779bc4c75 100644 --- a/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp +++ b/StaticAnalyser/AmstradCPC/StaticAnalyser.cpp @@ -9,7 +9,7 @@ #include "StaticAnalyser.hpp" #include "../../Storage/Disk/Parsers/CPM.hpp" -#include "../../Storage/Disk/Encodings/MFM.hpp" +#include "../../Storage/Disk/Encodings/MFM/MFM.hpp" static bool strcmp_insensitive(const char *a, const char *b) { if(strlen(a) != strlen(b)) return false; diff --git a/Storage/Disk/Controller/MFMDiskController.cpp b/Storage/Disk/Controller/MFMDiskController.cpp index e98878776..e8c273e0a 100644 --- a/Storage/Disk/Controller/MFMDiskController.cpp +++ b/Storage/Disk/Controller/MFMDiskController.cpp @@ -8,7 +8,7 @@ #include "MFMDiskController.hpp" -#include "../Encodings/MFM.hpp" +#include "../Encodings/MFM/MFM.hpp" using namespace Storage::Disk; @@ -16,7 +16,7 @@ MFMController::MFMController(Cycles clock_rate) : Storage::Disk::Controller(clock_rate), crc_generator_(0x1021, 0xffff), data_mode_(DataMode::Scanning), - is_awaiting_marker_value_(false) { + shifter_(&crc_generator_) { } void MFMController::process_index_hole() { @@ -34,7 +34,7 @@ void MFMController::set_is_double_density(bool is_double_density) { bit_length.clock_rate = is_double_density ? 500000 : 250000; set_expected_bit_length(bit_length); - if(!is_double_density) is_awaiting_marker_value_ = false; + shifter_.set_is_double_density(is_double_density); } bool MFMController::get_is_double_density() { @@ -43,6 +43,7 @@ bool MFMController::get_is_double_density() { void MFMController::set_data_mode(DataMode mode) { data_mode_ = mode; + shifter_.set_should_obey_syncs(mode == DataMode::Scanning); } MFMController::Token MFMController::get_latest_token() { @@ -56,102 +57,32 @@ NumberTheory::CRC16 &MFMController::get_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); + shifter_.add_input_bit(value); + switch(shifter_.get_token()) { + case Encodings::MFM::Shifter::Token::None: return; + + 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; } + latest_token_.byte_value = shifter_.get_byte(); + posit_event((int)Event::Token); } void MFMController::write_bit(int bit) { diff --git a/Storage/Disk/Controller/MFMDiskController.hpp b/Storage/Disk/Controller/MFMDiskController.hpp index e90360ca0..372f04a93 100644 --- a/Storage/Disk/Controller/MFMDiskController.hpp +++ b/Storage/Disk/Controller/MFMDiskController.hpp @@ -12,6 +12,7 @@ #include "DiskController.hpp" #include "../../../NumberTheory/CRC.hpp" #include "../../../ClockReceiver/ClockReceiver.hpp" +#include "../Encodings/MFM/Shifter.hpp" namespace Storage { namespace Disk { @@ -150,18 +151,14 @@ class MFMController: public Controller { virtual void process_index_hole(); virtual void process_write_completed(); - // PLL input state - int bits_since_token_; - int shift_register_; - bool is_awaiting_marker_value_; + // Reading state. + Token latest_token_; + Encodings::MFM::Shifter shifter_; // input configuration bool is_double_density_; DataMode data_mode_; - // output - Token latest_token_; - // writing int last_bit_; diff --git a/Storage/Disk/DiskImage/Formats/AcornADF.cpp b/Storage/Disk/DiskImage/Formats/AcornADF.cpp index 3bc3917b8..6066699d3 100644 --- a/Storage/Disk/DiskImage/Formats/AcornADF.cpp +++ b/Storage/Disk/DiskImage/Formats/AcornADF.cpp @@ -9,7 +9,7 @@ #include "AcornADF.hpp" #include -#include "../../Encodings/MFM.hpp" +#include "../../Encodings/MFM/MFM.hpp" namespace { static const unsigned int sectors_per_track = 16; diff --git a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp index 84fc4e2fc..31c6e1e28 100644 --- a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp @@ -8,7 +8,7 @@ #include "CPCDSK.hpp" -#include "../../Encodings/MFM.hpp" +#include "../../Encodings/MFM/MFM.hpp" using namespace Storage::Disk; diff --git a/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp b/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp index 3640176e1..db18a8b15 100644 --- a/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/OricMFMDSK.cpp @@ -9,7 +9,7 @@ #include "OricMFMDSK.hpp" #include "../../Track/PCMTrack.hpp" -#include "../../Encodings/MFM.hpp" +#include "../../Encodings/MFM/MFM.hpp" using namespace Storage::Disk; diff --git a/Storage/Disk/DiskImage/Formats/SSD.cpp b/Storage/Disk/DiskImage/Formats/SSD.cpp index fd6e54fdd..a3c9adff4 100644 --- a/Storage/Disk/DiskImage/Formats/SSD.cpp +++ b/Storage/Disk/DiskImage/Formats/SSD.cpp @@ -8,7 +8,7 @@ #include "SSD.hpp" -#include "../../Encodings/MFM.hpp" +#include "../../Encodings/MFM/MFM.hpp" using namespace Storage::Disk; diff --git a/Storage/Disk/Encodings/MFM/Constants.hpp b/Storage/Disk/Encodings/MFM/Constants.hpp new file mode 100644 index 000000000..06fe8a4f1 --- /dev/null +++ b/Storage/Disk/Encodings/MFM/Constants.hpp @@ -0,0 +1,37 @@ +// +// Constants.hpp +// Clock Signal +// +// Created by Thomas Harte on 24/09/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Constants_h +#define Constants_h + +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; // 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 + +const uint8_t MFMIndexSyncByteValue = 0xc2; +const uint8_t MFMSyncByteValue = 0xa1; + +} +} +} + +#endif /* Constants_h */ diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM/MFM.cpp similarity index 99% rename from Storage/Disk/Encodings/MFM.cpp rename to Storage/Disk/Encodings/MFM/MFM.cpp index a0e506249..d4f2096da 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM/MFM.cpp @@ -8,9 +8,9 @@ #include "MFM.hpp" -#include "../Track/PCMTrack.hpp" -#include "../SingleTrackDisk/SingleTrackDisk.hpp" -#include "../../../NumberTheory/CRC.hpp" +#include "../../Track/PCMTrack.hpp" +#include "../../SingleTrackDisk/SingleTrackDisk.hpp" +#include "../../../../NumberTheory/CRC.hpp" #include diff --git a/Storage/Disk/Encodings/MFM.hpp b/Storage/Disk/Encodings/MFM/MFM.hpp similarity index 77% rename from Storage/Disk/Encodings/MFM.hpp rename to Storage/Disk/Encodings/MFM/MFM.hpp index 8d59ce63e..2431e4f97 100644 --- a/Storage/Disk/Encodings/MFM.hpp +++ b/Storage/Disk/Encodings/MFM/MFM.hpp @@ -11,31 +11,15 @@ #include #include -#include "../Disk.hpp" -#include "../Controller/DiskController.hpp" -#include "../../../NumberTheory/CRC.hpp" +#include "Constants.hpp" +#include "../../Disk.hpp" +#include "../../Controller/DiskController.hpp" +#include "../../../../NumberTheory/CRC.hpp" 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; // 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 - -const uint8_t MFMIndexSyncByteValue = 0xc2; -const uint8_t MFMSyncByteValue = 0xa1; - /*! Represents a single [M]FM sector, identified by its track, side and sector records, a blob of data and a few extra flags of metadata. diff --git a/Storage/Disk/Encodings/MFM/Shifter.cpp b/Storage/Disk/Encodings/MFM/Shifter.cpp new file mode 100644 index 000000000..7f5636063 --- /dev/null +++ b/Storage/Disk/Encodings/MFM/Shifter.cpp @@ -0,0 +1,120 @@ +// +// 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" + +using namespace Storage::Encodings::MFM; + +Shifter::Shifter() : owned_crc_generator_(new NumberTheory::CRC16(0x1021, 0xffff)), crc_generator_(owned_crc_generator_.get()) {} +Shifter::Shifter(NumberTheory::CRC16 *crc_generator) : crc_generator_(crc_generator) {} + +void Shifter::set_is_double_density(bool is_double_density) { + is_double_density_ = is_double_density; + if(!is_double_density) 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) | value; + bits_since_token_++; + + token_ = Token::None; + if(should_obey_syncs_) { + if(!is_double_density_) { + 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: + 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_double_density_) { + 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 (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)); +} diff --git a/Storage/Disk/Encodings/MFM/Shifter.hpp b/Storage/Disk/Encodings/MFM/Shifter.hpp new file mode 100644 index 000000000..54b315b3e --- /dev/null +++ b/Storage/Disk/Encodings/MFM/Shifter.hpp @@ -0,0 +1,59 @@ +// +// Shifter.hpp +// Clock Signal +// +// Created by Thomas Harte on 24/09/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef Shifter_hpp +#define Shifter_hpp + +#include +#include +#include "../../../../NumberTheory/CRC.hpp" + +namespace Storage { +namespace Encodings { +namespace MFM { + +class Shifter { + public: + Shifter(); + Shifter(NumberTheory::CRC16 *crc_generator); + + void set_is_double_density(bool is_double_density); + void set_should_obey_syncs(bool should_obey_syncs); + void add_input_bit(int bit); + + enum Token { + Index, ID, Data, DeletedData, Sync, Byte, None + }; + uint8_t get_byte() const; + Token get_token() const { + return token_; + } + NumberTheory::CRC16 &get_crc_generator() { + return *crc_generator_; + } + + private: + // Bit stream input state + int bits_since_token_ = 0; + int shift_register_ = 0; + bool is_awaiting_marker_value_ = false; + bool should_obey_syncs_; + Token token_; + + // input configuration + bool is_double_density_ = false; + + std::unique_ptr owned_crc_generator_; + NumberTheory::CRC16 *crc_generator_; +}; + +} +} +} + +#endif /* Shifter_hpp */ diff --git a/Storage/Disk/Parsers/CPM.cpp b/Storage/Disk/Parsers/CPM.cpp index c50d58db4..5bc7f650b 100644 --- a/Storage/Disk/Parsers/CPM.cpp +++ b/Storage/Disk/Parsers/CPM.cpp @@ -8,7 +8,7 @@ #include "CPM.hpp" -#include "../Encodings/MFM.hpp" +#include "../Encodings/MFM/MFM.hpp" using namespace Storage::Disk::CPM;