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