summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/addrmap.cpp
blob: 3cc309c0a742645c95c5000ee47c8d0a5744db83 (plain) (tree)
1
2
3
4
5
6
7
8

                                





                                                                            


                                                                            








                                                                            






























                                                                                  


                                                                            
                     

                                                                            
                                                   


                                                   
                                                                                                  
                          
                           
                                  

                                   

                                
                                
                          
                             

                                  
                             
                                         
                                 




                                                   
                                     

                                                   
                                                        



                                                 
                     



                                                   




                                                        
                                                                                      
















                                                        

                                                   
                                                        
 


                       
 
 






                                                                                      
                                          
                           
                                           
                            











                                                                                       
                                 
                     



                                                   
                                
                              

                                                   
                                                            

                               
                                            
                          
                                    
                         
                     


 
                                                             

                               
                                             
                           
                                     
                         
                     


 
                                                                                     
 

                 
                     


 
                                                   
                                
                               

                                                   
                                                             

                               
                                            
                           
                                    
                          
                     


 
                                                              

                               
                                             
                            
                                     
                          
                     


 
                                                                                       
 

                 
                     


 
                                                   
                                
                               

                                                   
                                                             

                               
                                            
                           
                                    
                          
                     


 
                                                              

                               
                                             
                            
                                     
                          
                     


 
                                                                                       
 

                 
                     


 
                                                   
                                
                               

                                                   
                                                             

                               
                                            
                           
                                    
                          
                     


 
                                                              

                               
                                             
                            
                                     
                          
                     


 
                                                                                       
 

                 
                     


 
                                                   


                                                   
                                                                        



                                                   
                                           
                         
                     


                                                   



                                                   
                                                                                                 
 
     



                                                                   



                                                                                                                                                        



                                                                                  
                                     



                                                                                                                                                         
 

                                                                         



                                                                                                                                                                                           
 
                                                       

                                                                                 
                      

                               


                                                          



                                                                                                                                                                                

                                     
 
     









                                                                                        



                                                                                                                                          
      
      
 



                    







                                                                            
                                                        
                               
                                  

                               

                                   
                                               

                                                                                                       


                                                                                  
                                   
                                                                                                                                           
 
                                               
                                                     

                                          
                                                      

                                   


                                                                                

                                                          
         

                                                                        

                                                   


 




                                                   
                                                                    
                                 
                                  

                               

                              

                                                      


 




                                                            
                                                                                                                                                                    
                                       
                                  
                                          
                                              
 
                                                                                               


 





                                                   



                                                   



                                                   
                                          
 





                                                   
                         

                                                   
                                                                    
 
                                                                                               
                                 
                    
 


                                                   
                                                    

                                                   
                                                                                                                
 
                                          
                                                       

                                                           



                                                              


                                                                     


                                                                                                                                                                                                                        
                         
 


                                                              

                                                                                       
 

                                                                               
                                                                                              
                         

                                                                                                                   
                                 
                                                                                                       


                                                                              










                                                                                      
 












                                                                                  
                                                                    


                                                                                        
                                 
                                                                                                       
 
























                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
 

                                                                                                              


                                                                              




                                                                                                                         
 
                                                                                     
                                         

                                                                
                                         
 



                                                                                  



                                                             
                                                       







                                              






                                                   
                                                                                 

                                                                                                      
                                                                                             
                                                        









                                                                                                    
 
                                                                            


                                          
                                                
                                                    
         


                                               






                                                                                                                       
                                 
                                                                                                                                                                                                                                                                                                             


                                                                
                         


                                                    
                                                        
                                                                                                                                                             
 




                                                                                                                                                                                                   





                                                                                                                                                                                                                                                                                                                               
 
                                              















                                                                                                                                                                                           
 





















                                                                                                                                                                                                                                                
                                                                               
                                                                                
                 
                                                         
                                                            


                                                                        
                                                                          
                 



                                                                                                                                              

                                                                               
                                                                                          

                                              
                                                                                                

                                                                                                                      
                                 
                                                                                         

                                                                                                         
                                                                                          
                                                                                                                                              
                                                                                                                                                                                                                                   


                                                             
                         


                                             
                                                                                                                                                                                                  


                                              
                                                               

                                                                         
                                                     
                                                    
                         



                                                                                        
                         
                                                                         
                                                                                                                                      
                                                                                      
                                                    
                                                                                                                    
      
                 
                                                                

                                                                         
                                                     
                                                     
                         



                                                                                        
                         
                                                                         
                                                                                                                                     
                                                                                      
                                                    
                                                                                                                      
      
                 
                                                                      

                                                                         

                                                                           
                                                                                                                                      
                                                                                      


                                        

                                                                                                                                  
                                                                                                                                         

                                               





                                                                

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

    addrmap.c

    Macros and helper functions for handling address map definitions.

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

