Coverage Report

Created: 2026-03-10 08:46

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