// license:BSD-3-Clause // copyright-holders:Aaron Giles /*************************************************************************** mconfig.c Machine configuration macros and functions. ***************************************************************************/ #include "emu.h" #include "emuopts.h" #include //************************************************************************** // MACHINE CONFIGURATIONS //************************************************************************** //------------------------------------------------- // machine_config - constructor //------------------------------------------------- machine_config::machine_config(const game_driver &gamedrv, emu_options &options) : m_minimum_quantum(attotime::zero), m_default_layout(nullptr), m_gamedrv(gamedrv), m_options(options) { // construct the config (*gamedrv.machine_config)(*this, nullptr, nullptr); bool is_selected_driver = core_stricmp(gamedrv.name,options.system_name())==0; // intialize slot devices - make sure that any required devices have been allocated for (device_slot_interface &slot : slot_interface_iterator(root_device())) { device_t &owner = slot.device(); std::string selval; bool isdefault = (options.priority(owner.tag()+1)==OPTION_PRIORITY_DEFAULT); if (is_selected_driver && options.exists(owner.tag()+1)) selval = options.main_value(owner.tag()+1); else if (slot.default_option() != nullptr) selval.assign(slot.default_option()); if (!selval.empty()) { const device_slot_option *option = slot.option(selval.c_str()); if (option && (isdefault || option->selectable())) { device_t *new_dev = device_add(&owner, option->name(), option->devtype(), option->clock()); const char *default_bios = option->default_bios(); if (default_bios != nullptr) device_t::static_set_default_bios_tag(*new_dev, default_bios); machine_config_constructor additions = option->machine_config(); if (additions != nullptr) (*additions)(const_cast(*this), new_dev, new_dev); const input_device_default *input_device_defaults = option->input_device_defaults(); if (input_device_defaults) device_t::static_set_input_default(*new_dev, input_device_defaults); } else throw emu_fatalerror("Unknown slot option '%s' in slot '%s'", selval.c_str(), owner.tag()+1); } } // when finished, set the game driver driver_device::static_set_game(*m_root_device, gamedrv); // then notify all devices that their configuration is complete for (device_t &device : device_iterator(root_device())) if (!device.configured()) device.config_complete(); } //------------------------------------------------- // ~machine_config - destructor //------------------------------------------------- machine_config::~machine_config() { } //------------------------------------------------- // first_screen - return a pointer to the first // screen device //------------------------------------------------- screen_device *machine_config::first_screen() const { return screen_device_iterator(root_device()).first(); } //------------------------------------------------- // device_add - configuration helper to add a // new device //------------------------------------------------- device_t *machine_config::device_add(device_t *owner, const char *tag, device_type type, UINT32 clock) { const char *orig_tag = tag; // if the device path is absolute, start from the root if (tag[0] == ':') { tag++; owner = m_root_device.get(); } // go down the path until we're done with it while (strchr(tag, ':')) { const char *next = strchr(tag, ':'); assert(next != tag); std::string part(tag, next-tag); owner = owner->subdevices().find(part); if (owner == nullptr) throw emu_fatalerror("Could not find %s when looking up path for device %s\n", part.c_str(), orig_tag); tag = next+1; } assert(tag[0] != '\0'); if (owner != nullptr) { // allocate the new device device_t *device = (*type)(*this, tag, owner, clock); // append it to the owner's list return &config_new_device(owner->subdevices().m_list.append(*device)); } // allocate the root device directly assert(m_root_device == nullptr); m_root_device.reset((*type)(*this, tag, nullptr, clock)); return &config_new_device(*m_root_device); } //------------------------------------------------- // device_replace - configuration helper to // replace one device with a new device //------------------------------------------------- device_t *machine_config::device_replace(device_t *owner, const char *tag, device_type type, UINT32 clock) { // find the original device by relative tag (must exist) assert(owner != nullptr); device_t *old_device = owner->subdevice(tag); if (old_device == nullptr) { osd_printf_warning("Warning: attempting to replace non-existent device '%s'\n", tag); return device_add(owner, tag, type, clock); } // make sure we have the old device's actual owner owner = old_device->owner(); assert(owner != nullptr); // remove references to the old device remove_references(*old_device); // allocate the new device device_t *new_device = (*type)(*this, tag, owner, clock); // substitute it for the old one in the owner's list return &config_new_device(owner->subdevices().m_list.replace_and_remove(*new_device, *old_device)); } //------------------------------------------------- // device_remove - configuration helper to // remove a device //------------------------------------------------- device_t *machine_config::device_remove(device_t *owner, const char *tag) { // find the original device by relative tag (must exist) assert(owner != nullptr); device_t *device = owner->subdevice(tag); if (device == nullptr) { osd_printf_warning("Warning: attempting to remove non-existent device '%s'\n", tag); return nullptr; } // make sure we have the old device's actual owner owner = device->owner(); assert(owner != nullptr); // remove references to the old device remove_references(*device); // let the device's owner do the work owner->subdevices().m_list.remove(*device); return nullptr; } //------------------------------------------------- // device_find - configuration helper to // locate a device //------------------------------------------------- device_t *machine_config::device_find(device_t *owner, const char *tag) { // find the original device by relative tag (must exist) assert(owner != nullptr); device_t *device = owner->subdevice(tag); assert(device != nullptr); if (device == nullptr) throw emu_fatalerror("Unable to find device '%s'\n", tag); // return the device return device; } //------------------------------------------------- // remove_references - globally remove references // to a device about to be removed from the tree //------------------------------------------------- void machine_config::remove_references(ATTR_UNUSED device_t &device) { // iterate over all devices and remove any references for (device_t &scan : device_iterator(root_device())) scan.subdevices().m_tagmap.clear(); //remove(&device); } //------------------------------------------------- // config_new_device - helper for recursive // configuration of newly added devices //------------------------------------------------- device_t &machine_config::config_new_device(device_t &device) { // apply any machine configuration owned by the device now machine_config_constructor additions = device.machine_config_additions(); if (additions != nullptr) (*additions)(*this, &device, nullptr); // return the new device return device; }