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