summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/drcuml.h
blob: 5bb4bb04ae419d2b89f67eed885ca79022a1c8f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    drcuml.h

    Universal machine language for dynamic recompiling CPU cores.

***************************************************************************/
#ifndef MAME_CPU_DRCUML_H
#define MAME_CPU_DRCUML_H

#pragma once

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

#include <iostream>
#include <list>
#include <memory>
#include <vector>


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

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



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

// opaque structure describing UML generation state
class drcuml_state;


// an integer register, with low/high parts
union drcuml_ireg
{
#ifdef LSB_FIRST
	struct { u32 l, h; }    w;                      // 32-bit low, high parts of the register
#else
	struct { u32 h, l; }    w;                      // 32-bit low, high parts of the register
#endif
	u64                     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
	u32                     exp;                    // exception parameter register
	u8                      fmod;                   // fmod (floating-point mode) register
	u8                      flags;                  // flags state
};


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


// a drcuml_block describes a basic block of instructions
class drcuml_block
{
public:
	// construction/destruction
	drcuml_block(drcuml_state &drcuml, u32 maxinst);
	drcuml_block(drcuml_block const &) = delete;
	drcuml_block &operator=(drcuml_block const &) = delete;
	~drcuml_block();

	// getters
	bool inuse() const { return m_inuse; }
	u32 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();
	char const *get_comment_text(uml::instruction const &inst, std::string &comment);

	// internal state
	drcuml_state &                  m_drcuml;   // pointer back to the owning UML
	u32                             m_nextinst; // next instruction to fill in the cache
	u32                             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:
	// allow deleting through base pointer
	virtual ~drcbe_interface();

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

protected:
	// base constructor
	drcbe_interface(drcuml_state &drcuml, drc_cache &cache, device_t &device);

	// 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
	std::vector<address_space *>    m_space;       // 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, u32 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(u32 maxinst);

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

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

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

	// logging
	bool logging() const { return bool(m_umllog); }
	template <typename Format, typename... Params>
	void log_printf(Format &&fmt, Params &&...args)
	{
		log_vprintf(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
	}
	void log_vprintf(util::format_argument_pack<std::ostream> const &args);
	void log_flush() { if (logging()) m_umllog->flush(); }
	bool logging_native() const { return m_beintf->logging(); }

private:
	// symbol class
	class symbol
	{
	public:
		// construction/destruction
		symbol(void *base, u32 length, char const *name)
			: m_base(reinterpret_cast<drccodeptr>(base))
			, m_length(length)
			, m_name(name)
		{ }

		// getters
		bool includes(drccodeptr search) const { return (m_base <= search) && ((m_base + m_length) > search); }
		drccodeptr base() const { return m_base; }
		std::string const &name() const { return m_name; }

	private:
		// internal state
		drccodeptr  m_base;     // base of the symbol
		u32         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> const  m_beintf;           // backend interface pointer
	std::unique_ptr<std::ostream> const     m_umllog;           // handle to the UML logfile
	std::list<drcuml_block>                 m_blocklist;        // list of active blocks
	std::list<uml::code_handle>             m_handlelist;       // list of active handles
	std::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 const temp(util::string_format(std::forward<Format>(fmt), std::forward<Params>(args)...));

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

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


#endif // MAME_CPU_DRCUML_H