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 */ 39 40/* ??? This can be improved upon. */ 41#undef CGEN_DIS_HASH_SIZE 42#define CGEN_DIS_HASH_SIZE 16 43#undef CGEN_DIS_HASH 44#define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4) 45 46/* -- */ 47 48/* -- asm.c */ 49/* Handle register lists for LDMx and STMx. */ 50 51static int 52parse_register_number (const char **strp) 53{ 54 int regno; 55 56 if (**strp < '0' || **strp > '9') 57 return -1; /* Error. */ 58 regno = **strp - '0'; 59 ++*strp; 60 61 if (**strp >= '0' && **strp <= '9') 62 { 63 regno = regno * 10 + (**strp - '0'); 64 ++*strp; 65 } 66 67 return regno; 68} 69 70static const char * 71parse_register_list (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 72 const char **strp, 73 int opindex ATTRIBUTE_UNUSED, 74 unsigned long *valuep, 75 int high_low, /* 0 == high, 1 == low. */ 76 int load_store) /* 0 == load, 1 == store. */ 77{ 78 *valuep = 0; 79 while (**strp && **strp != ')') 80 { 81 int regno; 82 83 if (**strp != 'R' && **strp != 'r') 84 break; 85 ++*strp; 86 87 regno = parse_register_number (strp); 88 if (regno == -1) 89 return _("Register number is not valid"); 90 if (regno > 7 && !high_low) 91 return _("Register must be between r0 and r7"); 92 if (regno < 8 && high_low) 93 return _("Register must be between r8 and r15"); 94 95 if (high_low) 96 regno -= 8; 97 98 if (load_store) /* Mask is reversed for store. */ 99 *valuep |= 0x80 >> regno; 100 else 101 *valuep |= 1 << regno; 102 103 if (**strp == ',') 104 { 105 if (*(*strp + 1) == ')') 106 break; 107 ++*strp; 108 } 109 } 110 111 if (!*strp || **strp != ')') 112 return _("Register list is not valid"); 113 114 return NULL; 115} 116 117static const char * 118parse_low_register_list_ld (CGEN_CPU_DESC cd, 119 const char **strp, 120 int opindex, 121 unsigned long *valuep) 122{ 123 return parse_register_list (cd, strp, opindex, valuep, 124 0 /* Low. */, 0 /* Load. */); 125} 126 127static const char * 128parse_hi_register_list_ld (CGEN_CPU_DESC cd, 129 const char **strp, 130 int opindex, 131 unsigned long *valuep) 132{ 133 return parse_register_list (cd, strp, opindex, valuep, 134 1 /* High. */, 0 /* Load. */); 135} 136 137static const char * 138parse_low_register_list_st (CGEN_CPU_DESC cd, 139 const char **strp, 140 int opindex, 141 unsigned long *valuep) 142{ 143 return parse_register_list (cd, strp, opindex, valuep, 144 0 /* Low. */, 1 /* Store. */); 145} 146 147static const char * 148parse_hi_register_list_st (CGEN_CPU_DESC cd, 149 const char **strp, 150 int opindex, 151 unsigned long *valuep) 152{ 153 return parse_register_list (cd, strp, opindex, valuep, 154 1 /* High. */, 1 /* Store. */); 155} 156 157/* -- */ 158 159/* -- dis.c */ 160static void 161print_register_list (void * dis_info, 162 long value, 163 long offset, 164 int load_store) /* 0 == load, 1 == store. */ 165{ 166 disassemble_info *info = dis_info; 167 int mask; 168 int reg_index = 0; 169 char * comma = ""; 170 171 if (load_store) 172 mask = 0x80; 173 else 174 mask = 1; 175 176 if (value & mask) 177 { 178 (*info->fprintf_func) (info->stream, "r%li", reg_index + offset); 179 comma = ","; 180 } 181 182 for (reg_index = 1; reg_index <= 7; ++reg_index) 183 { 184 if (load_store) 185 mask >>= 1; 186 else 187 mask <<= 1; 188 189 if (value & mask) 190 { 191 (*info->fprintf_func) (info->stream, "%sr%li", comma, reg_index + offset); 192 comma = ","; 193 } 194 } 195} 196 197static void 198print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 199 void * dis_info, 200 long value, 201 unsigned int attrs ATTRIBUTE_UNUSED, 202 bfd_vma pc ATTRIBUTE_UNUSED, 203 int length ATTRIBUTE_UNUSED) 204{ 205 print_register_list (dis_info, value, 8, 0 /* Load. */); 206} 207 208static void 209print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 210 void * dis_info, 211 long value, 212 unsigned int attrs ATTRIBUTE_UNUSED, 213 bfd_vma pc ATTRIBUTE_UNUSED, 214 int length ATTRIBUTE_UNUSED) 215{ 216 print_register_list (dis_info, value, 0, 0 /* Load. */); 217} 218 219static void 220print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 221 void * dis_info, 222 long value, 223 unsigned int attrs ATTRIBUTE_UNUSED, 224 bfd_vma pc ATTRIBUTE_UNUSED, 225 int length ATTRIBUTE_UNUSED) 226{ 227 print_register_list (dis_info, value, 8, 1 /* Store. */); 228} 229 230static void 231print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 232 void * dis_info, 233 long value, 234 unsigned int attrs ATTRIBUTE_UNUSED, 235 bfd_vma pc ATTRIBUTE_UNUSED, 236 int length ATTRIBUTE_UNUSED) 237{ 238 print_register_list (dis_info, value, 0, 1 /* Store. */); 239} 240 241static void 242print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 243 void * dis_info, 244 long value, 245 unsigned int attrs ATTRIBUTE_UNUSED, 246 bfd_vma pc ATTRIBUTE_UNUSED, 247 int length ATTRIBUTE_UNUSED) 248{ 249 disassemble_info *info = (disassemble_info *) dis_info; 250 251 (*info->fprintf_func) (info->stream, "%ld", value); 252} 253/* -- */ 254