1111#include < string.h>
1212
1313static_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 */
3434const 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 */
4242const 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 */
5050const 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 */
5858const 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 */
8181const 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
9492class IbmDecoder : public AbstractDecoder
9593{
9694public:
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
212218private:
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
227235private:
228- const IbmDecoderProto& _config;
236+ const IbmDecoderProto& _config;
229237 unsigned _currentSectorSize;
230238 unsigned _currentHeaderLength;
231239};
232240
233241std::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-
0 commit comments