openMSX
RawTrack.hh
Go to the documentation of this file.
1 #ifndef RAWTRACK_HH
2 #define RAWTRACK_HH
3 
4 #include "openmsx.hh"
5 #include "serialize_meta.hh"
6 #include <vector>
7 
8 namespace openmsx {
9 
10 class CRC16;
11 
12 // This class represents a raw disk track. It contains the logical sector
13 // content, but also address blocks, CRC checksums, sync blocks and the data
14 // in the gaps between these blocks.
15 //
16 // The internal representation is based on the DMK disk image file format. See:
17 // http://www.trs-80.com/wordpress/dsk-and-dmk-image-utilities/
18 // (at the bottom of the page)
19 //
20 // Besides the raw track data, this format also stores the positions of the
21 // 'address marks' in the track (this roughly corresponds with the start of a
22 // sector). Of course a real disk doesn't have such a list. In a real disk this
23 // information is stored as 'MFM encodings with missing clock transitions'.
24 //
25 // Normal MFM encoding goes like this: An input bit of '0' is encoded as 'x0'
26 // with x the inverse of the previously encoded bit. A '1' input bit is encoded
27 // as '01'. (More in detail: a '1' encoded bit indicates a magnetic flux
28 // transition, a '0' bit is no flux transition). So for example the input byte
29 // 0xA1 (binary 10100001) is MFM encoded as '01 00 01 00 10 10 10 01'. (Note
30 // that decoding is simply taking every 2nd bit (the data bits), the other bits
31 // (the clock bits) ensure that between encoded '1' bits is always at least 1
32 // and at most 3 zero bits. So no too dense flux transitions and not too far
33 // apart to keep the stream synchronized).
34 //
35 // Now for the missing clock transitions: besides the encodings for the 256
36 // possible input bytes, the FDC can write two other encodings, namely:
37 // 01 00 01 00 10 00 10 01 (0xA1 with missing clock between bit 4 and 5)
38 // 01 01 00 10 00 10 01 00 (0xC2 with missing clock between bit 3 and 4)
39 //
40 // So in principle we should store each of these special 0xA1 or 0xC2 bytes.
41 // Instead we only store the locations of '0xA1 0xA1 0xA1 0xFE' sequences (the
42 // 0xA1 bytes have missing clocks, this sequence indicates the start of an
43 // address mark). So we don't store the location of the special 0xC2 bytes, nor
44 // the location of each special 0xA1 byte. These certainly do occur on a real
45 // disk track, but the WD2793 controller only reacts to the full sequence
46 // above, so for us this is good enough. (The FDC also uses these special
47 // encodings to re-synchronize itself with the input stream, e.g. figure out
48 // which bit is the start bit in a byte, but from a functional emulation point
49 // of view we can ignore this).
50 //
51 // Also note that it's possible to create real disks that have still completely
52 // different magnetic flux patterns than the 256+2 possible MFM patterns
53 // described above. Such disks cannot be described by this class. But for
54 // openMSX that's not a problem because the WD2793 or TC8566AF disk controllers
55 // anyway can't handle such disks (they would always interpret the flux pattern
56 // as one of the 256+2 MFM patterns). Other systems (like Amiga) have disk
57 // controllers that allow more direct access to the disk and could for example
58 // encode the data in a more efficient way than MFM (e.g. GCR6). That's why
59 // Amiga can fit more data on the same disk (even more than simply storing 10
60 // or 11 sectors on a track by making the gaps between the sectors smaller).
61 
62 class RawTrack {
63 public:
64  // Typical track length is 6250 bytes:
65  // 250kbps, 300rpm -> 6250 bytes per rotation.
66  // The IBM Disk Format Specification confirms this number.
67  // Of course this is in ideal circumstances: in reality the rotation
68  // speed can vary and thus the disk can be formatted with slightly more
69  // or slightly less raw bytes per track. This class can also represent
70  // tracks of different lengths.
71  static const unsigned STANDARD_SIZE = 6250;
72 
73  struct Sector
74  {
75  int addrIdx;
76  int dataIdx;
81  bool deleted;
82  bool addrCrcErr;
83  bool dataCrcErr;
84 
85  template<typename Archive>
86  void serialize(Archive& ar, unsigned version);
87  };
88 
89  /* Construct a (cleared) track. */
90  explicit RawTrack(unsigned size = STANDARD_SIZE);
91 
93  void clear(unsigned size);
94 
96  unsigned getLength() const { return unsigned(data.size()); }
97 
98  void addIdam(unsigned idx);
99 
100  // In the methods below, 'index' is allowed to be 'out-of-bounds',
101  // it will wrap like in a circular buffer.
102 
103  byte read(int idx) const { return data[wrapIndex(idx)]; }
104  void write(int idx, byte val, bool setIdam = false);
105  int wrapIndex(int idx) const {
106  // operator% is not a modulo but a remainder operation (makes a
107  // difference for negative inputs). Hence the extra test.
108  int tmp = idx % int(data.size());
109  return (tmp >= 0) ? tmp : int(tmp + data.size());
110  }
111 
112  byte* getRawBuffer() { return data.data(); }
113  const byte* getRawBuffer() const { return data.data(); }
114  const std::vector<unsigned>& getIdamBuffer() const { return idam; }
115 
117  std::vector<Sector> decodeAll() const;
118 
120  bool decodeNextSector(unsigned startIdx, Sector& sector) const;
121 
127  bool decodeSector(byte sectorNum, Sector& sector) const;
128 
130  void readBlock (int idx, unsigned size, byte* destination) const;
131  void writeBlock(int idx, unsigned size, const byte* source);
132 
134  word calcCrc(int idx, int size) const;
135  void updateCrc(CRC16& crc, int idx, int size) const;
136 
138 
139  template<typename Archive>
140  void serialize(Archive& ar, unsigned version);
141 
142 private:
143  bool decodeSectorImpl(int idx, Sector& sector) const;
144 
145  // Index into 'data'-array to positions where an address mark
146  // starts (it points to the 'FE' byte in the 'A1 A1 A1 FE ..'
147  // sequence.
148  std::vector<unsigned> idam;
149 
150  // MFM-decoded raw data, this does NOT include the missing clock
151  // transitions that can occur in the encodings of the 'A1' and
152  // 'C2' bytes.
153  std::vector<byte> data;
154 };
156 
157 } // namespace openmsx
158 
159 #endif
bool decodeSector(byte sectorNum, Sector &sector) const
Get a sector with a specific number.
Definition: RawTrack.cc:153
void addIdam(unsigned idx)
Definition: RawTrack.cc:34
void applyWd2793ReadTrackQuirk()
Definition: RawTrack.cc:199
unsigned getLength() const
Get track length.
Definition: RawTrack.hh:96
void updateCrc(CRC16 &crc, int idx, int size) const
Definition: RawTrack.cc:179
byte read(int idx) const
Definition: RawTrack.hh:103
word calcCrc(int idx, int size) const
Convenience method to calculate CRC for part of this track.
Definition: RawTrack.cc:192
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
const byte * getRawBuffer() const
Definition: RawTrack.hh:113
const std::vector< unsigned > & getIdamBuffer() const
Definition: RawTrack.hh:114
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
int wrapIndex(int idx) const
Definition: RawTrack.hh:105
This class calculates CRC numbers for the polygon x^16 + x^12 + x^5 + 1.
Definition: CRC16.hh:37
bool decodeNextSector(unsigned startIdx, Sector &sector) const
Get the next sector (starting from a certain index).
Definition: RawTrack.cc:142
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
byte * getRawBuffer()
Definition: RawTrack.hh:112
void clear(unsigned size)
Clear track data.
Definition: RawTrack.cc:28
void readBlock(int idx, unsigned size, byte *destination) const
Like memcpy() but copy from/to circular buffer.
Definition: RawTrack.cc:166
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
static const unsigned STANDARD_SIZE
Definition: RawTrack.hh:71
std::vector< Sector > decodeAll() const
Get info on all sectors in this track.
Definition: RawTrack.cc:119
void write(int idx, byte val, bool setIdam=false)
Definition: RawTrack.cc:41
RawTrack(unsigned size=STANDARD_SIZE)
Definition: RawTrack.cc:23
constexpr auto size(const C &c) -> decltype(c.size())
Definition: span.hh:62
void writeBlock(int idx, unsigned size, const byte *source)
Definition: RawTrack.cc:172
void serialize(Archive &ar, unsigned version)
Definition: RawTrack.cc:292