Add the prototype MX decoder.

This commit is contained in:
David Given
2019-07-02 00:40:38 +02:00
parent bba2f856a5
commit 3ee31b96a4
9 changed files with 156 additions and 1 deletions

View File

@@ -1,6 +1,9 @@
all: .obj/build.ninja
@ninja -C .obj test
clean:
rm -rf .obj
.obj/build.ninja:
@mkdir -p .obj
meson .obj
meson .obj --buildtype=debugoptimized

View File

@@ -168,6 +168,23 @@ Bytes toBytes(
return bytes;
}
Bytes Bytes::swab() const
{
Bytes output;
ByteWriter bw(output);
ByteReader br(*this);
while (!br.eof())
{
uint8_t a = br.read_8();
uint8_t b = br.read_8();
bw.write_8(b);
bw.write_8(a);
}
return output;
}
Bytes Bytes::compress() const
{
uLongf destsize = compressBound(size());

View File

@@ -47,6 +47,7 @@ public:
{ resize(0); return *this; }
Bytes slice(unsigned start, unsigned len) const;
Bytes swab() const;
Bytes compress() const;
Bytes decompress() const;
Bytes crunch() const;

View File

@@ -22,6 +22,7 @@ void AbstractDecoder::decodeToSectors(Track& track)
_sector = &sector;
_fmr = &fmr;
beginTrack();
for (;;)
{
Fluxmap::Position recordStart = sector.position = fmr.tell();

View File

@@ -51,6 +51,7 @@ public:
{ return _fmr->seek(pos); }
protected:
virtual void beginTrack() {};
virtual RecordType advanceToNextRecord() = 0;
virtual void decodeSectorRecord() = 0;
virtual void decodeDataRecord() {};

75
lib/mx/decoder.cc Normal file
View File

@@ -0,0 +1,75 @@
#include "globals.h"
#include "decoders.h"
#include "mx.h"
#include "crc.h"
#include "fluxmap.h"
#include "fluxmapreader.h"
#include "sector.h"
#include "record.h"
#include "track.h"
#include <string.h>
const int SECTOR_SIZE = 256;
/*
* MX disks are a bunch of sectors glued together with no gaps or sync markers,
* following a single beginning-of-track synchronisation and identification
* sequence.
*/
/* FM beginning of track marker:
* 1010 1010 1010 1010 1111 1111 1010 1111
* a a a a f f a f
*/
const FluxPattern ID_PATTERN(32, 0xaaaaffaf);
void MxDecoder::beginTrack()
{
_currentSector = -1;
_clock = 0;
}
AbstractDecoder::RecordType MxDecoder::advanceToNextRecord()
{
if (_currentSector == -1)
{
/* First sector in the track: look for the sync marker. */
const FluxMatcher* matcher = nullptr;
_sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher);
readRawBits(32); /* skip the ID mark */
readRawBits(32); /* skip the track number */
}
else if (_currentSector == 10)
{
/* That was the last sector on the disk. */
return UNKNOWN_RECORD;
}
else
{
/* Otherwise we assume the clock from the first sector is still valid.
* The decoder framwork will automatically stop when we hit the end of
* the track. */
_sector->clock = _clock;
}
_currentSector++;
return SECTOR_RECORD;
}
void MxDecoder::decodeSectorRecord()
{
auto bits = readRawBits((SECTOR_SIZE+2)*16);
auto bytes = decodeFmMfm(bits).slice(0, SECTOR_SIZE+2).swab();
uint16_t gotChecksum = 0;
ByteReader br(bytes);
for (int i=0; i<(SECTOR_SIZE/2); i++)
gotChecksum += br.read_le16();
uint16_t wantChecksum = br.read_le16();
_sector->logicalTrack = _track->physicalTrack;
_sector->logicalSide = _track->physicalSide;
_sector->logicalSector = _currentSector;
_sector->data = bytes.slice(0, SECTOR_SIZE);
_sector->status = (gotChecksum == wantChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
}

20
lib/mx/mx.h Normal file
View File

@@ -0,0 +1,20 @@
#ifndef MX_H
#define MX_H
#include "decoders.h"
class MxDecoder : public AbstractDecoder
{
public:
virtual ~MxDecoder() {}
void beginTrack();
RecordType advanceToNextRecord();
void decodeSectorRecord();
private:
nanoseconds_t _clock;
int _currentSector;
};
#endif

View File

@@ -214,6 +214,15 @@ macdecoderlib = declare_dependency(
include_directories('lib/macintosh')
)
mxdecoderlib = declare_dependency(
link_with:
shared_library('mxdecoderlib',
[ 'lib/mx/decoder.cc', ],
dependencies: [fmtlib, felib, decoderlib]),
include_directories:
include_directories('lib/mx')
)
zilogmczdecoderlib = declare_dependency(
link_with:
shared_library('zilogmczdecoderlib',
@@ -246,6 +255,7 @@ executable('fe-readf85', ['src/fe-readf85.cc'], dependencies
executable('fe-readfb100', ['src/fe-readfb100.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, fb100decoderlib])
executable('fe-readibm', ['src/fe-readibm.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, ibmdecoderlib])
executable('fe-readmac', ['src/fe-readmac.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, macdecoderlib])
executable('fe-readmx', ['src/fe-readmx.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, mxdecoderlib])
executable('fe-readzilogmcz', ['src/fe-readzilogmcz.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, zilogmczdecoderlib])
executable('fe-readvictor9k', ['src/fe-readvictor9k.cc'], dependencies: [fmtlib, felib, decoderlib, readerlib, victor9kdecoderlib])
executable('fe-rpm', ['src/fe-rpm.cc'], dependencies: [fmtlib, felib])

27
src/fe-readmx.cc Normal file
View File

@@ -0,0 +1,27 @@
#include "globals.h"
#include "flags.h"
#include "reader.h"
#include "fluxmap.h"
#include "decoders.h"
#include "mx.h"
#include "image.h"
#include "sector.h"
#include "sectorset.h"
#include "record.h"
#include <fmt/format.h>
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
"mx.img");
int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0-1");
Flag::parseFlags(argc, argv);
MxDecoder decoder;
readDiskCommand(decoder, outputFilename);
return 0;
}