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