diff --git a/arch/tids990/encoder.cc b/arch/tids990/encoder.cc index 4d8adf19..361bb60f 100644 --- a/arch/tids990/encoder.cc +++ b/arch/tids990/encoder.cc @@ -6,33 +6,54 @@ #include "crc.h" #include "sectorset.h" #include "writer.h" +#include FlagGroup tids990EncoderFlags; -static DoubleFlag clockRateUs( - { "--clock-rate" }, - "Encoded data clock rate (microseconds).", - 3.83); +static IntFlag trackLengthMs( + { "--tids990-track-length-ms" }, + "Length of a track in milliseconds.", + 166); -static DoubleFlag postIndexGapMs( - { "--post-index-gap" }, - "Post-index gap before first sector header (milliseconds).", - 1.0); +static IntFlag sectorCount( + { "--tids990-sector-count" }, + "Number of sectors per track.", + 26); -static DoubleFlag sectorSpacingMs( - { "--sector-spacing" }, - "Time between successive sector headers (milliseconds).", - 16.2); +static IntFlag clockRateKhz( + { "--tids990-clock-rate-khz" }, + "Clock rate of data to write.", + 500); -static DoubleFlag postHeaderSpacingMs( - { "--post-header-spacing" }, - "Time between a sector's header and data records (milliseconds).", - 0.69); +static HexIntFlag am1Byte( + { "--tids990-am1-byte" }, + "16-bit RAW bit pattern to use for the AM1 ID byte", + 0x2244); + +static HexIntFlag am2Byte( + { "--tids990-am2-byte" }, + "16-bit RAW bit pattern to use for the AM2 ID byte", + 0x2245); + +static IntFlag gap1( + { "--tids990-gap1-bytes" }, + "Size of gap 1 (the post-index gap).", + 80); + +static IntFlag gap2( + { "--tids990-gap2-bytes" }, + "Size of gap 2 (the post-ID gap).", + 21); + +static IntFlag gap3( + { "--tids990-gap3-bytes" }, + "Size of gap 3 (the post-data or format gap).", + 51); static StringFlag sectorSkew( - { "--sector-skew" }, - "Order in which to write sectors.", - "05a3816b4927"); + { "--tids990-sector-skew" }, + "Order to emit sectors.", + "1mhc72nid83oje94pkfa50lgb6"); static int charToInt(char c) { @@ -41,59 +62,115 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } +void TiDs990Encoder::writeRawBits(uint32_t data, int width) +{ + _cursor += width; + _lastBit = data & 1; + for (int i=0; i>= 1; + } +} + +void TiDs990Encoder::writeBytes(const Bytes& bytes) +{ + encodeMfm(_bits, _cursor, bytes, _lastBit); +} + +void TiDs990Encoder::writeBytes(int count, uint8_t byte) +{ + Bytes bytes = { byte }; + for (int i=0; i TiDs990Encoder::encode( int physicalTrack, int physicalSide, const SectorSet& allSectors) { - int logicalTrack; - if (physicalSide != 0) - return std::unique_ptr(); -// physicalTrack -= _bias; -// switch (_format) -// { -// case 120: -// if ((physicalTrack < 0) || (physicalTrack >= (BROTHER_TRACKS_PER_120KB_DISK*2)) -// || (physicalTrack & 1)) -// return std::unique_ptr(); -// logicalTrack = physicalTrack/2; -// break; -// -// case 240: -// if ((physicalTrack < 0) || (physicalTrack >= BROTHER_TRACKS_PER_240KB_DISK)) -// return std::unique_ptr(); -// logicalTrack = physicalTrack; -// break; -// } -// -// int bitsPerRevolution = 200000.0 / clockRateUs; -// const std::string& skew = sectorSkew.get(); -// std::vector bits(bitsPerRevolution); -// unsigned cursor = 0; -// -// for (int sectorCount=0; sectorCountdata); -// } -// -// if (cursor >= bits.size()) -// Error() << "track data overrun"; -// fillBitmapTo(bits, cursor, bits.size(), { true, false }); + double clockRateUs = 1e3 / clockRateKhz / 2.0; + int bitsPerRevolution = (trackLengthMs * 1000.0) / clockRateUs; + _bits.resize(bitsPerRevolution); + _cursor = 0; - // The pre-index gap is not normally reported. - // std::cerr << "pre-index gap " << 200.0 - (double)cursor*clockRateUs/1e3 << std::endl; + uint8_t am1Unencoded = decodeUint16(am1Byte); + uint8_t am2Unencoded = decodeUint16(am2Byte); + + writeBytes(gap1, 0x55); + + bool first = true; + for (char sectorChar : sectorSkew.get()) + { + int sectorId = charToInt(sectorChar); + if (!first) + writeBytes(gap3, 0x55); + first = false; + + const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); + if (!sectorData) + Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId); + + /* Writing the sector and data records are fantastically annoying. + * The CRC is calculated from the *very start* of the record, and + * include the malformed marker bytes. Our encoder doesn't know + * about this, of course, with the result that we have to construct + * the unencoded header, calculate the checksum, and then use the + * same logic to emit the bytes which require special encoding + * before encoding the rest of the header normally. */ + + { + Bytes header; + ByteWriter bw(header); + + writeBytes(12, 0x55); + bw.write_8(am1Unencoded); + bw.write_8(sectorData->logicalSide << 3); + bw.write_8(sectorData->logicalTrack); + bw.write_8(sectorCount); + bw.write_8(sectorData->logicalSector); + bw.write_be16(sectorData->data.size()); + uint16_t crc = crc16(CCITT_POLY, header); + bw.write_be16(crc); + + writeRawBits(am1Byte, 16); + writeBytes(header.slice(1)); + } + + writeBytes(gap2, 0x55); + + { + Bytes data; + ByteWriter bw(data); + + writeBytes(12, 0x55); + bw.write_8(am2Unencoded); + + bw += sectorData->data; + uint16_t crc = crc16(CCITT_POLY, data); + bw.write_be16(crc); + + writeRawBits(am2Byte, 16); + writeBytes(data.slice(1)); + } + } + + if (_cursor >= _bits.size()) + Error() << "track data overrun"; + while (_cursor < _bits.size()) + writeBytes(1, 0x55); std::unique_ptr fluxmap(new Fluxmap); -// fluxmap->appendBits(bits, clockRateUs*1e3); + fluxmap->appendBits(_bits, clockRateUs*1e3); return fluxmap; } diff --git a/arch/tids990/tids990.h b/arch/tids990/tids990.h index 6ef12911..44d8b675 100644 --- a/arch/tids990/tids990.h +++ b/arch/tids990/tids990.h @@ -25,8 +25,19 @@ class TiDs990Encoder : public AbstractEncoder public: virtual ~TiDs990Encoder() {} +private: + void writeRawBits(uint32_t data, int width); + void writeBytes(const Bytes& bytes); + void writeBytes(int count, uint8_t value); + void writeSync(); + public: std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); + +private: + std::vector _bits; + unsigned _cursor; + bool _lastBit; }; extern FlagGroup tids990EncoderFlags; diff --git a/src/fe-writetids990.cc b/src/fe-writetids990.cc index 85494177..b215aee1 100644 --- a/src/fe-writetids990.cc +++ b/src/fe-writetids990.cc @@ -12,7 +12,7 @@ static FlagGroup flags { &writerFlags, &tids990EncoderFlags }; int mainWriteTiDs990(int argc, const char* argv[]) { setWriterDefaultInput(":c=77:h=2:s=26:b=288"); - setWriterDefaultDest(":d=0:t=0-77"); + setWriterDefaultDest(":d=0:t=0-76:s=0-1"); flags.parseFlags(argc, argv); TiDs990Encoder encoder;