summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/device.cpp')
-rw-r--r--src/emu/device.cpp253
1 files changed, 140 insertions, 113 deletions
diff --git a/src/emu/device.cpp b/src/emu/device.cpp
index 7196b75e18f..1940c619455 100644
--- a/src/emu/device.cpp
+++ b/src/emu/device.cpp
@@ -20,7 +20,7 @@
// DEVICE TYPE REGISTRATION
//**************************************************************************
-namespace emu { namespace detail {
+namespace emu::detail {
namespace {
@@ -66,7 +66,7 @@ device_type_impl_base *device_registrar::register_device(device_type_impl_base &
return nullptr;
}
-} } // namespace emu::detail
+} // namespace emu::detail
emu::detail::device_registrar const registered_device_types;
@@ -136,6 +136,8 @@ std::vector<std::string> device_t::searchpath() const
system = system->owner();
if (system)
result = system->searchpath();
+ if (type().parent_rom_device_type())
+ result.emplace(result.begin(), type().parent_rom_device_type()->shortname());
result.emplace(result.begin(), shortname());
return result;
}
@@ -146,10 +148,10 @@ std::vector<std::string> device_t::searchpath() const
// info for a given region
//-------------------------------------------------
-memory_region *device_t::memregion(std::string _tag) const
+memory_region *device_t::memregion(std::string_view tag) const
{
// build a fully-qualified name and look it up
- auto search = machine().memory().regions().find(subtag(std::move(_tag)));
+ auto search = machine().memory().regions().find(subtag(tag));
if (search != machine().memory().regions().end())
return search->second.get();
else
@@ -162,10 +164,10 @@ memory_region *device_t::memregion(std::string _tag) const
// info for a given share
//-------------------------------------------------
-memory_share *device_t::memshare(std::string _tag) const
+memory_share *device_t::memshare(std::string_view tag) const
{
// build a fully-qualified name and look it up
- auto search = machine().memory().shares().find(subtag(std::move(_tag)));
+ auto search = machine().memory().shares().find(subtag(tag));
if (search != machine().memory().shares().end())
return search->second.get();
else
@@ -178,9 +180,9 @@ memory_share *device_t::memshare(std::string _tag) const
// bank info for a given bank
//-------------------------------------------------
-memory_bank *device_t::membank(std::string _tag) const
+memory_bank *device_t::membank(std::string_view tag) const
{
- auto search = machine().memory().banks().find(subtag(std::move(_tag)));
+ auto search = machine().memory().banks().find(subtag(tag));
if (search != machine().memory().banks().end())
return search->second.get();
else
@@ -193,10 +195,10 @@ memory_bank *device_t::membank(std::string _tag) const
// object for a given port name
//-------------------------------------------------
-ioport_port *device_t::ioport(std::string tag) const
+ioport_port *device_t::ioport(std::string_view tag) const
{
// build a fully-qualified name and look it up
- return machine().ioport().port(subtag(std::move(tag)).c_str());
+ return machine().ioport().port(subtag(tag));
}
@@ -205,7 +207,7 @@ ioport_port *device_t::ioport(std::string tag) const
// parameter
//-------------------------------------------------
-std::string device_t::parameter(const char *tag) const
+std::string device_t::parameter(std::string_view tag) const
{
// build a fully-qualified name and look it up
return machine().parameters().lookup(subtag(tag));
@@ -222,7 +224,7 @@ void device_t::add_machine_configuration(machine_config &config)
assert(&config == &m_machine_config);
machine_config::token const tok(config.begin_configuration(*this));
device_add_mconfig(config);
- for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next())
+ for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next())
autodev->end_configuration();
}
@@ -319,11 +321,7 @@ void device_t::config_complete()
void device_t::validity_check(validity_checker &valid) const
{
- // validate callbacks
- for (devcb_base const *callback : m_callbacks)
- callback->validity_check(valid);
-
- // validate via the interfaces
+ // validate mixins
for (device_interface &intf : interfaces())
intf.interface_validity_check(valid);
@@ -363,7 +361,7 @@ void device_t::reset()
// unscaled clock
//-------------------------------------------------
-void device_t::set_unscaled_clock(u32 clock)
+void device_t::set_unscaled_clock(u32 clock, bool sync_on_new_clock_domain)
{
// do nothing if no actual change
if (clock == m_unscaled_clock)
@@ -379,7 +377,7 @@ void device_t::set_unscaled_clock(u32 clock)
// if the device has already started, make sure it knows about the new clock
if (m_started)
- notify_clock_changed();
+ notify_clock_changed(sync_on_new_clock_domain);
}
@@ -437,7 +435,7 @@ attotime device_t::clocks_to_attotime(u64 numclocks) const noexcept
else
{
u32 remainder;
- u32 quotient = divu_64x32_rem(numclocks, m_clock, &remainder);
+ u32 quotient = divu_64x32_rem(numclocks, m_clock, remainder);
return attotime(quotient, u64(remainder) * u64(m_attoseconds_per_clock));
}
}
@@ -458,28 +456,6 @@ u64 device_t::attotime_to_clocks(const attotime &duration) const noexcept
//-------------------------------------------------
-// timer_alloc - allocate a timer for our device
-// callback
-//-------------------------------------------------
-
-emu_timer *device_t::timer_alloc(device_timer_id id, void *ptr)
-{
- return machine().scheduler().timer_alloc(*this, id, ptr);
-}
-
-
-//-------------------------------------------------
-// timer_set - set a temporary timer that will
-// call our device callback
-//-------------------------------------------------
-
-void device_t::timer_set(const attotime &duration, device_timer_id id, int param, void *ptr)
-{
- machine().scheduler().timer_set(duration, *this, id, param, ptr);
-}
-
-
-//-------------------------------------------------
// set_machine - notify that the machine now
// exists
//-------------------------------------------------
@@ -498,30 +474,15 @@ void device_t::set_machine(running_machine &machine)
bool device_t::findit(validity_checker *valid) const
{
bool allfound = true;
- for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->next())
+ for (auto *autodev = m_auto_finder_list; autodev; autodev = autodev->next())
{
- if (valid)
- {
- // sanity checking
- char const *const tag = autodev->finder_tag();
- if (!tag)
- {
- osd_printf_error("Finder tag is null!\n");
- allfound = false;
- continue;
- }
- if (tag[0] == '^' && tag[1] == ':')
- {
- osd_printf_error("Malformed finder tag: %s\n", tag);
- allfound = false;
- continue;
- }
- }
- allfound &= autodev->findit(valid);
+ if (!autodev->findit(valid))
+ allfound = false;
}
return allfound;
}
+
//-------------------------------------------------
// resolve_pre_map - find objects that may be used
// in memory maps
@@ -534,6 +495,7 @@ void device_t::resolve_pre_map()
m_string_buffer.reserve(1024);
}
+
//-------------------------------------------------
// resolve - find objects
//-------------------------------------------------
@@ -550,6 +512,16 @@ void device_t::resolve_post_map()
//-------------------------------------------------
+// view_register - register a view for future state saving
+//-------------------------------------------------
+
+void device_t::view_register(memory_view *view)
+{
+ m_viewlist.push_back(view);
+}
+
+
+//-------------------------------------------------
// start - start a device
//-------------------------------------------------
@@ -595,10 +567,15 @@ void device_t::start()
}
// register our save states
- save_item(NAME(m_clock));
save_item(NAME(m_unscaled_clock));
save_item(NAME(m_clock_scale));
+ // have the views register their state
+ if (!m_viewlist.empty())
+ osd_printf_verbose("%s: Registering %d views\n", m_tag, int(m_viewlist.size()));
+ for (memory_view *view : m_viewlist)
+ view->register_state();
+
// we're now officially started
m_started = true;
}
@@ -668,6 +645,21 @@ void device_t::pre_save()
void device_t::post_load()
{
+ // recompute clock-related parameters if something changed
+ u32 const scaled_clock = m_unscaled_clock * m_clock_scale;
+ if (m_clock != scaled_clock)
+ {
+ m_clock = scaled_clock;
+ m_attoseconds_per_clock = (scaled_clock == 0) ? 0 : HZ_TO_ATTOSECONDS(scaled_clock);
+
+ // recalculate all derived clocks
+ for (device_t &child : subdevices())
+ child.calculate_derived_clock();
+
+ // make sure the device knows about the new clock
+ notify_clock_changed();
+ }
+
// notify the interface
for (device_interface &intf : interfaces())
intf.interface_post_load();
@@ -682,11 +674,11 @@ void device_t::post_load()
// that the clock has changed
//-------------------------------------------------
-void device_t::notify_clock_changed()
+void device_t::notify_clock_changed(bool sync_on_new_clock_domain)
{
// first notify interfaces
for (device_interface &intf : interfaces())
- intf.interface_clock_changed();
+ intf.interface_clock_changed(sync_on_new_clock_domain);
// then notify the device
device_clock_changed();
@@ -848,22 +840,11 @@ void device_t::device_debug_setup()
//-------------------------------------------------
-// device_timer - called whenever a device timer
-// fires
-//-------------------------------------------------
-
-void device_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- // do nothing by default
-}
-
-
-//-------------------------------------------------
// subdevice_slow - perform a slow name lookup,
// caching the results
//-------------------------------------------------
-device_t *device_t::subdevice_slow(const char *tag) const
+device_t *device_t::subdevice_slow(std::string_view tag) const
{
// resolve the full path
std::string fulltag = subtag(tag);
@@ -875,16 +856,22 @@ device_t *device_t::subdevice_slow(const char *tag) const
// walk the device list to the final path
device_t *curdevice = &mconfig().root_device();
- if (fulltag.length() > 1)
- for (int start = 1, end = fulltag.find_first_of(':', start); start != 0 && curdevice != nullptr; start = end + 1, end = fulltag.find_first_of(':', start))
+ std::string_view part(std::string_view(fulltag).substr(1));
+ while (!part.empty() && curdevice != nullptr)
+ {
+ std::string_view::size_type end = part.find_first_of(':');
+ if (end == std::string::npos)
{
- std::string part(fulltag, start, (end == -1) ? -1 : end - start);
curdevice = curdevice->subdevices().find(part);
+ part = std::string_view();
+ }
+ else
+ {
+ curdevice = curdevice->subdevices().find(part.substr(0, end));
+ part.remove_prefix(end + 1);
}
+ }
- // if we got a match, add to the fast map
- if (curdevice != nullptr)
- m_subdevices.m_tagmap.insert(std::make_pair(tag, curdevice));
return curdevice;
}
@@ -894,14 +881,13 @@ device_t *device_t::subdevice_slow(const char *tag) const
// to our device based on the provided tag
//-------------------------------------------------
-std::string device_t::subtag(std::string _tag) const
+std::string device_t::subtag(std::string_view tag) const
{
- const char *tag = _tag.c_str();
std::string result;
- if (*tag == ':')
+ if (!tag.empty() && (tag[0] == ':'))
{
// if the tag begins with a colon, ignore our path and start from the root
- tag++;
+ tag.remove_prefix(1);
result.assign(":");
}
else
@@ -909,28 +895,41 @@ std::string device_t::subtag(std::string _tag) const
// otherwise, start with our path
result.assign(m_tag);
if (result != ":")
- result.append(":");
+ result.append(1, ':');
}
// iterate over the tag, look for special path characters to resolve
- const char *caret;
- while ((caret = strchr(tag, '^')) != nullptr)
+ std::string_view::size_type delimiter;
+ while ((delimiter = tag.find_first_of("^:")) != std::string_view::npos)
{
// copy everything up to there
- result.append(tag, caret - tag);
- tag = caret + 1;
+ bool const parent = tag[delimiter] == '^';
+ result.append(tag, 0, delimiter);
+ tag.remove_prefix(delimiter + 1);
- // strip trailing colons
- int len = result.length();
- while (result[--len] == ':')
- result = result.substr(0, len);
+ if (parent)
+ {
+ // strip trailing colons
+ std::string::size_type len = result.length();
+ while ((len > 1) && (result[--len] == ':'))
+ result.resize(len);
- // remove the last path part, leaving the last colon
- if (result != ":")
+ // remove the last path part, leaving the last colon
+ if (result != ":")
+ {
+ std::string::size_type lastcolon = result.find_last_of(':');
+ if (lastcolon != std::string::npos)
+ result.resize(lastcolon + 1);
+ }
+ }
+ else
{
- int lastcolon = result.find_last_of(':');
- if (lastcolon != -1)
- result = result.substr(0, lastcolon + 1);
+ // collapse successive colons
+ if (result.back() != ':')
+ result.append(1, ':');
+ delimiter = tag.find_first_not_of(':');
+ if (delimiter != std::string_view::npos)
+ tag.remove_prefix(delimiter);
}
}
@@ -938,30 +937,58 @@ std::string device_t::subtag(std::string _tag) const
result.append(tag);
// strip trailing colons up to the root
- int len = result.length();
- while (len > 1 && result[--len] == ':')
- result = result.substr(0, len);
+ std::string::size_type len = result.length();
+ while ((len > 1) && (result[--len] == ':'))
+ result.resize(len);
return result;
}
//-------------------------------------------------
-// register_auto_finder - add a new item to the
-// list of stuff to find after we go live
+// append - add a new subdevice to the list
//-------------------------------------------------
-finder_base *device_t::register_auto_finder(finder_base &autodev)
+device_t &device_t::subdevice_list::append(std::unique_ptr<device_t> &&device)
{
- // add to this list
- finder_base *old = m_auto_finder_list;
- m_auto_finder_list = &autodev;
- return old;
+ device_t &result(m_list.append(*device.release()));
+ m_tagmap.emplace(result.m_basetag, std::ref(result));
+ return result;
}
-void device_t::register_callback(devcb_base &callback)
+//-------------------------------------------------
+// replace_and_remove - add a new device to
+// replace an existing subdevice
+//-------------------------------------------------
+
+device_t &device_t::subdevice_list::replace_and_remove(std::unique_ptr<device_t> &&device, device_t &existing)
+{
+ m_tagmap.erase(existing.m_basetag);
+ device_t &result(m_list.replace_and_remove(*device.release(), existing));
+ m_tagmap.emplace(result.m_basetag, std::ref(result));
+ return result;
+}
+
+
+//-------------------------------------------------
+// remove - remove a subdevice from the list
+//-------------------------------------------------
+
+void device_t::subdevice_list::remove(device_t &device)
+{
+ m_tagmap.erase(device.m_basetag);
+ m_list.remove(device);
+}
+
+
+//-------------------------------------------------
+// register_auto_finder - add a new item to the
+// list of stuff to find after we go live
+//-------------------------------------------------
+
+device_resolver_base *device_t::register_auto_finder(device_resolver_base &autodev)
{
- m_callbacks.emplace_back(&callback);
+ return std::exchange(m_auto_finder_list, &autodev);
}
@@ -1113,7 +1140,7 @@ void device_interface::interface_post_load()
// implementation
//-------------------------------------------------
-void device_interface::interface_clock_changed()
+void device_interface::interface_clock_changed(bool sync_on_new_clock_domain)
{
// do nothing by default
}