trunk/src/lib/formats/dcp_dsk.c
| r0 | r242337 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:etabeta |
| 3 | /********************************************************************* |
| 4 | |
| 5 | formats/dcp_dsk.h |
| 6 | |
| 7 | PC98 DCP & DCU disk images |
| 8 | |
| 9 | 0xA2 header, followed by track data |
| 10 | header[0] - disk format |
| 11 | header[1-0xA1] - track map (1=track used, 0=track unused/unformatted) |
| 12 | header[0xA2] - all tracks used? |
| 13 | (there seems to be a diff in its usage between DCP and DCU) |
| 14 | |
| 15 | TODO: |
| 16 | - add support for track map. images available for tests were all |
| 17 | of type 0x01, with all 154 tracks present. combined with pete_j |
| 18 | reporting some images have faulty track map, we need some more |
| 19 | test cases to properly handle these disks! |
| 20 | |
| 21 | *********************************************************************/ |
| 22 | |
| 23 | #include "emu.h" |
| 24 | #include "dcp_dsk.h" |
| 25 | |
| 26 | dcp_format::dcp_format() |
| 27 | { |
| 28 | } |
| 29 | |
| 30 | const char *dcp_format::name() const |
| 31 | { |
| 32 | return "dcx"; |
| 33 | } |
| 34 | |
| 35 | const char *dcp_format::description() const |
| 36 | { |
| 37 | return "DCP/DCU disk image"; |
| 38 | } |
| 39 | |
| 40 | const char *dcp_format::extensions() const |
| 41 | { |
| 42 | return "dcp,dcu"; |
| 43 | } |
| 44 | |
| 45 | int dcp_format::identify(io_generic *io, UINT32 form_factor) |
| 46 | { |
| 47 | UINT64 size = io_generic_size(io); |
| 48 | UINT8 h[0xa2]; |
| 49 | int heads, tracks, spt, bps, count_tracks = 0; |
| 50 | bool is_hdb = false; |
| 51 | |
| 52 | io_generic_read(io, h, 0, 0xa2); |
| 53 | |
| 54 | // First byte is the disk format (see below in load() for details) |
| 55 | switch (h[0]) |
| 56 | { |
| 57 | case 0x01: |
| 58 | default: |
| 59 | heads = 2; tracks = 77; |
| 60 | spt = 8; bps = 1024; |
| 61 | break; |
| 62 | case 0x02: |
| 63 | heads = 2; tracks = 80; |
| 64 | spt = 15; bps = 512; |
| 65 | break; |
| 66 | case 0x03: |
| 67 | heads = 2; tracks = 80; |
| 68 | spt = 18; bps = 512; |
| 69 | break; |
| 70 | case 0x04: |
| 71 | heads = 2; tracks = 80; |
| 72 | spt = 8; bps = 512; |
| 73 | break; |
| 74 | case 0x05: |
| 75 | heads = 2; tracks = 80; |
| 76 | spt = 9; bps = 512; |
| 77 | break; |
| 78 | case 0x08: |
| 79 | heads = 2; tracks = 80; |
| 80 | spt = 9; bps = 1024; |
| 81 | break; |
| 82 | case 0x11: |
| 83 | is_hdb = true; |
| 84 | heads = 2; tracks = 77; |
| 85 | spt = 26; bps = 256; |
| 86 | break; |
| 87 | case 0x19: |
| 88 | heads = 2; tracks = 80; |
| 89 | spt = 16; bps = 256; |
| 90 | break; |
| 91 | case 0x21: |
| 92 | heads = 2; tracks = 80; |
| 93 | spt = 26; bps = 256; |
| 94 | break; |
| 95 | } |
| 96 | |
| 97 | // bytes 0x01 to 0xa1 are track map (0x01 if track is used, 0x00 if track is unformatted/unused) |
| 98 | for (int i = 1; i < 0xa1; i++) |
| 99 | if (h[i]) |
| 100 | count_tracks++; |
| 101 | |
| 102 | // in theory track map should be enough (former check), but some images have it wrong! |
| 103 | // hence, if this check fails, we also allow for images with all tracks and wrong track map |
| 104 | if (size - 0xa2 == (heads * count_tracks * spt * bps) || size - 0xa2 == (heads * tracks * spt * bps)) |
| 105 | return 100; |
| 106 | |
| 107 | // for disk type 0x11 the head 0 track 0 has 26 sectors of half width, so we need to compensate calculation |
| 108 | if (is_hdb && (size - 0xa2 + (0x80 * 26) == (heads * count_tracks * spt * bps) || size - 0xa2 + (0x80 * 26) == (heads * tracks * spt * bps))) |
| 109 | return 100; |
| 110 | |
| 111 | return 0; |
| 112 | } |
| 113 | |
| 114 | bool dcp_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 115 | { |
| 116 | UINT8 h[0xa2]; |
| 117 | int heads, tracks, spt, bps; |
| 118 | bool is_hdb = false; |
| 119 | |
| 120 | io_generic_read(io, h, 0, 0xa2); |
| 121 | |
| 122 | // First byte is the disk format: |
| 123 | switch (h[0]) |
| 124 | { |
| 125 | case 0x01: |
| 126 | default: |
| 127 | //01h: 2HD-8 sector (1.25MB) (BKDSK .HDM) (aka 2HS) |
| 128 | //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) |
| 129 | heads = 2; |
| 130 | tracks = 77; |
| 131 | spt = 8; |
| 132 | bps = 1024; |
| 133 | break; |
| 134 | case 0x02: |
| 135 | //02H: 2HD-15 sector (1.21MB) (BKDSK .HD5) (aka 2HC) |
| 136 | //2 sides, 80 tracks, 15 sectors/track, 512 bytes/sector = 1228800 bytes (360rpm) |
| 137 | heads = 2; |
| 138 | tracks = 80; |
| 139 | spt = 15; |
| 140 | bps = 512; |
| 141 | break; |
| 142 | case 0x03: |
| 143 | //03H: 2HQ-18 sector (1.44MB) (BKDSK .HD4) (aka 2HDE) |
| 144 | //2 sides, 80 tracks, 18 sectors/track, 512 bytes/sector = 1474560 bytes (300rpm) |
| 145 | heads = 2; |
| 146 | tracks = 80; |
| 147 | spt = 18; |
| 148 | bps = 512; |
| 149 | break; |
| 150 | case 0x04: |
| 151 | //04H: 2DD-8 sector (640KB) (BKDSK .DD6) |
| 152 | //2 sides, 80 tracks, 8 sectors/track, 512 bytes/sector = 655360 bytes (300rpm) |
| 153 | heads = 2; |
| 154 | tracks = 80; |
| 155 | spt = 8; |
| 156 | bps = 512; |
| 157 | break; |
| 158 | case 0x05: |
| 159 | //05h: 2DD-9 sector ( 720KB) (BKDSK .DD9) |
| 160 | //2 sides, 80 tracks, 9 sectors/track, 512 bytes/sector = 737280 bytes (300rpm) |
| 161 | heads = 2; |
| 162 | tracks = 80; |
| 163 | spt = 9; |
| 164 | bps = 512; |
| 165 | break; |
| 166 | case 0x08: |
| 167 | //08h: 2HD-9 sector (1.44MB) |
| 168 | //2 sides, 80 tracks, 9 sectors/track, 1024 bytes/sector = 1474560 bytes (300rpm)(??) |
| 169 | heads = 2; |
| 170 | tracks = 80; |
| 171 | spt = 9; |
| 172 | bps = 1024; |
| 173 | break; |
| 174 | case 0x11: |
| 175 | //11h: BASIC-2HD (BKDSK .HDB) |
| 176 | //Head 0 Track 0 - FM encoding - 26 sectors of 128 bytes = 1 track |
| 177 | //Head 1 Track 0 - MFM encoding - 26 sectors of 256 bytes = 1 track |
| 178 | //Head 0 Track 1 to Head 1 Track 77 - 26 sectors of 256 bytes = 152 tracks |
| 179 | //2 sides, 77 tracks, 26 sectors/track, 256 bytes/sector (except for head 0 track 0) = 1021696 bytes (360rpm) |
| 180 | is_hdb = true; |
| 181 | heads = 2; |
| 182 | tracks = 77; |
| 183 | spt = 26; |
| 184 | bps = 256; |
| 185 | break; |
| 186 | case 0x19: |
| 187 | //19h: BASIC 2DD (BKDSK .DDB) |
| 188 | //2 sides, 80 tracks, 16 sectors/track, 256 bytes/sector = 655360 bytes (300rpm) |
| 189 | heads = 2; |
| 190 | tracks = 80; |
| 191 | spt = 16; |
| 192 | bps = 256; |
| 193 | break; |
| 194 | case 0x21: |
| 195 | //21H: 2HD-26 sector |
| 196 | //2 sides, 80 tracks, 26 sectors/track, 256 bytes/sector = 1064960 bytes (??rpm)(??) |
| 197 | heads = 2; |
| 198 | tracks = 80; |
| 199 | spt = 26; |
| 200 | bps = 256; |
| 201 | break; |
| 202 | } |
| 203 | |
| 204 | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 205 | |
| 206 | int ssize; |
| 207 | for (ssize = 0; (128 << ssize) < bps; ssize++); |
| 208 | |
| 209 | desc_pc_sector sects[256]; |
| 210 | UINT8 sect_data[65536]; |
| 211 | |
| 212 | if (!is_hdb) |
| 213 | { |
| 214 | for (int track = 0; track < tracks; track++) |
| 215 | for (int head = 0; head < heads; head++) |
| 216 | { |
| 217 | io_generic_read(io, sect_data, 0xa2 + bps * spt * (track * heads + head), bps * spt); |
| 218 | |
| 219 | for (int i = 0; i < spt; i++) |
| 220 | { |
| 221 | sects[i].track = track; |
| 222 | sects[i].head = head; |
| 223 | sects[i].sector = i + 1; |
| 224 | sects[i].size = ssize; |
| 225 | sects[i].actual_size = bps; |
| 226 | sects[i].deleted = false; |
| 227 | sects[i].bad_crc = false; |
| 228 | sects[i].data = sect_data + i * bps; |
| 229 | } |
| 230 | |
| 231 | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 232 | } |
| 233 | } |
| 234 | else // FIXME: the code below is untested, because no image was found... there might be some silly mistake in the disk geometry! |
| 235 | { |
| 236 | // Read Head 0 Track 0 is FM with 26 sectors of 128bytes instead of 256 |
| 237 | io_generic_read(io, sect_data, 0xa2, 128 * spt); |
| 238 | |
| 239 | for (int i = 0; i < spt; i++) |
| 240 | { |
| 241 | sects[i].track = 0; |
| 242 | sects[i].head = 0; |
| 243 | sects[i].sector = i + 1; |
| 244 | sects[i].size = 0; |
| 245 | sects[i].actual_size = 128; |
| 246 | sects[i].deleted = false; |
| 247 | sects[i].bad_crc = false; |
| 248 | sects[i].data = sect_data + i * 128; |
| 249 | } |
| 250 | |
| 251 | build_pc_track_fm(0, 0, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, 128)); |
| 252 | |
| 253 | // Read Head 1 Track 0 is MFM with 26 sectors of 256bytes |
| 254 | io_generic_read(io, sect_data, 0xa2 + 128 * spt, bps * spt); |
| 255 | |
| 256 | for (int i = 0; i < spt; i++) |
| 257 | { |
| 258 | sects[i].track = 0; |
| 259 | sects[i].head = 1; |
| 260 | sects[i].sector = i + 1; |
| 261 | sects[i].size = ssize; |
| 262 | sects[i].actual_size = bps; |
| 263 | sects[i].deleted = false; |
| 264 | sects[i].bad_crc = false; |
| 265 | sects[i].data = sect_data + i * bps; |
| 266 | } |
| 267 | |
| 268 | build_pc_track_mfm(0, 1, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 269 | |
| 270 | // Read other tracks as usual |
| 271 | UINT32 data_offs = 0xa2 + (26 * 0x80) + (26 * 0x100); |
| 272 | for (int track = 1; track < tracks; track++) |
| 273 | for (int head = 0; head < heads; head++) |
| 274 | { |
| 275 | io_generic_read(io, sect_data, data_offs + bps * spt * ((track - 1) * heads + head), bps * spt); |
| 276 | |
| 277 | for (int i = 0; i < spt; i++) |
| 278 | { |
| 279 | sects[i].track = track; |
| 280 | sects[i].head = head; |
| 281 | sects[i].sector = i + 1; |
| 282 | sects[i].size = ssize; |
| 283 | sects[i].actual_size = bps; |
| 284 | sects[i].deleted = false; |
| 285 | sects[i].bad_crc = false; |
| 286 | sects[i].data = sect_data + i * bps; |
| 287 | } |
| 288 | |
| 289 | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | return true; |
| 294 | } |
| 295 | |
| 296 | bool dcp_format::supports_save() const |
| 297 | { |
| 298 | return false; |
| 299 | } |
| 300 | |
| 301 | const floppy_format_type FLOPPY_DCP_FORMAT = &floppy_image_format_creator<dcp_format>; |
trunk/src/lib/formats/dip_dsk.c
| r0 | r242337 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:etabeta |
| 3 | /********************************************************************* |
| 4 | |
| 5 | formats/dip_dsk.h |
| 6 | |
| 7 | PC98 DIP disk images |
| 8 | |
| 9 | 0x100 header, followed by track data |
| 10 | |
| 11 | TODO: |
| 12 | - Investigate header structure |
| 13 | - can this format be used to support different disc types? |
| 14 | |
| 15 | *********************************************************************/ |
| 16 | |
| 17 | #include "emu.h" |
| 18 | #include "dip_dsk.h" |
| 19 | |
| 20 | dip_format::dip_format() |
| 21 | { |
| 22 | } |
| 23 | |
| 24 | const char *dip_format::name() const |
| 25 | { |
| 26 | return "dip"; |
| 27 | } |
| 28 | |
| 29 | const char *dip_format::description() const |
| 30 | { |
| 31 | return "DIP disk image"; |
| 32 | } |
| 33 | |
| 34 | const char *dip_format::extensions() const |
| 35 | { |
| 36 | return "dip"; |
| 37 | } |
| 38 | |
| 39 | int dip_format::identify(io_generic *io, UINT32 form_factor) |
| 40 | { |
| 41 | UINT64 size = io_generic_size(io); |
| 42 | |
| 43 | if (size == 0x134000 + 0x100) |
| 44 | return 100; |
| 45 | |
| 46 | return 0; |
| 47 | } |
| 48 | |
| 49 | bool dip_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 50 | { |
| 51 | int heads, tracks, spt, bps; |
| 52 | |
| 53 | //For the moment we only support this disk structure... |
| 54 | //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) |
| 55 | heads = 2; |
| 56 | tracks = 77; |
| 57 | spt = 8; |
| 58 | bps = 1024; |
| 59 | |
| 60 | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 61 | |
| 62 | int ssize; |
| 63 | for (ssize = 0; (128 << ssize) < bps; ssize++); |
| 64 | |
| 65 | desc_pc_sector sects[256]; |
| 66 | UINT8 sect_data[65536]; |
| 67 | |
| 68 | for (int track = 0; track < tracks; track++) |
| 69 | for (int head = 0; head < heads; head++) |
| 70 | { |
| 71 | io_generic_read(io, sect_data, 0x100 + bps * spt * (track * heads + head), bps * spt); |
| 72 | |
| 73 | for (int i = 0; i < spt; i++) |
| 74 | { |
| 75 | sects[i].track = track; |
| 76 | sects[i].head = head; |
| 77 | sects[i].sector = i + 1; |
| 78 | sects[i].size = ssize; |
| 79 | sects[i].actual_size = bps; |
| 80 | sects[i].deleted = false; |
| 81 | sects[i].bad_crc = false; |
| 82 | sects[i].data = sect_data + i * bps; |
| 83 | } |
| 84 | |
| 85 | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 86 | } |
| 87 | |
| 88 | return true; |
| 89 | } |
| 90 | |
| 91 | bool dip_format::supports_save() const |
| 92 | { |
| 93 | return false; |
| 94 | } |
| 95 | |
| 96 | const floppy_format_type FLOPPY_DIP_FORMAT = &floppy_image_format_creator<dip_format>; |
trunk/src/lib/formats/fdd_dsk.c
| r0 | r242337 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:etabeta |
| 3 | /********************************************************************* |
| 4 | |
| 5 | formats/fdd_dsk.h |
| 6 | |
| 7 | PC98 FDD disk images |
| 8 | |
| 9 | 0xC3FC header, followed by track data |
| 10 | Sector map starts at offset 0xDC, with 12bytes for each sector |
| 11 | |
| 12 | Each entry of the sector map has the following structure |
| 13 | - 0x0 = track number (if 0xff the sector/track is unformatted/unused) |
| 14 | - 0x1 = head number |
| 15 | - 0x2 = sector number |
| 16 | - 0x3 = sector size (128 << this byte) |
| 17 | - 0x4 = fill byte. if it's not 0xff, then this sector in the original |
| 18 | disk consisted of this single value repeated for the whole |
| 19 | sector size, and the sector is skipped in the .fdd file. |
| 20 | if it's 0xff, then this sector is wholly contained in the .fdd |
| 21 | file |
| 22 | - 0x5 = ?? |
| 23 | - 0x6 = ?? |
| 24 | - 0x7 = ?? |
| 25 | - 0x8-0x0b = absolute offset of the data for this sector, or 0xfffffff |
| 26 | if the sector was skipped in the .fdd (and it has to be |
| 27 | filled with the value at 0x4) |
| 28 | |
| 29 | TODO: |
| 30 | - Investigate remaining sector map bytes (maybe related to protections?) |
| 31 | |
| 32 | *********************************************************************/ |
| 33 | |
| 34 | #include "emu.h" |
| 35 | #include "fdd_dsk.h" |
| 36 | |
| 37 | fdd_format::fdd_format() |
| 38 | { |
| 39 | } |
| 40 | |
| 41 | const char *fdd_format::name() const |
| 42 | { |
| 43 | return "fdd"; |
| 44 | } |
| 45 | |
| 46 | const char *fdd_format::description() const |
| 47 | { |
| 48 | return "FDD disk image"; |
| 49 | } |
| 50 | |
| 51 | const char *fdd_format::extensions() const |
| 52 | { |
| 53 | return "fdd"; |
| 54 | } |
| 55 | |
| 56 | int fdd_format::identify(io_generic *io, UINT32 form_factor) |
| 57 | { |
| 58 | UINT8 h[7]; |
| 59 | io_generic_read(io, h, 0, 7); |
| 60 | |
| 61 | if (strncmp((const char *)h, "VFD1.0", 6) == 0) |
| 62 | return 100; |
| 63 | |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | bool fdd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 68 | { |
| 69 | UINT8 hsec[0x0c]; |
| 70 | |
| 71 | // sector map |
| 72 | UINT8 num_secs[160]; |
| 73 | UINT32 track_sizes[160]; |
| 74 | UINT8 tracks[160 * 26]; |
| 75 | UINT8 heads[160 * 26]; |
| 76 | UINT8 secs[160 * 26]; |
| 77 | UINT8 fill_vals[160 * 26]; |
| 78 | UINT32 sec_offs[160 * 26]; |
| 79 | UINT8 sec_sizes[160 * 26]; |
| 80 | |
| 81 | int pos = 0xdc; |
| 82 | |
| 83 | for (int track = 0; track < 160; track++) |
| 84 | { |
| 85 | int curr_num_sec = 0, curr_track_size = 0; |
| 86 | for (int sect = 0; sect < 26; sect++) |
| 87 | { |
| 88 | // read sector map for this sector |
| 89 | io_generic_read(io, hsec, pos, 0x0c); |
| 90 | pos += 0x0c; |
| 91 | |
| 92 | if (hsec[0] == 0xff) // unformatted/unused sector |
| 93 | continue; |
| 94 | |
| 95 | tracks[(track * 26) + sect] = hsec[0]; |
| 96 | heads[(track * 26) + sect] = hsec[1]; |
| 97 | secs[(track * 26) + sect] = hsec[2]; |
| 98 | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 99 | fill_vals[(track * 26) + sect] = hsec[4]; |
| 100 | sec_offs[(track * 26) + sect] = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec + 0x08)); |
| 101 | |
| 102 | curr_track_size += (128 << hsec[3]); |
| 103 | curr_num_sec++; |
| 104 | } |
| 105 | num_secs[track] = curr_num_sec; |
| 106 | track_sizes[track] = curr_track_size; |
| 107 | } |
| 108 | |
| 109 | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 110 | desc_pc_sector sects[256]; |
| 111 | UINT8 sect_data[65536]; |
| 112 | int cur_sec_map = 0, sector_size; |
| 113 | |
| 114 | for (int track = 0; track < 160; track++) |
| 115 | { |
| 116 | int cur_pos = 0; |
| 117 | for (int i = 0; i < num_secs[track]; i++) |
| 118 | { |
| 119 | cur_sec_map = track * 26 + i; |
| 120 | sector_size = 128 << sec_sizes[cur_sec_map]; |
| 121 | |
| 122 | if (sec_offs[cur_sec_map] == 0xffffffff) |
| 123 | memset(sect_data + cur_pos, fill_vals[cur_sec_map], sector_size); |
| 124 | else |
| 125 | io_generic_read(io, sect_data + cur_pos, sec_offs[cur_sec_map], sector_size); |
| 126 | |
| 127 | sects[i].track = tracks[cur_sec_map]; |
| 128 | sects[i].head = heads[cur_sec_map]; |
| 129 | sects[i].sector = secs[cur_sec_map]; |
| 130 | sects[i].size = sec_sizes[cur_sec_map]; |
| 131 | sects[i].actual_size = sector_size; |
| 132 | sects[i].deleted = false; |
| 133 | sects[i].bad_crc = false; |
| 134 | sects[i].data = sect_data + cur_pos; |
| 135 | cur_pos += sector_size; |
| 136 | } |
| 137 | |
| 138 | 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]))); |
| 139 | } |
| 140 | |
| 141 | return true; |
| 142 | } |
| 143 | |
| 144 | bool fdd_format::supports_save() const |
| 145 | { |
| 146 | return false; |
| 147 | } |
| 148 | |
| 149 | const floppy_format_type FLOPPY_FDD_FORMAT = &floppy_image_format_creator<fdd_format>; |
trunk/src/lib/formats/nfd_dsk.c
| r0 | r242337 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:etabeta |
| 3 | /********************************************************************* |
| 4 | |
| 5 | formats/nfd_dsk.h |
| 6 | |
| 7 | PC98 NFD disk images (info from: http://www.geocities.jp/t98next/dev.html ) |
| 8 | |
| 9 | Revision 0 |
| 10 | ========== |
| 11 | |
| 12 | header structure (variable length > 0x120, header length = DWORD at 0x110) |
| 13 | 0x000-0x00F = T98FDDIMAGE.R* followed by 2 0x00 bytes, * = format revision (0 or 1 so far) |
| 14 | 0x010-0x10F = space for image info / comments |
| 15 | 0x110-0x113 = header length (DWORD) |
| 16 | 0x114 = write protect (any value > 0 means not writeable) |
| 17 | 0x115 = number of heads |
| 18 | 0x116-0x11F = reserved |
| 19 | 0x120-EOHeader = sector map (0x10 for each sector of the disk!) |
| 20 | last 0x10 are fixed to 0x00, probably it marks the end of sector map? |
| 21 | |
| 22 | sector map structure |
| 23 | 0x0 = track number |
| 24 | 0x1 = head |
| 25 | 0x2 = sector number |
| 26 | 0x3 = sector size (in 128byte chunks) |
| 27 | 0x4 = MFM/FM (1 = MFM, 0 = FM)? |
| 28 | 0x5 = DDAM/DAM (1 = DDAM, 0 = DAM) |
| 29 | 0x6-0x9 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 30 | 0xA = PDA (disk type) |
| 31 | 0xB-0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 32 | |
| 33 | |
| 34 | Revision 1 |
| 35 | ========== |
| 36 | |
| 37 | header structure (variable length > 0x120, header length = DWORD at 0x110) |
| 38 | 0x000-0x11F = same as Rev. 0 format |
| 39 | 0x120-0x3AF = 164 DWORDs containing, for each track, the absolute position of the sector maps |
| 40 | for sectors of the track. for unformatted/unused tracks 0 is used |
| 41 | 0x3B0-0x3B3 = absolute position of addintional info in the header, if any |
| 42 | 0x3B4-0x3BF = reserved |
| 43 | 0x120-EOHeader = sector map + special data for each track: |
| 44 | first 0x10 of each track = #sectors (WORD), #extra data (WORD), reserved 0xc bytes zeroed |
| 45 | then 0x10 for each sector of this track and 0x10 for each extra data chunk |
| 46 | |
| 47 | sector map structure |
| 48 | 0x0 = track number |
| 49 | 0x1 = head |
| 50 | 0x2 = sector number |
| 51 | 0x3 = sector size (in 128byte chunks) |
| 52 | 0x4 = MFM/FM (1 = MFM, 0 = FM)? |
| 53 | 0x5 = DDAM/DAM (1 = DDAM, 0 = DAM) |
| 54 | 0x6-0x9 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 55 | 0xA = RETRY DATA (1 = Yes, 0 = No) |
| 56 | 0xB = PDA (disk type) |
| 57 | 0xC-0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 58 | |
| 59 | extra data map structure |
| 60 | 0x0 = command |
| 61 | 0x1 = track number |
| 62 | 0x2 = head |
| 63 | 0x3 = sector number |
| 64 | 0x4 = sector size (in 128byte chunks) |
| 65 | 0x5-0x8 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 66 | 0x9 = Number of times to RETRY loading data |
| 67 | 0xA-0xD = length of RETRY DATA |
| 68 | 0xE = PDA (disk type) |
| 69 | 0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 70 | |
| 71 | TODO: |
| 72 | - add support for write protect header bit? apparently, some disks try to write and |
| 73 | fail to boot if they succeed which is the reason this bit was added |
| 74 | - add support for DDAM in Rev. 0 (need an image which set it in some sector) |
| 75 | - investigate the READ DATA bytes of sector headers |
| 76 | - investigate RETRY DATA chunks |
| 77 | |
| 78 | *********************************************************************/ |
| 79 | |
| 80 | #include "emu.h" |
| 81 | #include "nfd_dsk.h" |
| 82 | |
| 83 | nfd_format::nfd_format() |
| 84 | { |
| 85 | } |
| 86 | |
| 87 | const char *nfd_format::name() const |
| 88 | { |
| 89 | return "nfd"; |
| 90 | } |
| 91 | |
| 92 | const char *nfd_format::description() const |
| 93 | { |
| 94 | return "NFD disk image"; |
| 95 | } |
| 96 | |
| 97 | const char *nfd_format::extensions() const |
| 98 | { |
| 99 | return "nfd"; |
| 100 | } |
| 101 | |
| 102 | int nfd_format::identify(io_generic *io, UINT32 form_factor) |
| 103 | { |
| 104 | UINT8 h[16]; |
| 105 | io_generic_read(io, h, 0, 16); |
| 106 | |
| 107 | if (strncmp((const char *)h, "T98FDDIMAGE.R0", 14) == 0 || strncmp((const char *)h, "T98FDDIMAGE.R1", 14) == 0) |
| 108 | return 100; |
| 109 | |
| 110 | return 0; |
| 111 | } |
| 112 | |
| 113 | bool nfd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 114 | { |
| 115 | UINT64 size = io_generic_size(io); |
| 116 | UINT8 h[0x120], hsec[0x10]; |
| 117 | io_generic_read(io, h, 0, 0x120); |
| 118 | int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; |
| 119 | |
| 120 | // sector map (the 164th entry is only used by rev.1 format, loops with track < 163 are correct for rev.0) |
| 121 | UINT8 disk_type = 0; |
| 122 | UINT8 num_secs[164]; |
| 123 | UINT8 num_specials[164]; |
| 124 | UINT32 track_sizes[164]; |
| 125 | UINT8 tracks[164 * 26]; |
| 126 | UINT8 heads[164 * 26]; |
| 127 | UINT8 secs[164 * 26]; |
| 128 | UINT8 mfm[164 * 26]; |
| 129 | UINT8 sec_sizes[164 * 26]; |
| 130 | |
| 131 | UINT32 hsize = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x110)); |
| 132 | |
| 133 | int pos = 0x120; |
| 134 | |
| 135 | // set up sector map |
| 136 | if (format_version == 1) |
| 137 | { |
| 138 | for (int track = 0; track < 164; track++) |
| 139 | { |
| 140 | int curr_track_size = 0; |
| 141 | // read sector map absolute location |
| 142 | io_generic_read(io, hsec, pos, 4); |
| 143 | pos += 4; |
| 144 | UINT32 secmap_addr = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec)); |
| 145 | |
| 146 | if (secmap_addr) |
| 147 | { |
| 148 | // read actual sector map for the sectors of this track |
| 149 | // for rev.1 format the first 0x10 are a track summary: |
| 150 | // first WORD is # of sectors, second WORD is # of special data sectors |
| 151 | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 152 | secmap_addr += 0x10; |
| 153 | num_secs[track] = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hsec)); |
| 154 | num_specials[track] = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hsec + 0x2)); |
| 155 | |
| 156 | for (int sect = 0; sect < num_secs[track]; sect++) |
| 157 | { |
| 158 | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 159 | |
| 160 | if (track == 0 && sect == 0) |
| 161 | disk_type = hsec[0xb]; // can this change across the disk? I don't think so... |
| 162 | secmap_addr += 0x10; |
| 163 | |
| 164 | tracks[(track * 26) + sect] = hsec[0]; |
| 165 | heads[(track * 26) + sect] = hsec[1]; |
| 166 | secs[(track * 26) + sect] = hsec[2]; |
| 167 | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 168 | mfm[(track * 26) + sect] = hsec[4]; |
| 169 | |
| 170 | curr_track_size += (128 << hsec[3]); |
| 171 | } |
| 172 | |
| 173 | if (num_specials[track] > 0) |
| 174 | { |
| 175 | for (int sect = 0; sect < num_specials[track]; sect++) |
| 176 | { |
| 177 | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 178 | secmap_addr += 0x10; |
| 179 | curr_track_size += (hsec[9] + 1) * LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec + 0x0a)); |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | num_secs[track] = 0; |
| 186 | num_specials[track] = 0; |
| 187 | } |
| 188 | track_sizes[track] = curr_track_size; |
| 189 | } |
| 190 | } |
| 191 | else |
| 192 | { |
| 193 | for (int track = 0; track < 163 && pos < hsize; track++) |
| 194 | { |
| 195 | int curr_num_sec = 0, curr_track_size = 0; |
| 196 | for (int sect = 0; sect < 26; sect++) |
| 197 | { |
| 198 | // read sector map for this sector |
| 199 | // for rev.0 format each sector uses 0x10 bytes |
| 200 | io_generic_read(io, hsec, pos, 0x10); |
| 201 | |
| 202 | if (track == 0 && sect == 0) |
| 203 | disk_type = hsec[0xa]; // can this change across the disk? I don't think so... |
| 204 | pos += 0x10; |
| 205 | |
| 206 | if (hsec[0] == 0xff) // unformatted/unused sector |
| 207 | continue; |
| 208 | |
| 209 | tracks[(track * 26) + sect] = hsec[0]; |
| 210 | heads[(track * 26) + sect] = hsec[1]; |
| 211 | secs[(track * 26) + sect] = hsec[2]; |
| 212 | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 213 | mfm[(track * 26) + sect] = hsec[4]; |
| 214 | |
| 215 | curr_track_size += (128 << hsec[3]); |
| 216 | curr_num_sec++; |
| 217 | } |
| 218 | |
| 219 | num_secs[track] = curr_num_sec; |
| 220 | track_sizes[track] = curr_track_size; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | // shouln't this be set-up depending on disk_type? gaplus does not like having less than 166666 cells |
| 225 | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 226 | |
| 227 | switch (disk_type) |
| 228 | { |
| 229 | case 0x10: // 640K disk, 2DD |
| 230 | image->set_variant(floppy_image::DSDD); |
| 231 | break; |
| 232 | //case 0x30: // 1.44M disk, ?? (no images found) |
| 233 | // break; |
| 234 | case 0x90: // 1.2M disk, 2HD |
| 235 | default: |
| 236 | image->set_variant(floppy_image::DSHD); |
| 237 | break; |
| 238 | } |
| 239 | |
| 240 | desc_pc_sector sects[256]; |
| 241 | UINT8 sect_data[65536]; |
| 242 | int cur_sec_map = 0, sector_size; |
| 243 | pos = hsize; |
| 244 | |
| 245 | for (int track = 0; track < 163 && pos < size; track++) |
| 246 | { |
| 247 | io_generic_read(io, sect_data, pos, track_sizes[track]); |
| 248 | |
| 249 | for (int i = 0; i < num_secs[track]; i++) |
| 250 | { |
| 251 | cur_sec_map = track * 26 + i; |
| 252 | sector_size = 128 << sec_sizes[cur_sec_map]; |
| 253 | sects[i].track = tracks[cur_sec_map]; |
| 254 | sects[i].head = heads[cur_sec_map]; |
| 255 | sects[i].sector = secs[cur_sec_map]; |
| 256 | sects[i].size = sec_sizes[cur_sec_map]; |
| 257 | sects[i].actual_size = sector_size; |
| 258 | sects[i].deleted = false; |
| 259 | sects[i].bad_crc = false; |
| 260 | sects[i].data = sect_data + i * sector_size; |
| 261 | } |
| 262 | pos += track_sizes[track]; |
| 263 | |
| 264 | // notice that the operation below might fail if sectors of the same track have variable sec_sizes, |
| 265 | // because the gap3 calculation would account correctly only for the first sector... |
| 266 | // examined images had constant sec_sizes in the each track, so probably this is not an issue |
| 267 | if (mfm[track * 26]) |
| 268 | 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]))); |
| 269 | else |
| 270 | 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]))); |
| 271 | } |
| 272 | |
| 273 | return true; |
| 274 | } |
| 275 | |
| 276 | bool nfd_format::supports_save() const |
| 277 | { |
| 278 | return false; |
| 279 | } |
| 280 | |
| 281 | const floppy_format_type FLOPPY_NFD_FORMAT = &floppy_image_format_creator<nfd_format>; |
trunk/src/lib/formats/pc98dcp_dsk.c
| r242336 | r242337 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:etabeta |
| 3 | | /********************************************************************* |
| 4 | | |
| 5 | | formats/pc98dcp_dsk.h |
| 6 | | |
| 7 | | PC98 DCP & DCU disk images |
| 8 | | |
| 9 | | 0xA2 header, followed by track data |
| 10 | | header[0] - disk format |
| 11 | | header[1-0xA1] - track map (1=track used, 0=track unused/unformatted) |
| 12 | | header[0xA2] - all tracks used? |
| 13 | | (there seems to be a diff in its usage between DCP and DCU) |
| 14 | | |
| 15 | | TODO: |
| 16 | | - add support for track map. images available for tests were all |
| 17 | | of type 0x01, with all 154 tracks present. combined with pete_j |
| 18 | | reporting some images have faulty track map, we need some more |
| 19 | | test cases to properly handle these disks! |
| 20 | | |
| 21 | | *********************************************************************/ |
| 22 | | |
| 23 | | #include "emu.h" |
| 24 | | #include "pc98dcp_dsk.h" |
| 25 | | |
| 26 | | pc98dcp_format::pc98dcp_format() |
| 27 | | { |
| 28 | | } |
| 29 | | |
| 30 | | const char *pc98dcp_format::name() const |
| 31 | | { |
| 32 | | return "pc98_dcx"; |
| 33 | | } |
| 34 | | |
| 35 | | const char *pc98dcp_format::description() const |
| 36 | | { |
| 37 | | return "PC98 DCP/DCU disk image"; |
| 38 | | } |
| 39 | | |
| 40 | | const char *pc98dcp_format::extensions() const |
| 41 | | { |
| 42 | | return "dcp,dcu"; |
| 43 | | } |
| 44 | | |
| 45 | | int pc98dcp_format::identify(io_generic *io, UINT32 form_factor) |
| 46 | | { |
| 47 | | UINT64 size = io_generic_size(io); |
| 48 | | UINT8 h[0xa2]; |
| 49 | | int heads, tracks, spt, bps, count_tracks = 0; |
| 50 | | bool is_hdb = false; |
| 51 | | |
| 52 | | io_generic_read(io, h, 0, 0xa2); |
| 53 | | |
| 54 | | // First byte is the disk format (see below in load() for details) |
| 55 | | switch (h[0]) |
| 56 | | { |
| 57 | | case 0x01: |
| 58 | | default: |
| 59 | | heads = 2; tracks = 77; |
| 60 | | spt = 8; bps = 1024; |
| 61 | | break; |
| 62 | | case 0x02: |
| 63 | | heads = 2; tracks = 80; |
| 64 | | spt = 15; bps = 512; |
| 65 | | break; |
| 66 | | case 0x03: |
| 67 | | heads = 2; tracks = 80; |
| 68 | | spt = 18; bps = 512; |
| 69 | | break; |
| 70 | | case 0x04: |
| 71 | | heads = 2; tracks = 80; |
| 72 | | spt = 8; bps = 512; |
| 73 | | break; |
| 74 | | case 0x05: |
| 75 | | heads = 2; tracks = 80; |
| 76 | | spt = 9; bps = 512; |
| 77 | | break; |
| 78 | | case 0x08: |
| 79 | | heads = 2; tracks = 80; |
| 80 | | spt = 9; bps = 1024; |
| 81 | | break; |
| 82 | | case 0x11: |
| 83 | | is_hdb = true; |
| 84 | | heads = 2; tracks = 77; |
| 85 | | spt = 26; bps = 256; |
| 86 | | break; |
| 87 | | case 0x19: |
| 88 | | heads = 2; tracks = 80; |
| 89 | | spt = 16; bps = 256; |
| 90 | | break; |
| 91 | | case 0x21: |
| 92 | | heads = 2; tracks = 80; |
| 93 | | spt = 26; bps = 256; |
| 94 | | break; |
| 95 | | } |
| 96 | | |
| 97 | | // bytes 0x01 to 0xa1 are track map (0x01 if track is used, 0x00 if track is unformatted/unused) |
| 98 | | for (int i = 1; i < 0xa1; i++) |
| 99 | | if (h[i]) |
| 100 | | count_tracks++; |
| 101 | | |
| 102 | | // in theory track map should be enough (former check), but some images have it wrong! |
| 103 | | // hence, if this check fails, we also allow for images with all tracks and wrong track map |
| 104 | | if (size - 0xa2 == (heads * count_tracks * spt * bps) || size - 0xa2 == (heads * tracks * spt * bps)) |
| 105 | | return 100; |
| 106 | | |
| 107 | | // for disk type 0x11 the head 0 track 0 has 26 sectors of half width, so we need to compensate calculation |
| 108 | | if (is_hdb && (size - 0xa2 + (0x80 * 26) == (heads * count_tracks * spt * bps) || size - 0xa2 + (0x80 * 26) == (heads * tracks * spt * bps))) |
| 109 | | return 100; |
| 110 | | |
| 111 | | return 0; |
| 112 | | } |
| 113 | | |
| 114 | | bool pc98dcp_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 115 | | { |
| 116 | | UINT8 h[0xa2]; |
| 117 | | int heads, tracks, spt, bps; |
| 118 | | bool is_hdb = false; |
| 119 | | |
| 120 | | io_generic_read(io, h, 0, 0xa2); |
| 121 | | |
| 122 | | // First byte is the disk format: |
| 123 | | switch (h[0]) |
| 124 | | { |
| 125 | | case 0x01: |
| 126 | | default: |
| 127 | | //01h: 2HD-8 sector (1.25MB) (BKDSK .HDM) (aka 2HS) |
| 128 | | //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) |
| 129 | | heads = 2; |
| 130 | | tracks = 77; |
| 131 | | spt = 8; |
| 132 | | bps = 1024; |
| 133 | | break; |
| 134 | | case 0x02: |
| 135 | | //02H: 2HD-15 sector (1.21MB) (BKDSK .HD5) (aka 2HC) |
| 136 | | //2 sides, 80 tracks, 15 sectors/track, 512 bytes/sector = 1228800 bytes (360rpm) |
| 137 | | heads = 2; |
| 138 | | tracks = 80; |
| 139 | | spt = 15; |
| 140 | | bps = 512; |
| 141 | | break; |
| 142 | | case 0x03: |
| 143 | | //03H: 2HQ-18 sector (1.44MB) (BKDSK .HD4) (aka 2HDE) |
| 144 | | //2 sides, 80 tracks, 18 sectors/track, 512 bytes/sector = 1474560 bytes (300rpm) |
| 145 | | heads = 2; |
| 146 | | tracks = 80; |
| 147 | | spt = 18; |
| 148 | | bps = 512; |
| 149 | | break; |
| 150 | | case 0x04: |
| 151 | | //04H: 2DD-8 sector (640KB) (BKDSK .DD6) |
| 152 | | //2 sides, 80 tracks, 8 sectors/track, 512 bytes/sector = 655360 bytes (300rpm) |
| 153 | | heads = 2; |
| 154 | | tracks = 80; |
| 155 | | spt = 8; |
| 156 | | bps = 512; |
| 157 | | break; |
| 158 | | case 0x05: |
| 159 | | //05h: 2DD-9 sector ( 720KB) (BKDSK .DD9) |
| 160 | | //2 sides, 80 tracks, 9 sectors/track, 512 bytes/sector = 737280 bytes (300rpm) |
| 161 | | heads = 2; |
| 162 | | tracks = 80; |
| 163 | | spt = 9; |
| 164 | | bps = 512; |
| 165 | | break; |
| 166 | | case 0x08: |
| 167 | | //08h: 2HD-9 sector (1.44MB) |
| 168 | | //2 sides, 80 tracks, 9 sectors/track, 1024 bytes/sector = 1474560 bytes (300rpm)(??) |
| 169 | | heads = 2; |
| 170 | | tracks = 80; |
| 171 | | spt = 9; |
| 172 | | bps = 1024; |
| 173 | | break; |
| 174 | | case 0x11: |
| 175 | | //11h: BASIC-2HD (BKDSK .HDB) |
| 176 | | //Head 0 Track 0 - FM encoding - 26 sectors of 128 bytes = 1 track |
| 177 | | //Head 1 Track 0 - MFM encoding - 26 sectors of 256 bytes = 1 track |
| 178 | | //Head 0 Track 1 to Head 1 Track 77 - 26 sectors of 256 bytes = 152 tracks |
| 179 | | //2 sides, 77 tracks, 26 sectors/track, 256 bytes/sector (except for head 0 track 0) = 1021696 bytes (360rpm) |
| 180 | | is_hdb = true; |
| 181 | | heads = 2; |
| 182 | | tracks = 77; |
| 183 | | spt = 26; |
| 184 | | bps = 256; |
| 185 | | break; |
| 186 | | case 0x19: |
| 187 | | //19h: BASIC 2DD (BKDSK .DDB) |
| 188 | | //2 sides, 80 tracks, 16 sectors/track, 256 bytes/sector = 655360 bytes (300rpm) |
| 189 | | heads = 2; |
| 190 | | tracks = 80; |
| 191 | | spt = 16; |
| 192 | | bps = 256; |
| 193 | | break; |
| 194 | | case 0x21: |
| 195 | | //21H: 2HD-26 sector |
| 196 | | //2 sides, 80 tracks, 26 sectors/track, 256 bytes/sector = 1064960 bytes (??rpm)(??) |
| 197 | | heads = 2; |
| 198 | | tracks = 80; |
| 199 | | spt = 26; |
| 200 | | bps = 256; |
| 201 | | break; |
| 202 | | } |
| 203 | | |
| 204 | | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 205 | | |
| 206 | | int ssize; |
| 207 | | for (ssize = 0; (128 << ssize) < bps; ssize++); |
| 208 | | |
| 209 | | desc_pc_sector sects[256]; |
| 210 | | UINT8 sect_data[65536]; |
| 211 | | |
| 212 | | if (!is_hdb) |
| 213 | | { |
| 214 | | for (int track = 0; track < tracks; track++) |
| 215 | | for (int head = 0; head < heads; head++) |
| 216 | | { |
| 217 | | io_generic_read(io, sect_data, 0xa2 + bps * spt * (track * heads + head), bps * spt); |
| 218 | | |
| 219 | | for (int i = 0; i < spt; i++) |
| 220 | | { |
| 221 | | sects[i].track = track; |
| 222 | | sects[i].head = head; |
| 223 | | sects[i].sector = i + 1; |
| 224 | | sects[i].size = ssize; |
| 225 | | sects[i].actual_size = bps; |
| 226 | | sects[i].deleted = false; |
| 227 | | sects[i].bad_crc = false; |
| 228 | | sects[i].data = sect_data + i * bps; |
| 229 | | } |
| 230 | | |
| 231 | | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 232 | | } |
| 233 | | } |
| 234 | | else // FIXME: the code below is untested, because no image was found... there might be some silly mistake in the disk geometry! |
| 235 | | { |
| 236 | | // Read Head 0 Track 0 is FM with 26 sectors of 128bytes instead of 256 |
| 237 | | io_generic_read(io, sect_data, 0xa2, 128 * spt); |
| 238 | | |
| 239 | | for (int i = 0; i < spt; i++) |
| 240 | | { |
| 241 | | sects[i].track = 0; |
| 242 | | sects[i].head = 0; |
| 243 | | sects[i].sector = i + 1; |
| 244 | | sects[i].size = 0; |
| 245 | | sects[i].actual_size = 128; |
| 246 | | sects[i].deleted = false; |
| 247 | | sects[i].bad_crc = false; |
| 248 | | sects[i].data = sect_data + i * 128; |
| 249 | | } |
| 250 | | |
| 251 | | build_pc_track_fm(0, 0, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, 128)); |
| 252 | | |
| 253 | | // Read Head 1 Track 0 is MFM with 26 sectors of 256bytes |
| 254 | | io_generic_read(io, sect_data, 0xa2 + 128 * spt, bps * spt); |
| 255 | | |
| 256 | | for (int i = 0; i < spt; i++) |
| 257 | | { |
| 258 | | sects[i].track = 0; |
| 259 | | sects[i].head = 1; |
| 260 | | sects[i].sector = i + 1; |
| 261 | | sects[i].size = ssize; |
| 262 | | sects[i].actual_size = bps; |
| 263 | | sects[i].deleted = false; |
| 264 | | sects[i].bad_crc = false; |
| 265 | | sects[i].data = sect_data + i * bps; |
| 266 | | } |
| 267 | | |
| 268 | | build_pc_track_mfm(0, 1, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 269 | | |
| 270 | | // Read other tracks as usual |
| 271 | | UINT32 data_offs = 0xa2 + (26 * 0x80) + (26 * 0x100); |
| 272 | | for (int track = 1; track < tracks; track++) |
| 273 | | for (int head = 0; head < heads; head++) |
| 274 | | { |
| 275 | | io_generic_read(io, sect_data, data_offs + bps * spt * ((track - 1) * heads + head), bps * spt); |
| 276 | | |
| 277 | | for (int i = 0; i < spt; i++) |
| 278 | | { |
| 279 | | sects[i].track = track; |
| 280 | | sects[i].head = head; |
| 281 | | sects[i].sector = i + 1; |
| 282 | | sects[i].size = ssize; |
| 283 | | sects[i].actual_size = bps; |
| 284 | | sects[i].deleted = false; |
| 285 | | sects[i].bad_crc = false; |
| 286 | | sects[i].data = sect_data + i * bps; |
| 287 | | } |
| 288 | | |
| 289 | | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 290 | | } |
| 291 | | } |
| 292 | | |
| 293 | | return true; |
| 294 | | } |
| 295 | | |
| 296 | | bool pc98dcp_format::supports_save() const |
| 297 | | { |
| 298 | | return false; |
| 299 | | } |
| 300 | | |
| 301 | | const floppy_format_type FLOPPY_PC98DCP_FORMAT = &floppy_image_format_creator<pc98dcp_format>; |
trunk/src/lib/formats/pc98dip_dsk.c
| r242336 | r242337 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:etabeta |
| 3 | | /********************************************************************* |
| 4 | | |
| 5 | | formats/pc98dip_dsk.h |
| 6 | | |
| 7 | | PC98DIP disk images |
| 8 | | |
| 9 | | 0x100 header, followed by track data |
| 10 | | |
| 11 | | TODO: |
| 12 | | - Investigate header structure |
| 13 | | - can this format be used to support different disc types? |
| 14 | | |
| 15 | | *********************************************************************/ |
| 16 | | |
| 17 | | #include "emu.h" |
| 18 | | #include "pc98dip_dsk.h" |
| 19 | | |
| 20 | | pc98dip_format::pc98dip_format() |
| 21 | | { |
| 22 | | } |
| 23 | | |
| 24 | | const char *pc98dip_format::name() const |
| 25 | | { |
| 26 | | return "pc98_dip"; |
| 27 | | } |
| 28 | | |
| 29 | | const char *pc98dip_format::description() const |
| 30 | | { |
| 31 | | return "PC98 DIP disk image"; |
| 32 | | } |
| 33 | | |
| 34 | | const char *pc98dip_format::extensions() const |
| 35 | | { |
| 36 | | return "dip"; |
| 37 | | } |
| 38 | | |
| 39 | | int pc98dip_format::identify(io_generic *io, UINT32 form_factor) |
| 40 | | { |
| 41 | | UINT64 size = io_generic_size(io); |
| 42 | | |
| 43 | | if (size == 0x134000 + 0x100) |
| 44 | | return 100; |
| 45 | | |
| 46 | | return 0; |
| 47 | | } |
| 48 | | |
| 49 | | bool pc98dip_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 50 | | { |
| 51 | | int heads, tracks, spt, bps; |
| 52 | | |
| 53 | | //For the moment we only support this disk structure... |
| 54 | | //2 sides, 77 tracks, 8 sectors/track, 1024 bytes/sector = 1261568 bytes (360rpm) |
| 55 | | heads = 2; |
| 56 | | tracks = 77; |
| 57 | | spt = 8; |
| 58 | | bps = 1024; |
| 59 | | |
| 60 | | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 61 | | |
| 62 | | int ssize; |
| 63 | | for (ssize = 0; (128 << ssize) < bps; ssize++); |
| 64 | | |
| 65 | | desc_pc_sector sects[256]; |
| 66 | | UINT8 sect_data[65536]; |
| 67 | | |
| 68 | | for (int track = 0; track < tracks; track++) |
| 69 | | for (int head = 0; head < heads; head++) |
| 70 | | { |
| 71 | | io_generic_read(io, sect_data, 0x100 + bps * spt * (track * heads + head), bps * spt); |
| 72 | | |
| 73 | | for (int i = 0; i < spt; i++) |
| 74 | | { |
| 75 | | sects[i].track = track; |
| 76 | | sects[i].head = head; |
| 77 | | sects[i].sector = i + 1; |
| 78 | | sects[i].size = ssize; |
| 79 | | sects[i].actual_size = bps; |
| 80 | | sects[i].deleted = false; |
| 81 | | sects[i].bad_crc = false; |
| 82 | | sects[i].data = sect_data + i * bps; |
| 83 | | } |
| 84 | | |
| 85 | | build_pc_track_mfm(track, head, image, cell_count, spt, sects, calc_default_pc_gap3_size(form_factor, bps)); |
| 86 | | } |
| 87 | | |
| 88 | | return true; |
| 89 | | } |
| 90 | | |
| 91 | | bool pc98dip_format::supports_save() const |
| 92 | | { |
| 93 | | return false; |
| 94 | | } |
| 95 | | |
| 96 | | const floppy_format_type FLOPPY_PC98DIP_FORMAT = &floppy_image_format_creator<pc98dip_format>; |
trunk/src/lib/formats/pc98fdd_dsk.c
| r242336 | r242337 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:etabeta |
| 3 | | /********************************************************************* |
| 4 | | |
| 5 | | formats/pc98fdd_dsk.h |
| 6 | | |
| 7 | | PC98FDD disk images |
| 8 | | |
| 9 | | 0xC3FC header, followed by track data |
| 10 | | Sector map starts at offset 0xDC, with 12bytes for each sector |
| 11 | | |
| 12 | | Each entry of the sector map has the following structure |
| 13 | | - 0x0 = track number (if 0xff the sector/track is unformatted/unused) |
| 14 | | - 0x1 = head number |
| 15 | | - 0x2 = sector number |
| 16 | | - 0x3 = sector size (128 << this byte) |
| 17 | | - 0x4 = fill byte. if it's not 0xff, then this sector in the original |
| 18 | | disk consisted of this single value repeated for the whole |
| 19 | | sector size, and the sector is skipped in the .fdd file. |
| 20 | | if it's 0xff, then this sector is wholly contained in the .fdd |
| 21 | | file |
| 22 | | - 0x5 = ?? |
| 23 | | - 0x6 = ?? |
| 24 | | - 0x7 = ?? |
| 25 | | - 0x8-0x0b = absolute offset of the data for this sector, or 0xfffffff |
| 26 | | if the sector was skipped in the .fdd (and it has to be |
| 27 | | filled with the value at 0x4) |
| 28 | | |
| 29 | | TODO: |
| 30 | | - Investigate remaining sector map bytes (maybe related to protections?) |
| 31 | | |
| 32 | | *********************************************************************/ |
| 33 | | |
| 34 | | #include "emu.h" |
| 35 | | #include "pc98fdd_dsk.h" |
| 36 | | |
| 37 | | pc98fdd_format::pc98fdd_format() |
| 38 | | { |
| 39 | | } |
| 40 | | |
| 41 | | const char *pc98fdd_format::name() const |
| 42 | | { |
| 43 | | return "pc98_fdd"; |
| 44 | | } |
| 45 | | |
| 46 | | const char *pc98fdd_format::description() const |
| 47 | | { |
| 48 | | return "PC98 FDD disk image"; |
| 49 | | } |
| 50 | | |
| 51 | | const char *pc98fdd_format::extensions() const |
| 52 | | { |
| 53 | | return "fdd"; |
| 54 | | } |
| 55 | | |
| 56 | | int pc98fdd_format::identify(io_generic *io, UINT32 form_factor) |
| 57 | | { |
| 58 | | UINT8 h[7]; |
| 59 | | io_generic_read(io, h, 0, 7); |
| 60 | | |
| 61 | | if (strncmp((const char *)h, "VFD1.0", 6) == 0) |
| 62 | | return 100; |
| 63 | | |
| 64 | | return 0; |
| 65 | | } |
| 66 | | |
| 67 | | bool pc98fdd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 68 | | { |
| 69 | | UINT8 hsec[0x0c]; |
| 70 | | |
| 71 | | // sector map |
| 72 | | UINT8 num_secs[160]; |
| 73 | | UINT32 track_sizes[160]; |
| 74 | | UINT8 tracks[160 * 26]; |
| 75 | | UINT8 heads[160 * 26]; |
| 76 | | UINT8 secs[160 * 26]; |
| 77 | | UINT8 fill_vals[160 * 26]; |
| 78 | | UINT32 sec_offs[160 * 26]; |
| 79 | | UINT8 sec_sizes[160 * 26]; |
| 80 | | |
| 81 | | int pos = 0xdc; |
| 82 | | |
| 83 | | for (int track = 0; track < 160; track++) |
| 84 | | { |
| 85 | | int curr_num_sec = 0, curr_track_size = 0; |
| 86 | | for (int sect = 0; sect < 26; sect++) |
| 87 | | { |
| 88 | | // read sector map for this sector |
| 89 | | io_generic_read(io, hsec, pos, 0x0c); |
| 90 | | pos += 0x0c; |
| 91 | | |
| 92 | | if (hsec[0] == 0xff) // unformatted/unused sector |
| 93 | | continue; |
| 94 | | |
| 95 | | tracks[(track * 26) + sect] = hsec[0]; |
| 96 | | heads[(track * 26) + sect] = hsec[1]; |
| 97 | | secs[(track * 26) + sect] = hsec[2]; |
| 98 | | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 99 | | fill_vals[(track * 26) + sect] = hsec[4]; |
| 100 | | sec_offs[(track * 26) + sect] = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec + 0x08)); |
| 101 | | |
| 102 | | curr_track_size += (128 << hsec[3]); |
| 103 | | curr_num_sec++; |
| 104 | | } |
| 105 | | num_secs[track] = curr_num_sec; |
| 106 | | track_sizes[track] = curr_track_size; |
| 107 | | } |
| 108 | | |
| 109 | | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 110 | | desc_pc_sector sects[256]; |
| 111 | | UINT8 sect_data[65536]; |
| 112 | | int cur_sec_map = 0, sector_size; |
| 113 | | |
| 114 | | for (int track = 0; track < 160; track++) |
| 115 | | { |
| 116 | | int cur_pos = 0; |
| 117 | | for (int i = 0; i < num_secs[track]; i++) |
| 118 | | { |
| 119 | | cur_sec_map = track * 26 + i; |
| 120 | | sector_size = 128 << sec_sizes[cur_sec_map]; |
| 121 | | |
| 122 | | if (sec_offs[cur_sec_map] == 0xffffffff) |
| 123 | | memset(sect_data + cur_pos, fill_vals[cur_sec_map], sector_size); |
| 124 | | else |
| 125 | | io_generic_read(io, sect_data + cur_pos, sec_offs[cur_sec_map], sector_size); |
| 126 | | |
| 127 | | sects[i].track = tracks[cur_sec_map]; |
| 128 | | sects[i].head = heads[cur_sec_map]; |
| 129 | | sects[i].sector = secs[cur_sec_map]; |
| 130 | | sects[i].size = sec_sizes[cur_sec_map]; |
| 131 | | sects[i].actual_size = sector_size; |
| 132 | | sects[i].deleted = false; |
| 133 | | sects[i].bad_crc = false; |
| 134 | | sects[i].data = sect_data + cur_pos; |
| 135 | | cur_pos += sector_size; |
| 136 | | } |
| 137 | | |
| 138 | | 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]))); |
| 139 | | } |
| 140 | | |
| 141 | | return true; |
| 142 | | } |
| 143 | | |
| 144 | | bool pc98fdd_format::supports_save() const |
| 145 | | { |
| 146 | | return false; |
| 147 | | } |
| 148 | | |
| 149 | | const floppy_format_type FLOPPY_PC98FDD_FORMAT = &floppy_image_format_creator<pc98fdd_format>; |
trunk/src/lib/formats/pc98nfd_dsk.c
| r242336 | r242337 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:etabeta |
| 3 | | /********************************************************************* |
| 4 | | |
| 5 | | formats/pc98nfd_dsk.h |
| 6 | | |
| 7 | | PC98NFD disk images (info from: http://www.geocities.jp/t98next/dev.html ) |
| 8 | | |
| 9 | | Revision 0 |
| 10 | | ========== |
| 11 | | |
| 12 | | header structure (variable length > 0x120, header length = DWORD at 0x110) |
| 13 | | 0x000-0x00F = T98FDDIMAGE.R* followed by 2 0x00 bytes, * = format revision (0 or 1 so far) |
| 14 | | 0x010-0x10F = space for image info / comments |
| 15 | | 0x110-0x113 = header length (DWORD) |
| 16 | | 0x114 = write protect (any value > 0 means not writeable) |
| 17 | | 0x115 = number of heads |
| 18 | | 0x116-0x11F = reserved |
| 19 | | 0x120-EOHeader = sector map (0x10 for each sector of the disk!) |
| 20 | | last 0x10 are fixed to 0x00, probably it marks the end of sector map? |
| 21 | | |
| 22 | | sector map structure |
| 23 | | 0x0 = track number |
| 24 | | 0x1 = head |
| 25 | | 0x2 = sector number |
| 26 | | 0x3 = sector size (in 128byte chunks) |
| 27 | | 0x4 = MFM/FM (1 = MFM, 0 = FM)? |
| 28 | | 0x5 = DDAM/DAM (1 = DDAM, 0 = DAM) |
| 29 | | 0x6-0x9 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 30 | | 0xA = PDA (disk type) |
| 31 | | 0xB-0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 32 | | |
| 33 | | |
| 34 | | Revision 1 |
| 35 | | ========== |
| 36 | | |
| 37 | | header structure (variable length > 0x120, header length = DWORD at 0x110) |
| 38 | | 0x000-0x11F = same as Rev. 0 format |
| 39 | | 0x120-0x3AF = 164 DWORDs containing, for each track, the absolute position of the sector maps |
| 40 | | for sectors of the track. for unformatted/unused tracks 0 is used |
| 41 | | 0x3B0-0x3B3 = absolute position of addintional info in the header, if any |
| 42 | | 0x3B4-0x3BF = reserved |
| 43 | | 0x120-EOHeader = sector map + special data for each track: |
| 44 | | first 0x10 of each track = #sectors (WORD), #extra data (WORD), reserved 0xc bytes zeroed |
| 45 | | then 0x10 for each sector of this track and 0x10 for each extra data chunk |
| 46 | | |
| 47 | | sector map structure |
| 48 | | 0x0 = track number |
| 49 | | 0x1 = head |
| 50 | | 0x2 = sector number |
| 51 | | 0x3 = sector size (in 128byte chunks) |
| 52 | | 0x4 = MFM/FM (1 = MFM, 0 = FM)? |
| 53 | | 0x5 = DDAM/DAM (1 = DDAM, 0 = DAM) |
| 54 | | 0x6-0x9 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 55 | | 0xA = RETRY DATA (1 = Yes, 0 = No) |
| 56 | | 0xB = PDA (disk type) |
| 57 | | 0xC-0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 58 | | |
| 59 | | extra data map structure |
| 60 | | 0x0 = command |
| 61 | | 0x1 = track number |
| 62 | | 0x2 = head |
| 63 | | 0x3 = sector number |
| 64 | | 0x4 = sector size (in 128byte chunks) |
| 65 | | 0x5-0x8 = READ DATA (FDDBIOS) Results (Status, St0, St1, St2) ?? |
| 66 | | 0x9 = Number of times to RETRY loading data |
| 67 | | 0xA-0xD = length of RETRY DATA |
| 68 | | 0xE = PDA (disk type) |
| 69 | | 0xF = reserved and equal to 0x00 (possibly available for future format extensions?) |
| 70 | | |
| 71 | | TODO: |
| 72 | | - add support for write protect header bit? apparently, some disks try to write and |
| 73 | | fail to boot if they succeed which is the reason this bit was added |
| 74 | | - add support for DDAM in Rev. 0 (need an image which set it in some sector) |
| 75 | | - investigate the READ DATA bytes of sector headers |
| 76 | | - investigate RETRY DATA chunks |
| 77 | | |
| 78 | | *********************************************************************/ |
| 79 | | |
| 80 | | #include "emu.h" |
| 81 | | #include "pc98nfd_dsk.h" |
| 82 | | |
| 83 | | pc98nfd_format::pc98nfd_format() |
| 84 | | { |
| 85 | | } |
| 86 | | |
| 87 | | const char *pc98nfd_format::name() const |
| 88 | | { |
| 89 | | return "pc98_nfd"; |
| 90 | | } |
| 91 | | |
| 92 | | const char *pc98nfd_format::description() const |
| 93 | | { |
| 94 | | return "PC98 NFD disk image"; |
| 95 | | } |
| 96 | | |
| 97 | | const char *pc98nfd_format::extensions() const |
| 98 | | { |
| 99 | | return "nfd"; |
| 100 | | } |
| 101 | | |
| 102 | | int pc98nfd_format::identify(io_generic *io, UINT32 form_factor) |
| 103 | | { |
| 104 | | UINT8 h[16]; |
| 105 | | io_generic_read(io, h, 0, 16); |
| 106 | | |
| 107 | | if (strncmp((const char *)h, "T98FDDIMAGE.R0", 14) == 0 || strncmp((const char *)h, "T98FDDIMAGE.R1", 14) == 0) |
| 108 | | return 100; |
| 109 | | |
| 110 | | return 0; |
| 111 | | } |
| 112 | | |
| 113 | | bool pc98nfd_format::load(io_generic *io, UINT32 form_factor, floppy_image *image) |
| 114 | | { |
| 115 | | UINT64 size = io_generic_size(io); |
| 116 | | UINT8 h[0x120], hsec[0x10]; |
| 117 | | io_generic_read(io, h, 0, 0x120); |
| 118 | | int format_version = !strncmp((const char *)h, "T98FDDIMAGE.R0", 14) ? 0 : 1; |
| 119 | | |
| 120 | | // sector map (the 164th entry is only used by rev.1 format, loops with track < 163 are correct for rev.0) |
| 121 | | UINT8 disk_type = 0; |
| 122 | | UINT8 num_secs[164]; |
| 123 | | UINT8 num_specials[164]; |
| 124 | | UINT32 track_sizes[164]; |
| 125 | | UINT8 tracks[164 * 26]; |
| 126 | | UINT8 heads[164 * 26]; |
| 127 | | UINT8 secs[164 * 26]; |
| 128 | | UINT8 mfm[164 * 26]; |
| 129 | | UINT8 sec_sizes[164 * 26]; |
| 130 | | |
| 131 | | UINT32 hsize = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x110)); |
| 132 | | |
| 133 | | int pos = 0x120; |
| 134 | | |
| 135 | | // set up sector map |
| 136 | | if (format_version == 1) |
| 137 | | { |
| 138 | | for (int track = 0; track < 164; track++) |
| 139 | | { |
| 140 | | int curr_track_size = 0; |
| 141 | | // read sector map absolute location |
| 142 | | io_generic_read(io, hsec, pos, 4); |
| 143 | | pos += 4; |
| 144 | | UINT32 secmap_addr = LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec)); |
| 145 | | |
| 146 | | if (secmap_addr) |
| 147 | | { |
| 148 | | // read actual sector map for the sectors of this track |
| 149 | | // for rev.1 format the first 0x10 are a track summary: |
| 150 | | // first WORD is # of sectors, second WORD is # of special data sectors |
| 151 | | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 152 | | secmap_addr += 0x10; |
| 153 | | num_secs[track] = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hsec)); |
| 154 | | num_specials[track] = LITTLE_ENDIANIZE_INT16(*(UINT16 *)(hsec + 0x2)); |
| 155 | | |
| 156 | | for (int sect = 0; sect < num_secs[track]; sect++) |
| 157 | | { |
| 158 | | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 159 | | |
| 160 | | if (track == 0 && sect == 0) |
| 161 | | disk_type = hsec[0xb]; // can this change across the disk? I don't think so... |
| 162 | | secmap_addr += 0x10; |
| 163 | | |
| 164 | | tracks[(track * 26) + sect] = hsec[0]; |
| 165 | | heads[(track * 26) + sect] = hsec[1]; |
| 166 | | secs[(track * 26) + sect] = hsec[2]; |
| 167 | | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 168 | | mfm[(track * 26) + sect] = hsec[4]; |
| 169 | | |
| 170 | | curr_track_size += (128 << hsec[3]); |
| 171 | | } |
| 172 | | |
| 173 | | if (num_specials[track] > 0) |
| 174 | | { |
| 175 | | for (int sect = 0; sect < num_specials[track]; sect++) |
| 176 | | { |
| 177 | | io_generic_read(io, hsec, secmap_addr, 0x10); |
| 178 | | secmap_addr += 0x10; |
| 179 | | curr_track_size += (hsec[9] + 1) * LITTLE_ENDIANIZE_INT32(*(UINT32 *)(hsec + 0x0a)); |
| 180 | | } |
| 181 | | } |
| 182 | | } |
| 183 | | else |
| 184 | | { |
| 185 | | num_secs[track] = 0; |
| 186 | | num_specials[track] = 0; |
| 187 | | } |
| 188 | | track_sizes[track] = curr_track_size; |
| 189 | | } |
| 190 | | } |
| 191 | | else |
| 192 | | { |
| 193 | | for (int track = 0; track < 163 && pos < hsize; track++) |
| 194 | | { |
| 195 | | int curr_num_sec = 0, curr_track_size = 0; |
| 196 | | for (int sect = 0; sect < 26; sect++) |
| 197 | | { |
| 198 | | // read sector map for this sector |
| 199 | | // for rev.0 format each sector uses 0x10 bytes |
| 200 | | io_generic_read(io, hsec, pos, 0x10); |
| 201 | | |
| 202 | | if (track == 0 && sect == 0) |
| 203 | | disk_type = hsec[0xa]; // can this change across the disk? I don't think so... |
| 204 | | pos += 0x10; |
| 205 | | |
| 206 | | if (hsec[0] == 0xff) // unformatted/unused sector |
| 207 | | continue; |
| 208 | | |
| 209 | | tracks[(track * 26) + sect] = hsec[0]; |
| 210 | | heads[(track * 26) + sect] = hsec[1]; |
| 211 | | secs[(track * 26) + sect] = hsec[2]; |
| 212 | | sec_sizes[(track * 26) + sect] = hsec[3]; |
| 213 | | mfm[(track * 26) + sect] = hsec[4]; |
| 214 | | |
| 215 | | curr_track_size += (128 << hsec[3]); |
| 216 | | curr_num_sec++; |
| 217 | | } |
| 218 | | |
| 219 | | num_secs[track] = curr_num_sec; |
| 220 | | track_sizes[track] = curr_track_size; |
| 221 | | } |
| 222 | | } |
| 223 | | |
| 224 | | // shouln't this be set-up depending on disk_type? gaplus does not like having less than 166666 cells |
| 225 | | int cell_count = form_factor == floppy_image::FF_35 ? 200000 : 166666; |
| 226 | | |
| 227 | | switch (disk_type) |
| 228 | | { |
| 229 | | case 0x10: // 640K disk, 2DD |
| 230 | | image->set_variant(floppy_image::DSDD); |
| 231 | | break; |
| 232 | | //case 0x30: // 1.44M disk, ?? (no images found) |
| 233 | | // break; |
| 234 | | case 0x90: // 1.2M disk, 2HD |
| 235 | | default: |
| 236 | | image->set_variant(floppy_image::DSHD); |
| 237 | | break; |
| 238 | | } |
| 239 | | |
| 240 | | desc_pc_sector sects[256]; |
| 241 | | UINT8 sect_data[65536]; |
| 242 | | int cur_sec_map = 0, sector_size; |
| 243 | | pos = hsize; |
| 244 | | |
| 245 | | for (int track = 0; track < 163 && pos < size; track++) |
| 246 | | { |
| 247 | | io_generic_read(io, sect_data, pos, track_sizes[track]); |
| 248 | | |
| 249 | | for (int i = 0; i < num_secs[track]; i++) |
| 250 | | { |
| 251 | | cur_sec_map = track * 26 + i; |
| 252 | | sector_size = 128 << sec_sizes[cur_sec_map]; |
| 253 | | sects[i].track = tracks[cur_sec_map]; |
| 254 | | sects[i].head = heads[cur_sec_map]; |
| 255 | | sects[i].sector = secs[cur_sec_map]; |
| 256 | | sects[i].size = sec_sizes[cur_sec_map]; |
| 257 | | sects[i].actual_size = sector_size; |
| 258 | | sects[i].deleted = false; |
| 259 | | sects[i].bad_crc = false; |
| 260 | | sects[i].data = sect_data + i * sector_size; |
| 261 | | } |
| 262 | | pos += track_sizes[track]; |
| 263 | | |
| 264 | | // notice that the operation below might fail if sectors of the same track have variable sec_sizes, |
| 265 | | // because the gap3 calculation would account correctly only for the first sector... |
| 266 | | // examined images had constant sec_sizes in the each track, so probably this is not an issue |
| 267 | | if (mfm[track * 26]) |
| 268 | | 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]))); |
| 269 | | else |
| 270 | | 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]))); |
| 271 | | } |
| 272 | | |
| 273 | | return true; |
| 274 | | } |
| 275 | | |
| 276 | | bool pc98nfd_format::supports_save() const |
| 277 | | { |
| 278 | | return false; |
| 279 | | } |
| 280 | | |
| 281 | | const floppy_format_type FLOPPY_PC98NFD_FORMAT = &floppy_image_format_creator<pc98nfd_format>; |