1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria,Paul Priest,Aaron Giles,Vas Crabb
3 /*********************************************************************
4
5 romload.cpp
6
7 ROM loading functions.
8
9 *********************************************************************/
10
11 #include "emu.h"
12 #include "romload.h"
13
14 #include "emuopts.h"
15 #include "drivenum.h"
16 #include "softlist_dev.h"
17 #include "ui/uimain.h"
18
19 #include <algorithm>
20 #include <set>
21
22
23 #define LOG_LOAD 0
24 #define LOG(...) do { if (LOG_LOAD) debugload(__VA_ARGS__); } while(0)
25
26
27 /***************************************************************************
28 CONSTANTS
29 ***************************************************************************/
30
31 #define TEMPBUFFER_MAX_SIZE (1024 * 1024 * 1024)
32
33 /***************************************************************************
34 HELPERS
35 ****************************************************************************/
36
37 namespace {
38
next_parent_system(game_driver const & system)39 auto next_parent_system(game_driver const &system)
40 {
41 return
42 [sys = &system, roms = std::vector<rom_entry>()] () mutable -> rom_entry const *
43 {
44 if (!sys)
45 return nullptr;
46 int const parent(driver_list::find(sys->parent));
47 if (0 > parent)
48 {
49 sys = nullptr;
50 return nullptr;
51 }
52 else
53 {
54 sys = &driver_list::driver(parent);
55 roms = rom_build_entries(sys->rom);
56 return &roms[0];
57 }
58 };
59 }
60
61
next_parent_software(std::vector<software_info const * > const & parents)62 auto next_parent_software(std::vector<software_info const *> const &parents)
63 {
64 auto part(parents.front()->parts().end());
65 return
66 [&parents, current = parents.cbegin(), part, end = part] () mutable -> const rom_entry *
67 {
68 if (part == end)
69 {
70 if (parents.end() == current)
71 return nullptr;
72 part = (*current)->parts().cbegin();
73 end = (*current)->parts().cend();
74 do { ++current; } while ((parents.cend() != current) && (*current)->parts().empty());
75 }
76 return &(*part++).romdata()[0];
77 };
78 }
79
80
make_software_searchpath(software_list_device & swlist,software_info const & swinfo,std::vector<software_info const * > & parents)81 std::vector<std::string> make_software_searchpath(software_list_device &swlist, software_info const &swinfo, std::vector<software_info const *> &parents)
82 {
83 std::vector<std::string> result;
84
85 // search <rompath>/<list>/<software> following parents
86 for (software_info const *i = &swinfo; i; )
87 {
88 if (std::find(parents.begin(), parents.end(), i) != parents.end())
89 break;
90 parents.emplace_back(i);
91 result.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), i->shortname()));
92 i = i->parentname().empty() ? nullptr : swlist.find(i->parentname());
93 }
94
95 // search <rompath>/<software> following parents
96 for (software_info const *i : parents)
97 result.emplace_back(i->shortname());
98
99 return result;
100 }
101
102
do_open_disk(const emu_options & options,std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const rom_entry * romp,chd_file & chd,std::function<const rom_entry * ()> next_parent)103 chd_error do_open_disk(const emu_options &options, std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, chd_file &chd, std::function<const rom_entry * ()> next_parent)
104 {
105 // hashes are fixed, but we might need to try multiple filenames
106 std::set<std::string> tried;
107 const util::hash_collection hashes(ROM_GETHASHDATA(romp));
108 std::string filename, fullpath;
109 const rom_entry *parent(nullptr);
110 chd_error result(CHDERR_FILE_NOT_FOUND);
111 while (romp && (CHDERR_NONE != result))
112 {
113 filename = ROM_GETNAME(romp);
114 filename.append(".chd");
115 if (tried.insert(filename).second)
116 {
117 // piggyback on emu_file to find the disk image file
118 std::unique_ptr<emu_file> imgfile;
119 for (const std::vector<std::string> &paths : searchpath)
120 {
121 imgfile.reset(new emu_file(options.media_path(), paths, OPEN_FLAG_READ));
122 imgfile->set_restrict_to_mediapath(1);
123 const osd_file::error filerr(imgfile->open(filename, OPEN_FLAG_READ));
124 if (osd_file::error::NONE == filerr)
125 break;
126 else
127 imgfile.reset();
128 }
129
130 // if we couldn't open a candidate file, report an error; otherwise reopen it as a CHD
131 if (imgfile)
132 {
133 fullpath = imgfile->fullpath();
134 imgfile.reset();
135 result = chd.open(fullpath.c_str());
136 }
137 }
138
139 // walk the parents looking for a CHD with the same hashes but a different name
140 if (CHDERR_NONE != result)
141 {
142 while (romp)
143 {
144 // find a file in a disk region
145 if (parent)
146 romp = rom_next_file(romp);
147 while (!parent || !romp)
148 {
149 if (!parent)
150 {
151 parent = next_parent();
152 if (!parent)
153 {
154 romp = nullptr;
155 break;
156 }
157 while (ROMENTRY_ISPARAMETER(parent) || ROMENTRY_ISSYSTEM_BIOS(parent) || ROMENTRY_ISDEFAULT_BIOS(parent))
158 ++parent;
159 if (ROMENTRY_ISEND(parent))
160 parent = nullptr;
161 }
162 else
163 {
164 parent = rom_next_region(parent);
165 }
166 while (parent && !ROMREGION_ISDISKDATA(parent))
167 parent = rom_next_region(parent);
168 if (parent)
169 romp = rom_first_file(parent);
170 }
171
172 // try it if it matches the hashes
173 if (romp && (util::hash_collection(ROM_GETHASHDATA(romp)) == hashes))
174 break;
175 }
176 }
177 }
178 return result;
179 }
180
181 } // anonymous namespace
182
183
184 /***************************************************************************
185 ROM LOADING
186 ***************************************************************************/
187
188 /*-------------------------------------------------
189 rom_first_region - return pointer to first ROM
190 region
191 -------------------------------------------------*/
192
rom_first_region(const device_t & device)193 const rom_entry *rom_first_region(const device_t &device)
194 {
195 return rom_first_region(&device.rom_region_vector().front());
196 }
197
rom_first_region(const rom_entry * romp)198 const rom_entry *rom_first_region(const rom_entry *romp)
199 {
200 while (ROMENTRY_ISPARAMETER(romp) || ROMENTRY_ISSYSTEM_BIOS(romp) || ROMENTRY_ISDEFAULT_BIOS(romp))
201 romp++;
202 return !ROMENTRY_ISEND(romp) ? romp : nullptr;
203 }
204
205
206 /*-------------------------------------------------
207 rom_next_region - return pointer to next ROM
208 region
209 -------------------------------------------------*/
210
rom_next_region(const rom_entry * romp)211 const rom_entry *rom_next_region(const rom_entry *romp)
212 {
213 romp++;
214 while (!ROMENTRY_ISREGIONEND(romp))
215 romp++;
216 while (ROMENTRY_ISPARAMETER(romp))
217 romp++;
218 return ROMENTRY_ISEND(romp) ? nullptr : romp;
219 }
220
221
222 /*-------------------------------------------------
223 rom_first_file - return pointer to first ROM
224 file
225 -------------------------------------------------*/
226
rom_first_file(const rom_entry * romp)227 const rom_entry *rom_first_file(const rom_entry *romp)
228 {
229 romp++;
230 while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
231 romp++;
232 return ROMENTRY_ISREGIONEND(romp) ? nullptr : romp;
233 }
234
235
236 /*-------------------------------------------------
237 rom_next_file - return pointer to next ROM
238 file
239 -------------------------------------------------*/
240
rom_next_file(const rom_entry * romp)241 const rom_entry *rom_next_file(const rom_entry *romp)
242 {
243 romp++;
244 while (!ROMENTRY_ISFILE(romp) && !ROMENTRY_ISREGIONEND(romp))
245 romp++;
246 return ROMENTRY_ISREGIONEND(romp) ? nullptr : romp;
247 }
248
249
250 /*-------------------------------------------------
251 rom_first_parameter - return pointer to the first
252 per-game parameter
253 -------------------------------------------------*/
254
rom_first_parameter(const device_t & device)255 const rom_entry *rom_first_parameter(const device_t &device)
256 {
257 const rom_entry *romp = &device.rom_region_vector().front();
258 while (romp && !ROMENTRY_ISEND(romp) && !ROMENTRY_ISPARAMETER(romp))
259 romp++;
260 return (romp != nullptr && !ROMENTRY_ISEND(romp)) ? romp : nullptr;
261 }
262
263
264 /*-------------------------------------------------
265 rom_next_parameter - return pointer to the next
266 per-game parameter
267 -------------------------------------------------*/
268
rom_next_parameter(const rom_entry * romp)269 const rom_entry *rom_next_parameter(const rom_entry *romp)
270 {
271 romp++;
272 while (!ROMENTRY_ISREGIONEND(romp) && !ROMENTRY_ISPARAMETER(romp))
273 romp++;
274 return ROMENTRY_ISEND(romp) ? nullptr : romp;
275 }
276
277
278 /*-------------------------------------------------
279 rom_file_size - return the expected size of a
280 file given the ROM description
281 -------------------------------------------------*/
282
rom_file_size(const rom_entry * romp)283 u32 rom_file_size(const rom_entry *romp)
284 {
285 u32 maxlength = 0;
286
287 /* loop until we run out of reloads */
288 do
289 {
290 /* loop until we run out of continues/ignores */
291 u32 curlength = ROM_GETLENGTH(romp++);
292 while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp))
293 curlength += ROM_GETLENGTH(romp++);
294
295 /* track the maximum length */
296 maxlength = std::max(maxlength, curlength);
297 }
298 while (ROMENTRY_ISRELOAD(romp));
299
300 return maxlength;
301 }
302
303
304 /*-------------------------------------------------
305 debugload - log data to a file
306 -------------------------------------------------*/
307
debugload(const char * string,...)308 static void CLIB_DECL ATTR_PRINTF(1,2) debugload(const char *string, ...)
309 {
310 static int opened;
311 va_list arg;
312 FILE *f;
313
314 f = fopen("romload.log", opened++ ? "a" : "w");
315 if (f)
316 {
317 va_start(arg, string);
318 vfprintf(f, string, arg);
319 va_end(arg);
320 fclose(f);
321 }
322 }
323
324
325 /***************************************************************************
326 HARD DISK HANDLING
327 ***************************************************************************/
328
329 /*-------------------------------------------------
330 get_disk_handle - return a pointer to the
331 CHD file associated with the given region
332 -------------------------------------------------*/
333
get_disk_handle(const char * region)334 chd_file *rom_load_manager::get_disk_handle(const char *region)
335 {
336 for (auto &curdisk : m_chd_list)
337 if (strcmp(curdisk->region(), region) == 0)
338 return &curdisk->chd();
339 return nullptr;
340 }
341
342
343 /*-------------------------------------------------
344 set_disk_handle - set a pointer to the CHD
345 file associated with the given region
346 -------------------------------------------------*/
347
set_disk_handle(const char * region,const char * fullpath)348 int rom_load_manager::set_disk_handle(const char *region, const char *fullpath)
349 {
350 auto chd = std::make_unique<open_chd>(region);
351 auto err = chd->orig_chd().open(fullpath);
352 if (err == CHDERR_NONE)
353 m_chd_list.push_back(std::move(chd));
354 return err;
355 }
356
357 /*-------------------------------------------------
358 determine_bios_rom - determine system_bios
359 from SystemBios structure and OPTION_BIOS
360 -------------------------------------------------*/
361
determine_bios_rom(device_t & device,const char * specbios)362 void rom_load_manager::determine_bios_rom(device_t &device, const char *specbios)
363 {
364 // default is applied by the device at config complete time
365 if (specbios && *specbios && core_stricmp(specbios, "default"))
366 {
367 bool found(false);
368 for (const rom_entry &rom : device.rom_region_vector())
369 {
370 if (ROMENTRY_ISSYSTEM_BIOS(&rom))
371 {
372 char const *const biosname = ROM_GETNAME(&rom);
373 int const bios_flags = ROM_GETBIOSFLAGS(&rom);
374 char bios_number[20];
375
376 // Allow '-bios n' to still be used
377 sprintf(bios_number, "%d", bios_flags - 1);
378 if (!core_stricmp(bios_number, specbios) || !core_stricmp(biosname, specbios))
379 {
380 found = true;
381 device.set_system_bios(bios_flags);
382 break;
383 }
384 }
385 }
386
387 // if we got neither an empty string nor 'default' then warn the user
388 if (!found)
389 {
390 m_errorstring.append(util::string_format("%s: invalid BIOS \"%s\", reverting to default\n", device.tag(), specbios));
391 m_warnings++;
392 }
393 }
394
395 // log final result
396 LOG("For \"%s\" using System BIOS: %d\n", device.tag(), device.system_bios());
397 }
398
399
400 /*-------------------------------------------------
401 count_roms - counts the total number of ROMs
402 that will need to be loaded
403 -------------------------------------------------*/
404
count_roms()405 void rom_load_manager::count_roms()
406 {
407 const rom_entry *region, *rom;
408
409 /* start with 0 */
410 m_romstotal = 0;
411 m_romstotalsize = 0;
412
413 /* loop over regions, then over files */
414 for (device_t &device : device_iterator(machine().config().root_device()))
415 for (region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
416 for (rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
417 if (ROM_GETBIOSFLAGS(rom) == 0 || ROM_GETBIOSFLAGS(rom) == device.system_bios())
418 {
419 m_romstotal++;
420 m_romstotalsize += rom_file_size(rom);
421 }
422 }
423
424
425 /*-------------------------------------------------
426 fill_random - fills an area of memory with
427 random data
428 -------------------------------------------------*/
429
fill_random(u8 * base,u32 length)430 void rom_load_manager::fill_random(u8 *base, u32 length)
431 {
432 while (length--)
433 *base++ = machine().rand();
434 }
435
436
437 /*-------------------------------------------------
438 handle_missing_file - handles error generation
439 for missing files
440 -------------------------------------------------*/
441
handle_missing_file(const rom_entry * romp,const std::vector<std::string> & tried_file_names,chd_error chderr)442 void rom_load_manager::handle_missing_file(const rom_entry *romp, const std::vector<std::string> &tried_file_names, chd_error chderr)
443 {
444 std::string tried;
445 if (!tried_file_names.empty())
446 {
447 tried = " (tried in";
448 for (const std::string &path : tried_file_names)
449 {
450 tried += ' ';
451 tried += path;
452 }
453 tried += ')';
454 }
455
456 std::string name(ROM_GETNAME(romp));
457
458 const bool is_chd(chderr != CHDERR_NONE);
459 if (is_chd)
460 name += ".chd";
461
462 const bool is_chd_error(is_chd && chderr != CHDERR_FILE_NOT_FOUND);
463 if (is_chd_error)
464 m_errorstring.append(string_format("%s CHD ERROR: %s\n", name.c_str(), chd_file::error_string(chderr)));
465
466 if (ROM_ISOPTIONAL(romp))
467 {
468 // optional files are okay
469 if (!is_chd_error)
470 m_errorstring.append(string_format("OPTIONAL %s NOT FOUND%s\n", name, tried));
471 m_warnings++;
472 }
473 else if (util::hash_collection(ROM_GETHASHDATA(romp)).flag(util::hash_collection::FLAG_NO_DUMP))
474 {
475 // no good dumps are okay
476 if (!is_chd_error)
477 m_errorstring.append(string_format("%s NOT FOUND (NO GOOD DUMP KNOWN)%s\n", name, tried));
478 m_knownbad++;
479 }
480 else
481 {
482 // anything else is bad
483 if (!is_chd_error)
484 m_errorstring.append(string_format("%s NOT FOUND%s\n", name, tried));
485 m_errors++;
486 }
487 }
488
489
490 /*-------------------------------------------------
491 dump_wrong_and_correct_checksums - dump an
492 error message containing the wrong and the
493 correct checksums for a given ROM
494 -------------------------------------------------*/
495
dump_wrong_and_correct_checksums(const util::hash_collection & hashes,const util::hash_collection & acthashes)496 void rom_load_manager::dump_wrong_and_correct_checksums(const util::hash_collection &hashes, const util::hash_collection &acthashes)
497 {
498 m_errorstring.append(string_format(" EXPECTED: %s\n", hashes.macro_string().c_str()));
499 m_errorstring.append(string_format(" FOUND: %s\n", acthashes.macro_string().c_str()));
500 }
501
502
503 /*-------------------------------------------------
504 verify_length_and_hash - verify the length
505 and hash signatures of a file
506 -------------------------------------------------*/
507
verify_length_and_hash(emu_file * file,const char * name,u32 explength,const util::hash_collection & hashes)508 void rom_load_manager::verify_length_and_hash(emu_file *file, const char *name, u32 explength, const util::hash_collection &hashes)
509 {
510 // we've already complained if there is no file
511 if (!file)
512 return;
513
514 // verify length
515 u64 const actlength = file->size();
516 if (explength != actlength)
517 {
518 m_errorstring.append(string_format("%s WRONG LENGTH (expected: %08x found: %08x)\n", name, explength, actlength));
519 m_warnings++;
520 }
521
522 if (hashes.flag(util::hash_collection::FLAG_NO_DUMP))
523 {
524 // If there is no good dump known, write it
525 m_errorstring.append(string_format("%s NO GOOD DUMP KNOWN\n", name));
526 m_knownbad++;
527 }
528 else
529 {
530 // verify checksums
531 util::hash_collection const &acthashes = file->hashes(hashes.hash_types().c_str());
532 if (hashes != acthashes)
533 {
534 // otherwise, it's just bad
535 util::hash_collection const &all_acthashes = (acthashes.hash_types() == util::hash_collection::HASH_TYPES_ALL)
536 ? acthashes
537 : file->hashes(util::hash_collection::HASH_TYPES_ALL);
538 m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", name));
539 dump_wrong_and_correct_checksums(hashes, all_acthashes);
540 m_warnings++;
541 }
542 else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
543 {
544 // If it matches, but it is actually a bad dump, write it
545 m_errorstring.append(string_format("%s ROM NEEDS REDUMP\n", name));
546 m_knownbad++;
547 }
548 }
549 }
550
551
552 /*-------------------------------------------------
553 display_loading_rom_message - display
554 messages about ROM loading to the user
555 -------------------------------------------------*/
556
display_loading_rom_message(const char * name,bool from_list)557 void rom_load_manager::display_loading_rom_message(const char *name, bool from_list)
558 {
559 std::string buffer;
560 if (name)
561 buffer = util::string_format("%s (%d%%)", from_list ? "Loading Software" : "Loading Machine", u32(100 * m_romsloadedsize / m_romstotalsize));
562 else
563 buffer = "Loading Complete";
564
565 if (!machine().ui().is_menu_active())
566 machine().ui().set_startup_text(buffer.c_str(), false);
567 }
568
569
570 /*-------------------------------------------------
571 display_rom_load_results - display the final
572 results of ROM loading
573 -------------------------------------------------*/
574
display_rom_load_results(bool from_list)575 void rom_load_manager::display_rom_load_results(bool from_list)
576 {
577 /* final status display */
578 display_loading_rom_message(nullptr, from_list);
579
580 /* if we had errors, they are fatal */
581 if (m_errors != 0)
582 {
583 /* create the error message and exit fatally */
584 osd_printf_error("%s", m_errorstring);
585 throw emu_fatalerror(EMU_ERR_MISSING_FILES, "Required files are missing, the machine cannot be run.");
586 }
587
588 /* if we had warnings, output them, but continue */
589 if ((m_warnings) || (m_knownbad))
590 {
591 m_errorstring.append("WARNING: the machine might not run correctly.");
592 osd_printf_warning("%s\n", m_errorstring);
593 }
594 }
595
596
597 /*-------------------------------------------------
598 region_post_process - post-process a region,
599 byte swapping and inverting data as necessary
600 -------------------------------------------------*/
601
region_post_process(memory_region * region,bool invert)602 void rom_load_manager::region_post_process(memory_region *region, bool invert)
603 {
604 // do nothing if no region
605 if (region == nullptr)
606 return;
607
608 LOG("+ datawidth=%dbit endian=%s\n", region->bitwidth(),
609 region->endianness() == ENDIANNESS_LITTLE ? "little" : "big");
610
611 /* if the region is inverted, do that now */
612 if (invert)
613 {
614 LOG("+ Inverting region\n");
615 u8 *base = region->base();
616 for (int i = 0; i < region->bytes(); i++)
617 *base++ ^= 0xff;
618 }
619
620 /* swap the endianness if we need to */
621 if (region->bytewidth() > 1 && region->endianness() != ENDIANNESS_NATIVE)
622 {
623 LOG("+ Byte swapping region\n");
624 int datawidth = region->bytewidth();
625 u8 *base = region->base();
626 for (int i = 0; i < region->bytes(); i += datawidth)
627 {
628 u8 temp[8];
629 memcpy(temp, base, datawidth);
630 for (int j = datawidth - 1; j >= 0; j--)
631 *base++ = temp[j];
632 }
633 }
634 }
635
636
637 /*-------------------------------------------------
638 open_rom_file - open a ROM file, searching
639 up the parent and loading by checksum
640 -------------------------------------------------*/
641
open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const rom_entry * romp,std::vector<std::string> & tried_file_names,bool from_list)642 std::unique_ptr<emu_file> rom_load_manager::open_rom_file(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const rom_entry *romp, std::vector<std::string> &tried_file_names, bool from_list)
643 {
644 osd_file::error filerr = osd_file::error::NOT_FOUND;
645 u32 const romsize = rom_file_size(romp);
646 tried_file_names.clear();
647
648 // update status display
649 display_loading_rom_message(ROM_GETNAME(romp), from_list);
650
651 // extract CRC to use for searching
652 u32 crc = 0;
653 bool const has_crc = util::hash_collection(ROM_GETHASHDATA(romp)).crc(crc);
654
655 // attempt reading up the chain through the parents
656 // it also automatically attempts any kind of load by checksum supported by the archives.
657 std::unique_ptr<emu_file> result;
658 for (const std::vector<std::string> &paths : searchpath)
659 {
660 result = open_rom_file(paths, tried_file_names, has_crc, crc, ROM_GETNAME(romp), filerr);
661 if (result)
662 break;
663 }
664
665 // update counters
666 m_romsloaded++;
667 m_romsloadedsize += romsize;
668
669 // return the result
670 if (osd_file::error::NONE != filerr)
671 return nullptr;
672 else
673 return result;
674 }
675
676
open_rom_file(const std::vector<std::string> & paths,std::vector<std::string> & tried,bool has_crc,u32 crc,const std::string & name,osd_file::error & filerr)677 std::unique_ptr<emu_file> rom_load_manager::open_rom_file(const std::vector<std::string> &paths, std::vector<std::string> &tried, bool has_crc, u32 crc, const std::string &name, osd_file::error &filerr)
678 {
679 // record the set names we search
680 tried.insert(tried.end(), paths.begin(), paths.end());
681
682 // attempt to open the file
683 std::unique_ptr<emu_file> result(new emu_file(machine().options().media_path(), paths, OPEN_FLAG_READ));
684 result->set_restrict_to_mediapath(1);
685 if (has_crc)
686 filerr = result->open(name, crc);
687 else
688 filerr = result->open(name);
689
690 // don't return anything if unsuccessful
691 if (osd_file::error::NONE != filerr)
692 return nullptr;
693 else
694 return result;
695 }
696
697
698 /*-------------------------------------------------
699 rom_fread - cheesy fread that fills with
700 random data for a nullptr file
701 -------------------------------------------------*/
702
rom_fread(emu_file * file,u8 * buffer,int length,const rom_entry * parent_region)703 int rom_load_manager::rom_fread(emu_file *file, u8 *buffer, int length, const rom_entry *parent_region)
704 {
705 if (file) // files just pass through
706 return file->read(buffer, length);
707
708 if (!ROMREGION_ISERASE(parent_region)) // otherwise, fill with randomness unless it was already specifically erased
709 fill_random(buffer, length);
710
711 return length;
712 }
713
714
715 /*-------------------------------------------------
716 read_rom_data - read ROM data for a single
717 entry
718 -------------------------------------------------*/
719
read_rom_data(emu_file * file,const rom_entry * parent_region,const rom_entry * romp)720 int rom_load_manager::read_rom_data(emu_file *file, const rom_entry *parent_region, const rom_entry *romp)
721 {
722 int datashift = ROM_GETBITSHIFT(romp);
723 int datamask = ((1 << ROM_GETBITWIDTH(romp)) - 1) << datashift;
724 int numbytes = ROM_GETLENGTH(romp);
725 int groupsize = ROM_GETGROUPSIZE(romp);
726 int skip = ROM_GETSKIPCOUNT(romp);
727 int reversed = ROM_ISREVERSED(romp);
728 int numgroups = (numbytes + groupsize - 1) / groupsize;
729 u8 *base = m_region->base() + ROM_GETOFFSET(romp);
730 u32 tempbufsize;
731 int i;
732
733 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);
734
735 /* make sure the length was an even multiple of the group size */
736 if (numbytes % groupsize != 0)
737 osd_printf_warning("Warning in RomModule definition: %s length not an even multiple of group size\n", ROM_GETNAME(romp));
738
739 /* make sure we only fill within the region space */
740 if (ROM_GETOFFSET(romp) + numgroups * groupsize + (numgroups - 1) * skip > m_region->bytes())
741 throw emu_fatalerror("Error in RomModule definition: %s out of memory region space\n", ROM_GETNAME(romp));
742
743 /* make sure the length was valid */
744 if (numbytes == 0)
745 throw emu_fatalerror("Error in RomModule definition: %s has an invalid length\n", ROM_GETNAME(romp));
746
747 /* special case for simple loads */
748 if (datamask == 0xff && (groupsize == 1 || !reversed) && skip == 0)
749 return rom_fread(file, base, numbytes, parent_region);
750
751 /* use a temporary buffer for complex loads */
752 tempbufsize = std::min(TEMPBUFFER_MAX_SIZE, numbytes);
753 std::vector<u8> tempbuf(tempbufsize);
754
755 /* chunky reads for complex loads */
756 skip += groupsize;
757 while (numbytes > 0)
758 {
759 int evengroupcount = (tempbufsize / groupsize) * groupsize;
760 int bytesleft = (numbytes > evengroupcount) ? evengroupcount : numbytes;
761 u8 *bufptr = &tempbuf[0];
762
763 /* read as much as we can */
764 LOG(" Reading %X bytes into buffer\n", bytesleft);
765 if (rom_fread(file, bufptr, bytesleft, parent_region) != bytesleft)
766 return 0;
767 numbytes -= bytesleft;
768
769 LOG(" Copying to %p\n", base);
770
771 /* unmasked cases */
772 if (datamask == 0xff)
773 {
774 /* non-grouped data */
775 if (groupsize == 1)
776 for (i = 0; i < bytesleft; i++, base += skip)
777 *base = *bufptr++;
778
779 /* grouped data -- non-reversed case */
780 else if (!reversed)
781 while (bytesleft)
782 {
783 for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
784 base[i] = *bufptr++;
785 base += skip;
786 }
787
788 /* grouped data -- reversed case */
789 else
790 while (bytesleft)
791 {
792 for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
793 base[i] = *bufptr++;
794 base += skip;
795 }
796 }
797
798 /* masked cases */
799 else
800 {
801 /* non-grouped data */
802 if (groupsize == 1)
803 for (i = 0; i < bytesleft; i++, base += skip)
804 *base = (*base & ~datamask) | ((*bufptr++ << datashift) & datamask);
805
806 /* grouped data -- non-reversed case */
807 else if (!reversed)
808 while (bytesleft)
809 {
810 for (i = 0; i < groupsize && bytesleft; i++, bytesleft--)
811 base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
812 base += skip;
813 }
814
815 /* grouped data -- reversed case */
816 else
817 while (bytesleft)
818 {
819 for (i = groupsize - 1; i >= 0 && bytesleft; i--, bytesleft--)
820 base[i] = (base[i] & ~datamask) | ((*bufptr++ << datashift) & datamask);
821 base += skip;
822 }
823 }
824 }
825
826 LOG(" All done\n");
827 return ROM_GETLENGTH(romp);
828 }
829
830
831 /*-------------------------------------------------
832 fill_rom_data - fill a region of ROM space
833 -------------------------------------------------*/
834
fill_rom_data(const rom_entry * romp)835 void rom_load_manager::fill_rom_data(const rom_entry *romp)
836 {
837 u32 numbytes = ROM_GETLENGTH(romp);
838 int skip = ROM_GETSKIPCOUNT(romp);
839 u8 *base = m_region->base() + ROM_GETOFFSET(romp);
840
841 // make sure we fill within the region space
842 if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
843 throw emu_fatalerror("Error in RomModule definition: FILL out of memory region space\n");
844
845 // make sure the length was valid
846 if (numbytes == 0)
847 throw emu_fatalerror("Error in RomModule definition: FILL has an invalid length\n");
848
849 // for fill bytes, the byte that gets filled is the first byte of the hashdata string
850 u8 fill_byte = u8(strtol(ROM_GETHASHDATA(romp), nullptr, 0));
851
852 // fill the data (filling value is stored in place of the hashdata)
853 if(skip != 0)
854 {
855 for (int i = 0; i < numbytes; i+= skip + 1)
856 base[i] = fill_byte;
857 }
858 else
859 memset(base, fill_byte, numbytes);
860 }
861
862
863 /*-------------------------------------------------
864 copy_rom_data - copy a region of ROM space
865 -------------------------------------------------*/
866
copy_rom_data(const rom_entry * romp)867 void rom_load_manager::copy_rom_data(const rom_entry *romp)
868 {
869 u8 *base = m_region->base() + ROM_GETOFFSET(romp);
870 const char *srcrgntag = ROM_GETNAME(romp);
871 u32 numbytes = ROM_GETLENGTH(romp);
872 u32 srcoffs = u32(strtol(ROM_GETHASHDATA(romp), nullptr, 0)); /* srcoffset in place of hashdata */
873
874 /* make sure we copy within the region space */
875 if (ROM_GETOFFSET(romp) + numbytes > m_region->bytes())
876 throw emu_fatalerror("Error in RomModule definition: COPY out of target memory region space\n");
877
878 /* make sure the length was valid */
879 if (numbytes == 0)
880 throw emu_fatalerror("Error in RomModule definition: COPY has an invalid length\n");
881
882 /* make sure the source was valid */
883 memory_region *region = machine().root_device().memregion(srcrgntag);
884 if (region == nullptr)
885 throw emu_fatalerror("Error in RomModule definition: COPY from an invalid region\n");
886
887 /* make sure we find within the region space */
888 if (srcoffs + numbytes > region->bytes())
889 throw emu_fatalerror("Error in RomModule definition: COPY out of source memory region space\n");
890
891 /* fill the data */
892 memcpy(base, region->base() + srcoffs, numbytes);
893 }
894
895
896 /*-------------------------------------------------
897 process_rom_entries - process all ROM entries
898 for a region
899 -------------------------------------------------*/
900
process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,u8 bios,const rom_entry * parent_region,const rom_entry * romp,bool from_list)901 void rom_load_manager::process_rom_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, u8 bios, const rom_entry *parent_region, const rom_entry *romp, bool from_list)
902 {
903 u32 lastflags = 0;
904 std::vector<std::string> tried_file_names;
905
906 // loop until we hit the end of this region
907 while (!ROMENTRY_ISREGIONEND(romp))
908 {
909 tried_file_names.clear();
910
911 if (ROMENTRY_ISCONTINUE(romp))
912 throw emu_fatalerror("Error in RomModule definition: ROM_CONTINUE not preceded by ROM_LOAD\n");
913
914 if (ROMENTRY_ISIGNORE(romp))
915 throw emu_fatalerror("Error in RomModule definition: ROM_IGNORE not preceded by ROM_LOAD\n");
916
917 if (ROMENTRY_ISRELOAD(romp))
918 throw emu_fatalerror("Error in RomModule definition: ROM_RELOAD not preceded by ROM_LOAD\n");
919
920 if (ROMENTRY_ISFILL(romp))
921 {
922 if (!ROM_GETBIOSFLAGS(romp) || (ROM_GETBIOSFLAGS(romp) == bios))
923 fill_rom_data(romp);
924
925 romp++;
926 }
927 else if (ROMENTRY_ISCOPY(romp))
928 {
929 copy_rom_data(romp++);
930 }
931 else if (ROMENTRY_ISFILE(romp))
932 {
933 // handle files
934 bool const irrelevantbios = (ROM_GETBIOSFLAGS(romp) != 0) && (ROM_GETBIOSFLAGS(romp) != bios);
935 rom_entry const *baserom = romp;
936 int explength = 0;
937
938 // open the file if it is a non-BIOS or matches the current BIOS
939 LOG("Opening ROM file: %s\n", ROM_GETNAME(romp));
940 std::unique_ptr<emu_file> file;
941 if (!irrelevantbios)
942 {
943 file = open_rom_file(searchpath, romp, tried_file_names, from_list);
944 if (!file)
945 handle_missing_file(romp, tried_file_names, CHDERR_NONE);
946 }
947
948 // loop until we run out of reloads
949 do
950 {
951 // loop until we run out of continues/ignores
952 do
953 {
954 rom_entry modified_romp = *romp++;
955 //int readresult;
956
957 // handle flag inheritance
958 if (!ROM_INHERITSFLAGS(&modified_romp))
959 lastflags = modified_romp.get_flags();
960 else
961 modified_romp.set_flags((modified_romp.get_flags() & ~ROM_INHERITEDFLAGS) | lastflags);
962
963 explength += ROM_GETLENGTH(&modified_romp);
964
965 // attempt to read using the modified entry
966 if (!ROMENTRY_ISIGNORE(&modified_romp) && !irrelevantbios)
967 /*readresult = */read_rom_data(file.get(), parent_region, &modified_romp);
968 }
969 while (ROMENTRY_ISCONTINUE(romp) || ROMENTRY_ISIGNORE(romp));
970
971 // if this was the first use of this file, verify the length and CRC
972 if (baserom)
973 {
974 LOG("Verifying length (%X) and checksums\n", explength);
975 verify_length_and_hash(file.get(), ROM_GETNAME(baserom), explength, util::hash_collection(ROM_GETHASHDATA(baserom)));
976 LOG("Verify finished\n");
977 }
978
979 // re-seek to the start and clear the baserom so we don't reverify
980 if (file)
981 file->seek(0, SEEK_SET);
982 baserom = nullptr;
983 explength = 0;
984 }
985 while (ROMENTRY_ISRELOAD(romp));
986
987 // close the file
988 if (file)
989 {
990 LOG("Closing ROM file\n");
991 file.reset();
992 }
993 }
994 else
995 {
996 romp++; // something else - skip
997 }
998 }
999 }
1000
1001
1002 /*-------------------------------------------------
1003 open_disk_diff - open a DISK diff file
1004 -------------------------------------------------*/
1005
open_disk_diff(emu_options & options,const rom_entry * romp,chd_file & source,chd_file & diff_chd)1006 chd_error rom_load_manager::open_disk_diff(emu_options &options, const rom_entry *romp, chd_file &source, chd_file &diff_chd)
1007 {
1008 // TODO: use system name and/or software list name in the path - the current setup doesn't scale
1009 std::string fname = std::string(ROM_GETNAME(romp)).append(".dif");
1010
1011 /* try to open the diff */
1012 LOG("Opening differencing image file: %s\n", fname.c_str());
1013 emu_file diff_file(options.diff_directory(), OPEN_FLAG_READ | OPEN_FLAG_WRITE);
1014 osd_file::error filerr = diff_file.open(fname);
1015 if (filerr == osd_file::error::NONE)
1016 {
1017 std::string fullpath(diff_file.fullpath());
1018 diff_file.close();
1019
1020 LOG("Opening differencing image file: %s\n", fullpath.c_str());
1021 return diff_chd.open(fullpath.c_str(), true, &source);
1022 }
1023
1024 /* didn't work; try creating it instead */
1025 LOG("Creating differencing image: %s\n", fname.c_str());
1026 diff_file.set_openflags(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
1027 filerr = diff_file.open(fname);
1028 if (filerr == osd_file::error::NONE)
1029 {
1030 std::string fullpath(diff_file.fullpath());
1031 diff_file.close();
1032
1033 /* create the CHD */
1034 LOG("Creating differencing image file: %s\n", fullpath.c_str());
1035 chd_codec_type compression[4] = { CHD_CODEC_NONE };
1036 chd_error err = diff_chd.create(fullpath.c_str(), source.logical_bytes(), source.hunk_bytes(), compression, source);
1037 if (err != CHDERR_NONE)
1038 return err;
1039
1040 return diff_chd.clone_all_metadata(source);
1041 }
1042
1043 return CHDERR_FILE_NOT_FOUND;
1044 }
1045
1046
1047 /*-------------------------------------------------
1048 process_disk_entries - process all disk entries
1049 for a region
1050 -------------------------------------------------*/
1051
process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string>>> searchpath,const char * regiontag,const rom_entry * romp,std::function<const rom_entry * ()> next_parent)1052 void rom_load_manager::process_disk_entries(std::initializer_list<std::reference_wrapper<const std::vector<std::string> > > searchpath, const char *regiontag, const rom_entry *romp, std::function<const rom_entry * ()> next_parent)
1053 {
1054 /* remove existing disk entries for this region */
1055 m_chd_list.erase(std::remove_if(m_chd_list.begin(), m_chd_list.end(),
1056 [regiontag] (std::unique_ptr<open_chd> &chd) { return !strcmp(chd->region(), regiontag); }), m_chd_list.end());
1057
1058 /* loop until we hit the end of this region */
1059 for ( ; !ROMENTRY_ISREGIONEND(romp); romp++)
1060 {
1061 /* handle files */
1062 if (ROMENTRY_ISFILE(romp))
1063 {
1064 auto chd = std::make_unique<open_chd>(regiontag);
1065 chd_error err;
1066
1067 /* make the filename of the source */
1068 const std::string filename = std::string(ROM_GETNAME(romp)).append(".chd");
1069
1070 /* first open the source drive */
1071 // FIXME: we've lost the ability to search parents here
1072 LOG("Opening disk image: %s\n", filename.c_str());
1073 err = do_open_disk(machine().options(), searchpath, romp, chd->orig_chd(), next_parent);
1074 if (err != CHDERR_NONE)
1075 {
1076 handle_missing_file(romp, std::vector<std::string>(), err);
1077 chd = nullptr;
1078 continue;
1079 }
1080
1081 /* get the header and extract the SHA1 */
1082 util::hash_collection acthashes;
1083 acthashes.add_sha1(chd->orig_chd().sha1());
1084
1085 /* verify the hash */
1086 const util::hash_collection hashes(ROM_GETHASHDATA(romp));
1087 if (hashes != acthashes)
1088 {
1089 m_errorstring.append(string_format("%s WRONG CHECKSUMS:\n", filename));
1090 dump_wrong_and_correct_checksums(hashes, acthashes);
1091 m_warnings++;
1092 }
1093 else if (hashes.flag(util::hash_collection::FLAG_BAD_DUMP))
1094 {
1095 m_errorstring.append(string_format("%s CHD NEEDS REDUMP\n", filename));
1096 m_knownbad++;
1097 }
1098
1099 /* if not read-only, make the diff file */
1100 if (!DISK_ISREADONLY(romp))
1101 {
1102 /* try to open or create the diff */
1103 err = open_disk_diff(machine().options(), romp, chd->orig_chd(), chd->diff_chd());
1104 if (err != CHDERR_NONE)
1105 {
1106 m_errorstring.append(string_format("%s DIFF CHD ERROR: %s\n", filename, chd_file::error_string(err)));
1107 m_errors++;
1108 chd = nullptr;
1109 continue;
1110 }
1111 }
1112
1113 /* we're okay, add to the list of disks */
1114 LOG("Assigning to handle %d\n", DISK_GETINDEX(romp));
1115 m_chd_list.push_back(std::move(chd));
1116 }
1117 }
1118 }
1119
1120
1121 /*-------------------------------------------------
1122 get_software_searchpath - get search path
1123 for a software list item
1124 -------------------------------------------------*/
1125
get_software_searchpath(software_list_device & swlist,const software_info & swinfo)1126 std::vector<std::string> rom_load_manager::get_software_searchpath(software_list_device &swlist, const software_info &swinfo)
1127 {
1128 std::vector<software_info const *> parents;
1129 return make_software_searchpath(swlist, swinfo, parents);
1130 }
1131
1132
1133 /*-------------------------------------------------
1134 open_disk_image - open a disk image for a
1135 device
1136 -------------------------------------------------*/
1137
open_disk_image(const emu_options & options,const device_t & device,const rom_entry * romp,chd_file & image_chd)1138 chd_error rom_load_manager::open_disk_image(const emu_options &options, const device_t &device, const rom_entry *romp, chd_file &image_chd)
1139 {
1140 const std::vector<std::string> searchpath(device.searchpath());
1141
1142 driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
1143 std::function<const rom_entry * ()> next_parent;
1144 if (driver)
1145 next_parent = next_parent_system(driver->system());
1146 else
1147 next_parent = [] () { return nullptr; };
1148 return do_open_disk(options, { searchpath }, romp, image_chd, std::move(next_parent));
1149 }
1150
1151
1152 /*-------------------------------------------------
1153 open_disk_image - open a disk image for a
1154 software item
1155 -------------------------------------------------*/
1156
open_disk_image(const emu_options & options,software_list_device & swlist,const software_info & swinfo,const rom_entry * romp,chd_file & image_chd)1157 chd_error rom_load_manager::open_disk_image(const emu_options &options, software_list_device &swlist, const software_info &swinfo, const rom_entry *romp, chd_file &image_chd)
1158 {
1159 std::vector<software_info const *> parents;
1160 std::vector<std::string> searchpath = make_software_searchpath(swlist, swinfo, parents);
1161 searchpath.emplace_back(swlist.list_name()); // look for loose disk images in software list directory
1162 return do_open_disk(options, { searchpath }, romp, image_chd, next_parent_software(parents));
1163 }
1164
1165
1166 /*-------------------------------------------------
1167 normalize_flags_for_device - modify the region
1168 flags for the given device
1169 -------------------------------------------------*/
1170
normalize_flags_for_device(const char * rgntag,u8 & width,endianness_t & endian)1171 void rom_load_manager::normalize_flags_for_device(const char *rgntag, u8 &width, endianness_t &endian)
1172 {
1173 device_t *device = machine().root_device().subdevice(rgntag);
1174 device_memory_interface *memory;
1175 if (device != nullptr && device->interface(memory))
1176 {
1177 const address_space_config *spaceconfig = memory->space_config();
1178 if (spaceconfig != nullptr)
1179 {
1180 int buswidth;
1181
1182 /* set the endianness */
1183 if (spaceconfig->endianness() == ENDIANNESS_LITTLE)
1184 endian = ENDIANNESS_LITTLE;
1185 else
1186 endian = ENDIANNESS_BIG;
1187
1188 /* set the width */
1189 buswidth = spaceconfig->data_width();
1190 if (buswidth <= 8)
1191 width = 1;
1192 else if (buswidth <= 16)
1193 width = 2;
1194 else if (buswidth <= 32)
1195 width = 4;
1196 else
1197 width = 8;
1198 }
1199 }
1200 }
1201
1202
1203 /*-------------------------------------------------
1204 load_software_part_region - load a software part
1205
1206 This is used by MESS when loading a piece of
1207 software. The code should be merged with
1208 process_region_list or updated to use a slight
1209 more general process_region_list.
1210 -------------------------------------------------*/
1211
load_software_part_region(device_t & device,software_list_device & swlist,const char * swname,const rom_entry * start_region)1212 void rom_load_manager::load_software_part_region(device_t &device, software_list_device &swlist, const char *swname, const rom_entry *start_region)
1213 {
1214 m_errorstring.clear();
1215 m_softwarningstring.clear();
1216
1217 m_romstotal = 0;
1218 m_romstotalsize = 0;
1219 m_romsloadedsize = 0;
1220
1221 std::vector<const software_info *> parents;
1222 std::vector<std::string> swsearch, disksearch, devsearch;
1223 const software_info *const swinfo = swlist.find(swname);
1224 if (swinfo)
1225 {
1226 // dispay a warning for unsupported software
1227 // TODO: list supported clones like we do for machines?
1228 const u32 supported(swinfo->supported());
1229 if (supported == SOFTWARE_SUPPORTED_PARTIAL)
1230 {
1231 m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
1232 m_softwarningstring.append(string_format("Support for software %s (in list %s) is only partial\n", swname, swlist.list_name()));
1233 }
1234 if (supported == SOFTWARE_SUPPORTED_NO)
1235 {
1236 m_errorstring.append(string_format("WARNING: support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
1237 m_softwarningstring.append(string_format("Support for software %s (in list %s) is only preliminary\n", swname, swlist.list_name()));
1238 }
1239
1240 // walk the chain of parents and add them to the search path
1241 swsearch = make_software_searchpath(swlist, *swinfo, parents);
1242 }
1243 else
1244 {
1245 swsearch.emplace_back(util::string_format("%s" PATH_SEPARATOR "%s", swlist.list_name(), swname));
1246 swsearch.emplace_back(swname);
1247 }
1248
1249 // this is convenient for CD-only lists so you don't need an extra level of directories containing one file each
1250 disksearch.emplace_back(swlist.list_name());
1251
1252 // for historical reasons, add the search path for the software list device's owner
1253 const device_t *const listowner = swlist.owner();
1254 if (listowner)
1255 devsearch = listowner->searchpath();
1256
1257 // loop until we hit the end
1258 std::function<const rom_entry * ()> next_parent;
1259 for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
1260 {
1261 u32 regionlength = ROMREGION_GETLENGTH(region);
1262
1263 std::string regiontag = device.subtag(ROMREGION_GETTAG(region));
1264 LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
1265
1266 // the first entry must be a region
1267 assert(ROMENTRY_ISREGION(region));
1268
1269 // if this is a device region, override with the device width and endianness
1270 endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
1271 u8 width = ROMREGION_GETWIDTH(region) / 8;
1272 memory_region *memregion = machine().root_device().memregion(regiontag);
1273 if (memregion != nullptr)
1274 {
1275 normalize_flags_for_device(regiontag.c_str(), width, endianness);
1276
1277 // clear old region (TODO: should be moved to an image unload function)
1278 machine().memory().region_free(memregion->name());
1279 }
1280
1281 // remember the base and length
1282 m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
1283 LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
1284
1285 if (ROMREGION_ISERASE(region)) // clear the region if it's requested
1286 memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
1287 else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
1288 memset(m_region->base(), 0, m_region->bytes());
1289 #ifdef MAME_DEBUG
1290 else // if we're debugging, fill region with random data to catch errors
1291 fill_random(m_region->base(), m_region->bytes());
1292 #endif
1293
1294 // update total number of roms
1295 for (const rom_entry *rom = rom_first_file(region); rom != nullptr; rom = rom_next_file(rom))
1296 {
1297 m_romstotal++;
1298 m_romstotalsize += rom_file_size(rom);
1299 }
1300
1301 // now process the entries in the region
1302 if (ROMREGION_ISROMDATA(region))
1303 {
1304 if (devsearch.empty())
1305 process_rom_entries({ swsearch }, 0U, region, region + 1, true);
1306 else
1307 process_rom_entries({ swsearch, devsearch }, 0U, region, region + 1, true);
1308 }
1309 else if (ROMREGION_ISDISKDATA(region))
1310 {
1311 if (!next_parent)
1312 {
1313 if (!parents.empty())
1314 next_parent = next_parent_software(parents);
1315 else
1316 next_parent = [] () { return nullptr; };
1317 }
1318 if (devsearch.empty())
1319 process_disk_entries({ swsearch, disksearch }, regiontag.c_str(), region + 1, next_parent);
1320 else
1321 process_disk_entries({ swsearch, disksearch, devsearch }, regiontag.c_str(), region + 1, next_parent);
1322 }
1323 }
1324
1325 // now go back and post-process all the regions
1326 for (const rom_entry *region = start_region; region != nullptr; region = rom_next_region(region))
1327 region_post_process(device.memregion(ROMREGION_GETTAG(region)), ROMREGION_ISINVERTED(region));
1328
1329 // display the results and exit
1330 display_rom_load_results(true);
1331 }
1332
1333
1334 /*-------------------------------------------------
1335 process_region_list - process a region list
1336 -------------------------------------------------*/
1337
process_region_list()1338 void rom_load_manager::process_region_list()
1339 {
1340 // loop until we hit the end
1341 device_iterator deviter(machine().root_device());
1342 std::vector<std::string> searchpath;
1343 for (device_t &device : deviter)
1344 {
1345 searchpath.clear();
1346 std::function<const rom_entry * ()> next_parent;
1347 for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
1348 {
1349 u32 regionlength = ROMREGION_GETLENGTH(region);
1350
1351 std::string regiontag = device.subtag(ROM_GETNAME(region));
1352 LOG("Processing region \"%s\" (length=%X)\n", regiontag.c_str(), regionlength);
1353
1354 // the first entry must be a region
1355 assert(ROMENTRY_ISREGION(region));
1356
1357 if (ROMREGION_ISROMDATA(region))
1358 {
1359 // if this is a device region, override with the device width and endianness
1360 u8 width = ROMREGION_GETWIDTH(region) / 8;
1361 endianness_t endianness = ROMREGION_ISBIGENDIAN(region) ? ENDIANNESS_BIG : ENDIANNESS_LITTLE;
1362 normalize_flags_for_device(regiontag.c_str(), width, endianness);
1363
1364 // remember the base and length
1365 m_region = machine().memory().region_alloc(regiontag.c_str(), regionlength, width, endianness);
1366 LOG("Allocated %X bytes @ %p\n", m_region->bytes(), m_region->base());
1367
1368 if (ROMREGION_ISERASE(region)) // clear the region if it's requested
1369 memset(m_region->base(), ROMREGION_GETERASEVAL(region), m_region->bytes());
1370 else if (m_region->bytes() <= 0x400000) // or if it's sufficiently small (<= 4MB)
1371 memset(m_region->base(), 0, m_region->bytes());
1372 #ifdef MAME_DEBUG
1373 else // if we're debugging, fill region with random data to catch errors
1374 fill_random(m_region->base(), m_region->bytes());
1375 #endif
1376
1377 // now process the entries in the region
1378 if (searchpath.empty())
1379 searchpath = device.searchpath();
1380 assert(!searchpath.empty());
1381 process_rom_entries({ searchpath }, device.system_bios(), region, region + 1, false);
1382 }
1383 else if (ROMREGION_ISDISKDATA(region))
1384 {
1385 if (searchpath.empty())
1386 searchpath = device.searchpath();
1387 assert(!searchpath.empty());
1388 if (!next_parent)
1389 {
1390 driver_device const *const driver(dynamic_cast<driver_device const *>(&device));
1391 if (driver)
1392 next_parent = next_parent_system(driver->system());
1393 else
1394 next_parent = [] () { return nullptr; };
1395 }
1396 process_disk_entries({ searchpath }, regiontag.c_str(), region + 1, next_parent);
1397 }
1398 }
1399 }
1400
1401 // now go back and post-process all the regions
1402 for (device_t &device : deviter)
1403 for (const rom_entry *region = rom_first_region(device); region != nullptr; region = rom_next_region(region))
1404 region_post_process(device.memregion(ROM_GETNAME(region)), ROMREGION_ISINVERTED(region));
1405
1406 // and finally register all per-game parameters
1407 for (device_t &device : deviter)
1408 {
1409 for (const rom_entry *param = rom_first_parameter(device); param != nullptr; param = rom_next_parameter(param))
1410 {
1411 std::string regiontag = device.subtag(param->name());
1412 machine().parameters().add(regiontag, param->hashdata());
1413 }
1414 }
1415 }
1416
1417
1418 /*-------------------------------------------------
1419 rom_init - load the ROMs and open the disk
1420 images associated with the given machine
1421 -------------------------------------------------*/
1422
rom_load_manager(running_machine & machine)1423 rom_load_manager::rom_load_manager(running_machine &machine)
1424 : m_machine(machine)
1425 , m_warnings(0)
1426 , m_knownbad(0)
1427 , m_errors(0)
1428 , m_romsloaded(0)
1429 , m_romstotal(0)
1430 , m_romsloadedsize(0)
1431 , m_romstotalsize(0)
1432 , m_chd_list()
1433 , m_region(nullptr)
1434 , m_errorstring()
1435 , m_softwarningstring()
1436 {
1437 // figure out which BIOS we are using
1438 std::map<std::string, std::string> card_bios;
1439 for (device_t &device : device_iterator(machine.config().root_device()))
1440 {
1441 device_slot_interface const *const slot(dynamic_cast<device_slot_interface *>(&device));
1442 if (slot)
1443 {
1444 device_t const *const card(slot->get_card_device());
1445 slot_option const &slot_opt(machine.options().slot_option(slot->slot_name()));
1446 if (card && !slot_opt.bios().empty())
1447 card_bios.emplace(std::make_pair(std::string(card->tag()), slot_opt.bios()));
1448 }
1449
1450 if (device.rom_region())
1451 {
1452 std::string specbios;
1453 if (!device.owner())
1454 {
1455 specbios = machine.options().bios();
1456 }
1457 else
1458 {
1459 auto const found(card_bios.find(device.tag()));
1460 if (card_bios.end() != found)
1461 {
1462 specbios = std::move(found->second);
1463 card_bios.erase(found);
1464 }
1465 }
1466 determine_bios_rom(device, specbios.c_str());
1467 }
1468 }
1469
1470 // count the total number of ROMs
1471 count_roms();
1472
1473 // reset the disk list
1474 m_chd_list.clear();
1475
1476 // process the ROM entries we were passed
1477 process_region_list();
1478
1479 // display the results and exit
1480 display_rom_load_results(false);
1481 }
1482
1483
1484 // -------------------------------------------------
1485 // rom_build_entries - builds a rom_entry vector
1486 // from a tiny_rom_entry array
1487 // -------------------------------------------------
1488
rom_build_entries(const tiny_rom_entry * tinyentries)1489 std::vector<rom_entry> rom_build_entries(const tiny_rom_entry *tinyentries)
1490 {
1491 std::vector<rom_entry> result;
1492 if (tinyentries)
1493 {
1494 int i = 0;
1495 do
1496 {
1497 result.emplace_back(tinyentries[i]);
1498 }
1499 while (!ROMENTRY_ISEND(tinyentries[i++]));
1500 }
1501 else
1502 {
1503 tiny_rom_entry const end_entry = { nullptr, nullptr, 0, 0, ROMENTRYTYPE_END };
1504 result.emplace_back(end_entry);
1505 }
1506 return result;
1507 }
1508