bool g64_format::save(io_generic *io, floppy_image *image) { int tracks, heads; image->get_actual_geometry(tracks, heads); tracks = TRACK_COUNT * heads; // write header UINT8 header[] = { 'G', 'C', 'R', '-', '1', '5', '4', '1', 0x00, tracks, TRACK_LENGTH & 0xff, TRACK_LENGTH >> 8 }; io_generic_write(io, header, POS_SIGNATURE, sizeof(header)); // write tracks for (int head = 0; head < heads; head++) { int tracks_written = 0; dynamic_buffer trackbuf(TRACK_LENGTH-2); for (int track = 0; track < TRACK_COUNT; track++) { UINT32 tpos = POS_TRACK_OFFSET + (track * 4); UINT32 spos = tpos + (tracks * 4); UINT32 dpos = POS_TRACK_OFFSET + (tracks * 4 * 2) + (tracks_written * TRACK_LENGTH); io_generic_write_filler(io, 0x00, tpos, 4); io_generic_write_filler(io, 0x00, spos, 4); if (image->get_buffer(track, head).size() <= 1) continue; int track_size; int speed_zone; // figure out the cell size and speed zone from the track data if ((speed_zone = generate_bitstream(track, head, 3, &trackbuf[0], track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 2, &trackbuf[0], track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 1, &trackbuf[0], track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 0, &trackbuf[0], track_size, image)) == -1) throw emu_fatalerror("g64_format: Cannot determine speed zone for track %u", track); LOG_FORMATS("head %u track %u size %u cell %u\n", head, track, track_size, c1541_cell_size[speed_zone]); UINT8 track_offset[4]; UINT8 speed_offset[4]; UINT8 track_length[2]; place_integer_le(track_offset, 0, 4, dpos); place_integer_le(speed_offset, 0, 4, speed_zone); place_integer_le(track_length, 0, 2, track_size/8); io_generic_write(io, track_offset, tpos, 4); io_generic_write(io, speed_offset, spos, 4); io_generic_write_filler(io, 0xff, dpos, TRACK_LENGTH); io_generic_write(io, track_length, dpos, 2); io_generic_write(io, &trackbuf[0], dpos + 2, track_size); tracks_written++; } } return true; }
bool mfi_format::save(io_generic *io, floppy_image *image) { int tracks, heads; image->get_actual_geometry(tracks, heads); int max_track_size = 0; for(int track=0; track<tracks; track++) for(int head=0; head<heads; head++) { int tsize = image->get_track_size(track, head); if(tsize > max_track_size) max_track_size = tsize; } header h; entry entries[84*2]; memcpy(h.sign, sign, 16); h.cyl_count = tracks; h.head_count = heads; io_generic_write(io, &h, 0, sizeof(header)); memset(entries, 0, sizeof(entries)); int pos = sizeof(header) + tracks*heads*sizeof(entry); int epos = 0; UINT32 *precomp = global_alloc_array(UINT32, max_track_size); UINT8 *postcomp = global_alloc_array(UINT8, max_track_size*4 + 1000); for(int track=0; track<tracks; track++) for(int head=0; head<heads; head++) { int tsize = image->get_track_size(track, head); if(!tsize) { epos++; continue; } memcpy(precomp, image->get_buffer(track, head), tsize*4); for(int j=0; j<tsize-1; j++) precomp[j] = (precomp[j] & floppy_image::MG_MASK) | ((precomp[j+1] & floppy_image::TIME_MASK) - (precomp[j] & floppy_image::TIME_MASK)); precomp[tsize-1] = (precomp[tsize-1] & floppy_image::MG_MASK) | (200000000 - (precomp[tsize-1] & floppy_image::TIME_MASK)); uLongf csize = max_track_size*4 + 1000; if(compress(postcomp, &csize, (const Bytef *)precomp, tsize*4) != Z_OK) return false; entries[epos].offset = pos; entries[epos].uncompressed_size = tsize*4; entries[epos].compressed_size = csize; epos++; io_generic_write(io, postcomp, pos, csize); pos += csize; } io_generic_write(io, entries, sizeof(header), tracks*heads*sizeof(entry)); return true; }
bool g64_format::save(io_generic *io, floppy_image *image) { UINT8 header[] = { 'G', 'C', 'R', '-', '1', '5', '4', '1', 0x00, 0x54, TRACK_LENGTH & 0xff, TRACK_LENGTH >> 8 }; io_generic_write(io, header, SIGNATURE, sizeof(header)); int head = 0; int tracks_written = 0; for (int track = 0; track < 84; track++) { offs_t tpos = TRACK_OFFSET + track * 4; offs_t spos = SPEED_ZONE + track * 4; offs_t dpos = TRACK_DATA + tracks_written * TRACK_LENGTH; io_generic_write_filler(io, 0x00, tpos, 4); io_generic_write_filler(io, 0x00, spos, 4); if (image->get_track_size(track, head) <= 1) continue; UINT8 *trackbuf = global_alloc_array(UINT8, TRACK_LENGTH-2); int track_size; int speed_zone; // figure out the cell size and speed zone from the track data if ((speed_zone = generate_bitstream(track, head, 3, trackbuf, track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 2, trackbuf, track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 1, trackbuf, track_size, image)) == -1) if ((speed_zone = generate_bitstream(track, head, 0, trackbuf, track_size, image)) == -1) throw emu_fatalerror("g64_format: Cannot determine speed zone for track %u", track); LOG_FORMATS("track %u size %u cell %u\n", track, track_size, c1541_cell_size[speed_zone]); UINT8 track_offset[4]; UINT8 speed_offset[4]; UINT8 track_length[2]; place_integer_le(track_offset, 0, 4, dpos); place_integer_le(speed_offset, 0, 4, speed_zone); place_integer_le(track_length, 0, 2, track_size/8); io_generic_write(io, track_offset, tpos, 4); io_generic_write(io, speed_offset, spos, 4); io_generic_write_filler(io, 0xff, dpos, TRACK_LENGTH); io_generic_write(io, track_length, dpos, 2); io_generic_write(io, trackbuf, dpos + 2, track_size); tracks_written++; global_free(trackbuf); } return true; }
bool vdk_format::save(io_generic *io, floppy_image *image) { uint8_t bitstream[500000/8]; uint8_t sector_data[50000]; desc_xs sectors[256]; uint64_t file_offset = 0; int track_count, head_count; image->get_actual_geometry(track_count, head_count); // write header uint8_t header[12]; header[0] = 'd'; header[1] = 'k'; header[2] = sizeof(header) % 0x100; header[3] = sizeof(header) / 0x100; header[4] = 0x10; header[5] = 0x10; header[6] = 'M'; header[7] = 0x01; header[8] = track_count; header[9] = head_count; header[10] = 0; header[11] = 0; io_generic_write(io, header, file_offset, sizeof(header)); file_offset += sizeof(header); // write disk data for (int track = 0; track < track_count; track++) { for (int head = 0; head < head_count; head++) { int track_size; generate_bitstream_from_track(track, head, 2000, bitstream, track_size, image); extract_sectors_from_bitstream_mfm_pc(bitstream, track_size, sectors, sector_data, sizeof(sector_data)); for (int i = 0; i < SECTOR_COUNT; i++) { io_generic_write(io, sectors[FIRST_SECTOR_ID + i].data, file_offset, SECTOR_SIZE); file_offset += SECTOR_SIZE; } } } return true; }
bool esqimg_format::save(io_generic *io, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); if(track_count != 80) track_count = 80; // Happens for a fully unformatted floppy if(!head_count) head_count = 2; if(sector_count != 10) sector_count = 10; UINT8 sectdata[11*512]; int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); } } return true; }
bool st_format::save(io_generic *io, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); if(track_count < 80) track_count = 80; else if(track_count > 82) track_count = 82; // Happens for a fully unformatted floppy if(!head_count) head_count = 1; if(sector_count > 11) sector_count = 11; else if(sector_count < 9) sector_count = 9; uint8_t sectdata[11*512]; int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); } } return true; }
bool mfm_format::save(io_generic *io, floppy_image *image) { // TODO: HD support MFMIMG header; int track_count, head_count; image->get_actual_geometry(track_count, head_count); memcpy(&header.headername, MFM_FORMAT_HEADER, 7); header.number_of_track = track_count; header.number_of_side = head_count; header.floppyRPM = 0; header.floppyBitRate = 250; header.floppyiftype = 4; header.mfmtracklistoffset = sizeof(MFMIMG); io_generic_write(io, &header, 0, sizeof(MFMIMG)); int tpos = sizeof(MFMIMG); int dpos = tpos + track_count*head_count*sizeof(MFMTRACKIMG); UINT8 trackbuf[150000/8]; for(int track=0; track < track_count; track++) { for(int side=0; side < head_count; side++) { int track_size; generate_bitstream_from_track(track, side, 2000, trackbuf, track_size, image); track_size = (track_size+7)/8; MFMTRACKIMG trackdesc; trackdesc.track_number = track; trackdesc.side_number = side; trackdesc.mfmtracksize = track_size; trackdesc.mfmtrackoffset = dpos; io_generic_write(io, &trackdesc, tpos, sizeof(MFMTRACKIMG)); io_generic_write(io, trackbuf, dpos, track_size); tpos += sizeof(MFMTRACKIMG); dpos += track_size; } } return true; }
bool jvc_format::save(io_generic *io, floppy_image *image) { UINT8 bitstream[500000/8]; UINT8 sector_data[50000]; desc_xs sectors[256]; UINT64 file_offset = 0; int track_count, head_count; image->get_actual_geometry(track_count, head_count); // we'll write a header if the disk is two-sided if (head_count == 2) { UINT8 header[2]; header[0] = 18; header[1] = 2; io_generic_write(io, header, file_offset, sizeof(header)); file_offset += sizeof(header); } // write disk data for (int track = 0; track < track_count; track++) { for (int head = 0; head < head_count; head++) { int track_size; generate_bitstream_from_track(track, head, 2000, bitstream, track_size, image); extract_sectors_from_bitstream_mfm_pc(bitstream, track_size, sectors, sector_data, sizeof(sector_data)); for (int i = 0; i < 18; i++) { if (sectors[1 + i].size != 256) emu_fatalerror("jvc_format: invalid sector size: %d\n", sectors[1 + i].size); io_generic_write(io, sectors[1 + i].data, file_offset, sectors[1 + i].size); file_offset += sectors[1 + i].size; } } } return true; }
void io_generic_write_filler(struct io_generic *generic, UINT8 filler, UINT64 offset, size_t length) { UINT8 buffer[512]; size_t this_length; memset(buffer, filler, MIN(length, sizeof(buffer))); while(length > 0) { this_length = MIN(length, sizeof(buffer)); io_generic_write(generic, buffer, offset, this_length); offset += this_length; length -= this_length; } }
bool rx50img_format::save(io_generic *io, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); if(track_count != 80) track_count = 80; // Happens for a fully unformatted floppy if(!head_count) head_count = 1; if(sector_count == 9) // [VT180] 9 sector format : no save! return false; if(sector_count != 10) // either 8 or 10 sectors sector_count = 10; // [STANDARD] /* if(sector_count != 10) // either 8 or 10 sectors { if(sector_count == 8) { track_count = 40; // [DOS] } else { sector_count = 10; // [STANDARD] } } */ uint8_t sectdata[11*512]; int track_size = sector_count*512; for(int track=0; track < track_count; track++) { for(int head=0; head < head_count; head++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); io_generic_write(io, sectdata, (track*head_count + head)*track_size, track_size); } } return true; }
bool mgt_format::save(io_generic *io, floppy_image *image) { int track_count, head_count, sector_count; get_geometry_mfm_pc(image, 2000, track_count, head_count, sector_count); if(sector_count > 10) sector_count = 10; else if(sector_count < 9) sector_count = 9; uint8_t sectdata[10*512]; int track_size = sector_count*512; for(int head=0; head < 2; head++) { for(int track=0; track < 80; track++) { get_track_data_mfm_pc(track, head, image, 2000, 512, sector_count, sectdata); io_generic_write(io, sectdata, (head*80 + track)*track_size, track_size); } } return true; }
bool upd765_format::save(io_generic *io, floppy_image *image) { // Count the number of formats int formats_count; for(formats_count=0; formats[formats_count].form_factor; formats_count++); // Allocate the storage for the list of testable formats for a // given cell size int *candidates = global_alloc_array(int, formats_count); // Format we're finally choosing int chosen_candidate = -1; // Previously tested cell size int min_cell_size = 0; for(;;) { // Build the list of all formats for the immediatly superior cell size int cur_cell_size = 0; int candidates_count = 0; for(int i=0; i != formats_count; i++) { if(image->get_form_factor() == floppy_image::FF_UNKNOWN || image->get_form_factor() == formats[i].form_factor) { if(formats[i].cell_size == cur_cell_size) candidates[candidates_count++] = i; else if((!cur_cell_size || formats[i].cell_size < cur_cell_size) && formats[i].cell_size > min_cell_size) { candidates[0] = i; candidates_count = 1; cur_cell_size = formats[i].cell_size; } } } min_cell_size = cur_cell_size; // No candidates with a cell size bigger than the previously // tested one, we're done if(!candidates_count) break; // Filter with track 0 head 0 check_compatibility(image, candidates, candidates_count); // Nobody matches, try with the next cell size if(!candidates_count) continue; // We have a match at that cell size, we just need to find the // best one given the geometry // If there's only one, we're done if(candidates_count == 1) { chosen_candidate = candidates[0]; break; } // Otherwise, find the best int tracks, heads; image->get_actual_geometry(tracks, heads); chosen_candidate = candidates[0]; for(int i=1; i != candidates_count; i++) { const format &cc = formats[chosen_candidate]; const format &cn = formats[candidates[i]]; // Handling enough sides is better than not if(cn.head_count >= heads && cc.head_count < heads) goto change; else if(cc.head_count >= heads && cn.head_count < heads) goto dont_change; // Since we're limited to two heads, at that point head // count is identical for both formats. // Handling enough tracks is better than not if(cn.track_count >= tracks && cc.track_count < tracks) goto change; else if(cn.track_count >= tracks && cc.track_count < tracks) goto dont_change; // Both are on the same side of the track count, so closest is best if(cc.track_count < tracks && cn.track_count > cc.track_count) goto change; if(cc.track_count >= tracks && cn.track_count < cc.track_count) goto change; goto dont_change; change: chosen_candidate = candidates[i]; dont_change: ; } // We have a winner, bail out break; } // No match, pick the first one and be done with it if(chosen_candidate == -1) chosen_candidate = 0; const format &f = formats[chosen_candidate]; int track_size = compute_track_size(f); UINT8 sectdata[40*512]; desc_s sectors[40]; build_sector_description(f, sectdata, sectors); for(int track=0; track < f.track_count; track++) for(int head=0; head < f.head_count; head++) { extract_sectors(image, f, sectors, track, head); io_generic_write(io, sectdata, (track*f.head_count + head)*track_size, track_size); } return true; }
void floppy_image_write(floppy_image *floppy, const void *buffer, UINT64 offset, size_t length) { io_generic_write(&floppy->io, buffer, offset, length); }
bool wd177x_format::save(io_generic *io, floppy_image *image) { // Count the number of formats int formats_count; for(formats_count=0; formats[formats_count].form_factor; formats_count++) {}; // Allocate the storage for the list of testable formats for a // given cell size std::vector<int> candidates; // Format we're finally choosing int chosen_candidate = -1; // Previously tested cell size int min_cell_size = 0; for(;;) { // Build the list of all formats for the immediately superior cell size int cur_cell_size = 0; candidates.clear(); for(int i=0; i != formats_count; i++) { if(image->get_form_factor() == floppy_image::FF_UNKNOWN || image->get_form_factor() == formats[i].form_factor) { if(formats[i].cell_size == cur_cell_size) candidates.push_back(i); else if((!cur_cell_size || formats[i].cell_size < cur_cell_size) && formats[i].cell_size > min_cell_size) { candidates.clear(); candidates.push_back(i); cur_cell_size = formats[i].cell_size; } } } min_cell_size = cur_cell_size; // No candidates with a cell size bigger than the previously // tested one, we're done if(candidates.empty()) break; // Filter with track 0 head 0 check_compatibility(image, candidates); // Nobody matches, try with the next cell size if(candidates.empty()) continue; // We have a match at that cell size, we just need to find the // best one given the geometry // If there's only one, we're done if(candidates.size() == 1) { chosen_candidate = candidates[0]; break; } // Otherwise, find the best int tracks, heads; image->get_actual_geometry(tracks, heads); chosen_candidate = candidates[0]; for(unsigned int i=1; i != candidates.size(); i++) { const format &cc = formats[chosen_candidate]; const format &cn = formats[candidates[i]]; // Handling enough sides is better than not if(cn.head_count >= heads && cc.head_count < heads) goto change; else if(cc.head_count >= heads && cn.head_count < heads) goto dont_change; // Handling enough tracks is better than not if(cn.track_count >= tracks && cc.track_count < tracks) goto change; else if(cc.track_count >= tracks && cn.track_count < tracks) goto dont_change; // Both are on the same side of the track count, so closest is best if(cc.track_count < tracks && cn.track_count > cc.track_count) goto change; if(cc.track_count >= tracks && cn.track_count < cc.track_count) goto change; // Lower number of heads is better if (cn.head_count < cc.head_count && cn.head_count <= heads) goto change; goto dont_change; change: chosen_candidate = candidates[i]; dont_change: ; } // We have a winner, bail out break; } // No match, pick the first one and be done with it if(chosen_candidate == -1) chosen_candidate = 0; const format &f = formats[chosen_candidate]; int track_size = compute_track_size(f); uint8_t sectdata[40*512]; desc_s sectors[40]; for(int track=0; track < f.track_count; track++) for(int head=0; head < f.head_count; head++) { build_sector_description(f, sectdata, sectors, track, head); extract_sectors(image, f, sectors, track, head); io_generic_write(io, sectdata, get_image_offset(f, head, track), track_size); } return true; }