Partial conversion to do automatic scaling of flux based on the disk rotation

speed. Although, something seems to have broken for 5.25" disks.
This commit is contained in:
David Given
2022-03-27 23:50:32 +02:00
parent 0da3d8b231
commit adff739a5d
51 changed files with 291 additions and 302 deletions

View File

@@ -2,7 +2,7 @@ syntax = "proto2";
import "lib/common.proto";
// Next: 13
// Next: 14
message DriveProto
{
optional int32 drive = 1
@@ -22,13 +22,15 @@ message DriveProto
[ default = 81, (help) = "Number of tracks supported by drive" ];
optional int32 heads = 8
[ default = 2, (help) = "Number of heads supported by drive" ];
optional int32 head_bias = 10 [
optional int32 head_bias = 9 [
default = 0,
(help) = "Bias to apply to the head position (in tracks)"
];
optional int32 head_width = 11
optional int32 head_width = 10
[ default = 1, (help) = "Width of the head (in tracks)" ];
optional int32 tpi = 9 [ default = 96, (help) = "TPI of drive" ];
optional int32 tpi = 11 [ default = 96, (help) = "TPI of drive" ];
optional double rotational_period_ms = 12
[ default = 0, (help) = "Rotational period of the drive in milliseconds (0 to autodetect)"];
}
// vim: ts=4 sw=4 et

View File

@@ -19,5 +19,6 @@ message FluxFileProto {
optional int32 magic = 1;
optional FluxFileVersion version = 2;
repeated TrackFluxProto track = 3;
optional double rotational_period_ms = 4;
}

View File

@@ -1,5 +1,6 @@
#include "globals.h"
#include "fluxmap.h"
#include "decoders/fluxmapreader.h"
#include "protocol.h"
Fluxmap& Fluxmap::appendBytes(const Bytes& bytes)
@@ -62,39 +63,6 @@ Fluxmap& Fluxmap::appendDesync()
return *this;
}
void Fluxmap::precompensate(int threshold_ticks, int amount_ticks)
{
uint8_t junk = 0xff;
for (unsigned i = 0; i < _bytes.size(); i++)
{
uint8_t& prev = (i == 0) ? junk : _bytes[i - 1];
uint8_t prevticks = prev & 0x3f;
uint8_t currticks = _bytes[i] & 0x3f;
if (currticks < (3 * threshold_ticks))
{
if ((prevticks <= threshold_ticks) && (currticks > threshold_ticks))
{
/* 01001; move the previous bit backwards. */
if (prevticks >= (1 + amount_ticks))
prev -= amount_ticks;
if (currticks <= (0x7f - amount_ticks))
currticks += amount_ticks;
}
else if ((prevticks > threshold_ticks) &&
(currticks <= threshold_ticks))
{
/* 00101; move the current bit forwards. */
if (prevticks <= (0x7f - amount_ticks))
prev += amount_ticks;
if (currticks >= (1 + amount_ticks))
currticks -= amount_ticks;
}
}
}
}
std::vector<std::unique_ptr<const Fluxmap>> Fluxmap::split() const
{
std::vector<std::unique_ptr<const Fluxmap>> maps;
@@ -108,24 +76,3 @@ std::vector<std::unique_ptr<const Fluxmap>> Fluxmap::split() const
return maps;
}
std::unique_ptr<const Fluxmap> Fluxmap::rescale(double scale) const
{
if (scale == 1.0)
return std::make_unique<Fluxmap>(rawBytes());
auto newFluxmap = std::make_unique<Fluxmap>();
int lastEvent = 0;
for (uint8_t b : _bytes)
{
lastEvent += b & 0x3f;
if (b & 0xc0)
{
newFluxmap->appendInterval(lastEvent * scale + 0.5);
newFluxmap->findLastByte() |= b & 0xc0;
lastEvent = 0;
}
}
return newFluxmap;
}

View File

