diff options
author | 2011-01-05 15:59:06 +0000 | |
---|---|---|
committer | 2011-01-05 15:59:06 +0000 | |
commit | 12a5370d85b9176b7b8849354432d40f8f8531b0 (patch) | |
tree | 674c3441a416e1e37e75b438f989acbb3d80907e /src/emu/imagedev/flopdrv.c | |
parent | 56b43ee6871a3a4b01e2d23a5bb3e6e0b0c8f32b (diff) |
Moved image devices implementation and related UI functions to emu section from MESS [Miodrag Milanovic]
Diffstat (limited to 'src/emu/imagedev/flopdrv.c')
-rw-r--r-- | src/emu/imagedev/flopdrv.c | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/src/emu/imagedev/flopdrv.c b/src/emu/imagedev/flopdrv.c new file mode 100644 index 00000000000..8295839a1df --- /dev/null +++ b/src/emu/imagedev/flopdrv.c @@ -0,0 +1,1045 @@ +/* + This code handles the floppy drives. + All FDD actions should be performed using these functions. + + The functions are emulated and a disk image is used. + + Real disk operation: + - set unit id + + TODO: + - Override write protect if disk image has been opened in read mode +*/ + +#include "emu.h" +#include "imageutl.h" +#include "flopdrv.h" + +#define VERBOSE 0 +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define FLOPDRVTAG "flopdrv" +#define LOG_FLOPPY 0 + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _floppy_drive floppy_drive; +struct _floppy_drive +{ + /* callbacks */ + devcb_resolved_write_line out_idx_func; + devcb_resolved_read_line in_mon_func; + devcb_resolved_write_line out_tk00_func; + devcb_resolved_write_line out_wpt_func; + devcb_resolved_write_line out_rdy_func; + devcb_resolved_write_line out_dskchg_func; + + /* state of input lines */ + int drtn; /* direction */ + int stp; /* step */ + int wtg; /* write gate */ + int mon; /* motor on */ + + /* state of output lines */ + int idx; /* index pulse */ + int tk00; /* track 00 */ + int wpt; /* write protect */ + int rdy; /* ready */ + int dskchg; /* disk changed */ + + /* drive select logic */ + int drive_id; + int active; + + const floppy_config *config; + + /* flags */ + int flags; + /* maximum track allowed */ + int max_track; + /* num sides */ + int num_sides; + /* current track - this may or may not relate to the present cylinder number + stored by the fdc */ + int current_track; + + /* index pulse timer */ + void *index_timer; + /* index pulse callback */ + void (*index_pulse_callback)(device_t *controller,device_t *image, int state); + /* rotation per minute => gives index pulse frequency */ + float rpm; + + void (*ready_state_change_callback)(device_t *controller,device_t *img, int state); + + int id_index; + + device_t *controller; + + floppy_image *floppy; + int track; + void (*load_proc)(device_image_interface &image); + void (*unload_proc)(device_image_interface &image); + void *custom_data; + int floppy_drive_type; +}; + + +typedef struct _floppy_error_map floppy_error_map; +struct _floppy_error_map +{ + floperr_t ferr; + image_error_t ierr; + const char *message; +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static const floppy_error_map errmap[] = +{ + { FLOPPY_ERROR_SUCCESS, IMAGE_ERROR_SUCCESS }, + { FLOPPY_ERROR_INTERNAL, IMAGE_ERROR_INTERNAL }, + { FLOPPY_ERROR_UNSUPPORTED, IMAGE_ERROR_UNSUPPORTED }, + { FLOPPY_ERROR_OUTOFMEMORY, IMAGE_ERROR_OUTOFMEMORY }, + { FLOPPY_ERROR_INVALIDIMAGE, IMAGE_ERROR_INVALIDIMAGE } +}; + +/*************************************************************************** + IMPLEMENTATION +***************************************************************************/ +DECLARE_LEGACY_IMAGE_DEVICE(FLOPPY_APPLE, apple525); +DECLARE_LEGACY_IMAGE_DEVICE(FLOPPY_SONY, sonydriv); + +INLINE floppy_drive *get_safe_token(device_t *device) +{ + assert( device != NULL ); + assert( device->type() == FLOPPY || device->type() == FLOPPY_APPLE || device->type() == FLOPPY_SONY); + return (floppy_drive *) downcast<legacy_device_base *>(device)->token(); +} + +floppy_image *flopimg_get_image(device_t *image) +{ + return get_safe_token(image)->floppy; +} + +void *flopimg_get_custom_data(device_t *image) +{ + floppy_drive *flopimg = get_safe_token( image ); + return flopimg->custom_data; +} + +void flopimg_alloc_custom_data(device_t *image,void *custom) +{ + floppy_drive *flopimg = get_safe_token( image ); + flopimg->custom_data = custom; +} + +static int flopimg_get_sectors_per_track(device_t *image, int side) +{ + floperr_t err; + int sector_count; + floppy_drive *flopimg = get_safe_token( image ); + + if (!flopimg || !flopimg->floppy) + return 0; + + err = floppy_get_sector_count(flopimg->floppy, side, flopimg->track, §or_count); + if (err) + return 0; + return sector_count; +} + +static void flopimg_get_id_callback(device_t *image, chrn_id *id, int id_index, int side) +{ + floppy_drive *flopimg; + int cylinder, sector, N; + unsigned long flags; + UINT32 sector_length; + + flopimg = get_safe_token( image ); + if (!flopimg || !flopimg->floppy) + return; + + floppy_get_indexed_sector_info(flopimg->floppy, side, flopimg->track, id_index, &cylinder, &side, §or, §or_length, &flags); + + N = compute_log2(sector_length); + + id->C = cylinder; + id->H = side; + id->R = sector; + id->data_id = id_index; + id->flags = flags; + id->N = ((N >= 7) && (N <= 10)) ? N - 7 : 0; +} + +static void log_readwrite(const char *name, int head, int track, int sector, const char *buf, int length) +{ + char membuf[1024]; + int i; + for (i = 0; i < length; i++) + sprintf(membuf + i*2, "%02x", (int) (UINT8) buf[i]); + logerror("%s: head=%i track=%i sector=%i buffer='%s'\n", name, head, track, sector, membuf); +} + +static void floppy_drive_set_geometry_absolute(device_t *img, int tracks, int sides) +{ + floppy_drive *pDrive = get_safe_token( img ); + pDrive->max_track = tracks; + pDrive->num_sides = sides; +} + +void floppy_drive_set_geometry(device_t *img, floppy_type_t type) +{ + floppy_drive_set_geometry_absolute(img, type.max_track_number, type.head_number); +} + +static TIMER_CALLBACK(floppy_drive_index_callback); + +/* this is called on device init */ +static void floppy_drive_init(device_t *img) +{ + floppy_drive *pDrive = get_safe_token( img ); + + /* initialise flags */ + pDrive->flags = 0; + pDrive->index_pulse_callback = NULL; + pDrive->ready_state_change_callback = NULL; + pDrive->index_timer = timer_alloc(img->machine, floppy_drive_index_callback, (void *) img); + pDrive->idx = 0; + + floppy_drive_set_geometry(img, ((floppy_config*)img->baseconfig().static_config())->floppy_type); + + /* initialise id index - not so important */ + pDrive->id_index = 0; + /* initialise track */ + pDrive->current_track = 0; + + /* default RPM */ + pDrive->rpm = 300; + + pDrive->controller = NULL; + + pDrive->custom_data = NULL; + + pDrive->floppy_drive_type = FLOPPY_TYPE_REGULAR; +} + +/* index pulses at rpm/60 Hz, and stays high 1/20th of time */ +static void floppy_drive_index_func(device_t *img) +{ + floppy_drive *drive = get_safe_token( img ); + + double ms = 1000.0 / (drive->rpm / 60.0); + + if (drive->idx) + { + drive->idx = 0; + timer_adjust_oneshot((emu_timer*)drive->index_timer, double_to_attotime(ms*19/20/1000.0), 0); + } + else + { + drive->idx = 1; + timer_adjust_oneshot((emu_timer*)drive->index_timer, double_to_attotime(ms/20/1000.0), 0); + } + + devcb_call_write_line(&drive->out_idx_func, drive->idx); + + if (drive->index_pulse_callback) + drive->index_pulse_callback(drive->controller, img, drive->idx); +} + +static TIMER_CALLBACK(floppy_drive_index_callback) +{ + device_t *image = (device_t *) ptr; + floppy_drive_index_func(image); +} + +/*************************************************************************/ +/* IO_FLOPPY device functions */ + +/* set flag state */ +void floppy_drive_set_flag_state(device_t *img, int flag, int state) +{ + floppy_drive *drv = get_safe_token( img ); + int prev_state; + int new_state; + + /* get old state */ + prev_state = drv->flags & flag; + + /* set new state */ + drv->flags &= ~flag; + if (state) + drv->flags |= flag; + + /* get new state */ + new_state = drv->flags & flag; + + /* changed state? */ + if (prev_state ^ new_state) + { + if (flag & FLOPPY_DRIVE_READY) + { + /* trigger state change callback */ + devcb_call_write_line(&drv->out_rdy_func, new_state ? ASSERT_LINE : CLEAR_LINE); + + if (drv->ready_state_change_callback) + drv->ready_state_change_callback(drv->controller, img, new_state); + } + } +} + +/* for pc, drive is always ready, for amstrad,pcw,spectrum it is only ready under +a fixed set of circumstances */ +/* use this to set ready state of drive */ +void floppy_drive_set_ready_state(device_t *img, int state, int flag) +{ + floppy_drive *drive = get_safe_token(img); + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + if (flag) + { + /* set ready only if drive is present, disk is in the drive, + and disk motor is on - for Amstrad, Spectrum and PCW*/ + + /* drive present? */ + /* disk inserted? */ + if (image->exists()) + { + if (drive->mon == CLEAR_LINE) + { + /* set state */ + floppy_drive_set_flag_state(img, FLOPPY_DRIVE_READY, state); + return; + } + } + floppy_drive_set_flag_state(img, FLOPPY_DRIVE_READY, 0); + } + else + { + /* force ready state - for PC driver */ + floppy_drive_set_flag_state(img, FLOPPY_DRIVE_READY, state); + } +} + +/* get flag state */ +int floppy_drive_get_flag_state(device_t *img, int flag) +{ + floppy_drive *drv = get_safe_token( img ); + int drive_flags; + int flags; + + flags = 0; + + drive_flags = drv->flags; + + /* these flags are independant of a real drive/disk image */ + flags |= drive_flags & (FLOPPY_DRIVE_READY | FLOPPY_DRIVE_INDEX); + + flags &= flag; + + return flags; +} + + +void floppy_drive_seek(device_t *img, signed int signed_tracks) +{ + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + floppy_drive *pDrive; + + pDrive = get_safe_token( img ); + + LOG(("seek from: %d delta: %d\n",pDrive->current_track, signed_tracks)); + + /* update position */ + pDrive->current_track+=signed_tracks; + + if (pDrive->current_track<0) + { + pDrive->current_track = 0; + } + else + if (pDrive->current_track>=pDrive->max_track) + { + pDrive->current_track = pDrive->max_track-1; + } + + /* set track 0 flag */ + pDrive->tk00 = (pDrive->current_track == 0) ? CLEAR_LINE : ASSERT_LINE; + devcb_call_write_line(&pDrive->out_tk00_func, pDrive->tk00); + + /* clear disk changed flag */ + pDrive->dskchg = ASSERT_LINE; + //devcb_call_write_line(&flopimg->out_dskchg_func, flopimg->dskchg); + + /* inform disk image of step operation so it can cache information */ + if (image->exists()) + pDrive->track = pDrive->current_track; + + pDrive->id_index = 0; +} + + +/* this is not accurate. But it will do for now */ +int floppy_drive_get_next_id(device_t *img, int side, chrn_id *id) +{ + floppy_drive *pDrive; + int spt; + + pDrive = get_safe_token( img ); + + /* get sectors per track */ + spt = flopimg_get_sectors_per_track(img, side); + + /* set index */ + if ((pDrive->id_index==(spt-1)) || (spt==0)) + { + floppy_drive_set_flag_state(img, FLOPPY_DRIVE_INDEX, 1); + } + else + { + floppy_drive_set_flag_state(img, FLOPPY_DRIVE_INDEX, 0); + } + + /* get id */ + if (spt!=0) + { + flopimg_get_id_callback(img, id, pDrive->id_index, side); + } + + pDrive->id_index++; + if (spt!=0) + pDrive->id_index %= spt; + else + pDrive->id_index = 0; + + return (spt == 0) ? 0 : 1; +} + +void floppy_drive_read_track_data_info_buffer(device_t *img, int side, void *ptr, int *length ) +{ + floppy_drive *flopimg; + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { + flopimg = get_safe_token( img ); + if (!flopimg || !flopimg->floppy) + return; + + floppy_read_track_data(flopimg->floppy, side, flopimg->track, ptr, *length); + } +} + +void floppy_drive_write_track_data_info_buffer(device_t *img, int side, const void *ptr, int *length ) +{ + floppy_drive *flopimg; + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { + flopimg = get_safe_token( img ); + if (!flopimg || !flopimg->floppy) + return; + + floppy_write_track_data(flopimg->floppy, side, flopimg->track, ptr, *length); + } +} + +void floppy_drive_format_sector(device_t *img, int side, int sector_index,int c,int h, int r, int n, int filler) +{ + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { +/* if (drv->interface_.format_sector) + drv->interface_.format_sector(img, side, sector_index,c, h, r, n, filler);*/ + } +} + +void floppy_drive_read_sector_data(device_t *img, int side, int index1, void *ptr, int length) +{ + floppy_drive *flopimg; + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { + flopimg = get_safe_token( img ); + if (!flopimg || !flopimg->floppy) + return; + + floppy_read_indexed_sector(flopimg->floppy, side, flopimg->track, index1, 0, ptr, length); + + if (LOG_FLOPPY) + log_readwrite("sector_read", side, flopimg->track, index1, (const char *)ptr, length); + + } +} + +void floppy_drive_write_sector_data(device_t *img, int side, int index1, const void *ptr,int length, int ddam) +{ + floppy_drive *flopimg; + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { + flopimg = get_safe_token( img ); + if (!flopimg || !flopimg->floppy) + return; + + if (LOG_FLOPPY) + log_readwrite("sector_write", side, flopimg->track, index1, (const char *)ptr, length); + + floppy_write_indexed_sector(flopimg->floppy, side, flopimg->track, index1, 0, ptr, length, ddam); + } +} + +void floppy_install_load_proc(device_t *image, void (*proc)(device_image_interface &image)) +{ + floppy_drive *flopimg = get_safe_token( image ); + flopimg->load_proc = proc; +} + +void floppy_install_unload_proc(device_t *image, void (*proc)(device_image_interface &image)) +{ + floppy_drive *flopimg = get_safe_token( image ); + flopimg->unload_proc = proc; +} + +/* set the callback for the index pulse */ +void floppy_drive_set_index_pulse_callback(device_t *img, void (*callback)(device_t *controller,device_t *image, int state)) +{ + floppy_drive *pDrive = get_safe_token( img ); + pDrive->index_pulse_callback = callback; +} + + +void floppy_drive_set_ready_state_change_callback(device_t *img, void (*callback)(device_t *controller,device_t *img, int state)) +{ + floppy_drive *pDrive = get_safe_token( img ); + pDrive->ready_state_change_callback = callback; +} + +int floppy_drive_get_current_track(device_t *img) +{ + floppy_drive *drv = get_safe_token( img ); + return drv->current_track; +} + +UINT64 floppy_drive_get_current_track_size(device_t *img, int head) +{ + floppy_drive *drv = get_safe_token( img ); + int size = 0; + device_image_interface *image = dynamic_cast<device_image_interface *>(img); + + if (image->exists()) + { + size = floppy_get_track_size(drv->floppy, head, drv->current_track); + } + + return size; +} + +void floppy_drive_set_rpm(device_t *img, float rpm) +{ + floppy_drive *drv = get_safe_token( img ); + drv->rpm = rpm; +} + +void floppy_drive_set_controller(device_t *img, device_t *controller) +{ + floppy_drive *drv = get_safe_token( img ); + drv->controller = controller; +} + +/* ----------------------------------------------------------------------- */ +DEVICE_START( floppy ) +{ + floppy_drive *floppy = get_safe_token( device ); + floppy->config = (const floppy_config*)device->baseconfig().static_config(); + floppy_drive_init(device); + + floppy->drive_id = floppy_get_drive(device); + floppy->active = FALSE; + + /* resolve callbacks */ + devcb_resolve_write_line(&floppy->out_idx_func, &floppy->config->out_idx_func, device); + devcb_resolve_read_line(&floppy->in_mon_func, &floppy->config->in_mon_func, device); + devcb_resolve_write_line(&floppy->out_tk00_func, &floppy->config->out_tk00_func, device); + devcb_resolve_write_line(&floppy->out_wpt_func, &floppy->config->out_wpt_func, device); + devcb_resolve_write_line(&floppy->out_rdy_func, &floppy->config->out_rdy_func, device); +// devcb_resolve_write_line(&floppy->out_dskchg_func, &floppy->config->out_dskchg_func, device); + + /* by default we are not write-protected */ + floppy->wpt = ASSERT_LINE; + devcb_call_write_line(&floppy->out_wpt_func, floppy->wpt); + + /* not at track 0 */ + floppy->tk00 = ASSERT_LINE; + devcb_call_write_line(&floppy->out_tk00_func, floppy->tk00); + + /* motor off */ + floppy->mon = ASSERT_LINE; + + /* disk changed */ + floppy->dskchg = CLEAR_LINE; +// devcb_call_write_line(&floppy->out_dskchg_func, floppy->dskchg); +} + +static int internal_floppy_device_load(device_image_interface *image, int create_format, option_resolution *create_args) +{ + floperr_t err; + floppy_drive *flopimg; + const struct FloppyFormat *floppy_options; + int floppy_flags, i; + const char *extension; + + /* look up instance data */ + flopimg = get_safe_token( &image->device() ); + + /* figure out the floppy options */ + floppy_options = ((floppy_config*)image->device().baseconfig().static_config())->formats; + + if (image->has_been_created()) + { + /* creating an image */ + assert(create_format >= 0); + err = floppy_create((void *) image, &image_ioprocs, &floppy_options[create_format], create_args, &flopimg->floppy); + if (err) + goto error; + } + else + { + /* opening an image */ + floppy_flags = image->is_writable() ? FLOPPY_FLAGS_READWRITE : FLOPPY_FLAGS_READONLY; + extension = image->filetype(); + err = floppy_open_choices((void *) image, &image_ioprocs, extension, floppy_options, floppy_flags, &flopimg->floppy); + if (err) + goto error; + } + if (floppy_callbacks(flopimg->floppy)->get_heads_per_disk && floppy_callbacks(flopimg->floppy)->get_tracks_per_disk) + { + floppy_drive_set_geometry_absolute(&image->device(), + floppy_get_tracks_per_disk(flopimg->floppy), + floppy_get_heads_per_disk(flopimg->floppy)); + } + return IMAGE_INIT_PASS; + +error: + for (i = 0; i < ARRAY_LENGTH(errmap); i++) + { + if (err == errmap[i].ferr) + image->seterror(errmap[i].ierr, errmap[i].message); + } + return IMAGE_INIT_FAIL; +} + +static TIMER_CALLBACK( set_wpt ) +{ + floppy_drive *flopimg = (floppy_drive *)ptr; + + flopimg->wpt = param; + devcb_call_write_line(&flopimg->out_wpt_func, param); +} + +DEVICE_IMAGE_LOAD( floppy ) +{ + floppy_drive *flopimg; + int retVal = internal_floppy_device_load(&image, -1, NULL); + flopimg = get_safe_token( &image.device() ); + if (retVal==IMAGE_INIT_PASS) { + /* if we have one of our hacky unload procs, call it */ + if (flopimg->load_proc) + flopimg->load_proc(image); + } + + /* push disk halfway into drive */ + flopimg->wpt = CLEAR_LINE; + devcb_call_write_line(&flopimg->out_wpt_func, flopimg->wpt); + + /* set timer for disk load */ + int next_wpt; + + if (image.is_writable()) + next_wpt = ASSERT_LINE; + else + next_wpt = CLEAR_LINE; + + timer_set(image.device().machine, ATTOTIME_IN_MSEC(250), flopimg, next_wpt, set_wpt); + + return retVal; +} + +DEVICE_IMAGE_CREATE( floppy ) +{ + return internal_floppy_device_load(&image, create_format, create_args); +} + +DEVICE_IMAGE_UNLOAD( floppy ) +{ + floppy_drive *flopimg = get_safe_token( &image.device() ); + if (flopimg->unload_proc) + flopimg->unload_proc(image); + + floppy_close(flopimg->floppy); + flopimg->floppy = NULL; + + /* disk changed */ + flopimg->dskchg = CLEAR_LINE; + //devcb_call_write_line(&flopimg->out_dskchg_func, flopimg->dskchg); + + /* pull disk halfway out of drive */ + flopimg->wpt = CLEAR_LINE; + devcb_call_write_line(&flopimg->out_wpt_func, flopimg->wpt); + + /* set timer for disk eject */ + timer_set(image.device().machine, ATTOTIME_IN_MSEC(250), flopimg, ASSERT_LINE, set_wpt); +} + +device_t *floppy_get_device(running_machine *machine,int drive) +{ + switch(drive) { + case 0 : return machine->device(FLOPPY_0); + case 1 : return machine->device(FLOPPY_1); + case 2 : return machine->device(FLOPPY_2); + case 3 : return machine->device(FLOPPY_3); + } + return NULL; +} + +int floppy_get_drive_type(device_t *image) +{ + floppy_drive *flopimg = get_safe_token( image ); + return flopimg->floppy_drive_type; +} + +void floppy_set_type(device_t *image,int ftype) +{ + floppy_drive *flopimg = get_safe_token( image ); + flopimg->floppy_drive_type = ftype; +} + +device_t *floppy_get_device_by_type(running_machine *machine,int ftype,int drive) +{ + int i; + int cnt = 0; + for (i=0;i<4;i++) { + device_t *disk = floppy_get_device(machine,i); + if (floppy_get_drive_type(disk)==ftype) { + if (cnt==drive) { + return disk; + } + cnt++; + } + } + return NULL; +} + +int floppy_get_drive(device_t *image) +{ + int drive =0; + if (strcmp(image->tag(), FLOPPY_0) == 0) drive = 0; + if (strcmp(image->tag(), FLOPPY_1) == 0) drive = 1; + if (strcmp(image->tag(), FLOPPY_2) == 0) drive = 2; + if (strcmp(image->tag(), FLOPPY_3) == 0) drive = 3; + return drive; +} + +int floppy_get_drive_by_type(device_t *image,int ftype) +{ + int i,drive =0; + for (i=0;i<4;i++) { + device_t *disk = floppy_get_device(image->machine,i); + if (floppy_get_drive_type(disk)==ftype) { + if (image==disk) { + return drive; + } + drive++; + } + } + return drive; +} + +int floppy_get_count(running_machine *machine) +{ + int cnt = 0; + if (machine->device(FLOPPY_0)) cnt++; + if (machine->device(FLOPPY_1)) cnt++; + if (machine->device(FLOPPY_2)) cnt++; + if (machine->device(FLOPPY_3)) cnt++; + return cnt; +} + + +/* drive select 0 */ +WRITE_LINE_DEVICE_HANDLER( floppy_ds0_w ) +{ + floppy_drive *drive = get_safe_token(device); + + if (state == CLEAR_LINE) + drive->active = (drive->drive_id == 0); +} + +/* drive select 1 */ +WRITE_LINE_DEVICE_HANDLER( floppy_ds1_w ) +{ + floppy_drive *drive = get_safe_token(device); + + if (state == CLEAR_LINE) + drive->active = (drive->drive_id == 1); +} + +/* drive select 2 */ +WRITE_LINE_DEVICE_HANDLER( floppy_ds2_w ) +{ + floppy_drive *drive = get_safe_token(device); + + if (state == CLEAR_LINE) + drive->active = (drive->drive_id == 2); +} + +/* drive select 3 */ +WRITE_LINE_DEVICE_HANDLER( floppy_ds3_w ) +{ + floppy_drive *drive = get_safe_token(device); + + if (state == CLEAR_LINE) + drive->active = (drive->drive_id == 3); +} + +/* shortcut to write all four ds lines */ +WRITE8_DEVICE_HANDLER( floppy_ds_w ) +{ + floppy_ds0_w(device, BIT(data, 0)); + floppy_ds1_w(device, BIT(data, 1)); + floppy_ds2_w(device, BIT(data, 2)); + floppy_ds3_w(device, BIT(data, 3)); +} + +/* motor on, active low */ +WRITE_LINE_DEVICE_HANDLER( floppy_mon_w ) +{ + floppy_drive *drive = get_safe_token(device); + device_image_interface *image = dynamic_cast<device_image_interface *>(device); + /* force off if there is no attached image */ + if (!image->exists()) + state = ASSERT_LINE; + + /* off -> on */ + if (drive->mon && state == CLEAR_LINE) + { + drive->idx = 0; + floppy_drive_index_func(device); + } + + /* on -> off */ + else if (drive->mon == CLEAR_LINE && state) + timer_adjust_oneshot((emu_timer*)drive->index_timer, attotime_zero, 0); + + drive->mon = state; +} + +/* direction */ +WRITE_LINE_DEVICE_HANDLER( floppy_drtn_w ) +{ + floppy_drive *drive = get_safe_token(device); + drive->drtn = state; +} + +/* write data */ +WRITE_LINE_DEVICE_HANDLER( floppy_wtd_w ) +{ + +} + +/* step */ +WRITE_LINE_DEVICE_HANDLER( floppy_stp_w ) +{ + floppy_drive *drive = get_safe_token(device); + + /* move head one track when going from high to low and write gate is high */ + if (drive->active && drive->stp && state == CLEAR_LINE && drive->wtg) + { + /* move head according to the direction line */ + if (drive->drtn) + { + /* move head outward */ + if (drive->current_track > 0) + drive->current_track--; + + /* are we at track 0 now? */ + drive->tk00 = (drive->current_track == 0) ? CLEAR_LINE : ASSERT_LINE; + } + else + { + /* move head inward */ + if (drive->current_track < drive->max_track) + drive->current_track++; + + /* we can't be at track 0 here, so reset the line */ + drive->tk00 = ASSERT_LINE; + } + + /* update track 0 line with new status */ + devcb_call_write_line(&drive->out_tk00_func, drive->tk00); + } + + drive->stp = state; +} + +/* write gate */ +WRITE_LINE_DEVICE_HANDLER( floppy_wtg_w ) +{ + floppy_drive *drive = get_safe_token(device); + drive->wtg = state; +} + +/* write protect signal, active low */ +READ_LINE_DEVICE_HANDLER( floppy_wpt_r ) +{ + floppy_drive *drive = get_safe_token(device); + return drive->wpt; +} + +/* track 0 detect */ +READ_LINE_DEVICE_HANDLER( floppy_tk00_r ) +{ + floppy_drive *drive = get_safe_token(device); + return drive->tk00; +} + +/* disk changed */ +READ_LINE_DEVICE_HANDLER( floppy_dskchg_r ) +{ + floppy_drive *drive = get_safe_token(device); + return drive->dskchg; +} + +/* 2-sided disk */ +READ_LINE_DEVICE_HANDLER( floppy_twosid_r ) +{ + floppy_drive *drive = get_safe_token(device); + + if (drive->floppy == NULL) + return ASSERT_LINE; + else + return !floppy_get_heads_per_disk(drive->floppy); +} + +/*------------------------------------------------- + DEVICE_IMAGE_SOFTLIST_LOAD(floppy) +-------------------------------------------------*/ +static DEVICE_IMAGE_SOFTLIST_LOAD(floppy) +{ + return image.load_software(swlist, swname, start_entry); +} + +/************************************* + * + * Device specification function + * + *************************************/ +/*------------------------------------------------- + safe_strcpy - hack +-------------------------------------------------*/ + +static void safe_strcpy(char *dst, const char *src) +{ + strcpy(dst, src ? src : ""); +} + +DEVICE_GET_INFO(floppy) +{ + switch( state ) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(floppy_drive); break; + case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; + case DEVINFO_INT_IMAGE_TYPE: info->i = IO_FLOPPY; break; + case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; + case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break; + case DEVINFO_INT_IMAGE_CREATABLE: + { + int cnt = 0; + if ( device && device->static_config() ) + { + const struct FloppyFormat *floppy_options = ((floppy_config*)device->static_config())->formats; + int i; + for ( i = 0; floppy_options[i].construct; i++ ) { + if(floppy_options[i].param_guidelines) cnt++; + } + } + info->i = (cnt>0) ? 1 : 0; + } + break; + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(floppy); break; + case DEVINFO_FCT_IMAGE_CREATE: info->f = (genf *) DEVICE_IMAGE_CREATE_NAME(floppy); break; + case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(floppy); break; + case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(floppy); break; + case DEVINFO_FCT_IMAGE_SOFTLIST_LOAD: info->f = (genf *) DEVICE_IMAGE_SOFTLIST_LOAD_NAME(floppy); break; + case DEVINFO_PTR_IMAGE_CREATE_OPTGUIDE: info->p = (void *)floppy_option_guide; break; + case DEVINFO_INT_IMAGE_CREATE_OPTCOUNT: + { + const struct FloppyFormat *floppy_options = ((floppy_config*)device->static_config())->formats; + int count; + for (count = 0; floppy_options[count].construct; count++) + ; + info->i = count; + break; + } + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Floppy Disk"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Floppy Disk"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: + if ( device && device->static_config() ) + { + const struct FloppyFormat *floppy_options = ((floppy_config*)device->static_config())->formats; + int i; + /* set up a temporary string */ + info->s[0] = '\0'; + for ( i = 0; floppy_options[i].construct; i++ ) + image_specify_extension( info->s, 256, floppy_options[i].extensions ); + } + break; + case DEVINFO_STR_IMAGE_INTERFACE: + if ( device && device->static_config() && ((floppy_config *)device->static_config())->interface) + { + strcpy(info->s, ((floppy_config *)device->static_config())->interface ); + } + break; + default: + { + if ( device && device->static_config() ) + { + const struct FloppyFormat *floppy_options = ((floppy_config*)device->static_config())->formats; + if ((state >= DEVINFO_PTR_IMAGE_CREATE_OPTSPEC) && (state < DEVINFO_PTR_IMAGE_CREATE_OPTSPEC + DEVINFO_IMAGE_CREATE_OPTMAX)) { + info->p = (void *) floppy_options[state - DEVINFO_PTR_IMAGE_CREATE_OPTSPEC].param_guidelines; + } else if ((state >= DEVINFO_STR_IMAGE_CREATE_OPTNAME) && (state < DEVINFO_STR_IMAGE_CREATE_OPTNAME + DEVINFO_IMAGE_CREATE_OPTMAX)) { + safe_strcpy(info->s,floppy_options[state - DEVINFO_STR_IMAGE_CREATE_OPTNAME].name); + } + else if ((state >= DEVINFO_STR_IMAGE_CREATE_OPTDESC) && (state < DEVINFO_STR_IMAGE_CREATE_OPTDESC + DEVINFO_IMAGE_CREATE_OPTMAX)) { + safe_strcpy(info->s,floppy_options[state - DEVINFO_STR_IMAGE_CREATE_OPTDESC].description); + } + else if ((state >= DEVINFO_STR_IMAGE_CREATE_OPTEXTS) && (state < DEVINFO_STR_IMAGE_CREATE_OPTEXTS + DEVINFO_IMAGE_CREATE_OPTMAX)) { + safe_strcpy(info->s,floppy_options[state - DEVINFO_STR_IMAGE_CREATE_OPTEXTS].extensions); + } + } + } + + break; + } +} + +DEFINE_LEGACY_IMAGE_DEVICE(FLOPPY, floppy); |