6f3bc4b7f1cf795ec0f1e91365839a9ccdce02c4
[reactos.git] / lib / 3rdparty / softx86 / softx87 / softx87.c
1 /*
2 * softx87.c
3 *
4 * Copyright (C) 2003, 2004 Jonathan Campbell <jcampbell@mdjk.com>
5 *
6 * Softx87 library API.
7 *
8 * Initialization, de-initialization, register modification, and default
9 * routines for callbacks (in case they weren't set by the host app).
10 *
11 * Internal to this library, there are also functions to take care of
12 * fetching the current opcode (as referred to by CS:IP), fetching
13 * the current opcode for the decompiler (as referred to by a separate
14 * pair CS:IP), and pushing/popping data to/from the stack (SS:SP).
15 *
16 ***********************************************************************************
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 ************************************************************************************/
31
32 #include <softx87.h>
33 #include <memory.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include "optab87.h"
38
39 /* utility function to normalize a floating point value */
40 void softx87_normalize(softx87_ctx* ctx,softx87_reg80 *val)
41 {
42 int lead0;
43 sx87_uldword sh;
44
45 if (!val->mantissa)
46 return;
47
48 /* how many leading 0 bits in the mantissa */
49 lead0=0;
50 sh=0;
51 while (!((val->mantissa>>(63-sh))&1)) {
52 lead0++;
53 sh++;
54 }
55
56 /* if none, don't do anything */
57 if (!sh)
58 return;
59
60 /* normalize */
61 val->exponent -= sh;
62 val->mantissa <<= sh;
63 }
64
65
66 /* API for converting an FPU register to a type "double" value.
67 Yes, it is an approximation. Don't take it as the exact value. */
68 double softx87_get_fpu_double(softx87_ctx* ctx,softx87_reg80 *reg,int *numtype)
69 {
70 double val;
71 int exp;
72
73 /* all special cases seem to revolve around exp == 0x7FFF */
74 if (reg->exponent == 0x7FFF) {
75 if (reg->mantissa == 0) {
76 if (reg->sign_bit) {
77 if (numtype)
78 *numtype = SX87_FPU_NUMTYPE_NEGINF;
79
80 return 0.00;
81 }
82 else {
83 if (numtype)
84 *numtype = SX87_FPU_NUMTYPE_POSINF;
85
86 return 0.00;
87 }
88 }
89 else {
90 if (numtype)
91 *numtype = SX87_FPU_NUMTYPE_NAN;
92
93 return 0.00;
94 }
95 }
96
97 /* 16383 is the IEEE-754 bias for double extended precision numbers */
98 exp = reg->exponent - (16383+63);
99 #ifdef MSVC_CANT_CONVERT_UI64_TO_DOUBLE
100 if ((reg->mantissa >> ((sx87_uldword)63))&1)
101 /* +2^64 to encourage positive value */
102 val = ((double)((sx87_sldword)reg->mantissa)) + 18446744073709551616.00;
103 else
104 val = (double)((sx87_sldword)reg->mantissa);
105 #else
106 val = (double)(reg->mantissa);
107 #endif
108 val *= pow(2,(double)exp);
109
110 if (numtype)
111 *numtype = SX87_FPU_NUMTYPE_NUMBER;
112
113 if (reg->sign_bit)
114 val = -val;
115
116 return val;
117 }
118
119 double softx87_get_fpu_register_double(softx87_ctx* ctx,int i,int *numtype)
120 {
121 if (i < 0 || i > 7) {
122 if (numtype)
123 *numtype = SX87_FPU_NUMTYPE_NAN;
124
125 return 0.00;
126 }
127
128 return softx87_get_fpu_double(ctx,&ctx->state.st[i],numtype);
129 }
130
131 /* API for converting a type "double" value to an FPU register.
132 Yes, it is an approximation. Don't take it as the exact value. */
133 void softx87_set_fpu_double(softx87_ctx* ctx,softx87_reg80 *reg,double val)
134 {
135 /* log2 x = ln x / ln 2 */
136 double sal;
137 int l2b;
138 int sgn;
139
140 if (val < 0) {
141 sgn = 1;
142 val = -val;
143 }
144 else {
145 sgn = 0;
146 }
147
148 if (val == 0) {
149 reg->sign_bit = sgn;
150 reg->exponent = 0;
151 reg->mantissa = 0;
152 return;
153 }
154
155 l2b = (int)ceil(log(val)/log(2.0));
156 /* calculate just so to produce a normalized value */
157 sal = val * pow(2,(double)(63-l2b));
158 l2b = 16383 + l2b;
159 /* store */
160 reg->sign_bit = sgn;
161 reg->exponent = l2b;
162 reg->mantissa = (sx87_uldword)sal;
163 }
164
165 void softx87_set_fpu_register_double(softx87_ctx* ctx,int i,double val)
166 {
167 if (i < 0 || i > 7)
168 return;
169
170 softx87_set_fpu_double(ctx,&ctx->state.st[i],val);
171 }
172
173 /* callbacks intended to be called by softx86 */
174 int softx87_on_fpu_opcode_exec(/* softx86_ctx */ void* _ctx86,/* softx87_ctx */ void* _ctx87,sx86_ubyte opcode)
175 {
176 Sfx87OpcodeTable *sop;
177 softx86_ctx *ctx86;
178 softx87_ctx *ctx87;
179 sx87_ubyte op2;
180
181 /* sanity check */
182 ctx86 = (softx86_ctx*)_ctx86;
183 ctx87 = (softx87_ctx*)_ctx87;
184 if (!_ctx86 || !_ctx87) return 0;
185 if (opcode < 0xD8 || opcode > 0xDF) return 0;
186 sop = (Sfx87OpcodeTable*)ctx87->opcode_table;
187
188 op2 = ctx87->callbacks.on_softx86_fetch_exec_byte(ctx86);
189 return sop->table[opcode-0xD8].exec(op2,ctx87);
190 }
191
192 int softx87_on_fpu_opcode_dec(/* softx86_ctx */ void* _ctx86,/* softx87_ctx */ void* _ctx87,sx86_ubyte opcode,char buf[128])
193 {
194 Sfx87OpcodeTable *sop;
195 softx86_ctx *ctx86;
196 softx87_ctx *ctx87;
197 sx87_ubyte op2;
198
199 /* sanity check */
200 ctx86 = (softx86_ctx*)_ctx86;
201 ctx87 = (softx87_ctx*)_ctx87;
202 if (!_ctx86 || !_ctx87) return 0;
203 if (opcode < 0xD8 || opcode > 0xDF) return 0;
204 sop = (Sfx87OpcodeTable*)ctx87->opcode_table;
205
206 op2 = ctx87->callbacks.on_softx86_fetch_dec_byte(ctx86);
207 return sop->table[opcode-0xD8].dec(op2,ctx87,buf);
208 }
209
210 void softx87_finit_setup(softx87_ctx* ctx)
211 {
212 softx87_set_fpu_register_double(ctx,0,0.00);
213 softx87_set_fpu_register_double(ctx,1,0.00);
214 softx87_set_fpu_register_double(ctx,2,0.00);
215 softx87_set_fpu_register_double(ctx,3,0.00);
216 softx87_set_fpu_register_double(ctx,4,0.00);
217 softx87_set_fpu_register_double(ctx,5,0.00);
218 softx87_set_fpu_register_double(ctx,6,0.00);
219 softx87_set_fpu_register_double(ctx,7,0.00);
220 ctx->state.control_word = 0x037F;
221 ctx->state.status_word = 0x0000;
222 ctx->state.tag_word = 0xFFFF; // all empty
223 ctx->state.last_instruction_memptr.offset = 0;
224 ctx->state.last_instruction_memptr.segment = 0;
225 ctx->state.data_pointer.offset = 0;
226 ctx->state.data_pointer.segment = 0;
227 ctx->state.last_opcode = 0;
228 }
229
230 /* softx87_reset(context)
231 Resets a FPU
232
233 return value:
234 0 = failed
235 1 = success */
236 int softx87_reset(softx87_ctx* ctx)
237 {
238 if (!ctx) return 0;
239
240 /* switch on/off bugs */
241 ctx->bugs.ip_ignores_prefix =
242 (ctx->level <= SX87_FPULEVEL_8087)?1:0;
243
244 /* opcode table */
245 ctx->opcode_table = (void*)(&optab8087);
246
247 /* set up as if FINIT */
248 softx87_finit_setup(ctx);
249
250 return 1; /* success */
251 }
252
253 int softx87_getversion(int *major,int *minor,int *subminor)
254 {
255 if (!minor || !major || !subminor) return 0;
256
257 *major = SOFTX87_VERSION_HI;
258 *minor = SOFTX87_VERSION_LO;
259 *subminor = SOFTX87_VERSION_SUBLO;
260 return 1;
261 }
262
263 /* softx87_init(context)
264 Initialize a FPU context structure.
265
266 return value:
267 0 = failed
268 1 = success
269 2 = beta development advisory (FPU level emulation not quite stable) */
270 int softx87_init(softx87_ctx* ctx,int level)
271 {
272 int ret;
273
274 ret=1;
275 if (!ctx) return 0;
276 if (level > SX87_FPULEVEL_8087) return 0; /* we currently support up to the 8087 */
277 if (level < 0) return 0; /* apparently the host wants an 80(-1)87? :) */
278 // if (level > SX87_FPULEVEL_8087) ret=2; /* 80287 or higher emulation is not stable yet */
279 ctx->level = level;
280
281 if (!softx87_reset(ctx)) return 0;
282
283 /* store version in the structure */
284 ctx->version_hi = SOFTX87_VERSION_HI;
285 ctx->version_lo = SOFTX87_VERSION_LO;
286 ctx->version_sublo = SOFTX87_VERSION_SUBLO;
287
288 /* default callbacks */
289 ctx->callbacks.on_read_memory = softx87_step_def_on_read_memory;
290 ctx->callbacks.on_write_memory = softx87_step_def_on_write_memory;
291 ctx->callbacks.on_softx86_fetch_exec_byte = softx87_def_on_softx86_fetch_exec_byte;
292 ctx->callbacks.on_softx86_fetch_dec_byte = softx87_def_on_softx86_fetch_dec_byte;
293 ctx->callbacks.on_sx86_exec_full_modrmonly_memx = softx87_on_sx86_exec_full_modrmonly_memx;
294 ctx->callbacks.on_sx86_dec_full_modrmonly = softx87_on_sx86_dec_full_modrmonly;
295
296 return ret; /* success */
297 }
298
299 /* softx86_free(context)
300 Free a FPU context structure */
301 int softx87_free(softx87_ctx* ctx)
302 {
303 if (!ctx) return 0;
304
305 return 1; /* success */
306 }
307
308 /* enable/disable emulation of specific bugs. */
309 int softx87_setbug(softx87_ctx* ctx,sx86_udword bug_id,sx86_ubyte on_off)
310 {
311 if (bug_id == SX87_BUG_IP_IGNORES_PREFIX) {
312 ctx->bugs.ip_ignores_prefix = on_off;
313 return 1;
314 }
315
316 return 0;
317 }
318
319 /*--------------------------------------------------------------------------------
320 default callbacks
321 --------------------------------------------------------------------------------*/
322
323 void softx87_on_sx86_exec_full_modrmonly_memx(softx86_ctx *ctx,sx86_ubyte mod,sx86_ubyte rm,int sz,void (*op64)(softx86_ctx* ctx,char *datz,int sz))
324 {
325 }
326
327 void softx87_on_sx86_dec_full_modrmonly(softx86_ctx* ctx,sx86_ubyte is_word,sx86_ubyte dat32,sx86_ubyte mod,sx86_ubyte rm,char* op1)
328 {
329 }
330
331 sx86_ubyte softx87_def_on_softx86_fetch_exec_byte(softx86_ctx* ctx)
332 {
333 return 0xFF;
334 }
335
336 sx86_ubyte softx87_def_on_softx86_fetch_dec_byte(softx86_ctx* ctx)
337 {
338 return 0xFF;
339 }
340
341 void softx87_step_def_on_read_memory(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
342 {
343 softx87_ctx *ctx = ((softx87_ctx*)_ctx);
344 if (!ctx || !buf || size < 1) return;
345 memset(buf,0xFF,size);
346 }
347
348 void softx87_step_def_on_write_memory(void* _ctx,sx86_udword address,sx86_ubyte *buf,int size)
349 {
350 softx87_ctx *ctx = ((softx87_ctx*)_ctx);
351 if (!ctx || !buf || size < 1) return;
352 }
353
354 /* loading/storing and conversion code */
355
356 /* loads 16-bit integer from data[] */
357 void softx87_unpack_raw_int16(softx87_ctx* ctx,sx87_ubyte *data,softx87_reg80 *v)
358 {
359 #if SX86_BYTE_ORDER == LE
360 v->mantissa = (sx87_uldword)(*((sx87_uword*)data));
361 #else
362 v->mantissa = (sx87_uldword)data[0];
363 v->mantissa |= ((sx87_uldword)data[1])<<((sx87_uldword)8);
364 #endif
365
366 /* there. we have all 16 bits. spread them around. */
367 v->sign_bit = (v->mantissa >> ((sx87_uldword)15));
368 v->exponent = 14;
369 if (v->sign_bit) v->mantissa = ((v->mantissa ^ 0xFFFF)+1);
370 v->mantissa <<= (sx87_uldword)49;
371
372 /* convert the exponent */
373 v->exponent = v->exponent + 16383;
374 }
375
376 /* loads 32-bit integer from data[] */
377 void softx87_unpack_raw_int32(softx87_ctx* ctx,sx87_ubyte *data,softx87_reg80 *v)
378 {
379 #if SX86_BYTE_ORDER == LE
380 v->mantissa = (sx87_uldword)(*((sx87_udword*)data));
381 #else
382 v->mantissa = (sx87_uldword)data[3];
383 v->mantissa |= ((sx87_uldword)data[2])<<((sx87_uldword)8);
384 v->mantissa |= ((sx87_uldword)data[1])<<((sx87_uldword)16);
385 v->mantissa |= ((sx87_uldword)data[0])<<((sx87_uldword)24);
386 #endif
387
388 /* there. we have all 32 bits. spread them around. */
389 v->sign_bit = (v->mantissa >> ((sx87_uldword)31));
390 v->exponent = 30;
391 if (v->sign_bit) v->mantissa = ((v->mantissa ^ 0xFFFFFFFF)+1);
392 v->mantissa <<= (sx87_uldword)33;
393
394 /* convert the exponent */
395 v->exponent = v->exponent + 16383;
396 }
397
398 /* loads 32-bit double precision floating point from data[] */
399 void softx87_unpack_raw_fp32(softx87_ctx* ctx,sx87_ubyte *data,softx87_reg80 *v)
400 {
401 #if SX86_BYTE_ORDER == LE
402 v->mantissa = (sx87_uldword)(*((sx87_udword*)data));
403 #else
404 v->mantissa = (sx87_uldword)data[3];
405 v->mantissa |= ((sx87_uldword)data[2])<<((sx87_uldword)8);
406 v->mantissa |= ((sx87_uldword)data[1])<<((sx87_uldword)16);
407 v->mantissa |= ((sx87_uldword)data[0])<<((sx87_uldword)24);
408 #endif
409
410 /* there. we have all 32 bits. spread them around. */
411 v->sign_bit = (v->mantissa >> ((sx87_uldword)31));
412 v->exponent = (v->mantissa >> ((sx87_uldword)23))&0xFF;
413 v->mantissa &= (sx87_uldword)(0x7FFFFF);
414 v->mantissa |= (sx87_uldword)(0x800000); /* implied "1"? */
415 v->mantissa <<= (sx87_uldword)40;
416
417 /* convert the exponent */
418 v->exponent = (v->exponent - 127) + 16383;
419 }
420
421 /* loads 64-bit double precision floating point from data[] */
422 void softx87_unpack_raw_fp64(softx87_ctx* ctx,sx87_ubyte *data,softx87_reg80 *v)
423 {
424 #if SX86_BYTE_ORDER == LE
425 v->mantissa = *((sx87_uldword*)data);
426 #else
427 v->mantissa = (sx87_uldword)data[7];
428 v->mantissa |= ((sx87_uldword)data[6])<<((sx87_uldword)8);
429 v->mantissa |= ((sx87_uldword)data[5])<<((sx87_uldword)16);
430 v->mantissa |= ((sx87_uldword)data[4])<<((sx87_uldword)24);
431 v->mantissa |= ((sx87_uldword)data[3])<<((sx87_uldword)32);
432 v->mantissa |= ((sx87_uldword)data[2])<<((sx87_uldword)40);
433 v->mantissa |= ((sx87_uldword)data[1])<<((sx87_uldword)48);
434 v->mantissa |= ((sx87_uldword)data[0])<<((sx87_uldword)56);
435 #endif
436
437 /* there. we have all 64 bits. spread them around. */
438 v->sign_bit = (v->mantissa >> ((sx87_uldword)63));
439 v->exponent = (v->mantissa >> ((sx87_uldword)52))&0x7FF;
440 v->mantissa &= (sx87_uldword)(0x0FFFFFFFFFFFFF);
441 v->mantissa |= (sx87_uldword)(0x10000000000000); /* implied "1"? */
442 v->mantissa <<= (sx87_uldword)11;
443
444 /* convert the exponent */
445 v->exponent = (v->exponent - 1023) + 16383;
446 }