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