Statistics
| Branch: | Revision:

root / helper-i386.c @ a412ac57

History | View | Annotate | Download (37.8 kB)

1 3ec9c4fc bellard
/*
2 3ec9c4fc bellard
 *  i386 helpers
3 3ec9c4fc bellard
 * 
4 3ec9c4fc bellard
 *  Copyright (c) 2003 Fabrice Bellard
5 3ec9c4fc bellard
 *
6 3ec9c4fc bellard
 * This library is free software; you can redistribute it and/or
7 3ec9c4fc bellard
 * modify it under the terms of the GNU Lesser General Public
8 3ec9c4fc bellard
 * License as published by the Free Software Foundation; either
9 3ec9c4fc bellard
 * version 2 of the License, or (at your option) any later version.
10 3ec9c4fc bellard
 *
11 3ec9c4fc bellard
 * This library is distributed in the hope that it will be useful,
12 3ec9c4fc bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 3ec9c4fc bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 3ec9c4fc bellard
 * Lesser General Public License for more details.
15 3ec9c4fc bellard
 *
16 3ec9c4fc bellard
 * You should have received a copy of the GNU Lesser General Public
17 3ec9c4fc bellard
 * License along with this library; if not, write to the Free Software
18 3ec9c4fc bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 3ec9c4fc bellard
 */
20 3ec9c4fc bellard
#include "exec-i386.h"
21 3ec9c4fc bellard
22 1e5ffbed bellard
const uint8_t parity_table[256] = {
23 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
24 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
25 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
26 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
27 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
28 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
29 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
30 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
31 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
32 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
33 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
34 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
35 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
36 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
37 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
38 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
39 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
40 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
41 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
42 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
43 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
44 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
45 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
46 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
47 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
48 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
49 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
50 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
51 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
52 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
53 1e5ffbed bellard
    CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
54 1e5ffbed bellard
    0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
55 1e5ffbed bellard
};
56 1e5ffbed bellard
57 1e5ffbed bellard
/* modulo 17 table */
58 1e5ffbed bellard
const uint8_t rclw_table[32] = {
59 1e5ffbed bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
60 1e5ffbed bellard
    8, 9,10,11,12,13,14,15,
61 1e5ffbed bellard
   16, 0, 1, 2, 3, 4, 5, 6,
62 1e5ffbed bellard
    7, 8, 9,10,11,12,13,14,
63 1e5ffbed bellard
};
64 1e5ffbed bellard
65 1e5ffbed bellard
/* modulo 9 table */
66 1e5ffbed bellard
const uint8_t rclb_table[32] = {
67 1e5ffbed bellard
    0, 1, 2, 3, 4, 5, 6, 7, 
68 1e5ffbed bellard
    8, 0, 1, 2, 3, 4, 5, 6,
69 1e5ffbed bellard
    7, 8, 0, 1, 2, 3, 4, 5, 
70 1e5ffbed bellard
    6, 7, 8, 0, 1, 2, 3, 4,
71 1e5ffbed bellard
};
72 1e5ffbed bellard
73 2d0e9143 bellard
const CPU86_LDouble f15rk[7] =
74 2d0e9143 bellard
{
75 2d0e9143 bellard
    0.00000000000000000000L,
76 2d0e9143 bellard
    1.00000000000000000000L,
77 2d0e9143 bellard
    3.14159265358979323851L,  /*pi*/
78 2d0e9143 bellard
    0.30102999566398119523L,  /*lg2*/
79 2d0e9143 bellard
    0.69314718055994530943L,  /*ln2*/
80 2d0e9143 bellard
    1.44269504088896340739L,  /*l2e*/
81 2d0e9143 bellard
    3.32192809488736234781L,  /*l2t*/
82 2d0e9143 bellard
};
83 2d0e9143 bellard
    
84 2d0e9143 bellard
/* thread support */
85 2d0e9143 bellard
86 2d0e9143 bellard
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
87 2d0e9143 bellard
88 2d0e9143 bellard
void cpu_lock(void)
89 2d0e9143 bellard
{
90 2d0e9143 bellard
    spin_lock(&global_cpu_lock);
91 2d0e9143 bellard
}
92 2d0e9143 bellard
93 2d0e9143 bellard
void cpu_unlock(void)
94 2d0e9143 bellard
{
95 2d0e9143 bellard
    spin_unlock(&global_cpu_lock);
96 2d0e9143 bellard
}
97 2d0e9143 bellard
98 2d0e9143 bellard
void cpu_loop_exit(void)
99 2d0e9143 bellard
{
100 2d0e9143 bellard
    /* NOTE: the register at this point must be saved by hand because
101 2d0e9143 bellard
       longjmp restore them */
102 2d0e9143 bellard
#ifdef reg_EAX
103 2d0e9143 bellard
    env->regs[R_EAX] = EAX;
104 2d0e9143 bellard
#endif
105 2d0e9143 bellard
#ifdef reg_ECX
106 2d0e9143 bellard
    env->regs[R_ECX] = ECX;
107 2d0e9143 bellard
#endif
108 2d0e9143 bellard
#ifdef reg_EDX
109 2d0e9143 bellard
    env->regs[R_EDX] = EDX;
110 2d0e9143 bellard
#endif
111 2d0e9143 bellard
#ifdef reg_EBX
112 2d0e9143 bellard
    env->regs[R_EBX] = EBX;
113 2d0e9143 bellard
#endif
114 2d0e9143 bellard
#ifdef reg_ESP
115 2d0e9143 bellard
    env->regs[R_ESP] = ESP;
116 2d0e9143 bellard
#endif
117 2d0e9143 bellard
#ifdef reg_EBP
118 2d0e9143 bellard
    env->regs[R_EBP] = EBP;
119 2d0e9143 bellard
#endif
120 2d0e9143 bellard
#ifdef reg_ESI
121 2d0e9143 bellard
    env->regs[R_ESI] = ESI;
122 2d0e9143 bellard
#endif
123 2d0e9143 bellard
#ifdef reg_EDI
124 2d0e9143 bellard
    env->regs[R_EDI] = EDI;
125 2d0e9143 bellard
#endif
126 2d0e9143 bellard
    longjmp(env->jmp_env, 1);
127 2d0e9143 bellard
}
128 2d0e9143 bellard
129 90a9fdae bellard
static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
130 90a9fdae bellard
                                       uint32_t *esp_ptr, int dpl)
131 90a9fdae bellard
{
132 90a9fdae bellard
    int type, index, shift;
133 90a9fdae bellard
    
134 3ec9c4fc bellard
#if 0
135 90a9fdae bellard
    {
136 90a9fdae bellard
        int i;
137 90a9fdae bellard
        printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
138 90a9fdae bellard
        for(i=0;i<env->tr.limit;i++) {
139 90a9fdae bellard
            printf("%02x ", env->tr.base[i]);
140 90a9fdae bellard
            if ((i & 7) == 7) printf("\n");
141 90a9fdae bellard
        }
142 90a9fdae bellard
        printf("\n");
143 90a9fdae bellard
    }
144 90a9fdae bellard
#endif
145 90a9fdae bellard
146 90a9fdae bellard
    if (!(env->tr.flags & DESC_P_MASK))
147 90a9fdae bellard
        cpu_abort(env, "invalid tss");
148 90a9fdae bellard
    type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
149 90a9fdae bellard
    if ((type & 7) != 1)
150 90a9fdae bellard
        cpu_abort(env, "invalid tss type");
151 90a9fdae bellard
    shift = type >> 3;
152 90a9fdae bellard
    index = (dpl * 4 + 2) << shift;
153 90a9fdae bellard
    if (index + (4 << shift) - 1 > env->tr.limit)
154 90a9fdae bellard
        raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
155 90a9fdae bellard
    if (shift == 0) {
156 90a9fdae bellard
        *esp_ptr = lduw(env->tr.base + index);
157 90a9fdae bellard
        *ss_ptr = lduw(env->tr.base + index + 2);
158 90a9fdae bellard
    } else {
159 90a9fdae bellard
        *esp_ptr = ldl(env->tr.base + index);
160 90a9fdae bellard
        *ss_ptr = lduw(env->tr.base + index + 4);
161 90a9fdae bellard
    }
162 90a9fdae bellard
}
163 90a9fdae bellard
164 90a9fdae bellard
/* return non zero if error */
165 90a9fdae bellard
static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
166 90a9fdae bellard
                               int selector)
167 3ec9c4fc bellard
{
168 90a9fdae bellard
    SegmentCache *dt;
169 90a9fdae bellard
    int index;
170 3ec9c4fc bellard
    uint8_t *ptr;
171 90a9fdae bellard
172 90a9fdae bellard
    if (selector & 0x4)
173 90a9fdae bellard
        dt = &env->ldt;
174 90a9fdae bellard
    else
175 90a9fdae bellard
        dt = &env->gdt;
176 90a9fdae bellard
    index = selector & ~7;
177 90a9fdae bellard
    if ((index + 7) > dt->limit)
178 90a9fdae bellard
        return -1;
179 90a9fdae bellard
    ptr = dt->base + index;
180 90a9fdae bellard
    *e1_ptr = ldl(ptr);
181 90a9fdae bellard
    *e2_ptr = ldl(ptr + 4);
182 90a9fdae bellard
    return 0;
183 90a9fdae bellard
}
184 90a9fdae bellard
                                     
185 90a9fdae bellard
186 90a9fdae bellard
/* protected mode interrupt */
187 90a9fdae bellard
static void do_interrupt_protected(int intno, int is_int, int error_code,
188 90a9fdae bellard
                                      unsigned int next_eip)
