From d906d92016d8afc87930253c3f58291ad81e59a7 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 8 Aug 2019 23:52:21 +0200 Subject: [PATCH 1/2] Add skeleton QuickDisk support. --- lib/dataspec.cc | 3 +- lib/dataspec.h | 1 + lib/fluxsource/fluxsource.cc | 7 +++- lib/fluxsource/fluxsource.h | 2 ++ lib/fluxsource/quickdiskfluxsource.cc | 50 +++++++++++++++++++++++++++ lib/reader.cc | 7 ++-- lib/usb.cc | 19 ++++++++++ lib/usb.h | 1 + mkninja.sh | 2 ++ protocol.h | 4 ++- src/fe-readqd.cc | 26 ++++++++++++++ src/fluxengine.cc | 2 ++ tests/dataspec.cc | 9 +++++ 13 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 lib/fluxsource/quickdiskfluxsource.cc create mode 100644 src/fe-readqd.cc diff --git a/lib/dataspec.cc b/lib/dataspec.cc index cbc04f3e5..b59cec6fb 100644 --- a/lib/dataspec.cc +++ b/lib/dataspec.cc @@ -112,6 +112,7 @@ FluxSpec::FluxSpec(const DataSpec& spec) locations.clear(); + quickdisk = spec.has("qd") && spec.at("qd").only(); const auto& drives = spec.at("d").data; if (drives.size() != 1) Error() << "you must specify exactly one drive"; @@ -128,7 +129,7 @@ FluxSpec::FluxSpec(const DataSpec& spec) for (const auto& e : spec.modifiers) { const auto name = e.second.name; - if ((name != "t") && (name != "s") && (name != "d")) + if ((name != "t") && (name != "s") && (name != "d") && (name != "qd")) Error() << fmt::format("unknown fluxspec modifier '{}'", name); } } diff --git a/lib/dataspec.h b/lib/dataspec.h index ff3aac348..1d3ccd34b 100644 --- a/lib/dataspec.h +++ b/lib/dataspec.h @@ -73,6 +73,7 @@ class FluxSpec std::string filename; std::vector locations; unsigned drive; + bool quickdisk : 1; }; class ImageSpec diff --git a/lib/fluxsource/fluxsource.cc b/lib/fluxsource/fluxsource.cc index f8551fe47..6a354c4c8 100644 --- a/lib/fluxsource/fluxsource.cc +++ b/lib/fluxsource/fluxsource.cc @@ -15,7 +15,12 @@ std::unique_ptr FluxSource::create(const FluxSpec& spec) const auto& filename = spec.filename; if (filename.empty()) - return createHardwareFluxSource(spec.drive); + { + if (spec.quickdisk) + return createQuickdiskFluxSource(spec.drive); + else + return createHardwareFluxSource(spec.drive); + } else if (ends_with(filename, ".flux")) return createSqliteFluxSource(filename); else if (ends_with(filename, "/")) diff --git a/lib/fluxsource/fluxsource.h b/lib/fluxsource/fluxsource.h index ac3c38650..6db05397c 100644 --- a/lib/fluxsource/fluxsource.h +++ b/lib/fluxsource/fluxsource.h @@ -4,6 +4,7 @@ #include "flags.h" extern FlagGroup hardwareFluxSourceFlags; +extern FlagGroup quickdiskFluxSourceFlags; class Fluxmap; class FluxSpec; @@ -16,6 +17,7 @@ class FluxSource private: static std::unique_ptr createSqliteFluxSource(const std::string& filename); static std::unique_ptr createHardwareFluxSource(unsigned drive); + static std::unique_ptr createQuickdiskFluxSource(unsigned drive); static std::unique_ptr createStreamFluxSource(const std::string& path); public: diff --git a/lib/fluxsource/quickdiskfluxsource.cc b/lib/fluxsource/quickdiskfluxsource.cc new file mode 100644 index 000000000..ff85b3bcc --- /dev/null +++ b/lib/fluxsource/quickdiskfluxsource.cc @@ -0,0 +1,50 @@ +#include "globals.h" +#include "flags.h" +#include "fluxmap.h" +#include "usb.h" +#include "fluxsource/fluxsource.h" + +FlagGroup quickdiskFluxSourceFlags; + +class QuickdiskFluxSource : public FluxSource +{ +public: + QuickdiskFluxSource(unsigned drive): + _drive(drive) + { + } + + ~QuickdiskFluxSource() + { + } + +public: + std::unique_ptr readFlux(int track, int side) + { + usbSetDrive(_drive, false); + Bytes crunched = usbReadQD(side); + auto fluxmap = std::make_unique(); + fluxmap->appendBytes(crunched.uncrunch()); + return fluxmap; + } + + void recalibrate() + { + } + + bool retryable() + { + return true; + } + +private: + unsigned _drive; +}; + +std::unique_ptr FluxSource::createQuickdiskFluxSource(unsigned drive) +{ + return std::unique_ptr(new QuickdiskFluxSource(drive)); +} + + + diff --git a/lib/reader.cc b/lib/reader.cc index 86bccba64..a48b719e4 100644 --- a/lib/reader.cc +++ b/lib/reader.cc @@ -16,7 +16,7 @@ #include "track.h" #include "fmt/format.h" -FlagGroup readerFlags { &hardwareFluxSourceFlags, &fluxmapReaderFlags }; +FlagGroup readerFlags { &hardwareFluxSourceFlags, &quickdiskFluxSourceFlags, &fluxmapReaderFlags }; static DataSpecFlag source( { "--source", "-s" }, @@ -85,8 +85,6 @@ std::vector> readTracks() std::cout << "Reading from: " << source << std::endl; - setHardwareFluxSourceDensity(highDensityFlag); - if (!destination.get().empty()) { outdb = sqlOpen(destination, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); @@ -102,8 +100,9 @@ std::vector> readTracks() ); } - std::shared_ptr fluxSource = FluxSource::create(spec); + setHardwareFluxSourceDensity(highDensityFlag); + std::shared_ptr fluxSource = FluxSource::create(spec); std::vector> tracks; for (const auto& location : spec.locations) { diff --git a/lib/usb.cc b/lib/usb.cc index 57043a87e..81950a963 100644 --- a/lib/usb.cc +++ b/lib/usb.cc @@ -221,6 +221,25 @@ Bytes usbRead(int side, int revolutions) return buffer; } +Bytes usbReadQD(int side) +{ + struct read_frame f = { + .f = { .type = F_FRAME_READ_QD_CMD, .size = sizeof(f) }, + .side = (uint8_t) side, + .revolutions = 1 + }; + usb_cmd_send(&f, f.f.size); + + auto fluxmap = std::unique_ptr(new Fluxmap); + + Bytes buffer(1024*1024); + int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer); + buffer.resize(len); + + await_reply(F_FRAME_READ_REPLY); + return buffer; +} + void usbWrite(int side, const Bytes& bytes) { unsigned safelen = bytes.size() & ~(FRAME_SIZE-1); diff --git a/lib/usb.h b/lib/usb.h index 3f47da941..fc1a700b3 100644 --- a/lib/usb.h +++ b/lib/usb.h @@ -10,6 +10,7 @@ extern void usbSeek(int track); extern nanoseconds_t usbGetRotationalPeriod(); extern void usbTestBulkTransport(); extern Bytes usbRead(int side, int revolutions); +extern Bytes usbReadQD(int side); extern void usbWrite(int side, const Bytes& bytes); extern void usbErase(int side); extern void usbSetDrive(int drive, bool high_density); diff --git a/mkninja.sh b/mkninja.sh index 1d66febd2..784096215 100644 --- a/mkninja.sh +++ b/mkninja.sh @@ -165,6 +165,7 @@ buildlibrary libbackend.a \ lib/fluxsink/sqlitefluxsink.cc \ lib/fluxsource/fluxsource.cc \ lib/fluxsource/hardwarefluxsource.cc \ + lib/fluxsource/quickdiskfluxsource.cc \ lib/fluxsource/kryoflux.cc \ lib/fluxsource/sqlitefluxsource.cc \ lib/fluxsource/streamfluxsource.cc \ @@ -199,6 +200,7 @@ buildlibrary libfrontend.a \ src/fe-readibm.cc \ src/fe-readmac.cc \ src/fe-readmx.cc \ + src/fe-readqd.cc \ src/fe-readvictor9k.cc \ src/fe-readzilogmcz.cc \ src/fe-rpm.cc \ diff --git a/protocol.h b/protocol.h index 1f4abfbee..781a945a5 100644 --- a/protocol.h +++ b/protocol.h @@ -3,7 +3,7 @@ enum { - FLUXENGINE_VERSION = 8, + FLUXENGINE_VERSION = 9, FLUXENGINE_VID = 0x1209, FLUXENGINE_PID = 0x6e00, @@ -54,6 +54,8 @@ enum F_FRAME_BULK_TEST_REPLY, /* any_frame */ F_FRAME_READ_CMD, /* read_frame */ F_FRAME_READ_REPLY, /* any_frame */ + F_FRAME_READ_QD_CMD, /* read_frame */ + F_FRAME_READ_QD_REPLY, /* any_frame */ F_FRAME_WRITE_CMD, /* write_frame */ F_FRAME_WRITE_REPLY, /* any_frame */ F_FRAME_ERASE_CMD, /* erase_frame */ diff --git a/src/fe-readqd.cc b/src/fe-readqd.cc new file mode 100644 index 000000000..67668006d --- /dev/null +++ b/src/fe-readqd.cc @@ -0,0 +1,26 @@ +#include "globals.h" +#include "flags.h" +#include "reader.h" +#include "fluxmap.h" +#include "decoders/decoders.h" +#include "image.h" +#include "sector.h" +#include "sectorset.h" +#include "record.h" +#include "ibm/ibm.h" +#include "fmt/format.h" + +static FlagGroup flags { &readerFlags }; + +int mainReadQd(int argc, const char* argv[]) +{ + setReaderDefaultSource(":qd=1"); + setReaderDefaultOutput("qd.img"); + setReaderRevolutions(2); + flags.parseFlags(argc, argv); + + IbmDecoder decoder(0); + readDiskCommand(decoder); + return 0; +} + diff --git a/src/fluxengine.cc b/src/fluxengine.cc index 26ce9a008..3cc11340e 100644 --- a/src/fluxengine.cc +++ b/src/fluxengine.cc @@ -20,6 +20,7 @@ extern command_cb mainReadFB100; extern command_cb mainReadIBM; extern command_cb mainReadMac; extern command_cb mainReadMx; +extern command_cb mainReadQd; extern command_cb mainReadVictor9K; extern command_cb mainReadZilogMCZ; extern command_cb mainRpm; @@ -71,6 +72,7 @@ static std::vector readables = { "ibm", mainReadIBM, "Reads the ubiquitous IBM format disks.", }, { "mac", mainReadMac, "Reads Apple Macintosh disks.", }, { "mx", mainReadMx, "Reads MX disks.", }, + { "qd", mainReadQd, "Reads QuickDisk disks.", }, { "victor9k", mainReadVictor9K, "Reads Victor 9000 disks.", }, { "zilogmcz", mainReadZilogMCZ, "Reads Zilog MCZ disks.", }, }; diff --git a/tests/dataspec.cc b/tests/dataspec.cc index 4c937caba..978d05c4b 100644 --- a/tests/dataspec.cc +++ b/tests/dataspec.cc @@ -85,6 +85,15 @@ static void test_fluxspec(void) {{1, 9, 1}})); assert((std::string)spec == ":d=1:s=1:t=9"); } + + spec.set(""); + assert(FluxSpec(spec).quickdisk == false); + + spec.set(":qd=0"); + assert(FluxSpec(spec).quickdisk == false); + + spec.set(":qd=1"); + assert(FluxSpec(spec).quickdisk == true); } static void test_imagespec(void) From 047521475f8c36f7fb2acac06f34123f941a32e6 Mon Sep 17 00:00:00 2001 From: David Given Date: Fri, 9 Aug 2019 00:24:09 +0200 Subject: [PATCH 2/2] Add incredibly untested firmware for reading QuickDisk disks. --- FluxEngine.cydsn/FluxEngine.cyprj | 41 +++- FluxEngine.cydsn/TopDesign/TopDesign.cysch | Bin 215882 -> 215880 bytes FluxEngine.cydsn/main.c | 209 ++++++++++++++------- lib/usb.cc | 2 +- 4 files changed, 181 insertions(+), 71 deletions(-) diff --git a/FluxEngine.cydsn/FluxEngine.cyprj b/FluxEngine.cydsn/FluxEngine.cyprj index 4566365c7..1cb49e91d 100644 --- a/FluxEngine.cydsn/FluxEngine.cyprj +++ b/FluxEngine.cydsn/FluxEngine.cyprj @@ -1058,27 +1058,27 @@ - + - + - + - + @@ -3282,6 +3282,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FluxEngine.cydsn/TopDesign/TopDesign.cysch b/FluxEngine.cydsn/TopDesign/TopDesign.cysch index ffe2bf131c9393ba1875f94bdaec18977de6b456..f96255765444d7967a094ed94ef522b4466ed522 100644 GIT binary patch delta 7559 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 delta 7539 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 diff --git a/FluxEngine.cydsn/main.c b/FluxEngine.cydsn/main.c index 9b956ba5e..f6da2a936 100644 --- a/FluxEngine.cydsn/main.c +++ b/FluxEngine.cydsn/main.c @@ -12,7 +12,7 @@ #define STEP_SETTLING_TIME 50 /* ms */ #define DISKSTATUS_WPT 1 -#define DISKSTATUS_DSKCHG 2 +#define DISKSTATUS_READY 2 /* Only used on QuickDisk drives */ #define STEP_TOWARDS0 1 #define STEP_AWAYFROM0 0 @@ -37,6 +37,7 @@ static uint8_t dma_channel; static volatile int dma_writing_to_td = 0; static volatile int dma_reading_from_td = 0; static volatile bool dma_underrun = false; +static crunch_state_t cs = {}; #define DECLARE_REPLY_FRAME(STRUCT, TYPE) \ STRUCT r = {.f = { .type = TYPE, .size = sizeof(STRUCT) }} @@ -269,13 +270,8 @@ static void init_capture_dma(void) } } -static void cmd_read(struct read_frame* f) +static void init_capture(void) { - SIDE_REG_Write(f->side); - seek_to(current_track); - - /* Do slow setup *before* we go into the real-time bit. */ - SAMPLER_CONTROL_Write(1); /* reset */ { @@ -288,84 +284,69 @@ static void cmd_read(struct read_frame* f) wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); init_capture_dma(); +} - /* Wait for the beginning of a rotation. */ - - print("wait"); - index_irq = false; - while (!index_irq) - ; - index_irq = false; - - crunch_state_t cs = {}; +static void start_capture(void) +{ + memset(&cs, 0, sizeof(crunch_state_t)); cs.outputptr = usb_buffer; cs.outputlen = BUFFER_SIZE; dma_writing_to_td = 0; dma_reading_from_td = -1; dma_underrun = false; - int count = 0; SAMPLER_CONTROL_Write(0); /* !reset */ CAPTURE_CONTROL_Write(1); CyDmaChSetInitialTd(dma_channel, td[dma_writing_to_td]); CyDmaClearPendingDrq(dma_channel); CyDmaChEnable(dma_channel, 1); - /* Wait for the first DMA transfer to complete, after which we can start the - * USB transfer. */ + /* Wait for the first DMA transfer to complete, after which we can start + * the USB transfer. */ - while ((dma_writing_to_td == 0) && !index_irq) + while (dma_writing_to_td == 0) ; dma_reading_from_td = 0; - - /* Start transferring. */ +} - int revolutions = f->revolutions; - while (!dma_underrun) +/* returns true if capture is aborted */ +static bool do_capture_chunk(void) +{ + /* Wait for the next block to be read. */ + while (dma_reading_from_td == dma_writing_to_td) { - CyWdtClear(); - - /* Have we reached the index pulse? */ - if (index_irq) - { - index_irq = false; - revolutions--; - if (revolutions == 0) - break; - } - - /* Wait for the next block to be read. */ - while (dma_reading_from_td == dma_writing_to_td) - { - /* On an underrun, give up immediately. */ - if (dma_underrun) - goto abort; - } + /* On an underrun, give up immediately. */ + if (dma_underrun) + return true; + } - uint8_t dma_buffer_usage = 0; - while (dma_buffer_usage < BUFFER_SIZE) + uint8_t dma_buffer_usage = 0; + while (dma_buffer_usage < BUFFER_SIZE) + { + cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; + cs.inputlen = BUFFER_SIZE - dma_buffer_usage; + crunch(&cs); + dma_buffer_usage += BUFFER_SIZE - cs.inputlen; + if (cs.outputlen == 0) { - cs.inputptr = dma_buffer[dma_reading_from_td] + dma_buffer_usage; - cs.inputlen = BUFFER_SIZE - dma_buffer_usage; - crunch(&cs); - dma_buffer_usage += BUFFER_SIZE - cs.inputlen; - count++; - if (cs.outputlen == 0) + while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY) { - while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY) - { - if (index_irq || dma_underrun) - goto abort; - } - - USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); - cs.outputptr = usb_buffer; - cs.outputlen = BUFFER_SIZE; + if (dma_underrun) + return true; } + + USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE); + cs.outputptr = usb_buffer; + cs.outputlen = BUFFER_SIZE; } - dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); } -abort:; + dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td); + + return false; +} + +static void stop_capture(void) +{ CAPTURE_CONTROL_Write(0); CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN); while (CyDmaChGetRequest(dma_channel)) @@ -373,25 +354,117 @@ abort:; donecrunch(&cs); wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); - unsigned zz = cs.outputlen; if (cs.outputlen != BUFFER_SIZE) USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, usb_buffer, BUFFER_SIZE-cs.outputlen); if ((cs.outputlen == BUFFER_SIZE) || (cs.outputlen == 0)) USBFS_LoadInEP(FLUXENGINE_DATA_IN_EP_NUM, NULL, 0); wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM); deinit_dma(); +} - if (dma_underrun) +static void cmd_read(struct read_frame* f) +{ + SIDE_REG_Write(f->side); + seek_to(current_track); + + /* Do slow setup *before* we go into the real-time bit. */ + + init_capture(); + + /* Wait for the beginning of a rotation. */ + + index_irq = false; + while (!index_irq) + ; + index_irq = false; + + /* Start transferring. */ + + start_capture(); + int revolutions = f->revolutions; + while (!dma_underrun) { - print("underrun after %d packets"); - send_error(F_ERROR_UNDERRUN); + CyWdtClear(); + + /* Have we reached the index pulse? */ + if (index_irq) + { + index_irq = false; + revolutions--; + if (revolutions == 0) + break; + } + + if (do_capture_chunk()) + goto abort; } +abort:; + stop_capture(); + + if (dma_underrun) + send_error(F_ERROR_UNDERRUN); else { DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_READ_REPLY); send_reply(&r); } - print("count=%d i=%d d=%d zz=%d", count, index_irq, dma_underrun, zz); +} + +static void cmd_read_qd(struct read_frame* f) +{ + SIDE_REG_Write(f->side); + + /* Do slow setup *before* we go into the real-time bit. */ + + init_capture(); + + /* Reset the drive. */ + + STEP_REG_Write(2); + CyDelay(10); /* ms */ + STEP_REG_Write(0); + + /* Motor on, and wait for ready. */ + + MOTOR_REG_Write(1); + while (!(DISKSTATUS_REG_Read() & DISKSTATUS_READY)) + ; + + /* Turning the motor off has no effect until the head hits the stop, + * at which point it'll stop automatically. */ + + MOTOR_REG_Write(0); + + /* Start transferring. */ + + start_capture(); + while (!dma_underrun) + { + CyWdtClear(); + + /* Have we reached the end? */ + if (!(DISKSTATUS_REG_Read() & DISKSTATUS_READY)) + break; + + if (do_capture_chunk()) + goto abort; + } +abort:; + stop_capture(); + + /* Reset the drive again to ensure the motor stops. */ + + STEP_REG_Write(2); + CyDelay(10); /* ms */ + STEP_REG_Write(0); + + if (dma_underrun) + send_error(F_ERROR_UNDERRUN); + else + { + DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_READ_QD_REPLY); + send_reply(&r); + } } static void init_replay_dma(void) @@ -647,6 +720,10 @@ static void handle_command(void) cmd_read((struct read_frame*) f); break; + case F_FRAME_READ_QD_CMD: + cmd_read_qd((struct read_frame*) f); + break; + case F_FRAME_WRITE_CMD: cmd_write((struct write_frame*) f); break; diff --git a/lib/usb.cc b/lib/usb.cc index 81950a963..566016098 100644 --- a/lib/usb.cc +++ b/lib/usb.cc @@ -76,7 +76,7 @@ static void bad_reply(void) { struct error_frame* f = (struct error_frame*) buffer; if (f->f.type != F_FRAME_ERROR) - Error() << fmt::format("bad USB reply 0x{:2x}", f->f.type); + Error() << fmt::format("bad USB reply 0x{:02x}", f->f.type); switch (f->error) { case F_ERROR_BAD_COMMAND: