[patch][5/5] powerpc V2: Add the general support for Embedded Floating-Point instructions

Kumar Gala galak at kernel.crashing.org
Thu Feb 8 18:32:58 EST 2007


On Feb 7, 2007, at 9:55 PM, ebony.zhu at freescale.com wrote:

> Add the general support for Embedded Floating-Point instructions
> to fully comply with IEEE-754.
>
> Signed-off-by:Ebony Zhu <ebony.zhu at freescale.com>
> ---
>  arch/powerpc/kernel/head_fsl_booke.S |    4
>  arch/powerpc/kernel/traps.c          |   57 +++++
>  arch/powerpc/math-emu/Makefile       |   25 ++
>  arch/powerpc/math-emu/sfp-machine.h  |    2
>  arch/powerpc/math-emu/spe.h          |    1
>  arch/powerpc/sysdev/Makefile         |    1
>  arch/powerpc/sysdev/sigfpe_handler.c |  361 +++++++++++++++++++++++ 
> +++++++++++
>  7 files changed, 442 insertions(+), 9 deletions(-)

I thought we were going to have some general Kconfig option to enable  
all this?  EMDEDDED_FP_IEEE or something like that

>
> diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/ 
> kernel/head_fsl_booke.S
> index 66877bd..0d05db0 100644
> --- a/arch/powerpc/kernel/head_fsl_booke.S
> +++ b/arch/powerpc/kernel/head_fsl_booke.S
> @@ -705,7 +705,7 @@ #else
>  #endif /* CONFIG_SPE */
>
>  	/* SPE Floating Point Round */
> -	EXCEPTION(0x2050, SPEFloatingPointRound, unknown_exception,  
> EXC_XFER_EE)
> +	EXCEPTION(0x2050, SPEFloatingPointRound,  
> SPEFloatingPointException_Round, EXC_XFER_EE)
>
>  	/* Performance Monitor */
>  	EXCEPTION(0x2060, PerformanceMonitor,  
> performance_monitor_exception, EXC_XFER_STD)
> @@ -840,6 +840,8 @@ load_up_spe:
>  	oris	r5,r5,MSR_SPE at h
>  	mtmsr	r5			/* enable use of SPE now */
>  	isync
> +	li	r5,(SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE |  
> SPEFSCR_FOVFE)
> +	mtspr   SPRN_SPEFSCR,r5

We should do this via INIT_THREAD, is there a reason that you want to  
set these always?

>  /*
>   * For SMP, we don't do lazy SPE switching because it just gets too
>   * horrendously complex, especially when a task switches from one CPU
> diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
> index 6915b91..30ab0f7 100644
> --- a/arch/powerpc/kernel/traps.c
> +++ b/arch/powerpc/kernel/traps.c
> @@ -986,9 +986,16 @@ #endif /* CONFIG_FSL_BOOKE */
>  #ifdef CONFIG_SPE
>  void SPEFloatingPointException(struct pt_regs *regs)
>  {
> +	extern int spedata_handler(struct pt_regs *regs);
>  	unsigned long spefscr;
>  	int fpexc_mode;
>  	int code = 0;
> +	int err;
> +	
> +	preempt_disable();
> +	if (regs->msr & MSR_SPE)
> +		giveup_spe(current);
> +	preempt_enable();

use flush_spe_to_thread(current);

>
>  	spefscr = current->thread.spefscr;
>  	fpexc_mode = current->thread.fpexc_mode;
> @@ -1013,9 +1020,55 @@ void SPEFloatingPointException(struct pt
>  		code = FPE_FLTRES;
>
>  	current->thread.spefscr = spefscr;
> +	err = spedata_handler(regs);
> +	if (err == 0) {
> +		regs->nip += 4;		/* skip emulated instruction */
> +		emulate_single_step(regs);
> +		return;
> +	}

Take a look at the path I put up that reworks the error handling from  
do_mathemu() we need to be doing something similar (in parsing  
spefscr/fpexc_mode to setup code properly)

> -	_exception(SIGFPE, regs, code, regs->nip);
> -	return;
> +	if (err == -EFAULT) {
> +		/* got an error reading the instruction */
> +		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
> +	} else if (err == -EINVAL) {
> +		/* didn't recognize the instruction */
> +		printk(KERN_ERR "unrecognized spe instruction "
> +		       "in %s at %lx\n", current->comm, regs->nip);

We should probably just SIGSEGV in this case since will never make  
forward progress once we hit this case.

> +	} else {
> +		_exception(SIGFPE, regs, code, regs->nip);
> +		return;
> +	}
> +}
> +
> +void SPEFloatingPointException_Round(struct pt_regs *regs)
> +{
> +	extern int speround_handler(struct pt_regs *regs);
> +	int err;
> +


> +	preempt_disable();
> +	if (regs->msr & MSR_SPE)
> +		giveup_spe(current);
> +	preempt_enable();

use flush_spe_to_thread(current);

> +
> +	regs->nip -= 4;

uugh, just handle this in speround_handler()

> +	err = speround_handler(regs);
> +	if (err == 0) {
> +		regs->nip += 4;		/* skip emulated instruction */
> +		emulate_single_step(regs);

I don't think this emulate_single_step() needed since we really  
aren't changing NIP from the HW point of view.

> +		return;
> +	}
> +
> +	if (err == -EFAULT) {
> +		/* got an error reading the instruction */
> +		_exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip);
> +	} else if (err == -EINVAL) {
> +		/* didn't recognize the instruction */
> +		printk(KERN_ERR "unrecognized spe instruction "
> +		       "in %s at %lx\n", current->comm, regs->nip);

similar comment as above

> +	} else {
> +		_exception(SIGFPE, regs, 0, regs->nip);
> +		return;
> +	}
>  }
>  #endif
>
> diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/ 
> Makefile
> index 29bc912..2da11ba 100644
> --- a/arch/powerpc/math-emu/Makefile
> +++ b/arch/powerpc/math-emu/Makefile
> @@ -1,16 +1,29 @@
>
> -obj-y				:= math.o fmr.o lfd.o stfd.o
> -
> -obj-$(CONFIG_MATH_EMULATION)	+= fabs.o fadd.o fadds.o fcmpo.o  
> fcmpu.o \
> +obj-y				:= fabs.o fneg.o types.o udivmodti4.o

