1 /* IQ2000 opcode support. -*- C -*- 2 3 Copyright 2000, 2001, 2002, 2005, 2007, 2009 Free Software Foundation, Inc. 4 5 Contributed by Red Hat Inc; developed under contract from Fujitsu. 6 7 This file is part of the GNU Binutils. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 22 MA 02110-1301, USA. */ 23 24 /* This file is an addendum to iq2000.cpu. Heavy use of C code isn't 25 appropriate in .cpu files, so it resides here. This especially applies 26 to assembly/disassembly where parsing/printing can be quite involved. 27 Such things aren't really part of the specification of the cpu, per se, 28 so .cpu files provide the general framework and .opc files handle the 29 nitty-gritty details as necessary. 30 31 Each section is delimited with start and end markers. 32 33 <arch>-opc.h additions use: "-- opc.h" 34 <arch>-opc.c additions use: "-- opc.c" 35 <arch>-asm.c additions use: "-- asm.c" 36 <arch>-dis.c additions use: "-- dis.c" 37 <arch>-ibd.h additions use: "-- ibd.h". */ 38 39 /* -- opc.h */ 41 42 /* Allows reason codes to be output when assembler errors occur. */ 43 #define CGEN_VERBOSE_ASSEMBLER_ERRORS 44 45 /* Override disassembly hashing - there are variable bits in the top 46 byte of these instructions. */ 47 #define CGEN_DIS_HASH_SIZE 8 48 #define CGEN_DIS_HASH(buf,value) (((* (unsigned char*) (buf)) >> 6) % CGEN_DIS_HASH_SIZE) 49 50 /* following activates check beyond hashing since some iq2000 and iq10 51 instructions have same mnemonics but different functionality. */ 52 #define CGEN_VALIDATE_INSN_SUPPORTED 53 54 extern int iq2000_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *); 55 56 /* -- asm.c */ 57 58 #include "safe-ctype.h" 59 60 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); 61 62 /* Special check to ensure that instruction exists for given machine. */ 63 64 int 65 iq2000_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn) 66 { 67 int machs = cd->machs; 68 69 return (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH) & machs) != 0; 70 } 71 72 static int 73 iq2000_cgen_isa_register (const char **strp) 74 { 75 int len; 76 int ch1, ch2; 77 78 if (**strp == 'r' || **strp == 'R') 79 { 80 len = strlen (*strp); 81 if (len == 2) 82 { 83 ch1 = (*strp)[1]; 84 if ('0' <= ch1 && ch1 <= '9') 85 return 1; 86 } 87 else if (len == 3) 88 { 89 ch1 = (*strp)[1]; 90 ch2 = (*strp)[2]; 91 if (('1' <= ch1 && ch1 <= '2') && ('0' <= ch2 && ch2 <= '9')) 92 return 1; 93 if ('3' == ch1 && (ch2 == '0' || ch2 == '1')) 94 return 1; 95 } 96 } 97 if (**strp == '%' 98 && TOLOWER ((*strp)[1]) != 'l' 99 && TOLOWER ((*strp)[1]) != 'h') 100 return 1; 101 return 0; 102 } 103 104 /* Handle negated literal. */ 105 106 static const char * 107 parse_mimm (CGEN_CPU_DESC cd, 108 const char **strp, 109 int opindex, 110 unsigned long *valuep) 111 { 112 const char *errmsg; 113 114 /* Verify this isn't a register. */ 115 if (iq2000_cgen_isa_register (strp)) 116 errmsg = _("immediate value cannot be register"); 117 else 118 { 119 long value; 120 121 errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); 122 if (errmsg == NULL) 123 { 124 long x = (-value) & 0xFFFF0000; 125 126 if (x != 0 && x != (long) 0xFFFF0000) 127 errmsg = _("immediate value out of range"); 128 else 129 *valuep = (-value & 0xFFFF); 130 } 131 } 132 return errmsg; 133 } 134 135 /* Handle signed/unsigned literal. */ 136 137 static const char * 138 parse_imm (CGEN_CPU_DESC cd, 139 const char **strp, 140 int opindex, 141 unsigned long *valuep) 142 { 143 const char *errmsg; 144 145 if (iq2000_cgen_isa_register (strp)) 146 errmsg = _("immediate value cannot be register"); 147 else 148 { 149 long value; 150 151 errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); 152 if (errmsg == NULL) 153 { 154 long x = value & 0xFFFF0000; 155 156 if (x != 0 && x != (long) 0xFFFF0000) 157 errmsg = _("immediate value out of range"); 158 else 159 *valuep = (value & 0xFFFF); 160 } 161 } 162 return errmsg; 163 } 164 165 /* Handle iq10 21-bit jmp offset. */ 166 167 static const char * 168 parse_jtargq10 (CGEN_CPU_DESC cd, 169 const char **strp, 170 int opindex, 171 int reloc ATTRIBUTE_UNUSED, 172 enum cgen_parse_operand_result *type_addr ATTRIBUTE_UNUSED, 173 bfd_vma *valuep) 174 { 175 const char *errmsg; 176 bfd_vma value; 177 enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER; 178 179 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_OFFSET_21, 180 & result_type, & value); 181 if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 182 { 183 /* Check value is within 23-bits 184 (remembering that 2-bit shift right will occur). */ 185 if (value > 0x7fffff) 186 return _("21-bit offset out of range"); 187 } 188 *valuep = (value & 0x7FFFFF); 189 return errmsg; 190 } 191 192 /* Handle high(). */ 193 194 static const char * 195 parse_hi16 (CGEN_CPU_DESC cd, 196 const char **strp, 197 int opindex, 198 unsigned long *valuep) 199 { 200 if (strncasecmp (*strp, "%hi(", 4) == 0) 201 { 202 enum cgen_parse_operand_result result_type; 203 bfd_vma value; 204 const char *errmsg; 205 206 *strp += 4; 207 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16, 208 & result_type, & value); 209 if (**strp != ')') 210 return MISSING_CLOSING_PARENTHESIS; 211 212 ++*strp; 213 if (errmsg == NULL 214 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 215 { 216 /* If value has top-bit of %lo on, then it will 217 sign-propagate and so we compensate by adding 218 1 to the resultant %hi value. */ 219 if (value & 0x8000) 220 value += 0x10000; 221 value >>= 16; 222 value &= 0xffff; 223 } 224 *valuep = value; 225 226 return errmsg; 227 } 228 229 /* We add %uhi in case a user just wants the high 16-bits or is using 230 an insn like ori for %lo which does not sign-propagate. */ 231 if (strncasecmp (*strp, "%uhi(", 5) == 0) 232 { 233 enum cgen_parse_operand_result result_type; 234 bfd_vma value; 235 const char *errmsg; 236 237 *strp += 5; 238 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_UHI16, 239 & result_type, & value); 240 if (**strp != ')') 241 return MISSING_CLOSING_PARENTHESIS; 242 243 ++*strp; 244 if (errmsg == NULL 245 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 246 value >>= 16; 247 248 value &= 0xffff; 249 *valuep = value; 250 251 return errmsg; 252 } 253 254 return parse_imm (cd, strp, opindex, valuep); 255 } 256 257 /* Handle %lo in a signed context. 258 The signedness of the value doesn't matter to %lo(), but this also 259 handles the case where %lo() isn't present. */ 260 261 static const char * 262 parse_lo16 (CGEN_CPU_DESC cd, 263 const char **strp, 264 int opindex, 265 unsigned long *valuep) 266 { 267 if (strncasecmp (*strp, "%lo(", 4) == 0) 268 { 269 const char *errmsg; 270 enum cgen_parse_operand_result result_type; 271 bfd_vma value; 272 273 *strp += 4; 274 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, 275 & result_type, & value); 276 if (**strp != ')') 277 return MISSING_CLOSING_PARENTHESIS; 278 ++*strp; 279 if (errmsg == NULL 280 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 281 value &= 0xffff; 282 *valuep = value; 283 return errmsg; 284 } 285 286 return parse_imm (cd, strp, opindex, valuep); 287 } 288 289 /* Handle %lo in a negated signed context. 290 The signedness of the value doesn't matter to %lo(), but this also 291 handles the case where %lo() isn't present. */ 292 293 static const char * 294 parse_mlo16 (CGEN_CPU_DESC cd, 295 const char **strp, 296 int opindex, 297 unsigned long *valuep) 298 { 299 if (strncasecmp (*strp, "%lo(", 4) == 0) 300 { 301 const char *errmsg; 302 enum cgen_parse_operand_result result_type; 303 bfd_vma value; 304 305 *strp += 4; 306 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, 307 & result_type, & value); 308 if (**strp != ')') 309 return MISSING_CLOSING_PARENTHESIS; 310 ++*strp; 311 if (errmsg == NULL 312 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 313 value = (-value) & 0xffff; 314 *valuep = value; 315 return errmsg; 316 } 317 318 return parse_mimm (cd, strp, opindex, valuep); 319 } 320 321 /* -- */ 322