189 90a9fdae bellard
{
190 90a9fdae bellard
    SegmentCache *dt;
191 90a9fdae bellard
    uint8_t *ptr, *ssp;
192 90a9fdae bellard
    int type, dpl, cpl, selector, ss_dpl;
193 90a9fdae bellard
    int has_error_code, new_stack, shift;
194 90a9fdae bellard
    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
195 90a9fdae bellard
    uint32_t old_cs, old_ss, old_esp, old_eip;
196 90a9fdae bellard
197 3ec9c4fc bellard
    dt = &env->idt;
198 3ec9c4fc bellard
    if (intno * 8 + 7 > dt->limit)
199 3ec9c4fc bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
200 3ec9c4fc bellard
    ptr = dt->base + intno * 8;
201 3ec9c4fc bellard
    e1 = ldl(ptr);
202 3ec9c4fc bellard
    e2 = ldl(ptr + 4);
203 3ec9c4fc bellard
    /* check gate type */
204 3ec9c4fc bellard
    type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
205 3ec9c4fc bellard
    switch(type) {
206 3ec9c4fc bellard
    case 5: /* task gate */
207 90a9fdae bellard
        cpu_abort(env, "task gate not supported");
208 90a9fdae bellard
        break;
209 3ec9c4fc bellard
    case 6: /* 286 interrupt gate */
210 3ec9c4fc bellard
    case 7: /* 286 trap gate */
211 3ec9c4fc bellard
    case 14: /* 386 interrupt gate */
212 3ec9c4fc bellard
    case 15: /* 386 trap gate */
213 3ec9c4fc bellard
        break;
214 3ec9c4fc bellard
    default:
215 3ec9c4fc bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
216 3ec9c4fc bellard
        break;
217 3ec9c4fc bellard
    }
218 3ec9c4fc bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
219 a363e34c bellard
    if (env->eflags & VM_MASK)
220 a363e34c bellard
        cpl = 3;
221 a363e34c bellard
    else
222 a363e34c bellard
        cpl = env->segs[R_CS].selector & 3;
223 3ec9c4fc bellard
    /* check privledge if software int */
224 3ec9c4fc bellard
    if (is_int && dpl < cpl)
225 3ec9c4fc bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
226 3ec9c4fc bellard
    /* check valid bit */
227 3ec9c4fc bellard
    if (!(e2 & DESC_P_MASK))
228 3ec9c4fc bellard
        raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
229 90a9fdae bellard
    selector = e1 >> 16;
230 90a9fdae bellard
    offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
231 90a9fdae bellard
    if ((selector & 0xfffc) == 0)
232 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, 0);
233 90a9fdae bellard
234 90a9fdae bellard
    if (load_segment(&e1, &e2, selector) != 0)
235 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
236 90a9fdae bellard
    if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
237 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
238 90a9fdae bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
239 90a9fdae bellard
    if (dpl > cpl)
240 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
241 90a9fdae bellard
    if (!(e2 & DESC_P_MASK))
242 90a9fdae bellard
        raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
243 90a9fdae bellard
    if (!(e2 & DESC_C_MASK) && dpl < cpl) {
244 90a9fdae bellard
        /* to inner priviledge */
245 90a9fdae bellard
        get_ss_esp_from_tss(&ss, &esp, dpl);
246 90a9fdae bellard
        if ((ss & 0xfffc) == 0)
247 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
248 90a9fdae bellard
        if ((ss & 3) != dpl)
249 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
250 90a9fdae bellard
        if (load_segment(&ss_e1, &ss_e2, ss) != 0)
251 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
252 90a9fdae bellard
        ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
253 90a9fdae bellard
        if (ss_dpl != dpl)
254 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
255 90a9fdae bellard
        if (!(ss_e2 & DESC_S_MASK) ||
256 90a9fdae bellard
            (ss_e2 & DESC_CS_MASK) ||
257 90a9fdae bellard
            !(ss_e2 & DESC_W_MASK))
258 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
259 90a9fdae bellard
        if (!(ss_e2 & DESC_P_MASK))
260 90a9fdae bellard
            raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
261 90a9fdae bellard
        new_stack = 1;
262 90a9fdae bellard
    } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
263 90a9fdae bellard
        /* to same priviledge */
264 90a9fdae bellard
        new_stack = 0;
265 90a9fdae bellard
    } else {
266 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
267 90a9fdae bellard
        new_stack = 0; /* avoid warning */
268 90a9fdae bellard
    }
269 90a9fdae bellard
270 90a9fdae bellard
    shift = type >> 3;
271 90a9fdae bellard
    has_error_code = 0;
272 90a9fdae bellard
    if (!is_int) {
273 90a9fdae bellard
        switch(intno) {
274 90a9fdae bellard
        case 8:
275 90a9fdae bellard
        case 10:
276 90a9fdae bellard
        case 11:
277 90a9fdae bellard
        case 12:
278 90a9fdae bellard
        case 13:
279 90a9fdae bellard
        case 14:
280 90a9fdae bellard
        case 17:
281 90a9fdae bellard
            has_error_code = 1;
282 90a9fdae bellard
            break;
283 90a9fdae bellard
        }
284 90a9fdae bellard
    }
285 90a9fdae bellard
    push_size = 6 + (new_stack << 2) + (has_error_code << 1);
286 90a9fdae bellard
    if (env->eflags & VM_MASK)
287 90a9fdae bellard
        push_size += 8;
288 90a9fdae bellard
    push_size <<= shift;
289 90a9fdae bellard
290 90a9fdae bellard
    /* XXX: check that enough room is available */
291 90a9fdae bellard
    if (new_stack) {
292 90a9fdae bellard
        old_esp = env->regs[R_ESP];
293 90a9fdae bellard
        old_ss = env->segs[R_SS].selector;
294 90a9fdae bellard
        load_seg(R_SS, ss, env->eip);
295 90a9fdae bellard
    } else {
296 90a9fdae bellard
        old_esp = 0;
297 90a9fdae bellard
        old_ss = 0;
298 90a9fdae bellard
        esp = env->regs[R_ESP];
299 90a9fdae bellard
    }
300 90a9fdae bellard
    if (is_int)
301 90a9fdae bellard
        old_eip = next_eip;
302 90a9fdae bellard
    else
303 90a9fdae bellard
        old_eip = env->eip;
304 90a9fdae bellard
    old_cs = env->segs[R_CS].selector;
305 90a9fdae bellard
    load_seg(R_CS, selector, env->eip);
306 90a9fdae bellard
    env->eip = offset;
307 90a9fdae bellard
    env->regs[R_ESP] = esp - push_size;
308 90a9fdae bellard
    ssp = env->segs[R_SS].base + esp;
309 90a9fdae bellard
    if (shift == 1) {
310 90a9fdae bellard
        int old_eflags;
311 90a9fdae bellard
        if (env->eflags & VM_MASK) {
312 90a9fdae bellard
            ssp -= 4;
313 90a9fdae bellard
            stl(ssp, env->segs[R_GS].selector);
314 90a9fdae bellard
            ssp -= 4;
315 90a9fdae bellard
            stl(ssp, env->segs[R_FS].selector);
316 90a9fdae bellard
            ssp -= 4;
317 90a9fdae bellard
            stl(ssp, env->segs[R_DS].selector);
318 90a9fdae bellard
            ssp -= 4;
319 90a9fdae bellard
            stl(ssp, env->segs[R_ES].selector);
320 90a9fdae bellard
        }
321 90a9fdae bellard
        if (new_stack) {
322 90a9fdae bellard
            ssp -= 4;
323 90a9fdae bellard
            stl(ssp, old_ss);
324 90a9fdae bellard
            ssp -= 4;
325 90a9fdae bellard
            stl(ssp, old_esp);
326 90a9fdae bellard
        }
327 90a9fdae bellard
        ssp -= 4;
328 90a9fdae bellard
        old_eflags = compute_eflags();
329 90a9fdae bellard
        stl(ssp, old_eflags);
330 90a9fdae bellard
        ssp -= 4;
331 90a9fdae bellard
        stl(ssp, old_cs);
332 90a9fdae bellard
        ssp -= 4;
333 90a9fdae bellard
        stl(ssp, old_eip);
334 90a9fdae bellard
        if (has_error_code) {
335 90a9fdae bellard
            ssp -= 4;
336 90a9fdae bellard
            stl(ssp, error_code);
337 90a9fdae bellard
        }
338 90a9fdae bellard
    } else {
339 90a9fdae bellard
        if (new_stack) {
340 90a9fdae bellard
            ssp -= 2;
341 90a9fdae bellard
            stw(ssp, old_ss);
342 90a9fdae bellard
            ssp -= 2;
343 90a9fdae bellard
            stw(ssp, old_esp);
344 90a9fdae bellard
        }
345 90a9fdae bellard
        ssp -= 2;
346 90a9fdae bellard
        stw(ssp, compute_eflags());
347 90a9fdae bellard
        ssp -= 2;
348 90a9fdae bellard
        stw(ssp, old_cs);
349 90a9fdae bellard
        ssp -= 2;
350 90a9fdae bellard
        stw(ssp, old_eip);
351 90a9fdae bellard
        if (has_error_code) {
352 90a9fdae bellard
            ssp -= 2;
353 90a9fdae bellard
            stw(ssp, error_code);
354 90a9fdae bellard
        }
355 90a9fdae bellard
    }
356 90a9fdae bellard
    
357 90a9fdae bellard
    /* interrupt gate clear IF mask */
358 90a9fdae bellard
    if ((type & 1) == 0) {
359 90a9fdae bellard
        env->eflags &= ~IF_MASK;
360 90a9fdae bellard
    }
361 90a9fdae bellard
    env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
362 3ec9c4fc bellard
}
363 3ec9c4fc bellard
364 90a9fdae bellard
/* real mode interrupt */
365 90a9fdae bellard
static void do_interrupt_real(int intno, int is_int, int error_code,
366 90a9fdae bellard
                                 unsigned int next_eip)
367 90a9fdae bellard
{
368 90a9fdae bellard
    SegmentCache *dt;
369 90a9fdae bellard
    uint8_t *ptr, *ssp;
370 90a9fdae bellard
    int selector;
371 90a9fdae bellard
    uint32_t offset, esp;
372 90a9fdae bellard
    uint32_t old_cs, old_eip;
373 3ec9c4fc bellard
374 90a9fdae bellard
    /* real mode (simpler !) */
375 90a9fdae bellard
    dt = &env->idt;
376 90a9fdae bellard
    if (intno * 4 + 3 > dt->limit)
377 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
378 90a9fdae bellard
    ptr = dt->base + intno * 4;
379 90a9fdae bellard
    offset = lduw(ptr);
380 90a9fdae bellard
    selector = lduw(ptr + 2);
381 90a9fdae bellard
    esp = env->regs[R_ESP] & 0xffff;
382 90a9fdae bellard
    ssp = env->segs[R_SS].base + esp;
383 90a9fdae bellard
    if (is_int)
384 90a9fdae bellard
        old_eip = next_eip;
385 90a9fdae bellard
    else
386 90a9fdae bellard
        old_eip = env->eip;
387 90a9fdae bellard
    old_cs = env->segs[R_CS].selector;
388 90a9fdae bellard
    ssp -= 2;
389 90a9fdae bellard
    stw(ssp, compute_eflags());
390 90a9fdae bellard
    ssp -= 2;
391 90a9fdae bellard
    stw(ssp, old_cs);
392 90a9fdae bellard
    ssp -= 2;
393 90a9fdae bellard
    stw(ssp, old_eip);
394 90a9fdae bellard
    esp -= 6;
395 90a9fdae bellard
    
396 90a9fdae bellard
    /* update processor state */
397 90a9fdae bellard
    env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | (esp & 0xffff);
398 90a9fdae bellard
    env->eip = offset;
399 90a9fdae bellard
    env->segs[R_CS].selector = selector;
400 90a9fdae bellard
    env->segs[R_CS].base = (uint8_t *)(selector << 4);
401 90a9fdae bellard
    env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
402 90a9fdae bellard
}
403 90a9fdae bellard
404 90a9fdae bellard
/* fake user mode interrupt */
405 90a9fdae bellard
void do_interrupt_user(int intno, int is_int, int error_code, 
406 90a9fdae bellard
                       unsigned int next_eip)
