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