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