1 /* Disassemble Xilinx microblaze instructions.
3 Copyright (C) 2009-2019 Free Software Foundation, Inc.
5 This file is part of the GNU opcodes library.
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 It is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this file; see the file COPYING. If not, write to the
19 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
27 #include "disassemble.h"
29 #include "microblaze-opc.h"
30 #include "microblaze-dis.h"
32 #define get_field_rd(buf, instr) get_field (buf, instr, RD_MASK, RD_LOW)
33 #define get_field_r1(buf, instr) get_field (buf, instr, RA_MASK, RA_LOW)
34 #define get_field_r2(buf, instr) get_field (buf, instr, RB_MASK, RB_LOW)
35 #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
36 #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
39 #define STRBUF_SIZE 25
44 char str
[NUM_STRBUFS
][STRBUF_SIZE
];
48 strbuf (struct string_buf
*buf
)
50 #ifdef ENABLE_CHECKING
51 if (buf
->which
>= NUM_STRBUFS
)
54 return buf
->str
[buf
->which
++];
58 get_field (struct string_buf
*buf
, long instr
, long mask
, unsigned short low
)
60 char *p
= strbuf (buf
);
62 sprintf (p
, "%s%d", register_prefix
, (int)((instr
& mask
) >> low
));
67 get_field_imm (struct string_buf
*buf
, long instr
)
69 char *p
= strbuf (buf
);
71 sprintf (p
, "%d", (short)((instr
& IMM_MASK
) >> IMM_LOW
));
76 get_field_imm5 (struct string_buf
*buf
, long instr
)
78 char *p
= strbuf (buf
);
80 sprintf (p
, "%d", (short)((instr
& IMM5_MASK
) >> IMM_LOW
));
85 get_field_imm5_mbar (struct string_buf
*buf
, long instr
)
87 char *p
= strbuf (buf
);
89 sprintf (p
, "%d", (short)((instr
& IMM5_MBAR_MASK
) >> IMM_MBAR
));
94 get_field_rfsl (struct string_buf
*buf
, long instr
)
96 char *p
= strbuf (buf
);
98 sprintf (p
, "%s%d", fsl_register_prefix
,
99 (short)((instr
& RFSL_MASK
) >> IMM_LOW
));
104 get_field_imm15 (struct string_buf
*buf
, long instr
)
106 char *p
= strbuf (buf
);
108 sprintf (p
, "%d", (short)((instr
& IMM15_MASK
) >> IMM_LOW
));
113 get_field_special (struct string_buf
*buf
, long instr
,
114 struct op_code_struct
*op
)
116 char *p
= strbuf (buf
);
119 switch ((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
))
151 case REG_TLBLO_MASK
:
154 case REG_TLBHI_MASK
:
157 case REG_TLBSX_MASK
:
167 if (((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
) & 0xE000)
170 sprintf (p
, "%spvr%d", register_prefix
,
171 (unsigned short)(((instr
& IMM_MASK
) >> IMM_LOW
)
172 ^ op
->immval_mask
) ^ REG_PVR_MASK
);
180 sprintf (p
, "%s%s", register_prefix
, spr
);
185 read_insn_microblaze (bfd_vma memaddr
,
186 struct disassemble_info
*info
,
187 struct op_code_struct
**opr
)
189 unsigned char ibytes
[4];
191 struct op_code_struct
* op
;
194 status
= info
->read_memory_func (memaddr
, ibytes
, 4, info
);
198 info
->memory_error_func (status
, memaddr
, info
);
202 if (info
->endian
== BFD_ENDIAN_BIG
)
203 inst
= (((unsigned) ibytes
[0] << 24) | (ibytes
[1] << 16)
204 | (ibytes
[2] << 8) | ibytes
[3]);
205 else if (info
->endian
== BFD_ENDIAN_LITTLE
)
206 inst
= (((unsigned) ibytes
[3] << 24) | (ibytes
[2] << 16)
207 | (ibytes
[1] << 8) | ibytes
[0]);
211 /* Just a linear search of the table. */
212 for (op
= opcodes
; op
->name
!= 0; op
++)
213 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
222 print_insn_microblaze (bfd_vma memaddr
, struct disassemble_info
* info
)
224 fprintf_ftype print_func
= info
->fprintf_func
;
225 void * stream
= info
->stream
;
226 unsigned long inst
, prev_inst
;
227 struct op_code_struct
* op
, *pop
;
229 bfd_boolean immfound
= FALSE
;
230 static bfd_vma prev_insn_addr
= -1; /* Init the prev insn addr. */
231 static int prev_insn_vma
= -1; /* Init the prev insn vma. */
232 int curr_insn_vma
= info
->buffer_vma
;
233 struct string_buf buf
;
236 info
->bytes_per_chunk
= 4;
238 inst
= read_insn_microblaze (memaddr
, info
, &op
);
242 if (prev_insn_vma
== curr_insn_vma
)
244 if (memaddr
-(info
->bytes_per_chunk
) == prev_insn_addr
)
246 prev_inst
= read_insn_microblaze (prev_insn_addr
, info
, &pop
);
249 if (pop
->instr
== imm
)
251 immval
= (get_int_field_imm (prev_inst
) << 16) & 0xffff0000;
262 /* Make curr insn as prev insn. */
263 prev_insn_addr
= memaddr
;
264 prev_insn_vma
= curr_insn_vma
;
266 if (op
->name
== NULL
)
267 print_func (stream
, ".short 0x%04x", (unsigned int) inst
);
270 print_func (stream
, "%s", op
->name
);
272 switch (op
->inst_type
)
274 case INST_TYPE_RD_R1_R2
:
275 print_func (stream
, "\t%s, %s, %s", get_field_rd (&buf
, inst
),
276 get_field_r1 (&buf
, inst
), get_field_r2 (&buf
, inst
));
278 case INST_TYPE_RD_R1_IMM
:
279 print_func (stream
, "\t%s, %s, %s", get_field_rd (&buf
, inst
),
280 get_field_r1 (&buf
, inst
), get_field_imm (&buf
, inst
));
281 if (info
->print_address_func
&& get_int_field_r1 (inst
) == 0
282 && info
->symbol_at_address_func
)
285 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
288 immval
= get_int_field_imm (inst
);
290 immval
|= 0xFFFF0000;
292 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
294 print_func (stream
, "\t// ");
295 info
->print_address_func (immval
, info
);
299 case INST_TYPE_RD_R1_IMM5
:
300 print_func (stream
, "\t%s, %s, %s", get_field_rd (&buf
, inst
),
301 get_field_r1 (&buf
, inst
), get_field_imm5 (&buf
, inst
));
303 case INST_TYPE_RD_RFSL
:
304 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
305 get_field_rfsl (&buf
, inst
));
307 case INST_TYPE_R1_RFSL
:
308 print_func (stream
, "\t%s, %s", get_field_r1 (&buf
, inst
),
309 get_field_rfsl (&buf
, inst
));
311 case INST_TYPE_RD_SPECIAL
:
312 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
313 get_field_special (&buf
, inst
, op
));
315 case INST_TYPE_SPECIAL_R1
:
316 print_func (stream
, "\t%s, %s", get_field_special (&buf
, inst
, op
),
317 get_field_r1 (&buf
, inst
));
319 case INST_TYPE_RD_R1
:
320 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
321 get_field_r1 (&buf
, inst
));
323 case INST_TYPE_R1_R2
:
324 print_func (stream
, "\t%s, %s", get_field_r1 (&buf
, inst
),
325 get_field_r2 (&buf
, inst
));
327 case INST_TYPE_R1_IMM
:
328 print_func (stream
, "\t%s, %s", get_field_r1 (&buf
, inst
),
329 get_field_imm (&buf
, inst
));
330 /* The non-pc relative instructions are returns, which shouldn't
331 have a label printed. */
332 if (info
->print_address_func
&& op
->inst_offset_type
== INST_PC_OFFSET
333 && info
->symbol_at_address_func
)
336 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
339 immval
= get_int_field_imm (inst
);
341 immval
|= 0xFFFF0000;
344 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
346 print_func (stream
, "\t// ");
347 info
->print_address_func (immval
, info
);
351 print_func (stream
, "\t\t// ");
352 print_func (stream
, "%x", immval
);
356 case INST_TYPE_RD_IMM
:
357 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
358 get_field_imm (&buf
, inst
));
359 if (info
->print_address_func
&& info
->symbol_at_address_func
)
362 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
365 immval
= get_int_field_imm (inst
);
367 immval
|= 0xFFFF0000;
369 if (op
->inst_offset_type
== INST_PC_OFFSET
)
370 immval
+= (int) memaddr
;
371 if (info
->symbol_at_address_func (immval
, info
))
373 print_func (stream
, "\t// ");
374 info
->print_address_func (immval
, info
);
379 print_func (stream
, "\t%s", get_field_imm (&buf
, inst
));
380 if (info
->print_address_func
&& info
->symbol_at_address_func
384 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
387 immval
= get_int_field_imm (inst
);
389 immval
|= 0xFFFF0000;
391 if (op
->inst_offset_type
== INST_PC_OFFSET
)
392 immval
+= (int) memaddr
;
393 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
395 print_func (stream
, "\t// ");
396 info
->print_address_func (immval
, info
);
398 else if (op
->inst_offset_type
== INST_PC_OFFSET
)
400 print_func (stream
, "\t\t// ");
401 print_func (stream
, "%x", immval
);
405 case INST_TYPE_RD_R2
:
406 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
407 get_field_r2 (&buf
, inst
));
410 print_func (stream
, "\t%s", get_field_r2 (&buf
, inst
));
413 print_func (stream
, "\t%s", get_field_r1 (&buf
, inst
));
415 case INST_TYPE_R1_R2_SPECIAL
:
416 print_func (stream
, "\t%s, %s", get_field_r1 (&buf
, inst
),
417 get_field_r2 (&buf
, inst
));
419 case INST_TYPE_RD_IMM15
:
420 print_func (stream
, "\t%s, %s", get_field_rd (&buf
, inst
),
421 get_field_imm15 (&buf
, inst
));
425 print_func (stream
, "\t%s", get_field_imm5_mbar (&buf
, inst
));
427 /* For mbar 16 or sleep insn. */
430 /* For tuqula instruction */
432 print_func (stream
, "\t%s", get_field_rd (&buf
, inst
));
435 print_func (stream
, "\t%s", get_field_rfsl (&buf
, inst
));
438 /* If the disassembler lags the instruction set. */
439 print_func (stream
, "\tundecoded operands, inst is 0x%04x",
440 (unsigned int) inst
);
445 /* Say how many bytes we consumed. */
449 enum microblaze_instr
450 get_insn_microblaze (long inst
,
451 bfd_boolean
*isunsignedimm
,
452 enum microblaze_instr_type
*insn_type
,
455 struct op_code_struct
* op
;
456 *isunsignedimm
= FALSE
;
458 /* Just a linear search of the table. */
459 for (op
= opcodes
; op
->name
!= 0; op
++)
460 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
467 *isunsignedimm
= (op
->inst_type
== INST_TYPE_RD_R1_UNSIGNED_IMM
);
468 *insn_type
= op
->instr_type
;
469 *delay_slots
= op
->delay_slots
;
474 enum microblaze_instr
475 microblaze_decode_insn (long insn
, int *rd
, int *ra
, int *rb
, int *immed
)
477 enum microblaze_instr op
;
479 enum microblaze_instr_type t2
;
482 op
= get_insn_microblaze (insn
, &t1
, &t2
, &t3
);
483 *rd
= (insn
& RD_MASK
) >> RD_LOW
;
484 *ra
= (insn
& RA_MASK
) >> RA_LOW
;
485 *rb
= (insn
& RB_MASK
) >> RB_LOW
;
486 t3
= (insn
& IMM_MASK
) >> IMM_LOW
;
492 microblaze_get_target_address (long inst
, bfd_boolean immfound
, int immval
,
493 long pcval
, long r1val
, long r2val
,
494 bfd_boolean
*targetvalid
,
495 bfd_boolean
*unconditionalbranch
)
497 struct op_code_struct
* op
;
500 *unconditionalbranch
= FALSE
;
501 /* Just a linear search of the table. */
502 for (op
= opcodes
; op
->name
!= 0; op
++)
503 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
508 *targetvalid
= FALSE
;
510 else if (op
->instr_type
== branch_inst
)
512 switch (op
->inst_type
)
515 *unconditionalbranch
= TRUE
;
517 case INST_TYPE_RD_R2
:
518 case INST_TYPE_R1_R2
:
521 if (op
->inst_offset_type
== INST_PC_OFFSET
)
525 *unconditionalbranch
= TRUE
;
527 case INST_TYPE_RD_IMM
:
528 case INST_TYPE_R1_IMM
:
531 targetaddr
= (immval
<< 16) & 0xffff0000;
532 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
536 targetaddr
= get_int_field_imm (inst
);
537 if (targetaddr
& 0x8000)
538 targetaddr
|= 0xFFFF0000;
540 if (op
->inst_offset_type
== INST_PC_OFFSET
)
545 *targetvalid
= FALSE
;
549 else if (op
->instr_type
== return_inst
)
553 targetaddr
= (immval
<< 16) & 0xffff0000;
554 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
558 targetaddr
= get_int_field_imm (inst
);
559 if (targetaddr
& 0x8000)
560 targetaddr
|= 0xFFFF0000;
566 *targetvalid
= FALSE
;