aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/opcode/ChangeLog5
-rw-r--r--include/opcode/cgen.h6
-rw-r--r--opcodes/ChangeLog7
-rw-r--r--opcodes/cgen-dis.in4
-rw-r--r--opcodes/cgen-opc.c57
5 files changed, 74 insertions, 5 deletions
diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog
index 8ab1f70..a027c8d 100644
--- a/include/opcode/ChangeLog
+++ b/include/opcode/ChangeLog
@@ -1,3 +1,8 @@
+2001-07-11 Frank Ch. Eigler <fche@redhat.com>
+
+ * cgen.h (CGEN_MACH): Add insn_chunk_bitsize field.
+ (cgen_cpu_desc): Ditto.
+
2001-07-07 Ben Elliston <bje@redhat.com>
* m88k.h: Clean up and reformat. Remove unused code.
diff --git a/include/opcode/cgen.h b/include/opcode/cgen.h
index c13c4d9..c01b5c2 100644
--- a/include/opcode/cgen.h
+++ b/include/opcode/cgen.h
@@ -199,6 +199,8 @@ typedef struct {
const char *bfd_name;
/* one of enum mach_attr */
int num;
+ /* parameter from mach->cpu */
+ unsigned int insn_chunk_bitsize;
} CGEN_MACH;
/* Parse result (also extraction result).
@@ -1166,6 +1168,10 @@ typedef struct cgen_cpu_desc
lazily fetch the data from there. */
unsigned int word_bitsize;
+ /* Instruction chunk size (in bits), for purposes of endianness
+ conversion. */
+ unsigned int insn_chunk_bitsize;
+
/* Indicator if sizes are unknown.
This is used by default_insn_bitsize,base_insn_bitsize if there is a
difference between the selected isa's. */
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 2953237..4adba8a 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,3 +1,10 @@
+2001-07-11 Frank Ch. Eigler <fche@redhat.com>
+
+ * cgen-dis.in (print_insn): Use cgen_get_insn_value instead of
+ bfd_get_bits.
+ * cgen-opc.c (cgen_get_insn_value, cgen_put_insn_value): Respect
+ non-zero CGEN_CPU_DESC->insn_chunk_bitsize.
+
2001-07-09 Andreas Jaeger <aj@suse.de>, Karsten Keil <kkeil@suse.de>
* i386-dis.c (set_op): Handle 64 bit and 32 bit mode.
diff --git a/opcodes/cgen-dis.in b/opcodes/cgen-dis.in
index b2372fd..2c4ce7f 100644
--- a/opcodes/cgen-dis.in
+++ b/opcodes/cgen-dis.in
@@ -229,12 +229,12 @@ print_insn (cd, pc, info, buf, buflen)
char *buf;
int buflen;
{
- unsigned long insn_value;
+ CGEN_INSN_INT insn_value;
const CGEN_INSN_LIST *insn_list;
CGEN_EXTRACT_INFO ex_info;
/* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
- insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
+ insn_value = cgen_get_insn_value (cd, buf, buflen * 8);
/* Fill in ex_info fields like read_insn would. Don't actually call
read_insn, since the incoming buffer is already read (and possibly
diff --git a/opcodes/cgen-opc.c b/opcodes/cgen-opc.c
index 188a157..9dfc16e 100644
--- a/opcodes/cgen-opc.c
+++ b/opcodes/cgen-opc.c
@@ -391,7 +391,35 @@ cgen_get_insn_value (cd, buf, length)
unsigned char *buf;
int length;
{
- return bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
+ int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
+ int insn_chunk_bitsize = cd->insn_chunk_bitsize;
+ CGEN_INSN_INT value = 0;
+
+ if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
+ {
+ /* We need to divide up the incoming value into insn_chunk_bitsize-length
+ segments, and endian-convert them, one at a time. */
+ int i;
+
+ /* Enforce divisibility. */
+ if ((length % insn_chunk_bitsize) != 0)
+ abort ();
+
+ for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
+ {
+ int index;
+ bfd_vma this_value;
+ index = i; /* NB: not dependent on endianness; opposite of cgen_put_insn_value! */
+ this_value = bfd_get_bits (& buf[index / 8], insn_chunk_bitsize, big_p);
+ value = (value << insn_chunk_bitsize) | this_value;
+ }
+ }
+ else
+ {
+ value = bfd_get_bits (buf, length, cd->insn_endian == CGEN_ENDIAN_BIG);
+ }
+
+ return value;
}
/* Cover function to store an insn value properly byteswapped. */
@@ -403,8 +431,31 @@ cgen_put_insn_value (cd, buf, length, value)
int length;
CGEN_INSN_INT value;
{
- bfd_put_bits ((bfd_vma) value, buf, length,
- cd->insn_endian == CGEN_ENDIAN_BIG);
+ int big_p = (cd->insn_endian == CGEN_ENDIAN_BIG);
+ int insn_chunk_bitsize = cd->insn_chunk_bitsize;
+
+ if (insn_chunk_bitsize != 0 && insn_chunk_bitsize < length)
+ {
+ /* We need to divide up the incoming value into insn_chunk_bitsize-length
+ segments, and endian-convert them, one at a time. */
+ int i;
+
+ /* Enforce divisibility. */
+ if ((length % insn_chunk_bitsize) != 0)
+ abort ();
+
+ for (i = 0; i < length; i += insn_chunk_bitsize) /* NB: i == bits */
+ {
+ int index;
+ index = (length - insn_chunk_bitsize - i); /* NB: not dependent on endianness! */
+ bfd_put_bits ((bfd_vma) value, & buf[index / 8], insn_chunk_bitsize, big_p);
+ value >>= insn_chunk_bitsize;
+ }
+ }
+ else
+ {
+ bfd_put_bits ((bfd_vma) value, buf, length, big_p);
+ }
}
/* Look up instruction INSN_*_VALUE and extract its fields.