diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c gcc-4.1.2/gcc/config/arm/arm.c
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.c	2007-05-09 16:32:29.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.c	2007-05-15 09:39:41.000000000 +1000
@@ -4,6 +4,7 @@
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com).
+   Cirrus Crunch bugfixes by Vladimir Ivanov (vladit@nucleusys.com)
 
    This file is part of GCC.
 
@@ -131,9 +132,17 @@
 static bool arm_xscale_rtx_costs (rtx, int, int, int *);
 static bool arm_9e_rtx_costs (rtx, int, int, int *);
 static int arm_address_cost (rtx);
-static bool arm_memory_load_p (rtx);
+// static bool arm_memory_load_p (rtx);
 static bool arm_cirrus_insn_p (rtx);
-static void cirrus_reorg (rtx);
+// static void cirrus_reorg (rtx);
+static bool arm_mem_access_p (rtx);
+static bool cirrus_dest_regn_p (rtx, int);
+static rtx cirrus_prev_next_mach_insn (rtx, int *, int);
+static rtx cirrus_prev_mach_insn (rtx, int *);
+static rtx cirrus_next_mach_insn (rtx, int *);
+static void cirrus_reorg_branch (rtx);
+static void cirrus_reorg_bug1 (rtx);
+static void cirrus_reorg_bug10_12 (rtx);
 static void arm_init_builtins (void);
 static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void arm_init_iwmmxt_builtins (void);
@@ -5399,41 +5412,6 @@
               || TREE_CODE (valtype) == COMPLEX_TYPE));
 }
 
-/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
-   Use by the Cirrus Maverick code which has to workaround
-   a hardware bug triggered by such instructions.  */
-static bool
-arm_memory_load_p (rtx insn)
-{
-  rtx body, lhs, rhs;;
-
-  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
-    return false;
-
-  body = PATTERN (insn);
-
-  if (GET_CODE (body) != SET)
-    return false;
-
-  lhs = XEXP (body, 0);
-  rhs = XEXP (body, 1);
-
-  lhs = REG_OR_SUBREG_RTX (lhs);
-
-  /* If the destination is not a general purpose
-     register we do not have to worry.  */
-  if (GET_CODE (lhs) != REG
-      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
-    return false;
-
-  /* As well as loads from memory we also have to react
-     to loads of invalid constants which will be turned
-     into loads from the minipool.  */
-  return (GET_CODE (rhs) == MEM
-	  || GET_CODE (rhs) == SYMBOL_REF
-	  || note_invalid_constants (insn, -1, false));
-}
-
 /* Return TRUE if INSN is a Cirrus instruction.  */
 static bool
 arm_cirrus_insn_p (rtx insn)
@@ -5452,124 +5433,218 @@
   return attr != CIRRUS_NOT;
 }
 
