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

                                

                                                                            
           


                                      







                                                                            

                        
 
                     







                                                              





















                                                                                                                                                                                      
                                                                                                                                   
                     
                                                                                                                                 















































                                                                                                                             
 




                                                                            
                                                     




                                                                                                                                                                                                                                     

                                                      




                                                                                                                                                                                                                                        

                                                                            
                                                            
                                                      
                                                                                 
                                                  
                                                  

                                                                                          


                                                                                                                               










                                                                            
                                     
 
                











                                           
                                 
                                

                                  

                                    

                                   


                                   
                                                  
                              
 

                                                     





                                                      




                                  




                                                                 
                                                                                                                             
                                                                               

                                                                         
 
                                      
                        
         

          


                                                        
 
                            
         
                            
          
 
                          
         
                                     

          



                                                               
 
                                  
                                                                                        






                                                                                   
                                                                                                                                     
                                                                                                                           
                                                       


                           
                                                                                                                                 


                                                                                                                                                                      
                                       
                                                       
                                       
                              
                               
                              

                                 
 


                                                          


                                           
                                            
                                                  
          
 
                        
                                                                                     
                                                                                    
                                                                                  
                                                                           
                                                                                     
                                                                                  
                                                                                           

                        


                                                                                        
                                                                                 
                                                                   
                                                                                


  
                                          
 
                                         


                                   
                                                                             
 


































                                                                                                                                    

                                 
                                       
                                    
                                                                                                                                                     





                                                                                       
                                                                                                                                          
                                       
 

                       
                                                   
 


                                                           

                           

                                                                       
 
        
                   








                                                                                   

                        




                                                                                       

                        
                                                                                   
                                                                                
                                                                                      


  
                                           
 
                                          


                                   
                                                                              
 


































                                                                                                                                       

                                 
                                       
                                    
                                                                                                                                                      





                                                                                       
                                                                                          






                                                           
                                                                                                                                          
                                        




                            


                                                           

                           

                                                                                   
 
        
                   






                                                                                               
                                                                                            
                                                                                           


                                                                                              

                                                                                               
                                                                                             

                        




                                                                                       

                        
                                                                                          
                                                                                
                                                                                       


  
                                          
 
                                              

       
                                                                          

                                                                                                                        


  
                                      
 
                                          

       
                                                                         

                                                                                                                                                                 


  
                                       
 
                                           

       
                                                                            

                                                                                                                                                                     


  
                                       
 
                                           

       
                                                                                

                                                                                                                                                                         


  
                                       
 
                                           

       
                                                                                         

                                                                                                                                                                                  


  
                                           
 
                                                

       
                                                                            

                                                                                                                                     


  
                                       
 
                                            

       
                                                                           


                                                                                                                                                                 


  
                                        
 
                                             

       
                                                                              


                                                                                                                                                                     


  
                                        
 
                                             

       
                                                                                  


                                                                                                                                                                         


  
                                        
 
                                             

       
                                                                                           


                                                                                                                                                                                  


  





























                                                                                            

















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

    devcb.h

    Device callback interface helpers.

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

#pragma once

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

#ifndef MAME_EMU_DEVCB_H
#define MAME_EMU_DEVCB_H

#include <functional>
#include <type_traits>
#include <utility>


