pdp11-dis.c revision 1.10 1 1.1 christos /* Print DEC PDP-11 instructions.
2 1.10 christos Copyright (C) 2001-2025 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of the GNU opcodes library.
5 1.1 christos
6 1.1 christos This library is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3, or (at your option)
9 1.1 christos any later version.
10 1.1 christos
11 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
12 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 1.1 christos License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; if not, write to the Free Software
18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 1.1 christos MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos #include "sysdep.h"
22 1.6 christos #include "disassemble.h"
23 1.1 christos #include "opcode/pdp11.h"
24 1.1 christos
25 1.1 christos #define AFTER_INSTRUCTION "\t"
26 1.1 christos #define OPERAND_SEPARATOR ", "
27 1.1 christos
28 1.1 christos #define JUMP 0x1000 /* Flag that this operand is used in a jump. */
29 1.1 christos
30 1.1 christos #define FPRINTF (*info->fprintf_func)
31 1.1 christos #define F info->stream
32 1.1 christos
33 1.1 christos /* Sign-extend a 16-bit number in an int. */
34 1.7 christos #define sign_extend(x) ((((x) & 0xffff) ^ 0x8000) - 0x8000)
35 1.1 christos
36 1.1 christos static int
37 1.1 christos read_word (bfd_vma memaddr, int *word, disassemble_info *info)
38 1.1 christos {
39 1.1 christos int status;
40 1.1 christos bfd_byte x[2];
41 1.1 christos
42 1.1 christos status = (*info->read_memory_func) (memaddr, x, 2, info);
43 1.1 christos if (status != 0)
44 1.1 christos return -1;
45 1.1 christos
46 1.1 christos *word = x[1] << 8 | x[0];
47 1.1 christos return 0;
48 1.1 christos }
49 1.1 christos
50 1.1 christos static void
51 1.1 christos print_signed_octal (int n, disassemble_info *info)
52 1.1 christos {
53 1.1 christos if (n < 0)
54 1.1 christos FPRINTF (F, "-%o", -n);
55 1.1 christos else
56 1.1 christos FPRINTF (F, "%o", n);
57 1.1 christos }
58 1.1 christos
59 1.1 christos static void
60 1.1 christos print_reg (int reg, disassemble_info *info)
61 1.1 christos {
62 1.1 christos /* Mask off the addressing mode, if any. */
63 1.1 christos reg &= 7;
64 1.1 christos
65 1.1 christos switch (reg)
66 1.1 christos {
67 1.1 christos case 0: case 1: case 2: case 3: case 4: case 5:
68 1.1 christos FPRINTF (F, "r%d", reg); break;
69 1.1 christos case 6: FPRINTF (F, "sp"); break;
70 1.1 christos case 7: FPRINTF (F, "pc"); break;
71 1.1 christos default: ; /* error */
72 1.1 christos }
73 1.1 christos }
74 1.1 christos
75 1.1 christos static void
76 1.1 christos print_freg (int freg, disassemble_info *info)
77 1.1 christos {
78 1.1 christos FPRINTF (F, "fr%d", freg);
79 1.1 christos }
80 1.1 christos
81 1.1 christos static int
82 1.1 christos print_operand (bfd_vma *memaddr, int code, disassemble_info *info)
83 1.1 christos {
84 1.1 christos int mode = (code >> 3) & 7;
85 1.1 christos int reg = code & 7;
86 1.1 christos int disp;
87 1.1 christos
88 1.1 christos switch (mode)
89 1.1 christos {
90 1.1 christos case 0:
91 1.1 christos print_reg (reg, info);
92 1.1 christos break;
93 1.1 christos case 1:
94 1.1 christos FPRINTF (F, "(");
95 1.1 christos print_reg (reg, info);
96 1.1 christos FPRINTF (F, ")");
97 1.1 christos break;
98 1.1 christos case 2:
99 1.1 christos if (reg == 7)
100 1.1 christos {
101 1.1 christos int data;
102 1.1 christos
103 1.1 christos if (read_word (*memaddr, &data, info) < 0)
104 1.1 christos return -1;
105 1.1 christos FPRINTF (F, "$");
106 1.1 christos print_signed_octal (sign_extend (data), info);
107 1.1 christos *memaddr += 2;
108 1.1 christos }
109 1.1 christos else
110 1.1 christos {
111 1.1 christos FPRINTF (F, "(");
112 1.1 christos print_reg (reg, info);
113 1.1 christos FPRINTF (F, ")+");
114 1.1 christos }
115 1.1 christos break;
116 1.1 christos case 3:
117 1.1 christos if (reg == 7)
118 1.1 christos {
119 1.1 christos int address;
120 1.1 christos
121 1.1 christos if (read_word (*memaddr, &address, info) < 0)
122 1.1 christos return -1;
123 1.1 christos FPRINTF (F, "*$%o", address);
124 1.1 christos *memaddr += 2;
125 1.1 christos }
126 1.1 christos else
127 1.1 christos {
128 1.1 christos FPRINTF (F, "*(");
129 1.1 christos print_reg (reg, info);
130 1.1 christos FPRINTF (F, ")+");
131 1.1 christos }
132 1.1 christos break;
133 1.1 christos case 4:
134 1.1 christos FPRINTF (F, "-(");
135 1.1 christos print_reg (reg, info);
136 1.1 christos FPRINTF (F, ")");
137 1.1 christos break;
138 1.1 christos case 5:
139 1.1 christos FPRINTF (F, "*-(");
140 1.1 christos print_reg (reg, info);
141 1.1 christos FPRINTF (F, ")");
142 1.1 christos break;
143 1.1 christos case 6:
144 1.1 christos case 7:
145 1.1 christos if (read_word (*memaddr, &disp, info) < 0)
146 1.1 christos return -1;
147 1.1 christos *memaddr += 2;
148 1.1 christos if (reg == 7)
149 1.1 christos {
150 1.1 christos bfd_vma address = *memaddr + sign_extend (disp);
151 1.1 christos
152 1.1 christos if (mode == 7)
153 1.1 christos FPRINTF (F, "*");
154 1.1 christos if (!(code & JUMP))
155 1.1 christos FPRINTF (F, "$");
156 1.1 christos (*info->print_address_func) (address, info);
157 1.1 christos }
158 1.1 christos else
159 1.1 christos {
160 1.1 christos if (mode == 7)
161 1.1 christos FPRINTF (F, "*");
162 1.1 christos print_signed_octal (sign_extend (disp), info);
163 1.1 christos FPRINTF (F, "(");
164 1.1 christos print_reg (reg, info);
165 1.1 christos FPRINTF (F, ")");
166 1.1 christos }
167 1.1 christos break;
168 1.1 christos }
169 1.1 christos
170 1.1 christos return 0;
171 1.1 christos }
172 1.1 christos
173 1.1 christos static int
174 1.1 christos print_foperand (bfd_vma *memaddr, int code, disassemble_info *info)
175 1.1 christos {
176 1.1 christos int mode = (code >> 3) & 7;
177 1.1 christos int reg = code & 7;
178 1.1 christos
179 1.1 christos if (mode == 0)
180 1.1 christos print_freg (reg, info);
181 1.1 christos else
182 1.1 christos return print_operand (memaddr, code, info);
183 1.1 christos
184 1.1 christos return 0;
185 1.1 christos }
186 1.1 christos
187 1.1 christos /* Print the PDP-11 instruction at address MEMADDR in debugged memory,
188 1.1 christos on INFO->STREAM. Returns length of the instruction, in bytes. */
189 1.1 christos
190 1.1 christos int
191 1.1 christos print_insn_pdp11 (bfd_vma memaddr, disassemble_info *info)
192 1.1 christos {
193 1.1 christos bfd_vma start_memaddr = memaddr;
194 1.1 christos int opcode;
195 1.1 christos int src, dst;
196 1.1 christos int i;
197 1.1 christos
198 1.1 christos info->bytes_per_line = 6;
199 1.1 christos info->bytes_per_chunk = 2;
200 1.1 christos info->display_endian = BFD_ENDIAN_LITTLE;
201 1.1 christos
202 1.1 christos if (read_word (memaddr, &opcode, info) != 0)
203 1.1 christos return -1;
204 1.1 christos memaddr += 2;
205 1.1 christos
206 1.1 christos src = (opcode >> 6) & 0x3f;
207 1.1 christos dst = opcode & 0x3f;
208 1.1 christos
209 1.1 christos for (i = 0; i < pdp11_num_opcodes; i++)
210 1.1 christos {
211 1.1 christos #define OP pdp11_opcodes[i]
212 1.1 christos if ((opcode & OP.mask) == OP.opcode)
213 1.1 christos switch (OP.type)
214 1.1 christos {
215 1.1 christos case PDP11_OPCODE_NO_OPS:
216 1.1 christos FPRINTF (F, "%s", OP.name);
217 1.1 christos goto done;
218 1.1 christos case PDP11_OPCODE_REG:
219 1.1 christos FPRINTF (F, "%s", OP.name);
220 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
221 1.1 christos print_reg (dst, info);
222 1.1 christos goto done;
223 1.1 christos case PDP11_OPCODE_OP:
224 1.1 christos FPRINTF (F, "%s", OP.name);
225 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
226 1.1 christos if (strcmp (OP.name, "jmp") == 0)
227 1.1 christos dst |= JUMP;
228 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
229 1.1 christos return -1;
230 1.1 christos goto done;
231 1.1 christos case PDP11_OPCODE_FOP:
232 1.1 christos FPRINTF (F, "%s", OP.name);
233 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
234 1.1 christos if (strcmp (OP.name, "jmp") == 0)
235 1.1 christos dst |= JUMP;
236 1.1 christos if (print_foperand (&memaddr, dst, info) < 0)
237 1.1 christos return -1;
238 1.1 christos goto done;
239 1.1 christos case PDP11_OPCODE_REG_OP:
240 1.1 christos FPRINTF (F, "%s", OP.name);
241 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
242 1.1 christos print_reg (src, info);
243 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
244 1.1 christos if (strcmp (OP.name, "jsr") == 0)
245 1.1 christos dst |= JUMP;
246 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
247 1.1 christos return -1;
248 1.1 christos goto done;
249 1.1 christos case PDP11_OPCODE_REG_OP_REV:
250 1.1 christos FPRINTF (F, "%s", OP.name);
251 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
252 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
253 1.1 christos return -1;
254 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
255 1.1 christos print_reg (src, info);
256 1.1 christos goto done;
257 1.1 christos case PDP11_OPCODE_AC_FOP:
258 1.1 christos {
259 1.1 christos int ac = (opcode & 0xe0) >> 6;
260 1.1 christos FPRINTF (F, "%s", OP.name);
261 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
262 1.1 christos print_freg (ac, info);
263 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
264 1.1 christos if (print_foperand (&memaddr, dst, info) < 0)
265 1.1 christos return -1;
266 1.1 christos goto done;
267 1.1 christos }
268 1.1 christos case PDP11_OPCODE_FOP_AC:
269 1.1 christos {
270 1.1 christos int ac = (opcode & 0xe0) >> 6;
271 1.1 christos FPRINTF (F, "%s", OP.name);
272 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
273 1.1 christos if (print_foperand (&memaddr, dst, info) < 0)
274 1.1 christos return -1;
275 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
276 1.1 christos print_freg (ac, info);
277 1.1 christos goto done;
278 1.1 christos }
279 1.1 christos case PDP11_OPCODE_AC_OP:
280 1.1 christos {
281 1.1 christos int ac = (opcode & 0xe0) >> 6;
282 1.1 christos FPRINTF (F, "%s", OP.name);
283 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
284 1.1 christos print_freg (ac, info);
285 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
286 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
287 1.1 christos return -1;
288 1.1 christos goto done;
289 1.1 christos }
290 1.1 christos case PDP11_OPCODE_OP_AC:
291 1.1 christos {
292 1.1 christos int ac = (opcode & 0xe0) >> 6;
293 1.1 christos FPRINTF (F, "%s", OP.name);
294 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
295 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
296 1.1 christos return -1;
297 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
298 1.1 christos print_freg (ac, info);
299 1.1 christos goto done;
300 1.1 christos }
301 1.1 christos case PDP11_OPCODE_OP_OP:
302 1.1 christos FPRINTF (F, "%s", OP.name);
303 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
304 1.1 christos if (print_operand (&memaddr, src, info) < 0)
305 1.1 christos return -1;
306 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
307 1.1 christos if (print_operand (&memaddr, dst, info) < 0)
308 1.1 christos return -1;
309 1.1 christos goto done;
310 1.1 christos case PDP11_OPCODE_DISPL:
311 1.1 christos {
312 1.1 christos int displ = (opcode & 0xff) << 8;
313 1.1 christos bfd_vma address = memaddr + (sign_extend (displ) >> 7);
314 1.1 christos FPRINTF (F, "%s", OP.name);
315 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
316 1.1 christos (*info->print_address_func) (address, info);
317 1.1 christos goto done;
318 1.1 christos }
319 1.1 christos case PDP11_OPCODE_REG_DISPL:
320 1.1 christos {
321 1.1 christos int displ = (opcode & 0x3f) << 10;
322 1.1 christos bfd_vma address = memaddr - (displ >> 9);
323 1.1 christos
324 1.1 christos FPRINTF (F, "%s", OP.name);
325 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
326 1.1 christos print_reg (src, info);
327 1.1 christos FPRINTF (F, OPERAND_SEPARATOR);
328 1.1 christos (*info->print_address_func) (address, info);
329 1.1 christos goto done;
330 1.1 christos }
331 1.1 christos case PDP11_OPCODE_IMM8:
332 1.1 christos {
333 1.1 christos int code = opcode & 0xff;
334 1.1 christos FPRINTF (F, "%s", OP.name);
335 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
336 1.1 christos FPRINTF (F, "%o", code);
337 1.1 christos goto done;
338 1.1 christos }
339 1.1 christos case PDP11_OPCODE_IMM6:
340 1.1 christos {
341 1.1 christos int code = opcode & 0x3f;
342 1.1 christos FPRINTF (F, "%s", OP.name);
343 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
344 1.1 christos FPRINTF (F, "%o", code);
345 1.1 christos goto done;
346 1.1 christos }
347 1.1 christos case PDP11_OPCODE_IMM3:
348 1.1 christos {
349 1.1 christos int code = opcode & 7;
350 1.1 christos FPRINTF (F, "%s", OP.name);
351 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
352 1.1 christos FPRINTF (F, "%o", code);
353 1.1 christos goto done;
354 1.1 christos }
355 1.1 christos case PDP11_OPCODE_ILLEGAL:
356 1.1 christos {
357 1.1 christos FPRINTF (F, ".word");
358 1.1 christos FPRINTF (F, AFTER_INSTRUCTION);
359 1.1 christos FPRINTF (F, "%o", opcode);
360 1.1 christos goto done;
361 1.1 christos }
362 1.1 christos default:
363 1.1 christos /* TODO: is this a proper way of signalling an error? */
364 1.1 christos FPRINTF (F, "<internal error: unrecognized instruction type>");
365 1.1 christos return -1;
366 1.1 christos }
367 1.1 christos #undef OP
368 1.1 christos }
369 1.1 christos done:
370 1.1 christos
371 1.1 christos return memaddr - start_memaddr;
372 1.1 christos }
373