summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/cpu/drcuml.cpp
blob: 0a1dcae9d02379c62ccd942f7058fed33ef5fd7c (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                





                                                                            

                                                                            

                                
                    
                          
 




                                                                            
 
                                

                       






                                                                   

                                                                            
                
                   

                    


                     
 
                  

 
 


                                                                            
 

                                   

 
 


                                                                            
 







                                                          

                                                
 




                                 



  


                                                                            
 


                                                   
 
                                                                                          





                                                                                               
 

                                             
 


                                                     
         

                                                                                                                 



                                                                     
                 


                                                                             
                                                                                    
                         
                 
         
 
 
 


                                                   
 
                                   
 
 
 
 
 


                                                                            
 



                                                   











                                                                                                                                         
 


 


                                                   
 
                             
 
 
 
 
                                                   
                                                

                                                   
 



                                           
         



                                                 

                                                             
 
                                            
                                  
 
                                                        










                                                       


                                                 
                                                                          

         
 
 


                                                   
 
                                                         

                                                                 





                                                                                                                               
 
                                                       

                                                                                             
 
                          
                           
                          
 
 
 


                                                   
 
                                                              

                                                                 
                                                                       
 
 
 
                                                   
                                             

                                                   
 
                                                                       
 
                                                   
 
 
 
                                                   
                                           
                                                  

                                                   
 
                                                              
 
                                                                    
 
                               



                                                                                     
                 
                                                     


                                                                 
                 
         
 
                                    
                       



                                                   
                                                

                                                   
 
                                                                                    

                                         
                     
         

                                                     
         


 
 


                                                                            
 


                                                   
 





                                                             
 
 
 
 


                                                   
 

                             
 
 
 


                                                   
 




                                                     


 
                                                   
                                                

                                                   
 
                        
 
                        
 

                                            
 


                                                                    
 
                                             
                                                         
 


                                    
 
 


                                                   
 


                          
 

                                    
 


                                  
 
 


                                                   
 


                                                
                                                        
                                   
                                                                       
 

                       
 
 
                                                   
                                               

                                                   
 

                             
                                              
 


                                                              
                                                        
 
                                                   

                                                       
 



                                                                                                       
                                                                      
                                                         
 
                                                                                                       
                                                                 


                                                                         
 
                                

                                                                                                    
 
                                                              
                                                          

                                                                           
                                                                                                                  
 

                                                                       



         
                                                   
                                        

                                                   
 
                                
 
                            
 
                                               
                             
                                                              
         

                                                              
 
                                                          
                                                                                        



                                                       
 
                                                                   


                                                                                  
                                                                                      

                                                                                                                          
 
                                                    

                    
                                                                                  
 
                                                                               

                                               
                                                                                                                               
                                               
                                                     

                            


                                                                    
                 
 

                                                                                       


                                                       

                                                                                                          
                                                                                      



                                          

                                    


 



                                                   
 
                                                                                              
 


                                                
                                                                      




                                                                                                                                   

                                       




                                             



 

     
                                                                            
                       

                                                                            




                                                   
 
                                                                                                              
 
                                        
         






                                                            
         
                        
 
 





                                                                                                                                        


                                                     
                                                                   


                                                                                 

                                                                                           


                                                                                                         

                                                                              







                                                                                                  

                                                                                                            







                                                                                                                          

                                                                   



                                                                                 

                                                                                           



                                                                                                         

                                                                                    








                                                                                                  

                                                                                                            








                                                                                                                          
 
                                                       



                                                                     

                                                                       



                                                                                     


                                                                                


                                                                                              
 

                                                                                                                


                                                                                                                              

                                                                                


                                                                                              
                                                                                
 
                                                                                                                


                                                                                                                              


                                                                                                                
                                                                                     
                                                                                

                                                                                     

                                                                                                                
                                                                                                                     
                                                                                                                

                                                                                                                     

                                                                                


                                                                                     

                                                                                                                


                                                                                                                     









                                                   
                                     
                 
 



                                                        
 
                                    
                                           
                                                                          

                                                                          
                                                           


                                        
                           
                               
                                                                                         












                                                                                                                 
 
                                                   
                                                


                                                                                
                                          









                                                   
                                                                                                                                                         
 
                                                                      
                           
 
                                        
                                                                                               




                                                                                

                                                                                       
                                                                

                                           
 

                                                                                                                                 

                                         
                                                                                              
                                      
                         


                                                                                                                          

                         
                                                     

                                                                   
                                                  
                                             
 
                                                           

                                                    
 

                                                                                                                 
 
                                                                                                                                                  
                                                                                       
                                                                                                                                                                          
                                                                    
 
                                                                           

                                                                         
                                                                                                                                                  

                                                                                                                                                                           
                                                                    
 
                                                                          

                                          
                                                                     












                                                                                                                   
                                                                                                                                              
 
                                                                      

                                            
 
                                                      











                                                                                      
                                                                                                                                                           
 
                                                    
                                            
                             
                            
                           
                      
 
                                         
                                                                                                             
 

                          
 

                                        
                                      
 
                                        
                                                                   
 
                                                      

                                                                                                 
                            




                                      
                                                                  
                              
 
                       
                                                                             
                              
 
                       
                                                                                        
                              
 
                       
                                                                                                   
                              
 
                       
                                                                                                              



                                                    
                                                                                

                                 
 

                        
 

                                     
 
                             
                                                                                                                                                                                    
 
                      
                                                                                             



                                                   
                                        


                                                   
                                                                                                                      
 
                                                             
                   
 
                                                 


                                             
 
                                                        

                                                                   

                                                      

         
                                                      

                                                                   

                                                                    

         

                                                         
                                                                








                                                   
                                                                                                                                                                                      
 
                                                                      


                                                  
                           

                                    
                                  

                                                                
                                                                                        
                                                    
 
                                                                   
                                            
 
                                      

                                       

                                                                                   

                                                                    
 

                                                                                                                                     
                                                                                
                                                          
                                      
 

                                                                                                                                     
                                                                                
                                                          
                                      
 

                                                                                                                                    
                                                                             
                                               
                                                                                                    
                                    
                                                                                                    
                                      
 

                                                                                                                                     
                                                                                            
                                                             

                                      
                                                                              




                                                                 
 
                                                









                                                   
                                                                                                                                                                                                                                                                                        
 
                                                                      

                                                 




                                
 
                      
                                              

                                                                                                 









                                                                                          

         
                                       
                                                                
                                                         
                 
                                                                                                
                                                                                    
                                            
 
                                                               

                                                  



                                                                                         
                                              
 



                                                                                         
                                              
 

                                                                                 
                                                       
                                                                                                    
                                            
                                                                                                    
                                              
 


                                              
 
                                                 
                                                                                                                
                         
                                                           
                                                                                                                          
                                                                                                                                                 

                                                                                                                                  

                                                                                                                                                                    

                         
 
                                                                     


                                                                                                                      

                                                                                                                                      
 
                                                                   
                                                                   
                                                                                                               
                                                                                                                      

                                                                                                                                                                  
 
                                          

                               
                                                   
                                                              
 
                                                          


                                                                           
                                                  


                                         
                                                        

                                  
 

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

    drcuml.c

    Universal machine language for dynamic recompiling CPU cores.

****************************************************************************

    Future improvements/changes:

    * UML optimizer:
        - constant folding

    * Write a back-end validator:
        - checks all combinations of memory/register/immediate on all params
        - checks behavior of all opcodes

    * Extend registers to 16? Depends on if PPC can use them

    * Support for FPU exceptions

    * New instructions?
        - VALID opcode_desc,handle,param
            checksum/compare code referenced by opcode_desc; if not
            matching, generate exception with handle,param

        - RECALL handle
            change code at caller to call handle in the future

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

#include "emu.h"
#include "drcuml.h"

#include "emuopts.h"
#include "drcbec.h"
#include "drcbex86.h"
#include "drcbex64.h"

#include <fstream>



//**************************************************************************
//  DEBUGGING
//**************************************************************************

#define VALIDATE_BACKEND        (0)
#define LOG_SIMPLIFICATIONS     (0)



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

// determine the type of the native DRC, falling back to C
#ifndef NATIVE_DRC
typedef drcbe_c drcbe_native;
#else
typedef NATIVE_DRC drcbe_native;
#endif


// structure describing back-end validation test
struct bevalidate_test
{
	uml::opcode_t   opcode;
	u8              size;
	u8              iflags;
	u8              flags;
	u64             param[4];
};



//**************************************************************************
//  DRC BACKEND INTERFACE
//**************************************************************************

//-------------------------------------------------
//  drcbe_interface - constructor
//-------------------------------------------------

drcbe_interface::drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device)
	: m_drcuml(drcuml)
	, m_cache(cache)
	, m_device(device)
	, m_space()
	, m_state(*reinterpret_cast<drcuml_machine_state *>(cache.alloc_near(sizeof(m_state))))
	, m_accessors(nullptr)
{
	// reset the machine state
	memset(&m_state, 0, sizeof(m_state));

	// find the spaces and fetch memory accessors
	device_memory_interface *memory;
	if (device.interface(memory))
	{
		int const count = memory->max_space_count();
		m_accessors = reinterpret_cast<data_accessors *>(cache.alloc_near(sizeof(*m_accessors) * count));
		memset(m_accessors, 0, sizeof(*m_accessors) * count);
		m_space.resize(count, nullptr);

		for (int spacenum = 0; spacenum < count; ++spacenum)
		{
			if (memory->has_space(spacenum))
			{
				m_space[spacenum] = &memory->space(spacenum);
				m_space[spacenum]->accessors(m_accessors[spacenum]);
			}
		}
	}
}


