summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/drcbex86.h
blob: ef1bf57f0100193da8cdda232610903141590287 (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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    drcbex86.h

    32-bit x86 back-end for the universal machine language.

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

#pragma once

#ifndef __DRCBEX86_H__
#define __DRCBEX86_H__

#include "drcuml.h"
#include "drcbeut.h"
#include "x86log.h"

#define X86EMIT_SIZE 32
#include "x86emit.h"



namespace drc {
//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

class drcbe_x86 : public drcbe_interface
{
	typedef uint32_t (*x86_entry_point_func)(x86code *entry);

public:
	// construction/destruction
	drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
	virtual ~drcbe_x86();

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

private:
	// a be_parameter is similar to a uml::parameter but maps to native registers/memory
	class be_parameter
	{
	public:
		// parameter types
		enum be_parameter_type
		{
			PTYPE_NONE = 0,                     // invalid
			PTYPE_IMMEDIATE,                    // immediate; value = sign-extended to 64 bits
			PTYPE_INT_REGISTER,                 // integer register; value = 0-REG_MAX
			PTYPE_FLOAT_REGISTER,               // floating point register; value = 0-REG_MAX
			PTYPE_VECTOR_REGISTER,              // vector register; value = 0-REG_MAX
			PTYPE_MEMORY,                       // memory; value = pointer to memory
			PTYPE_MAX
		};

		// represents the value of a parameter
		typedef uint64_t be_parameter_value;

		// construction
		be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
		be_parameter(const be_parameter &param) : m_type(param.m_type), m_value(param.m_value) { }
		be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
		be_parameter(drcbe_x86 &drcbe, const uml::parameter &param, uint32_t allowed);

		// creators for types that don't safely default
		static inline be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
		static inline be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
		static inline be_parameter make_vreg(int regnum) { assert(regnum >= 0 && regnum < x86emit::REG_MAX); return be_parameter(PTYPE_VECTOR_REGISTER, regnum); }
		static inline be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
		static inline be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }

		// operators
		bool operator==(const be_parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
		bool operator!=(const be_parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }

		// getters
		be_parameter_type type() const { return m_type; }
		uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
		int ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; }
		int freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; }
		int vreg() const { assert(m_type == PTYPE_VECTOR_REGISTER); assert(m_value < x86emit::REG_MAX); return m_value; }
		void *memory(uint32_t offset = 0) const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value + offset); }

		// type queries
		bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
		bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
		bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
		bool is_vector_register() const { return (m_type == PTYPE_VECTOR_REGISTER); }
		bool is_memory() const { return (m_type == PTYPE_MEMORY); }

		// other queries
		bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }

		// helpers
		int select_register(int defreg) const;
		int select_register(int defreg, const be_parameter &checkparam) const;
		int select_register(int defreg, const be_parameter &checkparam, const be_parameter &checkparam2) const;

	private:
		// private constructor
		be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }

		// internals
		be_parameter_type   m_type;             // parameter type
		be_parameter_value  m_value;            // parameter value
	};

	// helpers
	void normalize_commutative(be_parameter &inner, be_parameter &outer);
	void emit_combine_z_flags(x86code *&dst);
	void emit_combine_z_shl_flags(x86code *&dst);
	void reset_last_upper_lower_reg();
	void set_last_lower_reg(x86code *&dst, const be_parameter &param, uint8_t reglo);
	void set_last_upper_reg(x86code *&dst, const be_parameter &param, uint8_t reghi);
	bool can_skip_lower_load(x86code *&dst, uint32_t *memref, uint8_t reglo);
	bool can_skip_upper_load(x86code *&dst, uint32_t *memref, uint8_t reghi);
	void track_resolve_link(x86code *&destptr, const emit_link &linkinfo);

	void fixup_label(void *parameter, drccodeptr labelcodeptr);
	void fixup_exception(drccodeptr *codeptr, void *param1, void *param2);

	static void debug_log_hashjmp(int mode, offs_t pc);

	// code generators
	void op_handle(x86code *&dst, const uml::instruction &inst);
	void op_hash(x86code *&dst, const uml::instruction &inst);
	void op_label(x86code *&dst, const uml::instruction &inst);
	void op_comment(x86code *&dst, const uml::instruction &inst);
	void op_mapvar(x86code *&dst, const uml::instruction &inst);

	void op_nop(x86code *&dst, const uml::instruction &inst);
	void op_debug(x86code *&dst, const uml::instruction &inst);
	void op_exit(x86code *&dst, const uml::instruction &inst);
	void op_hashjmp(x86code *&dst, const uml::instruction &inst);
	void op_jmp(x86code *&dst, const uml::instruction &inst);
	void op_exh(x86code *&dst, const uml::instruction &inst);
	void op_callh(x86code *&dst, const uml::instruction &inst);
	void op_ret(x86code *&dst, const uml::instruction &inst);
	void op_callc(x86code *&dst, const uml::instruction &inst);
	void op_recover(x86code *&dst, const uml::instruction &inst);

	void op_setfmod(x86code *&dst, const uml::instruction &inst);
	void op_getfmod(x86code *&dst, const uml::instruction &inst);
	void op_getexp(x86code *&dst, const uml::instruction &inst);
	void op_getflgs(x86code *&dst, const uml::instruction &inst);
	void op_save(x86code *&dst, const uml::instruction &inst);
	void op_restore(x86code *&dst, const uml::instruction &inst);

	void op_load(x86code *&dst, const uml::instruction &inst);
	void op_loads(x86code *&dst, const uml::instruction &inst);
	void op_store(x86code *&dst, const uml::instruction &inst);
	void op_read(x86code *&dst, const uml::instruction &inst);
	void op_readm(x86code *&dst, const uml::instruction &inst);
	void op_write(x86code *&dst, const uml::instruction &inst);
	void op_writem(x86code *&dst, const uml::instruction &inst);
	void op_carry(x86code *&dst, const uml::instruction &inst);
	void op_set(x86code *&dst, const uml::instruction &inst);
	void op_mov(x86code *&dst, const uml::instruction &inst);
	void op_sext(x86code *&dst, const uml::instruction &inst);
	void op_roland(x86code *&dst, const uml::instruction &inst);
	void op_rolins(x86code *&dst, const uml::instruction &inst);
	void op_add(x86code *&dst, const uml::instruction &inst);
	void op_addc(x86code *&dst, const uml::instruction &inst);
	void op_sub(x86code *&dst, const uml::instruction &inst);
	void op_subc(x86code *&dst, const uml::instruction &inst);
	void op_cmp(x86code *&dst, const uml::instruction &inst);
	void op_mulu(x86code *&dst, const uml::instruction &inst);
	void op_muls(x86code *&dst, const uml::instruction &inst);
	void op_divu(x86code *&dst, const uml::instruction &inst);
	void op_divs(x86code *&dst, const uml::instruction &inst);
	void op_and(x86code *&dst, const uml::instruction &inst);
	void op_test(x86code *&dst, const uml::instruction &inst);
	void op_or(x86code *&dst, const uml::instruction &inst);
	void op_xor(x86code *&dst, const uml::instruction &inst);
	void op_lzcnt(x86code *&dst, const uml::instruction &inst);
	void op_tzcnt(x86code *&dst, const uml::instruction &inst);
	void op_bswap(x86code *&dst, const uml::instruction &inst);
	void op_shl(x86code *&dst, const uml::instruction &inst);
	void op_shr(x86code *&dst, const uml::instruction &inst);
	void op_sar(x86code *&dst, const uml::instruction &inst);
	void op_ror(x86code *&dst, const uml::instruction &inst);
	void op_rol(x86code *&dst, const uml::instruction &inst);
	void op_rorc(x86code *&dst, const uml::instruction &inst);
	void op_rolc(x86code *&dst, const uml::instruction &inst);

	void op_fload(x86code *&dst, const uml::instruction &inst);
	void op_fstore(x86code *&dst, const uml::instruction &inst);
	void op_fread(x86code *&dst, const uml::instruction &inst);
	void op_fwrite(x86code *&dst, const uml::instruction &inst);
	void op_fmov(x86code *&dst, const uml::instruction &inst);
	void op_ftoint(x86code *&dst, const uml::instruction &inst);
	void op_ffrint(x86code *&dst, const uml::instruction &inst);
	void op_ffrflt(x86code *&dst, const uml::instruction &inst);
	void op_frnds(x86code *&dst, const uml::instruction &inst);
	void op_fadd(x86code *&dst, const uml::instruction &inst);
	void op_fsub(x86code *&dst, const uml::instruction &inst);
	void op_fcmp(x86code *&dst, const uml::instruction &inst);
	void op_fmul(x86code *&dst, const uml::instruction &inst);
	void op_fdiv(x86code *&dst, const uml::instruction &inst);
	void op_fneg(x86code *&dst, const uml::instruction &inst);
	void op_fabs(x86code *&dst, const uml::instruction &inst);
	void op_fsqrt(x86code *&dst, const uml::instruction &inst);
	void op_frecip(x86code *&dst, const uml::instruction &inst);
	void op_frsqrt(x86code *&dst, const uml::instruction &inst);
	void op_fcopyi(x86code *&dst, const uml::instruction &inst);
	void op_icopyf(x86code *&dst, const uml::instruction &inst);

	// 32-bit code emission helpers
	void emit_mov_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param);
	void emit_mov_r32_p32_keepflags(x86code *&dst, uint8_t reg, const be_parameter &param);
	void emit_mov_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param);
	void emit_mov_p32_r32(x86code *&dst, const be_parameter &param, uint8_t reg);
	void emit_add_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_add_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_adc_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_adc_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_sub_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_sub_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_sbb_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_sbb_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_cmp_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_cmp_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_and_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_and_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_test_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_test_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_or_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_or_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_xor_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_xor_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_shl_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_shl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_shr_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_shr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_sar_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_sar_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_rol_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_rol_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_ror_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_ror_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_rcl_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_rcl_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_rcr_r32_p32(x86code *&dst, uint8_t reg, const be_parameter &param, const uml::instruction &inst);
	void emit_rcr_m32_p32(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);

	// 64-bit code emission helpers
	void emit_mov_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param);
	void emit_mov_r64_p64_keepflags(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param);
	void emit_mov_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param);
	void emit_mov_p64_r64(x86code *&dst, const be_parameter &param, uint8_t reglo, uint8_t reghi);
	void emit_add_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_add_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_adc_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_adc_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_sub_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_sub_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_sbb_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_sbb_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_cmp_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_and_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_and_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_test_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_test_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_or_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_or_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_xor_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_xor_m64_p64(x86code *&dst, x86_memref memref, const be_parameter &param, const uml::instruction &inst);
	void emit_shl_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_shr_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_sar_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_rol_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_ror_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_rcl_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);
	void emit_rcr_r64_p64(x86code *&dst, uint8_t reglo, uint8_t reghi, const be_parameter &param, const uml::instruction &inst);

	// floating-point code emission helpers
	void emit_fld_p(x86code *&dst, int size, const be_parameter &param);
	void emit_fstp_p(x86code *&dst, int size, const be_parameter &param);

	// callback helpers
	static int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags);
	static int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags);
	static int ddivu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2);
	static int ddivs(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2);

	// internal state
	drc_hash_table          m_hash;                 // hash table state
	drc_map_variables       m_map;                  // code map
	drc_label_list          m_labels;               // label list
	x86log_context *        m_log;                  // logging
	bool                    m_logged_common;        // logged common code already?
	bool                    m_sse3;                 // do we have SSE3 support?

	x86_entry_point_func    m_entry;                // entry point
	x86code *               m_exit;                 // exit point
	x86code *               m_nocode;               // nocode handler
	x86code *               m_save;                 // save handler
	x86code *               m_restore;              // restore handler

	uint32_t *                m_reglo[x86emit::REG_MAX];// pointer to low part of data for each register
	uint32_t *                m_reghi[x86emit::REG_MAX];// pointer to high part of data for each register
	uint8_t                   m_last_lower_reg;       // last register we stored a lower from
	x86code *               m_last_lower_pc;        // PC after instruction where we last stored a lower register
	uint32_t *                m_last_lower_addr;      // address where we last stored an lower register
	uint8_t                   m_last_upper_reg;       // last register we stored an upper from
	x86code *               m_last_upper_pc;        // PC after instruction where we last stored an upper register
	uint32_t *                m_last_upper_addr;      // address where we last stored an upper register
	double                  m_fptemp;               // temporary storage for floating point

	uint16_t                  m_fpumode;              // saved FPU mode
	uint16_t                  m_fmodesave;            // temporary location for saving

	void *                  m_stacksave;            // saved stack pointer
	void *                  m_hashstacksave;        // saved stack pointer for hashjmp
	uint64_t                  m_reslo;                // extended low result
	uint64_t                  m_reshi;                // extended high result

	drc_label_fixup_delegate m_fixup_label;         // precomputed delegate for fixups
	drc_oob_delegate        m_fixup_exception;      // precomputed delegate for exception fixups

	// globals
	typedef void (drcbe_x86::*opcode_generate_func)(x86code *&dst, const uml::instruction &inst);
	struct opcode_table_entry
	{
		uml::opcode_t           opcode;             // opcode in question
		opcode_generate_func    func;               // function pointer to the work
	};
	static const opcode_table_entry s_opcode_table_source[];
	static opcode_generate_func s_opcode_table[uml::OP_MAX];
};

} // namespace drc

using drc::drcbe_x86;

#endif /* __DRCBEX86_H__ */