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