#include "emu.h"
#include "validity.h"


//**************************************************************************
//  PARAMETERS
//**************************************************************************

#define DETECT_OVERLAPPING_MEMORY   (0)

/*-------------------------------------------------
    core_i64_hex_format - i64 format printf helper
    why isn't fatalerror going through the same
    channels as logerror exactly?
-------------------------------------------------*/

static char *core_i64_hex_format(u64 value, u8 mindigits)
{
	static char buffer[16][64];
	// TODO: this can overflow - e.g. when a lot of unmapped writes are logged
	static int index;
	char *bufbase = &buffer[index++ % 16][0];
	char *bufptr = bufbase;
	s8 curdigit;

	for (curdigit = 15; curdigit >= 0; curdigit--)
	{
		int nibble = (value >> (curdigit * 4)) & 0xf;
		if (nibble != 0 || curdigit < mindigits)
		{
			mindigits = curdigit;
			*bufptr++ = "0123456789ABCDEF"[nibble];
		}
	}
	if (bufptr == bufbase)
		*bufptr++ = '0';
	*bufptr = 0;

	return bufbase;
}



//**************************************************************************
//  ADDRESS MAP ENTRY
//**************************************************************************

//-------------------------------------------------
//  address_map_entry - constructor
//-------------------------------------------------

address_map_entry::address_map_entry(device_t &device, address_map &map, offs_t start, offs_t end)
	: m_next(nullptr),
		m_map(map),
		m_devbase(device),
		m_addrstart(start),
		m_addrend(end),
		m_addrmirror(0),
		m_addrmask(0),
		m_addrselect(0),
		m_mask(0),
		m_cswidth(0),
		m_share(nullptr),
		m_region(nullptr),
		m_rgnoffs(0),
		m_submap_device(nullptr),
		m_memory(nullptr)
{
}


//-------------------------------------------------
//  mask - set the address mask value
//-------------------------------------------------

address_map_entry &address_map_entry::mask(offs_t _mask)
{
	m_addrmask = _mask;
	if (m_map.m_globalmask != 0)
		m_addrmask &= m_map.m_globalmask;
	return *this;
}


//-------------------------------------------------
//  umask16 - set a 16-bits unitmask value
//-------------------------------------------------

address_map_entry &address_map_entry::umask16(u16 _mask)
{
	m_mask = (u64(_mask) << 48) | (u64(_mask) << 32) | (u64(_mask) << 16) | _mask;
	return *this;
}


//-------------------------------------------------
//  umask32 - set a 32-bits unitmask value
//-------------------------------------------------

address_map_entry &address_map_entry::umask32(u32 _mask)
{
	m_mask = (u64(_mask) << 32) | _mask;
	return *this;
}


//-------------------------------------------------
//  umask64 - set a 64-bits unitmask value
//-------------------------------------------------

address_map_entry &address_map_entry::umask64(u64 _mask)
{
	m_mask = _mask;
	return *this;
}


//-------------------------------------------------
//  m - set up a handler for
//  retrieve a submap from a device
//-------------------------------------------------

address_map_entry &address_map_entry::m(const char *tag, address_map_constructor func)
{
	m_read.m_type = AMH_DEVICE_SUBMAP;
	m_read.m_tag = tag;
	m_write.m_type = AMH_DEVICE_SUBMAP;
	m_write.m_tag = tag;
	m_submap_device = nullptr;
	m_submap_delegate = func;
	return *this;
}

