// license:BSD-3-Clause // copyright-holders:Olivier Galibert /********************************************************************* formats/dsk_dsk.c DSK disk images *********************************************************************/ #include #include #include "imageutl.h" #include "flopimg.h" #define MV_CPC "MV - CPC" #define EXTENDED "EXTENDED" struct dskdsk_tag { int disk_image_type; /* image type: standard or extended */ int heads; int tracks; int sector_size; uint64_t track_offsets[84*2]; /* offset within data for each track */ }; static struct dskdsk_tag *get_tag(floppy_image_legacy *floppy) { struct dskdsk_tag *tag; tag = (dskdsk_tag *)floppy_tag(floppy); return tag; } FLOPPY_IDENTIFY( dsk_dsk_identify ) { uint8_t header[8]; floppy_image_read(floppy, header, 0, 8); if ( memcmp( header, MV_CPC, 8 ) ==0) { *vote = 100; } else if ( memcmp( header, EXTENDED, 8 ) ==0) { *vote = 100; } else { *vote = 0; } return FLOPPY_ERROR_SUCCESS; } static int dsk_get_heads_per_disk(floppy_image_legacy *floppy) { return get_tag(floppy)->heads; } static int dsk_get_tracks_per_disk(floppy_image_legacy *floppy) { return get_tag(floppy)->tracks; } static uint64_t dsk_get_track_offset(floppy_image_legacy *floppy, int head, int track) { return get_tag(floppy)->track_offsets[(track<<1) + head]; } static floperr_t get_offset(floppy_image_legacy *floppy, int head, int track, int sector, bool sector_is_index, uint64_t *offset) { uint64_t offs; uint64_t track_offset; uint8_t track_info[0x100]; uint8_t sectors_per_track; int i; /* translate the sector to a raw sector */ /* check to see if we are out of range */ if ((head < 0) || (head >= get_tag(floppy)->heads) || (track < 0) || (track >= get_tag(floppy)->tracks) || (sector < 0) ) return FLOPPY_ERROR_SEEKERROR; track_offset = dsk_get_track_offset(floppy, head, track); floppy_image_read(floppy, track_info, track_offset, 0x100); sectors_per_track = track_info[0x015]; if (!sector_is_index) { if (sector >= sectors_per_track) { return FLOPPY_ERROR_SEEKERROR; } } if (get_tag(floppy)->disk_image_type==0) { get_tag(floppy)->sector_size = (1<<(track_info[0x014]+7)); offs = track_offset + 0x100 +sector * get_tag(floppy)->sector_size; } else { get_tag(floppy)->sector_size = track_info[0x18 + (sector<<3) + 6] + (track_info[0x18+(sector<<3) + 7]<<8); offs = track_offset + 0x100; for (i=0;isector_size; } return FLOPPY_ERROR_SUCCESS; } static floperr_t dsk_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) { floperr_t retVal; uint64_t offset; uint8_t sector_info[0x100]; int pos; retVal = get_offset(floppy, head, track, sector_index, false, nullptr); offset = dsk_get_track_offset(floppy,head,track); pos = 0x18 + (sector_index << 3); floppy_image_read(floppy, sector_info, offset, 0x100); if (cylinder) *cylinder = sector_info[pos + 0]; if (side) *side = sector_info[pos + 1]; if (sector) *sector = sector_info[pos + 2]; if (sector_length) { *sector_length = 1 << (sector_info[pos + 3] + 7); } if (flags) { *flags = 0; if (sector_info[pos + 4] & 0x20) *flags |= ID_FLAG_CRC_ERROR_IN_ID_FIELD; if (sector_info[pos + 5] & 0x20) *flags |= ID_FLAG_CRC_ERROR_IN_DATA_FIELD; if (sector_info[pos + 5] & 0x40) *flags |= ID_FLAG_DELETED_DATA; } return retVal; } FLOPPY_CONSTRUCT( dsk_dsk_construct ) { struct FloppyCallbacks *callbacks; struct dskdsk_tag *tag; uint8_t header[0x100]; uint64_t tmp = 0; int i; int skip,cnt; if(params) { // create return FLOPPY_ERROR_UNSUPPORTED; } floppy_image_read(floppy, header, 0, 0x100); #ifdef SPOT_DUPLICATES // this allow to spot .dsk files with same data and different headers, making easier to debug softlists. uint32_t temp_size = floppy_image_size(floppy); uint8_t tmp_copy[temp_size - 0x100]; floppy_image_read(floppy,tmp_copy,0x100,temp_size - 0x100); printf("CRC16: %d\n", ccitt_crc16(0xffff, tmp_copy, temp_size - 0x100)); #endif tag = (struct dskdsk_tag *) floppy_create_tag(floppy, sizeof(struct dskdsk_tag)); if (!tag) return FLOPPY_ERROR_OUTOFMEMORY; tag->heads = header[0x31]; if (tag->heads==1) { skip = 2; } else { skip = 1; } tag->tracks = header[0x30]; cnt =0; if ( memcmp( header, MV_CPC, 8 ) ==0) { tag->disk_image_type = 0; tmp = 0x100; for (i=0; itracks * tag->heads; i++) { tag->track_offsets[cnt] = tmp; tmp += pick_integer_le(header, 0x32, 2); cnt += skip; } } else { tag->disk_image_type = 1; tmp = 0x100; for (i=0; itracks * tag->heads; i++) { tag->track_offsets[cnt] = tmp; tmp += header[0x34 + i] << 8; cnt += skip; } } callbacks = floppy_callbacks(floppy); callbacks->read_sector = dsk_read_sector; callbacks->write_sector = dsk_write_sector; callbacks->read_indexed_sector = dsk_read_indexed_sector; callbacks->write_indexed_sector = dsk_write_indexed_sector; callbacks->get_sector_length = dsk_get_sector_length; callbacks->get_heads_per_disk = dsk_get_heads_per_disk; callbacks->get_tracks_per_disk = dsk_get_tracks_per_disk; callbacks->get_indexed_sector_info = dsk_get_indexed_sector_info; return FLOPPY_ERROR_SUCCESS; } #include "dsk_dsk.h" #define DSK_FORMAT_HEADER "MV - CPC" #define EXT_FORMAT_HEADER "EXTENDED CPC DSK" dsk_format::dsk_format() : floppy_image_format_t() { } const char *dsk_format::name() const { return "dsk"; } const char *dsk_format::description() const { return "CPC DSK Format"; } const char *dsk_format::extensions() const { return "dsk"; } bool dsk_format::supports_save() const { return false; } int dsk_format::identify(io_generic *io, uint32_t form_factor) { uint8_t header[16]; io_generic_read(io, &header, 0, sizeof(header)); if ( memcmp( header, DSK_FORMAT_HEADER, 8 ) ==0) { return 100; } if ( memcmp( header, EXT_FORMAT_HEADER, 16 ) ==0) { return 100; } return 0; } #pragma pack(1) struct track_header { uint8_t headertag[13]; uint16_t unused1; uint8_t unused1b; uint8_t track_number; uint8_t side_number; uint8_t datarate; uint8_t rec_mode; uint8_t sector_size_code; uint8_t number_of_sector; uint8_t gap3_length; uint8_t filler_byte; }; struct sector_header { uint8_t track; uint8_t side; uint8_t sector_id; uint8_t sector_size_code; uint8_t fdc_status_reg1; uint8_t fdc_status_reg2; uint16_t data_length; }; #pragma pack() bool dsk_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint8_t header[0x100]; bool extendformat = false; uint64_t image_size = io_generic_size(io); io_generic_read(io, &header, 0, sizeof(header)); if ( memcmp( header, EXT_FORMAT_HEADER, 16 ) ==0) { extendformat = true; } int heads = header[0x31]; int skip = 1; if (heads==1) { skip = 2; } int tracks = header[0x30]; int img_tracks, img_heads; image->get_maximal_geometry(img_tracks, img_heads); if (tracks > img_tracks) { if (tracks - img_tracks > DUMP_THRESHOLD) { osd_printf_error("dsk: Floppy disk has too many tracks for this drive (floppy tracks=%d, drive tracks=%d).\n", tracks, img_tracks); return false; } else { // Some dumps has a few excess tracks to be safe, // lets be nice and just skip those tracks osd_printf_warning("dsk: Floppy disk has a slight excess of tracks for this drive that will be discarded (floppy tracks=%d, drive tracks=%d).\n", tracks, img_tracks); tracks = img_tracks; } } if (heads > img_heads) return false; uint64_t track_offsets[84*2]; int cnt =0; if (!extendformat) { int tmp = 0x100; for (int i=0; i= image_size) continue; track_header tr; io_generic_read(io, &tr,track_offsets[(track<<1)+side],sizeof(tr)); // skip if there are no sectors in this track if (tr.number_of_sector == 0) continue; int protection = 0; int first_sector_code = -1; for(int j=0;j 0) && (sector.sector_size_code == 2) && (first_sector_code == 6)) protection = 1; // first: 6144 rest: 512 if ((j > 0) && (sector.sector_size_code == j) && (first_sector_code == 0)) protection = 2; // first: 128 rest: N*128 } desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; int pos = track_offsets[(track<<1)+side] + 0x100; for(int j=0;j;