1 /* s12z-dis.c -- Freescale S12Z disassembly
2 Copyright (C) 2018-2019 Free Software Foundation, Inc.
4 This file is part of the GNU opcodes library.
6 This library is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 It is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
23 #include "bfd_stdint.h"
27 #include "opcode/s12z.h"
32 #include "disassemble.h"
36 struct mem_read_abstraction
38 struct mem_read_abstraction_base base
;
40 struct disassemble_info
* info
;
44 advance (struct mem_read_abstraction_base
*b
)
46 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
51 posn (struct mem_read_abstraction_base
*b
)
53 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
58 abstract_read_memory (struct mem_read_abstraction_base
*b
,
60 size_t n
, bfd_byte
*bytes
)
62 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
65 (*mra
->info
->read_memory_func
) (mra
->memaddr
+ offset
,
70 (*mra
->info
->memory_error_func
) (status
, mra
->memaddr
, mra
->info
);
76 /* Start of disassembly file. */
77 const struct reg registers
[S12Z_N_REGISTERS
] =
99 static const char *mnemonics
[] =
104 "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
105 "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
200 operand_separator (struct disassemble_info
*info
)
202 if ((info
->flags
& 0x2))
203 (*info
->fprintf_func
) (info
->stream
, ",");
205 (*info
->fprintf_func
) (info
->stream
, " ");
210 /* Render the symbol name whose value is ADDR + BASE or the adddress itself if
211 there is no symbol. If BASE is non zero, then the a PC relative adddress is
212 assumend (ie BASE is the value in the PC. */
214 decode_possible_symbol (bfd_vma addr
, bfd_vma base
,
215 struct disassemble_info
*info
, bool relative
)
217 const char *fmt
= relative
? "*%+" BFD_VMA_FMT
"d" : "%" BFD_VMA_FMT
"d";
218 if (!info
->symbol_at_address_func (addr
+ base
, info
))
220 (*info
->fprintf_func
) (info
->stream
, fmt
, addr
);
226 for (j
= 0; j
< info
->symtab_size
; ++j
)
228 sym
= info
->symtab
[j
];
229 if (bfd_asymbol_value (sym
) == addr
+ base
)
234 if (j
< info
->symtab_size
)
235 (*info
->fprintf_func
) (info
->stream
, "%s", bfd_asymbol_name (sym
));
237 (*info
->fprintf_func
) (info
->stream
, fmt
, addr
);
242 /* Emit the disassembled text for OPR */
244 opr_emit_disassembly (const struct operand
*opr
,
245 struct disassemble_info
*info
)
247 operand_separator (info
);
251 case OPND_CL_IMMEDIATE
:
252 (*info
->fprintf_func
) (info
->stream
, "#%d",
253 ((struct immediate_operand
*) opr
)->value
);
255 case OPND_CL_REGISTER
:
257 int r
= ((struct register_operand
*) opr
)->reg
;
258 (*info
->fprintf_func
) (info
->stream
, "%s", registers
[r
].name
);
261 case OPND_CL_REGISTER_ALL16
:
262 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL16b");
264 case OPND_CL_REGISTER_ALL
:
265 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL");
267 case OPND_CL_BIT_FIELD
:
268 (*info
->fprintf_func
) (info
->stream
, "#%d:%d",
269 ((struct bitfield_operand
*)opr
)->width
,
270 ((struct bitfield_operand
*)opr
)->offset
);
272 case OPND_CL_SIMPLE_MEMORY
:
274 struct simple_memory_operand
*mo
=
275 (struct simple_memory_operand
*) opr
;
276 decode_possible_symbol (mo
->addr
, mo
->base
, info
, mo
->relative
);
282 struct memory_operand
*mo
= (struct memory_operand
*) opr
;
283 (*info
->fprintf_func
) (info
->stream
, "%c", mo
->indirect
? '[' : '(');
286 assert (mo
->mutation
== OPND_RM_NONE
|| mo
->n_regs
== 1);
287 switch (mo
->mutation
)
289 case OPND_RM_PRE_DEC
:
292 case OPND_RM_PRE_INC
:
295 case OPND_RM_POST_DEC
:
298 case OPND_RM_POST_INC
:
304 (*info
->fprintf_func
) (info
->stream
, (mo
->n_regs
== 0) ? "%d" : "%d,", mo
->base_offset
);
309 (*info
->fprintf_func
) (info
->stream
, fmt
,
310 registers
[mo
->regs
[0]].name
);
313 if (mo
->n_regs
> used_reg
)
315 (*info
->fprintf_func
) (info
->stream
, ",%s",
316 registers
[mo
->regs
[used_reg
]].name
);
319 (*info
->fprintf_func
) (info
->stream
, "%c",
320 mo
->indirect
? ']' : ')');
326 static const char shift_size_table
[] = {
331 print_insn_s12z (bfd_vma memaddr
, struct disassemble_info
* info
)
334 enum optr
operator = OP_INVALID
;
337 /* The longest instruction in S12Z can have 6 operands.
338 (Most have 3 or less. Only PSH and PUL have so many. */
339 struct operand
*operands
[6];
341 struct mem_read_abstraction mra
;
342 mra
.base
.read
= (void *) abstract_read_memory
;
343 mra
.base
.advance
= advance
;
344 mra
.base
.posn
= posn
;
345 mra
.memaddr
= memaddr
;
350 decode_s12z (&operator, &osize
, &n_operands
, operands
,
351 (struct mem_read_abstraction_base
*) &mra
);
353 (info
->fprintf_func
) (info
->stream
, "%s", mnemonics
[(long)operator]);
355 /* Ship out size sufficies for those instructions which
360 for (o
= 0; o
< n_operands
; ++o
)
362 if (operands
[o
] && operands
[o
]->osize
!= -1)
366 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c", '.');
369 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c",
370 shift_size_table
[operands
[o
]->osize
]);
376 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, ".%c",
377 shift_size_table
[osize
]);
381 /* Ship out the operands. */
382 for (o
= 0; o
< n_operands
; ++o
)
385 opr_emit_disassembly (operands
[o
], mra
.info
);