Coverage Report

Created: 2026-04-04 08:16

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