-/* Cirrus reorg for invalid instruction combinations.  */
-static void
-cirrus_reorg (rtx first)
+/* Return TRUE if ISN does memory access.  */
+static bool
+arm_mem_access_p (rtx insn)
 {
-  enum attr_cirrus attr;
-  rtx body = PATTERN (first);
-  rtx t;
-  int nops;
+  enum attr_type attr;
 
-  /* Any branch must be followed by 2 non Cirrus instructions.  */
-  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
-    {
-      nops = 0;
-      t = next_nonnote_insn (first);
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!insn
+      || GET_CODE (insn) != INSN
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return 0;
 
-      if (arm_cirrus_insn_p (t))
-	++ nops;
+    attr = get_attr_type (insn);
 
-      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
-	++ nops;
+  return attr == TYPE_LOAD_BYTE
+   || attr == TYPE_LOAD1   || attr == TYPE_LOAD2    || attr == TYPE_LOAD3 || attr == TYPE_LOAD4
+   || attr == TYPE_F_CVT
+   || attr == TYPE_F_MEM_R || attr == TYPE_R_MEM_F  || attr == TYPE_F_2_R || attr == TYPE_R_2_F
+   || attr == TYPE_F_LOAD	|| attr == TYPE_F_LOADS  || attr == TYPE_F_LOADD
+   || attr == TYPE_F_STORE || attr == TYPE_F_STORES || attr == TYPE_F_STORED
+   || attr == TYPE_STORE1  || attr == TYPE_STORE2   || attr == TYPE_STORE3  || attr == TYPE_STORE4;
+
+}
 
-      while (nops --)
-	emit_insn_after (gen_nop (), first);
+/* Return TRUE if destination is certain Cirrus register.  */
+static bool
+cirrus_dest_regn_p (rtx body, int regn)
+{
+  rtx lhs;
+  int reg;
+  lhs = XEXP (body, 0);
+  if (GET_CODE (lhs) != REG)
+    return 0;
 
-      return;
-    }
+  reg = REGNO (lhs);
+  if (REGNO_REG_CLASS (reg) != CIRRUS_REGS)
+    return 0;
 
-  /* (float (blah)) is in parallel with a clobber.  */
-  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
-    body = XVECEXP (body, 0, 0);
+  return reg == regn;
+}
+
+/* Get previous/next machine instruction during Cirrus workaround scans.
+   Assume worst case (for the purpose of Cirrus workarounds)
+   for JUMP / CALL instructions.  */
+static rtx
+cirrus_prev_next_mach_insn (rtx insn, int *len, int next)
+{
+  rtx t;
+  int l = 0;
 
-  if (GET_CODE (body) == SET)
+  /* It seems that we can count only on INSN length.  */
+  for ( ; ; )
     {
-      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
+      if (next)
+    	insn = NEXT_INSN (insn);
+      else
+    	insn = PREV_INSN (insn);
+      if (!insn)
+    	break;
 
-      /* cfldrd, cfldr64, cfstrd, cfstr64 must
-	 be followed by a non Cirrus insn.  */
-      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
-	{
-	  if (arm_cirrus_insn_p (next_nonnote_insn (first)))
-	    emit_insn_after (gen_nop (), first);
+    if (GET_CODE (insn) == INSN)
+      {
+	    l = get_attr_length (insn) / 4;
+        if (l)
+	      break;
+      }
+    else if (GET_CODE (insn) == JUMP_INSN)
+      {
+        l = 1;
+        t = is_jump_table (insn);
+        if (t)
+          l += get_jump_table_size (t) / 4;
+        break;
+      }
+        else if (GET_CODE (insn) == CALL_INSN)
+      {
+        l = 1;
+        break;
+      }
+    }
 
-	  return;
-	}
-      else if (arm_memory_load_p (first))
-	{
-	  unsigned int arm_regno;
+  if (len)
+    *len = l;
 
-	  /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
-	     ldr/cfmv64hr combination where the Rd field is the same
-	     in both instructions must be split with a non Cirrus
-	     insn.  Example:
-
-	     ldr r0, blah
-	     nop
-	     cfmvsr mvf0, r0.  */
-
-	  /* Get Arm register number for ldr insn.  */
-	  if (GET_CODE (lhs) == REG)
-	    arm_regno = REGNO (lhs);
-	  else
-	    {
-	      gcc_assert (GET_CODE (rhs) == REG);
-	      arm_regno = REGNO (rhs);
-	    }
+  return insn;
+}
 
-	  /* Next insn.  */
-	  first = next_nonnote_insn (first);
+static rtx
+cirrus_prev_mach_insn (rtx insn, int *len)
+{
+  return cirrus_prev_next_mach_insn (insn, len, 0);
+}
 
-	  if (! arm_cirrus_insn_p (first))
-	    return;
+static rtx
+cirrus_next_mach_insn (rtx insn, int *len)
+{
+  return cirrus_prev_next_mach_insn (insn, len, 1);
+}
 
-	  body = PATTERN (first);
+/* Cirrus reorg for branch slots.  */
+static void
+cirrus_reorg_branch (rtx insn)
+{
+  rtx t;
+  int nops, l;
 
-          /* (float (blah)) is in parallel with a clobber.  */
-          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
-	    body = XVECEXP (body, 0, 0);
-
-	  if (GET_CODE (body) == FLOAT)
-	    body = XEXP (body, 0);
-
-	  if (get_attr_cirrus (first) == CIRRUS_MOVE
-	      && GET_CODE (XEXP (body, 1)) == REG
-	      && arm_regno == REGNO (XEXP (body, 1)))
-	    emit_insn_after (gen_nop (), first);
+  /* TODO: handle jump-tables.  */
+  t = is_jump_table (insn);
+  if (t)
+    return;
+
+  /* Any branch must be followed by 2 non Cirrus instructions.  */
+  t = insn;
+  for (nops = 2; nops > 0; )
+    {
+      if (!cirrus_next_mach_insn (t, 0))
+        {
+          insn = t;
+          break;
+        }
+      t = cirrus_next_mach_insn (t, &l);
+      if (arm_cirrus_insn_p (t))
+        break;
+      nops -= l;
 
-	  return;
-	}
     }
 
-  /* get_attr cannot accept USE or CLOBBER.  */
-  if (!first
-      || GET_CODE (first) != INSN
-      || GET_CODE (PATTERN (first)) == USE
-      || GET_CODE (PATTERN (first)) == CLOBBER)
-    return;
+  while (nops-- > 0)
+    emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+}
 
