mirror of
https://github.com/holub/mame
synced 2025-07-06 10:29:38 +03:00
Removed multcart from imagedev, slots and softlists replaces this functionality (no whatsnew)
This commit is contained in:
parent
877fd3d601
commit
f37d6fb4ab
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -723,8 +723,6 @@ src/emu/imagedev/floppy.c svneol=native#text/plain
|
||||
src/emu/imagedev/floppy.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/serial.c svneol=native#text/plain
|
||||
|
@ -300,7 +300,6 @@ EMUIMAGEDEVOBJS = \
|
||||
$(EMUIMAGEDEV)/flopdrv.o \
|
||||
$(EMUIMAGEDEV)/floppy.o \
|
||||
$(EMUIMAGEDEV)/harddriv.o \
|
||||
$(EMUIMAGEDEV)/multcart.o \
|
||||
$(EMUIMAGEDEV)/printer.o \
|
||||
$(EMUIMAGEDEV)/serial.o \
|
||||
$(EMUIMAGEDEV)/snapquik.o \
|
||||
|
@ -1,888 +0,0 @@
|
||||
/*********************************************************************
|
||||
|
||||
multcart.c
|
||||
|
||||
Multi-cartridge handling code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "multcart.h"
|
||||
#include "pool.h"
|
||||
#include "unzip.h"
|
||||
#include "corestr.h"
|
||||
#include "xmlfile.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];
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
INLINE multicartslot_t *get_token(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == MULTICARTSLOT);
|
||||
return (multicartslot_t *) downcast<legacy_device_base *>(device)->token();
|
||||
}
|
||||
|
||||
|
||||
INLINE const multicartslot_config *get_config(const device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == MULTICARTSLOT);
|
||||
return (const multicartslot_config *) downcast<const legacy_device_base *>(device)->inline_config();
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
/*-------------------------------------------------
|
||||
cartslot_get_pcb
|
||||
-------------------------------------------------*/
|
||||
|
||||
device_t *cartslot_get_pcb(device_t *device)
|
||||
{
|
||||
multicartslot_t *cart = get_token(device);
|
||||
return cart->pcb_device;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
cartslot_get_socket
|
||||
-------------------------------------------------*/
|
||||
|
||||
void *cartslot_get_socket(device_t *device, const char *socket_name)
|
||||
{
|
||||
multicartslot_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)
|
||||
{
|
||||
multicartslot_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;
|
||||
}
|
||||
/*-------------------------------------------------
|
||||
identify_pcb
|
||||
-------------------------------------------------*/
|
||||
|
||||
static const multicartslot_pcb_type *identify_pcb(device_image_interface &image)
|
||||
{
|
||||
const multicartslot_config *config = get_config(&image.device());
|
||||
astring pcb_name;
|
||||
const multicartslot_pcb_type *pcb_type = NULL;
|
||||
multicart_t *mc;
|
||||
int i;
|
||||
|
||||
if (image.exists())
|
||||
{
|
||||
/* try opening this as if it were a multicart */
|
||||
multicart_open_error me = multicart_open(image.device().machine().options(), image.filename(), image.device().machine().system().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(image.device().machine().options(), mc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me != MCERR_NOT_MULTICART)
|
||||
fatalerror("multicart error: %s", multicart_error_text(me));
|
||||
}
|
||||
|
||||
/* 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(multicartslot)
|
||||
{
|
||||
const multicartslot_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
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)))
|
||||
{
|
||||
hash_collection actual_hashes;
|
||||
actual_hashes.compute((const UINT8 *)resource->ptr, resource->length, hash_collection::HASH_TYPES_CRC_SHA1);
|
||||
|
||||
hash_collection expected_hashes;
|
||||
expected_hashes.add_from_string(hash_collection::HASH_SHA1, sha1, strlen(sha1));
|
||||
|
||||
if (actual_hashes != expected_hashes)
|
||||
{
|
||||
return MCERR_INVALID_FILE_REF;
|
||||
}
|
||||
}
|
||||
|
||||
return MCERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
load_ram_resource
|
||||
-------------------------------------------------*/
|
||||
|
||||
static multicart_open_error load_ram_resource(emu_options &options, 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_device::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(options, 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(emu_options &options, 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(options, 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(emu_options &options, 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(options, 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(emu_options &options, 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(options, 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(emu_options &options, 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(options, &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(options, state.multicart);
|
||||
state.multicart = NULL;
|
||||
}
|
||||
*cart = state.multicart;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
multicart_close - closes a multicart
|
||||
-------------------------------------------------*/
|
||||
|
||||
void multicart_close(emu_options &options, multicart_t *cart)
|
||||
{
|
||||
save_ram_resources(options, cart);
|
||||
pool_free_lib(cart->data->pool);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_START( multicartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_START( multicartslot )
|
||||
{
|
||||
const multicartslot_config *config = get_config(device);
|
||||
|
||||
/* if this cartridge has a custom DEVICE_START, use it */
|
||||
if (config->device_start != NULL)
|
||||
{
|
||||
(*config->device_start)(device);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_LOAD( cartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_LOAD( multicartslot )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
const multicartslot_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);
|
||||
|
||||
/* otherwise try the normal route */
|
||||
return IMAGE_INIT_PASS;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
DEVICE_IMAGE_UNLOAD( multicartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
static DEVICE_IMAGE_UNLOAD( multicartslot )
|
||||
{
|
||||
device_t *device = &image.device();
|
||||
const multicartslot_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;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------
|
||||
DEVICE_GET_INFO( multicartslot )
|
||||
-------------------------------------------------*/
|
||||
|
||||
DEVICE_GET_INFO( multicartslot )
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
||||
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(multicartslot_t); break;
|
||||
case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(multicartslot_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: info->i = 0; break;
|
||||
|
||||
/* --- the following bits of info are returned as pointers to functions --- */
|
||||
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(multicartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(multicartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(multicartslot); break;
|
||||
case DEVINFO_FCT_IMAGE_GET_DEVICES: info->f = (genf *) DEVICE_IMAGE_GET_DEVICES_NAME(multicartslot); break;
|
||||
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "MultiCartslot"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "MultiCartslot"); break;
|
||||
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
|
||||
case DEVINFO_STR_IMAGE_FILE_EXTENSIONS:
|
||||
if ( device && downcast<const legacy_image_device_base *>(device)->inline_config() && get_config(device)->extensions )
|
||||
{
|
||||
strcpy(info->s, get_config(device)->extensions);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(info->s, "bin");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_LEGACY_IMAGE_DEVICE(MULTICARTSLOT, multicartslot);
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CARTSLOT INTERFACE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_cart_slot_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_cart_slot_interface::device_cart_slot_interface(const machine_config &mconfig, device_t &device)
|
||||
: device_interface(device)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_cart_slot_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_cart_slot_interface::~device_cart_slot_interface()
|
||||
{
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE LEGACY cart_slot DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// legacy_cart_slot_device_base - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
legacy_cart_slot_device_base::legacy_cart_slot_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, device_get_config_func get_config)
|
||||
: legacy_device_base(mconfig, type, tag, owner, clock, get_config),
|
||||
device_cart_slot_interface(mconfig, *this)
|
||||
{
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
/*********************************************************************
|
||||
|
||||
multcart.h
|
||||
|
||||
Multi-cartridge handling code
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __MULTCART_H__
|
||||
#define __MULTCART_H__
|
||||
|
||||
#include "osdcore.h"
|
||||
|
||||
#define TAG_PCB "pcb"
|
||||
|
||||
DECLARE_LEGACY_IMAGE_DEVICE(MULTICARTSLOT, multicartslot);
|
||||
|
||||
/***************************************************************************
|
||||
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;
|
||||
};
|
||||
|
||||
typedef struct _multicartslot_t multicartslot_t;
|
||||
struct _multicartslot_t
|
||||
{
|
||||
device_t *pcb_device;
|
||||
multicart_t *mc;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _multicartslot_pcb_type multicartslot_pcb_type;
|
||||
struct _multicartslot_pcb_type
|
||||
{
|
||||
const char * name;
|
||||
device_type devtype;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _multicartslot_config multicartslot_config;
|
||||
struct _multicartslot_config
|
||||
{
|
||||
const char * extensions;
|
||||
device_start_func device_start;
|
||||
device_image_load_func device_load;
|
||||
device_image_unload_func device_unload;
|
||||
multicartslot_pcb_type pcb_types[16];
|
||||
};
|
||||
|
||||
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(emu_options &options, const char *filename, const char *drvname, multicart_load_flags load_flags, multicart_t **cart);
|
||||
|
||||
/* closes a multicart */
|
||||
void multicart_close(emu_options &options, multicart_t *cart);
|
||||
|
||||
/* 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);
|
||||
|
||||
#define DECLARE_LEGACY_CART_SLOT_DEVICE(name, basename) _DECLARE_LEGACY_DEVICE(name, basename, basename##_device, legacy_cart_slot_device_base)
|
||||
#define DEFINE_LEGACY_CART_SLOT_DEVICE(name, basename) _DEFINE_LEGACY_DEVICE(name, basename, basename##_device, legacy_cart_slot_device_base)
|
||||
|
||||
#define MCFG_MULTICARTSLOT_ADD(_tag) \
|
||||
MCFG_DEVICE_ADD(_tag, MULTICARTSLOT, 0) \
|
||||
|
||||
#define MCFG_MULTICARTSLOT_MODIFY(_tag) \
|
||||
MCFG_DEVICE_MODIFY(_tag) \
|
||||
|
||||
#define MCFG_MULTICARTSLOT_PCBTYPE(_index, _pcb_type_name, _pcb_devtype) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR_ARRAY_MEMBER(multicartslot_config, pcb_types, _index, multicartslot_pcb_type, name, _pcb_type_name) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR_ARRAY_MEMBER(multicartslot_config, pcb_types, _index, multicartslot_pcb_type, devtype, _pcb_devtype)
|
||||
|
||||
#define MCFG_MULTICARTSLOT_START(_start) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(multicartslot_config, device_start, DEVICE_START_NAME(_start))
|
||||
|
||||
#define MCFG_MULTICARTSLOT_LOAD(_load) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(multicartslot_config, device_load, DEVICE_IMAGE_LOAD_NAME(_load))
|
||||
|
||||
#define MCFG_MULTICARTSLOT_UNLOAD(_unload) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(multicartslot_config, device_unload, DEVICE_IMAGE_UNLOAD_NAME(_unload))
|
||||
|
||||
#define MCFG_MULTICARTSLOT_EXTENSION_LIST(_extensions) \
|
||||
MCFG_DEVICE_CONFIG_DATAPTR(multicartslot_config, extensions, _extensions)
|
||||
|
||||
|
||||
// ======================> 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(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_cart_slot_interface();
|
||||
};
|
||||
|
||||
|
||||
// ======================> 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(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, device_get_config_func get_config);
|
||||
|
||||
public:
|
||||
using legacy_device_base::get_legacy_int;
|
||||
using legacy_device_base::get_legacy_fct;
|
||||
using legacy_device_base::get_legacy_ptr;
|
||||
|
||||
// device_cart_slot_interface overrides
|
||||
};
|
||||
|
||||
|
||||
#endif /* __MULTCART_H__ */
|
Loading…
Reference in New Issue
Block a user