407 3ec9c4fc bellard
{
408 d8bc1fd0 bellard
    SegmentCache *dt;
409 3ec9c4fc bellard
    uint8_t *ptr;
410 3ec9c4fc bellard
    int dpl, cpl;
411 3ec9c4fc bellard
    uint32_t e2;
412 3ec9c4fc bellard
413 3ec9c4fc bellard
    dt = &env->idt;
414 3ec9c4fc bellard
    ptr = dt->base + (intno * 8);
415 3ec9c4fc bellard
    e2 = ldl(ptr + 4);
416 3ec9c4fc bellard
    
417 3ec9c4fc bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
418 3ec9c4fc bellard
    cpl = 3;
419 3ec9c4fc bellard
    /* check privledge if software int */
420 3ec9c4fc bellard
    if (is_int && dpl < cpl)
421 3ec9c4fc bellard
        raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
422 3ec9c4fc bellard
423 3ec9c4fc bellard
    /* Since we emulate only user space, we cannot do more than
424 3ec9c4fc bellard
       exiting the emulation with the suitable exception and error
425 3ec9c4fc bellard
       code */
426 3ec9c4fc bellard
    if (is_int)
427 3ec9c4fc bellard
        EIP = next_eip;
428 90a9fdae bellard
}
429 90a9fdae bellard
430 90a9fdae bellard
/*
431 90a9fdae bellard
 * Begin excution of an interruption. is_int is TRUE if coming from
432 90a9fdae bellard
 * the int instruction. next_eip is the EIP value AFTER the interrupt
433 90a9fdae bellard
 * instruction. It is only relevant if is_int is TRUE.  
434 90a9fdae bellard
 */
435 90a9fdae bellard
void do_interrupt(int intno, int is_int, int error_code, 
436 90a9fdae bellard
                  unsigned int next_eip)
437 90a9fdae bellard
{
438 90a9fdae bellard
    if (env->cr[0] & CR0_PE_MASK) {
439 90a9fdae bellard
        do_interrupt_protected(intno, is_int, error_code, next_eip);
440 90a9fdae bellard
    } else {
441 90a9fdae bellard
        do_interrupt_real(intno, is_int, error_code, next_eip);
442 90a9fdae bellard
    }
443 90a9fdae bellard
}
444 90a9fdae bellard
445 90a9fdae bellard
/*
446 90a9fdae bellard
 * Signal an interruption. It is executed in the main CPU loop.
447 90a9fdae bellard
 * is_int is TRUE if coming from the int instruction. next_eip is the
448 90a9fdae bellard
 * EIP value AFTER the interrupt instruction. It is only relevant if
449 90a9fdae bellard
 * is_int is TRUE.  
450 90a9fdae bellard
 */
451 90a9fdae bellard
void raise_interrupt(int intno, int is_int, int error_code, 
452 90a9fdae bellard
                     unsigned int next_eip)
453 90a9fdae bellard
{
454 3ec9c4fc bellard
    env->exception_index = intno;
455 3ec9c4fc bellard
    env->error_code = error_code;
456 90a9fdae bellard
    env->exception_is_int = is_int;
457 90a9fdae bellard
    env->exception_next_eip = next_eip;
458 3ec9c4fc bellard
    cpu_loop_exit();
459 3ec9c4fc bellard
}
460 3ec9c4fc bellard
461 3ec9c4fc bellard
/* shortcuts to generate exceptions */
462 3ec9c4fc bellard
void raise_exception_err(int exception_index, int error_code)
463 3ec9c4fc bellard
{
464 3ec9c4fc bellard
    raise_interrupt(exception_index, 0, error_code, 0);
465 3ec9c4fc bellard
}
466 3ec9c4fc bellard
467 3ec9c4fc bellard
void raise_exception(int exception_index)
468 3ec9c4fc bellard
{
469 3ec9c4fc bellard
    raise_interrupt(exception_index, 0, 0, 0);
470 3ec9c4fc bellard
}
471 3ec9c4fc bellard
472 2d0e9143 bellard
#ifdef BUGGY_GCC_DIV64
473 2d0e9143 bellard
/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
474 2d0e9143 bellard
   call it from another function */
