/* * D77 and D88 disk images * * * Header (total size = 0x2b0 bytes): * 0x00 - Disk label * 0x1a - Write protect (bit 3) * 0x1b - 2D/2DD format (bit 3) * 0x1c-1f - image size (should match file size) * 0x20 - offsets for each track (max 164) * * Sectors (0x110 bytes each, typically) * 0x00 - Sector info * byte 0 - track number * byte 1 - side (0 or 1) * byte 2 - sector number * 0x10 - sector data * * Images can be concatenated together. * Sectors can be in any order. * Tracks are in the order: * Track 0 side 0 * Track 0 side 1 * Track 1 side 0 * ... * * */ #include "flopimg.h" #include "imageutl.h" #define D88_HEADER_LEN 0x2b0 struct d88_tag { UINT32 image_size; UINT32 trackoffset[164]; UINT8 write_protect; UINT8 disk_type; UINT8 heads; }; static struct d88_tag *get_d88_tag(floppy_image_legacy *floppy) { return (d88_tag *)floppy_tag(floppy); } static int d88_get_sector_id(floppy_image_legacy *floppy, int head, int track, int sector_index) { struct d88_tag* tag = get_d88_tag(floppy); UINT32 offset; UINT8 sector_hdr[16]; int x; offset = tag->trackoffset[(track*tag->heads)+head]; if(offset == 0) return 0; floppy_image_read(floppy,sector_hdr,offset,16); // get to sector indexed x=0; while(xheads; } static int d88_get_sectors_per_track(floppy_image_legacy *floppy, int head, int track) { struct d88_tag* tag = get_d88_tag(floppy); UINT32 offset; UINT8 sector_hdr[16]; offset = tag->trackoffset[(track*tag->heads)+head]; floppy_image_read(floppy,sector_hdr,offset,16); return sector_hdr[4]; } static floperr_t d88_get_sector_length(floppy_image_legacy *floppy, int head, int track, int sector, UINT32 *sector_length) { struct d88_tag* tag = get_d88_tag(floppy); UINT32 offset; UINT8 sector_hdr[16]; UINT32 len; int count,secs; offset = tag->trackoffset[(track*tag->heads)+head]; floppy_image_read(floppy,sector_hdr,offset,16); secs = sector_hdr[4]; for(count=0;counttrackoffset[(track*tag->heads)+head]; floppy_image_read(floppy,sector_hdr,offset,16); secs = sector_hdr[4]; for(count=0;counttrackoffset[(track*tag->heads)+head]; if(offset == 0) return FLOPPY_ERROR_SEEKERROR; floppy_image_read(floppy,sector_hdr,offset,16); if(sector_index >= sector_hdr[4]) return FLOPPY_ERROR_SEEKERROR; // get to sector indexed x=0; while(x tag->image_size || offset == 0) return FLOPPY_ERROR_SEEKERROR; if(sector_length) *sector_length = (sector_hdr[15] << 8) | sector_hdr[14]; if(cylinder) *cylinder = sector_hdr[0]; if(side) *side = sector_hdr[1]; if(sector) *sector = sector_hdr[2]; if(flags) *flags = 0; return FLOPPY_ERROR_SUCCESS; } static floperr_t d88_read_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buflen) { UINT64 offset; UINT32 sector_length; offset = d88_get_sector_offset(floppy,head,track,sector); if(d88_get_sector_length(floppy,head,track,sector,§or_length) != FLOPPY_ERROR_SUCCESS) return FLOPPY_ERROR_SEEKERROR; if(offset == 0) return FLOPPY_ERROR_SEEKERROR; if(buflen > sector_length) return FLOPPY_ERROR_INTERNAL; floppy_image_read(floppy,buffer,offset,sector_length); return FLOPPY_ERROR_SUCCESS; } static floperr_t d88_read_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, void *buffer, size_t buffer_len) { int sec; sec = d88_get_sector_id(floppy,head,track,sector); return d88_read_sector(floppy,head,track,sec,buffer,buffer_len); } static floperr_t d88_write_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) { UINT64 offset; UINT32 sector_length; offset = d88_get_sector_offset(floppy,head,track,sector); if(d88_get_sector_length(floppy,head,track,sector,§or_length) != FLOPPY_ERROR_SUCCESS) return FLOPPY_ERROR_SEEKERROR; if(offset == 0) return FLOPPY_ERROR_SEEKERROR; if(buflen > sector_length) return FLOPPY_ERROR_INTERNAL; floppy_image_write(floppy,buffer,offset,sector_length); return FLOPPY_ERROR_SUCCESS; } static floperr_t d88_write_indexed_sector(floppy_image_legacy *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam) { int sec; sec = d88_get_sector_id(floppy,head,track,sector); return d88_write_sector(floppy,head,track,sec,buffer,buflen,ddam); } static void d88_get_header(floppy_image_legacy* floppy,UINT32* size, UINT8* prot, UINT8* type, UINT32* offsets) { UINT8 header[D88_HEADER_LEN]; int x,s; floppy_image_read(floppy,header,0,D88_HEADER_LEN); #ifdef SPOT_DUPLICATES // there exist many .d88 files with same data and different headers and // this allows to spot duplicates, making easier to debug softlists. UINT32 temp_size = floppy_image_size(floppy); UINT8 tmp_copy[temp_size - D88_HEADER_LEN]; floppy_image_read(floppy,tmp_copy,D88_HEADER_LEN,temp_size - D88_HEADER_LEN); printf("CRC16: %d\n", ccitt_crc16(0xffff, tmp_copy, temp_size - D88_HEADER_LEN)); #endif if(prot) *prot = header[0x1a]; if(type) *type = header[0x1b]; if(size) { s = 0; s |= header[0x1f] << 24; s |= header[0x1e] << 16; s |= header[0x1d] << 8; s |= header[0x1c]; *size = s; } if(offsets) { for(x=0;x<164;x++) { s = 0; s |= header[0x23 + (x*4)] << 24; s |= header[0x22 + (x*4)] << 16; s |= header[0x21 + (x*4)] << 8; s |= header[0x20 + (x*4)]; *(offsets+x) = s; } } } FLOPPY_IDENTIFY(d88_dsk_identify) { UINT32 size; d88_get_header(floppy,&size,NULL,NULL,NULL); if(floppy_image_size(floppy) == size) { *vote = 100; } else { *vote = 0; } return FLOPPY_ERROR_SUCCESS; } FLOPPY_CONSTRUCT(d88_dsk_construct) { struct FloppyCallbacks *callbacks; struct d88_tag *tag; UINT32 size; UINT8 prot,type = 0; UINT32 offs[164]; int x; if(params) { // create return FLOPPY_ERROR_UNSUPPORTED; } else { // load d88_get_header(floppy,&size,&prot,&type,offs); } tag = (d88_tag *)floppy_create_tag(floppy,sizeof(struct d88_tag)); if (!tag) return FLOPPY_ERROR_OUTOFMEMORY; tag->write_protect = prot; tag->disk_type = type; tag->heads = 2; if (tag->disk_type==0x30 || tag->disk_type==0x40) tag->heads = 1; tag->image_size = size; for(x=0;x<164;x++) tag->trackoffset[x] = offs[x]; callbacks = floppy_callbacks(floppy); callbacks->read_track = d88_read_track; callbacks->get_heads_per_disk = d88_get_heads_per_disk; callbacks->get_tracks_per_disk = d88_get_tracks_per_disk; callbacks->get_sector_length = d88_get_sector_length; callbacks->read_sector = d88_read_sector; callbacks->read_indexed_sector = d88_read_indexed_sector; callbacks->write_sector = d88_write_sector; callbacks->write_indexed_sector = d88_write_indexed_sector; callbacks->get_indexed_sector_info = d88_get_indexed_sector_info; callbacks->get_sectors_per_track = d88_get_sectors_per_track; return FLOPPY_ERROR_SUCCESS; } /*************************************************************************** Copyright Olivier Galibert All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name 'MAME' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************/ /********************************************************************* formats/d88_dsk.h D88 disk images *********************************************************************/ #include "emu.h" #include "d88_dsk.h" d88_format::d88_format() { } const char *d88_format::name() const { return "d88"; } const char *d88_format::description() const { return "D88 disk image"; } const char *d88_format::extensions() const { return "d77,d88,1dd"; } int d88_format::identify(io_generic *io, UINT32 form_factor) { int size = io_generic_size(io); UINT8 h[32]; io_generic_read(io, h, 0, 32); if((LITTLE_ENDIANIZE_INT32(*(UINT32 *)(h+0x1c)) == size) && (h[0x1b] == 0x00 || h[0x1b] == 0x10 || h[0x1b] == 0x20 || h[0x1b] == 0x30 || h[0x1b] == 0x40)) return 100; return 0; } 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;