Blame SPECS/power6emul.c

Packit 172be8
/* Emulate power6 mf[tf]gpr and fri[zpmn] instructions.
Packit 172be8
   Copyright (C) 2006 Red Hat, Inc.
Packit 172be8
   Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
Packit 172be8
Packit 172be8
   This library is free software; you can redistribute it and/or
Packit 172be8
   modify it under the terms of the GNU Lesser General Public
Packit 172be8
   License as published by the Free Software Foundation; either
Packit 172be8
   version 2.1 of the License, or (at your option) any later version.
Packit 172be8
Packit 172be8
   It is distributed in the hope that it will be useful,
Packit 172be8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 172be8
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 172be8
   Lesser General Public License for more details.
Packit 172be8
Packit 172be8
   You should have received a copy of the GNU Lesser General Public
Packit 172be8
   License along with the GNU C Library; if not, write to the Free
Packit 172be8
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
Packit 172be8
   02111-1307 USA.  */
Packit 172be8
Packit 172be8
#include <signal.h>
Packit 172be8
#include <stdio.h>
Packit 172be8
Packit 172be8
extern double frip (double), friz (double), frin (double), frim (double);
Packit 172be8
asm (".globl frip, friz, frin, frim\n.hidden frip, friz, frin, frim\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	".section \".toc\",\"aw\"\n"
Packit 172be8
"8:"	".tc FD_43300000_0[TC],0x4330000000000000\n"
Packit 172be8
"9:"	".tc FD_3fe00000_0[TC],0x3fe0000000000000\n\t"
Packit 172be8
	".previous\n\t"
Packit 172be8
#else
Packit 172be8
	".rodata\n\t"
Packit 172be8
	".align 2\n"
Packit 172be8
"8:"	".long 0x59800000\n"
Packit 172be8
"9:"	".long 0x3f000000\n\t"
Packit 172be8
	".previous\n\t"
Packit 172be8
#endif
Packit 172be8
	"# frip == ceil\n"
Packit 172be8
"frip:"	"mffs    11\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	"lfd     13,8b@toc(2)\n\t"
Packit 172be8
#else
Packit 172be8
	"mflr    11\n\t"
Packit 172be8
	"bcl     20,31,1f\n"
Packit 172be8
"1:"	"mflr    9\n\t"
Packit 172be8
	"addis   9,9,8b-1b@ha\n\t"
Packit 172be8
	"lfs     13,8b-1b@l(9)\n\t"
Packit 172be8
	"mtlr    11\n\t"
Packit 172be8
#endif
Packit 172be8
	"fabs    0,1\n\t"
Packit 172be8
	"fsub    12,13,13\n\t"
Packit 172be8
	"fcmpu   7,0,13\n\t"
Packit 172be8
	"fcmpu   6,1,12\n\t"
Packit 172be8
	"bnllr-  7\n\t"
Packit 172be8
	"mtfsfi  7,2\n\t"
Packit 172be8
	"ble-    6,2f\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fabs    1,1\n\t"
Packit 172be8
	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n"
Packit 172be8
"2:"	"bge-    6,3f\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fnabs   1,1\n"
Packit 172be8
"3:"	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n\t"
Packit 172be8
	"# friz == trunc\n"
Packit 172be8
"friz:"	"mffs    11\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	"lfd     13,8b@toc(2)\n\t"
Packit 172be8
#else
Packit 172be8
	"mflr    11\n\t"
Packit 172be8
	"bcl     20,31,1f\n"
Packit 172be8
"1:"	"mflr    9\n\t"
Packit 172be8
	"addis   9,9,8b-1b@ha\n\t"
Packit 172be8
	"lfs     13,8b-1b@l(9)\n\t"
Packit 172be8
	"mtlr    11\n\t"
Packit 172be8
#endif
Packit 172be8
	"fabs    0,1\n\t"
Packit 172be8
	"fsub    12,13,13\n\t"
Packit 172be8
	"fcmpu   7,0,13\n\t"
Packit 172be8
	"fcmpu   6,1,12\n\t"
Packit 172be8
	"bnllr-  7\n\t"
Packit 172be8
	"mtfsfi  7,1\n\t"
Packit 172be8
	"ble-    6,2f\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fabs    1,1\n\t"
Packit 172be8
	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n"
Packit 172be8
"2:"	"bge-    6,3f\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fnabs   1,1\n"
Packit 172be8
"3:"	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n\t"
Packit 172be8
	"# frin == round\n"
Packit 172be8
"frin:"	"mffs    11\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	"lfd     13,8b@toc(2)\n\t"
Packit 172be8
#else
Packit 172be8
	"mflr    11\n\t"
Packit 172be8
	"bcl     20,31,1f\n"
Packit 172be8
"1:"	"mflr    9\n\t"
Packit 172be8
	"addis   9,9,8b-1b@ha\n\t"
Packit 172be8
	"addi    9,9,8b-1b@l\n\t"
Packit 172be8
	"mtlr    11\n\t"
Packit 172be8
	"lfs     13,0(9)\n\t"
Packit 172be8
#endif
Packit 172be8
	"fabs    0,1\n\t"
Packit 172be8
	"fsub    12,13,13\n\t"
Packit 172be8
	"fcmpu   7,0,13\n\t"
Packit 172be8
	"fcmpu   6,1,12\n\t"
Packit 172be8
	"bnllr-  7\n\t"
Packit 172be8
	"mtfsfi  7,1\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	"lfd     10,9b@toc(2)\n\t"
Packit 172be8
#else
Packit 172be8
	"lfs     10,9b-8b(9)\n\t"
Packit 172be8
#endif
Packit 172be8
	"ble-    6,2f\n\t"
Packit 172be8
	"fadd    1,1,10\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fabs    1,1\n\t"
Packit 172be8
	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n"
Packit 172be8
"2:"	"fsub    9,1,10\n\t"
Packit 172be8
	"bge-    6,3f\n\t"
Packit 172be8
	"fsub    1,9,13\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fnabs   1,1\n"
Packit 172be8
"3:"	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n\t"
Packit 172be8
	"# frim == floor\n"
Packit 172be8
"frim:"	"mffs    11\n\t"
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
	"lfd     13,8b@toc(2)\n\t"
Packit 172be8
#else
Packit 172be8
	"mflr    11\n\t"
Packit 172be8
	"bcl     20,31,1f\n"
Packit 172be8
"1:"	"mflr    9\n\t"
Packit 172be8
	"addis   9,9,8b-1b@ha\n\t"
Packit 172be8
	"lfs     13,8b-1b@l(9)\n\t"
Packit 172be8
	"mtlr    11\n\t"
Packit 172be8
#endif
Packit 172be8
	"fabs    0,1\n\t"
Packit 172be8
	"fsub    12,13,13\n\t"
Packit 172be8
	"fcmpu   7,0,13\n\t"
Packit 172be8
	"fcmpu   6,1,12\n\t"
Packit 172be8
	"bnllr-  7\n\t"
Packit 172be8
	"mtfsfi  7,3\n\t"
Packit 172be8
	"ble-    6,2f\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fabs    1,1\n\t"
Packit 172be8
	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n"
Packit 172be8
"2:"	"bge-    6,3f\n\t"
Packit 172be8
	"fsub    1,1,13\n\t"
Packit 172be8
	"fadd    1,1,13\n\t"
Packit 172be8
	"fnabs   1,1\n"
Packit 172be8
"3:"	"mtfsf   0x01,11\n\t"
Packit 172be8
	"blr\n");
