Files
fluxengine/arch/fb100/decoder.cc
dg 4ab66afca0 Split the encoder's use of clock and bitcell, as for FM/MFM they're different
things; make the FM/MFM decoders use twice the bitcell for the clock.
2021-12-06 23:18:31 +00:00

150 lines
3.2 KiB
C++

#include "globals.h"
#include "fluxmap.h"
#include "decoders/fluxmapreader.h"
#include "protocol.h"
#include "decoders/decoders.h"
#include "sector.h"
#include "fb100.h"
#include "crc.h"
#include "bytes.h"
#include "decoders/rawbits.h"
#include "fmt/format.h"
#include <string.h>
#include <algorithm>
const FluxPattern SECTOR_ID_PATTERN(16, 0xabaa);
/*
* Reverse engineered from a dump of the floppy drive's ROM. I have no idea how
* it works.
*
* LF8BA:
* clra
* staa X00B0
* staa X00B1
* ldx #$8000
* LF8C2: ldaa $00,x
* inx
* bsr LF8CF
* cpx #$8011
* bne LF8C2
* ldd X00B0
* rts
* LF8CF:
* eora X00B0
* staa X00CF
* asla
* asla
* asla
* asla
* eora X00CF
* staa X00CF
* rola
* rola
* rola
* tab
* anda #$F8
* eora X00B1
* staa X00B0
* rolb
* rolb
* andb #$0F
* eorb X00B0
* stab X00B0
* rolb
* eorb X00CF
* stab X00B1
* rts
*/
static void rol(uint8_t& b, bool& c)
{
bool newc = b & 0x80;
b <<= 1;
b |= c;
c = newc;
}
static uint16_t checksum(const Bytes& bytes)
{
uint8_t crclo = 0;
uint8_t crchi = 0;
for (uint8_t a : bytes)
{
a ^= crchi;
uint8_t t1 = a;
a <<= 4;
bool c = a & 0x10;
a ^= t1;
t1 = a;
rol(a, c);
rol(a, c);
rol(a, c);
uint8_t b = a;
a &= 0xf8;
a ^= crclo;
crchi = a;
rol(b, c);
rol(b, c);
b &= 0x0f;
b ^= crchi;
crchi = b;
rol(b, c);
b ^= t1;
crclo = b;
}
return (crchi << 8) | crclo;
}
class Fb100Decoder : public AbstractDecoder
{
public:
Fb100Decoder(const DecoderProto& config):
AbstractDecoder(config)
{}
RecordType advanceToNextRecord()
{
const FluxMatcher* matcher = nullptr;
_sector->bitcell = _fmr->seekToPattern(SECTOR_ID_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
if (matcher == &SECTOR_ID_PATTERN)
return RecordType::SECTOR_RECORD;
return RecordType::UNKNOWN_RECORD;
}
void decodeSectorRecord()
{
auto rawbits = readRawBits(FB100_RECORD_SIZE*16);
const Bytes bytes = decodeFmMfm(rawbits).slice(0, FB100_RECORD_SIZE);
ByteReader br(bytes);
br.seek(1);
const Bytes id = br.read(FB100_ID_SIZE);
uint16_t wantIdCrc = br.read_be16();
uint16_t gotIdCrc = checksum(id);
const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
uint16_t wantPayloadCrc = br.read_be16();
uint16_t gotPayloadCrc = checksum(payload);
if (wantIdCrc != gotIdCrc)
return;
uint8_t abssector = id[2];
_sector->logicalTrack = abssector >> 1;
_sector->logicalSide = 0;
_sector->logicalSector = abssector & 1;
_sector->data.writer().append(id.slice(5, 12)).append(payload);
_sector->status = (wantPayloadCrc == gotPayloadCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
}
};
std::unique_ptr<AbstractDecoder> createFb100Decoder(const DecoderProto& config)
{
return std::unique_ptr<AbstractDecoder>(new Fb100Decoder(config));
}