1 /* Disassemble Xilinx microblaze instructions.
3 Copyright (C) 2009-2014 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. */
29 #include "microblaze-opc.h"
30 #include "microblaze-dis.h"
32 #define get_field_rd(instr) get_field (instr, RD_MASK, RD_LOW)
33 #define get_field_r1(instr) get_field (instr, RA_MASK, RA_LOW)
34 #define get_field_r2(instr) get_field (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)
41 get_field (long instr
, long mask
, unsigned short low
)
45 sprintf (tmpstr
, "%s%d", register_prefix
, (int)((instr
& mask
) >> low
));
46 return (strdup (tmpstr
));
50 get_field_imm (long instr
)
54 sprintf (tmpstr
, "%d", (short)((instr
& IMM_MASK
) >> IMM_LOW
));
55 return (strdup (tmpstr
));
59 get_field_imm5 (long instr
)
63 sprintf (tmpstr
, "%d", (short)((instr
& IMM5_MASK
) >> IMM_LOW
));
64 return (strdup (tmpstr
));
68 get_field_imm5_mbar (long instr
)
72 sprintf(tmpstr
, "%d", (short)((instr
& IMM5_MBAR_MASK
) >> IMM_MBAR
));
73 return(strdup(tmpstr
));
77 get_field_rfsl (long instr
)
81 sprintf (tmpstr
, "%s%d", fsl_register_prefix
,
82 (short)((instr
& RFSL_MASK
) >> IMM_LOW
));
83 return (strdup (tmpstr
));
87 get_field_imm15 (long instr
)
91 sprintf (tmpstr
, "%d", (short)((instr
& IMM15_MASK
) >> IMM_LOW
));
92 return (strdup (tmpstr
));
96 get_field_special (long instr
, struct op_code_struct
* op
)
101 switch ((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
))
131 strcpy (spr
, "tlbx");
133 case REG_TLBLO_MASK
:
134 strcpy (spr
, "tlblo");
136 case REG_TLBHI_MASK
:
137 strcpy (spr
, "tlbhi");
139 case REG_TLBSX_MASK
:
140 strcpy (spr
, "tlbsx");
149 if (((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
) & 0xE000)
152 sprintf (tmpstr
, "%spvr%d", register_prefix
,
153 (unsigned short)(((instr
& IMM_MASK
) >> IMM_LOW
)
154 ^ op
->immval_mask
) ^ REG_PVR_MASK
);
155 return (strdup (tmpstr
));
162 sprintf (tmpstr
, "%s%s", register_prefix
, spr
);
163 return (strdup (tmpstr
));
167 read_insn_microblaze (bfd_vma memaddr
,
168 struct disassemble_info
*info
,
169 struct op_code_struct
**opr
)
171 unsigned char ibytes
[4];
173 struct op_code_struct
* op
;
176 status
= info
->read_memory_func (memaddr
, ibytes
, 4, info
);
180 info
->memory_error_func (status
, memaddr
, info
);
184 if (info
->endian
== BFD_ENDIAN_BIG
)
185 inst
= (ibytes
[0] << 24) | (ibytes
[1] << 16) | (ibytes
[2] << 8) | ibytes
[3];
186 else if (info
->endian
== BFD_ENDIAN_LITTLE
)
187 inst
= (ibytes
[3] << 24) | (ibytes
[2] << 16) | (ibytes
[1] << 8) | ibytes
[0];
191 /* Just a linear search of the table. */
192 for (op
= opcodes
; op
->name
!= 0; op
++)
193 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
202 print_insn_microblaze (bfd_vma memaddr
, struct disassemble_info
* info
)
204 fprintf_ftype print_func
= info
->fprintf_func
;
205 void * stream
= info
->stream
;
206 unsigned long inst
, prev_inst
;
207 struct op_code_struct
* op
, *pop
;
209 bfd_boolean immfound
= FALSE
;
210 static bfd_vma prev_insn_addr
= -1; /* Init the prev insn addr. */
211 static int prev_insn_vma
= -1; /* Init the prev insn vma. */
212 int curr_insn_vma
= info
->buffer_vma
;
214 info
->bytes_per_chunk
= 4;
216 inst
= read_insn_microblaze (memaddr
, info
, &op
);
220 if (prev_insn_vma
== curr_insn_vma
)
222 if (memaddr
-(info
->bytes_per_chunk
) == prev_insn_addr
)
224 prev_inst
= read_insn_microblaze (prev_insn_addr
, info
, &pop
);
227 if (pop
->instr
== imm
)
229 immval
= (get_int_field_imm (prev_inst
) << 16) & 0xffff0000;
240 /* Make curr insn as prev insn. */
241 prev_insn_addr
= memaddr
;
242 prev_insn_vma
= curr_insn_vma
;
244 if (op
->name
== NULL
)
245 print_func (stream
, ".short 0x%04x", (unsigned int) inst
);
248 print_func (stream
, "%s", op
->name
);
250 switch (op
->inst_type
)
252 case INST_TYPE_RD_R1_R2
:
253 print_func (stream
, "\t%s, %s, %s", get_field_rd (inst
),
254 get_field_r1(inst
), get_field_r2 (inst
));
256 case INST_TYPE_RD_R1_IMM
:
257 print_func (stream
, "\t%s, %s, %s", get_field_rd (inst
),
258 get_field_r1(inst
), get_field_imm (inst
));
259 if (info
->print_address_func
&& get_int_field_r1 (inst
) == 0
260 && info
->symbol_at_address_func
)
263 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
266 immval
= get_int_field_imm (inst
);
268 immval
|= 0xFFFF0000;
270 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
272 print_func (stream
, "\t// ");
273 info
->print_address_func (immval
, info
);
277 case INST_TYPE_RD_R1_IMM5
:
278 print_func (stream
, "\t%s, %s, %s", get_field_rd (inst
),
279 get_field_r1(inst
), get_field_imm5 (inst
));
281 case INST_TYPE_RD_RFSL
:
282 print_func (stream
, "\t%s, %s", get_field_rd (inst
), get_field_rfsl (inst
));
284 case INST_TYPE_R1_RFSL
:
285 print_func (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_rfsl (inst
));
287 case INST_TYPE_RD_SPECIAL
:
288 print_func (stream
, "\t%s, %s", get_field_rd (inst
),
289 get_field_special (inst
, op
));
291 case INST_TYPE_SPECIAL_R1
:
292 print_func (stream
, "\t%s, %s", get_field_special (inst
, op
),
295 case INST_TYPE_RD_R1
:
296 print_func (stream
, "\t%s, %s", get_field_rd (inst
), get_field_r1 (inst
));
298 case INST_TYPE_R1_R2
:
299 print_func (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_r2 (inst
));
301 case INST_TYPE_R1_IMM
:
302 print_func (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_imm (inst
));
303 /* The non-pc relative instructions are returns, which shouldn't
304 have a label printed. */
305 if (info
->print_address_func
&& op
->inst_offset_type
== INST_PC_OFFSET
306 && info
->symbol_at_address_func
)
309 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
312 immval
= get_int_field_imm (inst
);
314 immval
|= 0xFFFF0000;
317 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
319 print_func (stream
, "\t// ");
320 info
->print_address_func (immval
, info
);
324 print_func (stream
, "\t\t// ");
325 print_func (stream
, "%x", immval
);
329 case INST_TYPE_RD_IMM
:
330 print_func (stream
, "\t%s, %s", get_field_rd (inst
), get_field_imm (inst
));
331 if (info
->print_address_func
&& info
->symbol_at_address_func
)
334 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
337 immval
= get_int_field_imm (inst
);
339 immval
|= 0xFFFF0000;
341 if (op
->inst_offset_type
== INST_PC_OFFSET
)
342 immval
+= (int) memaddr
;
343 if (info
->symbol_at_address_func (immval
, info
))
345 print_func (stream
, "\t// ");
346 info
->print_address_func (immval
, info
);
351 print_func (stream
, "\t%s", get_field_imm (inst
));
352 if (info
->print_address_func
&& info
->symbol_at_address_func
356 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
359 immval
= get_int_field_imm (inst
);
361 immval
|= 0xFFFF0000;
363 if (op
->inst_offset_type
== INST_PC_OFFSET
)
364 immval
+= (int) memaddr
;
365 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
367 print_func (stream
, "\t// ");
368 info
->print_address_func (immval
, info
);
370 else if (op
->inst_offset_type
== INST_PC_OFFSET
)
372 print_func (stream
, "\t\t// ");
373 print_func (stream
, "%x", immval
);
377 case INST_TYPE_RD_R2
:
378 print_func (stream
, "\t%s, %s", get_field_rd (inst
), get_field_r2 (inst
));
381 print_func (stream
, "\t%s", get_field_r2 (inst
));
384 print_func (stream
, "\t%s", get_field_r1 (inst
));
386 case INST_TYPE_R1_R2_SPECIAL
:
387 print_func (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_r2 (inst
));
389 case INST_TYPE_RD_IMM15
:
390 print_func (stream
, "\t%s, %s", get_field_rd (inst
), get_field_imm15 (inst
));
394 print_func (stream
, "\t%s", get_field_imm5_mbar (inst
));
396 /* For mbar 16 or sleep insn. */
399 /* For tuqula instruction */
401 print_func (stream
, "\t%s", get_field_rd (inst
));
404 print_func (stream
, "\t%s", get_field_rfsl (inst
));
407 /* If the disassembler lags the instruction set. */
408 print_func (stream
, "\tundecoded operands, inst is 0x%04x", (unsigned int) inst
);
413 /* Say how many bytes we consumed. */
417 enum microblaze_instr
418 get_insn_microblaze (long inst
,
419 bfd_boolean
*isunsignedimm
,
420 enum microblaze_instr_type
*insn_type
,
423 struct op_code_struct
* op
;
424 *isunsignedimm
= FALSE
;
426 /* Just a linear search of the table. */
427 for (op
= opcodes
; op
->name
!= 0; op
++)
428 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
435 *isunsignedimm
= (op
->inst_type
== INST_TYPE_RD_R1_UNSIGNED_IMM
);
436 *insn_type
= op
->instr_type
;
437 *delay_slots
= op
->delay_slots
;
442 enum microblaze_instr
443 microblaze_decode_insn (long insn
, int *rd
, int *ra
, int *rb
, int *immed
)
445 enum microblaze_instr op
;
447 enum microblaze_instr_type t2
;
450 op
= get_insn_microblaze (insn
, &t1
, &t2
, &t3
);
451 *rd
= (insn
& RD_MASK
) >> RD_LOW
;
452 *ra
= (insn
& RA_MASK
) >> RA_LOW
;
453 *rb
= (insn
& RB_MASK
) >> RB_LOW
;
454 t3
= (insn
& IMM_MASK
) >> IMM_LOW
;
460 microblaze_get_target_address (long inst
, bfd_boolean immfound
, int immval
,
461 long pcval
, long r1val
, long r2val
,
462 bfd_boolean
*targetvalid
,
463 bfd_boolean
*unconditionalbranch
)
465 struct op_code_struct
* op
;
468 *unconditionalbranch
= FALSE
;
469 /* Just a linear search of the table. */
470 for (op
= opcodes
; op
->name
!= 0; op
++)
471 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
476 *targetvalid
= FALSE
;
478 else if (op
->instr_type
== branch_inst
)
480 switch (op
->inst_type
)
483 *unconditionalbranch
= TRUE
;
485 case INST_TYPE_RD_R2
:
486 case INST_TYPE_R1_R2
:
489 if (op
->inst_offset_type
== INST_PC_OFFSET
)
493 *unconditionalbranch
= TRUE
;
495 case INST_TYPE_RD_IMM
:
496 case INST_TYPE_R1_IMM
:
499 targetaddr
= (immval
<< 16) & 0xffff0000;
500 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
504 targetaddr
= get_int_field_imm (inst
);
505 if (targetaddr
& 0x8000)
506 targetaddr
|= 0xFFFF0000;
508 if (op
->inst_offset_type
== INST_PC_OFFSET
)
513 *targetvalid
= FALSE
;
517 else if (op
->instr_type
== return_inst
)
521 targetaddr
= (immval
<< 16) & 0xffff0000;
522 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
526 targetaddr
= get_int_field_imm (inst
);
527 if (targetaddr
& 0x8000)
528 targetaddr
|= 0xFFFF0000;
534 *targetvalid
= FALSE
;