summaryrefslogtreecommitdiff
path: root/sys/arch/sparc64
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2003-07-10 15:26:55 +0000
committerJason Wright <jason@cvs.openbsd.org>2003-07-10 15:26:55 +0000
commiteddea828bf6ae1fa168610d64ed2a0aecb393b22 (patch)
treeeff1a7c984959e50ea29d29705faae7ec18b5cf0 /sys/arch/sparc64
parent4da6f3580efe1cfabdf6dcba5e8fe6dc80911486 (diff)
- working emulation for POPC instruction
- good start are fully decoding LDQF(A)/STQF(A)
Diffstat (limited to 'sys/arch/sparc64')
-rw-r--r--sys/arch/sparc64/include/cpu.h5
-rw-r--r--sys/arch/sparc64/sparc64/emul.c63
-rw-r--r--sys/arch/sparc64/sparc64/trap.c11
3 files changed, 72 insertions, 7 deletions
diff --git a/sys/arch/sparc64/include/cpu.h b/sys/arch/sparc64/include/cpu.h
index 58b0864f2b4..9d73cd48b84 100644
--- a/sys/arch/sparc64/include/cpu.h
+++ b/sys/arch/sparc64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.23 2003/07/09 23:56:16 jason Exp $ */
+/* $OpenBSD: cpu.h,v 1.24 2003/07/10 15:26:54 jason Exp $ */
/* $NetBSD: cpu.h,v 1.28 2001/06/14 22:56:58 thorpej Exp $ */
/*
@@ -280,7 +280,8 @@ void kgdb_panic(void);
/* emul.c */
int fixalign(struct proc *, struct trapframe64 *);
int emulinstr(vaddr_t, struct trapframe64 *);
-int emul_qf(int32_t, struct proc *, union sigval);
+int emul_qf(int32_t, struct proc *, union sigval, struct trapframe64 *);
+int emul_popc(int32_t, struct proc *, union sigval, struct trapframe64 *);
/*
*
diff --git a/sys/arch/sparc64/sparc64/emul.c b/sys/arch/sparc64/sparc64/emul.c
index 96fcf536168..52e205a09e0 100644
--- a/sys/arch/sparc64/sparc64/emul.c
+++ b/sys/arch/sparc64/sparc64/emul.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: emul.c,v 1.4 2003/07/09 23:56:16 jason Exp $ */
+/* $OpenBSD: emul.c,v 1.5 2003/07/10 15:26:54 jason Exp $ */
/* $NetBSD: emul.c,v 1.8 2001/06/29 23:58:40 eeh Exp $ */
/*-
@@ -457,14 +457,51 @@ emulinstr(pc, tf)
return 0;
}
+#define SIGN_EXT13(v) (((int64_t)(v) << 51) >> 51)
+
+/*
+ * emulate STQF, STQFA, LDQF, and LDQFA
+ */
int
-emul_qf(int32_t insv, struct proc *p, union sigval sv)
+emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
{
union instr ins;
+ int freg, isload;
+ u_int8_t asi;
+ int64_t addr;
ins.i_int = insv;
+ freg = ins.i_op3.i_rd & ~1;
+ freg |= (ins.i_op3.i_rd & 1) << 5;
+
+ if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA)
+ isload = 1;
+ else
+ isload = 0;
+
+ if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF)
+ asi = ASI_PRIMARY;
+ else if (ins.i_loadstore.i_i) {
+ /* XXX asi = %asi, how do I get %asi here? kill it for now */
+ trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
+ return (0);
+ } else
+ asi = ins.i_asi.i_asi;
+
+ addr = tf->tf_global[ins.i_asi.i_rs1];
+ if (ins.i_loadstore.i_i)
+ addr += SIGN_EXT13(ins.i_simm13.i_simm13);
+ else
+ addr += tf->tf_global[ins.i_asi.i_rs2];
+
+ if ((asi & 0x80) == 0) {
+ /* priviledged asi */
+ trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
+ return (0);
+ }
- if (ins.i_op3.i_rd & 0x20) {
+ if ((freg & 3) != 0) {
+ /* only valid for %fN where N % 4 = 0 */
trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
return (0);
}
@@ -472,3 +509,23 @@ emul_qf(int32_t insv, struct proc *p, union sigval sv)
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
return (0);
}
+
+int
+emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
+{
+ u_int64_t val, ret = 0;
+ union instr ins;
+
+ ins.i_int = insv;
+ if (ins.i_simm13.i_i == 0)
+ val = tf->tf_global[ins.i_asi.i_rs2];
+ else
+ val = SIGN_EXT13(ins.i_simm13.i_simm13);
+
+ for (; val != 0; val >>= 1)
+ if (val & 1)
+ ret++;
+
+ tf->tf_global[ins.i_asi.i_rd] = ret;
+ return (1);
+}
diff --git a/sys/arch/sparc64/sparc64/trap.c b/sys/arch/sparc64/sparc64/trap.c
index 40a7191cd6a..cfeff9e132c 100644
--- a/sys/arch/sparc64/sparc64/trap.c
+++ b/sys/arch/sparc64/sparc64/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.26 2003/07/09 23:56:16 jason Exp $ */
+/* $OpenBSD: trap.c,v 1.27 2003/07/10 15:26:54 jason Exp $ */
/* $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */
/*
@@ -556,7 +556,14 @@ badtrap:
ins.i_op3.i_op3 == IOP3_STQF ||
ins.i_op3.i_op3 == IOP3_LDQFA ||
ins.i_op3.i_op3 == IOP3_STQFA)) {
- if (emul_qf(ins.i_int, p, sv))
+ if (emul_qf(ins.i_int, p, sv, tf))
+ ADVANCE;
+ break;
+ }
+ if (ins.i_any.i_op == IOP_reg &&
+ ins.i_op3.i_op3 == IOP3_POPC &&
+ ins.i_op3.i_rs1 == 0) {
+ if (emul_popc(ins.i_int, p, sv, tf))
ADVANCE;
break;
}