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