summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/cpu/drcuml.h
blob: 1e57e74b02cf308ab61488fad7071f57852ed1e8 (plain) (tree)
1
2
3
4
5
6
7
8

                                





                                                                            






                                                                            
                     
                

 


                                                                            
 
                                                                            
 
 
 


                                                                            
 

                                                          
              




                                

 

                                                   

 

                                           

                
                                                                                         
     
                                                                                         
      
                                                                       


  

                                                 

                
                                                                                         
     
                                                                                         
      
                                                                       


  

                                          
 




                                                                                      


  

                                           
 

                                                                                                   


  

                                                         
 
                                               










                                                           
                          





                                   
                                                                                                            











                                                      
                                                                                         

                         



                                                                                            
                                                                                    
                                                                           


  
                                     
                     




                                                                                  
 





                                                                                                         
                                                      


                         





                                                                                           
  
 
 






                                                                                                                
 







                                                                                
                          








                                                                                                                                           
 

                                                                     
                                                                      

                  
                                                              
                                                                  
                                                             
                                                                  





                                          
                                                 
 

                                                                   
                                          


                                                         






                                                       


                                                                                           
                                                                                 


                         

                                                                                            
                                                           




                                                                                    
  
 
 
 


























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

    drcuml.h

    Universal machine language for dynamic recompiling CPU cores.

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

#pragma once

#ifndef __DRCUML_H__
#define __DRCUML_H__

#include "drccache.h"
#include "uml.h"


//**************************************************************************
//  CONSTANTS
//**************************************************************************

// these options are passed into drcuml_alloc() and control global behaviors



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

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


// opaque structure describing UML generation state
class drcuml_state;


// an integer register, with low/high parts
union drcuml_ireg
{
#ifdef LSB_FIRST
	struct { UINT32 l,h; } w;               // 32-bit low, high parts of the register
#else
	struct { UINT32 h,l; } w;               // 32-bit low, high parts of the register
#endif
	UINT64              d;                  // 64-bit full register
};


// a floating-point register, with low/high parts
union drcuml_freg
{
#ifdef LSB_FIRST
	struct { float l,h; } s;                // 32-bit low, high parts of the register
#else
	struct { float h,l; } s;                // 32-bit low, high parts of the register
#endif
	double              d;                  // 64-bit full register
};


// the collected machine state of a system
struct drcuml_machine_state
{
	drcuml_ireg         r[uml::REG_I_COUNT];    // integer registers
	drcuml_freg         f[uml::REG_F_COUNT];    // floating-point registers
	UINT32              exp;                // exception parameter register
	UINT8               fmod;               // fmod (floating-point mode) register
	UINT8               flags;              // flags state
};


// hints and information about the back-end
struct drcbe_info
{
	UINT8               direct_iregs;       // number of direct-mapped integer registers
	UINT8               direct_fregs;       // number of direct-mapped floating point registers
};


// a drcuml_block describes a basic block of instructions
class drcuml_block
{
	friend class simple_list<drcuml_block>;

public:
	// construction/destruction
	drcuml_block(drcuml_state &drcuml, UINT32 maxinst);
	~drcuml_block();

	// getters
	drcuml_block *next() const { return m_next; }
	bool inuse() const { return m_inuse; }
	UINT32 maxinst() const { return m_maxinst; }

	// code generation
	void begin();
	void end();
	void abort();

	// instruction appending
	uml::instruction &append();
	template <typename Format, typename... Params> void append_comment(Format &&fmt, Params &&... args);

	// this class is thrown if abort() is called
	class abort_compilation : public emu_exception
	{
		friend class drcuml_block;
		abort_compilation() { }
	};

private:
	// internal helpers
	void optimize();
	void disassemble();
	const char *get_comment_text(const uml::instruction &inst, std::string &comment);

	// internal state
	drcuml_state &          m_drcuml;           // pointer back to the owning UML
	drcuml_block *          m_next;             // pointer to next block
	UINT32                  m_nextinst;         // next instruction to fill in the cache
	UINT32                  m_maxinst;          // maximum number of instructions
	std::vector<uml::instruction> m_inst;     // pointer to the instruction list
	bool                    m_inuse;            // this block is in use
};


