mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			13 Commits
		
	
	
		
			hardsector
			...
			geometry
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 8e5e4d3f5b | ||
|  | 3b81e84e05 | ||
|  | b8c198329d | ||
|  | 1b85464b85 | ||
|  | 9231325073 | ||
|  | 644f592df3 | ||
|  | dee44bf481 | ||
|  | 1fcb8c7179 | ||
|  | 1440c3c8d6 | ||
|  | 2935c2d925 | ||
|  | ebc25f9758 | ||
|  | 99b9145a0d | ||
|  | e7348eaa4f | 
| @@ -14,6 +14,7 @@ class Fluxmap; | ||||
| class SectorSet; | ||||
| class AmigaDecoderProto; | ||||
| class AmigaEncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class AmigaDecoder : public AbstractDecoder | ||||
| { | ||||
| @@ -30,15 +31,18 @@ public: | ||||
| class AmigaEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	AmigaEncoder(const AmigaEncoderProto& config): | ||||
| 		_config(config) {} | ||||
| 	AmigaEncoder(const AmigaEncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
| 	virtual ~AmigaEncoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	const AmigaEncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| }; | ||||
|  | ||||
| extern uint32_t amigaChecksum(const Bytes& bytes); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "geometry/geometry.h" | ||||
|  | ||||
| FlagGroup amigaEncoderFlags; | ||||
|  | ||||
| @@ -99,8 +100,7 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector | ||||
| 	write_bits(bits, cursor, dataBits); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> AmigaEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> AmigaEncoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK)) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
| @@ -114,8 +114,9 @@ std::unique_ptr<Fluxmap> AmigaEncoder::encode( | ||||
|  | ||||
| 	for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++) | ||||
| 	{ | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		write_sector(bits, cursor, sectorData); | ||||
| 		const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
| 		if (sectorData) | ||||
| 			write_sector(bits, cursor, sectorData); | ||||
|     } | ||||
|  | ||||
| 	if (cursor >= bits.size()) | ||||
|   | ||||
| @@ -18,6 +18,7 @@ class SectorSet; | ||||
| class Fluxmap; | ||||
| class BrotherDecoderProto; | ||||
| class BrotherEncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class BrotherDecoder : public AbstractDecoder | ||||
| { | ||||
| @@ -33,17 +34,19 @@ public: | ||||
| class BrotherEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	BrotherEncoder(const BrotherEncoderProto& config): | ||||
| 		_config(config) | ||||
| 	BrotherEncoder(const BrotherEncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~BrotherEncoder() {} | ||||
|  | ||||
| private: | ||||
| 	const BrotherEncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "arch/brother/brother.pb.h" | ||||
| #include "geometry/geometry.h" | ||||
|  | ||||
| FlagGroup brotherEncoderFlags; | ||||
|  | ||||
| @@ -127,8 +128,7 @@ static int charToInt(char c) | ||||
| 	return 10 + tolower(c) - 'a'; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> BrotherEncoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	int logicalTrack; | ||||
| 	if (physicalSide != 0) | ||||
| @@ -163,7 +163,7 @@ std::unique_ptr<Fluxmap> BrotherEncoder::encode( | ||||
| 		double dataMs = headerMs + postHeaderSpacingMs; | ||||
| 		unsigned dataCursor = dataMs*1e3 / clockRateUs; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(logicalTrack, 0, sectorId); | ||||
| 		const auto& sectorData = _mapper.get(logicalTrack, 0, sectorId); | ||||
|  | ||||
| 		fillBitmapTo(bits, cursor, headerCursor, { true, false }); | ||||
| 		write_sector_header(bits, cursor, logicalTrack, sectorId); | ||||
|   | ||||
| @@ -32,6 +32,7 @@ class Sector; | ||||
| class Fluxmap; | ||||
| class Commodore64DecoderProto; | ||||
| class Commodore64EncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class Commodore64Decoder : public AbstractDecoder | ||||
| { | ||||
| @@ -47,17 +48,19 @@ public: | ||||
| class Commodore64Encoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	Commodore64Encoder(const Commodore64EncoderProto& config): | ||||
| 		_config(config) | ||||
| 	Commodore64Encoder(const Commodore64EncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~Commodore64Encoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	const Commodore64EncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "writer.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/c64/c64.pb.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include <ctype.h> | ||||
| #include "bytes.h" | ||||
|  | ||||
| @@ -293,8 +294,7 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector | ||||
|     } | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> Commodore64Encoder::encode( | ||||
|     int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> Commodore64Encoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
|     /* The format ID Character # 1 and # 2 are in the .d64 image only present | ||||
|      * in track 18 sector zero which contains the BAM info in byte 162 and 163. | ||||
| @@ -305,7 +305,7 @@ std::unique_ptr<Fluxmap> Commodore64Encoder::encode( | ||||
|     if ((physicalTrack < 0) || (physicalTrack >= C64_TRACKS_PER_DISK)) | ||||
|         return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
|     const auto& sectorData = allSectors.get(C64_BAM_TRACK, 0, 0); //Read de BAM to get the DISK ID bytes | ||||
|     const auto* sectorData = _mapper.get(C64_BAM_TRACK, 0, 0); //Read de BAM to get the DISK ID bytes | ||||
|  | ||||
|     ByteReader br(sectorData->data); | ||||
|     br.seek(162); //goto position of the first Disk ID Byte | ||||
| @@ -325,7 +325,7 @@ std::unique_ptr<Fluxmap> Commodore64Encoder::encode( | ||||
|     unsigned numSectors = sectorsForTrack(physicalTrack); | ||||
|     for (int sectorId=0; sectorId<numSectors; sectorId++) | ||||
|     { | ||||
|         const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
|         const auto& sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
|         write_sector(bits, cursor, sectorData); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "arch/ibm/ibm.pb.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include <ctype.h> | ||||
|  | ||||
| @@ -99,8 +100,7 @@ void IbmEncoder::getTrackFormat(IbmEncoderProto::TrackdataProto& trackdata, unsi | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> IbmEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> IbmEncoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	IbmEncoderProto::TrackdataProto trackdata; | ||||
| 	getTrackFormat(trackdata, physicalTrack, physicalSide); | ||||
| @@ -165,7 +165,7 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode( | ||||
| 			writeFillerBytes(trackdata.gap3(), gapFill); | ||||
| 		first = false; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
| 		if (!sectorData) | ||||
| 		{ | ||||
| 			/* If there are any missing sectors, this is an empty track. */ | ||||
|   | ||||
| @@ -30,6 +30,8 @@ struct IbmIdam | ||||
|     uint8_t crc[2]; | ||||
| }; | ||||
|  | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class IbmDecoder : public AbstractDecoder | ||||
| { | ||||
| public: | ||||
| @@ -52,14 +54,15 @@ private: | ||||
| class IbmEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	IbmEncoder(const IbmEncoderProto& config): | ||||
| 		_config(config) | ||||
| 	IbmEncoder(const IbmEncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~IbmEncoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	void writeRawBits(uint32_t data, int width); | ||||
| @@ -69,6 +72,7 @@ private: | ||||
|  | ||||
| private: | ||||
| 	const IbmEncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| 	std::vector<bool> _bits; | ||||
| 	unsigned _cursor; | ||||
| 	bool _lastBit; | ||||
|   | ||||
| @@ -6,21 +6,11 @@ | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/macintosh/macintosh.pb.h" | ||||
| #include <ctype.h> | ||||
|  | ||||
| FlagGroup macintoshEncoderFlags; | ||||
|  | ||||
| static DoubleFlag postIndexGapUs( | ||||
| 	{ "--post-index-gap-us" }, | ||||
| 	"Post-index gap before first sector header (microseconds).", | ||||
| 	0); | ||||
|  | ||||
| static DoubleFlag clockCompensation( | ||||
| 	{ "--clock-compensation-factor" }, | ||||
| 	"Scale the output clock by this much.", | ||||
| 	1.0); | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
| static double clockRateUsForTrack(unsigned track) | ||||
| @@ -210,25 +200,25 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector | ||||
| 	write_bits(bits, cursor, 0xdeaaff, 3*8); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> MacintoshEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> MacintoshEncoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK)) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 	double clockRateUs = clockRateUsForTrack(physicalTrack) * clockCompensation; | ||||
| 	int bitsPerRevolution = 200000.0 / clockRateUs; | ||||
| 	double clockRateUs = clockRateUsForTrack(physicalTrack) * _config.clock_compensation_factor(); | ||||
| 	int bitsPerRevolution = 200000.0 / _config.clock_compensation_factor(); | ||||
| 	std::vector<bool> bits(bitsPerRevolution); | ||||
| 	unsigned cursor = 0; | ||||
|  | ||||
|     fillBitmapTo(bits, cursor, postIndexGapUs / clockRateUs, { true, false }); | ||||
|     fillBitmapTo(bits, cursor, _config.post_index_gap_us() / _config.clock_compensation_factor(), { true, false }); | ||||
| 	lastBit = false; | ||||
|  | ||||
| 	unsigned numSectors = sectorsForTrack(physicalTrack); | ||||
| 	for (int sectorId=0; sectorId<numSectors; sectorId++) | ||||
| 	{ | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		write_sector(bits, cursor, sectorData); | ||||
| 		const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
| 		if (sectorData) | ||||
| 			write_sector(bits, cursor, sectorData); | ||||
|     } | ||||
|  | ||||
| 	if (cursor >= bits.size()) | ||||
|   | ||||
| @@ -17,6 +17,7 @@ class Sector; | ||||
| class Fluxmap; | ||||
| class MacintoshDecoderProto; | ||||
| class MacintoshEncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class MacintoshDecoder : public AbstractDecoder | ||||
| { | ||||
| @@ -34,11 +35,19 @@ public: | ||||
| class MacintoshEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	MacintoshEncoder(const MacintoshEncoderProto&) {} | ||||
| 	MacintoshEncoder(const MacintoshEncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~MacintoshEncoder() {} | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	const MacintoshEncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| }; | ||||
|  | ||||
| extern FlagGroup macintoshEncoderFlags; | ||||
|   | ||||
| @@ -1,5 +1,13 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| message MacintoshDecoderProto {} | ||||
| message MacintoshEncoderProto {} | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message MacintoshDecoderProto {} | ||||
|  | ||||
| message MacintoshEncoderProto { | ||||
| 	optional double post_index_gap_us = 1 | ||||
| 		[default=0.0, (help)="Post-index gap before first sector header."]; | ||||
| 	optional double clock_compensation_factor = 2 | ||||
| 		[default=1.0, (help)="Scale the output clock by this much."]; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #include "globals.h" | ||||
| #include "northstar.h" | ||||
| #include "sectorset.h" | ||||
| #include "geometry/geometry.h" | ||||
|  | ||||
| #define GAP_FILL_SIZE_SD 30 | ||||
| #define PRE_HEADER_GAP_FILL_SIZE_SD 9 | ||||
| @@ -95,8 +96,7 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> NorthstarEncoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> NorthstarEncoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	int bitsPerRevolution = 100000; | ||||
| 	double clockRateUs = 4.00; | ||||
| @@ -104,7 +104,7 @@ std::unique_ptr<Fluxmap> NorthstarEncoder::encode( | ||||
| 	if ((physicalTrack < 0) || (physicalTrack >= 35)) | ||||
| 		return std::unique_ptr<Fluxmap>(); | ||||
|  | ||||
| 	const auto& sector = allSectors.get(physicalTrack, physicalSide, 0); | ||||
| 	const auto* sector = _mapper.get(physicalTrack, physicalSide, 0); | ||||
|  | ||||
| 	if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) { | ||||
| 		bitsPerRevolution /= 2;		// FM | ||||
| @@ -117,7 +117,7 @@ std::unique_ptr<Fluxmap> NorthstarEncoder::encode( | ||||
|  | ||||
| 	for (int sectorId = 0; sectorId < 10; sectorId++) | ||||
| 	{ | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
| 		write_sector(bits, cursor, sectorData); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -30,6 +30,7 @@ | ||||
|  | ||||
| class NorthstarEncoderProto; | ||||
| class NorthstarDecoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class NorthstarDecoder : public AbstractDecoder | ||||
| { | ||||
| @@ -55,15 +56,17 @@ private: | ||||
| class NorthstarEncoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	NorthstarEncoder(const NorthstarEncoderProto& config): | ||||
| 		_config(config) | ||||
| 	NorthstarEncoder(const NorthstarEncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
|  | ||||
| 	virtual ~NorthstarEncoder() {} | ||||
| 	std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
| 	std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	const NorthstarEncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| }; | ||||
|  | ||||
| extern FlagGroup northstarEncoderFlags; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include "crc.h" | ||||
| #include "sectorset.h" | ||||
| #include "writer.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "arch/tids990/tids990.pb.h" | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| @@ -49,8 +50,7 @@ static uint8_t decodeUint16(uint16_t raw) | ||||
| 	return decodeFmMfm(b.toBits())[0]; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Fluxmap> Tids990Encoder::encode( | ||||
| 	int physicalTrack, int physicalSide, const SectorSet& allSectors) | ||||
| std::unique_ptr<Fluxmap> Tids990Encoder::encode(int physicalTrack, int physicalSide) | ||||
| { | ||||
| 	double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0; | ||||
| 	int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs; | ||||
| @@ -70,7 +70,7 @@ std::unique_ptr<Fluxmap> Tids990Encoder::encode( | ||||
| 			writeBytes(_config.gap3_bytes(), 0x55); | ||||
| 		first = false; | ||||
|  | ||||
| 		const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId); | ||||
| 		const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId); | ||||
| 		if (!sectorData) | ||||
| 			Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId); | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,7 @@ class Fluxmap; | ||||
| class Track; | ||||
| class Tids990DecoderProto; | ||||
| class Tids990EncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class Tids990Decoder : public AbstractDecoder | ||||
| { | ||||
| @@ -26,8 +27,9 @@ public: | ||||
| class Tids990Encoder : public AbstractEncoder | ||||
| { | ||||
| public: | ||||
| 	Tids990Encoder(const Tids990EncoderProto& config): | ||||
| 		_config(config) | ||||
| 	Tids990Encoder(const Tids990EncoderProto& config, const DisassemblingGeometryMapper& mapper): | ||||
| 		_config(config), | ||||
| 		_mapper(mapper) | ||||
| 	{} | ||||
| 	virtual ~Tids990Encoder() {} | ||||
|  | ||||
| @@ -38,10 +40,11 @@ private: | ||||
| 	void writeSync(); | ||||
|  | ||||
| public: | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors); | ||||
|     std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide); | ||||
|  | ||||
| private: | ||||
| 	const Tids990EncoderProto& _config; | ||||
| 	const DisassemblingGeometryMapper& _mapper; | ||||
| 	std::vector<bool> _bits; | ||||
| 	unsigned _cursor; | ||||
| 	bool _lastBit; | ||||
|   | ||||
| @@ -32,9 +32,12 @@ fluxengine read northstar | ||||
| To read a single-sided North Star floppy, run: | ||||
|  | ||||
| ``` | ||||
| fluxengine read northstar -heads 0 | ||||
| fluxengine read <format> -heads 0 | ||||
| ``` | ||||
|  | ||||
| ...where `<format>` is `northstar87`, `northstar175` or `northstar350` | ||||
| depending on the format you want to read. | ||||
|  | ||||
| You should end up with a `northstar.nsi` with a file size dependent on the floppy | ||||
| disk type: | ||||
|  | ||||
|   | ||||
							
								
								
									
										18
									
								
								lib/bytes.cc
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								lib/bytes.cc
									
									
									
									
									
								
							| @@ -65,6 +65,14 @@ Bytes::Bytes(std::shared_ptr<std::vector<uint8_t>> data, unsigned start, unsigne | ||||
|     _high(end) | ||||
| {} | ||||
|  | ||||
| Bytes::Bytes(std::istream& stream, size_t size): | ||||
| 	_data(createVector(size)), | ||||
| 	_low(0), | ||||
| 	_high(size) | ||||
| { | ||||
| 	stream.read((char*)begin(), size); | ||||
| } | ||||
|  | ||||
| Bytes* Bytes::operator = (const Bytes& other) | ||||
| { | ||||
|     _data = other._data; | ||||
| @@ -130,14 +138,14 @@ uint8_t& Bytes::operator [] (unsigned pos) | ||||
|  | ||||
| Bytes Bytes::slice(unsigned start, unsigned len) const | ||||
| { | ||||
|     start += _low; | ||||
|     unsigned end = start + len; | ||||
|     if (start >= _high) | ||||
|     unsigned datastart = _low + start; | ||||
|     unsigned dataend = datastart + len; | ||||
|     if (datastart >= _high) | ||||
|     { | ||||
|         /* Asking for a completely out-of-range slice --- just return zeroes. */ | ||||
|         return Bytes(len); | ||||
|     } | ||||
|     else if (end > _high) | ||||
|     else if (dataend > _high) | ||||
|     { | ||||
|         /* Can't share the buffer, as we need to zero-pad the end. */ | ||||
|         Bytes b(len); | ||||
| @@ -147,7 +155,7 @@ Bytes Bytes::slice(unsigned start, unsigned len) const | ||||
|     else | ||||
|     { | ||||
|         /* Use the magic of shared_ptr to share the data. */ | ||||
|         Bytes b(_data, start, end); | ||||
|         Bytes b(_data, datastart, dataend); | ||||
|         return b; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										16
									
								
								lib/bytes.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								lib/bytes.h
									
									
									
									
									
								
							| @@ -16,6 +16,7 @@ public: | ||||
|     Bytes(std::initializer_list<uint8_t> data); | ||||
|     Bytes(std::shared_ptr<std::vector<uint8_t>> data); | ||||
|     Bytes(std::shared_ptr<std::vector<uint8_t>> data, unsigned start, unsigned end); | ||||
| 	Bytes(std::istream& stream, size_t len); | ||||
|  | ||||
|     Bytes* operator = (const Bytes& other); | ||||
|  | ||||
| @@ -64,6 +65,16 @@ public: | ||||
|     void writeToFile(const std::string& filename) const; | ||||
| 	void writeTo(std::ostream& stream) const; | ||||
|  | ||||
| 	template <class T> std::vector<T> toVector() const | ||||
| 	{ | ||||
| 		std::vector<T> v(size()); | ||||
| 		for (int i=0; i<size(); i++) | ||||
| 			v[i] = (*this)[i]; | ||||
| 		return v; | ||||
| 	} | ||||
|  | ||||
| 	std::vector<uint8_t> toVector() const; | ||||
|  | ||||
| private: | ||||
|     std::shared_ptr<std::vector<uint8_t>> _data; | ||||
|     unsigned _low; | ||||
| @@ -296,6 +307,11 @@ public: | ||||
|         return *this += stream; | ||||
|     } | ||||
|  | ||||
| 	ByteWriter& append(std::istream& stream, size_t len) | ||||
| 	{ | ||||
| 		return *this += Bytes(stream, len); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
|     Bytes& _bytes; | ||||
| }; | ||||
|   | ||||
| @@ -12,10 +12,14 @@ extend google.protobuf.FieldOptions { | ||||
|   optional string help = 50000; | ||||
| } | ||||
|  | ||||
| extend google.protobuf.EnumValueOptions { | ||||
|   optional string ehelp = 50000; | ||||
| } | ||||
|  | ||||
| enum IndexMode { | ||||
| 	INDEXMODE_DRIVE = 0; | ||||
| 	INDEXMODE_300 = 1; | ||||
| 	INDEXMODE_360 = 2; | ||||
| 	INDEXMODE_DRIVE = 0 [(ehelp) = "source index pulses from drive"]; | ||||
| 	INDEXMODE_300 = 1 [(ehelp) = "source index pulses from fake 300RPM source"]; | ||||
| 	INDEXMODE_360 = 2 [(ehelp) = "source index pulses from fake 360RPM source"]; | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import "lib/imagewriter/imagewriter.proto"; | ||||
| import "lib/fluxsource/fluxsource.proto"; | ||||
| import "lib/fluxsink/fluxsink.proto"; | ||||
| import "lib/usb/usb.proto"; | ||||
| import "lib/geometry/geometry.proto"; | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message InputProto { | ||||
| @@ -24,15 +25,16 @@ message OutputProto { | ||||
| } | ||||
|  | ||||
| message ConfigProto { | ||||
| 	optional string comment = 8; | ||||
| 	optional string comment = 1; | ||||
|  | ||||
| 	optional InputProto input = 1; | ||||
| 	optional OutputProto output = 2; | ||||
| 	optional EncoderProto encoder = 3; | ||||
| 	optional DecoderProto decoder = 4; | ||||
| 	optional UsbProto usb = 5; | ||||
| 	optional InputProto input = 2; | ||||
| 	optional OutputProto output = 3; | ||||
| 	optional EncoderProto encoder = 4; | ||||
| 	optional DecoderProto decoder = 5; | ||||
| 	optional UsbProto usb = 6; | ||||
| 	optional GeometryProto geometry = 7; | ||||
|  | ||||
| 	optional RangeProto cylinders = 6; | ||||
| 	optional RangeProto heads = 7; | ||||
| 	optional RangeProto cylinders = 8; | ||||
| 	optional RangeProto heads = 9; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -12,27 +12,28 @@ | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "protocol.h" | ||||
|  | ||||
| std::unique_ptr<AbstractEncoder> AbstractEncoder::create(const EncoderProto& config) | ||||
| std::unique_ptr<AbstractEncoder> AbstractEncoder::create( | ||||
| 		const EncoderProto& config, const DisassemblingGeometryMapper& mapper) | ||||
| { | ||||
| 	switch (config.format_case()) | ||||
| 	{ | ||||
| 		case EncoderProto::kAmiga: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new AmigaEncoder(config.amiga())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new AmigaEncoder(config.amiga(), mapper)); | ||||
|  | ||||
| 		case EncoderProto::kIbm: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new IbmEncoder(config.ibm())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new IbmEncoder(config.ibm(), mapper)); | ||||
|  | ||||
| 		case EncoderProto::kBrother: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new BrotherEncoder(config.brother())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new BrotherEncoder(config.brother(), mapper)); | ||||
|  | ||||
| 		case EncoderProto::kMacintosh: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new MacintoshEncoder(config.macintosh())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new MacintoshEncoder(config.macintosh(), mapper)); | ||||
|  | ||||
| 		case EncoderProto::kC64: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new Commodore64Encoder(config.c64())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new Commodore64Encoder(config.c64(), mapper)); | ||||
|  | ||||
| 		case EncoderProto::kNorthstar: | ||||
| 			return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config.northstar())); | ||||
| 			return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config.northstar(), mapper)); | ||||
|  | ||||
| 		default: | ||||
| 			Error() << "no input disk format specified"; | ||||
|   | ||||
| @@ -5,17 +5,17 @@ class FluxSource; | ||||
| class Fluxmap; | ||||
| class SectorSet; | ||||
| class EncoderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class AbstractEncoder | ||||
| { | ||||
| public: | ||||
|     virtual ~AbstractEncoder() {} | ||||
|  | ||||
| 	static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config); | ||||
| 	static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config, const DisassemblingGeometryMapper& mapper); | ||||
|  | ||||
| public: | ||||
|     virtual std::unique_ptr<Fluxmap> encode( | ||||
|         int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0; | ||||
|     virtual std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide) = 0; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										137
									
								
								lib/geometry/geometry.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/geometry/geometry.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| #include "globals.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "sectorset.h" | ||||
| #include "sector.h" | ||||
| #include "fmt/format.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| void AssemblingGeometryMapper::put(const SectorSet& sectors) | ||||
| { | ||||
| 	for (const auto& sit : sectors.get()) | ||||
| 		put(*sit.second); | ||||
| } | ||||
|  | ||||
| void AssemblingGeometryMapper::writeCsv(const SectorSet& sectors, const std::string& filename) | ||||
| { | ||||
| 	std::ofstream f(filename, std::ios::out); | ||||
| 	if (!f.is_open()) | ||||
| 		Error() << "cannot open CSV report file"; | ||||
|  | ||||
| 	f << "\"Physical track\"," | ||||
| 		"\"Physical side\"," | ||||
| 		"\"Logical track\"," | ||||
| 		"\"Logical side\"," | ||||
| 		"\"Logical sector\"," | ||||
| 		"\"Clock (ns)\"," | ||||
| 		"\"Header start (ns)\"," | ||||
| 		"\"Header end (ns)\"," | ||||
| 		"\"Data start (ns)\"," | ||||
| 		"\"Data end (ns)\"," | ||||
| 		"\"Raw data address (bytes)\"," | ||||
| 		"\"User payload length (bytes)\"," | ||||
| 		"\"Status\"" | ||||
| 		"\n"; | ||||
|  | ||||
| 	for (const auto& it : sectors.get()) | ||||
| 	{ | ||||
| 		const auto& sector = it.second; | ||||
| 		f << fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{}\n", | ||||
| 			sector->physicalTrack, | ||||
| 			sector->physicalSide, | ||||
| 			sector->logicalTrack, | ||||
| 			sector->logicalSide, | ||||
| 			sector->logicalSector, | ||||
| 			sector->clock, | ||||
| 			sector->headerStartTime, | ||||
| 			sector->headerEndTime, | ||||
| 			sector->dataStartTime, | ||||
| 			sector->dataEndTime, | ||||
| 			sector->position.bytes, | ||||
| 			sector->data.size(), | ||||
| 			Sector::statusToString(sector->status) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void AssemblingGeometryMapper::printMap(const SectorSet& sectors) | ||||
| { | ||||
| 	unsigned numCylinders; | ||||
| 	unsigned numHeads; | ||||
| 	unsigned numSectors; | ||||
| 	unsigned numBytes; | ||||
| 	sectors.calculateSize(numCylinders, numHeads, numSectors, numBytes); | ||||
|  | ||||
| 	int badSectors = 0; | ||||
| 	int missingSectors = 0; | ||||
| 	int totalSectors = 0; | ||||
|  | ||||
| 	std::cout << "     Tracks -> 1         2         3         "; | ||||
| 	if (numCylinders > 40) { | ||||
| 		std::cout << "4         5         6         7         8"; | ||||
| 	} | ||||
| 	std::cout << std::endl; | ||||
| 	std::cout << "H.SS 0123456789012345678901234567890123456789"; | ||||
| 	if (numCylinders > 40) { | ||||
| 		std::cout << "01234567890123456789012345678901234567890123"; | ||||
| 	} | ||||
| 	std::cout << std::endl; | ||||
|  | ||||
| 	for (int head = 0; head < numHeads; head++) | ||||
| 	{ | ||||
| 		for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
| 		{ | ||||
| 			std::cout << fmt::format("{}.{:2} ", head, sectorId); | ||||
| 			for (int track = 0; track < numCylinders; track++) | ||||
| 			{ | ||||
| 				const auto& sector = sectors.get(track, head, sectorId); | ||||
| 				if (!sector) | ||||
| 				{ | ||||
| 					std::cout << 'X'; | ||||
| 					missingSectors++; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					switch (sector->status) | ||||
| 					{ | ||||
| 						case Sector::OK: | ||||
|                             std::cout << '.'; | ||||
|                             break; | ||||
|  | ||||
|                         case Sector::BAD_CHECKSUM: | ||||
|                             std::cout << 'B'; | ||||
|                             badSectors++; | ||||
|                             break; | ||||
|  | ||||
|                         case Sector::CONFLICT: | ||||
|                             std::cout << 'C'; | ||||
|                             badSectors++; | ||||
|                             break; | ||||
|  | ||||
|                         default: | ||||
|                             std::cout << '?'; | ||||
|                             break; | ||||
|                     } | ||||
| 				} | ||||
| 				totalSectors++; | ||||
| 			} | ||||
| 			std::cout << std::endl; | ||||
| 		} | ||||
| 	} | ||||
| 	int goodSectors = totalSectors - missingSectors - badSectors; | ||||
| 	if (totalSectors == 0) | ||||
| 		std::cout << "No sectors in output; skipping analysis" << std::endl; | ||||
| 	else | ||||
| 	{ | ||||
| 		std::cout << "Good sectors: " << goodSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*goodSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
| 		std::cout << "Missing sectors: " << missingSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*missingSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
| 		std::cout << "Bad sectors: " << badSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*badSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										33
									
								
								lib/geometry/geometry.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/geometry/geometry.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #ifndef DGMAPPER_H | ||||
| #define DGMAPPER_H | ||||
|  | ||||
| class Sector; | ||||
| class SectorSet; | ||||
| class GeometryProto; | ||||
| class ImageReader; | ||||
| class ImageWriter; | ||||
|  | ||||
| class DisassemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	virtual const Sector* get(unsigned cylinder, unsigned head, unsigned sector) const = 0; | ||||
| }; | ||||
|  | ||||
| class AssemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	virtual void put(const Sector& sector) const = 0; | ||||
|  | ||||
| public: | ||||
| 	void put(const SectorSet& sectors); | ||||
| 	void printMap(const SectorSet& sectors); | ||||
| 	void writeCsv(const SectorSet& sectors, const std::string& filename); | ||||
| }; | ||||
|  | ||||
| extern std::unique_ptr<DisassemblingGeometryMapper> createSimpleDisassemblingGeometryMapper( | ||||
| 	const GeometryProto& proto, ImageReader& reader); | ||||
| extern std::unique_ptr<AssemblingGeometryMapper> createSimpleAssemblingGeometryMapper( | ||||
| 	const GeometryProto& proto, ImageWriter& reader); | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										27
									
								
								lib/geometry/geometry.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								lib/geometry/geometry.proto
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message GeometryProto { | ||||
| 	enum BlockOrdering { | ||||
| 		ORDER_CHS = 0 [(ehelp) = "head 0 interleaved with head 1"]; | ||||
| 		ORDER_HCS = 1 [(ehelp) = "all of head 0, then all of head 1"]; | ||||
| 		ORDER_NSI = 2 [(ehelp) = "all of head 0, then all of head 1 in reverse order"]; | ||||
| 	} | ||||
|  | ||||
| 	message TrackdataProto { | ||||
| 		optional int32 cylinder = 1 [(help) = "if set, this entry applies only to this cylinder"]; | ||||
| 		optional int32 head = 2 [(help) = "if set, this entry applies only to this head"]; | ||||
|  | ||||
| 		optional int32 sector_size = 4 [(help) = "number of bytes in each sector of this track"]; | ||||
| 		optional int32 sectors = 3 [(help) = "number of sectors on this track"]; | ||||
| 	} | ||||
|  | ||||
| 	optional int32 cylinders = 1 [(help) = "number of cylinders in the image"]; | ||||
| 	optional int32 heads = 2 [(help) = "number of sides in the image"]; | ||||
| 	repeated TrackdataProto trackdata = 3 [(help) = "descriptions of each track"]; | ||||
|  | ||||
| 	optional bool fortytrack = 4 [(help) = "set if this is for a forty-track (double stepped) geometry"]; | ||||
| 	optional BlockOrdering block_ordering = 5 [(help) = "order of blocks in the image"]; | ||||
| } | ||||
|  | ||||
							
								
								
									
										203
									
								
								lib/geometry/simplemapper.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								lib/geometry/simplemapper.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| #include "globals.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "sectorset.h" | ||||
| #include "sector.h" | ||||
| #include "geometry.h" | ||||
| #include "lib/geometry/geometry.pb.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| static std::string nameOf(GeometryProto::BlockOrdering ordering) | ||||
| { | ||||
| 	switch (ordering) | ||||
| 	{ | ||||
| 		case GeometryProto::ORDER_CHS: return "CHS"; | ||||
| 		case GeometryProto::ORDER_HCS: return "HCS"; | ||||
| 		default: return fmt::format("order({})", ordering); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| struct Trackdata | ||||
| { | ||||
| 	GeometryProto::TrackdataProto format; | ||||
| 	int offset; | ||||
| }; | ||||
|  | ||||
| static void parse_geometry(std::map<std::pair<int, int>, Trackdata>& offsets, const GeometryProto& config) | ||||
| { | ||||
| 	int offset = 0; | ||||
|  | ||||
| 	auto getTrackFormat = [&](GeometryProto::TrackdataProto& trackdata, unsigned cylinder, unsigned head) | ||||
| 	{ | ||||
| 		trackdata.Clear(); | ||||
| 		for (const GeometryProto::TrackdataProto& f : config.trackdata()) | ||||
| 		{ | ||||
| 			if (f.has_cylinder() && (f.cylinder() != cylinder)) | ||||
| 				continue; | ||||
| 			if (f.has_head() && (f.head() != head)) | ||||
| 				continue; | ||||
|  | ||||
| 			trackdata.MergeFrom(f); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	auto addBlock = [&](int cylinder, int head) { | ||||
| 		Trackdata& trackdata = offsets[std::make_pair(cylinder, head)]; | ||||
| 		trackdata.offset = offset; | ||||
| 		getTrackFormat(trackdata.format, cylinder, head); | ||||
| 		offset += trackdata.format.sectors() * trackdata.format.sector_size(); | ||||
| 	}; | ||||
|  | ||||
| 	switch (config.block_ordering()) | ||||
| 	{ | ||||
| 		case GeometryProto::ORDER_CHS: | ||||
| 			for (int cylinder = 0; cylinder < config.cylinders(); cylinder++) | ||||
| 				for (int head = 0; head < config.heads(); head++) | ||||
| 					addBlock(cylinder, head); | ||||
| 			break; | ||||
|  | ||||
| 		case GeometryProto::ORDER_HCS: | ||||
| 			for (int head = 0; head < config.heads(); head++) | ||||
| 				for (int cylinder = 0; cylinder < config.cylinders(); cylinder++) | ||||
| 					addBlock(cylinder, head); | ||||
| 			break; | ||||
|  | ||||
| 		case GeometryProto::ORDER_NSI: | ||||
| 			for (int cylinder = 0; cylinder < config.cylinders(); cylinder++) | ||||
| 				addBlock(cylinder, 0); | ||||
| 			if (config.heads() == 2) | ||||
| 				for (int cylinder = config.cylinders()-1; cylinder >= 0; cylinder--) | ||||
| 					addBlock(cylinder, 1); | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| 	std::cout << fmt::format("GEOM: input {} image of {} cylinders, {} heads\n",  | ||||
| 		nameOf(config.block_ordering()), config.cylinders(), config.heads()); | ||||
| } | ||||
|  | ||||
| class BaseGeometryMapper | ||||
| { | ||||
| protected: | ||||
| 	BaseGeometryMapper(const GeometryProto& config): | ||||
| 		_config(config) | ||||
| 	{} | ||||
|  | ||||
| protected: | ||||
| 	void getOffsetOf(unsigned cylinder, unsigned head, unsigned sector, off_t& offset, unsigned& sector_size) const | ||||
| 	{ | ||||
| 		const auto tit = _offsets.find(std::make_pair(cylinder, head)); | ||||
| 		if (tit == _offsets.end()) | ||||
| 		{ | ||||
| 			offset = -1; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		const Trackdata& trackdata = tit->second; | ||||
| 		sector_size = trackdata.format.sector_size(); | ||||
| 		offset = trackdata.offset + sector*sector_size; | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
| 	const GeometryProto& _config; | ||||
| 	mutable std::map<std::pair<int, int>, Trackdata> _offsets; | ||||
| }; | ||||
|  | ||||
| class SimpleDisassemblingGeometryMapper : public BaseGeometryMapper, public DisassemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	SimpleDisassemblingGeometryMapper(const GeometryProto& config, ImageReader& reader): | ||||
| 			BaseGeometryMapper(config), | ||||
| 			_reader(reader) | ||||
| 	{ | ||||
| 		_proxy = reader.getGeometryMapper(); | ||||
| 		if (_proxy) | ||||
| 		{ | ||||
| 			std::cout << "GEOM: geometry being overridden by input image\n"; | ||||
| 			return; | ||||
| 		} | ||||
| 		parse_geometry(_offsets, config); | ||||
| 	} | ||||
|  | ||||
| 	const Sector* get(unsigned cylinder, unsigned head, unsigned sector) const | ||||
| 	{ | ||||
| 		if (_proxy) | ||||
| 			return _proxy->get(cylinder, head, sector); | ||||
|  | ||||
| 		std::unique_ptr<Sector>& sit = _sectors.get(cylinder, head, sector); | ||||
| 		if (!sit) | ||||
| 		{ | ||||
| 			sit.reset(new Sector); | ||||
| 			sit->status = Sector::MISSING; | ||||
| 			sit->physicalTrack = sit->logicalTrack = cylinder; | ||||
| 			sit->physicalSide = sit->logicalSide = head; | ||||
| 			sit->logicalSector = sector; | ||||
|  | ||||
| 			off_t offset; | ||||
| 			unsigned sector_size; | ||||
| 			getOffsetOf(cylinder, head, sector, offset, sector_size); | ||||
| 			if (offset == -1) | ||||
| 				return nullptr; | ||||
| 			sit->data = _reader.getBlock(offset, sector_size); | ||||
| 		} | ||||
| 		return sit.get(); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	const ImageReader& _reader; | ||||
| 	const DisassemblingGeometryMapper* _proxy; | ||||
| 	mutable SectorSet _sectors; | ||||
| }; | ||||
|  | ||||
| class SimpleAssemblingGeometryMapper : public BaseGeometryMapper, public AssemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	SimpleAssemblingGeometryMapper(const GeometryProto& config, ImageWriter& writer): | ||||
| 			BaseGeometryMapper(config), | ||||
| 			_writer(writer) | ||||
| 	{ | ||||
| 		_proxy = writer.getGeometryMapper(); | ||||
| 		if (_proxy) | ||||
| 		{ | ||||
| 			std::cout << "GEOM: geometry mapping not used by output image\n"; | ||||
| 			return; | ||||
| 		} | ||||
| 		parse_geometry(_offsets, config); | ||||
| 	} | ||||
|  | ||||
| 	void put(const Sector& data) const | ||||
| 	{ | ||||
| 		if (_proxy) | ||||
| 		{ | ||||
| 			_proxy->put(data); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		off_t offset; | ||||
| 		unsigned sector_size; | ||||
| 		getOffsetOf(data.logicalTrack, data.logicalSide, data.logicalSector, offset, sector_size); | ||||
| 		if (offset == -1) | ||||
| 		{ | ||||
| 			std::cout << fmt::format("GEOM: sector {}.{}.{} discarded\n", | ||||
| 					data.logicalTrack, data.logicalSide, data.logicalSector); | ||||
| 			return; | ||||
| 		} | ||||
| 		_writer.putBlock(offset, sector_size, data.data); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	ImageWriter& _writer; | ||||
| 	const AssemblingGeometryMapper* _proxy; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<DisassemblingGeometryMapper> createSimpleDisassemblingGeometryMapper( | ||||
| 	const GeometryProto& config, ImageReader& reader) | ||||
| { | ||||
| 	return std::unique_ptr<DisassemblingGeometryMapper>(new SimpleDisassemblingGeometryMapper(config, reader)); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<AssemblingGeometryMapper> createSimpleAssemblingGeometryMapper( | ||||
| 	const GeometryProto& config, ImageWriter& writer) | ||||
| { | ||||
| 	return std::unique_ptr<AssemblingGeometryMapper>(new SimpleAssemblingGeometryMapper(config, writer)); | ||||
| } | ||||
|  | ||||
| @@ -1,98 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fmt/format.h" | ||||
| #include "proto.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| class D64ImageReader : public ImageReader | ||||
| { | ||||
| public: | ||||
| 	D64ImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
|         inputFile.seekg(0, inputFile.beg); | ||||
|         uint32_t begin = inputFile.tellg(); | ||||
|         inputFile.seekg(0, inputFile.end); | ||||
|         uint32_t end = inputFile.tellg(); | ||||
|         uint32_t inputFileSize = (end-begin); | ||||
|         inputFile.seekg(0, inputFile.beg); | ||||
| 		Bytes data; | ||||
| 		data.writer() += inputFile; | ||||
| 		ByteReader br(data); | ||||
|  | ||||
| 		unsigned numCylinders = 39; | ||||
| 		unsigned numHeads = 1; | ||||
| 		unsigned numSectors = 0; | ||||
|  | ||||
| 		std::cout << "reading D64 image\n" | ||||
| 		          << fmt::format("{} cylinders, {} heads\n", | ||||
| 				  		numCylinders, numHeads); | ||||
|  | ||||
|         uint32_t offset = 0; | ||||
|  | ||||
| 		auto sectorsPerTrack = [&](int track) -> int | ||||
| 		{ | ||||
|             if (track < 17) | ||||
|                 return 21; | ||||
|             if (track < 24) | ||||
|                 return 19; | ||||
|             if (track < 30) | ||||
|                 return 18; | ||||
|             return 17; | ||||
| 		}; | ||||
|  | ||||
|         SectorSet sectors; | ||||
|         for (int track = 0; track < 40; track++) | ||||
|         { | ||||
| 			int numSectors = sectorsPerTrack(track); | ||||
|             for (int head = 0; head < numHeads; head++) | ||||
|             { | ||||
|                 for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
|                 { | ||||
|                    if ((offset < inputFileSize)) | ||||
|                    {    //still data available sector OK | ||||
|                         br.seek(offset); | ||||
|                         Bytes payload = br.read(256); | ||||
|                         offset += 256; | ||||
|  | ||||
|                         std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId); | ||||
|                         sector.reset(new Sector); | ||||
|                         sector->status = Sector::OK; | ||||
|                         sector->logicalTrack = sector->physicalTrack = track; | ||||
|                         sector->logicalSide = sector->physicalSide = head; | ||||
|                         sector->logicalSector = sectorId; | ||||
|                         sector->data.writer().append(payload); | ||||
|                     } else | ||||
|                     {   //no more data in input file. Write sectors with status: DATA_MISSING | ||||
|                         std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId); | ||||
|                         sector.reset(new Sector); | ||||
|                         sector->status = Sector::DATA_MISSING; | ||||
|                         sector->logicalTrack = sector->physicalTrack = track; | ||||
|                         sector->logicalSide = sector->physicalSide = head; | ||||
|                         sector->logicalSector = sectorId; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return sectors; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createD64ImageReader(const ImageReaderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<ImageReader>(new D64ImageReader(config)); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -9,114 +9,64 @@ | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| #define SECTOR_SIZE 512 | ||||
| #define TAG_SIZE 12 | ||||
|  | ||||
| class DiskCopyImageReader : public ImageReader | ||||
| { | ||||
| public: | ||||
| 	DiskCopyImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
| 		_if.open(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!_if.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
| 		Bytes data; | ||||
| 		data.writer() += inputFile; | ||||
| 		ByteReader br(data); | ||||
| 		Bytes header(_if, 0x54); | ||||
| 		ByteReader br(header); | ||||
|  | ||||
| 		br.seek(1); | ||||
| 		std::string label = br.read(data[0]); | ||||
| 		uint8_t labelLen = br.read_8(); | ||||
| 		std::string label = br.read(labelLen); | ||||
|  | ||||
| 		br.seek(0x40); | ||||
| 		uint32_t dataSize = br.read_be32(); | ||||
| 		uint32_t tagSize = br.read_be32(); | ||||
| 		_numSectors = dataSize / SECTOR_SIZE; | ||||
| 		_sectorOffset = 0x54; | ||||
| 		_tagOffset = _sectorOffset + dataSize; | ||||
|  | ||||
| 		br.seek(0x50); | ||||
| 		uint8_t encoding = br.read_8(); | ||||
| 		uint8_t formatByte = br.read_8(); | ||||
| 		_if.seekg(0, std::ios::end); | ||||
|         std::cout << fmt::format("DISKCOPY: reading input image '{}' of {} sectors", | ||||
| 				label, _numSectors); | ||||
| 	} | ||||
|  | ||||
| 		unsigned numCylinders = 80; | ||||
| 		unsigned numHeads = 2; | ||||
| 		unsigned numSectors = 0; | ||||
| 		bool mfm = false; | ||||
| 	Bytes getBlock(size_t offset, size_t length) const | ||||
| 	{ | ||||
| 		if ((length != SECTOR_SIZE) && (length != (SECTOR_SIZE+TAG_SIZE))) | ||||
| 			Error() << fmt::format("diskcopy files only support sector lengths of {} and {}\n", | ||||
| 				SECTOR_SIZE, (SECTOR_SIZE+TAG_SIZE)); | ||||
|  | ||||
| 		switch (encoding) | ||||
| 		unsigned sectorNum = offset / length; | ||||
| 		if (offset % length) | ||||
| 			Error() << fmt::format("unaligned sector read"); | ||||
|  | ||||
| 		_if.seekg(_sectorOffset + SECTOR_SIZE*sectorNum); | ||||
| 		Bytes data(_if, SECTOR_SIZE); | ||||
|  | ||||
| 		if (length != SECTOR_SIZE) | ||||
| 		{ | ||||
| 			case 0: /* GCR CLV 400kB */ | ||||
| 				numHeads = 1; | ||||
| 				break; | ||||
|  | ||||
| 			case 1: /* GCR CLV 800kB */ | ||||
| 				break; | ||||
|  | ||||
| 			case 2: /* MFM CAV 720kB */ | ||||
| 				numSectors = 9; | ||||
| 				mfm = true; | ||||
| 				break; | ||||
|  | ||||
| 			case 3: /* MFM CAV 1440kB */ | ||||
| 				numSectors = 18; | ||||
| 				mfm = true; | ||||
| 				break; | ||||
|  | ||||
| 			default: | ||||
| 				Error() << fmt::format("don't understand DiskCopy disks of type {}", encoding); | ||||
| 			_if.seekg(_tagOffset + TAG_SIZE*sectorNum); | ||||
| 			data.writer().seekToEnd().append(_if, TAG_SIZE); | ||||
| 		} | ||||
|  | ||||
| 		std::cout << "reading DiskCopy 4.2 image\n" | ||||
| 		          << fmt::format("{} cylinders, {} heads; {}; {}\n", | ||||
| 				  		numCylinders, numHeads, | ||||
| 						mfm ? "MFM" : "GCR", | ||||
| 						label); | ||||
|  | ||||
| 		auto sectorsPerTrack = [&](int track) -> int | ||||
| 		{ | ||||
| 			if (mfm) | ||||
| 				return numSectors; | ||||
|  | ||||
| 			if (track < 16) | ||||
| 				return 12; | ||||
| 			if (track < 32) | ||||
| 				return 11; | ||||
| 			if (track < 48) | ||||
| 				return 10; | ||||
| 			if (track < 64) | ||||
| 				return 9; | ||||
| 			return 8; | ||||
| 		}; | ||||
|  | ||||
| 		uint32_t dataPtr = 0x54; | ||||
| 		uint32_t tagPtr = dataPtr + dataSize; | ||||
|  | ||||
|         SectorSet sectors; | ||||
|         for (int track = 0; track < numCylinders; track++) | ||||
|         { | ||||
| 			int numSectors = sectorsPerTrack(track); | ||||
|             for (int head = 0; head < numHeads; head++) | ||||
|             { | ||||
|                 for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
|                 { | ||||
| 					br.seek(dataPtr); | ||||
| 					Bytes payload = br.read(512); | ||||
| 					dataPtr += 512; | ||||
|  | ||||
| 					br.seek(tagPtr); | ||||
| 					Bytes tag = br.read(12); | ||||
| 					tagPtr += 12; | ||||
|  | ||||
|                     std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId); | ||||
|                     sector.reset(new Sector); | ||||
|                     sector->status = Sector::OK; | ||||
|                     sector->logicalTrack = sector->physicalTrack = track; | ||||
|                     sector->logicalSide = sector->physicalSide = head; | ||||
|                     sector->logicalSector = sectorId; | ||||
|                     sector->data.writer().append(payload).append(tag); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return sectors; | ||||
| 		return data; | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	mutable std::ifstream _if; | ||||
| 	unsigned _numSectors; | ||||
| 	off_t _sectorOffset; | ||||
| 	off_t _tagOffset; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createDiskCopyImageReader( | ||||
|   | ||||
| @@ -26,12 +26,6 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageReaderProto& config) | ||||
| 		case ImageReaderProto::kJv3: | ||||
| 			return ImageReader::createJv3ImageReader(config); | ||||
|  | ||||
| 		case ImageReaderProto::kD64: | ||||
| 			return ImageReader::createD64ImageReader(config); | ||||
|  | ||||
| 		case ImageReaderProto::kNsi: | ||||
| 			return ImageReader::createNsiImageReader(config); | ||||
|  | ||||
| 		default: | ||||
| 			Error() << "bad input file config"; | ||||
| 			return std::unique_ptr<ImageReader>(); | ||||
| @@ -44,12 +38,13 @@ void ImageReader::updateConfigForFilename(ImageReaderProto* proto, const std::st | ||||
| 	{ | ||||
| 		{".adf",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".jv3",      [&]() { proto->mutable_jv3(); }}, | ||||
| 		{".d64",      [&]() { proto->mutable_d64(); }}, | ||||
| 		{".d64",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".d81",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".diskcopy", [&]() { proto->mutable_diskcopy(); }}, | ||||
| 		{".img",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".st",       [&]() { proto->mutable_img(); }}, | ||||
| 		{".nsi",      [&]() { proto->mutable_nsi(); }}, | ||||
| 		{".nsi",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".imd",      [&]() { proto->mutable_imd(); }}, | ||||
| 	}; | ||||
|  | ||||
| 	for (const auto& it : formats) | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| class SectorSet; | ||||
| class ImageSpec; | ||||
| class ImageReaderProto; | ||||
| class DisassemblingGeometryMapper; | ||||
|  | ||||
| class ImageReader | ||||
| { | ||||
| @@ -16,15 +17,14 @@ public: | ||||
| 	static void updateConfigForFilename(ImageReaderProto* proto, const std::string& filename); | ||||
|  | ||||
| public: | ||||
|     static std::unique_ptr<ImageReader> createD64ImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createDiskCopyImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createImgImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createJv3ImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createIMDImageReader(const ImageReaderProto& config); | ||||
|     static std::unique_ptr<ImageReader> createNsiImageReader(const ImageReaderProto& config); | ||||
|  | ||||
| public: | ||||
| 	virtual SectorSet readImage() = 0; | ||||
| 	virtual Bytes getBlock(size_t offset, size_t length) const = 0; | ||||
| 	virtual const DisassemblingGeometryMapper* getGeometryMapper() const { return nullptr; } | ||||
|  | ||||
| protected: | ||||
| 	const ImageReaderProto& _config; | ||||
|   | ||||
| @@ -22,7 +22,6 @@ message DiskCopyInputProto {} | ||||
| message ImdInputProto {} | ||||
| message Jv3InputProto {} | ||||
| message D64InputProto {} | ||||
| message NsiInputProto {} | ||||
|  | ||||
| message ImageReaderProto { | ||||
| 	optional string filename = 1 [(help) = "filename of input sector image"]; | ||||
| @@ -32,7 +31,6 @@ message ImageReaderProto { | ||||
| 		ImdInputProto imd = 4; | ||||
| 		Jv3InputProto jv3 = 5; | ||||
| 		D64InputProto d64 = 6; | ||||
| 		NsiInputProto nsi = 7; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "lib/config.pb.h" | ||||
| #include "fmt/format.h" | ||||
| #include <algorithm> | ||||
| @@ -50,16 +51,16 @@ static unsigned getModulationandSpeed(uint8_t flags, bool *mfm) | ||||
| 		} | ||||
| } | ||||
|  | ||||
| struct TrackHeader | ||||
| struct Trackheader | ||||
| { | ||||
| 	uint8_t ModeValue; | ||||
| 	uint8_t modeValue; | ||||
| 	uint8_t track; | ||||
| 	uint8_t Head; | ||||
| 	uint8_t head; | ||||
| 	uint8_t numSectors; | ||||
| 	uint8_t SectorSize; | ||||
| 	uint8_t sectorSize; | ||||
| }; | ||||
|  | ||||
| static unsigned getSectorSize(uint8_t flags) | ||||
| static unsigned getsectorSize(uint8_t flags) | ||||
| { | ||||
| 	switch (flags) | ||||
| 	{ | ||||
| @@ -81,178 +82,157 @@ static unsigned getSectorSize(uint8_t flags) | ||||
| #define END_OF_FILE       0x1A | ||||
|  | ||||
|  | ||||
| class IMDImageReader : public ImageReader | ||||
| class IMDImageReader : public ImageReader, DisassemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	IMDImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	/* | ||||
| 	IMAGE FILE FORMAT | ||||
| 	The overall layout of an ImageDisk .IMD image file is: | ||||
| 	IMD v.vv: dd/mm/yyyy hh:mm:ss | ||||
| 	Comment (ASCII only - unlimited size) | ||||
| 	1A byte - ASCII EOF character | ||||
| 	- For each track on the disk: | ||||
| 	1 byte Mode value							see getModulationspeed for definition		 | ||||
| 	1 byte Cylinder | ||||
| 	1 byte Head | ||||
| 	1 byte number of sectors in track			 | ||||
| 	1 byte sector size							see getsectorsize for definition | ||||
| 	sector numbering map | ||||
| 	sector cylinder map (optional)				definied in high byte of head (since head is 0 or 1) | ||||
| 	sector head map (optional)					definied in high byte of head (since head is 0 or 1) | ||||
| 	sector data records | ||||
| 	<End of file> | ||||
| 	*/ | ||||
| 	{ | ||||
| 		//Read File | ||||
| 		/* | ||||
| 		 * IMAGE FILE FORMAT | ||||
| 		 * The overall layout of an ImageDisk .IMD image file is: | ||||
| 		 * IMD v.vv: dd/mm/yyyy hh:mm:ss | ||||
| 		 * Comment (ASCII only - unlimited size) | ||||
| 		 * 1A byte - ASCII EOF character | ||||
| 		 * - For each track on the disk: | ||||
| 		 * 1 byte Mode value							see getModulationspeed for definition		 | ||||
| 		 * 1 byte Cylinder | ||||
| 		 * 1 byte head | ||||
| 		 * 1 byte number of sectors in track			 | ||||
| 		 * 1 byte sector size							see getsectorsize for definition | ||||
| 		 * sector numbering map | ||||
| 		 * sector cylinder map (optional)				definied in high byte of head (since head is 0 or 1) | ||||
| 		 * sector head map (optional)					definied in high byte of head (since head is 0 or 1) | ||||
| 		 * sector data records | ||||
| 		 * <End of file> | ||||
| 		 */ | ||||
|  | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
| 		Bytes data; | ||||
| 		data.writer().append(inputFile); | ||||
| 		ByteReader br(data); | ||||
|  | ||||
| 		//define some variables | ||||
| 		bool mfm = false;	//define coding just to show in comment for setting the right write parameters | ||||
| 		inputFile.seekg(0, inputFile.end); | ||||
| 		int inputFileSize = inputFile.tellg();	// determine filesize | ||||
| 		inputFile.seekg(0, inputFile.beg); | ||||
| 		Bytes data; | ||||
| 		data.writer() += inputFile; | ||||
| 		ByteReader br(data); | ||||
| 		SectorSet sectors; | ||||
| 		TrackHeader header = {0, 0, 0, 0, 0}; | ||||
| 		Trackheader header = {0, 0, 0, 0, 0}; | ||||
|  | ||||
| 		unsigned n = 0; | ||||
| 		unsigned headerPtr = 0; | ||||
| 		unsigned Modulation_Speed = 0; | ||||
| 		unsigned modulation_speed = 0; | ||||
| 		unsigned sectorSize = 0; | ||||
| 		std::string sector_skew; | ||||
| 		int b; 	 | ||||
| 		unsigned char comment[8192]; //i choose a fixed value. dont know how to make dynamic arrays in C++. This should be enough | ||||
|  | ||||
| 		// Read comment | ||||
| 		while ((b = br.read_8()) != EOF && b != 0x1A) | ||||
| 		std::stringstream comment; | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			comment[n++] = (unsigned char)b; | ||||
| 		} | ||||
| 		headerPtr = n; //set pointer to after comment | ||||
| 		comment[n] = '\0'; // null-terminate the string | ||||
| 		//write comment to screen | ||||
| 		std::cout 	<< "Comment in IMD image:\n" | ||||
| 					<< fmt::format("{}\n", | ||||
| 					comment); | ||||
|  | ||||
| 		//first read header | ||||
| 		for (;;) | ||||
| 		{ | ||||
| 			if (headerPtr >= inputFileSize-1) | ||||
| 			{ | ||||
| 			int b = br.read_8(); | ||||
| 			if (b == 0x1a) | ||||
| 				break; | ||||
| 			} | ||||
| 			header.ModeValue = br.read_8(); | ||||
| 			headerPtr++; | ||||
| 			Modulation_Speed = getModulationandSpeed(header.ModeValue, &mfm); | ||||
| 			if (b == '\r') | ||||
| 				continue; | ||||
| 			if (b == '\n') | ||||
| 				b = 32; | ||||
| 			comment << (char) b; | ||||
| 		} | ||||
| 		std::cout << fmt::format("IMD: comment: {}\n", comment.str()); | ||||
|  | ||||
| 		while (!br.eof()) | ||||
| 		{ | ||||
| 			header.modeValue = br.read_8(); | ||||
| 			modulation_speed = getModulationandSpeed(header.modeValue, &mfm); | ||||
| 			header.track = br.read_8(); | ||||
| 			headerPtr++; | ||||
| 			header.Head = br.read_8(); | ||||
| 			headerPtr++; | ||||
| 			header.head = br.read_8(); | ||||
| 			int physicalHead = header.head & 0x3f; | ||||
| 			header.numSectors = br.read_8(); | ||||
| 			headerPtr++; | ||||
| 			header.SectorSize = br.read_8(); | ||||
| 			headerPtr++; | ||||
| 			sectorSize = getSectorSize(header.SectorSize); | ||||
| 			header.sectorSize = br.read_8(); | ||||
| 			sectorSize = getsectorSize(header.sectorSize); | ||||
|  | ||||
| 			//Read optional cylinder map To Do | ||||
| 			/* Read optional cylinder map */ | ||||
|  | ||||
| 			//Read optional sector head map To Do | ||||
| 			if (header.head & 0x80) | ||||
| 				Error() << "cylinder map"; | ||||
|  | ||||
| 			/* Read optional sector head map */ | ||||
|  | ||||
| 			if (header.head & 0x40) | ||||
| 				Error() << "sector head map"; | ||||
|  | ||||
| 			//read sector numbering map | ||||
| 			unsigned int sector_map[header.numSectors]; | ||||
| 			bool blnBaseOne = false;  | ||||
| 			sector_skew.clear(); | ||||
| 			for (b = 0;  b < header.numSectors; b++) | ||||
| 			for (int b = 0;  b < header.numSectors; b++) | ||||
| 			{	 | ||||
| 				sector_map[b] = br.read_8(); | ||||
| 				sector_skew.push_back(sector_map[b] + '0'); | ||||
| 				if (b == 0) //first sector see if base is 0 or 1 Fluxengine wants 0 | ||||
| 					{ | ||||
| 					if (sector_map[b]==1) | ||||
| 						{ | ||||
| 							blnBaseOne = true; | ||||
| 						} | ||||
| 					} | ||||
| 				if (blnBaseOne==true) | ||||
| 				{ | ||||
| 					sector_map[b] = (sector_map[b]-1); | ||||
| 					if (sector_map[b]==1) | ||||
| 						blnBaseOne = true; | ||||
| 				} | ||||
| 				headerPtr++; | ||||
| 				if (blnBaseOne==true) | ||||
| 					sector_map[b] = (sector_map[b]-1); | ||||
| 			} | ||||
| 			//read the sectors | ||||
| 			for (int s = 0; s < header.numSectors; s++) | ||||
| 			{ | ||||
| 				Bytes sectordata; | ||||
| 				std::unique_ptr<Sector>& sector = sectors.get(header.track, header.Head, sector_map[s]); | ||||
| 				std::unique_ptr<Sector>& sector = _sectors.get(header.track, physicalHead, sector_map[s]); | ||||
| 				sector.reset(new Sector); | ||||
| 				//read the status of the sector | ||||
| 				unsigned int Status_Sector = br.read_8(); | ||||
| 				headerPtr++; | ||||
| 				unsigned int sector_status = br.read_8(); | ||||
|  | ||||
| 				switch (Status_Sector) | ||||
| 				switch (sector_status) | ||||
| 				{ | ||||
| 					case 0: /* Sector data unavailable - could not be read */ | ||||
|  | ||||
| 						break; | ||||
|  | ||||
| 					case 1: /* Normal data: (Sector Size) bytes follow */ | ||||
| 						sectordata = br.read(sectorSize); | ||||
| 						headerPtr += sectorSize; | ||||
| 						sector->data.writer().append(sectordata); | ||||
|  | ||||
| 					{ | ||||
| 						Bytes sectordata = br.read(sectorSize); | ||||
| 						sector->data = sectordata; | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					case 2: /* Compressed: All bytes in sector have same value (xx) */ | ||||
| 						sectordata = br.read(1); | ||||
| 						headerPtr++; | ||||
| 					{ | ||||
| 						uint8_t sectordata = br.read_8(); | ||||
| 						sector->data.writer().append(sectordata); | ||||
|  | ||||
| 						ByteWriter bw(sector->data); | ||||
| 						for (int k = 1; k < sectorSize; k++) | ||||
| 						{ | ||||
| 							//fill data till sector is full | ||||
| 							sector->data.writer().append(sectordata); | ||||
| 							bw.write_8(sectordata); | ||||
| 						} | ||||
|  | ||||
| 						break; | ||||
| 					} | ||||
|  | ||||
| 					case 3: /* Normal data with "Deleted-Data address mark" */ | ||||
|  | ||||
| 						break; | ||||
|  | ||||
| 					case 4: /* Compressed with "Deleted-Data address mark"*/ | ||||
| 					 | ||||
| 						break; | ||||
|  | ||||
| 					case 5: /* Normal data read with data error */ | ||||
| 					 | ||||
| 						break; | ||||
|  | ||||
| 					case 6: /* Compressed read with data error" */ | ||||
|  | ||||
| 						break; | ||||
|  | ||||
| 					case 7: /* Deleted data read with data error" */ | ||||
| 					 | ||||
| 						break; | ||||
|  | ||||
| 					case 8: /* Compressed, Deleted read with data error" */ | ||||
| 					 | ||||
| 						break; | ||||
|  | ||||
| 					default: | ||||
| 						Error() << fmt::format("don't understand IMD disks with sector status {}", Status_Sector); | ||||
| 						Error() << fmt::format("don't understand IMD disks with sector status {}", sector_status); | ||||
| 				}		 | ||||
| 				sector->status = Sector::OK; | ||||
| 				sector->logicalTrack = sector->physicalTrack = header.track; | ||||
| 				sector->logicalSide = sector->physicalSide = header.Head; | ||||
| 				sector->logicalSide = sector->physicalSide = physicalHead; | ||||
| 				sector->logicalSector = (sector_map[s]); | ||||
| 			} | ||||
|  | ||||
| @@ -260,16 +240,28 @@ public: | ||||
| 		//Write format detected in IMD image to screen to help user set the right write parameters | ||||
|  | ||||
| 		size_t headSize = header.numSectors * sectorSize; | ||||
|         size_t trackSize = headSize * (header.Head + 1); | ||||
|         size_t trackSize = headSize * (header.head + 1); | ||||
|  | ||||
| 		std::cout 	<< "reading IMD image\n" | ||||
| 					<< fmt::format("{} tracks, {} heads; {}; {} kbps; {} sectoren; sectorsize {}; sectormap {}; {} kB total \n", | ||||
| 					header.track, header.Head + 1, | ||||
| 					mfm ? "MFM" : "FM", | ||||
| 					Modulation_Speed, header.numSectors, sectorSize, sector_skew, (header.track+1) * trackSize / 1024); | ||||
| 		std::cout << fmt::format("IMD: reading image with {} tracks, {} heads, {};\n" | ||||
| 								 "IMD: {} kbps; {} sectors; sectorsize {}; sectormap {}; {} kB total\n", | ||||
| 				  header.track, header.head + 1, | ||||
| 				  mfm ? "MFM" : "FM", | ||||
| 				  modulation_speed, header.numSectors, sectorSize, sector_skew, (header.track+1) * trackSize / 1024); | ||||
|  | ||||
|         return sectors; | ||||
|  	} | ||||
| 	} | ||||
|  | ||||
| 	Bytes getBlock(size_t offset, size_t length) const | ||||
| 	{ | ||||
| 		throw "unimplemented"; | ||||
| 	} | ||||
|  | ||||
| 	const Sector* get(unsigned cylinder, unsigned head, unsigned sector) const | ||||
| 	{ | ||||
| 		return _sectors.get(cylinder, head, sector); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	SectorSet _sectors; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createIMDImageReader( | ||||
|   | ||||
| @@ -14,62 +14,24 @@ class ImgImageReader : public ImageReader | ||||
| public: | ||||
| 	ImgImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
| 		_if.open(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!_if.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
|         SectorSet sectors; | ||||
|         for (int track = 0; track < _config.img().tracks(); track++) | ||||
|         { | ||||
|             for (int side = 0; side < _config.img().sides(); side++) | ||||
|             { | ||||
| 				ImgInputOutputProto::TrackdataProto trackdata; | ||||
| 				getTrackFormat(trackdata, track, side); | ||||
| 		_if.seekg(0, std::ios::end); | ||||
|         std::cout << fmt::format("IMG: reading input image of {} kB total\n", | ||||
| 						_if.tellg() / 1024); | ||||
| 	} | ||||
|  | ||||
|                 for (int sectorId = 0; sectorId < trackdata.sectors(); sectorId++) | ||||
|                 { | ||||
|                     Bytes data(trackdata.sector_size()); | ||||
|                     inputFile.read((char*) data.begin(), data.size()); | ||||
|  | ||||
|                     std::unique_ptr<Sector>& sector = sectors.get(track, side, sectorId); | ||||
|                     sector.reset(new Sector); | ||||
|                     sector->status = Sector::OK; | ||||
|                     sector->logicalTrack = track; | ||||
| 					sector->physicalTrack = track * _config.img().physical_step() + _config.img().physical_offset(); | ||||
|                     sector->logicalSide = sector->physicalSide = side; | ||||
|                     sector->logicalSector = sectorId; | ||||
|                     sector->data = data; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| 			if (inputFile.eof()) | ||||
| 				break; | ||||
|         } | ||||
|  | ||||
|         std::cout << fmt::format("reading {} tracks, {} sides, {} kB total\n", | ||||
|                         _config.img().tracks(), _config.img().sides(), | ||||
| 						inputFile.tellg() / 1024); | ||||
|         return sectors; | ||||
| 	Bytes getBlock(size_t offset, size_t length) const | ||||
| 	{ | ||||
| 		_if.seekg(offset); | ||||
| 		return Bytes(_if, length); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	void getTrackFormat(ImgInputOutputProto::TrackdataProto& trackdata, unsigned track, unsigned side) | ||||
| 	{ | ||||
| 		trackdata.Clear(); | ||||
| 		for (const ImgInputOutputProto::TrackdataProto& f : _config.img().trackdata()) | ||||
| 		{ | ||||
| 			if (f.has_track() && (f.track() != track)) | ||||
| 				continue; | ||||
| 			if (f.has_side() && (f.side() != side)) | ||||
| 				continue; | ||||
|  | ||||
| 			trackdata.MergeFrom(f); | ||||
| 		} | ||||
| 	} | ||||
| 	mutable std::ifstream _if; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createImgImageReader( | ||||
|   | ||||
| @@ -3,8 +3,10 @@ | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/config.pb.h" | ||||
| #include "lib/imagereader/imagereader.pb.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| @@ -31,13 +33,6 @@ | ||||
|  * } SectorHeader; | ||||
|  */ | ||||
|  | ||||
| struct SectorHeader | ||||
| { | ||||
| 	uint8_t track; | ||||
| 	uint8_t sector; | ||||
| 	uint8_t flags; | ||||
| }; | ||||
|  | ||||
| #define JV3_DENSITY     0x80  /* 1=dden, 0=sden */ | ||||
| #define JV3_DAM         0x60  /* data address mark code; see below */ | ||||
| #define JV3_SIDE        0x10  /* 0=side 0, 1=side 1 */ | ||||
| @@ -72,55 +67,51 @@ static unsigned getSectorSize(uint8_t flags) | ||||
| 		} | ||||
| 	} | ||||
| 	Error() << "not reachable"; | ||||
| 	throw 0; | ||||
| } | ||||
|  | ||||
| class Jv3ImageReader : public ImageReader | ||||
| class Jv3ImageReader : public ImageReader, DisassemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	Jv3ImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
| 		std::ifstream stream(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!stream.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
| 		inputFile.seekg( 0, std::ios::end); | ||||
| 		unsigned inputFileSize = inputFile.tellg(); | ||||
| 		unsigned headerPtr = 0; | ||||
| 		SectorSet sectors; | ||||
| 		Bytes image; | ||||
| 		image.writer() += stream; | ||||
| 		ByteReader br(image); | ||||
|  | ||||
| 		off_t headerPtr = 0; | ||||
| 		for (;;) | ||||
| 		{ | ||||
| 			unsigned dataPtr = headerPtr + 2901*3 + 1; | ||||
| 			if (dataPtr >= inputFileSize) | ||||
| 			off_t dataPtr = headerPtr + 2901*3 + 1; | ||||
| 			if (dataPtr >= image.size()) | ||||
| 				break; | ||||
|  | ||||
| 			br.seek(headerPtr); | ||||
| 			for (unsigned i=0; i<2901; i++) | ||||
| 			{ | ||||
| 				SectorHeader header = {0, 0, 0xff}; | ||||
| 				inputFile.seekg(headerPtr); | ||||
| 				inputFile.read((char*) &header, 3); | ||||
| 				unsigned sectorSize = getSectorSize(header.flags); | ||||
| 				if ((header.flags & JV3_FREEF) != JV3_FREEF) | ||||
| 				uint8_t track = br.read_8(); | ||||
| 				uint8_t sector = br.read_8(); | ||||
| 				uint8_t flags = br.read_8(); | ||||
|  | ||||
| 				if ((flags & JV3_FREEF) != JV3_FREEF) | ||||
| 				{ | ||||
| 					Bytes data(sectorSize); | ||||
| 					inputFile.seekg(dataPtr); | ||||
| 					inputFile.read((char*) data.begin(), sectorSize); | ||||
| 					unsigned side = !!(flags & JV3_SIDE); | ||||
| 					unsigned length = getSectorSize(flags); | ||||
|  | ||||
| 					unsigned head = !!(header.flags & JV3_SIDE); | ||||
|                     std::unique_ptr<Sector>& sector = sectors.get(header.track, head, header.sector); | ||||
|                     sector.reset(new Sector); | ||||
|                     sector->status = Sector::OK; | ||||
|                     sector->logicalTrack = sector->physicalTrack = header.track; | ||||
|                     sector->logicalSide = sector->physicalSide = head; | ||||
|                     sector->logicalSector = header.sector; | ||||
|                     sector->data = data; | ||||
| 					std::unique_ptr<Sector> s(new Sector); | ||||
| 					s->status = (flags & JV3_ERROR) ? Sector::BAD_CHECKSUM : Sector::OK; | ||||
| 					s->physicalTrack = s->logicalTrack = track; | ||||
| 					s->physicalSide = s->logicalSide = side; | ||||
| 					s->logicalSector = sector; | ||||
| 					s->data = image.slice(dataPtr, length); | ||||
| 					_sectors[std::make_tuple(track, side, sector)] = std::move(s); | ||||
| 					dataPtr += length; | ||||
| 				} | ||||
|  | ||||
| 				headerPtr += 3; | ||||
| 				dataPtr += sectorSize; | ||||
| 			} | ||||
|  | ||||
| 			/* dataPtr is now pointing at the beginning of the next chunk. */ | ||||
| @@ -128,8 +119,31 @@ public: | ||||
| 			headerPtr = dataPtr; | ||||
| 		} | ||||
|  | ||||
|         return sectors; | ||||
|         std::cout << fmt::format("JV3: reading input image of {} sectors total\n", | ||||
| 						_sectors.size()); | ||||
| 	} | ||||
|  | ||||
| 	const DisassemblingGeometryMapper* getGeometryMapper() const | ||||
| 	{ | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	Bytes getBlock(size_t offset, size_t length) const | ||||
| 	{ | ||||
| 		throw "unimplemented"; | ||||
| 	} | ||||
|  | ||||
| 	const Sector* get(unsigned cylinder, unsigned head, unsigned sector) const | ||||
| 	{ | ||||
| 		auto sit = _sectors.find(std::make_tuple(cylinder, head, sector)); | ||||
| 		if (sit == _sectors.end()) | ||||
| 			return nullptr; | ||||
|  | ||||
| 		return sit->second.get(); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	std::map<std::tuple<int, int, int>, std::unique_ptr<Sector>> _sectors; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createJv3ImageReader(const ImageReaderProto& config) | ||||
|   | ||||
| @@ -1,109 +0,0 @@ | ||||
| /* Image reader for Northstar floppy disk images */ | ||||
|  | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/imagereader/imagereader.pb.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| class NsiImageReader : public ImageReader | ||||
| { | ||||
| public: | ||||
| 	NsiImageReader(const ImageReaderProto& config): | ||||
| 		ImageReader(config) | ||||
| 	{} | ||||
|  | ||||
| 	SectorSet readImage() | ||||
| 	{ | ||||
|         std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary); | ||||
|         if (!inputFile.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
|  | ||||
| 		const auto begin = inputFile.tellg(); | ||||
| 		inputFile.seekg(0, std::ios::end); | ||||
| 		const auto end = inputFile.tellg(); | ||||
| 		const auto fsize = (end - begin); | ||||
|  | ||||
| 		std::cout << "NSI: Autodetecting geometry based on file size: " << fsize << std::endl; | ||||
|  | ||||
| 		int numCylinders = 35; | ||||
| 		int numSectors = 10; | ||||
| 		int numHeads = 2; | ||||
| 		int sectorSize = 512; | ||||
|  | ||||
| 		switch (fsize) { | ||||
| 			case 358400: | ||||
| 				numHeads = 2; | ||||
| 				sectorSize = 512; | ||||
| 				break; | ||||
|  | ||||
| 			case 179200: | ||||
| 				numHeads = 1; | ||||
| 				sectorSize = 512; | ||||
| 				break; | ||||
| 				 | ||||
| 			case 89600: | ||||
| 				numHeads = 1; | ||||
| 				sectorSize = 256; | ||||
| 				break; | ||||
|  | ||||
| 			default: | ||||
| 				Error() << "NSI: unknown file size"; | ||||
| 		} | ||||
|  | ||||
|         size_t trackSize = numSectors * sectorSize; | ||||
|  | ||||
|         std::cout << fmt::format("reading {} tracks, {} heads, {} sectors, {} bytes per sector, {} kB total", | ||||
|                         numCylinders, numHeads, | ||||
|                         numSectors, sectorSize, | ||||
|                         numCylinders * numHeads * trackSize / 1024) | ||||
|                 << std::endl; | ||||
|  | ||||
|         SectorSet sectors; | ||||
|         unsigned sectorFileOffset; | ||||
|  | ||||
|         for (int head = 0; head < numHeads; head++) | ||||
|         { | ||||
|             for (int track = 0; track < numCylinders; track++) | ||||
|             { | ||||
|                 for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
|                 { | ||||
|                     if (head == 0) { /* Head 0 is from track 0-34 */ | ||||
|                         sectorFileOffset = track * trackSize + sectorId * sectorSize; | ||||
|                     } | ||||
|                     else { /* Head 1 is from track 70-35 */ | ||||
|                         sectorFileOffset = (trackSize * numCylinders) + /* Skip over side 0 */ | ||||
|                             ((numCylinders - track - 1) * trackSize) + | ||||
|                             (sectorId * sectorSize); /* Sector offset from beginning of track. */ | ||||
|                     } | ||||
|  | ||||
|                     inputFile.seekg(sectorFileOffset, std::ios::beg); | ||||
|  | ||||
|                     Bytes data(sectorSize); | ||||
|                     inputFile.read((char*) data.begin(), sectorSize); | ||||
|  | ||||
|                     std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId); | ||||
|                     sector.reset(new Sector); | ||||
|                     sector->status = Sector::OK; | ||||
|                     sector->logicalTrack = sector->physicalTrack = track; | ||||
|                     sector->logicalSide = sector->physicalSide = head; | ||||
|                     sector->logicalSector = sectorId; | ||||
|                     sector->data = data; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return sectors; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageReader> ImageReader::createNsiImageReader( | ||||
| 	const ImageReaderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<ImageReader>(new NsiImageReader(config)); | ||||
| } | ||||
|  | ||||
| @@ -1,62 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include "ldbs.h" | ||||
| #include "lib/config.pb.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| static int sectors_per_track(int track) | ||||
| { | ||||
|     if (track < 17) | ||||
|         return 21; | ||||
|     if (track < 24) | ||||
|         return 19; | ||||
|     if (track < 30) | ||||
|         return 18; | ||||
|     return 17; | ||||
| } | ||||
|  | ||||
| class D64ImageWriter : public ImageWriter | ||||
| { | ||||
| public: | ||||
| 	D64ImageWriter(const ImageWriterProto& config): | ||||
| 		ImageWriter(config) | ||||
| 	{} | ||||
|  | ||||
| 	void writeImage(const SectorSet& sectors) | ||||
| 	{ | ||||
| 		std::cout << "writing D64 triangular image\n"; | ||||
|  | ||||
| 		std::ofstream outputFile(_config.filename(), std::ios::out | std::ios::binary); | ||||
| 		if (!outputFile.is_open()) | ||||
| 			Error() << "cannot open output file"; | ||||
|  | ||||
|         uint32_t offset = 0; | ||||
| 		for (int track = 0; track < 40; track++) | ||||
| 		{ | ||||
|             int sectorCount = sectors_per_track(track); | ||||
|             for (int sectorId = 0; sectorId < sectorCount; sectorId++) | ||||
|             { | ||||
|                 const auto& sector = sectors.get(track, 0, sectorId); | ||||
|                 if (sector) | ||||
|                 { | ||||
|                     outputFile.seekp(offset); | ||||
|                     outputFile.write((const char*) sector->data.cbegin(), 256); | ||||
|                 } | ||||
|  | ||||
|                 offset += 256; | ||||
|             } | ||||
| 		} | ||||
|     } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageWriter> ImageWriter::createD64ImageWriter(const ImageWriterProto& config) | ||||
| { | ||||
|     return std::unique_ptr<ImageWriter>(new D64ImageWriter(config)); | ||||
| } | ||||
|  | ||||
| @@ -166,6 +166,9 @@ public: | ||||
|  | ||||
| 		image.writeToFile(_config.filename()); | ||||
|     } | ||||
|  | ||||
| 	void putBlock(size_t offset, size_t length, const Bytes& data) | ||||
| 	{ throw "unimplemented"; } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageWriter> ImageWriter::createDiskCopyImageWriter( | ||||
|   | ||||
| @@ -17,17 +17,13 @@ std::unique_ptr<ImageWriter> ImageWriter::create(const ImageWriterProto& config) | ||||
| 		case ImageWriterProto::kImg: | ||||
| 			return ImageWriter::createImgImageWriter(config); | ||||
|  | ||||
| 		case ImageWriterProto::kD64: | ||||
| 			return ImageWriter::createD64ImageWriter(config); | ||||
|  | ||||
| 		case ImageWriterProto::kLdbs: | ||||
| 			return ImageWriter::createLDBSImageWriter(config); | ||||
|  | ||||
| #if 0 | ||||
| 		case ImageWriterProto::kDiskcopy: | ||||
| 			return ImageWriter::createDiskCopyImageWriter(config); | ||||
|  | ||||
| 		case ImageWriterProto::kNsi: | ||||
| 			return ImageWriter::createNsiImageWriter(config); | ||||
| #endif | ||||
|  | ||||
| 		default: | ||||
| 			Error() << "bad output image config"; | ||||
| @@ -40,13 +36,13 @@ void ImageWriter::updateConfigForFilename(ImageWriterProto* proto, const std::st | ||||
| 	static const std::map<std::string, std::function<void(void)>> formats = | ||||
| 	{ | ||||
| 		{".adf",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".d64",      [&]() { proto->mutable_d64(); }}, | ||||
| 		{".d64",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".d81",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".diskcopy", [&]() { proto->mutable_diskcopy(); }}, | ||||
| 		{".img",      [&]() { proto->mutable_img(); }}, | ||||
| 		{".ldbs",     [&]() { proto->mutable_ldbs(); }}, | ||||
| 		{".st",       [&]() { proto->mutable_img(); }}, | ||||
| 		{".nsi",      [&]() { proto->mutable_nsi(); }}, | ||||
| 		{".nsi",      [&]() { proto->mutable_img(); }}, | ||||
| 	}; | ||||
|  | ||||
| 	for (const auto& it : formats) | ||||
| @@ -66,125 +62,3 @@ ImageWriter::ImageWriter(const ImageWriterProto& config): | ||||
| 	_config(config) | ||||
| {} | ||||
|  | ||||
| void ImageWriter::writeCsv(const SectorSet& sectors, const std::string& filename) | ||||
| { | ||||
| 	std::ofstream f(filename, std::ios::out); | ||||
| 	if (!f.is_open()) | ||||
| 		Error() << "cannot open CSV report file"; | ||||
|  | ||||
| 	f << "\"Physical track\"," | ||||
| 		"\"Physical side\"," | ||||
| 		"\"Logical track\"," | ||||
| 		"\"Logical side\"," | ||||
| 		"\"Logical sector\"," | ||||
| 		"\"Clock (ns)\"," | ||||
| 		"\"Header start (ns)\"," | ||||
| 		"\"Header end (ns)\"," | ||||
| 		"\"Data start (ns)\"," | ||||
| 		"\"Data end (ns)\"," | ||||
| 		"\"Raw data address (bytes)\"," | ||||
| 		"\"User payload length (bytes)\"," | ||||
| 		"\"Status\"" | ||||
| 		"\n"; | ||||
|  | ||||
| 	for (const auto& it : sectors.get()) | ||||
| 	{ | ||||
| 		const auto& sector = it.second; | ||||
| 		f << fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{}\n", | ||||
| 			sector->physicalTrack, | ||||
| 			sector->physicalSide, | ||||
| 			sector->logicalTrack, | ||||
| 			sector->logicalSide, | ||||
| 			sector->logicalSector, | ||||
| 			sector->clock, | ||||
| 			sector->headerStartTime, | ||||
| 			sector->headerEndTime, | ||||
| 			sector->dataStartTime, | ||||
| 			sector->dataEndTime, | ||||
| 			sector->position.bytes, | ||||
| 			sector->data.size(), | ||||
| 			Sector::statusToString(sector->status) | ||||
| 		); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void ImageWriter::printMap(const SectorSet& sectors) | ||||
| { | ||||
| 	unsigned numCylinders; | ||||
| 	unsigned numHeads; | ||||
| 	unsigned numSectors; | ||||
| 	unsigned numBytes; | ||||
| 	sectors.calculateSize(numCylinders, numHeads, numSectors, numBytes); | ||||
|  | ||||
| 	int badSectors = 0; | ||||
| 	int missingSectors = 0; | ||||
| 	int totalSectors = 0; | ||||
|  | ||||
| 	std::cout << "     Tracks -> 1         2         3         "; | ||||
| 	if (numCylinders > 40) { | ||||
| 		std::cout << "4         5         6         7         8"; | ||||
| 	} | ||||
| 	std::cout << std::endl; | ||||
| 	std::cout << "H.SS 0123456789012345678901234567890123456789"; | ||||
| 	if (numCylinders > 40) { | ||||
| 		std::cout << "01234567890123456789012345678901234567890123"; | ||||
| 	} | ||||
| 	std::cout << std::endl; | ||||
|  | ||||
| 	for (int head = 0; head < numHeads; head++) | ||||
| 	{ | ||||
| 		for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
| 		{ | ||||
| 			std::cout << fmt::format("{}.{:2} ", head, sectorId); | ||||
| 			for (int track = 0; track < numCylinders; track++) | ||||
| 			{ | ||||
| 				const auto& sector = sectors.get(track, head, sectorId); | ||||
| 				if (!sector) | ||||
| 				{ | ||||
| 					std::cout << 'X'; | ||||
| 					missingSectors++; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					switch (sector->status) | ||||
| 					{ | ||||
| 						case Sector::OK: | ||||
|                             std::cout << '.'; | ||||
|                             break; | ||||
|  | ||||
|                         case Sector::BAD_CHECKSUM: | ||||
|                             std::cout << 'B'; | ||||
|                             badSectors++; | ||||
|                             break; | ||||
|  | ||||
|                         case Sector::CONFLICT: | ||||
|                             std::cout << 'C'; | ||||
|                             badSectors++; | ||||
|                             break; | ||||
|  | ||||
|                         default: | ||||
|                             std::cout << '?'; | ||||
|                             break; | ||||
|                     } | ||||
| 				} | ||||
| 				totalSectors++; | ||||
| 			} | ||||
| 			std::cout << std::endl; | ||||
| 		} | ||||
| 	} | ||||
| 	int goodSectors = totalSectors - missingSectors - badSectors; | ||||
| 	if (totalSectors == 0) | ||||
| 		std::cout << "No sectors in output; skipping analysis" << std::endl; | ||||
| 	else | ||||
| 	{ | ||||
| 		std::cout << "Good sectors: " << goodSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*goodSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
| 		std::cout << "Missing sectors: " << missingSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*missingSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
| 		std::cout << "Bad sectors: " << badSectors << "/" << totalSectors | ||||
| 				  << " (" << (100*badSectors/totalSectors) << "%)" | ||||
| 				  << std::endl; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| class SectorSet; | ||||
| class ImageWriterProto; | ||||
| class AssemblingGeometryMapper; | ||||
|  | ||||
| class ImageWriter | ||||
| { | ||||
| @@ -18,17 +19,14 @@ public: | ||||
| 		const ImageWriterProto& config); | ||||
|     static std::unique_ptr<ImageWriter> createLDBSImageWriter( | ||||
| 		const ImageWriterProto& config); | ||||
|     static std::unique_ptr<ImageWriter> createD64ImageWriter( | ||||
| 		const ImageWriterProto& config); | ||||
|     static std::unique_ptr<ImageWriter> createDiskCopyImageWriter( | ||||
| 		const ImageWriterProto& config); | ||||
|     static std::unique_ptr<ImageWriter> createNsiImageWriter( | ||||
| 		const ImageWriterProto& config); | ||||
|  | ||||
| public: | ||||
| 	void printMap(const SectorSet& sectors); | ||||
| 	void writeCsv(const SectorSet& sectors, const std::string& filename); | ||||
| 	virtual void writeImage(const SectorSet& sectors) = 0; | ||||
| 	virtual void putBlock(size_t offset, size_t length, const Bytes& data) = 0; | ||||
| 	virtual const AssemblingGeometryMapper* getGeometryMapper() const { return nullptr; } | ||||
|  | ||||
| protected: | ||||
| 	const ImageWriterProto& _config; | ||||
|   | ||||
| @@ -3,19 +3,15 @@ syntax = "proto2"; | ||||
| import "lib/imagereader/imagereader.proto"; | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message D64OutputProto {} | ||||
| message LDBSOutputProto {} | ||||
| message DiskCopyOutputProto {} | ||||
| message NsiOutputProto {} | ||||
|  | ||||
| message ImageWriterProto { | ||||
| 	optional string filename = 1 [(help) = "filename of output sector image"]; | ||||
| 	oneof format { | ||||
| 		ImgInputOutputProto img = 2; | ||||
| 		D64OutputProto d64 = 3; | ||||
| 		LDBSOutputProto ldbs = 4; | ||||
| 		DiskCopyOutputProto diskcopy = 5; | ||||
| 		NsiOutputProto nsi = 6; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -14,63 +14,27 @@ class ImgImageWriter : public ImageWriter | ||||
| public: | ||||
| 	ImgImageWriter(const ImageWriterProto& config): | ||||
| 		ImageWriter(config) | ||||
| 	{} | ||||
|  | ||||
| 	void writeImage(const SectorSet& sectors) | ||||
| 	{ | ||||
| 		unsigned autoTracks; | ||||
| 		unsigned autoSides; | ||||
| 		unsigned autoSectors; | ||||
| 		unsigned autoBytes; | ||||
| 		sectors.calculateSize(autoTracks, autoSides, autoSectors, autoBytes); | ||||
| 		_of.open(_config.filename(), std::ios::out | std::ios::trunc | std::ios::binary); | ||||
|         if (!_of.is_open()) | ||||
|             Error() << "cannot open input file"; | ||||
| 	} | ||||
|  | ||||
| 		int tracks = _config.img().has_tracks() ? _config.img().tracks() : autoTracks; | ||||
| 		int sides = _config.img().has_sides() ? _config.img().sides() : autoSides; | ||||
| 	~ImgImageWriter() | ||||
| 	{ | ||||
| 		_of.seekp(0, std::ios::end); | ||||
|         std::cout << fmt::format("IMG: written output image of {} kB total\n", | ||||
| 						_of.tellp() / 1024); | ||||
| 	} | ||||
|  | ||||
| 		std::ofstream outputFile(_config.filename(), std::ios::out | std::ios::binary); | ||||
| 		if (!outputFile.is_open()) | ||||
| 			Error() << "cannot open output file"; | ||||
|  | ||||
| 		for (int track = 0; track < tracks; track++) | ||||
| 		{ | ||||
| 			for (int side = 0; side < sides; side++) | ||||
| 			{ | ||||
| 				ImgInputOutputProto::TrackdataProto trackdata; | ||||
| 				getTrackFormat(trackdata, track, side); | ||||
|  | ||||
| 				int numSectors = trackdata.has_sectors() ? trackdata.sectors() : autoSectors; | ||||
| 				int sectorSize = trackdata.has_sector_size() ? trackdata.sector_size() : autoBytes; | ||||
|  | ||||
| 				for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
| 				{ | ||||
| 					const auto& sector = sectors.get(track, side, sectorId); | ||||
| 					if (sector) | ||||
| 						sector->data.slice(0, sectorSize).writeTo(outputFile); | ||||
| 					else | ||||
| 						outputFile.seekp(sectorSize, std::ios::cur); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		std::cout << fmt::format("wrote {} tracks, {} sides, {} kB total\n", | ||||
| 						tracks, sides, | ||||
| 						outputFile.tellp() / 1024); | ||||
| 	void putBlock(size_t offset, size_t length, const Bytes& data) | ||||
| 	{ | ||||
| 		_of.seekp(offset); | ||||
| 		data.slice(0, length).writeTo(_of); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	void getTrackFormat(ImgInputOutputProto::TrackdataProto& trackdata, unsigned track, unsigned side) | ||||
| 	{ | ||||
| 		trackdata.Clear(); | ||||
| 		for (const ImgInputOutputProto::TrackdataProto& f : _config.img().trackdata()) | ||||
| 		{ | ||||
| 			if (f.has_track() && (f.track() != track)) | ||||
| 				continue; | ||||
| 			if (f.has_side() && (f.side() != side)) | ||||
| 				continue; | ||||
|  | ||||
| 			trackdata.MergeFrom(f); | ||||
| 		} | ||||
| 	} | ||||
| 	std::ofstream _of; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageWriter> ImageWriter::createImgImageWriter( | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include "ldbs.h" | ||||
| #include "lib/config.pb.h" | ||||
| @@ -10,14 +11,15 @@ | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| class LDBSImageWriter : public ImageWriter | ||||
| class LDBSImageWriter : public ImageWriter, public AssemblingGeometryMapper | ||||
| { | ||||
| public: | ||||
| 	LDBSImageWriter(const ImageWriterProto& config): | ||||
| 		ImageWriter(config) | ||||
| 	{} | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	void writeImage(const SectorSet& sectors) | ||||
| 	~LDBSImageWriter() | ||||
| 	{ | ||||
|         LDBS ldbs; | ||||
|  | ||||
| @@ -25,13 +27,29 @@ public: | ||||
| 		unsigned numHeads; | ||||
| 		unsigned numSectors; | ||||
| 		unsigned numBytes; | ||||
| 		sectors.calculateSize(numCylinders, numHeads, numSectors, numBytes); | ||||
| 		_sectors.calculateSize(numCylinders, numHeads, numSectors, numBytes); | ||||
|  | ||||
| 		std::cout << fmt::format("writing {} tracks, {} heads, {} sectors, {} bytes per sector", | ||||
| 		std::cout << fmt::format("LDBS: writing {} tracks, {} heads, {} sectors, {} bytes per sector", | ||||
| 						numCylinders, numHeads, | ||||
| 						numSectors, numBytes) | ||||
| 				<< std::endl; | ||||
|  | ||||
| 		Bytes geomBlock; | ||||
| 		ByteWriter geomBlockWriter(geomBlock); | ||||
| 		geomBlockWriter.write_8(0); /* alternating sides */ | ||||
| 		geomBlockWriter.write_le16(numCylinders); | ||||
| 		geomBlockWriter.write_8(numHeads); | ||||
| 		geomBlockWriter.write_8(numSectors); | ||||
| 		geomBlockWriter.write_8(0); /* first sector ID */ | ||||
| 		geomBlockWriter.write_le16(numBytes); | ||||
| 		geomBlockWriter.write_8(0); /* data rate */ | ||||
| 		geomBlockWriter.write_8(0); /* read/write gap */ | ||||
| 		geomBlockWriter.write_8(0); /* format gap */ | ||||
| 		geomBlockWriter.write_8(0); /* recording mode */ | ||||
| 		geomBlockWriter.write_8(0); /* complement flag */ | ||||
| 		geomBlockWriter.write_8(0); /* disable multitrack read/writes */ | ||||
| 		geomBlockWriter.write_8(0); /* do not skip deleted data */ | ||||
|  | ||||
|         Bytes trackDirectory; | ||||
|         ByteWriter trackDirectoryWriter(trackDirectory); | ||||
|         int trackDirectorySize = 0; | ||||
| @@ -47,7 +65,7 @@ public: | ||||
|                 int actualSectors = 0; | ||||
| 				for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
| 				{ | ||||
| 					const auto& sector = sectors.get(track, head, sectorId); | ||||
| 					const auto& sector = _sectors.get(track, head, sectorId); | ||||
| 					if (sector) | ||||
|                         actualSectors++; | ||||
|                 } | ||||
| @@ -63,7 +81,7 @@ public: | ||||
|  | ||||
| 				for (int sectorId = 0; sectorId < numSectors; sectorId++) | ||||
| 				{ | ||||
| 					const auto& sector = sectors.get(track, head, sectorId); | ||||
| 					const auto& sector = _sectors.get(track, head, sectorId); | ||||
| 					if (sector) | ||||
| 					{ | ||||
|                         uint32_t sectorLabel = (('S') << 24) | ((track & 0xff) << 16) | (head << 8) | sectorId; | ||||
| @@ -92,13 +110,37 @@ public: | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		trackDirectoryWriter.write_be32(LDBS_GEOM_BLOCK); | ||||
| 		trackDirectoryWriter.write_le32(ldbs.put(geomBlock, LDBS_GEOM_BLOCK)); | ||||
| 		trackDirectorySize++; | ||||
|  | ||||
|         trackDirectoryWriter.seek(0); | ||||
|         trackDirectoryWriter.write_le16(trackDirectorySize); | ||||
|  | ||||
|         uint32_t trackDirectoryAddress = ldbs.put(trackDirectory, LDBS_TRACK_BLOCK); | ||||
|         Bytes data = ldbs.write(trackDirectoryAddress); | ||||
|         data.writeToFile(_config.filename()); | ||||
|     } | ||||
|  | ||||
|         std::cout << fmt::format("LDBS: written output image of {} kB total\n", | ||||
| 						data.size() / 1024); | ||||
| 	} | ||||
|  | ||||
| 	const AssemblingGeometryMapper* getGeometryMapper() const | ||||
| 	{ | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	void put(const Sector& sector) const | ||||
| 	{ | ||||
| 		auto& ptr = _sectors.get(sector.logicalTrack, sector.logicalSide, sector.logicalSector); | ||||
| 		ptr.reset(new Sector(sector)); | ||||
| 	} | ||||
|  | ||||
| 	void putBlock(size_t offset, size_t length, const Bytes& data) | ||||
| 	{ throw "unimplemented"; } | ||||
|  | ||||
| private: | ||||
| 	mutable SectorSet _sectors; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageWriter> ImageWriter::createLDBSImageWriter(const ImageWriterProto& config) | ||||
|   | ||||
| @@ -1,70 +0,0 @@ | ||||
| #include "globals.h" | ||||
| #include "flags.h" | ||||
| #include "sector.h" | ||||
| #include "sectorset.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "fmt/format.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "arch/northstar/northstar.h" | ||||
| #include "lib/imagewriter/imagewriter.pb.h" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | ||||
| class NsiImageWriter : public ImageWriter | ||||
| { | ||||
| public: | ||||
| 	NsiImageWriter(const ImageWriterProto& config): | ||||
| 		ImageWriter(config) | ||||
| 	{} | ||||
|  | ||||
| 	void writeImage(const SectorSet& sectors) | ||||
| 	{ | ||||
| 		unsigned autoTracks; | ||||
| 		unsigned autoSides; | ||||
| 		unsigned autoSectors; | ||||
| 		unsigned autoBytes; | ||||
| 		sectors.calculateSize(autoTracks, autoSides, autoSectors, autoBytes); | ||||
|  | ||||
| 		size_t trackSize = autoSectors * autoBytes; | ||||
|  | ||||
| 		std::cout << fmt::format("Writing {} cylinders, {} heads, {} sectors, {} ({} bytes/sector), {} kB total", | ||||
| 				autoTracks, autoSides, | ||||
| 				autoSectors, autoBytes == 256 ? "SD" : "DD", autoBytes, | ||||
| 				autoTracks * trackSize / 1024) | ||||
| 				<< std::endl; | ||||
|  | ||||
| 		std::ofstream outputFile(_config.filename(), std::ios::out | std::ios::binary); | ||||
| 		if (!outputFile.is_open()) | ||||
| 			Error() << "cannot open output file"; | ||||
|  | ||||
| 		unsigned sectorFileOffset; | ||||
| 		for (int track = 0; track < autoTracks * autoSides; track++) | ||||
| 		{ | ||||
| 			int head = (track < autoTracks) ? 0 : 1; | ||||
| 			for (int sectorId = 0; sectorId < autoSectors; sectorId++) | ||||
| 			{ | ||||
| 				const auto& sector = sectors.get(track % autoTracks, head, sectorId); | ||||
| 				if (sector) | ||||
| 				{ | ||||
| 					if (head == 0) { /* Side 0 is from track 0-34 */ | ||||
| 						sectorFileOffset = track * trackSize + sectorId * autoBytes; | ||||
| 					} | ||||
| 					else { /* Side 1 is from track 70-35 */ | ||||
| 						sectorFileOffset = (autoBytes * autoSectors * autoTracks) + /* Skip over side 0 */ | ||||
| 							((autoTracks - 1) - (track % autoTracks)) * (autoBytes * autoSectors) + | ||||
| 							(sectorId * autoBytes); /* Sector offset from beginning of track. */ | ||||
| 					} | ||||
| 					outputFile.seekp(sectorFileOffset, std::ios::beg); | ||||
| 					sector->data.slice(0, autoBytes).writeTo(outputFile); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<ImageWriter> ImageWriter::createNsiImageWriter( | ||||
| 	const ImageWriterProto& config) | ||||
| { | ||||
|     return std::unique_ptr<ImageWriter>(new NsiImageWriter(config)); | ||||
| } | ||||
| @@ -11,6 +11,7 @@ class Bytes; | ||||
| #define LDBS_FILE_TYPE 0x44534B02 /* "DSK\02" */ | ||||
| #define LDBS_BLOCK_MAGIC 0x4C444201 /* "LDB\01" */ | ||||
| #define LDBS_TRACK_BLOCK 0x44495201 /* "DIR\01" */ | ||||
| #define LDBS_GEOM_BLOCK 0x47454f4d /* "GEOM" */ | ||||
|  | ||||
| class LDBS | ||||
| { | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
| #include "decoders/rawbits.h" | ||||
| #include "track.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include "proto.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| @@ -62,7 +63,7 @@ static void replace_sector(std::unique_ptr<Sector>& replacing, Sector& replaceme | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWriter& writer) | ||||
| void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, AssemblingGeometryMapper& geometryMapper) | ||||
| { | ||||
| 	if (config.decoder().has_copy_flux_to()) | ||||
| 		outputFluxSink = FluxSink::create(config.decoder().copy_flux_to()); | ||||
| @@ -186,10 +187,10 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit | ||||
| 		} | ||||
|     } | ||||
|  | ||||
| 	writer.printMap(allSectors); | ||||
| 	geometryMapper.printMap(allSectors); | ||||
| 	if (config.decoder().has_write_csv_to()) | ||||
| 		writer.writeCsv(allSectors, config.decoder().write_csv_to()); | ||||
| 	writer.writeImage(allSectors); | ||||
| 		geometryMapper.writeCsv(allSectors, config.decoder().write_csv_to()); | ||||
| 	geometryMapper.put(allSectors); | ||||
|  | ||||
| 	if (failures) | ||||
| 		std::cerr << "Warning: some sectors could not be decoded." << std::endl; | ||||
|   | ||||
| @@ -5,12 +5,12 @@ class AbstractDecoder; | ||||
| class FluxSink; | ||||
| class FluxSource; | ||||
| class Fluxmap; | ||||
| class ImageWriter; | ||||
| class AssemblingGeometryMapper; | ||||
| class Track; | ||||
|  | ||||
| extern std::vector<std::unique_ptr<Track>> readTracks(); | ||||
|  | ||||
| extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, ImageWriter& writer); | ||||
| extern void readDiskCommand(FluxSource& source, AbstractDecoder& decoder, AssemblingGeometryMapper& geometryMapper); | ||||
| extern void rawReadDiskCommand(FluxSource& source, FluxSink& sink); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -65,13 +65,12 @@ void fillBitmapTo(std::vector<bool>& bitmap, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void writeDiskCommand(ImageReader& imageReader, AbstractEncoder& encoder, FluxSink& fluxSink) | ||||
| void writeDiskCommand(AbstractEncoder& encoder, FluxSink& fluxSink) | ||||
| { | ||||
| 	SectorSet allSectors = imageReader.readImage(); | ||||
| 	writeTracks(fluxSink, | ||||
| 		[&](int track, int side) -> std::unique_ptr<Fluxmap> | ||||
| 		{ | ||||
| 			return encoder.encode(track, side, allSectors); | ||||
| 			return encoder.encode(track, side); | ||||
| 		} | ||||
| 	); | ||||
| } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ extern void fillBitmapTo(std::vector<bool>& bitmap, | ||||
| 		unsigned& cursor, unsigned terminateAt, | ||||
| 		const std::vector<bool>& pattern); | ||||
| 	 | ||||
| extern void writeDiskCommand(ImageReader& imageReader, AbstractEncoder& encoder, FluxSink& fluxSink); | ||||
| extern void writeDiskCommand(AbstractEncoder& encoder, FluxSink& fluxSink); | ||||
| extern void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink); | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										14
									
								
								mkninja.sh
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								mkninja.sh
									
									
									
									
									
								
							| @@ -282,6 +282,7 @@ buildproto libproto.a \ | ||||
|     lib/encoders/encoders.proto \ | ||||
|     lib/fluxsource/fluxsource.proto \ | ||||
|     lib/fluxsink/fluxsink.proto \ | ||||
|     lib/geometry/geometry.proto \ | ||||
|     lib/imagereader/imagereader.proto \ | ||||
|     lib/imagewriter/imagewriter.proto \ | ||||
|     lib/usb/usb.proto \ | ||||
| @@ -337,21 +338,19 @@ buildlibrary libbackend.a \ | ||||
|     lib/fluxsource/scpfluxsource.cc \ | ||||
|     lib/fluxsource/sqlitefluxsource.cc \ | ||||
|     lib/fluxsource/testpatternfluxsource.cc \ | ||||
|     lib/geometry/simplemapper.cc \ | ||||
|     lib/geometry/geometry.cc \ | ||||
|     lib/globals.cc \ | ||||
|     lib/hexdump.cc \ | ||||
|     lib/imagereader/d64imagereader.cc \ | ||||
|     lib/imagereader/diskcopyimagereader.cc \ | ||||
|     lib/imagereader/imagereader.cc \ | ||||
|     lib/imagereader/imdimagereader.cc \ | ||||
|     lib/imagereader/imgimagereader.cc \ | ||||
|     lib/imagereader/jv3imagereader.cc \ | ||||
|     lib/imagereader/nsiimagereader.cc \ | ||||
|     lib/imagewriter/d64imagewriter.cc \ | ||||
|     lib/imagewriter/diskcopyimagewriter.cc \ | ||||
|     lib/imagewriter/imagewriter.cc \ | ||||
|     lib/imagewriter/imgimagewriter.cc \ | ||||
|     lib/imagewriter/ldbsimagewriter.cc \ | ||||
|     lib/imagewriter/nsiimagewriter.cc \ | ||||
|     lib/ldbs.cc \ | ||||
|     lib/proto.cc \ | ||||
|     lib/reader.cc \ | ||||
| @@ -384,7 +383,9 @@ READABLES="\ | ||||
|     macintosh \ | ||||
|     micropolis \ | ||||
|     mx \ | ||||
|     northstar \ | ||||
|     northstar87 \ | ||||
|     northstar175 \ | ||||
|     northstar350 \ | ||||
|     tids990 \ | ||||
|     victor9k \ | ||||
|     zilogmcz \ | ||||
| @@ -411,7 +412,8 @@ WRITABLES="\ | ||||
|     ibm360_525 \ | ||||
|     ibm720 \ | ||||
|     ibm720_525 \ | ||||
|     macintosh \ | ||||
|     macintosh400 \ | ||||
|     macintosh800 \ | ||||
|     northstar87 \ | ||||
|     northstar175 \ | ||||
|     northstar350 \ | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include "arch/brother/brother.h" | ||||
| #include "arch/ibm/ibm.h" | ||||
| #include "imagewriter/imagewriter.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include "fluxengine.h" | ||||
| #include <google/protobuf/text_format.h> | ||||
| @@ -78,10 +79,11 @@ int mainRead(int argc, const char* argv[]) | ||||
| 		Error() << "you cannot copy flux to a hardware device"; | ||||
|  | ||||
| 	std::unique_ptr<FluxSource> fluxSource(FluxSource::create(config.input().flux())); | ||||
| 	std::unique_ptr<AbstractDecoder> decoder(AbstractDecoder::create(config.decoder())); | ||||
| 	std::unique_ptr<ImageWriter> writer(ImageWriter::create(config.output().image())); | ||||
| 	std::unique_ptr<AssemblingGeometryMapper> geometryMapper(createSimpleAssemblingGeometryMapper(config.geometry(), *writer)); | ||||
| 	std::unique_ptr<AbstractDecoder> decoder(AbstractDecoder::create(config.decoder())); | ||||
|  | ||||
| 	readDiskCommand(*fluxSource, *decoder, *writer); | ||||
| 	readDiskCommand(*fluxSource, *decoder, *geometryMapper); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -13,6 +13,7 @@ | ||||
| #include "arch/ibm/ibm.h" | ||||
| #include "imagereader/imagereader.h" | ||||
| #include "fluxengine.h" | ||||
| #include "geometry/geometry.h" | ||||
| #include "fmt/format.h" | ||||
| #include <google/protobuf/text_format.h> | ||||
| #include <fstream> | ||||
| @@ -65,10 +66,11 @@ int mainWrite(int argc, const char* argv[]) | ||||
| 		Error() << "incomplete config (did you remember to specify the format?)"; | ||||
|  | ||||
| 	std::unique_ptr<ImageReader> reader(ImageReader::create(config.input().image())); | ||||
| 	std::unique_ptr<AbstractEncoder> encoder(AbstractEncoder::create(config.encoder())); | ||||
| 	std::unique_ptr<DisassemblingGeometryMapper> geometryMapper(createSimpleDisassemblingGeometryMapper(config.geometry(), *reader)); | ||||
| 	std::unique_ptr<AbstractEncoder> encoder(AbstractEncoder::create(config.encoder(), *geometryMapper)); | ||||
| 	std::unique_ptr<FluxSink> fluxSink(FluxSink::create(config.output().flux())); | ||||
|  | ||||
| 	writeDiskCommand(*reader, *encoder, *fluxSink); | ||||
| 	writeDiskCommand(*encoder, *fluxSink); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ input { | ||||
| output { | ||||
| 	image { | ||||
| 		filename: "commodore1541.d64" | ||||
| 		d64 {} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -17,6 +17,139 @@ decoder { | ||||
| 	c64 {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 41 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 17 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| 	# Cylinders 0..16: 21 sectors | ||||
| 	# Cylinders 17..23: 19 sectors | ||||
| 	# Cylinders 24..29: 18 sectors | ||||
| 	# Cylinders 30..41: 17 sectors (i.e. all the rest) | ||||
| 	trackdata { | ||||
| 		cylinder: 0 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 1 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 2 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 3 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 4 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 5 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 6 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 7 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 8 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 9 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 10 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 11 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 12 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 13 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 14 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 15 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 16 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 17 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 18 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 19 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 20 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 21 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 22 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 23 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 24 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 25 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 26 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 27 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 28 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 29 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 79 | ||||
|   | ||||
							
								
								
									
										43
									
								
								src/readables/northstar175.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/readables/northstar175.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| comment: 'Northstar 175kB 5.25" 35-track single-sided double-density hard-sectored' | ||||
|  | ||||
| input { | ||||
| 	flux { | ||||
| 		drive { | ||||
| 			hard_sector_count: 10 | ||||
| 			sync_with_index: 1 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| output { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| decoder { | ||||
| 	northstar {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 1 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 39 | ||||
| } | ||||
|  | ||||
| heads { | ||||
| 	start: 0 | ||||
| 	end: 0 | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -1,4 +1,4 @@ | ||||
| comment: 'Northstar 87kB/175kB/350kB 5.25" 35-track 10-sector hard sectored' | ||||
| comment: 'Northstar 350kB 5.25" 35-track double-sided double-density hard-sectored' | ||||
| 
 | ||||
| input { | ||||
| 	flux { | ||||
| @@ -12,7 +12,7 @@ input { | ||||
| output { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		nsi {} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -20,9 +20,19 @@ decoder { | ||||
| 	northstar {} | ||||
| } | ||||
| 
 | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 2 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 34 | ||||
| 	end: 39 | ||||
| } | ||||
| 
 | ||||
| heads { | ||||
							
								
								
									
										42
									
								
								src/readables/northstar87.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/readables/northstar87.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| comment: 'Northstar 87.5kB 5.25" 35-track single-sided single-density hard-sectored' | ||||
|  | ||||
| input { | ||||
| 	flux { | ||||
| 		drive { | ||||
| 			hard_sector_count: 10 | ||||
| 			sync_with_index: 1 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| output { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| decoder { | ||||
| 	northstar {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 1 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 39 | ||||
| } | ||||
|  | ||||
| heads { | ||||
| 	start: 0 | ||||
| 	end: 0 | ||||
| } | ||||
|  | ||||
| @@ -3,14 +3,7 @@ comment: 'Amiga 880kB 3.5" double sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "amiga.adf" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 11 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -18,6 +11,15 @@ output { | ||||
| 	flux {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 11 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	amiga {} | ||||
| } | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 360kB 3.5" 80-track 9-sector single sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist360.st" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 370kB 3.5" 82-track 9-sector single sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist370.st" | ||||
| 		img { | ||||
| 			tracks: 82 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 82 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 400kB 3.5" 80-track 10-sector single sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist400.st" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 10 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 410kB 3.5" 82-track 10-sector single sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist410.st" | ||||
| 		img { | ||||
| 			tracks: 82 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 10 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 82 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 720kB 3.5" 80-track 9-sector double sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist720.st" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 740kB 3.5" 82-track 9-sector double sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist740.st" | ||||
| 		img { | ||||
| 			tracks: 82 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 82 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 800kB 3.5" 80-track 10-sector double sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist800.st" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 10 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Atari ST 820kB 3.5" 82-track 10-sector double sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "atarist820.st" | ||||
| 		img { | ||||
| 			tracks: 82 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 10 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 82 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Brother 120kB 3.5" 39-track GCR disks' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "brother120.img" | ||||
| 		img { | ||||
| 			tracks: 39 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 12 | ||||
| 				sector_size: 256 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 39 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 12 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	brother { | ||||
| 		format: BROTHER120 | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Brother 240kB 3.5" 78-track GCR disks' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "brother240.img" | ||||
| 		img { | ||||
| 			tracks: 78 | ||||
| 			sides: 1 | ||||
| 			trackdata { | ||||
| 				sectors: 12 | ||||
| 				sector_size: 256 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 78 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 12 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	brother {} | ||||
| } | ||||
|   | ||||
| @@ -2,8 +2,8 @@ comment: 'Commodore 1541 170kB 5.25" GCR disks' | ||||
|  | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "commodore1541.img" | ||||
| 		d64 {} | ||||
| 		filename: "commodore1541.d64" | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -17,9 +17,142 @@ encoder { | ||||
| 	c64 {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 41 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 17 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| 	# Cylinders 0..16: 21 sectors | ||||
| 	# Cylinders 17..23: 19 sectors | ||||
| 	# Cylinders 24..29: 18 sectors | ||||
| 	# Cylinders 30..41: 17 sectors (i.e. all the rest) | ||||
| 	trackdata { | ||||
| 		cylinder: 0 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 1 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 2 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 3 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 4 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 5 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 6 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 7 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 8 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 9 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 10 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 11 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 12 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 13 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 14 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 15 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 16 | ||||
| 		sectors: 21 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 17 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 18 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 19 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 20 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 21 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 22 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 23 | ||||
| 		sectors: 19 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 24 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 25 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 26 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 27 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 28 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 29 | ||||
| 		sectors: 18 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 79 | ||||
| 	end: 81 | ||||
| } | ||||
|  | ||||
| heads { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Commodore 1581 800kB 3.5" MFM disks' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "commodore1581.d81" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 10 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Hewlett-Packard LIF 770kB 3.5" disks' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "hplif770.img" | ||||
| 		img { | ||||
| 			tracks: 77 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 5 | ||||
| 				sector_size: 1024 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 77 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 5 | ||||
| 		sector_size: 1024 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'PC 1200kB 5.25" 80-track 15-sector double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm1200_525.img" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 15 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 15 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'PC 1440kB 3.5" 80-track 18-sector double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm1440.img" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 18 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 18 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,15 +3,7 @@ comment: 'PC 180kB 5.25" 40-track 9-sector single-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm180_525.img" | ||||
| 		img { | ||||
| 			tracks: 40 | ||||
| 			sides: 1 | ||||
| 			physical_step: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -21,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 40 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,15 +3,7 @@ comment: 'PC 360kB 5.25" 40-track 9-sector double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm360_525.img" | ||||
| 		img { | ||||
| 			tracks: 40 | ||||
| 			sides: 2 | ||||
| 			physical_step: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -21,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 40 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'PC 720kB 3.5" 80-track 9-sector double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm720.img" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'PC 720kB 5.25" 80-track 9-sector double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "ibm720_525.img" | ||||
| 		img { | ||||
| 			tracks: 80 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 9 | ||||
| 				sector_size: 512 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 9 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	ibm { | ||||
| 		trackdata { | ||||
|   | ||||
| @@ -1,29 +0,0 @@ | ||||
| comment: 'Macintosh 800kB 3.5" GCR double-sided' | ||||
|  | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "macintosh.diskcopy" | ||||
| 		diskcopy {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| output { | ||||
| 	flux { | ||||
| 		drive {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	macintosh {} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 79 | ||||
| } | ||||
|  | ||||
| heads { | ||||
| 	start: 0 | ||||
| 	end: 1 | ||||
| } | ||||
|  | ||||
							
								
								
									
										300
									
								
								src/writables/macintosh400.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								src/writables/macintosh400.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,300 @@ | ||||
| comment: 'Macintosh 400kB 3.5" GCR single-sided' | ||||
|  | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "macintosh.diskcopy" | ||||
| 		diskcopy {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| output { | ||||
| 	flux { | ||||
| 		drive {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	macintosh {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 1 | ||||
| 	trackdata { | ||||
| 		sectors: 8 | ||||
| 		sector_size: 524 | ||||
| 	} | ||||
|  | ||||
| 	# Cylinders 0..15: 12 sectors | ||||
| 	#           16..31: 11 sectors | ||||
| 	#           32..47: 10 sectors | ||||
| 	#           48..63: 9 sectors | ||||
| 	#           the rest: 8 sectors | ||||
| 	trackdata { | ||||
| 		cylinder: 0 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 1 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 2 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 3 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 4 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 5 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 6 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 7 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 8 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 9 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 10 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 11 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 12 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 13 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 14 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 15 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 16 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 17 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 18 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 19 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 20 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 21 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 22 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 23 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 24 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 25 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 26 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 27 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 28 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 29 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 30 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 31 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 32 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 33 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 34 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 35 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 36 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 37 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 38 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 39 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 40 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 41 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 42 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 43 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 44 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 45 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 46 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 47 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 48 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 49 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 50 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 51 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 52 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 53 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 54 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 55 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 56 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 57 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 58 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 59 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 60 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 61 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 62 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 63 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 79 | ||||
| } | ||||
|  | ||||
| heads { | ||||
| 	start: 0 | ||||
| 	end: 0 | ||||
| } | ||||
|  | ||||
							
								
								
									
										300
									
								
								src/writables/macintosh800.textpb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								src/writables/macintosh800.textpb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,300 @@ | ||||
| comment: 'Macintosh 800kB 3.5" GCR double-sided' | ||||
|  | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "macintosh.diskcopy" | ||||
| 		diskcopy {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| output { | ||||
| 	flux { | ||||
| 		drive {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	macintosh {} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 80 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 8 | ||||
| 		sector_size: 524 | ||||
| 	} | ||||
|  | ||||
| 	# Cylinders 0..15: 12 sectors | ||||
| 	#           16..31: 11 sectors | ||||
| 	#           32..47: 10 sectors | ||||
| 	#           48..63: 9 sectors | ||||
| 	#           the rest: 8 sectors | ||||
| 	trackdata { | ||||
| 		cylinder: 0 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 1 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 2 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 3 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 4 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 5 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 6 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 7 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 8 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 9 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 10 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 11 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 12 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 13 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 14 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 15 | ||||
| 		sectors: 12 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 16 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 17 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 18 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 19 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 20 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 21 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 22 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 23 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 24 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 25 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 26 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 27 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 28 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 29 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 30 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 31 | ||||
| 		sectors: 11 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 32 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 33 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 34 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 35 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 36 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 37 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 38 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 39 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 40 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 41 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 42 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 43 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 44 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 45 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 46 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 47 | ||||
| 		sectors: 10 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 48 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 49 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 50 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 51 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 52 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 53 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 54 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 55 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 56 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 57 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 58 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 59 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 60 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 61 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 62 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| 	trackdata { | ||||
| 		cylinder: 63 | ||||
| 		sectors: 9 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| cylinders { | ||||
| 	start: 0 | ||||
| 	end: 79 | ||||
| } | ||||
|  | ||||
| heads { | ||||
| 	start: 0 | ||||
| 	end: 1 | ||||
| } | ||||
|  | ||||
| @@ -3,7 +3,7 @@ comment: 'Northstar 175kB 5.25" 35-track single-sided double-density hard-sector | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		nsi {} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -15,6 +15,16 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 1 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	northstar {} | ||||
| } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ comment: 'Northstar 350kB 5.25" 35-track double-sided double-density hard-sector | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		nsi {} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -15,6 +15,16 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 2 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 512 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	northstar {} | ||||
| } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ comment: 'Northstar 87.5kB 5.25" 35-track single-sided single-density hard-secto | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "northstar.nsi" | ||||
| 		nsi {} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -15,6 +15,16 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 35 | ||||
| 	heads: 1 | ||||
| 	block_ordering: ORDER_NSI | ||||
| 	trackdata { | ||||
| 		sectors: 10 | ||||
| 		sector_size: 256 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	northstar {} | ||||
| } | ||||
|   | ||||
| @@ -3,14 +3,7 @@ comment: 'Texas Instruments DS990 1126kB 8" double-sided' | ||||
| input { | ||||
| 	image { | ||||
| 		filename: "tids990.img" | ||||
| 		img { | ||||
| 			tracks: 77 | ||||
| 			sides: 2 | ||||
| 			trackdata { | ||||
| 				sectors: 26 | ||||
| 				sector_size: 288 | ||||
| 			} | ||||
| 		} | ||||
| 		img {} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -20,6 +13,15 @@ output { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| geometry { | ||||
| 	cylinders: 77 | ||||
| 	heads: 2 | ||||
| 	trackdata { | ||||
| 		sectors: 26 | ||||
| 		sector_size: 288 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| encoder { | ||||
| 	tids990 {} | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| #include "globals.h" | ||||
| #include "bytes.h" | ||||
| #include "snowhouse/snowhouse.h" | ||||
|  | ||||
| using namespace snowhouse; | ||||
|  | ||||
| static void check_oob(Bytes& b, unsigned pos) | ||||
| { | ||||
| @@ -113,6 +116,13 @@ static void test_slice() | ||||
|      | ||||
|     bs = b.slice(4, 2); | ||||
|     assert((bs == Bytes{ 0, 0 })); | ||||
|      | ||||
|     bs = b.slice(2, 2); | ||||
|     assert((bs == Bytes{ 3, 0 })); | ||||
|  | ||||
| 	bs = b.slice(1, 4); | ||||
| 	bs = bs.slice(1, 4); | ||||
| 	AssertThat(bs.toVector<int>(), Equals(Bytes{ 3, 0, 0, 0 }.toVector<int>())); | ||||
| } | ||||
|  | ||||
| static void test_tobits() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user