Skip to content

Commit

Permalink
Merge pull request #752 from davidgiven/tartu
Browse files Browse the repository at this point in the history
Add encoder support for the Tartu format.
  • Loading branch information
davidgiven authored May 14, 2024
2 parents 91093e1 + 500fcde commit e4f1a5a
Show file tree
Hide file tree
Showing 13 changed files with 752 additions and 30 deletions.
4 changes: 2 additions & 2 deletions arch/tartu/decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ class TartuDecoder : public Decoder
if (readRaw64() != HEADER_BITS)
return;

auto bits = readRawBits(16 * 8);
auto bytes = decodeFmMfm(bits).slice(0, 8);
auto bits = readRawBits(16 * 4);
auto bytes = decodeFmMfm(bits).slice(0, 4);

ByteReader br(bytes);
uint8_t track = br.read_8();
Expand Down
114 changes: 114 additions & 0 deletions arch/tartu/encoder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "lib/globals.h"
#include "lib/decoders/decoders.h"
#include "lib/encoders/encoders.h"
#include "arch/tartu/tartu.h"
#include "lib/crc.h"
#include "lib/fluxmap.h"
#include "lib/sector.h"
#include <string.h>

class TartuEncoder : public Encoder
{
public:
TartuEncoder(const EncoderProto& config):
Encoder(config),
_config(config.tartu())
{
}

std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo,
const std::vector<std::shared_ptr<const Sector>>& sectors,
const Image& image) override
{
_clockRateUs = _config.clock_period_us();
int bitsPerRevolution =
(_config.target_rotational_period_ms() * 1000.0) / _clockRateUs;

const auto& sector = *sectors.begin();
_bits.resize(bitsPerRevolution);
_cursor = 0;

writeFillerRawBitsUs(_config.gap1_us());
bool first = true;
for (const auto& sectorData : sectors)
{
if (!first)
writeFillerRawBitsUs(_config.gap4_us());
first = false;
writeSector(sectorData);
}

if (_cursor > _bits.size())
error("track data overrun");
writeFillerRawBitsUs(_config.target_rotational_period_ms() * 1000.0);

std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(_bits,
calculatePhysicalClockPeriod(_clockRateUs * 1e3,
_config.target_rotational_period_ms() * 1e6));
return fluxmap;
}

private:
void writeBytes(const Bytes& bytes)
{
encodeMfm(_bits, _cursor, bytes, _lastBit);
}

void writeRawBits(uint64_t data, int width)
{
_cursor += width;
_lastBit = data & 1;
for (int i = 0; i < width; i++)
{
unsigned pos = _cursor - i - 1;
if (pos < _bits.size())
_bits[pos] = data & 1;
data >>= 1;
}
}

void writeFillerRawBitsUs(double us)
{
unsigned count = (us / _clockRateUs) / 2;
for (int i = 0; i < count; i++)
writeRawBits(0b10, 2);
};

void writeSector(const std::shared_ptr<const Sector>& sectorData)
{
writeRawBits(_config.header_marker(), 64);
{
Bytes bytes;
ByteWriter bw(bytes);
bw.write_8(
(sectorData->logicalTrack << 1) | sectorData->logicalSide);
bw.write_8(1);
bw.write_8(sectorData->logicalSector);
bw.write_8(~sumBytes(bytes.slice(0, 3)));
writeBytes(bytes);
}

writeFillerRawBitsUs(_config.gap3_us());
writeRawBits(_config.data_marker(), 64);
{
Bytes bytes;
ByteWriter bw(bytes);
bw.append(sectorData->data);
bw.write_8(~sumBytes(bytes.slice(0, sectorData->data.size())));
writeBytes(bytes);
}
}

private:
const TartuEncoderProto& _config;
double _clockRateUs;
std::vector<bool> _bits;
unsigned _cursor;
bool _lastBit;
};

std::unique_ptr<Encoder> createTartuEncoder(const EncoderProto& config)
{
return std::unique_ptr<Encoder>(new TartuEncoder(config));
}
1 change: 1 addition & 0 deletions arch/tartu/tartu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define TARTU_H

extern std::unique_ptr<Decoder> createTartuDecoder(const DecoderProto& config);
extern std::unique_ptr<Encoder> createTartuEncoder(const EncoderProto& config);

#endif

23 changes: 23 additions & 0 deletions arch/tartu/tartu.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
syntax = "proto2";