address_map_entry &address_map_entry::m(device_t *device, address_map_constructor func)
{
	m_read.m_type = AMH_DEVICE_SUBMAP;
	m_read.m_tag = nullptr;
	m_write.m_type = AMH_DEVICE_SUBMAP;
	m_write.m_tag = nullptr;
	m_submap_device = device;
	m_submap_delegate = func;
	return *this;
}


//-------------------------------------------------
//  r/w/rw - handler setters for
//  8-bit read/write delegates
//-------------------------------------------------

address_map_entry &address_map_entry::r(read8_delegate func)
{
	assert(!func.isnull());
	m_read.m_type = AMH_DEVICE_DELEGATE;
	m_read.m_bits = 8;
	m_read.m_name = func.name();
	m_rproto8 = func;
	return *this;
}


address_map_entry &address_map_entry::w(write8_delegate func)
{
	assert(!func.isnull());
	m_write.m_type = AMH_DEVICE_DELEGATE;
	m_write.m_bits = 8;
	m_write.m_name = func.name();
	m_wproto8 = func;
	return *this;
}


address_map_entry &address_map_entry::rw(read8_delegate rfunc, write8_delegate wfunc)
{
	r(rfunc);
	w(wfunc);
	return *this;
}


//-------------------------------------------------
//  r/w/rw - handler setters for
//  16-bit read/write delegates
//-------------------------------------------------

address_map_entry &address_map_entry::r(read16_delegate func)
{
	assert(!func.isnull());
	m_read.m_type = AMH_DEVICE_DELEGATE;
	m_read.m_bits = 16;
	m_read.m_name = func.name();
	m_rproto16 = func;
	return *this;
}


address_map_entry &address_map_entry::w(write16_delegate func)
{
	assert(!func.isnull());
	m_write.m_type = AMH_DEVICE_DELEGATE;
	m_write.m_bits = 16;
	m_write.m_name = func.name();
	m_wproto16 = func;
	return *this;
}


address_map_entry &address_map_entry::rw(read16_delegate rfunc, write16_delegate wfunc)
{
	r(rfunc);
	w(wfunc);
	return *this;
}


//-------------------------------------------------
//  r/w/rw - handler setters for
//  32-bit read/write delegates
//-------------------------------------------------

address_map_entry &address_map_entry::r(read32_delegate func)
{
	assert(!func.isnull());
	m_read.m_type = AMH_DEVICE_DELEGATE;
	m_read.m_bits = 32;
	m_read.m_name = func.name();
	m_rproto32 = func;
	return *this;
}


address_map_entry &address_map_entry::w(write32_delegate func)
{
	assert(!func.isnull());
	m_write.m_type = AMH_DEVICE_DELEGATE;
	m_write.m_bits = 32;
	m_write.m_name = func.name();
	m_wproto32 = func;
	return *this;
}


address_map_entry &address_map_entry::rw(read32_delegate rfunc, write32_delegate wfunc)
{
	r(rfunc);
	w(wfunc);
	return *this;
}


//-------------------------------------------------
//  r/w/rw - handler setters for
//  64-bit read/write delegates
//-------------------------------------------------

address_map_entry &address_map_entry::r(read64_delegate func)
{
	assert(!func.isnull());
	m_read.m_type = AMH_DEVICE_DELEGATE;
	m_read.m_bits = 64;
	m_read.m_name = func.name();
	m_rproto64 = func;
	return *this;
}


address_map_entry &address_map_entry::w(write64_delegate func)
{
	assert(!func.isnull());
	m_write.m_type = AMH_DEVICE_DELEGATE;
	m_write.m_bits = 64;
	m_write.m_name = func.name();
	m_wproto64 = func;
	return *this;
}


address_map_entry &address_map_entry::rw(read64_delegate rfunc, write64_delegate wfunc)
{
	r(rfunc);
	w(wfunc);
	return *this;
}


//-------------------------------------------------
//  set_handler - handler setter for setoffset
//-------------------------------------------------

address_map_entry &address_map_entry::setoffset(setoffset_delegate func)
{
	assert(!func.isnull());
	m_setoffsethd.m_type = AMH_DEVICE_DELEGATE;
	m_setoffsethd.m_bits = 0;
	m_setoffsethd.m_name = func.name();
	m_soproto = func;
	return *this;
}

