1/* Disassembler code for Renesas RX. 2 Copyright (C) 2008-2022 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#include "libiberty.h" 30#include "opintl.h" 31 32#include <setjmp.h> 33 34typedef struct 35{ 36 bfd_vma pc; 37 disassemble_info * dis; 38} RX_Data; 39 40struct private 41{ 42 OPCODES_SIGJMP_BUF bailout; 43}; 44 45static int 46rx_get_byte (void * vdata) 47{ 48 bfd_byte buf[1]; 49 RX_Data *rx_data = (RX_Data *) vdata; 50 int status; 51 52 status = rx_data->dis->read_memory_func (rx_data->pc, 53 buf, 54 1, 55 rx_data->dis); 56 if (status != 0) 57 { 58 struct private *priv = (struct private *) rx_data->dis->private_data; 59 60 rx_data->dis->memory_error_func (status, rx_data->pc, 61 rx_data->dis); 62 OPCODES_SIGLONGJMP (priv->bailout, 1); 63 } 64 65 rx_data->pc ++; 66 return buf[0]; 67} 68 69static char const * size_names[RX_MAX_SIZE] = 70{ 71 "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "", "<error>" 72}; 73 74static char const * opsize_names[RX_MAX_SIZE] = 75{ 76 "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", ".d", "<error>" 77}; 78 79static char const * register_names[] = 80{ 81 /* General registers. */ 82 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 83 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 84 /* Control registers. */ 85 "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL, 86 "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL, 87 "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL, 88 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 89}; 90 91static char const * condition_names[] = 92{ 93 /* Condition codes. */ 94 "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n", 95 "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>" 96}; 97 98static const char * flag_names[] = 99{ 100 "c", "z", "s", "o", "", "", "", "", 101 "", "", "", "", "", "", "", "", 102 "i", "u", "", "", "", "", "", "", 103 "", "", "", "", "", "", "", "" 104}; 105 106static const char * double_register_names[] = 107{ 108 "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", 109 "dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15" 110}; 111 112static const char * double_register_high_names[] = 113{ 114 "drh0", "drh1", "drh2", "drh3", "drh4", "drh5", "drh6", "drh7", 115 "drh8", "drh9", "drh10", "drh11", "drh12", "drh13", "drh14", "drh15" 116}; 117 118static const char * double_register_low_names[] = 119{ 120 "drl0", "drl1", "drl2", "drl3", "drl4", "drl5", "drl6", "drl7", 121 "drl8", "drl9", "drl10", "drl11", "drl12", "drl13", "drl14", "drl15" 122}; 123 124static const char * double_control_register_names[] = 125{ 126 "dpsw", "dcmr", "decnt", "depc" 127}; 128 129static const char * double_condition_names[] = 130{ 131 "", "un", "eq", "", "lt", "", "le" 132}; 133 134static inline const char * 135get_register_name (unsigned int reg) 136{ 137 if (reg < ARRAY_SIZE (register_names)) 138 return register_names[reg]; 139 return _("<invalid register number>"); 140} 141 142static inline const char * 143get_condition_name (unsigned int cond) 144{ 145 if (cond < ARRAY_SIZE (condition_names)) 146 return condition_names[cond]; 147 return _("<invalid condition code>"); 148} 149 150static inline const char * 151get_flag_name (unsigned int flag) 152{ 153 if (flag < ARRAY_SIZE (flag_names)) 154 return flag_names[flag]; 155 return _("<invalid flag>"); 156} 157 158static inline const char * 159get_double_register_name (unsigned int reg) 160{ 161 if (reg < ARRAY_SIZE (double_register_names)) 162 return double_register_names[reg]; 163 return _("<invalid register number>"); 164} 165 166static inline const char * 167get_double_register_high_name (unsigned int reg) 168{ 169 if (reg < ARRAY_SIZE (double_register_high_names)) 170 return double_register_high_names[reg]; 171 return _("<invalid register number>"); 172} 173 174static inline const char * 175get_double_register_low_name (unsigned int reg) 176{ 177 if (reg < ARRAY_SIZE (double_register_low_names)) 178 return double_register_low_names[reg]; 179 return _("<invalid register number>"); 180} 181 182static inline const char * 183get_double_control_register_name (unsigned int reg) 184{ 185 if (reg < ARRAY_SIZE (double_control_register_names)) 186 return double_control_register_names[reg]; 187 return _("<invalid register number>"); 188} 189 190static inline const char * 191get_double_condition_name (unsigned int cond) 192{ 193 if (cond < ARRAY_SIZE (double_condition_names)) 194 return double_condition_names[cond]; 195 return _("<invalid condition code>"); 196} 197 198static inline const char * 199get_opsize_name (unsigned int opsize) 200{ 201 if (opsize < ARRAY_SIZE (opsize_names)) 202 return opsize_names[opsize]; 203 return _("<invalid opsize>"); 204} 205 206static inline const char * 207get_size_name (unsigned int size) 208{ 209 if (size < ARRAY_SIZE (size_names)) 210 return size_names[size]; 211 return _("<invalid size>"); 212} 213 214 215int 216print_insn_rx (bfd_vma addr, disassemble_info * dis) 217{ 218 int rv; 219 RX_Data rx_data; 220 RX_Opcode_Decoded opcode; 221 const char * s; 222 struct private priv; 223 224 dis->private_data = &priv; 225 rx_data.pc = addr; 226 rx_data.dis = dis; 227 228 if (OPCODES_SIGSETJMP (priv.bailout) != 0) 229 { 230 /* Error return. */ 231 return -1; 232 } 233 234 rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data); 235 236 dis->bytes_per_line = 10; 237 238#define PR (dis->fprintf_func) 239#define PS (dis->stream) 240#define PC(c) PR (PS, "%c", c) 241 242 /* Detect illegal instructions. */ 243 if (opcode.op[0].size == RX_Bad_Size 244 || register_names [opcode.op[0].reg] == NULL 245 || register_names [opcode.op[1].reg] == NULL 246 || register_names [opcode.op[2].reg] == NULL) 247 { 248 bfd_byte buf[10]; 249 int i; 250 251 PR (PS, ".byte "); 252 rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis); 253 254 for (i = 0 ; i < rv; i++) 255 PR (PS, "0x%02x ", buf[i]); 256 return rv; 257 } 258 259 for (s = opcode.syntax; *s; s++) 260 { 261 if (*s != '%') 262 { 263 PC (*s); 264 } 265 else 266 { 267 RX_Opcode_Operand * oper; 268 int do_size = 0; 269 int do_hex = 0; 270 int do_addr = 0; 271 272 s ++; 273 274 if (*s == 'S') 275 { 276 do_size = 1; 277 s++; 278 } 279 if (*s == 'x') 280 { 281 do_hex = 1; 282 s++; 283 } 284 if (*s == 'a') 285 { 286 do_addr = 1; 287 s++; 288 } 289 290 switch (*s) 291 { 292 case '%': 293 PC ('%'); 294 break; 295 296 case 's': 297 PR (PS, "%s", get_opsize_name (opcode.size)); 298 break; 299 300 case 'b': 301 s ++; 302 if (*s == 'f') 303 { 304 int imm = opcode.op[2].addend; 305 int slsb, dlsb, width; 306 307 dlsb = (imm >> 5) & 0x1f; 308 slsb = (imm & 0x1f); 309 slsb = (slsb >= 0x10?(slsb ^ 0x1f) + 1:slsb); 310 slsb = dlsb - slsb; 311 slsb = (slsb < 0?-slsb:slsb); 312 width = ((imm >> 10) & 0x1f) - dlsb; 313 PR (PS, "#%d, #%d, #%d, %s, %s", 314 slsb, dlsb, width, 315 get_register_name (opcode.op[1].reg), 316 get_register_name (opcode.op[0].reg)); 317 } 318 break; 319 case '0': 320 case '1': 321 case '2': 322 oper = opcode.op + (*s - '0'); 323 if (do_size) 324 { 325 if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect) 326 PR (PS, "%s", get_size_name (oper->size)); 327 } 328 else 329 switch (oper->type) 330 { 331 case RX_Operand_Immediate: 332 if (do_addr) 333 dis->print_address_func (oper->addend, dis); 334 else if (do_hex 335 || oper->addend > 999 336 || oper->addend < -999) 337 PR (PS, "%#x", oper->addend); 338 else 339 PR (PS, "%d", oper->addend); 340 break; 341 case RX_Operand_Register: 342 case RX_Operand_TwoReg: 343 PR (PS, "%s", get_register_name (oper->reg)); 344 break; 345 case RX_Operand_Indirect: 346 PR (PS, "%d[%s]", oper->addend, get_register_name (oper->reg)); 347 break; 348 case RX_Operand_Zero_Indirect: 349 PR (PS, "[%s]", get_register_name (oper->reg)); 350 break; 351 case RX_Operand_Postinc: 352 PR (PS, "[%s+]", get_register_name (oper->reg)); 353 break; 354 case RX_Operand_Predec: 355 PR (PS, "[-%s]", get_register_name (oper->reg)); 356 break; 357 case RX_Operand_Condition: 358 PR (PS, "%s", get_condition_name (oper->reg)); 359 break; 360 case RX_Operand_Flag: 361 PR (PS, "%s", get_flag_name (oper->reg)); 362 break; 363 case RX_Operand_DoubleReg: 364 PR (PS, "%s", get_double_register_name (oper->reg)); 365 break; 366 case RX_Operand_DoubleRegH: 367 PR (PS, "%s", get_double_register_high_name (oper->reg)); 368 break; 369 case RX_Operand_DoubleRegL: 370 PR (PS, "%s", get_double_register_low_name (oper->reg)); 371 break; 372 case RX_Operand_DoubleCReg: 373 PR (PS, "%s", get_double_control_register_name (oper->reg)); 374 break; 375 case RX_Operand_DoubleCond: 376 PR (PS, "%s", get_double_condition_name (oper->reg)); 377 break; 378 default: 379 PR (PS, "[???]"); 380 break; 381 } 382 } 383 } 384 } 385 386 return rv; 387} 388