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