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

1     /*
2         NetWinder Floating Point Emulator
3         (c) Rebel.com, 1998-1999
4         (c) Philip Blundell, 1998
5     
6         Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7     
8         This program is free software; you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation; either version 2 of the License, or
11         (at your option) any later version.
12     
13         This program is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17     
18         You should have received a copy of the GNU General Public License
19         along with this program; if not, write to the Free Software
20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     */
22     
23     #include "softfloat.h"
24     #include "fpopcode.h"
25     #include "fpa11.h"
26     #include "fpmodule.h"
27     #include "fpmodule.inl"
28     
29     #include <asm/uaccess.h>
30     
31     static inline
32     void loadSingle(const unsigned int Fn,const unsigned int *pMem)
33     {
34        FPA11 *fpa11 = GET_FPA11();
35        fpa11->fType[Fn] = typeSingle;
36        get_user(fpa11->fpreg[Fn].fSingle, pMem);
37     }
38     
39     static inline
40     void loadDouble(const unsigned int Fn,const unsigned int *pMem)
41     {
42        FPA11 *fpa11 = GET_FPA11();
43        unsigned int *p;
44        p = (unsigned int*)&fpa11->fpreg[Fn].fDouble;
45        fpa11->fType[Fn] = typeDouble;
46        get_user(p[0], &pMem[1]);
47        get_user(p[1], &pMem[0]); /* sign & exponent */
48     }   
49     
50     static inline
51     void loadExtended(const unsigned int Fn,const unsigned int *pMem)
52     {
53        FPA11 *fpa11 = GET_FPA11();
54        unsigned int *p;
55        p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
56        fpa11->fType[Fn] = typeExtended;
57        get_user(p[0], &pMem[0]);  /* sign & exponent */
58        get_user(p[1], &pMem[2]);  /* ls bits */
59        get_user(p[2], &pMem[1]);  /* ms bits */
60     }   
61     
62     static inline
63     void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
64     {
65        FPA11 *fpa11 = GET_FPA11();
66        register unsigned int *p;
67        unsigned long x;
68     
69        p = (unsigned int*)&(fpa11->fpreg[Fn]);
70        get_user(x, &pMem[0]);
71        fpa11->fType[Fn] = (x >> 14) & 0x00000003;
72        
73        switch (fpa11->fType[Fn])
74        {
75           case typeSingle:
76           case typeDouble:
77           {
78              get_user(p[0], &pMem[2]);  /* Single */
79              get_user(p[1], &pMem[1]);  /* double msw */
80              p[2] = 0;        /* empty */
81           }
82           break; 
83        
84           case typeExtended:
85           {
86              get_user(p[1], &pMem[2]);
87              get_user(p[2], &pMem[1]);  /* msw */
88              p[0] = (x & 0x80003fff);      
89           }
90           break;
91        }
92     }
93     
94     static inline
95     void storeSingle(const unsigned int Fn,unsigned int *pMem)
96     {
97        FPA11 *fpa11 = GET_FPA11();
98        float32 val;
99        register unsigned int *p = (unsigned int*)&val;
100        
101        switch (fpa11->fType[Fn])
102        {
103           case typeDouble: 
104              val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
105           break;
106     
107           case typeExtended: 
108              val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
109           break;
110     
111           default: val = fpa11->fpreg[Fn].fSingle;
112        }
113       
114        put_user(p[0], pMem);
115     }   
116     
117     static inline
118     void storeDouble(const unsigned int Fn,unsigned int *pMem)
119     {
120        FPA11 *fpa11 = GET_FPA11();
121        float64 val;
122        register unsigned int *p = (unsigned int*)&val;
123     
124        switch (fpa11->fType[Fn])
125        {
126           case typeSingle: 
127              val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
128           break;
129     
130           case typeExtended:
131              val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
132           break;
133     
134           default: val = fpa11->fpreg[Fn].fDouble;
135        }
136        put_user(p[1], &pMem[0]);	/* msw */
137        put_user(p[0], &pMem[1]);	/* lsw */
138     }   
139     
140     static inline
141     void storeExtended(const unsigned int Fn,unsigned int *pMem)
142     {
143        FPA11 *fpa11 = GET_FPA11();
144        floatx80 val;
145        register unsigned int *p = (unsigned int*)&val;
146        
147        switch (fpa11->fType[Fn])
148        {
149           case typeSingle: 
150              val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
151           break;
152     
153           case typeDouble: 
154              val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
155           break;
156     
157           default: val = fpa11->fpreg[Fn].fExtended;
158        }
159        
160        put_user(p[0], &pMem[0]); /* sign & exp */
161        put_user(p[1], &pMem[2]);
162        put_user(p[2], &pMem[1]); /* msw */
163     }   
164     
165     static inline
166     void storeMultiple(const unsigned int Fn,unsigned int *pMem)
167     {
168        FPA11 *fpa11 = GET_FPA11();
169        register unsigned int nType, *p;
170        
171        p = (unsigned int*)&(fpa11->fpreg[Fn]);
172        nType = fpa11->fType[Fn];
173        
174        switch (nType)
175        {
176           case typeSingle:
177           case typeDouble:
178           {
179     	 put_user(p[0], &pMem[2]); /* single */
180     	 put_user(p[1], &pMem[1]); /* double msw */
181     	 put_user(nType << 14, &pMem[0]);
182           }
183           break; 
184        
185           case typeExtended:
186           {
187     	 put_user(p[2], &pMem[1]); /* msw */
188     	 put_user(p[1], &pMem[2]);
189     	 put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
190           }
191           break;
192        }
193     }
194     
195     unsigned int PerformLDF(const unsigned int opcode)
196     {
197        unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
198          write_back = WRITE_BACK(opcode);
199     
200        //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
201     
202        pBase = (unsigned int*)readRegister(getRn(opcode));
203        if (REG_PC == getRn(opcode))
204        {
205          pBase += 2;
206          write_back = 0;
207        }
208     
209        pFinal = pBase;
210        if (BIT_UP_SET(opcode))
211          pFinal += getOffset(opcode);
212        else
213          pFinal -= getOffset(opcode);
214     
215        if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
216     
217        switch (opcode & MASK_TRANSFER_LENGTH)
218        {
219           case TRANSFER_SINGLE  : loadSingle(getFd(opcode),pAddress);   break;
220           case TRANSFER_DOUBLE  : loadDouble(getFd(opcode),pAddress);   break;
221           case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
222           default: nRc = 0;
223        }
224        
225        if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
226        return nRc;
227     }
228     
229     unsigned int PerformSTF(const unsigned int opcode)
230     {
231        unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
232          write_back = WRITE_BACK(opcode);
233        
234        //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
235        SetRoundingMode(ROUND_TO_NEAREST);
236        
237        pBase = (unsigned int*)readRegister(getRn(opcode));
238        if (REG_PC == getRn(opcode))
239        {
240          pBase += 2;
241          write_back = 0;
242        }
243     
244        pFinal = pBase;
245        if (BIT_UP_SET(opcode))
246          pFinal += getOffset(opcode);
247        else
248          pFinal -= getOffset(opcode);
249     
250        if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
251     
252        switch (opcode & MASK_TRANSFER_LENGTH)
253        {
254           case TRANSFER_SINGLE  : storeSingle(getFd(opcode),pAddress);   break;
255           case TRANSFER_DOUBLE  : storeDouble(getFd(opcode),pAddress);   break;
256           case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
257           default: nRc = 0;
258        }
259        
260        if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
261        return nRc;
262     }
263     
264     unsigned int PerformLFM(const unsigned int opcode)
265     {
266        unsigned int i, Fd, *pBase, *pAddress, *pFinal,
267          write_back = WRITE_BACK(opcode);
268     
269        pBase = (unsigned int*)readRegister(getRn(opcode));
270        if (REG_PC == getRn(opcode))
271        {
272          pBase += 2;
273          write_back = 0;
274        }
275     
276        pFinal = pBase;
277        if (BIT_UP_SET(opcode))
278          pFinal += getOffset(opcode);
279        else
280          pFinal -= getOffset(opcode);
281     
282        if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
283     
284        Fd = getFd(opcode);
285        for (i=getRegisterCount(opcode);i>0;i--)
286        {
287          loadMultiple(Fd,pAddress);
288          pAddress += 3; Fd++;
289          if (Fd == 8) Fd = 0;
290        }
291     
292        if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
293        return 1;
294     }
295     
296     unsigned int PerformSFM(const unsigned int opcode)
297     {
298        unsigned int i, Fd, *pBase, *pAddress, *pFinal,
299          write_back = WRITE_BACK(opcode);
300        
301        pBase = (unsigned int*)readRegister(getRn(opcode));
302        if (REG_PC == getRn(opcode))
303        {
304          pBase += 2;
305          write_back = 0;
306        }
307        
308        pFinal = pBase;
309        if (BIT_UP_SET(opcode))
310          pFinal += getOffset(opcode);
311        else
312          pFinal -= getOffset(opcode);
313     
314        if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
315     
316        Fd = getFd(opcode);
317        for (i=getRegisterCount(opcode);i>0;i--)
318        {
319          storeMultiple(Fd,pAddress);
320          pAddress += 3; Fd++;
321          if (Fd == 8) Fd = 0;
322        }
323     
324        if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
325        return 1;
326     }
327     
328     #if 1
329     unsigned int EmulateCPDT(const unsigned int opcode)
330     {
331       unsigned int nRc = 0;
332     
333       //printk("EmulateCPDT(0x%08x)\n",opcode);
334       
335       if (LDF_OP(opcode))
336       {
337         nRc = PerformLDF(opcode);
338       }
339       else if (LFM_OP(opcode))
340       {
341         nRc = PerformLFM(opcode);
342       }
343       else if (STF_OP(opcode))
344       {
345         nRc = PerformSTF(opcode);
346       } 
347       else if (SFM_OP(opcode))
348       {
349         nRc = PerformSFM(opcode);
350       }
351       else
352       {
353         nRc = 0;
354       }
355       
356       return nRc;
357     }
358     #endif
359