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