/*************************************************************************** dsk.c CPCEMU standard and extended disk image support. Used on Amstrad CPC and Spectrum +3 drivers. KT - 27/2/00 - Moved Disk Image handling code into this file - Fixed a few bugs - Cleaned code up a bit ***************************************************************************/ #include #include "driver.h" #include "devices/flopdrv.h" #include "devices/dsk.h" /* disk image and extended disk image support code */ /* supports up to 84 tracks and 2 sides */ #define dsk_MAX_TRACKS 84 #define dsk_MAX_SIDES 2 #define dsk_NUM_DRIVES 4 #define dsk_SECTORS_PER_TRACK 20 typedef struct { unsigned char *data; /* the whole image data */ unsigned long track_offsets[dsk_MAX_TRACKS*dsk_MAX_SIDES]; /* offset within data for each track */ unsigned long sector_offsets[dsk_SECTORS_PER_TRACK]; /* offset within current track for sector data */ int current_track; /* current track */ int disk_image_type; /* image type: standard or extended */ } dsk_drive; static void dsk_disk_image_init(dsk_drive *); static void dsk_seek_callback(mess_image *img, int physical_track); static void dsk_get_id_callback(mess_image *img, struct chrn_id *id, int id_index, int side); static int dsk_get_sectors_per_track(mess_image *img, int side); static void dsk_write_sector_data_from_buffer(mess_image *img, int sector_index, int side, const char *ptr, int length, int ddam); static void dsk_read_sector_data_into_buffer(mess_image *img, int sector_index, int side, char *ptr, int length); static floppy_interface dsk_floppy_interface = { dsk_seek_callback, dsk_get_sectors_per_track, dsk_get_id_callback, dsk_read_sector_data_into_buffer, dsk_write_sector_data_from_buffer, NULL, NULL }; static dsk_drive drives[dsk_NUM_DRIVES]; /* the drives */ static dsk_drive *get_drive(mess_image *img) { return &drives[image_index_in_device(img)]; } static int dsk_floppy_verify(UINT8 *diskimage_data) { if ( (memcmp(diskimage_data, "MV - CPC", 8)==0) || /* standard disk image? */ (memcmp(diskimage_data, "EXTENDED", 8)==0)) /* extended disk image? */ { return IMAGE_VERIFY_PASS; } return IMAGE_VERIFY_FAIL; } static int device_init_dsk_floppy(mess_image *image) { return floppy_drive_init(image, NULL); } /* load floppy */ static int device_load_dsk_floppy(mess_image *image) { int id = image_index_in_device(image); dsk_drive *thedrive = &drives[id]; /* load disk image */ thedrive->data = (unsigned char *) image_ptr(image); if (thedrive->data) { dsk_disk_image_init(thedrive); /* initialise dsk */ floppy_drive_set_disk_image_interface(image, &dsk_floppy_interface); if(dsk_floppy_verify(thedrive->data) == IMAGE_VERIFY_PASS) return INIT_PASS; else return INIT_PASS; } return INIT_PASS; } static int dsk_save(mess_image *img, unsigned char **ptr) { int datasize; unsigned char *data; /* get file size */ datasize = image_length(img); if (datasize!=0) { data = *ptr; if (data!=NULL) { image_fwrite(img, data, datasize); /* ok! */ return 1; } } return 0; } static void device_unload_dsk_floppy(mess_image *image) { int id = image_index_in_device(image); dsk_drive *thedrive = &drives[id]; if (thedrive->data) dsk_save(image, &thedrive->data); thedrive->data = NULL; } static void dsk_dsk_init_track_offsets(dsk_drive *thedrive) { int track_offset; int i; int track_size; int tracks, sides; int skip, length,offs; unsigned char *file_loaded = thedrive->data; /* get size of each track from main header. Size of each track includes a 0x0100 byte header, and the actual sector data for all sectors on the track */ track_size = file_loaded[0x032] | (file_loaded[0x033]<<8); /* main header is 0x0100 in size */ track_offset = 0x0100; sides = file_loaded[0x031]; tracks = file_loaded[0x030]; /* single sided? */ if (sides==1) { skip = 2; length = tracks; } else { skip = 1; length = tracks*sides; } offs = 0; for (i=0; itrack_offsets[offs] = track_offset; track_offset+=track_size; offs+=skip; } } static void dsk_dsk_init_sector_offsets(dsk_drive *thedrive,int track,int side) { int track_offset; side = side & 0x01; /* get offset to track header in image */ track_offset = thedrive->track_offsets[(track<<1) + side]; if (track_offset!=0) { int spt; int sector_offset; int sector_size; int i; unsigned char *track_header; track_header= &thedrive->data[track_offset]; /* sectors per track as specified in nec765 format command */ /* sectors on this track */ spt = track_header[0x015]; sector_size = (1<<(track_header[0x014]+7)); /* track header is 0x0100 bytes in size */ sector_offset = 0x0100; for (i=0; isector_offsets[i] = sector_offset; sector_offset+=sector_size; } } } static void dsk_extended_dsk_init_track_offsets(dsk_drive *thedrive) { int track_offset; int i; int track_size; int tracks, sides; int offs, skip, length; unsigned char *file_loaded = thedrive->data; sides = file_loaded[0x031]; tracks = file_loaded[0x030]; if (sides==1) { skip = 2; length = tracks; } else { skip = 1; length = tracks*sides; } /* main header is 0x0100 in size */ track_offset = 0x0100; offs = 0; for (i=0; itrack_offsets[offs] = track_offset; track_offset+=track_size; } offs+=skip; } } static void dsk_extended_dsk_init_sector_offsets(dsk_drive *thedrive,int track,int side) { int track_offset; side = side & 0x01; /* get offset to track header in image */ track_offset = thedrive->track_offsets[(track<<1) + side]; if (track_offset!=0) { int spt; int sector_offset; int sector_size; int i; unsigned char *id_info; unsigned char *track_header; track_header= &thedrive->data[track_offset]; /* sectors per track as specified in nec765 format command */ /* sectors on this track */ spt = track_header[0x015]; id_info = track_header + 0x018; /* track header is 0x0100 bytes in size */ sector_offset = 0x0100; for (i=0; isector_offsets[i] = sector_offset; sector_offset+=sector_size; } } } static void dsk_disk_image_init(dsk_drive *thedrive) { /*-----------------27/02/00 11:26------------------- clear offsets --------------------------------------------------*/ memset(&thedrive->track_offsets[0], 0, dsk_MAX_TRACKS*dsk_MAX_SIDES*sizeof(unsigned long)); memset(&thedrive->sector_offsets[0], 0, 20*sizeof(unsigned long)); if (memcmp(thedrive->data,"MV - CPC",8)==0) { thedrive->disk_image_type = 0; /* standard disk image */ dsk_dsk_init_track_offsets(thedrive); } else if (memcmp(thedrive->data,"EXTENDED",8)==0) { thedrive->disk_image_type = 1; /* extended disk image */ dsk_extended_dsk_init_track_offsets(thedrive); } } static void dsk_seek_callback(mess_image *img, int physical_track) { get_drive(img)->current_track = physical_track; } static int get_track_offset(mess_image *img, int side) { dsk_drive *thedrive = get_drive(img); side = side & 0x01; return thedrive->track_offsets[(thedrive->current_track<<1) + side]; } static unsigned char *get_floppy_data(mess_image *img) { return get_drive(img)->data; } static void dsk_get_id_callback(mess_image *img, chrn_id *id, int id_index, int side) { int id_offset; int track_offset; unsigned char *track_header; unsigned char *data; side = side & 0x01; /* get offset to track header in image */ track_offset = get_track_offset(img, side); /* track exists? */ if (track_offset==0) return; /* yes */ data = get_floppy_data(img); if (data==0) return; track_header = data + track_offset; id_offset = 0x018 + (id_index<<3); id->C = track_header[id_offset + 0]; id->H = track_header[id_offset + 1]; id->R = track_header[id_offset + 2]; id->N = track_header[id_offset + 3]; id->flags = 0; id->data_id = id_index; if (track_header[id_offset + 5] & 0x040) { id->flags |= ID_FLAG_DELETED_DATA; } // id->ST0 = track_header[id_offset + 4]; // id->ST1 = track_header[id_offset + 5]; } static void dsk_set_ddam(mess_image *img, int id_index, int side, int ddam) { int id_offset; int track_offset; unsigned char *track_header; unsigned char *data; side = side & 0x01; /* get offset to track header in image */ track_offset = get_track_offset(img, side); /* track exists? */ if (track_offset==0) return; /* yes */ data = get_floppy_data(img); if (data==0) return; track_header = data + track_offset; id_offset = 0x018 + (id_index<<3); track_header[id_offset + 5] &= ~0x040; if (ddam) { track_header[id_offset + 5] |= 0x040; } } static char * dsk_get_sector_ptr_callback(mess_image *img, int sector_index, int side) { int track_offset; int sector_offset; int track; dsk_drive *thedrive; unsigned char *data; side = side & 0x01; thedrive = get_drive(img); track = thedrive->current_track; /* offset to track header in image */ track_offset = get_track_offset(img, side); /* track exists? */ if (track_offset==0) return NULL; /* setup sector offsets */ switch (thedrive->disk_image_type) { case 0: dsk_dsk_init_sector_offsets(thedrive,track, side); break; case 1: dsk_extended_dsk_init_sector_offsets(thedrive, track, side); break; default: break; } sector_offset = thedrive->sector_offsets[sector_index]; data = get_floppy_data(img); if (data==0) return NULL; return (char *)(data + track_offset + sector_offset); } static void dsk_write_sector_data_from_buffer(mess_image *img, int side, int index1, const char *ptr, int length, int ddam) { char * pSectorData; pSectorData = dsk_get_sector_ptr_callback(img, index1, side); if (pSectorData!=NULL) { memcpy(pSectorData, ptr, length); } /* set ddam */ dsk_set_ddam(img, index1, side,ddam); } static void dsk_read_sector_data_into_buffer(mess_image *img, int side, int index1, char *ptr, int length) { char *pSectorData; pSectorData = dsk_get_sector_ptr_callback(img, index1, side); if (pSectorData!=NULL) memcpy(ptr, pSectorData, length); } static int dsk_get_sectors_per_track(mess_image *img, int side) { int track_offset; unsigned char *track_header; unsigned char *data; side = side & 0x01; /* get offset to track header in image */ track_offset = get_track_offset(img, side); /* track exists? */ if (track_offset==0) return 0; data = get_floppy_data(img); if (data==0) return 0; /* yes, get sectors per track */ track_header = data + track_offset; return track_header[0x015]; } void legacydsk_device_getinfo(const device_class *devclass, UINT32 state, union devinfo *info) { switch(state) { /* --- the following bits of info are returned as 64-bit signed integers --- */ case DEVINFO_INT_TYPE: info->i = IO_FLOPPY; break; case DEVINFO_INT_READABLE: info->i = 1; break; case DEVINFO_INT_WRITEABLE: info->i = 1; break; case DEVINFO_INT_CREATABLE: info->i = 0; break; /* --- the following bits of info are returned as pointers to data or functions --- */ case DEVINFO_PTR_INIT: info->init = device_init_dsk_floppy; break; case DEVINFO_PTR_LOAD: info->load = device_load_dsk_floppy; break; case DEVINFO_PTR_UNLOAD: info->unload = device_unload_dsk_floppy; break; case DEVINFO_PTR_STATUS: /* info->status = floppy_status; */ break; /* --- the following bits of info are returned as NULL-terminated strings --- */ case DEVINFO_STR_DEV_FILE: strcpy(info->s = device_temp_str(), __FILE__); break; case DEVINFO_STR_FILE_EXTENSIONS: strcpy(info->s = device_temp_str(), "dsk"); break; } }