Compare commits

...

9 commits

Author SHA1 Message Date
dg
4ab66afca0 Split the encoder's use of clock and bitcell, as for FM/MFM they're different
things; make the FM/MFM decoders use twice the bitcell for the clock.
2021-12-06 23:18:31 +00:00
dg
0af57f3e97 Create new branch named "fixes" 2021-12-06 22:42:19 +00:00
dg
36c2263675 Fix the Micropolis decoder after the PLL upgrade. 2021-12-06 22:20:18 +00:00
David Given
28068d8d31
Merge pull request #375 from davidgiven/fl2
Make the new FL2 format the default.
2021-12-06 22:14:33 +00:00
David Given
376270dd53
Merge pull request #377 from tdaede/d88trackfill
Set FM gap fill byte in D88.
2021-12-06 16:21:13 +00:00
Thomas Daede
9056b23eaa Set FM gap fill byte in D88. 2021-12-06 08:10:02 -08:00
David Given
422620f4fe
Merge pull request #374 from davidgiven/ibm
Make the gap fill byte configurable.
2021-12-05 22:27:45 +00:00
dg
ebb5c17be4 Make the IBM format gap fill byte configurable. 2021-12-05 16:43:45 +00:00
dg
1e99fe5b04 Merge from master. 2021-12-05 16:37:04 +00:00
22 changed files with 57 additions and 40 deletions

View file

@ -32,8 +32,9 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
_sector->clock = _fmr->seekToPattern(SECTOR_PATTERN); _sector->bitcell = _fmr->seekToPattern(SECTOR_PATTERN);
if (_fmr->eof() || !_sector->clock) _sector->clock = _sector->bitcell * 2;
if (_fmr->eof() || !_sector->bitcell)
return UNKNOWN_RECORD; return UNKNOWN_RECORD;
return SECTOR_RECORD; return SECTOR_RECORD;
} }

View file

@ -31,8 +31,9 @@ public:
RecordType advanceToNextRecord() override RecordType advanceToNextRecord() override
{ {
_sector->clock = _fmr->seekToPattern(SECTOR_PATTERN); _sector->bitcell = _fmr->seekToPattern(SECTOR_PATTERN);
if (_fmr->eof() || !_sector->clock) _sector->clock = _sector->bitcell * 2;
if (_fmr->eof() || !_sector->bitcell)
return UNKNOWN_RECORD; return UNKNOWN_RECORD;
return SECTOR_RECORD; return SECTOR_RECORD;
} }

View file

