diff options
Diffstat (limited to 'cpu/fr30.opc')
-rw-r--r-- | cpu/fr30.opc | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/cpu/fr30.opc b/cpu/fr30.opc new file mode 100644 index 0000000..b09148e --- /dev/null +++ b/cpu/fr30.opc @@ -0,0 +1,253 @@ +/* FR30 opcode support. -*- C -*- + Copyright 2011 Free Software Foundation, Inc. + + Contributed by Red Hat Inc; + + This file is part of the GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* This file is an addendum to fr30.cpu. Heavy use of C code isn't + appropriate in .cpu files, so it resides here. This especially applies + to assembly/disassembly where parsing/printing can be quite involved. + Such things aren't really part of the specification of the cpu, per se, + so .cpu files provide the general framework and .opc files handle the + nitty-gritty details as necessary. + + Each section is delimited with start and end markers. + + <arch>-opc.h additions use: "-- opc.h" + <arch>-opc.c additions use: "-- opc.c" + <arch>-asm.c additions use: "-- asm.c" + <arch>-dis.c additions use: "-- dis.c" + <arch>-ibd.h additions use: "-- ibd.h". */ + +/* -- opc.h */ + +/* ??? This can be improved upon. */ +#undef CGEN_DIS_HASH_SIZE +#define CGEN_DIS_HASH_SIZE 16 +#undef CGEN_DIS_HASH +#define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4) + +/* -- */ + +/* -- asm.c */ +/* Handle register lists for LDMx and STMx. */ + +static int +parse_register_number (const char **strp) +{ + int regno; + + if (**strp < '0' || **strp > '9') + return -1; /* Error. */ + regno = **strp - '0'; + ++*strp; + + if (**strp >= '0' && **strp <= '9') + { + regno = regno * 10 + (**strp - '0'); + ++*strp; + } + + return regno; +} + +static const char * +parse_register_list (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + const char **strp, + int opindex ATTRIBUTE_UNUSED, + unsigned long *valuep, + int high_low, /* 0 == high, 1 == low. */ + int load_store) /* 0 == load, 1 == store. */ +{ + *valuep = 0; + while (**strp && **strp != ')') + { + int regno; + + if (**strp != 'R' && **strp != 'r') + break; + ++*strp; + + regno = parse_register_number (strp); + if (regno == -1) + return _("Register number is not valid"); + if (regno > 7 && !high_low) + return _("Register must be between r0 and r7"); + if (regno < 8 && high_low) + return _("Register must be between r8 and r15"); + + if (high_low) + regno -= 8; + + if (load_store) /* Mask is reversed for store. */ + *valuep |= 0x80 >> regno; + else + *valuep |= 1 << regno; + + if (**strp == ',') + { + if (*(*strp + 1) == ')') + break; + ++*strp; + } + } + + if (!*strp || **strp != ')') + return _("Register list is not valid"); + + return NULL; +} + +static const char * +parse_low_register_list_ld (CGEN_CPU_DESC cd, + const char **strp, + int opindex, + unsigned long *valuep) +{ + return parse_register_list (cd, strp, opindex, valuep, + 0 /* Low. */, 0 /* Load. */); +} + +static const char * +parse_hi_register_list_ld (CGEN_CPU_DESC cd, + const char **strp, + int opindex, + unsigned long *valuep) +{ + return parse_register_list (cd, strp, opindex, valuep, + 1 /* High. */, 0 /* Load. */); +} + +static const char * +parse_low_register_list_st (CGEN_CPU_DESC cd, + const char **strp, + int opindex, + unsigned long *valuep) +{ + return parse_register_list (cd, strp, opindex, valuep, + 0 /* Low. */, 1 /* Store. */); +} + +static const char * +parse_hi_register_list_st (CGEN_CPU_DESC cd, + const char **strp, + int opindex, + unsigned long *valuep) +{ + return parse_register_list (cd, strp, opindex, valuep, + 1 /* High. */, 1 /* Store. */); +} + +/* -- */ + +/* -- dis.c */ +static void +print_register_list (void * dis_info, + long value, + long offset, + int load_store) /* 0 == load, 1 == store. */ +{ + disassemble_info *info = dis_info; + int mask; + int reg_index = 0; + char * comma = ""; + + if (load_store) + mask = 0x80; + else + mask = 1; + + if (value & mask) + { + (*info->fprintf_func) (info->stream, "r%li", reg_index + offset); + comma = ","; + } + + for (reg_index = 1; reg_index <= 7; ++reg_index) + { + if (load_store) + mask >>= 1; + else + mask <<= 1; + + if (value & mask) + { + (*info->fprintf_func) (info->stream, "%sr%li", comma, reg_index + offset); + comma = ","; + } + } +} + +static void +print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + print_register_list (dis_info, value, 8, 0 /* Load. */); +} + +static void +print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + print_register_list (dis_info, value, 0, 0 /* Load. */); +} + +static void +print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + print_register_list (dis_info, value, 8, 1 /* Store. */); +} + +static void +print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + print_register_list (dis_info, value, 0, 1 /* Store. */); +} + +static void +print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, + void * dis_info, + long value, + unsigned int attrs ATTRIBUTE_UNUSED, + bfd_vma pc ATTRIBUTE_UNUSED, + int length ATTRIBUTE_UNUSED) +{ + disassemble_info *info = (disassemble_info *) dis_info; + + (*info->fprintf_func) (info->stream, "%ld", value); +} +/* -- */ |