Coverage Report

Created: 2026-07-12 09:22

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