LDS

From Msim

Jump to: navigation, search

This page refers to the LDS instruction.

Details

LDS loads from memory an single precision floating point.

lds Ra, Sign Extended Offset(Rb)
Ra is a floating point register
Rb is a general purpose register
Ra = Memory[Sign Extended Offset + Rb]

The result in Ra is a double precision value. Therefore, it must be converted from single to double precision.

Implementation

#define LDS_IMPL                                                       \
{                                                                      \
       sqword_t _longhold, _e1, _e2;                                   \
       enum md_fault_type _fault;                                      \
                                                                       \
       _longhold = READ_WORD(GPR(RB) + SEXT(OFS), _fault);             \
       if(_fault != md_fault_none)                                     \
               DECLARE_FAULT(_fault);                                  \
                                                                       \
       _e1 = _longhold & 0x40000000;                                   \
       _e2 = (_longhold >> 23) & ULL(0x7f);                            \
       if(_e1)                                                         \
       {                                                               \
               if(_e2 == ULL(0x7f))                                    \
                       _e2 = ULL(0x7ff);                               \
               else                                                    \
                       _e2 |= ULL(0x400);                              \
       }                                                               \
       else                                                            \
       {                                                               \
               if(_e2 != 0)                                            \
                       _e2 |= ULL(0x380);                              \
       }                                                               \
       SET_FPR_Q(RA, ((_longhold & ULL(0x80000000)) << 32              \
               | _e2 << 52 | (_longhold & ULL(0x7fffff)) << 29));      \
}


Correction

In the original code:

#define LDS_IMPL                                                       \
 {                                                                     \
   sqword_t _longhold, _e1, _e2;                                       \
   enum md_fault_type _fault;                                          \
                                                                       \
   _longhold = READ_WORD(GPR(RB) + SEXT(OFS), _fault);                 \
   if (_fault != md_fault_none)                                        \
     DECLARE_FAULT(_fault);                                            \
                                                                       \
   _e1 = _longhold & 0x40000000;                                       \
   _e2 = (_longhold >> 23) & ULL(0x7f);                                \
   if (_e1)                                                            \
     {                                                                 \
       if (_e2 == ULL(0x3f800000))                                     \
         _e2 = ULL(0x7ff);                                             \
       else                                                            \
         _e2 |= ULL(0x400);                                            \
     }                                                                 \
   else                                                                \
     {                                                                 \
       if (_e2 == 0)                                                   \
         _e2 = 0;                                                      \
       else                                                            \
         _e2 |= ULL(0x380);                                            \
     }                                                                 \
   SET_FPR_Q(RA, ((_longhold & ULL(0x80000000)) << 32                  \
                  | _e2 << 52 | (_longhold & ULL(0x7fffff)) << 29));   \
 }

The first bolded part is incorrect:

  • _e2 is bitmasked with 0x7f (lowest 7 bits) and theref3re can never equal 0x3f800000. Since the code changed _e2 to 0x7ff, this reflects an all 1s exponent in double precision. The correct check is for 0x7f which reflect 7 of the 8 exponent bits from a single precision value (_e1 retains the MSB exponent bit). If the _e2 hadn't been shifted (and been bitmasked for only the exponent bits) the original check would have been correct.


The second bolded part was fine but has been optimized:

  • e2 was not changed if it equaled zero. It would be ORed with 0x380 if it was not equal to zero. Therefore, we change the case to check and change on _e2 != 0 only.
Personal tools