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

                                





                                                                            








                                                                            
                                                   
 



















                             











                                                                            
                                                                                                                                   
                              
                               
                                     
                                 
                               

                                       
                                    
 
                                                                                                      
 
                           
 
                                      
                                     
                                         
                                      
                                         
                                         
                                            

 

                                                                              
                               

                              
                                                    





                                       

                                                   








                                                   




                                                                      
                                 

                                 
                                                                             
                                      
                        





                                                   









                                                   





                                  
                                             

                                                                                                   
                      
                                                                      
                        
                                                  



                                                   

                                                 

                                                   
                                               
 










                                                   



                                                   










                                                   
                                          
                                       

                                                   
                                                                             
 
                         
                             
 



                                  
                        

                          
                                                                     











                                                                                              
                                             











                                                                   
                                                             












                                                                                           

                                                                                 














                                                                                                 
                                                         







                                                                                                  
                                                                                 


                                                                                                               
                                                                 



                                             






                                                                                                 
                                                         







                                                                                          
                                                                                 


                                                                                                               
                                                                 



                                             






                                                                                                 
                                                         



                                                      
                                                         










                                                                                                 
                                                         







                                                                                                                                              
                                                                                 


                                                                                                               
                                                                 







                                                                                                 
                                                      



                                                                                                             
                                                            
                                 
                                                            

                                                                
                                                                 

                                    
                                                                   





                                                                                               






                                                   
                                        

                                                   
                                                   
 

                                              







                                                                          




                                                   












                                                       




                                                         



                                                   









                                                             








                                                            








                                                                            
                                                                                               
                                           

                                                      

                                      
                                           












                                                   
                                                   
                             

                                                   
                                                
 
                                                  
                                                                  
                             
                         
 










                                                   
                                       

                                                   
                                                                 
 
                                                             
                                                                  
                             
                                          
 
                                          
                           

                                                    

                                                                 

                                         
                                             









                                                              
                                                             
                                                                  
                             


                                                   
                                                



                                                   
                                              
                                     

                                                   
                                                                
 
                                                   
                                                                  
                             
                       
 









                                                   

                                                

                                                   
                                                                            
 
                                                   
                                                                  
                             
                       
 









                                                   
                                                

                                                   
                                                                                                  
 
                                        

                                                             

                                           

                                                                                                               
 
                         



                                                   





                                                                          
                                









                                                                          
                                







                                                   
                                                                                                   
 
                                







                                                   
                                                                                                         
 
                                



                                                   

                                                

                                                   
                                                   
 
                                                    
                                     
                                                                                                              







                                                   
                                                                                   

                                      

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

    distate.c

    Device state interfaces.

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

#include "emu.h"


//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

const u64 device_state_entry::k_decimal_divisor[] =
{
	1U,
	10U,
	100U,
	1000U,
	10000U,
	100000U,
	1000000U,
	10000000U,
	100000000U,
	1000000000U,
	10000000000U,
	100000000000U,
	1000000000000U,
	10000000000000U,
	100000000000000U,
	1000000000000000U,
	10000000000000000U,
	100000000000000000U,
	1000000000000000000U,
	10000000000000000000U
};



//**************************************************************************
//  DEVICE STATE ENTRY
//**************************************************************************

//-------------------------------------------------
//  device_state_entry - constructor
//-------------------------------------------------

device_state_entry::device_state_entry(int index, const char *symbol, u8 size, u64 sizemask, u8 flags, device_state_interface *dev)
	: m_device_state(dev),
		m_index(index),
		m_datamask(sizemask),
		m_datasize(size),
		m_flags(flags),
		m_symbol(symbol),
		m_default_format(true),
		m_sizemask(sizemask)
{
	assert(size == 1 || size == 2 || size == 4 || size == 8 || (flags & DSF_FLOATING_POINT) != 0);

	format_from_mask();

	// override well-known symbols
	if (index == STATE_GENPCBASE)
		m_symbol.assign("CURPC");
	else if (index == STATE_GENSP)
		m_symbol.assign("CURSP");
	else if (index == STATE_GENFLAGS)
		m_symbol.assign("CURFLAGS");
}

device_state_entry::device_state_entry(int index, device_state_interface *dev)
	: m_device_state(dev),
		m_index(index),
		m_datamask(0),
		m_datasize(0),
		m_flags(DSF_DIVIDER | DSF_READONLY),
		m_symbol(),
		m_default_format(true),
		m_sizemask(0)
{
}


