1 // license:BSD-3-Clause
2 // copyright-holders:Nathan Woods
3 /*********************************************************************
4
5 formats/basicdsk.c
6
7 Floppy format code for basic disks
8
9 *********************************************************************/
10
11 #include <cstdlib>
12 #include <cstring>
13 #include <cassert>
14
15 #include "basicdsk.h"
16
17 static floperr_t basicdsk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen);
18 static floperr_t basicdsk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
19 static floperr_t basicdsk_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen);
20 static floperr_t basicdsk_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
21 static floperr_t basicdsk_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length);
22 static floperr_t basicdsk_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, uint32_t *sector_length, unsigned long *flags);
23 static int basicdsk_get_heads_per_disk(floppy_image_legacy *floppy);
24 static int basicdsk_get_tracks_per_disk(floppy_image_legacy *floppy);
25 static floperr_t basicdsk_format_track(floppy_image_legacy *floppy, int head, int track, util::option_resolution *params);
26
27
28
29 #define BASICDSK_TAG "basicdsktag"
30
31 struct basicdsk_tag
32 {
33 struct basicdsk_geometry geometry;
34 };
35
36
37
38 /********************************************************************/
39
get_geometry(floppy_image_legacy * floppy)40 static const struct basicdsk_geometry *get_geometry(floppy_image_legacy *floppy)
41 {
42 const struct basicdsk_tag *tag;
43 tag = (const basicdsk_tag *)floppy_tag(floppy);
44 return &tag->geometry;
45 }
46
47
48
basicdsk_construct(floppy_image_legacy * floppy,const struct basicdsk_geometry * geometry)49 floperr_t basicdsk_construct(floppy_image_legacy *floppy, const struct basicdsk_geometry *geometry)
50 {
51 struct basicdsk_tag *tag;
52 struct FloppyCallbacks *format;
53
54 assert(geometry->heads);
55 assert(geometry->tracks);
56 assert(geometry->sectors);
57
58 tag = (struct basicdsk_tag *) floppy_create_tag(floppy, sizeof(struct basicdsk_tag));
59 if (!tag)
60 return FLOPPY_ERROR_OUTOFMEMORY;
61 tag->geometry = *geometry;
62
63 /* set up format callbacks */
64 format = floppy_callbacks(floppy);
65 format->read_sector = basicdsk_read_sector;
66 format->write_sector = basicdsk_write_sector;
67 format->read_indexed_sector = basicdsk_read_indexed_sector;
68 format->write_indexed_sector = basicdsk_write_indexed_sector;
69 format->get_sector_length = basicdsk_get_sector_length;
70 format->get_heads_per_disk = basicdsk_get_heads_per_disk;
71 format->get_tracks_per_disk = basicdsk_get_tracks_per_disk;
72 format->get_indexed_sector_info = basicdsk_get_indexed_sector_info;
73 format->format_track = basicdsk_format_track;
74
75 return FLOPPY_ERROR_SUCCESS;
76 }
77
78
79
get_offset(floppy_image_legacy * floppy,int head,int track,int sector,bool sector_is_index,uint64_t * offset)80 static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, uint64_t *offset)
81 {
82 const struct basicdsk_geometry *geom;
83 uint64_t offs;
84
85 geom = get_geometry(floppy);
86
87 /* translate the sector to a raw sector */
88 if (!sector_is_index)
89 {
90 sector -= geom->first_sector_id;
91 }
92
93 if (geom->translate_sector)
94 sector = geom->translate_sector(floppy, sector);
95
96 /* check to see if we are out of range */
97 if ((head < 0) || (head >= geom->heads) || (track < 0) || (track >= geom->tracks)
98 || (sector < 0) || (sector >= geom->sectors))
99 return FLOPPY_ERROR_SEEKERROR;
100
101 if (geom->translate_offset)
102 offs = geom->translate_offset(floppy, geom, track, head, sector);
103 else
104 {
105 offs = 0;
106 offs += track;
107 offs *= geom->heads;
108 offs += head;
109 offs *= geom->sectors;
110 offs += sector;
111 }
112 offs *= geom->sector_length;
113 offs += geom->offset;
114
115 if (offset)
116 *offset = offs;
117 return FLOPPY_ERROR_SUCCESS;
118 }
119
120
121
internal_basicdsk_translate_sector_interleave(floppy_image_legacy * floppy,int sector)122 static int internal_basicdsk_translate_sector_interleave(floppy_image_legacy *floppy, int sector)
123 {
124 const struct basicdsk_geometry *geom = get_geometry(floppy);
125 if (sector >= geom->sectors)
126 return sector;
127 return geom->sector_map[sector];
128 }
129
130
131
internal_basicdsk_read_sector(floppy_image_legacy * floppy,int head,int track,int sector,bool sector_is_index,void * buffer,size_t buflen)132 static floperr_t internal_basicdsk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, void *buffer, size_t buflen)
133 {
134 uint64_t offset;
135 floperr_t err;
136
137 err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
138 if (err)
139 return err;
140 floppy_image_read(floppy, buffer, offset, buflen);
141 return FLOPPY_ERROR_SUCCESS;
142 }
143
144
145
internal_basicdsk_write_sector(floppy_image_legacy * floppy,int head,int track,int sector,bool sector_is_index,const void * buffer,size_t buflen,int ddam)146 static floperr_t internal_basicdsk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, const void *buffer, size_t buflen, int ddam)
147 {
148 uint64_t offset;
149 floperr_t err;
150
151 err = get_offset(floppy, head, track, sector, sector_is_index, &offset);
152 if (err)
153 return err;
154
155 floppy_image_write(floppy, buffer, offset, buflen);
156 return FLOPPY_ERROR_SUCCESS;
157 }
158
159
160
basicdsk_read_sector(floppy_image_legacy * floppy,int head,int track,int sector,void * buffer,size_t buflen)161 static floperr_t basicdsk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
162 {
163 return internal_basicdsk_read_sector(floppy, head, track, sector, false, buffer, buflen);
164 }
165
basicdsk_write_sector(floppy_image_legacy * floppy,int head,int track,int sector,const void * buffer,size_t buflen,int ddam)166 static floperr_t basicdsk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
167 {
168 return internal_basicdsk_write_sector(floppy, head, track, sector, false, buffer, buflen, ddam);
169 }
170
basicdsk_read_indexed_sector(floppy_image_legacy * floppy,int head,int track,int sector,void * buffer,size_t buflen)171 static floperr_t basicdsk_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen)
172 {
173 return internal_basicdsk_read_sector(floppy, head, track, sector, true, buffer, buflen);
174 }
175
basicdsk_write_indexed_sector(floppy_image_legacy * floppy,int head,int track,int sector,const void * buffer,size_t buflen,int ddam)176 static floperr_t basicdsk_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
177 {
178 return internal_basicdsk_write_sector(floppy, head, track, sector, true, buffer, buflen, ddam);
179 }
180
181
182
basicdsk_format_track(floppy_image_legacy * floppy,int head,int track,util::option_resolution * params)183 static floperr_t basicdsk_format_track(floppy_image_legacy *floppy, int head, int track, util::option_resolution *params)
184 {
185 floperr_t err = FLOPPY_ERROR_SUCCESS;
186 uint8_t local_buffer[512];
187 void *alloc_buffer = nullptr;
188 void *buffer;
189 uint32_t sector_length;
190 int sector;
191 const struct basicdsk_geometry *geometry;
192
193 geometry = get_geometry(floppy);
194
195 sector_length = geometry->sector_length;
196
197 if (sector_length > sizeof(local_buffer))
198 {
199 alloc_buffer = malloc(sector_length);
200 if (!alloc_buffer)
201 {
202 err = FLOPPY_ERROR_OUTOFMEMORY;
203 goto done;
204 }
205 buffer = alloc_buffer;
206 }
207 else
208 {
209 alloc_buffer = nullptr;
210 buffer = local_buffer;
211 }
212
213 memset(buffer, floppy_get_filler(floppy), sector_length);
214
215 for (sector = 0; sector < geometry->sectors; sector++)
216 {
217 err = basicdsk_write_sector(floppy, head, track, sector + geometry->first_sector_id, buffer, sector_length, 0);
218 if (err)
219 goto done;
220 }
221
222 done:
223 if (alloc_buffer)
224 free(alloc_buffer);
225 return err;
226 }
227
228
229
basicdsk_get_heads_per_disk(floppy_image_legacy * floppy)230 static int basicdsk_get_heads_per_disk(floppy_image_legacy *floppy)
231 {
232 return get_geometry(floppy)->heads;
233 }
234
235
236
basicdsk_get_tracks_per_disk(floppy_image_legacy * floppy)237 static int basicdsk_get_tracks_per_disk(floppy_image_legacy *floppy)
238 {
239 return get_geometry(floppy)->tracks;
240 }
241
242
243
basicdsk_get_sector_length(floppy_image_legacy * floppy,int head,int track,int sector,uint32_t * sector_length)244 static floperr_t basicdsk_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, uint32_t *sector_length)
245 {
246 floperr_t err;
247
248 err = get_offset(floppy, head, track, sector, false, nullptr);
249 if (err)
250 return err;
251
252 if (sector_length)
253 *sector_length = get_geometry(floppy)->sector_length;
254 return FLOPPY_ERROR_SUCCESS;
255 }
256
257
258
basicdsk_get_indexed_sector_info(floppy_image_legacy * floppy,int head,int track,int sector_index,int * cylinder,int * side,int * sector,uint32_t * sector_length,unsigned long * flags)259 static floperr_t basicdsk_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, uint32_t *sector_length, unsigned long *flags)
260 {
261 const struct basicdsk_geometry *geom = get_geometry(floppy);
262
263 if (geom->translate_sector)
264 sector_index = geom->translate_sector(floppy, sector_index);
265
266 sector_index += geom->first_sector_id;
267
268 if (cylinder)
269 *cylinder = track;
270 if (side)
271 *side = head;
272 if (sector)
273 *sector = sector_index;
274 if (flags) {
275 /* TODO: read DAM or DDAM and determine flags */
276 *flags = 0;
277 if (geom->get_ddam)
278 *flags = geom->get_ddam(floppy, geom, track, head, sector_index);
279 }
280 return basicdsk_get_sector_length(floppy, head, track, sector_index, sector_length);
281 }
282
283
284
285 /********************************************************************
286 * Generic Basicdsk Constructors
287 ********************************************************************/
288
basicdsk_default_geometry(const struct FloppyFormat * format,struct basicdsk_geometry * geometry)289 static void basicdsk_default_geometry(const struct FloppyFormat *format, struct basicdsk_geometry *geometry)
290 {
291 int sector_length;
292 memset(geometry, 0, sizeof(*geometry));
293
294 auto err = util::option_resolution::get_default(format->param_guidelines, PARAM_HEADS, &geometry->heads);
295 assert(err == util::option_resolution::error::SUCCESS);
296 err = util::option_resolution::get_default(format->param_guidelines, PARAM_TRACKS, &geometry->tracks);
297 assert(err == util::option_resolution::error::SUCCESS);
298 err = util::option_resolution::get_default(format->param_guidelines, PARAM_SECTORS, &geometry->sectors);
299 assert(err == util::option_resolution::error::SUCCESS);
300 err = util::option_resolution::get_default(format->param_guidelines, PARAM_FIRST_SECTOR_ID, &geometry->first_sector_id);
301 assert(err == util::option_resolution::error::SUCCESS);
302 err = util::option_resolution::get_default(format->param_guidelines, PARAM_INTERLEAVE, &geometry->interleave);
303 if (err != util::option_resolution::error::SUCCESS) {
304 geometry->interleave = 1;
305 }
306 err = util::option_resolution::get_default(format->param_guidelines, PARAM_SECTOR_LENGTH, §or_length);
307 assert(err == util::option_resolution::error::SUCCESS);
308 geometry->sector_length = sector_length;
309
310 if (geometry->interleave > 1)
311 {
312 int sector = 0;
313
314 for (int i = 0; i < geometry->sectors; i++)
315 {
316 geometry->sector_map[i] = sector;
317
318 sector += geometry->interleave;
319
320 if (sector >= geometry->sectors)
321 sector -= geometry->sectors;
322 }
323
324 geometry->translate_sector = internal_basicdsk_translate_sector_interleave;
325 }
326 }
327
328
329
FLOPPY_CONSTRUCT(basicdsk_construct_default)330 FLOPPY_CONSTRUCT(basicdsk_construct_default)
331 {
332 struct basicdsk_geometry geometry;
333 basicdsk_default_geometry(format, &geometry);
334 return basicdsk_construct(floppy, &geometry);
335 }
336
337
338
FLOPPY_IDENTIFY(basicdsk_identify_default)339 FLOPPY_IDENTIFY(basicdsk_identify_default)
340 {
341 uint64_t expected_size;
342 struct basicdsk_geometry geometry;
343
344 basicdsk_default_geometry(format, &geometry);
345
346 expected_size = geometry.sector_length;
347 expected_size *= geometry.heads;
348 expected_size *= geometry.tracks;
349 expected_size *= geometry.sectors;
350 *vote = (floppy_image_size(floppy) == expected_size) ? 100 : 50;
351 return FLOPPY_ERROR_SUCCESS;
352 }
353