summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/device.cpp
blob: 97c345788da8e42fd8cfb0bc8acef5d0f3a91020 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                

                                                                            
            


                               

                                                                            
                
                   
                           

 
                                                                            
                          


                                                                            


                                            

                                                   
                                                                                                                                                                                
                       


                                        
                                 
                               
                                
 





                                                                                     
                                          
                                          
                                       
 

                                   


                                         
                                           
 

                                                                                                      
            
                                  
                                       


 
                                                   








                                                   
                                              


                                                   
                                                          
 
                                                      
                                                                       
 
 

                                                   



                                                   
                                                        
 
                                                      
                                                                      




                                                   


                                                   
                                                      
 
                                                      
                                                                     



                                                   



                                                   
                                                    
 
                                                      
                                                            



                                                   



                                                   
                                                      
 
                                                      
                                                          



                                                   








                                                               
                                                  








                                                                                                              
                                     


                                                   
                                

                                      

                                                   
 

                                        
 

                                       


 
                                                   


                                                   
 
                                                            
 
                                      

                                                     
 
                                         
                                     

 
 
                                                   
                          
                                                   
 
                      
 
                                               

                                                   


                           
 
                                  

                                            
 

                                                     

                                                

                                                   
 
 
 
                                                   
                                                
                  

                                                   
                                               
 

                                                   
                                                                                  
                               
 
 
 
                                                   

                                                 
                                                   
 
                                                 
 

                                                   
                                                                                  
                               
 
 
 
                                                   

                                             
                                                   
 
                                                             
 







                                                                                               


 
                                                   

                                               

                                                   
                                                                   
 
                                                                                                                          


 
                                                   

                                                 

                                                   
                                                               
 
                                                                 


 
                                                   

                                               
                                                   
 
                                                                                            
 
                                                                         



                                                   

                                             

                                                   
                                                    
 

                                 

 




                                                   
                                              

                             
                                                                                                      

















                                                                                    
                                                          
         

                        

                                                   
                          

                                                   
                      
 
                                          
                           
                                                                                         

                                               

                                                   










                                                                                          
                                                                                                   
         
                                                                                     
                                                                            
                                                                                               


                                                

                                                   






                                                              
                                                                









                                          



                                                   
                        

                                                   
                     
 
                                               

                                                   




                                                

                                                   

                                  
                        


                                                                      
                            



                                                   
                                      

                                                   
                            
 
                               

                                                   


                             



                                                   

                                                 

                                                   
                         
 
                               

                                                   


                            



                                                   

                                                  

                                                   
                          
 
                               

                                                   


                            



                                                   

                                                

                                                   
                                     
 
                                  

                                                   


                                 



                                                   


                                            

                                                   
                                       




                                
                                                   

                                                   

                                                   
                                                                   
 
                                



                                                   

                                                 

                                                   
                                                    
 
                          
                       



                                                   


                                                  

                                                   
                                                                     
 
                          
                       


 
                                                   

                                                  
                                                   
 
                                                       
 
                          
                       


 
                                                   


                                               
                                                   
 
                             
 
                                
 
 
 
                                                   












                                                   

                                                 
                                                   
 
                            
 
                                


 
                                                   


                                                
                                                   
 
                                
 
                                

 
 
                                                   

                                                 
                            
                                                   
 
                                 
 
                                


 
                                                   



                                                
                                                   
 
                                     
 
                                



                                                   

                                                 

                                                   
                                   
 
                                



                                                   

                                                 

                                                   
                                                                                       
 
                                



                                                   



                                                   
                                                         

                                
                                          







                                                                                  
                                 
                                                                                                                                                                          
                 
                                                                                         
                                                                       
                 
 
                                                 
                                 
                                                                             








                                                   
                                                   
 
                           



                                                                                  
                                   
         
 


                                         
                                     
                                  
                                           



                                                                            
                                                     

                                              
                                                
                                
 
                                        
                                          
                                            
                                                       
 


                                                                    
                                                                 
                                            
                                                                         



                               
                           

                                               
                                  
                                               
                                               




                                                   

                                                
                                                   
 
                                                                 
 
                           
                                              
                                      
                   

 



                                                                            
                                                   
                                  

                                                   
                                                                      
                                    

                                 
 
                                   
                                                                                                                     
                        



                                                   
                                  

                                                   
                                     
 



                                                   


                                            

                                                   
                                                  

                                


 
                                                   


                                                 
                                                   
 
                                                                              
 
 
 

                                                   

                                           

                                                   
                                            





                                                   

                                           

                                                   
                                             

                                


 
                                                   

                                           

                                                   
                                            





                                                   

                                           
                                                   
 
                                             
 
                                
 


                                                   

                                          

                                                   
                                           
 
                                



                                                   

                                          

                                                   
                                            
 
                                



                                                   


                                                   

                                                   
                                           
 
                                



                                                   


                                                    

                                                   
                                            
 
                                



                                                   



                                                

                                                   
                                                
 
                                



                                                   


                                               

                                                   
                                              
 
                                
 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    device.c

    Device interface functions.