475 2d0e9143 bellard
uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
476 2d0e9143 bellard
{
477 2d0e9143 bellard
    *q_ptr = num / den;
478 2d0e9143 bellard
    return num % den;
479 2d0e9143 bellard
}
480 2d0e9143 bellard
481 2d0e9143 bellard
int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
482 2d0e9143 bellard
{
483 2d0e9143 bellard
    *q_ptr = num / den;
484 2d0e9143 bellard
    return num % den;
485 2d0e9143 bellard
}
486 2d0e9143 bellard
#endif
487 2d0e9143 bellard
488 2d0e9143 bellard
void helper_divl_EAX_T0(uint32_t eip)
489 2d0e9143 bellard
{
490 2d0e9143 bellard
    unsigned int den, q, r;
491 2d0e9143 bellard
    uint64_t num;
492 2d0e9143 bellard
    
493 2d0e9143 bellard
    num = EAX | ((uint64_t)EDX << 32);
494 2d0e9143 bellard
    den = T0;
495 2d0e9143 bellard
    if (den == 0) {
496 2d0e9143 bellard
        EIP = eip;
497 2d0e9143 bellard
        raise_exception(EXCP00_DIVZ);
498 2d0e9143 bellard
    }
499 2d0e9143 bellard
#ifdef BUGGY_GCC_DIV64
500 2d0e9143 bellard
    r = div64(&q, num, den);
501 2d0e9143 bellard
#else
502 2d0e9143 bellard
    q = (num / den);
503 2d0e9143 bellard
    r = (num % den);
504 2d0e9143 bellard
#endif
505 2d0e9143 bellard
    EAX = q;
506 2d0e9143 bellard
    EDX = r;
507 2d0e9143 bellard
}
508 2d0e9143 bellard
509 2d0e9143 bellard
void helper_idivl_EAX_T0(uint32_t eip)
510 2d0e9143 bellard
{
511 2d0e9143 bellard
    int den, q, r;
512 2d0e9143 bellard
    int64_t num;
513 2d0e9143 bellard
    
514 2d0e9143 bellard
    num = EAX | ((uint64_t)EDX << 32);
515 2d0e9143 bellard
    den = T0;
516 2d0e9143 bellard
    if (den == 0) {
517 2d0e9143 bellard
        EIP = eip;
518 2d0e9143 bellard
        raise_exception(EXCP00_DIVZ);
519 2d0e9143 bellard
    }
520 2d0e9143 bellard
#ifdef BUGGY_GCC_DIV64
521 2d0e9143 bellard
    r = idiv64(&q, num, den);
522 2d0e9143 bellard
#else
523 2d0e9143 bellard
    q = (num / den);
524 2d0e9143 bellard
    r = (num % den);
525 2d0e9143 bellard
#endif
526 2d0e9143 bellard
    EAX = q;
527 2d0e9143 bellard
    EDX = r;
528 2d0e9143 bellard
}
529 2d0e9143 bellard
530 2d0e9143 bellard
void helper_cmpxchg8b(void)
531 2d0e9143 bellard
{
532 2d0e9143 bellard
    uint64_t d;
533 2d0e9143 bellard
    int eflags;
534 2d0e9143 bellard
535 2d0e9143 bellard
    eflags = cc_table[CC_OP].compute_all();
536 2d0e9143 bellard
    d = ldq((uint8_t *)A0);
537 2d0e9143 bellard
    if (d == (((uint64_t)EDX << 32) | EAX)) {
538 2d0e9143 bellard
        stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
539 2d0e9143 bellard
        eflags |= CC_Z;
540 2d0e9143 bellard
    } else {
541 2d0e9143 bellard
        EDX = d >> 32;
542 2d0e9143 bellard
        EAX = d;
543 2d0e9143 bellard
        eflags &= ~CC_Z;
544 2d0e9143 bellard
    }
545 2d0e9143 bellard
    CC_SRC = eflags;
546 2d0e9143 bellard
}
547 2d0e9143 bellard
548 3ec9c4fc bellard
/* We simulate a pre-MMX pentium as in valgrind */
549 3ec9c4fc bellard
#define CPUID_FP87 (1 << 0)
550 3ec9c4fc bellard
#define CPUID_VME  (1 << 1)
551 3ec9c4fc bellard
#define CPUID_DE   (1 << 2)
552 3ec9c4fc bellard
#define CPUID_PSE  (1 << 3)
553 3ec9c4fc bellard
#define CPUID_TSC  (1 << 4)
554 3ec9c4fc bellard
#define CPUID_MSR  (1 << 5)
555 3ec9c4fc bellard
#define CPUID_PAE  (1 << 6)
556 3ec9c4fc bellard
#define CPUID_MCE  (1 << 7)
557 3ec9c4fc bellard
#define CPUID_CX8  (1 << 8)
558 3ec9c4fc bellard
#define CPUID_APIC (1 << 9)
559 3ec9c4fc bellard
#define CPUID_SEP  (1 << 11) /* sysenter/sysexit */
560 3ec9c4fc bellard
#define CPUID_MTRR (1 << 12)
561 3ec9c4fc bellard
#define CPUID_PGE  (1 << 13)
562 3ec9c4fc bellard
#define CPUID_MCA  (1 << 14)
563 3ec9c4fc bellard
#define CPUID_CMOV (1 << 15)
564 3ec9c4fc bellard
/* ... */
565 3ec9c4fc bellard
#define CPUID_MMX  (1 << 23)
566 3ec9c4fc bellard
#define CPUID_FXSR (1 << 24)
567 3ec9c4fc bellard
#define CPUID_SSE  (1 << 25)
568 3ec9c4fc bellard
#define CPUID_SSE2 (1 << 26)
569 3ec9c4fc bellard
570 3ec9c4fc bellard
void helper_cpuid(void)
571 3ec9c4fc bellard
{
572 3ec9c4fc bellard
    if (EAX == 0) {
573 3ec9c4fc bellard
        EAX = 1; /* max EAX index supported */
574 3ec9c4fc bellard
        EBX = 0x756e6547;
575 3ec9c4fc bellard
        ECX = 0x6c65746e;
576 3ec9c4fc bellard
        EDX = 0x49656e69;
577 3ec9c4fc bellard
    } else if (EAX == 1) {
578 a363e34c bellard
        int family, model, stepping;
579 3ec9c4fc bellard
        /* EAX = 1 info */
580 a363e34c bellard
#if 0
581 a363e34c bellard
        /* pentium 75-200 */
582 a363e34c bellard
        family = 5;
583 a363e34c bellard
        model = 2;
584 a363e34c bellard
        stepping = 11;
585 a363e34c bellard
#else
586 a363e34c bellard
        /* pentium pro */
587 a363e34c bellard
        family = 6;
588 a363e34c bellard
        model = 1;
589 a363e34c bellard
        stepping = 3;
590 a363e34c bellard
#endif
591 a363e34c bellard
        EAX = (family << 8) | (model << 4) | stepping;
592 3ec9c4fc bellard
        EBX = 0;
593 3ec9c4fc bellard
        ECX = 0;
594 3ec9c4fc bellard
        EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
595 3ec9c4fc bellard
            CPUID_TSC | CPUID_MSR | CPUID_MCE |
596 a363e34c bellard
            CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
597 3ec9c4fc bellard
    }
598 3ec9c4fc bellard
}
599 3ec9c4fc bellard
600 d8bc1fd0 bellard
static inline void load_seg_cache(SegmentCache *sc, uint32_t e1, uint32_t e2)
601 d8bc1fd0 bellard
{
602 d8bc1fd0 bellard
    sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
603 d8bc1fd0 bellard
    sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
604 90a9fdae bellard
    if (e2 & DESC_G_MASK)
605 d8bc1fd0 bellard
        sc->limit = (sc->limit << 12) | 0xfff;
606 90a9fdae bellard
    sc->flags = e2;
607 d8bc1fd0 bellard
}
608 d8bc1fd0 bellard
609 d8bc1fd0 bellard
void helper_lldt_T0(void)
610 d8bc1fd0 bellard
{
611 d8bc1fd0 bellard
    int selector;
612 d8bc1fd0 bellard
    SegmentCache *dt;
613 d8bc1fd0 bellard
    uint32_t e1, e2;
614 d8bc1fd0 bellard
    int index;
615 d8bc1fd0 bellard
    uint8_t *ptr;
616 d8bc1fd0 bellard
    
617 d8bc1fd0 bellard
    selector = T0 & 0xffff;
618 d8bc1fd0 bellard
    if ((selector & 0xfffc) == 0) {
619 d8bc1fd0 bellard
        /* XXX: NULL selector case: invalid LDT */
620 d8bc1fd0 bellard
        env->ldt.base = NULL;
621 d8bc1fd0 bellard
        env->ldt.limit = 0;
622 d8bc1fd0 bellard
    } else {
623 d8bc1fd0 bellard
        if (selector & 0x4)
624 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
625 d8bc1fd0 bellard
        dt = &env->gdt;
626 d8bc1fd0 bellard
        index = selector & ~7;
627 d8bc1fd0 bellard
        if ((index + 7) > dt->limit)
628 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
629 d8bc1fd0 bellard
        ptr = dt->base + index;
630 d8bc1fd0 bellard
        e1 = ldl(ptr);
631 d8bc1fd0 bellard
        e2 = ldl(ptr + 4);
632 d8bc1fd0 bellard
        if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
633 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
634 d8bc1fd0 bellard
        if (!(e2 & DESC_P_MASK))
635 d8bc1fd0 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
636 d8bc1fd0 bellard
        load_seg_cache(&env->ldt, e1, e2);
637 d8bc1fd0 bellard
    }
638 d8bc1fd0 bellard
    env->ldt.selector = selector;
639 d8bc1fd0 bellard
}
640 d8bc1fd0 bellard
641 d8bc1fd0 bellard
void helper_ltr_T0(void)
642 d8bc1fd0 bellard
{
643 d8bc1fd0 bellard
    int selector;
644 d8bc1fd0 bellard
    SegmentCache *dt;
645 d8bc1fd0 bellard
    uint32_t e1, e2;
646 d8bc1fd0 bellard
    int index, type;
647 d8bc1fd0 bellard
    uint8_t *ptr;
648 d8bc1fd0 bellard
    
649 d8bc1fd0 bellard
    selector = T0 & 0xffff;
650 d8bc1fd0 bellard
    if ((selector & 0xfffc) == 0) {
651 90a9fdae bellard
        /* NULL selector case: invalid LDT */
652 d8bc1fd0 bellard
        env->tr.base = NULL;
653 d8bc1fd0 bellard
        env->tr.limit = 0;
654 90a9fdae bellard
        env->tr.flags = 0;
655 d8bc1fd0 bellard
    } else {
656 d8bc1fd0 bellard
        if (selector & 0x4)
657 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
658 d8bc1fd0 bellard
        dt = &env->gdt;
659 d8bc1fd0 bellard
        index = selector & ~7;
660 d8bc1fd0 bellard
        if ((index + 7) > dt->limit)
661 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
662 d8bc1fd0 bellard
        ptr = dt->base + index;
663 d8bc1fd0 bellard
        e1 = ldl(ptr);
664 d8bc1fd0 bellard
        e2 = ldl(ptr + 4);
665 d8bc1fd0 bellard
        type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
666 d8bc1fd0 bellard
        if ((e2 & DESC_S_MASK) || 
667 d8bc1fd0 bellard
            (type != 2 && type != 9))
668 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
669 d8bc1fd0 bellard
        if (!(e2 & DESC_P_MASK))
670 d8bc1fd0 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
671 d8bc1fd0 bellard
        load_seg_cache(&env->tr, e1, e2);
672 d8bc1fd0 bellard
        e2 |= 0x00000200; /* set the busy bit */
673 d8bc1fd0 bellard
        stl(ptr + 4, e2);
674 d8bc1fd0 bellard
    }
675 d8bc1fd0 bellard
    env->tr.selector = selector;
676 d8bc1fd0 bellard
}
677 d8bc1fd0 bellard
678 3ec9c4fc bellard
/* only works if protected mode and not VM86 */
679 d8bc1fd0 bellard
void load_seg(int seg_reg, int selector, unsigned int cur_eip)
680 3ec9c4fc bellard
{
681 3ec9c4fc bellard
    SegmentCache *sc;
682 3ec9c4fc bellard
    uint32_t e1, e2;
683 d8bc1fd0 bellard
    
684 d8bc1fd0 bellard
    sc = &env->segs[seg_reg];
685 3ec9c4fc bellard
    if ((selector & 0xfffc) == 0) {
686 3ec9c4fc bellard
        /* null selector case */
687 3ec9c4fc bellard
        if (seg_reg == R_SS) {
688 3ec9c4fc bellard
            EIP = cur_eip;
689 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, 0);
690 3ec9c4fc bellard
        } else {
691 3ec9c4fc bellard
            /* XXX: each access should trigger an exception */
692 3ec9c4fc bellard
            sc->base = NULL;
693 3ec9c4fc bellard
            sc->limit = 0;
694 90a9fdae bellard
            sc->flags = 0;
695 3ec9c4fc bellard
        }
696 3ec9c4fc bellard
    } else {
697 90a9fdae bellard
        if (load_segment(&e1, &e2, selector) != 0) {
698 3ec9c4fc bellard
            EIP = cur_eip;
699 3ec9c4fc bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
700 3ec9c4fc bellard
        }
701 3ec9c4fc bellard
        if (!(e2 & DESC_S_MASK) ||
702 3ec9c4fc bellard
            (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
703 3ec9c4fc bellard
            EIP = cur_eip;
704 3ec9c4fc bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
705 3ec9c4fc bellard
        }
706 3ec9c4fc bellard
707 3ec9c4fc bellard
        if (seg_reg == R_SS) {
708 3ec9c4fc bellard
            if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
709 3ec9c4fc bellard
                EIP = cur_eip;
710 3ec9c4fc bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
711 3ec9c4fc bellard
            }
712 3ec9c4fc bellard
        } else {
713 3ec9c4fc bellard
            if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
714 3ec9c4fc bellard
                EIP = cur_eip;
715 3ec9c4fc bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
716 3ec9c4fc bellard
            }
717 3ec9c4fc bellard
        }
718 3ec9c4fc bellard
719 3ec9c4fc bellard
        if (!(e2 & DESC_P_MASK)) {
720 3ec9c4fc bellard
            EIP = cur_eip;
721 3ec9c4fc bellard
            if (seg_reg == R_SS)
722 3ec9c4fc bellard
                raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
723 3ec9c4fc bellard
            else
724 3ec9c4fc bellard
                raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
725 3ec9c4fc bellard
        }
726 d8bc1fd0 bellard
        load_seg_cache(sc, e1, e2);
727 3ec9c4fc bellard
#if 0
728 90a9fdae bellard
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
729 90a9fdae bellard
                selector, (unsigned long)sc->base, sc->limit, sc->flags);
730 3ec9c4fc bellard
#endif
731 3ec9c4fc bellard
    }
732 d8bc1fd0 bellard
    sc->selector = selector;
733 d8bc1fd0 bellard
}
734 d8bc1fd0 bellard
735 d8bc1fd0 bellard
/* protected mode jump */
736 d8bc1fd0 bellard
void jmp_seg(int selector, unsigned int new_eip)
737 d8bc1fd0 bellard
{
738 d8bc1fd0 bellard
    SegmentCache sc1;
739 d8bc1fd0 bellard
    uint32_t e1, e2, cpl, dpl, rpl;
740 d8bc1fd0 bellard
741 d8bc1fd0 bellard
    if ((selector & 0xfffc) == 0) {
742 d8bc1fd0 bellard
        raise_exception_err(EXCP0D_GPF, 0);
743 d8bc1fd0 bellard
    }
744 d8bc1fd0 bellard
745 90a9fdae bellard
    if (load_segment(&e1, &e2, selector) != 0)
746 d8bc1fd0 bellard
        raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
747 d8bc1fd0 bellard
    cpl = env->segs[R_CS].selector & 3;
748 d8bc1fd0 bellard
    if (e2 & DESC_S_MASK) {
749 d8bc1fd0 bellard
        if (!(e2 & DESC_CS_MASK))
750 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
751 d8bc1fd0 bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
752 d8bc1fd0 bellard
        if (e2 & DESC_CS_MASK) {
753 d8bc1fd0 bellard
            /* conforming code segment */
754 d8bc1fd0 bellard
            if (dpl > cpl)
755 d8bc1fd0 bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
756 d8bc1fd0 bellard
        } else {
757 d8bc1fd0 bellard
            /* non conforming code segment */
758 d8bc1fd0 bellard
            rpl = selector & 3;
759 d8bc1fd0 bellard
            if (rpl > cpl)
760 d8bc1fd0 bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
761 d8bc1fd0 bellard
            if (dpl != cpl)
762 d8bc1fd0 bellard
                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
763 d8bc1fd0 bellard
        }
764 d8bc1fd0 bellard
        if (!(e2 & DESC_P_MASK))
765 d8bc1fd0 bellard
            raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
766 d8bc1fd0 bellard
        load_seg_cache(&sc1, e1, e2);
767 d8bc1fd0 bellard
        if (new_eip > sc1.limit)
768 d8bc1fd0 bellard
            raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
769 a363e34c bellard
        env->segs[R_CS].base = sc1.base;
770 a363e34c bellard
        env->segs[R_CS].limit = sc1.limit;
771 a363e34c bellard
        env->segs[R_CS].flags = sc1.flags;
772 d8bc1fd0 bellard
        env->segs[R_CS].selector = (selector & 0xfffc) | cpl;
773 d8bc1fd0 bellard
        EIP = new_eip;
774 d8bc1fd0 bellard
    } else {
775 d8bc1fd0 bellard
        cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", 
776 d8bc1fd0 bellard
                  selector, new_eip);
777 d8bc1fd0 bellard
    }
