Home | History | Annotate | Download | only in useful
      1 
      2 /* Testing framework, for developing code to copy vex's x87 simulation
      3    state to and from a real x87 state image (the 108-byte thing).
      4 
      5    Includes code from fp_80_64.c.
      6 */
      7 
      8 #include "../pub/libvex_basictypes.h"
      9 #include "../pub/libvex_ir.h"
     10 #include "../priv/guest-x86/gdefs.h"
     11 #include <stdio.h>
     12 #include <assert.h>
     13 #include <stdlib.h>
     14 
     15 /* Get definitions of convert_f64le_to_f80le and
     16    convert_f80le_to_f64le. */
     17 #define USED_AS_INCLUDE
     18 #include "fp_80_64.c"
     19 #undef  USED_AS_INCLUDE
     20 
     21 
     22 ////////////////////////////////////////////////////////////////
     23 
     24 /* Layout of the real x87 state. */
     25 
     26 typedef
     27    struct {
     28       UShort env[14];
     29       UChar  reg[80];
     30    }
     31    Fpu_State;
     32 
     33 /* Offsets, in 16-bit ints, into the FPU environment (env) area. */
     34 #define FP_ENV_CTRL   0
     35 #define FP_ENV_STAT   2
     36 #define FP_ENV_TAG    4
     37 #define FP_ENV_IP     6 /* and 7 */
     38 #define FP_ENV_CS     8
     39 #define FP_ENV_OPOFF  10 /* and 11 */
     40 #define FP_ENV_OPSEL  12
     41 #define FP_REG(ii)    (10*(7-(ii)))
     42 
     43 
     44 /* Layout of vex's FP state is defined in ../priv/guest-x86/gdefs.h */
     45 
     46 static void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
     47 {
     48    Int        r;
     49    UInt       tag;
     50    Double*    vexRegs = (Double*)(vex_state + OFFB_F0);
     51    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
     52    Fpu_State* x87     = (Fpu_State*)x87_state;
     53    UInt       ftop    = (x87->env[FP_ENV_STAT] >> 11) & 7;
     54    UInt       tagw    = x87->env[FP_ENV_TAG];
     55 
     56    /* Copy registers and tags */
     57    for (r = 0; r < 8; r++) {
     58       tag = (tagw >> (2*r)) & 3;
     59       if (tag == 3) {
     60          /* register is empty */
     61          vexRegs[r] = 0.0;
     62          vexTags[r] = 0;
     63       } else {
     64          /* register is non-empty */
     65          convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] );
     66          vexTags[r] = 1;
     67       }
     68    }
     69 
     70    /* stack pointer */
     71    *(UInt*)(vex_state + OFFB_FTOP) = ftop;
     72 
     73    /* TODO: Check the CW is 037F.  Or at least, bottom 6 bits are 1
     74       (all exceptions masked), and 11:10, which is rounding control,
     75       is set to ..?
     76    */
     77 }
     78 
     79 
     80 static void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
     81 {
     82    Int        i, r;
     83    UInt       tagw;
     84    Double*    vexRegs = (Double*)(vex_state + OFFB_F0);
     85    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
     86    Fpu_State* x87     = (Fpu_State*)x87_state;
     87    UInt       ftop    = *(UInt*)(vex_state + OFFB_FTOP);
     88 
     89    for (i = 0; i < 14; i++)
     90       x87->env[i] = 0;
     91 
     92    x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
     93    x87->env[FP_ENV_CTRL] = 0x037F;
     94    x87->env[FP_ENV_STAT] = (ftop & 7) << 11;
     95 
     96    tagw = 0;
     97    for (r = 0; r < 8; r++) {
     98       if (vexTags[r] == 0) {
     99          /* register is empty */
    100          tagw |= (3 << (2*r));
    101          convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
    102       } else {
    103          /* register is full. */
    104          tagw |= (0 << (2*r));
    105          convert_f64le_to_f80le( (UChar*)&vexRegs[r],  &x87->reg[FP_REG(r)] );
    106       }
    107    }
    108    x87->env[FP_ENV_TAG] = tagw;
    109 }
    110 
    111 ////////////////////////////////////////////////////////////////
    112 
    113 // fwds ...
    114 static void printFpuState ( UChar* fpu_state );
    115 static void printVexState ( UChar* vex_state );
    116 
    117 
    118 /* Capture the FPU state.  Convert it to vex.  Convert it back
    119    to x87.  Print it at all stages.
    120 */
    121 void capture_convert_show ( /* preallocated storage */
    122                             UChar* x87_state0,
    123                             UChar* x87_state1,
    124                             UChar* vex_state )
    125 {
    126    asm volatile ("fsave (%0)"
    127                  :
    128                  : "r" (x87_state0)
    129                  : "memory" );
    130    x87_to_vex(x87_state0, vex_state);
    131    vex_to_x87(vex_state, x87_state1);
    132    printf("\n\n=================================================\n\n");
    133    printFpuState(x87_state0);
    134    printf("\n\n");
    135    printVexState(vex_state);
    136    printf("\n\n");
    137 #if 0
    138    asm volatile("frstor (%0) ; fsave (%0)"
    139                  :
    140                  : "r" (x87_state1)
    141                  : "memory" );
    142 #endif
    143    printFpuState(x87_state1);
    144    printf("\n\n");
    145    x87_to_vex(x87_state1, vex_state);
    146    printVexState(vex_state);
    147    printf("\n\n");
    148 }
    149 
    150 int main ( void )
    151 {
    152   UChar*  x87_state0 = malloc(sizeof(Fpu_State));
    153   UChar* x87_state1 = malloc(sizeof(Fpu_State));
    154   UChar* vex_state = malloc(1000);
    155   asm volatile ("finit");
    156   capture_convert_show(x87_state0, x87_state1, vex_state);
    157   asm volatile ("fldpi");
    158   capture_convert_show(x87_state0, x87_state1, vex_state);
    159   asm volatile ("fldz ; fld1 ; fdiv %st(1)");
    160   asm volatile ("fldln2 ; fldlg2 ; fchs ; fsqrt");
    161   capture_convert_show(x87_state0, x87_state1, vex_state);
    162   return 1;
    163 }
    164 
    165 ////////////////////////////////////////////////////////////////
    166 
    167 /* Bitfield offsets for exceptions in the FPU status and control words. */
    168 #define FP_E_INVAL    0
    169 #define FP_E_DENOR    1
    170 #define FP_E_DIVZ     2
    171 #define FP_E_OVERF    3
    172 #define FP_E_UNDER    4
    173 #define FP_E_LOS      5
    174 
    175 /* More bitfield offsets, but for the status word only. */
    176 #define FP_E_STACKF   6
    177 #define FP_E_SUMMARY  7
    178 #define FP_F_C0       8
    179 #define FP_F_C1       9
    180 #define FP_F_C2      10
    181 #define FP_F_C3      14
    182 /* top-of-stack ptr is bits 13,12,11 of the word */
    183 #define FP_F_TOS_LO  11
    184 #define FP_F_TOS_HI  13
    185 
    186 /* Register tags. */
    187 #define FP_TAG_VALID 0
    188 #define FP_TAG_ZERO  1
    189 #define FP_TAG_SPEC  2
    190 #define FP_TAG_EMPTY 3
    191 
    192 char* fp_tag_names[4]
    193    = { "Valid", "Zero", "Spec", "Empty" };
    194 
    195 char* fp_exception_names[6]
    196    = { "INVAL", "DENOR", "DIVZ", "OVERF", "UNDERF", "LOS" };
    197 
    198 
    199 UInt fp_get_tos ( Fpu_State* x87 )
    200 {
    201    return (x87->env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7;
    202 }
    203 
    204 UInt fp_get_tag ( Fpu_State* x87, UInt regno )
    205 {
    206    assert(!(regno < 0 || regno > 7));
    207    return (x87->env[FP_ENV_TAG] >> (2*regno)) & 3;
    208 }
    209 
    210 UInt fp_get_statusword_flag ( Fpu_State* x87, UInt flagno )
    211 {
    212    assert(!(flagno < 0 || flagno > 15));
    213    return (x87->env[FP_ENV_STAT] >> flagno) & 0x1;
    214 }
    215 
    216 UInt fp_get_controlword_flag ( Fpu_State* x87, UInt flagno )
    217 {
    218    assert(!(flagno < 0 || flagno > 15));
    219    return (x87->env[FP_ENV_CTRL] >> flagno) & 0x1;
    220 }
    221 
    222 
    223 static void printFpuState ( UChar* fpu_state )
    224 {
    225    Fpu_State* x87 = (Fpu_State*)fpu_state;
    226 
    227    Int i, j, k;
    228    assert(sizeof(Fpu_State)==108);
    229    for (i = 7; i >= 0; i--) {
    230       printf ( " %s fpreg%d: 0x",
    231                (UInt)i == fp_get_tos(x87) ? "**" : "  ", i );
    232       for (k = 0, j = FP_REG(i)+9; k < 10; k++,j--)
    233          printf ( "%02x", (UInt)x87->reg[j]);
    234       printf ( "  %5s  ", fp_tag_names[fp_get_tag(x87,i)] );
    235       printf("\n");
    236       //printf ( "%20.16e\n", fp_get_reg(i) );
    237    }
    238    printf("     fctrl:     0x%04x  masked: ",
    239           (UInt)x87->env[FP_ENV_CTRL] );
    240    for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
    241       if (fp_get_controlword_flag(x87,i))
    242          printf ( "%s ", fp_exception_names[i] );
    243    printf ( "\n" );
    244 
    245    printf("     fstat:     0x%04x  except:",
    246           (UInt)x87->env[FP_ENV_STAT] );
    247    for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
    248       if (fp_get_statusword_flag(x87,i))
    249          printf ( "%s ", fp_exception_names[i] );
    250    printf ( "  top: %d  ", fp_get_tos(x87) );
    251    printf ( "c3210: %d%d%d%d",
    252             fp_get_statusword_flag(x87,FP_F_C3),
    253             fp_get_statusword_flag(x87,FP_F_C2),
    254             fp_get_statusword_flag(x87,FP_F_C1),
    255             fp_get_statusword_flag(x87,FP_F_C0) );
    256    printf ( "  STACKF: %d\n", fp_get_statusword_flag(x87,FP_E_STACKF) );
    257 
    258    printf("      ftag:     0x%04x  ", (UInt)x87->env[FP_ENV_TAG] );
    259    for (i = 7; i >= 0; i--)
    260       printf ( "%d:%s ", i, fp_tag_names[fp_get_tag(x87,i)] );
    261    printf("\n");
    262 
    263    printf("       fip: 0x%08x\n",
    264            (((UInt)x87->env[FP_ENV_IP+1]) << 16) |
    265             ((UInt)x87->env[FP_ENV_IP]) );
    266    printf("       fcs:     0x%04x\n",
    267            ((UInt)x87->env[FP_ENV_CS]) );
    268    printf("    fopoff: 0x%08x\n",
    269            (((UInt)x87->env[FP_ENV_OPOFF+1]) << 16) |
    270             ((UInt)x87->env[FP_ENV_OPOFF]) );
    271    printf("    fopsel:     0x%04x\n",
    272            ((UInt)x87->env[FP_ENV_OPSEL]) );
    273 }
    274 
    275 
    276 static void printVexState ( UChar* vex_state )
    277 {
    278    Int r;
    279    ULong*     vexRegs = (ULong*)(vex_state + OFFB_F0);
    280    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
    281    UInt       ftop    = *(UInt*)(vex_state + OFFB_FTOP);
    282 
    283    for (r = 7; r >= 0; r--) {
    284       printf("%s %%f%d:  0x%llx  %s\n",
    285               r == ftop ? "##" : "  ",
    286               r,
    287               vexRegs[r],
    288 	      vexTags[r] == 0 ? "Empty" : "Full" );
    289    }
    290 
    291 }
    292