1 /* Disassemble Xilinx microblaze instructions.
3 Copyright 2009 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 "microblaze-opc.h"
31 #define get_field_rd(instr) get_field (instr, RD_MASK, RD_LOW)
32 #define get_field_r1(instr) get_field (instr, RA_MASK, RA_LOW)
33 #define get_field_r2(instr) get_field (instr, RB_MASK, RB_LOW)
34 #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
35 #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
38 enum microblaze_instr
get_insn_microblaze (long, bfd_boolean
*,
39 enum microblaze_instr_type
*, short *);
40 unsigned long microblaze_get_target_address (long, bfd_boolean
, int, long, long,
41 long, bfd_boolean
*, bfd_boolean
*);
42 enum microblaze_instr
microblaze_decode_insn (long insn
, int *rd
, int *ra
, int *rb
, int *imm
);
45 get_field (long instr
, long mask
, unsigned short low
)
49 sprintf (tmpstr
, "%s%d", register_prefix
, (int)((instr
& mask
) >> low
));
50 return (strdup (tmpstr
));
54 get_field_imm (long instr
)
58 sprintf (tmpstr
, "%d", (short)((instr
& IMM_MASK
) >> IMM_LOW
));
59 return (strdup (tmpstr
));
63 get_field_imm5 (long instr
)
67 sprintf (tmpstr
, "%d", (short)((instr
& IMM5_MASK
) >> IMM_LOW
));
68 return (strdup (tmpstr
));
72 get_field_rfsl (long instr
)
76 sprintf (tmpstr
, "%s%d", fsl_register_prefix
,
77 (short)((instr
& RFSL_MASK
) >> IMM_LOW
));
78 return (strdup (tmpstr
));
82 get_field_imm15 (long instr
)
86 sprintf (tmpstr
, "%d", (short)((instr
& IMM15_MASK
) >> IMM_LOW
));
87 return (strdup (tmpstr
));
91 get_field_special (long instr
, struct op_code_struct
* op
)
96 switch ((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
))
126 strcpy (spr
, "tlbx");
128 case REG_TLBLO_MASK
:
129 strcpy (spr
, "tlblo");
131 case REG_TLBHI_MASK
:
132 strcpy (spr
, "tlbhi");
134 case REG_TLBSX_MASK
:
135 strcpy (spr
, "tlbsx");
138 if (((((instr
& IMM_MASK
) >> IMM_LOW
) ^ op
->immval_mask
) & 0xE000)
141 sprintf (tmpstr
, "%spvr%d", register_prefix
,
142 (unsigned short)(((instr
& IMM_MASK
) >> IMM_LOW
)
143 ^ op
->immval_mask
) ^ REG_PVR_MASK
);
144 return (strdup (tmpstr
));
151 sprintf (tmpstr
, "%s%s", register_prefix
, spr
);
152 return (strdup (tmpstr
));
156 read_insn_microblaze (bfd_vma memaddr
,
157 struct disassemble_info
*info
,
158 struct op_code_struct
**opr
)
160 unsigned char ibytes
[4];
162 struct op_code_struct
* op
;
165 status
= info
->read_memory_func (memaddr
, ibytes
, 4, info
);
169 info
->memory_error_func (status
, memaddr
, info
);
173 if (info
->endian
== BFD_ENDIAN_BIG
)
174 inst
= (ibytes
[0] << 24) | (ibytes
[1] << 16) | (ibytes
[2] << 8) | ibytes
[3];
175 else if (info
->endian
== BFD_ENDIAN_LITTLE
)
176 inst
= (ibytes
[3] << 24) | (ibytes
[2] << 16) | (ibytes
[1] << 8) | ibytes
[0];
180 /* Just a linear search of the table. */
181 for (op
= opcodes
; op
->name
!= 0; op
++)
182 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
191 print_insn_microblaze (bfd_vma memaddr
, struct disassemble_info
* info
)
193 fprintf_ftype fprintf
= info
->fprintf_func
;
194 void * stream
= info
->stream
;
195 unsigned long inst
, prev_inst
;
196 struct op_code_struct
* op
, *pop
;
198 bfd_boolean immfound
= FALSE
;
199 static bfd_vma prev_insn_addr
= -1; /* Init the prev insn addr. */
200 static int prev_insn_vma
= -1; /* Init the prev insn vma. */
201 int curr_insn_vma
= info
->buffer_vma
;
203 info
->bytes_per_chunk
= 4;
205 inst
= read_insn_microblaze (memaddr
, info
, &op
);
209 if (prev_insn_vma
== curr_insn_vma
)
211 if (memaddr
-(info
->bytes_per_chunk
) == prev_insn_addr
)
213 prev_inst
= read_insn_microblaze (prev_insn_addr
, info
, &pop
);
216 if (pop
->instr
== imm
)
218 immval
= (get_int_field_imm (prev_inst
) << 16) & 0xffff0000;
229 /* Make curr insn as prev insn. */
230 prev_insn_addr
= memaddr
;
231 prev_insn_vma
= curr_insn_vma
;
233 if (op
->name
== NULL
)
234 fprintf (stream
, ".short 0x%04x", inst
);
237 fprintf (stream
, "%s", op
->name
);
239 switch (op
->inst_type
)
241 case INST_TYPE_RD_R1_R2
:
242 fprintf (stream
, "\t%s, %s, %s", get_field_rd (inst
),
243 get_field_r1(inst
), get_field_r2 (inst
));
245 case INST_TYPE_RD_R1_IMM
:
246 fprintf (stream
, "\t%s, %s, %s", get_field_rd (inst
),
247 get_field_r1(inst
), get_field_imm (inst
));
248 if (info
->print_address_func
&& get_int_field_r1 (inst
) == 0
249 && info
->symbol_at_address_func
)
252 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
255 immval
= get_int_field_imm (inst
);
257 immval
|= 0xFFFF0000;
259 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
261 fprintf (stream
, "\t// ");
262 info
->print_address_func (immval
, info
);
266 case INST_TYPE_RD_R1_IMM5
:
267 fprintf (stream
, "\t%s, %s, %s", get_field_rd (inst
),
268 get_field_r1(inst
), get_field_imm5 (inst
));
270 case INST_TYPE_RD_RFSL
:
271 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_rfsl (inst
));
273 case INST_TYPE_R1_RFSL
:
274 fprintf (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_rfsl (inst
));
276 case INST_TYPE_RD_SPECIAL
:
277 fprintf (stream
, "\t%s, %s", get_field_rd (inst
),
278 get_field_special (inst
, op
));
280 case INST_TYPE_SPECIAL_R1
:
281 fprintf (stream
, "\t%s, %s", get_field_special (inst
, op
),
284 case INST_TYPE_RD_R1
:
285 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_r1 (inst
));
287 case INST_TYPE_R1_R2
:
288 fprintf (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_r2 (inst
));
290 case INST_TYPE_R1_IMM
:
291 fprintf (stream
, "\t%s, %s", get_field_r1 (inst
), get_field_imm (inst
));
292 /* The non-pc relative instructions are returns, which shouldn't
293 have a label printed. */
294 if (info
->print_address_func
&& op
->inst_offset_type
== INST_PC_OFFSET
295 && info
->symbol_at_address_func
)
298 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
301 immval
= get_int_field_imm (inst
);
303 immval
|= 0xFFFF0000;
306 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
308 fprintf (stream
, "\t// ");
309 info
->print_address_func (immval
, info
);
313 fprintf (stream
, "\t\t// ");
314 fprintf (stream
, "%x", immval
);
318 case INST_TYPE_RD_IMM
:
319 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_imm (inst
));
320 if (info
->print_address_func
&& info
->symbol_at_address_func
)
323 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
326 immval
= get_int_field_imm (inst
);
328 immval
|= 0xFFFF0000;
330 if (op
->inst_offset_type
== INST_PC_OFFSET
)
331 immval
+= (int) memaddr
;
332 if (info
->symbol_at_address_func (immval
, info
))
334 fprintf (stream
, "\t// ");
335 info
->print_address_func (immval
, info
);
340 fprintf (stream
, "\t%s", get_field_imm (inst
));
341 if (info
->print_address_func
&& info
->symbol_at_address_func
345 immval
|= (get_int_field_imm (inst
) & 0x0000ffff);
348 immval
= get_int_field_imm (inst
);
350 immval
|= 0xFFFF0000;
352 if (op
->inst_offset_type
== INST_PC_OFFSET
)
353 immval
+= (int) memaddr
;
354 if (immval
> 0 && info
->symbol_at_address_func (immval
, info
))
356 fprintf (stream
, "\t// ");
357 info
->print_address_func (immval
, info
);
359 else if (op
->inst_offset_type
== INST_PC_OFFSET
)
361 fprintf (stream
, "\t\t// ");
362 fprintf (stream
, "%x", immval
);
366 case INST_TYPE_RD_R2
:
367 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_r2 (inst
));
370 fprintf (stream
, "\t%s", get_field_r2 (inst
));
373 fprintf (stream
, "\t%s", get_field_r1 (inst
));
375 case INST_TYPE_RD_R1_SPECIAL
:
376 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_r2 (inst
));
378 case INST_TYPE_RD_IMM15
:
379 fprintf (stream
, "\t%s, %s", get_field_rd (inst
), get_field_imm15 (inst
));
381 /* For tuqula instruction */
383 fprintf (stream
, "\t%s", get_field_rd (inst
));
386 fprintf (stream
, "\t%s", get_field_rfsl (inst
));
389 /* If the disassembler lags the instruction set. */
390 fprintf (stream
, "\tundecoded operands, inst is 0x%04x", inst
);
395 /* Say how many bytes we consumed. */
399 enum microblaze_instr
400 get_insn_microblaze (long inst
,
401 bfd_boolean
*isunsignedimm
,
402 enum microblaze_instr_type
*insn_type
,
405 struct op_code_struct
* op
;
406 *isunsignedimm
= FALSE
;
408 /* Just a linear search of the table. */
409 for (op
= opcodes
; op
->name
!= 0; op
++)
410 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
417 *isunsignedimm
= (op
->inst_type
== INST_TYPE_RD_R1_UNSIGNED_IMM
);
418 *insn_type
= op
->instr_type
;
419 *delay_slots
= op
->delay_slots
;
424 enum microblaze_instr
425 microblaze_decode_insn (long insn
, int *rd
, int *ra
, int *rb
, int *imm
)
427 enum microblaze_instr op
;
429 enum microblaze_instr_type t2
;
432 op
= get_insn_microblaze (insn
, &t1
, &t2
, &t3
);
433 *rd
= (insn
& RD_MASK
) >> RD_LOW
;
434 *ra
= (insn
& RA_MASK
) >> RA_LOW
;
435 *rb
= (insn
& RB_MASK
) >> RB_LOW
;
436 t3
= (insn
& IMM_MASK
) >> IMM_LOW
;
442 microblaze_get_target_address (long inst
, bfd_boolean immfound
, int immval
,
443 long pcval
, long r1val
, long r2val
,
444 bfd_boolean
*targetvalid
,
445 bfd_boolean
*unconditionalbranch
)
447 struct op_code_struct
* op
;
450 *unconditionalbranch
= FALSE
;
451 /* Just a linear search of the table. */
452 for (op
= opcodes
; op
->name
!= 0; op
++)
453 if (op
->bit_sequence
== (inst
& op
->opcode_mask
))
458 *targetvalid
= FALSE
;
460 else if (op
->instr_type
== branch_inst
)
462 switch (op
->inst_type
)
465 *unconditionalbranch
= TRUE
;
467 case INST_TYPE_RD_R2
:
468 case INST_TYPE_R1_R2
:
471 if (op
->inst_offset_type
== INST_PC_OFFSET
)
475 *unconditionalbranch
= TRUE
;
477 case INST_TYPE_RD_IMM
:
478 case INST_TYPE_R1_IMM
:
481 targetaddr
= (immval
<< 16) & 0xffff0000;
482 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
486 targetaddr
= get_int_field_imm (inst
);
487 if (targetaddr
& 0x8000)
488 targetaddr
|= 0xFFFF0000;
490 if (op
->inst_offset_type
== INST_PC_OFFSET
)
495 *targetvalid
= FALSE
;
499 else if (op
->instr_type
== return_inst
)
503 targetaddr
= (immval
<< 16) & 0xffff0000;
504 targetaddr
|= (get_int_field_imm (inst
) & 0x0000ffff);
508 targetaddr
= get_int_field_imm (inst
);
509 if (targetaddr
& 0x8000)
510 targetaddr
|= 0xFFFF0000;
516 *targetvalid
= FALSE
;