| 
									
										
										
										
											2010-02-19 11:00:40 +01:00
										 |  |  | /* | 
					
						
							|  |  |  |  *  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) | 
					
						
							| 
									
										
										
										
											2010-05-31 21:59:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | _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 |