Coverage Report

Created: 2026-07-25 10:20

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
1.21M
{
44
1.21M
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
45
1.21M
  mra->memaddr ++;
46
1.21M
}
47
48
static bfd_vma
49
posn (struct mem_read_abstraction_base *b)
50
72.3k
{
51
72.3k
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
52
72.3k
  return mra->memaddr;
53
72.3k
}
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
3.45M
{
60
3.45M
  struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b;
61
62
3.45M
  int status = (*mra->info->read_memory_func) (mra->memaddr + offset,
63
3.45M
                 bytes, n, mra->info);
64
3.45M
  if (status != 0)
65
1.45k
    (*mra->info->memory_error_func) (status, mra->memaddr + offset,
66
1.45k
                                     mra->info);
67
3.45M
  return status != 0 ? -1 : 0;
68
3.45M
}
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
1.31M
{
196
1.31M
  if ((info->flags & 0x2))
197
831k
    (*info->fprintf_func) (info->stream, ",");
198
199
1.31M
  (*info->fprintf_func) (info->stream, " ");
200
201
1.31M
  info->flags |= 0x2;
202
1.31M
}
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
219k
{
211
219k
  const char *fmt = relative ? "*%+" PRId64 : "%" PRId64;
212
219k
  asymbol *sym = info->symbol_at_address_func (addr + base, info);
213
214
219k
  if (!sym)
215
219k
    (*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
219k
}
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
1.31M
{
226
1.31M
  operand_separator (info);
227
228
1.31M
  switch (opr->cl)
229
1.31M
    {
230
209k
    case OPND_CL_IMMEDIATE:
231
209k
      (*info->fprintf_func) (info->stream, "#%d",
232
209k
           ((struct immediate_operand *) opr)->value);
233
209k
      break;
234
671k
    case OPND_CL_REGISTER:
235
671k
      {
236
671k
        int r = ((struct register_operand*) opr)->reg;
237
238
671k
  if (r < 0 || r >= S12Z_N_REGISTERS)
239
339
    (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
240
671k
  else
241
671k
    (*info->fprintf_func) (info->stream, "%s", registers[r].name);
242
671k
      }
243
671k
      break;
244
835
    case OPND_CL_REGISTER_ALL16:
245
835
      (*info->fprintf_func) (info->stream, "%s", "ALL16b");
246
835
      break;
247
8.94k
    case OPND_CL_REGISTER_ALL:
248
8.94k
      (*info->fprintf_func) (info->stream, "%s", "ALL");
249
8.94k
      break;
250
847
    case OPND_CL_BIT_FIELD:
251
847
      (*info->fprintf_func) (info->stream, "#%d:%d",
252
847
                             ((struct bitfield_operand*)opr)->width,
253
847
                             ((struct bitfield_operand*)opr)->offset);
254
847
      break;
255
219k
    case OPND_CL_SIMPLE_MEMORY:
256
219k
      {
257
219k
        struct simple_memory_operand *mo =
258
219k
    (struct simple_memory_operand *) opr;
259
219k
  decode_possible_symbol (mo->addr, mo->base, info, mo->relative);
260
219k
      }
261
219k
      break;
262
199k
    case OPND_CL_MEMORY:
263
199k
      {
264
199k
        int used_reg = 0;
265
199k
        struct memory_operand *mo = (struct memory_operand *) opr;
266
199k
  (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '(');
267
268
199k
  const char *fmt;
269
199k
  assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1);
270
199k
  switch (mo->mutation)
271
199k
    {
272
1.57k
    case OPND_RM_PRE_DEC:
273
1.57k
      fmt = "-%s";
274
1.57k
      break;
275
7.11k
    case OPND_RM_PRE_INC:
276
7.11k
      fmt = "+%s";
277
7.11k
      break;
278
1.43k
    case OPND_RM_POST_DEC:
279
1.43k
      fmt = "%s-";
280
1.43k
      break;
281
9.73k
    case OPND_RM_POST_INC:
282
9.73k
      fmt = "%s+";
283
9.73k
      break;
284
179k
    case OPND_RM_NONE:
285
179k
    default:
286
179k
      if (mo->n_regs < 2)
287
129k
        (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset);
288
179k
      fmt = "%s";
289
179k
      break;
290
199k
    }
291
199k
  if (mo->n_regs > 0)
292
198k
    {
293
198k
      int r = mo->regs[0];
294
295
198k
      if (r < 0 || r >= S12Z_N_REGISTERS)
296
0
        (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
297
198k
      else
298
198k
        (*info->fprintf_func) (info->stream, fmt, registers[r].name);
299
198k
    }
300
199k
  used_reg = 1;
301
302
199k
        if (mo->n_regs > used_reg)
303
50.2k
          {
304
50.2k
      int r = mo->regs[used_reg];
305
306
50.2k
      if (r < 0 || r >= S12Z_N_REGISTERS)
307
0
        (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
308
50.2k
      else
309
50.2k
        (*info->fprintf_func) (info->stream, ",%s",
310
50.2k
             registers[r].name);
311
50.2k
          }
312
313
199k
  (*info->fprintf_func) (info->stream, "%c",
314
199k
             mo->indirect ? ']' : ')');
315
199k
      }
316
0
      break;
317
1.31M
    };
318
1.31M
}
319
320
141k
#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
1.20M
{
329
1.20M
  int o;
330
1.20M
  enum optr operator = OP_INVALID;
331
1.20M
  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
1.20M
  struct operand *operands[6];
336
337
1.20M
  struct mem_read_abstraction mra;
338
1.20M
  mra.base.read = (void *) abstract_read_memory ;
339
1.20M
  mra.base.advance = advance ;
340
1.20M
  mra.base.posn = posn;
341
1.20M
  mra.memaddr = memaddr;
342
1.20M
  mra.info = info;
343
344
1.20M
  short osize = -1;
345
1.20M
  int n_bytes =
346
1.20M
    decode_s12z (&operator, &osize, &n_operands, operands,
347
1.20M
     (struct mem_read_abstraction_base *) &mra);
348
349
1.20M
  (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]);
350
351
  /* Ship out size sufficies for those instructions which
352
     need them.  */
353
1.20M
  if (osize == -1)
354
1.13M
    {
355
1.13M
      bool suffix = false;
356
357
2.35M
      for (o = 0; o < n_operands; ++o)
358
1.21M
  {
359
1.21M
    if (operands[o] && operands[o]->osize != -1)
360
68.1k
      {
361
68.1k
        if (!suffix)
362
49.9k
    {
363
49.9k
      (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
364
49.9k
      suffix = true;
365
49.9k
    }
366
367
68.1k
        osize = operands[o]->osize;
368
369
68.1k
        if (osize < 0 || osize >= S12Z_N_SIZES)
370
0
    (*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
371
68.1k
        else
372
68.1k
    (*mra.info->fprintf_func) (mra.info->stream, "%c",
373
68.1k
             shift_size_table[osize]);
374
68.1k
      }
375
1.21M
  }
376
1.13M
    }
377
73.7k
  else
378
73.7k
    {
379
73.7k
      if (osize < 0 || osize >= S12Z_N_SIZES)
380
0
  (*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
381
73.7k
      else
382
73.7k
  (*mra.info->fprintf_func) (mra.info->stream, ".%c",
383
73.7k
           shift_size_table[osize]);
384
73.7k
    }
385
386
  /* Ship out the operands.  */
387
2.51M
  for (o = 0; o < n_operands; ++o)
388
1.31M
    {
389
1.31M
      if (operands[o])
390
1.31M
  opr_emit_disassembly (operands[o], mra.info);
391
1.31M
      free (operands[o]);
392
1.31M
    }
393
394
1.20M
  return n_bytes;
395
1.20M
}