diff options
author | Andrew Burgess <andrew.burgess@embecosm.com> | 2016-03-24 16:54:37 +0000 |
---|---|---|
committer | Andrew Burgess <andrew.burgess@embecosm.com> | 2016-04-14 17:15:18 +0100 |
commit | cb040366b36ca624874e036805ca1fca740dae9f (patch) | |
tree | 774830bc95253881147800e16dbf1ab067da3d9d /opcodes/arc-dis.c | |
parent | 7634c4e679156fc6a93ccb8b33898f5cf41eb233 (diff) | |
download | gdb-cb040366b36ca624874e036805ca1fca740dae9f.zip gdb-cb040366b36ca624874e036805ca1fca740dae9f.tar.gz gdb-cb040366b36ca624874e036805ca1fca740dae9f.tar.bz2 |
opcodes/arc: Move instruction length logic to new function
Move the logic that calculates the instruction length out to a new
function. Restructure the code to make it simpler.
opcodes/ChangeLog:
* arc-dis.c (arc_insn_length): New function.
(print_insn_arc): Use arc_insn_length, change insnLen to unsigned.
(find_format): Change insnLen parameter to unsigned.
Diffstat (limited to 'opcodes/arc-dis.c')
-rw-r--r-- | opcodes/arc-dis.c | 57 |
1 files changed, 44 insertions, 13 deletions
diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index eb8bd67..7757ef6 100644 --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -105,7 +105,7 @@ special_flag_p (const char *opname, /* Find proper format for the given opcode. */ static const struct arc_opcode * find_format (const struct arc_opcode *arc_table, - unsigned *insn, int insnLen, + unsigned *insn, unsigned int insnLen, unsigned isa_mask) { unsigned int i = 0; @@ -309,6 +309,37 @@ get_auxreg (const struct arc_opcode *opcode, } return NULL; } + +/* Calculate the instruction length for an instruction starting with MSB + and LSB, the most and least significant byte. The ISA_MASK is used to + filter the instructions considered to only those that are part of the + current architecture. + + The instruction lengths are calculated from the ARC_OPCODE table, and + cached for later use. */ + +static unsigned int +arc_insn_length (bfd_byte msb, struct disassemble_info *info) +{ + bfd_byte major_opcode = msb >> 3; + + switch (info->mach) + { + case bfd_mach_arc_nps400: + case bfd_mach_arc_arc700: + case bfd_mach_arc_arc600: + return (major_opcode > 0xb) ? 2 : 4; + break; + + case bfd_mach_arc_arcv2: + return (major_opcode > 0x7) ? 2 : 4; + break; + + default: + abort (); + } +} + /* Disassemble ARC instructions. */ static int @@ -318,7 +349,7 @@ print_insn_arc (bfd_vma memaddr, bfd_byte buffer[4]; unsigned int lowbyte, highbyte; int status; - int insnLen = 0; + unsigned int insnLen; unsigned insn[2] = { 0, 0 }; unsigned isa_mask; const unsigned char *opidx; @@ -422,20 +453,19 @@ print_insn_arc (bfd_vma memaddr, return size; } - if ((((buffer[lowbyte] & 0xf8) > 0x38) - && ((buffer[lowbyte] & 0xf8) != 0x48)) - || ((info->mach == bfd_mach_arc_arcv2) - && ((buffer[lowbyte] & 0xF8) == 0x48)) /* FIXME! ugly. */ - ) + insnLen = arc_insn_length (buffer[lowbyte], info); + switch (insnLen) { - /* This is a short instruction. */ - insnLen = 2; + case 2: insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte]; - } - else - { - insnLen = 4; + break; + default: + /* An unknown instruction is treated as being length 4. This is + possibly not the best solution, but matches the behaviour that was + in place before the table based instruction length look-up was + introduced. */ + case 4: /* This is a long instruction: Read the remaning 2 bytes. */ status = (*info->read_memory_func) (memaddr + 2, &buffer[2], 2, info); if (status != 0) @@ -444,6 +474,7 @@ print_insn_arc (bfd_vma memaddr, return -1; } insn[0] = ARRANGE_ENDIAN (info, buffer); + break; } /* Set some defaults for the insn info. */ |