summaryrefslogtreecommitdiffstats
path: root/docs/release/src/emu/validity.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'docs/release/src/emu/validity.cpp')
-rw-r--r--docs/release/src/emu/validity.cpp395
1 files changed, 267 insertions, 128 deletions
diff --git a/docs/release/src/emu/validity.cpp b/docs/release/src/emu/validity.cpp
index 9e3996d9c9f..5fdb48c53b0 100644
--- a/docs/release/src/emu/validity.cpp
+++ b/docs/release/src/emu/validity.cpp
@@ -16,7 +16,6 @@
#include <ctype.h>
#include <type_traits>
-#include <typeindex>
#include <typeinfo>
@@ -183,7 +182,7 @@ void validity_checker::check_shared_source(const game_driver &driver)
// then iterate over all drivers and check the ones that share the same source file
m_drivlist.reset();
while (m_drivlist.next())
- if (strcmp(driver.source_file, m_drivlist.driver().source_file) == 0)
+ if (strcmp(driver.type.source(), m_drivlist.driver().type.source()) == 0)
validate_one(m_drivlist.driver());
// cleanup
@@ -219,9 +218,15 @@ bool validity_checker::check_all_matching(const char *string)
// then iterate over all drivers and check them
m_drivlist.reset();
+ bool validated_any = false;
while (m_drivlist.next())
+ {
if (m_drivlist.matches(string, m_drivlist.driver().name))
+ {
validate_one(m_drivlist.driver());
+ validated_any = true;
+ }
+ }
// validate devices
if (!string)
@@ -230,6 +235,10 @@ bool validity_checker::check_all_matching(const char *string)
// cleanup
validate_end();
+ // if we failed to match anything, it
+ if (string && !validated_any)
+ throw emu_fatalerror(EMU_ERR_NO_SUCH_GAME, "No matching systems found for '%s'", string);
+
return !(m_errors > 0 || m_warnings > 0);
}
@@ -279,7 +288,7 @@ void validity_checker::validate_one(const game_driver &driver)
{
// help verbose validation detect configuration-related crashes
if (m_print_verbose)
- output_via_delegate(OSD_OUTPUT_CHANNEL_ERROR, "Validating driver %s (%s)...\n", driver.name, core_filename_extract_base(driver.source_file).c_str());
+ output_via_delegate(OSD_OUTPUT_CHANNEL_ERROR, "Validating driver %s (%s)...\n", driver.name, core_filename_extract_base(driver.type.source()).c_str());
// set the current driver
m_current_driver = &driver;
@@ -301,7 +310,7 @@ void validity_checker::validate_one(const game_driver &driver)
machine_config config(driver, m_blank_options);
m_current_config = &config;
validate_driver();
- validate_roms();
+ validate_roms(m_current_config->root_device());
validate_inputs();
validate_devices();
m_current_config = nullptr;
@@ -315,7 +324,7 @@ void validity_checker::validate_one(const game_driver &driver)
if (m_errors > start_errors || m_warnings > start_warnings || !m_verbose_text.empty())
{
if (!m_print_verbose)
- output_via_delegate(OSD_OUTPUT_CHANNEL_ERROR, "Driver %s (file %s): ", driver.name, core_filename_extract_base(driver.source_file).c_str());
+ output_via_delegate(OSD_OUTPUT_CHANNEL_ERROR, "Driver %s (file %s): ", driver.name, core_filename_extract_base(driver.type.source()).c_str());
output_via_delegate(OSD_OUTPUT_CHANNEL_ERROR, "%d errors, %d warnings\n", m_errors - start_errors, m_warnings - start_warnings);
if (m_errors > start_errors)
output_indented_errors(m_error_text, "Errors");
@@ -505,9 +514,13 @@ void validity_checker::validate_inlines()
testi32a = (testi32a & 0x0000ffff) | 0x400000;
if (count_leading_zeros(testi32a) != 9)
osd_printf_error("Error testing count_leading_zeros\n");
+ if (count_leading_zeros(0) != 32)
+ osd_printf_error("Error testing count_leading_zeros\n");
testi32a = (testi32a | 0xffff0000) & ~0x400000;
if (count_leading_ones(testi32a) != 9)
osd_printf_error("Error testing count_leading_ones\n");
+ if (count_leading_ones(0xffffffff) != 32)
+ osd_printf_error("Error testing count_leading_ones\n");
}
@@ -588,6 +601,14 @@ void validity_checker::validate_rgb()
rgb.set(rgbaint_t(expected_a, expected_r, expected_g, expected_b));
check_expected("rgbaint_t::set(rgbaint_t)");
+ packed = random_i32();
+ expected_a = packed.a();
+ expected_r = packed.r();
+ expected_g = packed.g();
+ expected_b = packed.b();
+ rgb.set(packed);
+ check_expected("rgbaint_t::set(const rgb_t& rgb)");
+
// check construct/assign
expected_a = random_i32();
expected_r = random_i32();
@@ -753,6 +774,38 @@ void validity_checker::validate_rgb()
rgb.mul_imm_rgba(actual_a, actual_r, actual_g, actual_b);
check_expected("rgbaint_t::mul_imm_rgba");
+ // test select alpha element multiplication
+ expected_a *= actual_a = random_i32();
+ expected_r *= actual_a;
+ expected_g *= actual_a;
+ expected_b *= actual_a;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_alpha32());
+ check_expected("rgbaint_t::mul(select_alpha32)");
+
+ // test select red element multiplication
+ expected_a *= actual_r = random_i32();
+ expected_r *= actual_r;
+ expected_g *= actual_r;
+ expected_b *= actual_r;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_red32());
+ check_expected("rgbaint_t::mul(select_red32)");
+
+ // test select green element multiplication
+ expected_a *= actual_g = random_i32();
+ expected_r *= actual_g;
+ expected_g *= actual_g;
+ expected_b *= actual_g;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_green32());
+ check_expected("rgbaint_t::mul(select_green32)");
+
+ // test select blue element multiplication
+ expected_a *= actual_b = random_i32();
+ expected_r *= actual_b;
+ expected_g *= actual_b;
+ expected_b *= actual_b;
+ rgb.mul(rgbaint_t(actual_a, actual_r, actual_g, actual_b).select_blue32());
+ check_expected("rgbaint_t::mul(select_blue32)");
+
// test RGB and not
expected_a &= ~(actual_a = random_i32());
expected_r &= ~(actual_r = random_i32());
@@ -1350,20 +1403,20 @@ void validity_checker::validate_driver()
if (!m_names_map.insert(std::make_pair(m_current_driver->name, m_current_driver)).second)
{
const game_driver *match = m_names_map.find(m_current_driver->name)->second;
- osd_printf_error("Driver name is a duplicate of %s(%s)\n", core_filename_extract_base(match->source_file).c_str(), match->name);
+ osd_printf_error("Driver name is a duplicate of %s(%s)\n", core_filename_extract_base(match->type.source()).c_str(), match->name);
}
// check for duplicate descriptions
- if (!m_descriptions_map.insert(std::make_pair(m_current_driver->description, m_current_driver)).second)
+ if (!m_descriptions_map.insert(std::make_pair(m_current_driver->type.fullname(), m_current_driver)).second)
{
- const game_driver *match = m_descriptions_map.find(m_current_driver->description)->second;
- osd_printf_error("Driver description is a duplicate of %s(%s)\n", core_filename_extract_base(match->source_file).c_str(), match->name);
+ const game_driver *match = m_descriptions_map.find(m_current_driver->type.fullname())->second;
+ osd_printf_error("Driver description is a duplicate of %s(%s)\n", core_filename_extract_base(match->type.source()).c_str(), match->name);
}
// determine if we are a clone
bool is_clone = (strcmp(m_current_driver->parent, "0") != 0);
int clone_of = m_drivlist.clone(*m_current_driver);
- if (clone_of != -1 && (m_drivlist.driver(clone_of).flags & MACHINE_IS_BIOS_ROOT))
+ if (clone_of != -1 && (m_drivlist.driver(clone_of).flags & machine_flags::IS_BIOS_ROOT))
is_clone = false;
// if we have at least 100 drivers, validate the clone
@@ -1423,9 +1476,24 @@ void validity_checker::validate_driver()
}
// make sure sound-less drivers are flagged
- sound_interface_iterator iter(m_current_config->root_device());
- if ((m_current_driver->flags & MACHINE_IS_BIOS_ROOT) == 0 && iter.first() == nullptr && (m_current_driver->flags & MACHINE_NO_SOUND) == 0 && (m_current_driver->flags & MACHINE_NO_SOUND_HW) == 0)
- osd_printf_error("Driver is missing MACHINE_NO_SOUND flag\n");
+ device_t::feature_type const unemulated(m_current_driver->type.unemulated_features());
+ device_t::feature_type const imperfect(m_current_driver->type.imperfect_features());
+ if (!(m_current_driver->flags & (machine_flags::IS_BIOS_ROOT | machine_flags::NO_SOUND_HW)) && !(unemulated & device_t::feature::SOUND))
+ {
+ sound_interface_iterator iter(m_current_config->root_device());
+ if (!iter.first())
+ osd_printf_error("Driver is missing MACHINE_NO_SOUND or MACHINE_NO_SOUND_HW flag\n");
+ }
+
+ // catch invalid flag combinations
+ if (unemulated & ~device_t::feature::ALL)
+ osd_printf_error("Driver has invalid unemulated feature flags (0x%08lX)\n", static_cast<unsigned long>(unemulated & ~device_t::feature::ALL));
+ if (imperfect & ~device_t::feature::ALL)
+ osd_printf_error("Driver has invalid imperfect feature flags (0x%08lX)\n", static_cast<unsigned long>(imperfect & ~device_t::feature::ALL));
+ if (unemulated & imperfect)
+ osd_printf_error("Driver cannot have features that are both unemulated and imperfect (0x%08lX)\n", static_cast<unsigned long>(unemulated & imperfect));
+ if ((m_current_driver->flags & machine_flags::NO_SOUND_HW) && ((unemulated | imperfect) & device_t::feature::SOUND))
+ osd_printf_error("Machine without sound hardware cannot have unemulated/imperfect sound\n");
}
@@ -1433,37 +1501,39 @@ void validity_checker::validate_driver()
// validate_roms - validate ROM definitions
//-------------------------------------------------
-void validity_checker::validate_roms()
+void validity_checker::validate_roms(device_t &root)
{
// iterate, starting with the driver's ROMs and continuing with device ROMs
- for (device_t &device : device_iterator(m_current_config->root_device()))
+ for (device_t &device : device_iterator(root))
{
// track the current device
m_current_device = &device;
// scan the ROM entries for this device
- const char *last_region_name = "???";
- const char *last_name = "???";
+ char const *last_region_name = "???";
+ char const *last_name = "???";
u32 current_length = 0;
int items_since_region = 1;
int last_bios = 0;
int total_files = 0;
- for (const rom_entry *romp = rom_first_region(device); romp != nullptr && !ROMENTRY_ISEND(romp); romp++)
+ std::unordered_map<std::string, int> bios_names;
+ std::unordered_map<std::string, std::string> bios_descs;
+ char const *defbios = nullptr;
+ for (tiny_rom_entry const *romp = device.rom_region(); romp && !ROMENTRY_ISEND(romp); ++romp)
{
- // if this is a region, make sure it's valid, and record the length
- if (ROMENTRY_ISREGION(romp))
+ if (ROMENTRY_ISREGION(romp)) // if this is a region, make sure it's valid, and record the length
{
// if we haven't seen any items since the last region, print a warning
if (items_since_region == 0)
osd_printf_warning("Empty ROM region '%s' (warning)\n", last_region_name);
// reset our region tracking states
- const char *basetag = ROMREGION_GETTAG(romp);
+ char const *const basetag = romp->name;
items_since_region = (ROMREGION_ISERASE(romp) || ROMREGION_ISDISKDATA(romp)) ? 1 : 0;
last_region_name = basetag;
// check for a valid tag
- if (basetag == nullptr)
+ if (!basetag)
{
osd_printf_error("ROM_REGION tag with nullptr name\n");
continue;
@@ -1473,34 +1543,55 @@ void validity_checker::validate_roms()
validate_tag(basetag);
// generate the full tag
- std::string fulltag = rom_region_name(device, romp);
+ std::string const fulltag = device.subtag(romp->name);
// attempt to add it to the map, reporting duplicates as errors
current_length = ROMREGION_GETLENGTH(romp);
if (!m_region_map.insert(std::make_pair(fulltag, current_length)).second)
osd_printf_error("Multiple ROM_REGIONs with the same tag '%s' defined\n", fulltag.c_str());
}
-
- // If this is a system bios, make sure it is using the next available bios number
- else if (ROMENTRY_ISSYSTEM_BIOS(romp))
+ else if (ROMENTRY_ISSYSTEM_BIOS(romp)) // If this is a system bios, make sure it is using the next available bios number
{
- int bios_flags = ROM_GETBIOSFLAGS(romp);
+ int const bios_flags = ROM_GETBIOSFLAGS(romp);
+ char const *const biosname = romp->name;
if (bios_flags != last_bios + 1)
- osd_printf_error("Non-sequential bios %s (specified as %d, expected to be %d)\n", ROM_GETNAME(romp), bios_flags, last_bios + 1);
+ osd_printf_error("Non-sequential BIOS %s (specified as %d, expected to be %d)\n", biosname, bios_flags, last_bios + 1);
last_bios = bios_flags;
- }
- // if this is a file, make sure it is properly formatted
- else if (ROMENTRY_ISFILE(romp))
+ // validate the name
+ if (strlen(biosname) > 16)
+ osd_printf_error("BIOS name %s exceeds maximum 16 characters\n", biosname);
+ for (char const *s = biosname; *s; ++s)
+ {
+ if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '.') && (*s != '_') && (*s != '-'))
+ {
+ osd_printf_error("BIOS name %s contains invalid characters\n", biosname);
+ break;
+ }
+ }
+
+ // check for duplicate names/descriptions
+ auto const nameins = bios_names.emplace(biosname, bios_flags);
+ if (!nameins.second)
+ osd_printf_error("Duplicate BIOS name %s specified (%d and %d)\n", biosname, nameins.first->second, bios_flags);
+ auto const descins = bios_descs.emplace(romp->hashdata, biosname);
+ if (!descins.second)
+ osd_printf_error("BIOS %s has duplicate description '%s' (was %s)\n", biosname, romp->hashdata, descins.first->second.c_str());
+ }
+ else if (ROMENTRY_ISDEFAULT_BIOS(romp)) // if this is a default BIOS setting, remember it so it to check at the end
+ {
+ defbios = romp->name;
+ }
+ else if (ROMENTRY_ISFILE(romp)) // if this is a file, make sure it is properly formatted
{
// track the last filename we found
- last_name = ROM_GETNAME(romp);
+ last_name = romp->name;
total_files++;
// make sure the hash is valid
util::hash_collection hashes;
- if (!hashes.from_internal_string(ROM_GETHASHDATA(romp)))
- osd_printf_error("ROM '%s' has an invalid hash string '%s'\n", last_name, ROM_GETHASHDATA(romp));
+ if (!hashes.from_internal_string(romp->hashdata))
+ osd_printf_error("ROM '%s' has an invalid hash string '%s'\n", last_name, romp->hashdata);
}
// for any non-region ending entries, make sure they don't extend past the end
@@ -1512,11 +1603,14 @@ void validity_checker::validate_roms()
}
}
+ // check that default BIOS exists
+ if (defbios && (bios_names.find(defbios) == bios_names.end()))
+ osd_printf_error("Default BIOS '%s' not found\n", defbios);
+
// final check for empty regions
if (items_since_region == 0)
osd_printf_warning("Empty ROM region '%s' (warning)\n", last_region_name);
-
// reset the current device
m_current_device = nullptr;
}
@@ -1782,6 +1876,22 @@ void validity_checker::validate_inputs()
for (ioport_setting &setting : field.settings())
if (!setting.condition().none())
validate_condition(setting.condition(), device, port_map);
+
+ // verify natural keyboard codes
+ for (int which = 0; which < 1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1); which++)
+ {
+ std::vector<char32_t> codes = field.keyboard_codes(which);
+ for (char32_t code : codes)
+ {
+ if (!uchar_isvalid(code))
+ {
+ osd_printf_error("Field '%s' has non-character U+%04X in PORT_CHAR(%d)\n",
+ name,
+ (unsigned)code,
+ (int)code);
+ }
+ }
+ }
}
// done with this port
@@ -1815,48 +1925,69 @@ void validity_checker::validate_devices()
validate_tag(device.basetag());
// look for duplicates
- if (!device_map.insert(device.tag()).second)
- osd_printf_error("Multiple devices with the same tag '%s' defined\n", device.tag());
-
- // all devices must have a shortname
- if (strcmp(device.shortname(), "") == 0)
- osd_printf_error("Device does not have short name defined\n");
-
- // all devices must have a source file defined
- if (strcmp(device.source(), "") == 0)
- osd_printf_error("Device does not have source file location defined\n");
+ bool duplicate = !device_map.insert(device.tag()).second;
+ if (duplicate)
+ osd_printf_error("Multiple devices with the same tag defined\n");
// check for device-specific validity check
device.validity_check(*this);
// done with this device
m_current_device = nullptr;
- }
- // if device is slot cart device, we must have a shortname
- std::unordered_set<std::string> slot_device_map;
- for (const device_slot_interface &slot : slot_interface_iterator(m_current_config->root_device()))
- {
- for (auto &option : slot.option_list())
+ // if it's a slot, iterate over possible cards (don't recurse, or you'll stack infinite tee connectors)
+ device_slot_interface *const slot = dynamic_cast<device_slot_interface *>(&device);
+ if (slot != nullptr && !slot->fixed() && !duplicate)
{
- std::string temptag("_");
- temptag.append(option.second->name());
- device_t *dev = const_cast<machine_config &>(*m_current_config).device_add(&m_current_config->root_device(), temptag.c_str(), option.second->devtype(), 0);
-
- // notify this device and all its subdevices that they are now configured
- for (device_t &device : device_iterator(*dev))
- if (!device.configured())
- device.config_complete();
-
- if (strcmp(dev->shortname(), "") == 0) {
- if (slot_device_map.insert(dev->name()).second)
- osd_printf_error("Device '%s' is slot cart device but does not have short name defined\n", dev->name());
- }
+ for (auto &option : slot->option_list())
+ {
+ // the default option is already instantiated here, so don't try adding it again
+ if (slot->default_option() != nullptr && option.first == slot->default_option())
+ continue;
+
+ device_t *const card = m_current_config->device_add(&slot->device(), option.second->name(), option.second->devtype(), option.second->clock());
- const_cast<machine_config &>(*m_current_config).device_remove(&m_current_config->root_device(), temptag.c_str());
+ const char *const def_bios = option.second->default_bios();
+ if (def_bios)
+ device_t::static_set_default_bios_tag(*card, def_bios);
+ machine_config_constructor const additions = option.second->machine_config();
+ if (additions)
+ (*additions)(*m_current_config, card, card);
+
+ for (device_slot_interface &subslot : slot_interface_iterator(*card))
+ {
+ if (subslot.fixed())
+ {
+ device_slot_option const *const suboption = subslot.option(subslot.default_option());
+ if (suboption)
+ {
+ device_t *const sub_card = m_current_config->device_add(&subslot.device(), suboption->name(), suboption->devtype(), suboption->clock());
+ const char *const sub_bios = suboption->default_bios();
+ if (sub_bios)
+ device_t::static_set_default_bios_tag(*sub_card, sub_bios);
+ machine_config_constructor const sub_additions = suboption->machine_config();
+ if (sub_additions)
+ (*sub_additions)(*m_current_config, sub_card, sub_card);
+ }
+ }
+ }
+
+ for (device_t &card_dev : device_iterator(*card))
+ card_dev.config_complete();
+ validate_roms(*card);
+
+ for (device_t &card_dev : device_iterator(*card))
+ {
+ m_current_device = &card_dev;
+ card_dev.findit(true);
+ card_dev.validity_check(*this);
+ m_current_device = nullptr;
+ }
+
+ m_current_config->device_remove(&slot->device(), option.second->name());
+ }
}
}
-
}
@@ -1875,87 +2006,95 @@ void validity_checker::validate_device_types()
m_verbose_text.clear();
std::unordered_map<std::string, std::add_pointer_t<device_type> > device_name_map, device_shortname_map;
- std::unordered_set<std::type_index> device_types;
machine_config config(GAME_NAME(___empty), m_drivlist.options());
for (device_type type : registered_device_types)
{
- if (!device_types.emplace(type.type()).second)
+ device_t *const dev = config.device_add(&config.root_device(), "_tmp", type, 0);
+
+ char const *name((dev->shortname() && *dev->shortname()) ? dev->shortname() : type.type().name());
+ std::string const description((dev->source() && *dev->source()) ? util::string_format("%s(%s)", core_filename_extract_base(dev->source()).c_str(), name) : name);
+
+ // ensure shortname exists
+ if (!dev->shortname() || !*dev->shortname())
{
- osd_printf_error("Device class '%s' registered multiple times\n", type.type().name());
+ osd_printf_error("Device %s does not have short name defined\n", description.c_str());
}
else
{
- device_t *const dev = config.device_add(&config.root_device(), "_tmp", type, 0);
+ // make sure the device name is not too long
+ if (strlen(dev->shortname()) > 32)
+ osd_printf_error("Device short name must be 32 characters or less\n");
- char const *name((dev->shortname() && *dev->shortname()) ? dev->shortname() : type.type().name());
- std::string const description((dev->source() && *dev->source()) ? util::string_format("%s(%s)", core_filename_extract_base(dev->source()).c_str(), name) : name);
-
- // ensure shortname exists
- if (!dev->shortname() || !*dev->shortname())
- {
- osd_printf_error("Device %s does not have short name defined\n", description.c_str());
- }
- else
+ // check for invalid characters in shortname
+ for (char const *s = dev->shortname(); *s; ++s)
{
- // check for invalid characters in shortname
- for (char const *s = dev->shortname(); *s; ++s)
+ if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '_'))
{
- if (((*s < '0') || (*s > '9')) && ((*s < 'a') || (*s > 'z')) && (*s != '_'))
- {
- osd_printf_error("Device %s short name contains invalid characters\n", description.c_str());
- break;
- }
- }
-
- // check for name conflicts
- auto const drvname(m_names_map.find(dev->shortname()));
- auto const devname(device_shortname_map.emplace(dev->shortname(), &type));
- if (m_names_map.end() != drvname)
- {
- game_driver const &dup(*drvname->second);
- osd_printf_error("Device %s short name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup.source_file).c_str(), dup.name);
- }
- else if (!devname.second)
- {
- device_t *const dup = config.device_add(&config.root_device(), "_dup", *devname.first->second, 0);
- osd_printf_error("Device %s short name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup->source()).c_str(), dup->shortname());
- config.device_remove(&config.root_device(), "_dup");
+ osd_printf_error("Device %s short name contains invalid characters\n", description.c_str());
+ break;
}
}
- // ensure name exists
- if (!dev->name() || !*dev->name())
+ // check for name conflicts
+ std::string tmpname(dev->shortname());
+ game_driver_map::const_iterator const drvname(m_names_map.find(tmpname));
+ auto const devname(device_shortname_map.emplace(std::move(tmpname), &type));
+ if (m_names_map.end() != drvname)
{
- osd_printf_error("Device %s does not have name defined\n", description.c_str());
+ game_driver const &dup(*drvname->second);
+ osd_printf_error("Device %s short name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup.type.source()).c_str(), dup.name);
}
- else
+ else if (!devname.second)
{
- // check for description conflicts
- auto const drvdesc(m_descriptions_map.find(dev->name()));
- auto const devdesc(device_name_map.emplace(dev->name(), &type));
- if (m_names_map.end() != drvdesc)
- {
- game_driver const &dup(*drvdesc->second);
- osd_printf_error("Device %s name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup.source_file).c_str(), dup.name);
- }
- else if (!devdesc.second)
- {
- device_t *const dup = config.device_add(&config.root_device(), "_dup", *devdesc.first->second, 0);
- osd_printf_error("Device %s name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup->source()).c_str(), dup->shortname());
- config.device_remove(&config.root_device(), "_dup");
- }
+ device_t *const dup = config.device_add(&config.root_device(), "_dup", *devname.first->second, 0);
+ osd_printf_error("Device %s short name is a duplicate of %s(%s)\n", description.c_str(), core_filename_extract_base(dup->source()).c_str(), dup->shortname());
+ config.device_remove(&config.root_device(), "_dup");
}
+ }
- // ensure source exists
- if (!dev->source() || !*dev->source())
- osd_printf_error("Device %s does not have source defined\n", description.c_str());
-
- // check that reported type matches supplied type
- if (dev->type().type() != type.type())
- osd_printf_error("Device %s reports type '%s' (created with '%s')\n", description.c_str(), dev->type().type().name(), type.type().name());
-
- config.device_remove(&config.root_device(), "_tmp");
+ // ensure name exists
+ if (!dev->name() || !*dev->name())
+ {
+ osd_printf_error("Device %s does not have name defined\n", description.c_str());
+ }
+ else
+ {
+ // check for description conflicts
+ std::string tmpdesc(dev->name());
+ game_driver_map::const_iterator const drvdesc(m_descriptions_map.find(tmpdesc));
+ auto const devdesc(device_name_map.emplace(std::move(tmpdesc), &type));
+ if (m_descriptions_map.end() != drvdesc)
+ {
+ game_driver const &dup(*drvdesc->second);
+ osd_printf_error("Device %s name '%s' is a duplicate of %s(%s)\n", description.c_str(), dev->name(), core_filename_extract_base(dup.type.source()).c_str(), dup.name);
+ }
+ else if (!devdesc.second)
+ {
+ device_t *const dup = config.device_add(&config.root_device(), "_dup", *devdesc.first->second, 0);
+ osd_printf_error("Device %s name '%s' is a duplicate of %s(%s)\n", description.c_str(), dev->name(), core_filename_extract_base(dup->source()).c_str(), dup->shortname());
+ config.device_remove(&config.root_device(), "_dup");
+ }
}
+
+ // ensure source exists
+ if (!dev->source() || !*dev->source())
+ osd_printf_error("Device %s does not have source defined\n", description.c_str());
+
+ // check that reported type matches supplied type
+ if (dev->type().type() != type.type())
+ osd_printf_error("Device %s reports type '%s' (created with '%s')\n", description.c_str(), dev->type().type().name(), type.type().name());
+
+ // catch invalid flag combinations
+ device_t::feature_type const unemulated(dev->type().unemulated_features());
+ device_t::feature_type const imperfect(dev->type().imperfect_features());
+ if (unemulated & ~device_t::feature::ALL)
+ osd_printf_error("Device has invalid unemulated feature flags (0x%08lX)\n", static_cast<unsigned long>(unemulated & ~device_t::feature::ALL));
+ if (imperfect & ~device_t::feature::ALL)
+ osd_printf_error("Device has invalid imperfect feature flags (0x%08lX)\n", static_cast<unsigned long>(imperfect & ~device_t::feature::ALL));
+ if (unemulated & imperfect)
+ osd_printf_error("Device cannot have features that are both unemulated and imperfect (0x%08lX)\n", static_cast<unsigned long>(unemulated & imperfect));
+
+ config.device_remove(&config.root_device(), "_tmp");
}
// if we had warnings or errors, output