summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/device.h
blob: fd6a313a1171153165fab034464d599d64a19949 (plain) (tree)
1
2
3
4
5
6
7
8

                                

                                                                            
            


                               



                                                                            



                                                              

                    
 

 


                                                                            
 
                                                             
                                                                               
 
 
 


                                                                            
 
                    
                                     
                                                                
                                   
                                                    
                                             
                                                                                         
 



                                                                            

 
 


                                                                            
 
                     
                    
                   

                       
                               
                              
                             
                       
                 
                     
                
                            
                  
 
 
                    
                                                             

 
                                                          



                                                                                                                
                            

                                                                                                       
                                                                      
 
 
 


                               
                                   
 
                               
                                          
 
                                  
 





                                              

                                     
                                 
 

                                   
                                                                                                                                                                               
       
                            
 

                                                                                          

                                                         
                                                   
                                                   
                                                             
                                                               
                                                       


                                                                      
                                                                     
                                                                          


                                                                                                          
                                                                               

                                                             
                                                                       
 
                            

                                                                                                                                                          
 
                                                         
                                                                                                    
                                                                                                          
                                                                                                  
                                                                                                        
                                                                                                
                                                                                                      
                                                                                                   
                                                                                               
                                                                                           
 
                               
                                                                              
                                                              
                                                                                                                                                            
                                                        
                                                      
                                                    
                                                   
                                                   
                                                       

                                                                                                                                                       
                                                          

                                
                                                                     

                                                                                                                                        
                                                                                                                                                                   

                        

                                                             
                                                           
                                                  
                     
 







                                                                  
 




                                                                                                                                
 
                                  
                                    
                                                                                                                                                                           
                                    
                                                                                                                                                                                                      
 

                                                       

                             
 

                                                                    
                                                     
 

                                
                                                   
                     
                    



                                    
                                                                



                                                           

                                                                            
                                                              
                                              
                                                                                    


                                                  
                                                             

                                                  

                                            
                                                                                              
 
                                                         
 
                                 



                                                                                              
                                                                                  

                               



                                                                                                            

                            



                                                                                                  
 
                        





                                                                                              
                                           


                                                                                                   

                                                                                                

                                                                                          

                                                                                         







                                                                                                    






                                                                                                   
  
 
 
                                           
 
                                                                                    
                      

                                          
 

                                   
                                           
                                    
 


                                               
                                                           

                                                   
 

                                                                             
                                                                                                               

                                       



                                                                          
                                                 
                                                                             



                                            

                                           



                                               
 
          
                         

                                                 
  
 
 
                                          
 






                                                                    


                                                
 

                                                       
 


                                      
                                   

                                 
 






                                                                                    
 









                                                             
 







                                                                   
                                             


                                               
 


                                                  
 


                                               
                               



                                                                           
 




















                                                                                    



                                   







                                                                       
 







                                                                                                
















                                                                                                       
 


                                               
                               



                                                                               
 




















                                                                                        
                                       








                                                                              
 



                                                                     
                                           


                                                              
 
















                                                                                                       
 


                                               
                               



                                                                                  
 




















                                                                                           

                                       


  
 


                                                                            
 
                                                   

                                               

                                                   
                                                           
 










                                                             

 
 
                                                   
                                                











                                                               
 

                                                        
 


                                                       
 

                                                          

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

    device.h

    Device interface functions.

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

#pragma once

#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif

#ifndef __DEVICE_H__
#define __DEVICE_H__



//**************************************************************************
//  MACROS
//**************************************************************************

// macro for specifying a clock derived from an owning device
#define DERIVED_CLOCK(num, den)     (0xff000000 | ((num) << 12) | ((den) << 0))



//**************************************************************************
//  DEVICE CONFIGURATION MACROS
//**************************************************************************

// configure devices
#define MCFG_DEVICE_CONFIG(_config) \
	device_t::static_set_static_config(*device, &(_config));
#define MCFG_DEVICE_CLOCK(_clock) \
	device_t::static_set_clock(*device, _clock);
#define MCFG_DEVICE_INPUT_DEFAULTS(_config) \
	device_t::static_set_input_default(*device, DEVICE_INPUT_DEFAULTS_NAME(_config));

#define DECLARE_READ_LINE_MEMBER(name)      int  name()
#define READ_LINE_MEMBER(name)              int  name()
#define DECLARE_WRITE_LINE_MEMBER(name)     void name(ATTR_UNUSED int state)
#define WRITE_LINE_MEMBER(name)             void name(ATTR_UNUSED int state)



