[ARC] Enhance enter/leave mnemonics.
[external/binutils.git] / opcodes / pdp11-dis.c
1 /* Print DEC PDP-11 instructions.
2    Copyright (C) 2001-2017 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, "%s", OP.name);
218             goto done;
219           case PDP11_OPCODE_REG:
220             FPRINTF (F, "%s", OP.name);
221             FPRINTF (F, AFTER_INSTRUCTION);
222             print_reg (dst, info);
223             goto done;
224           case PDP11_OPCODE_OP:
225             FPRINTF (F, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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, "%s", 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 }