diff options
Diffstat (limited to 'trunk/src/lib/formats/z80ne_dsk.c')
-rw-r--r-- | trunk/src/lib/formats/z80ne_dsk.c | 848 |
1 files changed, 848 insertions, 0 deletions
diff --git a/trunk/src/lib/formats/z80ne_dsk.c b/trunk/src/lib/formats/z80ne_dsk.c new file mode 100644 index 00000000000..720687d8272 --- /dev/null +++ b/trunk/src/lib/formats/z80ne_dsk.c @@ -0,0 +1,848 @@ +/********************************************************************* + + formats/z80ne_dsk.c + + Nuova Elettronica Z80NE disk images + +*********************************************************************/ + +#include <assert.h> +#include "z80ne_dsk.h" +#include "basicdsk.h" +#include "imageutl.h" + +/* ----------------------------------------------------------------------- + * DMK file format + * + * David M. Keil's disk image format is aptly called an 'on disk' image + * format. This means that whatever written to the disk is encoded into + * the image file. IDAMS, sector headers, trailing CRCs, and intra-sector + * spacing. * + * + * HEADER DESCRIPTION: + * + * Offset Bytes Field Description + * ------ ----- ------------ ----------- + * 0 1 write_prot 0xff = Write Protected, 0x00 = R/W + * 1 1 tracks Number of tracks + * 2 2 track_length Bytes per track on DMK file (little endian) + * 4 1 disk_options Miscellaneous flags + * bit 0-3: Unused + * bit 4: Sides on DMK file + * 1=single, 0=double + * bit 5: Unused + * bit 6: Single Density DMK file + * 1=single (bytes written once + * on IDAMs) + * 0=double (bytes written + * two times for SD IDAMs) + * 5 7 reserved Reserved for future use + * 12 4 real_disk_code If this is 0x12345678 (little endian) + * then access a real disk drive + * (unsupported) + * + * Each track begins with a track TOC, consisting of 64 little endian 16-bit + * integers. Each integer has the following format: + * bit 0-13: Offset from beginning of track to 'FE' byte of IDAM + * Note these are always sorted from first to last. All empty + * entries are 0x00 + * bit 14: Undefined (reserved) + * bit 15: Sector double density (0=SD 1=DD) + * If not set and SD DMK flag is set then bytes are written + * once. + * ----------------------------------------------------------------------- */ + +struct dmk_tag +{ + int heads; + int tracks; + UINT32 track_size; +}; + +/* DMK file structure + * See WD1711 documentation + */ +/* DMK file header */ +#define DMK_HEADER_LEN 16 /* DMK header */ + /* For every track (40) */ + #define DMK_TOC_LEN 128 /* 64 16-bit relative offsets to IDAMs */ + #define DMK_GAP1_LEN 32 /* GAP1 (26 bytes 0xFF and 6 bytes 0x00) */ + + /* For every sector (10) 301 bytes */ + #define DMK_IDAM_LEN 7 /* IDAM (0xFE, Track, 0x00, Sector, 0x00, CRChi, CRClo) */ + #define DMK_ID_GAP_LEN 17 /* GAP2 (11 bytes 0xFF and 6 bytes 0x00) */ + #define DMK_DAM_LEN 1 /* Data Address Mark (0xFB) */ + #define DMK_DATA_LEN 256 /* Data */ + #define DMK_DATA_CRC_LEN 2 /* Data CRC (CRChi, CRClo) */ + #define DMK_DATA_GAP_LEN 18 /* GAP3 (12 bytes 0xFF and 6 bytes 0x00) (not for last sector) */ + + #define DMK_EXTRA_TRACK_LENGTH (176) /* GAP4 (192 bytes 0xFF) */ +/* End of DMK file structure */ + +#define dmk_idam_type(x) (x)[0] +#define dmk_idam_track(x) (x)[1] +#define dmk_idam_side(x) (x)[2] +#define dmk_idam_sector(x) (x)[3] +#define dmk_idam_sectorlength(x) (x)[4] +#define dmk_idam_crc(x) (((x)[5] << 8) + (x)[6]) +#define dmk_idam_set_crc(x, crc) (x)[5] = ((crc) >> 8); (x)[6] = ((crc) >> 0); + +static const char needle_data[] = "\x00\x00\x00\x00\x00\x00\x00\x00\xFB\xFB"; +static const char needle_deleted_data_fa[] = "\x00\x00\x00\x00\x00\x00\x00\x00\xFA\xFA"; +static const char needle_deleted_data_f8[] = "\x00\x00\x00\x00\x00\x00\x00\x00\xF8\xF8"; + + +static struct dmk_tag *get_dmk_tag(floppy_image_legacy *floppy) +{ + return (dmk_tag *)floppy_tag(floppy); +} + + +static floperr_t z80ne_dmk_get_track_offset(floppy_image_legacy *floppy, int head, int track, UINT64 *offset) +{ + struct dmk_tag *tag = get_dmk_tag(floppy); + + if ((head < 0) || (head >= tag->heads) || (track < 0) || (track >= tag->tracks)) + return FLOPPY_ERROR_SEEKERROR; + + *offset = track; + *offset *= tag->heads; + *offset += head; + *offset *= tag->track_size; + *offset += DMK_HEADER_LEN; + return FLOPPY_ERROR_SUCCESS; +} + + +static UINT32 z80ne_dmk_min_track_size(int sectors, int sector_length) +{ + int sector_physical_length; + sector_physical_length = (DMK_IDAM_LEN + DMK_ID_GAP_LEN + DMK_DAM_LEN + sector_length + DMK_DATA_CRC_LEN + DMK_DATA_GAP_LEN); + return DMK_TOC_LEN + 2 * (DMK_GAP1_LEN + (sectors * sector_physical_length) - DMK_DATA_GAP_LEN + DMK_EXTRA_TRACK_LENGTH); +} + + + +static floperr_t z80ne_dmk_read_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen) +{ + floperr_t err; + UINT64 track_offset; + + err = z80ne_dmk_get_track_offset(floppy, head, track, &track_offset); + if (err) + return err; + + floppy_image_read(floppy, buffer, offset + track_offset, buflen); + return FLOPPY_ERROR_SUCCESS; +} + + + +static floperr_t z80ne_dmk_write_track(floppy_image_legacy *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen) +{ + floperr_t err; + UINT64 track_offset; + + err = z80ne_dmk_get_track_offset(floppy, head, track, &track_offset); + if (err) + return err; + + floppy_image_write(floppy, buffer, offset + track_offset, buflen); + return FLOPPY_ERROR_SUCCESS; +} + + + +static floperr_t z80ne_dmk_get_track_data_offset(floppy_image_legacy *floppy, int head, int track, UINT64 *offset) +{ + *offset = DMK_TOC_LEN + 1; + return FLOPPY_ERROR_SUCCESS; +} + + +static floperr_t z80ne_dmk_format_track(floppy_image_legacy *floppy, int head, int track, option_resolution *params) +{ + int sectors; + int sector_length; + int interleave; + int first_sector_id; + floperr_t err; + int physical_sector; + int logical_sector; + int track_position; + UINT16 idam_offset; + UINT16 crc; + UINT8 *track_data; + void *track_data_v; + UINT32 max_track_size; + int *sector_map = NULL; + UINT8 *local_sector = NULL; + int local_sector_size; + int sector_position; + int i; + + err = FLOPPY_ERROR_SUCCESS; + + sectors = option_resolution_lookup_int(params, PARAM_SECTORS); + sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); + interleave = option_resolution_lookup_int(params, PARAM_INTERLEAVE); + first_sector_id = option_resolution_lookup_int(params, PARAM_FIRST_SECTOR_ID); + + max_track_size = get_dmk_tag(floppy)->track_size; + + if (sectors > DMK_TOC_LEN/2) + { + err = FLOPPY_ERROR_INTERNAL; + goto done; + } + + if (max_track_size < z80ne_dmk_min_track_size(sectors, sector_length)) + { + err = FLOPPY_ERROR_NOSPACE; + goto done; + } + + err = floppy_load_track(floppy, head, track, TRUE, &track_data_v, NULL); + if (err) + goto done; + track_data = (UINT8 *) track_data_v; + + /* set up sector map */ + sector_map = (int*)malloc(sectors * sizeof(*sector_map)); + if (!sector_map) + { + err = FLOPPY_ERROR_OUTOFMEMORY; + goto done; + } + memset(sector_map, 0xFF, sectors * sizeof(*sector_map)); + + physical_sector = 0; + for (logical_sector = 0; logical_sector < sectors; logical_sector++) + { + while(sector_map[physical_sector] >= 0) + { + physical_sector++; + physical_sector %= sectors; + } + + sector_map[physical_sector] = logical_sector + first_sector_id; + physical_sector += interleave + 1; + physical_sector %= sectors; + } + + /* set up a local physical sector template */ + local_sector_size = (DMK_IDAM_LEN + + DMK_ID_GAP_LEN + + DMK_DAM_LEN + + sector_length + + DMK_DATA_CRC_LEN + + DMK_DATA_GAP_LEN); + local_sector = (UINT8*)malloc(local_sector_size); + if (!local_sector) + { + err = FLOPPY_ERROR_OUTOFMEMORY; + goto done; + } + memset(local_sector, 0x00, local_sector_size); + + /* set up track table of contents */ + physical_sector = 0; + + /* write GAP1 (track lead in) */ + memset(&track_data[DMK_TOC_LEN], 0xFF, 52); + memset(&track_data[DMK_TOC_LEN+52], 0x00, 12); + track_position = DMK_TOC_LEN + DMK_GAP1_LEN * 2; + + /* + * prepare template in local sector + */ + + /* IDAM */ + sector_position = 0; + dmk_idam_type( &local_sector[sector_position]) = 0xFE; + dmk_idam_track( &local_sector[sector_position]) = track; + dmk_idam_side( &local_sector[sector_position]) = head; + dmk_idam_sector( &local_sector[sector_position]) = 0; /* replace in sector instances */ + dmk_idam_sectorlength( &local_sector[sector_position]) = compute_log2(sector_length / 128); + dmk_idam_set_crc( &local_sector[sector_position], 0); /* replace in sector instances */ + sector_position += 7; + + /* GAP2 (ID GAP) */ + memset(&local_sector[sector_position], 0xFF, 11); + sector_position += 11; + memset(&local_sector[sector_position], 0x00, 6); + sector_position += 6; + + /* sector body */ + local_sector[sector_position] = 0xFB; + memset(&local_sector[sector_position + 1], floppy_get_filler(floppy), sector_length); + crc = ccitt_crc16(0xffff, &local_sector[sector_position], sector_length + 1); + local_sector[sector_position + sector_length + 1] = (UINT8) (crc >> 8); + local_sector[sector_position + sector_length + 2] = (UINT8) (crc >> 0); + sector_position += sector_length + 3; + + /* GAP3 (Data GAP) */ + memset(&local_sector[sector_position], 0xFF, 12); + sector_position += 12; + memset(&local_sector[sector_position], 0x00, 6); + sector_position += 6; + + /* + * start of track data + */ + while(physical_sector < DMK_TOC_LEN/2) + { + if (physical_sector >= sectors) + { + /* no more sectors */ + idam_offset = 0; + } + else + { + /* this is a sector */ + idam_offset = track_position; + logical_sector = sector_map[physical_sector]; + + /* update IDAM in local sector template */ + dmk_idam_sector( &local_sector[0]) = logical_sector; /* update sector number in sector instance */ + crc = ccitt_crc16(0xffff, &local_sector[0], DMK_IDAM_LEN - 2); /* and recalculate crc */ + dmk_idam_set_crc( &local_sector[0], crc); + + /* write local sector in track doubling every byte (DMK double density mode) */ + for(i=0; i<local_sector_size; i++) + track_data[track_position + i*2] = track_data[track_position + (i*2) + 1] = local_sector[i]; + track_position += (2 * local_sector_size); + if (physical_sector == (sectors-1)) /* on last sector remove GAP3 */ + track_position -= (2 * DMK_DATA_GAP_LEN); + } + + /* write the TOC entry */ + track_data[physical_sector * 2 + 0] = (UINT8) (idam_offset >> 0); + track_data[physical_sector * 2 + 1] = (UINT8) (idam_offset >> 8); + + physical_sector++; + } + + /* write track footer GAP4 */ + assert(max_track_size >= (UINT32)track_position); + memset(&track_data[track_position], 0xFF, max_track_size - track_position); + +done: + if (sector_map) + free(sector_map); + if (local_sector) + free(local_sector); + + return err; +} + + + +static int z80ne_dmk_get_heads_per_disk(floppy_image_legacy *floppy) +{ + return get_dmk_tag(floppy)->heads; +} + + + +static int z80ne_dmk_get_tracks_per_disk(floppy_image_legacy *floppy) +{ + return get_dmk_tag(floppy)->tracks; +} + + + +static UINT32 z80ne_dmk_get_track_size(floppy_image_legacy *floppy, int head, int track) +{ + return get_dmk_tag(floppy)->track_size; +} + +static UINT8 * my_memmem(UINT8 *haystack, size_t haystacklen, + UINT8 *needle, size_t needlelen) +{ + register UINT8 *h = haystack; + register UINT8 *n = needle; + register size_t hl = haystacklen; + register size_t nl = needlelen; + register size_t i; + + if (nl == 0) return haystack; /* The first occurrence of the empty string is deemed to occur at + the beginning of the string. */ + if (hl < nl) + return NULL; + + for( i = 0; (i < hl) && (i + nl <= hl ); i++ ) + if (h[i] == *n) /* first match */ + if ( !memcmp(&h[i]+1, n + 1, nl - 1) ) + return (haystack+i); /* returns a pointer to the substring */ + + return (UINT8 *)NULL; /* not found */ +} + + + +static floperr_t z80ne_dmk_seek_sector_in_track(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, int dirtify, UINT8 **sector_data, UINT32 *sector_length) +{ + struct dmk_tag *tag = get_dmk_tag(floppy); + floperr_t err; + size_t idam_offset = 0; + UINT16 calculated_crc; + size_t i, j; + size_t offs; + /*int state;*/ + UINT8 *track_data; + void *track_data_v; + size_t track_length; + size_t sec_len; + UINT8 *local_idam = NULL; + int local_idam_size; + UINT8 *sec_data; + + + err = FLOPPY_ERROR_SUCCESS; + + err = floppy_load_track(floppy, head, track, dirtify, &track_data_v, &track_length); + if (err) + goto done; + track_data = (UINT8 *) track_data_v; + + /* set up a local IDAM space */ + local_idam_size = (DMK_IDAM_LEN + + DMK_ID_GAP_LEN + + DMK_DAM_LEN + + DMK_DATA_GAP_LEN); + local_idam = (UINT8*)malloc(local_idam_size); + if (!local_idam) + { + err = FLOPPY_ERROR_OUTOFMEMORY; + goto done; + } + memset(local_idam, 0x00, local_idam_size); + + /* search for matching IDAM */ + for (i = 0; i < DMK_TOC_LEN / 2; i++) + { + idam_offset = track_data[i * 2 + 1]; + idam_offset <<= 8; + idam_offset |= track_data[i * 2 + 0]; + idam_offset &= 0x3FFF; + + if (idam_offset == 0) + { + /* we've reached the end of the road */ + i = DMK_TOC_LEN; + break; + } + + if ((idam_offset + DMK_IDAM_LEN * 2) >= tag->track_size) + continue; + + /* overflowing the track? */ + if ((idam_offset + local_idam_size * 2) >= tag->track_size) + { + err = FLOPPY_ERROR_SEEKERROR; + goto done; + } + + /* create a local copy of sector of IDAM */ + for(j = 0; j < (DMK_IDAM_LEN + DMK_ID_GAP_LEN + DMK_DAM_LEN); j++) + local_idam[j] = track_data[idam_offset + j*2]; + + /* from now on all operations are done in local copy of IDAM */ + calculated_crc = ccitt_crc16(0xffff, &local_idam[0], DMK_IDAM_LEN - 2); + + /* check IDAM integrity and check for matching sector */ + if (calculated_crc == dmk_idam_crc(&local_idam[0])) + { + if (sector_is_index) + { + /* the sector is indexed; decrement the index and go */ + if (sector-- == 0) + break; + } + else + { + /* check for matching sector ID */ + if (sector == dmk_idam_sector(&local_idam[0])) + break; + } + } + } + + if (i >= DMK_TOC_LEN / 2) + { + err = FLOPPY_ERROR_SEEKERROR; + goto done; + } + + /* we found a matching sector ID */ + /*state = 0;*/ + offs = idam_offset + 2 * DMK_IDAM_LEN; + + /* find pattern 0x0000FB; this represents the start of a data sector */ + sec_data = my_memmem(&track_data[offs], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_data, 10); + if(!sec_data) + { + /* find pattern 0x0000FA; this represents the start of a deleted data sector (used for system sectors) */ + sec_data = my_memmem(&track_data[offs], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_deleted_data_fa, 10); + } + if(!sec_data) + { + /* find pattern 0x0000F8; this represents the start of a deleted data sector (used for system sectors) */ + sec_data = my_memmem(&track_data[offs], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_deleted_data_f8, 10); + } + + if(sec_data) + sec_data += 10; + else + { + err = FLOPPY_ERROR_SEEKERROR; + goto done; + } + offs = sec_data - &track_data[offs]; + + sec_len = 128 << dmk_idam_sectorlength(&local_idam[0]); + + if ((offs + 2 * sec_len) > track_length) + { + err = FLOPPY_ERROR_INVALIDIMAGE; + goto done; + } + + if (sector_data) + *sector_data = sec_data; + if (sector_length) + *sector_length = sec_len; +done: + if (local_idam) + free(local_idam); + return err; +} + + + +static floperr_t z80ne_dmk_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length) +{ + return z80ne_dmk_seek_sector_in_track(floppy, head, track, sector, FALSE, FALSE, NULL, sector_length); +} + + + +static floperr_t z80ne_dmk_get_indexed_sector_info(floppy_image_legacy *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags) +{ + floperr_t err; + size_t idam_offset; + UINT8 *track_data; + void *track_data_v; + unsigned long dam; + + if (sector_index * 2 >= DMK_TOC_LEN) + return FLOPPY_ERROR_SEEKERROR; + + err = floppy_load_track(floppy, head, track, FALSE, &track_data_v, NULL); + if (err) + return err; + track_data = (UINT8 *) track_data_v; + + idam_offset = track_data[sector_index * 2 + 1]; + idam_offset <<= 8; + idam_offset |= track_data[sector_index * 2 + 0]; + idam_offset &= 0x3FFF; + + if (idam_offset == 0) + return FLOPPY_ERROR_SEEKERROR; + + /* determine type of data sector */ + /* find pattern 0x0000FB; this represents the start of a data sector */ + if ( my_memmem(&track_data[idam_offset+14], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_data, 10) ) + dam = 0; + /* find pattern 0x0000FA; this represents the start of a deleted data sector (used for system sectors) */ + else if ( my_memmem(&track_data[idam_offset+14], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_deleted_data_fa, 10) ) + dam = ID_FLAG_DELETED_DATA; + /* find pattern 0x0000F8; this represents the start of a deleted data sector (used for system sectors) */ + else if ( my_memmem(&track_data[idam_offset+14], 4 * (DMK_ID_GAP_LEN + DMK_DAM_LEN), (UINT8 *)needle_deleted_data_f8, 10) ) + dam = ID_FLAG_DELETED_DATA; + else + return FLOPPY_ERROR_SEEKERROR; + + if (cylinder) + *cylinder = (&track_data[idam_offset])[2]; + if (side) + *side = (&track_data[idam_offset])[4]; + if (sector) + *sector = (&track_data[idam_offset])[6]; + if (sector_length) + *sector_length = 128 << (&track_data[idam_offset])[8]; + if (flags) + *flags = dam; + return FLOPPY_ERROR_SUCCESS; +} + + + +static floperr_t internal_z80ne_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, void *buffer, size_t buflen) +{ + floperr_t err; + UINT32 sector_length; + UINT16 crc_on_disk; + UINT16 calculated_crc; + UINT8 *sector_data = NULL; + UINT8 *local_sector = NULL; + int local_sector_size; + int i; + + err = FLOPPY_ERROR_SUCCESS; + + /* get sector length and data pointer */ + err = z80ne_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, FALSE, §or_data, §or_length); + if (err) + goto done; + + /* set up a local physical sector space (DAM + data + crc + GAP) */ + local_sector_size = (DMK_DAM_LEN + sector_length + DMK_DATA_CRC_LEN + DMK_DATA_GAP_LEN); + local_sector = (UINT8*)malloc(local_sector_size); + if (!local_sector) + { + err = FLOPPY_ERROR_OUTOFMEMORY; + goto done; + } + memset(local_sector, 0x00, local_sector_size); + + /* get sector data */ + /* create a local copy of sector data including DAM (for crc calculation) */ + for(i = 0; i < (DMK_DAM_LEN + sector_length + DMK_DATA_CRC_LEN); i++) + local_sector[i] = (sector_data - 2)[i*2]; + + crc_on_disk = local_sector[sector_length + 0 + 1]; + crc_on_disk <<= 8; + crc_on_disk += local_sector[sector_length + 1 + 1]; + + /* crc calculated including DAM */ + calculated_crc = ccitt_crc16(0xffff, local_sector, sector_length+1); + if (calculated_crc != crc_on_disk) + { + err = FLOPPY_ERROR_INVALIDIMAGE; + goto done; + } + + /* copy local sector data excluding DAM */ + memcpy(buffer, local_sector+1, MIN(sector_length, buflen)); + + done: + if (local_sector) + free(local_sector); + return err; +} + + + +static floperr_t internal_z80ne_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, int sector_is_index, const void *buffer, size_t buflen, int ddam) +{ + floperr_t err; + UINT32 sector_length; + UINT8 *sector_data; + UINT16 crc; + UINT8 *local_sector = NULL; + int local_sector_size; + int i; + + err = FLOPPY_ERROR_SUCCESS; + + /* get sector length */ + err = z80ne_dmk_seek_sector_in_track(floppy, head, track, sector, sector_is_index, TRUE, §or_data, §or_length); + if (err) + goto done; + + /* set up a local physical sector space */ + local_sector_size = (DMK_DAM_LEN + sector_length + DMK_DATA_CRC_LEN + DMK_DATA_GAP_LEN); + local_sector = (UINT8*)malloc(local_sector_size); + if (!local_sector) + { + err = FLOPPY_ERROR_OUTOFMEMORY; + goto done; + } + memset(local_sector, 0x00, local_sector_size); + if(!ddam) + local_sector[0] = 0xFB; + else + local_sector[0] = 0xFA; + + if (buflen > sector_length) + { + err = FLOPPY_ERROR_INTERNAL; + goto done; + } + + memcpy(&local_sector[1], buffer, buflen); + + crc = ccitt_crc16(0xffff, local_sector, DMK_DAM_LEN + sector_length); + local_sector[DMK_DAM_LEN + sector_length + 0] = crc >> 8; + local_sector[DMK_DAM_LEN + sector_length + 1] = crc >> 0; + + /* write local sector in track doubling every byte (DMK double density mode) */ + /* write DAM or DDAM too */ + sector_data -= 2; + for(i=0; i < (DMK_DAM_LEN + sector_length + DMK_DATA_CRC_LEN); i++) + sector_data[i*2] = sector_data[(i*2)+1] = local_sector[i]; + + done: + if (local_sector) + free(local_sector); + return err; +} + + + +static floperr_t z80ne_dmk_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) +{ + return internal_z80ne_dmk_read_sector(floppy, head, track, sector, FALSE, buffer, buflen); +} + +static floperr_t z80ne_dmk_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) +{ + return internal_z80ne_dmk_write_sector(floppy, head, track, sector, FALSE, buffer, buflen, ddam); +} + +static floperr_t z80ne_dmk_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) +{ + return internal_z80ne_dmk_read_sector(floppy, head, track, sector, TRUE, buffer, buflen); +} + +static floperr_t z80ne_dmk_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) +{ + return internal_z80ne_dmk_write_sector(floppy, head, track, sector, TRUE, buffer, buflen, ddam); +} + + + +static void z80ne_dmk_interpret_header(floppy_image_legacy *floppy, int *heads, int *tracks, int * sectors, int *track_size) +{ + UINT8 header[DMK_HEADER_LEN + DMK_TOC_LEN]; + int i; + int idam_offset; + int sects; + + floppy_image_read(floppy, header, 0, DMK_HEADER_LEN + DMK_TOC_LEN); + + if (tracks) + *tracks = header[1]; + if (heads) + *heads = (header[4] & 0x10) ? 1 : 2; + if (track_size) + *track_size = ((int) header[3]) * 0x100 + header[2]; + if(sectors) + { + /* count sectors on first track */ + sects = 0; + for (i = 0; i < DMK_TOC_LEN / 2; i++) + { + idam_offset = header[DMK_HEADER_LEN + i * 2 + 1]; + idam_offset <<= 8; + idam_offset |= header[DMK_HEADER_LEN + i * 2 + 0]; + idam_offset &= 0x3FFF; + + if (idam_offset == 0) + break; + else + sects++; + } + *sectors = sects; + } + +} + + + +FLOPPY_CONSTRUCT(z80ne_dmk_construct) +{ + struct FloppyCallbacks *callbacks; + struct dmk_tag *tag; + UINT8 header[DMK_HEADER_LEN]; + int heads, tracks, track_size, sectors, sector_length; + + if (params) + { + heads = option_resolution_lookup_int(params, PARAM_HEADS); + tracks = option_resolution_lookup_int(params, PARAM_TRACKS); + sectors = option_resolution_lookup_int(params, PARAM_SECTORS); + sector_length = option_resolution_lookup_int(params, PARAM_SECTOR_LENGTH); + + track_size = z80ne_dmk_min_track_size(sectors, sector_length); + + memset(header, 0, sizeof(header)); + header[1] = tracks; + header[2] = track_size >> 0; + header[3] = track_size >> 8; + header[4] = (heads == 2) ? 0x00 : 0x10; + + floppy_image_write(floppy, header, 0, sizeof(header)); + } + else + { + z80ne_dmk_interpret_header(floppy, &heads, &tracks, §ors, &track_size); + } + + tag = (dmk_tag*)floppy_create_tag(floppy, sizeof(struct dmk_tag)); + if (!tag) + return FLOPPY_ERROR_OUTOFMEMORY; + tag->heads = heads; + tag->track_size = track_size; + tag->tracks = tracks; + + callbacks = floppy_callbacks(floppy); + callbacks->read_track = z80ne_dmk_read_track; + callbacks->write_track = z80ne_dmk_write_track; + callbacks->get_track_data_offset = z80ne_dmk_get_track_data_offset; + callbacks->format_track = z80ne_dmk_format_track; + callbacks->get_heads_per_disk = z80ne_dmk_get_heads_per_disk; + callbacks->get_tracks_per_disk = z80ne_dmk_get_tracks_per_disk; + callbacks->get_track_size = z80ne_dmk_get_track_size; + callbacks->get_sector_length = z80ne_dmk_get_sector_length; + callbacks->get_indexed_sector_info = z80ne_dmk_get_indexed_sector_info; + callbacks->read_sector = z80ne_dmk_read_sector; + callbacks->write_sector = z80ne_dmk_write_sector; + callbacks->read_indexed_sector = z80ne_dmk_read_indexed_sector; + callbacks->write_indexed_sector = z80ne_dmk_write_indexed_sector; + + return FLOPPY_ERROR_SUCCESS; +} + + + +FLOPPY_IDENTIFY(z80ne_dmk_identify) +{ + int heads, tracks, sectors, track_size; + UINT64 size, expected_size; + + size = floppy_image_size(floppy); + z80ne_dmk_interpret_header(floppy, &heads, &tracks, §ors, &track_size); + expected_size = DMK_HEADER_LEN + (heads * tracks * track_size); + *vote = (size == expected_size) ? 90 : 0; + *vote += (sectors == 10) ? 10 : 0; + return FLOPPY_ERROR_SUCCESS; +} + + + +/* ----------------------------------------------------------------------- */ + +LEGACY_FLOPPY_OPTIONS_START( z80ne ) + /* + * Single side + * Single density + * FM, 125 kbit/s, + * 40 tracks, track ID: 0..39 + * 10 sectors/track, sector ID: 0..9 + * 256 bytes/sector + * Interleave 1 (sector ID sequence on track: 0 5 1 6 2 7 3 8 4 9) + * 3125 byte/track unformatted + * Rotation speed 300 rpm (5 rps) + */ + LEGACY_FLOPPY_OPTION( z80ne_dmk, "zmk", "Z80NE DMK disk image", z80ne_dmk_identify, z80ne_dmk_construct, NULL, + HEADS([1]) + TRACKS([40]) + SECTORS([10]) + SECTOR_LENGTH([256]) + INTERLEAVE([1]) + FIRST_SECTOR_ID([0])) +LEGACY_FLOPPY_OPTIONS_END |