From eaa3c5742570395cda63630ec345986606ff5cfb Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 1 Dec 2019 09:07:43 +0100 Subject: [PATCH 1/8] Non-functional boilerplate of Amiga write support. --- arch/amiga/amiga.h | 16 +++++++++ arch/amiga/encoder.cc | 79 +++++++++++++++++++++++++++++++++++++++++++ mkninja.sh | 2 ++ src/fe-writeamiga.cc | 23 +++++++++++++ src/fluxengine.cc | 2 ++ 5 files changed, 122 insertions(+) create mode 100644 arch/amiga/encoder.cc create mode 100644 src/fe-writeamiga.cc diff --git a/arch/amiga/amiga.h b/arch/amiga/amiga.h index d1d5400b..efb753a3 100644 --- a/arch/amiga/amiga.h +++ b/arch/amiga/amiga.h @@ -1,12 +1,17 @@ #ifndef AMIGA_H #define AMIGA_H +#include "encoders/encoders.h" + #define AMIGA_SECTOR_RECORD 0xaaaa44894489LL +#define AMIGA_TRACKS_PER_DISK 80 +#define AMIGA_SECTORS_PER_TRACK 11 #define AMIGA_RECORD_SIZE 0x21f class Sector; class Fluxmap; +class SectorSet; class AmigaDecoder : public AbstractDecoder { @@ -17,4 +22,15 @@ class AmigaDecoder : public AbstractDecoder void decodeSectorRecord(); }; +class AmigaEncoder : public AbstractEncoder +{ +public: + virtual ~AmigaEncoder() {} + +public: + std::unique_ptr encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); +}; + +extern FlagGroup amigaEncoderFlags; + #endif diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc new file mode 100644 index 00000000..a57fadba --- /dev/null +++ b/arch/amiga/encoder.cc @@ -0,0 +1,79 @@ +#include "globals.h" +#include "record.h" +#include "decoders/decoders.h" +#include "encoders/encoders.h" +#include "amiga.h" +#include "crc.h" +#include "sectorset.h" +#include "writer.h" + +FlagGroup amigaEncoderFlags; + +static DoubleFlag clockRateUs( + { "--clock-rate" }, + "Encoded data clock rate (microseconds).", + 2.00); + +static DoubleFlag postIndexGapMs( + { "--post-index-gap" }, + "Post-index gap before first sector header (milliseconds).", + 20.0); + +static int charToInt(char c) +{ + if (isdigit(c)) + return c - '0'; + return 10 + tolower(c) - 'a'; +} + +static void write_bits(std::vector& bits, unsigned& cursor, uint64_t data, int width) +{ + cursor += width; + for (int i=0; i>= 1; + } +} + +static void write_sector(std::vector bits, unsigned& cursor, const Sector* sector) +{ + write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8); + + Bytes header(4); + ByteWriter bw(header); + bw.write_8(0xff); /* Amiga 1.0 format byte */ + bw.write_8(sector->logicalTrack); + bw.write_8(sector->logicalSector); + bw.write_8(AMIGA_SECTORS_PER_TRACK - sector->logicalSector); +} + +std::unique_ptr AmigaEncoder::encode( + int physicalTrack, int physicalSide, const SectorSet& allSectors) +{ + if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) + return std::unique_ptr(); + + int bitsPerRevolution = 200000.0 / clockRateUs; + std::vector bits(bitsPerRevolution); + unsigned cursor = 0; + + fillBitmapTo(bits, cursor, postIndexGapMs * 1000 / clockRateUs, { true, false }); + + for (int sectorId=0; sectorId bits.size()) + Error() << "track data overrun"; + fillBitmapTo(bits, cursor, bits.size(), { true, false }); + + std::unique_ptr fluxmap(new Fluxmap); + fluxmap->appendBits(bits, clockRateUs*1e3); + return fluxmap; +} + diff --git a/mkninja.sh b/mkninja.sh index 272d2276..6b95a37a 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -145,6 +145,7 @@ buildlibrary libbackend.a \ lib/imagewriter/ldbsimagewriter.cc \ arch/aeslanier/decoder.cc \ arch/amiga/decoder.cc \ + arch/amiga/encoder.cc \ arch/apple2/decoder.cc \ arch/brother/decoder.cc \ arch/brother/encoder.cc \ @@ -213,6 +214,7 @@ buildlibrary libfrontend.a \ src/fe-seek.cc \ src/fe-testbulktransport.cc \ src/fe-upgradefluxfile.cc \ + src/fe-writeamiga.cc \ src/fe-writebrother.cc \ src/fe-writeflux.cc \ src/fe-writetestpattern.cc \ diff --git a/src/fe-writeamiga.cc b/src/fe-writeamiga.cc new file mode 100644 index 00000000..da13c1d9 --- /dev/null +++ b/src/fe-writeamiga.cc @@ -0,0 +1,23 @@ +#include "globals.h" +#include "flags.h" +#include "decoders/decoders.h" +#include "amiga/amiga.h" +#include "writer.h" +#include "fmt/format.h" +#include "image.h" +#include + +static FlagGroup flags { &writerFlags, &amigaEncoderFlags }; + +int mainWriteAmiga(int argc, const char* argv[]) +{ + setWriterDefaultInput(":c=80:h=2:s=11:b=512"); + setWriterDefaultDest(":d=0:t=0-79:s=0-1"); + flags.parseFlags(argc, argv); + + AmigaEncoder encoder; + writeDiskCommand(encoder); + + return 0; +} + diff --git a/src/fluxengine.cc b/src/fluxengine.cc index 1bf3498f..f9164a28 100644 --- a/src/fluxengine.cc +++ b/src/fluxengine.cc @@ -28,6 +28,7 @@ extern command_cb mainRpm; extern command_cb mainSeek; extern command_cb mainTestBulkTransport; extern command_cb mainUpgradeFluxFile; +extern command_cb mainWriteAmiga; extern command_cb mainWriteBrother; extern command_cb mainWriteFlux; extern command_cb mainWriteTestPattern; @@ -79,6 +80,7 @@ static std::vector readables = static std::vector writeables = { + { "amiga", mainWriteAmiga, "Writes Amiga disks.", }, { "brother", mainWriteBrother, "Writes 120kB and 240kB Brother word processor disks.", }, }; From d2f8c27cb68a3b75acf6d53cf02bc50ba09485f9 Mon Sep 17 00:00:00 2001 From: David Given Date: Sun, 1 Dec 2019 09:11:36 +0100 Subject: [PATCH 2/8] Add checksum routine. --- arch/amiga/encoder.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index a57fadba..eade7f1b 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -26,6 +26,18 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } +static uint32_t checksum(const Bytes& bytes) +{ + ByteReader br(bytes); + uint32_t checksum = 0; + + assert((bytes.size() & 3) == 0); + while (!br.eof()) + checksum ^= br.read_be32(); + + return checksum & 0x55555555; +} + static void write_bits(std::vector& bits, unsigned& cursor, uint64_t data, int width) { cursor += width; @@ -45,7 +57,7 @@ static void write_sector(std::vector bits, unsigned& cursor, const Sector* Bytes header(4); ByteWriter bw(header); bw.write_8(0xff); /* Amiga 1.0 format byte */ - bw.write_8(sector->logicalTrack); + bw.write_8((sector->logicalTrack<<1) | sector->logicalSide); bw.write_8(sector->logicalSector); bw.write_8(AMIGA_SECTORS_PER_TRACK - sector->logicalSector); } From 5a0fb2761ac04d1c966130fd55f6c205f4768ca5 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 11:37:43 +0100 Subject: [PATCH 3/8] Update OSX build instructions. --- doc/building.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/building.md b/doc/building.md index 38aa5881..d47af53a 100644 --- a/doc/building.md +++ b/doc/building.md @@ -182,7 +182,7 @@ install some support packages. - For Linux (this is Ubuntu, but this should apply to Debian too): `ninja-build`, `libusb-1.0-0-dev`, `libsqlite3-dev`. - - For OSX with Homebrew: `ninja`. + - For OSX with Homebrew: `ninja`, `libusb`, `pkg-config`, `sqlite`. - For Windows with MSYS2: `make`, `ninja`, `mingw-w64-i686-libusb`, `mingw-w64-i686-sqlite3`, `mingw-w64-i686-zlib`, `mingw-w64-i686-gcc`. From 792cc881929e21ed16d60bdafb3c94f1daee1c71 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 20:44:48 +0100 Subject: [PATCH 4/8] The Amiga writer now generates valid flux files --- but it looks like the writer's broken (both the Amiga and the Brother have failed). --- arch/amiga/amiga.cc | 101 ++++++++++++++++++++++++++++++++++++++++ arch/amiga/amiga.h | 5 ++ arch/amiga/decoder.cc | 55 +++------------------- arch/amiga/encoder.cc | 68 +++++++++++++++++++-------- arch/brother/encoder.cc | 2 +- lib/decoders/decoders.h | 1 + lib/decoders/fmmfm.cc | 22 +++++++++ mkninja.sh | 2 + tests/amiga.cc | 38 +++++++++++++++ 9 files changed, 226 insertions(+), 68 deletions(-) create mode 100644 arch/amiga/amiga.cc create mode 100644 tests/amiga.cc diff --git a/arch/amiga/amiga.cc b/arch/amiga/amiga.cc new file mode 100644 index 00000000..2ca89957 --- /dev/null +++ b/arch/amiga/amiga.cc @@ -0,0 +1,101 @@ +#include "globals.h" +#include "record.h" +#include "decoders/decoders.h" +#include "amiga.h" +#include "bytes.h" +#include "fmt/format.h" + +uint32_t amigaChecksum(const Bytes& bytes) +{ + ByteReader br(bytes); + uint32_t checksum = 0; + + assert((bytes.size() & 3) == 0); + while (!br.eof()) + checksum ^= br.read_be32(); + + return checksum & 0x55555555; +} + +static uint8_t everyother(uint16_t x) +{ + /* aabb ccdd eeff gghh */ + x &= 0x6666; /* 0ab0 0cd0 0ef0 0gh0 */ + x >>= 1; /* 00ab 00cd 00ef 00gh */ + x |= x << 2; /* abab cdcd efef ghgh */ + x &= 0x3c3c; /* 00ab cd00 00ef gh00 */ + x >>= 2; /* 0000 abcd 0000 efgh */ + x |= x >> 4; /* 0000 abcd abcd efgh */ + return x; +} + +Bytes amigaInterleave(const Bytes& input) +{ + Bytes output; + ByteWriter bw(output); + + /* Write all odd bits. (Numbering starts at 0...) */ + + { + ByteReader br(input); + while (!br.eof()) + { + uint16_t x = br.read_be16(); + x &= 0xaaaa; /* a0b0 c0d0 e0f0 g0h0 */ + x |= x >> 1; /* aabb ccdd eeff gghh */ + x = everyother(x); /* 0000 0000 abcd efgh */ + bw.write_8(x); + } + } + + /* Write all even bits. */ + + { + ByteReader br(input); + while (!br.eof()) + { + uint16_t x = br.read_be16(); + x &= 0x5555; /* 0a0b 0c0d 0e0f 0g0h */ + x |= x << 1; /* aabb ccdd eeff gghh */ + x = everyother(x); /* 0000 0000 abcd efgh */ + bw.write_8(x); + } + } + + return output; +} + +Bytes amigaDeinterleave(const uint8_t*& input, size_t len) +{ + assert(!(len & 1)); + const uint8_t* odds = &input[0]; + const uint8_t* evens = &input[len/2]; + Bytes output; + ByteWriter bw(output); + + for (size_t i=0; i> 49) & 0x5555) | + (((o * 0x0101010101010101ULL & 0x8040201008040201ULL) + * 0x0102040810204081ULL >> 48) & 0xAAAA); + + bw.write_be16(result); + } + + input += len; + return output; +} + +Bytes amigaDeinterleave(const Bytes& input) +{ + const uint8_t* ptr = input.cbegin(); + return amigaDeinterleave(ptr, input.size()); +} diff --git a/arch/amiga/amiga.h b/arch/amiga/amiga.h index efb753a3..82fb441e 100644 --- a/arch/amiga/amiga.h +++ b/arch/amiga/amiga.h @@ -33,4 +33,9 @@ class AmigaEncoder : public AbstractEncoder extern FlagGroup amigaEncoderFlags; +extern uint32_t amigaChecksum(const Bytes& bytes); +extern Bytes amigaInterleave(const Bytes& input); +extern Bytes amigaDeinterleave(const uint8_t*& input, size_t len); +extern Bytes amigaDeinterleave(const Bytes& input); + #endif diff --git a/arch/amiga/decoder.cc b/arch/amiga/decoder.cc index 8ae3b896..4e5a9f01 100644 --- a/arch/amiga/decoder.cc +++ b/arch/amiga/decoder.cc @@ -21,47 +21,6 @@ static const FluxPattern SECTOR_PATTERN(48, AMIGA_SECTOR_RECORD); -static Bytes deinterleave(const uint8_t*& input, size_t len) -{ - assert(!(len & 1)); - const uint8_t* odds = &input[0]; - const uint8_t* evens = &input[len/2]; - Bytes output; - ByteWriter bw(output); - - for (size_t i=0; i> 49) & 0x5555) | - (((o * 0x0101010101010101ULL & 0x8040201008040201ULL) - * 0x0102040810204081ULL >> 48) & 0xAAAA); - - bw.write_be16(result); - } - - input += len; - return output; -} - -static uint32_t checksum(const Bytes& bytes) -{ - ByteReader br(bytes); - uint32_t checksum = 0; - - assert((bytes.size() & 3) == 0); - while (!br.eof()) - checksum ^= br.read_be32(); - - return checksum & 0x55555555; -} - AbstractDecoder::RecordType AmigaDecoder::advanceToNextRecord() { _sector->clock = _fmr->seekToPattern(SECTOR_PATTERN); @@ -78,22 +37,22 @@ void AmigaDecoder::decodeSectorRecord() const uint8_t* ptr = bytes.begin() + 3; - Bytes header = deinterleave(ptr, 4); - Bytes recoveryinfo = deinterleave(ptr, 16); + Bytes header = amigaDeinterleave(ptr, 4); + Bytes recoveryinfo = amigaDeinterleave(ptr, 16); _sector->logicalTrack = header[1] >> 1; _sector->logicalSide = header[1] & 1; _sector->logicalSector = header[2]; - uint32_t wantedheaderchecksum = deinterleave(ptr, 4).reader().read_be32(); - uint32_t gotheaderchecksum = checksum(rawbytes.slice(6, 40)); + uint32_t wantedheaderchecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); + uint32_t gotheaderchecksum = amigaChecksum(rawbytes.slice(6, 40)); if (gotheaderchecksum != wantedheaderchecksum) return; - uint32_t wanteddatachecksum = deinterleave(ptr, 4).reader().read_be32(); - uint32_t gotdatachecksum = checksum(rawbytes.slice(62, 1024)); + uint32_t wanteddatachecksum = amigaDeinterleave(ptr, 4).reader().read_be32(); + uint32_t gotdatachecksum = amigaChecksum(rawbytes.slice(62, 1024)); _sector->data.clear(); - _sector->data.writer().append(deinterleave(ptr, 512)).append(recoveryinfo); + _sector->data.writer().append(amigaDeinterleave(ptr, 512)).append(recoveryinfo); _sector->status = (gotdatachecksum == wanteddatachecksum) ? Sector::OK : Sector::BAD_CHECKSUM; } diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index eade7f1b..8155b2b3 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -17,7 +17,7 @@ static DoubleFlag clockRateUs( static DoubleFlag postIndexGapMs( { "--post-index-gap" }, "Post-index gap before first sector header (milliseconds).", - 20.0); + 5.0); static int charToInt(char c) { @@ -26,16 +26,13 @@ static int charToInt(char c) return 10 + tolower(c) - 'a'; } -static uint32_t checksum(const Bytes& bytes) +static void write_bits(std::vector& bits, unsigned& cursor, const std::vector& src) { - ByteReader br(bytes); - uint32_t checksum = 0; - - assert((bytes.size() & 3) == 0); - while (!br.eof()) - checksum ^= br.read_be32(); - - return checksum & 0x55555555; + for (bool bit : src) + { + if (cursor < bits.size()) + bits[cursor++] = bit; + } } static void write_bits(std::vector& bits, unsigned& cursor, uint64_t data, int width) @@ -50,16 +47,49 @@ static void write_bits(std::vector& bits, unsigned& cursor, uint64_t data, } } -static void write_sector(std::vector bits, unsigned& cursor, const Sector* sector) +static void write_interleaved_bytes(std::vector& bits, unsigned& cursor, const Bytes& bytes) +{ + assert(!(bytes.size() & 3)); + Bytes interleaved = amigaInterleave(bytes); + encodeMfm(bits, cursor, interleaved); +} + +static void write_interleaved_bytes(std::vector& bits, unsigned& cursor, uint32_t data) +{ + Bytes b(4); + ByteWriter bw(b); + bw.write_be32(data); + write_interleaved_bytes(bits, cursor, b); +} + +static void write_sector(std::vector& bits, unsigned& cursor, const Sector* sector) { write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8); - Bytes header(4); - ByteWriter bw(header); - bw.write_8(0xff); /* Amiga 1.0 format byte */ - bw.write_8((sector->logicalTrack<<1) | sector->logicalSide); - bw.write_8(sector->logicalSector); - bw.write_8(AMIGA_SECTORS_PER_TRACK - sector->logicalSector); + std::vector headerBits(20*16); + unsigned headerCursor = 0; + + Bytes header = + { + 0xff, /* Amiga 1.0 format byte */ + (uint8_t) ((sector->logicalTrack<<1) | sector->logicalSide), + (uint8_t) sector->logicalSector, + (uint8_t) (AMIGA_SECTORS_PER_TRACK - sector->logicalSector) + }; + write_interleaved_bytes(headerBits, headerCursor, header); + Bytes recoveryInfo(16); + write_interleaved_bytes(headerBits, headerCursor, recoveryInfo); + + std::vector dataBits(512*16); + unsigned dataCursor = 0; + write_interleaved_bytes(dataBits, dataCursor, sector->data); + + write_bits(bits, cursor, headerBits); + uint32_t headerChecksum = amigaChecksum(toBytes(headerBits)); + write_interleaved_bytes(bits, cursor, headerChecksum); + uint32_t dataChecksum = amigaChecksum(toBytes(dataBits)); + write_interleaved_bytes(bits, cursor, dataChecksum); + write_bits(bits, cursor, dataBits); } std::unique_ptr AmigaEncoder::encode( @@ -76,11 +106,11 @@ std::unique_ptr AmigaEncoder::encode( for (int sectorId=0; sectorId bits.size()) + if (cursor >= bits.size()) Error() << "track data overrun"; fillBitmapTo(bits, cursor, bits.size(), { true, false }); diff --git a/arch/brother/encoder.cc b/arch/brother/encoder.cc index 20911866..3037db01 100644 --- a/arch/brother/encoder.cc +++ b/arch/brother/encoder.cc @@ -154,7 +154,7 @@ std::unique_ptr BrotherEncoder::encode( write_sector_data(bits, cursor, sectorData->data); } - if (cursor > bits.size()) + if (cursor >= bits.size()) Error() << "track data overrun"; fillBitmapTo(bits, cursor, bits.size(), { true, false }); diff --git a/lib/decoders/decoders.h b/lib/decoders/decoders.h index f1f68b3c..d622e4a0 100644 --- a/lib/decoders/decoders.h +++ b/lib/decoders/decoders.h @@ -20,6 +20,7 @@ extern void setDecoderManualClockRate(double clockrate_us); extern Bytes decodeFmMfm(std::vector::const_iterator start, std::vector::const_iterator end); +extern void encodeMfm(std::vector& bits, unsigned& cursor, const Bytes& input); static inline Bytes decodeFmMfm(const std::vector bits) { return decodeFmMfm(bits.begin(), bits.end()); } diff --git a/lib/decoders/fmmfm.cc b/lib/decoders/fmmfm.cc index 097214bf..cba3aa42 100644 --- a/lib/decoders/fmmfm.cc +++ b/lib/decoders/fmmfm.cc @@ -51,3 +51,25 @@ Bytes decodeFmMfm( return bytes; } + +void encodeMfm(std::vector& bits, unsigned& cursor, const Bytes& input) +{ + bool lastBit = false; + unsigned len = bits.size()-1; + + for (uint8_t b : input) + { + for (int i=0; i<8; i++) + { + bool bit = b & 0x80; + b <<= 1; + + if (cursor >= len) + return; + + bits[cursor++] = !lastBit && !bit; + bits[cursor++] = bit; + lastBit = bit; + } + } +} diff --git a/mkninja.sh b/mkninja.sh index c755cd9f..689fea4c 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -146,6 +146,7 @@ buildlibrary libbackend.a \ arch/aeslanier/decoder.cc \ arch/amiga/decoder.cc \ arch/amiga/encoder.cc \ + arch/amiga/amiga.cc \ arch/apple2/decoder.cc \ arch/brother/decoder.cc \ arch/brother/encoder.cc \ @@ -253,3 +254,4 @@ runtest fluxpattern-test tests/fluxpattern.cc runtest fmmfm-test tests/fmmfm.cc runtest kryoflux-test tests/kryoflux.cc runtest ldbs-test tests/ldbs.cc +runtest amiga-test tests/amiga.cc diff --git a/tests/amiga.cc b/tests/amiga.cc new file mode 100644 index 00000000..db6af12f --- /dev/null +++ b/tests/amiga.cc @@ -0,0 +1,38 @@ +#include "globals.h" +#include "bytes.h" +#include "record.h" +#include "decoders/decoders.h" +#include "arch/amiga/amiga.h" +#include + +static const Bytes testData = { + 0x52, /* 0101 0010 */ + 0xff, /* 1111 1111 */ + 0x4a, /* 0100 1010 */ + 0x22, /* 0010 0010 */ +}; +static const Bytes testDataInterleaved = { + 0x1f, /* 0001 1111 */ + 0x35, /* 0011 0101 */ + 0xcf, /* 1100 1111 */ + 0x80, /* 1000 0000 */ +}; + +static void testInterleave(void) +{ + Bytes interleaved = amigaInterleave(testData); + assert(interleaved == testDataInterleaved); +} + +static void testDeinterleave(void) +{ + Bytes deinterleaved = amigaDeinterleave(testDataInterleaved); + assert(deinterleaved == testData); +} + +int main(int argc, const char* argv[]) +{ + testDeinterleave(); + testInterleave(); + return 0; +} From 5c9639ec5ae542cdec14fc88c518357be47dfecf Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 21:15:47 +0100 Subject: [PATCH 5/8] Document the Amiga write support. --- doc/disk-amiga.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/doc/disk-amiga.md b/doc/disk-amiga.md index b3edbe3b..e69a8be0 100644 --- a/doc/disk-amiga.md +++ b/doc/disk-amiga.md @@ -10,7 +10,7 @@ Bizarrely, the data in each sector is stored with all the odd bits first, and then all the even bits. This is tied into the checksum algorithm, which is distinctly subpar and not particularly good at detecting errors. -Reading discs +Reading disks ------------- Just do: @@ -34,6 +34,28 @@ You will end up with a 929280 byte long image which you probably _can't_ use in an emulator; each sector will contain the 512 bytes of user payload followed by the 16 bytes of metadata. +Writing disks +------------- + +Just do: + +``` +fluxengine write amiga -i amiga.adf +``` + +This will rake a normal 901120 byte long ADF file and write it to a DD disk. +Note that writing to an HD disk will probably not work (this will depend on +your drive and disk and potential FluxEngine bugs I'm still working on --- +please [get in touch](https://github.com/davidgiven/fluxengine/issues/new) if +you have any insight here). + +If you want to write the metadata as well, specify a 528 byte sector size for +the output image and supply a 929280 byte long file as described above. + +``` +fluxengine write amiga -i amiga.adf:b=528 +``` + Useful references ----------------- From 4475e9f08562354b6b866ddb1549aba96413aeaa Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 21:33:39 +0100 Subject: [PATCH 6/8] Increase the default bit-error-threshold to 0.4, because that's the value I almost always end up using. --- lib/decoders/fluxmapreader.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decoders/fluxmapreader.cc b/lib/decoders/fluxmapreader.cc index 5d7dfb50..ec2ca933 100644 --- a/lib/decoders/fluxmapreader.cc +++ b/lib/decoders/fluxmapreader.cc @@ -18,7 +18,7 @@ DoubleFlag pulseDebounceThreshold( static DoubleFlag clockDecodeThreshold( { "--bit-error-threshold" }, "Amount of error to tolerate in pulse timing, in fractions of a clock.", - 0.20); + 0.40); static DoubleFlag clockIntervalBias( { "--clock-interval-bias" }, From 7c66e1b0d4fad17d65da7866d735d2d40ef08fec Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 21:43:48 +0100 Subject: [PATCH 7/8] Don't recalibrate after drive errors --- it's really annoying and I don't think it helps. --- lib/reader.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/reader.cc b/lib/reader.cc index 03eedd2f..1a16f306 100644 --- a/lib/reader.cc +++ b/lib/reader.cc @@ -219,10 +219,7 @@ void readDiskCommand(AbstractDecoder& decoder) std::cout << "giving up" << std::endl << " "; else - { std::cout << retry << " retries remaining" << std::endl; - track->fluxsource->recalibrate(); - } } if (dumpRecords) From d0ed5b32f7f1e9dc8cdb56f0002f730e680bfb56 Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 14 Dec 2019 21:49:31 +0100 Subject: [PATCH 8/8] Add support for 528-byte sectors. Adjust the post-index gap to (try?) and fit all the data in one revolution. I think my write clock is a bit slow. --- arch/amiga/encoder.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/amiga/encoder.cc b/arch/amiga/encoder.cc index 8155b2b3..5e8b5c55 100644 --- a/arch/amiga/encoder.cc +++ b/arch/amiga/encoder.cc @@ -17,7 +17,7 @@ static DoubleFlag clockRateUs( static DoubleFlag postIndexGapMs( { "--post-index-gap" }, "Post-index gap before first sector header (milliseconds).", - 5.0); + 0.5); static int charToInt(char c) { @@ -64,6 +64,9 @@ static void write_interleaved_bytes(std::vector& bits, unsigned& cursor, u static void write_sector(std::vector& bits, unsigned& cursor, const Sector* sector) { + if ((sector->data.size() != 512) && (sector->data.size() != 528)) + Error() << "unsupported sector size --- you must pick 512 or 528"; + write_bits(bits, cursor, AMIGA_SECTOR_RECORD, 6*8); std::vector headerBits(20*16); @@ -78,6 +81,8 @@ static void write_sector(std::vector& bits, unsigned& cursor, const Sector }; write_interleaved_bytes(headerBits, headerCursor, header); Bytes recoveryInfo(16); + if (sector->data.size() == 528) + recoveryInfo = sector->data.slice(512, 16); write_interleaved_bytes(headerBits, headerCursor, recoveryInfo); std::vector dataBits(512*16);