Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fpa11_cpdo.c
Go to the documentation of this file.
1 /*
2  NetWinder Floating Point Emulator
3  (c) Rebel.COM, 1998,1999
4  (c) Philip Blundell, 2001
5 
6  Direct questions, comments to Scott Bambrough <[email protected]>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 
23 #include "fpa11.h"
24 #include "fpopcode.h"
25 
26 unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
27 unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
28 unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
29 
30 unsigned int EmulateCPDO(const unsigned int opcode)
31 {
32  FPA11 *fpa11 = GET_FPA11();
33  FPREG *rFd;
34  unsigned int nType, nDest, nRc;
35  struct roundingData roundData;
36 
37  /* Get the destination size. If not valid let Linux perform
38  an invalid instruction trap. */
39  nDest = getDestinationSize(opcode);
40  if (typeNone == nDest)
41  return 0;
42 
43  roundData.mode = SetRoundingMode(opcode);
44  roundData.precision = SetRoundingPrecision(opcode);
45  roundData.exception = 0;
46 
47  /* Compare the size of the operands in Fn and Fm.
48  Choose the largest size and perform operations in that size,
49  in order to make use of all the precision of the operands.
50  If Fm is a constant, we just grab a constant of a size
51  matching the size of the operand in Fn. */
52  if (MONADIC_INSTRUCTION(opcode))
53  nType = nDest;
54  else
55  nType = fpa11->fType[getFn(opcode)];
56 
57  if (!CONSTANT_FM(opcode)) {
58  register unsigned int Fm = getFm(opcode);
59  if (nType < fpa11->fType[Fm]) {
60  nType = fpa11->fType[Fm];
61  }
62  }
63 
64  rFd = &fpa11->fpreg[getFd(opcode)];
65 
66  switch (nType) {
67  case typeSingle:
68  nRc = SingleCPDO(&roundData, opcode, rFd);
69  break;
70  case typeDouble:
71  nRc = DoubleCPDO(&roundData, opcode, rFd);
72  break;
73 #ifdef CONFIG_FPE_NWFPE_XP
74  case typeExtended:
75  nRc = ExtendedCPDO(&roundData, opcode, rFd);
76  break;
77 #endif
78  default:
79  nRc = 0;
80  }
81 
82  /* The CPDO functions used to always set the destination type
83  to be the same as their working size. */
84 
85  if (nRc != 0) {
86  /* If the operation succeeded, check to see if the result in the
87  destination register is the correct size. If not force it
88  to be. */
89 
90  fpa11->fType[getFd(opcode)] = nDest;
91 
92 #ifdef CONFIG_FPE_NWFPE_XP
93  if (nDest != nType) {
94  switch (nDest) {
95  case typeSingle:
96  {
97  if (typeDouble == nType)
98  rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
99  else
100  rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
101  }
102  break;
103 
104  case typeDouble:
105  {
106  if (typeSingle == nType)
107  rFd->fDouble = float32_to_float64(rFd->fSingle);
108  else
109  rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
110  }
111  break;
112 
113  case typeExtended:
114  {
115  if (typeSingle == nType)
116  rFd->fExtended = float32_to_floatx80(rFd->fSingle);
117  else
118  rFd->fExtended = float64_to_floatx80(rFd->fDouble);
119  }
120  break;
121  }
122  }
123 #else
124  if (nDest != nType) {
125  if (nDest == typeSingle)
126  rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
127  else
128  rFd->fDouble = float32_to_float64(rFd->fSingle);
129  }
130 #endif
131  }
132 
133  if (roundData.exception)
134  float_raise(roundData.exception);
135 
136  return nRc;
137 }