#include "globals.h" #include "fluxmap.h" #include "decoders/fluxmapreader.h" #include "protocol.h" #include "decoders/decoders.h" #include "sector.h" #include "amiga.h" #include "bytes.h" #include "fmt/format.h" #include "lib/decoders/decoders.pb.h" #include #include /* * Amiga disks use MFM but it's not quite the same as IBM MFM. They only use * a single type of record with a different marker byte. * * See the big comment in the IBM MFM decoder for the gruesome details of how * MFM works. */ static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD); class AmigaDecoder : public AbstractDecoder { public: AmigaDecoder(const DecoderProto& config): AbstractDecoder(config), _config(config.amiga()) {} RecordType advanceToNextRecord() override { _sector->clock = _fmr->seekToPattern(SECTOR_PATTERN); if (_fmr->eof() || !_sector->clock) return UNKNOWN_RECORD; return SECTOR_RECORD; } void decodeSectorRecord() override { const auto& rawbits = readRawBits(AMIGA_RECORD_SIZE*16); if (rawbits.size() < (AMIGA_RECORD_SIZE*16)) return; const auto& rawbytes = toBytes(rawbits).slice(0, AMIGA_RECORD_SIZE*2); const auto& bytes = decodeFmMfm(rawbits).slice(0, AMIGA_RECORD_SIZE); const uint8_t* ptr = bytes.begin() + 3; Bytes header = amigaDeinterleave(ptr, 4); Bytes recoveryinfo = amigaDeinterleave(ptr, 16); _sector->logicalTrack = header[1] >> 1; _sector->logicalSide = header[1] & 1; _sector->logicalSector = header[2]; uint32_t wantedheaderchecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(6, 40)); if (gotheaderchecksum != wantedheaderchecksum) return; uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(62, 1024)); Bytes data; data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); _sector->data = data; _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; } std::set requiredSectors(unsigned cylinder, unsigned head) const override { static std::set sectors = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; return sectors; } private: const AmigaDecoderProto& _config; }; std::unique_ptr createAmigaDecoder(const DecoderProto& config) { return std::unique_ptr(new AmigaDecoder(config)); }