qemu/linux-user/arm/nwfpe/fpa11_cpdt.c
<<
>>
Prefs
   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
  31static inline
  32void 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
  40static inline
  41void 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 HOST_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
  58static inline
  59void 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
  71static inline
  72void 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
 106static inline
 107void 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
 130static inline
 131void 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 HOST_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
 159static inline
 160void 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
 185static inline
 186void 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
 215static 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
 250static 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
 286static 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
 319static 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
 353unsigned 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