~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to linux-user/arm/nwfpe/fpa11_cpdt.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "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