From 56cbf39d59831389fe93ef24d3d07d906c6d9edd Mon Sep 17 00:00:00 2001 From: David Given Date: Mon, 5 Jul 2021 23:16:03 +0200 Subject: [PATCH] Finally make the Amiga encoder work properly. Do some FM/MFM/bits refactoring. --- arch/amiga/encoder.cc | 62 +++++++++++++++++++++++------------------ lib/bytes.cc | 16 +++++++++++ lib/bytes.h | 19 +++++++++++++ lib/decoders/decoders.h | 1 + lib/decoders/fmmfm.cc | 22 +++++++++++++++ 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index 5869d36b..91d17158 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -22,13 +22,14 @@ static void write_bits(std::vector& bits, unsigned& cursor, const std::vec for (bool bit : src) { if (cursor < bits.size()) - bits[cursor++] = bit; + lastBit = bits[cursor++] = bit; } } static void write_bits(std::vector& bits, unsigned& cursor, uint64_t data, int width) { cursor += width; + lastBit = data & 1; for (int i=0; i& bits, unsigned& cursor, uint64_t data, } } -static void write_interleaved_bytes(std::vector& bits, unsigned& cursor, const Bytes& bytes) +static void write_bits(std::vector& bits, unsigned& cursor, const Bytes& bytes) { - assert(!(bytes.size() & 3)); - Bytes interleaved = amigaInterleave(bytes); - encodeMfm(bits, cursor, interleaved, lastBit); -} + ByteReader br(bytes); + BitReader bitr(br); -static void write_interleaved_bytes(std::vector& bits, unsigned& cursor, uint32_t data) -{ - Bytes b(4); - ByteWriter bw(b); - bw.write_be32(data); - write_interleaved_bytes(bits, cursor, b); + while (!bitr.eof()) + { + if (cursor < bits.size()) + bits[cursor++] = bitr.get(); + } } static void write_sector(std::vector& bits, unsigned& cursor, const Sector* sector) @@ -58,11 +56,27 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector if ((sector->data.size() != 512) && (sector->data.size() != 528)) Error() << "unsupported sector size --- you must pick 512 or 528"; + uint32_t checksum = 0; + + auto write_interleaved_bytes = [&](const Bytes& bytes) + { + Bytes interleaved = amigaInterleave(bytes); + Bytes mfm = encodeMfm(interleaved, lastBit); + checksum ^= amigaChecksum(mfm); + checksum &= 0x55555555; + write_bits(bits, cursor, mfm); + }; + + auto write_interleaved_word = [&](uint32_t word) + { + Bytes b(4); + b.writer().write_be32(word); + write_interleaved_bytes(b); + }; + write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8); - std::vector headerBits(20*16); - unsigned headerCursor = 0; - + checksum = 0; Bytes header = { 0xff, /* Amiga 1.0 format byte */ @@ -70,22 +84,16 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector (uint8_t) sector->logicalSector, (uint8_t) (AMIGA_SECTORS_PER_TRACK - sector->logicalSector) }; - write_interleaved_bytes(headerBits, headerCursor, header); + write_interleaved_bytes(header); Bytes recoveryInfo(16); if (sector->data.size() == 528) recoveryInfo = sector->data.slice(512, 16); - write_interleaved_bytes(headerBits, headerCursor, recoveryInfo); + write_interleaved_bytes(recoveryInfo); + write_interleaved_word(checksum); - std::vector dataBits(512*16); - unsigned dataCursor = 0; - write_interleaved_bytes(dataBits, dataCursor, sector->data); - - write_bits(bits, cursor, headerBits); - uint32_t headerChecksum = amigaChecksum(toBytes(headerBits)); - write_interleaved_bytes(bits, cursor, headerChecksum); - uint32_t dataChecksum = amigaChecksum(toBytes(dataBits)); - write_interleaved_bytes(bits, cursor, dataChecksum); - write_bits(bits, cursor, dataBits); + Bytes data = sector->data.slice(0, 512); + write_interleaved_word(amigaChecksum(encodeMfm(amigaInterleave(data), lastBit))); + write_interleaved_bytes(data); } std::unique_ptr AmigaEncoder::encode( diff --git a/lib/bytes.cc b/lib/bytes.cc index 23610295..d3a896b2 100644 --- a/lib/bytes.cc +++ b/lib/bytes.cc @@ -316,6 +316,22 @@ void BitWriter::flush() } } +bool BitReader::eof() +{ + return (_bitcount == 0) && _br.eof(); +} + +bool BitReader::get() +{ + if (_bitcount == 0) + _fifo = _br.read_8(); + + bool bit = _fifo & 0x80; + _fifo <<= 1; + _bitcount = (_bitcount+1) & 7; + return bit; +} + std::vector reverseBits(const std::vector& bits) { std::vector output(bits.rbegin(), bits.rend()); diff --git a/lib/bytes.h b/lib/bytes.h index d7651770..19011001 100644 --- a/lib/bytes.h +++ b/lib/bytes.h @@ -310,6 +310,7 @@ public: BitWriter(ByteWriter&&) = delete; void push(uint32_t bits, size_t size); + void push(bool bit) { push(bit, 1); } void flush(); private: @@ -318,6 +319,24 @@ private: ByteWriter& _bw; }; +class BitReader +{ +public: + BitReader(ByteReader& br): + _br(br) + {} + + BitReader(ByteReader&&) = delete; + + bool get(); + bool eof(); + +private: + uint8_t _fifo = 0; + size_t _bitcount = 0; + ByteReader& _br; +}; + static inline uint8_t reverse_bits(uint8_t b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; diff --git a/lib/decoders/decoders.h b/lib/decoders/decoders.h index 43f2c722..555d127a 100644 --- a/lib/decoders/decoders.h +++ b/lib/decoders/decoders.h @@ -23,6 +23,7 @@ extern Bytes decodeFmMfm(std::vector::const_iterator start, std::vector::const_iterator end); extern void encodeMfm(std::vector& bits, unsigned& cursor, const Bytes& input, bool& lastBit); extern void encodeFm(std::vector& bits, unsigned& cursor, const Bytes& input); +extern Bytes encodeMfm(const Bytes& input, bool& lastBit); static inline Bytes decodeFmMfm(const std::vector bits) { return decodeFmMfm(bits.begin(), bits.end()); } diff --git a/lib/decoders/fmmfm.cc b/lib/decoders/fmmfm.cc index a4006a27..40dfd548 100644 --- a/lib/decoders/fmmfm.cc +++ b/lib/decoders/fmmfm.cc @@ -96,3 +96,25 @@ void encodeMfm(std::vector& bits, unsigned& cursor, const Bytes& input, bo } } } + +Bytes encodeMfm(const Bytes& input, bool& lastBit) +{ + ByteReader br(input); + BitReader bitr(br); + Bytes b; + ByteWriter bw(b); + BitWriter bitw(bw); + + while (!bitr.eof()) + { + uint8_t bit = bitr.get(); + + bitw.push(!lastBit && !bit); + bitw.push(bit); + lastBit = bit; + } + + bitw.flush(); + return b; +} +