mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Compare commits
13 Commits
| 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 SectorSet;
|
||||||
class AmigaDecoderProto;
|
class AmigaDecoderProto;
|
||||||
class AmigaEncoderProto;
|
class AmigaEncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class AmigaDecoder : public AbstractDecoder
|
class AmigaDecoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -30,15 +31,18 @@ public:
|
|||||||
class AmigaEncoder : public AbstractEncoder
|
class AmigaEncoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AmigaEncoder(const AmigaEncoderProto& config):
|
AmigaEncoder(const AmigaEncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config) {}
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
|
{}
|
||||||
virtual ~AmigaEncoder() {}
|
virtual ~AmigaEncoder() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const AmigaEncoderProto& _config;
|
const AmigaEncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern uint32_t amigaChecksum(const Bytes& bytes);
|
extern uint32_t amigaChecksum(const Bytes& bytes);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
|
|
||||||
FlagGroup amigaEncoderFlags;
|
FlagGroup amigaEncoderFlags;
|
||||||
|
|
||||||
@@ -99,8 +100,7 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector
|
|||||||
write_bits(bits, cursor, dataBits);
|
write_bits(bits, cursor, dataBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fluxmap> AmigaEncoder::encode(
|
std::unique_ptr<Fluxmap> AmigaEncoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK))
|
if ((physicalTrack < 0) || (physicalTrack >= AMIGA_TRACKS_PER_DISK))
|
||||||
return std::unique_ptr<Fluxmap>();
|
return std::unique_ptr<Fluxmap>();
|
||||||
@@ -114,7 +114,8 @@ std::unique_ptr<Fluxmap> AmigaEncoder::encode(
|
|||||||
|
|
||||||
for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++)
|
for (int sectorId=0; sectorId<AMIGA_SECTORS_PER_TRACK; sectorId++)
|
||||||
{
|
{
|
||||||
const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId);
|
const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId);
|
||||||
|
if (sectorData)
|
||||||
write_sector(bits, cursor, sectorData);
|
write_sector(bits, cursor, sectorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class SectorSet;
|
|||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class BrotherDecoderProto;
|
class BrotherDecoderProto;
|
||||||
class BrotherEncoderProto;
|
class BrotherEncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class BrotherDecoder : public AbstractDecoder
|
class BrotherDecoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -33,17 +34,19 @@ public:
|
|||||||
class BrotherEncoder : public AbstractEncoder
|
class BrotherEncoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BrotherEncoder(const BrotherEncoderProto& config):
|
BrotherEncoder(const BrotherEncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config)
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~BrotherEncoder() {}
|
virtual ~BrotherEncoder() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const BrotherEncoderProto& _config;
|
const BrotherEncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include "arch/brother/brother.pb.h"
|
#include "arch/brother/brother.pb.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
|
|
||||||
FlagGroup brotherEncoderFlags;
|
FlagGroup brotherEncoderFlags;
|
||||||
|
|
||||||
@@ -127,8 +128,7 @@ static int charToInt(char c)
|
|||||||
return 10 + tolower(c) - 'a';
|
return 10 + tolower(c) - 'a';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fluxmap> BrotherEncoder::encode(
|
std::unique_ptr<Fluxmap> BrotherEncoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
int logicalTrack;
|
int logicalTrack;
|
||||||
if (physicalSide != 0)
|
if (physicalSide != 0)
|
||||||
@@ -163,7 +163,7 @@ std::unique_ptr<Fluxmap> BrotherEncoder::encode(
|
|||||||
double dataMs = headerMs + postHeaderSpacingMs;
|
double dataMs = headerMs + postHeaderSpacingMs;
|
||||||
unsigned dataCursor = dataMs*1e3 / clockRateUs;
|
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 });
|
fillBitmapTo(bits, cursor, headerCursor, { true, false });
|
||||||
write_sector_header(bits, cursor, logicalTrack, sectorId);
|
write_sector_header(bits, cursor, logicalTrack, sectorId);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class Sector;
|
|||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class Commodore64DecoderProto;
|
class Commodore64DecoderProto;
|
||||||
class Commodore64EncoderProto;
|
class Commodore64EncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class Commodore64Decoder : public AbstractDecoder
|
class Commodore64Decoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -47,17 +48,19 @@ public:
|
|||||||
class Commodore64Encoder : public AbstractEncoder
|
class Commodore64Encoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Commodore64Encoder(const Commodore64EncoderProto& config):
|
Commodore64Encoder(const Commodore64EncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config)
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~Commodore64Encoder() {}
|
virtual ~Commodore64Encoder() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Commodore64EncoderProto& _config;
|
const Commodore64EncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "arch/c64/c64.pb.h"
|
#include "arch/c64/c64.pb.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "bytes.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(
|
std::unique_ptr<Fluxmap> Commodore64Encoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
/* The format ID Character # 1 and # 2 are in the .d64 image only present
|
/* 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.
|
* 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))
|
if ((physicalTrack < 0) || (physicalTrack >= C64_TRACKS_PER_DISK))
|
||||||
return std::unique_ptr<Fluxmap>();
|
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);
|
ByteReader br(sectorData->data);
|
||||||
br.seek(162); //goto position of the first Disk ID Byte
|
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);
|
unsigned numSectors = sectorsForTrack(physicalTrack);
|
||||||
for (int sectorId=0; sectorId<numSectors; sectorId++)
|
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);
|
write_sector(bits, cursor, sectorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
#include "arch/ibm/ibm.pb.h"
|
#include "arch/ibm/ibm.pb.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -99,8 +100,7 @@ void IbmEncoder::getTrackFormat(IbmEncoderProto::TrackdataProto& trackdata, unsi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fluxmap> IbmEncoder::encode(
|
std::unique_ptr<Fluxmap> IbmEncoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
IbmEncoderProto::TrackdataProto trackdata;
|
IbmEncoderProto::TrackdataProto trackdata;
|
||||||
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
getTrackFormat(trackdata, physicalTrack, physicalSide);
|
||||||
@@ -165,7 +165,7 @@ std::unique_ptr<Fluxmap> IbmEncoder::encode(
|
|||||||
writeFillerBytes(trackdata.gap3(), gapFill);
|
writeFillerBytes(trackdata.gap3(), gapFill);
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId);
|
const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId);
|
||||||
if (!sectorData)
|
if (!sectorData)
|
||||||
{
|
{
|
||||||
/* If there are any missing sectors, this is an empty track. */
|
/* If there are any missing sectors, this is an empty track. */
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ struct IbmIdam
|
|||||||
uint8_t crc[2];
|
uint8_t crc[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class IbmDecoder : public AbstractDecoder
|
class IbmDecoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -52,14 +54,15 @@ private:
|
|||||||
class IbmEncoder : public AbstractEncoder
|
class IbmEncoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IbmEncoder(const IbmEncoderProto& config):
|
IbmEncoder(const IbmEncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config)
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~IbmEncoder() {}
|
virtual ~IbmEncoder() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void writeRawBits(uint32_t data, int width);
|
void writeRawBits(uint32_t data, int width);
|
||||||
@@ -69,6 +72,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const IbmEncoderProto& _config;
|
const IbmEncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
std::vector<bool> _bits;
|
std::vector<bool> _bits;
|
||||||
unsigned _cursor;
|
unsigned _cursor;
|
||||||
bool _lastBit;
|
bool _lastBit;
|
||||||
|
|||||||
@@ -6,21 +6,11 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
#include "arch/macintosh/macintosh.pb.h"
|
||||||
#include <ctype.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 bool lastBit;
|
||||||
|
|
||||||
static double clockRateUsForTrack(unsigned track)
|
static double clockRateUsForTrack(unsigned track)
|
||||||
@@ -210,24 +200,24 @@ static void write_sector(std::vector<bool>& bits, unsigned& cursor, const Sector
|
|||||||
write_bits(bits, cursor, 0xdeaaff, 3*8);
|
write_bits(bits, cursor, 0xdeaaff, 3*8);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fluxmap> MacintoshEncoder::encode(
|
std::unique_ptr<Fluxmap> MacintoshEncoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK))
|
if ((physicalTrack < 0) || (physicalTrack >= MAC_TRACKS_PER_DISK))
|
||||||
return std::unique_ptr<Fluxmap>();
|
return std::unique_ptr<Fluxmap>();
|
||||||
|
|
||||||
double clockRateUs = clockRateUsForTrack(physicalTrack) * clockCompensation;
|
double clockRateUs = clockRateUsForTrack(physicalTrack) * _config.clock_compensation_factor();
|
||||||
int bitsPerRevolution = 200000.0 / clockRateUs;
|
int bitsPerRevolution = 200000.0 / _config.clock_compensation_factor();
|
||||||
std::vector<bool> bits(bitsPerRevolution);
|
std::vector<bool> bits(bitsPerRevolution);
|
||||||
unsigned cursor = 0;
|
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;
|
lastBit = false;
|
||||||
|
|
||||||
unsigned numSectors = sectorsForTrack(physicalTrack);
|
unsigned numSectors = sectorsForTrack(physicalTrack);
|
||||||
for (int sectorId=0; sectorId<numSectors; sectorId++)
|
for (int sectorId=0; sectorId<numSectors; sectorId++)
|
||||||
{
|
{
|
||||||
const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId);
|
const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId);
|
||||||
|
if (sectorData)
|
||||||
write_sector(bits, cursor, sectorData);
|
write_sector(bits, cursor, sectorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class Sector;
|
|||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class MacintoshDecoderProto;
|
class MacintoshDecoderProto;
|
||||||
class MacintoshEncoderProto;
|
class MacintoshEncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class MacintoshDecoder : public AbstractDecoder
|
class MacintoshDecoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -34,11 +35,19 @@ public:
|
|||||||
class MacintoshEncoder : public AbstractEncoder
|
class MacintoshEncoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MacintoshEncoder(const MacintoshEncoderProto&) {}
|
MacintoshEncoder(const MacintoshEncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
|
{}
|
||||||
|
|
||||||
virtual ~MacintoshEncoder() {}
|
virtual ~MacintoshEncoder() {}
|
||||||
|
|
||||||
public:
|
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;
|
extern FlagGroup macintoshEncoderFlags;
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
|
|
||||||
message MacintoshDecoderProto {}
|
import "lib/common.proto";
|
||||||
message MacintoshEncoderProto {}
|
|
||||||
|
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 "globals.h"
|
||||||
#include "northstar.h"
|
#include "northstar.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
|
|
||||||
#define GAP_FILL_SIZE_SD 30
|
#define GAP_FILL_SIZE_SD 30
|
||||||
#define PRE_HEADER_GAP_FILL_SIZE_SD 9
|
#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(
|
std::unique_ptr<Fluxmap> NorthstarEncoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
int bitsPerRevolution = 100000;
|
int bitsPerRevolution = 100000;
|
||||||
double clockRateUs = 4.00;
|
double clockRateUs = 4.00;
|
||||||
@@ -104,7 +104,7 @@ std::unique_ptr<Fluxmap> NorthstarEncoder::encode(
|
|||||||
if ((physicalTrack < 0) || (physicalTrack >= 35))
|
if ((physicalTrack < 0) || (physicalTrack >= 35))
|
||||||
return std::unique_ptr<Fluxmap>();
|
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) {
|
if (sector->data.size() == NORTHSTAR_PAYLOAD_SIZE_SD) {
|
||||||
bitsPerRevolution /= 2; // FM
|
bitsPerRevolution /= 2; // FM
|
||||||
@@ -117,7 +117,7 @@ std::unique_ptr<Fluxmap> NorthstarEncoder::encode(
|
|||||||
|
|
||||||
for (int sectorId = 0; sectorId < 10; sectorId++)
|
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);
|
write_sector(bits, cursor, sectorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
class NorthstarEncoderProto;
|
class NorthstarEncoderProto;
|
||||||
class NorthstarDecoderProto;
|
class NorthstarDecoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class NorthstarDecoder : public AbstractDecoder
|
class NorthstarDecoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -55,15 +56,17 @@ private:
|
|||||||
class NorthstarEncoder : public AbstractEncoder
|
class NorthstarEncoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NorthstarEncoder(const NorthstarEncoderProto& config):
|
NorthstarEncoder(const NorthstarEncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config)
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~NorthstarEncoder() {}
|
virtual ~NorthstarEncoder() {}
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const NorthstarEncoderProto& _config;
|
const NorthstarEncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern FlagGroup northstarEncoderFlags;
|
extern FlagGroup northstarEncoderFlags;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "writer.h"
|
#include "writer.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "arch/tids990/tids990.pb.h"
|
#include "arch/tids990/tids990.pb.h"
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
@@ -49,8 +50,7 @@ static uint8_t decodeUint16(uint16_t raw)
|
|||||||
return decodeFmMfm(b.toBits())[0];
|
return decodeFmMfm(b.toBits())[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fluxmap> Tids990Encoder::encode(
|
std::unique_ptr<Fluxmap> Tids990Encoder::encode(int physicalTrack, int physicalSide)
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors)
|
|
||||||
{
|
{
|
||||||
double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0;
|
double clockRateUs = 1e3 / _config.clock_rate_khz() / 2.0;
|
||||||
int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs;
|
int bitsPerRevolution = (_config.track_length_ms() * 1000.0) / clockRateUs;
|
||||||
@@ -70,7 +70,7 @@ std::unique_ptr<Fluxmap> Tids990Encoder::encode(
|
|||||||
writeBytes(_config.gap3_bytes(), 0x55);
|
writeBytes(_config.gap3_bytes(), 0x55);
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
const auto& sectorData = allSectors.get(physicalTrack, physicalSide, sectorId);
|
const auto* sectorData = _mapper.get(physicalTrack, physicalSide, sectorId);
|
||||||
if (!sectorData)
|
if (!sectorData)
|
||||||
Error() << fmt::format("format tried to find sector {} which wasn't in the input file", sectorId);
|
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 Track;
|
||||||
class Tids990DecoderProto;
|
class Tids990DecoderProto;
|
||||||
class Tids990EncoderProto;
|
class Tids990EncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class Tids990Decoder : public AbstractDecoder
|
class Tids990Decoder : public AbstractDecoder
|
||||||
{
|
{
|
||||||
@@ -26,8 +27,9 @@ public:
|
|||||||
class Tids990Encoder : public AbstractEncoder
|
class Tids990Encoder : public AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Tids990Encoder(const Tids990EncoderProto& config):
|
Tids990Encoder(const Tids990EncoderProto& config, const DisassemblingGeometryMapper& mapper):
|
||||||
_config(config)
|
_config(config),
|
||||||
|
_mapper(mapper)
|
||||||
{}
|
{}
|
||||||
virtual ~Tids990Encoder() {}
|
virtual ~Tids990Encoder() {}
|
||||||
|
|
||||||
@@ -38,10 +40,11 @@ private:
|
|||||||
void writeSync();
|
void writeSync();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide, const SectorSet& allSectors);
|
std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Tids990EncoderProto& _config;
|
const Tids990EncoderProto& _config;
|
||||||
|
const DisassemblingGeometryMapper& _mapper;
|
||||||
std::vector<bool> _bits;
|
std::vector<bool> _bits;
|
||||||
unsigned _cursor;
|
unsigned _cursor;
|
||||||
bool _lastBit;
|
bool _lastBit;
|
||||||
|
|||||||
@@ -32,9 +32,12 @@ fluxengine read northstar
|
|||||||
To read a single-sided North Star floppy, run:
|
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
|
You should end up with a `northstar.nsi` with a file size dependent on the floppy
|
||||||
disk type:
|
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)
|
_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)
|
Bytes* Bytes::operator = (const Bytes& other)
|
||||||
{
|
{
|
||||||
_data = other._data;
|
_data = other._data;
|
||||||
@@ -130,14 +138,14 @@ uint8_t& Bytes::operator [] (unsigned pos)
|
|||||||
|
|
||||||
Bytes Bytes::slice(unsigned start, unsigned len) const
|
Bytes Bytes::slice(unsigned start, unsigned len) const
|
||||||
{
|
{
|
||||||
start += _low;
|
unsigned datastart = _low + start;
|
||||||
unsigned end = start + len;
|
unsigned dataend = datastart + len;
|
||||||
if (start >= _high)
|
if (datastart >= _high)
|
||||||
{
|
{
|
||||||
/* Asking for a completely out-of-range slice --- just return zeroes. */
|
/* Asking for a completely out-of-range slice --- just return zeroes. */
|
||||||
return Bytes(len);
|
return Bytes(len);
|
||||||
}
|
}
|
||||||
else if (end > _high)
|
else if (dataend > _high)
|
||||||
{
|
{
|
||||||
/* Can't share the buffer, as we need to zero-pad the end. */
|
/* Can't share the buffer, as we need to zero-pad the end. */
|
||||||
Bytes b(len);
|
Bytes b(len);
|
||||||
@@ -147,7 +155,7 @@ Bytes Bytes::slice(unsigned start, unsigned len) const
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Use the magic of shared_ptr to share the data. */
|
/* Use the magic of shared_ptr to share the data. */
|
||||||
Bytes b(_data, start, end);
|
Bytes b(_data, datastart, dataend);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
lib/bytes.h
16
lib/bytes.h
@@ -16,6 +16,7 @@ public:
|
|||||||
Bytes(std::initializer_list<uint8_t> data);
|
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);
|
||||||
Bytes(std::shared_ptr<std::vector<uint8_t>> data, unsigned start, unsigned end);
|
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);
|
Bytes* operator = (const Bytes& other);
|
||||||
|
|
||||||
@@ -64,6 +65,16 @@ public:
|
|||||||
void writeToFile(const std::string& filename) const;
|
void writeToFile(const std::string& filename) const;
|
||||||
void writeTo(std::ostream& stream) 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:
|
private:
|
||||||
std::shared_ptr<std::vector<uint8_t>> _data;
|
std::shared_ptr<std::vector<uint8_t>> _data;
|
||||||
unsigned _low;
|
unsigned _low;
|
||||||
@@ -296,6 +307,11 @@ public:
|
|||||||
return *this += stream;
|
return *this += stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteWriter& append(std::istream& stream, size_t len)
|
||||||
|
{
|
||||||
|
return *this += Bytes(stream, len);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Bytes& _bytes;
|
Bytes& _bytes;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ extend google.protobuf.FieldOptions {
|
|||||||
optional string help = 50000;
|
optional string help = 50000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extend google.protobuf.EnumValueOptions {
|
||||||
|
optional string ehelp = 50000;
|
||||||
|
}
|
||||||
|
|
||||||
enum IndexMode {
|
enum IndexMode {
|
||||||
INDEXMODE_DRIVE = 0;
|
INDEXMODE_DRIVE = 0 [(ehelp) = "source index pulses from drive"];
|
||||||
INDEXMODE_300 = 1;
|
INDEXMODE_300 = 1 [(ehelp) = "source index pulses from fake 300RPM source"];
|
||||||
INDEXMODE_360 = 2;
|
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/fluxsource/fluxsource.proto";
|
||||||
import "lib/fluxsink/fluxsink.proto";
|
import "lib/fluxsink/fluxsink.proto";
|
||||||
import "lib/usb/usb.proto";
|
import "lib/usb/usb.proto";
|
||||||
|
import "lib/geometry/geometry.proto";
|
||||||
import "lib/common.proto";
|
import "lib/common.proto";
|
||||||
|
|
||||||
message InputProto {
|
message InputProto {
|
||||||
@@ -24,15 +25,16 @@ message OutputProto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message ConfigProto {
|
message ConfigProto {
|
||||||
optional string comment = 8;
|
optional string comment = 1;
|
||||||
|
|
||||||
optional InputProto input = 1;
|
optional InputProto input = 2;
|
||||||
optional OutputProto output = 2;
|
optional OutputProto output = 3;
|
||||||
optional EncoderProto encoder = 3;
|
optional EncoderProto encoder = 4;
|
||||||
optional DecoderProto decoder = 4;
|
optional DecoderProto decoder = 5;
|
||||||
optional UsbProto usb = 5;
|
optional UsbProto usb = 6;
|
||||||
|
optional GeometryProto geometry = 7;
|
||||||
|
|
||||||
optional RangeProto cylinders = 6;
|
optional RangeProto cylinders = 8;
|
||||||
optional RangeProto heads = 7;
|
optional RangeProto heads = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,27 +12,28 @@
|
|||||||
#include "lib/encoders/encoders.pb.h"
|
#include "lib/encoders/encoders.pb.h"
|
||||||
#include "protocol.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())
|
switch (config.format_case())
|
||||||
{
|
{
|
||||||
case EncoderProto::kAmiga:
|
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:
|
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:
|
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:
|
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:
|
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:
|
case EncoderProto::kNorthstar:
|
||||||
return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config.northstar()));
|
return std::unique_ptr<AbstractEncoder>(new NorthstarEncoder(config.northstar(), mapper));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error() << "no input disk format specified";
|
Error() << "no input disk format specified";
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ class FluxSource;
|
|||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class SectorSet;
|
class SectorSet;
|
||||||
class EncoderProto;
|
class EncoderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class AbstractEncoder
|
class AbstractEncoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractEncoder() {}
|
virtual ~AbstractEncoder() {}
|
||||||
|
|
||||||
static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config);
|
static std::unique_ptr<AbstractEncoder> create(const EncoderProto& config, const DisassemblingGeometryMapper& mapper);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual std::unique_ptr<Fluxmap> encode(
|
virtual std::unique_ptr<Fluxmap> encode(int physicalTrack, int physicalSide) = 0;
|
||||||
int physicalTrack, int physicalSide, const SectorSet& allSectors) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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 <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#define SECTOR_SIZE 512
|
||||||
|
#define TAG_SIZE 12
|
||||||
|
|
||||||
class DiskCopyImageReader : public ImageReader
|
class DiskCopyImageReader : public ImageReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DiskCopyImageReader(const ImageReaderProto& config):
|
DiskCopyImageReader(const ImageReaderProto& config):
|
||||||
ImageReader(config)
|
ImageReader(config)
|
||||||
{}
|
|
||||||
|
|
||||||
SectorSet readImage()
|
|
||||||
{
|
{
|
||||||
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
|
_if.open(_config.filename(), std::ios::in | std::ios::binary);
|
||||||
if (!inputFile.is_open())
|
if (!_if.is_open())
|
||||||
Error() << "cannot open input file";
|
Error() << "cannot open input file";
|
||||||
|
|
||||||
Bytes data;
|
Bytes header(_if, 0x54);
|
||||||
data.writer() += inputFile;
|
ByteReader br(header);
|
||||||
ByteReader br(data);
|
|
||||||
|
|
||||||
br.seek(1);
|
uint8_t labelLen = br.read_8();
|
||||||
std::string label = br.read(data[0]);
|
std::string label = br.read(labelLen);
|
||||||
|
|
||||||
br.seek(0x40);
|
br.seek(0x40);
|
||||||
uint32_t dataSize = br.read_be32();
|
uint32_t dataSize = br.read_be32();
|
||||||
|
uint32_t tagSize = br.read_be32();
|
||||||
|
_numSectors = dataSize / SECTOR_SIZE;
|
||||||
|
_sectorOffset = 0x54;
|
||||||
|
_tagOffset = _sectorOffset + dataSize;
|
||||||
|
|
||||||
br.seek(0x50);
|
_if.seekg(0, std::ios::end);
|
||||||
uint8_t encoding = br.read_8();
|
std::cout << fmt::format("DISKCOPY: reading input image '{}' of {} sectors",
|
||||||
uint8_t formatByte = br.read_8();
|
label, _numSectors);
|
||||||
|
|
||||||
unsigned numCylinders = 80;
|
|
||||||
unsigned numHeads = 2;
|
|
||||||
unsigned numSectors = 0;
|
|
||||||
bool mfm = false;
|
|
||||||
|
|
||||||
switch (encoding)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "reading DiskCopy 4.2 image\n"
|
Bytes getBlock(size_t offset, size_t length) const
|
||||||
<< fmt::format("{} cylinders, {} heads; {}; {}\n",
|
|
||||||
numCylinders, numHeads,
|
|
||||||
mfm ? "MFM" : "GCR",
|
|
||||||
label);
|
|
||||||
|
|
||||||
auto sectorsPerTrack = [&](int track) -> int
|
|
||||||
{
|
{
|
||||||
if (mfm)
|
if ((length != SECTOR_SIZE) && (length != (SECTOR_SIZE+TAG_SIZE)))
|
||||||
return numSectors;
|
Error() << fmt::format("diskcopy files only support sector lengths of {} and {}\n",
|
||||||
|
SECTOR_SIZE, (SECTOR_SIZE+TAG_SIZE));
|
||||||
|
|
||||||
if (track < 16)
|
unsigned sectorNum = offset / length;
|
||||||
return 12;
|
if (offset % length)
|
||||||
if (track < 32)
|
Error() << fmt::format("unaligned sector read");
|
||||||
return 11;
|
|
||||||
if (track < 48)
|
|
||||||
return 10;
|
|
||||||
if (track < 64)
|
|
||||||
return 9;
|
|
||||||
return 8;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t dataPtr = 0x54;
|
_if.seekg(_sectorOffset + SECTOR_SIZE*sectorNum);
|
||||||
uint32_t tagPtr = dataPtr + dataSize;
|
Bytes data(_if, SECTOR_SIZE);
|
||||||
|
|
||||||
SectorSet sectors;
|
if (length != SECTOR_SIZE)
|
||||||
for (int track = 0; track < numCylinders; track++)
|
|
||||||
{
|
{
|
||||||
int numSectors = sectorsPerTrack(track);
|
_if.seekg(_tagOffset + TAG_SIZE*sectorNum);
|
||||||
for (int head = 0; head < numHeads; head++)
|
data.writer().seekToEnd().append(_if, TAG_SIZE);
|
||||||
{
|
}
|
||||||
for (int sectorId = 0; sectorId < numSectors; sectorId++)
|
|
||||||
{
|
|
||||||
br.seek(dataPtr);
|
|
||||||
Bytes payload = br.read(512);
|
|
||||||
dataPtr += 512;
|
|
||||||
|
|
||||||
br.seek(tagPtr);
|
return data;
|
||||||
Bytes tag = br.read(12);
|
}
|
||||||
tagPtr += 12;
|
|
||||||
|
|
||||||
std::unique_ptr<Sector>& sector = sectors.get(track, head, sectorId);
|
private:
|
||||||
sector.reset(new Sector);
|
mutable std::ifstream _if;
|
||||||
sector->status = Sector::OK;
|
unsigned _numSectors;
|
||||||
sector->logicalTrack = sector->physicalTrack = track;
|
off_t _sectorOffset;
|
||||||
sector->logicalSide = sector->physicalSide = head;
|
off_t _tagOffset;
|
||||||
sector->logicalSector = sectorId;
|
|
||||||
sector->data.writer().append(payload).append(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sectors;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ImageReader> ImageReader::createDiskCopyImageReader(
|
std::unique_ptr<ImageReader> ImageReader::createDiskCopyImageReader(
|
||||||
|
|||||||
@@ -26,12 +26,6 @@ std::unique_ptr<ImageReader> ImageReader::create(const ImageReaderProto& config)
|
|||||||
case ImageReaderProto::kJv3:
|
case ImageReaderProto::kJv3:
|
||||||
return ImageReader::createJv3ImageReader(config);
|
return ImageReader::createJv3ImageReader(config);
|
||||||
|
|
||||||
case ImageReaderProto::kD64:
|
|
||||||
return ImageReader::createD64ImageReader(config);
|
|
||||||
|
|
||||||
case ImageReaderProto::kNsi:
|
|
||||||
return ImageReader::createNsiImageReader(config);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error() << "bad input file config";
|
Error() << "bad input file config";
|
||||||
return std::unique_ptr<ImageReader>();
|
return std::unique_ptr<ImageReader>();
|
||||||
@@ -44,12 +38,13 @@ void ImageReader::updateConfigForFilename(ImageReaderProto* proto, const std::st
|
|||||||
{
|
{
|
||||||
{".adf", [&]() { proto->mutable_img(); }},
|
{".adf", [&]() { proto->mutable_img(); }},
|
||||||
{".jv3", [&]() { proto->mutable_jv3(); }},
|
{".jv3", [&]() { proto->mutable_jv3(); }},
|
||||||
{".d64", [&]() { proto->mutable_d64(); }},
|
{".d64", [&]() { proto->mutable_img(); }},
|
||||||
{".d81", [&]() { proto->mutable_img(); }},
|
{".d81", [&]() { proto->mutable_img(); }},
|
||||||
{".diskcopy", [&]() { proto->mutable_diskcopy(); }},
|
{".diskcopy", [&]() { proto->mutable_diskcopy(); }},
|
||||||
{".img", [&]() { proto->mutable_img(); }},
|
{".img", [&]() { proto->mutable_img(); }},
|
||||||
{".st", [&]() { proto->mutable_img(); }},
|
{".st", [&]() { proto->mutable_img(); }},
|
||||||
{".nsi", [&]() { proto->mutable_nsi(); }},
|
{".nsi", [&]() { proto->mutable_img(); }},
|
||||||
|
{".imd", [&]() { proto->mutable_imd(); }},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& it : formats)
|
for (const auto& it : formats)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
class SectorSet;
|
class SectorSet;
|
||||||
class ImageSpec;
|
class ImageSpec;
|
||||||
class ImageReaderProto;
|
class ImageReaderProto;
|
||||||
|
class DisassemblingGeometryMapper;
|
||||||
|
|
||||||
class ImageReader
|
class ImageReader
|
||||||
{
|
{
|
||||||
@@ -16,15 +17,14 @@ public:
|
|||||||
static void updateConfigForFilename(ImageReaderProto* proto, const std::string& filename);
|
static void updateConfigForFilename(ImageReaderProto* proto, const std::string& filename);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<ImageReader> createD64ImageReader(const ImageReaderProto& config);
|
|
||||||
static std::unique_ptr<ImageReader> createDiskCopyImageReader(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> createImgImageReader(const ImageReaderProto& config);
|
||||||
static std::unique_ptr<ImageReader> createJv3ImageReader(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> createIMDImageReader(const ImageReaderProto& config);
|
||||||
static std::unique_ptr<ImageReader> createNsiImageReader(const ImageReaderProto& config);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual SectorSet readImage() = 0;
|
virtual Bytes getBlock(size_t offset, size_t length) const = 0;
|
||||||
|
virtual const DisassemblingGeometryMapper* getGeometryMapper() const { return nullptr; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const ImageReaderProto& _config;
|
const ImageReaderProto& _config;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ message DiskCopyInputProto {}
|
|||||||
message ImdInputProto {}
|
message ImdInputProto {}
|
||||||
message Jv3InputProto {}
|
message Jv3InputProto {}
|
||||||
message D64InputProto {}
|
message D64InputProto {}
|
||||||
message NsiInputProto {}
|
|
||||||
|
|
||||||
message ImageReaderProto {
|
message ImageReaderProto {
|
||||||
optional string filename = 1 [(help) = "filename of input sector image"];
|
optional string filename = 1 [(help) = "filename of input sector image"];
|
||||||
@@ -32,7 +31,6 @@ message ImageReaderProto {
|
|||||||
ImdInputProto imd = 4;
|
ImdInputProto imd = 4;
|
||||||
Jv3InputProto jv3 = 5;
|
Jv3InputProto jv3 = 5;
|
||||||
D64InputProto d64 = 6;
|
D64InputProto d64 = 6;
|
||||||
NsiInputProto nsi = 7;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "sector.h"
|
#include "sector.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "imagereader/imagereader.h"
|
#include "imagereader/imagereader.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "lib/config.pb.h"
|
#include "lib/config.pb.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <algorithm>
|
#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 track;
|
||||||
uint8_t Head;
|
uint8_t head;
|
||||||
uint8_t numSectors;
|
uint8_t numSectors;
|
||||||
uint8_t SectorSize;
|
uint8_t sectorSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned getSectorSize(uint8_t flags)
|
static unsigned getsectorSize(uint8_t flags)
|
||||||
{
|
{
|
||||||
switch (flags)
|
switch (flags)
|
||||||
{
|
{
|
||||||
@@ -81,178 +82,157 @@ static unsigned getSectorSize(uint8_t flags)
|
|||||||
#define END_OF_FILE 0x1A
|
#define END_OF_FILE 0x1A
|
||||||
|
|
||||||
|
|
||||||
class IMDImageReader : public ImageReader
|
class IMDImageReader : public ImageReader, DisassemblingGeometryMapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IMDImageReader(const ImageReaderProto& config):
|
IMDImageReader(const ImageReaderProto& config):
|
||||||
ImageReader(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);
|
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
|
||||||
if (!inputFile.is_open())
|
if (!inputFile.is_open())
|
||||||
Error() << "cannot open input file";
|
Error() << "cannot open input file";
|
||||||
|
Bytes data;
|
||||||
|
data.writer().append(inputFile);
|
||||||
|
ByteReader br(data);
|
||||||
|
|
||||||
//define some variables
|
//define some variables
|
||||||
bool mfm = false; //define coding just to show in comment for setting the right write parameters
|
bool mfm = false; //define coding just to show in comment for setting the right write parameters
|
||||||
inputFile.seekg(0, inputFile.end);
|
Trackheader header = {0, 0, 0, 0, 0};
|
||||||
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};
|
|
||||||
|
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
unsigned headerPtr = 0;
|
unsigned modulation_speed = 0;
|
||||||
unsigned Modulation_Speed = 0;
|
|
||||||
unsigned sectorSize = 0;
|
unsigned sectorSize = 0;
|
||||||
std::string sector_skew;
|
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
|
// 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;
|
break;
|
||||||
|
if (b == '\r')
|
||||||
|
continue;
|
||||||
|
if (b == '\n')
|
||||||
|
b = 32;
|
||||||
|
comment << (char) b;
|
||||||
}
|
}
|
||||||
header.ModeValue = br.read_8();
|
std::cout << fmt::format("IMD: comment: {}\n", comment.str());
|
||||||
headerPtr++;
|
|
||||||
Modulation_Speed = getModulationandSpeed(header.ModeValue, &mfm);
|
while (!br.eof())
|
||||||
|
{
|
||||||
|
header.modeValue = br.read_8();
|
||||||
|
modulation_speed = getModulationandSpeed(header.modeValue, &mfm);
|
||||||
header.track = br.read_8();
|
header.track = br.read_8();
|
||||||
headerPtr++;
|
header.head = br.read_8();
|
||||||
header.Head = br.read_8();
|
int physicalHead = header.head & 0x3f;
|
||||||
headerPtr++;
|
|
||||||
header.numSectors = br.read_8();
|
header.numSectors = br.read_8();
|
||||||
headerPtr++;
|
header.sectorSize = br.read_8();
|
||||||
header.SectorSize = br.read_8();
|
sectorSize = getsectorSize(header.sectorSize);
|
||||||
headerPtr++;
|
|
||||||
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
|
//read sector numbering map
|
||||||
unsigned int sector_map[header.numSectors];
|
unsigned int sector_map[header.numSectors];
|
||||||
bool blnBaseOne = false;
|
bool blnBaseOne = false;
|
||||||
sector_skew.clear();
|
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_map[b] = br.read_8();
|
||||||
sector_skew.push_back(sector_map[b] + '0');
|
sector_skew.push_back(sector_map[b] + '0');
|
||||||
if (b == 0) //first sector see if base is 0 or 1 Fluxengine wants 0
|
if (b == 0) //first sector see if base is 0 or 1 Fluxengine wants 0
|
||||||
{
|
{
|
||||||
if (sector_map[b]==1)
|
if (sector_map[b]==1)
|
||||||
{
|
|
||||||
blnBaseOne = true;
|
blnBaseOne = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (blnBaseOne==true)
|
if (blnBaseOne==true)
|
||||||
{
|
|
||||||
sector_map[b] = (sector_map[b]-1);
|
sector_map[b] = (sector_map[b]-1);
|
||||||
}
|
}
|
||||||
headerPtr++;
|
|
||||||
}
|
|
||||||
//read the sectors
|
//read the sectors
|
||||||
for (int s = 0; s < header.numSectors; s++)
|
for (int s = 0; s < header.numSectors; s++)
|
||||||
{
|
{
|
||||||
Bytes sectordata;
|
std::unique_ptr<Sector>& sector = _sectors.get(header.track, physicalHead, sector_map[s]);
|
||||||
std::unique_ptr<Sector>& sector = sectors.get(header.track, header.Head, sector_map[s]);
|
|
||||||
sector.reset(new Sector);
|
sector.reset(new Sector);
|
||||||
//read the status of the sector
|
//read the status of the sector
|
||||||
unsigned int Status_Sector = br.read_8();
|
unsigned int sector_status = br.read_8();
|
||||||
headerPtr++;
|
|
||||||
|
|
||||||
switch (Status_Sector)
|
switch (sector_status)
|
||||||
{
|
{
|
||||||
case 0: /* Sector data unavailable - could not be read */
|
case 0: /* Sector data unavailable - could not be read */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: /* Normal data: (Sector Size) bytes follow */
|
case 1: /* Normal data: (Sector Size) bytes follow */
|
||||||
sectordata = br.read(sectorSize);
|
{
|
||||||
headerPtr += sectorSize;
|
Bytes sectordata = br.read(sectorSize);
|
||||||
sector->data.writer().append(sectordata);
|
sector->data = sectordata;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 2: /* Compressed: All bytes in sector have same value (xx) */
|
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);
|
sector->data.writer().append(sectordata);
|
||||||
|
|
||||||
|
ByteWriter bw(sector->data);
|
||||||
for (int k = 1; k < sectorSize; k++)
|
for (int k = 1; k < sectorSize; k++)
|
||||||
{
|
{
|
||||||
//fill data till sector is full
|
//fill data till sector is full
|
||||||
sector->data.writer().append(sectordata);
|
bw.write_8(sectordata);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* Normal data with "Deleted-Data address mark" */
|
case 3: /* Normal data with "Deleted-Data address mark" */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: /* Compressed with "Deleted-Data address mark"*/
|
case 4: /* Compressed with "Deleted-Data address mark"*/
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: /* Normal data read with data error */
|
case 5: /* Normal data read with data error */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: /* Compressed read with data error" */
|
case 6: /* Compressed read with data error" */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7: /* Deleted data read with data error" */
|
case 7: /* Deleted data read with data error" */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 8: /* Compressed, Deleted read with data error" */
|
case 8: /* Compressed, Deleted read with data error" */
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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->status = Sector::OK;
|
||||||
sector->logicalTrack = sector->physicalTrack = header.track;
|
sector->logicalTrack = sector->physicalTrack = header.track;
|
||||||
sector->logicalSide = sector->physicalSide = header.Head;
|
sector->logicalSide = sector->physicalSide = physicalHead;
|
||||||
sector->logicalSector = (sector_map[s]);
|
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
|
//Write format detected in IMD image to screen to help user set the right write parameters
|
||||||
|
|
||||||
size_t headSize = header.numSectors * sectorSize;
|
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"
|
std::cout << fmt::format("IMD: reading image with {} tracks, {} heads, {};\n"
|
||||||
<< fmt::format("{} tracks, {} heads; {}; {} kbps; {} sectoren; sectorsize {}; sectormap {}; {} kB total \n",
|
"IMD: {} kbps; {} sectors; sectorsize {}; sectormap {}; {} kB total\n",
|
||||||
header.track, header.Head + 1,
|
header.track, header.head + 1,
|
||||||
mfm ? "MFM" : "FM",
|
mfm ? "MFM" : "FM",
|
||||||
Modulation_Speed, header.numSectors, sectorSize, sector_skew, (header.track+1) * trackSize / 1024);
|
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(
|
std::unique_ptr<ImageReader> ImageReader::createIMDImageReader(
|
||||||
|
|||||||
@@ -14,62 +14,24 @@ class ImgImageReader : public ImageReader
|
|||||||
public:
|
public:
|
||||||
ImgImageReader(const ImageReaderProto& config):
|
ImgImageReader(const ImageReaderProto& config):
|
||||||
ImageReader(config)
|
ImageReader(config)
|
||||||
{}
|
|
||||||
|
|
||||||
SectorSet readImage()
|
|
||||||
{
|
{
|
||||||
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
|
_if.open(_config.filename(), std::ios::in | std::ios::binary);
|
||||||
if (!inputFile.is_open())
|
if (!_if.is_open())
|
||||||
Error() << "cannot open input file";
|
Error() << "cannot open input file";
|
||||||
|
|
||||||
SectorSet sectors;
|
_if.seekg(0, std::ios::end);
|
||||||
for (int track = 0; track < _config.img().tracks(); track++)
|
std::cout << fmt::format("IMG: reading input image of {} kB total\n",
|
||||||
{
|
_if.tellg() / 1024);
|
||||||
for (int side = 0; side < _config.img().sides(); side++)
|
|
||||||
{
|
|
||||||
ImgInputOutputProto::TrackdataProto trackdata;
|
|
||||||
getTrackFormat(trackdata, track, side);
|
|
||||||
|
|
||||||
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())
|
Bytes getBlock(size_t offset, size_t length) const
|
||||||
break;
|
{
|
||||||
}
|
_if.seekg(offset);
|
||||||
|
return Bytes(_if, length);
|
||||||
std::cout << fmt::format("reading {} tracks, {} sides, {} kB total\n",
|
|
||||||
_config.img().tracks(), _config.img().sides(),
|
|
||||||
inputFile.tellg() / 1024);
|
|
||||||
return sectors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getTrackFormat(ImgInputOutputProto::TrackdataProto& trackdata, unsigned track, unsigned side)
|
mutable std::ifstream _if;
|
||||||
{
|
|
||||||
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::unique_ptr<ImageReader> ImageReader::createImgImageReader(
|
std::unique_ptr<ImageReader> ImageReader::createImgImageReader(
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
#include "sector.h"
|
#include "sector.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "imagereader/imagereader.h"
|
#include "imagereader/imagereader.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "lib/config.pb.h"
|
#include "lib/config.pb.h"
|
||||||
|
#include "lib/imagereader/imagereader.pb.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -31,13 +33,6 @@
|
|||||||
* } SectorHeader;
|
* } SectorHeader;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SectorHeader
|
|
||||||
{
|
|
||||||
uint8_t track;
|
|
||||||
uint8_t sector;
|
|
||||||
uint8_t flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define JV3_DENSITY 0x80 /* 1=dden, 0=sden */
|
#define JV3_DENSITY 0x80 /* 1=dden, 0=sden */
|
||||||
#define JV3_DAM 0x60 /* data address mark code; see below */
|
#define JV3_DAM 0x60 /* data address mark code; see below */
|
||||||
#define JV3_SIDE 0x10 /* 0=side 0, 1=side 1 */
|
#define JV3_SIDE 0x10 /* 0=side 0, 1=side 1 */
|
||||||
@@ -72,55 +67,51 @@ static unsigned getSectorSize(uint8_t flags)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Error() << "not reachable";
|
Error() << "not reachable";
|
||||||
|
throw 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Jv3ImageReader : public ImageReader
|
class Jv3ImageReader : public ImageReader, DisassemblingGeometryMapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Jv3ImageReader(const ImageReaderProto& config):
|
Jv3ImageReader(const ImageReaderProto& config):
|
||||||
ImageReader(config)
|
ImageReader(config)
|
||||||
{}
|
|
||||||
|
|
||||||
SectorSet readImage()
|
|
||||||
{
|
{
|
||||||
std::ifstream inputFile(_config.filename(), std::ios::in | std::ios::binary);
|
std::ifstream stream(_config.filename(), std::ios::in | std::ios::binary);
|
||||||
if (!inputFile.is_open())
|
if (!stream.is_open())
|
||||||
Error() << "cannot open input file";
|
Error() << "cannot open input file";
|
||||||
|
|
||||||
inputFile.seekg( 0, std::ios::end);
|
Bytes image;
|
||||||
unsigned inputFileSize = inputFile.tellg();
|
image.writer() += stream;
|
||||||
unsigned headerPtr = 0;
|
ByteReader br(image);
|
||||||
SectorSet sectors;
|
|
||||||
|
off_t headerPtr = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
unsigned dataPtr = headerPtr + 2901*3 + 1;
|
off_t dataPtr = headerPtr + 2901*3 + 1;
|
||||||
if (dataPtr >= inputFileSize)
|
if (dataPtr >= image.size())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
br.seek(headerPtr);
|
||||||
for (unsigned i=0; i<2901; i++)
|
for (unsigned i=0; i<2901; i++)
|
||||||
{
|
{
|
||||||
SectorHeader header = {0, 0, 0xff};
|
uint8_t track = br.read_8();
|
||||||
inputFile.seekg(headerPtr);
|
uint8_t sector = br.read_8();
|
||||||
inputFile.read((char*) &header, 3);
|
uint8_t flags = br.read_8();
|
||||||
unsigned sectorSize = getSectorSize(header.flags);
|
|
||||||
if ((header.flags & JV3_FREEF) != JV3_FREEF)
|
if ((flags & JV3_FREEF) != JV3_FREEF)
|
||||||
{
|
{
|
||||||
Bytes data(sectorSize);
|
unsigned side = !!(flags & JV3_SIDE);
|
||||||
inputFile.seekg(dataPtr);
|
unsigned length = getSectorSize(flags);
|
||||||
inputFile.read((char*) data.begin(), sectorSize);
|
|
||||||
|
|
||||||
unsigned head = !!(header.flags & JV3_SIDE);
|
std::unique_ptr<Sector> s(new Sector);
|
||||||
std::unique_ptr<Sector>& sector = sectors.get(header.track, head, header.sector);
|
s->status = (flags & JV3_ERROR) ? Sector::BAD_CHECKSUM : Sector::OK;
|
||||||
sector.reset(new Sector);
|
s->physicalTrack = s->logicalTrack = track;
|
||||||
sector->status = Sector::OK;
|
s->physicalSide = s->logicalSide = side;
|
||||||
sector->logicalTrack = sector->physicalTrack = header.track;
|
s->logicalSector = sector;
|
||||||
sector->logicalSide = sector->physicalSide = head;
|
s->data = image.slice(dataPtr, length);
|
||||||
sector->logicalSector = header.sector;
|
_sectors[std::make_tuple(track, side, sector)] = std::move(s);
|
||||||
sector->data = data;
|
dataPtr += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
headerPtr += 3;
|
|
||||||
dataPtr += sectorSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dataPtr is now pointing at the beginning of the next chunk. */
|
/* dataPtr is now pointing at the beginning of the next chunk. */
|
||||||
@@ -128,8 +119,31 @@ public:
|
|||||||
headerPtr = dataPtr;
|
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)
|
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());
|
image.writeToFile(_config.filename());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void putBlock(size_t offset, size_t length, const Bytes& data)
|
||||||
|
{ throw "unimplemented"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<ImageWriter> ImageWriter::createDiskCopyImageWriter(
|
std::unique_ptr<ImageWriter> ImageWriter::createDiskCopyImageWriter(
|
||||||
|
|||||||
@@ -17,17 +17,13 @@ std::unique_ptr<ImageWriter> ImageWriter::create(const ImageWriterProto& config)
|
|||||||
case ImageWriterProto::kImg:
|
case ImageWriterProto::kImg:
|
||||||
return ImageWriter::createImgImageWriter(config);
|
return ImageWriter::createImgImageWriter(config);
|
||||||
|
|
||||||
case ImageWriterProto::kD64:
|
|
||||||
return ImageWriter::createD64ImageWriter(config);
|
|
||||||
|
|
||||||
case ImageWriterProto::kLdbs:
|
case ImageWriterProto::kLdbs:
|
||||||
return ImageWriter::createLDBSImageWriter(config);
|
return ImageWriter::createLDBSImageWriter(config);
|
||||||
|
|
||||||
|
#if 0
|
||||||
case ImageWriterProto::kDiskcopy:
|
case ImageWriterProto::kDiskcopy:
|
||||||
return ImageWriter::createDiskCopyImageWriter(config);
|
return ImageWriter::createDiskCopyImageWriter(config);
|
||||||
|
#endif
|
||||||
case ImageWriterProto::kNsi:
|
|
||||||
return ImageWriter::createNsiImageWriter(config);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error() << "bad output image config";
|
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 =
|
static const std::map<std::string, std::function<void(void)>> formats =
|
||||||
{
|
{
|
||||||
{".adf", [&]() { proto->mutable_img(); }},
|
{".adf", [&]() { proto->mutable_img(); }},
|
||||||
{".d64", [&]() { proto->mutable_d64(); }},
|
{".d64", [&]() { proto->mutable_img(); }},
|
||||||
{".d81", [&]() { proto->mutable_img(); }},
|
{".d81", [&]() { proto->mutable_img(); }},
|
||||||
{".diskcopy", [&]() { proto->mutable_diskcopy(); }},
|
{".diskcopy", [&]() { proto->mutable_diskcopy(); }},
|
||||||
{".img", [&]() { proto->mutable_img(); }},
|
{".img", [&]() { proto->mutable_img(); }},
|
||||||
{".ldbs", [&]() { proto->mutable_ldbs(); }},
|
{".ldbs", [&]() { proto->mutable_ldbs(); }},
|
||||||
{".st", [&]() { proto->mutable_img(); }},
|
{".st", [&]() { proto->mutable_img(); }},
|
||||||
{".nsi", [&]() { proto->mutable_nsi(); }},
|
{".nsi", [&]() { proto->mutable_img(); }},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& it : formats)
|
for (const auto& it : formats)
|
||||||
@@ -66,125 +62,3 @@ ImageWriter::ImageWriter(const ImageWriterProto& config):
|
|||||||
_config(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 SectorSet;
|
||||||
class ImageWriterProto;
|
class ImageWriterProto;
|
||||||
|
class AssemblingGeometryMapper;
|
||||||
|
|
||||||
class ImageWriter
|
class ImageWriter
|
||||||
{
|
{
|
||||||
@@ -18,17 +19,14 @@ public:
|
|||||||
const ImageWriterProto& config);
|
const ImageWriterProto& config);
|
||||||
static std::unique_ptr<ImageWriter> createLDBSImageWriter(
|
static std::unique_ptr<ImageWriter> createLDBSImageWriter(
|
||||||
const ImageWriterProto& config);
|
const ImageWriterProto& config);
|
||||||
static std::unique_ptr<ImageWriter> createD64ImageWriter(
|
|
||||||
const ImageWriterProto& config);
|
|
||||||
static std::unique_ptr<ImageWriter> createDiskCopyImageWriter(
|
static std::unique_ptr<ImageWriter> createDiskCopyImageWriter(
|
||||||
const ImageWriterProto& config);
|
const ImageWriterProto& config);
|
||||||
static std::unique_ptr<ImageWriter> createNsiImageWriter(
|
static std::unique_ptr<ImageWriter> createNsiImageWriter(
|
||||||
const ImageWriterProto& config);
|
const ImageWriterProto& config);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void printMap(const SectorSet& sectors);
|
virtual void putBlock(size_t offset, size_t length, const Bytes& data) = 0;
|
||||||
void writeCsv(const SectorSet& sectors, const std::string& filename);
|
virtual const AssemblingGeometryMapper* getGeometryMapper() const { return nullptr; }
|
||||||
virtual void writeImage(const SectorSet& sectors) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const ImageWriterProto& _config;
|
const ImageWriterProto& _config;
|
||||||
|
|||||||
@@ -3,19 +3,15 @@ syntax = "proto2";
|
|||||||
import "lib/imagereader/imagereader.proto";
|
import "lib/imagereader/imagereader.proto";
|
||||||
import "lib/common.proto";
|
import "lib/common.proto";
|
||||||
|
|
||||||
message D64OutputProto {}
|
|
||||||
message LDBSOutputProto {}
|
message LDBSOutputProto {}
|
||||||
message DiskCopyOutputProto {}
|
message DiskCopyOutputProto {}
|
||||||
message NsiOutputProto {}
|
|
||||||
|
|
||||||
message ImageWriterProto {
|
message ImageWriterProto {
|
||||||
optional string filename = 1 [(help) = "filename of output sector image"];
|
optional string filename = 1 [(help) = "filename of output sector image"];
|
||||||
oneof format {
|
oneof format {
|
||||||
ImgInputOutputProto img = 2;
|
ImgInputOutputProto img = 2;
|
||||||
D64OutputProto d64 = 3;
|
|
||||||
LDBSOutputProto ldbs = 4;
|
LDBSOutputProto ldbs = 4;
|
||||||
DiskCopyOutputProto diskcopy = 5;
|
DiskCopyOutputProto diskcopy = 5;
|
||||||
NsiOutputProto nsi = 6;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,63 +14,27 @@ class ImgImageWriter : public ImageWriter
|
|||||||
public:
|
public:
|
||||||
ImgImageWriter(const ImageWriterProto& config):
|
ImgImageWriter(const ImageWriterProto& config):
|
||||||
ImageWriter(config)
|
ImageWriter(config)
|
||||||
{}
|
|
||||||
|
|
||||||
void writeImage(const SectorSet& sectors)
|
|
||||||
{
|
{
|
||||||
unsigned autoTracks;
|
_of.open(_config.filename(), std::ios::out | std::ios::trunc | std::ios::binary);
|
||||||
unsigned autoSides;
|
if (!_of.is_open())
|
||||||
unsigned autoSectors;
|
Error() << "cannot open input file";
|
||||||
unsigned autoBytes;
|
|
||||||
sectors.calculateSize(autoTracks, autoSides, autoSectors, autoBytes);
|
|
||||||
|
|
||||||
int tracks = _config.img().has_tracks() ? _config.img().tracks() : autoTracks;
|
|
||||||
int sides = _config.img().has_sides() ? _config.img().sides() : autoSides;
|
|
||||||
|
|
||||||
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",
|
~ImgImageWriter()
|
||||||
tracks, sides,
|
{
|
||||||
outputFile.tellp() / 1024);
|
_of.seekp(0, std::ios::end);
|
||||||
|
std::cout << fmt::format("IMG: written output image of {} kB total\n",
|
||||||
|
_of.tellp() / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void putBlock(size_t offset, size_t length, const Bytes& data)
|
||||||
|
{
|
||||||
|
_of.seekp(offset);
|
||||||
|
data.slice(0, length).writeTo(_of);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getTrackFormat(ImgInputOutputProto::TrackdataProto& trackdata, unsigned track, unsigned side)
|
std::ofstream _of;
|
||||||
{
|
|
||||||
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::unique_ptr<ImageWriter> ImageWriter::createImgImageWriter(
|
std::unique_ptr<ImageWriter> ImageWriter::createImgImageWriter(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "sector.h"
|
#include "sector.h"
|
||||||
#include "sectorset.h"
|
#include "sectorset.h"
|
||||||
#include "imagewriter/imagewriter.h"
|
#include "imagewriter/imagewriter.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "ldbs.h"
|
#include "ldbs.h"
|
||||||
#include "lib/config.pb.h"
|
#include "lib/config.pb.h"
|
||||||
@@ -10,14 +11,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
class LDBSImageWriter : public ImageWriter
|
class LDBSImageWriter : public ImageWriter, public AssemblingGeometryMapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LDBSImageWriter(const ImageWriterProto& config):
|
LDBSImageWriter(const ImageWriterProto& config):
|
||||||
ImageWriter(config)
|
ImageWriter(config)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void writeImage(const SectorSet& sectors)
|
~LDBSImageWriter()
|
||||||
{
|
{
|
||||||
LDBS ldbs;
|
LDBS ldbs;
|
||||||
|
|
||||||
@@ -25,13 +27,29 @@ public:
|
|||||||
unsigned numHeads;
|
unsigned numHeads;
|
||||||
unsigned numSectors;
|
unsigned numSectors;
|
||||||
unsigned numBytes;
|
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,
|
numCylinders, numHeads,
|
||||||
numSectors, numBytes)
|
numSectors, numBytes)
|
||||||
<< std::endl;
|
<< 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;
|
Bytes trackDirectory;
|
||||||
ByteWriter trackDirectoryWriter(trackDirectory);
|
ByteWriter trackDirectoryWriter(trackDirectory);
|
||||||
int trackDirectorySize = 0;
|
int trackDirectorySize = 0;
|
||||||
@@ -47,7 +65,7 @@ public:
|
|||||||
int actualSectors = 0;
|
int actualSectors = 0;
|
||||||
for (int sectorId = 0; sectorId < numSectors; sectorId++)
|
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)
|
if (sector)
|
||||||
actualSectors++;
|
actualSectors++;
|
||||||
}
|
}
|
||||||
@@ -63,7 +81,7 @@ public:
|
|||||||
|
|
||||||
for (int sectorId = 0; sectorId < numSectors; sectorId++)
|
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)
|
if (sector)
|
||||||
{
|
{
|
||||||
uint32_t sectorLabel = (('S') << 24) | ((track & 0xff) << 16) | (head << 8) | sectorId;
|
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.seek(0);
|
||||||
trackDirectoryWriter.write_le16(trackDirectorySize);
|
trackDirectoryWriter.write_le16(trackDirectorySize);
|
||||||
|
|
||||||
uint32_t trackDirectoryAddress = ldbs.put(trackDirectory, LDBS_TRACK_BLOCK);
|
uint32_t trackDirectoryAddress = ldbs.put(trackDirectory, LDBS_TRACK_BLOCK);
|
||||||
Bytes data = ldbs.write(trackDirectoryAddress);
|
Bytes data = ldbs.write(trackDirectoryAddress);
|
||||||
data.writeToFile(_config.filename());
|
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)
|
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_FILE_TYPE 0x44534B02 /* "DSK\02" */
|
||||||
#define LDBS_BLOCK_MAGIC 0x4C444201 /* "LDB\01" */
|
#define LDBS_BLOCK_MAGIC 0x4C444201 /* "LDB\01" */
|
||||||
#define LDBS_TRACK_BLOCK 0x44495201 /* "DIR\01" */
|
#define LDBS_TRACK_BLOCK 0x44495201 /* "DIR\01" */
|
||||||
|
#define LDBS_GEOM_BLOCK 0x47454f4d /* "GEOM" */
|
||||||
|
|
||||||
class LDBS
|
class LDBS
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "decoders/rawbits.h"
|
#include "decoders/rawbits.h"
|
||||||
#include "track.h"
|
#include "track.h"
|
||||||
#include "imagewriter/imagewriter.h"
|
#include "imagewriter/imagewriter.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "lib/decoders/decoders.pb.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())
|
if (config.decoder().has_copy_flux_to())
|
||||||
outputFluxSink = FluxSink::create(config.decoder().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())
|
if (config.decoder().has_write_csv_to())
|
||||||
writer.writeCsv(allSectors, config.decoder().write_csv_to());
|
geometryMapper.writeCsv(allSectors, config.decoder().write_csv_to());
|
||||||
writer.writeImage(allSectors);
|
geometryMapper.put(allSectors);
|
||||||
|
|
||||||
if (failures)
|
if (failures)
|
||||||
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
|
std::cerr << "Warning: some sectors could not be decoded." << std::endl;
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ class AbstractDecoder;
|
|||||||
class FluxSink;
|
class FluxSink;
|
||||||
class FluxSource;
|
class FluxSource;
|
||||||
class Fluxmap;
|
class Fluxmap;
|
||||||
class ImageWriter;
|
class AssemblingGeometryMapper;
|
||||||
class Track;
|
class Track;
|
||||||
|
|
||||||
extern std::vector<std::unique_ptr<Track>> readTracks();
|
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);
|
extern void rawReadDiskCommand(FluxSource& source, FluxSink& sink);
|
||||||
|
|
||||||
#endif
|
#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,
|
writeTracks(fluxSink,
|
||||||
[&](int track, int side) -> std::unique_ptr<Fluxmap>
|
[&](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,
|
unsigned& cursor, unsigned terminateAt,
|
||||||
const std::vector<bool>& pattern);
|
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);
|
extern void writeRawDiskCommand(FluxSource& fluxSource, FluxSink& fluxSink);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
14
mkninja.sh
14
mkninja.sh
@@ -282,6 +282,7 @@ buildproto libproto.a \
|
|||||||
lib/encoders/encoders.proto \
|
lib/encoders/encoders.proto \
|
||||||
lib/fluxsource/fluxsource.proto \
|
lib/fluxsource/fluxsource.proto \
|
||||||
lib/fluxsink/fluxsink.proto \
|
lib/fluxsink/fluxsink.proto \
|
||||||
|
lib/geometry/geometry.proto \
|
||||||
lib/imagereader/imagereader.proto \
|
lib/imagereader/imagereader.proto \
|
||||||
lib/imagewriter/imagewriter.proto \
|
lib/imagewriter/imagewriter.proto \
|
||||||
lib/usb/usb.proto \
|
lib/usb/usb.proto \
|
||||||
@@ -337,21 +338,19 @@ buildlibrary libbackend.a \
|
|||||||
lib/fluxsource/scpfluxsource.cc \
|
lib/fluxsource/scpfluxsource.cc \
|
||||||
lib/fluxsource/sqlitefluxsource.cc \
|
lib/fluxsource/sqlitefluxsource.cc \
|
||||||
lib/fluxsource/testpatternfluxsource.cc \
|
lib/fluxsource/testpatternfluxsource.cc \
|
||||||
|
lib/geometry/simplemapper.cc \
|
||||||
|
lib/geometry/geometry.cc \
|
||||||
lib/globals.cc \
|
lib/globals.cc \
|
||||||
lib/hexdump.cc \
|
lib/hexdump.cc \
|
||||||
lib/imagereader/d64imagereader.cc \
|
|
||||||
lib/imagereader/diskcopyimagereader.cc \
|
lib/imagereader/diskcopyimagereader.cc \
|
||||||
lib/imagereader/imagereader.cc \
|
lib/imagereader/imagereader.cc \
|
||||||
lib/imagereader/imdimagereader.cc \
|
lib/imagereader/imdimagereader.cc \
|
||||||
lib/imagereader/imgimagereader.cc \
|
lib/imagereader/imgimagereader.cc \
|
||||||
lib/imagereader/jv3imagereader.cc \
|
lib/imagereader/jv3imagereader.cc \
|
||||||
lib/imagereader/nsiimagereader.cc \
|
|
||||||
lib/imagewriter/d64imagewriter.cc \
|
|
||||||
lib/imagewriter/diskcopyimagewriter.cc \
|
lib/imagewriter/diskcopyimagewriter.cc \
|
||||||
lib/imagewriter/imagewriter.cc \
|
lib/imagewriter/imagewriter.cc \
|
||||||
lib/imagewriter/imgimagewriter.cc \
|
lib/imagewriter/imgimagewriter.cc \
|
||||||
lib/imagewriter/ldbsimagewriter.cc \
|
lib/imagewriter/ldbsimagewriter.cc \
|
||||||
lib/imagewriter/nsiimagewriter.cc \
|
|
||||||
lib/ldbs.cc \
|
lib/ldbs.cc \
|
||||||
lib/proto.cc \
|
lib/proto.cc \
|
||||||
lib/reader.cc \
|
lib/reader.cc \
|
||||||
@@ -384,7 +383,9 @@ READABLES="\
|
|||||||
macintosh \
|
macintosh \
|
||||||
micropolis \
|
micropolis \
|
||||||
mx \
|
mx \
|
||||||
northstar \
|
northstar87 \
|
||||||
|
northstar175 \
|
||||||
|
northstar350 \
|
||||||
tids990 \
|
tids990 \
|
||||||
victor9k \
|
victor9k \
|
||||||
zilogmcz \
|
zilogmcz \
|
||||||
@@ -411,7 +412,8 @@ WRITABLES="\
|
|||||||
ibm360_525 \
|
ibm360_525 \
|
||||||
ibm720 \
|
ibm720 \
|
||||||
ibm720_525 \
|
ibm720_525 \
|
||||||
macintosh \
|
macintosh400 \
|
||||||
|
macintosh800 \
|
||||||
northstar87 \
|
northstar87 \
|
||||||
northstar175 \
|
northstar175 \
|
||||||
northstar350 \
|
northstar350 \
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "arch/brother/brother.h"
|
#include "arch/brother/brother.h"
|
||||||
#include "arch/ibm/ibm.h"
|
#include "arch/ibm/ibm.h"
|
||||||
#include "imagewriter/imagewriter.h"
|
#include "imagewriter/imagewriter.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fluxengine.h"
|
#include "fluxengine.h"
|
||||||
#include <google/protobuf/text_format.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";
|
Error() << "you cannot copy flux to a hardware device";
|
||||||
|
|
||||||
std::unique_ptr<FluxSource> fluxSource(FluxSource::create(config.input().flux()));
|
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<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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "arch/ibm/ibm.h"
|
#include "arch/ibm/ibm.h"
|
||||||
#include "imagereader/imagereader.h"
|
#include "imagereader/imagereader.h"
|
||||||
#include "fluxengine.h"
|
#include "fluxengine.h"
|
||||||
|
#include "geometry/geometry.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include <google/protobuf/text_format.h>
|
#include <google/protobuf/text_format.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -65,10 +66,11 @@ int mainWrite(int argc, const char* argv[])
|
|||||||
Error() << "incomplete config (did you remember to specify the format?)";
|
Error() << "incomplete config (did you remember to specify the format?)";
|
||||||
|
|
||||||
std::unique_ptr<ImageReader> reader(ImageReader::create(config.input().image()));
|
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()));
|
std::unique_ptr<FluxSink> fluxSink(FluxSink::create(config.output().flux()));
|
||||||
|
|
||||||
writeDiskCommand(*reader, *encoder, *fluxSink);
|
writeDiskCommand(*encoder, *fluxSink);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ input {
|
|||||||
output {
|
output {
|
||||||
image {
|
image {
|
||||||
filename: "commodore1541.d64"
|
filename: "commodore1541.d64"
|
||||||
d64 {}
|
img {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,6 +17,139 @@ decoder {
|
|||||||
c64 {}
|
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 {
|
cylinders {
|
||||||
start: 0
|
start: 0
|
||||||
end: 79
|
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 {
|
input {
|
||||||
flux {
|
flux {
|
||||||
@@ -12,7 +12,7 @@ input {
|
|||||||
output {
|
output {
|
||||||
image {
|
image {
|
||||||
filename: "northstar.nsi"
|
filename: "northstar.nsi"
|
||||||
nsi {}
|
img {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,9 +20,19 @@ decoder {
|
|||||||
northstar {}
|
northstar {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 35
|
||||||
|
heads: 2
|
||||||
|
block_ordering: ORDER_NSI
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cylinders {
|
cylinders {
|
||||||
start: 0
|
start: 0
|
||||||
end: 34
|
end: 39
|
||||||
}
|
}
|
||||||
|
|
||||||
heads {
|
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 {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "amiga.adf"
|
filename: "amiga.adf"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 11
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,6 +11,15 @@ output {
|
|||||||
flux {}
|
flux {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 11
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
amiga {}
|
amiga {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 360kB 3.5" 80-track 9-sector single sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist360.st"
|
filename: "atarist360.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 370kB 3.5" 82-track 9-sector single sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist370.st"
|
filename: "atarist370.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 82
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 82
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 400kB 3.5" 80-track 10-sector single sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist400.st"
|
filename: "atarist400.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 10
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 410kB 3.5" 82-track 10-sector single sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist410.st"
|
filename: "atarist410.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 82
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 10
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 82
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 720kB 3.5" 80-track 9-sector double sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist720.st"
|
filename: "atarist720.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 740kB 3.5" 82-track 9-sector double sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist740.st"
|
filename: "atarist740.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 82
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 82
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 800kB 3.5" 80-track 10-sector double sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist800.st"
|
filename: "atarist800.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 10
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Atari ST 820kB 3.5" 82-track 10-sector double sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "atarist820.st"
|
filename: "atarist820.st"
|
||||||
img {
|
img {}
|
||||||
tracks: 82
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 10
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 82
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Brother 120kB 3.5" 39-track GCR disks'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "brother120.img"
|
filename: "brother120.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 39
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 12
|
|
||||||
sector_size: 256
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 39
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 12
|
||||||
|
sector_size: 256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
brother {
|
brother {
|
||||||
format: BROTHER120
|
format: BROTHER120
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Brother 240kB 3.5" 78-track GCR disks'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "brother240.img"
|
filename: "brother240.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 78
|
|
||||||
sides: 1
|
|
||||||
trackdata {
|
|
||||||
sectors: 12
|
|
||||||
sector_size: 256
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 78
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 12
|
||||||
|
sector_size: 256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
brother {}
|
brother {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ comment: 'Commodore 1541 170kB 5.25" GCR disks'
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "commodore1541.img"
|
filename: "commodore1541.d64"
|
||||||
d64 {}
|
img {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,9 +17,142 @@ encoder {
|
|||||||
c64 {}
|
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 {
|
cylinders {
|
||||||
start: 0
|
start: 0
|
||||||
end: 79
|
end: 81
|
||||||
}
|
}
|
||||||
|
|
||||||
heads {
|
heads {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Commodore 1581 800kB 3.5" MFM disks'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "commodore1581.d81"
|
filename: "commodore1581.d81"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 10
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 10
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Hewlett-Packard LIF 770kB 3.5" disks'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "hplif770.img"
|
filename: "hplif770.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 77
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 5
|
|
||||||
sector_size: 1024
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 77
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 5
|
||||||
|
sector_size: 1024
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'PC 1200kB 5.25" 80-track 15-sector double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm1200_525.img"
|
filename: "ibm1200_525.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 15
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 15
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'PC 1440kB 3.5" 80-track 18-sector double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm1440.img"
|
filename: "ibm1440.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 18
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 18
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,15 +3,7 @@ comment: 'PC 180kB 5.25" 40-track 9-sector single-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm180_525.img"
|
filename: "ibm180_525.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 40
|
|
||||||
sides: 1
|
|
||||||
physical_step: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 40
|
||||||
|
heads: 1
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,15 +3,7 @@ comment: 'PC 360kB 5.25" 40-track 9-sector double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm360_525.img"
|
filename: "ibm360_525.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 40
|
|
||||||
sides: 2
|
|
||||||
physical_step: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 40
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'PC 720kB 3.5" 80-track 9-sector double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm720.img"
|
filename: "ibm720.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
trackdata {
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'PC 720kB 5.25" 80-track 9-sector double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "ibm720_525.img"
|
filename: "ibm720_525.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 80
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 9
|
|
||||||
sector_size: 512
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 80
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 9
|
||||||
|
sector_size: 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
ibm {
|
ibm {
|
||||||
trackdata {
|
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 {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "northstar.nsi"
|
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 {
|
encoder {
|
||||||
northstar {}
|
northstar {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ comment: 'Northstar 350kB 5.25" 35-track double-sided double-density hard-sector
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "northstar.nsi"
|
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 {
|
encoder {
|
||||||
northstar {}
|
northstar {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ comment: 'Northstar 87.5kB 5.25" 35-track single-sided single-density hard-secto
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "northstar.nsi"
|
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 {
|
encoder {
|
||||||
northstar {}
|
northstar {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,7 @@ comment: 'Texas Instruments DS990 1126kB 8" double-sided'
|
|||||||
input {
|
input {
|
||||||
image {
|
image {
|
||||||
filename: "tids990.img"
|
filename: "tids990.img"
|
||||||
img {
|
img {}
|
||||||
tracks: 77
|
|
||||||
sides: 2
|
|
||||||
trackdata {
|
|
||||||
sectors: 26
|
|
||||||
sector_size: 288
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +13,15 @@ output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
geometry {
|
||||||
|
cylinders: 77
|
||||||
|
heads: 2
|
||||||
|
trackdata {
|
||||||
|
sectors: 26
|
||||||
|
sector_size: 288
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
encoder {
|
encoder {
|
||||||
tids990 {}
|
tids990 {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "bytes.h"
|
#include "bytes.h"
|
||||||
|
#include "snowhouse/snowhouse.h"
|
||||||
|
|
||||||
|
using namespace snowhouse;
|
||||||
|
|
||||||
static void check_oob(Bytes& b, unsigned pos)
|
static void check_oob(Bytes& b, unsigned pos)
|
||||||
{
|
{
|
||||||
@@ -113,6 +116,13 @@ static void test_slice()
|
|||||||
|
|
||||||
bs = b.slice(4, 2);
|
bs = b.slice(4, 2);
|
||||||
assert((bs == Bytes{ 0, 0 }));
|
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()
|
static void test_tobits()
|
||||||
|
|||||||
Reference in New Issue
Block a user