1 /* s12z-dis.c -- Freescale S12Z disassembly
2 Copyright (C) 2018-2023 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. */
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
,
65 (*mra
->info
->memory_error_func
) (status
, mra
->memaddr
+ offset
,
67 return status
!= 0 ? -1 : 0;
70 /* Start of disassembly file. */
71 const struct reg registers
[S12Z_N_REGISTERS
] =
93 static const char *mnemonics
[] =
98 "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
99 "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
194 operand_separator (struct disassemble_info
*info
)
196 if ((info
->flags
& 0x2))
197 (*info
->fprintf_func
) (info
->stream
, ",");
199 (*info
->fprintf_func
) (info
->stream
, " ");
204 /* Render the symbol name whose value is ADDR + BASE or the adddress itself if
205 there is no symbol. If BASE is non zero, then the a PC relative adddress is
206 assumend (ie BASE is the value in the PC. */
208 decode_possible_symbol (bfd_signed_vma addr
, bfd_vma base
,
209 struct disassemble_info
*info
, bool relative
)
211 const char *fmt
= relative
? "*%+" PRId64
: "%" PRId64
;
212 asymbol
*sym
= info
->symbol_at_address_func (addr
+ base
, info
);
215 (*info
->fprintf_func
) (info
->stream
, fmt
, (int64_t) addr
);
217 (*info
->fprintf_func
) (info
->stream
, "%s", bfd_asymbol_name (sym
));
221 /* Emit the disassembled text for OPR */
223 opr_emit_disassembly (const struct operand
*opr
,
224 struct disassemble_info
*info
)
226 operand_separator (info
);
230 case OPND_CL_IMMEDIATE
:
231 (*info
->fprintf_func
) (info
->stream
, "#%d",
232 ((struct immediate_operand
*) opr
)->value
);
234 case OPND_CL_REGISTER
:
236 int r
= ((struct register_operand
*) opr
)->reg
;
238 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
239 (*info
->fprintf_func
) (info
->stream
, _("<illegal reg num>"));
241 (*info
->fprintf_func
) (info
->stream
, "%s", registers
[r
].name
);
244 case OPND_CL_REGISTER_ALL16
:
245 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL16b");
247 case OPND_CL_REGISTER_ALL
:
248 (*info
->fprintf_func
) (info
->stream
, "%s", "ALL");
250 case OPND_CL_BIT_FIELD
:
251 (*info
->fprintf_func
) (info
->stream
, "#%d:%d",
252 ((struct bitfield_operand
*)opr
)->width
,
253 ((struct bitfield_operand
*)opr
)->offset
);
255 case OPND_CL_SIMPLE_MEMORY
:
257 struct simple_memory_operand
*mo
=
258 (struct simple_memory_operand
*) opr
;
259 decode_possible_symbol (mo
->addr
, mo
->base
, info
, mo
->relative
);
265 struct memory_operand
*mo
= (struct memory_operand
*) opr
;
266 (*info
->fprintf_func
) (info
->stream
, "%c", mo
->indirect
? '[' : '(');
269 assert (mo
->mutation
== OPND_RM_NONE
|| mo
->n_regs
== 1);
270 switch (mo
->mutation
)
272 case OPND_RM_PRE_DEC
:
275 case OPND_RM_PRE_INC
:
278 case OPND_RM_POST_DEC
:
281 case OPND_RM_POST_INC
:
287 (*info
->fprintf_func
) (info
->stream
, (mo
->n_regs
== 0) ? "%d" : "%d,", mo
->base_offset
);
295 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
296 (*info
->fprintf_func
) (info
->stream
, fmt
, _("<illegal reg num>"));
298 (*info
->fprintf_func
) (info
->stream
, fmt
, registers
[r
].name
);
302 if (mo
->n_regs
> used_reg
)
304 int r
= mo
->regs
[used_reg
];
306 if (r
< 0 || r
>= S12Z_N_REGISTERS
)
307 (*info
->fprintf_func
) (info
->stream
, _("<illegal reg num>"));
309 (*info
->fprintf_func
) (info
->stream
, ",%s",
313 (*info
->fprintf_func
) (info
->stream
, "%c",
314 mo
->indirect
? ']' : ')');
320 #define S12Z_N_SIZES 4
321 static const char shift_size_table
[S12Z_N_SIZES
] =
327 print_insn_s12z (bfd_vma memaddr
, struct disassemble_info
* info
)
330 enum optr
operator = OP_INVALID
;
333 /* The longest instruction in S12Z can have 6 operands.
334 (Most have 3 or less. Only PSH and PUL have so many. */
335 struct operand
*operands
[6];
337 struct mem_read_abstraction mra
;
338 mra
.base
.read
= (void *) abstract_read_memory
;
339 mra
.base
.advance
= advance
;
340 mra
.base
.posn
= posn
;
341 mra
.memaddr
= memaddr
;
346 decode_s12z (&operator, &osize
, &n_operands
, operands
,
347 (struct mem_read_abstraction_base
*) &mra
);
349 (info
->fprintf_func
) (info
->stream
, "%s", mnemonics
[(long)operator]);
351 /* Ship out size sufficies for those instructions which
357 for (o
= 0; o
< n_operands
; ++o
)
359 if (operands
[o
] && operands
[o
]->osize
!= -1)
363 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c", '.');
367 osize
= operands
[o
]->osize
;
369 if (osize
< 0 || osize
>= S12Z_N_SIZES
)
370 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, _("<bad>"));
372 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, "%c",
373 shift_size_table
[osize
]);
379 if (osize
< 0 || osize
>= S12Z_N_SIZES
)
380 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, _(".<bad>"));
382 (*mra
.info
->fprintf_func
) (mra
.info
->stream
, ".%c",
383 shift_size_table
[osize
]);
386 /* Ship out the operands. */
387 for (o
= 0; o
< n_operands
; ++o
)
390 opr_emit_disassembly (operands
[o
], mra
.info
);