Skip to content

Commit 5e05083

Browse files
authored
Merge pull request #584 from davidgiven/c64
Another attempt at fixing the C64 1581 bug.
2 parents d441ad8 + 339e9cc commit 5e05083

File tree

11 files changed

+223
-189
lines changed

11 files changed

+223
-189
lines changed

arch/ibm/decoder.cc

Lines changed: 150 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,53 @@
1111
#include <string.h>
1212

1313
static_assert(std::is_trivially_copyable<IbmIdam>::value,
14-
"IbmIdam is not trivially copyable");
14+
"IbmIdam is not trivially copyable");
1515

1616
/*
1717
* The markers at the beginning of records are special, and have
1818
* missing clock pulses, allowing them to be found by the logic.
19-
*
19+
*
2020
* IAM record:
2121
* flux: XXXX-XXX-XXXX-X- = 0xf77a
2222
* clock: X X - X - X X X = 0xd7
2323
* data: X X X X X X - - = 0xfc
24-
*
24+
*
2525
* (We just ignore this one --- it's useless and optional.)
2626
*/
2727

28-
/*
28+
/*
2929
* IDAM record:
3030
* flux: XXXX-X-X-XXXXXX- = 0xf57e
3131
* clock: X X - - - X X X = 0xc7
3232
* data: X X X X X X X - = 0xfe
3333
*/
3434
const FluxPattern FM_IDAM_PATTERN(16, 0xf57e);
3535

36-
/*
36+
/*
3737
* DAM1 record:
3838
* flux: XXXX-X-X-XX-X-X- = 0xf56a
3939
* clock: X X - - - X X X = 0xc7
4040
* data: X X X X X - - - = 0xf8
4141
*/
4242
const FluxPattern FM_DAM1_PATTERN(16, 0xf56a);
4343

44-
/*
44+
/*
4545
* DAM2 record:
4646
* flux: XXXX-X-X-XX-XXXX = 0xf56f
4747
* clock: X X - - - X X X = 0xc7
4848
* data: X X X X X - X X = 0xfb
4949
*/
5050
const FluxPattern FM_DAM2_PATTERN(16, 0xf56f);
5151

52-
/*
52+
/*
5353
* TRS80DAM1 record:
5454
* flux: XXXX-X-X-XX-X-XX = 0xf56b
5555
* clock: X X - - - X X X = 0xc7
5656
* data: X X X X X - - X = 0xf9
5757
*/
5858
const FluxPattern FM_TRS80DAM1_PATTERN(16, 0xf56b);
5959

60-
/*
60+
/*
6161
* TRS80DAM2 record:
6262
* flux: XXXX-X-X-XX-XXX- = 0xf56e
6363
* clock: X X - - - X X X = 0xc7
@@ -73,165 +73,172 @@ const FluxPattern FM_TRS80DAM2_PATTERN(16, 0xf56e);
7373
* ^^^^^
7474
* When shifted out of phase, the special 0xa1 byte becomes an illegal
7575
* encoding (you can't do 10 00). So this can't be spoofed by user data.
76-
*
76+
*
7777
* shifted: 10 00 10 01 00 01 00 1
78-
*
78+
*
7979
* It's repeated three times.
8080
*/
8181
const FluxPattern MFM_PATTERN(48, 0x448944894489LL);
8282

83-
const FluxMatchers ANY_RECORD_PATTERN(
84-
{
85-
&MFM_PATTERN,
86-
&FM_IDAM_PATTERN,
87-
&FM_DAM1_PATTERN,
88-
&FM_DAM2_PATTERN,
89-
&FM_TRS80DAM1_PATTERN,
90-
&FM_TRS80DAM2_PATTERN,
91-
}
92-
);
83+
const FluxMatchers ANY_RECORD_PATTERN({
84+
&MFM_PATTERN,
85+
&FM_IDAM_PATTERN,
86+
&FM_DAM1_PATTERN,
87+
&FM_DAM2_PATTERN,
88+
&FM_TRS80DAM1_PATTERN,
89+
&FM_TRS80DAM2_PATTERN,
90+
});
9391

