/* 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. -opc.h additions use: "-- opc.h" -opc.c additions use: "-- opc.c" -asm.c additions use: "-- asm.c" -dis.c additions use: "-- dis.c" -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; } /* -- */