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