1/* Disassembler code for Renesas RX. 2 Copyright (C) 2008-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 "dis-asm.h" 28#include "opcode/rx.h" 29 30#include <setjmp.h> 31 32typedef struct 33{ 34 bfd_vma pc; 35 disassemble_info * dis; 36} RX_Data; 37 38struct private 39{ 40 OPCODES_SIGJMP_BUF bailout; 41}; 42 43static int 44rx_get_byte (void * vdata) 45{ 46 bfd_byte buf[1]; 47 RX_Data *rx_data = (RX_Data *) vdata; 48 int status; 49 50 status = rx_data->dis->read_memory_func (rx_data->pc, 51 buf, 52 1, 53 rx_data->dis); 54 if (status != 0) 55 { 56 struct private *priv = (struct private *) rx_data->dis->private_data; 57 58 rx_data->dis->memory_error_func (status, rx_data->pc, 59 rx_data->dis); 60 OPCODES_SIGLONGJMP (priv->bailout, 1); 61 } 62 63 rx_data->pc ++; 64 return buf[0]; 65} 66 67static char const * size_names[RX_MAX_SIZE] = 68{ 69 "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "<error>" 70}; 71 72static char const * opsize_names[RX_MAX_SIZE] = 73{ 74 "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", "<error>" 75}; 76 77static char const * register_names[] = 78{ 79 /* general registers */ 80 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 81 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 82 /* control register */ 83 "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL, 84 "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL, 85 "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL, 86 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 87}; 88 89static char const * condition_names[] = 90{ 91 /* condition codes */ 92 "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n", 93 "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>" 94}; 95 96static const char * flag_names[] = 97{ 98 "c", "z", "s", "o", "", "", "", "", 99 "", "", "", "", "", "", "", "", 100 "i", "u", "", "", "", "", "", "" 101 "", "", "", "", "", "", "", "", 102}; 103 104int 105print_insn_rx (bfd_vma addr, disassemble_info * dis) 106{ 107 int rv; 108 RX_Data rx_data; 109 RX_Opcode_Decoded opcode; 110 const char * s; 111 struct private priv; 112 113 dis->private_data = (PTR) &priv; 114 rx_data.pc = addr; 115 rx_data.dis = dis; 116 117 if (OPCODES_SIGSETJMP (priv.bailout) != 0) 118 { 119 /* Error return. */ 120 return -1; 121 } 122 123 rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data); 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 /* Detect illegal instructions. */ 132 if (opcode.op[0].size == RX_Bad_Size 133 || register_names [opcode.op[0].reg] == NULL 134 || register_names [opcode.op[1].reg] == NULL 135 || register_names [opcode.op[2].reg] == NULL) 136 { 137 bfd_byte buf[10]; 138 int i; 139 140 PR (PS, ".byte "); 141 rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis); 142 143 for (i = 0 ; i < rv; i++) 144 PR (PS, "0x%02x ", buf[i]); 145 return rv; 146 } 147 148 for (s = opcode.syntax; *s; s++) 149 { 150 if (*s != '%') 151 { 152 PC (*s); 153 } 154 else 155 { 156 RX_Opcode_Operand * oper; 157 int do_size = 0; 158 int do_hex = 0; 159 int do_addr = 0; 160 161 s ++; 162 163 if (*s == 'S') 164 { 165 do_size = 1; 166 s++; 167 } 168 if (*s == 'x') 169 { 170 do_hex = 1; 171 s++; 172 } 173 if (*s == 'a') 174 { 175 do_addr = 1; 176 s++; 177 } 178 179 switch (*s) 180 { 181 case '%': 182 PC ('%'); 183 break; 184 185 case 's': 186 PR (PS, "%s", opsize_names[opcode.size]); 187 break; 188 189 case '0': 190 case '1': 191 case '2': 192 oper = opcode.op + *s - '0'; 193 if (do_size) 194 { 195 if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect) 196 PR (PS, "%s", size_names[oper->size]); 197 } 198 else 199 switch (oper->type) 200 { 201 case RX_Operand_Immediate: 202 if (do_addr) 203 dis->print_address_func (oper->addend, dis); 204 else if (do_hex 205 || oper->addend > 999 206 || oper->addend < -999) 207 PR (PS, "%#x", oper->addend); 208 else 209 PR (PS, "%d", oper->addend); 210 break; 211 case RX_Operand_Register: 212 case RX_Operand_TwoReg: 213 PR (PS, "%s", register_names[oper->reg]); 214 break; 215 case RX_Operand_Indirect: 216 PR (PS, "%d[%s]", oper->addend, register_names[oper->reg]); 217 break; 218 case RX_Operand_Zero_Indirect: 219 PR (PS, "[%s]", register_names[oper->reg]); 220 break; 221 case RX_Operand_Postinc: 222 PR (PS, "[%s+]", register_names[oper->reg]); 223 break; 224 case RX_Operand_Predec: 225 PR (PS, "[-%s]", register_names[oper->reg]); 226 break; 227 case RX_Operand_Condition: 228 PR (PS, "%s", condition_names[oper->reg]); 229 break; 230 case RX_Operand_Flag: 231 PR (PS, "%s", flag_names[oper->reg]); 232 break; 233 default: 234 PR (PS, "[???]"); 235 break; 236 } 237 } 238 } 239 } 240 241 return rv; 242} 243