1 /* FR30 opcode support. -*- C -*- 2 Copyright 2011 Free Software Foundation, Inc. 3 4 Contributed by Red Hat Inc; 5 6 This file is part of the GNU 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 3 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 /* This file is an addendum to fr30.cpu. Heavy use of C code isn't 24 appropriate in .cpu files, so it resides here. This especially applies 25 to assembly/disassembly where parsing/printing can be quite involved. 26 Such things aren't really part of the specification of the cpu, per se, 27 so .cpu files provide the general framework and .opc files handle the 28 nitty-gritty details as necessary. 29 30 Each section is delimited with start and end markers. 31 32 <arch>-opc.h additions use: "-- opc.h" 33 <arch>-opc.c additions use: "-- opc.c" 34 <arch>-asm.c additions use: "-- asm.c" 35 <arch>-dis.c additions use: "-- dis.c" 36 <arch>-ibd.h additions use: "-- ibd.h". */ 37 38 /* -- opc.h */ 40 41 /* ??? This can be improved upon. */ 42 #undef CGEN_DIS_HASH_SIZE 43 #define CGEN_DIS_HASH_SIZE 16 44 #undef CGEN_DIS_HASH 45 #define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4) 46 47 /* -- */ 48 49 /* -- asm.c */ 51 /* Handle register lists for LDMx and STMx. */ 52 53 static int 54 parse_register_number (const char **strp) 55 { 56 int regno; 57 58 if (**strp < '0' || **strp > '9') 59 return -1; /* Error. */ 60 regno = **strp - '0'; 61 ++*strp; 62 63 if (**strp >= '0' && **strp <= '9') 64 { 65 regno = regno * 10 + (**strp - '0'); 66 ++*strp; 67 } 68 69 return regno; 70 } 71 72 static const char * 73 parse_register_list (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 74 const char **strp, 75 int opindex ATTRIBUTE_UNUSED, 76 unsigned long *valuep, 77 int high_low, /* 0 == high, 1 == low. */ 78 int load_store) /* 0 == load, 1 == store. */ 79 { 80 *valuep = 0; 81 while (**strp && **strp != ')') 82 { 83 int regno; 84 85 if (**strp != 'R' && **strp != 'r') 86 break; 87 ++*strp; 88 89 regno = parse_register_number (strp); 90 if (regno == -1) 91 return _("Register number is not valid"); 92 if (regno > 7 && !high_low) 93 return _("Register must be between r0 and r7"); 94 if (regno < 8 && high_low) 95 return _("Register must be between r8 and r15"); 96 97 if (high_low) 98 regno -= 8; 99 100 if (load_store) /* Mask is reversed for store. */ 101 *valuep |= 0x80 >> regno; 102 else 103 *valuep |= 1 << regno; 104 105 if (**strp == ',') 106 { 107 if (*(*strp + 1) == ')') 108 break; 109 ++*strp; 110 } 111 } 112 113 if (!*strp || **strp != ')') 114 return _("Register list is not valid"); 115 116 return NULL; 117 } 118 119 static const char * 120 parse_low_register_list_ld (CGEN_CPU_DESC cd, 121 const char **strp, 122 int opindex, 123 unsigned long *valuep) 124 { 125 return parse_register_list (cd, strp, opindex, valuep, 126 0 /* Low. */, 0 /* Load. */); 127 } 128 129 static const char * 130 parse_hi_register_list_ld (CGEN_CPU_DESC cd, 131 const char **strp, 132 int opindex, 133 unsigned long *valuep) 134 { 135 return parse_register_list (cd, strp, opindex, valuep, 136 1 /* High. */, 0 /* Load. */); 137 } 138 139 static const char * 140 parse_low_register_list_st (CGEN_CPU_DESC cd, 141 const char **strp, 142 int opindex, 143 unsigned long *valuep) 144 { 145 return parse_register_list (cd, strp, opindex, valuep, 146 0 /* Low. */, 1 /* Store. */); 147 } 148 149 static const char * 150 parse_hi_register_list_st (CGEN_CPU_DESC cd, 151 const char **strp, 152 int opindex, 153 unsigned long *valuep) 154 { 155 return parse_register_list (cd, strp, opindex, valuep, 156 1 /* High. */, 1 /* Store. */); 157 } 158 159 /* -- */ 160 161 /* -- dis.c */ 162 static void 163 print_register_list (void * dis_info, 164 long value, 165 long offset, 166 int load_store) /* 0 == load, 1 == store. */ 167 { 168 disassemble_info *info = dis_info; 169 int mask; 170 int reg_index = 0; 171 char * comma = ""; 172 173 if (load_store) 174 mask = 0x80; 175 else 176 mask = 1; 177 178 if (value & mask) 179 { 180 (*info->fprintf_func) (info->stream, "r%li", reg_index + offset); 181 comma = ","; 182 } 183 184 for (reg_index = 1; reg_index <= 7; ++reg_index) 185 { 186 if (load_store) 187 mask >>= 1; 188 else 189 mask <<= 1; 190 191 if (value & mask) 192 { 193 (*info->fprintf_func) (info->stream, "%sr%li", comma, reg_index + offset); 194 comma = ","; 195 } 196 } 197 } 198 199 static void 200 print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 201 void * dis_info, 202 long value, 203 unsigned int attrs ATTRIBUTE_UNUSED, 204 bfd_vma pc ATTRIBUTE_UNUSED, 205 int length ATTRIBUTE_UNUSED) 206 { 207 print_register_list (dis_info, value, 8, 0 /* Load. */); 208 } 209 210 static void 211 print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 212 void * dis_info, 213 long value, 214 unsigned int attrs ATTRIBUTE_UNUSED, 215 bfd_vma pc ATTRIBUTE_UNUSED, 216 int length ATTRIBUTE_UNUSED) 217 { 218 print_register_list (dis_info, value, 0, 0 /* Load. */); 219 } 220 221 static void 222 print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 223 void * dis_info, 224 long value, 225 unsigned int attrs ATTRIBUTE_UNUSED, 226 bfd_vma pc ATTRIBUTE_UNUSED, 227 int length ATTRIBUTE_UNUSED) 228 { 229 print_register_list (dis_info, value, 8, 1 /* Store. */); 230 } 231 232 static void 233 print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 234 void * dis_info, 235 long value, 236 unsigned int attrs ATTRIBUTE_UNUSED, 237 bfd_vma pc ATTRIBUTE_UNUSED, 238 int length ATTRIBUTE_UNUSED) 239 { 240 print_register_list (dis_info, value, 0, 1 /* Store. */); 241 } 242 243 static void 244 print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 245 void * dis_info, 246 long value, 247 unsigned int attrs ATTRIBUTE_UNUSED, 248 bfd_vma pc ATTRIBUTE_UNUSED, 249 int length ATTRIBUTE_UNUSED) 250 { 251 disassemble_info *info = (disassemble_info *) dis_info; 252 253 (*info->fprintf_func) (info->stream, "%ld", value); 254 } 255 /* -- */ 256