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