//-------------------------------------------------
//  unitmask_is_appropriate - verify that the
//  provided unitmask is valid and expected
//-------------------------------------------------

bool address_map_entry::unitmask_is_appropriate(u8 width, u64 unitmask, const char *string) const
{
#if 0
	// if no mask, this must match the default width of the map
	if (unitmask == 0)
	{
		if (m_map.m_databits != width)
		{
			osd_printf_error("Handler %s is a %d-bit handler but was specified in a %d-bit address map\n", string, width, m_map.m_databits);
			return false;
		}
		return true;
	}

	// if we have a mask, we must be smaller than the default width of the map
	if (m_map.m_databits < width)
	{
		osd_printf_error("Handler %s is a %d-bit handler and is too wide to be used in a %d-bit address map\n", string, width, m_map.m_databits);
		return false;
	}

	// if map is narrower than 64 bits, check the mask width as well
	if (m_map.m_databits < 64 && (unitmask >> m_map.m_databits) != 0)
	{
		osd_printf_error("Handler %s specified a mask of %08X%08X, too wide to be used in a %d-bit address map\n", string, (u32)(unitmask >> 32), (u32)unitmask, m_map.m_databits);
		return false;
	}

	// the mask must represent whole units of width
	u32 basemask = (width == 8) ? 0xff : (width == 16) ? 0xffff : 0xffffffff;
	u64 singlemask = basemask;
	int count = 0;
	while (singlemask != 0)
	{
		if ((unitmask & singlemask) == singlemask)
			count++;
		else if ((unitmask & singlemask) != 0)
		{
			osd_printf_error("Handler %s specified a mask of %08X%08X; needs to be in even chunks of %X\n", string, (u32)(unitmask >> 32), (u32)unitmask, basemask);
			return false;
		}
		singlemask <<= width;
	}

#if 0
	// the mask must be symmetrical
	u64 unitmask_bh = unitmask >> 8 & 0x00ff00ff00ff00ffU;
	u64 unitmask_bl = unitmask & 0x00ff00ff00ff00ffU;
	u64 unitmask_wh = unitmask >> 16 & 0x0000ffff0000ffffU;
	u64 unitmask_wl = unitmask & 0x0000ffff0000ffffU;
	u64 unitmask_dh = unitmask >> 32 & 0x00000000ffffffffU;
	u64 unitmask_dl = unitmask & 0x00000000ffffffffU;
	if ((unitmask_bh != 0 && unitmask_bl != 0 && unitmask_bh != unitmask_bl)
		|| (unitmask_wh != 0 && unitmask_wl != 0 && unitmask_wh != unitmask_wl)
		|| (unitmask_dh != 0 && unitmask_dl != 0 && unitmask_dh != unitmask_dl))
	{
		osd_printf_error("Handler %s specified an asymmetrical mask of %08X%08X\n", string, (u32)(unitmask >> 32), (u32)unitmask);
		return false;
	}
#endif
#endif

	return true;
}


//**************************************************************************
//  ADDRESS MAP
//**************************************************************************

//-------------------------------------------------
//  address_map - constructor
//-------------------------------------------------

address_map::address_map(device_t &device, int spacenum)
	: m_spacenum(spacenum),
		m_device(&device),
		m_unmapval(0),
		m_globalmask(0)
{
	// get our memory interface
	const device_memory_interface *memintf;
	if (!m_device->interface(memintf))
		throw emu_fatalerror("No memory interface defined for device '%s'\n", m_device->tag());

	// and then the configuration for the current address space
	const address_space_config *spaceconfig = memintf->space_config(spacenum);
	if (spaceconfig == nullptr)
		throw emu_fatalerror("No memory address space configuration found for device '%s', space %d\n", m_device->tag(), spacenum);

	// append the map provided by the owner
	if (!memintf->get_addrmap(spacenum).isnull())
	{
		m_device = device.owner();
		memintf->get_addrmap(spacenum)(*this);
		m_device = &device;
	}
	else
	{
		// if the owner didn't provide a map, use the default device map
		if (!spaceconfig->m_default_map.isnull())
			spaceconfig->m_default_map(*this);
	}

	// construct the internal device map (last so it takes priority)
	if (!spaceconfig->m_internal_map.isnull())
		spaceconfig->m_internal_map(*this);
}