***************************************************************************/

#include "emu.h"
#include "string.h"
#include "debug/debugcpu.h"


//**************************************************************************
//  LIVE DEVICE MANAGEMENT
//**************************************************************************

//-------------------------------------------------
//  device_t - constructor for a new
//  running device; initial state is derived
//  from the provided config
//-------------------------------------------------

device_t::device_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
	: m_type(type),
		m_name(name),
		m_shortname(shortname),
		m_searchpath(shortname),
		m_source(source),
		m_owner(owner),
		m_next(nullptr),

		m_configured_clock(clock),
		m_unscaled_clock(clock),
		m_clock(clock),
		m_clock_scale(1.0),
		m_attoseconds_per_clock((clock == 0) ? 0 : HZ_TO_ATTOSECONDS(clock)),

		m_machine_config(mconfig),
		m_input_defaults(nullptr),
		m_default_bios_tag(""),

		m_machine(nullptr),
		m_save(nullptr),
		m_basetag(tag),
		m_config_complete(false),
		m_started(false),
		m_auto_finder_list(nullptr)
{
	if (owner != nullptr)
		m_tag.assign((owner->owner() == nullptr) ? "" : owner->tag()).append(":").append(tag);
	else
		m_tag.assign(":");
	static_set_clock(*this, clock);
}


//-------------------------------------------------
//  ~device_t - destructor for a device_t
//-------------------------------------------------

device_t::~device_t()
{
}


//-------------------------------------------------
//  memregion - return a pointer to the region
//  info for a given region
//-------------------------------------------------

memory_region *device_t::memregion(const char *_tag) const
{
	// build a fully-qualified name and look it up
	return machine().memory().regions().find(subtag(_tag).c_str());
}


//-------------------------------------------------
//  memshare - return a pointer to the memory share
//  info for a given share
//-------------------------------------------------

memory_share *device_t::memshare(const char *_tag) const
{
	// build a fully-qualified name and look it up
	return machine().memory().shares().find(subtag(_tag).c_str());
}


//-------------------------------------------------
//  membank - return a pointer to the memory
//  bank info for a given bank
//-------------------------------------------------

memory_bank *device_t::membank(const char *_tag) const
{
	// build a fully-qualified name and look it up
	return machine().memory().banks().find(subtag(_tag).c_str());
}


//-------------------------------------------------
//  ioport - return a pointer to the I/O port
//  object for a given port name
//-------------------------------------------------

ioport_port *device_t::ioport(const char *tag) const
{
	// build a fully-qualified name and look it up
	return machine().ioport().port(subtag(tag).c_str());
}


//-------------------------------------------------
//  ioport - return a pointer to the I/O port
//  object for a given port name
//-------------------------------------------------

std::string device_t::parameter(const char *tag) const
{
	// build a fully-qualified name and look it up
	return machine().parameters().lookup(subtag(tag));
}


//-------------------------------------------------
//  static_set_clock - set/change the clock on
//  a device
//-------------------------------------------------

void device_t::static_set_clock(device_t &device, UINT32 clock)
{
	// derive the clock from our owner if requested
	if ((clock & 0xff000000) == 0xff000000)
	{
		assert(device.m_owner != nullptr);
		clock = device.m_owner->m_configured_clock * ((clock >> 12) & 0xfff) / ((clock >> 0) & 0xfff);
	}

	device.m_clock = device.m_unscaled_clock = device.m_configured_clock = clock;
	device.m_attoseconds_per_clock = (clock == 0) ? 0 : HZ_TO_ATTOSECONDS(clock);
}


//-------------------------------------------------
//  config_complete - called when the
//  configuration of a device is complete
//-------------------------------------------------

void device_t::config_complete()
{
	// first notify the interfaces
	for (device_interface &intf : interfaces())
		intf.interface_config_complete();

	// then notify the device itself
	device_config_complete();

	// then mark ourselves complete
	m_config_complete = true;
}