Packit 172be8
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
#define m1 0x5555555555555555L
Packit 172be8
#define m2 0x3333333333333333L
Packit 172be8
#define m3 0x0f0f0f0f0f0f0f0fL
Packit 172be8
#else
Packit 172be8
#define m1 0x55555555
Packit 172be8
#define m2 0x33333333
Packit 172be8
#define m3 0x0f0f0f0f
Packit 172be8
#endif
Packit 172be8
Packit 172be8
static inline unsigned long
Packit 172be8
popcntb (unsigned long n)
Packit 172be8
{
Packit 172be8
  n -= (n >> 1) & m1;
Packit 172be8
  n = (n & m2) + ((n >> 2) & m2);
Packit 172be8
  n = (n + (n >> 4)) & m3;
Packit 172be8
  return n;
Packit 172be8
}
Packit 172be8
Packit 172be8
static void
Packit 172be8
catch_sigill (int signal, struct sigcontext *ctx)
Packit 172be8
{
Packit 172be8
  unsigned int insn = *(unsigned int *) (ctx->regs->nip);
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
  if ((insn & 0xfc1f07ff) == 0x7c0005be) /* mftgpr */
Packit 172be8
    {
Packit 172be8
      unsigned long *regs = (unsigned long *) ctx->regs;
Packit 172be8
      unsigned fpr = (insn >> 11) & 0x1f;
Packit 172be8
      unsigned gpr = (insn >> 21) & 0x1f;
Packit 172be8
      regs[gpr] = regs[fpr + 0x30];
Packit 172be8
      ctx->regs->nip += 4;
Packit 172be8
      return;
Packit 172be8
    }
Packit 172be8
  if ((insn & 0xfc1f07ff) == 0x7c0004be) /*mffgpr */
Packit 172be8
    {
Packit 172be8
      unsigned long *regs = (unsigned long *) ctx->regs;
Packit 172be8
      unsigned fpr = (insn >> 21) & 0x1f;
Packit 172be8
      unsigned gpr = (insn >> 11) & 0x1f;
Packit 172be8
      regs[fpr + 0x30] = regs[gpr];
Packit 172be8
      ctx->regs->nip += 4;
Packit 172be8
      return;
Packit 172be8
    }
Packit 172be8
#endif
Packit 172be8
  if ((insn & 0xfc1f073f) == 0xfc000310) /* fri[pznm] */
Packit 172be8
    {
Packit 172be8
#ifdef __powerpc64__
Packit 172be8
      double *regs = (double *) (((char *) ctx->regs) + 0x30 * 8);
Packit 172be8
      unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x50 * 8 + 4);
Packit 172be8
#else
Packit 172be8
      double *regs = (double *) (((char *) ctx->regs) + 0x30 * 4);
Packit 172be8
      unsigned int *fpscr = (unsigned int *) (((char *) ctx->regs) + 0x30 * 4 + 0x20 * 8 + 4);
Packit 172be8
#endif
Packit 172be8
      unsigned dest = (insn >> 21) & 0x1f;
Packit 172be8
      unsigned src = (insn >> 11) & 0x1f;
Packit 172be8
      switch (insn & 0xc0)
Packit 172be8
	{
Packit 172be8
	case 0:
Packit 172be8
	  regs[dest] = frin (regs[src]);
Packit 172be8
	  break;
Packit 172be8
	case 0x40:
Packit 172be8
	  regs[dest] = friz (regs[src]);
Packit 172be8
	  break;
Packit 172be8
	case 0x80:
Packit 172be8
	  regs[dest] = frip (regs[src]);
Packit 172be8
	  break;
Packit 172be8
	case 0xc0:
Packit 172be8
	  regs[dest] = frim (regs[src]);
Packit 172be8
	  break;
Packit 172be8
	}
Packit 172be8
      /* Update raised exceptions.  */
Packit 172be8
      union { unsigned int i[2]; double d; } u;
Packit 172be8
      asm volatile ("mffs %0" : "=f" (u.d));
Packit 172be8
      u.i[1] &= 0xfffe0000; /* Is this correct?  */
Packit 172be8
      *fpscr |= u.i[1];
Packit 172be8
      ctx->regs->nip += 4;
Packit 172be8
      return;
Packit 172be8
    }