778 d8bc1fd0 bellard
}
779 d8bc1fd0 bellard
780 90a9fdae bellard
/* init the segment cache in vm86 mode */
781 90a9fdae bellard
static inline void load_seg_vm(int seg, int selector)
782 90a9fdae bellard
{
783 90a9fdae bellard
    SegmentCache *sc = &env->segs[seg];
784 90a9fdae bellard
    selector &= 0xffff;
785 90a9fdae bellard
    sc->base = (uint8_t *)(selector << 4);
786 90a9fdae bellard
    sc->selector = selector;
787 90a9fdae bellard
    sc->flags = 0;
788 90a9fdae bellard
    sc->limit = 0xffff;
789 90a9fdae bellard
}
790 90a9fdae bellard
791 8f186479 bellard
/* real mode iret */
792 8f186479 bellard
void helper_iret_real(int shift)
793 8f186479 bellard
{
794 8f186479 bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
795 8f186479 bellard
    uint8_t *ssp;
796 8f186479 bellard
    int eflags_mask;
797 8f186479 bellard
    
798 8f186479 bellard
    sp = env->regs[R_ESP] & 0xffff;
799 8f186479 bellard
    ssp = env->segs[R_SS].base + sp;
800 8f186479 bellard
    if (shift == 1) {
801 8f186479 bellard
        /* 32 bits */
802 8f186479 bellard
        new_eflags = ldl(ssp + 8);
803 8f186479 bellard
        new_cs = ldl(ssp + 4) & 0xffff;
804 8f186479 bellard
        new_eip = ldl(ssp) & 0xffff;
805 8f186479 bellard
    } else {
806 8f186479 bellard
        /* 16 bits */
807 8f186479 bellard
        new_eflags = lduw(ssp + 4);
808 8f186479 bellard
        new_cs = lduw(ssp + 2);
809 8f186479 bellard
        new_eip = lduw(ssp);
810 8f186479 bellard
    }
811 8f186479 bellard
    new_esp = sp + (6 << shift);
812 8f186479 bellard
    env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | 
813 8f186479 bellard
        (new_esp & 0xffff);
814 8f186479 bellard
    load_seg_vm(R_CS, new_cs);
815 8f186479 bellard
    env->eip = new_eip;
816 8f186479 bellard
    eflags_mask = FL_UPDATE_CPL0_MASK;
817 8f186479 bellard
    if (shift == 0)
818 8f186479 bellard
        eflags_mask &= 0xffff;
819 8f186479 bellard
    load_eflags(new_eflags, eflags_mask);
820 8f186479 bellard
}
821 8f186479 bellard
822 90a9fdae bellard
/* protected mode iret */
823 90a9fdae bellard
void helper_iret_protected(int shift)
824 90a9fdae bellard
{
825 90a9fdae bellard
    uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;
826 90a9fdae bellard
    uint32_t new_es, new_ds, new_fs, new_gs;
827 90a9fdae bellard
    uint32_t e1, e2;
828 90a9fdae bellard
    int cpl, dpl, rpl, eflags_mask;
829 90a9fdae bellard
    uint8_t *ssp;
830 90a9fdae bellard
    
831 90a9fdae bellard
    sp = env->regs[R_ESP];
832 90a9fdae bellard
    if (!(env->segs[R_SS].flags & DESC_B_MASK))
833 90a9fdae bellard
        sp &= 0xffff;
834 90a9fdae bellard
    ssp = env->segs[R_SS].base + sp;
835 90a9fdae bellard
    if (shift == 1) {
836 90a9fdae bellard
        /* 32 bits */
837 90a9fdae bellard
        new_eflags = ldl(ssp + 8);
838 90a9fdae bellard
        new_cs = ldl(ssp + 4) & 0xffff;
839 90a9fdae bellard
        new_eip = ldl(ssp);
840 90a9fdae bellard
        if (new_eflags & VM_MASK)
841 90a9fdae bellard
            goto return_to_vm86;
842 90a9fdae bellard
    } else {
843 90a9fdae bellard
        /* 16 bits */
844 90a9fdae bellard
        new_eflags = lduw(ssp + 4);
845 90a9fdae bellard
        new_cs = lduw(ssp + 2);
846 90a9fdae bellard
        new_eip = lduw(ssp);
847 90a9fdae bellard
    }
848 90a9fdae bellard
    if ((new_cs & 0xfffc) == 0)
849 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
850 90a9fdae bellard
    if (load_segment(&e1, &e2, new_cs) != 0)
851 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
852 90a9fdae bellard
    if (!(e2 & DESC_S_MASK) ||
853 90a9fdae bellard
        !(e2 & DESC_CS_MASK))
854 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
855 90a9fdae bellard
    cpl = env->segs[R_CS].selector & 3;
856 90a9fdae bellard
    rpl = new_cs & 3; 
857 90a9fdae bellard
    if (rpl < cpl)
858 90a9fdae bellard
        raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
859 90a9fdae bellard
    dpl = (e2 >> DESC_DPL_SHIFT) & 3;
860 90a9fdae bellard
    if (e2 & DESC_CS_MASK) {
861 90a9fdae bellard
        if (dpl > rpl)
862 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
863 90a9fdae bellard
    } else {
864 90a9fdae bellard
        if (dpl != rpl)
865 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
866 90a9fdae bellard
    }
867 90a9fdae bellard
    if (!(e2 & DESC_P_MASK))
868 90a9fdae bellard
        raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
869 90a9fdae bellard
    
870 90a9fdae bellard
    if (rpl == cpl) {
871 90a9fdae bellard
        /* return to same priledge level */
872 90a9fdae bellard
        load_seg(R_CS, new_cs, env->eip);
873 90a9fdae bellard
        new_esp = sp + (6 << shift);
874 90a9fdae bellard
    } else {
875 90a9fdae bellard
        /* return to differentr priviledge level */
876 90a9fdae bellard
        if (shift == 1) {
877 90a9fdae bellard
            /* 32 bits */
878 90a9fdae bellard
            new_esp = ldl(ssp + 12);
879 90a9fdae bellard
            new_ss = ldl(ssp + 16) & 0xffff;
880 90a9fdae bellard
        } else {
881 90a9fdae bellard
            /* 16 bits */
882 90a9fdae bellard
            new_esp = lduw(ssp + 6);
883 90a9fdae bellard
            new_ss = lduw(ssp + 8);
884 90a9fdae bellard
        }
885 90a9fdae bellard
        
886 90a9fdae bellard
        if ((new_ss & 3) != rpl)
887 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
888 90a9fdae bellard
        if (load_segment(&e1, &e2, new_ss) != 0)
889 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
890 90a9fdae bellard
        if (!(e2 & DESC_S_MASK) ||
891 90a9fdae bellard
            (e2 & DESC_CS_MASK) ||
892 90a9fdae bellard
            !(e2 & DESC_W_MASK))
893 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
894 90a9fdae bellard
        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
895 90a9fdae bellard
        if (dpl != rpl)
896 90a9fdae bellard
            raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
897 90a9fdae bellard
        if (!(e2 & DESC_P_MASK))
898 90a9fdae bellard
            raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
899 90a9fdae bellard
900 90a9fdae bellard
        load_seg(R_CS, new_cs, env->eip);
901 90a9fdae bellard
        load_seg(R_SS, new_ss, env->eip);
902 90a9fdae bellard
    }
903 90a9fdae bellard
    if (env->segs[R_SS].flags & DESC_B_MASK)
904 90a9fdae bellard
        env->regs[R_ESP] = new_esp;
905 90a9fdae bellard
    else
906 90a9fdae bellard
        env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | 
907 90a9fdae bellard
            (new_esp & 0xffff);
908 90a9fdae bellard
    env->eip = new_eip;
909 90a9fdae bellard
    if (cpl == 0)
910 90a9fdae bellard
        eflags_mask = FL_UPDATE_CPL0_MASK;
911 90a9fdae bellard
    else
912 90a9fdae bellard
        eflags_mask = FL_UPDATE_MASK32;
913 90a9fdae bellard
    if (shift == 0)
914 90a9fdae bellard
        eflags_mask &= 0xffff;
915 90a9fdae bellard
    load_eflags(new_eflags, eflags_mask);
916 90a9fdae bellard
    return;
917 90a9fdae bellard
918 90a9fdae bellard
 return_to_vm86:
919 90a9fdae bellard
    new_esp = ldl(ssp + 12);
920 90a9fdae bellard
    new_ss = ldl(ssp + 16);
921 90a9fdae bellard
    new_es = ldl(ssp + 20);
922 90a9fdae bellard
    new_ds = ldl(ssp + 24);
923 90a9fdae bellard
    new_fs = ldl(ssp + 28);
924 90a9fdae bellard
    new_gs = ldl(ssp + 32);
925 90a9fdae bellard
    
926 90a9fdae bellard
    /* modify processor state */
927 90a9fdae bellard
    load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
928 90a9fdae bellard
    load_seg_vm(R_CS, new_cs);
929 90a9fdae bellard
    load_seg_vm(R_SS, new_ss);
930 90a9fdae bellard
    load_seg_vm(R_ES, new_es);
931 90a9fdae bellard
    load_seg_vm(R_DS, new_ds);
932 90a9fdae bellard
    load_seg_vm(R_FS, new_fs);
933 90a9fdae bellard
    load_seg_vm(R_GS, new_gs);
934 90a9fdae bellard
    
935 90a9fdae bellard
    env->eip = new_eip;
936 90a9fdae bellard
    env->regs[R_ESP] = new_esp;
937 90a9fdae bellard
}
938 90a9fdae bellard
939 d8bc1fd0 bellard
void helper_movl_crN_T0(int reg)
940 d8bc1fd0 bellard
{
941 90a9fdae bellard
    env->cr[reg] = T0;
942 d8bc1fd0 bellard
    switch(reg) {
943 d8bc1fd0 bellard
    case 0:
944 90a9fdae bellard
        cpu_x86_update_cr0(env);
945 d8bc1fd0 bellard
        break;
946 d8bc1fd0 bellard
    case 3:
947 90a9fdae bellard
        cpu_x86_update_cr3(env);
948 d8bc1fd0 bellard
        break;
949 d8bc1fd0 bellard
    }
950 d8bc1fd0 bellard
}
951 d8bc1fd0 bellard
952 d8bc1fd0 bellard
/* XXX: do more */
953 d8bc1fd0 bellard
void helper_movl_drN_T0(int reg)
954 d8bc1fd0 bellard
{
955 d8bc1fd0 bellard
    env->dr[reg] = T0;
956 3ec9c4fc bellard
}
957 3ec9c4fc bellard
958 90a9fdae bellard
void helper_invlpg(unsigned int addr)
959 90a9fdae bellard
{
960 90a9fdae bellard
    cpu_x86_flush_tlb(env, addr);
961 90a9fdae bellard
}
962 90a9fdae bellard
963 2d0e9143 bellard
/* rdtsc */
964 2d0e9143 bellard
#ifndef __i386__
965 2d0e9143 bellard
uint64_t emu_time;
966 2d0e9143 bellard
#endif
967 2d0e9143 bellard
968 2d0e9143 bellard
void helper_rdtsc(void)
969 2d0e9143 bellard
{
970 2d0e9143 bellard
    uint64_t val;
971 2d0e9143 bellard
#ifdef __i386__
972 2d0e9143 bellard
    asm("rdtsc" : "=A" (val));
973 2d0e9143 bellard
#else
974 2d0e9143 bellard
    /* better than nothing: the time increases */
975 2d0e9143 bellard
    val = emu_time++;
976 2d0e9143 bellard
#endif
977 2d0e9143 bellard
    EAX = val;
978 2d0e9143 bellard
    EDX = val >> 32;
979 2d0e9143 bellard
}
980 2d0e9143 bellard
981 3c1cf9fa bellard
void helper_wrmsr(void)
982 3c1cf9fa bellard
{
983 3c1cf9fa bellard
    switch(ECX) {
984 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_CS:
985 3c1cf9fa bellard
        env->sysenter_cs = EAX & 0xffff;
986 3c1cf9fa bellard
        break;
987 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_ESP:
988 3c1cf9fa bellard
        env->sysenter_esp = EAX;
989 3c1cf9fa bellard
        break;
990 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_EIP:
991 3c1cf9fa bellard
        env->sysenter_eip = EAX;
992 3c1cf9fa bellard
        break;
993 3c1cf9fa bellard
    default:
994 3c1cf9fa bellard
        /* XXX: exception ? */
995 3c1cf9fa bellard
        break; 
996 3c1cf9fa bellard
    }
997 3c1cf9fa bellard
}
998 3c1cf9fa bellard
999 3c1cf9fa bellard
void helper_rdmsr(void)
1000 3c1cf9fa bellard
{
1001 3c1cf9fa bellard
    switch(ECX) {
1002 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_CS:
1003 3c1cf9fa bellard
        EAX = env->sysenter_cs;
1004 3c1cf9fa bellard
        EDX = 0;
1005 3c1cf9fa bellard
        break;
1006 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_ESP:
1007 3c1cf9fa bellard
        EAX = env->sysenter_esp;
1008 3c1cf9fa bellard
        EDX = 0;
1009 3c1cf9fa bellard
        break;
1010 3c1cf9fa bellard
    case MSR_IA32_SYSENTER_EIP:
1011 3c1cf9fa bellard
        EAX = env->sysenter_eip;
1012 3c1cf9fa bellard
        EDX = 0;
1013 3c1cf9fa bellard
        break;
1014 3c1cf9fa bellard
    default:
1015 3c1cf9fa bellard
        /* XXX: exception ? */
1016 3c1cf9fa bellard
        break; 
1017 3c1cf9fa bellard
    }
1018 3c1cf9fa bellard
}
1019 3c1cf9fa bellard
1020 3ec9c4fc bellard
void helper_lsl(void)
1021 3ec9c4fc bellard
{
1022 3ec9c4fc bellard
    unsigned int selector, limit;
1023 3ec9c4fc bellard
    uint32_t e1, e2;
1024 3ec9c4fc bellard
1025 3ec9c4fc bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1026 3ec9c4fc bellard
    selector = T0 & 0xffff;
1027 90a9fdae bellard
    if (load_segment(&e1, &e2, selector) != 0)
1028 3ec9c4fc bellard
        return;
1029 3ec9c4fc bellard
    limit = (e1 & 0xffff) | (e2 & 0x000f0000);
1030 3ec9c4fc bellard
    if (e2 & (1 << 23))
1031 3ec9c4fc bellard
        limit = (limit << 12) | 0xfff;
1032 3ec9c4fc bellard
    T1 = limit;
1033 3ec9c4fc bellard
    CC_SRC |= CC_Z;
1034 3ec9c4fc bellard
}
1035 3ec9c4fc bellard
1036 3ec9c4fc bellard
void helper_lar(void)
1037 3ec9c4fc bellard
{
1038 3ec9c4fc bellard
    unsigned int selector;
1039 90a9fdae bellard
    uint32_t e1, e2;
1040 3ec9c4fc bellard
1041 3ec9c4fc bellard
    CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
1042 3ec9c4fc bellard
    selector = T0 & 0xffff;
1043 90a9fdae bellard
    if (load_segment(&e1, &e2, selector) != 0)
1044 3ec9c4fc bellard
        return;
1045 3ec9c4fc bellard
    T1 = e2 & 0x00f0ff00;
1046 3ec9c4fc bellard
    CC_SRC |= CC_Z;
1047 3ec9c4fc bellard
}
1048 3ec9c4fc bellard
1049 3ec9c4fc bellard
/* FPU helpers */
1050 3ec9c4fc bellard
1051 3ec9c4fc bellard
#ifndef USE_X86LDOUBLE
1052 3ec9c4fc bellard
void helper_fldt_ST0_A0(void)
1053 3ec9c4fc bellard
{
1054 4d40895f bellard
    int new_fpstt;
1055 4d40895f bellard
    new_fpstt = (env->fpstt - 1) & 7;
1056 4d40895f bellard
    env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
1057 4d40895f bellard
    env->fpstt = new_fpstt;
1058 4d40895f bellard
    env->fptags[new_fpstt] = 0; /* validate stack entry */
1059 3ec9c4fc bellard
}
1060 3ec9c4fc bellard
1061 3ec9c4fc bellard
void helper_fstt_ST0_A0(void)
1062 3ec9c4fc bellard
{
1063 3ec9c4fc bellard
    helper_fstt(ST0, (uint8_t *)A0);
1064 3ec9c4fc bellard
}
1065 3ec9c4fc bellard
#endif
1066 3ec9c4fc bellard
1067 3ec9c4fc bellard
/* BCD ops */
1068 3ec9c4fc bellard
1069 3ec9c4fc bellard
#define MUL10(iv) ( iv + iv + (iv << 3) )
1070 3ec9c4fc bellard
1071 3ec9c4fc bellard
void helper_fbld_ST0_A0(void)
1072 3ec9c4fc bellard
{
1073 4d40895f bellard
    CPU86_LDouble tmp;
1074 4d40895f bellard
    uint64_t val;
1075 3ec9c4fc bellard
    unsigned int v;
1076 4d40895f bellard
    int i;
1077 3ec9c4fc bellard
1078 4d40895f bellard
    val = 0;
1079 4d40895f bellard
    for(i = 8; i >= 0; i--) {
1080 4d40895f bellard
        v = ldub((uint8_t *)A0 + i);
1081 4d40895f bellard
        val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
1082 4d40895f bellard
    }
1083 4d40895f bellard
    tmp = val;
1084 4d40895f bellard
    if (ldub((uint8_t *)A0 + 9) & 0x80)
1085 4d40895f bellard
        tmp = -tmp;
1086 4d40895f bellard
    fpush();
1087 4d40895f bellard
    ST0 = tmp;
1088 3ec9c4fc bellard
}
1089 3ec9c4fc bellard
1090 3ec9c4fc bellard
void helper_fbst_ST0_A0(void)
1091 3ec9c4fc bellard
{
1092 4d40895f bellard
    CPU86_LDouble tmp;
1093 3ec9c4fc bellard
    int v;
1094 3ec9c4fc bellard
    uint8_t *mem_ref, *mem_end;
1095 4d40895f bellard
    int64_t val;
1096 3ec9c4fc bellard
1097 4d40895f bellard
    tmp = rint(ST0);
1098 4d40895f bellard
    val = (int64_t)tmp;
1099 3ec9c4fc bellard
    mem_ref = (uint8_t *)A0;
1100 4d40895f bellard
    mem_end = mem_ref + 9;
1101 4d40895f bellard
    if (val < 0) {
1102 4d40895f bellard
        stb(mem_end, 0x80);
1103 4d40895f bellard
        val = -val;
1104 3ec9c4fc bellard
    } else {
1105 4d40895f bellard
        stb(mem_end, 0x00);
1106 3ec9c4fc bellard
    }
1107 3ec9c4fc bellard
    while (mem_ref < mem_end) {
1108 4d40895f bellard
        if (val == 0)
1109 3ec9c4fc bellard
            break;
1110 4d40895f bellard
        v = val % 100;
1111 4d40895f bellard
        val = val / 100;
1112 4d40895f bellard
        v = ((v / 10) << 4) | (v % 10);
1113 3ec9c4fc bellard
        stb(mem_ref++, v);
1114 3ec9c4fc bellard
    }
1115 3ec9c4fc bellard
    while (mem_ref < mem_end) {
1116 3ec9c4fc bellard
        stb(mem_ref++, 0);
1117 3ec9c4fc bellard
    }
1118 3ec9c4fc bellard
}
1119 3ec9c4fc bellard
1120 3ec9c4fc bellard
void helper_f2xm1(void)
1121 3ec9c4fc bellard
{
1122 3ec9c4fc bellard
    ST0 = pow(2.0,ST0) - 1.0;
1123 3ec9c4fc bellard
}
1124 3ec9c4fc bellard
1125 3ec9c4fc bellard
void helper_fyl2x(void)
1126 3ec9c4fc bellard
{
1127 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1128 3ec9c4fc bellard
    
1129 3ec9c4fc bellard
    fptemp = ST0;
1130 3ec9c4fc bellard
    if (fptemp>0.0){
1131 3ec9c4fc bellard
        fptemp = log(fptemp)/log(2.0);         /* log2(ST) */
1132 3ec9c4fc bellard
        ST1 *= fptemp;
1133 3ec9c4fc bellard
        fpop();
1134 3ec9c4fc bellard
    } else { 
1135 3ec9c4fc bellard
        env->fpus &= (~0x4700);
1136 3ec9c4fc bellard
        env->fpus |= 0x400;
1137 3ec9c4fc bellard
    }
1138 3ec9c4fc bellard
}
1139 3ec9c4fc bellard
1140 3ec9c4fc bellard
void helper_fptan(void)
1141 3ec9c4fc bellard
{
1142 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1143 3ec9c4fc bellard
1144 3ec9c4fc bellard
    fptemp = ST0;
1145 3ec9c4fc bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1146 3ec9c4fc bellard
        env->fpus |= 0x400;
1147 3ec9c4fc bellard
    } else {
1148 3ec9c4fc bellard
        ST0 = tan(fptemp);
1149 3ec9c4fc bellard
        fpush();
1150 3ec9c4fc bellard
        ST0 = 1.0;
1151 3ec9c4fc bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1152 3ec9c4fc bellard
        /* the above code is for  |arg| < 2**52 only */
1153 3ec9c4fc bellard
    }
