]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/s12z-dis.c
972aad80bff79dfd094b426f5c6b59f2624ccba2
[thirdparty/binutils-gdb.git] / opcodes / s12z-dis.c
1 /* s12z-dis.c -- Freescale S12Z disassembly
2 Copyright (C) 2018-2022 Free Software Foundation, Inc.
3
4 This file is part of the GNU opcodes library.
5
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)
9 any later version.
10
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.
15
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. */
20
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdbool.h>
25 #include <assert.h>
26
27 #include "opcode/s12z.h"
28 #include "bfd.h"
29 #include "dis-asm.h"
30 #include "disassemble.h"
31 #include "s12z-opc.h"
32 #include "opintl.h"
33
34 struct mem_read_abstraction
35 {
36 struct mem_read_abstraction_base base;
37 bfd_vma memaddr;
38 struct disassemble_info* info;
39 };
40
41 static void
42 advance (struct mem_read_abstraction_base *b)
43 {
44 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
45 mra->memaddr ++;
46 }
47
48 static bfd_vma
49 posn (struct mem_read_abstraction_base *b)
50 {
51 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
52 return mra->memaddr;
53 }
54
55 static int
56 abstract_read_memory (struct mem_read_abstraction_base *b,
57 int offset,
58 size_t n, bfd_byte *bytes)
59 {
60 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
61
62 int status = (*mra->info->read_memory_func) (mra->memaddr + offset,
63 bytes, n, mra->info);
64 if (status != 0)
65 (*mra->info->memory_error_func) (status, mra->memaddr + offset,
66 mra->info);
67 return status != 0 ? -1 : 0;
68 }
69
70 /* Start of disassembly file. */
71 const struct reg registers[S12Z_N_REGISTERS] =
72 {
73 {"d2", 2},
74 {"d3", 2},
75 {"d4", 2},
76 {"d5", 2},
77
78 {"d0", 1},
79 {"d1", 1},
80
81 {"d6", 4},
82 {"d7", 4},
83
84 {"x", 3},
85 {"y", 3},
86 {"s", 3},
87 {"p", 3},
88 {"cch", 1},
89 {"ccl", 1},
90 {"ccw", 2}
91 };
92
93 static const char *mnemonics[] =
94 {
95 "!!invalid!!",
96 "psh",
97 "pul",
98 "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble",
99 "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble",
100 "sex",
101 "exg",
102 "lsl", "lsr",
103 "asl", "asr",
104 "rol", "ror",
105 "bfins", "bfext",
106
107 "trap",
108
109 "ld",
110 "st",
111 "cmp",
112
113 "stop",
114 "wai",
115 "sys",
116
117 "minu",
118 "mins",
119 "maxu",
120 "maxs",
121
122 "abs",
123 "adc",
124 "bit",
125 "sbc",
126 "rti",
127 "clb",
128 "eor",
129
130 "sat",
131
132 "nop",
133 "bgnd",
134 "brclr",
135 "brset",
136 "rts",
137 "lea",
138 "mov",
139
140 "bra",
141 "bsr",
142 "bhi",
143 "bls",
144 "bcc",
145 "bcs",
146 "bne",
147 "beq",
148 "bvc",
149 "bvs",
150 "bpl",
151 "bmi",
152 "bge",
153 "blt",
154 "bgt",
155 "ble",
156 "inc",
157 "clr",
158 "dec",
159
160 "add",
161 "sub",
162 "and",
163 "or",
164
165 "tfr",
166 "jmp",
167 "jsr",
168 "com",
169 "andcc",
170 "neg",
171 "orcc",
172 "bclr",
173 "bset",
174 "btgl",
175 "swi",
176
177 "mulu",
178 "divu",
179 "modu",
180 "macu",
181 "qmulu",
182
183 "muls",
184 "divs",
185 "mods",
186 "macs",
187 "qmuls",
188
189 NULL
190 };
191
192
193 static void
194 operand_separator (struct disassemble_info *info)
195 {
196 if ((info->flags & 0x2))
197 (*info->fprintf_func) (info->stream, ",");
198
199 (*info->fprintf_func) (info->stream, " ");
200
201 info->flags |= 0x2;
202 }
203
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. */
207 static void
208 decode_possible_symbol (bfd_vma addr, bfd_vma base,
209 struct disassemble_info *info, bool relative)
210 {
211 const char *fmt = relative ? "*%+" BFD_VMA_FMT "d" : "%" BFD_VMA_FMT "d";
212 asymbol *sym = info->symbol_at_address_func (addr + base, info);
213
214 if (!sym)
215 (*info->fprintf_func) (info->stream, fmt, addr);
216 else
217 (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym));
218 }
219
220
221 /* Emit the disassembled text for OPR */
222 static void
223 opr_emit_disassembly (const struct operand *opr,
224 struct disassemble_info *info)
225 {
226 operand_separator (info);
227
228 switch (opr->cl)
229 {
230 case OPND_CL_IMMEDIATE:
231 (*info->fprintf_func) (info->stream, "#%d",
232 ((struct immediate_operand *) opr)->value);
233 break;
234 case OPND_CL_REGISTER:
235 {
236 int r = ((struct register_operand*) opr)->reg;
237
238 if (r < 0 || r >= S12Z_N_REGISTERS)
239 (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
240 else
241 (*info->fprintf_func) (info->stream, "%s", registers[r].name);
242 }
243 break;
244 case OPND_CL_REGISTER_ALL16:
245 (*info->fprintf_func) (info->stream, "%s", "ALL16b");
246 break;
247 case OPND_CL_REGISTER_ALL:
248 (*info->fprintf_func) (info->stream, "%s", "ALL");
249 break;
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);
254 break;
255 case OPND_CL_SIMPLE_MEMORY:
256 {
257 struct simple_memory_operand *mo =
258 (struct simple_memory_operand *) opr;
259 decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
260 }
261 break;
262 case OPND_CL_MEMORY:
263 {
264 int used_reg = 0;
265 struct memory_operand *mo = (struct memory_operand *) opr;
266 (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
267
268 const char *fmt;
269 assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1);
270 switch (mo->mutation)
271 {
272 case OPND_RM_PRE_DEC:
273 fmt = "-%s";
274 break;
275 case OPND_RM_PRE_INC:
276 fmt = "+%s";
277 break;
278 case OPND_RM_POST_DEC:
279 fmt = "%s-";
280 break;
281 case OPND_RM_POST_INC:
282 fmt = "%s+";
283 break;
284 case OPND_RM_NONE:
285 default:
286 if (mo->n_regs < 2)
287 (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset);
288 fmt = "%s";
289 break;
290 }
291 if (mo->n_regs > 0)
292 {
293 int r = mo->regs[0];
294
295 if (r < 0 || r >= S12Z_N_REGISTERS)
296 (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
297 else
298 (*info->fprintf_func) (info->stream, fmt, registers[r].name);
299 }
300 used_reg = 1;
301
302 if (mo->n_regs > used_reg)
303 {
304 int r = mo->regs[used_reg];
305
306 if (r < 0 || r >= S12Z_N_REGISTERS)
307 (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
308 else
309 (*info->fprintf_func) (info->stream, ",%s",
310 registers[r].name);
311 }
312
313 (*info->fprintf_func) (info->stream, "%c",
314 mo->indirect ? ']' : ')');
315 }
316 break;
317 };
318 }
319
320 #define S12Z_N_SIZES 4
321 static const char shift_size_table[S12Z_N_SIZES] =
322 {
323 'b', 'w', 'p', 'l'
324 };
325
326 int
327 print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
328 {
329 int o;
330 enum optr operator = OP_INVALID;
331 int n_operands = 0;
332
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];
336
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;
342 mra.info = info;
343
344 short osize = -1;
345 int n_bytes =
346 decode_s12z (&operator, &osize, &n_operands, operands,
347 (struct mem_read_abstraction_base *) &mra);
348
349 (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
350
351 /* Ship out size sufficies for those instructions which
352 need them. */
353 if (osize == -1)
354 {
355 bool suffix = false;
356
357 for (o = 0; o < n_operands; ++o)
358 {
359 if (operands[o] && operands[o]->osize != -1)
360 {
361 if (!suffix)
362 {
363 (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
364 suffix = true;
365 }
366
367 osize = operands[o]->osize;
368
369 if (osize < 0 || osize >= S12Z_N_SIZES)
370 (*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
371 else
372 (*mra.info->fprintf_func) (mra.info->stream, "%c",
373 shift_size_table[osize]);
374 }
375 }
376 }
377 else
378 {
379 if (osize < 0 || osize >= S12Z_N_SIZES)
380 (*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
381 else
382 (*mra.info->fprintf_func) (mra.info->stream, ".%c",
383 shift_size_table[osize]);
384 }
385
386 /* Ship out the operands. */
387 for (o = 0; o < n_operands; ++o)
388 {
389 if (operands[o])
390 opr_emit_disassembly (operands[o], mra.info);
391 free (operands[o]);
392 }
393
394 return n_bytes;
395 }