//-------------------------------------------------
//  address_map - constructor in the submap case
//-------------------------------------------------

address_map::address_map(device_t &device, address_map_entry *entry)
	: m_spacenum(AS_PROGRAM),
		m_device(&device),
		m_unmapval(0),
		m_globalmask(0)
{
	// Retrieve the submap
	entry->m_submap_delegate.late_bind(*m_device);
	entry->m_submap_delegate(*this);
}



//----------------------------------------------------------
//  address_map - constructor dynamic device mapping case
//----------------------------------------------------------

address_map::address_map(const address_space &space, offs_t start, offs_t end, u64 unitmask, int cswidth, device_t &device, address_map_constructor submap_delegate)
	: m_spacenum(space.spacenum()),
		m_device(&device),
		m_unmapval(space.unmap()),
		m_globalmask(space.addrmask())
{
	(*this)(start, end).m(DEVICE_SELF, submap_delegate).umask64(unitmask).cswidth(cswidth);
}


//-------------------------------------------------
//  ~address_map - destructor
//-------------------------------------------------

address_map::~address_map()
{
}


//-------------------------------------------------
//  append - append an entry to the end of the
//  list
//-------------------------------------------------

void address_map::global_mask(offs_t mask)
{
	m_globalmask = mask;
}



//-------------------------------------------------
//  add - add a new entry
//-------------------------------------------------

address_map_entry &address_map::operator()(offs_t start, offs_t end)
{
	address_map_entry *ptr = global_alloc(address_map_entry(*m_device, *this, start, end));
	m_entrylist.append(*ptr);
	return *ptr;
}


//-------------------------------------------------
//  import_submaps - propagate in the device submaps
//-------------------------------------------------

void address_map::import_submaps(running_machine &machine, device_t &owner, int data_width, endianness_t endian)
{
	address_map_entry *prev = nullptr;
	address_map_entry *entry = m_entrylist.first();
	u64 base_unitmask = (~u64(0)) >> (64 - data_width);

	while (entry)
	{
		if (entry->m_read.m_type == AMH_DEVICE_SUBMAP)
		{
			device_t *mapdevice = entry->m_submap_device;
			if (!mapdevice)
			{
				mapdevice = owner.subdevice(entry->m_read.m_tag);
				if (mapdevice == nullptr)
					throw emu_fatalerror("Attempted to submap a non-existent device '%s' in space %d of device '%s'\n", owner.subtag(entry->m_read.m_tag).c_str(), m_spacenum, m_device->basetag());
			}

			// Grab the submap
			address_map submap(*mapdevice, entry);

			// Recursively import if needed
			submap.import_submaps(machine, *mapdevice, data_width, endian);

			offs_t max_end = entry->m_addrend - entry->m_addrstart;

			if(!entry->m_mask || (entry->m_mask & base_unitmask) == base_unitmask)
			{
				// Easy case, no unitmask at mapping level - Merge in all the map contents in order
				while (submap.m_entrylist.count())
				{
					address_map_entry *subentry = submap.m_entrylist.detach_head();
					if (subentry->m_addrend > max_end)
						subentry->m_addrend = max_end;

					subentry->m_addrstart += entry->m_addrstart;
					subentry->m_addrend += entry->m_addrstart;
					subentry->m_addrmirror |= entry->m_addrmirror;
					subentry->m_addrmask |= entry->m_addrmask;
					subentry->m_addrselect |= entry->m_addrselect;

					if (subentry->m_addrstart > entry->m_addrend)
					{
						delete subentry;
						continue;
					}

					// Insert the entry in the map
					m_entrylist.insert_after(*subentry, prev);
					prev = subentry;
				}
			}
			else
			{
				// There is a unitmask, calculate its ratio
				int ratio = 0;
				for (int i=0; i != data_width; i++)
					if ((entry->m_mask >> i) & 1)
						ratio ++;
				ratio = data_width / ratio;
				max_end = (max_end + 1) / ratio - 1;

				// Then merge the contents taking the ratio into account
				while (submap.m_entrylist.count())
				{
					address_map_entry *subentry = submap.m_entrylist.detach_head();

					if (subentry->m_mask && (subentry->m_mask != 0xffffffffffffffffU))
					{
						// Check if the mask can actually fit
						int subentry_ratio = 0;
						for (int i=0; i != data_width; i++)
							if ((subentry->m_mask >> i) & 1)
								subentry_ratio ++;
						subentry_ratio = data_width / subentry_ratio;
						if (ratio * subentry_ratio > data_width / 8)
							fatalerror("import_submap: In range %x-%x mask %x mirror %x select %x of device %s, the import unitmask of %s combined with an entry unitmask of %s does not fit in %d bits.\n", subentry->m_addrstart, subentry->m_addrend, subentry->m_addrmask, subentry->m_addrmirror, subentry->m_addrselect, entry->m_read.m_tag, core_i64_hex_format(entry->m_mask, data_width/4), core_i64_hex_format(subentry->m_mask, data_width/4), data_width);

						// Regenerate the unitmask
						u64 newmask = 0;
						int bit_in_subentry = 0;
						for (int i=0; i != data_width; i++)
							if ((entry->m_mask >> i) & 1)
							{
								if ((subentry->m_mask >> bit_in_subentry) & 1)
									newmask |= u64(1) << i;
								bit_in_subentry ++;
							}
						subentry->m_mask = newmask;
					}
					else
						subentry->m_mask = entry->m_mask;

					subentry->m_cswidth = std::max(subentry->m_cswidth, entry->m_cswidth);

					if (subentry->m_addrend > max_end)
						subentry->m_addrend = max_end;

					subentry->m_addrstart = subentry->m_addrstart * ratio + entry->m_addrstart;
					subentry->m_addrend = (subentry->m_addrend + 1) * ratio - 1 + entry->m_addrstart;
					subentry->m_addrmirror = (subentry->m_addrmirror / ratio) | entry->m_addrmirror;
					subentry->m_addrmask = (subentry->m_addrmask / ratio) | entry->m_addrmask;
					subentry->m_addrselect = (subentry->m_addrselect / ratio) | entry->m_addrselect;

					if (subentry->m_addrstart > entry->m_addrend)
					{
						delete subentry;
						continue;
					}

					// Insert the entry in the map
					m_entrylist.insert_after(*subentry, prev);
					prev = subentry;
				}
			}

			address_map_entry *to_delete = entry;
			entry = entry->next();
			m_entrylist.remove(*to_delete);
		}
		else
		{
			prev = entry;
			entry = entry->next();
		}
	}
}


