v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / 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