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