-  attr = get_attr_cirrus (first);
+/* Cirrus reorg for bug #1 (cirrus + cfcmpxx).  */
+static void
+cirrus_reorg_bug1 (rtx insn)
+{
+  rtx body = PATTERN (insn), body2;
+  rtx t;
+  int i, nops, l;
+  enum attr_cirrus attr;
 
-  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
-     must be followed by a non-coprocessor instruction.  */
-  if (attr == CIRRUS_COMPARE)
+  /* Check if destination or clobber is Cirrus register.  */
+  if (GET_CODE (body) == PARALLEL)
     {
-      nops = 0;
-
-      t = next_nonnote_insn (first);
+      for (i = 0; i < XVECLEN (body, 0); i++)
+	  {
+	  body2 = XVECEXP (body, 0, i);
+      if (GET_CODE (body2) == SET)
+        {
+          if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM))
+            {
+		       nops = 5;
+               goto fix;
+            }
+        }
+      else if (GET_CODE (body2) == CLOBBER)
+        {
+          if (cirrus_dest_regn_p (body2, LAST_CIRRUS_FP_REGNUM))
+		    {
+		      nops = 4;
+		      goto fix;
+            }
+        }
+      }
+    }
+  else if (GET_CODE (body) == SET)
+    {
+      if (cirrus_dest_regn_p (body, LAST_CIRRUS_FP_REGNUM))
+	  {
+	    nops = 5;
+        goto fix;
+	  }
+    }
+  return;
 
-      if (arm_cirrus_insn_p (t))
-	++ nops;
+fix:
+  t = insn;
+  for ( ; nops > 0; )
+    {
+      t = cirrus_next_mach_insn (t, &l);
+      if (!t)
+	break;
+      if (GET_CODE (t) == JUMP_INSN
+	  || GET_CODE (t) == CALL_INSN)
+	{
+	  nops -= l;
+	  break;
+	}
+      else if (arm_cirrus_insn_p (t))
+	{
+	  attr = get_attr_cirrus (t);
+	  if (attr == CIRRUS_COMPARE)
+	    break;
+	}
+      nops -= l;
+    }
 
-      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
-	++ nops;
+  while (nops-- > 0)
+    emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+}
 
-      while (nops --)
-	emit_insn_after (gen_nop (), first);
+/* Cirrus reorg for bugs #10 and #12 (data aborts).  */
+static void
+cirrus_reorg_bug10_12 (rtx insn)
+{
+  rtx t;
 
-      return;
-    }
+  t = cirrus_next_mach_insn (insn, 0);
+  if (arm_cirrus_insn_p (t))
+    if (TARGET_CIRRUS_D0 ||
+	get_attr_cirrus (t) == CIRRUS_DOUBLE)
+      emit_insn_after (gen_nop (), insn); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
 }
 
 /* Return TRUE if X references a SYMBOL_REF.  */
@@ -7727,7 +7796,7 @@
 {
   Mnode * mp;
   Mnode * nmp;
-  int align64 = 0;
+  int align64 = 0, stuffnop = 0;
 
   if (ARM_DOUBLEWORD_ALIGN)
     for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
@@ -7742,8 +7811,27 @@
 	     ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
 	     INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
 
+  /* Check if branch before minipool is already stuffed with nops.  */
+  if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1)
+    {
+      rtx t;
+
+      t = prev_active_insn (scan);
+      if (GET_CODE (t) != INSN
+	  || PATTERN (t) != const0_rtx)
+	  stuffnop = 1;
+    }
   scan = emit_label_after (gen_label_rtx (), scan);
   scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
