diff --git a/NumberTheory/CRC.cpp b/NumberTheory/CRC.cpp new file mode 100644 index 000000000..2833155fd --- /dev/null +++ b/NumberTheory/CRC.cpp @@ -0,0 +1,11 @@ +// +// CRC.cpp +// Clock Signal +// +// Created by Thomas Harte on 18/09/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "CRC.hpp" + +using namespace NumberTheory; diff --git a/NumberTheory/CRC.hpp b/NumberTheory/CRC.hpp new file mode 100644 index 000000000..a705e3d4c --- /dev/null +++ b/NumberTheory/CRC.hpp @@ -0,0 +1,40 @@ +// +// CRC.hpp +// Clock Signal +// +// Created by Thomas Harte on 18/09/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef CRC_hpp +#define CRC_hpp + +#include + +namespace NumberTheory { + +class CRC16 { + public: + CRC16(uint16_t polynomial, uint16_t reset_value) : + reset_value_(reset_value), value_(reset_value), polynomial_(polynomial) {} + + inline void reset() { value_ = reset_value_; } + inline void add(uint8_t value) { + // TODO: go table based + value_ ^= (uint16_t)value << 8; + for(int c = 0; c < 8; c++) + { + uint16_t exclusive_or = (value_&0x8000) ? polynomial_ : 0x0000; + value_ = (uint16_t)(value_ << 1) ^ exclusive_or; + } + } + inline uint16_t get_value() { return value_; } + + private: + uint16_t reset_value_, polynomial_; + uint16_t value_; +}; + +} + +#endif /* CRC_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index f0b7f1e0a..3728929e5 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -356,6 +356,7 @@ 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 */; }; + 4BF829601D8F3C87001BAE39 /* CRC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF8295E1D8F3C87001BAE39 /* CRC.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -808,6 +809,8 @@ 4BF1354B1D6D2C300054B2EA /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = StaticAnalyser.hpp; path = ../../StaticAnalyser/StaticAnalyser.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 = ""; }; + 4BF8295E1D8F3C87001BAE39 /* CRC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRC.cpp; path = ../../NumberTheory/CRC.cpp; sourceTree = ""; }; + 4BF8295F1D8F3C87001BAE39 /* CRC.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRC.hpp; path = ../../NumberTheory/CRC.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1394,6 +1397,8 @@ isa = PBXGroup; children = ( 4BB697C61D4B558F00248BDF /* Factors.hpp */, + 4BF8295E1D8F3C87001BAE39 /* CRC.cpp */, + 4BF8295F1D8F3C87001BAE39 /* CRC.hpp */, ); name = NumberTheory; sourceTree = ""; @@ -2079,6 +2084,7 @@ 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */, 4BA799951D8B656E0045123D /* StaticAnalyser.cpp in Sources */, + 4BF829601D8F3C87001BAE39 /* CRC.cpp in Sources */, 4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */, 4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */, 4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */, diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp index ef6a9846f..bcd586bd5 100644 --- a/Storage/Disk/Encodings/MFM.cpp +++ b/Storage/Disk/Encodings/MFM.cpp @@ -9,6 +9,7 @@ #include "MFM.hpp" #import "../PCMTrack.hpp" +#import "../../../NumberTheory/CRC.hpp" using namespace Storage::Encodings::MFM; @@ -106,6 +107,19 @@ template class FMShifter: public Shifter { } }; +static uint8_t logarithmic_size_for_size(size_t size) +{ + switch(size) + { + default: return 0; + case 256: return 1; + case 512: return 2; + case 1024: return 3; + case 2048: return 4; + case 4196: return 5; + } +} + template std::shared_ptr GetTrackWithSectors( const std::vector §ors, @@ -115,6 +129,7 @@ template std::shared_ptr size_t inter_sector_gap) { T shifter; + NumberTheory::CRC16 crc_generator(0x1021, 0xffff); // output the index mark shifter.add_index_address_mark(); @@ -125,30 +140,46 @@ template std::shared_ptr // add sectors for(const Sector §or : sectors) { + // gap for(int c = 0; c < pre_address_mark_bytes; c++) shifter.add_byte(0x00); + // sector header shifter.add_ID_address_mark(); shifter.add_byte(sector.track); shifter.add_byte(sector.side); shifter.add_byte(sector.sector); - switch(sector.data.size()) - { - default: shifter.add_byte(0); break; - case 256: shifter.add_byte(1); break; - case 512: shifter.add_byte(2); break; - case 1024: shifter.add_byte(3); break; - case 2048: shifter.add_byte(4); break; - case 4196: shifter.add_byte(5); break; - } - // TODO: CRC of bytes since the track number + uint8_t size = logarithmic_size_for_size(sector.data.size()); + shifter.add_byte(size); + // header CRC + crc_generator.reset(); + crc_generator.add(sector.track); + crc_generator.add(sector.side); + crc_generator.add(sector.sector); + crc_generator.add(size); + uint16_t crc_value = crc_generator.get_value(); + shifter.add_byte(crc_value & 0xff); + shifter.add_byte(crc_value >> 8); + + // gap for(int c = 0; c < post_address_mark_bytes; c++) shifter.add_byte(0x4e); for(int c = 0; c < pre_data_mark_bytes; c++) shifter.add_byte(0x00); + // data shifter.add_data_address_mark(); - for(size_t c = 0; c < sector.data.size(); c++) shifter.add_byte(sector.data[c]); - // TODO: CRC of data + crc_generator.reset(); + for(size_t c = 0; c < sector.data.size(); c++) + { + shifter.add_byte(sector.data[c]); + crc_generator.add(sector.data[c]); + } + // data CRC + crc_value = crc_generator.get_value(); + shifter.add_byte(crc_value & 0xff); + shifter.add_byte(crc_value >> 8); + + // gap for(int c = 0; c < post_data_bytes; c++) shifter.add_byte(0x00); for(int c = 0; c < inter_sector_gap; c++) shifter.add_byte(0x4e); } @@ -159,17 +190,19 @@ template std::shared_ptr return std::shared_ptr(new Storage::Disk::PCMTrack(std::move(segment))); } +struct VectorReceiver { + void output_short(uint16_t value) { + data.push_back(value & 0xff); + data.push_back(value >> 8); + } + std::vector data; +}; std::shared_ptr Storage::Encodings::MFM::GetFMTrackWithSectors(const std::vector §ors) { - struct VectorShifter: public FMShifter { - void output_short(uint16_t value) { - data.push_back(value & 0xff); - data.push_back(value >> 8); - } - std::vector data; + struct VectorShifter: public FMShifter, VectorReceiver { + using VectorReceiver::output_short; }; - return GetTrackWithSectors( sectors, 16, 0x00, @@ -180,14 +213,9 @@ std::shared_ptr Storage::Encodings::MFM::GetFMTrackWithSec std::shared_ptr Storage::Encodings::MFM::GetMFMTrackWithSectors(const std::vector §ors) { - struct VectorShifter: public MFMShifter { - void output_short(uint16_t value) { - data.push_back(value & 0xff); - data.push_back(value >> 8); - } - std::vector data; + struct VectorShifter: public MFMShifter, VectorReceiver { + using VectorReceiver::output_short; }; - return GetTrackWithSectors( sectors, 50, 0x4e,