mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-24 11:11:02 -07:00
292 lines
8.7 KiB
C++
292 lines
8.7 KiB
C++
#include "lib/core/globals.h"
|
|
#include "lib/config/config.h"
|
|
#include "lib/data/layout.h"
|
|
#include "lib/config/proto.h"
|
|
#include "lib/core/logger.h"
|
|
|
|
static unsigned getTrackStep()
|
|
{
|
|
auto format_type = globalConfig()->layout().format_type();
|
|
auto drive_type = globalConfig()->drive().drive_type();
|
|
|
|
switch (format_type)
|
|
{
|
|
case FORMATTYPE_40TRACK:
|
|
switch (drive_type)
|
|
{
|
|
case DRIVETYPE_40TRACK:
|
|
return 1;
|
|
|
|
case DRIVETYPE_80TRACK:
|
|
return 2;
|
|
|
|
case DRIVETYPE_APPLE2:
|
|
return 4;
|
|
}
|
|
|
|
case FORMATTYPE_80TRACK:
|
|
switch (drive_type)
|
|
{
|
|
case DRIVETYPE_40TRACK:
|
|
error(
|
|
"you can't read/write an 80 track image from/to a 40 "
|
|
"track "
|
|
"drive");
|
|
|
|
case DRIVETYPE_80TRACK:
|
|
return 1;
|
|
|
|
case DRIVETYPE_APPLE2:
|
|
error(
|
|
"you can't read/write an 80 track image from/to an "
|
|
"Apple II "
|
|
"drive");
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
unsigned Layout::remapTrackPhysicalToLogical(unsigned ptrack)
|
|
{
|
|
return (ptrack - globalConfig()->drive().head_bias()) / getTrackStep();
|
|
}
|
|
|
|
unsigned Layout::remapTrackLogicalToPhysical(unsigned ltrack)
|
|
{
|
|
return globalConfig()->drive().head_bias() + ltrack * getTrackStep();
|
|
}
|
|
|
|
unsigned Layout::remapSidePhysicalToLogical(unsigned pside)
|
|
{
|
|
return pside ^ globalConfig()->layout().swap_sides();
|
|
}
|
|
|
|
unsigned Layout::remapSideLogicalToPhysical(unsigned lside)
|
|
{
|
|
return lside ^ globalConfig()->layout().swap_sides();
|
|
}
|
|
|
|
std::vector<CylinderHead> Layout::computePhysicalLocations()
|
|
{
|
|
if (globalConfig()->has_tracks())
|
|
return parseCylinderHeadsString(globalConfig()->tracks());
|
|
|
|
std::set<unsigned> tracks = iterate(0, globalConfig()->layout().tracks());
|
|
std::set<unsigned> heads = iterate(0, globalConfig()->layout().sides());
|
|
|
|
std::vector<CylinderHead> locations;
|
|
for (unsigned logicalTrack : tracks)
|
|
for (unsigned logicalHead : heads)
|
|
locations.push_back(
|
|
CylinderHead{remapTrackLogicalToPhysical(logicalTrack),
|
|
remapSideLogicalToPhysical(logicalHead)});
|
|
|
|
return locations;
|
|
}
|
|
|
|
Layout::LayoutBounds Layout::getBounds(
|
|
const std::vector<CylinderHead>& locations)
|
|
{
|
|
LayoutBounds r{.minTrack = INT_MAX,
|
|
.maxTrack = INT_MIN,
|
|
.minSide = INT_MAX,
|
|
.maxSide = INT_MIN};
|
|
|
|
for (const auto& ti : locations)
|
|
{
|
|
r.minTrack = std::min<int>(r.minTrack, ti.cylinder);
|
|
r.maxTrack = std::max<int>(r.maxTrack, ti.cylinder);
|
|
r.minSide = std::min<int>(r.minSide, ti.head);
|
|
r.maxSide = std::max<int>(r.maxSide, ti.head);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
std::vector<std::pair<int, int>> Layout::getTrackOrdering(
|
|
LayoutProto::Order ordering, unsigned guessedTracks, unsigned guessedSides)
|
|
{
|
|
auto layout = globalConfig()->layout();
|
|
int tracks = layout.has_tracks() ? layout.tracks() : guessedTracks;
|
|
int sides = layout.has_sides() ? layout.sides() : guessedSides;
|
|
|
|
std::vector<std::pair<int, int>> trackList;
|
|
switch (ordering)
|
|
{
|
|
case LayoutProto::CHS:
|
|
{
|
|
for (int track = 0; track < tracks; track++)
|
|
{
|
|
for (int side = 0; side < sides; side++)
|
|
trackList.push_back(std::make_pair(track, side));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LayoutProto::HCS:
|
|
{
|
|
for (int side = 0; side < sides; side++)
|
|
{
|
|
for (int track = 0; track < tracks; track++)
|
|
trackList.push_back(std::make_pair(track, side));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case LayoutProto::HCS_RH1:
|
|
{
|
|
for (int side = 0; side < sides; side++)
|
|
{
|
|
if (side == 0)
|
|
for (int track = 0; track < tracks; track++)
|
|
trackList.push_back(std::make_pair(track, side));
|
|
if (side == 1)
|
|
for (int track = tracks; track >= 0; track--)
|
|
trackList.push_back(std::make_pair(track - 1, side));
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
error("LAYOUT: invalid track trackList");
|
|
}
|
|
|
|
return trackList;
|
|
}
|
|
|
|
std::vector<unsigned> Layout::expandSectorList(
|
|
const SectorListProto& sectorsProto)
|
|
{
|
|
std::vector<unsigned> sectors;
|
|
|
|
if (sectorsProto.has_count())
|
|
{
|
|
if (sectorsProto.sector_size() != 0)
|
|
error(
|
|
"LAYOUT: if you use a sector count, you can't use an "
|
|
"explicit sector list");
|
|
|
|
std::set<unsigned> sectorset;
|
|
int id = sectorsProto.start_sector();
|
|
for (int i = 0; i < sectorsProto.count(); i++)
|
|
{
|
|
while (sectorset.find(id) != sectorset.end())
|
|
{
|
|
id++;
|
|
if (id >= (sectorsProto.start_sector() + sectorsProto.count()))
|
|
id -= sectorsProto.count();
|
|
}
|
|
|
|
sectorset.insert(id);
|
|
sectors.push_back(id);
|
|
|
|
id += sectorsProto.skew();
|
|
if (id >= (sectorsProto.start_sector() + sectorsProto.count()))
|
|
id -= sectorsProto.count();
|
|
}
|
|
}
|
|
else if (sectorsProto.sector_size() > 0)
|
|
{
|
|
for (int sectorId : sectorsProto.sector())
|
|
sectors.push_back(sectorId);
|
|
}
|
|
else
|
|
error("LAYOUT: no sectors in sector definition!");
|
|
|
|
return sectors;
|
|
}
|
|
|
|
std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrack(
|
|
unsigned logicalTrack, unsigned logicalSide)
|
|
{
|
|
auto trackInfo = std::make_shared<TrackInfo>();
|
|
|
|
LayoutProto::LayoutdataProto layoutdata;
|
|
for (const auto& f : globalConfig()->layout().layoutdata())
|
|
{
|
|
if (f.has_track() && f.has_up_to_track() &&
|
|
((logicalTrack < f.track()) || (logicalTrack > f.up_to_track())))
|
|
continue;
|
|
if (f.has_track() && !f.has_up_to_track() &&
|
|
(logicalTrack != f.track()))
|
|
continue;
|
|
if (f.has_side() && (f.side() != logicalSide))
|
|
continue;
|
|
|
|
layoutdata.MergeFrom(f);
|
|
}
|
|
|
|
trackInfo->numTracks = globalConfig()->layout().tracks();
|
|
trackInfo->numSides = globalConfig()->layout().sides();
|
|
trackInfo->sectorSize = layoutdata.sector_size();
|
|
trackInfo->logicalTrack = logicalTrack;
|
|
trackInfo->logicalSide = logicalSide;
|
|
trackInfo->physicalTrack = remapTrackLogicalToPhysical(logicalTrack);
|
|
trackInfo->physicalSide =
|
|
logicalSide ^ globalConfig()->layout().swap_sides();
|
|
trackInfo->groupSize = getTrackStep();
|
|
trackInfo->diskSectorOrder = expandSectorList(layoutdata.physical());
|
|
trackInfo->naturalSectorOrder = trackInfo->diskSectorOrder;
|
|
std::sort(trackInfo->naturalSectorOrder.begin(),
|
|
trackInfo->naturalSectorOrder.end());
|
|
trackInfo->numSectors = trackInfo->naturalSectorOrder.size();
|
|
|
|
if (layoutdata.has_filesystem())
|
|
{
|
|
trackInfo->filesystemSectorOrder =
|
|
expandSectorList(layoutdata.filesystem());
|
|
if (trackInfo->filesystemSectorOrder.size() != trackInfo->numSectors)
|
|
error(
|
|
"filesystem sector order list doesn't contain the right "
|
|
"number of sectors");
|
|
}
|
|
else
|
|
trackInfo->filesystemSectorOrder = trackInfo->naturalSectorOrder;
|
|
|
|
for (int i = 0; i < trackInfo->numSectors; i++)
|
|
{
|
|
unsigned fid = trackInfo->naturalSectorOrder[i];
|
|
unsigned lid = trackInfo->filesystemSectorOrder[i];
|
|
trackInfo->filesystemToNaturalSectorMap[fid] = lid;
|
|
trackInfo->naturalToFilesystemSectorMap[lid] = fid;
|
|
}
|
|
|
|
return trackInfo;
|
|
}
|
|
|
|
std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrackPhysical(
|
|
unsigned physicalTrack, unsigned physicalSide)
|
|
{
|
|
return getLayoutOfTrack(remapTrackPhysicalToLogical(physicalTrack),
|
|
remapSidePhysicalToLogical(physicalSide));
|
|
}
|
|
|
|
std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrackPhysical(
|
|
const CylinderHead& physicalLocation)
|
|
{
|
|
return getLayoutOfTrackPhysical(
|
|
physicalLocation.cylinder, physicalLocation.head);
|
|
}
|
|
|
|
std::vector<std::shared_ptr<const TrackInfo>> Layout::getLayoutOfTracksPhysical(
|
|
const std::vector<CylinderHead>& physicalLocations)
|
|
{
|
|
std::vector<std::shared_ptr<const TrackInfo>> results;
|
|
for (const auto& physicalLocation : physicalLocations)
|
|
results.push_back(getLayoutOfTrackPhysical(physicalLocation));
|
|
return results;
|
|
}
|
|
|
|
int Layout::getHeadWidth()
|
|
{
|
|
switch (globalConfig()->drive().drive_type())
|
|
{
|
|
case DRIVETYPE_APPLE2:
|
|
return 4;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|