Blame view

arch/arm/nwfpe/fpa11_cpdo.c 3.75 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
      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.
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  #include "fpa11.h"
  #include "fpopcode.h"
f148af259   Richard Purdie   [PATCH] ARM: 2837...
24
25
26
  unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
  
  unsigned int EmulateCPDO(const unsigned int opcode)
  {
  	FPA11 *fpa11 = GET_FPA11();
  	FPREG *rFd;
  	unsigned int nType, nDest, nRc;
f148af259   Richard Purdie   [PATCH] ARM: 2837...
33
  	struct roundingData roundData;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
  
  	/* Get the destination size.  If not valid let Linux perform
  	   an invalid instruction trap. */
  	nDest = getDestinationSize(opcode);
  	if (typeNone == nDest)
  		return 0;
f148af259   Richard Purdie   [PATCH] ARM: 2837...
40
41
42
  	roundData.mode = SetRoundingMode(opcode);
  	roundData.precision = SetRoundingPrecision(opcode);
  	roundData.exception = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  	/* Compare the size of the operands in Fn and Fm.
  	   Choose the largest size and perform operations in that size,
  	   in order to make use of all the precision of the operands.
  	   If Fm is a constant, we just grab a constant of a size
  	   matching the size of the operand in Fn. */
  	if (MONADIC_INSTRUCTION(opcode))
  		nType = nDest;
  	else
  		nType = fpa11->fType[getFn(opcode)];
  
  	if (!CONSTANT_FM(opcode)) {
  		register unsigned int Fm = getFm(opcode);
  		if (nType < fpa11->fType[Fm]) {
  			nType = fpa11->fType[Fm];
  		}
  	}
  
  	rFd = &fpa11->fpreg[getFd(opcode)];
  
  	switch (nType) {
  	case typeSingle:
f148af259   Richard Purdie   [PATCH] ARM: 2837...
65
  		nRc = SingleCPDO(&roundData, opcode, rFd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  		break;
  	case typeDouble:
f148af259   Richard Purdie   [PATCH] ARM: 2837...
68
  		nRc = DoubleCPDO(&roundData, opcode, rFd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
  		break;
  #ifdef CONFIG_FPE_NWFPE_XP
  	case typeExtended:
f148af259   Richard Purdie   [PATCH] ARM: 2837...
72
  		nRc = ExtendedCPDO(&roundData, opcode, rFd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  		break;
  #endif
  	default:
  		nRc = 0;
  	}
  
  	/* The CPDO functions used to always set the destination type
  	   to be the same as their working size. */
  
  	if (nRc != 0) {
  		/* If the operation succeeded, check to see if the result in the
  		   destination register is the correct size.  If not force it
  		   to be. */
  
  		fpa11->fType[getFd(opcode)] = nDest;
  
  #ifdef CONFIG_FPE_NWFPE_XP
  		if (nDest != nType) {
  			switch (nDest) {
  			case typeSingle:
  				{
  					if (typeDouble == nType)
f148af259   Richard Purdie   [PATCH] ARM: 2837...
95
  						rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  					else
f148af259   Richard Purdie   [PATCH] ARM: 2837...
97
  						rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
  				}
  				break;
  
  			case typeDouble:
  				{
  					if (typeSingle == nType)
  						rFd->fDouble = float32_to_float64(rFd->fSingle);
  					else
f148af259   Richard Purdie   [PATCH] ARM: 2837...
106
  						rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  				}
  				break;
  
  			case typeExtended:
  				{
  					if (typeSingle == nType)
  						rFd->fExtended = float32_to_floatx80(rFd->fSingle);
  					else
  						rFd->fExtended = float64_to_floatx80(rFd->fDouble);
  				}
  				break;
  			}
  		}
  #else
  		if (nDest != nType) {
  			if (nDest == typeSingle)
f148af259   Richard Purdie   [PATCH] ARM: 2837...
123
  				rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
126
127
128
  			else
  				rFd->fDouble = float32_to_float64(rFd->fSingle);
  		}
  #endif
  	}
f148af259   Richard Purdie   [PATCH] ARM: 2837...
129
130
  	if (roundData.exception)
  		float_raise(roundData.exception);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
  	return nRc;
  }