//-------------------------------------------------
//  validity_check - validate a device after the
//  configuration has been constructed
//-------------------------------------------------

void device_t::validity_check(validity_checker &valid) const
{
	// validate via the interfaces
	for (device_interface &intf : interfaces())
		intf.interface_validity_check(valid);

	// let the device itself validate
	device_validity_check(valid);
}


//-------------------------------------------------
//  reset - reset a device
//-------------------------------------------------

void device_t::reset()
{
	// let the interfaces do their pre-work
	for (device_interface &intf : interfaces())
		intf.interface_pre_reset();

	// reset the device
	device_reset();

	// reset all child devices
	for (device_t &child : subdevices())
		child.reset();

	// now allow for some post-child reset action
	device_reset_after_children();

	// let the interfaces do their post-work
	for (device_interface &intf : interfaces())
		intf.interface_post_reset();
}


//-------------------------------------------------
//  set_unscaled_clock - sets the given device's
//  unscaled clock
//-------------------------------------------------

void device_t::set_unscaled_clock(UINT32 clock)
{
	m_unscaled_clock = clock;
	m_clock = m_unscaled_clock * m_clock_scale;
	m_attoseconds_per_clock = (m_clock == 0) ? 0 : HZ_TO_ATTOSECONDS(m_clock);
	notify_clock_changed();
}


//-------------------------------------------------
//  set_clock_scale - sets a scale factor for the
//  device's clock
//-------------------------------------------------

void device_t::set_clock_scale(double clockscale)
{
	m_clock_scale = clockscale;
	m_clock = m_unscaled_clock * m_clock_scale;
	m_attoseconds_per_clock = (m_clock == 0) ? 0 : HZ_TO_ATTOSECONDS(m_clock);
	notify_clock_changed();
}


//-------------------------------------------------
//  clocks_to_attotime - converts a number of
//  clock ticks to an attotime
//-------------------------------------------------

attotime device_t::clocks_to_attotime(UINT64 numclocks) const
{
	if (numclocks < m_clock)
		return attotime(0, numclocks * m_attoseconds_per_clock);
	else
	{
		UINT32 remainder;
		UINT32 quotient = divu_64x32_rem(numclocks, m_clock, &remainder);
		return attotime(quotient, (UINT64)remainder * (UINT64)m_attoseconds_per_clock);
	}
}


//-------------------------------------------------
//  attotime_to_clocks - converts a duration as
//  attotime to CPU clock ticks
//-------------------------------------------------

UINT64 device_t::attotime_to_clocks(const attotime &duration) const
{
	return mulu_32x32(duration.seconds(), m_clock) + (UINT64)duration.attoseconds() / (UINT64)m_attoseconds_per_clock;
}


//-------------------------------------------------
//  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
//-------------------------------------------------

void device_t::set_machine(running_machine &machine)
{
	m_machine = &machine;
	m_save = &machine.save();
}

//-------------------------------------------------
//  findit - seach for all objects in auto finder
//  list and return status
//-------------------------------------------------

