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