X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=opcodes%2Ffr30-dis.c;h=f171395cbeafe912ab53b62c98743f21b65a8548;hb=677f415c03a33889e1f133003f2e3dc15368dcb3;hp=d2cbab3d16720557c7aec77d69793e8280faeb64;hpb=1c8f439ec6f8f43fa3a6e1987fb5ea23ebd910f8;p=deliverable%2Fbinutils-gdb.git diff --git a/opcodes/fr30-dis.c b/opcodes/fr30-dis.c index d2cbab3d16..f171395cbe 100644 --- a/opcodes/fr30-dis.c +++ b/opcodes/fr30-dis.c @@ -40,9 +40,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., /* Default text to print if an instruction isn't recognized. */ #define UNKNOWN_INSN_MSG _("*unknown*") +/* Used by the ifield rtx function. */ +#define FLD(f) (fields->f) + static int extract_normal - PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES, - unsigned int, int, int, int, long *)); + PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT, + unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, bfd_vma, long *)); static void print_normal PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int)); static void print_address @@ -51,7 +55,7 @@ static void print_keyword PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int)); static int extract_insn_normal PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *, - unsigned long, CGEN_FIELDS *, bfd_vma)); + CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma)); static void print_insn_normal PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int)); @@ -61,6 +65,107 @@ static int default_print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *)); /* -- disassembler routines inserted here */ +/* -- dis.c */ + +static void +print_register_list (dis_info, value, offset, load_store) + PTR dis_info; + long value; + long offset; + int load_store; /* 0 == load, 1 == store */ +{ + disassemble_info *info = dis_info; + int mask; + int index = 0; + char* comma = ""; + + if (load_store) + mask = 0x80; + else + mask = 1; + + if (value & mask) + { + (*info->fprintf_func) (info->stream, "r%i", index + offset); + comma = ","; + } + + for (index = 1; index <= 7; ++index) + { + if (load_store) + mask >>= 1; + else + mask <<= 1; + + if (value & mask) + { + (*info->fprintf_func) (info->stream, "%sr%i", comma, index + offset); + comma = ","; + } + } +} + +static void +print_hi_register_list_ld (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + print_register_list (dis_info, value, 8, 0/*load*/); +} + +static void +print_low_register_list_ld (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + print_register_list (dis_info, value, 0, 0/*load*/); +} + +static void +print_hi_register_list_st (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + print_register_list (dis_info, value, 8, 1/*store*/); +} + +static void +print_low_register_list_st (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + PTR dis_info; + long value; + unsigned int attrs; + bfd_vma pc; + int length; +{ + print_register_list (dis_info, value, 0, 1/*store*/); +} + +static void +print_m4 (od, dis_info, value, attrs, pc, length) + CGEN_OPCODE_DESC od; + 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, "%ld", value); +} +/* -- */ /* Main entry point for operand extraction. @@ -81,19 +186,178 @@ fr30_cgen_extract_operand (od, opindex, ex_info, insn_value, fields, pc) CGEN_OPCODE_DESC od; int opindex; CGEN_EXTRACT_INFO *ex_info; - CGEN_INSN_BYTES insn_value; + CGEN_INSN_INT insn_value; CGEN_FIELDS * fields; bfd_vma pc; { int length; + unsigned int total_length = CGEN_FIELDS_BITSIZE (fields); switch (opindex) { case FR30_OPERAND_RI : - length = extract_normal (od, ex_info, insn_value, 0|(1<f_Ri); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Ri); break; case FR30_OPERAND_RJ : - length = extract_normal (od, ex_info, insn_value, 0|(1<f_Rj); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Rj); + break; + case FR30_OPERAND_RIC : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Ric); + break; + case FR30_OPERAND_RJC : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Rjc); + break; + case FR30_OPERAND_CRI : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_CRi); + break; + case FR30_OPERAND_CRJ : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_CRj); + break; + case FR30_OPERAND_RS1 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Rs1); + break; + case FR30_OPERAND_RS2 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_Rs2); + break; + case FR30_OPERAND_R13 : + length = extract_normal (od, ex_info, insn_value, 0, 0, 0, 0, 0, total_length, pc, & fields->f_nil); + break; + case FR30_OPERAND_R14 : + length = extract_normal (od, ex_info, insn_value, 0, 0, 0, 0, 0, total_length, pc, & fields->f_nil); + break; + case FR30_OPERAND_R15 : + length = extract_normal (od, ex_info, insn_value, 0, 0, 0, 0, 0, total_length, pc, & fields->f_nil); + break; + case FR30_OPERAND_PS : + length = extract_normal (od, ex_info, insn_value, 0, 0, 0, 0, 0, total_length, pc, & fields->f_nil); + break; + case FR30_OPERAND_U4 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_u4); + break; + case FR30_OPERAND_U4C : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_u4c); + break; + case FR30_OPERAND_U8 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_u8); + break; + case FR30_OPERAND_I8 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_i8); + break; + case FR30_OPERAND_UDISP6 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_udisp6 = value; + } + break; + case FR30_OPERAND_DISP8 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp8); + break; + case FR30_OPERAND_DISP9 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp9 = value; + } + break; + case FR30_OPERAND_DISP10 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_disp10 = value; + } + break; + case FR30_OPERAND_S10 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_s10 = value; + } + break; + case FR30_OPERAND_U10 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_u10 = value; + } + break; + case FR30_OPERAND_I32 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_i32); + break; + case FR30_OPERAND_M4 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_m4 = value; + } + break; + case FR30_OPERAND_I20 : + { + length = extract_normal (od, ex_info, insn_value, 0|(1<f_i20_4); + length = extract_normal (od, ex_info, insn_value, 0|(1<f_i20_16); +do { + FLD (f_i20) = ((((FLD (f_i20_4)) << (16))) | (FLD (f_i20_16))); +} while (0); + } + break; + case FR30_OPERAND_DIR8 : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_dir8); + break; + case FR30_OPERAND_DIR9 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_dir9 = value; + } + break; + case FR30_OPERAND_DIR10 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_dir10 = value; + } + break; + case FR30_OPERAND_LABEL9 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_rel9 = value; + } + break; + case FR30_OPERAND_LABEL12 : + { + long value; + length = extract_normal (od, ex_info, insn_value, 0|(1<f_rel12 = value; + } + break; + case FR30_OPERAND_REGLIST_LOW_LD : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_reglist_low_ld); + break; + case FR30_OPERAND_REGLIST_HI_LD : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_reglist_hi_ld); + break; + case FR30_OPERAND_REGLIST_LOW_ST : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_reglist_low_st); + break; + case FR30_OPERAND_REGLIST_HI_ST : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_reglist_hi_st); + break; + case FR30_OPERAND_CC : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_cc); + break; + case FR30_OPERAND_CCC : + length = extract_normal (od, ex_info, insn_value, 0|(1<f_ccc); break; default : @@ -138,6 +402,108 @@ fr30_cgen_print_operand (od, opindex, info, fields, attrs, pc, length) case FR30_OPERAND_RJ : print_keyword (od, info, & fr30_cgen_opval_h_gr, fields->f_Rj, 0|(1<f_Ric, 0|(1<f_Rjc, 0|(1<f_CRi, 0|(1<f_CRj, 0|(1<f_Rs1, 0|(1<f_Rs2, 0|(1<f_nil, 0); + break; + case FR30_OPERAND_R14 : + print_keyword (od, info, & fr30_cgen_opval_h_r14, fields->f_nil, 0); + break; + case FR30_OPERAND_R15 : + print_keyword (od, info, & fr30_cgen_opval_h_r15, fields->f_nil, 0); + break; + case FR30_OPERAND_PS : + print_keyword (od, info, & fr30_cgen_opval_h_ps, fields->f_nil, 0); + break; + case FR30_OPERAND_U4 : + print_normal (od, info, fields->f_u4, 0|(1<f_u4c, 0|(1<f_u8, 0|(1<f_i8, 0|(1<f_udisp6, 0|(1<f_disp8, 0|(1<f_disp9, 0|(1<f_disp10, 0|(1<f_s10, 0|(1<f_u10, 0|(1<f_i32, 0|(1<f_m4, 0|(1<f_i20, 0|(1<f_dir8, 0|(1<f_dir9, 0|(1<f_dir10, 0|(1<f_rel9, 0|(1<f_rel12, 0|(1<f_reglist_low_ld, 0|(1<f_reglist_hi_ld, 0|(1<f_reglist_low_st, 0|(1<f_reglist_hi_st, 0|(1<f_cc, 0|(1<f_ccc, 0|(1<dis_info; + + /* First do a quick check. */ + mask = (1 << bytes) - 1; + if (((ex_info->valid >> offset) & mask) == mask) + return 1; + + /* Search for the first byte we need to read. */ + for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1) + if (! (mask & ex_info->valid)) + break; + + if (bytes) + { + int status; + + pc += offset; + status = (*info->read_memory_func) + (pc, ex_info->insn_bytes + offset, bytes, info); + + if (status != 0) + { + (*info->memory_error_func) (status, pc, info); + return 0; + } + + ex_info->valid |= ((1 << bytes) - 1) << offset; + } + + return 1; +} + /* Subroutine of extract_normal. */ static INLINE long -extract_1 (od, ex_info, start, length, word_length, bufp) +extract_1 (od, ex_info, start, length, word_length, bufp, pc) CGEN_OPCODE_DESC od; - CGEN_EXTRACT_INFO *info; + CGEN_EXTRACT_INFO *ex_info; int start,length,word_length; unsigned char *bufp; + bfd_vma pc; { unsigned long x,mask; int shift; int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG; - /* FIXME: Need to use ex_info to ensure bytes have been fetched. */ - switch (word_length) { case 8: @@ -199,9 +612,9 @@ extract_1 (od, ex_info, start, length, word_length, bufp) /* ??? This may need reworking as these cases don't necessarily want the first byte and the last two bytes handled like this. */ if (big_p) - x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1); + x = (bufp[0] << 16) | bfd_getb16 (bufp + 1); else - x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16); + x = bfd_getl16 (bufp) | (bufp[2] << 16); break; case 32: if (big_p) @@ -216,7 +629,7 @@ extract_1 (od, ex_info, start, length, word_length, bufp) /* Written this way to avoid undefined behaviour. */ mask = (((1L << (length - 1)) - 1) << 1) | 1; if (CGEN_INSN_LSB0_P) - shift = start; + shift = (start + 1) - length; else shift = (word_length - (start + length)); return (x >> shift) & mask; @@ -226,22 +639,36 @@ extract_1 (od, ex_info, start, length, word_length, bufp) /* Default extraction routine. - ATTRS is a mask of the boolean attributes. We only need `unsigned', - but for generality we take a bitmask of all of them. */ + INSN_VALUE is the first CGEN_BASE_INSN_SIZE bits of the insn in host order, + or sometimes less for cases like the m32r where the base insn size is 32 + but some insns are 16 bits. + ATTRS is a mask of the boolean attributes. We only need `UNSIGNED', + but for generality we take a bitmask of all of them. + WORD_OFFSET is the offset in bits from the start of the insn of the value. + WORD_LENGTH is the length of the word in bits in which the value resides. + START is the starting bit number in the word, architecture origin. + LENGTH is the length of VALUE in bits. + TOTAL_LENGTH is the total length of the insn in bits. + + Returns 1 for success, 0 for failure. */ + +/* ??? The return code isn't properly used. wip. */ /* ??? This doesn't handle bfd_vma's. Create another function when necessary. */ static int -extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep) +extract_normal (od, ex_info, insn_value, attrs, word_offset, start, length, + word_length, total_length, pc, valuep) CGEN_OPCODE_DESC od; CGEN_EXTRACT_INFO *ex_info; - CGEN_INSN_BYTES insn_value; + CGEN_INSN_INT insn_value; unsigned int attrs; - int start, length, total_length; + unsigned int word_offset, start, length, word_length, total_length; + bfd_vma pc; long *valuep; { - unsigned long value; + CGEN_INSN_INT value; /* If LENGTH is zero, this operand doesn't contribute to the value so give it a standard value of zero. */ @@ -251,100 +678,58 @@ extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, val return 1; } -#if CGEN_INT_INSN_P - - { - /* Written this way to avoid undefined behaviour. */ - unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1; - - if (CGEN_INSN_LSB0_P) - value = insn_value >> start; - else - value = insn_value >> (total_length - (start + length)); - value &= mask; - /* sign extend? */ - if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED)) - && (value & (1L << (length - 1)))) - value |= ~mask; - } - -#else + if (CGEN_INT_INSN_P + && word_offset != 0) + abort (); - /* The hard case is probably too slow for the normal cases. - It's certainly more difficult to understand than the normal case. - Thus this is split into two. Keep it that way. The hard case is defined - to be when a field straddles a (loosely defined) word boundary - (??? which may require target specific help to determine). */ + if (word_length > 32) + abort (); -#if 0 /*wip*/ + /* For architectures with insns smaller than the insn-base-bitsize, + word_length may be too big. */ +#if CGEN_MIN_INSN_BITSIZE < CGEN_BASE_INSN_BITSIZE + if (word_offset == 0 + && word_length > total_length) + word_length = total_length; +#endif -#define HARD_CASE_P 0 /* FIXME:wip */ + /* Does the value reside in INSN_VALUE? */ - if (HARD_CASE_P) + if (word_offset == 0) { + /* Written this way to avoid undefined behaviour. */ + CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1; + + if (CGEN_INSN_LSB0_P) + value = insn_value >> ((start + 1) - length); + else + value = insn_value >> (word_length - (start + length)); + value &= mask; + /* sign extend? */ + if (! CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED) + && (value & (1L << (length - 1)))) + value |= ~mask; } -#endif + +#if ! CGEN_INT_INSN_P + else { - unsigned char *bufp = (unsigned char *) insn_value; + unsigned char *bufp = ex_info->insn_bytes + word_offset / 8; - if (length > 32) + if (word_length > 32) abort (); - /* Adjust start,total_length,bufp to point to the pseudo-word that holds - the value. For example in a 48 bit insn where the value to insert - (say an immediate value) is the last 16 bits then word_length here - would be 16. To handle a 24 bit insn with an 18 bit immediate, - extract_1 handles 24 bits (using a combination of bfd_get8,16). */ - - if (total_length > 32) - { - int needed_width = start % 8 + length; - int fetch_length = (needed_width <= 8 ? 8 - : needed_width <= 16 ? 16 - : 32); - - if (CGEN_INSN_LSB0_P) - { - if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) - { - abort (); /* wip */ - } - else - { - int offset = start & ~7; - - bufp += offset / 8; - start -= offset; - total_length -= offset; - } - } - else - { - if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG) - { - int offset = start & ~7; - - bufp += offset / 8; - start -= offset; - total_length -= offset; - } - else - { - abort (); /* wip */ - } - } - } + if (fill_cache (od, ex_info, word_offset / 8, word_length / 8, pc) == 0) + return 0; - /* FIXME: which bytes are being extracted have been lost. */ - value = extract_1 (od, ex_info, start, length, total_length, bufp); + value = extract_1 (od, ex_info, start, length, word_length, bufp, pc); } #endif /* ! CGEN_INT_INSN_P */ *valuep = value; - /* FIXME: for now */ return 1; } @@ -438,7 +823,7 @@ extract_insn_normal (od, insn, ex_info, insn_value, fields, pc) CGEN_OPCODE_DESC od; const CGEN_INSN *insn; CGEN_EXTRACT_INFO *ex_info; - unsigned long insn_value; + CGEN_INSN_INT insn_value; CGEN_FIELDS *fields; bfd_vma pc; { @@ -525,7 +910,7 @@ print_insn (od, pc, info, buf, buflen) ex_info.dis_info = info; ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1; - ex_info.bytes = buf; + ex_info.insn_bytes = buf; switch (buflen) { @@ -561,7 +946,8 @@ print_insn (od, pc, info, buf, buflen) /* Basic bit mask must be correct. */ /* ??? May wish to allow target to defer this check until the extract handler. */ - if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn)) + if ((insn_value & CGEN_INSN_BASE_MASK (insn)) + == CGEN_INSN_BASE_VALUE (insn)) { /* Printing is handled in two passes. The first pass parses the machine insn and extracts the fields. The second pass prints