bool device_t::findit(bool isvalidation) const
{
	bool allfound = true;
	for (finder_base *autodev = m_auto_finder_list; autodev != nullptr; autodev = autodev->m_next)
	{
		if (isvalidation)
		{
			// sanity checking
			const char *tag = autodev->finder_tag();
			if (tag == nullptr)
			{
				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(isvalidation);
	}
	return allfound;
}

//-------------------------------------------------
//  start - start a device
//-------------------------------------------------

void device_t::start()
{
	// find all the registered devices
	if (!findit(false))
		throw emu_fatalerror("Missing some required objects, unable to proceed");

	// let the interfaces do their pre-work
	for (device_interface &intf : interfaces())
		intf.interface_pre_start();

	// remember the number of state registrations
	int state_registrations = machine().save().registration_count();

	// start the device
	device_start();

	// complain if nothing was registered by the device
	state_registrations = machine().save().registration_count() - state_registrations;
	device_execute_interface *exec;
	device_sound_interface *sound;
	if (state_registrations == 0 && (interface(exec) || interface(sound)) && type() != SPEAKER)
	{
		logerror("Device '%s' did not register any state to save!\n", tag());
		if ((machine().system().flags & MACHINE_SUPPORTS_SAVE) != 0)
			fatalerror("Device '%s' did not register any state to save!\n", tag());
	}

	// let the interfaces do their post-work
	for (device_interface &intf : interfaces())
		intf.interface_post_start();

	// force an update of the clock
	notify_clock_changed();

	// if we're debugging, create a device_debug object
	if ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0)
	{
		m_debug = std::make_unique<device_debug>(*this);
		debug_setup();
	}

	// register our save states
	save_item(NAME(m_clock));
	save_item(NAME(m_unscaled_clock));
	save_item(NAME(m_clock_scale));

	// we're now officially started
	m_started = true;
}


//-------------------------------------------------
//  stop - stop a device
//-------------------------------------------------

void device_t::stop()
{
	// let the interfaces do their pre-work
	for (device_interface &intf : interfaces())
		intf.interface_pre_stop();

	// stop the device
	device_stop();

	// let the interfaces do their post-work
	for (device_interface &intf : interfaces())
		intf.interface_post_stop();

	// free any debugging info
	m_debug.reset();

	// we're now officially stopped, and the machine is off-limits
	m_started = false;
	m_machine = nullptr;
}


//-------------------------------------------------
//  debug_setup - set up for debugging
//-------------------------------------------------

void device_t::debug_setup()
{
	// notify the interface
	for (device_interface &intf : interfaces())
		intf.interface_debug_setup();

	// notify the device
	device_debug_setup();
}


//-------------------------------------------------
//  pre_save - tell the device and its interfaces
//  that we are about to save
//-------------------------------------------------

void device_t::pre_save()
{
	// notify the interface
	for (device_interface &intf : interfaces())
		intf.interface_pre_save();

	// notify the device
	device_pre_save();
}


//-------------------------------------------------
//  post_load - tell the device and its interfaces
//  that we just completed a load
//-------------------------------------------------

void device_t::post_load()
{
	// notify the interface
	for (device_interface &intf : interfaces())
		intf.interface_post_load();

	// notify the device
	device_post_load();
}


//-------------------------------------------------
//  notify_clock_changed - notify all interfaces
//  that the clock has changed
//-------------------------------------------------

void device_t::notify_clock_changed()
{
	// first notify interfaces
	for (device_interface &intf : interfaces())
		intf.interface_clock_changed();

	// then notify the device
	device_clock_changed();
}


//-------------------------------------------------
//  device_config_complete - perform any
//  operations now that the configuration is
//  complete
//-------------------------------------------------

void device_t::device_config_complete()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_validity_check - validate a device after
//  the configuration has been constructed
//-------------------------------------------------

void device_t::device_validity_check(validity_checker &valid) const
{
	// do nothing by default
}


//-------------------------------------------------
//  rom_region - return a pointer to the implicit
//  rom region description for this device
//-------------------------------------------------

const rom_entry *device_t::device_rom_region() const
{
	// none by default
	return nullptr;
}


//-------------------------------------------------
//  machine_config - return a pointer to a machine
//  config constructor describing sub-devices for
//  this device
//-------------------------------------------------

machine_config_constructor device_t::device_mconfig_additions() const
{
	// none by default
	return nullptr;
}


//-------------------------------------------------
//  input_ports - return a pointer to the implicit
//  input ports description for this device
//-------------------------------------------------

ioport_constructor device_t::device_input_ports() const
{
	// none by default
	return nullptr;
}


//-------------------------------------------------
//  device_reset - actually handle resetting of
//  a device; designed to be overriden by the
//  actual device implementation
//-------------------------------------------------

void device_t::device_reset()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_reset_after_children - hook to do
//  reset logic that must happen after the children
//  are reset; designed to be overriden by the
//  actual device implementation
//-------------------------------------------------

void device_t::device_reset_after_children()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_stop - clean up anything that needs to
//  happen before the running_machine goes away
//-------------------------------------------------

void device_t::device_stop()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_pre_save - called prior to saving the
//  state, so that registered variables can be
//  properly normalized
//-------------------------------------------------

void device_t::device_pre_save()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_post_load - called after the loading a
//  saved state, so that registered variables can
//  be expanded as necessary
//-------------------------------------------------

void device_t::device_post_load()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_clock_changed - called when the
//  device clock is altered in any way; designed
//  to be overridden by the actual device
//  implementation
//-------------------------------------------------

void device_t::device_clock_changed()
{
	// do nothing by default
}


//-------------------------------------------------
//  device_debug_setup - called when the debugger
//  is active to allow for device-specific setup
//-------------------------------------------------

void device_t::device_debug_setup()
{
	// do nothing by default
}


//-------------------------------------------------
//  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
{
	// resolve the full path
	std::string fulltag = subtag(tag);

	// we presume the result is a rooted path; also doubled colons mess up our
	// tree walk, so catch them early
	assert(fulltag[0] == ':');
	assert(fulltag.find("::") == -1);

	// 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 part(fulltag, start, (end == -1) ? -1 : end - start);
			curdevice = curdevice->subdevices().find(part);
		}

	// 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;
}