//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// forward references
class memory_region;
class device_debug;
class device_t;
class device_interface;
class device_execute_interface;
class device_memory_interface;
class device_state_interface;
class validity_checker;
struct rom_entry;
class machine_config;
class emu_timer;
struct input_device_default;
class finder_base;


// exception classes
class device_missing_dependencies : public emu_exception { };


// a device_type is simply a pointer to its alloc function
typedef device_t *(*device_type)(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);


// this template function creates a stub which constructs a device
template<class _DeviceClass>
device_t *device_creator(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
{
	return global_alloc(_DeviceClass(mconfig, tag, owner, clock));
}


// timer IDs for devices
typedef UINT32 device_timer_id;

// ======================> device_t

// device_t represents a device
class device_t : public delegate_late_bind
{
	DISABLE_COPYING(device_t);

	friend class device_interface;
	friend class device_memory_interface;
	friend class device_state_interface;
	friend class device_execute_interface;
	friend class simple_list<device_t>;
	friend class device_list;
	friend class machine_config;
	friend class running_machine;
	friend class finder_base;

protected:
	// construction/destruction
	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);
public:
	virtual ~device_t();

	// getters
	running_machine &machine() const { assert(m_machine != NULL); return *m_machine; }
	const char *tag() const { return m_tag; }
	const char *basetag() const { return m_basetag; }
	device_type type() const { return m_type; }
	const char *name() const { return m_name; }
	const char *shortname() const { return m_shortname; }
	const char *searchpath() const { return m_searchpath; }
	const char *source() const { return m_source; }
	device_t *owner() const { return m_owner; }
	device_t *next() const { return m_next; }
	UINT32 configured_clock() const { return m_configured_clock; }
	const void *static_config() const { return m_static_config; }
	const machine_config &mconfig() const { return m_machine_config; }
	const input_device_default *input_ports_defaults() const { return m_input_defaults; }
	const rom_entry *rom_region() const { return device_rom_region(); }
	machine_config_constructor machine_config_additions() const { return device_mconfig_additions(); }
	ioport_constructor input_ports() const { return device_input_ports(); }
	UINT8 default_bios() const { return m_default_bios; }
	UINT8 system_bios() const { return m_system_bios; }
	astring default_bios_tag() const { return m_default_bios_tag; }

	// interface helpers
	template<class _DeviceClass> bool interface(_DeviceClass *&intf) { intf = dynamic_cast<_DeviceClass *>(this); return (intf != NULL); }
	template<class _DeviceClass> bool interface(_DeviceClass *&intf) const { intf = dynamic_cast<const _DeviceClass *>(this); return (intf != NULL); }

	// specialized helpers for common core interfaces
	bool interface(device_execute_interface *&intf) { intf = m_execute; return (intf != NULL); }
	bool interface(device_execute_interface *&intf) const { intf = m_execute; return (intf != NULL); }
	bool interface(device_memory_interface *&intf) { intf = m_memory; return (intf != NULL); }
	bool interface(device_memory_interface *&intf) const { intf = m_memory; return (intf != NULL); }
	bool interface(device_state_interface *&intf) { intf = m_state; return (intf != NULL); }
	bool interface(device_state_interface *&intf) const { intf = m_state; return (intf != NULL); }
	device_execute_interface &execute() const { assert(m_execute != NULL); return *m_execute; }
	device_memory_interface &memory() const { assert(m_memory != NULL); return *m_memory; }
	device_state_interface &state() const { assert(m_state != NULL); return *m_state; }

	// owned object helpers
	device_t *first_subdevice() const { return m_subdevice_list.first(); }
	astring &subtag(astring &dest, const char *tag) const;
	astring &siblingtag(astring &dest, const char *tag) const { return (this != NULL && m_owner != NULL) ? m_owner->subtag(dest, tag) : dest.cpy(tag); }
	memory_region *memregion(const char *tag) const;
	memory_share *memshare(const char *tag) const;
	memory_bank *membank(const char *tag) const;
	ioport_port *ioport(const char *tag) const;
	device_t *subdevice(const char *tag) const;
	device_t *siblingdevice(const char *tag) const;
	template<class _DeviceClass> inline _DeviceClass *subdevice(const char *tag) const { return downcast<_DeviceClass *>(subdevice(tag)); }
	template<class _DeviceClass> inline _DeviceClass *siblingdevice(const char *tag) const { return downcast<_DeviceClass *>(siblingdevice(tag)); }
	memory_region *region() const { return m_region; }

	// configuration helpers
	static void static_set_clock(device_t &device, UINT32 clock);
	static void static_set_static_config(device_t &device, const void *config) { device.m_static_config = config; }
	static void static_set_input_default(device_t &device, const input_device_default *config) { device.m_input_defaults = config; }
	static void static_set_default_bios_tag(device_t &device, const char *tag) { astring default_bios_tag(tag); device.m_default_bios_tag = default_bios_tag; }

	// state helpers
	void config_complete();
	bool configured() const { return m_config_complete; }
	void validity_check(validity_checker &valid) const;
	bool started() const { return m_started; }
	void reset();

	// clock/timing accessors
	UINT32 clock() const { return m_clock; }
	UINT32 unscaled_clock() const { return m_unscaled_clock; }
	void set_unscaled_clock(UINT32 clock);
	double clock_scale() const { return m_clock_scale; }
	void set_clock_scale(double clockscale);
	attotime clocks_to_attotime(UINT64 clocks) const;
	UINT64 attotime_to_clocks(attotime duration) const;

	// timer interfaces
	emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = NULL);
	void timer_set(attotime duration, device_timer_id id = 0, int param = 0, void *ptr = NULL);
	void synchronize(device_timer_id id = 0, int param = 0, void *ptr = NULL) { timer_set(attotime::zero, id, param, ptr); }
	void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); }

	// state saving interfaces
	template<typename _ItemType>
	void ATTR_COLD save_item(_ItemType &value, const char *valname, int index = 0) { assert(m_save != NULL); m_save->save_item(name(), tag(), index, value, valname); }
	template<typename _ItemType>
	void ATTR_COLD save_pointer(_ItemType *value, const char *valname, UINT32 count, int index = 0) { assert(m_save != NULL); m_save->save_pointer(name(), tag(), index, value, valname, count); }

	// debugging
	device_debug *debug() const { return m_debug; }
	offs_t safe_pc();
	offs_t safe_pcbase();

	void set_default_bios(UINT8 bios) { m_default_bios = bios; }
	void set_system_bios(UINT8 bios) { m_system_bios = bios; }
	bool findit(bool isvalidation = false) const;

