summaryrefslogtreecommitdiff
path: root/cgen/m32r.opc
diff options
context:
space:
mode:
Diffstat (limited to 'cgen/m32r.opc')
-rw-r--r--cgen/m32r.opc264
1 files changed, 264 insertions, 0 deletions
diff --git a/cgen/m32r.opc b/cgen/m32r.opc
new file mode 100644
index 00000000000..601ca58d121
--- /dev/null
+++ b/cgen/m32r.opc
@@ -0,0 +1,264 @@
+/* M32R opcode support. -*- C -*-
+ Copyright (C) 2000 Red Hat, Inc.
+ This file is part of CGEN. */
+
+/* This file is an addendum to m32r.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 */
+
+#undef CGEN_DIS_HASH_SIZE
+#define CGEN_DIS_HASH_SIZE 256
+#undef CGEN_DIS_HASH
+#define X(b) (((unsigned char *) (b))[0] & 0xf0)
+#define CGEN_DIS_HASH(buffer, value) \
+(X (buffer) | \
+ (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
+ : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
+ : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
+ : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
+
+/* -- */
+
+/* -- asm.c */
+
+/* Handle '#' prefixes (i.e. skip over them). */
+
+static const char *
+parse_hash (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ if (**strp == '#')
+ ++*strp;
+ return NULL;
+}
+
+/* Handle shigh(), high(). */
+
+static const char *
+parse_hi16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "high(", 5) == 0)
+ {
+ *strp += 5;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value >>= 16;
+ *valuep = value;
+ return errmsg;
+ }
+ else if (strncasecmp (*strp, "shigh(", 6) == 0)
+ {
+ *strp += 6;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value = (value >> 16) + (value & 0x8000 ? 1 : 0);
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
+}
+
+/* Handle low() in a signed context. Also handle sda().
+ The signedness of the value doesn't matter to low(), but this also
+ handles the case where low() isn't present. */
+
+static const char *
+parse_slo16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "low(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value &= 0xffff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ if (strncasecmp (*strp, "sda(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
+ NULL, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_signed_integer (cd, strp, opindex, valuep);
+}
+
+/* Handle low() in an unsigned context.
+ The signedness of the value doesn't matter to low(), but this also
+ handles the case where low() isn't present. */
+
+static const char *
+parse_ulo16 (cd, strp, opindex, valuep)
+ CGEN_CPU_DESC cd;
+ const char **strp;
+ int opindex;
+ unsigned long *valuep;
+{
+ const char *errmsg;
+ enum cgen_parse_operand_result result_type;
+ bfd_vma value;
+
+ if (**strp == '#')
+ ++*strp;
+
+ if (strncasecmp (*strp, "low(", 4) == 0)
+ {
+ *strp += 4;
+ errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
+ &result_type, &value);
+ if (**strp != ')')
+ return "missing `)'";
+ ++*strp;
+ if (errmsg == NULL
+ && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+ value &= 0xffff;
+ *valuep = value;
+ return errmsg;
+ }
+
+ return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
+}
+
+/* -- */
+
+/* -- dis.c */
+
+/* Immediate values are prefixed with '#'. */
+
+#define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
+do { \
+ if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
+ (*info->fprintf_func) (info->stream, "#"); \
+} while (0)
+
+/* Handle '#' prefixes as operands. */
+
+static void
+print_hash (cd, dis_info, value, attrs, pc, length)
+ CGEN_CPU_DESC cd;
+ PTR dis_info;
+ long value;
+ unsigned int attrs;
+ bfd_vma pc;
+ int length;
+{
+ disassemble_info *info = (disassemble_info *) dis_info;
+ (*info->fprintf_func) (info->stream, "#");
+}
+
+#undef CGEN_PRINT_INSN
+#define CGEN_PRINT_INSN my_print_insn
+
+static int
+my_print_insn (cd, pc, info)
+ CGEN_CPU_DESC cd;
+ bfd_vma pc;
+ disassemble_info *info;
+{
+ char buffer[CGEN_MAX_INSN_SIZE];
+ char *buf = buffer;
+ int status;
+ int buflen = (pc & 3) == 0 ? 4 : 2;
+
+ /* Read the base part of the insn. */
+
+ status = (*info->read_memory_func) (pc, buf, buflen, info);
+ if (status != 0)
+ {
+ (*info->memory_error_func) (status, pc, info);
+ return -1;
+ }
+
+ /* 32 bit insn? */
+ if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
+ return print_insn (cd, pc, info, buf, buflen);
+
+ /* Print the first insn. */
+ if ((pc & 3) == 0)
+ {
+ if (print_insn (cd, pc, info, buf, 2) == 0)
+ (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
+ buf += 2;
+ }
+
+ if (buf[0] & 0x80)
+ {
+ /* Parallel. */
+ (*info->fprintf_func) (info->stream, " || ");
+ buf[0] &= 0x7f;
+ }
+ else
+ (*info->fprintf_func) (info->stream, " -> ");
+
+ /* The "& 3" is to pass a consistent address.
+ Parallel insns arguably both begin on the word boundary.
+ Also, branch insns are calculated relative to the word boundary. */
+ if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
+ (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
+
+ return (pc & 3) ? 2 : 4;
+}
+
+/* -- */