1/* Disassembler code for Renesas RL78. 2 Copyright (C) 2011-2017 Free Software Foundation, Inc. 3 Contributed by Red Hat. 4 Written by DJ Delorie. 5 6 This file is part of the GNU opcodes library. 7 8 This library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 It is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 MA 02110-1301, USA. */ 22 23#include "sysdep.h" 24#include <stdio.h> 25 26#include "bfd.h" 27#include "elf-bfd.h" 28#include "dis-asm.h" 29#include "opcode/rl78.h" 30#include "elf/rl78.h" 31 32#include <setjmp.h> 33 34#define DEBUG_SEMANTICS 0 35 36typedef struct 37{ 38 bfd_vma pc; 39 disassemble_info * dis; 40} RL78_Data; 41 42struct private 43{ 44 OPCODES_SIGJMP_BUF bailout; 45}; 46 47static int 48rl78_get_byte (void * vdata) 49{ 50 bfd_byte buf[1]; 51 RL78_Data *rl78_data = (RL78_Data *) vdata; 52 int status; 53 54 status = rl78_data->dis->read_memory_func (rl78_data->pc, 55 buf, 56 1, 57 rl78_data->dis); 58 if (status != 0) 59 { 60 struct private *priv = (struct private *) rl78_data->dis->private_data; 61 62 rl78_data->dis->memory_error_func (status, rl78_data->pc, 63 rl78_data->dis); 64 OPCODES_SIGLONGJMP (priv->bailout, 1); 65 } 66 67 rl78_data->pc ++; 68 return buf[0]; 69} 70 71static char const * 72register_names[] = 73{ 74 "", 75 "x", "a", "c", "b", "e", "d", "l", "h", 76 "ax", "bc", "de", "hl", 77 "sp", "psw", "cs", "es", "pmc", "mem" 78}; 79 80static char const * 81condition_names[] = 82{ 83 "t", "f", "c", "nc", "h", "nh", "z", "nz" 84}; 85 86static int 87indirect_type (int t) 88{ 89 switch (t) 90 { 91 case RL78_Operand_Indirect: 92 case RL78_Operand_BitIndirect: 93 case RL78_Operand_PostInc: 94 case RL78_Operand_PreDec: 95 return 1; 96 default: 97 return 0; 98 } 99} 100 101static int 102print_insn_rl78_common (bfd_vma addr, disassemble_info * dis, RL78_Dis_Isa isa) 103{ 104 int rv; 105 RL78_Data rl78_data; 106 RL78_Opcode_Decoded opcode; 107 const char * s; 108#if DEBUG_SEMANTICS 109 static char buf[200]; 110#endif 111 struct private priv; 112 113 dis->private_data = (PTR) &priv; 114 rl78_data.pc = addr; 115 rl78_data.dis = dis; 116 117 if (OPCODES_SIGSETJMP (priv.bailout) != 0) 118 { 119 /* Error return. */ 120 return -1; 121 } 122 123 rv = rl78_decode_opcode (addr, &opcode, rl78_get_byte, &rl78_data, isa); 124 125 dis->bytes_per_line = 10; 126 127#define PR (dis->fprintf_func) 128#define PS (dis->stream) 129#define PC(c) PR (PS, "%c", c) 130 131 s = opcode.syntax; 132 133#if DEBUG_SEMANTICS 134 135 switch (opcode.id) 136 { 137 case RLO_unknown: s = "uknown"; break; 138 case RLO_add: s = "add: %e0%0 += %e1%1"; break; 139 case RLO_addc: s = "addc: %e0%0 += %e1%1 + CY"; break; 140 case RLO_and: s = "and: %e0%0 &= %e1%1"; break; 141 case RLO_branch: s = "branch: pc = %e0%0"; break; 142 case RLO_branch_cond: s = "branch_cond: pc = %e0%0 if %c1 / %e1%1"; break; 143 case RLO_branch_cond_clear: s = "branch_cond_clear: pc = %e0%0 if %c1 / %e1%1, %e1%1 = 0"; break; 144 case RLO_call: s = "call: pc = %e1%0"; break; 145 case RLO_cmp: s = "cmp: %e0%0 - %e1%1"; break; 146 case RLO_mov: s = "mov: %e0%0 = %e1%1"; break; 147 case RLO_or: s = "or: %e0%0 |= %e1%1"; break; 148 case RLO_rol: s = "rol: %e0%0 <<= %e1%1"; break; 149 case RLO_rolc: s = "rol: %e0%0 <<= %e1%1,CY"; break; 150 case RLO_ror: s = "ror: %e0%0 >>= %e1%1"; break; 151 case RLO_rorc: s = "ror: %e0%0 >>= %e1%1,CY"; break; 152 case RLO_sar: s = "sar: %e0%0 >>= %e1%1 signed"; break; 153 case RLO_sel: s = "sel: rb = %1"; break; 154 case RLO_shr: s = "shr: %e0%0 >>= %e1%1 unsigned"; break; 155 case RLO_shl: s = "shl: %e0%0 <<= %e1%1"; break; 156 case RLO_skip: s = "skip: if %c1"; break; 157 case RLO_sub: s = "sub: %e0%0 -= %e1%1"; break; 158 case RLO_subc: s = "subc: %e0%0 -= %e1%1 - CY"; break; 159 case RLO_xch: s = "xch: %e0%0 <-> %e1%1"; break; 160 case RLO_xor: s = "xor: %e0%0 ^= %e1%1"; break; 161 } 162 163 sprintf(buf, "%s%%W%%f\t\033[32m%s\033[0m", s, opcode.syntax); 164 s = buf; 165 166#endif 167 168 for (; *s; s++) 169 { 170 if (*s != '%') 171 { 172 PC (*s); 173 } 174 else 175 { 176 RL78_Opcode_Operand * oper; 177 int do_hex = 0; 178 int do_addr = 0; 179 int do_es = 0; 180 int do_sfr = 0; 181 int do_cond = 0; 182 int do_bang = 0; 183 184 while (1) 185 { 186 s ++; 187 switch (*s) 188 { 189 case 'x': 190 do_hex = 1; 191 break; 192 case '!': 193 do_bang = 1; 194 break; 195 case 'e': 196 do_es = 1; 197 break; 198 case 'a': 199 do_addr = 1; 200 break; 201 case 's': 202 do_sfr = 1; 203 break; 204 case 'c': 205 do_cond = 1; 206 break; 207 default: 208 goto no_more_modifiers; 209 } 210 } 211 no_more_modifiers:; 212 213 switch (*s) 214 { 215 case '%': 216 PC ('%'); 217 break; 218 219#if DEBUG_SEMANTICS 220 221 case 'W': 222 if (opcode.size == RL78_Word) 223 PR (PS, " \033[33mW\033[0m"); 224 break; 225 226 case 'f': 227 if (opcode.flags) 228 { 229 char *comma = ""; 230 PR (PS, " \033[35m"); 231 232 if (opcode.flags & RL78_PSW_Z) 233 { PR (PS, "Z"); comma = ","; } 234 if (opcode.flags & RL78_PSW_AC) 235 { PR (PS, "%sAC", comma); comma = ","; } 236 if (opcode.flags & RL78_PSW_CY) 237 { PR (PS, "%sCY", comma); comma = ","; } 238 PR (PS, "\033[0m"); 239 } 240 break; 241 242#endif 243 244 case '0': 245 case '1': 246 oper = *s == '0' ? &opcode.op[0] : &opcode.op[1]; 247 if (do_es) 248 { 249 if (oper->use_es && indirect_type (oper->type)) 250 PR (PS, "es:"); 251 } 252 253 if (do_bang) 254 { 255 /* If we are going to display SP by name, we must omit the bang. */ 256 if ((oper->type == RL78_Operand_Indirect 257 || oper->type == RL78_Operand_BitIndirect) 258 && oper->reg == RL78_Reg_None 259 && do_sfr 260 && ((oper->addend == 0xffff8 && opcode.size == RL78_Word) 261 || (oper->addend == 0x0fff8 && do_es && opcode.size == RL78_Word))) 262 ; 263 else 264 PC ('!'); 265 } 266 267 if (do_cond) 268 { 269 PR (PS, "%s", condition_names[oper->condition]); 270 break; 271 } 272 273 switch (oper->type) 274 { 275 case RL78_Operand_Immediate: 276 if (do_addr) 277 dis->print_address_func (oper->addend, dis); 278 else if (do_hex 279 || oper->addend > 999 280 || oper->addend < -999) 281 PR (PS, "%#x", oper->addend); 282 else 283 PR (PS, "%d", oper->addend); 284 break; 285 286 case RL78_Operand_Register: 287 PR (PS, "%s", register_names[oper->reg]); 288 break; 289 290 case RL78_Operand_Bit: 291 PR (PS, "%s.%d", register_names[oper->reg], oper->bit_number); 292 break; 293 294 case RL78_Operand_Indirect: 295 case RL78_Operand_BitIndirect: 296 switch (oper->reg) 297 { 298 case RL78_Reg_None: 299 if (oper->addend == 0xffffa && do_sfr && opcode.size == RL78_Byte) 300 PR (PS, "psw"); 301 else if (oper->addend == 0xffff8 && do_sfr && opcode.size == RL78_Word) 302 PR (PS, "sp"); 303 else if (oper->addend == 0x0fff8 && do_sfr && do_es && opcode.size == RL78_Word) 304 PR (PS, "sp"); 305 else if (oper->addend == 0xffff8 && do_sfr && opcode.size == RL78_Byte) 306 PR (PS, "spl"); 307 else if (oper->addend == 0xffff9 && do_sfr && opcode.size == RL78_Byte) 308 PR (PS, "sph"); 309 else if (oper->addend == 0xffffc && do_sfr && opcode.size == RL78_Byte) 310 PR (PS, "cs"); 311 else if (oper->addend == 0xffffd && do_sfr && opcode.size == RL78_Byte) 312 PR (PS, "es"); 313 else if (oper->addend == 0xffffe && do_sfr && opcode.size == RL78_Byte) 314 PR (PS, "pmc"); 315 else if (oper->addend == 0xfffff && do_sfr && opcode.size == RL78_Byte) 316 PR (PS, "mem"); 317 else if (oper->addend >= 0xffe20) 318 PR (PS, "%#x", oper->addend); 319 else 320 { 321 int faddr = oper->addend; 322 if (do_es && ! oper->use_es) 323 faddr += 0xf0000; 324 dis->print_address_func (faddr, dis); 325 } 326 break; 327 328 case RL78_Reg_B: 329 case RL78_Reg_C: 330 case RL78_Reg_BC: 331 PR (PS, "%d[%s]", oper->addend, register_names[oper->reg]); 332 break; 333 334 default: 335 PR (PS, "[%s", register_names[oper->reg]); 336 if (oper->reg2 != RL78_Reg_None) 337 PR (PS, "+%s", register_names[oper->reg2]); 338 if (oper->addend || do_addr) 339 PR (PS, "+%d", oper->addend); 340 PC (']'); 341 break; 342 343 } 344 if (oper->type == RL78_Operand_BitIndirect) 345 PR (PS, ".%d", oper->bit_number); 346 break; 347 348#if DEBUG_SEMANTICS 349 /* Shouldn't happen - push and pop don't print 350 [SP] directly. But we *do* use them for 351 semantic debugging. */ 352 case RL78_Operand_PostInc: 353 PR (PS, "[%s++]", register_names[oper->reg]); 354 break; 355 case RL78_Operand_PreDec: 356 PR (PS, "[--%s]", register_names[oper->reg]); 357 break; 358#endif 359 360 default: 361 /* If we ever print this, that means the 362 programmer tried to print an operand with a 363 type we don't expect. Print the line and 364 operand number from rl78-decode.opc for 365 them. */ 366 PR (PS, "???%d.%d", opcode.lineno, *s - '0'); 367 break; 368 } 369 } 370 } 371 } 372 373#if DEBUG_SEMANTICS 374 375 PR (PS, "\t\033[34m(line %d)\033[0m", opcode.lineno); 376 377#endif 378 379 return rv; 380} 381 382int 383print_insn_rl78 (bfd_vma addr, disassemble_info * dis) 384{ 385 return print_insn_rl78_common (addr, dis, RL78_ISA_DEFAULT); 386} 387 388int 389print_insn_rl78_g10 (bfd_vma addr, disassemble_info * dis) 390{ 391 return print_insn_rl78_common (addr, dis, RL78_ISA_G10); 392} 393 394int 395print_insn_rl78_g13 (bfd_vma addr, disassemble_info * dis) 396{ 397 return print_insn_rl78_common (addr, dis, RL78_ISA_G13); 398} 399 400int 401print_insn_rl78_g14 (bfd_vma addr, disassemble_info * dis) 402{ 403 return print_insn_rl78_common (addr, dis, RL78_ISA_G14); 404} 405 406disassembler_ftype 407rl78_get_disassembler (bfd *abfd) 408{ 409 int cpu = abfd->tdata.elf_obj_data->elf_header->e_flags & E_FLAG_RL78_CPU_MASK; 410 switch (cpu) 411 { 412 case E_FLAG_RL78_G10: 413 return print_insn_rl78_g10; 414 case E_FLAG_RL78_G13: 415 return print_insn_rl78_g13; 416 case E_FLAG_RL78_G14: 417 return print_insn_rl78_g14; 418 default: 419 return print_insn_rl78; 420 } 421} 422