diff options
Diffstat (limited to 'trunk/src/emu/imagedev/multcart.c')
-rw-r--r-- | trunk/src/emu/imagedev/multcart.c | 888 |
1 files changed, 888 insertions, 0 deletions
diff --git a/trunk/src/emu/imagedev/multcart.c b/trunk/src/emu/imagedev/multcart.c new file mode 100644 index 00000000000..506e1231126 --- /dev/null +++ b/trunk/src/emu/imagedev/multcart.c @@ -0,0 +1,888 @@ +/********************************************************************* + + 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_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) +{ +} |