This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

cgen/gas: some support for funny-endian instruction sets


Hi -

The patch below gives an interpretation to the hitherto-unused
cgen "word-bitsize" CPU parameter.  It is interpreted to mean
the chunking size for endianness conversions when processing
long instructions.  When this parameter is set smaller than
"base-insn-size" or happens to be smaller than the length of an
instruction, then the instruction bytes are chunked into
"word-bitsize" units, and individually endianness-converted.

For example:  word-bitsize=16, base-insn-size=32
insn-word=0x76543210 -EB=>0x76 0x54 0x32 0x10 -EL=>0x54 0x76 0x10 0x32
insn-word=0x3210     -EB=>0x32 0x10           -EL=>0x10 0x32

The support for this is incomplete.  Among the missing:
* simulator support (insn fetch/decode)
* non-INT_INSN_P target support
but it's a first step.

The patch is not intended to affect existing ports; I tested a bunch
of them both with and without opcodes/ regeneration.

In the absence of objections, I plan to commit this shortly.

- FChE


[cgen/ChangeLog]
2001-07-09  Frank Ch. Eigler  <fche@redhat.com>

	* desc-cpu.scm (-gen-mach-table-defns): Emit fourth field: the
	mach->cpu word-bitsize.
	(-gen-cpu-open): In @arch@_cgen_rebuild_tables, process above new
	field toward CGEN_CPU_TABLE->word_bitsize.

[opcodes/ChangeLog]
Index: ChangeLog
2001-07-09  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->word_bitsize.

[include/opcodes/ChangeLog]
2001-07-09  Frank Ch. Eigler  <fche@redhat.com>

	* cgen.h (CGEN_MACH): Add word_bitsize field at end.



Index: cgen/desc-cpu.scm
===================================================================
--- cgen/desc-cpu.scm	2001/03/20 18:20:06	1.27
+++ cgen/desc-cpu.scm	2001/07/09 14:39:35
@@ -70,11 +70,12 @@
 		       (string-append "  { "
 				      "\"" (obj:name mach) "\", "
 				      "\"" (mach-bfd-name mach) "\", "
-				      (mach-enum mach)
+				      (mach-enum mach) ", "
+				      (number->string (cpu-word-bitsize (mach-cpu mach)))
 				      " },\n")))
 		    (current-mach-list))
    "\
-  { 0, 0, 0 }
+  { 0, 0, 0, 0 }
 };
 \n"
    )
@@ -635,11 +636,9 @@
 @arch@_cgen_rebuild_tables (cd)
      CGEN_CPU_TABLE *cd;
 {
-  int i,n_isas;
+  int i;
   unsigned int isas = cd->isas;
-#if 0
   unsigned int machs = cd->machs;
-#endif
 
   cd->int_insn_p = CGEN_INT_INSN_P;
 
@@ -677,20 +676,26 @@
 	  cd->min_insn_bitsize = isa->min_insn_bitsize;
 	if (isa->max_insn_bitsize > cd->max_insn_bitsize)
 	  cd->max_insn_bitsize = isa->max_insn_bitsize;
-
-	++n_isas;
       }
 
-#if 0 /* Does nothing?? */
   /* Data derived from the mach spec.  */
   for (i = 0; i < MAX_MACHS; ++i)
     if (((1 << i) & machs) != 0)
       {
 	const CGEN_MACH *mach = & @arch@_cgen_mach_table[i];
+
+	if (mach->word_bitsize != 0)
+	{
+	  if (cd->word_bitsize != 0 && cd->word_bitsize != mach->word_bitsize)
+	    {
+	      fprintf (stderr, \"@arch@_cgen_rebuild_tables: conflicting word-bitsize values: `%d' vs. `%d'\\n\",
+		       cd->word_bitsize, mach->word_bitsize);
+	      abort ();
+	    }
 
-	++n_machs;
+ 	  cd->word_bitsize = mach->word_bitsize;
+	}
       }
-#endif
 
   /* Determine which hw elements are used by MACH.  */
   build_hw_table (cd);



