summaryrefslogtreecommitdiff
path: root/opcodes/cgen-opc.c
diff options
context:
space:
mode:
authorFrank Ch. Eigler <fche@redhat.com>2001-07-12 02:32:25 +0000
committerFrank Ch. Eigler <fche@redhat.com>2001-07-12 02:32:25 +0000
commita0f3fd1ec805986ef571cda5b295ee1edba410e6 (patch)
treee05e4c4498995b23df5d0b6dec738da02bc64926 /opcodes/cgen-opc.c
parentacf20f18a97063c87a6169d6493150c7bff7e813 (diff)
downloadbinutils-redhat-a0f3fd1ec805986ef571cda5b295ee1edba410e6.tar.gz
* some support for funny-endian 16/32-bit insn sets
[cgen/ChangeLog] 2001-07-11 Frank Ch. Eigler <fche@redhat.com> * desc-cpu.scm (-gen-mach-table-defns): Emit fourth field: the mach->cpu insn-chunk-bitsize. (-gen-cpu-open): In @arch@_cgen_rebuild_tables, process above new field toward CGEN_CPU_TABLE->insn_chunk_bitsize. * mach.scm (<cpu>): New field insn-chunk-bitsize. (-cpu-parse, -cpu-read): Parse/initialize it. * doc/rtl.texi (define-cpu): Document it. [opcodes/ChangeLog] 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. [include/opcode/ChangeLog] 2001-07-11 Frank Ch. Eigler <fche@redhat.com> * cgen.h (CGEN_MACH): Add insn_chunk_bitsize field. (cgen_cpu_desc): Ditto.
Diffstat (limited to 'opcodes/cgen-opc.c')
-rw-r--r--opcodes/cgen-opc.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/opcodes/cgen-opc.c b/opcodes/cgen-opc.c
index 188a157f3a..9dfc16e9e5 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.