/*1* FPU helper code to use FPU operations from inside the kernel2*3* Copyright (C) 2010 Alexander Graf ([email protected])4*5* This program is free software; you can redistribute it and/or6* modify it under the terms of the GNU General Public License7* as published by the Free Software Foundation; either version8* 2 of the License, or (at your option) any later version.9*10*/1112#include <asm/reg.h>13#include <asm/page.h>14#include <asm/mmu.h>15#include <asm/pgtable.h>16#include <asm/cputable.h>17#include <asm/cache.h>18#include <asm/thread_info.h>19#include <asm/ppc_asm.h>20#include <asm/asm-offsets.h>2122/* Instructions operating on single parameters */2324/*25* Single operation with one input operand26*27* R3 = (double*)&fpscr28* R4 = (short*)&result29* R5 = (short*)¶m130*/31#define FPS_ONE_IN(name) \32_GLOBAL(fps_ ## name); \33lfd 0,0(r3); /* load up fpscr value */ \34MTFSF_L(0); \35lfs 0,0(r5); \36\37name 0,0; \38\39stfs 0,0(r4); \40mffs 0; \41stfd 0,0(r3); /* save new fpscr value */ \42blr4344/*45* Single operation with two input operands46*47* R3 = (double*)&fpscr48* R4 = (short*)&result49* R5 = (short*)¶m150* R6 = (short*)¶m251*/52#define FPS_TWO_IN(name) \53_GLOBAL(fps_ ## name); \54lfd 0,0(r3); /* load up fpscr value */ \55MTFSF_L(0); \56lfs 0,0(r5); \57lfs 1,0(r6); \58\59name 0,0,1; \60\61stfs 0,0(r4); \62mffs 0; \63stfd 0,0(r3); /* save new fpscr value */ \64blr6566/*67* Single operation with three input operands68*69* R3 = (double*)&fpscr70* R4 = (short*)&result71* R5 = (short*)¶m172* R6 = (short*)¶m273* R7 = (short*)¶m374*/75#define FPS_THREE_IN(name) \76_GLOBAL(fps_ ## name); \77lfd 0,0(r3); /* load up fpscr value */ \78MTFSF_L(0); \79lfs 0,0(r5); \80lfs 1,0(r6); \81lfs 2,0(r7); \82\83name 0,0,1,2; \84\85stfs 0,0(r4); \86mffs 0; \87stfd 0,0(r3); /* save new fpscr value */ \88blr8990FPS_ONE_IN(fres)91FPS_ONE_IN(frsqrte)92FPS_ONE_IN(fsqrts)93FPS_TWO_IN(fadds)94FPS_TWO_IN(fdivs)95FPS_TWO_IN(fmuls)96FPS_TWO_IN(fsubs)97FPS_THREE_IN(fmadds)98FPS_THREE_IN(fmsubs)99FPS_THREE_IN(fnmadds)100FPS_THREE_IN(fnmsubs)101FPS_THREE_IN(fsel)102103104/* Instructions operating on double parameters */105106/*107* Beginning of double instruction processing108*109* R3 = (double*)&fpscr110* R4 = (u32*)&cr111* R5 = (double*)&result112* R6 = (double*)¶m1113* R7 = (double*)¶m2 [load_two]114* R8 = (double*)¶m3 [load_three]115* LR = instruction call function116*/117fpd_load_three:118lfd 2,0(r8) /* load param3 */119fpd_load_two:120lfd 1,0(r7) /* load param2 */121fpd_load_one:122lfd 0,0(r6) /* load param1 */123fpd_load_none:124lfd 3,0(r3) /* load up fpscr value */125MTFSF_L(3)126lwz r6, 0(r4) /* load cr */127mtcr r6128blr129130/*131* End of double instruction processing132*133* R3 = (double*)&fpscr134* R4 = (u32*)&cr135* R5 = (double*)&result136* LR = caller of instruction call function137*/138fpd_return:139mfcr r6140stfd 0,0(r5) /* save result */141mffs 0142stfd 0,0(r3) /* save new fpscr value */143stw r6,0(r4) /* save new cr value */144blr145146/*147* Double operation with no input operand148*149* R3 = (double*)&fpscr150* R4 = (u32*)&cr151* R5 = (double*)&result152*/153#define FPD_NONE_IN(name) \154_GLOBAL(fpd_ ## name); \155mflr r12; \156bl fpd_load_none; \157mtlr r12; \158\159name. 0; /* call instruction */ \160b fpd_return161162/*163* Double operation with one input operand164*165* R3 = (double*)&fpscr166* R4 = (u32*)&cr167* R5 = (double*)&result168* R6 = (double*)¶m1169*/170#define FPD_ONE_IN(name) \171_GLOBAL(fpd_ ## name); \172mflr r12; \173bl fpd_load_one; \174mtlr r12; \175\176name. 0,0; /* call instruction */ \177b fpd_return178179/*180* Double operation with two input operands181*182* R3 = (double*)&fpscr183* R4 = (u32*)&cr184* R5 = (double*)&result185* R6 = (double*)¶m1186* R7 = (double*)¶m2187* R8 = (double*)¶m3188*/189#define FPD_TWO_IN(name) \190_GLOBAL(fpd_ ## name); \191mflr r12; \192bl fpd_load_two; \193mtlr r12; \194\195name. 0,0,1; /* call instruction */ \196b fpd_return197198/*199* CR Double operation with two input operands200*201* R3 = (double*)&fpscr202* R4 = (u32*)&cr203* R5 = (double*)¶m1204* R6 = (double*)¶m2205* R7 = (double*)¶m3206*/207#define FPD_TWO_IN_CR(name) \208_GLOBAL(fpd_ ## name); \209lfd 1,0(r6); /* load param2 */ \210lfd 0,0(r5); /* load param1 */ \211lfd 3,0(r3); /* load up fpscr value */ \212MTFSF_L(3); \213lwz r6, 0(r4); /* load cr */ \214mtcr r6; \215\216name 0,0,1; /* call instruction */ \217mfcr r6; \218mffs 0; \219stfd 0,0(r3); /* save new fpscr value */ \220stw r6,0(r4); /* save new cr value */ \221blr222223/*224* Double operation with three input operands225*226* R3 = (double*)&fpscr227* R4 = (u32*)&cr228* R5 = (double*)&result229* R6 = (double*)¶m1230* R7 = (double*)¶m2231* R8 = (double*)¶m3232*/233#define FPD_THREE_IN(name) \234_GLOBAL(fpd_ ## name); \235mflr r12; \236bl fpd_load_three; \237mtlr r12; \238\239name. 0,0,1,2; /* call instruction */ \240b fpd_return241242FPD_ONE_IN(fsqrts)243FPD_ONE_IN(frsqrtes)244FPD_ONE_IN(fres)245FPD_ONE_IN(frsp)246FPD_ONE_IN(fctiw)247FPD_ONE_IN(fctiwz)248FPD_ONE_IN(fsqrt)249FPD_ONE_IN(fre)250FPD_ONE_IN(frsqrte)251FPD_ONE_IN(fneg)252FPD_ONE_IN(fabs)253FPD_TWO_IN(fadds)254FPD_TWO_IN(fsubs)255FPD_TWO_IN(fdivs)256FPD_TWO_IN(fmuls)257FPD_TWO_IN_CR(fcmpu)258FPD_TWO_IN(fcpsgn)259FPD_TWO_IN(fdiv)260FPD_TWO_IN(fadd)261FPD_TWO_IN(fmul)262FPD_TWO_IN_CR(fcmpo)263FPD_TWO_IN(fsub)264FPD_THREE_IN(fmsubs)265FPD_THREE_IN(fmadds)266FPD_THREE_IN(fnmsubs)267FPD_THREE_IN(fnmadds)268FPD_THREE_IN(fsel)269FPD_THREE_IN(fmsub)270FPD_THREE_IN(fmadd)271FPD_THREE_IN(fnmsub)272FPD_THREE_IN(fnmadd)273274_GLOBAL(kvm_cvt_fd)275lfs 0,0(r3)276stfd 0,0(r4)277blr278279_GLOBAL(kvm_cvt_df)280lfd 0,0(r3)281stfs 0,0(r4)282blr283284285