diff options
Diffstat (limited to 'trunk/src/emu/romload.c')
-rw-r--r-- | trunk/src/emu/romload.c | 1604 |
1 files changed, 1604 insertions, 0 deletions
diff --git a/trunk/src/emu/romload.c b/trunk/src/emu/romload.c new file mode 100644 index 00000000000..caf568a1bd8 --- /dev/null +++ b/trunk/src/emu/romload.c @@ -0,0 +1,1604 @@ +/********************************************************************* + + romload.c + + ROM loading functions. + + Copyright Nicola Salmoria and the MAME Team. + Visit http://mamedev.org for licensing and usage restrictions. + +*********************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "hash.h" +#include "png.h" +#include "harddisk.h" +#include "config.h" +#include "ui.h" + + +#define LOG_LOAD 0 +#define LOG(x) do { if (LOG_LOAD) debugload x; } while(0) + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define TEMPBUFFER_MAX_SIZE (1024 * 1024 * 1024) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +typedef struct _open_chd open_chd; +struct _open_chd +{ + open_chd * next; /* pointer to next in the list */ + const char * region; /* disk region we came from */ + chd_file * origchd; /* handle to the original CHD */ + emu_file * origfile; /* file handle to the original CHD file */ + chd_file * diffchd; /* handle to the diff CHD */ + emu_file * difffile; /* file handle to the diff CHD file */ +}; + + +typedef struct _romload_private rom_load_data; +struct _romload_private +{ + running_machine &machine() const { assert(m_machine != NULL); return *m_machine; } + + running_machine *m_machine; /* machine object where needed */ + int system_bios; /* the system BIOS we wish to load */ + int default_bios; /* the default system BIOS */ + + int warnings; /* warning count during processing */ + int knownbad; /* BAD_DUMP/NO_DUMP count during processing */ + int errors; /* error count during processing */ + + int romsloaded; /* current ROMs loaded count */ + int romstotal; /* total number of ROMs to read */ + UINT32 romsloadedsize; /* total size of ROMs loaded so far */ + UINT32 romstotalsize; /* total size of ROMs to read */ + + emu_file * file; /* current file */ + open_chd * chd_list; /* disks */ + open_chd ** chd_list_tailptr; + + memory_region * region; /* info about current region */ + + astring errorstring; /* error string */ +}; + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void rom_exit(running_machine &machine); + +/*************************************************************************** + HELPERS (also used by devimage.c) + ***************************************************************************/ + +file_error common_process_file(emu_options &options, const char *location, const char *ext, const rom_entry *romp, emu_file **image_file) +{ + *image_file = global_alloc(emu_file(options.media_path(), OPEN_FLAG_READ)); + file_error filerr; + + if (location != NULL && strcmp(location, "") != 0) + filerr = (*image_file)->open(location, PATH_SEPARATOR, ROM_GETNAME(romp), ext); + else + filerr = (*image_file)->open(ROM_GETNAME(romp), ext); + + if (filerr != FILERR_NONE) + { + global_free(*image_file); + *image_file = NULL; + } + return filerr; +} + +file_error common_process_file(emu_options &options, const char *location, bool has_crc, UINT32 crc, const rom_entry *romp, emu_file **image_file) +{ + *image_file = global_alloc(emu_file(options.media_path(), OPEN_FLAG_READ)); + file_error filerr; + + if (has_crc) + filerr = (*image_file)->open(location, PATH_SEPARATOR, ROM_GETNAME(romp), crc); + else + filerr = (*image_file)->open(location, PATH_SEPARATOR, ROM_GETNAME(romp)); + + if (filerr != FILERR_NONE) + { + global_free(*image_file); + *image_file = NULL; + } + return filerr; +} + + +/*************************************************************************** + HARD DISK HANDLING +***************************************************************************/ + +/*------------------------------------------------- + get_disk_handle - return a pointer to the + CHD file associated with the given region +-------------------------------------------------*/ + +chd_file *get_disk_handle(running_machine &machine, const char *region) +{ + open_chd *curdisk; + + for (curdisk = machine.romload_data->chd_list; curdisk != NULL; curdisk = curdisk->next) + if (strcmp(curdisk->region, region) == 0) + return (curdisk->diffchd != NULL) ? curdisk->diffchd : curdisk->origchd; + return NULL; +} + + +/*------------------------------------------------- + add_disk_handle - add a disk to the to the + list of CHD files +-------------------------------------------------*/ + +static void add_disk_handle(running_machine &machine, open_chd *chd) +{ + romload_private *romload_data = machine.romload_data; + + *romload_data->chd_list_tailptr = auto_alloc(machine, open_chd); + **romload_data->chd_list_tailptr = *chd; + romload_data->chd_list_tailptr = &(*romload_data->chd_list_tailptr)->next; +} + + +/*------------------------------------------------- + set_disk_handle - set a pointer to the CHD + file associated with the given region +-------------------------------------------------*/ + +void set_disk_handle(running_machine &machine, const char *region, emu_file &file, chd_file &chdfile) +{ + open_chd chd = { 0 }; + + /* note the region we are in */ + chd.region = region; + chd.origchd = &chdfile; + chd.origfile = &file; + + /* we're okay, add to the list of disks */ + add_disk_handle(machine, &chd); +} + + + +/*************************************************************************** + ROM LOADING +***************************************************************************/ + +/*------------------------------------------------- + rom_first_source - return pointer to first ROM + source +-------------------------------------------------*/ + +const rom_source *rom_first_source(const machine_config &config) +{ + /* look through devices */ + for (const device_t *device = config.devicelist().first(); device != NULL; device = device->next()) + if (device->rom_region() != NULL) + return device; + + return NULL; +} + + +/*------------------------------------------------- + rom_next_source - return pointer to next ROM + source +-------------------------------------------------*/ + +const rom_source *rom_next_source(const rom_source &previous) +{ + /* look for further devices with ROM definitions */ + for (const device_t *device = previous.next(); device != NULL; device = device->next()) + if (device->rom_region() != NULL) + return (rom_source *)device; + + return NULL; +} + + +/*------------------------------------------------- + rom_first_region - return pointer to first ROM + region +-------------------------------------------------*/ + +const rom_entry *rom_first_region(const rom_source &source) +{ + const rom_entry *romp = source.rom_region(); + return (romp != NULL && !ROMENTRY_ISEND(romp)) ? romp : NULL; +} + + +/*------------------------------------------------- + rom_next_region - return pointer to next ROM + region +-------------------------------------------------*/ + +const rom_entry *rom_next_region(const rom_entry *romp) +{ + romp++; + while (!ROMENTRY_ISREGIONEND(romp)) + romp++; + return ROMENTRY_ISEND(romp) ? NULL : romp; +} + + +/*------------------------------------------------- + rom_first_file - return pointer to first ROM + file +-------------------------------------------------*/ + +const rom_entry *rom_first_file(const rom_entry *romp) +{ + romp++; + while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp)) + romp++; + return ROMENTRY_ISREGIONEND(romp) ? NULL : romp; +} + + +/*------------------------------------------------- + rom_next_file - return pointer to next ROM + file +-------------------------------------------------*/ + +const rom_entry *rom_next_file(const rom_entry *romp) +{ + romp++; + while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp)) + romp++; + return ROMENTRY_ISREGIONEND(romp) ? NULL : romp; +} + + +/*------------------------------------------------- + rom_region_name - return the appropriate name + for a rom region +-------------------------------------------------*/ + +astring &rom_region_name(astring &result, const game_driver *drv, const rom_source *source, const rom_entry *romp) +{ + return source->subtag(result, ROMREGION_GETTAG(romp)); +} + + +/*------------------------------------------------- + rom_file_size - return the expected size of a + file given the ROM description +-------------------------------------------------*/ + +UINT32 rom_file_size(const rom_entry *romp) +{ + UINT32 maxlength = 0; + + /* loop until we run out of reloads */ + do + { + UINT32 curlength; + + /* loop until we run out of continues/ignores */ + curlength = ROM_GETLENGTH(romp++); + while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)) + curlength += ROM_GETLENGTH(romp++); + + /* track the maximum length */ + maxlength = MAX(maxlength, curlength); + } + while (ROMENTRY_ISRELOAD(romp)); + + return maxlength; +} + + +/*------------------------------------------------- + debugload - log data to a file +-------------------------------------------------*/ + +static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...) +{ + static int opened; + va_list arg; + FILE *f; + + f = fopen("romload.log", opened++ ? "a" : "w"); + if (f) + { + va_start(arg, string); + vfprintf(f, string, arg); + va_end(arg); + fclose(f); + } +} + + +/*------------------------------------------------- + determine_bios_rom - determine system_bios + from SystemBios structure and OPTION_BIOS +-------------------------------------------------*/ + +static void determine_bios_rom(rom_load_data *romdata) +{ + const char *specbios = romdata->machine().options().bios(); + const char *defaultname = NULL; + const rom_entry *rom; + int default_no = 1; + int bios_count = 0; + + romdata->system_bios = 0; + + for (const rom_source *source = rom_first_source(romdata->machine().config()); source != NULL; source = rom_next_source(*source)) + { + /* first determine the default BIOS name */ + for (rom = source->rom_region(); !ROMENTRY_ISEND(rom); rom++) + if (ROMENTRY_ISDEFAULT_BIOS(rom)) + defaultname = ROM_GETNAME(rom); + + /* look for a BIOS with a matching name */ + for (rom = source->rom_region(); !ROMENTRY_ISEND(rom); rom++) + if (ROMENTRY_ISSYSTEM_BIOS(rom)) + { + const char *biosname = ROM_GETNAME(rom); + int bios_flags = ROM_GETBIOSFLAGS(rom); + char bios_number[20]; + + /* Allow '-bios n' to still be used */ + sprintf(bios_number, "%d", bios_flags - 1); + if (mame_stricmp(bios_number, specbios) == 0 || mame_stricmp(biosname, specbios) == 0) + romdata->system_bios = bios_flags; + if (defaultname != NULL && mame_stricmp(biosname, defaultname) == 0) + default_no = bios_flags; + bios_count++; + } + + /* if none found, use the default */ + if (romdata->system_bios == 0 && bios_count > 0) + { + /* if we got neither an empty string nor 'default' then warn the user */ + if (specbios[0] != 0 && strcmp(specbios, "default") != 0 && romdata != NULL) + { + romdata->errorstring.catprintf("%s: invalid bios\n", specbios); + romdata->warnings++; + } + + /* set to default */ + romdata->system_bios = default_no; + } + romdata->default_bios = default_no; + LOG(("Using System BIOS: %d\n", romdata->system_bios)); + } +} + + +/*------------------------------------------------- + count_roms - counts the total number of ROMs + that will need to be loaded +-------------------------------------------------*/ + +static void count_roms(rom_load_data *romdata) +{ + const rom_entry *region, *rom; + const rom_source *source; + + /* start with 0 */ + romdata->romstotal = 0; + romdata->romstotalsize = 0; + + /* loop over regions, then over files */ + for (source = rom_first_source(romdata->machine().config()); source != NULL; source = rom_next_source(*source)) + for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) + if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == romdata->system_bios) + { + romdata->romstotal++; + romdata->romstotalsize += rom_file_size(rom); + } +} + + +/*------------------------------------------------- + fill_random - fills an area of memory with + random data +-------------------------------------------------*/ + +static void fill_random(running_machine &machine, UINT8 *base, UINT32 length) +{ + while (length--) + *base++ = machine.rand(); +} + + +/*------------------------------------------------- + handle_missing_file - handles error generation + for missing files +-------------------------------------------------*/ + +static void handle_missing_file(rom_load_data *romdata, const rom_entry *romp) +{ + /* optional files are okay */ + if (ROM_ISOPTIONAL(romp)) + { + romdata->errorstring.catprintf("OPTIONAL %s NOT FOUND\n", ROM_GETNAME(romp)); + romdata->warnings++; + } + + /* no good dumps are okay */ + else if (hash_collection(ROM_GETHASHDATA(romp)).flag(hash_collection::FLAG_NO_DUMP)) + { + romdata->errorstring.catprintf("%s NOT FOUND (NO GOOD DUMP KNOWN)\n", ROM_GETNAME(romp)); + romdata->knownbad++; + } + + /* anything else is bad */ + else + { + romdata->errorstring.catprintf("%s NOT FOUND\n", ROM_GETNAME(romp)); + romdata->errors++; + } +} + + +/*------------------------------------------------- + dump_wrong_and_correct_checksums - dump an + error message containing the wrong and the + correct checksums for a given ROM +-------------------------------------------------*/ + +static void dump_wrong_and_correct_checksums(rom_load_data *romdata, const hash_collection &hashes, const hash_collection &acthashes) +{ + astring tempstr; + romdata->errorstring.catprintf(" EXPECTED: %s\n", hashes.macro_string(tempstr)); + romdata->errorstring.catprintf(" FOUND: %s\n", acthashes.macro_string(tempstr)); + + // warn about any ill-formed hashes + for (hash_base *hash = hashes.first(); hash != NULL; hash = hash->next()) + if (hash->parse_error()) + { + romdata->errorstring.catprintf("\tInvalid %s checksum treated as 0 (check leading zeros)\n", hash->name()); + romdata->warnings++; + } +} + + +/*------------------------------------------------- + verify_length_and_hash - verify the length + and hash signatures of a file +-------------------------------------------------*/ + +static void verify_length_and_hash(rom_load_data *romdata, const char *name, UINT32 explength, const hash_collection &hashes) +{ + /* we've already complained if there is no file */ + if (romdata->file == NULL) + return; + + /* verify length */ + UINT32 actlength = romdata->file->size(); + if (explength != actlength) + { + romdata->errorstring.catprintf("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength); + romdata->warnings++; + } + + /* If there is no good dump known, write it */ + astring tempstr; + hash_collection &acthashes = romdata->file->hashes(hashes.hash_types(tempstr)); + if (hashes.flag(hash_collection::FLAG_NO_DUMP)) + { + romdata->errorstring.catprintf("%s NO GOOD DUMP KNOWN\n", name); + romdata->knownbad++; + } + /* verify checksums */ + else if (hashes != acthashes) + { + /* otherwise, it's just bad */ + romdata->errorstring.catprintf("%s WRONG CHECKSUMS:\n", name); + dump_wrong_and_correct_checksums(romdata, hashes, acthashes); + romdata->warnings++; + } + /* If it matches, but it is actually a bad dump, write it */ + else if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) + { + romdata->errorstring.catprintf("%s ROM NEEDS REDUMP\n",name); + romdata->knownbad++; + } +} + + +/*------------------------------------------------- + display_loading_rom_message - display + messages about ROM loading to the user +-------------------------------------------------*/ + +static void display_loading_rom_message(rom_load_data *romdata, const char *name) +{ + char buffer[200]; + + // 2010-04, FP - FIXME: in MESS, load_software_part_region sometimes calls this with romstotalsize = 0! + // as a temp workaround, I added a check for romstotalsize !=0. + if (name != NULL && romdata->romstotalsize) + sprintf(buffer, "Loading (%d%%)", (UINT32)(100 * (UINT64)romdata->romsloadedsize / (UINT64)romdata->romstotalsize)); + else + sprintf(buffer, "Loading Complete"); + + ui_set_startup_text(romdata->machine(), buffer, FALSE); +} + + +/*------------------------------------------------- + display_rom_load_results - display the final + results of ROM loading +-------------------------------------------------*/ + +static void display_rom_load_results(rom_load_data *romdata) +{ + /* final status display */ + display_loading_rom_message(romdata, NULL); + + /* if we had errors, they are fatal */ + if (romdata->errors != 0) + { + /* create the error message and exit fatally */ + mame_printf_error("%s", romdata->errorstring.cstr()); + fatalerror_exitcode(romdata->machine(), MAMERR_MISSING_FILES, "ERROR: required files are missing, the "GAMENOUN" cannot be run."); + } + + /* if we had warnings, output them, but continue */ + if ((romdata-> warnings) || (romdata->knownbad)) + { + romdata->errorstring.cat("WARNING: the "GAMENOUN" might not run correctly."); + mame_printf_warning("%s\n", romdata->errorstring.cstr()); + } +} + + +/*------------------------------------------------- + region_post_process - post-process a region, + byte swapping and inverting data as necessary +-------------------------------------------------*/ + +static void region_post_process(rom_load_data *romdata, const char *rgntag, bool invert) +{ + const memory_region *region = romdata->machine().region(rgntag); + UINT8 *base; + int i, j; + + // do nothing if no region + if (region == NULL) + return; + + LOG(("+ datawidth=%d little=%d\n", region->width(), region->endianness() == ENDIANNESS_LITTLE)); + + /* if the region is inverted, do that now */ + if (invert) + { + LOG(("+ Inverting region\n")); + for (i = 0, base = region->base(); i < region->bytes(); i++) + *base++ ^= 0xff; + } + + /* swap the endianness if we need to */ + if (region->width() > 1 && region->endianness() != ENDIANNESS_NATIVE) + { + LOG(("+ Byte swapping region\n")); + int datawidth = region->width(); + for (i = 0, base = region->base(); i < region->bytes(); i += datawidth) + { + UINT8 temp[8]; + memcpy(temp, base, datawidth); + for (j = datawidth - 1; j >= 0; j--) + *base++ = temp[j]; + } + } +} + + +/*------------------------------------------------- + open_rom_file - open a ROM file, searching + up the parent and loading by checksum +-------------------------------------------------*/ + +static int open_rom_file(rom_load_data *romdata, const char *regiontag, const rom_entry *romp) +{ + file_error filerr = FILERR_NOT_FOUND; + UINT32 romsize = rom_file_size(romp); + + /* update status display */ + display_loading_rom_message(romdata, ROM_GETNAME(romp)); + + /* extract CRC to use for searching */ + UINT32 crc = 0; + bool has_crc = hash_collection(ROM_GETHASHDATA(romp)).crc(crc); + + /* attempt reading up the chain through the parents. It automatically also + attempts any kind of load by checksum supported by the archives. */ + romdata->file = NULL; + for (int drv = driver_list::find(romdata->machine().system()); romdata->file == NULL && drv != -1; drv = driver_list::clone(drv)) + filerr = common_process_file(romdata->machine().options(), driver_list::driver(drv).name, has_crc, crc, romp, &romdata->file); + + /* if the region is load by name, load the ROM from there */ + if (romdata->file == NULL && regiontag != NULL) + { + // check if we are dealing with softwarelists. if so, locationtag + // is actually a concatenation of: listname + setname + parentname + // separated by '%' (parentname being present only for clones) + astring tag1(regiontag), tag2, tag3, tag4, tag5; + bool is_list = FALSE; + bool has_parent = FALSE; + + int separator1 = tag1.chr(0, '%'); + if (separator1 != -1) + { + is_list = TRUE; + + // we are loading through softlists, split the listname from the regiontag + tag4.cpysubstr(tag1, separator1 + 1, tag1.len() - separator1 + 1); + tag1.del(separator1, tag1.len() - separator1); + tag1.cat(PATH_SEPARATOR); + + // check if we are loading a clone (if this is the case also tag1 have a separator '%') + int separator2 = tag4.chr(0, '%'); + if (separator2 != -1) + { + has_parent = TRUE; + + // we are loading a clone through softlists, split the setname from the parentname + tag5.cpysubstr(tag4, separator2 + 1, tag4.len() - separator2 + 1); + tag4.del(separator2, tag4.len() - separator2); + } + + // prepare locations where we have to load from: list/parentname & list/clonename + astring swlist(tag1.cstr()); + tag2.cpy(swlist.cat(tag4)); + if (has_parent) + { + swlist.cpy(tag1); + tag3.cpy(swlist.cat(tag5)); + } + } + + if (tag5.chr(0, '%') != -1) + fatalerror("We do not support clones of clones!\n"); + + // try to load from the available location(s): + // - if we are not using lists, we have regiontag only; + // - if we are using lists, we have: list/clonename, list/parentname, clonename, parentname + if (!is_list) + filerr = common_process_file(romdata->machine().options(), tag1.cstr(), has_crc, crc, romp, &romdata->file); + else + { + // try to load from list/setname + if ((romdata->file == NULL) && (tag2.cstr() != NULL)) + filerr = common_process_file(romdata->machine().options(), tag2.cstr(), has_crc, crc, romp, &romdata->file); + // try to load from list/parentname + if ((romdata->file == NULL) && has_parent && (tag3.cstr() != NULL)) + filerr = common_process_file(romdata->machine().options(), tag3.cstr(), has_crc, crc, romp, &romdata->file); + // try to load from setname + if ((romdata->file == NULL) && (tag4.cstr() != NULL)) + filerr = common_process_file(romdata->machine().options(), tag4.cstr(), has_crc, crc, romp, &romdata->file); + // try to load from parentname + if ((romdata->file == NULL) && has_parent && (tag5.cstr() != NULL)) + filerr = common_process_file(romdata->machine().options(), tag5.cstr(), has_crc, crc, romp, &romdata->file); + } + } + + /* update counters */ + romdata->romsloaded++; + romdata->romsloadedsize += romsize; + + /* return the result */ + return (filerr == FILERR_NONE); +} + + +/*------------------------------------------------- + rom_fread - cheesy fread that fills with + random data for a NULL file +-------------------------------------------------*/ + +static int rom_fread(rom_load_data *romdata, UINT8 *buffer, int length) +{ + /* files just pass through */ + if (romdata->file != NULL) + return romdata->file->read(buffer, length); + + /* otherwise, fill with randomness */ + else + fill_random(romdata->machine(), buffer, length); + + return length; +} + + +/*------------------------------------------------- + read_rom_data - read ROM data for a single + entry +-------------------------------------------------*/ + +static int read_rom_data(rom_load_data *romdata, const rom_entry *romp) +{ + int datashift = ROM_GETBITSHIFT(romp); + int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift; + int numbytes = ROM_GETLENGTH(romp); + int groupsize = ROM_GETGROUPSIZE(romp); + int skip = ROM_GETSKIPCOUNT(romp); + int reversed = ROM_ISREVERSED(romp); + int numgroups = (numbytes + groupsize - 1) / groupsize; + UINT8 *base = romdata->region->base() + ROM_GETOFFSET(romp); + UINT32 tempbufsize; + UINT8 *tempbuf; + int i; + + LOG(("Loading ROM data: offs=%X len=%X mask=%02X group=%d skip=%d reverse=%d\n", ROM_GETOFFSET(romp), numbytes, datamask, groupsize, skip, reversed)); + + /* make sure the length was an even multiple of the group size */ + if (numbytes % groupsize != 0) + mame_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", ROM_GETNAME(romp)); + + /* make sure we only fill within the region space */ + if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > romdata->region->bytes()) + fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp)); + + /* make sure the length was valid */ + if (numbytes == 0) + fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp)); + + /* special case for simple loads */ + if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0) + return rom_fread(romdata, base, numbytes); + + /* use a temporary buffer for complex loads */ + tempbufsize = MIN(TEMPBUFFER_MAX_SIZE, numbytes); + tempbuf = auto_alloc_array(romdata->machine(), UINT8, tempbufsize); + + /* chunky reads for complex loads */ + skip += groupsize; + while (numbytes > 0) + { + int evengroupcount = (tempbufsize / groupsize) * groupsize; + int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes; + UINT8 *bufptr = tempbuf; + + /* read as much as we can */ + LOG((" Reading %X bytes into buffer\n", bytesleft)); + if (rom_fread(romdata, bufptr, bytesleft) != bytesleft) + { + auto_free(romdata->machine(), tempbuf); + return 0; + } + numbytes -= bytesleft; + + LOG((" Copying to %p\n", base)); + + /* unmasked cases */ + if (datamask == 0xff) + { + /* non-grouped data */ + if (groupsize == 1) + for (i = 0; i < bytesleft; i++, base += skip) + *base = *bufptr++; + + /* grouped data -- non-reversed case */ + else if (!reversed) + while (bytesleft) + { + for (i = 0; i < groupsize && bytesleft; i++, bytesleft--) + base[i] = *bufptr++; + base += skip; + } + + /* grouped data -- reversed case */ + else + while (bytesleft) + { + for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) + base[i] = *bufptr++; + base += skip; + } + } + + /* masked cases */ + else + { + /* non-grouped data */ + if (groupsize == 1) + for (i = 0; i < bytesleft; i++, base += skip) + *base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask); + + /* grouped data -- non-reversed case */ + else if (!reversed) + while (bytesleft) + { + for (i = 0; i < groupsize && bytesleft; i++, bytesleft--) + base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask); + base += skip; + } + + /* grouped data -- reversed case */ + else + while (bytesleft) + { + for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--) + base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask); + base += skip; + } + } + } + auto_free(romdata->machine(), tempbuf); + + LOG((" All done\n")); + return ROM_GETLENGTH(romp); +} + + +/*------------------------------------------------- + fill_rom_data - fill a region of ROM space +-------------------------------------------------*/ + +static void fill_rom_data(rom_load_data *romdata, const rom_entry *romp) +{ + UINT32 numbytes = ROM_GETLENGTH(romp); + UINT8 *base = romdata->region->base() + ROM_GETOFFSET(romp); + + /* make sure we fill within the region space */ + if (ROM_GETOFFSET(romp) + numbytes > romdata->region->bytes()) + fatalerror("Error in RomModule definition: FILL out of memory region space\n"); + + /* make sure the length was valid */ + if (numbytes == 0) + fatalerror("Error in RomModule definition: FILL has an invalid length\n"); + + /* fill the data (filling value is stored in place of the hashdata) */ + memset(base, (FPTR)ROM_GETHASHDATA(romp) & 0xff, numbytes); +} + + +/*------------------------------------------------- + copy_rom_data - copy a region of ROM space +-------------------------------------------------*/ + +static void copy_rom_data(rom_load_data *romdata, const rom_entry *romp) +{ + UINT8 *base = romdata->region->base() + ROM_GETOFFSET(romp); + const char *srcrgntag = ROM_GETNAME(romp); + UINT32 numbytes = ROM_GETLENGTH(romp); + UINT32 srcoffs = (FPTR)ROM_GETHASHDATA(romp); /* srcoffset in place of hashdata */ + + /* make sure we copy within the region space */ + if (ROM_GETOFFSET(romp) + numbytes > romdata->region->bytes()) + fatalerror("Error in RomModule definition: COPY out of target memory region space\n"); + + /* make sure the length was valid */ + if (numbytes == 0) + fatalerror("Error in RomModule definition: COPY has an invalid length\n"); + + /* make sure the source was valid */ + const memory_region *region = romdata->machine().region(srcrgntag); + if (region == NULL) + fatalerror("Error in RomModule definition: COPY from an invalid region\n"); + + /* make sure we find within the region space */ + if (srcoffs + numbytes > region->bytes()) + fatalerror("Error in RomModule definition: COPY out of source memory region space\n"); + + /* fill the data */ + memcpy(base, region->base() + srcoffs, numbytes); +} + + +/*------------------------------------------------- + process_rom_entries - process all ROM entries + for a region +-------------------------------------------------*/ + +static void process_rom_entries(rom_load_data *romdata, const char *regiontag, const rom_entry *romp) +{ + UINT32 lastflags = 0; + + /* loop until we hit the end of this region */ + while (!ROMENTRY_ISREGIONEND(romp)) + { + /* if this is a continue entry, it's invalid */ + if (ROMENTRY_ISCONTINUE(romp)) + fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n"); + + /* if this is an ignore entry, it's invalid */ + if (ROMENTRY_ISIGNORE(romp)) + fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n"); + + /* if this is a reload entry, it's invalid */ + if (ROMENTRY_ISRELOAD(romp)) + fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n"); + + /* handle fills */ + if (ROMENTRY_ISFILL(romp)) + fill_rom_data(romdata, romp++); + + /* handle copies */ + else if (ROMENTRY_ISCOPY(romp)) + copy_rom_data(romdata, romp++); + + /* handle files */ + else if (ROMENTRY_ISFILE(romp)) + { + int irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0 && ROM_GETBIOSFLAGS(romp) != romdata->system_bios); + const rom_entry *baserom = romp; + int explength = 0; + + /* open the file if it is a non-BIOS or matches the current BIOS */ + LOG(("Opening ROM file: %s\n", ROM_GETNAME(romp))); + if (!irrelevantbios && !open_rom_file(romdata, regiontag, romp)) + handle_missing_file(romdata, romp); + + /* loop until we run out of reloads */ + do + { + /* loop until we run out of continues/ignores */ + do + { + rom_entry modified_romp = *romp++; + //int readresult; + + /* handle flag inheritance */ + if (!ROM_INHERITSFLAGS(&modified_romp)) + lastflags = modified_romp._flags; + else + modified_romp._flags = (modified_romp._flags & ~ROM_INHERITEDFLAGS) | lastflags; + + explength += ROM_GETLENGTH(&modified_romp); + + /* attempt to read using the modified entry */ + if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios) + /*readresult = */read_rom_data(romdata, &modified_romp); + } + while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp)); + + /* if this was the first use of this file, verify the length and CRC */ + if (baserom) + { + LOG(("Verifying length (%X) and checksums\n", explength)); + verify_length_and_hash(romdata, ROM_GETNAME(baserom), explength, hash_collection(ROM_GETHASHDATA(baserom))); + LOG(("Verify finished\n")); + } + + /* reseek to the start and clear the baserom so we don't reverify */ + if (romdata->file != NULL) + romdata->file->seek(0, SEEK_SET); + baserom = NULL; + explength = 0; + } + while (ROMENTRY_ISRELOAD(romp)); + + /* close the file */ + if (romdata->file != NULL) + { + LOG(("Closing ROM file\n")); + global_free(romdata->file); + romdata->file = NULL; + } + } + else + { + romp++; /* something else; skip */ + } + } +} + + +/*------------------------------------------------- + open_disk_image - open a disk image, + searching up the parent and loading by + checksum +-------------------------------------------------*/ + +chd_error open_disk_image(emu_options &options, const game_driver *gamedrv, const rom_entry *romp, emu_file **image_file, chd_file **image_chd, const char *locationtag) +{ + const rom_entry *region, *rom; + const rom_source *source; + file_error filerr; + chd_error err; + + *image_file = NULL; + *image_chd = NULL; + + /* attempt to open the properly named file, scanning up through parent directories */ + filerr = FILERR_NOT_FOUND; + for (int searchdrv = driver_list::find(*gamedrv); searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", romp, image_file); + + if (filerr != FILERR_NONE) + filerr = common_process_file(options, NULL, ".chd", romp, image_file); + + /* look for the disk in the locationtag too */ + if (filerr != FILERR_NONE && locationtag != NULL) + { + // check if we are dealing with softwarelists. if so, locationtag + // is actually a concatenation of: listname + setname + parentname + // separated by '%' (parentname being present only for clones) + astring tag1(locationtag), tag2, tag3, tag4, tag5; + bool is_list = FALSE; + bool has_parent = FALSE; + + int separator1 = tag1.chr(0, '%'); + if (separator1 != -1) + { + is_list = TRUE; + + // we are loading through softlists, split the listname from the regiontag + tag4.cpysubstr(tag1, separator1 + 1, tag1.len() - separator1 + 1); + tag1.del(separator1, tag1.len() - separator1); + tag1.cat(PATH_SEPARATOR); + + // check if we are loading a clone (if this is the case also tag1 have a separator '%') + int separator2 = tag4.chr(0, '%'); + if (separator2 != -1) + { + has_parent = TRUE; + + // we are loading a clone through softlists, split the setname from the parentname + tag5.cpysubstr(tag4, separator2 + 1, tag4.len() - separator2 + 1); + tag4.del(separator2, tag4.len() - separator2); + } + + // prepare locations where we have to load from: list/parentname (if any) & list/clonename + astring swlist(tag1.cstr()); + tag2.cpy(swlist.cat(tag4)); + if (has_parent) + { + swlist.cpy(tag1); + tag3.cpy(swlist.cat(tag5)); + } + } + + if (tag5.chr(0, '%') != -1) + fatalerror("We do not support clones of clones!\n"); + + // try to load from the available location(s): + // - if we are not using lists, we have locationtag only; + // - if we are using lists, we have: list/clonename, list/parentname, clonename, parentname + if (!is_list) + filerr = common_process_file(options, locationtag, ".chd", romp, image_file); + else + { + // try to load from list/setname + if ((filerr != FILERR_NONE) && (tag2.cstr() != NULL)) + filerr = common_process_file(options, tag2.cstr(), ".chd", romp, image_file); + // try to load from list/parentname (if any) + if ((filerr != FILERR_NONE) && has_parent && (tag3.cstr() != NULL)) + filerr = common_process_file(options, tag3.cstr(), ".chd", romp, image_file); + // try to load from setname + if ((filerr != FILERR_NONE) && (tag4.cstr() != NULL)) + filerr = common_process_file(options, tag4.cstr(), ".chd", romp, image_file); + // try to load from parentname (if any) + if ((filerr != FILERR_NONE) && has_parent && (tag5.cstr() != NULL)) + filerr = common_process_file(options, tag5.cstr(), ".chd", romp, image_file); + // only for CHD we also try to load from list/ + if ((filerr != FILERR_NONE) && (tag1.cstr() != NULL)) + { + tag1.del(tag1.len() - 1, 1); // remove the PATH_SEPARATOR + filerr = common_process_file(options, tag1.cstr(), ".chd", romp, image_file); + } + } + } + + /* did the file open succeed? */ + if (filerr == FILERR_NONE) + { + /* try to open the CHD */ + err = chd_open_file(**image_file, CHD_OPEN_READ, NULL, image_chd); + if (err == CHDERR_NONE) + return err; + + /* close the file on failure */ + global_free(*image_file); + *image_file = NULL; + } + else + err = CHDERR_FILE_NOT_FOUND; + + /* otherwise, look at our parents for a CHD with an identical checksum */ + /* and try to open that */ + hash_collection romphashes(ROM_GETHASHDATA(romp)); + for (int drv = driver_list::find(*gamedrv); drv != -1; drv = driver_list::clone(drv)) + { + machine_config config(driver_list::driver(drv), options); + for (source = rom_first_source(config); source != NULL; source = rom_next_source(*source)) + for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + if (ROMREGION_ISDISKDATA(region)) + for (rom = rom_first_file(region); rom != NULL; rom = rom_next_file(rom)) + + /* look for a differing name but with the same hash data */ + if (strcmp(ROM_GETNAME(romp), ROM_GETNAME(rom)) != 0 && + romphashes == hash_collection(ROM_GETHASHDATA(rom))) + { + /* attempt to open the properly named file, scanning up through parent directories */ + filerr = FILERR_NOT_FOUND; + for (int searchdrv = drv; searchdrv != -1 && filerr != FILERR_NONE; searchdrv = driver_list::clone(searchdrv)) + filerr = common_process_file(options, driver_list::driver(searchdrv).name, ".chd", rom, image_file); + + if (filerr != FILERR_NONE) + filerr = common_process_file(options, NULL, ".chd", rom, image_file); + + /* did the file open succeed? */ + if (filerr == FILERR_NONE) + { + /* try to open the CHD */ + err = chd_open_file(**image_file, CHD_OPEN_READ, NULL, image_chd); + if (err == CHDERR_NONE) + return err; + + /* close the file on failure */ + global_free(*image_file); + *image_file = NULL; + } + } + } + + return err; +} + + +/*------------------------------------------------- + open_disk_diff - open a DISK diff file +-------------------------------------------------*/ + +static chd_error open_disk_diff(emu_options &options, const rom_entry *romp, chd_file *source, emu_file **diff_file, chd_file **diff_chd) +{ + astring fname(ROM_GETNAME(romp), ".dif"); + chd_error err; + + *diff_file = NULL; + *diff_chd = NULL; + + /* try to open the diff */ + LOG(("Opening differencing image file: %s\n", fname.cstr())); + *diff_file = global_alloc(emu_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE)); + file_error filerr = (*diff_file)->open(fname); + if (filerr != FILERR_NONE) + { + /* didn't work; try creating it instead */ + LOG(("Creating differencing image: %s\n", fname.cstr())); + (*diff_file)->set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + filerr = (*diff_file)->open(fname); + if (filerr != FILERR_NONE) + { + err = CHDERR_FILE_NOT_FOUND; + goto done; + } + + /* create the CHD */ + err = chd_create_file(**diff_file, 0, 0, CHDCOMPRESSION_NONE, source); + if (err != CHDERR_NONE) + goto done; + } + + LOG(("Opening differencing image file: %s\n", fname.cstr())); + err = chd_open_file(**diff_file, CHD_OPEN_READWRITE, source, diff_chd); + if (err != CHDERR_NONE) + goto done; + +done: + if ((err != CHDERR_NONE) && (*diff_file != NULL)) + { + global_free(*diff_file); + *diff_file = NULL; + } + return err; +} + + +/*------------------------------------------------- + process_disk_entries - process all disk entries + for a region +-------------------------------------------------*/ + +static void process_disk_entries(rom_load_data *romdata, const char *regiontag, const rom_entry *romp, const char *locationtag) +{ + /* loop until we hit the end of this region */ + for ( ; !ROMENTRY_ISREGIONEND(romp); romp++) + { + /* handle files */ + if (ROMENTRY_ISFILE(romp)) + { + hash_collection hashes(ROM_GETHASHDATA(romp)); + open_chd chd = { 0 }; + chd_header header; + chd_error err; + + /* note the region we are in */ + chd.region = regiontag; + + /* make the filename of the source */ + astring filename(ROM_GETNAME(romp), ".chd"); + + /* first open the source drive */ + LOG(("Opening disk image: %s\n", filename.cstr())); + err = open_disk_image(romdata->machine().options(), &romdata->machine().system(), romp, &chd.origfile, &chd.origchd, locationtag); + if (err != CHDERR_NONE) + { + if (err == CHDERR_FILE_NOT_FOUND) + romdata->errorstring.catprintf("%s NOT FOUND\n", filename.cstr()); + else + romdata->errorstring.catprintf("%s CHD ERROR: %s\n", filename.cstr(), chd_error_string(err)); + + /* if this is NO_DUMP, keep going, though the system may not be able to handle it */ + if (hashes.flag(hash_collection::FLAG_NO_DUMP)) + romdata->knownbad++; + else if (DISK_ISOPTIONAL(romp)) + romdata->warnings++; + else + romdata->errors++; + continue; + } + + /* get the header and extract the SHA1 */ + header = *chd_get_header(chd.origchd); + hash_collection acthashes; + acthashes.add_from_buffer(hash_collection::HASH_SHA1, header.sha1, sizeof(header.sha1)); + + /* verify the hash */ + if (hashes != acthashes) + { + romdata->errorstring.catprintf("%s WRONG CHECKSUMS:\n", filename.cstr()); + dump_wrong_and_correct_checksums(romdata, hashes, acthashes); + romdata->warnings++; + } + else if (hashes.flag(hash_collection::FLAG_BAD_DUMP)) + { + romdata->errorstring.catprintf("%s CHD NEEDS REDUMP\n", filename.cstr()); + romdata->knownbad++; + } + + /* if not read-only, make the diff file */ + if (!DISK_ISREADONLY(romp)) + { + /* try to open or create the diff */ + err = open_disk_diff(romdata->machine().options(), romp, chd.origchd, &chd.difffile, &chd.diffchd); + if (err != CHDERR_NONE) + { + romdata->errorstring.catprintf("%s DIFF CHD ERROR: %s\n", filename.cstr(), chd_error_string(err)); + romdata->errors++; + continue; + } + } + + /* we're okay, add to the list of disks */ + LOG(("Assigning to handle %d\n", DISK_GETINDEX(romp))); + add_disk_handle(romdata->machine(), &chd); + } + } +} + + +/*------------------------------------------------- + normalize_flags_for_device - modify the region + flags for the given device +-------------------------------------------------*/ + +static void normalize_flags_for_device(running_machine &machine, const char *rgntag, UINT8 &width, endianness_t &endian) +{ + device_t *device = machine.device(rgntag); + device_memory_interface *memory; + if (device->interface(memory)) + { + const address_space_config *spaceconfig = memory->space_config(); + if (spaceconfig != NULL) + { + int buswidth; + + /* set the endianness */ + if (spaceconfig->m_endianness == ENDIANNESS_LITTLE) + endian = ENDIANNESS_LITTLE; + else + endian = ENDIANNESS_BIG; + + /* set the width */ + buswidth = spaceconfig->m_databus_width; + if (buswidth <= 8) + width = 1; + else if (buswidth <= 16) + width = 2; + else if (buswidth <= 32) + width = 4; + else + width = 8; + } + } +} + + +/*------------------------------------------------- + load_software_part_region - load a software part + + This is used by MESS when loading a piece of + software. The code should be merged with + process_region_list or updated to use a slight + more general process_region_list. +-------------------------------------------------*/ + +void load_software_part_region(device_t *device, char *swlist, char *swname, rom_entry *start_region) +{ + astring locationtag(swlist), breakstr("%"); + rom_load_data *romdata = device->machine().romload_data; + const rom_entry *region; + astring regiontag; + + // attempt reading up the chain through the parents and create a locationtag astring in the format + // " swlist % clonename % parentname " + // open_rom_file contains the code to split the elements and to create paths to load from + + software_list *software_list_ptr = software_list_open(device->machine().options(), swlist, FALSE, NULL); + if (software_list_ptr) + { + locationtag.cat(breakstr); + + for (software_info *swinfo = software_list_find(software_list_ptr, swname, NULL); swinfo != NULL; ) + { + { + astring tmp(swinfo->shortname); + locationtag.cat(tmp); + locationtag.cat(breakstr); + // printf("%s\n", locationtag.cstr()); + } + const char *parentname = software_get_clone(device->machine().options(), swlist, swinfo->shortname); + if (parentname != NULL) + swinfo = software_list_find(software_list_ptr, parentname, NULL); + else + swinfo = NULL; + } + // strip the final '%' + locationtag.del(locationtag.len() - 1, 1); + software_list_close(software_list_ptr); + } + + /* Make sure we are passed a device */ + assert(device != NULL); + + romdata->errorstring.reset(); + + if (software_get_support(device->machine().options(), swlist, swname) == SOFTWARE_SUPPORTED_PARTIAL) + { + romdata->errorstring.catprintf("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist); + romdata->warnings++; + } + if (software_get_support(device->machine().options(), swlist, swname) == SOFTWARE_SUPPORTED_NO) + { + romdata->errorstring.catprintf("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist); + romdata->warnings++; + } + + /* loop until we hit the end */ + for (region = start_region; region != NULL; region = rom_next_region(region)) + { + UINT32 regionlength = ROMREGION_GETLENGTH(region); + + device->subtag(regiontag, ROMREGION_GETTAG(region)); + LOG(("Processing region \"%s\" (length=%X)\n", regiontag.cstr(), regionlength)); + + /* the first entry must be a region */ + assert(ROMENTRY_ISREGION(region)); + + /* if this is a device region, override with the device width and endianness */ + endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + UINT8 width = ROMREGION_GETWIDTH(region) / 8; + const memory_region *memregion = romdata->machine().region(regiontag); + if (memregion != NULL) + { + if (romdata->machine().device(regiontag) != NULL) + normalize_flags_for_device(romdata->machine(), regiontag, width, endianness); + + /* clear old region (todo: should be moved to an image unload function) */ + romdata->machine().region_free(memregion->name()); + } + + /* remember the base and length */ + romdata->region = romdata->machine().region_alloc(regiontag, regionlength, width, endianness); + LOG(("Allocated %X bytes @ %p\n", romdata->region->bytes(), romdata->region->base())); + + /* clear the region if it's requested */ + if (ROMREGION_ISERASE(region)) + memset(romdata->region->base(), ROMREGION_GETERASEVAL(region), romdata->region->bytes()); + + /* or if it's sufficiently small (<= 4MB) */ + else if (romdata->region->bytes() <= 0x400000) + memset(romdata->region->base(), 0, romdata->region->bytes()); + +#ifdef MAME_DEBUG + /* if we're debugging, fill region with random data to catch errors */ + else + fill_random(romdata->machine(), romdata->region->base(), romdata->region->bytes()); +#endif + + /* now process the entries in the region */ + if (ROMREGION_ISROMDATA(region)) + process_rom_entries(romdata, locationtag, region + 1); + else if (ROMREGION_ISDISKDATA(region)) + process_disk_entries(romdata, core_strdup(regiontag.cstr()), region + 1, locationtag); + } + + /* now go back and post-process all the regions */ + for (region = start_region; region != NULL; region = rom_next_region(region)) { + device->subtag(regiontag, ROMREGION_GETTAG(region)); + region_post_process(romdata, regiontag.cstr(), ROMREGION_ISINVERTED(region)); + } + + /* display the results and exit */ + display_rom_load_results(romdata); +} + + +/*------------------------------------------------- + process_region_list - process a region list +-------------------------------------------------*/ + +static void process_region_list(rom_load_data *romdata) +{ + astring regiontag; + const rom_source *source; + const rom_entry *region; + + /* loop until we hit the end */ + for (source = rom_first_source(romdata->machine().config()); source != NULL; source = rom_next_source(*source)) + for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) + { + UINT32 regionlength = ROMREGION_GETLENGTH(region); + + rom_region_name(regiontag, &romdata->machine().system(), source, region); + LOG(("Processing region \"%s\" (length=%X)\n", regiontag.cstr(), regionlength)); + + /* the first entry must be a region */ + assert(ROMENTRY_ISREGION(region)); + + if (ROMREGION_ISROMDATA(region)) + { + /* if this is a device region, override with the device width and endianness */ + UINT8 width = ROMREGION_GETWIDTH(region) / 8; + endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + if (romdata->machine().device(regiontag) != NULL) + normalize_flags_for_device(romdata->machine(), regiontag, width, endianness); + + /* remember the base and length */ + romdata->region = romdata->machine().region_alloc(regiontag, regionlength, width, endianness); + LOG(("Allocated %X bytes @ %p\n", romdata->region->bytes(), romdata->region->base())); + + /* clear the region if it's requested */ + if (ROMREGION_ISERASE(region)) + memset(romdata->region->base(), ROMREGION_GETERASEVAL(region), romdata->region->bytes()); + + /* or if it's sufficiently small (<= 4MB) */ + else if (romdata->region->bytes() <= 0x400000) + memset(romdata->region->base(), 0, romdata->region->bytes()); + +#ifdef MAME_DEBUG + /* if we're debugging, fill region with random data to catch errors */ + else + fill_random(romdata->machine(), romdata->region->base(), romdata->region->bytes()); +#endif + + /* now process the entries in the region */ + process_rom_entries(romdata, (source->shortname()!=NULL) ? source->shortname() : NULL, region + 1); + } + else if (ROMREGION_ISDISKDATA(region)) + process_disk_entries(romdata, ROMREGION_GETTAG(region), region + 1, NULL); + } + + /* now go back and post-process all the regions */ + for (source = rom_first_source(romdata->machine().config()); source != NULL; source = rom_next_source(*source)) + for (region = rom_first_region(*source); region != NULL; region = rom_next_region(region)) { + rom_region_name(regiontag, &romdata->machine().system(), source, region); + region_post_process(romdata, regiontag, ROMREGION_ISINVERTED(region)); + } +} + + +/*------------------------------------------------- + rom_init - load the ROMs and open the disk + images associated with the given machine +-------------------------------------------------*/ + +void rom_init(running_machine &machine) +{ + rom_load_data *romdata; + + /* allocate private data */ + machine.romload_data = romdata = auto_alloc_clear(machine, romload_private); + + /* make sure we get called back on the way out */ + machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(rom_exit), &machine)); + + /* reset the romdata struct */ + romdata->m_machine = &machine; + + /* figure out which BIOS we are using */ + determine_bios_rom(romdata); + + /* count the total number of ROMs */ + count_roms(romdata); + + /* reset the disk list */ + romdata->chd_list = NULL; + romdata->chd_list_tailptr = &machine.romload_data->chd_list; + + /* process the ROM entries we were passed */ + process_region_list(romdata); + + /* display the results and exit */ + display_rom_load_results(romdata); +} + + +/*------------------------------------------------- + rom_exit - clean up after ourselves +-------------------------------------------------*/ + +static void rom_exit(running_machine &machine) +{ + open_chd *curchd; + + /* close all hard drives */ + for (curchd = machine.romload_data->chd_list; curchd != NULL; curchd = curchd->next) + { + if (curchd->diffchd != NULL) + chd_close(curchd->diffchd); + if (curchd->difffile != NULL) + global_free(curchd->difffile); + if (curchd->origchd != NULL) + chd_close(curchd->origchd); + if (curchd->origfile != NULL) + global_free(curchd->origfile); + } +} + + +/*------------------------------------------------- + rom_load_warnings - return the number of + warnings we generated +-------------------------------------------------*/ + +int rom_load_warnings(running_machine &machine) +{ + return machine.romload_data->warnings; +} + + +/*------------------------------------------------- + rom_load_knownbad - return the number of + BAD_DUMP/NO_DUMP warnings we generated +-------------------------------------------------*/ + +int rom_load_knownbad(running_machine &machine) +{ + return machine.romload_data->knownbad; +} + + +/*------------------------------------------------- + rom_system_bios - return id of selected bios +-------------------------------------------------*/ + +int rom_system_bios(running_machine &machine) +{ + return machine.romload_data->system_bios; +} + +/*------------------------------------------------- + rom_default_bios - return id of default bios +-------------------------------------------------*/ + +int rom_default_bios(running_machine &machine) +{ + return machine.romload_data->default_bios; +} |