mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Port the Brother decoder to the new *new* architecture.
This commit is contained in:
@@ -3,22 +3,23 @@
|
||||
|
||||
/* Brother word processor format (or at least, one of them) */
|
||||
|
||||
#define BROTHER_SECTOR_RECORD 0xFFFFFD57
|
||||
#define BROTHER_DATA_RECORD 0xFFFFFDDB
|
||||
#define BROTHER_DATA_RECORD_PAYLOAD 256
|
||||
#define BROTHER_DATA_RECORD_CHECKSUM 3
|
||||
#define BROTHER_SECTOR_RECORD 0xFFFFFD57
|
||||
#define BROTHER_DATA_RECORD 0xFFFFFDDB
|
||||
#define BROTHER_DATA_RECORD_PAYLOAD 256
|
||||
#define BROTHER_DATA_RECORD_CHECKSUM 3
|
||||
#define BROTHER_DATA_RECORD_ENCODED_SIZE 415
|
||||
|
||||
class Sector;
|
||||
class Fluxmap;
|
||||
|
||||
class BrotherDecoder : public AbstractSoftSectorDecoder
|
||||
class BrotherDecoder : public AbstractSimplifiedDecoder
|
||||
{
|
||||
public:
|
||||
virtual ~BrotherDecoder() {}
|
||||
|
||||
SectorVector decodeToSectors(
|
||||
const RawRecordVector& rawRecords, unsigned physicalTrack, unsigned physicalSide);
|
||||
int recordMatcher(uint64_t fifo) const;
|
||||
RecordType advanceToNextRecord();
|
||||
void decodeSectorRecord();
|
||||
void decodeDataRecord();
|
||||
};
|
||||
|
||||
extern void writeBrotherSectorHeader(std::vector<bool>& bits, unsigned& cursor,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "globals.h"
|
||||
#include "sql.h"
|
||||
#include "fluxmap.h"
|
||||
#include "fluxmapreader.h"
|
||||
#include "decoders.h"
|
||||
#include "record.h"
|
||||
#include "brother.h"
|
||||
@@ -9,6 +10,10 @@
|
||||
#include "crc.h"
|
||||
#include <ctype.h>
|
||||
|
||||
const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD);
|
||||
const FluxPattern DATA_RECORD_PATTERN(32, BROTHER_DATA_RECORD);
|
||||
const FluxMatchers ANY_RECORD_PATTERN({ &SECTOR_RECORD_PATTERN, &DATA_RECORD_PATTERN });
|
||||
|
||||
static std::vector<uint8_t> outputbuffer;
|
||||
|
||||
/*
|
||||
@@ -48,89 +53,56 @@ static int decode_header_gcr(uint16_t word)
|
||||
return -1;
|
||||
};
|
||||
|
||||
SectorVector BrotherDecoder::decodeToSectors(const RawRecordVector& rawRecords, unsigned, unsigned)
|
||||
AbstractSimplifiedDecoder::RecordType BrotherDecoder::advanceToNextRecord()
|
||||
{
|
||||
std::vector<std::unique_ptr<Sector>> sectors;
|
||||
bool headerIsValid = false;
|
||||
unsigned nextTrack = 0;
|
||||
unsigned nextSector = 0;
|
||||
const FluxMatcher* matcher = nullptr;
|
||||
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
|
||||
if (matcher == &SECTOR_RECORD_PATTERN)
|
||||
return RecordType::SECTOR_RECORD;
|
||||
if (matcher == &DATA_RECORD_PATTERN)
|
||||
return RecordType::DATA_RECORD;
|
||||
return RecordType::UNKNOWN_RECORD;
|
||||
}
|
||||
|
||||
for (auto& rawrecord : rawRecords)
|
||||
{
|
||||
if (rawrecord->data.size() < 64)
|
||||
{
|
||||
headerIsValid = false;
|
||||
continue;
|
||||
}
|
||||
void BrotherDecoder::decodeSectorRecord()
|
||||
{
|
||||
_fmr->readRawBits(32, _sector->clock);
|
||||
const auto& rawbits = _fmr->readRawBits(32, _sector->clock);
|
||||
const auto& bytes = toBytes(rawbits).slice(0, 4);
|
||||
|
||||
auto ii = rawrecord->data.cbegin();
|
||||
uint32_t signature = toBytes(ii, ii+32).reader().read_be32();
|
||||
switch (signature)
|
||||
{
|
||||
case BROTHER_SECTOR_RECORD:
|
||||
{
|
||||
headerIsValid = false;
|
||||
if (rawrecord->data.size() < (32+32))
|
||||
break;
|
||||
ByteReader br(bytes);
|
||||
_sector->logicalTrack = decode_header_gcr(br.read_be16());
|
||||
_sector->logicalSector = decode_header_gcr(br.read_be16());
|
||||
|
||||
const auto& by = toBytes(ii+32, ii+64);
|
||||
ByteReader br(by);
|
||||
nextTrack = decode_header_gcr(br.read_be16());
|
||||
nextSector = decode_header_gcr(br.read_be16());
|
||||
/* Sanity check the values read; there's no header checksum and
|
||||
* occasionally we get garbage due to bit errors. */
|
||||
if (_sector->logicalSector > 11)
|
||||
return;
|
||||
if (_sector->logicalTrack > 79)
|
||||
return;
|
||||
|
||||
/* Sanity check the values read; there's no header checksum and
|
||||
* occasionally we get garbage due to bit errors. */
|
||||
if (nextSector > 11)
|
||||
break;
|
||||
if (nextTrack > 79)
|
||||
break;
|
||||
_sector->status = Sector::DATA_MISSING;
|
||||
}
|
||||
|
||||
headerIsValid = true;
|
||||
break;
|
||||
}
|
||||
void BrotherDecoder::decodeDataRecord()
|
||||
{
|
||||
_fmr->readRawBits(32, _sector->clock);
|
||||
|
||||
case BROTHER_DATA_RECORD:
|
||||
{
|
||||
if (!headerIsValid)
|
||||
break;
|
||||
const auto& rawbits = _fmr->readRawBits(BROTHER_DATA_RECORD_ENCODED_SIZE*8, _sector->clock);
|
||||
const auto& rawbytes = toBytes(rawbits).slice(0, BROTHER_DATA_RECORD_ENCODED_SIZE);
|
||||
|
||||
Bytes rawbytes = toBytes(rawrecord->data.cbegin()+32, rawrecord->data.cend());
|
||||
const int totalsize = BROTHER_DATA_RECORD_PAYLOAD + BROTHER_DATA_RECORD_CHECKSUM;
|
||||
|
||||
Bytes output;
|
||||
ByteWriter bw(output);
|
||||
BitWriter bitw(bw);
|
||||
for (uint8_t b : rawbytes)
|
||||
{
|
||||
uint32_t nibble = decode_data_gcr(b);
|
||||
bitw.push(nibble, 5);
|
||||
if (output.size() == totalsize)
|
||||
break;
|
||||
}
|
||||
bitw.flush();
|
||||
output.resize(totalsize);
|
||||
|
||||
Bytes payload = output.slice(0, BROTHER_DATA_RECORD_PAYLOAD);
|
||||
uint32_t realCrc = crcbrother(payload);
|
||||
uint32_t wantCrc = output.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24();
|
||||
int status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
|
||||
|
||||
auto sector = std::unique_ptr<Sector>(
|
||||
new Sector(status, nextTrack, 0, nextSector, payload));
|
||||
sectors.push_back(std::move(sector));
|
||||
headerIsValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Bytes bytes;
|
||||
ByteWriter bw(bytes);
|
||||
BitWriter bitw(bw);
|
||||
for (uint8_t b : rawbytes)
|
||||
{
|
||||
uint32_t nibble = decode_data_gcr(b);
|
||||
bitw.push(nibble, 5);
|
||||
}
|
||||
bitw.flush();
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
int BrotherDecoder::recordMatcher(uint64_t fifo) const
|
||||
{
|
||||
uint32_t masked = fifo & 0xffffffff;
|
||||
if ((masked == BROTHER_SECTOR_RECORD) || (masked == BROTHER_DATA_RECORD))
|
||||
return 32;
|
||||
return 0;
|
||||
_sector->data = bytes.slice(0, BROTHER_DATA_RECORD_PAYLOAD);
|
||||
uint32_t realCrc = crcbrother(_sector->data);
|
||||
uint32_t wantCrc = bytes.reader().seek(BROTHER_DATA_RECORD_PAYLOAD).read_be24();
|
||||
_sector->status = (realCrc == wantCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
|
||||
}
|
||||
|
||||
@@ -169,6 +169,72 @@ nanoseconds_t AbstractDecoder::guessClockImpl(Track& track) const
|
||||
return track.fluxmap->guessClock();
|
||||
}
|
||||
|
||||
void AbstractSimplifiedDecoder::decodeToSectors(Track& track)
|
||||
{
|
||||
Sector sector;
|
||||
sector.physicalSide = track.physicalSide;
|
||||
sector.physicalTrack = track.physicalTrack;
|
||||
FluxmapReader fmr(*track.fluxmap);
|
||||
|
||||
_track = &track;
|
||||
_sector = §or;
|
||||
_fmr = &fmr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Fluxmap::Position recordStart = sector.position = fmr.tell();
|
||||
sector.clock = 0;
|
||||
sector.status = Sector::MISSING;
|
||||
sector.data.clear();
|
||||
sector.logicalSector = sector.logicalSide = sector.logicalTrack = 0;
|
||||
RecordType r = advanceToNextRecord();
|
||||
if (fmr.eof() || !sector.clock)
|
||||
return;
|
||||
if ((r == UNKNOWN_RECORD) || (r == DATA_RECORD))
|
||||
{
|
||||
fmr.readNextMatchingOpcode(F_OP_PULSE);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read the sector record. */
|
||||
|
||||
recordStart = fmr.tell();
|
||||
decodeSectorRecord();
|
||||
pushRecord(recordStart, fmr.tell());
|
||||
if (sector.status == Sector::DATA_MISSING)
|
||||
{
|
||||
/* The data is in a separate record. */
|
||||
|
||||
r = advanceToNextRecord();
|
||||
if (r == DATA_RECORD)
|
||||
{
|
||||
recordStart = fmr.tell();
|
||||
decodeDataRecord();
|
||||
pushRecord(recordStart, fmr.tell());
|
||||
}
|
||||
}
|
||||
|
||||
if (sector.status != Sector::MISSING)
|
||||
track.sectors.push_back(sector);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSimplifiedDecoder::pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end)
|
||||
{
|
||||
Fluxmap::Position here = _fmr->tell();
|
||||
|
||||
RawRecord record;
|
||||
record.physicalSide = _track->physicalSide;
|
||||
record.physicalTrack = _track->physicalTrack;
|
||||
record.clock = _sector->clock;
|
||||
record.position = start;
|
||||
|
||||
_fmr->seek(start);
|
||||
record.data = toBytes(_fmr->readRawBits(end, _sector->clock));
|
||||
_track->rawrecords.push_back(record);
|
||||
_fmr->seek(here);
|
||||
}
|
||||
|
||||
void AbstractStatefulDecoder::decodeToSectors(Track& track)
|
||||
{
|
||||
Sector sector;
|
||||
|
||||
@@ -34,6 +34,30 @@ public:
|
||||
virtual void decodeToSectors(Track& track) = 0;
|
||||
};
|
||||
|
||||
class AbstractSimplifiedDecoder : public AbstractDecoder
|
||||
{
|
||||
public:
|
||||
enum RecordType
|
||||
{
|
||||
SECTOR_RECORD,
|
||||
DATA_RECORD,
|
||||
UNKNOWN_RECORD
|
||||
};
|
||||
|
||||
public:
|
||||
void decodeToSectors(Track& track) override;
|
||||
void pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end);
|
||||
|
||||
protected:
|
||||
virtual RecordType advanceToNextRecord() = 0;
|
||||
virtual void decodeSectorRecord() = 0;
|
||||
virtual void decodeDataRecord() {};
|
||||
|
||||
FluxmapReader* _fmr;
|
||||
Track* _track;
|
||||
Sector* _sector;
|
||||
};
|
||||
|
||||
class AbstractStatefulDecoder : public AbstractDecoder
|
||||
{
|
||||
public:
|
||||
|
||||
20
meson.build
20
meson.build
@@ -151,15 +151,15 @@ apple2decoderlib = declare_dependency(
|
||||
include_directories('lib/apple2')
|
||||
)
|
||||
|
||||
#brotherdecoderlib = declare_dependency(
|
||||
# link_with:
|
||||
# shared_library('brotherdecoderlib',
|
||||
# [ 'lib/brother/decoder.cc', ],
|
||||
# dependencies: [fmtlib, felib, decoderlib, sqlite]),
|
||||
# include_directories:
|
||||
# include_directories('lib/brother')
|
||||
#)
|
||||
#
|
||||
brotherdecoderlib = declare_dependency(
|
||||
link_with:
|
||||
shared_library('brotherdecoderlib',
|
||||
[ 'lib/brother/decoder.cc', ],
|
||||
dependencies: [fmtlib, felib, decoderlib, sqlite]),
|
||||
include_directories:
|
||||
include_directories('lib/brother')
|
||||
)
|
||||
|
||||
#brotherencoderlib = declare_dependency(
|
||||
# link_with:
|
||||
# shared_library('brotherencoderlib',
|
||||
@@ -239,7 +239,7 @@ executable('fe-readaeslanier', ['src/fe-readaeslanier.cc'], dependencies
|
||||
executable('fe-readamiga', ['src/fe-readamiga.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, amigadecoderlib])
|
||||
executable('fe-readampro', ['src/fe-readampro.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, ibmdecoderlib])
|
||||
executable('fe-readapple2', ['src/fe-readapple2.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, apple2decoderlib])
|
||||
#executable('fe-readbrother', ['src/fe-readbrother.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, brotherdecoderlib])
|
||||
executable('fe-readbrother', ['src/fe-readbrother.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, brotherdecoderlib])
|
||||
executable('fe-readc64', ['src/fe-readc64.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, c64decoderlib])
|
||||
executable('fe-readdfs', ['src/fe-readdfs.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, ibmdecoderlib])
|
||||
executable('fe-readf85', ['src/fe-readf85.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, f85decoderlib])
|
||||
|
||||
Reference in New Issue
Block a user