summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/i386/i386dasm.h
blob: 25f5ec0d4d6028b216bd5466b2b4db36c246b191 (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
// license:BSD-3-Clause
// copyright-holders:Ville Linde, Peter Ferrie

#ifndef MAME_CPU_I386_I386DASM_H
#define MAME_CPU_I386_I386DASM_H

#pragma once

class i386_disassembler : public util::disasm_interface
{
public:
	class config {
	public:
		virtual ~config() = default;
		virtual int get_mode() const = 0;
	};

	i386_disassembler(config *conf);

	virtual u32 opcode_alignment() const override;
	virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;

private:
	enum
	{
		PARAM_REG = 1,      /* 16 or 32-bit register */
		PARAM_REG8,         /* 8-bit register */
		PARAM_REG16,        /* 16-bit register */
		PARAM_REG32,        /* 32-bit register */
		PARAM_REG3264,      /* 32-bit or 64-bit register */
		PARAM_REG2_32,      /* 32-bit register */
		PARAM_MMX,          /* MMX register */
		PARAM_MMX2,         /* MMX register in modrm */
		PARAM_XMM,          /* XMM register */
		PARAM_RM,           /* 16 or 32-bit memory or register */
		PARAM_RM8,          /* 8-bit memory or register */
		PARAM_RM16,         /* 16-bit memory or register */
		PARAM_RM32,         /* 32-bit memory or register */
		PARAM_RMPTR,        /* 16 or 32-bit memory or register */
		PARAM_RMPTR8,       /* 8-bit memory or register */
		PARAM_RMPTR16,      /* 16-bit memory or register */
		PARAM_RMPTR32,      /* 32-bit memory or register */
		PARAM_RMXMM,        /* 32 or 64-bit memory or register */
		PARAM_REGORXMM,     /* 32 or 64-bit register or XMM register */
		PARAM_M64,          /* 64-bit memory */
		PARAM_M64PTR,       /* 64-bit memory */
		PARAM_MMXM,         /* 64-bit memory or MMX register */
		PARAM_XMMM,         /* 128-bit memory or XMM register */
		PARAM_I4,           /* 4-bit signed immediate */
		PARAM_I8,           /* 8-bit signed immediate */
		PARAM_I16,          /* 16-bit signed immediate */
		PARAM_UI8,          /* 8-bit unsigned immediate */
		PARAM_UI16,         /* 16-bit unsigned immediate */
		PARAM_IMM,          /* 16 or 32-bit immediate */
		PARAM_IMM64,        /* 16, 32 or 64-bit immediate */
		PARAM_ADDR,         /* 16:16 or 16:32 address */
		PARAM_REL,          /* 16 or 32-bit PC-relative displacement */
		PARAM_REL8,         /* 8-bit PC-relative displacement */
		PARAM_MEM_OFFS,     /* 16 or 32-bit mem offset */
		PARAM_PREIMP,       /* prefix with implicit register */
		PARAM_SREG,         /* segment register */
		PARAM_CREG,         /* control register */
		PARAM_DREG,         /* debug register */
		PARAM_TREG,         /* test register */
		PARAM_1,            /* used by shift/rotate instructions */
		PARAM_AL,
		PARAM_CL,
		PARAM_DL,
		PARAM_BL,
		PARAM_AH,
		PARAM_CH,
		PARAM_DH,
		PARAM_BH,
		PARAM_DX,
		PARAM_EAX,          /* EAX or AX */
		PARAM_ECX,          /* ECX or CX */
		PARAM_EDX,          /* EDX or DX */
		PARAM_EBX,          /* EBX or BX */
		PARAM_ESP,          /* ESP or SP */
		PARAM_EBP,          /* EBP or BP */
		PARAM_ESI,          /* ESI or SI */
		PARAM_EDI,          /* EDI or DI */
		PARAM_XMM0,
		PARAM_XMM64,            /* 64-bit memory or XMM register */
		PARAM_XMM32,            /* 32-bit memory or XMM register */
		PARAM_XMM16             /* 16-bit memory or XMM register */
	};

	enum
	{
		MODRM = 1,
		GROUP,
		FPU,
		OP_SIZE,
		ADDR_SIZE,
		TWO_BYTE,
		PREFIX,
		SEG_CS,
		SEG_DS,
		SEG_ES,
		SEG_FS,
		SEG_GS,
		SEG_SS,
		ISREX,
		THREE_BYTE          /* [prefix] 0f op1 op2 and then mod/rm */
	};

	enum {
		FLAGS_MASK =         0x0ff,
		VAR_NAME   =         0x100,
		VAR_NAME4  =         0x200,
		ALWAYS64   =         0x400,
		SPECIAL64  =         0x800,
		GROUP_MOD  =        0x1000
	};

	struct I386_OPCODE {
		const char *mnemonic;
		u32 flags;
		u32 param1;
		u32 param2;
		u32 param3;
		offs_t dasm_flags;
	};

	struct GROUP_OP {
		char mnemonic[32];
		const I386_OPCODE *opcode;
	};

	static constexpr u32 SPECIAL64_ENT(u32 x) {
		return SPECIAL64 | (x << 24);
	}

	static const I386_OPCODE i386_opcode_table1[256];
	static const I386_OPCODE x64_opcode_alt[];
	static const I386_OPCODE i386_opcode_table2[256];
	static const I386_OPCODE i386_opcode_table0F38[256];
	static const I386_OPCODE i386_opcode_table0F3A[256];
	static const I386_OPCODE group80_table[8];
	static const I386_OPCODE group81_table[8];
	static const I386_OPCODE group83_table[8];
	static const I386_OPCODE groupC0_table[8];
	static const I386_OPCODE groupC1_table[8];
	static const I386_OPCODE groupD0_table[8];
	static const I386_OPCODE groupD1_table[8];
	static const I386_OPCODE groupD2_table[8];
	static const I386_OPCODE groupD3_table[8];
	static const I386_OPCODE groupF6_table[8];
	static const I386_OPCODE groupF7_table[8];
	static const I386_OPCODE groupFE_table[8];
	static const I386_OPCODE groupFF_table[8];
	static const I386_OPCODE group0F00_table[8];
	static const I386_OPCODE group0F01_table[8];
	static const I386_OPCODE group0F0D_table[8];
	static const I386_OPCODE group0F12_table[4];
	static const I386_OPCODE group0F16_table[4];
	static const I386_OPCODE group0F18_table[8];
	static const I386_OPCODE group0F71_table[8];
	static const I386_OPCODE group0F72_table[8];
	static const I386_OPCODE group0F73_table[8];
	static const I386_OPCODE group0FAE_table[8];
	static const I386_OPCODE group0FBA_table[8];
	static const I386_OPCODE group0FC7_table[8];
	static const GROUP_OP group_op_table[];
	static const char *const i386_reg[3][16];
	static const char *const i386_reg8[8];
	static const char *const i386_reg8rex[16];
	static const char *const i386_sreg[8];

	config *m_config;

	int address_size;
	int operand_size;
	int address_prefix;
	int operand_prefix;
	int max_length;
	uint8_t modrm;
	uint32_t segment;
	offs_t dasm_flags;
	std::string modrm_string;
	uint8_t rex, regex, sibex, rmex;
	uint8_t pre0f;

	inline u8 MODRM_REG1() const {
		return (modrm >> 3) & 0x7;
	}

	inline u8 MODRM_REG2() const {
		return modrm & 0x7;
	}

	inline u8 MODRM_MOD() const {
		return (modrm >> 6) & 0x7;
	}

	inline uint8_t FETCH(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	inline uint16_t FETCH16(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	inline uint32_t FETCH32(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	inline uint8_t FETCHD(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	inline uint16_t FETCHD16(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	inline uint32_t FETCHD32(offs_t base_pc, offs_t &pc, const data_buffer &opcodes);

	char *hexstring(uint32_t value, int digits);
	char *hexstring64(uint32_t lo, uint32_t hi);
	char *hexstringpc(uint64_t pc);
	char *shexstring(uint32_t value, int digits, bool always);
	void handle_sib_byte(std::ostream &stream, uint8_t mod, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	void handle_modrm(std::ostream &stream, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	void handle_modrm(std::string &buffer, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	void handle_param(std::ostream &stream, uint32_t param, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	void handle_fpu(std::ostream &stream, uint8_t op1, uint8_t op2, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
	void decode_opcode(std::ostream &stream, const I386_OPCODE *op, uint8_t op1, offs_t base_pc, offs_t &pc, const data_buffer &opcodes);
};

#endif