// interface structure for a back-end
class drcbe_interface
{
public:
	// construction/destruction
	drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device);
	virtual ~drcbe_interface();

	// required overrides
	virtual void reset() = 0;
	virtual int execute(uml::code_handle &entry) = 0;
	virtual void generate(drcuml_block &block, const uml::instruction *instlist, UINT32 numinst) = 0;
	virtual bool hash_exists(UINT32 mode, UINT32 pc) = 0;
	virtual void get_info(drcbe_info &info) = 0;
	virtual bool logging() const { return false; }

protected:
	// internal state
	drcuml_state &          m_drcuml;           // pointer back to our owner
	drc_cache &             m_cache;            // pointer to the cache
	device_t &              m_device;           // CPU device we are associated with
	address_space *         m_space[ADDRESS_SPACES];// pointers to CPU's address space
	drcuml_machine_state &  m_state;            // state of the machine (in near cache)
	data_accessors *        m_accessors;        // memory accessors (in near cache)
};


// structure describing UML generation state
class drcuml_state
{
public:
	// construction/destruction
	drcuml_state(device_t &device, drc_cache &cache, UINT32 flags, int modes, int addrbits, int ignorebits);
	~drcuml_state();

	// getters
	device_t &device() const { return m_device; }
	drc_cache &cache() const { return m_cache; }

	// reset the state
	void reset();
	int execute(uml::code_handle &entry) { return m_beintf.execute(entry); }

	// code generation
	drcuml_block *begin_block(UINT32 maxinst);

	// back-end interface
	void get_backend_info(drcbe_info &info) { m_beintf.get_info(info); }
	bool hash_exists(UINT32 mode, UINT32 pc) { return m_beintf.hash_exists(mode, pc); }
	void generate(drcuml_block &block, uml::instruction *instructions, UINT32 count) { m_beintf.generate(block, instructions, count); }

	// handle management
	uml::code_handle *handle_alloc(const char *name);

	// symbol management
	void symbol_add(void *base, UINT32 length, const char *name);
	const char *symbol_find(void *base, UINT32 *offset = nullptr);

	// logging
	bool logging() const { return (m_umllog != nullptr); }
	void log_printf(const char *format, ...) ATTR_PRINTF(2,3);
	void log_flush() { if (logging()) fflush(m_umllog); }
	bool logging_native() const { return m_beintf.logging(); }

private:
	// symbol class
	class symbol
	{
		friend class drcuml_state;
		friend class simple_list<symbol>;

		// construction/destruction
		symbol(void *base, UINT32 length, const char *name)
			: m_next(nullptr),
				m_base(drccodeptr(base)),
				m_length(length),
				m_name(name) { }

	public:
		// getters
		symbol *next() const { return m_next; }

	private:
		// internal state
		symbol *                m_next;             // link to the next symbol
		drccodeptr              m_base;             // base of the symbol
		UINT32                  m_length;           // length of the region covered
		std::string             m_name;             // name of the symbol
	};

	// internal state
	device_t &                  m_device;           // CPU device we are associated with
	drc_cache &                 m_cache;            // pointer to the codegen cache
	std::unique_ptr<drcbe_interface> m_drcbe_interface;
	drcbe_interface &           m_beintf;           // backend interface pointer
	FILE *                      m_umllog;           // handle to the UML logfile
	simple_list<drcuml_block>   m_blocklist;        // list of active blocks
	simple_list<uml::code_handle> m_handlelist;     // list of active handles
	simple_list<symbol>         m_symlist;          // list of symbols
};



//**************************************************************************
//  MEMBER TEMPLATES
//**************************************************************************

//-------------------------------------------------
//  comment - attach a comment to the current
//  output location in the specified block
//-------------------------------------------------

template <typename Format, typename... Params>
inline void drcuml_block::append_comment(Format &&fmt, Params &&... args)
{
	// do the printf
	std::string temp(util::string_format(std::forward<Format>(fmt), std::forward<Params>(args)...));

	// allocate space in the cache to hold the comment
	char *comment = (char *)m_drcuml.cache().alloc_temporary(temp.length() + 1);
	if (comment != nullptr)
	{
		strcpy(comment, temp.c_str());

		// add an instruction with a pointer
		append().comment(comment);
	}
}


#endif /* __DRCUML_H__ */