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]
Other format: [Raw text]

Committed: CRISv32 port, part 1: include, opcodes, bfd, gas and ld; except testsuite.


(Part of the CRIS port.)  There's a small binary- and
source-compatible instruction subset expected to be usable for
bootcode-like situations.  Nope, no ISO C90 changes yet.

There's a new badness warning (one among many for as.dvi, but
the only one in c-cris.texi) for "Underfull \hbox (badness 5036)
in paragraph at lines 386--388" when generating the gas dvi
which comes from the new docs.  I inspected the result and it
doesn't look any bad to me, so no action taken.

include/elf:
	* cris.h (EF_CRIS_VARIANT_MASK, EF_CRIS_VARIANT_ANY_V0_V10)
	(EF_CRIS_VARIANT_V32, EF_CRIS_VARIANT_COMMON_V10_V32): New
	macros.

include/opcode:
	* cris.h (enum cris_insn_version_usage): Tweak formatting and
	comments.  Remove member cris_ver_sim.  Add members
	cris_ver_sim_v0_10, cris_ver_v0_10, cris_ver_v3_10,
	cris_ver_v8_10, cris_ver_v10, cris_ver_v10p.
	(struct cris_support_reg, struct cris_cond15): New types.
	(cris_conds15): Declare.
	(JUMP_PC_INCR_OPCODE_V32, BA_DWORD_OPCODE, NOP_OPCODE_COMMON)
	(NOP_OPCODE_ZBITS_COMMON, LAPC_DWORD_OPCODE, LAPC_DWORD_Z_BITS)
	(NOP_OPCODE_V32, NOP_Z_BITS_V32): New macros.
	(NOP_Z_BITS): Define in terms of NOP_OPCODE.
	(cris_imm_oprnd_size_type): New members SIZE_FIELD_SIGNED and
	SIZE_FIELD_UNSIGNED.

gas:
	* configure.in (crisv32): Recognize.  AC_DEFINE_UNQUOTED
	DEFAULT_CRIS_ARCH.  Handle crisv32-*-linux-gnu* like
	cris-*-linux-gnu* and crisv32-*-* like cris-*-*.
	* configure: Regenerate.
	* config/tc-cris.c (enum cris_archs): New.
	(cris_mach, cris_arch_from_string, s_cris_arch, get_sup_reg)
	(cris_insn_ver_valid_for_arch): New functions.
	(DEFAULT_CRIS_ARCH): New macro, default to cris_any_v0_v10.
	(cris_arch): New variable.
	(md_pseudo_table): New pseudo .arch.
	(err_for_dangerous_mul_placement): Initialize according to
	DEFAULT_CRIS_ARCH.
	(STATE_COND_BRANCH): Renamed from STATE_CONDITIONAL_BRANCH.
	All users changed.
	(STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON)
	(STATE_ABS_BRANCH_V32, STATE_LAPC, BRANCH_BF_V32, BRANCH_BB_V32)
	(BRANCH_WF_V32, BRANCH_WB_V32): New.
	(BRANCH_BF, BRANCH_BB, BRANCH_WF, BRANCH_WB): Don't undef after
	use in md_cris_relax_table.
	(md_cris_relax_table): Add entries for STATE_COND_BRANCH_V32,
	STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC.
	Update and improve head comment.
	(OPTION_PIC): Define in terms of previous option, OPTION_US.
	(OPTION_MULBUG_ABORT_ON, OPTION_MULBUG_ABORT_OFF): Similar.
	(OPTION_ARCH): New.
	(md_longopts): New option --march=...
	(cris_any_v0_v10_long_jump_size, crisv32_long_jump_size): New
	macros.
	(md_long_jump_size): Initialize in terms of DEFAULT_CRIS_ARCH.
	(HANDLE_RELAXABLE): New macro.
	(md_estimate_size_before_relax): Use HANDLE_RELAXABLE for common
	cases.  Check for weak symbols and assume not relaxable.  Handle
	STATE_COND_BRANCH_V32, STATE_COND_BRANCH_COMMON,
	STATE_ABS_BRANCH_V32, STATE_LAPC.  Use new variable symbolP, not
	fragP->fr_symbol.
	(md_convert_frag): Handle STATE_COND_BRANCH_V32,
	STATE_COND_BRANCH_COMMON, STATE_ABS_BRANCH_V32, STATE_LAPC.
	(cris_relax_frag): Handle new states.
	(cris_create_short_jump): Adjust for CRISv32.
	(md_create_long_jump): Ditto.  Emit error for common_v10_v32.
	(md_begin): Define symbols "..asm.arch.cris.v32",
	"..asm.arch.cris.v10", "..asm.arch.cris.common_v10_v32" and
	"..asm.arch.cris.any_v0_v10".  Use cris_insn_ver_valid_for_arch
	when entering opcode table entry points.
	(md_assemble): Adjust branch handling for CRISv32.  Handle LAPC
	relaxation.  In fix_new_exp call for main insn, pass 1 for pcrel
	parameter for 8, 16 and 32-bit pc-relative insns and LAPC.
	(cris_process_instruction): Initialize out_insnp->insn_type to
	CRIS_INSN_NONE, not CRIS_INSN_NORMAL.
	<case ']', '[', 'A', 'd', 'Q', 'N', 'n', 'Y', 'U', 'u', 'T'>: New
	cases.
	<case 'm'>: Check that modified_char == '.'.
	<invalid operands>: Consume the rest of the line.
	When operands don't match, skip over subsequent insns with
	non-matching version specifier but same mnemonic.
	<immediate constant, case SIZE_SPEC_REG>: Immediate operands for
	special registers in CRISv32 are always 32 bit long.
	<immediate constant, case SIZE_FIELD_SIGNED, SIZE_FIELD_UNSIGNED>:
	New cases.
	(get_gen_reg): Only recognize "PC" when followed by "+]" for v32
	and compatible.  Recognize "ACR" for v32, unless followed by "+".
	(get_spec_reg): Consider cris_arch when looking up register.
	(get_autoinc_prefix_or_indir_op): Don't recognize assignment for
	v32 or compatible.
	(get_3op_or_dip_prefix_op): Check for ']' after seeing '[rN+'.
	(cris_get_expression): Restore input_line_pointer if failing "early".
	(get_flags): Consider cris_arch and recognize flags accordingly.
	(branch_disp): Adjust for CRISv32.
	(gen_cond_branch_32): Similar.  Emit error for common_v10_v32.
	(cris_number_to_imm): Use as_bad_where, not as_bad.  Remove
	related FIXME.  Don't insist on BFD_RELOC_32_PCREL fixup to be
	resolved.  Don't enter zeros in object file for
	BFD_RELOC_32_PCREL.
	<case BFD_RELOC_CRIS_LAPCQ_OFFSET, BFD_RELOC_CRIS_SIGNED_16>
	<case BFD_RELOC_CRIS_SIGNED_8>: New case.
	(md_parse_option): Break out "return 1".
	<OPTION_ARCH> New case.
	(tc_gen_reloc): <case BFD_RELOC_CRIS_LAPCQ_OFFSET>
	<case BFD_RELOC_CRIS_SIGNED_16, BFD_RELOC_CRIS_SIGNED_8>
	<case BFD_RELOC_CRIS_UNSIGNED_8, BFD_RELOC_CRIS_UNSIGNED_16>
	<case BFD_RELOC_32_PCREL>: New cases.
	Addends for non-zero fx_pcrel are too in fx_offset.
	(md_show_usage): Show --march=<arch>.
	(md_apply_fix3): Adjust val for BFD_RELOC_CRIS_LAPCQ_OFFSET.
	(md_pcrel_from): BFD_RELOC_CRIS_LAPCQ_OFFSET is PC-relative too.
	(s_syntax) <struct syntaxes>: Properly constify member operand.
	* config/tc-cris.h (TARGET_MACH): Define.
	(cris_mach): Declare.
	* doc/as.texinfo (Overview) <CRIS>: Add --march=...
	* doc/c-cris.texi (CRIS-Symbols): New node for built-in symbols.
	(CRIS-Opts): Document --march=...
	(CRIS-Pseudos): Document .arch.

opcodes:
	Generally, handle CRISv32.
	* cris-dis.c (TRACE_CASE): Define as (disdata->trace_case).
	(struct cris_disasm_data): New type.
	(format_reg, format_hex, cris_constraint, print_flags)
	(get_opcode_entry): Add struct cris_disasm_data * parameter.  All
	callers changed.
	(format_sup_reg, print_insn_crisv32_with_register_prefix)
	(print_insn_crisv32_without_register_prefix)
	(print_insn_crisv10_v32_with_register_prefix)
	(print_insn_crisv10_v32_without_register_prefix)
	(cris_parse_disassembler_options): New functions.
	(bytes_to_skip, cris_spec_reg): Add enum cris_disass_family
	parameter.  All callers changed.
	(get_opcode_entry): Call malloc, not xmalloc.  Return NULL on
	failure.
	(cris_constraint) <case 'Y', 'U'>: New cases.
	(bytes_to_skip): Handle 'Y' and 'N' as 's'.  Skip size is 4 bytes
	for constraint 'n'.
	(print_with_operands) <case 'Y'>: New case.
	(print_with_operands) <case 'T', 'A', '[', ']', 'd', 'n', 'u'>
	<case 'N', 'Y', 'Q'>: New cases.
	(print_insn_cris_generic): Emit "bcc ." for zero and CRISv32.
	(print_insn_cris_with_register_prefix)
	(print_insn_cris_without_register_prefix): Call
	cris_parse_disassembler_options.
	* cris-opc.c (cris_spec_regs): Mention that this table isn't used
	for CRISv32 and the size of immediate operands.  New v32-only
	entries for bz, pid, srs, wz, exs, eda, dz, ebp, erp, nrp, ccs and
	spc.  Add v32-only 4-byte entries for p2, p3, p5 and p6.  Change
	ccr, ibr, irp to be v0..v10.  Change bar, dccr to be v8..v10.
	Change brp to be v3..v10.
	(cris_support_regs): New vector.
	(cris_opcodes): Update head comment.  New format characters '[',
	']', space, 'A', 'd', 'N', 'n', 'Q', 'T', 'u', 'U', 'Y'.
	Add new opcodes for v32 and adjust existing opcodes to accommodate
	differences to earlier variants.
	(cris_cond15s): New vector.

bfd:
	* config.bfd: Support crisv32-*-* like cris-*-*.
	* archures.c (bfd_mach_cris_v0_v10, bfd_mach_cris_v32)
	(bfd_mach_cris_v10_v32): New macros.
	* cpu-cris.c: Tweak formatting.
	(get_compatible): New function.
	(N): New macro.
	(bfd_cris_arch_compat_v10_v32, bfd_cris_arch_v32): New
	bfd_arch_info_type:s.
	(bfd_cris_arch): Use bfd_mach_cris_v0_v10 for member mach,
	get_compatible for member compatible and link bfd_cris_arch_v32 as
	next.
	* elf32-cris.c (cris_elf_pcrel_reloc)
	(cris_elf_set_mach_from_flags): New functions.
	(cris_elf_howto_table) <R_CRIS_8_PCREL, R_CRIS_16_PCREL>
	<R_CRIS_32_PCREL>: Use cris_elf_pcrel_reloc.
	(cris_elf_grok_prstatus, cris_elf_grok_psinfo): Give correct
	numbers for bfd_mach_cris_v32.
	(PLT_ENTRY_SIZE_V32): New macro.
	(elf_cris_plt0_entry): Drop last comma in initializer.
	(elf_cris_plt0_entry_v32, elf_cris_plt_entry_v32)
	(elf_cris_pic_plt0_entry_v32, elf_cris_pic_plt_entry_v32): New
	PLT initializers.
	(cris_elf_relocate_section): Change all "%B(%A)" messages to
	"%B, section %A".
	(elf_cris_finish_dynamic_symbol): Do V32-specific PLT entries.
	(elf_cris_finish_dynamic_sections): Similar.
	(elf_cris_adjust_dynamic_symbol): Similar.
	(cris_elf_check_relocs): Change all "%B(%A)" messages to "%B,
	section %A".
	<switch with PIC relocs>: Emit error and return FALSE for
	bfd_mach_cris_v10_v32.
	<case R_CRIS_8_PCREL, case R_CRIS_16_PCREL, case R_CRIS_32_PCREL>:
	Emit warning when generating textrel reloc.
	(cris_elf_object_p): Call cris_elf_set_mach_from_flags.
	(cris_elf_final_write_processing): Set flags according to mach.
	(cris_elf_print_private_bfd_data): Display
	EF_CRIS_VARIANT_COMMON_V10_V32 and EF_CRIS_VARIANT_V32.
	(cris_elf_merge_private_bfd_data): Drop variables old_flags,
	new_flags.  Don't call cris_elf_final_write_processing.  Don't
	look at the actual elf header flags at all; use
	bfd_get_symbol_leading_char to check ibfd, obfd.  Trap difference
	in bfd_get_mach for ibfd and obfd and handle merging of compatible
	objects.
	(bfd_elf32_bfd_copy_private_bfd_data): Define.
	* reloc.c (BFD_RELOC_CRIS_SIGNED_8, BFD_RELOC_CRIS_UNSIGNED_8)
	(BFD_RELOC_CRIS_SIGNED_16, BFD_RELOC_CRIS_UNSIGNED_16)
	(BFD_RELOC_CRIS_LAPCQ_OFFSET): New relocs.
	* bfd-in2.h, libbfd.h: Regenerate.

ld:
	* configure.tgt (crisv32-*-*): Handle like cris-*-* for non-aout.
	* emulparams/criself.sh (INIT_START): Remove emitted "push srp".
	(FINI_START): Ditto.
	(INIT_END): Remove emitted "jump [sp+]".
	(FINI_END): Ditto.

Index: gas/configure.in
===================================================================
RCS file: /cvs/src/src/gas/configure.in,v
retrieving revision 1.161
diff -p -c -u -p -r1.161 configure.in
--- gas/configure.in	3 Sep 2004 17:15:40 -0000	1.161
+++ gas/configure.in	4 Nov 2004 13:33:45 -0000
@@ -129,6 +129,10 @@ changequote([,])dnl
       arm*b|xscale*b|strongarm*b) cpu_type=arm endian=big ;;
       arm*|xscale*|strongarm*)    cpu_type=arm endian=little ;;
       c4x*)		cpu_type=tic4x ;;
+      crisv32)		cpu_type=cris arch=crisv32
+			AC_DEFINE_UNQUOTED(DEFAULT_CRIS_ARCH, $arch,
+					   [Default CRIS architecture.])
+			;;
       crx*)		cpu_type=crx endian=little ;;
       hppa*)		cpu_type=hppa ;;
 changequote(,)dnl
@@ -224,8 +228,9 @@ changequote([,])dnl
 
       avr-*-*)				fmt=elf ;;
 
-      cris-*-linux-gnu*)		fmt=multi bfd_gas=yes em=linux ;;
-      cris-*-*)				fmt=multi bfd_gas=yes ;;
+      cris-*-linux-gnu* | crisv32-*-linux-gnu*)
+					fmt=multi bfd_gas=yes em=linux ;;
+      cris-*-* | crisv32-*-*)		fmt=multi bfd_gas=yes ;;
 
       crx-*-elf*)	    		fmt=elf ;;
 
Index: gas/config/tc-cris.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-cris.c,v
retrieving revision 1.30
diff -p -c -u -p -r1.30 tc-cris.c
--- gas/config/tc-cris.c	3 Nov 2004 01:54:24 -0000	1.30
+++ gas/config/tc-cris.c	4 Nov 2004 13:33:48 -0000
@@ -113,6 +113,17 @@ struct cris_instruction
   int imm_oprnd_size;
 };
 
+enum cris_archs
+{
+  arch_cris_unknown,
+  arch_crisv0, arch_crisv3, arch_crisv8, arch_crisv10,
+  arch_cris_any_v0_v10, arch_crisv32, arch_cris_common_v10_v32
+};
+
+static enum cris_archs cris_arch_from_string PARAMS ((char **));
+static int cris_insn_ver_valid_for_arch PARAMS ((enum cris_insn_version_usage,
+						 enum cris_archs));
+
 static void cris_process_instruction PARAMS ((char *,
 					      struct cris_instruction *,
 					      struct cris_prefix *));
