| /* | |
| * FPU helper code to use FPU operations from inside the kernel | |
| * | |
| * Copyright (C) 2010 Alexander Graf (agraf@suse.de) | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License | |
| * as published by the Free Software Foundation; either version | |
| * 2 of the License, or (at your option) any later version. | |
| * | |
| */ | |
| #include <asm/reg.h> | |
| #include <asm/page.h> | |
| #include <asm/mmu.h> | |
| #include <asm/pgtable.h> | |
| #include <asm/cputable.h> | |
| #include <asm/cache.h> | |
| #include <asm/thread_info.h> | |
| #include <asm/ppc_asm.h> | |
| #include <asm/asm-offsets.h> | |
| /* Instructions operating on single parameters */ | |
| /* | |
| * Single operation with one input operand | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (short*)&result | |
| * R5 = (short*)¶m1 | |
| */ | |
| #define FPS_ONE_IN(name) \ | |
| _GLOBAL(fps_ ## name); \ | |
| lfd 0,0(r3); /* load up fpscr value */ \ | |
| MTFSF_L(0); \ | |
| lfs 0,0(r5); \ | |
| \ | |
| name 0,0; \ | |
| \ | |
| stfs 0,0(r4); \ | |
| mffs 0; \ | |
| stfd 0,0(r3); /* save new fpscr value */ \ | |
| blr | |
| /* | |
| * Single operation with two input operands | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (short*)&result | |
| * R5 = (short*)¶m1 | |
| * R6 = (short*)¶m2 | |
| */ | |
| #define FPS_TWO_IN(name) \ | |
| _GLOBAL(fps_ ## name); \ | |
| lfd 0,0(r3); /* load up fpscr value */ \ | |
| MTFSF_L(0); \ | |
| lfs 0,0(r5); \ | |
| lfs 1,0(r6); \ | |
| \ | |
| name 0,0,1; \ | |
| \ | |
| stfs 0,0(r4); \ | |
| mffs 0; \ | |
| stfd 0,0(r3); /* save new fpscr value */ \ | |
| blr | |
| /* | |
| * Single operation with three input operands | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (short*)&result | |
| * R5 = (short*)¶m1 | |
| * R6 = (short*)¶m2 | |
| * R7 = (short*)¶m3 | |
| */ | |
| #define FPS_THREE_IN(name) \ | |
| _GLOBAL(fps_ ## name); \ | |
| lfd 0,0(r3); /* load up fpscr value */ \ | |
| MTFSF_L(0); \ | |
| lfs 0,0(r5); \ | |
| lfs 1,0(r6); \ | |
| lfs 2,0(r7); \ | |
| \ | |
| name 0,0,1,2; \ | |
| \ | |
| stfs 0,0(r4); \ | |
| mffs 0; \ | |
| stfd 0,0(r3); /* save new fpscr value */ \ | |
| blr | |
| FPS_ONE_IN(fres) | |
| FPS_ONE_IN(frsqrte) | |
| FPS_ONE_IN(fsqrts) | |
| FPS_TWO_IN(fadds) | |
| FPS_TWO_IN(fdivs) | |
| FPS_TWO_IN(fmuls) | |
| FPS_TWO_IN(fsubs) | |
| FPS_THREE_IN(fmadds) | |
| FPS_THREE_IN(fmsubs) | |
| FPS_THREE_IN(fnmadds) | |
| FPS_THREE_IN(fnmsubs) | |
| FPS_THREE_IN(fsel) | |
| /* Instructions operating on double parameters */ | |
| /* | |
| * Beginning of double instruction processing | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| * R6 = (double*)¶m1 | |
| * R7 = (double*)¶m2 [load_two] | |
| * R8 = (double*)¶m3 [load_three] | |
| * LR = instruction call function | |
| */ | |
| fpd_load_three: | |
| lfd 2,0(r8) /* load param3 */ | |
| fpd_load_two: | |
| lfd 1,0(r7) /* load param2 */ | |
| fpd_load_one: | |
| lfd 0,0(r6) /* load param1 */ | |
| fpd_load_none: | |
| lfd 3,0(r3) /* load up fpscr value */ | |
| MTFSF_L(3) | |
| lwz r6, 0(r4) /* load cr */ | |
| mtcr r6 | |
| blr | |
| /* | |
| * End of double instruction processing | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| * LR = caller of instruction call function | |
| */ | |
| fpd_return: | |
| mfcr r6 | |
| stfd 0,0(r5) /* save result */ | |
| mffs 0 | |
| stfd 0,0(r3) /* save new fpscr value */ | |
| stw r6,0(r4) /* save new cr value */ | |
| blr | |
| /* | |
| * Double operation with no input operand | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| */ | |
| #define FPD_NONE_IN(name) \ | |
| _GLOBAL(fpd_ ## name); \ | |
| mflr r12; \ | |
| bl fpd_load_none; \ | |
| mtlr r12; \ | |
| \ | |
| name. 0; /* call instruction */ \ | |
| b fpd_return | |
| /* | |
| * Double operation with one input operand | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| * R6 = (double*)¶m1 | |
| */ | |
| #define FPD_ONE_IN(name) \ | |
| _GLOBAL(fpd_ ## name); \ | |
| mflr r12; \ | |
| bl fpd_load_one; \ | |
| mtlr r12; \ | |
| \ | |
| name. 0,0; /* call instruction */ \ | |
| b fpd_return | |
| /* | |
| * Double operation with two input operands | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| * R6 = (double*)¶m1 | |
| * R7 = (double*)¶m2 | |
| * R8 = (double*)¶m3 | |
| */ | |
| #define FPD_TWO_IN(name) \ | |
| _GLOBAL(fpd_ ## name); \ | |
| mflr r12; \ | |
| bl fpd_load_two; \ | |
| mtlr r12; \ | |
| \ | |
| name. 0,0,1; /* call instruction */ \ | |
| b fpd_return | |
| /* | |
| * CR Double operation with two input operands | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)¶m1 | |
| * R6 = (double*)¶m2 | |
| * R7 = (double*)¶m3 | |
| */ | |
| #define FPD_TWO_IN_CR(name) \ | |
| _GLOBAL(fpd_ ## name); \ | |
| lfd 1,0(r6); /* load param2 */ \ | |
| lfd 0,0(r5); /* load param1 */ \ | |
| lfd 3,0(r3); /* load up fpscr value */ \ | |
| MTFSF_L(3); \ | |
| lwz r6, 0(r4); /* load cr */ \ | |
| mtcr r6; \ | |
| \ | |
| name 0,0,1; /* call instruction */ \ | |
| mfcr r6; \ | |
| mffs 0; \ | |
| stfd 0,0(r3); /* save new fpscr value */ \ | |
| stw r6,0(r4); /* save new cr value */ \ | |
| blr | |
| /* | |
| * Double operation with three input operands | |
| * | |
| * R3 = (double*)&fpscr | |
| * R4 = (u32*)&cr | |
| * R5 = (double*)&result | |
| * R6 = (double*)¶m1 | |
| * R7 = (double*)¶m2 | |
| * R8 = (double*)¶m3 | |
| */ | |
| #define FPD_THREE_IN(name) \ | |
| _GLOBAL(fpd_ ## name); \ | |
| mflr r12; \ | |
| bl fpd_load_three; \ | |
| mtlr r12; \ | |
| \ | |
| name. 0,0,1,2; /* call instruction */ \ | |
| b fpd_return | |
| FPD_ONE_IN(fsqrts) | |
| FPD_ONE_IN(frsqrtes) | |
| FPD_ONE_IN(fres) | |
| FPD_ONE_IN(frsp) | |
| FPD_ONE_IN(fctiw) | |
| FPD_ONE_IN(fctiwz) | |
| FPD_ONE_IN(fsqrt) | |
| FPD_ONE_IN(fre) | |
| FPD_ONE_IN(frsqrte) | |
| FPD_ONE_IN(fneg) | |
| FPD_ONE_IN(fabs) | |
| FPD_TWO_IN(fadds) | |
| FPD_TWO_IN(fsubs) | |
| FPD_TWO_IN(fdivs) | |
| FPD_TWO_IN(fmuls) | |
| FPD_TWO_IN_CR(fcmpu) | |
| FPD_TWO_IN(fcpsgn) | |
| FPD_TWO_IN(fdiv) | |
| FPD_TWO_IN(fadd) | |
| FPD_TWO_IN(fmul) | |
| FPD_TWO_IN_CR(fcmpo) | |
| FPD_TWO_IN(fsub) | |
| FPD_THREE_IN(fmsubs) | |
| FPD_THREE_IN(fmadds) | |
| FPD_THREE_IN(fnmsubs) | |
| FPD_THREE_IN(fnmadds) | |
| FPD_THREE_IN(fsel) | |
| FPD_THREE_IN(fmsub) | |
| FPD_THREE_IN(fmadd) | |
| FPD_THREE_IN(fnmsub) | |
| FPD_THREE_IN(fnmadd) | |
| _GLOBAL(kvm_cvt_fd) | |
| lfs 0,0(r3) | |
| stfd 0,0(r4) | |
| blr | |
| _GLOBAL(kvm_cvt_df) | |
| lfd 0,0(r3) | |
| stfs 0,0(r4) | |
| blr |