import "lib/common.proto";

message TartuDecoderProto {}

message TartuEncoderProto {
optional double clock_period_us = 1
[ default = 2.0, (help) = "clock rate on the real device (for MFM)" ];
optional double target_rotational_period_ms = 2
[ default=200, (help) = "rotational period of target disk" ];
optional double gap1_us = 3
[ default = 1200,
(help) = "size of gap 1 (the post-index gap)" ];
optional double gap3_us = 4
[ default = 150,
(help) = "size of gap 3 (the pre-data gap)" ];
optional double gap4_us = 5
[ default = 180,
(help) = "size of gap 4 (the post-data or format gap)" ];
optional uint64 header_marker = 6
[ default = 0xaaaaaaaa44895554,
(help) = "64-bit raw bit pattern of header record marker" ];
optional uint64 data_marker = 7
[ default = 0xaaaaaaaa44895545,
(help) = "64-bit raw bit pattern of data record marker" ];
}
3 changes: 3 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
"./arch/rolandd20/decoder.cc",
"./arch/smaky6/decoder.cc",
"./arch/tartu/decoder.cc",
"./arch/tartu/encoder.cc",
"./arch/tids990/decoder.cc",
"./arch/tids990/encoder.cc",
"./arch/victor9k/decoder.cc",
Expand Down Expand Up @@ -280,6 +281,8 @@
("mac", "scripts/mac800_test.textpb", "--800"),
("n88basic", "", ""),
("rx50", "", ""),
("tartu", "", "--390 40track_drive"),
("tartu", "", "--780"),
("tids990", "", ""),
("victor9k", "", "--612"),
("victor9k", "", "--1224"),
Expand Down
5 changes: 5 additions & 0 deletions doc/disk-tartu.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ To read:
- `fluxengine read tartu --390 -s drive:0 -o tartu.img`
- `fluxengine read tartu --780 -s drive:0 -o tartu.img`

To write:

- `fluxengine write tartu --390 -d drive:0 -i tartu.img`
- `fluxengine write tartu --780 -d drive:0 -i tartu.img`

## References

- [The Estonia Museum of Electronics](https://www.elektroonikamuuseum.ee/tartu_arvuti_lugu.html)
Expand Down
4 changes: 3 additions & 1 deletion lib/encoders/encoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "arch/macintosh/macintosh.h"
#include "arch/micropolis/micropolis.h"
#include "arch/northstar/northstar.h"
#include "arch/tartu/tartu.h"
#include "arch/tids990/tids990.h"
#include "arch/victor9k/victor9k.h"
#include "lib/encoders/encoders.pb.h"
Expand All @@ -24,15 +25,16 @@ std::unique_ptr<Encoder> Encoder::create(const EncoderProto& config)
static const std::map<int,
std::function<std::unique_ptr<Encoder>(const EncoderProto&)>>
encoders = {
{EncoderProto::kAmiga, createAmigaEncoder },
{EncoderProto::kAgat, createAgatEncoder },
{EncoderProto::kAmiga, createAmigaEncoder },
{EncoderProto::kApple2, createApple2Encoder },
{EncoderProto::kBrother, createBrotherEncoder },
{EncoderProto::kC64, createCommodore64Encoder},
{EncoderProto::kIbm, createIbmEncoder },
{EncoderProto::kMacintosh, createMacintoshEncoder },
{EncoderProto::kMicropolis, createMicropolisEncoder },
{EncoderProto::kNorthstar, createNorthstarEncoder },
{EncoderProto::kTartu, createTartuEncoder },
{EncoderProto::kTids990, createTids990Encoder },
{EncoderProto::kVictor9K, createVictor9kEncoder },
};
Expand Down
2 changes: 2 additions & 0 deletions lib/encoders/encoders.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "arch/ibm/ibm.proto";
import "arch/macintosh/macintosh.proto";
import "arch/micropolis/micropolis.proto";
import "arch/northstar/northstar.proto";
import "arch/tartu/tartu.proto";
import "arch/tids990/tids990.proto";
import "arch/victor9k/victor9k.proto";

Expand All @@ -27,5 +28,6 @@ message EncoderProto
Victor9kEncoderProto victor9k = 11;
Apple2EncoderProto apple2 = 12;
AgatEncoderProto agat = 13;
TartuEncoderProto tartu = 14;
}
}
Loading

0 comments on commit e4f1a5a

Please sign in to comment.