0.7.0-alt1
[qemu] / qemu / target-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 "fpa11.h"
24 #include "softfloat.h"
25 #include "fpopcode.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 #ifdef WORDS_BIGENDIAN
47    get_user(p[0], &pMem[0]); /* sign & exponent */
48    get_user(p[1], &pMem[1]);
49 #else
50    get_user(p[0], &pMem[1]);
51    get_user(p[1], &pMem[0]); /* sign & exponent */
52 #endif
53 }   
54
55 static inline
56 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
57 {
58    FPA11 *fpa11 = GET_FPA11();
59    unsigned int *p;
60    p = (unsigned int*)&fpa11->fpreg[Fn].fExtended;
61    fpa11->fType[Fn] = typeExtended;
62    get_user(p[0], &pMem[0]);  /* sign & exponent */
63    get_user(p[1], &pMem[2]);  /* ls bits */
64    get_user(p[2], &pMem[1]);  /* ms bits */
65 }   
66
67 static inline
68 void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
69 {
70    FPA11 *fpa11 = GET_FPA11();
71    register unsigned int *p;
72    unsigned long x;
73
74    p = (unsigned int*)&(fpa11->fpreg[Fn]);
75    get_user(x, &pMem[0]);
76    fpa11->fType[Fn] = (x >> 14) & 0x00000003;
77    
78    switch (fpa11->fType[Fn])
79    {
80       case typeSingle:
81       case typeDouble:
82       {
83          get_user(p[0], &pMem[2]);  /* Single */
84          get_user(p[1], &pMem[1]);  /* double msw */
85          p[2] = 0;        /* empty */
86       }
87       break; 
88    
89       case typeExtended:
90       {
91          get_user(p[1], &pMem[2]);
92          get_user(p[2], &pMem[1]);  /* msw */
93          p[0] = (x & 0x80003fff);      
94       }
95       break;
96    }
97 }
98
99 static inline
100 void storeSingle(const unsigned int Fn,unsigned int *pMem)
101 {
102    FPA11 *fpa11 = GET_FPA11();
103    float32 val;
104    register unsigned int *p = (unsigned int*)&val;
105    
106    switch (fpa11->fType[Fn])
107    {
108       case typeDouble: 
109          val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
110       break;
111
112       case typeExtended: 
113          val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
114       break;
115
116       default: val = fpa11->fpreg[Fn].fSingle;
117    }
118   
119    put_user(p[0], pMem);
120 }   
121
122 static inline
123 void storeDouble(const unsigned int Fn,unsigned int *pMem)
124 {
125    FPA11 *fpa11 = GET_FPA11();
126    float64 val;
127    register unsigned int *p = (unsigned int*)&val;
128
129    switch (fpa11->fType[Fn])
130    {
131       case typeSingle: 
132          val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
133       break;
134
135       case typeExtended:
136          val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
137       break;
138
139       default: val = fpa11->fpreg[Fn].fDouble;
140    }
141 #ifdef WORDS_BIGENDIAN
142    put_user(p[0], &pMem[0]);    /* msw */
143    put_user(p[1], &pMem[1]);    /* lsw */
144 #else
145    put_user(p[1], &pMem[0]);    /* msw */
146    put_user(p[0], &pMem[1]);    /* lsw */
147 #endif
148 }   
149
150 static inline
151 void storeExtended(const unsigned int Fn,unsigned int *pMem)
152 {
153    FPA11 *fpa11 = GET_FPA11();
154    floatx80 val;
155    register unsigned int *p = (unsigned int*)&val;
156    
157    switch (fpa11->fType[Fn])
158    {
159       case typeSingle: 
160          val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
161       break;
162
163       case typeDouble: 
164          val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
165       break;
166
167       default: val = fpa11->fpreg[Fn].fExtended;
168    }
169    
170    put_user(p[0], &pMem[0]); /* sign & exp */
171    put_user(p[1], &pMem[2]);
172    put_user(p[2], &pMem[1]); /* msw */
173 }   
174
175 static inline
176 void storeMultiple(const unsigned int Fn,unsigned int *pMem)
177 {
178    FPA11 *fpa11 = GET_FPA11();
179    register unsigned int nType, *p;
180    
181    p = (unsigned int*)&(fpa11->fpreg[Fn]);
182    nType = fpa11->fType[Fn];
183    
184    switch (nType)
185    {
186       case typeSingle:
187       case typeDouble:
188       {
189          put_user(p[0], &pMem[2]); /* single */
190          put_user(p[1], &pMem[1]); /* double msw */
191          put_user(nType << 14, &pMem[0]);
192       }
193       break; 
194    
195       case typeExtended:
196       {
197          put_user(p[2], &pMem[1]); /* msw */
198          put_user(p[1], &pMem[2]);
199          put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
200       }
201       break;
202    }
203 }
204
205 unsigned int PerformLDF(const unsigned int opcode)
206 {
207    unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
208      write_back = WRITE_BACK(opcode);
209
210    //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
211
212    pBase = (unsigned int*)readRegister(getRn(opcode));
213    if (REG_PC == getRn(opcode))
214    {
215      pBase += 2;
216      write_back = 0;
217    }
218
219    pFinal = pBase;
220    if (BIT_UP_SET(opcode))
221      pFinal += getOffset(opcode);
222    else
223      pFinal -= getOffset(opcode);
224
225    if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
226
227    switch (opcode & MASK_TRANSFER_LENGTH)
228    {
229       case TRANSFER_SINGLE  : loadSingle(getFd(opcode),pAddress);   break;
230       case TRANSFER_DOUBLE  : loadDouble(getFd(opcode),pAddress);   break;
231       case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
232       default: nRc = 0;
233    }
234    
235    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
236    return nRc;
237 }
238
239 unsigned int PerformSTF(const unsigned int opcode)
240 {
241    unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
242      write_back = WRITE_BACK(opcode);
243    
244    //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
245    SetRoundingMode(ROUND_TO_NEAREST);
246    
247    pBase = (unsigned int*)readRegister(getRn(opcode));
248    if (REG_PC == getRn(opcode))
249    {
250      pBase += 2;
251      write_back = 0;
252    }
253
254    pFinal = pBase;
255    if (BIT_UP_SET(opcode))
256      pFinal += getOffset(opcode);
257    else
258      pFinal -= getOffset(opcode);
259
260    if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
261
262    switch (opcode & MASK_TRANSFER_LENGTH)
263    {
264       case TRANSFER_SINGLE  : storeSingle(getFd(opcode),pAddress);   break;
265       case TRANSFER_DOUBLE  : storeDouble(getFd(opcode),pAddress);   break;
266       case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
267       default: nRc = 0;
268    }
269    
270    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
271    return nRc;
272 }
273
274 unsigned int PerformLFM(const unsigned int opcode)
275 {
276    unsigned int i, Fd, *pBase, *pAddress, *pFinal,
277      write_back = WRITE_BACK(opcode);
278
279    pBase = (unsigned int*)readRegister(getRn(opcode));
280    if (REG_PC == getRn(opcode))
281    {
282      pBase += 2;
283      write_back = 0;
284    }
285
286    pFinal = pBase;
287    if (BIT_UP_SET(opcode))
288      pFinal += getOffset(opcode);
289    else
290      pFinal -= getOffset(opcode);
291
292    if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
293
294    Fd = getFd(opcode);
295    for (i=getRegisterCount(opcode);i>0;i--)
296    {
297      loadMultiple(Fd,pAddress);
298      pAddress += 3; Fd++;
299      if (Fd == 8) Fd = 0;
300    }
301
302    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
303    return 1;
304 }
305
306 unsigned int PerformSFM(const unsigned int opcode)
307 {
308    unsigned int i, Fd, *pBase, *pAddress, *pFinal,
309      write_back = WRITE_BACK(opcode);
310    
311    pBase = (unsigned int*)readRegister(getRn(opcode));
312    if (REG_PC == getRn(opcode))
313    {
314      pBase += 2;
315      write_back = 0;
316    }
317    
318    pFinal = pBase;
319    if (BIT_UP_SET(opcode))
320      pFinal += getOffset(opcode);
321    else
322      pFinal -= getOffset(opcode);
323
324    if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
325
326    Fd = getFd(opcode);
327    for (i=getRegisterCount(opcode);i>0;i--)
328    {
329      storeMultiple(Fd,pAddress);
330      pAddress += 3; Fd++;
331      if (Fd == 8) Fd = 0;
332    }
333
334    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
335    return 1;
336 }
337
338 #if 1
339 unsigned int EmulateCPDT(const unsigned int opcode)
340 {
341   unsigned int nRc = 0;
342
343   //printk("EmulateCPDT(0x%08x)\n",opcode);
344   
345   if (LDF_OP(opcode))
346   {
347     nRc = PerformLDF(opcode);
348   }
349   else if (LFM_OP(opcode))
350   {
351     nRc = PerformLFM(opcode);
352   }
353   else if (STF_OP(opcode))
354   {
355     nRc = PerformSTF(opcode);
356   } 
357   else if (SFM_OP(opcode))
358   {
359     nRc = PerformSFM(opcode);
360   }
361   else
362   {
363     nRc = 0;
364   }
365   
366   return nRc;
367 }
368 #endif