summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/sparc/sparcdasm.h
blob: de0b89d3d74d8540148a2cc0f907850830c28fd0 (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
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz, Vas Crabb
/*
    SPARC disassembler
*/

#ifndef MAME_DEVICES_CPU_SPARC_SPARC_DASM_H
#define MAME_DEVICES_CPU_SPARC_SPARC_DASM_H

#pragma once

#include <map>


class sparc_debug_state
{
public:
	virtual uint64_t get_reg_r(unsigned index) const = 0;
	virtual uint64_t get_translated_pc() const = 0;
	virtual uint8_t get_icc() const = 0;
	virtual uint8_t get_xcc() const = 0;
	virtual uint8_t get_fcc(unsigned index) const = 0; // ?><=

protected:
	~sparc_debug_state() { }
};


class sparc_disassembler
{
public:
	enum vis_level { vis_none, vis_1, vis_2, vis_2p, vis_3, vis_3b };

	struct asi_desc
	{
		asi_desc() { }
		asi_desc(const char *name_, const char *desc_) : name(name_), desc(desc_) { }
		const char *name = nullptr;
		const char *desc = nullptr;
	};
	typedef std::map<uint8_t, asi_desc> asi_desc_map;

	struct state_reg_desc
	{
		state_reg_desc() { }
		state_reg_desc(bool reserved_, const char *read_name_, const char *write_name_) : reserved(reserved_), read_name(read_name_), write_name(write_name_) { }
		bool        reserved = false;
		const char  *read_name = nullptr;
		const char  *write_name = nullptr;
	};
	typedef std::map<uint8_t, state_reg_desc> state_reg_desc_map;

	struct prftch_desc
	{
		prftch_desc() { }
		prftch_desc(const char *name_) : name(name_) { }
		const char *name = nullptr;
	};
	typedef std::map<uint8_t, prftch_desc> prftch_desc_map;

	sparc_disassembler(const sparc_debug_state *state, unsigned version);
	sparc_disassembler(const sparc_debug_state *state, unsigned version, vis_level vis);

	template <typename T> void add_state_reg_desc(const T &desc)
	{
		for (const auto &it : desc)
		{
			auto ins = m_state_reg_desc.insert(it);
			if (!ins.second)
			{
				ins.first->second.reserved = it.second.reserved;
				if (it.second.read_name)
					ins.first->second.read_name = it.second.read_name;
				if (it.second.write_name)
					ins.first->second.write_name = it.second.write_name;
			}
		}
	}

	template <typename T> void add_asi_desc(const T &desc)
	{
		// TODO: support ranges
		for (const auto &it : desc)
		{
			auto ins = m_asi_desc.insert(it);
			if (!ins.second)
			{
				if (it.second.name)
					ins.first->second.name = it.second.name;
				if (it.second.desc)
					ins.first->second.desc = it.second.desc;
			}
		}
	}

	template <typename T> void add_prftch_desc(const T &desc)
	{
		for (const auto &it : desc)
		{
			auto ins = m_prftch_desc.insert(it);
			if (!ins.second)
			{
				if (it.second.name)
					ins.first->second.name = it.second.name;
			}
		}
	}

	offs_t dasm(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm(char *buf, offs_t pc, uint32_t op) const;

private:
	struct branch_desc
	{
		int32_t           (*get_disp)(uint32_t op);
		const char *    (*get_comment)(const sparc_debug_state *state, bool use_cc, offs_t pc, uint32_t op);
		int             disp_width;
		bool            use_pred, use_cc;
		const char      *reg_cc[4];
		const char      *mnemonic[16];
	};

	struct int_op_desc
	{
		bool            hex_imm;
		const char      *mnemonic;
		const char      *g0_synth;
	};
	typedef std::map<uint8_t, int_op_desc> int_op_desc_map;

	struct fpop1_desc
	{
		fpop1_desc() { }
		fpop1_desc(bool three_op_, bool rs1_shift_, bool rs2_shift_, bool rd_shift_, const char *mnemonic_) : three_op(three_op_), rs1_shift(rs1_shift_), rs2_shift(rs2_shift_), rd_shift(rd_shift_), mnemonic(mnemonic_) { }
		bool        three_op = true;
		bool        rs1_shift = false;
		bool        rs2_shift = false;
		bool        rd_shift = false;
		const char  *mnemonic = nullptr;
	};
	typedef std::map<uint16_t, fpop1_desc> fpop1_desc_map;

	struct fpop2_desc
	{
		fpop2_desc() { }
		fpop2_desc(bool int_rs1_, bool shift_, const char *mnemonic_) : int_rs1(int_rs1_), shift(shift_), mnemonic(mnemonic_) { }
		bool        int_rs1 = false;
		bool        shift = false;
		const char  *mnemonic = nullptr;
	};
	typedef std::map<uint16_t, fpop2_desc> fpop2_desc_map;

	struct ldst_desc
	{
		ldst_desc() { }
		ldst_desc(bool rd_first_, bool alternate_, char rd_alt_reg_, bool rd_shift_, const char *mnemonic_, const char *g0_synth_) : rd_first(rd_first_), alternate(alternate_), rd_alt_reg(rd_alt_reg_), rd_shift(rd_shift_), mnemonic(mnemonic_), g0_synth(g0_synth_) { }
		bool        rd_first = false;
		bool        alternate = false;
		char        rd_alt_reg = '\0';
		bool        rd_shift = false;
		const char  *mnemonic = nullptr;
		const char  *g0_synth = nullptr;
	};
	typedef std::map<uint8_t, ldst_desc> ldst_desc_map;

	struct vis_op_desc
	{
		enum arg { X, R, Fs, Fd };
		vis_op_desc() { }
		vis_op_desc(arg rs1_, arg rs2_, arg rd_, bool collapse_, const char *mnemonic_) : rs1(rs1_), rs2(rs2_), rd(rd_), collapse(collapse_), mnemonic(mnemonic_) { }
		arg         rs1 = X;
		arg         rs2 = X;
		arg         rd = X;
		bool        collapse = false;
		const char  *mnemonic = nullptr;
	};
	typedef std::map<uint16_t, vis_op_desc> vis_op_desc_map;

	offs_t dasm_invalid(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_branch(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_shift(std::ostream &stream, offs_t pc, uint32_t op, const char *mnemonic, const char *mnemonicx, const char *mnemonicx0) const;
	offs_t dasm_read_state_reg(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_write_state_reg(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_move_cond(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_move_reg_cond(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_fpop1(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_fpop2(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_impdep1(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_jmpl(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_return(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_tcc(std::ostream &stream, offs_t pc, uint32_t op) const;
	offs_t dasm_ldst(std::ostream &stream, offs_t pc, uint32_t op) const;

	void dasm_address(std::ostream &stream, uint32_t op) const;
	void dasm_asi(std::ostream &stream, uint32_t op) const;
	void dasm_asi_comment(std::ostream &stream, uint32_t op) const;
	void dasm_vis_arg(std::ostream &stream, bool &args, vis_op_desc::arg fmt, uint32_t reg) const;

	uint32_t freg(uint32_t val, bool shift) const;

	template <typename T> void add_int_op_desc(const T &desc);
	template <typename T> void add_fpop1_desc(const T &desc);
	template <typename T> void add_fpop2_desc(const T &desc);
	template <typename T> void add_ldst_desc(const T &desc);
	template <typename T> void add_vis_op_desc(const T &desc);

	void pad_op_field(std::ostream &stream, std::streampos start_position) const;

	static const char * const                   REG_NAMES[32];
	static const branch_desc                    EMPTY_BRANCH_DESC;
	static const branch_desc                    BPCC_DESC;
	static const branch_desc                    BICC_DESC;
	static const branch_desc                    BPR_DESC;
	static const branch_desc                    FBPFCC_DESC;
	static const branch_desc                    FBFCC_DESC;
	static const branch_desc                    CBCCC_DESC;
	static const int_op_desc_map::value_type    V7_INT_OP_DESC[];
	static const int_op_desc_map::value_type    V8_INT_OP_DESC[];
	static const int_op_desc_map::value_type    V9_INT_OP_DESC[];
	static const state_reg_desc_map::value_type V9_STATE_REG_DESC[];
	static const char * const                   MOVCC_CC_NAMES[8];
	static const char * const                   MOVCC_COND_NAMES[32];
	static const char * const                   MOVE_INT_COND_MNEMONICS[8];
	static const char * const                   V9_PRIV_REG_NAMES[32];
	static const fpop1_desc_map::value_type     V7_FPOP1_DESC[];
	static const fpop1_desc_map::value_type     V9_FPOP1_DESC[];
	static const fpop2_desc_map::value_type     V7_FPOP2_DESC[];
	static const fpop2_desc_map::value_type     V9_FPOP2_DESC[];
	static const ldst_desc_map::value_type      V7_LDST_DESC[];
	static const ldst_desc_map::value_type      V9_LDST_DESC[];
	static const asi_desc_map::value_type       V9_ASI_DESC[];
	static const prftch_desc_map::value_type    V9_PRFTCH_DESC[];
	static const vis_op_desc_map::value_type    VIS1_OP_DESC[];
	static const state_reg_desc_map::value_type VIS1_STATE_REG_DESC[];
	static const asi_desc_map::value_type       VIS1_ASI_DESC[];
	static const vis_op_desc_map::value_type    VIS2_OP_DESC[];
	static const asi_desc_map::value_type       VIS2P_ASI_DESC[];
	static const fpop1_desc_map::value_type     VIS3_FPOP1_DESC[];
	static const vis_op_desc_map::value_type    VIS3_OP_DESC[];
	static const vis_op_desc_map::value_type    VIS3B_OP_DESC[];

	//const sparc_debug_state *m_state;
	unsigned                m_version;
	vis_level               m_vis_level;
	int                     m_op_field_width;
	branch_desc             m_branch_desc[8];
	int_op_desc_map         m_int_op_desc;
	state_reg_desc_map      m_state_reg_desc;
	fpop1_desc_map          m_fpop1_desc;
	fpop2_desc_map          m_fpop2_desc;
	ldst_desc_map           m_ldst_desc;
	asi_desc_map            m_asi_desc;
	prftch_desc_map         m_prftch_desc;
	vis_op_desc_map         m_vis_op_desc;
};

#endif // MAME_DEVICES_CPU_SPARC_SPARC_DASM_H