//-------------------------------------------------
//  ~drcbe_interface - destructor
//-------------------------------------------------

drcbe_interface::~drcbe_interface()
{
}



//**************************************************************************
//  DRCUML STATE
//**************************************************************************

//-------------------------------------------------
//  drcuml_state - constructor
//-------------------------------------------------

drcuml_state::drcuml_state(device_t &device, drc_cache &cache, u32 flags, int modes, int addrbits, int ignorebits)
	: m_device(device)
	, m_cache(cache)
	, m_beintf(device.machine().options().drc_use_c()
			? std::unique_ptr<drcbe_interface>{ new drcbe_c(*this, device, cache, flags, modes, addrbits, ignorebits) }
			: std::unique_ptr<drcbe_interface>{ new drcbe_native(*this, device, cache, flags, modes, addrbits, ignorebits) })
	, m_umllog(device.machine().options().drc_log_uml()
			? new std::ofstream(util::string_format("drcuml_%s.asm", device.shortname()))
			: nullptr)
	, m_blocklist()
	, m_handlelist()
	, m_symlist()
{
}


//-------------------------------------------------
//  ~drcuml_state - destructor
//-------------------------------------------------

drcuml_state::~drcuml_state()
{
}


//-------------------------------------------------
//  reset - reset the state completely, flushing
//  the cache and all information
//-------------------------------------------------

void drcuml_state::reset()
{
	// if we error here, we are screwed
	try
	{
		// flush the cache
		m_cache.flush();

		// reset all handle code pointers
		for (uml::code_handle &handle : m_handlelist)
			*handle.codeptr_addr() = nullptr;

		// call the backend to reset
		m_beintf->reset();

		// do a one-time validation if requested
#if 0
		if (VALIDATE_BACKEND)
		{
			static bool validated = false;
			if (!validated)
			{
				validated = true;
				validate_backend(this);
			}
		}
#endif
	}
	catch (drcuml_block::abort_compilation &)
	{
		fatalerror("Out of cache space in drcuml_state::reset\n");
	}
}


//-------------------------------------------------
//  begin_block - begin a new code block
//-------------------------------------------------

drcuml_block &drcuml_state::begin_block(uint32_t maxinst)
{
	// find an inactive block that matches our qualifications
	drcuml_block *bestblock(nullptr);
	for (drcuml_block &block : m_blocklist)
	{
		if (!block.inuse() && (block.maxinst() >= maxinst) && (!bestblock || (block.maxinst() < bestblock->maxinst())))
			bestblock = &block;
	}

	// if we failed to find one, allocate a new one
	if (!bestblock)
		bestblock = &*m_blocklist.emplace(m_blocklist.end(), *this, maxinst * 3 / 2);

	// start the block
	bestblock->begin();
	return *bestblock;
}


