All of lore.kernel.org
 help / color / mirror / Atom feed
* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
@ 2018-08-21 14:38 Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 1/4] or1k: Add relocations for high-signed and low-stores Stafford Horne
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Stafford Horne @ 2018-08-21 14:38 UTC (permalink / raw)
  To: openrisc

Hello,

This series contains a lot of updates for OpenRISC binutils.  Including:
  - Definitions for missing instructions.
  - New relocations used in the new GCC OpenRISC port
  - A new instruction l.adrp

The patches were for the most part written by Richard Henderson, I have fixed a
few bugs, added additional tests and wrote the ChangeLogs.

These patches have been tested and used in the new OpenRISC GCC clean-room
rewrite done by Richard and Me.

  http://stffrdhrn.github.io/software/embedded/openrisc/2018/02/03/openrisc_gcc_rewrite.html

-Stafford

Richard Henderson (2):
  or1k: Add relocations for high-signed and low-stores
  or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns

Stafford Horne (2):
  or1k: Fix messages for relocations in shared libraries
  or1k: Add the l.adrp insn and supporting relocations

 bfd/bfd-in2.h                                 |   19 +-
 bfd/elf32-or1k.c                              | 1002 +++++++++++++----
 bfd/libbfd.h                                  |   19 +-
 bfd/reloc.c                                   |   34 +-
 cpu/or1k.opc                                  |  582 +++++-----
 cpu/or1korbis.cpu                             |  300 +++--
 gas/config/tc-or1k.c                          |    6 +
 gas/testsuite/gas/or1k/allinsn.d              |   50 +-
 gas/testsuite/gas/or1k/allinsn.s              |   25 +
 .../gas/or1k/{allinsn.exp => or1k.exp}        |    1 +
 gas/testsuite/gas/or1k/reloc-1.d              |   72 ++
 gas/testsuite/gas/or1k/reloc-1.s              |   76 ++
 gas/testsuite/gas/or1k/reloc-2.l              |   11 +
 gas/testsuite/gas/or1k/reloc-2.s              |   13 +
 include/elf/or1k.h                            |   19 +
 ld/testsuite/ld-or1k/offsets1.d               |  212 ++++
 ld/testsuite/ld-or1k/offsets1.s               |   14 +
 ld/testsuite/ld-or1k/or1k.exp                 |   91 ++
 ld/testsuite/ld-or1k/plt1.dd                  |   27 +
 ld/testsuite/ld-or1k/plt1.s                   |   11 +
 ld/testsuite/ld-or1k/plt1.x.dd                |   27 +
 ld/testsuite/ld-or1k/plta1.dd                 |   27 +
 ld/testsuite/ld-or1k/plta1.s                  |   11 +
 ld/testsuite/ld-or1k/pltlib.s                 |   12 +
 opcodes/or1k-asm.c                            |  587 +++++-----
 opcodes/or1k-desc.c                           |   34 +-
 opcodes/or1k-desc.h                           |   48 +-
 opcodes/or1k-dis.c                            |    3 +
 opcodes/or1k-ibld.c                           |   29 +-
 opcodes/or1k-opc.c                            |   44 +-
 opcodes/or1k-opc.h                            |   65 +-
 opcodes/or1k-opinst.c                         |   98 +-
 sim/common/cgen-ops.h                         |   36 +
 sim/or1k/cpu.h                                |   32 +
 sim/or1k/decode.c                             |  239 +++-
 sim/or1k/decode.h                             |   82 +-
 sim/or1k/model.c                              |  186 ++-
 sim/or1k/sem-switch.c                         |  281 ++++-
 sim/or1k/sem.c                                |  293 ++++-
 sim/testsuite/sim/or1k/div.S                  |   12 +-
 sim/testsuite/sim/or1k/mul.S                  |  109 +-
 41 files changed, 3643 insertions(+), 1196 deletions(-)
 rename gas/testsuite/gas/or1k/{allinsn.exp => or1k.exp} (83%)
 create mode 100644 gas/testsuite/gas/or1k/reloc-1.d
 create mode 100644 gas/testsuite/gas/or1k/reloc-1.s
 create mode 100644 gas/testsuite/gas/or1k/reloc-2.l
 create mode 100644 gas/testsuite/gas/or1k/reloc-2.s
 create mode 100644 ld/testsuite/ld-or1k/offsets1.d
 create mode 100644 ld/testsuite/ld-or1k/offsets1.s
 create mode 100644 ld/testsuite/ld-or1k/or1k.exp
 create mode 100644 ld/testsuite/ld-or1k/plt1.dd
 create mode 100644 ld/testsuite/ld-or1k/plt1.s
 create mode 100644 ld/testsuite/ld-or1k/plt1.x.dd
 create mode 100644 ld/testsuite/ld-or1k/plta1.dd
 create mode 100644 ld/testsuite/ld-or1k/plta1.s
 create mode 100644 ld/testsuite/ld-or1k/pltlib.s

-- 
2.17.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 1/4] or1k: Add relocations for high-signed and low-stores
  2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
@ 2018-08-21 14:38 ` Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 2/4] or1k: Fix messages for relocations in shared libraries Stafford Horne
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-08-21 14:38 UTC (permalink / raw)
  To: openrisc

From: Richard Henderson <rth@redhat.com>

This patch adds the following target relocations:

 - BFD_RELOC_HI16_S		High 16-bit relocation, for used with signed
   asm: ha()			lower.
 - BFD_RELOC_HI16_S_GOTOFF	High 16-bit GOT offset relocation for local
   asm: gotoffha()		symbols, for use with signed lower.
 - BFD_RELOC_OR1K_TLS_IE_AHI16	High 16-bit TLS relocation with initial
   asm: gottpoffha()		executable calculation, for use with signed
				lower.
 - BFD_RELOC_OR1K_TLS_LE_AHI16	High 16-bit TLS relocation for local executable
   asm: tpoffha()		variables, for use with signed lower.

 - BFD_RELOC_OR1K_SLO16		Split lower 16-bit relocation, used with
   asm: lo()			OpenRISC store instructions.
 - BFD_RELOC_OR1K_GOTOFF_SLO16	Split lower 16-bit GOT offset relocation for
   asm: gotofflo()		local symbols, used with OpenRISC store
				instructions.
 - BFD_RELOC_OR1K_TLS_LE_SLO16	Split lower 16-bit relocation for TLS local
   asm: tpofflo()		executable variables, used with OpenRISC store
				instructions.

bfd/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* bfd-in2.h: Regenerated.
	* elf32-or1k.c (N_ONES): New macro.
	(or1k_elf_howto_table): Fix R_OR1K_PLT26 to complain on overflow.
	Add definitions for R_OR1K_TLS_TPOFF, R_OR1K_TLS_DTPOFF,
	R_OR1K_TLS_DTPMOD, R_OR1K_AHI16, R_OR1K_GOTOFF_AHI16,
	R_OR1K_TLS_IE_AHI16, R_OR1K_TLS_LE_AHI16, R_OR1K_SLO16,
	R_OR1K_GOTOFF_SLO16, R_OR1K_TLS_LE_SLO16.
	(or1k_reloc_map): Add entries for BFD_RELOC_HI16_S,
	BFD_RELOC_LO16_GOTOFF, BFD_RELOC_HI16_GOTOFF, BFD_RELOC_HI16_S_GOTOFF,
	BFD_RELOC_OR1K_TLS_IE_AHI16, BFD_RELOC_OR1K_TLS_LE_AHI16,
	BFD_RELOC_OR1K_SLO16, BFD_RELOC_OR1K_GOTOFF_SLO16,
	BFD_RELOC_OR1K_TLS_LE_SLO16.
	(or1k_reloc_type_lookup): Change search loop to start ad index 0 and
	also check results before returning.
	(or1k_reloc_name_lookup): Simplify loop to use R_OR1K_max as index
	limit.
	(or1k_final_link_relocate): New function.
	(or1k_elf_relocate_section): Add support for new AHI and SLO
	relocations.  Use or1k_final_link_relocate instead of generic
	_bfd_final_link_relocate.
	(or1k_elf_check_relocs): Add support for new AHI and SLO relocations.
	* reloc.c: Add new enums for BFD_RELOC_OR1K_SLO16,
	BFD_RELOC_OR1K_GOTOFF_SLO16, BFD_RELOC_OR1K_TLS_IE_AHI16,
	BFD_RELOC_OR1K_TLS_IE_AHI16, BFD_RELOC_OR1K_TLS_LE_AHI16,
	BFD_RELOC_OR1K_TLS_LE_SLO16.  Remove unused BFD_RELOC_OR1K_GOTOFF_HI16
	and BFD_RELOC_OR1K_GOTOFF_LO16.
	* libbfd.h: Regenerated.

cpu/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* or1k.opc: Add RTYPE_ enum.
	(INVALID_STORE_RELOC): New string.
	(or1k_imm16_relocs): New array array.
	(parse_reloc): New static function that just does the parsing.
	(parse_imm16): New static function for generic parsing.
	(parse_simm16): Change to just call parse_imm16.
	(parse_simm16_split): New function.
	(parse_uimm16): Change to call parse_imm16.
	(parse_uimm16_split): New function.
	* or1korbis.cpu (simm16-split): Change to use new simm16_split.
	(uimm16-split): Change to use new uimm16_split.

gas/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* testsuite/gas/or1k/allinsn.d (l_ha): Add result for ha() relocation.
	* testsuite/gas/or1k/allinsn.s (l_ha): Add test for ha() relocations.
	* testsuite/gas/or1k/allinsn.exp: Renamed to or1k.exp.
	* testsuite/gas/or1k/or1k.exp: Add reloc-2 list test.
	* testsuite/gas/or1k/reloc-1.d: New file.
	* testsuite/gas/or1k/reloc-1.s: New file.
	* testsuite/gas/or1k/reloc-2.l: New file.
	* testsuite/gas/or1k/reloc-2.s: New file.

include/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* elf/or1k.h (elf_or1k_reloc_type): Add R_OR1K_AHI16,
	R_OR1K_GOTOFF_AHI16, R_OR1K_TLS_IE_AHI16, R_OR1K_TLS_LE_AHI16,
	R_OR1K_SLO16, R_OR1K_GOTOFF_SLO16, R_OR1K_TLS_LE_SLO16.

ld/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* testsuite/ld-or1k/offsets1.d: New file.
	* testsuite/ld-or1k/offsets1.s: New file.
	* testsuite/ld-or1k/or1k.exp: New file.

opcodes/ChangeLog:

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

	* or1k-asm.c: Regenerate.
---
 bfd/bfd-in2.h                                 |   7 +-
 bfd/elf32-or1k.c                              | 360 +++++++++++--
 bfd/libbfd.h                                  |   7 +-
 bfd/reloc.c                                   |  12 +-
 cpu/or1k.opc                                  | 475 +++++++-----------
 cpu/or1korbis.cpu                             |   4 +-
 gas/testsuite/gas/or1k/allinsn.d              |  19 +-
 gas/testsuite/gas/or1k/allinsn.s              |   2 +
 .../gas/or1k/{allinsn.exp => or1k.exp}        |   1 +
 gas/testsuite/gas/or1k/reloc-1.d              |  56 +++
 gas/testsuite/gas/or1k/reloc-1.s              |  56 +++
 gas/testsuite/gas/or1k/reloc-2.l              |  10 +
 gas/testsuite/gas/or1k/reloc-2.s              |  12 +
 include/elf/or1k.h                            |   7 +
 ld/testsuite/ld-or1k/offsets1.d               | 212 ++++++++
 ld/testsuite/ld-or1k/offsets1.s               |  14 +
 ld/testsuite/ld-or1k/or1k.exp                 |  69 +++
 opcodes/or1k-asm.c                            | 439 ++++++----------
 18 files changed, 1149 insertions(+), 613 deletions(-)
 rename gas/testsuite/gas/or1k/{allinsn.exp => or1k.exp} (83%)
 create mode 100644 gas/testsuite/gas/or1k/reloc-1.d
 create mode 100644 gas/testsuite/gas/or1k/reloc-1.s
 create mode 100644 gas/testsuite/gas/or1k/reloc-2.l
 create mode 100644 gas/testsuite/gas/or1k/reloc-2.s
 create mode 100644 ld/testsuite/ld-or1k/offsets1.d
 create mode 100644 ld/testsuite/ld-or1k/offsets1.s
 create mode 100644 ld/testsuite/ld-or1k/or1k.exp

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 58afff24c9..a51ead9273 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5467,12 +5467,12 @@ then it may be truncated to 8 bits.  */
 
 /* OpenRISC 1000 Relocations.  */
   BFD_RELOC_OR1K_REL_26,
+  BFD_RELOC_OR1K_SLO16,
   BFD_RELOC_OR1K_GOTPC_HI16,
   BFD_RELOC_OR1K_GOTPC_LO16,
   BFD_RELOC_OR1K_GOT16,
   BFD_RELOC_OR1K_PLT26,
-  BFD_RELOC_OR1K_GOTOFF_HI16,
-  BFD_RELOC_OR1K_GOTOFF_LO16,
+  BFD_RELOC_OR1K_GOTOFF_SLO16,
   BFD_RELOC_OR1K_COPY,
   BFD_RELOC_OR1K_GLOB_DAT,
   BFD_RELOC_OR1K_JMP_SLOT,
@@ -5484,9 +5484,12 @@ then it may be truncated to 8 bits.  */
   BFD_RELOC_OR1K_TLS_LDO_HI16,
   BFD_RELOC_OR1K_TLS_LDO_LO16,
   BFD_RELOC_OR1K_TLS_IE_HI16,
+  BFD_RELOC_OR1K_TLS_IE_AHI16,
   BFD_RELOC_OR1K_TLS_IE_LO16,
   BFD_RELOC_OR1K_TLS_LE_HI16,
+  BFD_RELOC_OR1K_TLS_LE_AHI16,
   BFD_RELOC_OR1K_TLS_LE_LO16,
+  BFD_RELOC_OR1K_TLS_LE_SLO16,
   BFD_RELOC_OR1K_TLS_TPOFF,
   BFD_RELOC_OR1K_TLS_DTPOFF,
   BFD_RELOC_OR1K_TLS_DTPMOD,
diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
index 91b780fedf..9f3f6a6dd8 100644
--- a/bfd/elf32-or1k.c
+++ b/bfd/elf32-or1k.c
@@ -27,6 +27,8 @@
 #include "elf/or1k.h"
 #include "libiberty.h"
 
+#define N_ONES(X)	(((bfd_vma)2 << (X)) - 1)
+
 #define PLT_ENTRY_SIZE 20
 
 #define PLT0_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(.got+4) */
@@ -278,7 +280,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 	 26,			/* Bitsize.  */
 	 TRUE,			/* PC_relative.  */
 	 0,			/* Bitpos.  */
-	 complain_overflow_dont, /* Complain on overflow.  */
+	 complain_overflow_signed, /* Complain on overflow.  */
 	 bfd_elf_generic_reloc,/* Special Function.  */
 	 "R_OR1K_PLT26",	/* Name.  */
 	 FALSE,		/* Partial Inplace.  */
@@ -510,6 +512,145 @@ static reloc_howto_type or1k_elf_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_OR1K_TLS_TPOFF,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_TPOFF",    /* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_DTPOFF,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_DTPOFF",   /* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_DTPMOD,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_DTPMOD",   /* name */
+	 FALSE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_AHI16,		/* type */
+	 16,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_AHI16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_GOTOFF_AHI16,	/* type */
+	 16,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_GOTOFF_AHI16", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_IE_AHI16,   /* type */
+	 16,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_IE_AHI16", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_LE_AHI16,	/* type */
+	 16,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_LE_AHI16", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_SLO16,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_SLO16",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_GOTOFF_SLO16,	/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_GOTOFF_SLO16", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_LE_SLO16,   /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_LE_SLO16", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 };
 
 /* Map BFD reloc types to Or1k ELF reloc types.  */
@@ -528,18 +669,20 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
   { BFD_RELOC_8,		R_OR1K_8 },
   { BFD_RELOC_LO16,		R_OR1K_LO_16_IN_INSN },
   { BFD_RELOC_HI16,		R_OR1K_HI_16_IN_INSN },
+  { BFD_RELOC_HI16_S,		R_OR1K_AHI16 },
   { BFD_RELOC_OR1K_REL_26,	R_OR1K_INSN_REL_26 },
   { BFD_RELOC_VTABLE_ENTRY,	R_OR1K_GNU_VTENTRY },
   { BFD_RELOC_VTABLE_INHERIT,	R_OR1K_GNU_VTINHERIT },
   { BFD_RELOC_32_PCREL,		R_OR1K_32_PCREL },
   { BFD_RELOC_16_PCREL,		R_OR1K_16_PCREL },
   { BFD_RELOC_8_PCREL,		R_OR1K_8_PCREL },
+  { BFD_RELOC_LO16_GOTOFF,	R_OR1K_GOTOFF_LO16 },
+  { BFD_RELOC_HI16_GOTOFF,	R_OR1K_GOTOFF_HI16 },
+  { BFD_RELOC_HI16_S_GOTOFF,	R_OR1K_GOTOFF_AHI16 },
   { BFD_RELOC_OR1K_GOTPC_HI16,	R_OR1K_GOTPC_HI16 },
   { BFD_RELOC_OR1K_GOTPC_LO16,	R_OR1K_GOTPC_LO16 },
   { BFD_RELOC_OR1K_GOT16,	R_OR1K_GOT16 },
   { BFD_RELOC_OR1K_PLT26,	R_OR1K_PLT26 },
-  { BFD_RELOC_OR1K_GOTOFF_HI16, R_OR1K_GOTOFF_HI16 },
-  { BFD_RELOC_OR1K_GOTOFF_LO16, R_OR1K_GOTOFF_LO16 },
   { BFD_RELOC_OR1K_GLOB_DAT,	R_OR1K_GLOB_DAT },
   { BFD_RELOC_OR1K_COPY,	R_OR1K_COPY },
   { BFD_RELOC_OR1K_JMP_SLOT,	R_OR1K_JMP_SLOT },
@@ -552,8 +695,13 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
   { BFD_RELOC_OR1K_TLS_LDO_LO16,	R_OR1K_TLS_LDO_LO16 },
   { BFD_RELOC_OR1K_TLS_IE_HI16, R_OR1K_TLS_IE_HI16 },
   { BFD_RELOC_OR1K_TLS_IE_LO16, R_OR1K_TLS_IE_LO16 },
+  { BFD_RELOC_OR1K_TLS_IE_AHI16, R_OR1K_TLS_IE_AHI16 },
   { BFD_RELOC_OR1K_TLS_LE_HI16, R_OR1K_TLS_LE_HI16 },
   { BFD_RELOC_OR1K_TLS_LE_LO16, R_OR1K_TLS_LE_LO16 },
+  { BFD_RELOC_OR1K_TLS_LE_AHI16, R_OR1K_TLS_LE_AHI16 },
+  { BFD_RELOC_OR1K_SLO16,	R_OR1K_SLO16 },
+  { BFD_RELOC_OR1K_GOTOFF_SLO16, R_OR1K_GOTOFF_SLO16 },
+  { BFD_RELOC_OR1K_TLS_LE_SLO16, R_OR1K_TLS_LE_SLO16 },
 };
 
 #define TLS_UNKNOWN    0
@@ -671,13 +819,19 @@ or1k_elf_link_hash_table_create (bfd *abfd)
 
 static reloc_howto_type *
 or1k_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
-			bfd_reloc_code_real_type code)
+			bfd_reloc_code_real_type bcode)
 {
   unsigned int i;
 
-  for (i = ARRAY_SIZE (or1k_reloc_map); i--;)
-    if (or1k_reloc_map[i].bfd_reloc_val == code)
-      return & or1k_elf_howto_table[or1k_reloc_map[i].or1k_reloc_val];
+  for (i = 0; i < ARRAY_SIZE (or1k_reloc_map); i++)
+    if (or1k_reloc_map[i].bfd_reloc_val == bcode)
+      {
+	unsigned int ocode = or1k_reloc_map[i].or1k_reloc_val;
+	if (ocode < (unsigned int) R_OR1K_max)
+	  return &or1k_elf_howto_table[ocode];
+	else
+	  break;
+      }
 
   return NULL;
 }
@@ -688,10 +842,7 @@ or1k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < (sizeof (or1k_elf_howto_table)
-	    / sizeof (or1k_elf_howto_table[0]));
-       i++)
+  for (i = 0; i < R_OR1K_max; i++)
     if (or1k_elf_howto_table[i].name != NULL
 	&& strcasecmp (or1k_elf_howto_table[i].name, r_name) == 0)
       return &or1k_elf_howto_table[i];
@@ -736,6 +887,134 @@ tpoff (struct bfd_link_info *info, bfd_vma address)
   return (address - elf_hash_table (info)->tls_sec->vma);
 }
 
+/* Like _bfd_final_link_relocate, but handles non-contiguous fields.  */
+
+static bfd_reloc_status_type
+or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+			  asection *input_section, bfd_byte *contents,
+			  bfd_vma offset, bfd_vma value)
+{
+  bfd_reloc_status_type status = bfd_reloc_ok;
+  int size = bfd_get_reloc_size (howto);
+  unsigned bitsize, bits;
+  bfd_vma x;
+
+  /* Sanity check the address.  */
+  if (offset + size > bfd_get_section_limit_octets (input_bfd, input_section))
+    return bfd_reloc_outofrange;
+
+  if (howto->pc_relative)
+    {
+      value -= (input_section->output_section->vma
+		+ input_section->output_offset);
+      if (howto->pcrel_offset)
+	value -= offset;
+    }
+
+  switch (howto->type)
+    {
+    case R_OR1K_AHI16:
+    case R_OR1K_GOTOFF_AHI16:
+    case R_OR1K_TLS_IE_AHI16:
+    case R_OR1K_TLS_LE_AHI16:
+      /* Adjust the operand to match with a signed LO16.  */
+      value += 0x8000;
+      break;
+
+    case R_OR1K_INSN_REL_26:
+      /* Diagnose mis-aligned branch targets.  */
+      if (value & 3)
+	status = bfd_reloc_dangerous;
+      break;
+    }
+
+  bitsize = howto->bitsize;
+  bits = bitsize + howto->rightshift;
+  switch (howto->complain_on_overflow)
+    {
+    case complain_overflow_dont:
+      break;
+    case complain_overflow_signed:
+      if (bits < sizeof (bfd_vma) * 8)
+	{
+	  bfd_signed_vma lim = (bfd_vma)1 << bits;
+	  bfd_signed_vma svalue = value;
+
+	  if (svalue < -lim || svalue >= lim)
+	    status = bfd_reloc_overflow;
+	}
+      break;
+    case complain_overflow_unsigned:
+      if (bits < sizeof (bfd_vma) * 8)
+	{
+	  bfd_vma lim = (bfd_vma)1 << bits;
+	  if (value >= lim)
+	    status = bfd_reloc_overflow;
+	}
+      break;
+    case complain_overflow_bitfield:
+    default:
+      abort ();
+    }
+
+  value >>= howto->rightshift;
+
+  /* If we're overwriting the entire destination,
+     then no need to read the current contents.  */
+  if (size == 0 || howto->dst_mask == N_ONES (size))
+    x = 0;
+  else
+    {
+      BFD_ASSERT (size == 4);
+      x = bfd_get_32 (input_bfd, contents + offset);
+    }
+
+  switch (howto->type)
+    {
+    case R_OR1K_SLO16:
+    case R_OR1K_GOTOFF_SLO16:
+    case R_OR1K_TLS_LE_SLO16:
+      /* The split imm16 field used for stores.  */
+      x = (x & ~0x3e007ff) | ((value & 0xf800) << 10) | (value & 0x7ff);
+      break;
+
+    default:
+      {
+	bfd_vma fieldmask = howto->dst_mask;
+	value <<= howto->bitpos;
+	x = (x & ~fieldmask) | (value & fieldmask);
+      }
+      break;
+    }
+
+  /* Put the relocated value back in the object file.  */
+  switch (size)
+    {
+    default:
+      abort ();
+    case 0:
+      break;
+    case 1:
+      bfd_put_8 (input_bfd, x, contents + offset);
+      break;
+    case 2:
+      bfd_put_16 (input_bfd, x, contents + offset);
+      break;
+    case 4:
+      bfd_put_32 (input_bfd, x, contents + offset);
+      break;
+    case 8:
+#ifdef BFD64
+      bfd_put_64 (input_bfd, x, contents + offset);
+#else
+      abort ();
+#endif
+      break;
+    }
+
+  return status;
+}
+
 /* Relocate an Or1k ELF section.
 
    The RELOCATE_SECTION function is called by the new ELF backend linker
@@ -972,6 +1251,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 	case R_OR1K_GOTOFF_LO16:
 	case R_OR1K_GOTOFF_HI16:
+	case R_OR1K_GOTOFF_AHI16:
+	case R_OR1K_GOTOFF_SLO16:
 	  /* Relocation is offset from GOT.  */
 	  BFD_ASSERT (sgot != NULL);
 	  relocation
@@ -983,6 +1264,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	case R_OR1K_INSN_REL_26:
 	case R_OR1K_HI_16_IN_INSN:
 	case R_OR1K_LO_16_IN_INSN:
+	case R_OR1K_AHI16:
+	case R_OR1K_SLO16:
 	case R_OR1K_32:
 	  /* R_OR1K_16? */
 	  {
@@ -1080,11 +1363,11 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	  bfd_set_error (bfd_error_bad_value);
 	  return FALSE;
 
-
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
+	case R_OR1K_TLS_IE_AHI16:
 	  {
 	    bfd_vma gotoff;
 	    Elf_Internal_Rela rela;
@@ -1196,9 +1479,11 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	    relocation = sgot->output_offset + gotoff;
 	    break;
 	  }
+
 	case R_OR1K_TLS_LE_HI16:
 	case R_OR1K_TLS_LE_LO16:
-
+	case R_OR1K_TLS_LE_AHI16:
+	case R_OR1K_TLS_LE_SLO16:
 	  /* Relocation is offset from TP.  */
 	  relocation = tpoff (info, relocation);
 	  break;
@@ -1218,8 +1503,9 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	default:
 	  break;
 	}
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
-				    rel->r_offset, relocation, rel->r_addend);
+
+      r = or1k_final_link_relocate (howto, input_bfd, input_section, contents,
+				    rel->r_offset, relocation + rel->r_addend);
 
       if (r != bfd_reloc_ok)
 	{
@@ -1329,6 +1615,7 @@ or1k_elf_check_relocs (bfd *abfd,
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
       unsigned char tls_type;
+      int r_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -1341,7 +1628,8 @@ or1k_elf_check_relocs (bfd *abfd,
 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 	}
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      r_type = ELF32_R_TYPE (rel->r_info);
+      switch (r_type)
 	{
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
@@ -1355,10 +1643,13 @@ or1k_elf_check_relocs (bfd *abfd,
 	  break;
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
+	case R_OR1K_TLS_IE_AHI16:
 	  tls_type = TLS_IE;
 	  break;
 	case R_OR1K_TLS_LE_HI16:
 	case R_OR1K_TLS_LE_LO16:
+	case R_OR1K_TLS_LE_AHI16:
+	case R_OR1K_TLS_LE_SLO16:
 	  tls_type = TLS_LE;
 	  break;
 	default:
@@ -1387,7 +1678,7 @@ or1k_elf_check_relocs (bfd *abfd,
 	  local_tls_type[r_symndx] = tls_type;
 	}
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      switch (r_type)
 	{
 	  /* This relocation describes the C++ object vtable hierarchy.
 	     Reconstruct it for later use during GC.  */
@@ -1415,23 +1706,11 @@ or1k_elf_check_relocs (bfd *abfd,
 	  break;
 
 	case R_OR1K_GOT16:
-	case R_OR1K_GOTOFF_HI16:
-	case R_OR1K_GOTOFF_LO16:
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
-	  if (htab->root.sgot == NULL)
-	    {
-	      if (dynobj == NULL)
-		htab->root.dynobj = dynobj = abfd;
-	      if (!_bfd_elf_create_got_section (dynobj, info))
-		return FALSE;
-	    }
-
-	  if (ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_HI16 &&
-	      ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_LO16)
-	    {
+	case R_OR1K_TLS_IE_AHI16:
 	      if (h != NULL)
 		h->got.refcount += 1;
 	      else
@@ -1453,14 +1732,27 @@ or1k_elf_check_relocs (bfd *abfd,
 		    }
 		  local_got_refcounts[r_symndx] += 1;
 		}
+	  /* FALLTHRU */
+
+	case R_OR1K_GOTOFF_HI16:
+	case R_OR1K_GOTOFF_LO16:
+	case R_OR1K_GOTOFF_AHI16:
+	case R_OR1K_GOTOFF_SLO16:
+	  if (htab->root.sgot == NULL)
+	    {
+	      if (dynobj == NULL)
+		htab->root.dynobj = dynobj = abfd;
+	      if (!_bfd_elf_create_got_section (dynobj, info))
+		return FALSE;
 	    }
 	  break;
 
 	case R_OR1K_INSN_REL_26:
 	case R_OR1K_HI_16_IN_INSN:
 	case R_OR1K_LO_16_IN_INSN:
+	case R_OR1K_AHI16:
+	case R_OR1K_SLO16:
 	case R_OR1K_32:
-	  /* R_OR1K_16? */
 	  {
 	    if (h != NULL && !bfd_link_pic (info))
 	      {
@@ -1469,7 +1761,7 @@ or1k_elf_check_relocs (bfd *abfd,
 
 		/* We may also need a .plt entry.  */
 		h->plt.refcount += 1;
-		if (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26)
+		if (r_type != R_OR1K_INSN_REL_26)
 		  h->pointer_equality_needed = 1;
 	      }
 
@@ -1497,7 +1789,7 @@ or1k_elf_check_relocs (bfd *abfd,
 
 	    if ((bfd_link_pic (info)
 		 && (sec->flags & SEC_ALLOC) != 0
-		 && (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26
+		 && (r_type != R_OR1K_INSN_REL_26
 		     || (h != NULL
 			 && (!SYMBOLIC_BIND (info, h)
 			     || h->root.type == bfd_link_hash_defweak
@@ -1593,7 +1885,7 @@ or1k_elf_check_relocs (bfd *abfd,
 		  }
 
 		p->count += 1;
-		if (ELF32_R_TYPE (rel->r_info) == R_OR1K_INSN_REL_26)
+		if (r_type == R_OR1K_INSN_REL_26)
 		  p->pc_count += 1;
 	      }
 	  }
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 6c1e1ea9a5..f887e516ae 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2642,12 +2642,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_CRIS_DTPMOD",
   "BFD_RELOC_CRIS_32_IE",
   "BFD_RELOC_OR1K_REL_26",
+  "BFD_RELOC_OR1K_SLO16",
   "BFD_RELOC_OR1K_GOTPC_HI16",
   "BFD_RELOC_OR1K_GOTPC_LO16",
   "BFD_RELOC_OR1K_GOT16",
   "BFD_RELOC_OR1K_PLT26",
-  "BFD_RELOC_OR1K_GOTOFF_HI16",
-  "BFD_RELOC_OR1K_GOTOFF_LO16",
+  "BFD_RELOC_OR1K_GOTOFF_SLO16",
   "BFD_RELOC_OR1K_COPY",
   "BFD_RELOC_OR1K_GLOB_DAT",
   "BFD_RELOC_OR1K_JMP_SLOT",
@@ -2659,9 +2659,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_OR1K_TLS_LDO_HI16",
   "BFD_RELOC_OR1K_TLS_LDO_LO16",
   "BFD_RELOC_OR1K_TLS_IE_HI16",
+  "BFD_RELOC_OR1K_TLS_IE_AHI16",
   "BFD_RELOC_OR1K_TLS_IE_LO16",
   "BFD_RELOC_OR1K_TLS_LE_HI16",
+  "BFD_RELOC_OR1K_TLS_LE_AHI16",
   "BFD_RELOC_OR1K_TLS_LE_LO16",
+  "BFD_RELOC_OR1K_TLS_LE_SLO16",
   "BFD_RELOC_OR1K_TLS_TPOFF",
   "BFD_RELOC_OR1K_TLS_DTPOFF",
   "BFD_RELOC_OR1K_TLS_DTPMOD",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index aaf3a801fd..de870441df 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6134,6 +6134,8 @@ ENUMDOC
 
 ENUM
   BFD_RELOC_OR1K_REL_26
+ENUMX
+  BFD_RELOC_OR1K_SLO16
 ENUMX
   BFD_RELOC_OR1K_GOTPC_HI16
 ENUMX
@@ -6143,9 +6145,7 @@ ENUMX
 ENUMX
   BFD_RELOC_OR1K_PLT26
 ENUMX
-  BFD_RELOC_OR1K_GOTOFF_HI16
-ENUMX
-  BFD_RELOC_OR1K_GOTOFF_LO16
+  BFD_RELOC_OR1K_GOTOFF_SLO16
 ENUMX
   BFD_RELOC_OR1K_COPY
 ENUMX
@@ -6168,12 +6168,18 @@ ENUMX
   BFD_RELOC_OR1K_TLS_LDO_LO16
 ENUMX
   BFD_RELOC_OR1K_TLS_IE_HI16
+ENUMX
+  BFD_RELOC_OR1K_TLS_IE_AHI16
 ENUMX
   BFD_RELOC_OR1K_TLS_IE_LO16
 ENUMX
   BFD_RELOC_OR1K_TLS_LE_HI16
+ENUMX
+  BFD_RELOC_OR1K_TLS_LE_AHI16
 ENUMX
   BFD_RELOC_OR1K_TLS_LE_LO16
+ENUMX
+  BFD_RELOC_OR1K_TLS_LE_SLO16
 ENUMX
   BFD_RELOC_OR1K_TLS_TPOFF
 ENUMX
diff --git a/cpu/or1k.opc b/cpu/or1k.opc
index 98b7532746..20b6820059 100644
--- a/cpu/or1k.opc
+++ b/cpu/or1k.opc
@@ -48,6 +48,7 @@
 /* -- asm.c */
 
 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
+static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
 
 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
 
@@ -81,315 +82,186 @@ parse_disp26 (CGEN_CPU_DESC cd,
   return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
 }
 
+enum {
+  RTYPE_LO = 0,
+  RTYPE_HI = 1,
+  RTYPE_AHI = 2,
+  RTYPE_SLO = 3,
+
+  RTYPE_GOT      = (1 << 2),
+  RTYPE_GOTPC    = (2 << 2),
+  RTYPE_GOTOFF   = (3 << 2),
+  RTYPE_TLSGD    = (4 << 2),
+  RTYPE_TLSLDM   = (5 << 2),
+  RTYPE_DTPOFF   = (6 << 2),
+  RTYPE_GOTTPOFF = (7 << 2),
+  RTYPE_TPOFF    = (8 << 2),
+};
+
+static const bfd_reloc_code_real_type or1k_imm16_relocs[][4] = {
+  { BFD_RELOC_LO16,
+    BFD_RELOC_HI16,
+    BFD_RELOC_HI16_S,
+    BFD_RELOC_OR1K_SLO16 },
+  { BFD_RELOC_OR1K_GOT16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_GOTPC_LO16,
+    BFD_RELOC_OR1K_GOTPC_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_LO16_GOTOFF,
+    BFD_RELOC_HI16_GOTOFF,
+    BFD_RELOC_HI16_S_GOTOFF,
+    BFD_RELOC_OR1K_GOTOFF_SLO16 },
+  { BFD_RELOC_OR1K_TLS_GD_LO16,
+    BFD_RELOC_OR1K_TLS_GD_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LDM_LO16,
+    BFD_RELOC_OR1K_TLS_LDM_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LDO_LO16,
+    BFD_RELOC_OR1K_TLS_LDO_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_IE_LO16,
+    BFD_RELOC_OR1K_TLS_IE_HI16,
+    BFD_RELOC_OR1K_TLS_IE_AHI16,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LE_LO16,
+    BFD_RELOC_OR1K_TLS_LE_HI16,
+    BFD_RELOC_OR1K_TLS_LE_AHI16,
+    BFD_RELOC_OR1K_TLS_LE_SLO16 }
+};
+
+static int
+parse_reloc(const char **strp)
+{
+    const char *str = *strp;
+    int ret = 0;
+
+    if (strncasecmp (str, "got(", 4) == 0)
+      {
+	*strp = str + 4;
+	return RTYPE_GOT | RTYPE_LO;
+      }
+
+    if (strncasecmp (str, "gotpc", 5) == 0)
+      {
+	str += 5;
+	ret = RTYPE_GOTPC;
+      }
+    else if (strncasecmp (str, "gotoff", 6) == 0)
+      {
+	str += 6;
+	ret = RTYPE_GOTOFF;
+      }
+    else if (strncasecmp (str, "tlsgd", 5) == 0)
+      {
+	str += 5;
+	ret = RTYPE_TLSGD;
+      }
+    else if (strncasecmp (str, "tlsldm", 6) == 0)
+      {
+	str += 6;
+	ret = RTYPE_TLSLDM;
+      }
+    else if (strncasecmp (str, "dtpoff", 6) == 0)
+      {
+	str += 6;
+	ret = RTYPE_DTPOFF;
+      }
+    else if (strncasecmp (str, "gottpoff", 8) == 0)
+      {
+	str += 8;
+	ret = RTYPE_GOTTPOFF;
+      }
+    else if (strncasecmp (str, "tpoff", 5) == 0)
+      {
+	str += 5;
+	ret = RTYPE_TPOFF;
+      }
+
+    if (strncasecmp (str, "hi(", 3) == 0)
+      {
+	str += 3;
+	ret |= RTYPE_HI;
+      }
+    else if (strncasecmp (str, "lo(", 3) == 0)
+      {
+	str += 3;
+	ret |= RTYPE_LO;
+      }
+    else if (strncasecmp (str, "ha(", 3) == 0)
+      {
+	str += 3;
+	ret |= RTYPE_AHI;
+      }
+    else
+      return -1;
+
+    *strp = str;
+    return ret;
+}
+
 static const char *
-parse_simm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, long * valuep)
+parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
+	     long *valuep, int splitp)
 {
   const char *errmsg;
   enum cgen_parse_operand_result result_type;
-  long ret;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+  int reloc_type;
+  bfd_vma ret;
 
   if (**strp == '#')
     ++*strp;
 
-  if (strncasecmp (*strp, "hi(", 3) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 3;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
-				   & result_type, & value);
-      if (**strp != ')')
-	errmsg = MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-
-      ret = value;
-
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	{
-	  ret >>= 16;
-	  ret &= 0xffff;
-	  ret = (ret ^ 0x8000) - 0x8000;
-	}
-    }
-  else if (strncasecmp (*strp, "lo(", 3) == 0)
+  reloc_type = parse_reloc (strp);
+  if (reloc_type >= 0)
     {
-      bfd_vma value;
-
-      *strp += 3;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-
-      ret = value;
-
-      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+      if (splitp)
 	{
-	  ret &= 0xffff;
-	  ret = (ret ^ 0x8000) - 0x8000;
+	  if ((reloc_type & 3) == RTYPE_LO && reloc_type != RTYPE_GOT)
+	    reloc_type |= RTYPE_SLO;
+	  else
+	    return INVALID_STORE_RELOC;
 	}
+      reloc = or1k_imm16_relocs[reloc_type >> 2][reloc_type & 3];
     }
-  else if (strncasecmp (*strp, "got(", 4) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 4;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_OR1K_GOT16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gotpchi(", 8) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTPC_HI16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gotpclo(", 8) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTPC_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gotoffhi(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTOFF_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gotofflo(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTOFF_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tlsgdhi(", 8) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_GD_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tlsgdlo(", 8) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_GD_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tlsldmhi(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDM_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tlsldmlo(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDM_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "dtpoffhi(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDO_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "dtpofflo(", 9) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDO_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gottpoffhi(", 11) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 11;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_IE_HI16,
-				   & result_type, & value);
 
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gottpofflo(", 11) == 0)
+  if (reloc != BFD_RELOC_UNUSED)
     {
       bfd_vma value;
 
-      *strp += 11;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_IE_LO16,
+      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
 				   &result_type, &value);
       if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
+	errmsg = MISSING_CLOSING_PARENTHESIS;
       ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tpoffhi(", 8) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LE_HI16,
-				   & result_type, & value);
 
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tpofflo(", 8) == 0)
-    {
-      bfd_vma value;
+      ret = value;
 
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LE_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+      if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	switch (reloc_type & 3)
+	  {
+	  case RTYPE_AHI:
+	    ret += 0x8000;
+	    /* FALLTHRU */
+	  case RTYPE_HI:
+	    ret >>= 16;
+	    /* FALLTHRU */
+	  case RTYPE_LO:
+	  case RTYPE_SLO:
+	    ret &= 0xffff;
+	    ret = (ret ^ 0x8000) - 0x8000;
+	    break;
+	  default:
+	    abort ();
+	  }
     }
   else
     {
@@ -405,10 +277,33 @@ parse_simm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, long * valuep)
 }
 
 static const char *
-parse_uimm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, unsigned long * valuep)
+parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
 {
-  const char *errmsg = parse_simm16(cd, strp, opindex, (long *) valuep);
+  return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
+}
 
+static const char *
+parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
+		    long *valuep)
+{
+  return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
+}
+
+static const char *
+parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
+	      unsigned long *valuep)
+{
+  const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
+  if (errmsg == NULL)
+    *valuep &= 0xffff;
+  return errmsg;
+}
+
+static const char *
+parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
+		    unsigned long *valuep)
+{
+  const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
   if (errmsg == NULL)
     *valuep &= 0xffff;
   return errmsg;
diff --git a/cpu/or1korbis.cpu b/cpu/or1korbis.cpu
index 408a135fa0..535bd28bff 100644
--- a/cpu/or1korbis.cpu
+++ b/cpu/or1korbis.cpu
@@ -335,7 +335,7 @@
   (attrs (MACH ORBIS-MACHS) SIGN-OPT)
   (type h-simm16)
   (index f-simm16-split)
-  (handlers (parse "simm16"))
+  (handlers (parse "simm16_split"))
 )
 
 (define-operand
@@ -344,7 +344,7 @@
   (attrs (MACH ORBIS-MACHS))
   (type h-uimm16)
   (index f-uimm16-split)
-  (handlers (parse "uimm16"))
+  (handlers (parse "uimm16_split"))
 )
 
 ; Instructions.
diff --git a/gas/testsuite/gas/or1k/allinsn.d b/gas/testsuite/gas/or1k/allinsn.d
index 27884fe82d..1b36cce1bc 100644
--- a/gas/testsuite/gas/or1k/allinsn.d
+++ b/gas/testsuite/gas/or1k/allinsn.d
@@ -679,11 +679,14 @@ Disassembly of section \.text:
 00000824 <l_hi>:
  824:	18 20 de ad 	l\.movhi r1,0xdead
 
-00000828 <l_mac>:
- 828:	c4 01 10 01 	l.mac r1,r2
-
-0000082c <l_maci>:
- 82c:	4c 01 00 00 	l\.maci r1,0
- 830:	4c 02 ff ff 	l\.maci r2,-1
- 834:	4c 02 7f ff 	l\.maci r2,32767
- 838:	4c 02 80 00 	l\.maci r2,-32768
+00000828 <l_ha>:
+ 828:	18 20 de ae 	l\.movhi r1,0xdeae
+
+0000082c <l_mac>:
+ 82c:	c4 01 10 01 	l.mac r1,r2
+
+00000830 <l_maci>:
+ 830:	4c 01 00 00 	l\.maci r1,0
+ 834:	4c 02 ff ff 	l\.maci r2,-1
+ 838:	4c 02 7f ff 	l\.maci r2,32767
+ 83c:	4c 02 80 00 	l\.maci r2,-32768
diff --git a/gas/testsuite/gas/or1k/allinsn.s b/gas/testsuite/gas/or1k/allinsn.s
index 05647f2ffd..321aea3036 100644
--- a/gas/testsuite/gas/or1k/allinsn.s
+++ b/gas/testsuite/gas/or1k/allinsn.s
@@ -667,6 +667,8 @@ l_lo:
 	l.addi	r1, r1, lo(0xdeadbeef)
 l_hi:	
 	l.movhi	r1, hi(0xdeadbeef)
+l_ha:	
+	l.movhi	r1, ha(0xdeadbeef)
 
 l_mac:
 	l.mac r1,r2
diff --git a/gas/testsuite/gas/or1k/allinsn.exp b/gas/testsuite/gas/or1k/or1k.exp
similarity index 83%
rename from gas/testsuite/gas/or1k/allinsn.exp
rename to gas/testsuite/gas/or1k/or1k.exp
index 11eacd766e..e0e0515f42 100644
--- a/gas/testsuite/gas/or1k/allinsn.exp
+++ b/gas/testsuite/gas/or1k/or1k.exp
@@ -2,4 +2,5 @@
 
 if [istarget or1k*-*-*] {
         run_dump_tests [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+	run_list_test "reloc-2" ""
 }
diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
new file mode 100644
index 0000000000..f90a1ae269
--- /dev/null
+++ b/gas/testsuite/gas/or1k/reloc-1.d
@@ -0,0 +1,56 @@
+#as:
+#objdump: -r
+#name: reloc
+
+.*: +file format .*
+
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET   TYPE              VALUE 
+00000000 R_OR1K_HI_16_IN_INSN  x
+00000004 R_OR1K_HI_16_IN_INSN  x
+00000008 R_OR1K_HI_16_IN_INSN  x
+0000000c R_OR1K_HI_16_IN_INSN  x
+00000010 R_OR1K_LO_16_IN_INSN  x
+00000014 R_OR1K_LO_16_IN_INSN  x
+00000018 R_OR1K_LO_16_IN_INSN  x
+0000001c R_OR1K_LO_16_IN_INSN  x
+00000020 R_OR1K_LO_16_IN_INSN  x
+00000024 R_OR1K_LO_16_IN_INSN  x
+00000028 R_OR1K_LO_16_IN_INSN  x
+0000002c R_OR1K_LO_16_IN_INSN  x
+00000030 R_OR1K_LO_16_IN_INSN  x
+00000034 R_OR1K_LO_16_IN_INSN  x
+00000038 R_OR1K_SLO16      x
+0000003c R_OR1K_SLO16      x
+00000040 R_OR1K_SLO16      x
+00000044 R_OR1K_SLO16      x
+00000048 R_OR1K_AHI16      x
+0000004c R_OR1K_AHI16      x
+00000050 R_OR1K_AHI16      x
+00000054 R_OR1K_GOT16      x
+00000058 R_OR1K_GOT16      x
+0000005c R_OR1K_GOT16      x
+00000060 R_OR1K_GOTPC_HI16  _GLOBAL_OFFSET_TABLE_-0x00000004
+00000064 R_OR1K_GOTPC_LO16  _GLOBAL_OFFSET_TABLE_-0x00000008
+00000068 R_OR1K_GOTOFF_HI16  x
+0000006c R_OR1K_GOTOFF_LO16  x
+00000070 R_OR1K_GOTOFF_AHI16  x
+00000074 R_OR1K_GOTOFF_LO16  x
+00000078 R_OR1K_GOTOFF_SLO16  x
+0000007c R_OR1K_TLS_GD_HI16  x
+00000080 R_OR1K_TLS_GD_LO16  x
+00000084 R_OR1K_TLS_LDM_HI16  x
+00000088 R_OR1K_TLS_LDM_LO16  x
+0000008c R_OR1K_TLS_LDO_HI16  x
+00000090 R_OR1K_TLS_LDO_LO16  x
+00000094 R_OR1K_TLS_IE_HI16  x
+00000098 R_OR1K_TLS_IE_LO16  x
+0000009c R_OR1K_TLS_IE_AHI16  x
+000000a0 R_OR1K_TLS_IE_LO16  x
+000000a4 R_OR1K_TLS_LE_HI16  x
+000000a8 R_OR1K_TLS_LE_LO16  x
+000000ac R_OR1K_TLS_LE_AHI16  x
+000000b0 R_OR1K_TLS_LE_LO16  x
+000000b4 R_OR1K_TLS_LE_SLO16  x
+
+
diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
new file mode 100644
index 0000000000..4966dc56be
--- /dev/null
+++ b/gas/testsuite/gas/or1k/reloc-1.s
@@ -0,0 +1,56 @@
+	l.movhi	r3,hi(x)
+	l.ori	r3,r4,hi(x)
+	l.addi	r3,r4,hi(x)
+	l.lwz	r3,hi(x)(r4)
+
+	l.movhi	r3,lo(x)
+	l.ori	r3,r4,lo(x)
+	l.addi	r3,r4,lo(x)
+	l.lwz	r3,lo(x)(r4)
+	l.lws	r3,lo(x)(r4)
+	l.lhz	r3,lo(x)(r4)
+	l.lhs	r3,lo(x)(r4)
+	l.lbz	r3,lo(x)(r4)
+	l.lbs	r3,lo(x)(r4)
+	l.lwa	r3,lo(x)(r4)
+	l.sw	lo(x)(r4),r3
+	l.sh	lo(x)(r4),r3
+	l.sb	lo(x)(r4),r3
+	l.swa	lo(x)(r4),r3
+
+	l.movhi	r3,ha(x)
+	l.ori	r3,r4,ha(x)
+	l.addi	r3,r4,ha(x)
+
+	l.ori	r3,r0,got(x)
+	l.addi	r3,r4,got(x)
+	l.lwz	r3,got(x)(r4)
+
+	l.movhi	r3,gotpchi(_GLOBAL_OFFSET_TABLE_-4)
+	l.ori	r3,r3,gotpclo(_GLOBAL_OFFSET_TABLE_-8)
+
+	l.movhi	r3,gotoffhi(x)
+	l.ori	r3,r3,gotofflo(x)
+	l.movhi	r3,gotoffha(x)
+	l.lwz	r3,gotofflo(x)(r3)
+	l.sw	gotofflo(x)(r3),r3
+
+	l.movhi	r3,tlsgdhi(x)
+	l.ori	r3,r3,tlsgdlo(x)
+
+	l.movhi	r3,tlsldmhi(x)
+	l.ori	r3,r3,tlsldmlo(x)
+
+	l.movhi	r3,dtpoffhi(x)
+	l.ori	r3,r3,dtpofflo(x)
+
+	l.movhi	r3,gottpoffhi(x)
+	l.ori	r3,r3,gottpofflo(x)
+	l.movhi	r3,gottpoffha(x)
+	l.lwz	r3,gottpofflo(x)(r3)
+
+	l.movhi	r3,tpoffhi(x)
+	l.ori	r3,r3,tpofflo(x)
+	l.movhi	r3,tpoffha(x)
+	l.lwz	r3,tpofflo(x)(r3)
+	l.sw	tpofflo(x)(r3),r3
diff --git a/gas/testsuite/gas/or1k/reloc-2.l b/gas/testsuite/gas/or1k/reloc-2.l
new file mode 100644
index 0000000000..7a32a7dc14
--- /dev/null
+++ b/gas/testsuite/gas/or1k/reloc-2.l
@@ -0,0 +1,10 @@
+.*: Assembler messages:
+.*:2: Error: relocation invalid for store .*
+.*:3: Error: relocation invalid for store .*
+.*:4: Error: relocation invalid for store .*
+.*:6: Error: relocation invalid for store .*
+.*:7: Error: relocation invalid for store .*
+.*:8: Error: relocation invalid for store .*
+.*:9: Error: relocation invalid for store .*
+.*:11: Error: relocation invalid for store .*
+.*:12: Error: relocation invalid for store .*
diff --git a/gas/testsuite/gas/or1k/reloc-2.s b/gas/testsuite/gas/or1k/reloc-2.s
new file mode 100644
index 0000000000..835dd1c84b
--- /dev/null
+++ b/gas/testsuite/gas/or1k/reloc-2.s
@@ -0,0 +1,12 @@
+	l.sw	lo(x)(r4),r3
+	l.sw	hi(x)(r4),r3
+	l.sw	ha(x)(r4),r3
+	l.sw	got(x)(r4),r3
+	l.sw	gotofflo(x)(r4),r3
+	l.sw	gotoffhi(x)(r4),r3
+	l.sw	gotoffha(x)(r4),r3
+	l.sw	dtpoffhi(x)(r4),r3
+	l.sw	gottpoffhi(x)(r4),r3
+	l.sw	tpofflo(x)(r4),r3
+	l.sw	tpoffhi(x)(r4),r3
+	l.sw	tpoffha(x)(r4),r3
diff --git a/include/elf/or1k.h b/include/elf/or1k.h
index 0c5e15bcc8..e3291d31d3 100644
--- a/include/elf/or1k.h
+++ b/include/elf/or1k.h
@@ -58,6 +58,13 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
   RELOC_NUMBER (R_OR1K_TLS_TPOFF,     32)
   RELOC_NUMBER (R_OR1K_TLS_DTPOFF,    33)
   RELOC_NUMBER (R_OR1K_TLS_DTPMOD,    34)
+  RELOC_NUMBER (R_OR1K_AHI16,         35)
+  RELOC_NUMBER (R_OR1K_GOTOFF_AHI16,  36)
+  RELOC_NUMBER (R_OR1K_TLS_IE_AHI16,  37)
+  RELOC_NUMBER (R_OR1K_TLS_LE_AHI16,  38)
+  RELOC_NUMBER (R_OR1K_SLO16,         39)
+  RELOC_NUMBER (R_OR1K_GOTOFF_SLO16,  40)
+  RELOC_NUMBER (R_OR1K_TLS_LE_SLO16,  41)
 END_RELOC_NUMBERS (R_OR1K_max)
 
 #define EF_OR1K_NODELAY (1UL << 0)
diff --git a/ld/testsuite/ld-or1k/offsets1.d b/ld/testsuite/ld-or1k/offsets1.d
new file mode 100644
index 0000000000..aff09d4a4b
--- /dev/null
+++ b/ld/testsuite/ld-or1k/offsets1.d
@@ -0,0 +1,212 @@
+#source: store1.s
+#as:
+#ld:
+#objdump: -drj.text
+#target: or1k*-*-*
+
+.*: +file format elf32-or1k
+
+
+Disassembly of section \.text:
+
+.* <_start>:
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 03 00 00 	l.sw 0\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 03 03 e8 	l.sw 1000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 03 07 d0 	l.sw 2000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 23 03 b8 	l.sw 3000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 23 07 a0 	l.sw 4000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 43 03 88 	l.sw 5000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 43 07 70 	l.sw 6000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 63 03 58 	l.sw 7000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 63 07 40 	l.sw 8000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 83 03 28 	l.sw 9000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 83 07 10 	l.sw 10000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 a3 02 f8 	l.sw 11000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 a3 06 e0 	l.sw 12000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 c3 02 c8 	l.sw 13000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 c3 06 b0 	l.sw 14000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 e3 02 98 	l.sw 15000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d4 e3 06 80 	l.sw 16000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 03 02 68 	l.sw 17000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 03 06 50 	l.sw 18000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 23 02 38 	l.sw 19000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 23 06 20 	l.sw 20000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 43 02 08 	l.sw 21000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 43 05 f0 	l.sw 22000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 63 01 d8 	l.sw 23000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 63 05 c0 	l.sw 24000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 83 01 a8 	l.sw 25000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 83 05 90 	l.sw 26000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 a3 01 78 	l.sw 27000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 a3 05 60 	l.sw 28000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 c3 01 48 	l.sw 29000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 c3 05 30 	l.sw 30000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 e3 01 18 	l.sw 31000\(r3\),r0
+.*:	18 60 00 01 	l.movhi r3,0x1
+.*:	d5 e3 05 00 	l.sw 32000\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 03 00 e8 	l.sw -32536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 03 04 d0 	l.sw -31536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 23 00 b8 	l.sw -30536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 23 04 a0 	l.sw -29536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 43 00 88 	l.sw -28536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 43 04 70 	l.sw -27536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 63 00 58 	l.sw -26536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 63 04 40 	l.sw -25536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 83 00 28 	l.sw -24536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 83 04 10 	l.sw -23536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 83 07 f8 	l.sw -22536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 a3 03 e0 	l.sw -21536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 a3 07 c8 	l.sw -20536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 c3 03 b0 	l.sw -19536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 c3 07 98 	l.sw -18536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 e3 03 80 	l.sw -17536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d6 e3 07 68 	l.sw -16536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 03 03 50 	l.sw -15536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 03 07 38 	l.sw -14536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 23 03 20 	l.sw -13536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 23 07 08 	l.sw -12536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 43 02 f0 	l.sw -11536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 43 06 d8 	l.sw -10536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 63 02 c0 	l.sw -9536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 63 06 a8 	l.sw -8536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 83 02 90 	l.sw -7536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 83 06 78 	l.sw -6536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 a3 02 60 	l.sw -5536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 a3 06 48 	l.sw -4536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 c3 02 30 	l.sw -3536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 c3 06 18 	l.sw -2536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 e3 02 00 	l.sw -1536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d7 e3 05 e8 	l.sw -536\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 03 01 d0 	l.sw 464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 03 05 b8 	l.sw 1464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 23 01 a0 	l.sw 2464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 23 05 88 	l.sw 3464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 43 01 70 	l.sw 4464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 43 05 58 	l.sw 5464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 63 01 40 	l.sw 6464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 63 05 28 	l.sw 7464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 83 01 10 	l.sw 8464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 83 04 f8 	l.sw 9464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 a3 00 e0 	l.sw 10464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 a3 04 c8 	l.sw 11464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 c3 00 b0 	l.sw 12464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 c3 04 98 	l.sw 13464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 e3 00 80 	l.sw 14464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d4 e3 04 68 	l.sw 15464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 03 00 50 	l.sw 16464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 03 04 38 	l.sw 17464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 23 00 20 	l.sw 18464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 23 04 08 	l.sw 19464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 23 07 f0 	l.sw 20464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 43 03 d8 	l.sw 21464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 43 07 c0 	l.sw 22464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 63 03 a8 	l.sw 23464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 63 07 90 	l.sw 24464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 83 03 78 	l.sw 25464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 83 07 60 	l.sw 26464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 a3 03 48 	l.sw 27464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 a3 07 30 	l.sw 28464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 c3 03 18 	l.sw 29464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 c3 07 00 	l.sw 30464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 e3 02 e8 	l.sw 31464\(r3\),r0
+.*:	18 60 00 02 	l.movhi r3,0x2
+.*:	d5 e3 06 d0 	l.sw 32464\(r3\),r0
+.*:	18 60 00 03 	l.movhi r3,0x3
+.*:	d6 03 02 b8 	l.sw -32072\(r3\),r0
diff --git a/ld/testsuite/ld-or1k/offsets1.s b/ld/testsuite/ld-or1k/offsets1.s
new file mode 100644
index 0000000000..94cb06887d
--- /dev/null
+++ b/ld/testsuite/ld-or1k/offsets1.s
@@ -0,0 +1,14 @@
+	.data
+	.p2align 16
+x:	.skip	10000
+
+	.text
+	.globl	_start
+_start:
+
+	.set	i, 0
+.rept 100
+	l.movhi	r3, ha(x+i)
+	l.sw	lo(x+i)(r3), r0
+	.set	i, i+1000
+.endr
diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
new file mode 100644
index 0000000000..8f09a7c40e
--- /dev/null
+++ b/ld/testsuite/ld-or1k/or1k.exp
@@ -0,0 +1,69 @@
+# Expect script for ld-or1k tests
+#   Copyright (C) 2015 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if { ![istarget "or1k*-*-*"] } {
+    return
+}
+
+# List contains test-items with 3 items followed by 2 lists:
+# 0:name 1:ld early options 2:ld late options 3:assembler options
+# 4:filenames of assembler files 5: action and options. 6: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result.  Compare with regex (last arg).
+# nm: Apply nm options on result.  Compare with regex (last arg).
+# readelf: Apply readelf options on result.  Compare with regex (last arg).
+
+set or1ktests {
+    {"offsets1" "" "" "" {offsets1.s}
+     {{objdump -drj.text offsets1.d}}
+     "offsets1"}
+}
+
+# Not implemented yet
+#   {"TLS -fpic -shared" "-shared -melf64alpha" ""
+#    "" {align.s tlspic1.s tlspic2.s}
+#    {{readelf -WSsrl tlspic.rd} {objdump -drj.text tlspic.dd}
+#     {objdump -sj.got tlspic.sd} {objdump -sj.tdata tlspic.td}}
+#    "libtlspic.so"}
+#   {"Helper shared library" "-shared -melf64alpha" ""
+#    "" {tlslib.s} {} "libtlslib.so"}
+#   {"TLS -fpic and -fno-pic exec"
+#    "-melf64alpha tmpdir/libtlslib.so" "" "" {align.s tlsbinpic.s tlsbin.s}
+#    {{readelf -WSsrl tlsbin.rd} {objdump -drj.text tlsbin.dd}
+#     {objdump -sj.got tlsbin.sd} {objdump -sj.tdata tlsbin.td}}
+#    "tlsbin"}
+#   {"TLS -fpic and -fno-pic exec -relax"
+#    "-relax -melf64alpha tmpdir/libtlslib.so" ""
+#    "" {align.s tlsbinpic.s tlsbin.s}
+#    {{readelf -WSsrl tlsbinr.rd} {objdump -drj.text tlsbinr.dd}
+#     {objdump -sj.got tlsbinr.sd}}
+#    "tlsbinr"}
+#   {"empty got"
+#    "-melf64alpha" "" ""
+#    {emptygot.s}
+#    {{nm "-n" emptygot.nm}}
+#    "emptygot"}
+#   {"TLS in debug sections" "-melf64alpha" ""
+#    "" {tlsg.s}
+#    {{objdump -sj.debug_foobar tlsg.sd}} "tlsg"}
+
+run_ld_link_tests $or1ktests
diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
index 3162ff3b9f..17bc17e244 100644
--- a/opcodes/or1k-asm.c
+++ b/opcodes/or1k-asm.c
@@ -52,6 +52,7 @@ static const char * parse_insn_normal
 /* -- asm.c */
 
 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
+static const char * INVALID_STORE_RELOC = N_("relocation invalid for store");
 
 #define CGEN_VERBOSE_ASSEMBLER_ERRORS
 
@@ -85,315 +86,186 @@ parse_disp26 (CGEN_CPU_DESC cd,
   return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
 }
 
-static const char *
-parse_simm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, long * valuep)
-{
-  const char *errmsg;
-  enum cgen_parse_operand_result result_type;
-  long ret;
-
-  if (**strp == '#')
-    ++*strp;
-
-  if (strncasecmp (*strp, "hi(", 3) == 0)
-    {
-      bfd_vma value;
+enum {
+  RTYPE_LO = 0,
+  RTYPE_HI = 1,
+  RTYPE_AHI = 2,
+  RTYPE_SLO = 3,
+
+  RTYPE_GOT      = (1 << 2),
+  RTYPE_GOTPC    = (2 << 2),
+  RTYPE_GOTOFF   = (3 << 2),
+  RTYPE_TLSGD    = (4 << 2),
+  RTYPE_TLSLDM   = (5 << 2),
+  RTYPE_DTPOFF   = (6 << 2),
+  RTYPE_GOTTPOFF = (7 << 2),
+  RTYPE_TPOFF    = (8 << 2),
+};
 
-      *strp += 3;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16,
-				   & result_type, & value);
-      if (**strp != ')')
-	errmsg = MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
+static const bfd_reloc_code_real_type or1k_imm16_relocs[][4] = {
+  { BFD_RELOC_LO16,
+    BFD_RELOC_HI16,
+    BFD_RELOC_HI16_S,
+    BFD_RELOC_OR1K_SLO16 },
+  { BFD_RELOC_OR1K_GOT16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_GOTPC_LO16,
+    BFD_RELOC_OR1K_GOTPC_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_LO16_GOTOFF,
+    BFD_RELOC_HI16_GOTOFF,
+    BFD_RELOC_HI16_S_GOTOFF,
+    BFD_RELOC_OR1K_GOTOFF_SLO16 },
+  { BFD_RELOC_OR1K_TLS_GD_LO16,
+    BFD_RELOC_OR1K_TLS_GD_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LDM_LO16,
+    BFD_RELOC_OR1K_TLS_LDM_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LDO_LO16,
+    BFD_RELOC_OR1K_TLS_LDO_HI16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_IE_LO16,
+    BFD_RELOC_OR1K_TLS_IE_HI16,
+    BFD_RELOC_OR1K_TLS_IE_AHI16,
+    BFD_RELOC_UNUSED },
+  { BFD_RELOC_OR1K_TLS_LE_LO16,
+    BFD_RELOC_OR1K_TLS_LE_HI16,
+    BFD_RELOC_OR1K_TLS_LE_AHI16,
+    BFD_RELOC_OR1K_TLS_LE_SLO16 }
+};
 
-      ret = value;
+static int
+parse_reloc(const char **strp)
+{
+    const char *str = *strp;
+    int ret = 0;
 
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+    if (strncasecmp (str, "got(", 4) == 0)
 	{
-	  ret >>= 16;
-	  ret &= 0xffff;
-	  ret = (ret ^ 0x8000) - 0x8000;
+	*strp = str + 4;
+	return RTYPE_GOT | RTYPE_LO;
 	}
-    }
-  else if (strncasecmp (*strp, "lo(", 3) == 0)
-    {
-      bfd_vma value;
-
-      *strp += 3;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
 
-      ret = value;
-
-      if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+    if (strncasecmp (str, "gotpc", 5) == 0)
 	{
-	  ret &= 0xffff;
-	  ret = (ret ^ 0x8000) - 0x8000;
+	str += 5;
+	ret = RTYPE_GOTPC;
 	}
-    }
-  else if (strncasecmp (*strp, "got(", 4) == 0)
+    else if (strncasecmp (str, "gotoff", 6) == 0)
     {
-      bfd_vma value;
-
-      *strp += 4;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_OR1K_GOT16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 6;
+	ret = RTYPE_GOTOFF;
     }
-  else if (strncasecmp (*strp, "gotpchi(", 8) == 0)
+    else if (strncasecmp (str, "tlsgd", 5) == 0)
     {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTPC_HI16,
-				   & result_type, & value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 5;
+	ret = RTYPE_TLSGD;
     }
-  else if (strncasecmp (*strp, "gotpclo(", 8) == 0)
+    else if (strncasecmp (str, "tlsldm", 6) == 0)
     {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTPC_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 6;
+	ret = RTYPE_TLSLDM;
     }
-  else if (strncasecmp (*strp, "gotoffhi(", 9) == 0)
+    else if (strncasecmp (str, "dtpoff", 6) == 0)
     {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTOFF_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 6;
+	ret = RTYPE_DTPOFF;
     }
-  else if (strncasecmp (*strp, "gotofflo(", 9) == 0)
+    else if (strncasecmp (str, "gottpoff", 8) == 0)
     {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_GOTOFF_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 8;
+	ret = RTYPE_GOTTPOFF;
     }
-  else if (strncasecmp (*strp, "tlsgdhi(", 8) == 0)
+    else if (strncasecmp (str, "tpoff", 5) == 0)
     {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_GD_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 5;
+	ret = RTYPE_TPOFF;
     }
-  else if (strncasecmp (*strp, "tlsgdlo(", 8) == 0)
-    {
-      bfd_vma value;
 
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_GD_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tlsldmhi(", 9) == 0)
+    if (strncasecmp (str, "hi(", 3) == 0)
     {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDM_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 3;
+	ret |= RTYPE_HI;
     }
-  else if (strncasecmp (*strp, "tlsldmlo(", 9) == 0)
+    else if (strncasecmp (str, "lo(", 3) == 0)
     {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDM_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 3;
+	ret |= RTYPE_LO;
     }
-  else if (strncasecmp (*strp, "dtpoffhi(", 9) == 0)
+    else if (strncasecmp (str, "ha(", 3) == 0)
     {
-      bfd_vma value;
-
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDO_HI16,
-				   & result_type, & value);
-
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	str += 3;
+	ret |= RTYPE_AHI;
     }
-  else if (strncasecmp (*strp, "dtpofflo(", 9) == 0)
-    {
-      bfd_vma value;
+    else
+      return -1;
 
-      *strp += 9;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LDO_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "gottpoffhi(", 11) == 0)
-    {
-      bfd_vma value;
+    *strp = str;
+    return ret;
+}
 
-      *strp += 11;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_IE_HI16,
-				   & result_type, & value);
+static const char *
+parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
+	     long *valuep, int splitp)
+{
+  const char *errmsg;
+  enum cgen_parse_operand_result result_type;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+  int reloc_type;
+  bfd_vma ret;
 
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
+  if (**strp == '#')
       ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
+
+  reloc_type = parse_reloc (strp);
+  if (reloc_type >= 0)
+    {
+      if (splitp)
+	{
+	  if ((reloc_type & 3) == RTYPE_LO && reloc_type != RTYPE_GOT)
+	    reloc_type |= RTYPE_SLO;
+	  else
+	    return INVALID_STORE_RELOC;
+    }
+      reloc = or1k_imm16_relocs[reloc_type >> 2][reloc_type & 3];
     }
-  else if (strncasecmp (*strp, "gottpofflo(", 11) == 0)
+
+  if (reloc != BFD_RELOC_UNUSED)
     {
       bfd_vma value;
 
-      *strp += 11;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_IE_LO16,
+      errmsg = cgen_parse_address (cd, strp, opindex, reloc,
 				   &result_type, &value);
       if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
+	errmsg = MISSING_CLOSING_PARENTHESIS;
       ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tpoffhi(", 8) == 0)
-    {
-      bfd_vma value;
 
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LE_HI16,
-				   & result_type, & value);
+      ret = value;
 
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 16) & 0xffff;
-      *valuep = value;
-      return errmsg;
-    }
-  else if (strncasecmp (*strp, "tpofflo(", 8) == 0)
+      if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
+	switch (reloc_type & 3)
     {
-      bfd_vma value;
-
-      *strp += 8;
-      errmsg = cgen_parse_address (cd, strp, opindex,
-				   BFD_RELOC_OR1K_TLS_LE_LO16,
-				   &result_type, &value);
-      if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value &= 0xffff;
-      *valuep = value;
-      return errmsg;
+	  case RTYPE_AHI:
+	    ret += 0x8000;
+	    /* FALLTHRU */
+	  case RTYPE_HI:
+	    ret >>= 16;
+	    /* FALLTHRU */
+	  case RTYPE_LO:
+	  case RTYPE_SLO:
+	    ret &= 0xffff;
+	    ret = (ret ^ 0x8000) - 0x8000;
+	    break;
+	  default:
+	    abort ();
+	  }
     }
   else
     {
@@ -409,10 +281,33 @@ parse_simm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, long * valuep)
 }
 
 static const char *
-parse_uimm16 (CGEN_CPU_DESC cd, const char ** strp, int opindex, unsigned long * valuep)
+parse_simm16 (CGEN_CPU_DESC cd, const char **strp, int opindex, long *valuep)
+{
+  return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
+}
+
+static const char *
+parse_simm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
+		    long *valuep)
 {
-  const char *errmsg = parse_simm16(cd, strp, opindex, (long *) valuep);
+  return parse_imm16(cd, strp, opindex, (long *) valuep, 1);
+}
 
+static const char *
+parse_uimm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
+	      unsigned long *valuep)
+{
+  const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 0);
+  if (errmsg == NULL)
+    *valuep &= 0xffff;
+  return errmsg;
+}
+
+static const char *
+parse_uimm16_split (CGEN_CPU_DESC cd, const char **strp, int opindex,
+		    unsigned long *valuep)
+{
+  const char *errmsg = parse_imm16(cd, strp, opindex, (long *) valuep, 1);
   if (errmsg == NULL)
     *valuep &= 0xffff;
   return errmsg;
@@ -486,13 +381,13 @@ or1k_cgen_parse_operand (CGEN_CPU_DESC cd,
       errmsg = parse_simm16 (cd, strp, OR1K_OPERAND_SIMM16, (long *) (& fields->f_simm16));
       break;
     case OR1K_OPERAND_SIMM16_SPLIT :
-      errmsg = parse_simm16 (cd, strp, OR1K_OPERAND_SIMM16_SPLIT, (long *) (& fields->f_simm16_split));
+      errmsg = parse_simm16_split (cd, strp, OR1K_OPERAND_SIMM16_SPLIT, (long *) (& fields->f_simm16_split));
       break;
     case OR1K_OPERAND_UIMM16 :
       errmsg = parse_uimm16 (cd, strp, OR1K_OPERAND_UIMM16, (unsigned long *) (& fields->f_uimm16));
       break;
     case OR1K_OPERAND_UIMM16_SPLIT :
-      errmsg = parse_uimm16 (cd, strp, OR1K_OPERAND_UIMM16_SPLIT, (unsigned long *) (& fields->f_uimm16_split));
+      errmsg = parse_uimm16_split (cd, strp, OR1K_OPERAND_UIMM16_SPLIT, (unsigned long *) (& fields->f_uimm16_split));
       break;
     case OR1K_OPERAND_UIMM6 :
       errmsg = cgen_parse_unsigned_integer (cd, strp, OR1K_OPERAND_UIMM6, (unsigned long *) (& fields->f_uimm6));
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 2/4] or1k: Fix messages for relocations in shared libraries
  2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 1/4] or1k: Add relocations for high-signed and low-stores Stafford Horne
@ 2018-08-21 14:38 ` Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 3/4] or1k: Add the l.adrp insn and supporting relocations Stafford Horne
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-08-21 14:38 UTC (permalink / raw)
  To: openrisc

Added checks include:

 - Do not allow relocations to global symbols using relocations which are
   meant for local symbol relocations.
 - Require the use of -fpic when compiling shared libraries.
 - Require zero addend for plt relocations.

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

bfd/ChangeLog:

	* elf32-or1k.c (or1k_elf_relocate_section): Add error for unknown
	relocations.  Add error for non zero addend with plt and got
	relocations.  Add error for got and plt references against dynamic, non
	local, symbols.  Add error when linking non shared liraries with
	flag_pic.
---
 bfd/elf32-or1k.c | 148 ++++++++++++++++++++++++++++-------------------
 1 file changed, 90 insertions(+), 58 deletions(-)

diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
index 9f3f6a6dd8..f3119e4dff 100644
--- a/bfd/elf32-or1k.c
+++ b/bfd/elf32-or1k.c
@@ -1063,7 +1063,9 @@ or1k_elf_relocate_section (bfd *output_bfd,
   bfd *dynobj;
   asection *sreloc;
   bfd_vma *local_got_offsets;
-  asection *sgot;
+  asection *sgot, *splt;
+  bfd_vma plt_base, got_base;
+  bfd_boolean ret_val = TRUE;
 
   if (htab == NULL)
     return FALSE;
@@ -1073,7 +1075,15 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
   sreloc = elf_section_data (input_section)->sreloc;
 
+  splt = htab->root.splt;
+  plt_base = 0;
+  if (splt != NULL)
+    plt_base = splt->output_section->vma + splt->output_offset;
+
   sgot = htab->root.sgot;
+  got_base = 0;
+  if (sgot != NULL)
+    got_base = sgot->output_section->vma + sgot->output_offset;
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -1100,8 +1110,12 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
       if (r_type < 0 || r_type >= (int) R_OR1K_max)
 	{
+	  _bfd_error_handler
+	    (_("%pB: unknown relocation type %d"),
+	     input_bfd, (int) r_type);
 	  bfd_set_error (bfd_error_bad_value);
-	  return FALSE;
+	  ret_val = FALSE;
+	  continue;
 	}
 
       howto = or1k_elf_howto_table + ELF32_R_TYPE (rel->r_info);
@@ -1127,6 +1141,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 				   r_symndx, symtab_hdr, sym_hashes,
 				   h, sec, relocation,
 				   unresolved_reloc, warned, ignored);
+	  name = h->root.root.string;
 	}
 
       if (sec != NULL && discarded_section (sec))
@@ -1139,16 +1154,24 @@ or1k_elf_relocate_section (bfd *output_bfd,
       switch (howto->type)
 	{
 	case R_OR1K_PLT26:
-	  {
-	    if (htab->root.splt != NULL && h != NULL
-		&& h->plt.offset != (bfd_vma) -1)
-	      {
-		relocation = (htab->root.splt->output_section->vma
-			      + htab->root.splt->output_offset
-			      + h->plt.offset);
-	      }
-	    break;
-	  }
+	  /* If the call is not local, redirect the branch to the PLT.
+	     Otherwise do nothing to send the branch to the symbol direct.  */
+	  if (!SYMBOL_CALLS_LOCAL (info, h))
+	    {
+	      BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
+	      relocation = plt_base + h->plt.offset;
+	    }
+
+	  /* Addend should be zero.  */
+	  if (rel->r_addend != 0)
+	    {
+	      _bfd_error_handler
+		(_("%pB: addend should be zero for plt relocations"),
+		 input_bfd);
+	      bfd_set_error (bfd_error_bad_value);
+	      ret_val = FALSE;
+	    }
+	  break;
 
 	case R_OR1K_GOT16:
 	  /* Relocation is to the entry for this symbol in the global
@@ -1225,9 +1248,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		      srelgot = htab->root.srelgot;
 		      BFD_ASSERT (srelgot != NULL);
 
-		      outrel.r_offset = (sgot->output_section->vma
-					 + sgot->output_offset
-					 + off);
+		      outrel.r_offset = got_base + off;
 		      outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE);
 		      outrel.r_addend = relocation;
 		      loc = srelgot->contents;
@@ -1243,10 +1264,13 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 	  /* Addend should be zero.  */
 	  if (rel->r_addend != 0)
-	    _bfd_error_handler
-	      (_("internal error: addend should be zero for %s"),
-	       "R_OR1K_GOT16");
-
+	    {
+	      _bfd_error_handler
+		(_("%pB: addend should be zero for got relocations"),
+		 input_bfd);
+	      bfd_set_error (bfd_error_bad_value);
+	      ret_val = FALSE;
+	    }
 	  break;
 
 	case R_OR1K_GOTOFF_LO16:
@@ -1255,17 +1279,44 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	case R_OR1K_GOTOFF_SLO16:
 	  /* Relocation is offset from GOT.  */
 	  BFD_ASSERT (sgot != NULL);
-	  relocation
-	    -= (htab->root.hgot->root.u.def.value
-		+ htab->root.hgot->root.u.def.section->output_offset
-		+ htab->root.hgot->root.u.def.section->output_section->vma);
+	  if (!SYMBOL_REFERENCES_LOCAL (info, h))
+	    {
+	      _bfd_error_handler
+		(_("%pB: gotoff relocation against dynamic symbol %s"),
+		 input_bfd, h->root.root.string);
+	      ret_val = FALSE;
+	      bfd_set_error (bfd_error_bad_value);
+	    }
+	  relocation -= got_base;
 	  break;
 
 	case R_OR1K_INSN_REL_26:
+	  /* For a non-shared link, these will reference either the plt
+	     or a .dynbss copy of the symbol.  */
+	  if (bfd_link_pic (info) && !SYMBOL_REFERENCES_LOCAL (info, h))
+	    {
+	      _bfd_error_handler
+		(_("%pB: pc-relative relocation against dynamic symbol %s"),
+		 input_bfd, name);
+	      ret_val = FALSE;
+	      bfd_set_error (bfd_error_bad_value);
+	    }
+	  break;
+
 	case R_OR1K_HI_16_IN_INSN:
 	case R_OR1K_LO_16_IN_INSN:
 	case R_OR1K_AHI16:
 	case R_OR1K_SLO16:
+	  if (bfd_link_pic (info))
+	    {
+	      _bfd_error_handler
+		(_("%pB: non-pic relocation against symbol %s"),
+		 input_bfd, name);
+	      ret_val = FALSE;
+	      bfd_set_error (bfd_error_bad_value);
+	    }
+	  break;
+
 	case R_OR1K_32:
 	  /* R_OR1K_16? */
 	  {
@@ -1276,18 +1327,17 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		|| (input_section->flags & SEC_ALLOC) == 0)
 	      break;
 
-	    if ((bfd_link_pic (info)
-		 && (h == NULL
+	    /* Emit a direct relocation if the symbol is dynamic,
+	       or a RELATIVE reloc for shared objects.  We can omit
+	       RELATIVE relocs to local undefweak symbols.  */
+	    if (bfd_link_pic (info)
+		? (h == NULL
 		     || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		     || h->root.type != bfd_link_hash_undefweak)
-		 && (howto->type != R_OR1K_INSN_REL_26
-		     || !SYMBOL_CALLS_LOCAL (info, h)))
-		|| (!bfd_link_pic (info)
-		    && h != NULL
+		: (h != NULL
 		    && h->dynindx != -1
 		    && !h->non_got_ref
-		    && ((h->def_dynamic
-			 && !h->def_regular)
+		   && ((h->def_dynamic && !h->def_regular)
 			|| h->root.type == bfd_link_hash_undefweak
 			|| h->root.type == bfd_link_hash_undefined)))
 	      {
@@ -1315,32 +1365,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 		if (skip)
 		  memset (&outrel, 0, sizeof outrel);
-		/* h->dynindx may be -1 if the symbol was marked to
-		   become local.  */
-		else if (h != NULL
-			 && ((! info->symbolic && h->dynindx != -1)
-			     || !h->def_regular))
+		else if (SYMBOL_REFERENCES_LOCAL (info, h))
 		  {
-		    BFD_ASSERT (h->dynindx != -1);
-		    outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
-		    outrel.r_addend = rel->r_addend;
+		    outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE);
+		    outrel.r_addend = relocation + rel->r_addend;
 		  }
 		else
 		  {
-		    if (r_type == R_OR1K_32)
-		      {
-			outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE);
-			outrel.r_addend = relocation + rel->r_addend;
-		      }
-		    else
-		      {
-			BFD_FAIL ();
-			_bfd_error_handler
-			  (_("%pB: probably compiled without -fPIC?"),
-			   input_bfd);
-			bfd_set_error (bfd_error_bad_value);
-			return FALSE;
-		      }
+		    BFD_ASSERT (h->dynindx != -1);
+		    outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+		    outrel.r_addend = rel->r_addend;
 		  }
 
 		loc = sreloc->contents;
@@ -1416,8 +1450,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		/* Add DTPMOD and DTPOFF GOT and rela entries.  */
 		for (i = 0; i < 2; ++i)
 		  {
-		    rela.r_offset = sgot->output_section->vma +
-		      sgot->output_offset + gotoff + i*4;
+		    rela.r_offset = got_base + gotoff + i*4;
 		    if (h != NULL && h->dynindx != -1)
 		      {
 			rela.r_info = ELF32_R_INFO (h->dynindx,
@@ -1451,8 +1484,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	    else if (dynamic)
 	      {
 		/* Add TPOFF GOT and rela entries.  */
-		rela.r_offset = sgot->output_section->vma +
-		  sgot->output_offset + gotoff;
+		rela.r_offset = got_base + gotoff;
 		if (h != NULL && h->dynindx != -1)
 		  {
 		    rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_TLS_TPOFF);
@@ -1547,7 +1579,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	}
     }
 
-  return TRUE;
+  return ret_val;
 }
 
 /* Return the section that should be marked against GC for a given
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 3/4] or1k: Add the l.adrp insn and supporting relocations
  2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 1/4] or1k: Add relocations for high-signed and low-stores Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 2/4] or1k: Fix messages for relocations in shared libraries Stafford Horne
@ 2018-08-21 14:38 ` Stafford Horne
  2018-08-21 14:38 ` [OpenRISC] [PATCH 4/4] or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns Stafford Horne
  2018-09-08 21:35 ` [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
  4 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-08-21 14:38 UTC (permalink / raw)
  To: openrisc

This patch adds the new instruction and relocation as per proposal:
   https://openrisc.io/proposals/ladrp

This is to be added to the spec in an upcoming revision.  The new instruction
l.adrp loads the page offset of the current instruction offset by
a 21-bit immediate shifted left 13-bits.  This is meant to be used with
a 13-bit lower bit page offset.  This allows us to free up the got
register r16.

  l.adrp  r3, foo
  l.ori   r4, r3, po(foo)
  l.lbz   r5, po(foo)(r3)
  l.sb    po(foo)(r3), r6

The relocations we add are:

 - BFD_RELOC_OR1K_PLTA26	For PLT jump relocation with PLT entry
   asm: plta()			implemented using l.ardp, meaning
				no need for r16 (the GOT reg)

 - BFD_RELOC_OR1K_GOT_PG21	Upper 21-bit Page offset got address
   asm: got()
 - BFD_RELOC_OR1K_TLS_GD_PG21	Upper 21-bit Page offset with TLS General
   asm: tlsgd()			Dynamic calculation
 - BFD_RELOC_OR1K_TLS_LDM_PG21	Upper 21-bit Page offset with TLS local
   asm: tlsldm()		dynamic calculation
 - BFD_RELOC_OR1K_TLS_IE_PG21	Upper 21-bit Page offset with TLS Initial
   asm: gottp() 		Executable calculation
 - BFD_RELOC_OR1K_PCREL_PG21	Default relocation for disp21 (l.adrp
				instructions)

 - BFD_RELOC_OR1K_LO13		low 13-bit page offset relocation
   asm: po()			i.e. mem loads, addi etc
 - BFD_RELOC_OR1K_SLO13		low 13-bit page offset relocation
   asm: po()			i.e. mem stores, with split immediate
 - BFD_RELOC_OR1K_GOT_LO13,	low 13-bit page offset with GOT calcs
   asm: gotpo()
 - BFD_RELOC_OR1K_TLS_GD_LO13	Lower 13-bit offset with TLS GD calcs
   asm: tlsgdpo()
 - BFD_RELOC_OR1K_TLS_LDM_LO13	Lower 13-bit offset with TLS LD calcs
   asm: tlsldmpo()
 - BFD_RELOC_OR1K_TLS_IE_LO13	Lower 13-bit offset with TLS IE calcs
   asm: gottppo()

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>

bfd/ChangeLog:

	* bfd-in2.h: Regenerated.
	* elf32-or1k.c: (or1k_elf_howto_table): Fix formatting for
	R_OR1K_PLT26, Add R_OR1K_PCREL_PG21, R_OR1K_GOT_PG21,
	R_OR1K_TLS_GD_PG21, R_OR1K_TLS_LDM_PG21, R_OR1K_TLS_IE_PG21,
	R_OR1K_LO13, R_OR1K_GOT_LO13, R_OR1K_TLS_GD_LO13, R_OR1K_TLS_LDM_LO13,
	R_OR1K_TLS_IE_LO13, R_OR1K_SLO13, R_OR1K_PLTA26.
	(or1k_reloc_map): Add BFD_RELOC_OR1K_PCREL_PG21,
	BFD_RELOC_OR1K_GOT_PG21, BFD_RELOC_OR1K_TLS_GD_PG21,
	BFD_RELOC_OR1K_TLS_LDM_PG21, BFD_RELOC_OR1K_TLS_IE_PG21,
	BFD_RELOC_OR1K_LO13, BFD_RELOC_OR1K_GOT_LO13,
	BFD_RELOC_OR1K_TLS_GD_LO13, BFD_RELOC_OR1K_TLS_GD_LO13,
	BFD_RELOC_OR1K_TLS_LDM_LO13, BFD_RELOC_OR1K_TLS_IE_LO13,
	BFD_RELOC_OR1K_SLO13, BFD_RELOC_OR1K_PLTA26.
	(elf_or1k_link_hash_table): Add field saw_plta.
	(or1k_final_link_relocate): Add value calculations for new relocations.
	(or1k_elf_relocate_section): Add section relocations for new
	relocations.
	(or1k_write_plt_entry): New function.
	(or1k_elf_finish_dynamic_sections): Add support for PLTA relocations
	using new l.adrp instruction.  Cleanup PLT relocation code generation.
	* libbfd.h: Regenerated.
	* reloc.c: Add BFD_RELOC_OR1K_PCREL_PG21, BFD_RELOC_OR1K_LO13,
	BFD_RELOC_OR1K_SLO13, BFD_RELOC_OR1K_GOT_PG21, BFD_RELOC_OR1K_GOT_LO13,
	BFD_RELOC_OR1K_PLTA26, BFD_RELOC_OR1K_TLS_GD_PG21,
	BFD_RELOC_OR1K_TLS_GD_LO13, BFD_RELOC_OR1K_TLS_LDM_PG21,
	BFD_RELOC_OR1K_TLS_LDM_LO13, BFD_RELOC_OR1K_TLS_IE_PG21,
	BFD_RELOC_OR1K_TLS_IE_LO13.

cpu/ChangeLog:

	* or1k.opc (parse_disp26): Add support for plta() relocations.
	(parse_disp21): New function.
	(or1k_rclass): New enum.
	(or1k_rtype): New enum.
	(or1k_imm16_relocs): Define new PO and SPO relocation mappings.
	(parse_reloc): Add new po(), gotpo() and gottppo() for LO13 relocations.
	(parse_imm16): Add support for the new 21bit and 13bit relocations.
	* or1korbis.cpu (f-disp26): Don't assume SI.
	(f-disp21): New pc-relative 21-bit 13 shifted to right.
	(insn-opcode): Add ADRP.
	(l-adrp): New instruction.

gas/ChangeLog:

	* config/tc-or1k.c (or1k_apply_fix): Add BFD_RELOC_OR1K_TLS_GD_PG21,
	BFD_RELOC_OR1K_TLS_GD_LO13, BFD_RELOC_OR1K_TLS_LDM_PG21,
	BFD_RELOC_OR1K_TLS_LDM_LO13, BFD_RELOC_OR1K_TLS_IE_PG21,
	BFD_RELOC_OR1K_TLS_IE_LO13.
	* testsuite/gas/or1k/allinsn.s: Add test for l.adrp.
	* testsuite/gas/or1k/allinsn.d: Add test results for new
	instructions.
	* testsuite/gas/or1k/reloc-1.s: Add tests to generate
	R_OR1K_PLTA26, R_OR1K_GOT_PG21, R_OR1K_TLS_GD_PG21, R_OR1K_TLS_LDM_PG21,
	R_OR1K_TLS_IE_PG21, R_OR1K_LO13, R_OR1K_GOT_LO13, R_OR1K_TLS_GD_LO13,
	R_OR1K_TLD_LDM_LO13, R_OR1K_TLS_IE_LO13, R_OR1K_LO13, R_OR1K_SLO13
	relocations.
	* testsuite/gas/or1k/reloc-1.d: Add relocation results for
	tests.
	* testsuite/gas/or1k/reloc-2.s: Add negative tests for store to
	gotpo().
	* testsuite/gas/or1k/reloc-2.l: Add expected error test results.

ld/ChangeLog:

	* testsuite/ld-or1k/or1k.exp: Add test cases for plt generation.
	* testsuite/ld-or1k/plt1.dd: New file.
	* testsuite/ld-or1k/plt1.s: New file.
	* testsuite/ld-or1k/plt1.x.dd: New file.
	* testsuite/ld-or1k/plta1.dd: New file.
	* testsuite/ld-or1k/plta1.s: New file.
	* testsuite/ld-or1k/pltlib.s: New file.

include/ChangeLog:

	* elf/or1k.h (elf_or1k_reloc_type): Add R_OR1K_PCREL_PG21,
	R_OR1K_GOT_PG21, R_OR1K_TLS_GD_PG21, R_OR1K_TLS_LDM_PG21,
	R_OR1K_TLS_IE_PG21, R_OR1K_LO13, R_OR1K_GOT_LO13,
	R_OR1K_TLS_GD_LO13, R_OR1K_TLS_LDM_LO13, R_OR1K_TLS_IE_LO13,
	R_OR1K_SLO13, R_OR1K_PLTA26.

opcodes/ChangeLog:

	* or1k-asm.c: Regenerated.
	* or1k-desc.c: Regenerated.
	* or1k-desc.h: Regenerated.
	* or1k-dis.c: Regenerated.
	* or1k-ibld.c: Regenerated.
	* or1k-opc.c: Regenerated.
	* or1k-opc.h: Regenerated.
	* or1k-opinst.c: Regenerated.
---
 bfd/bfd-in2.h                    |  12 +
 bfd/elf32-or1k.c                 | 526 +++++++++++++++++++++++--------
 bfd/libbfd.h                     |  12 +
 bfd/reloc.c                      |  24 ++
 cpu/or1k.opc                     | 225 +++++++++----
 cpu/or1korbis.cpu                |  35 +-
 gas/config/tc-or1k.c             |   6 +
 gas/testsuite/gas/or1k/allinsn.d |   6 +
 gas/testsuite/gas/or1k/allinsn.s |   3 +
 gas/testsuite/gas/or1k/reloc-1.d |  16 +
 gas/testsuite/gas/or1k/reloc-1.s |  20 ++
 gas/testsuite/gas/or1k/reloc-2.l |   1 +
 gas/testsuite/gas/or1k/reloc-2.s |   1 +
 include/elf/or1k.h               |  12 +
 ld/testsuite/ld-or1k/or1k.exp    |  22 ++
 ld/testsuite/ld-or1k/plt1.dd     |  27 ++
 ld/testsuite/ld-or1k/plt1.s      |  11 +
 ld/testsuite/ld-or1k/plt1.x.dd   |  27 ++
 ld/testsuite/ld-or1k/plta1.dd    |  27 ++
 ld/testsuite/ld-or1k/plta1.s     |  11 +
 ld/testsuite/ld-or1k/pltlib.s    |  12 +
 opcodes/or1k-asm.c               | 282 ++++++++++++-----
 opcodes/or1k-desc.c              |  10 +
 opcodes/or1k-desc.h              |  37 +--
 opcodes/or1k-dis.c               |   3 +
 opcodes/or1k-ibld.c              |  29 +-
 opcodes/or1k-opc.c               |  10 +
 opcodes/or1k-opc.h               |  64 ++--
 opcodes/or1k-opinst.c            |   7 +
 29 files changed, 1154 insertions(+), 324 deletions(-)
 create mode 100644 ld/testsuite/ld-or1k/plt1.dd
 create mode 100644 ld/testsuite/ld-or1k/plt1.s
 create mode 100644 ld/testsuite/ld-or1k/plt1.x.dd
 create mode 100644 ld/testsuite/ld-or1k/plta1.dd
 create mode 100644 ld/testsuite/ld-or1k/plta1.s
 create mode 100644 ld/testsuite/ld-or1k/pltlib.s

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index a51ead9273..a714c3601d 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5468,10 +5468,16 @@ then it may be truncated to 8 bits.  */
 /* OpenRISC 1000 Relocations.  */
   BFD_RELOC_OR1K_REL_26,
   BFD_RELOC_OR1K_SLO16,
+  BFD_RELOC_OR1K_PCREL_PG21,
+  BFD_RELOC_OR1K_LO13,
+  BFD_RELOC_OR1K_SLO13,
   BFD_RELOC_OR1K_GOTPC_HI16,
   BFD_RELOC_OR1K_GOTPC_LO16,
   BFD_RELOC_OR1K_GOT16,
+  BFD_RELOC_OR1K_GOT_PG21,
+  BFD_RELOC_OR1K_GOT_LO13,
   BFD_RELOC_OR1K_PLT26,
+  BFD_RELOC_OR1K_PLTA26,
   BFD_RELOC_OR1K_GOTOFF_SLO16,
   BFD_RELOC_OR1K_COPY,
   BFD_RELOC_OR1K_GLOB_DAT,
@@ -5479,13 +5485,19 @@ then it may be truncated to 8 bits.  */
   BFD_RELOC_OR1K_RELATIVE,
   BFD_RELOC_OR1K_TLS_GD_HI16,
   BFD_RELOC_OR1K_TLS_GD_LO16,
+  BFD_RELOC_OR1K_TLS_GD_PG21,
+  BFD_RELOC_OR1K_TLS_GD_LO13,
   BFD_RELOC_OR1K_TLS_LDM_HI16,
   BFD_RELOC_OR1K_TLS_LDM_LO16,
+  BFD_RELOC_OR1K_TLS_LDM_PG21,
+  BFD_RELOC_OR1K_TLS_LDM_LO13,
   BFD_RELOC_OR1K_TLS_LDO_HI16,
   BFD_RELOC_OR1K_TLS_LDO_LO16,
   BFD_RELOC_OR1K_TLS_IE_HI16,
   BFD_RELOC_OR1K_TLS_IE_AHI16,
   BFD_RELOC_OR1K_TLS_IE_LO16,
+  BFD_RELOC_OR1K_TLS_IE_PG21,
+  BFD_RELOC_OR1K_TLS_IE_LO13,
   BFD_RELOC_OR1K_TLS_LE_HI16,
   BFD_RELOC_OR1K_TLS_LE_AHI16,
   BFD_RELOC_OR1K_TLS_LE_LO16,
diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
index f3119e4dff..ceed1d1f6b 100644
--- a/bfd/elf32-or1k.c
+++ b/bfd/elf32-or1k.c
@@ -29,31 +29,14 @@
 
 #define N_ONES(X)	(((bfd_vma)2 << (X)) - 1)
 
-#define PLT_ENTRY_SIZE 20
-
-#define PLT0_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(.got+4) */
-#define PLT0_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(.got+4) */
-#define PLT0_ENTRY_WORD2 0x85ec0004 /* l.lwz r15, 4(r12) <- *(.got+8)*/
-#define PLT0_ENTRY_WORD3 0x44007800 /* l.jr r15 */
-#define PLT0_ENTRY_WORD4 0x858c0000 /* l.lwz r12, 0(r12) */
-
-#define PLT0_PIC_ENTRY_WORD0 0x85900004 /* l.lwz r12, 4(r16) */
-#define PLT0_PIC_ENTRY_WORD1 0x85f00008 /* l.lwz r15, 8(r16) */
-#define PLT0_PIC_ENTRY_WORD2 0x44007800 /* l.jr r15 */
-#define PLT0_PIC_ENTRY_WORD3 0x15000000 /* l.nop */
-#define PLT0_PIC_ENTRY_WORD4 0x15000000 /* l.nop */
-
-#define PLT_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(got idx addr) */
-#define PLT_ENTRY_WORD1 0xa98c0000 /* l.ori r12, r12, 0 <- lo(got idx addr) */
-#define PLT_ENTRY_WORD2 0x858c0000 /* l.lwz r12, 0(r12) */
-#define PLT_ENTRY_WORD3 0x44006000 /* l.jr r12 */
-#define PLT_ENTRY_WORD4 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */
-
-#define PLT_PIC_ENTRY_WORD0 0x85900000 /* l.lwz r12, 0(r16) <- index in got */
-#define PLT_PIC_ENTRY_WORD1 0xa9600000 /* l.ori r11, r0, 0 <- reloc offset */
-#define PLT_PIC_ENTRY_WORD2 0x44006000 /* l.jr r12 */
-#define PLT_PIC_ENTRY_WORD3 0x15000000 /* l.nop */
-#define PLT_PIC_ENTRY_WORD4 0x15000000 /* l.nop */
+#define PLT_ENTRY_SIZE 16
+
+#define OR1K_MOVHI(D)		(0x18000000 | (D << 21))
+#define OR1K_ADRP(D)		(0x08000000 | (D << 21))
+#define OR1K_LWZ(D,A)		(0x84000000 | (D << 21) | (A << 16))
+#define OR1K_ORI0(D)		(0xA8000000 | (D << 21))
+#define OR1K_JR(B)		(0x44000000 | (B << 11))
+#define OR1K_NOP		0x15000000
 
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
@@ -274,16 +257,16 @@ static reloc_howto_type or1k_elf_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* A 26 bit PLT relocation.  Shifted by 2.  */
-  HOWTO (R_OR1K_PLT26,	/* Type.  */
+  HOWTO (R_OR1K_PLT26,		/* Type.  */
 	 2,			/* Rightshift.  */
 	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
 	 26,			/* Bitsize.  */
-	 TRUE,			/* PC_relative.  */
+	 TRUE,			/* pc_relative.  */
 	 0,			/* Bitpos.  */
 	 complain_overflow_signed, /* Complain on overflow.  */
-	 bfd_elf_generic_reloc,/* Special Function.  */
+	 bfd_elf_generic_reloc, /* Special Function.  */
 	 "R_OR1K_PLT26",	/* Name.  */
-	 FALSE,		/* Partial Inplace.  */
+	 FALSE,			/* Partial Inplace.  */
 	 0,			/* Source Mask.  */
 	 0x03ffffff,		/* Dest Mask.  */
 	 TRUE),			/* PC relative offset?  */
@@ -651,6 +634,180 @@ static reloc_howto_type or1k_elf_howto_table[] =
 	 0x0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
+
+  /* A page relative 21 bit relocation, right shifted by 13, aligned.
+     Note that this is *page* relative, not pc relative.  The idea is
+     similar, but normally the section alignment is not such that the
+     assembler can infer a final value, which it attempts to do with
+     pc-relative relocations to local symbols.  */
+  HOWTO (R_OR1K_PCREL_PG21,    /* type */
+	 13,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_PCREL_PG21",   /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001fffff,		/* dst_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_OR1K_GOT_PG21,       /* type */
+	 13,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_GOT_PG21",     /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001fffff,		/* dst_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_GD_PG21,    /* type */
+	 13,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_GD_PG21",  /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001fffff,		/* dst_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_LDM_PG21,   /* type */
+	 13,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_LDM_PG21", /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001fffff,		/* dst_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_IE_PG21,    /* type */
+	 13,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 21,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_IE_PG21",  /* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0x001fffff,		/* dst_mask */
+	 TRUE),			/* pcrel_offset */
+
+  HOWTO (R_OR1K_LO13,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_LO13",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_GOT_LO13,       /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_GOT_LO13",     /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_GD_LO13,    /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_GD_LO13",  /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_LDM_LO13,   /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLD_LDM_LO13", /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_TLS_IE_LO13,    /* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_TLS_IE_LO13",  /* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_OR1K_SLO13,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_OR1K_SLO13",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0x0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* A 26 bit PLT relocation, using ADRP.  Shifted by 2.  */
+  HOWTO (R_OR1K_PLTA26,		/* Type.  */
+	 2,			/* Rightshift.  */
+	 2,			/* Size (0 = byte, 1 = short, 2 = long).  */
+	 26,			/* Bitsize.  */
+	 TRUE,			/* pc_relative.  */
+	 0,			/* Bitpos.  */
+	 complain_overflow_signed, /* Complain on overflow.  */
+	 bfd_elf_generic_reloc,	/* Special Function.  */
+	 "R_OR1K_PLTA26",	/* Name.  */
+	 FALSE,			/* Partial Inplace.  */
+	 0,			/* Source Mask.  */
+	 0x03ffffff,		/* Dest Mask.  */
+	 TRUE),			/* PC relative offset?  */
 };
 
 /* Map BFD reloc types to Or1k ELF reloc types.  */
@@ -702,6 +859,18 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
   { BFD_RELOC_OR1K_SLO16,	R_OR1K_SLO16 },
   { BFD_RELOC_OR1K_GOTOFF_SLO16, R_OR1K_GOTOFF_SLO16 },
   { BFD_RELOC_OR1K_TLS_LE_SLO16, R_OR1K_TLS_LE_SLO16 },
+  { BFD_RELOC_OR1K_PCREL_PG21,	R_OR1K_PCREL_PG21 },
+  { BFD_RELOC_OR1K_GOT_PG21,	R_OR1K_GOT_PG21 },
+  { BFD_RELOC_OR1K_TLS_GD_PG21,	R_OR1K_TLS_GD_PG21 },
+  { BFD_RELOC_OR1K_TLS_LDM_PG21, R_OR1K_TLS_LDM_PG21 },
+  { BFD_RELOC_OR1K_TLS_IE_PG21,	R_OR1K_TLS_IE_PG21 },
+  { BFD_RELOC_OR1K_LO13,	R_OR1K_LO13 },
+  { BFD_RELOC_OR1K_GOT_LO13,	R_OR1K_GOT_LO13 },
+  { BFD_RELOC_OR1K_TLS_GD_LO13,	R_OR1K_TLS_GD_LO13 },
+  { BFD_RELOC_OR1K_TLS_LDM_LO13, R_OR1K_TLS_LDM_LO13 },
+  { BFD_RELOC_OR1K_TLS_IE_LO13,	R_OR1K_TLS_IE_LO13 },
+  { BFD_RELOC_OR1K_SLO13,	R_OR1K_SLO13 },
+  { BFD_RELOC_OR1K_PLTA26,	R_OR1K_PLTA26 },
 };
 
 #define TLS_UNKNOWN    0
@@ -745,6 +914,8 @@ struct elf_or1k_link_hash_table
 
   /* Small local sym to section mapping cache.  */
   struct sym_cache sym_sec;
+
+  bfd_boolean saw_plta;
 };
 
 /* Get the ELF linker hash table from a link_info structure.  */
@@ -897,19 +1068,15 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
   bfd_reloc_status_type status = bfd_reloc_ok;
   int size = bfd_get_reloc_size (howto);
   unsigned bitsize, bits;
-  bfd_vma x;
+  bfd_vma x, place;
 
   /* Sanity check the address.  */
   if (offset + size > bfd_get_section_limit_octets (input_bfd, input_section))
     return bfd_reloc_outofrange;
 
-  if (howto->pc_relative)
-    {
-      value -= (input_section->output_section->vma
-		+ input_section->output_offset);
-      if (howto->pcrel_offset)
-	value -= offset;
-    }
+  place = (input_section->output_section->vma
+	   + input_section->output_offset
+	   + (howto->pcrel_offset ? offset : 0));
 
   switch (howto->type)
     {
@@ -922,10 +1089,33 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
       break;
 
     case R_OR1K_INSN_REL_26:
+      value -= place;
       /* Diagnose mis-aligned branch targets.  */
       if (value & 3)
 	status = bfd_reloc_dangerous;
       break;
+
+    case R_OR1K_PCREL_PG21:
+    case R_OR1K_GOT_PG21:
+    case R_OR1K_TLS_GD_PG21:
+    case R_OR1K_TLS_LDM_PG21:
+    case R_OR1K_TLS_IE_PG21:
+      value = (value & -8192) - (place & -8192);
+      break;
+
+    case R_OR1K_LO13:
+    case R_OR1K_GOT_LO13:
+    case R_OR1K_TLS_GD_LO13:
+    case R_OR1K_TLS_LDM_LO13:
+    case R_OR1K_TLS_IE_LO13:
+    case R_OR1K_SLO13:
+      value &= 8191;
+      break;
+
+    default:
+      if (howto->pc_relative)
+	value -= place;
+      break;
     }
 
   bitsize = howto->bitsize;
@@ -974,6 +1164,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
     case R_OR1K_SLO16:
     case R_OR1K_GOTOFF_SLO16:
     case R_OR1K_TLS_LE_SLO16:
+    case R_OR1K_SLO13:
       /* The split imm16 field used for stores.  */
       x = (x & ~0x3e007ff) | ((value & 0xf800) << 10) | (value & 0x7ff);
       break;
@@ -1064,7 +1255,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
   asection *sreloc;
   bfd_vma *local_got_offsets;
   asection *sgot, *splt;
-  bfd_vma plt_base, got_base;
+  bfd_vma plt_base, got_base, got_sym_value;
   bfd_boolean ret_val = TRUE;
 
   if (htab == NULL)
@@ -1081,9 +1272,15 @@ or1k_elf_relocate_section (bfd *output_bfd,
     plt_base = splt->output_section->vma + splt->output_offset;
 
   sgot = htab->root.sgot;
-  got_base = 0;
+  got_sym_value = got_base = 0;
   if (sgot != NULL)
+    {
+      struct elf_link_hash_entry *hgot = htab->root.hgot;
+      got_sym_value = (hgot->root.u.def.value
+		       + hgot->root.u.def.section->output_section->vma
+		       + hgot->root.u.def.section->output_offset);
     got_base = sgot->output_section->vma + sgot->output_offset;
+    }
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
@@ -1154,13 +1351,12 @@ or1k_elf_relocate_section (bfd *output_bfd,
       switch (howto->type)
 	{
 	case R_OR1K_PLT26:
+	case R_OR1K_PLTA26:
 	  /* If the call is not local, redirect the branch to the PLT.
 	     Otherwise do nothing to send the branch to the symbol direct.  */
-	  if (!SYMBOL_CALLS_LOCAL (info, h))
-	    {
-	      BFD_ASSERT (h->plt.offset != (bfd_vma) -1);
-	      relocation = plt_base + h->plt.offset;
-	    }
+	  if (!SYMBOL_CALLS_LOCAL (info, h)
+	      && h->plt.offset != (bfd_vma) -1)
+	    relocation = plt_base + h->plt.offset;
 
 	  /* Addend should be zero.  */
 	  if (rel->r_addend != 0)
@@ -1174,13 +1370,17 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	  break;
 
 	case R_OR1K_GOT16:
-	  /* Relocation is to the entry for this symbol in the global
-	     offset table.  */
+	case R_OR1K_GOT_PG21:
+	case R_OR1K_GOT_LO13:
+	  {
+	    bfd_vma off;
+
+	    /* Relocation is to the entry for this symbol
+	       in the global offset table.  */
 	  BFD_ASSERT (sgot != NULL);
 	  if (h != NULL)
 	    {
 	      bfd_boolean dyn;
-	      bfd_vma off;
 
 	      off = h->got.offset;
 	      BFD_ASSERT (off != (bfd_vma) -1);
@@ -1192,14 +1392,13 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		  || (bfd_link_pic (info)
 		      && SYMBOL_REFERENCES_LOCAL (info, h)))
 		{
-		  /* This is actually a static link, or it is a
-		     -Bsymbolic link and the symbol is defined
-		     locally, or the symbol was forced to be local
-		     because of a version file.  We must initialize
-		     this entry in the global offset table.  Since the
-		     offset must always be a multiple of 4, we use the
-		     least significant bit to record whether we have
-		     initialized it already.
+		    /* This is actually a static link, or it is a -Bsymbolic
+		       link and the symbol is defined locally, or the symbol
+		       was forced to be local because of a version file.
+		       We must initialize this entry in the GOT.  Since the
+		       offset must always be a multiple of 4, we use the least
+		       significant bit to record whether we have initialized
+		       it already.
 
 		     When doing a dynamic link, we create a .rela.got
 		     relocation entry to initialize the value.  This
@@ -1215,12 +1414,9 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		      h->got.offset |= 1;
 		    }
 		}
-
-	      relocation = sgot->output_offset + off;
 	    }
 	  else
 	    {
-	      bfd_vma off;
 	      bfd_byte *loc;
 
 	      BFD_ASSERT (local_got_offsets != NULL
@@ -1245,23 +1441,28 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 		      /* We need to generate a R_OR1K_RELATIVE reloc
 			 for the dynamic linker.  */
-		      srelgot = htab->root.srelgot;
+			srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 		      BFD_ASSERT (srelgot != NULL);
 
 		      outrel.r_offset = got_base + off;
 		      outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE);
 		      outrel.r_addend = relocation;
 		      loc = srelgot->contents;
-		      loc += srelgot->reloc_count * sizeof (Elf32_External_Rela);
+			loc += (srelgot->reloc_count
+				* sizeof (Elf32_External_Rela));
 		      bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc);
 		      ++srelgot->reloc_count;
 		    }
-
 		  local_got_offsets[r_symndx] |= 1;
 		}
-	      relocation = sgot->output_offset + off;
 	    }
 
+	    /* The GOT_PG21 and GOT_LO13 relocs are pc-relative,
+	       while the GOT16 reloc is GOT relative.  */
+	    relocation = got_base + off;
+	    if (r_type == R_OR1K_GOT16)
+	      relocation -= got_sym_value;
+
 	  /* Addend should be zero.  */
 	  if (rel->r_addend != 0)
 	    {
@@ -1271,6 +1472,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	      bfd_set_error (bfd_error_bad_value);
 	      ret_val = FALSE;
 	    }
+	  }
 	  break;
 
 	case R_OR1K_GOTOFF_LO16:
@@ -1287,10 +1489,13 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	      ret_val = FALSE;
 	      bfd_set_error (bfd_error_bad_value);
 	    }
-	  relocation -= got_base;
+	  relocation -= got_sym_value;
 	  break;
 
 	case R_OR1K_INSN_REL_26:
+	case R_OR1K_PCREL_PG21:
+	case R_OR1K_LO13:
+	case R_OR1K_SLO13:
 	  /* For a non-shared link, these will reference either the plt
 	     or a .dynbss copy of the symbol.  */
 	  if (bfd_link_pic (info) && !SYMBOL_REFERENCES_LOCAL (info, h))
@@ -1387,6 +1592,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 	case R_OR1K_TLS_LDM_HI16:
 	case R_OR1K_TLS_LDM_LO16:
+	case R_OR1K_TLS_LDM_PG21:
+	case R_OR1K_TLS_LDM_LO13:
 	case R_OR1K_TLS_LDO_HI16:
 	case R_OR1K_TLS_LDO_LO16:
 	  /* TODO: implement support for local dynamic.  */
@@ -1399,8 +1606,12 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
+	case R_OR1K_TLS_GD_PG21:
+	case R_OR1K_TLS_GD_LO13:
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
+	case R_OR1K_TLS_IE_PG21:
+	case R_OR1K_TLS_IE_LO13:
 	case R_OR1K_TLS_IE_AHI16:
 	  {
 	    bfd_vma gotoff;
@@ -1442,8 +1653,11 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		  && (h->root.type == bfd_link_hash_defweak || !h->def_regular));
 
 	    /* Shared GD.  */
-	    if (dynamic && (howto->type == R_OR1K_TLS_GD_HI16
-			    || howto->type == R_OR1K_TLS_GD_LO16))
+	    if (dynamic
+		&& (howto->type == R_OR1K_TLS_GD_HI16
+		    || howto->type == R_OR1K_TLS_GD_LO16
+		    || howto->type == R_OR1K_TLS_GD_PG21
+		    || howto->type == R_OR1K_TLS_GD_LO13))
 	      {
 		int i;
 
@@ -1474,7 +1688,9 @@ or1k_elf_relocate_section (bfd *output_bfd,
 	      }
 	    /* Static GD.  */
 	    else if (howto->type == R_OR1K_TLS_GD_HI16
-		     || howto->type == R_OR1K_TLS_GD_LO16)
+		     || howto->type == R_OR1K_TLS_GD_LO16
+		     || howto->type == R_OR1K_TLS_GD_PG21
+		     || howto->type == R_OR1K_TLS_GD_LO13)
 	      {
 		bfd_put_32 (output_bfd, 1, sgot->contents + gotoff);
 		bfd_put_32 (output_bfd, tpoff (info, relocation),
@@ -1508,9 +1724,17 @@ or1k_elf_relocate_section (bfd *output_bfd,
 		bfd_put_32 (output_bfd, tpoff (info, relocation),
 			    sgot->contents + gotoff);
 	      }
-	    relocation = sgot->output_offset + gotoff;
-	    break;
+
+	    /* The PG21 and LO13 relocs are pc-relative, while the
+	       rest are GOT relative.  */
+	    relocation = got_base + gotoff;
+	    if (!(r_type == R_OR1K_TLS_GD_PG21
+		  || r_type == R_OR1K_TLS_GD_LO13
+		  || r_type == R_OR1K_TLS_IE_PG21
+		  || r_type == R_OR1K_TLS_IE_LO13))
+	      relocation -= got_sym_value;
 	  }
+	  break;
 
 	case R_OR1K_TLS_LE_HI16:
 	case R_OR1K_TLS_LE_LO16:
@@ -1665,16 +1889,22 @@ or1k_elf_check_relocs (bfd *abfd,
 	{
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
+	case R_OR1K_TLS_GD_PG21:
+	case R_OR1K_TLS_GD_LO13:
 	  tls_type = TLS_GD;
 	  break;
 	case R_OR1K_TLS_LDM_HI16:
 	case R_OR1K_TLS_LDM_LO16:
+	case R_OR1K_TLS_LDM_PG21:
+	case R_OR1K_TLS_LDM_LO13:
 	case R_OR1K_TLS_LDO_HI16:
 	case R_OR1K_TLS_LDO_LO16:
 	  tls_type = TLS_LD;
 	  break;
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
+	case R_OR1K_TLS_IE_PG21:
+	case R_OR1K_TLS_IE_LO13:
 	case R_OR1K_TLS_IE_AHI16:
 	  tls_type = TLS_IE;
 	  break;
@@ -1729,6 +1959,9 @@ or1k_elf_check_relocs (bfd *abfd,
 	  break;
 
 	  /* This relocation requires .plt entry.  */
+	case R_OR1K_PLTA26:
+	  htab->saw_plta = TRUE;
+	  /* FALLTHRU */
 	case R_OR1K_PLT26:
 	  if (h != NULL)
 	    {
@@ -1738,10 +1971,16 @@ or1k_elf_check_relocs (bfd *abfd,
 	  break;
 
 	case R_OR1K_GOT16:
+	case R_OR1K_GOT_PG21:
+	case R_OR1K_GOT_LO13:
 	case R_OR1K_TLS_GD_HI16:
 	case R_OR1K_TLS_GD_LO16:
+	case R_OR1K_TLS_GD_PG21:
+	case R_OR1K_TLS_GD_LO13:
 	case R_OR1K_TLS_IE_HI16:
 	case R_OR1K_TLS_IE_LO16:
+	case R_OR1K_TLS_IE_PG21:
+	case R_OR1K_TLS_IE_LO13:
 	case R_OR1K_TLS_IE_AHI16:
 	      if (h != NULL)
 		h->got.refcount += 1;
@@ -1785,6 +2024,9 @@ or1k_elf_check_relocs (bfd *abfd,
 	case R_OR1K_AHI16:
 	case R_OR1K_SLO16:
 	case R_OR1K_32:
+	case R_OR1K_PCREL_PG21:
+	case R_OR1K_LO13:
+	case R_OR1K_SLO13:
 	  {
 	    if (h != NULL && !bfd_link_pic (info))
 	      {
@@ -1928,6 +2170,36 @@ or1k_elf_check_relocs (bfd *abfd,
   return TRUE;
 }
 
+static void
+or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insn1,
+		      unsigned insn2, unsigned insn3, unsigned insnj)
+{
+  unsigned nodelay = elf_elfheader (output_bfd)->e_flags & EF_OR1K_NODELAY;
+  unsigned insn4;
+
+  /* Honor the no-delay-slot setting.  */
+  if (insn3 == OR1K_NOP)
+    {
+      insn4 = insn3;
+      if (nodelay)
+	insn3 = insnj;
+      else
+	insn3 = insn2, insn2 = insnj;
+    }
+  else
+    {
+      if (nodelay)
+	insn4 = insnj;
+      else
+	insn4 = insn3, insn3 = insnj;
+    }
+
+  bfd_put_32 (output_bfd, insn1, contents);
+  bfd_put_32 (output_bfd, insn2, contents + 4);
+  bfd_put_32 (output_bfd, insn3, contents + 8);
+  bfd_put_32 (output_bfd, insn4, contents + 12);
+}
+
 /* Finish up the dynamic sections.  */
 
 static bfd_boolean
@@ -1992,35 +2264,39 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
       splt = htab->root.splt;
       if (splt && splt->size > 0)
 	{
-	  if (bfd_link_pic (info))
+	  unsigned plt0, plt1, plt2;
+	  bfd_vma got_addr = sgot->output_section->vma + sgot->output_offset;
+
+	  /* Note we force 16 byte alignment on the .got, so that
+	     the movhi/adrp can be shared between the two loads.  */
+
+	  if (htab->saw_plta)
 	    {
-	      bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD0,
-			  splt->contents);
-	      bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD1,
-			  splt->contents + 4);
-	      bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD2,
-			  splt->contents + 8);
-	      bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD3,
-			  splt->contents + 12);
-	      bfd_put_32 (output_bfd, PLT0_PIC_ENTRY_WORD4,
-			  splt->contents + 16);
+	      bfd_vma pc = splt->output_section->vma + splt->output_offset;
+	      unsigned pa = ((got_addr >> 13) - (pc >> 13)) & 0x1fffff;
+	      unsigned po = got_addr & 0x1fff;
+	      plt0 = OR1K_ADRP(12) | pa;
+	      plt1 = OR1K_LWZ(15,12) | (po + 8);
+	      plt2 = OR1K_LWZ(12,12) | (po + 4);
+	    }
+	  else if (bfd_link_pic (info))
+	    {
+	      plt0 = OR1K_LWZ(15, 16) | 8;	/* .got+8 */
+	      plt1 = OR1K_LWZ(12, 16) | 4;	/* .got+4 */
+	      plt2 = OR1K_NOP;
 	    }
 	  else
 	    {
-	      unsigned long addr;
-	      /* addr = .got + 4 */
-	      addr = sgot->output_section->vma + sgot->output_offset + 4;
-	      bfd_put_32 (output_bfd,
-			  PLT0_ENTRY_WORD0 | ((addr >> 16) & 0xffff),
-			  splt->contents);
-	      bfd_put_32 (output_bfd,
-			  PLT0_ENTRY_WORD1 | (addr & 0xffff),
-			  splt->contents + 4);
-	      bfd_put_32 (output_bfd, PLT0_ENTRY_WORD2, splt->contents + 8);
-	      bfd_put_32 (output_bfd, PLT0_ENTRY_WORD3, splt->contents + 12);
-	      bfd_put_32 (output_bfd, PLT0_ENTRY_WORD4, splt->contents + 16);
+	      unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+	      unsigned lo = got_addr & 0xffff;
+	      plt0 = OR1K_MOVHI(12) | ha;
+	      plt1 = OR1K_LWZ(15,12) | (lo + 8);
+	      plt2 = OR1K_LWZ(12,12) | (lo + 4);
 	    }
 
+	  or1k_write_plt_entry (output_bfd, splt->contents,
+				plt0, plt1, plt2, OR1K_JR(15));
+
 	  elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
 	}
     }
@@ -2062,11 +2338,15 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
 
   if (h->plt.offset != (bfd_vma) -1)
     {
+      unsigned int plt0, plt1, plt2;
       asection *splt;
       asection *sgot;
       asection *srela;
-
+      bfd_vma plt_base_addr;
+      bfd_vma plt_addr;
       bfd_vma plt_index;
+      bfd_vma plt_reloc;
+      bfd_vma got_base_addr;
       bfd_vma got_offset;
       bfd_vma got_addr;
       Elf_Internal_Rela rela;
@@ -2080,60 +2360,55 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
       srela = htab->root.srelplt;
       BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
 
+      plt_base_addr = splt->output_section->vma + splt->output_offset;
+      got_base_addr = sgot->output_section->vma + sgot->output_offset;
+
       /* Get the index in the procedure linkage table which
 	 corresponds to this symbol.  This is the index of this symbol
 	 in all the symbols for which we are making plt entries.  The
 	 first entry in the procedure linkage table is reserved.  */
       plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+      plt_addr = plt_base_addr + h->plt.offset;
+      plt_reloc = plt_index * sizeof (Elf32_External_Rela);
 
       /* Get the offset into the .got table of the entry that
 	corresponds to this function.  Each .got entry is 4 bytes.
 	The first three are reserved.  */
       got_offset = (plt_index + 3) * 4;
-      got_addr = got_offset;
+      got_addr = got_base_addr + got_offset;
 
       /* Fill in the entry in the procedure linkage table.  */
-      if (! bfd_link_pic (info))
+      if (htab->saw_plta)
 	{
-	  got_addr += htab->root.sgotplt->output_section->vma
-	    + htab->root.sgotplt->output_offset;
-	  bfd_put_32 (output_bfd, PLT_ENTRY_WORD0 | ((got_addr >> 16) & 0xffff),
-		      splt->contents + h->plt.offset);
-	  bfd_put_32 (output_bfd, PLT_ENTRY_WORD1 | (got_addr & 0xffff),
-		      splt->contents + h->plt.offset + 4);
-	  bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD2,
-		      splt->contents + h->plt.offset + 8);
-	  bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD3,
-		      splt->contents + h->plt.offset + 12);
-	  bfd_put_32 (output_bfd, PLT_ENTRY_WORD4
-		      | plt_index * sizeof (Elf32_External_Rela),
-		      splt->contents + h->plt.offset + 16);
+	  unsigned pa = ((got_addr >> 13) - (plt_addr >> 13)) & 0x1fffff;
+	  unsigned po = (got_addr & 0x1fff);
+	  plt0 = OR1K_ADRP(12) | pa;
+	  plt1 = OR1K_LWZ(12,12) | po;
+	  plt2 = OR1K_ORI0(11) | plt_reloc;
+	}
+      else if (bfd_link_pic (info))
+	{
+	  plt0 = OR1K_LWZ(12,16) | got_offset;
+	  plt1 = OR1K_ORI0(11) | plt_reloc;
+	  plt2 = OR1K_NOP;
 	}
       else
 	{
-	  bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD0 | (got_addr & 0xffff),
-		      splt->contents + h->plt.offset);
-	  bfd_put_32 (output_bfd, PLT_PIC_ENTRY_WORD1
-		      | plt_index * sizeof (Elf32_External_Rela),
-		      splt->contents + h->plt.offset + 4);
-	  bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD2,
-		      splt->contents + h->plt.offset + 8);
-	  bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD3,
-		      splt->contents + h->plt.offset + 12);
-	  bfd_put_32 (output_bfd, (bfd_vma) PLT_PIC_ENTRY_WORD4,
-		      splt->contents + h->plt.offset + 16);
+	  unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+	  unsigned lo = got_addr & 0xffff;
+	  plt0 = OR1K_MOVHI(12) | ha;
+	  plt1 = OR1K_LWZ(12,12) | lo;
+	  plt2 = OR1K_ORI0(11) | plt_reloc;
 	}
 
+      or1k_write_plt_entry (output_bfd, splt->contents + h->plt.offset,
+			    plt0, plt1, plt2, OR1K_JR(12));
+
       /* Fill in the entry in the global offset table.  */
-      bfd_put_32 (output_bfd,
-		  (splt->output_section->vma
-		   + splt->output_offset), /* Same offset.  */
-		  sgot->contents + got_offset);
+      bfd_put_32 (output_bfd, plt_addr, sgot->contents + got_offset);
 
       /* Fill in the entry in the .rela.plt section.  */
-      rela.r_offset = (sgot->output_section->vma
-		       + sgot->output_offset
-		       + got_offset);
+      rela.r_offset = got_addr;
       rela.r_info = ELF32_R_INFO (h->dynindx, R_OR1K_JMP_SLOT);
       rela.r_addend = 0;
       loc = srela->contents;
@@ -2146,7 +2421,6 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
 	     the .plt section.  Leave the value alone.  */
 	  sym->st_shndx = SHN_UNDEF;
 	}
-
     }
 
   if (h->got.offset != (bfd_vma) -1
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index f887e516ae..709fc09824 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2643,10 +2643,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_CRIS_32_IE",
   "BFD_RELOC_OR1K_REL_26",
   "BFD_RELOC_OR1K_SLO16",
+  "BFD_RELOC_OR1K_PCREL_PG21",
+  "BFD_RELOC_OR1K_LO13",
+  "BFD_RELOC_OR1K_SLO13",
   "BFD_RELOC_OR1K_GOTPC_HI16",
   "BFD_RELOC_OR1K_GOTPC_LO16",
   "BFD_RELOC_OR1K_GOT16",
+  "BFD_RELOC_OR1K_GOT_PG21",
+  "BFD_RELOC_OR1K_GOT_LO13",
   "BFD_RELOC_OR1K_PLT26",
+  "BFD_RELOC_OR1K_PLTA26",
   "BFD_RELOC_OR1K_GOTOFF_SLO16",
   "BFD_RELOC_OR1K_COPY",
   "BFD_RELOC_OR1K_GLOB_DAT",
@@ -2654,13 +2660,19 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_OR1K_RELATIVE",
   "BFD_RELOC_OR1K_TLS_GD_HI16",
   "BFD_RELOC_OR1K_TLS_GD_LO16",
+  "BFD_RELOC_OR1K_TLS_GD_PG21",
+  "BFD_RELOC_OR1K_TLS_GD_LO13",
   "BFD_RELOC_OR1K_TLS_LDM_HI16",
   "BFD_RELOC_OR1K_TLS_LDM_LO16",
+  "BFD_RELOC_OR1K_TLS_LDM_PG21",
+  "BFD_RELOC_OR1K_TLS_LDM_LO13",
   "BFD_RELOC_OR1K_TLS_LDO_HI16",
   "BFD_RELOC_OR1K_TLS_LDO_LO16",
   "BFD_RELOC_OR1K_TLS_IE_HI16",
   "BFD_RELOC_OR1K_TLS_IE_AHI16",
   "BFD_RELOC_OR1K_TLS_IE_LO16",
+  "BFD_RELOC_OR1K_TLS_IE_PG21",
+  "BFD_RELOC_OR1K_TLS_IE_LO13",
   "BFD_RELOC_OR1K_TLS_LE_HI16",
   "BFD_RELOC_OR1K_TLS_LE_AHI16",
   "BFD_RELOC_OR1K_TLS_LE_LO16",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index de870441df..0a9324be7b 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6136,14 +6136,26 @@ ENUM
   BFD_RELOC_OR1K_REL_26
 ENUMX
   BFD_RELOC_OR1K_SLO16
+ENUMX
+  BFD_RELOC_OR1K_PCREL_PG21
+ENUMX
+  BFD_RELOC_OR1K_LO13
+ENUMX
+  BFD_RELOC_OR1K_SLO13
 ENUMX
   BFD_RELOC_OR1K_GOTPC_HI16
 ENUMX
   BFD_RELOC_OR1K_GOTPC_LO16
 ENUMX
   BFD_RELOC_OR1K_GOT16
+ENUMX
+  BFD_RELOC_OR1K_GOT_PG21
+ENUMX
+  BFD_RELOC_OR1K_GOT_LO13
 ENUMX
   BFD_RELOC_OR1K_PLT26
+ENUMX
+  BFD_RELOC_OR1K_PLTA26
 ENUMX
   BFD_RELOC_OR1K_GOTOFF_SLO16
 ENUMX
@@ -6158,10 +6170,18 @@ ENUMX
   BFD_RELOC_OR1K_TLS_GD_HI16
 ENUMX
   BFD_RELOC_OR1K_TLS_GD_LO16
+ENUMX
+  BFD_RELOC_OR1K_TLS_GD_PG21
+ENUMX
+  BFD_RELOC_OR1K_TLS_GD_LO13
 ENUMX
   BFD_RELOC_OR1K_TLS_LDM_HI16
 ENUMX
   BFD_RELOC_OR1K_TLS_LDM_LO16
+ENUMX
+  BFD_RELOC_OR1K_TLS_LDM_PG21
+ENUMX
+  BFD_RELOC_OR1K_TLS_LDM_LO13
 ENUMX
   BFD_RELOC_OR1K_TLS_LDO_HI16
 ENUMX
@@ -6172,6 +6192,10 @@ ENUMX
   BFD_RELOC_OR1K_TLS_IE_AHI16
 ENUMX
   BFD_RELOC_OR1K_TLS_IE_LO16
+ENUMX
+  BFD_RELOC_OR1K_TLS_IE_PG21
+ENUMX
+  BFD_RELOC_OR1K_TLS_IE_LO13
 ENUMX
   BFD_RELOC_OR1K_TLS_LE_HI16
 ENUMX
diff --git a/cpu/or1k.opc b/cpu/or1k.opc
index 20b6820059..d41565470a 100644
--- a/cpu/or1k.opc
+++ b/cpu/or1k.opc
@@ -56,155 +56,249 @@ static const char *
 parse_disp26 (CGEN_CPU_DESC cd,
 	      const char ** strp,
 	      int opindex,
-	      int opinfo,
+	      int opinfo ATTRIBUTE_UNUSED,
 	      enum cgen_parse_operand_result * resultp,
 	      bfd_vma * valuep)
 {
+  const char *str = *strp;
   const char *errmsg = NULL;
-  enum cgen_parse_operand_result result_type;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
 
-  if (strncasecmp (*strp, "plt(", 4) == 0)
+  if (strncasecmp (str, "plta(", 5) == 0)
     {
-      bfd_vma value;
+      *strp = str + 5;
+      reloc = BFD_RELOC_OR1K_PLTA26;
+    }
+  else if (strncasecmp (str, "plt(", 4) == 0)
+    {
+      *strp = str + 4;
+      reloc = BFD_RELOC_OR1K_PLT26;
+    }
 
-      *strp += 4;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_OR1K_PLT26,
-				   & result_type, & value);
+  errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
+
+  if (reloc != BFD_RELOC_OR1K_REL_26)
+    {
       if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 2) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	errmsg = MISSING_CLOSING_PARENTHESIS;
+      else
+	++*strp;
+    }
+
+  return errmsg;
+}
+
+static const char *
+parse_disp21 (CGEN_CPU_DESC cd,
+	      const char ** strp,
+	      int opindex,
+	      int opinfo ATTRIBUTE_UNUSED,
+	      enum cgen_parse_operand_result * resultp,
+	      bfd_vma * valuep)
+{
+  const char *str = *strp;
+  const char *errmsg = NULL;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
+
+  if (strncasecmp (str, "got(", 4) == 0)
+    {
+      *strp = str + 4;
+      reloc = BFD_RELOC_OR1K_GOT_PG21;
+    }
+  else if (strncasecmp (str, "tlsgd(", 6) == 0)
+    {
+      *strp = str + 6;
+      reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
+    }
+  else if (strncasecmp (str, "tlsldm(", 7) == 0)
+    {
+      *strp = str + 7;
+      reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
+    }
+  else if (strncasecmp (str, "gottp(", 6) == 0)
+    {
+      *strp = str + 6;
+      reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
+    }
+
+  errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
+
+  if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
+    {
+      if (**strp != ')')
+	errmsg = MISSING_CLOSING_PARENTHESIS;
+      else
+	++*strp;
     }
-  return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
+
+  return errmsg;
 }
 
-enum {
+enum or1k_rclass {
+  RCLASS_DIRECT   = 0,
+  RCLASS_GOT      = 1,
+  RCLASS_GOTPC    = 2,
+  RCLASS_GOTOFF   = 3,
+  RCLASS_TLSGD    = 4,
+  RCLASS_TLSLDM   = 5,
+  RCLASS_DTPOFF   = 6,
+  RCLASS_GOTTPOFF = 7,
+  RCLASS_TPOFF    = 8,
+};
+
+enum or1k_rtype {
   RTYPE_LO = 0,
-  RTYPE_HI = 1,
-  RTYPE_AHI = 2,
-  RTYPE_SLO = 3,
-
-  RTYPE_GOT      = (1 << 2),
-  RTYPE_GOTPC    = (2 << 2),
-  RTYPE_GOTOFF   = (3 << 2),
-  RTYPE_TLSGD    = (4 << 2),
-  RTYPE_TLSLDM   = (5 << 2),
-  RTYPE_DTPOFF   = (6 << 2),
-  RTYPE_GOTTPOFF = (7 << 2),
-  RTYPE_TPOFF    = (8 << 2),
+  RTYPE_SLO = 1,
+  RTYPE_PO = 2,
+  RTYPE_SPO = 3,
+  RTYPE_HI = 4,
+  RTYPE_AHI = 5,
 };
 
-static const bfd_reloc_code_real_type or1k_imm16_relocs[][4] = {
+#define RCLASS_SHIFT 3
+#define RTYPE_MASK   7
+
+static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
   { BFD_RELOC_LO16,
+    BFD_RELOC_OR1K_SLO16,
+    BFD_RELOC_OR1K_LO13,
+    BFD_RELOC_OR1K_SLO13,
     BFD_RELOC_HI16,
-    BFD_RELOC_HI16_S,
-    BFD_RELOC_OR1K_SLO16 },
+    BFD_RELOC_HI16_S, },
   { BFD_RELOC_OR1K_GOT16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_GOT_LO13,
     BFD_RELOC_UNUSED,
     BFD_RELOC_UNUSED,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_GOTPC_LO16,
-    BFD_RELOC_OR1K_GOTPC_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_GOTPC_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_LO16_GOTOFF,
+    BFD_RELOC_OR1K_GOTOFF_SLO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_HI16_GOTOFF,
-    BFD_RELOC_HI16_S_GOTOFF,
-    BFD_RELOC_OR1K_GOTOFF_SLO16 },
+    BFD_RELOC_HI16_S_GOTOFF },
   { BFD_RELOC_OR1K_TLS_GD_LO16,
-    BFD_RELOC_OR1K_TLS_GD_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_GD_LO13,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_GD_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_LDM_LO16,
-    BFD_RELOC_OR1K_TLS_LDM_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDM_LO13,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDM_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_LDO_LO16,
-    BFD_RELOC_OR1K_TLS_LDO_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDO_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_IE_LO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_IE_LO13,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_OR1K_TLS_IE_HI16,
-    BFD_RELOC_OR1K_TLS_IE_AHI16,
-    BFD_RELOC_UNUSED },
+    BFD_RELOC_OR1K_TLS_IE_AHI16 },
   { BFD_RELOC_OR1K_TLS_LE_LO16,
+    BFD_RELOC_OR1K_TLS_LE_SLO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_OR1K_TLS_LE_HI16,
-    BFD_RELOC_OR1K_TLS_LE_AHI16,
-    BFD_RELOC_OR1K_TLS_LE_SLO16 }
+    BFD_RELOC_OR1K_TLS_LE_AHI16 },
 };
 
 static int
 parse_reloc(const char **strp)
 {
     const char *str = *strp;
-    int ret = 0;
+    enum or1k_rclass cls = RCLASS_DIRECT;
+    enum or1k_rtype typ;
 
     if (strncasecmp (str, "got(", 4) == 0)
       {
 	*strp = str + 4;
-	return RTYPE_GOT | RTYPE_LO;
+	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
+      }
+    if (strncasecmp (str, "gotpo(", 6) == 0)
+      {
+	*strp = str + 6;
+	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
+      }
+    if (strncasecmp (str, "gottppo(", 8) == 0)
+      {
+	*strp = str + 8;
+	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
       }
 
     if (strncasecmp (str, "gotpc", 5) == 0)
       {
 	str += 5;
-	ret = RTYPE_GOTPC;
+	cls = RCLASS_GOTPC;
       }
     else if (strncasecmp (str, "gotoff", 6) == 0)
       {
 	str += 6;
-	ret = RTYPE_GOTOFF;
+	cls = RCLASS_GOTOFF;
       }
     else if (strncasecmp (str, "tlsgd", 5) == 0)
       {
 	str += 5;
-	ret = RTYPE_TLSGD;
+	cls = RCLASS_TLSGD;
       }
     else if (strncasecmp (str, "tlsldm", 6) == 0)
       {
 	str += 6;
-	ret = RTYPE_TLSLDM;
+	cls = RCLASS_TLSLDM;
       }
     else if (strncasecmp (str, "dtpoff", 6) == 0)
       {
 	str += 6;
-	ret = RTYPE_DTPOFF;
+	cls = RCLASS_DTPOFF;
       }
     else if (strncasecmp (str, "gottpoff", 8) == 0)
       {
 	str += 8;
-	ret = RTYPE_GOTTPOFF;
+	cls = RCLASS_GOTTPOFF;
       }
     else if (strncasecmp (str, "tpoff", 5) == 0)
       {
 	str += 5;
-	ret = RTYPE_TPOFF;
+	cls = RCLASS_TPOFF;
       }
 
     if (strncasecmp (str, "hi(", 3) == 0)
       {
 	str += 3;
-	ret |= RTYPE_HI;
+	typ = RTYPE_HI;
       }
     else if (strncasecmp (str, "lo(", 3) == 0)
       {
 	str += 3;
-	ret |= RTYPE_LO;
+	typ = RTYPE_LO;
       }
     else if (strncasecmp (str, "ha(", 3) == 0)
       {
 	str += 3;
-	ret |= RTYPE_AHI;
+	typ = RTYPE_AHI;
+      }
+    else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
+      {
+	str += 3;
+	typ = RTYPE_PO;
       }
     else
       return -1;
 
     *strp = str;
-    return ret;
+    return (cls << RCLASS_SHIFT) | typ;
 }
 
 static const char *
@@ -214,23 +308,28 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
   const char *errmsg;
   enum cgen_parse_operand_result result_type;
   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
-  int reloc_type;
+  enum or1k_rtype reloc_type;
+  int reloc_code;
   bfd_vma ret;
 
   if (**strp == '#')
     ++*strp;
 
-  reloc_type = parse_reloc (strp);
-  if (reloc_type >= 0)
+  reloc_code = parse_reloc (strp);
+  reloc_type = reloc_code & RTYPE_MASK;
+  if (reloc_code >= 0)
     {
+      enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
       if (splitp)
 	{
-	  if ((reloc_type & 3) == RTYPE_LO && reloc_type != RTYPE_GOT)
-	    reloc_type |= RTYPE_SLO;
+	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
+	      && reloc_class != RCLASS_GOT)
+	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
+	    reloc_type |= 1;
 	  else
 	    return INVALID_STORE_RELOC;
 	}
-      reloc = or1k_imm16_relocs[reloc_type >> 2][reloc_type & 3];
+      reloc = or1k_imm16_relocs[reloc_class][reloc_type];
     }
 
   if (reloc != BFD_RELOC_UNUSED)
@@ -246,7 +345,7 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
       ret = value;
 
       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	switch (reloc_type & 3)
+	switch (reloc_type)
 	  {
 	  case RTYPE_AHI:
 	    ret += 0x8000;
@@ -259,6 +358,10 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
 	    ret &= 0xffff;
 	    ret = (ret ^ 0x8000) - 0x8000;
 	    break;
+	  case RTYPE_PO:
+	  case RTYPE_SPO:
+	    ret &= 0x1fff;
+	    break;
 	  default:
 	    abort ();
 	  }
diff --git a/cpu/or1korbis.cpu b/cpu/or1korbis.cpu
index 535bd28bff..6fbf40ad99 100644
--- a/cpu/or1korbis.cpu
+++ b/cpu/or1korbis.cpu
@@ -74,10 +74,25 @@
     25
     26
     INT
-    ((value pc) (sra SI (sub IAI value pc) (const 2)))
+    ((value pc) (sra IAI (sub IAI value pc) (const 2)))
     ((value pc) (add IAI (sll IAI value (const 2)) pc))
     )
 
+; PC relative, 21-bit, 13 shifted to right, aligned.
+; Note that the alignment means that we can't simplify relocations in the
+; same way as we do for pc-relative, so we use ABS-ADDR instead of PCREL-ADDR.
+(df f-disp21
+    "disp21"
+    ((MACH ORBIS-MACHS) ABS-ADDR)
+    20
+    21
+    INT
+    ((value pc)
+     (sub IAI (sra IAI value (const 13)) (sra IAI pc (const 13))))
+    ((value pc)
+     (sll IAI (add IAI value (sra IAI pc (const 13))) (const 13)))
+    )
+
 ; Immediates.
 (dnf f-uimm16    "uimm16"                      ((MACH ORBIS-MACHS))          15 16)
 (df  f-simm16    "simm16"                      ((MACH ORBIS-MACHS) SIGN-OPT) 15 16 INT #f #f)
@@ -134,6 +149,7 @@
   insn-opcode "insn main opcode enums" ((MACH ORBIS-MACHS)) OPC_ f-opcode
   (("J"            #x00)
    ("JAL"          #x01)
+   ("ADRP"	   #x02)
    ("BNF"          #x03)
    ("BF"           #x04)
    ("NOP"          #x05)
@@ -311,6 +327,15 @@
   (handlers (parse "disp26"))
   )
 
+(define-operand
+  (name disp21)
+  (comment "pc-rel 21 bit")
+  (attrs (MACH ORBIS-MACHS))
+  (type h-iaddr)
+  (index f-disp21)
+  (handlers (parse "disp21"))
+  )
+
 (define-operand
   (name simm16)
   (comment "16-bit signed immediate")
@@ -403,6 +428,14 @@
            )
   )
 
+(dni l-adrp "adrp reg/disp21"
+    ((MACH ORBIS-MACHS))
+    "l.adrp $rD,${disp21}"
+    (+ OPC_ADRP rD disp21)
+    (set UWI rD disp21)
+    ()
+  )
+
 (define-cti
   l-jal
   "jump and link (pc-relative iaddr)"
diff --git a/gas/config/tc-or1k.c b/gas/config/tc-or1k.c
index 8862c35480..c7dd457c36 100644
--- a/gas/config/tc-or1k.c
+++ b/gas/config/tc-or1k.c
@@ -362,12 +362,18 @@ or1k_apply_fix (struct fix *f, valueT *t, segT s)
     {
     case BFD_RELOC_OR1K_TLS_GD_HI16:
     case BFD_RELOC_OR1K_TLS_GD_LO16:
+    case BFD_RELOC_OR1K_TLS_GD_PG21:
+    case BFD_RELOC_OR1K_TLS_GD_LO13:
     case BFD_RELOC_OR1K_TLS_LDM_HI16:
     case BFD_RELOC_OR1K_TLS_LDM_LO16:
+    case BFD_RELOC_OR1K_TLS_LDM_PG21:
+    case BFD_RELOC_OR1K_TLS_LDM_LO13:
     case BFD_RELOC_OR1K_TLS_LDO_HI16:
     case BFD_RELOC_OR1K_TLS_LDO_LO16:
     case BFD_RELOC_OR1K_TLS_IE_HI16:
     case BFD_RELOC_OR1K_TLS_IE_LO16:
+    case BFD_RELOC_OR1K_TLS_IE_PG21:
+    case BFD_RELOC_OR1K_TLS_IE_LO13:
     case BFD_RELOC_OR1K_TLS_LE_HI16:
     case BFD_RELOC_OR1K_TLS_LE_LO16:
       S_SET_THREAD_LOCAL (f->fx_addsy);
diff --git a/gas/testsuite/gas/or1k/allinsn.d b/gas/testsuite/gas/or1k/allinsn.d
index 1b36cce1bc..a4ffe43f0b 100644
--- a/gas/testsuite/gas/or1k/allinsn.d
+++ b/gas/testsuite/gas/or1k/allinsn.d
@@ -690,3 +690,9 @@ Disassembly of section \.text:
  834:	4c 02 ff ff 	l\.maci r2,-1
  838:	4c 02 7f ff 	l\.maci r2,32767
  83c:	4c 02 80 00 	l\.maci r2,-32768
+
+00000840 <l_adrp>:
+ 840:	08 60 00 00 	l\.adrp r3,0 <localtext>
+			840: R_OR1K_PCREL_PG21	globaldata
+ 844:	08 60 00 00 	l\.adrp r3,0 <localtext>
+			844: R_OR1K_PCREL_PG21	\.data
diff --git a/gas/testsuite/gas/or1k/allinsn.s b/gas/testsuite/gas/or1k/allinsn.s
index 321aea3036..55d703734e 100644
--- a/gas/testsuite/gas/or1k/allinsn.s
+++ b/gas/testsuite/gas/or1k/allinsn.s
@@ -677,3 +677,6 @@ l_maci:
 	l.maci r2,-1
 	l.maci r2,32767
 	l.maci r2,-32768
+l_adrp:
+	l.adrp r3,globaldata
+	l.adrp r3,localdata
diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
index f90a1ae269..d1bcf5608b 100644
--- a/gas/testsuite/gas/or1k/reloc-1.d
+++ b/gas/testsuite/gas/or1k/reloc-1.d
@@ -52,5 +52,21 @@ OFFSET   TYPE              VALUE
 000000ac R_OR1K_TLS_LE_AHI16  x
 000000b0 R_OR1K_TLS_LE_LO16  x
 000000b4 R_OR1K_TLS_LE_SLO16  x
+000000b8 R_OR1K_PLTA26     x
+000000bc R_OR1K_PLTA26     x
+000000c0 R_OR1K_PLTA26     x
+000000c4 R_OR1K_PLTA26     x
+000000c8 R_OR1K_GOT_PG21   x
+000000cc R_OR1K_TLS_GD_PG21  x
+000000d0 R_OR1K_TLS_LDM_PG21  x
+000000d4 R_OR1K_TLS_IE_PG21  x
+000000d8 R_OR1K_LO13       x
+000000dc R_OR1K_GOT_LO13   x
+000000e0 R_OR1K_TLS_GD_LO13  x
+000000e4 R_OR1K_TLD_LDM_LO13  x
+000000e8 R_OR1K_TLS_IE_LO13  x
+000000ec R_OR1K_LO13       x
+000000f0 R_OR1K_GOT_LO13   x
+000000f4 R_OR1K_SLO13      x
 
 
diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
index 4966dc56be..e76abef653 100644
--- a/gas/testsuite/gas/or1k/reloc-1.s
+++ b/gas/testsuite/gas/or1k/reloc-1.s
@@ -54,3 +54,23 @@
 	l.movhi	r3,tpoffha(x)
 	l.lwz	r3,tpofflo(x)(r3)
 	l.sw	tpofflo(x)(r3),r3
+
+	l.j	plta(x)
+	l.jal	plta(x)
+	l.bf	plta(x)
+	l.bnf	plta(x)
+
+	l.adrp	r3,got(x)
+	l.adrp	r3,tlsgd(x)
+	l.adrp	r3,tlsldm(x)
+	l.adrp	r3,gottp(x)
+
+	l.ori	r4,r3,po(x)
+	l.ori	r4,r3,gotpo(x)
+	l.ori	r4,r3,tlsgdpo(x)
+	l.ori	r4,r3,tlsldmpo(x)
+	l.ori	r4,r3,gottppo(x)
+
+	l.lbz	r5,po(x)(r3)
+	l.lbz	r5,gotpo(x)(r3)
+	l.sb	po(x)(r3),r6
diff --git a/gas/testsuite/gas/or1k/reloc-2.l b/gas/testsuite/gas/or1k/reloc-2.l
index 7a32a7dc14..c104fd9d6e 100644
--- a/gas/testsuite/gas/or1k/reloc-2.l
+++ b/gas/testsuite/gas/or1k/reloc-2.l
@@ -8,3 +8,4 @@
 .*:9: Error: relocation invalid for store .*
 .*:11: Error: relocation invalid for store .*
 .*:12: Error: relocation invalid for store .*
+.*:13: Error: relocation invalid for store .*
diff --git a/gas/testsuite/gas/or1k/reloc-2.s b/gas/testsuite/gas/or1k/reloc-2.s
index 835dd1c84b..4d20aa7ba0 100644
--- a/gas/testsuite/gas/or1k/reloc-2.s
+++ b/gas/testsuite/gas/or1k/reloc-2.s
@@ -10,3 +10,4 @@
 	l.sw	tpofflo(x)(r4),r3
 	l.sw	tpoffhi(x)(r4),r3
 	l.sw	tpoffha(x)(r4),r3
+	l.sw	gotpo(x)(r4),r3
diff --git a/include/elf/or1k.h b/include/elf/or1k.h
index e3291d31d3..4369e6250d 100644
--- a/include/elf/or1k.h
+++ b/include/elf/or1k.h
@@ -65,6 +65,18 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
   RELOC_NUMBER (R_OR1K_SLO16,         39)
   RELOC_NUMBER (R_OR1K_GOTOFF_SLO16,  40)
   RELOC_NUMBER (R_OR1K_TLS_LE_SLO16,  41)
+  RELOC_NUMBER (R_OR1K_PCREL_PG21,    42)
+  RELOC_NUMBER (R_OR1K_GOT_PG21,      43)
+  RELOC_NUMBER (R_OR1K_TLS_GD_PG21,   44)
+  RELOC_NUMBER (R_OR1K_TLS_LDM_PG21,  45)
+  RELOC_NUMBER (R_OR1K_TLS_IE_PG21,   46)
+  RELOC_NUMBER (R_OR1K_LO13,          47)
+  RELOC_NUMBER (R_OR1K_GOT_LO13,      48)
+  RELOC_NUMBER (R_OR1K_TLS_GD_LO13,   49)
+  RELOC_NUMBER (R_OR1K_TLS_LDM_LO13,  50)
+  RELOC_NUMBER (R_OR1K_TLS_IE_LO13,   51)
+  RELOC_NUMBER (R_OR1K_SLO13,         52)
+  RELOC_NUMBER (R_OR1K_PLTA26,        53)
 END_RELOC_NUMBERS (R_OR1K_max)
 
 #define EF_OR1K_NODELAY (1UL << 0)
diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
index 8f09a7c40e..540ca29ed4 100644
--- a/ld/testsuite/ld-or1k/or1k.exp
+++ b/ld/testsuite/ld-or1k/or1k.exp
@@ -38,6 +38,23 @@ set or1ktests {
      "offsets1"}
 }
 
+set or1kplttests {
+    {"PLTA -fpic -shared" "-fpic -shared" ""
+     "" {plta1.s}
+     {{objdump -dr plta1.dd}}
+     "libplta1.so"}
+    {"PLT -fpic -shared" "-fpic -shared" ""
+     "" {plt1.s}
+     {{objdump -dr plt1.dd}}
+     "libplt1.so"}
+    {"Helper shared library" "-fpic -shared" ""
+     "" {pltlib.s} {} "libpltlib.so"}
+    {"PLT -fno-pic exec -relax" "-relax tmpdir/libpltlib.so" ""
+     "" {plt1.s}
+     {{objdump -dr plt1.x.dd}}
+     "plt1.x"}
+}
+
 # Not implemented yet
 #   {"TLS -fpic -shared" "-shared -melf64alpha" ""
 #    "" {align.s tlspic1.s tlspic2.s}
@@ -66,4 +83,9 @@ set or1ktests {
 #    "" {tlsg.s}
 #    {{objdump -sj.debug_foobar tlsg.sd}} "tlsg"}
 
+# Shared objects not supported on newlib
 run_ld_link_tests $or1ktests
+if { ![istarget "or1k*-*-elf*"] } {
+    run_ld_link_tests $or1kplttests
+    return
+}
diff --git a/ld/testsuite/ld-or1k/plt1.dd b/ld/testsuite/ld-or1k/plt1.dd
new file mode 100644
index 0000000000..a982530fa9
--- /dev/null
+++ b/ld/testsuite/ld-or1k/plt1.dd
@@ -0,0 +1,27 @@
+
+.*\.so:     file format elf32-or1k
+
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <\.plt>:
+ [0-9a-f]+:	85 f0 00 08 	l\.lwz r15,8\(r16\)
+ [0-9a-f]+:	44 00 78 00 	l\.jr r15
+ [0-9a-f]+:	85 90 00 04 	l\.lwz r12,4\(r16\)
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+ [0-9a-f]+:	85 90 00 0c 	l\.lwz r12,12\(r16\)
+ [0-9a-f]+:	44 00 60 00 	l\.jr r12
+ [0-9a-f]+:	a9 60 00 00 	l\.ori r11,r0,0x0
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+ [0-9a-f]+:	85 90 00 10 	l\.lwz r12,16\(r16\)
+ [0-9a-f]+:	44 00 60 00 	l\.jr r12
+ [0-9a-f]+:	a9 60 00 0c 	l\.ori r11,r0,0xc
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+:	03 ff ff f8 	l\.j [0-9a-f]+ <.plt\+0x10>
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+ [0-9a-f]+:	03 ff ff fa 	l\.j [0-9a-f]+ <.plt\+0x20>
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
diff --git a/ld/testsuite/ld-or1k/plt1.s b/ld/testsuite/ld-or1k/plt1.s
new file mode 100644
index 0000000000..a5573bdc2f
--- /dev/null
+++ b/ld/testsuite/ld-or1k/plt1.s
@@ -0,0 +1,11 @@
+	.data
+	.p2align 16
+
+	.text
+	.globl	_start
+_start:
+
+	l.j plt(x)
+	 l.nop
+	l.j plt(y)
+	 l.nop
diff --git a/ld/testsuite/ld-or1k/plt1.x.dd b/ld/testsuite/ld-or1k/plt1.x.dd
new file mode 100644
index 0000000000..d2f47a1257
--- /dev/null
+++ b/ld/testsuite/ld-or1k/plt1.x.dd
@@ -0,0 +1,27 @@
+
+.*\.x:     file format elf32-or1k
+
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <\.plt>:
+ +[0-9a-f]+:	19 80 00 00 	l\.movhi r12,0x0
+ +[0-9a-f]+:	85 ec [0-9a-f]+ [0-9a-f]+ 	l\.lwz r15,[0-9]+\(r12\)
+ +[0-9a-f]+:	44 00 78 00 	l\.jr r15
+ +[0-9a-f]+:	85 8c [0-9a-f]+ [0-9a-f]+ 	l\.lwz r12,[0-9]+\(r12\)
+ +[0-9a-f]+:	19 80 00 00 	l\.movhi r12,0x0
+ +[0-9a-f]+:	85 8c [0-9a-f]+ [0-9a-f]+ 	l\.lwz r12,[0-9]+\(r12\)
+ +[0-9a-f]+:	44 00 60 00 	l\.jr r12
+ +[0-9a-f]+:	a9 60 00 00 	l\.ori r11,r0,0x0
+ +[0-9a-f]+:	19 80 00 00 	l\.movhi r12,0x0
+ +[0-9a-f]+:	85 8c [0-9a-f]+ [0-9a-f]+ 	l\.lwz r12,[0-9]+\(r12\)
+ +[0-9a-f]+:	44 00 60 00 	l\.jr r12
+ +[0-9a-f]+:	a9 60 00 0c 	l\.ori r11,r0,0xc
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+ +[0-9a-f]+:	03 ff ff f8 	l\.j [0-9a-f]+ <.plt\+0x10>
+ +[0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+ +[0-9a-f]+:	03 ff ff fa 	l\.j [0-9a-f]+ <.plt\+0x20>
+ +[0-9a-f]+:	15 00 00 00 	l\.nop 0x0
diff --git a/ld/testsuite/ld-or1k/plta1.dd b/ld/testsuite/ld-or1k/plta1.dd
new file mode 100644
index 0000000000..6767c41607
--- /dev/null
+++ b/ld/testsuite/ld-or1k/plta1.dd
@@ -0,0 +1,27 @@
+
+.*\.so:     file format elf32-or1k
+
+
+Disassembly of section .plt:
+
+[0-9a-f]+ <.plt>:
+ [0-9a-f]+:	09 80 00 01 	l\.adrp r12,2000 <.*>
+ [0-9a-f]+:	85 ec 02 10 	l\.lwz r15,528\(r12\)
+ [0-9a-f]+:	44 00 78 00 	l\.jr r15
+ [0-9a-f]+:	85 8c 02 0c 	l\.lwz r12,524\(r12\)
+ [0-9a-f]+:	09 80 00 01 	l\.adrp r12,2000 <.*>
+ [0-9a-f]+:	85 8c 02 14 	l\.lwz r12,532\(r12\)
+ [0-9a-f]+:	44 00 60 00 	l\.jr r12
+ [0-9a-f]+:	a9 60 00 00 	l\.ori r11,r0,0x0
+ [0-9a-f]+:	09 80 00 01 	l\.adrp r12,2000 <.*>
+ [0-9a-f]+:	85 8c 02 18 	l\.lwz r12,536\(r12\)
+ [0-9a-f]+:	44 00 60 00 	l\.jr r12
+ [0-9a-f]+:	a9 60 00 0c 	l\.ori r11,r0,0xc
+
+Disassembly of section .text:
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+:	03 ff ff f8 	l\.j [0-9a-f]+ <.plt\+0x10>
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
+ [0-9a-f]+:	03 ff ff fa 	l\.j [0-9a-f]+ <.plt\+0x20>
+ [0-9a-f]+:	15 00 00 00 	l\.nop 0x0
diff --git a/ld/testsuite/ld-or1k/plta1.s b/ld/testsuite/ld-or1k/plta1.s
new file mode 100644
index 0000000000..82f8175b16
--- /dev/null
+++ b/ld/testsuite/ld-or1k/plta1.s
@@ -0,0 +1,11 @@
+	.data
+	.p2align 16
+
+	.text
+	.globl	_start
+_start:
+
+	l.j plta(x)
+	 l.nop
+	l.j plta(y)
+	 l.nop
diff --git a/ld/testsuite/ld-or1k/pltlib.s b/ld/testsuite/ld-or1k/pltlib.s
new file mode 100644
index 0000000000..baf76ca1af
--- /dev/null
+++ b/ld/testsuite/ld-or1k/pltlib.s
@@ -0,0 +1,12 @@
+	.section .data
+	.globl x, y
+x:	.long 33
+y:	.long 44
+
+	.section .text
+	.align 4
+	.global	func
+	.type	func, @function
+func:
+	l.jr	r9
+	 l.nop
diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
index 17bc17e244..b7d63d6f5d 100644
--- a/opcodes/or1k-asm.c
+++ b/opcodes/or1k-asm.c
@@ -60,155 +60,249 @@ static const char *
 parse_disp26 (CGEN_CPU_DESC cd,
 	      const char ** strp,
 	      int opindex,
-	      int opinfo,
+	      int opinfo ATTRIBUTE_UNUSED,
 	      enum cgen_parse_operand_result * resultp,
 	      bfd_vma * valuep)
 {
+  const char *str = *strp;
   const char *errmsg = NULL;
-  enum cgen_parse_operand_result result_type;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_REL_26;
 
-  if (strncasecmp (*strp, "plt(", 4) == 0)
+  if (strncasecmp (str, "plta(", 5) == 0)
     {
-      bfd_vma value;
+      *strp = str + 5;
+      reloc = BFD_RELOC_OR1K_PLTA26;
+    }
+  else if (strncasecmp (str, "plt(", 4) == 0)
+    {
+      *strp = str + 4;
+      reloc = BFD_RELOC_OR1K_PLT26;
+    }
 
-      *strp += 4;
-      errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_OR1K_PLT26,
-				   & result_type, & value);
+  errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
+
+  if (reloc != BFD_RELOC_OR1K_REL_26)
+    {
       if (**strp != ')')
-	return MISSING_CLOSING_PARENTHESIS;
-      ++*strp;
-      if (errmsg == NULL
-	  && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	value = (value >> 2) & 0xffff;
-      *valuep = value;
-      return errmsg;
+	errmsg = MISSING_CLOSING_PARENTHESIS;
+      else
+	++*strp;
     }
-  return cgen_parse_address (cd, strp, opindex, opinfo, resultp, valuep);
+
+  return errmsg;
 }
 
-enum {
+static const char *
+parse_disp21 (CGEN_CPU_DESC cd,
+	      const char ** strp,
+	      int opindex,
+	      int opinfo ATTRIBUTE_UNUSED,
+	      enum cgen_parse_operand_result * resultp,
+	      bfd_vma * valuep)
+{
+  const char *str = *strp;
+  const char *errmsg = NULL;
+  bfd_reloc_code_real_type reloc = BFD_RELOC_OR1K_PCREL_PG21;
+
+  if (strncasecmp (str, "got(", 4) == 0)
+    {
+      *strp = str + 4;
+      reloc = BFD_RELOC_OR1K_GOT_PG21;
+    }
+  else if (strncasecmp (str, "tlsgd(", 6) == 0)
+    {
+      *strp = str + 6;
+      reloc = BFD_RELOC_OR1K_TLS_GD_PG21;
+    }
+  else if (strncasecmp (str, "tlsldm(", 7) == 0)
+    {
+      *strp = str + 7;
+      reloc = BFD_RELOC_OR1K_TLS_LDM_PG21;
+    }
+  else if (strncasecmp (str, "gottp(", 6) == 0)
+    {
+      *strp = str + 6;
+      reloc = BFD_RELOC_OR1K_TLS_IE_PG21;
+    }
+
+  errmsg = cgen_parse_address (cd, strp, opindex, reloc, resultp, valuep);
+
+  if (reloc != BFD_RELOC_OR1K_PCREL_PG21)
+    {
+      if (**strp != ')')
+	errmsg = MISSING_CLOSING_PARENTHESIS;
+      else
+	++*strp;
+    }
+
+  return errmsg;
+}
+
+enum or1k_rclass {
+  RCLASS_DIRECT   = 0,
+  RCLASS_GOT      = 1,
+  RCLASS_GOTPC    = 2,
+  RCLASS_GOTOFF   = 3,
+  RCLASS_TLSGD    = 4,
+  RCLASS_TLSLDM   = 5,
+  RCLASS_DTPOFF   = 6,
+  RCLASS_GOTTPOFF = 7,
+  RCLASS_TPOFF    = 8,
+};
+
+enum or1k_rtype {
   RTYPE_LO = 0,
-  RTYPE_HI = 1,
-  RTYPE_AHI = 2,
-  RTYPE_SLO = 3,
-
-  RTYPE_GOT      = (1 << 2),
-  RTYPE_GOTPC    = (2 << 2),
-  RTYPE_GOTOFF   = (3 << 2),
-  RTYPE_TLSGD    = (4 << 2),
-  RTYPE_TLSLDM   = (5 << 2),
-  RTYPE_DTPOFF   = (6 << 2),
-  RTYPE_GOTTPOFF = (7 << 2),
-  RTYPE_TPOFF    = (8 << 2),
+  RTYPE_SLO = 1,
+  RTYPE_PO = 2,
+  RTYPE_SPO = 3,
+  RTYPE_HI = 4,
+  RTYPE_AHI = 5,
 };
 
-static const bfd_reloc_code_real_type or1k_imm16_relocs[][4] = {
+#define RCLASS_SHIFT 3
+#define RTYPE_MASK   7
+
+static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
   { BFD_RELOC_LO16,
+    BFD_RELOC_OR1K_SLO16,
+    BFD_RELOC_OR1K_LO13,
+    BFD_RELOC_OR1K_SLO13,
     BFD_RELOC_HI16,
-    BFD_RELOC_HI16_S,
-    BFD_RELOC_OR1K_SLO16 },
+    BFD_RELOC_HI16_S, },
   { BFD_RELOC_OR1K_GOT16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_GOT_LO13,
     BFD_RELOC_UNUSED,
     BFD_RELOC_UNUSED,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_GOTPC_LO16,
-    BFD_RELOC_OR1K_GOTPC_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_GOTPC_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_LO16_GOTOFF,
+    BFD_RELOC_OR1K_GOTOFF_SLO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_HI16_GOTOFF,
-    BFD_RELOC_HI16_S_GOTOFF,
-    BFD_RELOC_OR1K_GOTOFF_SLO16 },
+    BFD_RELOC_HI16_S_GOTOFF },
   { BFD_RELOC_OR1K_TLS_GD_LO16,
-    BFD_RELOC_OR1K_TLS_GD_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_GD_LO13,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_GD_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_LDM_LO16,
-    BFD_RELOC_OR1K_TLS_LDM_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDM_LO13,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDM_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_LDO_LO16,
-    BFD_RELOC_OR1K_TLS_LDO_HI16,
     BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_LDO_HI16,
     BFD_RELOC_UNUSED },
   { BFD_RELOC_OR1K_TLS_IE_LO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_OR1K_TLS_IE_LO13,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_OR1K_TLS_IE_HI16,
-    BFD_RELOC_OR1K_TLS_IE_AHI16,
-    BFD_RELOC_UNUSED },
+    BFD_RELOC_OR1K_TLS_IE_AHI16 },
   { BFD_RELOC_OR1K_TLS_LE_LO16,
+    BFD_RELOC_OR1K_TLS_LE_SLO16,
+    BFD_RELOC_UNUSED,
+    BFD_RELOC_UNUSED,
     BFD_RELOC_OR1K_TLS_LE_HI16,
-    BFD_RELOC_OR1K_TLS_LE_AHI16,
-    BFD_RELOC_OR1K_TLS_LE_SLO16 }
+    BFD_RELOC_OR1K_TLS_LE_AHI16 },
 };
 
 static int
 parse_reloc(const char **strp)
 {
     const char *str = *strp;
-    int ret = 0;
+    enum or1k_rclass cls = RCLASS_DIRECT;
+    enum or1k_rtype typ;
 
     if (strncasecmp (str, "got(", 4) == 0)
-	{
+      {
 	*strp = str + 4;
-	return RTYPE_GOT | RTYPE_LO;
-	}
+	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_LO;
+      }
+    if (strncasecmp (str, "gotpo(", 6) == 0)
+      {
+	*strp = str + 6;
+	return (RCLASS_GOT << RCLASS_SHIFT) | RTYPE_PO;
+      }
+    if (strncasecmp (str, "gottppo(", 8) == 0)
+      {
+	*strp = str + 8;
+	return (RCLASS_GOTTPOFF << RCLASS_SHIFT) | RTYPE_PO;
+      }
 
     if (strncasecmp (str, "gotpc", 5) == 0)
-	{
+      {
 	str += 5;
-	ret = RTYPE_GOTPC;
-	}
+	cls = RCLASS_GOTPC;
+      }
     else if (strncasecmp (str, "gotoff", 6) == 0)
-    {
+      {
 	str += 6;
-	ret = RTYPE_GOTOFF;
-    }
+	cls = RCLASS_GOTOFF;
+      }
     else if (strncasecmp (str, "tlsgd", 5) == 0)
-    {
+      {
 	str += 5;
-	ret = RTYPE_TLSGD;
-    }
+	cls = RCLASS_TLSGD;
+      }
     else if (strncasecmp (str, "tlsldm", 6) == 0)
-    {
+      {
 	str += 6;
-	ret = RTYPE_TLSLDM;
-    }
+	cls = RCLASS_TLSLDM;
+      }
     else if (strncasecmp (str, "dtpoff", 6) == 0)
-    {
+      {
 	str += 6;
-	ret = RTYPE_DTPOFF;
-    }
+	cls = RCLASS_DTPOFF;
+      }
     else if (strncasecmp (str, "gottpoff", 8) == 0)
-    {
+      {
 	str += 8;
-	ret = RTYPE_GOTTPOFF;
-    }
+	cls = RCLASS_GOTTPOFF;
+      }
     else if (strncasecmp (str, "tpoff", 5) == 0)
-    {
+      {
 	str += 5;
-	ret = RTYPE_TPOFF;
-    }
+	cls = RCLASS_TPOFF;
+      }
 
     if (strncasecmp (str, "hi(", 3) == 0)
-    {
+      {
 	str += 3;
-	ret |= RTYPE_HI;
-    }
+	typ = RTYPE_HI;
+      }
     else if (strncasecmp (str, "lo(", 3) == 0)
-    {
+      {
 	str += 3;
-	ret |= RTYPE_LO;
-    }
+	typ = RTYPE_LO;
+      }
     else if (strncasecmp (str, "ha(", 3) == 0)
-    {
+      {
 	str += 3;
-	ret |= RTYPE_AHI;
-    }
+	typ = RTYPE_AHI;
+      }
+    else if (strncasecmp (str, "po(", 3) == 0 && cls != RCLASS_GOTTPOFF)
+      {
+	str += 3;
+	typ = RTYPE_PO;
+      }
     else
       return -1;
 
     *strp = str;
-    return ret;
+    return (cls << RCLASS_SHIFT) | typ;
 }
 
 static const char *
@@ -218,23 +312,28 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
   const char *errmsg;
   enum cgen_parse_operand_result result_type;
   bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
-  int reloc_type;
+  enum or1k_rtype reloc_type;
+  int reloc_code;
   bfd_vma ret;
 
   if (**strp == '#')
-      ++*strp;
+    ++*strp;
 
-  reloc_type = parse_reloc (strp);
-  if (reloc_type >= 0)
+  reloc_code = parse_reloc (strp);
+  reloc_type = reloc_code & RTYPE_MASK;
+  if (reloc_code >= 0)
     {
+      enum or1k_rclass reloc_class = reloc_code >> RCLASS_SHIFT;
       if (splitp)
 	{
-	  if ((reloc_type & 3) == RTYPE_LO && reloc_type != RTYPE_GOT)
-	    reloc_type |= RTYPE_SLO;
+	  if ((reloc_type == RTYPE_LO || reloc_type == RTYPE_PO)
+	      && reloc_class != RCLASS_GOT)
+	    /* If split we or up the type to RTYPE_SLO or RTYPE_SPO.  */
+	    reloc_type |= 1;
 	  else
 	    return INVALID_STORE_RELOC;
-    }
-      reloc = or1k_imm16_relocs[reloc_type >> 2][reloc_type & 3];
+	}
+      reloc = or1k_imm16_relocs[reloc_class][reloc_type];
     }
 
   if (reloc != BFD_RELOC_UNUSED)
@@ -250,8 +349,8 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
       ret = value;
 
       if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
-	switch (reloc_type & 3)
-    {
+	switch (reloc_type)
+	  {
 	  case RTYPE_AHI:
 	    ret += 0x8000;
 	    /* FALLTHRU */
@@ -263,6 +362,10 @@ parse_imm16 (CGEN_CPU_DESC cd, const char **strp, int opindex,
 	    ret &= 0xffff;
 	    ret = (ret ^ 0x8000) - 0x8000;
 	    break;
+	  case RTYPE_PO:
+	  case RTYPE_SPO:
+	    ret &= 0x1fff;
+	    break;
 	  default:
 	    abort ();
 	  }
@@ -343,6 +446,13 @@ or1k_cgen_parse_operand (CGEN_CPU_DESC cd,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      {
+        bfd_vma value = 0;
+        errmsg = parse_disp21 (cd, strp, OR1K_OPERAND_DISP21, 0, NULL,  & value);
+        fields->f_disp21 = value;
+      }
+      break;
     case OR1K_OPERAND_DISP26 :
       {
         bfd_vma value = 0;
diff --git a/opcodes/or1k-desc.c b/opcodes/or1k-desc.c
index f1c0768e9c..91c2fbd73d 100644
--- a/opcodes/or1k-desc.c
+++ b/opcodes/or1k-desc.c
@@ -967,6 +967,7 @@ const CGEN_IFLD or1k_cgen_ifld_table[] =
   { OR1K_F_IMM16_25_5, "f-imm16-25-5", 0, 32, 25, 5, { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
   { OR1K_F_IMM16_10_11, "f-imm16-10-11", 0, 32, 10, 11, { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
   { OR1K_F_DISP26, "f-disp26", 0, 32, 25, 26, { 0|A(PCREL_ADDR), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
+  { OR1K_F_DISP21, "f-disp21", 0, 32, 20, 21, { 0|A(ABS_ADDR), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
   { OR1K_F_UIMM16, "f-uimm16", 0, 32, 15, 16, { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
   { OR1K_F_SIMM16, "f-simm16", 0, 32, 15, 16, { 0|A(SIGN_OPT), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
   { OR1K_F_UIMM6, "f-uimm6", 0, 32, 5, 6, { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
@@ -1091,6 +1092,10 @@ const CGEN_OPERAND or1k_cgen_operand_table[] =
   { "disp26", OR1K_OPERAND_DISP26, HW_H_IADDR, 25, 26,
     { 0, { (const PTR) &or1k_cgen_ifld_table[OR1K_F_DISP26] } },
     { 0|A(PCREL_ADDR), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
+/* disp21: pc-rel 21 bit */
+  { "disp21", OR1K_OPERAND_DISP21, HW_H_IADDR, 20, 21,
+    { 0, { (const PTR) &or1k_cgen_ifld_table[OR1K_F_DISP21] } },
+    { 0|A(ABS_ADDR), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }  },
 /* simm16: 16-bit signed immediate */
   { "simm16", OR1K_OPERAND_SIMM16, HW_H_SIMM16, 15, 16,
     { 0, { (const PTR) &or1k_cgen_ifld_table[OR1K_F_SIMM16] } },
@@ -1156,6 +1161,11 @@ static const CGEN_IBASE or1k_cgen_insn_table[MAX_INSNS] =
     OR1K_INSN_L_J, "l-j", "l.j", 32,
     { 0|A(UNCOND_CTI)|A(NOT_IN_DELAY_SLOT)|A(DELAYED_CTI)|A(SKIP_CTI)|A(DELAY_SLOT), { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
+/* l.adrp $rD,${disp21} */
+  {
+    OR1K_INSN_L_ADRP, "l-adrp", "l.adrp", 32,
+    { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
+  },
 /* l.jal ${disp26} */
   {
     OR1K_INSN_L_JAL, "l-jal", "l.jal", 32,
diff --git a/opcodes/or1k-desc.h b/opcodes/or1k-desc.h
index 894a8bb462..d84f0fa52a 100644
--- a/opcodes/or1k-desc.h
+++ b/opcodes/or1k-desc.h
@@ -279,18 +279,18 @@ typedef enum spr_field_masks {
 
 /* Enum declaration for insn main opcode enums.  */
 typedef enum insn_opcode {
-  OPC_J = 0, OPC_JAL = 1, OPC_BNF = 3, OPC_BF = 4
- , OPC_NOP = 5, OPC_MOVHIMACRC = 6, OPC_SYSTRAPSYNCS = 8, OPC_RFE = 9
- , OPC_VECTOR = 10, OPC_JR = 17, OPC_JALR = 18, OPC_MACI = 19
- , OPC_LWA = 27, OPC_CUST1 = 28, OPC_CUST2 = 29, OPC_CUST3 = 30
- , OPC_CUST4 = 31, OPC_LD = 32, OPC_LWZ = 33, OPC_LWS = 34
- , OPC_LBZ = 35, OPC_LBS = 36, OPC_LHZ = 37, OPC_LHS = 38
- , OPC_ADDI = 39, OPC_ADDIC = 40, OPC_ANDI = 41, OPC_ORI = 42
- , OPC_XORI = 43, OPC_MULI = 44, OPC_MFSPR = 45, OPC_SHROTI = 46
- , OPC_SFI = 47, OPC_MTSPR = 48, OPC_MAC = 49, OPC_FLOAT = 50
- , OPC_SWA = 51, OPC_SD = 52, OPC_SW = 53, OPC_SB = 54
- , OPC_SH = 55, OPC_ALU = 56, OPC_SF = 57, OPC_CUST5 = 60
- , OPC_CUST6 = 61, OPC_CUST7 = 62, OPC_CUST8 = 63
+  OPC_J = 0, OPC_JAL = 1, OPC_ADRP = 2, OPC_BNF = 3
+ , OPC_BF = 4, OPC_NOP = 5, OPC_MOVHIMACRC = 6, OPC_SYSTRAPSYNCS = 8
+ , OPC_RFE = 9, OPC_VECTOR = 10, OPC_JR = 17, OPC_JALR = 18
+ , OPC_MACI = 19, OPC_LWA = 27, OPC_CUST1 = 28, OPC_CUST2 = 29
+ , OPC_CUST3 = 30, OPC_CUST4 = 31, OPC_LD = 32, OPC_LWZ = 33
+ , OPC_LWS = 34, OPC_LBZ = 35, OPC_LBS = 36, OPC_LHZ = 37
+ , OPC_LHS = 38, OPC_ADDI = 39, OPC_ADDIC = 40, OPC_ANDI = 41
+ , OPC_ORI = 42, OPC_XORI = 43, OPC_MULI = 44, OPC_MFSPR = 45
+ , OPC_SHROTI = 46, OPC_SFI = 47, OPC_MTSPR = 48, OPC_MAC = 49
+ , OPC_FLOAT = 50, OPC_SWA = 51, OPC_SD = 52, OPC_SW = 53
+ , OPC_SB = 54, OPC_SH = 55, OPC_ALU = 56, OPC_SF = 57
+ , OPC_CUST5 = 60, OPC_CUST6 = 61, OPC_CUST7 = 62, OPC_CUST8 = 63
 } INSN_OPCODE;
 
 /* Enum declaration for systrapsync insn opcode enums.  */
@@ -401,8 +401,8 @@ typedef enum ifield_type {
  , OR1K_F_RESV_20_5, OR1K_F_RESV_20_4, OR1K_F_RESV_15_8, OR1K_F_RESV_15_6
  , OR1K_F_RESV_10_11, OR1K_F_RESV_10_7, OR1K_F_RESV_10_3, OR1K_F_RESV_10_1
  , OR1K_F_RESV_7_4, OR1K_F_RESV_5_2, OR1K_F_IMM16_25_5, OR1K_F_IMM16_10_11
- , OR1K_F_DISP26, OR1K_F_UIMM16, OR1K_F_SIMM16, OR1K_F_UIMM6
- , OR1K_F_UIMM16_SPLIT, OR1K_F_SIMM16_SPLIT, OR1K_F_MAX
+ , OR1K_F_DISP26, OR1K_F_DISP21, OR1K_F_UIMM16, OR1K_F_SIMM16
+ , OR1K_F_UIMM6, OR1K_F_UIMM16_SPLIT, OR1K_F_SIMM16_SPLIT, OR1K_F_MAX
 } IFIELD_TYPE;
 
 #define MAX_IFLD ((int) OR1K_F_MAX)
@@ -622,13 +622,14 @@ typedef enum cgen_operand_type {
  , OR1K_OPERAND_SYS_SR_OVE, OR1K_OPERAND_SYS_CPUCFGR_OB64S, OR1K_OPERAND_SYS_CPUCFGR_ND, OR1K_OPERAND_SYS_FPCSR_RM
  , OR1K_OPERAND_MAC_MACHI, OR1K_OPERAND_MAC_MACLO, OR1K_OPERAND_ATOMIC_RESERVE, OR1K_OPERAND_ATOMIC_ADDRESS
  , OR1K_OPERAND_UIMM6, OR1K_OPERAND_RD, OR1K_OPERAND_RA, OR1K_OPERAND_RB
- , OR1K_OPERAND_DISP26, OR1K_OPERAND_SIMM16, OR1K_OPERAND_UIMM16, OR1K_OPERAND_SIMM16_SPLIT
- , OR1K_OPERAND_UIMM16_SPLIT, OR1K_OPERAND_RDSF, OR1K_OPERAND_RASF, OR1K_OPERAND_RBSF
- , OR1K_OPERAND_RDDF, OR1K_OPERAND_RADF, OR1K_OPERAND_RBDF, OR1K_OPERAND_MAX
+ , OR1K_OPERAND_DISP26, OR1K_OPERAND_DISP21, OR1K_OPERAND_SIMM16, OR1K_OPERAND_UIMM16
+ , OR1K_OPERAND_SIMM16_SPLIT, OR1K_OPERAND_UIMM16_SPLIT, OR1K_OPERAND_RDSF, OR1K_OPERAND_RASF
+ , OR1K_OPERAND_RBSF, OR1K_OPERAND_RDDF, OR1K_OPERAND_RADF, OR1K_OPERAND_RBDF
+ , OR1K_OPERAND_MAX
 } CGEN_OPERAND_TYPE;
 
 /* Number of operands types.  */
-#define MAX_OPERANDS 31
+#define MAX_OPERANDS 32
 
 /* Maximum number of operands referenced by any insn.  */
 #define MAX_OPERAND_INSTANCES 9
diff --git a/opcodes/or1k-dis.c b/opcodes/or1k-dis.c
index f54b6b411f..6f8001a2be 100644
--- a/opcodes/or1k-dis.c
+++ b/opcodes/or1k-dis.c
@@ -90,6 +90,9 @@ or1k_cgen_print_operand (CGEN_CPU_DESC cd,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      print_address (cd, info, fields->f_disp21, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
+      break;
     case OR1K_OPERAND_DISP26 :
       print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
       break;
diff --git a/opcodes/or1k-ibld.c b/opcodes/or1k-ibld.c
index 139457c080..acfede7639 100644
--- a/opcodes/or1k-ibld.c
+++ b/opcodes/or1k-ibld.c
@@ -573,10 +573,17 @@ or1k_cgen_insert_operand (CGEN_CPU_DESC cd,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      {
+        long value = fields->f_disp21;
+        value = ((((DI) (value) >> (13))) - (((DI) (pc) >> (13))));
+        errmsg = insert_normal (cd, value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_ABS_ADDR), 0, 20, 21, 32, total_length, buffer);
+      }
+      break;
     case OR1K_OPERAND_DISP26 :
       {
         long value = fields->f_disp26;
-        value = ((SI) (((value) - (pc))) >> (2));
+        value = ((DI) (((value) - (pc))) >> (2));
         errmsg = insert_normal (cd, value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_PCREL_ADDR), 0, 25, 26, 32, total_length, buffer);
       }
       break;
@@ -688,6 +695,14 @@ or1k_cgen_extract_operand (CGEN_CPU_DESC cd,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      {
+        long value;
+        length = extract_normal (cd, ex_info, insn_value, 0|(1<<CGEN_IFLD_SIGNED)|(1<<CGEN_IFLD_ABS_ADDR), 0, 20, 21, 32, total_length, pc, & value);
+        value = ((((value) + (((DI) (pc) >> (13))))) << (13));
+        fields->f_disp21 = value;
+      }
+      break;
     case OR1K_OPERAND_DISP26 :
       {
         long value;
@@ -789,6 +804,9 @@ or1k_cgen_get_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      value = fields->f_disp21;
+      break;
     case OR1K_OPERAND_DISP26 :
       value = fields->f_disp26;
       break;
@@ -855,6 +873,9 @@ or1k_cgen_get_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      value = fields->f_disp21;
+      break;
     case OR1K_OPERAND_DISP26 :
       value = fields->f_disp26;
       break;
@@ -928,6 +949,9 @@ or1k_cgen_set_int_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 {
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      fields->f_disp21 = value;
+      break;
     case OR1K_OPERAND_DISP26 :
       fields->f_disp26 = value;
       break;
@@ -991,6 +1015,9 @@ or1k_cgen_set_vma_operand (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 {
   switch (opindex)
     {
+    case OR1K_OPERAND_DISP21 :
+      fields->f_disp21 = value;
+      break;
     case OR1K_OPERAND_DISP26 :
       fields->f_disp26 = value;
       break;
diff --git a/opcodes/or1k-opc.c b/opcodes/or1k-opc.c
index 0352bc3ebf..ba820a4c57 100644
--- a/opcodes/or1k-opc.c
+++ b/opcodes/or1k-opc.c
@@ -52,6 +52,10 @@ static const CGEN_IFMT ifmt_l_j ATTRIBUTE_UNUSED = {
   32, 32, 0xfc000000, { { F (F_OPCODE) }, { F (F_DISP26) }, { 0 } }
 };
 
+static const CGEN_IFMT ifmt_l_adrp ATTRIBUTE_UNUSED = {
+  32, 32, 0xfc000000, { { F (F_OPCODE) }, { F (F_R1) }, { F (F_DISP21) }, { 0 } }
+};
+
 static const CGEN_IFMT ifmt_l_jr ATTRIBUTE_UNUSED = {
   32, 32, 0xffff07ff, { { F (F_OPCODE) }, { F (F_RESV_25_10) }, { F (F_R3) }, { F (F_RESV_10_11) }, { 0 } }
 };
@@ -189,6 +193,12 @@ static const CGEN_OPCODE or1k_cgen_insn_opcode_table[MAX_INSNS] =
     { { MNEM, ' ', OP (DISP26), 0 } },
     & ifmt_l_j, { 0x0 }
   },
+/* l.adrp $rD,${disp21} */
+  {
+    { 0, 0, 0, 0 },
+    { { MNEM, ' ', OP (RD), ',', OP (DISP21), 0 } },
+    & ifmt_l_adrp, { 0x8000000 }
+  },
 /* l.jal ${disp26} */
   {
     { 0, 0, 0, 0 },
diff --git a/opcodes/or1k-opc.h b/opcodes/or1k-opc.h
index 5692ea95f1..d2a377257f 100644
--- a/opcodes/or1k-opc.h
+++ b/opcodes/or1k-opc.h
@@ -40,37 +40,38 @@ extern "C" {
 /* -- */
 /* Enum declaration for or1k instruction types.  */
 typedef enum cgen_insn_type {
-  OR1K_INSN_INVALID, OR1K_INSN_L_J, OR1K_INSN_L_JAL, OR1K_INSN_L_JR
- , OR1K_INSN_L_JALR, OR1K_INSN_L_BNF, OR1K_INSN_L_BF, OR1K_INSN_L_TRAP
- , OR1K_INSN_L_SYS, OR1K_INSN_L_MSYNC, OR1K_INSN_L_PSYNC, OR1K_INSN_L_CSYNC
- , OR1K_INSN_L_RFE, OR1K_INSN_L_NOP_IMM, OR1K_INSN_L_NOP, OR1K_INSN_L_MOVHI
- , OR1K_INSN_L_MACRC, OR1K_INSN_L_MFSPR, OR1K_INSN_L_MTSPR, OR1K_INSN_L_LWZ
- , OR1K_INSN_L_LWS, OR1K_INSN_L_LWA, OR1K_INSN_L_LBZ, OR1K_INSN_L_LBS
- , OR1K_INSN_L_LHZ, OR1K_INSN_L_LHS, OR1K_INSN_L_SW, OR1K_INSN_L_SB
- , OR1K_INSN_L_SH, OR1K_INSN_L_SWA, OR1K_INSN_L_SLL, OR1K_INSN_L_SLLI
- , OR1K_INSN_L_SRL, OR1K_INSN_L_SRLI, OR1K_INSN_L_SRA, OR1K_INSN_L_SRAI
- , OR1K_INSN_L_ROR, OR1K_INSN_L_RORI, OR1K_INSN_L_AND, OR1K_INSN_L_OR
- , OR1K_INSN_L_XOR, OR1K_INSN_L_ADD, OR1K_INSN_L_SUB, OR1K_INSN_L_ADDC
- , OR1K_INSN_L_MUL, OR1K_INSN_L_MULU, OR1K_INSN_L_DIV, OR1K_INSN_L_DIVU
- , OR1K_INSN_L_FF1, OR1K_INSN_L_FL1, OR1K_INSN_L_ANDI, OR1K_INSN_L_ORI
- , OR1K_INSN_L_XORI, OR1K_INSN_L_ADDI, OR1K_INSN_L_ADDIC, OR1K_INSN_L_MULI
- , OR1K_INSN_L_EXTHS, OR1K_INSN_L_EXTBS, OR1K_INSN_L_EXTHZ, OR1K_INSN_L_EXTBZ
- , OR1K_INSN_L_EXTWS, OR1K_INSN_L_EXTWZ, OR1K_INSN_L_CMOV, OR1K_INSN_L_SFGTS
- , OR1K_INSN_L_SFGTSI, OR1K_INSN_L_SFGTU, OR1K_INSN_L_SFGTUI, OR1K_INSN_L_SFGES
- , OR1K_INSN_L_SFGESI, OR1K_INSN_L_SFGEU, OR1K_INSN_L_SFGEUI, OR1K_INSN_L_SFLTS
- , OR1K_INSN_L_SFLTSI, OR1K_INSN_L_SFLTU, OR1K_INSN_L_SFLTUI, OR1K_INSN_L_SFLES
- , OR1K_INSN_L_SFLESI, OR1K_INSN_L_SFLEU, OR1K_INSN_L_SFLEUI, OR1K_INSN_L_SFEQ
- , OR1K_INSN_L_SFEQI, OR1K_INSN_L_SFNE, OR1K_INSN_L_SFNEI, OR1K_INSN_L_MAC
- , OR1K_INSN_L_MSB, OR1K_INSN_L_MACI, OR1K_INSN_L_CUST1, OR1K_INSN_L_CUST2
- , OR1K_INSN_L_CUST3, OR1K_INSN_L_CUST4, OR1K_INSN_L_CUST5, OR1K_INSN_L_CUST6
- , OR1K_INSN_L_CUST7, OR1K_INSN_L_CUST8, OR1K_INSN_LF_ADD_S, OR1K_INSN_LF_ADD_D
- , OR1K_INSN_LF_SUB_S, OR1K_INSN_LF_SUB_D, OR1K_INSN_LF_MUL_S, OR1K_INSN_LF_MUL_D
- , OR1K_INSN_LF_DIV_S, OR1K_INSN_LF_DIV_D, OR1K_INSN_LF_REM_S, OR1K_INSN_LF_REM_D
- , OR1K_INSN_LF_ITOF_S, OR1K_INSN_LF_ITOF_D, OR1K_INSN_LF_FTOI_S, OR1K_INSN_LF_FTOI_D
- , OR1K_INSN_LF_EQ_S, OR1K_INSN_LF_EQ_D, OR1K_INSN_LF_NE_S, OR1K_INSN_LF_NE_D
- , OR1K_INSN_LF_GE_S, OR1K_INSN_LF_GE_D, OR1K_INSN_LF_GT_S, OR1K_INSN_LF_GT_D
- , OR1K_INSN_LF_LT_S, OR1K_INSN_LF_LT_D, OR1K_INSN_LF_LE_S, OR1K_INSN_LF_LE_D
- , OR1K_INSN_LF_MADD_S, OR1K_INSN_LF_MADD_D, OR1K_INSN_LF_CUST1_S, OR1K_INSN_LF_CUST1_D
+  OR1K_INSN_INVALID, OR1K_INSN_L_J, OR1K_INSN_L_ADRP, OR1K_INSN_L_JAL
+ , OR1K_INSN_L_JR, OR1K_INSN_L_JALR, OR1K_INSN_L_BNF, OR1K_INSN_L_BF
+ , OR1K_INSN_L_TRAP, OR1K_INSN_L_SYS, OR1K_INSN_L_MSYNC, OR1K_INSN_L_PSYNC
+ , OR1K_INSN_L_CSYNC, OR1K_INSN_L_RFE, OR1K_INSN_L_NOP_IMM, OR1K_INSN_L_NOP
+ , OR1K_INSN_L_MOVHI, OR1K_INSN_L_MACRC, OR1K_INSN_L_MFSPR, OR1K_INSN_L_MTSPR
+ , OR1K_INSN_L_LWZ, OR1K_INSN_L_LWS, OR1K_INSN_L_LWA, OR1K_INSN_L_LBZ
+ , OR1K_INSN_L_LBS, OR1K_INSN_L_LHZ, OR1K_INSN_L_LHS, OR1K_INSN_L_SW
+ , OR1K_INSN_L_SB, OR1K_INSN_L_SH, OR1K_INSN_L_SWA, OR1K_INSN_L_SLL
+ , OR1K_INSN_L_SLLI, OR1K_INSN_L_SRL, OR1K_INSN_L_SRLI, OR1K_INSN_L_SRA
+ , OR1K_INSN_L_SRAI, OR1K_INSN_L_ROR, OR1K_INSN_L_RORI, OR1K_INSN_L_AND
+ , OR1K_INSN_L_OR, OR1K_INSN_L_XOR, OR1K_INSN_L_ADD, OR1K_INSN_L_SUB
+ , OR1K_INSN_L_ADDC, OR1K_INSN_L_MUL, OR1K_INSN_L_MULU, OR1K_INSN_L_DIV
+ , OR1K_INSN_L_DIVU, OR1K_INSN_L_FF1, OR1K_INSN_L_FL1, OR1K_INSN_L_ANDI
+ , OR1K_INSN_L_ORI, OR1K_INSN_L_XORI, OR1K_INSN_L_ADDI, OR1K_INSN_L_ADDIC
+ , OR1K_INSN_L_MULI, OR1K_INSN_L_EXTHS, OR1K_INSN_L_EXTBS, OR1K_INSN_L_EXTHZ
+ , OR1K_INSN_L_EXTBZ, OR1K_INSN_L_EXTWS, OR1K_INSN_L_EXTWZ, OR1K_INSN_L_CMOV
+ , OR1K_INSN_L_SFGTS, OR1K_INSN_L_SFGTSI, OR1K_INSN_L_SFGTU, OR1K_INSN_L_SFGTUI
+ , OR1K_INSN_L_SFGES, OR1K_INSN_L_SFGESI, OR1K_INSN_L_SFGEU, OR1K_INSN_L_SFGEUI
+ , OR1K_INSN_L_SFLTS, OR1K_INSN_L_SFLTSI, OR1K_INSN_L_SFLTU, OR1K_INSN_L_SFLTUI
+ , OR1K_INSN_L_SFLES, OR1K_INSN_L_SFLESI, OR1K_INSN_L_SFLEU, OR1K_INSN_L_SFLEUI
+ , OR1K_INSN_L_SFEQ, OR1K_INSN_L_SFEQI, OR1K_INSN_L_SFNE, OR1K_INSN_L_SFNEI
+ , OR1K_INSN_L_MAC, OR1K_INSN_L_MSB, OR1K_INSN_L_MACI, OR1K_INSN_L_CUST1
+ , OR1K_INSN_L_CUST2, OR1K_INSN_L_CUST3, OR1K_INSN_L_CUST4, OR1K_INSN_L_CUST5
+ , OR1K_INSN_L_CUST6, OR1K_INSN_L_CUST7, OR1K_INSN_L_CUST8, OR1K_INSN_LF_ADD_S
+ , OR1K_INSN_LF_ADD_D, OR1K_INSN_LF_SUB_S, OR1K_INSN_LF_SUB_D, OR1K_INSN_LF_MUL_S
+ , OR1K_INSN_LF_MUL_D, OR1K_INSN_LF_DIV_S, OR1K_INSN_LF_DIV_D, OR1K_INSN_LF_REM_S
+ , OR1K_INSN_LF_REM_D, OR1K_INSN_LF_ITOF_S, OR1K_INSN_LF_ITOF_D, OR1K_INSN_LF_FTOI_S
+ , OR1K_INSN_LF_FTOI_D, OR1K_INSN_LF_EQ_S, OR1K_INSN_LF_EQ_D, OR1K_INSN_LF_NE_S
+ , OR1K_INSN_LF_NE_D, OR1K_INSN_LF_GE_S, OR1K_INSN_LF_GE_D, OR1K_INSN_LF_GT_S
+ , OR1K_INSN_LF_GT_D, OR1K_INSN_LF_LT_S, OR1K_INSN_LF_LT_D, OR1K_INSN_LF_LE_S
+ , OR1K_INSN_LF_LE_D, OR1K_INSN_LF_MADD_S, OR1K_INSN_LF_MADD_D, OR1K_INSN_LF_CUST1_S
+ , OR1K_INSN_LF_CUST1_D
 } CGEN_INSN_TYPE;
 
 /* Index of `invalid' insn place holder.  */
@@ -116,6 +117,7 @@ struct cgen_fields
   long f_imm16_25_5;
   long f_imm16_10_11;
   long f_disp26;
+  long f_disp21;
   long f_uimm16;
   long f_simm16;
   long f_uimm6;
diff --git a/opcodes/or1k-opinst.c b/opcodes/or1k-opinst.c
index 936ed67f1b..c267efb6c4 100644
--- a/opcodes/or1k-opinst.c
+++ b/opcodes/or1k-opinst.c
@@ -49,6 +49,12 @@ static const CGEN_OPINST sfmt_l_j_ops[] ATTRIBUTE_UNUSED = {
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
+static const CGEN_OPINST sfmt_l_adrp_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "disp21", HW_H_IADDR, CGEN_MODE_UDI, OP_ENT (DISP21), 0, 0 },
+  { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
 static const CGEN_OPINST sfmt_l_jal_ops[] ATTRIBUTE_UNUSED = {
   { INPUT, "disp26", HW_H_IADDR, CGEN_MODE_UDI, OP_ENT (DISP26), 0, 0 },
   { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, 0 },
@@ -453,6 +459,7 @@ static const CGEN_OPINST sfmt_lf_madd_d_ops[] ATTRIBUTE_UNUSED = {
 static const CGEN_OPINST *or1k_cgen_opinst_table[MAX_INSNS] = {
   0,
   & sfmt_l_j_ops[0],
+  & sfmt_l_adrp_ops[0],
   & sfmt_l_jal_ops[0],
   & sfmt_l_jr_ops[0],
   & sfmt_l_jalr_ops[0],
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 4/4] or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns
  2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
                   ` (2 preceding siblings ...)
  2018-08-21 14:38 ` [OpenRISC] [PATCH 3/4] or1k: Add the l.adrp insn and supporting relocations Stafford Horne
@ 2018-08-21 14:38 ` Stafford Horne
  2018-09-08 21:35 ` [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
  4 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-08-21 14:38 UTC (permalink / raw)
  To: openrisc

From: Richard Henderson <rth@redhat.com>

Also fix the incorrect definitions of multiply and divide carry and
overflow float.

Changes to the instructions are made in the .cpu file, then we
regenerate the binutils and sim files.

The changes also required a few fixups for tests and additional sim helpers.

yyyy-mm-dd  Richard Henderson  <rth@twiddle.net>
	    Stafford Horne  <shorne@gmail.com>

cpu/ChangeLog:

	* or1korbis.cpu (insn-opcode-mac): Add opcodes for MACU and MSBU.
	(insn-opcode-alu-regreg): Add opcodes for MULD and MULDU.
	(l-mul): Fix overflow support and indentation.
	(l-mulu): Fix overflow support and indentation.
	(l-muld, l-muldu, l-msbu, l-macu): New instructions.
	(l-div); Remove incorrect carry behavior.
	(l-divu): Fix carry and overflow behavior.
	(l-mac): Add overflow support.
	(l-msb, l-msbu): Add carry and overflow support.

opcodes/ChangeLog:

	* or1k-desc.c: Regenerate.
	* or1k-desc.h: Regenerate.
	* or1k-opc.c: Regenerate.
	* or1k-opc.h: Regenerate.
	* or1k-opinst.c: Regenerate.

sim/common/ChangeLog:

	* cgen-ops.h (ADDCFDI): New function, add carry flag DI variant.
	(ADDOFDI): New function, add overflow flag DI variant.
	(SUBCFDI): New function, subtract carry flag DI variant.
	(SUBOFDI): New function, subtract overflow flag DI variant.

sim/or1k/ChangeLog:

	* or1k/cpu.h: Regenerate.
	* or1k/decode.c: Regenerate.
	* or1k/decode.h: Regenerate.
	* or1k/model.c: Regenerate.
	* or1k/sem-switch.c: Regenerate.
	* or1k/sem.c: Regenerate:

sim/testsuite/sim/or1k/ChangeLog:

	* div.S: Fix tests to match correct overflow/carry semantics.
	* mul.S: Likewise.

yyyy-mm-dd  Stafford Horne  <shorne@gmail.com>

gas/ChangeLog:

	* testsuite/gas/or1k/allinsn.s: Add instruction tests for
	l.muld, l.muldu, l.macu, l.msb, l.msbu.
	* testsuite/gas/or1k/allinsn.d: Add test results for new
	instructions.
---
 cpu/or1korbis.cpu                | 261 +++++++++++++++++----------
 gas/testsuite/gas/or1k/allinsn.d |  25 +++
 gas/testsuite/gas/or1k/allinsn.s |  20 +++
 opcodes/or1k-desc.c              |  24 ++-
 opcodes/or1k-desc.h              |  11 +-
 opcodes/or1k-opc.c               |  34 +++-
 opcodes/or1k-opc.h               |  23 +--
 opcodes/or1k-opinst.c            |  91 +++++++++-
 sim/common/cgen-ops.h            |  36 ++++
 sim/or1k/cpu.h                   |  32 ++++
 sim/or1k/decode.c                | 239 +++++++++++++++++++++++--
 sim/or1k/decode.h                |  82 ++++-----
 sim/or1k/model.c                 | 186 +++++++++++++++++++-
 sim/or1k/sem-switch.c            | 281 +++++++++++++++++++++++------
 sim/or1k/sem.c                   | 293 +++++++++++++++++++++++++------
 sim/testsuite/sim/or1k/div.S     |  12 +-
 sim/testsuite/sim/or1k/mul.S     | 109 ++++++------
 17 files changed, 1404 insertions(+), 355 deletions(-)

diff --git a/cpu/or1korbis.cpu b/cpu/or1korbis.cpu
index 6fbf40ad99..094f0185a7 100644
--- a/cpu/or1korbis.cpu
+++ b/cpu/or1korbis.cpu
@@ -220,8 +220,10 @@
 (define-normal-insn-enum insn-opcode-mac
   "multiply/accumulate insn opcode enums" ((MACH ORBIS-MACHS))
   OPC_MAC_ f-op-3-4
-  (("MAC" #x1)
-   ("MSB" #x2)
+  (("MAC"   #x1)
+   ("MSB"   #x2)
+   ("MACU"  #x3)
+   ("MSBU"  #x4)
    )
   )
 
@@ -263,12 +265,14 @@
    ("OR"    #x4)
    ("XOR"   #x5)
    ("MUL"   #x6)
+   ("MULD"  #x7)
    ("SHROT" #x8)
    ("DIV"   #x9)
    ("DIVU"  #xA)
    ("MULU"  #xB)
    ("EXTBH" #xC)
    ("EXTW"  #xD)
+   ("MULDU" #xD)
    ("CMOV"  #xE)
    ("FFL1"  #xF)
    )
@@ -595,7 +599,7 @@
                (set UWI mac-machi 0)
                )
      ()
-     )
+)
 
 \f
 ; System releated instructions
@@ -816,77 +820,93 @@
 )
 
 (dni (l-mul) "l.mul reg/reg/reg"
-          ((MACH ORBIS-MACHS))
-          ("l.mul $rD,$rA,$rB")
-          (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MUL)
-          (sequence ()
-                    (sequence ()
-                              ; 2's complement overflow
-                              (set BI sys-sr-ov (mul-o2flag WI rA rB))
-                              ; 1's complement overflow
-                              (set BI sys-sr-cy (mul-o1flag WI rA rB))
-                              (set rD (mul WI rA rB))
-                              )
-                    (if (andif sys-sr-ov sys-sr-ove)
-                        (raise-exception EXCEPT-RANGE))
-                    )
-          ()
+     ((MACH ORBIS-MACHS))
+     ("l.mul $rD,$rA,$rB")
+     (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MUL)
+     (sequence ()
+	(sequence ()
+	   (set BI sys-sr-ov (mul-o2flag WI rA rB))
+	   (set rD (mul WI rA rB))
+	)
+	(if (andif sys-sr-ov sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
+     )
+     ()
+)
+
+(dni (l-muld) "l.muld reg/reg"
+     ((MACH ORBIS-MACHS))
+     ("l.muld $rA,$rB")
+     (+ OPC_ALU (f-resv-25-5 0) rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MULD)
+     (sequence ((DI result))
+	(set DI result (mul DI (ext DI rA) (ext DI rB)))
+	(set SI mac-machi (subword SI result 0))
+	(set SI mac-maclo (subword SI result 1))
+     )
+     ()
 )
 
 (dni (l-mulu) "l.mulu reg/reg/reg"
-          ((MACH ORBIS-MACHS))
-          ("l.mulu $rD,$rA,$rB")
-          (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MULU)
-          (sequence ()
-                    (sequence ()
-                              ; 2's complement overflow
-                              (set BI sys-sr-ov 0)
-                              ; 1's complement overflow
-                              (set BI sys-sr-cy (mul-o1flag UWI rA rB))
-                              (set rD (mul UWI rA rB))
-                              )
-                    (if (andif sys-sr-ov sys-sr-ove)
-                        (raise-exception EXCEPT-RANGE))
-                    )
-          ()
+     ((MACH ORBIS-MACHS))
+     ("l.mulu $rD,$rA,$rB")
+     (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MULU)
+     (sequence ()
+	(sequence ()
+	   (set BI sys-sr-cy (mul-o1flag UWI rA rB))
+	   (set rD (mul UWI rA rB))
+	)
+	(if (andif sys-sr-cy sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
+     )
+     ()
+)
+
+(dni (l-muldu) "l.muld reg/reg"
+     ((MACH ORBIS-MACHS))
+     ("l.muldu $rA,$rB")
+     (+ OPC_ALU (f-resv-25-5 0) rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_MULDU)
+     (sequence ((DI result))
+	(set DI result (mul DI (zext DI rA) (zext DI rB)))
+	(set SI mac-machi (subword SI result 0))
+	(set SI mac-maclo (subword SI result 1))
+     )
+     ()
 )
 
 (dni l-div "divide (signed)"
-          ((MACH ORBIS-MACHS))
-          "l.div $rD,$rA,$rB"
-          (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_DIV)
-          (sequence ()
-                    (if (ne rB 0)
-                        (sequence ()
-                                  (set BI sys-sr-cy 0)
-                                  (set WI rD (div WI rA rB))
-                                  )
-                        (set BI sys-sr-cy 1)
-                        )
-                    (set BI sys-sr-ov 0)
-                    (if (andif sys-sr-cy sys-sr-ove)
-                        (raise-exception EXCEPT-RANGE))
-                    )
-          ()
+     ((MACH ORBIS-MACHS))
+     "l.div $rD,$rA,$rB"
+     (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_DIV)
+     (if (ne rB 0)
+	(sequence ()
+	   (set BI sys-sr-ov 0)
+	   (set WI rD (div WI rA rB))
+	)
+	(sequence ()
+	   (set BI sys-sr-ov 1)
+	   (if sys-sr-ove
+	      (raise-exception EXCEPT-RANGE))
+	)
+     )
+     ()
 )
 
 (dni l-divu "divide (unsigned)"
-          ((MACH ORBIS-MACHS))
-          "l.divu $rD,$rA,$rB"
-          (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_DIVU)
-          (sequence ()
-                    (if (ne rB 0)
-                        (sequence ()
-                                  (set BI sys-sr-cy 0)
-                                  (set rD (udiv UWI rA rB))
-                                  )
-                        (set BI sys-sr-cy 1)
-                        )
-                    (set BI sys-sr-ov 0)
-                    (if (andif sys-sr-cy sys-sr-ove)
-                        (raise-exception EXCEPT-RANGE))
-                    )
-          ()
+     ((MACH ORBIS-MACHS))
+     "l.divu $rD,$rA,$rB"
+     (+ OPC_ALU rD rA rB (f-resv-10-7 #x30) OPC_ALU_REGREG_DIVU)
+     (if (ne rB 0)
+	(sequence ()
+	   (set BI sys-sr-cy 0)
+	   (set rD (udiv UWI rA rB))
+	)
+	(sequence ()
+	   (set BI sys-sr-cy 1)
+	   (if sys-sr-ove
+	       (raise-exception EXCEPT-RANGE))
+	)
+     )
+     ()
 )
 
 (dni l-ff1 "find first '1'"
@@ -984,17 +1004,14 @@
      (+ OPC_MULI rD rA simm16)
      (sequence ()
                (sequence ()
-                         ; 2's complement overflow
                          (set sys-sr-ov (mul-o2flag WI rA (ext WI simm16)))
-                         ; 1's complement overflow
-                         (set sys-sr-cy (mul-o1flag UWI rA (ext UWI simm16)))
                          (set rD (mul WI rA (ext WI simm16)))
                          )
                (if (andif sys-sr-ov sys-sr-ove)
                    (raise-exception EXCEPT-RANGE))
                )
      ()
-     )
+)
 
 (define-pmacro (extbh-insn mnemonic extop extmode truncmode)
   (begin
@@ -1118,42 +1135,100 @@
      ((MACH ORBIS-MACHS))
      "l.mac $rA,$rB"
      (+  OPC_MAC (f-op-25-5 0) rA rB (f-resv-10-7 0) OPC_MAC_MAC)
-     (sequence ((WI prod) (DI result))
-               (set WI prod (mul WI rA rB))
-               (set DI result (add (join DI SI mac-machi mac-maclo) (ext DI prod)))
-               (set SI mac-machi (subword SI result 0))
-               (set SI mac-maclo (subword SI result 1))
-               )
+     (sequence ()
+	(sequence ((DI prod) (DI mac) (DI result))
+	   (set DI prod (mul DI (ext DI rA) (ext DI rB)))
+	   (set DI mac (join DI SI mac-machi mac-maclo))
+	   (set DI result (add prod mac))
+	   (set SI mac-machi (subword SI result 0))
+	   (set SI mac-maclo (subword SI result 1))
+	   (set BI sys-sr-ov (addc-oflag prod mac 0))
+	)
+	(if (andif sys-sr-ov sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
+     )
      ()
+)
+
+(dni l-maci
+     "l.maci reg/simm16"
+     ((MACH ORBIS-MACHS))
+     "l.maci $rA,${simm16}"
+     (+ OPC_MACI (f-resv-25-5 0) rA simm16)
+     (sequence ()
+	(sequence ((DI prod) (DI mac) (DI result))
+	   (set DI prod (mul DI (ext DI rA) (ext DI simm16)))
+	   (set DI mac (join DI SI mac-machi mac-maclo))
+	   (set DI result (add mac prod))
+	   (set SI mac-machi (subword SI result 0))
+	   (set SI mac-maclo (subword SI result 1))
+	   (set BI sys-sr-ov (addc-oflag prod mac 0))
+	)
+	(if (andif sys-sr-ov sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
      )
+     ()
+)
+
+(dni l-macu
+     "l.macu reg/reg"
+     ((MACH ORBIS-MACHS))
+     "l.macu $rA,$rB"
+     (+  OPC_MAC (f-op-25-5 0) rA rB (f-resv-10-7 0) OPC_MAC_MACU)
+     (sequence ()
+	(sequence ((DI prod) (DI mac) (DI result))
+	   (set DI prod (mul DI (zext DI rA) (zext DI rB)))
+	   (set DI mac (join DI SI mac-machi mac-maclo))
+	   (set DI result (add prod mac))
+	   (set SI mac-machi (subword SI result 0))
+	   (set SI mac-maclo (subword SI result 1))
+	   (set BI sys-sr-cy (addc-cflag prod mac 0))
+	)
+	(if (andif sys-sr-cy sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
+     )
+     ()
+)
 
 (dni l-msb
      "l.msb reg/reg"
      ((MACH ORBIS-MACHS))
      "l.msb $rA,$rB"
      (+  OPC_MAC (f-op-25-5 0) rA rB (f-resv-10-7 0) OPC_MAC_MSB)
-     (sequence ((WI prod) (DI result))
-               (set WI prod (mul WI rA rB))
-               (set DI result (sub (join DI SI mac-machi mac-maclo) (ext DI prod)))
-               (set SI mac-machi (subword SI result 0))
-               (set SI mac-maclo (subword SI result 1))
-               )
-     ()
+     (sequence ()
+	(sequence ((DI prod) (DI mac) (DI result))
+	   (set DI prod (mul DI (ext DI rA) (ext DI rB)))
+	   (set DI mac (join DI SI mac-machi mac-maclo))
+	   (set DI result (sub mac prod))
+	   (set SI mac-machi (subword SI result 0))
+	   (set SI mac-maclo (subword SI result 1))
+	   (set BI sys-sr-ov (subc-oflag mac result 0))
+	)
+	(if (andif sys-sr-ov sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
      )
+     ()
+)
 
-(dni l-maci
-     "l.maci reg/simm16"
+(dni l-msbu
+     "l.msbu reg/reg"
      ((MACH ORBIS-MACHS))
-     "l.maci $rA,${simm16}"
-     (+ OPC_MACI (f-resv-25-5 0) rA simm16)
-     (sequence ((WI prod) (DI result))
-               (set WI prod (mul WI (ext WI simm16) rA))
-               (set DI result (add (join DI SI mac-machi mac-maclo) (ext DI prod)))
-               (set SI mac-machi (subword SI result 0))
-               (set SI mac-maclo (subword SI result 1))
-               )
-     ()
+     "l.msbu $rA,$rB"
+     (+  OPC_MAC (f-op-25-5 0) rA rB (f-resv-10-7 0) OPC_MAC_MSBU)
+     (sequence ()
+	(sequence ((DI prod) (DI mac) (DI result))
+	   (set DI prod (mul DI (zext DI rA) (zext DI rB)))
+	   (set DI mac (join DI SI mac-machi mac-maclo))
+	   (set DI result (sub mac prod))
+	   (set SI mac-machi (subword SI result 0))
+	   (set SI mac-maclo (subword SI result 1))
+	   (set BI sys-sr-cy (subc-cflag mac result 0))
+	)
+	(if (andif sys-sr-cy sys-sr-ove)
+	    (raise-exception EXCEPT-RANGE))
      )
+     ()
+)
 
 (define-pmacro (cust-insn cust-num)
   (begin
diff --git a/gas/testsuite/gas/or1k/allinsn.d b/gas/testsuite/gas/or1k/allinsn.d
index a4ffe43f0b..4260498fdb 100644
--- a/gas/testsuite/gas/or1k/allinsn.d
+++ b/gas/testsuite/gas/or1k/allinsn.d
@@ -696,3 +696,28 @@ Disassembly of section \.text:
 			840: R_OR1K_PCREL_PG21	globaldata
  844:	08 60 00 00 	l\.adrp r3,0 <localtext>
 			844: R_OR1K_PCREL_PG21	\.data
+
+00000848 <l_muld>:
+ 848:	e0 00 03 07 	l\.muld r0,r0
+ 84c:	e0 1f fb 07 	l\.muld r31,r31
+ 850:	e0 03 23 07 	l\.muld r3,r4
+
+00000854 <l_muldu>:
+ 854:	e0 00 03 0d 	l\.muldu r0,r0
+ 858:	e0 1f fb 0d 	l\.muldu r31,r31
+ 85c:	e0 03 23 0d 	l\.muldu r3,r4
+
+00000860 <l_macu>:
+ 860:	c4 00 00 03 	l\.macu r0,r0
+ 864:	c4 1f f8 03 	l\.macu r31,r31
+ 868:	c4 03 20 03 	l\.macu r3,r4
+
+0000086c <l_msb>:
+ 86c:	c4 00 00 02 	l\.msb r0,r0
+ 870:	c4 1f f8 02 	l\.msb r31,r31
+ 874:	c4 03 20 02 	l\.msb r3,r4
+
+00000878 <l_msbu>:
+ 878:	c4 00 00 04 	l\.msbu r0,r0
+ 87c:	c4 1f f8 04 	l\.msbu r31,r31
+ 880:	c4 03 20 04 	l\.msbu r3,r4
diff --git a/gas/testsuite/gas/or1k/allinsn.s b/gas/testsuite/gas/or1k/allinsn.s
index 55d703734e..e5a7906464 100644
--- a/gas/testsuite/gas/or1k/allinsn.s
+++ b/gas/testsuite/gas/or1k/allinsn.s
@@ -680,3 +680,23 @@ l_maci:
 l_adrp:
 	l.adrp r3,globaldata
 	l.adrp r3,localdata
+l_muld:
+	l.muld r0,r0
+	l.muld r31,r31
+	l.muld r3,r4
+l_muldu:
+	l.muldu r0,r0
+	l.muldu r31,r31
+	l.muldu r3,r4
+l_macu:
+	l.macu r0,r0
+	l.macu r31,r31
+	l.macu r3,r4
+l_msb:
+	l.msb r0,r0
+	l.msb r31,r31
+	l.msb r3,r4
+l_msbu:
+	l.msbu r0,r0
+	l.msbu r31,r31
+	l.msbu r3,r4
diff --git a/opcodes/or1k-desc.c b/opcodes/or1k-desc.c
index 91c2fbd73d..f3c4e9ee23 100644
--- a/opcodes/or1k-desc.c
+++ b/opcodes/or1k-desc.c
@@ -1381,11 +1381,21 @@ static const CGEN_IBASE or1k_cgen_insn_table[MAX_INSNS] =
     OR1K_INSN_L_MUL, "l-mul", "l.mul", 32,
     { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
+/* l.muld $rA,$rB */
+  {
+    OR1K_INSN_L_MULD, "l-muld", "l.muld", 32,
+    { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
+  },
 /* l.mulu $rD,$rA,$rB */
   {
     OR1K_INSN_L_MULU, "l-mulu", "l.mulu", 32,
     { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
+/* l.muldu $rA,$rB */
+  {
+    OR1K_INSN_L_MULDU, "l-muldu", "l.muldu", 32,
+    { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
+  },
 /* l.div $rD,$rA,$rB */
   {
     OR1K_INSN_L_DIV, "l-div", "l.div", 32,
@@ -1576,14 +1586,24 @@ static const CGEN_IBASE or1k_cgen_insn_table[MAX_INSNS] =
     OR1K_INSN_L_MAC, "l-mac", "l.mac", 32,
     { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
+/* l.maci $rA,${simm16} */
+  {
+    OR1K_INSN_L_MACI, "l-maci", "l.maci", 32,
+    { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
+  },
+/* l.macu $rA,$rB */
+  {
+    OR1K_INSN_L_MACU, "l-macu", "l.macu", 32,
+    { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
+  },
 /* l.msb $rA,$rB */
   {
     OR1K_INSN_L_MSB, "l-msb", "l.msb", 32,
     { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
-/* l.maci $rA,${simm16} */
+/* l.msbu $rA,$rB */
   {
-    OR1K_INSN_L_MACI, "l-maci", "l.maci", 32,
+    OR1K_INSN_L_MSBU, "l-msbu", "l.msbu", 32,
     { 0, { { { (1<<MACH_OR32)|(1<<MACH_OR32ND)|(1<<MACH_OR64)|(1<<MACH_OR64ND), 0 } } } }
   },
 /* l.cust1 */
diff --git a/opcodes/or1k-desc.h b/opcodes/or1k-desc.h
index d84f0fa52a..040bd926c5 100644
--- a/opcodes/or1k-desc.h
+++ b/opcodes/or1k-desc.h
@@ -306,7 +306,7 @@ typedef enum insn_opcode_movehimacrc {
 
 /* Enum declaration for multiply/accumulate insn opcode enums.  */
 typedef enum insn_opcode_mac {
-  OPC_MAC_MAC = 1, OPC_MAC_MSB = 2
+  OPC_MAC_MAC = 1, OPC_MAC_MSB = 2, OPC_MAC_MACU = 3, OPC_MAC_MSBU = 4
 } INSN_OPCODE_MAC;
 
 /* Enum declaration for shift/rotate insn opcode enums.  */
@@ -327,9 +327,10 @@ typedef enum insn_opcode_extws {
 /* Enum declaration for alu reg/reg insn opcode enums.  */
 typedef enum insn_opcode_alu_regreg {
   OPC_ALU_REGREG_ADD = 0, OPC_ALU_REGREG_ADDC = 1, OPC_ALU_REGREG_SUB = 2, OPC_ALU_REGREG_AND = 3
- , OPC_ALU_REGREG_OR = 4, OPC_ALU_REGREG_XOR = 5, OPC_ALU_REGREG_MUL = 6, OPC_ALU_REGREG_SHROT = 8
- , OPC_ALU_REGREG_DIV = 9, OPC_ALU_REGREG_DIVU = 10, OPC_ALU_REGREG_MULU = 11, OPC_ALU_REGREG_EXTBH = 12
- , OPC_ALU_REGREG_EXTW = 13, OPC_ALU_REGREG_CMOV = 14, OPC_ALU_REGREG_FFL1 = 15
+ , OPC_ALU_REGREG_OR = 4, OPC_ALU_REGREG_XOR = 5, OPC_ALU_REGREG_MUL = 6, OPC_ALU_REGREG_MULD = 7
+ , OPC_ALU_REGREG_SHROT = 8, OPC_ALU_REGREG_DIV = 9, OPC_ALU_REGREG_DIVU = 10, OPC_ALU_REGREG_MULU = 11
+ , OPC_ALU_REGREG_EXTBH = 12, OPC_ALU_REGREG_EXTW = 13, OPC_ALU_REGREG_MULDU = 13, OPC_ALU_REGREG_CMOV = 14
+ , OPC_ALU_REGREG_FFL1 = 15
 } INSN_OPCODE_ALU_REGREG;
 
 /* Enum declaration for setflag insn opcode enums.  */
@@ -632,7 +633,7 @@ typedef enum cgen_operand_type {
 #define MAX_OPERANDS 32
 
 /* Maximum number of operands referenced by any insn.  */
-#define MAX_OPERAND_INSTANCES 9
+#define MAX_OPERAND_INSTANCES 10
 
 /* Insn attribute indices.  */
 
diff --git a/opcodes/or1k-opc.c b/opcodes/or1k-opc.c
index ba820a4c57..337dda5306 100644
--- a/opcodes/or1k-opc.c
+++ b/opcodes/or1k-opc.c
@@ -116,6 +116,10 @@ static const CGEN_IFMT ifmt_l_and ATTRIBUTE_UNUSED = {
   32, 32, 0xfc0007ff, { { F (F_OPCODE) }, { F (F_R1) }, { F (F_R2) }, { F (F_R3) }, { F (F_RESV_10_7) }, { F (F_OP_3_4) }, { 0 } }
 };
 
+static const CGEN_IFMT ifmt_l_muld ATTRIBUTE_UNUSED = {
+  32, 32, 0xffe007ff, { { F (F_OPCODE) }, { F (F_RESV_25_5) }, { F (F_R2) }, { F (F_R3) }, { F (F_RESV_10_7) }, { F (F_OP_3_4) }, { 0 } }
+};
+
 static const CGEN_IFMT ifmt_l_exths ATTRIBUTE_UNUSED = {
   32, 32, 0xfc00ffff, { { F (F_OPCODE) }, { F (F_R1) }, { F (F_R2) }, { F (F_RESV_15_6) }, { F (F_OP_9_4) }, { F (F_RESV_5_2) }, { F (F_OP_3_4) }, { 0 } }
 };
@@ -457,12 +461,24 @@ static const CGEN_OPCODE or1k_cgen_insn_opcode_table[MAX_INSNS] =
     { { MNEM, ' ', OP (RD), ',', OP (RA), ',', OP (RB), 0 } },
     & ifmt_l_and, { 0xe0000306 }
   },
+/* l.muld $rA,$rB */
+  {
+    { 0, 0, 0, 0 },
+    { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
+    & ifmt_l_muld, { 0xe0000307 }
+  },
 /* l.mulu $rD,$rA,$rB */
   {
     { 0, 0, 0, 0 },
     { { MNEM, ' ', OP (RD), ',', OP (RA), ',', OP (RB), 0 } },
     & ifmt_l_and, { 0xe000030b }
   },
+/* l.muldu $rA,$rB */
+  {
+    { 0, 0, 0, 0 },
+    { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
+    & ifmt_l_muld, { 0xe000030d }
+  },
 /* l.div $rD,$rA,$rB */
   {
     { 0, 0, 0, 0 },
@@ -691,17 +707,29 @@ static const CGEN_OPCODE or1k_cgen_insn_opcode_table[MAX_INSNS] =
     { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
     & ifmt_l_mac, { 0xc4000001 }
   },
+/* l.maci $rA,${simm16} */
+  {
+    { 0, 0, 0, 0 },
+    { { MNEM, ' ', OP (RA), ',', OP (SIMM16), 0 } },
+    & ifmt_l_maci, { 0x4c000000 }
+  },
+/* l.macu $rA,$rB */
+  {
+    { 0, 0, 0, 0 },
+    { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
+    & ifmt_l_mac, { 0xc4000003 }
+  },
 /* l.msb $rA,$rB */
   {
     { 0, 0, 0, 0 },
     { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
     & ifmt_l_mac, { 0xc4000002 }
   },
-/* l.maci $rA,${simm16} */
+/* l.msbu $rA,$rB */
   {
     { 0, 0, 0, 0 },
-    { { MNEM, ' ', OP (RA), ',', OP (SIMM16), 0 } },
-    & ifmt_l_maci, { 0x4c000000 }
+    { { MNEM, ' ', OP (RA), ',', OP (RB), 0 } },
+    & ifmt_l_mac, { 0xc4000004 }
   },
 /* l.cust1 */
   {
diff --git a/opcodes/or1k-opc.h b/opcodes/or1k-opc.h
index d2a377257f..66d077361f 100644
--- a/opcodes/or1k-opc.h
+++ b/opcodes/or1k-opc.h
@@ -51,17 +51,18 @@ typedef enum cgen_insn_type {
  , OR1K_INSN_L_SLLI, OR1K_INSN_L_SRL, OR1K_INSN_L_SRLI, OR1K_INSN_L_SRA
  , OR1K_INSN_L_SRAI, OR1K_INSN_L_ROR, OR1K_INSN_L_RORI, OR1K_INSN_L_AND
  , OR1K_INSN_L_OR, OR1K_INSN_L_XOR, OR1K_INSN_L_ADD, OR1K_INSN_L_SUB
- , OR1K_INSN_L_ADDC, OR1K_INSN_L_MUL, OR1K_INSN_L_MULU, OR1K_INSN_L_DIV
- , OR1K_INSN_L_DIVU, OR1K_INSN_L_FF1, OR1K_INSN_L_FL1, OR1K_INSN_L_ANDI
- , OR1K_INSN_L_ORI, OR1K_INSN_L_XORI, OR1K_INSN_L_ADDI, OR1K_INSN_L_ADDIC
- , OR1K_INSN_L_MULI, OR1K_INSN_L_EXTHS, OR1K_INSN_L_EXTBS, OR1K_INSN_L_EXTHZ
- , OR1K_INSN_L_EXTBZ, OR1K_INSN_L_EXTWS, OR1K_INSN_L_EXTWZ, OR1K_INSN_L_CMOV
- , OR1K_INSN_L_SFGTS, OR1K_INSN_L_SFGTSI, OR1K_INSN_L_SFGTU, OR1K_INSN_L_SFGTUI
- , OR1K_INSN_L_SFGES, OR1K_INSN_L_SFGESI, OR1K_INSN_L_SFGEU, OR1K_INSN_L_SFGEUI
- , OR1K_INSN_L_SFLTS, OR1K_INSN_L_SFLTSI, OR1K_INSN_L_SFLTU, OR1K_INSN_L_SFLTUI
- , OR1K_INSN_L_SFLES, OR1K_INSN_L_SFLESI, OR1K_INSN_L_SFLEU, OR1K_INSN_L_SFLEUI
- , OR1K_INSN_L_SFEQ, OR1K_INSN_L_SFEQI, OR1K_INSN_L_SFNE, OR1K_INSN_L_SFNEI
- , OR1K_INSN_L_MAC, OR1K_INSN_L_MSB, OR1K_INSN_L_MACI, OR1K_INSN_L_CUST1
+ , OR1K_INSN_L_ADDC, OR1K_INSN_L_MUL, OR1K_INSN_L_MULD, OR1K_INSN_L_MULU
+ , OR1K_INSN_L_MULDU, OR1K_INSN_L_DIV, OR1K_INSN_L_DIVU, OR1K_INSN_L_FF1
+ , OR1K_INSN_L_FL1, OR1K_INSN_L_ANDI, OR1K_INSN_L_ORI, OR1K_INSN_L_XORI
+ , OR1K_INSN_L_ADDI, OR1K_INSN_L_ADDIC, OR1K_INSN_L_MULI, OR1K_INSN_L_EXTHS
+ , OR1K_INSN_L_EXTBS, OR1K_INSN_L_EXTHZ, OR1K_INSN_L_EXTBZ, OR1K_INSN_L_EXTWS
+ , OR1K_INSN_L_EXTWZ, OR1K_INSN_L_CMOV, OR1K_INSN_L_SFGTS, OR1K_INSN_L_SFGTSI
+ , OR1K_INSN_L_SFGTU, OR1K_INSN_L_SFGTUI, OR1K_INSN_L_SFGES, OR1K_INSN_L_SFGESI
+ , OR1K_INSN_L_SFGEU, OR1K_INSN_L_SFGEUI, OR1K_INSN_L_SFLTS, OR1K_INSN_L_SFLTSI
+ , OR1K_INSN_L_SFLTU, OR1K_INSN_L_SFLTUI, OR1K_INSN_L_SFLES, OR1K_INSN_L_SFLESI
+ , OR1K_INSN_L_SFLEU, OR1K_INSN_L_SFLEUI, OR1K_INSN_L_SFEQ, OR1K_INSN_L_SFEQI
+ , OR1K_INSN_L_SFNE, OR1K_INSN_L_SFNEI, OR1K_INSN_L_MAC, OR1K_INSN_L_MACI
+ , OR1K_INSN_L_MACU, OR1K_INSN_L_MSB, OR1K_INSN_L_MSBU, OR1K_INSN_L_CUST1
  , OR1K_INSN_L_CUST2, OR1K_INSN_L_CUST3, OR1K_INSN_L_CUST4, OR1K_INSN_L_CUST5
  , OR1K_INSN_L_CUST6, OR1K_INSN_L_CUST7, OR1K_INSN_L_CUST8, OR1K_INSN_LF_ADD_S
  , OR1K_INSN_LF_ADD_D, OR1K_INSN_LF_SUB_S, OR1K_INSN_LF_SUB_D, OR1K_INSN_LF_MUL_S
diff --git a/opcodes/or1k-opinst.c b/opcodes/or1k-opinst.c
index c267efb6c4..53268e21f4 100644
--- a/opcodes/or1k-opinst.c
+++ b/opcodes/or1k-opinst.c
@@ -278,15 +278,53 @@ static const CGEN_OPINST sfmt_l_addc_ops[] ATTRIBUTE_UNUSED = {
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
-static const CGEN_OPINST sfmt_l_div_ops[] ATTRIBUTE_UNUSED = {
+static const CGEN_OPINST sfmt_l_mul_ops[] ATTRIBUTE_UNUSED = {
   { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
-  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
+  { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { INPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, 0 },
+  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
+static const CGEN_OPINST sfmt_l_muld_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
+  { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { OUTPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
+static const CGEN_OPINST sfmt_l_mulu_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
   { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
   { INPUT, "sys_sr_cy", HW_H_SYS_SR_CY, CGEN_MODE_UDI, 0, 0, 0 },
   { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, 0 },
+  { OUTPUT, "sys_sr_cy", HW_H_SYS_SR_CY, CGEN_MODE_UDI, 0, 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
+static const CGEN_OPINST sfmt_l_div_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, COND_REF },
+  { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, COND_REF },
+  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
+static const CGEN_OPINST sfmt_l_divu_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, COND_REF },
+  { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, COND_REF },
   { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, COND_REF },
   { OUTPUT, "sys_sr_cy", HW_H_SYS_SR_CY, CGEN_MODE_UDI, 0, 0, COND_REF },
-  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
@@ -328,6 +366,17 @@ static const CGEN_OPINST sfmt_l_addic_ops[] ATTRIBUTE_UNUSED = {
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
+static const CGEN_OPINST sfmt_l_muli_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
+  { INPUT, "simm16", HW_H_SIMM16, CGEN_MODE_INT, OP_ENT (SIMM16), 0, 0 },
+  { INPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, 0 },
+  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
 static const CGEN_OPINST sfmt_l_exths_ops[] ATTRIBUTE_UNUSED = {
   { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
   { OUTPUT, "rD", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RD), 0, 0 },
@@ -359,20 +408,42 @@ static const CGEN_OPINST sfmt_l_sfgtsi_ops[] ATTRIBUTE_UNUSED = {
 static const CGEN_OPINST sfmt_l_mac_ops[] ATTRIBUTE_UNUSED = {
   { INPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
   { INPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
   { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
   { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { INPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
   { OUTPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
   { OUTPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
 static const CGEN_OPINST sfmt_l_maci_ops[] ATTRIBUTE_UNUSED = {
   { INPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
   { INPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
   { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
   { INPUT, "simm16", HW_H_SIMM16, CGEN_MODE_INT, OP_ENT (SIMM16), 0, 0 },
+  { INPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
   { OUTPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
   { OUTPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "sys_sr_ov", HW_H_SYS_SR_OV, CGEN_MODE_UDI, 0, 0, 0 },
+  { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
+};
+
+static const CGEN_OPINST sfmt_l_macu_ops[] ATTRIBUTE_UNUSED = {
+  { INPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "pc", HW_H_PC, CGEN_MODE_UDI, 0, 0, COND_REF },
+  { INPUT, "rA", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RA), 0, 0 },
+  { INPUT, "rB", HW_H_GPR, CGEN_MODE_UDI, OP_ENT (RB), 0, 0 },
+  { INPUT, "sys_sr_cy", HW_H_SYS_SR_CY, CGEN_MODE_UDI, 0, 0, 0 },
+  { INPUT, "sys_sr_ove", HW_H_SYS_SR_OVE, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "mac_machi", HW_H_MAC_MACHI, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "mac_maclo", HW_H_MAC_MACLO, CGEN_MODE_UDI, 0, 0, 0 },
+  { OUTPUT, "sys_sr_cy", HW_H_SYS_SR_CY, CGEN_MODE_UDI, 0, 0, 0 },
   { END, (const char *)0, (enum cgen_hw_type)0, (enum cgen_mode)0, (enum cgen_operand_type)0, 0, 0 }
 };
 
@@ -502,10 +573,12 @@ static const CGEN_OPINST *or1k_cgen_opinst_table[MAX_INSNS] = {
   & sfmt_l_add_ops[0],
   & sfmt_l_add_ops[0],
   & sfmt_l_addc_ops[0],
-  & sfmt_l_add_ops[0],
-  & sfmt_l_add_ops[0],
-  & sfmt_l_div_ops[0],
+  & sfmt_l_mul_ops[0],
+  & sfmt_l_muld_ops[0],
+  & sfmt_l_mulu_ops[0],
+  & sfmt_l_muld_ops[0],
   & sfmt_l_div_ops[0],
+  & sfmt_l_divu_ops[0],
   & sfmt_l_ff1_ops[0],
   & sfmt_l_ff1_ops[0],
   & sfmt_l_mfspr_ops[0],
@@ -513,7 +586,7 @@ static const CGEN_OPINST *or1k_cgen_opinst_table[MAX_INSNS] = {
   & sfmt_l_xori_ops[0],
   & sfmt_l_addi_ops[0],
   & sfmt_l_addic_ops[0],
-  & sfmt_l_addi_ops[0],
+  & sfmt_l_muli_ops[0],
   & sfmt_l_exths_ops[0],
   & sfmt_l_exths_ops[0],
   & sfmt_l_exths_ops[0],
@@ -542,8 +615,10 @@ static const CGEN_OPINST *or1k_cgen_opinst_table[MAX_INSNS] = {
   & sfmt_l_sfgts_ops[0],
   & sfmt_l_sfgtsi_ops[0],
   & sfmt_l_mac_ops[0],
-  & sfmt_l_mac_ops[0],
   & sfmt_l_maci_ops[0],
+  & sfmt_l_macu_ops[0],
+  & sfmt_l_mac_ops[0],
+  & sfmt_l_macu_ops[0],
   & sfmt_l_msync_ops[0],
   & sfmt_l_msync_ops[0],
   & sfmt_l_msync_ops[0],
diff --git a/sim/common/cgen-ops.h b/sim/common/cgen-ops.h
index 87ca4836ba..0ce7e58bba 100644
--- a/sim/common/cgen-ops.h
+++ b/sim/common/cgen-ops.h
@@ -647,6 +647,38 @@ MUL1OFSI (USI a, USI b)
   return res;
 }
 
+SEMOPS_INLINE BI
+ADDCFDI (DI a, DI b, BI c)
+{
+  DI tmp = ADDDI (a, ADDDI (b, c));
+  BI res = ((UDI) tmp < (UDI) a) || (c && tmp == a);
+  return res;
+}
+
+SEMOPS_INLINE BI
+ADDOFDI (DI a, DI b, BI c)
+{
+  DI tmp = ADDDI (a, ADDDI (b, c));
+  BI res = (((a < 0) == (b < 0))
+	    && ((a < 0) != (tmp < 0)));
+  return res;
+}
+
+SEMOPS_INLINE BI
+SUBCFDI (DI a, DI b, BI c)
+{
+  BI res = ((UDI) a < (UDI) b) || (c && a == b);
+  return res;
+}
+
+SEMOPS_INLINE BI
+SUBOFDI (DI a, DI b, BI c)
+{
+  DI tmp = SUBDI (a, ADDSI (b, c));
+  BI res = (((a < 0) != (b < 0))
+	    && ((a < 0) != (tmp < 0)));
+  return res;
+}
 #else
 
 SI ADDCSI (SI, SI, BI);
@@ -669,6 +701,10 @@ UBI SUBCFQI (QI, QI, BI);
 UBI SUBOFQI (QI, QI, BI);
 BI MUL1OFSI (SI a, SI b);
 BI MUL2OFSI (SI a, SI b);
+BI ADDCFDI (DI a, DI b, BI c);
+BI ADDOFDI (DI a, DI b, BI c);
+BI SUBCFDI (DI a, DI b, BI c);
+BI SUBOFDI (DI a, DI b, BI c);
 
 #endif
 
diff --git a/sim/or1k/cpu.h b/sim/or1k/cpu.h
index 9646c33df6..b847f53032 100644
--- a/sim/or1k/cpu.h
+++ b/sim/or1k/cpu.h
@@ -4515,6 +4515,10 @@ union sem_fields {
   struct { /*  */
     IADDR i_disp26;
   } sfmt_l_j;
+  struct { /*  */
+    IADDR i_disp21;
+    UINT f_r1;
+  } sfmt_l_adrp;
   struct { /*  */
     UINT f_r1;
     UINT f_r2;
@@ -4614,6 +4618,17 @@ struct scache {
   f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
   f_disp26 = ((((EXTRACT_LSB0_SINT (insn, 32, 25, 26)) << (2))) + (pc)); \
 
+#define EXTRACT_IFMT_L_ADRP_VARS \
+  UINT f_opcode; \
+  UINT f_r1; \
+  USI f_disp21; \
+  unsigned int length;
+#define EXTRACT_IFMT_L_ADRP_CODE \
+  length = 4; \
+  f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
+  f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
+  f_disp21 = ((((EXTRACT_LSB0_SINT (insn, 32, 20, 21)) + (((SI) (pc) >> (13))))) << (13)); \
+
 #define EXTRACT_IFMT_L_JR_VARS \
   UINT f_opcode; \
   UINT f_resv_25_10; \
@@ -4831,6 +4846,23 @@ struct scache {
   f_resv_10_7 = EXTRACT_LSB0_UINT (insn, 32, 10, 7); \
   f_op_3_4 = EXTRACT_LSB0_UINT (insn, 32, 3, 4); \
 
+#define EXTRACT_IFMT_L_MULD_VARS \
+  UINT f_opcode; \
+  UINT f_resv_25_5; \
+  UINT f_r2; \
+  UINT f_r3; \
+  UINT f_resv_10_7; \
+  UINT f_op_3_4; \
+  unsigned int length;
+#define EXTRACT_IFMT_L_MULD_CODE \
+  length = 4; \
+  f_opcode = EXTRACT_LSB0_UINT (insn, 32, 31, 6); \
+  f_resv_25_5 = EXTRACT_LSB0_UINT (insn, 32, 25, 5); \
+  f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5); \
+  f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5); \
+  f_resv_10_7 = EXTRACT_LSB0_UINT (insn, 32, 10, 7); \
+  f_op_3_4 = EXTRACT_LSB0_UINT (insn, 32, 3, 4); \
+
 #define EXTRACT_IFMT_L_EXTHS_VARS \
   UINT f_opcode; \
   UINT f_r1; \
diff --git a/sim/or1k/decode.c b/sim/or1k/decode.c
index bc99cc2819..e62476f559 100644
--- a/sim/or1k/decode.c
+++ b/sim/or1k/decode.c
@@ -47,6 +47,7 @@ static const struct insn_sem or1k32bf_insn_sem[] =
   { VIRTUAL_INSN_X_CHAIN, OR1K32BF_INSN_X_CHAIN, OR1K32BF_SFMT_EMPTY },
   { VIRTUAL_INSN_X_BEGIN, OR1K32BF_INSN_X_BEGIN, OR1K32BF_SFMT_EMPTY },
   { OR1K_INSN_L_J, OR1K32BF_INSN_L_J, OR1K32BF_SFMT_L_J },
+  { OR1K_INSN_L_ADRP, OR1K32BF_INSN_L_ADRP, OR1K32BF_SFMT_L_ADRP },
   { OR1K_INSN_L_JAL, OR1K32BF_INSN_L_JAL, OR1K32BF_SFMT_L_JAL },
   { OR1K_INSN_L_JR, OR1K32BF_INSN_L_JR, OR1K32BF_SFMT_L_JR },
   { OR1K_INSN_L_JALR, OR1K32BF_INSN_L_JALR, OR1K32BF_SFMT_L_JALR },
@@ -88,10 +89,12 @@ static const struct insn_sem or1k32bf_insn_sem[] =
   { OR1K_INSN_L_ADD, OR1K32BF_INSN_L_ADD, OR1K32BF_SFMT_L_ADD },
   { OR1K_INSN_L_SUB, OR1K32BF_INSN_L_SUB, OR1K32BF_SFMT_L_ADD },
   { OR1K_INSN_L_ADDC, OR1K32BF_INSN_L_ADDC, OR1K32BF_SFMT_L_ADDC },
-  { OR1K_INSN_L_MUL, OR1K32BF_INSN_L_MUL, OR1K32BF_SFMT_L_ADD },
-  { OR1K_INSN_L_MULU, OR1K32BF_INSN_L_MULU, OR1K32BF_SFMT_L_ADD },
+  { OR1K_INSN_L_MUL, OR1K32BF_INSN_L_MUL, OR1K32BF_SFMT_L_MUL },
+  { OR1K_INSN_L_MULD, OR1K32BF_INSN_L_MULD, OR1K32BF_SFMT_L_MULD },
+  { OR1K_INSN_L_MULU, OR1K32BF_INSN_L_MULU, OR1K32BF_SFMT_L_MULU },
+  { OR1K_INSN_L_MULDU, OR1K32BF_INSN_L_MULDU, OR1K32BF_SFMT_L_MULD },
   { OR1K_INSN_L_DIV, OR1K32BF_INSN_L_DIV, OR1K32BF_SFMT_L_DIV },
-  { OR1K_INSN_L_DIVU, OR1K32BF_INSN_L_DIVU, OR1K32BF_SFMT_L_DIV },
+  { OR1K_INSN_L_DIVU, OR1K32BF_INSN_L_DIVU, OR1K32BF_SFMT_L_DIVU },
   { OR1K_INSN_L_FF1, OR1K32BF_INSN_L_FF1, OR1K32BF_SFMT_L_FF1 },
   { OR1K_INSN_L_FL1, OR1K32BF_INSN_L_FL1, OR1K32BF_SFMT_L_FF1 },
   { OR1K_INSN_L_ANDI, OR1K32BF_INSN_L_ANDI, OR1K32BF_SFMT_L_MFSPR },
@@ -99,7 +102,7 @@ static const struct insn_sem or1k32bf_insn_sem[] =
   { OR1K_INSN_L_XORI, OR1K32BF_INSN_L_XORI, OR1K32BF_SFMT_L_XORI },
   { OR1K_INSN_L_ADDI, OR1K32BF_INSN_L_ADDI, OR1K32BF_SFMT_L_ADDI },
   { OR1K_INSN_L_ADDIC, OR1K32BF_INSN_L_ADDIC, OR1K32BF_SFMT_L_ADDIC },
-  { OR1K_INSN_L_MULI, OR1K32BF_INSN_L_MULI, OR1K32BF_SFMT_L_ADDI },
+  { OR1K_INSN_L_MULI, OR1K32BF_INSN_L_MULI, OR1K32BF_SFMT_L_MULI },
   { OR1K_INSN_L_EXTHS, OR1K32BF_INSN_L_EXTHS, OR1K32BF_SFMT_L_EXTHS },
   { OR1K_INSN_L_EXTBS, OR1K32BF_INSN_L_EXTBS, OR1K32BF_SFMT_L_EXTHS },
   { OR1K_INSN_L_EXTHZ, OR1K32BF_INSN_L_EXTHZ, OR1K32BF_SFMT_L_EXTHS },
@@ -128,8 +131,10 @@ static const struct insn_sem or1k32bf_insn_sem[] =
   { OR1K_INSN_L_SFNE, OR1K32BF_INSN_L_SFNE, OR1K32BF_SFMT_L_SFGTS },
   { OR1K_INSN_L_SFNEI, OR1K32BF_INSN_L_SFNEI, OR1K32BF_SFMT_L_SFGTSI },
   { OR1K_INSN_L_MAC, OR1K32BF_INSN_L_MAC, OR1K32BF_SFMT_L_MAC },
-  { OR1K_INSN_L_MSB, OR1K32BF_INSN_L_MSB, OR1K32BF_SFMT_L_MAC },
   { OR1K_INSN_L_MACI, OR1K32BF_INSN_L_MACI, OR1K32BF_SFMT_L_MACI },
+  { OR1K_INSN_L_MACU, OR1K32BF_INSN_L_MACU, OR1K32BF_SFMT_L_MACU },
+  { OR1K_INSN_L_MSB, OR1K32BF_INSN_L_MSB, OR1K32BF_SFMT_L_MAC },
+  { OR1K_INSN_L_MSBU, OR1K32BF_INSN_L_MSBU, OR1K32BF_SFMT_L_MACU },
   { OR1K_INSN_L_CUST1, OR1K32BF_INSN_L_CUST1, OR1K32BF_SFMT_L_MSYNC },
   { OR1K_INSN_L_CUST2, OR1K32BF_INSN_L_CUST2, OR1K32BF_SFMT_L_MSYNC },
   { OR1K_INSN_L_CUST3, OR1K32BF_INSN_L_CUST3, OR1K32BF_SFMT_L_MSYNC },
@@ -297,6 +302,38 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
       case 61 : /* fall through */
       case 62 : /* fall through */
       case 63 : itype = OR1K32BF_INSN_L_JAL; goto extract_sfmt_l_jal;
+      case 64 : /* fall through */
+      case 65 : /* fall through */
+      case 66 : /* fall through */
+      case 67 : /* fall through */
+      case 68 : /* fall through */
+      case 69 : /* fall through */
+      case 70 : /* fall through */
+      case 71 : /* fall through */
+      case 72 : /* fall through */
+      case 73 : /* fall through */
+      case 74 : /* fall through */
+      case 75 : /* fall through */
+      case 76 : /* fall through */
+      case 77 : /* fall through */
+      case 78 : /* fall through */
+      case 79 : /* fall through */
+      case 80 : /* fall through */
+      case 81 : /* fall through */
+      case 82 : /* fall through */
+      case 83 : /* fall through */
+      case 84 : /* fall through */
+      case 85 : /* fall through */
+      case 86 : /* fall through */
+      case 87 : /* fall through */
+      case 88 : /* fall through */
+      case 89 : /* fall through */
+      case 90 : /* fall through */
+      case 91 : /* fall through */
+      case 92 : /* fall through */
+      case 93 : /* fall through */
+      case 94 : /* fall through */
+      case 95 : itype = OR1K32BF_INSN_L_ADRP; goto extract_sfmt_l_adrp;
       case 96 : /* fall through */
       case 97 : /* fall through */
       case 98 : /* fall through */
@@ -998,7 +1035,7 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
       case 1436 : /* fall through */
       case 1437 : /* fall through */
       case 1438 : /* fall through */
-      case 1439 : itype = OR1K32BF_INSN_L_MULI; goto extract_sfmt_l_addi;
+      case 1439 : itype = OR1K32BF_INSN_L_MULI; goto extract_sfmt_l_muli;
       case 1440 : /* fall through */
       case 1441 : /* fall through */
       case 1442 : /* fall through */
@@ -1212,6 +1249,14 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
         if ((entire_insn & 0xffe007ff) == 0xc4000002)
           { itype = OR1K32BF_INSN_L_MSB; goto extract_sfmt_l_mac; }
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+      case 1571 :
+        if ((entire_insn & 0xffe007ff) == 0xc4000003)
+          { itype = OR1K32BF_INSN_L_MACU; goto extract_sfmt_l_macu; }
+        itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+      case 1572 :
+        if ((entire_insn & 0xffe007ff) == 0xc4000004)
+          { itype = OR1K32BF_INSN_L_MSBU; goto extract_sfmt_l_macu; }
+        itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1600 :
         if ((entire_insn & 0xfc0007ff) == 0xc8000000)
           { itype = OR1K32BF_INSN_LF_ADD_S; goto extract_sfmt_lf_add_s; }
@@ -1426,7 +1471,11 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1798 :
         if ((entire_insn & 0xfc0007ff) == 0xe0000306)
-          { itype = OR1K32BF_INSN_L_MUL; goto extract_sfmt_l_add; }
+          { itype = OR1K32BF_INSN_L_MUL; goto extract_sfmt_l_mul; }
+        itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+      case 1799 :
+        if ((entire_insn & 0xffe007ff) == 0xe0000307)
+          { itype = OR1K32BF_INSN_L_MULD; goto extract_sfmt_l_muld; }
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1800 :
         {
@@ -1450,11 +1499,11 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1802 :
         if ((entire_insn & 0xfc0007ff) == 0xe000030a)
-          { itype = OR1K32BF_INSN_L_DIVU; goto extract_sfmt_l_div; }
+          { itype = OR1K32BF_INSN_L_DIVU; goto extract_sfmt_l_divu; }
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1803 :
         if ((entire_insn & 0xfc0007ff) == 0xe000030b)
-          { itype = OR1K32BF_INSN_L_MULU; goto extract_sfmt_l_add; }
+          { itype = OR1K32BF_INSN_L_MULU; goto extract_sfmt_l_mulu; }
         itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
       case 1804 :
         {
@@ -1473,9 +1522,21 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
           }
         }
       case 1805 :
-        if ((entire_insn & 0xfc00ffff) == 0xe000000d)
-          { itype = OR1K32BF_INSN_L_EXTWS; goto extract_sfmt_l_exths; }
-        itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+        {
+          unsigned int val = (((insn >> 8) & (3 << 0)));
+          switch (val)
+          {
+          case 0 :
+            if ((entire_insn & 0xfc00ffff) == 0xe000000d)
+              { itype = OR1K32BF_INSN_L_EXTWS; goto extract_sfmt_l_exths; }
+            itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+          case 3 :
+            if ((entire_insn & 0xffe007ff) == 0xe000030d)
+              { itype = OR1K32BF_INSN_L_MULDU; goto extract_sfmt_l_muld; }
+            itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+          default : itype = OR1K32BF_INSN_X_INVALID; goto extract_sfmt_empty;
+          }
+        }
       case 1806 :
         if ((entire_insn & 0xfc0007ff) == 0xe000000e)
           { itype = OR1K32BF_INSN_L_CMOV; goto extract_sfmt_l_cmov; }
@@ -1629,6 +1690,26 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   FLD (i_disp26) = f_disp26;
   TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_j", "disp26 0x%x", 'x', f_disp26, (char *) 0));
 
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_adrp:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
+    UINT f_r1;
+    USI f_disp21;
+
+    f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
+    f_disp21 = ((((EXTRACT_LSB0_SINT (insn, 32, 20, 21)) + (((SI) (pc) >> (13))))) << (13));
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r1) = f_r1;
+  FLD (i_disp21) = f_disp21;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_adrp", "f_r1 0x%x", 'x', f_r1, "disp21 0x%x", 'x', f_disp21, (char *) 0));
+
 #undef FLD
     return idesc;
   }
@@ -1768,7 +1849,7 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   {
     const IDESC *idesc = &or1k32bf_insn_data[itype];
     CGEN_INSN_WORD insn = entire_insn;
-#define FLD(f) abuf->fields.sfmt_l_slli.f
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
     UINT f_r1;
 
     f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
@@ -2211,6 +2292,72 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   FLD (f_r1) = f_r1;
   TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_addc", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, "f_r1 0x%x", 'x', f_r1, (char *) 0));
 
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_mul:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+    UINT f_r1;
+    UINT f_r2;
+    UINT f_r3;
+
+    f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_r3) = f_r3;
+  FLD (f_r1) = f_r1;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_mul", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, "f_r1 0x%x", 'x', f_r1, (char *) 0));
+
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_muld:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+    UINT f_r2;
+    UINT f_r3;
+
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_r3) = f_r3;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_muld", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, (char *) 0));
+
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_mulu:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+    UINT f_r1;
+    UINT f_r2;
+    UINT f_r3;
+
+    f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_r3) = f_r3;
+  FLD (f_r1) = f_r1;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_mulu", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, "f_r1 0x%x", 'x', f_r1, (char *) 0));
+
 #undef FLD
     return idesc;
   }
@@ -2234,6 +2381,29 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   FLD (f_r1) = f_r1;
   TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_div", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, "f_r1 0x%x", 'x', f_r1, (char *) 0));
 
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_divu:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+    UINT f_r1;
+    UINT f_r2;
+    UINT f_r3;
+
+    f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_r3) = f_r3;
+  FLD (f_r1) = f_r1;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_divu", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, "f_r1 0x%x", 'x', f_r1, (char *) 0));
+
 #undef FLD
     return idesc;
   }
@@ -2323,6 +2493,29 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   FLD (f_r1) = f_r1;
   TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_addic", "f_r2 0x%x", 'x', f_r2, "f_simm16 0x%x", 'x', f_simm16, "f_r1 0x%x", 'x', f_r1, (char *) 0));
 
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_muli:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_lwz.f
+    UINT f_r1;
+    UINT f_r2;
+    INT f_simm16;
+
+    f_r1 = EXTRACT_LSB0_UINT (insn, 32, 25, 5);
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_simm16 = EXTRACT_LSB0_SINT (insn, 32, 15, 16);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_simm16) = f_simm16;
+  FLD (f_r1) = f_r1;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_muli", "f_r2 0x%x", 'x', f_r2, "f_simm16 0x%x", 'x', f_simm16, "f_r1 0x%x", 'x', f_r1, (char *) 0));
+
 #undef FLD
     return idesc;
   }
@@ -2446,6 +2639,26 @@ or1k32bf_decode (SIM_CPU *current_cpu, IADDR pc,
   FLD (f_simm16) = f_simm16;
   TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_maci", "f_r2 0x%x", 'x', f_r2, "f_simm16 0x%x", 'x', f_simm16, (char *) 0));
 
+#undef FLD
+    return idesc;
+  }
+
+ extract_sfmt_l_macu:
+  {
+    const IDESC *idesc = &or1k32bf_insn_data[itype];
+    CGEN_INSN_WORD insn = entire_insn;
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+    UINT f_r2;
+    UINT f_r3;
+
+    f_r2 = EXTRACT_LSB0_UINT (insn, 32, 20, 5);
+    f_r3 = EXTRACT_LSB0_UINT (insn, 32, 15, 5);
+
+  /* Record the fields for the semantic handler.  */
+  FLD (f_r2) = f_r2;
+  FLD (f_r3) = f_r3;
+  TRACE_EXTRACT (current_cpu, abuf, (current_cpu, pc, "sfmt_l_macu", "f_r2 0x%x", 'x', f_r2, "f_r3 0x%x", 'x', f_r3, (char *) 0));
+
 #undef FLD
     return idesc;
   }
diff --git a/sim/or1k/decode.h b/sim/or1k/decode.h
index 019a0aa342..b45e4f205d 100644
--- a/sim/or1k/decode.h
+++ b/sim/or1k/decode.h
@@ -35,50 +35,52 @@ extern void or1k32bf_semf_init_idesc_table (SIM_CPU *);
 /* Enum declaration for instructions in cpu family or1k32bf.  */
 typedef enum or1k32bf_insn_type {
   OR1K32BF_INSN_X_INVALID, OR1K32BF_INSN_X_AFTER, OR1K32BF_INSN_X_BEFORE, OR1K32BF_INSN_X_CTI_CHAIN
- , OR1K32BF_INSN_X_CHAIN, OR1K32BF_INSN_X_BEGIN, OR1K32BF_INSN_L_J, OR1K32BF_INSN_L_JAL
- , OR1K32BF_INSN_L_JR, OR1K32BF_INSN_L_JALR, OR1K32BF_INSN_L_BNF, OR1K32BF_INSN_L_BF
- , OR1K32BF_INSN_L_TRAP, OR1K32BF_INSN_L_SYS, OR1K32BF_INSN_L_MSYNC, OR1K32BF_INSN_L_PSYNC
- , OR1K32BF_INSN_L_CSYNC, OR1K32BF_INSN_L_RFE, OR1K32BF_INSN_L_NOP_IMM, OR1K32BF_INSN_L_MOVHI
- , OR1K32BF_INSN_L_MACRC, OR1K32BF_INSN_L_MFSPR, OR1K32BF_INSN_L_MTSPR, OR1K32BF_INSN_L_LWZ
- , OR1K32BF_INSN_L_LWS, OR1K32BF_INSN_L_LWA, OR1K32BF_INSN_L_LBZ, OR1K32BF_INSN_L_LBS
- , OR1K32BF_INSN_L_LHZ, OR1K32BF_INSN_L_LHS, OR1K32BF_INSN_L_SW, OR1K32BF_INSN_L_SB
- , OR1K32BF_INSN_L_SH, OR1K32BF_INSN_L_SWA, OR1K32BF_INSN_L_SLL, OR1K32BF_INSN_L_SLLI
- , OR1K32BF_INSN_L_SRL, OR1K32BF_INSN_L_SRLI, OR1K32BF_INSN_L_SRA, OR1K32BF_INSN_L_SRAI
- , OR1K32BF_INSN_L_ROR, OR1K32BF_INSN_L_RORI, OR1K32BF_INSN_L_AND, OR1K32BF_INSN_L_OR
- , OR1K32BF_INSN_L_XOR, OR1K32BF_INSN_L_ADD, OR1K32BF_INSN_L_SUB, OR1K32BF_INSN_L_ADDC
- , OR1K32BF_INSN_L_MUL, OR1K32BF_INSN_L_MULU, OR1K32BF_INSN_L_DIV, OR1K32BF_INSN_L_DIVU
- , OR1K32BF_INSN_L_FF1, OR1K32BF_INSN_L_FL1, OR1K32BF_INSN_L_ANDI, OR1K32BF_INSN_L_ORI
- , OR1K32BF_INSN_L_XORI, OR1K32BF_INSN_L_ADDI, OR1K32BF_INSN_L_ADDIC, OR1K32BF_INSN_L_MULI
- , OR1K32BF_INSN_L_EXTHS, OR1K32BF_INSN_L_EXTBS, OR1K32BF_INSN_L_EXTHZ, OR1K32BF_INSN_L_EXTBZ
- , OR1K32BF_INSN_L_EXTWS, OR1K32BF_INSN_L_EXTWZ, OR1K32BF_INSN_L_CMOV, OR1K32BF_INSN_L_SFGTS
- , OR1K32BF_INSN_L_SFGTSI, OR1K32BF_INSN_L_SFGTU, OR1K32BF_INSN_L_SFGTUI, OR1K32BF_INSN_L_SFGES
- , OR1K32BF_INSN_L_SFGESI, OR1K32BF_INSN_L_SFGEU, OR1K32BF_INSN_L_SFGEUI, OR1K32BF_INSN_L_SFLTS
- , OR1K32BF_INSN_L_SFLTSI, OR1K32BF_INSN_L_SFLTU, OR1K32BF_INSN_L_SFLTUI, OR1K32BF_INSN_L_SFLES
- , OR1K32BF_INSN_L_SFLESI, OR1K32BF_INSN_L_SFLEU, OR1K32BF_INSN_L_SFLEUI, OR1K32BF_INSN_L_SFEQ
- , OR1K32BF_INSN_L_SFEQI, OR1K32BF_INSN_L_SFNE, OR1K32BF_INSN_L_SFNEI, OR1K32BF_INSN_L_MAC
- , OR1K32BF_INSN_L_MSB, OR1K32BF_INSN_L_MACI, OR1K32BF_INSN_L_CUST1, OR1K32BF_INSN_L_CUST2
- , OR1K32BF_INSN_L_CUST3, OR1K32BF_INSN_L_CUST4, OR1K32BF_INSN_L_CUST5, OR1K32BF_INSN_L_CUST6
- , OR1K32BF_INSN_L_CUST7, OR1K32BF_INSN_L_CUST8, OR1K32BF_INSN_LF_ADD_S, OR1K32BF_INSN_LF_SUB_S
- , OR1K32BF_INSN_LF_MUL_S, OR1K32BF_INSN_LF_DIV_S, OR1K32BF_INSN_LF_REM_S, OR1K32BF_INSN_LF_ITOF_S
- , OR1K32BF_INSN_LF_FTOI_S, OR1K32BF_INSN_LF_EQ_S, OR1K32BF_INSN_LF_NE_S, OR1K32BF_INSN_LF_GE_S
- , OR1K32BF_INSN_LF_GT_S, OR1K32BF_INSN_LF_LT_S, OR1K32BF_INSN_LF_LE_S, OR1K32BF_INSN_LF_MADD_S
- , OR1K32BF_INSN_LF_CUST1_S, OR1K32BF_INSN__MAX
+ , OR1K32BF_INSN_X_CHAIN, OR1K32BF_INSN_X_BEGIN, OR1K32BF_INSN_L_J, OR1K32BF_INSN_L_ADRP
+ , OR1K32BF_INSN_L_JAL, OR1K32BF_INSN_L_JR, OR1K32BF_INSN_L_JALR, OR1K32BF_INSN_L_BNF
+ , OR1K32BF_INSN_L_BF, OR1K32BF_INSN_L_TRAP, OR1K32BF_INSN_L_SYS, OR1K32BF_INSN_L_MSYNC
+ , OR1K32BF_INSN_L_PSYNC, OR1K32BF_INSN_L_CSYNC, OR1K32BF_INSN_L_RFE, OR1K32BF_INSN_L_NOP_IMM
+ , OR1K32BF_INSN_L_MOVHI, OR1K32BF_INSN_L_MACRC, OR1K32BF_INSN_L_MFSPR, OR1K32BF_INSN_L_MTSPR
+ , OR1K32BF_INSN_L_LWZ, OR1K32BF_INSN_L_LWS, OR1K32BF_INSN_L_LWA, OR1K32BF_INSN_L_LBZ
+ , OR1K32BF_INSN_L_LBS, OR1K32BF_INSN_L_LHZ, OR1K32BF_INSN_L_LHS, OR1K32BF_INSN_L_SW
+ , OR1K32BF_INSN_L_SB, OR1K32BF_INSN_L_SH, OR1K32BF_INSN_L_SWA, OR1K32BF_INSN_L_SLL
+ , OR1K32BF_INSN_L_SLLI, OR1K32BF_INSN_L_SRL, OR1K32BF_INSN_L_SRLI, OR1K32BF_INSN_L_SRA
+ , OR1K32BF_INSN_L_SRAI, OR1K32BF_INSN_L_ROR, OR1K32BF_INSN_L_RORI, OR1K32BF_INSN_L_AND
+ , OR1K32BF_INSN_L_OR, OR1K32BF_INSN_L_XOR, OR1K32BF_INSN_L_ADD, OR1K32BF_INSN_L_SUB
+ , OR1K32BF_INSN_L_ADDC, OR1K32BF_INSN_L_MUL, OR1K32BF_INSN_L_MULD, OR1K32BF_INSN_L_MULU
+ , OR1K32BF_INSN_L_MULDU, OR1K32BF_INSN_L_DIV, OR1K32BF_INSN_L_DIVU, OR1K32BF_INSN_L_FF1
+ , OR1K32BF_INSN_L_FL1, OR1K32BF_INSN_L_ANDI, OR1K32BF_INSN_L_ORI, OR1K32BF_INSN_L_XORI
+ , OR1K32BF_INSN_L_ADDI, OR1K32BF_INSN_L_ADDIC, OR1K32BF_INSN_L_MULI, OR1K32BF_INSN_L_EXTHS
+ , OR1K32BF_INSN_L_EXTBS, OR1K32BF_INSN_L_EXTHZ, OR1K32BF_INSN_L_EXTBZ, OR1K32BF_INSN_L_EXTWS
+ , OR1K32BF_INSN_L_EXTWZ, OR1K32BF_INSN_L_CMOV, OR1K32BF_INSN_L_SFGTS, OR1K32BF_INSN_L_SFGTSI
+ , OR1K32BF_INSN_L_SFGTU, OR1K32BF_INSN_L_SFGTUI, OR1K32BF_INSN_L_SFGES, OR1K32BF_INSN_L_SFGESI
+ , OR1K32BF_INSN_L_SFGEU, OR1K32BF_INSN_L_SFGEUI, OR1K32BF_INSN_L_SFLTS, OR1K32BF_INSN_L_SFLTSI
+ , OR1K32BF_INSN_L_SFLTU, OR1K32BF_INSN_L_SFLTUI, OR1K32BF_INSN_L_SFLES, OR1K32BF_INSN_L_SFLESI
+ , OR1K32BF_INSN_L_SFLEU, OR1K32BF_INSN_L_SFLEUI, OR1K32BF_INSN_L_SFEQ, OR1K32BF_INSN_L_SFEQI
+ , OR1K32BF_INSN_L_SFNE, OR1K32BF_INSN_L_SFNEI, OR1K32BF_INSN_L_MAC, OR1K32BF_INSN_L_MACI
+ , OR1K32BF_INSN_L_MACU, OR1K32BF_INSN_L_MSB, OR1K32BF_INSN_L_MSBU, OR1K32BF_INSN_L_CUST1
+ , OR1K32BF_INSN_L_CUST2, OR1K32BF_INSN_L_CUST3, OR1K32BF_INSN_L_CUST4, OR1K32BF_INSN_L_CUST5
+ , OR1K32BF_INSN_L_CUST6, OR1K32BF_INSN_L_CUST7, OR1K32BF_INSN_L_CUST8, OR1K32BF_INSN_LF_ADD_S
+ , OR1K32BF_INSN_LF_SUB_S, OR1K32BF_INSN_LF_MUL_S, OR1K32BF_INSN_LF_DIV_S, OR1K32BF_INSN_LF_REM_S
+ , OR1K32BF_INSN_LF_ITOF_S, OR1K32BF_INSN_LF_FTOI_S, OR1K32BF_INSN_LF_EQ_S, OR1K32BF_INSN_LF_NE_S
+ , OR1K32BF_INSN_LF_GE_S, OR1K32BF_INSN_LF_GT_S, OR1K32BF_INSN_LF_LT_S, OR1K32BF_INSN_LF_LE_S
+ , OR1K32BF_INSN_LF_MADD_S, OR1K32BF_INSN_LF_CUST1_S, OR1K32BF_INSN__MAX
 } OR1K32BF_INSN_TYPE;
 
 /* Enum declaration for semantic formats in cpu family or1k32bf.  */
 typedef enum or1k32bf_sfmt_type {
-  OR1K32BF_SFMT_EMPTY, OR1K32BF_SFMT_L_J, OR1K32BF_SFMT_L_JAL, OR1K32BF_SFMT_L_JR
- , OR1K32BF_SFMT_L_JALR, OR1K32BF_SFMT_L_BNF, OR1K32BF_SFMT_L_TRAP, OR1K32BF_SFMT_L_MSYNC
- , OR1K32BF_SFMT_L_NOP_IMM, OR1K32BF_SFMT_L_MOVHI, OR1K32BF_SFMT_L_MACRC, OR1K32BF_SFMT_L_MFSPR
- , OR1K32BF_SFMT_L_MTSPR, OR1K32BF_SFMT_L_LWZ, OR1K32BF_SFMT_L_LWS, OR1K32BF_SFMT_L_LWA
- , OR1K32BF_SFMT_L_LBZ, OR1K32BF_SFMT_L_LBS, OR1K32BF_SFMT_L_LHZ, OR1K32BF_SFMT_L_LHS
- , OR1K32BF_SFMT_L_SW, OR1K32BF_SFMT_L_SB, OR1K32BF_SFMT_L_SH, OR1K32BF_SFMT_L_SWA
- , OR1K32BF_SFMT_L_SLL, OR1K32BF_SFMT_L_SLLI, OR1K32BF_SFMT_L_AND, OR1K32BF_SFMT_L_ADD
- , OR1K32BF_SFMT_L_ADDC, OR1K32BF_SFMT_L_DIV, OR1K32BF_SFMT_L_FF1, OR1K32BF_SFMT_L_XORI
- , OR1K32BF_SFMT_L_ADDI, OR1K32BF_SFMT_L_ADDIC, OR1K32BF_SFMT_L_EXTHS, OR1K32BF_SFMT_L_CMOV
- , OR1K32BF_SFMT_L_SFGTS, OR1K32BF_SFMT_L_SFGTSI, OR1K32BF_SFMT_L_MAC, OR1K32BF_SFMT_L_MACI
- , OR1K32BF_SFMT_LF_ADD_S, OR1K32BF_SFMT_LF_ITOF_S, OR1K32BF_SFMT_LF_FTOI_S, OR1K32BF_SFMT_LF_EQ_S
- , OR1K32BF_SFMT_LF_MADD_S
+  OR1K32BF_SFMT_EMPTY, OR1K32BF_SFMT_L_J, OR1K32BF_SFMT_L_ADRP, OR1K32BF_SFMT_L_JAL
+ , OR1K32BF_SFMT_L_JR, OR1K32BF_SFMT_L_JALR, OR1K32BF_SFMT_L_BNF, OR1K32BF_SFMT_L_TRAP
+ , OR1K32BF_SFMT_L_MSYNC, OR1K32BF_SFMT_L_NOP_IMM, OR1K32BF_SFMT_L_MOVHI, OR1K32BF_SFMT_L_MACRC
+ , OR1K32BF_SFMT_L_MFSPR, OR1K32BF_SFMT_L_MTSPR, OR1K32BF_SFMT_L_LWZ, OR1K32BF_SFMT_L_LWS
+ , OR1K32BF_SFMT_L_LWA, OR1K32BF_SFMT_L_LBZ, OR1K32BF_SFMT_L_LBS, OR1K32BF_SFMT_L_LHZ
+ , OR1K32BF_SFMT_L_LHS, OR1K32BF_SFMT_L_SW, OR1K32BF_SFMT_L_SB, OR1K32BF_SFMT_L_SH
+ , OR1K32BF_SFMT_L_SWA, OR1K32BF_SFMT_L_SLL, OR1K32BF_SFMT_L_SLLI, OR1K32BF_SFMT_L_AND
+ , OR1K32BF_SFMT_L_ADD, OR1K32BF_SFMT_L_ADDC, OR1K32BF_SFMT_L_MUL, OR1K32BF_SFMT_L_MULD
+ , OR1K32BF_SFMT_L_MULU, OR1K32BF_SFMT_L_DIV, OR1K32BF_SFMT_L_DIVU, OR1K32BF_SFMT_L_FF1
+ , OR1K32BF_SFMT_L_XORI, OR1K32BF_SFMT_L_ADDI, OR1K32BF_SFMT_L_ADDIC, OR1K32BF_SFMT_L_MULI
+ , OR1K32BF_SFMT_L_EXTHS, OR1K32BF_SFMT_L_CMOV, OR1K32BF_SFMT_L_SFGTS, OR1K32BF_SFMT_L_SFGTSI
+ , OR1K32BF_SFMT_L_MAC, OR1K32BF_SFMT_L_MACI, OR1K32BF_SFMT_L_MACU, OR1K32BF_SFMT_LF_ADD_S
+ , OR1K32BF_SFMT_LF_ITOF_S, OR1K32BF_SFMT_LF_FTOI_S, OR1K32BF_SFMT_LF_EQ_S, OR1K32BF_SFMT_LF_MADD_S
 } OR1K32BF_SFMT_TYPE;
 
 /* Function unit handlers (user written).  */
diff --git a/sim/or1k/model.c b/sim/or1k/model.c
index 35c6479fd7..bf6b00b33a 100644
--- a/sim/or1k/model.c
+++ b/sim/or1k/model.c
@@ -50,6 +50,22 @@ model_or1200_l_j (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200_l_adrp (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200_l_jal (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -261,7 +277,7 @@ model_or1200_l_movhi (SIM_CPU *current_cpu, void *sem_arg)
 static int
 model_or1200_l_macrc (SIM_CPU *current_cpu, void *sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_slli.f
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
   const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
   const IDESC * UNUSED idesc = abuf->idesc;
   int cycles = 0;
@@ -722,6 +738,22 @@ model_or1200_l_mul (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200_l_muld (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200_l_mulu (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -738,6 +770,22 @@ model_or1200_l_mulu (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200_l_muldu (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200_l_div (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -1346,6 +1394,38 @@ model_or1200_l_mac (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200_l_maci (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_lwz.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
+static int
+model_or1200_l_macu (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200_l_msb (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -1363,9 +1443,9 @@ model_or1200_l_msb (SIM_CPU *current_cpu, void *sem_arg)
 }
 
 static int
-model_or1200_l_maci (SIM_CPU *current_cpu, void *sem_arg)
+model_or1200_l_msbu (SIM_CPU *current_cpu, void *sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_lwz.f
+#define FLD(f) abuf->fields.sfmt_l_sll.f
   const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
   const IDESC * UNUSED idesc = abuf->idesc;
   int cycles = 0;
@@ -1762,6 +1842,22 @@ model_or1200nd_l_j (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200nd_l_adrp (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200nd_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200nd_l_jal (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -1973,7 +2069,7 @@ model_or1200nd_l_movhi (SIM_CPU *current_cpu, void *sem_arg)
 static int
 model_or1200nd_l_macrc (SIM_CPU *current_cpu, void *sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_slli.f
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
   const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
   const IDESC * UNUSED idesc = abuf->idesc;
   int cycles = 0;
@@ -2434,6 +2530,22 @@ model_or1200nd_l_mul (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200nd_l_muld (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200nd_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200nd_l_mulu (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -2450,6 +2562,22 @@ model_or1200nd_l_mulu (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200nd_l_muldu (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200nd_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200nd_l_div (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -3058,6 +3186,38 @@ model_or1200nd_l_mac (SIM_CPU *current_cpu, void *sem_arg)
 #undef FLD
 }
 
+static int
+model_or1200nd_l_maci (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_lwz.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200nd_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
+static int
+model_or1200nd_l_macu (SIM_CPU *current_cpu, void *sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
+  const IDESC * UNUSED idesc = abuf->idesc;
+  int cycles = 0;
+  {
+    int referenced = 0;
+    int UNUSED insn_referenced = abuf->written;
+    cycles += or1k32bf_model_or1200nd_u_exec (current_cpu, idesc, 0, referenced);
+  }
+  return cycles;
+#undef FLD
+}
+
 static int
 model_or1200nd_l_msb (SIM_CPU *current_cpu, void *sem_arg)
 {
@@ -3075,9 +3235,9 @@ model_or1200nd_l_msb (SIM_CPU *current_cpu, void *sem_arg)
 }
 
 static int
-model_or1200nd_l_maci (SIM_CPU *current_cpu, void *sem_arg)
+model_or1200nd_l_msbu (SIM_CPU *current_cpu, void *sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_lwz.f
+#define FLD(f) abuf->fields.sfmt_l_sll.f
   const ARGBUF * UNUSED abuf = SEM_ARGBUF ((SEM_ARG) sem_arg);
   const IDESC * UNUSED idesc = abuf->idesc;
   int cycles = 0;
@@ -3471,6 +3631,7 @@ static const INSN_TIMING or1200_timing[] = {
   { OR1K32BF_INSN_X_CHAIN, 0, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_X_BEGIN, 0, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_J, model_or1200_l_j, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_ADRP, model_or1200_l_adrp, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JAL, model_or1200_l_jal, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JR, model_or1200_l_jr, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JALR, model_or1200_l_jalr, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
@@ -3513,7 +3674,9 @@ static const INSN_TIMING or1200_timing[] = {
   { OR1K32BF_INSN_L_SUB, model_or1200_l_sub, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_ADDC, model_or1200_l_addc, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MUL, model_or1200_l_mul, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MULD, model_or1200_l_muld, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MULU, model_or1200_l_mulu, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MULDU, model_or1200_l_muldu, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_DIV, model_or1200_l_div, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_DIVU, model_or1200_l_divu, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_FF1, model_or1200_l_ff1, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
@@ -3552,8 +3715,10 @@ static const INSN_TIMING or1200_timing[] = {
   { OR1K32BF_INSN_L_SFNE, model_or1200_l_sfne, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_SFNEI, model_or1200_l_sfnei, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MAC, model_or1200_l_mac, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
-  { OR1K32BF_INSN_L_MSB, model_or1200_l_msb, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MACI, model_or1200_l_maci, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MACU, model_or1200_l_macu, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MSB, model_or1200_l_msb, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MSBU, model_or1200_l_msbu, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST1, model_or1200_l_cust1, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST2, model_or1200_l_cust2, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST3, model_or1200_l_cust3, { { (int) UNIT_OR1200_U_EXEC, 1, 1 } } },
@@ -3589,6 +3754,7 @@ static const INSN_TIMING or1200nd_timing[] = {
   { OR1K32BF_INSN_X_CHAIN, 0, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_X_BEGIN, 0, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_J, model_or1200nd_l_j, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_ADRP, model_or1200nd_l_adrp, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JAL, model_or1200nd_l_jal, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JR, model_or1200nd_l_jr, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_JALR, model_or1200nd_l_jalr, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
@@ -3631,7 +3797,9 @@ static const INSN_TIMING or1200nd_timing[] = {
   { OR1K32BF_INSN_L_SUB, model_or1200nd_l_sub, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_ADDC, model_or1200nd_l_addc, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MUL, model_or1200nd_l_mul, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MULD, model_or1200nd_l_muld, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MULU, model_or1200nd_l_mulu, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MULDU, model_or1200nd_l_muldu, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_DIV, model_or1200nd_l_div, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_DIVU, model_or1200nd_l_divu, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_FF1, model_or1200nd_l_ff1, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
@@ -3670,8 +3838,10 @@ static const INSN_TIMING or1200nd_timing[] = {
   { OR1K32BF_INSN_L_SFNE, model_or1200nd_l_sfne, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_SFNEI, model_or1200nd_l_sfnei, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MAC, model_or1200nd_l_mac, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
-  { OR1K32BF_INSN_L_MSB, model_or1200nd_l_msb, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_MACI, model_or1200nd_l_maci, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MACU, model_or1200nd_l_macu, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MSB, model_or1200nd_l_msb, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
+  { OR1K32BF_INSN_L_MSBU, model_or1200nd_l_msbu, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST1, model_or1200nd_l_cust1, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST2, model_or1200nd_l_cust2, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
   { OR1K32BF_INSN_L_CUST3, model_or1200nd_l_cust3, { { (int) UNIT_OR1200ND_U_EXEC, 1, 1 } } },
diff --git a/sim/or1k/sem-switch.c b/sim/or1k/sem-switch.c
index 2f8e0f34da..2045567214 100644
--- a/sim/or1k/sem-switch.c
+++ b/sim/or1k/sem-switch.c
@@ -39,6 +39,7 @@ This file is part of the GNU simulators.
     { OR1K32BF_INSN_X_CHAIN, && case_sem_INSN_X_CHAIN },
     { OR1K32BF_INSN_X_BEGIN, && case_sem_INSN_X_BEGIN },
     { OR1K32BF_INSN_L_J, && case_sem_INSN_L_J },
+    { OR1K32BF_INSN_L_ADRP, && case_sem_INSN_L_ADRP },
     { OR1K32BF_INSN_L_JAL, && case_sem_INSN_L_JAL },
     { OR1K32BF_INSN_L_JR, && case_sem_INSN_L_JR },
     { OR1K32BF_INSN_L_JALR, && case_sem_INSN_L_JALR },
@@ -81,7 +82,9 @@ This file is part of the GNU simulators.
     { OR1K32BF_INSN_L_SUB, && case_sem_INSN_L_SUB },
     { OR1K32BF_INSN_L_ADDC, && case_sem_INSN_L_ADDC },
     { OR1K32BF_INSN_L_MUL, && case_sem_INSN_L_MUL },
+    { OR1K32BF_INSN_L_MULD, && case_sem_INSN_L_MULD },
     { OR1K32BF_INSN_L_MULU, && case_sem_INSN_L_MULU },
+    { OR1K32BF_INSN_L_MULDU, && case_sem_INSN_L_MULDU },
     { OR1K32BF_INSN_L_DIV, && case_sem_INSN_L_DIV },
     { OR1K32BF_INSN_L_DIVU, && case_sem_INSN_L_DIVU },
     { OR1K32BF_INSN_L_FF1, && case_sem_INSN_L_FF1 },
@@ -120,8 +123,10 @@ This file is part of the GNU simulators.
     { OR1K32BF_INSN_L_SFNE, && case_sem_INSN_L_SFNE },
     { OR1K32BF_INSN_L_SFNEI, && case_sem_INSN_L_SFNEI },
     { OR1K32BF_INSN_L_MAC, && case_sem_INSN_L_MAC },
-    { OR1K32BF_INSN_L_MSB, && case_sem_INSN_L_MSB },
     { OR1K32BF_INSN_L_MACI, && case_sem_INSN_L_MACI },
+    { OR1K32BF_INSN_L_MACU, && case_sem_INSN_L_MACU },
+    { OR1K32BF_INSN_L_MSB, && case_sem_INSN_L_MSB },
+    { OR1K32BF_INSN_L_MSBU, && case_sem_INSN_L_MSBU },
     { OR1K32BF_INSN_L_CUST1, && case_sem_INSN_L_CUST1 },
     { OR1K32BF_INSN_L_CUST2, && case_sem_INSN_L_CUST2 },
     { OR1K32BF_INSN_L_CUST3, && case_sem_INSN_L_CUST3 },
@@ -373,6 +378,25 @@ if (1)
 }
   NEXT (vpc);
 
+  CASE (sem, INSN_L_ADRP) : /* l.adrp $rD,${disp21} */
+{
+  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+  {
+    USI opval = FLD (i_disp21);
+    SET_H_GPR (FLD (f_r1), opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
+  }
+
+#undef FLD
+}
+  NEXT (vpc);
+
   CASE (sem, INSN_L_JAL) : /* l.jal ${disp26} */
 {
   SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
@@ -690,7 +714,7 @@ or1k32bf_nop (current_cpu, ZEXTSISI (FLD (f_uimm16)));
 {
   SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
-#define FLD(f) abuf->fields.sfmt_l_slli.f
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
   int UNUSED written = 0;
   IADDR UNUSED pc = abuf->addr;
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
@@ -1365,11 +1389,6 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
     SET_H_SYS_SR_OV (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-  {
-    BI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-    SET_H_SYS_SR_CY (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
   {
     USI opval = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
@@ -1385,7 +1404,7 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
   NEXT (vpc);
 
-  CASE (sem, INSN_L_MULU) : /* l.mulu $rD,$rA,$rB */
+  CASE (sem, INSN_L_MULD) : /* l.muld $rA,$rB */
 {
   SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
@@ -1395,12 +1414,35 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-{
+  DI tmp_result;
+  tmp_result = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
   {
-    BI opval = 0;
-    SET_H_SYS_SR_OV (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+}
+
+#undef FLD
+}
+  NEXT (vpc);
+
+  CASE (sem, INSN_L_MULU) : /* l.mulu $rD,$rA,$rB */
+{
+  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+{
   {
     BI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_SYS_SR_CY (opval);
@@ -1412,7 +1454,7 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
-if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
 }
@@ -1421,7 +1463,7 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
   NEXT (vpc);
 
-  CASE (sem, INSN_L_DIV) : /* l.div $rD,$rA,$rB */
+  CASE (sem, INSN_L_MULDU) : /* l.muldu $rA,$rB */
 {
   SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
@@ -1431,37 +1473,60 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
+  DI tmp_result;
+  tmp_result = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+}
+
+#undef FLD
+}
+  NEXT (vpc);
+
+  CASE (sem, INSN_L_DIV) : /* l.div $rD,$rA,$rB */
+{
+  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
 if (NESI (GET_H_GPR (FLD (f_r3)), 0)) {
 {
   {
     BI opval = 0;
-    SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+    SET_H_SYS_SR_OV (opval);
+    written |= (1 << 5);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
   {
     SI opval = DIVSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
-    written |= (1 << 5);
+    written |= (1 << 4);
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
 } else {
+{
   {
     BI opval = 1;
-    SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
-}
-  {
-    BI opval = 0;
     SET_H_SYS_SR_OV (opval);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+if (GET_H_SYS_SR_OVE ()) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
+}
 }
 
   abuf->written = written;
@@ -1478,38 +1543,33 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
   IADDR UNUSED pc = abuf->addr;
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
-{
 if (NESI (GET_H_GPR (FLD (f_r3)), 0)) {
 {
   {
     BI opval = 0;
     SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
   }
   {
     USI opval = UDIVSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
-    written |= (1 << 5);
+    written |= (1 << 4);
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
 } else {
+{
   {
     BI opval = 1;
     SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
   }
-}
-  {
-    BI opval = 0;
-    SET_H_SYS_SR_OV (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
-  }
-if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+if (GET_H_SYS_SR_OVE ()) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
+}
 }
 
   abuf->written = written;
@@ -1702,11 +1762,6 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
     SET_H_SYS_SR_OV (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-  {
-    USI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), EXTSISI (FLD (f_simm16)));
-    SET_H_SYS_SR_CY (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
   {
     USI opval = MULSI (GET_H_GPR (FLD (f_r2)), EXTSISI (FLD (f_simm16)));
     SET_H_GPR (FLD (f_r1), opval);
@@ -2256,10 +2311,97 @@ if (GET_H_SYS_SR_F ()) {
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
+  DI tmp_result;
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_prod, tmp_mac);
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+  {
+    BI opval = ADDOFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
+}
+
+#undef FLD
+}
+  NEXT (vpc);
+
+  CASE (sem, INSN_L_MACI) : /* l.maci $rA,${simm16} */
+{
+  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+#define FLD(f) abuf->fields.sfmt_l_lwz.f
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+{
+  DI tmp_prod;
+  DI tmp_mac;
+  DI tmp_result;
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (FLD (f_simm16)));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_mac, tmp_prod);
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+  {
+    BI opval = ADDOFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
+}
+
+#undef FLD
+}
+  NEXT (vpc);
+
+  CASE (sem, INSN_L_MACU) : /* l.macu $rA,$rB */
+{
+  SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-  tmp_result = ADDDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_prod, tmp_mac);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2270,6 +2412,15 @@ if (GET_H_SYS_SR_F ()) {
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = ADDCFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_CY (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
 #undef FLD
@@ -2286,10 +2437,13 @@ if (GET_H_SYS_SR_F ()) {
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-  tmp_result = SUBDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = SUBDI (tmp_mac, tmp_prod);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2300,26 +2454,38 @@ if (GET_H_SYS_SR_F ()) {
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = SUBOFDI (tmp_mac, tmp_result, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
 #undef FLD
 }
   NEXT (vpc);
 
-  CASE (sem, INSN_L_MACI) : /* l.maci $rA,${simm16} */
+  CASE (sem, INSN_L_MSBU) : /* l.msbu $rA,$rB */
 {
   SEM_ARG sem_arg = SEM_SEM_ARG (vpc, sc);
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
-#define FLD(f) abuf->fields.sfmt_l_lwz.f
+#define FLD(f) abuf->fields.sfmt_l_sll.f
   int UNUSED written = 0;
   IADDR UNUSED pc = abuf->addr;
   vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (EXTSISI (FLD (f_simm16)), GET_H_GPR (FLD (f_r2)));
-  tmp_result = ADDDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = SUBDI (tmp_mac, tmp_prod);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2330,6 +2496,15 @@ if (GET_H_SYS_SR_F ()) {
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = SUBCFDI (tmp_mac, tmp_result, 0);
+    SET_H_SYS_SR_CY (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
 #undef FLD
diff --git a/sim/or1k/sem.c b/sim/or1k/sem.c
index 6c052ac79d..f67e50e5f5 100644
--- a/sim/or1k/sem.c
+++ b/sim/or1k/sem.c
@@ -228,6 +228,27 @@ if (1)
 #undef FLD
 }
 
+/* l-adrp: l.adrp $rD,${disp21} */
+
+static SEM_PC
+SEM_FN_NAME (or1k32bf,l_adrp) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+  {
+    USI opval = FLD (i_disp21);
+    SET_H_GPR (FLD (f_r1), opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
+  }
+
+  return vpc;
+#undef FLD
+}
+
 /* l-jal: l.jal ${disp26} */
 
 static SEM_PC
@@ -572,7 +593,7 @@ SEM_FN_NAME (or1k32bf,l_movhi) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
 static SEM_PC
 SEM_FN_NAME (or1k32bf,l_macrc) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_slli.f
+#define FLD(f) abuf->fields.sfmt_l_adrp.f
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
   int UNUSED written = 0;
   IADDR UNUSED pc = abuf->addr;
@@ -1304,11 +1325,6 @@ SEM_FN_NAME (or1k32bf,l_mul) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     SET_H_SYS_SR_OV (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-  {
-    BI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-    SET_H_SYS_SR_CY (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
   {
     USI opval = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
@@ -1324,6 +1340,36 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 #undef FLD
 }
 
+/* l-muld: l.muld $rA,$rB */
+
+static SEM_PC
+SEM_FN_NAME (or1k32bf,l_muld) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+  DI tmp_result;
+  tmp_result = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+}
+
+  return vpc;
+#undef FLD
+}
+
 /* l-mulu: l.mulu $rD,$rA,$rB */
 
 static SEM_PC
@@ -1337,11 +1383,6 @@ SEM_FN_NAME (or1k32bf,l_mulu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
 
 {
 {
-  {
-    BI opval = 0;
-    SET_H_SYS_SR_OV (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
-  }
   {
     BI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_SYS_SR_CY (opval);
@@ -1353,7 +1394,7 @@ SEM_FN_NAME (or1k32bf,l_mulu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
-if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
 }
@@ -1362,6 +1403,36 @@ or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 #undef FLD
 }
 
+/* l-muldu: l.muldu $rA,$rB */
+
+static SEM_PC
+SEM_FN_NAME (or1k32bf,l_muldu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+  DI tmp_result;
+  tmp_result = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+}
+
+  return vpc;
+#undef FLD
+}
+
 /* l-div: l.div $rD,$rA,$rB */
 
 static SEM_PC
@@ -1373,38 +1444,33 @@ SEM_FN_NAME (or1k32bf,l_div) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
   IADDR UNUSED pc = abuf->addr;
   SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
-{
 if (NESI (GET_H_GPR (FLD (f_r3)), 0)) {
 {
   {
     BI opval = 0;
-    SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+    SET_H_SYS_SR_OV (opval);
+    written |= (1 << 5);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
   {
     SI opval = DIVSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
-    written |= (1 << 5);
+    written |= (1 << 4);
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
 } else {
+{
   {
     BI opval = 1;
-    SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
-}
-  {
-    BI opval = 0;
     SET_H_SYS_SR_OV (opval);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+if (GET_H_SYS_SR_OVE ()) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
+}
 }
 
   abuf->written = written;
@@ -1423,38 +1489,33 @@ SEM_FN_NAME (or1k32bf,l_divu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
   IADDR UNUSED pc = abuf->addr;
   SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
-{
 if (NESI (GET_H_GPR (FLD (f_r3)), 0)) {
 {
   {
     BI opval = 0;
     SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
   }
   {
     USI opval = UDIVSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
     SET_H_GPR (FLD (f_r1), opval);
-    written |= (1 << 5);
+    written |= (1 << 4);
     CGEN_TRACE_RESULT (current_cpu, abuf, "gpr", 'x', opval);
   }
 }
 } else {
+{
   {
     BI opval = 1;
     SET_H_SYS_SR_CY (opval);
-    written |= (1 << 6);
+    written |= (1 << 5);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
   }
-}
-  {
-    BI opval = 0;
-    SET_H_SYS_SR_OV (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
-  }
-if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+if (GET_H_SYS_SR_OVE ()) {
 or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
 }
+}
 }
 
   abuf->written = written;
@@ -1663,11 +1724,6 @@ SEM_FN_NAME (or1k32bf,l_muli) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     SET_H_SYS_SR_OV (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
   }
-  {
-    USI opval = MUL1OFSI (GET_H_GPR (FLD (f_r2)), EXTSISI (FLD (f_simm16)));
-    SET_H_SYS_SR_CY (opval);
-    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
-  }
   {
     USI opval = MULSI (GET_H_GPR (FLD (f_r2)), EXTSISI (FLD (f_simm16)));
     SET_H_GPR (FLD (f_r1), opval);
@@ -2273,10 +2329,13 @@ SEM_FN_NAME (or1k32bf,l_mac) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
   SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-  tmp_result = ADDDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_prod, tmp_mac);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2287,6 +2346,103 @@ SEM_FN_NAME (or1k32bf,l_mac) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = ADDOFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
+}
+
+  return vpc;
+#undef FLD
+}
+
+/* l-maci: l.maci $rA,${simm16} */
+
+static SEM_PC
+SEM_FN_NAME (or1k32bf,l_maci) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_lwz.f
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+{
+  DI tmp_prod;
+  DI tmp_mac;
+  DI tmp_result;
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (FLD (f_simm16)));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_mac, tmp_prod);
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+  {
+    BI opval = ADDOFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
+}
+
+  return vpc;
+#undef FLD
+}
+
+/* l-macu: l.macu $rA,$rB */
+
+static SEM_PC
+SEM_FN_NAME (or1k32bf,l_macu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+{
+#define FLD(f) abuf->fields.sfmt_l_sll.f
+  ARGBUF *abuf = SEM_ARGBUF (sem_arg);
+  int UNUSED written = 0;
+  IADDR UNUSED pc = abuf->addr;
+  SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
+
+{
+{
+  DI tmp_prod;
+  DI tmp_mac;
+  DI tmp_result;
+  tmp_prod = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = ADDDI (tmp_prod, tmp_mac);
+  {
+    SI opval = SUBWORDDISI (tmp_result, 0);
+    SET_H_MAC_MACHI (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-machi", 'x', opval);
+  }
+  {
+    SI opval = SUBWORDDISI (tmp_result, 1);
+    SET_H_MAC_MACLO (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
+  }
+  {
+    BI opval = ADDCFDI (tmp_prod, tmp_mac, 0);
+    SET_H_SYS_SR_CY (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
   return vpc;
@@ -2305,10 +2461,13 @@ SEM_FN_NAME (or1k32bf,l_msb) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
   SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (GET_H_GPR (FLD (f_r2)), GET_H_GPR (FLD (f_r3)));
-  tmp_result = SUBDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (EXTSIDI (GET_H_GPR (FLD (f_r2))), EXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = SUBDI (tmp_mac, tmp_prod);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2319,28 +2478,40 @@ SEM_FN_NAME (or1k32bf,l_msb) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = SUBOFDI (tmp_mac, tmp_result, 0);
+    SET_H_SYS_SR_OV (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-ov", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_OV (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
   return vpc;
 #undef FLD
 }
 
-/* l-maci: l.maci $rA,${simm16} */
+/* l-msbu: l.msbu $rA,$rB */
 
 static SEM_PC
-SEM_FN_NAME (or1k32bf,l_maci) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
+SEM_FN_NAME (or1k32bf,l_msbu) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
 {
-#define FLD(f) abuf->fields.sfmt_l_lwz.f
+#define FLD(f) abuf->fields.sfmt_l_sll.f
   ARGBUF *abuf = SEM_ARGBUF (sem_arg);
   int UNUSED written = 0;
   IADDR UNUSED pc = abuf->addr;
   SEM_PC vpc = SEM_NEXT_VPC (sem_arg, pc, 4);
 
 {
-  SI tmp_prod;
+{
+  DI tmp_prod;
+  DI tmp_mac;
   DI tmp_result;
-  tmp_prod = MULSI (EXTSISI (FLD (f_simm16)), GET_H_GPR (FLD (f_r2)));
-  tmp_result = ADDDI (JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ()), EXTSIDI (tmp_prod));
+  tmp_prod = MULDI (ZEXTSIDI (GET_H_GPR (FLD (f_r2))), ZEXTSIDI (GET_H_GPR (FLD (f_r3))));
+  tmp_mac = JOINSIDI (GET_H_MAC_MACHI (), GET_H_MAC_MACLO ());
+  tmp_result = SUBDI (tmp_mac, tmp_prod);
   {
     SI opval = SUBWORDDISI (tmp_result, 0);
     SET_H_MAC_MACHI (opval);
@@ -2351,6 +2522,15 @@ SEM_FN_NAME (or1k32bf,l_maci) (SIM_CPU *current_cpu, SEM_ARG sem_arg)
     SET_H_MAC_MACLO (opval);
     CGEN_TRACE_RESULT (current_cpu, abuf, "mac-maclo", 'x', opval);
   }
+  {
+    BI opval = SUBCFDI (tmp_mac, tmp_result, 0);
+    SET_H_SYS_SR_CY (opval);
+    CGEN_TRACE_RESULT (current_cpu, abuf, "sys-sr-cy", 'x', opval);
+  }
+}
+if (ANDIF (GET_H_SYS_SR_CY (), GET_H_SYS_SR_OVE ())) {
+or1k32bf_exception (current_cpu, pc, EXCEPT_RANGE);
+}
 }
 
   return vpc;
@@ -2814,6 +2994,7 @@ static const struct sem_fn_desc sem_fns[] = {
   { OR1K32BF_INSN_X_CHAIN, SEM_FN_NAME (or1k32bf,x_chain) },
   { OR1K32BF_INSN_X_BEGIN, SEM_FN_NAME (or1k32bf,x_begin) },
   { OR1K32BF_INSN_L_J, SEM_FN_NAME (or1k32bf,l_j) },
+  { OR1K32BF_INSN_L_ADRP, SEM_FN_NAME (or1k32bf,l_adrp) },
   { OR1K32BF_INSN_L_JAL, SEM_FN_NAME (or1k32bf,l_jal) },
   { OR1K32BF_INSN_L_JR, SEM_FN_NAME (or1k32bf,l_jr) },
   { OR1K32BF_INSN_L_JALR, SEM_FN_NAME (or1k32bf,l_jalr) },
@@ -2856,7 +3037,9 @@ static const struct sem_fn_desc sem_fns[] = {
   { OR1K32BF_INSN_L_SUB, SEM_FN_NAME (or1k32bf,l_sub) },
   { OR1K32BF_INSN_L_ADDC, SEM_FN_NAME (or1k32bf,l_addc) },
   { OR1K32BF_INSN_L_MUL, SEM_FN_NAME (or1k32bf,l_mul) },
+  { OR1K32BF_INSN_L_MULD, SEM_FN_NAME (or1k32bf,l_muld) },
   { OR1K32BF_INSN_L_MULU, SEM_FN_NAME (or1k32bf,l_mulu) },
+  { OR1K32BF_INSN_L_MULDU, SEM_FN_NAME (or1k32bf,l_muldu) },
   { OR1K32BF_INSN_L_DIV, SEM_FN_NAME (or1k32bf,l_div) },
   { OR1K32BF_INSN_L_DIVU, SEM_FN_NAME (or1k32bf,l_divu) },
   { OR1K32BF_INSN_L_FF1, SEM_FN_NAME (or1k32bf,l_ff1) },
@@ -2895,8 +3078,10 @@ static const struct sem_fn_desc sem_fns[] = {
   { OR1K32BF_INSN_L_SFNE, SEM_FN_NAME (or1k32bf,l_sfne) },
   { OR1K32BF_INSN_L_SFNEI, SEM_FN_NAME (or1k32bf,l_sfnei) },
   { OR1K32BF_INSN_L_MAC, SEM_FN_NAME (or1k32bf,l_mac) },
-  { OR1K32BF_INSN_L_MSB, SEM_FN_NAME (or1k32bf,l_msb) },
   { OR1K32BF_INSN_L_MACI, SEM_FN_NAME (or1k32bf,l_maci) },
+  { OR1K32BF_INSN_L_MACU, SEM_FN_NAME (or1k32bf,l_macu) },
+  { OR1K32BF_INSN_L_MSB, SEM_FN_NAME (or1k32bf,l_msb) },
+  { OR1K32BF_INSN_L_MSBU, SEM_FN_NAME (or1k32bf,l_msbu) },
   { OR1K32BF_INSN_L_CUST1, SEM_FN_NAME (or1k32bf,l_cust1) },
   { OR1K32BF_INSN_L_CUST2, SEM_FN_NAME (or1k32bf,l_cust2) },
   { OR1K32BF_INSN_L_CUST3, SEM_FN_NAME (or1k32bf,l_cust3) },
diff --git a/sim/testsuite/sim/or1k/div.S b/sim/testsuite/sim/or1k/div.S
index e1e28d5621..a3202e9f8c 100644
--- a/sim/testsuite/sim/or1k/div.S
+++ b/sim/testsuite/sim/or1k/div.S
@@ -75,30 +75,30 @@
 # output: report(0x0000000c);\n
 # output: report(0x00000000);\n
 # output: report(0xfffffffd);\n
-# output: report(0x00000001);\n
 # output: report(0x00000000);\n
+# output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffffff4);\n
 # output: report(0x00000000);\n
 # output: report(0xfffffffd);\n
-# output: report(0x00000001);\n
 # output: report(0x00000000);\n
+# output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0x0000000c);\n
 # output: report(0x00000000);\n
 # output: report(0xfffffffd);\n
-# output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: report(0x00000001);\n
+# output: report(0x00000001);\n
 # output: \n
 # output: report(0xfffffff4);\n
 # output: report(0x00000000);\n
 # output: report(0xfffffffd);\n
-# output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: report(0x00000001);\n
+# output: report(0x00000001);\n
 # output: \n
 # output: report(0x0000000c);\n
 # output: report(0x00000003);\n
@@ -233,7 +233,7 @@ start_tests:
 	TEST_INST_I32_I32 l.div, 0x0000000c, 0xfffffffd
 	TEST_INST_I32_I32 l.div, 0x0000000b, 0xfffffffd
 
-	/* Divide by zero.  This will set the carry flag.  */
+	/* Divide by zero.  This will set the overflow flag.  */
 	TEST_INST_I32_I32 l.div, 0x0000000c, 0x00000000
 	TEST_INST_I32_I32 l.div, 0xfffffff4, 0x00000000
 
@@ -241,7 +241,7 @@ start_tests:
 
 	SET_SPR_SR_FLAGS SPR_SR_OVE, r2, r3
 
-	/* Divide by zero.  This will set the carry flag and trigger an
+	/* Divide by zero.  This will set the overflow flag and trigger an
 	   exception.  */
 	TEST_INST_I32_I32 l.div, 0x0000000c, 0x00000000
 	TEST_INST_I32_I32 l.div, 0xfffffff4, 0x00000000
diff --git a/sim/testsuite/sim/or1k/mul.S b/sim/testsuite/sim/or1k/mul.S
index 964badd951..70bbc41e19 100644
--- a/sim/testsuite/sim/or1k/mul.S
+++ b/sim/testsuite/sim/or1k/mul.S
@@ -40,56 +40,56 @@
 # output: report(0x00010000);\n
 # output: report(0x00010000);\n
 # output: report(0x00000000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffffffe);\n
 # output: report(0xfffffffd);\n
 # output: report(0x00000006);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff7fff);\n
 # output: report(0xffff0002);\n
 # output: report(0x7ffffffe);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff7fff);\n
 # output: report(0xffff0000);\n
 # output: report(0x80010000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff0000);\n
 # output: report(0xfffeffff);\n
 # output: report(0x00010000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0x00000002);\n
 # output: report(0xfffffffd);\n
 # output: report(0xfffffffa);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff8000);\n
 # output: report(0x00010000);\n
 # output: report(0x80000000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff7fff);\n
 # output: report(0x00010000);\n
 # output: report(0x7fff0000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
@@ -110,14 +110,14 @@
 # output: report(0x00000002);\n
 # output: report(0xfffffffd);\n
 # output: report(0xfffffffa);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xffff7fff);\n
 # output: report(0xffff0000);\n
 # output: report(0x80010000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000001);\n
 # output: \n
@@ -145,56 +145,56 @@
 # output: report(0x00040000);\n
 # output: report(0x00004000);\n
 # output: report(0x00000000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffffffe);\n
 # output: report(0x0000fffd);\n
 # output: report(0x00000006);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffefffe);\n
 # output: report(0x00008001);\n
 # output: report(0x7ffffffe);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffe0000);\n
 # output: report(0x0000bfff);\n
 # output: report(0x80020000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffdfffe);\n
 # output: report(0x00008000);\n
 # output: report(0x00010000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0x00000002);\n
 # output: report(0x0000fffd);\n
 # output: report(0xfffffffa);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0x00010000);\n
 # output: report(0x00008000);\n
 # output: report(0x80000000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffdfffc);\n
 # output: report(0x00004000);\n
 # output: report(0x7fff0000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
 # output: \n
@@ -215,14 +215,14 @@
 # output: report(0xfffffffe);\n
 # output: report(0x0000fffd);\n
 # output: report(0x00000006);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: report(0x00000000);\n
 # output: \n
 # output: report(0xfffdfffe);\n
 # output: report(0x00008000);\n
 # output: report(0x00010000);\n
-# output: report(0x00000001);\n
+# output: report(0x00000000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000001);\n
 # output: \n
@@ -322,14 +322,14 @@
 # output: report(0xfffffffa);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
-# output: report(0x00000000);\n
+# output: report(0x00000001);\n
 # output: \n
 # output: report(0xffff7fff);\n
 # output: report(0xffff0000);\n
 # output: report(0x80010000);\n
 # output: report(0x00000001);\n
 # output: report(0x00000000);\n
-# output: report(0x00000000);\n
+# output: report(0x00000001);\n
 # output: \n
 # output: exit(0)\n
 
@@ -375,21 +375,19 @@ start_tests:
 	   set the overflow, but not the carry flag .  */
 	TEST_INST_I32_I32 l.mul, 0x00008000, 0x00010000
 
-	/* Multiply two large positive numbers.  This should set both the
-	   carry and overflow flags (even though the result is not a
-	   negative number.  */
+	/* Multiply two large positive numbers.  This should set the
+	   overflow flags (even though the result is not a negative
+	   number.  */
 	TEST_INST_I32_I32 l.mul, 0x00010000, 0x00010000
 
-	/* Multiply two small negative numbers.  This will set the carry
-	   flag, but not the overflow flag.  */
+	/* Multiply two small negative numbers.  This will set no flags.  */
 	TEST_INST_I32_I32 l.mul, 0xfffffffe, 0xfffffffd
 
-	/* Multiply two quite large negative numbers.  This will set the
-	   carry flag, but not the overflow flag.  */
+	/* Multiply two quite large negative numbers.  This will no flags.  */
 	TEST_INST_I32_I32 l.mul, 0xffff7fff, 0xffff0002
 
 	/* Multiply two slightly too large negative numbers.  This should
-	   set both the overflow, and the carry flags  */
+	   set the overflow flag.  */
 	TEST_INST_I32_I32 l.mul, 0xffff7fff, 0xffff0000
 
 	/* Multiply two large negative numbers.  This should set the
@@ -398,18 +396,15 @@ start_tests:
 	TEST_INST_I32_I32 l.mul, 0xffff0000, 0xfffeffff
 
 	/* Multiply one small negative number and one small positive
-	   number.  This will set the carry flag, but not the overflow
-	   flag.  */
+	   number.  This will set the no flags.  */
 	TEST_INST_I32_I32 l.mul, 0x00000002, 0xfffffffd
 
 	/* Multiply one quite large negative number and one quite large
-	   positive number.  This will set the carry, but not the
-	   overflow flag.  */
+	   positive number.  This will set no flags.  */
 	TEST_INST_I32_I32 l.mul, 0xffff8000, 0x00010000
 
 	/* Multiply one slightly too large negative number and one slightly
-	   too large positive number.  This should set both the carry and
-	   overflow flags.  */
+	   too large positive number.  This should set the overflow flag.  */
 	TEST_INST_I32_I32 l.mul, 0xffff7fff, 0x00010000
 
 	/* Multiply the largest negative number by positive unity.  This
@@ -423,10 +418,11 @@ start_tests:
 	/* Check that an overflow alone causes a RANGE Exception.  */
 	TEST_INST_I32_I32 l.mul, 0x00008000, 0x00010000
 
-	/* Check that a carry alone does not cause a RANGE Exception.  */
+	/* Check multiply of a negative and positive does not cause a RANGE
+	   Exception.  */
 	TEST_INST_I32_I32 l.mul, 0x00000002, 0xfffffffd
 
-	/* Check that carry and overflow together cause an exception.  */
+	/* Check that negative overflow causes a RANGE exception.  */
 	TEST_INST_I32_I32 l.mul, 0xffff7fff, 0xffff0000
 
 	CLEAR_SPR_SR_FLAGS SPR_SR_OVE, r2, r3
@@ -445,41 +441,35 @@ start_tests:
 	   set the overflow, but not the carry flag.  */
 	TEST_INST_I32_I16 l.muli, 0x00020000, 0x4000
 
-	/* Multiply two large positive numbers.  This should set both the
-	   carry and overflow flags (even though the result is not a
-	   negative number.  */
+	/* Multiply two large positive numbers.  This should set the
+	   overflow flag, even though the result is not a negative number.  */
 	TEST_INST_I32_I16 l.muli, 0x00040000, 0x4000
 
-	/* Multiply two small negative numbers.  This should set the
-	   carry flag, but not the overflow flag.  */
+	/* Multiply two small negative numbers.  This should set no flags.  */
 	TEST_INST_I32_I16 l.muli, 0xfffffffe, 0xfffd
 
-	/* Multiply two quite large negative numbers.  This will set the
-	   carry, but not the overflow flag.  */
+	/* Multiply two quite large negative numbers.  This will set no
+	   flags.  */
 	TEST_INST_I32_I16 l.muli, 0xfffefffe, 0x8001
 
 	/* Multiply two slightly too large negative numbers.  This should
-	   set both the overflow, and the carry flags  */
+	   set the overflow flag.  */
 	TEST_INST_I32_I16 l.muli, 0xfffe0000, 0xbfff
 
-	/* Multiply two large negative numbers.  This should set the both
-	   the carry and overflow flags (even though the result is a
-	   positive number.  */
+	/* Multiply two large negative numbers.  This should set the
+	   overflow flag, even though the result is a positive number.  */
 	TEST_INST_I32_I16 l.muli, 0xfffdfffe, 0x8000
 
 	/* Multiply one small negative number and one small positive
-	   number.  This will set the carry flag, but not the overflow
-	   flag.  */
+	   number.  This will set no flags.  */
 	TEST_INST_I32_I16 l.muli, 0x00000002, 0xfffd
 
 	/* Multiply one quite large negative number and one quite large
-	   positive number.  This will set the carry flag, but not the
-	   overflow flag.  */
+	   positive number.  This will set no flags.  */
 	TEST_INST_I32_I16 l.muli, 0x00010000, 0x8000
 
 	/* Multiply one slightly too large negative number and one slightly
-	   too large positive number.  This should set both the carry and
-	   overflow flags.  */
+	   too large positive number.  This will set the overflow flag.  */
 	TEST_INST_I32_I16 l.muli, 0xfffdfffc, 0x4000
 
 	/* Multiply the largest negative number by positive unity.  Should
@@ -493,10 +483,11 @@ start_tests:
 	/* Check that an overflow alone causes a RANGE Exception.  */
 	TEST_INST_I32_I16 l.muli, 0x00020000, 0x4000
 
-	/* Check that a carry alone does not cause a RANGE Exception.  */
+	/* Check that two negatives will not cause a RANGE Exception.  */
 	TEST_INST_I32_I16 l.muli, 0xfffffffe, 0xfffd
 
-	/* Check that carry and overflow together cause an exception.  */
+	/* Check that multiply of larget negative and positive numbers causes
+	   a RANGE exception and overflow.  */
 	TEST_INST_I32_I16 l.muli, 0xfffdfffe, 0x8000
 
 	CLEAR_SPR_SR_FLAGS SPR_SR_OVE, r2, r3
@@ -561,11 +552,11 @@ start_tests:
 	   does not cause a RANGE Exception.  */
 	TEST_INST_I32_I32 l.mulu, 0x00008000, 0x00010000
 
-	/* Check that a carry alone does not cause a RANGE Exception.  */
+	/* Check that a carry causes a RANGE Exception.  */
 	TEST_INST_I32_I32 l.mulu, 0x00000002, 0xfffffffd
 
 	/* Check that what would cause an overflow and carry in 2's
-	   complement does not cause a RANGE Exception.  */
+	   complement causes a RANGE Exception.  */
 	TEST_INST_I32_I32 l.mulu, 0xffff7fff, 0xffff0000
 
 	CLEAR_SPR_SR_FLAGS SPR_SR_OVE, r2, r3
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
                   ` (3 preceding siblings ...)
  2018-08-21 14:38 ` [OpenRISC] [PATCH 4/4] or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns Stafford Horne
@ 2018-09-08 21:35 ` Stafford Horne
  2018-09-17 15:07   ` Nick Clifton
  4 siblings, 1 reply; 16+ messages in thread
From: Stafford Horne @ 2018-09-08 21:35 UTC (permalink / raw)
  To: openrisc

Hello,

Does anyone have concerns with these patches?  Mostly they are for openrisc
parts only.

Thoughts; We have new relocations here, maybe I need to add documentation?

Other than that I think it looks ok.

-Stafford

On Tue, Aug 21, 2018 at 11:38:19PM +0900, Stafford Horne wrote:
> Hello,
> 
> This series contains a lot of updates for OpenRISC binutils.  Including:
>   - Definitions for missing instructions.
>   - New relocations used in the new GCC OpenRISC port
>   - A new instruction l.adrp
> 
> The patches were for the most part written by Richard Henderson, I have fixed a
> few bugs, added additional tests and wrote the ChangeLogs.
> 
> These patches have been tested and used in the new OpenRISC GCC clean-room
> rewrite done by Richard and Me.
> 
>   http://stffrdhrn.github.io/software/embedded/openrisc/2018/02/03/openrisc_gcc_rewrite.html
> 
> -Stafford
> 
> Richard Henderson (2):
>   or1k: Add relocations for high-signed and low-stores
>   or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns
> 
> Stafford Horne (2):
>   or1k: Fix messages for relocations in shared libraries
>   or1k: Add the l.adrp insn and supporting relocations
> 
>  bfd/bfd-in2.h                                 |   19 +-
>  bfd/elf32-or1k.c                              | 1002 +++++++++++++----
>  bfd/libbfd.h                                  |   19 +-
>  bfd/reloc.c                                   |   34 +-
>  cpu/or1k.opc                                  |  582 +++++-----
>  cpu/or1korbis.cpu                             |  300 +++--
>  gas/config/tc-or1k.c                          |    6 +
>  gas/testsuite/gas/or1k/allinsn.d              |   50 +-
>  gas/testsuite/gas/or1k/allinsn.s              |   25 +
>  .../gas/or1k/{allinsn.exp => or1k.exp}        |    1 +
>  gas/testsuite/gas/or1k/reloc-1.d              |   72 ++
>  gas/testsuite/gas/or1k/reloc-1.s              |   76 ++
>  gas/testsuite/gas/or1k/reloc-2.l              |   11 +
>  gas/testsuite/gas/or1k/reloc-2.s              |   13 +
>  include/elf/or1k.h                            |   19 +
>  ld/testsuite/ld-or1k/offsets1.d               |  212 ++++
>  ld/testsuite/ld-or1k/offsets1.s               |   14 +
>  ld/testsuite/ld-or1k/or1k.exp                 |   91 ++
>  ld/testsuite/ld-or1k/plt1.dd                  |   27 +
>  ld/testsuite/ld-or1k/plt1.s                   |   11 +
>  ld/testsuite/ld-or1k/plt1.x.dd                |   27 +
>  ld/testsuite/ld-or1k/plta1.dd                 |   27 +
>  ld/testsuite/ld-or1k/plta1.s                  |   11 +
>  ld/testsuite/ld-or1k/pltlib.s                 |   12 +
>  opcodes/or1k-asm.c                            |  587 +++++-----
>  opcodes/or1k-desc.c                           |   34 +-
>  opcodes/or1k-desc.h                           |   48 +-
>  opcodes/or1k-dis.c                            |    3 +
>  opcodes/or1k-ibld.c                           |   29 +-
>  opcodes/or1k-opc.c                            |   44 +-
>  opcodes/or1k-opc.h                            |   65 +-
>  opcodes/or1k-opinst.c                         |   98 +-
>  sim/common/cgen-ops.h                         |   36 +
>  sim/or1k/cpu.h                                |   32 +
>  sim/or1k/decode.c                             |  239 +++-
>  sim/or1k/decode.h                             |   82 +-
>  sim/or1k/model.c                              |  186 ++-
>  sim/or1k/sem-switch.c                         |  281 ++++-
>  sim/or1k/sem.c                                |  293 ++++-
>  sim/testsuite/sim/or1k/div.S                  |   12 +-
>  sim/testsuite/sim/or1k/mul.S                  |  109 +-
>  41 files changed, 3643 insertions(+), 1196 deletions(-)
>  rename gas/testsuite/gas/or1k/{allinsn.exp => or1k.exp} (83%)
>  create mode 100644 gas/testsuite/gas/or1k/reloc-1.d
>  create mode 100644 gas/testsuite/gas/or1k/reloc-1.s
>  create mode 100644 gas/testsuite/gas/or1k/reloc-2.l
>  create mode 100644 gas/testsuite/gas/or1k/reloc-2.s
>  create mode 100644 ld/testsuite/ld-or1k/offsets1.d
>  create mode 100644 ld/testsuite/ld-or1k/offsets1.s
>  create mode 100644 ld/testsuite/ld-or1k/or1k.exp
>  create mode 100644 ld/testsuite/ld-or1k/plt1.dd
>  create mode 100644 ld/testsuite/ld-or1k/plt1.s
>  create mode 100644 ld/testsuite/ld-or1k/plt1.x.dd
>  create mode 100644 ld/testsuite/ld-or1k/plta1.dd
>  create mode 100644 ld/testsuite/ld-or1k/plta1.s
>  create mode 100644 ld/testsuite/ld-or1k/pltlib.s
> 
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-08 21:35 ` [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
@ 2018-09-17 15:07   ` Nick Clifton
  2018-09-17 16:29     ` Richard Henderson
  2018-09-18  9:52     ` Stafford Horne
  0 siblings, 2 replies; 16+ messages in thread
From: Nick Clifton @ 2018-09-17 15:07 UTC (permalink / raw)
  To: openrisc

Hi Stafford,

> Does anyone have concerns with these patches?  Mostly they are for openrisc
> parts only.

Sorry for the long silence - I have been very busy of late.

The patch series looks basically fine to me, so I have no concerns there.
There are a few minor formatting glitches, but nothing serious.

I do not see any need to add extra document for the new relocs, unless you
have created new assembler pseudo-ops to generate them.  (I did not see any
code to add such operators, but I may have missed something).

I do have one question though.  Is there a need to be able to distinguish 
between binaries that use the new l.adrp instruction and those that don't.
For example if a library is built using the new instruction but then it is
linked into an executable which is supposed to run on silicon which does
not support the new instruction, should the linker issue an error ?  If so,
how does it detect this situation ?

Cheers
  Nick

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-17 15:07   ` Nick Clifton
@ 2018-09-17 16:29     ` Richard Henderson
  2018-09-18  9:52     ` Stafford Horne
  1 sibling, 0 replies; 16+ messages in thread
From: Richard Henderson @ 2018-09-17 16:29 UTC (permalink / raw)
  To: openrisc

On 9/17/18 8:07 AM, Nick Clifton wrote:
> I do not see any need to add extra document for the new relocs, unless you
> have created new assembler pseudo-ops to generate them.  (I did not see any
> code to add such operators, but I may have missed something).

There is new syntax for these new relocs, in the form of function-like markup.

E.g:

	l.ori	r3,r4, at lo(foo)		# an existing reloc
	l.ori	r3,r4, at po(foo)		# a new reloc added here

> I do have one question though.  Is there a need to be able to distinguish 
> between binaries that use the new l.adrp instruction and those that don't.
> For example if a library is built using the new instruction but then it is
> linked into an executable which is supposed to run on silicon which does
> not support the new instruction, should the linker issue an error ?  If so,
> how does it detect this situation ?

I have never been a fan of how this is handled e.g. for mips.
To that end, I have done nothing at all.  This is more in line
with how we (do not) handle this situation for x86.


r~

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-17 15:07   ` Nick Clifton
  2018-09-17 16:29     ` Richard Henderson
@ 2018-09-18  9:52     ` Stafford Horne
  2018-09-18 11:55       ` Nick Clifton
  1 sibling, 1 reply; 16+ messages in thread
From: Stafford Horne @ 2018-09-18  9:52 UTC (permalink / raw)
  To: openrisc

On Mon, Sep 17, 2018 at 04:07:44PM +0100, Nick Clifton wrote:
> Hi Stafford,
> 
> > Does anyone have concerns with these patches?  Mostly they are for openrisc
> > parts only.
> 
> Sorry for the long silence - I have been very busy of late.
> 
> The patch series looks basically fine to me, so I have no concerns there.
> There are a few minor formatting glitches, but nothing serious.

Will you be able to point them out?  Even just some hints?  We have tried to
follow conventions, but there might be some missed spots.  I will go over
everything again just in case and run any formatting tools I have, but any tips
will be helpful.

> I do not see any need to add extra document for the new relocs, unless you
> have created new assembler pseudo-ops to generate them.  (I did not see any
> code to add such operators, but I may have missed something).

As Richard mentioned we have added a few, see PATCH 3/4 in cpu/or1k.opc the
change:

	(parse_reloc): Add new po(), gotpo() and gottppo() for LO13 relocations.

Is this what you mean?  I will look into adding the documentation for these.

> I do have one question though.  Is there a need to be able to distinguish 
> between binaries that use the new l.adrp instruction and those that don't.
> For example if a library is built using the new instruction but then it is
> linked into an executable which is supposed to run on silicon which does
> not support the new instruction, should the linker issue an error ?  If so,
> how does it detect this situation ?

As Richard mentioned we don't handle this.

We have cases like this right now as well, i.e. binaries generated with `l.mul`
or `l.div` instructions will link fine into an executable that assume those
instrunctions should be emulated.  That doesn't throw an error and I don't think
it has been a problem.

-Stafford

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-18  9:52     ` Stafford Horne
@ 2018-09-18 11:55       ` Nick Clifton
  2018-09-18 12:07         ` Joel Sherrill
                           ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Nick Clifton @ 2018-09-18 11:55 UTC (permalink / raw)
  To: openrisc

Hi Stafford,

>> There are a few minor formatting glitches, but nothing serious.
> 
> Will you be able to point them out?  Even just some hints?

Sure...

So for example in patch 1/4 there is:

  +enum {
  +  RTYPE_LO = 0,

when really it should be:

  +enum 
  +{
  +  RTYPE_LO = 0,

(And similarly in other places.  Basically, try to avoid ending a line
with an opening curly brace, unless that brace is the only character on
the line).

Then there is:

  +static int
  +parse_reloc(const char **strp)

Which ought to be:

  +static int
  +parse_reloc (const char **strp)

Ie - a single space between the function name and its parameters.
(I did say that these were minor formatting nits...)  In a similar
vein there is:

  +  return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
  +}
 
which also needs a space between the function name and its arguments.

There are a few other cases of the above issues in the other patches,
but nothing else of note.


One other thing:  There are several places where you add calls to 
abort().  Now this is not wrong, and certainly not a reason to 
reject the patch, but I consider it to be unhelpful.  To my mind
a library, or tool, should generate an error message when something
goes wrong and not leave the user wondering why they have suddenly
got a segmentation fault.

Plus if you have a call to abort() in the code you can bet that some 
enterprising person with a binary fuzzer will find a way to trigger 
it, and then file a CVE about it.  (Fixing CVEs is the bane of my 
life as they involve lots of extra administrivia).



>> I do not see any need to add extra document for the new relocs, unless you
>> have created new assembler pseudo-ops to generate them.

> As Richard mentioned we have added a few, see PATCH 3/4 in cpu/or1k.opc the
> change:
> 
> 	(parse_reloc): Add new po(), gotpo() and gottppo() for LO13 relocations.
> 
> Is this what you mean?  I will look into adding the documentation for these.

Please do.  Most likely you will want to create a gas/doc/c-or1k.c file,
(copying the contents from another, similar file and modifying as needed), and
then patch the gas/doc/as.texi file to include it and the gas/doc/all.texi file
to define a macro for it.


>> I do have one question though.  Is there a need to be able to distinguish 
>> between binaries that use the new l.adrp instruction and those that don't.

> As Richard mentioned we don't handle this.
> 
> We have cases like this right now as well, i.e. binaries generated with `l.mul`
> or `l.div` instructions will link fine into an executable that assume those
> instrunctions should be emulated.  That doesn't throw an error and I don't think
> it has been a problem.

OK, well it is your target, so if you are OK with this then so be it.
I would recommend however thinking about a solution for the future, should the
openRISC architecture gain more variants.  My suggestion would be to make use
of ELF notes, as has been done with other ports.

Cheers
  Nick



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-18 11:55       ` Nick Clifton
@ 2018-09-18 12:07         ` Joel Sherrill
  2018-09-21 12:40           ` Stafford Horne
  2018-09-19 13:23         ` Stafford Horne
  2018-09-27  6:07         ` Stafford Horne
  2 siblings, 1 reply; 16+ messages in thread
From: Joel Sherrill @ 2018-09-18 12:07 UTC (permalink / raw)
  To: openrisc

On Tue, Sep 18, 2018, 6:56 AM Nick Clifton <nickc@redhat.com> wrote:

> Hi Stafford,
>
> >> There are a few minor formatting glitches, but nothing serious.
> >
> > Will you be able to point them out?  Even just some hints?
>
> Sure...
>
> So for example in patch 1/4 there is:
>
>   +enum {
>   +  RTYPE_LO = 0,
>
> when really it should be:
>
>   +enum
>   +{
>   +  RTYPE_LO = 0,
>
> (And similarly in other places.  Basically, try to avoid ending a line
> with an opening curly brace, unless that brace is the only character on
> the line).
>
> Then there is:
>
>   +static int
>   +parse_reloc(const char **strp)
>
> Which ought to be:
>
>   +static int
>   +parse_reloc (const char **strp)
>
> Ie - a single space between the function name and its parameters.
> (I did say that these were minor formatting nits...)  In a similar
> vein there is:
>
>   +  return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
>   +}
>
> which also needs a space between the function name and its arguments.
>
> There are a few other cases of the above issues in the other patches,
> but nothing else of note.
>
>
> One other thing:  There are several places where you add calls to
> abort().  Now this is not wrong, and certainly not a reason to
> reject the patch, but I consider it to be unhelpful.  To my mind
> a library, or tool, should generate an error message when something
> goes wrong and not leave the user wondering why they have suddenly
> got a segmentation fault.
>
> Plus if you have a call to abort() in the code you can bet that some
> enterprising person with a binary fuzzer will find a way to trigger
> it, and then file a CVE about it.  (Fixing CVEs is the bane of my
> life as they involve lots of extra administrivia).
>
>
>
> >> I do not see any need to add extra document for the new relocs, unless
> you
> >> have created new assembler pseudo-ops to generate them.
>
> > As Richard mentioned we have added a few, see PATCH 3/4 in cpu/or1k.opc
> the
> > change:
> >
> >       (parse_reloc): Add new po(), gotpo() and gottppo() for LO13
> relocations.
> >
> > Is this what you mean?  I will look into adding the documentation for
> these.
>
> Please do.  Most likely you will want to create a gas/doc/c-or1k.c file,
> (copying the contents from another, similar file and modifying as needed),
> and
> then patch the gas/doc/as.texi file to include it and the gas/doc/all.texi
> file
> to define a macro for it.
>
>
> >> I do have one question though.  Is there a need to be able to
> distinguish
> >> between binaries that use the new l.adrp instruction and those that
> don't.
>
> > As Richard mentioned we don't handle this.
> >
> > We have cases like this right now as well, i.e. binaries generated with
> `l.mul`
> > or `l.div` instructions will link fine into an executable that assume
> those
> > instrunctions should be emulated.  That doesn't throw an error and I
> don't think
> > it has been a problem.
>
> OK, well it is your target, so if you are OK with this then so be it.
> I would recommend however thinking about a solution for the future, should
> the
> openRISC architecture gain more variants.  My suggestion would be to make
> use
> of ELF notes, as has been done with other ports.
>

Is there a way to avoid these instructions with GCC? As a general rule, for
RTEMS we assume the code is properly generated for the target CPU and don't
emulate missing instructions.

Also for these cases, is there a flag implicitly set by GCC based on CPU
specific flags to let assembly code.know not to use them.

And are there mulilibs which do and do not use them?

In the deeply embedded space, we assume the tools and user can generate
code which doesn't need emulation traps. There is some responsibility on
the toolchain to.make it possible.

Thanks.

--joel

>
> Cheers
>   Nick
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.librecores.org/pipermail/openrisc/attachments/20180918/3f16dea6/attachment-0001.html>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-18 11:55       ` Nick Clifton
  2018-09-18 12:07         ` Joel Sherrill
@ 2018-09-19 13:23         ` Stafford Horne
  2018-09-27  6:07         ` Stafford Horne
  2 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-09-19 13:23 UTC (permalink / raw)
  To: openrisc

On Tue, Sep 18, 2018 at 12:55:48PM +0100, Nick Clifton wrote:
> Hi Stafford,
> 
> >> There are a few minor formatting glitches, but nothing serious.
> > 
> > Will you be able to point them out?  Even just some hints?
> 
> Sure...
> 
> So for example in patch 1/4 there is:
> 
>   +enum {
>   +  RTYPE_LO = 0,
> 
> when really it should be:
> 
>   +enum 
>   +{
>   +  RTYPE_LO = 0,
> 
> (And similarly in other places.  Basically, try to avoid ending a line
> with an opening curly brace, unless that brace is the only character on
> the line).
> 
> Then there is:
> 
>   +static int
>   +parse_reloc(const char **strp)
> 
> Which ought to be:
> 
>   +static int
>   +parse_reloc (const char **strp)
> 
> Ie - a single space between the function name and its parameters.
> (I did say that these were minor formatting nits...)  In a similar
> vein there is:
> 
>   +  return parse_imm16(cd, strp, opindex, (long *) valuep, 0);
>   +}
>  
> which also needs a space between the function name and its arguments.
> 
> There are a few other cases of the above issues in the other patches,
> but nothing else of note.

Ack on the braces and function spaces.  I will clean those up.

> One other thing:  There are several places where you add calls to 
> abort().  Now this is not wrong, and certainly not a reason to 
> reject the patch, but I consider it to be unhelpful.  To my mind
> a library, or tool, should generate an error message when something
> goes wrong and not leave the user wondering why they have suddenly
> got a segmentation fault.
> 
> Plus if you have a call to abort() in the code you can bet that some 
> enterprising person with a binary fuzzer will find a way to trigger 
> it, and then file a CVE about it.  (Fixing CVEs is the bane of my 
> life as they involve lots of extra administrivia).

OK, I will fix those too.

> >> I do not see any need to add extra document for the new relocs, unless you
> >> have created new assembler pseudo-ops to generate them.
> 
> > As Richard mentioned we have added a few, see PATCH 3/4 in cpu/or1k.opc the
> > change:
> > 
> > 	(parse_reloc): Add new po(), gotpo() and gottppo() for LO13 relocations.
> > 
> > Is this what you mean?  I will look into adding the documentation for these.
> 
> Please do.  Most likely you will want to create a gas/doc/c-or1k.c file,
> (copying the contents from another, similar file and modifying as needed), and
> then patch the gas/doc/as.texi file to include it and the gas/doc/all.texi file
> to define a macro for it.

Sure I will do that.

> >> I do have one question though.  Is there a need to be able to distinguish 
> >> between binaries that use the new l.adrp instruction and those that don't.
> 
> > As Richard mentioned we don't handle this.
> > 
> > We have cases like this right now as well, i.e. binaries generated with `l.mul`
> > or `l.div` instructions will link fine into an executable that assume those
> > instrunctions should be emulated.  That doesn't throw an error and I don't think
> > it has been a problem.
> 
> OK, well it is your target, so if you are OK with this then so be it.
> I would recommend however thinking about a solution for the future, should the
> openRISC architecture gain more variants.  My suggestion would be to make use
> of ELF notes, as has been done with other ports.

Thanks, I will keep that in mind.

-Stafford

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-18 12:07         ` Joel Sherrill
@ 2018-09-21 12:40           ` Stafford Horne
  0 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-09-21 12:40 UTC (permalink / raw)
  To: openrisc

Hi Joel,


On Tue, Sep 18, 2018 at 2:07 PM, Joel Sherrill <joel@rtems.org> wrote:

>
>
> On Tue, Sep 18, 2018, 6:56 AM Nick Clifton <nickc@redhat.com> wrote:
>
>>
>> > As Richard mentioned we don't handle this.
>> >
>> > We have cases like this right now as well, i.e. binaries generated with
>> `l.mul`
>> > or `l.div` instructions will link fine into an executable that assume
>> those
>> > instrunctions should be emulated.  That doesn't throw an error and I
>> don't think
>> > it has been a problem.
>>
>> OK, well it is your target, so if you are OK with this then so be it.
>> I would recommend however thinking about a solution for the future,
>> should the
>> openRISC architecture gain more variants.  My suggestion would be to make
>> use
>> of ELF notes, as has been done with other ports.
>>
>
> Is there a way to avoid these instructions with GCC? As a general rule,
> for RTEMS we assume the code is properly generated for the target CPU and
> don't emulate missing instructions.
>
> Also for these cases, is there a flag implicitly set by GCC based on CPU
> specific flags to let assembly code.know not to use them.
>
> And are there mulilibs which do and do not use them?
>

To answer all, yes.  There were some recent openrisc mailing list
discussions on this. I have decided to add a new multilib flag -mclass1
-mclass2 (default is mclass1 instructions only) to  stop gcc from using any
class2 instructions.


> In the deeply embedded space, we assume the tools and user can generate
> code which doesn't need emulation traps. There is some responsibility on
> the toolchain to.make it possible.
>

Yes, We did think about this when we were writing the new port, but we are
only just implementing it now.  Check the GCC docs in the next patch
version I submit.

-Stafford
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.librecores.org/pipermail/openrisc/attachments/20180921/c56779cd/attachment.html>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-18 11:55       ` Nick Clifton
  2018-09-18 12:07         ` Joel Sherrill
  2018-09-19 13:23         ` Stafford Horne
@ 2018-09-27  6:07         ` Stafford Horne
  2018-09-28 15:39           ` Nick Clifton
  2 siblings, 1 reply; 16+ messages in thread
From: Stafford Horne @ 2018-09-27  6:07 UTC (permalink / raw)
  To: openrisc

Hi Nick,

On Tue, Sep 18, 2018 at 12:55:48PM +0100, Nick Clifton wrote:
> One other thing:  There are several places where you add calls to 
> abort().  Now this is not wrong, and certainly not a reason to 
> reject the patch, but I consider it to be unhelpful.  To my mind
> a library, or tool, should generate an error message when something
> goes wrong and not leave the user wondering why they have suddenly
> got a segmentation fault.
> 
> Plus if you have a call to abort() in the code you can bet that some 
> enterprising person with a binary fuzzer will find a way to trigger 
> it, and then file a CVE about it.  (Fixing CVEs is the bane of my 
> life as they involve lots of extra administrivia).

I have been away the last week and am just getting to fixing these abort()'s
now.  However, I have a question.

The aborts I see are:

  bfd/elf32-or1k.c (or1k_final_link_relocate) - 2 places
  cpu/or1k-asm.c (parse_imm16) - 1 place

In these cases we call abort if a switch statement falls through to the default
case. If we get an abort its definitely a bug.

To produce these errors I need to change the code, Using abort we see:

   /home/shorne/work/gnu-toolchain/local/lib/gcc/or1k-elf/9.0.0/../../../../or1k-elf/bin/ld: \
      BFD (GNU Binutils) 2.31.51.20180927 internal error, \
      aborting at ../../binutils-gdb/bfd/elf32-or1k.c:1152 in or1k_final_link_relocate

   /home/shorne/work/gnu-toolchain/local/lib/gcc/or1k-elf/9.0.0/../../../../or1k-elf/bin/ld: \
      Please report this bug.

   collect2: error: ld returned 1 exit status

There is no segmentation fault.  I agree, it is more nice to create a message
inform which error triggered the issue.

Is something like this ok?

    default:
      _bfd_error_handler
	(_("%pB: Unknown complain on overflow value on howto specified %d"),
	 input_bfd, (int) howto->complain_on_overflow);
      abort();

i.e. _bfd_error_handler() followed by abort().  I couldn't really see a way to
_bfd_error_handler() to actually cause the program to exit.

-Stafford

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-27  6:07         ` Stafford Horne
@ 2018-09-28 15:39           ` Nick Clifton
  2018-10-01  7:08             ` Stafford Horne
  0 siblings, 1 reply; 16+ messages in thread
From: Nick Clifton @ 2018-09-28 15:39 UTC (permalink / raw)
  To: openrisc

Hi Stafford,

> To produce these errors I need to change the code, Using abort we see:
> 
>    /home/shorne/work/gnu-toolchain/local/lib/gcc/or1k-elf/9.0.0/../../../../or1k-elf/bin/ld: \
>       BFD (GNU Binutils) 2.31.51.20180927 internal error, \
>       aborting at ../../binutils-gdb/bfd/elf32-or1k.c:1152 in or1k_final_link_relocate

> There is no segmentation fault.

Sorry, you are right - the abort does not trigger a segmentation fault.



> I agree, it is more nice to create a message
> inform which error triggered the issue.
> 
> Is something like this ok?
> 
>     default:
>       _bfd_error_handler
> 	(_("%pB: Unknown complain on overflow value on howto specified %d"),
> 	 input_bfd, (int) howto->complain_on_overflow);
>       abort();
> 
> i.e. _bfd_error_handler() followed by abort().  I couldn't really see a way to
> _bfd_error_handler() to actually cause the program to exit.

Depending upon where you are in your code, if you have access to the link_info
structure you can use its einfo() routine instead of bfd_error_handler.  This
has the advantage that it allows a %X formatting directive, which causes the 
program to terminate with an error exit code.

But otherwise, if there is no reasonable way to return to the caller, then
caryr on using abort.  Adding the error messages still helps though.

Cheers
  Nick



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs
  2018-09-28 15:39           ` Nick Clifton
@ 2018-10-01  7:08             ` Stafford Horne
  0 siblings, 0 replies; 16+ messages in thread
From: Stafford Horne @ 2018-10-01  7:08 UTC (permalink / raw)
  To: openrisc

On Fri, Sep 28, 2018 at 04:39:03PM +0100, Nick Clifton wrote:
> 
> > To produce these errors I need to change the code, Using abort we see:
> > 
> >    /home/shorne/work/gnu-toolchain/local/lib/gcc/or1k-elf/9.0.0/../../../../or1k-elf/bin/ld: \
> >       BFD (GNU Binutils) 2.31.51.20180927 internal error, \
> >       aborting at ../../binutils-gdb/bfd/elf32-or1k.c:1152 in or1k_final_link_relocate
> 
[...] 
> Depending upon where you are in your code, if you have access to the link_info
> structure you can use its einfo() routine instead of bfd_error_handler.  This
> has the advantage that it allows a %X formatting directive, which causes the 
> program to terminate with an error exit code.

OK, thanks for the info.  I tested it out using einfo(), it does exit with an
error code, but it doesn't produce the line numbers and function name that
abort() gives us.  I am sure I could make it do it, but for now I will use the
error message + abort() as it gives me what I would want to see in a bug report
:).

V2 of the patch should be coming up soon.

-Stafford


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2018-10-01  7:08 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-21 14:38 [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
2018-08-21 14:38 ` [OpenRISC] [PATCH 1/4] or1k: Add relocations for high-signed and low-stores Stafford Horne
2018-08-21 14:38 ` [OpenRISC] [PATCH 2/4] or1k: Fix messages for relocations in shared libraries Stafford Horne
2018-08-21 14:38 ` [OpenRISC] [PATCH 3/4] or1k: Add the l.adrp insn and supporting relocations Stafford Horne
2018-08-21 14:38 ` [OpenRISC] [PATCH 4/4] or1k: Add the l.muld, l.muldu, l.macu, l.msbu insns Stafford Horne
2018-09-08 21:35 ` [OpenRISC] [PATCH 0/4] OpenRISC binutils updates and new relocs Stafford Horne
2018-09-17 15:07   ` Nick Clifton
2018-09-17 16:29     ` Richard Henderson
2018-09-18  9:52     ` Stafford Horne
2018-09-18 11:55       ` Nick Clifton
2018-09-18 12:07         ` Joel Sherrill
2018-09-21 12:40           ` Stafford Horne
2018-09-19 13:23         ` Stafford Horne
2018-09-27  6:07         ` Stafford Horne
2018-09-28 15:39           ` Nick Clifton
2018-10-01  7:08             ` Stafford Horne

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.