Compare commits

...

4 Commits
devices ... qd

Author SHA1 Message Date
David Given
c8fd984c5c Merge. 2019-08-10 21:41:26 +02:00
David Given
14ed696993 Merge. 2019-08-09 21:22:42 +02:00
David Given
047521475f Add incredibly untested firmware for reading QuickDisk disks. 2019-08-09 00:24:09 +02:00
David Given
d906d92016 Add skeleton QuickDisk support. 2019-08-08 23:52:21 +02:00
16 changed files with 309 additions and 80 deletions

View File

@@ -1058,27 +1058,27 @@
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG" persistent="">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG_aliases.h" persistent="Generated_Source\PSoC5\DSKCHG_aliases.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG.c" persistent="Generated_Source\PSoC5\DSKCHG.c">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="DSKCHG.h" persistent="Generated_Source\PSoC5\DSKCHG.h">
<Hidden v="False" />
<Hidden v="True" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
@@ -3282,6 +3282,39 @@
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
<filters />
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
<CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFolderSerialize" version="3">
<CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtBaseContainerSerialize" version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY" persistent="">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<CyGuid_0820c2e7-528d-4137-9a08-97257b946089 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemListSerialize" version="2">
<dependencies>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY_aliases.h" persistent="Generated_Source\PSoC5\READY_aliases.h">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY.c" persistent="Generated_Source\PSoC5\READY.c">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="SOURCE_C;CortexM3;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
<CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtFileSerialize" version="3" xml_contents_version="1">
<CyGuid_31768f72-0253-412b-af77-e7dba74d1330 type_name="CyDesigner.Common.ProjMgmt.Model.CyPrjMgmtItemSerialize" version="2" name="READY.h" persistent="Generated_Source\PSoC5\READY.h">
<Hidden v="False" />
</CyGuid_31768f72-0253-412b-af77-e7dba74d1330>
<build_action v="HEADER;;;;" />
<PropertyDeltas />
</CyGuid_8b8ab257-35d3-4473-b57b-36315200b38b>
</dependencies>
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>
<filters />
</CyGuid_ebc4f06d-207f-49c2-a540-72acf4adabc0>
</dependencies>
</CyGuid_0820c2e7-528d-4137-9a08-97257b946089>
</CyGuid_2f73275c-45bf-46ba-b3b1-00a2fe0c8dd8>

View File

Binary file not shown.

View File

@@ -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,38 +284,103 @@ 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;
}
/* 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)
{
/* On an underrun, give up immediately. */
if (dma_underrun)
return true;
}
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)
{
while (USBFS_GetEPState(FLUXENGINE_DATA_IN_EP_NUM) != USBFS_IN_BUFFER_EMPTY)
{
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);
return false;
}
static void stop_capture(void)
{
CAPTURE_CONTROL_Write(0);
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
while (CyDmaChGetRequest(dma_channel))
;
donecrunch(&cs);
wait_until_writeable(FLUXENGINE_DATA_IN_EP_NUM);
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();
}
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)
{
@@ -333,65 +394,77 @@ static void cmd_read(struct read_frame* f)
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;
}
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;
count++;
if (cs.outputlen == 0)
{
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;
}
}
dma_reading_from_td = NEXT_BUFFER(dma_reading_from_td);
if (do_capture_chunk())
goto abort;
}
abort:;
CAPTURE_CONTROL_Write(0);
CyDmaChSetRequest(dma_channel, CY_DMA_CPU_TERM_CHAIN);
while (CyDmaChGetRequest(dma_channel))
;
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();
stop_capture();
if (dma_underrun)
{
print("underrun after %d packets");
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;

View File

@@ -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);
}
}

View File

@@ -73,6 +73,7 @@ public:
std::string filename;
std::vector<Location> locations;
unsigned drive;
bool quickdisk : 1;
};
class ImageSpec

View File

@@ -15,7 +15,12 @@ std::unique_ptr<FluxSource> 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, "/"))

View File

@@ -4,6 +4,7 @@
#include "flags.h"
extern FlagGroup hardwareFluxSourceFlags;
extern FlagGroup quickdiskFluxSourceFlags;
class Fluxmap;
class FluxSpec;
@@ -16,6 +17,7 @@ public:
private:
static std::unique_ptr<FluxSource> createSqliteFluxSource(const std::string& filename);
static std::unique_ptr<FluxSource> createHardwareFluxSource(unsigned drive);
static std::unique_ptr<FluxSource> createQuickdiskFluxSource(unsigned drive);
static std::unique_ptr<FluxSource> createStreamFluxSource(const std::string& path);
public:

View File

@@ -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<Fluxmap> readFlux(int track, int side)
{
usbSetDrive(_drive, false);
Bytes crunched = usbReadQD(side);
auto fluxmap = std::make_unique<Fluxmap>();
fluxmap->appendBytes(crunched.uncrunch());
return fluxmap;
}
void recalibrate()
{
}
bool retryable()
{
return true;
}
private:
unsigned _drive;
};
std::unique_ptr<FluxSource> FluxSource::createQuickdiskFluxSource(unsigned drive)
{
return std::unique_ptr<FluxSource>(new QuickdiskFluxSource(drive));
}

View File

@@ -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<std::unique_ptr<Track>> 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<std::unique_ptr<Track>> readTracks()
);
}
std::shared_ptr<FluxSource> fluxSource = FluxSource::create(spec);
setHardwareFluxSourceDensity(highDensityFlag);
std::shared_ptr<FluxSource> fluxSource = FluxSource::create(spec);
std::vector<std::unique_ptr<Track>> tracks;
for (const auto& location : spec.locations)
{

View File

@@ -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:
@@ -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<Fluxmap>(new Fluxmap);
Bytes buffer(1024*1024);
int len = large_bulk_transfer(FLUXENGINE_DATA_IN_EP, buffer);
buffer.resize(len);
await_reply<struct any_frame>(F_FRAME_READ_REPLY);
return buffer;
}
void usbWrite(int side, const Bytes& bytes)
{
unsigned safelen = bytes.size() & ~(FRAME_SIZE-1);

View File

@@ -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);

View File

@@ -170,6 +170,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 \
@@ -203,6 +204,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 \

View File

@@ -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 */

26
src/fe-readqd.cc Normal file
View File

@@ -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;
}

View File

@@ -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<Command> 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.", },
};

View File

@@ -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)