linux/arch/powerpc/kvm/fpu.S
<<
>>
Prefs
   1/*
   2 *  FPU helper code to use FPU operations from inside the kernel
   3 *
   4 *    Copyright (C) 2010 Alexander Graf (agraf@suse.de)
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *  modify it under the terms of the GNU General Public License
   8 *  as published by the Free Software Foundation; either version
   9 *  2 of the License, or (at your option) any later version.
  10 *
  11 */
  12
  13#include <asm/reg.h>
  14#include <asm/page.h>
  15#include <asm/mmu.h>
  16#include <asm/pgtable.h>
  17#include <asm/cputable.h>
  18#include <asm/cache.h>
  19#include <asm/thread_info.h>
  20#include <asm/ppc_asm.h>
  21#include <asm/asm-offsets.h>
  22
  23/* Instructions operating on single parameters */
  24
  25/*
  26 * Single operation with one input operand
  27 *
  28 * R3 = (double*)&fpscr
  29 * R4 = (short*)&result
  30 * R5 = (short*)&param1
  31 */
  32#define FPS_ONE_IN(name)                                        \
  33_GLOBAL(fps_ ## name);                                                  \
  34        lfd     0,0(r3);                /* load up fpscr value */       \
  35        MTFSF_L(0);                                                     \
  36        lfs     0,0(r5);                                                \
  37                                                                        \
  38        name    0,0;                                                    \
  39                                                                        \
  40        stfs    0,0(r4);                                                \
  41        mffs    0;                                                      \
  42        stfd    0,0(r3);        /* save new fpscr value */      \
  43        blr
  44
  45/*
  46 * Single operation with two input operands
  47 *
  48 * R3 = (double*)&fpscr
  49 * R4 = (short*)&result
  50 * R5 = (short*)&param1
  51 * R6 = (short*)&param2
  52 */
  53#define FPS_TWO_IN(name)                                        \
  54_GLOBAL(fps_ ## name);                                                  \
  55        lfd     0,0(r3);                /* load up fpscr value */       \
  56        MTFSF_L(0);                                                     \
  57        lfs     0,0(r5);                                                \
  58        lfs     1,0(r6);                                                \
  59                                                                        \
  60        name    0,0,1;                                                  \
  61                                                                        \
  62        stfs    0,0(r4);                                                \
  63        mffs    0;                                                      \
  64        stfd    0,0(r3);                /* save new fpscr value */      \
  65        blr
  66
  67/*
  68 * Single operation with three input operands
  69 *
  70 * R3 = (double*)&fpscr
  71 * R4 = (short*)&result
  72 * R5 = (short*)&param1
  73 * R6 = (short*)&param2
  74 * R7 = (short*)&param3
  75 */
  76#define FPS_THREE_IN(name)                                      \
  77_GLOBAL(fps_ ## name);                                                  \
  78        lfd     0,0(r3);                /* load up fpscr value */       \
  79        MTFSF_L(0);                                                     \
  80        lfs     0,0(r5);                                                \
  81        lfs     1,0(r6);                                                \
  82        lfs     2,0(r7);                                                \
  83                                                                        \
  84        name    0,0,1,2;                                                \
  85                                                                        \
  86        stfs    0,0(r4);                                                \
  87        mffs    0;                                                      \
  88        stfd    0,0(r3);                /* save new fpscr value */      \
  89        blr
  90
  91FPS_ONE_IN(fres)
  92FPS_ONE_IN(frsqrte)
  93FPS_ONE_IN(fsqrts)
  94FPS_TWO_IN(fadds)
  95FPS_TWO_IN(fdivs)
  96FPS_TWO_IN(fmuls)
  97FPS_TWO_IN(fsubs)
  98FPS_THREE_IN(fmadds)
  99FPS_THREE_IN(fmsubs)
 100FPS_THREE_IN(fnmadds)
 101FPS_THREE_IN(fnmsubs)
 102FPS_THREE_IN(fsel)
 103
 104
 105/* Instructions operating on double parameters */
 106
 107/*
 108 * Beginning of double instruction processing
 109 *
 110 * R3 = (double*)&fpscr
 111 * R4 = (u32*)&cr
 112 * R5 = (double*)&result
 113 * R6 = (double*)&param1
 114 * R7 = (double*)&param2 [load_two]
 115 * R8 = (double*)&param3 [load_three]
 116 * LR = instruction call function
 117 */
 118fpd_load_three:
 119        lfd     2,0(r8)                 /* load param3 */
 120fpd_load_two:
 121        lfd     1,0(r7)                 /* load param2 */
 122fpd_load_one:
 123        lfd     0,0(r6)                 /* load param1 */
 124fpd_load_none:
 125        lfd     3,0(r3)                 /* load up fpscr value */
 126        MTFSF_L(3)
 127        lwz     r6, 0(r4)               /* load cr */
 128        mtcr    r6
 129        blr
 130
 131/*
 132 * End of double instruction processing
 133 *
 134 * R3 = (double*)&fpscr
 135 * R4 = (u32*)&cr
 136 * R5 = (double*)&result
 137 * LR = caller of instruction call function
 138 */
 139fpd_return:
 140        mfcr    r6
 141        stfd    0,0(r5)                 /* save result */
 142        mffs    0
 143        stfd    0,0(r3)                 /* save new fpscr value */
 144        stw     r6,0(r4)                /* save new cr value */
 145        blr
 146
 147/*
 148 * Double operation with no input operand
 149 *
 150 * R3 = (double*)&fpscr
 151 * R4 = (u32*)&cr
 152 * R5 = (double*)&result
 153 */
 154#define FPD_NONE_IN(name)                                               \
 155_GLOBAL(fpd_ ## name);                                                  \
 156        mflr    r12;                                                    \
 157        bl      fpd_load_none;                                          \
 158        mtlr    r12;                                                    \
 159                                                                        \
 160        name.   0;                      /* call instruction */          \
 161        b       fpd_return
 162
 163/*
 164 * Double operation with one input operand
 165 *
 166 * R3 = (double*)&fpscr
 167 * R4 = (u32*)&cr
 168 * R5 = (double*)&result
 169 * R6 = (double*)&param1
 170 */
 171#define FPD_ONE_IN(name)                                                \
 172_GLOBAL(fpd_ ## name);                                                  \
 173        mflr    r12;                                                    \
 174        bl      fpd_load_one;                                           \
 175        mtlr    r12;                                                    \
 176                                                                        \
 177        name.   0,0;                    /* call instruction */          \
 178        b       fpd_return
 179
 180/*
 181 * Double operation with two input operands
 182 *
 183 * R3 = (double*)&fpscr
 184 * R4 = (u32*)&cr
 185 * R5 = (double*)&result
 186 * R6 = (double*)&param1
 187 * R7 = (double*)&param2
 188 * R8 = (double*)&param3
 189 */
 190#define FPD_TWO_IN(name)                                                \
 191_GLOBAL(fpd_ ## name);                                                  \
 192        mflr    r12;                                                    \
 193        bl      fpd_load_two;                                           \
 194        mtlr    r12;                                                    \
 195                                                                        \
 196        name.   0,0,1;                  /* call instruction */          \
 197        b       fpd_return
 198
 199/*
 200 * CR Double operation with two input operands
 201 *
 202 * R3 = (double*)&fpscr
 203 * R4 = (u32*)&cr
 204 * R5 = (double*)&param1
 205 * R6 = (double*)&param2
 206 * R7 = (double*)&param3
 207 */
 208#define FPD_TWO_IN_CR(name)                                             \
 209_GLOBAL(fpd_ ## name);                                                  \
 210        lfd     1,0(r6);                /* load param2 */               \
 211        lfd     0,0(r5);                /* load param1 */               \
 212        lfd     3,0(r3);                /* load up fpscr value */       \
 213        MTFSF_L(3);                                                     \
 214        lwz     r6, 0(r4);              /* load cr */                   \
 215        mtcr    r6;                                                     \
 216                                                                        \
 217        name    0,0,1;                  /* call instruction */          \
 218        mfcr    r6;                                                     \
 219        mffs    0;                                                      \
 220        stfd    0,0(r3);                /* save new fpscr value */      \
 221        stw     r6,0(r4);               /* save new cr value */         \
 222        blr
 223
 224/*
 225 * Double operation with three input operands
 226 *
 227 * R3 = (double*)&fpscr
 228 * R4 = (u32*)&cr
 229 * R5 = (double*)&result
 230 * R6 = (double*)&param1
 231 * R7 = (double*)&param2
 232 * R8 = (double*)&param3
 233 */
 234#define FPD_THREE_IN(name)                                              \
 235_GLOBAL(fpd_ ## name);                                                  \
 236        mflr    r12;                                                    \
 237        bl      fpd_load_three;                                         \
 238        mtlr    r12;                                                    \
 239                                                                        \
 240        name.   0,0,1,2;                /* call instruction */          \
 241        b       fpd_return
 242
 243FPD_ONE_IN(fsqrts)
 244FPD_ONE_IN(frsqrtes)
 245FPD_ONE_IN(fres)
 246FPD_ONE_IN(frsp)
 247FPD_ONE_IN(fctiw)
 248FPD_ONE_IN(fctiwz)
 249FPD_ONE_IN(fsqrt)
 250FPD_ONE_IN(fre)
 251FPD_ONE_IN(frsqrte)
 252FPD_ONE_IN(fneg)
 253FPD_ONE_IN(fabs)
 254FPD_TWO_IN(fadds)
 255FPD_TWO_IN(fsubs)
 256FPD_TWO_IN(fdivs)
 257FPD_TWO_IN(fmuls)
 258FPD_TWO_IN_CR(fcmpu)
 259FPD_TWO_IN(fcpsgn)
 260FPD_TWO_IN(fdiv)
 261FPD_TWO_IN(fadd)
 262FPD_TWO_IN(fmul)
 263FPD_TWO_IN_CR(fcmpo)
 264FPD_TWO_IN(fsub)
 265FPD_THREE_IN(fmsubs)
 266FPD_THREE_IN(fmadds)
 267FPD_THREE_IN(fnmsubs)
 268FPD_THREE_IN(fnmadds)
 269FPD_THREE_IN(fsel)
 270FPD_THREE_IN(fmsub)
 271FPD_THREE_IN(fmadd)
 272FPD_THREE_IN(fnmsub)
 273FPD_THREE_IN(fnmadd)
 274
 275_GLOBAL(kvm_cvt_fd)
 276        lfs     0,0(r3)
 277        stfd    0,0(r4)
 278        blr
 279
 280_GLOBAL(kvm_cvt_df)
 281        lfd     0,0(r3)
 282        stfs    0,0(r4)
 283        blr
 284