//-------------------------------------------------
//  handle_alloc - allocate a new handle
//-------------------------------------------------

uml::code_handle *drcuml_state::handle_alloc(char const *name)
{
	// allocate the handle, add it to our list, and return it
	return &*m_handlelist.emplace(m_handlelist.end(), *this, name);
}


//-------------------------------------------------
//  symbol_add - add a symbol to the internal
//  symbol table
//-------------------------------------------------

void drcuml_state::symbol_add(void *base, u32 length, char const *name)
{
	m_symlist.emplace_back(base, length, name);
}


//-------------------------------------------------
//  symbol_find - look up a symbol from the
//  internal symbol table or return nullptr if not
//  found
//-------------------------------------------------

const char *drcuml_state::symbol_find(void *base, u32 *offset)
{
	drccodeptr const search(reinterpret_cast<drccodeptr>(base));

	// simple linear search
	for (symbol const &cursym : m_symlist)
	{
		// if no offset pointer, only match perfectly
		if (cursym.includes(search) && (offset || (cursym.base() == search)))
		{
			// return the offset and name
			if (offset)
				*offset = search - cursym.base();
			return cursym.name().c_str();
		}
	}

	// not found; return nullptr
	return nullptr;
}


//-------------------------------------------------
//  log_vprintf - directly printf to the UML log
//  if generated
//-------------------------------------------------

void drcuml_state::log_vprintf(util::format_argument_pack<std::ostream> const &args)
{
	// if we have a file, print to it
	if (m_umllog)
	{
		util::stream_format(*m_umllog, args);
		m_umllog->flush();
	}
}



//**************************************************************************
//  DRCUML BLOCK
//**************************************************************************

//-------------------------------------------------
//  drcuml_block - constructor
//-------------------------------------------------

drcuml_block::drcuml_block(drcuml_state &drcuml, u32 maxinst)
	: m_drcuml(drcuml)
	, m_nextinst(0)
	, m_maxinst(maxinst * 3/2)
	, m_inst(m_maxinst)
	, m_inuse(false)
{
}


//-------------------------------------------------
//  ~drcuml_block - destructor
//-------------------------------------------------

drcuml_block::~drcuml_block()
{
}


//-------------------------------------------------
//  begin - begin code generation
//-------------------------------------------------

void drcuml_block::begin()
{
	// set up the block information and return it
	m_inuse = true;
	m_nextinst = 0;
}


//-------------------------------------------------
//  end - complete a code block and commit it to
//  the cache via the back-end
//-------------------------------------------------

void drcuml_block::end()
{
	assert(m_inuse);

	// optimize the resulting code first
	optimize();

	// if we have a logfile, generate a disassembly of the block
	if (m_drcuml.logging())
		disassemble();

	// generate the code via the back-end
	m_drcuml.generate(*this, &m_inst[0], m_nextinst);

	// block is no longer in use
	m_inuse = false;
}


//-------------------------------------------------
//  abort - abort a code block in progress
//-------------------------------------------------

void drcuml_block::abort()
{
	assert(m_inuse);

	// block is no longer in use
	m_inuse = false;

	// unwind
	throw abort_compilation();
}


//-------------------------------------------------
//  append - append an opcode to the block
//-------------------------------------------------

uml::instruction &drcuml_block::append()
{
	// get a pointer to the next instruction
	uml::instruction &curinst(m_inst[m_nextinst++]);
	if (m_nextinst > m_maxinst)
		fatalerror("Overran maxinst in drcuml_block_append\n");

	return curinst;
}


//-------------------------------------------------
//  optimize - apply various optimizations to a
//  block of code
//-------------------------------------------------

void drcuml_block::optimize()
{
	u32 mapvar[uml::MAPVAR_COUNT] = { 0 };

	// iterate over instructions
	for (int instnum = 0; instnum < m_nextinst; instnum++)
	{
		uml::instruction &inst(m_inst[instnum]);

		// first compute what flags we need
		u8 accumflags(0);
		u8 remainingflags(inst.output_flags());

		// scan ahead until we run out of possible remaining flags
		for (int scannum = instnum + 1; remainingflags != 0 && scannum < m_nextinst; scannum++)
		{
			// any input flags are required
			uml::instruction const &scan(m_inst[scannum]);
			accumflags |= scan.input_flags();

			// if the scanahead instruction is unconditional, assume his flags are modified
			if (scan.condition() == uml::COND_ALWAYS)
				remainingflags &= ~scan.modified_flags();
		}
		inst.set_flags(accumflags);

		// track mapvars
		if (inst.opcode() == uml::OP_MAPVAR)
			mapvar[inst.param(0).mapvar() - uml::MAPVAR_M0] = inst.param(1).immediate();

		// convert all mapvar parameters to immediates
		else if (inst.opcode() != uml::OP_RECOVER)
			for (int pnum = 0; pnum < inst.numparams(); pnum++)
				if (inst.param(pnum).is_mapvar())
					inst.set_mapvar(pnum, mapvar[inst.param(pnum).mapvar() - uml::MAPVAR_M0]);

		// now that flags are correct, simplify the instruction
		inst.simplify();
	}
}


//-------------------------------------------------
//  disassemble - disassemble a block of
//  instructions to the log
//-------------------------------------------------

void drcuml_block::disassemble()
{
	std::string comment;

	// iterate over instructions and output
	int firstcomment(-1);
	for (int instnum = 0; instnum < m_nextinst; instnum++)
	{
		uml::instruction const &inst(m_inst[instnum]);
		bool flushcomments(false);

		// remember comments and mapvars for later
		if (inst.opcode() == uml::OP_COMMENT || inst.opcode() == uml::OP_MAPVAR)
		{
			if (firstcomment == -1)
				firstcomment = instnum;
		}

		// print labels, handles, and hashes left justified
		else if (inst.opcode() == uml::OP_LABEL)
			m_drcuml.log_printf("$%X:\n", u32(inst.param(0).label()));
		else if (inst.opcode() == uml::OP_HANDLE)
			m_drcuml.log_printf("%s:\n", inst.param(0).handle().string());
		else if (inst.opcode() == uml::OP_HASH)
			m_drcuml.log_printf("(%X,%X):\n", u32(inst.param(0).immediate()), u32(inst.param(1).immediate()));

		// indent everything else with a tab
		else
		{
			std::string const dasm(m_inst[instnum].disasm(&m_drcuml));

			// include the first accumulated comment with this line
			if (firstcomment != -1)
			{
				m_drcuml.log_printf("\t%-50.50s; %s\n", dasm, get_comment_text(m_inst[firstcomment], comment));
				firstcomment++;
				flushcomments = true;
			}
			else
			{
				m_drcuml.log_printf("\t%s\n", dasm);
			}
		}

		// flush any comments pending
		if (firstcomment != -1 && (flushcomments || instnum == m_nextinst - 1))
		{
			while (firstcomment <= instnum)
			{
				char const *const text(get_comment_text(m_inst[firstcomment++], comment));
				if (text)
					m_drcuml.log_printf("\t%50s; %s\n", "", text);
			}
			firstcomment = -1;
		}
	}
	m_drcuml.log_printf("\n\n");
	m_drcuml.log_flush();
}


