1/* Instruction printing code for the OpenRISC 1000 2 Copyright (C) 2002, 2005, 2007 Free Software Foundation, Inc. 3 Contributed by Damjan Lampret <lampret@opencores.org>. 4 Modified from a29k port. 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#define DEBUG 0 24 25#include "dis-asm.h" 26#include "opcode/or32.h" 27#include "safe-ctype.h" 28#include <string.h> 29#include <stdlib.h> 30 31#define EXTEND29(x) ((x) & (unsigned long) 0x10000000 ? ((x) | (unsigned long) 0xf0000000) : ((x))) 32 33/* Now find the four bytes of INSN_CH and put them in *INSN. */ 34 35static void 36find_bytes_big (unsigned char *insn_ch, unsigned long *insn) 37{ 38 *insn = 39 ((unsigned long) insn_ch[0] << 24) + 40 ((unsigned long) insn_ch[1] << 16) + 41 ((unsigned long) insn_ch[2] << 8) + 42 ((unsigned long) insn_ch[3]); 43#if DEBUG 44 printf ("find_bytes_big3: %x\n", *insn); 45#endif 46} 47 48static void 49find_bytes_little (unsigned char *insn_ch, unsigned long *insn) 50{ 51 *insn = 52 ((unsigned long) insn_ch[3] << 24) + 53 ((unsigned long) insn_ch[2] << 16) + 54 ((unsigned long) insn_ch[1] << 8) + 55 ((unsigned long) insn_ch[0]); 56} 57 58typedef void (*find_byte_func_type) (unsigned char *, unsigned long *); 59 60static unsigned long 61or32_extract (char param_ch, char *enc_initial, unsigned long insn) 62{ 63 char *enc; 64 unsigned long ret = 0; 65 int opc_pos = 0; 66 int param_pos = 0; 67 68 for (enc = enc_initial; *enc != '\0'; enc++) 69 if (*enc == param_ch) 70 { 71 if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) 72 continue; 73 else 74 param_pos++; 75 } 76 77#if DEBUG 78 printf ("or32_extract: %c %x ", param_ch, param_pos); 79#endif 80 opc_pos = 32; 81 82 for (enc = enc_initial; *enc != '\0'; ) 83 if ((*enc == '0') && (*(enc + 1) == 'x')) 84 { 85 opc_pos -= 4; 86 87 if ((param_ch == '0') || (param_ch == '1')) 88 { 89 unsigned long tmp = strtoul (enc, NULL, 16); 90#if DEBUG 91 printf (" enc=%s, tmp=%x ", enc, tmp); 92#endif 93 if (param_ch == '0') 94 tmp = 15 - tmp; 95 ret |= tmp << opc_pos; 96 } 97 enc += 3; 98 } 99 else if ((*enc == '0') || (*enc == '1')) 100 { 101 opc_pos--; 102 if (param_ch == *enc) 103 ret |= 1 << opc_pos; 104 enc++; 105 } 106 else if (*enc == param_ch) 107 { 108 opc_pos--; 109 param_pos--; 110#if DEBUG 111 printf ("\n ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos); 112#endif 113 ret += ((insn >> opc_pos) & 0x1) << param_pos; 114 115 if (!param_pos 116 && letter_signed (param_ch) 117 && ret >> (letter_range (param_ch) - 1)) 118 { 119#if DEBUG 120 printf ("\n ret=%x opc_pos=%x, param_pos=%x\n", 121 ret, opc_pos, param_pos); 122#endif 123 ret |= 0xffffffff << letter_range(param_ch); 124#if DEBUG 125 printf ("\n after conversion to signed: ret=%x\n", ret); 126#endif 127 } 128 enc++; 129 } 130 else if (ISALPHA (*enc)) 131 { 132 opc_pos--; 133 enc++; 134 } 135 else if (*enc == '-') 136 { 137 opc_pos--; 138 enc++; 139 } 140 else 141 enc++; 142 143#if DEBUG 144 printf ("ret=%x\n", ret); 145#endif 146 return ret; 147} 148 149static int 150or32_opcode_match (unsigned long insn, char *encoding) 151{ 152 unsigned long ones, zeros; 153 154#if DEBUG 155 printf ("or32_opcode_match: %.8lx\n", insn); 156#endif 157 ones = or32_extract ('1', encoding, insn); 158 zeros = or32_extract ('0', encoding, insn); 159 160#if DEBUG 161 printf ("ones: %x \n", ones); 162 printf ("zeros: %x \n", zeros); 163#endif 164 if ((insn & ones) != ones) 165 { 166#if DEBUG 167 printf ("ret1\n"); 168#endif 169 return 0; 170 } 171 172 if ((~insn & zeros) != zeros) 173 { 174#if DEBUG 175 printf ("ret2\n"); 176#endif 177 return 0; 178 } 179 180#if DEBUG 181 printf ("ret3\n"); 182#endif 183 return 1; 184} 185 186/* Print register to INFO->STREAM. Used only by print_insn. */ 187 188static void 189or32_print_register (char param_ch, 190 char *encoding, 191 unsigned long insn, 192 struct disassemble_info *info) 193{ 194 int regnum = or32_extract (param_ch, encoding, insn); 195 196#if DEBUG 197 printf ("or32_print_register: %c, %s, %x\n", param_ch, encoding, insn); 198#endif 199 if (param_ch == 'A') 200 (*info->fprintf_func) (info->stream, "r%d", regnum); 201 else if (param_ch == 'B') 202 (*info->fprintf_func) (info->stream, "r%d", regnum); 203 else if (param_ch == 'D') 204 (*info->fprintf_func) (info->stream, "r%d", regnum); 205 else if (regnum < 16) 206 (*info->fprintf_func) (info->stream, "r%d", regnum); 207 else if (regnum < 32) 208 (*info->fprintf_func) (info->stream, "r%d", regnum-16); 209 else 210 (*info->fprintf_func) (info->stream, "X%d", regnum); 211} 212 213/* Print immediate to INFO->STREAM. Used only by print_insn. */ 214 215static void 216or32_print_immediate (char param_ch, 217 char *encoding, 218 unsigned long insn, 219 struct disassemble_info *info) 220{ 221 int imm = or32_extract(param_ch, encoding, insn); 222 223 if (letter_signed(param_ch)) 224 (*info->fprintf_func) (info->stream, "0x%x", imm); 225/* (*info->fprintf_func) (info->stream, "%d", imm); */ 226 else 227 (*info->fprintf_func) (info->stream, "0x%x", imm); 228} 229 230/* Print one instruction from MEMADDR on INFO->STREAM. 231 Return the size of the instruction (always 4 on or32). */ 232 233static int 234print_insn (bfd_vma memaddr, struct disassemble_info *info) 235{ 236 /* The raw instruction. */ 237 unsigned char insn_ch[4]; 238 /* Address. Will be sign extened 27-bit. */ 239 unsigned long addr; 240 /* The four bytes of the instruction. */ 241 unsigned long insn; 242 find_byte_func_type find_byte_func = (find_byte_func_type) info->private_data; 243 struct or32_opcode const * opcode; 244 245 { 246 int status = 247 (*info->read_memory_func) (memaddr, (bfd_byte *) &insn_ch[0], 4, info); 248 249 if (status != 0) 250 { 251 (*info->memory_error_func) (status, memaddr, info); 252 return -1; 253 } 254 } 255 256 (*find_byte_func) (&insn_ch[0], &insn); 257 258 for (opcode = &or32_opcodes[0]; 259 opcode < &or32_opcodes[or32_num_opcodes]; 260 ++opcode) 261 { 262 if (or32_opcode_match (insn, opcode->encoding)) 263 { 264 char *s; 265 266 (*info->fprintf_func) (info->stream, "%s ", opcode->name); 267 268 for (s = opcode->args; *s != '\0'; ++s) 269 { 270 switch (*s) 271 { 272 case '\0': 273 return 4; 274 275 case 'r': 276 or32_print_register (*++s, opcode->encoding, insn, info); 277 break; 278 279 case 'X': 280 addr = or32_extract ('X', opcode->encoding, insn) << 2; 281 282 /* Calulate the correct address. XXX is this really correct ?? */ 283 addr = memaddr + EXTEND29 (addr); 284 285 (*info->print_address_func) 286 (addr, info); 287 break; 288 289 default: 290 if (strchr (opcode->encoding, *s)) 291 or32_print_immediate (*s, opcode->encoding, insn, info); 292 else 293 (*info->fprintf_func) (info->stream, "%c", *s); 294 } 295 } 296 297 return 4; 298 } 299 } 300 301 /* This used to be %8x for binutils. */ 302 (*info->fprintf_func) 303 (info->stream, ".word 0x%08lx", insn); 304 return 4; 305} 306 307/* Disassemble a big-endian or32 instruction. */ 308 309int 310print_insn_big_or32 (bfd_vma memaddr, struct disassemble_info *info) 311{ 312 info->private_data = find_bytes_big; 313 314 return print_insn (memaddr, info); 315} 316 317/* Disassemble a little-endian or32 instruction. */ 318 319int 320print_insn_little_or32 (bfd_vma memaddr, struct disassemble_info *info) 321{ 322 info->private_data = find_bytes_little; 323 return print_insn (memaddr, info); 324} 325