1 /* s12z-dis.c -- Freescale S12Z disassembly 2 Copyright (C) 2018-2020 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 <stdio.h> 23 #include "bfd_stdint.h" 24 #include <stdbool.h> 25 #include <assert.h> 26 27 #include "opcode/s12z.h" 28 #include "bfd.h" 29 #include "dis-asm.h" 30 #include "disassemble.h" 31 #include "s12z-opc.h" 32 #include "opintl.h" 33 34 struct mem_read_abstraction 35 { 36 struct mem_read_abstraction_base base; 37 bfd_vma memaddr; 38 struct disassemble_info* info; 39 }; 40 41 static void 42 advance (struct mem_read_abstraction_base *b) 43 { 44 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; 45 mra->memaddr ++; 46 } 47 48 static bfd_vma 49 posn (struct mem_read_abstraction_base *b) 50 { 51 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; 52 return mra->memaddr; 53 } 54 55 static int 56 abstract_read_memory (struct mem_read_abstraction_base *b, 57 int offset, 58 size_t n, bfd_byte *bytes) 59 { 60 struct mem_read_abstraction *mra = (struct mem_read_abstraction *) b; 61 62 int status = (*mra->info->read_memory_func) (mra->memaddr + offset, 63 bytes, n, mra->info); 64 return status != 0 ? -1 : 0; 65 } 66 67 /* Start of disassembly file. */ 68 const struct reg registers[S12Z_N_REGISTERS] = 69 { 70 {"d2", 2}, 71 {"d3", 2}, 72 {"d4", 2}, 73 {"d5", 2}, 74 75 {"d0", 1}, 76 {"d1", 1}, 77 78 {"d6", 4}, 79 {"d7", 4}, 80 81 {"x", 3}, 82 {"y", 3}, 83 {"s", 3}, 84 {"p", 3}, 85 {"cch", 1}, 86 {"ccl", 1}, 87 {"ccw", 2} 88 }; 89 90 static const char *mnemonics[] = 91 { 92 "!!invalid!!", 93 "psh", 94 "pul", 95 "tbne", "tbeq", "tbpl", "tbmi", "tbgt", "tble", 96 "dbne", "dbeq", "dbpl", "dbmi", "dbgt", "dble", 97 "sex", 98 "exg", 99 "lsl", "lsr", 100 "asl", "asr", 101 "rol", "ror", 102 "bfins", "bfext", 103 104 "trap", 105 106 "ld", 107 "st", 108 "cmp", 109 110 "stop", 111 "wai", 112 "sys", 113 114 "minu", 115 "mins", 116 "maxu", 117 "maxs", 118 119 "abs", 120 "adc", 121 "bit", 122 "sbc", 123 "rti", 124 "clb", 125 "eor", 126 127 "sat", 128 129 "nop", 130 "bgnd", 131 "brclr", 132 "brset", 133 "rts", 134 "lea", 135 "mov", 136 137 "bra", 138 "bsr", 139 "bhi", 140 "bls", 141 "bcc", 142 "bcs", 143 "bne", 144 "beq", 145 "bvc", 146 "bvs", 147 "bpl", 148 "bmi", 149 "bge", 150 "blt", 151 "bgt", 152 "ble", 153 "inc", 154 "clr", 155 "dec", 156 157 "add", 158 "sub", 159 "and", 160 "or", 161 162 "tfr", 163 "jmp", 164 "jsr", 165 "com", 166 "andcc", 167 "neg", 168 "orcc", 169 "bclr", 170 "bset", 171 "btgl", 172 "swi", 173 174 "mulu", 175 "divu", 176 "modu", 177 "macu", 178 "qmulu", 179 180 "muls", 181 "divs", 182 "mods", 183 "macs", 184 "qmuls", 185 186 NULL 187 }; 188 189 190 static void 191 operand_separator (struct disassemble_info *info) 192 { 193 if ((info->flags & 0x2)) 194 (*info->fprintf_func) (info->stream, ","); 195 196 (*info->fprintf_func) (info->stream, " "); 197 198 info->flags |= 0x2; 199 } 200 201 /* Render the symbol name whose value is ADDR + BASE or the adddress itself if 202 there is no symbol. If BASE is non zero, then the a PC relative adddress is 203 assumend (ie BASE is the value in the PC. */ 204 static void 205 decode_possible_symbol (bfd_vma addr, bfd_vma base, 206 struct disassemble_info *info, bool relative) 207 { 208 const char *fmt = relative ? "*%+" BFD_VMA_FMT "d" : "%" BFD_VMA_FMT "d"; 209 if (!info->symbol_at_address_func (addr + base, info)) 210 { 211 (*info->fprintf_func) (info->stream, fmt, addr); 212 } 213 else 214 { 215 asymbol *sym = NULL; 216 int j; 217 for (j = 0; j < info->symtab_size; ++j) 218 { 219 sym = info->symtab[j]; 220 if (bfd_asymbol_value (sym) == addr + base) 221 { 222 break; 223 } 224 } 225 if (j < info->symtab_size) 226 (*info->fprintf_func) (info->stream, "%s", bfd_asymbol_name (sym)); 227 else 228 (*info->fprintf_func) (info->stream, fmt, addr); 229 } 230 } 231 232 233 /* Emit the disassembled text for OPR */ 234 static void 235 opr_emit_disassembly (const struct operand *opr, 236 struct disassemble_info *info) 237 { 238 operand_separator (info); 239 240 switch (opr->cl) 241 { 242 case OPND_CL_IMMEDIATE: 243 (*info->fprintf_func) (info->stream, "#%d", 244 ((struct immediate_operand *) opr)->value); 245 break; 246 case OPND_CL_REGISTER: 247 { 248 int r = ((struct register_operand*) opr)->reg; 249 250 if (r < 0 || r >= S12Z_N_REGISTERS) 251 (*info->fprintf_func) (info->stream, _("<illegal reg num>")); 252 else 253 (*info->fprintf_func) (info->stream, "%s", registers[r].name); 254 } 255 break; 256 case OPND_CL_REGISTER_ALL16: 257 (*info->fprintf_func) (info->stream, "%s", "ALL16b"); 258 break; 259 case OPND_CL_REGISTER_ALL: 260 (*info->fprintf_func) (info->stream, "%s", "ALL"); 261 break; 262 case OPND_CL_BIT_FIELD: 263 (*info->fprintf_func) (info->stream, "#%d:%d", 264 ((struct bitfield_operand*)opr)->width, 265 ((struct bitfield_operand*)opr)->offset); 266 break; 267 case OPND_CL_SIMPLE_MEMORY: 268 { 269 struct simple_memory_operand *mo = 270 (struct simple_memory_operand *) opr; 271 decode_possible_symbol (mo->addr, mo->base, info, mo->relative); 272 } 273 break; 274 case OPND_CL_MEMORY: 275 { 276 int used_reg = 0; 277 struct memory_operand *mo = (struct memory_operand *) opr; 278 (*info->fprintf_func) (info->stream, "%c", mo->indirect ? '[' : '('); 279 280 const char *fmt; 281 assert (mo->mutation == OPND_RM_NONE || mo->n_regs == 1); 282 switch (mo->mutation) 283 { 284 case OPND_RM_PRE_DEC: 285 fmt = "-%s"; 286 break; 287 case OPND_RM_PRE_INC: 288 fmt = "+%s"; 289 break; 290 case OPND_RM_POST_DEC: 291 fmt = "%s-"; 292 break; 293 case OPND_RM_POST_INC: 294 fmt = "%s+"; 295 break; 296 case OPND_RM_NONE: 297 default: 298 if (mo->n_regs < 2) 299 (*info->fprintf_func) (info->stream, (mo->n_regs == 0) ? "%d" : "%d,", mo->base_offset); 300 fmt = "%s"; 301 break; 302 } 303 if (mo->n_regs > 0) 304 { 305 int r = mo->regs[0]; 306 307 if (r < 0 || r >= S12Z_N_REGISTERS) 308 (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>")); 309 else 310 (*info->fprintf_func) (info->stream, fmt, registers[r].name); 311 } 312 used_reg = 1; 313 314 if (mo->n_regs > used_reg) 315 { 316 int r = mo->regs[used_reg]; 317 318 if (r < 0 || r >= S12Z_N_REGISTERS) 319 (*info->fprintf_func) (info->stream, _("<illegal reg num>")); 320 else 321 (*info->fprintf_func) (info->stream, ",%s", 322 registers[r].name); 323 } 324 325 (*info->fprintf_func) (info->stream, "%c", 326 mo->indirect ? ']' : ')'); 327 } 328 break; 329 }; 330 } 331 332 #define S12Z_N_SIZES 4 333 static const char shift_size_table[S12Z_N_SIZES] = 334 { 335 'b', 'w', 'p', 'l' 336 }; 337 338 int 339 print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info) 340 { 341 int o; 342 enum optr operator = OP_INVALID; 343 int n_operands = 0; 344 345 /* The longest instruction in S12Z can have 6 operands. 346 (Most have 3 or less. Only PSH and PUL have so many. */ 347 struct operand *operands[6]; 348 349 struct mem_read_abstraction mra; 350 mra.base.read = (void *) abstract_read_memory ; 351 mra.base.advance = advance ; 352 mra.base.posn = posn; 353 mra.memaddr = memaddr; 354 mra.info = info; 355 356 short osize = -1; 357 int n_bytes = 358 decode_s12z (&operator, &osize, &n_operands, operands, 359 (struct mem_read_abstraction_base *) &mra); 360 361 (info->fprintf_func) (info->stream, "%s", mnemonics[(long)operator]); 362 363 /* Ship out size sufficies for those instructions which 364 need them. */ 365 if (osize == -1) 366 { 367 bool suffix = false; 368 369 for (o = 0; o < n_operands; ++o) 370 { 371 if (operands[o] && operands[o]->osize != -1) 372 { 373 if (!suffix) 374 { 375 (*mra.info->fprintf_func) (mra.info->stream, "%c", '.'); 376 suffix = true; 377 } 378 379 osize = operands[o]->osize; 380 381 if (osize < 0 || osize >= S12Z_N_SIZES) 382 (*mra.info->fprintf_func) (mra.info->stream, _("<bad>")); 383 else 384 (*mra.info->fprintf_func) (mra.info->stream, "%c", 385 shift_size_table[osize]); 386 } 387 } 388 } 389 else 390 { 391 if (osize < 0 || osize >= S12Z_N_SIZES) 392 (*mra.info->fprintf_func) (mra.info->stream, _(".<bad>")); 393 else 394 (*mra.info->fprintf_func) (mra.info->stream, ".%c", 395 shift_size_table[osize]); 396 } 397 398 /* Ship out the operands. */ 399 for (o = 0; o < n_operands; ++o) 400 { 401 if (operands[o]) 402 opr_emit_disassembly (operands[o], mra.info); 403 free (operands[o]); 404 } 405 406 return n_bytes; 407 } 408