@ -74,7 +74,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -63,7 +63,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -61,7 +61,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -61,7 +61,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -107,7 +107,8 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(SECTOR_ID_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(SECTOR_ID_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
if (matcher == &SECTOR_ID_PATTERN) if (matcher == &SECTOR_ID_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
return RecordType::UNKNOWN_RECORD; return RecordType::UNKNOWN_RECORD;

View file

@ -101,7 +101,8 @@ public:
RecordType advanceToNextRecord() override RecordType advanceToNextRecord() override
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
/* If this is the MFM prefix byte, the the decoder is going to expect three /* If this is the MFM prefix byte, the the decoder is going to expect three
* extra bytes on the front of the header. */ * extra bytes on the front of the header. */

View file

@ -133,11 +133,17 @@ public:
encodeMfm(_bits, _cursor, bytes, _lastBit); encodeMfm(_bits, _cursor, bytes, _lastBit);
}; };
auto writeFillerRawBytes = [&](int count, uint16_t byte)
{
for (int i=0; i<count; i++)
writeRawBits(byte, 16);
};
auto writeFillerBytes = [&](int count, uint8_t byte) auto writeFillerBytes = [&](int count, uint8_t byte)
{ {
Bytes bytes = { byte }; Bytes b { byte };
for (int i=0; i<count; i++) for (int i=0; i<count; i++)
writeBytes(bytes); writeBytes(b);
}; };
double clockRateUs = 1e3 / trackdata.clock_rate_khz(); double clockRateUs = 1e3 / trackdata.clock_rate_khz();
@ -160,9 +166,9 @@ public:
} }
} }
uint8_t gapFill = trackdata.use_fm() ? 0x00 : 0x4e; uint16_t gapFill = trackdata.gap_fill_byte();
writeFillerBytes(trackdata.gap0(), gapFill); writeFillerRawBytes(trackdata.gap0(), gapFill);
if (trackdata.emit_iam()) if (trackdata.emit_iam())
{ {
writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00); writeFillerBytes(trackdata.use_fm() ? 6 : 12, 0x00);
@ -172,7 +178,7 @@ public:
writeRawBits(MFM_IAM_SEPARATOR, 16); writeRawBits(MFM_IAM_SEPARATOR, 16);
} }
writeRawBits(trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16); writeRawBits(trackdata.use_fm() ? FM_IAM_RECORD : MFM_IAM_RECORD, 16);
writeFillerBytes(trackdata.gap1(), gapFill); writeFillerRawBytes(trackdata.gap1(), gapFill);
} }
int logicalSide = physicalSide ^ trackdata.swap_sides(); int logicalSide = physicalSide ^ trackdata.swap_sides();
@ -180,7 +186,7 @@ public:
for (int sectorId : trackdata.sectors().sector()) for (int sectorId : trackdata.sectors().sector())
{ {
if (!first) if (!first)
writeFillerBytes(trackdata.gap3(), gapFill); writeFillerRawBytes(trackdata.gap3(), gapFill);
first = false; first = false;
const auto& sectorData = image.get(physicalTrack, logicalSide, sectorId); const auto& sectorData = image.get(physicalTrack, logicalSide, sectorId);
@ -227,7 +233,7 @@ public:
writeBytes(header.slice(conventionalHeaderStart)); writeBytes(header.slice(conventionalHeaderStart));
} }
writeFillerBytes(trackdata.gap2(), gapFill); writeFillerRawBytes(trackdata.gap2(), gapFill);
{ {
Bytes data; Bytes data;
@ -264,7 +270,7 @@ public:
if (_cursor >= _bits.size()) if (_cursor >= _bits.size())
Error() << "track data overrun"; Error() << "track data overrun";
while (_cursor < _bits.size()) while (_cursor < _bits.size())
writeFillerBytes(1, gapFill); writeFillerRawBytes(1, gapFill);
std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); std::unique_ptr<Fluxmap> fluxmap(new Fluxmap);
fluxmap->appendBits(_bits, clockRateUs*1e3); fluxmap->appendBits(_bits, clockRateUs*1e3);

View file

@ -15,7 +15,7 @@ message IbmDecoderProto {
} }
message IbmEncoderProto { message IbmEncoderProto {
// Next: 18 // Next: 19
message TrackdataProto { message TrackdataProto {
message SectorsProto { message SectorsProto {
repeated int32 sector = 1 [(help) = "write these sectors (in order) on each track"]; repeated int32 sector = 1 [(help) = "write these sectors (in order) on each track"];
@ -37,6 +37,7 @@ message IbmEncoderProto {
optional int32 gap3 = 12 [default=80, (help) = "size of gap 4 (the post-data or format gap)"]; optional int32 gap3 = 12 [default=80, (help) = "size of gap 4 (the post-data or format gap)"];
optional bool swap_sides = 14 [default=false, (help) = "swap side bytes when writing"]; optional bool swap_sides = 14 [default=false, (help) = "swap side bytes when writing"];
optional SectorsProto sectors = 17 [(help) = "write these sectors (in order) on each track"]; optional SectorsProto sectors = 17 [(help) = "write these sectors (in order) on each track"];
optional int32 gap_fill_byte = 18 [default=0x9254, (help) = "16-bit raw bit pattern of gap fill byte"];
} }
repeated TrackdataProto trackdata = 1; repeated TrackdataProto trackdata = 1;

View file

@ -132,7 +132,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return SECTOR_RECORD; return SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -35,9 +35,9 @@ public:
{ {
_fmr->seekToIndexMark(); _fmr->seekToIndexMark();
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(SECTOR_SYNC_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(SECTOR_SYNC_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
if (matcher == &SECTOR_SYNC_PATTERN) { if (matcher == &SECTOR_SYNC_PATTERN) {
readRawBits(16);
return SECTOR_RECORD; return SECTOR_RECORD;
} }
return UNKNOWN_RECORD; return UNKNOWN_RECORD;
@ -45,6 +45,7 @@ public:
void decodeSectorRecord() void decodeSectorRecord()
{ {
readRawBits(16);
auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE*16); auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE*16);
auto bytes = decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE); auto bytes = decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE);
ByteReader br(bytes); ByteReader br(bytes);

View file

@ -31,7 +31,7 @@ public:
void beginTrack() void beginTrack()
{ {
_currentSector = -1; _currentSector = -1;
_clock = 0; _bitcell = 0;
} }
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
@ -40,7 +40,8 @@ public:
{ {
/* First sector in the track: look for the sync marker. */ /* First sector in the track: look for the sync marker. */
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _clock = _fmr->seekToPattern(ID_PATTERN, matcher); _sector->bitcell = _bitcell = _fmr->seekToPattern(ID_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
readRawBits(32); /* skip the ID mark */ readRawBits(32); /* skip the ID mark */
_logicalTrack = decodeFmMfm(readRawBits(32)).slice(0, 32).reader().read_be16(); _logicalTrack = decodeFmMfm(readRawBits(32)).slice(0, 32).reader().read_be16();
} }
@ -54,7 +55,7 @@ public:
/* Otherwise we assume the clock from the first sector is still valid. /* Otherwise we assume the clock from the first sector is still valid.
* The decoder framwork will automatically stop when we hit the end of * The decoder framwork will automatically stop when we hit the end of
* the track. */ * the track. */
_sector->clock = _clock; _sector->bitcell = _bitcell;
} }
_currentSector++; _currentSector++;
@ -80,7 +81,7 @@ public:
} }
private: private:
nanoseconds_t _clock; nanoseconds_t _bitcell;
int _currentSector; int _currentSector;
int _logicalTrack; int _logicalTrack;
}; };

View file

@ -105,7 +105,8 @@ public:
* past one or more sector pulses. For this reason, calculate * past one or more sector pulses. For this reason, calculate
* _hardSectorId after the sector header is found. * _hardSectorId after the sector header is found.
*/ */
_sector->clock = _fmr->seekToPattern(ANY_SECTOR_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(ANY_SECTOR_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
int sectorFoundTimeRaw = std::round((_fmr->tell().ns()) / 1e6); int sectorFoundTimeRaw = std::round((_fmr->tell().ns()) / 1e6);
int sectorFoundTime; int sectorFoundTime;

View file

@ -48,7 +48,8 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return RecordType::SECTOR_RECORD; return RecordType::SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -62,7 +62,7 @@ public:
RecordType advanceToNextRecord() RecordType advanceToNextRecord()
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_sector->clock = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher); _sector->clock = _sector->bitcell = _fmr->seekToPattern(ANY_RECORD_PATTERN, matcher);
if (matcher == &SECTOR_RECORD_PATTERN) if (matcher == &SECTOR_RECORD_PATTERN)
return SECTOR_RECORD; return SECTOR_RECORD;
if (matcher == &DATA_RECORD_PATTERN) if (matcher == &DATA_RECORD_PATTERN)

View file

@ -24,7 +24,8 @@ public:
{ {
const FluxMatcher* matcher = nullptr; const FluxMatcher* matcher = nullptr;
_fmr->seekToIndexMark(); _fmr->seekToIndexMark();
_sector->clock = _fmr->seekToPattern(SECTOR_START_PATTERN, matcher); _sector->bitcell = _fmr->seekToPattern(SECTOR_START_PATTERN, matcher);
_sector->clock = _sector->bitcell * 2;
if (matcher == &SECTOR_START_PATTERN) if (matcher == &SECTOR_START_PATTERN)
return SECTOR_RECORD; return SECTOR_RECORD;
return UNKNOWN_RECORD; return UNKNOWN_RECORD;

View file

@ -77,9 +77,9 @@ std::unique_ptr<TrackDataFlux> AbstractDecoder::decodeToSectors(
_sector->physicalHead = physicalHead; _sector->physicalHead = physicalHead;
Fluxmap::Position recordStart = fmr.tell(); Fluxmap::Position recordStart = fmr.tell();
_decoder.reset(new FluxDecoder(&fmr, _sector->clock, _config)); _decoder.reset(new FluxDecoder(&fmr, _sector->bitcell, _config));
RecordType r = advanceToNextRecord(); RecordType r = advanceToNextRecord();
if (fmr.eof() || !_sector->clock) if (fmr.eof() || !_sector->bitcell)
return std::move(_trackdata); return std::move(_trackdata);
if ((r == UNKNOWN_RECORD) || (r == DATA_RECORD)) if ((r == UNKNOWN_RECORD) || (r == DATA_RECORD))
{ {
@ -134,17 +134,17 @@ void AbstractDecoder::pushRecord(const Fluxmap::Position& start, const Fluxmap::
record->startTime = start.ns(); record->startTime = start.ns();
record->endTime = end.ns(); record->endTime = end.ns();
record->clock = _sector->clock; record->bitcell = _sector->bitcell;
_fmr->seek(start); _fmr->seek(start);
FluxDecoder decoder(_fmr, _sector->clock, _config); FluxDecoder decoder(_fmr, _sector->bitcell, _config);
record->rawData = toBytes(decoder.readBits(end)); record->rawData = toBytes(decoder.readBits(end));
_fmr->seek(here); _fmr->seek(here);
} }
void AbstractDecoder::resetFluxDecoder() void AbstractDecoder::resetFluxDecoder()
{ {
_decoder.reset(new FluxDecoder(_fmr, _sector->clock, _config)); _decoder.reset(new FluxDecoder(_fmr, _sector->bitcell, _config));
} }
std::vector<bool> AbstractDecoder::readRawBits(unsigned count) std::vector<bool> AbstractDecoder::readRawBits(unsigned count)

View file

@ -6,7 +6,7 @@ class Image;
struct Record struct Record
{ {
nanoseconds_t clock = 0; nanoseconds_t bitcell = 0;
nanoseconds_t startTime = 0; nanoseconds_t startTime = 0;
nanoseconds_t endTime = 0; nanoseconds_t endTime = 0;
Bytes rawData; Bytes rawData;

View file

@ -127,7 +127,7 @@ public:
trackdata->set_sector_size(sectorSize); trackdata->set_sector_size(sectorSize);
trackdata->set_use_fm(fm); trackdata->set_use_fm(fm);
if (fm) { if (fm) {
//trackdata->set_clock_rate_khz(250*300/360); trackdata->set_gap_fill_byte(0xffff);
trackdata->set_idam_byte(0xf57e); trackdata->set_idam_byte(0xf57e);
trackdata->set_dam_byte(0xf56f); trackdata->set_dam_byte(0xf56f);
} }

View file

@ -156,9 +156,9 @@ void readDiskCommand(FluxSource& fluxsource, AbstractDecoder& decoder, ImageWrit
std::cout << "\nRaw (undecoded) records follow:\n\n"; std::cout << "\nRaw (undecoded) records follow:\n\n";
for (const auto& record : track_records) for (const auto& record : track_records)
{ {
std::cout << fmt::format("I+{:.2f}us with {:.2f}us clock\n", std::cout << fmt::format("I+{:.2f}us with {:.2f}us bitcell\n",
record->startTime / 1000.0, record->startTime / 1000.0,
record->clock / 1000.0); record->bitcell / 1000.0);
hexdump(std::cout, record->rawData); hexdump(std::cout, record->rawData);
std::cout << std::endl; std::cout << std::endl;
} }

View file

@ -28,6 +28,7 @@ public:
Status status = Status::INTERNAL_ERROR; Status status = Status::INTERNAL_ERROR;
Fluxmap::Position position; Fluxmap::Position position;
nanoseconds_t clock = 0; nanoseconds_t clock = 0;
nanoseconds_t bitcell = 0;
nanoseconds_t headerStartTime = 0; nanoseconds_t headerStartTime = 0;
nanoseconds_t headerEndTime = 0; nanoseconds_t headerEndTime = 0;
nanoseconds_t dataStartTime = 0; nanoseconds_t dataStartTime = 0;