@@ -121,6 +132,7 @@ static int get_bw_size_modifier PARAMS (
 static int get_gen_reg PARAMS ((char **, int *));
 static int get_spec_reg PARAMS ((char **,
 				 const struct cris_spec_reg **));
+static int get_sup_reg PARAMS ((char **, int *));
 static int get_autoinc_prefix_or_indir_op PARAMS ((char **,
 						   struct cris_prefix *,
 						   int *, int *, int *,
@@ -139,6 +151,7 @@ static void cris_create_short_jump PARAM
 static void s_syntax PARAMS ((int));
 static void s_cris_file PARAMS ((int));
 static void s_cris_loc PARAMS ((int));
+static void s_cris_arch PARAMS ((int));
 
 /* Get ":GOT", ":GOTOFF", ":PLT" etc. suffixes.  */
 static void cris_get_pic_suffix PARAMS ((char **,
@@ -176,12 +189,22 @@ static bfd_boolean symbols_have_leading_
 /* Whether or not we allow PIC, and expand to PIC-friendly constructs.  */
 static bfd_boolean pic = FALSE;
 
+/* If we're configured for "cris", default to allow all v0..v10
+   instructions and register names.  */
+#ifndef DEFAULT_CRIS_ARCH
+#define DEFAULT_CRIS_ARCH cris_any_v0_v10
+#endif
+
+/* No whitespace in the CONCAT2 parameter list.  */
+static enum cris_archs cris_arch = XCONCAT2 (arch_,DEFAULT_CRIS_ARCH);
+
 const pseudo_typeS md_pseudo_table[] =
 {
   {"dword", cons, 4},
   {"syntax", s_syntax, 0},
   {"file", s_cris_file, 0},
   {"loc", s_cris_loc, 0},
+  {"arch", s_cris_arch, 0},
   {NULL, 0, 0}
 };
 
@@ -189,7 +212,8 @@ static int warn_for_branch_expansion = 0
 
 /* Whether to emit error when a MULS/MULU could be located last on a
    cache-line.  */
-static int err_for_dangerous_mul_placement = 1;
+static int err_for_dangerous_mul_placement
+ = (XCONCAT2 (arch_,DEFAULT_CRIS_ARCH) != arch_crisv32);
 
 const char cris_comment_chars[] = ";";
 
@@ -214,12 +238,11 @@ const char FLT_CHARS[] = "";
       ---/ /--+-----------------+-----------------+-----------------+
 
    The "how long" bits are 00 = byte, 01 = word, 10 = dword (long).
-   This is a Un*x convention.
    Not all lengths are legit for a given value of (what state).
 
    Groups for CRIS address relaxing:
 
-   1. Bcc
+   1. Bcc (pre-V32)
       length: byte, word, 10-byte expansion
 
    2. BDAP
@@ -228,11 +251,28 @@ const char FLT_CHARS[] = "";
    3. MULS/MULU
       Not really a relaxation (no infrastructure to get delay-slots
       right), just an alignment and placement checker for the v10
-      multiply/cache-bug.  */
+      multiply/cache-bug.
+
+   4. Bcc (V32 and later)
+      length: byte, word, 14-byte expansion
+
+   5. Bcc (V10+V32)
+      length: byte, word, error
+
+   6. BA (V32)
+      length: byte, word, dword
 
-#define STATE_CONDITIONAL_BRANCH    (1)
+   7. LAPC (V32)
+      length: byte, dword
+  */
+
+#define STATE_COND_BRANCH           (1)
 #define STATE_BASE_PLUS_DISP_PREFIX (2)
 #define STATE_MUL		    (3)
+#define STATE_COND_BRANCH_V32       (4)
+#define STATE_COND_BRANCH_COMMON    (5)
+#define STATE_ABS_BRANCH_V32	    (6)
+#define STATE_LAPC		    (7)
 
 #define STATE_LENGTH_MASK	    (3)
 #define STATE_BYTE		    (0)
@@ -248,8 +288,12 @@ const char FLT_CHARS[] = "";
 
 #define BRANCH_BF ( 254)
 #define BRANCH_BB (-256)
+#define BRANCH_BF_V32 ( 252)
+#define BRANCH_BB_V32 (-258)
 #define BRANCH_WF (2 +  32767)
 #define BRANCH_WB (2 + -32768)
+#define BRANCH_WF_V32 (-2 + 32767)
+#define BRANCH_WB_V32 (-2 + -32768)
 
 #define BDAP_BF	  ( 127)
 #define BDAP_BB	  (-128)
@@ -295,39 +339,90 @@ const relax_typeS md_cris_relax_table[] 
   {0,	      0,	 4,  0},
 
   /* Unused (2, 3).  */
-  {0,	      0,	 0,  0},
+  {1,	      1,	 0,  0},
 
   /* MULS/MULU (3, 0).  Positions (3, 1..3) are unused.  */
-  {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}
+  {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
+
+  /* V32: Bcc o (4, 0).  */
+  {BRANCH_BF_V32, BRANCH_BB_V32, 0,  ENCODE_RELAX (4, 1)},
+
+  /* V32: Bcc [PC+] (4, 1).  */
+  {BRANCH_WF_V32, BRANCH_WB_V32, 2,  ENCODE_RELAX (4, 2)},
+
+  /* V32: BA .+12; NOP; BA32 target; NOP; Bcc .-6  (4, 2).  */
+  {0,	      0,	 12, 0},
+
+  /* Unused (4, 3).  */
+  {1,	      1,	 0,  0},
+
+  /* COMMON: Bcc o (5, 0).  The offsets are calculated as for v32.  Code
+     should contain two nop insns (or four if offset size is large or
+     unknown) after every label.  */
+  {BRANCH_BF_V32, BRANCH_BB_V32, 0,  ENCODE_RELAX (5, 1)},
+
+  /* COMMON: Bcc [PC+] (5, 1).  */
+  {BRANCH_WF_V32, BRANCH_WB_V32, 2,  ENCODE_RELAX (5, 2)},
+
+  /* COMMON: FIXME: ???.  Treat as error currently.  */
+  {0,	      0,	 12, 0},
+
+  /* Unused (5, 3).  */
+  {1,	      1,	 0,  0},
+
+  /* V32: BA o (6, 0).  */
+  {BRANCH_BF_V32, BRANCH_BB_V32, 0,  ENCODE_RELAX (6, 1)},
+
+  /* V32: BA.W (6, 1).  */
+  {BRANCH_WF_V32, BRANCH_WB_V32, 2,  ENCODE_RELAX (6, 2)},
+
+  /* V32: BA.D (6, 2).  */
+  {0,	      0,	 4, 0},
+
+  /* Unused (6, 3).  */
+  {1,	      1,	 0,  0},
+
+  /* LAPC: LAPCQ .+0..15*2,Rn  (7, 0).  */
+  {14*2,   -1*2,	 0,  ENCODE_RELAX (7, 2)},
+
+  /* Unused (7, 1).
+     While there's a shorter sequence, e.g. LAPCQ + an ADDQ or SUBQ,
+     that would affect flags, so we can't do that as it wouldn't be a
+     proper insn expansion of LAPCQ.  This row is associated with a
+     2-byte expansion, so it's unused rather than the next.  */
+  {1,	      1,	 0,  0},
+
+  /* LAPC: LAPC.D (7, 2).  */
+  {0,	      0,	 4, 0},
+
+  /* Unused (7, 3).  */
+  {1,	      1,	 0,  0}
 };
 
-#undef BRANCH_BF
-#undef BRANCH_BB
-#undef BRANCH_WF
-#undef BRANCH_WB
 #undef BDAP_BF
 #undef BDAP_BB
 #undef BDAP_WF
 #undef BDAP_WB
 
-/* Target-specific multicharacter options, not const-declared at usage
-   in 2.9.1 and CVS of 2000-02-16.  */
+/* Target-specific multicharacter options, not const-declared.  */
 struct option md_longopts[] =
 {
 #define OPTION_NO_US (OPTION_MD_BASE + 0)
   {"no-underscore", no_argument, NULL, OPTION_NO_US},
 #define OPTION_US (OPTION_MD_BASE + 1)
   {"underscore", no_argument, NULL, OPTION_US},
-#define OPTION_PIC (OPTION_MD_BASE + 2)
+#define OPTION_PIC (OPTION_US + 1)
   {"pic", no_argument, NULL, OPTION_PIC},
-#define OPTION_MULBUG_ABORT_ON (OPTION_MD_BASE + 3)
+#define OPTION_MULBUG_ABORT_ON (OPTION_PIC + 1)
   {"mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_ON},
-#define OPTION_MULBUG_ABORT_OFF (OPTION_MD_BASE + 4)
+#define OPTION_MULBUG_ABORT_OFF (OPTION_MULBUG_ABORT_ON + 1)
   {"no-mul-bug-abort", no_argument, NULL, OPTION_MULBUG_ABORT_OFF},
+#define OPTION_ARCH (OPTION_MULBUG_ABORT_OFF + 1)
+  {"march", required_argument, NULL, OPTION_ARCH},
   {NULL, no_argument, NULL, 0}
 };
 
-/* Not const-declared at usage in 2.9.1.  */
+/* Not const-declared.  */
 size_t md_longopts_size = sizeof (md_longopts);
 const char *md_shortopts = "hHN";
 
@@ -342,7 +437,12 @@ const char *md_shortopts = "hHN";
    numbers, and md_create_short_jump is called after relaxation.  */
 
 int md_short_jump_size = 6;
-int md_long_jump_size = 6;
+
+/* The v32 version has a delay-slot, hence two bytes longer.  */
+#define cris_any_v0_v10_long_jump_size 6
+#define crisv32_long_jump_size 8
+
+int md_long_jump_size = XCONCAT2 (DEFAULT_CRIS_ARCH,_long_jump_size);
 
 /* Report output format.  Small changes in output format (like elf
    variants below) can happen until all options are parsed, but after
@@ -367,6 +467,36 @@ cris_target_format ()
     }
 }
 
+/* Return a bfd_mach_cris... value corresponding to the value of
+   cris_arch.  */
+
+unsigned int
+cris_mach ()
+{
+  unsigned int retval = 0;
+
+  switch (cris_arch)
+    {
+    case arch_cris_common_v10_v32:
+      retval = bfd_mach_cris_v10_v32;
+      break;
+
+    case arch_crisv32:
+      retval = bfd_mach_cris_v32;
+      break;
+
+    case arch_crisv10:
+    case arch_cris_any_v0_v10:
+      retval = bfd_mach_cris_v0_v10;
+      break;
+
+    default:
+      BAD_CASE (cris_arch);
+    }
+
+  return retval;
+}
+
 /* We need a port-specific relaxation function to cope with sym2 - sym1
    relative expressions with both symbols in the same segment (but not
    necessarily in the same frag as this insn), for example:
@@ -394,7 +524,11 @@ cris_relax_frag (seg, fragP, stretch)
      because of the different reasons that they aren't relaxable.  */
   switch (fragP->fr_subtype)
     {
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+    case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
       /* When we get to these states, the frag won't grow any more.  */
       return 0;
@@ -484,21 +618,63 @@ md_estimate_size_before_relax (fragP, se
      segT segment_type;
 {
   int old_fr_fix;
+  symbolS *symbolP = fragP->fr_symbol;
+
+#define HANDLE_RELAXABLE(state)						\
+    case ENCODE_RELAX (state, STATE_UNDF):				\
+      if (symbolP != NULL						\
+	  && S_GET_SEGMENT (symbolP) == segment_type			\
+	  && !S_IS_WEAK (symbolP))					\
+	/* The symbol lies in the same segment - a relaxable		\
+	   case.  */							\
+	fragP->fr_subtype						\
+	  = ENCODE_RELAX (state, STATE_BYTE);				\
+      else								\
+	/* Unknown or not the same segment, so not relaxable.  */	\
+	fragP->fr_subtype						\
+	  = ENCODE_RELAX (state, STATE_DWORD);				\
+      fragP->fr_var							\
+	= md_cris_relax_table[fragP->fr_subtype].rlx_length;		\
+      break
 
   old_fr_fix = fragP->fr_fix;
 
   switch (fragP->fr_subtype)
     {
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_UNDF):
-      if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type)
-	/* The symbol lies in the same segment - a relaxable case.  */
-	fragP->fr_subtype
-	  = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE);
+      HANDLE_RELAXABLE (STATE_COND_BRANCH);
+      HANDLE_RELAXABLE (STATE_COND_BRANCH_V32);
+      HANDLE_RELAXABLE (STATE_COND_BRANCH_COMMON);
+      HANDLE_RELAXABLE (STATE_ABS_BRANCH_V32);
+
+    case ENCODE_RELAX (STATE_LAPC, STATE_UNDF):
+      if (symbolP != NULL
+	  && S_GET_SEGMENT (symbolP) == segment_type
+	  && !S_IS_WEAK (symbolP))
+	{
+	  /* The symbol lies in the same segment - a relaxable case.
+	     Check if we currently have an odd offset; we can't code
+	     that into the instruction.  Relaxing presumably only cause
+	     multiple-of-two changes, so we should only need to adjust
+	     for that here.  */
+	  bfd_vma target_address
+	    = (symbolP
+	       ? S_GET_VALUE (symbolP)
+	       : 0) + fragP->fr_offset;
+	  bfd_vma var_part_offset = fragP->fr_fix;
+	  bfd_vma address_of_var_part = fragP->fr_address + var_part_offset;
+	  long offset = target_address - (address_of_var_part - 2);
+
+	  fragP->fr_subtype
+	    = (offset & 1)
+	    ? ENCODE_RELAX (STATE_LAPC, STATE_DWORD)
+	    : ENCODE_RELAX (STATE_LAPC, STATE_BYTE);
+	}
       else
 	/* Unknown or not the same segment, so not relaxable.  */
 	fragP->fr_subtype
-	  = ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD);
-      fragP->fr_var = md_cris_relax_table[fragP->fr_subtype].rlx_length;
+	  = ENCODE_RELAX (STATE_LAPC, STATE_DWORD);
+      fragP->fr_var
+	= md_cris_relax_table[fragP->fr_subtype].rlx_length;
       break;
 
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_UNDF):
@@ -512,7 +688,7 @@ md_estimate_size_before_relax (fragP, se
 	 would in general be no shorter or faster code, only more
 	 complicated.  */
 
-      if (S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+      if (S_GET_SEGMENT (symbolP) != absolute_section)
 	{
 	  /* Go for dword if not absolute or same segment.  */
 	  fragP->fr_subtype
@@ -534,7 +710,8 @@ md_estimate_size_before_relax (fragP, se
 	{
 	  /* Absolute expression.  */
 	  long int value;
-	  value = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
+	  value = (symbolP != NULL
+		   ? S_GET_VALUE (symbolP) : 0) + fragP->fr_offset;
 
 	  if (value >= -128 && value <= 127)
 	    {
@@ -571,9 +748,20 @@ md_estimate_size_before_relax (fragP, se
 	}
       break;
 
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+    case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+    case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_WORD):
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_DWORD):
@@ -648,24 +836,35 @@ md_convert_frag (abfd, sec, fragP)
 
   switch (fragP->fr_subtype)
     {
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_BYTE):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_BYTE):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_BYTE):
       opcodep[0] = branch_disp ((target_address - address_of_var_part));
       var_part_size = 0;
       break;
 
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_WORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_WORD):
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_WORD):
       /* We had a quick immediate branch, now turn it into a word one i.e. a
 	 PC autoincrement.  */
       opcodep[0] = BRANCH_PC_LOW;
       opcodep[1] &= 0xF0;
       opcodep[1] |= BRANCH_INCR_HIGH;
       md_number_to_chars (var_partp,
-			  (long) (target_address - (address_of_var_part + 2)),
+			  (long)
+			  (target_address
+			   - (address_of_var_part
+			      + (cris_arch == arch_crisv32
+				 || cris_arch == arch_cris_common_v10_v32
+				 ? -2 : 2))),
 			  2);
       var_part_size = 2;
       break;
 
-    case ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, STATE_DWORD):
+    case ENCODE_RELAX (STATE_COND_BRANCH, STATE_DWORD):
       gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
 			  fragP->fr_symbol, (symbolS *) NULL,
 			  fragP->fr_offset);
@@ -673,6 +872,74 @@ md_convert_frag (abfd, sec, fragP)
       var_part_size = 2 + 2 + 4 + 2;
       break;
 
+    case ENCODE_RELAX (STATE_COND_BRANCH_V32, STATE_DWORD):
+      gen_cond_branch_32 (fragP->fr_opcode, var_partp, fragP,
+			  fragP->fr_symbol, (symbolS *) NULL,
+			  fragP->fr_offset);
+      /* Twelve bytes added: a branch, nop and another branch and nop.  */
+      var_part_size = 2 + 2 + 2 + 4 + 2;
+      break;
+
+    case ENCODE_RELAX (STATE_COND_BRANCH_COMMON, STATE_DWORD):
+      as_bad_where (fragP->fr_file, fragP->fr_line,
+		    _("Relaxation to long branches for .arch common_v10_v32\
+ not implemented"));
+      /* Pretend we have twelve bytes for sake of quelling further
+         errors.  */
+      var_part_size = 2 + 2 + 2 + 4 + 2;
+      break;
+
+    case ENCODE_RELAX (STATE_ABS_BRANCH_V32, STATE_DWORD):
+      /* We had a quick immediate branch or a word immediate ba.  Now
+	 turn it into a dword one.  */
+      opcodep[0] = BA_DWORD_OPCODE & 255;
+      opcodep[1] = (BA_DWORD_OPCODE >> 8) & 255;
+      fix_new (fragP, var_partp - fragP->fr_literal, 4, symbolP,
+	       fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+      var_part_size = 4;
+      break;
+
+    case ENCODE_RELAX (STATE_LAPC, STATE_BYTE):
+      {
+	long offset = target_address - (address_of_var_part - 2);
+
+	/* This is mostly a sanity check; useful occurrences (if there
+	   really are any) should have been caught in
+	   md_estimate_size_before_relax.  We can (at least
+	   theoretically) stumble over invalid code with odd sizes and
+	   .p2aligns within the code, so emit an error if that happens.
+	   (The generic relaxation machinery is not fit to check this.)  */
+
+	if (offset & 1)
+	  as_bad_where (fragP->fr_file, fragP->fr_line,
+		    _("Complicated LAPC target operand is not\
+ a multiple of two.  Use LAPC.D"));
+
+	/* FIXME: This *is* a sanity check.  Remove when done with.  */
+	if (offset > 15*2 || offset < 0)
+	  as_fatal (_("Internal error found in md_convert_frag: offset %ld.\
+  Please report this."),
+		    offset);
+
+	opcodep[0] |= (offset / 2) & 0xf;
+	var_part_size = 0;
+      }
+      break;
+
+    case ENCODE_RELAX (STATE_LAPC, STATE_DWORD):
+      {
+	md_number_to_chars (opcodep,
+			    LAPC_DWORD_OPCODE + (opcodep[1] & 0xf0) * 256,
+			    2);
+	/* Remember that the reloc is against the position *after* the
+	   relocated contents, so we need to adjust to the start of
+	   the insn.  */
+	fix_new (fragP, var_partp - fragP->fr_literal, 4, fragP->fr_symbol,
+		 fragP->fr_offset + 6, 1, BFD_RELOC_32_PCREL);
+	var_part_size = 4;
+      }
+      break;
+
     case ENCODE_RELAX (STATE_BASE_PLUS_DISP_PREFIX, STATE_BYTE):
       if (symbolP == NULL)
 	as_fatal (_("internal inconsistency in %s: bdapq no symbol"),
@@ -737,9 +1004,8 @@ md_convert_frag (abfd, sec, fragP)
    Used by md_create_long_jump.
 
    This used to be md_create_short_jump, but is now called from
-   md_create_long_jump instead, when sufficient.
-   since the sizes of the jumps are the same.  It used to be brittle,
-   making possibilities for creating bad code.  */
+   md_create_long_jump instead, when sufficient, since the sizes of the
+   jumps are the same for pre-v32.  */
 
 static void
 cris_create_short_jump (storep, from_addr, to_addr, fragP, to_symbol)
@@ -751,20 +1017,39 @@ cris_create_short_jump (storep, from_add
 {
   long int distance;
 
+  /* See md_create_long_jump about the comment on the "+ 2".  */
+  long int max_minimal_minus_distance;
+  long int max_minimal_plus_distance;
+  int nop_opcode;
+
+  if (cris_arch == arch_crisv32)
+    {
+      max_minimal_minus_distance = BRANCH_BB_V32 + 2;
+      max_minimal_plus_distance = BRANCH_BF_V32 + 2;
+      nop_opcode = NOP_OPCODE_V32;
+    }
+  else
+    {
+      max_minimal_minus_distance = BRANCH_BB + 2;
+      max_minimal_plus_distance = BRANCH_BF + 2;
+      nop_opcode = NOP_OPCODE;
+    }
+
   distance = to_addr - from_addr;
 
-  if (-254 <= distance && distance <= 256)
+  if (max_minimal_minus_distance <= distance
+      && distance <= max_minimal_plus_distance)
     {
       /* Create a "short" short jump: "BA distance - 2".  */
       storep[0] = branch_disp (distance - 2);
       storep[1] = BA_QUICK_HIGH;
 
       /* A nop for the delay slot.  */
-      md_number_to_chars (storep + 2, NOP_OPCODE, 2);
+      md_number_to_chars (storep + 2, nop_opcode, 2);
 
       /* The extra word should be filled with something sane too.  Make it
 	 a nop to keep disassembly sane.  */
-      md_number_to_chars (storep + 4, NOP_OPCODE, 2);
+      md_number_to_chars (storep + 4, nop_opcode, 2);
     }
   else
     {
@@ -772,10 +1057,14 @@ cris_create_short_jump (storep, from_add
       md_number_to_chars (storep, BA_PC_INCR_OPCODE, 2);
 
       /* ".WORD distance - 4".  */
-      md_number_to_chars (storep + 2, (long) (distance - 4), 2);
+      md_number_to_chars (storep + 2,
+			  (long) (distance - 4
+				  - (cris_arch == arch_crisv32
+				     ? -4 : 0)),
+			  2);
 
       /* A nop for the delay slot.  */
-      md_number_to_chars (storep + 4, NOP_OPCODE, 2);
+      md_number_to_chars (storep + 4, nop_opcode, 2);
     }
 }
 
@@ -798,24 +1087,50 @@ md_create_long_jump (storep, from_addr, 
 {
   long int distance;
 
+  /* FIXME: What's that "+ 3"?  It comes from the magic numbers that
+     used to be here, it's just translated to the limit macros used in
+     the relax table.  But why + 3?  */
+  long int max_short_minus_distance
+    = cris_arch != arch_crisv32 ? BRANCH_WB + 3 : BRANCH_WB_V32 + 3;
+
+  long int max_short_plus_distance
+    = cris_arch != arch_crisv32 ? BRANCH_WF + 3 : BRANCH_WF_V32 + 3;
+
+  /* Bail out for compatibility mode.  (It seems it can be implemented,
+     perhaps with a 10-byte sequence: "move.d NNNN,$pc/$acr", "jump
+     $acr", "nop"; but doesn't seem worth it at the moment.)  */
+  if (cris_arch == arch_cris_common_v10_v32)
+    as_fatal (_("Out-of-range .word offset handling\
+ is not implemented for .arch common_v10_v32"));
+
   distance = to_addr - from_addr;
 
-  if (-32763 <= distance && distance <= 32772)
-    {
-      /* Then make it a "short" long jump.  */
-      cris_create_short_jump (storep, from_addr, to_addr, fragP,
-			      to_symbol);
-    }
+  if (max_short_minus_distance <= distance
+      && distance <= max_short_plus_distance)
+    /* Then make it a "short" long jump.  */
+    cris_create_short_jump (storep, from_addr, to_addr, fragP,
+			    to_symbol);
   else
     {
-      /* We have a "long" long jump: "JUMP [PC+]".
-	 Make it an "ADD [PC+],PC" if we're supposed to emit PIC code.  */
+      /* We have a "long" long jump: "JUMP [PC+]".  If CRISv32, always
+	 make it a BA.  Else make it an "ADD [PC+],PC" if we're supposed
+	 to emit PIC code.  */
       md_number_to_chars (storep,
-			  pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE, 2);
+			  cris_arch == arch_crisv32
+			  ? BA_DWORD_OPCODE
+			  : (pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE),
+			  2);
 
       /* Follow with a ".DWORD to_addr", PC-relative for PIC.  */
       fix_new (fragP, storep + 2 - fragP->fr_literal, 4, to_symbol,
-	       0, pic ? 1 : 0, pic ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+	       cris_arch == arch_crisv32 ? 6 : 0,
+	       cris_arch == arch_crisv32 || pic ? 1 : 0,
+	       cris_arch == arch_crisv32 || pic
+	       ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+
+      /* Follow it with a "NOP" for CRISv32.  */
+      if (cris_arch == arch_crisv32)
+	md_number_to_chars (storep + 6, NOP_OPCODE_V32, 2);
     }
 }
 
@@ -852,9 +1167,34 @@ md_begin ()
   if (op_hash == NULL)
     as_fatal (_("Virtual memory exhausted"));
 
+  /* Enable use of ".if ..asm.arch.cris.v32"
+     and ".if ..asm.arch.cris.common_v10_v32" and a few others.  */
+  symbol_table_insert (symbol_new ("..asm.arch.cris.v32", absolute_section,
+				   (cris_arch == arch_crisv32),
+				   &zero_address_frag));
+  symbol_table_insert (symbol_new ("..asm.arch.cris.v10", absolute_section,
+				   (cris_arch == arch_crisv10),
+				   &zero_address_frag));
+  symbol_table_insert (symbol_new ("..asm.arch.cris.common_v10_v32",
+				   absolute_section,
+				   (cris_arch == arch_cris_common_v10_v32),
+				   &zero_address_frag));
+  symbol_table_insert (symbol_new ("..asm.arch.cris.any_v0_v10",
+				   absolute_section,
+				   (cris_arch == arch_cris_any_v0_v10),
+				   &zero_address_frag));
+
   while (cris_opcodes[i].name != NULL)
     {
       const char *name = cris_opcodes[i].name;
+
+      if (! cris_insn_ver_valid_for_arch (cris_opcodes[i].applicable_version,
+					  cris_arch))
+	{
+	  i++;
+	  continue;
+	}
+
       hashret = hash_insert (op_hash, name, (PTR) &cris_opcodes[i]);
 
       if (hashret != NULL && *hashret != '\0')
@@ -980,7 +1320,12 @@ md_assemble (str)
 	    is_undefined = 1;
 	}
 
-      if (to_seg == now_seg || is_undefined)
+      if (to_seg == now_seg || is_undefined
+	  /* In CRISv32, there *is* a 32-bit absolute branch, so don't
+	     emit the 12-byte sequence for known symbols in other
+	     segments.  */
+	  || (cris_arch == arch_crisv32
+	      && output_instruction.opcode == BA_QUICK_OPCODE))
 	{
 	  /* Handle complex expressions.  */
 	  valueT addvalue
@@ -992,12 +1337,24 @@ md_assemble (str)
 	       ? output_instruction.expr.X_add_symbol
 	       : make_expr_symbol (&output_instruction.expr));
 
-	  /* If is_undefined, then the expression may BECOME now_seg.  */
-	  length_code = is_undefined ? STATE_UNDF : STATE_BYTE;
-
-	  /* Make room for max ten bytes of variable length.  */
-	  frag_var (rs_machine_dependent, 10, 0,
-		    ENCODE_RELAX (STATE_CONDITIONAL_BRANCH, length_code),
+	  /* If is_undefined, the expression may still become now_seg.
+	     That case is handled by md_estimate_size_before_relax.  */
+	  length_code = to_seg == now_seg ? STATE_BYTE : STATE_UNDF;
+
+	  /* Make room for max twelve bytes of variable length for v32 mode,
+	     ten for v10 and older.  */
+	  frag_var (rs_machine_dependent,
+		    (cris_arch == arch_crisv32
+		     || cris_arch == arch_cris_common_v10_v32) ? 12 : 10, 0,
+		    ENCODE_RELAX (cris_arch == arch_crisv32
+				  ? (output_instruction.opcode
+				     == BA_QUICK_OPCODE
+				     ? STATE_ABS_BRANCH_V32
+				     : STATE_COND_BRANCH_V32)
+				  : (cris_arch == arch_cris_common_v10_v32
+				     ? STATE_COND_BRANCH_COMMON
+				     : STATE_COND_BRANCH),
+				  length_code),
 		    sym, addvalue, opcodep);
 	}
       else
@@ -1005,7 +1362,10 @@ md_assemble (str)
 	  /* We have: to_seg != now_seg && to_seg != undefined_section.
 	     This means it is a branch to a known symbol in another
 	     section, perhaps an absolute address.  Emit a 32-bit branch.  */
-	  char *cond_jump = frag_more (10);
+	  char *cond_jump
+	    = frag_more ((cris_arch == arch_crisv32
+			  || cris_arch == arch_cris_common_v10_v32)
+			 ? 12 : 10);
 
 	  gen_cond_branch_32 (opcodep, cond_jump, frag_now,
 			      output_instruction.expr.X_add_symbol,
@@ -1057,7 +1417,29 @@ md_assemble (str)
 	  p = frag_more (output_instruction.imm_oprnd_size);
 	  fix_new_exp (frag_now, (p - frag_now->fr_literal),
 		       output_instruction.imm_oprnd_size,
-		       &output_instruction.expr, 0, reloc);
+		       &output_instruction.expr,
+		       reloc == BFD_RELOC_32_PCREL
+		       || reloc == BFD_RELOC_16_PCREL
+		       || reloc == BFD_RELOC_8_PCREL, reloc);
+	}
+      else if (output_instruction.reloc == BFD_RELOC_CRIS_LAPCQ_OFFSET
+	       && output_instruction.expr.X_md != 0)
+	{
+	  /* Handle complex expressions.  */
+	  valueT addvalue
+	    = (output_instruction.expr.X_op_symbol != NULL
+	       ? 0 : output_instruction.expr.X_add_number);
+	  symbolS *sym
+	    = (output_instruction.expr.X_op_symbol != NULL
+	       ? make_expr_symbol (&output_instruction.expr)
+	       : output_instruction.expr.X_add_symbol);
+
+	  /* This is a relaxing construct, so we need a frag_var rather
+	     than the fix_new_exp call below.  */
+	  frag_var (rs_machine_dependent,
+		    4, 0,
+		    ENCODE_RELAX (STATE_LAPC, STATE_UNDF),
+		    sym, addvalue, opcodep);
 	}
       else if (output_instruction.reloc != BFD_RELOC_NONE)
 	{
@@ -1069,7 +1451,12 @@ md_assemble (str)
 	     expressions" - where the expression contains a difference of
 	     two symbols in the same segment.  */
 	  fix_new_exp (frag_now, (opcodep - frag_now->fr_literal), 2,
-		       &output_instruction.expr, 0,
+		       &output_instruction.expr,
+		       output_instruction.reloc == BFD_RELOC_32_PCREL
+		       || output_instruction.reloc == BFD_RELOC_16_PCREL
+		       || output_instruction.reloc == BFD_RELOC_8_PCREL
+		       || (output_instruction.reloc
+			   == BFD_RELOC_CRIS_LAPCQ_OFFSET),
 		       output_instruction.reloc);
 	}
     }
@@ -1097,7 +1484,7 @@ cris_process_instruction (insn_text, out
      error.  */
   prefixp->kind = PREFIX_NONE;
   prefixp->reloc = BFD_RELOC_NONE;
-  out_insnp->insn_type = CRIS_INSN_NORMAL;
+  out_insnp->insn_type = CRIS_INSN_NONE;
   out_insnp->imm_oprnd_size = 0;
 
   /* Find the end of the opcode mnemonic.  We assume (true in 2.9.1)
@@ -1183,6 +1570,8 @@ cris_process_instruction (insn_text, out
 		 Ignore it here.  */
 	      continue;
 
+	    case '[':
+	    case ']':
 	    case ',':
 	    case ' ':
 	      /* These must match exactly.  */
@@ -1190,6 +1579,21 @@ cris_process_instruction (insn_text, out
 		continue;
 	      break;
 
+	    case 'A':
+	      /* "ACR", case-insensitive.
+		 Handle a sometimes-mandatory dollar sign as register
+		 prefix.  */
+	      if (*s == REGISTER_PREFIX_CHAR)
+		s++;
+	      else if (demand_register_prefix)
+		break;
+
+	      if ((*s++ != 'a' && s[-1] != 'A')
+		  || (*s++ != 'c' && s[-1] != 'C')
+		  || (*s++ != 'r' && s[-1] != 'R'))
+		break;
+	      continue;
+
 	    case 'B':
 	      /* This is not really an operand, but causes a "BDAP
 		 -size,SP" prefix to be output, for PUSH instructions.  */
@@ -1237,6 +1641,19 @@ cris_process_instruction (insn_text, out
 		  continue;
 		}
 
+ 	      /* For 'd', check for an optional ".d" or ".D" at the
+                 start of the operands, followed by a space character.  */
+	    case 'd':
+	      if (modified_char == '.' && *s == '.')
+		{
+		  if ((s[1] != 'd' && s[1] == 'D')
+		      || ! ISSPACE (s[2]))
+		    break;
+		  s += 2;
+		  continue;
+		}
+	      continue;
+
 	    case 'D':
 	      /* General register in bits <15:12> and <3:0>.  */
 	      if (! get_gen_reg (&s, &regno))
@@ -1317,7 +1734,8 @@ cris_process_instruction (insn_text, out
 
 	    case 'm':
 	      /* A size modifier, B, W or D, to be put in bits <5:4>.  */
-	      if (! get_bwd_size_modifier (&s, &size_bits))
+	      if (modified_char != '.'
+		  || ! get_bwd_size_modifier (&s, &size_bits))
 		break;
 	      else
 		{
@@ -1335,8 +1753,25 @@ cris_process_instruction (insn_text, out
 		  continue;
 		}
 
+	    case 'Q':
+	      /* A 8-bit quick BDAP expression, "expr,R".  */
+	      if (! cris_get_expression (&s, &out_insnp->expr))
+		break;
+
+	      if (*s != ',')
+		break;
+
+	      s++;
+
+	      if (!get_gen_reg (&s, &regno))
+		break;
+
+	      out_insnp->opcode |= regno << 12;
+	      out_insnp->reloc = BFD_RELOC_CRIS_SIGNED_8;
+	      continue;
+	      
 	    case 'O':
-	      /* A BDAP expression for any size, "expr,r".  */
+	      /* A BDAP expression for any size, "expr,R".  */
 	      if (! cris_get_expression (&s, &prefixp->expr))
 		break;
 	      else
@@ -1420,7 +1855,7 @@ cris_process_instruction (insn_text, out
 	    case 's':
 	      /* Source operand in bits <10>, <3:0> and optionally a
 		 prefix; i.e. an indirect operand or an side-effect
-		 prefix.  */
+		 prefix (where valid).  */
 	      if (! get_autoinc_prefix_or_indir_op (&s, prefixp, &mode,
 						    &regno,
 						    &imm_expr_found,
@@ -1452,6 +1887,71 @@ cris_process_instruction (insn_text, out
 		  continue;
 		}
 
+	    case 'N':
+	    case 'Y':
+	      /* Like 's', but immediate operand only.  Also does not
+		 modify insn.  There are no insns where a PIC reloc
+		 specifier makes sense.  */
+	      if (cris_get_expression (&s, &out_insnp->expr))
+		{
+		  imm_expr_found = 1;
+		  continue;
+		}
+	      break;
+
+	    case 'n':
+	      /* Like 'N', but PC-relative to the start of the insn.
+		 There might be a :PLT to request a PLT entry.  */
+	      if (cris_get_expression (&s, &out_insnp->expr))
+		{
+		  imm_expr_found = 1;
+		  out_insnp->reloc = BFD_RELOC_32_PCREL;
+
+		  /* We have to adjust the expression, because that
+		     relocation is to the location *after* the
+		     relocation.  So add 2 for the insn and 4 for the
+		     relocation.  */
+		  out_insnp->expr.X_add_number += 6;
+
+		  if (pic && *s == PIC_SUFFIX_CHAR)
+		    cris_get_pic_suffix (&s, &out_insnp->reloc,
+					 &out_insnp->expr);
+
+		  continue;
+		}
+	      break;
+
+	    case 'U':
+	      /* Maybe 'u', maybe 'n'.  Only for LAPC/LAPCQ.  */
+	      if (cris_get_expression (&s, &out_insnp->expr))
+		{
+		  out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+		  /* Define 1 as relaxing.  */
+		  out_insnp->expr.X_md = 1;
+		  continue;
+		}
+	      break;
+
+	    case 'u':
+	      /* Four PC-relative bits in <3:0> representing <4:1>:0 of
+		 an offset relative to the beginning of the current
+		 insn.  */
+	      if (cris_get_expression (&s, &out_insnp->expr))
+		{
+		  out_insnp->reloc = BFD_RELOC_CRIS_LAPCQ_OFFSET;
+
+		  /* Define 0 as non-relaxing.  */
+		  out_insnp->expr.X_md = 0;
+
+		  /* We have to adjust the expression, because that
+		     relocation is to the location *after* the
+		     insn.  So add 2 for the insn.  */
+		  out_insnp->expr.X_add_number += 2;
+		  continue;
+		}
+	      break;
+
 	    case 'x':
 	      /* Rs.m in bits <15:12> and <5:4>.  */
 	      if (! get_gen_reg (&s, &regno)
@@ -1506,6 +2006,15 @@ cris_process_instruction (insn_text, out
 		  continue;
 		}
 
+	    case 'T':
+	      if (cris_arch == arch_crisv32
+		  && get_sup_reg (&s, &regno))
+		{
+		  out_insnp->opcode |= regno << 12;
+		  continue;
+		}
+	      break;
+
 	    default:
 	      BAD_CASE (*args);
 	    }
@@ -1520,9 +2029,19 @@ cris_process_instruction (insn_text, out
 	{
 	  /* If it's just that the args don't match, maybe the next
 	     item in the table is the same opcode but with
-	     matching operands.  */
+	     matching operands.  First skip any invalid ones.  */
+	  while (instruction[1].name != NULL
+		 && strcmp (instruction->name, instruction[1].name) == 0
+		 && ! cris_insn_ver_valid_for_arch (instruction[1]
+						    .applicable_version,
+						    cris_arch))
+	    ++instruction;
+
 	  if (instruction[1].name != NULL
-	      && ! strcmp (instruction->name, instruction[1].name))
+	      && strcmp (instruction->name, instruction[1].name) == 0
+	      && cris_insn_ver_valid_for_arch (instruction[1]
+					       .applicable_version,
+					       cris_arch))
 	    {
 	      /* Yep.  Restart and try that one instead.  */
 	      ++instruction;
@@ -1534,6 +2053,11 @@ cris_process_instruction (insn_text, out
 	      /* We've come to the end of instructions with this
 		 opcode, so it must be an error.  */
 	      as_bad (_("Illegal operands"));
+
+	      /* As discard_rest_of_line, but without continuing to the
+		 next line.  */
+	      while (!is_end_of_line[(unsigned char) *input_line_pointer])
+		input_line_pointer++;
 	      return;
 	    }
 	}
@@ -1558,52 +2082,91 @@ cris_process_instruction (insn_text, out
 		  break;
 
 		case SIZE_SPEC_REG:
-		  switch (out_insnp->spec_reg->reg_size)
-		    {
-		    case 1:
-		      if (out_insnp->expr.X_op == O_constant
-			  && (out_insnp->expr.X_add_number < -128
-			      || out_insnp->expr.X_add_number > 255))
-			as_bad (_("Immediate value not in 8 bit range: %ld"),
-				out_insnp->expr.X_add_number);
-		      /* Fall through.  */
-		    case 2:
-		      /* FIXME:  We need an indicator in the instruction
-			 table to pass on, to indicate if we need to check
-			 overflow for a signed or unsigned number.  */
-		      if (out_insnp->expr.X_op == O_constant
-			  && (out_insnp->expr.X_add_number < -32768
-			      || out_insnp->expr.X_add_number > 65535))
-			as_bad (_("Immediate value not in 16 bit range: %ld"),
-				out_insnp->expr.X_add_number);
-		      out_insnp->imm_oprnd_size = 2;
-		      break;
-
-		    case 4:
-		      out_insnp->imm_oprnd_size = 4;
-		      break;
-
-		    default:
-		      BAD_CASE (out_insnp->spec_reg->reg_size);
-		    }
+		  if (cris_arch == arch_crisv32)
+		    /* All immediate loads of special registers are
+		       32-bit on CRISv32.  */
+		    out_insnp->imm_oprnd_size = 4;
+		  else
+		    switch (out_insnp->spec_reg->reg_size)
+		      {
+		      case 1:
+			if (out_insnp->expr.X_op == O_constant
+			    && (out_insnp->expr.X_add_number < -128
+				|| out_insnp->expr.X_add_number > 255))
+			  as_bad (_("Immediate value not in 8 bit range: %ld"),
+				  out_insnp->expr.X_add_number);
+			/* Fall through.  */
+		      case 2:
+			/* FIXME:  We need an indicator in the instruction
+			   table to pass on, to indicate if we need to check
+			   overflow for a signed or unsigned number.  */
+			if (out_insnp->expr.X_op == O_constant
+			    && (out_insnp->expr.X_add_number < -32768
+				|| out_insnp->expr.X_add_number > 65535))
+			  as_bad (_("Immediate value not in 16 bit range: %ld"),
+				  out_insnp->expr.X_add_number);
+			out_insnp->imm_oprnd_size = 2;
+			break;
+
+		      case 4:
+			out_insnp->imm_oprnd_size = 4;
+			break;
+
+		      default:
+			BAD_CASE (out_insnp->spec_reg->reg_size);
+		      }
 		  break;
 
 		case SIZE_FIELD:
+		case SIZE_FIELD_SIGNED:
+		case SIZE_FIELD_UNSIGNED:
 		  switch (size_bits)
 		    {
+		      /* FIXME: Find way to pass un/signedness to
+			 caller, and set reloc type instead, postponing
+			 this check until cris_number_to_imm.  That
+			 necessarily corrects the reloc type for the
+			 byte case, maybe requiring further changes.  */
 		    case 0:
-		      if (out_insnp->expr.X_op == O_constant
-			  && (out_insnp->expr.X_add_number < -128
-			      || out_insnp->expr.X_add_number > 255))
-			as_bad (_("Immediate value not in 8 bit range: %ld"),
-				out_insnp->expr.X_add_number);
+		      if (out_insnp->expr.X_op == O_constant)
+			{
+			  if (instruction->imm_oprnd_size == SIZE_FIELD
+			      && (out_insnp->expr.X_add_number < -128
+				  || out_insnp->expr.X_add_number > 255))
+			    as_bad (_("Immediate value not in 8 bit range: %ld"),
+				    out_insnp->expr.X_add_number);
+			  else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+			      && (out_insnp->expr.X_add_number < -128
+				  || out_insnp->expr.X_add_number > 127))
+			    as_bad (_("Immediate value not in 8 bit signed range: %ld"),
+				    out_insnp->expr.X_add_number);
+			  else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+				   && (out_insnp->expr.X_add_number < 0
+				       || out_insnp->expr.X_add_number > 255))
+			    as_bad (_("Immediate value not in 8 bit unsigned range: %ld"),
+				    out_insnp->expr.X_add_number);
+			}
+
 		      /* Fall through.  */
 		    case 1:
-		      if (out_insnp->expr.X_op == O_constant
-			  && (out_insnp->expr.X_add_number < -32768
-			      || out_insnp->expr.X_add_number > 65535))
-			as_bad (_("Immediate value not in 16 bit range: %ld"),
-				out_insnp->expr.X_add_number);
+		      if (out_insnp->expr.X_op == O_constant)
+			{
+			  if (instruction->imm_oprnd_size == SIZE_FIELD
+			      && (out_insnp->expr.X_add_number < -32768
+				  || out_insnp->expr.X_add_number > 65535))
+			    as_bad (_("Immediate value not in 16 bit range: %ld"),
+				    out_insnp->expr.X_add_number);
+			  else if (instruction->imm_oprnd_size == SIZE_FIELD_SIGNED
+			      && (out_insnp->expr.X_add_number < -32768
+				  || out_insnp->expr.X_add_number > 32767))
+			    as_bad (_("Immediate value not in 16 bit signed range: %ld"),
+				    out_insnp->expr.X_add_number);
+			  else if (instruction->imm_oprnd_size == SIZE_FIELD_UNSIGNED
+			      && (out_insnp->expr.X_add_number < 0
+				  || out_insnp->expr.X_add_number > 65535))
+			    as_bad (_("Immediate value not in 16 bit unsigned range: %ld"),
+				    out_insnp->expr.X_add_number);
+			}
 		      out_insnp->imm_oprnd_size = 2;
 		      break;
 
@@ -1767,7 +2330,18 @@ get_gen_reg (cPP, regnop)
       (*cPP)++;
 
       if ((**cPP == 'C' || **cPP == 'c')
-	  && ! ISALNUM ((*cPP)[1]))
+	  && ! ISALNUM ((*cPP)[1])
+	  /* Here's a little twist: For v32 and the compatibility mode,
+	     we only recognize PC as a register number if there's '+]'
+	     after.  We don't consume that, but the presence can only be
+	     valid after a register in a post-increment context, which
+	     is also the only valid context for PC as a register for
+	     v32.  Not that it's used very often, but saying "MOVE.D
+	     [PC+],R5" should remain valid.  It's not supported for
+	     jump-type insns or other insns with no [Rn+] mode, though.  */
+	  && ((cris_arch != arch_crisv32
+	       && cris_arch != arch_cris_common_v10_v32)
+	      || ((*cPP)[1] == '+' && (*cPP)[2] == ']')))
 	{
 	  /* It's "PC": consume the "c" and we're done.  */
 	  (*cPP)++;
@@ -1776,6 +2350,20 @@ get_gen_reg (cPP, regnop)
 	}
       break;
 
+      /* Like with PC, we recognize ACR, but only if it's *not* followed
+	 by '+', and only for v32.  */
+    case 'A':
+    case 'a':
+      if (cris_arch != arch_crisv32
+	  || ((*cPP)[1] != 'c' && (*cPP)[1] != 'C')
+	  || ((*cPP)[2] != 'r' && (*cPP)[2] != 'R')
+	  || ISALNUM ((*cPP)[3])
+	  || (*cPP)[3] == '+')
+	break;
+      (*cPP) += 3;
+      *regnop = 15;
+      return 1;
+
     case 'R':
     case 'r':
       /* Hopefully r[0-9] or r1[0-5].  Consume 'R' or 'r'.  */
@@ -1878,7 +2466,9 @@ get_spec_reg (cPP, sregpp)
       /* For a match, we must have consumed the name in the table, and we
 	 must be outside what could be part of a name.	Assume here that a
 	 test for alphanumerics is sufficient for a name test.  */
-      if (*s2 == 0 && ! ISALNUM (*s1))
+      if (*s2 == 0 && ! ISALNUM (*s1)
+	  && cris_insn_ver_valid_for_arch (sregp->applicable_version,
+					   cris_arch))
 	{
 	  /* We have a match.  Update the pointer and be done.  */
 	  *cPP = s1;
@@ -1891,6 +2481,64 @@ get_spec_reg (cPP, sregpp)
   return 0;
 }
 
+/* Get a support register from the string pointed out by *cPP. The
+   variable *cPP is advanced to the character following the support-
+   register name if one is found, and retains its original position
+   otherwise.
+
+   cPP	    Pointer to pointer to string starting with a support-register
+	    name.
+
+   sregpp   Pointer to int containing the register number.
+
+   Return 1 iff a correct support-register name is found.  */
+
+static int
+get_sup_reg (cPP, regnop)
+     char **cPP;
+     int *regnop;
+{
+  char *s1;
+  const char *s2;
+  char *name_begin = *cPP;
+
+  const struct cris_support_reg *sregp;
+
+  /* Handle a sometimes-mandatory dollar sign as register prefix.  */
+  if (*name_begin == REGISTER_PREFIX_CHAR)
+    name_begin++;
+  else if (demand_register_prefix)
+    return 0;
+
+  /* Loop over all support-registers.  */
+  for (sregp = cris_support_regs; sregp->name != NULL; sregp++)
+    {
+      /* Start over from beginning of the supposed name.  */
+      s1 = name_begin;
+      s2 = sregp->name;
+
+      while (*s2 != '\0' && TOLOWER (*s1) == *s2)
+	{
+	  s1++;
+	  s2++;
+	}
+
+      /* For a match, we must have consumed the name in the table, and we
+	 must be outside what could be part of a name.	Assume here that a
+	 test for alphanumerics is sufficient for a name test.  */
+      if (*s2 == 0 && ! ISALNUM (*s1))
+	{
+	  /* We have a match.  Update the pointer and be done.  */
+	  *cPP = s1;
+	  *regnop = sregp->number;
+	  return 1;
+	}
+    }
+
+  /* If we got here, we did not find any name.  */
+  return 0;
+}
+
 /* Get an unprefixed or side-effect-prefix operand from the string pointed
    out by *cPP.  The pointer *cPP is advanced to the character following
    the indirect operand if we have success, else it contains an undefined
@@ -1968,7 +2616,12 @@ get_autoinc_prefix_or_indir_op (cPP, pre
 
 	    case '=':
 	      /* This must be indexed with assign, or offset with assign
-		 to match.  */
+		 to match.  Not supported for crisv32 or in
+		 compatibility mode.  */
+	      if (cris_arch == arch_crisv32
+		  || cris_arch == arch_cris_common_v10_v32)
+		return 0;
+
 	      (*cPP)++;
 
 	      /* Either way, the next thing must be a register.  */
@@ -2297,8 +2950,14 @@ get_3op_or_dip_prefix_op (cPP, prefixp)
 		prefixp->opcode |= size_bits << 4;
 	    }
 	  /* Seen "[rN+", but not a '[' or a register, so then
-	     it must be a constant "I".  */
-	  else if (cris_get_expression (cPP, &prefixp->expr))
+	     it must be a constant "I".
+
+	     As a quality of implementation improvement, we check for a
+	     closing ']', like in an erroneous "[rN+]".  If we don't,
+	     the expression parser will emit a confusing "bad
+	     expression" when it sees the ']', probably because it
+	     doesn't like seeing no expression.  */
+	  else if (**cPP != ']' && cris_get_expression (cPP, &prefixp->expr))
 	    {
 	      /* Expression found, so fill in the bits of offset
 		 mode and drop down to check the closing ']'.  */
@@ -2419,6 +3078,17 @@ cris_get_expression (cPP, exprP)
   saved_input_line_pointer = input_line_pointer;
   input_line_pointer = *cPP;
 
+  /* Avoid a common error, confusing addressing modes.  Beware that the
+     call to expression below does not signal that error; it treats []
+     as parentheses, unless #define NEED_INDEX_OPERATOR in which case it
+     gives them other confusing semantics rather than plain outlawing
+     them, which is what we want.  */
+  if (*input_line_pointer == '[')
+    {
+      input_line_pointer = saved_input_line_pointer;
+      return 0;
+    }
+
   exp = expression (exprP);
   if (exprP->X_op == O_illegal || exprP->X_op == O_absent)
     {
@@ -2454,15 +3124,49 @@ get_flags (cPP, flagsp)
 	{
 	case 'd':
 	case 'D':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+					      cris_arch))
+	    return 0;
+	  *flagsp |= 0x80;
+	  break;
+
 	case 'm':
 	case 'M':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+					      cris_arch))
+	    return 0;
 	  *flagsp |= 0x80;
 	  break;
 
 	case 'e':
 	case 'E':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v0_3,
+					      cris_arch))
+	    return 0;
+	  *flagsp |= 0x40;
+	  break;
+
 	case 'b':
 	case 'B':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v8_10,
+					      cris_arch))
+	    return 0;
+	  *flagsp |= 0x40;
+	  break;
+
+	case 'p':
+	case 'P':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+					      cris_arch))
+	    return 0;
+	  *flagsp |= 0x80;
+	  break;
+
+	case 'u':
+	case 'U':
+	  if (! cris_insn_ver_valid_for_arch (cris_ver_v32p,
+					      cris_arch))
+	    return 0;
 	  *flagsp |= 0x40;
 	  break;
 
@@ -2513,6 +3217,8 @@ get_flags (cPP, flagsp)
 }
 
 /* Generate code and fixes for a BDAP prefix.
+   For v32, this handles ADDOQ because thankfully the opcodes are the
+   same.
 
    base_regno	Int containing the base register number.
 
@@ -2591,6 +3297,10 @@ branch_disp (offset)
 {
   int disp;
 
+  /* Adjust all short branch offsets here.  */
+  if (cris_arch == arch_crisv32 || cris_arch == arch_cris_common_v10_v32)
+    offset += 2;
+
   disp = offset & 0xFE;
 
   if (offset < 0)
@@ -2623,6 +3333,27 @@ gen_cond_branch_32 (opcodep, writep, fra
      symbolS *sub_symP;
      long int add_num;
 {
+  int nop_opcode;
+  int opc_offset;
+  int branch_offset;
+
+  if (cris_arch == arch_crisv32)
+    {
+      nop_opcode = NOP_OPCODE_V32;
+      opc_offset = 10;
+      branch_offset = -2 - 8;
+    }
+  else
+    {
+      nop_opcode = NOP_OPCODE;
+      opc_offset = 8;
+      branch_offset = -2 - 6;
+    }
+
+  /* We should never get here for compatibility mode.  */
+  if (cris_arch == arch_cris_common_v10_v32)
+    as_fatal (_("Calling gen_cond_branch_32 for .arch common_v10_v32\n"));
+
   if (warn_for_branch_expansion)
     as_warn_where (fragP->fr_file, fragP->fr_line,
 		   _("32-bit conditional branch generated"));
@@ -2638,8 +3369,8 @@ gen_cond_branch_32 (opcodep, writep, fra
      it's not the optimal extended construct, but we should get this
      rarely enough that it shouldn't matter.  */
 
-  writep[8] = branch_disp (-2 - 6);
-  writep[9] = opcodep[1];
+  writep[opc_offset] = branch_disp (branch_offset);
+  writep[opc_offset + 1] = opcodep[1];
 
   /* Then, we change the branch to an unconditional branch over the
      extended part, to the new location of the Bcc:
@@ -2649,8 +3380,9 @@ gen_cond_branch_32 (opcodep, writep, fra
      Note that these two writes are to currently different locations,
      merged later.  */
 
-  md_number_to_chars (opcodep, BA_QUICK_OPCODE + 8, 2);
-  md_number_to_chars (writep, NOP_OPCODE, 2);
+  md_number_to_chars (opcodep, BA_QUICK_OPCODE
+		      + (cris_arch == arch_crisv32 ? 12 : 8), 2);
+  md_number_to_chars (writep, nop_opcode, 2);
 
   /* Then the extended thing, the 32-bit jump insn.
        opcodep+4: JUMP [PC+]
@@ -2658,7 +3390,9 @@ gen_cond_branch_32 (opcodep, writep, fra
        opcodep+4: ADD [PC+],PC.  */
 
   md_number_to_chars (writep + 2,
-		      pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE, 2);
+		      cris_arch == arch_crisv32
+		      ? BA_DWORD_OPCODE
+		      : (pic ? ADD_PC_INCR_OPCODE : JUMP_PC_INCR_OPCODE), 2);
 
   /* We have to fill in the actual value too.
        opcodep+6: .DWORD
@@ -2668,10 +3402,12 @@ gen_cond_branch_32 (opcodep, writep, fra
   if (add_symP == NULL && sub_symP == NULL)
     {
       /* An absolute address.  */
-      if (pic)
+      if (pic || cris_arch == arch_crisv32)
 	fix_new (fragP, writep + 4 - fragP->fr_literal, 4,
 		 section_symbol (absolute_section),
-		 add_num, 1, BFD_RELOC_32_PCREL);
+		 add_num
+		 + (cris_arch == arch_crisv32 ? 6 : 0),
+		 1, BFD_RELOC_32_PCREL);
       else
 	md_number_to_chars (writep + 4, add_num, 4);
     }
@@ -2683,8 +3419,15 @@ gen_cond_branch_32 (opcodep, writep, fra
 
       /* Not absolute, we have to make it a frag for later evaluation.  */
       fix_new (fragP, writep + 4 - fragP->fr_literal, 4, add_symP,
-	       add_num, pic ? 1 : 0, pic ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
+	       add_num + (cris_arch == arch_crisv32 ? 6 : 0),
+	       pic || cris_arch == arch_crisv32 ? 1 : 0,
+	       pic || cris_arch == arch_crisv32
+	       ? BFD_RELOC_32_PCREL : BFD_RELOC_32);
     }
+
+  if (cris_arch == arch_crisv32)
+    /* Follow it with a "NOP" for CRISv32.  */
+    md_number_to_chars (writep + 8, NOP_OPCODE_V32, 2);
 }
 
 /* Get the size of an immediate-reloc in bytes.  Only valid for PIC
@@ -2772,7 +3515,7 @@ cris_get_pic_suffix (cPP, relocp, exprP)
      syntax error.  */
 }
 
-/* This *could* be:
+/* This *could* have been:
 
    Turn a string in input_line_pointer into a floating point constant
    of type TYPE, and store the appropriate bytes in *LITP.  The number
@@ -2843,15 +3586,19 @@ cris_number_to_imm (bufp, val, n, fixP, 
     switch (fixP->fx_r_type)
       {
 	/* These must be fully resolved when getting here.  */
-      case BFD_RELOC_32_PCREL:
       case BFD_RELOC_16_PCREL:
       case BFD_RELOC_8_PCREL:
-	as_bad_where (fixP->fx_frag->fr_file, fixP->fx_frag->fr_line,
+	as_bad_where (fixP->fx_file, fixP->fx_line,
 		      _("PC-relative relocation must be trivially resolved"));
       default:
 	;
       }
 
+  /* Only do this for old-arch binaries.  */
+  if (cris_arch != arch_cris_any_v0_v10
+      && (fixP->fx_addsy != NULL || fixP->fx_pcrel))
+    return;
+
   switch (fixP->fx_r_type)
     {
       /* Ditto here, we put the addend into the object code as
@@ -2870,8 +3617,14 @@ cris_number_to_imm (bufp, val, n, fixP, 
 	 being relocated for these.  */
       break;
 
-    case BFD_RELOC_32:
     case BFD_RELOC_32_PCREL:
+      /* If this one isn't fully resolved, we don't want to put anything
+	 in the object.  */
+      if (fixP->fx_addsy != NULL || fixP->fx_pcrel)
+	break;
+
+      /* Fall through.  */
+    case BFD_RELOC_32:
       /* No use having warnings here, since most hosts have a 32-bit type
 	 for "long" (which will probably change soon, now that I wrote
 	 this).  */
@@ -2883,14 +3636,24 @@ cris_number_to_imm (bufp, val, n, fixP, 
 
       /* FIXME: The 16 and 8-bit cases should have a way to check
 	 whether a signed or unsigned (or any signedness) number is
-	 accepted.
-	 FIXME: Does the as_bad calls find the line number by themselves,
-	 or should we change them into as_bad_where?  */
+	 accepted.  */
 
     case BFD_RELOC_16:
     case BFD_RELOC_16_PCREL:
       if (val > 0xffff || val < -32768)
-	as_bad (_("Value not in 16 bit range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 16 bit range: %ld"), val);
+      if (! fixP->fx_addsy)
+	{
+	  bufp[1] = (val >> 8) & 0xFF;
+	  bufp[0] = val & 0xFF;
+	}
+      break;
+
+    case BFD_RELOC_CRIS_SIGNED_16:
+      if (val > 32767 || val < -32768)
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 16 bit signed range: %ld"), val);
       if (! fixP->fx_addsy)
 	{
 	  bufp[1] = (val >> 8) & 0xFF;
@@ -2901,35 +3664,50 @@ cris_number_to_imm (bufp, val, n, fixP, 
     case BFD_RELOC_8:
     case BFD_RELOC_8_PCREL:
       if (val > 255 || val < -128)
-	as_bad (_("Value not in 8 bit range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line, _("Value not in 8 bit range: %ld"), val);
       if (! fixP->fx_addsy)
 	bufp[0] = val & 0xFF;
       break;
 
+    case BFD_RELOC_CRIS_SIGNED_8:
+      if (val > 127 || val < -128)
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 8 bit signed range: %ld"), val);
+      if (! fixP->fx_addsy)
+	bufp[0] = val & 0xFF;
+      break;
+
+    case BFD_RELOC_CRIS_LAPCQ_OFFSET:
+      /* FIXME: Test-cases for out-of-range values.  Probably also need
+	 to use as_bad_where.  */
     case BFD_RELOC_CRIS_UNSIGNED_4:
       if (val > 15 || val < 0)
-	as_bad (_("Value not in 4 bit unsigned range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 4 bit unsigned range: %ld"), val);
       if (! fixP->fx_addsy)
 	bufp[0] |= val & 0x0F;
       break;
 
     case BFD_RELOC_CRIS_UNSIGNED_5:
       if (val > 31 || val < 0)
-	as_bad (_("Value not in 5 bit unsigned range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 5 bit unsigned range: %ld"), val);
       if (! fixP->fx_addsy)
 	bufp[0] |= val & 0x1F;
       break;
 
     case BFD_RELOC_CRIS_SIGNED_6:
       if (val > 31 || val < -32)
-	as_bad (_("Value not in 6 bit range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 6 bit range: %ld"), val);
       if (! fixP->fx_addsy)
 	bufp[0] |= val & 0x3F;
       break;
 
     case BFD_RELOC_CRIS_UNSIGNED_6:
       if (val > 63 || val < 0)
-	as_bad (_("Value not in 6 bit unsigned range: %ld"), val);
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("Value not in 6 bit unsigned range: %ld"), val);
       if (! fixP->fx_addsy)
 	bufp[0] |= val & 0x3F;
       break;
@@ -2983,7 +3761,7 @@ md_parse_option (arg, argp)
 
     case 'N':
       warn_for_branch_expansion = 1;
-      return 1;
+      break;
 
     case OPTION_NO_US:
       demand_register_prefix = TRUE;
@@ -2992,28 +3770,50 @@ md_parse_option (arg, argp)
 	as_bad (_("--no-underscore is invalid with a.out format"));
       else
 	symbols_have_leading_underscore = FALSE;
-      return 1;
+      break;
 
     case OPTION_US:
       demand_register_prefix = FALSE;
       symbols_have_leading_underscore = TRUE;
-      return 1;
+      break;
 
     case OPTION_PIC:
       pic = TRUE;
-      return 1;
+      break;
+
+    case OPTION_ARCH:
+      {
+	char *str = argp;
+	enum cris_archs argarch = cris_arch_from_string (&str);
+
+	if (argarch == arch_cris_unknown)
+	    as_bad (_("invalid <arch> in --march=<arch>: %s"), argp);
+	else
+	  cris_arch = argarch;
+
+	if (argarch == arch_crisv32)
+	  {
+	    err_for_dangerous_mul_placement = 0;
+	    md_long_jump_size = crisv32_long_jump_size;
+	  }
+	else
+	  md_long_jump_size = cris_any_v0_v10_long_jump_size;
+      }
+      break;
 
     case OPTION_MULBUG_ABORT_OFF:
       err_for_dangerous_mul_placement = 0;
-      return 1;
+      break;
 
     case OPTION_MULBUG_ABORT_ON:
       err_for_dangerous_mul_placement = 1;
-      return 1;
+      break;
 
     default:
       return 0;
     }
+
+  return 1;
 }
 
 /* Round up a section size to the appropriate boundary.  */
@@ -3057,6 +3857,14 @@ tc_gen_reloc (section, fixP)
 
   switch (fixP->fx_r_type)
     {
+    case BFD_RELOC_CRIS_SIGNED_8:
+      code = BFD_RELOC_8;
+      break;
+
+    case BFD_RELOC_CRIS_SIGNED_16:
+      code = BFD_RELOC_16;
+      break;
+
     case BFD_RELOC_CRIS_16_GOT:
     case BFD_RELOC_CRIS_32_GOT:
     case BFD_RELOC_CRIS_16_GOTPLT:
@@ -3065,10 +3873,14 @@ tc_gen_reloc (section, fixP)
     case BFD_RELOC_CRIS_32_PLT_GOTREL:
     case BFD_RELOC_CRIS_32_PLT_PCREL:
     case BFD_RELOC_32:
+    case BFD_RELOC_32_PCREL:
     case BFD_RELOC_16:
     case BFD_RELOC_8:
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_CRIS_UNSIGNED_8:
+    case BFD_RELOC_CRIS_UNSIGNED_16:
+    case BFD_RELOC_CRIS_LAPCQ_OFFSET:
       code = fixP->fx_r_type;
       break;
     default:
@@ -3083,10 +3895,7 @@ tc_gen_reloc (section, fixP)
   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
 
-  if (fixP->fx_pcrel)
-    relP->addend = 0;
-  else
-    relP->addend = fixP->fx_offset;
+  relP->addend = fixP->fx_offset;
 
   /* This is the standard place for KLUDGEs to work around bugs in
      bfd_install_relocation (first such note in the documentation
@@ -3154,6 +3963,9 @@ md_show_usage (stream)
 	   _("                          Registers will require a `$'-prefix.\n"));
   fprintf (stream, "%s",
 	   _("  --pic			Enable generation of position-independent code.\n"));
+  fprintf (stream, "%s",
+	   _("  --march=<arch>		Generate code for <arch>.  Valid choices for <arch>\n\
+				are v0_v10, v10, v32 and common_v10_v32.\n"));
 }
 
 /* Apply a fixS (fixup of an instruction or data that we didn't have
@@ -3186,6 +3998,9 @@ md_apply_fix3 (fixP, valP, seg)
 	as_bad_where (fixP->fx_file, fixP->fx_line,
 		      _("expression too complex"));
 
+      /* This operand-type is scaled.  */
+      if (fixP->fx_r_type == BFD_RELOC_CRIS_LAPCQ_OFFSET)
+	val /= 2;
       cris_number_to_imm (buf, val, fixP->fx_size, fixP, seg);
     }
 }
@@ -3208,7 +4023,8 @@ md_pcrel_from (fixP)
   if (OUTPUT_FLAVOR != bfd_target_elf_flavour
       || (fixP->fx_r_type != BFD_RELOC_8_PCREL
 	  && fixP->fx_r_type != BFD_RELOC_16_PCREL
-	  && fixP->fx_r_type != BFD_RELOC_32_PCREL))
+	  && fixP->fx_r_type != BFD_RELOC_32_PCREL
+	  && fixP->fx_r_type != BFD_RELOC_CRIS_LAPCQ_OFFSET))
     as_bad_where (fixP->fx_file, fixP->fx_line,
 		  _("Invalid pc-relative relocation"));
   return fixP->fx_size + addr;
@@ -3308,7 +4124,7 @@ s_syntax (ignore)
 {
   static const struct syntaxes
   {
-    const char *operand;
+    const char *const operand;
     void (*fn) PARAMS ((void));
   } syntax_table[] =
     {{SYNTAX_ENFORCE_REG_PREFIX, cris_force_reg_prefix},
@@ -3362,6 +4178,163 @@ s_cris_loc (dummy)
     dwarf2_directive_loc (dummy);
 }
 
+/* Translate a <arch> string (as common to --march=<arch> and .arch <arch>)
+   into an enum.  If the string *STR is recognized, *STR is updated to point
+   to the end of the string.  If the string is not recognized,
+   arch_cris_unknown is returned.  */
+
+static enum cris_archs
+cris_arch_from_string (str)
+     char **str;
+{
+  static const struct cris_arch_struct
+  {
+    const char *const name;
+    enum cris_archs arch;
+  } arch_table[] =
+      /* Keep in order longest-first for choices where one is a prefix
+	 of another.  */
+    {{"v0_v10", arch_cris_any_v0_v10},
+     {"v10", arch_crisv10},
+     {"v32", arch_crisv32},
+     {"common_v10_v32", arch_cris_common_v10_v32}};
+
+  const struct cris_arch_struct *ap;
+
+  for (ap = arch_table;
+       ap < arch_table + sizeof (arch_table) / sizeof (arch_table[0]);
+       ap++)
+    {
+      int len = strlen (ap->name);
+
+      if (strncmp (*str, ap->name, len) == 0
+	  && (str[0][len] == 0 || ISSPACE (str[0][len])))
+	{
+	  *str += strlen (ap->name);
+	  return ap->arch;
+	}
+    }
+
+  return arch_cris_unknown;
+}
+
+/* Return nonzero if architecture version ARCH matches version range in
+   IVER.  */
+
+static int
+cris_insn_ver_valid_for_arch (iver, arch)
+     enum cris_insn_version_usage iver;
+     enum cris_archs arch;
+{
+  switch (arch)
+    {
+    case arch_cris_any_v0_v10:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_warning
+	 || iver == cris_ver_v0_3
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v0_10
+	 || iver == cris_ver_sim_v0_10
+	 || iver == cris_ver_v3_10
+	 || iver == cris_ver_v8
+	 || iver == cris_ver_v8p
+	 || iver == cris_ver_v8_10
+	 || iver == cris_ver_v10
+	 || iver == cris_ver_v10p);
+      
+    case arch_crisv32:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v8p
+	 || iver == cris_ver_v10p
+	 || iver == cris_ver_v32p);
+
+    case arch_cris_common_v10_v32:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v8p
+	 || iver == cris_ver_v10p);
+
+    case arch_crisv0:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v0_3
+	 || iver == cris_ver_v0_10
+	 || iver == cris_ver_sim_v0_10);
+
+    case arch_crisv3:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v0_3
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v0_10
+	 || iver == cris_ver_sim_v0_10
+	 || iver == cris_ver_v3_10);
+
+    case arch_crisv8:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v0_10
+	 || iver == cris_ver_sim_v0_10
+	 || iver == cris_ver_v3_10
+	 || iver == cris_ver_v8
+	 || iver == cris_ver_v8p
+	 || iver == cris_ver_v8_10);
+
+    case arch_crisv10:
+      return
+	(iver == cris_ver_version_all
+	 || iver == cris_ver_v3p
+	 || iver == cris_ver_v0_10
+	 || iver == cris_ver_sim_v0_10
+	 || iver == cris_ver_v3_10
+	 || iver == cris_ver_v8p
+	 || iver == cris_ver_v8_10
+	 || iver == cris_ver_v10
+	 || iver == cris_ver_v10p);
+
+    default:
+      BAD_CASE (arch);
+   }
+}
+
+/* Assert that the .arch ARCHCHOICE1 is compatible with the specified or
+   default --march=<ARCHCHOICE2> option.  */
+
+static void
+s_cris_arch (dummy)
+     int dummy ATTRIBUTE_UNUSED;
+{
+  /* Right now we take the easy route and check for sameness.  It's not
+     obvious that allowing e.g. --march=v32 and .arch common_v0_v32
+     would be more useful than confusing, implementation-wise and
+     user-wise.  */
+
+  char *str = input_line_pointer;
+  enum cris_archs arch = cris_arch_from_string (&str);
+
+  if (arch == arch_cris_unknown)
+    {
+      as_bad (_("unknown operand to .arch"));
+
+      /* For this one, str does not reflect the end of the operand,
+	 since there was no matching arch.  Skip it manually; skip
+	 things that can be part of a word (a name).  */
+      while (is_part_of_name (*str))
+	str++;
+    }
+  else if (arch != cris_arch)
+    as_bad (_(".arch <arch> requires a matching --march=... option"));
+
+  input_line_pointer = str;
+  demand_empty_rest_of_line ();
+  return;
+}
+
 /*
  * Local variables:
  * eval: (c-set-style "gnu")
Index: gas/config/tc-cris.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-cris.h,v
retrieving revision 1.10
diff -p -c -u -p -r1.10 tc-cris.h
--- gas/config/tc-cris.h	3 Nov 2004 01:54:24 -0000	1.10
+++ gas/config/tc-cris.h	4 Nov 2004 13:33:48 -0000
@@ -39,6 +39,9 @@ extern const char *cris_target_format PA
 
 #define TARGET_ARCH bfd_arch_cris
 
+extern unsigned int cris_mach PARAMS ((void));
+#define TARGET_MACH (cris_mach ())
+
 #define TARGET_BYTES_BIG_ENDIAN 0
 
 extern const char *md_shortopts;
Index: gas/doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.107
diff -p -c -u -p -r1.107 as.texinfo
--- gas/doc/as.texinfo	11 Oct 2004 16:39:34 -0000	1.107
+++ gas/doc/as.texinfo	4 Nov 2004 13:33:52 -0000
@@ -276,6 +276,7 @@ gcc(1), ld(1), and the Info entries for 
    [@b{--underscore} | @b{--no-underscore}]
    [@b{--pic}] [@b{-N}]
    [@b{--emulation=criself} | @b{--emulation=crisaout}]
+   [@b{--march=v0_v10} | @b{--march=v10} | @b{--march=v32} | @b{--march=common_v10_v32}]
 @c Deprecated -- deliberately not documented.
 @c [@b{-h}] [@b{-H}]
 @end ifset
Index: gas/doc/c-cris.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-cris.texi,v
retrieving revision 1.2
diff -p -c -u -p -r1.2 c-cris.texi
--- gas/doc/c-cris.texi	21 Mar 2004 23:50:38 -0000	1.2
+++ gas/doc/c-cris.texi	4 Nov 2004 13:33:53 -0000
@@ -16,6 +16,7 @@
 @menu
 * CRIS-Opts::              Command-line Options
 * CRIS-Expand::            Instruction expansion
+* CRIS-Symbols::           Symbols
 * CRIS-Syntax::            Syntax
 @end menu
 
@@ -68,6 +69,39 @@ affect expansion of instructions.  The e
 @option{--pic} will use PC-relative rather than (slightly
 faster) absolute addresses in those expansions.
 
+@cindex @option{--march=@var{architecture}} command line option, CRIS
+@cindex CRIS @option{--march=@var{architecture}} command line option
+@cindex Architecture variant option, CRIS
+@cindex CRIS architecture variant option
+The option @option{--march=@var{architecture}}
+@anchor{march-option}specifies the recognized instruction set
+and recognized register names.  It also controls the
+architecture type of the object file.  Valid values for
+@var{architecture} are:
+@table @code
+
+@item v0_v10
+All instructions and register names for any architecture variant
+in the set v0@dots{}v10 are recognized.  This is the
+default if the target is configured as cris-*.
+
+@item v10
+Only instructions and register names for CRIS v10 (as found in
+ETRAX 100 LX) are recognized.  This is the default if the target
+is configured as crisv10-*.
+
+@item v32
+Only instructions and register names for CRIS v32 (code name
+Guinness) are recognized.  This is the default if the target is
+configured as crisv32-*.  This value implies
+@option{--no-mul-bug-abort}.  (A subsequent
+@option{--mul-bug-abort} will turn it back on.)
+
+@item common_v10_v32
+Only instructions with register names and addressing modes with
+opcodes common to the v10 and v32 are recognized.
+@end table
+
 @cindex @option{-N} command line option, CRIS
 @cindex CRIS @option{-N} command line option
 When @option{-N} is specified, @code{@value{AS}} will emit a
@@ -113,6 +147,59 @@ full 32-bit address.  Since this does no
 instruction, such expansions can optionally be warned about.
 @xref{CRIS-Opts}.
 
+If the operand is found to fit the range, a @code{lapc} mnemonic
+will translate to a @code{lapcq} instruction.  Use @code{lapc.d}
+to force the 32-bit @code{lapc} instruction.
+
+Similarly, the @code{addo} mnemonic will translate to the
+shortest fitting instruction of @code{addoq}, @code{addo.w} and
+@code{addo.d}, when used with a operand that is a constant known
+at assembly time.
+
+@node CRIS-Symbols
+@section Symbols
+@cindex Symbols, built-in, CRIS
+@cindex Symbols, CRIS, built-in
+@cindex CRIS built-in symbols
+@cindex Built-in symbols, CRIS
+
+Some symbols are defined by the assembler.  They're intended to
+be used in conditional assembly, for example:
+@smallexample
+ .if ..asm.arch.cris.v32
+ @var{code for CRIS v32}
+ .elseif ..asm.arch.cris.common_v10_v32
+ @var{code common to CRIS v32 and CRIS v10}
+ .elseif ..asm.arch.cris.v10 | ..asm.arch.cris.any_v0_v10
+ @var{code for v10}
+ .else
+ .error "Code needs to be added here."
+ .endif
+@end smallexample
+
+These symbols are defined in the assembler, reflecting
+command-line options, either when specified or the default.
+They are always defined, to 0 or 1.
+@table @code
+
+@item ..asm.arch.cris.any_v0_v10
+This symbol is non-zero when @option{--march=v0_v10} is specified
+or the default.
+
+@item ..asm.arch.cris.common_v10_v32
+Set according to the option @option{--march=common_v10_v32}.
+
+@item ..asm.arch.cris.v10
+Reflects the option @option{--march=v10}.
+
+@item ..asm.arch.cris.v32
+Corresponds to @option{--march=v10}.
+@end table
+
+Speaking of symbols, when a symbol is used in code, it can have
+a suffix modifying its value for use in position-independent
+code. @xref{CRIS-Pic}.
+
 @node CRIS-Syntax
 @section Syntax
 
@@ -147,7 +234,8 @@ separate instructions can be specified o
 @cindex Position-independent code, symbols in, CRIS
 
 When generating @anchor{crispic}position-independent code (SVR4
-PIC) for use in cris-axis-linux-gnu shared libraries, symbol
+PIC) for use in cris-axis-linux-gnu or crisv32-axis-linux-gnu
+shared libraries, symbol
 suffixes are used to specify what kind of run-time symbol lookup
 will be used, expressed in the object as different
 @emph{relocation types}.  Usually, all absolute symbol values
@@ -271,7 +359,7 @@ each expression, a 32-bit little-endian 
 @cindex pseudo-op .syntax, CRIS
 @cindex CRIS assembler directive .syntax
 @cindex CRIS pseudo-op .syntax
-The @code{.syntax} directive takes as ARGUMENT one of the
+The @code{.syntax} directive takes as @var{ARGUMENT} one of the
 following case-sensitive choices.
 
 @table @code
@@ -305,6 +393,16 @@ directive and emits an error if the opti
 is in effect.
 @end table
 
+@item .arch ARGUMENT
+@cindex assembler directive .arch, CRIS
+@cindex pseudo-op .arch, CRIS
+@cindex CRIS assembler directive .arch
+@cindex CRIS pseudo-op .arch
+This is an assertion directive, giving an error if the specified
+@var{ARGUMENT} is not the same as the specified or default value
+for the @option{--march=@var{architecture}} option
+(@pxref{march-option}).
+
 @c If you compare with md_pseudo_table, you see that we don't
 @c document ".file" and ".loc" here.  This is because we're just
 @c wrapping the corresponding ELF function and emitting an error for
Index: include/elf/cris.h
===================================================================
RCS file: /cvs/src/src/include/elf/cris.h,v
retrieving revision 1.4
diff -p -c -u -p -r1.4 cris.h
--- include/elf/cris.h	22 Mar 2001 13:03:58 -0000	1.4
+++ include/elf/cris.h	4 Nov 2004 13:33:57 -0000
@@ -98,4 +98,16 @@ END_RELOC_NUMBERS (R_CRIS_max)
 /* User symbols in this file have a leading underscore.  */
 #define EF_CRIS_UNDERSCORE		0x00000001
 
