mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Massive overhaul of how the physical/logical layout mapping is done, to make it
more consistent and bidirectional everywhere and just generally better. Hopefully this fixes that pesky 1581 problem.
This commit is contained in:
@@ -32,200 +32,204 @@
|
||||
|
||||
std::unique_ptr<Decoder> Decoder::create(const DecoderProto& config)
|
||||
{
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Decoder>(const DecoderProto&)>> decoders =
|
||||
{
|
||||
{ DecoderProto::kAgat, createAgatDecoder },
|
||||
{ DecoderProto::kAeslanier, createAesLanierDecoder },
|
||||
{ DecoderProto::kAmiga, createAmigaDecoder },
|
||||
{ DecoderProto::kApple2, createApple2Decoder },
|
||||
{ DecoderProto::kBrother, createBrotherDecoder },
|
||||
{ DecoderProto::kC64, createCommodore64Decoder },
|
||||
{ DecoderProto::kF85, createDurangoF85Decoder },
|
||||
{ DecoderProto::kFb100, createFb100Decoder },
|
||||
{ DecoderProto::kIbm, createIbmDecoder },
|
||||
{ DecoderProto::kMacintosh, createMacintoshDecoder },
|
||||
{ DecoderProto::kMicropolis, createMicropolisDecoder },
|
||||
{ DecoderProto::kMx, createMxDecoder },
|
||||
{ DecoderProto::kNorthstar, createNorthstarDecoder },
|
||||
{ DecoderProto::kTids990, createTids990Decoder },
|
||||
{ DecoderProto::kVictor9K, createVictor9kDecoder },
|
||||
{ DecoderProto::kZilogmcz, createZilogMczDecoder },
|
||||
};
|
||||
static const std::map<int,
|
||||
std::function<std::unique_ptr<Decoder>(const DecoderProto&)>>
|
||||
decoders = {
|
||||
{DecoderProto::kAgat, createAgatDecoder },
|
||||
{DecoderProto::kAeslanier, createAesLanierDecoder },
|
||||
{DecoderProto::kAmiga, createAmigaDecoder },
|
||||
{DecoderProto::kApple2, createApple2Decoder },
|
||||
{DecoderProto::kBrother, createBrotherDecoder },
|
||||
{DecoderProto::kC64, createCommodore64Decoder},
|
||||
{DecoderProto::kF85, createDurangoF85Decoder },
|
||||
{DecoderProto::kFb100, createFb100Decoder },
|
||||
{DecoderProto::kIbm, createIbmDecoder },
|
||||
{DecoderProto::kMacintosh, createMacintoshDecoder },
|
||||
{DecoderProto::kMicropolis, createMicropolisDecoder },
|
||||
{DecoderProto::kMx, createMxDecoder },
|
||||
{DecoderProto::kNorthstar, createNorthstarDecoder },
|
||||
{DecoderProto::kTids990, createTids990Decoder },
|
||||
{DecoderProto::kVictor9K, createVictor9kDecoder },
|
||||
{DecoderProto::kZilogmcz, createZilogMczDecoder },
|
||||
};
|
||||
|
||||
auto decoder = decoders.find(config.format_case());
|
||||
if (decoder == decoders.end())
|
||||
Error() << "no decoder specified";
|
||||
auto decoder = decoders.find(config.format_case());
|
||||
if (decoder == decoders.end())
|
||||
Error() << "no decoder specified";
|
||||
|
||||
return (decoder->second)(config);
|
||||
return (decoder->second)(config);
|
||||
}
|
||||
|
||||
std::shared_ptr<const TrackDataFlux> Decoder::decodeToSectors(
|
||||
std::shared_ptr<const Fluxmap> fluxmap, const Location& location)
|
||||
std::shared_ptr<const Fluxmap> fluxmap, const Location& location)
|
||||
{
|
||||
_trackdata = std::make_shared<TrackDataFlux>();
|
||||
_trackdata->fluxmap = fluxmap;
|
||||
_trackdata->location = location;
|
||||
|
||||
_trackdata = std::make_shared<TrackDataFlux>();
|
||||
_trackdata->fluxmap = fluxmap;
|
||||
_trackdata->location = location;
|
||||
|
||||
FluxmapReader fmr(*fluxmap);
|
||||
_fmr = &fmr;
|
||||
|
||||
auto newSector = [&] {
|
||||
_sector = std::make_shared<Sector>();
|
||||
_sector->status = Sector::MISSING;
|
||||
_sector->logicalTrack = location.logicalTrack;
|
||||
_sector->logicalSide = location.head;
|
||||
_sector->physicalTrack = location.physicalTrack;
|
||||
_sector->physicalHead = location.head;
|
||||
};
|
||||
auto newSector = [&]
|
||||
{
|
||||
_sector = std::make_shared<Sector>(location);
|
||||
_sector->status = Sector::MISSING;
|
||||
};
|
||||
|
||||
newSector();
|
||||
newSector();
|
||||
beginTrack();
|
||||
for (;;)
|
||||
{
|
||||
newSector();
|
||||
newSector();
|
||||
|
||||
Fluxmap::Position recordStart = fmr.tell();
|
||||
_sector->clock = advanceToNextRecord();
|
||||
if (fmr.eof() || !_sector->clock)
|
||||
if (fmr.eof() || !_sector->clock)
|
||||
return _trackdata;
|
||||
|
||||
/* Read the sector record. */
|
||||
|
||||
Fluxmap::Position before = fmr.tell();
|
||||
Fluxmap::Position before = fmr.tell();
|
||||
decodeSectorRecord();
|
||||
Fluxmap::Position after = fmr.tell();
|
||||
pushRecord(before, after);
|
||||
Fluxmap::Position after = fmr.tell();
|
||||
pushRecord(before, after);
|
||||
|
||||
if (_sector->status != Sector::DATA_MISSING)
|
||||
{
|
||||
_sector->position = before.bytes;
|
||||
_sector->dataStartTime = before.ns();
|
||||
_sector->dataEndTime = after.ns();
|
||||
}
|
||||
else
|
||||
{
|
||||
_sector->position = before.bytes;
|
||||
_sector->dataStartTime = before.ns();
|
||||
_sector->dataEndTime = after.ns();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The data is in a separate record. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
_sector->headerStartTime = before.ns();
|
||||
_sector->headerEndTime = after.ns();
|
||||
for (;;)
|
||||
{
|
||||
_sector->headerStartTime = before.ns();
|
||||
_sector->headerEndTime = after.ns();
|
||||
|
||||
_sector->clock = advanceToNextRecord();
|
||||
if (fmr.eof() || !_sector->clock)
|
||||
break;
|
||||
_sector->clock = advanceToNextRecord();
|
||||
if (fmr.eof() || !_sector->clock)
|
||||
break;
|
||||
|
||||
before = fmr.tell();
|
||||
decodeDataRecord();
|
||||
after = fmr.tell();
|
||||
before = fmr.tell();
|
||||
decodeDataRecord();
|
||||
after = fmr.tell();
|
||||
|
||||
if (_sector->status != Sector::DATA_MISSING)
|
||||
{
|
||||
_sector->position = before.bytes;
|
||||
_sector->dataStartTime = before.ns();
|
||||
_sector->dataEndTime = after.ns();
|
||||
pushRecord(before, after);
|
||||
break;
|
||||
}
|
||||
if (_sector->status != Sector::DATA_MISSING)
|
||||
{
|
||||
_sector->position = before.bytes;
|
||||
_sector->dataStartTime = before.ns();
|
||||
_sector->dataEndTime = after.ns();
|
||||
pushRecord(before, after);
|
||||
break;
|
||||
}
|
||||
|
||||
fmr.skipToEvent(F_BIT_PULSE);
|
||||
resetFluxDecoder();
|
||||
}
|
||||
fmr.skipToEvent(F_BIT_PULSE);
|
||||
resetFluxDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
if (_sector->status != Sector::MISSING)
|
||||
{
|
||||
auto& trackLayout = Layout::getLayoutOfTrack(_sector->logicalTrack, _sector->logicalSide);
|
||||
_trackdata->sectors.push_back(_sector);
|
||||
auto& trackLayout = Layout::getLayoutOfTrack(
|
||||
_sector->logicalTrack, _sector->logicalSide);
|
||||
_trackdata->sectors.push_back(_sector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Decoder::pushRecord(const Fluxmap::Position& start, const Fluxmap::Position& end)
|
||||
void Decoder::pushRecord(
|
||||
const Fluxmap::Position& start, const Fluxmap::Position& end)
|
||||
{
|
||||
Fluxmap::Position here = _fmr->tell();
|
||||
|
||||
auto record = std::make_shared<Record>();
|
||||
_trackdata->records.push_back(record);
|
||||
_sector->records.push_back(record);
|
||||
|
||||
record->startTime = start.ns();
|
||||
record->endTime = end.ns();
|
||||
auto record = std::make_shared<Record>();
|
||||
_trackdata->records.push_back(record);
|
||||
_sector->records.push_back(record);
|
||||
|
||||
record->startTime = start.ns();
|
||||
record->endTime = end.ns();
|
||||
record->clock = _sector->clock;
|
||||
|
||||
record->rawData = toBytes(_recordBits);
|
||||
_recordBits.clear();
|
||||
record->rawData = toBytes(_recordBits);
|
||||
_recordBits.clear();
|
||||
}
|
||||
|
||||
void Decoder::resetFluxDecoder()
|
||||
{
|
||||
_decoder.reset(new FluxDecoder(_fmr, _sector->clock, _config));
|
||||
_decoder.reset(new FluxDecoder(_fmr, _sector->clock, _config));
|
||||
}
|
||||
|
||||
nanoseconds_t Decoder::seekToPattern(const FluxMatcher& pattern)
|
||||
{
|
||||
nanoseconds_t clock = _fmr->seekToPattern(pattern);
|
||||
_decoder.reset(new FluxDecoder(_fmr, clock, _config));
|
||||
return clock;
|
||||
nanoseconds_t clock = _fmr->seekToPattern(pattern);
|
||||
_decoder.reset(new FluxDecoder(_fmr, clock, _config));
|
||||
return clock;
|
||||
}
|
||||
|
||||
void Decoder::seekToIndexMark()
|
||||
{
|
||||
_fmr->skipToEvent(F_BIT_PULSE);
|
||||
_fmr->seekToIndexMark();
|
||||
_fmr->skipToEvent(F_BIT_PULSE);
|
||||
_fmr->seekToIndexMark();
|
||||
}
|
||||
|
||||
std::vector<bool> Decoder::readRawBits(unsigned count)
|
||||
{
|
||||
auto bits = _decoder->readBits(count);
|
||||
_recordBits.insert(_recordBits.end(), bits.begin(), bits.end());
|
||||
return bits;
|
||||
auto bits = _decoder->readBits(count);
|
||||
_recordBits.insert(_recordBits.end(), bits.begin(), bits.end());
|
||||
return bits;
|
||||
}
|
||||
|
||||
uint8_t Decoder::readRaw8()
|
||||
{
|
||||
return toBytes(readRawBits(8)).reader().read_8();
|
||||
return toBytes(readRawBits(8)).reader().read_8();
|
||||
}
|
||||
|
||||
uint16_t Decoder::readRaw16()
|
||||
{
|
||||
return toBytes(readRawBits(16)).reader().read_be16();
|
||||
return toBytes(readRawBits(16)).reader().read_be16();
|
||||
}
|
||||
|
||||
uint32_t Decoder::readRaw20()
|
||||
{
|
||||
std::vector<bool> bits(4);
|
||||
for (bool b : readRawBits(20))
|
||||
bits.push_back(b);
|
||||
std::vector<bool> bits(4);
|
||||
for (bool b : readRawBits(20))
|
||||
bits.push_back(b);
|
||||
|
||||
return toBytes(bits).reader().read_be24();
|
||||
return toBytes(bits).reader().read_be24();
|
||||
}
|
||||
|
||||
uint32_t Decoder::readRaw24()
|
||||
{
|
||||
return toBytes(readRawBits(24)).reader().read_be24();
|
||||
return toBytes(readRawBits(24)).reader().read_be24();
|
||||
}
|
||||
|
||||
uint32_t Decoder::readRaw32()
|
||||
{
|
||||
return toBytes(readRawBits(32)).reader().read_be32();
|
||||
return toBytes(readRawBits(32)).reader().read_be32();
|
||||
}
|
||||
|
||||
uint64_t Decoder::readRaw48()
|
||||
{
|
||||
return toBytes(readRawBits(48)).reader().read_be48();
|
||||
return toBytes(readRawBits(48)).reader().read_be48();
|
||||
}
|
||||
|
||||
uint64_t Decoder::readRaw64()
|
||||
{
|
||||
return toBytes(readRawBits(64)).reader().read_be64();
|
||||
return toBytes(readRawBits(64)).reader().read_be64();
|
||||
}
|
||||
|
||||
|
||||
std::set<unsigned> Decoder::requiredSectors(const Location& location) const
|
||||
std::set<LogicalLocation> Decoder::requiredSectors(
|
||||
const Location& location) const
|
||||
{
|
||||
const auto& trackLayout = Layout::getLayoutOfTrack(location.logicalTrack, location.head);
|
||||
return std::set(trackLayout.logicalSectorOrder.begin(), trackLayout.logicalSectorOrder.end());
|
||||
}
|
||||
const auto& trackLayout =
|
||||
Layout::getLayoutOfTrackPhysical(location.physicalTrack, location.physicalSide);
|
||||
|
||||
std::set<LogicalLocation> results;
|
||||
for (unsigned sectorId : trackLayout.logicalSectorOrder)
|
||||
results.insert(LogicalLocation{
|
||||
trackLayout.logicalTrack, trackLayout.logicalSide, sectorId});
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
return _fmr->getDuration();
|
||||
}
|
||||
|
||||
virtual std::set<unsigned> requiredSectors(const Location& location) const;
|
||||
virtual std::set<LogicalLocation> requiredSectors(const Location& location) const;
|
||||
|
||||
protected:
|
||||
virtual void beginTrack(){};
|
||||
|
||||
@@ -59,7 +59,7 @@ nanoseconds_t Encoder::calculatePhysicalClockPeriod(
|
||||
std::shared_ptr<const Sector> Encoder::getSector(
|
||||
const Location& location, const Image& image, unsigned sectorId)
|
||||
{
|
||||
return image.get(location.logicalTrack, location.head, sectorId);
|
||||
return image.get(location.logicalTrack, location.logicalSide, sectorId);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const Sector>> Encoder::collectSectors(
|
||||
@@ -68,14 +68,14 @@ std::vector<std::shared_ptr<const Sector>> Encoder::collectSectors(
|
||||
std::vector<std::shared_ptr<const Sector>> sectors;
|
||||
|
||||
const auto& trackLayout =
|
||||
Layout::getLayoutOfTrack(location.logicalTrack, location.head);
|
||||
Layout::getLayoutOfTrack(location.logicalTrack, location.logicalSide);
|
||||
for (unsigned sectorId : trackLayout.diskSectorOrder)
|
||||
{
|
||||
const auto& sector = getSector(location, image, sectorId);
|
||||
if (!sector)
|
||||
Error() << fmt::format("sector {}.{}.{} is missing from the image",
|
||||
location.logicalTrack,
|
||||
location.head,
|
||||
location.logicalSide,
|
||||
sectorId);
|
||||
sectors.push_back(sector);
|
||||
}
|
||||
|
||||
19
lib/flux.h
19
lib/flux.h
@@ -18,24 +18,25 @@ struct Record
|
||||
struct Location
|
||||
{
|
||||
unsigned physicalTrack;
|
||||
unsigned physicalSide;
|
||||
unsigned logicalTrack;
|
||||
unsigned head;
|
||||
unsigned logicalSide;
|
||||
unsigned groupSize;
|
||||
|
||||
bool operator==(const Location& other) const
|
||||
{
|
||||
if (physicalTrack == other.physicalTrack)
|
||||
return true;
|
||||
return head == other.head;
|
||||
return key() == other.key();
|
||||
}
|
||||
|
||||
bool operator<(const Location& other) const
|
||||
{
|
||||
if (physicalTrack < other.physicalTrack)
|
||||
return true;
|
||||
if (physicalTrack == other.physicalTrack)
|
||||
return head < other.head;
|
||||
return false;
|
||||
return key() < other.key();
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<unsigned, unsigned> key() const
|
||||
{
|
||||
return std::make_tuple(physicalTrack, physicalSide);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
std::unique_ptr<FluxSourceIterator> readFlux(int track, int head) override
|
||||
std::unique_ptr<FluxSourceIterator> readFlux(int physicalTrack, int physicalSide) override
|
||||
{
|
||||
for (const auto& trackFlux : _flux.tracks)
|
||||
{
|
||||
if ((trackFlux->location.physicalTrack == track) && (trackFlux->location.head == head))
|
||||
if ((trackFlux->location.physicalTrack == physicalTrack) && (trackFlux->location.physicalSide == physicalSide))
|
||||
return std::make_unique<MemoryFluxSourceIterator>(*trackFlux);
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ std::shared_ptr<Sector> Image::put(
|
||||
sector->logicalSide = side;
|
||||
sector->logicalSector = sectorid;
|
||||
sector->physicalTrack = Layout::remapTrackLogicalToPhysical(track);
|
||||
sector->physicalHead = side;
|
||||
sector->physicalSide = side;
|
||||
_sectors[key] = sector;
|
||||
return sector;
|
||||
}
|
||||
|
||||
@@ -384,14 +384,14 @@ public:
|
||||
if (blnOptionalHeadMap) //there was een optional head map. write it to the sector
|
||||
//The Sector Head Map has one entry for each sector, and contains the logical Head ID for the corresponding sector in the Sector Numbering Map.
|
||||
{
|
||||
sector->physicalHead = header.Head;
|
||||
sector->physicalSide = header.Head;
|
||||
sector->logicalSide = optionalhead_map[s];
|
||||
blnOptionalHeadMap = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
sector->logicalSide = header.Head;
|
||||
sector->physicalHead = header.Head;
|
||||
sector->physicalSide = header.Head;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public:
|
||||
break;
|
||||
|
||||
uint8_t physicalTrack = br.read_8();
|
||||
uint8_t physicalHead = br.read_8() & 1;
|
||||
uint8_t physicalSide = br.read_8() & 1;
|
||||
br.skip(1); /* crc */
|
||||
|
||||
for (int i = 0; i < sectorCount; i++)
|
||||
@@ -186,7 +186,7 @@ public:
|
||||
image->put(logicalTrack, logicalSide, sectorId);
|
||||
sector->status = Sector::OK;
|
||||
sector->physicalTrack = physicalTrack;
|
||||
sector->physicalHead = physicalHead;
|
||||
sector->physicalSide = physicalSide;
|
||||
sector->data = data.slice(0, sectorSize);
|
||||
totalSize += sectorSize;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ void ImageWriter::writeCsv(const Image& image, const std::string& filename)
|
||||
{
|
||||
f << fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{}\n",
|
||||
sector->physicalTrack,
|
||||
sector->physicalHead,
|
||||
sector->physicalSide,
|
||||
sector->logicalSector,
|
||||
sector->logicalTrack,
|
||||
sector->logicalSide,
|
||||
|
||||
@@ -266,7 +266,7 @@ public:
|
||||
{
|
||||
blnOptionalCylinderMap = true;
|
||||
}
|
||||
if (sector->logicalSide != sector->physicalHead) //different physicalside fromn logicalside
|
||||
if (sector->logicalSide != sector->physicalSide) //different physicalside fromn logicalside
|
||||
{
|
||||
blnOptionalHeadMap = true;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
static Local<std::map<std::pair<int, int>, std::unique_ptr<Layout>>>
|
||||
layoutCache;
|
||||
|
||||
unsigned Layout::remapTrackPhysicalToLogical(unsigned ptrack)
|
||||
{
|
||||
return (ptrack - config.drive().head_bias()) / config.drive().head_width();
|
||||
}
|
||||
|
||||
static unsigned getTrackStep()
|
||||
{
|
||||
unsigned track_step =
|
||||
@@ -23,15 +18,28 @@ static unsigned getTrackStep()
|
||||
return track_step;
|
||||
}
|
||||
|
||||
unsigned Layout::remapTrackPhysicalToLogical(unsigned ptrack)
|
||||
{
|
||||
return (ptrack - config.drive().head_bias()) / getTrackStep();
|
||||
}
|
||||
|
||||
unsigned Layout::remapTrackLogicalToPhysical(unsigned ltrack)
|
||||
{
|
||||
return config.drive().head_bias() + ltrack * getTrackStep();
|
||||
}
|
||||
|
||||
unsigned Layout::remapSidePhysicalToLogical(unsigned pside)
|
||||
{
|
||||
return pside ^ config.layout().swap_sides();
|
||||
}
|
||||
|
||||
unsigned Layout::remapSideLogicalToPhysical(unsigned lside)
|
||||
{
|
||||
return lside ^ config.layout().swap_sides();
|
||||
}
|
||||
|
||||
std::set<Location> Layout::computeLocations()
|
||||
{
|
||||
std::set<Location> locations;
|
||||
|
||||
std::set<unsigned> tracks;
|
||||
if (config.has_tracks())
|
||||
tracks = iterate(config.tracks());
|
||||
@@ -44,32 +52,29 @@ std::set<Location> Layout::computeLocations()
|
||||
else
|
||||
heads = iterate(0, config.layout().sides());
|
||||
|
||||
std::set<Location> locations;
|
||||
for (unsigned logicalTrack : tracks)
|
||||
{
|
||||
for (unsigned head : heads)
|
||||
locations.insert(computeLocationFor(logicalTrack, head));
|
||||
for (unsigned logicalHead : heads)
|
||||
locations.insert(computeLocationFor(logicalTrack, logicalHead));
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
Location Layout::computeLocationFor(unsigned logicalTrack, unsigned logicalHead)
|
||||
Location Layout::computeLocationFor(unsigned logicalTrack, unsigned logicalSide)
|
||||
{
|
||||
if ((logicalTrack < config.layout().tracks()) &&
|
||||
(logicalHead < config.layout().sides()))
|
||||
(logicalSide < config.layout().sides()))
|
||||
{
|
||||
unsigned track_step = getTrackStep();
|
||||
unsigned physicalTrack =
|
||||
config.drive().head_bias() + logicalTrack * track_step;
|
||||
|
||||
return {.physicalTrack = physicalTrack,
|
||||
return Location {.physicalTrack = remapTrackLogicalToPhysical(logicalTrack),
|
||||
.physicalSide = remapSideLogicalToPhysical(logicalSide),
|
||||
.logicalTrack = logicalTrack,
|
||||
.head = logicalHead,
|
||||
.groupSize = track_step};
|
||||
.logicalSide = logicalSide,
|
||||
.groupSize = getTrackStep()};
|
||||
}
|
||||
|
||||
Error() << fmt::format(
|
||||
"track {}.{} is not part of the image", logicalTrack, logicalHead);
|
||||
"track {}.{} is not part of the image", logicalTrack, logicalSide);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> Layout::getTrackOrdering(
|
||||
@@ -131,14 +136,15 @@ std::vector<unsigned> Layout::expandSectorList(
|
||||
sectors.push_back(sectorId);
|
||||
}
|
||||
else
|
||||
Error() << "LAYOUT: no sectors in track!";
|
||||
Error() << "LAYOUT: no sectors in sector definition!";
|
||||
|
||||
return sectors;
|
||||
}
|
||||
|
||||
const Layout& Layout::getLayoutOfTrack(unsigned track, unsigned side)
|
||||
const Layout& Layout::getLayoutOfTrack(
|
||||
unsigned logicalTrack, unsigned logicalSide)
|
||||
{
|
||||
auto& layout = (*layoutCache)[std::make_pair(track, side)];
|
||||
auto& layout = (*layoutCache)[std::make_pair(logicalTrack, logicalSide)];
|
||||
if (!layout)
|
||||
{
|
||||
layout.reset(new Layout());
|
||||
@@ -147,11 +153,13 @@ const Layout& Layout::getLayoutOfTrack(unsigned track, unsigned side)
|
||||
for (const auto& f : config.layout().layoutdata())
|
||||
{
|
||||
if (f.has_track() && f.has_up_to_track() &&
|
||||
((track < f.track()) || (track > f.up_to_track())))
|
||||
((logicalTrack < f.track()) ||
|
||||
(logicalTrack > f.up_to_track())))
|
||||
continue;
|
||||
if (f.has_track() && !f.has_up_to_track() && (track != f.track()))
|
||||
if (f.has_track() && !f.has_up_to_track() &&
|
||||
(logicalTrack != f.track()))
|
||||
continue;
|
||||
if (f.has_side() && (f.side() != side))
|
||||
if (f.has_side() && (f.side() != logicalSide))
|
||||
continue;
|
||||
|
||||
layoutdata.MergeFrom(f);
|
||||
@@ -160,6 +168,11 @@ const Layout& Layout::getLayoutOfTrack(unsigned track, unsigned side)
|
||||
layout->numTracks = config.layout().tracks();
|
||||
layout->numSides = config.layout().sides();
|
||||
layout->sectorSize = layoutdata.sector_size();
|
||||
layout->logicalTrack = logicalTrack;
|
||||
layout->logicalSide = logicalSide;
|
||||
layout->physicalTrack = remapTrackLogicalToPhysical(logicalTrack);
|
||||
layout->physicalSide = logicalSide ^ config.layout().swap_sides();
|
||||
layout->groupSize = getTrackStep();
|
||||
layout->diskSectorOrder = expandSectorList(layoutdata.physical());
|
||||
layout->logicalSectorOrder = layout->diskSectorOrder;
|
||||
std::sort(
|
||||
@@ -192,3 +205,10 @@ const Layout& Layout::getLayoutOfTrack(unsigned track, unsigned side)
|
||||
|
||||
return *layout;
|
||||
}
|
||||
|
||||
const Layout& Layout::getLayoutOfTrackPhysical(
|
||||
unsigned physicalTrack, unsigned physicalSide)
|
||||
{
|
||||
return getLayoutOfTrack(remapTrackPhysicalToLogical(physicalTrack),
|
||||
remapSidePhysicalToLogical(physicalSide));
|
||||
}
|
||||
|
||||
36
lib/layout.h
36
lib/layout.h
@@ -16,13 +16,19 @@ private:
|
||||
Layout& operator=(const Layout&);
|
||||
|
||||
public:
|
||||
/* Translates logical track numbering (filesystem numbering) to
|
||||
* the track numbering on the actual drive, taking into account tpi
|
||||
* settings.
|
||||
/* Translates logical track numbering (the numbers actually written in the
|
||||
* sector headers) to the track numbering on the actual drive, taking into
|
||||
* account tpi settings.
|
||||
*/
|
||||
static unsigned remapTrackPhysicalToLogical(unsigned physicalTrack);
|
||||
static unsigned remapTrackLogicalToPhysical(unsigned logicalTrack);
|
||||
|
||||
/* Translates logical side numbering (the numbers actually written in the
|
||||
* sector headers) to the sides used on the actual drive.
|
||||
*/
|
||||
static unsigned remapSidePhysicalToLogical(unsigned physicalSide);
|
||||
static unsigned remapSideLogicalToPhysical(unsigned logicalSide);
|
||||
|
||||
/* Computes a Location for a given logical track and side, which
|
||||
* contains the physical drive location and group size. */
|
||||
static Location computeLocationFor(
|
||||
@@ -42,6 +48,10 @@ public:
|
||||
static const Layout& getLayoutOfTrack(
|
||||
unsigned logicalTrack, unsigned logicalHead);
|
||||
|
||||
/* Returns the layout of a given track via physical location. */
|
||||
static const Layout& getLayoutOfTrackPhysical(
|
||||
unsigned physicalTrack, unsigned physicalSide);
|
||||
|
||||
/* Expand a SectorList into the actual sector IDs. */
|
||||
static std::vector<unsigned> expandSectorList(
|
||||
const SectorListProto& sectorsProto);
|
||||
@@ -49,7 +59,27 @@ public:
|
||||
public:
|
||||
unsigned numTracks;
|
||||
unsigned numSides;
|
||||
|
||||
/* The number of sectors in this track. */
|
||||
unsigned numSectors;
|
||||
|
||||
/* Physical location of this track. */
|
||||
unsigned physicalTrack;
|
||||
|
||||
/* Physical side of this track. */
|
||||
unsigned physicalSide;
|
||||
|
||||
/* Logical location of this track. */
|
||||
unsigned logicalTrack;
|
||||
|
||||
/* Logical side of this track. */
|
||||
unsigned logicalSide;
|
||||
|
||||
/* The number of physical tracks which need to be written for one logical
|
||||
* track. */
|
||||
unsigned groupSize;
|
||||
|
||||
/* Number of bytes in a sector. */
|
||||
unsigned sectorSize;
|
||||
|
||||
/* Sector IDs in disk order. */
|
||||
|
||||
@@ -28,11 +28,11 @@ message LayoutProto
|
||||
message LayoutdataProto
|
||||
{
|
||||
optional int32 track = 1
|
||||
[ (help) = "if present, this format only applies to this track" ];
|
||||
[ (help) = "if present, this format only applies to this logical track" ];
|
||||
optional int32 up_to_track = 5
|
||||
[ (help) = "if present, forms a range with track" ];
|
||||
optional int32 side = 2
|
||||
[ (help) = "if present, this format only applies to this side" ];
|
||||
[ (help) = "if present, this format only applies to this logical side" ];
|
||||
|
||||
optional int32 sector_size = 3
|
||||
[ default = 512, (help) = "number of bytes per sector" ];
|
||||
@@ -51,4 +51,6 @@ message LayoutProto
|
||||
[ default = 0, (help) = "number of sides in image" ];
|
||||
optional Order order = 4
|
||||
[ default = CHS, (help) = "the order of sectors in the filesystem" ];
|
||||
optional bool swap_sides = 5
|
||||
[ default = false, (help) = "the sides are inverted on this disk" ];
|
||||
}
|
||||
|
||||
@@ -163,10 +163,9 @@ BadSectorsState combineRecordAndSectors(
|
||||
track_sectors.insert(
|
||||
trackdataflux->sectors.begin(), trackdataflux->sectors.end());
|
||||
|
||||
for (unsigned logical_sector : decoder.requiredSectors(trackFlux.location))
|
||||
for (auto& logicalLocation : decoder.requiredSectors(trackFlux.location))
|
||||
{
|
||||
auto sector = std::make_shared<Sector>(location);
|
||||
sector->logicalSector = logical_sector;
|
||||
auto sector = std::make_shared<Sector>(logicalLocation);
|
||||
sector->status = Sector::MISSING;
|
||||
track_sectors.insert(sector);
|
||||
}
|
||||
@@ -192,12 +191,12 @@ ReadResult readGroup(FluxSourceIteratorHolder& fluxSourceIteratorHolder,
|
||||
offset += config.drive().head_width())
|
||||
{
|
||||
auto& fluxSourceIterator = fluxSourceIteratorHolder.getIterator(
|
||||
location.physicalTrack + offset, location.head);
|
||||
location.physicalTrack + offset, location.physicalSide);
|
||||
if (!fluxSourceIterator.hasNext())
|
||||
continue;
|
||||
|
||||
Logger() << BeginReadOperationLogMessage{
|
||||
location.physicalTrack + offset, location.head};
|
||||
location.physicalTrack + offset, location.physicalSide};
|
||||
std::shared_ptr<const Fluxmap> fluxmap = fluxSourceIterator.next();
|
||||
// ->rescale(
|
||||
// 1.0 / config.flux_source().rescale());
|
||||
@@ -248,7 +247,7 @@ void writeTracks(FluxSink& fluxSink,
|
||||
unsigned physicalTrack = location.physicalTrack + offset;
|
||||
|
||||
Logger() << BeginWriteOperationLogMessage{
|
||||
physicalTrack, location.head};
|
||||
physicalTrack, location.physicalSide};
|
||||
|
||||
if (offset == config.drive().group_offset())
|
||||
{
|
||||
@@ -256,7 +255,8 @@ void writeTracks(FluxSink& fluxSink,
|
||||
if (!fluxmap)
|
||||
goto erase;
|
||||
|
||||
fluxSink.writeFlux(physicalTrack, location.head, *fluxmap);
|
||||
fluxSink.writeFlux(
|
||||
physicalTrack, location.physicalSide, *fluxmap);
|
||||
Logger() << fmt::format("writing {0} ms in {1} bytes",
|
||||
int(fluxmap->duration() / 1e6),
|
||||
fluxmap->bytes());
|
||||
@@ -267,7 +267,8 @@ void writeTracks(FluxSink& fluxSink,
|
||||
/* Erase this track rather than writing. */
|
||||
|
||||
Fluxmap blank;
|
||||
fluxSink.writeFlux(physicalTrack, location.head, blank);
|
||||
fluxSink.writeFlux(
|
||||
physicalTrack, location.physicalSide, blank);
|
||||
Logger() << "erased";
|
||||
}
|
||||
|
||||
@@ -301,7 +302,10 @@ void writeTracks(FluxSink& fluxSink,
|
||||
auto sectors = encoder.collectSectors(location, image);
|
||||
return encoder.encode(location, sectors, image);
|
||||
},
|
||||
[](const auto&) { return true; },
|
||||
[](const auto&)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
locations);
|
||||
}
|
||||
|
||||
@@ -401,10 +405,14 @@ void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink)
|
||||
fluxSink,
|
||||
[&](const Location& location)
|
||||
{
|
||||
return fluxSource.readFlux(location.physicalTrack, location.head)
|
||||
return fluxSource
|
||||
.readFlux(location.physicalTrack, location.physicalSide)
|
||||
->next();
|
||||
},
|
||||
[](const auto&){return true;},
|
||||
[](const auto&)
|
||||
{
|
||||
return true;
|
||||
},
|
||||
Layout::computeLocations());
|
||||
}
|
||||
|
||||
@@ -468,8 +476,9 @@ std::shared_ptr<const DiskFlux> readDiskCommand(
|
||||
if (outputFluxSink)
|
||||
{
|
||||
for (const auto& data : trackFlux->trackDatas)
|
||||
outputFluxSink->writeFlux(
|
||||
location.physicalTrack, location.head, *data->fluxmap);
|
||||
outputFluxSink->writeFlux(location.physicalTrack,
|
||||
location.physicalSide,
|
||||
*data->fluxmap);
|
||||
}
|
||||
|
||||
if (config.decoder().dump_records())
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
#include "globals.h"
|
||||
#include "flux.h"
|
||||
#include "sector.h"
|
||||
#include "layout.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
Sector::Sector(const LogicalLocation& location):
|
||||
LogicalLocation(location),
|
||||
physicalTrack(Layout::remapTrackLogicalToPhysical(location.logicalTrack)),
|
||||
physicalSide(Layout::remapSideLogicalToPhysical(location.logicalSide))
|
||||
{}
|
||||
|
||||
Sector::Sector(const Location& location):
|
||||
LogicalLocation({ location.logicalTrack, location.logicalSide, 0 }),
|
||||
physicalTrack(location.physicalTrack),
|
||||
physicalHead(location.head),
|
||||
logicalTrack(location.logicalTrack),
|
||||
logicalSide(location.head)
|
||||
physicalSide(location.physicalSide)
|
||||
{}
|
||||
|
||||
std::string Sector::statusToString(Status status)
|
||||
|
||||
45
lib/sector.h
45
lib/sector.h
@@ -7,14 +7,36 @@
|
||||
class Record;
|
||||
class Location;
|
||||
|
||||
/*
|
||||
* Note that sectors here used zero-based numbering throughout (to make the
|
||||
* maths easier); traditionally floppy disk use 0-based track numbering and
|
||||
* 1-based sector numbering, which makes no sense.
|
||||
*/
|
||||
class Sector
|
||||
struct LogicalLocation
|
||||
{
|
||||
unsigned logicalTrack;
|
||||
unsigned logicalSide;
|
||||
unsigned logicalSector;
|
||||
|
||||
std::tuple<int, int, int> key() const
|
||||
{
|
||||
return std::make_tuple(
|
||||
logicalTrack, logicalSide, logicalSector);
|
||||
}
|
||||
|
||||
bool operator==(const LogicalLocation& rhs) const
|
||||
{
|
||||
return key() == rhs.key();
|
||||
}
|
||||
|
||||
bool operator!=(const LogicalLocation& rhs) const
|
||||
{
|
||||
return key() != rhs.key();
|
||||
}
|
||||
|
||||
bool operator<(const LogicalLocation& rhs) const
|
||||
{
|
||||
return key() < rhs.key();
|
||||
}
|
||||
};
|
||||
|
||||
struct Sector : public LogicalLocation
|
||||
{
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
OK,
|
||||
@@ -30,22 +52,21 @@ public:
|
||||
static Status stringToStatus(const std::string& value);
|
||||
|
||||
Status status = Status::INTERNAL_ERROR;
|
||||
uint32_t position;
|
||||
uint32_t position = 0;
|
||||
nanoseconds_t clock = 0;
|
||||
nanoseconds_t headerStartTime = 0;
|
||||
nanoseconds_t headerEndTime = 0;
|
||||
nanoseconds_t dataStartTime = 0;
|
||||
nanoseconds_t dataEndTime = 0;
|
||||
unsigned physicalTrack = 0;
|
||||
unsigned physicalHead = 0;
|
||||
unsigned logicalTrack = 0;
|
||||
unsigned logicalSide = 0;
|
||||
unsigned logicalSector = 0;
|
||||
unsigned physicalSide = 0;
|
||||
Bytes data;
|
||||
std::vector<std::shared_ptr<Record>> records;
|
||||
|
||||
Sector() {}
|
||||
|
||||
Sector(const LogicalLocation& location);
|
||||
|
||||
Sector(const Location& location);
|
||||
|
||||
std::tuple<int, int, int, Status> key() const
|
||||
|
||||
Reference in New Issue
Block a user