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
|
// 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)
};
// 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<char> 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
|