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
26typedef
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
46static 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
80static 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 ...
114static void printFpuState ( UChar* fpu_state );
115static 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*/
121void 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
150int 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
192char* fp_tag_names[4]
193   = { "Valid", "Zero", "Spec", "Empty" };
194
195char* fp_exception_names[6]
196   = { "INVAL", "DENOR", "DIVZ", "OVERF", "UNDERF", "LOS" };
197
198
199UInt fp_get_tos ( Fpu_State* x87 )
200{
201   return (x87->env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7;
202}
203
204UInt 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
210UInt 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
216UInt 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
223static 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
276static 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