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