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