1 /* Instruction printing code for the OpenRISC 1000 2 Copyright (C) 2002, 2005 Free Software Foundation, Inc. 3 Contributed by Damjan Lampret <lampret@opencores.org>. 4 Modified from a29k port. 5 6 This file is part of Binutils. 7 8 This program 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 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public 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 35 static void 36 find_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 48 static void 49 find_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 58 typedef void (*find_byte_func_type) (unsigned char *, unsigned long *); 59 60 static unsigned long 61 or32_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 149 static int 150 or32_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 188 static void 189 or32_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 215 static void 216 or32_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 233 static int 234 print_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 309 int 310 print_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 319 int 320 print_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