//-------------------------------------------------
//  get_comment_text - determine the text
//  associated with a comment or mapvar
//-------------------------------------------------

char const *drcuml_block::get_comment_text(uml::instruction const &inst, std::string &comment)
{
	if (inst.opcode() == uml::OP_COMMENT)
	{
		// comments return their strings
		return comment.assign(inst.param(0).string()).c_str();
	}
	else if (inst.opcode() == uml::OP_MAPVAR)
	{
		// mapvars comment about their values
		comment = string_format("m%d = $%X", int(inst.param(0).mapvar() - uml::MAPVAR_M0), u32(inst.param(1).immediate()));
		return comment.c_str();
	}
	else
	{
		// everything else is nullptr
		return nullptr;
	}
}



#if 0

/***************************************************************************
    BACK-END VALIDATION
***************************************************************************/

//-------------------------------------------------
//  effective_test_psize - return the effective
//  parameter size based on the size and fixed
//  array of parameter values
//-------------------------------------------------

inline uint8_t effective_test_psize(const opcode_info &opinfo, int pnum, int instsize, const uint64_t *params)
{
	switch (opinfo.param[pnum].size)
	{
		case PSIZE_4:   return 4;
		case PSIZE_8:   return 8;
		case PSIZE_OP:  return instsize;
		case PSIZE_P1:  return 1 << (params[0] & 3);
		case PSIZE_P2:  return 1 << (params[1] & 3);
		case PSIZE_P3:  return 1 << (params[2] & 3);
		case PSIZE_P4:  return 1 << (params[3] & 3);
	}
	return instsize;
}

#define TEST_ENTRY_2(op, size, p1, p2, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2) } },
#define TEST_ENTRY_2F(op, size, p1, p2, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2) } },
#define TEST_ENTRY_3(op, size, p1, p2, p3, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3) } },
#define TEST_ENTRY_3F(op, size, p1, p2, p3, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3) } },
#define TEST_ENTRY_4(op, size, p1, p2, p3, p4, flags) { OP_##op, size, 0, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } },
#define TEST_ENTRY_4F(op, size, p1, p2, p3, p4, iflags, flags) { OP_##op, size, iflags, flags, { u64(p1), u64(p2), u64(p3), u64(p4) } },