protected:
	// miscellaneous helpers
	void set_machine(running_machine &machine);
	void start();
	void stop();
	void debug_setup();
	void pre_save();
	void post_load();
	void notify_clock_changed();
	finder_base *register_auto_finder(finder_base &autodev);

	//------------------- begin derived class overrides

	// device-level overrides
	virtual const rom_entry *device_rom_region() const;
	virtual machine_config_constructor device_mconfig_additions() const;
	virtual ioport_constructor device_input_ports() const;
	virtual void device_config_complete();
	virtual void device_validity_check(validity_checker &valid) const ATTR_COLD;
	virtual void device_start() ATTR_COLD = 0;
	virtual void device_stop() ATTR_COLD;
	virtual void device_reset() ATTR_COLD;
	virtual void device_reset_after_children() ATTR_COLD;
	virtual void device_pre_save() ATTR_COLD;
	virtual void device_post_load() ATTR_COLD;
	virtual void device_clock_changed();
	virtual void device_debug_setup();
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);

	//------------------- end derived class overrides

	// core device properties
	const device_type       m_type;                 // device type
	astring                 m_name;                 // name of the device
	astring                 m_shortname;            // short name of the device
	astring                 m_searchpath;           // search path, used for media loading
	astring                 m_source;               // device source file name

	// device relationships
	device_t *              m_owner;                // device that owns us
	device_t *              m_next;                 // next device by the same owner (of any type/class)
	simple_list<device_t>   m_subdevice_list;       // list of sub-devices we own
	mutable tagmap_t<device_t *> m_device_map;      // map of device names looked up and found

	// device interfaces
	device_interface *      m_interface_list;       // head of interface list
	device_execute_interface *m_execute;            // pre-cached pointer to execute interface
	device_memory_interface *m_memory;              // pre-cached pointer to memory interface
	device_state_interface *m_state;                // pre-cached pointer to state interface

	// device clocks
	UINT32                  m_configured_clock;     // originally configured device clock
	UINT32                  m_unscaled_clock;       // current unscaled device clock
	UINT32                  m_clock;                // current device clock, after scaling
	double                  m_clock_scale;          // clock scale factor
	attoseconds_t           m_attoseconds_per_clock;// period in attoseconds

	auto_pointer<device_debug> m_debug;
	memory_region *         m_region;               // our device-local region
	const machine_config &  m_machine_config;       // reference to the machine's configuration
	const void *            m_static_config;        // static device configuration
	const input_device_default *m_input_defaults;   // devices input ports default overrides

	UINT8                   m_system_bios;          // the system BIOS we wish to load
	UINT8                   m_default_bios;         // the default system BIOS
	astring                 m_default_bios_tag;     // tag of the default system BIOS