//-------------------------------------------------
//  device_state_entry - destructor
//-------------------------------------------------

device_state_entry::~device_state_entry()
{
}


//-------------------------------------------------
//  formatstr - specify a format string
//-------------------------------------------------

device_state_entry &device_state_entry::formatstr(const char *_format)
{
	m_format.assign(_format);
	m_default_format = false;

	// set the DSF_CUSTOM_STRING flag by formatting with a nullptr string
	m_flags &= ~DSF_CUSTOM_STRING;
	format(nullptr);

	return *this;
}


//-------------------------------------------------
//  format_from_mask - make a format based on
//  the data mask
//-------------------------------------------------

void device_state_entry::format_from_mask()
{
	// skip if we have a user-provided format
	if (!m_default_format)
		return;

	if (is_float())
	{
		m_format = "%12s";
		return;
	}

	// make up a format based on the mask
	if (m_datamask == 0)
		throw emu_fatalerror("%s state entry requires a nonzero mask\n", m_symbol.c_str());
	int width = 0;
	for (u64 tempmask = m_datamask; tempmask != 0; tempmask >>= 4)
		width++;
	m_format = string_format("%%0%dX", width);
}


//-------------------------------------------------
//  entry_baseptr - return a pointer to where the
//  data lives (if applicable)
//-------------------------------------------------

void *device_state_entry::entry_baseptr() const
{
	return nullptr;
}


//-------------------------------------------------
//  entry_value - return the current value as a u64
//-------------------------------------------------

u64 device_state_entry::entry_value() const
{
	return 0;
}


//-------------------------------------------------
//  entry_dvalue - return the current value as a
//  double
//-------------------------------------------------

double device_state_entry::entry_dvalue() const
{
	return 0.0;
}


//-------------------------------------------------
//  format - return the value of the given
//  pieces of indexed state as a string
//-------------------------------------------------

std::string device_state_entry::format(const char *string, bool maxout) const
{
	std::string dest;
	u64 result = value();

	// parse the format
	bool leadzero = false;
	bool percent = false;
	bool explicitsign = false;
	bool hitnonzero;
	bool reset = true;
	int width = 0;
	for (const char *fptr = m_format.c_str(); *fptr != 0; fptr++)
	{
		// reset any accumulated state
		if (reset)
		{
			leadzero = maxout;
			percent = explicitsign = reset = false;
			width = 0;
		}

		// if we're not within a format, then anything other than a % outputs directly
		if (!percent && *fptr != '%')
		{
			dest.append(fptr, 1);
			continue;
		}

		// handle each character in turn
		switch (*fptr)
		{
			// % starts a format; %% outputs a single %
			case '%':
				if (!percent)
					percent = true;
				else
				{
					dest.append(fptr, 1);
					percent = false;
				}
				break;

			// 0 means insert leading 0s, unless it follows another width digit
			case '0':
				if (width == 0)
					leadzero = true;
				else
					width *= 10;
				break;

			// 1-9 accumulate into the width
			case '1':   case '2':   case '3':   case '4':   case '5':
			case '6':   case '7':   case '8':   case '9':
				width = width * 10 + (*fptr - '0');
				break;

			// + means explicit sign
			case '+':
				explicitsign = true;
				break;

			// X outputs as hexadecimal
			case 'X':
				if (width == 0)
					throw emu_fatalerror("Width required for %%X formats\n");
				hitnonzero = false;
				while (leadzero && width > 16)
				{
					dest.append(" ");
					width--;
				}
				for (int digitnum = 15; digitnum >= 0; digitnum--)
				{
					int digit = (result >> (4 * digitnum)) & 0x0f;
					if (digit != 0)
					{
						static const char hexchars[] = "0123456789ABCDEF";
						dest.append(&hexchars[digit], 1);
						hitnonzero = true;
					}
					else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
						dest.append("0");
				}
				reset = true;
				break;

			// O outputs as octal
			case 'O':
				if (width == 0)
					throw emu_fatalerror("Width required for %%O formats\n");
				hitnonzero = false;
				while (leadzero && width > 22)
				{
					dest.append(" ");
					width--;
				}
				for (int digitnum = 21; digitnum >= 0; digitnum--)
				{
					int digit = (result >> (3 * digitnum)) & 07;
					if (digit != 0)
					{
						static const char octchars[] = "01234567";
						dest.append(&octchars[digit], 1);
						hitnonzero = true;
					}
					else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
						dest.append("0");
				}
				reset = true;
				break;

			// d outputs as signed decimal
			case 'd':
				if (width == 0)
					throw emu_fatalerror("Width required for %%d formats\n");
				if ((result & m_datamask) > (m_datamask >> 1))
				{
					result = -result & m_datamask;
					dest.append("-");
					width--;
				}
				else if (explicitsign)
				{
					dest.append("+");
					width--;
				}
				// fall through to unsigned case

			// u outputs as unsigned decimal
			case 'u':
				if (width == 0)
					throw emu_fatalerror("Width required for %%u formats\n");
				hitnonzero = false;
				while (leadzero && width > ARRAY_LENGTH(k_decimal_divisor))
				{
					dest.append(" ");
					width--;
				}
				for (int digitnum = ARRAY_LENGTH(k_decimal_divisor) - 1; digitnum >= 0; digitnum--)
				{
					int digit = (result >= k_decimal_divisor[digitnum]) ? (result / k_decimal_divisor[digitnum]) % 10 : 0;
					if (digit != 0)
					{
						static const char decchars[] = "0123456789";
						dest.append(&decchars[digit], 1);
						hitnonzero = true;
					}
					else if (hitnonzero || (leadzero && digitnum < width) || digitnum == 0)
						dest.append("0");
				}
				reset = true;
				break;

			// s outputs a custom string
			case 's':
				if (width == 0)
					throw emu_fatalerror("Width required for %%s formats\n");
				if (string == nullptr)
				{
					const_cast<device_state_entry *>(this)->m_flags |= DSF_CUSTOM_STRING;
					return dest;
				}
				if (strlen(string) <= width)
				{
					dest.append(string);
					width -= strlen(string);
					while (width-- != 0)
						dest.append(" ");
				}
				else
					dest.append(string, width);
				reset = true;
				break;

			// other formats unknown
			default:
				throw emu_fatalerror("Unknown format character '%c'\n", *fptr);
		}
	}
	return dest;
}


