VirtualC64 v5.0 beta
Commodore 64 Emulator
Loading...
Searching...
No Matches
DiskTypes.h
1// -----------------------------------------------------------------------------
2// This file is part of VirtualC64
3//
4// Copyright (C) Dirk W. Hoffmann. www.dirkwhoffmann.de
5// This FILE is dual-licensed. You are free to choose between:
6//
7// - The GNU General Public License v3 (or any later version)
8// - The Mozilla Public License v2
9//
10// SPDX-License-Identifier: GPL-3.0-or-later OR MPL-2.0
11// -----------------------------------------------------------------------------
12
13#pragma once
14
15#include "Reflection.h"
16#include "Serializable.h"
17#include "DriveTypes.h"
18
19namespace vc64 {
20
21//
22// Constants
23//
24
25/* The VC1541 can move the drive head to 84 distinct positions (1 .. 84). Odd
26 * numbers correspond to "full tracks" and even numbers to "half tracks". The
27 * full tracks between 1 and 70 correspond to the 35 tracks that are used by
28 * VC1541 DOS. The Rom code always moves the drive head by two positions. When
29 * programmed manually, the head can also be moved to even positions or
30 * positions beyond 70 which correspoonds to the innermost full track used by
31 * DOS.
32 *
33 * VirtualC64 provides two data types for specifying head positions: Track
34 * and Halftrack. They are related as follows:
35 *
36 * -----------------------------------------------------------------
37 * Layout: | 1 | 1.5 | 2 | 2.5 | ... | 35 | 35.5 | ... | 42 | 42.5 |
38 * -----------------------------------------------------------------
39 * -----------------------------------------------------------------
40 * Halftrack: | 1 | 2 | 3 | 4 | | 69 | 70 | | 83 | 84 |
41 * Track: | 1 | | 2 | | | 35 | | | 42 | |
42 * -----------------------------------------------------------------
43 */
44
45// Highest track and halftrack number (numbering starts with 1)
46static const isize highestTrack = 42;
47static const isize highestHalftrack = 84;
48
49// Highest sector number (numbering starts with 0)
50static const isize highestSector = 20;
51
52static inline bool isTrackNumber(isize nr) { return 1 <= nr && nr <= highestTrack; }
53static inline bool isHalftrackNumber(isize nr) { return 1 <= nr && nr <= highestHalftrack; }
54static inline bool isSectorNumber(isize nr) { return nr >= 0 && nr <= highestSector; }
55
56/* Maximum number of bits and bytes stored on a single track. Each track can
57 * store a maximum of 7928 bytes (63424 bits). The exact number depends on the
58 * track number (inner tracks contain fewer bytes) and the actual write speed
59 * of a drive.
60 */
61static const isize maxBytesOnTrack = 7928;
62static const isize maxBitsOnTrack = maxBytesOnTrack * 8;
63
64/* Returns the average duration of a single bit in 1/10 nano seconds. The
65 * returned value is the time span the drive head resists over a single bit.
66 * The exact value depends on the speed zone and the disk rotation speed. We
67 * assume a rotation speed of 300 rpm.
68 */
69static const i64 averageBitTimeSpan[] =
70{
71 4 * 10000, // 4 * 16/16 * 10^4 1/10 nsec
72 4 * 9375, // 4 * 15/16 * 10^4 1/10 nsec
73 4 * 8750, // 4 * 14/16 * 10^4 1/10 nsec
74 4 * 8125 // 4 * 13/16 * 10^4 1/10 nsec
75};
76
77/* Average number of bits stored on a single track. The values are based on a
78 * drive with 300 rotations per minute which means that a full rotation lasts
79 * 2.000.000.000 1/10 nsec.
80 */
81static const isize averageBitsOnTrack[4] =
82{
83 50000, // 200.000.000.000 / averageBitTimeSpan[0]
84 53333, // 200.000.000.000 / averageBitTimeSpan[1]
85 57142, // 200.000.000.000 / averageBitTimeSpan[2]
86 61528 // 200.000.000.000 / averageBitTimeSpan[3]
87};
88
89/* Average number of bytes stored on a single track. The values are based on a
90 * drive with 300 rotations per minute.
91 */
92static const isize averageBytesOnTrack[4] =
93{
94 6250, // averageBitsOnTrack[0] / 8
95 6666, // averageBitsOnTrack[1] / 8
96 7142, // averageBitsOnTrack[2] / 8
97 7692 // averageBitsOnTrack[3] / 8
98};
99
100/* Size of a sector header or data block in bits. Each data block consists of
101 * 325 GCR bytes (coding 260 real bytes).
102 */
103static const isize headerBlockSize = 10 * 8;
104static const isize dataBlockSize = 325 * 8;
105
106
107//
108// Enumerations
109//
110
117typedef DISK_TYPE DiskType;
118
119struct DiskTypeEnum : util::Reflection<DiskTypeEnum, DiskType> {
120
121 static constexpr long minVal = 0;
122 static constexpr long maxVal = DISK_TYPE_DS_SD;
123 static bool isValid(auto value) { return value >= minVal && value <= maxVal; }
124
125 static const char *prefix() { return "DISK_TYPE"; }
126 static const char *key(long value)
127 {
128 switch (value) {
129
130 case DISK_TYPE_SS_SD: return "SS_SD";
131 case DISK_TYPE_DS_SD: return "DS_SD";
132 }
133 return "???";
134 }
135};
136
137enum_long(CBM_FILE_TYPE)
138{
139 CBM_FILE_PRG,
140 CBM_FILE_SEQ,
141 CBM_FILE_USR,
142 CBM_FILE_REL
143};
144typedef CBM_FILE_TYPE CBMFileType;
145
146struct CBMFileTypeEnum : util::Reflection<CBMFileTypeEnum, CBMFileType> {
147
148 static constexpr long minVal = 0;
149 static constexpr long maxVal = CBM_FILE_REL;
150 static bool isValid(auto value) { return value >= minVal && value <= maxVal; }
151
152 static const char *prefix() { return "CBM"; }
153 static const char *key(long value)
154 {
155 switch (value) {
156
157 case CBM_FILE_PRG: return "PRG";
158 case CBM_FILE_SEQ: return "SEQ";
159 case CBM_FILE_USR: return "USR";
160 case CBM_FILE_REL: return "REL";
161 }
162 return "???";
163 }
164};
165
166enum_long(DISK_ERROR_CODE)
167{
168 DISK_OK = 0x1,
169 HEADER_BLOCK_NOT_FOUND_ERROR = 0x2,
170 NO_SYNC_SEQUENCE_ERROR = 0x3,
171 DATA_BLOCK_NOT_FOUND_ERROR = 0x4,
172 DATA_BLOCK_CHECKSUM_ERROR = 0x5,
173 WRITE_VERIFY_ERROR_ON_FORMAT_ERROR = 0x6,
174 WRITE_VERIFY_ERROR = 0x7,
175 WRITE_PROTECT_ON_ERROR = 0x8,
176 HEADER_BLOCK_CHECKSUM_ERROR = 0x9,
177 WRITE_ERROR = 0xA,
178 DISK_ID_MISMATCH_ERROR = 0xB,
179 DRIVE_NOT_READY_ERRROR = 0xF
180};
181typedef DISK_ERROR_CODE DiskErrorCode;
182
183struct DiskErrorCodeEnum : util::Reflection<DiskErrorCodeEnum, DiskErrorCode> {
184
185 static constexpr long minVal = 0;
186 static constexpr long maxVal = DRIVE_NOT_READY_ERRROR;
187 static bool isValid(auto value) { return value >= minVal && value <= maxVal; }
188
189 static const char *prefix() { return ""; }
190 static const char *key(long value)
191 {
192 switch (value) {
193
194 case DISK_OK: return "DISK_OK";
195 case HEADER_BLOCK_NOT_FOUND_ERROR: return "HEADER_BLOCK_NOT_FOUND_ERROR";
196 case NO_SYNC_SEQUENCE_ERROR: return "NO_SYNC_SEQUENCE_ERROR";
197 case DATA_BLOCK_NOT_FOUND_ERROR: return "DATA_BLOCK_NOT_FOUND_ERROR";
198 case DATA_BLOCK_CHECKSUM_ERROR: return "DATA_BLOCK_CHECKSUM_ERROR";
199 case WRITE_VERIFY_ERROR_ON_FORMAT_ERROR: return "WRITE_VERIFY_ERROR_ON_FORMAT_ERROR";
200 case WRITE_VERIFY_ERROR: return "WRITE_VERIFY_ERROR";
201 case WRITE_PROTECT_ON_ERROR: return "WRITE_PROTECT_ON_ERROR";
202 case HEADER_BLOCK_CHECKSUM_ERROR: return "HEADER_BLOCK_CHECKSUM_ERROR";
203 case WRITE_ERROR: return "WRITE_ERROR";
204 case DISK_ID_MISMATCH_ERROR: return "DISK_ID_MISMATCH_ERROR";
205 case DRIVE_NOT_READY_ERRROR: return "DRIVE_NOT_READY_ERRROR";
206 }
207 return "???";
208 }
209};
210
211
212//
213// Structures
214//
215
216/* Disk data
217 *
218 * - The first valid track and halftrack number is 1
219 * - data.halftack[i] points to the first byte of halftrack i
220 * - data.track[i] points to the first byte of track i
221 */
222struct DiskData : public Serializable
223{
224 union {
225
226 struct
227 {
228 u8 _pad[maxBytesOnTrack];
229 u8 halftrack[85][maxBytesOnTrack];
230 };
231
232 u8 track[43][2 * maxBytesOnTrack];
233 };
234
235 template <class W>
236 void serialize(W& worker)
237 {
238 worker
239
240 << track;
241
242 } SERIALIZERS(serialize);
243
244};
245
246/* Length of each halftrack in bits
247 *
248 * - length.halftack[i] is the length of halftrack i
249 * - length.track[i][0] is the length of track i
250 * - length.track[i][1] is the length of halftrack above track i
251 */
252
253struct DiskLength : public Serializable
254{
255 union {
256
257 struct
258 {
259 isize _pad;
260 isize halftrack[85];
261 };
262
263 isize track[43][2];
264 };
265
266 template <class W>
267 void serialize(W& worker)
268 {
269 worker
270
271 << track;
272
273 } SERIALIZERS(serialize);
274};
275
276// Disk parameters of a standard floppy disk
277typedef struct
278{
279 u8 sectors; // Typical number of sectors in this track
280 u8 speedZone; // Default speed zone for this track
281 u16 lengthInBytes; // Typical track size in bits
282 u16 lengthInBits; // Typical track size in bits
283 Sector firstSectorNr; // Logical number of first sector in track
284 double stagger; // Relative position of first bit (from Hoxs64)
285}
286TrackDefaults;
287
288}
VirtualC64 project namespace.
Definition CmdQueue.cpp:16
DISK_TYPE
Disk type.
Definition DiskTypes.h:113
@ DISK_TYPE_SS_SD
Single-sided, single density (VC1541)
Definition DiskTypes.h:114
@ DISK_TYPE_DS_SD
Double-sided, single density (VC1571) (unsupported)
Definition DiskTypes.h:115