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