diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/arm/nwfpe |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/arm/nwfpe')
-rw-r--r-- | arch/arm/nwfpe/ARM-gcc.h | 120 | ||||
-rw-r--r-- | arch/arm/nwfpe/ChangeLog | 91 | ||||
-rw-r--r-- | arch/arm/nwfpe/Makefile | 13 | ||||
-rw-r--r-- | arch/arm/nwfpe/double_cpdo.c | 167 | ||||
-rw-r--r-- | arch/arm/nwfpe/entry.S | 119 | ||||
-rw-r--r-- | arch/arm/nwfpe/entry26.S | 112 | ||||
-rw-r--r-- | arch/arm/nwfpe/extended_cpdo.c | 154 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11.c | 143 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11.h | 93 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11.inl | 51 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11_cpdo.c | 132 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11_cpdt.c | 392 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpa11_cprt.c | 369 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpmodule.c | 173 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpmodule.h | 47 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpmodule.inl | 74 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpopcode.c | 90 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpopcode.h | 479 | ||||
-rw-r--r-- | arch/arm/nwfpe/fpsr.h | 108 | ||||
-rw-r--r-- | arch/arm/nwfpe/milieu.h | 48 | ||||
-rw-r--r-- | arch/arm/nwfpe/single_cpdo.c | 124 | ||||
-rw-r--r-- | arch/arm/nwfpe/softfloat-macros | 740 | ||||
-rw-r--r-- | arch/arm/nwfpe/softfloat-specialize | 366 | ||||
-rw-r--r-- | arch/arm/nwfpe/softfloat.c | 3443 | ||||
-rw-r--r-- | arch/arm/nwfpe/softfloat.h | 278 |
25 files changed, 7926 insertions, 0 deletions
diff --git a/arch/arm/nwfpe/ARM-gcc.h b/arch/arm/nwfpe/ARM-gcc.h new file mode 100644 index 00000000000..e6598470b07 --- /dev/null +++ b/arch/arm/nwfpe/ARM-gcc.h @@ -0,0 +1,120 @@ +/* +------------------------------------------------------------------------------- +The macro `BITS64' can be defined to indicate that 64-bit integer types are +supported by the compiler. +------------------------------------------------------------------------------- +*/ +#define BITS64 + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines the most convenient type that holds +integers of at least as many bits as specified. For example, `uint8' should +be the most convenient type that can hold unsigned integers of as many as +8 bits. The `flag' type must be able to hold either a 0 or 1. For most +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +to the same as `int'. +------------------------------------------------------------------------------- +*/ +typedef char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines a type that holds integers +of _exactly_ the number of bits specified. For instance, for most +implementation of C, `bits16' and `sbits16' should be `typedef'ed to +`unsigned short int' and `signed short int' (or `short int'), respectively. +------------------------------------------------------------------------------- +*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short int bits16; +typedef signed short int sbits16; +typedef unsigned int bits32; +typedef signed int sbits32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +#ifdef BITS64 +/* +------------------------------------------------------------------------------- +The `LIT64' macro takes as its argument a textual integer literal and if +necessary ``marks'' the literal as having a 64-bit integer type. For +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be +appended with the letters `LL' standing for `long long', which is `gcc's +name for the 64-bit integer type. Some compilers may allow `LIT64' to be +defined as the identity macro: `#define LIT64( a ) a'. +------------------------------------------------------------------------------- +*/ +#define LIT64( a ) a##LL +#endif + +/* +------------------------------------------------------------------------------- +The macro `INLINE' can be used before functions that should be inlined. If +a compiler does not support explicit inlining, this macro should be defined +to be `static'. +------------------------------------------------------------------------------- +*/ +#define INLINE extern __inline__ + + +/* For use as a GCC soft-float library we need some special function names. */ + +#ifdef __LIBFLOAT__ + +/* Some 32-bit ops can be mapped straight across by just changing the name. */ +#define float32_add __addsf3 +#define float32_sub __subsf3 +#define float32_mul __mulsf3 +#define float32_div __divsf3 +#define int32_to_float32 __floatsisf +#define float32_to_int32_round_to_zero __fixsfsi +#define float32_to_uint32_round_to_zero __fixunssfsi + +/* These ones go through the glue code. To avoid namespace pollution + we rename the internal functions too. */ +#define float32_eq ___float32_eq +#define float32_le ___float32_le +#define float32_lt ___float32_lt + +/* All the 64-bit ops have to go through the glue, so we pull the same + trick. */ +#define float64_add ___float64_add +#define float64_sub ___float64_sub +#define float64_mul ___float64_mul +#define float64_div ___float64_div +#define int32_to_float64 ___int32_to_float64 +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero +#define float64_to_float32 ___float64_to_float32 +#define float32_to_float64 ___float32_to_float64 +#define float64_eq ___float64_eq +#define float64_le ___float64_le +#define float64_lt ___float64_lt + +#if 0 +#define float64_add __adddf3 +#define float64_sub __subdf3 +#define float64_mul __muldf3 +#define float64_div __divdf3 +#define int32_to_float64 __floatsidf +#define float64_to_int32_round_to_zero __fixdfsi +#define float64_to_uint32_round_to_zero __fixunsdfsi +#define float64_to_float32 __truncdfsf2 +#define float32_to_float64 __extendsfdf2 +#endif + +#endif diff --git a/arch/arm/nwfpe/ChangeLog b/arch/arm/nwfpe/ChangeLog new file mode 100644 index 00000000000..eeb5a7c5ff0 --- /dev/null +++ b/arch/arm/nwfpe/ChangeLog @@ -0,0 +1,91 @@ +2003-03-22 Ralph Siemsen <ralphs@netwinder.org> + * Reformat all but softfloat files to get a consistent coding style. + Used "indent -kr -i8 -ts8 -sob -l132 -ss" and a few manual fixups. + * Removed dead code and fixed function protypes to match definitions. + * Consolidated use of (opcode && MASK_ARITHMETIC_OPCODE) >> 20. + * Make 80-bit precision a compile-time option. (1%) + * Only initialize FPE state once in repeat-FP situations. (6%) + +2002-01-19 Russell King <rmk@arm.linux.org.uk> + + * fpa11.h - Add documentation + - remove userRegisters pointer from this structure. + - add new method to obtain integer register values. + * softfloat.c - Remove float128 + * softfloat.h - Remove float128 + * softfloat-specialize - Remove float128 + + * The FPA11 structure is not a kernel-specific data structure. + It is used by users of ptrace to examine the values of the + floating point registers. Therefore, any changes to the + FPA11 structure (size or position of elements contained + within) have to be well thought out. + + * Since 128-bit float requires the FPA11 structure to change + size, it has been removed. 128-bit float is currently unused, + and needs various things to be re-worked so that we won't + overflow the available space in the task structure. + + * The changes are designed to break any patch that goes on top + of this code, so that the authors properly review their changes. + +1999-08-19 Scott Bambrough <scottb@netwinder.org> + + * fpmodule.c - Changed version number to 0.95 + * fpa11.h - modified FPA11, FPREG structures + * fpa11.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdt.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cprt.c - Changes due to FPA11, FPREG structure alterations. + * single_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * double_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * extended_cpdo.c - Changes due to FPA11, FPREG structure alterations. + + * I discovered several bugs. First and worst is that the kernel + passes in a pointer to the FPE's state area. This is defined + as a struct user_fp (see user.h). This pointer was cast to a + FPA11*. Unfortunately FPA11 and user_fp are of different sizes; + user_fp is smaller. This meant that the FPE scribbled on things + below its area, which is bad, as the area is in the thread_struct + embedded in the process task structure. Thus we were scribbling + over one of the most important structures in the entire OS. + + * user_fp and FPA11 have now been harmonized. Most of the changes + in the above code were dereferencing problems due to moving the + register type out of FPREG, and getting rid of the union variable + fpvalue. + + * Second I noticed resetFPA11 was not always being called for a + task. This should happen on the first floating point exception + that occurs. It is controlled by init_flag in FPA11. The + comment in the code beside init_flag state the kernel guarantees + this to be zero. Not so. I found that the kernel recycles task + structures, and that recycled ones may not have init_flag zeroed. + I couldn't even find anything that guarantees it is zeroed when + when the task structure is initially allocated. In any case + I now initialize the entire FPE state in the thread structure to + zero when allocated and recycled. See alloc_task_struct() and + flush_thread() in arch/arm/process.c. The change to + alloc_task_struct() may not be necessary, but I left it in for + completeness (better safe than sorry). + +1998-11-23 Scott Bambrough <scottb@netwinder.org> + + * README.FPE - fix typo in description of lfm/sfm instructions + * NOTES - Added file to describe known bugs/problems + * fpmodule.c - Changed version number to 0.94 + +1998-11-20 Scott Bambrough <scottb@netwinder.org> + + * README.FPE - fix description of URD, NRM instructions + * TODO - remove URD, NRM instructions from TODO list + * single_cpdo.c - implement URD, NRM + * double_cpdo.c - implement URD, NRM + * extended_cpdo.c - implement URD, NRM + +1998-11-19 Scott Bambrough <scottb@netwinder.org> + + * ChangeLog - Added this file to track changes made. + * fpa11.c - added code to initialize register types to typeNone + * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to + typeDouble in switch statement) diff --git a/arch/arm/nwfpe/Makefile b/arch/arm/nwfpe/Makefile new file mode 100644 index 00000000000..ed7b26bf73f --- /dev/null +++ b/arch/arm/nwfpe/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 1998, 1999, 2001 Philip Blundell +# + +obj-$(CONFIG_FPE_NWFPE) += nwfpe.o + +nwfpe-y += fpa11.o fpa11_cpdo.o fpa11_cpdt.o \ + fpa11_cprt.o fpmodule.o fpopcode.o \ + softfloat.o single_cpdo.o double_cpdo.o + +nwfpe-$(CONFIG_FPE_NWFPE_XP) += extended_cpdo.o +nwfpe-$(CONFIG_CPU_26) += entry26.o +nwfpe-$(CONFIG_CPU_32) += entry.o diff --git a/arch/arm/nwfpe/double_cpdo.c b/arch/arm/nwfpe/double_cpdo.c new file mode 100644 index 00000000000..7ffd8cb9bc9 --- /dev/null +++ b/arch/arm/nwfpe/double_cpdo.c @@ -0,0 +1,167 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +union float64_components { + float64 f64; + unsigned int i[2]; +}; + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn, float64 rFm); +float64 float64_pol(float64 rFn, float64 rFm); + +static float64 float64_rsf(float64 rFn, float64 rFm) +{ + return float64_sub(rFm, rFn); +} + +static float64 float64_rdv(float64 rFn, float64 rFm) +{ + return float64_div(rFm, rFn); +} + +static float64 (*const dyadic_double[16])(float64 rFn, float64 rFm) = { + [ADF_CODE >> 20] = float64_add, + [MUF_CODE >> 20] = float64_mul, + [SUF_CODE >> 20] = float64_sub, + [RSF_CODE >> 20] = float64_rsf, + [DVF_CODE >> 20] = float64_div, + [RDF_CODE >> 20] = float64_rdv, + [RMF_CODE >> 20] = float64_rem, + + /* strictly, these opcodes should not be implemented */ + [FML_CODE >> 20] = float64_mul, + [FDV_CODE >> 20] = float64_div, + [FRD_CODE >> 20] = float64_rdv, +}; + +static float64 float64_mvf(float64 rFm) +{ + return rFm; +} + +static float64 float64_mnf(float64 rFm) +{ + union float64_components u; + + u.f64 = rFm; +#ifdef __ARMEB__ + u.i[0] ^= 0x80000000; +#else + u.i[1] ^= 0x80000000; +#endif + + return u.f64; +} + +static float64 float64_abs(float64 rFm) +{ + union float64_components u; + + u.f64 = rFm; +#ifdef __ARMEB__ + u.i[0] &= 0x7fffffff; +#else + u.i[1] &= 0x7fffffff; +#endif + + return u.f64; +} + +static float64 (*const monadic_double[16])(float64 rFm) = { + [MVF_CODE >> 20] = float64_mvf, + [MNF_CODE >> 20] = float64_mnf, + [ABS_CODE >> 20] = float64_abs, + [RND_CODE >> 20] = float64_round_to_int, + [URD_CODE >> 20] = float64_round_to_int, + [SQT_CODE >> 20] = float64_sqrt, + [NRM_CODE >> 20] = float64_mvf, +}; + +unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 rFm; + unsigned int Fm, opc_mask_shift; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) { + rFm = getDoubleConstant(Fm); + } else { + switch (fpa11->fType[Fm]) { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fDouble; + break; + + default: + return 0; + } + } + + opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20; + if (!MONADIC_INSTRUCTION(opcode)) { + unsigned int Fn = getFn(opcode); + float64 rFn; + + switch (fpa11->fType[Fn]) { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fDouble; + break; + + default: + return 0; + } + + if (dyadic_double[opc_mask_shift]) { + rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm); + } else { + return 0; + } + } else { + if (monadic_double[opc_mask_shift]) { + rFd->fDouble = monadic_double[opc_mask_shift](rFm); + } else { + return 0; + } + } + + return 1; +} diff --git a/arch/arm/nwfpe/entry.S b/arch/arm/nwfpe/entry.S new file mode 100644 index 00000000000..1dc13bc6d81 --- /dev/null +++ b/arch/arm/nwfpe/entry.S @@ -0,0 +1,119 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998 + (c) 1998, 1999 Philip Blundell + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + sub r4, r5, #4 + ldrt r0, [r4] @ r0 = instruction + adrsvc al, r9, ret_from_exception @ r9 = normal FP return + adrsvc al, lr, fpundefinstr @ lr = undefined instr return + + get_current_task r10 + mov r8, #1 + strb r8, [r10, #TSK_USED_MATH] @ set current->used_math + add r10, r10, #TSS_FPESAVE @ r10 = workspace + ldr r4, .LC2 + ldr pc, [r4] @ Call FP emulator entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception (passed in +r9) and the kernel takes care of returning control from the trap to +the user code. If the emulator is unable to emulate the instruction, +it returns via _fpundefinstr (passed via lr) and the kernel halts the +user program with a core dump. + +On entry to the emulator r10 points to an area of private FP workspace +reserved in the thread structure for this process. This is where the +emulator saves its registers across calls. The first word of this area +is used as a flag to detect the first time a process uses floating point, +so that the emulator startup cost can be avoided for tasks that don't +want it. + +This routine does three things: + +1) The kernel has created a struct pt_regs on the stack and saved the +user registers into it. See /usr/include/asm/proc/ptrace.h for details. + +2) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +3) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + mov r4, lr @ save the failure-return addresses + mov sl, sp @ we access the registers via 'sl' + + ldr r5, [sp, #60] @ get contents of PC; +emulate: + bl EmulateAll @ emulate the instruction + cmp r0, #0 @ was emulation successful + moveq pc, r4 @ no, return failure + +next: +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + movne pc, r9 @ return ok if not a fp insn + + str r5, [sp, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + ldr r1, [sp, #64] @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + b emulate @ if r0 != 0, goto EmulateAll + + @ We need to be prepared for the instructions at .Lx1 and .Lx2 + @ to fault. Emit the appropriate exception gunk to fix things up. + @ ??? For some reason, faults can happen at .Lx2 even with a + @ plain LDR instruction. Weird, but it seems harmless. + .section .fixup,"ax" + .align 2 +.Lfix: mov pc, r9 @ let the user eat segfaults + .previous + + .section __ex_table,"a" + .align 3 + .long .Lx1, .Lfix + .previous diff --git a/arch/arm/nwfpe/entry26.S b/arch/arm/nwfpe/entry26.S new file mode 100644 index 00000000000..0ed38b0913d --- /dev/null +++ b/arch/arm/nwfpe/entry26.S @@ -0,0 +1,112 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <asm/constants.h> + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + mov fp, #0 + teqp pc, #PSR_I_BIT | MODE_SVC + ldr r4, .LC2 + ldr pc, [r4] @ Call FP module USR entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception and the +kernel takes care of returning control from the trap to the user code. +If the emulator is unable to emulate the instruction, it returns to +fpundefinstr and the kernel halts the user program with a core dump. + +This routine does four things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It locates the FP emulator work area within the TSS structure and +points `fpa11' to it. + +3) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +4) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + mov sl, sp + ldr r5, [sp, #60] @ get contents of PC + bic r5, r5, #0xfc000003 + ldr r0, [r5, #-4] @ get actual instruction into r0 + bl EmulateAll @ emulate the instruction +1: cmp r0, #0 @ was emulation successful + beq fpundefinstr @ no, return failure + +next: +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + bne ret_from_exception @ return ok if not a fp insn + + ldr r9, [sp, #60] @ get new condition codes + and r9, r9, #0xfc000003 + orr r7, r5, r9 + str r7, [sp, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + mov r1, r9 @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + adr lr, 1b + orr lr, lr, #3 + b EmulateAll @ if r0 != 0, goto EmulateAll + +.Lret: b ret_from_exception @ let the user eat segfaults + + @ We need to be prepared for the instruction at .Lx1 to fault. + @ Emit the appropriate exception gunk to fix things up. + .section __ex_table,"a" + .align 3 + .long .Lx1 + ldr lr, [lr, $(.Lret - .Lx1)/4] + .previous diff --git a/arch/arm/nwfpe/extended_cpdo.c b/arch/arm/nwfpe/extended_cpdo.c new file mode 100644 index 00000000000..c39f68a3449 --- /dev/null +++ b/arch/arm/nwfpe/extended_cpdo.c @@ -0,0 +1,154 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn, floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn, floatx80 rFm); + +static floatx80 floatx80_rsf(floatx80 rFn, floatx80 rFm) +{ + return floatx80_sub(rFm, rFn); +} + +static floatx80 floatx80_rdv(floatx80 rFn, floatx80 rFm) +{ + return floatx80_div(rFm, rFn); +} + +static floatx80 (*const dyadic_extended[16])(floatx80 rFn, floatx80 rFm) = { + [ADF_CODE >> 20] = floatx80_add, + [MUF_CODE >> 20] = floatx80_mul, + [SUF_CODE >> 20] = floatx80_sub, + [RSF_CODE >> 20] = floatx80_rsf, + [DVF_CODE >> 20] = floatx80_div, + [RDF_CODE >> 20] = floatx80_rdv, + [RMF_CODE >> 20] = floatx80_rem, + + /* strictly, these opcodes should not be implemented */ + [FML_CODE >> 20] = floatx80_mul, + [FDV_CODE >> 20] = floatx80_div, + [FRD_CODE >> 20] = floatx80_rdv, +}; + +static floatx80 floatx80_mvf(floatx80 rFm) +{ + return rFm; +} + +static floatx80 floatx80_mnf(floatx80 rFm) +{ + rFm.high ^= 0x8000; + return rFm; +} + +static floatx80 floatx80_abs(floatx80 rFm) +{ + rFm.high &= 0x7fff; + return rFm; +} + +static floatx80 (*const monadic_extended[16])(floatx80 rFm) = { + [MVF_CODE >> 20] = floatx80_mvf, + [MNF_CODE >> 20] = floatx80_mnf, + [ABS_CODE >> 20] = floatx80_abs, + [RND_CODE >> 20] = floatx80_round_to_int, + [URD_CODE >> 20] = floatx80_round_to_int, + [SQT_CODE >> 20] = floatx80_sqrt, + [NRM_CODE >> 20] = floatx80_mvf, +}; + +unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 rFm; + unsigned int Fm, opc_mask_shift; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) { + rFm = getExtendedConstant(Fm); + } else { + switch (fpa11->fType[Fm]) { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: + return 0; + } + } + + opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20; + if (!MONADIC_INSTRUCTION(opcode)) { + unsigned int Fn = getFn(opcode); + floatx80 rFn; + + switch (fpa11->fType[Fn]) { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: + return 0; + } + + if (dyadic_extended[opc_mask_shift]) { + rFd->fExtended = dyadic_extended[opc_mask_shift](rFn, rFm); + } else { + return 0; + } + } else { + if (monadic_extended[opc_mask_shift]) { + rFd->fExtended = monadic_extended[opc_mask_shift](rFm); + } else { + return 0; + } + } + + return 1; +} diff --git a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c new file mode 100644 index 00000000000..bf61696865e --- /dev/null +++ b/arch/arm/nwfpe/fpa11.c @@ -0,0 +1,143 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 2001 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.org> + + 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "fpopcode.h" + +#include "fpmodule.h" +#include "fpmodule.inl" + +#include <linux/config.h> +#include <linux/compiler.h> +#include <linux/string.h> +#include <asm/system.h> + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int |