Add firmware support for hard sectors

This commit is contained in:
Eric Anderson
2020-12-24 15:41:51 -08:00
parent 15e6d4959e
commit f1506d0dbd
14 changed files with 143 additions and 31 deletions

View File

@@ -21,6 +21,10 @@ static bool drive1_present;
static volatile uint32_t clock = 0; /* ms */
static volatile bool index_irq = false;
/* Duration in ms. 0 causes every pulse to be an index pulse. Durations since
* last pulse greater than this value imply sector pulse. Otherwise is an index
* pulse. */
static volatile uint32_t hardsec_index_threshold = 0;
static bool motor_on = false;
static uint32_t motor_on_time = 0;
@@ -69,12 +73,34 @@ static void system_timer_cb(void)
CY_ISR(index_irq_cb)
{
index_irq = true;
/* Hard sectored media has sector pulses at the beginning of every sector
* and the index pulse is an extra pulse in the middle of the last sector.
* When the extra pulse is seen, the next sector pulse is also the start of
* the track. */
static bool hardsec_index_irq_primed = false;
static uint32_t hardsec_last_pulse_time = 0;
if (!hardsec_index_threshold)
{
index_irq = true;
hardsec_index_irq_primed = false;
}
else
{
index_irq = hardsec_index_irq_primed;
if (index_irq)
hardsec_index_irq_primed = false;
else
hardsec_index_irq_primed =
clock - hardsec_last_pulse_time <= hardsec_index_threshold;
hardsec_last_pulse_time = clock;
}
/* Stop writing the instant the index pulse comes along; it may take a few
* moments for the main code to notice the pulse, and we don't want to overwrite
* the beginning of the track. */
ERASE_REG_Write(0);
if (index_irq)
ERASE_REG_Write(0);
}
CY_ISR(capture_dma_finished_irq_cb)
@@ -267,7 +293,7 @@ static void cmd_recalibrate(void)
send_reply(&r);
}
static void cmd_measure_speed(struct any_frame* f)
static void cmd_measure_speed(struct measurespeed_frame* f)
{
start_motor();
@@ -286,10 +312,14 @@ static void cmd_measure_speed(struct any_frame* f)
if (elapsed != 0)
{
index_irq = false;
int target_pulse_count = f->hard_sector_count + 1;
start_clock = clock;
while (!index_irq)
elapsed = clock - start_clock;
for (int x=0; x<target_pulse_count; x++)
{
index_irq = false;
while (!index_irq)
elapsed = clock - start_clock;
}
}
DECLARE_REPLY_FRAME(struct speed_frame, F_FRAME_MEASURE_SPEED_REPLY);
@@ -401,10 +431,12 @@ static void cmd_read(struct read_frame* f)
if (f->synced)
{
hardsec_index_threshold = f->hardsec_threshold_ms;
index_irq = false;
while (!index_irq)
;
index_irq = false;
hardsec_index_threshold = 0;
}
dma_writing_to_td = 0;
@@ -591,6 +623,7 @@ static void cmd_write(struct write_frame* f)
/* Wait for the index marker. While this happens, the DMA engine
* will prime the FIFO. */
hardsec_index_threshold = f->hardsec_threshold_ms;
index_irq = false;
while (!index_irq)
;
@@ -625,6 +658,7 @@ abort:
}
print("p=%d cr=%d cw=%d f=%d w=%d index=%d underrun=%d", packets, count_read, count_written, finished, writing, index_irq, dma_underrun);
hardsec_index_threshold = 0;
if (!finished)
{
/* There's still some data to read, so just read and blackhole it ---
@@ -657,6 +691,7 @@ static void cmd_erase(struct erase_frame* f)
/* Disk is now spinning. */
print("start erasing");
hardsec_index_threshold = f->hardsec_threshold_ms;
index_irq = false;
while (!index_irq)
;
@@ -665,6 +700,7 @@ static void cmd_erase(struct erase_frame* f)
while (!index_irq)
;
ERASE_REG_Write(0);
hardsec_index_threshold = 0;
print("stop erasing");
DECLARE_REPLY_FRAME(struct any_frame, F_FRAME_ERASE_REPLY);
@@ -790,7 +826,7 @@ static void handle_command(void)
break;
case F_FRAME_MEASURE_SPEED_CMD:
cmd_measure_speed(f);
cmd_measure_speed((struct measurespeed_frame*) f);
break;
case F_FRAME_BULK_WRITE_TEST_CMD:

View File

@@ -24,6 +24,7 @@ public:
};
extern void setHardwareFluxSinkDensity(bool high_density);
extern void setHardwareFluxSinkHardSectorCount(int sectorCount);
#endif