//-------------------------------------------------
//  set_value - set the value from a u64
//-------------------------------------------------

void device_state_entry::set_value(u64 value) const
{
	assert((m_flags & DSF_READONLY) == 0);

	// apply the mask
	value &= m_datamask;

	// sign-extend if necessary
	if ((m_flags & DSF_IMPORT_SEXT) != 0 && value > (m_datamask >> 1))
		value |= ~m_datamask;

	// store the value
	entry_set_value(value);
}


//-------------------------------------------------
//  set_dvalue - set the value from a double
//-------------------------------------------------

void device_state_entry::set_dvalue(double value) const
{
	assert((m_flags & DSF_READONLY) == 0);

	// store the value
	entry_set_dvalue(value);
}


//-------------------------------------------------
//  entry_set_value - set the value from a u64
//-------------------------------------------------

void device_state_entry::entry_set_value(u64 value) const
{
}


//-------------------------------------------------
//  entry_set_dvalue - set the value from a double
//-------------------------------------------------

void device_state_entry::entry_set_dvalue(double value) const
{
	set_value(u64(value));
}


//-------------------------------------------------
//  set_value - set the value from a string
//-------------------------------------------------

void device_state_entry::set_value(const char *string) const
{
	// not implemented
}



//**************************************************************************
//  DEVICE STATE INTERFACE
//**************************************************************************

//-------------------------------------------------
//  device_state_interface - constructor
//-------------------------------------------------

device_state_interface::device_state_interface(const machine_config &mconfig, device_t &device)
	: device_interface(device, "state")
{
	memset(m_fast_state, 0, sizeof(m_fast_state));

	// configure the fast accessor
	device.interfaces().m_state = this;
}


//-------------------------------------------------
//  ~device_state_interface - destructor
//-------------------------------------------------

device_state_interface::~device_state_interface()
{
}


//-------------------------------------------------
//  state_int - return the value of the given piece
//  of indexed state as a u64
//-------------------------------------------------

u64 device_state_interface::state_int(int index)
{
	// nullptr or out-of-range entry returns 0
	const device_state_entry *entry = state_find_entry(index);
	if (entry == nullptr)
		return 0;

	// call the exporter before we do anything
	if (entry->needs_export())
		state_export(*entry);

	// pick up the value
	return entry->value();
}