namespace emu { namespace detail {

template <typename Delegate> struct devcb_delegate_initialiser
{
	devcb_delegate_initialiser(char const *tag, Delegate &&delegate) : m_base(nullptr), m_delegate(std::move(delegate))
	{
	}
	template <typename T>
	devcb_delegate_initialiser(T &device, std::enable_if_t<is_device_implementation<T>::value, Delegate &&> delegate) : m_base(&device), m_delegate(std::move(delegate))
	{
	}
	template <typename T>
	devcb_delegate_initialiser(T &interface, std::enable_if_t<is_device_interface<T>::value, Delegate &&> delegate) : m_base(&interface.device()), m_delegate(std::move(delegate))
	{
	}
	template <typename DeviceClass, bool Required>
	devcb_delegate_initialiser(device_finder<DeviceClass, Required> const &finder, Delegate &&delegate) : m_base(&finder.finder_target().first), m_delegate(std::move(delegate))
	{
	}

	device_t *m_base;
	Delegate &&m_delegate;
};

inline char const *devcb_delegate_get_tag(char const *tag) { return tag; }
template <typename T>
inline std::enable_if_t<is_device_implementation<T>::value, char const *> devcb_delegate_get_tag(T &device) { return DEVICE_SELF; }
template <typename T>
inline std::enable_if_t<is_device_interface<T>::value, char const *> devcb_delegate_get_tag(T &interface) { return DEVICE_SELF; }
template <typename DeviceClass, bool Required>
inline char const *devcb_delegate_get_tag(device_finder<DeviceClass, Required> const &finder) { return finder.finder_tag(); }

template <typename DescType> struct devcb_tag_desc_creator
{
	static DescType create(char const *tag)
	{
		return DescType{ nullptr, tag };
	}
	static DescType create(device_t &device)
	{
		return DescType{ &device, DEVICE_SELF };
	}
	static DescType create(device_interface &interface)
	{
		return DescType{ &interface.device(), DEVICE_SELF };
	}
	template <typename DeviceClass, bool Required>
	static DescType create(device_finder<DeviceClass, Required> const &finder)
	{
		std::pair<device_t &, char const *> const target(finder.finder_target());
		return DescType{ &target.first, target.second };
	}
};

template <typename DescType> struct devcb_line_desc_creator
{
	static DescType create(char const *tag, int inputnum)
	{
		return DescType{ nullptr, tag, inputnum };
	}
	static DescType create(device_t &device, int inputnum)
	{
		return DescType{ &device, DEVICE_SELF, inputnum };
	}
	static DescType create(device_interface &interface, int inputnum)
	{
		return DescType{ &interface.device(), DEVICE_SELF, inputnum };
	}
	template <typename DeviceClass, bool Required>
	static DescType create(device_finder<DeviceClass, Required> const &finder, int inputnum)
	{
		std::pair<device_t &, char const *> const target(finder.finder_target());
		return DescType{ &target.first, target.second, inputnum };
	}
};

} } // namespace emu::detail


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

// wrappers for read callbacks into any tagged device
#define DEVCB_READLINE(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read_line_delegate>((tag), read_line_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_READ8(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read8_delegate>((tag), read8_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_READ16(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read16_delegate>((tag), read16_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_READ32(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read32_delegate>((tag), read32_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_READ64(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<read64_delegate>((tag), read64_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))

// wrappers for write callbacks into any tagged device
#define DEVCB_WRITELINE(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write_line_delegate>((tag), write_line_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_WRITE8(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write8_delegate>((tag), write8_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_WRITE16(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write16_delegate>((tag), write16_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_WRITE32(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write32_delegate>((tag), write32_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))
#define DEVCB_WRITE64(tag, _class, _func) (emu::detail::devcb_delegate_initialiser<write64_delegate>((tag), write64_delegate(&_class::_func, #_class "::" #_func, emu::detail::devcb_delegate_get_tag(tag), (_class *)nullptr)))

// machine config helpers to add shift, mask, or address space configuration
#define MCFG_DEVCB_RSHIFT(_shift) devcb->set_rshift(_shift);
#define MCFG_DEVCB_MASK(_mask) devcb->set_mask(_mask);
#define MCFG_DEVCB_BIT(_bit) devcb->set_rshift(-(_bit)).set_mask(1ULL << (_bit));
#define MCFG_DEVCB_XOR(_xor) devcb->set_xor(_xor);
#define MCFG_DEVCB_INVERT devcb->set_xor(~u64(0));
#define MCFG_DEVCB_ADDRESS_SPACE(_device, _spacenum) devcb->set_space(_device, _spacenum);

// machine config helpers for chaining callbacks
#define MCFG_DEVCB_CHAIN_INPUT(_desc) devcb = &downcast<devcb_read_base &>(*devcb).chain_alloc().set_callback(DEVCB_##_desc);
#define MCFG_DEVCB_CHAIN_OUTPUT(_desc) devcb = &downcast<devcb_write_base &>(*devcb).chain_alloc().set_callback(DEVCB_##_desc);


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

// base delegate type for a read_line/write_line
typedef device_delegate<int ()> read_line_delegate;
typedef device_delegate<void (int)> write_line_delegate;


// ======================> devcb_base

class devcb_base
{
protected:
	// enumerate the types of callbacks
	enum callback_type
	{
		CALLBACK_NONE,
		CALLBACK_LINE,
		CALLBACK_8,
		CALLBACK_16,
		CALLBACK_32,
		CALLBACK_64,
		CALLBACK_IOPORT,
		CALLBACK_MEMBANK,
		CALLBACK_OUTPUT,
		CALLBACK_LOG,
		CALLBACK_CONSTANT,
		CALLBACK_INPUTLINE,
		CALLBACK_ASSERTLINE,
		CALLBACK_CLEARLINE,
		CALLBACK_HOLDLINE
	};

