mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
91 lines
2.9 KiB
C++
91 lines
2.9 KiB
C++
#include "lib/core/globals.h"
|
|
#include "lib/decoders/decoders.h"
|
|
#include "arch/agat/agat.h"
|
|
#include "lib/core/crc.h"
|
|
#include "lib/data/fluxmap.h"
|
|
#include "lib/data/fluxmapreader.h"
|
|
#include "lib/data/fluxpattern.h"
|
|
#include "lib/data/sector.h"
|
|
#include "lib/core/bytes.h"
|
|
#include "fmt/format.h"
|
|
#include <string.h>
|
|
|
|
// clang-format off
|
|
/*
|
|
* data: X X X X X X X X X - - X - X - X - X X - X - X - = 0xff956a
|
|
* flux: 01 01 01 01 01 01 01 01 01 00 10 01 00 01 00 01 00 01 01 00 01 00 01 00 = 0x555549111444
|
|
*
|
|
* data: X X X X X X X X - X X - X - X - X - - X - X - X = 0xff6a95
|
|
* flux: 01 01 01 01 01 01 01 01 00 01 01 00 01 00 01 00 01 00 10 01 00 01 00 01 = 0x555514444911
|
|
*
|
|
* Each pattern is prefixed with this one:
|
|
*
|
|
* data: - - - X - - X - = 0x12
|
|
* flux: (10) 10 10 10 01 00 10 01 00 = 0xa924
|
|
* magic: (10) 10 00 10 01 00 10 01 00 = 0x8924
|
|
* ^
|
|
*
|
|
* This seems to be generated by emitting A4 in MFM and then a single 0 bit to
|
|
* shift it out of phase, so the data bits become clock bits and vice versa.
|
|
*
|
|
* X - X - - X - - = 0xA4
|
|
* 0100010010010010 = MFM encoded
|
|
* 1000100100100100 = with trailing zero
|
|
* - - - X - - X - = effective bitstream = 0x12
|
|
*/
|
|
// clang-format on
|
|
|
|
static const FluxPattern SECTOR_PATTERN(64, SECTOR_ID);
|
|
static const FluxPattern DATA_PATTERN(64, DATA_ID);
|
|
|
|
static const FluxMatchers ALL_PATTERNS = {&SECTOR_PATTERN, &DATA_PATTERN};
|
|
|
|
class AgatDecoder : public Decoder
|
|
{
|
|
public:
|
|
AgatDecoder(const DecoderProto& config): Decoder(config) {}
|
|
|
|
nanoseconds_t advanceToNextRecord() override
|
|
{
|
|
return seekToPattern(ALL_PATTERNS);
|
|
}
|
|
|
|
void decodeSectorRecord() override
|
|
{
|
|
if (readRaw64() != SECTOR_ID)
|
|
return;
|
|
|
|
auto bytes = decodeFmMfm(readRawBits(64)).slice(0, 4);
|
|
if (bytes[3] != 0x5a)
|
|
return;
|
|
|
|
_sector->logicalTrack = bytes[1] >> 1;
|
|
_sector->logicalSector = bytes[2];
|
|
_sector->logicalSide = bytes[1] & 1;
|
|
_sector->status = Sector::DATA_MISSING; /* unintuitive but correct */
|
|
}
|
|
|
|
void decodeDataRecord() override
|
|
{
|
|
if (readRaw64() != DATA_ID)
|
|
return;
|
|
|
|
Bytes bytes = decodeFmMfm(readRawBits((AGAT_SECTOR_SIZE + 2) * 16))
|
|
.slice(0, AGAT_SECTOR_SIZE + 2);
|
|
|
|
if (bytes[AGAT_SECTOR_SIZE + 1] != 0x5a)
|
|
return;
|
|
|
|
_sector->data = bytes.slice(0, AGAT_SECTOR_SIZE);
|
|
uint8_t wantChecksum = bytes[AGAT_SECTOR_SIZE];
|
|
uint8_t gotChecksum = agatChecksum(_sector->data);
|
|
_sector->status =
|
|
(wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<Decoder> createAgatDecoder(const DecoderProto& config)
|
|
{
|
|
return std::unique_ptr<Decoder>(new AgatDecoder(config));
|
|
}
|