// license:BSD-3-Clause // copyright-holders:Wilbert Pol, tim lindner /********************************************************************* formats/sdf_dsk.h SDF disk images. Format created by Darren Atkinson for use with his CoCoSDC floppy disk emulator. http://cocosdc.blogspot.com/p/sd-card-socket-sd-card-socket-is-push.html *********************************************************************/ #include "sdf_dsk.h" #include sdf_format::sdf_format() { } const char *sdf_format::name() const { return "sdf"; } const char *sdf_format::description() const { return "SDF disk image"; } const char *sdf_format::extensions() const { return "sdf"; } int sdf_format::identify(io_generic *io, uint32_t form_factor) { uint8_t header[HEADER_SIZE]; uint64_t size = io_generic_size(io); if (size < HEADER_SIZE) { return 0; } io_generic_read(io, header, 0, HEADER_SIZE); int tracks = header[4]; int heads = header[5]; // Check magic bytes if (header[0] != 'S' || header[1] != 'D' || header[2] != 'F' || header[3] != '1') { return 0; } // Check heads if (heads != 1 && heads != 2) { return 0; } if (size == HEADER_SIZE + heads * tracks * TOTAL_TRACK_SIZE) { return 100; } return 0; } bool sdf_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint8_t header[HEADER_SIZE]; std::vector track_data(TOTAL_TRACK_SIZE); std::vector raw_track_data; io_generic_read(io, header, 0, HEADER_SIZE); const int tracks = header[4]; const int heads = header[5]; if (heads == 2) { image->set_variant(floppy_image::DSDD); } else { image->set_variant(floppy_image::SSDD); } for (int track = 0; track < tracks; track++) { for (int head = 0; head < heads; head++) { int iam_location = -1; int idam_location[SECTOR_SLOT_COUNT+1]; int dam_location[SECTOR_SLOT_COUNT+1]; raw_track_data.clear(); // Read track io_generic_read(io, &track_data[0], HEADER_SIZE + ( heads * track + head ) * TOTAL_TRACK_SIZE, TOTAL_TRACK_SIZE); int sector_count = track_data[0]; if (sector_count > SECTOR_SLOT_COUNT) return false; // Transfer IDAM and DAM locations to table for (int i = 0; i < SECTOR_SLOT_COUNT+1; i++) { if (i < sector_count ) { idam_location[i] = ((track_data[ 8 * (i+1) + 1] << 8 | track_data[ 8 * (i+1)]) & 0x3FFF) - 4; dam_location[i] = ((track_data[ 8 * (i+1) + 1 + 2] << 8 | track_data[ 8 * (i+1) + 2]) & 0x3FFF) - 4; if (idam_location[i] > TOTAL_TRACK_SIZE) return false; if (dam_location[i] > TOTAL_TRACK_SIZE) return false; } else { idam_location[i] = -1; dam_location[i] = -1; } } // Find IAM location for (int i = idam_location[0] - 1; i >= TRACK_HEADER_SIZE + 3; i--) { // It's usually 3 bytes but several dumped tracks seem to contain only 2 bytes if (track_data[i] == 0xfc && track_data[i-1] == 0xc2 && track_data[i-2] == 0xc2) { iam_location = i - 3; break; } } int idam_index = 0; int dam_index = 0; for (int offset = TRACK_HEADER_SIZE; offset < TRACK_HEADER_SIZE + TRACK_SIZE; offset++) { if (offset == iam_location) { // Write IAM raw_w(raw_track_data, 16, 0x5224); raw_w(raw_track_data, 16, 0x5224); raw_w(raw_track_data, 16, 0x5224); offset += 3; } if (offset == idam_location[idam_index]) { raw_w(raw_track_data, 16, 0x4489); raw_w(raw_track_data, 16, 0x4489); raw_w(raw_track_data, 16, 0x4489); idam_index += 1; offset += 3; } if (offset == dam_location[dam_index]) { raw_w(raw_track_data, 16, 0x4489); raw_w(raw_track_data, 16, 0x4489); raw_w(raw_track_data, 16, 0x4489); dam_index += 1; offset += 3; } mfm_w(raw_track_data, 8, track_data[offset]); } generate_track_from_levels(track, head, raw_track_data, 0, image); } } return true; } bool sdf_format::save(io_generic *io, floppy_image *image) { return false; } bool sdf_format::supports_save() const { return false; } const floppy_format_type FLOPPY_SDF_FORMAT = &floppy_image_format_creator;