	// construction/destruction
	devcb_base(device_t &device, u64 defmask);
	virtual ~devcb_base();

	template <callback_type Type> struct tag_desc
	{
		device_t *m_base;
		char const *m_tag;
	};

	template <callback_type Type> struct line_desc
	{
		device_t *m_base;
		char const *m_tag;
		int m_inputnum;
	};

public:
	// getters
	bool isnull() const { return (m_type == CALLBACK_NONE); }

	// additional configuration
	devcb_base &set_space(const char *device, int space = 0) { m_space_tag = device; m_space_num = space; return *this; }
	devcb_base &set_rshift(int rshift) { m_rshift = rshift; return *this; }
	devcb_base &set_mask(u64 mask) { m_mask = mask; return *this; }
	devcb_base &set_xor(u64 xorval) { m_xor = xorval; return *this; }

	// construction helper classes
	struct null_desc
	{
	};

	using ioport_desc = tag_desc<CALLBACK_IOPORT>;
	using membank_desc = tag_desc<CALLBACK_MEMBANK>;
	using output_desc = tag_desc<CALLBACK_OUTPUT>;

	struct constant_desc
	{
		u64 m_value;
	};

	struct logger_desc
	{
		const char *m_string;
	};

	using inputline_desc = line_desc<CALLBACK_INPUTLINE>;
	using assertline_desc = line_desc<CALLBACK_ASSERTLINE>;
	using clearline_desc = line_desc<CALLBACK_CLEARLINE>;
	using holdline_desc = line_desc<CALLBACK_HOLDLINE>;

	// shared callback setters
	devcb_base &set_callback(null_desc null) { reset(CALLBACK_NONE); return *this; }
	template <callback_type Type> devcb_base &set_callback(tag_desc<Type> desc)
	{
		if (desc.m_base) reset(*desc.m_base, Type);
		else reset(Type);
		m_target_tag = desc.m_tag;
		return *this;
	}
	devcb_base &set_callback(constant_desc constant) { reset(CALLBACK_CONSTANT); m_target_int = constant.m_value; return *this; }
	devcb_base &set_callback(logger_desc logger) { reset(CALLBACK_LOG); m_target_tag = logger.m_string; return *this; }
	void reset() { reset(m_owner, CALLBACK_NONE); }

protected:
	// internal helpers
	inline u64 shift_mask(u64 value) const { return ((m_rshift < 0) ? (value << -m_rshift) : (value >> m_rshift)) & m_mask; }
	inline u64 shift_mask_xor(u64 value) const { return (((m_rshift < 0) ? (value << -m_rshift) : (value >> m_rshift)) ^ m_xor) & m_mask; }
	inline u64 unshift_mask(u64 value) const { return (m_rshift < 0) ? ((value & m_mask) >> -m_rshift) : ((value & m_mask) << m_rshift); }
	inline u64 unshift_mask_xor(u64 value) const { return (m_rshift < 0) ? (((value ^ m_xor) & m_mask) >> -m_rshift) : (((value ^ m_xor) & m_mask) << m_rshift); }
	void reset(callback_type type);
	void reset(device_t &base, callback_type type);
	virtual void devcb_reset() = 0;
	void resolve_ioport();
	void resolve_membank();
	void resolve_output();
	void resolve_inputline();
	void resolve_space();

	// the callback target is going to be one of these
	union callback_target
	{
		void *              ptr;
		device_t *          device;
		ioport_port *       ioport;
		memory_bank *       membank;
		output_manager::output_item *item;
	};

	// configuration
	device_t &          m_owner;                // reference to our owning device
	std::reference_wrapper<device_t> m_base;    // device to resolve relative to
	callback_type       m_type;                 // type of callback registered
	const char *        m_target_tag;           // tag of target object
	u64                 m_target_int;           // integer value of target object
	const char *        m_space_tag;            // tag of address space device
	int                 m_space_num;            // address space number of space device

	// derived state
	address_space *     m_space;                // target address space
	callback_target     m_target;               // resolved pointer to target object
	int                 m_rshift;               // right shift to apply to data read
	u64                 m_mask;                 // mask to apply to data read
	const u64           m_defmask;              // default mask
	u64                 m_xor;                  // XOR to apply to data read
};


// ======================> devcb_read_base