This isn't right, we don't want to always build these files.

> +					
> +obj-$(CONFIG_MATH_EMULATION)	+= math.o fmr.o lfd.o stfd.o \
> +					fadd.o fadds.o fcmpo.o fcmpu.o \
>  					fctiw.o fctiwz.o fdiv.o fdivs.o \
>  					fmadd.o fmadds.o fmsub.o fmsubs.o \
> -					fmul.o fmuls.o fnabs.o fneg.o types.o \
> +					fmul.o fmuls.o fnabs.o \
>  					fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
>  					fres.o frsp.o frsqrte.o fsel.o lfs.o \
>  					fsqrt.o	fsqrts.o fsub.o fsubs.o \
>  					mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
> -					mtfsf.o mtfsfi.o stfiwx.o stfs.o \
> -					udivmodti4.o
> +					mtfsf.o mtfsfi.o stfiwx.o stfs.o
> +
> +obj-$(CONFIG_SPE)		+= efsabs.o efsadd.o efscfd.o efscmpeq.o \
> +					efscmpgt.o efscmplt.o efsctsf.o efsctsi.o \
> +					efsctsiz.o efsctuf.o efsctui.o efsctuiz.o \
> +					efsdiv.o efsmul.o efsnabs.o efsneg.o efssub.o \
> +					evfsabs.o evfsadd.o evfscmpeq.o evfscmpgt.o \
> +					evfscmplt.o evfsctsf.o evfsctsi.o evfsctsiz.o \
> +					evfsctuf.o evfsctui.o evfsctuiz.o evfsdiv.o \
> +					evfsmul.o evfsnabs.o evfsneg.o evfssub.o \
> +					efdadd.o efdcfs.o efdcmpeq.o efdcmpgt.o efdcmplt.o \
> +					efdctsf.o efdctsi.o efdctsidz.o efdctsiz.o efdctuf.o \
> +					efdctui.o efdctuidz.o efdctuiz.o efddiv.o efdmul.o \
> +					efdnabs.o efdsub.o
>
>  CFLAGS_fabs.o = -fno-builtin-fabs
>  CFLAGS_math.o = -fno-builtin-fabs
> diff --git a/arch/powerpc/math-emu/sfp-machine.h b/arch/powerpc/ 
> math-emu/sfp-machine.h
> index 4b17d83..07de8ef 100644
> --- a/arch/powerpc/math-emu/sfp-machine.h
> +++ b/arch/powerpc/math-emu/sfp-machine.h
> @@ -166,7 +166,9 @@ #define __FP_PACK_RAW_2(fs, val, X)			\
>  #include <linux/kernel.h>
>  #include <linux/sched.h>
>
> +#ifndef __FPU_FPSCR
>  #define __FPU_FPSCR	(current->thread.fpscr.val)
> +#endif
>
>  /* We only actually write to the destination register
>   * if exceptions signalled (if any) will not trap.
> diff --git a/arch/powerpc/math-emu/spe.h b/arch/powerpc/math-emu/spe.h
> new file mode 100644
> index 0000000..4f63630
> --- /dev/null
> +++ b/arch/powerpc/math-emu/spe.h
> @@ -0,0 +1 @@
> +#define __FPU_FPSCR	(current->thread.spefscr)
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/ 
> Makefile
> index 2621a7e..47f88b6 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_MMIO_NVRAM)	+= mmio_nvram.o
>  obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
>  obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
>  obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
> +obj-$(CONFIG_SPE)		+= sigfpe_handler.o
>
>  ifeq ($(CONFIG_PPC_MERGE),y)
>  obj-$(CONFIG_PPC_I8259)		+= i8259.o
> diff --git a/arch/powerpc/sysdev/sigfpe_handler.c b/arch/powerpc/ 
> sysdev/sigfpe_handler.c
> new file mode 100644
> index 0000000..8f9cfdb
> --- /dev/null
> +++ b/arch/powerpc/sysdev/sigfpe_handler.c
> @@ -0,0 +1,361 @@
> +/*
> + * arch/powerpc/sysdev/sigfpe_handler.c
> + *
> + * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights  
> reserved.
> + *
> + * Author: Ebony Zhu, ebony.zhu at freescale.com
> + *
> + * Derived from arch/powerpc/math-emu/math.c
> + * Copyright (C) 1999  Eddie C. Dost  (ecd at atecom.com)
> + *
> + * Description:
> + * This file is the exception handler to make E500 SPE instructions
> + * fully comply with IEEE-754 floating point standard.
> + *
> + * 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 <linux/types.h>
> +#include <asm/uaccess.h>
> +#include <asm/reg.h>
> +
> +#define SPEFUNC(x)	extern int x(void *, void *, void *, void *)
> +#define efdabs	fabs
> +#define efdneg	fneg
> +
> +/* Scalar SPFP functions */
> +SPEFUNC(efsabs);
> +SPEFUNC(efsadd);
> +SPEFUNC(efscfd);
> +SPEFUNC(efscmpeq);
> +SPEFUNC(efscmpgt);
> +SPEFUNC(efscmplt);
> +SPEFUNC(efsctsf);
> +SPEFUNC(efsctsi);
> +SPEFUNC(efsctsiz);
> +SPEFUNC(efsctuf);
> +SPEFUNC(efsctui);
> +SPEFUNC(efsctuiz);
> +SPEFUNC(efsdiv);
> +SPEFUNC(efsmul);
> +SPEFUNC(efsnabs);
> +SPEFUNC(efsneg);
> +SPEFUNC(efssub);
> +
> +/* Vector Floating-Point functions */
> +SPEFUNC(evfsabs);
> +SPEFUNC(evfsadd);
> +SPEFUNC(evfscmpeq);
> +SPEFUNC(evfscmpgt);
> +SPEFUNC(evfscmplt);
> +SPEFUNC(evfsctsf);
> +SPEFUNC(evfsctsi);
> +SPEFUNC(evfsctsiz);
> +SPEFUNC(evfsctuf);
> +SPEFUNC(evfsctui);
> +SPEFUNC(evfsctuiz);
> +SPEFUNC(evfsdiv);
> +SPEFUNC(evfsmul);
> +SPEFUNC(evfsnabs);
> +SPEFUNC(evfsneg);
> +SPEFUNC(evfssub);
> +
> +/* Scalar DPFP functions */
> +SPEFUNC(efdabs);
> +SPEFUNC(efdadd);
> +SPEFUNC(efdcfs);
> +SPEFUNC(efdcmpeq);
> +SPEFUNC(efdcmpgt);
> +SPEFUNC(efdcmplt);
> +SPEFUNC(efdctsf);
> +SPEFUNC(efdctsi);
> +SPEFUNC(efdctsidz);
> +SPEFUNC(efdctsiz);
> +SPEFUNC(efdctuf);
> +SPEFUNC(efdctui);
> +SPEFUNC(efdctuidz);
> +SPEFUNC(efdctuiz);
> +SPEFUNC(efddiv);
> +SPEFUNC(efdmul);
> +SPEFUNC(efdnabs);
> +SPEFUNC(efdneg);
> +SPEFUNC(efdsub);
> +
> +#define VCT		0x4
> +#define SPFP		0x6
> +#define DPFP		0x7
> +#define EFAPU		0x4
> +
> +#define EFSADD		0x2c0
> +#define EFSSUB		0x2c1
> +#define EFSABS		0x2c4
> +#define EFSNABS		0x2c5
> +#define EFSNEG		0x2c6
> +#define EFSMUL		0x2c8
> +#define EFSDIV		0x2c9
> +#define EFSCMPGT	0x2cc
> +#define EFSCMPLT	0x2cd
> +#define EFSCMPEQ	0x2ce
> +#define EFSCFD		0x2cf
> +#define EFSCTUI		0x2d4
> +#define EFSCTSI		0x2d5
> +#define EFSCTUF		0x2d6
> +#define EFSCTSF		0x2d7
> +#define EFSCTUIZ	0x2d8
> +#define EFSCTSIZ	0x2da
> +
> +#define EVFSADD		0x280
> +#define EVFSSUB		0x281
> +#define EVFSABS		0x284
> +#define EVFSNABS	0x285
> +#define EVFSNEG		0x286
> +#define EVFSMUL		0x288
> +#define EVFSDIV		0x289
> +#define EVFSCMPGT	0x28c
> +#define EVFSCMPLT	0x28d
> +#define EVFSCMPEQ	0x28e
> +#define EVFSCTUI	0x294
> +#define EVFSCTSI	0x295
> +#define EVFSCTUF	0x296
> +#define EVFSCTSF	0x297
> +#define EVFSCTUIZ	0x298
> +#define EVFSCTSIZ	0x29a
> +
> +#define EFDADD		0x2e0
> +#define EFDSUB		0x2e1
> +#define EFDABS		0x2e4
> +#define EFDNABS		0x2e5
> +#define EFDNEG		0x2e6
> +#define EFDMUL		0x2e8
> +#define EFDDIV		0x2e9
> +#define EFDCTUIDZ	0x2ea
> +#define EFDCTSIDZ	0x2eb
> +#define EFDCMPGT	0x2ec
> +#define EFDCMPLT	0x2ed
> +#define EFDCMPEQ	0x2ee
> +#define EFDCFS		0x2ef
> +#define EFDCTUI		0x2f4
> +#define EFDCTSI		0x2f5
> +#define EFDCTUF		0x2f6
> +#define EFDCTSF		0x2f7
> +#define EFDCTUIZ	0x2f8
> +#define EFDCTSIZ	0x2fa
> +
> +#define AB	2
> +#define XA	3
> +#define XB	4
> +#define XCR	5	
> +
> +static u64 fullgprs[32];
> +static u32 speinsn;
> +static int insn_decode(struct pt_regs *regs);
> +static int (*func)(void *, void *, void *, void *);
> +static void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0;
> +static int type = 0, flag;
> +
> +int
> +spedata_handler(struct pt_regs *regs)
> +{
> +	int i;
> +
> +	if (get_user(speinsn, (unsigned int __user *) regs->nip))
> +		return -EFAULT;
> +	if ((speinsn >> 26) != 4)
> +		return -EINVAL;         /* not an spe instruction */
> +	switch ((speinsn >> 5) & 0x7 ) {
> +	case SPFP:
> +		for(i = 0; i < 32; i++) {
> +			fullgprs[i] = regs->gpr[i];
> +			fullgprs[i] = fullgprs[i] << 32 | current->thread.evr[i];
> +		};
> +		break;
> +	default:
> +		for(i = 0; i < 32; i++) {
> +			fullgprs[i] = current->thread.evr[i];
> +			fullgprs[i] = (fullgprs[i] << 32) | (regs->gpr[i]);
> +		};
> +	}
> +	
> +	if (insn_decode(regs) == -ENOSYS) return -ENOSYS;
> +	flag = func(op0, op1, op2, op3);
> +	
> +	switch ((speinsn >> 5) & 0x7 ) {
> +	case SPFP:
> +		for (i = 0; i < 32; i++) {
> +			regs->gpr[i] = fullgprs[i] >> 32;
> +		};
> +		break;
> +	default:
> +		for (i = 0; i < 32; i++) {
> +			regs->gpr[i] = fullgprs[i];
> +			current->thread.evr[i] = fullgprs[i] >> 32;
> +		};
> +	}
> +	return 0;
> +}
> +
> +int
> +speround_handler(struct pt_regs *regs)
> +{
> +	u32 lsb_lo, lsb_hi;
> +	int s_lo, s_hi;
> +	int rD;
> +	
> +	if (get_user(speinsn, (unsigned int __user *) regs->nip))
> +		return -EFAULT;
> +	if ((speinsn >> 26) != 4)
> +		return -EINVAL;         /* not an spe instruction */
> +	
> +	rD = (speinsn >> 21) & 0x1f;
> +	flag = insn_decode(regs);
> +	if (type == XCR) return -ENOSYS;
> +
> +	s_lo = (regs->gpr[rD] & 0x80000000) >> 31;
> +	s_hi = (current->thread.evr[rD] & 0x80000000) >> 31;
> +	lsb_lo = regs->gpr[rD];
> +	lsb_hi = current->thread.evr[rD];
> +	switch ((speinsn >> 5) & 0x7 ) {
> +	/* Since SPE instructions on E500 core can handle round to nearest
> +	 * and round toward zero with IEEE-754 complied, we just need
> +	 * to handle round toward +Inf and round toward -Inf by software.
> +	 */
> +	case SPFP:
> +		if ((current->thread.spefscr & 0x3) == 0x2) { /* round to +Inf */
> +			if (!s_lo) lsb_lo++; /* Z > 0, choose Z1 */
> +		} else { /* round to -Inf */
> +			if (s_lo) lsb_lo++; /* Z < 0, choose Z2 */
> +		}
> +		regs->gpr[rD] = lsb_lo;
> +		break;
> +	case DPFP:
> +		fullgprs[rD] = current->thread.evr[rD];
> +		fullgprs[rD] = (fullgprs[rD] << 32) | (regs->gpr[rD]);
> +
> +		if ((current->thread.spefscr & 0x3) == 0x2) { /* round to +Inf */
> +			if (!s_hi) fullgprs[rD]++; /* Z > 0, choose Z1 */
> +		} else { /* round to -Inf */
> +			if (s_hi) fullgprs[rD]++; /* Z < 0, choose Z2 */
> +		}
> +		regs->gpr[rD] = fullgprs[rD];
> +		current->thread.evr[rD] = fullgprs[rD] >> 32;
> +		break;
> +	case VCT:
> +		if ((current->thread.spefscr & 0x3) == 0x2) { /* round to +Inf */
> +			if (!s_lo) lsb_lo++; /* Z_low > 0, choose Z1 */
> +			if (!s_hi) lsb_hi++; /* Z_high word > 0, choose Z1 */
> +		} else { /* round to -Inf */
> +			if (s_lo) lsb_lo++; /* Z_low < 0, choose Z2 */
> +			if (s_hi) lsb_hi++; /* Z_high < 0, choose Z2 */
> +		}
> +		regs->gpr[rD] = lsb_lo;
> +		current->thread.evr[rD] = lsb_hi;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}	
> +	return 0;
> +}
> +
> +static int insn_decode(struct pt_regs *regs)
> +{
> +	switch (speinsn >> 26) {
> +	
> +	case EFAPU:
> +		switch (speinsn & 0x7ff) {
> +		case EFSABS:	func = efsabs;		type = XA;	break;
> +		case EFSADD:	func = efsadd;		type = AB;      break;
> +		case EFSCFD:	func = efscfd;		type = XB;	break;
> +		case EFSCMPEQ:	func = efscmpeq;	type = XCR;	break;
> +		case EFSCMPGT:	func = efscmpgt;	type = XCR;	break;
> +		case EFSCMPLT:	func = efscmplt;	type = XCR;	break;
> +		case EFSCTSF:	func = efsctsf;		type = XB;	break;
> +		case EFSCTSI:	func = efsctsi;		type = XB;	break;
> +		case EFSCTSIZ:	func = efsctsiz;	type = XB;	break;
> +		case EFSCTUF:	func = efsctuf;		type = XB;	break;
> +		case EFSCTUI:	func = efsctui;		type = XB;	break;
> +		case EFSCTUIZ:	func = efsctuiz;	type = XB;	break;
> +		case EFSDIV:	func = efsdiv;		type = AB;	break;
> +		case EFSMUL:	func = efsmul;		type = AB;	break;
> +		case EFSNABS:	func = efsnabs;		type = XA;	break;
> +		case EFSNEG:	func = efsneg;		type = XA;	break;
> +		case EFSSUB:	func = efssub;		type = AB;	break;
> +
> +		case EVFSABS:	func = evfsabs;		type = XA;	break;
> +		case EVFSADD:	func = evfsadd;		type = AB;      break;
> +		case EVFSCMPEQ:	func = evfscmpeq;	type = XCR;	break;
> +		case EVFSCMPGT:	func = evfscmpgt;	type = XCR;	break;
> +		case EVFSCMPLT:	func = evfscmplt;	type = XCR;	break;
> +		case EVFSCTSF:	func = evfsctsf;	type = XB;	break;
> +		case EVFSCTSI:	func = evfsctsi;	type = XB;	break;
> +		case EVFSCTSIZ:	func = evfsctsiz;	type = XB;	break;
> +		case EVFSCTUF:	func = evfsctuf;	type = XB;	break;
> +		case EVFSCTUI:	func = evfsctui;	type = XB;	break;
> +		case EVFSCTUIZ:	func = evfsctuiz;	type = XB;	break;
> +		case EVFSDIV:	func = evfsdiv;		type = AB;	break;
> +		case EVFSMUL:	func = evfsmul;		type = AB;	break;
> +		case EVFSNABS:	func = evfsnabs;	type = XA;	break;
> +		case EVFSNEG:	func = evfsneg;		type = XA;	break;
> +		case EVFSSUB:	func = evfssub;		type = AB;	break;
> +
> +		case EFDABS:	func = efdabs;		type = XA;	break;
> +		case EFDADD:	func = efdadd;		type = AB;	break;
> +		case EFDCFS:	func = efdcfs;		type = XB;	break;
> +		case EFDCMPEQ:	func = efdcmpeq;	type = XCR;	break;
> +		case EFDCMPGT:	func = efdcmpgt;	type = XCR;	break;
> +		case EFDCMPLT:	func = efdcmplt;	type = XCR;	break;
> +		case EFDCTSF:	func = efdctsf;		type = XB;	break;
> +		case EFDCTSI:	func = efdctsi;		type = XB;	break;
> +		case EFDCTSIDZ:	func = efdctsidz;	type = XB;	break;
> +		case EFDCTSIZ:	func = efdctsiz;	type = XB;	break;
> +		case EFDCTUF:	func = efdctuf;		type = XB;	break;
> +		case EFDCTUI:	func = efdctui;		type = XB;	break;
> +		case EFDCTUIDZ:	func = efdctuidz;	type = XB;	break;
> +		case EFDCTUIZ:	func = efdctuiz;	type = XB;	break;
> +		case EFDDIV:	func = efddiv;		type = AB;	break;
> +		case EFDMUL:	func = efdmul;		type = AB;	break;
> +		case EFDNABS:	func = efdnabs;		type = XA;	break;
> +		case EFDNEG:	func = efdneg;		type = XA;	break;
> +		case EFDSUB:	func = efdsub;		type = AB;	break;		
> +		default:
> +			goto illegal;
> +		}
> +		break;
> +	default:
> +		goto illegal;
> +	}
> +
> +	switch (type) {
> +	case AB:
> +		op0 = &fullgprs[(speinsn >> 21) & 0x1f];
> +		op1 = &fullgprs[(speinsn >> 16) & 0x1f];
> +		op2 = &fullgprs[(speinsn >> 11) & 0x1f];
> +		break;
> +
> +	case XA:
> +		op0 = &fullgprs[(speinsn >> 21) & 0x1f];
> +		op1 = &fullgprs[(speinsn >> 16) & 0x1f];
> +		break;
> +
> +	case XB:
> +		op0 = &fullgprs[(speinsn >> 21) & 0x1f];
> +		op1 = &fullgprs[(speinsn >> 11) & 0x1f];
> +		break;
> +	
> +	case XCR:
> +		op0 = (void *)&regs->ccr;
> +		op1 = (void *)((speinsn >> 23) & 0x7);
> +		op2 = &fullgprs[(speinsn >> 16) & 0x1f];
> +		op3 = &fullgprs[(speinsn >> 11) & 0x1f];
> +		break;
> +
> +	default:
> +		goto illegal;
> +	}
> +	return 0;
> +illegal:
> +	printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered  
> un-supported instruction.\n");
> +	return -ENOSYS;
> +}
> -- 
> 1.4.0




More information about the Linuxppc-dev mailing list