//-------------------------------------------------
//  subtag - create a fully resolved path relative
//  to our device based on the provided tag
//-------------------------------------------------

std::string device_t::subtag(const char *tag) const
{
	std::string result;
	// if the tag begins with a colon, ignore our path and start from the root
	if (*tag == ':')
	{
		tag++;
		result.assign(":");
	}

	// otherwise, start with our path
	else
	{
		result.assign(m_tag);
		if (result != ":")
			result.append(":");
	}

	// iterate over the tag, look for special path characters to resolve
	const char *caret;
	while ((caret = strchr(tag, '^')) != nullptr)
	{
		// copy everything up to there
		result.append(tag, caret - tag);
		tag = caret + 1;

		// strip trailing colons
		int len = result.length();
		while (result[--len] == ':')
			result = result.substr(0, len);

		// remove the last path part, leaving the last colon
		if (result != ":")
		{
			int lastcolon = result.find_last_of(':');
			if (lastcolon != -1)
				result = result.substr(0, lastcolon + 1);
		}
	}

	// copy everything else
	result.append(tag);

	// strip trailing colons up to the root
	int len = result.length();
	while (len > 1 && result[--len] == ':')
		result = result.substr(0, len);
	return result;
}


//-------------------------------------------------
//  register_auto_finder - add a new item to the
//  list of stuff to find after we go live
//-------------------------------------------------

finder_base *device_t::register_auto_finder(finder_base &autodev)
{
	// add to this list
	finder_base *old = m_auto_finder_list;
	m_auto_finder_list = &autodev;
	return old;
}

//**************************************************************************
//  LIVE DEVICE INTERFACES
//**************************************************************************

//-------------------------------------------------
//  device_interface - constructor
//-------------------------------------------------

device_interface::device_interface(device_t &device, const char *type)
	: m_interface_next(nullptr),
		m_device(device),
		m_type(type)
{
	device_interface **tailptr;
	for (tailptr = &device.interfaces().m_head; *tailptr != nullptr; tailptr = &(*tailptr)->m_interface_next) { }
	*tailptr = this;
}


//-------------------------------------------------
//  ~device_interface - destructor
//-------------------------------------------------

device_interface::~device_interface()
{
}


//-------------------------------------------------
//  interface_config_complete - perform any
//  operations now that the configuration is
//  complete
//-------------------------------------------------

void device_interface::interface_config_complete()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_validity_check - default validation
//  for a device after the configuration has been
//  constructed
//-------------------------------------------------

void device_interface::interface_validity_check(validity_checker &valid) const
{
}


//-------------------------------------------------
//  interface_pre_start - called before the
//  device's own start function
//-------------------------------------------------

void device_interface::interface_pre_start()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_post_start - called after the
//  device's own start function
//-------------------------------------------------

void device_interface::interface_post_start()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_pre_reset - called before the
//  device's own reset function
//-------------------------------------------------

void device_interface::interface_pre_reset()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_post_reset - called after the
//  device's own reset function
//-------------------------------------------------

void device_interface::interface_post_reset()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_pre_stop - called before the
//  device's own stop function
//-------------------------------------------------

void device_interface::interface_pre_stop()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_post_stop - called after the
//  device's own stop function
//-------------------------------------------------

void device_interface::interface_post_stop()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_pre_save - called prior to saving the
//  state, so that registered variables can be
//  properly normalized
//-------------------------------------------------

void device_interface::interface_pre_save()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_post_load - called after the loading a
//  saved state, so that registered variables can
//  be expaneded as necessary
//-------------------------------------------------

void device_interface::interface_post_load()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_clock_changed - called when the
//  device clock is altered in any way; designed
//  to be overridden by the actual device
//  implementation
//-------------------------------------------------

void device_interface::interface_clock_changed()
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_debug_setup - called to allow
//  interfaces to set up any debugging for this
//  device
//-------------------------------------------------

void device_interface::interface_debug_setup()
{
	// do nothing by default
}