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 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 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 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; }