mirror of
https://github.com/holub/mame
synced 2025-05-17 11:15:06 +03:00
Moved image devices implementation and related UI functions to emu section from MESS [Miodrag Milanovic]
This commit is contained in:
parent
56b43ee687
commit
12a5370d85
24
.gitattributes
vendored
24
.gitattributes
vendored
@ -646,6 +646,30 @@ src/emu/hashfile.c svneol=native#text/plain
|
||||
src/emu/hashfile.h svneol=native#text/plain
|
||||
src/emu/image.c svneol=native#text/plain
|
||||
src/emu/image.h svneol=native#text/plain
|
||||
src/emu/imagedev/bitbngr.c svneol=native#text/plain
|
||||
src/emu/imagedev/bitbngr.h svneol=native#text/plain
|
||||
src/emu/imagedev/cartslot.c svneol=native#text/plain
|
||||
src/emu/imagedev/cartslot.h svneol=native#text/plain
|
||||
src/emu/imagedev/cassette.c svneol=native#text/plain
|
||||
src/emu/imagedev/cassette.h svneol=native#text/plain
|
||||
src/emu/imagedev/cassimg.c svneol=native#text/plain
|
||||
src/emu/imagedev/cassimg.h svneol=native#text/plain
|
||||
src/emu/imagedev/chd_cd.c svneol=native#text/plain
|
||||
src/emu/imagedev/chd_cd.h svneol=native#text/plain
|
||||
src/emu/imagedev/flopdrv.c svneol=native#text/plain
|
||||
src/emu/imagedev/flopdrv.h svneol=native#text/plain
|
||||
src/emu/imagedev/flopimg.c svneol=native#text/plain
|
||||
src/emu/imagedev/flopimg.h svneol=native#text/plain
|
||||
src/emu/imagedev/harddriv.c svneol=native#text/plain
|
||||
src/emu/imagedev/harddriv.h svneol=native#text/plain
|
||||
src/emu/imagedev/multcart.c svneol=native#text/plain
|
||||
src/emu/imagedev/multcart.h svneol=native#text/plain
|
||||
src/emu/imagedev/printer.c svneol=native#text/plain
|
||||
src/emu/imagedev/printer.h svneol=native#text/plain
|
||||
src/emu/imagedev/snapquik.c svneol=native#text/plain
|
||||
src/emu/imagedev/snapquik.h svneol=native#text/plain
|
||||
src/emu/imagedev/wavfile.c svneol=native#text/plain
|
||||
src/emu/imagedev/wavfile.h svneol=native#text/plain
|
||||
src/emu/info.c svneol=native#text/plain
|
||||
src/emu/info.h svneol=native#text/plain
|
||||
src/emu/inptport.c svneol=native#text/plain
|
||||
|
@ -17,6 +17,7 @@ EMUAUDIO = $(EMUOBJ)/audio
|
||||
EMUDRIVERS = $(EMUOBJ)/drivers
|
||||
EMULAYOUT = $(EMUOBJ)/layout
|
||||
EMUMACHINE = $(EMUOBJ)/machine
|
||||
EMUIMAGEDEV = $(EMUOBJ)/imagedev
|
||||
EMUVIDEO = $(EMUOBJ)/video
|
||||
|
||||
OBJDIRS += \
|
||||
@ -28,6 +29,7 @@ OBJDIRS += \
|
||||
$(EMUOBJ)/drivers \
|
||||
$(EMUOBJ)/machine \
|
||||
$(EMUOBJ)/layout \
|
||||
$(EMUOBJ)/imagedev \
|
||||
$(EMUOBJ)/video \
|
||||
|
||||
OSDSRC = $(SRC)/osd
|
||||
@ -235,7 +237,22 @@ EMUVIDEOOBJS = \
|
||||
$(EMUVIDEO)/vector.o \
|
||||
$(EMUVIDEO)/voodoo.o \
|
||||
|
||||
LIBEMUOBJS = $(EMUOBJS) $(EMUSOUNDOBJS) $(EMUAUDIOOBJS) $(EMUDRIVEROBJS) $(EMUMACHINEOBJS) $(EMUVIDEOOBJS)
|
||||
EMUIMAGEDEVOBJS = \
|
||||
$(EMUIMAGEDEV)/bitbngr.o \
|
||||
$(EMUIMAGEDEV)/cartslot.o \
|
||||
$(EMUIMAGEDEV)/cassette.o \
|
||||
$(EMUIMAGEDEV)/cassimg.o \
|
||||
$(EMUIMAGEDEV)/chd_cd.o \
|
||||
$(EMUIMAGEDEV)/flopdrv.o \
|
||||
$(EMUIMAGEDEV)/flopimg.o \
|
||||
$(EMUIMAGEDEV)/harddriv.o \
|
||||
$(EMUIMAGEDEV)/multcart.o \
|
||||
$(EMUIMAGEDEV)/printer.o \
|
||||
$(EMUIMAGEDEV)/snapquik.o \
|
||||
$(EMUIMAGEDEV)/wavfile.o \
|
||||
|
||||
|
||||
LIBEMUOBJS = $(EMUOBJS) $(EMUSOUNDOBJS) $(EMUAUDIOOBJS) $(EMUDRIVEROBJS) $(EMUMACHINEOBJS) $(EMUIMAGEDEVOBJS) $(EMUVIDEOOBJS)
|
||||
|
||||
$(LIBEMU): $(LIBEMUOBJS)
|
||||
|
||||
|
523
src/emu/imagedev/bitbngr.c
Normal file
523
src/emu/imagedev/bitbngr.c
Normal file
@ -0,0 +1,523 @@
|
||||
/*********************************************************************
|
||||
|
||||
bitbngr.c
|
||||
|
||||
TRS style "bitbanger" serial port
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "bitbngr.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _bitbanger_token bitbanger_token;
|
||||
struct _bitbanger_token
|
||||
{
|
||||
emu_timer *bitbanger_output_timer;
|
||||
emu_timer *bitbanger_input_timer;
|
||||
int output_value;
|
||||
int build_count;
|
||||
int build_byte;
|
||||
attotime idle_delay;
|
||||
attotime current_baud;
|
||||
UINT32 input_buffer_size;
|
||||
UINT32 input_buffer_cursor;
|
||||
int mode;
|
||||
int baud;
|
||||
int tune;
|
||||
UINT8 input_buffer[1000];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
static TIMER_CALLBACK(bitbanger_output_timer);
|
||||
static TIMER_CALLBACK(bitbanger_input_timer);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_token - safely gets the bitbanger data
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE bitbanger_token *get_token(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == BITBANGER);
|
||||
return (bitbanger_token *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_config - safely gets the bitbanger config
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE const bitbanger_config *get_config(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == BITBANGER);
|
||||
return (const bitbanger_config *) device->baseconfig().static_config();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
native_output - outputs data to a file
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void native_output(device_t *bitbanger, UINT8 data)
|
||||
{
|
||||
device_image_interface *image = dynamic_cast<device_image_interface *>(bitbanger);
|
||||
if (image->exists())
|
||||
{
|
||||
image->fwrite(&data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
native_input - inputs data from a file
|
||||
-------------------------------------------------*/
|
||||
|
||||
static UINT32 native_input(device_t *bitbanger, void *buffer, UINT32 length)
|
||||
{
|
||||
device_image_interface *image = dynamic_cast<device_image_interface *>(bitbanger);
|
||||
if (image->exists())
|
||||
{
|
||||
return image->fread(buffer, length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_mode_string
|
||||
-------------------------------------------------*/
|
||||
const char *bitbanger_mode_string(device_t *device)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
static const char *const modes[] = {"Printer", "Modem"};
|
||||
|
||||
return(modes[bi->mode]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_inc_mode
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_inc_mode(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_mode = (int)bi->mode + 1;
|
||||
|
||||
if( adjust_mode >= BITBANGER_MODE_MAX )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
bi->mode = adjust_mode;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_dec_mode
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_dec_mode(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_mode = bi->mode - 1;
|
||||
|
||||
if( adjust_mode < 0 )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
bi->mode = adjust_mode;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_tune_string
|
||||
-------------------------------------------------*/
|
||||
const char *bitbanger_tune_string(device_t *device)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
static const char *const tunes[] = {"-2.0%", "-1.75%", "-1.5%", "-1.25%", "-1.0%", "-0.75%", "-0.5", "-0.25%", "\xc2\xb1""0%",
|
||||
"+0.25%", "+0.5%", "+0.75%", "+1.0%", "+1.25%", "+1.5%", "+1.75%", "+2.0%"};
|
||||
|
||||
return(tunes[bi->tune]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_tune_value
|
||||
-------------------------------------------------*/
|
||||
static float bitbanger_tune_value(device_t *device)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
static const float tunes[] = {0.97f, 0.9825f, 0.985f, 0.9875f, 0.99f, 0.9925f, 0.995f, 0.9975f, 1.0f,
|
||||
1.0025f, 1.005f, 1.0075f, 1.01f, 1.0125f, 1.015f, 1.0175f, 1.02f};
|
||||
|
||||
return(tunes[bi->tune]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_baud_value
|
||||
-------------------------------------------------*/
|
||||
|
||||
static UINT32 bitbanger_baud_value(device_t *device)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
static const float bauds[] = { 150.0f, 300.0f, 600.0f, 1200.0f, 2400.0f, 4800.0f, 9600.0f,
|
||||
14400.0f, 28800.0f, 38400.0f, 57600.0f, 115200.0f};
|
||||
float result = bitbanger_tune_value(device) * bauds[bi->baud];
|
||||
return (UINT32)result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_baud_string
|
||||
-------------------------------------------------*/
|
||||
|
||||
const char *bitbanger_baud_string(device_t *device)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
static const char *const bauds[] = { "150", "300", "600", "1200", "2400", "4800",
|
||||
"9600", "14400", "28800", "38400", "57600", "115200"};
|
||||
|
||||
return(bauds[bi->baud]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_inc_baud
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_inc_baud(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_baud = (int)bi->baud + 1;
|
||||
|
||||
if( adjust_baud >= BITBANGER_BAUD_MAX )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
{
|
||||
bi->baud = adjust_baud;
|
||||
bi->current_baud = ATTOTIME_IN_HZ(bitbanger_baud_value(device));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_dec_baud
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_dec_baud(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_baud = bi->baud - 1;
|
||||
|
||||
if( adjust_baud < 0 )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
{
|
||||
bi->baud = adjust_baud;
|
||||
bi->current_baud = ATTOTIME_IN_HZ(bitbanger_baud_value(device));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_inc_tune
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_inc_tune(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_tune = (int)bi->tune + 1;
|
||||
|
||||
if( adjust_tune >= BITBANGER_TUNE_MAX )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
{
|
||||
bi->tune = adjust_tune;
|
||||
bi->current_baud = ATTOTIME_IN_HZ(bitbanger_baud_value(device));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_dec_tune
|
||||
-------------------------------------------------*/
|
||||
bool bitbanger_dec_tune(device_t *device, bool test)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
int adjust_tune = bi->tune - 1;
|
||||
|
||||
if( adjust_tune < 0 )
|
||||
return FALSE;
|
||||
|
||||
if( !test)
|
||||
{
|
||||
bi->tune = adjust_tune;
|
||||
bi->current_baud = ATTOTIME_IN_HZ(bitbanger_baud_value(device));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_bytes_to_bits_81N
|
||||
-------------------------------------------------*/
|
||||
static void bitbanger_bytes_to_bits_81N(device_t *img)
|
||||
{
|
||||
bitbanger_token *bi = get_token(img);
|
||||
UINT8 byte_buffer[100];
|
||||
UINT32 byte_buffer_size, bit_buffer_size;
|
||||
int i, j;
|
||||
static const UINT8 bitmask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
|
||||
|
||||
bit_buffer_size = 0;
|
||||
byte_buffer_size = native_input(img, byte_buffer, sizeof(byte_buffer));
|
||||
|
||||
/* Translate byte buffer into bit buffer using: 1 start bit, 8 data bits, 1 stop bit, no parity */
|
||||
|
||||
for( i=0; i<byte_buffer_size; i++ )
|
||||
{
|
||||
bi->input_buffer[bit_buffer_size++] = 0;
|
||||
|
||||
for( j=0; j<8; j++ )
|
||||
{
|
||||
if( byte_buffer[i] & bitmask[j] )
|
||||
bi->input_buffer[bit_buffer_size++] = 1;
|
||||
else
|
||||
bi->input_buffer[bit_buffer_size++] = 0;
|
||||
}
|
||||
|
||||
bi->input_buffer[bit_buffer_size++] = 1;
|
||||
}
|
||||
|
||||
bi->input_buffer_size = bit_buffer_size;
|
||||
bi->input_buffer_cursor = 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START(bitbanger)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START(bitbanger)
|
||||
{
|
||||
bitbanger_token *bi;
|
||||
const bitbanger_config *config = get_config(device);
|
||||
|
||||
bi = get_token(device);
|
||||
|
||||
/* output config */
|
||||
bi->build_count = 0;
|
||||
bi->bitbanger_output_timer = timer_alloc(device->machine, bitbanger_output_timer, (void *) device);
|
||||
|
||||
/* input config */
|
||||
bi->bitbanger_input_timer = timer_alloc(device->machine, bitbanger_input_timer, (void *) device );
|
||||
bi->idle_delay = ATTOTIME_IN_SEC(1);
|
||||
bi->input_buffer_size = 0;
|
||||
bi->input_buffer_cursor = 0;
|
||||
|
||||
bi->mode = config->default_mode;
|
||||
bi->baud = config->default_baud;
|
||||
bi->tune = config->default_tune;
|
||||
bi->current_baud = ATTOTIME_IN_HZ(bitbanger_baud_value(device));
|
||||
|
||||
/* test callback */
|
||||
if(!config->input_callback)
|
||||
fatalerror("Misconfigured bitbanger device: input_callback cannot be NULL\n");
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
TIMER_CALLBACK(bitbanger_output_timer)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK(bitbanger_output_timer)
|
||||
{
|
||||
device_t *device = (device_t *) ptr;
|
||||
bitbanger_token *bi = get_token(device);
|
||||
|
||||
/* this ia harded coded for 8-1-N */
|
||||
if( bi->output_value )
|
||||
bi->build_byte |= 0x200;
|
||||
|
||||
bi->build_byte >>= 1;
|
||||
bi->build_count--;
|
||||
|
||||
if(bi->build_count == 0)
|
||||
{
|
||||
if( bi->output_value == 1 )
|
||||
native_output( device, bi->build_byte );
|
||||
else
|
||||
logerror("Bitbanger: Output framing error.\n" );
|
||||
|
||||
timer_reset(bi->bitbanger_output_timer, attotime_never);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
TIMER_CALLBACK(bitbanger_input_timer)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK(bitbanger_input_timer)
|
||||
{
|
||||
device_t *device = (device_t *) ptr;
|
||||
bitbanger_token *bi = get_token(device);
|
||||
const bitbanger_config *config = get_config(device);
|
||||
|
||||
if(bi->input_buffer_cursor == bi->input_buffer_size)
|
||||
{
|
||||
/* get more data */
|
||||
bitbanger_bytes_to_bits_81N(device);
|
||||
|
||||
if(bi->input_buffer_size == 0)
|
||||
{
|
||||
/* no more data, wait and try again */
|
||||
bi->idle_delay = attotime_min(attotime_add(bi->idle_delay, ATTOTIME_IN_MSEC(100)), ATTOTIME_IN_SEC(1));
|
||||
timer_adjust_oneshot(bi->bitbanger_input_timer, bi->idle_delay, 0);
|
||||
|
||||
|
||||
if( bi->mode == BITBANGER_MODEM )
|
||||
config->input_callback(machine, 1);
|
||||
else
|
||||
config->input_callback(machine, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
bi->idle_delay = bi->current_baud;
|
||||
timer_adjust_periodic(bi->bitbanger_input_timer, bi->idle_delay, 0, bi->idle_delay);
|
||||
}
|
||||
}
|
||||
|
||||
/* send bit to driver */
|
||||
config->input_callback(machine, bi->input_buffer[(bi->input_buffer_cursor)++]);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_output - outputs data to a bitbanger
|
||||
port
|
||||
-------------------------------------------------*/
|
||||
|
||||
void bitbanger_output(device_t *device, int value)
|
||||
{
|
||||
bitbanger_token *bi = get_token(device);
|
||||
attotime one_point_five_baud;
|
||||
|
||||
if( bi->build_count == 0 && bi->output_value == 1 && value == 0 )
|
||||
{
|
||||
/* we found our start bit */
|
||||
/* eight bits of data, plus one of stop */
|
||||
bi->build_count = 9;
|
||||
bi->build_byte = 0;
|
||||
|
||||
one_point_five_baud = attotime_add(bi->current_baud, attotime_div(bi->current_baud,2));
|
||||
timer_adjust_periodic(bi->bitbanger_output_timer, one_point_five_baud, 0, bi->current_baud);
|
||||
}
|
||||
|
||||
//fprintf(stderr,"%s, %d\n", attotime_string(timer_get_time(device->machine),9), value);
|
||||
bi->output_value = value;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_LOAD( bitbanger )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_LOAD( bitbanger )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
bitbanger_token *bi;
|
||||
bi = get_token(device);
|
||||
|
||||
timer_enable(bi->bitbanger_input_timer, TRUE);
|
||||
timer_adjust_periodic(bi->bitbanger_input_timer, attotime_zero, 0, ATTOTIME_IN_SEC(1));
|
||||
|
||||
/* we don't need to do anything special */
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_UNLOAD( bitbanger )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( bitbanger )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
bitbanger_token *bi;
|
||||
bi = get_token(device);
|
||||
|
||||
timer_enable(bi->bitbanger_input_timer, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(bitbanger) - device getinfo
|
||||
function
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(bitbanger)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(bitbanger_token); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_PRINTER; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(bitbanger); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(bitbanger); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(bitbanger); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Bitbanger"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Bitbanger"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "prn"); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(BITBANGER, bitbanger);
|
99
src/emu/imagedev/bitbngr.h
Normal file
99
src/emu/imagedev/bitbngr.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*********************************************************************
|
||||
|
||||
bitbngr.h
|
||||
|
||||
TRS style "bitbanger" serial port
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __BITBNGR_H__
|
||||
#define __BITBNGR_H__
|
||||
|
||||
#include "image.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
BITBANGER_PRINTER = 0,
|
||||
BITBANGER_MODEM,
|
||||
BITBANGER_MODE_MAX,
|
||||
|
||||
BITBANGER_150 = 0,
|
||||
BITBANGER_300,
|
||||
BITBANGER_600,
|
||||
BITBANGER_1200,
|
||||
BITBANGER_2400,
|
||||
BITBANGER_4800,
|
||||
BITBANGER_9600,
|
||||
BITBANGER_14400,
|
||||
BITBANGER_28800,
|
||||
BITBANGER_38400,
|
||||
BITBANGER_57600,
|
||||
BITBANGER_115200,
|
||||
BITBANGER_BAUD_MAX,
|
||||
|
||||
BITBANGER_NEG40PERCENT = 0,
|
||||
BITBANGER_NEG35PERCENT,
|
||||
BITBANGER_NEG30PERCENT,
|
||||
BITBANGER_NEG25PERCENT,
|
||||
BITBANGER_NEG20PERCENT,
|
||||
BITBANGER_NEG15PERCENT,
|
||||
BITBANGER_NEG10PERCENT,
|
||||
BITBANGER_NEG5PERCENT,
|
||||
BITBANGER_0PERCENT,
|
||||
BITBANGER_POS5PERCENT,
|
||||
BITBANGER_POS10PERCENT,
|
||||
BITBANGER_POS15PERCENT,
|
||||
BITBANGER_POS20PERCENT,
|
||||
BITBANGER_POS25PERCENT,
|
||||
BITBANGER_POS30PERCENT,
|
||||
BITBANGER_POS35PERCENT,
|
||||
BITBANGER_POS40PERCENT,
|
||||
BITBANGER_TUNE_MAX
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(BITBANGER, bitbanger);
|
||||
|
||||
#define MCFG_BITBANGER_ADD(_tag, _intrf) \
|
||||
MCFG_DEVICE_ADD(_tag, BITBANGER, 0) \
|
||||
MCFG_DEVICE_CONFIG(_intrf)
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _bitbanger_config bitbanger_config;
|
||||
struct _bitbanger_config
|
||||
{
|
||||
/* callback to driver */
|
||||
void (*input_callback)(running_machine *machine, UINT8 bit);
|
||||
int default_mode; /* emulating a printer or modem */
|
||||
int default_baud; /* output bits per second */
|
||||
int default_tune; /* fine tune adjustment to the baud */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* outputs data to a bitbanger port */
|
||||
void bitbanger_output(device_t *device, int value);
|
||||
|
||||
/* ui functions */
|
||||
const char *bitbanger_mode_string(device_t *device);
|
||||
const char *bitbanger_baud_string(device_t *device);
|
||||
const char *bitbanger_tune_string(device_t *device);
|
||||
bool bitbanger_inc_mode(device_t *device, bool test);
|
||||
bool bitbanger_dec_mode(device_t *device, bool test);
|
||||
bool bitbanger_inc_tune(device_t *device, bool test);
|
||||
bool bitbanger_dec_tune(device_t *device, bool test);
|
||||
bool bitbanger_inc_baud(device_t *device, bool test);
|
||||
bool bitbanger_dec_baud(device_t *device, bool test);
|
||||
|
||||
#endif /* __BITBNGR_H__ */
|
569
src/emu/imagedev/cartslot.c
Normal file
569
src/emu/imagedev/cartslot.c
Normal file
@ -0,0 +1,569 @@
|
||||
/**********************************************************************
|
||||
|
||||
cartslot.c
|
||||
|
||||
Cartridge device
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include "emu.h"
|
||||
#include "cartslot.h"
|
||||
#include "multcart.h"
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
enum _process_mode
|
||||
{
|
||||
PROCESS_CLEAR,
|
||||
PROCESS_LOAD
|
||||
};
|
||||
typedef enum _process_mode process_mode;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
INLINE cartslot_t *get_token(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == CARTSLOT);
|
||||
return (cartslot_t *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
INLINE const cartslot_config *get_config(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == CARTSLOT);
|
||||
return (const cartslot_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
|
||||
}
|
||||
|
||||
INLINE const cartslot_config *get_config_dev(const device_config *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == CARTSLOT);
|
||||
return (const cartslot_config *)downcast<const legacy_device_config_base *>(device)->inline_config();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_cartridge
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int load_cartridge(device_image_interface *image, const rom_entry *romrgn, const rom_entry *roment, process_mode mode)
|
||||
{
|
||||
const char *region;
|
||||
const char *type;
|
||||
UINT32 flags;
|
||||
offs_t offset, length, read_length, pos = 0, len;
|
||||
UINT8 *ptr;
|
||||
UINT8 clear_val;
|
||||
int datawidth, littleendian, i, j;
|
||||
device_t *cpu;
|
||||
|
||||
region = ROMREGION_GETTAG(romrgn);
|
||||
offset = ROM_GETOFFSET(roment);
|
||||
length = ROM_GETLENGTH(roment);
|
||||
flags = ROM_GETFLAGS(roment);
|
||||
ptr = ((UINT8 *) image->device().machine->region(region)->base()) + offset;
|
||||
|
||||
if (mode == PROCESS_LOAD)
|
||||
{
|
||||
if (image->software_entry() == NULL)
|
||||
{
|
||||
/* must this be full size */
|
||||
if (flags & ROM_FULLSIZE)
|
||||
{
|
||||
if (image->length() != length)
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
/* read the ROM */
|
||||
pos = read_length = image->fread(ptr, length);
|
||||
|
||||
/* reset the ROM to the initial point. */
|
||||
/* eventually, we could add a flag to allow the ROM to continue instead of restarting whenever a new cart region is present */
|
||||
image->fseek(0, SEEK_SET);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* must this be full size */
|
||||
if (flags & ROM_FULLSIZE)
|
||||
{
|
||||
if (image->get_software_region_length("rom") != length)
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
/* read the ROM */
|
||||
pos = read_length = image->get_software_region_length("rom");
|
||||
memcpy(ptr, image->get_software_region("rom"), read_length);
|
||||
}
|
||||
|
||||
/* do we need to mirror the ROM? */
|
||||
if (flags & ROM_MIRROR)
|
||||
{
|
||||
while(pos < length)
|
||||
{
|
||||
len = MIN(read_length, length - pos);
|
||||
memcpy(ptr + pos, ptr, len);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* postprocess this region */
|
||||
type = ROMREGION_GETTAG(romrgn);
|
||||
littleendian = ROMREGION_ISLITTLEENDIAN(romrgn);
|
||||
datawidth = ROMREGION_GETWIDTH(romrgn) / 8;
|
||||
|
||||
/* if the region is inverted, do that now */
|
||||
device_memory_interface *memory;
|
||||
cpu = image->device().machine->device(type);
|
||||
if (cpu!=NULL && cpu->interface(memory))
|
||||
{
|
||||
datawidth = device_memory(cpu)->space_config(AS_PROGRAM)->m_databus_width / 8;
|
||||
littleendian = (device_memory(cpu)->space_config()->m_endianness == ENDIANNESS_LITTLE);
|
||||
}
|
||||
|
||||
/* swap the endianness if we need to */
|
||||
#ifdef LSB_FIRST
|
||||
if (datawidth > 1 && !littleendian)
|
||||
#else
|
||||
if (datawidth > 1 && littleendian)
|
||||
#endif
|
||||
{
|
||||
for (i = 0; i < length; i += datawidth)
|
||||
{
|
||||
UINT8 temp[8];
|
||||
memcpy(temp, &ptr[i], datawidth);
|
||||
for (j = datawidth - 1; j >= 0; j--)
|
||||
ptr[i + j] = temp[datawidth - 1 - j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* clear out anything that remains */
|
||||
if (!(flags & ROM_NOCLEAR))
|
||||
{
|
||||
clear_val = (flags & ROM_FILL_FF) ? 0xFF : 0x00;
|
||||
memset(ptr + pos, clear_val, length - pos);
|
||||
}
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
process_cartridge
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int process_cartridge(device_image_interface *image, process_mode mode)
|
||||
{
|
||||
const rom_source *source;
|
||||
const rom_entry *romrgn, *roment;
|
||||
int result = 0;
|
||||
|
||||
for (source = rom_first_source(*image->device().machine->config); source != NULL; source = rom_next_source(*source))
|
||||
{
|
||||
for (romrgn = rom_first_region(*source); romrgn != NULL; romrgn = rom_next_region(romrgn))
|
||||
{
|
||||
roment = romrgn + 1;
|
||||
while(!ROMENTRY_ISREGIONEND(roment))
|
||||
{
|
||||
if (ROMENTRY_GETTYPE(roment) == ROMENTRYTYPE_CARTRIDGE)
|
||||
{
|
||||
if (strcmp(roment->_hashdata,image->device().tag())==0)
|
||||
{
|
||||
result |= load_cartridge(image, romrgn, roment, mode);
|
||||
|
||||
/* if loading failed in any cart region, stop loading */
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
roment++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cartslot_get_pcb
|
||||
-------------------------------------------------*/
|
||||
|
||||
device_t *cartslot_get_pcb(device_t *device)
|
||||
{
|
||||
cartslot_t *cart = get_token(device);
|
||||
return cart->pcb_device;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cartslot_get_socket
|
||||
-------------------------------------------------*/
|
||||
|
||||
void *cartslot_get_socket(device_t *device, const char *socket_name)
|
||||
{
|
||||
cartslot_t *cart = get_token(device);
|
||||
device_image_interface *image = dynamic_cast<device_image_interface *>(device);
|
||||
void *result = NULL;
|
||||
|
||||
if (cart->mc != NULL)
|
||||
{
|
||||
const multicart_socket *socket;
|
||||
for (socket = cart->mc->sockets; socket != NULL; socket = socket->next)
|
||||
{
|
||||
if (!strcmp(socket->id, socket_name))
|
||||
break;
|
||||
}
|
||||
result = socket ? socket->ptr : NULL;
|
||||
}
|
||||
else if (socket_name[0] == '\0')
|
||||
{
|
||||
result = image->ptr();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
cartslot_get_resource_length
|
||||
-------------------------------------------------*/
|
||||
|
||||
int cartslot_get_resource_length(device_t *device, const char *socket_name)
|
||||
{
|
||||
cartslot_t *cart = get_token(device);
|
||||
int result = 0;
|
||||
|
||||
if (cart->mc != NULL)
|
||||
{
|
||||
const multicart_socket *socket;
|
||||
|
||||
for (socket = cart->mc->sockets; socket != NULL; socket = socket->next)
|
||||
{
|
||||
if (!strcmp(socket->id, socket_name)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (socket != NULL)
|
||||
result = socket->resource->length;
|
||||
}
|
||||
else
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START( cartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START( cartslot )
|
||||
{
|
||||
cartslot_t *cart = get_token(device);
|
||||
const cartslot_config *config = get_config(device);
|
||||
|
||||
/* if this cartridge has a custom DEVICE_START, use it */
|
||||
if (config->device_start != NULL)
|
||||
{
|
||||
(*config->device_start)(device);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* find the PCB (if there is one) */
|
||||
cart->pcb_device = device->subdevice(TAG_PCB);
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_LOAD( cartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_LOAD( cartslot )
|
||||
{
|
||||
int result;
|
||||
device_t *device = &image.device();
|
||||
cartslot_t *cart = get_token(device);
|
||||
const cartslot_config *config = get_config(device);
|
||||
|
||||
/* if this cartridge has a custom DEVICE_IMAGE_LOAD, use it */
|
||||
if (config->device_load != NULL)
|
||||
return (*config->device_load)(image);
|
||||
|
||||
/* try opening this as if it were a multicart */
|
||||
multicart_open(image.filename(), device->machine->gamedrv->name, MULTICART_FLAGS_LOAD_RESOURCES, &cart->mc);
|
||||
if (cart->mc == NULL)
|
||||
{
|
||||
|
||||
|
||||
/* otherwise try the normal route */
|
||||
result = process_cartridge(&image, PROCESS_LOAD);
|
||||
if (result != IMAGE_INIT_PASS)
|
||||
return result;
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_UNLOAD( cartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( cartslot )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
cartslot_t *cart = get_token(device);
|
||||
const cartslot_config *config = get_config(device);
|
||||
|
||||
/* if this cartridge has a custom DEVICE_IMAGE_UNLOAD, use it */
|
||||
if (config->device_unload != NULL)
|
||||
{
|
||||
(*config->device_unload)(image);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cart->mc != NULL)
|
||||
{
|
||||
multicart_close(cart->mc);
|
||||
cart->mc = NULL;
|
||||
}
|
||||
|
||||
process_cartridge(&image, PROCESS_CLEAR);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
identify_pcb
|
||||
-------------------------------------------------*/
|
||||
|
||||
static const cartslot_pcb_type *identify_pcb(device_image_interface &image)
|
||||
{
|
||||
const cartslot_config *config = get_config(&image.device());
|
||||
astring pcb_name;
|
||||
const cartslot_pcb_type *pcb_type = NULL;
|
||||
multicart_t *mc;
|
||||
int i;
|
||||
|
||||
if (image.software_entry() == NULL && image.exists())
|
||||
{
|
||||
/* try opening this as if it were a multicart */
|
||||
multicart_open_error me = multicart_open(image.filename(), image.device().machine->gamedrv->name, MULTICART_FLAGS_DONT_LOAD_RESOURCES, &mc);
|
||||
if (me == MCERR_NONE)
|
||||
{
|
||||
/* this was a multicart - read from it */
|
||||
astring_cpyc(&pcb_name, mc->pcb_type);
|
||||
multicart_close(mc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me != MCERR_NOT_MULTICART)
|
||||
fatalerror("multicart error: %s", multicart_error_text(me));
|
||||
|
||||
/* Force fetching of image metadata */
|
||||
image.crc();
|
||||
|
||||
if (image.pcb() != NULL)
|
||||
{
|
||||
/* read from hash file */
|
||||
astring_cpyc(&pcb_name, image.pcb());
|
||||
}
|
||||
}
|
||||
|
||||
/* look for PCB type with matching name */
|
||||
for (i = 0; (i < ARRAY_LENGTH(config->pcb_types)) && (config->pcb_types[i].name != NULL); i++)
|
||||
{
|
||||
if ((config->pcb_types[i].name[0] == '\0') || !strcmp(astring_c(&pcb_name), config->pcb_types[i].name))
|
||||
{
|
||||
pcb_type = &config->pcb_types[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for unknown PCB type */
|
||||
if ((mc != NULL) && (pcb_type == NULL))
|
||||
fatalerror("Unknown PCB type \"%s\"", astring_c(&pcb_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no device loaded; use the default */
|
||||
pcb_type = (config->pcb_types[0].name != NULL) ? &config->pcb_types[0] : NULL;
|
||||
}
|
||||
return pcb_type;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_GET_DEVICES(cartslot)
|
||||
-------------------------------------------------*/
|
||||
static DEVICE_IMAGE_GET_DEVICES(cartslot)
|
||||
{
|
||||
const cartslot_pcb_type *pcb_type;
|
||||
device_t *device = &image.device();
|
||||
|
||||
pcb_type = identify_pcb(image);
|
||||
if (pcb_type != NULL)
|
||||
{
|
||||
image_add_device_with_subdevices(device,pcb_type->devtype,TAG_PCB,0);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_SOFTLIST_LOAD(cartslot)
|
||||
-------------------------------------------------*/
|
||||
static DEVICE_IMAGE_SOFTLIST_LOAD(cartslot)
|
||||
{
|
||||
load_software_part_region( &image.device(), swlist, swname, start_entry );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO( cartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO( cartslot )
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(cartslot_t); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(cartslot_config); break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_CARTSLOT; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_RESET_ON_LOAD: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_MUST_BE_LOADED:
|
||||
if ( device && downcast<const legacy_image_device_config_base *>(device)->inline_config()) {
|
||||
info->i = get_config_dev(device)->must_be_loaded;
|
||||
} else {
|
||||
info->i = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(cartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(cartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(cartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_GET_DEVICES: info->f = (genf *) DEVICE_IMAGE_GET_DEVICES_NAME(cartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_SOFTLIST_LOAD: info->f = (genf *) DEVICE_IMAGE_SOFTLIST_LOAD_NAME(cartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_PARTIAL_HASH:
|
||||
if ( device && downcast<const legacy_image_device_config_base *>(device)->inline_config() && get_config_dev(device)->device_partialhash) {
|
||||
info->f = (genf *) get_config_dev(device)->device_partialhash;
|
||||
} else {
|
||||
info->f = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Cartslot"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Cartslot"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:
|
||||
if ( device && downcast<const legacy_image_device_config_base *>(device)->inline_config() && get_config_dev(device)->extensions )
|
||||
{
|
||||
strcpy(info->s, get_config_dev(device)->extensions);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(info->s, "bin");
|
||||
}
|
||||
break;
|
||||
case DEVINFO_STR_IMAGE_INTERFACE:
|
||||
if ( device && downcast<const legacy_image_device_config_base *>(device)->inline_config() && get_config_dev(device)->interface )
|
||||
{
|
||||
strcpy(info->s, get_config_dev(device)->interface );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(CARTSLOT, cartslot);
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CONFIG CARTSLOT INTERFACE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_cart_slot_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_config_cart_slot_interface::device_config_cart_slot_interface(const machine_config &mconfig, device_config &devconfig)
|
||||
: device_config_interface(mconfig, devconfig)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_config_cart_slot_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_config_cart_slot_interface::~device_config_cart_slot_interface()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CARTSLOT INTERFACE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_cart_slot_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_cart_slot_interface::device_cart_slot_interface(running_machine &machine, const device_config &config, device_t &device)
|
||||
: device_interface(machine, config, device),
|
||||
m_cart_slot_config(dynamic_cast<const device_config_cart_slot_interface &>(config))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_cart_slot_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_cart_slot_interface::~device_cart_slot_interface()
|
||||
{
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LEGACY cart_slot DEVICE CONFIGURATION
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// legacy_cart_slot_device_config_base - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
legacy_cart_slot_device_config_base::legacy_cart_slot_device_config_base(const machine_config &mconfig, device_type type, const char *tag, const device_config *owner, UINT32 clock, device_get_config_func get_config)
|
||||
: legacy_device_config_base(mconfig, type, tag, owner, clock, get_config),
|
||||
device_config_cart_slot_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE LEGACY cart_slot DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// legacy_cart_slot_device_base - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
legacy_cart_slot_device_base::legacy_cart_slot_device_base(running_machine &machine, const device_config &config)
|
||||
: legacy_device_base(machine, config),
|
||||
device_cart_slot_interface(machine, config, *this)
|
||||
{
|
||||
}
|
180
src/emu/imagedev/cartslot.h
Normal file
180
src/emu/imagedev/cartslot.h
Normal file
@ -0,0 +1,180 @@
|
||||
/***************************************************************************
|
||||
|
||||
Cartrige loading
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __CARTSLOT_H__
|
||||
#define __CARTSLOT_H__
|
||||
|
||||
#include "image.h"
|
||||
#include "multcart.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS
|
||||
***************************************************************************/
|
||||
#define TAG_PCB "pcb"
|
||||
|
||||
#define ROM_CART_LOAD(tag,offset,length,flags) \
|
||||
{ NULL, tag, offset, length, ROMENTRYTYPE_CARTRIDGE | (flags) },
|
||||
|
||||
#define ROM_MIRROR 0x01000000
|
||||
#define ROM_NOMIRROR 0x00000000
|
||||
#define ROM_FULLSIZE 0x02000000
|
||||
#define ROM_FILL_FF 0x04000000
|
||||
#define ROM_NOCLEAR 0x08000000
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(CARTSLOT, cartslot);
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _cartslot_t cartslot_t;
|
||||
struct _cartslot_t
|
||||
{
|
||||
device_t *pcb_device;
|
||||
multicart_t *mc;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _cartslot_pcb_type cartslot_pcb_type;
|
||||
struct _cartslot_pcb_type
|
||||
{
|
||||
const char * name;
|
||||
device_type devtype;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _cartslot_config cartslot_config;
|
||||
struct _cartslot_config
|
||||
{
|
||||
const char * extensions;
|
||||
const char * interface;
|
||||
int must_be_loaded;
|
||||
device_start_func device_start;
|
||||
device_image_load_func device_load;
|
||||
device_image_unload_func device_unload;
|
||||
device_image_partialhash_func device_partialhash;
|
||||
cartslot_pcb_type pcb_types[16];
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* accesses the PCB associated with this cartslot */
|
||||
device_t *cartslot_get_pcb(device_t *device);
|
||||
|
||||
/* accesses a particular socket */
|
||||
void *cartslot_get_socket(device_t *device, const char *socket_name);
|
||||
|
||||
/* accesses a particular socket; gets the length of the associated resource */
|
||||
int cartslot_get_resource_length(device_t *device, const char *socket_name);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_CARTSLOT_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, CARTSLOT, 0) \
|
||||
|
||||
#define MCFG_CARTSLOT_MODIFY(_tag) \
|
||||
MCFG_DEVICE_MODIFY(_tag) \
|
||||
|
||||
#define MCFG_CARTSLOT_EXTENSION_LIST(_extensions) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, extensions, _extensions)
|
||||
|
||||
#define MCFG_CARTSLOT_NOT_MANDATORY \
|
||||
MCFG_DEVICE_CONFIG_DATA32(cartslot_config, must_be_loaded, FALSE)
|
||||
|
||||
#define MCFG_CARTSLOT_MANDATORY \
|
||||
MCFG_DEVICE_CONFIG_DATA32(cartslot_config, must_be_loaded, TRUE)
|
||||
|
||||
#define MCFG_CARTSLOT_START(_start) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, device_start, DEVICE_START_NAME(_start))
|
||||
|
||||
#define MCFG_CARTSLOT_LOAD(_load) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, device_load, DEVICE_IMAGE_LOAD_NAME(_load))
|
||||
|
||||
#define MCFG_CARTSLOT_UNLOAD(_unload) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, device_unload, DEVICE_IMAGE_UNLOAD_NAME(_unload))
|
||||
|
||||
#define MCFG_CARTSLOT_PARTIALHASH(_partialhash) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, device_partialhash, _partialhash)
|
||||
|
||||
#define MCFG_CARTSLOT_PCBTYPE(_index, _pcb_type_name, _pcb_devtype) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR_ARRAY_MEMBER(cartslot_config, pcb_types, _index, cartslot_pcb_type, name, _pcb_type_name) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR_ARRAY_MEMBER(cartslot_config, pcb_types, _index, cartslot_pcb_type, devtype, _pcb_devtype)
|
||||
|
||||
#define MCFG_CARTSLOT_INTERFACE(_interface) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cartslot_config, interface, _interface )
|
||||
|
||||
#define DECLARE_LEGACY_CART_SLOT_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_cart_slot_device_config_base, legacy_cart_slot_device_base)
|
||||
#define DEFINE_LEGACY_CART_SLOT_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device_config, basename##_device, legacy_cart_slot_device_config_base, legacy_cart_slot_device_base)
|
||||
|
||||
// ======================> device_config_cart_slot_interface
|
||||
|
||||
// class representing interface-specific configuration cart_slot
|
||||
class device_config_cart_slot_interface : public device_config_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
device_config_cart_slot_interface(const machine_config &mconfig, device_config &device);
|
||||
virtual ~device_config_cart_slot_interface();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> device_cart_slot_interface
|
||||
|
||||
// class representing interface-specific live cart_slot
|
||||
class device_cart_slot_interface : public device_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
device_cart_slot_interface(running_machine &machine, const device_config &config, device_t &device);
|
||||
virtual ~device_cart_slot_interface();
|
||||
|
||||
// configuration access
|
||||
const device_config_cart_slot_interface &cart_slot_config() const { return m_cart_slot_config; }
|
||||
protected:
|
||||
|
||||
// configuration
|
||||
const device_config_cart_slot_interface &m_cart_slot_config; // reference to our device_config_execute_interface
|
||||
};
|
||||
// ======================> legacy_cart_slot_device_config
|
||||
|
||||
// legacy_cart_slot_device_config is a device_config with a cart_slot interface
|
||||
class legacy_cart_slot_device_config_base : public legacy_device_config_base,
|
||||
public device_config_cart_slot_interface
|
||||
{
|
||||
protected:
|
||||
// construction/destruction
|
||||
legacy_cart_slot_device_config_base(const machine_config &mconfig, device_type type, const char *tag, const device_config *owner, UINT32 clock, device_get_config_func get_config);
|
||||
public:
|
||||
INT64 get_config_int(UINT32 state) const { return get_legacy_config_int(state); }
|
||||
genf *get_config_fct(UINT32 state) const { return get_legacy_config_fct(state); }
|
||||
void *get_config_ptr(UINT32 state) const { return get_legacy_config_ptr(state); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> legacy_cart_slot_device
|
||||
|
||||
// legacy_cart_slot_device is a legacy_device_base with a cart_slot interface
|
||||
class legacy_cart_slot_device_base : public legacy_device_base,
|
||||
public device_cart_slot_interface
|
||||
{
|
||||
protected:
|
||||
// construction/destruction
|
||||
legacy_cart_slot_device_base(running_machine &machine, const device_config &config);
|
||||
|
||||
// device_cart_slot_interface overrides
|
||||
};
|
||||
#endif /* __cart_slot_H__ */
|
452
src/emu/imagedev/cassette.c
Normal file
452
src/emu/imagedev/cassette.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*********************************************************************
|
||||
|
||||
cassette.c
|
||||
|
||||
MESS interface to the cassette image abstraction code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "imageutl.h"
|
||||
#include "cassette.h"
|
||||
#include "cassimg.h"
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
#define CASSETTE_TAG "cassette"
|
||||
#define ANIMATION_FPS 1
|
||||
#define ANIMATION_FRAMES 4
|
||||
|
||||
#define VERBOSE 0
|
||||
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
|
||||
|
||||
typedef struct _dev_cassette_t dev_cassette_t;
|
||||
struct _dev_cassette_t
|
||||
{
|
||||
const cassette_config *config;
|
||||
cassette_image *cassette;
|
||||
cassette_state state;
|
||||
double position;
|
||||
double position_time;
|
||||
INT32 value;
|
||||
};
|
||||
|
||||
|
||||
/* Default cassette_config for drivers only wav files */
|
||||
const cassette_config default_cassette_config =
|
||||
{
|
||||
cassette_default_formats,
|
||||
NULL,
|
||||
CASSETTE_PLAY,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
INLINE dev_cassette_t *get_safe_token(device_t *device)
|
||||
{
|
||||
assert( device != NULL );
|
||||
assert( device->type() == CASSETTE );
|
||||
return (dev_cassette_t *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
cassette IO
|
||||
*********************************************************************/
|
||||
|
||||
INLINE int cassette_is_motor_on(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
if ((cassette->state & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED)
|
||||
return FALSE;
|
||||
if ((cassette->state & CASSETTE_MASK_MOTOR) != CASSETTE_MOTOR_ENABLED)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void cassette_update(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
double cur_time = attotime_to_double(timer_get_time(device->machine));
|
||||
|
||||
if (cassette_is_motor_on(device))
|
||||
{
|
||||
double new_position = cassette->position + (cur_time - cassette->position_time);
|
||||
|
||||
switch(cassette->state & CASSETTE_MASK_UISTATE) {
|
||||
case CASSETTE_RECORD:
|
||||
cassette_put_sample(cassette->cassette, 0, cassette->position, new_position - cassette->position, cassette->value);
|
||||
break;
|
||||
|
||||
case CASSETTE_PLAY:
|
||||
if ( cassette->cassette )
|
||||
{
|
||||
cassette_get_sample(cassette->cassette, 0, new_position, 0.0, &cassette->value);
|
||||
/* See if reached end of tape */
|
||||
double length = cassette_get_length(device);
|
||||
if (new_position > length)
|
||||
{
|
||||
cassette->state = (cassette_state)(( cassette->state & ~CASSETTE_MASK_UISTATE ) | CASSETTE_STOPPED);
|
||||
new_position = length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
cassette->position = new_position;
|
||||
}
|
||||
cassette->position_time = cur_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
cassette_state cassette_get_state(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
return cassette->state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cassette_change_state(device_t *device, cassette_state state, cassette_state mask)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
cassette_state new_state;
|
||||
|
||||
new_state = cassette->state;
|
||||
new_state = (cassette_state)(new_state & ~mask);
|
||||
new_state = (cassette_state)(new_state | (state & mask));
|
||||
|
||||
if (new_state != cassette->state)
|
||||
{
|
||||
cassette_update(device);
|
||||
cassette->state = new_state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cassette_set_state(device_t *device, cassette_state state)
|
||||
{
|
||||
cassette_change_state(device, state, (cassette_state)(~0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
double cassette_input(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
INT32 sample;
|
||||
double double_value;
|
||||
|
||||
cassette_update(device);
|
||||
sample = cassette->value;
|
||||
double_value = sample / ((double) 0x7FFFFFFF);
|
||||
|
||||
LOG(("cassette_input(): time_index=%g value=%g\n", cassette->position, double_value));
|
||||
|
||||
return double_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cassette_output(device_t *device, double value)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
if (((cassette->state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD) && (cassette->value != value))
|
||||
{
|
||||
cassette_update(device);
|
||||
|
||||
value = MIN(value, 1.0);
|
||||
value = MAX(value, -1.0);
|
||||
|
||||
cassette->value = (INT32) (value * 0x7FFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
cassette_image *cassette_get_image(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
return cassette->cassette;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double cassette_get_position(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
double position;
|
||||
|
||||
position = cassette->position;
|
||||
|
||||
if (cassette_is_motor_on(device))
|
||||
position += attotime_to_double(timer_get_time(device->machine)) - cassette->position_time;
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
double cassette_get_length(device_t *device)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
struct CassetteInfo info;
|
||||
|
||||
cassette_get_info(cassette->cassette, &info);
|
||||
return ((double) info.sample_count) / info.sample_frequency;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cassette_seek(device_t *device, double time, int origin)
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
double length;
|
||||
|
||||
cassette_update(device);
|
||||
|
||||
length = cassette_get_length(device);
|
||||
|
||||
switch(origin) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
time += length;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
time += cassette_get_position(device);
|
||||
break;
|
||||
}
|
||||
|
||||
/* clip position into legal bounds */
|
||||
if (time < 0)
|
||||
time = 0;
|
||||
else
|
||||
if (time > length)
|
||||
time = length;
|
||||
|
||||
cassette->position = time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
cassette device init/load/unload/specify
|
||||
*********************************************************************/
|
||||
|
||||
static DEVICE_START( cassette )
|
||||
{
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
/* set to default state */
|
||||
cassette->config = (const cassette_config*)device->baseconfig().static_config();
|
||||
cassette->cassette = NULL;
|
||||
cassette->state = cassette->config->default_state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DEVICE_IMAGE_LOAD( cassette )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
casserr_t err;
|
||||
int cassette_flags;
|
||||
const struct CassetteFormat * const *formats;
|
||||
const struct CassetteOptions *create_opts;
|
||||
const char *extension;
|
||||
int is_writable;
|
||||
|
||||
/* figure out the cassette format */
|
||||
formats = cassette->config->formats;
|
||||
|
||||
if (image.has_been_created())
|
||||
{
|
||||
/* creating an image */
|
||||
create_opts = cassette->config->create_opts;
|
||||
err = cassette_create(device->machine, (void *) &image, &image_ioprocs, &wavfile_format, create_opts, CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT, &cassette->cassette);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* opening an image */
|
||||
do
|
||||
{
|
||||
is_writable = image.is_writable();
|
||||
cassette_flags = is_writable ? (CASSETTE_FLAG_READWRITE|CASSETTE_FLAG_SAVEONEXIT) : CASSETTE_FLAG_READONLY;
|
||||
extension = image.filetype();
|
||||
err = cassette_open_choices(device->machine,(void *) &image, &image_ioprocs, extension, formats, cassette_flags, &cassette->cassette);
|
||||
|
||||
/* this is kind of a hack */
|
||||
if (err && is_writable)
|
||||
image.make_readonly();
|
||||
}
|
||||
while(err && is_writable);
|
||||
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* set to default state, but only change the UI state */
|
||||
cassette_change_state(device, cassette->config->default_state, CASSETTE_MASK_UISTATE);
|
||||
|
||||
/* reset the position */
|
||||
cassette->position = 0.0;
|
||||
cassette->position_time = attotime_to_double(timer_get_time(device->machine));
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
|
||||
error:
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( cassette )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
dev_cassette_t *cassette = get_safe_token( device );
|
||||
|
||||
/* if we are recording, write the value to the image */
|
||||
if ((cassette->state & CASSETTE_MASK_UISTATE) == CASSETTE_RECORD)
|
||||
cassette_update(device);
|
||||
|
||||
/* close out the cassette */
|
||||
cassette_close(cassette->cassette);
|
||||
cassette->cassette = NULL;
|
||||
|
||||
/* set to default state, but only change the UI state */
|
||||
cassette_change_state(device, CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
display a small tape icon, with the current position in the tape image
|
||||
*/
|
||||
static DEVICE_IMAGE_DISPLAY(cassette)
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
char buf[65];
|
||||
float x, y;
|
||||
int n;
|
||||
double position, length;
|
||||
cassette_state uistate;
|
||||
device_t *dev;
|
||||
static const UINT8 shapes[8] = { 0x2d, 0x5c, 0x7c, 0x2f, 0x2d, 0x20, 0x20, 0x20 };
|
||||
|
||||
/* abort if we should not be showing the image */
|
||||
if (!image.exists())
|
||||
return;
|
||||
if (!cassette_is_motor_on(device))
|
||||
return;
|
||||
|
||||
/* figure out where we are in the cassette */
|
||||
position = cassette_get_position(device);
|
||||
length = cassette_get_length(device);
|
||||
uistate = (cassette_state)(cassette_get_state(device) & CASSETTE_MASK_UISTATE);
|
||||
|
||||
/* choose a location on the screen */
|
||||
x = 0.2f;
|
||||
y = 0.5f;
|
||||
|
||||
dev = device->machine->m_devicelist.first(CASSETTE );
|
||||
|
||||
while ( dev && strcmp( dev->tag(), device->tag() ) )
|
||||
{
|
||||
y += 1;
|
||||
dev = dev->typenext();
|
||||
}
|
||||
|
||||
y *= ui_get_line_height(*device->machine) + 2.0f * UI_BOX_TB_BORDER;
|
||||
/* choose which frame of the animation we are at */
|
||||
n = ((int) position / ANIMATION_FPS) % ANIMATION_FRAMES;
|
||||
/* Since you can have anything in a BDF file, we will use crude ascii characters instead */
|
||||
snprintf(buf, ARRAY_LENGTH(buf), "%c%c %c %02d:%02d (%04d) [%02d:%02d (%04d)]",
|
||||
#if 0
|
||||
/* THE ANIMATION HASN'T WORKED SINCE 0.114 - LEFT HERE FOR REFERENCE */
|
||||
/* NEVER SEEN THE PLAY / RECORD ICONS */
|
||||
/* character pairs 2-3, 4-5, 6-7, 8-9 form little tape cassette images */
|
||||
n * 2 + 2, /* cassette icon left */
|
||||
n * 2 + 3, /* cassette icon right */
|
||||
(uistate == CASSETTE_PLAY) ? 16 : 14, /* play or record icon */
|
||||
#else
|
||||
shapes[n], /* cassette icon left */
|
||||
shapes[n|4], /* cassette icon right */
|
||||
(uistate == CASSETTE_PLAY) ? 0x50 : 0x52, /* play (P) or record (R) */
|
||||
#endif
|
||||
((int) position / 60),
|
||||
((int) position % 60),
|
||||
(int) position,
|
||||
((int) length / 60),
|
||||
((int) length % 60),
|
||||
(int) length);
|
||||
|
||||
/* draw the cassette */
|
||||
ui_draw_text_box(&device->machine->render().ui_container(), buf, JUSTIFY_LEFT, x, y, UI_BACKGROUND_COLOR);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_SOFTLIST_LOAD(cassette)
|
||||
-------------------------------------------------*/
|
||||
static DEVICE_IMAGE_SOFTLIST_LOAD(cassette)
|
||||
{
|
||||
return image.load_software(swlist, swname, start_entry);
|
||||
}
|
||||
|
||||
DEVICE_GET_INFO(cassette)
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(dev_cassette_t); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_CASSETTE; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(cassette); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(cassette); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(cassette); break;
|
||||
case DEVINFO_FCT_IMAGE_DISPLAY: info->f = (genf *) DEVICE_IMAGE_DISPLAY_NAME(cassette); break;
|
||||
case DEVINFO_FCT_IMAGE_SOFTLIST_LOAD: info->f = (genf *) DEVICE_IMAGE_SOFTLIST_LOAD_NAME(cassette); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Cassette"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Cassette"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:
|
||||
if ( device && device->static_config() )
|
||||
{
|
||||
const struct CassetteFormat * const *formats = ((cassette_config *)device->static_config())->formats;
|
||||
int i;
|
||||
|
||||
/* set up a temporary string */
|
||||
info->s[0] = '\0';
|
||||
|
||||
for ( i = 0; formats[i]; i++ )
|
||||
image_specify_extension( info->s, 256, formats[i]->extensions );
|
||||
}
|
||||
break;
|
||||
case DEVINFO_STR_IMAGE_INTERFACE:
|
||||
if ( device && device->static_config() && ((cassette_config *)device->static_config())->interface)
|
||||
{
|
||||
strcpy(info->s, ((cassette_config *)device->static_config())->interface );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(CASSETTE, cassette);
|
85
src/emu/imagedev/cassette.h
Normal file
85
src/emu/imagedev/cassette.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*********************************************************************
|
||||
|
||||
cassette.h
|
||||
|
||||
MESS interface to the cassette image abstraction code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef CASSETTE_H
|
||||
#define CASSETTE_H
|
||||
|
||||
#include "image.h"
|
||||
#include "cassimg.h"
|
||||
|
||||
|
||||
enum _cassette_state
|
||||
{
|
||||
/* this part of the state is controlled by the UI */
|
||||
CASSETTE_STOPPED = 0,
|
||||
CASSETTE_PLAY = 1,
|
||||
CASSETTE_RECORD = 2,
|
||||
|
||||
/* this part of the state is controlled by drivers */
|
||||
CASSETTE_MOTOR_ENABLED = 0,
|
||||
CASSETTE_MOTOR_DISABLED = 4,
|
||||
CASSETTE_SPEAKER_ENABLED = 0,
|
||||
CASSETTE_SPEAKER_MUTED = 8,
|
||||
|
||||
/* masks */
|
||||
CASSETTE_MASK_UISTATE = 3,
|
||||
CASSETTE_MASK_MOTOR = 4,
|
||||
CASSETTE_MASK_SPEAKER = 8,
|
||||
CASSETTE_MASK_DRVSTATE = 12
|
||||
};
|
||||
|
||||
typedef enum _cassette_state cassette_state;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct cassette_config_t cassette_config;
|
||||
struct cassette_config_t
|
||||
{
|
||||
const struct CassetteFormat* const *formats;
|
||||
const struct CassetteOptions *create_opts;
|
||||
const cassette_state default_state;
|
||||
const char * interface;
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
cassette_state cassette_get_state(device_t *cassette);
|
||||
void cassette_set_state(device_t *cassette, cassette_state state);
|
||||
void cassette_change_state(device_t *cassette, cassette_state state, cassette_state mask);
|
||||
|
||||
double cassette_input(device_t *cassette);
|
||||
void cassette_output(device_t *cassette, double value);
|
||||
|
||||
cassette_image *cassette_get_image(device_t *cassette);
|
||||
double cassette_get_position(device_t *cassette);
|
||||
double cassette_get_length(device_t *cassette);
|
||||
void cassette_seek(device_t *cassette, double time, int origin);
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(CASSETTE, cassette);
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_CASSETTE_ADD(_tag, _config) \
|
||||
MCFG_DEVICE_ADD(_tag, CASSETTE, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_CASSETTE_MODIFY(_tag, _config) \
|
||||
MCFG_DEVICE_MODIFY(_tag) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
extern const cassette_config default_cassette_config;
|
||||
|
||||
#endif /* CASSETTE_H */
|
1059
src/emu/imagedev/cassimg.c
Normal file
1059
src/emu/imagedev/cassimg.c
Normal file
File diff suppressed because it is too large
Load Diff
227
src/emu/imagedev/cassimg.h
Normal file
227
src/emu/imagedev/cassimg.h
Normal file
@ -0,0 +1,227 @@
|
||||
/*********************************************************************
|
||||
|
||||
cassimg.h
|
||||
|
||||
Cassette tape image abstraction code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef CASSIMG_H
|
||||
#define CASSIMG_H
|
||||
|
||||
#include "pool.h"
|
||||
#include "emu.h"
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Constants
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#define CASSETTE_FLAG_READWRITE 0
|
||||
#define CASSETTE_FLAG_READONLY 1
|
||||
#define CASSETTE_FLAG_NOSAVEONEXIT 0
|
||||
#define CASSETTE_FLAG_SAVEONEXIT 2
|
||||
|
||||
#define CASSETTE_WAVEFORM_8BIT 0
|
||||
#define CASSETTE_WAVEFORM_16BIT 2
|
||||
#define CASSETTE_WAVEFORM_16BIT_FLIP 3
|
||||
#define CASSETTE_WAVEFORM_32BIT 4
|
||||
#define CASSETTE_WAVEFORM_32BIT_FLIP 5
|
||||
#define CASSETTE_WAVEFORM_ENDIAN_FLIP 1
|
||||
|
||||
#define CASSETTE_MODULATION_SQUAREWAVE 0
|
||||
#define CASSETTE_MODULATION_SINEWAVE 1
|
||||
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
#define CASSETTE_WAVEFORM_16BITBE CASSETTE_WAVEFORM_16BIT_FLIP
|
||||
#define CASSETTE_WAVEFORM_16BITLE CASSETTE_WAVEFORM_16BIT
|
||||
#define CASSETTE_WAVEFORM_32BITBE CASSETTE_WAVEFORM_32BIT_FLIP
|
||||
#define CASSETTE_WAVEFORM_32BITLE CASSETTE_WAVEFORM_32BIT
|
||||
#else
|
||||
#define CASSETTE_WAVEFORM_16BITBE CASSETTE_WAVEFORM_16BIT
|
||||
#define CASSETTE_WAVEFORM_16BITLE CASSETTE_WAVEFORM_16BIT_FLIP
|
||||
#define CASSETTE_WAVEFORM_32BITBE CASSETTE_WAVEFORM_32BIT
|
||||
#define CASSETTE_WAVEFORM_32BITLE CASSETTE_WAVEFORM_32BIT_FLIP
|
||||
#endif
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Type definitions
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CASSETTE_ERROR_SUCCESS, /* no error */
|
||||
CASSETTE_ERROR_INTERNAL, /* fatal internal error */
|
||||
CASSETTE_ERROR_UNSUPPORTED, /* this operation is unsupported */
|
||||
CASSETTE_ERROR_OUTOFMEMORY, /* ran out of memory */
|
||||
CASSETTE_ERROR_INVALIDIMAGE, /* invalid image */
|
||||
CASSETTE_ERROR_INVALIDARG
|
||||
}
|
||||
casserr_t;
|
||||
|
||||
struct sample_block
|
||||
{
|
||||
INT32 *block;
|
||||
size_t sample_count;
|
||||
};
|
||||
|
||||
struct CassetteOptions
|
||||
{
|
||||
int channels;
|
||||
int bits_per_sample;
|
||||
UINT32 sample_frequency;
|
||||
};
|
||||
|
||||
struct CassetteInfo
|
||||
{
|
||||
int channels;
|
||||
int bits_per_sample;
|
||||
UINT32 sample_frequency;
|
||||
size_t sample_count;
|
||||
};
|
||||
|
||||
struct _cassette_image
|
||||
{
|
||||
const struct CassetteFormat *format;
|
||||
struct io_generic io;
|
||||
object_pool *pool;
|
||||
|
||||
int channels;
|
||||
int flags;
|
||||
UINT32 sample_frequency;
|
||||
|
||||
struct sample_block *blocks;
|
||||
size_t block_count;
|
||||
size_t sample_count;
|
||||
|
||||
running_machine *machine;
|
||||
};
|
||||
|
||||
typedef struct _cassette_image cassette_image;
|
||||
|
||||
struct CassetteFormat
|
||||
{
|
||||
const char *extensions;
|
||||
casserr_t (*identify)(cassette_image *cassette, struct CassetteOptions *opts);
|
||||
casserr_t (*load)(cassette_image *cassette);
|
||||
casserr_t (*save)(cassette_image *cassette, const struct CassetteInfo *info);
|
||||
};
|
||||
|
||||
/* used for the core modulation code */
|
||||
struct CassetteModulation
|
||||
{
|
||||
int flags;
|
||||
double zero_frequency_low;
|
||||
double zero_frequency_cannonical;
|
||||
double zero_frequency_high;
|
||||
double one_frequency_low;
|
||||
double one_frequency_cannonical;
|
||||
double one_frequency_high;
|
||||
};
|
||||
|
||||
/* code to adapt existing legacy fill_wave functions */
|
||||
struct CassetteLegacyWaveFiller
|
||||
{
|
||||
int (*fill_wave)(INT16 *, int, UINT8 *);
|
||||
int chunk_size;
|
||||
int chunk_samples;
|
||||
int (*chunk_sample_calc)(const UINT8 *bytes, int length);
|
||||
UINT32 sample_frequency;
|
||||
int header_samples;
|
||||
int trailer_samples;
|
||||
};
|
||||
|
||||
/* builtin formats */
|
||||
extern const struct CassetteFormat wavfile_format;
|
||||
|
||||
/* macros for specifying format lists */
|
||||
#define CASSETTE_FORMATLIST_EXTERN(name) \
|
||||
extern const struct CassetteFormat *const name[]
|
||||
|
||||
#define CASSETTE_FORMATLIST_START(name) \
|
||||
const struct CassetteFormat *const name[] = \
|
||||
{ \
|
||||
&wavfile_format, \
|
||||
|
||||
#define CASSETTE_FORMAT(name) \
|
||||
&(name), \
|
||||
|
||||
#define CASSETTE_FORMATLIST_END \
|
||||
NULL \
|
||||
};
|
||||
|
||||
CASSETTE_FORMATLIST_EXTERN(cassette_default_formats);
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Prototypes
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
casserr_t cassette_open(running_machine *machine,void *file, const struct io_procs *procs,
|
||||
const struct CassetteFormat *format, int flags, cassette_image **outcassette);
|
||||
casserr_t cassette_open_choices(running_machine *machine,void *file, const struct io_procs *procs, const char *extension,
|
||||
const struct CassetteFormat *const *formats, int flags, cassette_image **outcassette);
|
||||
casserr_t cassette_create(running_machine *machine,void *file, const struct io_procs *procs, const struct CassetteFormat *format,
|
||||
const struct CassetteOptions *opts, int flags, cassette_image **outcassette);
|
||||
casserr_t cassette_save(cassette_image *cassette);
|
||||
void cassette_close(cassette_image *cassette);
|
||||
void cassette_change(cassette_image *cassette, void *file, const struct io_procs *procs, const struct CassetteFormat *format, int flags);
|
||||
void cassette_get_info(cassette_image *cassette, struct CassetteInfo *info);
|
||||
|
||||
/* calls for accessing the raw cassette image */
|
||||
void cassette_image_read(cassette_image *cassette, void *buffer, UINT64 offset, size_t length);
|
||||
void cassette_image_write(cassette_image *cassette, const void *buffer, UINT64 offset, size_t length);
|
||||
UINT64 cassette_image_size(cassette_image *cassette);
|
||||
|
||||
/* waveform accesses */
|
||||
casserr_t cassette_get_samples(cassette_image *cassette, int channel,
|
||||
double time_index, double sample_period, size_t sample_count, size_t sample_bytes,
|
||||
void *samples, int waveform_flags);
|
||||
casserr_t cassette_put_samples(cassette_image *cassette, int channel,
|
||||
double time_index, double sample_period, size_t sample_count, size_t sample_bytes,
|
||||
const void *samples, int waveform_flags);
|
||||
casserr_t cassette_get_sample(cassette_image *cassette, int channel,
|
||||
double time_index, double sample_period, INT32 *sample);
|
||||
casserr_t cassette_put_sample(cassette_image *cassette, int channel,
|
||||
double time_index, double sample_period, INT32 sample);
|
||||
|
||||
/* waveform accesses to/from the raw image */
|
||||
casserr_t cassette_read_samples(cassette_image *cassette, int channels, double time_index,
|
||||
double sample_period, size_t sample_count, UINT64 offset, int waveform_flags);
|
||||
casserr_t cassette_write_samples(cassette_image *cassette, int channels, double time_index,
|
||||
double sample_period, size_t sample_count, UINT64 offset, int waveform_flags);
|
||||
|
||||
/* modulation support */
|
||||
casserr_t cassette_modulation_identify(cassette_image *cassette, const struct CassetteModulation *modulation,
|
||||
struct CassetteOptions *opts);
|
||||
casserr_t cassette_put_modulated_data(cassette_image *cassette, int channel, double time_index,
|
||||
const void *data, size_t data_length, const struct CassetteModulation *modulation,
|
||||
double *time_displacement);
|
||||
casserr_t cassette_put_modulated_filler(cassette_image *cassette, int channel, double time_index,
|
||||
UINT8 filler, size_t filler_length, const struct CassetteModulation *modulation,
|
||||
double *time_displacement);
|
||||
casserr_t cassette_read_modulated_data(cassette_image *cassette, int channel, double time_index,
|
||||
UINT64 offset, UINT64 length, const struct CassetteModulation *modulation,
|
||||
double *time_displacement);
|
||||
casserr_t cassette_put_modulated_data_bit(cassette_image *cassette, int channel, double time_index,
|
||||
UINT8 data, const struct CassetteModulation *modulation,
|
||||
double *time_displacement);
|
||||
|
||||
/* debug calls */
|
||||
void cassette_dump(cassette_image *image, const char *filename);
|
||||
|
||||
/* legacy code support */
|
||||
#define CODE_HEADER ((UINT8*)-1)
|
||||
#define CODE_TRAILER ((UINT8*)-2)
|
||||
casserr_t cassette_legacy_identify(cassette_image *cassette, struct CassetteOptions *opts,
|
||||
const struct CassetteLegacyWaveFiller *legacy_args);
|
||||
casserr_t cassette_legacy_construct(cassette_image *cassette,
|
||||
const struct CassetteLegacyWaveFiller *legacy_args);
|
||||
|
||||
#endif /* CASSIMG_H */
|
191
src/emu/imagedev/chd_cd.c
Normal file
191
src/emu/imagedev/chd_cd.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*********************************************************************
|
||||
|
||||
Code to interface the MESS image code with MAME's CHD-CD core.
|
||||
|
||||
Based on harddriv.c by Raphael Nabet 2003
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cdrom.h"
|
||||
#include "chd_cd.h"
|
||||
|
||||
|
||||
static const char *const error_strings[] =
|
||||
{
|
||||
"no error",
|
||||
"no drive interface",
|
||||
"out of memory",
|
||||
"invalid file",
|
||||
"invalid parameter",
|
||||
"invalid data",
|
||||
"file not found",
|
||||
"requires parent",
|
||||
"file not writeable",
|
||||
"read error",
|
||||
"write error",
|
||||
"codec error",
|
||||
"invalid parent",
|
||||
"hunk out of range",
|
||||
"decompression error",
|
||||
"compression error",
|
||||
"can't create file",
|
||||
"can't verify file"
|
||||
"operation not supported",
|
||||
"can't find metadata",
|
||||
"invalid metadata size",
|
||||
"unsupported CHD version"
|
||||
};
|
||||
|
||||
INLINE const cdrom_config *get_config_dev(const device_config *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == CDROM);
|
||||
return (const cdrom_config *)downcast<const legacy_device_config_base *>(device)->inline_config();
|
||||
}
|
||||
|
||||
static const char *chd_get_error_string(int chderr)
|
||||
{
|
||||
if ((chderr < 0 ) || (chderr >= ARRAY_LENGTH(error_strings)))
|
||||
return NULL;
|
||||
return error_strings[chderr];
|
||||
}
|
||||
|
||||
|
||||
static OPTION_GUIDE_START(mess_cd_option_guide)
|
||||
OPTION_INT('K', "hunksize", "Hunk Bytes")
|
||||
OPTION_GUIDE_END
|
||||
|
||||
static const char mess_cd_option_spec[] =
|
||||
"K512/1024/2048/[4096]";
|
||||
|
||||
|
||||
typedef struct _dev_cdrom_t dev_cdrom_t;
|
||||
struct _dev_cdrom_t
|
||||
{
|
||||
cdrom_file *cdrom_handle;
|
||||
};
|
||||
|
||||
|
||||
INLINE dev_cdrom_t *get_safe_token(device_t *device) {
|
||||
assert( device != NULL );
|
||||
assert( ( device->type() == CDROM ) );
|
||||
return (dev_cdrom_t *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_IMAGE_LOAD(cdrom)
|
||||
{
|
||||
dev_cdrom_t *cdrom = get_safe_token(&image.device());
|
||||
chd_error err = (chd_error)0;
|
||||
chd_file *chd = NULL;
|
||||
|
||||
err = chd_open_file( image.image_core_file(), CHD_OPEN_READ, NULL, &chd ); /* CDs are never writeable */
|
||||
if ( err )
|
||||
goto error;
|
||||
|
||||
/* open the CHD file */
|
||||
cdrom->cdrom_handle = cdrom_open( chd );
|
||||
if ( ! cdrom->cdrom_handle )
|
||||
goto error;
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
|
||||
error:
|
||||
if ( chd )
|
||||
chd_close( chd );
|
||||
if ( err )
|
||||
image.seterror( IMAGE_ERROR_UNSPECIFIED, chd_get_error_string( err ) );
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD(cdrom)
|
||||
{
|
||||
dev_cdrom_t *cdrom = get_safe_token( &image.device() );
|
||||
|
||||
assert( cdrom->cdrom_handle );
|
||||
cdrom_close( cdrom->cdrom_handle );
|
||||
cdrom->cdrom_handle = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Get the MESS/MAME cdrom handle (from the src/cdrom.c core)
|
||||
* after an image has been opened with the mess_cd core
|
||||
*
|
||||
*************************************/
|
||||
|
||||
cdrom_file *mess_cd_get_cdrom_file(device_t *image)
|
||||
{
|
||||
dev_cdrom_t *cdrom = get_safe_token( image );
|
||||
|
||||
return cdrom->cdrom_handle;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START(cdrom)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START(cdrom)
|
||||
{
|
||||
dev_cdrom_t *cdrom = get_safe_token( device );
|
||||
|
||||
cdrom->cdrom_handle = NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_SOFTLIST_LOAD(cdrom)
|
||||
-------------------------------------------------*/
|
||||
static DEVICE_IMAGE_SOFTLIST_LOAD(cdrom)
|
||||
{
|
||||
return image.load_software(swlist, swname, start_entry);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(cdrom)
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(cdrom)
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(dev_cdrom_t); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(cdrom_config); break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_CDROM; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_CREATE_OPTCOUNT: info->i = 1; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(cdrom); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(cdrom); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(cdrom); break;
|
||||
case DEVINFO_FCT_IMAGE_SOFTLIST_LOAD: info->f = (genf *) DEVICE_IMAGE_SOFTLIST_LOAD_NAME(cdrom); break;
|
||||
case DEVINFO_PTR_IMAGE_CREATE_OPTGUIDE: info->p = (void *) mess_cd_option_guide; break;
|
||||
case DEVINFO_PTR_IMAGE_CREATE_OPTSPEC+0: info->p = (void *) mess_cd_option_spec; break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Cdrom"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Cdrom"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "chd"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTNAME+0: strcpy(info->s, "chdcd"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTDESC+0: strcpy(info->s, "MAME/MESS CHD CD-ROM drive"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTEXTS+0: strcpy(info->s, "chd"); break;
|
||||
|
||||
case DEVINFO_STR_IMAGE_INTERFACE:
|
||||
if ( device && downcast<const legacy_image_device_config_base *>(device)->inline_config() && get_config_dev(device)->interface )
|
||||
{
|
||||
strcpy(info->s, get_config_dev(device)->interface );
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(CDROM, cdrom);
|
43
src/emu/imagedev/chd_cd.h
Normal file
43
src/emu/imagedev/chd_cd.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*********************************************************************
|
||||
|
||||
chd_cd.h
|
||||
|
||||
MESS interface to the MAME CHD CDROM code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MESS_CD_H
|
||||
#define MESS_CD_H
|
||||
|
||||
#include "cdrom.h"
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct cdrom_config_t cdrom_config;
|
||||
struct cdrom_config_t
|
||||
{
|
||||
const char * interface;
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(CDROM, cdrom);
|
||||
|
||||
|
||||
cdrom_file *mess_cd_get_cdrom_file(device_t *device);
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#define MCFG_CDROM_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, CDROM, 0) \
|
||||
|
||||
#define MCFG_CDROM_INTERFACE(_interface) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(cdrom_config, interface, _interface )
|
||||
|
||||
#endif /* MESS_CD_H */
|
1045
src/emu/imagedev/flopdrv.c
Normal file
1045
src/emu/imagedev/flopdrv.c
Normal file
File diff suppressed because it is too large
Load Diff
245
src/emu/imagedev/flopdrv.h
Normal file
245
src/emu/imagedev/flopdrv.h
Normal file
@ -0,0 +1,245 @@
|
||||
/* flopdrv provides simple emulation of a disc drive */
|
||||
/* the 8271, upd765 and wd179x use this */
|
||||
|
||||
#ifndef __FLOPDRV_H__
|
||||
#define __FLOPDRV_H__
|
||||
|
||||
#include "devcb.h"
|
||||
#include "image.h"
|
||||
#include "flopimg.h"
|
||||
|
||||
#define FLOPPY_TYPE_REGULAR 0
|
||||
#define FLOPPY_TYPE_APPLE 1
|
||||
#define FLOPPY_TYPE_SONY 2
|
||||
|
||||
#define FLOPPY_DRIVE_2_8_INCH 1
|
||||
#define FLOPPY_DRIVE_3_INCH 2
|
||||
#define FLOPPY_DRIVE_3_5_INCH 3
|
||||
#define FLOPPY_DRIVE_5_25_INCH 4
|
||||
#define FLOPPY_DRIVE_8_INCH 5
|
||||
|
||||
// Maximum supported density
|
||||
#define FLOPPY_DRIVE_SD 1
|
||||
#define FLOPPY_DRIVE_DD 2
|
||||
#define FLOPPY_DRIVE_QD 3
|
||||
#define FLOPPY_DRIVE_HD 4
|
||||
#define FLOPPY_DRIVE_ED 5
|
||||
|
||||
#define FLOPPY_STANDARD_3_SSDD { FLOPPY_DRIVE_3_INCH, 1, 42, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_3_DSDD { FLOPPY_DRIVE_3_INCH, 2, 42, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_3_5_DSDD { FLOPPY_DRIVE_3_5_INCH, 2, 83, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_3_5_DSHD { FLOPPY_DRIVE_3_5_INCH, 2, 83, FLOPPY_DRIVE_HD }
|
||||
#define FLOPPY_STANDARD_5_25_SSSD_35 { FLOPPY_DRIVE_5_25_INCH, 1, 37, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_5_25_DSSD_35 { FLOPPY_DRIVE_5_25_INCH, 2, 37, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_5_25_SSSD { FLOPPY_DRIVE_5_25_INCH, 1, 42, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_5_25_DSSD { FLOPPY_DRIVE_5_25_INCH, 2, 42, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_5_25_SSDD_40 { FLOPPY_DRIVE_5_25_INCH, 1, 42, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_5_25_DSDD_40 { FLOPPY_DRIVE_5_25_INCH, 2, 42, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_5_25_SSDD { FLOPPY_DRIVE_5_25_INCH, 1, 83, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_5_25_DSDD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_DD }
|
||||
#define FLOPPY_STANDARD_5_25_DSQD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_QD }
|
||||
#define FLOPPY_STANDARD_5_25_DSHD { FLOPPY_DRIVE_5_25_INCH, 2, 83, FLOPPY_DRIVE_HD }
|
||||
#define FLOPPY_STANDARD_8_SSSD { FLOPPY_DRIVE_8_INCH, 1, 77, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_8_DSSD { FLOPPY_DRIVE_8_INCH, 2, 77, FLOPPY_DRIVE_SD }
|
||||
#define FLOPPY_STANDARD_8_DSDD { FLOPPY_DRIVE_8_INCH, 2, 77, FLOPPY_DRIVE_DD }
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
typedef struct floppy_type_t floppy_type;
|
||||
struct floppy_type_t
|
||||
{
|
||||
UINT8 media_size;
|
||||
UINT8 head_number;
|
||||
UINT8 max_track_number;
|
||||
UINT8 max_density;
|
||||
};
|
||||
|
||||
typedef struct floppy_config_t floppy_config;
|
||||
struct floppy_config_t
|
||||
{
|
||||
devcb_write_line out_idx_func; /* index */
|
||||
devcb_read_line in_mon_func; /* motor on */
|
||||
devcb_write_line out_tk00_func; /* track 00 */
|
||||
devcb_write_line out_wpt_func; /* write protect */
|
||||
devcb_write_line out_rdy_func; /* ready */
|
||||
// devcb_write_line out_dskchg_func; /* disk changed */
|
||||
|
||||
floppy_type_t floppy_type;
|
||||
const struct FloppyFormat *formats;
|
||||
const char *interface;
|
||||
};
|
||||
|
||||
/* sector has a deleted data address mark */
|
||||
#define ID_FLAG_DELETED_DATA 0x0001
|
||||
/* CRC error in id field */
|
||||
#define ID_FLAG_CRC_ERROR_IN_ID_FIELD 0x0002
|
||||
/* CRC error in data field */
|
||||
#define ID_FLAG_CRC_ERROR_IN_DATA_FIELD 0x0004
|
||||
|
||||
typedef struct chrn_id
|
||||
{
|
||||
unsigned char C;
|
||||
unsigned char H;
|
||||
unsigned char R;
|
||||
unsigned char N;
|
||||
int data_id; // id for read/write data command
|
||||
unsigned long flags;
|
||||
} chrn_id;
|
||||
|
||||
/* set if drive is ready */
|
||||
#define FLOPPY_DRIVE_READY 0x0010
|
||||
/* set if index has just occured */
|
||||
#define FLOPPY_DRIVE_INDEX 0x0020
|
||||
|
||||
/* a callback which will be executed if the ready state of the drive changes e.g. not ready->ready, ready->not ready */
|
||||
void floppy_drive_set_ready_state_change_callback(device_t *img, void (*callback)(device_t *controller,device_t *img, int state));
|
||||
|
||||
void floppy_drive_set_index_pulse_callback(device_t *img, void (*callback)(device_t *controller,device_t *image, int state));
|
||||
|
||||
/* set flag state */
|
||||
int floppy_drive_get_flag_state(device_t *img, int flag);
|
||||
/* get flag state */
|
||||
void floppy_drive_set_flag_state(device_t *img, int flag, int state);
|
||||
/* get current physical track drive is on */
|
||||
int floppy_drive_get_current_track(device_t *img);
|
||||
/* get current physical track size */
|
||||
UINT64 floppy_drive_get_current_track_size(device_t *img, int head);
|
||||
|
||||
/* get next id from track, 1 if got a id, 0 if no id was got */
|
||||
int floppy_drive_get_next_id(device_t *img, int side, chrn_id *);
|
||||
/* set ready state of drive. If flag == 1, set ready state only if drive present,
|
||||
disk is in drive, and motor is on. Otherwise set ready state to the state passed */
|
||||
void floppy_drive_set_ready_state(device_t *img, int state, int flag);
|
||||
|
||||
/* seek up or down */
|
||||
void floppy_drive_seek(device_t *img, signed int signed_tracks);
|
||||
|
||||
void floppy_drive_read_track_data_info_buffer(device_t *img, int side, void *ptr, int *length );
|
||||
void floppy_drive_write_track_data_info_buffer(device_t *img, int side, const void *ptr, int *length );
|
||||
void floppy_drive_format_sector(device_t *img, int side, int sector_index, int c, int h, int r, int n, int filler);
|
||||
void floppy_drive_read_sector_data(device_t *img, int side, int index1, void *pBuffer, int length);
|
||||
void floppy_drive_write_sector_data(device_t *img, int side, int index1, const void *pBuffer, int length, int ddam);
|
||||
|
||||
/* set motor speed to get correct index pulses
|
||||
standard RPM are 300 RPM (common) and 360 RPM
|
||||
Note: this actually only works for soft sectored disks: one index pulse per
|
||||
track.
|
||||
*/
|
||||
void floppy_drive_set_rpm(device_t *image, float rpm);
|
||||
|
||||
void floppy_drive_set_controller(device_t *img, device_t *controller);
|
||||
|
||||
floppy_image *flopimg_get_image(device_t *image);
|
||||
|
||||
/* hack for apple II; replace this when we think of something better */
|
||||
void floppy_install_unload_proc(device_t *image, void (*proc)(device_image_interface &image));
|
||||
|
||||
void floppy_install_load_proc(device_t *image, void (*proc)(device_image_interface &image));
|
||||
|
||||
device_t *floppy_get_device(running_machine *machine,int drive);
|
||||
device_t *floppy_get_device_by_type(running_machine *machine,int ftype,int drive);
|
||||
int floppy_get_drive_type(device_t *image);
|
||||
void floppy_set_type(device_t *image,int ftype);
|
||||
int floppy_get_count(running_machine *machine);
|
||||
|
||||
int floppy_get_drive(device_t *image);
|
||||
int floppy_get_drive_by_type(device_t *image,int ftype);
|
||||
|
||||
void *flopimg_get_custom_data(device_t *image);
|
||||
void flopimg_alloc_custom_data(device_t *image,void *custom);
|
||||
|
||||
void floppy_drive_set_geometry(device_t *img, floppy_type_t type);
|
||||
|
||||
/* drive select lines */
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_ds0_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_ds1_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_ds2_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_ds3_w );
|
||||
WRITE8_DEVICE_HANDLER( floppy_ds_w );
|
||||
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_mon_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_drtn_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_stp_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_wtd_w );
|
||||
WRITE_LINE_DEVICE_HANDLER( floppy_wtg_w );
|
||||
|
||||
/* write-protect */
|
||||
READ_LINE_DEVICE_HANDLER( floppy_wpt_r );
|
||||
|
||||
/* track 0 detect */
|
||||
READ_LINE_DEVICE_HANDLER( floppy_tk00_r );
|
||||
|
||||
/* disk changed */
|
||||
READ_LINE_DEVICE_HANDLER( floppy_dskchg_r );
|
||||
|
||||
/* 2-sided disk */
|
||||
READ_LINE_DEVICE_HANDLER( floppy_twosid_r );
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(FLOPPY, floppy);
|
||||
|
||||
extern DEVICE_START( floppy );
|
||||
extern DEVICE_IMAGE_LOAD( floppy );
|
||||
extern DEVICE_IMAGE_CREATE( floppy );
|
||||
extern DEVICE_IMAGE_UNLOAD( floppy );
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
#define FLOPPY_0 "floppy0"
|
||||
#define FLOPPY_1 "floppy1"
|
||||
#define FLOPPY_2 "floppy2"
|
||||
#define FLOPPY_3 "floppy3"
|
||||
|
||||
|
||||
#define MCFG_FLOPPY_DRIVE_ADD(_tag, _config) \
|
||||
MCFG_DEVICE_ADD(_tag, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_DRIVE_MODIFY(_tag, _config) \
|
||||
MCFG_DEVICE_MODIFY(_tag) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_4_DRIVES_ADD(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_0, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_1, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_2, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_3, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_4_DRIVES_MODIFY(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_1) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_2) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_3) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_4_DRIVES_REMOVE() \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_0) \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_1) \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_2) \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_3)
|
||||
|
||||
#define MCFG_FLOPPY_2_DRIVES_ADD(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_0, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_ADD(FLOPPY_1, FLOPPY, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_2_DRIVES_MODIFY(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_0) \
|
||||
MCFG_DEVICE_CONFIG(_config) \
|
||||
MCFG_DEVICE_MODIFY(FLOPPY_1) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#define MCFG_FLOPPY_2_DRIVES_REMOVE() \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_0) \
|
||||
MCFG_DEVICE_REMOVE(FLOPPY_1)
|
||||
|
||||
#endif /* __FLOPDRV_H__ */
|
930
src/emu/imagedev/flopimg.c
Normal file
930
src/emu/imagedev/flopimg.c
Normal file
@ -0,0 +1,930 @@
|
||||
/*********************************************************************
|
||||
|
||||
flopimg.c
|
||||
|
||||
Floppy disk image abstraction code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "osdepend.h"
|
||||
#include "flopimg.h"
|
||||
#include "pool.h"
|
||||
#include "imageutl.h"
|
||||
|
||||
#define TRACK_LOADED 0x01
|
||||
#define TRACK_DIRTY 0x02
|
||||
|
||||
|
||||
struct _floppy_image
|
||||
{
|
||||
struct io_generic io;
|
||||
|
||||
const struct FloppyFormat *floppy_option;
|
||||
struct FloppyCallbacks format;
|
||||
|
||||
/* loaded track stuff */
|
||||
int loaded_track_head;
|
||||
int loaded_track_index;
|
||||
UINT32 loaded_track_size;
|
||||
void *loaded_track_data;
|
||||
UINT8 loaded_track_status;
|
||||
UINT8 flags;
|
||||
|
||||
/* tagging system */
|
||||
object_pool *tags;
|
||||
void *tag_data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct _floppy_params
|
||||
{
|
||||
int param;
|
||||
int value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static floperr_t floppy_track_unload(floppy_image *floppy);
|
||||
|
||||
OPTION_GUIDE_START(floppy_option_guide)
|
||||
OPTION_INT('H', "heads", "Heads")
|
||||
OPTION_INT('T', "tracks", "Tracks")
|
||||
OPTION_INT('S', "sectors", "Sectors")
|
||||
OPTION_INT('L', "sectorlength", "Sector Bytes")
|
||||
OPTION_INT('I', "interleave", "Interleave")
|
||||
OPTION_INT('F', "firstsectorid", "First Sector")
|
||||
OPTION_GUIDE_END
|
||||
|
||||
|
||||
static void floppy_close_internal(floppy_image *floppy, int close_file);
|
||||
|
||||
/*********************************************************************
|
||||
opening, closing and creating of floppy images
|
||||
*********************************************************************/
|
||||
|
||||
/* basic floppy_image initialization common to floppy_open() and floppy_create() */
|
||||
static floppy_image *floppy_init(void *fp, const struct io_procs *procs, int flags)
|
||||
{
|
||||
floppy_image *floppy;
|
||||
|
||||
floppy = (floppy_image *)malloc(sizeof(struct _floppy_image));
|
||||
if (!floppy)
|
||||
return NULL;
|
||||
|
||||
memset(floppy, 0, sizeof(*floppy));
|
||||
floppy->tags = pool_alloc_lib(NULL);
|
||||
floppy->tag_data = NULL;
|
||||
floppy->io.file = fp;
|
||||
floppy->io.procs = procs;
|
||||
floppy->io.filler = 0xFF;
|
||||
floppy->flags = (UINT8) flags;
|
||||
return floppy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* main code for identifying and maybe opening a disk image; not exposed
|
||||
* directly because this function is big and hideous */
|
||||
static floperr_t floppy_open_internal(void *fp, const struct io_procs *procs, const char *extension,
|
||||
const struct FloppyFormat *floppy_options, int max_options, int flags, floppy_image **outfloppy,
|
||||
int *outoption)
|
||||
{
|
||||
floperr_t err;
|
||||
floppy_image *floppy;
|
||||
int best_option = -1;
|
||||
int best_vote = 0;
|
||||
int vote;
|
||||
size_t i;
|
||||
|
||||
floppy = floppy_init(fp, procs, flags);
|
||||
if (!floppy)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* vote on the best format */
|
||||
for (i = 0; (i < max_options) && floppy_options[i].construct; i++)
|
||||
{
|
||||
if (!extension || !floppy_options[i].extensions || image_find_extension(floppy_options[i].extensions, extension))
|
||||
{
|
||||
if (floppy_options[i].identify)
|
||||
{
|
||||
vote = 0;
|
||||
err = floppy_options[i].identify(floppy, &floppy_options[i], &vote);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
vote = 1;
|
||||
}
|
||||
|
||||
/* is this option a better one? */
|
||||
if (vote > best_vote)
|
||||
{
|
||||
best_vote = vote;
|
||||
best_option = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* did we find a format? */
|
||||
if (best_option == -1)
|
||||
{
|
||||
err = FLOPPY_ERROR_INVALIDIMAGE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (outfloppy)
|
||||
{
|
||||
/* call the format constructor */
|
||||
err = floppy_options[best_option].construct(floppy, &floppy_options[best_option], NULL);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
floppy->floppy_option = &floppy_options[best_option];
|
||||
}
|
||||
|
||||
err = FLOPPY_ERROR_SUCCESS;
|
||||
|
||||
done:
|
||||
/* if we have a floppy disk and we either errored or are not keeping it, close it */
|
||||
if (floppy && (!outfloppy || err))
|
||||
{
|
||||
floppy_close_internal(floppy, FALSE);
|
||||
floppy = NULL;
|
||||
}
|
||||
|
||||
if (outoption)
|
||||
*outoption = err ? -1 : best_option;
|
||||
if (outfloppy)
|
||||
*outfloppy = floppy;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_identify(void *fp, const struct io_procs *procs, const char *extension,
|
||||
const struct FloppyFormat *formats, int *identified_format)
|
||||
{
|
||||
return floppy_open_internal(fp, procs, extension, formats, INT_MAX, FLOPPY_FLAGS_READONLY, NULL, identified_format);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_open(void *fp, const struct io_procs *procs, const char *extension,
|
||||
const struct FloppyFormat *format, int flags, floppy_image **outfloppy)
|
||||
{
|
||||
return floppy_open_internal(fp, procs, extension, format, 1, flags, outfloppy, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_open_choices(void *fp, const struct io_procs *procs, const char *extension,
|
||||
const struct FloppyFormat *formats, int flags, floppy_image **outfloppy)
|
||||
{
|
||||
return floppy_open_internal(fp, procs, extension, formats, INT_MAX, flags, outfloppy, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static floperr_t option_to_floppy_error(optreserr_t oerr)
|
||||
{
|
||||
floperr_t err;
|
||||
switch(oerr) {
|
||||
case OPTIONRESOLUTION_ERROR_SUCCESS:
|
||||
err = FLOPPY_ERROR_SUCCESS;
|
||||
break;
|
||||
case OPTIONRESOLUTION_ERROR_OUTOFMEMORY:
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
case OPTIONRESOLUTION_ERROR_PARAMOUTOFRANGE:
|
||||
case OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED:
|
||||
case OPTIONRESOLUTION_ERROR_PARAMNOTFOUND:
|
||||
case OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED:
|
||||
case OPTIONRESOLUTION_ERROR_BADPARAM:
|
||||
case OPTIONRESOLUTION_ERROR_SYNTAX:
|
||||
default:
|
||||
err = FLOPPY_ERROR_INTERNAL;
|
||||
break;
|
||||
};
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct FloppyFormat *format, option_resolution *parameters, floppy_image **outfloppy)
|
||||
{
|
||||
floppy_image *floppy = NULL;
|
||||
optreserr_t oerr;
|
||||
floperr_t err;
|
||||
int heads, tracks, h, t;
|
||||
option_resolution *alloc_resolution = NULL;
|
||||
|
||||
assert(format);
|
||||
|
||||
/* create the new image */
|
||||
floppy = floppy_init(fp, procs, 0);
|
||||
if (!floppy)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* if this format expects creation parameters and none were specified, create some */
|
||||
if (!parameters && format->param_guidelines)
|
||||
{
|
||||
alloc_resolution = option_resolution_create(floppy_option_guide, format->param_guidelines);
|
||||
if (!alloc_resolution)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
parameters = alloc_resolution;
|
||||
}
|
||||
|
||||
/* finish the parameters, if specified */
|
||||
if (parameters)
|
||||
{
|
||||
oerr = option_resolution_finish(parameters);
|
||||
if (oerr)
|
||||
{
|
||||
err = option_to_floppy_error(oerr);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* call the format constructor */
|
||||
err = format->construct(floppy, format, parameters);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
/* format the disk, ignoring if formatting not implemented */
|
||||
if (floppy->format.format_track)
|
||||
{
|
||||
heads = floppy_get_heads_per_disk(floppy);
|
||||
tracks = floppy_get_tracks_per_disk(floppy);
|
||||
|
||||
for (h = 0; h < heads; h++)
|
||||
{
|
||||
for (t = 0; t < tracks; t++)
|
||||
{
|
||||
err = floppy->format.format_track(floppy, h, t, parameters);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* call the post_format function, if present */
|
||||
if (floppy->format.post_format)
|
||||
{
|
||||
err = floppy->format.post_format(floppy, parameters);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
|
||||
floppy->floppy_option = format;
|
||||
err = FLOPPY_ERROR_SUCCESS;
|
||||
|
||||
done:
|
||||
if (err && floppy)
|
||||
{
|
||||
floppy_close_internal(floppy, FALSE);
|
||||
floppy = NULL;
|
||||
}
|
||||
|
||||
if (outfloppy)
|
||||
*outfloppy = floppy;
|
||||
else if (floppy)
|
||||
floppy_close_internal(floppy, FALSE);
|
||||
|
||||
if (alloc_resolution)
|
||||
option_resolution_close(alloc_resolution);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void floppy_close_internal(floppy_image *floppy, int close_file)
|
||||
{
|
||||
if (floppy) {
|
||||
floppy_track_unload(floppy);
|
||||
if (close_file)
|
||||
io_generic_close(&floppy->io);
|
||||
if (floppy->loaded_track_data)
|
||||
free(floppy->loaded_track_data);
|
||||
pool_free_lib(floppy->tags);
|
||||
|
||||
free(floppy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void floppy_close(floppy_image *floppy)
|
||||
{
|
||||
floppy_close_internal(floppy, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
functions useful in format constructors
|
||||
*********************************************************************/
|
||||
|
||||
struct FloppyCallbacks *floppy_callbacks(floppy_image *floppy)
|
||||
{
|
||||
assert(floppy);
|
||||
return &floppy->format;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *floppy_tag(floppy_image *floppy)
|
||||
{
|
||||
assert(floppy);
|
||||
return floppy->tag_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *floppy_create_tag(floppy_image *floppy, size_t tagsize)
|
||||
{
|
||||
floppy->tag_data = pool_malloc_lib(floppy->tags,tagsize);
|
||||
return floppy->tag_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UINT8 floppy_get_filler(floppy_image *floppy)
|
||||
{
|
||||
return floppy->io.filler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void floppy_set_filler(floppy_image *floppy, UINT8 filler)
|
||||
{
|
||||
floppy->io.filler = filler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
calls for accessing the raw disk image
|
||||
*********************************************************************/
|
||||
|
||||
void floppy_image_read(floppy_image *floppy, void *buffer, UINT64 offset, size_t length)
|
||||
{
|
||||
io_generic_read(&floppy->io, buffer, offset, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void floppy_image_write(floppy_image *floppy, const void *buffer, UINT64 offset, size_t length)
|
||||
{
|
||||
io_generic_write(&floppy->io, buffer, offset, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void floppy_image_write_filler(floppy_image *floppy, UINT8 filler, UINT64 offset, size_t length)
|
||||
{
|
||||
io_generic_write_filler(&floppy->io, filler, offset, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
UINT64 floppy_image_size(floppy_image *floppy)
|
||||
{
|
||||
return io_generic_size(&floppy->io);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
calls for accessing disk image data
|
||||
*********************************************************************/
|
||||
|
||||
static floperr_t floppy_readwrite_sector(floppy_image *floppy, int head, int track, int sector, int offset,
|
||||
void *buffer, size_t buffer_len, int writing, int indexed, int ddam)
|
||||
{
|
||||
floperr_t err;
|
||||
const struct FloppyCallbacks *fmt;
|
||||
size_t this_buffer_len;
|
||||
UINT8 *alloc_buf = NULL;
|
||||
UINT32 sector_length;
|
||||
UINT8 *buffer_ptr = (UINT8 *)buffer;
|
||||
floperr_t (*read_sector)(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen);
|
||||
floperr_t (*write_sector)(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
|
||||
|
||||
fmt = floppy_callbacks(floppy);
|
||||
|
||||
/* choose proper calls for indexed vs non-indexed */
|
||||
if (indexed)
|
||||
{
|
||||
read_sector = fmt->read_indexed_sector;
|
||||
write_sector = fmt->write_indexed_sector;
|
||||
if (!fmt->get_indexed_sector_info)
|
||||
{
|
||||
err = FLOPPY_ERROR_UNSUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
read_sector = fmt->read_sector;
|
||||
write_sector = fmt->write_sector;
|
||||
if (!fmt->get_sector_length)
|
||||
{
|
||||
err = FLOPPY_ERROR_UNSUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* check to make sure that the operation is supported */
|
||||
if (!read_sector || (writing && !write_sector))
|
||||
{
|
||||
err = FLOPPY_ERROR_UNSUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* main loop */
|
||||
while(buffer_len > 0)
|
||||
{
|
||||
/* find out the size of this sector */
|
||||
if (indexed)
|
||||
err = fmt->get_indexed_sector_info(floppy, head, track, sector, NULL, NULL, NULL, §or_length, NULL);
|
||||
else
|
||||
err = fmt->get_sector_length(floppy, head, track, sector, §or_length);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
/* do we even do anything with this sector? */
|
||||
if (offset < sector_length)
|
||||
{
|
||||
/* ok we will be doing something */
|
||||
if ((offset > 0) || (buffer_len < sector_length))
|
||||
{
|
||||
/* we will be doing an partial read/write; in other words we
|
||||
* will not be reading/writing a full sector */
|
||||
if (alloc_buf) free(alloc_buf);
|
||||
alloc_buf = (UINT8*)malloc(sector_length);
|
||||
if (!alloc_buf)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* read the sector (we need to do this even when writing */
|
||||
err = read_sector(floppy, head, track, sector, alloc_buf, sector_length);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
this_buffer_len = MIN(buffer_len, sector_length - offset);
|
||||
|
||||
if (writing)
|
||||
{
|
||||
memcpy(alloc_buf + offset, buffer_ptr, this_buffer_len);
|
||||
|
||||
err = write_sector(floppy, head, track, sector, alloc_buf, sector_length, ddam);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(buffer_ptr, alloc_buf + offset, this_buffer_len);
|
||||
}
|
||||
offset += this_buffer_len;
|
||||
offset %= sector_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_buffer_len = sector_length;
|
||||
|
||||
if (writing)
|
||||
err = write_sector(floppy, head, track, sector, buffer_ptr, sector_length, ddam);
|
||||
else
|
||||
err = read_sector(floppy, head, track, sector, buffer_ptr, sector_length);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* skip this sector */
|
||||
offset -= sector_length;
|
||||
this_buffer_len = 0;
|
||||
}
|
||||
|
||||
buffer_ptr += this_buffer_len;
|
||||
buffer_len -= this_buffer_len;
|
||||
sector++;
|
||||
}
|
||||
|
||||
err = FLOPPY_ERROR_SUCCESS;
|
||||
|
||||
done:
|
||||
if (alloc_buf)
|
||||
free(alloc_buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_read_sector(floppy_image *floppy, int head, int track, int sector, int offset, void *buffer, size_t buffer_len)
|
||||
{
|
||||
return floppy_readwrite_sector(floppy, head, track, sector, offset, buffer, buffer_len, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_write_sector(floppy_image *floppy, int head, int track, int sector, int offset, const void *buffer, size_t buffer_len, int ddam)
|
||||
{
|
||||
return floppy_readwrite_sector(floppy, head, track, sector, offset, (void *) buffer, buffer_len, TRUE, FALSE, ddam);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_read_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, int offset, void *buffer, size_t buffer_len)
|
||||
{
|
||||
return floppy_readwrite_sector(floppy, head, track, sector_index, offset, buffer, buffer_len, FALSE, TRUE, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_write_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, int offset, const void *buffer, size_t buffer_len, int ddam)
|
||||
{
|
||||
return floppy_readwrite_sector(floppy, head, track, sector_index, offset, (void *) buffer, buffer_len, TRUE, TRUE, ddam);
|
||||
}
|
||||
|
||||
|
||||
static floperr_t floppy_get_track_data_offset(floppy_image *floppy, int head, int track, UINT64 *offset)
|
||||
{
|
||||
floperr_t err;
|
||||
const struct FloppyCallbacks *callbacks;
|
||||
|
||||
*offset = 0;
|
||||
callbacks = floppy_callbacks(floppy);
|
||||
if (callbacks->get_track_data_offset)
|
||||
{
|
||||
err = callbacks->get_track_data_offset(floppy, head, track, offset);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return FLOPPY_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static floperr_t floppy_read_track_offset(floppy_image *floppy, int head, int track, UINT64 offset, void *buffer, size_t buffer_len)
|
||||
{
|
||||
floperr_t err;
|
||||
const struct FloppyCallbacks *format;
|
||||
|
||||
format = floppy_callbacks(floppy);
|
||||
|
||||
if (!format->read_track)
|
||||
return FLOPPY_ERROR_UNSUPPORTED;
|
||||
|
||||
err = floppy_track_unload(floppy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = format->read_track(floppy, head, track, offset, buffer, buffer_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return FLOPPY_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_read_track(floppy_image *floppy, int head, int track, void *buffer, size_t buffer_len)
|
||||
{
|
||||
return floppy_read_track_offset(floppy, head, track, 0, buffer, buffer_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_read_track_data(floppy_image *floppy, int head, int track, void *buffer, size_t buffer_len)
|
||||
{
|
||||
floperr_t err;
|
||||
UINT64 offset;
|
||||
|
||||
err = floppy_get_track_data_offset(floppy, head, track, &offset);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return floppy_read_track_offset(floppy, head, track, offset, buffer, buffer_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static floperr_t floppy_write_track_offset(floppy_image *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buffer_len)
|
||||
{
|
||||
floperr_t err;
|
||||
|
||||
/* track writing supported? */
|
||||
if (!floppy_callbacks(floppy)->write_track)
|
||||
return FLOPPY_ERROR_UNSUPPORTED;
|
||||
|
||||
/* read only? */
|
||||
if (floppy->flags & FLOPPY_FLAGS_READONLY)
|
||||
return FLOPPY_ERROR_READONLY;
|
||||
|
||||
err = floppy_track_unload(floppy);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = floppy_callbacks(floppy)->write_track(floppy, head, track, offset, buffer, buffer_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return FLOPPY_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_write_track(floppy_image *floppy, int head, int track, const void *buffer, size_t buffer_len)
|
||||
{
|
||||
return floppy_write_track_offset(floppy, head, track, 0, buffer, buffer_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_write_track_data(floppy_image *floppy, int head, int track, const void *buffer, size_t buffer_len)
|
||||
{
|
||||
floperr_t err;
|
||||
UINT64 offset;
|
||||
|
||||
err = floppy_get_track_data_offset(floppy, head, track, &offset);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return floppy_write_track_offset(floppy, head, track, offset, buffer, buffer_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_format_track(floppy_image *floppy, int head, int track, option_resolution *parameters)
|
||||
{
|
||||
floperr_t err;
|
||||
struct FloppyCallbacks *format;
|
||||
option_resolution *alloc_resolution = NULL;
|
||||
optreserr_t oerr;
|
||||
|
||||
/* supported? */
|
||||
format = floppy_callbacks(floppy);
|
||||
if (!format->format_track)
|
||||
{
|
||||
err = FLOPPY_ERROR_UNSUPPORTED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* create a dummy resolution; if no parameters were specified */
|
||||
if (!parameters)
|
||||
{
|
||||
alloc_resolution = option_resolution_create(floppy_option_guide, floppy->floppy_option->param_guidelines);
|
||||
if (!alloc_resolution)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto done;
|
||||
}
|
||||
parameters = alloc_resolution;
|
||||
}
|
||||
|
||||
oerr = option_resolution_finish(parameters);
|
||||
if (oerr)
|
||||
{
|
||||
err = option_to_floppy_error(oerr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = format->format_track(floppy, head, track, parameters);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (alloc_resolution)
|
||||
option_resolution_close(alloc_resolution);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int floppy_get_tracks_per_disk(floppy_image *floppy)
|
||||
{
|
||||
return floppy_callbacks(floppy)->get_tracks_per_disk(floppy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int floppy_get_heads_per_disk(floppy_image *floppy)
|
||||
{
|
||||
return floppy_callbacks(floppy)->get_heads_per_disk(floppy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
UINT32 floppy_get_track_size(floppy_image *floppy, int head, int track)
|
||||
{
|
||||
const struct FloppyCallbacks *fmt;
|
||||
|
||||
fmt = floppy_callbacks(floppy);
|
||||
if (!fmt->get_track_size)
|
||||
return 0;
|
||||
|
||||
return fmt->get_track_size(floppy, head, track);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length)
|
||||
{
|
||||
const struct FloppyCallbacks *fmt;
|
||||
|
||||
fmt = floppy_callbacks(floppy);
|
||||
if (!fmt->get_sector_length)
|
||||
return FLOPPY_ERROR_UNSUPPORTED;
|
||||
|
||||
return fmt->get_sector_length(floppy, head, track, sector, sector_length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags)
|
||||
{
|
||||
const struct FloppyCallbacks *fmt;
|
||||
|
||||
fmt = floppy_callbacks(floppy);
|
||||
if (!fmt->get_indexed_sector_info)
|
||||
return FLOPPY_ERROR_UNSUPPORTED;
|
||||
|
||||
return fmt->get_indexed_sector_info(floppy, head, track, sector_index, cylinder, side, sector, sector_length, flags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
floperr_t floppy_get_sector_count(floppy_image *floppy, int head, int track, int *sector_count)
|
||||
{
|
||||
floperr_t err;
|
||||
int sector_index = 0;
|
||||
|
||||
do
|
||||
{
|
||||
err = floppy_get_indexed_sector_info(floppy, head, track, sector_index, NULL, NULL, NULL, NULL, NULL);
|
||||
if (!err)
|
||||
sector_index++;
|
||||
}
|
||||
while(!err);
|
||||
|
||||
if (sector_index && (err == FLOPPY_ERROR_SEEKERROR))
|
||||
err = FLOPPY_ERROR_SUCCESS;
|
||||
if (sector_count)
|
||||
*sector_count = err ? 0 : sector_index;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int floppy_is_read_only(floppy_image *floppy)
|
||||
{
|
||||
return floppy->flags & FLOPPY_FLAGS_READONLY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UINT8 floppy_random_byte(floppy_image *floppy)
|
||||
{
|
||||
/* can't use mame_rand(); this might not be in the core */
|
||||
#ifdef rand
|
||||
#undef rand
|
||||
#endif
|
||||
return rand();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
calls for track based IO
|
||||
*********************************************************************/
|
||||
|
||||
floperr_t floppy_load_track(floppy_image *floppy, int head, int track, int dirtify, void **track_data, size_t *track_length)
|
||||
{
|
||||
floperr_t err;
|
||||
void *new_loaded_track_data;
|
||||
UINT32 track_size;
|
||||
|
||||
/* have we already loaded this track? */
|
||||
if (((floppy->loaded_track_status & TRACK_LOADED) == 0) || (head != floppy->loaded_track_head) || (track != floppy->loaded_track_index))
|
||||
{
|
||||
err = floppy_track_unload(floppy);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
track_size = floppy_callbacks(floppy)->get_track_size(floppy, head, track);
|
||||
|
||||
if (floppy->loaded_track_data) free(floppy->loaded_track_data);
|
||||
new_loaded_track_data = malloc(track_size);
|
||||
if (!new_loaded_track_data)
|
||||
{
|
||||
err = FLOPPY_ERROR_OUTOFMEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
floppy->loaded_track_data = new_loaded_track_data;
|
||||
floppy->loaded_track_size = track_size;
|
||||
floppy->loaded_track_head = head;
|
||||
floppy->loaded_track_index = track;
|
||||
|
||||
err = floppy_callbacks(floppy)->read_track(floppy, floppy->loaded_track_head, floppy->loaded_track_index, 0, floppy->loaded_track_data, floppy->loaded_track_size);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
floppy->loaded_track_status |= TRACK_LOADED | (dirtify ? TRACK_DIRTY : 0);
|
||||
}
|
||||
else
|
||||
floppy->loaded_track_status |= (dirtify ? TRACK_DIRTY : 0);
|
||||
|
||||
if (track_data)
|
||||
*track_data = floppy->loaded_track_data;
|
||||
if (track_length)
|
||||
*track_length = floppy->loaded_track_size;
|
||||
return FLOPPY_ERROR_SUCCESS;
|
||||
|
||||
error:
|
||||
if (track_data)
|
||||
*track_data = NULL;
|
||||
if (track_length)
|
||||
*track_length = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static floperr_t floppy_track_unload(floppy_image *floppy)
|
||||
{
|
||||
int err;
|
||||
if (floppy->loaded_track_status & TRACK_DIRTY)
|
||||
{
|
||||
err = floppy_callbacks(floppy)->write_track(floppy, floppy->loaded_track_head, floppy->loaded_track_index, 0, floppy->loaded_track_data, floppy->loaded_track_size);
|
||||
if (err)
|
||||
return (floperr_t)err;
|
||||
}
|
||||
|
||||
floppy->loaded_track_status &= ~(TRACK_LOADED | TRACK_DIRTY);
|
||||
return FLOPPY_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
accessors for meta information about the image
|
||||
*********************************************************************/
|
||||
|
||||
const char *floppy_format_description(floppy_image *floppy)
|
||||
{
|
||||
return floppy->floppy_option->description;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
misc calls
|
||||
*********************************************************************/
|
||||
|
||||
const char *floppy_error(floperr_t err)
|
||||
{
|
||||
static const char *const error_messages[] =
|
||||
{
|
||||
"The operation completed successfully",
|
||||
"Fatal internal error",
|
||||
"This operation is unsupported",
|
||||
"Out of memory",
|
||||
"Seek error",
|
||||
"Invalid image",
|
||||
"Attempted to write to read only image",
|
||||
"No space left on image",
|
||||
"Parameter out of range",
|
||||
"Required parameter not specified"
|
||||
};
|
||||
|
||||
if ((err < 0) || (err >= ARRAY_LENGTH(error_messages)))
|
||||
return NULL;
|
||||
return error_messages[err];
|
||||
}
|
||||
|
||||
|
||||
FLOPPY_OPTIONS_START(default)
|
||||
FLOPPY_OPTIONS_END
|
204
src/emu/imagedev/flopimg.h
Normal file
204
src/emu/imagedev/flopimg.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*********************************************************************
|
||||
|
||||
flopimg.h
|
||||
|
||||
Floppy disk image abstraction code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef FLOPIMG_H
|
||||
#define FLOPIMG_H
|
||||
|
||||
#include "emu.h"
|
||||
#include "opresolv.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Constants
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#define FLOPPY_FLAGS_READWRITE 0
|
||||
#define FLOPPY_FLAGS_READONLY 1
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Type definitions
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FLOPPY_ERROR_SUCCESS, /* no error */
|
||||
FLOPPY_ERROR_INTERNAL, /* fatal internal error */
|
||||
FLOPPY_ERROR_UNSUPPORTED, /* this operation is unsupported */
|
||||
FLOPPY_ERROR_OUTOFMEMORY, /* ran out of memory */
|
||||
FLOPPY_ERROR_SEEKERROR, /* attempted to seek to nonexistant location */
|
||||
FLOPPY_ERROR_INVALIDIMAGE, /* this image in invalid */
|
||||
FLOPPY_ERROR_READONLY, /* attempt to write to read-only image */
|
||||
FLOPPY_ERROR_NOSPACE,
|
||||
FLOPPY_ERROR_PARAMOUTOFRANGE,
|
||||
FLOPPY_ERROR_PARAMNOTSPECIFIED
|
||||
}
|
||||
floperr_t;
|
||||
|
||||
typedef struct _floppy_image floppy_image;
|
||||
|
||||
struct FloppyCallbacks
|
||||
{
|
||||
floperr_t (*read_sector)(floppy_image *floppy, int head, int track, int sector, void *buffer, size_t buflen);
|
||||
floperr_t (*write_sector)(floppy_image *floppy, int head, int track, int sector, const void *buffer, size_t buflen, int ddam);
|
||||
floperr_t (*read_indexed_sector)(floppy_image *floppy, int head, int track, int sector_index, void *buffer, size_t buflen);
|
||||
floperr_t (*write_indexed_sector)(floppy_image *floppy, int head, int track, int sector_index, const void *buffer, size_t buflen, int ddam);
|
||||
floperr_t (*read_track)(floppy_image *floppy, int head, int track, UINT64 offset, void *buffer, size_t buflen);
|
||||
floperr_t (*write_track)(floppy_image *floppy, int head, int track, UINT64 offset, const void *buffer, size_t buflen);
|
||||
floperr_t (*format_track)(floppy_image *floppy, int head, int track, option_resolution *params);
|
||||
floperr_t (*post_format)(floppy_image *floppy, option_resolution *params);
|
||||
int (*get_heads_per_disk)(floppy_image *floppy);
|
||||
int (*get_tracks_per_disk)(floppy_image *floppy);
|
||||
int (*get_sectors_per_track)(floppy_image *floppy, int head, int track);
|
||||
UINT32 (*get_track_size)(floppy_image *floppy, int head, int track);
|
||||
floperr_t (*get_sector_length)(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length);
|
||||
floperr_t (*get_indexed_sector_info)(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags);
|
||||
floperr_t (*get_track_data_offset)(floppy_image *floppy, int head, int track, UINT64 *offset);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct FloppyFormat
|
||||
{
|
||||
const char *name;
|
||||
const char *extensions;
|
||||
const char *description;
|
||||
floperr_t (*identify)(floppy_image *floppy, const struct FloppyFormat *format, int *vote);
|
||||
floperr_t (*construct)(floppy_image *floppy, const struct FloppyFormat *format, option_resolution *params);
|
||||
const char *param_guidelines;
|
||||
};
|
||||
|
||||
#define FLOPPY_IDENTIFY(name) floperr_t name(floppy_image *floppy, const struct FloppyFormat *format, int *vote)
|
||||
#define FLOPPY_CONSTRUCT(name) floperr_t name(floppy_image *floppy, const struct FloppyFormat *format, option_resolution *params)
|
||||
|
||||
FLOPPY_IDENTIFY(td0_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(td0_dsk_construct);
|
||||
|
||||
FLOPPY_IDENTIFY(imd_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(imd_dsk_construct);
|
||||
|
||||
FLOPPY_IDENTIFY(cqm_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(cqm_dsk_construct);
|
||||
|
||||
FLOPPY_IDENTIFY(dsk_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(dsk_dsk_construct);
|
||||
|
||||
FLOPPY_IDENTIFY(d88_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(d88_dsk_construct);
|
||||
|
||||
FLOPPY_IDENTIFY(fdi_dsk_identify);
|
||||
FLOPPY_CONSTRUCT(fdi_dsk_construct);
|
||||
|
||||
#define FLOPPY_OPTIONS_NAME(name) floppyoptions_##name
|
||||
|
||||
#define FLOPPY_OPTIONS_START(name) \
|
||||
const struct FloppyFormat floppyoptions_##name[] = \
|
||||
{ \
|
||||
|
||||
#define FLOPPY_OPTIONS_END0 \
|
||||
{ NULL } \
|
||||
};
|
||||
|
||||
#define FLOPPY_OPTIONS_EXTERN(name) \
|
||||
extern const struct FloppyFormat floppyoptions_##name[] \
|
||||
|
||||
#define FLOPPY_OPTION(name, extensions_, description_, identify_, construct_, ranges_)\
|
||||
{ #name, extensions_, description_, identify_, construct_, ranges_ }, \
|
||||
|
||||
#define FLOPPY_OPTIONS_END \
|
||||
FLOPPY_OPTION( fdi, "fdi", "Formatted Disk Image", fdi_dsk_identify, fdi_dsk_construct, NULL) \
|
||||
FLOPPY_OPTION( td0, "td0", "Teledisk floppy disk image", td0_dsk_identify, td0_dsk_construct, NULL) \
|
||||
FLOPPY_OPTION( imd, "imd", "IMD floppy disk image", imd_dsk_identify, imd_dsk_construct, NULL) \
|
||||
FLOPPY_OPTION( cqm, "cqm,dsk", "CopyQM floppy disk image", cqm_dsk_identify, cqm_dsk_construct, NULL) \
|
||||
FLOPPY_OPTION( dsk, "dsk", "DSK floppy disk image", dsk_dsk_identify, dsk_dsk_construct, NULL) \
|
||||
FLOPPY_OPTION( d88, "d77,d88,1dd", "D88 Floppy Disk image", d88_dsk_identify, d88_dsk_construct, NULL) \
|
||||
FLOPPY_OPTIONS_END0
|
||||
|
||||
FLOPPY_OPTIONS_EXTERN(default);
|
||||
|
||||
#define PARAM_END '\0'
|
||||
#define PARAM_HEADS 'H'
|
||||
#define PARAM_TRACKS 'T'
|
||||
#define PARAM_SECTORS 'S'
|
||||
#define PARAM_SECTOR_LENGTH 'L'
|
||||
#define PARAM_INTERLEAVE 'I'
|
||||
#define PARAM_FIRST_SECTOR_ID 'F'
|
||||
|
||||
#define HEADS(range) "H" #range
|
||||
#define TRACKS(range) "T" #range
|
||||
#define SECTORS(range) "S" #range
|
||||
#define SECTOR_LENGTH(range) "L" #range
|
||||
#define INTERLEAVE(range) "I" #range
|
||||
#define FIRST_SECTOR_ID(range) "F" #range
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Prototypes
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
OPTION_GUIDE_EXTERN(floppy_option_guide);
|
||||
|
||||
/* opening, closing and creating of floppy images */
|
||||
floperr_t floppy_open(void *fp, const struct io_procs *procs, const char *extension, const struct FloppyFormat *format, int flags, floppy_image **outfloppy);
|
||||
floperr_t floppy_open_choices(void *fp, const struct io_procs *procs, const char *extension, const struct FloppyFormat *formats, int flags, floppy_image **outfloppy);
|
||||
floperr_t floppy_create(void *fp, const struct io_procs *procs, const struct FloppyFormat *format, option_resolution *parameters, floppy_image **outfloppy);
|
||||
void floppy_close(floppy_image *floppy);
|
||||
|
||||
/* useful for identifying a floppy image */
|
||||
floperr_t floppy_identify(void *fp, const struct io_procs *procs, const char *extension,
|
||||
const struct FloppyFormat *formats, int *identified_format);
|
||||
|
||||
/* functions useful within format constructors */
|
||||
void *floppy_tag(floppy_image *floppy);
|
||||
void *floppy_create_tag(floppy_image *floppy, size_t tagsize);
|
||||
struct FloppyCallbacks *floppy_callbacks(floppy_image *floppy);
|
||||
UINT8 floppy_get_filler(floppy_image *floppy);
|
||||
void floppy_set_filler(floppy_image *floppy, UINT8 filler);
|
||||
|
||||
/* calls for accessing disk image data */
|
||||
floperr_t floppy_read_sector(floppy_image *floppy, int head, int track, int sector, int offset, void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_write_sector(floppy_image *floppy, int head, int track, int sector, int offset, const void *buffer, size_t buffer_len, int ddam);
|
||||
floperr_t floppy_read_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, int offset, void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_write_indexed_sector(floppy_image *floppy, int head, int track, int sector_index, int offset, const void *buffer, size_t buffer_len, int ddam);
|
||||
floperr_t floppy_read_track(floppy_image *floppy, int head, int track, void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_write_track(floppy_image *floppy, int head, int track, const void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_read_track_data(floppy_image *floppy, int head, int track, void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_write_track_data(floppy_image *floppy, int head, int track, const void *buffer, size_t buffer_len);
|
||||
floperr_t floppy_format_track(floppy_image *floppy, int head, int track, option_resolution *params);
|
||||
int floppy_get_tracks_per_disk(floppy_image *floppy);
|
||||
int floppy_get_heads_per_disk(floppy_image *floppy);
|
||||
UINT32 floppy_get_track_size(floppy_image *floppy, int head, int track);
|
||||
floperr_t floppy_get_sector_length(floppy_image *floppy, int head, int track, int sector, UINT32 *sector_length);
|
||||
floperr_t floppy_get_indexed_sector_info(floppy_image *floppy, int head, int track, int sector_index, int *cylinder, int *side, int *sector, UINT32 *sector_length, unsigned long *flags);
|
||||
floperr_t floppy_get_sector_count(floppy_image *floppy, int head, int track, int *sector_count);
|
||||
floperr_t floppy_load_track(floppy_image *floppy, int head, int track, int dirtify, void **track_data, size_t *track_length);
|
||||
int floppy_is_read_only(floppy_image *floppy);
|
||||
UINT8 floppy_random_byte(floppy_image *floppy);
|
||||
|
||||
/* accessors for meta information about the image */
|
||||
const char *floppy_format_description(floppy_image *floppy);
|
||||
|
||||
/* calls for accessing the raw disk image */
|
||||
void floppy_image_read(floppy_image *floppy, void *buffer, UINT64 offset, size_t length);
|
||||
void floppy_image_write(floppy_image *floppy, const void *buffer, UINT64 offset, size_t length);
|
||||
void floppy_image_write_filler(floppy_image *floppy, UINT8 filler, UINT64 offset, size_t length);
|
||||
UINT64 floppy_image_size(floppy_image *floppy);
|
||||
|
||||
/* misc */
|
||||
const char *floppy_error(floperr_t err);
|
||||
|
||||
|
||||
#endif /* FLOPIMG_H */
|
||||
|
404
src/emu/imagedev/harddriv.c
Normal file
404
src/emu/imagedev/harddriv.c
Normal file
@ -0,0 +1,404 @@
|
||||
/*********************************************************************
|
||||
|
||||
Code to interface the MESS image code with MAME's harddisk core.
|
||||
|
||||
We do not support diff files as it will involve some changes in
|
||||
the MESS image code. Additionally, the need for diff files comes
|
||||
from MAME's need for "cannonical" hard drive images.
|
||||
|
||||
Raphael Nabet 2003
|
||||
|
||||
Update: 23-Feb-2004 - Unlike floppy disks, for which we support
|
||||
myriad formats on many systems, it is my intention for MESS to
|
||||
standardize on the CHD file format for hard drives so I made a few
|
||||
changes to support this
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "harddisk.h"
|
||||
#include "harddriv.h"
|
||||
|
||||
|
||||
static const char *const error_strings[] =
|
||||
{
|
||||
"no error",
|
||||
"no drive interface",
|
||||
"out of memory",
|
||||
"invalid file",
|
||||
"invalid parameter",
|
||||
"invalid data",
|
||||
"file not found",
|
||||
"requires parent",
|
||||
"file not writeable",
|
||||
"read error",
|
||||
"write error",
|
||||
"codec error",
|
||||
"invalid parent",
|
||||
"hunk out of range",
|
||||
"decompression error",
|
||||
"compression error",
|
||||
"can't create file",
|
||||
"can't verify file"
|
||||
"operation not supported",
|
||||
"can't find metadata",
|
||||
"invalid metadata size",
|
||||
"unsupported CHD version"
|
||||
};
|
||||
|
||||
static const char *chd_get_error_string(int chderr)
|
||||
{
|
||||
if ((chderr < 0 ) || (chderr >= ARRAY_LENGTH(error_strings)))
|
||||
return NULL;
|
||||
return error_strings[chderr];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static OPTION_GUIDE_START(mess_hd_option_guide)
|
||||
OPTION_INT('C', "cylinders", "Cylinders")
|
||||
OPTION_INT('H', "heads", "Heads")
|
||||
OPTION_INT('S', "sectors", "Sectors")
|
||||
OPTION_INT('L', "sectorlength", "Sector Bytes")
|
||||
OPTION_INT('K', "hunksize", "Hunk Bytes")
|
||||
OPTION_GUIDE_END
|
||||
|
||||
static const char *mess_hd_option_spec =
|
||||
"C1-[512]-1024;H1/2/[4]/8;S1-[16]-64;L128/256/[512]/1024;K512/1024/2048/[4096]";
|
||||
|
||||
|
||||
typedef struct _dev_harddisk_t dev_harddisk_t;
|
||||
struct _dev_harddisk_t
|
||||
{
|
||||
const struct harddisk_callback_config *config;
|
||||
chd_file *chd;
|
||||
hard_disk_file *hard_disk_handle;
|
||||
};
|
||||
|
||||
|
||||
INLINE dev_harddisk_t *get_safe_token(device_t *device)
|
||||
{
|
||||
assert( device != NULL );
|
||||
assert( ( device->type() == HARDDISK ) ||
|
||||
( device->type() == IDE_HARDDISK ) );
|
||||
return (dev_harddisk_t *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* DEVICE_IMAGE_LOAD(mess_hd)
|
||||
* DEVICE_IMAGE_CREATE(mess_hd)
|
||||
*
|
||||
* Device load and create
|
||||
*
|
||||
*************************************/
|
||||
|
||||
static int internal_load_mess_hd(device_image_interface &image, const char *metadata)
|
||||
{
|
||||
dev_harddisk_t *harddisk = get_safe_token( &image.device() );
|
||||
chd_error err = (chd_error)0;
|
||||
int is_writeable;
|
||||
|
||||
/* open the CHD file */
|
||||
do
|
||||
{
|
||||
is_writeable = image.is_writable();
|
||||
harddisk->chd = NULL;
|
||||
err = chd_open_file(image.image_core_file(), is_writeable ? CHD_OPEN_READWRITE : CHD_OPEN_READ, NULL, &harddisk->chd);
|
||||
|
||||
/* special case; if we get CHDERR_FILE_NOT_WRITEABLE, make the
|
||||
* image read only and repeat */
|
||||
if (err == CHDERR_FILE_NOT_WRITEABLE)
|
||||
image.make_readonly();
|
||||
}
|
||||
while(!harddisk->chd && is_writeable && (err == CHDERR_FILE_NOT_WRITEABLE));
|
||||
if (!harddisk->chd)
|
||||
goto done;
|
||||
|
||||
/* if we created the image and hence, have metadata to set, set the metadata */
|
||||
if (metadata)
|
||||
{
|
||||
err = chd_set_metadata(harddisk->chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
|
||||
if (err != CHDERR_NONE)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* open the hard disk file */
|
||||
harddisk->hard_disk_handle = hard_disk_open(harddisk->chd);
|
||||
if (!harddisk->hard_disk_handle)
|
||||
goto done;
|
||||
|
||||
done:
|
||||
if (err)
|
||||
{
|
||||
/* if we had an error, close out the CHD */
|
||||
if (harddisk->chd != NULL)
|
||||
{
|
||||
chd_close(harddisk->chd);
|
||||
harddisk->chd = NULL;
|
||||
}
|
||||
|
||||
image.seterror(IMAGE_ERROR_UNSPECIFIED, chd_get_error_string(err));
|
||||
}
|
||||
return err ? IMAGE_INIT_FAIL : IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static DEVICE_IMAGE_LOAD( mess_hd )
|
||||
{
|
||||
dev_harddisk_t *harddisk = get_safe_token( image );
|
||||
int our_result;
|
||||
|
||||
our_result = internal_load_mess_hd(image, NULL);
|
||||
|
||||
/* Check if there is an image_load callback defined */
|
||||
if ( harddisk->config && harddisk->config->device_image_load )
|
||||
{
|
||||
/* Let the override do some additional work/checks */
|
||||
our_result = harddisk->config->device_image_load( image );
|
||||
}
|
||||
return our_result;
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_IMAGE_CREATE( mess_hd )
|
||||
{
|
||||
int err;
|
||||
char metadata[256];
|
||||
UINT32 sectorsize, hunksize;
|
||||
UINT32 cylinders, heads, sectors, totalsectors;
|
||||
|
||||
cylinders = option_resolution_lookup_int(create_args, 'C');
|
||||
heads = option_resolution_lookup_int(create_args, 'H');
|
||||
sectors = option_resolution_lookup_int(create_args, 'S');
|
||||
sectorsize = option_resolution_lookup_int(create_args, 'L');
|
||||
hunksize = option_resolution_lookup_int(create_args, 'K');
|
||||
|
||||
totalsectors = cylinders * heads * sectors;
|
||||
|
||||
/* create the CHD file */
|
||||
err = chd_create_file(image.image_core_file(), (UINT64)totalsectors * (UINT64)sectorsize, hunksize, CHDCOMPRESSION_NONE, NULL);
|
||||
if (err != CHDERR_NONE)
|
||||
goto error;
|
||||
|
||||
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
|
||||
return internal_load_mess_hd(image, metadata);
|
||||
|
||||
error:
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* DEVICE_IMAGE_UNLOAD(mess_hd)
|
||||
*
|
||||
* Device unload
|
||||
*
|
||||
*************************************/
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( mess_hd )
|
||||
{
|
||||
dev_harddisk_t *harddisk = get_safe_token( image );
|
||||
|
||||
/* Check if there is an image_unload callback defined */
|
||||
if ( harddisk->config && harddisk->config->device_image_unload )
|
||||
{
|
||||
harddisk->config->device_image_unload( image );
|
||||
}
|
||||
|
||||
if (harddisk->hard_disk_handle != NULL)
|
||||
{
|
||||
hard_disk_close(harddisk->hard_disk_handle);
|
||||
harddisk->hard_disk_handle = NULL;
|
||||
}
|
||||
|
||||
if (harddisk->chd != NULL)
|
||||
{
|
||||
chd_close(harddisk->chd);
|
||||
harddisk->chd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Get the MESS/MAME hard disk handle (from the src/harddisk.c core)
|
||||
* after an image has been opened with the mess_hd core
|
||||
*
|
||||
*************************************/
|
||||
|
||||
hard_disk_file *mess_hd_get_hard_disk_file(device_t *device)
|
||||
{
|
||||
dev_harddisk_t *harddisk = get_safe_token( device );
|
||||
|
||||
return harddisk->hard_disk_handle;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
*
|
||||
* Get the MESS/MAME CHD file (from the src/chd.c core)
|
||||
* after an image has been opened with the mess_hd core
|
||||
*
|
||||
*************************************/
|
||||
|
||||
chd_file *mess_hd_get_chd_file(device_t *device)
|
||||
{
|
||||
chd_file *result = NULL;
|
||||
hard_disk_file *hd_file;
|
||||
|
||||
if (device)
|
||||
{
|
||||
hd_file = mess_hd_get_hard_disk_file(device);
|
||||
if (hd_file)
|
||||
result = hard_disk_get_chd(hd_file);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START(mess_hd)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START(mess_hd)
|
||||
{
|
||||
dev_harddisk_t *harddisk = get_safe_token( device );
|
||||
|
||||
harddisk->config = (const harddisk_callback_config*)device->baseconfig().static_config();
|
||||
harddisk->chd = NULL;
|
||||
harddisk->hard_disk_handle = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(mess_hd)
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(mess_hd)
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(dev_harddisk_t); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_HARDDISK; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_CREATE_OPTCOUNT: info->i = 1; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mess_hd); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(mess_hd); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(mess_hd); break;
|
||||
case DEVINFO_FCT_IMAGE_CREATE: info->f = (genf *) DEVICE_IMAGE_CREATE_NAME(mess_hd); break;
|
||||
case DEVINFO_PTR_IMAGE_CREATE_OPTGUIDE: info->p = (void *) mess_hd_option_guide; break;
|
||||
case DEVINFO_PTR_IMAGE_CREATE_OPTSPEC+0: info->p = (void *) mess_hd_option_spec; break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Harddisk"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Harddisk"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "chd,hd"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTNAME+0: strcpy(info->s, "chd"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTDESC+0: strcpy(info->s, "MAME/MESS CHD Hard drive"); break;
|
||||
case DEVINFO_STR_IMAGE_CREATE_OPTEXTS+0: strcpy(info->s, "chd,hd"); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_START(mess_ide)
|
||||
{
|
||||
/* old code from idedrive.c */
|
||||
#ifdef UNUSED_FUNCTION
|
||||
int which_bus, which_address;
|
||||
struct ide_interface *intf;
|
||||
device_start_func parent_init;
|
||||
|
||||
/* get the basics */
|
||||
ide_get_params(device, &which_bus, &which_address, &intf, &parent_init, NULL, NULL);
|
||||
|
||||
/* call the parent init function */
|
||||
parent_init(device);
|
||||
|
||||
/* configure IDE */
|
||||
/* FIXME IDE */
|
||||
/* ide_controller_init_custom(which_bus, intf, NULL); */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_IMAGE_LOAD(mess_ide)
|
||||
{
|
||||
/* old code from idedrive.c */
|
||||
#ifdef UNUSED_FUNCTION
|
||||
int result, which_bus, which_address;
|
||||
struct ide_interface *intf;
|
||||
device_image_load_func parent_load;
|
||||
|
||||
/* get the basics */
|
||||
ide_get_params(image, &which_bus, &which_address, &intf, NULL, &parent_load, NULL);
|
||||
|
||||
/* call the parent load function */
|
||||
result = parent_load(image);
|
||||
if (result != IMAGE_INIT_PASS)
|
||||
return result;
|
||||
|
||||
/* configure IDE */
|
||||
/* FIXME IDE */
|
||||
/* ide_controller_init_custom(which_bus, intf, mess_hd_get_chd_file(image)); */
|
||||
/* ide_controller_reset(which_bus); */
|
||||
return IMAGE_INIT_PASS;
|
||||
#endif
|
||||
return device_load_mess_hd( image );
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD(mess_ide)
|
||||
{
|
||||
/* old code from idedrive.c */
|
||||
#ifdef UNUSED_FUNCTION
|
||||
int which_bus, which_address;
|
||||
struct ide_interface *intf;
|
||||
device_image_unload_func parent_unload;
|
||||
|
||||
/* get the basics */
|
||||
ide_get_params(image, &which_bus, &which_address, &intf, NULL, NULL, &parent_unload);
|
||||
|
||||
/* call the parent unload function */
|
||||
parent_unload(image);
|
||||
|
||||
/* configure IDE */
|
||||
/* FIXME IDE */
|
||||
/* ide_controller_init_custom(which_bus, intf, NULL); */
|
||||
/* ide_controller_reset(which_bus); */
|
||||
#endif
|
||||
device_unload_mess_hd( image );
|
||||
}
|
||||
|
||||
|
||||
DEVICE_GET_INFO(mess_ide)
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mess_ide); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(mess_ide); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(mess_ide); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "IDE harddisk"); break;
|
||||
case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "ideharddrive"); break;
|
||||
case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "idehd"); break;
|
||||
|
||||
default: DEVICE_GET_INFO_CALL( mess_hd ); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(HARDDISK, mess_hd);
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(IDE_HARDDISK, mess_ide);
|
34
src/emu/imagedev/harddriv.h
Normal file
34
src/emu/imagedev/harddriv.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*********************************************************************
|
||||
|
||||
harddriv.h
|
||||
|
||||
MESS interface to the MAME CHD code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MESS_HD_H
|
||||
#define MESS_HD_H
|
||||
|
||||
#include "image.h"
|
||||
#include "harddisk.h"
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(HARDDISK, mess_hd);
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(IDE_HARDDISK, mess_ide);
|
||||
|
||||
#define MCFG_HARDDISK_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, HARDDISK, 0) \
|
||||
|
||||
#define MCFG_IDE_HARDDISK_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, IDE_HARDDISK, 0) \
|
||||
|
||||
hard_disk_file *mess_hd_get_hard_disk_file(device_t *device);
|
||||
chd_file *mess_hd_get_chd_file(device_t *device);
|
||||
|
||||
struct harddisk_callback_config
|
||||
{
|
||||
device_image_load_func device_image_load;
|
||||
device_image_unload_func device_image_unload;
|
||||
};
|
||||
|
||||
|
||||
#endif /* MESS_HD_H */
|
607
src/emu/imagedev/multcart.c
Normal file
607
src/emu/imagedev/multcart.c
Normal file
@ -0,0 +1,607 @@
|
||||
/*********************************************************************
|
||||
|
||||
multcart.c
|
||||
|
||||
Multi-cartridge handling code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "multcart.h"
|
||||
#include "pool.h"
|
||||
#include "unzip.h"
|
||||
#include "corestr.h"
|
||||
#include "xmlfile.h"
|
||||
#include "emu.h"
|
||||
#include "hash.h"
|
||||
#include "machine/ram.h"
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
struct _multicart_private
|
||||
{
|
||||
object_pool * pool;
|
||||
zip_file * zip;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _multicart_load_state multicart_load_state;
|
||||
struct _multicart_load_state
|
||||
{
|
||||
multicart_t * multicart;
|
||||
zip_file * zip;
|
||||
xml_data_node * layout_xml;
|
||||
xml_data_node * resources_node;
|
||||
xml_data_node * pcb_node;
|
||||
multicart_resource * resources;
|
||||
multicart_socket * sockets;
|
||||
};
|
||||
|
||||
static const char error_text[14][30] =
|
||||
{
|
||||
"no error",
|
||||
"not a multicart",
|
||||
"module definition corrupt",
|
||||
"out of memory",
|
||||
"xml format error",
|
||||
"invalid file reference",
|
||||
"zip file error",
|
||||
"missing ram length",
|
||||
"invalid ram specification",
|
||||
"unknown resource type",
|
||||
"invalid resource reference",
|
||||
"invalid file format",
|
||||
"missing layout",
|
||||
"no pcb or resource found"
|
||||
};
|
||||
|
||||
const char *multicart_error_text(multicart_open_error error)
|
||||
{
|
||||
return error_text[(int)error];
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
find_file
|
||||
-------------------------------------------------*/
|
||||
|
||||
static const zip_file_header *find_file(zip_file *zip, const char *filename)
|
||||
{
|
||||
const zip_file_header *header;
|
||||
for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
|
||||
{
|
||||
if (!core_stricmp(header->filename, filename))
|
||||
return header;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const zip_file_header *find_file_crc(zip_file *zip, const char *filename, UINT32 crc)
|
||||
{
|
||||
const zip_file_header *header;
|
||||
for (header = zip_file_first_file(zip); header != NULL; header = zip_file_next_file(zip))
|
||||
{
|
||||
// if the CRC and name both match, we're good
|
||||
// if the CRC matches and the name doesn't, we're still good
|
||||
if ((!core_stricmp(header->filename, filename)) && (header->crc == crc))
|
||||
{
|
||||
return header;
|
||||
}
|
||||
else if (header->crc == crc)
|
||||
{
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
find_pcb_and_resource_nodes
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int find_pcb_and_resource_nodes(xml_data_node *layout_xml,
|
||||
xml_data_node **pcb_node, xml_data_node **resource_node)
|
||||
{
|
||||
xml_data_node *romset_node;
|
||||
xml_data_node *configuration_node;
|
||||
|
||||
*pcb_node = NULL;
|
||||
*resource_node = NULL;
|
||||
|
||||
romset_node = xml_get_sibling(layout_xml->child, "romset");
|
||||
if (romset_node == NULL)
|
||||
return FALSE;
|
||||
|
||||
configuration_node = xml_get_sibling(romset_node->child, "configuration");
|
||||
if (configuration_node == NULL)
|
||||
return FALSE;
|
||||
|
||||
*pcb_node = xml_get_sibling(configuration_node->child, "pcb");
|
||||
if (*pcb_node == NULL)
|
||||
return FALSE;
|
||||
|
||||
*resource_node = xml_get_sibling(romset_node->child, "resources");
|
||||
if (*resource_node == NULL)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_resource_type
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_resource_type get_resource_type(const char *s)
|
||||
{
|
||||
multicart_resource_type result;
|
||||
if (!strcmp(s, "rom"))
|
||||
result = MULTICART_RESOURCE_TYPE_ROM;
|
||||
else if (!strcmp(s, "ram"))
|
||||
result = MULTICART_RESOURCE_TYPE_RAM;
|
||||
else
|
||||
result = MULTICART_RESOURCE_TYPE_INVALID;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_rom_resource
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_rom_resource(multicart_load_state *state, xml_data_node *resource_node,
|
||||
multicart_resource *resource)
|
||||
{
|
||||
const char *file, *crcstr, *sha1;
|
||||
const zip_file_header *header;
|
||||
zip_error ziperr;
|
||||
UINT32 crc;
|
||||
|
||||
/* locate the 'file' attribute */
|
||||
file = xml_get_attribute_string(resource_node, "file", NULL);
|
||||
if (file == NULL)
|
||||
return MCERR_XML_ERROR;
|
||||
|
||||
if (!(crcstr = xml_get_attribute_string(resource_node, "crc", NULL)))
|
||||
{
|
||||
/* locate the file in the ZIP file */
|
||||
header = find_file(state->zip, file);
|
||||
}
|
||||
else /* CRC tag is present, use it */
|
||||
{
|
||||
crc = strtoul(crcstr, NULL, 16);
|
||||
header = find_file_crc(state->zip, file, crc);
|
||||
}
|
||||
if (header == NULL)
|
||||
return MCERR_INVALID_FILE_REF;
|
||||
resource->length = header->uncompressed_length;
|
||||
|
||||
/* allocate bytes for this resource */
|
||||
resource->ptr = pool_malloc_lib(state->multicart->data->pool, resource->length);
|
||||
if (resource->ptr == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
/* and decompress it */
|
||||
ziperr = zip_file_decompress(state->zip, resource->ptr, resource->length);
|
||||
if (ziperr != ZIPERR_NONE)
|
||||
return MCERR_ZIP_ERROR;
|
||||
|
||||
/* check SHA1 now */
|
||||
if ((sha1 = xml_get_attribute_string(resource_node, "sha1", NULL)))
|
||||
{
|
||||
char calc_sha[256];
|
||||
|
||||
memset(calc_sha, 0, sizeof(calc_sha));
|
||||
hash_compute(&calc_sha[0], (const unsigned char*)resource->ptr, resource->length, HASH_SHA1);
|
||||
|
||||
if ((strncmp(sha1, &calc_sha[2], 20)))
|
||||
{
|
||||
return MCERR_INVALID_FILE_REF;
|
||||
}
|
||||
}
|
||||
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_ram_resource
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_ram_resource(multicart_load_state *state, xml_data_node *resource_node,
|
||||
multicart_resource *resource)
|
||||
{
|
||||
const char *length_string;
|
||||
const char *ram_type;
|
||||
const char *ram_filename;
|
||||
|
||||
astring *ram_pathname;
|
||||
|
||||
/* locate the 'length' attribute */
|
||||
length_string = xml_get_attribute_string(resource_node, "length", NULL);
|
||||
if (length_string == NULL)
|
||||
return MCERR_MISSING_RAM_LENGTH;
|
||||
|
||||
/* ...and parse it */
|
||||
resource->length = ram_parse_string(length_string);
|
||||
if (resource->length <= 0)
|
||||
return MCERR_INVALID_RAM_SPEC;
|
||||
|
||||
/* allocate bytes for this resource */
|
||||
resource->ptr = pool_malloc_lib(state->multicart->data->pool, resource->length);
|
||||
if (resource->ptr == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
/* Is this a persistent RAM resource? Then try to load it. */
|
||||
ram_type = xml_get_attribute_string(resource_node, "type", NULL);
|
||||
if (ram_type != NULL)
|
||||
{
|
||||
if (strcmp(ram_type, "persistent")==0)
|
||||
{
|
||||
astring tmp;
|
||||
|
||||
/* Get the file name. */
|
||||
ram_filename = xml_get_attribute_string(resource_node, "file", NULL);
|
||||
if (ram_filename==NULL)
|
||||
return MCERR_XML_ERROR;
|
||||
|
||||
ram_pathname = astring_assemble_3(&tmp, state->multicart->gamedrv_name, PATH_SEPARATOR, ram_filename);
|
||||
|
||||
/* Save the file name so that we can write the contents on unloading.
|
||||
If the RAM resource has no filename, we know that it was volatile only. */
|
||||
resource->filename = pool_strdup_lib(state->multicart->data->pool, astring_c(ram_pathname));
|
||||
|
||||
if (resource->filename == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
image_battery_load_by_name(resource->filename, resource->ptr, resource->length, 0x00);
|
||||
}
|
||||
/* else this type is volatile, in which case we just have
|
||||
a memory expansion */
|
||||
}
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_resource
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_resource(multicart_load_state *state, xml_data_node *resource_node,
|
||||
multicart_resource_type resource_type)
|
||||
{
|
||||
const char *id;
|
||||
multicart_open_error err;
|
||||
multicart_resource *resource;
|
||||
multicart_resource **next_resource;
|
||||
|
||||
/* get the 'id' attribute; error if not present */
|
||||
id = xml_get_attribute_string(resource_node, "id", NULL);
|
||||
if (id == NULL)
|
||||
return MCERR_XML_ERROR;
|
||||
|
||||
/* allocate memory for the resource */
|
||||
resource = (multicart_resource *)pool_malloc_lib(state->multicart->data->pool, sizeof(*resource));
|
||||
if (resource == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
memset(resource, 0, sizeof(*resource));
|
||||
resource->type = resource_type;
|
||||
|
||||
/* copy id */
|
||||
resource->id = pool_strdup_lib(state->multicart->data->pool, id);
|
||||
if (resource->id == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
switch(resource->type)
|
||||
{
|
||||
case MULTICART_RESOURCE_TYPE_ROM:
|
||||
err = load_rom_resource(state, resource_node, resource);
|
||||
if (err != MCERR_NONE)
|
||||
return err;
|
||||
break;
|
||||
|
||||
case MULTICART_RESOURCE_TYPE_RAM:
|
||||
err = load_ram_resource(state, resource_node, resource);
|
||||
if (err != MCERR_NONE)
|
||||
return err;
|
||||
break;
|
||||
|
||||
default:
|
||||
return MCERR_UNKNOWN_RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
/* append the resource */
|
||||
for (next_resource = &state->resources; *next_resource; next_resource = &(*next_resource)->next)
|
||||
;
|
||||
*next_resource = resource;
|
||||
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_all_resources
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_all_resources(multicart_load_state *state)
|
||||
{
|
||||
multicart_open_error err;
|
||||
xml_data_node *resource_node;
|
||||
multicart_resource_type resource_type;
|
||||
|
||||
for (resource_node = state->resources_node->child; resource_node != NULL; resource_node = resource_node->next)
|
||||
{
|
||||
resource_type = get_resource_type(resource_node->name);
|
||||
if (resource_type != MULTICART_RESOURCE_TYPE_INVALID)
|
||||
{
|
||||
err = load_resource(state, resource_node, resource_type);
|
||||
if (err != MCERR_NONE)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
state->multicart->resources = state->resources;
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
save_ram_resources. This is important for persistent RAM. All
|
||||
resources were allocated within the memory pool of this device and will
|
||||
be freed on multicart_close.
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error save_ram_resources(multicart_t *cart)
|
||||
{
|
||||
const multicart_resource *resource;
|
||||
|
||||
for (resource = cart->resources; resource != NULL; resource = resource->next)
|
||||
{
|
||||
if ((resource->type == MULTICART_RESOURCE_TYPE_RAM) && (resource->filename != NULL))
|
||||
{
|
||||
image_battery_save_by_name(resource->filename, resource->ptr, resource->length);
|
||||
}
|
||||
}
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_socket
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_socket(multicart_load_state *state, xml_data_node *socket_node)
|
||||
{
|
||||
const char *id;
|
||||
const char *uses;
|
||||
const multicart_resource *resource;
|
||||
multicart_socket *socket;
|
||||
multicart_socket **next_socket;
|
||||
|
||||
/* get the 'id' and 'uses' attributes; error if not present */
|
||||
id = xml_get_attribute_string(socket_node, "id", NULL);
|
||||
uses = xml_get_attribute_string(socket_node, "uses", NULL);
|
||||
if ((id == NULL) || (uses == NULL))
|
||||
return MCERR_XML_ERROR;
|
||||
|
||||
/* find the resource */
|
||||
for (resource = state->multicart->resources; resource != NULL; resource = resource->next)
|
||||
{
|
||||
if (!strcmp(uses, resource->id))
|
||||
break;
|
||||
}
|
||||
if (resource == NULL)
|
||||
return MCERR_INVALID_RESOURCE_REF;
|
||||
|
||||
/* create the socket */
|
||||
socket = (multicart_socket *)pool_malloc_lib(state->multicart->data->pool, sizeof(*socket));
|
||||
if (socket == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
memset(socket, 0, sizeof(*socket));
|
||||
socket->resource = resource;
|
||||
socket->ptr = resource->ptr;
|
||||
|
||||
/* copy id */
|
||||
socket->id = pool_strdup_lib(state->multicart->data->pool, id);
|
||||
if (socket->id == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
/* which pointer should I use? */
|
||||
if (resource->ptr != NULL)
|
||||
{
|
||||
/* use the resource's ptr */
|
||||
socket->ptr = resource->ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* allocate bytes for this socket */
|
||||
socket->ptr = pool_malloc_lib(state->multicart->data->pool, resource->length);
|
||||
if (socket->ptr == NULL)
|
||||
return MCERR_OUT_OF_MEMORY;
|
||||
|
||||
/* ...and clear it */
|
||||
memset(socket->ptr, 0xCD, resource->length);
|
||||
}
|
||||
|
||||
/* append the resource */
|
||||
for (next_socket = &state->sockets; *next_socket; next_socket = &(*next_socket)->next)
|
||||
;
|
||||
*next_socket = socket;
|
||||
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_all_sockets
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_all_sockets(multicart_load_state *state)
|
||||
{
|
||||
multicart_open_error err;
|
||||
xml_data_node *socket_node;
|
||||
|
||||
for (socket_node = xml_get_sibling(state->pcb_node->child, "socket"); socket_node != NULL;
|
||||
socket_node = xml_get_sibling(socket_node->next, "socket"))
|
||||
{
|
||||
err = load_socket(state, socket_node);
|
||||
if (err != MCERR_NONE)
|
||||
return err;
|
||||
}
|
||||
|
||||
state->multicart->sockets = state->sockets;
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
multicart_open - opens a multicart
|
||||
-------------------------------------------------*/
|
||||
|
||||
multicart_open_error multicart_open(const char *filename, const char *gamedrv, multicart_load_flags load_flags, multicart_t **cart)
|
||||
{
|
||||
multicart_open_error err;
|
||||
zip_error ziperr;
|
||||
object_pool *pool;
|
||||
multicart_load_state state = {0, };
|
||||
const zip_file_header *header;
|
||||
const char *pcb_type;
|
||||
char *layout_text = NULL;
|
||||
|
||||
/* allocate an object pool */
|
||||
pool = pool_alloc_lib(NULL);
|
||||
if (pool == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* allocate the multicart */
|
||||
state.multicart = (multicart_t*)pool_malloc_lib(pool, sizeof(*state.multicart));
|
||||
if (state.multicart == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
memset(state.multicart, 0, sizeof(*state.multicart));
|
||||
|
||||
/* allocate the multicart's private data */
|
||||
state.multicart->data = (multicart_private*)pool_malloc_lib(pool, sizeof(*state.multicart->data));
|
||||
if (state.multicart->data == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
memset(state.multicart->data, 0, sizeof(*state.multicart->data));
|
||||
state.multicart->data->pool = pool;
|
||||
pool = NULL;
|
||||
|
||||
/* open the ZIP file */
|
||||
ziperr = zip_file_open(filename, &state.zip);
|
||||
if (ziperr != ZIPERR_NONE)
|
||||
{
|
||||
err = MCERR_NOT_MULTICART;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* find the layout.xml file */
|
||||
header = find_file(state.zip, "layout.xml");
|
||||
if (header == NULL)
|
||||
{
|
||||
err = MCERR_MISSING_LAYOUT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* reserve space for the layout text */
|
||||
layout_text = (char*)malloc(header->uncompressed_length + 1);
|
||||
if (layout_text == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* uncompress the layout text */
|
||||
ziperr = zip_file_decompress(state.zip, layout_text, header->uncompressed_length);
|
||||
if (ziperr != ZIPERR_NONE)
|
||||
{
|
||||
err = MCERR_ZIP_ERROR;
|
||||
goto done;
|
||||
}
|
||||
layout_text[header->uncompressed_length] = '\0';
|
||||
|
||||
/* parse the layout text */
|
||||
state.layout_xml = xml_string_read(layout_text, NULL);
|
||||
if (state.layout_xml == NULL)
|
||||
{
|
||||
err = MCERR_XML_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* locate the PCB node */
|
||||
if (!find_pcb_and_resource_nodes(state.layout_xml, &state.pcb_node, &state.resources_node))
|
||||
{
|
||||
err = MCERR_NO_PCB_OR_RESOURCES;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* get the PCB resource_type */
|
||||
pcb_type = xml_get_attribute_string(state.pcb_node, "type", "");
|
||||
state.multicart->pcb_type = pool_strdup_lib(state.multicart->data->pool, pcb_type);
|
||||
if (state.multicart->pcb_type == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
state.multicart->gamedrv_name = pool_strdup_lib(state.multicart->data->pool, gamedrv);
|
||||
if (state.multicart->gamedrv_name == NULL)
|
||||
{
|
||||
err = MCERR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* do we have to load resources? */
|
||||
if (load_flags & MULTICART_FLAGS_LOAD_RESOURCES)
|
||||
{
|
||||
err = load_all_resources(&state);
|
||||
if (err != MCERR_NONE)
|
||||
goto done;
|
||||
|
||||
err = load_all_sockets(&state);
|
||||
if (err != MCERR_NONE)
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = MCERR_NONE;
|
||||
|
||||
done:
|
||||
if (pool != NULL)
|
||||
pool_free_lib(pool);
|
||||
if (state.zip != NULL)
|
||||
zip_file_close(state.zip);
|
||||
if (layout_text != NULL)
|
||||
free(layout_text);
|
||||
if (state.layout_xml != NULL)
|
||||
xml_file_free(state.layout_xml);
|
||||
|
||||
if ((err != MCERR_NONE) && (state.multicart != NULL))
|
||||
{
|
||||
multicart_close(state.multicart);
|
||||
state.multicart = NULL;
|
||||
}
|
||||
*cart = state.multicart;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
multicart_close - closes a multicart
|
||||
-------------------------------------------------*/
|
||||
|
||||
void multicart_close(multicart_t *cart)
|
||||
{
|
||||
save_ram_resources(cart);
|
||||
pool_free_lib(cart->data->pool);
|
||||
}
|
100
src/emu/imagedev/multcart.h
Normal file
100
src/emu/imagedev/multcart.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*********************************************************************
|
||||
|
||||
multcart.h
|
||||
|
||||
Multi-cartridge handling code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __MULTCART_H__
|
||||
#define __MULTCART_H__
|
||||
|
||||
#include "osdcore.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
enum _multicart_load_flags
|
||||
{
|
||||
MULTICART_FLAGS_DONT_LOAD_RESOURCES = 0x00,
|
||||
MULTICART_FLAGS_LOAD_RESOURCES = 0x01
|
||||
};
|
||||
typedef enum _multicart_load_flags multicart_load_flags;
|
||||
|
||||
enum _multicart_resource_type
|
||||
{
|
||||
MULTICART_RESOURCE_TYPE_INVALID,
|
||||
MULTICART_RESOURCE_TYPE_ROM,
|
||||
MULTICART_RESOURCE_TYPE_RAM
|
||||
};
|
||||
typedef enum _multicart_resource_type multicart_resource_type;
|
||||
|
||||
typedef struct _multicart_resource multicart_resource;
|
||||
struct _multicart_resource
|
||||
{
|
||||
const char * id;
|
||||
const char * filename;
|
||||
multicart_resource * next;
|
||||
multicart_resource_type type;
|
||||
UINT32 length;
|
||||
void * ptr;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _multicart_socket multicart_socket;
|
||||
struct _multicart_socket
|
||||
{
|
||||
const char * id;
|
||||
multicart_socket * next;
|
||||
const multicart_resource * resource;
|
||||
void * ptr;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _multicart_private multicart_private;
|
||||
|
||||
typedef struct _multicart_t multicart_t;
|
||||
struct _multicart_t
|
||||
{
|
||||
const multicart_resource * resources;
|
||||
const multicart_socket * sockets;
|
||||
const char * pcb_type;
|
||||
const char * gamedrv_name; /* need this to find the path to the nvram files */
|
||||
multicart_private * data;
|
||||
};
|
||||
|
||||
|
||||
enum _multicart_open_error
|
||||
{
|
||||
MCERR_NONE,
|
||||
MCERR_NOT_MULTICART,
|
||||
MCERR_CORRUPT,
|
||||
MCERR_OUT_OF_MEMORY,
|
||||
MCERR_XML_ERROR,
|
||||
MCERR_INVALID_FILE_REF,
|
||||
MCERR_ZIP_ERROR,
|
||||
MCERR_MISSING_RAM_LENGTH,
|
||||
MCERR_INVALID_RAM_SPEC,
|
||||
MCERR_UNKNOWN_RESOURCE_TYPE,
|
||||
MCERR_INVALID_RESOURCE_REF,
|
||||
MCERR_INVALID_FILE_FORMAT,
|
||||
MCERR_MISSING_LAYOUT,
|
||||
MCERR_NO_PCB_OR_RESOURCES
|
||||
};
|
||||
typedef enum _multicart_open_error multicart_open_error;
|
||||
|
||||
const char *multicart_error_text(multicart_open_error error);
|
||||
|
||||
/***************************************************************************
|
||||
PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* opens a multicart */
|
||||
multicart_open_error multicart_open(const char *filename, const char *drvname, multicart_load_flags load_flags, multicart_t **cart);
|
||||
|
||||
/* closes a multicart */
|
||||
void multicart_close(multicart_t *cart);
|
||||
|
||||
#endif /* __MULTCART_H__ */
|
116
src/emu/imagedev/printer.c
Normal file
116
src/emu/imagedev/printer.c
Normal file
@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
|
||||
printer.c
|
||||
|
||||
Code for handling printer devices
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "printer.h"
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
printer_is_ready - checks to see if a printer
|
||||
is ready
|
||||
-------------------------------------------------*/
|
||||
|
||||
int printer_is_ready(device_t *printer)
|
||||
{
|
||||
device_image_interface *image = dynamic_cast<device_image_interface *>(printer);
|
||||
/* if there is a file attached to it, it's online */
|
||||
return image->exists() != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
printer_output - outputs data to a printer
|
||||
-------------------------------------------------*/
|
||||
|
||||
void printer_output(device_t *printer, UINT8 data)
|
||||
{
|
||||
device_image_interface *image = dynamic_cast<device_image_interface *>(printer);
|
||||
if (image->exists())
|
||||
{
|
||||
image->fwrite(&data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_LOAD( printer )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_LOAD( printer )
|
||||
{
|
||||
const printer_config *conf = (const printer_config *)downcast<const legacy_image_device_config_base &>(image.device().baseconfig()).inline_config();
|
||||
|
||||
/* send notify that the printer is now online */
|
||||
if (conf != NULL && conf->online != NULL)
|
||||
conf->online(image, TRUE);
|
||||
|
||||
/* we don't need to do anything special */
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_UNLOAD( printer )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( printer )
|
||||
{
|
||||
const printer_config *conf = (const printer_config *)downcast<const legacy_image_device_config_base &>(image.device().baseconfig()).inline_config();
|
||||
|
||||
/* send notify that the printer is now offline */
|
||||
if (conf != NULL && conf->online != NULL)
|
||||
conf->online(image, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START(printer)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START(printer)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(printer)
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(printer)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = 1; break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(printer_config); break;
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_PRINTER; break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to data or functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(printer); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(printer); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(printer); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Printer"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Printer"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "prn"); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(PRINTER, printer);
|
48
src/emu/imagedev/printer.h
Normal file
48
src/emu/imagedev/printer.h
Normal file
@ -0,0 +1,48 @@
|
||||
/****************************************************************************
|
||||
|
||||
printer.h
|
||||
|
||||
Code for handling printer devices
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __PRINTER_H__
|
||||
#define __PRINTER_H__
|
||||
|
||||
#include "image.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef void (*online_func)(device_t *device, int state);
|
||||
|
||||
typedef struct _printer_config printer_config;
|
||||
struct _printer_config
|
||||
{
|
||||
online_func online;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(PRINTER, printer);
|
||||
|
||||
|
||||
#define MCFG_PRINTER_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, PRINTER, 0) \
|
||||
|
||||
#define MCFG_PRINTER_ONLINE(_online) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(printer_config, online, _online)
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
/* checks to see if a printer is ready */
|
||||
int printer_is_ready(device_t *printer);
|
||||
|
||||
/* outputs data to a printer */
|
||||
void printer_output(device_t *printer, UINT8 data);
|
||||
|
||||
#endif /* __PRINTER_H__ */
|
373
src/emu/imagedev/snapquik.c
Normal file
373
src/emu/imagedev/snapquik.c
Normal file
@ -0,0 +1,373 @@
|
||||
/*********************************************************************
|
||||
|
||||
snapquik.h
|
||||
|
||||
Snapshots and quickloads
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "snapquik.h"
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct _snapquick_token snapquick_token;
|
||||
struct _snapquick_token
|
||||
{
|
||||
emu_timer *timer;
|
||||
snapquick_load_func load;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
assert_is_snapshot_or_quickload - asserts/confirms
|
||||
that a given device is a snapshot or quickload
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE void assert_is_snapshot_or_quickload(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config() != NULL);
|
||||
assert((device->type() == SNAPSHOT) || (device->type() == QUICKLOAD)
|
||||
|| (device->type() == Z80BIN));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_token - safely gets the snapshot/quickload data
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE snapquick_token *get_token(device_t *device)
|
||||
{
|
||||
assert_is_snapshot_or_quickload(device);
|
||||
return (snapquick_token *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_config - safely gets the quickload config
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE const snapquick_config *get_config(device_t *device)
|
||||
{
|
||||
assert_is_snapshot_or_quickload(device);
|
||||
return (const snapquick_config *) downcast<const legacy_device_config_base &>(device->baseconfig()).inline_config();
|
||||
}
|
||||
|
||||
INLINE const snapquick_config *get_config_dev(const device_config *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert((device->type() == SNAPSHOT) || (device->type() == QUICKLOAD)
|
||||
|| (device->type() == Z80BIN));
|
||||
return (const snapquick_config *) downcast<const legacy_device_config_base *>(device)->inline_config();
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
log_quickload - logs and displays useful
|
||||
data for the end user
|
||||
-------------------------------------------------*/
|
||||
|
||||
void log_quickload(const char *type, UINT32 start, UINT32 length, UINT32 exec, const char *exec_format)
|
||||
{
|
||||
astring tempstring;
|
||||
|
||||
logerror("Loading %04X bytes of RAM at %04X\n", length, start);
|
||||
|
||||
tempstring.catprintf("Quickload type: %s Length: %d bytes\n", type, length);
|
||||
tempstring.catprintf("Start: 0x%04X End: 0x%04X Exec: ", start, start + length - 1);
|
||||
|
||||
logerror("Quickload loaded.\n");
|
||||
if (!mame_stricmp(exec_format, EXEC_NA))
|
||||
tempstring.cat("N/A");
|
||||
else
|
||||
{
|
||||
logerror("Execution can resume with ");
|
||||
logerror(exec_format, exec);
|
||||
logerror("\n");
|
||||
tempstring.catprintf(exec_format, exec);
|
||||
}
|
||||
|
||||
ui_popup_time(10, "%s", tempstring.cstr());
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
TIMER_CALLBACK(process_snapshot_or_quickload)
|
||||
-------------------------------------------------*/
|
||||
|
||||
static TIMER_CALLBACK(process_snapshot_or_quickload)
|
||||
{
|
||||
device_image_interface *image = (device_image_interface *) ptr;
|
||||
snapquick_token *token = get_token(&image->device());
|
||||
|
||||
/* invoke the load */
|
||||
(*token->load)(*image,
|
||||
image->filetype(),
|
||||
image->length());
|
||||
|
||||
/* unload the device */
|
||||
image->unload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START( snapquick )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START( snapquick )
|
||||
{
|
||||
snapquick_token *token = get_token(device);
|
||||
|
||||
/* allocate a timer */
|
||||
token->timer = timer_alloc(device->machine, process_snapshot_or_quickload, (void *) dynamic_cast<device_image_interface *>(device));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_LOAD( snapquick )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_LOAD( snapquick )
|
||||
{
|
||||
const snapquick_config *config = get_config(image);
|
||||
snapquick_token *token = get_token(image);
|
||||
|
||||
/* locate the load function */
|
||||
token->load = (snapquick_load_func) reinterpret_cast<snapquick_load_func>(image.get_device_specific_call());
|
||||
|
||||
/* adjust the timer */
|
||||
timer_adjust_oneshot(
|
||||
token->timer,
|
||||
attotime_make(config->delay_seconds, config->delay_attoseconds),
|
||||
0);
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(snapquick) - device getinfo
|
||||
function
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_GET_INFO(snapquick)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(snapquick_token); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(snapquick_config); break;
|
||||
case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break;
|
||||
case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 0; break;
|
||||
case DEVINFO_INT_IMAGE_CREATABLE: info->i = 0; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(snapquick); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(snapquick); break;
|
||||
case DEVINFO_FCT_SNAPSHOT_QUICKLOAD_LOAD: info->f = (genf *) get_config_dev(device)->load; break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, get_config_dev(device)->file_extensions); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(snapshot) - device getinfo
|
||||
function
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(snapshot)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_SNAPSHOT; break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Snapshot"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Snapshot"); break;
|
||||
|
||||
default: DEVICE_GET_INFO_CALL(snapquick); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(quickload) - device getinfo
|
||||
function
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(quickload)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_IMAGE_TYPE: info->i = IO_QUICKLOAD; break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Quickload"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "Quickload"); break;
|
||||
|
||||
default: DEVICE_GET_INFO_CALL(snapquick); break;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------
|
||||
z80bin_load_file - load a z80bin file into
|
||||
memory
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int z80bin_load_file(device_image_interface *image, const char *file_type, UINT16 *exec_addr, UINT16 *start_addr, UINT16 *end_addr )
|
||||
{
|
||||
int ch;
|
||||
UINT16 args[3];
|
||||
UINT16 i=0, j, size;
|
||||
UINT8 data;
|
||||
char pgmname[256];
|
||||
char message[256];
|
||||
|
||||
image->fseek(7, SEEK_SET);
|
||||
|
||||
while((ch = image->fgetc()) != 0x1A)
|
||||
{
|
||||
if (ch == EOF)
|
||||
{
|
||||
image->seterror(IMAGE_ERROR_INVALIDIMAGE, "Unexpected EOF while getting file name");
|
||||
image->message(" Unexpected EOF while getting file name");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
if (ch != '\0')
|
||||
{
|
||||
if (i >= (ARRAY_LENGTH(pgmname) - 1))
|
||||
{
|
||||
image->seterror(IMAGE_ERROR_INVALIDIMAGE, "File name too long");
|
||||
image->message(" File name too long");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
pgmname[i] = ch; /* build program name */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
pgmname[i] = '\0'; /* terminate string with a null */
|
||||
|
||||
if (image->fread(args, sizeof(args)) != sizeof(args))
|
||||
{
|
||||
image->seterror(IMAGE_ERROR_INVALIDIMAGE, "Unexpected EOF while getting file size");
|
||||
image->message(" Unexpected EOF while getting file size");
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
|
||||
exec_addr[0] = LITTLE_ENDIANIZE_INT16(args[0]);
|
||||
start_addr[0] = LITTLE_ENDIANIZE_INT16(args[1]);
|
||||
end_addr[0] = LITTLE_ENDIANIZE_INT16(args[2]);
|
||||
|
||||
size = (end_addr[0] - start_addr[0] + 1) & 0xffff;
|
||||
|
||||
/* display a message about the loaded quickload */
|
||||
image->message(" %s\nsize=%04X : start=%04X : end=%04X : exec=%04X",pgmname,size,start_addr[0],end_addr[0],exec_addr[0]);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
j = (start_addr[0] + i) & 0xffff;
|
||||
if (image->fread(&data, 1) != 1)
|
||||
{
|
||||
snprintf(message, ARRAY_LENGTH(message), "%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j);
|
||||
image->seterror(IMAGE_ERROR_INVALIDIMAGE, message);
|
||||
image->message("%s: Unexpected EOF while writing byte to %04X", pgmname, (unsigned) j);
|
||||
return IMAGE_INIT_FAIL;
|
||||
}
|
||||
cputag_get_address_space(image->device().machine,"maincpu",ADDRESS_SPACE_PROGRAM)->write_byte(j, data);
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
QUICKLOAD_LOAD( z80bin )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static QUICKLOAD_LOAD( z80bin )
|
||||
{
|
||||
const z80bin_config *config;
|
||||
UINT16 exec_addr, start_addr, end_addr;
|
||||
int autorun;
|
||||
|
||||
/* load the binary into memory */
|
||||
if (z80bin_load_file(&image, file_type, &exec_addr, &start_addr, &end_addr) == IMAGE_INIT_FAIL)
|
||||
return IMAGE_INIT_FAIL;
|
||||
|
||||
/* is this file executable? */
|
||||
if (exec_addr != 0xffff)
|
||||
{
|
||||
config = (const z80bin_config *)downcast<const legacy_device_config_base &>(image.device().baseconfig()).inline_config();
|
||||
|
||||
/* check to see if autorun is on (I hate how this works) */
|
||||
autorun = input_port_read_safe(image.device().machine, "CONFIG", 0xFF) & 1;
|
||||
|
||||
/* start program */
|
||||
if (config->execute != NULL)
|
||||
{
|
||||
(*config->execute)(image.device().machine, start_addr, end_addr, exec_addr, autorun);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (autorun)
|
||||
cpu_set_reg(image.device().machine->device("maincpu"), STATE_GENPC, exec_addr);
|
||||
}
|
||||
}
|
||||
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO(z80bin)
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO(z80bin)
|
||||
{
|
||||
/* quickload */
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(z80bin_config); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "bin"); break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to functions --- */
|
||||
case DEVINFO_FCT_SNAPSHOT_QUICKLOAD_LOAD: info->f = (genf *) quickload_load_z80bin; break;
|
||||
|
||||
default: DEVICE_GET_INFO_CALL(quickload); break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(Z80BIN, z80bin);
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(SNAPSHOT, snapshot);
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(QUICKLOAD, quickload);
|
115
src/emu/imagedev/snapquik.h
Normal file
115
src/emu/imagedev/snapquik.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*********************************************************************
|
||||
|
||||
snapquik.h
|
||||
|
||||
Snapshots and quickloads
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __SNAPQUIK_H__
|
||||
#define __SNAPQUIK_H__
|
||||
|
||||
#include "image.h"
|
||||
#include "ui.h"
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CONSTANTS
|
||||
***************************************************************************/
|
||||
|
||||
enum
|
||||
{
|
||||
DEVINFO_FCT_SNAPSHOT_QUICKLOAD_LOAD = DEVINFO_FCT_DEVICE_SPECIFIC
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
MACROS
|
||||
***************************************************************************/
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(SNAPSHOT, snapshot);
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(QUICKLOAD, quickload);
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(Z80BIN, z80bin);
|
||||
|
||||
#define SNAPSHOT_LOAD_NAME(name) snapshot_load_##name
|
||||
#define SNAPSHOT_LOAD(name) int SNAPSHOT_LOAD_NAME(name)(device_image_interface &image, const char *file_type, int snapshot_size)
|
||||
|
||||
#define QUICKLOAD_LOAD_NAME(name) quickload_load_##name
|
||||
#define QUICKLOAD_LOAD(name) int QUICKLOAD_LOAD_NAME(name)(device_image_interface &image, const char *file_type, int quickload_size)
|
||||
|
||||
#define Z80BIN_EXECUTE_NAME(name) z80bin_execute_##name
|
||||
#define Z80BIN_EXECUTE(name) void Z80BIN_EXECUTE_NAME(name)(running_machine *machine, UINT16 start_address, UINT16 end_address, UINT16 execute_address, int autorun)
|
||||
|
||||
#define LOAD_REG(_cpu, _reg, _data) \
|
||||
do { \
|
||||
cpu_set_reg(_cpu, _reg, (_data)); \
|
||||
} while (0)
|
||||
|
||||
#define EXEC_NA "N/A"
|
||||
#define z80bin_execute_default NULL
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
typedef int (*snapquick_load_func)(device_image_interface &image, const char *file_type, int file_size);
|
||||
|
||||
typedef struct _snapquick_config snapquick_config;
|
||||
struct _snapquick_config
|
||||
{
|
||||
snapquick_load_func load; /* loading function */
|
||||
const char * file_extensions; /* file extensions */
|
||||
seconds_t delay_seconds; /* loading delay (seconds) */
|
||||
attoseconds_t delay_attoseconds; /* loading delay (attoseconds) */
|
||||
};
|
||||
|
||||
typedef void (*z80bin_execute_func)(running_machine *machine, UINT16 start_address, UINT16 end_address, UINT16 execute_address, int autorun);
|
||||
|
||||
typedef struct _z80bin_config z80bin_config;
|
||||
struct _z80bin_config
|
||||
{
|
||||
snapquick_config base;
|
||||
z80bin_execute_func execute;
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
SNAPSHOT DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_SNAPSHOT_ADD(_tag, _load, _file_extensions, _delay) \
|
||||
MCFG_DEVICE_ADD(_tag, SNAPSHOT, 0) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(snapquick_config, load, SNAPSHOT_LOAD_NAME(_load)) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(snapquick_config, file_extensions, _file_extensions) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_seconds, (seconds_t) (_delay)) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_attoseconds, (attoseconds_t) (((_delay) - (int)(_delay)) * ATTOSECONDS_PER_SECOND)) \
|
||||
|
||||
/***************************************************************************
|
||||
QUICKLOAD DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_QUICKLOAD_ADD(_tag, _load, _file_extensions, _delay) \
|
||||
MCFG_DEVICE_ADD(_tag, QUICKLOAD, 0) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(snapquick_config, load, QUICKLOAD_LOAD_NAME(_load)) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(snapquick_config, file_extensions, _file_extensions) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_seconds, (seconds_t) (_delay)) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_attoseconds, (attoseconds_t) (((_delay) - (int)(_delay)) * ATTOSECONDS_PER_SECOND)) \
|
||||
|
||||
/***************************************************************************
|
||||
Z80BIN QUICKLOAD DEVICE CONFIGURATION MACROS
|
||||
***************************************************************************/
|
||||
|
||||
#define MCFG_Z80BIN_QUICKLOAD_ADD(_tag, _execute, _delay) \
|
||||
MCFG_DEVICE_ADD(_tag, Z80BIN, 0) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_seconds, (seconds_t) (_delay)) \
|
||||
MCFG_DEVICE_CONFIG_DATA64(snapquick_config, delay_attoseconds, (attoseconds_t) (((_delay) - (int)(_delay)) * ATTOSECONDS_PER_SECOND)) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(z80bin_config, execute, Z80BIN_EXECUTE_NAME(_execute))
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
void log_quickload(const char *type, UINT32 start, UINT32 length, UINT32 exec, const char *exec_format);
|
||||
|
||||
|
||||
#endif /* __SNAPQUIK_H__ */
|
291
src/emu/imagedev/wavfile.c
Normal file
291
src/emu/imagedev/wavfile.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*********************************************************************
|
||||
|
||||
wavfile.c
|
||||
|
||||
Format code for wave (*.wav) files
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "wavfile.h"
|
||||
#include "cassimg.h"
|
||||
|
||||
static const char magic1[4] = { 'R', 'I', 'F', 'F' };
|
||||
static const char magic2[4] = { 'W', 'A', 'V', 'E' };
|
||||
static const char format_tag_id[4] = { 'f', 'm', 't', ' ' };
|
||||
static const char data_tag_id[4] = { 'd', 'a', 't', 'a' };
|
||||
|
||||
#define WAV_FORMAT_PCM 1
|
||||
|
||||
|
||||
|
||||
static UINT32 get_leuint32(const void *ptr)
|
||||
{
|
||||
UINT32 value;
|
||||
memcpy(&value, ptr, sizeof(value));
|
||||
return LITTLE_ENDIANIZE_INT32(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static UINT16 get_leuint16(const void *ptr)
|
||||
{
|
||||
UINT16 value;
|
||||
memcpy(&value, ptr, sizeof(value));
|
||||
return LITTLE_ENDIANIZE_INT16(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void put_leuint32(void *ptr, UINT32 value)
|
||||
{
|
||||
value = LITTLE_ENDIANIZE_INT32(value);
|
||||
memcpy(ptr, &value, sizeof(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void put_leuint16(void *ptr, UINT16 value)
|
||||
{
|
||||
value = LITTLE_ENDIANIZE_INT16(value);
|
||||
memcpy(ptr, &value, sizeof(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static casserr_t wavfile_process(cassette_image *cassette, struct CassetteOptions *opts,
|
||||
int read_waveform)
|
||||
{
|
||||
UINT8 file_header[12];
|
||||
UINT8 tag_header[8];
|
||||
UINT8 format_tag[16];
|
||||
UINT32 stated_size;
|
||||
UINT64 file_size;
|
||||
UINT32 tag_size;
|
||||
UINT32 tag_samples;
|
||||
UINT64 offset;
|
||||
int format_specified = FALSE;
|
||||
|
||||
UINT16 format_type = 0;
|
||||
UINT32 bytes_per_second = 0;
|
||||
UINT16 block_align = 0;
|
||||
int waveform_flags = 0;
|
||||
|
||||
/* read header */
|
||||
cassette_image_read(cassette, file_header, 0, sizeof(file_header));
|
||||
offset = sizeof(file_header);
|
||||
|
||||
/* check magic numbers */
|
||||
if (memcmp(&file_header[0], magic1, 4))
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
if (memcmp(&file_header[8], magic2, 4))
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
|
||||
/* read and sanity check size */
|
||||
stated_size = get_leuint32(&file_header[4]) + 8;
|
||||
file_size = cassette_image_size(cassette);
|
||||
if (stated_size > file_size)
|
||||
stated_size = (UINT32) file_size;
|
||||
|
||||
while(offset < stated_size)
|
||||
{
|
||||
cassette_image_read(cassette, tag_header, offset, sizeof(tag_header));
|
||||
tag_size = get_leuint32(&tag_header[4]);
|
||||
offset += sizeof(tag_header);
|
||||
|
||||
if (!memcmp(tag_header, format_tag_id, 4))
|
||||
{
|
||||
/* format tag */
|
||||
if (format_specified || (tag_size < sizeof(format_tag)))
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
format_specified = TRUE;
|
||||
|
||||
cassette_image_read(cassette, format_tag, offset, sizeof(format_tag));
|
||||
|
||||
format_type = get_leuint16(&format_tag[0]);
|
||||
opts->channels = get_leuint16(&format_tag[2]);
|
||||
opts->sample_frequency = get_leuint32(&format_tag[4]);
|
||||
bytes_per_second = get_leuint32(&format_tag[8]);
|
||||
block_align = get_leuint16(&format_tag[12]);
|
||||
opts->bits_per_sample = get_leuint16(&format_tag[14]);
|
||||
|
||||
if (format_type != WAV_FORMAT_PCM)
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
if (opts->sample_frequency * opts->bits_per_sample * opts->channels / 8 != bytes_per_second)
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
|
||||
switch(opts->bits_per_sample)
|
||||
{
|
||||
case 8:
|
||||
waveform_flags = CASSETTE_WAVEFORM_8BIT;
|
||||
break;
|
||||
case 16:
|
||||
waveform_flags = CASSETTE_WAVEFORM_16BITLE;
|
||||
break;
|
||||
case 32:
|
||||
waveform_flags = CASSETTE_WAVEFORM_32BITLE;
|
||||
break;
|
||||
default:
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
}
|
||||
}
|
||||
else if (!memcmp(tag_header, data_tag_id, 4))
|
||||
{
|
||||
/* data tag */
|
||||
if (!format_specified)
|
||||
return CASSETTE_ERROR_INVALIDIMAGE;
|
||||
|
||||
if (read_waveform)
|
||||
{
|
||||
tag_samples = tag_size / (opts->bits_per_sample / 8) / opts->channels;
|
||||
cassette_read_samples(cassette, opts->channels, 0.0, tag_samples / ((double) opts->sample_frequency),
|
||||
tag_samples, offset, waveform_flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ignore other tags */
|
||||
}
|
||||
offset += tag_size;
|
||||
}
|
||||
|
||||
return CASSETTE_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static casserr_t wavfile_identify(cassette_image *cassette, struct CassetteOptions *opts)
|
||||
{
|
||||
return wavfile_process(cassette, opts, FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static casserr_t wavfile_load(cassette_image *cassette)
|
||||
{
|
||||
struct CassetteOptions opts;
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
return wavfile_process(cassette, &opts, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static casserr_t wavfile_save(cassette_image *cassette, const struct CassetteInfo *info)
|
||||
{
|
||||
casserr_t err;
|
||||
UINT8 consolidated_header[12 + 8 + 16 + 8];
|
||||
UINT8 *header = &consolidated_header[0];
|
||||
UINT8 *format_tag_header = &consolidated_header[12];
|
||||
UINT8 *format_tag_data = &consolidated_header[12 + 8];
|
||||
UINT8 *data_tag_header = &consolidated_header[12 + 8 + 16];
|
||||
UINT32 file_size;
|
||||
UINT32 bytes_per_second;
|
||||
UINT16 bits_per_sample;
|
||||
UINT32 data_size;
|
||||
size_t bytes_per_sample = 2;
|
||||
int waveform_flags = CASSETTE_WAVEFORM_16BITLE;
|
||||
UINT16 block_align;
|
||||
|
||||
bits_per_sample = (UINT16) (bytes_per_sample * 8);
|
||||
bytes_per_second = info->sample_frequency * bytes_per_sample * info->channels;
|
||||
data_size = (UINT32) (info->sample_count * bytes_per_sample * info->channels);
|
||||
file_size = data_size + sizeof(consolidated_header) - 8;
|
||||
block_align = (UINT16) (bytes_per_sample * info->channels);
|
||||
|
||||
/* set up header */
|
||||
memcpy(&header[0], magic1, 4);
|
||||
memcpy(&header[8], magic2, 4);
|
||||
put_leuint32(&header[4], file_size);
|
||||
|
||||
/* set up format tag */
|
||||
memcpy(&format_tag_header[0], format_tag_id, 4);
|
||||
put_leuint32(&format_tag_header[4], 16);
|
||||
put_leuint16(&format_tag_data[0], WAV_FORMAT_PCM);
|
||||
put_leuint16(&format_tag_data[2], info->channels);
|
||||
put_leuint32(&format_tag_data[4], info->sample_frequency);
|
||||
put_leuint32(&format_tag_data[8], bytes_per_second);
|
||||
put_leuint16(&format_tag_data[12], block_align);
|
||||
put_leuint16(&format_tag_data[14], bits_per_sample);
|
||||
|
||||
/* set up data tag */
|
||||
memcpy(&data_tag_header[0], data_tag_id, 4);
|
||||
put_leuint32(&data_tag_header[4], data_size);
|
||||
|
||||
/* write consolidated header */
|
||||
cassette_image_write(cassette, consolidated_header, 0, sizeof(consolidated_header));
|
||||
|
||||
/* write out the actual data */
|
||||
err = cassette_write_samples(cassette, info->channels, 0.0, info->sample_count
|
||||
/ (double) info->sample_frequency, info->sample_count, sizeof(consolidated_header),
|
||||
waveform_flags);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return CASSETTE_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const struct CassetteFormat wavfile_format =
|
||||
{
|
||||
"wav",
|
||||
wavfile_identify,
|
||||
wavfile_load,
|
||||
wavfile_save
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
wavfile_testload()
|
||||
|
||||
This is a hokey function used to test the cassette wave loading
|
||||
system, specifically to test that when one loads a WAV file image
|
||||
that the resulting info queried will be the same data in the WAV.
|
||||
|
||||
This code has already identified some rounding errors
|
||||
*********************************************************************/
|
||||
|
||||
#ifdef UNUSED_FUNCTION
|
||||
void wavfile_testload(const char *fname)
|
||||
{
|
||||
cassette_image *cassette;
|
||||
FILE *f;
|
||||
long offset;
|
||||
int freq, samples, i;
|
||||
INT32 cassamp;
|
||||
INT16 wavsamp;
|
||||
|
||||
f = fopen(fname, "rb");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
if (cassette_open(f, &stdio_ioprocs, &wavfile_format, CASSETTE_FLAG_READONLY, &cassette))
|
||||
{
|
||||
fclose(f);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 44;
|
||||
freq = 44100;
|
||||
samples = 5667062;
|
||||
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
cassette_get_sample(cassette, 0, i / (double) freq, 0.0, &cassamp);
|
||||
|
||||
fseek(f, offset + i * 2, SEEK_SET);
|
||||
fread(&wavsamp, 1, 2, f);
|
||||
assert(cassamp == (((UINT32) wavsamp) << 16));
|
||||
}
|
||||
|
||||
cassette_close(cassette);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
16
src/emu/imagedev/wavfile.h
Normal file
16
src/emu/imagedev/wavfile.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*********************************************************************
|
||||
|
||||
wavfile.h
|
||||
|
||||
Format code for wave (*.wav) files
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef WAVFILE_H
|
||||
#define WAVFILE_H
|
||||
|
||||
#include "cassimg.h"
|
||||
|
||||
extern const struct CassetteFormat wavfile_format;
|
||||
|
||||
#endif /* WAVFILE_H */
|
@ -7,10 +7,7 @@
|
||||
#include "emu.h"
|
||||
#include "idectrl.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#ifdef MESS
|
||||
#include "devices/harddriv.h"
|
||||
#endif
|
||||
#include "imagedev/harddriv.h"
|
||||
|
||||
/***************************************************************************
|
||||
DEBUGGING
|
||||
|
@ -8,9 +8,7 @@
|
||||
#include "scsidev.h"
|
||||
#include "cdrom.h"
|
||||
#include "sound/cdda.h"
|
||||
#ifdef MESS
|
||||
#include "devices/chd_cd.h"
|
||||
#endif
|
||||
#include "imagedev/chd_cd.h"
|
||||
#include "scsicd.h"
|
||||
|
||||
typedef struct
|
||||
|
@ -7,10 +7,7 @@
|
||||
#include "emu.h"
|
||||
#include "scsidev.h"
|
||||
#include "harddisk.h"
|
||||
|
||||
#ifdef MESS
|
||||
#include "devices/harddriv.h"
|
||||
#endif
|
||||
#include "imagedev/harddriv.h"
|
||||
#include "scsihd.h"
|
||||
|
||||
typedef struct
|
||||
|
@ -15,16 +15,13 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "streams.h"
|
||||
#ifdef MESS
|
||||
#include "devices/cassette.h"
|
||||
#endif
|
||||
#include "imagedev/cassette.h"
|
||||
#include "wave.h"
|
||||
|
||||
#define ALWAYS_PLAY_SOUND 0
|
||||
|
||||
static STREAM_UPDATE( wave_sound_update )
|
||||
{
|
||||
#ifdef MESS
|
||||
device_image_interface *image = (device_image_interface *)param;
|
||||
int speakers = speaker_output_count(image->device().machine->config);
|
||||
cassette_image *cassette;
|
||||
@ -62,7 +59,6 @@ static STREAM_UPDATE( wave_sound_update )
|
||||
if (speakers > 1)
|
||||
memset(right_buffer, 0, sizeof(*right_buffer) * samples);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -74,9 +70,7 @@ static DEVICE_START( wave )
|
||||
assert( device != NULL );
|
||||
assert( device->baseconfig().static_config() != NULL );
|
||||
int speakers = speaker_output_count(device->machine->config);
|
||||
#ifdef MESS
|
||||
image = dynamic_cast<device_image_interface *>(device->machine->device( (const char *)device->baseconfig().static_config()));
|
||||
#endif
|
||||
if (speakers > 1)
|
||||
stream_create(device, 0, 2, device->machine->sample_rate, (void *)image, wave_sound_update);
|
||||
else
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "uimenu.h"
|
||||
#include "zippath.h"
|
||||
#include "unicode.h"
|
||||
#include "imagedev/cassette.h"
|
||||
#include "imagedev/bitbngr.h"
|
||||
|
||||
|
||||
|
||||
@ -1014,3 +1016,426 @@ void ui_image_menu_image_info(running_machine *machine, ui_menu *menu, void *par
|
||||
/* process the menu */
|
||||
ui_menu_process(machine, menu, 0);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
#define TAPECMD_NULL ((void *) 0x0000)
|
||||
#define TAPECMD_STOP ((void *) 0x0001)
|
||||
#define TAPECMD_PLAY ((void *) 0x0002)
|
||||
#define TAPECMD_RECORD ((void *) 0x0003)
|
||||
#define TAPECMD_REWIND ((void *) 0x0004)
|
||||
#define TAPECMD_FAST_FORWARD ((void *) 0x0005)
|
||||
#define TAPECMD_SLIDER ((void *) 0x0006)
|
||||
#define TAPECMD_SELECT ((void *) 0x0007)
|
||||
|
||||
#define BITBANGERCMD_SELECT ((void *) 0x0000)
|
||||
#define BITBANGERCMD_MODE ((void *) 0x0001)
|
||||
#define BITBANGERCMD_BAUD ((void *) 0x0002)
|
||||
#define BITBANGERCMD_TUNE ((void *) 0x0003)
|
||||
|
||||
|
||||
typedef struct _tape_control_menu_state tape_control_menu_state;
|
||||
struct _tape_control_menu_state
|
||||
{
|
||||
int index;
|
||||
device_image_interface *device;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct _bitbanger_control_menu_state bitbanger_control_menu_state;
|
||||
struct _bitbanger_control_menu_state
|
||||
{
|
||||
int index;
|
||||
device_image_interface *device;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
cassette_count - returns the number of cassette
|
||||
devices in the machine
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE int cassette_count( running_machine *machine )
|
||||
{
|
||||
int count = 0;
|
||||
device_t *device = machine->m_devicelist.first(CASSETTE);
|
||||
|
||||
while ( device )
|
||||
{
|
||||
count++;
|
||||
device = device->typenext();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
bitbanger_count - returns the number of bitbanger
|
||||
devices in the machine
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE int bitbanger_count( running_machine *machine )
|
||||
{
|
||||
int count = 0;
|
||||
device_t *device = machine->m_devicelist.first(BITBANGER);
|
||||
|
||||
while ( device )
|
||||
{
|
||||
count++;
|
||||
device = device->typenext();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
tapecontrol_gettime - returns a textual
|
||||
representation of the time
|
||||
-------------------------------------------------*/
|
||||
|
||||
astring *tapecontrol_gettime(astring *dest, device_t *device, int *curpos, int *endpos)
|
||||
{
|
||||
double t0, t1;
|
||||
|
||||
t0 = cassette_get_position(device);
|
||||
t1 = cassette_get_length(device);
|
||||
|
||||
if (t1)
|
||||
astring_printf(dest, "%04d/%04d", (int) t0, (int) t1);
|
||||
else
|
||||
astring_printf(dest, "%04d/%04d", 0, (int) t1);
|
||||
|
||||
if (curpos != NULL)
|
||||
*curpos = t0;
|
||||
if (endpos != NULL)
|
||||
*endpos = t1;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
menu_tape_control_populate - populates the
|
||||
main tape control menu
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void menu_tape_control_populate(running_machine *machine, ui_menu *menu, tape_control_menu_state *menustate)
|
||||
{
|
||||
astring timepos;
|
||||
cassette_state state;
|
||||
int count = cassette_count(machine);
|
||||
UINT32 flags = 0;
|
||||
|
||||
if( count > 0 )
|
||||
{
|
||||
if( menustate->index == (count-1) )
|
||||
flags |= MENU_FLAG_LEFT_ARROW;
|
||||
else
|
||||
flags |= MENU_FLAG_RIGHT_ARROW;
|
||||
}
|
||||
|
||||
if (menustate->device->exists())
|
||||
{
|
||||
double t0, t1;
|
||||
UINT32 tapeflags = 0;
|
||||
|
||||
t0 = cassette_get_position(&menustate->device->device());
|
||||
t1 = cassette_get_length(&menustate->device->device());
|
||||
|
||||
if (t1 > 0)
|
||||
{
|
||||
if (t0 > 0)
|
||||
tapeflags |= MENU_FLAG_LEFT_ARROW;
|
||||
if (t0 < t1)
|
||||
tapeflags |= MENU_FLAG_RIGHT_ARROW;
|
||||
}
|
||||
|
||||
/* name of tape */
|
||||
ui_menu_item_append(menu, menustate->device->image_config().devconfig().name(), menustate->device->filename(), flags, TAPECMD_SELECT);
|
||||
|
||||
/* state */
|
||||
tapecontrol_gettime(&timepos, &menustate->device->device(), NULL, NULL);
|
||||
state = cassette_get_state(&menustate->device->device());
|
||||
ui_menu_item_append(
|
||||
menu,
|
||||
(state & CASSETTE_MASK_UISTATE) == CASSETTE_STOPPED
|
||||
? "stopped"
|
||||
: ((state & CASSETTE_MASK_UISTATE) == CASSETTE_PLAY
|
||||
? ((state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED ? "playing" : "(playing)")
|
||||
: ((state & CASSETTE_MASK_MOTOR) == CASSETTE_MOTOR_ENABLED ? "recording" : "(recording)")
|
||||
),
|
||||
astring_c(&timepos),
|
||||
tapeflags,
|
||||
TAPECMD_SLIDER);
|
||||
|
||||
/* pause or stop */
|
||||
ui_menu_item_append(menu, "Pause/Stop", NULL, 0, TAPECMD_STOP);
|
||||
|
||||
/* play */
|
||||
ui_menu_item_append(menu, "Play", NULL, 0, TAPECMD_PLAY);
|
||||
|
||||
/* record */
|
||||
ui_menu_item_append(menu, "Record", NULL, 0, TAPECMD_RECORD);
|
||||
|
||||
/* rewind */
|
||||
ui_menu_item_append(menu, "Rewind", NULL, 0, TAPECMD_REWIND);
|
||||
|
||||
/* fast forward */
|
||||
ui_menu_item_append(menu, "Fast Forward", NULL, 0, TAPECMD_FAST_FORWARD);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no tape loaded */
|
||||
ui_menu_item_append(menu, "No Tape Image loaded", NULL, flags, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
menu_bitbanger_control_populate - populates the
|
||||
main bitbanger control menu
|
||||
-------------------------------------------------*/
|
||||
|
||||
static void menu_bitbanger_control_populate(running_machine *machine, ui_menu *menu, bitbanger_control_menu_state *menustate)
|
||||
{
|
||||
int count = bitbanger_count(machine);
|
||||
UINT32 flags = 0, mode_flags = 0, baud_flags = 0, tune_flags = 0;
|
||||
|
||||
if( count > 0 )
|
||||
{
|
||||
if( menustate->index == (count-1) )
|
||||
flags |= MENU_FLAG_LEFT_ARROW;
|
||||
else
|
||||
flags |= MENU_FLAG_RIGHT_ARROW;
|
||||
}
|
||||
|
||||
if (bitbanger_inc_mode(&menustate->device->device(), TRUE))
|
||||
mode_flags |= MENU_FLAG_RIGHT_ARROW;
|
||||
|
||||
if (bitbanger_dec_mode(&menustate->device->device(), TRUE))
|
||||
mode_flags |= MENU_FLAG_LEFT_ARROW;
|
||||
|
||||
if (bitbanger_inc_baud(&menustate->device->device(), TRUE))
|
||||
baud_flags |= MENU_FLAG_RIGHT_ARROW;
|
||||
|
||||
if (bitbanger_dec_baud(&menustate->device->device(), TRUE))
|
||||
baud_flags |= MENU_FLAG_LEFT_ARROW;
|
||||
|
||||
if (bitbanger_inc_tune(&menustate->device->device(), TRUE))
|
||||
tune_flags |= MENU_FLAG_RIGHT_ARROW;
|
||||
|
||||
if (bitbanger_dec_tune(&menustate->device->device(), TRUE))
|
||||
tune_flags |= MENU_FLAG_LEFT_ARROW;
|
||||
|
||||
|
||||
if (menustate->device->exists())
|
||||
{
|
||||
/* name of bitbanger file */
|
||||
ui_menu_item_append(menu, menustate->device->image_config().devconfig().name(), menustate->device->filename(), flags, BITBANGERCMD_SELECT);
|
||||
ui_menu_item_append(menu, "Device Mode:", bitbanger_mode_string(&menustate->device->device()), mode_flags, BITBANGERCMD_MODE);
|
||||
ui_menu_item_append(menu, "Baud:", bitbanger_baud_string(&menustate->device->device()), baud_flags, BITBANGERCMD_BAUD);
|
||||
ui_menu_item_append(menu, "Baud Tune:", bitbanger_tune_string(&menustate->device->device()), tune_flags, BITBANGERCMD_TUNE);
|
||||
ui_menu_item_append(menu, "Protocol:", "8-1-N", 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no tape loaded */
|
||||
ui_menu_item_append(menu, "No Bitbanger Image loaded", NULL, flags, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
menu_tape_control - main tape control menu
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ui_mess_menu_tape_control(running_machine *machine, ui_menu *menu, void *parameter, void *state)
|
||||
{
|
||||
tape_control_menu_state *menustate;
|
||||
const ui_menu_event *event;
|
||||
|
||||
/* if no state, allocate some */
|
||||
if (state == NULL)
|
||||
state = ui_menu_alloc_state(menu, sizeof(*menustate), NULL);
|
||||
menustate = (tape_control_menu_state *) state;
|
||||
|
||||
/* do we have to load the device? */
|
||||
if (menustate->device == NULL)
|
||||
{
|
||||
int index = menustate->index;
|
||||
device_image_interface *device = NULL;
|
||||
for (bool gotone = machine->m_devicelist.first(device); gotone; gotone = device->next(device))
|
||||
{
|
||||
if(device->device().type() == CASSETTE) {
|
||||
if (index==0) break;
|
||||
index--;
|
||||
}
|
||||
}
|
||||
menustate->device = device;
|
||||
ui_menu_reset(menu, (ui_menu_reset_options)0);
|
||||
}
|
||||
|
||||
/* rebuild the menu - we have to do this so that the counter updates */
|
||||
ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_POSITION);
|
||||
menu_tape_control_populate(machine, menu, (tape_control_menu_state*)state);
|
||||
|
||||
/* process the menu */
|
||||
event = ui_menu_process(machine, menu, UI_MENU_PROCESS_LR_REPEAT);
|
||||
if (event != NULL)
|
||||
{
|
||||
switch(event->iptkey)
|
||||
{
|
||||
case IPT_UI_LEFT:
|
||||
if (event->itemref==TAPECMD_SLIDER)
|
||||
cassette_seek(&menustate->device->device(), -1, SEEK_CUR);
|
||||
else
|
||||
if (event->itemref==TAPECMD_SELECT)
|
||||
{
|
||||
/* left arrow - rotate left through cassette devices */
|
||||
if (menustate->index > 0)
|
||||
menustate->index--;
|
||||
else
|
||||
menustate->index = cassette_count(machine) - 1;
|
||||
menustate->device = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPT_UI_RIGHT:
|
||||
if (event->itemref==TAPECMD_SLIDER)
|
||||
cassette_seek(&menustate->device->device(), +1, SEEK_CUR);
|
||||
else
|
||||
if (event->itemref==TAPECMD_SELECT)
|
||||
{
|
||||
/* right arrow - rotate right through cassette devices */
|
||||
if (menustate->index < cassette_count(machine) - 1)
|
||||
menustate->index++;
|
||||
else
|
||||
menustate->index = 0;
|
||||
menustate->device = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IPT_UI_SELECT:
|
||||
{
|
||||
if (event->itemref==TAPECMD_STOP)
|
||||
cassette_change_state(&menustate->device->device(), CASSETTE_STOPPED, CASSETTE_MASK_UISTATE);
|
||||
else
|
||||
if (event->itemref==TAPECMD_PLAY)
|
||||
cassette_change_state(&menustate->device->device(), CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
|
||||
else
|
||||
if (event->itemref==TAPECMD_RECORD)
|
||||
cassette_change_state(&menustate->device->device(), CASSETTE_RECORD, CASSETTE_MASK_UISTATE);
|
||||
else
|
||||
if (event->itemref==TAPECMD_REWIND)
|
||||
cassette_seek(&menustate->device->device(), -30, SEEK_CUR);
|
||||
else
|
||||
if (event->itemref==TAPECMD_FAST_FORWARD)
|
||||
cassette_seek(&menustate->device->device(), 30, SEEK_CUR);
|
||||
else
|
||||
if (event->itemref==TAPECMD_SLIDER)
|
||||
cassette_seek(&menustate->device->device(), 0, SEEK_SET);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
menu_bitbanger_control - main bitbanger
|
||||
control menu
|
||||
-------------------------------------------------*/
|
||||
|
||||
void ui_mess_menu_bitbanger_control(running_machine *machine, ui_menu *menu, void *parameter, void *state)
|
||||
{
|
||||
bitbanger_control_menu_state *menustate;
|
||||
const ui_menu_event *event;
|
||||
|
||||
/* if no state, allocate some */
|
||||
if (state == NULL)
|
||||
state = ui_menu_alloc_state(menu, sizeof(*menustate), NULL);
|
||||
menustate = (bitbanger_control_menu_state *) state;
|
||||
|
||||
/* do we have to load the device? */
|
||||
if (menustate->device == NULL)
|
||||
{
|
||||
int index = menustate->index;
|
||||
device_image_interface *device = NULL;
|
||||
for (bool gotone = machine->m_devicelist.first(device); gotone; gotone = device->next(device))
|
||||
{
|
||||
if(device->device().type() == BITBANGER) {
|
||||
if (index==0) break;
|
||||
index--;
|
||||
}
|
||||
}
|
||||
menustate->device = device;
|
||||
ui_menu_reset(menu, (ui_menu_reset_options)0);
|
||||
}
|
||||
|
||||
/* rebuild the menu */
|
||||
ui_menu_reset(menu, UI_MENU_RESET_REMEMBER_POSITION);
|
||||
menu_bitbanger_control_populate(machine, menu, (bitbanger_control_menu_state*)state);
|
||||
|
||||
/* process the menu */
|
||||
event = ui_menu_process(machine, menu, UI_MENU_PROCESS_LR_REPEAT);
|
||||
if (event != NULL)
|
||||
{
|
||||
switch(event->iptkey)
|
||||
{
|
||||
case IPT_UI_LEFT:
|
||||
if (event->itemref==BITBANGERCMD_SELECT)
|
||||
{
|
||||
/* left arrow - rotate left through cassette devices */
|
||||
if (menustate->index > 0)
|
||||
menustate->index--;
|
||||
else
|
||||
menustate->index = bitbanger_count(machine) - 1;
|
||||
menustate->device = NULL;
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_MODE)
|
||||
{
|
||||
bitbanger_dec_mode(&menustate->device->device(), FALSE);
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_BAUD)
|
||||
{
|
||||
bitbanger_dec_baud(&menustate->device->device(), FALSE);
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_TUNE)
|
||||
{
|
||||
bitbanger_dec_tune(&menustate->device->device(), FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPT_UI_RIGHT:
|
||||
if (event->itemref==BITBANGERCMD_SELECT)
|
||||
{
|
||||
/* right arrow - rotate right through cassette devices */
|
||||
if (menustate->index < bitbanger_count(machine) - 1)
|
||||
menustate->index++;
|
||||
else
|
||||
menustate->index = 0;
|
||||
menustate->device = NULL;
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_MODE)
|
||||
{
|
||||
bitbanger_inc_mode(&menustate->device->device(), FALSE);
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_BAUD)
|
||||
{
|
||||
bitbanger_inc_baud(&menustate->device->device(), FALSE);
|
||||
}
|
||||
else if (event->itemref==BITBANGERCMD_TUNE)
|
||||
{
|
||||
bitbanger_inc_tune(&menustate->device->device(), FALSE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,4 +24,8 @@ void ui_image_menu_file_manager(running_machine *machine, ui_menu *menu, void *p
|
||||
|
||||
void ui_image_menu_image_info(running_machine *machine, ui_menu *menu, void *parameter, void *state);
|
||||
|
||||
void ui_mess_menu_bitbanger_control(running_machine *machine, ui_menu *menu, void *parameter, void *state);
|
||||
|
||||
void ui_mess_menu_tape_control(running_machine *machine, ui_menu *menu, void *parameter, void *state);
|
||||
|
||||
#endif /* __UIIMAGE_H__ */
|
||||
|
@ -19,12 +19,9 @@
|
||||
#include "uimenu.h"
|
||||
#include "audit.h"
|
||||
#include "crsshair.h"
|
||||
|
||||
#ifdef MESS
|
||||
#include "uimess.h"
|
||||
#endif /* MESS */
|
||||
|
||||
#include <ctype.h>
|
||||
#include "imagedev/cassette.h"
|
||||
#include "imagedev/bitbngr.h"
|
||||
|
||||
|
||||
|
||||
@ -1549,10 +1546,14 @@ static void menu_main_populate(running_machine *machine, ui_menu *menu, void *st
|
||||
|
||||
/* add file manager menu */
|
||||
ui_menu_item_append(menu, "File Manager", NULL, 0, (void*)ui_image_menu_file_manager);
|
||||
#ifdef MESS
|
||||
/* add MESS-specific menus */
|
||||
ui_mess_main_menu_populate(machine, menu);
|
||||
#endif /* MESS */
|
||||
|
||||
/* add tape control menu */
|
||||
if (machine->m_devicelist.first(CASSETTE))
|
||||
ui_menu_item_append(menu, "Tape Control", NULL, 0, (void*)ui_mess_menu_tape_control);
|
||||
|
||||
/* add bitbanger control menu */
|
||||
if (machine->m_devicelist.first(BITBANGER))
|
||||
ui_menu_item_append(menu, "Bitbanger Control", NULL, 0, (void*)ui_mess_menu_bitbanger_control);
|
||||
}
|
||||
/* add keyboard mode menu */
|
||||
if (input_machine_has_keyboard(machine) && inputx_can_post(machine))
|
||||
|
@ -271,9 +271,7 @@ a tilemap-like structure, from which data is copied)
|
||||
#include "cpu/sh2/sh2.h"
|
||||
#include "cpu/sh2/sh2comn.h"
|
||||
#include "sound/cdda.h"
|
||||
#ifdef MESS
|
||||
#include "devices/chd_cd.h"
|
||||
#endif
|
||||
#include "imagedev/chd_cd.h"
|
||||
#include "sound/rf5c68.h"
|
||||
|
||||
#define MEGADRIV_VDP_VRAM(address) megadrive_vdp_vram[(address)&0x7fff]
|
||||
|
@ -22,9 +22,7 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#ifdef MESS
|
||||
#include "devices/chd_cd.h"
|
||||
#endif
|
||||
#include "imagedev/chd_cd.h"
|
||||
#include "cdrom.h"
|
||||
#include "stvcd.h"
|
||||
|
||||
|
@ -72,12 +72,6 @@
|
||||
#include "strconv.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef MESS
|
||||
#include "uimess.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//============================================================
|
||||
// PARAMETERS
|
||||
//============================================================
|
||||
|
Loading…
Reference in New Issue
Block a user