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