1 /* s12z-dis.c -- Freescale S12Z disassembly
2 Copyright (C) 2018-2020 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"
30 #include "disassemble.h"
34 struct mem_read_abstraction
36 struct mem_read_abstraction_base base
;
38 struct disassemble_info
* info
;
42 advance (struct mem_read_abstraction_base
*b
)
44 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
49 posn (struct mem_read_abstraction_base
*b
)
51 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
56 abstract_read_memory (struct mem_read_abstraction_base
*b
,
58 size_t n
, bfd_byte
*bytes
)
60 struct mem_read_abstraction
*mra
= (struct mem_read_abstraction
*) b
;
62 int status
= (*mra
->info
->read_memory_func
) (mra
->memaddr
+ offset
,
64 return status
!= 0 ? -1 : 0;
67 /* Start of disassembly file. */
68 const struct reg registers
[S12Z_N_REGISTERS
] =
90 static const char *mnemonics
[] =
95 "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
96 "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
191 operand_separator (struct disassemble_info
*info
)
193 if ((info
->flags
& 0x2))
194 (*info
->fprintf_func
) (info
->stream
, ",");
196 (*info
->fprintf_func
) (info
->stream
, " ");
201 /* Render the symbol name whose value is ADDR + BASE or the adddress itself if
202 there is no symbol. If BASE is non zero, then the a PC relative adddress is
203 assumend (ie BASE is the value in the PC. */
205 decode_possible_symbol (bfd_vma addr
, bfd_vma base
,
206 struct disassemble_info
*info
, bool relative
)
208 const char *fmt
= relative
? "*%+" BFD_VMA_FMT
"d" : "%" BFD_VMA_FMT
"d";
209 if (!info
->symbol_at_address_func (addr
+ base
, info
))
211 (*info
->fprintf_func
) (info
->stream
, fmt
, addr
);
217 for (j
= 0; j
< info
->symtab_size
; ++j
)
219 sym
= info
->symtab
[j
];
220 if (bfd_asymbol_value (sym
) == addr
+ base
)
225 if (j
< info
->symtab_size
)
226 (*info
->fprintf_func
) (info
->stream
, "%s", bfd_asymbol_name (sym
));
228 (*info
->fprintf_func
) (info
->stream
, fmt
, addr
);
233 /* Emit the disassembled text for OPR */
235 opr_emit_disassembly (const struct operand
*opr
,
236 struct disassemble_info
*info
)
238 operand_separator (info
);
242 case OPND_CL_IMMEDIATE
:
243 (*info
->fprintf_func
) (info
->stream
, "#%d",
244 ((struct immediate_operand
*) opr
)->value
);
246 case OPND_CL_REGISTER
:
248 int r
= ((struct register_operand
*) opr
)->reg
;
250 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
251 (*info
->fprintf_func
) (info
->stream
, _("<illegal reg num>"));
253 (*info
->fprintf_func
) (info
->stream
, "%s", registers
[r
].name
);
256 case OPND_CL_REGISTER_ALL16
:
257 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL16b");
259 case OPND_CL_REGISTER_ALL
:
260 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL");
262 case OPND_CL_BIT_FIELD
:
263 (*info
->fprintf_func
) (info
->stream
, "#%d:%d",
264 ((struct bitfield_operand
*)opr
)->width
,
265 ((struct bitfield_operand
*)opr
)->offset
);
267 case OPND_CL_SIMPLE_MEMORY
:
269 struct simple_memory_operand
*mo
=
270 (struct simple_memory_operand
*) opr
;
271 decode_possible_symbol (mo
->addr
, mo
->base
, info
, mo
->relative
);
277 struct memory_operand
*mo
= (struct memory_operand
*) opr
;
278 (*info
->fprintf_func
) (info
->stream
, "%c", mo
->indirect
? '[' : '(');
281 assert (mo
->mutation
== OPND_RM_NONE
|| mo
->n_regs
== 1);
282 switch (mo
->mutation
)
284 case OPND_RM_PRE_DEC
:
287 case OPND_RM_PRE_INC
:
290 case OPND_RM_POST_DEC
:
293 case OPND_RM_POST_INC
:
299 (*info
->fprintf_func
) (info
->stream
, (mo
->n_regs
== 0) ? "%d" : "%d,", mo
->base_offset
);
307 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
308 (*info
->fprintf_func
) (info
->stream
, fmt
, _("<illegal reg num>"));
310 (*info
->fprintf_func
) (info
->stream
, fmt
, registers
[r
].name
);
314 if (mo
->n_regs
> used_reg
)
316 int r
= mo
->regs
[used_reg
];
318 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
319 (*info
->fprintf_func
) (info
->stream
, _("<illegal reg num>"));
321 (*info
->fprintf_func
) (info
->stream
, ",%s",
325 (*info
->fprintf_func
) (info
->stream
, "%c",
326 mo
->indirect
? ']' : ')');
332 #define S12Z_N_SIZES 4
333 static const char shift_size_table
[S12Z_N_SIZES
] =
339 print_insn_s12z (bfd_vma memaddr
, struct disassemble_info
* info
)
342 enum optr
operator = OP_INVALID
;
345 /* The longest instruction in S12Z can have 6 operands.
346 (Most have 3 or less. Only PSH and PUL have so many. */
347 struct operand
*operands
[6];
349 struct mem_read_abstraction mra
;
350 mra
.base
.read
= (void *) abstract_read_memory
;
351 mra
.base
.advance
= advance
;
352 mra
.base
.posn
= posn
;
353 mra
.memaddr
= memaddr
;
358 decode_s12z (&operator, &osize
, &n_operands
, operands
,
359 (struct mem_read_abstraction_base
*) &mra
);
361 (info
->fprintf_func
) (info
->stream
, "%s", mnemonics
[(long)operator]);
363 /* Ship out size sufficies for those instructions which
369 for (o
= 0; o
< n_operands
; ++o
)
371 if (operands
[o
] && operands
[o
]->osize
!= -1)
375 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c", '.');
379 osize
= operands
[o
]->osize
;
381 if (osize
< 0 || osize
>= S12Z_N_SIZES
)
382 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, _("<bad>"));
384 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c",
385 shift_size_table
[osize
]);
391 if (osize
< 0 || osize
>= S12Z_N_SIZES
)
392 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, _(".<bad>"));
394 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, ".%c",
395 shift_size_table
[osize
]);
398 /* Ship out the operands. */
399 for (o
= 0; o
< n_operands
; ++o
)
402 opr_emit_disassembly (operands
[o
], mra
.info
);