static const bevalidate_test bevalidate_test_list[] =
{
	TEST_ENTRY_3(ADD, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0)
	TEST_ENTRY_3(ADD, 4, 0x80000000, 0x12345678, 0x6dcba988, FLAG_V | FLAG_S)
	TEST_ENTRY_3(ADD, 4, 0xffffffff, 0x92345678, 0x6dcba987, FLAG_S)
	TEST_ENTRY_3(ADD, 4, 0x00000000, 0x92345678, 0x6dcba988, FLAG_C | FLAG_Z)

	TEST_ENTRY_3(ADD, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0)
	TEST_ENTRY_3(ADD, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, FLAG_V | FLAG_S)
	TEST_ENTRY_3(ADD, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_S)
	TEST_ENTRY_3(ADD, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, FLAG_C | FLAG_Z)

	TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba987, 0,       0)
	TEST_ENTRY_3F(ADDC, 4, 0x7fffffff, 0x12345678, 0x6dcba986, FLAG_C, 0)
	TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba988, 0,             FLAG_V | FLAG_S)
	TEST_ENTRY_3F(ADDC, 4, 0x80000000, 0x12345678, 0x6dcba987, FLAG_C, FLAG_V | FLAG_S)
	TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba987, 0,             FLAG_S)
	TEST_ENTRY_3F(ADDC, 4, 0xffffffff, 0x92345678, 0x6dcba986, FLAG_C, FLAG_S)
	TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba988, 0,             FLAG_C | FLAG_Z)
	TEST_ENTRY_3F(ADDC, 4, 0x00000000, 0x92345678, 0x6dcba987, FLAG_C, FLAG_C | FLAG_Z)
	TEST_ENTRY_3F(ADDC, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C)

	TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba9876543210, 0,             0)
	TEST_ENTRY_3F(ADDC, 8, 0x7fffffffffffffff, 0x0123456789abcdef, 0x7edcba987654320f, FLAG_C, 0)
	TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543211, 0,             FLAG_V | FLAG_S)
	TEST_ENTRY_3F(ADDC, 8, 0x8000000000000000, 0x0123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_V | FLAG_S)
	TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba9876543210, 0,             FLAG_S)
	TEST_ENTRY_3F(ADDC, 8, 0xffffffffffffffff, 0x8123456789abcdef, 0x7edcba987654320f, FLAG_C, FLAG_S)
	TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543211, 0,             FLAG_C | FLAG_Z)
	TEST_ENTRY_3F(ADDC, 8, 0x0000000000000000, 0x8123456789abcdef, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_Z)
	TEST_ENTRY_3F(ADDC, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C)

	TEST_ENTRY_3(SUB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0)
	TEST_ENTRY_3(SUB, 4, 0x12345678, 0x80000000, 0x6dcba988, FLAG_V)
	TEST_ENTRY_3(SUB, 4, 0x92345678, 0xffffffff, 0x6dcba987, FLAG_S)
	TEST_ENTRY_3(SUB, 4, 0x92345678, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S)
	TEST_ENTRY_3(SUB, 4, 0x00000000, 0x12345678, 0x12345678, FLAG_Z)

	TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0)
	TEST_ENTRY_3(SUB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, FLAG_V)
	TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S)
	TEST_ENTRY_3(SUB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S)
	TEST_ENTRY_3(SUB, 8, 0x0000000000000000, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z)

	TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba987, 0,             0)
	TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x7fffffff, 0x6dcba986, FLAG_C, 0)
	TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba988, 0,             FLAG_V)
	TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x80000000, 0x6dcba987, FLAG_C, FLAG_V)
	TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba987, 0,             FLAG_S)
	TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0xffffffff, 0x6dcba986, FLAG_C, FLAG_S)
	TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba988, 0,             FLAG_C | FLAG_S)
	TEST_ENTRY_3F(SUBB, 4, 0x92345678, 0x00000000, 0x6dcba987, FLAG_C, FLAG_C | FLAG_S)
	TEST_ENTRY_3F(SUBB, 4, 0x12345678, 0x12345678, 0xffffffff, FLAG_C, FLAG_C)
	TEST_ENTRY_3F(SUBB, 4, 0x00000000, 0x12345678, 0x12345677, FLAG_C, FLAG_Z)

	TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba9876543210, 0,             0)
	TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x7fffffffffffffff, 0x7edcba987654320f, FLAG_C, 0)
	TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543211, 0,             FLAG_V)
	TEST_ENTRY_3F(SUBB, 8, 0x0123456789abcdef, 0x8000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_V)
	TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba9876543210, 0,             FLAG_S)
	TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0xffffffffffffffff, 0x7edcba987654320f, FLAG_C, FLAG_S)
	TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543211, 0,             FLAG_C | FLAG_S)
	TEST_ENTRY_3F(SUBB, 8, 0x8123456789abcdef, 0x0000000000000000, 0x7edcba9876543210, FLAG_C, FLAG_C | FLAG_S)
	TEST_ENTRY_3F(SUBB, 8, 0x123456789abcdef0, 0x123456789abcdef0, 0xffffffffffffffff, FLAG_C, FLAG_C)
	TEST_ENTRY_3F(SUBB, 8, 0x0000000000000000, 0x123456789abcdef0, 0x123456789abcdeef, FLAG_C, FLAG_Z)

	TEST_ENTRY_2(CMP, 4, 0x7fffffff, 0x6dcba987, 0)
	TEST_ENTRY_2(CMP, 4, 0x80000000, 0x6dcba988, FLAG_V)
	TEST_ENTRY_2(CMP, 4, 0xffffffff, 0x6dcba987, FLAG_S)
	TEST_ENTRY_2(CMP, 4, 0x00000000, 0x6dcba988, FLAG_C | FLAG_S)
	TEST_ENTRY_2(CMP, 4, 0x12345678, 0x12345678, FLAG_Z)

	TEST_ENTRY_2(CMP, 8, 0x7fffffffffffffff, 0x7edcba9876543210, 0)
	TEST_ENTRY_2(CMP, 8, 0x8000000000000000, 0x7edcba9876543211, FLAG_V)
	TEST_ENTRY_2(CMP, 8, 0xffffffffffffffff, 0x7edcba9876543210, FLAG_S)
	TEST_ENTRY_2(CMP, 8, 0x0000000000000000, 0x7edcba9876543211, FLAG_C | FLAG_S)
	TEST_ENTRY_2(CMP, 8, 0x0123456789abcdef, 0x0123456789abcdef, FLAG_Z)

	TEST_ENTRY_4(MULU, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0)
	TEST_ENTRY_4(MULU, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, 0)
	TEST_ENTRY_4(MULU, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z)
	TEST_ENTRY_4(MULU, 4, 0xea61d951, 0x37c048d0, 0x77777777, 0x77777777, FLAG_V)
	TEST_ENTRY_4(MULU, 4, 0x32323233, 0xcdcdcdcc, 0xcdcdcdcd, 0xffffffff, FLAG_V | FLAG_S)

	TEST_ENTRY_4(MULU, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0)
	TEST_ENTRY_4(MULU, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, 0)
	TEST_ENTRY_4(MULU, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z)
	TEST_ENTRY_4(MULU, 8, 0x0c83fb72ea61d951, 0x37c048d159e26af3, 0x7777777777777777, 0x7777777777777777, FLAG_V)
	TEST_ENTRY_4(MULU, 8, 0x3232323232323233, 0xcdcdcdcdcdcdcdcc, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, FLAG_V | FLAG_S)

	TEST_ENTRY_4(MULS, 4, 0x77777777, 0x00000000, 0x11111111, 0x00000007, 0)
	TEST_ENTRY_4(MULS, 4, 0xffffffff, 0x00000000, 0x11111111, 0x0000000f, FLAG_V)
	TEST_ENTRY_4(MULS, 4, 0x00000000, 0x00000000, 0x11111111, 0x00000000, FLAG_Z)
	TEST_ENTRY_4(MULS, 4, 0x9e26af38, 0xc83fb72e, 0x77777777, 0x88888888, FLAG_V | FLAG_S)
	TEST_ENTRY_4(MULS, 4, 0x32323233, 0x00000000, 0xcdcdcdcd, 0xffffffff, 0)

	TEST_ENTRY_4(MULS, 8, 0x7777777777777777, 0x0000000000000000, 0x1111111111111111, 0x0000000000000007, 0)
	TEST_ENTRY_4(MULS, 8, 0xffffffffffffffff, 0x0000000000000000, 0x1111111111111111, 0x000000000000000f, FLAG_V)
	TEST_ENTRY_4(MULS, 8, 0x0000000000000000, 0x0000000000000000, 0x1111111111111111, 0x0000000000000000, FLAG_Z)
	TEST_ENTRY_4(MULS, 8, 0x7c048d159e26af38, 0xc83fb72ea61d950c, 0x7777777777777777, 0x8888888888888888, FLAG_V | FLAG_S)
	TEST_ENTRY_4(MULS, 8, 0x3232323232323233, 0x0000000000000000, 0xcdcdcdcdcdcdcdcd, 0xffffffffffffffff, 0)

	TEST_ENTRY_4(DIVU, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0)
	TEST_ENTRY_4(DIVU, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z)
	TEST_ENTRY_4(DIVU, 4, 0x7fffffff, 0x00000000, 0xfffffffe, 0x00000002, 0)
	TEST_ENTRY_4(DIVU, 4, 0xfffffffe, 0x00000000, 0xfffffffe, 0x00000001, FLAG_S)
	TEST_ENTRY_4(DIVU, 4, UNDEFINED,  UNDEFINED,  0xffffffff, 0x00000000, FLAG_V)

	TEST_ENTRY_4(DIVU, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0)
	TEST_ENTRY_4(DIVU, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z)
	TEST_ENTRY_4(DIVU, 8, 0x7fffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, 0)
	TEST_ENTRY_4(DIVU, 8, 0xfffffffffffffffe, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000001, FLAG_S)
	TEST_ENTRY_4(DIVU, 8, UNDEFINED,          UNDEFINED,          0xffffffffffffffff, 0x0000000000000000, FLAG_V)

	TEST_ENTRY_4(DIVS, 4, 0x02702702, 0x00000003, 0x11111111, 0x00000007, 0)
	TEST_ENTRY_4(DIVS, 4, 0x00000000, 0x11111111, 0x11111111, 0x11111112, FLAG_Z)
	TEST_ENTRY_4(DIVS, 4, 0xffffffff, 0x00000000, 0xfffffffe, 0x00000002, FLAG_S)
	TEST_ENTRY_4(DIVS, 4, UNDEFINED,  UNDEFINED,  0xffffffff, 0x00000000, FLAG_V)

	TEST_ENTRY_4(DIVS, 8, 0x0270270270270270, 0x0000000000000001, 0x1111111111111111, 0x0000000000000007, 0)
	TEST_ENTRY_4(DIVS, 8, 0x0000000000000000, 0x1111111111111111, 0x1111111111111111, 0x1111111111111112, FLAG_Z)
	TEST_ENTRY_4(DIVS, 8, 0xffffffffffffffff, 0x0000000000000000, 0xfffffffffffffffe, 0x0000000000000002, FLAG_S)
	TEST_ENTRY_4(DIVS, 8, UNDEFINED,          UNDEFINED,          0xffffffffffffffff, 0x0000000000000000, FLAG_V)
};


