Add an extremely prototype version of the Smaky decoder.

This commit is contained in:
dg
2022-11-23 21:44:40 +00:00
parent a60b8e68ca
commit 7e9a1268a5
10 changed files with 226 additions and 9 deletions

View File

@@ -111,6 +111,7 @@ PROTOS = \
arch/micropolis/micropolis.proto \
arch/mx/mx.proto \
arch/northstar/northstar.proto \
arch/smaky/smaky.proto \
arch/tids990/tids990.proto \
arch/victor9k/victor9k.proto \
arch/zilogmcz/zilogmcz.proto \

View File

@@ -1,5 +1,7 @@
LIBARCH_SRCS = \
arch/aeslanier/decoder.cc \
arch/agat/agat.cc \
arch/agat/decoder.cc \
arch/amiga/amiga.cc \
arch/amiga/decoder.cc \
arch/amiga/encoder.cc \
@@ -16,18 +18,17 @@ LIBARCH_SRCS = \
arch/ibm/encoder.cc \
arch/macintosh/decoder.cc \
arch/macintosh/encoder.cc \
arch/micropolis/decoder.cc \
arch/micropolis/encoder.cc \
arch/mx/decoder.cc \
arch/northstar/decoder.cc \
arch/northstar/encoder.cc \
arch/smaky/decoder.cc \
arch/tids990/decoder.cc \
arch/tids990/encoder.cc \
arch/victor9k/decoder.cc \
arch/victor9k/encoder.cc \
arch/zilogmcz/decoder.cc \
arch/tids990/decoder.cc \
arch/tids990/encoder.cc \
arch/micropolis/decoder.cc \
arch/micropolis/encoder.cc \
arch/northstar/decoder.cc \
arch/northstar/encoder.cc \
arch/agat/agat.cc \
arch/agat/decoder.cc \
LIBARCH_OBJS = $(patsubst %.cc, $(OBJDIR)/%.o, $(LIBARCH_SRCS))
OBJS += $(LIBARCH_OBJS)

156
arch/smaky/decoder.cc Normal file
View File

