All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PULL 00/26] New hppa-linux target support
@ 2017-01-23  2:17 Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 01/26] Revert "Remove remainders of HPPA backend" Richard Henderson
                   ` (25 more replies)
  0 siblings, 26 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

This is a linux-user only port, emulating a 32-bit only version of a
pa-2.0 cpu.  This is good enough to do well with both the gcc and glibc
testsuites.  Helge Deller has provided invaluable assistance testing 
with a more complete debian chroot.

What's missing:
  * Space registers.  Since Linux sets them all equal (for a flat
    address space) and uses them like address-space identifiers,
    we can simply set them all to 0 and ignore them.

  * Architecture subsets.  There's no markup for running a pure pa1.0
    or pa1.1 cpu.  I happily accept everything up to pa2.0 at the moment.

  * Wide mode.  While I have pa2.0 instructions, I don't support running
    in 64-bit mode.  Since neither the linux kernel nor glibc support a
    64-bit userland, it would be a lot more work than just adding the insns.

  * Multimedia instructions.  These are tied to wide mode, so...

When squashing the patches down from my development tree, I wanted to
preserve Helge's contributions, so the linux-user part is more patches
than I would normally have preserved.


r~



The following changes since commit d1c82f7cc34443841095f490345f86c9d8baca34:

  Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170120-v2' into staging (2017-01-20 15:53:58 +0000)

are available in the git repository at:

  git://github.com/rth7680/qemu.git tags/pull-hppa-20170122

for you to fetch changes up to 0ce588d6c60c338c0856b0dac78d19fc7e698477:

  target-hppa: Implement floating-point insns (2017-01-22 18:14:12 -0800)

----------------------------------------------------------------
hppa-linux target support

----------------------------------------------------------------
Helge Deller (3):
      linux-user: Handle TIOCSTART and TIOCSTOP
      linux-user: Add SIOCGPGRP, SIOCGSTAMP, SIOCGSTAMPNS
      linux-user: Add some hppa ioctls

Richard Henderson (23):
      Revert "Remove remainders of HPPA backend"
      linux-user: Support stack-grows-up in elfload.c
      linux-user: Handle ERFKILL and EHWPOISON
      linux-user: Handle more IPV6 sockopts
      linux-user: Add HPPA socket.h definitions
      linux-user: Add HPPA syscall numbers
      linux-user: Add HPPA termbits.h
      linux-user: Add HPPA target_syscall.h
      linux-user: Add HPPA definitions to syscall_defs.h
      linux-user: Add HPPA target_structs.h
      linux-user: Add HPPA target_signal.h and target_cpu.h
      linux-user: Add HPPA signal handling
      linux-user: Add HPPA startup and main loop
      target-hppa: Add softfloat specializations
      target-hppa: Add framework and enable compilation
      target-hppa: Add nullification framework
      target-hppa: Implement basic arithmetic
      target-hppa: Implement branches
      target-hppa: Implement linux-user gateway page
      target-hppa: Implement shifts and deposits
      target-hppa: Implement loads and stores
      target-hppa: Implement system and memory-management insns
      target-hppa: Implement floating-point insns

 MAINTAINERS                         |    6 +
 configure                           |    7 +-
 default-configs/hppa-linux-user.mak |    1 +
 disas.c                             |    2 +
 disas/Makefile.objs                 |    1 +
 disas/hppa.c                        | 2832 +++++++++++++++++++++++++
 fpu/softfloat-specialize.h          |   20 +-
 linux-user/alpha/target_syscall.h   |    2 +
 linux-user/elfload.c                |  259 ++-
 linux-user/errno_defs.h             |    3 +
 linux-user/hppa/sockbits.h          |   97 +
 linux-user/hppa/syscall_nr.h        |  353 ++++
 linux-user/hppa/target_cpu.h        |   35 +
 linux-user/hppa/target_signal.h     |   29 +
 linux-user/hppa/target_structs.h    |   54 +
 linux-user/hppa/target_syscall.h    |  237 +++
 linux-user/hppa/termbits.h          |  219 ++
 linux-user/ioctls.h                 |    8 +
 linux-user/main.c                   |  185 +-
 linux-user/mips/target_syscall.h    |    5 +
 linux-user/mips64/target_syscall.h  |    5 +
 linux-user/qemu.h                   |    3 +
 linux-user/signal.c                 |  191 +-
 linux-user/socket.h                 |    2 +
 linux-user/syscall.c                |   41 +-
 linux-user/syscall_defs.h           |  154 +-
 linux-user/syscall_types.h          |    6 +
 target/hppa/Makefile.objs           |    1 +
 target/hppa/cpu-qom.h               |   52 +
 target/hppa/cpu.c                   |  164 ++
 target/hppa/cpu.h                   |  144 ++
 target/hppa/gdbstub.c               |  111 +
 target/hppa/helper.c                |  137 ++
 target/hppa/helper.h                |   66 +
 target/hppa/op_helper.c             |  570 +++++
 target/hppa/translate.c             | 3946 +++++++++++++++++++++++++++++++++++
 36 files changed, 9869 insertions(+), 79 deletions(-)
 create mode 100644 default-configs/hppa-linux-user.mak
 create mode 100644 disas/hppa.c
 create mode 100644 linux-user/hppa/sockbits.h
 create mode 100644 linux-user/hppa/syscall_nr.h
 create mode 100644 linux-user/hppa/target_cpu.h
 create mode 100644 linux-user/hppa/target_signal.h
 create mode 100644 linux-user/hppa/target_structs.h
 create mode 100644 linux-user/hppa/target_syscall.h
 create mode 100644 linux-user/hppa/termbits.h
 create mode 100644 target/hppa/Makefile.objs
 create mode 100644 target/hppa/cpu-qom.h
 create mode 100644 target/hppa/cpu.c
 create mode 100644 target/hppa/cpu.h
 create mode 100644 target/hppa/gdbstub.c
 create mode 100644 target/hppa/helper.c
 create mode 100644 target/hppa/helper.h
 create mode 100644 target/hppa/op_helper.c
 create mode 100644 target/hppa/translate.c

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

* [Qemu-devel] [PULL 01/26] Revert "Remove remainders of HPPA backend"
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c Richard Henderson
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

This reverts commit d41f3c3cc7a5fb9de144cc4022da14a9ff010671.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 configure                 |    5 +
 disas.c                   |    2 +
 disas/Makefile.objs       |    1 +
 disas/hppa.c              | 2832 +++++++++++++++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h |    4 +-
 5 files changed, 2842 insertions(+), 2 deletions(-)
 create mode 100644 disas/hppa.c

diff --git a/configure b/configure
index 17d52cd..494c9cc 100755
--- a/configure
+++ b/configure
@@ -510,6 +510,8 @@ elif check_define __arm__ ; then
   cpu="arm"
 elif check_define __aarch64__ ; then
   cpu="aarch64"
+elif check_define __hppa__ ; then
+  cpu="hppa"
 else
   cpu=$(uname -m)
 fi
@@ -6107,6 +6109,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
   cris)
     disas_config "CRIS"
   ;;
+  hppa)
+    disas_config "HPPA"
+  ;;
   i386|x86_64|x32)
     disas_config "I386"
   ;;
diff --git a/disas.c b/disas.c
index 67f116a..05a7a12 100644
--- a/disas.c
+++ b/disas.c
@@ -310,6 +310,8 @@ void disas(FILE *out, void *code, unsigned long size)
     print_insn = print_insn_m68k;
 #elif defined(__s390__)
     print_insn = print_insn_s390;
+#elif defined(__hppa__)
+    print_insn = print_insn_hppa;
 #elif defined(__ia64__)
     print_insn = print_insn_ia64;
 #endif
diff --git a/disas/Makefile.objs b/disas/Makefile.objs
index 09bc992..abeba84 100644
--- a/disas/Makefile.objs
+++ b/disas/Makefile.objs
@@ -9,6 +9,7 @@ libvixldir = $(SRC_PATH)/disas/libvixl
 # versions do not.
 arm-a64.o-cflags := -I$(libvixldir) -Wno-sign-compare
 common-obj-$(CONFIG_CRIS_DIS) += cris.o
+common-obj-$(CONFIG_HPPA_DIS) += hppa.o
 common-obj-$(CONFIG_I386_DIS) += i386.o
 common-obj-$(CONFIG_IA64_DIS) += ia64.o
 common-obj-$(CONFIG_M68K_DIS) += m68k.o
diff --git a/disas/hppa.c b/disas/hppa.c
new file mode 100644
index 0000000..43facdc
--- /dev/null
+++ b/disas/hppa.c
@@ -0,0 +1,2832 @@
+/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
+   Copyright 1989, 1990, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2003,
+   2005 Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs@cs.utah.edu).
+
+   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 2 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, see <http://www.gnu.org/licenses/>. */
+
+#include "qemu/osdep.h"
+#include "disas/bfd.h"
+
+/* HP PA-RISC SOM object file format:  definitions internal to BFD.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2003 Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs@cs.utah.edu).
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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 2 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBHPPA_H
+#define _LIBHPPA_H
+
+#define BYTES_IN_WORD 4
+#define PA_PAGESIZE 0x1000
+
+/* The PA instruction set variants.  */
+enum pa_arch {pa10 = 10, pa11 = 11, pa20 = 20, pa20w = 25};
+
+/* HP PA-RISC relocation types */
+
+enum hppa_reloc_field_selector_type
+  {
+    R_HPPA_FSEL = 0x0,
+    R_HPPA_LSSEL = 0x1,
+    R_HPPA_RSSEL = 0x2,
+    R_HPPA_LSEL = 0x3,
+    R_HPPA_RSEL = 0x4,
+    R_HPPA_LDSEL = 0x5,
+    R_HPPA_RDSEL = 0x6,
+    R_HPPA_LRSEL = 0x7,
+    R_HPPA_RRSEL = 0x8,
+    R_HPPA_NSEL  = 0x9,
+    R_HPPA_NLSEL  = 0xa,
+    R_HPPA_NLRSEL  = 0xb,
+    R_HPPA_PSEL = 0xc,
+    R_HPPA_LPSEL = 0xd,
+    R_HPPA_RPSEL = 0xe,
+    R_HPPA_TSEL = 0xf,
+    R_HPPA_LTSEL = 0x10,
+    R_HPPA_RTSEL = 0x11,
+    R_HPPA_LTPSEL = 0x12,
+    R_HPPA_RTPSEL = 0x13
+  };
+
+/* /usr/include/reloc.h defines these to constants.  We want to use
+   them in enums, so #undef them before we start using them.  We might
+   be able to fix this another way by simply managing not to include
+   /usr/include/reloc.h, but currently GDB picks up these defines
+   somewhere.  */
+#undef e_fsel
+#undef e_lssel
+#undef e_rssel
+#undef e_lsel
+#undef e_rsel
+#undef e_ldsel
+#undef e_rdsel
+#undef e_lrsel
+#undef e_rrsel
+#undef e_nsel
+#undef e_nlsel
+#undef e_nlrsel
+#undef e_psel
+#undef e_lpsel
+#undef e_rpsel
+#undef e_tsel
+#undef e_ltsel
+#undef e_rtsel
+#undef e_one
+#undef e_two
+#undef e_pcrel
+#undef e_con
+#undef e_plabel
+#undef e_abs
+
+/* for compatibility */
+enum hppa_reloc_field_selector_type_alt
+  {
+    e_fsel = R_HPPA_FSEL,
+    e_lssel = R_HPPA_LSSEL,
+    e_rssel = R_HPPA_RSSEL,
+    e_lsel = R_HPPA_LSEL,
+    e_rsel = R_HPPA_RSEL,
+    e_ldsel = R_HPPA_LDSEL,
+    e_rdsel = R_HPPA_RDSEL,
+    e_lrsel = R_HPPA_LRSEL,
+    e_rrsel = R_HPPA_RRSEL,
+    e_nsel = R_HPPA_NSEL,
+    e_nlsel = R_HPPA_NLSEL,
+    e_nlrsel = R_HPPA_NLRSEL,
+    e_psel = R_HPPA_PSEL,
+    e_lpsel = R_HPPA_LPSEL,
+    e_rpsel = R_HPPA_RPSEL,
+    e_tsel = R_HPPA_TSEL,
+    e_ltsel = R_HPPA_LTSEL,
+    e_rtsel = R_HPPA_RTSEL,
+    e_ltpsel = R_HPPA_LTPSEL,
+    e_rtpsel = R_HPPA_RTPSEL
+  };
+
+enum hppa_reloc_expr_type
+  {
+    R_HPPA_E_ONE = 0,
+    R_HPPA_E_TWO = 1,
+    R_HPPA_E_PCREL = 2,
+    R_HPPA_E_CON = 3,
+    R_HPPA_E_PLABEL = 7,
+    R_HPPA_E_ABS = 18
+  };
+
+/* for compatibility */
+enum hppa_reloc_expr_type_alt
+  {
+    e_one = R_HPPA_E_ONE,
+    e_two = R_HPPA_E_TWO,
+    e_pcrel = R_HPPA_E_PCREL,
+    e_con = R_HPPA_E_CON,
+    e_plabel = R_HPPA_E_PLABEL,
+    e_abs = R_HPPA_E_ABS
+  };
+
+
+/* Relocations for function calls must be accompanied by parameter
+   relocation bits.  These bits describe exactly where the caller has
+   placed the function's arguments and where it expects to find a return
+   value.
+
+   Both ELF and SOM encode this information within the addend field
+   of the call relocation.  (Note this could break very badly if one
+   was to make a call like bl foo + 0x12345678).
+
+   The high order 10 bits contain parameter relocation information,
+   the low order 22 bits contain the constant offset.  */
+
+#define HPPA_R_ARG_RELOC(a)	\
+  (((a) >> 22) & 0x3ff)
+#define HPPA_R_CONSTANT(a)	\
+  ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE-22)) >> (BFD_ARCH_SIZE-22))
+#define HPPA_R_ADDEND(r, c)	\
+  (((r) << 22) + ((c) & 0x3fffff))
+
+
+/* Some functions to manipulate PA instructions.  */
+
+/* Declare the functions with the unused attribute to avoid warnings.  */
+static inline int sign_extend (int, int) ATTRIBUTE_UNUSED;
+static inline int low_sign_extend (int, int) ATTRIBUTE_UNUSED;
+static inline int sign_unext (int, int) ATTRIBUTE_UNUSED;
+static inline int low_sign_unext (int, int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_3 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_12 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_14 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_16 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_17 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_21 (int) ATTRIBUTE_UNUSED;
+static inline int re_assemble_22 (int) ATTRIBUTE_UNUSED;
+static inline bfd_signed_vma hppa_field_adjust
+  (bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt)
+  ATTRIBUTE_UNUSED;
+static inline int hppa_rebuild_insn (int, int, int) ATTRIBUTE_UNUSED;
+
+
+/* The *sign_extend functions are used to assemble various bitfields
+   taken from an instruction and return the resulting immediate
+   value.  */
+
+static inline int
+sign_extend (int x, int len)
+{
+  int signbit = (1 << (len - 1));
+  int mask = (signbit << 1) - 1;
+  return ((x & mask) ^ signbit) - signbit;
+}
+
+static inline int
+low_sign_extend (int x, int len)
+{
+  return (x >> 1) - ((x & 1) << (len - 1));
+}
+
+
+/* The re_assemble_* functions prepare an immediate value for
+   insertion into an opcode. pa-risc uses all sorts of weird bitfields
+   in the instruction to hold the value.  */
+
+static inline int
+sign_unext (int x, int len)
+{
+  int len_ones;
+
+  len_ones = (1 << len) - 1;
+
+  return x & len_ones;
+}
+
+static inline int
+low_sign_unext (int x, int len)
+{
+  int temp;
+  int sign;
+
+  sign = (x >> (len-1)) & 1;
+
+  temp = sign_unext (x, len-1);
+
+  return (temp << 1) | sign;
+}
+
+static inline int
+re_assemble_3 (int as3)
+{
+  return ((  (as3 & 4) << (13-2))
+	  | ((as3 & 3) << (13+1)));
+}
+
+static inline int
+re_assemble_12 (int as12)
+{
+  return ((  (as12 & 0x800) >> 11)
+	  | ((as12 & 0x400) >> (10 - 2))
+	  | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_14 (int as14)
+{
+  return ((  (as14 & 0x1fff) << 1)
+	  | ((as14 & 0x2000) >> 13));
+}
+
+static inline int
+re_assemble_16 (int as16)
+{
+  int s, t;
+
+  /* Unusual 16-bit encoding, for wide mode only.  */
+  t = (as16 << 1) & 0xffff;
+  s = (as16 & 0x8000);
+  return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+static inline int
+re_assemble_17 (int as17)
+{
+  return ((  (as17 & 0x10000) >> 16)
+	  | ((as17 & 0x0f800) << (16 - 11))
+	  | ((as17 & 0x00400) >> (10 - 2))
+	  | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_21 (int as21)
+{
+  return ((  (as21 & 0x100000) >> 20)
+	  | ((as21 & 0x0ffe00) >> 8)
+	  | ((as21 & 0x000180) << 7)
+	  | ((as21 & 0x00007c) << 14)
+	  | ((as21 & 0x000003) << 12));
+}
+
+static inline int
+re_assemble_22 (int as22)
+{
+  return ((  (as22 & 0x200000) >> 21)
+	  | ((as22 & 0x1f0000) << (21 - 16))
+	  | ((as22 & 0x00f800) << (16 - 11))
+	  | ((as22 & 0x000400) >> (10 - 2))
+	  | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+
+/* Handle field selectors for PA instructions.
+   The L and R (and LS, RS etc.) selectors are used in pairs to form a
+   full 32 bit address.  eg.
+
+   LDIL	L'start,%r1		; put left part into r1
+   LDW	R'start(%r1),%r2	; add r1 and right part to form address
+
+   This function returns sign extended values in all cases.
+*/
+
+static inline bfd_signed_vma
+hppa_field_adjust (bfd_vma sym_val,
+		   bfd_signed_vma addend,
+		   enum hppa_reloc_field_selector_type_alt r_field)
+{
+  bfd_signed_vma value;
+
+  value = sym_val + addend;
+  switch (r_field)
+    {
+    case e_fsel:
+      /* F: No change.  */
+      break;
+
+    case e_nsel:
+      /* N: null selector.  I don't really understand what this is all
+	 about, but HP's documentation says "this indicates that zero
+	 bits are to be used for the displacement on the instruction.
+	 This fixup is used to identify three-instruction sequences to
+	 access data (for importing shared library data)."  */
+      value = 0;
+      break;
+
+    case e_lsel:
+    case e_nlsel:
+      /* L:  Select top 21 bits.  */
+      value = value >> 11;
+      break;
+
+    case e_rsel:
+      /* R:  Select bottom 11 bits.  */
+      value = value & 0x7ff;
+      break;
+
+    case e_lssel:
+      /* LS:  Round to nearest multiple of 2048 then select top 21 bits.  */
+      value = value + 0x400;
+      value = value >> 11;
+      break;
+
+    case e_rssel:
+      /* RS:  Select bottom 11 bits for LS.
+	 We need to return a value such that 2048 * LS'x + RS'x == x.
+	 ie. RS'x = x - ((x + 0x400) & -0x800)
+	 this is just a sign extension from bit 21.  */
+      value = ((value & 0x7ff) ^ 0x400) - 0x400;
+      break;
+
+    case e_ldsel:
+      /* LD:  Round to next multiple of 2048 then select top 21 bits.
+	 Yes, if we are already on a multiple of 2048, we go up to the
+	 next one.  RD in this case will be -2048.  */
+      value = value + 0x800;
+      value = value >> 11;
+      break;
+
+    case e_rdsel:
+      /* RD:  Set bits 0-20 to one.  */
+      value = value | -0x800;
+      break;
+
+    case e_lrsel:
+    case e_nlrsel:
+      /* LR:  L with rounding of the addend to nearest 8k.  */
+      value = sym_val + ((addend + 0x1000) & -0x2000);
+      value = value >> 11;
+      break;
+
+    case e_rrsel:
+      /* RR:  R with rounding of the addend to nearest 8k.
+	 We need to return a value such that 2048 * LR'x + RR'x == x
+	 ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800))
+	 .	  = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000))
+	 .	  = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000)  */
+      value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000);
+      break;
+
+    default:
+      abort ();
+    }
+  return value;
+}
+
+/* PA-RISC OPCODES */
+#define get_opcode(insn)	(((insn) >> 26) & 0x3f)
+
+enum hppa_opcode_type
+{
+  /* None of the opcodes in the first group generate relocs, so we
+     aren't too concerned about them.  */
+  OP_SYSOP   = 0x00,
+  OP_MEMMNG  = 0x01,
+  OP_ALU     = 0x02,
+  OP_NDXMEM  = 0x03,
+  OP_SPOP    = 0x04,
+  OP_DIAG    = 0x05,
+  OP_FMPYADD = 0x06,
+  OP_UNDEF07 = 0x07,
+  OP_COPRW   = 0x09,
+  OP_COPRDW  = 0x0b,
+  OP_COPR    = 0x0c,
+  OP_FLOAT   = 0x0e,
+  OP_PRDSPEC = 0x0f,
+  OP_UNDEF15 = 0x15,
+  OP_UNDEF1d = 0x1d,
+  OP_FMPYSUB = 0x26,
+  OP_FPFUSED = 0x2e,
+  OP_SHEXDP0 = 0x34,
+  OP_SHEXDP1 = 0x35,
+  OP_SHEXDP2 = 0x36,
+  OP_UNDEF37 = 0x37,
+  OP_SHEXDP3 = 0x3c,
+  OP_SHEXDP4 = 0x3d,
+  OP_MULTMED = 0x3e,
+  OP_UNDEF3f = 0x3f,
+
+  OP_LDIL    = 0x08,
+  OP_ADDIL   = 0x0a,
+
+  OP_LDO     = 0x0d,
+  OP_LDB     = 0x10,
+  OP_LDH     = 0x11,
+  OP_LDW     = 0x12,
+  OP_LDWM    = 0x13,
+  OP_STB     = 0x18,
+  OP_STH     = 0x19,
+  OP_STW     = 0x1a,
+  OP_STWM    = 0x1b,
+
+  OP_LDD     = 0x14,
+  OP_STD     = 0x1c,
+
+  OP_FLDW    = 0x16,
+  OP_LDWL    = 0x17,
+  OP_FSTW    = 0x1e,
+  OP_STWL    = 0x1f,
+
+  OP_COMBT   = 0x20,
+  OP_COMIBT  = 0x21,
+  OP_COMBF   = 0x22,
+  OP_COMIBF  = 0x23,
+  OP_CMPBDT  = 0x27,
+  OP_ADDBT   = 0x28,
+  OP_ADDIBT  = 0x29,
+  OP_ADDBF   = 0x2a,
+  OP_ADDIBF  = 0x2b,
+  OP_CMPBDF  = 0x2f,
+  OP_BVB     = 0x30,
+  OP_BB      = 0x31,
+  OP_MOVB    = 0x32,
+  OP_MOVIB   = 0x33,
+  OP_CMPIBD  = 0x3b,
+
+  OP_COMICLR = 0x24,
+  OP_SUBI    = 0x25,
+  OP_ADDIT   = 0x2c,
+  OP_ADDI    = 0x2d,
+
+  OP_BE      = 0x38,
+  OP_BLE     = 0x39,
+  OP_BL      = 0x3a
+};
+
+
+/* Insert VALUE into INSN using R_FORMAT to determine exactly what
+   bits to change.  */
+
+static inline int
+hppa_rebuild_insn (int insn, int value, int r_format)
+{
+  switch (r_format)
+    {
+    case 11:
+      return (insn & ~ 0x7ff) | low_sign_unext (value, 11);
+
+    case 12:
+      return (insn & ~ 0x1ffd) | re_assemble_12 (value);
+
+
+    case 10:
+      return (insn & ~ 0x3ff1) | re_assemble_14 (value & -8);
+
+    case -11:
+      return (insn & ~ 0x3ff9) | re_assemble_14 (value & -4);
+
+    case 14:
+      return (insn & ~ 0x3fff) | re_assemble_14 (value);
+
+
+    case -10:
+      return (insn & ~ 0xfff1) | re_assemble_16 (value & -8);
+
+    case -16:
+      return (insn & ~ 0xfff9) | re_assemble_16 (value & -4);
+
+    case 16:
+      return (insn & ~ 0xffff) | re_assemble_16 (value);
+
+
+    case 17:
+      return (insn & ~ 0x1f1ffd) | re_assemble_17 (value);
+
+    case 21:
+      return (insn & ~ 0x1fffff) | re_assemble_21 (value);
+
+    case 22:
+      return (insn & ~ 0x3ff1ffd) | re_assemble_22 (value);
+
+    case 32:
+      return value;
+
+    default:
+      abort ();
+    }
+  return insn;
+}
+
+#endif /* _LIBHPPA_H */
+/* Table of opcodes for the PA-RISC.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   Contributed by the Center for Software Science at the
+   University of Utah (pa-gdb-bugs@cs.utah.edu).
+
+This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler.
+
+GAS/GDB 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 1, or (at your option)
+any later version.
+
+GAS/GDB 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 GAS or GDB; see the file COPYING.
+If not, see <http://www.gnu.org/licenses/>. */
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif
+
+/*
+ * Structure of an opcode table entry.
+ */
+
+/* There are two kinds of delay slot nullification: normal which is
+ * controlled by the nullification bit, and conditional, which depends
+ * on the direction of the branch and its success or failure.
+ *
+ * NONE is unfortunately #defined in the hiux system include files.
+ * #undef it away.
+ */
+#undef NONE
+struct pa_opcode
+{
+    const char *name;
+    unsigned long int match;	/* Bits that must be set...  */
+    unsigned long int mask;	/* ... in these bits. */
+    const char *args;
+    enum pa_arch arch;
+    char flags;
+};
+
+/* Enables strict matching.  Opcodes with match errors are skipped
+   when this bit is set.  */
+#define FLAG_STRICT 0x1
+
+/*
+   All hppa opcodes are 32 bits.
+
+   The match component is a mask saying which bits must match a
+   particular opcode in order for an instruction to be an instance
+   of that opcode.
+
+   The args component is a string containing one character for each operand of
+   the instruction.  Characters used as a prefix allow any second character to
+   be used without conflicting with the main operand characters.
+
+   Bit positions in this description follow HP usage of lsb = 31,
+   "at" is lsb of field.
+
+   In the args field, the following characters must match exactly:
+
+	'+,() '
+
+   In the args field, the following characters are unused:
+
+	'  "         -  /   34 6789:;    '
+	'@  C         M             [\]  '
+	'`    e g                     }  '
+
+   Here are all the characters:
+
+	' !"#$%&'()*+-,./0123456789:;<=>?'
+	'@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'
+	'`abcdefghijklmnopqrstuvwxyz{|}~ '
+
+Kinds of operands:
+   x    integer register field at 15.
+   b    integer register field at 10.
+   t    integer register field at 31.
+   a	integer register field at 10 and 15 (for PERMH)
+   5    5 bit immediate at 15.
+   s    2 bit space specifier at 17.
+   S    3 bit space specifier at 18.
+   V    5 bit immediate value at 31
+   i    11 bit immediate value at 31
+   j    14 bit immediate value at 31
+   k    21 bit immediate value at 31
+   l    16 bit immediate value at 31 (wide mode only, unusual encoding).
+   n	nullification for branch instructions
+   N	nullification for spop and copr instructions
+   w    12 bit branch displacement
+   W    17 bit branch displacement (PC relative)
+   X    22 bit branch displacement (PC relative)
+   z    17 bit branch displacement (just a number, not an address)
+
+Also these:
+
+   .    2 bit shift amount at 25
+   *    4 bit shift amount at 25
+   p    5 bit shift count at 26 (to support the SHD instruction) encoded as
+        31-p
+   ~    6 bit shift count at 20,22:26 encoded as 63-~.
+   P    5 bit bit position at 26
+   q    6 bit bit position at 20,22:26
+   T    5 bit field length at 31 (encoded as 32-T)
+   %	6 bit field length at 23,27:31 (variable extract/deposit)
+   |	6 bit field length at 19,27:31 (fixed extract/deposit)
+   A    13 bit immediate at 18 (to support the BREAK instruction)
+   ^	like b, but describes a control register
+   !    sar (cr11) register
+   D    26 bit immediate at 31 (to support the DIAG instruction)
+   $    9 bit immediate at 28 (to support POPBTS)
+
+   v    3 bit Special Function Unit identifier at 25
+   O    20 bit Special Function Unit operation split between 15 bits at 20
+        and 5 bits at 31
+   o    15 bit Special Function Unit operation at 20
+   2    22 bit Special Function Unit operation split between 17 bits at 20
+        and 5 bits at 31
+   1    15 bit Special Function Unit operation split between 10 bits at 20
+        and 5 bits at 31
+   0    10 bit Special Function Unit operation split between 5 bits at 20
+        and 5 bits at 31
+   u    3 bit coprocessor unit identifier at 25
+   F    Source Floating Point Operand Format Completer encoded 2 bits at 20
+   I    Source Floating Point Operand Format Completer encoded 1 bits at 20
+	(for 0xe format FP instructions)
+   G    Destination Floating Point Operand Format Completer encoded 2 bits at 18
+   H    Floating Point Operand Format at 26 for 'fmpyadd' and 'fmpysub'
+        (very similar to 'F')
+
+   r	5 bit immediate value at 31 (for the break instruction)
+	(very similar to V above, except the value is unsigned instead of
+	low_sign_ext)
+   R	5 bit immediate value at 15 (for the ssm, rsm, probei instructions)
+	(same as r above, except the value is in a different location)
+   U	10 bit immediate value at 15 (for SSM, RSM on pa2.0)
+   Q	5 bit immediate value at 10 (a bit position specified in
+	the bb instruction. It's the same as r above, except the
+        value is in a different location)
+   B	5 bit immediate value at 10 (a bit position specified in
+	the bb instruction. Similar to Q, but 64 bit handling is
+	different.
+   Z    %r1 -- implicit target of addil instruction.
+   L    ,%r2 completer for new syntax branch
+   {    Source format completer for fcnv
+   _    Destination format completer for fcnv
+   h    cbit for fcmp
+   =    gfx tests for ftest
+   d    14 bit offset for single precision FP long load/store.
+   #    14 bit offset for double precision FP load long/store.
+   J    Yet another 14 bit offset for load/store with ma,mb completers.
+   K    Yet another 14 bit offset for load/store with ma,mb completers.
+   y    16 bit offset for word aligned load/store (PA2.0 wide).
+   &    16 bit offset for dword aligned load/store (PA2.0 wide).
+   <    16 bit offset for load/store with ma,mb completers (PA2.0 wide).
+   >    16 bit offset for load/store with ma,mb completers (PA2.0 wide).
+   Y    %sr0,%r31 -- implicit target of be,l instruction.
+   @	implicit immediate value of 0
+
+Completer operands all have 'c' as the prefix:
+
+   cx   indexed load and store completer.
+   cX   indexed load and store completer.  Like cx, but emits a space
+	after in disassembler.
+   cm   short load and store completer.
+   cM   short load and store completer.  Like cm, but emits a space
+        after in disassembler.
+   cq   long load and store completer (like cm, but inserted into a
+	different location in the target instruction).
+   cs   store bytes short completer.
+   cA   store bytes short completer.  Like cs, but emits a space
+        after in disassembler.
+   ce   long load/store completer for LDW/STW with a different encoding
+	than the others
+   cc   load cache control hint
+   cd   load and clear cache control hint
+   cC   store cache control hint
+   co	ordered access
+
+   cp	branch link and push completer
+   cP	branch pop completer
+   cl	branch link completer
+   cg	branch gate completer
+
+   cw	read/write completer for PROBE
+   cW	wide completer for MFCTL
+   cL	local processor completer for cache control
+   cZ   System Control Completer (to support LPA, LHA, etc.)
+
+   ci	correction completer for DCOR
+   ca	add completer
+   cy	32 bit add carry completer
+   cY	64 bit add carry completer
+   cv	signed overflow trap completer
+   ct	trap on condition completer for ADDI, SUB
+   cT	trap on condition completer for UADDCM
+   cb	32 bit borrow completer for SUB
+   cB	64 bit borrow completer for SUB
+
+   ch	left/right half completer
+   cH	signed/unsigned saturation completer
+   cS	signed/unsigned completer at 21
+   cz	zero/sign extension completer.
+   c*	permutation completer
+
+Condition operands all have '?' as the prefix:
+
+   ?f   Floating point compare conditions (encoded as 5 bits at 31)
+
+   ?a	add conditions
+   ?A	64 bit add conditions
+   ?@   add branch conditions followed by nullify
+   ?d	non-negated add branch conditions
+   ?D	negated add branch conditions
+   ?w	wide mode non-negated add branch conditions
+   ?W	wide mode negated add branch conditions
+
+   ?s   compare/subtract conditions
+   ?S	64 bit compare/subtract conditions
+   ?t   non-negated compare and branch conditions
+   ?n   32 bit compare and branch conditions followed by nullify
+   ?N   64 bit compare and branch conditions followed by nullify
+   ?Q	64 bit compare and branch conditions for CMPIB instruction
+
+   ?l   logical conditions
+   ?L	64 bit logical conditions
+
+   ?b   branch on bit conditions
+   ?B	64 bit branch on bit conditions
+
+   ?x   shift/extract/deposit conditions
+   ?X	64 bit shift/extract/deposit conditions
+   ?y   shift/extract/deposit conditions followed by nullify for conditional
+        branches
+
+   ?u   unit conditions
+   ?U   64 bit unit conditions
+
+Floating point registers all have 'f' as a prefix:
+
+   ft	target register at 31
+   fT	target register with L/R halves at 31
+   fa	operand 1 register at 10
+   fA   operand 1 register with L/R halves at 10
+   fX   Same as fA, except prints a space before register during disasm
+   fb	operand 2 register at 15
+   fB   operand 2 register with L/R halves at 15
+   fC   operand 3 register with L/R halves at 16:18,21:23
+   fe   Like fT, but encoding is different.
+   fE   Same as fe, except prints a space before register during disasm.
+   fx	target register at 15 (only for PA 2.0 long format FLDD/FSTD).
+
+Float registers for fmpyadd and fmpysub:
+
+   fi	mult operand 1 register at 10
+   fj	mult operand 2 register at 15
+   fk	mult target register at 20
+   fl	add/sub operand register at 25
+   fm	add/sub target register at 31
+
+*/
+
+
+#if 0
+/* List of characters not to put a space after.  Note that
+   "," is included, as the "spopN" operations use literal
+   commas in their completer sections.  */
+static const char *const completer_chars = ",CcY<>?!@+&U~FfGHINnOoZMadu|/=0123%e$m}";
+#endif
+
+/* The order of the opcodes in this table is significant:
+
+   * The assembler requires that all instances of the same mnemonic be
+     consecutive.  If they aren't, the assembler will bomb at runtime.
+
+   * Immediate fields use pa_get_absolute_expression to parse the
+     string.  It will generate a "bad expression" error if passed
+     a register name.  Thus, register index variants of an opcode
+     need to precede immediate variants.
+
+   * The disassembler does not care about the order of the opcodes
+     except in cases where implicit addressing is used.
+
+   Here are the rules for ordering the opcodes of a mnemonic:
+
+   1) Opcodes with FLAG_STRICT should precede opcodes without
+      FLAG_STRICT.
+
+   2) Opcodes with FLAG_STRICT should be ordered as follows:
+      register index opcodes, short immediate opcodes, and finally
+      long immediate opcodes.  When both pa10 and pa11 variants
+      of the same opcode are available, the pa10 opcode should
+      come first for correct architectural promotion.
+
+   3) When implicit addressing is available for an opcode, the
+      implicit opcode should precede the explicit opcode.
+
+   4) Opcodes without FLAG_STRICT should be ordered as follows:
+      register index opcodes, long immediate opcodes, and finally
+      short immediate opcodes.  */
+
+static const struct pa_opcode pa_opcodes[] =
+{
+
+/* Pseudo-instructions.  */
+
+{ "ldi",	0x34000000, 0xffe00000, "l,x", pa20w, 0},/* ldo val(r0),r */
+{ "ldi",	0x34000000, 0xffe0c000, "j,x", pa10, 0},/* ldo val(r0),r */
+
+{ "cmpib",	0xec000000, 0xfc000000, "?Qn5,b,w", pa20, FLAG_STRICT},
+{ "cmpib", 	0x84000000, 0xf4000000, "?nn5,b,w", pa10, FLAG_STRICT},
+{ "comib", 	0x84000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "comib", 	0x8c000000, 0xfc000000, "?nn5,b,w", pa10, 0}, /* comib{tf}*/
+{ "cmpb",	0x9c000000, 0xdc000000, "?Nnx,b,w", pa20, FLAG_STRICT},
+{ "cmpb",	0x80000000, 0xf4000000, "?nnx,b,w", pa10, FLAG_STRICT},
+{ "comb",	0x80000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "comb",	0x88000000, 0xfc000000, "?nnx,b,w", pa10, 0}, /* comb{tf} */
+{ "addb",	0xa0000000, 0xf4000000, "?Wnx,b,w", pa20w, FLAG_STRICT},
+{ "addb",	0xa0000000, 0xfc000000, "?@nx,b,w", pa10, 0}, /* addb{tf} */
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "addb",	0xa8000000, 0xfc000000, "?@nx,b,w", pa10, 0},
+{ "addib",	0xa4000000, 0xf4000000, "?Wn5,b,w", pa20w, FLAG_STRICT},
+{ "addib",	0xa4000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/
+/* This entry is for the disassembler only.  It will never be used by
+   assembler.  */
+{ "addib",	0xac000000, 0xfc000000, "?@n5,b,w", pa10, 0}, /* addib{tf}*/
+{ "nop",	0x08000240, 0xffffffff, "", pa10, 0},      /* or 0,0,0 */
+{ "copy",	0x08000240, 0xffe0ffe0, "x,t", pa10, 0},   /* or r,0,t */
+{ "mtsar",	0x01601840, 0xffe0ffff, "x", pa10, 0}, /* mtctl r,cr11 */
+
+/* Loads and Stores for integer registers.  */
+
+{ "ldd",	0x0c0000c0, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0000c0, 0xfc0013c0, "cxccx(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010e0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010e0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010c0, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x0c0010c0, 0xfc0013c0, "cmcc5(s,b),t", pa20, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc000002, "cq&(b),x", pa20w, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc00c002, "cq#(b),x", pa20, FLAG_STRICT},
+{ "ldd",	0x50000000, 0xfc000002, "cq#(s,b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c0010a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldw",	0x0c0010a0, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc000000, "ce<(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc000006, "ce>(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x48000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc00c006, "ceK(b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x5c000004, 0xfc000006, "ceK(s,b),x", pa20, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc00c000, "ceJ(b),x", pa10, FLAG_STRICT},
+{ "ldw",	0x4c000000, 0xfc000000, "ceJ(s,b),x", pa10, FLAG_STRICT},
+{ "ldw",	0x48000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldw",	0x48000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "ldh",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c001060, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldh",	0x0c001060, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldh",	0x44000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldh",	0x44000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldh",	0x44000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "ldb",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c001020, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldb",	0x0c001020, 0xfc1f33e0, "cocc@(s,b),t", pa20, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldb",	0x40000000, 0xfc000000, "l(b),x", pa20w, FLAG_STRICT},
+{ "ldb",	0x40000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldb",	0x40000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "std",	0x0c0012e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012e0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT},
+{ "std",	0x0c0012c0, 0xfc0013c0, "cmcCx,V(s,b)", pa20, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc000002, "cqx,&(b)", pa20w, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc00c002, "cqx,#(b)", pa20, FLAG_STRICT},
+{ "std",	0x70000000, 0xfc000002, "cqx,#(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c0012a0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c0012a0, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stw",	0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc000000, "cex,<(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc000006, "cex,>(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x68000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc00c006, "cex,K(b)", pa20, FLAG_STRICT},
+{ "stw",	0x7c000004, 0xfc000006, "cex,K(s,b)", pa20, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc00c000, "cex,J(b)", pa10, FLAG_STRICT},
+{ "stw",	0x6c000000, 0xfc000000, "cex,J(s,b)", pa10, FLAG_STRICT},
+{ "stw",	0x68000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stw",	0x68000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "sth",	0x0c001260, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "sth",	0x0c001260, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "sth",	0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "sth",	0x64000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "sth",	0x64000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "sth",	0x64000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "stb",	0x0c001220, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stb",	0x0c001220, 0xfc0033ff, "cocCx,@(s,b)", pa20, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stb",	0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stb",	0x60000000, 0xfc000000, "x,l(b)", pa20w, FLAG_STRICT},
+{ "stb",	0x60000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stb",	0x60000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "ldwm",	0x4c000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldwm",	0x4c000000, 0xfc000000, "j(s,b),x", pa10, 0},
+{ "stwm",	0x6c000000, 0xfc00c000, "x,j(b)", pa10, 0},
+{ "stwm",	0x6c000000, 0xfc000000, "x,j(s,b)", pa10, 0},
+{ "ldwx",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldwx",	0x0c000080, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldwx",	0x0c000080, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldhx",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldhx",	0x0c000040, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldhx",	0x0c000040, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldbx",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc0013c0, "cxccx(s,b),t", pa11, FLAG_STRICT},
+{ "ldbx",	0x0c000000, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldbx",	0x0c000000, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldwa",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwa",	0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwa",	0x0c0011a0, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldwa",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldwa",	0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT},
+{ "ldcw",	0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT},
+{ "stwa",	0x0c0013a0, 0xfc00d3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stwa",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stwa",	0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT},
+{ "stby",	0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT},
+{ "ldda",	0x0c000100, 0xfc00d3c0, "cxccx(b),t", pa20, FLAG_STRICT},
+{ "ldda",	0x0c001120, 0xfc1ff3e0, "cocc@(b),t", pa20, FLAG_STRICT},
+{ "ldda",	0x0c001100, 0xfc00d3c0, "cmcc5(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c000140, 0xfc00d3c0, "cxcdx(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c000140, 0xfc0013c0, "cxcdx(s,b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c001140, 0xfc00d3c0, "cmcd5(b),t", pa20, FLAG_STRICT},
+{ "ldcd",	0x0c001140, 0xfc0013c0, "cmcd5(s,b),t", pa20, FLAG_STRICT},
+{ "stda",	0x0c0013e0, 0xfc00f3ff, "cocCx,@(b)", pa20, FLAG_STRICT},
+{ "stda",	0x0c0013c0, 0xfc00d3c0, "cmcCx,V(b)", pa20, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00d3c0, "cxccx(b),t", pa11, FLAG_STRICT},
+{ "ldwax",	0x0c000180, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldcwx",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc00d3c0, "cxcdx(b),t", pa11, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc0013c0, "cxcdx(s,b),t", pa11, FLAG_STRICT},
+{ "ldcwx",	0x0c0001c0, 0xfc00dfc0, "cXx(b),t", pa10, 0},
+{ "ldcwx",	0x0c0001c0, 0xfc001fc0, "cXx(s,b),t", pa10, 0},
+{ "ldws",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldws",	0x0c001080, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldws",	0x0c001080, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldhs",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldhs",	0x0c001040, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldhs",	0x0c001040, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldbs",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc0013c0, "cmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "ldbs",	0x0c001000, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldbs",	0x0c001000, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "ldwas",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldwas",	0x0c001180, 0xfc00d3c0, "cmcc5(b),t", pa11, FLAG_STRICT},
+{ "ldwas",	0x0c001180, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldcws",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc00d3c0, "cmcd5(b),t", pa11, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc0013c0, "cmcd5(s,b),t", pa11, FLAG_STRICT},
+{ "ldcws",	0x0c0011c0, 0xfc00dfc0, "cM5(b),t", pa10, 0},
+{ "ldcws",	0x0c0011c0, 0xfc001fc0, "cM5(s,b),t", pa10, 0},
+{ "stws",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stws",	0x0c001280, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stws",	0x0c001280, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "sths",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "sths",	0x0c001240, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "sths",	0x0c001240, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "stbs",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc0013c0, "cmcCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stbs",	0x0c001200, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stbs",	0x0c001200, 0xfc001fc0, "cMx,V(s,b)", pa10, 0},
+{ "stwas",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, FLAG_STRICT},
+{ "stwas",	0x0c001380, 0xfc00d3c0, "cmcCx,V(b)", pa11, FLAG_STRICT},
+{ "stwas",	0x0c001380, 0xfc00dfc0, "cMx,V(b)", pa10, 0},
+{ "stdby",	0x0c001340, 0xfc00d3c0, "cscCx,V(b)", pa20, FLAG_STRICT},
+{ "stdby",	0x0c001340, 0xfc0013c0, "cscCx,V(s,b)", pa20, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00d3c0, "cscCx,V(b)", pa11, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc0013c0, "cscCx,V(s,b)", pa11, FLAG_STRICT},
+{ "stbys",	0x0c001300, 0xfc00dfc0, "cAx,V(b)", pa10, 0},
+{ "stbys",	0x0c001300, 0xfc001fc0, "cAx,V(s,b)", pa10, 0},
+
+/* Immediate instructions.  */
+{ "ldo",	0x34000000, 0xfc000000, "l(b),x", pa20w, 0},
+{ "ldo",	0x34000000, 0xfc00c000, "j(b),x", pa10, 0},
+{ "ldil",	0x20000000, 0xfc000000, "k,b", pa10, 0},
+{ "addil",	0x28000000, 0xfc000000, "k,b,Z", pa10, 0},
+{ "addil",	0x28000000, 0xfc000000, "k,b", pa10, 0},
+
+/* Branching instructions.  */
+{ "b",		0xe8008000, 0xfc00e000, "cpnXL", pa20, FLAG_STRICT},
+{ "b",		0xe800a000, 0xfc00e000, "clnXL", pa20, FLAG_STRICT},
+{ "b",		0xe8000000, 0xfc00e000, "clnW,b", pa10, FLAG_STRICT},
+{ "b",		0xe8002000, 0xfc00e000, "cgnW,b", pa10, FLAG_STRICT},
+{ "b",		0xe8000000, 0xffe0e000, "nW", pa10, 0},  /* b,l foo,r0 */
+{ "bl",		0xe8000000, 0xfc00e000, "nW,b", pa10, 0},
+{ "gate",	0xe8002000, 0xfc00e000, "nW,b", pa10, 0},
+{ "blr",	0xe8004000, 0xfc00e001, "nx,b", pa10, 0},
+{ "bv",		0xe800c000, 0xfc00fffd, "nx(b)", pa10, 0},
+{ "bv",		0xe800c000, 0xfc00fffd, "n(b)", pa10, 0},
+{ "bve",	0xe800f001, 0xfc1ffffd, "cpn(b)L", pa20, FLAG_STRICT},
+{ "bve",	0xe800f000, 0xfc1ffffd, "cln(b)L", pa20, FLAG_STRICT},
+{ "bve",	0xe800d001, 0xfc1ffffd, "cPn(b)", pa20, FLAG_STRICT},
+{ "bve",	0xe800d000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT},
+{ "be",		0xe4000000, 0xfc000000, "clnz(S,b),Y", pa10, FLAG_STRICT},
+{ "be",		0xe4000000, 0xfc000000, "clnz(b),Y", pa10, FLAG_STRICT},
+{ "be",		0xe0000000, 0xfc000000, "nz(S,b)", pa10, 0},
+{ "be",		0xe0000000, 0xfc000000, "nz(b)", pa10, 0},
+{ "ble",	0xe4000000, 0xfc000000, "nz(S,b)", pa10, 0},
+{ "movb",	0xc8000000, 0xfc000000, "?ynx,b,w", pa10, 0},
+{ "movib",	0xcc000000, 0xfc000000, "?yn5,b,w", pa10, 0},
+{ "combt",	0x80000000, 0xfc000000, "?tnx,b,w", pa10, 0},
+{ "combf",	0x88000000, 0xfc000000, "?tnx,b,w", pa10, 0},
+{ "comibt",	0x84000000, 0xfc000000, "?tn5,b,w", pa10, 0},
+{ "comibf",	0x8c000000, 0xfc000000, "?tn5,b,w", pa10, 0},
+{ "addbt",	0xa0000000, 0xfc000000, "?dnx,b,w", pa10, 0},
+{ "addbf",	0xa8000000, 0xfc000000, "?dnx,b,w", pa10, 0},
+{ "addibt",	0xa4000000, 0xfc000000, "?dn5,b,w", pa10, 0},
+{ "addibf",	0xac000000, 0xfc000000, "?dn5,b,w", pa10, 0},
+{ "bb",		0xc0004000, 0xffe06000, "?bnx,!,w", pa10, FLAG_STRICT},
+{ "bb",		0xc0006000, 0xffe06000, "?Bnx,!,w", pa20, FLAG_STRICT},
+{ "bb",		0xc4004000, 0xfc006000, "?bnx,Q,w", pa10, FLAG_STRICT},
+{ "bb",		0xc4004000, 0xfc004000, "?Bnx,B,w", pa20, FLAG_STRICT},
+{ "bvb",	0xc0004000, 0xffe04000, "?bnx,w", pa10, 0},
+{ "clrbts",	0xe8004005, 0xffffffff, "", pa20, FLAG_STRICT},
+{ "popbts",	0xe8004005, 0xfffff007, "$", pa20, FLAG_STRICT},
+{ "pushnom",	0xe8004001, 0xffffffff, "", pa20, FLAG_STRICT},
+{ "pushbts",	0xe8004001, 0xffe0ffff, "x", pa20, FLAG_STRICT},
+
+/* Computation Instructions.  */
+
+{ "cmpclr",	0x080008a0, 0xfc000fe0, "?Sx,b,t", pa20, FLAG_STRICT},
+{ "cmpclr",	0x08000880, 0xfc000fe0, "?sx,b,t", pa10, FLAG_STRICT},
+{ "comclr",	0x08000880, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "or",		0x08000260, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "or",		0x08000240, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "xor",	0x080002a0, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "xor",	0x08000280, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "and",	0x08000220, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "and",	0x08000200, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "andcm",	0x08000020, 0xfc000fe0, "?Lx,b,t", pa20, FLAG_STRICT},
+{ "andcm",	0x08000000, 0xfc000fe0, "?lx,b,t", pa10, 0},
+{ "uxor",	0x080003a0, 0xfc000fe0, "?Ux,b,t", pa20, FLAG_STRICT},
+{ "uxor",	0x08000380, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "uaddcm",	0x080009a0, 0xfc000fa0, "cT?Ux,b,t", pa20, FLAG_STRICT},
+{ "uaddcm",	0x08000980, 0xfc000fa0, "cT?ux,b,t", pa10, FLAG_STRICT},
+{ "uaddcm",	0x08000980, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "uaddcmt",	0x080009c0, 0xfc000fe0, "?ux,b,t", pa10, 0},
+{ "dcor",	0x08000ba0, 0xfc1f0fa0, "ci?Ub,t", pa20, FLAG_STRICT},
+{ "dcor",	0x08000b80, 0xfc1f0fa0, "ci?ub,t", pa10, FLAG_STRICT},
+{ "dcor",	0x08000b80, 0xfc1f0fe0, "?ub,t",   pa10, 0},
+{ "idcor",	0x08000bc0, 0xfc1f0fe0, "?ub,t",   pa10, 0},
+{ "addi",	0xb0000000, 0xfc000000, "ct?ai,b,x", pa10, FLAG_STRICT},
+{ "addi",	0xb4000000, 0xfc000000, "cv?ai,b,x", pa10, FLAG_STRICT},
+{ "addi",	0xb4000000, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addio",	0xb4000800, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addit",	0xb0000000, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "addito",	0xb0000800, 0xfc000800, "?ai,b,x", pa10, 0},
+{ "add",	0x08000720, 0xfc0007e0, "cY?Ax,b,t", pa20, FLAG_STRICT},
+{ "add",	0x08000700, 0xfc0007e0, "cy?ax,b,t", pa10, FLAG_STRICT},
+{ "add",	0x08000220, 0xfc0003e0, "ca?Ax,b,t", pa20, FLAG_STRICT},
+{ "add",	0x08000200, 0xfc0003e0, "ca?ax,b,t", pa10, FLAG_STRICT},
+{ "add",	0x08000600, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addl",	0x08000a00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addo",	0x08000e00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addc",	0x08000700, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "addco",	0x08000f00, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sub",	0x080004e0, 0xfc0007e0, "ct?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x080004c0, 0xfc0007e0, "ct?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000520, 0xfc0007e0, "cB?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x08000500, 0xfc0007e0, "cb?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000420, 0xfc0007e0, "cv?Sx,b,t", pa20, FLAG_STRICT},
+{ "sub",	0x08000400, 0xfc0007e0, "cv?sx,b,t", pa10, FLAG_STRICT},
+{ "sub",	0x08000400, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subo",	0x08000c00, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subb",	0x08000500, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subbo",	0x08000d00, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subt",	0x080004c0, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subto",	0x08000cc0, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "ds",		0x08000440, 0xfc000fe0, "?sx,b,t", pa10, 0},
+{ "subi",	0x94000000, 0xfc000000, "cv?si,b,x", pa10, FLAG_STRICT},
+{ "subi",	0x94000000, 0xfc000800, "?si,b,x", pa10, 0},
+{ "subio",	0x94000800, 0xfc000800, "?si,b,x", pa10, 0},
+{ "cmpiclr",	0x90000800, 0xfc000800, "?Si,b,x", pa20, FLAG_STRICT},
+{ "cmpiclr",	0x90000000, 0xfc000800, "?si,b,x", pa10, FLAG_STRICT},
+{ "comiclr",	0x90000000, 0xfc000800, "?si,b,x", pa10, 0},
+{ "shladd",	0x08000220, 0xfc000320, "ca?Ax,.,b,t", pa20, FLAG_STRICT},
+{ "shladd",	0x08000200, 0xfc000320, "ca?ax,.,b,t", pa10, FLAG_STRICT},
+{ "sh1add",	0x08000640, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh1addl",	0x08000a40, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh1addo",	0x08000e40, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2add",	0x08000680, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2addl",	0x08000a80, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh2addo",	0x08000e80, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3add",	0x080006c0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3addl",	0x08000ac0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+{ "sh3addo",	0x08000ec0, 0xfc000fe0, "?ax,b,t", pa10, 0},
+
+/* Subword Operation Instructions.  */
+
+{ "hadd",	0x08000300, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT},
+{ "havg",	0x080002c0, 0xfc00ffe0, "x,b,t", pa20, FLAG_STRICT},
+{ "hshl",	0xf8008800, 0xffe0fc20, "x,*,t", pa20, FLAG_STRICT},
+{ "hshladd",	0x08000700, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT},
+{ "hshr",	0xf800c800, 0xfc1ff820, "cSb,*,t", pa20, FLAG_STRICT},
+{ "hshradd",	0x08000500, 0xfc00ff20, "x,.,b,t", pa20, FLAG_STRICT},
+{ "hsub",	0x08000100, 0xfc00ff20, "cHx,b,t", pa20, FLAG_STRICT},
+{ "mixh",	0xf8008400, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT},
+{ "mixw",	0xf8008000, 0xfc009fe0, "chx,b,t", pa20, FLAG_STRICT},
+{ "permh",	0xf8000000, 0xfc009020, "c*a,t", pa20, FLAG_STRICT},
+
+
+/* Extract and Deposit Instructions.  */
+
+{ "shrpd",	0xd0000200, 0xfc001fe0, "?Xx,b,!,t", pa20, FLAG_STRICT},
+{ "shrpd",	0xd0000400, 0xfc001400, "?Xx,b,~,t", pa20, FLAG_STRICT},
+{ "shrpw",	0xd0000000, 0xfc001fe0, "?xx,b,!,t", pa10, FLAG_STRICT},
+{ "shrpw",	0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, FLAG_STRICT},
+{ "vshd",	0xd0000000, 0xfc001fe0, "?xx,b,t", pa10, 0},
+{ "shd",	0xd0000800, 0xfc001c00, "?xx,b,p,t", pa10, 0},
+{ "extrd",	0xd0001200, 0xfc001ae0, "cS?Xb,!,%,x", pa20, FLAG_STRICT},
+{ "extrd",	0xd8000000, 0xfc000000, "cS?Xb,q,|,x", pa20, FLAG_STRICT},
+{ "extrw",	0xd0001000, 0xfc001be0, "cS?xb,!,T,x", pa10, FLAG_STRICT},
+{ "extrw",	0xd0001800, 0xfc001800, "cS?xb,P,T,x", pa10, FLAG_STRICT},
+{ "vextru",	0xd0001000, 0xfc001fe0, "?xb,T,x", pa10, 0},
+{ "vextrs",	0xd0001400, 0xfc001fe0, "?xb,T,x", pa10, 0},
+{ "extru",	0xd0001800, 0xfc001c00, "?xb,P,T,x", pa10, 0},
+{ "extrs",	0xd0001c00, 0xfc001c00, "?xb,P,T,x", pa10, 0},
+{ "depd",	0xd4000200, 0xfc001ae0, "cz?Xx,!,%,b", pa20, FLAG_STRICT},
+{ "depd",	0xf0000000, 0xfc000000, "cz?Xx,~,|,b", pa20, FLAG_STRICT},
+{ "depdi",	0xd4001200, 0xfc001ae0, "cz?X5,!,%,b", pa20, FLAG_STRICT},
+{ "depdi",	0xf4000000, 0xfc000000, "cz?X5,~,|,b", pa20, FLAG_STRICT},
+{ "depw",	0xd4000000, 0xfc001be0, "cz?xx,!,T,b", pa10, FLAG_STRICT},
+{ "depw",	0xd4000800, 0xfc001800, "cz?xx,p,T,b", pa10, FLAG_STRICT},
+{ "depwi",	0xd4001000, 0xfc001be0, "cz?x5,!,T,b", pa10, FLAG_STRICT},
+{ "depwi",	0xd4001800, 0xfc001800, "cz?x5,p,T,b", pa10, FLAG_STRICT},
+{ "zvdep",	0xd4000000, 0xfc001fe0, "?xx,T,b", pa10, 0},
+{ "vdep",	0xd4000400, 0xfc001fe0, "?xx,T,b", pa10, 0},
+{ "zdep",	0xd4000800, 0xfc001c00, "?xx,p,T,b", pa10, 0},
+{ "dep",	0xd4000c00, 0xfc001c00, "?xx,p,T,b", pa10, 0},
+{ "zvdepi",	0xd4001000, 0xfc001fe0, "?x5,T,b", pa10, 0},
+{ "vdepi",	0xd4001400, 0xfc001fe0, "?x5,T,b", pa10, 0},
+{ "zdepi",	0xd4001800, 0xfc001c00, "?x5,p,T,b", pa10, 0},
+{ "depi",	0xd4001c00, 0xfc001c00, "?x5,p,T,b", pa10, 0},
+
+/* System Control Instructions.  */
+
+{ "break",	0x00000000, 0xfc001fe0, "r,A", pa10, 0},
+{ "rfi",	0x00000c00, 0xffffff1f, "cr", pa10, FLAG_STRICT},
+{ "rfi",	0x00000c00, 0xffffffff, "", pa10, 0},
+{ "rfir",	0x00000ca0, 0xffffffff, "", pa11, 0},
+{ "ssm",	0x00000d60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT},
+{ "ssm",	0x00000d60, 0xffe0ffe0, "R,t", pa10, 0},
+{ "rsm",	0x00000e60, 0xfc00ffe0, "U,t", pa20, FLAG_STRICT},
+{ "rsm",	0x00000e60, 0xffe0ffe0, "R,t", pa10, 0},
+{ "mtsm",	0x00001860, 0xffe0ffff, "x", pa10, 0},
+{ "ldsid",	0x000010a0, 0xfc1fffe0, "(b),t", pa10, 0},
+{ "ldsid",	0x000010a0, 0xfc1f3fe0, "(s,b),t", pa10, 0},
+{ "mtsp",	0x00001820, 0xffe01fff, "x,S", pa10, 0},
+{ "mtctl",	0x00001840, 0xfc00ffff, "x,^", pa10, 0},
+{ "mtsarcm",	0x016018C0, 0xffe0ffff, "x", pa20, FLAG_STRICT},
+{ "mfia",	0x000014A0, 0xffffffe0, "t", pa20, FLAG_STRICT},
+{ "mfsp",	0x000004a0, 0xffff1fe0, "S,t", pa10, 0},
+{ "mfctl",	0x016048a0, 0xffffffe0, "cW!,t", pa20, FLAG_STRICT},
+{ "mfctl",	0x000008a0, 0xfc1fffe0, "^,t", pa10, 0},
+{ "sync",	0x00000400, 0xffffffff, "", pa10, 0},
+{ "syncdma",	0x00100400, 0xffffffff, "", pa10, 0},
+{ "probe",	0x04001180, 0xfc00ffa0, "cw(b),x,t", pa10, FLAG_STRICT},
+{ "probe",	0x04001180, 0xfc003fa0, "cw(s,b),x,t", pa10, FLAG_STRICT},
+{ "probei",	0x04003180, 0xfc00ffa0, "cw(b),R,t", pa10, FLAG_STRICT},
+{ "probei",	0x04003180, 0xfc003fa0, "cw(s,b),R,t", pa10, FLAG_STRICT},
+{ "prober",	0x04001180, 0xfc00ffe0, "(b),x,t", pa10, 0},
+{ "prober",	0x04001180, 0xfc003fe0, "(s,b),x,t", pa10, 0},
+{ "proberi",	0x04003180, 0xfc00ffe0, "(b),R,t", pa10, 0},
+{ "proberi",	0x04003180, 0xfc003fe0, "(s,b),R,t", pa10, 0},
+{ "probew",	0x040011c0, 0xfc00ffe0, "(b),x,t", pa10, 0},
+{ "probew",	0x040011c0, 0xfc003fe0, "(s,b),x,t", pa10, 0},
+{ "probewi",	0x040031c0, 0xfc00ffe0, "(b),R,t", pa10, 0},
+{ "probewi",	0x040031c0, 0xfc003fe0, "(s,b),R,t", pa10, 0},
+{ "lpa",	0x04001340, 0xfc00ffc0, "cZx(b),t", pa10, 0},
+{ "lpa",	0x04001340, 0xfc003fc0, "cZx(s,b),t", pa10, 0},
+{ "lci",	0x04001300, 0xfc00ffe0, "x(b),t", pa11, 0},
+{ "lci",	0x04001300, 0xfc003fe0, "x(s,b),t", pa11, 0},
+{ "pdtlb",	0x04001600, 0xfc00ffdf, "cLcZx(b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc003fdf, "cLcZx(s,b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc1fffdf, "cLcZ@(b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001600, 0xfc1f3fdf, "cLcZ@(s,b)", pa20, FLAG_STRICT},
+{ "pdtlb",	0x04001200, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdtlb",	0x04001200, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "pitlb",	0x04000600, 0xfc001fdf, "cLcZx(S,b)", pa20, FLAG_STRICT},
+{ "pitlb",	0x04000600, 0xfc1f1fdf, "cLcZ@(S,b)", pa20, FLAG_STRICT},
+{ "pitlb",	0x04000200, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "pdtlbe",	0x04001240, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdtlbe",	0x04001240, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "pitlbe",	0x04000240, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "idtlba",	0x04001040, 0xfc00ffff, "x,(b)", pa10, 0},
+{ "idtlba",	0x04001040, 0xfc003fff, "x,(s,b)", pa10, 0},
+{ "iitlba",	0x04000040, 0xfc001fff, "x,(S,b)", pa10, 0},
+{ "idtlbp",	0x04001000, 0xfc00ffff, "x,(b)", pa10, 0},
+{ "idtlbp",	0x04001000, 0xfc003fff, "x,(s,b)", pa10, 0},
+{ "iitlbp",	0x04000000, 0xfc001fff, "x,(S,b)", pa10, 0},
+{ "pdc",	0x04001380, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "pdc",	0x04001380, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fdc",	0x04001280, 0xfc00ffdf, "cZx(b)", pa10, FLAG_STRICT},
+{ "fdc",	0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, FLAG_STRICT},
+{ "fdc",	0x04003280, 0xfc00ffff, "5(b)", pa20, FLAG_STRICT},
+{ "fdc",	0x04003280, 0xfc003fff, "5(s,b)", pa20, FLAG_STRICT},
+{ "fdc",	0x04001280, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "fdc",	0x04001280, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fic",	0x040013c0, 0xfc00dfdf, "cZx(b)", pa20, FLAG_STRICT},
+{ "fic",	0x04000280, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "fdce",	0x040012c0, 0xfc00ffdf, "cZx(b)", pa10, 0},
+{ "fdce",	0x040012c0, 0xfc003fdf, "cZx(s,b)", pa10, 0},
+{ "fice",	0x040002c0, 0xfc001fdf, "cZx(S,b)", pa10, 0},
+{ "diag",	0x14000000, 0xfc000000, "D", pa10, 0},
+{ "idtlbt",	0x04001800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT},
+{ "iitlbt",	0x04000800, 0xfc00ffff, "x,b", pa20, FLAG_STRICT},
+
+/* These may be specific to certain versions of the PA.  Joel claimed
+   they were 72000 (7200?) specific.  However, I'm almost certain the
+   mtcpu/mfcpu were undocumented, but available in the older 700 machines.  */
+{ "mtcpu",	0x14001600, 0xfc00ffff, "x,^", pa10, 0},
+{ "mfcpu",	0x14001A00, 0xfc00ffff, "^,x", pa10, 0},
+{ "tocen",	0x14403600, 0xffffffff, "", pa10, 0},
+{ "tocdis",	0x14401620, 0xffffffff, "", pa10, 0},
+{ "shdwgr",	0x14402600, 0xffffffff, "", pa10, 0},
+{ "grshdw",	0x14400620, 0xffffffff, "", pa10, 0},
+
+/* gfw and gfr are not in the HP PA 1.1 manual, but they are in either
+   the Timex FPU or the Mustang ERS (not sure which) manual.  */
+{ "gfw",	0x04001680, 0xfc00ffdf, "cZx(b)", pa11, 0},
+{ "gfw",	0x04001680, 0xfc003fdf, "cZx(s,b)", pa11, 0},
+{ "gfr",	0x04001a80, 0xfc00ffdf, "cZx(b)", pa11, 0},
+{ "gfr",	0x04001a80, 0xfc003fdf, "cZx(s,b)", pa11, 0},
+
+/* Floating Point Coprocessor Instructions.  */
+
+{ "fldw",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24001020, 0xfc1ff3a0, "cocc@(b),fT", pa20, FLAG_STRICT},
+{ "fldw",	0x24001020, 0xfc1f33a0, "cocc@(s,b),fT", pa20, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc00df80, "cM5(b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc001f80, "cM5(s,b),fT", pa10, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc000004, "y(b),fe", pa20w, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc000000, "cJy(b),fe", pa20w, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc00c004, "d(b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x5c000000, 0xfc000004, "d(s,b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc00c000, "cJd(b),fe", pa20, FLAG_STRICT},
+{ "fldw",	0x58000000, 0xfc000000, "cJd(s,b),fe", pa20, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c001020, 0xfc1ff3e0, "cocc@(b),ft", pa20, FLAG_STRICT},
+{ "fldd",	0x2c001020, 0xfc1f33e0, "cocc@(s,b),ft", pa20, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc00dfc0, "cM5(b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc001fc0, "cM5(s,b),ft", pa10, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc000002, "cq&(b),fx", pa20w, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc00c002, "cq#(b),fx", pa20, FLAG_STRICT},
+{ "fldd",	0x50000002, 0xfc000002, "cq#(s,b),fx", pa20, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc00df80, "cXfT,x(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc001f80, "cXfT,x(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT},
+{ "fstw",	0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT},
+{ "fstw",	0x24001220, 0xfc1ff3a0, "cocCfT,@(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x24001220, 0xfc1f33a0, "cocCfT,@(s,b)", pa20, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc00df80, "cMfT,5(b)", pa10, FLAG_STRICT},
+{ "fstw",	0x24001200, 0xfc001f80, "cMfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc000004, "fE,y(b)", pa20w, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc000000, "cJfE,y(b)", pa20w, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc00c004, "fE,d(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x7c000000, 0xfc000004, "fE,d(s,b)", pa20, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc00c000, "cJfE,d(b)", pa20, FLAG_STRICT},
+{ "fstw",	0x78000000, 0xfc000000, "cJfE,d(s,b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc00dfc0, "cXft,x(b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc001fc0, "cXft,x(s,b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c001220, 0xfc1ff3e0, "cocCft,@(b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c001220, 0xfc1f33e0, "cocCft,@(s,b)", pa20, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc00dfc0, "cMft,5(b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc001fc0, "cMft,5(s,b)", pa10, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT},
+{ "fstd",	0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc000002, "cqfx,&(b)", pa20w, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc00c002, "cqfx,#(b)", pa20, FLAG_STRICT},
+{ "fstd",	0x70000002, 0xfc000002, "cqfx,#(s,b)", pa20, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00d380, "cxccx(b),fT", pa11, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc001380, "cxccx(s,b),fT", pa11, FLAG_STRICT},
+{ "fldwx",	0x24000000, 0xfc00df80, "cXx(b),fT", pa10, 0},
+{ "fldwx",	0x24000000, 0xfc001f80, "cXx(s,b),fT", pa10, 0},
+{ "flddx",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc00d3c0, "cxccx(b),ft", pa11, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc0013c0, "cxccx(s,b),ft", pa11, FLAG_STRICT},
+{ "flddx",	0x2c000000, 0xfc00dfc0, "cXx(b),ft", pa10, 0},
+{ "flddx",	0x2c000000, 0xfc001fc0, "cXx(s,b),ft", pa10, 0},
+{ "fstwx",	0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc00d380, "cxcCfT,x(b)", pa11, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc001380, "cxcCfT,x(s,b)", pa11, FLAG_STRICT},
+{ "fstwx",	0x24000200, 0xfc00df80, "cxfT,x(b)", pa10, 0},
+{ "fstwx",	0x24000200, 0xfc001f80, "cxfT,x(s,b)", pa10, 0},
+{ "fstdx",	0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc00d3c0, "cxcCft,x(b)", pa11, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc0013c0, "cxcCft,x(s,b)", pa11, FLAG_STRICT},
+{ "fstdx",	0x2c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0},
+{ "fstdx",	0x2c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0},
+{ "fstqx",	0x3c000200, 0xfc00dfc0, "cxft,x(b)", pa10, 0},
+{ "fstqx",	0x3c000200, 0xfc001fc0, "cxft,x(s,b)", pa10, 0},
+{ "fldws",	0x24001000, 0xfc00df80, "cm5(b),fT", pa10, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc00d380, "cmcc5(b),fT", pa11, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc001380, "cmcc5(s,b),fT", pa11, FLAG_STRICT},
+{ "fldws",	0x24001000, 0xfc00df80, "cm5(b),fT", pa10, 0},
+{ "fldws",	0x24001000, 0xfc001f80, "cm5(s,b),fT", pa10, 0},
+{ "fldds",	0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc00d3c0, "cmcc5(b),ft", pa11, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc0013c0, "cmcc5(s,b),ft", pa11, FLAG_STRICT},
+{ "fldds",	0x2c001000, 0xfc00dfc0, "cm5(b),ft", pa10, 0},
+{ "fldds",	0x2c001000, 0xfc001fc0, "cm5(s,b),ft", pa10, 0},
+{ "fstws",	0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc00d380, "cmcCfT,5(b)", pa11, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc001380, "cmcCfT,5(s,b)", pa11, FLAG_STRICT},
+{ "fstws",	0x24001200, 0xfc00df80, "cmfT,5(b)", pa10, 0},
+{ "fstws",	0x24001200, 0xfc001f80, "cmfT,5(s,b)", pa10, 0},
+{ "fstds",	0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc00d3c0, "cmcCft,5(b)", pa11, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc0013c0, "cmcCft,5(s,b)", pa11, FLAG_STRICT},
+{ "fstds",	0x2c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0},
+{ "fstds",	0x2c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0},
+{ "fstqs",	0x3c001200, 0xfc00dfc0, "cmft,5(b)", pa10, 0},
+{ "fstqs",	0x3c001200, 0xfc001fc0, "cmft,5(s,b)", pa10, 0},
+{ "fadd",	0x30000600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fadd",	0x38000600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fsub",	0x30002600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fsub",	0x38002600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fmpy",	0x30004600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fmpy",	0x38004600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fdiv",	0x30006600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "fdiv",	0x38006600, 0xfc00e720, "IfA,fB,fT", pa10, 0},
+{ "fsqrt",	0x30008000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fsqrt",	0x38008000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fabs",	0x30006000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fabs",	0x38006000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "frem",	0x30008600, 0xfc00e7e0, "Ffa,fb,fT", pa10, 0},
+{ "frem",	0x38008600, 0xfc00e720, "FfA,fB,fT", pa10, 0},
+{ "frnd",	0x3000a000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "frnd",	0x3800a000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fcpy",	0x30004000, 0xfc1fe7e0, "Ffa,fT", pa10, 0},
+{ "fcpy",	0x38004000, 0xfc1fe720, "FfA,fT", pa10, 0},
+{ "fcnvff",	0x30000200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvff",	0x38000200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvxf",	0x30008200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvxf",	0x38008200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvfx",	0x30010200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvfx",	0x38010200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fcnvfxt",	0x30018200, 0xfc1f87e0, "FGfa,fT", pa10, 0},
+{ "fcnvfxt",	0x38018200, 0xfc1f8720, "FGfA,fT", pa10, 0},
+{ "fmpyfadd",	0xb8000000, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT},
+{ "fmpynfadd",	0xb8000020, 0xfc000020, "IfA,fB,fC,fT", pa20, FLAG_STRICT},
+{ "fneg",	0x3000c000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT},
+{ "fneg",	0x3800c000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT},
+{ "fnegabs",	0x3000e000, 0xfc1fe7e0, "Ffa,fT", pa20, FLAG_STRICT},
+{ "fnegabs",	0x3800e000, 0xfc1fe720, "IfA,fT", pa20, FLAG_STRICT},
+{ "fcnv",	0x30000200, 0xfc1c0720, "{_fa,fT", pa20, FLAG_STRICT},
+{ "fcnv",	0x38000200, 0xfc1c0720, "FGfA,fT", pa20, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, FLAG_STRICT},
+{ "fcmp",	0x38000400, 0xfc00e720, "I?ffA,fB", pa10, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc0007e0, "F?ffa,fb,h", pa20, FLAG_STRICT},
+{ "fcmp",	0x38000400, 0xfc000720, "I?ffA,fB,h", pa20, FLAG_STRICT},
+{ "fcmp",	0x30000400, 0xfc00e7e0, "F?ffa,fb", pa10, 0},
+{ "fcmp",	0x38000400, 0xfc00e720, "I?ffA,fB", pa10, 0},
+{ "xmpyu",	0x38004700, 0xfc00e720, "fX,fB,fT", pa11, 0},
+{ "fmpyadd",	0x18000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0},
+{ "fmpysub",	0x98000000, 0xfc000000, "Hfi,fj,fk,fl,fm", pa11, 0},
+{ "ftest",	0x30002420, 0xffffffff, "", pa10, FLAG_STRICT},
+{ "ftest",	0x30002420, 0xffffffe0, ",=", pa20, FLAG_STRICT},
+{ "ftest",	0x30000420, 0xffff1fff, "m", pa20, FLAG_STRICT},
+{ "fid",	0x30000000, 0xffffffff, "", pa11, 0},
+
+/* Performance Monitor Instructions.  */
+
+{ "pmdis",	0x30000280, 0xffffffdf, "N", pa20, FLAG_STRICT},
+{ "pmenb",	0x30000680, 0xffffffff, "", pa20, FLAG_STRICT},
+
+/* Assist Instructions.  */
+
+{ "spop0",	0x10000000, 0xfc000600, "v,ON", pa10, 0},
+{ "spop1",	0x10000200, 0xfc000600, "v,oNt", pa10, 0},
+{ "spop2",	0x10000400, 0xfc000600, "v,1Nb", pa10, 0},
+{ "spop3",	0x10000600, 0xfc000600, "v,0Nx,b", pa10, 0},
+{ "copr",	0x30000000, 0xfc000000, "u,2N", pa10, 0},
+{ "cldw",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldw",	0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00d200, "ucocc@(b),t", pa20, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001200, "ucocc@(s,b),t", pa20, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldd",	0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstw",	0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00d200, "ucocCt,@(b)", pa20, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001200, "ucocCt,@(s,b)", pa20, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstd",	0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "cldwx",	0x24000000, 0xfc00de00, "ucXx(b),t", pa10, 0},
+{ "cldwx",	0x24000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0},
+{ "clddx",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc00d200, "ucxccx(b),t", pa11, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc001200, "ucxccx(s,b),t", pa11, FLAG_STRICT},
+{ "clddx",	0x2c000000, 0xfc00de00, "ucXx(b),t", pa10, 0},
+{ "clddx",	0x2c000000, 0xfc001e00, "ucXx(s,b),t", pa10, 0},
+{ "cstwx",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstwx",	0x24000200, 0xfc00de00, "ucXt,x(b)", pa10, 0},
+{ "cstwx",	0x24000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0},
+{ "cstdx",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc00d200, "ucxcCt,x(b)", pa11, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc001200, "ucxcCt,x(s,b)", pa11, FLAG_STRICT},
+{ "cstdx",	0x2c000200, 0xfc00de00, "ucXt,x(b)", pa10, 0},
+{ "cstdx",	0x2c000200, 0xfc001e00, "ucXt,x(s,b)", pa10, 0},
+{ "cldws",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldws",	0x24001000, 0xfc00de00, "ucM5(b),t", pa10, 0},
+{ "cldws",	0x24001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0},
+{ "cldds",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc00d200, "ucmcc5(b),t", pa11, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc001200, "ucmcc5(s,b),t", pa11, FLAG_STRICT},
+{ "cldds",	0x2c001000, 0xfc00de00, "ucM5(b),t", pa10, 0},
+{ "cldds",	0x2c001000, 0xfc001e00, "ucM5(s,b),t", pa10, 0},
+{ "cstws",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstws",	0x24001200, 0xfc00de00, "ucMt,5(b)", pa10, 0},
+{ "cstws",	0x24001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0},
+{ "cstds",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc00d200, "ucmcCt,5(b)", pa11, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc001200, "ucmcCt,5(s,b)", pa11, FLAG_STRICT},
+{ "cstds",	0x2c001200, 0xfc00de00, "ucMt,5(b)", pa10, 0},
+{ "cstds",	0x2c001200, 0xfc001e00, "ucMt,5(s,b)", pa10, 0},
+
+/* More pseudo instructions which must follow the main table.  */
+{ "call",	0xe800f000, 0xfc1ffffd, "n(b)", pa20, FLAG_STRICT},
+{ "call",	0xe800a000, 0xffe0e000, "nW", pa10, FLAG_STRICT},
+{ "ret",	0xe840d000, 0xfffffffd, "n", pa20, FLAG_STRICT},
+
+};
+
+#define NUMOPCODES ((sizeof pa_opcodes)/(sizeof pa_opcodes[0]))
+
+/* SKV 12/18/92. Added some denotations for various operands.  */
+
+#define PA_IMM11_AT_31 'i'
+#define PA_IMM14_AT_31 'j'
+#define PA_IMM21_AT_31 'k'
+#define PA_DISP12 'w'
+#define PA_DISP17 'W'
+
+#define N_HPPA_OPERAND_FORMATS 5
+
+/* Integer register names, indexed by the numbers which appear in the
+   opcodes.  */
+static const char *const reg_names[] =
+{
+  "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+  "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+  "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1",
+  "sp", "r31"
+};
+
+/* Floating point register names, indexed by the numbers which appear in the
+   opcodes.  */
+static const char *const fp_reg_names[] =
+{
+  "fpsr", "fpe2", "fpe4", "fpe6",
+  "fr4", "fr5", "fr6", "fr7", "fr8",
+  "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
+  "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
+  "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31"
+};
+
+typedef unsigned int CORE_ADDR;
+
+/* Get at various relevant fields of an instruction word.  */
+
+#define MASK_5  0x1f
+#define MASK_10 0x3ff
+#define MASK_11 0x7ff
+#define MASK_14 0x3fff
+#define MASK_16 0xffff
+#define MASK_21 0x1fffff
+
+/* These macros get bit fields using HP's numbering (MSB = 0).  */
+
+#define GET_FIELD(X, FROM, TO) \
+  ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
+
+#define GET_BIT(X, WHICH) \
+  GET_FIELD (X, WHICH, WHICH)
+
+/* Some of these have been converted to 2-d arrays because they
+   consume less storage this way.  If the maintenance becomes a
+   problem, convert them back to const 1-d pointer arrays.  */
+static const char *const control_reg[] =
+{
+  "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
+  "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4",
+  "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr",
+  "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3",
+  "tr4", "tr5", "tr6", "tr7"
+};
+
+static const char *const compare_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od",
+  ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev"
+};
+static const char *const compare_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev"
+};
+static const char *const cmpib_cond_64_names[] =
+{
+  ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>"
+};
+static const char *const add_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od",
+  ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev"
+};
+static const char *const add_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev"
+};
+static const char *const wide_add_cond_names[] =
+{
+  "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=",
+  ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>"
+};
+static const char *const logical_cond_names[] =
+{
+  "", ",=", ",<", ",<=", 0, 0, 0, ",od",
+  ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"};
+static const char *const logical_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od",
+  ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"};
+static const char *const unit_cond_names[] =
+{
+  "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc",
+  ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc"
+};
+static const char *const unit_cond_64_names[] =
+{
+  "", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc",
+  ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc"
+};
+static const char *const shift_cond_names[] =
+{
+  "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"
+};
+static const char *const shift_cond_64_names[] =
+{
+  "", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev"
+};
+static const char *const bb_cond_64_names[] =
+{
+  ",*<", ",*>="
+};
+static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"};
+static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
+static const char *const short_bytes_compl_names[] =
+{
+  "", ",b,m", ",e", ",e,m"
+};
+static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"};
+static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"};
+static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"};
+static const char *const float_comp_names[] =
+{
+  ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
+  ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
+  ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
+  ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
+};
+static const char *const signed_unsigned_names[] = {",u", ",s"};
+static const char *const mix_half_names[] = {",l", ",r"};
+static const char *const saturation_names[] = {",us", ",ss", 0, ""};
+static const char *const read_write_names[] = {",r", ",w"};
+static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" };
+
+/* For a bunch of different instructions form an index into a
+   completer name table.  */
+#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \
+			 GET_FIELD (insn, 18, 18) << 1)
+
+#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
+			(GET_FIELD ((insn), 19, 19) ? 8 : 0))
+
+/* Utility function to print registers.  Put these first, so gcc's function
+   inlining can do its stuff.  */
+
+#define fputs_filtered(STR,F)	(*info->fprintf_func) (info->stream, "%s", STR)
+
+static void
+fput_reg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0");
+}
+
+static void
+fput_fp_reg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0");
+}
+
+static void
+fput_fp_reg_r (unsigned reg, disassemble_info *info)
+{
+  /* Special case floating point exception registers.  */
+  if (reg < 4)
+    (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1);
+  else
+    (*info->fprintf_func) (info->stream, "%sR",
+			   reg ? fp_reg_names[reg] : "fr0");
+}
+
+static void
+fput_creg (unsigned reg, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "%s", control_reg[reg]);
+}
+
+/* Print constants with sign.  */
+
+static void
+fput_const (unsigned num, disassemble_info *info)
+{
+  if ((int) num < 0)
+    (*info->fprintf_func) (info->stream, "-%x", - (int) num);
+  else
+    (*info->fprintf_func) (info->stream, "%x", num);
+}
+
+/* Routines to extract various sized constants out of hppa
+   instructions.  */
+
+/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp.  */
+static int
+extract_3 (unsigned word)
+{
+  return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
+}
+
+static int
+extract_5_load (unsigned word)
+{
+  return low_sign_extend (word >> 16 & MASK_5, 5);
+}
+
+/* Extract the immediate field from a st{bhw}s instruction.  */
+
+static int
+extract_5_store (unsigned word)
+{
+  return low_sign_extend (word & MASK_5, 5);
+}
+
+/* Extract the immediate field from a break instruction.  */
+
+static unsigned
+extract_5r_store (unsigned word)
+{
+  return (word & MASK_5);
+}
+
+/* Extract the immediate field from a {sr}sm instruction.  */
+
+static unsigned
+extract_5R_store (unsigned word)
+{
+  return (word >> 16 & MASK_5);
+}
+
+/* Extract the 10 bit immediate field from a {sr}sm instruction.  */
+
+static unsigned
+extract_10U_store (unsigned word)
+{
+  return (word >> 16 & MASK_10);
+}
+
+/* Extract the immediate field from a bb instruction.  */
+
+static unsigned
+extract_5Q_store (unsigned word)
+{
+  return (word >> 21 & MASK_5);
+}
+
+/* Extract an 11 bit immediate field.  */
+
+static int
+extract_11 (unsigned word)
+{
+  return low_sign_extend (word & MASK_11, 11);
+}
+
+/* Extract a 14 bit immediate field.  */
+
+static int
+extract_14 (unsigned word)
+{
+  return low_sign_extend (word & MASK_14, 14);
+}
+
+/* Extract a 16 bit immediate field (PA2.0 wide only).  */
+
+static int
+extract_16 (unsigned word)
+{
+  int m15, m0, m1;
+
+  m0 = GET_BIT (word, 16);
+  m1 = GET_BIT (word, 17);
+  m15 = GET_BIT (word, 31);
+  word = (word >> 1) & 0x1fff;
+  word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13);
+  return sign_extend (word, 16);
+}
+
+/* Extract a 21 bit constant.  */
+
+static int
+extract_21 (unsigned word)
+{
+  int val;
+
+  word &= MASK_21;
+  word <<= 11;
+  val = GET_FIELD (word, 20, 20);
+  val <<= 11;
+  val |= GET_FIELD (word, 9, 19);
+  val <<= 2;
+  val |= GET_FIELD (word, 5, 6);
+  val <<= 5;
+  val |= GET_FIELD (word, 0, 4);
+  val <<= 2;
+  val |= GET_FIELD (word, 7, 8);
+  return sign_extend (val, 21) << 11;
+}
+
+/* Extract a 12 bit constant from branch instructions.  */
+
+static int
+extract_12 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | (word & 0x1) << 11, 12) << 2;
+}
+
+/* Extract a 17 bit constant from branch instructions, returning the
+   19 bit signed value.  */
+
+static int
+extract_17 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | GET_FIELD (word, 11, 15) << 11
+		      | (word & 0x1) << 16, 17) << 2;
+}
+
+static int
+extract_22 (unsigned word)
+{
+  return sign_extend (GET_FIELD (word, 19, 28)
+		      | GET_FIELD (word, 29, 29) << 10
+		      | GET_FIELD (word, 11, 15) << 11
+		      | GET_FIELD (word, 6, 10) << 16
+		      | (word & 0x1) << 21, 22) << 2;
+}
+
+/* Print one instruction.  */
+
+int
+print_insn_hppa (bfd_vma memaddr, disassemble_info *info)
+{
+  bfd_byte buffer[4];
+  unsigned int insn, i;
+
+  {
+    int status =
+      (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
+    if (status != 0)
+      {
+	(*info->memory_error_func) (status, memaddr, info);
+	return -1;
+      }
+  }
+
+  insn = bfd_getb32 (buffer);
+
+  for (i = 0; i < NUMOPCODES; ++i)
+    {
+      const struct pa_opcode *opcode = &pa_opcodes[i];
+
+      if ((insn & opcode->mask) == opcode->match)
+	{
+	  const char *s;
+#ifndef BFD64
+	  if (opcode->arch == pa20w)
+	    continue;
+#endif
+	  (*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+	  if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0]))
+	    (*info->fprintf_func) (info->stream, " ");
+	  for (s = opcode->args; *s != '\0'; ++s)
+	    {
+	      switch (*s)
+		{
+		case 'x':
+		  fput_reg (GET_FIELD (insn, 11, 15), info);
+		  break;
+		case 'a':
+		case 'b':
+		  fput_reg (GET_FIELD (insn, 6, 10), info);
+		  break;
+		case '^':
+		  fput_creg (GET_FIELD (insn, 6, 10), info);
+		  break;
+		case 't':
+		  fput_reg (GET_FIELD (insn, 27, 31), info);
+		  break;
+
+		  /* Handle floating point registers.  */
+		case 'f':
+		  switch (*++s)
+		    {
+		    case 't':
+		      fput_fp_reg (GET_FIELD (insn, 27, 31), info);
+		      break;
+		    case 'T':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 27, 31), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 27, 31), info);
+		      break;
+		    case 'a':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 6, 10), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 6, 10), info);
+		      break;
+
+		      /* 'fA' will not generate a space before the regsiter
+			 name.  Normally that is fine.  Except that it
+			 causes problems with xmpyu which has no FP format
+			 completer.  */
+		    case 'X':
+		      fputs_filtered (" ", info);
+		      /* FALLTHRU */
+
+		    case 'A':
+		      if (GET_FIELD (insn, 24, 24))
+			fput_fp_reg_r (GET_FIELD (insn, 6, 10), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 6, 10), info);
+		      break;
+		    case 'b':
+		      if (GET_FIELD (insn, 25, 25))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'B':
+		      if (GET_FIELD (insn, 19, 19))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'C':
+		      {
+			int reg = GET_FIELD (insn, 21, 22);
+			reg |= GET_FIELD (insn, 16, 18) << 2;
+			if (GET_FIELD (insn, 23, 23) != 0)
+			  fput_fp_reg_r (reg, info);
+			else
+			  fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'i':
+		      {
+			int reg = GET_FIELD (insn, 6, 10);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'j':
+		      {
+			int reg = GET_FIELD (insn, 11, 15);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'k':
+		      {
+			int reg = GET_FIELD (insn, 27, 31);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'l':
+		      {
+			int reg = GET_FIELD (insn, 21, 25);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+		    case 'm':
+		      {
+			int reg = GET_FIELD (insn, 16, 20);
+
+			reg |= (GET_FIELD (insn, 26, 26) << 4);
+			fput_fp_reg (reg, info);
+			break;
+		      }
+
+		      /* 'fe' will not generate a space before the register
+			 name.  Normally that is fine.  Except that it
+			 causes problems with fstw fe,y(b) which has no FP
+			 format completer.  */
+		    case 'E':
+		      fputs_filtered (" ", info);
+		      /* FALLTHRU */
+
+		    case 'e':
+		      if (GET_FIELD (insn, 30, 30))
+			fput_fp_reg_r (GET_FIELD (insn, 11, 15), info);
+		      else
+			fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    case 'x':
+		      fput_fp_reg (GET_FIELD (insn, 11, 15), info);
+		      break;
+		    }
+		  break;
+
+		case '5':
+		  fput_const (extract_5_load (insn), info);
+		  break;
+		case 's':
+		  {
+		    int space = GET_FIELD (insn, 16, 17);
+		    /* Zero means implicit addressing, not use of sr0.  */
+		    if (space != 0)
+		      (*info->fprintf_func) (info->stream, "sr%d", space);
+		  }
+		  break;
+
+		case 'S':
+		  (*info->fprintf_func) (info->stream, "sr%d",
+					 extract_3 (insn));
+		  break;
+
+		  /* Handle completers.  */
+		case 'c':
+		  switch (*++s)
+		    {
+		    case 'x':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 index_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'X':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 index_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'm':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 short_ldst_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'M':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 short_ldst_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'A':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 short_bytes_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 's':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 short_bytes_compl_names[GET_COMPL (insn)]);
+		      break;
+		    case 'c':
+		    case 'C':
+		      switch (GET_FIELD (insn, 20, 21))
+			{
+			case 1:
+			  (*info->fprintf_func) (info->stream, ",bc ");
+			  break;
+			case 2:
+			  (*info->fprintf_func) (info->stream, ",sl ");
+			  break;
+			default:
+			  (*info->fprintf_func) (info->stream, " ");
+			}
+		      break;
+		    case 'd':
+		      switch (GET_FIELD (insn, 20, 21))
+			{
+			case 1:
+			  (*info->fprintf_func) (info->stream, ",co ");
+			  break;
+			default:
+			  (*info->fprintf_func) (info->stream, " ");
+			}
+		      break;
+		    case 'o':
+		      (*info->fprintf_func) (info->stream, ",o");
+		      break;
+		    case 'g':
+		      (*info->fprintf_func) (info->stream, ",gate");
+		      break;
+		    case 'p':
+		      (*info->fprintf_func) (info->stream, ",l,push");
+		      break;
+		    case 'P':
+		      (*info->fprintf_func) (info->stream, ",pop");
+		      break;
+		    case 'l':
+		    case 'L':
+		      (*info->fprintf_func) (info->stream, ",l");
+		      break;
+		    case 'w':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 read_write_names[GET_FIELD (insn, 25, 25)]);
+		      break;
+		    case 'W':
+		      (*info->fprintf_func) (info->stream, ",w ");
+		      break;
+		    case 'r':
+		      if (GET_FIELD (insn, 23, 26) == 5)
+			(*info->fprintf_func) (info->stream, ",r");
+		      break;
+		    case 'Z':
+		      if (GET_FIELD (insn, 26, 26))
+			(*info->fprintf_func) (info->stream, ",m ");
+		      else
+			(*info->fprintf_func) (info->stream, " ");
+		      break;
+		    case 'i':
+		      if (GET_FIELD (insn, 25, 25))
+			(*info->fprintf_func) (info->stream, ",i");
+		      break;
+		    case 'z':
+		      if (!GET_FIELD (insn, 21, 21))
+			(*info->fprintf_func) (info->stream, ",z");
+		      break;
+		    case 'a':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'Y':
+		      (*info->fprintf_func)
+			(info->stream, ",dc%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'y':
+		      (*info->fprintf_func)
+			(info->stream, ",c%s",
+			 add_compl_names[GET_FIELD (insn, 20, 21)]);
+		      break;
+		    case 'v':
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 't':
+		      (*info->fprintf_func) (info->stream, ",tc");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'B':
+		      (*info->fprintf_func) (info->stream, ",db");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'b':
+		      (*info->fprintf_func) (info->stream, ",b");
+		      if (GET_FIELD (insn, 20, 20))
+			(*info->fprintf_func) (info->stream, ",tsv");
+		      break;
+		    case 'T':
+		      if (GET_FIELD (insn, 25, 25))
+			(*info->fprintf_func) (info->stream, ",tc");
+		      break;
+		    case 'S':
+		      /* EXTRD/W has a following condition.  */
+		      if (*(s + 1) == '?')
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   signed_unsigned_names[GET_FIELD (insn, 21, 21)]);
+		      else
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   signed_unsigned_names[GET_FIELD (insn, 21, 21)]);
+		      break;
+		    case 'h':
+		      (*info->fprintf_func)
+			(info->stream, "%s",
+			 mix_half_names[GET_FIELD (insn, 17, 17)]);
+		      break;
+		    case 'H':
+		      (*info->fprintf_func)
+			(info->stream, "%s ",
+			 saturation_names[GET_FIELD (insn, 24, 25)]);
+		      break;
+		    case '*':
+		      (*info->fprintf_func)
+			(info->stream, ",%d%d%d%d ",
+			 GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21),
+			 GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25));
+		      break;
+
+		    case 'q':
+		      {
+			int m, a;
+
+			m = GET_FIELD (insn, 28, 28);
+			a = GET_FIELD (insn, 29, 29);
+
+			if (m && !a)
+			  fputs_filtered (",ma ", info);
+			else if (m && a)
+			  fputs_filtered (",mb ", info);
+			else
+			  fputs_filtered (" ", info);
+			break;
+		      }
+
+		    case 'J':
+		      {
+			int opc = GET_FIELD (insn, 0, 5);
+
+			if (opc == 0x16 || opc == 0x1e)
+			  {
+			    if (GET_FIELD (insn, 29, 29) == 0)
+			      fputs_filtered (",ma ", info);
+			    else
+			      fputs_filtered (",mb ", info);
+			  }
+			else
+			  fputs_filtered (" ", info);
+			break;
+		      }
+
+		    case 'e':
+		      {
+			int opc = GET_FIELD (insn, 0, 5);
+
+			if (opc == 0x13 || opc == 0x1b)
+			  {
+			    if (GET_FIELD (insn, 18, 18) == 1)
+			      fputs_filtered (",mb ", info);
+			    else
+			      fputs_filtered (",ma ", info);
+			  }
+			else if (opc == 0x17 || opc == 0x1f)
+			  {
+			    if (GET_FIELD (insn, 31, 31) == 1)
+			      fputs_filtered (",ma ", info);
+			    else
+			      fputs_filtered (",mb ", info);
+			  }
+			else
+			  fputs_filtered (" ", info);
+
+			break;
+		      }
+		    }
+		  break;
+
+		  /* Handle conditions.  */
+		case '?':
+		  {
+		    s++;
+		    switch (*s)
+		      {
+		      case 'f':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   float_comp_names[GET_FIELD (insn, 27, 31)]);
+			break;
+
+			/* These four conditions are for the set of instructions
+			   which distinguish true/false conditions by opcode
+			   rather than by the 'f' bit (sigh): comb, comib,
+			   addb, addib.  */
+		      case 't':
+			fputs_filtered
+			  (compare_cond_names[GET_FIELD (insn, 16, 18)], info);
+			break;
+		      case 'n':
+			fputs_filtered
+			  (compare_cond_names[GET_FIELD (insn, 16, 18)
+					      + GET_FIELD (insn, 4, 4) * 8],
+			   info);
+			break;
+		      case 'N':
+			fputs_filtered
+			  (compare_cond_64_names[GET_FIELD (insn, 16, 18)
+						 + GET_FIELD (insn, 2, 2) * 8],
+			   info);
+			break;
+		      case 'Q':
+			fputs_filtered
+			  (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)],
+			   info);
+			break;
+		      case '@':
+			fputs_filtered
+			  (add_cond_names[GET_FIELD (insn, 16, 18)
+					  + GET_FIELD (insn, 4, 4) * 8],
+			   info);
+			break;
+		      case 's':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   compare_cond_names[GET_COND (insn)]);
+			break;
+		      case 'S':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   compare_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'a':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   add_cond_names[GET_COND (insn)]);
+			break;
+		      case 'A':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   add_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'd':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   add_cond_names[GET_FIELD (insn, 16, 18)]);
+			break;
+
+		      case 'W':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   wide_add_cond_names[GET_FIELD (insn, 16, 18) +
+					       GET_FIELD (insn, 4, 4) * 8]);
+			break;
+
+		      case 'l':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   logical_cond_names[GET_COND (insn)]);
+			break;
+		      case 'L':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   logical_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'u':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   unit_cond_names[GET_COND (insn)]);
+			break;
+		      case 'U':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   unit_cond_64_names[GET_COND (insn)]);
+			break;
+		      case 'y':
+		      case 'x':
+		      case 'b':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   shift_cond_names[GET_FIELD (insn, 16, 18)]);
+
+			/* If the next character in args is 'n', it will handle
+			   putting out the space.  */
+			if (s[1] != 'n')
+			  (*info->fprintf_func) (info->stream, " ");
+			break;
+		      case 'X':
+			(*info->fprintf_func)
+			  (info->stream, "%s ",
+			   shift_cond_64_names[GET_FIELD (insn, 16, 18)]);
+			break;
+		      case 'B':
+			(*info->fprintf_func)
+			  (info->stream, "%s",
+			   bb_cond_64_names[GET_FIELD (insn, 16, 16)]);
+
+			/* If the next character in args is 'n', it will handle
+			   putting out the space.  */
+			if (s[1] != 'n')
+			  (*info->fprintf_func) (info->stream, " ");
+			break;
+		      }
+		    break;
+		  }
+
+		case 'V':
+		  fput_const (extract_5_store (insn), info);
+		  break;
+		case 'r':
+		  fput_const (extract_5r_store (insn), info);
+		  break;
+		case 'R':
+		  fput_const (extract_5R_store (insn), info);
+		  break;
+		case 'U':
+		  fput_const (extract_10U_store (insn), info);
+		  break;
+		case 'B':
+		case 'Q':
+		  fput_const (extract_5Q_store (insn), info);
+		  break;
+		case 'i':
+		  fput_const (extract_11 (insn), info);
+		  break;
+		case 'j':
+		  fput_const (extract_14 (insn), info);
+		  break;
+		case 'k':
+		  fputs_filtered ("L%", info);
+		  fput_const (extract_21 (insn), info);
+		  break;
+		case '<':
+		case 'l':
+		  /* 16-bit long disp., PA2.0 wide only.  */
+		  fput_const (extract_16 (insn), info);
+		  break;
+		case 'n':
+		  if (insn & 0x2)
+		    (*info->fprintf_func) (info->stream, ",n ");
+		  else
+		    (*info->fprintf_func) (info->stream, " ");
+		  break;
+		case 'N':
+		  if ((insn & 0x20) && s[1])
+		    (*info->fprintf_func) (info->stream, ",n ");
+		  else if (insn & 0x20)
+		    (*info->fprintf_func) (info->stream, ",n");
+		  else if (s[1])
+		    (*info->fprintf_func) (info->stream, " ");
+		  break;
+		case 'w':
+		  (*info->print_address_func)
+		    (memaddr + 8 + extract_12 (insn), info);
+		  break;
+		case 'W':
+		  /* 17 bit PC-relative branch.  */
+		  (*info->print_address_func)
+		    ((memaddr + 8 + extract_17 (insn)), info);
+		  break;
+		case 'z':
+		  /* 17 bit displacement.  This is an offset from a register
+		     so it gets disasssembled as just a number, not any sort
+		     of address.  */
+		  fput_const (extract_17 (insn), info);
+		  break;
+
+		case 'Z':
+		  /* addil %r1 implicit output.  */
+		  fputs_filtered ("r1", info);
+		  break;
+
+		case 'Y':
+		  /* be,l %sr0,%r31 implicit output.  */
+		  fputs_filtered ("sr0,r31", info);
+		  break;
+
+		case '@':
+		  (*info->fprintf_func) (info->stream, "0");
+		  break;
+
+		case '.':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 24, 25));
+		  break;
+		case '*':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 22, 25));
+		  break;
+		case '!':
+		  fputs_filtered ("sar", info);
+		  break;
+		case 'p':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 31 - GET_FIELD (insn, 22, 26));
+		  break;
+		case '~':
+		  {
+		    int num;
+		    num = GET_FIELD (insn, 20, 20) << 5;
+		    num |= GET_FIELD (insn, 22, 26);
+		    (*info->fprintf_func) (info->stream, "%d", 63 - num);
+		    break;
+		  }
+		case 'P':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 GET_FIELD (insn, 22, 26));
+		  break;
+		case 'q':
+		  {
+		    int num;
+		    num = GET_FIELD (insn, 20, 20) << 5;
+		    num |= GET_FIELD (insn, 22, 26);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case 'T':
+		  (*info->fprintf_func) (info->stream, "%d",
+					 32 - GET_FIELD (insn, 27, 31));
+		  break;
+		case '%':
+		  {
+		    int num;
+		    num = (GET_FIELD (insn, 23, 23) + 1) * 32;
+		    num -= GET_FIELD (insn, 27, 31);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case '|':
+		  {
+		    int num;
+		    num = (GET_FIELD (insn, 19, 19) + 1) * 32;
+		    num -= GET_FIELD (insn, 27, 31);
+		    (*info->fprintf_func) (info->stream, "%d", num);
+		    break;
+		  }
+		case '$':
+		  fput_const (GET_FIELD (insn, 20, 28), info);
+		  break;
+		case 'A':
+		  fput_const (GET_FIELD (insn, 6, 18), info);
+		  break;
+		case 'D':
+		  fput_const (GET_FIELD (insn, 6, 31), info);
+		  break;
+		case 'v':
+		  (*info->fprintf_func) (info->stream, ",%d",
+					 GET_FIELD (insn, 23, 25));
+		  break;
+		case 'O':
+		  fput_const ((GET_FIELD (insn, 6,20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case 'o':
+		  fput_const (GET_FIELD (insn, 6, 20), info);
+		  break;
+		case '2':
+		  fput_const ((GET_FIELD (insn, 6, 22) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case '1':
+		  fput_const ((GET_FIELD (insn, 11, 20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case '0':
+		  fput_const ((GET_FIELD (insn, 16, 20) << 5 |
+			       GET_FIELD (insn, 27, 31)), info);
+		  break;
+		case 'u':
+		  (*info->fprintf_func) (info->stream, ",%d",
+					 GET_FIELD (insn, 23, 25));
+		  break;
+		case 'F':
+		  /* If no destination completer and not before a completer
+		     for fcmp, need a space here.  */
+		  if (s[1] == 'G' || s[1] == '?')
+		    fputs_filtered
+		      (float_format_names[GET_FIELD (insn, 19, 20)], info);
+		  else
+		    (*info->fprintf_func)
+		      (info->stream, "%s ",
+		       float_format_names[GET_FIELD (insn, 19, 20)]);
+		  break;
+		case 'G':
+		  (*info->fprintf_func)
+		    (info->stream, "%s ",
+		     float_format_names[GET_FIELD (insn, 17, 18)]);
+		  break;
+		case 'H':
+		  if (GET_FIELD (insn, 26, 26) == 1)
+		    (*info->fprintf_func) (info->stream, "%s ",
+					   float_format_names[0]);
+		  else
+		    (*info->fprintf_func) (info->stream, "%s ",
+					   float_format_names[1]);
+		  break;
+		case 'I':
+		  /* If no destination completer and not before a completer
+		     for fcmp, need a space here.  */
+		  if (s[1] == '?')
+		    fputs_filtered
+		      (float_format_names[GET_FIELD (insn, 20, 20)], info);
+		  else
+		    (*info->fprintf_func)
+		      (info->stream, "%s ",
+		       float_format_names[GET_FIELD (insn, 20, 20)]);
+		  break;
+
+		case 'J':
+		  fput_const (extract_14 (insn), info);
+		  break;
+
+		case '#':
+		  {
+		    int sign = GET_FIELD (insn, 31, 31);
+		    int imm10 = GET_FIELD (insn, 18, 27);
+		    int disp;
+
+		    if (sign)
+		      disp = (-1 << 10) | imm10;
+		    else
+		      disp = imm10;
+
+		    disp <<= 3;
+		    fput_const (disp, info);
+		    break;
+		  }
+		case 'K':
+		case 'd':
+		  {
+		    int sign = GET_FIELD (insn, 31, 31);
+		    int imm11 = GET_FIELD (insn, 18, 28);
+		    int disp;
+
+		    if (sign)
+		      disp = (-1 << 11) | imm11;
+		    else
+		      disp = imm11;
+
+		    disp <<= 2;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '>':
+		case 'y':
+		  {
+		    /* 16-bit long disp., PA2.0 wide only.  */
+		    int disp = extract_16 (insn);
+		    disp &= ~3;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '&':
+		  {
+		    /* 16-bit long disp., PA2.0 wide only.  */
+		    int disp = extract_16 (insn);
+		    disp &= ~7;
+		    fput_const (disp, info);
+		    break;
+		  }
+
+		case '_':
+		  break; /* Dealt with by '{' */
+
+		case '{':
+		  {
+		    int sub = GET_FIELD (insn, 14, 16);
+		    int df = GET_FIELD (insn, 17, 18);
+		    int sf = GET_FIELD (insn, 19, 20);
+		    const char * const * source = float_format_names;
+		    const char * const * dest = float_format_names;
+		    const char *t = "";
+
+		    if (sub == 4)
+		      {
+			fputs_filtered (",UND ", info);
+			break;
+		      }
+		    if ((sub & 3) == 3)
+		      t = ",t";
+		    if ((sub & 3) == 1)
+		      source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names;
+		    if (sub & 2)
+		      dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names;
+
+		    (*info->fprintf_func) (info->stream, "%s%s%s ",
+					   t, source[sf], dest[df]);
+		    break;
+		  }
+
+		case 'm':
+		  {
+		    int y = GET_FIELD (insn, 16, 18);
+
+		    if (y != 1)
+		      fput_const ((y ^ 1) - 1, info);
+		  }
+		  break;
+
+		case 'h':
+		  {
+		    int cbit;
+
+		    cbit = GET_FIELD (insn, 16, 18);
+
+		    if (cbit > 0)
+		      (*info->fprintf_func) (info->stream, ",%d", cbit - 1);
+		    break;
+		  }
+
+		case '=':
+		  {
+		    int cond = GET_FIELD (insn, 27, 31);
+
+		    switch (cond)
+		      {
+		      case  0: fputs_filtered (" ", info); break;
+		      case  1: fputs_filtered ("acc ", info); break;
+		      case  2: fputs_filtered ("rej ", info); break;
+		      case  5: fputs_filtered ("acc8 ", info); break;
+		      case  6: fputs_filtered ("rej8 ", info); break;
+		      case  9: fputs_filtered ("acc6 ", info); break;
+		      case 13: fputs_filtered ("acc4 ", info); break;
+		      case 17: fputs_filtered ("acc2 ", info); break;
+		      default: break;
+		      }
+		    break;
+		  }
+
+		case 'X':
+		  (*info->print_address_func)
+		    (memaddr + 8 + extract_22 (insn), info);
+		  break;
+		case 'L':
+		  fputs_filtered (",rp", info);
+		  break;
+		default:
+		  (*info->fprintf_func) (info->stream, "%c", *s);
+		  break;
+		}
+	    }
+	  return sizeof (insn);
+	}
+    }
+  (*info->fprintf_func) (info->stream, "#%8x", insn);
+  return sizeof (insn);
+}
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 0b15466..7607df8 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2375,8 +2375,8 @@ struct target_flock {
 struct target_flock64 {
     short  l_type;
     short  l_whence;
-#if defined(TARGET_PPC) || defined(TARGET_X86_64) \
-    || defined(TARGET_MIPS) || defined(TARGET_SPARC) \
+#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) \
+    || defined(TARGET_SPARC) || defined(TARGET_HPPA) \
     || defined(TARGET_MICROBLAZE) || defined(TARGET_TILEGX)
     int __pad;
 #endif
-- 
2.9.3

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

* [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 01/26] Revert "Remove remainders of HPPA backend" Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-06-27 16:32   ` Peter Maydell
  2017-01-23  2:17 ` [Qemu-devel] [PULL 03/26] linux-user: Handle TIOCSTART and TIOCSTOP Richard Henderson
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

HPPA is a (the) stack-grows-up target, and supporting that requires
rearranging how we compute addresses while laying out the initial
program stack.  In addition, hppa32 requires 64-byte stack alignment
so parameterize that as well.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c | 235 +++++++++++++++++++++++++++++++++++++--------------
 linux-user/main.c    |  13 +--
 linux-user/qemu.h    |   3 +
 3 files changed, 180 insertions(+), 71 deletions(-)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 547053c..5cea39d 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1231,6 +1231,14 @@ static inline void init_thread(struct target_pt_regs *regs,
 #define ELF_HWCAP 0
 #endif
 
+#ifndef STACK_GROWS_DOWN
+#define STACK_GROWS_DOWN 1
+#endif
+
+#ifndef STACK_ALIGNMENT
+#define STACK_ALIGNMENT 16
+#endif
+
 #ifdef TARGET_ABI32
 #undef ELF_CLASS
 #define ELF_CLASS ELFCLASS32
@@ -1374,45 +1382,78 @@ static abi_ulong copy_elf_strings(int argc, char **argv, char *scratch,
                                   abi_ulong p, abi_ulong stack_limit)
 {
     char *tmp;
-    int len, offset;
+    int len, i;
     abi_ulong top = p;
 
     if (!p) {
         return 0;       /* bullet-proofing */
     }
 
-    offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
+    if (STACK_GROWS_DOWN) {
+        int offset = ((p - 1) % TARGET_PAGE_SIZE) + 1;
+        for (i = argc - 1; i >= 0; --i) {
+            tmp = argv[i];
+            if (!tmp) {
+                fprintf(stderr, "VFS: argc is wrong");
+                exit(-1);
+            }
+            len = strlen(tmp) + 1;
+            tmp += len;
 
-    while (argc-- > 0) {
-        tmp = argv[argc];
-        if (!tmp) {
-            fprintf(stderr, "VFS: argc is wrong");
-            exit(-1);
+            if (len > (p - stack_limit)) {
+                return 0;
+            }
+            while (len) {
+                int bytes_to_copy = (len > offset) ? offset : len;
+                tmp -= bytes_to_copy;
+                p -= bytes_to_copy;
+                offset -= bytes_to_copy;
+                len -= bytes_to_copy;
+
+                memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
+
+                if (offset == 0) {
+                    memcpy_to_target(p, scratch, top - p);
+                    top = p;
+                    offset = TARGET_PAGE_SIZE;
+                }
+            }
         }
-        len = strlen(tmp) + 1;
-        tmp += len;
-
-        if (len > (p - stack_limit)) {
-            return 0;
+        if (p != top) {
+            memcpy_to_target(p, scratch + offset, top - p);
         }
-        while (len) {
-            int bytes_to_copy = (len > offset) ? offset : len;
-            tmp -= bytes_to_copy;
-            p -= bytes_to_copy;
-            offset -= bytes_to_copy;
-            len -= bytes_to_copy;
-
-            memcpy_fromfs(scratch + offset, tmp, bytes_to_copy);
-
-            if (offset == 0) {
-                memcpy_to_target(p, scratch, top - p);
-                top = p;
-                offset = TARGET_PAGE_SIZE;
+    } else {
+        int remaining = TARGET_PAGE_SIZE - (p % TARGET_PAGE_SIZE);
+        for (i = 0; i < argc; ++i) {
+            tmp = argv[i];
+            if (!tmp) {
+                fprintf(stderr, "VFS: argc is wrong");
+                exit(-1);
+            }
+            len = strlen(tmp) + 1;
+            if (len > (stack_limit - p)) {
+                return 0;
+            }
+            while (len) {
+                int bytes_to_copy = (len > remaining) ? remaining : len;
+
+                memcpy_fromfs(scratch + (p - top), tmp, bytes_to_copy);
+
+                tmp += bytes_to_copy;
+                remaining -= bytes_to_copy;
+                p += bytes_to_copy;
+                len -= bytes_to_copy;
+
+                if (remaining == 0) {
+                    memcpy_to_target(top, scratch, p - top);
+                    top = p;
+                    remaining = TARGET_PAGE_SIZE;
+                }
             }
         }
-    }
-    if (offset) {
-        memcpy_to_target(p, scratch + offset, top - p);
+        if (p != top) {
+            memcpy_to_target(top, scratch, p - top);
+        }
     }
 
     return p;
@@ -1447,11 +1488,15 @@ static abi_ulong setup_arg_pages(struct linux_binprm *bprm,
     }
 
     /* We reserve one extra page at the top of the stack as guard.  */
-    target_mprotect(error, guard, PROT_NONE);
-
-    info->stack_limit = error + guard;
-
-    return info->stack_limit + size - sizeof(void *);
+    if (STACK_GROWS_DOWN) {
+        target_mprotect(error, guard, PROT_NONE);
+        info->stack_limit = error + guard;
+        return info->stack_limit + size - sizeof(void *);
+    } else {
+        target_mprotect(error + size, guard, PROT_NONE);
+        info->stack_limit = error + size;
+        return error;
+    }
 }
 
 /* Map and zero the bss.  We need to explicitly zero any fractional pages
@@ -1529,7 +1574,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    struct image_info *interp_info)
 {
     abi_ulong sp;
-    abi_ulong sp_auxv;
+    abi_ulong u_argc, u_argv, u_envp, u_auxv;
     int size;
     int i;
     abi_ulong u_rand_bytes;
@@ -1558,10 +1603,25 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     k_platform = ELF_PLATFORM;
     if (k_platform) {
         size_t len = strlen(k_platform) + 1;
-        sp -= (len + n - 1) & ~(n - 1);
-        u_platform = sp;
-        /* FIXME - check return value of memcpy_to_target() for failure */
-        memcpy_to_target(sp, k_platform, len);
+        if (STACK_GROWS_DOWN) {
+            sp -= (len + n - 1) & ~(n - 1);
+            u_platform = sp;
+            /* FIXME - check return value of memcpy_to_target() for failure */
+            memcpy_to_target(sp, k_platform, len);
+        } else {
+            memcpy_to_target(sp, k_platform, len);
+            u_platform = sp;
+            sp += len + 1;
+        }
+    }
+
+    /* Provide 16 byte alignment for the PRNG, and basic alignment for
+     * the argv and envp pointers.
+     */
+    if (STACK_GROWS_DOWN) {
+        sp = QEMU_ALIGN_DOWN(sp, 16);
+    } else {
+        sp = QEMU_ALIGN_UP(sp, 16);
     }
 
     /*
@@ -1571,15 +1631,17 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     for (i = 0; i < 16; i++) {
         k_rand_bytes[i] = rand();
     }
-    sp -= 16;
-    u_rand_bytes = sp;
-    /* FIXME - check return value of memcpy_to_target() for failure */
-    memcpy_to_target(sp, k_rand_bytes, 16);
+    if (STACK_GROWS_DOWN) {
+        sp -= 16;
+        u_rand_bytes = sp;
+        /* FIXME - check return value of memcpy_to_target() for failure */
+        memcpy_to_target(sp, k_rand_bytes, 16);
+    } else {
+        memcpy_to_target(sp, k_rand_bytes, 16);
+        u_rand_bytes = sp;
+        sp += 16;
+    }
 
-    /*
-     * Force 16 byte _final_ alignment here for generality.
-     */
-    sp = sp &~ (abi_ulong)15;
     size = (DLINFO_ITEMS + 1) * 2;
     if (k_platform)
         size += 2;
@@ -1592,20 +1654,31 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     size += envc + argc + 2;
     size += 1;  /* argc itself */
     size *= n;
-    if (size & 15)
-        sp -= 16 - (size & 15);
+
+    /* Allocate space and finalize stack alignment for entry now.  */
+    if (STACK_GROWS_DOWN) {
+        u_argc = QEMU_ALIGN_DOWN(sp - size, STACK_ALIGNMENT);
+        sp = u_argc;
+    } else {
+        u_argc = sp;
+        sp = QEMU_ALIGN_UP(sp + size, STACK_ALIGNMENT);
+    }
+
+    u_argv = u_argc + n;
+    u_envp = u_argv + (argc + 1) * n;
+    u_auxv = u_envp + (envc + 1) * n;
+    info->saved_auxv = u_auxv;
+    info->arg_start = u_argv;
+    info->arg_end = u_argv + argc * n;
 
     /* This is correct because Linux defines
      * elf_addr_t as Elf32_Off / Elf64_Off
      */
 #define NEW_AUX_ENT(id, val) do {               \
-        sp -= n; put_user_ual(val, sp);         \
-        sp -= n; put_user_ual(id, sp);          \
+        put_user_ual(id, u_auxv);  u_auxv += n; \
+        put_user_ual(val, u_auxv); u_auxv += n; \
     } while(0)
 
-    sp_auxv = sp;
-    NEW_AUX_ENT (AT_NULL, 0);
-
     /* There must be exactly DLINFO_ITEMS entries here.  */
     NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
     NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
@@ -1626,8 +1699,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
 #endif
 
-    if (k_platform)
+    if (u_platform) {
         NEW_AUX_ENT(AT_PLATFORM, u_platform);
+    }
 #ifdef ARCH_DLINFO
     /*
      * ARCH_DLINFO must come last so platform specific code can enforce
@@ -1635,14 +1709,29 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
      */
     ARCH_DLINFO;
 #endif
+    NEW_AUX_ENT (AT_NULL, 0);
 #undef NEW_AUX_ENT
 
-    info->saved_auxv = sp;
-    info->auxv_len = sp_auxv - sp;
+    info->auxv_len = u_argv - info->saved_auxv;
+
+    put_user_ual(argc, u_argc);
+
+    p = info->arg_strings;
+    for (i = 0; i < argc; ++i) {
+        put_user_ual(p, u_argv);
+        u_argv += n;
+        p += target_strlen(p) + 1;
+    }
+    put_user_ual(0, u_argv);
+
+    p = info->env_strings;
+    for (i = 0; i < envc; ++i) {
+        put_user_ual(p, u_envp);
+        u_envp += n;
+        p += target_strlen(p) + 1;
+    }
+    put_user_ual(0, u_envp);
 
-    sp = loader_build_argptr(envc, argc, sp, p, 0);
-    /* Check the right amount of stack was allocated for auxvec, envp & argv. */
-    assert(sp_auxv - sp == size);
     return sp;
 }
 
@@ -2213,12 +2302,28 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
     bprm->p = setup_arg_pages(bprm, info);
 
     scratch = g_new0(char, TARGET_PAGE_SIZE);
-    bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
-                               bprm->p, info->stack_limit);
-    bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
-                               bprm->p, info->stack_limit);
-    bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
-                               bprm->p, info->stack_limit);
+    if (STACK_GROWS_DOWN) {
+        bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
+                                   bprm->p, info->stack_limit);
+        info->file_string = bprm->p;
+        bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
+                                   bprm->p, info->stack_limit);
+        info->env_strings = bprm->p;
+        bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
+                                   bprm->p, info->stack_limit);
+        info->arg_strings = bprm->p;
+    } else {
+        info->arg_strings = bprm->p;
+        bprm->p = copy_elf_strings(bprm->argc, bprm->argv, scratch,
+                                   bprm->p, info->stack_limit);
+        info->env_strings = bprm->p;
+        bprm->p = copy_elf_strings(bprm->envc, bprm->envp, scratch,
+                                   bprm->p, info->stack_limit);
+        info->file_string = bprm->p;
+        bprm->p = copy_elf_strings(1, &bprm->filename, scratch,
+                                   bprm->p, info->stack_limit);
+    }
+
     g_free(scratch);
 
     if (!bprm->p) {
diff --git a/linux-user/main.c b/linux-user/main.c
index 94a636f..aae29bd 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -4179,15 +4179,16 @@ int main(int argc, char **argv, char **envp)
 
         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
-        qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
-                 info->start_code);
-        qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
-                 info->start_data);
+        qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n", info->start_code);
+        qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n", info->start_data);
         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
-        qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
-                 info->start_stack);
+        qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", info->start_stack);
         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
+        qemu_log("argv_start  0x" TARGET_ABI_FMT_lx "\n", info->arg_start);
+        qemu_log("env_start   0x" TARGET_ABI_FMT_lx "\n",
+                 info->arg_end + (abi_ulong)sizeof(abi_ulong));
+        qemu_log("auxv_start  0x" TARGET_ABI_FMT_lx "\n", info->saved_auxv);
     }
 
     target_set_brk(info->brk);
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index da73a01..4edd7d0 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -48,6 +48,9 @@ struct image_info {
         abi_ulong       auxv_len;
         abi_ulong       arg_start;
         abi_ulong       arg_end;
+        abi_ulong       arg_strings;
+        abi_ulong       env_strings;
+        abi_ulong       file_string;
         uint32_t        elf_flags;
 	int		personality;
 #ifdef CONFIG_USE_FDPIC
-- 
2.9.3

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

* [Qemu-devel] [PULL 03/26] linux-user: Handle TIOCSTART and TIOCSTOP
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 01/26] Revert "Remove remainders of HPPA backend" Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 04/26] linux-user: Add SIOCGPGRP, SIOCGSTAMP, SIOCGSTAMPNS Richard Henderson
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Helge Deller

From: Helge Deller <deller@gmx.de>

Some architectures (ppc, alpha, sparc, parisc, sh and xtensa) define the
BSD TIOCSTART and TIOCSTOP ioctls in their kernel headers to provide
compatibility to other operating systems.

Those ioctls are not implemented in Linux, nevertheless, bash will use
this ioctl if it's available on those architectures.

To avoid false warnings, add code to simply ignore those ioctls.

Signed-off-by: Helge Deller <deller@gmx.de>
Message-Id: <20161206152403.GA6651@ls3530>
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/ioctls.h  | 5 +++++
 linux-user/syscall.c | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index 1bad701..eaf6fe6 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -422,3 +422,8 @@
                 MK_PTR(MK_STRUCT(STRUCT_rtentry)))
   IOCTL_SPECIAL(SIOCDELRT, IOC_W, do_ioctl_rt,
                 MK_PTR(MK_STRUCT(STRUCT_rtentry)))
+
+#ifdef TARGET_TIOCSTART
+  IOCTL_IGNORE(TIOCSTART)
+  IOCTL_IGNORE(TIOCSTOP)
+#endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7b77503..acb004f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5453,6 +5453,8 @@ static IOCTLEntry ioctl_entries[] = {
     { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
 #define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
     { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
+#define IOCTL_IGNORE(cmd) \
+    { TARGET_ ## cmd, 0, #cmd },
 #include "ioctls.h"
     { 0, 0, },
 };
@@ -5484,6 +5486,10 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
 #endif
     if (ie->do_ioctl) {
         return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
+    } else if (!ie->host_cmd) {
+        /* Some architectures define BSD ioctls in their headers
+           that are not implemented in Linux.  */
+        return -TARGET_ENOSYS;
     }
 
     switch(arg_type[0]) {
-- 
2.9.3

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

* [Qemu-devel] [PULL 04/26] linux-user: Add SIOCGPGRP, SIOCGSTAMP, SIOCGSTAMPNS
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (2 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 03/26] linux-user: Handle TIOCSTART and TIOCSTOP Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 05/26] linux-user: Handle ERFKILL and EHWPOISON Richard Henderson
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell, Helge Deller

From: Helge Deller <deller@gmx.de>

Mirror syscall_defs.h for the element type of struct timeval
and struct timespec, even though that's not 100% accurate for
each guest.

Signed-off-by: Helge Deller <deller@gmx.de>
[rth: Changed the MK_ARRAY types as per above; added ioctl.h entries.]
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/ioctls.h        | 3 +++
 linux-user/syscall_defs.h  | 4 ++++
 linux-user/syscall_types.h | 6 ++++++
 3 files changed, 13 insertions(+)

diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index eaf6fe6..2f6e85b 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -164,6 +164,9 @@
   IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
   IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
   IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
+  IOCTL(SIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) /* pid_t */
+  IOCTL(SIOCGSTAMP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timeval)))
+  IOCTL(SIOCGSTAMPNS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timespec)))
 
   IOCTL(CDROMPAUSE, 0, TYPE_NULL)
   IOCTL(CDROMSTART, 0, TYPE_NULL)
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 7607df8..55ae367 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -930,9 +930,13 @@ struct target_pollfd {
 
 #if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SH4)
 #define TARGET_SIOCATMARK      TARGET_IOR('s', 7, int)
+#define TARGET_SIOCGPGRP       TARGET_IOR('s', 9, pid_t)
 #else
 #define TARGET_SIOCATMARK      0x8905
+#define TARGET_SIOCGPGRP       0x8904
 #endif
+#define TARGET_SIOCGSTAMP      0x8906          /* Get stamp (timeval) */
+#define TARGET_SIOCGSTAMPNS    0x8907          /* Get stamp (timespec) */
 
 /* Networking ioctls */
 #define TARGET_SIOCADDRT       0x890B          /* add routing table entry */
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index af79fbf..2b8c0c6 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -14,6 +14,12 @@ STRUCT(serial_icounter_struct,
 STRUCT(sockaddr,
        TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14))
 
+STRUCT(timeval,
+       MK_ARRAY(TYPE_LONG, 2))
+
+STRUCT(timespec,
+       MK_ARRAY(TYPE_LONG, 2))
+
 STRUCT(rtentry,
        TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr),
        TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID,
-- 
2.9.3

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

* [Qemu-devel] [PULL 05/26] linux-user: Handle ERFKILL and EHWPOISON
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (3 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 04/26] linux-user: Add SIOCGPGRP, SIOCGSTAMP, SIOCGSTAMPNS Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 06/26] linux-user: Handle more IPV6 sockopts Richard Henderson
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

With definitions for generic, alpha and mips taken from 4.9-rc2.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/alpha/target_syscall.h  | 2 ++
 linux-user/errno_defs.h            | 3 +++
 linux-user/mips/target_syscall.h   | 5 +++++
 linux-user/mips64/target_syscall.h | 5 +++++
 linux-user/syscall.c               | 6 ++++++
 5 files changed, 21 insertions(+)

diff --git a/linux-user/alpha/target_syscall.h b/linux-user/alpha/target_syscall.h
index b580fc5..3426cc5 100644
--- a/linux-user/alpha/target_syscall.h
+++ b/linux-user/alpha/target_syscall.h
@@ -235,6 +235,8 @@ struct target_pt_regs {
 #define TARGET_ENOTRECOVERABLE	137
 #undef TARGET_ERFKILL
 #define TARGET_ERFKILL		138
+#undef TARGET_EHWPOISON
+#define TARGET_EHWPOISON        139
 
 // For sys_osf_getsysinfo
 #define TARGET_GSI_UACPROC		8
diff --git a/linux-user/errno_defs.h b/linux-user/errno_defs.h
index 65522c4..55fbebd 100644
--- a/linux-user/errno_defs.h
+++ b/linux-user/errno_defs.h
@@ -140,6 +140,9 @@
 #define TARGET_EOWNERDEAD      130     /* Owner died */
 #define TARGET_ENOTRECOVERABLE 131     /* State not recoverable */
 
+#define TARGET_ERFKILL         132     /* Operation not possible due to RF-kill */
+#define TARGET_EHWPOISON       133     /* Memory page has hardware error */
+
 /* QEMU internal, not visible to the guest. This is returned when a
  * system call should be restarted, to tell the main loop that it
  * should wind the guest PC backwards so it will re-execute the syscall
diff --git a/linux-user/mips/target_syscall.h b/linux-user/mips/target_syscall.h
index 0b64b73..2fca1c6 100644
--- a/linux-user/mips/target_syscall.h
+++ b/linux-user/mips/target_syscall.h
@@ -221,6 +221,11 @@ struct target_pt_regs {
 #undef TARGET_ENOTRECOVERABLE
 #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
 
+#undef TARGET_ERFKILL
+#define TARGET_ERFKILL         167
+#undef TARGET_EHWPOISON
+#define TARGET_EHWPOISON       168
+
 #undef TARGET_EDQUOT
 #define TARGET_EDQUOT          1133    /* Quota exceeded */
 
diff --git a/linux-user/mips64/target_syscall.h b/linux-user/mips64/target_syscall.h
index 6692917..078437d 100644
--- a/linux-user/mips64/target_syscall.h
+++ b/linux-user/mips64/target_syscall.h
@@ -218,6 +218,11 @@ struct target_pt_regs {
 #undef TARGET_ENOTRECOVERABLE
 #define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
 
+#undef TARGET_ERFKILL
+#define TARGET_ERFKILL         167
+#undef TARGET_EHWPOISON
+#define TARGET_EHWPOISON       168
+
 #undef TARGET_EDQUOT
 #define TARGET_EDQUOT          1133    /* Quota exceeded */
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index acb004f..11a311f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -798,6 +798,12 @@ static uint16_t host_to_target_errno_table[ERRNO_TABLE_SIZE] = {
 #ifdef ENOMSG
     [ENOMSG]            = TARGET_ENOMSG,
 #endif
+#ifdef ERKFILL
+    [ERFKILL]           = TARGET_ERFKILL,
+#endif
+#ifdef EHWPOISON
+    [EHWPOISON]         = TARGET_EHWPOISON,
+#endif
 };
 
 static inline int host_to_target_errno(int err)
-- 
2.9.3

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

* [Qemu-devel] [PULL 06/26] linux-user: Handle more IPV6 sockopts
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (4 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 05/26] linux-user: Handle ERFKILL and EHWPOISON Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 08/26] linux-user: Add HPPA socket.h definitions Richard Henderson
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

All of the ones added have an "int" parameter that
needs no more adjustment to pass on to the host.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/syscall.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 11a311f..0b2b283 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2811,10 +2811,35 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
         break;
     case SOL_IPV6:
         switch (optname) {
-        case IPV6_MTU_DISCOVER:
-        case IPV6_MTU:
         case IPV6_V6ONLY:
         case IPV6_RECVPKTINFO:
+        case IPV6_2292PKTINFO:
+        case IPV6_RECVHOPLIMIT:
+        case IPV6_2292HOPLIMIT:
+        case IPV6_RECVRTHDR:
+        case IPV6_2292RTHDR:
+        case IPV6_RECVHOPOPTS:
+        case IPV6_2292HOPOPTS:
+        case IPV6_RECVDSTOPTS:
+        case IPV6_2292DSTOPTS:
+        case IPV6_TCLASS:
+        case IPV6_RECVTCLASS:
+        case IPV6_RECVPATHMTU:
+        case IPV6_TRANSPARENT:
+        case IPV6_RECVORIGDSTADDR:
+        case IPV6_UNICAST_HOPS:
+        case IPV6_MULTICAST_HOPS:
+        case IPV6_MULTICAST_LOOP:
+        case IPV6_UNICAST_IF:
+        case IPV6_MULTICAST_IF:
+        case IPV6_ROUTER_ALERT:
+        case IPV6_MTU_DISCOVER:
+        case IPV6_MTU:
+        case IPV6_RECVERR:
+        case IPV6_ADDR_PREFERENCES:
+        case IPV6_MINHOPCOUNT:
+        case IPV6_DONTFRAG:
+        case IPV6_AUTOFLOWLABEL:
             val = 0;
             if (optlen < sizeof(uint32_t)) {
                 return -TARGET_EINVAL;
-- 
2.9.3

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

* [Qemu-devel] [PULL 08/26] linux-user: Add HPPA socket.h definitions
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (5 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 06/26] linux-user: Handle more IPV6 sockopts Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 09/26] linux-user: Add HPPA syscall numbers Richard Henderson
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Split this out into a "cpu/sockbits.h" file now,
like we ought to do for all of the other targets.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/sockbits.h | 97 ++++++++++++++++++++++++++++++++++++++++++++++
 linux-user/socket.h        |  2 +
 2 files changed, 99 insertions(+)
 create mode 100644 linux-user/hppa/sockbits.h

diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h
new file mode 100644
index 0000000..5044619
--- /dev/null
+++ b/linux-user/hppa/sockbits.h
@@ -0,0 +1,97 @@
+#define TARGET_SOL_SOCKET      0xffff
+
+#define TARGET_SO_DEBUG        0x0001
+#define TARGET_SO_REUSEADDR    0x0004
+#define TARGET_SO_KEEPALIVE    0x0008
+#define TARGET_SO_DONTROUTE    0x0010
+#define TARGET_SO_BROADCAST    0x0020
+#define TARGET_SO_LINGER       0x0080
+#define TARGET_SO_OOBINLINE    0x0100
+#define TARGET_SO_REUSEPORT    0x0200
+#define TARGET_SO_SNDBUF       0x1001
+#define TARGET_SO_RCVBUF       0x1002
+#define TARGET_SO_SNDBUFFORCE  0x100a
+#define TARGET_SO_RCVBUFFORCE  0x100b
+#define TARGET_SO_SNDLOWAT     0x1003
+#define TARGET_SO_RCVLOWAT     0x1004
+#define TARGET_SO_SNDTIMEO     0x1005
+#define TARGET_SO_RCVTIMEO     0x1006
+#define TARGET_SO_ERROR        0x1007
+#define TARGET_SO_TYPE         0x1008
+#define TARGET_SO_PROTOCOL     0x1028
+#define TARGET_SO_DOMAIN       0x1029
+#define TARGET_SO_PEERNAME     0x2000
+#define TARGET_SO_NO_CHECK     0x400b
+#define TARGET_SO_PRIORITY     0x400c
+#define TARGET_SO_BSDCOMPAT    0x400e
+#define TARGET_SO_PASSCRED     0x4010
+#define TARGET_SO_PEERCRED     0x4011
+#define TARGET_SO_TIMESTAMP    0x4012
+#define TARGET_SCM_TIMESTAMP   TARGET_SO_TIMESTAMP
+#define TARGET_SO_TIMESTAMPNS  0x4013
+#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS
+
+#define TARGET_SO_SECURITY_AUTHENTICATION              0x4016
+#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT        0x4017
+#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK          0x4018
+
+#define TARGET_SO_BINDTODEVICE         0x4019
+#define TARGET_SO_ATTACH_FILTER        0x401a
+#define TARGET_SO_DETACH_FILTER        0x401b
+#define TARGET_SO_GET_FILTER           TARGET_SO_ATTACH_FILTER
+#define TARGET_SO_ACCEPTCONN           0x401c
+#define TARGET_SO_PEERSEC              0x401d
+#define TARGET_SO_PASSSEC              0x401e
+#define TARGET_SO_MARK                 0x401f
+#define TARGET_SO_TIMESTAMPING         0x4020
+#define TARGET_SCM_TIMESTAMPING        TARGET_SO_TIMESTAMPING
+#define TARGET_SO_RXQ_OVFL             0x4021
+#define TARGET_SO_WIFI_STATUS          0x4022
+#define TARGET_SCM_WIFI_STATUS         TARGET_SO_WIFI_STATUS
+#define TARGET_SO_PEEK_OFF             0x4023
+#define TARGET_SO_NOFCS                0x4024
+#define TARGET_SO_LOCK_FILTER          0x4025
+#define TARGET_SO_SELECT_ERR_QUEUE     0x4026
+#define TARGET_SO_BUSY_POLL            0x4027
+#define TARGET_SO_MAX_PACING_RATE      0x4028
+#define TARGET_SO_BPF_EXTENSIONS       0x4029
+#define TARGET_SO_INCOMING_CPU         0x402A
+#define TARGET_SO_ATTACH_BPF           0x402B
+#define TARGET_SO_DETACH_BPF           TARGET_SO_DETACH_FILTER
+
+#define TARGET_SO_ATTACH_REUSEPORT_CBPF        0x402C
+#define TARGET_SO_ATTACH_REUSEPORT_EBPF        0x402D
+
+#define TARGET_SO_CNX_ADVICE           0x402E
+
+/** sock_type - Socket types - default values
+ *
+ *
+ * @SOCK_STREAM - stream (connection) socket
+ * @SOCK_DGRAM - datagram (conn.less) socket
+ * @SOCK_RAW - raw socket
+ * @SOCK_RDM - reliably-delivered message
+ * @SOCK_SEQPACKET - sequential packet socket
+ * @SOCK_DCCP - Datagram Congestion Control Protocol socket
+ * @SOCK_PACKET - linux specific way of getting packets at the dev level.
+ *                For writing rarp and other similar things on the user
+ *                level.
+ * @SOCK_CLOEXEC - sets the close-on-exec (FD_CLOEXEC) flag.
+ * @SOCK_NONBLOCK - sets the O_NONBLOCK file status flag.
+ */
+enum sock_type {
+   TARGET_SOCK_STREAM      = 1,
+   TARGET_SOCK_DGRAM       = 2,
+   TARGET_SOCK_RAW         = 3,
+   TARGET_SOCK_RDM         = 4,
+   TARGET_SOCK_SEQPACKET   = 5,
+   TARGET_SOCK_DCCP        = 6,
+   TARGET_SOCK_PACKET      = 10,
+   TARGET_SOCK_CLOEXEC     = 010000000,
+   TARGET_SOCK_NONBLOCK    = 0x40000000,
+};
+
+#define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
+#define TARGET_SOCK_TYPE_MASK    0xf  /* Covers up to TARGET_SOCK_MAX-1. */
+
+#define ARCH_HAS_SOCKET_TYPES 1
diff --git a/linux-user/socket.h b/linux-user/socket.h
index 4dacae6..7051cd2 100644
--- a/linux-user/socket.h
+++ b/linux-user/socket.h
@@ -205,6 +205,8 @@
 
     #define TARGET_SOCK_MAX (TARGET_SOCK_PACKET + 1)
     #define TARGET_SOCK_TYPE_MASK    0xf  /* Covers up to TARGET_SOCK_MAX-1. */
+#elif defined(TARGET_HPPA)
+#include <hppa/sockbits.h>
 #else
 
 #if defined(TARGET_SPARC)
-- 
2.9.3

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

* [Qemu-devel] [PULL 09/26] linux-user: Add HPPA syscall numbers
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (6 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 08/26] linux-user: Add HPPA socket.h definitions Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 10/26] linux-user: Add HPPA termbits.h Richard Henderson
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/syscall_nr.h | 353 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 353 insertions(+)
 create mode 100644 linux-user/hppa/syscall_nr.h

diff --git a/linux-user/hppa/syscall_nr.h b/linux-user/hppa/syscall_nr.h
new file mode 100644
index 0000000..0f396fa
--- /dev/null
+++ b/linux-user/hppa/syscall_nr.h
@@ -0,0 +1,353 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_restart_syscall 0
+#define TARGET_NR_exit            1
+#define TARGET_NR_fork            2
+#define TARGET_NR_read            3
+#define TARGET_NR_write           4
+#define TARGET_NR_open            5
+#define TARGET_NR_close           6
+#define TARGET_NR_waitpid         7
+#define TARGET_NR_creat           8
+#define TARGET_NR_link            9
+#define TARGET_NR_unlink         10
+#define TARGET_NR_execve         11
+#define TARGET_NR_chdir          12
+#define TARGET_NR_time           13
+#define TARGET_NR_mknod          14
+#define TARGET_NR_chmod          15
+#define TARGET_NR_lchown         16
+#define TARGET_NR_socket         17
+#define TARGET_NR_stat           18
+#define TARGET_NR_lseek          19
+#define TARGET_NR_getpid         20
+#define TARGET_NR_mount          21
+#define TARGET_NR_bind           22
+#define TARGET_NR_setuid         23
+#define TARGET_NR_getuid         24
+#define TARGET_NR_stime          25
+#define TARGET_NR_ptrace         26
+#define TARGET_NR_alarm          27
+#define TARGET_NR_fstat          28
+#define TARGET_NR_pause          29
+#define TARGET_NR_utime          30
+#define TARGET_NR_connect        31
+#define TARGET_NR_listen         32
+#define TARGET_NR_access         33
+#define TARGET_NR_nice           34
+#define TARGET_NR_accept         35
+#define TARGET_NR_sync           36
+#define TARGET_NR_kill           37
+#define TARGET_NR_rename         38
+#define TARGET_NR_mkdir          39
+#define TARGET_NR_rmdir          40
+#define TARGET_NR_dup            41
+#define TARGET_NR_pipe           42
+#define TARGET_NR_times          43
+#define TARGET_NR_getsockname    44
+#define TARGET_NR_brk            45
+#define TARGET_NR_setgid         46
+#define TARGET_NR_getgid         47
+#define TARGET_NR_signal         48
+#define TARGET_NR_geteuid        49
+#define TARGET_NR_getegid        50
+#define TARGET_NR_acct           51
+#define TARGET_NR_umount2        52
+#define TARGET_NR_getpeername    53
+#define TARGET_NR_ioctl          54
+#define TARGET_NR_fcntl          55
+#define TARGET_NR_socketpair     56
+#define TARGET_NR_setpgid        57
+#define TARGET_NR_send           58
+#define TARGET_NR_uname          59
+#define TARGET_NR_umask          60
+#define TARGET_NR_chroot         61
+#define TARGET_NR_ustat          62
+#define TARGET_NR_dup2           63
+#define TARGET_NR_getppid        64
+#define TARGET_NR_getpgrp        65
+#define TARGET_NR_setsid         66
+#define TARGET_NR_pivot_root     67
+#define TARGET_NR_sgetmask       68
+#define TARGET_NR_ssetmask       69
+#define TARGET_NR_setreuid       70
+#define TARGET_NR_setregid       71
+#define TARGET_NR_mincore        72
+#define TARGET_NR_sigpending     73
+#define TARGET_NR_sethostname    74
+#define TARGET_NR_setrlimit      75
+#define TARGET_NR_getrlimit      76
+#define TARGET_NR_getrusage      77
+#define TARGET_NR_gettimeofday   78
+#define TARGET_NR_settimeofday   79
+#define TARGET_NR_getgroups      80
+#define TARGET_NR_setgroups      81
+#define TARGET_NR_sendto         82
+#define TARGET_NR_symlink        83
+#define TARGET_NR_lstat          84
+#define TARGET_NR_readlink       85
+#define TARGET_NR_uselib         86
+#define TARGET_NR_swapon         87
+#define TARGET_NR_reboot         88
+#define TARGET_NR_mmap2          89
+#define TARGET_NR_mmap           90
+#define TARGET_NR_munmap         91
+#define TARGET_NR_truncate       92
+#define TARGET_NR_ftruncate      93
+#define TARGET_NR_fchmod         94
+#define TARGET_NR_fchown         95
+#define TARGET_NR_getpriority    96
+#define TARGET_NR_setpriority    97
+#define TARGET_NR_recv           98
+#define TARGET_NR_statfs         99
+#define TARGET_NR_fstatfs       100
+#define TARGET_NR_stat64        101
+#define TARGET_NR_socketcall    102
+#define TARGET_NR_syslog        103
+#define TARGET_NR_setitimer     104
+#define TARGET_NR_getitimer     105
+#define TARGET_NR_capget        106
+#define TARGET_NR_capset        107
+#define TARGET_NR_pread64       108
+#define TARGET_NR_pwrite64      109
+#define TARGET_NR_getcwd        110
+#define TARGET_NR_vhangup       111
+#define TARGET_NR_fstat64       112
+#define TARGET_NR_vfork         113
+#define TARGET_NR_wait4         114
+#define TARGET_NR_swapoff       115
+#define TARGET_NR_sysinfo       116
+#define TARGET_NR_shutdown      117
+#define TARGET_NR_fsync         118
+#define TARGET_NR_madvise       119
+#define TARGET_NR_clone         120
+#define TARGET_NR_setdomainname 121
+#define TARGET_NR_sendfile      122
+#define TARGET_NR_recvfrom      123
+#define TARGET_NR_adjtimex      124
+#define TARGET_NR_mprotect      125
+#define TARGET_NR_sigprocmask   126
+#define TARGET_NR_create_module 127
+#define TARGET_NR_init_module   128
+#define TARGET_NR_delete_module 129
+#define TARGET_NR_get_kernel_syms 130
+#define TARGET_NR_quotactl      131
+#define TARGET_NR_getpgid       132
+#define TARGET_NR_fchdir        133
+#define TARGET_NR_bdflush       134
+#define TARGET_NR_sysfs         135
+#define TARGET_NR_personality   136
+#define TARGET_NR_afs_syscall   137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid      138
+#define TARGET_NR_setfsgid      139
+#define TARGET_NR__llseek       140
+#define TARGET_NR_getdents      141
+#define TARGET_NR__newselect    142
+#define TARGET_NR_flock         143
+#define TARGET_NR_msync         144
+#define TARGET_NR_readv         145
+#define TARGET_NR_writev        146
+#define TARGET_NR_getsid        147
+#define TARGET_NR_fdatasync     148
+#define TARGET_NR__sysctl       149
+#define TARGET_NR_mlock         150
+#define TARGET_NR_munlock       151
+#define TARGET_NR_mlockall      152
+#define TARGET_NR_munlockall    153
+#define TARGET_NR_sched_setparam          154
+#define TARGET_NR_sched_getparam          155
+#define TARGET_NR_sched_setscheduler      156
+#define TARGET_NR_sched_getscheduler      157
+#define TARGET_NR_sched_yield             158
+#define TARGET_NR_sched_get_priority_max  159
+#define TARGET_NR_sched_get_priority_min  160
+#define TARGET_NR_sched_rr_get_interval   161
+#define TARGET_NR_nanosleep     162
+#define TARGET_NR_mremap        163
+#define TARGET_NR_setresuid     164
+#define TARGET_NR_getresuid     165
+#define TARGET_NR_sigaltstack   166
+#define TARGET_NR_query_module  167
+#define TARGET_NR_poll          168
+#define TARGET_NR_nfsservctl    169
+#define TARGET_NR_setresgid     170
+#define TARGET_NR_getresgid     171
+#define TARGET_NR_prctl         172
+#define TARGET_NR_rt_sigreturn          173
+#define TARGET_NR_rt_sigaction          174
+#define TARGET_NR_rt_sigprocmask        175
+#define TARGET_NR_rt_sigpending         176
+#define TARGET_NR_rt_sigtimedwait       177
+#define TARGET_NR_rt_sigqueueinfo       178
+#define TARGET_NR_rt_sigsuspend         179
+#define TARGET_NR_chown         180
+#define TARGET_NR_setsockopt    181
+#define TARGET_NR_getsockopt    182
+#define TARGET_NR_sendmsg       183
+#define TARGET_NR_recvmsg       184
+#define TARGET_NR_semop         185
+#define TARGET_NR_semget        186
+#define TARGET_NR_semctl        187
+#define TARGET_NR_msgsnd        188
+#define TARGET_NR_msgrcv        189
+#define TARGET_NR_msgget        190
+#define TARGET_NR_msgctl        191
+#define TARGET_NR_shmat         192
+#define TARGET_NR_shmdt         193
+#define TARGET_NR_shmget        194
+#define TARGET_NR_shmctl        195
+#define TARGET_NR_getpmsg       196
+#define TARGET_NR_putpmsg       197
+#define TARGET_NR_lstat64       198
+#define TARGET_NR_truncate64    199
+#define TARGET_NR_ftruncate64   200
+#define TARGET_NR_getdents64    201
+#define TARGET_NR_fcntl64       202
+#define TARGET_NR_attrctl       203
+#define TARGET_NR_acl_get       204
+#define TARGET_NR_acl_set       205
+#define TARGET_NR_gettid        206
+#define TARGET_NR_readahead     207
+#define TARGET_NR_tkill         208
+#define TARGET_NR_sendfile64    209
+#define TARGET_NR_futex         210
+#define TARGET_NR_sched_setaffinity 211
+#define TARGET_NR_sched_getaffinity 212
+#define TARGET_NR_set_thread_area   213
+#define TARGET_NR_get_thread_area   214
+#define TARGET_NR_io_setup          215
+#define TARGET_NR_io_destroy        216
+#define TARGET_NR_io_getevents      217
+#define TARGET_NR_io_submit         218
+#define TARGET_NR_io_cancel         219
+#define TARGET_NR_alloc_hugepages   220
+#define TARGET_NR_free_hugepages    221
+#define TARGET_NR_exit_group        222
+#define TARGET_NR_lookup_dcookie    223
+#define TARGET_NR_epoll_create      224
+#define TARGET_NR_epoll_ctl         225
+#define TARGET_NR_epill_wait        226
+#define TARGET_NR_remap_file_pages  227
+#define TARGET_NR_semtimedop        228
+#define TARGET_NR_mq_open           229
+#define TARGET_NR_mq_unlink         230
+#define TARGET_NR_mq_timedsend      231
+#define TARGET_NR_mq_timedreceive   232
+#define TARGET_NR_mq_notify         233
+#define TARGET_NR_mq_getsetattr     234
+#define TARGET_NR_waitid            235
+#define TARGET_NR_fadvise64_64      236
+#define TARGET_NR_set_tid_address   237
+#define TARGET_NR_setxattr          238
+#define TARGET_NR_lsetxattr         239
+#define TARGET_NR_fsetxattr         240
+#define TARGET_NR_getxattr          241
+#define TARGET_NR_lgetxattr         242
+#define TARGET_NR_fgetxattr         243
+#define TARGET_NR_listxattr         244
+#define TARGET_NR_llistxattr        245
+#define TARGET_NR_flistxattr        246
+#define TARGET_NR_removexattr       247
+#define TARGET_NR_lremovexattr      248
+#define TARGET_NR_fremovexattr      249
+#define TARGET_NR_timer_create      250
+#define TARGET_NR_timer_settime     251
+#define TARGET_NR_timer_gettime     252
+#define TARGET_NR_timer_getoverrun  253
+#define TARGET_NR_timer_delete      254
+#define TARGET_NR_clock_settime     255
+#define TARGET_NR_clock_gettime     256
+#define TARGET_NR_clock_getres      257
+#define TARGET_NR_clock_nanosleep   258
+#define TARGET_NR_tgkill            259
+#define TARGET_NR_mbind             260
+#define TARGET_NR_get_mempolicy     261
+#define TARGET_NR_set_mempolicy     262
+#define TARGET_NR_vserver           263
+#define TARGET_NR_add_key           264
+#define TARGET_NR_request_key       265
+#define TARGET_NR_keyctl            266
+#define TARGET_NR_ioprio_set        267
+#define TARGET_NR_ioprio_get        268
+#define TARGET_NR_inotify_init      269
+#define TARGET_NR_inotify_add_watch 270
+#define TARGET_NR_inotify_rm_watch  271
+#define TARGET_NR_migrate_pages     272
+#define TARGET_NR_pselect6          273
+#define TARGET_NR_ppoll             274
+#define TARGET_NR_openat            275
+#define TARGET_NR_mkdirat           276
+#define TARGET_NR_mknotat           277
+#define TARGET_NR_fchownat          278
+#define TARGET_NR_futimesat         279
+#define TARGET_NR_fstatat64         280
+#define TARGET_NR_unlinkat          281
+#define TARGET_NR_renameat          282
+#define TARGET_NR_linkat            283
+#define TARGET_NR_symlinkat         284
+#define TARGET_NR_readlinkat        285
+#define TARGET_NR_fchmodat          286
+#define TARGET_NR_faccessat         287
+#define TARGET_NR_unshare           288
+#define TARGET_NR_set_robust_list   289
+#define TARGET_NR_get_robust_list   290
+#define TARGET_NR_splice            291
+#define TARGET_NR_sync_file_range   292
+#define TARGET_NR_tee               293
+#define TARGET_NR_vmsplice          294
+#define TARGET_NR_move_pages        295
+#define TARGET_NR_getcpu            296
+#define TARGET_NR_epoll_pwait       297
+#define TARGET_NR_statfs64          298
+#define TARGET_NR_fstatfs64         299
+#define TARGET_NR_kexec_load        300
+#define TARGET_NR_utimensat         301
+#define TARGET_NR_signalfd          302
+#define TARGET_NR_timerfd           303
+#define TARGET_NR_eventfd           304
+#define TARGET_NR_fallocate         305
+#define TARGET_NR_timerfd_create    306
+#define TARGET_NR_timerfd_settime   307
+#define TARGET_NR_timerfd_gettime   308
+#define TARGET_NR_signalfd4         309
+#define TARGET_NR_eventfd2          310
+#define TARGET_NR_epoll_create1     311
+#define TARGET_NR_dup3              312
+#define TARGET_NR_pipe2             313
+#define TARGET_NR_inotify_init1     314
+#define TARGET_NR_preadv            315
+#define TARGET_NR_pwritev           316
+#define TARGET_NR_rt_tgsigqueueinfo 317
+#define TARGET_NR_perf_event_open   318
+#define TARGET_NR_recvmmsg          319
+#define TARGET_NR_accept4           320
+#define TARGET_NR_prlimit64         321
+#define TARGET_NR_fanotify_init     322
+#define TARGET_NR_fanotify_mark     323
+#define TARGET_NR_clock_adjtime     324
+#define TARGET_NR_name_to_handle_at 325
+#define TARGET_NR_open_by_handle_at 326
+#define TARGET_NR_syncfs            327
+#define TARGET_NR_setns             328
+#define TARGET_NR_sendmmsg          329
+#define TARGET_NR_process_vm_readv  330
+#define TARGET_NR_process_vm_writev 331
+#define TARGET_NR_kcmp              332
+#define TARGET_NR_finit_module      333
+#define TARGET_NR_sched_setattr     334
+#define TARGET_NR_sched_getattr     335
+#define TARGET_NR_utimes            336
+#define TARGET_NR_renameat2         337
+#define TARGET_NR_seccomp           338
+#define TARGET_NR_getrandom         339
+#define TARGET_NR_memfd_create      340
+#define TARGET_NR_bpf               341
+#define TARGET_NR_execveat          342
+#define TARGET_NR_membarrier        343
+#define TARGET_NR_userfaultfd       344
+#define TARGET_NR_mlock2            345
+#define TARGET_NR_copy_file_range   346
+#define TARGET_NR_preadv2           347
+#define TARGET_NR_pwritev2          348
-- 
2.9.3

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

* [Qemu-devel] [PULL 10/26] linux-user: Add HPPA termbits.h
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (7 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 09/26] linux-user: Add HPPA syscall numbers Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 11/26] linux-user: Add HPPA target_syscall.h Richard Henderson
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/termbits.h | 219 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 219 insertions(+)
 create mode 100644 linux-user/hppa/termbits.h

diff --git a/linux-user/hppa/termbits.h b/linux-user/hppa/termbits.h
new file mode 100644
index 0000000..e9633ef
--- /dev/null
+++ b/linux-user/hppa/termbits.h
@@ -0,0 +1,219 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0040000
+#define TARGET_IUTF8   0100000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_TOSTOP  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_IEXTEN  0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR    0
+#define TARGET_VQUIT    1
+#define TARGET_VERASE   2
+#define TARGET_VKILL    3
+#define TARGET_VEOF     4
+#define TARGET_VTIME    5
+#define TARGET_VMIN     6
+#define TARGET_VSWTC    7
+#define TARGET_VSTART   8
+#define TARGET_VSTOP    9
+#define TARGET_VSUSP    10
+#define TARGET_VEOL     11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE  14
+#define TARGET_VLNEXT   15
+#define TARGET_VEOL2    16
+
+/* ioctls */
+
+#define TARGET_TCGETS           TARGET_IOR('T', 16, struct target_termios)
+#define TARGET_TCSETS           TARGET_IOW('T', 17, struct target_termios)
+#define TARGET_TCSETSW          TARGET_IOW('T', 18, struct target_termios)
+#define TARGET_TCSETSF          TARGET_IOW('T', 19, struct target_termios)
+#define TARGET_TCGETA           TARGET_IOR('T', 1, struct target_termios)
+#define TARGET_TCSETA           TARGET_IOW('T', 2, struct target_termios)
+#define TARGET_TCSETAW          TARGET_IOW('T', 3, struct target_termios)
+#define TARGET_TCSETAF          TARGET_IOW('T', 4, struct target_termios)
+#define TARGET_TCSBRK           TARGET_IO('T', 5)
+#define TARGET_TCXONC           TARGET_IO('T', 6)
+#define TARGET_TCFLSH           TARGET_IO('T', 7)
+
+#define TARGET_TIOCEXCL         0x540C
+#define TARGET_TIOCNXCL         0x540D
+#define TARGET_TIOCSCTTY        0x540E
+#define TARGET_TIOCGPGRP        TARGET_IOR('T', 30, int)
+#define TARGET_TIOCSPGRP        TARGET_IOW('T', 29, int)
+#define TARGET_TIOCOUTQ         0x5411
+#define TARGET_TIOCSTI          0x5412
+#define TARGET_TIOCGWINSZ       0x5413
+#define TARGET_TIOCSWINSZ       0x5414
+#define TARGET_TIOCMGET         0x5415
+#define TARGET_TIOCMBIS         0x5416
+#define TARGET_TIOCMBIC         0x5417
+#define TARGET_TIOCMSET         0x5418
+#define TARGET_TIOCGSOFTCAR     0x5419
+#define TARGET_TIOCSSOFTCAR     0x541A
+#define TARGET_FIONREAD         0x541B
+#define TARGET_TIOCINQ          TARGET_FIONREAD
+#define TARGET_TIOCLINUX        0x541C
+#define TARGET_TIOCCONS         0x541D
+#define TARGET_TIOCGSERIAL      0x541E
+#define TARGET_TIOCSSERIAL      0x541F
+#define TARGET_TIOCPKT          0x5420
+#define TARGET_FIONBIO          0x5421
+#define TARGET_TIOCNOTTY        0x5422
+#define TARGET_TIOCSETD         0x5423
+#define TARGET_TIOCGETD         0x5424
+#define TARGET_TCSBRKP          0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT   0x5426 /* For debugging only */
+#define TARGET_TIOCSBRK         0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK         0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID         TARGET_IOR('T', 20, int)
+#define TARGET_TIOCGPTN         TARGET_IOR('T', 0x30, unsigned int)
+        /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK       TARGET_IOW('T', 0x31, int)
+        /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX         0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX          0x5451
+#define TARGET_FIOASYNC         0x5452
+#define TARGET_TIOCSERCONFIG    0x5453
+#define TARGET_TIOCSERGWILD     0x5454
+#define TARGET_TIOCSERSWILD     0x5455
+#define TARGET_TIOCGLCKTRMIOS   0x5456
+#define TARGET_TIOCSLCKTRMIOS   0x5457
+#define TARGET_TIOCSERGSTRUCT   0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR    0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI  0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI  0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT      0x545C  /* wait for a change on serial */
+#define TARGET_TIOCGICOUNT     0x545D
+#define TARGET_FIOQSIZE        0x5460
+#define TARGET_TIOCSTART       0x5461
+#define TARGET_TIOCSTOP        0x5462
+#define TARGET_TIOCSLTC        0x5462
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA              0
+#define TARGET_TIOCPKT_FLUSHREAD         1
+#define TARGET_TIOCPKT_FLUSHWRITE        2
+#define TARGET_TIOCPKT_STOP              4
+#define TARGET_TIOCPKT_START             8
+#define TARGET_TIOCPKT_NOSTOP           16
+#define TARGET_TIOCPKT_DOSTOP           32
+
+#define TARGET_TIOCSER_TEMT    0x01 /* Transmitter physically empty */
-- 
2.9.3

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

* [Qemu-devel] [PULL 11/26] linux-user: Add HPPA target_syscall.h
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (8 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 10/26] linux-user: Add HPPA termbits.h Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 12/26] linux-user: Add HPPA definitions to syscall_defs.h Richard Henderson
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Which is primarily a re-definition of errno numbers.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/target_syscall.h | 237 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100644 linux-user/hppa/target_syscall.h

diff --git a/linux-user/hppa/target_syscall.h b/linux-user/hppa/target_syscall.h
new file mode 100644
index 0000000..ac18a9c
--- /dev/null
+++ b/linux-user/hppa/target_syscall.h
@@ -0,0 +1,237 @@
+#ifndef HPPA_TARGET_SYSCALL_H
+#define HPPA_TARGET_SYSCALL_H
+
+struct target_pt_regs {
+    target_ulong gr[32];
+    uint64_t     fr[32];
+    target_ulong sr[8];
+    target_ulong iasq[2];
+    target_ulong iaoq[2];
+    target_ulong cr27;
+    target_ulong __pad0;
+    target_ulong orig_r28;
+    target_ulong ksp;
+    target_ulong kpc;
+    target_ulong sar;
+    target_ulong iir;
+    target_ulong isr;
+    target_ulong ior;
+    target_ulong ipsw;
+};
+
+#define UNAME_MACHINE "hppa"
+#define UNAME_MINIMUM_RELEASE "2.6.32"
+#define TARGET_CLONE_BACKWARDS
+#define TARGET_MINSIGSTKSZ       2048
+#define TARGET_MLOCKALL_MCL_CURRENT 1
+#define TARGET_MLOCKALL_MCL_FUTURE  2
+
+#undef  TARGET_ENOMSG
+#define TARGET_ENOMSG          35
+#undef  TARGET_EIDRM
+#define TARGET_EIDRM           36
+#undef  TARGET_ECHRNG
+#define TARGET_ECHRNG          37
+#undef  TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38
+#undef  TARGET_EL3HLT
+#define TARGET_EL3HLT          39
+#undef  TARGET_EL3RST
+#define TARGET_EL3RST          40
+#undef  TARGET_ELNRNG
+#define TARGET_ELNRNG          41
+#undef  TARGET_EUNATCH
+#define TARGET_EUNATCH         42
+#undef  TARGET_ENOCSI
+#define TARGET_ENOCSI          43
+#undef  TARGET_EL2HLT
+#define TARGET_EL2HLT          44
+#undef  TARGET_EDEADLK
+#define TARGET_EDEADLK         45
+#undef  TARGET_ENOLCK
+#define TARGET_ENOLCK          46
+#undef  TARGET_EILSEQ
+#define TARGET_EILSEQ          47
+
+#undef  TARGET_ENONET
+#define TARGET_ENONET          50
+#undef  TARGET_ENODATA
+#define TARGET_ENODATA         51
+#undef  TARGET_ETIME
+#define TARGET_ETIME           52
+#undef  TARGET_ENOSR
+#define TARGET_ENOSR           53
+#undef  TARGET_ENOSTR
+#define TARGET_ENOSTR          54
+#undef  TARGET_ENOPKG
+#define TARGET_ENOPKG          55
+
+#undef  TARGET_ENOLINK
+#define TARGET_ENOLINK         57
+#undef  TARGET_EADV
+#define TARGET_EADV            58
+#undef  TARGET_ESRMNT
+#define TARGET_ESRMNT          59
+#undef  TARGET_ECOMM
+#define TARGET_ECOMM           60
+#undef  TARGET_EPROTO
+#define TARGET_EPROTO          61
+
+#undef  TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       64
+
+#undef  TARGET_EDOTDOT
+#define TARGET_EDOTDOT         66
+#undef  TARGET_EBADMSG
+#define TARGET_EBADMSG         67
+#undef  TARGET_EUSERS
+#define TARGET_EUSERS          68
+#undef  TARGET_EDQUOT
+#define TARGET_EDQUOT          69
+#undef  TARGET_ESTALE
+#define TARGET_ESTALE          70
+#undef  TARGET_EREMOTE
+#define TARGET_EREMOTE         71
+#undef  TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       72
+
+#undef  TARGET_EBADE
+#define TARGET_EBADE           160
+#undef  TARGET_EBADR
+#define TARGET_EBADR           161
+#undef  TARGET_EXFULL
+#define TARGET_EXFULL          162
+#undef  TARGET_ENOANO
+#define TARGET_ENOANO          163
+#undef  TARGET_EBADRQC
+#define TARGET_EBADRQC         164
+#undef  TARGET_EBADSLT
+#define TARGET_EBADSLT         165
+#undef  TARGET_EBFONT
+#define TARGET_EBFONT          166
+#undef  TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        167
+#undef  TARGET_EBADFD
+#define TARGET_EBADFD          168
+#undef  TARGET_EREMCHG
+#define TARGET_EREMCHG         169
+#undef  TARGET_ELIBACC
+#define TARGET_ELIBACC         170
+#undef  TARGET_ELIBBAD
+#define TARGET_ELIBBAD         171
+#undef  TARGET_ELIBSCN
+#define TARGET_ELIBSCN         172
+#undef  TARGET_ELIBMAX
+#define TARGET_ELIBMAX         173
+#undef  TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        174
+#undef  TARGET_ERESTART
+#define TARGET_ERESTART        175
+#undef  TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        176
+#undef  TARGET_EUCLEAN
+#define TARGET_EUCLEAN         177
+#undef  TARGET_ENOTNAM
+#define TARGET_ENOTNAM         178
+#undef  TARGET_ENAVAIL
+#define TARGET_ENAVAIL         179
+#undef  TARGET_EISNAM
+#define TARGET_EISNAM          180
+#undef  TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       181
+#undef  TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       182
+#undef  TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     183
+#undef  TARGET_ENOKEY
+#define TARGET_ENOKEY          184
+#undef  TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     185
+#undef  TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     186
+#undef  TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    187
+
+/* Never used in linux.  */
+/* #define TARGET_ENOSYM          215 */
+#undef  TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        216
+#undef  TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    217
+#undef  TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        218
+#undef  TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      219
+#undef  TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     220
+#undef  TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 221
+#undef  TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 222
+#undef  TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      223
+#undef  TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    224
+#undef  TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    225
+#undef  TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      226
+#undef  TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   227
+#undef  TARGET_ENETDOWN
+#define TARGET_ENETDOWN        228
+#undef  TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     229
+#undef  TARGET_ENETRESET
+#define TARGET_ENETRESET       230
+#undef  TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    231
+#undef  TARGET_ECONNRESET
+#define TARGET_ECONNRESET      232
+#undef  TARGET_ENOBUFS
+#define TARGET_ENOBUFS         233
+#undef  TARGET_EISCONN
+#define TARGET_EISCONN         234
+#undef  TARGET_ENOTCONN
+#define TARGET_ENOTCONN        235
+#undef  TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       236
+#undef  TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    237
+#undef  TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       238
+#undef  TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    239
+#define TARGET_EREMOTERELEASE  240
+#undef  TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       241
+#undef  TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    242
+
+#undef  TARGET_EALREADY
+#define TARGET_EALREADY        244
+#undef  TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     245
+#undef  TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       247
+#undef  TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    248
+#undef  TARGET_ELOOP
+#define TARGET_ELOOP           249
+#undef  TARGET_ENOSYS
+#define TARGET_ENOSYS          251
+
+#undef  TARGET_ECANCELED
+#define TARGET_ECANCELED       253
+
+#undef  TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      254
+#undef  TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 255
+
+#undef  TARGET_ERFKILL
+#define TARGET_ERFKILL         256
+#undef  TARGET_EHWPOISON
+#define TARGET_EHWPOISON       257
+
+#endif /* HPPA_TARGET_SYSCALL_H */
-- 
2.9.3

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

* [Qemu-devel] [PULL 12/26] linux-user: Add HPPA definitions to syscall_defs.h
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (9 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 11/26] linux-user: Add HPPA target_syscall.h Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 13/26] linux-user: Add HPPA target_structs.h Richard Henderson
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

---
 linux-user/syscall_defs.h | 131 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 130 insertions(+), 1 deletion(-)

diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 957b737..39848a8 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -90,6 +90,15 @@
 #define TARGET_IOC_READ	  2U
 #define TARGET_IOC_WRITE  4U
 
+#elif defined(TARGET_HPPA)
+
+#define TARGET_IOC_SIZEBITS  14
+#define TARGET_IOC_DIRBITS    2
+
+#define TARGET_IOC_NONE   0U
+#define TARGET_IOC_WRITE  2U
+#define TARGET_IOC_READ   1U
+
 #else
 #error unsupported CPU
 #endif
@@ -417,7 +426,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
     || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) \
     || defined(TARGET_MICROBLAZE) || defined(TARGET_UNICORE32) \
     || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \
-    || defined(TARGET_TILEGX)
+    || defined(TARGET_TILEGX) || defined(TARGET_HPPA)
 
 #if defined(TARGET_SPARC)
 #define TARGET_SA_NOCLDSTOP    8u
@@ -587,6 +596,46 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 #define TARGET_SIG_UNBLOCK	2	/* for unblocking signals */
 #define TARGET_SIG_SETMASK	3	/* for setting the signal mask */
 
+#elif defined(TARGET_HPPA)
+
+#define TARGET_SIGHUP           1
+#define TARGET_SIGINT           2
+#define TARGET_SIGQUIT          3
+#define TARGET_SIGILL           4
+#define TARGET_SIGTRAP          5
+#define TARGET_SIGABRT          6
+#define TARGET_SIGIOT           6
+#define TARGET_SIGSTKFLT        7
+#define TARGET_SIGFPE           8
+#define TARGET_SIGKILL          9
+#define TARGET_SIGBUS          10
+#define TARGET_SIGSEGV         11
+#define TARGET_SIGXCPU         12
+#define TARGET_SIGPIPE         13
+#define TARGET_SIGALRM         14
+#define TARGET_SIGTERM         15
+#define TARGET_SIGUSR1         16
+#define TARGET_SIGUSR2         17
+#define TARGET_SIGCHLD         18
+#define TARGET_SIGPWR          19
+#define TARGET_SIGVTALRM       20
+#define TARGET_SIGPROF         21
+#define TARGET_SIGIO           22
+#define TARGET_SIGPOLL         TARGET_SIGIO
+#define TARGET_SIGWINCH        23
+#define TARGET_SIGSTOP         24
+#define TARGET_SIGTSTP         25
+#define TARGET_SIGCONT         26
+#define TARGET_SIGTTIN         27
+#define TARGET_SIGTTOU         28
+#define TARGET_SIGURG          29
+#define TARGET_SIGXFSZ         30
+#define TARGET_SIGSYS          31
+
+#define TARGET_SIG_BLOCK       0
+#define TARGET_SIG_UNBLOCK     1
+#define TARGET_SIG_SETMASK     2
+
 #else
 
 /* OpenRISC Using the general signals */
@@ -1279,6 +1328,16 @@ struct target_winsize {
 #define TARGET_MAP_NORESERVE	0x10000		/* no check for reservations */
 #define TARGET_MAP_POPULATE	0x20000		/* pop (prefault) pagetables */
 #define TARGET_MAP_NONBLOCK	0x40000		/* do not block on IO */
+#elif defined(TARGET_HPPA)
+#define TARGET_MAP_ANONYMOUS	0x10		/* don't use a file */
+#define TARGET_MAP_FIXED	0x04		/* Interpret addr exactly */
+#define TARGET_MAP_GROWSDOWN	0x08000		/* stack-like segment */
+#define TARGET_MAP_DENYWRITE	0x00800		/* ETXTBSY */
+#define TARGET_MAP_EXECUTABLE	0x01000		/* mark it as an executable */
+#define TARGET_MAP_LOCKED	0x02000		/* lock the mapping */
+#define TARGET_MAP_NORESERVE	0x04000		/* no check for reservations */
+#define TARGET_MAP_POPULATE	0x10000		/* pop (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x20000		/* do not block on IO */
 #else
 #define TARGET_MAP_FIXED	0x10		/* Interpret addr exactly */
 #define TARGET_MAP_ANONYMOUS	0x20		/* don't use a file */
@@ -2029,6 +2088,62 @@ struct target_stat64 {
     unsigned int __unused5;
 };
 
+#elif defined(TARGET_HPPA)
+
+struct target_stat {
+    abi_uint   st_dev;
+    abi_uint   st_ino;
+    abi_ushort st_mode;
+    abi_ushort st_nlink;
+    abi_ushort _res1;
+    abi_ushort _res2;
+    abi_uint   st_rdev;
+    abi_int    st_size;
+    abi_int    target_st_atime;
+    abi_uint   target_st_atime_nsec;
+    abi_int    target_st_mtime;
+    abi_uint   target_st_mtime_nsec;
+    abi_int    target_st_ctime;
+    abi_uint   target_st_ctime_nsec;
+    abi_int    st_blksize;
+    abi_int    st_blocks;
+    abi_uint   _unused1;
+    abi_uint   _unused2;
+    abi_uint   _unused3;
+    abi_uint   _unused4;
+    abi_ushort _unused5;
+    abi_short  st_fstype;
+    abi_uint   st_realdev;
+    abi_ushort st_basemode;
+    abi_ushort _unused6;
+    abi_uint   st_uid;
+    abi_uint   st_gid;
+    abi_uint   _unused7[3];
+};
+
+#define TARGET_HAS_STRUCT_STAT64
+struct target_stat64 {
+    uint64_t   st_dev;
+    abi_uint   _pad1;
+    abi_uint   _res1;
+    abi_uint   st_mode;
+    abi_uint   st_nlink;
+    abi_uint   st_uid;
+    abi_uint   st_gid;
+    uint64_t   st_rdev;
+    abi_uint   _pad2;
+    int64_t    st_size;
+    abi_int    st_blksize;
+    int64_t    st_blocks;
+    abi_int    target_st_atime;
+    abi_uint   target_st_atime_nsec;
+    abi_int    target_st_mtime;
+    abi_uint   target_st_mtime_nsec;
+    abi_int    target_st_ctime;
+    abi_uint   target_st_ctime_nsec;
+    uint64_t   st_ino;
+};
+
 #else
 #error unsupported CPU
 #endif
@@ -2273,6 +2388,20 @@ struct target_statfs64 {
 #define TARGET_O_CLOEXEC     010000000
 #define TARGET___O_SYNC      020000000
 #define TARGET_O_PATH        040000000
+#elif defined(TARGET_HPPA)
+#define TARGET_O_NONBLOCK    000200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define TARGET_O_APPEND      000000010
+#define TARGET_O_CREAT       000000400 /* not fcntl */
+#define TARGET_O_EXCL        000002000 /* not fcntl */
+#define TARGET_O_NOCTTY      000400000 /* not fcntl */
+#define TARGET_O_DSYNC       001000000
+#define TARGET_O_LARGEFILE   000004000
+#define TARGET_O_DIRECTORY   000010000 /* must be a directory */
+#define TARGET_O_NOFOLLOW    000000200 /* don't follow links */
+#define TARGET_O_NOATIME     004000000
+#define TARGET_O_CLOEXEC     010000000
+#define TARGET___O_SYNC      000100000
+#define TARGET_O_PATH        020000000
 #elif defined(TARGET_ARM) || defined(TARGET_M68K)
 #define TARGET_O_DIRECTORY      040000 /* must be a directory */
 #define TARGET_O_NOFOLLOW      0100000 /* don't follow links */
-- 
2.9.3

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

* [Qemu-devel] [PULL 13/26] linux-user: Add HPPA target_structs.h
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (10 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 12/26] linux-user: Add HPPA definitions to syscall_defs.h Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 14/26] linux-user: Add HPPA target_signal.h and target_cpu.h Richard Henderson
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/target_structs.h | 54 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 linux-user/hppa/target_structs.h

diff --git a/linux-user/hppa/target_structs.h b/linux-user/hppa/target_structs.h
new file mode 100644
index 0000000..b560b18
--- /dev/null
+++ b/linux-user/hppa/target_structs.h
@@ -0,0 +1,54 @@
+/*
+ * HPPA specific structures for linux-user
+ *
+ * Copyright (c) 2016  Richard Henderson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HPPA_TARGET_STRUCTS_H
+#define HPPA_TARGET_STRUCTS_H
+
+struct target_ipc_perm {
+    abi_int __key;                      /* Key.  */
+    abi_uint uid;                       /* Owner's user ID.  */
+    abi_uint gid;                       /* Owner's group ID.  */
+    abi_uint cuid;                      /* Creator's user ID.  */
+    abi_uint cgid;                      /* Creator's group ID.  */
+    abi_ushort __pad1;
+    abi_ushort mode;                    /* Read/write permission.  */
+    abi_ushort __pad2;
+    abi_ushort __seq;                   /* Sequence number.  */
+    abi_uint __pad3;
+    uint64_t __unused1;
+    uint64_t __unused2;
+};
+
+struct target_shmid_ds {
+    struct target_ipc_perm shm_perm;    /* operation permission struct */
+    abi_uint __pad1;
+    abi_ulong shm_atime;                /* time of last shmat() */
+    abi_uint __pad2;
+    abi_ulong shm_dtime;                /* time of last shmdt() */
+    abi_uint __pad3;
+    abi_ulong shm_ctime;                /* time of last change by shmctl() */
+    abi_uint __pad4;
+    abi_long shm_segsz;                 /* size of segment in bytes */
+    abi_int shm_cpid;                   /* pid of creator */
+    abi_int shm_lpid;                   /* pid of last shmop */
+    abi_ulong shm_nattch;               /* number of current attaches */
+    abi_ulong __unused1;
+    abi_ulong __unused2;
+};
+
+#endif
-- 
2.9.3

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

* [Qemu-devel] [PULL 14/26] linux-user: Add HPPA target_signal.h and target_cpu.h
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (11 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 13/26] linux-user: Add HPPA target_structs.h Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 15/26] linux-user: Add HPPA signal handling Richard Henderson
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

The cpu.h structure that these manipulate hasn't been defined
yet, but we haven't enabled compilation yet either.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/hppa/target_cpu.h    | 35 +++++++++++++++++++++++++++++++++++
 linux-user/hppa/target_signal.h | 29 +++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 linux-user/hppa/target_cpu.h
 create mode 100644 linux-user/hppa/target_signal.h

diff --git a/linux-user/hppa/target_cpu.h b/linux-user/hppa/target_cpu.h
new file mode 100644
index 0000000..1a5ceca
--- /dev/null
+++ b/linux-user/hppa/target_cpu.h
@@ -0,0 +1,35 @@
+/*
+ * HPPA specific CPU ABI and functions for linux-user
+ *
+ *  Copyright (c) 2016  Richard Henderson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef ALPHA_TARGET_CPU_H
+#define ALPHA_TARGET_CPU_H
+
+static inline void cpu_clone_regs(CPUHPPAState *env, target_ulong newsp)
+{
+    if (newsp) {
+        env->gr[30] = newsp;
+    }
+    env->gr[28] = 0;
+}
+
+static inline void cpu_set_tls(CPUHPPAState *env, target_ulong newtls)
+{
+    env->cr27 = newtls;
+}
+
+#endif
diff --git a/linux-user/hppa/target_signal.h b/linux-user/hppa/target_signal.h
new file mode 100644
index 0000000..e115890
--- /dev/null
+++ b/linux-user/hppa/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef HPPA_TARGET_SIGNAL_H
+#define HPPA_TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+    abi_ulong ss_sp;
+    int32_t ss_flags;
+    abi_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline abi_ulong get_sp_from_cpustate(CPUHPPAState *state)
+{
+    return state->gr[30];
+}
+
+#endif /* HPPA_TARGET_SIGNAL_H */
-- 
2.9.3

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

* [Qemu-devel] [PULL 15/26] linux-user: Add HPPA signal handling
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (12 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 14/26] linux-user: Add HPPA target_signal.h and target_cpu.h Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 16/26] linux-user: Add HPPA startup and main loop Richard Henderson
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/signal.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 1 deletion(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index c750053..0a5bb4e 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -5888,6 +5888,195 @@ long do_rt_sigreturn(CPUTLGState *env)
     return -TARGET_QEMU_ESIGRETURN;
 }
 
+#elif defined(TARGET_HPPA)
+
+struct target_sigcontext {
+    abi_ulong sc_flags;
+    abi_ulong sc_gr[32];
+    uint64_t sc_fr[32];
+    abi_ulong sc_iasq[2];
+    abi_ulong sc_iaoq[2];
+    abi_ulong sc_sar;
+};
+
+struct target_ucontext {
+    abi_uint tuc_flags;
+    abi_ulong tuc_link;
+    target_stack_t tuc_stack;
+    abi_uint pad[1];
+    struct target_sigcontext tuc_mcontext;
+    target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+    abi_uint tramp[9];
+    target_siginfo_t info;
+    struct target_ucontext uc;
+    /* hidden location of upper halves of pa2.0 64-bit gregs */
+};
+
+static void setup_sigcontext(struct target_sigcontext *sc, CPUArchState *env)
+{
+    int flags = 0;
+    int i;
+
+    /* ??? if on_sig_stack, flags |= 1 (PARISC_SC_FLAG_ONSTACK).  */
+
+    if (env->iaoq_f < TARGET_PAGE_SIZE) {
+        /* In the gateway page, executing a syscall.  */
+        flags |= 2; /* PARISC_SC_FLAG_IN_SYSCALL */
+        __put_user(env->gr[31], &sc->sc_iaoq[0]);
+        __put_user(env->gr[31] + 4, &sc->sc_iaoq[1]);
+    } else {
+        __put_user(env->iaoq_f, &sc->sc_iaoq[0]);
+        __put_user(env->iaoq_b, &sc->sc_iaoq[1]);
+    }
+    __put_user(0, &sc->sc_iasq[0]);
+    __put_user(0, &sc->sc_iasq[1]);
+    __put_user(flags, &sc->sc_flags);
+
+    __put_user(cpu_hppa_get_psw(env), &sc->sc_gr[0]);
+    for (i = 1; i < 32; ++i) {
+        __put_user(env->gr[i], &sc->sc_gr[i]);
+    }
+
+    __put_user((uint64_t)env->fr0_shadow << 32, &sc->sc_fr[0]);
+    for (i = 1; i < 32; ++i) {
+        __put_user(env->fr[i], &sc->sc_fr[i]);
+    }
+
+    __put_user(env->sar, &sc->sc_sar);
+}
+
+static void restore_sigcontext(CPUArchState *env, struct target_sigcontext *sc)
+{
+    target_ulong psw;
+    int i;
+
+    __get_user(psw, &sc->sc_gr[0]);
+    cpu_hppa_put_psw(env, psw);
+
+    for (i = 1; i < 32; ++i) {
+        __get_user(env->gr[i], &sc->sc_gr[i]);
+    }
+    for (i = 0; i < 32; ++i) {
+        __get_user(env->fr[i], &sc->sc_fr[i]);
+    }
+    cpu_hppa_loaded_fr0(env);
+
+    __get_user(env->iaoq_f, &sc->sc_iaoq[0]);
+    __get_user(env->iaoq_b, &sc->sc_iaoq[1]);
+    __get_user(env->sar, &sc->sc_sar);
+}
+
+/* No, this doesn't look right, but it's copied straight from the kernel.  */
+#define PARISC_RT_SIGFRAME_SIZE32 \
+    ((sizeof(struct target_rt_sigframe) + 48 + 64) & -64)
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+                           target_sigset_t *set, CPUArchState *env)
+{
+    abi_ulong frame_addr, sp, haddr;
+    struct target_rt_sigframe *frame;
+    int i;
+
+    sp = env->gr[30];
+    if (ka->sa_flags & TARGET_SA_ONSTACK) {
+        if (sas_ss_flags(sp) == 0) {
+            sp = (target_sigaltstack_used.ss_sp + 0x7f) & ~0x3f;
+        }
+    }
+    frame_addr = QEMU_ALIGN_UP(sp, 64);
+    sp = frame_addr + PARISC_RT_SIGFRAME_SIZE32;
+
+    trace_user_setup_rt_frame(env, frame_addr);
+
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+        goto give_sigsegv;
+    }
+
+    tswap_siginfo(&frame->info, info);
+    frame->uc.tuc_flags = 0;
+    frame->uc.tuc_link = 0;
+
+    __put_user(target_sigaltstack_used.ss_sp, &frame->uc.tuc_stack.ss_sp);
+    __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+               &frame->uc.tuc_stack.ss_flags);
+    __put_user(target_sigaltstack_used.ss_size,
+               &frame->uc.tuc_stack.ss_size);
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
+    }
+
+    setup_sigcontext(&frame->uc.tuc_mcontext, env);
+
+    __put_user(0x34190000, frame->tramp + 0); /* ldi 0,%r25 */
+    __put_user(0x3414015a, frame->tramp + 1); /* ldi __NR_rt_sigreturn,%r20 */
+    __put_user(0xe4008200, frame->tramp + 2); /* be,l 0x100(%sr2,%r0) */
+    __put_user(0x08000240, frame->tramp + 3); /* nop */
+
+    unlock_user_struct(frame, frame_addr, 1);
+
+    env->gr[2] = h2g(frame->tramp);
+    env->gr[30] = sp;
+    env->gr[26] = sig;
+    env->gr[25] = h2g(&frame->info);
+    env->gr[24] = h2g(&frame->uc);
+
+    haddr = ka->_sa_handler;
+    if (haddr & 2) {
+        /* Function descriptor.  */
+        target_ulong *fdesc, dest;
+
+        haddr &= -4;
+        if (!lock_user_struct(VERIFY_READ, fdesc, haddr, 1)) {
+            goto give_sigsegv;
+        }
+        __get_user(dest, fdesc);
+        __get_user(env->gr[19], fdesc + 1);
+        unlock_user_struct(fdesc, haddr, 1);
+        haddr = dest;
+    }
+    env->iaoq_f = haddr;
+    env->iaoq_b = haddr + 4;;
+    return;
+
+ give_sigsegv:
+    force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPUArchState *env)
+{
+    abi_ulong frame_addr = env->gr[30] - PARISC_RT_SIGFRAME_SIZE32;
+    struct target_rt_sigframe *frame;
+    sigset_t set;
+
+    trace_user_do_rt_sigreturn(env, frame_addr);
+    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+        goto badframe;
+    }
+    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
+    set_sigmask(&set);
+
+    restore_sigcontext(env, &frame->uc.tuc_mcontext);
+    unlock_user_struct(frame, frame_addr, 0);
+
+    if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
+                                             uc.tuc_stack),
+                       0, env->gr[30]) == -EFAULT) {
+        goto badframe;
+    }
+
+    unlock_user_struct(frame, frame_addr, 0);
+    return -TARGET_QEMU_ESIGRETURN;
+
+ badframe:
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_QEMU_ESIGRETURN;
+}
+
 #else
 
 static void setup_frame(int sig, struct target_sigaction *ka,
@@ -5989,7 +6178,7 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
         /* prepare the stack frame of the virtual CPU */
 #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
         || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \
-        || defined(TARGET_PPC64)
+        || defined(TARGET_PPC64) || defined(TARGET_HPPA)
         /* These targets do not have traditional signals.  */
         setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
 #else
-- 
2.9.3

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

* [Qemu-devel] [PULL 16/26] linux-user: Add HPPA startup and main loop
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (13 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 15/26] linux-user: Add HPPA signal handling Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 17/26] target-hppa: Add softfloat specializations Richard Henderson
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Including support for the atomic memory op syscalls.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 linux-user/elfload.c |  24 +++++++
 linux-user/main.c    | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 196 insertions(+)

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 5cea39d..51794bb 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1215,6 +1215,30 @@ static inline void init_thread(struct target_pt_regs *regs,
 
 #endif /* TARGET_TILEGX */
 
+#ifdef TARGET_HPPA
+
+#define ELF_START_MMAP  0x80000000
+#define ELF_CLASS       ELFCLASS32
+#define ELF_ARCH        EM_PARISC
+#define ELF_PLATFORM    "PARISC"
+#define STACK_GROWS_DOWN 0
+#define STACK_ALIGNMENT  64
+
+static inline void init_thread(struct target_pt_regs *regs,
+                               struct image_info *infop)
+{
+    regs->iaoq[0] = infop->entry;
+    regs->iaoq[1] = infop->entry + 4;
+    regs->gr[23] = 0;
+    regs->gr[24] = infop->arg_start;
+    regs->gr[25] = (infop->arg_end - infop->arg_start) / sizeof(abi_ulong);
+    /* The top-of-stack contains a linkage buffer.  */
+    regs->gr[30] = infop->start_stack + 64;
+    regs->gr[31] = infop->entry;
+}
+
+#endif /* TARGET_HPPA */
+
 #ifndef ELF_PLATFORM
 #define ELF_PLATFORM (NULL)
 #endif
diff --git a/linux-user/main.c b/linux-user/main.c
index aae29bd..db4eb68 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3512,6 +3512,169 @@ void cpu_loop(CPUTLGState *env)
 
 #endif
 
+#ifdef TARGET_HPPA
+
+static abi_ulong hppa_lws(CPUHPPAState *env)
+{
+    uint32_t which = env->gr[20];
+    abi_ulong addr = env->gr[26];
+    abi_ulong old = env->gr[25];
+    abi_ulong new = env->gr[24];
+    abi_ulong size, ret;
+
+    switch (which) {
+    default:
+        return -TARGET_ENOSYS;
+
+    case 0: /* elf32 atomic 32bit cmpxchg */
+        if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) {
+            return -TARGET_EFAULT;
+        }
+        old = tswap32(old);
+        new = tswap32(new);
+        ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+        ret = tswap32(ret);
+        break;
+
+    case 2: /* elf32 atomic "new" cmpxchg */
+        size = env->gr[23];
+        if (size >= 4) {
+            return -TARGET_ENOSYS;
+        }
+        if (((addr | old | new) & ((1 << size) - 1))
+            || !access_ok(VERIFY_WRITE, addr, 1 << size)
+            || !access_ok(VERIFY_READ, old, 1 << size)
+            || !access_ok(VERIFY_READ, new, 1 << size)) {
+            return -TARGET_EFAULT;
+        }
+        /* Note that below we use host-endian loads so that the cmpxchg
+           can be host-endian as well.  */
+        switch (size) {
+        case 0:
+            old = *(uint8_t *)g2h(old);
+            new = *(uint8_t *)g2h(new);
+            ret = atomic_cmpxchg((uint8_t *)g2h(addr), old, new);
+            ret = ret != old;
+            break;
+        case 1:
+            old = *(uint16_t *)g2h(old);
+            new = *(uint16_t *)g2h(new);
+            ret = atomic_cmpxchg((uint16_t *)g2h(addr), old, new);
+            ret = ret != old;
+            break;
+        case 2:
+            old = *(uint32_t *)g2h(old);
+            new = *(uint32_t *)g2h(new);
+            ret = atomic_cmpxchg((uint32_t *)g2h(addr), old, new);
+            ret = ret != old;
+            break;
+        case 3:
+            {
+                uint64_t o64, n64, r64;
+                o64 = *(uint64_t *)g2h(old);
+                n64 = *(uint64_t *)g2h(new);
+#ifdef CONFIG_ATOMIC64
+                r64 = atomic_cmpxchg__nocheck((uint64_t *)g2h(addr), o64, n64);
+                ret = r64 != o64;
+#else
+                start_exclusive();
+                r64 = *(uint64_t *)g2h(addr);
+                ret = 1;
+                if (r64 == o64) {
+                    *(uint64_t *)g2h(addr) = n64;
+                    ret = 0;
+                }
+                end_exclusive();
+#endif
+            }
+            break;
+        }
+        break;
+    }
+
+    env->gr[28] = ret;
+    return 0;
+}
+
+void cpu_loop(CPUHPPAState *env)
+{
+    CPUState *cs = CPU(hppa_env_get_cpu(env));
+    target_siginfo_t info;
+    abi_ulong ret;
+    int trapnr;
+
+    while (1) {
+        cpu_exec_start(cs);
+        trapnr = cpu_exec(cs);
+        cpu_exec_end(cs);
+        process_queued_cpu_work(cs);
+
+        switch (trapnr) {
+        case EXCP_SYSCALL:
+            ret = do_syscall(env, env->gr[20],
+                             env->gr[26], env->gr[25],
+                             env->gr[24], env->gr[23],
+                             env->gr[22], env->gr[21], 0, 0);
+            switch (ret) {
+            default:
+                env->gr[28] = ret;
+                /* We arrived here by faking the gateway page.  Return.  */
+                env->iaoq_f = env->gr[31];
+                env->iaoq_b = env->gr[31] + 4;
+                break;
+            case -TARGET_ERESTARTSYS:
+            case -TARGET_QEMU_ESIGRETURN:
+                break;
+            }
+            break;
+        case EXCP_SYSCALL_LWS:
+            env->gr[21] = hppa_lws(env);
+            /* We arrived here by faking the gateway page.  Return.  */
+            env->iaoq_f = env->gr[31];
+            env->iaoq_b = env->gr[31] + 4;
+            break;
+        case EXCP_SIGSEGV:
+            info.si_signo = TARGET_SIGSEGV;
+            info.si_errno = 0;
+            info.si_code = TARGET_SEGV_ACCERR;
+            info._sifields._sigfault._addr = env->ior;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
+        case EXCP_SIGILL:
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->iaoq_f;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
+        case EXCP_SIGFPE:
+            info.si_signo = TARGET_SIGFPE;
+            info.si_errno = 0;
+            info.si_code = 0;
+            info._sifields._sigfault._addr = env->iaoq_f;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
+        case EXCP_DEBUG:
+            trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+            if (trapnr) {
+                info.si_signo = trapnr;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        default:
+            g_assert_not_reached();
+        }
+        process_pending_signals(env);
+    }
+}
+
+#endif /* TARGET_HPPA */
+
 THREAD CPUState *thread_cpu;
 
 bool qemu_cpu_is_self(CPUState *cpu)
@@ -4539,6 +4702,15 @@ int main(int argc, char **argv, char **envp)
         }
         env->pc = regs->pc;
     }
+#elif defined(TARGET_HPPA)
+    {
+        int i;
+        for (i = 1; i < 32; i++) {
+            env->gr[i] = regs->gr[i];
+        }
+        env->iaoq_f = regs->iaoq[0];
+        env->iaoq_b = regs->iaoq[1];
+    }
 #else
 #error unsupported target CPU
 #endif
-- 
2.9.3

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

* [Qemu-devel] [PULL 17/26] target-hppa: Add softfloat specializations
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (14 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 16/26] linux-user: Add HPPA startup and main loop Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation Richard Henderson
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Like the original MIPS, HPPA has the MSB of an SNaN set.
However, it has different rules for silencing an SNaN:
(1) msb is cleared and (2) msb-1 must be set if the fraction
is now zero, and (implementation defined) may be set always.
I haven't checked real hardware but chose the set always
alternative because it's easy and within spec.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 fpu/softfloat-specialize.h | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f5aed72..f05c865 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -116,6 +116,8 @@ float32 float32_default_nan(float_status *status)
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
       defined(TARGET_XTENSA) || defined(TARGET_S390X) || defined(TARGET_TRICORE)
     return const_float32(0x7FC00000);
+#elif defined(TARGET_HPPA)
+    return const_float32(0x7FA00000);
 #else
     if (status->snan_bit_is_one) {
         return const_float32(0x7FBFFFFF);
@@ -139,6 +141,8 @@ float64 float64_default_nan(float_status *status)
 #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
       defined(TARGET_S390X)
     return const_float64(LIT64(0x7FF8000000000000));
+#elif defined(TARGET_HPPA)
+    return const_float64(LIT64(0x7FF4000000000000));
 #else
     if (status->snan_bit_is_one) {
         return const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
@@ -361,7 +365,14 @@ float32 float32_maybe_silence_nan(float32 a_, float_status *status)
 {
     if (float32_is_signaling_nan(a_, status)) {
         if (status->snan_bit_is_one) {
+#ifdef TARGET_HPPA
+            uint32_t a = float32_val(a_);
+            a &= ~0x00400000;
+            a |=  0x00200000;
+            return make_float32(a);
+#else
             return float32_default_nan(status);
+#endif
         } else {
             uint32_t a = float32_val(a_);
             a |= (1 << 22);
@@ -449,7 +460,7 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
         return 1;
     }
 }
-#elif defined(TARGET_MIPS)
+#elif defined(TARGET_MIPS) || defined(TARGET_HPPA)
 static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
                     flag aIsLargerSignificand)
 {
@@ -794,7 +805,14 @@ float64 float64_maybe_silence_nan(float64 a_, float_status *status)
 {
     if (float64_is_signaling_nan(a_, status)) {
         if (status->snan_bit_is_one) {
+#ifdef TARGET_HPPA
+            uint64_t a = float64_val(a_);
+            a &= ~0x0008000000000000ULL;
+            a |=  0x0004000000000000ULL;
+            return make_float64(a);
+#else
             return float64_default_nan(status);
+#endif
         } else {
             uint64_t a = float64_val(a_);
             a |= LIT64(0x0008000000000000);
-- 
2.9.3

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

* [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (15 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 17/26] target-hppa: Add softfloat specializations Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-30 13:49   ` Peter Maydell
  2017-01-23  2:17 ` [Qemu-devel] [PULL 19/26] target-hppa: Add nullification framework Richard Henderson
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

This is just about the minimum required to enable compilation
without actually executing any instructions.  This contains the
HPPACPU structure and the required callbacks, the gdbstub, the
basic translation loop, and a translate_one function that always
results in an illegal instruction.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 MAINTAINERS                         |   6 +
 configure                           |   6 +-
 default-configs/hppa-linux-user.mak |   1 +
 target/hppa/Makefile.objs           |   1 +
 target/hppa/cpu-qom.h               |  52 +++++
 target/hppa/cpu.c                   | 164 ++++++++++++++
 target/hppa/cpu.h                   | 144 ++++++++++++
 target/hppa/gdbstub.c               | 111 ++++++++++
 target/hppa/helper.c                | 137 ++++++++++++
 target/hppa/helper.h                |   3 +
 target/hppa/op_helper.c             |  65 ++++++
 target/hppa/translate.c             | 429 ++++++++++++++++++++++++++++++++++++
 12 files changed, 1116 insertions(+), 3 deletions(-)
 create mode 100644 default-configs/hppa-linux-user.mak
 create mode 100644 target/hppa/Makefile.objs
 create mode 100644 target/hppa/cpu-qom.h
 create mode 100644 target/hppa/cpu.c
 create mode 100644 target/hppa/cpu.h
 create mode 100644 target/hppa/gdbstub.c
 create mode 100644 target/hppa/helper.c
 create mode 100644 target/hppa/helper.h
 create mode 100644 target/hppa/op_helper.c
 create mode 100644 target/hppa/translate.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b5ebfab..44c42fb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -132,6 +132,12 @@ F: include/hw/cris/
 F: tests/tcg/cris/
 F: disas/cris.c
 
+HPPA (PA-RISC)
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
+F: target/hppa/
+F: disas/hppa.c
+
 LM32
 M: Michael Walle <michael@walle.cc>
 S: Maintained
diff --git a/configure b/configure
index 494c9cc..90f01e8 100755
--- a/configure
+++ b/configure
@@ -510,8 +510,6 @@ elif check_define __arm__ ; then
   cpu="arm"
 elif check_define __aarch64__ ; then
   cpu="aarch64"
-elif check_define __hppa__ ; then
-  cpu="hppa"
 else
   cpu=$(uname -m)
 fi
@@ -5847,7 +5845,7 @@ target_name=$(echo $target | cut -d '-' -f 1)
 target_bigendian="no"
 
 case "$target_name" in
-  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
+  armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
   target_bigendian=yes
   ;;
 esac
@@ -5910,6 +5908,8 @@ case "$target_name" in
   ;;
   cris)
   ;;
+  hppa)
+  ;;
   lm32)
   ;;
   m68k)
diff --git a/default-configs/hppa-linux-user.mak b/default-configs/hppa-linux-user.mak
new file mode 100644
index 0000000..7963939
--- /dev/null
+++ b/default-configs/hppa-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for hppa-linux-user
diff --git a/target/hppa/Makefile.objs b/target/hppa/Makefile.objs
new file mode 100644
index 0000000..263446f
--- /dev/null
+++ b/target/hppa/Makefile.objs
@@ -0,0 +1 @@
+obj-y += translate.o helper.o cpu.o op_helper.o gdbstub.o
diff --git a/target/hppa/cpu-qom.h b/target/hppa/cpu-qom.h
new file mode 100644
index 0000000..9084e47
--- /dev/null
+++ b/target/hppa/cpu-qom.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU HPPA CPU
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_HPPA_CPU_QOM_H
+#define QEMU_HPPA_CPU_QOM_H
+
+#include "qom/cpu.h"
+
+#define TYPE_HPPA_CPU "hppa-cpu"
+
+#define HPPA_CPU_CLASS(klass) \
+    OBJECT_CLASS_CHECK(HPPACPUClass, (klass), TYPE_HPPA_CPU)
+#define HPPA_CPU(obj) \
+    OBJECT_CHECK(HPPACPU, (obj), TYPE_HPPA_CPU)
+#define HPPA_CPU_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(HPPACPUClass, (obj), TYPE_HPPA_CPU)
+
+/**
+ * HPPACPUClass:
+ * @parent_realize: The parent class' realize handler.
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An HPPA CPU model.
+ */
+typedef struct HPPACPUClass {
+    /*< private >*/
+    CPUClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+    void (*parent_reset)(CPUState *cpu);
+} HPPACPUClass;
+
+typedef struct HPPACPU HPPACPU;
+
+#endif
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
new file mode 100644
index 0000000..1d791d0
--- /dev/null
+++ b/target/hppa/cpu.c
@@ -0,0 +1,164 @@
+/*
+ * QEMU HPPA CPU
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "migration/vmstate.h"
+#include "exec/exec-all.h"
+
+
+static void hppa_cpu_set_pc(CPUState *cs, vaddr value)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+
+    cpu->env.iaoq_f = value;
+    cpu->env.iaoq_b = value + 4;
+}
+
+static void hppa_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+
+    cpu->env.iaoq_f = tb->pc;
+    cpu->env.iaoq_b = tb->cs_base;
+    cpu->env.psw_n = tb->flags & 1;
+}
+
+static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
+{
+    info->mach = bfd_mach_hppa20;
+    info->print_insn = print_insn_hppa;
+}
+
+static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+    CPUState *cs = CPU(dev);
+    HPPACPUClass *acc = HPPA_CPU_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    cpu_exec_realizefn(cs, &local_err);
+    if (local_err != NULL) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    qemu_init_vcpu(cs);
+    acc->parent_realize(dev, errp);
+}
+
+/* Sort hppabetically by type name. */
+static gint hppa_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+    ObjectClass *class_a = (ObjectClass *)a;
+    ObjectClass *class_b = (ObjectClass *)b;
+    const char *name_a, *name_b;
+
+    name_a = object_class_get_name(class_a);
+    name_b = object_class_get_name(class_b);
+    return strcmp(name_a, name_b);
+}
+
+static void hppa_cpu_list_entry(gpointer data, gpointer user_data)
+{
+    ObjectClass *oc = data;
+    CPUListState *s = user_data;
+
+    (*s->cpu_fprintf)(s->file, "  %s\n", object_class_get_name(oc));
+}
+
+void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    CPUListState s = {
+        .file = f,
+        .cpu_fprintf = cpu_fprintf,
+    };
+    GSList *list;
+
+    list = object_class_get_list(TYPE_HPPA_CPU, false);
+    list = g_slist_sort(list, hppa_cpu_list_compare);
+    (*cpu_fprintf)(f, "Available CPUs:\n");
+    g_slist_foreach(list, hppa_cpu_list_entry, &s);
+    g_slist_free(list);
+}
+
+static void hppa_cpu_initfn(Object *obj)
+{
+    CPUState *cs = CPU(obj);
+    HPPACPU *cpu = HPPA_CPU(obj);
+    CPUHPPAState *env = &cpu->env;
+
+    cs->env_ptr = env;
+    cpu_hppa_loaded_fr0(env);
+    set_snan_bit_is_one(true, &env->fp_status);
+
+    hppa_translate_init();
+}
+
+HPPACPU *cpu_hppa_init(const char *cpu_model)
+{
+    HPPACPU *cpu;
+
+    cpu = HPPA_CPU(object_new(TYPE_HPPA_CPU));
+
+    object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
+
+    return cpu;
+}
+
+static void hppa_cpu_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    CPUClass *cc = CPU_CLASS(oc);
+    HPPACPUClass *acc = HPPA_CPU_CLASS(oc);
+
+    acc->parent_realize = dc->realize;
+    dc->realize = hppa_cpu_realizefn;
+
+    cc->do_interrupt = hppa_cpu_do_interrupt;
+    cc->cpu_exec_interrupt = hppa_cpu_exec_interrupt;
+    cc->dump_state = hppa_cpu_dump_state;
+    cc->set_pc = hppa_cpu_set_pc;
+    cc->synchronize_from_tb = hppa_cpu_synchronize_from_tb;
+    cc->gdb_read_register = hppa_cpu_gdb_read_register;
+    cc->gdb_write_register = hppa_cpu_gdb_write_register;
+    cc->handle_mmu_fault = hppa_cpu_handle_mmu_fault;
+    cc->disas_set_info = hppa_cpu_disas_set_info;
+
+    cc->gdb_num_core_regs = 128;
+}
+
+static const TypeInfo hppa_cpu_type_info = {
+    .name = TYPE_HPPA_CPU,
+    .parent = TYPE_CPU,
+    .instance_size = sizeof(HPPACPU),
+    .instance_init = hppa_cpu_initfn,
+    .abstract = false,
+    .class_size = sizeof(HPPACPUClass),
+    .class_init = hppa_cpu_class_init,
+};
+
+static void hppa_cpu_register_types(void)
+{
+    type_register_static(&hppa_cpu_type_info);
+}
+
+type_init(hppa_cpu_register_types)
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
new file mode 100644
index 0000000..4cf4ac6
--- /dev/null
+++ b/target/hppa/cpu.h
@@ -0,0 +1,144 @@
+/*
+ * PA-RISC emulation cpu definitions for qemu.
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HPPA_CPU_H
+#define HPPA_CPU_H
+
+#include "qemu-common.h"
+#include "cpu-qom.h"
+
+/* We only support hppa-linux-user at present, so 32-bit only.  */
+#define TARGET_LONG_BITS 32
+#define TARGET_PHYS_ADDR_SPACE_BITS  32
+#define TARGET_VIRT_ADDR_SPACE_BITS  32
+
+#define CPUArchState struct CPUHPPAState
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+#define TARGET_PAGE_BITS 12
+
+#define ALIGNED_ONLY
+#define NB_MMU_MODES     1
+#define MMU_USER_IDX     0
+#define TARGET_INSN_START_EXTRA_WORDS 1
+
+#define EXCP_SYSCALL     1
+#define EXCP_SYSCALL_LWS 2
+#define EXCP_SIGSEGV     3
+#define EXCP_SIGILL      4
+#define EXCP_SIGFPE      5
+
+typedef struct CPUHPPAState CPUHPPAState;
+
+struct CPUHPPAState {
+    target_ulong gr[32];
+    uint64_t fr[32];
+
+    target_ulong sar;
+    target_ulong cr26;
+    target_ulong cr27;
+
+    target_ulong psw_n;      /* boolean */
+    target_long  psw_v;      /* in most significant bit */
+
+    /* Splitting the carry-borrow field into the MSB and "the rest", allows
+     * for "the rest" to be deleted when it is unused, but the MSB is in use.
+     * In addition, it's easier to compute carry-in for bit B+1 than it is to
+     * compute carry-out for bit B (3 vs 4 insns for addition, assuming the
+     * host has the appropriate add-with-carry insn to compute the msb).
+     * Therefore the carry bits are stored as: cb_msb : cb & 0x11111110.
+     */
+    target_ulong psw_cb;     /* in least significant bit of next nibble */
+    target_ulong psw_cb_msb; /* boolean */
+
+    target_ulong iaoq_f;     /* front */
+    target_ulong iaoq_b;     /* back, aka next instruction */
+
+    target_ulong ior;        /* interrupt offset register */
+
+    uint32_t fr0_shadow;     /* flags, c, ca/cq, rm, d, enables */
+    float_status fp_status;
+
+    /* Those resources are used only in QEMU core */
+    CPU_COMMON
+};
+
+/**
+ * HPPACPU:
+ * @env: #CPUHPPAState
+ *
+ * An HPPA CPU.
+ */
+struct HPPACPU {
+    /*< private >*/
+    CPUState parent_obj;
+    /*< public >*/
+
+    CPUHPPAState env;
+};
+
+static inline HPPACPU *hppa_env_get_cpu(CPUHPPAState *env)
+{
+    return container_of(env, HPPACPU, env);
+}
+
+#define ENV_GET_CPU(e)  CPU(hppa_env_get_cpu(e))
+#define ENV_OFFSET      offsetof(HPPACPU, env)
+
+#include "exec/cpu-all.h"
+
+static inline int cpu_mmu_index(CPUHPPAState *env, bool ifetch)
+{
+    return 0;
+}
+
+void hppa_translate_init(void);
+
+HPPACPU *cpu_hppa_init(const char *cpu_model);
+
+#define cpu_init(cpu_model) CPU(cpu_hppa_init(cpu_model))
+
+void hppa_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+
+static inline void cpu_get_tb_cpu_state(CPUHPPAState *env, target_ulong *pc,
+                                        target_ulong *cs_base,
+                                        uint32_t *pflags)
+{
+    *pc = env->iaoq_f;
+    *cs_base = env->iaoq_b;
+    *pflags = env->psw_n;
+}
+
+target_ulong cpu_hppa_get_psw(CPUHPPAState *env);
+void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong);
+void cpu_hppa_loaded_fr0(CPUHPPAState *env);
+
+#define cpu_signal_handler cpu_hppa_signal_handler
+
+int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
+int hppa_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, int midx);
+int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+void hppa_cpu_do_interrupt(CPUState *cpu);
+bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void hppa_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function, int);
+
+#endif /* HPPA_CPU_H */
diff --git a/target/hppa/gdbstub.c b/target/hppa/gdbstub.c
new file mode 100644
index 0000000..413a5e1
--- /dev/null
+++ b/target/hppa/gdbstub.c
@@ -0,0 +1,111 @@
+/*
+ * HPPA gdb server stub
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "exec/gdbstub.h"
+
+int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+    CPUHPPAState *env = &cpu->env;
+    target_ulong val;
+
+    switch (n) {
+    case 0:
+        val = cpu_hppa_get_psw(env);
+        break;
+    case 1 ... 31:
+        val = env->gr[n];
+        break;
+    case 32:
+        val = env->sar;
+        break;
+    case 33:
+        val = env->iaoq_f;
+        break;
+    case 35:
+        val = env->iaoq_b;
+        break;
+    case 59:
+        val = env->cr26;
+        break;
+    case 60:
+        val = env->cr27;
+        break;
+    case 64 ... 127:
+        val = extract64(env->fr[(n - 64) / 2], (n & 1 ? 0 : 32), 32);
+        break;
+    default:
+        if (n < 128) {
+            val = 0;
+        } else {
+            return 0;
+        }
+        break;
+    }
+    return gdb_get_regl(mem_buf, val);
+}
+
+int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+    CPUHPPAState *env = &cpu->env;
+    target_ulong val = ldtul_p(mem_buf);
+
+    switch (n) {
+    case 0:
+        cpu_hppa_put_psw(env, val);
+        break;
+    case 1 ... 31:
+        env->gr[n] = val;
+        break;
+    case 32:
+        env->sar = val;
+        break;
+    case 33:
+        env->iaoq_f = val;
+        break;
+    case 35:
+        env->iaoq_b = val;
+    case 59:
+        env->cr26 = val;
+        break;
+    case 60:
+        env->cr27 = val;
+        break;
+    case 64:
+        env->fr[0] = deposit64(env->fr[0], 32, 32, val);
+        cpu_hppa_loaded_fr0(env);
+        break;
+    case 65 ... 127:
+        {
+            uint64_t *fr = &env->fr[(n - 64) / 2];
+            *fr = deposit64(*fr, val, (n & 1 ? 0 : 32), 32);
+        }
+        break;
+    default:
+        if (n >= 128) {
+            return 0;
+        }
+        break;
+    }
+    return sizeof(target_ulong);
+}
diff --git a/target/hppa/helper.c b/target/hppa/helper.c
new file mode 100644
index 0000000..ba04a9a
--- /dev/null
+++ b/target/hppa/helper.c
@@ -0,0 +1,137 @@
+/*
+ *  HPPA emulation cpu helpers for qemu.
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "fpu/softfloat.h"
+#include "exec/helper-proto.h"
+
+target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
+{
+    target_ulong psw;
+
+    /* Fold carry bits down to 8 consecutive bits.  */
+    /* ??? Needs tweaking for hppa64.  */
+    /* .......b...c...d...e...f...g...h */
+    psw = (env->psw_cb >> 4) & 0x01111111;
+    /* .......b..bc..cd..de..ef..fg..gh */
+    psw |= psw >> 3;
+    /* .............bcd............efgh */
+    psw |= (psw >> 6) & 0x000f000f;
+    /* .........................bcdefgh */
+    psw |= (psw >> 12) & 0xf;
+    psw |= env->psw_cb_msb << 7;
+    psw <<= 8;
+
+    psw |= env->psw_n << 21;
+    psw |= (env->psw_v < 0) << 17;
+
+    return psw;
+}
+
+void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
+{
+    target_ulong cb = 0;
+
+    env->psw_n = (psw >> 21) & 1;
+    env->psw_v = -((psw >> 17) & 1);
+    env->psw_cb_msb = (psw >> 15) & 1;
+
+    cb |= ((psw >> 14) & 1) << 28;
+    cb |= ((psw >> 13) & 1) << 24;
+    cb |= ((psw >> 12) & 1) << 20;
+    cb |= ((psw >> 11) & 1) << 16;
+    cb |= ((psw >> 10) & 1) << 12;
+    cb |= ((psw >>  9) & 1) <<  8;
+    cb |= ((psw >>  8) & 1) <<  4;
+    env->psw_cb = cb;
+}
+
+int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
+                              int rw, int mmu_idx)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+
+    cs->exception_index = EXCP_SIGSEGV;
+    cpu->env.ior = address;
+    return 1;
+}
+
+void hppa_cpu_do_interrupt(CPUState *cs)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+    CPUHPPAState *env = &cpu->env;
+    int i = cs->exception_index;
+
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        static int count;
+        const char *name = "<unknown>";
+
+        switch (i) {
+        case EXCP_SYSCALL:
+            name = "syscall";
+            break;
+        case EXCP_SIGSEGV:
+            name = "sigsegv";
+            break;
+        case EXCP_SIGILL:
+            name = "sigill";
+            break;
+        case EXCP_SIGFPE:
+            name = "sigfpe";
+            break;
+        }
+        qemu_log("INT %6d: %s ia_f=" TARGET_FMT_lx "\n",
+                 ++count, name, env->iaoq_f);
+    }
+    cs->exception_index = -1;
+}
+
+bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    abort();
+    return false;
+}
+
+void hppa_cpu_dump_state(CPUState *cs, FILE *f,
+                         fprintf_function cpu_fprintf, int flags)
+{
+    HPPACPU *cpu = HPPA_CPU(cs);
+    CPUHPPAState *env = &cpu->env;
+    int i;
+
+    cpu_fprintf(f, "IA_F " TARGET_FMT_lx
+                   " IA_B " TARGET_FMT_lx
+                   " PSW  " TARGET_FMT_lx
+                   " [N:" TARGET_FMT_ld " V:%d"
+                   " CB:" TARGET_FMT_lx "]\n              ",
+                env->iaoq_f, env->iaoq_b, cpu_hppa_get_psw(env),
+                env->psw_n, env->psw_v < 0,
+                ((env->psw_cb >> 4) & 0x01111111) | (env->psw_cb_msb << 28));
+    for (i = 1; i < 32; i++) {
+        cpu_fprintf(f, "GR%02d " TARGET_FMT_lx " ", i, env->gr[i]);
+        if ((i % 4) == 3) {
+            cpu_fprintf(f, "\n");
+        }
+    }
+
+    /* ??? FR */
+}
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
new file mode 100644
index 0000000..9c94dac
--- /dev/null
+++ b/target/hppa/helper.h
@@ -0,0 +1,3 @@
+DEF_HELPER_2(excp, noreturn, env, int)
+
+DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
new file mode 100644
index 0000000..4dd0119
--- /dev/null
+++ b/target/hppa/op_helper.c
@@ -0,0 +1,65 @@
+/*
+ * Helpers for HPPA instructions.
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "exec/helper-proto.h"
+
+void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
+{
+    HPPACPU *cpu = hppa_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = excp;
+    cpu_loop_exit(cs);
+}
+
+void HELPER(loaded_fr0)(CPUHPPAState *env)
+{
+    uint32_t shadow = env->fr[0] >> 32;
+    int rm, d;
+
+    env->fr0_shadow = shadow;
+
+    switch (extract32(shadow, 9, 2)) {
+    default:
+        rm = float_round_nearest_even;
+        break;
+    case 1:
+        rm = float_round_to_zero;
+        break;
+    case 2:
+        rm = float_round_up;
+        break;
+    case 3:
+        rm = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rm, &env->fp_status);
+
+    d = extract32(shadow, 5, 1);
+    set_flush_to_zero(d, &env->fp_status);
+    set_flush_inputs_to_zero(d, &env->fp_status);
+}
+
+void cpu_hppa_loaded_fr0(CPUHPPAState *env)
+{
+    helper_loaded_fr0(env);
+}
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
new file mode 100644
index 0000000..8d61853
--- /dev/null
+++ b/target/hppa/translate.c
@@ -0,0 +1,429 @@
+/*
+ * HPPA emulation cpu translation for qemu.
+ *
+ * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "disas/disas.h"
+#include "qemu/host-utils.h"
+#include "exec/exec-all.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+
+#include "trace-tcg.h"
+#include "exec/log.h"
+
+typedef struct DisasCond {
+    TCGCond c;
+    TCGv a0, a1;
+    bool a0_is_n;
+    bool a1_is_0;
+} DisasCond;
+
+typedef struct DisasContext {
+    struct TranslationBlock *tb;
+    CPUState *cs;
+
+    target_ulong iaoq_f;
+    target_ulong iaoq_b;
+    target_ulong iaoq_n;
+    TCGv iaoq_n_var;
+
+    int ntemps;
+    TCGv temps[8];
+
+    DisasCond null_cond;
+    TCGLabel *null_lab;
+
+    bool singlestep_enabled;
+    bool psw_n_nonzero;
+} DisasContext;
+
+/* Return values from translate_one, indicating the state of the TB.
+   Note that zero indicates that we are not exiting the TB.  */
+
+typedef enum {
+    NO_EXIT,
+
+    /* We have emitted one or more goto_tb.  No fixup required.  */
+    EXIT_GOTO_TB,
+
+    /* We are not using a goto_tb (for whatever reason), but have updated
+       the iaq (for whatever reason), so don't do it again on exit.  */
+    EXIT_IAQ_N_UPDATED,
+
+    /* We are exiting the TB, but have neither emitted a goto_tb, nor
+       updated the iaq for the next instruction to be executed.  */
+    EXIT_IAQ_N_STALE,
+
+    /* We are ending the TB with a noreturn function call, e.g. longjmp.
+       No following code will be executed.  */
+    EXIT_NORETURN,
+} ExitStatus;
+
+typedef struct DisasInsn {
+    uint32_t insn, mask;
+    ExitStatus (*trans)(DisasContext *ctx, uint32_t insn,
+                        const struct DisasInsn *f);
+} DisasInsn;
+
+/* global register indexes */
+static TCGv_env cpu_env;
+static TCGv cpu_gr[32];
+static TCGv cpu_iaoq_f;
+static TCGv cpu_iaoq_b;
+static TCGv cpu_sar;
+static TCGv cpu_psw_n;
+static TCGv cpu_psw_v;
+static TCGv cpu_psw_cb;
+static TCGv cpu_psw_cb_msb;
+static TCGv cpu_cr26;
+static TCGv cpu_cr27;
+
+#include "exec/gen-icount.h"
+
+void hppa_translate_init(void)
+{
+#define DEF_VAR(V)  { &cpu_##V, #V, offsetof(CPUHPPAState, V) }
+
+    typedef struct { TCGv *var; const char *name; int ofs; } GlobalVar;
+    static const GlobalVar vars[] = {
+        DEF_VAR(sar),
+        DEF_VAR(cr26),
+        DEF_VAR(cr27),
+        DEF_VAR(psw_n),
+        DEF_VAR(psw_v),
+        DEF_VAR(psw_cb),
+        DEF_VAR(psw_cb_msb),
+        DEF_VAR(iaoq_f),
+        DEF_VAR(iaoq_b),
+    };
+
+#undef DEF_VAR
+
+    /* Use the symbolic register names that match the disassembler.  */
+    static const char gr_names[32][4] = {
+        "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
+        "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
+        "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+        "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+    };
+
+    static bool done_init = 0;
+    int i;
+
+    if (done_init) {
+        return;
+    }
+    done_init = 1;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+    tcg_ctx.tcg_env = cpu_env;
+
+    TCGV_UNUSED(cpu_gr[0]);
+    for (i = 1; i < 32; i++) {
+        cpu_gr[i] = tcg_global_mem_new(cpu_env,
+                                       offsetof(CPUHPPAState, gr[i]),
+                                       gr_names[i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(vars); ++i) {
+        const GlobalVar *v = &vars[i];
+        *v->var = tcg_global_mem_new(cpu_env, v->ofs, v->name);
+    }
+}
+
+static TCGv get_temp(DisasContext *ctx)
+{
+    unsigned i = ctx->ntemps++;
+    g_assert(i < ARRAY_SIZE(ctx->temps));
+    return ctx->temps[i] = tcg_temp_new();
+}
+
+static TCGv load_const(DisasContext *ctx, target_long v)
+{
+    TCGv t = get_temp(ctx);
+    tcg_gen_movi_tl(t, v);
+    return t;
+}
+
+static TCGv load_gpr(DisasContext *ctx, unsigned reg)
+{
+    if (reg == 0) {
+        TCGv t = get_temp(ctx);
+        tcg_gen_movi_tl(t, 0);
+        return t;
+    } else {
+        return cpu_gr[reg];
+    }
+}
+
+static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
+{
+    if (reg == 0) {
+        return get_temp(ctx);
+    } else {
+        return cpu_gr[reg];
+    }
+}
+
+static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
+{
+    if (unlikely(ival == -1)) {
+        tcg_gen_mov_tl(dest, vval);
+    } else {
+        tcg_gen_movi_tl(dest, ival);
+    }
+}
+
+static inline target_ulong iaoq_dest(DisasContext *ctx, target_long disp)
+{
+    return ctx->iaoq_f + disp + 8;
+}
+
+static void gen_excp_1(int exception)
+{
+    TCGv_i32 t = tcg_const_i32(exception);
+    gen_helper_excp(cpu_env, t);
+    tcg_temp_free_i32(t);
+}
+
+static ExitStatus gen_excp(DisasContext *ctx, int exception)
+{
+    copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
+    copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
+    gen_excp_1(exception);
+    return EXIT_NORETURN;
+}
+
+static ExitStatus gen_illegal(DisasContext *ctx)
+{
+    return gen_excp(ctx, EXCP_SIGILL);
+}
+
+static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
+{
+    /* Suppress goto_tb in the case of single-steping and IO.  */
+    if ((ctx->tb->cflags & CF_LAST_IO) || ctx->singlestep_enabled) {
+        return false;
+    }
+    return true;
+}
+
+static void gen_goto_tb(DisasContext *ctx, int which,
+                        target_ulong f, target_ulong b)
+{
+    if (f != -1 && b != -1 && use_goto_tb(ctx, f)) {
+        tcg_gen_goto_tb(which);
+        tcg_gen_movi_tl(cpu_iaoq_f, f);
+        tcg_gen_movi_tl(cpu_iaoq_b, b);
+        tcg_gen_exit_tb((uintptr_t)ctx->tb + which);
+    } else {
+        copy_iaoq_entry(cpu_iaoq_f, f, cpu_iaoq_b);
+        copy_iaoq_entry(cpu_iaoq_b, b, ctx->iaoq_n_var);
+        if (ctx->singlestep_enabled) {
+            gen_excp_1(EXCP_DEBUG);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+    }
+}
+
+static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
+                                      const DisasInsn table[], size_t n)
+{
+    size_t i;
+    for (i = 0; i < n; ++i) {
+        if ((insn & table[i].mask) == table[i].insn) {
+            return table[i].trans(ctx, insn, &table[i]);
+        }
+    }
+    return gen_illegal(ctx);
+}
+
+#define translate_table(ctx, insn, table) \
+    translate_table_int(ctx, insn, table, ARRAY_SIZE(table))
+
+static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
+{
+    uint32_t opc = extract32(insn, 26, 6);
+
+    switch (opc) {
+    default:
+        break;
+    }
+    return gen_illegal(ctx);
+}
+
+void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
+{
+    HPPACPU *cpu = hppa_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+    DisasContext ctx;
+    ExitStatus ret;
+    int num_insns, max_insns, i;
+
+    ctx.tb = tb;
+    ctx.cs = cs;
+    ctx.iaoq_f = tb->pc;
+    ctx.iaoq_b = tb->cs_base;
+    ctx.singlestep_enabled = cs->singlestep_enabled;
+
+    ctx.ntemps = 0;
+    for (i = 0; i < ARRAY_SIZE(ctx.temps); ++i) {
+        TCGV_UNUSED(ctx.temps[i]);
+    }
+
+    /* Compute the maximum number of insns to execute, as bounded by
+       (1) icount, (2) single-stepping, (3) branch delay slots, or
+       (4) the number of insns remaining on the current page.  */
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0) {
+        max_insns = CF_COUNT_MASK;
+    }
+    if (ctx.singlestep_enabled || singlestep) {
+        max_insns = 1;
+    } else if (max_insns > TCG_MAX_INSNS) {
+        max_insns = TCG_MAX_INSNS;
+    }
+
+    num_insns = 0;
+    gen_tb_start(tb);
+
+    do {
+        tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
+        num_insns++;
+
+        if (unlikely(cpu_breakpoint_test(cs, ctx.iaoq_f, BP_ANY))) {
+            ret = gen_excp(&ctx, EXCP_DEBUG);
+            break;
+        }
+        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
+            gen_io_start();
+        }
+
+        {
+            /* Always fetch the insn, even if nullified, so that we check
+               the page permissions for execute.  */
+            uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
+
+            /* Set up the IA queue for the next insn.
+               This will be overwritten by a branch.  */
+            if (ctx.iaoq_b == -1) {
+                ctx.iaoq_n = -1;
+                ctx.iaoq_n_var = get_temp(&ctx);
+                tcg_gen_addi_tl(ctx.iaoq_n_var, cpu_iaoq_b, 4);
+            } else {
+                ctx.iaoq_n = ctx.iaoq_b + 4;
+                TCGV_UNUSED(ctx.iaoq_n_var);
+            }
+
+            ret = translate_one(&ctx, insn);
+        }
+
+        for (i = 0; i < ctx.ntemps; ++i) {
+            tcg_temp_free(ctx.temps[i]);
+            TCGV_UNUSED(ctx.temps[i]);
+        }
+        ctx.ntemps = 0;
+
+        /* If we see non-linear instructions, exhaust instruction count,
+           or run out of buffer space, stop generation.  */
+        /* ??? The non-linear instruction restriction is purely due to
+           the debugging dump.  Otherwise we *could* follow unconditional
+           branches within the same page.  */
+        if (ret == NO_EXIT
+            && (ctx.iaoq_b != ctx.iaoq_f + 4
+                || num_insns >= max_insns
+                || tcg_op_buf_full())) {
+            ret = EXIT_IAQ_N_STALE;
+        }
+
+        ctx.iaoq_f = ctx.iaoq_b;
+        ctx.iaoq_b = ctx.iaoq_n;
+        if (ret == EXIT_NORETURN
+            || ret == EXIT_GOTO_TB
+            || ret == EXIT_IAQ_N_UPDATED) {
+            break;
+        }
+        if (ctx.iaoq_f == -1) {
+            tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
+            copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
+            ret = EXIT_IAQ_N_UPDATED;
+            break;
+        }
+        if (ctx.iaoq_b == -1) {
+            tcg_gen_mov_tl(cpu_iaoq_b, ctx.iaoq_n_var);
+        }
+    } while (ret == NO_EXIT);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    switch (ret) {
+    case EXIT_GOTO_TB:
+    case EXIT_NORETURN:
+        break;
+    case EXIT_IAQ_N_STALE:
+        copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
+        copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
+        /* FALLTHRU */
+    case EXIT_IAQ_N_UPDATED:
+        if (ctx.singlestep_enabled) {
+            gen_excp_1(EXCP_DEBUG);
+        } else {
+            tcg_gen_exit_tb(0);
+        }
+        break;
+    default:
+        abort();
+    }
+
+    gen_tb_end(tb, num_insns);
+
+    tb->size = num_insns * 4;
+    tb->icount = num_insns;
+
+#ifdef DEBUG_DISAS
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
+        && qemu_log_in_addr_range(tb->pc)) {
+        qemu_log_lock();
+        qemu_log("IN: %s\n", lookup_symbol(tb->pc));
+        log_target_disas(cs, tb->pc, tb->size, 1);
+        qemu_log("\n");
+        qemu_log_unlock();
+    }
+#endif
+}
+
+void restore_state_to_opc(CPUHPPAState *env, TranslationBlock *tb,
+                          target_ulong *data)
+{
+    env->iaoq_f = data[0];
+    if (data[1] != -1) {
+        env->iaoq_b = data[1];
+    }
+    /* Since we were executing the instruction at IAOQ_F, and took some
+       sort of action that provoked the cpu_restore_state, we can infer
+       that the instruction was not nullified.  */
+    env->psw_n = 0;
+}
-- 
2.9.3

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

* [Qemu-devel] [PULL 19/26] target-hppa: Add nullification framework
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (16 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 20/26] target-hppa: Implement basic arithmetic Richard Henderson
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

The HPPA cpu has a unique form of predicated execution in which
almost any instruction can set the PSW[N] (or "nullify") bit,
which suppresses execution (and even decoding) of the following
instruction.  Execution of a nullified insn clears the PSW[N] bit.

This adds a generic framework for branching over nullified insns,
or for sufficiently simple insns, transforming the writeback of
the result to a conditional move.  In the process, we want to be
able to represent PSW[N] as a TCG condition, which implies management
of the related tcg temps.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/translate.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 224 insertions(+), 4 deletions(-)

diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 8d61853..22dfb73 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -151,6 +151,78 @@ void hppa_translate_init(void)
     }
 }
 
+static DisasCond cond_make_f(void)
+{
+    DisasCond r = { .c = TCG_COND_NEVER };
+    TCGV_UNUSED(r.a0);
+    TCGV_UNUSED(r.a1);
+    return r;
+}
+
+static DisasCond cond_make_n(void)
+{
+    DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true };
+    r.a0 = cpu_psw_n;
+    TCGV_UNUSED(r.a1);
+    return r;
+}
+
+static DisasCond cond_make_0(TCGCond c, TCGv a0)
+{
+    DisasCond r = { .c = c, .a1_is_0 = true };
+
+    assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
+    r.a0 = tcg_temp_new();
+    tcg_gen_mov_tl(r.a0, a0);
+    TCGV_UNUSED(r.a1);
+
+    return r;
+}
+
+static DisasCond cond_make(TCGCond c, TCGv a0, TCGv a1)
+{
+    DisasCond r = { .c = c };
+
+    assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS);
+    r.a0 = tcg_temp_new();
+    tcg_gen_mov_tl(r.a0, a0);
+    r.a1 = tcg_temp_new();
+    tcg_gen_mov_tl(r.a1, a1);
+
+    return r;
+}
+
+static void cond_prep(DisasCond *cond)
+{
+    if (cond->a1_is_0) {
+        cond->a1_is_0 = false;
+        cond->a1 = tcg_const_tl(0);
+    }
+}
+
+static void cond_free(DisasCond *cond)
+{
+    switch (cond->c) {
+    default:
+        if (!cond->a0_is_n) {
+            tcg_temp_free(cond->a0);
+        }
+        if (!cond->a1_is_0) {
+            tcg_temp_free(cond->a1);
+        }
+        cond->a0_is_n = false;
+        cond->a1_is_0 = false;
+        TCGV_UNUSED(cond->a0);
+        TCGV_UNUSED(cond->a1);
+        /* fallthru */
+    case TCG_COND_ALWAYS:
+        cond->c = TCG_COND_NEVER;
+        break;
+    case TCG_COND_NEVER:
+        break;
+    }
+}
+
 static TCGv get_temp(DisasContext *ctx)
 {
     unsigned i = ctx->ntemps++;
@@ -178,13 +250,125 @@ static TCGv load_gpr(DisasContext *ctx, unsigned reg)
 
 static TCGv dest_gpr(DisasContext *ctx, unsigned reg)
 {
-    if (reg == 0) {
+    if (reg == 0 || ctx->null_cond.c != TCG_COND_NEVER) {
         return get_temp(ctx);
     } else {
         return cpu_gr[reg];
     }
 }
 
+static void save_or_nullify(DisasContext *ctx, TCGv dest, TCGv t)
+{
+    if (ctx->null_cond.c != TCG_COND_NEVER) {
+        cond_prep(&ctx->null_cond);
+        tcg_gen_movcond_tl(ctx->null_cond.c, dest, ctx->null_cond.a0,
+                           ctx->null_cond.a1, dest, t);
+    } else {
+        tcg_gen_mov_tl(dest, t);
+    }
+}
+
+static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
+{
+    if (reg != 0) {
+        save_or_nullify(ctx, cpu_gr[reg], t);
+    }
+}
+
+/* Skip over the implementation of an insn that has been nullified.
+   Use this when the insn is too complex for a conditional move.  */
+static void nullify_over(DisasContext *ctx)
+{
+    if (ctx->null_cond.c != TCG_COND_NEVER) {
+        /* The always condition should have been handled in the main loop.  */
+        assert(ctx->null_cond.c != TCG_COND_ALWAYS);
+
+        ctx->null_lab = gen_new_label();
+        cond_prep(&ctx->null_cond);
+
+        /* If we're using PSW[N], copy it to a temp because... */
+        if (ctx->null_cond.a0_is_n) {
+            ctx->null_cond.a0_is_n = false;
+            ctx->null_cond.a0 = tcg_temp_new();
+            tcg_gen_mov_tl(ctx->null_cond.a0, cpu_psw_n);
+        }
+        /* ... we clear it before branching over the implementation,
+           so that (1) it's clear after nullifying this insn and
+           (2) if this insn nullifies the next, PSW[N] is valid.  */
+        if (ctx->psw_n_nonzero) {
+            ctx->psw_n_nonzero = false;
+            tcg_gen_movi_tl(cpu_psw_n, 0);
+        }
+
+        tcg_gen_brcond_tl(ctx->null_cond.c, ctx->null_cond.a0,
+                          ctx->null_cond.a1, ctx->null_lab);
+        cond_free(&ctx->null_cond);
+    }
+}
+
+/* Save the current nullification state to PSW[N].  */
+static void nullify_save(DisasContext *ctx)
+{
+    if (ctx->null_cond.c == TCG_COND_NEVER) {
+        if (ctx->psw_n_nonzero) {
+            tcg_gen_movi_tl(cpu_psw_n, 0);
+        }
+        return;
+    }
+    if (!ctx->null_cond.a0_is_n) {
+        cond_prep(&ctx->null_cond);
+        tcg_gen_setcond_tl(ctx->null_cond.c, cpu_psw_n,
+                           ctx->null_cond.a0, ctx->null_cond.a1);
+        ctx->psw_n_nonzero = true;
+    }
+    cond_free(&ctx->null_cond);
+}
+
+/* Set a PSW[N] to X.  The intention is that this is used immediately
+   before a goto_tb/exit_tb, so that there is no fallthru path to other
+   code within the TB.  Therefore we do not update psw_n_nonzero.  */
+static void nullify_set(DisasContext *ctx, bool x)
+{
+    if (ctx->psw_n_nonzero || x) {
+        tcg_gen_movi_tl(cpu_psw_n, x);
+    }
+}
+
+/* Mark the end of an instruction that may have been nullified.
+   This is the pair to nullify_over.  */
+static ExitStatus nullify_end(DisasContext *ctx, ExitStatus status)
+{
+    TCGLabel *null_lab = ctx->null_lab;
+
+    if (likely(null_lab == NULL)) {
+        /* The current insn wasn't conditional or handled the condition
+           applied to it without a branch, so the (new) setting of
+           NULL_COND can be applied directly to the next insn.  */
+        return status;
+    }
+    ctx->null_lab = NULL;
+
+    if (likely(ctx->null_cond.c == TCG_COND_NEVER)) {
+        /* The next instruction will be unconditional,
+           and NULL_COND already reflects that.  */
+        gen_set_label(null_lab);
+    } else {
+        /* The insn that we just executed is itself nullifying the next
+           instruction.  Store the condition in the PSW[N] global.
+           We asserted PSW[N] = 0 in nullify_over, so that after the
+           label we have the proper value in place.  */
+        nullify_save(ctx);
+        gen_set_label(null_lab);
+        ctx->null_cond = cond_make_n();
+    }
+
+    assert(status != EXIT_GOTO_TB && status != EXIT_IAQ_N_UPDATED);
+    if (status == EXIT_NORETURN) {
+        status = NO_EXIT;
+    }
+    return status;
+}
+
 static void copy_iaoq_entry(TCGv dest, target_ulong ival, TCGv vval)
 {
     if (unlikely(ival == -1)) {
@@ -210,13 +394,15 @@ static ExitStatus gen_excp(DisasContext *ctx, int exception)
 {
     copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_f, cpu_iaoq_f);
     copy_iaoq_entry(cpu_iaoq_b, ctx->iaoq_b, cpu_iaoq_b);
+    nullify_save(ctx);
     gen_excp_1(exception);
     return EXIT_NORETURN;
 }
 
 static ExitStatus gen_illegal(DisasContext *ctx)
 {
-    return gen_excp(ctx, EXCP_SIGILL);
+    nullify_over(ctx);
+    return nullify_end(ctx, gen_excp(ctx, EXCP_SIGILL));
 }
 
 static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
@@ -228,6 +414,16 @@ static bool use_goto_tb(DisasContext *ctx, target_ulong dest)
     return true;
 }
 
+/* If the next insn is to be nullified, and it's on the same page,
+   and we're not attempting to set a breakpoint on it, then we can
+   totally skip the nullified insn.  This avoids creating and
+   executing a TB that merely branches to the next TB.  */
+static bool use_nullify_skip(DisasContext *ctx)
+{
+    return (((ctx->iaoq_b ^ ctx->iaoq_f) & TARGET_PAGE_MASK) == 0
+            && !cpu_breakpoint_test(ctx->cs, ctx->iaoq_b, BP_ANY));
+}
+
 static void gen_goto_tb(DisasContext *ctx, int which,
                         target_ulong f, target_ulong b)
 {
@@ -308,6 +504,15 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
     num_insns = 0;
     gen_tb_start(tb);
 
+    /* Seed the nullification status from PSW[N], as shown in TB->FLAGS.  */
+    ctx.null_cond = cond_make_f();
+    ctx.psw_n_nonzero = false;
+    if (tb->flags & 1) {
+        ctx.null_cond.c = TCG_COND_ALWAYS;
+        ctx.psw_n_nonzero = true;
+    }
+    ctx.null_lab = NULL;
+
     do {
         tcg_gen_insn_start(ctx.iaoq_f, ctx.iaoq_b);
         num_insns++;
@@ -336,7 +541,13 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
                 TCGV_UNUSED(ctx.iaoq_n_var);
             }
 
-            ret = translate_one(&ctx, insn);
+            if (unlikely(ctx.null_cond.c == TCG_COND_ALWAYS)) {
+                ctx.null_cond.c = TCG_COND_NEVER;
+                ret = NO_EXIT;
+            } else {
+                ret = translate_one(&ctx, insn);
+                assert(ctx.null_lab == NULL);
+            }
         }
 
         for (i = 0; i < ctx.ntemps; ++i) {
@@ -354,7 +565,14 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
             && (ctx.iaoq_b != ctx.iaoq_f + 4
                 || num_insns >= max_insns
                 || tcg_op_buf_full())) {
-            ret = EXIT_IAQ_N_STALE;
+            if (ctx.null_cond.c == TCG_COND_NEVER
+                || ctx.null_cond.c == TCG_COND_ALWAYS) {
+                nullify_set(&ctx, ctx.null_cond.c == TCG_COND_ALWAYS);
+                gen_goto_tb(&ctx, 0, ctx.iaoq_b, ctx.iaoq_n);
+                ret = EXIT_GOTO_TB;
+            } else {
+                ret = EXIT_IAQ_N_STALE;
+            }
         }
 
         ctx.iaoq_f = ctx.iaoq_b;
@@ -367,6 +585,7 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
         if (ctx.iaoq_f == -1) {
             tcg_gen_mov_tl(cpu_iaoq_f, cpu_iaoq_b);
             copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_n, ctx.iaoq_n_var);
+            nullify_save(&ctx);
             ret = EXIT_IAQ_N_UPDATED;
             break;
         }
@@ -386,6 +605,7 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
     case EXIT_IAQ_N_STALE:
         copy_iaoq_entry(cpu_iaoq_f, ctx.iaoq_f, cpu_iaoq_f);
         copy_iaoq_entry(cpu_iaoq_b, ctx.iaoq_b, cpu_iaoq_b);
+        nullify_save(&ctx);
         /* FALLTHRU */
     case EXIT_IAQ_N_UPDATED:
         if (ctx.singlestep_enabled) {
-- 
2.9.3

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

* [Qemu-devel] [PULL 20/26] target-hppa: Implement basic arithmetic
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (17 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 19/26] target-hppa: Add nullification framework Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 21/26] target-hppa: Implement branches Richard Henderson
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/helper.h    |   2 +
 target/hppa/op_helper.c |  23 ++
 target/hppa/translate.c | 882 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 907 insertions(+)

diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index 9c94dac..ecff17c 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -1,3 +1,5 @@
 DEF_HELPER_2(excp, noreturn, env, int)
+DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl)
 
 DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 4dd0119..f36ce74 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -31,6 +31,29 @@ void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
     cpu_loop_exit(cs);
 }
 
+static void QEMU_NORETURN dynexcp(CPUHPPAState *env, int excp, uintptr_t ra)
+{
+    HPPACPU *cpu = hppa_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+
+    cs->exception_index = excp;
+    cpu_loop_exit_restore(cs, ra);
+}
+
+void HELPER(tsv)(CPUHPPAState *env, target_ulong cond)
+{
+    if (unlikely((target_long)cond < 0)) {
+        dynexcp(env, EXCP_SIGFPE, GETPC());
+    }
+}
+
+void HELPER(tcond)(CPUHPPAState *env, target_ulong cond)
+{
+    if (unlikely(cond)) {
+        dynexcp(env, EXCP_SIGFPE, GETPC());
+    }
+}
+
 void HELPER(loaded_fr0)(CPUHPPAState *env)
 {
     uint32_t shadow = env->fr[0] >> 32;
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 22dfb73..2ad651c 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -83,6 +83,9 @@ typedef struct DisasInsn {
     uint32_t insn, mask;
     ExitStatus (*trans)(DisasContext *ctx, uint32_t insn,
                         const struct DisasInsn *f);
+    union {
+        void (*f_ttt)(TCGv, TCGv, TCGv);
+    };
 } DisasInsn;
 
 /* global register indexes */
@@ -443,6 +446,870 @@ static void gen_goto_tb(DisasContext *ctx, int which,
     }
 }
 
+/* PA has a habit of taking the LSB of a field and using that as the sign,
+   with the rest of the field becoming the least significant bits.  */
+static target_long low_sextract(uint32_t val, int pos, int len)
+{
+    target_ulong x = -(target_ulong)extract32(val, pos, 1);
+    x = (x << (len - 1)) | extract32(val, pos + 1, len - 1);
+    return x;
+}
+
+static target_long assemble_16(uint32_t insn)
+{
+    /* Take the name from PA2.0, which produces a 16-bit number
+       only with wide mode; otherwise a 14-bit number.  Since we don't
+       implement wide mode, this is always the 14-bit number.  */
+    return low_sextract(insn, 0, 14);
+}
+
+static target_long assemble_21(uint32_t insn)
+{
+    target_ulong x = -(target_ulong)(insn & 1);
+    x = (x << 11) | extract32(insn, 1, 11);
+    x = (x <<  2) | extract32(insn, 14, 2);
+    x = (x <<  5) | extract32(insn, 16, 5);
+    x = (x <<  2) | extract32(insn, 12, 2);
+    return x << 11;
+}
+
+/* The parisc documentation describes only the general interpretation of
+   the conditions, without describing their exact implementation.  The
+   interpretations do not stand up well when considering ADD,C and SUB,B.
+   However, considering the Addition, Subtraction and Logical conditions
+   as a whole it would appear that these relations are similar to what
+   a traditional NZCV set of flags would produce.  */
+
+static DisasCond do_cond(unsigned cf, TCGv res, TCGv cb_msb, TCGv sv)
+{
+    DisasCond cond;
+    TCGv tmp;
+
+    switch (cf >> 1) {
+    case 0: /* Never / TR */
+        cond = cond_make_f();
+        break;
+    case 1: /* = / <>        (Z / !Z) */
+        cond = cond_make_0(TCG_COND_EQ, res);
+        break;
+    case 2: /* < / >=        (N / !N) */
+        cond = cond_make_0(TCG_COND_LT, res);
+        break;
+    case 3: /* <= / >        (N | Z / !N & !Z) */
+        cond = cond_make_0(TCG_COND_LE, res);
+        break;
+    case 4: /* NUV / UV      (!C / C) */
+        cond = cond_make_0(TCG_COND_EQ, cb_msb);
+        break;
+    case 5: /* ZNV / VNZ     (!C | Z / C & !Z) */
+        tmp = tcg_temp_new();
+        tcg_gen_neg_tl(tmp, cb_msb);
+        tcg_gen_and_tl(tmp, tmp, res);
+        cond = cond_make_0(TCG_COND_EQ, tmp);
+        tcg_temp_free(tmp);
+        break;
+    case 6: /* SV / NSV      (V / !V) */
+        cond = cond_make_0(TCG_COND_LT, sv);
+        break;
+    case 7: /* OD / EV */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_tl(tmp, res, 1);
+        cond = cond_make_0(TCG_COND_NE, tmp);
+        tcg_temp_free(tmp);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    if (cf & 1) {
+        cond.c = tcg_invert_cond(cond.c);
+    }
+
+    return cond;
+}
+
+/* Similar, but for the special case of subtraction without borrow, we
+   can use the inputs directly.  This can allow other computation to be
+   deleted as unused.  */
+
+static DisasCond do_sub_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2, TCGv sv)
+{
+    DisasCond cond;
+
+    switch (cf >> 1) {
+    case 1: /* = / <> */
+        cond = cond_make(TCG_COND_EQ, in1, in2);
+        break;
+    case 2: /* < / >= */
+        cond = cond_make(TCG_COND_LT, in1, in2);
+        break;
+    case 3: /* <= / > */
+        cond = cond_make(TCG_COND_LE, in1, in2);
+        break;
+    case 4: /* << / >>= */
+        cond = cond_make(TCG_COND_LTU, in1, in2);
+        break;
+    case 5: /* <<= / >> */
+        cond = cond_make(TCG_COND_LEU, in1, in2);
+        break;
+    default:
+        return do_cond(cf, res, sv, sv);
+    }
+    if (cf & 1) {
+        cond.c = tcg_invert_cond(cond.c);
+    }
+
+    return cond;
+}
+
+/* Similar, but for logicals, where the carry and overflow bits are not
+   computed, and use of them is undefined.  */
+
+static DisasCond do_log_cond(unsigned cf, TCGv res)
+{
+    switch (cf >> 1) {
+    case 4: case 5: case 6:
+        cf &= 1;
+        break;
+    }
+    return do_cond(cf, res, res, res);
+}
+
+/* Similar, but for unit conditions.  */
+
+static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
+{
+    DisasCond cond;
+    TCGv tmp, cb;
+
+    TCGV_UNUSED(cb);
+    if (cf & 8) {
+        /* Since we want to test lots of carry-out bits all at once, do not
+         * do our normal thing and compute carry-in of bit B+1 since that
+         * leaves us with carry bits spread across two words.
+         */
+        cb = tcg_temp_new();
+        tmp = tcg_temp_new();
+        tcg_gen_or_tl(cb, in1, in2);
+        tcg_gen_and_tl(tmp, in1, in2);
+        tcg_gen_andc_tl(cb, cb, res);
+        tcg_gen_or_tl(cb, cb, tmp);
+        tcg_temp_free(tmp);
+    }
+
+    switch (cf >> 1) {
+    case 0: /* never / TR */
+    case 1: /* undefined */
+    case 5: /* undefined */
+        cond = cond_make_f();
+        break;
+
+    case 2: /* SBZ / NBZ */
+        /* See hasless(v,1) from
+         * https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
+         */
+        tmp = tcg_temp_new();
+        tcg_gen_subi_tl(tmp, res, 0x01010101u);
+        tcg_gen_andc_tl(tmp, tmp, res);
+        tcg_gen_andi_tl(tmp, tmp, 0x80808080u);
+        cond = cond_make_0(TCG_COND_NE, tmp);
+        tcg_temp_free(tmp);
+        break;
+
+    case 3: /* SHZ / NHZ */
+        tmp = tcg_temp_new();
+        tcg_gen_subi_tl(tmp, res, 0x00010001u);
+        tcg_gen_andc_tl(tmp, tmp, res);
+        tcg_gen_andi_tl(tmp, tmp, 0x80008000u);
+        cond = cond_make_0(TCG_COND_NE, tmp);
+        tcg_temp_free(tmp);
+        break;
+
+    case 4: /* SDC / NDC */
+        tcg_gen_andi_tl(cb, cb, 0x88888888u);
+        cond = cond_make_0(TCG_COND_NE, cb);
+        break;
+
+    case 6: /* SBC / NBC */
+        tcg_gen_andi_tl(cb, cb, 0x80808080u);
+        cond = cond_make_0(TCG_COND_NE, cb);
+        break;
+
+    case 7: /* SHC / NHC */
+        tcg_gen_andi_tl(cb, cb, 0x80008000u);
+        cond = cond_make_0(TCG_COND_NE, cb);
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+    if (cf & 8) {
+        tcg_temp_free(cb);
+    }
+    if (cf & 1) {
+        cond.c = tcg_invert_cond(cond.c);
+    }
+
+    return cond;
+}
+
+/* Compute signed overflow for addition.  */
+static TCGv do_add_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
+{
+    TCGv sv = get_temp(ctx);
+    TCGv tmp = tcg_temp_new();
+
+    tcg_gen_xor_tl(sv, res, in1);
+    tcg_gen_xor_tl(tmp, in1, in2);
+    tcg_gen_andc_tl(sv, sv, tmp);
+    tcg_temp_free(tmp);
+
+    return sv;
+}
+
+/* Compute signed overflow for subtraction.  */
+static TCGv do_sub_sv(DisasContext *ctx, TCGv res, TCGv in1, TCGv in2)
+{
+    TCGv sv = get_temp(ctx);
+    TCGv tmp = tcg_temp_new();
+
+    tcg_gen_xor_tl(sv, res, in1);
+    tcg_gen_xor_tl(tmp, in1, in2);
+    tcg_gen_and_tl(sv, sv, tmp);
+    tcg_temp_free(tmp);
+
+    return sv;
+}
+
+static ExitStatus do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
+                         unsigned shift, bool is_l, bool is_tsv, bool is_tc,
+                         bool is_c, unsigned cf)
+{
+    TCGv dest, cb, cb_msb, sv, tmp;
+    unsigned c = cf >> 1;
+    DisasCond cond;
+
+    dest = tcg_temp_new();
+    TCGV_UNUSED(cb);
+    TCGV_UNUSED(cb_msb);
+
+    if (shift) {
+        tmp = get_temp(ctx);
+        tcg_gen_shli_tl(tmp, in1, shift);
+        in1 = tmp;
+    }
+
+    if (!is_l || c == 4 || c == 5) {
+        TCGv zero = tcg_const_tl(0);
+        cb_msb = get_temp(ctx);
+        tcg_gen_add2_tl(dest, cb_msb, in1, zero, in2, zero);
+        if (is_c) {
+            tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cpu_psw_cb_msb, zero);
+        }
+        tcg_temp_free(zero);
+        if (!is_l) {
+            cb = get_temp(ctx);
+            tcg_gen_xor_tl(cb, in1, in2);
+            tcg_gen_xor_tl(cb, cb, dest);
+        }
+    } else {
+        tcg_gen_add_tl(dest, in1, in2);
+        if (is_c) {
+            tcg_gen_add_tl(dest, dest, cpu_psw_cb_msb);
+        }
+    }
+
+    /* Compute signed overflow if required.  */
+    TCGV_UNUSED(sv);
+    if (is_tsv || c == 6) {
+        sv = do_add_sv(ctx, dest, in1, in2);
+        if (is_tsv) {
+            /* ??? Need to include overflow from shift.  */
+            gen_helper_tsv(cpu_env, sv);
+        }
+    }
+
+    /* Emit any conditional trap before any writeback.  */
+    cond = do_cond(cf, dest, cb_msb, sv);
+    if (is_tc) {
+        cond_prep(&cond);
+        tmp = tcg_temp_new();
+        tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
+        gen_helper_tcond(cpu_env, tmp);
+        tcg_temp_free(tmp);
+    }
+
+    /* Write back the result.  */
+    if (!is_l) {
+        save_or_nullify(ctx, cpu_psw_cb, cb);
+        save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
+    }
+    save_gpr(ctx, rt, dest);
+    tcg_temp_free(dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    ctx->null_cond = cond;
+    return NO_EXIT;
+}
+
+static ExitStatus do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
+                         bool is_tsv, bool is_b, bool is_tc, unsigned cf)
+{
+    TCGv dest, sv, cb, cb_msb, zero, tmp;
+    unsigned c = cf >> 1;
+    DisasCond cond;
+
+    dest = tcg_temp_new();
+    cb = tcg_temp_new();
+    cb_msb = tcg_temp_new();
+
+    zero = tcg_const_tl(0);
+    if (is_b) {
+        /* DEST,C = IN1 + ~IN2 + C.  */
+        tcg_gen_not_tl(cb, in2);
+        tcg_gen_add2_tl(dest, cb_msb, in1, zero, cpu_psw_cb_msb, zero);
+        tcg_gen_add2_tl(dest, cb_msb, dest, cb_msb, cb, zero);
+        tcg_gen_xor_tl(cb, cb, in1);
+        tcg_gen_xor_tl(cb, cb, dest);
+    } else {
+        /* DEST,C = IN1 + ~IN2 + 1.  We can produce the same result in fewer
+           operations by seeding the high word with 1 and subtracting.  */
+        tcg_gen_movi_tl(cb_msb, 1);
+        tcg_gen_sub2_tl(dest, cb_msb, in1, cb_msb, in2, zero);
+        tcg_gen_eqv_tl(cb, in1, in2);
+        tcg_gen_xor_tl(cb, cb, dest);
+    }
+    tcg_temp_free(zero);
+
+    /* Compute signed overflow if required.  */
+    TCGV_UNUSED(sv);
+    if (is_tsv || c == 6) {
+        sv = do_sub_sv(ctx, dest, in1, in2);
+        if (is_tsv) {
+            gen_helper_tsv(cpu_env, sv);
+        }
+    }
+
+    /* Compute the condition.  We cannot use the special case for borrow.  */
+    if (!is_b) {
+        cond = do_sub_cond(cf, dest, in1, in2, sv);
+    } else {
+        cond = do_cond(cf, dest, cb_msb, sv);
+    }
+
+    /* Emit any conditional trap before any writeback.  */
+    if (is_tc) {
+        cond_prep(&cond);
+        tmp = tcg_temp_new();
+        tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
+        gen_helper_tcond(cpu_env, tmp);
+        tcg_temp_free(tmp);
+    }
+
+    /* Write back the result.  */
+    save_or_nullify(ctx, cpu_psw_cb, cb);
+    save_or_nullify(ctx, cpu_psw_cb_msb, cb_msb);
+    save_gpr(ctx, rt, dest);
+    tcg_temp_free(dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    ctx->null_cond = cond;
+    return NO_EXIT;
+}
+
+static ExitStatus do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1,
+                            TCGv in2, unsigned cf)
+{
+    TCGv dest, sv;
+    DisasCond cond;
+
+    dest = tcg_temp_new();
+    tcg_gen_sub_tl(dest, in1, in2);
+
+    /* Compute signed overflow if required.  */
+    TCGV_UNUSED(sv);
+    if ((cf >> 1) == 6) {
+        sv = do_sub_sv(ctx, dest, in1, in2);
+    }
+
+    /* Form the condition for the compare.  */
+    cond = do_sub_cond(cf, dest, in1, in2, sv);
+
+    /* Clear.  */
+    tcg_gen_movi_tl(dest, 0);
+    save_gpr(ctx, rt, dest);
+    tcg_temp_free(dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    ctx->null_cond = cond;
+    return NO_EXIT;
+}
+
+static ExitStatus do_log(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2,
+                         unsigned cf, void (*fn)(TCGv, TCGv, TCGv))
+{
+    TCGv dest = dest_gpr(ctx, rt);
+
+    /* Perform the operation, and writeback.  */
+    fn(dest, in1, in2);
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (cf) {
+        ctx->null_cond = do_log_cond(cf, dest);
+    }
+    return NO_EXIT;
+}
+
+static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
+                          TCGv in2, unsigned cf, bool is_tc,
+                          void (*fn)(TCGv, TCGv, TCGv))
+{
+    TCGv dest;
+    DisasCond cond;
+
+    if (cf == 0) {
+        dest = dest_gpr(ctx, rt);
+        fn(dest, in1, in2);
+        save_gpr(ctx, rt, dest);
+        cond_free(&ctx->null_cond);
+    } else {
+        dest = tcg_temp_new();
+        fn(dest, in1, in2);
+
+        cond = do_unit_cond(cf, dest, in1, in2);
+
+        if (is_tc) {
+            TCGv tmp = tcg_temp_new();
+            cond_prep(&cond);
+            tcg_gen_setcond_tl(cond.c, tmp, cond.a0, cond.a1);
+            gen_helper_tcond(cpu_env, tmp);
+            tcg_temp_free(tmp);
+        }
+        save_gpr(ctx, rt, dest);
+
+        cond_free(&ctx->null_cond);
+        ctx->null_cond = cond;
+    }
+    return NO_EXIT;
+}
+
+static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned ext = extract32(insn, 8, 4);
+    unsigned shift = extract32(insn, 6, 2);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2;
+    bool is_c = false;
+    bool is_l = false;
+    bool is_tc = false;
+    bool is_tsv = false;
+    ExitStatus ret;
+
+    switch (ext) {
+    case 0x6: /* ADD, SHLADD */
+        break;
+    case 0xa: /* ADD,L, SHLADD,L */
+        is_l = true;
+        break;
+    case 0xe: /* ADD,TSV, SHLADD,TSV (1) */
+        is_tsv = true;
+        break;
+    case 0x7: /* ADD,C */
+        is_c = true;
+        break;
+    case 0xf: /* ADD,C,TSV */
+        is_c = is_tsv = true;
+        break;
+    default:
+        return gen_illegal(ctx);
+    }
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_add(ctx, rt, tcg_r1, tcg_r2, shift, is_l, is_tsv, is_tc, is_c, cf);
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_sub(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned ext = extract32(insn, 6, 6);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2;
+    bool is_b = false;
+    bool is_tc = false;
+    bool is_tsv = false;
+    ExitStatus ret;
+
+    switch (ext) {
+    case 0x10: /* SUB */
+        break;
+    case 0x30: /* SUB,TSV */
+        is_tsv = true;
+        break;
+    case 0x14: /* SUB,B */
+        is_b = true;
+        break;
+    case 0x34: /* SUB,B,TSV */
+        is_b = is_tsv = true;
+        break;
+    case 0x13: /* SUB,TC */
+        is_tc = true;
+        break;
+    case 0x33: /* SUB,TSV,TC */
+        is_tc = is_tsv = true;
+        break;
+    default:
+        return gen_illegal(ctx);
+    }
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_sub(ctx, rt, tcg_r1, tcg_r2, is_tsv, is_b, is_tc, cf);
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_log(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_log(ctx, rt, tcg_r1, tcg_r2, cf, di->f_ttt);
+    return nullify_end(ctx, ret);
+}
+
+/* OR r,0,t -> COPY (according to gas) */
+static ExitStatus trans_copy(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned rt = extract32(insn,  0, 5);
+
+    if (r1 == 0) {
+        TCGv dest = dest_gpr(ctx, rt);
+        tcg_gen_movi_tl(dest, 0);
+        save_gpr(ctx, rt, dest);
+    } else {
+        save_gpr(ctx, rt, cpu_gr[r1]);
+    }
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_cmpclr(DisasContext *ctx, uint32_t insn,
+                               const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_cmpclr(ctx, rt, tcg_r1, tcg_r2, cf);
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_uxor(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_unit(ctx, rt, tcg_r1, tcg_r2, cf, false, tcg_gen_xor_tl);
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_uaddcm(DisasContext *ctx, uint32_t insn,
+                               const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned is_tc = extract32(insn, 6, 1);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tcg_r1, tcg_r2, tmp;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+    tcg_r1 = load_gpr(ctx, r1);
+    tcg_r2 = load_gpr(ctx, r2);
+    tmp = get_temp(ctx);
+    tcg_gen_not_tl(tmp, tcg_r2);
+    ret = do_unit(ctx, rt, tcg_r1, tmp, cf, is_tc, tcg_gen_add_tl);
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_dcor(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned is_i = extract32(insn, 6, 1);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv tmp;
+    ExitStatus ret;
+
+    nullify_over(ctx);
+
+    tmp = get_temp(ctx);
+    tcg_gen_shri_tl(tmp, cpu_psw_cb, 3);
+    if (!is_i) {
+        tcg_gen_not_tl(tmp, tmp);
+    }
+    tcg_gen_andi_tl(tmp, tmp, 0x11111111);
+    tcg_gen_muli_tl(tmp, tmp, 6);
+    ret = do_unit(ctx, rt, tmp, load_gpr(ctx, r2), cf, false,
+                  is_i ? tcg_gen_add_tl : tcg_gen_sub_tl);
+
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_ds(DisasContext *ctx, uint32_t insn,
+                           const DisasInsn *di)
+{
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn,  0, 5);
+    TCGv dest, add1, add2, addc, zero, in1, in2;
+
+    nullify_over(ctx);
+
+    in1 = load_gpr(ctx, r1);
+    in2 = load_gpr(ctx, r2);
+
+    add1 = tcg_temp_new();
+    add2 = tcg_temp_new();
+    addc = tcg_temp_new();
+    dest = tcg_temp_new();
+    zero = tcg_const_tl(0);
+
+    /* Form R1 << 1 | PSW[CB]{8}.  */
+    tcg_gen_add_tl(add1, in1, in1);
+    tcg_gen_add_tl(add1, add1, cpu_psw_cb_msb);
+
+    /* Add or subtract R2, depending on PSW[V].  Proper computation of
+       carry{8} requires that we subtract via + ~R2 + 1, as described in
+       the manual.  By extracting and masking V, we can produce the
+       proper inputs to the addition without movcond.  */
+    tcg_gen_sari_tl(addc, cpu_psw_v, TARGET_LONG_BITS - 1);
+    tcg_gen_xor_tl(add2, in2, addc);
+    tcg_gen_andi_tl(addc, addc, 1);
+    /* ??? This is only correct for 32-bit.  */
+    tcg_gen_add2_i32(dest, cpu_psw_cb_msb, add1, zero, add2, zero);
+    tcg_gen_add2_i32(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, addc, zero);
+
+    tcg_temp_free(addc);
+    tcg_temp_free(zero);
+
+    /* Write back the result register.  */
+    save_gpr(ctx, rt, dest);
+
+    /* Write back PSW[CB].  */
+    tcg_gen_xor_tl(cpu_psw_cb, add1, add2);
+    tcg_gen_xor_tl(cpu_psw_cb, cpu_psw_cb, dest);
+
+    /* Write back PSW[V] for the division step.  */
+    tcg_gen_neg_tl(cpu_psw_v, cpu_psw_cb_msb);
+    tcg_gen_xor_tl(cpu_psw_v, cpu_psw_v, in2);
+
+    /* Install the new nullification.  */
+    if (cf) {
+        TCGv sv;
+        TCGV_UNUSED(sv);
+        if (cf >> 1 == 6) {
+            /* ??? The lshift is supposed to contribute to overflow.  */
+            sv = do_add_sv(ctx, dest, add1, add2);
+        }
+        ctx->null_cond = do_cond(cf, dest, cpu_psw_cb_msb, sv);
+    }
+
+    tcg_temp_free(add1);
+    tcg_temp_free(add2);
+    tcg_temp_free(dest);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_arith_log[] = {
+    { 0x08000240u, 0xfc00ffffu, trans_nop },  /* or x,y,0 */
+    { 0x08000240u, 0xffe0ffe0u, trans_copy }, /* or x,0,t */
+    { 0x08000000u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_andc_tl },
+    { 0x08000200u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_and_tl },
+    { 0x08000240u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_or_tl },
+    { 0x08000280u, 0xfc000fe0u, trans_log, .f_ttt = tcg_gen_xor_tl },
+    { 0x08000880u, 0xfc000fe0u, trans_cmpclr },
+    { 0x08000380u, 0xfc000fe0u, trans_uxor },
+    { 0x08000980u, 0xfc000fa0u, trans_uaddcm },
+    { 0x08000b80u, 0xfc1f0fa0u, trans_dcor },
+    { 0x08000440u, 0xfc000fe0u, trans_ds },
+    { 0x08000700u, 0xfc0007e0u, trans_add }, /* add */
+    { 0x08000400u, 0xfc0006e0u, trans_sub }, /* sub; sub,b; sub,tsv */
+    { 0x080004c0u, 0xfc0007e0u, trans_sub }, /* sub,tc; sub,tsv,tc */
+    { 0x08000200u, 0xfc000320u, trans_add }, /* shladd */
+};
+
+static ExitStatus trans_addi(DisasContext *ctx, uint32_t insn)
+{
+    target_long im = low_sextract(insn, 0, 11);
+    unsigned e1 = extract32(insn, 11, 1);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned o1 = extract32(insn, 26, 1);
+    TCGv tcg_im, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+
+    tcg_im = load_const(ctx, im);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_add(ctx, rt, tcg_im, tcg_r2, 0, false, e1, !o1, false, cf);
+
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_subi(DisasContext *ctx, uint32_t insn)
+{
+    target_long im = low_sextract(insn, 0, 11);
+    unsigned e1 = extract32(insn, 11, 1);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned r2 = extract32(insn, 21, 5);
+    TCGv tcg_im, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+
+    tcg_im = load_const(ctx, im);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_sub(ctx, rt, tcg_im, tcg_r2, e1, false, false, cf);
+
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
+{
+    target_long im = low_sextract(insn, 0, 11);
+    unsigned cf = extract32(insn, 12, 4);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned r2 = extract32(insn, 21, 5);
+    TCGv tcg_im, tcg_r2;
+    ExitStatus ret;
+
+    if (cf) {
+        nullify_over(ctx);
+    }
+
+    tcg_im = load_const(ctx, im);
+    tcg_r2 = load_gpr(ctx, r2);
+    ret = do_cmpclr(ctx, rt, tcg_im, tcg_r2, cf);
+
+    return nullify_end(ctx, ret);
+}
+
+static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rt = extract32(insn, 21, 5);
+    target_long i = assemble_21(insn);
+    TCGv tcg_rt = dest_gpr(ctx, rt);
+
+    tcg_gen_movi_tl(tcg_rt, i);
+    save_gpr(ctx, rt, tcg_rt);
+    cond_free(&ctx->null_cond);
+
+    return NO_EXIT;
+}
+
+static ExitStatus trans_addil(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rt = extract32(insn, 21, 5);
+    target_long i = assemble_21(insn);
+    TCGv tcg_rt = load_gpr(ctx, rt);
+    TCGv tcg_r1 = dest_gpr(ctx, 1);
+
+    tcg_gen_addi_tl(tcg_r1, tcg_rt, i);
+    save_gpr(ctx, 1, tcg_r1);
+    cond_free(&ctx->null_cond);
+
+    return NO_EXIT;
+}
+
+static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = extract32(insn, 16, 5);
+    target_long i = assemble_16(insn);
+    TCGv tcg_rt = dest_gpr(ctx, rt);
+
+    /* Special case rb == 0, for the LDI pseudo-op.
+       The COPY pseudo-op is handled for free within tcg_gen_addi_tl.  */
+    if (rb == 0) {
+        tcg_gen_movi_tl(tcg_rt, i);
+    } else {
+        tcg_gen_addi_tl(tcg_rt, cpu_gr[rb], i);
+    }
+    save_gpr(ctx, rt, tcg_rt);
+    cond_free(&ctx->null_cond);
+
+    return NO_EXIT;
+}
+
 static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
                                       const DisasInsn table[], size_t n)
 {
@@ -463,6 +1330,21 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     uint32_t opc = extract32(insn, 26, 6);
 
     switch (opc) {
+    case 0x02:
+        return translate_table(ctx, insn, table_arith_log);
+    case 0x08:
+        return trans_ldil(ctx, insn);
+    case 0x0A:
+        return trans_addil(ctx, insn);
+    case 0x0D:
+        return trans_ldo(ctx, insn);
+    case 0x24:
+        return trans_cmpiclr(ctx, insn);
+    case 0x25:
+        return trans_subi(ctx, insn);
+    case 0x2C:
+    case 0x2D:
+        return trans_addi(ctx, insn);
     default:
         break;
     }
-- 
2.9.3

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

* [Qemu-devel] [PULL 21/26] target-hppa: Implement branches
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (18 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 20/26] target-hppa: Implement basic arithmetic Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-26 12:14   ` Paolo Bonzini
  2017-01-23  2:17 ` [Qemu-devel] [PULL 22/26] target-hppa: Implement linux-user gateway page Richard Henderson
                   ` (5 subsequent siblings)
  25 siblings, 1 reply; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/translate.c | 477 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 477 insertions(+)

diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 2ad651c..1d0976f 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -455,6 +455,14 @@ static target_long low_sextract(uint32_t val, int pos, int len)
     return x;
 }
 
+static target_long assemble_12(uint32_t insn)
+{
+    target_ulong x = -(target_ulong)(insn & 1);
+    x = (x <<  1) | extract32(insn, 2, 1);
+    x = (x << 10) | extract32(insn, 3, 10);
+    return x;
+}
+
 static target_long assemble_16(uint32_t insn)
 {
     /* Take the name from PA2.0, which produces a 16-bit number
@@ -463,6 +471,15 @@ static target_long assemble_16(uint32_t insn)
     return low_sextract(insn, 0, 14);
 }
 
+static target_long assemble_17(uint32_t insn)
+{
+    target_ulong x = -(target_ulong)(insn & 1);
+    x = (x <<  5) | extract32(insn, 16, 5);
+    x = (x <<  1) | extract32(insn, 2, 1);
+    x = (x << 10) | extract32(insn, 3, 10);
+    return x << 2;
+}
+
 static target_long assemble_21(uint32_t insn)
 {
     target_ulong x = -(target_ulong)(insn & 1);
@@ -473,6 +490,15 @@ static target_long assemble_21(uint32_t insn)
     return x << 11;
 }
 
+static target_long assemble_22(uint32_t insn)
+{
+    target_ulong x = -(target_ulong)(insn & 1);
+    x = (x << 10) | extract32(insn, 16, 10);
+    x = (x <<  1) | extract32(insn, 2, 1);
+    x = (x << 10) | extract32(insn, 3, 10);
+    return x << 2;
+}
+
 /* The parisc documentation describes only the general interpretation of
    the conditions, without describing their exact implementation.  The
    interpretations do not stand up well when considering ADD,C and SUB,B.
@@ -574,6 +600,24 @@ static DisasCond do_log_cond(unsigned cf, TCGv res)
     return do_cond(cf, res, res, res);
 }
 
+/* Similar, but for shift/extract/deposit conditions.  */
+
+static DisasCond do_sed_cond(unsigned orig, TCGv res)
+{
+    unsigned c, f;
+
+    /* Convert the compressed condition codes to standard.
+       0-2 are the same as logicals (nv,<,<=), while 3 is OD.
+       4-7 are the reverse of 0-3.  */
+    c = orig & 3;
+    if (c == 3) {
+        c = 7;
+    }
+    f = (orig & 4) / 4;
+
+    return do_log_cond(c * 2 + f, res);
+}
+
 /* Similar, but for unit conditions.  */
 
 static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2)
@@ -897,6 +941,188 @@ static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
     return NO_EXIT;
 }
 
+/* Emit an unconditional branch to a direct target, which may or may not
+   have already had nullification handled.  */
+static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
+                             unsigned link, bool is_n)
+{
+    if (ctx->null_cond.c == TCG_COND_NEVER && ctx->null_lab == NULL) {
+        if (link != 0) {
+            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+        }
+        ctx->iaoq_n = dest;
+        if (is_n) {
+            ctx->null_cond.c = TCG_COND_ALWAYS;
+        }
+        return NO_EXIT;
+    } else {
+        nullify_over(ctx);
+
+        if (link != 0) {
+            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+        }
+
+        if (is_n && use_nullify_skip(ctx)) {
+            nullify_set(ctx, 0);
+            gen_goto_tb(ctx, 0, dest, dest + 4);
+        } else {
+            nullify_set(ctx, is_n);
+            gen_goto_tb(ctx, 0, ctx->iaoq_b, dest);
+        }
+
+        nullify_end(ctx, NO_EXIT);
+
+        nullify_set(ctx, 0);
+        gen_goto_tb(ctx, 1, ctx->iaoq_b, ctx->iaoq_n);
+        return EXIT_GOTO_TB;
+    }
+}
+
+/* Emit a conditional branch to a direct target.  If the branch itself
+   is nullified, we should have already used nullify_over.  */
+static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
+                             DisasCond *cond)
+{
+    target_ulong dest = iaoq_dest(ctx, disp);
+    TCGLabel *taken = NULL;
+    TCGCond c = cond->c;
+    int which = 0;
+    bool n;
+
+    assert(ctx->null_cond.c == TCG_COND_NEVER);
+
+    /* Handle TRUE and NEVER as direct branches.  */
+    if (c == TCG_COND_ALWAYS) {
+        return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
+    }
+    if (c == TCG_COND_NEVER) {
+        return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
+    }
+
+    taken = gen_new_label();
+    cond_prep(cond);
+    tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
+    cond_free(cond);
+
+    /* Not taken: Condition not satisfied; nullify on backward branches. */
+    n = is_n && disp < 0;
+    if (n && use_nullify_skip(ctx)) {
+        nullify_set(ctx, 0);
+        gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4);
+    } else {
+        if (!n && ctx->null_lab) {
+            gen_set_label(ctx->null_lab);
+            ctx->null_lab = NULL;
+        }
+        nullify_set(ctx, n);
+        gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n);
+    }
+
+    gen_set_label(taken);
+
+    /* Taken: Condition satisfied; nullify on forward branches.  */
+    n = is_n && disp >= 0;
+    if (n && use_nullify_skip(ctx)) {
+        nullify_set(ctx, 0);
+        gen_goto_tb(ctx, which++, dest, dest + 4);
+    } else {
+        nullify_set(ctx, n);
+        gen_goto_tb(ctx, which++, ctx->iaoq_b, dest);
+    }
+
+    /* Not taken: the branch itself was nullified.  */
+    if (ctx->null_lab) {
+        gen_set_label(ctx->null_lab);
+        ctx->null_lab = NULL;
+        if (which < 2) {
+            nullify_set(ctx, 0);
+            gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n);
+            return EXIT_GOTO_TB;
+        } else {
+            return EXIT_IAQ_N_STALE;
+        }
+    } else {
+        return EXIT_GOTO_TB;
+    }
+}
+
+/* Emit an unconditional branch to an indirect target.  This handles
+   nullification of the branch itself.  */
+static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
+                             unsigned link, bool is_n)
+{
+    TCGv a0, a1, next, tmp;
+    TCGCond c;
+
+    assert(ctx->null_lab == NULL);
+
+    if (ctx->null_cond.c == TCG_COND_NEVER) {
+        if (link != 0) {
+            copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
+        }
+        next = get_temp(ctx);
+        tcg_gen_mov_tl(next, dest);
+        ctx->iaoq_n = -1;
+        ctx->iaoq_n_var = next;
+        if (is_n) {
+            ctx->null_cond.c = TCG_COND_ALWAYS;
+        }
+    } else if (is_n && use_nullify_skip(ctx)) {
+        /* The (conditional) branch, B, nullifies the next insn, N,
+           and we're allowed to skip execution N (no single-step or
+           tracepoint in effect).  Since the exit_tb that we must use
+           for the indirect branch consumes no special resources, we
+           can (conditionally) skip B and continue execution.  */
+        /* The use_nullify_skip test implies we have a known control path.  */
+        tcg_debug_assert(ctx->iaoq_b != -1);
+        tcg_debug_assert(ctx->iaoq_n != -1);
+
+        /* We do have to handle the non-local temporary, DEST, before
+           branching.  Since IOAQ_F is not really live at this point, we
+           can simply store DEST optimistically.  Similarly with IAOQ_B.  */
+        tcg_gen_mov_tl(cpu_iaoq_f, dest);
+        tcg_gen_addi_tl(cpu_iaoq_b, dest, 4);
+
+        nullify_over(ctx);
+        if (link != 0) {
+            tcg_gen_movi_tl(cpu_gr[link], ctx->iaoq_n);
+        }
+        tcg_gen_exit_tb(0);
+        return nullify_end(ctx, NO_EXIT);
+    } else {
+        cond_prep(&ctx->null_cond);
+        c = ctx->null_cond.c;
+        a0 = ctx->null_cond.a0;
+        a1 = ctx->null_cond.a1;
+
+        tmp = tcg_temp_new();
+        next = get_temp(ctx);
+
+        copy_iaoq_entry(tmp, ctx->iaoq_n, ctx->iaoq_n_var);
+        tcg_gen_movcond_tl(c, next, a0, a1, tmp, dest);
+        ctx->iaoq_n = -1;
+        ctx->iaoq_n_var = next;
+
+        if (link != 0) {
+            tcg_gen_movcond_tl(c, cpu_gr[link], a0, a1, cpu_gr[link], tmp);
+        }
+
+        if (is_n) {
+            /* The branch nullifies the next insn, which means the state of N
+               after the branch is the inverse of the state of N that applied
+               to the branch.  */
+            tcg_gen_setcond_tl(tcg_invert_cond(c), cpu_psw_n, a0, a1);
+            cond_free(&ctx->null_cond);
+            ctx->null_cond = cond_make_n();
+            ctx->psw_n_nonzero = true;
+        } else {
+            cond_free(&ctx->null_cond);
+        }
+    }
+
+    return NO_EXIT;
+}
+
 static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
                             const DisasInsn *di)
 {
@@ -1310,6 +1536,224 @@ static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
     return NO_EXIT;
 }
 
+static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
+                             bool is_true, bool is_imm, bool is_dw)
+{
+    target_long disp = assemble_12(insn) * 4;
+    unsigned n = extract32(insn, 1, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned r = extract32(insn, 21, 5);
+    unsigned cf = c * 2 + !is_true;
+    TCGv dest, in1, in2, sv;
+    DisasCond cond;
+
+    nullify_over(ctx);
+
+    if (is_imm) {
+        in1 = load_const(ctx, low_sextract(insn, 16, 5));
+    } else {
+        in1 = load_gpr(ctx, extract32(insn, 16, 5));
+    }
+    in2 = load_gpr(ctx, r);
+    dest = get_temp(ctx);
+
+    tcg_gen_sub_tl(dest, in1, in2);
+
+    TCGV_UNUSED(sv);
+    if (c == 6) {
+        sv = do_sub_sv(ctx, dest, in1, in2);
+    }
+
+    cond = do_sub_cond(cf, dest, in1, in2, sv);
+    return do_cbranch(ctx, disp, n, &cond);
+}
+
+static ExitStatus trans_addb(DisasContext *ctx, uint32_t insn,
+                             bool is_true, bool is_imm)
+{
+    target_long disp = assemble_12(insn) * 4;
+    unsigned n = extract32(insn, 1, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned r = extract32(insn, 21, 5);
+    unsigned cf = c * 2 + !is_true;
+    TCGv dest, in1, in2, sv, cb_msb;
+    DisasCond cond;
+
+    nullify_over(ctx);
+
+    if (is_imm) {
+        in1 = load_const(ctx, low_sextract(insn, 16, 5));
+    } else {
+        in1 = load_gpr(ctx, extract32(insn, 16, 5));
+    }
+    in2 = load_gpr(ctx, r);
+    dest = dest_gpr(ctx, r);
+    TCGV_UNUSED(sv);
+    TCGV_UNUSED(cb_msb);
+
+    switch (c) {
+    default:
+        tcg_gen_add_tl(dest, in1, in2);
+        break;
+    case 4: case 5:
+        cb_msb = get_temp(ctx);
+        tcg_gen_movi_tl(cb_msb, 0);
+        tcg_gen_add2_tl(dest, cb_msb, in1, cb_msb, in2, cb_msb);
+        break;
+    case 6:
+        tcg_gen_add_tl(dest, in1, in2);
+        sv = do_add_sv(ctx, dest, in1, in2);
+        break;
+    }
+
+    cond = do_cond(cf, dest, cb_msb, sv);
+    return do_cbranch(ctx, disp, n, &cond);
+}
+
+static ExitStatus trans_bb(DisasContext *ctx, uint32_t insn)
+{
+    target_long disp = assemble_12(insn) * 4;
+    unsigned n = extract32(insn, 1, 1);
+    unsigned c = extract32(insn, 15, 1);
+    unsigned r = extract32(insn, 16, 5);
+    unsigned p = extract32(insn, 21, 5);
+    unsigned i = extract32(insn, 26, 1);
+    TCGv tmp, tcg_r;
+    DisasCond cond;
+
+    nullify_over(ctx);
+
+    tmp = tcg_temp_new();
+    tcg_r = load_gpr(ctx, r);
+    if (i) {
+        tcg_gen_shli_tl(tmp, tcg_r, p);
+    } else {
+        tcg_gen_shl_tl(tmp, tcg_r, cpu_sar);
+    }
+
+    cond = cond_make_0(c ? TCG_COND_GE : TCG_COND_LT, tmp);
+    tcg_temp_free(tmp);
+    return do_cbranch(ctx, disp, n, &cond);
+}
+
+static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
+{
+    target_long disp = assemble_12(insn) * 4;
+    unsigned n = extract32(insn, 1, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned t = extract32(insn, 16, 5);
+    unsigned r = extract32(insn, 21, 5);
+    TCGv dest;
+    DisasCond cond;
+
+    nullify_over(ctx);
+
+    dest = dest_gpr(ctx, r);
+    if (is_imm) {
+        tcg_gen_movi_tl(dest, low_sextract(t, 0, 5));
+    } else if (t == 0) {
+        tcg_gen_movi_tl(dest, 0);
+    } else {
+        tcg_gen_mov_tl(dest, cpu_gr[t]);
+    }
+
+    cond = do_sed_cond(c, dest);
+    return do_cbranch(ctx, disp, n, &cond);
+}
+
+static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
+{
+    unsigned n = extract32(insn, 1, 1);
+    unsigned b = extract32(insn, 21, 5);
+    target_long disp = assemble_17(insn);
+
+    /* unsigned s = low_uextract(insn, 13, 3); */
+    /* ??? It seems like there should be a good way of using
+       "be disp(sr2, r0)", the canonical gateway entry mechanism
+       to our advantage.  But that appears to be inconvenient to
+       manage along side branch delay slots.  Therefore we handle
+       entry into the gateway page via absolute address.  */
+
+    /* Since we don't implement spaces, just branch.  Do notice the special
+       case of "be disp(*,r0)" using a direct branch to disp, so that we can
+       goto_tb to the TB containing the syscall.  */
+    if (b == 0) {
+        return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
+    } else {
+        TCGv tmp = get_temp(ctx);
+        tcg_gen_addi_tl(tmp, load_gpr(ctx, b), disp);
+        return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
+    }
+}
+
+static ExitStatus trans_bl(DisasContext *ctx, uint32_t insn,
+                           const DisasInsn *di)
+{
+    unsigned n = extract32(insn, 1, 1);
+    unsigned link = extract32(insn, 21, 5);
+    target_long disp = assemble_17(insn);
+
+    return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
+}
+
+static ExitStatus trans_bl_long(DisasContext *ctx, uint32_t insn,
+                                const DisasInsn *di)
+{
+    unsigned n = extract32(insn, 1, 1);
+    target_long disp = assemble_22(insn);
+
+    return do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
+}
+
+static ExitStatus trans_blr(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    unsigned n = extract32(insn, 1, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned link = extract32(insn, 21, 5);
+    TCGv tmp = get_temp(ctx);
+
+    tcg_gen_shli_tl(tmp, load_gpr(ctx, rx), 3);
+    tcg_gen_addi_tl(tmp, tmp, ctx->iaoq_f + 8);
+    return do_ibranch(ctx, tmp, link, n);
+}
+
+static ExitStatus trans_bv(DisasContext *ctx, uint32_t insn,
+                           const DisasInsn *di)
+{
+    unsigned n = extract32(insn, 1, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    TCGv dest;
+
+    if (rx == 0) {
+        dest = load_gpr(ctx, rb);
+    } else {
+        dest = get_temp(ctx);
+        tcg_gen_shli_tl(dest, load_gpr(ctx, rx), 3);
+        tcg_gen_add_tl(dest, dest, load_gpr(ctx, rb));
+    }
+    return do_ibranch(ctx, dest, 0, n);
+}
+
+static ExitStatus trans_bve(DisasContext *ctx, uint32_t insn,
+                            const DisasInsn *di)
+{
+    unsigned n = extract32(insn, 1, 1);
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned link = extract32(insn, 13, 1) ? 2 : 0;
+
+    return do_ibranch(ctx, load_gpr(ctx, rb), link, n);
+}
+
+static const DisasInsn table_branch[] = {
+    { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
+    { 0xe800a000u, 0xfc00e000u, trans_bl_long },
+    { 0xe8004000u, 0xfc00fffdu, trans_blr },
+    { 0xe800c000u, 0xfc00fffdu, trans_bv },
+    { 0xe800d000u, 0xfc00dffcu, trans_bve },
+};
+
 static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
                                       const DisasInsn table[], size_t n)
 {
@@ -1338,13 +1782,46 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_addil(ctx, insn);
     case 0x0D:
         return trans_ldo(ctx, insn);
+    case 0x20:
+        return trans_cmpb(ctx, insn, true, false, false);
+    case 0x21:
+        return trans_cmpb(ctx, insn, true, true, false);
+    case 0x22:
+        return trans_cmpb(ctx, insn, false, false, false);
+    case 0x23:
+        return trans_cmpb(ctx, insn, false, true, false);
     case 0x24:
         return trans_cmpiclr(ctx, insn);
     case 0x25:
         return trans_subi(ctx, insn);
+    case 0x27:
+        return trans_cmpb(ctx, insn, true, false, true);
+    case 0x28:
+        return trans_addb(ctx, insn, true, false);
+    case 0x29:
+        return trans_addb(ctx, insn, true, true);
+    case 0x2A:
+        return trans_addb(ctx, insn, false, false);
+    case 0x2B:
+        return trans_addb(ctx, insn, false, true);
     case 0x2C:
     case 0x2D:
         return trans_addi(ctx, insn);
+    case 0x2F:
+        return trans_cmpb(ctx, insn, false, false, true);
+    case 0x30:
+    case 0x31:
+        return trans_bb(ctx, insn);
+    case 0x32:
+        return trans_movb(ctx, insn, false);
+    case 0x33:
+        return trans_movb(ctx, insn, true);
+    case 0x38:
+        return trans_be(ctx, insn, false);
+    case 0x39:
+        return trans_be(ctx, insn, true);
+    case 0x3A:
+        return translate_table(ctx, insn, table_branch);
     default:
         break;
     }
-- 
2.9.3

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

* [Qemu-devel] [PULL 22/26] target-hppa: Implement linux-user gateway page
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (19 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 21/26] target-hppa: Implement branches Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 23/26] target-hppa: Implement shifts and deposits Richard Henderson
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

For linux, page 0 is mapped as an execute-only gateway.  A gateway
page is a special bit in the page table that allows a B,GATE insn
within that page to raise processor permissions.  This is how system
calls are implemented for HPPA.

Rather than actually map anything here, or handle permissions at all,
implement the semantics of the actual linux syscall entry points.

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/translate.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 81 insertions(+), 4 deletions(-)

diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 1d0976f..14fe4bb 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -1123,6 +1123,64 @@ static ExitStatus do_ibranch(DisasContext *ctx, TCGv dest,
     return NO_EXIT;
 }
 
+/* On Linux, page zero is normally marked execute only + gateway.
+   Therefore normal read or write is supposed to fail, but specific
+   offsets have kernel code mapped to raise permissions to implement
+   system calls.  Handling this via an explicit check here, rather
+   in than the "be disp(sr2,r0)" instruction that probably sent us
+   here, is the easiest way to handle the branch delay slot on the
+   aforementioned BE.  */
+static ExitStatus do_page_zero(DisasContext *ctx)
+{
+    /* If by some means we get here with PSW[N]=1, that implies that
+       the B,GATE instruction would be skipped, and we'd fault on the
+       next insn within the privilaged page.  */
+    switch (ctx->null_cond.c) {
+    case TCG_COND_NEVER:
+        break;
+    case TCG_COND_ALWAYS:
+        tcg_gen_movi_tl(cpu_psw_n, 0);
+        goto do_sigill;
+    default:
+        /* Since this is always the first (and only) insn within the
+           TB, we should know the state of PSW[N] from TB->FLAGS.  */
+        g_assert_not_reached();
+    }
+
+    /* Check that we didn't arrive here via some means that allowed
+       non-sequential instruction execution.  Normally the PSW[B] bit
+       detects this by disallowing the B,GATE instruction to execute
+       under such conditions.  */
+    if (ctx->iaoq_b != ctx->iaoq_f + 4) {
+        goto do_sigill;
+    }
+
+    switch (ctx->iaoq_f) {
+    case 0x00: /* Null pointer call */
+        gen_excp_1(EXCP_SIGSEGV);
+        return EXIT_NORETURN;
+
+    case 0xb0: /* LWS */
+        gen_excp_1(EXCP_SYSCALL_LWS);
+        return EXIT_NORETURN;
+
+    case 0xe0: /* SET_THREAD_POINTER */
+        tcg_gen_mov_tl(cpu_cr27, cpu_gr[26]);
+        tcg_gen_mov_tl(cpu_iaoq_f, cpu_gr[31]);
+        tcg_gen_addi_tl(cpu_iaoq_b, cpu_iaoq_f, 4);
+        return EXIT_IAQ_N_UPDATED;
+
+    case 0x100: /* SYSCALL */
+        gen_excp_1(EXCP_SYSCALL);
+        return EXIT_NORETURN;
+
+    default:
+    do_sigill:
+        gen_excp_1(EXCP_SIGILL);
+        return EXIT_NORETURN;
+    }
+}
+
 static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
                             const DisasInsn *di)
 {
@@ -1884,7 +1942,10 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
             gen_io_start();
         }
 
-        {
+        if (ctx.iaoq_f < TARGET_PAGE_SIZE) {
+            ret = do_page_zero(&ctx);
+            assert(ret != NO_EXIT);
+        } else {
             /* Always fetch the insn, even if nullified, so that we check
                the page permissions for execute.  */
             uint32_t insn = cpu_ldl_code(env, ctx.iaoq_f);
@@ -1986,9 +2047,25 @@ void gen_intermediate_code(CPUHPPAState *env, struct TranslationBlock *tb)
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
         && qemu_log_in_addr_range(tb->pc)) {
         qemu_log_lock();
-        qemu_log("IN: %s\n", lookup_symbol(tb->pc));
-        log_target_disas(cs, tb->pc, tb->size, 1);
-        qemu_log("\n");
+        switch (tb->pc) {
+        case 0x00:
+            qemu_log("IN:\n0x00000000:  (null)\n\n");
+            break;
+        case 0xb0:
+            qemu_log("IN:\n0x000000b0:  light-weight-syscall\n\n");
+            break;
+        case 0xe0:
+            qemu_log("IN:\n0x000000e0:  set-thread-pointer-syscall\n\n");
+            break;
+        case 0x100:
+            qemu_log("IN:\n0x00000100:  syscall\n\n");
+            break;
+        default:
+            qemu_log("IN: %s\n", lookup_symbol(tb->pc));
+            log_target_disas(cs, tb->pc, tb->size, 1);
+            qemu_log("\n");
+            break;
+        }
         qemu_log_unlock();
     }
 #endif
-- 
2.9.3

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

* [Qemu-devel] [PULL 23/26] target-hppa: Implement shifts and deposits
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (20 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 22/26] target-hppa: Implement linux-user gateway page Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 24/26] target-hppa: Implement loads and stores Richard Henderson
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/translate.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 309 insertions(+)

diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 14fe4bb..093a65e 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -1719,6 +1719,311 @@ static ExitStatus trans_movb(DisasContext *ctx, uint32_t insn, bool is_imm)
     return do_cbranch(ctx, disp, n, &cond);
 }
 
+static ExitStatus trans_shrpw_sar(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned r2 = extract32(insn, 21, 5);
+    TCGv dest;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+
+    dest = dest_gpr(ctx, rt);
+    if (r1 == 0) {
+        tcg_gen_ext32u_tl(dest, load_gpr(ctx, r2));
+        tcg_gen_shr_tl(dest, dest, cpu_sar);
+    } else if (r1 == r2) {
+        TCGv_i32 t32 = tcg_temp_new_i32();
+        tcg_gen_trunc_tl_i32(t32, load_gpr(ctx, r2));
+        tcg_gen_rotr_i32(t32, t32, cpu_sar);
+        tcg_gen_extu_i32_tl(dest, t32);
+        tcg_temp_free_i32(t32);
+    } else {
+        TCGv_i64 t = tcg_temp_new_i64();
+        TCGv_i64 s = tcg_temp_new_i64();
+
+        tcg_gen_concat_tl_i64(t, load_gpr(ctx, r2), load_gpr(ctx, r1));
+        tcg_gen_extu_tl_i64(s, cpu_sar);
+        tcg_gen_shr_i64(t, t, s);
+        tcg_gen_trunc_i64_tl(dest, t);
+
+        tcg_temp_free_i64(t);
+        tcg_temp_free_i64(s);
+    }
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_shrpw_imm(DisasContext *ctx, uint32_t insn,
+                                  const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned cpos = extract32(insn, 5, 5);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned r1 = extract32(insn, 16, 5);
+    unsigned r2 = extract32(insn, 21, 5);
+    unsigned sa = 31 - cpos;
+    TCGv dest, t2;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+
+    dest = dest_gpr(ctx, rt);
+    t2 = load_gpr(ctx, r2);
+    if (r1 == r2) {
+        TCGv_i32 t32 = tcg_temp_new_i32();
+        tcg_gen_trunc_tl_i32(t32, t2);
+        tcg_gen_rotri_i32(t32, t32, sa);
+        tcg_gen_extu_i32_tl(dest, t32);
+        tcg_temp_free_i32(t32);
+    } else if (r1 == 0) {
+        tcg_gen_extract_tl(dest, t2, sa, 32 - sa);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_extract_tl(t0, t2, sa, 32 - sa);
+        tcg_gen_deposit_tl(dest, t0, cpu_gr[r1], 32 - sa, sa);
+        tcg_temp_free(t0);
+    }
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_extrw_sar(DisasContext *ctx, uint32_t insn,
+                                  const DisasInsn *di)
+{
+    unsigned clen = extract32(insn, 0, 5);
+    unsigned is_se = extract32(insn, 10, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned rr = extract32(insn, 21, 5);
+    unsigned len = 32 - clen;
+    TCGv dest, src, tmp;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+
+    dest = dest_gpr(ctx, rt);
+    src = load_gpr(ctx, rr);
+    tmp = tcg_temp_new();
+
+    /* Recall that SAR is using big-endian bit numbering.  */
+    tcg_gen_xori_tl(tmp, cpu_sar, TARGET_LONG_BITS - 1);
+    if (is_se) {
+        tcg_gen_sar_tl(dest, src, tmp);
+        tcg_gen_sextract_tl(dest, dest, 0, len);
+    } else {
+        tcg_gen_shr_tl(dest, src, tmp);
+        tcg_gen_extract_tl(dest, dest, 0, len);
+    }
+    tcg_temp_free(tmp);
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_extrw_imm(DisasContext *ctx, uint32_t insn,
+                                  const DisasInsn *di)
+{
+    unsigned clen = extract32(insn, 0, 5);
+    unsigned pos = extract32(insn, 5, 5);
+    unsigned is_se = extract32(insn, 10, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned rr = extract32(insn, 21, 5);
+    unsigned len = 32 - clen;
+    unsigned cpos = 31 - pos;
+    TCGv dest, src;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+
+    dest = dest_gpr(ctx, rt);
+    src = load_gpr(ctx, rr);
+    if (is_se) {
+        tcg_gen_sextract_tl(dest, src, cpos, len);
+    } else {
+        tcg_gen_extract_tl(dest, src, cpos, len);
+    }
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_sh_ex[] = {
+    { 0xd0000000u, 0xfc001fe0u, trans_shrpw_sar },
+    { 0xd0000800u, 0xfc001c00u, trans_shrpw_imm },
+    { 0xd0001000u, 0xfc001be0u, trans_extrw_sar },
+    { 0xd0001800u, 0xfc001800u, trans_extrw_imm },
+};
+
+static ExitStatus trans_depw_imm_c(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned clen = extract32(insn, 0, 5);
+    unsigned cpos = extract32(insn, 5, 5);
+    unsigned nz = extract32(insn, 10, 1);
+    unsigned c = extract32(insn, 13, 3);
+    target_long val = low_sextract(insn, 16, 5);
+    unsigned rt = extract32(insn, 21, 5);
+    unsigned len = 32 - clen;
+    target_long mask0, mask1;
+    TCGv dest;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+    if (cpos + len > 32) {
+        len = 32 - cpos;
+    }
+
+    dest = dest_gpr(ctx, rt);
+    mask0 = deposit64(0, cpos, len, val);
+    mask1 = deposit64(-1, cpos, len, val);
+
+    if (nz) {
+        TCGv src = load_gpr(ctx, rt);
+        if (mask1 != -1) {
+            tcg_gen_andi_tl(dest, src, mask1);
+            src = dest;
+        }
+        tcg_gen_ori_tl(dest, src, mask0);
+    } else {
+        tcg_gen_movi_tl(dest, mask0);
+    }
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_depw_imm(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned clen = extract32(insn, 0, 5);
+    unsigned cpos = extract32(insn, 5, 5);
+    unsigned nz = extract32(insn, 10, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned rr = extract32(insn, 16, 5);
+    unsigned rt = extract32(insn, 21, 5);
+    unsigned rs = nz ? rt : 0;
+    unsigned len = 32 - clen;
+    TCGv dest, val;
+
+    if (c) {
+        nullify_over(ctx);
+    }
+    if (cpos + len > 32) {
+        len = 32 - cpos;
+    }
+
+    dest = dest_gpr(ctx, rt);
+    val = load_gpr(ctx, rr);
+    if (rs == 0) {
+        tcg_gen_deposit_z_tl(dest, val, cpos, len);
+    } else {
+        tcg_gen_deposit_tl(dest, cpu_gr[rs], val, cpos, len);
+    }
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_depw_sar(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned clen = extract32(insn, 0, 5);
+    unsigned nz = extract32(insn, 10, 1);
+    unsigned i = extract32(insn, 12, 1);
+    unsigned c = extract32(insn, 13, 3);
+    unsigned rt = extract32(insn, 21, 5);
+    unsigned rs = nz ? rt : 0;
+    unsigned len = 32 - clen;
+    TCGv val, mask, tmp, shift, dest;
+    unsigned msb = 1U << (len - 1);
+
+    if (c) {
+        nullify_over(ctx);
+    }
+
+    if (i) {
+        val = load_const(ctx, low_sextract(insn, 16, 5));
+    } else {
+        val = load_gpr(ctx, extract32(insn, 16, 5));
+    }
+    dest = dest_gpr(ctx, rt);
+    shift = tcg_temp_new();
+    tmp = tcg_temp_new();
+
+    /* Convert big-endian bit numbering in SAR to left-shift.  */
+    tcg_gen_xori_tl(shift, cpu_sar, TARGET_LONG_BITS - 1);
+
+    mask = tcg_const_tl(msb + (msb - 1));
+    tcg_gen_and_tl(tmp, val, mask);
+    if (rs) {
+        tcg_gen_shl_tl(mask, mask, shift);
+        tcg_gen_shl_tl(tmp, tmp, shift);
+        tcg_gen_andc_tl(dest, cpu_gr[rs], mask);
+        tcg_gen_or_tl(dest, dest, tmp);
+    } else {
+        tcg_gen_shl_tl(dest, tmp, shift);
+    }
+    tcg_temp_free(shift);
+    tcg_temp_free(mask);
+    tcg_temp_free(tmp);
+    save_gpr(ctx, rt, dest);
+
+    /* Install the new nullification.  */
+    cond_free(&ctx->null_cond);
+    if (c) {
+        ctx->null_cond = do_sed_cond(c, dest);
+    }
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_depw[] = {
+    { 0xd4000000u, 0xfc000be0u, trans_depw_sar },
+    { 0xd4000800u, 0xfc001800u, trans_depw_imm },
+    { 0xd4001800u, 0xfc001800u, trans_depw_imm_c },
+};
+
 static ExitStatus trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
 {
     unsigned n = extract32(insn, 1, 1);
@@ -1874,6 +2179,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_movb(ctx, insn, false);
     case 0x33:
         return trans_movb(ctx, insn, true);
+    case 0x34:
+        return translate_table(ctx, insn, table_sh_ex);
+    case 0x35:
+        return translate_table(ctx, insn, table_depw);
     case 0x38:
         return trans_be(ctx, insn, false);
     case 0x39:
-- 
2.9.3

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

* [Qemu-devel] [PULL 24/26] target-hppa: Implement loads and stores
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (21 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 23/26] target-hppa: Implement shifts and deposits Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 25/26] target-hppa: Implement system and memory-management insns Richard Henderson
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/helper.h    |   3 +
 target/hppa/op_helper.c |  78 ++++++
 target/hppa/translate.c | 618 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 699 insertions(+)

diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index ecff17c..88db719 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -2,4 +2,7 @@ DEF_HELPER_2(excp, noreturn, env, int)
 DEF_HELPER_FLAGS_2(tsv, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl)
 
+DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tl)
+DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tl)
+
 DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index f36ce74..0aa5fb9 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -21,6 +21,7 @@
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
 
 void QEMU_NORETURN HELPER(excp)(CPUHPPAState *env, int excp)
 {
@@ -54,6 +55,83 @@ void HELPER(tcond)(CPUHPPAState *env, target_ulong cond)
     }
 }
 
+static void atomic_store_3(CPUHPPAState *env, target_ulong addr, uint32_t val,
+                           uint32_t mask, uintptr_t ra)
+{
+    uint32_t old, new, cmp;
+
+#ifdef CONFIG_USER_ONLY
+    uint32_t *haddr = g2h(addr - 1);
+    old = *haddr;
+    while (1) {
+        new = (old & ~mask) | (val & mask);
+        cmp = atomic_cmpxchg(haddr, old, new);
+        if (cmp == old) {
+            return;
+        }
+        old = cmp;
+    }
+#else
+#error "Not implemented."
+#endif
+}
+
+void HELPER(stby_b)(CPUHPPAState *env, target_ulong addr, target_ulong val)
+{
+    uintptr_t ra = GETPC();
+
+    switch (addr & 3) {
+    case 3:
+        cpu_stb_data_ra(env, addr, val, ra);
+        break;
+    case 2:
+        cpu_stw_data_ra(env, addr, val, ra);
+        break;
+    case 1:
+        /* The 3 byte store must appear atomic.  */
+        if (parallel_cpus) {
+            atomic_store_3(env, addr, val, 0x00ffffffu, ra);
+        } else {
+            cpu_stb_data_ra(env, addr, val >> 16, ra);
+            cpu_stw_data_ra(env, addr + 1, val, ra);
+        }
+        break;
+    default:
+        cpu_stl_data_ra(env, addr, val, ra);
+        break;
+    }
+}
+
+void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val)
+{
+    uintptr_t ra = GETPC();
+
+    switch (addr & 3) {
+    case 3:
+        /* The 3 byte store must appear atomic.  */
+        if (parallel_cpus) {
+            atomic_store_3(env, addr - 3, val, 0xffffff00u, ra);
+        } else {
+            cpu_stw_data_ra(env, addr - 3, val >> 16, ra);
+            cpu_stb_data_ra(env, addr - 1, val >> 8, ra);
+        }
+        break;
+    case 2:
+        cpu_stw_data_ra(env, addr - 2, val >> 16, ra);
+        break;
+    case 1:
+        cpu_stb_data_ra(env, addr - 1, val >> 24, ra);
+        break;
+    default:
+        /* Nothing is stored, but protection is checked and the
+           cacheline is marked dirty.  */
+#ifndef CONFIG_USER_ONLY
+        probe_write(env, addr, cpu_mmu_index(env, 0), ra);
+#endif
+        break;
+    }
+}
+
 void HELPER(loaded_fr0)(CPUHPPAState *env)
 {
     uint32_t shadow = env->fr[0] >> 32;
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 093a65e..1973777 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -278,6 +278,45 @@ static void save_gpr(DisasContext *ctx, unsigned reg, TCGv t)
     }
 }
 
+#ifdef HOST_WORDS_BIGENDIAN
+# define HI_OFS  0
+# define LO_OFS  4
+#else
+# define HI_OFS  4
+# define LO_OFS  0
+#endif
+
+static TCGv_i32 load_frw_i32(unsigned rt)
+{
+    TCGv_i32 ret = tcg_temp_new_i32();
+    tcg_gen_ld_i32(ret, cpu_env,
+                   offsetof(CPUHPPAState, fr[rt & 31])
+                   + (rt & 32 ? LO_OFS : HI_OFS));
+    return ret;
+}
+
+static void save_frw_i32(unsigned rt, TCGv_i32 val)
+{
+    tcg_gen_st_i32(val, cpu_env,
+                   offsetof(CPUHPPAState, fr[rt & 31])
+                   + (rt & 32 ? LO_OFS : HI_OFS));
+}
+
+#undef HI_OFS
+#undef LO_OFS
+
+static TCGv_i64 load_frd(unsigned rt)
+{
+    TCGv_i64 ret = tcg_temp_new_i64();
+    tcg_gen_ld_i64(ret, cpu_env, offsetof(CPUHPPAState, fr[rt]));
+    return ret;
+}
+
+static void save_frd(unsigned rt, TCGv_i64 val)
+{
+    tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
+}
+
 /* Skip over the implementation of an insn that has been nullified.
    Use this when the insn is too complex for a conditional move.  */
 static void nullify_over(DisasContext *ctx)
@@ -471,6 +510,16 @@ static target_long assemble_16(uint32_t insn)
     return low_sextract(insn, 0, 14);
 }
 
+static target_long assemble_16a(uint32_t insn)
+{
+    /* Take the name from PA2.0, which produces a 14-bit shifted number
+       only with wide mode; otherwise a 12-bit shifted number.  Since we
+       don't implement wide mode, this is always the 12-bit number.  */
+    target_ulong x = -(target_ulong)(insn & 1);
+    x = (x << 11) | extract32(insn, 2, 11);
+    return x << 2;
+}
+
 static target_long assemble_17(uint32_t insn)
 {
     target_ulong x = -(target_ulong)(insn & 1);
@@ -941,6 +990,234 @@ static ExitStatus do_unit(DisasContext *ctx, unsigned rt, TCGv in1,
     return NO_EXIT;
 }
 
+/* Emit a memory load.  The modify parameter should be
+ * < 0 for pre-modify,
+ * > 0 for post-modify,
+ * = 0 for no base register update.
+ */
+static void do_load_32(DisasContext *ctx, TCGv_i32 dest, unsigned rb,
+                       unsigned rx, int scale, target_long disp,
+                       int modify, TCGMemOp mop)
+{
+    TCGv addr, base;
+
+    /* Caller uses nullify_over/nullify_end.  */
+    assert(ctx->null_cond.c == TCG_COND_NEVER);
+
+    addr = tcg_temp_new();
+    base = load_gpr(ctx, rb);
+
+    /* Note that RX is mutually exclusive with DISP.  */
+    if (rx) {
+        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
+        tcg_gen_add_tl(addr, addr, base);
+    } else {
+        tcg_gen_addi_tl(addr, base, disp);
+    }
+
+    if (modify == 0) {
+        tcg_gen_qemu_ld_i32(dest, addr, MMU_USER_IDX, mop);
+    } else {
+        tcg_gen_qemu_ld_i32(dest, (modify < 0 ? addr : base),
+                            MMU_USER_IDX, mop);
+        save_gpr(ctx, rb, addr);
+    }
+    tcg_temp_free(addr);
+}
+
+static void do_load_64(DisasContext *ctx, TCGv_i64 dest, unsigned rb,
+                       unsigned rx, int scale, target_long disp,
+                       int modify, TCGMemOp mop)
+{
+    TCGv addr, base;
+
+    /* Caller uses nullify_over/nullify_end.  */
+    assert(ctx->null_cond.c == TCG_COND_NEVER);
+
+    addr = tcg_temp_new();
+    base = load_gpr(ctx, rb);
+
+    /* Note that RX is mutually exclusive with DISP.  */
+    if (rx) {
+        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
+        tcg_gen_add_tl(addr, addr, base);
+    } else {
+        tcg_gen_addi_tl(addr, base, disp);
+    }
+
+    if (modify == 0) {
+        tcg_gen_qemu_ld_i64(dest, addr, MMU_USER_IDX, mop);
+    } else {
+        tcg_gen_qemu_ld_i64(dest, (modify < 0 ? addr : base),
+                            MMU_USER_IDX, mop);
+        save_gpr(ctx, rb, addr);
+    }
+    tcg_temp_free(addr);
+}
+
+static void do_store_32(DisasContext *ctx, TCGv_i32 src, unsigned rb,
+                        unsigned rx, int scale, target_long disp,
+                        int modify, TCGMemOp mop)
+{
+    TCGv addr, base;
+
+    /* Caller uses nullify_over/nullify_end.  */
+    assert(ctx->null_cond.c == TCG_COND_NEVER);
+
+    addr = tcg_temp_new();
+    base = load_gpr(ctx, rb);
+
+    /* Note that RX is mutually exclusive with DISP.  */
+    if (rx) {
+        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
+        tcg_gen_add_tl(addr, addr, base);
+    } else {
+        tcg_gen_addi_tl(addr, base, disp);
+    }
+
+    tcg_gen_qemu_st_i32(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
+
+    if (modify != 0) {
+        save_gpr(ctx, rb, addr);
+    }
+    tcg_temp_free(addr);
+}
+
+static void do_store_64(DisasContext *ctx, TCGv_i64 src, unsigned rb,
+                        unsigned rx, int scale, target_long disp,
+                        int modify, TCGMemOp mop)
+{
+    TCGv addr, base;
+
+    /* Caller uses nullify_over/nullify_end.  */
+    assert(ctx->null_cond.c == TCG_COND_NEVER);
+
+    addr = tcg_temp_new();
+    base = load_gpr(ctx, rb);
+
+    /* Note that RX is mutually exclusive with DISP.  */
+    if (rx) {
+        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
+        tcg_gen_add_tl(addr, addr, base);
+    } else {
+        tcg_gen_addi_tl(addr, base, disp);
+    }
+
+    tcg_gen_qemu_st_i64(src, (modify <= 0 ? addr : base), MMU_USER_IDX, mop);
+
+    if (modify != 0) {
+        save_gpr(ctx, rb, addr);
+    }
+    tcg_temp_free(addr);
+}
+
+#if TARGET_LONG_BITS == 64
+#define do_load_tl  do_load_64
+#define do_store_tl do_store_64
+#else
+#define do_load_tl  do_load_32
+#define do_store_tl do_store_32
+#endif
+
+static ExitStatus do_load(DisasContext *ctx, unsigned rt, unsigned rb,
+                          unsigned rx, int scale, target_long disp,
+                          int modify, TCGMemOp mop)
+{
+    TCGv dest;
+
+    nullify_over(ctx);
+
+    if (modify == 0) {
+        /* No base register update.  */
+        dest = dest_gpr(ctx, rt);
+    } else {
+        /* Make sure if RT == RB, we see the result of the load.  */
+        dest = get_temp(ctx);
+    }
+    do_load_tl(ctx, dest, rb, rx, scale, disp, modify, mop);
+    save_gpr(ctx, rt, dest);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_floadw(DisasContext *ctx, unsigned rt, unsigned rb,
+                            unsigned rx, int scale, target_long disp,
+                            int modify)
+{
+    TCGv_i32 tmp;
+
+    nullify_over(ctx);
+
+    tmp = tcg_temp_new_i32();
+    do_load_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
+    save_frw_i32(rt, tmp);
+    tcg_temp_free_i32(tmp);
+
+    if (rt == 0) {
+        gen_helper_loaded_fr0(cpu_env);
+    }
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_floadd(DisasContext *ctx, unsigned rt, unsigned rb,
+                            unsigned rx, int scale, target_long disp,
+                            int modify)
+{
+    TCGv_i64 tmp;
+
+    nullify_over(ctx);
+
+    tmp = tcg_temp_new_i64();
+    do_load_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
+    save_frd(rt, tmp);
+    tcg_temp_free_i64(tmp);
+
+    if (rt == 0) {
+        gen_helper_loaded_fr0(cpu_env);
+    }
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_store(DisasContext *ctx, unsigned rt, unsigned rb,
+                           target_long disp, int modify, TCGMemOp mop)
+{
+    nullify_over(ctx);
+    do_store_tl(ctx, load_gpr(ctx, rt), rb, 0, 0, disp, modify, mop);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fstorew(DisasContext *ctx, unsigned rt, unsigned rb,
+                             unsigned rx, int scale, target_long disp,
+                             int modify)
+{
+    TCGv_i32 tmp;
+
+    nullify_over(ctx);
+
+    tmp = load_frw_i32(rt);
+    do_store_32(ctx, tmp, rb, rx, scale, disp, modify, MO_TEUL);
+    tcg_temp_free_i32(tmp);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
+                             unsigned rx, int scale, target_long disp,
+                             int modify)
+{
+    TCGv_i64 tmp;
+
+    nullify_over(ctx);
+
+    tmp = load_frd(rt);
+    do_store_64(ctx, tmp, rb, rx, scale, disp, modify, MO_TEQ);
+    tcg_temp_free_i64(tmp);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
 /* Emit an unconditional branch to a direct target, which may or may not
    have already had nullification handled.  */
 static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
@@ -1547,6 +1824,149 @@ static ExitStatus trans_cmpiclr(DisasContext *ctx, uint32_t insn)
     return nullify_end(ctx, ret);
 }
 
+static ExitStatus trans_ld_idx_i(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned sz = extract32(insn, 6, 2);
+    unsigned a = extract32(insn, 13, 1);
+    int disp = low_sextract(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    int modify = (m ? (a ? -1 : 1) : 0);
+    TCGMemOp mop = MO_TE | sz;
+
+    return do_load(ctx, rt, rb, 0, 0, disp, modify, mop);
+}
+
+static ExitStatus trans_ld_idx_x(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned sz = extract32(insn, 6, 2);
+    unsigned u = extract32(insn, 13, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    TCGMemOp mop = MO_TE | sz;
+
+    return do_load(ctx, rt, rb, rx, u ? sz : 0, 0, m, mop);
+}
+
+static ExitStatus trans_st_idx_i(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    int disp = low_sextract(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned sz = extract32(insn, 6, 2);
+    unsigned a = extract32(insn, 13, 1);
+    unsigned rr = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    int modify = (m ? (a ? -1 : 1) : 0);
+    TCGMemOp mop = MO_TE | sz;
+
+    return do_store(ctx, rr, rb, disp, modify, mop);
+}
+
+static ExitStatus trans_ldcw(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned i = extract32(insn, 12, 1);
+    unsigned au = extract32(insn, 13, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    TCGMemOp mop = MO_TEUL | MO_ALIGN_16;
+    TCGv zero, addr, base, dest;
+    int modify, disp = 0, scale = 0;
+
+    nullify_over(ctx);
+
+    /* ??? Share more code with do_load and do_load_{32,64}.  */
+
+    if (i) {
+        modify = (m ? (au ? -1 : 1) : 0);
+        disp = low_sextract(rx, 0, 5);
+        rx = 0;
+    } else {
+        modify = m;
+        if (au) {
+            scale = mop & MO_SIZE;
+        }
+    }
+    if (modify) {
+        /* Base register modification.  Make sure if RT == RB, we see
+           the result of the load.  */
+        dest = get_temp(ctx);
+    } else {
+        dest = dest_gpr(ctx, rt);
+    }
+
+    addr = tcg_temp_new();
+    base = load_gpr(ctx, rb);
+    if (rx) {
+        tcg_gen_shli_tl(addr, cpu_gr[rx], scale);
+        tcg_gen_add_tl(addr, addr, base);
+    } else {
+        tcg_gen_addi_tl(addr, base, disp);
+    }
+
+    zero = tcg_const_tl(0);
+    tcg_gen_atomic_xchg_tl(dest, (modify <= 0 ? addr : base),
+                           zero, MMU_USER_IDX, mop);
+    if (modify) {
+        save_gpr(ctx, rb, addr);
+    }
+    save_gpr(ctx, rt, dest);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_stby(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    target_long disp = low_sextract(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned a = extract32(insn, 13, 1);
+    unsigned rt = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    TCGv addr, val;
+
+    nullify_over(ctx);
+
+    addr = tcg_temp_new();
+    if (m || disp == 0) {
+        tcg_gen_mov_tl(addr, load_gpr(ctx, rb));
+    } else {
+        tcg_gen_addi_tl(addr, load_gpr(ctx, rb), disp);
+    }
+    val = load_gpr(ctx, rt);
+
+    if (a) {
+        gen_helper_stby_e(cpu_env, addr, val);
+    } else {
+        gen_helper_stby_b(cpu_env, addr, val);
+    }
+
+    if (m) {
+        tcg_gen_addi_tl(addr, addr, disp);
+        tcg_gen_andi_tl(addr, addr, ~3);
+        save_gpr(ctx, rb, addr);
+    }
+    tcg_temp_free(addr);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_index_mem[] = {
+    { 0x0c001000u, 0xfc001300, trans_ld_idx_i }, /* LD[BHWD], im */
+    { 0x0c000000u, 0xfc001300, trans_ld_idx_x }, /* LD[BHWD], rx */
+    { 0x0c001200u, 0xfc001300, trans_st_idx_i }, /* ST[BHWD] */
+    { 0x0c0001c0u, 0xfc0003c0, trans_ldcw },
+    { 0x0c001300u, 0xfc0013c0, trans_stby },
+};
+
 static ExitStatus trans_ldil(DisasContext *ctx, uint32_t insn)
 {
     unsigned rt = extract32(insn, 21, 5);
@@ -1594,6 +2014,160 @@ static ExitStatus trans_ldo(DisasContext *ctx, uint32_t insn)
     return NO_EXIT;
 }
 
+static ExitStatus trans_load(DisasContext *ctx, uint32_t insn,
+                             bool is_mod, TCGMemOp mop)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = extract32(insn, 16, 5);
+    target_long i = assemble_16(insn);
+
+    return do_load(ctx, rt, rb, 0, 0, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
+}
+
+static ExitStatus trans_load_w(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = extract32(insn, 16, 5);
+    target_long i = assemble_16a(insn);
+    unsigned ext2 = extract32(insn, 1, 2);
+
+    switch (ext2) {
+    case 0:
+    case 1:
+        /* FLDW without modification.  */
+        return do_floadw(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
+    case 2:
+        /* LDW with modification.  Note that the sign of I selects
+           post-dec vs pre-inc.  */
+        return do_load(ctx, rt, rb, 0, 0, i, (i < 0 ? 1 : -1), MO_TEUL);
+    default:
+        return gen_illegal(ctx);
+    }
+}
+
+static ExitStatus trans_fload_mod(DisasContext *ctx, uint32_t insn)
+{
+    target_long i = assemble_16a(insn);
+    unsigned t1 = extract32(insn, 1, 1);
+    unsigned a = extract32(insn, 2, 1);
+    unsigned t0 = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+
+    /* FLDW with modification.  */
+    return do_floadw(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
+}
+
+static ExitStatus trans_store(DisasContext *ctx, uint32_t insn,
+                              bool is_mod, TCGMemOp mop)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = extract32(insn, 16, 5);
+    target_long i = assemble_16(insn);
+
+    return do_store(ctx, rt, rb, i, is_mod ? (i < 0 ? -1 : 1) : 0, mop);
+}
+
+static ExitStatus trans_store_w(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = extract32(insn, 16, 5);
+    target_long i = assemble_16a(insn);
+    unsigned ext2 = extract32(insn, 1, 2);
+
+    switch (ext2) {
+    case 0:
+    case 1:
+        /* FSTW without modification.  */
+        return do_fstorew(ctx, ext2 * 32 + rt, rb, 0, 0, i, 0);
+    case 2:
+        /* LDW with modification.  */
+        return do_store(ctx, rt, rb, i, (i < 0 ? 1 : -1), MO_TEUL);
+    default:
+        return gen_illegal(ctx);
+    }
+}
+
+static ExitStatus trans_fstore_mod(DisasContext *ctx, uint32_t insn)
+{
+    target_long i = assemble_16a(insn);
+    unsigned t1 = extract32(insn, 1, 1);
+    unsigned a = extract32(insn, 2, 1);
+    unsigned t0 = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+
+    /* FSTW with modification.  */
+    return do_fstorew(ctx, t1 * 32 + t0, rb, 0, 0, i, (a ? -1 : 1));
+}
+
+static ExitStatus trans_copr_w(DisasContext *ctx, uint32_t insn)
+{
+    unsigned t0 = extract32(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned t1 = extract32(insn, 6, 1);
+    unsigned ext3 = extract32(insn, 7, 3);
+    /* unsigned cc = extract32(insn, 10, 2); */
+    unsigned i = extract32(insn, 12, 1);
+    unsigned ua = extract32(insn, 13, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rt = t1 * 32 + t0;
+    int modify = (m ? (ua ? -1 : 1) : 0);
+    int disp, scale;
+
+    if (i == 0) {
+        scale = (ua ? 2 : 0);
+        disp = 0;
+        modify = m;
+    } else {
+        disp = low_sextract(rx, 0, 5);
+        scale = 0;
+        rx = 0;
+        modify = (m ? (ua ? -1 : 1) : 0);
+    }
+
+    switch (ext3) {
+    case 0: /* FLDW */
+        return do_floadw(ctx, rt, rb, rx, scale, disp, modify);
+    case 4: /* FSTW */
+        return do_fstorew(ctx, rt, rb, rx, scale, disp, modify);
+    }
+    return gen_illegal(ctx);
+}
+
+static ExitStatus trans_copr_dw(DisasContext *ctx, uint32_t insn)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned m = extract32(insn, 5, 1);
+    unsigned ext4 = extract32(insn, 6, 4);
+    /* unsigned cc = extract32(insn, 10, 2); */
+    unsigned i = extract32(insn, 12, 1);
+    unsigned ua = extract32(insn, 13, 1);
+    unsigned rx = extract32(insn, 16, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    int modify = (m ? (ua ? -1 : 1) : 0);
+    int disp, scale;
+
+    if (i == 0) {
+        scale = (ua ? 3 : 0);
+        disp = 0;
+        modify = m;
+    } else {
+        disp = low_sextract(rx, 0, 5);
+        scale = 0;
+        rx = 0;
+        modify = (m ? (ua ? -1 : 1) : 0);
+    }
+
+    switch (ext4) {
+    case 0: /* FLDD */
+        return do_floadd(ctx, rt, rb, rx, scale, disp, modify);
+    case 8: /* FSTD */
+        return do_fstored(ctx, rt, rb, rx, scale, disp, modify);
+    default:
+        return gen_illegal(ctx);
+    }
+}
+
 static ExitStatus trans_cmpb(DisasContext *ctx, uint32_t insn,
                              bool is_true, bool is_imm, bool is_dw)
 {
@@ -2139,12 +2713,44 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     switch (opc) {
     case 0x02:
         return translate_table(ctx, insn, table_arith_log);
+    case 0x03:
+        return translate_table(ctx, insn, table_index_mem);
     case 0x08:
         return trans_ldil(ctx, insn);
+    case 0x09:
+        return trans_copr_w(ctx, insn);
     case 0x0A:
         return trans_addil(ctx, insn);
+    case 0x0B:
+        return trans_copr_dw(ctx, insn);
     case 0x0D:
         return trans_ldo(ctx, insn);
+
+    case 0x10:
+        return trans_load(ctx, insn, false, MO_UB);
+    case 0x11:
+        return trans_load(ctx, insn, false, MO_TEUW);
+    case 0x12:
+        return trans_load(ctx, insn, false, MO_TEUL);
+    case 0x13:
+        return trans_load(ctx, insn, true, MO_TEUL);
+    case 0x16:
+        return trans_fload_mod(ctx, insn);
+    case 0x17:
+        return trans_load_w(ctx, insn);
+    case 0x18:
+        return trans_store(ctx, insn, false, MO_UB);
+    case 0x19:
+        return trans_store(ctx, insn, false, MO_TEUW);
+    case 0x1A:
+        return trans_store(ctx, insn, false, MO_TEUL);
+    case 0x1B:
+        return trans_store(ctx, insn, true, MO_TEUL);
+    case 0x1E:
+        return trans_fstore_mod(ctx, insn);
+    case 0x1F:
+        return trans_store_w(ctx, insn);
+
     case 0x20:
         return trans_cmpb(ctx, insn, true, false, false);
     case 0x21:
@@ -2172,6 +2778,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_addi(ctx, insn);
     case 0x2F:
         return trans_cmpb(ctx, insn, false, false, true);
+
     case 0x30:
     case 0x31:
         return trans_bb(ctx, insn);
@@ -2189,6 +2796,17 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_be(ctx, insn, true);
     case 0x3A:
         return translate_table(ctx, insn, table_branch);
+
+    case 0x04: /* spopn */
+    case 0x05: /* diag */
+    case 0x0F: /* product specific */
+        break;
+
+    case 0x07: /* unassigned */
+    case 0x15: /* unassigned */
+    case 0x1D: /* unassigned */
+    case 0x37: /* unassigned */
+    case 0x3F: /* unassigned */
     default:
         break;
     }
-- 
2.9.3

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

* [Qemu-devel] [PULL 25/26] target-hppa: Implement system and memory-management insns
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (22 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 24/26] target-hppa: Implement loads and stores Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23  2:17 ` [Qemu-devel] [PULL 26/26] target-hppa: Implement floating-point insns Richard Henderson
  2017-01-23 10:31 ` [Qemu-devel] [PULL 00/26] New hppa-linux target support Peter Maydell
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/helper.h    |   3 +
 target/hppa/op_helper.c |  10 +++
 target/hppa/translate.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+)

diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index 88db719..d51cf6d 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -5,4 +5,7 @@ DEF_HELPER_FLAGS_2(tcond, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_3(stby_b, TCG_CALL_NO_WG, void, env, tl, tl)
 DEF_HELPER_FLAGS_3(stby_e, TCG_CALL_NO_WG, void, env, tl, tl)
 
+DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tl, tl)
+
 DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 0aa5fb9..670e600 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -132,6 +132,16 @@ void HELPER(stby_e)(CPUHPPAState *env, target_ulong addr, target_ulong val)
     }
 }
 
+target_ulong HELPER(probe_r)(target_ulong addr)
+{
+    return page_check_range(addr, 1, PAGE_READ);
+}
+
+target_ulong HELPER(probe_w)(target_ulong addr)
+{
+    return page_check_range(addr, 1, PAGE_WRITE);
+}
+
 void HELPER(loaded_fr0)(CPUHPPAState *env)
 {
     uint32_t shadow = env->fr[0] >> 32;
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 1973777..cfdb9ee 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -1465,6 +1465,208 @@ static ExitStatus trans_nop(DisasContext *ctx, uint32_t insn,
     return NO_EXIT;
 }
 
+static ExitStatus trans_break(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    nullify_over(ctx);
+    return nullify_end(ctx, gen_excp(ctx, EXCP_DEBUG));
+}
+
+static ExitStatus trans_sync(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    /* No point in nullifying the memory barrier.  */
+    tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_mfia(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    TCGv tmp = dest_gpr(ctx, rt);
+    tcg_gen_movi_tl(tmp, ctx->iaoq_f);
+    save_gpr(ctx, rt, tmp);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_mfsp(DisasContext *ctx, uint32_t insn,
+                             const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    TCGv tmp = dest_gpr(ctx, rt);
+
+    /* ??? We don't implement space registers.  */
+    tcg_gen_movi_tl(tmp, 0);
+    save_gpr(ctx, rt, tmp);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_mfctl(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ctl = extract32(insn, 21, 5);
+    TCGv tmp;
+
+    switch (ctl) {
+    case 11: /* SAR */
+#ifdef TARGET_HPPA64
+        if (extract32(insn, 14, 1) == 0) {
+            /* MFSAR without ,W masks low 5 bits.  */
+            tmp = dest_gpr(ctx, rt);
+            tcg_gen_andi_tl(tmp, cpu_sar, 31);
+            save_gpr(ctx, rt, tmp);
+            break;
+        }
+#endif
+        save_gpr(ctx, rt, cpu_sar);
+        break;
+    case 16: /* Interval Timer */
+        tmp = dest_gpr(ctx, rt);
+        tcg_gen_movi_tl(tmp, 0); /* FIXME */
+        save_gpr(ctx, rt, tmp);
+        break;
+    case 26:
+        save_gpr(ctx, rt, cpu_cr26);
+        break;
+    case 27:
+        save_gpr(ctx, rt, cpu_cr27);
+        break;
+    default:
+        /* All other control registers are privileged.  */
+        return gen_illegal(ctx);
+    }
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_mtctl(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    unsigned rin = extract32(insn, 16, 5);
+    unsigned ctl = extract32(insn, 21, 5);
+    TCGv tmp;
+
+    if (ctl == 11) { /* SAR */
+        tmp = tcg_temp_new();
+        tcg_gen_andi_tl(tmp, load_gpr(ctx, rin), TARGET_LONG_BITS - 1);
+        save_or_nullify(ctx, cpu_sar, tmp);
+        tcg_temp_free(tmp);
+    } else {
+        /* All other control registers are privileged or read-only.  */
+        return gen_illegal(ctx);
+    }
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_mtsarcm(DisasContext *ctx, uint32_t insn,
+                                const DisasInsn *di)
+{
+    unsigned rin = extract32(insn, 16, 5);
+    TCGv tmp = tcg_temp_new();
+
+    tcg_gen_not_tl(tmp, load_gpr(ctx, rin));
+    tcg_gen_andi_tl(tmp, tmp, TARGET_LONG_BITS - 1);
+    save_or_nullify(ctx, cpu_sar, tmp);
+    tcg_temp_free(tmp);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_ldsid(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    TCGv dest = dest_gpr(ctx, rt);
+
+    /* Since we don't implement space registers, this returns zero.  */
+    tcg_gen_movi_tl(dest, 0);
+    save_gpr(ctx, rt, dest);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static const DisasInsn table_system[] = {
+    { 0x00000000u, 0xfc001fe0u, trans_break },
+    /* We don't implement space register, so MTSP is a nop.  */
+    { 0x00001820u, 0xffe01fffu, trans_nop },
+    { 0x00001840u, 0xfc00ffffu, trans_mtctl },
+    { 0x016018c0u, 0xffe0ffffu, trans_mtsarcm },
+    { 0x000014a0u, 0xffffffe0u, trans_mfia },
+    { 0x000004a0u, 0xffff1fe0u, trans_mfsp },
+    { 0x000008a0u, 0xfc1fffe0u, trans_mfctl },
+    { 0x00000400u, 0xffffffffu, trans_sync },
+    { 0x000010a0u, 0xfc1f3fe0u, trans_ldsid },
+};
+
+static ExitStatus trans_base_idx_mod(DisasContext *ctx, uint32_t insn,
+                                     const DisasInsn *di)
+{
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned rx = extract32(insn, 16, 5);
+    TCGv dest = dest_gpr(ctx, rb);
+    TCGv src1 = load_gpr(ctx, rb);
+    TCGv src2 = load_gpr(ctx, rx);
+
+    /* The only thing we need to do is the base register modification.  */
+    tcg_gen_add_tl(dest, src1, src2);
+    save_gpr(ctx, rb, dest);
+
+    cond_free(&ctx->null_cond);
+    return NO_EXIT;
+}
+
+static ExitStatus trans_probe(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned rb = extract32(insn, 21, 5);
+    unsigned is_write = extract32(insn, 6, 1);
+    TCGv dest;
+
+    nullify_over(ctx);
+
+    /* ??? Do something with priv level operand.  */
+    dest = dest_gpr(ctx, rt);
+    if (is_write) {
+        gen_helper_probe_w(dest, load_gpr(ctx, rb));
+    } else {
+        gen_helper_probe_r(dest, load_gpr(ctx, rb));
+    }
+    save_gpr(ctx, rt, dest);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_mem_mgmt[] = {
+    { 0x04003280u, 0xfc003fffu, trans_nop },          /* fdc, disp */
+    { 0x04001280u, 0xfc003fffu, trans_nop },          /* fdc, index */
+    { 0x040012a0u, 0xfc003fffu, trans_base_idx_mod }, /* fdc, index, base mod */
+    { 0x040012c0u, 0xfc003fffu, trans_nop },          /* fdce */
+    { 0x040012e0u, 0xfc003fffu, trans_base_idx_mod }, /* fdce, base mod */
+    { 0x04000280u, 0xfc001fffu, trans_nop },          /* fic 0a */
+    { 0x040002a0u, 0xfc001fffu, trans_base_idx_mod }, /* fic 0a, base mod */
+    { 0x040013c0u, 0xfc003fffu, trans_nop },          /* fic 4f */
+    { 0x040013e0u, 0xfc003fffu, trans_base_idx_mod }, /* fic 4f, base mod */
+    { 0x040002c0u, 0xfc001fffu, trans_nop },          /* fice */
+    { 0x040002e0u, 0xfc001fffu, trans_base_idx_mod }, /* fice, base mod */
+    { 0x04002700u, 0xfc003fffu, trans_nop },          /* pdc */
+    { 0x04002720u, 0xfc003fffu, trans_base_idx_mod }, /* pdc, base mod */
+    { 0x04001180u, 0xfc003fa0u, trans_probe },        /* probe */
+    { 0x04003180u, 0xfc003fa0u, trans_probe },        /* probei */
+};
+
 static ExitStatus trans_add(DisasContext *ctx, uint32_t insn,
                             const DisasInsn *di)
 {
@@ -2711,6 +2913,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     uint32_t opc = extract32(insn, 26, 6);
 
     switch (opc) {
+    case 0x00: /* system op */
+        return translate_table(ctx, insn, table_system);
+    case 0x01:
+        return translate_table(ctx, insn, table_mem_mgmt);
     case 0x02:
         return translate_table(ctx, insn, table_arith_log);
     case 0x03:
-- 
2.9.3

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

* [Qemu-devel] [PULL 26/26] target-hppa: Implement floating-point insns
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (23 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 25/26] target-hppa: Implement system and memory-management insns Richard Henderson
@ 2017-01-23  2:17 ` Richard Henderson
  2017-01-23 10:31 ` [Qemu-devel] [PULL 00/26] New hppa-linux target support Peter Maydell
  25 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-23  2:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: peter.maydell

Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target/hppa/helper.h    |  55 ++++
 target/hppa/op_helper.c | 394 ++++++++++++++++++++++++++
 target/hppa/translate.c | 728 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1177 insertions(+)

diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index d51cf6d..789f07f 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -9,3 +9,58 @@ DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tl, tl)
 
 DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env)
+
+DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_RWG, f32, env, f32)
+DEF_HELPER_FLAGS_2(frnd_s, TCG_CALL_NO_RWG, f32, env, f32)
+DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fmpy_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
+DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_RWG, f32, env, f32, f32)
+
+DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_RWG, f64, env, f64)
+DEF_HELPER_FLAGS_2(frnd_d, TCG_CALL_NO_RWG, f64, env, f64)
+DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fmpy_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
+DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_RWG, f64, env, f64, f64)
+
+DEF_HELPER_FLAGS_2(fcnv_s_d, TCG_CALL_NO_RWG, f64, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_d_s, TCG_CALL_NO_RWG, f32, env, f64)
+
+DEF_HELPER_FLAGS_2(fcnv_w_s, TCG_CALL_NO_RWG, f32, env, s32)
+DEF_HELPER_FLAGS_2(fcnv_dw_s, TCG_CALL_NO_RWG, f32, env, s64)
+DEF_HELPER_FLAGS_2(fcnv_w_d, TCG_CALL_NO_RWG, f64, env, s32)
+DEF_HELPER_FLAGS_2(fcnv_dw_d, TCG_CALL_NO_RWG, f64, env, s64)
+
+DEF_HELPER_FLAGS_2(fcnv_s_w, TCG_CALL_NO_RWG, s32, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_d_w, TCG_CALL_NO_RWG, s32, env, f64)
+DEF_HELPER_FLAGS_2(fcnv_s_dw, TCG_CALL_NO_RWG, s64, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_d_dw, TCG_CALL_NO_RWG, s64, env, f64)
+
+DEF_HELPER_FLAGS_2(fcnv_t_s_w, TCG_CALL_NO_RWG, s32, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_t_d_w, TCG_CALL_NO_RWG, s32, env, f64)
+DEF_HELPER_FLAGS_2(fcnv_t_s_dw, TCG_CALL_NO_RWG, s64, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_t_d_dw, TCG_CALL_NO_RWG, s64, env, f64)
+
+DEF_HELPER_FLAGS_2(fcnv_uw_s, TCG_CALL_NO_RWG, f32, env, i32)
+DEF_HELPER_FLAGS_2(fcnv_udw_s, TCG_CALL_NO_RWG, f32, env, i64)
+DEF_HELPER_FLAGS_2(fcnv_uw_d, TCG_CALL_NO_RWG, f64, env, i32)
+DEF_HELPER_FLAGS_2(fcnv_udw_d, TCG_CALL_NO_RWG, f64, env, i64)
+
+DEF_HELPER_FLAGS_2(fcnv_s_uw, TCG_CALL_NO_RWG, i32, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_d_uw, TCG_CALL_NO_RWG, i32, env, f64)
+DEF_HELPER_FLAGS_2(fcnv_s_udw, TCG_CALL_NO_RWG, i64, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_d_udw, TCG_CALL_NO_RWG, i64, env, f64)
+
+DEF_HELPER_FLAGS_2(fcnv_t_s_uw, TCG_CALL_NO_RWG, i32, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_t_d_uw, TCG_CALL_NO_RWG, i32, env, f64)
+DEF_HELPER_FLAGS_2(fcnv_t_s_udw, TCG_CALL_NO_RWG, i64, env, f32)
+DEF_HELPER_FLAGS_2(fcnv_t_d_udw, TCG_CALL_NO_RWG, i64, env, f64)
+
+DEF_HELPER_FLAGS_5(fcmp_s, TCG_CALL_NO_RWG, void, env, f32, f32, i32, i32)
+DEF_HELPER_FLAGS_5(fcmp_d, TCG_CALL_NO_RWG, void, env, f64, f64, i32, i32)
+
+DEF_HELPER_FLAGS_4(fmpyfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
+DEF_HELPER_FLAGS_4(fmpynfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32)
+DEF_HELPER_FLAGS_4(fmpyfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmpynfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 670e600..c05c0d5 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -174,3 +174,397 @@ void cpu_hppa_loaded_fr0(CPUHPPAState *env)
 {
     helper_loaded_fr0(env);
 }
+
+#define CONVERT_BIT(X, SRC, DST)        \
+    ((SRC) > (DST)                      \
+     ? (X) / ((SRC) / (DST)) & (DST)    \
+     : ((X) & (SRC)) * ((DST) / (SRC)))
+
+static void update_fr0_op(CPUHPPAState *env, uintptr_t ra)
+{
+    uint32_t soft_exp = get_float_exception_flags(&env->fp_status);
+    uint32_t hard_exp = 0;
+    uint32_t shadow = env->fr0_shadow;
+
+    if (likely(soft_exp == 0)) {
+        env->fr[0] = (uint64_t)shadow << 32;
+        return;
+    }
+    set_float_exception_flags(0, &env->fp_status);
+
+    hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact,   1u << 0);
+    hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, 1u << 1);
+    hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow,  1u << 2);
+    hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, 1u << 3);
+    hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid,   1u << 4);
+    shadow |= hard_exp << (32 - 5);
+    env->fr0_shadow = shadow;
+    env->fr[0] = (uint64_t)shadow << 32;
+
+    if (hard_exp & shadow) {
+        dynexcp(env, EXCP_SIGFPE, ra);
+    }
+}
+
+float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg)
+{
+    float32 ret = float32_sqrt(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg)
+{
+    float32 ret = float32_round_to_int(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b)
+{
+    float32 ret = float32_add(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b)
+{
+    float32 ret = float32_sub(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b)
+{
+    float32 ret = float32_mul(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b)
+{
+    float32 ret = float32_div(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg)
+{
+    float64 ret = float64_sqrt(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg)
+{
+    float64 ret = float64_round_to_int(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b)
+{
+    float64 ret = float64_add(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b)
+{
+    float64 ret = float64_sub(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b)
+{
+    float64 ret = float64_mul(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b)
+{
+    float64 ret = float64_div(a, b, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg)
+{
+    float64 ret = float32_to_float64(arg, &env->fp_status);
+    ret = float64_maybe_silence_nan(ret, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg)
+{
+    float32 ret = float64_to_float32(arg, &env->fp_status);
+    ret = float32_maybe_silence_nan(ret, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg)
+{
+    float32 ret = int32_to_float32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg)
+{
+    float32 ret = int64_to_float32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg)
+{
+    float64 ret = int32_to_float64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg)
+{
+    float64 ret = int64_to_float64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg)
+{
+    int32_t ret = float32_to_int32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg)
+{
+    int32_t ret = float64_to_int32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg)
+{
+    int64_t ret = float32_to_int64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg)
+{
+    int64_t ret = float64_to_int64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg)
+{
+    int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg)
+{
+    int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg)
+{
+    int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg)
+{
+    int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg)
+{
+    float32 ret = uint32_to_float32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg)
+{
+    float32 ret = uint64_to_float32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg)
+{
+    float64 ret = uint32_to_float64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg)
+{
+    float64 ret = uint64_to_float64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg)
+{
+    uint32_t ret = float32_to_uint32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg)
+{
+    uint32_t ret = float64_to_uint32(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg)
+{
+    uint64_t ret = float32_to_uint64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg)
+{
+    uint64_t ret = float64_to_uint64(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg)
+{
+    uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg)
+{
+    uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg)
+{
+    uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg)
+{
+    uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r)
+{
+    uint32_t shadow = env->fr0_shadow;
+
+    switch (r) {
+    case float_relation_greater:
+        c = extract32(c, 4, 1);
+        break;
+    case float_relation_less:
+        c = extract32(c, 3, 1);
+        break;
+    case float_relation_equal:
+        c = extract32(c, 2, 1);
+        break;
+    case float_relation_unordered:
+        c = extract32(c, 1, 1);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    if (y) {
+        /* targeted comparison */
+        /* set fpsr[ca[y - 1]] to current compare */
+        shadow = deposit32(shadow, 21 - (y - 1), 1, c);
+    } else {
+        /* queued comparison */
+        /* shift cq right by one place */
+        shadow = deposit32(shadow, 11, 10, extract32(shadow, 12, 10));
+        /* move fpsr[c] to fpsr[cq[0]] */
+        shadow = deposit32(shadow, 21, 1, extract32(shadow, 26, 1));
+        /* set fpsr[c] to current compare */
+        shadow = deposit32(shadow, 26, 1, c);
+    }
+
+    env->fr0_shadow = shadow;
+    env->fr[0] = (uint64_t)shadow << 32;
+}
+
+void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b,
+                    uint32_t y, uint32_t c)
+{
+    int r;
+    if (c & 1) {
+        r = float32_compare(a, b, &env->fp_status);
+    } else {
+        r = float32_compare_quiet(a, b, &env->fp_status);
+    }
+    update_fr0_op(env, GETPC());
+    update_fr0_cmp(env, y, c, r);
+}
+
+void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b,
+                    uint32_t y, uint32_t c)
+{
+    int r;
+    if (c & 1) {
+        r = float64_compare(a, b, &env->fp_status);
+    } else {
+        r = float64_compare_quiet(a, b, &env->fp_status);
+    }
+    update_fr0_op(env, GETPC());
+    update_fr0_cmp(env, y, c, r);
+}
+
+float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
+{
+    float32 ret = float32_muladd(a, b, c, 0, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c)
+{
+    float32 ret = float32_muladd(a, b, c, float_muladd_negate_product,
+                                 &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
+{
+    float64 ret = float64_muladd(a, b, c, 0, &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
+
+float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c)
+{
+    float64 ret = float64_muladd(a, b, c, float_muladd_negate_product,
+                                 &env->fp_status);
+    update_fr0_op(env, GETPC());
+    return ret;
+}
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index cfdb9ee..4d243f7 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -85,6 +85,12 @@ typedef struct DisasInsn {
                         const struct DisasInsn *f);
     union {
         void (*f_ttt)(TCGv, TCGv, TCGv);
+        void (*f_weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32);
+        void (*f_dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64);
+        void (*f_wew)(TCGv_i32, TCGv_env, TCGv_i32);
+        void (*f_ded)(TCGv_i64, TCGv_env, TCGv_i64);
+        void (*f_wed)(TCGv_i32, TCGv_env, TCGv_i64);
+        void (*f_dew)(TCGv_i64, TCGv_env, TCGv_i32);
     };
 } DisasInsn;
 
@@ -295,6 +301,28 @@ static TCGv_i32 load_frw_i32(unsigned rt)
     return ret;
 }
 
+static TCGv_i32 load_frw0_i32(unsigned rt)
+{
+    if (rt == 0) {
+        return tcg_const_i32(0);
+    } else {
+        return load_frw_i32(rt);
+    }
+}
+
+static TCGv_i64 load_frw0_i64(unsigned rt)
+{
+    if (rt == 0) {
+        return tcg_const_i64(0);
+    } else {
+        TCGv_i64 ret = tcg_temp_new_i64();
+        tcg_gen_ld32u_i64(ret, cpu_env,
+                          offsetof(CPUHPPAState, fr[rt & 31])
+                          + (rt & 32 ? LO_OFS : HI_OFS));
+        return ret;
+    }
+}
+
 static void save_frw_i32(unsigned rt, TCGv_i32 val)
 {
     tcg_gen_st_i32(val, cpu_env,
@@ -312,6 +340,15 @@ static TCGv_i64 load_frd(unsigned rt)
     return ret;
 }
 
+static TCGv_i64 load_frd0(unsigned rt)
+{
+    if (rt == 0) {
+        return tcg_const_i64(0);
+    } else {
+        return load_frd(rt);
+    }
+}
+
 static void save_frd(unsigned rt, TCGv_i64 val)
 {
     tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt]));
@@ -494,6 +531,35 @@ static target_long low_sextract(uint32_t val, int pos, int len)
     return x;
 }
 
+static unsigned assemble_rt64(uint32_t insn)
+{
+    unsigned r1 = extract32(insn, 6, 1);
+    unsigned r0 = extract32(insn, 0, 5);
+    return r1 * 32 + r0;
+}
+
+static unsigned assemble_ra64(uint32_t insn)
+{
+    unsigned r1 = extract32(insn, 7, 1);
+    unsigned r0 = extract32(insn, 21, 5);
+    return r1 * 32 + r0;
+}
+
+static unsigned assemble_rb64(uint32_t insn)
+{
+    unsigned r1 = extract32(insn, 12, 1);
+    unsigned r0 = extract32(insn, 16, 5);
+    return r1 * 32 + r0;
+}
+
+static unsigned assemble_rc64(uint32_t insn)
+{
+    unsigned r2 = extract32(insn, 8, 1);
+    unsigned r1 = extract32(insn, 13, 3);
+    unsigned r0 = extract32(insn, 9, 2);
+    return r2 * 32 + r1 * 4 + r0;
+}
+
 static target_long assemble_12(uint32_t insn)
 {
     target_ulong x = -(target_ulong)(insn & 1);
@@ -1218,6 +1284,110 @@ static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
     return nullify_end(ctx, NO_EXIT);
 }
 
+static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra,
+                             void (*func)(TCGv_i32, TCGv_env, TCGv_i32))
+{
+    TCGv_i32 tmp;
+
+    nullify_over(ctx);
+    tmp = load_frw0_i32(ra);
+
+    func(tmp, cpu_env, tmp);
+
+    save_frw_i32(rt, tmp);
+    tcg_temp_free_i32(tmp);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra,
+                             void (*func)(TCGv_i32, TCGv_env, TCGv_i64))
+{
+    TCGv_i32 dst;
+    TCGv_i64 src;
+
+    nullify_over(ctx);
+    src = load_frd(ra);
+    dst = tcg_temp_new_i32();
+
+    func(dst, cpu_env, src);
+
+    tcg_temp_free_i64(src);
+    save_frw_i32(rt, dst);
+    tcg_temp_free_i32(dst);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra,
+                             void (*func)(TCGv_i64, TCGv_env, TCGv_i64))
+{
+    TCGv_i64 tmp;
+
+    nullify_over(ctx);
+    tmp = load_frd0(ra);
+
+    func(tmp, cpu_env, tmp);
+
+    save_frd(rt, tmp);
+    tcg_temp_free_i64(tmp);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra,
+                             void (*func)(TCGv_i64, TCGv_env, TCGv_i32))
+{
+    TCGv_i32 src;
+    TCGv_i64 dst;
+
+    nullify_over(ctx);
+    src = load_frw0_i32(ra);
+    dst = tcg_temp_new_i64();
+
+    func(dst, cpu_env, src);
+
+    tcg_temp_free_i32(src);
+    save_frd(rt, dst);
+    tcg_temp_free_i64(dst);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt,
+                              unsigned ra, unsigned rb,
+                              void (*func)(TCGv_i32, TCGv_env,
+                                           TCGv_i32, TCGv_i32))
+{
+    TCGv_i32 a, b;
+
+    nullify_over(ctx);
+    a = load_frw0_i32(ra);
+    b = load_frw0_i32(rb);
+
+    func(a, cpu_env, a, b);
+
+    tcg_temp_free_i32(b);
+    save_frw_i32(rt, a);
+    tcg_temp_free_i32(a);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt,
+                              unsigned ra, unsigned rb,
+                              void (*func)(TCGv_i64, TCGv_env,
+                                           TCGv_i64, TCGv_i64))
+{
+    TCGv_i64 a, b;
+
+    nullify_over(ctx);
+    a = load_frd0(ra);
+    b = load_frd0(rb);
+
+    func(a, cpu_env, a, b);
+
+    tcg_temp_free_i64(b);
+    save_frd(rt, a);
+    tcg_temp_free_i64(a);
+    return nullify_end(ctx, NO_EXIT);
+}
+
 /* Emit an unconditional branch to a direct target, which may or may not
    have already had nullification handled.  */
 static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
@@ -2893,6 +3063,554 @@ static const DisasInsn table_branch[] = {
     { 0xe800d000u, 0xfc00dffcu, trans_bve },
 };
 
+static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_wew(ctx, rt, ra, di->f_wew);
+}
+
+static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = assemble_rt64(insn);
+    unsigned ra = assemble_ra64(insn);
+    return do_fop_wew(ctx, rt, ra, di->f_wew);
+}
+
+static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn,
+                                const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_ded(ctx, rt, ra, di->f_ded);
+}
+
+static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_wed(ctx, rt, ra, di->f_wed);
+}
+
+static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = assemble_rt64(insn);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_wed(ctx, rt, ra, di->f_wed);
+}
+
+static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_dew(ctx, rt, ra, di->f_dew);
+}
+
+static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned ra = assemble_ra64(insn);
+    return do_fop_dew(ctx, rt, ra, di->f_dew);
+}
+
+static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn,
+                                    const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned rb = extract32(insn, 16, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_weww(ctx, rt, ra, rb, di->f_weww);
+}
+
+static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn,
+                                    const DisasInsn *di)
+{
+    unsigned rt = assemble_rt64(insn);
+    unsigned rb = assemble_rb64(insn);
+    unsigned ra = assemble_ra64(insn);
+    return do_fop_weww(ctx, rt, ra, rb, di->f_weww);
+}
+
+static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn,
+                                 const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned rb = extract32(insn, 16, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fop_dedd(ctx, rt, ra, rb, di->f_dedd);
+}
+
+static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
+{
+    tcg_gen_mov_i32(dst, src);
+}
+
+static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
+{
+    tcg_gen_mov_i64(dst, src);
+}
+
+static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
+{
+    tcg_gen_andi_i32(dst, src, INT32_MAX);
+}
+
+static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
+{
+    tcg_gen_andi_i64(dst, src, INT64_MAX);
+}
+
+static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
+{
+    tcg_gen_xori_i32(dst, src, INT32_MIN);
+}
+
+static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
+{
+    tcg_gen_xori_i64(dst, src, INT64_MIN);
+}
+
+static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src)
+{
+    tcg_gen_ori_i32(dst, src, INT32_MIN);
+}
+
+static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src)
+{
+    tcg_gen_ori_i64(dst, src, INT64_MIN);
+}
+
+static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb,
+                            unsigned y, unsigned c)
+{
+    TCGv_i32 ta, tb, tc, ty;
+
+    nullify_over(ctx);
+
+    ta = load_frw0_i32(ra);
+    tb = load_frw0_i32(rb);
+    ty = tcg_const_i32(y);
+    tc = tcg_const_i32(c);
+
+    gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc);
+
+    tcg_temp_free_i32(ta);
+    tcg_temp_free_i32(tb);
+    tcg_temp_free_i32(ty);
+    tcg_temp_free_i32(tc);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn,
+                                  const DisasInsn *di)
+{
+    unsigned c = extract32(insn, 0, 5);
+    unsigned y = extract32(insn, 13, 3);
+    unsigned rb = extract32(insn, 16, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    return do_fcmp_s(ctx, ra, rb, y, c);
+}
+
+static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn,
+                                  const DisasInsn *di)
+{
+    unsigned c = extract32(insn, 0, 5);
+    unsigned y = extract32(insn, 13, 3);
+    unsigned rb = assemble_rb64(insn);
+    unsigned ra = assemble_ra64(insn);
+    return do_fcmp_s(ctx, ra, rb, y, c);
+}
+
+static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn,
+                               const DisasInsn *di)
+{
+    unsigned c = extract32(insn, 0, 5);
+    unsigned y = extract32(insn, 13, 3);
+    unsigned rb = extract32(insn, 16, 5);
+    unsigned ra = extract32(insn, 21, 5);
+    TCGv_i64 ta, tb;
+    TCGv_i32 tc, ty;
+
+    nullify_over(ctx);
+
+    ta = load_frd0(ra);
+    tb = load_frd0(rb);
+    ty = tcg_const_i32(y);
+    tc = tcg_const_i32(c);
+
+    gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc);
+
+    tcg_temp_free_i64(ta);
+    tcg_temp_free_i64(tb);
+    tcg_temp_free_i32(ty);
+    tcg_temp_free_i32(tc);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn,
+                                const DisasInsn *di)
+{
+    unsigned y = extract32(insn, 13, 3);
+    unsigned cbit = (y ^ 1) - 1;
+    TCGv t;
+
+    nullify_over(ctx);
+
+    t = tcg_temp_new();
+    tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
+    tcg_gen_extract_tl(t, t, 21 - cbit, 1);
+    ctx->null_cond = cond_make_0(TCG_COND_NE, t);
+    tcg_temp_free(t);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn,
+                                const DisasInsn *di)
+{
+    unsigned c = extract32(insn, 0, 5);
+    int mask;
+    bool inv = false;
+    TCGv t;
+
+    nullify_over(ctx);
+
+    t = tcg_temp_new();
+    tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow));
+
+    switch (c) {
+    case 0: /* simple */
+        tcg_gen_andi_tl(t, t, 0x4000000);
+        ctx->null_cond = cond_make_0(TCG_COND_NE, t);
+        goto done;
+    case 2: /* rej */
+        inv = true;
+        /* fallthru */
+    case 1: /* acc */
+        mask = 0x43ff800;
+        break;
+    case 6: /* rej8 */
+        inv = true;
+        /* fallthru */
+    case 5: /* acc8 */
+        mask = 0x43f8000;
+        break;
+    case 9: /* acc6 */
+        mask = 0x43e0000;
+        break;
+    case 13: /* acc4 */
+        mask = 0x4380000;
+        break;
+    case 17: /* acc2 */
+        mask = 0x4200000;
+        break;
+    default:
+        return gen_illegal(ctx);
+    }
+    if (inv) {
+        TCGv c = load_const(ctx, mask);
+        tcg_gen_or_tl(t, t, c);
+        ctx->null_cond = cond_make(TCG_COND_EQ, t, c);
+    } else {
+        tcg_gen_andi_tl(t, t, mask);
+        ctx->null_cond = cond_make_0(TCG_COND_EQ, t);
+    }
+ done:
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn,
+                              const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned rb = assemble_rb64(insn);
+    unsigned ra = assemble_ra64(insn);
+    TCGv_i64 a, b;
+
+    nullify_over(ctx);
+
+    a = load_frw0_i64(ra);
+    b = load_frw0_i64(rb);
+    tcg_gen_mul_i64(a, a, b);
+    save_frd(rt, a);
+    tcg_temp_free_i64(a);
+    tcg_temp_free_i64(b);
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+#define FOP_DED  trans_fop_ded, .f_ded
+#define FOP_DEDD trans_fop_dedd, .f_dedd
+
+#define FOP_WEW  trans_fop_wew_0c, .f_wew
+#define FOP_DEW  trans_fop_dew_0c, .f_dew
+#define FOP_WED  trans_fop_wed_0c, .f_wed
+#define FOP_WEWW trans_fop_weww_0c, .f_weww
+
+static const DisasInsn table_float_0c[] = {
+    /* floating point class zero */
+    { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s },
+    { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s },
+    { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s },
+    { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s },
+    { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s },
+    { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s },
+
+    { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
+    { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
+    { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
+    { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
+    { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
+    { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
+
+    /* floating point class three */
+    { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s },
+    { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s },
+    { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s },
+    { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s },
+
+    { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
+    { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
+    { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
+    { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
+
+    /* floating point class one */
+    /* float/float */
+    { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s },
+    { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d },
+    /* int/float */
+    { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s },
+    { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s },
+    { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d },
+    { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
+    /* float/int */
+    { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w },
+    { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w },
+    { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw },
+    { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
+    /* float/int truncate */
+    { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w },
+    { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w },
+    { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw },
+    { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
+    /* uint/float */
+    { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s },
+    { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s },
+    { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d },
+    { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
+    /* float/uint */
+    { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw },
+    { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw },
+    { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw },
+    { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
+    /* float/uint truncate */
+    { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw },
+    { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw },
+    { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw },
+    { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
+
+    /* floating point class two */
+    { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c },
+    { 0x30000c00, 0xfc001fe0, trans_fcmp_d },
+    { 0x30002420, 0xffffffe0, trans_ftest_q },
+    { 0x30000420, 0xffff1fff, trans_ftest_t },
+
+    /* FID.  Note that ra == rt == 0, which via fcpy puts 0 into fr0.
+       This is machine/revision == 0, which is reserved for simulator.  */
+    { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s },
+};
+
+#undef FOP_WEW
+#undef FOP_DEW
+#undef FOP_WED
+#undef FOP_WEWW
+#define FOP_WEW  trans_fop_wew_0e, .f_wew
+#define FOP_DEW  trans_fop_dew_0e, .f_dew
+#define FOP_WED  trans_fop_wed_0e, .f_wed
+#define FOP_WEWW trans_fop_weww_0e, .f_weww
+
+static const DisasInsn table_float_0e[] = {
+    /* floating point class zero */
+    { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s },
+    { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s },
+    { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s },
+    { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s },
+    { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s },
+    { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s },
+
+    { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d },
+    { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d },
+    { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d },
+    { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d },
+    { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d },
+    { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d },
+
+    /* floating point class three */
+    { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s },
+    { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s },
+    { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s },
+    { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s },
+
+    { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d },
+    { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d },
+    { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d },
+    { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d },
+
+    { 0x38004700, 0xfc00ef60, trans_xmpyu },
+
+    /* floating point class one */
+    /* float/float */
+    { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s },
+    { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d },
+    /* int/float */
+    { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s },
+    { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s },
+    { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d },
+    { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d },
+    /* float/int */
+    { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w },
+    { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w },
+    { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw },
+    { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw },
+    /* float/int truncate */
+    { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w },
+    { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w },
+    { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw },
+    { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw },
+    /* uint/float */
+    { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s },
+    { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s },
+    { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d },
+    { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d },
+    /* float/uint */
+    { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw },
+    { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw },
+    { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw },
+    { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw },
+    /* float/uint truncate */
+    { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw },
+    { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw },
+    { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw },
+    { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw },
+
+    /* floating point class two */
+    { 0x38000400, 0xfc000f60, trans_fcmp_s_0e },
+    { 0x38000c00, 0xfc001fe0, trans_fcmp_d },
+};
+
+#undef FOP_WEW
+#undef FOP_DEW
+#undef FOP_WED
+#undef FOP_WEWW
+#undef FOP_DED
+#undef FOP_DEDD
+
+/* Convert the fmpyadd single-precision register encodings to standard.  */
+static inline int fmpyadd_s_reg(unsigned r)
+{
+    return (r & 16) * 2 + 16 + (r & 15);
+}
+
+static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub)
+{
+    unsigned tm = extract32(insn, 0, 5);
+    unsigned f = extract32(insn, 5, 1);
+    unsigned ra = extract32(insn, 6, 5);
+    unsigned ta = extract32(insn, 11, 5);
+    unsigned rm2 = extract32(insn, 16, 5);
+    unsigned rm1 = extract32(insn, 21, 5);
+
+    nullify_over(ctx);
+
+    /* Independent multiply & add/sub, with undefined behaviour
+       if outputs overlap inputs.  */
+    if (f == 0) {
+        tm = fmpyadd_s_reg(tm);
+        ra = fmpyadd_s_reg(ra);
+        ta = fmpyadd_s_reg(ta);
+        rm2 = fmpyadd_s_reg(rm2);
+        rm1 = fmpyadd_s_reg(rm1);
+        do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s);
+        do_fop_weww(ctx, ta, ta, ra,
+                    is_sub ? gen_helper_fsub_s : gen_helper_fadd_s);
+    } else {
+        do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d);
+        do_fop_dedd(ctx, ta, ta, ra,
+                    is_sub ? gen_helper_fsub_d : gen_helper_fadd_d);
+    }
+
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = assemble_rt64(insn);
+    unsigned neg = extract32(insn, 5, 1);
+    unsigned rm1 = assemble_ra64(insn);
+    unsigned rm2 = assemble_rb64(insn);
+    unsigned ra3 = assemble_rc64(insn);
+    TCGv_i32 a, b, c;
+
+    nullify_over(ctx);
+    a = load_frw0_i32(rm1);
+    b = load_frw0_i32(rm2);
+    c = load_frw0_i32(ra3);
+
+    if (neg) {
+        gen_helper_fmpynfadd_s(a, cpu_env, a, b, c);
+    } else {
+        gen_helper_fmpyfadd_s(a, cpu_env, a, b, c);
+    }
+
+    tcg_temp_free_i32(b);
+    tcg_temp_free_i32(c);
+    save_frw_i32(rt, a);
+    tcg_temp_free_i32(a);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn,
+                                   const DisasInsn *di)
+{
+    unsigned rt = extract32(insn, 0, 5);
+    unsigned neg = extract32(insn, 5, 1);
+    unsigned rm1 = extract32(insn, 21, 5);
+    unsigned rm2 = extract32(insn, 16, 5);
+    unsigned ra3 = assemble_rc64(insn);
+    TCGv_i64 a, b, c;
+
+    nullify_over(ctx);
+    a = load_frd0(rm1);
+    b = load_frd0(rm2);
+    c = load_frd0(ra3);
+
+    if (neg) {
+        gen_helper_fmpynfadd_d(a, cpu_env, a, b, c);
+    } else {
+        gen_helper_fmpyfadd_d(a, cpu_env, a, b, c);
+    }
+
+    tcg_temp_free_i64(b);
+    tcg_temp_free_i64(c);
+    save_frd(rt, a);
+    tcg_temp_free_i64(a);
+    return nullify_end(ctx, NO_EXIT);
+}
+
+static const DisasInsn table_fp_fused[] = {
+    { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s },
+    { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d }
+};
+
 static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
                                       const DisasInsn table[], size_t n)
 {
@@ -2921,6 +3639,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return translate_table(ctx, insn, table_arith_log);
     case 0x03:
         return translate_table(ctx, insn, table_index_mem);
+    case 0x06:
+        return trans_fmpyadd(ctx, insn, false);
     case 0x08:
         return trans_ldil(ctx, insn);
     case 0x09:
@@ -2929,8 +3649,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_addil(ctx, insn);
     case 0x0B:
         return trans_copr_dw(ctx, insn);
+    case 0x0C:
+        return translate_table(ctx, insn, table_float_0c);
     case 0x0D:
         return trans_ldo(ctx, insn);
+    case 0x0E:
+        return translate_table(ctx, insn, table_float_0e);
 
     case 0x10:
         return trans_load(ctx, insn, false, MO_UB);
@@ -2969,6 +3693,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
         return trans_cmpiclr(ctx, insn);
     case 0x25:
         return trans_subi(ctx, insn);
+    case 0x26:
+        return trans_fmpyadd(ctx, insn, true);
     case 0x27:
         return trans_cmpb(ctx, insn, true, false, true);
     case 0x28:
@@ -2982,6 +3708,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
     case 0x2C:
     case 0x2D:
         return trans_addi(ctx, insn);
+    case 0x2E:
+        return translate_table(ctx, insn, table_fp_fused);
     case 0x2F:
         return trans_cmpb(ctx, insn, false, false, true);
 
-- 
2.9.3

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

* Re: [Qemu-devel] [PULL 00/26] New hppa-linux target support
  2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
                   ` (24 preceding siblings ...)
  2017-01-23  2:17 ` [Qemu-devel] [PULL 26/26] target-hppa: Implement floating-point insns Richard Henderson
@ 2017-01-23 10:31 ` Peter Maydell
  25 siblings, 0 replies; 32+ messages in thread
From: Peter Maydell @ 2017-01-23 10:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU Developers

On 23 January 2017 at 02:17, Richard Henderson <rth@twiddle.net> wrote:
> This is a linux-user only port, emulating a 32-bit only version of a
> pa-2.0 cpu.  This is good enough to do well with both the gcc and glibc
> testsuites.  Helge Deller has provided invaluable assistance testing
> with a more complete debian chroot.
>
> What's missing:
>   * Space registers.  Since Linux sets them all equal (for a flat
>     address space) and uses them like address-space identifiers,
>     we can simply set them all to 0 and ignore them.
>
>   * Architecture subsets.  There's no markup for running a pure pa1.0
>     or pa1.1 cpu.  I happily accept everything up to pa2.0 at the moment.
>
>   * Wide mode.  While I have pa2.0 instructions, I don't support running
>     in 64-bit mode.  Since neither the linux kernel nor glibc support a
>     64-bit userland, it would be a lot more work than just adding the insns.
>
>   * Multimedia instructions.  These are tied to wide mode, so...
>
> When squashing the patches down from my development tree, I wanted to
> preserve Helge's contributions, so the linux-user part is more patches
> than I would normally have preserved.
>
>
> r~
>
>
>
> The following changes since commit d1c82f7cc34443841095f490345f86c9d8baca34:
>
>   Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170120-v2' into staging (2017-01-20 15:53:58 +0000)
>
> are available in the git repository at:
>
>   git://github.com/rth7680/qemu.git tags/pull-hppa-20170122
>
> for you to fetch changes up to 0ce588d6c60c338c0856b0dac78d19fc7e698477:
>
>   target-hppa: Implement floating-point insns (2017-01-22 18:14:12 -0800)
>
> ----------------------------------------------------------------
> hppa-linux target support
>

Hi; I'm afraid this fails to build on a couple of my test hosts:

PPC64BE host, arm32, aarch64 host:
/home/pm215/qemu/linux-user/syscall.c: In function ‘do_setsockopt’:
/home/pm215/qemu/linux-user/syscall.c:2827:14: error:
‘IPV6_RECVPATHMTU’ undeclared (first use in this function)
         case IPV6_RECVPATHMTU:
              ^
/home/pm215/qemu/linux-user/syscall.c:2827:14: note: each undeclared
identifier is reported only once for each function it appears in
/home/pm215/qemu/linux-user/syscall.c:2828:14: error:
‘IPV6_TRANSPARENT’ undeclared (first use in this function)
         case IPV6_TRANSPARENT:
              ^
/home/pm215/qemu/linux-user/syscall.c:2829:14: error:
‘IPV6_RECVORIGDSTADDR’ undeclared (first use in this function)
         case IPV6_RECVORIGDSTADDR:
              ^
/home/pm215/qemu/linux-user/syscall.c:2833:14: error:
‘IPV6_UNICAST_IF’ undeclared (first use in this function)
         case IPV6_UNICAST_IF:
              ^
/home/pm215/qemu/linux-user/syscall.c:2839:14: error:
‘IPV6_ADDR_PREFERENCES’ undeclared (first use in this function)
         case IPV6_ADDR_PREFERENCES:
              ^
/home/pm215/qemu/linux-user/syscall.c:2840:14: error:
‘IPV6_MINHOPCOUNT’ undeclared (first use in this function)
         case IPV6_MINHOPCOUNT:
              ^
/home/pm215/qemu/linux-user/syscall.c:2841:14: error: ‘IPV6_DONTFRAG’
undeclared (first use in this function)
         case IPV6_DONTFRAG:
              ^
/home/pm215/qemu/linux-user/syscall.c:2842:14: error:
‘IPV6_AUTOFLOWLABEL’ undeclared (first use in this function)
         case IPV6_AUTOFLOWLABEL:
              ^

(same for all targets).

Looking at the systems in question these constants are #defined
in /usr/include/linux/in6.h. The difference from the working x86
host is I think that x86 also defines them in
/usr/include/x86-64-linux-gnu/bits/in.h.
Presumably they're being implicitly dragged in by some other header
and we need to explicitly #include something instead. I'm
not sure what, though.

thanks
-- PMM

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

* Re: [Qemu-devel] [PULL 21/26] target-hppa: Implement branches
  2017-01-23  2:17 ` [Qemu-devel] [PULL 21/26] target-hppa: Implement branches Richard Henderson
@ 2017-01-26 12:14   ` Paolo Bonzini
  2017-01-26 17:18     ` Richard Henderson
  0 siblings, 1 reply; 32+ messages in thread
From: Paolo Bonzini @ 2017-01-26 12:14 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: peter.maydell

I haven't studied the code much, so I'm just reporting what Coverity
says.  Not sure if the code has a bug or can just be simplified.

On 23/01/2017 03:17, Richard Henderson wrote:
> +/* Emit a conditional branch to a direct target.  If the branch itself
> +   is nullified, we should have already used nullify_over.  */
> +static ExitStatus do_cbranch(DisasContext *ctx, target_long disp, bool is_n,
> +                             DisasCond *cond)
> +{
> +    target_ulong dest = iaoq_dest(ctx, disp);
> +    TCGLabel *taken = NULL;
> +    TCGCond c = cond->c;
> +    int which = 0;
> +    bool n;
> +
> +    assert(ctx->null_cond.c == TCG_COND_NEVER);
> +
> +    /* Handle TRUE and NEVER as direct branches.  */
> +    if (c == TCG_COND_ALWAYS) {
> +        return do_dbranch(ctx, dest, 0, is_n && disp >= 0);
> +    }
> +    if (c == TCG_COND_NEVER) {
> +        return do_dbranch(ctx, ctx->iaoq_n, 0, is_n && disp < 0);
> +    }
> +
> +    taken = gen_new_label();
> +    cond_prep(cond);
> +    tcg_gen_brcond_tl(c, cond->a0, cond->a1, taken);
> +    cond_free(cond);
> +
> +    /* Not taken: Condition not satisfied; nullify on backward branches. */
> +    n = is_n && disp < 0;
> +    if (n && use_nullify_skip(ctx)) {
> +        nullify_set(ctx, 0);
> +        gen_goto_tb(ctx, which++, ctx->iaoq_n, ctx->iaoq_n + 4);
> +    } else {
> +        if (!n && ctx->null_lab) {
> +            gen_set_label(ctx->null_lab);
> +            ctx->null_lab = NULL;
> +        }
> +        nullify_set(ctx, n);
> +        gen_goto_tb(ctx, which++, ctx->iaoq_b, ctx->iaoq_n);
> +    }

Both branches increment "which", so you can replace it with 0 and which
is always 1 now.

> +    gen_set_label(taken);
> +
> +    /* Taken: Condition satisfied; nullify on forward branches.  */
> +    n = is_n && disp >= 0;
> +    if (n && use_nullify_skip(ctx)) {
> +        nullify_set(ctx, 0);
> +        gen_goto_tb(ctx, which++, dest, dest + 4);
> +    } else {
> +        nullify_set(ctx, n);
> +        gen_goto_tb(ctx, which++, ctx->iaoq_b, dest);
> +    }

Both branches increment "which", so you can replace it with 1 and which
is always 2.

> +    /* Not taken: the branch itself was nullified.  */
> +    if (ctx->null_lab) {
> +        gen_set_label(ctx->null_lab);
> +        ctx->null_lab = NULL;
> +        if (which < 2) {
> +            nullify_set(ctx, 0);
> +            gen_goto_tb(ctx, which, ctx->iaoq_b, ctx->iaoq_n);
> +            return EXIT_GOTO_TB;

So this branch of the "if" is dead.

> +        } else {
> +            return EXIT_IAQ_N_STALE;
> +        }
> +    } else {
> +        return EXIT_GOTO_TB;
> +    }
> +}

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

* Re: [Qemu-devel] [PULL 21/26] target-hppa: Implement branches
  2017-01-26 12:14   ` Paolo Bonzini
@ 2017-01-26 17:18     ` Richard Henderson
  0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-01-26 17:18 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel; +Cc: peter.maydell

On 01/26/2017 04:14 AM, Paolo Bonzini wrote:
> I haven't studied the code much, so I'm just reporting what Coverity
> says.  Not sure if the code has a bug or can just be simplified.

It looks like it can be simplified.

I'm sure at one point in the development, "which" was not a constant like that.


r~

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

* Re: [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation
  2017-01-23  2:17 ` [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation Richard Henderson
@ 2017-01-30 13:49   ` Peter Maydell
  2017-02-07  2:27     ` Richard Henderson
  0 siblings, 1 reply; 32+ messages in thread
From: Peter Maydell @ 2017-01-30 13:49 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU Developers

On 23 January 2017 at 02:17, Richard Henderson <rth@twiddle.net> wrote:
> This is just about the minimum required to enable compilation
> without actually executing any instructions.  This contains the
> HPPACPU structure and the required callbacks, the gdbstub, the
> basic translation loop, and a translate_one function that always
> results in an illegal instruction.
>
> Signed-off-by: Richard Henderson <rth@twiddle.net>

> --- /dev/null
> +++ b/target/hppa/gdbstub.c
> @@ -0,0 +1,111 @@
> +/*
> + * HPPA gdb server stub

> +int hppa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
> +{
> +    HPPACPU *cpu = HPPA_CPU(cs);
> +    CPUHPPAState *env = &cpu->env;
> +    target_ulong val = ldtul_p(mem_buf);
> +
> +    switch (n) {
> +    case 0:
> +        cpu_hppa_put_psw(env, val);
> +        break;
> +    case 1 ... 31:
> +        env->gr[n] = val;
> +        break;
> +    case 32:
> +        env->sar = val;
> +        break;
> +    case 33:
> +        env->iaoq_f = val;
> +        break;
> +    case 35:
> +        env->iaoq_b = val;

Is this a missing "break;" or a missing "/* fall through */" ?

(spotted by Coverity, CID 1369420.)

> +    case 59:
> +        env->cr26 = val;
> +        break;
> +    case 60:
> +        env->cr27 = val;
> +        break;
> +    case 64:
> +        env->fr[0] = deposit64(env->fr[0], 32, 32, val);
> +        cpu_hppa_loaded_fr0(env);
> +        break;
> +    case 65 ... 127:
> +        {
> +            uint64_t *fr = &env->fr[(n - 64) / 2];
> +            *fr = deposit64(*fr, val, (n & 1 ? 0 : 32), 32);
> +        }
> +        break;
> +    default:
> +        if (n >= 128) {
> +            return 0;
> +        }
> +        break;
> +    }
> +    return sizeof(target_ulong);
> +})

thanks
-- PMM

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

* Re: [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation
  2017-01-30 13:49   ` Peter Maydell
@ 2017-02-07  2:27     ` Richard Henderson
  0 siblings, 0 replies; 32+ messages in thread
From: Richard Henderson @ 2017-02-07  2:27 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers

On 01/30/2017 05:49 AM, Peter Maydell wrote:
>> +    case 35:
>> +        env->iaoq_b = val;
>
> Is this a missing "break;" or a missing "/* fall through */" ?

Yep, thanks.


r~

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

* Re: [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c
  2017-01-23  2:17 ` [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c Richard Henderson
@ 2017-06-27 16:32   ` Peter Maydell
  0 siblings, 0 replies; 32+ messages in thread
From: Peter Maydell @ 2017-06-27 16:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: QEMU Developers

On 23 January 2017 at 02:17, Richard Henderson <rth@twiddle.net> wrote:
> HPPA is a (the) stack-grows-up target, and supporting that requires
> rearranging how we compute addresses while laying out the initial
> program stack.  In addition, hppa32 requires 64-byte stack alignment
> so parameterize that as well.

>  #define NEW_AUX_ENT(id, val) do {               \
> -        sp -= n; put_user_ual(val, sp);         \
> -        sp -= n; put_user_ual(id, sp);          \
> +        put_user_ual(id, u_auxv);  u_auxv += n; \
> +        put_user_ual(val, u_auxv); u_auxv += n; \
>      } while(0)

I've just noticed that this change breaks powerpc32, because now
we fill in the auxv starting at the lowest address and working
up, rather than starting at the highest address and working down.
powerpc32 needs some magic values at the lowest address, which
we deal with in ARCH_DLINFO. So now we need to invoke ARCH_DLINFO
first, rather than last (the kernel also fills auxv in from
low to high and invokes ARCH_DLINFO first). The PPC ARCH_DLINFO
also needs to have its entries reversed so the AT_IGNOREPPC
entries come first (lowest address).

The effect of this bug is that my ppc test program
(which is one of the ones in the ancient collection on the
wiki: http://wiki.qemu.org/download/linux-user-test-0.3.tar.gz )
segfaults on startup if the environment is the wrong size:

e104462:xenial:linux-user-test-0.3$ X=1
/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/ppc-linux-user/qemu-ppc
-L ./gnemul/qemu-ppc ppc/ls -l dummyfile
-rw-r--r--    1 petmay01 petmay01        0 Nov 12  2007 dummyfile
e104462:xenial:linux-user-test-0.3$ X=1 Y=1
/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/ppc-linux-user/qemu-ppc
-L ./gnemul/qemu-ppc ppc/ls -l dummyfile
-rw-r--r--    1 petmay01 petmay01        0 Nov 12  2007 dummyfile
e104462:xenial:linux-user-test-0.3$ X=1 Y=1 Z=1
/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/ppc-linux-user/qemu-ppc
-L ./gnemul/qemu-ppc ppc/ls -l dummyfile
-rw-r--r--    1 petmay01 petmay01        0 Nov 12  2007 dummyfile
e104462:xenial:linux-user-test-0.3$ X=1 Y=1 Z=1 A=1
/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/ppc-linux-user/qemu-ppc
-L ./gnemul/qemu-ppc ppc/ls -l dummyfile
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
Segmentation fault (core dumped)
e104462:xenial:linux-user-test-0.3$ X=1 Y=1 Z=1 A=1 B=1
/home/petmay01/linaro/qemu-for-merges/build/all-linux-static/ppc-linux-user/qemu-ppc
-L ./gnemul/qemu-ppc ppc/ls -l dummyfile
-rw-r--r--    1 petmay01 petmay01        0 Nov 12  2007 dummyfile

(exactly which 1 out of 4 will fail for you will depend
on the size of your environment, etc, obviously.)

Newer ppc binaries which have glibc versions that dropped
that attempt to handle alignment won't trip over this,
only older ones.

thanks
-- PMM

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

end of thread, other threads:[~2017-06-27 16:54 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-23  2:17 [Qemu-devel] [PULL 00/26] New hppa-linux target support Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 01/26] Revert "Remove remainders of HPPA backend" Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 02/26] linux-user: Support stack-grows-up in elfload.c Richard Henderson
2017-06-27 16:32   ` Peter Maydell
2017-01-23  2:17 ` [Qemu-devel] [PULL 03/26] linux-user: Handle TIOCSTART and TIOCSTOP Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 04/26] linux-user: Add SIOCGPGRP, SIOCGSTAMP, SIOCGSTAMPNS Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 05/26] linux-user: Handle ERFKILL and EHWPOISON Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 06/26] linux-user: Handle more IPV6 sockopts Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 08/26] linux-user: Add HPPA socket.h definitions Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 09/26] linux-user: Add HPPA syscall numbers Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 10/26] linux-user: Add HPPA termbits.h Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 11/26] linux-user: Add HPPA target_syscall.h Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 12/26] linux-user: Add HPPA definitions to syscall_defs.h Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 13/26] linux-user: Add HPPA target_structs.h Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 14/26] linux-user: Add HPPA target_signal.h and target_cpu.h Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 15/26] linux-user: Add HPPA signal handling Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 16/26] linux-user: Add HPPA startup and main loop Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 17/26] target-hppa: Add softfloat specializations Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 18/26] target-hppa: Add framework and enable compilation Richard Henderson
2017-01-30 13:49   ` Peter Maydell
2017-02-07  2:27     ` Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 19/26] target-hppa: Add nullification framework Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 20/26] target-hppa: Implement basic arithmetic Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 21/26] target-hppa: Implement branches Richard Henderson
2017-01-26 12:14   ` Paolo Bonzini
2017-01-26 17:18     ` Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 22/26] target-hppa: Implement linux-user gateway page Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 23/26] target-hppa: Implement shifts and deposits Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 24/26] target-hppa: Implement loads and stores Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 25/26] target-hppa: Implement system and memory-management insns Richard Henderson
2017-01-23  2:17 ` [Qemu-devel] [PULL 26/26] target-hppa: Implement floating-point insns Richard Henderson
2017-01-23 10:31 ` [Qemu-devel] [PULL 00/26] New hppa-linux target support Peter Maydell

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.