| ~ | | I've tested this by writing a MIPS assembly test that converts a test set of words to
|
| ~ | | floats. For example:: |
| | ~ | I've tested this in two ways: 1) by writing a MIPS assembly test that
|
| | ~ | converts a test set of words to floats, and 2) in a C++ isolation test. |
| | |
|
| ~ | | TEST( cvt.s.w, 0x4372a3d5, 0x4e86e548 )
|
| ~ | | TEST( cvt.s.w, 0xffffffff, 0xbf800000 ) |
| | ~ | MIPS assembly test |
| | ~ |
|
| | + | I've compiled some handwritten assembly like this:: |
| | + |
|
| | + | TEST( cvt.s.w, 0x4372a3d5, 0x4e86e548 )
|
| | + | TEST( cvt.s.w, 0xffffffff, 0xbf800000 ) |
| | | |
| | |
|
| | | .. where TEST is a test macro that uses the instruction in arg0 with the data in arg1.
|
| ~ | | The reference output is in arg2. |
| | ~ | The reference output is in arg2. |
| | |
|
| | | The objdump looks like this for each test:: |
| | |
|
| ~ | | 808000: 3c024372 lui v0,0x4372
|
| ~ | | 808004: 3442a3d5 ori v0,v0,0xa3d5
|
| ~ | | 808008: 46801120 cvt.s.w a0,v0
|
| ~ | | 80800c: 241d000d li sp,13
|
| ~ | | 808010: 3c014e86 lui at,0x4e86
|
| ~ | | 808014: 3421e548 ori at,at,0xe548
|
| ~ | | 808018: 14810095 bne a0,at,808270 <_fail> |
| | ~ | 808000: 3c024372 lui v0,0x4372
|
| | ~ | 808004: 3442a3d5 ori v0,v0,0xa3d5 |
| | ~ | 808008: 46801120 cvt.s.w a0,v0 |
| | ~ | 80800c: 3c014e86 lui at,0x4e86 |
| | ~ | 808010: 3421e548 ori at,at,0xe548 |
| | ~ | 808014: 14810095 bne a0,at,808270 <_fail> |
| | ~ | |
| | |
|
| | | $V0 gets the src data. $A0 gets the fp-converted data. $AT gets the reference data.
|
| ~ | | We branch to fail code if they don't match. |
| | ~ | We branch to fail code if they don't match. |
| | + |
|
| | + | All negative number tests fail without this patch. |
| | + |
|
| | + | C++ testing |
| | + |
|
| | + | I copied the fpConvert() function and the ConvertType enum to a separate C++
|
| | + | test file to test in isolation. |
| | + |
|
| | + | fptest.cc:: |
| | + |
|
| | + | |
| | + | #include <stdint.h> |
| | + | |
| | + | //used in FP convert & round function |
| | + | enum ConvertType{ |
| | + | SINGLE_TO_DOUBLE, |
| | + | SINGLE_TO_WORD, |
| | + | SINGLE_TO_LONG, |
| | + | |
| | + | DOUBLE_TO_SINGLE, |
| | + | DOUBLE_TO_WORD, |
| | + | DOUBLE_TO_LONG, |
| | + | |
| | + | LONG_TO_SINGLE, |
| | + | LONG_TO_DOUBLE, |
| | + | LONG_TO_WORD, |
| | + | LONG_TO_PS, |
| | + | |
| | + | WORD_TO_SINGLE, |
| | + | WORD_TO_DOUBLE, |
| | + | WORD_TO_LONG, |
| | + | WORD_TO_PS, |
| | + | |
| | + | PL_TO_SINGLE, |
| | + | PU_TO_SINGLE |
| | + | }; |
| | + | |
| | + | uint64_t |
| | + | fpConvert(ConvertType cvt_type, double fp_val) |
| | + | { |
| | + | |
| | + | switch (cvt_type) |
| | + | { |
| | + | case SINGLE_TO_DOUBLE: |
| | + | { |
| | + | double sdouble_val = fp_val; |
| | + | void *sdouble_ptr = &sdouble_val; |
| | + | uint64_t sdp_bits = *(uint64_t *) sdouble_ptr; |
| | + | return sdp_bits; |
| | + | } |
| | + | |
| | + | case SINGLE_TO_WORD: |
| | + | { |
| | + | int32_t sword_val = (int32_t) fp_val; |
| | + | void *sword_ptr = &sword_val; |
| | + | uint64_t sword_bits= *(uint32_t *) sword_ptr; |
| | + | return sword_bits; |
| | + | } |
| | + | |
| | + | case WORD_TO_SINGLE: |
| | + | { |
| | + | float wfloat_val = fp_val; |
| | + | void *wfloat_ptr = &wfloat_val; |
| | + | uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr; |
| | + | return wfloat_bits; |
| | + | } |
| | + | |
| | + | case WORD_TO_DOUBLE: |
| | + | { |
| | + | double wdouble_val = fp_val; |
| | + | void *wdouble_ptr = &wdouble_val; |
| | + | uint64_t wdp_bits = *(uint64_t *) wdouble_ptr; |
| | + | return wdp_bits; |
| | + | } |
| | + | |
| | + | default: |
| | + | std::cout << "ERROR" << std::endl; |
| | + | return 0; |
| | + | } |
| | + | } |
| | + | |
| | + | int main(int argc, const char *argv[]) |
| | + | { |
| | + | uint32_t test_value_original = 0xffffffff; |
| | + | int32_t test_value_patched = 0xffffffff; |
| | + | |
| | + | uint64_t converted_value_original = fpConvert(WORD_TO_SINGLE, test_value_original); |
| | + | uint64_t converted_value_patched = fpConvert(WORD_TO_SINGLE, test_value_patched); |
| | + | |
| | + | std::cout << std::hex << converted_value_original << std::endl; |
| | + | std::cout << std::hex << converted_value_patched << std::endl; |
| | + | |
| | + | return 0; |
| | + | } |
| | + | |
| | + |
|
| | + | In main, I print out the fpConvert'ed values for 0xffffffff inputs wrapped
|
| | + | inside uint32_t and int32_t. The output is:: |
| | + |
|
| | + | |
| | + | bf800000 |
| | + | |
| | |
|
| ~ | | Without this bug fix, all negative number tests fail. |
| | ~ | 0xBF800000 is the expected value (-1 in single precision floating point).
|
| | + | 0x4F800000 is MAX_INT in single precision floating point -- not what we
|
| | + | want. |