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