1/* Print DEC PDP-11 instructions. 2 Copyright 2001, 2002 Free Software Foundation, Inc. 3 4This file is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2 of the License, or 7(at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program; if not, write to the Free Software 16Foundation, 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 34static int read_word PARAMS ((bfd_vma memaddr, int *word, 35 disassemble_info *info)); 36static void print_signed_octal PARAMS ((int n, disassemble_info *info)); 37static void print_reg PARAMS ((int reg, disassemble_info *info)); 38static void print_freg PARAMS ((int freg, disassemble_info *info)); 39static int print_operand PARAMS ((bfd_vma *memaddr, int code, 40 disassemble_info *info)); 41static int print_foperand PARAMS ((bfd_vma *memaddr, int code, 42 disassemble_info *info)); 43int print_insn_pdp11 PARAMS ((bfd_vma memaddr, disassemble_info *info)); 44 45static int 46read_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 62static void 63print_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 73static void 74print_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 91static void 92print_freg (freg, info) 93 int freg; 94 disassemble_info *info; 95{ 96 FPRINTF (F, "fr%d", freg); 97} 98 99static int 100print_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 191static int 192print_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 211int 212print_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 - (displ >> 9); 346 347 FPRINTF (F, OP.name); 348 FPRINTF (F, AFTER_INSTRUCTION); 349 print_reg (src, info); 350 FPRINTF (F, OPERAND_SEPARATOR); 351 (*info->print_address_func) (address, info); 352 goto done; 353 } 354 case PDP11_OPCODE_IMM8: 355 { 356 int code = opcode & 0xff; 357 FPRINTF (F, OP.name); 358 FPRINTF (F, AFTER_INSTRUCTION); 359 FPRINTF (F, "%o", code); 360 goto done; 361 } 362 case PDP11_OPCODE_IMM6: 363 { 364 int code = opcode & 0x3f; 365 FPRINTF (F, OP.name); 366 FPRINTF (F, AFTER_INSTRUCTION); 367 FPRINTF (F, "%o", code); 368 goto done; 369 } 370 case PDP11_OPCODE_IMM3: 371 { 372 int code = opcode & 7; 373 FPRINTF (F, OP.name); 374 FPRINTF (F, AFTER_INSTRUCTION); 375 FPRINTF (F, "%o", code); 376 goto done; 377 } 378 case PDP11_OPCODE_ILLEGAL: 379 { 380 FPRINTF (F, ".word"); 381 FPRINTF (F, AFTER_INSTRUCTION); 382 FPRINTF (F, "%o", opcode); 383 goto done; 384 } 385 default: 386 /* TODO: is this a proper way of signalling an error? */ 387 FPRINTF (F, "<internal error: unrecognized instruction type>"); 388 return -1; 389 } 390#undef OP 391 } 392 done: 393 394 return memaddr - start_memaddr; 395} 396