Packit 172be8
  if ((insn & 0xfc00ffff) == 0x7c0000f4) /* popcntb */
Packit 172be8
    {
Packit 172be8
      unsigned long *regs = (unsigned long *) ctx->regs;
Packit 172be8
      unsigned dest = (insn >> 16) & 0x1f;
Packit 172be8
      unsigned src = (insn >> 21) & 0x1f;
Packit 172be8
      unsigned long res = 0;
Packit 172be8
      int i;
Packit 172be8
Packit 172be8
      regs[dest] = popcntb (regs[src]);
Packit 172be8
      ctx->regs->nip += 4;
Packit 172be8
      return;
Packit 172be8
    }
Packit 172be8
Packit 172be8
  struct sigaction sa;
Packit 172be8
  sa.sa_handler = SIG_DFL;
Packit 172be8
  sigemptyset (&sa.sa_mask);
Packit 172be8
  sa.sa_flags = 0;
Packit 172be8
  sigaction (signal, &sa, NULL);
Packit 172be8
  raise (signal);
Packit 172be8
}
Packit 172be8
Packit 172be8
static void
Packit 172be8
__attribute__ ((constructor))
Packit 172be8
install_handler (void)
Packit 172be8
{
Packit 172be8
  struct sigaction sa;
Packit 172be8
  sa.sa_handler = (void *) catch_sigill;
Packit 172be8
  sigemptyset (&sa.sa_mask);
Packit 172be8
  sa.sa_flags = SA_RESTART;
Packit 172be8
  sigaction (SIGILL, &sa, NULL);
Packit 172be8
}