//-------------------------------------------------
//  state_string - return the value of the given
//  pieces of indexed state as a string
//-------------------------------------------------

std::string device_state_interface::state_string(int index) const
{
	// nullptr or out-of-range entry returns bogus string
	const device_state_entry *entry = state_find_entry(index);
	if (entry == nullptr)
		return std::string("???");

	// get the custom string if needed
	std::string custom;
	if (entry->needs_custom_string())
		state_string_export(*entry, custom);
	else if (entry->is_float())
		custom = string_format("%-12G", entry->dvalue());

	// ask the entry to format itself
	return entry->format(custom.c_str());
}


//-------------------------------------------------
//  state_string_max_length - return the maximum
//  length of the given state string
//-------------------------------------------------

int device_state_interface::state_string_max_length(int index)
{
	// nullptr or out-of-range entry returns bogus string
	const device_state_entry *entry = state_find_entry(index);
	if (entry == nullptr)
		return 3;

	// ask the entry to format itself maximally
	return entry->format("", true).length();
}


//-------------------------------------------------
//  set_state_int - set the value of the given
//  piece of indexed state from a u64
//-------------------------------------------------

void device_state_interface::set_state_int(int index, u64 value)
{
	// nullptr or out-of-range entry is a no-op
	const device_state_entry *entry = state_find_entry(index);
	if (entry == nullptr)
		return;

	// set the value
	entry->set_value(value);

	// call the importer to finish up
	if (entry->needs_import())
		state_import(*entry);
}


//-------------------------------------------------
//  set_state - set the value of the given piece
//  of indexed state from a string
//-------------------------------------------------

void device_state_interface::set_state_string(int index, const char *string)
{
	// nullptr or out-of-range entry is a no-op
	const device_state_entry *entry = state_find_entry(index);
	if (entry == nullptr)
		return;

	// set the value
	entry->set_value(string);

	// call the importer to finish up
	if (entry->needs_import())
		state_import(*entry);
}


//-------------------------------------------------
//  state_add - add a new piece of indexed state
//-------------------------------------------------

device_state_entry &device_state_interface::state_add(std::unique_ptr<device_state_entry> &&entry)
{
	// append to the end of the list
	m_state_list.push_back(std::move(entry));
	device_state_entry &new_entry = *m_state_list.back();

	// set the fast entry if applicable
	if (new_entry.index() >= FAST_STATE_MIN && new_entry.index() <= FAST_STATE_MAX && !new_entry.divider())
		m_fast_state[new_entry.index() - FAST_STATE_MIN] = &new_entry;

	return new_entry;
}


//-------------------------------------------------
//  state_import - called after new state is
//  written to perform any post-processing
//-------------------------------------------------

void device_state_interface::state_import(const device_state_entry &entry)
{
	// do nothing by default
}


//-------------------------------------------------
//  state_export - called prior to new state
//  reading the state
//-------------------------------------------------

void device_state_interface::state_export(const device_state_entry &entry)
{
	// do nothing by default
}


//-------------------------------------------------
//  state_string_import - called after new state is
//  written to perform any post-processing
//-------------------------------------------------

void device_state_interface::state_string_import(const device_state_entry &entry, std::string &str)
{
	// do nothing by default
}


//-------------------------------------------------
//  state_string_export - called after new state is
//  written to perform any post-processing
//-------------------------------------------------

void device_state_interface::state_string_export(const device_state_entry &entry, std::string &str) const
{
	// do nothing by default
}


//-------------------------------------------------
//  interface_post_start - verify that state was
//  properly set up
//-------------------------------------------------

void device_state_interface::interface_post_start()
{
	// make sure we got something during startup
	if (m_state_list.size() == 0)
		throw emu_fatalerror("No state registered for device '%s' that supports it!", m_device.tag());
}


//-------------------------------------------------
//  state_find_entry - return a pointer to the
//  state entry for the given index
//-------------------------------------------------

const device_state_entry *device_state_interface::state_find_entry(int index) const
{
	// use fast lookup if possible
	if (index >= FAST_STATE_MIN && index <= FAST_STATE_MAX)
		return m_fast_state[index - FAST_STATE_MIN];

	// otherwise, scan the first
	for (auto &entry : m_state_list)
		if (entry->m_index == index)
			return entry.get();

	// handle failure by returning nullptr
	return nullptr;
}