+/* This is a mask for different incompatible machine variants.  */
+#define EF_CRIS_VARIANT_MASK		0x0000000e
+
+/* Variant 0; may contain v0..10 object.  */
+#define EF_CRIS_VARIANT_ANY_V0_V10	0x00000000
+
+/* Variant 1; contains v32 object.  */
+#define EF_CRIS_VARIANT_V32		0x00000002
+
+/* Variant 2; contains object compatible with v32 and v10.  */
+#define EF_CRIS_VARIANT_COMMON_V10_V32	0x00000004
+
 #endif /* _ELF_CRIS_H */
Index: include/opcode/cris.h
===================================================================
RCS file: /cvs/src/src/include/opcode/cris.h,v
retrieving revision 1.3
diff -p -c -u -p -r1.3 cris.h
--- include/opcode/cris.h	5 Apr 2001 19:35:17 -0000	1.3
+++ include/opcode/cris.h	4 Nov 2004 13:33:57 -0000
@@ -1,5 +1,5 @@
 /* cris.h -- Header file for CRIS opcode and register tables.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
    Contributed by Axis Communications AB, Lund, Sweden.
    Originally written for GAS 1.38.1 by Mikael Asker.
    Updated, BFDized and GNUified by Hans-Peter Nilsson.
@@ -38,15 +38,12 @@ Foundation, Inc., 59 Temple Place - Suit
    immediate operands.  */
 enum cris_insn_version_usage
 {
-  /* Any version. */
+  /* Any version.  */
   cris_ver_version_all=0,
 
   /* Indeterminate (intended for disassembly only, or obsolete).  */
   cris_ver_warning,
 
-  /* Simulator only (reserved).  */
-  cris_ver_sim,
-
   /* Only for v0..3 (Etrax 1..4).  */
   cris_ver_v0_3,
 
@@ -59,10 +56,28 @@ enum cris_insn_version_usage
   /* Only for v8 or higher (ETRAX 100, ETRAX 100 LX).  */
   cris_ver_v8p,
 
-  /* Only for v10 or higher (ETRAX 100 LX).
-     Of course some or all these of may change to cris_ver_v10p if/when
+  /* Only for v0..10.  FIXME: Not sure what to do with this.  */
+  cris_ver_sim_v0_10,
+
+  /* Only for v0..10.  */
+  cris_ver_v0_10,
+
+  /* Only for v3..10.  (ETRAX 4, ETRAX 100 and ETRAX 100 LX).  */
+  cris_ver_v3_10,
+
+  /* Only for v8..10 (ETRAX 100 and ETRAX 100 LX).  */
+  cris_ver_v8_10,
+
+  /* Only for v10 (ETRAX 100 LX) and same series.  */
+  cris_ver_v10,
+
+  /* Only for v10 (ETRAX 100 LX) and same series.  */
+  cris_ver_v10p,
+
+  /* Only for v32 or higher (codename GUINNESS).
+     Of course some or all these of may change to cris_ver_v32p if/when
      there's a new revision. */
-  cris_ver_v10p
+  cris_ver_v32p
 };
 
 