1154 3ec9c4fc bellard
}
1155 3ec9c4fc bellard
1156 3ec9c4fc bellard
void helper_fpatan(void)
1157 3ec9c4fc bellard
{
1158 3ec9c4fc bellard
    CPU86_LDouble fptemp, fpsrcop;
1159 3ec9c4fc bellard
1160 3ec9c4fc bellard
    fpsrcop = ST1;
1161 3ec9c4fc bellard
    fptemp = ST0;
1162 3ec9c4fc bellard
    ST1 = atan2(fpsrcop,fptemp);
1163 3ec9c4fc bellard
    fpop();
1164 3ec9c4fc bellard
}
1165 3ec9c4fc bellard
1166 3ec9c4fc bellard
void helper_fxtract(void)
1167 3ec9c4fc bellard
{
1168 3ec9c4fc bellard
    CPU86_LDoubleU temp;
1169 3ec9c4fc bellard
    unsigned int expdif;
1170 3ec9c4fc bellard
1171 3ec9c4fc bellard
    temp.d = ST0;
1172 3ec9c4fc bellard
    expdif = EXPD(temp) - EXPBIAS;
1173 3ec9c4fc bellard
    /*DP exponent bias*/
1174 3ec9c4fc bellard
    ST0 = expdif;
1175 3ec9c4fc bellard
    fpush();
1176 3ec9c4fc bellard
    BIASEXPONENT(temp);
1177 3ec9c4fc bellard
    ST0 = temp.d;
1178 3ec9c4fc bellard
}
1179 3ec9c4fc bellard
1180 3ec9c4fc bellard
void helper_fprem1(void)
1181 3ec9c4fc bellard
{
1182 3ec9c4fc bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
1183 3ec9c4fc bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
1184 3ec9c4fc bellard
    int expdif;
1185 3ec9c4fc bellard
    int q;
1186 3ec9c4fc bellard
1187 3ec9c4fc bellard
    fpsrcop = ST0;
1188 3ec9c4fc bellard
    fptemp = ST1;
1189 3ec9c4fc bellard
    fpsrcop1.d = fpsrcop;
1190 3ec9c4fc bellard
    fptemp1.d = fptemp;
1191 3ec9c4fc bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1192 3ec9c4fc bellard
    if (expdif < 53) {
1193 3ec9c4fc bellard
        dblq = fpsrcop / fptemp;
1194 3ec9c4fc bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1195 3ec9c4fc bellard
        ST0 = fpsrcop - fptemp*dblq;
1196 3ec9c4fc bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
1197 3ec9c4fc bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1198 3ec9c4fc bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
1199 3ec9c4fc bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1200 3ec9c4fc bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1201 3ec9c4fc bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1202 3ec9c4fc bellard
    } else {
1203 3ec9c4fc bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
1204 3ec9c4fc bellard
        fptemp = pow(2.0, expdif-50);
1205 3ec9c4fc bellard
        fpsrcop = (ST0 / ST1) / fptemp;
1206 3ec9c4fc bellard
        /* fpsrcop = integer obtained by rounding to the nearest */
1207 3ec9c4fc bellard
        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
1208 3ec9c4fc bellard
            floor(fpsrcop): ceil(fpsrcop);
1209 3ec9c4fc bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
1210 3ec9c4fc bellard
    }
1211 3ec9c4fc bellard
}
1212 3ec9c4fc bellard
1213 3ec9c4fc bellard
void helper_fprem(void)
1214 3ec9c4fc bellard
{
1215 3ec9c4fc bellard
    CPU86_LDouble dblq, fpsrcop, fptemp;
1216 3ec9c4fc bellard
    CPU86_LDoubleU fpsrcop1, fptemp1;
1217 3ec9c4fc bellard
    int expdif;
1218 3ec9c4fc bellard
    int q;
1219 3ec9c4fc bellard
    
1220 3ec9c4fc bellard
    fpsrcop = ST0;
1221 3ec9c4fc bellard
    fptemp = ST1;
1222 3ec9c4fc bellard
    fpsrcop1.d = fpsrcop;
1223 3ec9c4fc bellard
    fptemp1.d = fptemp;
1224 3ec9c4fc bellard
    expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
1225 3ec9c4fc bellard
    if ( expdif < 53 ) {
1226 3ec9c4fc bellard
        dblq = fpsrcop / fptemp;
1227 3ec9c4fc bellard
        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
1228 3ec9c4fc bellard
        ST0 = fpsrcop - fptemp*dblq;
1229 3ec9c4fc bellard
        q = (int)dblq; /* cutting off top bits is assumed here */
1230 3ec9c4fc bellard
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
1231 3ec9c4fc bellard
                                /* (C0,C1,C3) <-- (q2,q1,q0) */
1232 3ec9c4fc bellard
        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
1233 3ec9c4fc bellard
        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
1234 3ec9c4fc bellard
        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
1235 3ec9c4fc bellard
    } else {
1236 3ec9c4fc bellard
        env->fpus |= 0x400;  /* C2 <-- 1 */
1237 3ec9c4fc bellard
        fptemp = pow(2.0, expdif-50);
1238 3ec9c4fc bellard
        fpsrcop = (ST0 / ST1) / fptemp;
1239 3ec9c4fc bellard
        /* fpsrcop = integer obtained by chopping */
1240 3ec9c4fc bellard
        fpsrcop = (fpsrcop < 0.0)?
1241 3ec9c4fc bellard
            -(floor(fabs(fpsrcop))): floor(fpsrcop);
1242 3ec9c4fc bellard
        ST0 -= (ST1 * fpsrcop * fptemp);
1243 3ec9c4fc bellard
    }
1244 3ec9c4fc bellard
}
1245 3ec9c4fc bellard
1246 3ec9c4fc bellard
void helper_fyl2xp1(void)
1247 3ec9c4fc bellard
{
1248 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1249 3ec9c4fc bellard
1250 3ec9c4fc bellard
    fptemp = ST0;
1251 3ec9c4fc bellard
    if ((fptemp+1.0)>0.0) {
1252 3ec9c4fc bellard
        fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
1253 3ec9c4fc bellard
        ST1 *= fptemp;
1254 3ec9c4fc bellard
        fpop();
1255 3ec9c4fc bellard
    } else { 
1256 3ec9c4fc bellard
        env->fpus &= (~0x4700);
1257 3ec9c4fc bellard
        env->fpus |= 0x400;
1258 3ec9c4fc bellard
    }
1259 3ec9c4fc bellard
}
1260 3ec9c4fc bellard
1261 3ec9c4fc bellard
void helper_fsqrt(void)
1262 3ec9c4fc bellard
{
1263 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1264 3ec9c4fc bellard
1265 3ec9c4fc bellard
    fptemp = ST0;
1266 3ec9c4fc bellard
    if (fptemp<0.0) { 
1267 3ec9c4fc bellard
        env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
1268 3ec9c4fc bellard
        env->fpus |= 0x400;
1269 3ec9c4fc bellard
    }
1270 3ec9c4fc bellard
    ST0 = sqrt(fptemp);
1271 3ec9c4fc bellard
}
1272 3ec9c4fc bellard
1273 3ec9c4fc bellard
void helper_fsincos(void)
1274 3ec9c4fc bellard
{
1275 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1276 3ec9c4fc bellard
1277 3ec9c4fc bellard
    fptemp = ST0;
1278 3ec9c4fc bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1279 3ec9c4fc bellard
        env->fpus |= 0x400;
1280 3ec9c4fc bellard
    } else {
1281 3ec9c4fc bellard
        ST0 = sin(fptemp);
1282 3ec9c4fc bellard
        fpush();
1283 3ec9c4fc bellard
        ST0 = cos(fptemp);
1284 3ec9c4fc bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1285 3ec9c4fc bellard
        /* the above code is for  |arg| < 2**63 only */
1286 3ec9c4fc bellard
    }
