1 // license:BSD-3-Clause
2 // copyright-holders:Jason Eckhardt
3 /***************************************************************************
4 
5     i860dis.c
6 
7     Disassembler for the Intel i860 emulator.
8 
9     Copyright (C) 1995-present Jason Eckhardt (jle@rice.edu)
10 
11 ***************************************************************************/
12 
13 #include "emu.h"
14 #include "i860dis.h"
15 
16 /* Macros for accessing register fields in instruction word.  */
17 #define get_isrc1(bits) (((bits) >> 11) & 0x1f)
18 #define get_isrc2(bits) (((bits) >> 21) & 0x1f)
19 #define get_idest(bits) (((bits) >> 16) & 0x1f)
20 #define get_fsrc1(bits) (((bits) >> 11) & 0x1f)
21 #define get_fsrc2(bits) (((bits) >> 21) & 0x1f)
22 #define get_fdest(bits) (((bits) >> 16) & 0x1f)
23 #define get_creg(bits)  (((bits) >> 21) & 0x7)
24 
25 /* Macros for accessing immediate fields.  */
26 /* 16-bit immediate.  */
27 #define get_imm16(insn) ((insn) & 0xffff)
28 
29 
30 /* Control register names.  */
31 const char *const i860_disassembler::cr2str[] =
32 	{"fir", "psr", "dirbase", "db", "fsr", "epsr", "!", "!"};
33 
34 
35 /* Sign extend N-bit number.  */
sign_ext(uint32_t x,int n)36 int32_t i860_disassembler::sign_ext(uint32_t x, int n)
37 {
38 	int32_t t;
39 	t = x >> (n - 1);
40 	t = ((-t) << n) | x;
41 	return t;
42 }
43 
44 
45 /* Basic integer 3-address register format:
46  *   mnemonic %rs1,%rs2,%rd  */
int_12d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)47 void i860_disassembler::int_12d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
48 {
49 	/* Possibly prefix shrd with 'd.' */
50 	if (((insn & 0xfc000000) == 0xb0000000) && (insn & 0x200))
51 		util::stream_format(stream, "d.%s\t%%r%d,%%r%d,%%r%d", mnemonic,
52 			get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
53 	else
54 		util::stream_format(stream, "%s\t%%r%d,%%r%d,%%r%d", mnemonic,
55 			get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
56 }
57 
58 
59 /* Basic integer 3-address imm16 format:
60  *   mnemonic #imm16,%rs2,%rd  */
int_i2d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)61 void i860_disassembler::int_i2d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
62 {
63 	/* Sign extend the 16-bit immediate.
64 	   Print as hex for the bitwise operations.  */
65 	int upper_6bits = (insn >> 26) & 0x3f;
66 	if (upper_6bits >= 0x30 && upper_6bits <= 0x3f)
67 		util::stream_format(stream, "%s\t0x%04x,%%r%d,%%r%d", mnemonic,
68 			(uint32_t)(get_imm16 (insn)), get_isrc2 (insn), get_idest (insn));
69 	else
70 		util::stream_format(stream, "%s\t%d,%%r%d,%%r%d", mnemonic,
71 			sign_ext(get_imm16 (insn), 16), get_isrc2 (insn), get_idest (insn));
72 }
73 
74 
75 /* Integer (mixed) 2-address  isrc1ni,fdest.  */
int_1d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)76 void i860_disassembler::int_1d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
77 {
78 	util::stream_format(stream, "%s\t%%r%d,%%f%d", mnemonic, get_isrc1 (insn), get_fdest (insn));
79 }
80 
81 
82 /* Integer (mixed) 2-address  csrc2,idest.  */
int_cd(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)83 void i860_disassembler::int_cd(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
84 {
85 	util::stream_format(stream, "%s\t%%%s,%%r%d", mnemonic, cr2str[get_creg (insn)], get_idest (insn));
86 }
87 
88 
89 /* Integer (mixed) 2-address  isrc1,csrc2.  */
int_1c(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)90 void i860_disassembler::int_1c(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
91 {
92 	util::stream_format(stream, "%s\t%%r%d,%%%s", mnemonic, get_isrc1(insn), cr2str[get_creg (insn)]);
93 }
94 
95 
96 /* Integer 1-address register format:
97  *   mnemonic %rs1  */
int_1(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)98 void i860_disassembler::int_1(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
99 {
100 	util::stream_format(stream, "%s\t%%r%d", mnemonic, get_isrc1 (insn));
101 }
102 
103 
104 /* Integer no-address register format:
105  *   mnemonic  */
int_0(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)106 void i860_disassembler::int_0(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
107 {
108 	util::stream_format(stream, "%s", mnemonic);
109 }
110 
111 
112 /* Basic floating-point 3-address register format:
113  *   mnemonic %fs1,%fs2,%fd  */
flop_12d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)114 void i860_disassembler::flop_12d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
115 {
116 	char newname[256];
117 	const char *const suffix[4] = { "ss", "sd", "ds", "dd" };
118 	const char *prefix_d, *prefix_p;
119 	prefix_p = (insn & 0x400) ? "p" : "";
120 	prefix_d = (insn & 0x200) ? "d." : "";
121 
122 	/* Special case: pf[m]am and pf[m]sm families are always pipelined, so they
123 	   do not have a prefix.  Also, for the pfmam and pfmsm families, replace
124 	   any 'a' in the mnemonic with 'm' and prepend an 'm'.  */
125 	if ((insn & 0x7f) < 0x20)
126 	{
127 		int is_pfam = insn & 0x400;
128 		if (!is_pfam)
129 		{
130 			char *op = mnemonic;
131 			char *np = newname + 1;
132 			newname[0] = 'm';
133 			while (*op)
134 			{
135 				if (*op == 'a')
136 					*np = 'm';
137 				else
138 					*np = *op;
139 				np++;
140 				op++;
141 			}
142 			*np = 0;
143 			mnemonic = newname;
144 		}
145 		prefix_p = "";
146 	}
147 
148 	/* Special case: pfgt/pfle-- R-bit distinguishes the two.  */
149 	if ((insn & 0x7f) == 0x34)
150 	{
151 		const char *const mn[2] = { "fgt.", "fle." };
152 		int r = (insn & 0x080) >> 7;
153 		int s = (insn & 0x100) ? 3 : 0;
154 		util::stream_format(stream, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mn[r],
155 			suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn));
156 	}
157 	else
158 	{
159 		int s = (insn & 0x180) >> 7;
160 		util::stream_format(stream, "%s%s%s%s\t%%f%d,%%f%d,%%f%d", prefix_d, prefix_p, mnemonic,
161 			suffix[s], get_fsrc1 (insn), get_fsrc2 (insn), get_fdest (insn));
162 	}
163 }
164 
165 
166 /* Floating-point 2-address register format:
167  *   mnemonic %fs1,%fd  */
flop_1d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)168 void i860_disassembler::flop_1d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
169 {
170 	const char *const suffix[4] = { "ss", "sd", "ds", "dd" };
171 	const char *prefix_d, *prefix_p;
172 	int s = (insn & 0x180) >> 7;
173 	prefix_p = (insn & 0x400) ? "p" : "";
174 	prefix_d = (insn & 0x200) ? "d." : "";
175 	util::stream_format(stream, "%s%s%s%s\t%%f%d,%%f%d", prefix_d, prefix_p, mnemonic,
176 		suffix[s], get_fsrc1 (insn), get_fdest (insn));
177 }
178 
179 
180 /* Floating-point 2-address register format:
181  *   mnemonic %fs2,%fd  */
flop_2d(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)182 void i860_disassembler::flop_2d(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
183 {
184 	const char *const suffix[4] = { "ss", "sd", "ds", "dd" };
185 	const char *prefix_d;
186 	int s = (insn & 0x180) >> 7;
187 	prefix_d = (insn & 0x200) ? "d." : "";
188 	util::stream_format(stream, "%s%s%s\t%%f%d,%%f%d", prefix_d, mnemonic, suffix[s],
189 		get_fsrc2 (insn), get_fdest (insn));
190 }
191 
192 
193 /* Floating-point (mixed) 2-address register format:
194  *  fxfr fsrc1,idest.  */
flop_fxfr(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)195 void i860_disassembler::flop_fxfr(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
196 {
197 	const char *prefix_d = (insn & 0x200) ? "d." : "";
198 	util::stream_format(stream, "%s%s\t%%f%d,%%r%d", prefix_d, mnemonic, get_fsrc1 (insn),
199 		get_idest (insn));
200 }
201 
202 
203 /* Branch with reg,reg,sbroff format:
204  *   mnemonic %rs1,%rs2,sbroff  */
int_12S(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)205 void i860_disassembler::int_12S(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
206 {
207 	int32_t sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
208 	int32_t rel = (int32_t)pc + (sbroff << 2) + 4;
209 
210 	util::stream_format(stream, "%s\t%%r%d,%%r%d,0x%08x", mnemonic, get_isrc1 (insn),
211 		get_isrc2 (insn), (uint32_t)rel);
212 }
213 
214 
215 /* Branch with #const5,reg,sbroff format:
216  *   mnemonic #const5,%rs2,sbroff  */
int_i2S(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)217 void i860_disassembler::int_i2S(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
218 {
219 	int32_t sbroff = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
220 	int32_t rel = (int32_t)pc + (sbroff << 2) + 4;
221 
222 	util::stream_format(stream, "%s\t%d,%%r%d,0x%08x", mnemonic, ((insn >> 11) & 0x1f),
223 		get_isrc2 (insn), (uint32_t)rel);
224 }
225 
226 
227 /* Branch with lbroff format:
228  *   mnemonic lbroff  */
int_L(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)229 void i860_disassembler::int_L(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
230 {
231 	int32_t lbroff =  sign_ext ((insn & 0x03ffffff), 26);
232 	int32_t rel = (int32_t)pc + (lbroff << 2) + 4;
233 
234 	util::stream_format(stream, "%s\t0x%08x", mnemonic, (uint32_t)rel);
235 }
236 
237 
238 /* Integer load.
239  *  ld.{b,s,l} isrc1(isrc2),idest
240  *  ld.{b,s,l} #const(isrc2),idest  */
int_ldx(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)241 void i860_disassembler::int_ldx(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
242 {
243 	/* Operand size, in bytes.  */
244 	int sizes[4] = { 1, 1, 2, 4 };
245 	const char *const suffix[4] = { "b", "b", "s", "l" };
246 	uint32_t idx;
247 
248 	/* Bits 28 and 0 determine the operand size.  */
249 	idx = ((insn >> 27) & 2) | (insn & 1);
250 
251 	/* Bit 26 determines the addressing mode (reg+reg or disp+reg).  */
252 	if (insn & 0x04000000)
253 	{
254 		/* Chop off lower bits of displacement.  */
255 		int32_t immsrc1 = sign_ext (get_imm16 (insn), 16);
256 		int size = sizes[idx];
257 		immsrc1 &= ~(size - 1);
258 		util::stream_format(stream, "%s%s\t%d(%%r%d),%%r%d", mnemonic, suffix[idx],
259 			immsrc1, get_isrc2 (insn), get_idest (insn));
260 	}
261 	else
262 		util::stream_format(stream, "%s%s\t%%r%d(%%r%d),%%r%d", mnemonic, suffix[idx],
263 			get_isrc1 (insn), get_isrc2 (insn), get_idest (insn));
264 }
265 
266 
267 /* Integer store: st.b isrc1ni,#const(isrc2)  */
int_stx(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)268 void i860_disassembler::int_stx(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
269 {
270 	/* Operand size, in bytes.  */
271 	int sizes[4] = { 1, 1, 2, 4 };
272 	const char *const suffix[4] = { "b", "b", "s", "l" };
273 	int idx;
274 	int size;
275 	int32_t immsrc = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16);
276 
277 	/* Bits 28 and 0 determine the operand size.  */
278 	idx = ((insn >> 27) & 2) | (insn & 1);
279 
280 	/* Chop off lower bits of displacement.  */
281 	size = sizes[idx];
282 	immsrc &= ~(size - 1);
283 	util::stream_format(stream, "%s%s\t%%r%d,%d(%%r%d)", mnemonic, suffix[idx],
284 		get_isrc1 (insn), immsrc, get_isrc2 (insn));
285 }
286 
287 
288 /* Disassemble:
289  *  "[p]fld.y isrc1(isrc2),fdest", "[p]fld.y isrc1(isrc2)++,idest",
290  *  "[p]fld.y #const(isrc2),fdest" or "[p]fld.y #const(isrc2)++,idest".
291  *  "fst.y fdest,isrc1(isrc2)", "fst.y fdest,isrc1(isrc2)++",
292  *  "fst.y fdest,#const(isrc2)" or "fst.y fdest,#const(isrc2)++"
293  *  Where y = {l,d,q}.  Note, there is no pfld.q, though.  */
int_fldst(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)294 void i860_disassembler::int_fldst(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
295 {
296 	int32_t immsrc1 = sign_ext (get_imm16 (insn), 16);
297 	/* Operand size, in bytes.  */
298 	int sizes[4] = { 8, 4, 16, 4 };
299 	const char *const suffix[4] = { "d", "l", "q", "l" };
300 	int idx;
301 	int size;
302 	int auto_inc = (insn & 1);
303 	const char *const auto_suff[2] = { "", "++" };
304 	int piped = (insn & 0x40000000) >> 30;
305 	const char *const piped_suff[2] = { "", "p" };
306 	int upper_6bits = (insn >> 26) & 0x3f;
307 	int is_load = (upper_6bits == 8 || upper_6bits == 9 || upper_6bits == 24
308 					|| upper_6bits == 25);
309 
310 	/* Bits 2 and 1 determine the operand size.  */
311 	idx = ((insn >> 1) & 3);
312 	size = sizes[idx];
313 
314 	/* There is no pipelined load quad on XR.  */
315 	if (piped && size == 16)
316 	{
317 		util::stream_format(stream, ".long\t%#08x; *", insn);
318 		return;
319 	}
320 
321 	/* There is only a 64-bit pixel store.  */
322 	if ((upper_6bits == 15) && size != 8)
323 	{
324 		util::stream_format(stream, ".long\t%#08x", insn);
325 		return;
326 	}
327 
328 	/* Bit 26 determines the addressing mode (reg+reg or disp+reg).  */
329 	if (insn & 0x04000000)
330 	{
331 		/* Chop off lower bits of displacement.  */
332 		immsrc1 &= ~(size - 1);
333 		if (is_load)
334 			util::stream_format(stream, "%s%s%s\t%d(%%r%d)%s,%%f%d", piped_suff[piped], mnemonic,
335 				suffix[idx], immsrc1, get_isrc2 (insn), auto_suff[auto_inc],
336 				get_fdest (insn));
337 		else
338 			util::stream_format(stream, "%s%s\t%%f%d,%d(%%r%d)%s", mnemonic, suffix[idx],
339 				get_fdest (insn), immsrc1, get_isrc2 (insn), auto_suff[auto_inc]);
340 	}
341 	else
342 	{
343 		if (is_load)
344 			util::stream_format(stream, "%s%s%s\t%%r%d(%%r%d)%s,%%f%d", piped_suff[piped],
345 				mnemonic, suffix[idx], get_isrc1 (insn), get_isrc2 (insn),
346 				auto_suff[auto_inc], get_fdest (insn));
347 		else
348 			util::stream_format(stream, "%s%s\t%%f%d,%%r%d(%%r%d)%s", mnemonic, suffix[idx],
349 				get_fdest (insn), get_isrc1 (insn), get_isrc2 (insn),
350 				auto_suff[auto_inc]);
351 	}
352 }
353 
354 
355 /* flush #const(isrc2)[++].  */
int_flush(std::ostream & stream,char * mnemonic,uint32_t pc,uint32_t insn)356 void i860_disassembler::int_flush(std::ostream &stream, char *mnemonic, uint32_t pc, uint32_t insn)
357 {
358 	const char *const auto_suff[2] = { "", "++" };
359 	int32_t immsrc = sign_ext (get_imm16 (insn), 16);
360 	immsrc &= ~(16-1);
361 	util::stream_format(stream, "%s\t%d(%%r%d)%s", mnemonic, immsrc, get_isrc2 (insn),
362 		auto_suff[(insn & 1)]);
363 }
364 
365 
366 /* First-level decode table (i.e., for the 6 primary opcode bits).  */
367 const i860_disassembler::decode_tbl_t i860_disassembler::decode_tbl[64] =
368 {
369 	/* A slight bit of decoding for loads and stores is done in the
370 	   execution routines (operand size and addressing mode), which
371 	   is why their respective entries are identical.  */
372 	{ &i860_disassembler::int_ldx,   DEC_DECODED, "ld."        }, /* ld.b isrc1(isrc2),idest.  */
373 	{ &i860_disassembler::int_ldx,   DEC_DECODED, "ld."        }, /* ld.b #const(isrc2),idest.  */
374 	{ &i860_disassembler::int_1d,    DEC_DECODED, "ixfr"       }, /* ixfr isrc1ni,fdest.        */
375 	{ &i860_disassembler::int_stx,   DEC_DECODED, "st."        }, /* st.b isrc1ni,#const(isrc2).  */
376 	{ &i860_disassembler::int_ldx,   DEC_DECODED, "ld."        }, /* ld.{s,l} isrc1(isrc2),idest.  */
377 	{ &i860_disassembler::int_ldx,   DEC_DECODED, "ld."        }, /* ld.{s,l} #const(isrc2),idest.  */
378 	{ nullptr,                       0           , nullptr     },
379 	{ &i860_disassembler::int_stx,   DEC_DECODED, "st."        }, /* st.{s,l} isrc1ni,#const(isrc2),idest.*/
380 	{ &i860_disassembler::int_fldst, DEC_DECODED, "fld."       }, /* fld.{l,d,q} isrc1(isrc2)[++],fdest.  */
381 	{ &i860_disassembler::int_fldst, DEC_DECODED, "fld."       }, /* fld.{l,d,q} #const(isrc2)[++],fdest. */
382 	{ &i860_disassembler::int_fldst, DEC_DECODED, "fst."       }, /* fst.{l,d,q} fdest,isrc1(isrc2)[++]   */
383 	{ &i860_disassembler::int_fldst, DEC_DECODED, "fst."       }, /* fst.{l,d,q} fdest,#const(isrc2)[++]  */
384 	{ &i860_disassembler::int_cd,    DEC_DECODED, "ld.c"       }, /* ld.c csrc2,idest.                    */
385 	{ &i860_disassembler::int_flush, DEC_DECODED, "flush"      }, /* flush #const(isrc2) (or autoinc).    */
386 	{ &i860_disassembler::int_1c,    DEC_DECODED, "st.c"       }, /* st.c isrc1,csrc2.                    */
387 	{ &i860_disassembler::int_fldst, DEC_DECODED, "pstd."      }, /* pst.d fdest,#const(isrc2)[++].       */
388 	{ &i860_disassembler::int_1,     DEC_DECODED, "bri"        }, /* bri isrc1ni.                         */
389 	{ &i860_disassembler::int_12d,   DEC_DECODED, "trap"       }, /* trap isrc1ni,isrc2,idest.            */
390 	{ nullptr,                       DEC_MORE,    nullptr      }, /* FP ESCAPE FORMAT, more decode.       */
391 	{ nullptr,                       DEC_MORE,    nullptr      }, /* CORE ESCAPE FORMAT, more decode.     */
392 	{ &i860_disassembler::int_12S,   DEC_DECODED, "btne"       }, /* btne isrc1,isrc2,sbroff.             */
393 	{ &i860_disassembler::int_i2S,   DEC_DECODED, "btne"       }, /* btne #const,isrc2,sbroff.            */
394 	{ &i860_disassembler::int_12S,   DEC_DECODED, "bte"        }, /* bte isrc1,isrc2,sbroff.              */
395 	{ &i860_disassembler::int_i2S,   DEC_DECODED, "bte"        }, /* bte #const5,isrc2,idest.             */
396 	{ &i860_disassembler::int_fldst, DEC_DECODED, "pfld."      }, /* pfld.{l,d,q} isrc1(isrc2)[++],fdest. */
397 	{ &i860_disassembler::int_fldst, DEC_DECODED, "pfld."      }, /* pfld.{l,d,q} #const(isrc2)[++],fdest.*/
398 	{ &i860_disassembler::int_L,     DEC_DECODED, "br"         }, /* br lbroff.    */
399 	{ &i860_disassembler::int_L,     DEC_DECODED, "call"       }, /* call lbroff . */
400 	{ &i860_disassembler::int_L,     DEC_DECODED, "bc"         }, /* bc lbroff.    */
401 	{ &i860_disassembler::int_L,     DEC_DECODED, "bc.t"       }, /* bc.t lbroff.  */
402 	{ &i860_disassembler::int_L,     DEC_DECODED, "bnc"        }, /* bnc lbroff.   */
403 	{ &i860_disassembler::int_L,     DEC_DECODED, "bnc.t"      }, /* bnc.t lbroff. */
404 	{ &i860_disassembler::int_12d,   DEC_DECODED, "addu"       }, /* addu isrc1,isrc2,idest.    */
405 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "addu"       }, /* addu #const,isrc2,idest.   */
406 	{ &i860_disassembler::int_12d,   DEC_DECODED, "subu"       }, /* subu isrc1,isrc2,idest.    */
407 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "subu"       }, /* subu #const,isrc2,idest.   */
408 	{ &i860_disassembler::int_12d,   DEC_DECODED, "adds"       }, /* adds isrc1,isrc2,idest.    */
409 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "adds"       }, /* adds #const,isrc2,idest.   */
410 	{ &i860_disassembler::int_12d,   DEC_DECODED, "subs"       }, /* subs isrc1,isrc2,idest.    */
411 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "subs"       }, /* subs #const,isrc2,idest.   */
412 	{ &i860_disassembler::int_12d,   DEC_DECODED, "shl"        }, /* shl isrc1,isrc2,idest.     */
413 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "shl"        }, /* shl #const,isrc2,idest.    */
414 	{ &i860_disassembler::int_12d,   DEC_DECODED, "shr"        }, /* shr isrc1,isrc2,idest.     */
415 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "shr"        }, /* shr #const,isrc2,idest.    */
416 	{ &i860_disassembler::int_12d,   DEC_DECODED, "shrd"       }, /* shrd isrc1ni,isrc2,idest.  */
417 	{ &i860_disassembler::int_12S,   DEC_DECODED, "bla"        }, /* bla isrc1ni,isrc2,sbroff.  */
418 	{ &i860_disassembler::int_12d,   DEC_DECODED, "shra"       }, /* shra isrc1,isrc2,idest.    */
419 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "shra"       }, /* shra #const,isrc2,idest.   */
420 	{ &i860_disassembler::int_12d,   DEC_DECODED, "and"        }, /* and isrc1,isrc2,idest.     */
421 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "and"        }, /* and #const,isrc2,idest.    */
422 	{ nullptr,                       0           , nullptr     },
423 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "andh"       }, /* andh #const,isrc2,idest.   */
424 	{ &i860_disassembler::int_12d,   DEC_DECODED, "andnot"     }, /* andnot isrc1,isrc2,idest.  */
425 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "andnot"     }, /* andnot #const,isrc2,idest. */
426 	{ nullptr,                       0           , nullptr     },
427 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "andnoth"    }, /* andnoth #const,isrc2,idest.*/
428 	{ &i860_disassembler::int_12d,   DEC_DECODED, "or"         }, /* or isrc1,isrc2,idest.      */
429 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "or"         }, /* or #const,isrc2,idest.     */
430 	{ nullptr,                       0           , nullptr     },
431 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "orh"        }, /* orh #const,isrc2,idest.    */
432 	{ &i860_disassembler::int_12d,   DEC_DECODED, "xor"        }, /* xor isrc1,isrc2,idest.     */
433 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "xor"        }, /* xor #const,isrc2,idest.    */
434 	{ nullptr,                       0           , nullptr     },
435 	{ &i860_disassembler::int_i2d,   DEC_DECODED, "xorh"       }, /* xorh #const,isrc2,idest.   */
436 };
437 
438 
439 /* Second-level decode table (i.e., for the 3 core escape opcode bits).  */
440 const i860_disassembler::decode_tbl_t i860_disassembler::core_esc_decode_tbl[8] =
441 {
442 	{ nullptr,                       0          , nullptr     },
443 	{ &i860_disassembler::int_0,     DEC_DECODED, "lock"      }, /* lock.           */
444 	{ &i860_disassembler::int_1,     DEC_DECODED, "calli"     }, /* calli isrc1ni.  */
445 	{ nullptr,                       0          , nullptr     },
446 	{ &i860_disassembler::int_0,     DEC_DECODED, "intovr"    }, /* intovr.         */
447 	{ nullptr,                       0          , nullptr     },
448 	{ nullptr,                       0          , nullptr     },
449 	{ &i860_disassembler::int_0,     DEC_DECODED, "unlock"    }, /* unlock.         */
450 };
451 
452 
453 /* Second-level decode table (i.e., for the 7 FP extended opcode bits).  */
454 const i860_disassembler::decode_tbl_t i860_disassembler::fp_decode_tbl[128] =
455 {
456 	/* Floating point instructions.  The least significant 7 bits are
457 	   the (extended) opcode and bits 10:7 are P,D,S,R respectively
458 	   ([p]ipelined, [d]ual, [s]ource prec., [r]esult prec.).
459 	   For some operations, I defer decoding the P,S,R bits to the
460 	   emulation routine for them.  */
461 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2p1."     }, /* 0x00 pf[m]am */
462 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2pt."     }, /* 0x01 pf[m]am */
463 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2ap1."    }, /* 0x02 pf[m]am */
464 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2apt."    }, /* 0x03 pf[m]am */
465 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2p1."     }, /* 0x04 pf[m]am */
466 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2pt."     }, /* 0x05 pf[m]am */
467 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2ap1."    }, /* 0x06 pf[m]am */
468 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2apt."    }, /* 0x07 pf[m]am */
469 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "rat1p2."   }, /* 0x08 pf[m]am */
470 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12apm."   }, /* 0x09 pf[m]am */
471 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "ra1p2."    }, /* 0x0A pf[m]am */
472 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12ttpa."  }, /* 0x0B pf[m]am */
473 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "iat1p2."   }, /* 0x0C pf[m]am */
474 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12tpm."   }, /* 0x0D pf[m]am */
475 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "ia1p2."    }, /* 0x0E pf[m]am */
476 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12tpa."   }, /* 0x0F pf[m]am */
477 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2s1."     }, /* 0x10 pf[m]sm */
478 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2st."     }, /* 0x11 pf[m]sm */
479 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2as1."    }, /* 0x12 pf[m]sm */
480 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "r2ast."    }, /* 0x13 pf[m]sm */
481 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2s1."     }, /* 0x14 pf[m]sm */
482 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2st."     }, /* 0x15 pf[m]sm */
483 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2as1."    }, /* 0x16 pf[m]sm */
484 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "i2ast."    }, /* 0x17 pf[m]sm */
485 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "rat1s2."   }, /* 0x18 pf[m]sm */
486 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12asm."   }, /* 0x19 pf[m]sm */
487 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "ra1s2."    }, /* 0x1A pf[m]sm */
488 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12ttsa."  }, /* 0x1B pf[m]sm */
489 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "iat1s2."   }, /* 0x1C pf[m]sm */
490 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12tsm."   }, /* 0x1D pf[m]sm */
491 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "ia1s2."    }, /* 0x1E pf[m]sm */
492 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "m12tsa."   }, /* 0x1F pf[m]sm */
493 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fmul."     }, /* 0x20 [p]fmul */
494 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fmlow."    }, /* 0x21 fmlow.dd */
495 	{ &i860_disassembler::flop_2d,   DEC_DECODED, "frcp."     }, /* 0x22 frcp.{ss,sd,dd} */
496 	{ &i860_disassembler::flop_2d,   DEC_DECODED, "frsqr."    }, /* 0x23 frsqr.{ss,sd,dd} */
497 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "pfmul3.dd" }, /* 0x24 pfmul3.dd */
498 	{ nullptr,                       0          , nullptr     }, /* 0x25 */
499 	{ nullptr,                       0          , nullptr     }, /* 0x26 */
500 	{ nullptr,                       0          , nullptr     }, /* 0x27 */
501 	{ nullptr,                       0          , nullptr     }, /* 0x28 */
502 	{ nullptr,                       0          , nullptr     }, /* 0x29 */
503 	{ nullptr,                       0          , nullptr     }, /* 0x2A */
504 	{ nullptr,                       0          , nullptr     }, /* 0x2B */
505 	{ nullptr,                       0          , nullptr     }, /* 0x2C */
506 	{ nullptr,                       0          , nullptr     }, /* 0x2D */
507 	{ nullptr,                       0          , nullptr     }, /* 0x2E */
508 	{ nullptr,                       0          , nullptr     }, /* 0x2F */
509 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fadd."     }, /* 0x30, [p]fadd.{ss,sd,dd} */
510 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fsub."     }, /* 0x31, [p]fsub.{ss,sd,dd} */
511 	{ &i860_disassembler::flop_1d,   DEC_DECODED, "fix."      }, /* 0x32, [p]fix.{ss,sd,dd} */
512 	{ &i860_disassembler::flop_1d,   DEC_DECODED, "famov."    }, /* 0x33, [p]famov.{ss,sd,ds,dd} */
513 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "f{gt,le}"  }, /* 0x34, pf{gt,le}.{ss,dd} */
514 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "feq."      }, /* 0x35, pfeq.{ss,dd} */
515 	{ nullptr,                       0          , nullptr     }, /* 0x36 */
516 	{ nullptr,                       0          , nullptr     }, /* 0x37 */
517 	{ nullptr,                       0          , nullptr     }, /* 0x38 */
518 	{ nullptr,                       0          , nullptr     }, /* 0x39 */
519 	{ &i860_disassembler::flop_1d,   DEC_DECODED, "ftrunc."   }, /* 0x3A, [p]ftrunc.{ss,sd,dd} */
520 	{ nullptr,                       0          , nullptr     }, /* 0x3B */
521 	{ nullptr,                       0          , nullptr     }, /* 0x3C */
522 	{ nullptr,                       0          , nullptr     }, /* 0x3D */
523 	{ nullptr,                       0          , nullptr     }, /* 0x3E */
524 	{ nullptr,                       0          , nullptr     }, /* 0x3F */
525 	{ &i860_disassembler::flop_fxfr, DEC_DECODED, "fxfr"      }, /* 0x40, fxfr fsrc1,idest. */
526 	{ nullptr,                       0          , nullptr     }, /* 0x41 */
527 	{ nullptr,                       0          , nullptr     }, /* 0x42 */
528 	{ nullptr,                       0          , nullptr     }, /* 0x43 */
529 	{ nullptr,                       0          , nullptr     }, /* 0x44 */
530 	{ nullptr,                       0          , nullptr     }, /* 0x45 */
531 	{ nullptr,                       0          , nullptr     }, /* 0x46 */
532 	{ nullptr,                       0          , nullptr     }, /* 0x47 */
533 	{ nullptr,                       0          , nullptr     }, /* 0x48 */
534 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fiadd."    }, /* 0x49, [p]fiadd.{ss,dd} */
535 	{ nullptr,                       0          , nullptr     }, /* 0x4A */
536 	{ nullptr,                       0          , nullptr     }, /* 0x4B */
537 	{ nullptr,                       0          , nullptr     }, /* 0x4C */
538 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fisub."    }, /* 0x4D, [p]fisub.{ss,dd} */
539 	{ nullptr,                       0          , nullptr     }, /* 0x4E */
540 	{ nullptr,                       0          , nullptr     }, /* 0x4F */
541 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "faddp"     }, /* 0x50, [p]faddp */
542 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "faddz"     }, /* 0x51, [p]faddz */
543 	{ nullptr,                       0          , nullptr     }, /* 0x52 */
544 	{ nullptr,                       0          , nullptr     }, /* 0x53 */
545 	{ nullptr,                       0          , nullptr     }, /* 0x54 */
546 	{ nullptr,                       0          , nullptr     }, /* 0x55 */
547 	{ nullptr,                       0          , nullptr     }, /* 0x56 */
548 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fzchkl"    }, /* 0x57, [p]fzchkl */
549 	{ nullptr,                       0          , nullptr     }, /* 0x58 */
550 	{ nullptr,                       0          , nullptr     }, /* 0x59 */
551 	{ &i860_disassembler::flop_1d,   DEC_DECODED, "form"      }, /* 0x5A, [p]form.dd */
552 	{ nullptr,                       0          , nullptr     }, /* 0x5B */
553 	{ nullptr,                       0          , nullptr     }, /* 0x5C */
554 	{ nullptr,                       0          , nullptr     }, /* 0x5D */
555 	{ nullptr,                       0          , nullptr     }, /* 0x5E */
556 	{ &i860_disassembler::flop_12d,  DEC_DECODED, "fzchks"    }, /* 0x5F, [p]fzchks */
557 	{ nullptr,                       0          , nullptr     }, /* 0x60 */
558 	{ nullptr,                       0          , nullptr     }, /* 0x61 */
559 	{ nullptr,                       0          , nullptr     }, /* 0x62 */
560 	{ nullptr,                       0          , nullptr     }, /* 0x63 */
561 	{ nullptr,                       0          , nullptr     }, /* 0x64 */
562 	{ nullptr,                       0          , nullptr     }, /* 0x65 */
563 	{ nullptr,                       0          , nullptr     }, /* 0x66 */
564 	{ nullptr,                       0          , nullptr     }, /* 0x67 */
565 	{ nullptr,                       0          , nullptr     }, /* 0x68 */
566 	{ nullptr,                       0          , nullptr     }, /* 0x69 */
567 	{ nullptr,                       0          , nullptr     }, /* 0x6A */
568 	{ nullptr,                       0          , nullptr     }, /* 0x6B */
569 	{ nullptr,                       0          , nullptr     }, /* 0x6C */
570 	{ nullptr,                       0          , nullptr     }, /* 0x6D */
571 	{ nullptr,                       0          , nullptr     }, /* 0x6E */
572 	{ nullptr,                       0          , nullptr     }, /* 0x6F */
573 	{ nullptr,                       0          , nullptr     }, /* 0x70 */
574 	{ nullptr,                       0          , nullptr     }, /* 0x71 */
575 	{ nullptr,                       0          , nullptr     }, /* 0x72 */
576 	{ nullptr,                       0          , nullptr     }, /* 0x73 */
577 	{ nullptr,                       0          , nullptr     }, /* 0x74 */
578 	{ nullptr,                       0          , nullptr     }, /* 0x75 */
579 	{ nullptr,                       0          , nullptr     }, /* 0x76 */
580 	{ nullptr,                       0          , nullptr     }, /* 0x77 */
581 	{ nullptr,                       0          , nullptr     }, /* 0x78 */
582 	{ nullptr,                       0          , nullptr     }, /* 0x79 */
583 	{ nullptr,                       0          , nullptr     }, /* 0x7A */
584 	{ nullptr,                       0          , nullptr     }, /* 0x7B */
585 	{ nullptr,                       0          , nullptr     }, /* 0x7C */
586 	{ nullptr,                       0          , nullptr     }, /* 0x7D */
587 	{ nullptr,                       0          , nullptr     }, /* 0x7E */
588 	{ nullptr,                       0          , nullptr     }, /* 0x7F */
589 };
590 
591 
592 /* Replaces tabs with spaces.  */
i860_dasm_tab_replacer(std::ostream & stream,const std::string & buf,int tab_size)593 void i860_disassembler::i860_dasm_tab_replacer(std::ostream &stream, const std::string &buf, int tab_size)
594 {
595 	int tab_count = 0;
596 
597 	for (char ch : buf)
598 	{
599 		if (ch != '\t')
600 		{
601 			stream << ch;
602 			tab_count++;
603 		}
604 		else
605 		{
606 			while (tab_count % tab_size != 0)
607 			{
608 				stream << ' ';
609 				tab_count++;
610 			}
611 		}
612 	}
613 }
614 
615 
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)616 offs_t i860_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
617 {
618 	std::stringstream tstream;
619 
620 	uint32_t insn = opcodes.r32(pc);
621 
622 	int unrecognized_op = 1;
623 	int upper_6bits = (insn >> 26) & 0x3f;
624 	char flags = decode_tbl[upper_6bits].flags;
625 	if (flags & DEC_DECODED)
626 	{
627 		const char *s = decode_tbl[upper_6bits].mnemonic;
628 		(this->*(decode_tbl[upper_6bits].insn_dis)) (tstream, (char *)s, pc, insn);
629 		unrecognized_op = 0;
630 	}
631 	else if (flags & DEC_MORE)
632 	{
633 		if (upper_6bits == 0x12)
634 		{
635 			/* FP instruction format handled here.  */
636 			char fp_flags = fp_decode_tbl[insn & 0x7f].flags;
637 			const char *s = fp_decode_tbl[insn & 0x7f].mnemonic;
638 			if (fp_flags & DEC_DECODED)
639 			{
640 				(this->*(fp_decode_tbl[insn & 0x7f].insn_dis)) (tstream, (char *)s, pc, insn);
641 				unrecognized_op = 0;
642 			}
643 		}
644 		else if (upper_6bits == 0x13)
645 		{
646 			/* Core escape instruction format handled here.  */
647 			char esc_flags = core_esc_decode_tbl[insn & 0x3].flags;
648 			const char *s = core_esc_decode_tbl[insn & 0x3].mnemonic;
649 			if (esc_flags & DEC_DECODED)
650 			{
651 				(this->*(core_esc_decode_tbl[insn & 0x3].insn_dis)) (tstream, (char *)s, pc, insn);
652 				unrecognized_op = 0;
653 			}
654 		}
655 	}
656 
657 	if (unrecognized_op)
658 		util::stream_format(tstream, ".long\t%#08x", insn);
659 
660 	/* Replace tabs with spaces */
661 	i860_dasm_tab_replacer(stream, tstream.str(), 10);
662 
663 	/* Return number of bytes disassembled.  */
664 	/* MAME dasm flags haven't been added yet */
665 	return (4);
666 }
667 
opcode_alignment() const668 u32 i860_disassembler::opcode_alignment() const
669 {
670 	return 4;
671 }
672