diff --git a/arch/amiga/amiga.h b/arch/amiga/amiga.h index 139c87e2..d9a6d475 100644 --- a/arch/amiga/amiga.h +++ b/arch/amiga/amiga.h @@ -9,27 +9,8 @@ #define AMIGA_SECTORS_PER_TRACK 11 #define AMIGA_RECORD_SIZE 0x21f -class Sector; -class Fluxmap; -class SectorSet; -class AmigaDecoderProto; -class AmigaEncoderProto; - -class AmigaEncoder : public AbstractEncoder -{ -public: - AmigaEncoder(const AmigaEncoderProto& config): - _config(config) {} - virtual ~AmigaEncoder() {} - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); - -private: - const AmigaEncoderProto& _config; -}; - extern std::unique_ptr createAmigaDecoder(const DecoderProto& config); +extern std::unique_ptr createAmigaEncoder(const EncoderProto& config); extern uint32_t amigaChecksum(const Bytes& bytes); extern Bytes amigaInterleave(const Bytes& input); diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index 91d17158..4859393a 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -7,6 +7,7 @@ #include "sectorset.h" #include "writer.h" #include "arch/amiga/amiga.pb.h" +#include "lib/encoders/encoders.pb.h" static bool lastBit; @@ -96,31 +97,48 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector write_interleaved_bytes(data); } -std::unique_ptr AmigaEncoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) +class AmigaEncoder : public AbstractEncoder { - if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) - return std::unique_ptr(); +public: + AmigaEncoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.amiga()) {} - int bitsPerRevolution = 200000.0 / _config.clock_rate_us(); - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; - - fillBitmapTo(bits, cursor, _config.post_index_gap_ms() * 1000 / _config.clock_rate_us(), { true, false }); - lastBit = false; - - for (int sectorId=0; sectorId encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) { - const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); - write_sector(bits, cursor, sectorData); - } + if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) + return std::unique_ptr(); - if (cursor >= bits.size()) - Error() << "track data overrun"; - fillBitmapTo(bits, cursor, bits.size(), { true, false }); + int bitsPerRevolution = 200000.0 / _config.clock_rate_us(); + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, _config.clock_rate_us()*1e3); - return fluxmap; + fillBitmapTo(bits, cursor, _config.post_index_gap_ms() * 1000 / _config.clock_rate_us(), { true, false }); + lastBit = false; + + for (int sectorId=0; sectorId= bits.size()) + Error() << "track data overrun"; + fillBitmapTo(bits, cursor, bits.size(), { true, false }); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, _config.clock_rate_us()*1e3); + return fluxmap; + } + +private: + const AmigaEncoderProto& _config; +}; + +std::unique_ptr createAmigaEncoder(const EncoderProto& config) +{ + return std::unique_ptr(new AmigaEncoder(config)); } + diff --git a/arch/brother/brother.h b/arch/brother/brother.h index 1ab30d1f..160e4f89 100644 --- a/arch/brother/brother.h +++ b/arch/brother/brother.h @@ -13,28 +13,7 @@ #define BROTHER_TRACKS_PER_120KB_DISK 39 #define BROTHER_SECTORS_PER_TRACK 12 -class Sector; -class SectorSet; -class Fluxmap; -class BrotherDecoderProto; -class BrotherEncoderProto; - -class BrotherEncoder : public AbstractEncoder -{ -public: - BrotherEncoder(const BrotherEncoderProto& config): - _config(config) - {} - - virtual ~BrotherEncoder() {} - -private: - const BrotherEncoderProto& _config; - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); -}; - extern std::unique_ptr createBrotherDecoder(const DecoderProto& config); +extern std::unique_ptr createBrotherEncoder(const EncoderProto& config); #endif diff --git a/arch/brother/encoder.cc b/arch/brother/encoder.cc index bfb9ef20..8e042272 100644 --- a/arch/brother/encoder.cc +++ b/arch/brother/encoder.cc @@ -7,6 +7,7 @@ #include "sectorset.h" #include "writer.h" #include "arch/brother/brother.pb.h" +#include "lib/encoders/encoders.pb.h" FlagGroup brotherEncoderFlags; @@ -127,58 +128,78 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } -std::unique_ptr BrotherEncoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) +class BrotherEncoder : public AbstractEncoder { - int logicalTrack; - if (physicalSide != 0) - return std::unique_ptr(); - physicalTrack -= _config.bias(); - switch (_config.format()) - { - case BROTHER120: - if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2)) - || (physicalTrack & 1)) - return std::unique_ptr(); - logicalTrack = physicalTrack/2; - break; +public: + BrotherEncoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.brother()) + {} - case BROTHER240: - if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK)) - return std::unique_ptr(); - logicalTrack = physicalTrack; - break; +public: + std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) + { + int logicalTrack; + if (physicalSide != 0) + return std::unique_ptr(); + physicalTrack -= _config.bias(); + switch (_config.format()) + { + case BROTHER120: + if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2)) + || (physicalTrack & 1)) + return std::unique_ptr(); + logicalTrack = physicalTrack/2; + break; + + case BROTHER240: + if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK)) + return std::unique_ptr(); + logicalTrack = physicalTrack; + break; + } + + int bitsPerRevolution = 200000.0 / clockRateUs; + const std::string& skew = sectorSkew.get(); + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; + + for (int sectorCount=0; sectorCountdata); + } + + if (cursor >= bits.size()) + Error() << "track data overrun"; + fillBitmapTo(bits, cursor, bits.size(), { true, false }); + + // The pre-index gap is not normally reported. + // std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl; + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, clockRateUs*1e3); + return fluxmap; } - int bitsPerRevolution = 200000.0 / clockRateUs; - const std::string& skew = sectorSkew.get(); - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; +private: + const BrotherEncoderProto& _config; - for (int sectorCount=0; sectorCountdata); - } - - if (cursor >= bits.size()) - Error() << "track data overrun"; - fillBitmapTo(bits, cursor, bits.size(), { true, false }); - - // The pre-index gap is not normally reported. - // std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl; - - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, clockRateUs*1e3); - return fluxmap; +std::unique_ptr createBrotherEncoder(const EncoderProto& config) +{ + return std::unique_ptr(new BrotherEncoder(config)); } + + diff --git a/arch/c64/c64.h b/arch/c64/c64.h index ef76193e..98972d11 100644 --- a/arch/c64/c64.h +++ b/arch/c64/c64.h @@ -27,33 +27,7 @@ #define C64_TRACKS_PER_DISK 40 #define C64_BAM_TRACK 17 - -class Sector; -class Fluxmap; -class Commodore64DecoderProto; -class Commodore64EncoderProto; - -class Commodore64Encoder : public AbstractEncoder -{ -public: - Commodore64Encoder(const Commodore64EncoderProto& config): - _config(config) - {} - - virtual ~Commodore64Encoder() {} - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); - -private: - void writeSector(std::vector& bits, unsigned& cursor, const Sector* sector) const; - -private: - const Commodore64EncoderProto& _config; - uint8_t _formatByte1; - uint8_t _formatByte2; -}; - extern std::unique_ptr createCommodore64Decoder(const DecoderProto& config); +extern std::unique_ptr createCommodore64Encoder(const EncoderProto& config); #endif diff --git a/arch/c64/encoder.cc b/arch/c64/encoder.cc index 2eef6d30..53f74be7 100644 --- a/arch/c64/encoder.cc +++ b/arch/c64/encoder.cc @@ -9,6 +9,7 @@ #include "writer.h" #include "fmt/format.h" #include "arch/c64/c64.pb.h" +#include "lib/encoders/encoders.pb.h" #include #include "bytes.h" @@ -202,147 +203,167 @@ static std::vector encode_data(uint8_t input) return output; } -void Commodore64Encoder::writeSector(std::vector& bits, unsigned& cursor, const Sector* sector) const +class Commodore64Encoder : public AbstractEncoder { - /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html - * 1. Header sync FF FF FF FF FF (40 'on' bits, not GCR) - * 2. Header info 52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes) - * 3. Header gap 55 55 55 55 55 55 55 55 55 (9 bytes, never read) - * 4. Data sync FF FF FF FF FF (40 'on' bits, not GCR) - * 5. Data block 55...4A (325 GCR bytes) - * 6. Inter-sector gap 55 55 55 55...55 55 (4 to 12 bytes, never read) - * 1. Header sync (SYNC for the next sector) - */ - if ((sector->status == Sector::OK) or (sector->status == Sector::BAD_CHECKSUM)) +public: + Commodore64Encoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.c64()) + {} + +public: + std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) { - // There is data to encode to disk. - if ((sector->data.size() != C64_SECTOR_LENGTH)) - Error() << fmt::format("unsupported sector size {} --- you must pick 256", sector->data.size()); + /* The format ID Character # 1 and # 2 are in the .d64 image only present + * in track 18 sector zero which contains the BAM info in byte 162 and 163. + * it is written in every header of every sector and track. headers are not + * stored in a d64 disk image so we have to get it from track 18 which + * contains the BAM. + */ - // 1. Write header Sync (not GCR) - for (int i=0; i<6; i++) - write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */ - - // 2. Write Header info 10 GCR bytes - /* - * The 10 byte header info (#2) is GCR encoded and must be decoded to - * it's normal 8 bytes to be understood. Once decoded, its breakdown is - * as follows: - * - * Byte $00 - header block ID ($08) - * 01 - header block checksum 16 (EOR of $02-$05) - * 02 - Sector - * 03 - Track - * 04 - Format ID byte #2 - * 05 - Format ID byte #1 - * 06-07 - $0F ("off" bytes) - */ - uint8_t encodedTrack = ((sector->logicalTrack) + 1); // C64 track numbering starts with 1. Fluxengine with 0. - uint8_t encodedSector = sector->logicalSector; - // uint8_t formatByte1 = C64_FORMAT_ID_BYTE1; - // uint8_t formatByte2 = C64_FORMAT_ID_BYTE2; - uint8_t headerChecksum = (encodedTrack ^ encodedSector ^ _formatByte1 ^ _formatByte2); - write_bits(bits, cursor, encode_data(C64_HEADER_BLOCK_ID)); - write_bits(bits, cursor, encode_data(headerChecksum)); - write_bits(bits, cursor, encode_data(encodedSector)); - write_bits(bits, cursor, encode_data(encodedTrack)); - write_bits(bits, cursor, encode_data(_formatByte2)); - write_bits(bits, cursor, encode_data(_formatByte1)); - write_bits(bits, cursor, encode_data(C64_PADDING)); - write_bits(bits, cursor, encode_data(C64_PADDING)); - - // 3. Write header GAP not GCR - for (int i=0; i<9; i++) - write_bits(bits, cursor, C64_HEADER_GAP, 1*8); /* header gap */ - - // 4. Write Data sync not GCR - for (int i=0; i<6; i++) - write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */ - - // 5. Write data block 325 GCR bytes - /* - * The 325 byte data block (#5) is GCR encoded and must be decoded to its - * normal 260 bytes to be understood. The data block is made up of the following: - * - * Byte $00 - data block ID ($07) - * 01-100 - 256 bytes data - * 101 - data block checksum (EOR of $01-100) - * 102-103 - $00 ("off" bytes, to make the sector size a multiple of 5) - */ - - write_bits(bits, cursor, encode_data(C64_DATA_BLOCK_ID)); - uint8_t dataChecksum = xorBytes(sector->data); - ByteReader br(sector->data); - int i = 0; - for (i = 0; i < C64_SECTOR_LENGTH; i++) - { - uint8_t val = br.read_8(); - write_bits(bits, cursor, encode_data(val)); - } - write_bits(bits, cursor, encode_data(dataChecksum)); - write_bits(bits, cursor, encode_data(C64_PADDING)); - write_bits(bits, cursor, encode_data(C64_PADDING)); - - //6. Write inter-sector gap 9 - 12 bytes nor gcr - for (int i=0; i<9; i++) - write_bits(bits, cursor, C64_INTER_SECTOR_GAP, 1*8); /* sync */ - - } -} - -std::unique_ptr Commodore64Encoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) -{ - /* The format ID Character # 1 and # 2 are in the .d64 image only present - * in track 18 sector zero which contains the BAM info in byte 162 and 163. - * it is written in every header of every sector and track. headers are not - * stored in a d64 disk image so we have to get it from track 18 which - * contains the BAM. - */ - - const auto& sectorData = allSectors.get(C64_BAM_TRACK*2, 0, 0); //Read de BAM to get the DISK ID bytes - if (sectorData) - { - ByteReader br(sectorData->data); - br.seek(162); //goto position of the first Disk ID Byte - _formatByte1 = br.read_8(); - _formatByte2 = br.read_8(); - } - else - _formatByte1 = _formatByte2 = 0; - - int logicalTrack = physicalTrack / 2; - double clockRateUs = clockRateUsForTrack(logicalTrack) * _config.clock_compensation_factor(); - - int bitsPerRevolution = 200000.0 / clockRateUs; - - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; - - fillBitmapTo(bits, cursor, _config.post_index_gap_us() / clockRateUs, { true, false }); - lastBit = false; - - unsigned numSectors = sectorsForTrack(logicalTrack); - unsigned writtenSectors = 0; - for (int sectorId=0; sectorIddata); + br.seek(162); //goto position of the first Disk ID Byte + _formatByte1 = br.read_8(); + _formatByte2 = br.read_8(); + } + else + _formatByte1 = _formatByte2 = 0; + + int logicalTrack = physicalTrack / 2; + double clockRateUs = clockRateUsForTrack(logicalTrack) * _config.clock_compensation_factor(); + + int bitsPerRevolution = 200000.0 / clockRateUs; + + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; + + fillBitmapTo(bits, cursor, _config.post_index_gap_us() / clockRateUs, { true, false }); + lastBit = false; + + unsigned numSectors = sectorsForTrack(logicalTrack); + unsigned writtenSectors = 0; + for (int sectorId=0; sectorId(); + + if (cursor >= bits.size()) + Error() << fmt::format("track data overrun by {} bits", cursor - bits.size()); + fillBitmapTo(bits, cursor, bits.size(), { true, false }); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, clockRateUs*1e3); + return fluxmap; + } + +private: + void writeSector(std::vector& bits, unsigned& cursor, const Sector* sector) const + { + /* Source: http://www.unusedino.de/ec64/technical/formats/g64.html + * 1. Header sync FF FF FF FF FF (40 'on' bits, not GCR) + * 2. Header info 52 54 B5 29 4B 7A 5E 95 55 55 (10 GCR bytes) + * 3. Header gap 55 55 55 55 55 55 55 55 55 (9 bytes, never read) + * 4. Data sync FF FF FF FF FF (40 'on' bits, not GCR) + * 5. Data block 55...4A (325 GCR bytes) + * 6. Inter-sector gap 55 55 55 55...55 55 (4 to 12 bytes, never read) + * 1. Header sync (SYNC for the next sector) + */ + if ((sector->status == Sector::OK) or (sector->status == Sector::BAD_CHECKSUM)) + { + // There is data to encode to disk. + if ((sector->data.size() != C64_SECTOR_LENGTH)) + Error() << fmt::format("unsupported sector size {} --- you must pick 256", sector->data.size()); + + // 1. Write header Sync (not GCR) + for (int i=0; i<6; i++) + write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */ + + // 2. Write Header info 10 GCR bytes + /* + * The 10 byte header info (#2) is GCR encoded and must be decoded to + * it's normal 8 bytes to be understood. Once decoded, its breakdown is + * as follows: + * + * Byte $00 - header block ID ($08) + * 01 - header block checksum 16 (EOR of $02-$05) + * 02 - Sector + * 03 - Track + * 04 - Format ID byte #2 + * 05 - Format ID byte #1 + * 06-07 - $0F ("off" bytes) + */ + uint8_t encodedTrack = ((sector->logicalTrack) + 1); // C64 track numbering starts with 1. Fluxengine with 0. + uint8_t encodedSector = sector->logicalSector; + // uint8_t formatByte1 = C64_FORMAT_ID_BYTE1; + // uint8_t formatByte2 = C64_FORMAT_ID_BYTE2; + uint8_t headerChecksum = (encodedTrack ^ encodedSector ^ _formatByte1 ^ _formatByte2); + write_bits(bits, cursor, encode_data(C64_HEADER_BLOCK_ID)); + write_bits(bits, cursor, encode_data(headerChecksum)); + write_bits(bits, cursor, encode_data(encodedSector)); + write_bits(bits, cursor, encode_data(encodedTrack)); + write_bits(bits, cursor, encode_data(_formatByte2)); + write_bits(bits, cursor, encode_data(_formatByte1)); + write_bits(bits, cursor, encode_data(C64_PADDING)); + write_bits(bits, cursor, encode_data(C64_PADDING)); + + // 3. Write header GAP not GCR + for (int i=0; i<9; i++) + write_bits(bits, cursor, C64_HEADER_GAP, 1*8); /* header gap */ + + // 4. Write Data sync not GCR + for (int i=0; i<6; i++) + write_bits(bits, cursor, C64_HEADER_DATA_SYNC, 1*8); /* sync */ + + // 5. Write data block 325 GCR bytes + /* + * The 325 byte data block (#5) is GCR encoded and must be decoded to its + * normal 260 bytes to be understood. The data block is made up of the following: + * + * Byte $00 - data block ID ($07) + * 01-100 - 256 bytes data + * 101 - data block checksum (EOR of $01-100) + * 102-103 - $00 ("off" bytes, to make the sector size a multiple of 5) + */ + + write_bits(bits, cursor, encode_data(C64_DATA_BLOCK_ID)); + uint8_t dataChecksum = xorBytes(sector->data); + ByteReader br(sector->data); + int i = 0; + for (i = 0; i < C64_SECTOR_LENGTH; i++) + { + uint8_t val = br.read_8(); + write_bits(bits, cursor, encode_data(val)); + } + write_bits(bits, cursor, encode_data(dataChecksum)); + write_bits(bits, cursor, encode_data(C64_PADDING)); + write_bits(bits, cursor, encode_data(C64_PADDING)); + + //6. Write inter-sector gap 9 - 12 bytes nor gcr + for (int i=0; i<9; i++) + write_bits(bits, cursor, C64_INTER_SECTOR_GAP, 1*8); /* sync */ + } } - if (writtenSectors == 0) - return std::unique_ptr(); + +private: + const Commodore64EncoderProto& _config; + uint8_t _formatByte1; + uint8_t _formatByte2; +}; - if (cursor >= bits.size()) - Error() << fmt::format("track data overrun by {} bits", cursor - bits.size()); - fillBitmapTo(bits, cursor, bits.size(), { true, false }); - - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, clockRateUs*1e3); - return fluxmap; +std::unique_ptr createCommodore64Encoder(const EncoderProto& config) +{ + return std::unique_ptr(new Commodore64Encoder(config)); } // vim: sw=4 ts=4 et diff --git a/arch/ibm/encoder.cc b/arch/ibm/encoder.cc index aa180974..3c61a822 100644 --- a/arch/ibm/encoder.cc +++ b/arch/ibm/encoder.cc @@ -7,6 +7,7 @@ #include "sectorset.h" #include "writer.h" #include "arch/ibm/ibm.pb.h" +#include "lib/encoders/encoders.pb.h" #include "fmt/format.h" #include @@ -64,19 +65,6 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } -void IbmEncoder::writeRawBits(uint32_t data, int width) -{ - _cursor += width; - _lastBit = data & 1; - for (int i=0; i>= 1; - } -} - static uint8_t decodeUint16(uint16_t raw) { Bytes b; @@ -85,174 +73,209 @@ static uint8_t decodeUint16(uint16_t raw) return decodeFmMfm(b.toBits())[0]; } -void IbmEncoder::getTrackFormat(IbmEncoderProto::TrackdataProto& trackdata, unsigned cylinder, unsigned head) +class IbmEncoder : public AbstractEncoder { - trackdata.Clear(); - for (const auto& f : _config.trackdata()) +public: + IbmEncoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.ibm()) + {} + +private: + void writeRawBits(uint32_t data, int width) { - if (f.has_cylinder() && (f.cylinder() != cylinder)) - continue; - if (f.has_head() && (f.head() != head)) - continue; - - trackdata.MergeFrom(f); - } -} - -std::unique_ptr IbmEncoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) -{ - IbmEncoderProto::TrackdataProto trackdata; - getTrackFormat(trackdata, physicalTrack, physicalSide); - - auto writeBytes = [&](const Bytes& bytes) - { - if (trackdata.use_fm()) - encodeFm(_bits, _cursor, bytes); - else - encodeMfm(_bits, _cursor, bytes, _lastBit); - }; - - auto writeFillerBytes = [&](int count, uint8_t byte) - { - Bytes bytes = { byte }; - for (int i=0; i> 7; - while (s > 1) + _cursor += width; + _lastBit = data & 1; + for (int i=0; i>= 1; - sectorSize += 1; + unsigned pos = _cursor - i - 1; + if (pos < _bits.size()) + _bits[pos] = data & 1; + data >>= 1; } } - uint8_t gapFill = trackdata.use_fm() ? 0x00 : 0x4e; - - writeFillerBytes(trackdata.gap0(), gapFill); - if (trackdata.emit_iam()) + void getTrackFormat(IbmEncoderProto::TrackdataProto& trackdata, unsigned cylinder, unsigned head) { - writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); + trackdata.Clear(); + for (const auto& f : _config.trackdata()) + { + if (f.has_cylinder() && (f.cylinder() != cylinder)) + continue; + if (f.has_head() && (f.head() != head)) + continue; + + trackdata.MergeFrom(f); + } + } + +public: + std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) + { + IbmEncoderProto::TrackdataProto trackdata; + getTrackFormat(trackdata, physicalTrack, physicalSide); + + auto writeBytes = [&](const Bytes& bytes) + { + if (trackdata.use_fm()) + encodeFm(_bits, _cursor, bytes); + else + encodeMfm(_bits, _cursor, bytes, _lastBit); + }; + + auto writeFillerBytes = [&](int count, uint8_t byte) + { + Bytes bytes = { byte }; + for (int i=0; i> 7; + while (s > 1) + { + s >>= 1; + sectorSize += 1; + } } - writeRawBits(trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16); - writeFillerBytes(trackdata.gap1(), gapFill); + + uint8_t gapFill = trackdata.use_fm() ? 0x00 : 0x4e; + + writeFillerBytes(trackdata.gap0(), gapFill); + if (trackdata.emit_iam()) + { + writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); + if (!trackdata.use_fm()) + { + for (int i=0; i<3; i++) + writeRawBits(MFM_IAM_SEPARATOR, 16); + } + writeRawBits(trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16); + writeFillerBytes(trackdata.gap1(), gapFill); + } + + bool first = true; + for (char sectorChar : trackdata.sector_skew()) + { + int sectorId = charToInt(sectorChar); + if (!first) + writeFillerBytes(trackdata.gap3(), gapFill); + first = false; + + const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); + if (!sectorData) + { + /* If there are any missing sectors, this is an empty track. */ + return std::unique_ptr(); + } + + /* Writing the sector and data records are fantastically annoying. + * The CRC is calculated from the *very start* of the record, and + * include the malformed marker bytes. Our encoder doesn't know + * about this, of course, with the result that we have to construct + * the unencoded header, calculate the checksum, and then use the + * same logic to emit the bytes which require special encoding + * before encoding the rest of the header normally. */ + + { + Bytes header; + ByteWriter bw(header); + + writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); + if (!trackdata.use_fm()) + { + for (int i=0; i<3; i++) + bw.write_8(MFM_RECORD_SEPARATOR_BYTE); + } + bw.write_8(idamUnencoded); + bw.write_8(sectorData->logicalTrack); + bw.write_8(sectorData->logicalSide); + bw.write_8(sectorData->logicalSector + trackdata.start_sector_id()); + bw.write_8(sectorSize); + uint16_t crc = crc16(CCITT_POLY, header); + bw.write_be16(crc); + + int conventionalHeaderStart = 0; + if (!trackdata.use_fm()) + { + for (int i=0; i<3; i++) + writeRawBits(MFM_RECORD_SEPARATOR, 16); + conventionalHeaderStart += 3; + + } + writeRawBits(trackdata.idam_byte(), 16); + conventionalHeaderStart += 1; + + writeBytes(header.slice(conventionalHeaderStart)); + } + + writeFillerBytes(trackdata.gap2(), gapFill); + + { + Bytes data; + ByteWriter bw(data); + + writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); + if (!trackdata.use_fm()) + { + for (int i=0; i<3; i++) + bw.write_8(MFM_RECORD_SEPARATOR_BYTE); + } + bw.write_8(damUnencoded); + + Bytes truncatedData = sectorData->data.slice(0, trackdata.sector_size()); + bw += truncatedData; + uint16_t crc = crc16(CCITT_POLY, data); + bw.write_be16(crc); + + int conventionalHeaderStart = 0; + if (!trackdata.use_fm()) + { + for (int i=0; i<3; i++) + writeRawBits(MFM_RECORD_SEPARATOR, 16); + conventionalHeaderStart += 3; + + } + writeRawBits(trackdata.dam_byte(), 16); + conventionalHeaderStart += 1; + + writeBytes(data.slice(conventionalHeaderStart)); + } + } + + if (_cursor >= _bits.size()) + Error() << "track data overrun"; + while (_cursor < _bits.size()) + writeFillerBytes(1, gapFill); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(_bits, clockRateUs*1e3); + return fluxmap; } - bool first = true; - for (char sectorChar : trackdata.sector_skew()) - { - int sectorId = charToInt(sectorChar); - if (!first) - writeFillerBytes(trackdata.gap3(), gapFill); - first = false; +private: + const IbmEncoderProto& _config; + std::vector _bits; + unsigned _cursor; + bool _lastBit; +}; - const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); - if (!sectorData) - { - /* If there are any missing sectors, this is an empty track. */ - return std::unique_ptr(); - } - - /* Writing the sector and data records are fantastically annoying. - * The CRC is calculated from the *very start* of the record, and - * include the malformed marker bytes. Our encoder doesn't know - * about this, of course, with the result that we have to construct - * the unencoded header, calculate the checksum, and then use the - * same logic to emit the bytes which require special encoding - * before encoding the rest of the header normally. */ - - { - Bytes header; - ByteWriter bw(header); - - writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); - if (!trackdata.use_fm()) - { - for (int i=0; i<3; i++) - bw.write_8(MFM_RECORD_SEPARATOR_BYTE); - } - bw.write_8(idamUnencoded); - bw.write_8(sectorData->logicalTrack); - bw.write_8(sectorData->logicalSide); - bw.write_8(sectorData->logicalSector + trackdata.start_sector_id()); - bw.write_8(sectorSize); - uint16_t crc = crc16(CCITT_POLY, header); - bw.write_be16(crc); - - int conventionalHeaderStart = 0; - if (!trackdata.use_fm()) - { - for (int i=0; i<3; i++) - writeRawBits(MFM_RECORD_SEPARATOR, 16); - conventionalHeaderStart += 3; - - } - writeRawBits(trackdata.idam_byte(), 16); - conventionalHeaderStart += 1; - - writeBytes(header.slice(conventionalHeaderStart)); - } - - writeFillerBytes(trackdata.gap2(), gapFill); - - { - Bytes data; - ByteWriter bw(data); - - writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); - if (!trackdata.use_fm()) - { - for (int i=0; i<3; i++) - bw.write_8(MFM_RECORD_SEPARATOR_BYTE); - } - bw.write_8(damUnencoded); - - Bytes truncatedData = sectorData->data.slice(0, trackdata.sector_size()); - bw += truncatedData; - uint16_t crc = crc16(CCITT_POLY, data); - bw.write_be16(crc); - - int conventionalHeaderStart = 0; - if (!trackdata.use_fm()) - { - for (int i=0; i<3; i++) - writeRawBits(MFM_RECORD_SEPARATOR, 16); - conventionalHeaderStart += 3; - - } - writeRawBits(trackdata.dam_byte(), 16); - conventionalHeaderStart += 1; - - writeBytes(data.slice(conventionalHeaderStart)); - } - } - - if (_cursor >= _bits.size()) - Error() << "track data overrun"; - while (_cursor < _bits.size()) - writeFillerBytes(1, gapFill); - - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(_bits, clockRateUs*1e3); - return fluxmap; +std::unique_ptr createIbmEncoder(const EncoderProto& config) +{ + return std::unique_ptr(new IbmEncoder(config)); } + diff --git a/arch/ibm/ibm.h b/arch/ibm/ibm.h index 57b50912..ee572164 100644 --- a/arch/ibm/ibm.h +++ b/arch/ibm/ibm.h @@ -1,10 +1,6 @@ #ifndef IBM_H #define IBM_H -#include "decoders/decoders.h" -#include "encoders/encoders.h" -#include "arch/ibm/ibm.pb.h" - /* IBM format (i.e. ordinary PC floppies). */ #define IBM_MFM_SYNC 0xA1 /* sync byte for MFM */ @@ -30,31 +26,12 @@ struct IbmIdam uint8_t crc[2]; }; -class IbmEncoder : public AbstractEncoder -{ -public: - IbmEncoder(const IbmEncoderProto& config): - _config(config) - {} - - virtual ~IbmEncoder() {} - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); - -private: - void writeRawBits(uint32_t data, int width); - void writeSync(); - - void getTrackFormat(IbmEncoderProto::TrackdataProto& format, unsigned track, unsigned side); - -private: - const IbmEncoderProto& _config; - std::vector _bits; - unsigned _cursor; - bool _lastBit; -}; +class AbstractEncoder; +class AbstractDecoder; +class DecoderProto; +class EncoderProto; extern std::unique_ptr createIbmDecoder(const DecoderProto& config); +extern std::unique_ptr createIbmEncoder(const EncoderProto& config); #endif diff --git a/arch/macintosh/decoder.cc b/arch/macintosh/decoder.cc index 5a8a9f9b..8b3c7407 100644 --- a/arch/macintosh/decoder.cc +++ b/arch/macintosh/decoder.cc @@ -218,4 +218,3 @@ std::unique_ptr createMacintoshDecoder(const DecoderProto& conf return std::unique_ptr(new MacintoshDecoder(config)); } - diff --git a/arch/macintosh/encoder.cc b/arch/macintosh/encoder.cc index 558818dd..f4c9f52f 100644 --- a/arch/macintosh/encoder.cc +++ b/arch/macintosh/encoder.cc @@ -210,33 +210,46 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector write_bits(bits, cursor, 0xdeaaff, 3*8); } -std::unique_ptr MacintoshEncoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) +class MacintoshEncoder : public AbstractEncoder { - if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK)) - return std::unique_ptr(); +public: + MacintoshEncoder(const EncoderProto& config): + AbstractEncoder(config) + {} - double clockRateUs = clockRateUsForTrack(physicalTrack) * clockCompensation; - int bitsPerRevolution = 200000.0 / clockRateUs; - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; - - fillBitmapTo(bits, cursor, postIndexGapUs / clockRateUs, { true, false }); - lastBit = false; - - unsigned numSectors = sectorsForTrack(physicalTrack); - for (int sectorId=0; sectorId encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) { - const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); - write_sector(bits, cursor, sectorData); - } + if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK)) + return std::unique_ptr(); - if (cursor >= bits.size()) - Error() << fmt::format("track data overrun by {} bits", cursor - bits.size()); - fillBitmapTo(bits, cursor, bits.size(), { true, false }); + double clockRateUs = clockRateUsForTrack(physicalTrack) * clockCompensation; + int bitsPerRevolution = 200000.0 / clockRateUs; + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, clockRateUs*1e3); - return fluxmap; + fillBitmapTo(bits, cursor, postIndexGapUs / clockRateUs, { true, false }); + lastBit = false; + + unsigned numSectors = sectorsForTrack(physicalTrack); + for (int sectorId=0; sectorId= bits.size()) + Error() << fmt::format("track data overrun by {} bits", cursor - bits.size()); + fillBitmapTo(bits, cursor, bits.size(), { true, false }); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, clockRateUs*1e3); + return fluxmap; + } +}; + +std::unique_ptr createMacintoshEncoder(const EncoderProto& config) +{ + return std::unique_ptr(new MacintoshEncoder(config)); } diff --git a/arch/macintosh/macintosh.h b/arch/macintosh/macintosh.h index f3f9e11a..162da0e2 100644 --- a/arch/macintosh/macintosh.h +++ b/arch/macintosh/macintosh.h @@ -1,9 +1,6 @@ #ifndef MACINTOSH_H #define MACINTOSH_H -#include "decoders/decoders.h" -#include "encoders/encoders.h" - #define MAC_SECTOR_RECORD 0xd5aa96 /* 1101 0101 1010 1010 1001 0110 */ #define MAC_DATA_RECORD 0xd5aaad /* 1101 0101 1010 1010 1010 1101 */ @@ -13,24 +10,13 @@ #define MAC_TRACKS_PER_DISK 80 -class Sector; -class Fluxmap; -class MacintoshDecoderProto; -class MacintoshEncoderProto; - -class MacintoshEncoder : public AbstractEncoder -{ -public: - MacintoshEncoder(const MacintoshEncoderProto&) {} - virtual ~MacintoshEncoder() {} - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); -}; - -extern FlagGroup macintoshEncoderFlags; +class AbstractEncoder; +class AbstractDecoder; +class DecoderProto; +class EncoderProto; extern std::unique_ptr createMacintoshDecoder(const DecoderProto& config); +extern std::unique_ptr createMacintoshEncoder(const EncoderProto& config); #endif diff --git a/arch/northstar/decoder.cc b/arch/northstar/decoder.cc index 620ef97d..8b73be67 100644 --- a/arch/northstar/decoder.cc +++ b/arch/northstar/decoder.cc @@ -194,5 +194,3 @@ std::unique_ptr createNorthstarDecoder(const DecoderProto& conf return std::unique_ptr(new NorthstarDecoder(config)); } - - diff --git a/arch/northstar/encoder.cc b/arch/northstar/encoder.cc index 098b7cba..595ac1e2 100644 --- a/arch/northstar/encoder.cc +++ b/arch/northstar/encoder.cc @@ -1,6 +1,11 @@ #include "globals.h" #include "northstar.h" +#include "sector.h" #include "sectorset.h" +#include "bytes.h" +#include "decoders/decoders.h" +#include "encoders/encoders.h" +#include "lib/encoders/encoders.pb.h" #define GAP_FILL_SIZE_SD 30 #define PRE_HEADER_GAP_FILL_SIZE_SD 9 @@ -95,36 +100,53 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector } } -std::unique_ptr NorthstarEncoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) +class NorthstarEncoder : public AbstractEncoder { - int bitsPerRevolution = 100000; - double clockRateUs = 4.00; +public: + NorthstarEncoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.northstar()) + {} - if ((physicalTrack < 0) || (physicalTrack >= 35)) - return std::unique_ptr(); - - const auto& sector = allSectors.get(physicalTrack, physicalSide, 0); - - if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) { - bitsPerRevolution /= 2; // FM - } else { - clockRateUs /= 2.00; - } - - std::vector bits(bitsPerRevolution); - unsigned cursor = 0; - - for (int sectorId = 0; sectorId < 10; sectorId++) + std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) { - const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); - write_sector(bits, cursor, sectorData); + int bitsPerRevolution = 100000; + double clockRateUs = 4.00; + + if ((physicalTrack < 0) || (physicalTrack >= 35)) + return std::unique_ptr(); + + const auto& sector = allSectors.get(physicalTrack, physicalSide, 0); + + if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) { + bitsPerRevolution /= 2; // FM + } else { + clockRateUs /= 2.00; + } + + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; + + for (int sectorId = 0; sectorId < 10; sectorId++) + { + const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); + write_sector(bits, cursor, sectorData); + } + + if (cursor > bits.size()) + Error() << "track data overrun"; + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, clockRateUs * 1e3); + return fluxmap; } - if (cursor > bits.size()) - Error() << "track data overrun"; +private: + const NorthstarEncoderProto& _config; +}; - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(bits, clockRateUs * 1e3); - return fluxmap; +std::unique_ptr createNorthstarEncoder(const EncoderProto& config) +{ + return std::unique_ptr(new NorthstarEncoder(config)); } + diff --git a/arch/northstar/northstar.h b/arch/northstar/northstar.h index 56e6f1ad..c20a084e 100644 --- a/arch/northstar/northstar.h +++ b/arch/northstar/northstar.h @@ -12,9 +12,6 @@ * */ -#include "decoders/decoders.h" -#include "encoders/encoders.h" - #define NORTHSTAR_PREAMBLE_SIZE_SD (16) #define NORTHSTAR_PREAMBLE_SIZE_DD (32) #define NORTHSTAR_HEADER_SIZE_SD (1) @@ -28,26 +25,14 @@ #define SECTOR_TYPE_MFM (0) #define SECTOR_TYPE_FM (1) -class NorthstarEncoderProto; -class NorthstarDecoderProto; +class AbstractDecoder; +class AbstractEncoder; +class EncoderProto; +class DecoderProto; -class NorthstarEncoder : public AbstractEncoder -{ -public: - NorthstarEncoder(const NorthstarEncoderProto& config): - _config(config) - {} - - virtual ~NorthstarEncoder() {} - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); - -private: - const NorthstarEncoderProto& _config; -}; - -extern FlagGroup northstarEncoderFlags; extern uint8_t northstarChecksum(const Bytes& bytes); extern std::unique_ptr createNorthstarDecoder(const DecoderProto& config); +extern std::unique_ptr createNorthstarEncoder(const EncoderProto& config); #endif /* NORTHSTAR */ diff --git a/arch/tids990/encoder.cc b/arch/tids990/encoder.cc index de2f705e..d0bff891 100644 --- a/arch/tids990/encoder.cc +++ b/arch/tids990/encoder.cc @@ -7,6 +7,7 @@ #include "sectorset.h" #include "writer.h" #include "arch/tids990/tids990.pb.h" +#include "lib/encoders/encoders.pb.h" #include static int charToInt(char c) @@ -16,31 +17,6 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } -void Tids990Encoder::writeRawBits(uint32_t data, int width) -{ - _cursor += width; - _lastBit = data & 1; - for (int i=0; i>= 1; - } -} - -void Tids990Encoder::writeBytes(const Bytes& bytes) -{ - encodeMfm(_bits, _cursor, bytes, _lastBit); -} - -void Tids990Encoder::writeBytes(int count, uint8_t byte) -{ - Bytes bytes = { byte }; - for (int i=0; i Tids990Encoder::encode( - int physicalTrack, int physicalSide, const SectorSet& allSectors) +class Tids990Encoder : public AbstractEncoder { - double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0; - int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs; - _bits.resize(bitsPerRevolution); - _cursor = 0; +public: + Tids990Encoder(const EncoderProto& config): + AbstractEncoder(config), + _config(config.tids990()) + {} - uint8_t am1Unencoded = decodeUint16(_config.am1_byte()); - uint8_t am2Unencoded = decodeUint16(_config.am2_byte()); - - writeBytes(_config.gap1_bytes(), 0x55); - - bool first = true; - for (char sectorChar : _config.sector_skew()) +private: + void writeRawBits(uint32_t data, int width) { - int sectorId = charToInt(sectorChar); - if (!first) - writeBytes(_config.gap3_bytes(), 0x55); - first = false; - - const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); - if (!sectorData) - Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId); - - /* Writing the sector and data records are fantastically annoying. - * The CRC is calculated from the *very start* of the record, and - * include the malformed marker bytes. Our encoder doesn't know - * about this, of course, with the result that we have to construct - * the unencoded header, calculate the checksum, and then use the - * same logic to emit the bytes which require special encoding - * before encoding the rest of the header normally. */ - + _cursor += width; + _lastBit = data & 1; + for (int i=0; i>= 1; + } + } - writeBytes(12, 0x55); - bw.write_8(am1Unencoded); - bw.write_8(sectorData->logicalSide << 3); - bw.write_8(sectorData->logicalTrack); - bw.write_8(_config.sector_count()); - bw.write_8(sectorData->logicalSector); - bw.write_be16(sectorData->data.size()); - uint16_t crc = crc16(CCITT_POLY, header); - bw.write_be16(crc); + void writeBytes(const Bytes& bytes) + { + encodeMfm(_bits, _cursor, bytes, _lastBit); + } - writeRawBits(_config.am1_byte(), 16); - writeBytes(header.slice(1)); + void writeBytes(int count, uint8_t byte) + { + Bytes bytes = { byte }; + for (int i=0; i encode(int physicalTrack, int physicalSide, const SectorSet& allSectors) + { + double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0; + int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs; + _bits.resize(bitsPerRevolution); + _cursor = 0; + + uint8_t am1Unencoded = decodeUint16(_config.am1_byte()); + uint8_t am2Unencoded = decodeUint16(_config.am2_byte()); + + writeBytes(_config.gap1_bytes(), 0x55); + + bool first = true; + for (char sectorChar : _config.sector_skew()) + { + int sectorId = charToInt(sectorChar); + if (!first) + writeBytes(_config.gap3_bytes(), 0x55); + first = false; + + const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); + if (!sectorData) + Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId); + + /* Writing the sector and data records are fantastically annoying. + * The CRC is calculated from the *very start* of the record, and + * include the malformed marker bytes. Our encoder doesn't know + * about this, of course, with the result that we have to construct + * the unencoded header, calculate the checksum, and then use the + * same logic to emit the bytes which require special encoding + * before encoding the rest of the header normally. */ + + { + Bytes header; + ByteWriter bw(header); + + writeBytes(12, 0x55); + bw.write_8(am1Unencoded); + bw.write_8(sectorData->logicalSide << 3); + bw.write_8(sectorData->logicalTrack); + bw.write_8(_config.sector_count()); + bw.write_8(sectorData->logicalSector); + bw.write_be16(sectorData->data.size()); + uint16_t crc = crc16(CCITT_POLY, header); + bw.write_be16(crc); + + writeRawBits(_config.am1_byte(), 16); + writeBytes(header.slice(1)); + } + + writeBytes(_config.gap2_bytes(), 0x55); + + { + Bytes data; + ByteWriter bw(data); + + writeBytes(12, 0x55); + bw.write_8(am2Unencoded); + + bw += sectorData->data; + uint16_t crc = crc16(CCITT_POLY, data); + bw.write_be16(crc); + + writeRawBits(_config.am2_byte(), 16); + writeBytes(data.slice(1)); + } } - writeBytes(_config.gap2_bytes(), 0x55); + if (_cursor >= _bits.size()) + Error() << "track data overrun"; + while (_cursor < _bits.size()) + writeBytes(1, 0x55); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(_bits, clockRateUs*1e3); + return fluxmap; + } - { - Bytes data; - ByteWriter bw(data); +private: + const Tids990EncoderProto& _config; + std::vector _bits; + unsigned _cursor; + bool _lastBit; +}; - writeBytes(12, 0x55); - bw.write_8(am2Unencoded); - - bw += sectorData->data; - uint16_t crc = crc16(CCITT_POLY, data); - bw.write_be16(crc); - - writeRawBits(_config.am2_byte(), 16); - writeBytes(data.slice(1)); - } - } - - if (_cursor >= _bits.size()) - Error() << "track data overrun"; - while (_cursor < _bits.size()) - writeBytes(1, 0x55); - - std::unique_ptr fluxmap(new Fluxmap); - fluxmap->appendBits(_bits, clockRateUs*1e3); - return fluxmap; +std::unique_ptr createTids990Encoder(const EncoderProto& config) +{ + return std::unique_ptr(new Tids990Encoder(config)); } + diff --git a/arch/tids990/tids990.h b/arch/tids990/tids990.h index 11e4eea9..5f0a9601 100644 --- a/arch/tids990/tids990.h +++ b/arch/tids990/tids990.h @@ -5,38 +5,10 @@ #define TIDS990_SECTOR_RECORD_SIZE 10 /* bytes */ #define TIDS990_DATA_RECORD_SIZE (TIDS990_PAYLOAD_SIZE + 4) /* bytes */ -class Sector; -class SectorSet; -class Fluxmap; -class Track; -class Tids990DecoderProto; -class Tids990EncoderProto; - -class Tids990Encoder : public AbstractEncoder -{ -public: - Tids990Encoder(const Tids990EncoderProto& config): - _config(config) - {} - virtual ~Tids990Encoder() {} - -private: - void writeRawBits(uint32_t data, int width); - void writeBytes(const Bytes& bytes); - void writeBytes(int count, uint8_t value); - void writeSync(); - -public: - std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); - -private: - const Tids990EncoderProto& _config; - std::vector _bits; - unsigned _cursor; - bool _lastBit; -}; - -extern FlagGroup tids990EncoderFlags; +class AbstractEncoder; +class AbstractDecoder; +class DecoderProto; +class EncoderProto; extern std::unique_ptr createTids990Decoder(const DecoderProto& config); diff --git a/lib/encoders/encoders.cc b/lib/encoders/encoders.cc index ad228bb7..bc091158 100644 --- a/lib/encoders/encoders.cc +++ b/lib/encoders/encoders.cc @@ -14,33 +14,24 @@ std::unique_ptr AbstractEncoder::create(const EncoderProto& config) { - switch (config.format_case()) + static const std::map(const EncoderProto&)>> encoders = { - case EncoderProto::kAmiga: - return std::unique_ptr(new AmigaEncoder(config.amiga())); + { EncoderProto::kAmiga, createAmigaEncoder }, + { EncoderProto::kBrother, createBrotherEncoder }, + { EncoderProto::kC64, createCommodore64Encoder }, + { EncoderProto::kIbm, createIbmEncoder }, + { EncoderProto::kMacintosh, createMacintoshEncoder }, + { EncoderProto::kNorthstar, createNorthstarEncoder }, + }; - case EncoderProto::kIbm: - return std::unique_ptr(new IbmEncoder(config.ibm())); + auto encoder = encoders.find(config.format_case()); + if (encoder == encoders.end()) + Error() << "no encoder specified"; - case EncoderProto::kBrother: - return std::unique_ptr(new BrotherEncoder(config.brother())); - - case EncoderProto::kMacintosh: - return std::unique_ptr(new MacintoshEncoder(config.macintosh())); - - case EncoderProto::kC64: - return std::unique_ptr(new Commodore64Encoder(config.c64())); - - case EncoderProto::kNorthstar: - return std::unique_ptr(new NorthstarEncoder(config.northstar())); - - default: - Error() << "no input disk format specified"; - } - return std::unique_ptr(); + return (encoder->second)(config); } - Fluxmap& Fluxmap::appendBits(const std::vector& bits, nanoseconds_t clock) { nanoseconds_t now = duration(); diff --git a/lib/encoders/encoders.h b/lib/encoders/encoders.h index 03266f71..6bd6674f 100644 --- a/lib/encoders/encoders.h +++ b/lib/encoders/encoders.h @@ -9,7 +9,7 @@ class EncoderProto; class AbstractEncoder { public: - virtual ~AbstractEncoder() {} + AbstractEncoder(const EncoderProto& config) {} static std::unique_ptr create(const EncoderProto& config);