+  /* Last instruction was branch, so put two non-Cirrus opcodes.  */
+  if (stuffnop)
+    {
+#if TARGET_CIRRUS /* This is doubling up on nops, so I don't think this is a good idea */
+      emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+      emit_insn_before (gen_nop (), scan); /* WARNING: this appears to cause "bad immediate value for offset" errors in the assembler */
+#endif
+    }
+
   scan = emit_label_after (minipool_vector_label, scan);
 
   for (mp = minipool_vector_head; mp != NULL; mp = nmp)
@@ -8151,15 +8239,38 @@
   gcc_assert (GET_CODE (insn) == NOTE);
   minipool_pad = 0;
 
+#if TARGET_CIRRUS /* I think this is a double-up */
+  /* Scan all the insn and fix Cirrus issues.  */
+  if (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1)
+    {
+      rtx t, s;
+
+      for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0))
+    if (arm_mem_access_p (t))
+      cirrus_reorg_bug10_12 (t);
+
+      if (TARGET_CIRRUS_D0)
+        for (t = cirrus_next_mach_insn (insn, 0); t; t = cirrus_next_mach_insn (t, 0))
+      if (arm_cirrus_insn_p (t))
+        cirrus_reorg_bug1 (t);
+
+      /* Find last insn.  */
+      for (t = insn; ; t = s)
+        {
+          s = cirrus_next_mach_insn (t, 0);
+          if (!s)
+            break;
+	    }
+      /* Scan backward and fix branches. - WARNING: appears to cause "bad immediate value for offset" problems! */
+      for ( ; t; t = cirrus_prev_mach_insn (t, 0))
+        if (GET_CODE (t) == JUMP_INSN
+        || GET_CODE (t) == CALL_INSN)
+          cirrus_reorg_branch (t);
+    }
+#endif
   /* Scan all the insns and record the operands that will need fixing.  */
   for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
     {
-      if (TARGET_CIRRUS_FIX_INVALID_INSNS
-          && (arm_cirrus_insn_p (insn)
-	      || GET_CODE (insn) == JUMP_INSN
-	      || arm_memory_load_p (insn)))
-	cirrus_reorg (insn);
-
       if (GET_CODE (insn) == BARRIER)
 	push_minipool_barrier (insn, address);
       else if (INSN_P (insn))
@@ -11755,16 +11910,10 @@
 		  || get_attr_conds (this_insn) != CONDS_NOCOND)
 		fail = TRUE;
 
-	      /* A conditional cirrus instruction must be followed by
-		 a non Cirrus instruction.  However, since we
-		 conditionalize instructions in this function and by
-		 the time we get here we can't add instructions
-		 (nops), because shorten_branches() has already been
-		 called, we will disable conditionalizing Cirrus
-		 instructions to be safe.  */
-	      if (GET_CODE (scanbody) != USE
-		  && GET_CODE (scanbody) != CLOBBER
-		  && get_attr_cirrus (this_insn) != CIRRUS_NOT)
+	      /* To avoid erratic behaviour, we avoid conditional Cirrus
+		 instructions when doing workarounds.  */
+	      if (arm_cirrus_insn_p(this_insn)
+    	  && (TARGET_CIRRUS_D0 || TARGET_CIRRUS_D1))
 		fail = TRUE;
 	      break;
 
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h gcc-4.1.2/gcc/config/arm/arm.h
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.h	2005-11-05 01:02:51.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.h	2007-05-15 10:15:05.000000000 +1000
@@ -5,6 +5,7 @@
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com)
    Minor hacks by Nick Clifton (nickc@cygnus.com)
+   Cirrus Crunch fixes by Vladimir Ivanov (vladitx@nucleusys.com)
 
    This file is part of GCC.
 
@@ -140,7 +141,9 @@
 %{msoft-float:%{mhard-float:						\
 	%e-msoft-float and -mhard_float may not be used together}}	\
 %{mbig-endian:%{mlittle-endian:						\
-	%e-mbig-endian and -mlittle-endian may not be used together}}"
+	%e-mbig-endian and -mlittle-endian may not be used together}}  \
+%{mfix-crunch-d0:%{mfix-crunch-d1:					\
+	%e-mfix-crunch-d0 and -mfix-crunch-d1 may not be used together}}"
 
 #ifndef CC1_SPEC
 #define CC1_SPEC ""