@@ -85,6 +100,25 @@ struct cris_spec_reg
 };
 extern const struct cris_spec_reg cris_spec_regs[];
 
+
+/* Support registers (kind of special too, but not named as such).  */
+struct cris_support_reg
+{
+  const char *const name;
+  unsigned int number;
+};
+extern const struct cris_support_reg cris_support_regs[];
+
+struct cris_cond15
+{
+  /* The name of the condition.  */
+  const char *const name;
+
+  /* What CPU version this condition name applies to.  */
+  enum cris_insn_version_usage applicable_version;
+};
+extern const struct cris_cond15 cris_conds15[];
+
 /* Opcode-dependent constants.  */
 #define AUTOINCR_BIT (0x04)
 
@@ -163,9 +197,28 @@ extern const char *const cris_cc_strings
 #define ADD_PC_INCR_OPCODE \
  (0xfa00 + (2 << 4) + AUTOINCR_BIT * 0x0100 + REG_PC)
 
+#define JUMP_PC_INCR_OPCODE_V32 (0x0DBF)
+
+/* BA DWORD (V32).  */
+#define BA_DWORD_OPCODE (0x0EBF)
+
 /* Nop.  */
 #define NOP_OPCODE (0x050F)
-#define NOP_Z_BITS (0xFAF0)
+#define NOP_Z_BITS (0xFFFF ^ NOP_OPCODE)
+
+#define NOP_OPCODE_V32 (0x05B0)
+#define NOP_Z_BITS_V32 (0xFFFF ^ NOP_OPCODE_V32)
+
+/* For the compatibility mode, let's use "MOVE R0,P0".  Doesn't affect
+   registers or flags.  Unfortunately shuts off interrupts for one cycle
+   for < v32, but there doesn't seem to be any alternative without that
+   effect.  */
+#define NOP_OPCODE_COMMON (0x630)
+#define NOP_OPCODE_ZBITS_COMMON (0xffff & ~NOP_OPCODE_COMMON)
+
+/* LAPC.D  */
+#define LAPC_DWORD_OPCODE (0x0D7F)
+#define LAPC_DWORD_Z_BITS (0x0fff & ~LAPC_DWORD_OPCODE)
 
 /* Structure of an opcode table entry.  */
 enum cris_imm_oprnd_size_type
@@ -179,7 +232,13 @@ enum cris_imm_oprnd_size_type
   /* Indicated by size of special register.  */
   SIZE_SPEC_REG,
 
-  /* Indicated by size field.  */
+  /* Indicated by size field, signed.  */
+  SIZE_FIELD_SIGNED,
+
+  /* Indicated by size field, unsigned.  */
+  SIZE_FIELD_UNSIGNED,
+
+  /* Indicated by size field, no sign implied.  */
   SIZE_FIELD
 };
 
Index: opcodes/cris-dis.c
===================================================================
RCS file: /cvs/src/src/opcodes/cris-dis.c,v
retrieving revision 1.8
diff -p -c -u -p -r1.8 cris-dis.c
--- opcodes/cris-dis.c	30 Nov 2002 08:39:46 -0000	1.8
+++ opcodes/cris-dis.c	4 Nov 2004 13:33:58 -0000
@@ -62,9 +62,24 @@ Foundation, Inc., 59 Temple Place - Suit
 
    FIXME: Make this optional later.  */
 #ifndef TRACE_CASE
-#define TRACE_CASE 1
+#define TRACE_CASE (disdata->trace_case)
 #endif
 
+enum cris_disass_family
+ { cris_dis_v0_v10, cris_dis_common_v10_v32, cris_dis_v32 };
+
+/* Stored in the disasm_info->private_data member.  */
+struct cris_disasm_data
+{
+  /* Whether to print something less confusing if we find something
+     matching a switch-construct.  */
+  bfd_boolean trace_case;
+
+  /* Whether this code is flagged as crisv32.  FIXME: Should be an enum
+     that includes "compatible".  */
+  enum cris_disass_family distype;
+};
+
 /* Value of first element in switch.  */
 static long case_offset = 0;
 
@@ -80,45 +95,99 @@ static long last_immediate = 0;
 static int number_of_bits
   PARAMS ((unsigned int));
 static char *format_hex
-  PARAMS ((unsigned long, char *));
+  PARAMS ((unsigned long, char *, struct cris_disasm_data *));
 static char *format_dec
   PARAMS ((long, char *, int));
 static char *format_reg
-  PARAMS ((int, char *, bfd_boolean));
+  PARAMS ((struct cris_disasm_data *, int, char *, bfd_boolean));
+static char *format_sup_reg
+  PARAMS ((unsigned int, char *, bfd_boolean));
 static int cris_constraint
-  PARAMS ((const char *, unsigned int, unsigned int));
+  PARAMS ((const char *, unsigned int, unsigned int,
+	   struct cris_disasm_data *));
 static unsigned bytes_to_skip
-  PARAMS ((unsigned int, const struct cris_opcode *));
+  PARAMS ((unsigned int, const struct cris_opcode *,
+	   enum cris_disass_family));
 static char *print_flags
-  PARAMS ((unsigned int, char *));
+  PARAMS ((struct cris_disasm_data *, unsigned int, char *));
 static void print_with_operands
   PARAMS ((const struct cris_opcode *, unsigned int, unsigned char *,
 	   bfd_vma, disassemble_info *, const struct cris_opcode *,
 	   unsigned int, unsigned char *, bfd_boolean));
 static const struct cris_spec_reg *spec_reg_info
-  PARAMS ((unsigned int));
+  PARAMS ((unsigned int, enum cris_disass_family));
 static int print_insn_cris_generic
   PARAMS ((bfd_vma, disassemble_info *, bfd_boolean));
 static int print_insn_cris_with_register_prefix
   PARAMS ((bfd_vma, disassemble_info *));
 static int print_insn_cris_without_register_prefix
   PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv32_with_register_prefix
+  PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv32_without_register_prefix
+  PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv10_v32_with_register_prefix
+  PARAMS ((bfd_vma, disassemble_info *));
+static int print_insn_crisv10_v32_without_register_prefix
+  PARAMS ((bfd_vma, disassemble_info *));
+static bfd_boolean cris_parse_disassembler_options
+  PARAMS ((disassemble_info *, enum cris_disass_family));
 static const struct cris_opcode *get_opcode_entry
-  PARAMS ((unsigned int, unsigned int));
+  PARAMS ((unsigned int, unsigned int, struct cris_disasm_data *));
+
+/* Parse disassembler options and store state in info.  FIXME: For the
+   time being, we abuse static variables.  */
+
+static bfd_boolean
+cris_parse_disassembler_options (info, distype)
+     disassemble_info *info;
+     enum cris_disass_family distype;
+{
+  struct cris_disasm_data *disdata;
+
+  info->private_data = calloc (1, sizeof (struct cris_disasm_data));
+  disdata = (struct cris_disasm_data *) info->private_data;
+  if (disdata == NULL)
+    return FALSE;
+
+  /* Default true.  */
+  disdata->trace_case
+    = (info->disassembler_options == NULL
+       || (strcmp (info->disassembler_options, "nocase") != 0));
+
+  disdata->distype = distype;
+  return TRUE;
+}
 
-/* Return the descriptor of a special register.
-   FIXME: Depend on a CPU-version specific argument when all machinery
-   is in place.  */
 
 static const struct cris_spec_reg *
-spec_reg_info (sreg)
+spec_reg_info (sreg, distype)
      unsigned int sreg;
