diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2003-07-10 15:26:55 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2003-07-10 15:26:55 +0000 |
commit | eddea828bf6ae1fa168610d64ed2a0aecb393b22 (patch) | |
tree | eff1a7c984959e50ea29d29705faae7ec18b5cf0 /sys/arch/sparc64 | |
parent | 4da6f3580efe1cfabdf6dcba5e8fe6dc80911486 (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.h | 5 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/emul.c | 63 | ||||
-rw-r--r-- | sys/arch/sparc64/sparc64/trap.c | 11 |
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; } |