@@ -179,6 +182,9 @@
 #define TARGET_HARD_FLOAT_ABI		(arm_float_abi == ARM_FLOAT_ABI_HARD)
 #define TARGET_FPA			(arm_fp_model == ARM_FP_MODEL_FPA)
 #define TARGET_MAVERICK			(arm_fp_model == ARM_FP_MODEL_MAVERICK)
+#define TARGET_CIRRUS			(arm_arch_cirrus)
+#define TARGET_CIRRUS_D0		0 /* (target_flags & ARM_FLAG_CIRRUS_D0) */
+#define TARGET_CIRRUS_D1		1 /* (target_flags & ARM_FLAG_CIRRUS_D1) */
 #define TARGET_VFP			(arm_fp_model == ARM_FP_MODEL_VFP)
 #define TARGET_IWMMXT			(arm_arch_iwmmxt)
 #define TARGET_REALLY_IWMMXT		(TARGET_IWMMXT && TARGET_ARM)
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt gcc-4.1.2/gcc/config/arm/arm.opt
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/config/arm/arm.opt	2005-11-05 01:02:51.000000000 +1000
+++ gcc-4.1.2/gcc/config/arm/arm.opt	2007-05-15 10:09:31.000000000 +1000
@@ -68,6 +68,14 @@
 Target Report Mask(CIRRUS_FIX_INVALID_INSNS)
 Cirrus: Place NOPs to avoid invalid instruction combinations
 
+fix-crunch-d0
+Target Report Mask(ARM_FLAG_CIRRUS_D0)
+Cirrus: workarounds for Crunch coprocessor revision D0
+
+fix-crunch-d1
+Target Report Mask(ARM_FLAG_CIRRUS_D1)
+Cirrus: workarounds for Crunch coprocessor revision D1
+
 mcpu=
 Target RejectNegative Joined
 Specify the name of the target CPU
diff -ruN /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi gcc-4.1.2/gcc/doc/invoke.texi
--- /home/hwilliams/openembedded/build/tmp/work/ep9312-angstrom-linux-gnueabi/gcc-cross-4.1.2-r0/gcc-4.1.2/gcc/doc/invoke.texi	2006-09-26 07:21:58.000000000 +1000
+++ gcc-4.1.2/gcc/doc/invoke.texi	2007-05-15 10:07:04.000000000 +1000
@@ -408,7 +408,7 @@
 -msingle-pic-base  -mno-single-pic-base @gol
 -mpic-register=@var{reg} @gol
 -mnop-fun-dllimport @gol
--mcirrus-fix-invalid-insns -mno-cirrus-fix-invalid-insns @gol
+-mfix-crunch-d0 -mfix-crunch-d1 @gol
 -mpoke-function-name @gol
 -mthumb  -marm @gol
 -mtpcs-frame  -mtpcs-leaf-frame @gol
@@ -7435,17 +7435,12 @@
 Specify the register to be used for PIC addressing.  The default is R10
 unless stack-checking is enabled, when R9 is used.
 
-@item -mcirrus-fix-invalid-insns
-@opindex mcirrus-fix-invalid-insns
-@opindex mno-cirrus-fix-invalid-insns
-Insert NOPs into the instruction stream to in order to work around
-problems with invalid Maverick instruction combinations.  This option
-is only valid if the @option{-mcpu=ep9312} option has been used to
-enable generation of instructions for the Cirrus Maverick floating
-point co-processor.  This option is not enabled by default, since the
-problem is only present in older Maverick implementations.  The default
-can be re-enabled by use of the @option{-mno-cirrus-fix-invalid-insns}
-switch.
+@item -mfix-crunch-d0
+@itemx -mfix-crunch-d1
+@opindex mfix-crunch-d0
+@opindex mfix-crunch-d1
+Enable workarounds for the Cirrus MaverickCrunch coprocessor revisions
+D0 and D1 respectively.
 
 @item -mpoke-function-name
 @opindex mpoke-function-name