Index: cgen-dis.in
===================================================================
RCS file: /cvs/cvsfiles/devo/opcodes/cgen-dis.in,v
retrieving revision 1.37
diff -u -2 -0 -r1.37 cgen-dis.in
--- cgen-dis.in	2001/05/15 18:08:19	1.37
+++ cgen-dis.in	2001/07/09 14:42:39
@@ -212,46 +212,46 @@
   ex_info->insn_bytes = buf;
 
   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
   return 0;
 }
 
 /* Utility to print an insn.
    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
    The result is the size of the insn in bytes or zero for an unknown insn
    or -1 if an error occurs fetching data (memory_error_func will have
    been called).  */
 
 static int
 print_insn (cd, pc, info, buf, buflen)
      CGEN_CPU_DESC cd;
      bfd_vma pc;
      disassemble_info *info;
      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
      modified a la m32r).  */
   ex_info.valid = (1 << buflen) - 1;
   ex_info.dis_info = info;
   ex_info.insn_bytes = buf;
 
   /* The instructions are stored in hash lists.
      Pick the first one and keep trying until we find the right one.  */
 
   insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
   while (insn_list != NULL)
     {
       const CGEN_INSN *insn = insn_list->insn;
       CGEN_FIELDS fields;
       int length;
       unsigned long insn_value_cropped;
 
 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
Index: cgen-opc.c
===================================================================
RCS file: /cvs/cvsfiles/devo/opcodes/cgen-opc.c,v
retrieving revision 1.29
diff -u -2 -0 -r1.29 cgen-opc.c
--- cgen-opc.c	2001/06/29 00:10:04	1.29
+++ cgen-opc.c	2001/07/09 14:42:39
@@ -374,54 +374,105 @@
 cgen_macro_insn_count (cd)
      CGEN_CPU_DESC cd;
 {
   int count = cd->macro_insn_table.num_init_entries;
   CGEN_INSN_LIST *rt_insns = cd->macro_insn_table.new_entries;
 
   for ( ; rt_insns != NULL; rt_insns = rt_insns->next)
     ++count;
 
   return count;
 }
 
 /* Cover function to read and properly byteswap an insn value.  */
 
 CGEN_INSN_INT
 cgen_get_insn_value (cd, buf, length)
      CGEN_CPU_DESC cd;
      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 word_bitsize = cd->word_bitsize;
+  CGEN_INSN_INT value = 0;
+
+  if (word_bitsize != 0 && word_bitsize < length)
+    {
+      /* We need to divide up the incoming value into word_bitsize-length
+	 segments, and endian-convert them, one at a time. */
+      int i;
+
+      /* Enforce divisibility. */ 
+      if ((length % word_bitsize) != 0)
+	abort ();
+
+      for (i = 0; i < length; i += word_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], word_bitsize, big_p);
+	  value = (value << word_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.  */
 
 void
 cgen_put_insn_value (cd, buf, length, value)
      CGEN_CPU_DESC cd;
      unsigned char *buf;
      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 word_bitsize = cd->word_bitsize;
+
+  if (word_bitsize != 0 && word_bitsize < length)
+    {
+      /* We need to divide up the incoming value into word_bitsize-length
+	 segments, and endian-convert them, one at a time. */
+      int i;
+
+      /* Enforce divisibility. */ 
+      if ((length % word_bitsize) != 0)
+	abort ();
+
+      for (i = 0; i < length; i += word_bitsize) /* NB: i == bits */
+	{
+	  int index;
+	  index = (length - word_bitsize - i); /* NB: not dependent on endianness! */
+	  bfd_put_bits ((bfd_vma) value, & buf[index / 8], word_bitsize, big_p);
+	  value >>= word_bitsize;
+	}
+    }
+  else
+    {
+      bfd_put_bits ((bfd_vma) value, buf, length, big_p);
+    }
 }
 
 /* Look up instruction INSN_*_VALUE and extract its fields.
    INSN_INT_VALUE is used if CGEN_INT_INSN_P.
    Otherwise INSN_BYTES_VALUE is used.
    INSN, if non-null, is the insn table entry.
    Otherwise INSN_*_VALUE is examined to compute it.
    LENGTH is the bit length of INSN_*_VALUE if known, otherwise 0.
    0 is only valid if `insn == NULL && ! CGEN_INT_INSN_P'.
    If INSN != NULL, LENGTH must be valid.
    ALIAS_P is non-zero if alias insns are to be included in the search.
 
    The result is a pointer to the insn table entry, or NULL if the instruction
    wasn't recognized.  */
 
 /* ??? Will need to be revisited for VLIW architectures.  */
 
 const CGEN_INSN *
 cgen_lookup_insn (cd, insn, insn_int_value, insn_bytes_value, length, fields,
 		  alias_p)




Index: cgen.h
===================================================================
RCS file: /cvs/cvsfiles/devo/include/opcode/cgen.h,v
retrieving revision 1.59
diff -u -5 -r1.59 cgen.h
--- cgen.h	2001/06/16 15:22:00	1.59
+++ cgen.h	2001/07/09 14:42:53
@@ -197,10 +197,12 @@
   const char *name;
   /* The argument to bfd_arch_info->scan.  */
   const char *bfd_name;
   /* one of enum mach_attr */
   int num;
+  /* parameter from mach->cpu */
+  unsigned int word_bitsize;
 } CGEN_MACH;
 
 /* Parse result (also extraction result).
 
    The result of parsing an insn is stored here.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]