class devcb_read_base : public devcb_base
{
protected:
	// construction/destruction
	devcb_read_base(device_t &device, u64 defmask, bool chained = false);

	template <typename Delegate, typename Dummy> struct set_helper
	{
		static constexpr bool valid = false;
	};
	template <typename Dummy> struct set_helper<read_line_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_LINE;
		static void apply(devcb_read_base &devcb, read_line_delegate &&delegate) { devcb.m_readline = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<read8_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_8;
		static void apply(devcb_read_base &devcb, read8_delegate &&delegate) { devcb.m_read8 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<read16_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_16;
		static void apply(devcb_read_base &devcb, read16_delegate &&delegate) { devcb.m_read16 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<read32_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_32;
		static void apply(devcb_read_base &devcb, read32_delegate &&delegate) { devcb.m_read32 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<read64_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_64;
		static void apply(devcb_read_base &devcb, read64_delegate &&delegate) { devcb.m_read64 = std::move(delegate); }
	};

public:
	// callback configuration
	using devcb_base::set_callback;
	template <typename Delegate>
	std::enable_if_t<set_helper<Delegate, void>::valid, devcb_read_base &> set_callback(emu::detail::devcb_delegate_initialiser<Delegate> &&desc)
	{
		if (desc.m_base) reset(*desc.m_base, set_helper<Delegate, void>::type);
		else reset(set_helper<Delegate, void>::type);
		set_helper<Delegate, void>::apply(*this, std::move(desc.m_delegate));
		return *this;
	}
	template <typename... Params> auto &chain(Params &&... args) { return chain_alloc().set_callback(std::forward<Params>(args)...); }
	devcb_read_base &chain_alloc();

	// resolution
	void resolve();
	void resolve_safe(u64 none_constant_value);

	// validity checking
	void validity_check(validity_checker &valid) const;

protected:
	// internal helpers
	virtual void devcb_reset() override;
	inline u64 read(address_space &space, offs_t offset, u64 mask);

private:
	// adapters
	u64 read_unresolved_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read_line_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read8_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read16_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read32_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read64_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read_ioport_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read_logged_adapter(address_space &space, offs_t offset, u64 mask);
	u64 read_constant_adapter(address_space &space, offs_t offset, u64 mask);

	// configuration
	read_line_delegate  m_readline;             // copy of registered line reader
	read8_delegate      m_read8;                // copy of registered 8-bit reader
	read16_delegate     m_read16;               // copy of registered 16-bit reader
	read32_delegate     m_read32;               // copy of registered 32-bit reader
	read64_delegate     m_read64;               // copy of registered 64-bit reader

	// derived state
	typedef u64 (devcb_read_base::*adapter_func)(address_space &, offs_t, u64);
	adapter_func        m_adapter;              // actual callback to invoke
	std::unique_ptr<devcb_read_base> m_chain;   // next callback for chained input
};


// ======================> devcb_write_base

class devcb_write_base : public devcb_base
{
protected:
	// construction/destruction
	devcb_write_base(device_t &device, u64 defmask, bool chained = false);

	template <typename Delegate, typename Dummy> struct set_helper
	{
		static constexpr bool valid = false;
	};
	template <typename Dummy> struct set_helper<write_line_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_LINE;
		static void apply(devcb_write_base &devcb, write_line_delegate &&delegate) { devcb.m_writeline = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<write8_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_8;
		static void apply(devcb_write_base &devcb, write8_delegate &&delegate) { devcb.m_write8 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<write16_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_16;
		static void apply(devcb_write_base &devcb, write16_delegate &&delegate) { devcb.m_write16 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<write32_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_32;
		static void apply(devcb_write_base &devcb, write32_delegate &&delegate) { devcb.m_write32 = std::move(delegate); }
	};
	template <typename Dummy> struct set_helper<write64_delegate, Dummy>
	{
		static constexpr bool valid = true;
		static constexpr callback_type type = CALLBACK_64;
		static void apply(devcb_write_base &devcb, write64_delegate &&delegate) { devcb.m_write64 = std::move(delegate); }
	};

public:
	// callback configuration
	using devcb_base::set_callback;
	template <typename Delegate>
	std::enable_if_t<set_helper<Delegate, void>::valid, devcb_write_base &> set_callback(emu::detail::devcb_delegate_initialiser<Delegate> &&desc)
	{
		if (desc.m_base) reset(*desc.m_base, set_helper<Delegate, void>::type);
		else reset(set_helper<Delegate, void>::type);
		set_helper<Delegate, void>::apply(*this, std::move(desc.m_delegate));
		return *this;
	}
	template <callback_type Type> devcb_write_base &set_callback(line_desc<Type> desc)
	{
		if (desc.m_base) reset(*desc.m_base, Type);
		else reset(Type);
		m_target_tag = desc.m_tag;
		m_target_int = desc.m_inputnum;
		return *this;
	}
	template <typename... Params> auto &chain(Params &&... args) { return chain_alloc().set_callback(std::forward<Params>(args)...); }
	devcb_write_base &chain_alloc();

	// resolution
	void resolve();
	void resolve_safe();

	// validity checking
	void validity_check(validity_checker &valid) const;

protected:
	// internal helpers
	virtual void devcb_reset() override;
	inline void write(address_space &space, offs_t offset, u64 data, u64 mask);

private:
	// adapters
	void write_unresolved_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_line_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write8_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write16_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write32_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write64_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_ioport_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_membank_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_output_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_logged_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_noop_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_inputline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_assertline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_clearline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);
	void write_holdline_adapter(address_space &space, offs_t offset, u64 data, u64 mask);

	// configuration
	write_line_delegate m_writeline;            // copy of registered line writer
	write8_delegate     m_write8;               // copy of registered 8-bit writer
	write16_delegate    m_write16;              // copy of registered 16-bit writer
	write32_delegate    m_write32;              // copy of registered 32-bit writer
	write64_delegate    m_write64;              // copy of registered 64-bit writer

	// derived state
	typedef void (devcb_write_base::*adapter_func)(address_space &, offs_t, u64, u64);
	adapter_func        m_adapter;              // actual callback to invoke
	std::unique_ptr<devcb_write_base> m_chain;  // next callback for chained output
};


// ======================> devcb_read_line

class devcb_read_line : public devcb_read_base
{
public:
	devcb_read_line(device_t &device) : devcb_read_base(device, 1) { }
	int operator()() { return read(*m_space, 0, 0xffU) & 1; }
	int operator()(address_space &space) { return read((m_space_tag != nullptr) ? *m_space : space, 0, 0xffU) & 1; }
};


// ======================> devcb_read8

class devcb_read8 : public devcb_read_base
{
public:
	devcb_read8(device_t &device) : devcb_read_base(device, 0xff) { }
	u8 operator()(offs_t offset = 0, u8 mask = 0xff) { return read(*m_space, offset, mask) & mask; }
	u8 operator()(address_space &space, offs_t offset = 0, u8 mask = 0xff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
};


// ======================> devcb_read16

class devcb_read16 : public devcb_read_base
{
public:
	devcb_read16(device_t &device) : devcb_read_base(device, 0xffff) { }
	u16 operator()(offs_t offset = 0, u16 mask = 0xffff) { return read(*m_space, offset, mask) & mask; }
	u16 operator()(address_space &space, offs_t offset = 0, u16 mask = 0xffff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
};


// ======================> devcb_read32

class devcb_read32 : public devcb_read_base
{
public:
	devcb_read32(device_t &device) : devcb_read_base(device, 0xffffffff) { }
	u32 operator()(offs_t offset = 0, u32 mask = 0xffffffff) { return read(*m_space, offset, mask) & mask; }
	u32 operator()(address_space &space, offs_t offset = 0, u32 mask = 0xffffffff) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
};


// ======================> devcb_read64

class devcb_read64 : public devcb_read_base
{
public:
	devcb_read64(device_t &device) : devcb_read_base(device, 0xffffffffffffffffU) { }
	u64 operator()(offs_t offset = 0, u64 mask = 0xffffffffffffffffU) { return read(*m_space, offset, mask) & mask; }
	u64 operator()(address_space &space, offs_t offset = 0, u64 mask = 0xffffffffffffffffU) { return read((m_space_tag != nullptr) ? *m_space : space, offset, mask) & mask; }
};


// ======================> devcb_write_line

class devcb_write_line : public devcb_write_base
{
public:
	devcb_write_line(device_t &device) : devcb_write_base(device, 1) { }
	void operator()(int state) { write(*m_space, 0, state & 1, 0xffU); }
	void operator()(address_space &space, int state) { write((m_space_tag != nullptr) ? *m_space : space, 0, state & 1, 0xffU); }
};


// ======================> devcb_write8

class devcb_write8 : public devcb_write_base
{
public:
	devcb_write8(device_t &device) : devcb_write_base(device, 0xff) { }
	void operator()(u8 data, u8 mask = 0xff) { write(*m_space, 0, data, mask); }
	void operator()(offs_t offset, u8 data, u8 mask = 0xff) { write(*m_space, offset, data, mask); }
	void operator()(address_space &space, offs_t offset, u8 data, u8 mask = 0xff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
};


// ======================> devcb_write16

class devcb_write16 : public devcb_write_base
{
public:
	devcb_write16(device_t &device) : devcb_write_base(device, 0xffff) { }
	void operator()(u16 data, u16 mask = 0xffff) { write(*m_space, 0, data, mask); }
	void operator()(offs_t offset, u16 data, u16 mask = 0xffff) { write(*m_space, offset, data, mask); }
	void operator()(address_space &space, offs_t offset, u16 data, u16 mask = 0xffff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
};


// ======================> devcb_write32

class devcb_write32 : public devcb_write_base
{
public:
	devcb_write32(device_t &device) : devcb_write_base(device, 0xffffffff) { }
	void operator()(u32 data, u32 mask = 0xffffffff) { write(*m_space, 0, data, mask); }
	void operator()(offs_t offset, u32 data, u32 mask = 0xffffffff) { write(*m_space, offset, data, mask); }
	void operator()(address_space &space, offs_t offset, u32 data, u32 mask = 0xffffffff) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
};


// ======================> devcb_write64

class devcb_write64 : public devcb_write_base
{
public:
	devcb_write64(device_t &device) : devcb_write_base(device, 0xffffffffffffffffU) { }
	void operator()(u64 data, u64 mask = 0xffffffffffffffffU) { write(*m_space, 0, data, mask); }
	void operator()(offs_t offset, u64 data, u64 mask = 0xffffffffffffffffU) { write(*m_space, offset, data, mask); }
	void operator()(address_space &space, offs_t offset, u64 data, u64 mask = 0xffffffffffffffffU) { write((m_space_tag != nullptr) ? *m_space : space, offset, data, mask); }
};



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

//-------------------------------------------------
//  read - generic read callback dispatch
//-------------------------------------------------

inline u64 devcb_read_base::read(address_space &space, offs_t offset, u64 mask)
{
	u64 result = (this->*m_adapter)(space, offset, mask);
	if (m_chain != nullptr)
		result |= m_chain->read(space, offset, mask);
	return result;
}


//-------------------------------------------------
//  write - generic write callback dispatch
//-------------------------------------------------

inline void devcb_write_base::write(address_space &space, offs_t offset, u64 data, u64 mask)
{
	(this->*m_adapter)(space, offset, data, mask);
	if (m_chain != nullptr)
		m_chain->write(space, offset, data, mask);
}


//-------------------------------------------------
//  wrappers for ioports, constants, and loggers
//-------------------------------------------------

#define DEVCB_NOOP devcb_base::null_desc{ }
template <typename... Params> inline devcb_base::ioport_desc DEVCB_IOPORT(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::ioport_desc>::create(std::forward<Params>(args)...); }
template <typename... Params> inline devcb_base::membank_desc DEVCB_MEMBANK(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::membank_desc>::create(std::forward<Params>(args)...); }
template <typename... Params> inline devcb_base::output_desc DEVCB_OUTPUT(Params &&... args) { return emu::detail::devcb_tag_desc_creator<devcb_base::output_desc>::create(std::forward<Params>(args)...); }
inline devcb_base::constant_desc DEVCB_CONSTANT(u64 value) { return devcb_base::constant_desc{ value }; }
inline devcb_base::logger_desc DEVCB_LOGGER(char const *string) { return devcb_base::logger_desc{ string }; }
template <typename... Params> inline devcb_base::inputline_desc DEVCB_INPUTLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::inputline_desc>::create(std::forward<Params>(args)...); }
template <typename... Params> inline devcb_base::assertline_desc DEVCB_ASSERTLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::assertline_desc>::create(std::forward<Params>(args)...); }
template <typename... Params> inline devcb_base::clearline_desc DEVCB_CLEARLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::clearline_desc>::create(std::forward<Params>(args)...); }
template <typename... Params> inline devcb_base::holdline_desc DEVCB_HOLDLINE(Params &&... args) { return emu::detail::devcb_line_desc_creator<devcb_base::holdline_desc>::create(std::forward<Params>(args)...); }
#define DEVCB_VCC DEVCB_CONSTANT(1)
#define DEVCB_GND DEVCB_CONSTANT(0)

#endif // MAME_EMU_DEVCB_H