private:
	// private helpers
	device_t *add_subdevice(device_type type, const char *tag, UINT32 clock);
	device_t *replace_subdevice(device_t &old, device_type type, const char *tag, UINT32 clock);
	void remove_subdevice(device_t &device);
	device_t *subdevice_slow(const char *tag) const;

	// private state; accessor use required
	running_machine *       m_machine;
	save_manager *          m_save;
	astring                 m_tag;                  // full tag for this instance
	astring                 m_basetag;              // base part of the tag
	bool                    m_config_complete;      // have we completed our configuration?
	bool                    m_started;              // true if the start function has succeeded
	finder_base *           m_auto_finder_list;     // list of objects to auto-find
};


// ======================> device_interface

// device_interface represents runtime information for a particular device interface
class device_interface
{
	DISABLE_COPYING(device_interface);

protected:
	// construction/destruction
	device_interface(device_t &device);
	virtual ~device_interface();

public:
	// casting helpers
	device_t &device() { return m_device; }
	const device_t &device() const { return m_device; }
	operator device_t &() { return m_device; }
	operator device_t *() { return &m_device; }

	// iteration helpers
	device_interface *interface_next() const { return m_interface_next; }
	template<class _InterfaceClass> bool next(_InterfaceClass *&intf) const { return m_device.next(intf); }

	// optional operation overrides
	//
	// WARNING: interface_pre_start must be callable multiple times in
	// case another interface throws a missing dependency.  In
	// particular, state saving registrations should be done in post.
	virtual void interface_config_complete();
	virtual void interface_validity_check(validity_checker &valid) const;
	virtual void interface_pre_start();
	virtual void interface_post_start();
	virtual void interface_pre_reset();
	virtual void interface_post_reset();
	virtual void interface_pre_stop();
	virtual void interface_post_stop();
	virtual void interface_pre_save();
	virtual void interface_post_load();
	virtual void interface_clock_changed();
	virtual void interface_debug_setup();

protected:
	// internal state
	device_interface *      m_interface_next;
	device_t &              m_device;
};


// ======================> device_iterator

// helper class to iterate over the hierarchy of devices depth-first
class device_iterator
{
public:
	// construction
	device_iterator(device_t &root, int maxdepth = 255)
		: m_root(&root),
			m_current(NULL),
			m_curdepth(0),
			m_maxdepth(maxdepth) { }

	// getters
	device_t *current() const { return m_current; }

	// reset and return first item
	device_t *first()
	{
		m_current = m_root;
		return m_current;
	}

	// advance depth-first
	device_t *next()
	{
		// remember our starting position, and end immediately if we're NULL
		device_t *start = m_current;
		if (start == NULL)
			return NULL;

		// search down first
		if (m_curdepth < m_maxdepth)
		{
			m_current = start->first_subdevice();
			if (m_current != NULL)
			{
				m_curdepth++;
				return m_current;
			}
		}

		// search next for neighbors up the ownership chain
		while (m_curdepth > 0)
		{
			// found a neighbor? great!
			m_current = start->next();
			if (m_current != NULL)
				return m_current;

			// no? try our parent
			start = start->owner();
			m_curdepth--;
		}

		// returned to the top; we're done
		return m_current = NULL;
	}

	// return the number of items available
	int count()
	{
		int result = 0;
		for (device_t *item = first(); item != NULL; item = next())
			result++;
		return result;
	}

	// return the index of a given item in the virtual list
	int indexof(device_t &device)
	{
		int index = 0;
		for (device_t *item = first(); item != NULL; item = next(), index++)
			if (item == &device)
				return index;
		return -1;
	}

	// return the indexed item in the list
	device_t *byindex(int index)
	{
		for (device_t *item = first(); item != NULL; item = next(), index--)
			if (index == 0)
				return item;
		return NULL;
	}

private:
	// internal state
	device_t *      m_root;
	device_t *      m_current;
	int             m_curdepth;
	int             m_maxdepth;
};


// ======================> device_type_iterator