1287 3ec9c4fc bellard
}
1288 3ec9c4fc bellard
1289 3ec9c4fc bellard
void helper_frndint(void)
1290 3ec9c4fc bellard
{
1291 1e5ffbed bellard
    CPU86_LDouble a;
1292 1e5ffbed bellard
1293 1e5ffbed bellard
    a = ST0;
1294 1e5ffbed bellard
#ifdef __arm__
1295 1e5ffbed bellard
    switch(env->fpuc & RC_MASK) {
1296 1e5ffbed bellard
    default:
1297 1e5ffbed bellard
    case RC_NEAR:
1298 1e5ffbed bellard
        asm("rndd %0, %1" : "=f" (a) : "f"(a));
1299 1e5ffbed bellard
        break;
1300 1e5ffbed bellard
    case RC_DOWN:
1301 1e5ffbed bellard
        asm("rnddm %0, %1" : "=f" (a) : "f"(a));
1302 1e5ffbed bellard
        break;
1303 1e5ffbed bellard
    case RC_UP:
1304 1e5ffbed bellard
        asm("rnddp %0, %1" : "=f" (a) : "f"(a));
1305 1e5ffbed bellard
        break;
1306 1e5ffbed bellard
    case RC_CHOP:
1307 1e5ffbed bellard
        asm("rnddz %0, %1" : "=f" (a) : "f"(a));
1308 1e5ffbed bellard
        break;
1309 1e5ffbed bellard
    }
1310 1e5ffbed bellard
#else
1311 1e5ffbed bellard
    a = rint(a);
1312 1e5ffbed bellard
#endif
1313 1e5ffbed bellard
    ST0 = a;
1314 3ec9c4fc bellard
}
1315 3ec9c4fc bellard
1316 3ec9c4fc bellard
void helper_fscale(void)
1317 3ec9c4fc bellard
{
1318 3ec9c4fc bellard
    CPU86_LDouble fpsrcop, fptemp;
1319 3ec9c4fc bellard
1320 3ec9c4fc bellard
    fpsrcop = 2.0;
1321 3ec9c4fc bellard
    fptemp = pow(fpsrcop,ST1);
1322 3ec9c4fc bellard
    ST0 *= fptemp;
1323 3ec9c4fc bellard
}
1324 3ec9c4fc bellard
1325 3ec9c4fc bellard
void helper_fsin(void)
1326 3ec9c4fc bellard
{
1327 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1328 3ec9c4fc bellard
1329 3ec9c4fc bellard
    fptemp = ST0;
1330 3ec9c4fc bellard
    if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1331 3ec9c4fc bellard
        env->fpus |= 0x400;
1332 3ec9c4fc bellard
    } else {
1333 3ec9c4fc bellard
        ST0 = sin(fptemp);
1334 3ec9c4fc bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1335 3ec9c4fc bellard
        /* the above code is for  |arg| < 2**53 only */
1336 3ec9c4fc bellard
    }
