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