File: /usr/src/linux/arch/arm/nwfpe/fpa11.c

1     /*
2         NetWinder Floating Point Emulator
3         (c) Rebel.COM, 1998,1999
4     
5         Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
6     
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.
11     
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.
16     
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.
20     */
21     
22     #include <asm/system.h>
23     
24     #include "fpa11.h"
25     #include "fpopcode.h"
26     
27     #include "fpmodule.h"
28     #include "fpmodule.inl"
29     
30     /* forward declarations */
31     unsigned int EmulateCPDO(const unsigned int);
32     unsigned int EmulateCPDT(const unsigned int);
33     unsigned int EmulateCPRT(const unsigned int);
34     
35     /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
36     void resetFPA11(void)
37     {
38       int i;
39       FPA11 *fpa11 = GET_FPA11();
40       
41       /* initialize the register type array */
42       for (i=0;i<=7;i++)
43       {
44         fpa11->fType[i] = typeNone;
45       }
46       
47       /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
48       fpa11->fpsr = FP_EMULATOR | BIT_AC;
49       
50       /* FPCR: set SB, AB and DA bits, clear all others */
51     #if MAINTAIN_FPCR
52       fpa11->fpcr = MASK_RESET;
53     #endif
54     }
55     
56     void SetRoundingMode(const unsigned int opcode)
57     {
58     #if MAINTAIN_FPCR
59        fpa11->fpcr &= ~MASK_ROUNDING_MODE;
60     #endif   
61        switch (opcode & MASK_ROUNDING_MODE)
62        {
63           default:
64           case ROUND_TO_NEAREST:
65              float_rounding_mode = float_round_nearest_even;
66     #if MAINTAIN_FPCR         
67              fpa11->fpcr |= ROUND_TO_NEAREST;
68     #endif         
69           break;
70           
71           case ROUND_TO_PLUS_INFINITY:
72              float_rounding_mode = float_round_up;
73     #if MAINTAIN_FPCR         
74              fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
75     #endif         
76           break;
77           
78           case ROUND_TO_MINUS_INFINITY:
79              float_rounding_mode = float_round_down;
80     #if MAINTAIN_FPCR         
81              fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
82     #endif         
83           break;
84           
85           case ROUND_TO_ZERO:
86              float_rounding_mode = float_round_to_zero;
87     #if MAINTAIN_FPCR         
88              fpa11->fpcr |= ROUND_TO_ZERO;
89     #endif         
90           break;
91       }
92     }
93     
94     void SetRoundingPrecision(const unsigned int opcode)
95     {
96     #if MAINTAIN_FPCR
97        fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
98     #endif   
99        switch (opcode & MASK_ROUNDING_PRECISION)
100        {
101           case ROUND_SINGLE:
102              floatx80_rounding_precision = 32;
103     #if MAINTAIN_FPCR         
104              fpa11->fpcr |= ROUND_SINGLE;
105     #endif         
106           break;
107           
108           case ROUND_DOUBLE:
109              floatx80_rounding_precision = 64;
110     #if MAINTAIN_FPCR         
111              fpa11->fpcr |= ROUND_DOUBLE;
112     #endif         
113           break;
114           
115           case ROUND_EXTENDED:
116              floatx80_rounding_precision = 80;
117     #if MAINTAIN_FPCR         
118              fpa11->fpcr |= ROUND_EXTENDED;
119     #endif         
120           break;
121           
122           default: floatx80_rounding_precision = 80;
123       }
124     }
125     
126     /* Emulate the instruction in the opcode. */
127     unsigned int EmulateAll(unsigned int opcode)
128     {
129       unsigned int nRc = 0;
130       unsigned long flags;
131       FPA11 *fpa11; 
132       save_flags(flags); sti();
133     
134       fpa11 = GET_FPA11();
135     
136       if (fpa11->initflag == 0)		/* good place for __builtin_expect */
137       {
138         resetFPA11();
139         SetRoundingMode(ROUND_TO_NEAREST);
140         SetRoundingPrecision(ROUND_EXTENDED);
141         fpa11->initflag = 1;
142       }
143     
144       if (TEST_OPCODE(opcode,MASK_CPRT))
145       {
146         /* Emulate conversion opcodes. */
147         /* Emulate register transfer opcodes. */
148         /* Emulate comparison opcodes. */
149         nRc = EmulateCPRT(opcode);
150       }
151       else if (TEST_OPCODE(opcode,MASK_CPDO))
152       {
153         /* Emulate monadic arithmetic opcodes. */
154         /* Emulate dyadic arithmetic opcodes. */
155         nRc = EmulateCPDO(opcode);
156       }
157       else if (TEST_OPCODE(opcode,MASK_CPDT))
158       {
159         /* Emulate load/store opcodes. */
160         /* Emulate load/store multiple opcodes. */
161         nRc = EmulateCPDT(opcode);
162       }
163       else
164       {
165         /* Invalid instruction detected.  Return FALSE. */
166         nRc = 0;
167       }
168     
169       restore_flags(flags);
170     
171       return(nRc);
172     }
173     
174     #if 0
175     unsigned int EmulateAll1(unsigned int opcode)
176     {
177       switch ((opcode >> 24) & 0xf)
178       {
179          case 0xc:
180          case 0xd:
181            if ((opcode >> 20) & 0x1)
182            {
183               switch ((opcode >> 8) & 0xf)
184               {
185                  case 0x1: return PerformLDF(opcode); break;
186                  case 0x2: return PerformLFM(opcode); break;
187                  default: return 0;
188               }
189            }
190            else
191            {
192               switch ((opcode >> 8) & 0xf)
193               {
194                  case 0x1: return PerformSTF(opcode); break;
195                  case 0x2: return PerformSFM(opcode); break;
196                  default: return 0;
197               }
198           }
199          break;
200          
201          case 0xe: 
202            if (opcode & 0x10)
203              return EmulateCPDO(opcode);
204            else
205              return EmulateCPRT(opcode);
206          break;
207       
208          default: return 0;
209       }
210     }
211     #endif
212     
213