+     enum cris_disass_family distype;
 {
   int i;
   for (i = 0; cris_spec_regs[i].name != NULL; i++)
     {
       if (cris_spec_regs[i].number == sreg)
-	return &cris_spec_regs[i];
+	{
+	  if (distype == cris_dis_v32)
+	    switch (cris_spec_regs[i].applicable_version)
+	      {
+	      case cris_ver_warning:
+	      case cris_ver_version_all:
+	      case cris_ver_v3p:
+	      case cris_ver_v8p:
+	      case cris_ver_v10p:
+	      case cris_ver_v32p:
+		/* No ambiguous sizes or register names with CRISv32.  */
+		if (cris_spec_regs[i].warning == NULL)
+		  return &cris_spec_regs[i];
+	      default:
+		;
+	      }
+	  else if (cris_spec_regs[i].applicable_version != cris_ver_v32p)
+	    return &cris_spec_regs[i];
+	}
     }
 
   return NULL;
@@ -141,9 +210,10 @@ number_of_bits (val)
 /* Get an entry in the opcode-table.  */
 
 static const struct cris_opcode *
-get_opcode_entry (insn, prefix_insn)
+get_opcode_entry (insn, prefix_insn, disdata)
      unsigned int insn;
      unsigned int prefix_insn;
+     struct cris_disasm_data *disdata;
 {
   /* For non-prefixed insns, we keep a table of pointers, indexed by the
      insn code.  Each entry is initialized when found to be NULL.  */
@@ -162,27 +232,45 @@ get_opcode_entry (insn, prefix_insn)
   /* Allocate and clear the opcode-table.  */
   if (opc_table == NULL)
     {
-      opc_table = xmalloc (65536 * sizeof (opc_table[0]));
+      opc_table = malloc (65536 * sizeof (opc_table[0]));
+      if (opc_table == NULL)
+	return NULL;
+
       memset (opc_table, 0, 65536 * sizeof (const struct cris_opcode *));
 
       dip_prefixes
-	= xmalloc (65536 * sizeof (const struct cris_opcode **));
+	= malloc (65536 * sizeof (const struct cris_opcode **));
+      if (dip_prefixes == NULL)
+	return NULL;
+
       memset (dip_prefixes, 0, 65536 * sizeof (dip_prefixes[0]));
 
       bdapq_m1_prefixes
-	= xmalloc (65536 * sizeof (const struct cris_opcode **));
+	= malloc (65536 * sizeof (const struct cris_opcode **));
+      if (bdapq_m1_prefixes == NULL)
+	return NULL;
+
       memset (bdapq_m1_prefixes, 0, 65536 * sizeof (bdapq_m1_prefixes[0]));
 
       bdapq_m2_prefixes
-	= xmalloc (65536 * sizeof (const struct cris_opcode **));
+	= malloc (65536 * sizeof (const struct cris_opcode **));
+      if (bdapq_m2_prefixes == NULL)
+	return NULL;
+
       memset (bdapq_m2_prefixes, 0, 65536 * sizeof (bdapq_m2_prefixes[0]));
 
       bdapq_m4_prefixes
-	= xmalloc (65536 * sizeof (const struct cris_opcode **));
+	= malloc (65536 * sizeof (const struct cris_opcode **));
+      if (bdapq_m4_prefixes == NULL)
+	return NULL;
+
       memset (bdapq_m4_prefixes, 0, 65536 * sizeof (bdapq_m4_prefixes[0]));
 
       rest_prefixes
-	= xmalloc (65536 * sizeof (const struct cris_opcode **));
+	= malloc (65536 * sizeof (const struct cris_opcode **));
+      if (rest_prefixes == NULL)
+	return NULL;
+
       memset (rest_prefixes, 0, 65536 * sizeof (rest_prefixes[0]));
     }
 
@@ -197,7 +285,7 @@ get_opcode_entry (insn, prefix_insn)
       const struct cris_opcode *popcodep
 	= (opc_table[prefix_insn] != NULL
 	   ? opc_table[prefix_insn]
-	   : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX));
+	   : get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata));
 
       if (popcodep == NULL)
 	return NULL;