// helper class to find devices of a given type in the device hierarchy
template<device_type _DeviceType, class _DeviceClass = device_t>
class device_type_iterator
{
public:
	// construction
	device_type_iterator(device_t &root, int maxdepth = 255)
		: m_iterator(root, maxdepth) { }

	// getters
	_DeviceClass *current() const { return downcast<_DeviceClass *>(m_iterator.current()); }

	// reset and return first item
	_DeviceClass *first()
	{
		for (device_t *device = m_iterator.first(); device != NULL; device = m_iterator.next())
			if (device->type() == _DeviceType)
				return downcast<_DeviceClass *>(device);
		return NULL;
	}

	// advance depth-first
	_DeviceClass *next()
	{
		for (device_t *device = m_iterator.next(); device != NULL; device = m_iterator.next())
			if (device->type() == _DeviceType)
				return downcast<_DeviceClass *>(device);
		return NULL;
	}

	// return the number of items available
	int count()
	{
		int result = 0;
		for (_DeviceClass *item = first(); item != NULL; item = next())
			result++;
		return result;
	}

	// return the index of a given item in the virtual list
	int indexof(_DeviceClass &device)
	{
		int index = 0;
		for (_DeviceClass *item = first(); item != NULL; item = next(), index++)
			if (item == &device)
				return index;
		return -1;
	}

	// return the indexed item in the list
	_DeviceClass *byindex(int index)
	{
		for (_DeviceClass *item = first(); item != NULL; item = next(), index--)
			if (index == 0)
				return item;
		return NULL;
	}

private:
	// internal state
	device_iterator     m_iterator;
};


// ======================> device_interface_iterator

// helper class to find devices with a given interface in the device hierarchy
// also works for findnig devices derived from a given subclass
template<class _InterfaceClass>
class device_interface_iterator
{
public:
	// construction
	device_interface_iterator(device_t &root, int maxdepth = 255)
		: m_iterator(root, maxdepth),
			m_current(NULL) { }

	// getters
	_InterfaceClass *current() const { return m_current; }

	// reset and return first item
	_InterfaceClass *first()
	{
		for (device_t *device = m_iterator.first(); device != NULL; device = m_iterator.next())
			if (device->interface(m_current))
				return m_current;
		return NULL;
	}

	// advance depth-first
	_InterfaceClass *next()
	{
		for (device_t *device = m_iterator.next(); device != NULL; device = m_iterator.next())
			if (device->interface(m_current))
				return m_current;
		return NULL;
	}

	// return the number of items available
	int count()
	{
		int result = 0;
		for (_InterfaceClass *item = first(); item != NULL; item = next())
			result++;
		return result;
	}

	// return the index of a given item in the virtual list
	int indexof(_InterfaceClass &intrf)
	{
		int index = 0;
		for (_InterfaceClass *item = first(); item != NULL; item = next(), index++)
			if (item == &intrf)
				return index;
		return -1;
	}

	// return the indexed item in the list
	_InterfaceClass *byindex(int index)
	{
		for (_InterfaceClass *item = first(); item != NULL; item = next(), index--)
			if (index == 0)
				return item;
		return NULL;
	}

private:
	// internal state
	device_iterator     m_iterator;
	_InterfaceClass *   m_current;
};



//**************************************************************************
//  INLINE FUNCTIONS
//**************************************************************************

//-------------------------------------------------
//  subdevice - given a tag, find the device by
//  name relative to this device
//-------------------------------------------------

inline device_t *device_t::subdevice(const char *tag) const
{
	// safety first
	if (this == NULL)
		return NULL;

	// empty string or NULL means this device
	if (tag == NULL || *tag == 0)
		return const_cast<device_t *>(this);

	// do a quick lookup and return that if possible
	device_t *quick = m_device_map.find(tag);
	return (quick != NULL) ? quick : subdevice_slow(tag);
}


//-------------------------------------------------
//  siblingdevice - given a tag, find the device
//  by name relative to this device's parent
//-------------------------------------------------

inline device_t *device_t::siblingdevice(const char *tag) const
{
	// safety first
	if (this == NULL)
		return NULL;

	// empty string or NULL means this device
	if (tag == NULL || *tag == 0)
		return const_cast<device_t *>(this);

	// leading caret implies the owner, just skip it
	if (tag[0] == '^') tag++;

	// query relative to the parent, if we have one
	if (m_owner != NULL)
		return m_owner->subdevice(tag);

	// otherwise, it's NULL unless the tag is absolute
	return (tag[0] == ':') ? subdevice(tag) : NULL;
}

#endif  /* __DEVICE_H__ */