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*)¶m1 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*)¶m1 51 * R6 = (short*)¶m2 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*)¶m1 73 * R6 = (short*)¶m2 74 * R7 = (short*)¶m3 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*)¶m1 114 * R7 = (double*)¶m2 [load_two] 115 * R8 = (double*)¶m3 [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*)¶m1 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*)¶m1 187 * R7 = (double*)¶m2 188 * R8 = (double*)¶m3 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*)¶m1 205 * R6 = (double*)¶m2 206 * R7 = (double*)¶m3 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*)¶m1 231 * R7 = (double*)¶m2 232 * R8 = (double*)¶m3 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