@@ -254,6 +342,60 @@ get_opcode_entry (insn, prefix_insn)
 	{
 	  int level_of_match;
 
+	  if (disdata->distype == cris_dis_v32)
+	    {
+	      switch (opcodep->applicable_version)
+		{
+		case cris_ver_version_all:
+		  break;
+
+		case cris_ver_v0_3:
+		case cris_ver_v0_10:
+		case cris_ver_v3_10:
+		case cris_ver_sim_v0_10:
+		case cris_ver_v8_10:
+		case cris_ver_v10:
+		case cris_ver_warning:
+		  continue;
+
+		case cris_ver_v3p:
+		case cris_ver_v8p:
+		case cris_ver_v10p:
+		case cris_ver_v32p:
+		  break;
+
+		case cris_ver_v8:
+		  abort ();
+		default:
+		  abort ();
+		}
+	    }
+	  else
+	    {
+	      switch (opcodep->applicable_version)
+		{
+		case cris_ver_version_all:
+		case cris_ver_v0_3:
+		case cris_ver_v3p:
+		case cris_ver_v0_10:
+		case cris_ver_v8p:
+		case cris_ver_v8_10:
+		case cris_ver_v10:
+		case cris_ver_sim_v0_10:
+		case cris_ver_v10p:
+		case cris_ver_warning:
+		  break;
+
+		case cris_ver_v32p:
+		  continue;
+
+		case cris_ver_v8:
+		  abort ();
+		default:
+		  abort ();
+		}
+	    }
+
 	  /* We give a double lead for bits matching the template in
 	     cris_opcodes.  Not even, because then "move p8,r10" would
 	     be given 2 bits lead over "clear.d r10".  When there's a
@@ -265,7 +407,8 @@ get_opcode_entry (insn, prefix_insn)
 	      && ((level_of_match
 		   = cris_constraint (opcodep->args,
 				      insn,
-				      prefix_insn))
+				      prefix_insn,
+				      disdata))
 		  >= 0)
 	      && ((level_of_match
 		   += 2 * number_of_bits (opcodep->match
@@ -300,9 +443,10 @@ get_opcode_entry (insn, prefix_insn)
 /* Format number as hex with a leading "0x" into outbuffer.  */
 
 static char *
-format_hex (number, outbuffer)
+format_hex (number, outbuffer, disdata)
      unsigned long number;
      char *outbuffer;
+     struct cris_disasm_data *disdata;
 {
   /* Obfuscate to avoid warning on 32-bit host, but properly truncate
      negative numbers on >32-bit hosts.  */
@@ -337,7 +481,8 @@ format_dec (number, outbuffer, signedp)
 /* Format the name of the general register regno into outbuffer.  */
 
 static char *
-format_reg (regno, outbuffer_start, with_reg_prefix)
+format_reg (disdata, regno, outbuffer_start, with_reg_prefix)
+     struct cris_disasm_data *disdata;
      int regno;
      char *outbuffer_start;
      bfd_boolean with_reg_prefix;
@@ -350,7 +495,11 @@ format_reg (regno, outbuffer_start, with
   switch (regno)
     {
     case 15:
-      strcpy (outbuffer, "pc");
+      /* For v32, there is no context in which we output PC.  */
+      if (disdata->distype == cris_dis_v32)
+	strcpy (outbuffer, "acr");
+      else
+	strcpy (outbuffer, "pc");
       break;
 
     case 14:
@@ -365,15 +514,43 @@ format_reg (regno, outbuffer_start, with
   return outbuffer_start + strlen (outbuffer_start);
 }
 
+/* Format the name of a support register into outbuffer.  */
+
+static char *
+format_sup_reg (regno, outbuffer_start, with_reg_prefix)
+     unsigned int regno;
+     char *outbuffer_start;
+     bfd_boolean with_reg_prefix;
+{
+  char *outbuffer = outbuffer_start;
+  int i;
+
+  if (with_reg_prefix)
+    *outbuffer++ = REGISTER_PREFIX_CHAR;
+
+  for (i = 0; cris_support_regs[i].name != NULL; i++)
+    if (cris_support_regs[i].number == regno)
+      {
+	sprintf (outbuffer, "%s", cris_support_regs[i].name);
+	return outbuffer_start + strlen (outbuffer_start);
+      }
+
+  /* There's supposed to be register names covering all numbers, though
+     some may be generic names.  */
+  sprintf (outbuffer, "format_sup_reg-BUG");
+  return outbuffer_start + strlen (outbuffer_start);
+}
+
 /* Return -1 if the constraints of a bitwise-matched instruction say
    that there is no match.  Otherwise return a nonnegative number
    indicating the confidence in the match (higher is better).  */
 
 static int
-cris_constraint (cs, insn, prefix_insn)
+cris_constraint (cs, insn, prefix_insn, disdata)
      const char *cs;
      unsigned int insn;
      unsigned int prefix_insn;
+     struct cris_disasm_data *disdata;
 {
   int retval = 0;
   int tmp;
@@ -384,11 +561,17 @@ cris_constraint (cs, insn, prefix_insn)
     switch (*s)
       {
       case '!':
-	/* Do not recognize "pop" if there's a prefix.  */
-	if (prefix_insn != NO_CRIS_PREFIX)
+	/* Do not recognize "pop" if there's a prefix and then only for
+           v0..v10.  */
+	if (prefix_insn != NO_CRIS_PREFIX
+	    || disdata->distype != cris_dis_v0_v10)
 	  return -1;
 	break;
 
+      case 'U':
+	/* Not recognized at disassembly.  */
+	return -1;
+
       case 'M':
 	/* Size modifier for "clear", i.e. special register 0, 4 or 8.
 	   Check that it is one of them.  Only special register 12 could
@@ -416,6 +599,7 @@ cris_constraint (cs, insn, prefix_insn)
 
       case 's':
       case 'y':
+      case 'Y':
 	/* If this is a prefixed insn with postincrement (side-effect),
 	   the prefix must not be DIP.  */
 	if (prefix_insn != NO_CRIS_PREFIX)
@@ -423,7 +607,7 @@ cris_constraint (cs, insn, prefix_insn)
 	    if (insn & 0x400)
 	      {
 		const struct cris_opcode *prefix_opcodep
-		  = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
+		  = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
 
 		if (prefix_opcodep->match == DIP_OPCODE)
 		  return -1;
@@ -443,7 +627,7 @@ cris_constraint (cs, insn, prefix_insn)
 	  {
 	    /* Match the prefix insn to BDAPQ.  */
 	    const struct cris_opcode *prefix_opcodep
-	      = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX);
+	      = get_opcode_entry (prefix_insn, NO_CRIS_PREFIX, disdata);
 
 	    if (prefix_opcodep->match == BDAP_QUICK_OPCODE)
 	      {
@@ -456,7 +640,7 @@ cris_constraint (cs, insn, prefix_insn)
 		  {
 		    unsigned int spec_reg = (insn >> 12) & 15;
 		    const struct cris_spec_reg *sregp
-		      = spec_reg_info (spec_reg);
+		      = spec_reg_info (spec_reg, disdata->distype);
 
 		    /* For a special-register, the "prefix size" must
 		       match the size of the register.  */
@@ -485,7 +669,7 @@ cris_constraint (cs, insn, prefix_insn)
       case 'P':
 	{
 	  const struct cris_spec_reg *sregp
-	    = spec_reg_info ((insn >> 12) & 15);
+	    = spec_reg_info ((insn >> 12) & 15, disdata->distype);
 
 	  /* Since we match four bits, we will give a value of 4-1 = 3
 	     in a match.  If there is a corresponding exact match of a
@@ -518,9 +702,10 @@ cris_constraint (cs, insn, prefix_insn)
 /* Return the length of an instruction.  */
 
 static unsigned
-bytes_to_skip (insn, matchedp)
+bytes_to_skip (insn, matchedp, distype)
      unsigned int insn;
      const struct cris_opcode *matchedp;
+     enum cris_disass_family distype;
 {
   /* Each insn is a word plus "immediate" operands.  */
   unsigned to_skip = 2;
@@ -528,7 +713,8 @@ bytes_to_skip (insn, matchedp)
   const char *s;
 
   for (s = template; *s; s++)
-    if (*s == 's' && (insn & 0x400) && (insn & 15) == 15)
+    if ((*s == 's' || *s == 'N' || *s == 'Y')
+	&& (insn & 0x400) && (insn & 15) == 15)
       {
 	/* Immediate via [pc+], so we have to check the size of the
 	   operand.  */
@@ -539,19 +725,24 @@ bytes_to_skip (insn, matchedp)
 	else if (matchedp->imm_oprnd_size == SIZE_SPEC_REG)
 	  {
 	    const struct cris_spec_reg *sregp
-	      = spec_reg_info ((insn >> 12) & 15);
+	      = spec_reg_info ((insn >> 12) & 15, distype);
 
 	    /* FIXME: Improve error handling; should have been caught
 	       earlier.  */
 	    if (sregp == NULL)
 	      return 2;
 
-	    /* PC is incremented by two, not one, for a byte.  */
-	    to_skip += (sregp->reg_size + 1) & ~1;
+	    /* PC is incremented by two, not one, for a byte.  Except on
+	       CRISv32, where constants are always DWORD-size for
+	       special registers.  */
+	    to_skip +=
+	      distype == cris_dis_v32 ? 4 : (sregp->reg_size + 1) & ~1;
 	  }
 	else
 	  to_skip += (mode_size + 1) & ~1;
       }
+    else if (*s == 'n')
+      to_skip += 4;
     else if (*s == 'b')
       to_skip += 2;
 
@@ -561,15 +752,20 @@ bytes_to_skip (insn, matchedp)
 /* Print condition code flags.  */
 
 static char *
-print_flags (insn, cp)
+print_flags (disdata, insn, cp)
+     struct cris_disasm_data *disdata;
      unsigned int insn;
      char *cp;
 {
   /* Use the v8 (Etrax 100) flag definitions for disassembly.
      The differences with v0 (Etrax 1..4) vs. Svinto are:
-     v0 'd' <=> v8 'm'
-     v0 'e' <=> v8 'b'.  */
-  static const char fnames[] = "cvznxibm";
+      v0 'd' <=> v8 'm'
+      v0 'e' <=> v8 'b'.
+     FIXME: Emit v0..v3 flag names somehow.  */
+  static const char v8_fnames[] = "cvznxibm";
+  static const char v32_fnames[] = "cvznxiup";
+  const char *fnames
+    = disdata->distype == cris_dis_v32 ? v32_fnames : v8_fnames;
 
   unsigned char flagbits = (((insn >> 8) & 0xf0) | (insn & 15));
   int i;
@@ -608,6 +804,8 @@ print_with_operands (opcodep, insn, buff
   static const char mode_char[] = "bwd?";
   const char *s;
   const char *cs;
+  struct cris_disasm_data *disdata
+    = (struct cris_disasm_data *) info->private_data;
 
   /* Print out the name first thing we do.  */
   (*info->fprintf_func) (info->stream, "%s", opcodep->name);
@@ -658,14 +856,33 @@ print_with_operands (opcodep, insn, buff
     {
     switch (*s)
       {
+      case 'T':
+	tp = format_sup_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+	break;
+
+      case 'A':
+	if (with_reg_prefix)
+	  *tp++ = REGISTER_PREFIX_CHAR;
+	*tp++ = 'a';
+	*tp++ = 'c';
+	*tp++ = 'r';
+	break;
+	
+      case '[':
+      case ']':
       case ',':
 	*tp++ = *s;
 	break;
 
       case '!':
-	/* Ignore at this point; used at earlier stages to avoid recognition
-	   if there's a prefixes at something that in other ways looks like
-	   a "pop".  */
+	/* Ignore at this point; used at earlier stages to avoid
+	   recognition if there's a prefix at something that in other
+	   ways looks like a "pop".  */
+	break;
+
+      case 'd':
+	/* Ignore.  This is an optional ".d " on the large one of
+	   relaxable insns.  */
 	break;
 
       case 'B':
@@ -677,14 +894,48 @@ print_with_operands (opcodep, insn, buff
 
       case 'D':
       case 'r':
-	tp = format_reg (insn & 15, tp, with_reg_prefix);
+	tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
 	break;
 
       case 'R':
-	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
+	break;
+
+      case 'n':
+	{
+	  /* Like N but pc-relative to the start of the insn.  */
+	  unsigned long number
+	    = (buffer[2] + buffer[3] * 256 + buffer[4] * 65536
+	       + buffer[5] * 0x1000000 + addr);
+
+	  /* Finish off and output previous formatted bytes.  */
+	  *tp = 0;
+	  if (temp[0])
+	    (*info->fprintf_func) (info->stream, "%s", temp);
+	  tp = temp;
+
+	  (*info->print_address_func) ((bfd_vma) number, info);
+	}
+	break;
+
+      case 'u':
+	{
+	  /* Like n but the offset is bits <3:0> in the instruction.  */
+	  unsigned long number = (buffer[0] & 0xf) * 2 + addr;
+
+	  /* Finish off and output previous formatted bytes.  */
+	  *tp = 0;
+	  if (temp[0])
+	    (*info->fprintf_func) (info->stream, "%s", temp);
+	  tp = temp;
+
+	  (*info->print_address_func) ((bfd_vma) number, info);
+	}
 	break;
 
+      case 'N':
       case 'y':
+      case 'Y':
       case 'S':
       case 's':
 	/* Any "normal" memory operand.  */
@@ -703,7 +954,7 @@ print_with_operands (opcodep, insn, buff
 	    else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
 	      {
 		const struct cris_spec_reg *sregp
-		  = spec_reg_info ((insn >> 12) & 15);
+		  = spec_reg_info ((insn >> 12) & 15, disdata->distype);
 
 		/* A NULL return should have been as a non-match earlier,
 		   so catch it as an internal error in the error-case
@@ -712,8 +963,11 @@ print_with_operands (opcodep, insn, buff
 		  /* Whatever non-valid size.  */
 		  nbytes = 42;
 		else
-		  /* PC is always incremented by a multiple of two.  */
-		  nbytes = (sregp->reg_size + 1) & ~1;
+		  /* PC is always incremented by a multiple of two.
+		     For CRISv32, immediates are always 4 bytes for
+		     special registers.  */
+		  nbytes = disdata->distype == cris_dis_v32
+		    ? 4 : (sregp->reg_size + 1) & ~1;
 	      }
 	    else
 	      {
@@ -781,7 +1035,7 @@ print_with_operands (opcodep, insn, buff
 		    info->target = number;
 		  }
 		else
-		  tp = format_hex (number, tp);
+		  tp = format_hex (number, tp, disdata);
 	      }
 	  }
 	else
@@ -802,7 +1056,7 @@ print_with_operands (opcodep, insn, buff
 		else if (opcodep->imm_oprnd_size == SIZE_SPEC_REG)
 		  {
 		    const struct cris_spec_reg *sregp
-		      = spec_reg_info ((insn >> 12) & 15);
+		      = spec_reg_info ((insn >> 12) & 15, disdata->distype);
 
 		    /* FIXME: Improve error handling; should have been caught
 		       earlier.  */
@@ -827,7 +1081,7 @@ print_with_operands (opcodep, insn, buff
 	      {
 		if (insn & 0x400)
 		  {
-		    tp = format_reg (insn & 15, tp, with_reg_prefix);
+		    tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
 		    *tp++ = '=';
 		  }
 
@@ -869,7 +1123,7 @@ print_with_operands (opcodep, insn, buff
 			info->target2 = prefix_insn & 15;
 
 			*tp++ = '[';
-			tp = format_reg (prefix_insn & 15, tp,
+			tp = format_reg (disdata, prefix_insn & 15, tp,
 					 with_reg_prefix);
 			if (prefix_insn & 0x400)
 			  *tp++ = '+';
@@ -886,7 +1140,7 @@ print_with_operands (opcodep, insn, buff
 			number -= 256;
 
 		      /* Output "reg+num" or, if num < 0, "reg-num".  */
-		      tp = format_reg ((prefix_insn >> 12) & 15, tp,
+		      tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
 				       with_reg_prefix);
 		      if (number >= 0)
 			*tp++ = '+';
@@ -900,9 +1154,10 @@ print_with_operands (opcodep, insn, buff
 
 		  case BIAP_OPCODE:
 		    /* Output "r+R.m".  */
-		    tp = format_reg (prefix_insn & 15, tp, with_reg_prefix);
+		    tp = format_reg (disdata, prefix_insn & 15, tp,
+				     with_reg_prefix);
 		    *tp++ = '+';
-		    tp = format_reg ((prefix_insn >> 12) & 15, tp,
+		    tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
 				     with_reg_prefix);
 		    *tp++ = '.';
 		    *tp++ = mode_char[(prefix_insn >> 4) & 3];
@@ -925,7 +1180,7 @@ print_with_operands (opcodep, insn, buff
 		  case BDAP_INDIR_OPCODE:
 		    /* Output "r+s.m", or, if "s" is [pc+], "r+s" or
 		       "r-s".  */
-		    tp = format_reg ((prefix_insn >> 12) & 15, tp,
+		    tp = format_reg (disdata, (prefix_insn >> 12) & 15, tp,
 				     with_reg_prefix);
 
 		    if ((prefix_insn & 0x400) && (prefix_insn & 15) == 15)
@@ -996,7 +1251,7 @@ print_with_operands (opcodep, insn, buff
 			/* Output "r+[R].m" or "r+[R+].m".  */
 			*tp++ = '+';
 			*tp++ = '[';
-			tp = format_reg (prefix_insn & 15, tp,
+			tp = format_reg (disdata, prefix_insn & 15, tp,
 					 with_reg_prefix);
 			if (prefix_insn & 0x400)
 			  *tp++ = '+';
@@ -1026,7 +1281,7 @@ print_with_operands (opcodep, insn, buff
 	      }
 	    else
 	      {
-		tp = format_reg (insn & 15, tp, with_reg_prefix);
+		tp = format_reg (disdata, insn & 15, tp, with_reg_prefix);
 
 		info->flags |= CRIS_DIS_FLAG_MEM_TARGET_IS_REG;
 		info->target = insn & 15;
@@ -1039,7 +1294,7 @@ print_with_operands (opcodep, insn, buff
 	break;
 
       case 'x':
-	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
 	*tp++ = '.';
 	*tp++ = mode_char[(insn >> 4) & 3];
 	break;
@@ -1055,7 +1310,7 @@ print_with_operands (opcodep, insn, buff
 	  if (where > 32767)
 	    where -= 65536;
 
-	  where += addr + 4;
+	  where += addr + ((disdata->distype == cris_dis_v32) ? 0 : 4);
 
 	  if (insn == BA_PC_INCR_OPCODE)
 	    info->insn_type = dis_branch;
@@ -1084,6 +1339,7 @@ print_with_operands (opcodep, insn, buff
     case 'o':
       {
 	long offset = insn & 0xfe;
+	bfd_vma target;
 
 	if (insn & 1)
 	  offset |= ~0xff;
@@ -1093,15 +1349,16 @@ print_with_operands (opcodep, insn, buff
 	else
 	  info->insn_type = dis_condbranch;
 
-	info->target = (bfd_vma) (addr + 2 + offset);
+	target = addr + ((disdata->distype == cris_dis_v32) ? 0 : 2) + offset;
+	info->target = target;
 	*tp = 0;
 	tp = temp;
 	(*info->fprintf_func) (info->stream, "%s", temp);
-
-	(*info->print_address_func) ((bfd_vma) (addr + 2 + offset), info);
+	(*info->print_address_func) (target, info);
       }
       break;
 
+    case 'Q':
     case 'O':
       {
 	long number = buffer[0];
@@ -1111,12 +1368,12 @@ print_with_operands (opcodep, insn, buff
 
 	tp = format_dec (number, tp, 1);
 	*tp++ = ',';
-	tp = format_reg ((insn >> 12) & 15, tp, with_reg_prefix);
+	tp = format_reg (disdata, (insn >> 12) & 15, tp, with_reg_prefix);
       }
       break;
 
     case 'f':
-      tp = print_flags (insn, tp);
+      tp = print_flags (disdata, insn, tp);
       break;
 
     case 'i':
@@ -1126,7 +1383,7 @@ print_with_operands (opcodep, insn, buff
     case 'P':
       {
 	const struct cris_spec_reg *sregp
-	  = spec_reg_info ((insn >> 12) & 15);
+	  = spec_reg_info ((insn >> 12) & 15, disdata->distype);
 
 	if (sregp->name == NULL)
 	  /* Should have been caught as a non-match eariler.  */
@@ -1198,6 +1455,8 @@ print_insn_cris_generic (memaddr, info, 
   unsigned int insn;
   const struct cris_opcode *matchedp;
   int advance = 0;
+  struct cris_disasm_data *disdata
+    = (struct cris_disasm_data *) info->private_data;
 
   /* No instruction will be disassembled as longer than this number of
      bytes; stacked prefixes will not be expanded.  */
@@ -1276,7 +1535,9 @@ print_insn_cris_generic (memaddr, info, 
 	     valid "bcc .+2" insn, it is also useless enough and enough
 	     of a nuiscance that we will just output "bcc .+2" for it
 	     and signal it as a noninsn.  */
-	  (*info->fprintf_func) (info->stream, "bcc .+2");
+	  (*info->fprintf_func) (info->stream,
+				 disdata->distype == cris_dis_v32
+				 ? "bcc ." : "bcc .+2");
 	  info->insn_type = dis_noninsn;
 	  advance += 2;
 	}
@@ -1287,7 +1548,7 @@ print_insn_cris_generic (memaddr, info, 
 	  unsigned int prefix_insn = insn;
 	  int prefix_size = 0;
 
-	  matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX);
+	  matchedp = get_opcode_entry (insn, NO_CRIS_PREFIX, disdata);
 
 	  /* Check if we're supposed to write out prefixes as address
 	     modes and if this was a prefix.  */
@@ -1295,11 +1556,12 @@ print_insn_cris_generic (memaddr, info, 
 	    {
 	      /* If it's a prefix, put it into the prefix vars and get the
 		 main insn.  */
-	      prefix_size = bytes_to_skip (prefix_insn, matchedp);
+	      prefix_size = bytes_to_skip (prefix_insn, matchedp,
+					   disdata->distype);
 	      prefix_opcodep = matchedp;
 
 	      insn = bufp[prefix_size] + bufp[prefix_size + 1] * 256;
-	      matchedp = get_opcode_entry (insn, prefix_insn);
+	      matchedp = get_opcode_entry (insn, prefix_insn, disdata);
 
 	      if (matchedp != NULL)
 		{
@@ -1327,7 +1589,7 @@ print_insn_cris_generic (memaddr, info, 
 	    }
 	  else
 	    {
-	      advance += bytes_to_skip (insn, matchedp);
+	      advance += bytes_to_skip (insn, matchedp, disdata->distype);
 
 	      /* The info_type and assorted fields will be set according
 		 to the operands.   */
@@ -1368,28 +1630,90 @@ print_insn_cris_generic (memaddr, info, 
   return advance;
 }
 
-/* Disassemble, prefixing register names with `$'.  */
+/* Disassemble, prefixing register names with `$'.  CRIS v0..v10.  */
 
 static int
 print_insn_cris_with_register_prefix (vma, info)
      bfd_vma vma;
      disassemble_info *info;
 {
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+    return -1;
+  return print_insn_cris_generic (vma, info, TRUE);
+}
+
+/* Disassemble, prefixing register names with `$'.  CRIS v32.  */
+
+static int
+print_insn_crisv32_with_register_prefix (vma, info)
+     bfd_vma vma;
+     disassemble_info *info;
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, TRUE);
+}
+
+/* Disassemble, prefixing register names with `$'.
+   Common v10 and v32 subset.  */
+
+static int
+print_insn_crisv10_v32_with_register_prefix (vma, info)
+     bfd_vma vma;
+     disassemble_info *info;
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+    return -1;
   return print_insn_cris_generic (vma, info, TRUE);
 }
 
-/* Disassemble, no prefixes on register names.  */
+/* Disassemble, no prefixes on register names.  CRIS v0..v10.  */
 
 static int
 print_insn_cris_without_register_prefix (vma, info)
      bfd_vma vma;
      disassemble_info *info;
 {
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v0_v10))
+    return -1;
+  return print_insn_cris_generic (vma, info, FALSE);
+}
+
+/* Disassemble, no prefixes on register names.  CRIS v32.  */
+
+static int
+print_insn_crisv32_without_register_prefix (vma, info)
+     bfd_vma vma;
+     disassemble_info *info;
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_v32))
+    return -1;
+  return print_insn_cris_generic (vma, info, FALSE);
+}
+
+/* Disassemble, no prefixes on register names.
+   Common v10 and v32 subset.  */
+
+static int
+print_insn_crisv10_v32_without_register_prefix (vma, info)
+     bfd_vma vma;
+     disassemble_info *info;
+{
+  if (info->private_data == NULL
+      && !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
+    return -1;
   return print_insn_cris_generic (vma, info, FALSE);
 }
 
 /* Return a disassembler-function that prints registers with a `$' prefix,
-   or one that prints registers without a prefix.  */
+   or one that prints registers without a prefix.
+   FIXME: We should improve the solution to avoid the multitude of
+   functions seen above.  */
 
 disassembler_ftype
 cris_get_disassembler (abfd)
@@ -1397,10 +1721,26 @@ cris_get_disassembler (abfd)
 {
   /* If there's no bfd in sight, we return what is valid as input in all
      contexts if fed back to the assembler: disassembly *with* register
-     prefix.  */
-  if (abfd == NULL || bfd_get_symbol_leading_char (abfd) == 0)
+     prefix.  Unfortunately this will be totally wrong for v32.  */
+  if (abfd == NULL)
     return print_insn_cris_with_register_prefix;
 
+  if (bfd_get_symbol_leading_char (abfd) == 0)
+    {
+      if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+	return print_insn_crisv32_with_register_prefix;
+      if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+	return print_insn_crisv10_v32_with_register_prefix;
+
+      /* We default to v10.  This may be specifically specified in the
+	 bfd mach, but is also the default setting.  */
+      return print_insn_cris_with_register_prefix;
+    }
+
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+    return print_insn_crisv32_without_register_prefix;
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v10_v32)
+    return print_insn_crisv10_v32_without_register_prefix;
   return print_insn_cris_without_register_prefix;
 }
 
Index: opcodes/cris-opc.c
===================================================================
RCS file: /cvs/src/src/opcodes/cris-opc.c,v
retrieving revision 1.3
diff -p -c -u -p -r1.3 cris-opc.c
--- opcodes/cris-opc.c	18 May 2001 15:21:59 -0000	1.3
+++ opcodes/cris-opc.c	4 Nov 2004 13:33:58 -0000
@@ -26,19 +26,30 @@ Foundation, Inc., 59 Temple Place - Suit
 #define NULL (0)
 #endif
 
+/* This table isn't used for CRISv32 and the size of immediate operands.  */
 const struct cris_spec_reg
 cris_spec_regs[] =
 {
+  {"bz",  0,  1, cris_ver_v32p,	   NULL},
   {"p0",  0,  1, 0,		   NULL},
   {"vr",  1,  1, 0,		   NULL},
   {"p1",  1,  1, 0,		   NULL},
+  {"pid", 2,  1, cris_ver_v32p,    NULL},
+  {"p2",  2,  1, cris_ver_v32p,	   NULL},
   {"p2",  2,  1, cris_ver_warning, NULL},
+  {"srs", 3,  1, cris_ver_v32p,    NULL},
+  {"p3",  3,  1, cris_ver_v32p,	   NULL},
   {"p3",  3,  1, cris_ver_warning, NULL},
+  {"wz",  4,  2, cris_ver_v32p,	   NULL},
   {"p4",  4,  2, 0,		   NULL},
-  {"ccr", 5,  2, 0,		   NULL},
-  {"p5",  5,  2, 0,		   NULL},
+  {"ccr", 5,  2, cris_ver_v0_10,   NULL},
+  {"exs", 5,  4, cris_ver_v32p,	   NULL},
+  {"p5",  5,  2, cris_ver_v0_10,   NULL},
+  {"p5",  5,  4, cris_ver_v32p,	   NULL},
   {"dcr0",6,  2, cris_ver_v0_3,	   NULL},
+  {"eda", 6,  4, cris_ver_v32p,	   NULL},
   {"p6",  6,  2, cris_ver_v0_3,	   NULL},
+  {"p6",  6,  4, cris_ver_v32p,	   NULL},
   {"dcr1/mof", 7, 4, cris_ver_v10p,
    "Register `dcr1/mof' with ambiguous size specified.  Guessing 4 bytes"},
   {"dcr1/mof", 7, 2, cris_ver_v0_3,
@@ -47,32 +58,63 @@ cris_spec_regs[] =
   {"dcr1",7,  2, cris_ver_v0_3,	   NULL},
   {"p7",  7,  4, cris_ver_v10p,	   NULL},
   {"p7",  7,  2, cris_ver_v0_3,	   NULL},
+  {"dz",  8,  4, cris_ver_v32p,	   NULL},
   {"p8",  8,  4, 0,		   NULL},
-  {"ibr", 9,  4, 0,		   NULL},
+  {"ibr", 9,  4, cris_ver_v0_10,   NULL},
+  {"ebp", 9,  4, cris_ver_v32p,	   NULL},
   {"p9",  9,  4, 0,		   NULL},
-  {"irp", 10, 4, 0,		   NULL},
+  {"irp", 10, 4, cris_ver_v0_10,   NULL},
+  {"erp", 10, 4, cris_ver_v32p,	   NULL},
   {"p10", 10, 4, 0,		   NULL},
   {"srp", 11, 4, 0,		   NULL},
   {"p11", 11, 4, 0,		   NULL},
   /* For disassembly use only.  Accept at assembly with a warning.  */
   {"bar/dtp0", 12, 4, cris_ver_warning,
    "Ambiguous register `bar/dtp0' specified"},
-  {"bar", 12, 4, cris_ver_v8p,	   NULL},
+  {"nrp", 12, 4, cris_ver_v32p,	   NULL},
+  {"bar", 12, 4, cris_ver_v8_10,   NULL},
   {"dtp0",12, 4, cris_ver_v0_3,	   NULL},
   {"p12", 12, 4, 0,		   NULL},
   /* For disassembly use only.  Accept at assembly with a warning.  */
   {"dccr/dtp1",13, 4, cris_ver_warning,
    "Ambiguous register `dccr/dtp1' specified"},
-  {"dccr",13, 4, cris_ver_v8p,	   NULL},
+  {"ccs", 13, 4, cris_ver_v32p,	   NULL},
+  {"dccr",13, 4, cris_ver_v8_10,   NULL},
   {"dtp1",13, 4, cris_ver_v0_3,	   NULL},
   {"p13", 13, 4, 0,		   NULL},
-  {"brp", 14, 4, cris_ver_v3p,	   NULL},
+  {"brp", 14, 4, cris_ver_v3_10,   NULL},
+  {"usp", 14, 4, cris_ver_v32p,	   NULL},
   {"p14", 14, 4, cris_ver_v3p,	   NULL},
-  {"usp", 15, 4, cris_ver_v10p,	   NULL},
+  {"usp", 15, 4, cris_ver_v10,	   NULL},
+  {"spc", 15, 4, cris_ver_v32p,	   NULL},
   {"p15", 15, 4, cris_ver_v10p,	   NULL},
   {NULL, 0, 0, cris_ver_version_all, NULL}
 };
 
+/* Add version specifiers to this table when necessary.
+   The (now) regular coding of register names suggests a simpler
+   implementation.  */
+const struct cris_support_reg cris_support_regs[] =
+{
+  {"s0", 0},
+  {"s1", 1},
+  {"s2", 2},
+  {"s3", 3},
+  {"s4", 4},
+  {"s5", 5},
+  {"s6", 6},
+  {"s7", 7},
+  {"s8", 8},
+  {"s9", 9},
+  {"s10", 10},
+  {"s11", 11},
+  {"s12", 12},
+  {"s13", 13},
+  {"s14", 14},
+  {"s15", 15},
+  {NULL, 0}
+};
+
 /* All CRIS opcodes are 16 bits.
 
    - The match component is a mask saying which bits must match a
@@ -84,43 +126,61 @@ cris_spec_regs[] =
      and disassembly.
 
      Operand-matching characters:
+     [ ] , space
+        Verbatim.
+     A	The string "ACR" (case-insensitive).
      B	Not really an operand.  It causes a "BDAP -size,SP" prefix to be
-	output for the PUSH alias-instructions and recognizes a
-	push-prefix at disassembly.  Must be followed by a R or P letter.
+	output for the PUSH alias-instructions and recognizes a push-
+	prefix at disassembly.  This letter isn't recognized for v32.
+	Must be followed by a R or P letter.
      !	Non-match pattern, will not match if there's a prefix insn.
      b	Non-matching operand, used for branches with 16-bit
 	displacement. Only recognized by the disassembler.
      c	5-bit unsigned immediate in bits <4:0>.
      C	4-bit unsigned immediate in bits <3:0>.
+     d  At assembly, optionally (as in put other cases before this one)
+	".d" or ".D" at the start of the operands, followed by one space
+	character.  At disassembly, nothing.
      D	General register in bits <15:12> and <3:0>.
      f	List of flags in bits <15:12> and <3:0>.
      i	6-bit signed immediate in bits <5:0>.
      I	6-bit unsigned immediate in bits <5:0>.
      M	Size modifier (B, W or D) for CLEAR instructions.
      m	Size modifier (B, W or D) in bits <5:4>
+     N  A 32-bit dword, like in the difference between s and y.
+        This has no effect on bits in the opcode.  Can also be expressed
+	as "[pc+]" in input.
+     n  As N, but PC-relative (to the start of the instruction).
      o	[-128..127] word offset in bits <7:1> and <0>.  Used by 8-bit
 	branch instructions.
      O	[-128..127] offset in bits <7:0>.  Also matches a comma and a
-	general register after the expression.  Used only for the BDAP
-	prefix insn.
+	general register after the expression, in bits <15:12>.  Used
+	only for the BDAP prefix insn (in v32 the ADDOQ insn; same opcode).
      P	Special register in bits <15:12>.
      p	Indicates that the insn is a prefix insn.  Must be first
 	character.
+     Q  As O, but don't relax; force an 8-bit offset.
      R	General register in bits <15:12>.
      r	General register in bits <3:0>.
      S	Source operand in bit <10> and a prefix; a 3-operand prefix
 	without side-effect.
      s	Source operand in bits <10> and <3:0>, optionally with a
-	side-effect prefix.
+	side-effect prefix, except [pc] (the name, not R15 as in ACR)
+	isn't allowed for v32 and higher.
+     T  Support register in bits <15:12>.
+     u  4-bit (PC-relative) unsigned immediate word offset in bits <3:0>.
+     U  Relaxes to either u or n, instruction is assumed LAPCQ or LAPC.
+	Not recognized at disassembly.
      x	Register-dot-modifier, for example "r5.w" in bits <15:12> and <5:4>.
      y	Like 's' but do not allow an integer at assembly.
+     Y	The difference s-y; only an integer is allowed.
      z	Size modifier (B or W) in bit <4>.  */
 
 
 /* Please note the order of the opcodes in this table is significant.
    The assembler requires that all instances of the same mnemonic must
    be consecutive.  If they aren't, the assembler might not recognize
-   them, or may indicate and internal error.
+   them, or may indicate an internal error.
 
    The disassembler should not normally care about the order of the
    opcodes, but will prefer an earlier alternative if the "match-score"
@@ -142,40 +202,81 @@ cris_opcodes[] =
   {"add",     0x0A00, 0x01c0,		  "m s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"add",     0x0A00, 0x01c0,		  "m S,D",   0, SIZE_NONE,     0,
+  {"add",     0x0A00, 0x01c0,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"add",     0x0a00, 0x05c0,		  "m S,R,r", 0, SIZE_NONE,     0,
+  {"add",     0x0a00, 0x05c0,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
+  {"add",     0x0A00, 0x01c0,		  "m s,R",   0, SIZE_FIELD,
+   cris_ver_v32p,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"addc",    0x0570, 0x0A80,		  "r,R",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addc",    0x09A0, 0x0250,		  "s,R",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addi",    0x0540, 0x0A80,		  "x,r,A",   0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_addi_op},
+
   {"addi",    0x0500, 0x0Ac0,		  "x,r",     0, SIZE_NONE,     0,
    cris_addi_op},
 
+  /* This collates after "addo", but we want to disassemble as "addoq",
+     not "addo".  */
+  {"addoq",   0x0100, 0x0E00,		  "Q,A",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"addo",    0x0940, 0x0280,		  "m s,R,A", 0, SIZE_FIELD_SIGNED,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  /* This must be located after the insn above, lest we misinterpret
+     "addo.b -1,r0,acr" as "addo .b-1,r0,acr".  FIXME: Sounds like a
+     parser bug.  */
+  {"addo",   0x0100, 0x0E00,		  "O,A",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
   {"addq",    0x0200, 0x0Dc0,		  "I,R",     0, SIZE_NONE,     0,
    cris_quick_mode_add_sub_op},
 
   {"adds",    0x0420, 0x0Bc0,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
   {"adds",    0x0820, 0x03c0,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"adds",    0x0820, 0x03c0,		  "z S,D",   0, SIZE_NONE,     0,
+  {"adds",    0x0820, 0x03c0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"adds",    0x0820, 0x07c0,		  "z S,R,r", 0, SIZE_NONE,     0,
+  {"adds",    0x0820, 0x07c0,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"addu",    0x0400, 0x0be0,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
   {"addu",    0x0800, 0x03e0,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"addu",    0x0800, 0x03e0,		  "z S,D",   0, SIZE_NONE,     0,
+  {"addu",    0x0800, 0x03e0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"addu",    0x0800, 0x07e0,		  "z S,R,r", 0, SIZE_NONE,     0,
+  {"addu",    0x0800, 0x07e0,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"and",     0x0700, 0x08C0,		  "m r,R",   0, SIZE_NONE,     0,
@@ -184,10 +285,12 @@ cris_opcodes[] =
   {"and",     0x0B00, 0x00C0,		  "m s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"and",     0x0B00, 0x00C0,		  "m S,D",   0, SIZE_NONE,     0,
+  {"and",     0x0B00, 0x00C0,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"and",     0x0B00, 0x04C0,		  "m S,R,r", 0, SIZE_NONE,     0,
+  {"and",     0x0B00, 0x04C0,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"andq",    0x0300, 0x0CC0,		  "i,R",     0, SIZE_NONE,     0,
@@ -211,6 +314,21 @@ cris_opcodes[] =
    0x0F00+(0xF-CC_A)*0x1000,		  "o",	     1, SIZE_NONE,     0,
    cris_eight_bit_offset_branch_op},
 
+  /* Needs to come after the usual "ba o", which might be relaxed to
+     this one.  */
+  {"ba",     BA_DWORD_OPCODE,
+   0xffff & (~BA_DWORD_OPCODE),		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bas",     0x0EBF, 0x0140,		  "n,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"basc",     0x0EFF, 0x0100,		  "n,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
   {"bcc",
    BRANCH_QUICK_OPCODE+CC_CC*0x1000,
    0x0f00+(0xF-CC_CC)*0x1000,		  "o",	     1, SIZE_NONE,     0,
@@ -222,11 +340,13 @@ cris_opcodes[] =
    cris_eight_bit_offset_branch_op},
 
   {"bdap",
-   BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS,  "pm s,R",  0, SIZE_FIELD,    0,
+   BDAP_INDIR_OPCODE, BDAP_INDIR_Z_BITS,  "pm s,R",  0, SIZE_FIELD_SIGNED,
+   cris_ver_v0_10,
    cris_bdap_prefix},
 
   {"bdap",
-   BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS,  "pO",	     0, SIZE_NONE,     0,
+   BDAP_QUICK_OPCODE, BDAP_QUICK_Z_BITS,  "pO",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_quick_mode_bdap_prefix},
 
   {"beq",
@@ -235,11 +355,12 @@ cris_opcodes[] =
    cris_eight_bit_offset_branch_op},
 
   /* This is deliberately put before "bext" to trump it, even though not
-     in alphabetical order.  */
+     in alphabetical order, since we don't do excluding version checks
+     for v0..v10.  */
   {"bwf",
    BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
    0x0f00+(0xF-CC_EXT)*0x1000,		  "o",	     1, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_eight_bit_offset_branch_op},
 
   {"bext",
@@ -268,7 +389,8 @@ cris_opcodes[] =
    0x0f00+(0xF-CC_HS)*0x1000,		  "o",	     1, SIZE_NONE,     0,
    cris_eight_bit_offset_branch_op},
 
-  {"biap", BIAP_OPCODE, BIAP_Z_BITS,	  "pm r,R",  0, SIZE_NONE,     0,
+  {"biap", BIAP_OPCODE, BIAP_Z_BITS,	  "pm r,R",  0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_biap_prefix},
 
   {"ble",
@@ -297,15 +419,15 @@ cris_opcodes[] =
    cris_eight_bit_offset_branch_op},
 
   {"bmod",    0x0ab0, 0x0140,		  "s,R",     0, SIZE_FIX_32,
-   cris_ver_sim,
+   cris_ver_sim_v0_10,
    cris_not_implemented_op},
 
   {"bmod",    0x0ab0, 0x0140,		  "S,D",     0, SIZE_NONE,
-   cris_ver_sim,
+   cris_ver_sim_v0_10,
    cris_not_implemented_op},
 
   {"bmod",    0x0ab0, 0x0540,		  "S,R,r",   0, SIZE_NONE,
-   cris_ver_sim,
+   cris_ver_sim_v0_10,
    cris_not_implemented_op},
 
   {"bne",
@@ -315,12 +437,20 @@ cris_opcodes[] =
 
   {"bound",   0x05c0, 0x0A00,		  "m r,R",   0, SIZE_NONE,     0,
    cris_two_operand_bound_op},
-  {"bound",   0x09c0, 0x0200,		  "m s,R",   0, SIZE_FIELD,    0,
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"bound",   0x09c0, 0x0200,		  "m s,R",   0, SIZE_FIELD,
+   cris_ver_v0_10,
    cris_two_operand_bound_op},
-  {"bound",   0x09c0, 0x0200,		  "m S,D",   0, SIZE_NONE,     0,
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
+  {"bound",   0x0dcf, 0x0200,		  "m Y,R",   0, SIZE_FIELD,    0,
    cris_two_operand_bound_op},
-  {"bound",   0x09c0, 0x0600,		  "m S,R,r", 0, SIZE_NONE,     0,
+  {"bound",   0x09c0, 0x0200,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_two_operand_bound_op},
+  {"bound",   0x09c0, 0x0600,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_bound_op},
+
   {"bpl",
    BRANCH_QUICK_OPCODE+CC_PL*0x1000,
    0x0f00+(0xF-CC_PL)*0x1000,		  "o",	     1, SIZE_NONE,     0,
@@ -330,6 +460,20 @@ cris_opcodes[] =
    cris_ver_v3p,
    cris_break_op},
 
+  {"bsb",
+   BRANCH_QUICK_OPCODE+CC_EXT*0x1000,
+   0x0f00+(0xF-CC_EXT)*0x1000,		  "o",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_eight_bit_offset_branch_op},
+
+  {"bsr",     0xBEBF, 0x4140,		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"bsrc",     0xBEFF, 0x4100,		  "n",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
   {"bstore",  0x0af0, 0x0100,		  "s,R",     0, SIZE_FIX_32,
    cris_ver_warning,
    cris_not_implemented_op},
@@ -346,6 +490,7 @@ cris_opcodes[] =
    cris_btst_nop_op},
   {"btstq",   0x0380, 0x0C60,		  "c,R",     0, SIZE_NONE,     0,
    cris_btst_nop_op},
+
   {"bvc",
    BRANCH_QUICK_OPCODE+CC_VC*0x1000,
    0x0f00+(0xF-CC_VC)*0x1000,		  "o",	     1, SIZE_NONE,     0,
@@ -362,7 +507,8 @@ cris_opcodes[] =
   {"clear",   0x0A70, 0x3180,		  "M y",     0, SIZE_NONE,     0,
    cris_none_reg_mode_clear_test_op},
 
-  {"clear",   0x0A70, 0x3180,		  "M S",     0, SIZE_NONE,     0,
+  {"clear",   0x0A70, 0x3180,		  "M S",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_clear_test_op},
 
   {"clearf",  0x05F0, 0x0A00,		  "f",	     0, SIZE_NONE,     0,
@@ -374,28 +520,34 @@ cris_opcodes[] =
   {"cmp",     0x0Ac0, 0x0100,		  "m s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"cmp",     0x0Ac0, 0x0100,		  "m S,D",   0, SIZE_NONE,     0,
+  {"cmp",     0x0Ac0, 0x0100,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
   {"cmpq",    0x02C0, 0x0D00,		  "i,R",     0, SIZE_NONE,     0,
    cris_quick_mode_and_cmp_move_or_op},
 
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
   {"cmps",    0x08e0, 0x0300,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"cmps",    0x08e0, 0x0300,		  "z S,D",   0, SIZE_NONE,     0,
+  {"cmps",    0x08e0, 0x0300,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
   {"cmpu",    0x08c0, 0x0320,		  "z s,R" ,  0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"cmpu",    0x08c0, 0x0320,		  "z S,D",   0, SIZE_NONE,     0,
+  {"cmpu",    0x08c0, 0x0320,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
   {"di",      0x25F0, 0xDA0F,		  "",	     0, SIZE_NONE,     0,
    cris_clearf_di_op},
 
-  {"dip",     DIP_OPCODE, DIP_Z_BITS,	  "ps",	     0, SIZE_FIX_32,   0,
+  {"dip",     DIP_OPCODE, DIP_Z_BITS,	  "ps",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
    cris_dip_prefix},
 
   {"div",     0x0980, 0x0640,		  "m R,r",   0, SIZE_FIELD,    0,
@@ -407,79 +559,156 @@ cris_opcodes[] =
   {"ei",      0x25B0, 0xDA4F,		  "",	     0, SIZE_NONE,     0,
    cris_ax_ei_setf_op},
 
+  {"fidxd",    0x0ab0, 0xf540,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"fidxi",    0x0d30, 0xF2C0,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"ftagd",    0x1AB0, 0xE540,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"ftagi",    0x1D30, 0xE2C0,		  "[r]",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"halt",    0xF930, 0x06CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"jas",    0x09B0, 0x0640,		  "r,P",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jas",    0x0DBF, 0x0240,		  "N,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jasc",    0x0B30, 0x04C0,		  "r,P",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jasc",    0x0F3F, 0x00C0,		  "N,P",     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
   {"jbrc",    0x69b0, 0x9640,		  "r",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_reg_mode_jump_op},
 
   {"jbrc",    0x6930, 0x92c0,		  "s",	     0, SIZE_FIX_32,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
   {"jbrc",    0x6930, 0x92c0,		  "S",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
-  {"jir",     0xA9b0, 0x5640,		  "r",	     0, SIZE_NONE,     0,
+  {"jir",     0xA9b0, 0x5640,		  "r",	     0, SIZE_NONE,
+   cris_ver_v8_10,
    cris_reg_mode_jump_op},
 
-  {"jir",     0xA930, 0x52c0,		  "s",	     0, SIZE_FIX_32,   0,
+  {"jir",     0xA930, 0x52c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
-  {"jir",     0xA930, 0x52c0,		  "S",	     0, SIZE_NONE,     0,
+  {"jir",     0xA930, 0x52c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
   {"jirc",    0x29b0, 0xd640,		  "r",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_reg_mode_jump_op},
 
   {"jirc",    0x2930, 0xd2c0,		  "s",	     0, SIZE_FIX_32,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
   {"jirc",    0x2930, 0xd2c0,		  "S",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
   {"jsr",     0xB9b0, 0x4640,		  "r",	     0, SIZE_NONE,     0,
    cris_reg_mode_jump_op},
 
-  {"jsr",     0xB930, 0x42c0,		  "s",	     0, SIZE_FIX_32,   0,
+  {"jsr",     0xB930, 0x42c0,		  "s",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
    cris_none_reg_mode_jump_op},
 
-  {"jsr",     0xB930, 0x42c0,		  "S",	     0, SIZE_NONE,     0,
+  {"jsr",     0xBDBF, 0x4240,		  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_none_reg_mode_jump_op},
+
+  {"jsr",     0xB930, 0x42c0,		  "S",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_jump_op},
 
   {"jsrc",    0x39b0, 0xc640,		  "r",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_reg_mode_jump_op},
 
   {"jsrc",    0x3930, 0xc2c0,		  "s",	     0, SIZE_FIX_32,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
   {"jsrc",    0x3930, 0xc2c0,		  "S",	     0, SIZE_NONE,
-   cris_ver_v8p,
+   cris_ver_v8_10,
    cris_none_reg_mode_jump_op},
 
+  {"jsrc",    0xBB30, 0x44C0,		  "r",       0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
+  {"jsrc",    0xBF3F, 0x40C0,		  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_reg_mode_jump_op},
+
   {"jump",    0x09b0, 0xF640,		  "r",	     0, SIZE_NONE,     0,
    cris_reg_mode_jump_op},
 
   {"jump",
-   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "s",	     0, SIZE_FIX_32,   0,
+   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "s",	     0, SIZE_FIX_32,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jump",
+   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "S",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_jump_op},
+
+  {"jump",    0x09F0, 0x060F,		  "P",	     0, SIZE_NONE,
+   cris_ver_v32p,
    cris_none_reg_mode_jump_op},
 
   {"jump",
-   JUMP_INDIR_OPCODE, JUMP_INDIR_Z_BITS,  "S",	     0, SIZE_NONE,     0,
+   JUMP_PC_INCR_OPCODE_V32,
+   (0xffff & ~JUMP_PC_INCR_OPCODE_V32),	  "N",	     0, SIZE_FIX_32,
+   cris_ver_v32p,
    cris_none_reg_mode_jump_op},
 
   {"jmpu",    0x8930, 0x72c0,		  "s",	     0, SIZE_FIX_32,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_none_reg_mode_jump_op},
 
   {"jmpu",    0x8930, 0x72c0,		   "S",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_none_reg_mode_jump_op},
 
+  {"lapc",    0x0970, 0x0680,		  "U,R",    0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"lapc",    0x0D7F, 0x0280,		  "dn,R",    0, SIZE_FIX_32,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"lapcq",   0x0970, 0x0680,		  "u,R",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_addi_op},
+
   {"lsl",     0x04C0, 0x0B00,		  "m r,R",   0, SIZE_NONE,     0,
    cris_dstep_logshift_mstep_neg_not_op},
 
@@ -496,9 +725,20 @@ cris_opcodes[] =
    cris_ver_v3p,
    cris_not_implemented_op},
 
+  {"mcp",      0x07f0, 0x0800,		  "P,r",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
   {"move",    0x0640, 0x0980,		  "m r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  {"move",    0x0A40, 0x0180,		  "m s,R",   0, SIZE_FIELD,    0,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
+  {"move",    0x0A40, 0x0180,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
+
   {"move",    0x0630, 0x09c0,		  "r,P",     0, SIZE_NONE,     0,
    cris_move_to_preg_op},
 
@@ -508,37 +748,44 @@ cris_opcodes[] =
   {"move",    0x0BC0, 0x0000,		  "m R,y",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"move",    0x0BC0, 0x0000,		  "m D,S",   0, SIZE_NONE,     0,
-   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
-  {"move",    0x0A40, 0x0180,		  "m s,R",   0, SIZE_FIELD,    0,
-   cris_none_reg_mode_add_sub_cmp_and_or_move_op},
-
-  {"move",    0x0A40, 0x0180,		  "m S,D",   0, SIZE_NONE,     0,
+  {"move",    0x0BC0, 0x0000,		  "m D,S",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
   {"move",    0x0A30, 0x01c0,		  "s,P",     0, SIZE_SPEC_REG, 0,
    cris_move_to_preg_op},
 
-  {"move",    0x0A30, 0x01c0,		  "S,P",     0, SIZE_NONE,     0,
+  {"move",    0x0A30, 0x01c0,		  "S,P",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_move_to_preg_op},
 
   {"move",    0x0A70, 0x0180,		  "P,y",     0, SIZE_SPEC_REG, 0,
    cris_none_reg_mode_move_from_preg_op},
 
-  {"move",    0x0A70, 0x0180,		  "P,S",     0, SIZE_NONE,     0,
+  {"move",    0x0A70, 0x0180,		  "P,S",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_move_from_preg_op},
 
+  {"move",    0x0B70, 0x0480,		  "r,T",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"move",    0x0F70, 0x0080,		  "T,r",     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
   {"movem",   0x0BF0, 0x0000,		  "R,y",     0, SIZE_FIX_32,   0,
    cris_move_reg_to_mem_movem_op},
 
-  {"movem",   0x0BF0, 0x0000,		  "D,S",     0, SIZE_NONE,     0,
+  {"movem",   0x0BF0, 0x0000,		  "D,S",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_move_reg_to_mem_movem_op},
 
   {"movem",   0x0BB0, 0x0040,		  "s,R",     0, SIZE_FIX_32,   0,
    cris_move_mem_to_reg_movem_op},
 
-  {"movem",   0x0BB0, 0x0040,		  "S,D",     0, SIZE_NONE,     0,
+  {"movem",   0x0BB0, 0x0040,		  "S,D",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_move_mem_to_reg_movem_op},
 
   {"moveq",   0x0240, 0x0D80,		  "i,R",     0, SIZE_NONE,     0,
@@ -547,22 +794,27 @@ cris_opcodes[] =
   {"movs",    0x0460, 0x0B80,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
   {"movs",    0x0860, 0x0380,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"movs",    0x0860, 0x0380,		  "z S,D",   0, SIZE_NONE,     0,
+  {"movs",    0x0860, 0x0380,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
   {"movu",    0x0440, 0x0Ba0,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
   {"movu",    0x0840, 0x03a0,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"movu",    0x0840, 0x03a0,		  "z S,D",   0, SIZE_NONE,     0,
+  {"movu",    0x0840, 0x03a0,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"mstep",   0x07f0, 0x0800,		  "r,R",     0, SIZE_NONE,     0,
+  {"mstep",   0x07f0, 0x0800,		  "r,R",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_dstep_logshift_mstep_neg_not_op},
 
   {"muls",    0x0d00, 0x02c0,		  "m r,R",   0, SIZE_NONE,
@@ -576,7 +828,12 @@ cris_opcodes[] =
   {"neg",     0x0580, 0x0A40,		  "m r,R",   0, SIZE_NONE,     0,
    cris_dstep_logshift_mstep_neg_not_op},
 
-  {"nop",     NOP_OPCODE, NOP_Z_BITS,	  "",	     0, SIZE_NONE,     0,
+  {"nop",     NOP_OPCODE, NOP_Z_BITS,	  "",	     0, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_btst_nop_op},
+
+  {"nop",     NOP_OPCODE_V32, NOP_Z_BITS_V32, "",    0, SIZE_NONE,
+   cris_ver_v32p,
    cris_btst_nop_op},
 
   {"not",     0x8770, 0x7880,		  "r",	     0, SIZE_NONE,     0,
@@ -588,50 +845,83 @@ cris_opcodes[] =
   {"or",      0x0B40, 0x0080,		  "m s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"or",      0x0B40, 0x0080,		  "m S,D",   0, SIZE_NONE,     0,
+  {"or",      0x0B40, 0x0080,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"or",      0x0B40, 0x0480,		  "m S,R,r", 0, SIZE_NONE,     0,
+  {"or",      0x0B40, 0x0480,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"orq",     0x0340, 0x0C80,		  "i,R",     0, SIZE_NONE,     0,
    cris_quick_mode_and_cmp_move_or_op},
 
-  {"pop",     0x0E6E, 0x0191,		  "!R",	     0, SIZE_NONE,     0,
+  {"pop",     0x0E6E, 0x0191,		  "!R",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"pop",     0x0e3e, 0x01c1,		  "!P",	     0, SIZE_NONE,     0,
+  {"pop",     0x0e3e, 0x01c1,		  "!P",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_move_from_preg_op},
 
-  {"push",    0x0FEE, 0x0011,		  "BR",	     0, SIZE_NONE,     0,
+  {"push",    0x0FEE, 0x0011,		  "BR",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"push",    0x0E7E, 0x0181,		  "BP",	     0, SIZE_NONE,     0,
+  {"push",    0x0E7E, 0x0181,		  "BP",	     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_move_to_preg_op},
 
   {"rbf",     0x3b30, 0xc0c0,		  "y",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_not_implemented_op},
 
   {"rbf",     0x3b30, 0xc0c0,		  "S",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
+   cris_not_implemented_op},
+
+  {"rfe",     0x2930, 0xD6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"rfg",     0x4930, 0xB6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
+  {"rfn",     0x5930, 0xA6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
    cris_not_implemented_op},
 
-  {"ret",     0xB67F, 0x4980,		  "",	     1, SIZE_NONE,     0,
+  {"ret",     0xB67F, 0x4980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_move_from_preg_op},
+
+  {"ret",     0xB9F0, 0x460F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
    cris_reg_mode_move_from_preg_op},
 
-  {"retb",    0xe67f, 0x1980,		  "",	     1, SIZE_NONE,     0,
+  {"retb",    0xe67f, 0x1980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
    cris_reg_mode_move_from_preg_op},
 
-  {"reti",    0xA67F, 0x5980,		  "",	     1, SIZE_NONE,     0,
+  {"rete",     0xA9F0, 0x560F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
+   cris_reg_mode_move_from_preg_op},
+
+  {"reti",    0xA67F, 0x5980,		  "",	     1, SIZE_NONE,
+   cris_ver_v0_10,
+   cris_reg_mode_move_from_preg_op},
+
+  {"retn",     0xC9F0, 0x360F,		  "",	     1, SIZE_NONE,
+   cris_ver_v32p,
    cris_reg_mode_move_from_preg_op},
 
   {"sbfs",    0x3b70, 0xc080,		  "y",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_not_implemented_op},
 
   {"sbfs",    0x3b70, 0xc080,		  "S",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_not_implemented_op},
 
   {"sa",
@@ -639,6 +929,12 @@ cris_opcodes[] =
    0x0AC0+(0xf-CC_A)*0x1000,		  "r",	     0, SIZE_NONE,     0,
    cris_scc_op},
 
+  {"ssb",
+   0x0530+CC_EXT*0x1000,
+   0x0AC0+(0xf-CC_EXT)*0x1000,		  "r",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_scc_op},
+
   {"scc",
    0x0530+CC_CC*0x1000,
    0x0AC0+(0xf-CC_CC)*0x1000,		  "r",	     0, SIZE_NONE,     0,
@@ -657,12 +953,16 @@ cris_opcodes[] =
   {"setf",    0x05b0, 0x0A40,		  "f",	     0, SIZE_NONE,     0,
    cris_ax_ei_setf_op},
 
+  {"sfe",    0x3930, 0xC6CF,		  "",	     0, SIZE_NONE,
+   cris_ver_v32p,
+   cris_not_implemented_op},
+
   /* Need to have "swf" in front of "sext" so it is the one displayed in
      disassembly.  */
   {"swf",
    0x0530+CC_EXT*0x1000,
    0x0AC0+(0xf-CC_EXT)*0x1000,		  "r",	     0, SIZE_NONE,
-   cris_ver_v10p,
+   cris_ver_v10,
    cris_scc_op},
 
   {"sext",
@@ -732,10 +1032,12 @@ cris_opcodes[] =
   {"sub",     0x0a80, 0x0140,		  "m s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"sub",     0x0a80, 0x0140,		  "m S,D",   0, SIZE_NONE,     0,
+  {"sub",     0x0a80, 0x0140,		  "m S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"sub",     0x0a80, 0x0540,		  "m S,R,r", 0, SIZE_NONE,     0,
+  {"sub",     0x0a80, 0x0540,		  "m S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"subq",    0x0280, 0x0d40,		  "I,R",     0, SIZE_NONE,     0,
@@ -744,25 +1046,31 @@ cris_opcodes[] =
   {"subs",    0x04a0, 0x0b40,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_SIGNED and all necessary changes.  */
   {"subs",    0x08a0, 0x0340,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"subs",    0x08a0, 0x0340,		  "z S,D",   0, SIZE_NONE,     0,
+  {"subs",    0x08a0, 0x0340,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"subs",    0x08a0, 0x0740,		  "z S,R,r", 0, SIZE_NONE,     0,
+  {"subs",    0x08a0, 0x0740,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"subu",    0x0480, 0x0b60,		  "z r,R",   0, SIZE_NONE,     0,
    cris_reg_mode_add_sub_cmp_and_or_move_op},
 
+  /* FIXME: SIZE_FIELD_UNSIGNED and all necessary changes.  */
   {"subu",    0x0880, 0x0360,		  "z s,R",   0, SIZE_FIELD,    0,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"subu",    0x0880, 0x0360,		  "z S,D",   0, SIZE_NONE,     0,
+  {"subu",    0x0880, 0x0360,		  "z S,D",   0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_add_sub_cmp_and_or_move_op},
 
-  {"subu",    0x0880, 0x0760,		  "z S,R,r", 0, SIZE_NONE,     0,
+  {"subu",    0x0880, 0x0760,		  "z S,R,r", 0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_three_operand_add_sub_cmp_and_or_op},
 
   {"svc",
@@ -838,13 +1146,15 @@ cris_opcodes[] =
    cris_ver_v8p,
    cris_not_implemented_op},
 
-  {"test",    0x0640, 0x0980,		  "m D",     0, SIZE_NONE,     0,
+  {"test",    0x0640, 0x0980,		  "m D",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_reg_mode_test_op},
 
-  {"test",    0x0b80, 0xf040,		  "m s",     0, SIZE_FIELD,    0,
+  {"test",    0x0b80, 0xf040,		  "m y",     0, SIZE_FIELD,    0,
    cris_none_reg_mode_clear_test_op},
 
-  {"test",    0x0b80, 0xf040,		  "m S",     0, SIZE_NONE,     0,
+  {"test",    0x0b80, 0xf040,		  "m S",     0, SIZE_NONE,
+   cris_ver_v0_10,
    cris_none_reg_mode_clear_test_op},
 
   {"xor",     0x07B0, 0x0840,		  "r,R",     0, SIZE_NONE,     0,
@@ -872,8 +1182,19 @@ cris_cc_strings[] =
   "gt",
   "le",
   "a",
-  /* In v0, this would be "ext".  */
-  "wf",
+  /* This is a placeholder.  In v0, this would be "ext".  In v32, this
+     is "sb".  See cris_conds15.  */
+  "wf"
+};
+
+/* Different names and semantics for condition 1111 (0xf).  */
+const struct cris_cond15 cris_cond15s[] =
+{
+  /* FIXME: In what version did condition "ext" disappear?  */
+  {"ext", cris_ver_v0_3},
+  {"wf", cris_ver_v10},
+  {"sb", cris_ver_v32p},
+  {NULL, 0}
 };
 
Index: bfd/archures.c
===================================================================
RCS file: /cvs/src/src/bfd/archures.c,v
retrieving revision 1.97
diff -p -c -u -p -r1.97 archures.c
--- bfd/archures.c	30 Jul 2004 10:08:00 -0000	1.97
+++ bfd/archures.c	4 Nov 2004 13:33:31 -0000
@@ -323,6 +323,9 @@ DESCRIPTION
 .  bfd_arch_crx,       {*  National Semiconductor CRX.  *}
 .#define bfd_mach_crx		1
 .  bfd_arch_cris,      {* Axis CRIS *}
+.#define bfd_mach_cris_v0_v10	255
+.#define bfd_mach_cris_v32	32
+.#define bfd_mach_cris_v10_v32	1032
 .  bfd_arch_s390,      {* IBM s390 *}
 .#define bfd_mach_s390_31       31
 .#define bfd_mach_s390_64       64
Index: bfd/config.bfd
===================================================================
RCS file: /cvs/src/src/bfd/config.bfd,v
retrieving revision 1.175
diff -p -c -u -p -r1.175 config.bfd
--- bfd/config.bfd	2 Nov 2004 16:24:35 -0000	1.175
+++ bfd/config.bfd	4 Nov 2004 13:33:34 -0000
@@ -54,6 +54,7 @@ arm*)		 targ_archs=bfd_arm_arch ;;
 c30*)		 targ_archs=bfd_tic30_arch ;;
 c4x*)		 targ_archs=bfd_tic4x_arch ;;
 c54x*)		 targ_archs=bfd_tic54x_arch ;;
+crisv32)	 targ_archs=bfd_cris_arch ;;
 crx*)		 targ_archs=bfd_crx_arch ;;
 dlx*)		 targ_archs=bfd_dlx_arch ;;
 hppa*)		 targ_archs=bfd_hppa_arch ;;
@@ -326,7 +327,7 @@ case "${targ}" in
     targ_underscore=yes
     ;;
 
-  cris-*-*)
+  cris-*-* | crisv32-*-*)
     targ_defvec=cris_aout_vec
     targ_selvecs="bfd_elf32_us_cris_vec bfd_elf32_cris_vec ieee_vec"
     targ_underscore=yes # Note: not true for bfd_elf32_cris_vec.
Index: bfd/cpu-cris.c
===================================================================
RCS file: /cvs/src/src/bfd/cpu-cris.c,v
retrieving revision 1.4
diff -p -c -u -p -r1.4 cpu-cris.c
--- bfd/cpu-cris.c	20 Dec 2002 22:41:13 -0000	1.4
+++ bfd/cpu-cris.c	4 Nov 2004 13:33:34 -0000
@@ -23,8 +23,58 @@ Foundation, Inc., 59 Temple Place - Suit
 #include "sysdep.h"
 #include "libbfd.h"
 
-const bfd_arch_info_type
-bfd_cris_arch =
+/* This routine is provided two arch_infos and returns the lowest common
+   denominator.  CRIS v0..v10 vs. v32 are not compatible in general, but
+   there's a compatible subset for which we provide an arch_info.  */
+
+static const bfd_arch_info_type * get_compatible
+  PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *));
+
+static const bfd_arch_info_type *
+get_compatible (a,b)
+     const bfd_arch_info_type *a;
+     const bfd_arch_info_type *b;
+{
+  /* Arches must match.  */
+  if (a->arch != b->arch)
+   return NULL;
+
+  /* If either is the compatible mach, return the other.  */
+  if (a->mach == bfd_mach_cris_v10_v32)
+    return b;
+  if (b->mach == bfd_mach_cris_v10_v32)
+    return a;
+
+#if 0
+  /* See ldlang.c:lang_check.  Quite illogically, incompatible arches
+     (as signalled by this function) are only *warned* about, while with
+     this function signalling compatible ones, we can have the
+     cris_elf_merge_private_bfd_data function return an error.  This is
+     undoubtedly a FIXME: in general.  Also, the
+     command_line.warn_mismatch flag and the --no-warn-mismatch option
+     are misnamed for the multitude of ports that signal compatibility:
+     it is there an error, not a warning.  We work around it by
+     pretending matching machs here.  */
+
+  /* Except for the compatible mach, machs must match.  */
+  if (a->mach != b->mach)
+    return NULL;
+#endif
+
+  return a;
+}
+
+#define N(NUMBER, PRINT, NEXT)  \
+ { 32, 32, 8, bfd_arch_cris, NUMBER, "cris", PRINT, 1, FALSE, \
+   get_compatible, bfd_default_scan, NEXT }
+
+static const bfd_arch_info_type bfd_cris_arch_compat_v10_v32 =
+ N (bfd_mach_cris_v10_v32, "cris:common_v10_v32", NULL);
+
+static const bfd_arch_info_type bfd_cris_arch_v32 =
+ N (bfd_mach_cris_v32, "crisv32", &bfd_cris_arch_compat_v10_v32);
+
+const bfd_arch_info_type bfd_cris_arch =
 {
   32,				/* There's 32 bits_per_word.  */
   32,				/* There's 32 bits_per_address.  */
@@ -32,20 +82,20 @@ bfd_cris_arch =
   bfd_arch_cris,		/* One of enum bfd_architecture, defined
 				   in archures.c and provided in
 				   generated header files.  */
-  0xff,				/* Only 1 machine, but #255 for
-				   historical reasons.  */
+  bfd_mach_cris_v0_v10,		/* Random BFD-internal number for this
+				   machine, similarly listed in
+				   archures.c.  Not emitted in output.  */
   "cris",			/* The arch_name.  */
   "cris",			/* The printable name is the same.  */
   1,				/* Section alignment power; each section
 				   is aligned to (only) 2^1 bytes.  */
-  TRUE,				/* This is the default "machine", since
-				   there's only one.  */
-  bfd_default_compatible,	/* A default function for testing
+  TRUE,				/* This is the default "machine".  */
+  get_compatible,		/* A function for testing
 				   "machine" compatibility of two
 				   bfd_arch_info_type.  */
   bfd_default_scan,		/* Check if a bfd_arch_info_type is a
 				   match.  */
-  NULL				/* Pointer to next bfd_arch_info_type in
+  &bfd_cris_arch_v32		/* Pointer to next bfd_arch_info_type in
 				   the same family.  */
 };
 
Index: bfd/elf32-cris.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-cris.c,v
retrieving revision 1.59
diff -p -c -u -p -r1.59 elf32-cris.c
--- bfd/elf32-cris.c	21 Oct 2004 15:28:20 -0000	1.59
+++ bfd/elf32-cris.c	4 Nov 2004 13:33:39 -0000
@@ -33,6 +33,9 @@ static reloc_howto_type * cris_reloc_typ
 static void cris_info_to_howto_rela
   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
 
+static bfd_reloc_status_type cris_elf_pcrel_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+
 static bfd_boolean cris_elf_grok_prstatus
   PARAMS ((bfd *abfd, Elf_Internal_Note *note));
 
@@ -59,9 +62,13 @@ static bfd_boolean cris_elf_object_p PAR
 
 static void cris_elf_final_write_processing PARAMS ((bfd *, bfd_boolean));
 
+static bfd_boolean cris_elf_set_mach_from_flags
+  PARAMS ((bfd *, unsigned long int));
+
 static bfd_boolean cris_elf_print_private_bfd_data PARAMS ((bfd *, PTR));
 
 static bfd_boolean cris_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
+static bfd_boolean cris_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
 
 struct elf_cris_link_hash_entry;
 static bfd_boolean elf_cris_discard_excess_dso_dynamics
@@ -164,7 +171,7 @@ static reloc_howto_type cris_elf_howto_t
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
-	 bfd_elf_generic_reloc,	/* special_function */
+	 cris_elf_pcrel_reloc,	/* special_function */
 	 "R_CRIS_8_PCREL",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0x0000,		/* src_mask */
@@ -179,7 +186,7 @@ static reloc_howto_type cris_elf_howto_t
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
-	 bfd_elf_generic_reloc,	/* special_function */
+	 cris_elf_pcrel_reloc,	/* special_function */
 	 "R_CRIS_16_PCREL",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0x00000000,		/* src_mask */
@@ -194,7 +201,7 @@ static reloc_howto_type cris_elf_howto_t
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
-	 bfd_elf_generic_reloc,	/* special_function */
+	 cris_elf_pcrel_reloc,	/* special_function */
 	 "R_CRIS_32_PCREL",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0x00000000,		/* src_mask */
@@ -398,7 +405,7 @@ static reloc_howto_type cris_elf_howto_t
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
-	 bfd_elf_generic_reloc,	/* special_function */
+	 cris_elf_pcrel_reloc,	/* special_function */
 	 "R_CRIS_32_PLT_PCREL",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0,			/* src_mask */
@@ -466,8 +473,39 @@ cris_info_to_howto_rela (abfd, cache_ptr
   BFD_ASSERT (r_type < (unsigned int) R_CRIS_max);
   cache_ptr->howto = & cris_elf_howto_table [r_type];
 }
+
+bfd_reloc_status_type
+cris_elf_pcrel_reloc (abfd, reloc_entry, symbol, data, input_section,
+		      output_bfd, error_message)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  /* By default (using only bfd_elf_generic_reloc when linking to
+     non-ELF formats) PC-relative relocs are relative to the beginning
+     of the reloc.  CRIS PC-relative relocs are relative to the position
+     *after* the reloc because that's what pre-CRISv32 PC points to
+     after reading an insn field with that reloc.  (For CRISv32, PC is
+     actually relative to the start of the insn, but we keep the old
+     definition.)  Still, we use as much generic machinery as we can.
+
+     Only adjust when doing a final link.  */
+  if (output_bfd == (bfd *) NULL)
+    reloc_entry->addend -= 1 << reloc_entry->howto->size;
+
+  return
+    bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+			   input_section, output_bfd, error_message);
+}
 
-/* Support for core dump NOTE sections.  */
+/* Support for core dump NOTE sections.
+   The slightly unintuitive code layout is an attempt to keep at least
+   some similarities with other ports, hoping to simplify general
+   changes, while still keeping Linux/CRIS and Linux/CRISv32 code apart.  */
 
 static bfd_boolean
 cris_elf_grok_prstatus (abfd, note)
@@ -477,8 +515,28 @@ cris_elf_grok_prstatus (abfd, note)
   int offset;
   size_t size;
 
-  switch (note->descsz)
-    {
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+    switch (note->descsz)
+      {
+      default:
+	return FALSE;
+
+      case 202:		/* Linux/CRISv32 */
+	/* pr_cursig */
+	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+	/* pr_pid */
+	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 22);
+
+	/* pr_reg */
+	offset = 70;
+	size = 128;
+
+	break;
+      }
+  else
+    switch (note->descsz)
+      {
       default:
 	return FALSE;
 
@@ -494,7 +552,7 @@ cris_elf_grok_prstatus (abfd, note)
 	size = 140;
 
 	break;
-    }
+      }
 
   /* Make a ".reg/999" section.  */
   return _bfd_elfcore_make_pseudosection (abfd, ".reg",
@@ -506,17 +564,30 @@ cris_elf_grok_psinfo (abfd, note)
      bfd *abfd;
      Elf_Internal_Note *note;
 {
-  switch (note->descsz)
-    {
+  if (bfd_get_mach (abfd) == bfd_mach_cris_v32)
+    switch (note->descsz)
+      {
+      default:
+	return FALSE;
+
+      case 124:		/* Linux/CRISv32 elf_prpsinfo */
+	elf_tdata (abfd)->core_program
+	  = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+	elf_tdata (abfd)->core_command
+	  = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+      }
+  else
+    switch (note->descsz)
+      {
       default:
 	return FALSE;
 
       case 124:		/* Linux/CRIS elf_prpsinfo */
 	elf_tdata (abfd)->core_program
-	 = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
+	  = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
 	elf_tdata (abfd)->core_command
-	 = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
-    }
+	  = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
+      }
 
   /* Note that for some reason, a spurious space is tacked
      onto the end of the args in some (at least one anyway)
@@ -541,6 +612,7 @@ cris_elf_grok_psinfo (abfd, note)
 /* The size in bytes of an entry in the procedure linkage table.  */
 
 #define PLT_ENTRY_SIZE 20
+#define PLT_ENTRY_SIZE_V32 26
 
 /* The first entry in an absolute procedure linkage table looks like this.  */
 
@@ -553,7 +625,21 @@ static const bfd_byte elf_cris_plt0_entr
   0x30, 0x7a,	/* move [...],mof */
   0x7f, 0x0d,   /*  (dip [pc+]) */
   0, 0, 0, 0,	/*  Replaced with address of .got + 8.  */
-  0x30, 0x09,	/* jump [...] */
+  0x30, 0x09	/* jump [...] */
+};
+
+static const bfd_byte elf_cris_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+  0x84, 0xe2,	/* subq 4,$sp */
+  0x6f, 0xfe,	/* move.d 0,$acr */
+  0, 0, 0, 0,	/*  Replaced by address of .got + 4.  */
+  0x7e, 0x7a,	/* move $mof,[$sp] */
+  0x3f, 0x7a,	/* move [$acr],$mof */
+  0x04, 0xf2,	/* addq 4,acr */
+  0x6f, 0xfa,	/* move.d [$acr],$acr */
+  0xbf, 0x09,	/* jump $acr */
+  0xb0, 0x05,	/* nop */
+  0, 0		/*  Pad out to 26 bytes.  */
 };
 
 /* Subsequent entries in an absolute procedure linkage table look like
@@ -571,6 +657,20 @@ static const bfd_byte elf_cris_plt_entry
   0xff, 0xff	/*  Replaced with offset to start of .plt.  */
 };
 
+static const bfd_byte elf_cris_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+  0x6f, 0xfe,	/* move.d 0,$acr */
+  0, 0, 0, 0,	/*  Replaced with address of this symbol in .got.  */
+  0x6f, 0xfa,   /* move.d [$acr],$acr */
+  0xbf, 0x09,   /* jump $acr */
+  0xb0, 0x05,	/* nop */
+  0x3f, 0x7e,	/* move 0,mof */
+  0, 0, 0, 0,	/*  Replaced with offset into relocation table. */
+  0xbf, 0x0e,	/* ba start_of_plt0_entry */
+  0, 0, 0, 0,	/*  Replaced with offset to plt0 entry.  */
+  0xb0, 0x05	/* nop */
+};
+
 /* The first entry in a PIC procedure linkage table looks like this.  */
 
 static const bfd_byte elf_cris_pic_plt0_entry[PLT_ENTRY_SIZE] =
@@ -581,6 +681,21 @@ static const bfd_byte elf_cris_pic_plt0_
   0, 0, 0, 0, 0, 0, 0, 0,	/*  Pad out to 20 bytes.  */
 };
 
+static const bfd_byte elf_cris_pic_plt0_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+  0x84, 0xe2,	/* subq 4,$sp */
+  0x04, 0x01,	/* addoq 4,$r0,$acr */
+  0x7e, 0x7a,	/* move $mof,[$sp] */
+  0x3f, 0x7a,	/* move [$acr],$mof */
+  0x04, 0xf2,	/* addq 4,$acr */
+  0x6f, 0xfa,	/* move.d [$acr],$acr */
+  0xbf, 0x09,	/* jump $acr */
+  0xb0, 0x05,	/* nop */
+  0, 0,		/*  Pad out to 26 bytes.  */
+  0, 0, 0, 0,
+  0, 0, 0, 0
+};
+
 /* Subsequent entries in a PIC procedure linkage table look like this.  */
 
 static const bfd_byte elf_cris_pic_plt_entry[PLT_ENTRY_SIZE] =
@@ -594,6 +709,20 @@ static const bfd_byte elf_cris_pic_plt_e
   0xec, 0xff,	/*  Replaced with offset to start of .plt.  */
   0xff, 0xff
 };
+
+static const bfd_byte elf_cris_pic_plt_entry_v32[PLT_ENTRY_SIZE_V32] =
+{
+  0x6f, 0x0d,	/* addo.d 0,$r0,$acr */
+  0, 0, 0, 0,	/*  Replaced with offset of this symbol in .got.  */
+  0x6f, 0xfa,	/* move.d [$acr],$acr */
+  0xbf, 0x09,	/* jump $acr */
+  0xb0, 0x05,	/* nop */
+  0x3f, 0x7e,	/* move relocoffs,$mof */
+  0, 0, 0, 0,	/*  Replaced with offset into relocation table.  */
+  0xbf, 0x0e,	/* ba start_of_plt */
+  0, 0, 0, 0,	/*  Replaced with offset to start of .plt.  */
+  0xb0, 0x05	/* nop */
+};
 
 /* We copy elf32-m68k.c and elf32-i386.c for the basic linker hash bits
    (and most other PIC/shlib stuff).  Check that we don't drift away
@@ -917,7 +1046,7 @@ cris_elf_relocate_section (output_bfd, i
 	      else if (unresolved_reloc)
 		{
 		  _bfd_error_handler
-		    (_("%B(%A): unresolvable relocation %s against symbol `%s'"),
+		    (_("%B, section %A: unresolvable relocation %s against symbol `%s'"),
 		     input_bfd,
 		     input_section,
 		     cris_elf_howto_table[r_type].name,
@@ -972,9 +1101,9 @@ cris_elf_relocate_section (output_bfd, i
 	    {
 	      (*_bfd_error_handler)
 		((h->got.offset == (bfd_vma) -1)
-		 ? _("%B(%A): No PLT nor GOT for relocation %s"
+		 ? _("%B, section %A: No PLT nor GOT for relocation %s"
 		     " against symbol `%s'")
-		 : _("%B(%A): No PLT for relocation %s"
+		 : _("%B, section %A: No PLT for relocation %s"
 		     " against symbol `%s'"),
 		 input_bfd,
 		 input_section,
@@ -1098,7 +1227,7 @@ cris_elf_relocate_section (output_bfd, i
 		   allowed to pass us these kinds of things.  */
 		if (h == NULL)
 		  (*_bfd_error_handler)
-		    (_("%B(%A): relocation %s with non-zero addend %d"
+		    (_("%B, section %A: relocation %s with non-zero addend %d"
 		       " against local symbol"),
 		     input_bfd,
 		     input_section,
@@ -1106,7 +1235,7 @@ cris_elf_relocate_section (output_bfd, i
 		     rel->r_addend);
 		else
 		  (*_bfd_error_handler)
-		    (_("%B(%A): relocation %s with non-zero addend %d"
+		    (_("%B, section %A: relocation %s with non-zero addend %d"
 		       " against symbol `%s'"),
 		     input_bfd,
 		     input_section,
@@ -1132,7 +1261,8 @@ cris_elf_relocate_section (output_bfd, i
 			   && h->root.type == bfd_link_hash_undefweak))))
 	    {
 	      (*_bfd_error_handler)
-		(_("%B(%A): relocation %s is not allowed for global symbol: `%s'"),
+		(_("%B, section %A: relocation %s is"
+		   " not allowed for global symbol: `%s'"),
 		 input_bfd,
 		 input_section,
 		 cris_elf_howto_table[r_type].name,
@@ -1147,7 +1277,7 @@ cris_elf_relocate_section (output_bfd, i
 	  if (sgot == NULL)
 	    {
 	      (*_bfd_error_handler)
-		(_("%B: relocation %s in section %A with no GOT created"),
+		(_("%B, section %A: relocation %s with no GOT created"),
 		 input_bfd,
 		 input_section,
 		 cris_elf_howto_table[r_type].name);
@@ -1407,8 +1537,33 @@ elf_cris_finish_dynamic_symbol (output_b
      Elf_Internal_Sym *sym;
 {
   bfd *dynobj;
+
+  /* Where in the plt entry to put values.  */
   int plt_off1 = 2, plt_off2 = 10, plt_off3 = 16;
 
+  /* What offset to add to the distance to the first PLT entry for the
+     value at plt_off3.   */
+  int plt_off3_value_bias = 4;
+
+  /* Where in the PLT entry the call-dynlink-stub is (happens to be same
+     for PIC and non-PIC for v32 and pre-v32).  */
+  int plt_stub_offset = 8;
+  int plt_entry_size = PLT_ENTRY_SIZE;
+  const bfd_byte *plt_entry = elf_cris_plt_entry;
+  const bfd_byte *plt_pic_entry = elf_cris_pic_plt_entry;
+
+  /* Adjust the various PLT entry offsets.  */
+  if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32)
+    {
+      plt_off2 = 14;
+      plt_off3 = 20;
+      plt_off3_value_bias = -2;
+      plt_stub_offset = 12;
+      plt_entry_size = PLT_ENTRY_SIZE_V32;
+      plt_entry = elf_cris_plt_entry_v32;
+      plt_pic_entry = elf_cris_pic_plt_entry_v32;
+    }
+
   dynobj = elf_hash_table (info)->dynobj;
 
   if (h->plt.offset != (bfd_vma) -1)
@@ -1460,8 +1615,8 @@ elf_cris_finish_dynamic_symbol (output_b
       /* Fill in the entry in the procedure linkage table.  */
       if (! info->shared)
 	{
-	  memcpy (splt->contents + h->plt.offset, elf_cris_plt_entry,
-		  PLT_ENTRY_SIZE);
+	  memcpy (splt->contents + h->plt.offset, plt_entry,
+		  plt_entry_size);
 
 	  /* We need to enter the absolute address of the GOT entry here.  */
 	  bfd_put_32 (output_bfd, got_base + got_offset,
@@ -1469,8 +1624,8 @@ elf_cris_finish_dynamic_symbol (output_b
 	}
       else
 	{
-	  memcpy (splt->contents + h->plt.offset, elf_cris_pic_plt_entry,
-		  PLT_ENTRY_SIZE);
+	  memcpy (splt->contents + h->plt.offset, plt_pic_entry,
+		  plt_entry_size);
 	  bfd_put_32 (output_bfd, got_offset,
 		      splt->contents + h->plt.offset + plt_off1);
 	}
@@ -1479,13 +1634,14 @@ elf_cris_finish_dynamic_symbol (output_b
 	 PLT entry.  */
       if (has_gotplt)
 	{
-	  /* Fill in the offset into the reloc table.  */
+	  /* Fill in the offset to the reloc table.  */
 	  bfd_put_32 (output_bfd,
 		      gotplt_index * sizeof (Elf32_External_Rela),
 		      splt->contents + h->plt.offset + plt_off2);
 
 	  /* Fill in the offset to the first PLT entry, where to "jump".  */
-	  bfd_put_32 (output_bfd, - (h->plt.offset + plt_off3 + 4),
+	  bfd_put_32 (output_bfd,
+		      - (h->plt.offset + plt_off3 + plt_off3_value_bias),
 		      splt->contents + h->plt.offset + plt_off3);
 
 	  /* Fill in the entry in the global offset table with the address of
@@ -1494,7 +1650,7 @@ elf_cris_finish_dynamic_symbol (output_b
 		      (splt->output_section->vma
 		       + splt->output_offset
 		       + h->plt.offset
-		       + 8),
+		       + plt_stub_offset),
 		      sgotplt->contents + got_offset);
 
 	  /* Fill in the entry in the .rela.plt section.  */
@@ -1695,20 +1851,45 @@ elf_cris_finish_dynamic_sections (output
       /* Fill in the first entry in the procedure linkage table.  */
       if (splt->size > 0)
 	{
-	  if (info->shared)
-	    memcpy (splt->contents, elf_cris_pic_plt0_entry, PLT_ENTRY_SIZE);
+	  if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32)
+	    {
+	      if (info->shared)
+		memcpy (splt->contents, elf_cris_pic_plt0_entry_v32,
+			PLT_ENTRY_SIZE_V32);
+	      else
+		{
+		  memcpy (splt->contents, elf_cris_plt0_entry_v32,
+			  PLT_ENTRY_SIZE_V32);
+		  bfd_put_32 (output_bfd,
+			      sgot->output_section->vma
+			      + sgot->output_offset + 4,
+			      splt->contents + 4);
+
+		  elf_section_data (splt->output_section)->this_hdr.sh_entsize
+		    = PLT_ENTRY_SIZE_V32;
+		}
+	    }
 	  else
-            {
-	      memcpy (splt->contents, elf_cris_plt0_entry, PLT_ENTRY_SIZE);
-	      bfd_put_32 (output_bfd,
-			  sgot->output_section->vma + sgot->output_offset + 4,
-			  splt->contents + 6);
-	      bfd_put_32 (output_bfd,
-			  sgot->output_section->vma + sgot->output_offset + 8,
-			  splt->contents + 14);
+	    {
+	      if (info->shared)
+		memcpy (splt->contents, elf_cris_pic_plt0_entry,
+			PLT_ENTRY_SIZE);
+	      else
+		{
+		  memcpy (splt->contents, elf_cris_plt0_entry,
+			  PLT_ENTRY_SIZE);
+		  bfd_put_32 (output_bfd,
+			      sgot->output_section->vma
+			      + sgot->output_offset + 4,
+			      splt->contents + 6);
+		  bfd_put_32 (output_bfd,
+			      sgot->output_section->vma
+			      + sgot->output_offset + 8,
+			      splt->contents + 14);
 
-              elf_section_data (splt->output_section)->this_hdr.sh_entsize
-               = PLT_ENTRY_SIZE;
+		  elf_section_data (splt->output_section)->this_hdr.sh_entsize
+		    = PLT_ENTRY_SIZE;
+		}
             }
 	}
     }
@@ -2018,6 +2199,7 @@ elf_cris_adjust_dynamic_symbol (info, h)
   bfd *dynobj;
   asection *s;
   unsigned int power_of_two;
+  bfd_size_type plt_entry_size;
 
   dynobj = elf_hash_table (info)->dynobj;
 
@@ -2029,6 +2211,10 @@ elf_cris_adjust_dynamic_symbol (info, h)
 		      && h->ref_regular
 		      && !h->def_regular)));
 
+  plt_entry_size
+    = (bfd_get_mach (dynobj) == bfd_mach_cris_v32
+       ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE);
+
   /* If this is a function, put it in the procedure linkage table.  We
      will fill in the contents of the procedure linkage table later,
      when we know the address of the .got section.  */
@@ -2089,7 +2275,7 @@ elf_cris_adjust_dynamic_symbol (info, h)
       /* If this is the first .plt entry, make room for the special
 	 first entry.  */
       if (s->size == 0)
-	s->size += PLT_ENTRY_SIZE;
+	s->size += plt_entry_size;
 
       /* If this symbol is not defined in a regular file, and we are
 	 not generating a shared library, then set the symbol to this
@@ -2113,8 +2299,8 @@ elf_cris_adjust_dynamic_symbol (info, h)
 
 	  /* Mark the PLT offset to use the GOT entry by setting the low
 	     bit in the plt offset; it is always a multiple of
-	     pointer-size.  */
-	  BFD_ASSERT ((s->size & 3) == 0);
+	     plt_entry_size (which is at least a multiple of 2).  */
+	  BFD_ASSERT ((s->size % plt_entry_size) == 0);
 
 	  /* Change the PLT refcount to an offset.  */
 	  h->plt.offset = s->size;
@@ -2125,7 +2311,7 @@ elf_cris_adjust_dynamic_symbol (info, h)
 		       h)->gotplt_offset == 0);
 
 	  /* Make room for this entry.  */
-	  s->size += PLT_ENTRY_SIZE;
+	  s->size += plt_entry_size;
 
 	  return TRUE;
 	}
@@ -2134,7 +2320,7 @@ elf_cris_adjust_dynamic_symbol (info, h)
       h->plt.offset = s->size;
 
       /* Make room for this entry.  */
-      s->size += PLT_ENTRY_SIZE;
+      s->size += plt_entry_size;
 
       /* We also need to make an entry in the .got.plt section, which
 	 will be placed in the .got section by the linker script.  */
@@ -2305,6 +2491,18 @@ cris_elf_check_relocs (abfd, info, sec, 
 	    {
 	      elf_hash_table (info)->dynobj = dynobj = abfd;
 
+	      /* We could handle this if we can get a handle on the
+		 output bfd in elf_cris_adjust_dynamic_symbol.  Failing
+		 that, we must insist on dynobj being a specific mach.  */
+	      if (bfd_get_mach (dynobj) == bfd_mach_cris_v10_v32)
+		{
+		  (*_bfd_error_handler)
+		    (_("%B, section %A:\n  v10/v32 compatible object %s"
+		       " must not contain a PIC relocation"),
+		     abfd, sec);
+		  return FALSE;
+		}
+
 	      /* Create the .got section, so we can assume it's always
 		 present whenever there's a dynobj.  */
 	      if (!_bfd_elf_create_got_section (dynobj, info))
@@ -2486,7 +2684,8 @@ cris_elf_check_relocs (abfd, info, sec, 
 	    {
 	      /* FIXME: How do we make this optionally a warning only?  */
 	      (*_bfd_error_handler)
-		(_("%B, section %A:\n  relocation %s should not be used in a shared object; recompile with -fPIC"),
+		(_("%B, section %A:\n  relocation %s should not"
+		   " be used in a shared object; recompile with -fPIC"),
 		 abfd,
 		 sec,
 		 cris_elf_howto_table[r_type].name);
@@ -2548,6 +2747,17 @@ cris_elf_check_relocs (abfd, info, sec, 
 		  && h->root.type != bfd_link_hash_defweak
 		  && h->def_regular)
 		break;
+
+	      if ((sec->flags & SEC_READONLY) != 0)
+		{
+		  /* FIXME: How do we make this optionally a warning only?  */
+		  (*_bfd_error_handler)
+		    (_("%B, section %A:\n  relocation %s should not be used"
+		       " in a shared object; recompile with -fPIC"),
+		     abfd,
+		     sec,
+		     cris_elf_howto_table[r_type].name);
+		}
 	    }
 
 	  /* We create a reloc section in dynobj and make room for this
@@ -2932,23 +3142,81 @@ static bfd_boolean
 cris_elf_object_p (abfd)
      bfd *abfd;
 {
+  if (! cris_elf_set_mach_from_flags (abfd, elf_elfheader (abfd)->e_flags))
+    return FALSE;
+
   if ((elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE))
     return (bfd_get_symbol_leading_char (abfd) == '_');
   else
     return (bfd_get_symbol_leading_char (abfd) == 0);
 }
 
-/* Mark presence or absence of leading underscore.  */
+/* Mark presence or absence of leading underscore.  Set machine type
+   flags from mach type.  */
 
 static void
 cris_elf_final_write_processing (abfd, linker)
      bfd *abfd;
      bfd_boolean linker ATTRIBUTE_UNUSED;
 {
+  unsigned long e_flags = elf_elfheader (abfd)->e_flags;
+
+  e_flags &= ~EF_CRIS_UNDERSCORE;
   if (bfd_get_symbol_leading_char (abfd) == '_')
-    elf_elfheader (abfd)->e_flags |= EF_CRIS_UNDERSCORE;
-  else
-    elf_elfheader (abfd)->e_flags &= ~EF_CRIS_UNDERSCORE;
+    e_flags |= EF_CRIS_UNDERSCORE;
+
+  switch (bfd_get_mach (abfd))
+    {
+    case bfd_mach_cris_v0_v10:
+      e_flags |= EF_CRIS_VARIANT_ANY_V0_V10;
+      break;
+
+    case bfd_mach_cris_v10_v32:
+      e_flags |= EF_CRIS_VARIANT_COMMON_V10_V32;
+      break;
+
+    case bfd_mach_cris_v32:
+      e_flags |= EF_CRIS_VARIANT_V32;
+      break;
+
+    default:
+      _bfd_abort (__FILE__, __LINE__,
+		  _("Unexpected machine number"));
+    }
+
+  elf_elfheader (abfd)->e_flags = e_flags;
+}
+
+/* Set the mach type from e_flags value.  */
+
+static bfd_boolean
+cris_elf_set_mach_from_flags (abfd, flags)
+     bfd *abfd;
+     unsigned long flags;
+{
+  switch (flags & EF_CRIS_VARIANT_MASK)
+    {
+    case EF_CRIS_VARIANT_ANY_V0_V10:
+      bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v0_v10);
+      break;
+
+    case EF_CRIS_VARIANT_V32:
+      bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v32);
+      break;
+
+    case EF_CRIS_VARIANT_COMMON_V10_V32:
+      bfd_default_set_arch_mach (abfd, bfd_arch_cris, bfd_mach_cris_v10_v32);
+      break;
+
+    default:
+      /* Since we don't recognize them, we obviously can't support them
+	 with this code; we'd have to require that all future handling
+	 would be optional.  */
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
+
+  return TRUE;
 }
 
 /* Display the flags field.  */
@@ -2968,6 +3236,12 @@ cris_elf_print_private_bfd_data (abfd, p
 
   if (elf_elfheader (abfd)->e_flags & EF_CRIS_UNDERSCORE)
     fprintf (file, _(" [symbols have a _ prefix]"));
+  if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK)
+      == EF_CRIS_VARIANT_COMMON_V10_V32)
+    fprintf (file, _(" [v10 and v32]"));
+  if ((elf_elfheader (abfd)->e_flags & EF_CRIS_VARIANT_MASK)
+      == EF_CRIS_VARIANT_V32)
+    fprintf (file, _(" [v32]"));
 
   fputc ('\n', file);
   return TRUE;
@@ -2980,7 +3254,7 @@ cris_elf_merge_private_bfd_data (ibfd, o
      bfd *ibfd;
      bfd *obfd;
 {
-  flagword old_flags, new_flags;
+  int imach, omach;
 
   if (! _bfd_generic_verify_endian_match (ibfd, obfd))
     return FALSE;
@@ -2989,23 +3263,29 @@ cris_elf_merge_private_bfd_data (ibfd, o
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
     return TRUE;
 
+  imach = bfd_get_mach (ibfd);
+
   if (! elf_flags_init (obfd))
     {
       /* This happens when ld starts out with a 'blank' output file.  */
       elf_flags_init (obfd) = TRUE;
 
-      /* Set flags according to current bfd_target.  */
-      cris_elf_final_write_processing (obfd, FALSE);
+      /* We ignore the linker-set mach, and instead set it according to
+	 the first input file.  This would also happen if we could
+	 somehow filter out the OUTPUT_ARCH () setting from elf.sc.
+	 This allows us to keep the same linker config across
+	 cris(v0..v10) and crisv32.  The drawback is that we can't force
+	 the output type, which might be a sane thing to do for a
+	 v10+v32 compatibility object.  */
+      if (! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
+	return FALSE;
     }
 
-  old_flags = elf_elfheader (obfd)->e_flags;
-  new_flags = elf_elfheader (ibfd)->e_flags;
-
-  /* Is this good or bad?  We'll follow with other excluding flags.  */
-  if ((old_flags & EF_CRIS_UNDERSCORE) != (new_flags & EF_CRIS_UNDERSCORE))
+  if (bfd_get_symbol_leading_char (ibfd)
+      != bfd_get_symbol_leading_char (obfd))
     {
       (*_bfd_error_handler)
-	((new_flags & EF_CRIS_UNDERSCORE)
+	(bfd_get_symbol_leading_char (ibfd) == '_'
 	 ? _("%B: uses _-prefixed symbols, but writing file with non-prefixed symbols")
 	 : _("%B: uses non-prefixed symbols, but writing file with _-prefixed symbols"),
 	 ibfd);
@@ -3013,9 +3293,61 @@ cris_elf_merge_private_bfd_data (ibfd, o
       return FALSE;
     }
 
+  omach = bfd_get_mach (obfd);
+
+  if (imach != omach)
+    {
+      /* We can get an incompatible combination only if either is
+	 bfd_mach_cris_v32, and the other one isn't compatible.  */
+      if ((imach == bfd_mach_cris_v32
+	   && omach != bfd_mach_cris_v10_v32)
+	  || (omach == bfd_mach_cris_v32
+	      && imach != bfd_mach_cris_v10_v32))
+	{
+	  (*_bfd_error_handler)
+	    ((imach == bfd_mach_cris_v32)
+	     ? _("%B contains CRIS v32 code, incompatible"
+		 " with previous objects")
+	     : _("%B contains non-CRIS-v32 code, incompatible"
+		 " with previous objects"),
+	     ibfd);
+	  bfd_set_error (bfd_error_bad_value);
+	  return FALSE;
+	}
+
+      /* We don't have to check the case where the input is compatible
+	 with v10 and v32, because the output is already known to be set
+	 to the other (compatible) mach.  */
+      if (omach == bfd_mach_cris_v10_v32
+	  && ! bfd_set_arch_mach (obfd, bfd_arch_cris, imach))
+	return FALSE;
+    }
+
   return TRUE;
 }
 
+/* Do side-effects of e_flags copying to obfd.  */
+
+static bfd_boolean
+cris_elf_copy_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  /* Call the base function.  */
+  if (!_bfd_elf_copy_private_bfd_data (ibfd, obfd))
+    return FALSE;
+
+  /* If output is big-endian for some obscure reason, stop here.  */
+  if (_bfd_generic_verify_endian_match (ibfd, obfd) == FALSE)
+    return FALSE;
+
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Do what we really came here for.  */
+  return bfd_set_arch_mach (obfd, bfd_arch_cris, bfd_get_mach (ibfd));
+}
 
 static enum elf_reloc_type_class
 elf_cris_reloc_type_class (rela)
@@ -3061,6 +3393,8 @@ elf_cris_reloc_type_class (rela)
 	cris_elf_print_private_bfd_data
 #define bfd_elf32_bfd_merge_private_bfd_data \
 	cris_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_copy_private_bfd_data \
+	cris_elf_copy_private_bfd_data
 
 #define bfd_elf32_bfd_reloc_type_lookup		cris_reloc_type_lookup
 
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.116
diff -p -c -u -p -r1.116 reloc.c
--- bfd/reloc.c	21 Oct 2004 15:28:30 -0000	1.116
+++ bfd/reloc.c	4 Nov 2004 13:33:40 -0000
@@ -3947,6 +3947,16 @@ ENUMX
 ENUMX
   BFD_RELOC_CRIS_UNSIGNED_6
 ENUMX
+  BFD_RELOC_CRIS_SIGNED_8
+ENUMX
+  BFD_RELOC_CRIS_UNSIGNED_8
+ENUMX
+  BFD_RELOC_CRIS_SIGNED_16
+ENUMX
+  BFD_RELOC_CRIS_UNSIGNED_16
+ENUMX
+  BFD_RELOC_CRIS_LAPCQ_OFFSET
+ENUMX
   BFD_RELOC_CRIS_UNSIGNED_4
 ENUMDOC
   These relocs are only used within the CRIS assembler.  They are not

Index: ld/configure.tgt
===================================================================
RCS file: /cvs/src/src/ld/configure.tgt,v
retrieving revision 1.156
diff -p -c -u -p -r1.156 configure.tgt
--- ld/configure.tgt	8 Oct 2004 13:55:11 -0000	1.156
+++ ld/configure.tgt	4 Nov 2004 13:33:57 -0000
@@ -30,8 +30,9 @@ cr16c-*-elf*)           targ_emul=elf32c
 cris-*-*aout*)		targ_emul=crisaout
 			targ_extra_emuls="criself crislinux"
 			targ_extra_libpath=$targ_extra_emuls ;;
-cris-*-linux-gnu*)	targ_emul=crislinux ;;
-cris-*-*)		targ_emul=criself
+cris-*-linux-gnu* | cris-*-linux-gnu*)
+			targ_emul=crislinux ;;
+cris-*-* | crisv32-*-*)	targ_emul=criself
 			targ_extra_emuls="crisaout crislinux"
 			targ_extra_libpath=$targ_extra_emuls ;;
 crx-*-elf*)		targ_emul=elf32crx ;;
Index: ld/emulparams/criself.sh
===================================================================
RCS file: /cvs/src/src/ld/emulparams/criself.sh,v
retrieving revision 1.6
diff -p -c -u -p -r1.6 criself.sh
--- ld/emulparams/criself.sh	4 Dec 2001 18:28:31 -0000	1.6
+++ ld/emulparams/criself.sh	4 Nov 2004 13:33:57 -0000
@@ -53,12 +53,9 @@ INIT_START='
  . = ALIGN(2);
  ___init__start = .;
  PROVIDE (___do_global_ctors = .);
- SHORT (0xe1fc); /* push srp */
- SHORT (0xbe7e);
 '
 
 INIT_END='
- SHORT (0x0d3e); /* jump [sp+] */
  PROVIDE (__init__end = .);
  PROVIDE (___init__end = .);
 '
@@ -67,12 +64,9 @@ FINI_START='
  . = ALIGN (2);
  ___fini__start = .;
  PROVIDE (___do_global_dtors = .);
- SHORT (0xe1fc); /* push srp */
- SHORT (0xbe7e);
 '
 
 FINI_END='
- SHORT (0x0d3e); /* jump [sp+] */
  PROVIDE (__fini__end = .);
  ___fini__end = .;
 '

brgds, H-P


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