2 NetWinder Floating Point Emulator
3 (c) Rebel.com, 1998-1999
5 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "fpmodule.inl"
30 /* forward declarations */
31 unsigned int EmulateCPDO(const unsigned int);
32 unsigned int EmulateCPDT(const unsigned int);
33 unsigned int EmulateCPRT(const unsigned int);
35 /* Emulator registers */
38 /* Reset the FPA11 chip. Called to initialize and reset the emulator. */
42 /* initialize the registers */
45 fpa11
->fpreg
[i
].fType
= typeNone
;
48 /* FPSR: set system id to FP_EMULATOR, clear all other bits */
49 fpa11
->fpsr
= FP_EMULATOR
;
51 /* FPCR: set SB, AB and DA bits, clear all others */
53 fpa11
->fpcr
= MASK_RESET
;
57 void SetRoundingMode(const unsigned int opcode
)
60 fpa11
->fpcr
&= ~MASK_ROUNDING_MODE
;
62 switch (opcode
& MASK_ROUNDING_MODE
)
65 case ROUND_TO_NEAREST
:
66 float_rounding_mode
= float_round_nearest_even
;
68 fpa11
->fpcr
|= ROUND_TO_NEAREST
;
72 case ROUND_TO_PLUS_INFINITY
:
73 float_rounding_mode
= float_round_up
;
75 fpa11
->fpcr
|= ROUND_TO_PLUS_INFINITY
;
79 case ROUND_TO_MINUS_INFINITY
:
80 float_rounding_mode
= float_round_down
;
82 fpa11
->fpcr
|= ROUND_TO_MINUS_INFINITY
;
87 float_rounding_mode
= float_round_to_zero
;
89 fpa11
->fpcr
|= ROUND_TO_ZERO
;
95 void SetRoundingPrecision(const unsigned int opcode
)
98 fpa11
->fpcr
&= ~MASK_ROUNDING_PRECISION
;
100 switch (opcode
& MASK_ROUNDING_PRECISION
)
103 floatx80_rounding_precision
= 32;
105 fpa11
->fpcr
|= ROUND_SINGLE
;
110 floatx80_rounding_precision
= 64;
112 fpa11
->fpcr
|= ROUND_DOUBLE
;
117 floatx80_rounding_precision
= 80;
119 fpa11
->fpcr
|= ROUND_EXTENDED
;
123 default: floatx80_rounding_precision
= 80;
127 /* Emulate the instruction in the opcode. */
128 unsigned int EmulateAll(unsigned int opcode
)
130 unsigned int nRc
= 0;
132 if (fpa11
->initflag
== 0) /* good place for __builtin_expect */
135 SetRoundingMode(ROUND_TO_NEAREST
);
136 SetRoundingPrecision(ROUND_EXTENDED
);
140 if (TEST_OPCODE(opcode
,MASK_CPRT
))
142 /* Emulate conversion opcodes. */
143 /* Emulate register transfer opcodes. */
144 /* Emulate comparison opcodes. */
145 nRc
= EmulateCPRT(opcode
);
147 else if (TEST_OPCODE(opcode
,MASK_CPDO
))
149 /* Emulate monadic arithmetic opcodes. */
150 /* Emulate dyadic arithmetic opcodes. */
151 nRc
= EmulateCPDO(opcode
);
153 else if (TEST_OPCODE(opcode
,MASK_CPDT
))
155 /* Emulate load/store opcodes. */
156 /* Emulate load/store multiple opcodes. */
157 nRc
= EmulateCPDT(opcode
);
161 /* Invalid instruction detected. Return FALSE. */
169 unsigned int EmulateAll1(unsigned int opcode
)
171 switch ((opcode
>> 24) & 0xf)
175 if ((opcode
>> 20) & 0x1)
177 switch ((opcode
>> 8) & 0xf)
179 case 0x1: return PerformLDF(opcode
); break;
180 case 0x2: return PerformLFM(opcode
); break;
186 switch ((opcode
>> 8) & 0xf)
188 case 0x1: return PerformSTF(opcode
); break;
189 case 0x2: return PerformSFM(opcode
); break;
197 return EmulateCPDO(opcode
);
199 return EmulateCPRT(opcode
);