summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schwab <schwab@redhat.com>2009-08-25 18:31:56 +0200
committerAndreas Schwab <schwab@redhat.com>2009-08-25 19:31:17 +0200
commitbc9dd948ffc9cf1992d3e77e753789ab897e3dc6 (patch)
tree160b3fff25473e9394274f8655af2183551902ff
parent9aadad69ed7b1a24947f8d5cf878f94096317f81 (diff)
Add emulation of popcntb.
-rw-r--r--fedora/power6emul.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/fedora/power6emul.c b/fedora/power6emul.c
index f1d0d20e0f..1b0187bddd 100644
--- a/fedora/power6emul.c
+++ b/fedora/power6emul.c
@@ -163,6 +163,25 @@ asm (".globl frip, friz, frin, frim\n.hidden frip, friz, frin, frim\n\t"
"3:" "mtfsf 0x01,11\n\t"
"blr\n");
+#ifdef __powerpc64__
+#define m1 0x5555555555555555L
+#define m2 0x3333333333333333L
+#define m3 0x0f0f0f0f0f0f0f0fL
+#else
+#define m1 0x55555555
+#define m2 0x33333333
+#define m3 0x0f0f0f0f
+#endif
+
+static inline unsigned long
+popcntb (unsigned long n)
+{
+ n -= (n >> 1) & m1;
+ n = (n & m2) + ((n >> 2) & m2);
+ n = (n + (n >> 4)) & m3;
+ return n;
+}
+
static void
catch_sigill (int signal, struct sigcontext *ctx)
{
@@ -221,6 +240,18 @@ catch_sigill (int signal, struct sigcontext *ctx)
ctx->regs->nip += 4;
return;
}
+ if ((insn & 0xfc00ffff) == 0x7c0000f4) /* popcntb */
+ {
+ unsigned long *regs = (unsigned long *) ctx->regs;
+ unsigned dest = (insn >> 16) & 0x1f;
+ unsigned src = (insn >> 21) & 0x1f;
+ unsigned long res = 0;
+ int i;
+
+ regs[dest] = popcntb (regs[src]);
+ ctx->regs->nip += 4;
+ return;
+ }
struct sigaction sa;
sa.sa_handler = SIG_DFL;