//-------------------------------------------------
//  map_validity_check - perform validity checks on
//  one of the device's address maps
//-------------------------------------------------

void address_map::map_validity_check(validity_checker &valid, int spacenum) const
{
	// it's safe to assume here that the device has a memory interface and a config for this space
	const address_space_config &spaceconfig = *m_device->memory().space_config(spacenum);
	int default_alignunit = spaceconfig.alignment();

	bool detected_overlap = DETECT_OVERLAPPING_MEMORY ? false : true;

	// if this is an empty map, just ignore it
	if (m_entrylist.first() == nullptr)
		return;

	// validate the global map parameters
	if (m_spacenum != spacenum)
		osd_printf_error("Space %d has address space %d handlers!\n", spacenum, m_spacenum);

	offs_t globalmask = 0xffffffffUL >> (32 - spaceconfig.m_addr_width);
	if (m_globalmask != 0)
		globalmask = m_globalmask;

	// loop over entries and look for errors
	for (address_map_entry &entry : m_entrylist)
	{
		// look for overlapping entries
		if (!detected_overlap)
		{
			for (address_map_entry &scan : m_entrylist)
			{
				if (&scan == &entry)
					break;
				if (entry.m_addrstart <= scan.m_addrend && entry.m_addrend >= scan.m_addrstart &&
					((entry.m_read.m_type != AMH_NONE && scan.m_read.m_type != AMH_NONE) ||
						(entry.m_write.m_type != AMH_NONE && scan.m_write.m_type != AMH_NONE)))
				{
					osd_printf_warning("%s space has overlapping memory (%X-%X,%d,%d) vs (%X-%X,%d,%d)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_read.m_type, entry.m_write.m_type, scan.m_addrstart, scan.m_addrend, scan.m_read.m_type, scan.m_write.m_type);
					detected_overlap = true;
					break;
				}
			}
		}

		// look for inverted start/end pairs
		if (entry.m_addrend < entry.m_addrstart)
			osd_printf_error("Wrong %s memory read handler start = %08x > end = %08x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend);

		// look for ranges outside the global mask
		if (entry.m_addrstart & ~globalmask)
			osd_printf_error("In %s memory range %x-%x, start address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask);
		if (entry.m_addrend & ~globalmask)
			osd_printf_error("In %s memory range %x-%x, end address is outside of the global address mask %x\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, globalmask);
		if (entry.m_addrmask & ~globalmask)
			osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, mask is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrmask & globalmask);
		if ((entry.m_addrmirror & ~globalmask) && (entry.m_addrmirror | globalmask) != 0xffffffff >> (32 - spaceconfig.m_addr_width))
			osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, mirror is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrmirror & globalmask);
		if (entry.m_addrselect & ~globalmask)
			osd_printf_error("In %s range %x-%x mask %x mirror %x select %x, select is outside of the global address mask %x, did you mean %x ?\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmirror, entry.m_addrselect, globalmask, entry.m_addrselect & globalmask);

		// look for misaligned entries
		if (entry.m_read.m_type != AMH_NONE)
		{
			int alignunit = spaceconfig.byte2addr(entry.m_read.m_bits / 8);
			if (!alignunit)
				alignunit = default_alignunit;
			if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1))
				osd_printf_error("Wrong %s memory read handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit);
		}
		if (entry.m_write.m_type != AMH_NONE)
		{
			int alignunit = spaceconfig.byte2addr(entry.m_write.m_bits / 8);
			if (!alignunit)
				alignunit = default_alignunit;
			if ((entry.m_addrstart & (alignunit - 1)) != 0 || (entry.m_addrend & (alignunit - 1)) != (alignunit - 1))
				osd_printf_error("Wrong %s memory write handler start = %08x, end = %08x ALIGN = %d\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, alignunit);
		}

		// verify mask/mirror/select
		offs_t set_bits = entry.m_addrstart | entry.m_addrend;
		offs_t changing_bits = entry.m_addrstart ^ entry.m_addrend;
		changing_bits |= changing_bits >> 1;
		changing_bits |= changing_bits >> 2;
		changing_bits |= changing_bits >> 4;
		changing_bits |= changing_bits >> 8;
		changing_bits |= changing_bits >> 16;

		if (entry.m_addrmask & ~changing_bits)
			osd_printf_error("In %s memory range %x-%x, mask %x is trying to unmask an unchanging address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmask, entry.m_addrmask & ~changing_bits);
		if (entry.m_addrmirror & changing_bits)
			osd_printf_error("In %s memory range %x-%x, mirror %x touches a changing address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & changing_bits);
		if (entry.m_addrselect & changing_bits)
			osd_printf_error("In %s memory range %x-%x, select %x touches a changing address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrselect, entry.m_addrselect & changing_bits);
		if (entry.m_addrmirror & set_bits)
			osd_printf_error("In %s memory range %x-%x, mirror %x touches a set address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & set_bits);
		if (entry.m_addrselect & set_bits)
			osd_printf_error("In %s memory range %x-%x, select %x touches a set address bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrselect, entry.m_addrselect & set_bits);
		if (entry.m_addrmirror & entry.m_addrselect)
			osd_printf_error("In %s memory range %x-%x, mirror %x touches a select bit (%x)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_addrmirror, entry.m_addrmirror & entry.m_addrselect);

		// if this is a program space, auto-assign implicit ROM entries
		if (entry.m_read.m_type == AMH_ROM && entry.m_region == nullptr)
		{
			entry.m_region = m_device->tag();
			entry.m_rgnoffs = entry.m_addrstart;
		}

		// if this entry references a memory region, validate it
		if (entry.m_region != nullptr && entry.m_share == nullptr)
		{
			// address map entries that reference regions but are NOPs are pointless
			if (entry.m_read.m_type == AMH_NONE && entry.m_write.m_type == AMH_NONE)
				osd_printf_error("%s space references memory region %s, but is AM_NOP\n", spaceconfig.m_name, entry.m_region);

			// make sure we can resolve the full path to the region
			bool found = false;
			std::string entry_region = entry.m_devbase.subtag(entry.m_region);

			// look for the region
			for (device_t &dev : device_iterator(m_device->mconfig().root_device()))
			{
				for (romload::region const &region : romload::entries(dev.rom_region()).get_regions())
				{
					if (dev.subtag(region.get_tag()) == entry_region)
					{
						// verify the address range is within the region's bounds
						offs_t const length = region.get_length();
						if (entry.m_rgnoffs + spaceconfig.addr2byte(entry.m_addrend - entry.m_addrstart + 1) > length)
							osd_printf_error("%s space memory map entry %X-%X extends beyond region '%s' size (%X)\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region, length);
						found = true;
					}
				}
			}

			// error if not found
			if (!found)
				osd_printf_error("%s space memory map entry %X-%X references non-existant region '%s'\n", spaceconfig.m_name, entry.m_addrstart, entry.m_addrend, entry.m_region);
		}

		// make sure all devices exist
		if (entry.m_read.m_type == AMH_DEVICE_DELEGATE)
		{
			// extract the device tag from the proto-delegate
			const char *devtag = nullptr;
			switch (entry.m_read.m_bits)
			{
				case 8: devtag = entry.m_rproto8.device_name(); break;
				case 16: devtag = entry.m_rproto16.device_name(); break;
				case 32: devtag = entry.m_rproto32.device_name(); break;
				case 64: devtag = entry.m_rproto64.device_name(); break;
			}
			if (entry.m_devbase.subdevice(devtag) == nullptr)
				osd_printf_error("%s space memory map entry reads from nonexistent device '%s'\n", spaceconfig.m_name,
					devtag != nullptr ? devtag : "<unspecified>");
#ifndef MAME_DEBUG // assert will catch this earlier
			(void)entry.unitmask_is_appropriate(entry.m_read.m_bits, entry.m_mask, entry.m_read.m_name);
#endif
		}
		if (entry.m_write.m_type == AMH_DEVICE_DELEGATE)
		{
			// extract the device tag from the proto-delegate
			const char *devtag = nullptr;
			switch (entry.m_write.m_bits)
			{
				case 8: devtag = entry.m_wproto8.device_name(); break;
				case 16: devtag = entry.m_wproto16.device_name(); break;
				case 32: devtag = entry.m_wproto32.device_name(); break;
				case 64: devtag = entry.m_wproto64.device_name(); break;
			}
			if (entry.m_devbase.subdevice(devtag) == nullptr)
				osd_printf_error("%s space memory map entry writes to nonexistent device '%s'\n", spaceconfig.m_name,
					devtag != nullptr ? devtag : "<unspecified>");
#ifndef MAME_DEBUG // assert will catch this earlier
			(void)entry.unitmask_is_appropriate(entry.m_write.m_bits, entry.m_mask, entry.m_write.m_name);
#endif
		}
		if (entry.m_setoffsethd.m_type == AMH_DEVICE_DELEGATE)
		{
			// extract the device tag from the proto-delegate
			const char *devtag = entry.m_soproto.device_name();
			if (entry.m_devbase.subdevice(devtag) == nullptr)
				osd_printf_error("%s space memory map entry references nonexistent device '%s'\n", spaceconfig.m_name,
					devtag != nullptr ? devtag : "<unspecified>");
		}

		// make sure ports exist
//      if ((entry.m_read.m_type == AMH_PORT && entry.m_read.m_tag != nullptr && portlist.find(entry.m_read.m_tag) == nullptr) ||
//          (entry.m_write.m_type == AMH_PORT && entry.m_write.m_tag != nullptr && portlist.find(entry.m_write.m_tag) == nullptr))
//          osd_printf_error("%s space memory map entry references nonexistent port tag '%s'\n", spaceconfig.m_name, entry.m_read.m_tag);

		// validate bank and share tags
		if (entry.m_read.m_type == AMH_BANK)
			valid.validate_tag(entry.m_read.m_tag);
		if (entry.m_write.m_type == AMH_BANK)
			valid.validate_tag(entry.m_write.m_tag);
		if (entry.m_share != nullptr)
			valid.validate_tag(entry.m_share);
	}
}