9492
class IbmDecoder : public AbstractDecoder
9593
{
9694
public:
9795
IbmDecoder(const DecoderProto& config):
98-
AbstractDecoder(config),
99-
_config(config.ibm())
100-
{}
96+
AbstractDecoder(config),
97+
_config(config.ibm())
98+
{
99+
}
101100

102101
nanoseconds_t advanceToNextRecord() override
103-
{
104-
return seekToPattern(ANY_RECORD_PATTERN);
105-
}
102+
{
103+
return seekToPattern(ANY_RECORD_PATTERN);
104+
}
106105

107106
void decodeSectorRecord() override
108-
{
109-
/* This is really annoying because the IBM record scheme has a
110-
* variable-sized header _and_ the checksum covers this header too. So
111-
* we have to read and decode a byte at a time until we know where the
112-
* record itself starts, saving the bytes for the checksumming later.
113-
*/
114-
115-
Bytes bytes;
116-
ByteWriter bw(bytes);
117-
118-
auto readByte = [&]() {
119-
auto bits = readRawBits(16);
120-
auto bytes = decodeFmMfm(bits).slice(0, 1);
121-
uint8_t byte = bytes[0];
122-
bw.write_8(byte);
123-
return byte;
124-
};
125-
126-
uint8_t id = readByte();
127-
if (id == 0xa1)
128-
{
129-
readByte();
130-
readByte();
131-
id = readByte();
132-
}
133-
if (id != IBM_IDAM)
134-
return;
135-
136-
ByteReader br(bytes);
137-
br.seek(bw.pos);
138-
139-
auto bits = readRawBits(IBM_IDAM_LEN*16);
140-
bw += decodeFmMfm(bits).slice(0, IBM_IDAM_LEN);
141-
142-
IbmDecoderProto::TrackdataProto trackdata;
143-
getTrackFormat(trackdata, _sector->physicalTrack, _sector->physicalHead);
144-
145-
_sector->logicalTrack = br.read_8();
146-
_sector->logicalSide = br.read_8();
147-
_sector->logicalSector = br.read_8();
148-
_currentSectorSize = 1 << (br.read_8() + 7);
149-
uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
150-
uint16_t wantCrc = br.read_be16();
151-
if (wantCrc == gotCrc)
152-
_sector->status = Sector::DATA_MISSING; /* correct but unintuitive */
153-
154-
_sector->logicalSide ^= trackdata.invert_side_byte();
155-
if (trackdata.ignore_side_byte())
156-
_sector->logicalSide = _sector->physicalHead;
157-
if (trackdata.ignore_track_byte())
158-
_sector->logicalTrack = _sector->physicalTrack;
159-
160-
for (int sector : trackdata.ignore_sector())
161-
if (_sector->logicalSector == sector)
162-
{
163-
_sector->status = Sector::MISSING;
164-
break;
165-
}
166-
}
107+
{
108+
/* This is really annoying because the IBM record scheme has a
109+
* variable-sized header _and_ the checksum covers this header too. So
110+
* we have to read and decode a byte at a time until we know where the
111+
* record itself starts, saving the bytes for the checksumming later.
112+
*/
113+
114+
Bytes bytes;
115+
ByteWriter bw(bytes);
116+
117+
auto readByte = [&]()
118+
{
119+
auto bits = readRawBits(16);
120+
auto bytes = decodeFmMfm(bits).slice(0, 1);
121+
uint8_t byte = bytes[0];
122+
bw.write_8(byte);
123+
return byte;
124+
};
125+
126+
uint8_t id = readByte();
127+
if (id == 0xa1)
128+
{
129+
readByte();
130+
readByte();
131+
id = readByte();
132+
}
133+
if (id != IBM_IDAM)
134+
return;
135+
136+
ByteReader br(bytes);
137+
br.seek(bw.pos);
138+
139+
auto bits = readRawBits(IBM_IDAM_LEN * 16);
140+
bw += decodeFmMfm(bits).slice(0, IBM_IDAM_LEN);
141+
142+
IbmDecoderProto::TrackdataProto trackdata;
143+
getTrackFormat(
144+
trackdata, _sector->physicalTrack, _sector->physicalHead);
145+
146+
_sector->logicalTrack = br.read_8();
147+
_sector->logicalSide = br.read_8();
148+
_sector->logicalSector = br.read_8();
149+
_currentSectorSize = 1 << (br.read_8() + 7);
150+
uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
151+
uint16_t wantCrc = br.read_be16();
152+
if (wantCrc == gotCrc)
153+
_sector->status =
154+
Sector::DATA_MISSING; /* correct but unintuitive */
155+
156+
if (trackdata.ignore_side_byte())
157+
_sector->logicalSide = _sector->physicalHead;
158+
_sector->logicalSide ^= trackdata.invert_side_byte();
159+
if (trackdata.ignore_track_byte())
160+
_sector->logicalTrack = _sector->physicalTrack;
161+
162+
for (int sector : trackdata.ignore_sector())
163+
if (_sector->logicalSector == sector)
164+
{
165+
_sector->status = Sector::MISSING;
166+
break;
167+
}
168+
}
167169

168170
void decodeDataRecord() override
169-
{
170-
/* This is the same deal as the sector record. */
171-
172-
Bytes bytes;
173-
ByteWriter bw(bytes);
174-
175-
auto readByte = [&]() {
176-
auto bits = readRawBits(16);
177-
auto bytes = decodeFmMfm(bits).slice(0, 1);
178-
uint8_t byte = bytes[0];
179-
bw.write_8(byte);
180-
return byte;
181-
};
182-
183-
uint8_t id = readByte();
184-
if (id == 0xa1)
185-
{
186-
readByte();
187-
readByte();
188-
id = readByte();
189-
}
190-
if ((id != IBM_DAM1) && (id != IBM_DAM2)
191-
&& (id != IBM_TRS80DAM1) && (id != IBM_TRS80DAM2))
192-
return;
193-
194-
ByteReader br(bytes);
195-
br.seek(bw.pos);
196-
197-
auto bits = readRawBits((_currentSectorSize + 2) * 16);
198-
bw += decodeFmMfm(bits).slice(0, _currentSectorSize+2);
199-
200-
_sector->data = br.read(_currentSectorSize);
201-
uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
202-
uint16_t wantCrc = br.read_be16();
203-
_sector->status = (wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
204-
}
205-
206-
std::set<unsigned> requiredSectors(const Location& location) const override
207-
{
208-
auto& trackLayout = Layout::getLayoutOfTrack(location.logicalTrack, location.head);
209-
return std::set<unsigned>(trackLayout.logicalSectorOrder.begin(), trackLayout.logicalSectorOrder.end());
210-
}
171+
{
172+
/* This is the same deal as the sector record. */
173+
174+
Bytes bytes;
175+
ByteWriter bw(bytes);
176+
177+
auto readByte = [&]()
178+
{
179+
auto bits = readRawBits(16);
180+
auto bytes = decodeFmMfm(bits).slice(0, 1);
181+
uint8_t byte = bytes[0];
182+
bw.write_8(byte);
183+
return byte;
184+
};
185+
186+
uint8_t id = readByte();
187+
if (id == 0xa1)
188+
{
189+
readByte();
190+
readByte();
191+
id = readByte();
192+
}
193+
if ((id != IBM_DAM1) && (id != IBM_DAM2) && (id != IBM_TRS80DAM1) &&
194+
(id != IBM_TRS80DAM2))
195+
return;
196+
197+
ByteReader br(bytes);
198+
br.seek(bw.pos);
199+
200+
auto bits = readRawBits((_currentSectorSize + 2) * 16);
201+
bw += decodeFmMfm(bits).slice(0, _currentSectorSize + 2);
202+
203+
_sector->data = br.read(_currentSectorSize);
204+
uint16_t gotCrc = crc16(CCITT_POLY, bytes.slice(0, br.pos));
205+
uint16_t wantCrc = br.read_be16();
206+
_sector->status =
207+
(wantCrc == gotCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
208+
}
209+
210+
std::set<unsigned> requiredSectors(const Location& location) const override
211+
{
212+
auto& trackLayout =
213+
Layout::getLayoutOfTrack(location.logicalTrack, location.head);
214+
return std::set<unsigned>(trackLayout.logicalSectorOrder.begin(),
215+
trackLayout.logicalSectorOrder.end());
216+
}
211217

212218
private:
213-
void getTrackFormat(IbmDecoderProto::TrackdataProto& trackdata, unsigned track, unsigned head) const
214-
{
215-
trackdata.Clear();
216-
for (const auto& f : _config.trackdata())
217-
{
218-
if (f.has_track() && (f.track() != track))
219-
continue;
220-
if (f.has_head() && (f.head() != head))
221-
continue;
222-
223-
trackdata.MergeFrom(f);
224-
}
225-
}
219+
void getTrackFormat(IbmDecoderProto::TrackdataProto& trackdata,
220+
unsigned track,
221+
unsigned head) const
222+
{
223+
trackdata.Clear();
224+
for (const auto& f : _config.trackdata())
225+
{
226+
if (f.has_track() && (f.track() != track))
227+
continue;
228+
if (f.has_head() && (f.head() != head))
229+
continue;
230+
231+
trackdata.MergeFrom(f);
232+
}
233+
}
226234

227235
private:
228-
const IbmDecoderProto& _config;
236+
const IbmDecoderProto& _config;
229237
unsigned _currentSectorSize;
230238
unsigned _currentHeaderLength;
231239
};
232240

233241
std::unique_ptr<AbstractDecoder> createIbmDecoder(const DecoderProto& config)
234242
{
235-
return std::unique_ptr<AbstractDecoder>(new IbmDecoder(config));
243+
return std::unique_ptr<AbstractDecoder>(new IbmDecoder(config));
236244
}
237-

arch/ibm/encoder.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,25 @@ class IbmEncoder : public AbstractEncoder
107107
}
108108

109109
public:
110+
std::shared_ptr<const Sector> getSector(
111+
const Location& location, const Image& image, unsigned sectorId)
112+
{
113+
IbmEncoderProto::TrackdataProto trackdata;
114+
getEncoderTrackData(trackdata, location.logicalTrack, location.head);
115+
116+
if (trackdata.swap_sides())
117+
{
118+
Location newLocation = location;
119+
newLocation.head ^= 1;
120+
auto sector = std::make_shared<Sector>(
121+
*AbstractEncoder::getSector(newLocation, image, sectorId));
122+
sector->logicalSide ^= 1;
123+
return sector;
124+
}
125+
else
126+
return image.get(location.logicalTrack, location.head, sectorId);
127+
}
128+
110129
std::unique_ptr<Fluxmap> encode(const Location& location,
111130
const std::vector<std::shared_ptr<const Sector>>& sectors,
112131
const Image& image) override

0 commit comments

Comments
 (0)