xref: /openbsd-src/gnu/usr.bin/binutils-2.17/opcodes/pdp11-dis.c (revision 3d8817e467ea46cf4772788d6804dd293abfb01a)
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