#include "lib/core/globals.h" #include "lib/data/fluxmap.h" #include "lib/data/fluxmapreader.h" #include "lib/data/fluxpattern.h" #include "protocol.h" #include "lib/decoders/decoders.h" #include "lib/data/sector.h" #include "arch/amiga/amiga.h" #include "lib/core/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 Decoder { public: AmigaDecoder(const DecoderProto& config): Decoder(config), _config(config.amiga()) { } nanoseconds_t advanceToNextRecord() override { return seekToPattern(SECTOR_PATTERN); } void decodeSectorRecord() override { if (readRaw48() != AMIGA_SECTOR_RECORD) return; 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(); 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(0, 40)); if (gotheaderchecksum != wantedheaderchecksum) return; uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(56, 1024)); Bytes data; data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); _sector->data = data; _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; } private: const AmigaDecoderProto& _config; nanoseconds_t _clock; }; std::unique_ptr createAmigaDecoder(const DecoderProto& config) { return std::unique_ptr(new AmigaDecoder(config)); }