/*-------------------------------------------------
    validate_backend - execute a number of
    generic tests on the backend code generator
-------------------------------------------------*/

static void validate_backend(drcuml_state *drcuml)
{
	uml::code_handle *handles[3];
	int tnum;

	// allocate handles for the code
	handles[0] = drcuml->handle_alloc("test_entry");
	handles[1] = drcuml->handle_alloc("code_start");
	handles[2] = drcuml->handle_alloc("code_end");

	// iterate over test entries
	printf("Backend validation....\n");
	for (tnum = 31; tnum < ARRAY_LENGTH(bevalidate_test_list); tnum++)
	{
		const bevalidate_test *test = &bevalidate_test_list[tnum];
		parameter param[ARRAY_LENGTH(test->param)];
		char mnemonic[20], *dst;
		const char *src;

		// progress
		dst = mnemonic;
		for (src = opcode_info_table[test->opcode()]->mnemonic; *src != 0; src++)
		{
			if (*src == '!')
			{
				if (test->size == 8)
					*dst++ = 'd';
			}
			else if (*src == '#')
				*dst++ = (test->size == 8) ? 'd' : 's';
			else
				*dst++ = *src;
		}
		*dst = 0;
		printf("Executing test %d/%d (%s)", tnum + 1, (int)ARRAY_LENGTH(bevalidate_test_list), mnemonic);

		// reset parameter list and iterate
		memset(param, 0, sizeof(param));
		bevalidate_iterate_over_params(drcuml, handles, test, param, 0);
		printf("\n");
	}
	fatalerror("All tests passed!\n");
}


/*-------------------------------------------------
    bevalidate_iterate_over_params - iterate over
    all supported types and values of a parameter
    and recursively hand off to the next parameter,
    or else move on to iterate over the flags
-------------------------------------------------*/

static void bevalidate_iterate_over_params(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist, int pnum)
{
	const opcode_info *opinfo = opcode_info_table[test->opcode()];
	drcuml_ptype ptype;

	// if no parameters, execute now
	if (pnum >= ARRAY_LENGTH(opinfo->param) || opinfo->param[pnum].typemask == PTYPES_NONE)
	{
		bevalidate_iterate_over_flags(drcuml, handles, test, paramlist);
		return;
	}

	// iterate over valid parameter types
	for (ptype = parameter::PTYPE_IMMEDIATE; ptype < parameter::PTYPE_MAX; ptype++)
		if (opinfo->param[pnum].typemask & (1 << ptype))
		{
			int pindex, pcount;

			// mapvars can only do 32-bit tests
			if (ptype == parameter::PTYPE_MAPVAR && effective_test_psize(opinfo, pnum, test->size, test->param) == 8)
				continue;

			// for some parameter types, we wish to iterate over all possibilities
			switch (ptype)
			{
				case parameter::PTYPE_INT_REGISTER:     pcount = REG_I_END - REG_I0;        break;
				case parameter::PTYPE_FLOAT_REGISTER:   pcount = REG_F_END - REG_F0;        break;
				default:                            pcount = 1;                                     break;
			}

			// iterate over possibilities
			for (pindex = 0; pindex < pcount; pindex++)
			{
				bool skip = false;
				int pscannum;

				// for param 0, print a dot
				if (pnum == 0)
					printf(".");

				// can't duplicate multiple source parameters unless they are immediates
				if (ptype != parameter::PTYPE_IMMEDIATE && (opinfo->param[pnum].output & PIO_IN))

					// loop over all parameters we've done before; if the parameter is a source and matches us, skip this case
					for (pscannum = 0; pscannum < pnum; pscannum++)
						if ((opinfo->param[pscannum].output & PIO_IN) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value)
							skip = true;

				// can't duplicate multiple dest parameters
				if (opinfo->param[pnum].output & PIO_OUT)

					// loop over all parameters we've done before; if the parameter is a source and matches us, skip this case
					for (pscannum = 0; pscannum < pnum; pscannum++)
						if ((opinfo->param[pscannum].output & PIO_OUT) && ptype == paramlist[pscannum].type && pindex == paramlist[pscannum].value)
							skip = true;

				// iterate over the next parameter in line
				if (!skip)
				{
					paramlist[pnum].type = ptype;
					paramlist[pnum].value = pindex;
					bevalidate_iterate_over_params(drcuml, handles, test, paramlist, pnum + 1);
				}
			}
		}
}