1337 3ec9c4fc bellard
}
1338 3ec9c4fc bellard
1339 3ec9c4fc bellard
void helper_fcos(void)
1340 3ec9c4fc bellard
{
1341 3ec9c4fc bellard
    CPU86_LDouble fptemp;
1342 3ec9c4fc bellard
1343 3ec9c4fc bellard
    fptemp = ST0;
1344 3ec9c4fc bellard
    if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
1345 3ec9c4fc bellard
        env->fpus |= 0x400;
1346 3ec9c4fc bellard
    } else {
1347 3ec9c4fc bellard
        ST0 = cos(fptemp);
1348 3ec9c4fc bellard
        env->fpus &= (~0x400);  /* C2 <-- 0 */
1349 3ec9c4fc bellard
        /* the above code is for  |arg5 < 2**63 only */
1350 3ec9c4fc bellard
    }
1351 3ec9c4fc bellard
}
1352 3ec9c4fc bellard
1353 3ec9c4fc bellard
void helper_fxam_ST0(void)
1354 3ec9c4fc bellard
{
1355 3ec9c4fc bellard
    CPU86_LDoubleU temp;
1356 3ec9c4fc bellard
    int expdif;
1357 3ec9c4fc bellard
1358 3ec9c4fc bellard
    temp.d = ST0;
1359 3ec9c4fc bellard
1360 3ec9c4fc bellard
    env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
1361 3ec9c4fc bellard
    if (SIGND(temp))
1362 3ec9c4fc bellard
        env->fpus |= 0x200; /* C1 <-- 1 */
1363 3ec9c4fc bellard
1364 3ec9c4fc bellard
    expdif = EXPD(temp);
1365 3ec9c4fc bellard
    if (expdif == MAXEXPD) {
1366 3ec9c4fc bellard
        if (MANTD(temp) == 0)
1367 3ec9c4fc bellard
            env->fpus |=  0x500 /*Infinity*/;
1368 3ec9c4fc bellard
        else
1369 3ec9c4fc bellard
            env->fpus |=  0x100 /*NaN*/;
1370 3ec9c4fc bellard
    } else if (expdif == 0) {
1371 3ec9c4fc bellard
        if (MANTD(temp) == 0)
1372 3ec9c4fc bellard
            env->fpus |=  0x4000 /*Zero*/;
1373 3ec9c4fc bellard
        else
1374 3ec9c4fc bellard
            env->fpus |= 0x4400 /*Denormal*/;
1375 3ec9c4fc bellard
    } else {
1376 3ec9c4fc bellard
        env->fpus |= 0x400;
1377 3ec9c4fc bellard
    }
1378 3ec9c4fc bellard
}
1379 3ec9c4fc bellard
1380 3ec9c4fc bellard
void helper_fstenv(uint8_t *ptr, int data32)
1381 3ec9c4fc bellard
{
1382 3ec9c4fc bellard
    int fpus, fptag, exp, i;
1383 3ec9c4fc bellard
    uint64_t mant;
1384 3ec9c4fc bellard
    CPU86_LDoubleU tmp;
1385 3ec9c4fc bellard
1386 3ec9c4fc bellard
    fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
1387 3ec9c4fc bellard
    fptag = 0;
1388 3ec9c4fc bellard
    for (i=7; i>=0; i--) {
1389 3ec9c4fc bellard
        fptag <<= 2;
1390 3ec9c4fc bellard
        if (env->fptags[i]) {
1391 3ec9c4fc bellard
            fptag |= 3;
1392 3ec9c4fc bellard
        } else {
1393 3ec9c4fc bellard
            tmp.d = env->fpregs[i];
1394 3ec9c4fc bellard
            exp = EXPD(tmp);
1395 3ec9c4fc bellard
            mant = MANTD(tmp);
1396 3ec9c4fc bellard
            if (exp == 0 && mant == 0) {
1397 3ec9c4fc bellard
                /* zero */
1398 3ec9c4fc bellard
                fptag |= 1;
1399 3ec9c4fc bellard
            } else if (exp == 0 || exp == MAXEXPD
1400 3ec9c4fc bellard
#ifdef USE_X86LDOUBLE
1401 3ec9c4fc bellard
                       || (mant & (1LL << 63)) == 0
1402 3ec9c4fc bellard
#endif
1403 3ec9c4fc bellard
                       ) {
1404 3ec9c4fc bellard
                /* NaNs, infinity, denormal */
1405 3ec9c4fc bellard
                fptag |= 2;
1406 3ec9c4fc bellard
            }
1407 3ec9c4fc bellard
        }
1408 3ec9c4fc bellard
    }
1409 3ec9c4fc bellard
    if (data32) {
1410 3ec9c4fc bellard
        /* 32 bit */
1411 3ec9c4fc bellard
        stl(ptr, env->fpuc);
1412 3ec9c4fc bellard
        stl(ptr + 4, fpus);
1413 3ec9c4fc bellard
        stl(ptr + 8, fptag);
1414 3ec9c4fc bellard
        stl(ptr + 12, 0);
1415 3ec9c4fc bellard
        stl(ptr + 16, 0);
1416 3ec9c4fc bellard
        stl(ptr + 20, 0);
1417 3ec9c4fc bellard
        stl(ptr + 24, 0);
1418 3ec9c4fc bellard
    } else {
1419 3ec9c4fc bellard
        /* 16 bit */
1420 3ec9c4fc bellard
        stw(ptr, env->fpuc);
1421 3ec9c4fc bellard
        stw(ptr + 2, fpus);
1422 3ec9c4fc bellard
        stw(ptr + 4, fptag);
1423 3ec9c4fc bellard
        stw(ptr + 6, 0);
1424 3ec9c4fc bellard
        stw(ptr + 8, 0);
1425 3ec9c4fc bellard
        stw(ptr + 10, 0);
1426 3ec9c4fc bellard
        stw(ptr + 12, 0);
1427 3ec9c4fc bellard
    }
1428 3ec9c4fc bellard
}
1429 3ec9c4fc bellard
1430 3ec9c4fc bellard
void helper_fldenv(uint8_t *ptr, int data32)
1431 3ec9c4fc bellard
{
1432 3ec9c4fc bellard
    int i, fpus, fptag;
1433 3ec9c4fc bellard
1434 3ec9c4fc bellard
    if (data32) {
1435 3ec9c4fc bellard
        env->fpuc = lduw(ptr);
1436 3ec9c4fc bellard
        fpus = lduw(ptr + 4);
1437 3ec9c4fc bellard
        fptag = lduw(ptr + 8);
1438 3ec9c4fc bellard
    }
1439 3ec9c4fc bellard
    else {
1440 3ec9c4fc bellard
        env->fpuc = lduw(ptr);
1441 3ec9c4fc bellard
        fpus = lduw(ptr + 2);
1442 3ec9c4fc bellard
        fptag = lduw(ptr + 4);
1443 3ec9c4fc bellard
    }
1444 3ec9c4fc bellard
    env->fpstt = (fpus >> 11) & 7;
1445 3ec9c4fc bellard
    env->fpus = fpus & ~0x3800;
1446 3ec9c4fc bellard
    for(i = 0;i < 7; i++) {
1447 3ec9c4fc bellard
        env->fptags[i] = ((fptag & 3) == 3);
1448 3ec9c4fc bellard
        fptag >>= 2;
1449 3ec9c4fc bellard
    }
1450 3ec9c4fc bellard
}
1451 3ec9c4fc bellard
1452 3ec9c4fc bellard
void helper_fsave(uint8_t *ptr, int data32)
1453 3ec9c4fc bellard
{
1454 3ec9c4fc bellard
    CPU86_LDouble tmp;
1455 3ec9c4fc bellard
    int i;
1456 3ec9c4fc bellard
1457 3ec9c4fc bellard
    helper_fstenv(ptr, data32);
1458 3ec9c4fc bellard
1459 3ec9c4fc bellard
    ptr += (14 << data32);
1460 3ec9c4fc bellard
    for(i = 0;i < 8; i++) {
1461 3ec9c4fc bellard
        tmp = ST(i);
1462 3ec9c4fc bellard
#ifdef USE_X86LDOUBLE
1463 3ec9c4fc bellard
        *(long double *)ptr = tmp;
1464 3ec9c4fc bellard
#else
1465 3ec9c4fc bellard
        helper_fstt(tmp, ptr);
1466 3ec9c4fc bellard
#endif        
1467 3ec9c4fc bellard
        ptr += 10;
1468 3ec9c4fc bellard
    }
1469 3ec9c4fc bellard
1470 3ec9c4fc bellard
    /* fninit */
1471 3ec9c4fc bellard
    env->fpus = 0;
1472 3ec9c4fc bellard
    env->fpstt = 0;
1473 3ec9c4fc bellard
    env->fpuc = 0x37f;
1474 3ec9c4fc bellard
    env->fptags[0] = 1;
1475 3ec9c4fc bellard
    env->fptags[1] = 1;
1476 3ec9c4fc bellard
    env->fptags[2] = 1;
1477 3ec9c4fc bellard
    env->fptags[3] = 1;
1478 3ec9c4fc bellard
    env->fptags[4] = 1;
1479 3ec9c4fc bellard
    env->fptags[5] = 1;
1480 3ec9c4fc bellard
    env->fptags[6] = 1;
1481 3ec9c4fc bellard
    env->fptags[7] = 1;
1482 3ec9c4fc bellard
}
1483 3ec9c4fc bellard
1484 3ec9c4fc bellard
void helper_frstor(uint8_t *ptr, int data32)
1485 3ec9c4fc bellard
{
1486 3ec9c4fc bellard
    CPU86_LDouble tmp;
1487 3ec9c4fc bellard
    int i;
1488 3ec9c4fc bellard
1489 3ec9c4fc bellard
    helper_fldenv(ptr, data32);
1490 3ec9c4fc bellard
    ptr += (14 << data32);
1491 3ec9c4fc bellard
1492 3ec9c4fc bellard
    for(i = 0;i < 8; i++) {
1493 3ec9c4fc bellard
#ifdef USE_X86LDOUBLE
1494 3ec9c4fc bellard
        tmp = *(long double *)ptr;
1495 3ec9c4fc bellard
#else
1496 3ec9c4fc bellard
        tmp = helper_fldt(ptr);
1497 3ec9c4fc bellard
#endif        
1498 3ec9c4fc bellard
        ST(i) = tmp;
1499 3ec9c4fc bellard
        ptr += 10;
1500 3ec9c4fc bellard
    }
1501 3ec9c4fc bellard
}