mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Another massive overhaul to rip out the last remaining bits of Layout.
This commit is contained in:
		| @@ -107,7 +107,8 @@ public: | |||||||
|                 Sector::DATA_MISSING; /* unintuitive but correct */ |                 Sector::DATA_MISSING; /* unintuitive but correct */ | ||||||
|  |  | ||||||
|         if (_sector->logicalHead == 1) |         if (_sector->logicalHead == 1) | ||||||
|             _sector->logicalCylinder -= _config.apple2().side_one_track_offset(); |             _sector->logicalCylinder -= | ||||||
|  |                 _config.apple2().side_one_track_offset(); | ||||||
|  |  | ||||||
|         /* Sanity check. */ |         /* Sanity check. */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -207,16 +207,14 @@ public: | |||||||
|         _sector->status = |         _sector->status = | ||||||
|             (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM; |             (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||||
|  |  | ||||||
|         auto layout = Layout::getLayoutOfTrack( |         if (_currentSectorSize != _ltl->sectorSize) | ||||||
|             _sector->logicalCylinder, _sector->logicalHead); |  | ||||||
|         if (_currentSectorSize != layout->sectorSize) |  | ||||||
|             std::cerr << fmt::format( |             std::cerr << fmt::format( | ||||||
|                 "Warning: configured sector size for t{}.h{}.s{} is {} bytes " |                 "Warning: configured sector size for t{}.h{}.s{} is {} bytes " | ||||||
|                 "but that seen on disk is {} bytes\n", |                 "but that seen on disk is {} bytes\n", | ||||||
|                 _sector->logicalCylinder, |                 _sector->logicalCylinder, | ||||||
|                 _sector->logicalHead, |                 _sector->logicalHead, | ||||||
|                 _sector->logicalSector, |                 _sector->logicalSector, | ||||||
|                 layout->sectorSize, |                 _ltl->sectorSize, | ||||||
|                 _currentSectorSize); |                 _currentSectorSize); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -359,7 +359,7 @@ static ReadGroupResult readGroup(const DiskLayout& diskLayout, | |||||||
|     ReadGroupResult rgr = {BAD_AND_CAN_NOT_RETRY}; |     ReadGroupResult rgr = {BAD_AND_CAN_NOT_RETRY}; | ||||||
|  |  | ||||||
|     for (unsigned offset = 0; offset < ltl->groupSize; |     for (unsigned offset = 0; offset < ltl->groupSize; | ||||||
|         offset += Layout::getHeadWidth()) |         offset += diskLayout.headWidth) | ||||||
|     { |     { | ||||||
|         unsigned physicalCylinder = ltl->physicalCylinder + offset; |         unsigned physicalCylinder = ltl->physicalCylinder + offset; | ||||||
|         unsigned physicalHead = ltl->physicalHead; |         unsigned physicalHead = ltl->physicalHead; | ||||||
| @@ -578,7 +578,6 @@ void writeDiskCommand(const DiskLayout& diskLayout, | |||||||
| { | { | ||||||
|     auto chs = std::ranges::views::keys(diskLayout.layoutByLogicalLocation) | |     auto chs = std::ranges::views::keys(diskLayout.layoutByLogicalLocation) | | ||||||
|                std::ranges::to<std::vector>(); |                std::ranges::to<std::vector>(); | ||||||
|     auto trackinfos = Layout::getLayoutOfTracksPhysical(physicalLocations); |  | ||||||
|     if (fluxSource && decoder) |     if (fluxSource && decoder) | ||||||
|         writeTracksAndVerify( |         writeTracksAndVerify( | ||||||
|             diskLayout, fluxSink, encoder, *fluxSource, *decoder, image, chs); |             diskLayout, fluxSink, encoder, *fluxSource, *decoder, image, chs); | ||||||
|   | |||||||
| @@ -22,21 +22,6 @@ void Image::clear() | |||||||
|     _geometry = {0, 0, 0}; |     _geometry = {0, 0, 0}; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Image::createBlankImage() |  | ||||||
| { |  | ||||||
|     clear(); |  | ||||||
|     for (const auto& trackAndHead : Layout::getTrackOrdering( |  | ||||||
|              globalConfig()->layout().filesystem_track_order())) |  | ||||||
|     { |  | ||||||
|         unsigned track = trackAndHead.first; |  | ||||||
|         unsigned side = trackAndHead.second; |  | ||||||
|         auto trackLayout = Layout::getLayoutOfTrack(track, side); |  | ||||||
|         Bytes blank(trackLayout->sectorSize); |  | ||||||
|         for (unsigned sectorId : trackLayout->naturalSectorOrder) |  | ||||||
|             put(track, side, sectorId)->data = blank; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool Image::empty() const | bool Image::empty() const | ||||||
| { | { | ||||||
|     return _sectors.empty(); |     return _sectors.empty(); | ||||||
| @@ -67,7 +52,7 @@ void Image::erase(const LogicalLocation& location) | |||||||
|     _sectors.erase(location); |     _sectors.erase(location); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Image::addMissingSectors(const DiskLayout& diskLayout) | void Image::addMissingSectors(const DiskLayout& diskLayout, bool populated) | ||||||
| { | { | ||||||
|     for (auto& location : diskLayout.logicalSectorLocationsInFilesystemOrder) |     for (auto& location : diskLayout.logicalSectorLocationsInFilesystemOrder) | ||||||
|         if (!_sectors.contains(location)) |         if (!_sectors.contains(location)) | ||||||
| @@ -75,7 +60,12 @@ void Image::addMissingSectors(const DiskLayout& diskLayout) | |||||||
|             auto& ltl = diskLayout.layoutByLogicalLocation.at( |             auto& ltl = diskLayout.layoutByLogicalLocation.at( | ||||||
|                 {location.logicalCylinder, location.logicalHead}); |                 {location.logicalCylinder, location.logicalHead}); | ||||||
|             auto sector = std::make_shared<Sector>(location); |             auto sector = std::make_shared<Sector>(location); | ||||||
|             sector->status = Sector::MISSING; |  | ||||||
|  |             if (populated) | ||||||
|  |                 sector->data = Bytes(ltl->sectorSize); | ||||||
|  |             else | ||||||
|  |                 sector->status = Sector::MISSING; | ||||||
|  |  | ||||||
|             _sectors[location] = sector; |             _sectors[location] = sector; | ||||||
|         } |         } | ||||||
|     calculateSize(); |     calculateSize(); | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ public: | |||||||
|         erase({cylinder, head, sector}); |         erase({cylinder, head, sector}); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void addMissingSectors(const DiskLayout& layout); |     void addMissingSectors(const DiskLayout& layout, bool populated = false); | ||||||
|  |  | ||||||
|     const_iterator begin() const |     const_iterator begin() const | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -56,88 +56,10 @@ static unsigned getTrackStep(const ConfigProto& config = globalConfig()) | |||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| unsigned Layout::remapCylinderPhysicalToLogical(unsigned ptrack) | static std::vector<CylinderHead> getTrackOrdering( | ||||||
|  |     LayoutProto::Order ordering, unsigned tracks, unsigned sides) | ||||||
| { | { | ||||||
|     return (ptrack - globalConfig()->drive().head_bias()) / getTrackStep(); |     std::vector<CylinderHead> trackList; | ||||||
| } |  | ||||||
|  |  | ||||||
| unsigned Layout::remapCylinderLogicalToPhysical(unsigned ltrack) |  | ||||||
| { |  | ||||||
|     return globalConfig()->drive().head_bias() + ltrack * getTrackStep(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| unsigned Layout::remapHeadPhysicalToLogical(unsigned pside) |  | ||||||
| { |  | ||||||
|     return pside ^ globalConfig()->layout().swap_sides(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| unsigned Layout::remapHeadLogicalToPhysical(unsigned lside) |  | ||||||
| { |  | ||||||
|     return lside ^ globalConfig()->layout().swap_sides(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<CylinderHead> Layout::computePhysicalLocations() |  | ||||||
| { |  | ||||||
|     if (!globalConfig()->tracks().empty()) |  | ||||||
|         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 logicalCylinder : tracks) |  | ||||||
|         for (unsigned logicalHead : heads) |  | ||||||
|             locations.push_back( |  | ||||||
|                 CylinderHead{remapCylinderLogicalToPhysical(logicalCylinder), |  | ||||||
|                     remapHeadLogicalToPhysical(logicalHead)}); |  | ||||||
|  |  | ||||||
|     return locations; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<CylinderHead> Layout::computeLogicalLocations() |  | ||||||
| { |  | ||||||
|     if (!globalConfig()->tracks().empty()) |  | ||||||
|         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 logicalCylinder : tracks) |  | ||||||
|         for (unsigned logicalHead : heads) |  | ||||||
|             locations.push_back(CylinderHead{logicalCylinder, logicalHead}); |  | ||||||
|  |  | ||||||
|     return locations; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Layout::LayoutBounds Layout::getBounds( |  | ||||||
|     const std::vector<CylinderHead>& locations) |  | ||||||
| { |  | ||||||
|     LayoutBounds r{.minCylinder = INT_MAX, |  | ||||||
|         .maxCylinder = INT_MIN, |  | ||||||
|         .minHead = INT_MAX, |  | ||||||
|         .maxHead = INT_MIN}; |  | ||||||
|  |  | ||||||
|     for (const auto& ti : locations) |  | ||||||
|     { |  | ||||||
|         r.minCylinder = std::min<int>(r.minCylinder, ti.cylinder); |  | ||||||
|         r.maxCylinder = std::max<int>(r.maxCylinder, ti.cylinder); |  | ||||||
|         r.minHead = std::min<int>(r.minHead, ti.head); |  | ||||||
|         r.maxHead = std::max<int>(r.maxHead, ti.head); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return r; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( |  | ||||||
|     const ConfigProto& config, |  | ||||||
|     LayoutProto::Order ordering, |  | ||||||
|     unsigned tracks, |  | ||||||
|     unsigned sides) |  | ||||||
| { |  | ||||||
|     auto layout = config.layout(); |  | ||||||
|  |  | ||||||
|     std::vector<std::pair<unsigned, unsigned>> trackList; |  | ||||||
|     switch (ordering) |     switch (ordering) | ||||||
|     { |     { | ||||||
|         case LayoutProto::CHS: |         case LayoutProto::CHS: | ||||||
| @@ -145,7 +67,7 @@ std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( | |||||||
|             for (unsigned track = 0; track < tracks; track++) |             for (unsigned track = 0; track < tracks; track++) | ||||||
|             { |             { | ||||||
|                 for (unsigned side = 0; side < sides; side++) |                 for (unsigned side = 0; side < sides; side++) | ||||||
|                     trackList.push_back(std::make_pair(track, side)); |                     trackList.push_back({track, side}); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -155,7 +77,7 @@ std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( | |||||||
|             for (unsigned side = 0; side < sides; side++) |             for (unsigned side = 0; side < sides; side++) | ||||||
|             { |             { | ||||||
|                 for (unsigned track = 0; track < tracks; track++) |                 for (unsigned track = 0; track < tracks; track++) | ||||||
|                     trackList.push_back(std::make_pair(track, side)); |                     trackList.push_back({track, side}); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -166,10 +88,10 @@ std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( | |||||||
|             { |             { | ||||||
|                 if (side == 0) |                 if (side == 0) | ||||||
|                     for (unsigned track = 0; track < tracks; track++) |                     for (unsigned track = 0; track < tracks; track++) | ||||||
|                         trackList.push_back(std::make_pair(track, side)); |                         trackList.push_back({track, side}); | ||||||
|                 if (side == 1) |                 if (side == 1) | ||||||
|                     for (unsigned track = tracks; track >= 0; track--) |                     for (unsigned track = tracks; track >= 0; track--) | ||||||
|                         trackList.push_back(std::make_pair(track - 1, side)); |                         trackList.push_back({track - 1, side}); | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| @@ -181,19 +103,7 @@ std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( | |||||||
|     return trackList; |     return trackList; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<std::pair<unsigned, unsigned>> Layout::getTrackOrdering( | static std::vector<unsigned> expandSectorList( | ||||||
|     LayoutProto::Order ordering, |  | ||||||
|     unsigned guessedCylinders, |  | ||||||
|     unsigned guessedHeads) |  | ||||||
| { |  | ||||||
|     auto& layout = globalConfig()->layout(); |  | ||||||
|     return ::getTrackOrdering(globalConfig(), |  | ||||||
|         ordering, |  | ||||||
|         layout.has_tracks() ? layout.tracks() : guessedCylinders, |  | ||||||
|         layout.has_sides() ? layout.sides() : guessedHeads); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<unsigned> Layout::expandSectorList( |  | ||||||
|     const SectorListProto& sectorsProto) |     const SectorListProto& sectorsProto) | ||||||
| { | { | ||||||
|     std::vector<unsigned> sectors; |     std::vector<unsigned> sectors; | ||||||
| @@ -239,7 +149,7 @@ static const LayoutProto::LayoutdataProto getLayoutData( | |||||||
|     unsigned logicalCylinder, unsigned logicalHead, const ConfigProto& config) |     unsigned logicalCylinder, unsigned logicalHead, const ConfigProto& config) | ||||||
| { | { | ||||||
|     LayoutProto::LayoutdataProto layoutData; |     LayoutProto::LayoutdataProto layoutData; | ||||||
|     for (const auto& f : globalConfig()->layout().layoutdata()) |     for (const auto& f : config.layout().layoutdata()) | ||||||
|     { |     { | ||||||
|         if (f.has_track() && f.has_up_to_track() && |         if (f.has_track() && f.has_up_to_track() && | ||||||
|             ((logicalCylinder < f.track()) || |             ((logicalCylinder < f.track()) || | ||||||
| @@ -256,113 +166,6 @@ static const LayoutProto::LayoutdataProto getLayoutData( | |||||||
|     return layoutData; |     return layoutData; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::shared_ptr<const TrackInfo> Layout::getLayoutOfTrack( |  | ||||||
|     unsigned logicalCylinder, unsigned logicalHead) |  | ||||||
| { |  | ||||||
|     auto trackInfo = std::make_shared<TrackInfo>(); |  | ||||||
|  |  | ||||||
|     auto layoutdata = |  | ||||||
|         getLayoutData(logicalCylinder, logicalHead, globalConfig()); |  | ||||||
|     trackInfo->numCylinders = globalConfig()->layout().tracks(); |  | ||||||
|     trackInfo->numHeads = globalConfig()->layout().sides(); |  | ||||||
|     trackInfo->sectorSize = layoutdata.sector_size(); |  | ||||||
|     trackInfo->logicalCylinder = logicalCylinder; |  | ||||||
|     trackInfo->logicalHead = logicalHead; |  | ||||||
|     trackInfo->physicalCylinder = |  | ||||||
|         remapCylinderLogicalToPhysical(logicalCylinder); |  | ||||||
|     trackInfo->physicalHead = |  | ||||||
|         logicalHead ^ 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 physicalCylinder, unsigned physicalHead) |  | ||||||
| { |  | ||||||
|     return getLayoutOfTrack(remapCylinderPhysicalToLogical(physicalCylinder), |  | ||||||
|         remapHeadPhysicalToLogical(physicalHead)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| 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; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| std::vector<LogicalLocation> Layout::computeFilesystemLogicalOrdering() |  | ||||||
| { |  | ||||||
|     std::vector<LogicalLocation> result; |  | ||||||
|     auto& layout = globalConfig()->layout(); |  | ||||||
|     if (layout.has_tracks() && layout.has_sides()) |  | ||||||
|     { |  | ||||||
|         unsigned block = 0; |  | ||||||
|         for (const auto& p : |  | ||||||
|             Layout::getTrackOrdering(layout.filesystem_track_order(), |  | ||||||
|                 layout.tracks(), |  | ||||||
|                 layout.sides())) |  | ||||||
|         { |  | ||||||
|             unsigned track = p.first; |  | ||||||
|             unsigned side = p.second; |  | ||||||
|  |  | ||||||
|             auto trackLayout = Layout::getLayoutOfTrack(track, side); |  | ||||||
|             if (trackLayout->numSectors == 0) |  | ||||||
|                 continue; |  | ||||||
|  |  | ||||||
|             for (unsigned sectorId : trackLayout->filesystemSectorOrder) |  | ||||||
|                 result.push_back({track, side, sectorId}); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| DiskLayout::DiskLayout(const ConfigProto& config) | DiskLayout::DiskLayout(const ConfigProto& config) | ||||||
| { | { | ||||||
|     minPhysicalCylinder = minPhysicalHead = UINT_MAX; |     minPhysicalCylinder = minPhysicalHead = UINT_MAX; | ||||||
| @@ -375,7 +178,7 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|     headBias = config.drive().head_bias(); |     headBias = config.drive().head_bias(); | ||||||
|     swapSides = config.layout().swap_sides(); |     swapSides = config.layout().swap_sides(); | ||||||
|  |  | ||||||
|     switch (globalConfig()->drive().drive_type()) |     switch (config.drive().drive_type()) | ||||||
|     { |     { | ||||||
|         case DRIVETYPE_APPLE2: |         case DRIVETYPE_APPLE2: | ||||||
|             headWidth = 4; |             headWidth = 4; | ||||||
| @@ -411,10 +214,9 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|             maxPhysicalHead = std::max(maxPhysicalHead, ltl->physicalHead); |             maxPhysicalHead = std::max(maxPhysicalHead, ltl->physicalHead); | ||||||
|  |  | ||||||
|             auto layoutdata = |             auto layoutdata = | ||||||
|                 getLayoutData(logicalCylinder, logicalHead, globalConfig()); |                 getLayoutData(logicalCylinder, logicalHead, config); | ||||||
|             ltl->sectorSize = layoutdata.sector_size(); |             ltl->sectorSize = layoutdata.sector_size(); | ||||||
|             ltl->diskSectorOrder = |             ltl->diskSectorOrder = expandSectorList(layoutdata.physical()); | ||||||
|                 Layout::expandSectorList(layoutdata.physical()); |  | ||||||
|             ltl->naturalSectorOrder = ltl->diskSectorOrder; |             ltl->naturalSectorOrder = ltl->diskSectorOrder; | ||||||
|             std::sort( |             std::sort( | ||||||
|                 ltl->naturalSectorOrder.begin(), ltl->naturalSectorOrder.end()); |                 ltl->naturalSectorOrder.begin(), ltl->naturalSectorOrder.end()); | ||||||
| @@ -423,7 +225,7 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|             if (layoutdata.has_filesystem()) |             if (layoutdata.has_filesystem()) | ||||||
|             { |             { | ||||||
|                 ltl->filesystemSectorOrder = |                 ltl->filesystemSectorOrder = | ||||||
|                     Layout::expandSectorList(layoutdata.filesystem()); |                     expandSectorList(layoutdata.filesystem()); | ||||||
|                 if (ltl->filesystemSectorOrder.size() != ltl->numSectors) |                 if (ltl->filesystemSectorOrder.size() != ltl->numSectors) | ||||||
|                     error( |                     error( | ||||||
|                         "filesystem sector order list doesn't contain the " |                         "filesystem sector order list doesn't contain the " | ||||||
| @@ -436,8 +238,8 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|             { |             { | ||||||
|                 unsigned fid = ltl->naturalSectorOrder[i]; |                 unsigned fid = ltl->naturalSectorOrder[i]; | ||||||
|                 unsigned lid = ltl->filesystemSectorOrder[i]; |                 unsigned lid = ltl->filesystemSectorOrder[i]; | ||||||
|                 ltl->filesystemToNaturalSectorMap[fid] = lid; |                 ltl->sectorIdToNaturalOrdering[i] = fid; | ||||||
|                 ltl->naturalToFilesystemSectorMap[lid] = fid; |                 ltl->sectorIdToFilesystemOrdering[i] = fid; | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -449,7 +251,9 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|             physicalHead++) |             physicalHead++) | ||||||
|         { |         { | ||||||
|             auto ptl = std::make_shared<PhysicalTrackLayout>(); |             auto ptl = std::make_shared<PhysicalTrackLayout>(); | ||||||
|             layoutByPhysicalLocation[{physicalCylinder, physicalHead}] = ptl; |             CylinderHead ch(physicalCylinder, physicalHead); | ||||||
|  |             layoutByPhysicalLocation[ch] = ptl; | ||||||
|  |             physicalLocations.push_back(ch); | ||||||
|  |  | ||||||
|             ptl->physicalCylinder = physicalCylinder; |             ptl->physicalCylinder = physicalCylinder; | ||||||
|             ptl->physicalHead = physicalHead; |             ptl->physicalHead = physicalHead; | ||||||
| @@ -464,31 +268,54 @@ DiskLayout::DiskLayout(const ConfigProto& config) | |||||||
|  |  | ||||||
|     unsigned sectorOffset = 0; |     unsigned sectorOffset = 0; | ||||||
|     unsigned blockId = 0; |     unsigned blockId = 0; | ||||||
|     for (auto [logicalCylinder, logicalHead] : getTrackOrdering(config, |     for (auto& ch : getTrackOrdering(config.layout().filesystem_track_order(), | ||||||
|              config.layout().filesystem_track_order(), |  | ||||||
|              numLogicalCylinders, |              numLogicalCylinders, | ||||||
|              numLogicalHeads)) |              numLogicalHeads)) | ||||||
|     { |     { | ||||||
|         const auto& ltl = |         const auto& ltl = layoutByLogicalLocation[ch]; | ||||||
|             layoutByLogicalLocation[{logicalCylinder, logicalHead}]; |         logicalLocationsInFilesystemOrder.push_back(ch); | ||||||
|  |  | ||||||
|         for (unsigned lid : ltl->filesystemSectorOrder) |         for (unsigned lid : ltl->filesystemSectorOrder) | ||||||
|         { |         { | ||||||
|             LogicalLocation logicalLocation = { |             LogicalLocation logicalLocation = {ch.cylinder, ch.head, lid}; | ||||||
|                 logicalCylinder, logicalHead, lid}; |             logicalSectorLocationBySectorOffset[sectorOffset] = logicalLocation; | ||||||
|             logicalLocationBySectorOffset[sectorOffset] = logicalLocation; |             sectorOffsetByLogicalSectorLocation[logicalLocation] = sectorOffset; | ||||||
|             sectorOffsetByLogicalLocation[logicalLocation] = sectorOffset; |             logicalSectorLocationsInFilesystemOrder.push_back(logicalLocation); | ||||||
|             sectorOffset += ltl->sectorSize; |             sectorOffset += ltl->sectorSize; | ||||||
|  |  | ||||||
|             logicalLocationByBlockId[blockId] = logicalLocation; |             blockIdByLogicalSectorLocation[logicalLocation] = blockId; | ||||||
|             blockIdByLogicalLocation[logicalLocation] = blockId; |  | ||||||
|             blockId++; |             blockId++; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| static Layout::LayoutBounds getBounds(std::ranges::view auto keys) | static ConfigProto createTestConfig(unsigned numCylinders, | ||||||
|  |     unsigned numHeads, | ||||||
|  |     unsigned numSectors, | ||||||
|  |     unsigned sectorSize) | ||||||
| { | { | ||||||
|     Layout::LayoutBounds r{.minCylinder = INT_MAX, |     ConfigProto config; | ||||||
|  |     auto* layout = config.mutable_layout(); | ||||||
|  |     layout->set_tracks(numCylinders); | ||||||
|  |     layout->set_sides(numHeads); | ||||||
|  |     auto* layoutData = layout->add_layoutdata(); | ||||||
|  |     layoutData->set_sector_size(sectorSize); | ||||||
|  |     layoutData->mutable_physical()->set_count(numSectors); | ||||||
|  |  | ||||||
|  |     return config; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | DiskLayout::DiskLayout(unsigned numCylinders, | ||||||
|  |     unsigned numHeads, | ||||||
|  |     unsigned numSectors, | ||||||
|  |     unsigned sectorSize): | ||||||
|  |     DiskLayout(createTestConfig(numCylinders, numHeads, numSectors, sectorSize)) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static DiskLayout::LayoutBounds getBounds(std::ranges::view auto keys) | ||||||
|  | { | ||||||
|  |     DiskLayout::LayoutBounds r{.minCylinder = INT_MAX, | ||||||
|         .maxCylinder = INT_MIN, |         .maxCylinder = INT_MIN, | ||||||
|         .minHead = INT_MAX, |         .minHead = INT_MAX, | ||||||
|         .maxHead = INT_MIN}; |         .maxHead = INT_MIN}; | ||||||
| @@ -504,12 +331,12 @@ static Layout::LayoutBounds getBounds(std::ranges::view auto keys) | |||||||
|     return r; |     return r; | ||||||
| } | } | ||||||
|  |  | ||||||
| Layout::LayoutBounds DiskLayout::getPhysicalBounds() const | DiskLayout::LayoutBounds DiskLayout::getPhysicalBounds() const | ||||||
| { | { | ||||||
|     return getBounds(std::views::keys(layoutByPhysicalLocation)); |     return getBounds(std::views::keys(layoutByPhysicalLocation)); | ||||||
| } | } | ||||||
|  |  | ||||||
| Layout::LayoutBounds DiskLayout::getLogicalBounds() const | DiskLayout::LayoutBounds DiskLayout::getLogicalBounds() const | ||||||
| { | { | ||||||
|     return getBounds(std::views::keys(layoutByLogicalLocation)); |     return getBounds(std::views::keys(layoutByLogicalLocation)); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,76 +7,6 @@ | |||||||
| #include "lib/data/locations.h" | #include "lib/data/locations.h" | ||||||
|  |  | ||||||
| class ConfigProto; | class ConfigProto; | ||||||
| class SectorListProto; |  | ||||||
| class TrackInfo; |  | ||||||
|  |  | ||||||
| class Layout |  | ||||||
| { |  | ||||||
| public: |  | ||||||
|     /* 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 remapCylinderPhysicalToLogical(unsigned physicalCylinder); |  | ||||||
|     static unsigned remapCylinderLogicalToPhysical(unsigned logicalCylinder); |  | ||||||
|  |  | ||||||
|     /* Translates logical side numbering (the numbers actually written in the |  | ||||||
|      * sector headers) to the sides used on the actual drive. |  | ||||||
|      */ |  | ||||||
|     static unsigned remapHeadPhysicalToLogical(unsigned physicalHead); |  | ||||||
|     static unsigned remapHeadLogicalToPhysical(unsigned logicalHead); |  | ||||||
|  |  | ||||||
|     /* Uses the layout and current track and heads settings to determine |  | ||||||
|      * which physical/logical tracks are going to be read from or written to. |  | ||||||
|      */ |  | ||||||
|     static std::vector<CylinderHead> computePhysicalLocations(); |  | ||||||
|     static std::vector<CylinderHead> computeLogicalLocations(); |  | ||||||
|  |  | ||||||
|     /* Uses the current layout to compute the filesystem's block order, in |  | ||||||
|      * _logical_ tracks. */ |  | ||||||
|     static std::vector<LogicalLocation> computeFilesystemLogicalOrdering(); |  | ||||||
|  |  | ||||||
|     /* Given a list of CylinderHead locations, determines the minimum and |  | ||||||
|      * maximum track and side settings. */ |  | ||||||
|     struct LayoutBounds |  | ||||||
|     { |  | ||||||
|         std::strong_ordering operator<=>( |  | ||||||
|             const LayoutBounds& other) const = default; |  | ||||||
|  |  | ||||||
|         int minCylinder, maxCylinder, minHead, maxHead; |  | ||||||
|     }; |  | ||||||
|     static LayoutBounds getBounds(const std::vector<CylinderHead>& locations); |  | ||||||
|  |  | ||||||
|     /* Returns a series of logical <track, side> pairs representing the |  | ||||||
|      * filesystem ordering of the disk, in logical numbers. */ |  | ||||||
|     static std::vector<std::pair<unsigned, unsigned>> getTrackOrdering( |  | ||||||
|         LayoutProto::Order ordering, |  | ||||||
|         unsigned guessedCylinders = 0, |  | ||||||
|         unsigned guessedHeads = 0); |  | ||||||
|  |  | ||||||
|     /* Returns the layout of a given track. */ |  | ||||||
|     static std::shared_ptr<const TrackInfo> getLayoutOfTrack( |  | ||||||
|         unsigned logicalCylinder, unsigned logicalHead); |  | ||||||
|  |  | ||||||
|     /* Returns the layout of a given track via physical location. */ |  | ||||||
|     static std::shared_ptr<const TrackInfo> getLayoutOfTrackPhysical( |  | ||||||
|         unsigned physicalCylinder, unsigned physicalHead); |  | ||||||
|  |  | ||||||
|     /* Returns the layout of a given track via physical location. */ |  | ||||||
|     static std::shared_ptr<const TrackInfo> getLayoutOfTrackPhysical( |  | ||||||
|         const CylinderHead& physicalLocation); |  | ||||||
|  |  | ||||||
|     /* Returns the layouts of a multiple tracks via physical location. */ |  | ||||||
|     static std::vector<std::shared_ptr<const TrackInfo>> |  | ||||||
|     getLayoutOfTracksPhysical(const std::vector<CylinderHead>& locations); |  | ||||||
|  |  | ||||||
|     /* Expand a SectorList into the actual sector IDs. */ |  | ||||||
|     static std::vector<unsigned> expandSectorList( |  | ||||||
|         const SectorListProto& sectorsProto); |  | ||||||
|  |  | ||||||
|     /* Return the head width of the current drive. */ |  | ||||||
|     static int getHeadWidth(); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| struct LogicalTrackLayout | struct LogicalTrackLayout | ||||||
| { | { | ||||||
| @@ -113,11 +43,11 @@ struct LogicalTrackLayout | |||||||
|      * uses them. */ |      * uses them. */ | ||||||
|     std::vector<unsigned> filesystemSectorOrder; |     std::vector<unsigned> filesystemSectorOrder; | ||||||
|  |  | ||||||
|     /* Mapping of filesystem order to natural order. */ |     /* Mapping of sector ID to filesystem ordering. */ | ||||||
|     std::map<unsigned, unsigned> filesystemToNaturalSectorMap; |     std::map<unsigned, unsigned> sectorIdToFilesystemOrdering; | ||||||
|  |  | ||||||
|     /* Mapping of natural order to filesystem order. */ |     /* Mapping of sector ID to natural ordering. */ | ||||||
|     std::map<unsigned, unsigned> naturalToFilesystemSectorMap; |     std::map<unsigned, unsigned> sectorIdToNaturalOrdering; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| struct PhysicalTrackLayout | struct PhysicalTrackLayout | ||||||
| @@ -140,29 +70,51 @@ class DiskLayout | |||||||
| public: | public: | ||||||
|     DiskLayout(const ConfigProto& config = globalConfig()); |     DiskLayout(const ConfigProto& config = globalConfig()); | ||||||
|  |  | ||||||
| public: |     /* Makes a simplified layout for testing. */ | ||||||
|     unsigned headBias; |  | ||||||
|     unsigned headWidth; |  | ||||||
|     bool swapSides; |  | ||||||
|  |  | ||||||
|     unsigned minPhysicalCylinder, maxPhysicalCylinder; |     DiskLayout(unsigned numCylinders, | ||||||
|     unsigned minPhysicalHead, maxPhysicalHead; |         unsigned numHeads, | ||||||
|     unsigned groupSize; |         unsigned numSectors, | ||||||
|  |         unsigned sectorSize); | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     /* Logical size. */ | ||||||
|  |  | ||||||
|     unsigned numLogicalCylinders; |     unsigned numLogicalCylinders; | ||||||
|     unsigned numLogicalHeads; |     unsigned numLogicalHeads; | ||||||
|  |  | ||||||
|  |     /* Physical size and properties. */ | ||||||
|  |  | ||||||
|  |     unsigned minPhysicalCylinder, maxPhysicalCylinder; | ||||||
|  |     unsigned minPhysicalHead, maxPhysicalHead; | ||||||
|  |     unsigned groupSize; /* Number of physical cylinders per logical cylinder */ | ||||||
|  |     unsigned headBias;  /* Physical cylinder offset */ | ||||||
|  |     unsigned headWidth; /* Width of the physical head */ | ||||||
|  |     bool swapSides;     /* Whether sides need to be swapped */ | ||||||
|  |  | ||||||
|  |     /* Physical and logical layouts by location. */ | ||||||
|  |  | ||||||
|     std::map<CylinderHead, std::shared_ptr<const PhysicalTrackLayout>> |     std::map<CylinderHead, std::shared_ptr<const PhysicalTrackLayout>> | ||||||
|         layoutByPhysicalLocation; |         layoutByPhysicalLocation; | ||||||
|     std::map<CylinderHead, std::shared_ptr<const LogicalTrackLayout>> |     std::map<CylinderHead, std::shared_ptr<const LogicalTrackLayout>> | ||||||
|         layoutByLogicalLocation; |         layoutByLogicalLocation; | ||||||
|  |  | ||||||
|  |     /* Ordered lists of physical and logical locations. */ | ||||||
|  |  | ||||||
|     std::vector<CylinderHead> logicalLocations; |     std::vector<CylinderHead> logicalLocations; | ||||||
|     std::vector<CylinderHeadSector> physicalSectorLocationsInFilesystemOrder; |     std::vector<CylinderHead> logicalLocationsInFilesystemOrder; | ||||||
|  |     std::vector<CylinderHead> physicalLocations; | ||||||
|  |  | ||||||
|  |     /* Ordered lists of sector locations, plus the reverse mapping. */ | ||||||
|  |  | ||||||
|     std::vector<LogicalLocation> logicalSectorLocationsInFilesystemOrder; |     std::vector<LogicalLocation> logicalSectorLocationsInFilesystemOrder; | ||||||
|     std::map<unsigned, LogicalLocation> logicalLocationBySectorOffset; |     std::map<LogicalLocation, unsigned> blockIdByLogicalSectorLocation; | ||||||
|     std::map<LogicalLocation, unsigned> sectorOffsetByLogicalLocation; |     std::vector<CylinderHeadSector> physicalSectorLocationsInFilesystemOrder; | ||||||
|     std::map<unsigned, LogicalLocation> logicalLocationByBlockId; |  | ||||||
|     std::map<LogicalLocation, unsigned> blockIdByLogicalLocation; |     /* Mapping from logical location to sector offset and back again. */ | ||||||
|  |  | ||||||
|  |     std::map<unsigned, LogicalLocation> logicalSectorLocationBySectorOffset; | ||||||
|  |     std::map<LogicalLocation, unsigned> sectorOffsetByLogicalSectorLocation; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     unsigned remapCylinderPhysicalToLogical(unsigned physicalCylinder) const |     unsigned remapCylinderPhysicalToLogical(unsigned physicalCylinder) const | ||||||
| @@ -185,8 +137,18 @@ public: | |||||||
|         return logicalHead ^ swapSides; |         return logicalHead ^ swapSides; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Layout::LayoutBounds getPhysicalBounds() const; |     /* Given a list of CylinderHead locations, determines the minimum and | ||||||
|     Layout::LayoutBounds getLogicalBounds() const; |      * maximum track and side settings. */ | ||||||
|  |     struct LayoutBounds | ||||||
|  |     { | ||||||
|  |         std::strong_ordering operator<=>( | ||||||
|  |             const LayoutBounds& other) const = default; | ||||||
|  |  | ||||||
|  |         int minCylinder, maxCylinder, minHead, maxHead; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     LayoutBounds getPhysicalBounds() const; | ||||||
|  |     LayoutBounds getLogicalBounds() const; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static std::shared_ptr<DiskLayout> createDiskLayout( | static std::shared_ptr<DiskLayout> createDiskLayout( | ||||||
|   | |||||||
| @@ -89,11 +89,7 @@ std::shared_ptr<DecodedTrack> Decoder::decodeToSectors( | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (_sector->status != Sector::MISSING) |         if (_sector->status != Sector::MISSING) | ||||||
|         { |  | ||||||
|             auto trackLayout = Layout::getLayoutOfTrack( |  | ||||||
|                 _sector->logicalCylinder, _sector->logicalHead); |  | ||||||
|             _trackdata->sectors.push_back(_sector); |             _trackdata->sectors.push_back(_sector); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return _trackdata; |     return _trackdata; | ||||||
|   | |||||||
| @@ -36,8 +36,8 @@ std::vector<std::shared_ptr<const Sector>> Encoder::collectSectors( | |||||||
|  |  | ||||||
|     for (unsigned sectorId : ltl.diskSectorOrder) |     for (unsigned sectorId : ltl.diskSectorOrder) | ||||||
|     { |     { | ||||||
|         const auto& sector = getSector( |         const auto& sector = | ||||||
|             {ltl.logicalCylinder, ltl.logicalHead}, image, sectorId); |             getSector({ltl.logicalCylinder, ltl.logicalHead}, image, sectorId); | ||||||
|         if (!sector) |         if (!sector) | ||||||
|             error("sector {}.{}.{} is missing from the image", |             error("sector {}.{}.{} is missing from the image", | ||||||
|                 ltl.logicalCylinder, |                 ltl.logicalCylinder, | ||||||
|   | |||||||
| @@ -39,9 +39,11 @@ namespace | |||||||
|  |  | ||||||
|         ~A2RFluxSink() |         ~A2RFluxSink() | ||||||
|         { |         { | ||||||
|             auto physicalLocations = Layout::computePhysicalLocations(); |             // FIXME: should use a passed-in DiskLayout object. | ||||||
|  |             auto diskLayout = createDiskLayout(); | ||||||
|             auto [minCylinder, maxCylinder, minHead, maxHead] = |             auto [minCylinder, maxCylinder, minHead, maxHead] = | ||||||
|                 Layout::getBounds(physicalLocations); |                 diskLayout->getPhysicalBounds(); | ||||||
|  |  | ||||||
|             _minCylinder = minCylinder; |             _minCylinder = minCylinder; | ||||||
|             _maxCylinder = maxCylinder; |             _maxCylinder = maxCylinder; | ||||||
|             _minHead = minHead; |             _minHead = minHead; | ||||||
|   | |||||||
| @@ -41,8 +41,10 @@ class ScpFluxSink : public FluxSink | |||||||
| public: | public: | ||||||
|     ScpFluxSink(const ScpFluxSinkProto& lconfig): _config(lconfig) |     ScpFluxSink(const ScpFluxSinkProto& lconfig): _config(lconfig) | ||||||
|     { |     { | ||||||
|  |         // FIXME: should use a passed-in DiskLayout object. | ||||||
|  |         auto diskLayout = createDiskLayout(); | ||||||
|         auto [minCylinder, maxCylinder, minHead, maxHead] = |         auto [minCylinder, maxCylinder, minHead, maxHead] = | ||||||
|             Layout::getBounds(Layout::computePhysicalLocations()); |             diskLayout->getPhysicalBounds(); | ||||||
|  |  | ||||||
|         _fileheader.file_id[0] = 'S'; |         _fileheader.file_id[0] = 'S'; | ||||||
|         _fileheader.file_id[1] = 'C'; |         _fileheader.file_id[1] = 'C'; | ||||||
|   | |||||||
| @@ -119,8 +119,14 @@ public: | |||||||
|  |  | ||||||
|                 auto keys = std::views::keys(_v2data); |                 auto keys = std::views::keys(_v2data); | ||||||
|                 std::vector<CylinderHead> chs{keys.begin(), keys.end()}; |                 std::vector<CylinderHead> chs{keys.begin(), keys.end()}; | ||||||
|                 auto [minCylinder, maxCylinder, minHead, maxHead] = |                 unsigned minCylinder = std::ranges::min( | ||||||
|                     Layout::getBounds(chs); |                     chs | std::views::transform(&CylinderHead::cylinder)); | ||||||
|  |                 unsigned maxCylinder = std::ranges::min( | ||||||
|  |                     chs | std::views::transform(&CylinderHead::cylinder)); | ||||||
|  |                 unsigned minHead = std::ranges::min( | ||||||
|  |                     chs | std::views::transform(&CylinderHead::head)); | ||||||
|  |                 unsigned maxHead = std::ranges::min( | ||||||
|  |                     chs | std::views::transform(&CylinderHead::head)); | ||||||
|                 log("A2R: reading A2R {} file with {} cylinders and {} head{}", |                 log("A2R: reading A2R {} file with {} cylinders and {} head{}", | ||||||
|                     (disktype == 1)   ? "Apple II" |                     (disktype == 1)   ? "Apple II" | ||||||
|                     : (disktype == 2) ? "normal" |                     : (disktype == 2) ? "normal" | ||||||
|   | |||||||
| @@ -62,7 +62,4 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageReaderProto& config) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| ImageReader::ImageReader(const ImageReaderProto& config): | ImageReader::ImageReader(const ImageReaderProto& config): _config(config) {} | ||||||
|     _config(config) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -31,28 +31,28 @@ public: | |||||||
|                 "IMG: bad configuration; did you remember to set the " |                 "IMG: bad configuration; did you remember to set the " | ||||||
|                 "tracks, sides and trackdata fields in the layout?"); |                 "tracks, sides and trackdata fields in the layout?"); | ||||||
|  |  | ||||||
|  |         const auto diskLayout = createDiskLayout(); | ||||||
|         bool in_filesystem_order = _config.img().filesystem_sector_order(); |         bool in_filesystem_order = _config.img().filesystem_sector_order(); | ||||||
|         std::unique_ptr<Image> image(new Image); |         std::unique_ptr<Image> image(new Image); | ||||||
|         for (const auto& p : Layout::getTrackOrdering( |  | ||||||
|                  in_filesystem_order ? layout.filesystem_track_order() |         for (auto& logicalLocation : | ||||||
|                                      : layout.image_track_order())) |             in_filesystem_order ? diskLayout->logicalLocationsInFilesystemOrder | ||||||
|  |                                 : diskLayout->logicalLocations) | ||||||
|         { |         { | ||||||
|             int track = p.first; |             auto& ltl = diskLayout->layoutByLogicalLocation.at(logicalLocation); | ||||||
|             int side = p.second; |  | ||||||
|  |  | ||||||
|             if (inputFile.eof()) |             for (unsigned sectorId : in_filesystem_order | ||||||
|                 break; |                                          ? ltl->filesystemSectorOrder | ||||||
|  |                                          : ltl->naturalSectorOrder) | ||||||
|             auto trackLayout = Layout::getLayoutOfTrack(track, side); |  | ||||||
|             for (int sectorId : trackLayout->naturalSectorOrder) |  | ||||||
|             { |             { | ||||||
|                 Bytes data(trackLayout->sectorSize); |                 if (inputFile.eof()) | ||||||
|  |                     break; | ||||||
|  |  | ||||||
|  |                 Bytes data(ltl->sectorSize); | ||||||
|                 inputFile.read((char*)data.begin(), data.size()); |                 inputFile.read((char*)data.begin(), data.size()); | ||||||
|  |  | ||||||
|                 if (in_filesystem_order) |                 const auto& sector = image->put( | ||||||
|                     sectorId = |                     logicalLocation.cylinder, logicalLocation.head, sectorId); | ||||||
|                         trackLayout->filesystemToNaturalSectorMap.at(sectorId); |  | ||||||
|                 const auto& sector = image->put(track, side, sectorId); |  | ||||||
|                 sector->status = Sector::OK; |                 sector->status = Sector::OK; | ||||||
|                 sector->data = data; |                 sector->data = data; | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -32,29 +32,25 @@ public: | |||||||
|         if (!outputFile.is_open()) |         if (!outputFile.is_open()) | ||||||
|             error("cannot open output file"); |             error("cannot open output file"); | ||||||
|  |  | ||||||
|  |         const auto diskLayout = createDiskLayout(); | ||||||
|         bool in_filesystem_order = _config.img().filesystem_sector_order(); |         bool in_filesystem_order = _config.img().filesystem_sector_order(); | ||||||
|         for (const auto& p : Layout::getTrackOrdering( |  | ||||||
|                  in_filesystem_order ? layout.filesystem_track_order() |         for (auto& logicalLocation : | ||||||
|                                      : layout.image_track_order(), |             in_filesystem_order ? diskLayout->logicalLocationsInFilesystemOrder | ||||||
|                  tracks, |                                 : diskLayout->logicalLocations) | ||||||
|                  sides)) |  | ||||||
|         { |         { | ||||||
|             int track = p.first; |             auto& ltl = diskLayout->layoutByLogicalLocation.at(logicalLocation); | ||||||
|             int side = p.second; |  | ||||||
|  |  | ||||||
|             auto trackLayout = Layout::getLayoutOfTrack(track, side); |             for (unsigned sectorId : in_filesystem_order | ||||||
|             for (int sectorId : trackLayout->naturalSectorOrder) |                                          ? ltl->filesystemSectorOrder | ||||||
|  |                                          : ltl->naturalSectorOrder) | ||||||
|             { |             { | ||||||
|                 if (in_filesystem_order) |                 const auto& sector = image.get( | ||||||
|                     sectorId = |                     logicalLocation.cylinder, logicalLocation.head, sectorId); | ||||||
|                         trackLayout->filesystemToNaturalSectorMap.at(sectorId); |  | ||||||
|  |  | ||||||
|                 const auto& sector = image.get(track, side, sectorId); |  | ||||||
|                 if (sector) |                 if (sector) | ||||||
|                     sector->data.slice(0, trackLayout->sectorSize) |                     sector->data.slice(0, ltl->sectorSize).writeTo(outputFile); | ||||||
|                         .writeTo(outputFile); |  | ||||||
|                 else |                 else | ||||||
|                     outputFile.seekp(trackLayout->sectorSize, std::ios::cur); |                     outputFile.seekp(ltl->sectorSize, std::ios::cur); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -106,9 +106,10 @@ public: | |||||||
| class AcornDfsFilesystem : public Filesystem | class AcornDfsFilesystem : public Filesystem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     AcornDfsFilesystem( |     AcornDfsFilesystem(const AcornDfsProto& config, | ||||||
|         const AcornDfsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -178,7 +179,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createAcornDfsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createAcornDfsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<AcornDfsFilesystem>(config.acorndfs(), sectors); |     return std::make_unique<AcornDfsFilesystem>( | ||||||
|  |         config.acorndfs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -50,9 +50,10 @@ static std::string modeToString(long access) | |||||||
| class AmigaFfsFilesystem : public Filesystem | class AmigaFfsFilesystem : public Filesystem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     AmigaFfsFilesystem( |     AmigaFfsFilesystem(const AmigaFfsProto& config, | ||||||
|         const AmigaFfsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -91,7 +92,8 @@ public: | |||||||
|         dev.devType = DEVTYPE_FLOPDD; |         dev.devType = DEVTYPE_FLOPDD; | ||||||
|         dev.cylinders = globalConfig()->layout().tracks(); |         dev.cylinders = globalConfig()->layout().tracks(); | ||||||
|         dev.heads = globalConfig()->layout().sides(); |         dev.heads = globalConfig()->layout().sides(); | ||||||
|         dev.sectors = Layout::getLayoutOfTrack(0, 0)->numSectors; |         dev.sectors = | ||||||
|  |             _diskLayout->layoutByLogicalLocation.at({0, 0})->numSectors; | ||||||
|         adfInitDevice(&dev, nullptr, false); |         adfInitDevice(&dev, nullptr, false); | ||||||
|         int res = adfCreateFlop(&dev, (char*)volumeName.c_str(), 0); |         int res = adfCreateFlop(&dev, (char*)volumeName.c_str(), 0); | ||||||
|         if (res != RC_OK) |         if (res != RC_OK) | ||||||
| @@ -469,7 +471,10 @@ static BOOL adfIsDevNative(char*) | |||||||
| } | } | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createAmigaFfsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createAmigaFfsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<AmigaFfsFilesystem>(config.amigaffs(), sectors); |     return std::make_unique<AmigaFfsFilesystem>( | ||||||
|  |         config.amigaffs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -43,9 +43,10 @@ class AppledosFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     AppledosFilesystem( |     AppledosFilesystem(const AppledosProto& config, | ||||||
|         const AppledosProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -175,7 +176,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createAppledosFilesystem( | std::unique_ptr<Filesystem> Filesystem::createAppledosFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<AppledosFilesystem>(config.appledos(), sectors); |     return std::make_unique<AppledosFilesystem>( | ||||||
|  |         config.appledos(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -226,8 +226,9 @@ class Brother120Filesystem : public Filesystem | |||||||
| { | { | ||||||
| public: | public: | ||||||
|     Brother120Filesystem(const Brother120FsProto& config, |     Brother120Filesystem(const Brother120FsProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         std::shared_ptr<SectorInterface> sectors): |         std::shared_ptr<SectorInterface> sectors): | ||||||
|         Filesystem(sectors), |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -348,7 +349,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createBrother120Filesystem( | std::unique_ptr<Filesystem> Filesystem::createBrother120Filesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<Brother120Filesystem>(config.brother120(), sectors); |     return std::make_unique<Brother120Filesystem>( | ||||||
|  |         config.brother120(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -189,9 +189,10 @@ class CbmfsFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     CbmfsFilesystem( |     CbmfsFilesystem(const CbmfsProto& config, | ||||||
|         const CbmfsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -281,7 +282,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createCbmfsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createCbmfsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<CbmfsFilesystem>(config.cbmfs(), sectors); |     return std::make_unique<CbmfsFilesystem>( | ||||||
|  |         config.cbmfs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -183,9 +183,10 @@ class CpmFsFilesystem : public Filesystem, public HasBitmap, public HasMount | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     CpmFsFilesystem( |     CpmFsFilesystem(const CpmFsProto& config, | ||||||
|         const CpmFsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -661,7 +662,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createCpmFsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createCpmFsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<CpmFsFilesystem>(config.cpmfs(), sectors); |     return std::make_unique<CpmFsFilesystem>( | ||||||
|  |         config.cpmfs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,9 +29,10 @@ static std::string modeToString(BYTE attrib) | |||||||
| class FatFsFilesystem : public Filesystem | class FatFsFilesystem : public Filesystem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     FatFsFilesystem( |     FatFsFilesystem(const FatFsProto& config, | ||||||
|         const FatFsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -336,7 +337,10 @@ DWORD get_fattime(void) | |||||||
| } | } | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createFatFsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createFatFsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<FatFsFilesystem>(config.fatfs(), sectors); |     return std::make_unique<FatFsFilesystem>( | ||||||
|  |         config.fatfs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -132,8 +132,8 @@ private: | |||||||
|     { |     { | ||||||
|         CylinderHead logicalLocation = {logicalCylinder, logicalSide}; |         CylinderHead logicalLocation = {logicalCylinder, logicalSide}; | ||||||
|         auto& ltl = _diskLayout->layoutByLogicalLocation.at(logicalLocation); |         auto& ltl = _diskLayout->layoutByLogicalLocation.at(logicalLocation); | ||||||
|         auto trackdata = readAndDecodeTrack( |         auto trackdata = | ||||||
|             *_diskLayout, *_fluxSource, *_decoder, ltl); |             readAndDecodeTrack(*_diskLayout, *_fluxSource, *_decoder, ltl); | ||||||
|  |  | ||||||
|         for (const auto& sector : trackdata.sectors) |         for (const auto& sector : trackdata.sectors) | ||||||
|             *_loadedSectors.put(logicalLocation, sector->logicalSector) = |             *_loadedSectors.put(logicalLocation, sector->logicalSector) = | ||||||
|   | |||||||
| @@ -10,8 +10,10 @@ | |||||||
| class ImageSectorInterface : public SectorInterface | class ImageSectorInterface : public SectorInterface | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     ImageSectorInterface(std::shared_ptr<ImageReader> reader, |     ImageSectorInterface(const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         std::shared_ptr<ImageWriter> writer): |         const std::shared_ptr<ImageReader>& reader, | ||||||
|  |         const std::shared_ptr<ImageWriter>& writer): | ||||||
|  |         _diskLayout(diskLayout), | ||||||
|         _reader(reader), |         _reader(reader), | ||||||
|         _writer(writer) |         _writer(writer) | ||||||
|     { |     { | ||||||
| @@ -55,20 +57,23 @@ public: | |||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             _image = std::make_shared<Image>(); |             _image = std::make_shared<Image>(); | ||||||
|             _image->createBlankImage(); |             _image->addMissingSectors(*_diskLayout); | ||||||
|         } |         } | ||||||
|         _changed = false; |         _changed = false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     std::shared_ptr<Image> _image; |     std::shared_ptr<Image> _image; | ||||||
|  |     std::shared_ptr<const DiskLayout> _diskLayout; | ||||||
|     std::shared_ptr<ImageReader> _reader; |     std::shared_ptr<ImageReader> _reader; | ||||||
|     std::shared_ptr<ImageWriter> _writer; |     std::shared_ptr<ImageWriter> _writer; | ||||||
|     bool _changed = false; |     bool _changed = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<SectorInterface> SectorInterface::createImageSectorInterface( | std::unique_ptr<SectorInterface> SectorInterface::createImageSectorInterface( | ||||||
|     std::shared_ptr<ImageReader> reader, std::shared_ptr<ImageWriter> writer) |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<ImageReader> reader, | ||||||
|  |     std::shared_ptr<ImageWriter> writer) | ||||||
| { | { | ||||||
|     return std::make_unique<ImageSectorInterface>(reader, writer); |     return std::make_unique<ImageSectorInterface>(diskLayout, reader, writer); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -134,9 +134,10 @@ class LifFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     LifFilesystem( |     LifFilesystem(const LifProto& config, | ||||||
|         const LifProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -288,7 +289,9 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createLifFilesystem( | std::unique_ptr<Filesystem> Filesystem::createLifFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<LifFilesystem>(config.lif(), sectors); |     return std::make_unique<LifFilesystem>(config.lif(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,9 +16,10 @@ static MacHfsFilesystem* currentMacHfs; | |||||||
| class MacHfsFilesystem : public Filesystem | class MacHfsFilesystem : public Filesystem | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     MacHfsFilesystem( |     MacHfsFilesystem(const MacHfsProto& config, | ||||||
|         const MacHfsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -459,7 +460,10 @@ unsigned long os_write(void** priv, const void* buffer, unsigned long len) | |||||||
| } | } | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createMacHfsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createMacHfsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<MacHfsFilesystem>(config.machfs(), sectors); |     return std::make_unique<MacHfsFilesystem>( | ||||||
|  |         config.machfs(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -94,9 +94,10 @@ class MicrodosFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     MicrodosFilesystem( |     MicrodosFilesystem(const MicrodosProto& config, | ||||||
|         const MicrodosProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -217,7 +218,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createMicrodosFilesystem( | std::unique_ptr<Filesystem> Filesystem::createMicrodosFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<MicrodosFilesystem>(config.microdos(), sectors); |     return std::make_unique<MicrodosFilesystem>( | ||||||
|  |         config.microdos(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -157,9 +157,10 @@ class PhileFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     PhileFilesystem( |     PhileFilesystem(const PhileProto& config, | ||||||
|         const PhileProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -293,7 +294,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createPhileFilesystem( | std::unique_ptr<Filesystem> Filesystem::createPhileFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<PhileFilesystem>(config.phile(), sectors); |     return std::make_unique<PhileFilesystem>( | ||||||
|  |         config.phile(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -133,9 +133,10 @@ class ProdosFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     ProdosFilesystem( |     ProdosFilesystem(const ProdosProto& config, | ||||||
|         const ProdosProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -302,7 +303,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createProdosFilesystem( | std::unique_ptr<Filesystem> Filesystem::createProdosFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<ProdosFilesystem>(config.prodos(), sectors); |     return std::make_unique<ProdosFilesystem>( | ||||||
|  |         config.prodos(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -93,9 +93,10 @@ private: | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     RolandFsFilesystem( |     RolandFsFilesystem(const RolandFsProto& config, | ||||||
|         const RolandFsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -421,7 +422,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createRolandFsFilesystem( | std::unique_ptr<Filesystem> Filesystem::createRolandFsFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<RolandFsFilesystem>(config.roland(), sectors); |     return std::make_unique<RolandFsFilesystem>( | ||||||
|  |         config.roland(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ public: | |||||||
|     static std::unique_ptr<SectorInterface> createMemorySectorInterface( |     static std::unique_ptr<SectorInterface> createMemorySectorInterface( | ||||||
|         std::shared_ptr<Image> image); |         std::shared_ptr<Image> image); | ||||||
|     static std::unique_ptr<SectorInterface> createImageSectorInterface( |     static std::unique_ptr<SectorInterface> createImageSectorInterface( | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         std::shared_ptr<ImageReader> reader, |         std::shared_ptr<ImageReader> reader, | ||||||
|         std::shared_ptr<ImageWriter> writer); |         std::shared_ptr<ImageWriter> writer); | ||||||
|     static std::unique_ptr<SectorInterface> createFluxSectorInterface( |     static std::unique_ptr<SectorInterface> createFluxSectorInterface( | ||||||
|   | |||||||
| @@ -132,9 +132,10 @@ class Smaky6Filesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     Smaky6Filesystem( |     Smaky6Filesystem(const Smaky6FsProto& config, | ||||||
|         const Smaky6FsProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -204,7 +205,10 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createSmaky6Filesystem( | std::unique_ptr<Filesystem> Filesystem::createSmaky6Filesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<Smaky6Filesystem>(config.smaky6(), sectors); |     return std::make_unique<Smaky6Filesystem>( | ||||||
|  |         config.smaky6(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										133
									
								
								lib/vfs/vfs.cc
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								lib/vfs/vfs.cc
									
									
									
									
									
								
							| @@ -151,82 +151,74 @@ void Filesystem::discardChanges() | |||||||
|     _sectors->discardChanges(); |     _sectors->discardChanges(); | ||||||
| } | } | ||||||
|  |  | ||||||
| Filesystem::Filesystem(std::shared_ptr<SectorInterface> sectors): | Filesystem::Filesystem(const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors): | ||||||
|  |     _diskLayout(diskLayout), | ||||||
|  |     _blockCount(diskLayout->logicalSectorLocationsInFilesystemOrder.size()), | ||||||
|     _sectors(sectors) |     _sectors(sectors) | ||||||
| { | { | ||||||
|     auto& layout = globalConfig()->layout(); |  | ||||||
|     if (!layout.has_tracks() || !layout.has_sides()) |  | ||||||
|         error( |  | ||||||
|             "FS: filesystem support cannot be used without concrete layout " |  | ||||||
|             "information"); |  | ||||||
|  |  | ||||||
|     unsigned block = 0; |  | ||||||
|     for (const auto& p : Layout::getTrackOrdering( |  | ||||||
|              layout.filesystem_track_order(), layout.tracks(), layout.sides())) |  | ||||||
|     { |  | ||||||
|         int track = p.first; |  | ||||||
|         int side = p.second; |  | ||||||
|  |  | ||||||
|         auto trackLayout = Layout::getLayoutOfTrack(track, side); |  | ||||||
|         if (trackLayout->numSectors == 0) |  | ||||||
|             error( |  | ||||||
|                 "FS: filesystem support cannot be used without concrete " |  | ||||||
|                 "layout information"); |  | ||||||
|  |  | ||||||
|         for (int sectorId : trackLayout->filesystemSectorOrder) |  | ||||||
|             _locations.push_back(std::make_tuple(track, side, sectorId)); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createFilesystem( | std::unique_ptr<Filesystem> Filesystem::createFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> image) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> image) | ||||||
| { | { | ||||||
|     switch (config.type()) |     switch (config.type()) | ||||||
|     { |     { | ||||||
|         case FilesystemProto::BROTHER120: |         case FilesystemProto::BROTHER120: | ||||||
|             return Filesystem::createBrother120Filesystem(config, image); |             return Filesystem::createBrother120Filesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::ACORNDFS: |         case FilesystemProto::ACORNDFS: | ||||||
|             return Filesystem::createAcornDfsFilesystem(config, image); |             return Filesystem::createAcornDfsFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::FATFS: |         case FilesystemProto::FATFS: | ||||||
|             return Filesystem::createFatFsFilesystem(config, image); |             return Filesystem::createFatFsFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::CPMFS: |         case FilesystemProto::CPMFS: | ||||||
|             return Filesystem::createCpmFsFilesystem(config, image); |             return Filesystem::createCpmFsFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::AMIGAFFS: |         case FilesystemProto::AMIGAFFS: | ||||||
|             return Filesystem::createAmigaFfsFilesystem(config, image); |             return Filesystem::createAmigaFfsFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::MACHFS: |         case FilesystemProto::MACHFS: | ||||||
|             return Filesystem::createMacHfsFilesystem(config, image); |             return Filesystem::createMacHfsFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::CBMFS: |         case FilesystemProto::CBMFS: | ||||||
|             return Filesystem::createCbmfsFilesystem(config, image); |             return Filesystem::createCbmfsFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::PRODOS: |         case FilesystemProto::PRODOS: | ||||||
|             return Filesystem::createProdosFilesystem(config, image); |             return Filesystem::createProdosFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::APPLEDOS: |         case FilesystemProto::APPLEDOS: | ||||||
|             return Filesystem::createAppledosFilesystem(config, image); |             return Filesystem::createAppledosFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::SMAKY6: |         case FilesystemProto::SMAKY6: | ||||||
|             return Filesystem::createSmaky6Filesystem(config, image); |             return Filesystem::createSmaky6Filesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::PHILE: |         case FilesystemProto::PHILE: | ||||||
|             return Filesystem::createPhileFilesystem(config, image); |             return Filesystem::createPhileFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::LIF: |         case FilesystemProto::LIF: | ||||||
|             return Filesystem::createLifFilesystem(config, image); |             return Filesystem::createLifFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::MICRODOS: |         case FilesystemProto::MICRODOS: | ||||||
|             return Filesystem::createMicrodosFilesystem(config, image); |             return Filesystem::createMicrodosFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::ZDOS: |         case FilesystemProto::ZDOS: | ||||||
|             return Filesystem::createZDosFilesystem(config, image); |             return Filesystem::createZDosFilesystem(config, diskLayout, image); | ||||||
|  |  | ||||||
|         case FilesystemProto::ROLAND: |         case FilesystemProto::ROLAND: | ||||||
|             return Filesystem::createRolandFsFilesystem(config, image); |             return Filesystem::createRolandFsFilesystem( | ||||||
|  |                 config, diskLayout, image); | ||||||
|  |  | ||||||
|         default: |         default: | ||||||
|             error("no filesystem configured"); |             error("no filesystem configured"); | ||||||
| @@ -237,6 +229,7 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystem( | |||||||
| std::unique_ptr<Filesystem> Filesystem::createFilesystemFromConfig() | std::unique_ptr<Filesystem> Filesystem::createFilesystemFromConfig() | ||||||
| { | { | ||||||
|     std::shared_ptr<SectorInterface> sectorInterface; |     std::shared_ptr<SectorInterface> sectorInterface; | ||||||
|  |     auto diskLayout = createDiskLayout(globalConfig()); | ||||||
|     if (globalConfig().hasFluxSource() || globalConfig().hasFluxSink()) |     if (globalConfig().hasFluxSource() || globalConfig().hasFluxSink()) | ||||||
|     { |     { | ||||||
|         std::shared_ptr<FluxSource> fluxSource; |         std::shared_ptr<FluxSource> fluxSource; | ||||||
| @@ -253,7 +246,6 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystemFromConfig() | |||||||
|             fluxSink = FluxSink::create(globalConfig()); |             fluxSink = FluxSink::create(globalConfig()); | ||||||
|             encoder = Arch::createEncoder(globalConfig()); |             encoder = Arch::createEncoder(globalConfig()); | ||||||
|         } |         } | ||||||
|         auto diskLayout = createDiskLayout(globalConfig()); |  | ||||||
|         sectorInterface = SectorInterface::createFluxSectorInterface( |         sectorInterface = SectorInterface::createFluxSectorInterface( | ||||||
|             diskLayout, fluxSource, fluxSink, encoder, decoder); |             diskLayout, fluxSource, fluxSink, encoder, decoder); | ||||||
|     } |     } | ||||||
| @@ -267,11 +259,12 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystemFromConfig() | |||||||
|         if (globalConfig().hasImageWriter()) |         if (globalConfig().hasImageWriter()) | ||||||
|             writer = ImageWriter::create(globalConfig()); |             writer = ImageWriter::create(globalConfig()); | ||||||
|  |  | ||||||
|         sectorInterface = |         sectorInterface = SectorInterface::createImageSectorInterface( | ||||||
|             SectorInterface::createImageSectorInterface(reader, writer); |             diskLayout, reader, writer); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return createFilesystem(globalConfig()->filesystem(), sectorInterface); |     return createFilesystem( | ||||||
|  |         globalConfig()->filesystem(), diskLayout, sectorInterface); | ||||||
| } | } | ||||||
|  |  | ||||||
| Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector) | Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector) | ||||||
| @@ -284,44 +277,40 @@ Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector) | |||||||
|  |  | ||||||
| Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count) | Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count) | ||||||
| { | { | ||||||
|     if ((number + count) > _locations.size()) |     if ((number + count) > _blockCount) | ||||||
|         throw BadFilesystemException(fmt::format( |         throw BadFilesystemException(fmt::format( | ||||||
|             "invalid filesystem: sector {} is out of bounds ({} maximum)", |             "invalid filesystem: sector {} is out of bounds ({} maximum)", | ||||||
|             number + count - 1, |             number + count - 1, | ||||||
|             _locations.size())); |             _diskLayout->logicalSectorLocationsInFilesystemOrder.size())); | ||||||
|  |  | ||||||
|     Bytes data; |     Bytes data; | ||||||
|     ByteWriter bw(data); |     ByteWriter bw(data); | ||||||
|     for (int i = 0; i < count; i++) |     for (int i = 0; i < count; i++) | ||||||
|     { |     { | ||||||
|         auto& it = _locations[number + i]; |         auto& [cylinder, head, sectorId] = | ||||||
|         int track = std::get<0>(it); |             _diskLayout->logicalSectorLocationsInFilesystemOrder.at(number + i); | ||||||
|         int side = std::get<1>(it); |         auto& ltl = _diskLayout->layoutByLogicalLocation.at({cylinder, head}); | ||||||
|         int sector = std::get<2>(it); |         bw += _sectors->get(cylinder, head, sectorId) | ||||||
|         auto trackLayout = Layout::getLayoutOfTrack(track, side); |                   ->data.slice(0, ltl->sectorSize); | ||||||
|         bw += _sectors->get(track, side, sector) |  | ||||||
|                   ->data.slice(0, trackLayout->sectorSize); |  | ||||||
|     } |     } | ||||||
|     return data; |     return data; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Filesystem::putLogicalSector(uint32_t number, const Bytes& data) | void Filesystem::putLogicalSector(uint32_t number, const Bytes& data) | ||||||
| { | { | ||||||
|     if (number >= _locations.size()) |     if (number >= _blockCount) | ||||||
|         throw BadFilesystemException(fmt::format( |         throw BadFilesystemException(fmt::format( | ||||||
|             "invalid filesystem: sector {} is out of bounds", number)); |             "invalid filesystem: sector {} is out of bounds", number)); | ||||||
|  |  | ||||||
|     unsigned pos = 0; |     unsigned pos = 0; | ||||||
|     while (pos < data.size()) |     while (pos < data.size()) | ||||||
|     { |     { | ||||||
|         auto& it = _locations[number]; |         auto& [cylinder, head, sectorId] = | ||||||
|         int track = std::get<0>(it); |             _diskLayout->logicalSectorLocationsInFilesystemOrder.at(number); | ||||||
|         int side = std::get<1>(it); |         auto& ltl = _diskLayout->layoutByLogicalLocation.at({cylinder, head}); | ||||||
|         int sector = std::get<2>(it); |         _sectors->put(cylinder, head, sectorId)->data = | ||||||
|         int sectorSize = Layout::getLayoutOfTrack(track, side)->sectorSize; |             data.slice(pos, ltl->sectorSize); | ||||||
|  |         pos += ltl->sectorSize; | ||||||
|         _sectors->put(track, side, sector)->data = data.slice(pos, sectorSize); |  | ||||||
|         pos += sectorSize; |  | ||||||
|         number++; |         number++; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -329,25 +318,23 @@ void Filesystem::putLogicalSector(uint32_t number, const Bytes& data) | |||||||
| unsigned Filesystem::getOffsetOfSector( | unsigned Filesystem::getOffsetOfSector( | ||||||
|     unsigned track, unsigned side, unsigned sector) |     unsigned track, unsigned side, unsigned sector) | ||||||
| { | { | ||||||
|     location_t key = {track, side, sector}; |     unsigned offset = findOrDefault(_diskLayout->sectorOffsetByLogicalSectorLocation, | ||||||
|  |         {track, side, sector}, | ||||||
|     for (int i = 0; i < _locations.size(); i++) |         UINT_MAX); | ||||||
|     { |     if (offset == UINT_MAX) | ||||||
|         if (_locations[i] >= key) |         throw BadFilesystemException(); | ||||||
|             return i; |     return offset; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     throw BadFilesystemException(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| unsigned Filesystem::getLogicalSectorCount() | unsigned Filesystem::getLogicalSectorCount() | ||||||
| { | { | ||||||
|     return _locations.size(); |     return _blockCount; | ||||||
| } | } | ||||||
|  |  | ||||||
| unsigned Filesystem::getLogicalSectorSize(unsigned track, unsigned side) | unsigned Filesystem::getLogicalSectorSize(unsigned cylinder, unsigned head) | ||||||
| { | { | ||||||
|     return Layout::getLayoutOfTrack(track, side)->sectorSize; |     auto& ltl = _diskLayout->layoutByLogicalLocation.at({cylinder, head}); | ||||||
|  |     return ltl->sectorSize; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Filesystem::eraseEverythingOnDisk() | void Filesystem::eraseEverythingOnDisk() | ||||||
|   | |||||||
| @@ -4,11 +4,12 @@ | |||||||
| #include "lib/core/bytes.h" | #include "lib/core/bytes.h" | ||||||
| #include "fmt/format.h" | #include "fmt/format.h" | ||||||
|  |  | ||||||
| class Sector; |  | ||||||
| class Image; |  | ||||||
| class Brother120Proto; | class Brother120Proto; | ||||||
| class DfsProto; | class DfsProto; | ||||||
|  | class DiskLayout; | ||||||
| class FilesystemProto; | class FilesystemProto; | ||||||
|  | class Image; | ||||||
|  | class Sector; | ||||||
| class SectorInterface; | class SectorInterface; | ||||||
|  |  | ||||||
| class Path : public std::vector<std::string> | class Path : public std::vector<std::string> | ||||||
| @@ -222,7 +223,8 @@ public: | |||||||
|     void discardChanges(); |     void discardChanges(); | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     Filesystem(std::shared_ptr<SectorInterface> sectors); |     Filesystem(const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> sectors); | ||||||
|  |  | ||||||
|     Bytes getSector(unsigned track, unsigned side, unsigned sector); |     Bytes getSector(unsigned track, unsigned side, unsigned sector); | ||||||
|  |  | ||||||
| @@ -235,45 +237,79 @@ public: | |||||||
|  |  | ||||||
|     void eraseEverythingOnDisk(); |     void eraseEverythingOnDisk(); | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     const std::shared_ptr<const DiskLayout>& _diskLayout; | ||||||
|  |     unsigned _blockCount; | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     typedef std::tuple<unsigned, unsigned, unsigned> location_t; |  | ||||||
|     std::vector<location_t> _locations; |  | ||||||
|     std::shared_ptr<SectorInterface> _sectors; |     std::shared_ptr<SectorInterface> _sectors; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     static std::unique_ptr<Filesystem> createBrother120Filesystem( |     static std::unique_ptr<Filesystem> createBrother120Filesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createAcornDfsFilesystem( |     static std::unique_ptr<Filesystem> createAcornDfsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createFatFsFilesystem( |     static std::unique_ptr<Filesystem> createFatFsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createCpmFsFilesystem( |     static std::unique_ptr<Filesystem> createCpmFsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createAmigaFfsFilesystem( |     static std::unique_ptr<Filesystem> createAmigaFfsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createMacHfsFilesystem( |     static std::unique_ptr<Filesystem> createMacHfsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createCbmfsFilesystem( |     static std::unique_ptr<Filesystem> createCbmfsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createProdosFilesystem( |     static std::unique_ptr<Filesystem> createProdosFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createAppledosFilesystem( |     static std::unique_ptr<Filesystem> createAppledosFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createSmaky6Filesystem( |     static std::unique_ptr<Filesystem> createSmaky6Filesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createPhileFilesystem( |     static std::unique_ptr<Filesystem> createPhileFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createLifFilesystem( |     static std::unique_ptr<Filesystem> createLifFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createMicrodosFilesystem( |     static std::unique_ptr<Filesystem> createMicrodosFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createZDosFilesystem( |     static std::unique_ptr<Filesystem> createZDosFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createRolandFsFilesystem( |     static std::unique_ptr<Filesystem> createRolandFsFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|  |  | ||||||
|     static std::unique_ptr<Filesystem> createFilesystem( |     static std::unique_ptr<Filesystem> createFilesystem( | ||||||
|         const FilesystemProto& config, std::shared_ptr<SectorInterface> image); |         const FilesystemProto& config, | ||||||
|  |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |         std::shared_ptr<SectorInterface> image); | ||||||
|     static std::unique_ptr<Filesystem> createFilesystemFromConfig(); |     static std::unique_ptr<Filesystem> createFilesystemFromConfig(); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -182,9 +182,10 @@ class ZDosFilesystem : public Filesystem | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     ZDosFilesystem( |     ZDosFilesystem(const ZDosProto& config, | ||||||
|         const ZDosProto& config, std::shared_ptr<SectorInterface> sectors): |         const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|         Filesystem(sectors), |         std::shared_ptr<SectorInterface> sectors): | ||||||
|  |         Filesystem(diskLayout, sectors), | ||||||
|         _config(config) |         _config(config) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| @@ -255,7 +256,8 @@ public: | |||||||
| private: | private: | ||||||
|     void mount() |     void mount() | ||||||
|     { |     { | ||||||
|         _sectorsPerTrack = Layout::getLayoutOfTrack(0, 0)->numSectors; |         _sectorsPerTrack = | ||||||
|  |             _diskLayout->layoutByLogicalLocation.at({0, 0})->numSectors; | ||||||
|  |  | ||||||
|         int rootBlock = toBlockNumber(_config.filesystem_start().sector(), |         int rootBlock = toBlockNumber(_config.filesystem_start().sector(), | ||||||
|             _config.filesystem_start().track()); |             _config.filesystem_start().track()); | ||||||
| @@ -319,7 +321,9 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Filesystem> Filesystem::createZDosFilesystem( | std::unique_ptr<Filesystem> Filesystem::createZDosFilesystem( | ||||||
|     const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors) |     const FilesystemProto& config, | ||||||
|  |     const std::shared_ptr<const DiskLayout>& diskLayout, | ||||||
|  |     std::shared_ptr<SectorInterface> sectors) | ||||||
| { | { | ||||||
|     return std::make_unique<ZDosFilesystem>(config.zdos(), sectors); |     return std::make_unique<ZDosFilesystem>(config.zdos(), diskLayout, sectors); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -44,9 +44,9 @@ int mainConvert(int argc, const char* argv[]) | |||||||
|     auto locations = globalConfig()->drive().tracks(); |     auto locations = globalConfig()->drive().tracks(); | ||||||
|     globalConfig().overrides()->set_tracks(locations); |     globalConfig().overrides()->set_tracks(locations); | ||||||
|  |  | ||||||
|     auto physicalLocations = Layout::computePhysicalLocations(); |     auto diskLayout = createDiskLayout(globalConfig()); | ||||||
|     auto [minCylinder, maxCylinder, minHead, maxHead] = |     auto [minCylinder, maxCylinder, minHead, maxHead] = | ||||||
|         Layout::getBounds(physicalLocations); |         diskLayout->getPhysicalBounds(); | ||||||
|     log("CONVERT: seen cylinders {}..{}, heads {}..{}", |     log("CONVERT: seen cylinders {}..{}, heads {}..{}", | ||||||
|         minCylinder, |         minCylinder, | ||||||
|         maxCylinder, |         maxCylinder, | ||||||
| @@ -55,7 +55,7 @@ int mainConvert(int argc, const char* argv[]) | |||||||
|  |  | ||||||
|     auto fluxSink = FluxSink::create(globalConfig()); |     auto fluxSink = FluxSink::create(globalConfig()); | ||||||
|  |  | ||||||
|     for (const auto& physicalLocation : physicalLocations) |     for (const auto& physicalLocation : diskLayout->physicalLocations) | ||||||
|     { |     { | ||||||
|         auto fi = fluxSource->readFlux(physicalLocation); |         auto fi = fluxSource->readFlux(physicalLocation); | ||||||
|         while (fi->hasNext()) |         while (fi->hasNext()) | ||||||
|   | |||||||
| @@ -143,7 +143,7 @@ void AbstractSectorView::drawContent() | |||||||
|                         }; |                         }; | ||||||
|  |  | ||||||
|                         auto block = findOptionally( |                         auto block = findOptionally( | ||||||
|                             diskFlux->layout->blockIdByLogicalLocation, |                             diskFlux->layout->blockIdByLogicalSectorLocation, | ||||||
|                             {sector->logicalCylinder, |                             {sector->logicalCylinder, | ||||||
|                                 sector->logicalHead, |                                 sector->logicalHead, | ||||||
|                                 sector->logicalSector}); |                                 sector->logicalSector}); | ||||||
|   | |||||||
| @@ -25,5 +25,5 @@ public: | |||||||
| protected: | protected: | ||||||
|     virtual std::shared_ptr<const Sector> getSector( |     virtual std::shared_ptr<const Sector> getSector( | ||||||
|         unsigned cylinder, unsigned head, unsigned sectorId) = 0; |         unsigned cylinder, unsigned head, unsigned sectorId) = 0; | ||||||
|     virtual Layout::LayoutBounds getBounds() = 0; |     virtual DiskLayout::LayoutBounds getBounds() = 0; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -44,14 +44,12 @@ static std::atomic<bool> failed; | |||||||
| static bool formattingSupported; | static bool formattingSupported; | ||||||
| static std::map<std::string, Datastore::Device> devices; | static std::map<std::string, Datastore::Device> devices; | ||||||
| static std::shared_ptr<const DiskLayout> diskLayout; | static std::shared_ptr<const DiskLayout> diskLayout; | ||||||
| static std::map<CylinderHead, std::shared_ptr<const TrackInfo>> |  | ||||||
|     physicalCylinderLayouts; |  | ||||||
| static std::map<CylinderHeadSector, std::shared_ptr<const Sector>> | static std::map<CylinderHeadSector, std::shared_ptr<const Sector>> | ||||||
|     sectorByPhysicalLocation; |     sectorByPhysicalLocation; | ||||||
| static std::map<LogicalLocation, std::shared_ptr<const Sector>> | static std::map<LogicalLocation, std::shared_ptr<const Sector>> | ||||||
|     sectorByLogicalLocation; |     sectorByLogicalLocation; | ||||||
| static Layout::LayoutBounds diskPhysicalBounds; | static DiskLayout::LayoutBounds diskPhysicalBounds; | ||||||
| static Layout::LayoutBounds diskLogicalBounds; | static DiskLayout::LayoutBounds diskLogicalBounds; | ||||||
|  |  | ||||||
| static void wtRebuildConfiguration(); | static void wtRebuildConfiguration(); | ||||||
|  |  | ||||||
| @@ -200,7 +198,7 @@ void Datastore::init() | |||||||
|             { |             { | ||||||
|                 auto sector = it->second; |                 auto sector = it->second; | ||||||
|                 unsigned offset = |                 unsigned offset = | ||||||
|                     diskFlux->layout->sectorOffsetByLogicalLocation.at( |                     diskFlux->layout->sectorOffsetByLogicalSectorLocation.at( | ||||||
|                         {sector->logicalCylinder, |                         {sector->logicalCylinder, | ||||||
|                             sector->logicalHead, |                             sector->logicalHead, | ||||||
|                             sector->logicalSector}); |                             sector->logicalSector}); | ||||||
| @@ -226,10 +224,10 @@ void Datastore::init() | |||||||
|             unsigned lastSectorId = ltl->filesystemSectorOrder.back(); |             unsigned lastSectorId = ltl->filesystemSectorOrder.back(); | ||||||
|  |  | ||||||
|             unsigned startOffset = |             unsigned startOffset = | ||||||
|                 diskFlux->layout->sectorOffsetByLogicalLocation.at( |                 diskFlux->layout->sectorOffsetByLogicalSectorLocation.at( | ||||||
|                     {ltl->logicalCylinder, ltl->logicalHead, firstSectorId}); |                     {ltl->logicalCylinder, ltl->logicalHead, firstSectorId}); | ||||||
|             unsigned endOffset = |             unsigned endOffset = | ||||||
|                 diskFlux->layout->sectorOffsetByLogicalLocation.at( |                 diskFlux->layout->sectorOffsetByLogicalSectorLocation.at( | ||||||
|                     {ltl->logicalCylinder, ltl->logicalHead, lastSectorId}) + |                     {ltl->logicalCylinder, ltl->logicalHead, lastSectorId}) + | ||||||
|                 ltl->sectorSize; |                 ltl->sectorSize; | ||||||
|  |  | ||||||
| @@ -393,8 +391,8 @@ void wtRebuildConfiguration() | |||||||
|     bool formattingSupported = false; |     bool formattingSupported = false; | ||||||
|     try |     try | ||||||
|     { |     { | ||||||
|         auto filesystem = |         auto filesystem = Filesystem::createFilesystem( | ||||||
|             Filesystem::createFilesystem(globalConfig()->filesystem(), nullptr); |             globalConfig()->filesystem(), diskLayout, nullptr); | ||||||
|         uint32_t flags = filesystem->capabilities(); |         uint32_t flags = filesystem->capabilities(); | ||||||
|         formattingSupported = flags & Filesystem::OP_CREATE; |         formattingSupported = flags & Filesystem::OP_CREATE; | ||||||
|     } |     } | ||||||
| @@ -404,14 +402,8 @@ void wtRebuildConfiguration() | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     auto diskLayout = createDiskLayout(); |     auto diskLayout = createDiskLayout(); | ||||||
|     auto locations = Layout::computePhysicalLocations(); |     auto diskPhysicalBounds = diskLayout->getPhysicalBounds(); | ||||||
|     auto diskPhysicalBounds = Layout::getBounds(locations); |     auto diskLogicalBounds = diskLayout->getLogicalBounds(); | ||||||
|     auto diskLogicalBounds = |  | ||||||
|         Layout::getBounds(Layout::computeLogicalLocations()); |  | ||||||
|  |  | ||||||
|     decltype(::physicalCylinderLayouts) physicalCylinderLayouts; |  | ||||||
|     for (auto& it : locations) |  | ||||||
|         physicalCylinderLayouts[it] = Layout::getLayoutOfTrackPhysical(it); |  | ||||||
|  |  | ||||||
|     hex::TaskManager::doLater( |     hex::TaskManager::doLater( | ||||||
|         [=] |         [=] | ||||||
| @@ -420,7 +412,6 @@ void wtRebuildConfiguration() | |||||||
|             ::diskLayout = diskLayout; |             ::diskLayout = diskLayout; | ||||||
|             ::diskPhysicalBounds = diskPhysicalBounds; |             ::diskPhysicalBounds = diskPhysicalBounds; | ||||||
|             ::diskLogicalBounds = diskLogicalBounds; |             ::diskLogicalBounds = diskLogicalBounds; | ||||||
|             ::physicalCylinderLayouts = physicalCylinderLayouts; |  | ||||||
|             rebuildDecodedDiskIndices(); |             rebuildDecodedDiskIndices(); | ||||||
|         }); |         }); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -66,17 +66,17 @@ void DiskProvider::readRaw(u64 offset, void* buffer, size_t size) | |||||||
|         while (size != 0) |         while (size != 0) | ||||||
|         { |         { | ||||||
|             auto it = |             auto it = | ||||||
|                 diskFlux->layout->logicalLocationBySectorOffset.upper_bound( |                 diskFlux->layout->logicalSectorLocationBySectorOffset.upper_bound( | ||||||
|                     offset); |                     offset); | ||||||
|             if (it != diskFlux->layout->logicalLocationBySectorOffset.begin()) |             if (it != diskFlux->layout->logicalSectorLocationBySectorOffset.begin()) | ||||||
|                 it--; |                 it--; | ||||||
|  |  | ||||||
|             unsigned realOffset = it->first; |             unsigned realOffset = it->first; | ||||||
|             auto logicalLocation = it->second; |             auto logicalLocation = it->second; | ||||||
|             auto sector = diskFlux->image->get(logicalLocation); |             auto sector = diskFlux->image->get(logicalLocation); | ||||||
|             unsigned blockOffset = realOffset - offset; |             unsigned blockOffset = realOffset - offset; | ||||||
|             unsigned bytesRemaining = std::min( |             unsigned bytesRemaining = | ||||||
|                 (unsigned)size, sector->data.size() - blockOffset); |                 std::min((unsigned)size, sector->data.size() - blockOffset); | ||||||
|             auto bytes = sector->data.slice(blockOffset, bytesRemaining); |             auto bytes = sector->data.slice(blockOffset, bytesRemaining); | ||||||
|             memcpy(buffer, bytes.cbegin(), bytes.size()); |             memcpy(buffer, bytes.cbegin(), bytes.size()); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ using namespace hex; | |||||||
|  |  | ||||||
| ImageView::ImageView(): AbstractSectorView("fluxengine.view.image.name") {} | ImageView::ImageView(): AbstractSectorView("fluxengine.view.image.name") {} | ||||||
|  |  | ||||||
| Layout::LayoutBounds ImageView::getBounds() | DiskLayout::LayoutBounds ImageView::getBounds() | ||||||
| { | { | ||||||
|     return Datastore::getDiskLayout()->getLogicalBounds(); |     return Datastore::getDiskLayout()->getLogicalBounds(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,5 +10,5 @@ public: | |||||||
|  |  | ||||||
|     std::shared_ptr<const Sector> getSector( |     std::shared_ptr<const Sector> getSector( | ||||||
|         unsigned cylinder, unsigned head, unsigned sectorId) override; |         unsigned cylinder, unsigned head, unsigned sectorId) override; | ||||||
|     Layout::LayoutBounds getBounds() override; |     DiskLayout::LayoutBounds getBounds() override; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ PhysicalView::PhysicalView(): | |||||||
|  |  | ||||||
| PhysicalView::~PhysicalView() {} | PhysicalView::~PhysicalView() {} | ||||||
|  |  | ||||||
| Layout::LayoutBounds PhysicalView::getBounds() | DiskLayout::LayoutBounds PhysicalView::getBounds() | ||||||
| { | { | ||||||
|     return Datastore::getDiskLayout()->getPhysicalBounds(); |     return Datastore::getDiskLayout()->getPhysicalBounds(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,5 +11,5 @@ public: | |||||||
|  |  | ||||||
|     std::shared_ptr<const Sector> getSector( |     std::shared_ptr<const Sector> getSector( | ||||||
|         unsigned cylinder, unsigned head, unsigned sectorId) override; |         unsigned cylinder, unsigned head, unsigned sectorId) override; | ||||||
|     Layout::LayoutBounds getBounds() override; |     DiskLayout::LayoutBounds getBounds() override; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
| #include "lib/data/image.h" | #include "lib/data/image.h" | ||||||
| #include "lib/config/proto.h" | #include "lib/config/proto.h" | ||||||
| #include "lib/data/sector.h" | #include "lib/data/sector.h" | ||||||
|  | #include "lib/data/layout.h" | ||||||
| #include "snowhouse/snowhouse.h" | #include "snowhouse/snowhouse.h" | ||||||
| #include <google/protobuf/text_format.h> | #include <google/protobuf/text_format.h> | ||||||
|  |  | ||||||
| @@ -13,11 +14,21 @@ using namespace snowhouse; | |||||||
|  |  | ||||||
| static Bytes blank_dirent = Bytes{0xe5} * 32; | static Bytes blank_dirent = Bytes{0xe5} * 32; | ||||||
|  |  | ||||||
|  | /* The layout must use one cylinder per CP/M block (eight sectors). */ | ||||||
|  |  | ||||||
|  | static std::shared_ptr<const DiskLayout> diskLayout = | ||||||
|  |     std::make_shared<DiskLayout>(10, 1, 8, 256); | ||||||
|  |  | ||||||
| namespace | namespace | ||||||
| { | { | ||||||
|     class TestSectorInterface : public SectorInterface |     class TestSectorInterface : public SectorInterface | ||||||
|     { |     { | ||||||
|     public: |     public: | ||||||
|  |         TestSectorInterface() | ||||||
|  |         { | ||||||
|  |             _image.addMissingSectors(*diskLayout, true); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         std::shared_ptr<const Sector> get( |         std::shared_ptr<const Sector> get( | ||||||
|             unsigned track, unsigned side, unsigned sectorId) override |             unsigned track, unsigned side, unsigned sectorId) override | ||||||
|         { |         { | ||||||
| @@ -125,7 +136,7 @@ static void testPartialExtent() | |||||||
| { | { | ||||||
|     auto sectors = std::make_shared<TestSectorInterface>(); |     auto sectors = std::make_shared<TestSectorInterface>(); | ||||||
|     auto fs = Filesystem::createCpmFsFilesystem( |     auto fs = Filesystem::createCpmFsFilesystem( | ||||||
|         globalConfig()->filesystem(), sectors); |         globalConfig()->filesystem(), diskLayout, sectors); | ||||||
|  |  | ||||||
|     setBlock(sectors, |     setBlock(sectors, | ||||||
|         0, |         0, | ||||||
| @@ -145,7 +156,7 @@ static void testLogicalExtents() | |||||||
| { | { | ||||||
|     auto sectors = std::make_shared<TestSectorInterface>(); |     auto sectors = std::make_shared<TestSectorInterface>(); | ||||||
|     auto fs = Filesystem::createCpmFsFilesystem( |     auto fs = Filesystem::createCpmFsFilesystem( | ||||||
|         globalConfig()->filesystem(), sectors); |         globalConfig()->filesystem(), diskLayout, sectors); | ||||||
|  |  | ||||||
|     setBlock(sectors, |     setBlock(sectors, | ||||||
|         0, |         0, | ||||||
| @@ -169,7 +180,7 @@ static void testBitmap() | |||||||
| { | { | ||||||
|     auto sectors = std::make_shared<TestSectorInterface>(); |     auto sectors = std::make_shared<TestSectorInterface>(); | ||||||
|     auto fs = Filesystem::createCpmFsFilesystem( |     auto fs = Filesystem::createCpmFsFilesystem( | ||||||
|         globalConfig()->filesystem(), sectors); |         globalConfig()->filesystem(), diskLayout, sectors); | ||||||
|  |  | ||||||
|     setBlock(sectors, |     setBlock(sectors, | ||||||
|         0, |         0, | ||||||
|   | |||||||
							
								
								
									
										139
									
								
								tests/layout.cc
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								tests/layout.cc
									
									
									
									
									
								
							| @@ -54,29 +54,16 @@ static void test_physical_sectors() | |||||||
| 		} | 		} | ||||||
| 	)M"); | 	)M"); | ||||||
|  |  | ||||||
|     { |     auto diskLayout = createDiskLayout(); | ||||||
|         auto layout = Layout::getLayoutOfTrack(0, 0); |     auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); | ||||||
|         AssertThat(layout->naturalSectorOrder, |     auto layout = physicalLayout->logicalTrackLayout; | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |     AssertThat(diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); | ||||||
|         AssertThat( |     AssertThat( | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 2, 1, 3})); |         layout->naturalSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); | ||||||
|         AssertThat(layout->filesystemSectorOrder, |     AssertThat( | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |         layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 2, 1, 3})); | ||||||
|     } |     AssertThat(layout->filesystemSectorOrder, | ||||||
|  |         Equals(std::vector<unsigned>{0, 1, 2, 3})); | ||||||
|     { |  | ||||||
|         auto diskLayout = createDiskLayout(); |  | ||||||
|         auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); |  | ||||||
|         auto layout = physicalLayout->logicalTrackLayout; |  | ||||||
|         AssertThat( |  | ||||||
|             diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); |  | ||||||
|         AssertThat(layout->naturalSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |  | ||||||
|         AssertThat( |  | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 2, 1, 3})); |  | ||||||
|         AssertThat(layout->filesystemSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void test_logical_sectors() | static void test_logical_sectors() | ||||||
| @@ -109,29 +96,16 @@ static void test_logical_sectors() | |||||||
| 		} | 		} | ||||||
| 	)M"); | 	)M"); | ||||||
|  |  | ||||||
|     { |     auto diskLayout = createDiskLayout(); | ||||||
|         auto layout = Layout::getLayoutOfTrack(0, 0); |     auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); | ||||||
|         AssertThat(layout->naturalSectorOrder, |     auto layout = physicalLayout->logicalTrackLayout; | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |     AssertThat(diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); | ||||||
|         AssertThat( |     AssertThat( | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); |         layout->naturalSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); | ||||||
|         AssertThat(layout->filesystemSectorOrder, |     AssertThat( | ||||||
|             Equals(std::vector<unsigned>{0, 2, 1, 3})); |         layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); | ||||||
|     } |     AssertThat(layout->filesystemSectorOrder, | ||||||
|  |         Equals(std::vector<unsigned>{0, 2, 1, 3})); | ||||||
|     { |  | ||||||
|         auto diskLayout = createDiskLayout(); |  | ||||||
|         auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); |  | ||||||
|         auto layout = physicalLayout->logicalTrackLayout; |  | ||||||
|         AssertThat( |  | ||||||
|             diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); |  | ||||||
|         AssertThat(layout->naturalSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |  | ||||||
|         AssertThat( |  | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); |  | ||||||
|         AssertThat(layout->filesystemSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 2, 1, 3})); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void test_both_sectors() | static void test_both_sectors() | ||||||
| @@ -164,29 +138,16 @@ static void test_both_sectors() | |||||||
| 		} | 		} | ||||||
| 	)M"); | 	)M"); | ||||||
|  |  | ||||||
|     { |     auto diskLayout = createDiskLayout(); | ||||||
|         auto layout = Layout::getLayoutOfTrack(0, 0); |     auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); | ||||||
|         AssertThat(layout->naturalSectorOrder, |     auto layout = physicalLayout->logicalTrackLayout; | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |     AssertThat(diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); | ||||||
|         AssertThat( |     AssertThat( | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{3, 2, 1, 0})); |         layout->naturalSectorOrder, Equals(std::vector<unsigned>{0, 1, 2, 3})); | ||||||
|         AssertThat(layout->filesystemSectorOrder, |     AssertThat( | ||||||
|             Equals(std::vector<unsigned>{0, 2, 1, 3})); |         layout->diskSectorOrder, Equals(std::vector<unsigned>{3, 2, 1, 0})); | ||||||
|     } |     AssertThat(layout->filesystemSectorOrder, | ||||||
|  |         Equals(std::vector<unsigned>{0, 2, 1, 3})); | ||||||
|     { |  | ||||||
|         auto diskLayout = createDiskLayout(); |  | ||||||
|         auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); |  | ||||||
|         auto layout = physicalLayout->logicalTrackLayout; |  | ||||||
|         AssertThat( |  | ||||||
|             diskLayout->layoutByLogicalLocation.at({0, 0}), Equals(layout)); |  | ||||||
|         AssertThat(layout->naturalSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 1, 2, 3})); |  | ||||||
|         AssertThat( |  | ||||||
|             layout->diskSectorOrder, Equals(std::vector<unsigned>{3, 2, 1, 0})); |  | ||||||
|         AssertThat(layout->filesystemSectorOrder, |  | ||||||
|             Equals(std::vector<unsigned>{0, 2, 1, 3})); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void test_skew() | static void test_skew() | ||||||
| @@ -212,27 +173,13 @@ static void test_skew() | |||||||
| 		} | 		} | ||||||
| 	)M"); | 	)M"); | ||||||
|  |  | ||||||
|     { |     auto diskLayout = createDiskLayout(); | ||||||
|         auto layout = Layout::getLayoutOfTrack(0, 0); |     auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); | ||||||
|         AssertThat(layout->naturalSectorOrder, |     auto layout = physicalLayout->logicalTrackLayout; | ||||||
|             Equals( |     AssertThat(layout->naturalSectorOrder, | ||||||
|                 std::vector<unsigned>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})); |         Equals(std::vector<unsigned>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})); | ||||||
|         AssertThat(layout->diskSectorOrder, |     AssertThat(layout->diskSectorOrder, | ||||||
|             Equals( |         Equals(std::vector<unsigned>{0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11})); | ||||||
|                 std::vector<unsigned>{0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11})); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     { |  | ||||||
|         auto diskLayout = createDiskLayout(); |  | ||||||
|         auto physicalLayout = diskLayout->layoutByPhysicalLocation.at({0, 0}); |  | ||||||
|         auto layout = physicalLayout->logicalTrackLayout; |  | ||||||
|         AssertThat(layout->naturalSectorOrder, |  | ||||||
|             Equals( |  | ||||||
|                 std::vector<unsigned>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})); |  | ||||||
|         AssertThat(layout->diskSectorOrder, |  | ||||||
|             Equals( |  | ||||||
|                 std::vector<unsigned>{0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11})); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void test_bounds() | static void test_bounds() | ||||||
| @@ -261,9 +208,9 @@ static void test_bounds() | |||||||
|     auto diskLayout = createDiskLayout(); |     auto diskLayout = createDiskLayout(); | ||||||
|     AssertThat(diskLayout->groupSize, Equals(2)); |     AssertThat(diskLayout->groupSize, Equals(2)); | ||||||
|     AssertThat(diskLayout->getLogicalBounds(), |     AssertThat(diskLayout->getLogicalBounds(), | ||||||
|         Equals(Layout::LayoutBounds{0, 1, 0, 1})); |         Equals(DiskLayout::LayoutBounds{0, 1, 0, 1})); | ||||||
|     AssertThat(diskLayout->getPhysicalBounds(), |     AssertThat(diskLayout->getPhysicalBounds(), | ||||||
|         Equals(Layout::LayoutBounds{0, 3, 0, 1})); |         Equals(DiskLayout::LayoutBounds{0, 3, 0, 1})); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename K, typename V> | template <typename K, typename V> | ||||||
| @@ -301,8 +248,8 @@ static void test_sectoroffsets() | |||||||
|  |  | ||||||
|     auto diskLayout = createDiskLayout(); |     auto diskLayout = createDiskLayout(); | ||||||
|     AssertThat(diskLayout->groupSize, Equals(1)); |     AssertThat(diskLayout->groupSize, Equals(1)); | ||||||
|     AssertThat(diskLayout->logicalLocationBySectorOffset, |     AssertThat(diskLayout->logicalSectorLocationBySectorOffset, | ||||||
|         EqualsContainer(decltype(diskLayout->logicalLocationBySectorOffset){ |         EqualsContainer(decltype(diskLayout->logicalSectorLocationBySectorOffset){ | ||||||
|             {0,    {0, 0, 0}}, |             {0,    {0, 0, 0}}, | ||||||
|             {256,  {0, 0, 2}}, |             {256,  {0, 0, 2}}, | ||||||
|             {512,  {0, 0, 1}}, |             {512,  {0, 0, 1}}, | ||||||
| @@ -320,8 +267,8 @@ static void test_sectoroffsets() | |||||||
|             {3584, {1, 1, 1}}, |             {3584, {1, 1, 1}}, | ||||||
|             {3840, {1, 1, 3}} |             {3840, {1, 1, 3}} | ||||||
|     })); |     })); | ||||||
|     AssertThat(diskLayout->sectorOffsetByLogicalLocation, |     AssertThat(diskLayout->sectorOffsetByLogicalSectorLocation, | ||||||
|         EqualsContainer(decltype(diskLayout->sectorOffsetByLogicalLocation){ |         EqualsContainer(decltype(diskLayout->sectorOffsetByLogicalSectorLocation){ | ||||||
|             {{0, 0, 0}, 0   }, |             {{0, 0, 0}, 0   }, | ||||||
|             {{0, 0, 1}, 512 }, |             {{0, 0, 1}, 512 }, | ||||||
|             {{0, 0, 2}, 256 }, |             {{0, 0, 2}, 256 }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user