|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/*
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 "fpopcode.h"
unsigned int EmulateCPDO(const unsigned int opcode)
{
FPA11 *fpa11 = GET_FPA11();
unsigned int Fd, nType, nDest, nRc = 1;
|
ths
authored
|
29
|
|
|
30
31
32
33
34
35
|
//printk("EmulateCPDO(0x%08x)\n",opcode);
/* Get the destination size. If not valid let Linux perform
an invalid instruction trap. */
nDest = getDestinationSize(opcode);
if (typeNone == nDest) return 0;
|
ths
authored
|
36
|
|
|
37
|
SetRoundingMode(opcode);
|
ths
authored
|
38
|
|
|
39
40
|
/* Compare the size of the operands in Fn and Fm.
Choose the largest size and perform operations in that size,
|
ths
authored
|
41
42
|
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
|
|
43
44
45
46
47
|
matching the size of the operand in Fn. */
if (MONADIC_INSTRUCTION(opcode))
nType = nDest;
else
nType = fpa11->fType[getFn(opcode)];
|
ths
authored
|
48
|
|
|
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
if (!CONSTANT_FM(opcode))
{
register unsigned int Fm = getFm(opcode);
if (nType < fpa11->fType[Fm])
{
nType = fpa11->fType[Fm];
}
}
switch (nType)
{
case typeSingle : nRc = SingleCPDO(opcode); break;
case typeDouble : nRc = DoubleCPDO(opcode); break;
case typeExtended : nRc = ExtendedCPDO(opcode); break;
default : 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. */
Fd = getFd(opcode);
nType = fpa11->fType[Fd];
if ((0 != nRc) && (nDest != nType))
{
switch (nDest)
{
case typeSingle:
{
if (typeDouble == nType)
|
ths
authored
|
78
|
fpa11->fpreg[Fd].fSingle =
|
|
79
|
float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
|
|
80
|
else
|
ths
authored
|
81
|
fpa11->fpreg[Fd].fSingle =
|
|
82
|
floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
|
|
83
84
|
}
break;
|
ths
authored
|
85
|
|
|
86
87
88
|
case typeDouble:
{
if (typeSingle == nType)
|
ths
authored
|
89
|
fpa11->fpreg[Fd].fDouble =
|
|
90
|
float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
|
|
91
|
else
|
ths
authored
|
92
|
fpa11->fpreg[Fd].fDouble =
|
|
93
|
floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
|
|
94
95
|
}
break;
|
ths
authored
|
96
|
|
|
97
98
99
|
case typeExtended:
{
if (typeSingle == nType)
|
ths
authored
|
100
|
fpa11->fpreg[Fd].fExtended =
|
|
101
|
float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
|
|
102
|
else
|
ths
authored
|
103
|
fpa11->fpreg[Fd].fExtended =
|
|
104
|
float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
|
|
105
106
107
|
}
break;
}
|
ths
authored
|
108
|
|
|
109
110
|
fpa11->fType[Fd] = nDest;
}
|
ths
authored
|
111
|
|
|
112
113
|
return nRc;
}
|