@@ -0,0 +1,156 @@
#include "globals.h"
#include "fluxmap.h"
#include "decoders/fluxmapreader.h"
#include "protocol.h"
#include "decoders/decoders.h"
#include "sector.h"
#include "smaky.h"
#include "bytes.h"
#include "crc.h"
#include "fmt/format.h"
#include "lib/decoders/decoders.pb.h"
#include <string.h>
#include <algorithm>
static const FluxPattern SECTOR_PATTERN(20, 0x92aaa);
class SmakyDecoder : public Decoder
{
public:
SmakyDecoder(const DecoderProto& config):
Decoder(config),
_config(config.smaky())
{}
void beginTrack() override
{
/* Find the start-of-track index marks, which will be an interval
* of about 6ms. */
seekToIndexMark();
for (;;)
{
auto previous = tell();
seekToIndexMark();
auto now = tell();
if (eof())
return;
if ((now.ns() - previous.ns()) < 8e6)
{
seekToIndexMark();
auto next = tell();
if ((next.ns() - now.ns()) < 8e6)
{
/* We have seen two short gaps in a row, so the index
* mark must be now. */
seek(previous);
break;
}
else
{
/* We have seen one short gap and one long gap. This
* means the index mark must be off the beginning of
* the data. Seek to the start to simulate this. */
rewind();
break;
}
}
}
/* Now we know where to start counting, start finding sectors. */
int sectorId = 0;
_sectorStarts.clear();
for (;;)
{
auto previous = tell();
seekToIndexMark();
auto now = tell();
if (eof())
{
if (_sectorStarts.empty())
return;
_sectorIndex = 0;
return;
}
if ((now.ns() - previous.ns()) < 8e6)
{
/* This is an index mark! */
/* Advance to the start of the first sector and record
* the time. */
seekToIndexMark();
sectorId = 0;
}
_sectorStarts.push_back(std::make_pair(sectorId, now));
sectorId++;
}
}
nanoseconds_t advanceToNextRecord() override
{
if (_sectorIndex == _sectorStarts.size())
{
seekToIndexMark();
return 0;
}
const auto& p = _sectorStarts[_sectorIndex++];
_sectorId = p.first;
seek(p.second);
nanoseconds_t clock = seekToPattern(SECTOR_PATTERN);
_sector->headerStartTime = tell().ns();
return clock;
}
void decodeSectorRecord() override
{
readRawBits(21);
const auto& rawbits = readRawBits(SMAKY_RECORD_SIZE*16);
if (rawbits.size() < SMAKY_SECTOR_SIZE)
return;
const auto& rawbytes = toBytes(rawbits).slice(0, SMAKY_RECORD_SIZE*16);
/* The Smaky bytes are stored backwards! Backwards! */
const auto& bytes = decodeFmMfm(rawbits).slice(0, SMAKY_RECORD_SIZE).reverseBits();
ByteReader br(bytes);
uint8_t track = br.read_8();
Bytes data = br.read(SMAKY_SECTOR_SIZE);
uint8_t wantedChecksum = br.read_8();
uint8_t gotChecksum = sumBytes(data) & 0xff;
if (track != _sector->physicalTrack)
return;
_sector->logicalTrack = _sector->physicalTrack;
_sector->logicalSide = _sector->physicalSide;
_sector->logicalSector = _sectorId;
_sector->data = data;
_sector->status = (wantedChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM;
}
private:
const SmakyDecoderProto& _config;
nanoseconds_t _startOfTrack;
std::vector<std::pair<int, Fluxmap::Position>> _sectorStarts;
int _sectorId;
int _sectorIndex;
};
std::unique_ptr<Decoder> createSmakyDecoder(const DecoderProto& config)
{
return std::unique_ptr<Decoder>(new SmakyDecoder(config));
}

10
arch/smaky/smaky.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef SMAKY_H
#define SMAKY_H
#define SMAKY_SECTOR_SIZE 256
#define SMAKY_RECORD_SIZE (1 + SMAKY_SECTOR_SIZE + 1)
extern std::unique_ptr<Decoder> createSmakyDecoder(const DecoderProto& config);
#endif

6
arch/smaky/smaky.proto Normal file
View File

@@ -0,0 +1,6 @@
syntax = "proto2";
import "lib/common.proto";
message SmakyDecoderProto {}

View File

@@ -16,6 +16,7 @@
#include "arch/micropolis/micropolis.h"
#include "arch/mx/mx.h"
#include "arch/northstar/northstar.h"
#include "arch/smaky/smaky.h"
#include "arch/tids990/tids990.h"
#include "arch/victor9k/victor9k.h"
#include "arch/zilogmcz/zilogmcz.h"
@@ -48,6 +49,7 @@ std::unique_ptr<Decoder> Decoder::create(const DecoderProto& config)
{DecoderProto::kMicropolis, createMicropolisDecoder },
{DecoderProto::kMx, createMxDecoder },
{DecoderProto::kNorthstar, createNorthstarDecoder },
{DecoderProto::kSmaky, createSmakyDecoder },
{DecoderProto::kTids990, createTids990Decoder },
{DecoderProto::kVictor9K, createVictor9kDecoder },
{DecoderProto::kZilogmcz, createZilogMczDecoder },

View File

@@ -71,6 +71,11 @@ public:
return _fmr->tell();
}
void rewind()
{
_fmr->rewind();
}
void seek(const Fluxmap::Position& pos)
{
return _fmr->seek(pos);

View File

@@ -13,13 +13,14 @@ import "arch/macintosh/macintosh.proto";
import "arch/micropolis/micropolis.proto";
import "arch/mx/mx.proto";
import "arch/northstar/northstar.proto";
import "arch/smaky/smaky.proto";
import "arch/tids990/tids990.proto";
import "arch/victor9k/victor9k.proto";
import "arch/zilogmcz/zilogmcz.proto";
import "lib/fluxsink/fluxsink.proto";
import "lib/common.proto";
//NEXT: 30
//NEXT: 31
message DecoderProto {
optional double pulse_debounce_threshold = 1 [default = 0.30,
(help) = "ignore pulses with intervals shorter than this, in fractions of a clock"];
@@ -46,6 +47,7 @@ message DecoderProto {
MicropolisDecoderProto micropolis = 14;
MxDecoderProto mx = 15;
NorthstarDecoderProto northstar = 24;
SmakyDecoderProto smaky = 30;
Tids990DecoderProto tids990 = 16;
Victor9kDecoderProto victor9k = 17;
ZilogMczDecoderProto zilogmcz = 18;

View File

@@ -63,6 +63,7 @@ FORMATS = \
northstar87 \
rx50 \
shugart_drive \
smaky \
tids990 \
victor9k_ds \
victor9k_ss \

33
src/formats/smaky.textpb Normal file
View File

@@ -0,0 +1,33 @@
comment: 'BK 800kB 5.25"/3.5" 80-track 10-sector DSDD'
image_reader {
filename: "smaky.img"
type: IMG
}
image_writer {
filename: "smaky.img"
type: IMG
}
layout {
tracks: 77
sides: 1
layoutdata {
sector_size: 256
physical {
start_sector: 0
count: 16
}
}
}
drive {
hard_sector_count: 16
sync_with_index: true
}
decoder {
smaky {}
}