/*-------------------------------------------------
    bevalidate_iterate_over_flags - iterate over
    all supported flag masks
-------------------------------------------------*/

static void bevalidate_iterate_over_flags(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, parameter *paramlist)
{
	const opcode_info *opinfo = opcode_info_table[test->opcode()];
	uint8_t flagmask = opinfo->outflags;
	uint8_t curmask;

	// iterate over all possible flag combinations
	for (curmask = 0; curmask <= flagmask; curmask++)
		if ((curmask & flagmask) == curmask)
			bevalidate_execute(drcuml, handles, test, paramlist, curmask);
}


/*-------------------------------------------------
    bevalidate_execute - execute a single instance
    of a test, generating code and verifying the
    results
-------------------------------------------------*/

static void bevalidate_execute(drcuml_state *drcuml, uml::code_handle **handles, const bevalidate_test *test, const parameter *paramlist, uint8_t flagmask)
{
	parameter params[ARRAY_LENGTH(test->param)];
	drcuml_machine_state istate, fstate;
	instruction testinst;
	drcuml_block *block;
	uint64_t *parammem;
	int numparams;

	// allocate memory for parameters
	parammem = (uint64_t *)drcuml->cache->alloc_near(sizeof(uint64_t) * (ARRAY_LENGTH(test->param) + 1));

	// flush the cache
	drcuml->reset();

	// start a new block
	block = drcuml->block_begin(30);
	UML_HANDLE(block, handles[0]);

	// set up a random initial state
	bevalidate_initialize_random_state(drcuml, block, &istate);

	// then populate the state with the parameters
	numparams = bevalidate_populate_state(block, &istate, test, paramlist, params, parammem);

	// generate the code
	UML_RESTORE(block, &istate);
	UML_HANDLE(block, handles[1]);
	switch (numparams)
	{
		case 0:
			block->append(test->opcode(), test->size);
			break;

		case 1:
			block->append(test->opcode(), test->size, params[0]);
			break;

		case 2:
			block->append(test->opcode(), test->size, params[0], params[1]);
			break;

		case 3:
			block->append(test->opcode(), test->size, params[0], params[1], params[2]);
			break;

		case 4:
			block->append(test->opcode(), test->size, params[0], params[1], params[2], params[3]);
			break;
	}
	testinst = block->inst[block->nextinst - 1];
	UML_HANDLE(block, handles[2]);
	UML_GETFLGS(block, MEM(&parammem[ARRAY_LENGTH(test->param)]), flagmask);
	UML_SAVE(block, &fstate);
	UML_EXIT(block, IMM(0));

	// end the block
	block->end();

	// execute
	drcuml->execute(*handles[0]);

	// verify the results
	bevalidate_verify_state(drcuml, &istate, &fstate, test, *(uint32_t *)&parammem[ARRAY_LENGTH(test->param)], params, &testinst, handles[1]->code, handles[2]->code, flagmask);

	// free memory
	drcuml->cache->dealloc(parammem, sizeof(uint64_t) * (ARRAY_LENGTH(test->param) + 1));
}


/*-------------------------------------------------
    bevalidate_initialize_random_state -
    initialize the machine state to randomness
-------------------------------------------------*/

static void bevalidate_initialize_random_state(drcuml_state *drcuml, drcuml_block *block, drcuml_machine_state *state)
{
	running_machine &machine = drcuml->device->machine();
	int regnum;

	// initialize core state to random values
	state->fmod = machine.rand() & 0x03;
	state->flags = machine.rand() & 0x1f;
	state->exp = machine.rand();

	// initialize integer registers to random values
	for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
	{
		state->r[regnum].w.h = machine.rand();
		state->r[regnum].w.l = machine.rand();
	}

	// initialize float registers to random values
	for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
	{
		*(uint32_t *)&state->f[regnum].s.h = machine.rand();
		*(uint32_t *)&state->f[regnum].s.l = machine.rand();
	}

	// initialize map variables to random values
	for (regnum = 0; regnum < MAPVAR_COUNT; regnum++)
		UML_MAPVAR(block, MVAR(regnum), machine.rand());
}


/*-------------------------------------------------
    bevalidate_populate_state - populate the
    machine state with the proper values prior
    to executing a test
-------------------------------------------------*/

static int bevalidate_populate_state(drcuml_block *block, drcuml_machine_state *state, const bevalidate_test *test, const parameter *paramlist, parameter *params, uint64_t *parammem)
{
	const opcode_info *opinfo = opcode_info_table[test->opcode()];
	int numparams = ARRAY_LENGTH(test->param);
	int pnum;

	// copy flags as-is
	state->flags = test->iflags;

	// iterate over parameters
	for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
	{
		int psize = effective_test_psize(opinfo, pnum, test->size, test->param);
		parameter *curparam = &params[pnum];

		// start with a copy of the parameter from the list
		*curparam = paramlist[pnum];

		// switch off the type
		switch (curparam->type)
		{
			// immediate parameters: take the value from the test entry
			case parameter::PTYPE_IMMEDIATE:
				curparam->value = test->param[pnum];
				break;

			// register parameters: set the register value in the state and set the parameter value to the register index
			case parameter::PTYPE_INT_REGISTER:
				state->r[curparam->value].d = test->param[pnum];
				curparam->value += REG_I0;
				break;

			// register parameters: set the register value in the state and set the parameter value to the register index
			case parameter::PTYPE_FLOAT_REGISTER:
				state->f[curparam->value].d = test->param[pnum];
				curparam->value += REG_F0;
				break;

			// memory parameters: set the memory value in the parameter space and set the parameter value to point to it
			case parameter::PTYPE_MEMORY:
				curparam->value = (uintptr_t)&parammem[pnum];
				if (psize == 4)
					*(uint32_t *)(uintptr_t)curparam->value = test->param[pnum];
				else
					*(uint64_t *)(uintptr_t)curparam->value = test->param[pnum];
				break;

			// map variables: issue a MAPVAR instruction to set the value and set the parameter value to the mapvar index
			case parameter::PTYPE_MAPVAR:
				UML_MAPVAR(block, MVAR(curparam->value), test->param[pnum]);
				curparam->value += MAPVAR_M0;
				break;

			// use anything else to count the number of parameters
			default:
				numparams = MIN(numparams, pnum);
				break;
		}
	}

	// return the total number of parameters
	return numparams;
}


