From 81f6038f98bd3ca48651c22779ffe6231d0873a0 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 12 Jul 2001 02:32:25 +0000 Subject: [PATCH] * some support for funny-endian 16/32-bit insn sets [cgen/ChangeLog] 2001-07-11 Frank Ch. Eigler * 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 (): 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 * 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 * cgen.h (CGEN_MACH): Add insn_chunk_bitsize field. (cgen_cpu_desc): Ditto. --- include/opcode/ChangeLog | 5 ++++ include/opcode/cgen.h | 6 +++++ opcodes/ChangeLog | 7 +++++ opcodes/cgen-dis.in | 4 +-- opcodes/cgen-opc.c | 57 +++++++++++++++++++++++++++++++++++++--- 5 files changed, 74 insertions(+), 5 deletions(-) diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog index 8ab1f704f14..a027c8df7d1 100644 --- a/include/opcode/ChangeLog +++ b/include/opcode/ChangeLog @@ -1,3 +1,8 @@ +2001-07-11 Frank Ch. Eigler + + * cgen.h (CGEN_MACH): Add insn_chunk_bitsize field. + (cgen_cpu_desc): Ditto. + 2001-07-07 Ben Elliston * m88k.h: Clean up and reformat. Remove unused code. diff --git a/include/opcode/cgen.h b/include/opcode/cgen.h index c13c4d9e8ae..c01b5c2a254 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 2953237b6c7..4adba8a416c 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,10 @@ +2001-07-11 Frank Ch. Eigler + + * 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 , Karsten Keil * 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 b2372fd56d7..2c4ce7feed9 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 188a157f3a1..9dfc16e9e51 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. -- 2.30.2