mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
150 lines
3.2 KiB
C++
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));
|
|
}
|
|
|
|
|