/*-------------------------------------------------
    bevalidate_verify_state - verify the final
    state after executing a test, and report any
    discrepancies
-------------------------------------------------*/

static int bevalidate_verify_state(drcuml_state *drcuml, const drcuml_machine_state *istate, drcuml_machine_state *state, const bevalidate_test *test, uint32_t flags, const parameter *params, const instruction *testinst, drccodeptr codestart, drccodeptr codeend, uint8_t flagmask)
{
	const opcode_info *opinfo = opcode_info_table[test->opcode()];
	uint8_t ireg[REG_I_END - REG_I0] = { 0 };
	uint8_t freg[REG_F_END - REG_F0] = { 0 };
	char errorbuf[1024];
	char *errend = errorbuf;
	int pnum, regnum;

	*errend = 0;

	// check flags
	if (flags != (test->flags & flagmask))
	{
		errend += sprintf(errend, "  Flags ... result:%c%c%c%c%c  expected:%c%c%c%c%c\n",
			(flagmask & FLAG_U) ? ((flags & FLAG_U) ? 'U' : '.') : '-',
			(flagmask & FLAG_S) ? ((flags & FLAG_S) ? 'S' : '.') : '-',
			(flagmask & FLAG_Z) ? ((flags & FLAG_Z) ? 'Z' : '.') : '-',
			(flagmask & FLAG_V) ? ((flags & FLAG_V) ? 'V' : '.') : '-',
			(flagmask & FLAG_C) ? ((flags & FLAG_C) ? 'C' : '.') : '-',
			(flagmask & FLAG_U) ? ((test->flags & FLAG_U) ? 'U' : '.') : '-',
			(flagmask & FLAG_S) ? ((test->flags & FLAG_S) ? 'S' : '.') : '-',
			(flagmask & FLAG_Z) ? ((test->flags & FLAG_Z) ? 'Z' : '.') : '-',
			(flagmask & FLAG_V) ? ((test->flags & FLAG_V) ? 'V' : '.') : '-',
			(flagmask & FLAG_C) ? ((test->flags & FLAG_C) ? 'C' : '.') : '-');
	}

	// check destination parameters
	for (pnum = 0; pnum < ARRAY_LENGTH(test->param); pnum++)
		if (opinfo->param[pnum].output & PIO_OUT)
		{
			int psize = effective_test_psize(opinfo, pnum, test->size, test->param);
			uint64_t mask = u64(0xffffffffffffffff) >> (64 - 8 * psize);
			uint64_t result = 0;

			// fetch the result from the parameters
			switch (params[pnum].type)
			{
				// integer registers fetch from the state
				case parameter::PTYPE_INT_REGISTER:
					ireg[params[pnum].value - REG_I0] = 1;
					result = state->r[params[pnum].value - REG_I0].d;
					break;

				// float registers fetch from the state
				case parameter::PTYPE_FLOAT_REGISTER:
					freg[params[pnum].value - REG_I0] = 1;
					result = state->f[params[pnum].value - REG_F0].d;
					break;

				// memory registers fetch from the memory address
				case parameter::PTYPE_MEMORY:
					if (psize == 4)
						result = *(uint32_t *)(uintptr_t)params[pnum].value;
					else
						result = *(uint64_t *)(uintptr_t)params[pnum].value;
					break;

				default:
					break;
			}

			// check against the mask
			if (test->param[pnum] != UNDEFINED_U64 && (result & mask) != (test->param[pnum] & mask))
			{
				if ((uint32_t)mask == mask)
					errend += sprintf(errend, "  Parameter %d ... result:%08X  expected:%08X\n", pnum,
										(uint32_t)(result & mask), (uint32_t)(test->param[pnum] & mask));
				else
					errend += sprintf(errend, "  Parameter %d ... result:%08X%08X  expected:%08X%08X\n", pnum,
										(uint32_t)((result & mask) >> 32), (uint32_t)(result & mask),
										(uint32_t)((test->param[pnum] & mask) >> 32), (uint32_t)(test->param[pnum] & mask));
			}
		}

	// check source integer parameters for unexpected alterations
	for (regnum = 0; regnum < ARRAY_LENGTH(state->r); regnum++)
		if (ireg[regnum] == 0 && istate->r[regnum].d != state->r[regnum].d)
			errend += sprintf(errend, "  Register i%d ... result:%08X%08X  originally:%08X%08X\n", regnum,
								(uint32_t)(state->r[regnum].d >> 32), (uint32_t)state->r[regnum].d,
								(uint32_t)(istate->r[regnum].d >> 32), (uint32_t)istate->r[regnum].d);

	// check source float parameters for unexpected alterations
	for (regnum = 0; regnum < ARRAY_LENGTH(state->f); regnum++)
		if (freg[regnum] == 0 && *(uint64_t *)&istate->f[regnum].d != *(uint64_t *)&state->f[regnum].d)
			errend += sprintf(errend, "  Register f%d ... result:%08X%08X  originally:%08X%08X\n", regnum,
								(uint32_t)(*(uint64_t *)&state->f[regnum].d >> 32), (uint32_t)*(uint64_t *)&state->f[regnum].d,
								(uint32_t)(*(uint64_t *)&istate->f[regnum].d >> 32), (uint32_t)*(uint64_t *)&istate->f[regnum].d);

	// output the error if we have one
	if (errend != errorbuf)
	{
		// disassemble the test instruction
		std::string disasm = testinst->disasm(drcuml);

		// output a description of what went wrong
		printf("\n");
		printf("----------------------------------------------\n");
		printf("Backend validation error:\n");
		printf("   %s\n", disasm.c_str());
		printf("\n");
		printf("Errors:\n");
		printf("%s\n", errorbuf);
		fatalerror("Error during validation\n");
	}
	return errend != errorbuf;
}

#endif