Statistics
| Branch: | Revision:

root / linux-user / arm / nwfpe / fpa11_cpdt.c @ d084469c

History | View | Annotate | Download (9.3 kB)

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, 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(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
#ifdef WORDS_BIGENDIAN
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
#ifdef WORDS_BIGENDIAN
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 (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 (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 (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 (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