Coverage Report

Created: 2026-10-02 09:53

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