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