View File

@@ -3,6 +3,7 @@
#include "fluxmap.h"
#include "usb/usb.h"
#include "fluxsink/fluxsink.h"
#include "fmt/format.h"
FlagGroup hardwareFluxSinkFlags = {
&usbFlags,
@@ -15,17 +16,34 @@ static IntFlag indexMode(
"index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source",
0);
static IntFlag hardSectorCount(
{ "--write-hard-sector-count" },
"number of hard sectors on the disk (0=soft sectors)",
0);
void setHardwareFluxSinkDensity(bool high_density)
{
::high_density = high_density;
}
void setHardwareFluxSinkHardSectorCount(int sectorCount)
{
::hardSectorCount.setDefaultValue(sectorCount);
}
class HardwareFluxSink : public FluxSink
{
public:
HardwareFluxSink(unsigned drive):
_drive(drive)
{
if (hardSectorCount.get())
{
std::cerr << "Measuring rotational speed... " << std::flush;
nanoseconds_t oneRevolution = usbGetRotationalPeriod(hardSectorCount);
_hardSectorThreshold = oneRevolution * 3 / (4 * hardSectorCount);
std::cerr << fmt::format("{}ms\n", oneRevolution / 1e6);
}
}
~HardwareFluxSink()
@@ -38,11 +56,12 @@ public:
usbSetDrive(_drive, high_density, indexMode);
usbSeek(track);
return usbWrite(side, fluxmap.rawBytes());
return usbWrite(side, fluxmap.rawBytes(), _hardSectorThreshold);
}
private:
unsigned _drive;
nanoseconds_t _hardSectorThreshold;
};
std::unique_ptr<FluxSink> FluxSink::createHardwareFluxSink(unsigned drive)

View File

@@ -30,6 +30,7 @@ public:
extern void setHardwareFluxSourceRevolutions(double revolutions);
extern void setHardwareFluxSourceDensity(bool high_density);
extern void setHardwareFluxSourceSynced(bool synced);
extern void setHardwareFluxSourceHardSectorCount(int sectorCount);
#endif

View File

