xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/s12z-dis.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
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