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