1
/*********************************************************************
5
Tandy Color Computer / Dragon disk images
7
*********************************************************************/
13
#include "formats/coco_dsk.h"
14
#include "formats/basicdsk.h"
17
/* -----------------------------------------------------------------------
18
* JVC (Jeff Vavasour CoCo) format
20
* Used by Jeff Vavasour's CoCo Emulators
22
* Documentation taken from Tim Linder's web site:
23
* http://home.netcom.com/~tlindner/JVC.html
26
* The header length is determined by the file length modulo 256:
27
* headerSize = fileLength % 256;
28
* This means that the header is variable length and the minimum size
29
* is zero bytes, and the maximum size of 255 bytes.
32
* Here is a description of the header bytes:
33
* Byte Offset Description Default
34
* ----------- ----------------- -------
35
* 0 Sectors per track 18
37
* 2 Sector size code 1
39
* 4 Sector attribute flag 0
41
* If the sector attribute flag is zero then the track count is determined
44
* (fileLength - headerSize) / (sectorsPerTrack * (128 <<
45
* sectorSizeCode)) / sideCount
47
* If the sector attribute flag is non zero then the track count is
48
* determined by the more complex formula:
50
* (fileLength - headerSize) / (sectorsPerTrack * ((128 <<
51
* sectorSizeCode) + 1) ) / sideCount
53
* If the length of the header is to short to contain the geometry desired,
54
* then the default values are assumed. If the header length is zero the all
55
* of the geometry is assumed. When creating disk images it is desirable to
56
* make the header length as short as possible. The header should only be
57
* used to deviate from the default values.
59
* The sector data begins immediately after the header. If the header length
60
* is zero then the sector data is at the beginning file.
62
* C. Sectors per track
63
* This is the number of sectors per track (ones based). A value of 18
64
* means there are 18 sectors per track
67
* This is the number of sides in the disk image. Values of 1 or 2 are
68
* acceptable. If there are two sides then the tracks are interleaved.
69
* The first track in the image file is track zero side 1, the second
70
* track in the image file is track zero side 2.
73
* The is the same value that is stored in the wd179x ID field to
74
* determine sector size:
81
* Other values are undefined. Every sector in the disk image must be the
85
* This determines the first sector ID for each track. Each successive
86
* sector adds one to the previous ID. If the first sector ID is 1, then
87
* the second sector has an ID of 2, and the third has an ID of 3.
89
* G. Sector Attribute Flag
90
* If this byte is non zero, then each sector contains an additional
91
* byte prepended to the sector data. If the attribute flag is zero then
92
* there are no extra bytes in front of the sector data.
94
* H. Sector attribute byte
95
* This byte is put at the begining of every sector if the header flag
96
* is turned on. The information this byte contains is the same as the
97
* status register (of the wd179x) would contain when a 'Read Sector'
98
* command was issued. The bit fields are defined as:
104
* | | | | | | | +--- Not used. Set to zero.
105
* | | | | | | +----- Not used. Set to zero.
106
* | | | | | +------- Not used. Set to zero.
107
* | | | | +--------- Set on CRC error.
108
* | | | +----------- Set if sector not found.
109
* | | +------------- Record type: 1 - Deleted Data Mark, 0 - Data Mark.
110
* | +--------------- Not Used. Set to zero.
111
* +----------------- Not Used. Set to zero.
113
* ----------------------------------------------------------------------- */
115
static int coco_jvc_decode_header(floppy_image *floppy, UINT64 size,
116
struct basicdsk_geometry *geometry)
119
UINT8 sector_attribute_flag;
120
UINT16 physical_bytes_per_sector;
121
UINT32 header_size, file_size;
122
struct basicdsk_geometry dummy_geometry;
125
memset(geometry, 0, sizeof(*geometry));
127
geometry = &dummy_geometry;
129
if (size > 0xFFFFFFFF)
131
file_size = (UINT32) size;
133
/* read the header */
134
header_size = (UINT32) file_size % 0x100;
135
floppy_image_read(floppy, header, 0, header_size);
136
geometry->offset = header_size;
138
/* byte offset 0 - sectors per track */
139
geometry->sectors = (header_size > 0) ? header[0] : 18;
140
if (geometry->sectors <= 0)
143
/* byte offset 1 - side count */
144
geometry->heads = (header_size > 1) ? header[1] : 1;
145
if (geometry->heads <= 0)
148
/* byte offset 2 - sector size code */
149
geometry->sector_length = 128 << ((header_size > 2) ? header[2] : 1);
150
if (geometry->sector_length <= 0)
153
/* byte offset 3 - first sector ID */
154
geometry->first_sector_id = (header_size > 3) ? header[3] : 1;
156
/* byte offset 4 - sector attribute flag */
157
sector_attribute_flag = (header_size > 4) ? header[4] : 0;
158
if (sector_attribute_flag != 0)
159
return -1; /* we do not support sector attribute flags */
161
physical_bytes_per_sector = geometry->sector_length;
162
if (sector_attribute_flag)
163
physical_bytes_per_sector++;
165
geometry->tracks = (file_size - header_size) / geometry->sectors / geometry->heads / physical_bytes_per_sector;
167
/* do we have an oddball size? reject this file if not */
168
if ((file_size - header_size) % physical_bytes_per_sector)
171
/* minimum of 35 tracks; support degenerate JVC files */
172
if (geometry->tracks < 35)
173
geometry->tracks = 35;
180
static FLOPPY_IDENTIFY(coco_jvc_identify)
183
size = floppy_image_size(floppy);
184
*vote = coco_jvc_decode_header(floppy, size, NULL) ? 0 : 100;
185
return FLOPPY_ERROR_SUCCESS;
190
static FLOPPY_CONSTRUCT(coco_jvc_construct)
192
struct basicdsk_geometry geometry;
199
memset(&geometry, 0, sizeof(geometry));
200
geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS);
201
geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS);
202
geometry.sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
203
geometry.first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID);
204
geometry.sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
206
header[0] = (UINT8) geometry.sectors;
207
header[1] = (UINT8) geometry.heads;
208
header[2] = (UINT8) compute_log2(geometry.sector_length) - 7;
209
header[3] = (UINT8) geometry.first_sector_id;
212
/* now that we have the header computed, figure out the header size */
225
geometry.offset = header_size;
227
floppy_image_write(floppy, header, 0, header_size);
232
if (coco_jvc_decode_header(floppy, floppy_image_size(floppy), &geometry))
233
return FLOPPY_ERROR_INVALIDIMAGE;
235
return basicdsk_construct(floppy, &geometry);
239
/* -----------------------------------------------------------------------
242
* This file format is largely a hack because there are a large amount of
243
* disk images that do not have geometry image separate from the disk image
244
* itself. So we support OS-9 images with are simply basic disks whose
245
* geometry is determined by the disk image.
247
* OS-9 images identified by an LSN; which are simply blocks of 256 bytes
251
* $00 3 sectors on disk
252
* $03 1 track size in sectors
253
* $04 2 bytes in allocation bit map; typically 1bit/sector so for
254
* 35 tracks of 18 sectors each that's $4E (single sided disk)
255
* 40 tracks per side, 18 sectors each = $B4
256
* $06 2 sectors per bit in allocation map; normally 1
257
* $08 3 LSN of root directory; normally 2 but depends on size of
259
* $0B 2 owner's user number; normally 0
260
* $0D 1 disk attributes; normally $FF
261
* $0E 2 psuedo random number for identification
262
* $10 1 disk format; typical is 3
263
* %00000001 0=single side 1=double side
264
* %00000010 0=single density (non Coco) 1=double density
265
* %00000100 0=48tracks/inch 1=96tracks/inch
266
* $11 2 sectors per track; normal is $12 skip several not needed
268
* $1A 5 date of creation Y:M:D:H:M
269
* $1F 32 ASCII name of disk, last letter has $80 added to it,
270
* the full 32 bytes do not need to be used.
272
* Allocation bit map, fill with zeros and set bits from low to high as
273
* sectors are used. So, for a fresh disk sectors LSN0,LSN1,LSN2, and LSN3
274
* will be in use so the first byte will be $FF $C0 and all others
277
* Root directory LSN2
279
* $00 1 attributes will be $BF
280
* $01 2 owners ID will be $0000
281
* $03 5 date last modified will be creation date Y:M:D:H:M
282
* $08 1 link count; set to $02
283
* $09 4 file size in bytes, set to $40
284
* $0D 3 date created Y:M:D
285
* $10 3 block LSN set to current sector number+1 ie $03 in this case
286
* $13 2 size in sectors of directory block, set to $07
287
* All other bytes in sector set to $00
288
* LSN3 first sector of directory with names
289
* Fill sector with all $00 and then set listed bytes
290
* $00 2 value $2EAE which is .. with last byte+$80
291
* $1F 1 value $02 LSN for start of this directory as there is
292
* none higher in tree
293
* $20 1 value $AE which is . with $80 added
294
* $3F 1 value $02 LSN for start of this directory
295
* ----------------------------------------------------------------------- */
297
static floperr_t coco_os9_readheader(floppy_image *floppy, struct basicdsk_geometry *geometry)
302
floppy_image_read(floppy, header, 0, sizeof(header));
304
total_sectors = (header[0x00] << 16) | (header[0x01] << 8) | header[0x02];
306
memset(geometry, 0, sizeof(*geometry));
307
geometry->first_sector_id = 1;
308
geometry->sector_length = 256;
309
geometry->sectors = (header[0x11] << 8) + header[0x12];
310
geometry->heads = (header[0x10] & 0x01) ? 2 : 1;
312
if (!geometry->sectors)
313
return FLOPPY_ERROR_INVALIDIMAGE;
315
geometry->tracks = total_sectors / geometry->sectors / geometry->heads;
317
if (total_sectors != geometry->tracks * geometry->sectors * geometry->heads)
318
return FLOPPY_ERROR_INVALIDIMAGE;
320
return FLOPPY_ERROR_SUCCESS;
325
static floperr_t coco_os9_post_format(floppy_image *floppy, option_resolution *params)
327
UINT8 header[0x0400];
331
int heads, tracks, sectors, total_sectors;
333
heads = option_resolution_lookup_int(params, PARAM_HEADS);
334
tracks = option_resolution_lookup_int(params, PARAM_TRACKS);
335
sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
336
total_sectors = heads * tracks * sectors;
338
/* write the initial header */
340
ltime = localtime(&t);
342
memset(&header, 0, sizeof(header));
343
header[0x0000] = (UINT8) (total_sectors >> 16);
344
header[0x0001] = (UINT8) (total_sectors >> 8);
345
header[0x0002] = (UINT8) (total_sectors >> 0);
346
header[0x0003] = (UINT8) sectors;
347
header[0x0004] = (UINT8) (((total_sectors + 7) / 8) >> 8);
348
header[0x0005] = (UINT8) (((total_sectors + 7) / 8) >> 0);
349
header[0x0006] = 0x00;
350
header[0x0007] = 0x01;
351
header[0x0008] = 0x00;
352
header[0x0009] = 0x00;
353
header[0x000a] = 0x02;
354
header[0x000b] = 0x00;
355
header[0x000c] = 0x00;
356
header[0x000d] = 0xff;
357
header[0x000e] = floppy_random_byte(floppy);
358
header[0x000f] = floppy_random_byte(floppy);
359
header[0x0010] = (heads == 2) ? 3 : 2;
360
header[0x0011] = (UINT8) (sectors >> 8);
361
header[0x0012] = (UINT8) (sectors >> 0);
362
header[0x001A] = (UINT8) ltime->tm_year;
363
header[0x001B] = (UINT8) ltime->tm_mon + 1;
364
header[0x001C] = (UINT8) ltime->tm_mday;
365
header[0x001D] = (UINT8) ltime->tm_hour;
366
header[0x001E] = (UINT8) ltime->tm_min;
367
header[0x001F] = 0xA0;
368
header[0x0100] = 0xFF;
369
header[0x0101] = 0xC0;
370
header[0x0200] = 0xBF;
371
header[0x0201] = 0x00;
372
header[0x0202] = 0x00;
373
header[0x0203] = (UINT8) ltime->tm_year;
374
header[0x0204] = (UINT8) ltime->tm_mon + 1;
375
header[0x0205] = (UINT8) ltime->tm_mday;
376
header[0x0206] = (UINT8) ltime->tm_hour;
377
header[0x0207] = (UINT8) ltime->tm_min;
378
header[0x0208] = 0x02;
379
header[0x0209] = 0x00;
380
header[0x020A] = 0x00;
381
header[0x020B] = 0x00;
382
header[0x020C] = 0x40;
383
header[0x020D] = (UINT8) (ltime->tm_year % 100);
384
header[0x020E] = (UINT8) ltime->tm_mon;
385
header[0x020F] = (UINT8) ltime->tm_mday;
386
header[0x0210] = 0x00;
387
header[0x0211] = 0x00;
388
header[0x0212] = 0x03;
389
header[0x0213] = 0x00;
390
header[0x0214] = 0x07;
391
header[0x0300] = 0x2E;
392
header[0x0301] = 0xAE;
393
header[0x031F] = 0x02;
394
header[0x0320] = 0xAE;
395
header[0x033F] = 0x02;
397
if (total_sectors % 8)
398
header[0x0100 + (total_sectors / 8)] = 0xFF >> (total_sectors % 8);
400
err = floppy_write_sector(floppy, 0, 0, 1, 0, &header[0x0000], 256, 0);
404
err = floppy_write_sector(floppy, 0, 0, 2, 0, &header[0x0100], 256, 0);
408
err = floppy_write_sector(floppy, 0, 0, 3, 0, &header[0x0200], 256, 0);
412
err = floppy_write_sector(floppy, 0, 0, 4, 0, &header[0x0300], 256, 0);
416
return FLOPPY_ERROR_SUCCESS;
421
static FLOPPY_IDENTIFY(coco_os9_identify)
423
struct basicdsk_geometry geometry;
424
*vote = coco_os9_readheader(floppy, &geometry) ? 0 : 100;
425
return FLOPPY_ERROR_SUCCESS;
430
static FLOPPY_CONSTRUCT(coco_os9_construct)
433
struct basicdsk_geometry geometry;
438
memset(&geometry, 0, sizeof(geometry));
439
geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS);
440
geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS);
441
geometry.sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
442
geometry.first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID);
443
geometry.sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
448
err = coco_os9_readheader(floppy, &geometry);
453
/* actually construct the image */
454
err = basicdsk_construct(floppy, &geometry);
455
floppy_callbacks(floppy)->post_format = coco_os9_post_format;
461
/* -----------------------------------------------------------------------
464
* Used by Paul Burgin's PC-Dragon emulator
466
* Offset Bytes Field Description
467
* ------ ----- ------------ -----------
468
* 0 1 magic1 Signature byte 1 ('d')
469
* 1 1 magic2 Signature byte 2 ('k')
470
* 2 2 header_len Total header length (little endian)
471
* 4 1 ver_actual Version of the VDK format (0x10)
472
* 5 1 ver_compat Backwards compatibility version (0x10)
473
* 6 1 source_id Identify of the file source
474
* 7 1 source_ver Version of the file source
475
* 8 1 tracks Number of tracks
476
* 9 1 sides Number of sides (1-2)
477
* 10 1 flags Various flags
478
* bit 0: Write protect
482
* 11 1 compression Compression flags (bits 0-2) and name length
483
* ----------------------------------------------------------------------- */
487
static int coco_vdk_decode_header(floppy_image *floppy, struct basicdsk_geometry *geometry)
490
int heads, tracks, sectors, sector_length, offset;
493
size = floppy_image_size(floppy);
495
floppy_image_read(floppy, header, 0, sizeof(header));
497
if (header[0] != 'd')
499
if (header[1] != 'k')
501
if (header[5] != 0x10)
503
if (header[11] & 0x07)
509
sector_length = 0x100;
511
offset = ((int) header[3]) * 0x100 + header[2];
513
if (size != (heads * tracks * sectors * sector_length + offset))
518
memset(geometry, 0, sizeof(*geometry));
519
geometry->heads = heads;
520
geometry->tracks = tracks;
521
geometry->sectors = sectors;
522
geometry->first_sector_id = 1;
523
geometry->sector_length = sector_length;
524
geometry->offset = offset;
531
static FLOPPY_IDENTIFY(coco_vdk_identify)
533
*vote = coco_vdk_decode_header(floppy, NULL) ? 0 : 100;
534
return FLOPPY_ERROR_SUCCESS;
539
static FLOPPY_CONSTRUCT(coco_vdk_construct)
541
struct basicdsk_geometry geometry;
547
memset(&geometry, 0, sizeof(geometry));
548
geometry.heads = option_resolution_lookup_int(params, PARAM_HEADS);
549
geometry.tracks = option_resolution_lookup_int(params, PARAM_TRACKS);
550
geometry.sectors = 18;
551
geometry.first_sector_id = 1;
552
geometry.sector_length = 256;
553
geometry.offset = sizeof(header);
555
memset(&header, 0, sizeof(header));
558
header[2] = (UINT8) (sizeof(header) >> 0);
559
header[3] = (UINT8) (sizeof(header) >> 8);
562
header[8] = (UINT8) geometry.tracks;
563
header[9] = (UINT8) geometry.heads;
565
floppy_image_write(floppy, header, 0, sizeof(header));
570
if (coco_vdk_decode_header(floppy, &geometry))
571
return FLOPPY_ERROR_INVALIDIMAGE;
573
return basicdsk_construct(floppy, &geometry);
578
/* -----------------------------------------------------------------------
581
* David M. Keil's disk image format is aptly called an 'on disk' image
582
* format. This means that whatever written to the disk is enocded into
583
* the image file. IDAMS, sector headers, traling CRCs, and intra sector
586
* HEADER DESCRIPTION:
588
* Offset Bytes Field Description
589
* ------ ----- ------------ -----------
590
* 0 1 write_prot 0xff = Writed Protected, 0x00 = R/W
591
* 1 1 tracks Number of tracks
592
* 2 2 track_length Bytes per track (little endian)
593
* 4 1 disk_options Miscellaneous flags
595
* bit 4: 1=single sided 0=dbl
597
* bit 6: Single density?
598
* bit 6: Ignore density flags?
599
* 5 7 reserved Reserved for future use
600
* 12 4 real_disk_code If this is 0x12345678 (little endian)
601
* then access a real disk drive
604
* Each track begins with a track TOC, consisting of 64 little endian 16-bit
605
* integers. Each integer has the following format:
606
* bit 0-13: Offset from begining of track to 'FE' byte of IDAM
607
* Note these are always sorted from first to last. All empty
609
* bit 14: Undefined (reserved)
610
* bit 15: Sector double density (0=SD 1=DD)
611
* ----------------------------------------------------------------------- */
620
#define DMK_HEADER_LEN 16
621
#define DMK_TOC_LEN 64
622
#define DMK_IDAM_LENGTH 7
623
#define DMK_DATA_GAP 80
624
#define DMK_LEAD_IN 32
625
#define DMK_EXTRA_TRACK_LENGTH 156
627
#define dmk_idam_type(x) (x)[0]
628
#define dmk_idam_track(x) (x)[1]
629
#define dmk_idam_side(x) (x)[2]
630
#define dmk_idam_sector(x) (x)[3]
631
#define dmk_idam_sectorlength(x) (x)[4]
632
#define dmk_idam_crc(x) (((x)[5] << 8) + (x)[6])
633
#define dmk_idam_set_crc(x, crc) (x)[5] = ((crc) >> 8); (x)[6] = ((crc) >> 0);
636
static struct dmk_tag *get_dmk_tag(floppy_image *floppy)
638
return (dmk_tag *)floppy_tag(floppy);
642
static floperr_t coco_dmk_get_offset(floppy_image *floppy, int head, int track, UINT64 *offset)
644
struct dmk_tag *tag = get_dmk_tag(floppy);
646
if ((head < 0) || (head >= tag->heads) || (track < 0) || (track >= tag->tracks))
647
return FLOPPY_ERROR_SEEKERROR;
650
*offset *= tag->heads;
652
*offset *= tag->track_size;
653
*offset += DMK_HEADER_LEN;
654
return FLOPPY_ERROR_SUCCESS;
659
static UINT32 coco_dmk_min_track_size(int sectors, int sector_length)
661
int sector_physical_length;
662
sector_physical_length = 8 + 3 + DMK_IDAM_LENGTH + 22 + 12 + 3 + 1 + sector_length + 2 + 24;
663
return DMK_TOC_LEN * 2 + DMK_LEAD_IN + (sectors * sector_physical_length);
668
static floperr_t coco_dmk_read_track(floppy_image *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen)
673
err = coco_dmk_get_offset(floppy, head, track, &track_offset);
677
floppy_image_read(floppy, buffer, offset + track_offset, buflen);
678
return FLOPPY_ERROR_SUCCESS;
683
static floperr_t coco_dmk_write_track(floppy_image *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen)
688
err = coco_dmk_get_offset(floppy, head, track, &track_offset);
692
floppy_image_write(floppy, buffer, offset + track_offset, buflen);
693
return FLOPPY_ERROR_SUCCESS;
698
static floperr_t coco_dmk_get_track_data_offset(floppy_image *floppy, int head, int track, UINT64 *offset)
700
*offset = DMK_TOC_LEN + 1;
701
return FLOPPY_ERROR_SUCCESS;
706
static floperr_t coco_dmk_format_track(floppy_image *floppy, int head, int track, option_resolution *params)
720
UINT32 max_track_size;
721
int *sector_map = NULL;
723
sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
724
sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
725
interleave = option_resolution_lookup_int(params, PARAM_INTERLEAVE);
726
first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID);
728
max_track_size = get_dmk_tag(floppy)->track_size;
730
if (sectors > DMK_TOC_LEN)
732
err = FLOPPY_ERROR_INTERNAL;
736
if (max_track_size < coco_dmk_min_track_size(sectors, sector_length))
738
err = FLOPPY_ERROR_NOSPACE;
742
err = floppy_load_track(floppy, head, track, TRUE, &track_data_v, NULL);
745
track_data = (UINT8 *) track_data_v;
747
/* set up sector map */
748
sector_map = (int*)malloc(sectors * sizeof(*sector_map));
751
err = FLOPPY_ERROR_OUTOFMEMORY;
754
memset(sector_map, 0xFF, sectors * sizeof(*sector_map));
757
for (logical_sector = 0; logical_sector < sectors; logical_sector++)
759
while(sector_map[physical_sector] >= 0)
762
physical_sector %= sectors;
765
sector_map[physical_sector] = logical_sector + first_sector_id;
766
physical_sector += interleave + 1;
767
physical_sector %= sectors;
770
/* set up track table of contents */
772
track_position = DMK_TOC_LEN * 2 + DMK_LEAD_IN;
773
while(physical_sector < DMK_TOC_LEN)
775
if (physical_sector >= sectors)
777
/* no more sectors */
782
/* this is a sector */
783
logical_sector = sector_map[physical_sector];
785
/* write the sector */
786
memset(&track_data[track_position], 0x00, 8);
789
memset(&track_data[track_position], 0xA1, 3);
792
idam_offset = track_position | 0x8000;
793
dmk_idam_type( &track_data[track_position]) = 0xFE;
794
dmk_idam_track( &track_data[track_position]) = track;
795
dmk_idam_side( &track_data[track_position]) = head;
796
dmk_idam_sector( &track_data[track_position]) = logical_sector;
797
dmk_idam_sectorlength( &track_data[track_position]) = compute_log2(sector_length / 128);
798
crc = ccitt_crc16(0xcdb4, &track_data[track_position], DMK_IDAM_LENGTH - 2);
799
dmk_idam_set_crc( &track_data[track_position], crc);
800
track_position += DMK_IDAM_LENGTH;
802
memset(&track_data[track_position], 0x4E, 22);
803
track_position += 22;
805
memset(&track_data[track_position], 0x00, 12);
806
track_position += 12;
808
memset(&track_data[track_position], 0xA1, 3);
811
/* write sector body */
812
track_data[track_position] = 0xFB;
813
memset(&track_data[track_position + 1], floppy_get_filler(floppy), sector_length);
814
crc = ccitt_crc16(0xcdb4, &track_data[track_position], sector_length + 1);
815
track_data[track_position + sector_length + 1] = (UINT8) (crc >> 8);
816
track_data[track_position + sector_length + 2] = (UINT8) (crc >> 0);
817
track_position += sector_length + 3;
819
/* write sector footer */
820
memset(&track_data[track_position], 0x4E, 24);
821
track_position += 24;
824
/* write the TOC entry */
825
track_data[physical_sector * 2 + 0] = (UINT8) (idam_offset >> 0);
826
track_data[physical_sector * 2 + 1] = (UINT8) (idam_offset >> 8);
831
/* write track lead in */
832
memset(&track_data[physical_sector * 2], 0x4e, DMK_LEAD_IN);
834
/* write track footer */
835
assert(max_track_size >= (UINT32)track_position);
836
memset(&track_data[track_position], 0x4e, max_track_size - track_position);
841
return FLOPPY_ERROR_SUCCESS;
846
static int coco_dmk_get_heads_per_disk(floppy_image *floppy)
848
return get_dmk_tag(floppy)->heads;
853
static int coco_dmk_get_tracks_per_disk(floppy_image *floppy)
855
return get_dmk_tag(floppy)->tracks;
860
static UINT32 coco_dmk_get_track_size(floppy_image *floppy, int head, int track)
862
return get_dmk_tag(floppy)->track_size;
867
static floperr_t coco_dmk_seek_sector_in_track(floppy_image *floppy, int head, int track, int sector, int sector_is_index, int dirtify, UINT8 **sector_data, UINT32 *sector_length)
869
struct dmk_tag *tag = get_dmk_tag(floppy);
871
UINT32 idam_offset = 0;
872
UINT16 calculated_crc;
881
err = floppy_load_track(floppy, head, track, dirtify, &track_data_v, &track_length);
884
track_data = (UINT8 *) track_data_v;
886
/* search for matching IDAM */
887
for (i = 0; i < DMK_TOC_LEN; i++)
889
idam_offset = track_data[i * 2 + 1];
891
idam_offset |= track_data[i * 2 + 0];
892
idam_offset &= 0x3FFF;
894
if (idam_offset == 0)
896
/* we've reached the end of the road */
901
if ((idam_offset + DMK_IDAM_LENGTH) >= tag->track_size)
904
calculated_crc = ccitt_crc16(0xCDB4, &track_data[idam_offset], DMK_IDAM_LENGTH - 2);
906
if (calculated_crc == dmk_idam_crc(&track_data[idam_offset]))
910
/* the sector is indexed; decrement the index and go */
916
/* check IDAM integrity and check for matching sector */
917
if ((sector == dmk_idam_sector(&track_data[idam_offset]))
918
/* && (track == dmk_idam_track(&track_data[idam_offset])) */
919
/* && (head == dmk_idam_side(&track_data[idam_offset])) */
926
if (i >= DMK_TOC_LEN)
927
return FLOPPY_ERROR_SEEKERROR;
929
/* we found a matching sector ID */
931
offs = idam_offset + DMK_IDAM_LENGTH;
933
/* find pattern 0xA1A1FB; this represents the start of a data sector */
934
for (i = 0; i < DMK_DATA_GAP; i++)
936
/* overflowing the track? */
937
if ((i + offs) >= tag->track_size)
938
return FLOPPY_ERROR_SEEKERROR;
940
if (track_data[offs + i] == 0xA1)
942
else if ((track_data[offs + i] == 0xFB) && state)
947
if (i >= DMK_DATA_GAP)
948
return FLOPPY_ERROR_SEEKERROR;
951
sec_len = 128 << dmk_idam_sectorlength(&track_data[idam_offset]);
953
if ((offs + sec_len) > track_length)
954
return FLOPPY_ERROR_INVALIDIMAGE;
957
*sector_data = track_data + offs;
959
*sector_length = sec_len;
960
return FLOPPY_ERROR_SUCCESS;
965
static floperr_t coco_dmk_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length)
967
return coco_dmk_seek_sector_in_track(floppy, head, track, sector, FALSE, FALSE, NULL, sector_length);
972
static floperr_t coco_dmk_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
976
const UINT8 *track_data;
979
if (sector_index*2 >= DMK_TOC_LEN)
980
return FLOPPY_ERROR_SEEKERROR;
982
err = floppy_load_track(floppy, head, track, FALSE, &track_data_v, NULL);
985
track_data = (UINT8 *) track_data_v;
987
idam_offset = track_data[sector_index * 2 + 1];
989
idam_offset |= track_data[sector_index * 2 + 0];
990
idam_offset &= 0x3FFF;
992
if (idam_offset == 0)
993
return FLOPPY_ERROR_SEEKERROR;
996
*cylinder = dmk_idam_track(&track_data[idam_offset]);
998
*side = dmk_idam_side(&track_data[idam_offset]);
1000
*sector = dmk_idam_sector(&track_data[idam_offset]);
1002
*sector_length = 128 << dmk_idam_sectorlength(&track_data[idam_offset]);
1004
/* TODO: read DAM or DDAM and determine flags */
1006
return FLOPPY_ERROR_SUCCESS;
1011
static floperr_t internal_coco_dmk_read_sector(floppy_image *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen)
1014
UINT32 sector_length;
1016
UINT16 calculated_crc;
1019
err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, FALSE, §or_data, §or_length);
1023
crc_on_disk = sector_data[sector_length + 0];
1025
crc_on_disk += sector_data[sector_length + 1];
1027
calculated_crc = ccitt_crc16(0xE295, sector_data, sector_length);
1028
if (calculated_crc != crc_on_disk)
1029
return FLOPPY_ERROR_INVALIDIMAGE;
1031
memcpy(buffer, sector_data, MIN(sector_length, buflen));
1033
return FLOPPY_ERROR_SUCCESS;
1038
static floperr_t internal_coco_dmk_write_sector(floppy_image *floppy, int head, int track, int sector, int sector_is_index, const void *buffer, size_t buflen, int ddam)
1041
UINT32 sector_length;
1045
err = coco_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, TRUE, §or_data, §or_length);
1049
if (buflen > sector_length)
1050
return FLOPPY_ERROR_INTERNAL;
1052
memcpy(sector_data, buffer, buflen);
1054
crc = ccitt_crc16(0xE295, sector_data, sector_length);
1055
sector_data[sector_length + 0] = crc >> 8;
1056
sector_data[sector_length + 1] = crc >> 0;
1057
return FLOPPY_ERROR_SUCCESS;
1062
static floperr_t coco_dmk_read_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
1064
return internal_coco_dmk_read_sector(floppy, head, track, sector, FALSE, buffer, buflen);
1067
static floperr_t coco_dmk_write_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
1069
return internal_coco_dmk_write_sector(floppy, head, track, sector, FALSE, buffer, buflen, ddam);
1072
static floperr_t coco_dmk_read_indexed_sector(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen)
1074
return internal_coco_dmk_read_sector(floppy, head, track, sector, TRUE, buffer, buflen);
1077
static floperr_t coco_dmk_write_indexed_sector(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam)
1079
return internal_coco_dmk_write_sector(floppy, head, track, sector, TRUE, buffer, buflen, ddam);
1084
static void coco_dmk_interpret_header(floppy_image *floppy, int *heads, int *tracks, int *track_size)
1086
UINT8 header[DMK_HEADER_LEN];
1088
floppy_image_read(floppy, header, 0, DMK_HEADER_LEN);
1091
*tracks = header[1];
1093
*heads = (header[4] & 0x10) ? 1 : 2;
1095
*track_size = ((int) header[3]) * 0x100 + header[2];
1100
FLOPPY_CONSTRUCT(coco_dmk_construct)
1102
struct FloppyCallbacks *callbacks;
1103
struct dmk_tag *tag;
1104
UINT8 header[DMK_HEADER_LEN];
1105
int heads, tracks, track_size, sectors, sector_length;
1109
heads = option_resolution_lookup_int(params, PARAM_HEADS);
1110
tracks = option_resolution_lookup_int(params, PARAM_TRACKS);
1111
sectors = option_resolution_lookup_int(params, PARAM_SECTORS);
1112
sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH);
1114
track_size = coco_dmk_min_track_size(sectors, sector_length) + DMK_EXTRA_TRACK_LENGTH;
1116
memset(header, 0, sizeof(header));
1118
header[2] = track_size >> 0;
1119
header[3] = track_size >> 8;
1120
header[4] = (heads == 2) ? 0x00 : 0x10;
1122
floppy_image_write(floppy, header, 0, sizeof(header));
1126
coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size);
1129
tag = (dmk_tag *)floppy_create_tag(floppy, sizeof(struct dmk_tag));
1131
return FLOPPY_ERROR_OUTOFMEMORY;
1133
tag->track_size = track_size;
1134
tag->tracks = tracks;
1136
callbacks = floppy_callbacks(floppy);
1137
callbacks->read_track = coco_dmk_read_track;
1138
callbacks->write_track = coco_dmk_write_track;
1139
callbacks->get_track_data_offset = coco_dmk_get_track_data_offset;
1140
callbacks->format_track = coco_dmk_format_track;
1141
callbacks->get_heads_per_disk = coco_dmk_get_heads_per_disk;
1142
callbacks->get_tracks_per_disk = coco_dmk_get_tracks_per_disk;
1143
callbacks->get_track_size = coco_dmk_get_track_size;
1144
callbacks->get_sector_length = coco_dmk_get_sector_length;
1145
callbacks->get_indexed_sector_info = coco_dmk_get_indexed_sector_info;
1146
callbacks->read_sector = coco_dmk_read_sector;
1147
callbacks->write_sector = coco_dmk_write_sector;
1148
callbacks->read_indexed_sector = coco_dmk_read_indexed_sector;
1149
callbacks->write_indexed_sector = coco_dmk_write_indexed_sector;
1151
return FLOPPY_ERROR_SUCCESS;
1156
FLOPPY_IDENTIFY(coco_dmk_identify)
1158
int heads, tracks, track_size;
1159
UINT64 size, expected_size;
1161
size = floppy_image_size(floppy);
1162
coco_dmk_interpret_header(floppy, &heads, &tracks, &track_size);
1163
expected_size = DMK_HEADER_LEN + (heads * tracks * track_size);
1164
*vote = (size == expected_size) ? 100 : 0;
1165
return FLOPPY_ERROR_SUCCESS;
1170
/* ----------------------------------------------------------------------- */
1172
FLOPPY_OPTIONS_START( coco )
1173
FLOPPY_OPTION( coco_jvc, "dsk", "CoCo JVC disk image", coco_jvc_identify, coco_jvc_construct, NULL,
1177
SECTOR_LENGTH(128/[256]/512/1024)
1178
FIRST_SECTOR_ID(0-[1]))
1179
FLOPPY_OPTION( coco_os9, "os9", "CoCo OS-9 disk image", coco_os9_identify, coco_os9_construct, NULL,
1183
SECTOR_LENGTH([256])
1184
FIRST_SECTOR_ID([1]))
1185
FLOPPY_OPTION( coco_vdk, "vdk", "CoCo VDK disk image", coco_vdk_identify, coco_vdk_construct, NULL,
1189
SECTOR_LENGTH([256])
1190
FIRST_SECTOR_ID([1]))
1191
FLOPPY_OPTION( coco_dmk, "dsk,dmk", "CoCo DMK disk image", coco_dmk_identify, coco_dmk_construct, NULL,
1195
SECTOR_LENGTH(128/[256]/512/1024/2048/4096/8192)
1196
INTERLEAVE(0-[6]-17)
1197
FIRST_SECTOR_ID(0-[1]))