bool dip_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { int heads, tracks, spt, bps; //For the moment we only support this disk structure... //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) heads = 2; tracks = 77; spt = 8; bps = 1024; int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; int ssize; for (ssize = 0; (128 << ssize) < bps; ssize++); desc_pc_sector sects[256]; UINT8 sect_data[65536]; for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { io_generic_read(io, sect_data, 0x100 + bps * spt * (track * heads + head), bps * spt); for (int i = 0; i < spt; i++) { sects[i].track = track; sects[i].head = head; sects[i].sector = i + 1; sects[i].size = ssize; sects[i].actual_size = bps; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * bps; } build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); } return true; }
bool pc98fdi_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 h[32]; io_generic_read(io, h, 0, 32); UINT32 hsize = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x8)); UINT32 sector_size = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x10)); UINT32 sector_count = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x14)); UINT32 head_count = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x18)); UINT32 track_count = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x1c)); int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; int ssize; for(ssize=0; (128 << ssize) < sector_size; ssize++); desc_pc_sector sects[256]; UINT8 sect_data[65536]; for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { io_generic_read(io, sect_data, hsize + sector_size*sector_count*(track*head_count + head), sector_size*sector_count); for(int i=0; i<sector_count; i++) { sects[i].track = track; sects[i].head = head; sects[i].sector = i+1; sects[i].size = ssize; sects[i].actual_size = sector_size; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i*sector_size; } build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sector_size)); } return true; }
bool imd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT64 size = io_generic_size(io); UINT8 *img = global_alloc_array(UINT8, size); io_generic_read(io, img, 0, size); UINT64 pos; for(pos=0; pos < size && img[pos] != 0x1a; pos++); pos++; if(pos >= size) return false; while(pos < size) { UINT8 mode = img[pos++]; UINT8 track = img[pos++]; UINT8 head = img[pos++]; UINT8 sector_count = img[pos++]; UINT8 ssize = img[pos++]; if(ssize == 0xff) throw emu_fatalerror("imd_format: Unsupported variable sector size on track %d head %d", track, head); UINT32 actual_size = ssize < 7 ? 128 << ssize : 8192; static const int rates[3] = { 500000, 300000, 250000 }; bool fm = mode < 3; int rate = rates[mode % 3]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int cell_count = (fm ? 1 : 2)*rate*60/rpm; const UINT8 *snum = img+pos; pos += sector_count; const UINT8 *tnum = head & 0x80 ? img+pos : NULL; if(tnum) pos += sector_count; const UINT8 *hnum = head & 0x40 ? img+pos : NULL; if(hnum) pos += sector_count; head &= 0x3f; int gap_3 = calc_default_pc_gap3_size(form_factor, actual_size); desc_pc_sector sects[256]; for(int i=0; i<sector_count; i++) { UINT8 stype = img[pos++]; sects[i].track = tnum ? tnum[i] : track; sects[i].head = hnum ? hnum[i] : head; sects[i].sector = snum[i]; sects[i].size = ssize; sects[i].actual_size = actual_size; if(stype == 0 || stype > 8) { sects[i].data = NULL; } else { sects[i].deleted = stype == 3 || stype == 4 || stype == 7 || stype == 8; sects[i].bad_crc = stype == 5 || stype == 6 || stype == 7 || stype == 8; if(stype == 2 || stype == 4 || stype == 6 || stype == 8) { sects[i].data = global_alloc_array(UINT8, actual_size); memset(sects[i].data, img[pos++], actual_size); } else { sects[i].data = img + pos; pos += actual_size; } } } if(fm) build_pc_track_fm(track, head, image, cell_count, sector_count, sects, gap_3); else build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, gap_3); for(int i=0; i<sector_count; i++) if(sects[i].data && (sects[i].data < img || sects[i].data >= img+size)) global_free(sects[i].data); } global_free(img); return true; }
bool d88_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint8_t h[32]; io_generic_read(io, h, 0, 32); int cell_count = 0; int track_count = 0; int head_count = 0; switch(h[0x1b]) { case 0x00: cell_count = 100000; track_count = 42; head_count = 2; image->set_variant(floppy_image::DSDD); break; case 0x10: cell_count = 100000; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSQD); break; case 0x20: cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSHD); break; case 0x30: cell_count = 100000; track_count = 42; head_count = 1; image->set_variant(floppy_image::SSDD); break; case 0x40: cell_count = 100000; track_count = 82; head_count = 1; image->set_variant(floppy_image::SSQD); break; } if(!head_count) return false; uint32_t track_pos[164]; io_generic_read(io, track_pos, 32, 164*4); for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { int pos = little_endianize_int32(track_pos[track * head_count + head]); if(!pos) continue; desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; int sector_count = 1; for(int i=0; i<sector_count; i++) { uint8_t hs[16]; io_generic_read(io, hs, pos, 16); pos += 16; uint16_t size = little_endianize_int16(*(uint16_t *)(hs+14)); if(i == 0) { sector_count = little_endianize_int16(*(uint16_t *)(hs+4)); // Support broken vfman converter if(sector_count == 0x1000) sector_count = 0x10; } sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].actual_size = size; sects[i].deleted = hs[7] != 0; sects[i].bad_crc = false; if(size) { sects[i].data = sect_data + sdatapos; io_generic_read(io, sects[i].data, pos, size); pos += size; sdatapos += size; } else sects[i].data = nullptr; } build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); } return true; }
bool dcp_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 h[0xa2]; int heads, tracks, spt, bps; bool is_hdb = false; io_generic_read(io, h, 0, 0xa2); // First byte is the disk format: switch (h[0]) { case 0x01: default: //01h: 2HD-8 sector (1.25MB) (BKDSK .HDM) (aka 2HS) //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) heads = 2; tracks = 77; spt = 8; bps = 1024; break; case 0x02: //02H: 2HD-15 sector (1.21MB) (BKDSK .HD5) (aka 2HC) //2 sides, 80 tracks, 15 sectors/track, 512 bytes/sector = 1228800 bytes (360rpm) heads = 2; tracks = 80; spt = 15; bps = 512; break; case 0x03: //03H: 2HQ-18 sector (1.44MB) (BKDSK .HD4) (aka 2HDE) //2 sides, 80 tracks, 18 sectors/track, 512 bytes/sector = 1474560 bytes (300rpm) heads = 2; tracks = 80; spt = 18; bps = 512; break; case 0x04: //04H: 2DD-8 sector (640KB) (BKDSK .DD6) //2 sides, 80 tracks, 8 sectors/track, 512 bytes/sector = 655360 bytes (300rpm) heads = 2; tracks = 80; spt = 8; bps = 512; break; case 0x05: //05h: 2DD-9 sector ( 720KB) (BKDSK .DD9) //2 sides, 80 tracks, 9 sectors/track, 512 bytes/sector = 737280 bytes (300rpm) heads = 2; tracks = 80; spt = 9; bps = 512; break; case 0x08: //08h: 2HD-9 sector (1.44MB) //2 sides, 80 tracks, 9 sectors/track, 1024 bytes/sector = 1474560 bytes (300rpm)(??) heads = 2; tracks = 80; spt = 9; bps = 1024; break; case 0x11: //11h: BASIC-2HD (BKDSK .HDB) //Head 0 Track 0 - FM encoding - 26 sectors of 128 bytes = 1 track //Head 1 Track 0 - MFM encoding - 26 sectors of 256 bytes = 1 track //Head 0 Track 1 to Head 1 Track 77 - 26 sectors of 256 bytes = 152 tracks //2 sides, 77 tracks, 26 sectors/track, 256 bytes/sector (except for head 0 track 0) = 1021696 bytes (360rpm) is_hdb = true; heads = 2; tracks = 77; spt = 26; bps = 256; break; case 0x19: //19h: BASIC 2DD (BKDSK .DDB) //2 sides, 80 tracks, 16 sectors/track, 256 bytes/sector = 655360 bytes (300rpm) heads = 2; tracks = 80; spt = 16; bps = 256; break; case 0x21: //21H: 2HD-26 sector //2 sides, 80 tracks, 26 sectors/track, 256 bytes/sector = 1064960 bytes (??rpm)(??) heads = 2; tracks = 80; spt = 26; bps = 256; break; } int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; int ssize; for (ssize = 0; (128 << ssize) < bps; ssize++); desc_pc_sector sects[256]; UINT8 sect_data[65536]; if (!is_hdb) { for (int track = 0; track < tracks; track++) for (int head = 0; head < heads; head++) { io_generic_read(io, sect_data, 0xa2 + bps * spt * (track * heads + head), bps * spt); for (int i = 0; i < spt; i++) { sects[i].track = track; sects[i].head = head; sects[i].sector = i + 1; sects[i].size = ssize; sects[i].actual_size = bps; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * bps; } build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); } } else // FIXME: the code below is untested, because no image was found... there might be some silly mistake in the disk geometry! { // Read Head 0 Track 0 is FM with 26 sectors of 128bytes instead of 256 io_generic_read(io, sect_data, 0xa2, 128 * spt); for (int i = 0; i < spt; i++) { sects[i].track = 0; sects[i].head = 0; sects[i].sector = i + 1; sects[i].size = 0; sects[i].actual_size = 128; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * 128; } build_pc_track_fm(0, 0, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, 128)); // Read Head 1 Track 0 is MFM with 26 sectors of 256bytes io_generic_read(io, sect_data, 0xa2 + 128 * spt, bps * spt); for (int i = 0; i < spt; i++) { sects[i].track = 0; sects[i].head = 1; sects[i].sector = i + 1; sects[i].size = ssize; sects[i].actual_size = bps; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * bps; } build_pc_track_mfm(0, 1, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); // Read other tracks as usual UINT32 data_offs = 0xa2 + (26 * 0x80) + (26 * 0x100); for (int track = 1; track < tracks; track++) for (int head = 0; head < heads; head++) { io_generic_read(io, sect_data, data_offs + bps * spt * ((track - 1) * heads + head), bps * spt); for (int i = 0; i < spt; i++) { sects[i].track = track; sects[i].head = head; sects[i].sector = i + 1; sects[i].size = ssize; sects[i].actual_size = bps; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * bps; } build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); } } return true; }
bool d88_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 h[32]; io_generic_read(io, h, 0, 32); int cell_count = 0; int track_count = 0; int head_count = 0; switch(h[0x1b]) { case 0x00: cell_count = 100000; track_count = 42; head_count = 2; image->set_variant(floppy_image::DSDD); break; case 0x10: cell_count = 100000; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSQD); break; case 0x20: cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; track_count = 82; head_count = 2; image->set_variant(floppy_image::DSHD); break; case 0x30: cell_count = 100000; track_count = 42; head_count = 1; image->set_variant(floppy_image::SSDD); break; case 0x40: cell_count = 100000; track_count = 82; head_count = 1; image->set_variant(floppy_image::SSQD); break; } if(!head_count) return false; UINT32 track_pos[164]; io_generic_read(io, track_pos, 32, 164*4); for(int track=0; track < track_count; track++) for(int head=0; head < head_count; head++) { int pos = LITTLE_ENDIANIZE_INT32(track_pos[track * head_count + head]); if(!pos) continue; desc_pc_sector sects[256]; UINT8 sect_data[65536]; int sdatapos = 0; int sector_count = 1; for(int i=0; i<sector_count; i++) { UINT8 hs[16]; io_generic_read(io, hs, pos, 16); pos += 16; UINT16 size = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hs+14)); if(i == 0) sector_count = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hs+4)); sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].actual_size = size; sects[i].deleted = hs[7] != 0; sects[i].bad_crc = false; if(size) { sects[i].data = sect_data + sdatapos; io_generic_read(io, sects[i].data, pos, size); pos += size; sdatapos += size; } else sects[i].data = NULL; } build_pc_track_mfm(track, head, image, cell_count, sector_count, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); } return true; }
bool fdd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 hsec[0x0c]; // sector map UINT8 num_secs[160]; UINT8 tracks[160 * 26]; UINT8 heads[160 * 26]; UINT8 secs[160 * 26]; UINT8 fill_vals[160 * 26]; UINT32 sec_offs[160 * 26]; UINT8 sec_sizes[160 * 26]; int pos = 0xdc; for (int track = 0; track < 160; track++) { int curr_num_sec = 0, curr_track_size = 0; for (int sect = 0; sect < 26; sect++) { // read sector map for this sector io_generic_read(io, hsec, pos, 0x0c); pos += 0x0c; if (hsec[0] == 0xff) // unformatted/unused sector continue; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; fill_vals[(track * 26) + sect] = hsec[4]; sec_offs[(track * 26) + sect] = little_endianize_int32(*(UINT32 *)(hsec + 0x08)); curr_track_size += (128 << hsec[3]); curr_num_sec++; } num_secs[track] = curr_num_sec; } int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; desc_pc_sector sects[256]; UINT8 sect_data[65536]; int cur_sec_map = 0, sector_size; for (int track = 0; track < 160; track++) { int cur_pos = 0; for (int i = 0; i < num_secs[track]; i++) { cur_sec_map = track * 26 + i; sector_size = 128 << sec_sizes[cur_sec_map]; if (sec_offs[cur_sec_map] == 0xffffffff) memset(sect_data + cur_pos, fill_vals[cur_sec_map], sector_size); else io_generic_read(io, sect_data + cur_pos, sec_offs[cur_sec_map], sector_size); sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; sects[i].sector = secs[cur_sec_map]; sects[i].size = sec_sizes[cur_sec_map]; sects[i].actual_size = sector_size; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + cur_pos; cur_pos += sector_size; } build_pc_track_mfm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); } return true; }
bool dsk_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { UINT8 header[0x100]; bool extendformat = FALSE; UINT64 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]; UINT64 track_offsets[84*2]; int cnt =0; if (!extendformat) { int tmp = 0x100; for (int i=0; i<tracks * heads; i++) { track_offsets[cnt] = tmp; tmp += pick_integer_le(header, 0x32, 2); cnt += skip; } } else { int tmp = 0x100; for (int i=0; i<tracks * heads; i++) { int length = header[0x34 + i] << 8; if (length != 0) { track_offsets[cnt] = tmp; tmp += length; } else { track_offsets[cnt] = image_size; } cnt += skip; } } int counter = 0; for(int track=0; track < tracks; track++) { for(int side=0; side < heads; side++) { if(track_offsets[(track<<1)+side] >= image_size) continue; track_header tr; io_generic_read(io, &tr,track_offsets[(track<<1)+side],sizeof(tr)); desc_pc_sector sects[256]; UINT8 sect_data[65536]; int sdatapos = 0; int pos = track_offsets[(track<<1)+side] + 0x100; for(int j=0;j<tr.number_of_sector;j++) { sector_header sector; io_generic_read(io, §or,track_offsets[(track<<1)+side]+sizeof(tr)+(sizeof(sector)*j),sizeof(sector)); sects[j].track = sector.track; sects[j].head = sector.side; sects[j].sector = sector.sector_id; sects[j].size = sector.sector_size_code; if(extendformat) sects[j].actual_size = sector.data_length; else sects[j].actual_size = 128 << tr.sector_size_code; sects[j].deleted = sector.fdc_status_reg1 == 0xb2; sects[j].bad_crc = sector.fdc_status_reg1 == 0xb5; if(!sects[j].deleted) { sects[j].data = sect_data + sdatapos; io_generic_read(io, sects[j].data, pos, sects[j].actual_size); sdatapos += sects[j].actual_size; } else sects[j].data = NULL; if(extendformat) pos += sector.data_length; else pos += 128 << tr.sector_size_code; } build_pc_track_mfm(track, side, image, 100000, tr.number_of_sector, sects, tr.gap3_length); counter++; } } return true; }
bool td0_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { int track_count = 0; int head_count = 0; int track_spt; int offset = 0; const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy std::vector<uint8_t> imagebuf(max_size); uint8_t header[12]; io_generic_read(io, header, 0, 12); head_count = header[9]; if(header[0] == 't') { td0dsk_t disk_decode; disk_decode.floppy_file = io; disk_decode.init_Decode(); disk_decode.floppy_file_offset = 12; disk_decode.Decode(&imagebuf[0], max_size); } else io_generic_read(io, &imagebuf[0], 12, io_generic_size(io)); if(header[7] & 0x80) offset = 10 + imagebuf[2] + (imagebuf[3] << 8); track_spt = imagebuf[offset]; if(track_spt == 255) // Empty file? return false; switch(header[6]) { case 2: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) image->set_variant(floppy_image::DSHD); else return false; // single side hd? break; } /* no break; could be qd, won't know until tracks are counted */ case 1: if(head_count == 2) image->set_variant(floppy_image::DSDD); else image->set_variant(floppy_image::SSDD); break; case 4: if((imagebuf[offset + 2] & 0x7f) == 2) // ? { if(head_count == 2) image->set_variant(floppy_image::DSHD); else return false; // single side 3.5? break; } else image->set_variant(floppy_image::SSDD); break; /* no break */ case 3: if(head_count == 2) { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::DSQD); else image->set_variant(floppy_image::DSDD); } else { if(form_factor == floppy_image::FF_525) image->set_variant(floppy_image::SSQD); else return false; // single side 3.5? } break; } static const int rates[3] = { 250000, 300000, 500000 }; int rate = (header[5] & 0x7f) >= 3 ? 500000 : rates[header[5] & 0x7f]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; while(track_spt != 255) { desc_pc_sector sects[256]; uint8_t sect_data[65536]; int sdatapos = 0; int track = imagebuf[offset + 1]; int head = imagebuf[offset + 2] & 1; bool fm = (header[5] & 0x80) || (imagebuf[offset + 2] & 0x80); // ? offset += 4; for(int i = 0; i < track_spt; i++) { uint8_t *hs = &imagebuf[offset]; uint16_t size; offset += 6; sects[i].track = hs[0]; sects[i].head = hs[1]; sects[i].sector = hs[2]; sects[i].size = hs[3]; sects[i].deleted = (hs[4] & 4) == 4; sects[i].bad_crc = (hs[4] & 2) == 2; if(hs[4] & 0x30) size = 0; else { offset += 3; size = 128 << hs[3]; int j, k; switch(hs[8]) { default: return false; case 0: memcpy(§_data[sdatapos], &imagebuf[offset], size); offset += size; break; case 1: offset += 4; k = (hs[9] + (hs[10] << 8)) * 2; k = (k <= size) ? k : size; for(j = 0; j < k; j += 2) { sect_data[sdatapos + j] = hs[11]; sect_data[sdatapos + j + 1] = hs[12]; } if(k < size) memset(§_data[sdatapos + k], '\0', size - k); break; case 2: k = 0; while(k < size) { uint16_t len = imagebuf[offset]; uint16_t rep = imagebuf[offset + 1]; offset += 2; if(!len) { memcpy(§_data[sdatapos + k], &imagebuf[offset], rep); offset += rep; k += rep; } else { len = (1 << len); rep = len * rep; rep = ((rep + k) <= size) ? rep : (size - k); for(j = 0; j < rep; j += len) memcpy(§_data[sdatapos + j + k], &imagebuf[offset], len); k += rep; offset += len; } } break; } } sects[i].actual_size = size; if(size) { sects[i].data = §_data[sdatapos]; sdatapos += size; } else sects[i].data = nullptr; } track_count = track; if(fm) build_pc_track_fm(track, head, image, base_cell_count, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); else build_pc_track_mfm(track, head, image, base_cell_count*2, track_spt, sects, calc_default_pc_gap3_size(form_factor, sects[0].actual_size)); track_spt = imagebuf[offset]; } if((track_count > 50) && (form_factor == floppy_image::FF_525)) // ? { if(image->get_variant() == floppy_image::DSDD) image->set_variant(floppy_image::DSQD); else if(image->get_variant() == floppy_image::SSDD) image->set_variant(floppy_image::SSQD); } return true; }
bool cqm_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) { const int max_size = 4*1024*1024; // 4MB ought to be large enough for any floppy dynamic_buffer imagebuf(max_size); UINT8 header[CQM_HEADER_SIZE]; io_generic_read(io, header, 0, CQM_HEADER_SIZE); int sector_size = (header[0x04] << 8) | header[0x03]; int sector_per_track = (header[0x11] << 8) | header[0x10]; int heads = (header[0x13] << 8) | header[0x12]; int tracks = header[0x5b]; // int blind = header[0x58]; // 0=DOS, 1=blind, 2=HFS int density = header[0x59]; // 0=DD, 1=HD, 2=ED int comment_size = (header[0x70] << 8) | header[0x6f]; int sector_base = header[0x71] + 1; // int interleave = header[0x74]; // TODO // int skew = header[0x75]; // TODO // int drive = header[0x76]; // source drive type: 1=5.25" 360KB, 2=5.25" 1.2MB, 3=3.5" 720KB, 4=3.5" 1.44MB, 6=3.5" 2.88MB, 8" is unknown (0 or 5?) switch(density) { case 0: if (form_factor == floppy_image::FF_525 && tracks > 50) image->set_variant(heads == 1 ? floppy_image::SSQD : floppy_image::DSQD); else image->set_variant(heads == 1 ? floppy_image::SSDD : floppy_image::DSDD); break; case 1: if (heads == 1) return false; // single side HD ? image->set_variant(floppy_image::DSHD); break; case 2: if (heads == 1) return false; // single side ED ? image->set_variant(floppy_image::DSED); default: return false; } static const int rates[3] = { 250000, 300000, 500000 }; int rate = density >= 3 ? 500000 : rates[density]; int rpm = form_factor == floppy_image::FF_8 || (form_factor == floppy_image::FF_525 && rate >= 300000) ? 360 : 300; int base_cell_count = rate*60/rpm; int cqm_size = io_generic_size(io); dynamic_buffer cqmbuf(cqm_size); io_generic_read(io, &cqmbuf[0], 0, cqm_size); // decode the RLE data for (int s = 0, pos = CQM_HEADER_SIZE + comment_size; pos < cqm_size; ) { INT16 len = (cqmbuf[pos + 1] << 8) | cqmbuf[pos]; pos += 2; if(len < 0) { len = -len; memset(&imagebuf[s], cqmbuf[pos], len); pos++; } else { memcpy(&imagebuf[s], &cqmbuf[pos], len); pos += len; } s += len; } int ssize; for(ssize=0; (128 << ssize) < sector_size; ssize++) ; desc_pc_sector sects[256]; for(int track = 0, pos = 0; track < tracks; track++) for(int head = 0; head < heads; head++) { for(int sector = 0; sector < sector_per_track; sector++) { sects[sector].track = track; sects[sector].head = head; sects[sector].sector = sector_base + sector; sects[sector].size = ssize; sects[sector].deleted = false; sects[sector].bad_crc = false; sects[sector].actual_size = sector_size; sects[sector].data = &imagebuf[pos]; pos += sector_size; } build_pc_track_mfm(track, head, image, base_cell_count*2, sector_per_track, sects, calc_default_pc_gap3_size(form_factor, sector_size)); } return true; }
bool nfd_format::load(io_generic *io, uint32_t form_factor, floppy_image *image) { uint64_t size = io_generic_size(io); uint8_t h[0x120], hsec[0x10]; io_generic_read(io, h, 0, 0x120); int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; // sector map (the 164th entry is only used by rev.1 format, loops with track < 163 are correct for rev.0) uint8_t disk_type = 0; uint8_t num_secs[164]; uint8_t num_specials[164]; uint32_t track_sizes[164]; uint8_t tracks[164 * 26]; uint8_t heads[164 * 26]; uint8_t secs[164 * 26]; uint8_t mfm[164 * 26]; uint8_t sec_sizes[164 * 26]; uint32_t hsize = little_endianize_int32(*(uint32_t *)(h+0x110)); int pos = 0x120; // set up sector map if (format_version == 1) { for (int track = 0; track < 164; track++) { int curr_track_size = 0; // read sector map absolute location io_generic_read(io, hsec, pos, 4); pos += 4; uint32_t secmap_addr = little_endianize_int32(*(uint32_t *)(hsec)); if (secmap_addr) { // read actual sector map for the sectors of this track // for rev.1 format the first 0x10 are a track summary: // first WORD is # of sectors, second WORD is # of special data sectors io_generic_read(io, hsec, secmap_addr, 0x10); secmap_addr += 0x10; num_secs[track] = little_endianize_int16(*(uint16_t *)(hsec)); num_specials[track] = little_endianize_int16(*(uint16_t *)(hsec + 0x2)); for (int sect = 0; sect < num_secs[track]; sect++) { io_generic_read(io, hsec, secmap_addr, 0x10); if (track == 0 && sect == 0) disk_type = hsec[0xb]; // can this change across the disk? I don't think so... secmap_addr += 0x10; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; mfm[(track * 26) + sect] = hsec[4]; curr_track_size += (128 << hsec[3]); } if (num_specials[track] > 0) { for (int sect = 0; sect < num_specials[track]; sect++) { io_generic_read(io, hsec, secmap_addr, 0x10); secmap_addr += 0x10; curr_track_size += (hsec[9] + 1) * little_endianize_int32(*(uint32_t *)(hsec + 0x0a)); } } } else { num_secs[track] = 0; num_specials[track] = 0; } track_sizes[track] = curr_track_size; } } else { for (int track = 0; track < 163 && pos < hsize; track++) { int curr_num_sec = 0, curr_track_size = 0; for (int sect = 0; sect < 26; sect++) { // read sector map for this sector // for rev.0 format each sector uses 0x10 bytes io_generic_read(io, hsec, pos, 0x10); if (track == 0 && sect == 0) disk_type = hsec[0xa]; // can this change across the disk? I don't think so... pos += 0x10; if (hsec[0] == 0xff) // unformatted/unused sector continue; tracks[(track * 26) + sect] = hsec[0]; heads[(track * 26) + sect] = hsec[1]; secs[(track * 26) + sect] = hsec[2]; sec_sizes[(track * 26) + sect] = hsec[3]; mfm[(track * 26) + sect] = hsec[4]; curr_track_size += (128 << hsec[3]); curr_num_sec++; } num_secs[track] = curr_num_sec; track_sizes[track] = curr_track_size; } } // shouln't this be set-up depending on disk_type? gaplus does not like having less than 166666 cells int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; switch (disk_type) { case 0x10: // 640K disk, 2DD image->set_variant(floppy_image::DSDD); break; //case 0x30: // 1.44M disk, ?? (no images found) // break; case 0x90: // 1.2M disk, 2HD default: image->set_variant(floppy_image::DSHD); break; } desc_pc_sector sects[256]; uint8_t sect_data[65536]; int cur_sec_map = 0, sector_size; pos = hsize; for (int track = 0; track < 163 && pos < size; track++) { io_generic_read(io, sect_data, pos, track_sizes[track]); for (int i = 0; i < num_secs[track]; i++) { cur_sec_map = track * 26 + i; sector_size = 128 << sec_sizes[cur_sec_map]; sects[i].track = tracks[cur_sec_map]; sects[i].head = heads[cur_sec_map]; sects[i].sector = secs[cur_sec_map]; sects[i].size = sec_sizes[cur_sec_map]; sects[i].actual_size = sector_size; sects[i].deleted = false; sects[i].bad_crc = false; sects[i].data = sect_data + i * sector_size; } pos += track_sizes[track]; // notice that the operation below might fail if sectors of the same track have variable sec_sizes, // because the gap3 calculation would account correctly only for the first sector... // examined images had constant sec_sizes in the each track, so probably this is not an issue if (mfm[track * 26]) build_pc_track_mfm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); else build_pc_track_fm(track / 2, track % 2, image, cell_count, num_secs[track], sects, calc_default_pc_gap3_size(form_factor, (128 << sec_sizes[track * 26]))); } return true; }