Coverage Report

Created: 2026-05-11 07:54

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