Coverage Report

Created: 2026-09-14 08:07

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