@@ -64,9 +64,8 @@ public:
Fluxmap& appendBits(const std::vector<bool>& bits, nanoseconds_t clock);
void precompensate(int threshold_ticks, int amount_ticks);
std::unique_ptr<const Fluxmap> precompensate(int threshold_ticks, int amount_ticks);
std::vector<std::unique_ptr<const Fluxmap>> split() const;
std::unique_ptr<const Fluxmap> rescale(double scale) const;
private:
uint8_t& findLastByte();

View File

@@ -24,7 +24,6 @@ message Fl2FluxSinkProto {
}
message FluxSinkProto {
optional double rescale = 7 [ default = 1.0, (help) = "amount to multiply pulse periods by" ];
oneof dest {
HardwareFluxSinkProto drive = 2;
AuFluxSinkProto au = 3;

View File

@@ -16,22 +16,27 @@ public:
{
if (config.drive().has_hard_sector_count())
{
nanoseconds_t oneRevolution;
int retries = 5;
usbSetDrive(config.drive().drive(), config.drive().high_density(), config.drive().index_mode());
Logger() << BeginSpeedOperationLogMessage();
do {
oneRevolution = usbGetRotationalPeriod(config.drive().hard_sector_count());
_hardSectorThreshold = oneRevolution * 3 / (4 * config.drive().hard_sector_count());
retries--;
} while ((oneRevolution == 0) && (retries > 0));
nanoseconds_t oneRevolution = config.drive().rotational_period_ms() * 1e6;
if (oneRevolution == 0)
{
Logger() << BeginSpeedOperationLogMessage();
do {
oneRevolution = usbGetRotationalPeriod(config.drive().hard_sector_count());
_hardSectorThreshold = oneRevolution * 3 / (4 * config.drive().hard_sector_count());
retries--;
} while ((oneRevolution == 0) && (retries > 0));
config.mutable_drive()->set_rotational_period_ms(oneRevolution / 1e6);
Logger() << EndSpeedOperationLogMessage { oneRevolution };
}
if (oneRevolution == 0) {
Error() << "Failed\nIs a disk in the drive?";
}
Logger() << EndSpeedOperationLogMessage { oneRevolution };
}
else
_hardSectorThreshold = 0;

View File

@@ -31,7 +31,6 @@ message Fl2FluxSourceProto {
}
message FluxSourceProto {
optional double rescale = 9 [ default = 1.0, (help) = "amount to divide pulse periods by" ];
oneof source {
HardwareFluxSourceProto drive = 2;
TestPatternFluxSourceProto test_pattern = 3;

View File

@@ -54,18 +54,23 @@ public:
usbSetDrive(config.drive().drive(), config.drive().high_density(), config.drive().index_mode());
Logger() << BeginSpeedOperationLogMessage();
do
{
_oneRevolution =
usbGetRotationalPeriod(config.drive().hard_sector_count());
if (config.drive().hard_sector_count() != 0)
_hardSectorThreshold =
_oneRevolution * 3 / (4 * config.drive().hard_sector_count());
else
_hardSectorThreshold = 0;
_oneRevolution = config.drive().rotational_period_ms() * 1e6;
if (_oneRevolution == 0)
{
do
{
_oneRevolution =
usbGetRotationalPeriod(config.drive().hard_sector_count());
if (config.drive().hard_sector_count() != 0)
_hardSectorThreshold =
_oneRevolution * 3 / (4 * config.drive().hard_sector_count());
else
_hardSectorThreshold = 0;
retries--;
} while ((_oneRevolution == 0) && (retries > 0));
retries--;
} while ((_oneRevolution == 0) && (retries > 0));
config.mutable_drive()->set_rotational_period_ms(_oneRevolution / 1e6);
}
if (_oneRevolution == 0)
Error() << "Failed\nIs a disk in the drive?";

View File

@@ -97,8 +97,8 @@ public:
int trackMfm = -1;
auto trackdata = ibm->add_trackdata();
trackdata->set_clock_rate_khz(clockRate);
trackdata->set_track_length_ms(167);
trackdata->set_target_clock_period_us(1e3 / clockRate);
trackdata->set_target_rotational_period_ms(167);
auto sectors = trackdata->mutable_sectors();
for (int sectorInTrack = 0; sectorInTrack < currentSectorsInTrack;
@@ -193,8 +193,8 @@ public:
if (mediaFlag != 0x20)
{
auto trackdata = ibm->add_trackdata();
trackdata->set_clock_rate_khz(clockRate);
trackdata->set_track_length_ms(167);
trackdata->set_target_clock_period_us(1e3 / clockRate);
trackdata->set_target_rotational_period_ms(167);
}
}

View File

@@ -102,7 +102,7 @@ public:
{
auto ibm = config.mutable_encoder()->mutable_ibm();
auto trackdata = ibm->add_trackdata();
trackdata->set_clock_rate_khz(500);
trackdata->set_target_clock_period_us(2);
auto sectors = trackdata->mutable_sectors();
switch (mediaByte)
{
@@ -110,7 +110,7 @@ public:
Logger() << "DIM: automatically setting format to 1.2MB "
"(1024 byte sectors)";
config.mutable_tracks()->set_end(76);
trackdata->set_track_length_ms(167);
trackdata->set_target_rotational_period_ms(167);
trackdata->set_sector_size(1024);
for (int i = 0; i < 9; i++)
sectors->add_sector(i);
@@ -118,14 +118,14 @@ public:
case 0x02:
Logger() << "DIM: automatically setting format to 1.2MB "
"(512 byte sectors)";
trackdata->set_track_length_ms(167);
trackdata->set_target_rotational_period_ms(167);
trackdata->set_sector_size(512);
for (int i = 0; i < 15; i++)
sectors->add_sector(i);
break;
case 0x03:
Logger() << "DIM: automatically setting format to 1.44MB";
trackdata->set_track_length_ms(200);
trackdata->set_target_rotational_period_ms(200);
trackdata->set_sector_size(512);
for (int i = 0; i < 18; i++)
sectors->add_sector(i);

View File

@@ -82,7 +82,7 @@ public:
{
auto ibm = config.mutable_encoder()->mutable_ibm();
auto trackdata = ibm->add_trackdata();
trackdata->set_clock_rate_khz(500);
trackdata->set_target_clock_period_us(2);
auto sectors = trackdata->mutable_sectors();
switch (fddType)
{
@@ -90,14 +90,14 @@ public:
Logger() << "FDI: automatically setting format to 1.2MB "
"(1024 byte sectors)";
config.mutable_tracks()->set_end(76);
trackdata->set_track_length_ms(167);
trackdata->set_target_rotational_period_ms(167);
trackdata->set_sector_size(1024);
for (int i = 0; i < 9; i++)
sectors->add_sector(i);
break;
case 0x30:
Logger() << "FDI: automatically setting format to 1.44MB";
trackdata->set_track_length_ms(200);
trackdata->set_target_rotational_period_ms(200);
trackdata->set_sector_size(512);
for (int i = 0; i < 18; i++)
sectors->add_sector(i);

View File

@@ -65,8 +65,8 @@ public:
for (int track = 0; track < 163; track++)
{
auto trackdata = ibm->add_trackdata();
trackdata->set_clock_rate_khz(500);
trackdata->set_track_length_ms(167);
trackdata->set_target_clock_period_us(2);
trackdata->set_target_rotational_period_ms(167);
auto sectors = trackdata->mutable_sectors();
int currentTrackTrack = -1;
int currentTrackHead = -1;

View File

@@ -78,16 +78,27 @@ std::string Logger::toString(const AnyLogMessage& message)
[&](const TrackReadLogMessage& m)
{
const auto& track = *m.track;
const auto& trackdataflux = track.trackDatas.end()[-1];
std::set<std::shared_ptr<const Sector>> rawSectors;
std::set<std::shared_ptr<const Record>> rawRecords;
for (const auto& trackDataFlux : track.trackDatas)
{
rawSectors.insert(trackDataFlux->sectors.begin(), trackDataFlux->sectors.end());
rawRecords.insert(trackDataFlux->records.begin(), trackDataFlux->records.end());
}
nanoseconds_t clock = 0;
for (const auto& sector : rawSectors)
clock += sector->clock;
if (!rawSectors.empty())
clock /= rawSectors.size();
indent();
stream << fmt::format("{} raw records, {} raw sectors",
trackdataflux->records.size(),
trackdataflux->sectors.size());
if (trackdataflux->sectors.size() > 0)
rawRecords.size(),
rawSectors.size());
if (clock != 0)
{
nanoseconds_t clock =
(*trackdataflux->sectors.begin())->clock;
stream << fmt::format("; {:.2f}us clock ({:.0f}kHz)",
clock / 1000.0,
1000000.0 / clock);
@@ -104,7 +115,9 @@ std::string Logger::toString(const AnyLogMessage& message)
sectors.begin(), sectors.end(), sectorPointerSortPredicate);
for (const auto& sector : sectors)
stream << fmt::format(" {}{}",
stream << fmt::format(" {}.{}.{}{}",
sector->logicalTrack,
sector->logicalSide,
sector->logicalSector,
Sector::statusToChar(sector->status));
@@ -119,18 +132,6 @@ std::string Logger::toString(const AnyLogMessage& message)
size += sector->data.size();
}
if (!track_ids.empty())
{
std::vector<std::string> ids;
for (const auto& i : track_ids)
ids.push_back(fmt::format("{}.{}", i.first, i.second));
indent();
stream << fmt::format(
"logical track {}\n", fmt::join(ids, "; "));
}
indent();
stream << fmt::format("{} bytes decoded\n", size);
},

View File

@@ -107,14 +107,13 @@ std::unique_ptr<const Image> Mapper::remapSectorsLogicalToPhysical(
unsigned Mapper::remapTrackPhysicalToLogical(unsigned ptrack)
{
return (ptrack - config.drive().head_bias()) /
config.drive().head_width();
return (ptrack - config.drive().head_bias()) / config.drive().head_width();
}
static unsigned getTrackStep()
{
unsigned track_step =
(config.tpi() == 0) ? 1 : (config.drive().tpi() / config.tpi());
(config.tpi() == 0) ? 1 : (config.drive().tpi() / config.tpi());
if (track_step == 0)
Error()
@@ -124,7 +123,7 @@ static unsigned getTrackStep()
unsigned Mapper::remapTrackLogicalToPhysical(unsigned ltrack)
{
return config.drive().head_bias() + ltrack*getTrackStep();
return config.drive().head_bias() + ltrack * getTrackStep();
}
std::set<Location> Mapper::computeLocations()
@@ -136,7 +135,8 @@ std::set<Location> Mapper::computeLocations()
{
for (unsigned head : iterate(config.heads()))
{
unsigned physicalTrack = config.drive().head_bias() + logicalTrack * track_step;
unsigned physicalTrack =
config.drive().head_bias() + logicalTrack * track_step;
locations.insert({.physicalTrack = physicalTrack,
.logicalTrack = logicalTrack,
@@ -147,3 +147,15 @@ std::set<Location> Mapper::computeLocations()
return locations;
}
nanoseconds_t Mapper::calculatePhysicalClockPeriod(
nanoseconds_t targetClockPeriod, nanoseconds_t targetRotationalPeriod)
{
nanoseconds_t currentRotationalPeriod =
config.drive().rotational_period_ms() * 1e6;
if (currentRotationalPeriod == 0)
Error() << "you must set --drive.rotational_period_ms as it can't be "
"autodetected";
return targetClockPeriod * (currentRotationalPeriod / targetRotationalPeriod);
}

View File

@@ -16,7 +16,10 @@ public:
static unsigned remapTrackPhysicalToLogical(unsigned track);
static unsigned remapTrackLogicalToPhysical(unsigned track);
static std::set<Location> computeLocations();
static std::set<Location> computeLocations();
static nanoseconds_t calculatePhysicalClockPeriod(
nanoseconds_t targetClockPeriod, nanoseconds_t targetRotationalPeriod);
};
#endif

View File

@@ -153,9 +153,9 @@ ReadResult readGroup(FluxSourceIteratorHolder& fluxSourceIteratorHolder,
Logger() << BeginReadOperationLogMessage{
location.physicalTrack + offset, location.head};
std::shared_ptr<const Fluxmap> fluxmap =
fluxSourceIterator.next()->rescale(
1.0 / config.flux_source().rescale());
std::shared_ptr<const Fluxmap> fluxmap = fluxSourceIterator.next();
// ->rescale(
// 1.0 / config.flux_source().rescale());
Logger() << EndReadOperationLogMessage()
<< fmt::format("{0:.0} ms in {1} bytes",
fluxmap->duration() / 1e6,
@@ -186,8 +186,8 @@ void writeTracks(FluxSink& fluxSink,
int retriesRemaining = config.decoder().retries();
for (;;)
{
for (unsigned offset = 0; offset < location.groupSize;
offset += config.drive().head_width())
for (int offset = location.groupSize - 1; offset >= 0;
offset -= config.drive().head_width())
{
unsigned physicalTrack = location.physicalTrack + offset;
@@ -200,13 +200,7 @@ void writeTracks(FluxSink& fluxSink,
if (!fluxmap)
goto erase;
auto scaled =
fluxmap->rescale(config.flux_sink().rescale());
/* Precompensation actually seems to make things worse, so
* let's leave it disabled for now. */
// fluxmap->precompensate(PRECOMPENSATION_THRESHOLD_TICKS,
// 2);
fluxSink.writeFlux(physicalTrack, location.head, *scaled);
fluxSink.writeFlux(physicalTrack, location.head, *fluxmap);
Logger() << fmt::format("writing {0} ms in {1} bytes",
int(fluxmap->duration() / 1e6),
fluxmap->bytes());
@@ -273,9 +267,16 @@ void writeTracksAndVerify(FluxSink& fluxSink,
auto trackFlux = std::make_shared<TrackFlux>();
trackFlux->location = location;
FluxSourceIteratorHolder fluxSourceIteratorHolder(fluxSource);
readGroup(fluxSourceIteratorHolder, location, *trackFlux, decoder);
auto result = readGroup(
fluxSourceIteratorHolder, location, *trackFlux, decoder);
Logger() << TrackReadLogMessage{trackFlux};
if (result != GOOD_READ)
{
Logger() << "bad read";
return false;
}
auto wantedSectors = encoder.collectSectors(location, image);
std::sort(wantedSectors.begin(),
wantedSectors.end(),
@@ -287,11 +288,16 @@ void writeTracksAndVerify(FluxSink& fluxSink,
gotSectors.end(),
sectorPointerSortPredicate);
return std::equal(gotSectors.begin(),
gotSectors.end(),
wantedSectors.begin(),
wantedSectors.end(),
sectorPointerEqualsPredicate);
if (!std::equal(gotSectors.begin(),
gotSectors.end(),
wantedSectors.begin(),
wantedSectors.end(),
sectorPointerEqualsPredicate))
{
Logger() << "good read but the data doesn't match";
return false;
}
return true;
});
}
@@ -475,8 +481,7 @@ void rawReadDiskCommand(FluxSource& fluxsource, FluxSink& fluxsink)
auto fluxSourceIterator = fluxsource.readFlux(track, head);
Logger() << BeginReadOperationLogMessage{track, head};
auto fluxmap = fluxSourceIterator->next()->rescale(
1.0 / config.flux_source().rescale());
auto fluxmap = fluxSourceIterator->next();
Logger() << EndReadOperationLogMessage()
<< fmt::format("{0:.0} ms in {1} bytes",
fluxmap->duration() / 1e6,