1e6c7e151Schristos /* s12z-dis.c -- Freescale S12Z disassembly
2*c42dbd0eSchristos Copyright (C) 2018-2022 Free Software Foundation, Inc.
3e6c7e151Schristos
4e6c7e151Schristos This file is part of the GNU opcodes library.
5e6c7e151Schristos
6e6c7e151Schristos This library is free software; you can redistribute it and/or modify
7e6c7e151Schristos it under the terms of the GNU General Public License as published by
8e6c7e151Schristos the Free Software Foundation; either version 3, or (at your option)
9e6c7e151Schristos any later version.
10e6c7e151Schristos
11e6c7e151Schristos It is distributed in the hope that it will be useful, but WITHOUT
12e6c7e151Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13e6c7e151Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14e6c7e151Schristos License for more details.
15e6c7e151Schristos
16e6c7e151Schristos You should have received a copy of the GNU General Public License
17e6c7e151Schristos along with this program; if not, write to the Free Software
18e6c7e151Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19e6c7e151Schristos MA 02110-1301, USA. */
20e6c7e151Schristos
21e6c7e151Schristos #include "sysdep.h"
22e6c7e151Schristos #include <stdio.h>
23*c42dbd0eSchristos #include <stdint.h>
24e6c7e151Schristos #include <stdbool.h>
25e6c7e151Schristos #include <assert.h>
26e6c7e151Schristos
27867d70fcSchristos #include "opcode/s12z.h"
28e6c7e151Schristos #include "bfd.h"
29e6c7e151Schristos #include "dis-asm.h"
30e6c7e151Schristos #include "disassemble.h"
31867d70fcSchristos #include "s12z-opc.h"
32867d70fcSchristos #include "opintl.h"
33867d70fcSchristos
34867d70fcSchristos struct mem_read_abstraction
35867d70fcSchristos {
36867d70fcSchristos struct mem_read_abstraction_base base;
37867d70fcSchristos bfd_vma memaddr;
38867d70fcSchristos struct disassemble_info* info;
39867d70fcSchristos };
40867d70fcSchristos
41867d70fcSchristos static void
advance(struct mem_read_abstraction_base * b)42867d70fcSchristos advance (struct mem_read_abstraction_base *b)
43867d70fcSchristos {
44867d70fcSchristos struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
45867d70fcSchristos mra->memaddr ++;
46867d70fcSchristos }
47867d70fcSchristos
48867d70fcSchristos static bfd_vma
posn(struct mem_read_abstraction_base * b)49867d70fcSchristos posn (struct mem_read_abstraction_base *b)
50867d70fcSchristos {
51867d70fcSchristos struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
52867d70fcSchristos return mra->memaddr;
53867d70fcSchristos }
54e6c7e151Schristos
55e6c7e151Schristos static int
abstract_read_memory(struct mem_read_abstraction_base * b,int offset,size_t n,bfd_byte * bytes)56867d70fcSchristos abstract_read_memory (struct mem_read_abstraction_base *b,
57867d70fcSchristos int offset,
58867d70fcSchristos size_t n, bfd_byte *bytes)
59e6c7e151Schristos {
60867d70fcSchristos struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
61867d70fcSchristos
62*c42dbd0eSchristos int status = (*mra->info->read_memory_func) (mra->memaddr + offset,
63867d70fcSchristos bytes, n, mra->info);
64e6c7e151Schristos if (status != 0)
65*c42dbd0eSchristos (*mra->info->memory_error_func) (status, mra->memaddr + offset,
66*c42dbd0eSchristos mra->info);
67*c42dbd0eSchristos return status != 0 ? -1 : 0;
68e6c7e151Schristos }
69e6c7e151Schristos
70867d70fcSchristos /* Start of disassembly file. */
71e6c7e151Schristos const struct reg registers[S12Z_N_REGISTERS] =
72e6c7e151Schristos {
73e6c7e151Schristos {"d2", 2},
74e6c7e151Schristos {"d3", 2},
75e6c7e151Schristos {"d4", 2},
76e6c7e151Schristos {"d5", 2},
77e6c7e151Schristos
78e6c7e151Schristos {"d0", 1},
79e6c7e151Schristos {"d1", 1},
80e6c7e151Schristos
81e6c7e151Schristos {"d6", 4},
82e6c7e151Schristos {"d7", 4},
83e6c7e151Schristos
84e6c7e151Schristos {"x", 3},
85e6c7e151Schristos {"y", 3},
86e6c7e151Schristos {"s", 3},
87e6c7e151Schristos {"p", 3},
88e6c7e151Schristos {"cch", 1},
89e6c7e151Schristos {"ccl", 1},
90e6c7e151Schristos {"ccw", 2}
91e6c7e151Schristos };
92e6c7e151Schristos
93867d70fcSchristos static const char *mnemonics[] =
94e6c7e151Schristos {
95867d70fcSchristos "!!invalid!!",
96867d70fcSchristos "psh",
97867d70fcSchristos "pul",
98867d70fcSchristos "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
99867d70fcSchristos "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
100867d70fcSchristos "sex",
101867d70fcSchristos "exg",
102867d70fcSchristos "lsl", "lsr",
103867d70fcSchristos "asl", "asr",
104867d70fcSchristos "rol", "ror",
105867d70fcSchristos "bfins", "bfext",
106e6c7e151Schristos
107867d70fcSchristos "trap",
108e6c7e151Schristos
109867d70fcSchristos "ld",
110867d70fcSchristos "st",
111867d70fcSchristos "cmp",
112867d70fcSchristos
113867d70fcSchristos "stop",
114867d70fcSchristos "wai",
115867d70fcSchristos "sys",
116867d70fcSchristos
117867d70fcSchristos "minu",
118867d70fcSchristos "mins",
119867d70fcSchristos "maxu",
120867d70fcSchristos "maxs",
121867d70fcSchristos
122867d70fcSchristos "abs",
123867d70fcSchristos "adc",
124867d70fcSchristos "bit",
125867d70fcSchristos "sbc",
126867d70fcSchristos "rti",
127867d70fcSchristos "clb",
128867d70fcSchristos "eor",
129867d70fcSchristos
130867d70fcSchristos "sat",
131867d70fcSchristos
132867d70fcSchristos "nop",
133867d70fcSchristos "bgnd",
134867d70fcSchristos "brclr",
135867d70fcSchristos "brset",
136867d70fcSchristos "rts",
137867d70fcSchristos "lea",
138867d70fcSchristos "mov",
139867d70fcSchristos
140867d70fcSchristos "bra",
141867d70fcSchristos "bsr",
142867d70fcSchristos "bhi",
143867d70fcSchristos "bls",
144867d70fcSchristos "bcc",
145867d70fcSchristos "bcs",
146867d70fcSchristos "bne",
147867d70fcSchristos "beq",
148867d70fcSchristos "bvc",
149867d70fcSchristos "bvs",
150867d70fcSchristos "bpl",
151867d70fcSchristos "bmi",
152867d70fcSchristos "bge",
153867d70fcSchristos "blt",
154867d70fcSchristos "bgt",
155867d70fcSchristos "ble",
156867d70fcSchristos "inc",
157867d70fcSchristos "clr",
158867d70fcSchristos "dec",
159867d70fcSchristos
160867d70fcSchristos "add",
161867d70fcSchristos "sub",
162867d70fcSchristos "and",
163867d70fcSchristos "or",
164867d70fcSchristos
165867d70fcSchristos "tfr",
166867d70fcSchristos "jmp",
167867d70fcSchristos "jsr",
168867d70fcSchristos "com",
169867d70fcSchristos "andcc",
170867d70fcSchristos "neg",
171867d70fcSchristos "orcc",
172867d70fcSchristos "bclr",
173867d70fcSchristos "bset",
174867d70fcSchristos "btgl",
175867d70fcSchristos "swi",
176867d70fcSchristos
177867d70fcSchristos "mulu",
178867d70fcSchristos "divu",
179867d70fcSchristos "modu",
180867d70fcSchristos "macu",
181867d70fcSchristos "qmulu",
182867d70fcSchristos
183867d70fcSchristos "muls",
184867d70fcSchristos "divs",
185867d70fcSchristos "mods",
186867d70fcSchristos "macs",
187867d70fcSchristos "qmuls",
188867d70fcSchristos
189867d70fcSchristos NULL
190867d70fcSchristos };
191867d70fcSchristos
192867d70fcSchristos
193e6c7e151Schristos static void
operand_separator(struct disassemble_info * info)194867d70fcSchristos operand_separator (struct disassemble_info *info)
195e6c7e151Schristos {
196867d70fcSchristos if ((info->flags & 0x2))
197867d70fcSchristos (*info->fprintf_func) (info->stream, ",");
198867d70fcSchristos
199867d70fcSchristos (*info->fprintf_func) (info->stream, " ");
200867d70fcSchristos
201867d70fcSchristos info->flags |= 0x2;
202867d70fcSchristos }
203867d70fcSchristos
204867d70fcSchristos /* Render the symbol name whose value is ADDR + BASE or the adddress itself if
205867d70fcSchristos there is no symbol. If BASE is non zero, then the a PC relative adddress is
206867d70fcSchristos assumend (ie BASE is the value in the PC. */
207867d70fcSchristos static void
decode_possible_symbol(bfd_vma addr,bfd_vma base,struct disassemble_info * info,bool relative)208867d70fcSchristos decode_possible_symbol (bfd_vma addr, bfd_vma base,
209867d70fcSchristos struct disassemble_info *info, bool relative)
210e6c7e151Schristos {
211867d70fcSchristos const char *fmt = relative ? "*%+" BFD_VMA_FMT "d" : "%" BFD_VMA_FMT "d";
212*c42dbd0eSchristos asymbol *sym = info->symbol_at_address_func (addr + base, info);
213*c42dbd0eSchristos
214*c42dbd0eSchristos if (!sym)
215867d70fcSchristos (*info->fprintf_func) (info->stream, fmt, addr);
216e6c7e151Schristos else
217e6c7e151Schristos (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
218867d70fcSchristos }
219e6c7e151Schristos
220867d70fcSchristos
221867d70fcSchristos /* Emit the disassembled text for OPR */
222867d70fcSchristos static void
opr_emit_disassembly(const struct operand * opr,struct disassemble_info * info)223867d70fcSchristos opr_emit_disassembly (const struct operand *opr,
224867d70fcSchristos struct disassemble_info *info)
225867d70fcSchristos {
226867d70fcSchristos operand_separator (info);
227867d70fcSchristos
228867d70fcSchristos switch (opr->cl)
229867d70fcSchristos {
230867d70fcSchristos case OPND_CL_IMMEDIATE:
231867d70fcSchristos (*info->fprintf_func) (info->stream, "#%d",
232867d70fcSchristos ((struct immediate_operand *) opr)->value);
233e6c7e151Schristos break;
234867d70fcSchristos case OPND_CL_REGISTER:
235e6c7e151Schristos {
236867d70fcSchristos int r = ((struct register_operand*) opr)->reg;
237867d70fcSchristos
238867d70fcSchristos if (r < 0 || r >= S12Z_N_REGISTERS)
239867d70fcSchristos (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
240867d70fcSchristos else
241867d70fcSchristos (*info->fprintf_func) (info->stream, "%s", registers[r].name);
242867d70fcSchristos }
243e6c7e151Schristos break;
244867d70fcSchristos case OPND_CL_REGISTER_ALL16:
245867d70fcSchristos (*info->fprintf_func) (info->stream, "%s", "ALL16b");
246e6c7e151Schristos break;
247867d70fcSchristos case OPND_CL_REGISTER_ALL:
248867d70fcSchristos (*info->fprintf_func) (info->stream, "%s", "ALL");
249e6c7e151Schristos break;
250867d70fcSchristos case OPND_CL_BIT_FIELD:
251867d70fcSchristos (*info->fprintf_func) (info->stream, "#%d:%d",
252867d70fcSchristos ((struct bitfield_operand*)opr)->width,
253867d70fcSchristos ((struct bitfield_operand*)opr)->offset);
254e6c7e151Schristos break;
255867d70fcSchristos case OPND_CL_SIMPLE_MEMORY:
256e6c7e151Schristos {
257867d70fcSchristos struct simple_memory_operand *mo =
258867d70fcSchristos (struct simple_memory_operand *) opr;
259867d70fcSchristos decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
260e6c7e151Schristos }
261e6c7e151Schristos break;
262867d70fcSchristos case OPND_CL_MEMORY:
263e6c7e151Schristos {
264867d70fcSchristos int used_reg = 0;
265867d70fcSchristos struct memory_operand *mo = (struct memory_operand *) opr;
266867d70fcSchristos (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
267e6c7e151Schristos
268867d70fcSchristos const char *fmt;
269867d70fcSchristos assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1);
270867d70fcSchristos switch (mo->mutation)
271e6c7e151Schristos {
272867d70fcSchristos case OPND_RM_PRE_DEC:
273867d70fcSchristos fmt = "-%s";
274e6c7e151Schristos break;
275867d70fcSchristos case OPND_RM_PRE_INC:
276867d70fcSchristos fmt = "+%s";
277e6c7e151Schristos break;
278867d70fcSchristos case OPND_RM_POST_DEC:
279867d70fcSchristos fmt = "%s-";
280e6c7e151Schristos break;
281867d70fcSchristos case OPND_RM_POST_INC:
282867d70fcSchristos fmt = "%s+";
283e6c7e151Schristos break;
284867d70fcSchristos case OPND_RM_NONE:
285e6c7e151Schristos default:
286867d70fcSchristos if (mo->n_regs < 2)
287867d70fcSchristos (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset);
288867d70fcSchristos fmt = "%s";
289e6c7e151Schristos break;
290e6c7e151Schristos }
291867d70fcSchristos if (mo->n_regs > 0)
292e6c7e151Schristos {
293867d70fcSchristos int r = mo->regs[0];
294e6c7e151Schristos
295867d70fcSchristos if (r < 0 || r >= S12Z_N_REGISTERS)
296867d70fcSchristos (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
297e6c7e151Schristos else
298867d70fcSchristos (*info->fprintf_func) (info->stream, fmt, registers[r].name);
299e6c7e151Schristos }
300867d70fcSchristos used_reg = 1;
301e6c7e151Schristos
302867d70fcSchristos if (mo->n_regs > used_reg)
303e6c7e151Schristos {
304867d70fcSchristos int r = mo->regs[used_reg];
305867d70fcSchristos
306867d70fcSchristos if (r < 0 || r >= S12Z_N_REGISTERS)
307867d70fcSchristos (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
308e6c7e151Schristos else
309867d70fcSchristos (*info->fprintf_func) (info->stream, ",%s",
310867d70fcSchristos registers[r].name);
311867d70fcSchristos }
312867d70fcSchristos
313867d70fcSchristos (*info->fprintf_func) (info->stream, "%c",
314867d70fcSchristos mo->indirect ? ']' : ')');
315867d70fcSchristos }
316e6c7e151Schristos break;
317e6c7e151Schristos };
318e6c7e151Schristos }
319e6c7e151Schristos
320867d70fcSchristos #define S12Z_N_SIZES 4
321867d70fcSchristos static const char shift_size_table[S12Z_N_SIZES] =
322e6c7e151Schristos {
323e6c7e151Schristos 'b', 'w', 'p', 'l'
324e6c7e151Schristos };
325e6c7e151Schristos
326e6c7e151Schristos int
print_insn_s12z(bfd_vma memaddr,struct disassemble_info * info)327e6c7e151Schristos print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
328e6c7e151Schristos {
329867d70fcSchristos int o;
330867d70fcSchristos enum optr operator = OP_INVALID;
331867d70fcSchristos int n_operands = 0;
332e6c7e151Schristos
333867d70fcSchristos /* The longest instruction in S12Z can have 6 operands.
334867d70fcSchristos (Most have 3 or less. Only PSH and PUL have so many. */
335867d70fcSchristos struct operand *operands[6];
336867d70fcSchristos
337867d70fcSchristos struct mem_read_abstraction mra;
338867d70fcSchristos mra.base.read = (void *) abstract_read_memory ;
339867d70fcSchristos mra.base.advance = advance ;
340867d70fcSchristos mra.base.posn = posn;
341867d70fcSchristos mra.memaddr = memaddr;
342867d70fcSchristos mra.info = info;
343867d70fcSchristos
344867d70fcSchristos short osize = -1;
345867d70fcSchristos int n_bytes =
346867d70fcSchristos decode_s12z (&operator, &osize, &n_operands, operands,
347867d70fcSchristos (struct mem_read_abstraction_base *) &mra);
348867d70fcSchristos
349867d70fcSchristos (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
350867d70fcSchristos
351867d70fcSchristos /* Ship out size sufficies for those instructions which
352867d70fcSchristos need them. */
353867d70fcSchristos if (osize == -1)
354e6c7e151Schristos {
355867d70fcSchristos bool suffix = false;
356867d70fcSchristos
357867d70fcSchristos for (o = 0; o < n_operands; ++o)
358867d70fcSchristos {
359867d70fcSchristos if (operands[o] && operands[o]->osize != -1)
360867d70fcSchristos {
361867d70fcSchristos if (!suffix)
362867d70fcSchristos {
363867d70fcSchristos (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
364867d70fcSchristos suffix = true;
365e6c7e151Schristos }
366867d70fcSchristos
367867d70fcSchristos osize = operands[o]->osize;
368867d70fcSchristos
369867d70fcSchristos if (osize < 0 || osize >= S12Z_N_SIZES)
370867d70fcSchristos (*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
371e6c7e151Schristos else
372867d70fcSchristos (*mra.info->fprintf_func) (mra.info->stream, "%c",
373867d70fcSchristos shift_size_table[osize]);
374e6c7e151Schristos }
375e6c7e151Schristos }
376e6c7e151Schristos }
377e6c7e151Schristos else
378e6c7e151Schristos {
379867d70fcSchristos if (osize < 0 || osize >= S12Z_N_SIZES)
380867d70fcSchristos (*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
381e6c7e151Schristos else
382867d70fcSchristos (*mra.info->fprintf_func) (mra.info->stream, ".%c",
383867d70fcSchristos shift_size_table[osize]);
384867d70fcSchristos }
385867d70fcSchristos
386867d70fcSchristos /* Ship out the operands. */
387867d70fcSchristos for (o = 0; o < n_operands; ++o)
388e6c7e151Schristos {
389867d70fcSchristos if (operands[o])
390867d70fcSchristos opr_emit_disassembly (operands[o], mra.info);
391867d70fcSchristos free (operands[o]);
392e6c7e151Schristos }
393e6c7e151Schristos
394867d70fcSchristos return n_bytes;
395e6c7e151Schristos }
396