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