]> Shamusworld >> Repos - apple2/blob - src/floppydrive.h
a98415cfa99a386ba0b1080648cdf991a9829f85
[apple2] / src / floppydrive.h
1 //
2 // Apple 2 floppy disk support
3 //
4
5 #ifndef __FLOPPY_H__
6 #define __FLOPPY_H__
7
8 // MAX_PATH isn't defined in stdlib.h on *nix, so we do it here...
9 #ifdef __GCCUNIX__
10 #include <limits.h>
11 #define MAX_PATH        _POSIX_PATH_MAX
12 #else
13 #include <stdlib.h>             // for MAX_PATH on MinGW/Darwin
14 // Kludge for Win64
15 #ifndef MAX_PATH
16 #define MAX_PATH        _MAX_PATH
17 #endif
18 #endif
19
20 #include <stdint.h>
21 #include <stdio.h>
22
23 enum { DT_EMPTY = 0, DT_WOZ, DT_DOS33, DT_DOS33_HDR, DT_PRODOS, DT_NYBBLE,
24         DFT_UNKNOWN };
25 enum { DLS_OFF, DLS_READ, DLS_WRITE };
26
27 // N.B.: All 32/16-bit values are stored in little endian.  Which means, to
28 //       read/write them safely, we need to use translators as this code may or
29 //       may not be compiled on an architecture that supports little endian
30 //       natively.
31
32 struct WOZTrack
33 {
34         uint8_t bits[6646];
35         uint16_t byteCount;
36         uint16_t bitCount;
37         uint16_t splicePoint;
38         uint8_t spliceNibble;
39         uint8_t spliceBitCount;
40         uint16_t reserved;
41 };
42
43 struct WOZMetadata
44 {
45         uint8_t metaTag[4];             // "META"
46         uint32_t metaSize;              // Size of the META chunk
47         uint8_t data[];                 // Variable length array of metadata
48 };
49
50 struct WOZ
51 {
52         // Header
53         uint8_t magic[8];               // "WOZ1" $FF $0A $0D $0A
54         uint32_t crc32;                 // CRC32 of the remaining data in the file
55
56         // INFO chunk
57         uint8_t infoTag[4];             // "INFO"
58         uint32_t infoSize;              // Always 60 bytes long
59         uint8_t infoVersion;    // Currently 1
60         uint8_t diskType;               // 1 = 5 1/4", 2 = 3 1/2"
61         uint8_t writeProtected; // 1 = write protected disk
62         uint8_t synchronized;   // 1 = cross-track sync was used during imaging
63         uint8_t cleaned;                // 1 = fake bits removed from image
64         uint8_t creator[32];    // Software that made this image, padded with 0x20
65         uint8_t pad1[23];               // Padding to 60 bytes
66
67         // TMAP chunk
68         uint8_t tmapTag[4];             // "TMAP"
69         uint32_t tmapSize;              // Always 160 bytes long
70         uint8_t tmap[160];              // Track map, with empty tracks set to $FF
71
72         // TRKS chunk
73         uint8_t trksTag[4];             // "TRKS"
74         uint32_t trksSize;              // Varies, depending on # of tracks imaged
75         WOZTrack track[];               // Variable length array for the track data proper
76 };
77
78 struct WOZTrack2
79 {
80         uint16_t startingBlock; // 512 byte block # where this track starts (relative to the start of the file)
81         uint16_t blockCount;    // # of blocks in this track
82         uint32_t bitCount;              // # of bits in this track
83 };
84
85 struct WOZ2
86 {
87         // Header
88         uint8_t magic[8];               // "WOZ2" $FF $0A $0D $0A
89         uint32_t crc32;                 // CRC32 of the remaining data in the file
90
91         // INFO chunk
92         uint8_t infoTag[4];             // "INFO"
93         uint32_t infoSize;              // Always 60 bytes long
94         uint8_t infoVersion;    // Currently 1
95         uint8_t diskType;               // 1 = 5 1/4", 2 = 3 1/2"
96         uint8_t writeProtected; // 1 = write protected disk
97         uint8_t synchronized;   // 1 = cross-track sync was used during imaging
98         uint8_t cleaned;                // 1 = fake bits removed from image
99         uint8_t creator[32];    // Software that made this image, padded with 0x20
100         uint8_t diskSides;              // 5 1/4" disks always have 1 side (v2 from here on)
101         uint8_t bootSectorFmt;  // 5 1/4" only (0=unknown, 1=16 sector, 2=13 sector, 3=both)
102         uint8_t optimalBitTmg;  // In ticks, standard for 5 1/4" is 32 (4 µs)
103         uint16_t compatibleHW;  // Bitfield showing hardware compatibility (1=][, 2=][+, 4=//e (unenh), 8=//c, 16=//e (enh), 32=IIgs, 64=//c+, 128=///, 256=///+)
104         uint16_t requiredRAM;   // Minimum size in K, 0=unknown
105         uint16_t largestTrack;  // Number of 512 byte blocks used by largest track
106         uint8_t pad1[14];               // Padding to 60 bytes
107
108         // TMAP chunk
109         uint8_t tmapTag[4];             // "TMAP"
110         uint32_t tmapSize;              // Always 160 bytes long
111         uint8_t tmap[160];              // Track map, with empty tracks set to $FF
112
113         // TRKS chunk
114         uint8_t trksTag[4];             // "TRKS"
115         uint32_t trksSize;              // Varies, depending on # of tracks imaged
116         WOZTrack2 track[160];   // Actual track info (corresponding to TMAP data)
117         uint8_t data[];                 // Variable length array for the track data proper
118 };
119
120 class FloppyDrive
121 {
122         public:
123                 FloppyDrive();
124                 ~FloppyDrive();
125
126                 bool LoadImage(const char * filename, uint8_t driveNum = 0);
127                 bool SaveImage(uint8_t driveNum = 0);
128                 bool SaveImageAs(const char * filename, uint8_t driveNum = 0);
129                 void CreateBlankImage(uint8_t driveNum = 0);
130                 void SwapImages(void);
131                 const char * ImageName(uint8_t driveNum = 0);
132                 void EjectImage(uint8_t driveNum = 0);
133                 bool IsEmpty(uint8_t driveNum = 0);
134                 bool IsWriteProtected(uint8_t driveNum = 0);
135                 void SetWriteProtect(bool, uint8_t driveNum = 0);
136                 int DriveLightStatus(uint8_t driveNum = 0);
137                 void SaveState(FILE *);
138                 void LoadState(FILE *);
139                 void InitWOZ(uint8_t driveNum = 0);
140                 bool CheckWOZ(const uint8_t * wozData, uint32_t wozSize, uint8_t driveNum = 0);
141                 bool SaveWOZ(uint8_t driveNum);
142
143         private:
144                 uint32_t ReadLong(FILE *);
145                 void WriteLong(FILE *, uint32_t);
146                 void WriteLongLE(FILE *, uint32_t);
147                 void WriteWordLE(FILE *, uint16_t);
148                 void WriteZeroes(FILE *, uint32_t);
149
150                 // I/O functions ($C0Ex accesses)
151
152         public:
153                 void ControlStepper(uint8_t addr);
154                 void ControlMotor(uint8_t addr);
155                 void DriveEnable(uint8_t addr);
156                 void SetShiftLoadSwitch(uint8_t state);
157                 void SetReadWriteSwitch(uint8_t state);
158                 uint8_t DataRegister(void);
159                 void DataRegister(uint8_t);
160                 void RunSequencer(uint32_t);
161
162         protected:
163                 void DetectImageType(const char * filename, uint8_t driveNum);
164                 void WriteBits(uint8_t * dest, uint8_t * src, uint16_t bits, uint16_t * start);
165                 void WOZifyImage(uint8_t driveNum);
166
167         private:
168                 char imageName[2][MAX_PATH];
169                 uint8_t * disk[2];
170                 uint32_t diskSize[2];
171                 uint8_t diskType[2];
172                 bool imageDirty[2];
173                 uint8_t motorOn;
174                 uint8_t activeDrive;
175                 uint8_t ioMode;
176                 uint8_t dataRegister;
177                 uint8_t phase[2];
178                 uint8_t headPos[2];
179                 bool ioHappened;
180
181                 uint32_t currentPos[2];
182                 WOZ * woz[2];
183
184                 uint8_t cpuDataBus;
185                 uint8_t slSwitch;                       // Shift/Load soft switch
186                 uint8_t rwSwitch;                       // Read/Write soft switch
187                 uint8_t readPulse;                      // Disk read head "pulse" signal
188                 uint8_t pulseClock;                     // Disk read head bitstream "pulse clock"
189                 uint8_t sequencerState;
190                 uint32_t driveOffTimeout;
191                 uint8_t zeroBitCount;
192                 uint16_t trackLength[2];
193
194                 // And here are some private class variables (to reduce function
195                 // redundancy):
196                 static uint8_t doSector[16];
197                 static uint8_t poSector[16];
198                 static uint8_t wozHeader[9];
199                 static uint8_t wozHeader2[9];
200                 static uint8_t standardTMAP[141];
201                 static uint8_t sequencerROM[256];
202                 static uint8_t bitMask[8];
203                 static char nameBuf[MAX_PATH];
204 };
205
206 void InstallFloppy(uint8_t slot);
207 extern FloppyDrive floppyDrive[];
208
209 #endif  // __FLOPPY_H__
210