sewardj | 07e0962 | 2004-09-06 20:39:20 +0000 | [diff] [blame] | 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"); |
sewardj | 6c54d11 | 2004-09-06 23:17:37 +0000 | [diff] [blame] | 137 | #if 0 |
| 138 | asm volatile("frstor (%0) ; fsave (%0)" |
| 139 | : |
| 140 | : "r" (x87_state1) |
| 141 | : "memory" ); |
| 142 | #endif |
sewardj | 07e0962 | 2004-09-06 20:39:20 +0000 | [diff] [blame] | 143 | printFpuState(x87_state1); |
| 144 | printf("\n\n"); |
sewardj | 6c54d11 | 2004-09-06 23:17:37 +0000 | [diff] [blame] | 145 | x87_to_vex(x87_state1, vex_state); |
| 146 | printVexState(vex_state); |
| 147 | printf("\n\n"); |
sewardj | 07e0962 | 2004-09-06 20:39:20 +0000 | [diff] [blame] | 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)"); |
sewardj | 6c54d11 | 2004-09-06 23:17:37 +0000 | [diff] [blame] | 160 | asm volatile ("fldln2 ; fldlg2 ; fchs ; fsqrt"); |
sewardj | 07e0962 | 2004-09-06 20:39:20 +0000 | [diff] [blame] | 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 | } |