Coverage Report

Created: 2026-07-12 09:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/opcodes/pdp11-dis.c
Line
Count
Source
1
/* Print DEC PDP-11 instructions.
2
   Copyright (C) 2001-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 "disassemble.h"
23
#include "opcode/pdp11.h"
24
25
170k
#define AFTER_INSTRUCTION "\t"
26
131k
#define OPERAND_SEPARATOR ", "
27
28
21.2k
#define JUMP  0x1000  /* Flag that this operand is used in a jump.  */
29
30
1.20M
#define FPRINTF (*info->fprintf_func)
31
1.20M
#define F info->stream
32
33
/* Sign-extend a 16-bit number in an int.  */
34
74.9k
#define sign_extend(x) ((((x) & 0xffff) ^ 0x8000) - 0x8000)
35
36
static int
37
read_word (bfd_vma memaddr, int *word, disassemble_info *info)
38
260k
{
39
260k
  int status;
40
260k
  bfd_byte x[2];
41
42
260k
  status = (*info->read_memory_func) (memaddr, x, 2, info);
43
260k
  if (status != 0)
44
262
    return -1;
45
46
260k
  *word = x[1] << 8 | x[0];
47
260k
  return 0;
48
260k
}
49
50
static void
51
print_signed_octal (int n, disassemble_info *info)
52
46.0k
{
53
46.0k
  if (n < 0)
54
19.3k
    FPRINTF (F, "-%o", -n);
55
26.6k
  else
56
26.6k
    FPRINTF (F, "%o", n);
57
46.0k
}
58
59
static void
60
print_reg (int reg, disassemble_info *info)
61
233k
{
62
  /* Mask off the addressing mode, if any.  */
63
233k
  reg &= 7;
64
65
233k
  switch (reg)
66
233k
    {
67
199k
    case 0: case 1: case 2: case 3: case 4: case 5:
68
199k
    FPRINTF (F, "r%d", reg); break;
69
21.4k
    case 6: FPRINTF (F, "sp"); break;
70
12.6k
    case 7: FPRINTF (F, "pc"); break;
71
0
    default: ;  /* error */
72
233k
    }
73
233k
}
74
75
static void
76
print_freg (int freg, disassemble_info *info)
77
22.3k
{
78
22.3k
  FPRINTF (F, "fr%d", freg);
79
22.3k
}
80
81
static int
82
print_operand (bfd_vma *memaddr, int code, disassemble_info *info)
83
238k
{
84
238k
  int mode = (code >> 3) & 7;
85
238k
  int reg = code & 7;
86
238k
  int disp;
87
88
238k
  switch (mode)
89
238k
    {
90
49.8k
    case 0:
91
49.8k
      print_reg (reg, info);
92
49.8k
      break;
93
23.4k
    case 1:
94
23.4k
      FPRINTF (F, "(");
95
23.4k
      print_reg (reg, info);
96
23.4k
      FPRINTF (F, ")");
97
23.4k
      break;
98
25.3k
    case 2:
99
25.3k
      if (reg == 7)
100
2.69k
  {
101
2.69k
    int data;
102
103
2.69k
    if (read_word (*memaddr, &data, info) < 0)
104
7
      return -1;
105
2.69k
    FPRINTF (F, "$");
106
2.69k
    print_signed_octal (sign_extend (data), info);
107
2.69k
    *memaddr += 2;
108
2.69k
  }
109
22.6k
      else
110
22.6k
  {
111
22.6k
    FPRINTF (F, "(");
112
22.6k
    print_reg (reg, info);
113
22.6k
    FPRINTF (F, ")+");
114
22.6k
  }
115
25.3k
  break;
116
25.3k
    case 3:
117
21.1k
      if (reg == 7)
118
1.55k
  {
119
1.55k
    int address;
120
121
1.55k
    if (read_word (*memaddr, &address, info) < 0)
122
4
      return -1;
123
1.55k
    FPRINTF (F, "*$%o", address);
124
1.55k
    *memaddr += 2;
125
1.55k
  }
126
19.6k
      else
127
19.6k
  {
128
19.6k
    FPRINTF (F, "*(");
129
19.6k
    print_reg (reg, info);
130
19.6k
    FPRINTF (F, ")+");
131
19.6k
  }
132
21.1k
  break;
133
32.6k
    case 4:
134
32.6k
      FPRINTF (F, "-(");
135
32.6k
      print_reg (reg, info);
136
32.6k
      FPRINTF (F, ")");
137
32.6k
      break;
138
28.2k
    case 5:
139
28.2k
      FPRINTF (F, "*-(");
140
28.2k
      print_reg (reg, info);
141
28.2k
      FPRINTF (F, ")");
142
28.2k
      break;
143
25.5k
    case 6:
144
57.6k
    case 7:
145
57.6k
      if (read_word (*memaddr, &disp, info) < 0)
146
82
  return -1;
147
57.5k
      *memaddr += 2;
148
57.5k
      if (reg == 7)
149
14.2k
  {
150
14.2k
    bfd_vma address = *memaddr + sign_extend (disp);
151
152
14.2k
    if (mode == 7)
153
11.6k
      FPRINTF (F, "*");
154
14.2k
    if (!(code & JUMP))
155
13.9k
      FPRINTF (F, "$");
156
14.2k
    (*info->print_address_func) (address, info);
157
14.2k
  }
158
43.3k
      else
159
43.3k
  {
160
43.3k
    if (mode == 7)
161
20.4k
      FPRINTF (F, "*");
162
43.3k
    print_signed_octal (sign_extend (disp), info);
163
43.3k
    FPRINTF (F, "(");
164
43.3k
    print_reg (reg, info);
165
43.3k
    FPRINTF (F, ")");
166
43.3k
  }
167
57.5k
      break;
168
238k
    }
169
170
238k
  return 0;
171
238k
}
172
173
static int
174
print_foperand (bfd_vma *memaddr, int code, disassemble_info *info)
175
17.7k
{
176
17.7k
  int mode = (code >> 3) & 7;
177
17.7k
  int reg = code & 7;
178
179
17.7k
  if (mode == 0)
180
2.53k
    print_freg (reg, info);
181
15.2k
  else
182
15.2k
    return print_operand (memaddr, code, info);
183
184
2.53k
  return 0;
185
17.7k
}
186
187
/* Print the PDP-11 instruction at address MEMADDR in debugged memory,
188
   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
189
190
int
191
print_insn_pdp11 (bfd_vma memaddr, disassemble_info *info)
192
198k
{
193
198k
  bfd_vma start_memaddr = memaddr;
194
198k
  int opcode;
195
198k
  int src, dst;
196
198k
  int i;
197
198
198k
  info->bytes_per_line = 6;
199
198k
  info->bytes_per_chunk = 2;
200
198k
  info->display_endian = BFD_ENDIAN_LITTLE;
201
202
198k
  if (read_word (memaddr, &opcode, info) != 0)
203
169
    return -1;
204
198k
  memaddr += 2;
205
206
198k
  src = (opcode >> 6) & 0x3f;
207
198k
  dst = opcode & 0x3f;
208
209
20.5M
  for (i = 0; i < pdp11_num_opcodes; i++)
210
20.5M
    {
211
41.5M
#define OP pdp11_opcodes[i]
212
20.5M
      if ((opcode & OP.mask) == OP.opcode)
213
198k
  switch (OP.type)
214
198k
    {
215
28.3k
    case PDP11_OPCODE_NO_OPS:
216
28.3k
      FPRINTF (F, "%s", OP.name);
217
28.3k
      goto done;
218
646
    case PDP11_OPCODE_REG:
219
646
      FPRINTF (F, "%s", OP.name);
220
646
      FPRINTF (F, AFTER_INSTRUCTION);
221
646
      print_reg (dst, info);
222
646
      goto done;
223
11.2k
    case PDP11_OPCODE_OP:
224
11.2k
      FPRINTF (F, "%s", OP.name);
225
11.2k
      FPRINTF (F, AFTER_INSTRUCTION);
226
11.2k
      if (strcmp (OP.name, "jmp") == 0)
227
3.70k
        dst |= JUMP;
228
11.2k
      if (print_operand (&memaddr, dst, info) < 0)
229
9
        return -1;
230
11.2k
      goto done;
231
11.2k
    case PDP11_OPCODE_FOP:
232
1.12k
      FPRINTF (F, "%s", OP.name);
233
1.12k
      FPRINTF (F, AFTER_INSTRUCTION);
234
1.12k
      if (strcmp (OP.name, "jmp") == 0)
235
0
        dst |= JUMP;
236
1.12k
      if (print_foperand (&memaddr, dst, info) < 0)
237
1
        return -1;
238
1.12k
      goto done;
239
4.97k
    case PDP11_OPCODE_REG_OP:
240
4.97k
      FPRINTF (F, "%s", OP.name);
241
4.97k
      FPRINTF (F, AFTER_INSTRUCTION);
242
4.97k
      print_reg (src, info);
243
4.97k
      FPRINTF (F, OPERAND_SEPARATOR);
244
4.97k
      if (strcmp (OP.name, "jsr") == 0)
245
3.29k
        dst |= JUMP;
246
4.97k
      if (print_operand (&memaddr, dst, info) < 0)
247
1
        return -1;
248
4.97k
      goto done;
249
6.32k
    case PDP11_OPCODE_REG_OP_REV:
250
6.32k
      FPRINTF (F, "%s", OP.name);
251
6.32k
      FPRINTF (F, AFTER_INSTRUCTION);
252
6.32k
      if (print_operand (&memaddr, dst, info) < 0)
253
5
        return -1;
254
6.31k
      FPRINTF (F, OPERAND_SEPARATOR);
255
6.31k
      print_reg (src, info);
256
6.31k
      goto done;
257
1.75k
    case PDP11_OPCODE_AC_FOP:
258
1.75k
      {
259
1.75k
        int ac = (opcode & 0xe0) >> 6;
260
1.75k
        FPRINTF (F, "%s", OP.name);
261
1.75k
        FPRINTF (F, AFTER_INSTRUCTION);
262
1.75k
        print_freg (ac, info);
263
1.75k
        FPRINTF (F, OPERAND_SEPARATOR);
264
1.75k
        if (print_foperand (&memaddr, dst, info) < 0)
265
3
    return -1;
266
1.75k
        goto done;
267
1.75k
      }
268
14.9k
    case PDP11_OPCODE_FOP_AC:
269
14.9k
      {
270
14.9k
        int ac = (opcode & 0xe0) >> 6;
271
14.9k
        FPRINTF (F, "%s", OP.name);
272
14.9k
        FPRINTF (F, AFTER_INSTRUCTION);
273
14.9k
        if (print_foperand (&memaddr, dst, info) < 0)
274
14
    return -1;
275
14.8k
        FPRINTF (F, OPERAND_SEPARATOR);
276
14.8k
        print_freg (ac, info);
277
14.8k
        goto done;
278
14.9k
      }
279
1.09k
    case PDP11_OPCODE_AC_OP:
280
1.09k
      {
281
1.09k
        int ac = (opcode & 0xe0) >> 6;
282
1.09k
        FPRINTF (F, "%s", OP.name);
283
1.09k
        FPRINTF (F, AFTER_INSTRUCTION);
284
1.09k
        print_freg (ac, info);
285
1.09k
        FPRINTF (F, OPERAND_SEPARATOR);
286
1.09k
        if (print_operand (&memaddr, dst, info) < 0)
287
5
    return -1;
288
1.09k
        goto done;
289
1.09k
      }
290
2.08k
    case PDP11_OPCODE_OP_AC:
291
2.08k
      {
292
2.08k
        int ac = (opcode & 0xe0) >> 6;
293
2.08k
        FPRINTF (F, "%s", OP.name);
294
2.08k
        FPRINTF (F, AFTER_INSTRUCTION);
295
2.08k
        if (print_operand (&memaddr, dst, info) < 0)
296
5
    return -1;
297
2.07k
        FPRINTF (F, OPERAND_SEPARATOR);
298
2.07k
        print_freg (ac, info);
299
2.07k
        goto done;
300
2.08k
      }
301
98.6k
    case PDP11_OPCODE_OP_OP:
302
98.6k
      FPRINTF (F, "%s", OP.name);
303
98.6k
      FPRINTF (F, AFTER_INSTRUCTION);
304
98.6k
      if (print_operand (&memaddr, src, info) < 0)
305
31
        return -1;
306
98.6k
      FPRINTF (F, OPERAND_SEPARATOR);
307
98.6k
      if (print_operand (&memaddr, dst, info) < 0)
308
19
        return -1;
309
98.6k
      goto done;
310
98.6k
    case PDP11_OPCODE_DISPL:
311
14.6k
      {
312
14.6k
        int displ = (opcode & 0xff) << 8;
313
14.6k
        bfd_vma address = memaddr + (sign_extend (displ) >> 7);
314
14.6k
        FPRINTF (F, "%s", OP.name);
315
14.6k
        FPRINTF (F, AFTER_INSTRUCTION);
316
14.6k
        (*info->print_address_func) (address, info);
317
14.6k
        goto done;
318
98.6k
      }
319
1.74k
    case PDP11_OPCODE_REG_DISPL:
320
1.74k
      {
321
1.74k
        int displ = (opcode & 0x3f) << 10;
322
1.74k
        bfd_vma address = memaddr - (displ >> 9);
323
324
1.74k
        FPRINTF (F, "%s", OP.name);
325
1.74k
        FPRINTF (F, AFTER_INSTRUCTION);
326
1.74k
        print_reg (src, info);
327
1.74k
        FPRINTF (F, OPERAND_SEPARATOR);
328
1.74k
        (*info->print_address_func) (address, info);
329
1.74k
        goto done;
330
98.6k
      }
331
1.30k
    case PDP11_OPCODE_IMM8:
332
1.30k
      {
333
1.30k
        int code = opcode & 0xff;
334
1.30k
        FPRINTF (F, "%s", OP.name);
335
1.30k
        FPRINTF (F, AFTER_INSTRUCTION);
336
1.30k
        FPRINTF (F, "%o", code);
337
1.30k
        goto done;
338
98.6k
      }
339
517
    case PDP11_OPCODE_IMM6:
340
517
      {
341
517
        int code = opcode & 0x3f;
342
517
        FPRINTF (F, "%s", OP.name);
343
517
        FPRINTF (F, AFTER_INSTRUCTION);
344
517
        FPRINTF (F, "%o", code);
345
517
        goto done;
346
98.6k
      }
347
581
    case PDP11_OPCODE_IMM3:
348
581
      {
349
581
        int code = opcode & 7;
350
581
        FPRINTF (F, "%s", OP.name);
351
581
        FPRINTF (F, AFTER_INSTRUCTION);
352
581
        FPRINTF (F, "%o", code);
353
581
        goto done;
354
98.6k
      }
355
8.66k
    case PDP11_OPCODE_ILLEGAL:
356
8.66k
      {
357
8.66k
        FPRINTF (F, ".word");
358
8.66k
        FPRINTF (F, AFTER_INSTRUCTION);
359
8.66k
        FPRINTF (F, "%o", opcode);
360
8.66k
        goto done;
361
98.6k
      }
362
0
    default:
363
      /* TODO: is this a proper way of signalling an error? */
364
0
      FPRINTF (F, "<internal error: unrecognized instruction type>");
365
0
      return -1;
366
198k
    }
367
20.5M
#undef OP
368
20.5M
    }
369
198k
 done:
370
371
198k
  return memaddr - start_memaddr;
372
198k
}