@@ -24,6 +24,11 @@ static IntFlag indexMode(
"index pulse source (0=drive, 1=300 RPM fake source, 2=360 RPM fake source",
0);
static IntFlag hardSectorCount(
{ "--hard-sector-count" },
"number of hard sectors on the disk (0=soft sectors)",
0);
static bool high_density = false;
void setHardwareFluxSourceDensity(bool high_density)
@@ -39,7 +44,8 @@ public:
{
usbSetDrive(_drive, high_density, indexMode);
std::cerr << "Measuring rotational speed... " << std::flush;
_oneRevolution = usbGetRotationalPeriod();
_oneRevolution = usbGetRotationalPeriod(hardSectorCount);
_hardSectorThreshold = _oneRevolution * 3 / (4 * hardSectorCount);
std::cerr << fmt::format("{}ms\n", _oneRevolution / 1e6);
}
@@ -52,7 +58,8 @@ public:
{
usbSetDrive(_drive, high_density, indexMode);
usbSeek(track);
Bytes data = usbRead(side, synced, revolutions * _oneRevolution);
Bytes data = usbRead(
side, synced, revolutions * _oneRevolution, _hardSectorThreshold);
auto fluxmap = std::make_unique<Fluxmap>();
fluxmap->appendBytes(data);
return fluxmap;
@@ -72,6 +79,7 @@ private:
unsigned _drive;
unsigned _revolutions;
nanoseconds_t _oneRevolution;
nanoseconds_t _hardSectorThreshold;
};
void setHardwareFluxSourceRevolutions(double revolutions)
@@ -84,6 +92,11 @@ void setHardwareFluxSourceSynced(bool synced)
::synced.setDefaultValue(synced);
}
void setHardwareFluxSourceHardSectorCount(int sectorCount)
{
::hardSectorCount.setDefaultValue(sectorCount);
}
std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(unsigned drive)
{
return std::unique_ptr<FluxSource>(new HardwareFluxSource(drive));

View File

@@ -91,6 +91,11 @@ void setReaderRevolutions(int revolutions)
setHardwareFluxSourceRevolutions(revolutions);
}
void setReaderHardSectorCount(int sectorCount)
{
setHardwareFluxSourceHardSectorCount(sectorCount);
}
static void writeSectorsToFile(const SectorSet& sectors, const ImageSpec& spec)
{
std::unique_ptr<ImageWriter> writer(ImageWriter::create(sectors, spec));

View File

@@ -13,6 +13,7 @@ extern FlagGroup readerFlags;
extern void setReaderDefaultSource(const std::string& source);
extern void setReaderDefaultOutput(const std::string& output);
extern void setReaderRevolutions(int revolutions);
extern void setReaderHardSectorCount(int sectorCount);
extern std::vector<std::unique_ptr<Track>> readTracks();

View File

@@ -144,9 +144,12 @@ public:
await_reply<struct any_frame>(F_FRAME_RECALIBRATE_REPLY);
}
nanoseconds_t getRotationalPeriod(void)
nanoseconds_t getRotationalPeriod(int hardSectorCount)
{
struct any_frame f = { .f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)} };
struct measurespeed_frame f = {
.f = {.type = F_FRAME_MEASURE_SPEED_CMD, .size = sizeof(f)},
.hard_sector_count = (uint8_t) hardSectorCount,
};
usb_cmd_send(&f, f.f.size);
auto r = await_reply<struct speed_frame>(F_FRAME_MEASURE_SPEED_REPLY);
@@ -227,12 +230,15 @@ public:
await_reply<struct any_frame>(F_FRAME_BULK_READ_TEST_REPLY);
}
Bytes read(int side, bool synced, nanoseconds_t readTime)
Bytes read(int side, bool synced, nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold)
{
hardSectorThreshold += 5e5; /* Round to nearest ms. */
struct read_frame f = {
.f = { .type = F_FRAME_READ_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
.synced = (uint8_t) synced
.synced = (uint8_t) synced,
.hardsec_threshold_ms = (uint8_t) (hardSectorThreshold / 1e6),
};
uint16_t milliseconds = readTime / 1e6;
((uint8_t*)&f.milliseconds)[0] = milliseconds;
@@ -249,14 +255,16 @@ public:
return buffer;
}
void write(int side, const Bytes& bytes)
void write(int side, const Bytes& bytes, nanoseconds_t hardSectorThreshold)
{
unsigned safelen = bytes.size() & ~(FRAME_SIZE-1);
Bytes safeBytes = bytes.slice(0, safelen);
hardSectorThreshold += 5e5; /* Round to nearest ms. */
struct write_frame f = {
.f = { .type = F_FRAME_WRITE_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
.hardsec_threshold_ms = (uint8_t) (hardSectorThreshold / 1e6),
};
((uint8_t*)&f.bytes_to_write)[0] = safelen;
((uint8_t*)&f.bytes_to_write)[1] = safelen >> 8;
@@ -269,11 +277,13 @@ public:
await_reply<struct any_frame>(F_FRAME_WRITE_REPLY);
}
void erase(int side)
void erase(int side, nanoseconds_t hardSectorThreshold)
{
hardSectorThreshold += 5e5; /* Round to nearest ms. */
struct erase_frame f = {
.f = { .type = F_FRAME_ERASE_CMD, .size = sizeof(f) },
.side = (uint8_t) side,
.hardsec_threshold_ms = (uint8_t) (hardSectorThreshold / 1e6),
};
usb_cmd_send(&f, f.f.size);

View File

@@ -15,12 +15,14 @@ public:
virtual int getVersion() = 0;
virtual void recalibrate() = 0;
virtual void seek(int track) = 0;
virtual nanoseconds_t getRotationalPeriod() = 0;
virtual nanoseconds_t getRotationalPeriod(int hardSectorCount) = 0;
virtual void testBulkWrite() = 0;
virtual void testBulkRead() = 0;
virtual Bytes read(int side, bool synced, nanoseconds_t readTime) = 0;
virtual void write(int side, const Bytes& bytes) = 0;
virtual void erase(int side) = 0;
virtual Bytes read(int side, bool synced, nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold) = 0;
virtual void write(int side, const Bytes& bytes,
nanoseconds_t hardSectorThreshold) = 0;
virtual void erase(int side, nanoseconds_t hardSectorThreshold) = 0;
virtual void setDrive(int drive, bool high_density, int index_mode) = 0;
virtual void measureVoltages(struct voltages_frame* voltages) = 0;
@@ -40,16 +42,20 @@ static inline void usbRecalibrate() { getUsb().recalibrate(); }
static inline void usbSeek(int track) { getUsb().seek(track); }
static inline void usbTestBulkWrite() { getUsb().testBulkWrite(); }
static inline void usbTestBulkRead() { getUsb().testBulkRead(); }
static inline void usbErase(int side) { getUsb().erase(side); }
static inline nanoseconds_t usbGetRotationalPeriod()
{ return getUsb().getRotationalPeriod(); }
static inline void usbErase(int side, nanoseconds_t hardSectorThreshold)
{ getUsb().erase(side, hardSectorThreshold); }
static inline Bytes usbRead(int side, bool synced, nanoseconds_t readTime)
{ return getUsb().read(side, synced, readTime); }
static inline nanoseconds_t usbGetRotationalPeriod(int hardSectorCount)
{ return getUsb().getRotationalPeriod(hardSectorCount); }
static inline void usbWrite(int side, const Bytes& bytes)
{ getUsb().write(side, bytes); }
static inline Bytes usbRead(int side, bool synced, nanoseconds_t readTime,
nanoseconds_t hardSectorThreshold)
{ return getUsb().read(side, synced, readTime, hardSectorThreshold); }
static inline void usbWrite(int side, const Bytes& bytes,
nanoseconds_t hardSectorThreshold)
{ getUsb().write(side, bytes, hardSectorThreshold); }
static inline void usbSetDrive(int drive, bool high_density, int index_mode)
{ getUsb().setDrive(drive, high_density, index_mode); }

View File

@@ -43,6 +43,11 @@ void setWriterDefaultInput(const std::string& input)
::input.set(input);
}
void setWriterHardSectorCount(int sectorCount)
{
setHardwareFluxSinkHardSectorCount(sectorCount);
}
static SectorSet readSectorsFromFile(const ImageSpec& spec)
{
return ImageReader::create(spec)->readImage();

View File

@@ -11,6 +11,7 @@ class Geometry;
extern void setWriterDefaultDest(const std::string& dest);
extern void setWriterDefaultInput(const std::string& input);
extern void setWriterHardSectorCount(int sectorCount);
extern void writeTracks(const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer);

View File

@@ -3,7 +3,7 @@
enum
{
FLUXENGINE_VERSION = 14,
FLUXENGINE_VERSION = 15,
FLUXENGINE_VID = 0x1209,
FLUXENGINE_PID = 0x6e00,
@@ -48,7 +48,7 @@ enum
F_FRAME_GET_VERSION_REPLY, /* version_frame */
F_FRAME_SEEK_CMD, /* seek_frame */
F_FRAME_SEEK_REPLY, /* any_frame */
F_FRAME_MEASURE_SPEED_CMD, /* any_frame */
F_FRAME_MEASURE_SPEED_CMD, /* measurespeed_frame */
F_FRAME_MEASURE_SPEED_REPLY, /* speed_frame */
F_FRAME_BULK_WRITE_TEST_CMD, /* any_frame */
F_FRAME_BULK_WRITE_TEST_REPLY, /* any_frame */
@@ -125,6 +125,12 @@ struct seek_frame
uint8_t track;
};
struct measurespeed_frame
{
struct frame_header f;
uint8_t hard_sector_count;
};
struct speed_frame
{
struct frame_header f;
@@ -137,6 +143,7 @@ struct read_frame
uint8_t side;
uint8_t synced;
uint16_t milliseconds;
uint8_t hardsec_threshold_ms;
};
struct write_frame
@@ -144,12 +151,14 @@ struct write_frame
struct frame_header f;
uint8_t side;
uint32_t bytes_to_write;
uint8_t hardsec_threshold_ms;
};
struct erase_frame
{
struct frame_header f;
uint8_t side;
uint8_t hardsec_threshold_ms;
};
struct set_drive_frame

View File

@@ -16,7 +16,7 @@ int mainReadMicropolis(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-76");
setReaderDefaultOutput("micropolis.img");
setReaderRevolutions(21); /* 17 index holes * 1.25 */
setReaderHardSectorCount(16);
flags.parseFlags(argc, argv);
MicropolisDecoder decoder;

View File

@@ -13,13 +13,18 @@ static DataSpecFlag source(
"source for data",
":d=0:t=0:s=0");
static IntFlag hardSectorCount(
{ "--hard-sector-count" },
"number of hard sectors on the disk (0=soft sectors)",
0);
int mainRpm(int argc, const char* argv[])
{
flags.parseFlags(argc, argv);
FluxSpec spec(source);
usbSetDrive(spec.drive, false, F_INDEX_REAL);
nanoseconds_t period = usbGetRotationalPeriod();
nanoseconds_t period = usbGetRotationalPeriod(hardSectorCount);
if (period != 0)
std::cout << "Rotational period is " << period/1000000 << " ms (" << 60e9/period << " rpm)" << std::endl;
else