d30v-dis.c revision 1.9.2.1 1 1.1 christos /* Disassemble D30V instructions.
2 1.9.2.1 perseant Copyright (C) 1997-2022 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of the GNU opcodes library.
5 1.1 christos
6 1.1 christos This library is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3, or (at your option)
9 1.1 christos any later version.
10 1.1 christos
11 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
12 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 1.1 christos License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; if not, write to the Free Software
18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 1.1 christos MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "sysdep.h"
22 1.1 christos #include <stdio.h>
23 1.1 christos #include "opcode/d30v.h"
24 1.8 christos #include "disassemble.h"
25 1.1 christos #include "opintl.h"
26 1.9 christos #include "libiberty.h"
27 1.1 christos
28 1.1 christos #define PC_MASK 0xFFFFFFFF
29 1.1 christos
30 1.1 christos /* Return 0 if lookup fails,
31 1.1 christos 1 if found and only one form,
32 1.1 christos 2 if found and there are short and long forms. */
33 1.1 christos
34 1.1 christos static int
35 1.1 christos lookup_opcode (struct d30v_insn *insn, long num, int is_long)
36 1.1 christos {
37 1.1 christos int i = 0, op_index;
38 1.1 christos struct d30v_format *f;
39 1.1 christos struct d30v_opcode *op = (struct d30v_opcode *) d30v_opcode_table;
40 1.1 christos int op1 = (num >> 25) & 0x7;
41 1.1 christos int op2 = (num >> 20) & 0x1f;
42 1.1 christos int mod = (num >> 18) & 0x3;
43 1.1 christos
44 1.1 christos /* Find the opcode. */
45 1.1 christos do
46 1.1 christos {
47 1.1 christos if ((op->op1 == op1) && (op->op2 == op2))
48 1.1 christos break;
49 1.1 christos op++;
50 1.1 christos }
51 1.1 christos while (op->name);
52 1.1 christos
53 1.1 christos if (!op || !op->name)
54 1.1 christos return 0;
55 1.1 christos
56 1.1 christos while (op->op1 == op1 && op->op2 == op2)
57 1.1 christos {
58 1.1 christos /* Scan through all the formats for the opcode. */
59 1.1 christos op_index = op->format[i++];
60 1.1 christos do
61 1.1 christos {
62 1.1 christos f = (struct d30v_format *) &d30v_format_table[op_index];
63 1.1 christos while (f->form == op_index)
64 1.1 christos {
65 1.1 christos if ((!is_long || f->form >= LONG) && (f->modifier == mod))
66 1.1 christos {
67 1.1 christos insn->form = f;
68 1.1 christos break;
69 1.1 christos }
70 1.1 christos f++;
71 1.1 christos }
72 1.1 christos if (insn->form)
73 1.1 christos break;
74 1.1 christos }
75 1.1 christos while ((op_index = op->format[i++]) != 0);
76 1.1 christos if (insn->form)
77 1.1 christos break;
78 1.1 christos op++;
79 1.1 christos i = 0;
80 1.1 christos }
81 1.1 christos if (insn->form == NULL)
82 1.1 christos return 0;
83 1.1 christos
84 1.1 christos insn->op = op;
85 1.1 christos insn->ecc = (num >> 28) & 0x7;
86 1.1 christos if (op->format[1])
87 1.1 christos return 2;
88 1.1 christos else
89 1.1 christos return 1;
90 1.1 christos }
91 1.1 christos
92 1.1 christos static int
93 1.9 christos extract_value (uint64_t num, const struct d30v_operand *oper, int is_long)
94 1.1 christos {
95 1.9 christos unsigned int val;
96 1.1 christos int shift = 12 - oper->position;
97 1.9 christos unsigned int mask = (0xFFFFFFFF >> (32 - oper->bits));
98 1.1 christos
99 1.1 christos if (is_long)
100 1.1 christos {
101 1.1 christos if (oper->bits == 32)
102 1.1 christos /* Piece together 32-bit constant. */
103 1.1 christos val = ((num & 0x3FFFF)
104 1.1 christos | ((num & 0xFF00000) >> 2)
105 1.1 christos | ((num & 0x3F00000000LL) >> 6));
106 1.1 christos else
107 1.1 christos val = (num >> (32 + shift)) & mask;
108 1.1 christos }
109 1.1 christos else
110 1.1 christos val = (num >> shift) & mask;
111 1.1 christos
112 1.1 christos if (oper->flags & OPERAND_SHIFT)
113 1.1 christos val <<= 3;
114 1.1 christos
115 1.1 christos return val;
116 1.1 christos }
117 1.1 christos
118 1.1 christos static void
119 1.1 christos print_insn (struct disassemble_info *info,
120 1.1 christos bfd_vma memaddr,
121 1.9 christos uint64_t num,
122 1.1 christos struct d30v_insn *insn,
123 1.1 christos int is_long,
124 1.1 christos int show_ext)
125 1.1 christos {
126 1.9 christos unsigned int val, opnum;
127 1.9 christos const struct d30v_operand *oper;
128 1.9 christos int i, match, need_comma = 0, need_paren = 0, found_control = 0;
129 1.9 christos unsigned int opind = 0;
130 1.1 christos
131 1.1 christos (*info->fprintf_func) (info->stream, "%s", insn->op->name);
132 1.1 christos
133 1.1 christos /* Check for CMP or CMPU. */
134 1.1 christos if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME)
135 1.1 christos {
136 1.1 christos opind++;
137 1.1 christos val =
138 1.1 christos extract_value (num,
139 1.9 christos &d30v_operand_table[insn->form->operands[0]],
140 1.1 christos is_long);
141 1.1 christos (*info->fprintf_func) (info->stream, "%s", d30v_cc_names[val]);
142 1.1 christos }
143 1.1 christos
144 1.1 christos /* Add in ".s" or ".l". */
145 1.1 christos if (show_ext == 2)
146 1.1 christos {
147 1.1 christos if (is_long)
148 1.1 christos (*info->fprintf_func) (info->stream, ".l");
149 1.1 christos else
150 1.1 christos (*info->fprintf_func) (info->stream, ".s");
151 1.1 christos }
152 1.1 christos
153 1.1 christos if (insn->ecc)
154 1.1 christos (*info->fprintf_func) (info->stream, "/%s", d30v_ecc_names[insn->ecc]);
155 1.1 christos
156 1.1 christos (*info->fprintf_func) (info->stream, "\t");
157 1.1 christos
158 1.9 christos while (opind < ARRAY_SIZE (insn->form->operands)
159 1.9 christos && (opnum = insn->form->operands[opind++]) != 0)
160 1.1 christos {
161 1.1 christos int bits;
162 1.1 christos
163 1.9 christos oper = &d30v_operand_table[opnum];
164 1.1 christos bits = oper->bits;
165 1.1 christos if (oper->flags & OPERAND_SHIFT)
166 1.1 christos bits += 3;
167 1.1 christos
168 1.1 christos if (need_comma
169 1.1 christos && oper->flags != OPERAND_PLUS
170 1.1 christos && oper->flags != OPERAND_MINUS)
171 1.1 christos {
172 1.1 christos need_comma = 0;
173 1.1 christos (*info->fprintf_func) (info->stream, ", ");
174 1.1 christos }
175 1.1 christos
176 1.1 christos if (oper->flags == OPERAND_ATMINUS)
177 1.1 christos {
178 1.1 christos (*info->fprintf_func) (info->stream, "@-");
179 1.1 christos continue;
180 1.1 christos }
181 1.1 christos if (oper->flags == OPERAND_MINUS)
182 1.1 christos {
183 1.1 christos (*info->fprintf_func) (info->stream, "-");
184 1.1 christos continue;
185 1.1 christos }
186 1.1 christos if (oper->flags == OPERAND_PLUS)
187 1.1 christos {
188 1.1 christos (*info->fprintf_func) (info->stream, "+");
189 1.1 christos continue;
190 1.1 christos }
191 1.1 christos if (oper->flags == OPERAND_ATSIGN)
192 1.1 christos {
193 1.1 christos (*info->fprintf_func) (info->stream, "@");
194 1.1 christos continue;
195 1.1 christos }
196 1.1 christos if (oper->flags == OPERAND_ATPAR)
197 1.1 christos {
198 1.1 christos (*info->fprintf_func) (info->stream, "@(");
199 1.1 christos need_paren = 1;
200 1.1 christos continue;
201 1.1 christos }
202 1.1 christos
203 1.1 christos if (oper->flags == OPERAND_SPECIAL)
204 1.1 christos continue;
205 1.1 christos
206 1.1 christos val = extract_value (num, oper, is_long);
207 1.1 christos
208 1.1 christos if (oper->flags & OPERAND_REG)
209 1.1 christos {
210 1.1 christos match = 0;
211 1.1 christos if (oper->flags & OPERAND_CONTROL)
212 1.1 christos {
213 1.9 christos const struct d30v_operand *oper3
214 1.9 christos = &d30v_operand_table[insn->form->operands[2]];
215 1.1 christos int id = extract_value (num, oper3, is_long);
216 1.1 christos
217 1.1 christos found_control = 1;
218 1.1 christos switch (id)
219 1.1 christos {
220 1.1 christos case 0:
221 1.1 christos val |= OPERAND_CONTROL;
222 1.1 christos break;
223 1.1 christos case 1:
224 1.1 christos case 2:
225 1.1 christos val = OPERAND_CONTROL + MAX_CONTROL_REG + id;
226 1.1 christos break;
227 1.1 christos case 3:
228 1.1 christos val |= OPERAND_FLAG;
229 1.1 christos break;
230 1.1 christos default:
231 1.8 christos /* xgettext: c-format */
232 1.8 christos opcodes_error_handler (_("illegal id (%d)"), id);
233 1.8 christos abort ();
234 1.1 christos }
235 1.1 christos }
236 1.1 christos else if (oper->flags & OPERAND_ACC)
237 1.1 christos val |= OPERAND_ACC;
238 1.1 christos else if (oper->flags & OPERAND_FLAG)
239 1.1 christos val |= OPERAND_FLAG;
240 1.1 christos for (i = 0; i < reg_name_cnt (); i++)
241 1.1 christos {
242 1.1 christos if (val == pre_defined_registers[i].value)
243 1.1 christos {
244 1.1 christos if (pre_defined_registers[i].pname)
245 1.1 christos (*info->fprintf_func)
246 1.1 christos (info->stream, "%s", pre_defined_registers[i].pname);
247 1.1 christos else
248 1.1 christos (*info->fprintf_func)
249 1.1 christos (info->stream, "%s", pre_defined_registers[i].name);
250 1.1 christos match = 1;
251 1.1 christos break;
252 1.1 christos }
253 1.1 christos }
254 1.1 christos if (match == 0)
255 1.1 christos {
256 1.1 christos /* This would only get executed if a register was not in
257 1.1 christos the register table. */
258 1.1 christos (*info->fprintf_func)
259 1.1 christos (info->stream, _("<unknown register %d>"), val & 0x3F);
260 1.1 christos }
261 1.1 christos }
262 1.1 christos /* repeati has a relocation, but its first argument is a plain
263 1.1 christos immediate. OTOH instructions like djsri have a pc-relative
264 1.1 christos delay target, but an absolute jump target. Therefore, a test
265 1.1 christos of insn->op->reloc_flag is not specific enough; we must test
266 1.1 christos if the actual operand we are handling now is pc-relative. */
267 1.1 christos else if (oper->flags & OPERAND_PCREL)
268 1.1 christos {
269 1.1 christos int neg = 0;
270 1.1 christos
271 1.1 christos /* IMM6S3 is unsigned. */
272 1.1 christos if (oper->flags & OPERAND_SIGNED || bits == 32)
273 1.1 christos {
274 1.9 christos unsigned int sign = 1u << (bits - 1);
275 1.9 christos if (val & sign)
276 1.1 christos {
277 1.9 christos val = -val & (sign + sign - 1);
278 1.1 christos neg = 1;
279 1.1 christos }
280 1.1 christos }
281 1.1 christos if (neg)
282 1.1 christos {
283 1.1 christos (*info->fprintf_func) (info->stream, "-%x\t(", val);
284 1.1 christos (*info->print_address_func) ((memaddr - val) & PC_MASK, info);
285 1.1 christos (*info->fprintf_func) (info->stream, ")");
286 1.1 christos }
287 1.1 christos else
288 1.1 christos {
289 1.1 christos (*info->fprintf_func) (info->stream, "%x\t(", val);
290 1.1 christos (*info->print_address_func) ((memaddr + val) & PC_MASK, info);
291 1.1 christos (*info->fprintf_func) (info->stream, ")");
292 1.1 christos }
293 1.1 christos }
294 1.1 christos else if (insn->op->reloc_flag == RELOC_ABS)
295 1.1 christos {
296 1.1 christos (*info->print_address_func) (val, info);
297 1.1 christos }
298 1.1 christos else
299 1.1 christos {
300 1.1 christos if (oper->flags & OPERAND_SIGNED)
301 1.1 christos {
302 1.9 christos unsigned int sign = 1u << (bits - 1);
303 1.1 christos
304 1.9 christos if (val & sign)
305 1.1 christos {
306 1.9 christos val = -val & (sign + sign - 1);
307 1.1 christos (*info->fprintf_func) (info->stream, "-");
308 1.1 christos }
309 1.1 christos }
310 1.1 christos (*info->fprintf_func) (info->stream, "0x%x", val);
311 1.1 christos }
312 1.1 christos /* If there is another operand, then write a comma and space. */
313 1.9 christos if (opind < ARRAY_SIZE (insn->form->operands)
314 1.9 christos && insn->form->operands[opind]
315 1.9 christos && !(found_control && opind == 2))
316 1.1 christos need_comma = 1;
317 1.1 christos }
318 1.1 christos if (need_paren)
319 1.1 christos (*info->fprintf_func) (info->stream, ")");
320 1.1 christos }
321 1.1 christos
322 1.1 christos int
323 1.1 christos print_insn_d30v (bfd_vma memaddr, struct disassemble_info *info)
324 1.1 christos {
325 1.1 christos int status, result;
326 1.1 christos bfd_byte buffer[12];
327 1.9 christos uint32_t in1, in2;
328 1.1 christos struct d30v_insn insn;
329 1.9 christos uint64_t num;
330 1.1 christos
331 1.1 christos insn.form = NULL;
332 1.1 christos
333 1.1 christos info->bytes_per_line = 8;
334 1.1 christos info->bytes_per_chunk = 4;
335 1.1 christos info->display_endian = BFD_ENDIAN_BIG;
336 1.1 christos
337 1.1 christos status = (*info->read_memory_func) (memaddr, buffer, 4, info);
338 1.1 christos if (status != 0)
339 1.1 christos {
340 1.1 christos (*info->memory_error_func) (status, memaddr, info);
341 1.1 christos return -1;
342 1.1 christos }
343 1.1 christos in1 = bfd_getb32 (buffer);
344 1.1 christos
345 1.1 christos status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
346 1.1 christos if (status != 0)
347 1.1 christos {
348 1.1 christos info->bytes_per_line = 8;
349 1.1 christos if (!(result = lookup_opcode (&insn, in1, 0)))
350 1.9 christos (*info->fprintf_func) (info->stream, ".long\t0x%x", in1);
351 1.1 christos else
352 1.9 christos print_insn (info, memaddr, (uint64_t) in1, &insn, 0, result);
353 1.1 christos return 4;
354 1.1 christos }
355 1.1 christos in2 = bfd_getb32 (buffer);
356 1.1 christos
357 1.1 christos if (in1 & in2 & FM01)
358 1.1 christos {
359 1.1 christos /* LONG instruction. */
360 1.1 christos if (!(result = lookup_opcode (&insn, in1, 1)))
361 1.1 christos {
362 1.9 christos (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x", in1, in2);
363 1.1 christos return 8;
364 1.1 christos }
365 1.9 christos num = (uint64_t) in1 << 32 | in2;
366 1.1 christos print_insn (info, memaddr, num, &insn, 1, result);
367 1.1 christos }
368 1.1 christos else
369 1.1 christos {
370 1.1 christos num = in1;
371 1.1 christos if (!(result = lookup_opcode (&insn, in1, 0)))
372 1.9 christos (*info->fprintf_func) (info->stream, ".long\t0x%x", in1);
373 1.1 christos else
374 1.1 christos print_insn (info, memaddr, num, &insn, 0, result);
375 1.1 christos
376 1.1 christos switch (((in1 >> 31) << 1) | (in2 >> 31))
377 1.1 christos {
378 1.1 christos case 0:
379 1.1 christos (*info->fprintf_func) (info->stream, "\t||\t");
380 1.1 christos break;
381 1.1 christos case 1:
382 1.1 christos (*info->fprintf_func) (info->stream, "\t->\t");
383 1.1 christos break;
384 1.1 christos case 2:
385 1.1 christos (*info->fprintf_func) (info->stream, "\t<-\t");
386 1.1 christos default:
387 1.1 christos break;
388 1.1 christos }
389 1.1 christos
390 1.1 christos insn.form = NULL;
391 1.1 christos num = in2;
392 1.1 christos if (!(result = lookup_opcode (&insn, in2, 0)))
393 1.9 christos (*info->fprintf_func) (info->stream, ".long\t0x%x", in2);
394 1.1 christos else
395 1.1 christos print_insn (info, memaddr, num, &insn, 0, result);
396 1.1 christos }
397 1.1 christos return 8;
398 1.1 christos }
399