1687a306fSXin LI /* $OpenBSD: x86emu.c,v 1.9 2014/06/15 11:04:49 pirofti Exp $ */
2884e6d60SXin LI /* $NetBSD: x86emu.c,v 1.7 2009/02/03 19:26:29 joerg Exp $ */
3884e6d60SXin LI
4884e6d60SXin LI /*
5884e6d60SXin LI *
6884e6d60SXin LI * Realmode X86 Emulator Library
7884e6d60SXin LI *
8884e6d60SXin LI * Copyright (C) 1996-1999 SciTech Software, Inc.
9884e6d60SXin LI * Copyright (C) David Mosberger-Tang
10884e6d60SXin LI * Copyright (C) 1999 Egbert Eich
11884e6d60SXin LI * Copyright (C) 2007 Joerg Sonnenberger
12884e6d60SXin LI *
13884e6d60SXin LI * ========================================================================
14884e6d60SXin LI *
15884e6d60SXin LI * Permission to use, copy, modify, distribute, and sell this software and
16884e6d60SXin LI * its documentation for any purpose is hereby granted without fee,
17884e6d60SXin LI * provided that the above copyright notice appear in all copies and that
18884e6d60SXin LI * both that copyright notice and this permission notice appear in
19884e6d60SXin LI * supporting documentation, and that the name of the authors not be used
20884e6d60SXin LI * in advertising or publicity pertaining to distribution of the software
21884e6d60SXin LI * without specific, written prior permission. The authors makes no
22884e6d60SXin LI * representations about the suitability of this software for any purpose.
23884e6d60SXin LI * It is provided "as is" without express or implied warranty.
24884e6d60SXin LI *
25884e6d60SXin LI * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
26884e6d60SXin LI * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
27884e6d60SXin LI * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
28884e6d60SXin LI * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
29884e6d60SXin LI * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
30884e6d60SXin LI * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
31884e6d60SXin LI * PERFORMANCE OF THIS SOFTWARE.
32884e6d60SXin LI *
33884e6d60SXin LI */
34884e6d60SXin LI
35efba048eSXin LI #include <contrib/x86emu/x86emu.h>
36efba048eSXin LI #include <contrib/x86emu/x86emu_regs.h>
37884e6d60SXin LI
38884e6d60SXin LI static void x86emu_intr_raise (struct x86emu *, uint8_t type);
39884e6d60SXin LI
40884e6d60SXin LI static void x86emu_exec_one_byte(struct x86emu *);
41884e6d60SXin LI static void x86emu_exec_two_byte(struct x86emu *);
42884e6d60SXin LI
43884e6d60SXin LI static void fetch_decode_modrm (struct x86emu *);
44884e6d60SXin LI static uint8_t fetch_byte_imm (struct x86emu *);
45884e6d60SXin LI static uint16_t fetch_word_imm (struct x86emu *);
46884e6d60SXin LI static uint32_t fetch_long_imm (struct x86emu *);
47884e6d60SXin LI static uint8_t fetch_data_byte (struct x86emu *, uint32_t offset);
48efba048eSXin LI static uint8_t fetch_byte (struct x86emu *, u_int segment, uint32_t offset);
49884e6d60SXin LI static uint16_t fetch_data_word (struct x86emu *, uint32_t offset);
50884e6d60SXin LI static uint16_t fetch_word (struct x86emu *, uint32_t segment, uint32_t offset);
51884e6d60SXin LI static uint32_t fetch_data_long (struct x86emu *, uint32_t offset);
52884e6d60SXin LI static uint32_t fetch_long (struct x86emu *, uint32_t segment, uint32_t offset);
53884e6d60SXin LI static void store_data_byte (struct x86emu *, uint32_t offset, uint8_t val);
54884e6d60SXin LI static void store_byte (struct x86emu *, uint32_t segment, uint32_t offset, uint8_t val);
55884e6d60SXin LI static void store_data_word (struct x86emu *, uint32_t offset, uint16_t val);
56884e6d60SXin LI static void store_word (struct x86emu *, uint32_t segment, uint32_t offset, uint16_t val);
57884e6d60SXin LI static void store_data_long (struct x86emu *, uint32_t offset, uint32_t val);
58884e6d60SXin LI static void store_long (struct x86emu *, uint32_t segment, uint32_t offset, uint32_t val);
59884e6d60SXin LI static uint8_t* decode_rl_byte_register(struct x86emu *);
60884e6d60SXin LI static uint16_t* decode_rl_word_register(struct x86emu *);
61884e6d60SXin LI static uint32_t* decode_rl_long_register(struct x86emu *);
62884e6d60SXin LI static uint8_t* decode_rh_byte_register(struct x86emu *);
63884e6d60SXin LI static uint16_t* decode_rh_word_register(struct x86emu *);
64884e6d60SXin LI static uint32_t* decode_rh_long_register(struct x86emu *);
65884e6d60SXin LI static uint16_t* decode_rh_seg_register(struct x86emu *);
66884e6d60SXin LI static uint32_t decode_rl_address(struct x86emu *);
67884e6d60SXin LI
68884e6d60SXin LI static uint8_t decode_and_fetch_byte(struct x86emu *);
69884e6d60SXin LI static uint16_t decode_and_fetch_word(struct x86emu *);
70884e6d60SXin LI static uint32_t decode_and_fetch_long(struct x86emu *);
71884e6d60SXin LI
72884e6d60SXin LI static uint8_t decode_and_fetch_byte_imm8(struct x86emu *, uint8_t *);
73884e6d60SXin LI static uint16_t decode_and_fetch_word_imm8(struct x86emu *, uint8_t *);
74884e6d60SXin LI static uint32_t decode_and_fetch_long_imm8(struct x86emu *, uint8_t *);
75884e6d60SXin LI
76884e6d60SXin LI static uint16_t decode_and_fetch_word_disp(struct x86emu *, int16_t);
77884e6d60SXin LI static uint32_t decode_and_fetch_long_disp(struct x86emu *, int16_t);
78884e6d60SXin LI
79884e6d60SXin LI static void write_back_byte(struct x86emu *, uint8_t);
80884e6d60SXin LI static void write_back_word(struct x86emu *, uint16_t);
81884e6d60SXin LI static void write_back_long(struct x86emu *, uint32_t);
82884e6d60SXin LI
83884e6d60SXin LI static uint16_t aaa_word (struct x86emu *, uint16_t d);
84884e6d60SXin LI static uint16_t aas_word (struct x86emu *, uint16_t d);
85884e6d60SXin LI static uint16_t aad_word (struct x86emu *, uint16_t d);
86884e6d60SXin LI static uint16_t aam_word (struct x86emu *, uint8_t d);
87884e6d60SXin LI static uint8_t adc_byte (struct x86emu *, uint8_t d, uint8_t s);
88884e6d60SXin LI static uint16_t adc_word (struct x86emu *, uint16_t d, uint16_t s);
89884e6d60SXin LI static uint32_t adc_long (struct x86emu *, uint32_t d, uint32_t s);
90884e6d60SXin LI static uint8_t add_byte (struct x86emu *, uint8_t d, uint8_t s);
91884e6d60SXin LI static uint16_t add_word (struct x86emu *, uint16_t d, uint16_t s);
92884e6d60SXin LI static uint32_t add_long (struct x86emu *, uint32_t d, uint32_t s);
93884e6d60SXin LI static uint8_t and_byte (struct x86emu *, uint8_t d, uint8_t s);
94884e6d60SXin LI static uint16_t and_word (struct x86emu *, uint16_t d, uint16_t s);
95884e6d60SXin LI static uint32_t and_long (struct x86emu *, uint32_t d, uint32_t s);
96884e6d60SXin LI static uint8_t cmp_byte (struct x86emu *, uint8_t d, uint8_t s);
97884e6d60SXin LI static uint16_t cmp_word (struct x86emu *, uint16_t d, uint16_t s);
98884e6d60SXin LI static uint32_t cmp_long (struct x86emu *, uint32_t d, uint32_t s);
99884e6d60SXin LI static void cmp_byte_no_return (struct x86emu *, uint8_t d, uint8_t s);
100884e6d60SXin LI static void cmp_word_no_return (struct x86emu *, uint16_t d, uint16_t s);
101884e6d60SXin LI static void cmp_long_no_return (struct x86emu *, uint32_t d, uint32_t s);
102884e6d60SXin LI static uint8_t daa_byte (struct x86emu *, uint8_t d);
103884e6d60SXin LI static uint8_t das_byte (struct x86emu *, uint8_t d);
104884e6d60SXin LI static uint8_t dec_byte (struct x86emu *, uint8_t d);
105884e6d60SXin LI static uint16_t dec_word (struct x86emu *, uint16_t d);
106884e6d60SXin LI static uint32_t dec_long (struct x86emu *, uint32_t d);
107884e6d60SXin LI static uint8_t inc_byte (struct x86emu *, uint8_t d);
108884e6d60SXin LI static uint16_t inc_word (struct x86emu *, uint16_t d);
109884e6d60SXin LI static uint32_t inc_long (struct x86emu *, uint32_t d);
110884e6d60SXin LI static uint8_t or_byte (struct x86emu *, uint8_t d, uint8_t s);
111884e6d60SXin LI static uint16_t or_word (struct x86emu *, uint16_t d, uint16_t s);
112884e6d60SXin LI static uint32_t or_long (struct x86emu *, uint32_t d, uint32_t s);
113884e6d60SXin LI static uint8_t neg_byte (struct x86emu *, uint8_t s);
114884e6d60SXin LI static uint16_t neg_word (struct x86emu *, uint16_t s);
115884e6d60SXin LI static uint32_t neg_long (struct x86emu *, uint32_t s);
116884e6d60SXin LI static uint8_t rcl_byte (struct x86emu *, uint8_t d, uint8_t s);
117884e6d60SXin LI static uint16_t rcl_word (struct x86emu *, uint16_t d, uint8_t s);
118884e6d60SXin LI static uint32_t rcl_long (struct x86emu *, uint32_t d, uint8_t s);
119884e6d60SXin LI static uint8_t rcr_byte (struct x86emu *, uint8_t d, uint8_t s);
120884e6d60SXin LI static uint16_t rcr_word (struct x86emu *, uint16_t d, uint8_t s);
121884e6d60SXin LI static uint32_t rcr_long (struct x86emu *, uint32_t d, uint8_t s);
122884e6d60SXin LI static uint8_t rol_byte (struct x86emu *, uint8_t d, uint8_t s);
123884e6d60SXin LI static uint16_t rol_word (struct x86emu *, uint16_t d, uint8_t s);
124884e6d60SXin LI static uint32_t rol_long (struct x86emu *, uint32_t d, uint8_t s);
125884e6d60SXin LI static uint8_t ror_byte (struct x86emu *, uint8_t d, uint8_t s);
126884e6d60SXin LI static uint16_t ror_word (struct x86emu *, uint16_t d, uint8_t s);
127884e6d60SXin LI static uint32_t ror_long (struct x86emu *, uint32_t d, uint8_t s);
128884e6d60SXin LI static uint8_t shl_byte (struct x86emu *, uint8_t d, uint8_t s);
129884e6d60SXin LI static uint16_t shl_word (struct x86emu *, uint16_t d, uint8_t s);
130884e6d60SXin LI static uint32_t shl_long (struct x86emu *, uint32_t d, uint8_t s);
131884e6d60SXin LI static uint8_t shr_byte (struct x86emu *, uint8_t d, uint8_t s);
132884e6d60SXin LI static uint16_t shr_word (struct x86emu *, uint16_t d, uint8_t s);
133884e6d60SXin LI static uint32_t shr_long (struct x86emu *, uint32_t d, uint8_t s);
134884e6d60SXin LI static uint8_t sar_byte (struct x86emu *, uint8_t d, uint8_t s);
135884e6d60SXin LI static uint16_t sar_word (struct x86emu *, uint16_t d, uint8_t s);
136884e6d60SXin LI static uint32_t sar_long (struct x86emu *, uint32_t d, uint8_t s);
137884e6d60SXin LI static uint16_t shld_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
138884e6d60SXin LI static uint32_t shld_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
139884e6d60SXin LI static uint16_t shrd_word (struct x86emu *, uint16_t d, uint16_t fill, uint8_t s);
140884e6d60SXin LI static uint32_t shrd_long (struct x86emu *, uint32_t d, uint32_t fill, uint8_t s);
141884e6d60SXin LI static uint8_t sbb_byte (struct x86emu *, uint8_t d, uint8_t s);
142884e6d60SXin LI static uint16_t sbb_word (struct x86emu *, uint16_t d, uint16_t s);
143884e6d60SXin LI static uint32_t sbb_long (struct x86emu *, uint32_t d, uint32_t s);
144884e6d60SXin LI static uint8_t sub_byte (struct x86emu *, uint8_t d, uint8_t s);
145884e6d60SXin LI static uint16_t sub_word (struct x86emu *, uint16_t d, uint16_t s);
146884e6d60SXin LI static uint32_t sub_long (struct x86emu *, uint32_t d, uint32_t s);
147884e6d60SXin LI static void test_byte (struct x86emu *, uint8_t d, uint8_t s);
148884e6d60SXin LI static void test_word (struct x86emu *, uint16_t d, uint16_t s);
149884e6d60SXin LI static void test_long (struct x86emu *, uint32_t d, uint32_t s);
150884e6d60SXin LI static uint8_t xor_byte (struct x86emu *, uint8_t d, uint8_t s);
151884e6d60SXin LI static uint16_t xor_word (struct x86emu *, uint16_t d, uint16_t s);
152884e6d60SXin LI static uint32_t xor_long (struct x86emu *, uint32_t d, uint32_t s);
153884e6d60SXin LI static void imul_byte (struct x86emu *, uint8_t s);
154884e6d60SXin LI static void imul_word (struct x86emu *, uint16_t s);
155884e6d60SXin LI static void imul_long (struct x86emu *, uint32_t s);
156884e6d60SXin LI static void mul_byte (struct x86emu *, uint8_t s);
157884e6d60SXin LI static void mul_word (struct x86emu *, uint16_t s);
158884e6d60SXin LI static void mul_long (struct x86emu *, uint32_t s);
159884e6d60SXin LI static void idiv_byte (struct x86emu *, uint8_t s);
160884e6d60SXin LI static void idiv_word (struct x86emu *, uint16_t s);
161884e6d60SXin LI static void idiv_long (struct x86emu *, uint32_t s);
162884e6d60SXin LI static void div_byte (struct x86emu *, uint8_t s);
163884e6d60SXin LI static void div_word (struct x86emu *, uint16_t s);
164884e6d60SXin LI static void div_long (struct x86emu *, uint32_t s);
165884e6d60SXin LI static void ins (struct x86emu *, int size);
166884e6d60SXin LI static void outs (struct x86emu *, int size);
167884e6d60SXin LI static void push_word (struct x86emu *, uint16_t w);
168884e6d60SXin LI static void push_long (struct x86emu *, uint32_t w);
169884e6d60SXin LI static uint16_t pop_word (struct x86emu *);
170884e6d60SXin LI static uint32_t pop_long (struct x86emu *);
171884e6d60SXin LI
172884e6d60SXin LI /*
173884e6d60SXin LI * REMARKS:
174884e6d60SXin LI * Handles any pending asychronous interrupts.
175884e6d60SXin LI */
176884e6d60SXin LI static void
x86emu_intr_dispatch(struct x86emu * emu,uint8_t intno)177884e6d60SXin LI x86emu_intr_dispatch(struct x86emu *emu, uint8_t intno)
178884e6d60SXin LI {
179884e6d60SXin LI if (emu->_x86emu_intrTab[intno]) {
180884e6d60SXin LI (*emu->_x86emu_intrTab[intno]) (emu, intno);
181884e6d60SXin LI } else {
182884e6d60SXin LI push_word(emu, (uint16_t) emu->x86.R_FLG);
183884e6d60SXin LI CLEAR_FLAG(F_IF);
184884e6d60SXin LI CLEAR_FLAG(F_TF);
185884e6d60SXin LI push_word(emu, emu->x86.R_CS);
186884e6d60SXin LI emu->x86.R_CS = fetch_word(emu, 0, intno * 4 + 2);
187884e6d60SXin LI push_word(emu, emu->x86.R_IP);
188884e6d60SXin LI emu->x86.R_IP = fetch_word(emu, 0, intno * 4);
189884e6d60SXin LI }
190884e6d60SXin LI }
191884e6d60SXin LI
192884e6d60SXin LI static void
x86emu_intr_handle(struct x86emu * emu)193884e6d60SXin LI x86emu_intr_handle(struct x86emu *emu)
194884e6d60SXin LI {
195884e6d60SXin LI uint8_t intno;
196884e6d60SXin LI
197884e6d60SXin LI if (emu->x86.intr & INTR_SYNCH) {
198884e6d60SXin LI intno = emu->x86.intno;
199884e6d60SXin LI emu->x86.intr = 0;
200884e6d60SXin LI x86emu_intr_dispatch(emu, intno);
201884e6d60SXin LI }
202884e6d60SXin LI }
203884e6d60SXin LI
204884e6d60SXin LI /*
205884e6d60SXin LI * PARAMETERS:
206884e6d60SXin LI * intrnum - Interrupt number to raise
207884e6d60SXin LI *
208884e6d60SXin LI * REMARKS:
209884e6d60SXin LI * Raise the specified interrupt to be handled before the execution of the
210884e6d60SXin LI * next instruction.
211884e6d60SXin LI */
212884e6d60SXin LI void
x86emu_intr_raise(struct x86emu * emu,uint8_t intrnum)213884e6d60SXin LI x86emu_intr_raise(struct x86emu *emu, uint8_t intrnum)
214884e6d60SXin LI {
215884e6d60SXin LI emu->x86.intno = intrnum;
216884e6d60SXin LI emu->x86.intr |= INTR_SYNCH;
217884e6d60SXin LI }
218884e6d60SXin LI
219884e6d60SXin LI /*
220884e6d60SXin LI * REMARKS:
221884e6d60SXin LI * Main execution loop for the emulator. We return from here when the system
222884e6d60SXin LI * halts, which is normally caused by a stack fault when we return from the
223884e6d60SXin LI * original real mode call.
224884e6d60SXin LI */
225884e6d60SXin LI void
x86emu_exec(struct x86emu * emu)226884e6d60SXin LI x86emu_exec(struct x86emu *emu)
227884e6d60SXin LI {
228884e6d60SXin LI emu->x86.intr = 0;
229884e6d60SXin LI
230884e6d60SXin LI if (setjmp(emu->exec_state))
231884e6d60SXin LI return;
232884e6d60SXin LI
233884e6d60SXin LI for (;;) {
234884e6d60SXin LI if (emu->x86.intr) {
23506325fe0SXin LI if (((emu->x86.intr & INTR_SYNCH) &&
23606325fe0SXin LI (emu->x86.intno == 0 || emu->x86.intno == 2)) ||
237884e6d60SXin LI !ACCESS_FLAG(F_IF)) {
238884e6d60SXin LI x86emu_intr_handle(emu);
239884e6d60SXin LI }
240884e6d60SXin LI }
241884e6d60SXin LI if (emu->x86.R_CS == 0 && emu->x86.R_IP == 0)
242884e6d60SXin LI return;
243884e6d60SXin LI x86emu_exec_one_byte(emu);
244884e6d60SXin LI ++emu->cur_cycles;
245884e6d60SXin LI }
246884e6d60SXin LI }
247884e6d60SXin LI
248884e6d60SXin LI void
x86emu_exec_call(struct x86emu * emu,uint16_t seg,uint16_t off)249884e6d60SXin LI x86emu_exec_call(struct x86emu *emu, uint16_t seg, uint16_t off)
250884e6d60SXin LI {
251884e6d60SXin LI push_word(emu, 0);
252884e6d60SXin LI push_word(emu, 0);
253884e6d60SXin LI emu->x86.R_CS = seg;
254884e6d60SXin LI emu->x86.R_IP = off;
255884e6d60SXin LI
256884e6d60SXin LI x86emu_exec(emu);
257884e6d60SXin LI }
258884e6d60SXin LI
259884e6d60SXin LI void
x86emu_exec_intr(struct x86emu * emu,uint8_t intr)260884e6d60SXin LI x86emu_exec_intr(struct x86emu *emu, uint8_t intr)
261884e6d60SXin LI {
262884e6d60SXin LI push_word(emu, emu->x86.R_FLG);
263884e6d60SXin LI CLEAR_FLAG(F_IF);
264884e6d60SXin LI CLEAR_FLAG(F_TF);
265884e6d60SXin LI push_word(emu, 0);
266884e6d60SXin LI push_word(emu, 0);
267884e6d60SXin LI emu->x86.R_CS = (*emu->emu_rdw)(emu, intr * 4 + 2);
268884e6d60SXin LI emu->x86.R_IP = (*emu->emu_rdw)(emu, intr * 4);
269884e6d60SXin LI emu->x86.intr = 0;
270884e6d60SXin LI
271884e6d60SXin LI x86emu_exec(emu);
272884e6d60SXin LI }
273884e6d60SXin LI
274884e6d60SXin LI /*
275884e6d60SXin LI * REMARKS:
276884e6d60SXin LI * Halts the system by setting the halted system flag.
277884e6d60SXin LI */
278884e6d60SXin LI void
x86emu_halt_sys(struct x86emu * emu)279884e6d60SXin LI x86emu_halt_sys(struct x86emu *emu)
280884e6d60SXin LI {
281884e6d60SXin LI longjmp(emu->exec_state, 1);
282884e6d60SXin LI }
283884e6d60SXin LI
284884e6d60SXin LI /*
285884e6d60SXin LI * PARAMETERS:
286884e6d60SXin LI * mod - Mod value from decoded byte
287884e6d60SXin LI * regh - Reg h value from decoded byte
288884e6d60SXin LI * regl - Reg l value from decoded byte
289884e6d60SXin LI *
290884e6d60SXin LI * REMARKS:
291884e6d60SXin LI * Raise the specified interrupt to be handled before the execution of the
292884e6d60SXin LI * next instruction.
293884e6d60SXin LI *
294884e6d60SXin LI * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
295884e6d60SXin LI */
296884e6d60SXin LI static void
fetch_decode_modrm(struct x86emu * emu)297884e6d60SXin LI fetch_decode_modrm(struct x86emu *emu)
298884e6d60SXin LI {
299884e6d60SXin LI int fetched;
300884e6d60SXin LI
301884e6d60SXin LI fetched = fetch_byte_imm(emu);
302884e6d60SXin LI emu->cur_mod = (fetched >> 6) & 0x03;
303884e6d60SXin LI emu->cur_rh = (fetched >> 3) & 0x07;
304884e6d60SXin LI emu->cur_rl = (fetched >> 0) & 0x07;
305884e6d60SXin LI }
306884e6d60SXin LI
307884e6d60SXin LI /*
308884e6d60SXin LI * RETURNS:
309884e6d60SXin LI * Immediate byte value read from instruction queue
310884e6d60SXin LI *
311884e6d60SXin LI * REMARKS:
312884e6d60SXin LI * This function returns the immediate byte from the instruction queue, and
313884e6d60SXin LI * moves the instruction pointer to the next value.
314884e6d60SXin LI *
315884e6d60SXin LI * NOTE: Do not inline this function, as (*emu->emu_rdb) is already inline!
316884e6d60SXin LI */
317884e6d60SXin LI static uint8_t
fetch_byte_imm(struct x86emu * emu)318884e6d60SXin LI fetch_byte_imm(struct x86emu *emu)
319884e6d60SXin LI {
320884e6d60SXin LI uint8_t fetched;
321884e6d60SXin LI
322884e6d60SXin LI fetched = fetch_byte(emu, emu->x86.R_CS, emu->x86.R_IP);
323884e6d60SXin LI emu->x86.R_IP++;
324884e6d60SXin LI return fetched;
325884e6d60SXin LI }
326884e6d60SXin LI
327884e6d60SXin LI /*
328884e6d60SXin LI * RETURNS:
329884e6d60SXin LI * Immediate word value read from instruction queue
330884e6d60SXin LI *
331884e6d60SXin LI * REMARKS:
332884e6d60SXin LI * This function returns the immediate byte from the instruction queue, and
333884e6d60SXin LI * moves the instruction pointer to the next value.
334884e6d60SXin LI *
335884e6d60SXin LI * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
336884e6d60SXin LI */
337884e6d60SXin LI static uint16_t
fetch_word_imm(struct x86emu * emu)338884e6d60SXin LI fetch_word_imm(struct x86emu *emu)
339884e6d60SXin LI {
340884e6d60SXin LI uint16_t fetched;
341884e6d60SXin LI
342884e6d60SXin LI fetched = fetch_word(emu, emu->x86.R_CS, emu->x86.R_IP);
343884e6d60SXin LI emu->x86.R_IP += 2;
344884e6d60SXin LI return fetched;
345884e6d60SXin LI }
346884e6d60SXin LI
347884e6d60SXin LI /*
348884e6d60SXin LI * RETURNS:
349884e6d60SXin LI * Immediate lone value read from instruction queue
350884e6d60SXin LI *
351884e6d60SXin LI * REMARKS:
352884e6d60SXin LI * This function returns the immediate byte from the instruction queue, and
353884e6d60SXin LI * moves the instruction pointer to the next value.
354884e6d60SXin LI *
355884e6d60SXin LI * NOTE: Do not inline this function, as (*emu->emu_rdw) is already inline!
356884e6d60SXin LI */
357884e6d60SXin LI static uint32_t
fetch_long_imm(struct x86emu * emu)358884e6d60SXin LI fetch_long_imm(struct x86emu *emu)
359884e6d60SXin LI {
360884e6d60SXin LI uint32_t fetched;
361884e6d60SXin LI
362884e6d60SXin LI fetched = fetch_long(emu, emu->x86.R_CS, emu->x86.R_IP);
363884e6d60SXin LI emu->x86.R_IP += 4;
364884e6d60SXin LI return fetched;
365884e6d60SXin LI }
366884e6d60SXin LI
367884e6d60SXin LI /*
368884e6d60SXin LI * RETURNS:
369884e6d60SXin LI * Value of the default data segment
370884e6d60SXin LI *
371884e6d60SXin LI * REMARKS:
372884e6d60SXin LI * Inline function that returns the default data segment for the current
373884e6d60SXin LI * instruction.
374884e6d60SXin LI *
375884e6d60SXin LI * On the x86 processor, the default segment is not always DS if there is
376884e6d60SXin LI * no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
377884e6d60SXin LI * addresses relative to SS (ie: on the stack). So, at the minimum, all
378884e6d60SXin LI * decodings of addressing modes would have to set/clear a bit describing
379884e6d60SXin LI * whether the access is relative to DS or SS. That is the function of the
380884e6d60SXin LI * cpu-state-varible emu->x86.mode. There are several potential states:
381884e6d60SXin LI *
382884e6d60SXin LI * repe prefix seen (handled elsewhere)
383884e6d60SXin LI * repne prefix seen (ditto)
384884e6d60SXin LI *
385884e6d60SXin LI * cs segment override
386884e6d60SXin LI * ds segment override
387884e6d60SXin LI * es segment override
388884e6d60SXin LI * fs segment override
389884e6d60SXin LI * gs segment override
390884e6d60SXin LI * ss segment override
391884e6d60SXin LI *
392884e6d60SXin LI * ds/ss select (in absense of override)
393884e6d60SXin LI *
394884e6d60SXin LI * Each of the above 7 items are handled with a bit in the mode field.
395884e6d60SXin LI */
396884e6d60SXin LI static uint32_t
get_data_segment(struct x86emu * emu)397884e6d60SXin LI get_data_segment(struct x86emu *emu)
398884e6d60SXin LI {
399884e6d60SXin LI switch (emu->x86.mode & SYSMODE_SEGMASK) {
400884e6d60SXin LI case 0: /* default case: use ds register */
401884e6d60SXin LI case SYSMODE_SEGOVR_DS:
402884e6d60SXin LI case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
403884e6d60SXin LI return emu->x86.R_DS;
404884e6d60SXin LI case SYSMODE_SEG_DS_SS:/* non-overridden, use ss register */
405884e6d60SXin LI return emu->x86.R_SS;
406884e6d60SXin LI case SYSMODE_SEGOVR_CS:
407884e6d60SXin LI case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
408884e6d60SXin LI return emu->x86.R_CS;
409884e6d60SXin LI case SYSMODE_SEGOVR_ES:
410884e6d60SXin LI case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
411884e6d60SXin LI return emu->x86.R_ES;
412884e6d60SXin LI case SYSMODE_SEGOVR_FS:
413884e6d60SXin LI case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
414884e6d60SXin LI return emu->x86.R_FS;
415884e6d60SXin LI case SYSMODE_SEGOVR_GS:
416884e6d60SXin LI case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
417884e6d60SXin LI return emu->x86.R_GS;
418884e6d60SXin LI case SYSMODE_SEGOVR_SS:
419884e6d60SXin LI case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
420884e6d60SXin LI return emu->x86.R_SS;
421884e6d60SXin LI }
422884e6d60SXin LI x86emu_halt_sys(emu);
423884e6d60SXin LI }
424884e6d60SXin LI
425884e6d60SXin LI /*
426884e6d60SXin LI * PARAMETERS:
427884e6d60SXin LI * offset - Offset to load data from
428884e6d60SXin LI *
429884e6d60SXin LI * RETURNS:
430884e6d60SXin LI * Byte value read from the absolute memory location.
431884e6d60SXin LI *
432884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
433884e6d60SXin LI */
434884e6d60SXin LI static uint8_t
fetch_data_byte(struct x86emu * emu,uint32_t offset)435884e6d60SXin LI fetch_data_byte(struct x86emu *emu, uint32_t offset)
436884e6d60SXin LI {
437884e6d60SXin LI return fetch_byte(emu, get_data_segment(emu), offset);
438884e6d60SXin LI }
439884e6d60SXin LI
440884e6d60SXin LI /*
441884e6d60SXin LI * PARAMETERS:
442884e6d60SXin LI * offset - Offset to load data from
443884e6d60SXin LI *
444884e6d60SXin LI * RETURNS:
445884e6d60SXin LI * Word value read from the absolute memory location.
446884e6d60SXin LI *
447884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
448884e6d60SXin LI */
449884e6d60SXin LI static uint16_t
fetch_data_word(struct x86emu * emu,uint32_t offset)450884e6d60SXin LI fetch_data_word(struct x86emu *emu, uint32_t offset)
451884e6d60SXin LI {
452884e6d60SXin LI return fetch_word(emu, get_data_segment(emu), offset);
453884e6d60SXin LI }
454884e6d60SXin LI
455884e6d60SXin LI /*
456884e6d60SXin LI * PARAMETERS:
457884e6d60SXin LI * offset - Offset to load data from
458884e6d60SXin LI *
459884e6d60SXin LI * RETURNS:
460884e6d60SXin LI * Long value read from the absolute memory location.
461884e6d60SXin LI *
462884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
463884e6d60SXin LI */
464884e6d60SXin LI static uint32_t
fetch_data_long(struct x86emu * emu,uint32_t offset)465884e6d60SXin LI fetch_data_long(struct x86emu *emu, uint32_t offset)
466884e6d60SXin LI {
467884e6d60SXin LI return fetch_long(emu, get_data_segment(emu), offset);
468884e6d60SXin LI }
469884e6d60SXin LI
470884e6d60SXin LI /*
471884e6d60SXin LI * PARAMETERS:
472884e6d60SXin LI * segment - Segment to load data from
473884e6d60SXin LI * offset - Offset to load data from
474884e6d60SXin LI *
475884e6d60SXin LI * RETURNS:
476884e6d60SXin LI * Byte value read from the absolute memory location.
477884e6d60SXin LI *
478884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
479884e6d60SXin LI */
480884e6d60SXin LI static uint8_t
fetch_byte(struct x86emu * emu,uint32_t segment,uint32_t offset)481884e6d60SXin LI fetch_byte(struct x86emu *emu, uint32_t segment, uint32_t offset)
482884e6d60SXin LI {
483884e6d60SXin LI return (*emu->emu_rdb) (emu, ((uint32_t) segment << 4) + offset);
484884e6d60SXin LI }
485884e6d60SXin LI
486884e6d60SXin LI /*
487884e6d60SXin LI * PARAMETERS:
488884e6d60SXin LI * segment - Segment to load data from
489884e6d60SXin LI * offset - Offset to load data from
490884e6d60SXin LI *
491884e6d60SXin LI * RETURNS:
492884e6d60SXin LI * Word value read from the absolute memory location.
493884e6d60SXin LI *
494884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
495884e6d60SXin LI */
496884e6d60SXin LI static uint16_t
fetch_word(struct x86emu * emu,uint32_t segment,uint32_t offset)497884e6d60SXin LI fetch_word(struct x86emu *emu, uint32_t segment, uint32_t offset)
498884e6d60SXin LI {
499884e6d60SXin LI return (*emu->emu_rdw) (emu, ((uint32_t) segment << 4) + offset);
500884e6d60SXin LI }
501884e6d60SXin LI
502884e6d60SXin LI /*
503884e6d60SXin LI * PARAMETERS:
504884e6d60SXin LI * segment - Segment to load data from
505884e6d60SXin LI * offset - Offset to load data from
506884e6d60SXin LI *
507884e6d60SXin LI * RETURNS:
508884e6d60SXin LI * Long value read from the absolute memory location.
509884e6d60SXin LI *
510884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_rdX) is already inline!
511884e6d60SXin LI */
512884e6d60SXin LI static uint32_t
fetch_long(struct x86emu * emu,uint32_t segment,uint32_t offset)513884e6d60SXin LI fetch_long(struct x86emu *emu, uint32_t segment, uint32_t offset)
514884e6d60SXin LI {
515884e6d60SXin LI return (*emu->emu_rdl) (emu, ((uint32_t) segment << 4) + offset);
516884e6d60SXin LI }
517884e6d60SXin LI
518884e6d60SXin LI /*
519884e6d60SXin LI * PARAMETERS:
520884e6d60SXin LI * offset - Offset to store data at
521884e6d60SXin LI * val - Value to store
522884e6d60SXin LI *
523884e6d60SXin LI * REMARKS:
524884e6d60SXin LI * Writes a word value to an segmented memory location. The segment used is
525884e6d60SXin LI * the current 'default' segment, which may have been overridden.
526884e6d60SXin LI *
527884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
528884e6d60SXin LI */
529884e6d60SXin LI static void
store_data_byte(struct x86emu * emu,uint32_t offset,uint8_t val)530884e6d60SXin LI store_data_byte(struct x86emu *emu, uint32_t offset, uint8_t val)
531884e6d60SXin LI {
532884e6d60SXin LI store_byte(emu, get_data_segment(emu), offset, val);
533884e6d60SXin LI }
534884e6d60SXin LI
535884e6d60SXin LI /*
536884e6d60SXin LI * PARAMETERS:
537884e6d60SXin LI * offset - Offset to store data at
538884e6d60SXin LI * val - Value to store
539884e6d60SXin LI *
540884e6d60SXin LI * REMARKS:
541884e6d60SXin LI * Writes a word value to an segmented memory location. The segment used is
542884e6d60SXin LI * the current 'default' segment, which may have been overridden.
543884e6d60SXin LI *
544884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
545884e6d60SXin LI */
546884e6d60SXin LI static void
store_data_word(struct x86emu * emu,uint32_t offset,uint16_t val)547884e6d60SXin LI store_data_word(struct x86emu *emu, uint32_t offset, uint16_t val)
548884e6d60SXin LI {
549884e6d60SXin LI store_word(emu, get_data_segment(emu), offset, val);
550884e6d60SXin LI }
551884e6d60SXin LI
552884e6d60SXin LI /*
553884e6d60SXin LI * PARAMETERS:
554884e6d60SXin LI * offset - Offset to store data at
555884e6d60SXin LI * val - Value to store
556884e6d60SXin LI *
557884e6d60SXin LI * REMARKS:
558884e6d60SXin LI * Writes a long value to an segmented memory location. The segment used is
559884e6d60SXin LI * the current 'default' segment, which may have been overridden.
560884e6d60SXin LI *
561884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
562884e6d60SXin LI */
563884e6d60SXin LI static void
store_data_long(struct x86emu * emu,uint32_t offset,uint32_t val)564884e6d60SXin LI store_data_long(struct x86emu *emu, uint32_t offset, uint32_t val)
565884e6d60SXin LI {
566884e6d60SXin LI store_long(emu, get_data_segment(emu), offset, val);
567884e6d60SXin LI }
568884e6d60SXin LI
569884e6d60SXin LI /*
570884e6d60SXin LI * PARAMETERS:
571884e6d60SXin LI * segment - Segment to store data at
572884e6d60SXin LI * offset - Offset to store data at
573884e6d60SXin LI * val - Value to store
574884e6d60SXin LI *
575884e6d60SXin LI * REMARKS:
576884e6d60SXin LI * Writes a byte value to an absolute memory location.
577884e6d60SXin LI *
578884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
579884e6d60SXin LI */
580884e6d60SXin LI static void
store_byte(struct x86emu * emu,uint32_t segment,uint32_t offset,uint8_t val)581884e6d60SXin LI store_byte(struct x86emu *emu, uint32_t segment, uint32_t offset, uint8_t val)
582884e6d60SXin LI {
583884e6d60SXin LI (*emu->emu_wrb) (emu, ((uint32_t) segment << 4) + offset, val);
584884e6d60SXin LI }
585884e6d60SXin LI
586884e6d60SXin LI /*
587884e6d60SXin LI * PARAMETERS:
588884e6d60SXin LI * segment - Segment to store data at
589884e6d60SXin LI * offset - Offset to store data at
590884e6d60SXin LI * val - Value to store
591884e6d60SXin LI *
592884e6d60SXin LI * REMARKS:
593884e6d60SXin LI * Writes a word value to an absolute memory location.
594884e6d60SXin LI *
595884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
596884e6d60SXin LI */
597884e6d60SXin LI static void
store_word(struct x86emu * emu,uint32_t segment,uint32_t offset,uint16_t val)598884e6d60SXin LI store_word(struct x86emu *emu, uint32_t segment, uint32_t offset, uint16_t val)
599884e6d60SXin LI {
600884e6d60SXin LI (*emu->emu_wrw) (emu, ((uint32_t) segment << 4) + offset, val);
601884e6d60SXin LI }
602884e6d60SXin LI
603884e6d60SXin LI /*
604884e6d60SXin LI * PARAMETERS:
605884e6d60SXin LI * segment - Segment to store data at
606884e6d60SXin LI * offset - Offset to store data at
607884e6d60SXin LI * val - Value to store
608884e6d60SXin LI *
609884e6d60SXin LI * REMARKS:
610884e6d60SXin LI * Writes a long value to an absolute memory location.
611884e6d60SXin LI *
612884e6d60SXin LI * NOTE: Do not inline this function as (*emu->emu_wrX) is already inline!
613884e6d60SXin LI */
614884e6d60SXin LI static void
store_long(struct x86emu * emu,uint32_t segment,uint32_t offset,uint32_t val)615884e6d60SXin LI store_long(struct x86emu *emu, uint32_t segment, uint32_t offset, uint32_t val)
616884e6d60SXin LI {
617884e6d60SXin LI (*emu->emu_wrl) (emu, ((uint32_t) segment << 4) + offset, val);
618884e6d60SXin LI }
619884e6d60SXin LI
620884e6d60SXin LI /*
621884e6d60SXin LI * PARAMETERS:
622884e6d60SXin LI * reg - Register to decode
623884e6d60SXin LI *
624884e6d60SXin LI * RETURNS:
625884e6d60SXin LI * Pointer to the appropriate register
626884e6d60SXin LI *
627884e6d60SXin LI * REMARKS:
628884e6d60SXin LI * Return a pointer to the register given by the R/RM field of the
629884e6d60SXin LI * modrm byte, for byte operands. Also enables the decoding of instructions.
630884e6d60SXin LI */
631884e6d60SXin LI static uint8_t *
decode_rm_byte_register(struct x86emu * emu,int reg)632884e6d60SXin LI decode_rm_byte_register(struct x86emu *emu, int reg)
633884e6d60SXin LI {
634884e6d60SXin LI switch (reg) {
635884e6d60SXin LI case 0:
636884e6d60SXin LI return &emu->x86.R_AL;
637884e6d60SXin LI case 1:
638884e6d60SXin LI return &emu->x86.R_CL;
639884e6d60SXin LI case 2:
640884e6d60SXin LI return &emu->x86.R_DL;
641884e6d60SXin LI case 3:
642884e6d60SXin LI return &emu->x86.R_BL;
643884e6d60SXin LI case 4:
644884e6d60SXin LI return &emu->x86.R_AH;
645884e6d60SXin LI case 5:
646884e6d60SXin LI return &emu->x86.R_CH;
647884e6d60SXin LI case 6:
648884e6d60SXin LI return &emu->x86.R_DH;
649884e6d60SXin LI case 7:
650884e6d60SXin LI return &emu->x86.R_BH;
651884e6d60SXin LI default:
652884e6d60SXin LI x86emu_halt_sys(emu);
653884e6d60SXin LI }
654884e6d60SXin LI }
655884e6d60SXin LI
656884e6d60SXin LI static uint8_t *
decode_rl_byte_register(struct x86emu * emu)657884e6d60SXin LI decode_rl_byte_register(struct x86emu *emu)
658884e6d60SXin LI {
659884e6d60SXin LI return decode_rm_byte_register(emu, emu->cur_rl);
660884e6d60SXin LI }
661884e6d60SXin LI
662884e6d60SXin LI static uint8_t *
decode_rh_byte_register(struct x86emu * emu)663884e6d60SXin LI decode_rh_byte_register(struct x86emu *emu)
664884e6d60SXin LI {
665884e6d60SXin LI return decode_rm_byte_register(emu, emu->cur_rh);
666884e6d60SXin LI }
667884e6d60SXin LI
668884e6d60SXin LI /*
669884e6d60SXin LI * PARAMETERS:
670884e6d60SXin LI * reg - Register to decode
671884e6d60SXin LI *
672884e6d60SXin LI * RETURNS:
673884e6d60SXin LI * Pointer to the appropriate register
674884e6d60SXin LI *
675884e6d60SXin LI * REMARKS:
676884e6d60SXin LI * Return a pointer to the register given by the R/RM field of the
677884e6d60SXin LI * modrm byte, for word operands. Also enables the decoding of instructions.
678884e6d60SXin LI */
679884e6d60SXin LI static uint16_t *
decode_rm_word_register(struct x86emu * emu,int reg)680884e6d60SXin LI decode_rm_word_register(struct x86emu *emu, int reg)
681884e6d60SXin LI {
682884e6d60SXin LI switch (reg) {
683884e6d60SXin LI case 0:
684884e6d60SXin LI return &emu->x86.R_AX;
685884e6d60SXin LI case 1:
686884e6d60SXin LI return &emu->x86.R_CX;
687884e6d60SXin LI case 2:
688884e6d60SXin LI return &emu->x86.R_DX;
689884e6d60SXin LI case 3:
690884e6d60SXin LI return &emu->x86.R_BX;
691884e6d60SXin LI case 4:
692884e6d60SXin LI return &emu->x86.R_SP;
693884e6d60SXin LI case 5:
694884e6d60SXin LI return &emu->x86.R_BP;
695884e6d60SXin LI case 6:
696884e6d60SXin LI return &emu->x86.R_SI;
697884e6d60SXin LI case 7:
698884e6d60SXin LI return &emu->x86.R_DI;
699884e6d60SXin LI default:
700884e6d60SXin LI x86emu_halt_sys(emu);
701884e6d60SXin LI }
702884e6d60SXin LI }
703884e6d60SXin LI
704884e6d60SXin LI static uint16_t *
decode_rl_word_register(struct x86emu * emu)705884e6d60SXin LI decode_rl_word_register(struct x86emu *emu)
706884e6d60SXin LI {
707884e6d60SXin LI return decode_rm_word_register(emu, emu->cur_rl);
708884e6d60SXin LI }
709884e6d60SXin LI
710884e6d60SXin LI static uint16_t *
decode_rh_word_register(struct x86emu * emu)711884e6d60SXin LI decode_rh_word_register(struct x86emu *emu)
712884e6d60SXin LI {
713884e6d60SXin LI return decode_rm_word_register(emu, emu->cur_rh);
714884e6d60SXin LI }
715884e6d60SXin LI
716884e6d60SXin LI /*
717884e6d60SXin LI * PARAMETERS:
718884e6d60SXin LI * reg - Register to decode
719884e6d60SXin LI *
720884e6d60SXin LI * RETURNS:
721884e6d60SXin LI * Pointer to the appropriate register
722884e6d60SXin LI *
723884e6d60SXin LI * REMARKS:
724884e6d60SXin LI * Return a pointer to the register given by the R/RM field of the
725884e6d60SXin LI * modrm byte, for dword operands. Also enables the decoding of instructions.
726884e6d60SXin LI */
727884e6d60SXin LI static uint32_t *
decode_rm_long_register(struct x86emu * emu,int reg)728884e6d60SXin LI decode_rm_long_register(struct x86emu *emu, int reg)
729884e6d60SXin LI {
730884e6d60SXin LI switch (reg) {
731884e6d60SXin LI case 0:
732884e6d60SXin LI return &emu->x86.R_EAX;
733884e6d60SXin LI case 1:
734884e6d60SXin LI return &emu->x86.R_ECX;
735884e6d60SXin LI case 2:
736884e6d60SXin LI return &emu->x86.R_EDX;
737884e6d60SXin LI case 3:
738884e6d60SXin LI return &emu->x86.R_EBX;
739884e6d60SXin LI case 4:
740884e6d60SXin LI return &emu->x86.R_ESP;
741884e6d60SXin LI case 5:
742884e6d60SXin LI return &emu->x86.R_EBP;
743884e6d60SXin LI case 6:
744884e6d60SXin LI return &emu->x86.R_ESI;
745884e6d60SXin LI case 7:
746884e6d60SXin LI return &emu->x86.R_EDI;
747884e6d60SXin LI default:
748884e6d60SXin LI x86emu_halt_sys(emu);
749884e6d60SXin LI }
750884e6d60SXin LI }
751884e6d60SXin LI
752884e6d60SXin LI static uint32_t *
decode_rl_long_register(struct x86emu * emu)753884e6d60SXin LI decode_rl_long_register(struct x86emu *emu)
754884e6d60SXin LI {
755884e6d60SXin LI return decode_rm_long_register(emu, emu->cur_rl);
756884e6d60SXin LI }
757884e6d60SXin LI
758884e6d60SXin LI static uint32_t *
decode_rh_long_register(struct x86emu * emu)759884e6d60SXin LI decode_rh_long_register(struct x86emu *emu)
760884e6d60SXin LI {
761884e6d60SXin LI return decode_rm_long_register(emu, emu->cur_rh);
762884e6d60SXin LI }
763884e6d60SXin LI
764884e6d60SXin LI
765884e6d60SXin LI /*
766884e6d60SXin LI * PARAMETERS:
767884e6d60SXin LI * reg - Register to decode
768884e6d60SXin LI *
769884e6d60SXin LI * RETURNS:
770884e6d60SXin LI * Pointer to the appropriate register
771884e6d60SXin LI *
772884e6d60SXin LI * REMARKS:
773884e6d60SXin LI * Return a pointer to the register given by the R/RM field of the
774884e6d60SXin LI * modrm byte, for word operands, modified from above for the weirdo
775884e6d60SXin LI * special case of segreg operands. Also enables the decoding of instructions.
776884e6d60SXin LI */
777884e6d60SXin LI static uint16_t *
decode_rh_seg_register(struct x86emu * emu)778884e6d60SXin LI decode_rh_seg_register(struct x86emu *emu)
779884e6d60SXin LI {
780884e6d60SXin LI switch (emu->cur_rh) {
781884e6d60SXin LI case 0:
782884e6d60SXin LI return &emu->x86.R_ES;
783884e6d60SXin LI case 1:
784884e6d60SXin LI return &emu->x86.R_CS;
785884e6d60SXin LI case 2:
786884e6d60SXin LI return &emu->x86.R_SS;
787884e6d60SXin LI case 3:
788884e6d60SXin LI return &emu->x86.R_DS;
789884e6d60SXin LI case 4:
790884e6d60SXin LI return &emu->x86.R_FS;
791884e6d60SXin LI case 5:
792884e6d60SXin LI return &emu->x86.R_GS;
793884e6d60SXin LI default:
794884e6d60SXin LI x86emu_halt_sys(emu);
795884e6d60SXin LI }
796884e6d60SXin LI }
79706325fe0SXin LI
798884e6d60SXin LI /*
79906325fe0SXin LI * Return offset from the SIB Byte.
800884e6d60SXin LI */
801884e6d60SXin LI static uint32_t
decode_sib_address(struct x86emu * emu,int sib,int mod)802884e6d60SXin LI decode_sib_address(struct x86emu *emu, int sib, int mod)
803884e6d60SXin LI {
804884e6d60SXin LI uint32_t base = 0, i = 0, scale = 1;
805884e6d60SXin LI
806884e6d60SXin LI switch (sib & 0x07) {
807884e6d60SXin LI case 0:
808884e6d60SXin LI base = emu->x86.R_EAX;
809884e6d60SXin LI break;
810884e6d60SXin LI case 1:
811884e6d60SXin LI base = emu->x86.R_ECX;
812884e6d60SXin LI
813884e6d60SXin LI break;
814884e6d60SXin LI case 2:
815884e6d60SXin LI base = emu->x86.R_EDX;
816884e6d60SXin LI break;
817884e6d60SXin LI case 3:
818884e6d60SXin LI base = emu->x86.R_EBX;
819884e6d60SXin LI break;
820884e6d60SXin LI case 4:
821884e6d60SXin LI base = emu->x86.R_ESP;
822884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
823884e6d60SXin LI break;
824884e6d60SXin LI case 5:
825884e6d60SXin LI if (mod == 0) {
826884e6d60SXin LI base = fetch_long_imm(emu);
827884e6d60SXin LI } else {
828884e6d60SXin LI base = emu->x86.R_EBP;
829884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
830884e6d60SXin LI }
831884e6d60SXin LI break;
832884e6d60SXin LI case 6:
833884e6d60SXin LI base = emu->x86.R_ESI;
834884e6d60SXin LI break;
835884e6d60SXin LI case 7:
836884e6d60SXin LI base = emu->x86.R_EDI;
837884e6d60SXin LI break;
838884e6d60SXin LI }
839884e6d60SXin LI switch ((sib >> 3) & 0x07) {
840884e6d60SXin LI case 0:
841884e6d60SXin LI i = emu->x86.R_EAX;
842884e6d60SXin LI break;
843884e6d60SXin LI case 1:
844884e6d60SXin LI i = emu->x86.R_ECX;
845884e6d60SXin LI break;
846884e6d60SXin LI case 2:
847884e6d60SXin LI i = emu->x86.R_EDX;
848884e6d60SXin LI break;
849884e6d60SXin LI case 3:
850884e6d60SXin LI i = emu->x86.R_EBX;
851884e6d60SXin LI break;
852884e6d60SXin LI case 4:
853884e6d60SXin LI i = 0;
854884e6d60SXin LI break;
855884e6d60SXin LI case 5:
856884e6d60SXin LI i = emu->x86.R_EBP;
857884e6d60SXin LI break;
858884e6d60SXin LI case 6:
859884e6d60SXin LI i = emu->x86.R_ESI;
860884e6d60SXin LI break;
861884e6d60SXin LI case 7:
862884e6d60SXin LI i = emu->x86.R_EDI;
863884e6d60SXin LI break;
864884e6d60SXin LI }
865884e6d60SXin LI scale = 1 << ((sib >> 6) & 0x03);
866884e6d60SXin LI return base + (i * scale);
867884e6d60SXin LI }
868884e6d60SXin LI
869884e6d60SXin LI /*
870884e6d60SXin LI * PARAMETERS:
871884e6d60SXin LI * rm - RM value to decode
872884e6d60SXin LI *
873884e6d60SXin LI * RETURNS:
874884e6d60SXin LI * Offset in memory for the address decoding
875884e6d60SXin LI *
876884e6d60SXin LI * REMARKS:
877884e6d60SXin LI * Return the offset given by mod=00, mod=01 or mod=10 addressing.
878884e6d60SXin LI * Also enables the decoding of instructions.
879884e6d60SXin LI */
880884e6d60SXin LI static uint32_t
decode_rl_address(struct x86emu * emu)881884e6d60SXin LI decode_rl_address(struct x86emu *emu)
882884e6d60SXin LI {
883884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
884884e6d60SXin LI uint32_t offset, sib;
885884e6d60SXin LI /* 32-bit addressing */
886884e6d60SXin LI switch (emu->cur_rl) {
887884e6d60SXin LI case 0:
888884e6d60SXin LI offset = emu->x86.R_EAX;
889884e6d60SXin LI break;
890884e6d60SXin LI case 1:
891884e6d60SXin LI offset = emu->x86.R_ECX;
892884e6d60SXin LI break;
893884e6d60SXin LI case 2:
894884e6d60SXin LI offset = emu->x86.R_EDX;
895884e6d60SXin LI break;
896884e6d60SXin LI case 3:
897884e6d60SXin LI offset = emu->x86.R_EBX;
898884e6d60SXin LI break;
899884e6d60SXin LI case 4:
900884e6d60SXin LI sib = fetch_byte_imm(emu);
901884e6d60SXin LI offset = decode_sib_address(emu, sib, 0);
902884e6d60SXin LI break;
903884e6d60SXin LI case 5:
904884e6d60SXin LI if (emu->cur_mod == 0) {
905884e6d60SXin LI offset = fetch_long_imm(emu);
906884e6d60SXin LI } else {
907884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
908884e6d60SXin LI offset = emu->x86.R_EBP;
909884e6d60SXin LI }
910884e6d60SXin LI break;
911884e6d60SXin LI case 6:
912884e6d60SXin LI offset = emu->x86.R_ESI;
913884e6d60SXin LI break;
914884e6d60SXin LI case 7:
915884e6d60SXin LI offset = emu->x86.R_EDI;
916884e6d60SXin LI break;
917884e6d60SXin LI default:
918884e6d60SXin LI x86emu_halt_sys(emu);
919884e6d60SXin LI }
920884e6d60SXin LI if (emu->cur_mod == 1)
921884e6d60SXin LI offset += (int8_t)fetch_byte_imm(emu);
922884e6d60SXin LI else if (emu->cur_mod == 2)
923884e6d60SXin LI offset += fetch_long_imm(emu);
924884e6d60SXin LI return offset;
925884e6d60SXin LI } else {
926884e6d60SXin LI uint16_t offset;
927884e6d60SXin LI
928884e6d60SXin LI /* 16-bit addressing */
929884e6d60SXin LI switch (emu->cur_rl) {
930884e6d60SXin LI case 0:
931884e6d60SXin LI offset = emu->x86.R_BX + emu->x86.R_SI;
932884e6d60SXin LI break;
933884e6d60SXin LI case 1:
934884e6d60SXin LI offset = emu->x86.R_BX + emu->x86.R_DI;
935884e6d60SXin LI break;
936884e6d60SXin LI case 2:
937884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
938884e6d60SXin LI offset = emu->x86.R_BP + emu->x86.R_SI;
939884e6d60SXin LI break;
940884e6d60SXin LI case 3:
941884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
942884e6d60SXin LI offset = emu->x86.R_BP + emu->x86.R_DI;
943884e6d60SXin LI break;
944884e6d60SXin LI case 4:
945884e6d60SXin LI offset = emu->x86.R_SI;
946884e6d60SXin LI break;
947884e6d60SXin LI case 5:
948884e6d60SXin LI offset = emu->x86.R_DI;
949884e6d60SXin LI break;
950884e6d60SXin LI case 6:
951884e6d60SXin LI if (emu->cur_mod == 0) {
952884e6d60SXin LI offset = fetch_word_imm(emu);
953884e6d60SXin LI } else {
954884e6d60SXin LI emu->x86.mode |= SYSMODE_SEG_DS_SS;
955884e6d60SXin LI offset = emu->x86.R_BP;
956884e6d60SXin LI }
957884e6d60SXin LI break;
958884e6d60SXin LI case 7:
959884e6d60SXin LI offset = emu->x86.R_BX;
960884e6d60SXin LI break;
961884e6d60SXin LI default:
962884e6d60SXin LI x86emu_halt_sys(emu);
963884e6d60SXin LI }
964884e6d60SXin LI if (emu->cur_mod == 1)
965884e6d60SXin LI offset += (int8_t)fetch_byte_imm(emu);
966884e6d60SXin LI else if (emu->cur_mod == 2)
967884e6d60SXin LI offset += fetch_word_imm(emu);
968884e6d60SXin LI return offset;
969884e6d60SXin LI }
970884e6d60SXin LI }
971884e6d60SXin LI
972884e6d60SXin LI static uint8_t
decode_and_fetch_byte(struct x86emu * emu)973884e6d60SXin LI decode_and_fetch_byte(struct x86emu *emu)
974884e6d60SXin LI {
975884e6d60SXin LI if (emu->cur_mod != 3) {
976884e6d60SXin LI emu->cur_offset = decode_rl_address(emu);
977884e6d60SXin LI return fetch_data_byte(emu, emu->cur_offset);
978884e6d60SXin LI } else {
979884e6d60SXin LI return *decode_rl_byte_register(emu);
980884e6d60SXin LI }
981884e6d60SXin LI }
982884e6d60SXin LI
983884e6d60SXin LI static uint16_t
decode_and_fetch_word_disp(struct x86emu * emu,int16_t disp)984884e6d60SXin LI decode_and_fetch_word_disp(struct x86emu *emu, int16_t disp)
985884e6d60SXin LI {
986884e6d60SXin LI if (emu->cur_mod != 3) {
987884e6d60SXin LI /* TODO: A20 gate emulation */
988884e6d60SXin LI emu->cur_offset = decode_rl_address(emu) + disp;
989884e6d60SXin LI if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
990884e6d60SXin LI emu->cur_offset &= 0xffff;
991884e6d60SXin LI return fetch_data_word(emu, emu->cur_offset);
992884e6d60SXin LI } else {
993884e6d60SXin LI return *decode_rl_word_register(emu);
994884e6d60SXin LI }
995884e6d60SXin LI }
996884e6d60SXin LI
997884e6d60SXin LI static uint32_t
decode_and_fetch_long_disp(struct x86emu * emu,int16_t disp)998884e6d60SXin LI decode_and_fetch_long_disp(struct x86emu *emu, int16_t disp)
999884e6d60SXin LI {
1000884e6d60SXin LI if (emu->cur_mod != 3) {
1001884e6d60SXin LI /* TODO: A20 gate emulation */
1002884e6d60SXin LI emu->cur_offset = decode_rl_address(emu) + disp;
1003884e6d60SXin LI if ((emu->x86.mode & SYSMODE_PREFIX_ADDR) == 0)
1004884e6d60SXin LI emu->cur_offset &= 0xffff;
1005884e6d60SXin LI return fetch_data_long(emu, emu->cur_offset);
1006884e6d60SXin LI } else {
1007884e6d60SXin LI return *decode_rl_long_register(emu);
1008884e6d60SXin LI }
1009884e6d60SXin LI }
1010884e6d60SXin LI
1011884e6d60SXin LI uint16_t
decode_and_fetch_word(struct x86emu * emu)1012884e6d60SXin LI decode_and_fetch_word(struct x86emu *emu)
1013884e6d60SXin LI {
1014884e6d60SXin LI return decode_and_fetch_word_disp(emu, 0);
1015884e6d60SXin LI }
1016884e6d60SXin LI
1017884e6d60SXin LI uint32_t
decode_and_fetch_long(struct x86emu * emu)1018884e6d60SXin LI decode_and_fetch_long(struct x86emu *emu)
1019884e6d60SXin LI {
1020884e6d60SXin LI return decode_and_fetch_long_disp(emu, 0);
1021884e6d60SXin LI }
1022884e6d60SXin LI
1023884e6d60SXin LI uint8_t
decode_and_fetch_byte_imm8(struct x86emu * emu,uint8_t * imm)1024884e6d60SXin LI decode_and_fetch_byte_imm8(struct x86emu *emu, uint8_t *imm)
1025884e6d60SXin LI {
1026884e6d60SXin LI if (emu->cur_mod != 3) {
1027884e6d60SXin LI emu->cur_offset = decode_rl_address(emu);
1028884e6d60SXin LI *imm = fetch_byte_imm(emu);
1029884e6d60SXin LI return fetch_data_byte(emu, emu->cur_offset);
1030884e6d60SXin LI } else {
1031884e6d60SXin LI *imm = fetch_byte_imm(emu);
1032884e6d60SXin LI return *decode_rl_byte_register(emu);
1033884e6d60SXin LI }
1034884e6d60SXin LI }
1035884e6d60SXin LI
1036884e6d60SXin LI static uint16_t
decode_and_fetch_word_imm8(struct x86emu * emu,uint8_t * imm)1037884e6d60SXin LI decode_and_fetch_word_imm8(struct x86emu *emu, uint8_t *imm)
1038884e6d60SXin LI {
1039884e6d60SXin LI if (emu->cur_mod != 3) {
1040884e6d60SXin LI emu->cur_offset = decode_rl_address(emu);
1041884e6d60SXin LI *imm = fetch_byte_imm(emu);
1042884e6d60SXin LI return fetch_data_word(emu, emu->cur_offset);
1043884e6d60SXin LI } else {
1044884e6d60SXin LI *imm = fetch_byte_imm(emu);
1045884e6d60SXin LI return *decode_rl_word_register(emu);
1046884e6d60SXin LI }
1047884e6d60SXin LI }
1048884e6d60SXin LI
1049884e6d60SXin LI static uint32_t
decode_and_fetch_long_imm8(struct x86emu * emu,uint8_t * imm)1050884e6d60SXin LI decode_and_fetch_long_imm8(struct x86emu *emu, uint8_t *imm)
1051884e6d60SXin LI {
1052884e6d60SXin LI if (emu->cur_mod != 3) {
1053884e6d60SXin LI emu->cur_offset = decode_rl_address(emu);
1054884e6d60SXin LI *imm = fetch_byte_imm(emu);
1055884e6d60SXin LI return fetch_data_long(emu, emu->cur_offset);
1056884e6d60SXin LI } else {
1057884e6d60SXin LI *imm = fetch_byte_imm(emu);
1058884e6d60SXin LI return *decode_rl_long_register(emu);
1059884e6d60SXin LI }
1060884e6d60SXin LI }
1061884e6d60SXin LI
1062884e6d60SXin LI static void
write_back_byte(struct x86emu * emu,uint8_t val)1063884e6d60SXin LI write_back_byte(struct x86emu *emu, uint8_t val)
1064884e6d60SXin LI {
1065884e6d60SXin LI if (emu->cur_mod != 3)
1066884e6d60SXin LI store_data_byte(emu, emu->cur_offset, val);
1067884e6d60SXin LI else
1068884e6d60SXin LI *decode_rl_byte_register(emu) = val;
1069884e6d60SXin LI }
1070884e6d60SXin LI
1071884e6d60SXin LI static void
write_back_word(struct x86emu * emu,uint16_t val)1072884e6d60SXin LI write_back_word(struct x86emu *emu, uint16_t val)
1073884e6d60SXin LI {
1074884e6d60SXin LI if (emu->cur_mod != 3)
1075884e6d60SXin LI store_data_word(emu, emu->cur_offset, val);
1076884e6d60SXin LI else
1077884e6d60SXin LI *decode_rl_word_register(emu) = val;
1078884e6d60SXin LI }
1079884e6d60SXin LI
1080884e6d60SXin LI static void
write_back_long(struct x86emu * emu,uint32_t val)1081884e6d60SXin LI write_back_long(struct x86emu *emu, uint32_t val)
1082884e6d60SXin LI {
1083884e6d60SXin LI if (emu->cur_mod != 3)
1084884e6d60SXin LI store_data_long(emu, emu->cur_offset, val);
1085884e6d60SXin LI else
1086884e6d60SXin LI *decode_rl_long_register(emu) = val;
1087884e6d60SXin LI }
1088884e6d60SXin LI
1089884e6d60SXin LI static void
common_inc_word_long(struct x86emu * emu,union x86emu_register * reg)1090884e6d60SXin LI common_inc_word_long(struct x86emu *emu, union x86emu_register *reg)
1091884e6d60SXin LI {
1092884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1093884e6d60SXin LI reg->I32_reg.e_reg = inc_long(emu, reg->I32_reg.e_reg);
1094884e6d60SXin LI else
1095884e6d60SXin LI reg->I16_reg.x_reg = inc_word(emu, reg->I16_reg.x_reg);
1096884e6d60SXin LI }
1097884e6d60SXin LI
1098884e6d60SXin LI static void
common_dec_word_long(struct x86emu * emu,union x86emu_register * reg)1099884e6d60SXin LI common_dec_word_long(struct x86emu *emu, union x86emu_register *reg)
1100884e6d60SXin LI {
1101884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1102884e6d60SXin LI reg->I32_reg.e_reg = dec_long(emu, reg->I32_reg.e_reg);
1103884e6d60SXin LI else
1104884e6d60SXin LI reg->I16_reg.x_reg = dec_word(emu, reg->I16_reg.x_reg);
1105884e6d60SXin LI }
1106884e6d60SXin LI
1107884e6d60SXin LI static void
common_binop_byte_rm_r(struct x86emu * emu,uint8_t (* binop)(struct x86emu *,uint8_t,uint8_t))110806325fe0SXin LI common_binop_byte_rm_r(struct x86emu *emu,
110906325fe0SXin LI uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
1110884e6d60SXin LI {
1111884e6d60SXin LI uint32_t destoffset;
1112884e6d60SXin LI uint8_t *destreg, srcval;
1113884e6d60SXin LI uint8_t destval;
1114884e6d60SXin LI
1115884e6d60SXin LI fetch_decode_modrm(emu);
1116884e6d60SXin LI srcval = *decode_rh_byte_register(emu);
1117884e6d60SXin LI if (emu->cur_mod != 3) {
1118884e6d60SXin LI destoffset = decode_rl_address(emu);
1119884e6d60SXin LI destval = fetch_data_byte(emu, destoffset);
1120884e6d60SXin LI destval = (*binop)(emu, destval, srcval);
1121884e6d60SXin LI store_data_byte(emu, destoffset, destval);
1122884e6d60SXin LI } else {
1123884e6d60SXin LI destreg = decode_rl_byte_register(emu);
1124884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1125884e6d60SXin LI }
1126884e6d60SXin LI }
1127884e6d60SXin LI
1128884e6d60SXin LI static void
common_binop_ns_byte_rm_r(struct x86emu * emu,void (* binop)(struct x86emu *,uint8_t,uint8_t))112906325fe0SXin LI common_binop_ns_byte_rm_r(struct x86emu *emu,
113006325fe0SXin LI void (*binop)(struct x86emu *, uint8_t, uint8_t))
1131884e6d60SXin LI {
1132884e6d60SXin LI uint32_t destoffset;
1133884e6d60SXin LI uint8_t destval, srcval;
1134884e6d60SXin LI
1135884e6d60SXin LI fetch_decode_modrm(emu);
1136884e6d60SXin LI srcval = *decode_rh_byte_register(emu);
1137884e6d60SXin LI if (emu->cur_mod != 3) {
1138884e6d60SXin LI destoffset = decode_rl_address(emu);
1139884e6d60SXin LI destval = fetch_data_byte(emu, destoffset);
1140884e6d60SXin LI } else {
1141884e6d60SXin LI destval = *decode_rl_byte_register(emu);
1142884e6d60SXin LI }
1143884e6d60SXin LI (*binop)(emu, destval, srcval);
1144884e6d60SXin LI }
1145884e6d60SXin LI
1146884e6d60SXin LI static void
common_binop_word_rm_r(struct x86emu * emu,uint16_t (* binop)(struct x86emu *,uint16_t,uint16_t))114706325fe0SXin LI common_binop_word_rm_r(struct x86emu *emu,
114806325fe0SXin LI uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
1149884e6d60SXin LI {
1150884e6d60SXin LI uint32_t destoffset;
1151884e6d60SXin LI uint16_t destval, *destreg, srcval;
1152884e6d60SXin LI
1153884e6d60SXin LI fetch_decode_modrm(emu);
1154884e6d60SXin LI srcval = *decode_rh_word_register(emu);
1155884e6d60SXin LI if (emu->cur_mod != 3) {
1156884e6d60SXin LI destoffset = decode_rl_address(emu);
1157884e6d60SXin LI destval = fetch_data_word(emu, destoffset);
1158884e6d60SXin LI destval = (*binop)(emu, destval, srcval);
1159884e6d60SXin LI store_data_word(emu, destoffset, destval);
1160884e6d60SXin LI } else {
1161884e6d60SXin LI destreg = decode_rl_word_register(emu);
1162884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1163884e6d60SXin LI }
1164884e6d60SXin LI }
1165884e6d60SXin LI
1166884e6d60SXin LI static void
common_binop_byte_r_rm(struct x86emu * emu,uint8_t (* binop)(struct x86emu *,uint8_t,uint8_t))116706325fe0SXin LI common_binop_byte_r_rm(struct x86emu *emu,
116806325fe0SXin LI uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
1169884e6d60SXin LI {
1170884e6d60SXin LI uint8_t *destreg, srcval;
1171884e6d60SXin LI uint32_t srcoffset;
1172884e6d60SXin LI
1173884e6d60SXin LI fetch_decode_modrm(emu);
1174884e6d60SXin LI destreg = decode_rh_byte_register(emu);
1175884e6d60SXin LI if (emu->cur_mod != 3) {
1176884e6d60SXin LI srcoffset = decode_rl_address(emu);
1177884e6d60SXin LI srcval = fetch_data_byte(emu, srcoffset);
1178884e6d60SXin LI } else {
1179884e6d60SXin LI srcval = *decode_rl_byte_register(emu);
1180884e6d60SXin LI }
1181884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1182884e6d60SXin LI }
1183884e6d60SXin LI
1184884e6d60SXin LI static void
common_binop_long_rm_r(struct x86emu * emu,uint32_t (* binop)(struct x86emu *,uint32_t,uint32_t))118506325fe0SXin LI common_binop_long_rm_r(struct x86emu *emu,
118606325fe0SXin LI uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
1187884e6d60SXin LI {
1188884e6d60SXin LI uint32_t destoffset;
1189884e6d60SXin LI uint32_t destval, *destreg, srcval;
1190884e6d60SXin LI
1191884e6d60SXin LI fetch_decode_modrm(emu);
1192884e6d60SXin LI srcval = *decode_rh_long_register(emu);
1193884e6d60SXin LI if (emu->cur_mod != 3) {
1194884e6d60SXin LI destoffset = decode_rl_address(emu);
1195884e6d60SXin LI destval = fetch_data_long(emu, destoffset);
1196884e6d60SXin LI destval = (*binop)(emu, destval, srcval);
1197884e6d60SXin LI store_data_long(emu, destoffset, destval);
1198884e6d60SXin LI } else {
1199884e6d60SXin LI destreg = decode_rl_long_register(emu);
1200884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1201884e6d60SXin LI }
1202884e6d60SXin LI }
1203884e6d60SXin LI
1204884e6d60SXin LI static void
common_binop_word_long_rm_r(struct x86emu * emu,uint16_t (* binop16)(struct x86emu *,uint16_t,uint16_t),uint32_t (* binop32)(struct x86emu *,uint32_t,uint32_t))1205884e6d60SXin LI common_binop_word_long_rm_r(struct x86emu *emu,
120606325fe0SXin LI uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
120706325fe0SXin LI uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
1208884e6d60SXin LI {
1209884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1210884e6d60SXin LI common_binop_long_rm_r(emu, binop32);
1211884e6d60SXin LI else
1212884e6d60SXin LI common_binop_word_rm_r(emu, binop16);
1213884e6d60SXin LI }
1214884e6d60SXin LI
1215884e6d60SXin LI static void
common_binop_ns_word_rm_r(struct x86emu * emu,void (* binop)(struct x86emu *,uint16_t,uint16_t))121606325fe0SXin LI common_binop_ns_word_rm_r(struct x86emu *emu,
121706325fe0SXin LI void (*binop)(struct x86emu *, uint16_t, uint16_t))
1218884e6d60SXin LI {
1219884e6d60SXin LI uint32_t destoffset;
1220884e6d60SXin LI uint16_t destval, srcval;
1221884e6d60SXin LI
1222884e6d60SXin LI fetch_decode_modrm(emu);
1223884e6d60SXin LI srcval = *decode_rh_word_register(emu);
1224884e6d60SXin LI if (emu->cur_mod != 3) {
1225884e6d60SXin LI destoffset = decode_rl_address(emu);
1226884e6d60SXin LI destval = fetch_data_word(emu, destoffset);
1227884e6d60SXin LI } else {
1228884e6d60SXin LI destval = *decode_rl_word_register(emu);
1229884e6d60SXin LI }
1230884e6d60SXin LI (*binop)(emu, destval, srcval);
1231884e6d60SXin LI }
1232884e6d60SXin LI
1233884e6d60SXin LI
1234884e6d60SXin LI static void
common_binop_ns_long_rm_r(struct x86emu * emu,void (* binop)(struct x86emu *,uint32_t,uint32_t))123506325fe0SXin LI common_binop_ns_long_rm_r(struct x86emu *emu,
123606325fe0SXin LI void (*binop)(struct x86emu *, uint32_t, uint32_t))
1237884e6d60SXin LI {
1238884e6d60SXin LI uint32_t destoffset;
1239884e6d60SXin LI uint32_t destval, srcval;
1240884e6d60SXin LI
1241884e6d60SXin LI fetch_decode_modrm(emu);
1242884e6d60SXin LI srcval = *decode_rh_long_register(emu);
1243884e6d60SXin LI if (emu->cur_mod != 3) {
1244884e6d60SXin LI destoffset = decode_rl_address(emu);
1245884e6d60SXin LI destval = fetch_data_long(emu, destoffset);
1246884e6d60SXin LI } else {
1247884e6d60SXin LI destval = *decode_rl_long_register(emu);
1248884e6d60SXin LI }
1249884e6d60SXin LI (*binop)(emu, destval, srcval);
1250884e6d60SXin LI }
1251884e6d60SXin LI
1252884e6d60SXin LI static void
common_binop_ns_word_long_rm_r(struct x86emu * emu,void (* binop16)(struct x86emu *,uint16_t,uint16_t),void (* binop32)(struct x86emu *,uint32_t,uint32_t))1253884e6d60SXin LI common_binop_ns_word_long_rm_r(struct x86emu *emu,
125406325fe0SXin LI void (*binop16)(struct x86emu *, uint16_t, uint16_t),
125506325fe0SXin LI void (*binop32)(struct x86emu *, uint32_t, uint32_t))
1256884e6d60SXin LI {
1257884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1258884e6d60SXin LI common_binop_ns_long_rm_r(emu, binop32);
1259884e6d60SXin LI else
1260884e6d60SXin LI common_binop_ns_word_rm_r(emu, binop16);
1261884e6d60SXin LI }
1262884e6d60SXin LI
1263884e6d60SXin LI static void
common_binop_long_r_rm(struct x86emu * emu,uint32_t (* binop)(struct x86emu *,uint32_t,uint32_t))126406325fe0SXin LI common_binop_long_r_rm(struct x86emu *emu,
126506325fe0SXin LI uint32_t (*binop)(struct x86emu *, uint32_t, uint32_t))
1266884e6d60SXin LI {
1267884e6d60SXin LI uint32_t srcoffset;
1268884e6d60SXin LI uint32_t *destreg, srcval;
1269884e6d60SXin LI
1270884e6d60SXin LI fetch_decode_modrm(emu);
1271884e6d60SXin LI destreg = decode_rh_long_register(emu);
1272884e6d60SXin LI if (emu->cur_mod != 3) {
1273884e6d60SXin LI srcoffset = decode_rl_address(emu);
1274884e6d60SXin LI srcval = fetch_data_long(emu, srcoffset);
1275884e6d60SXin LI } else {
1276884e6d60SXin LI srcval = *decode_rl_long_register(emu);
1277884e6d60SXin LI }
1278884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1279884e6d60SXin LI }
1280884e6d60SXin LI
1281884e6d60SXin LI static void
common_binop_word_r_rm(struct x86emu * emu,uint16_t (* binop)(struct x86emu *,uint16_t,uint16_t))128206325fe0SXin LI common_binop_word_r_rm(struct x86emu *emu,
128306325fe0SXin LI uint16_t (*binop)(struct x86emu *, uint16_t, uint16_t))
1284884e6d60SXin LI {
1285884e6d60SXin LI uint32_t srcoffset;
1286884e6d60SXin LI uint16_t *destreg, srcval;
1287884e6d60SXin LI
1288884e6d60SXin LI fetch_decode_modrm(emu);
1289884e6d60SXin LI destreg = decode_rh_word_register(emu);
1290884e6d60SXin LI if (emu->cur_mod != 3) {
1291884e6d60SXin LI srcoffset = decode_rl_address(emu);
1292884e6d60SXin LI srcval = fetch_data_word(emu, srcoffset);
1293884e6d60SXin LI } else {
1294884e6d60SXin LI srcval = *decode_rl_word_register(emu);
1295884e6d60SXin LI }
1296884e6d60SXin LI *destreg = (*binop)(emu, *destreg, srcval);
1297884e6d60SXin LI }
1298884e6d60SXin LI
1299884e6d60SXin LI static void
common_binop_word_long_r_rm(struct x86emu * emu,uint16_t (* binop16)(struct x86emu *,uint16_t,uint16_t),uint32_t (* binop32)(struct x86emu *,uint32_t,uint32_t))1300884e6d60SXin LI common_binop_word_long_r_rm(struct x86emu *emu,
130106325fe0SXin LI uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
130206325fe0SXin LI uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
1303884e6d60SXin LI {
1304884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1305884e6d60SXin LI common_binop_long_r_rm(emu, binop32);
1306884e6d60SXin LI else
1307884e6d60SXin LI common_binop_word_r_rm(emu, binop16);
1308884e6d60SXin LI }
1309884e6d60SXin LI
1310884e6d60SXin LI static void
common_binop_byte_imm(struct x86emu * emu,uint8_t (* binop)(struct x86emu *,uint8_t,uint8_t))131106325fe0SXin LI common_binop_byte_imm(struct x86emu *emu,
131206325fe0SXin LI uint8_t (*binop)(struct x86emu *, uint8_t, uint8_t))
1313884e6d60SXin LI {
1314884e6d60SXin LI uint8_t srcval;
1315884e6d60SXin LI
1316884e6d60SXin LI srcval = fetch_byte_imm(emu);
1317884e6d60SXin LI emu->x86.R_AL = (*binop)(emu, emu->x86.R_AL, srcval);
1318884e6d60SXin LI }
1319884e6d60SXin LI
1320884e6d60SXin LI static void
common_binop_word_long_imm(struct x86emu * emu,uint16_t (* binop16)(struct x86emu *,uint16_t,uint16_t),uint32_t (* binop32)(struct x86emu *,uint32_t,uint32_t))1321884e6d60SXin LI common_binop_word_long_imm(struct x86emu *emu,
132206325fe0SXin LI uint16_t (*binop16)(struct x86emu *, uint16_t, uint16_t),
132306325fe0SXin LI uint32_t (*binop32)(struct x86emu *, uint32_t, uint32_t))
1324884e6d60SXin LI {
1325884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1326884e6d60SXin LI uint32_t srcval;
1327884e6d60SXin LI
1328884e6d60SXin LI srcval = fetch_long_imm(emu);
1329884e6d60SXin LI emu->x86.R_EAX = (*binop32)(emu, emu->x86.R_EAX, srcval);
1330884e6d60SXin LI } else {
1331884e6d60SXin LI uint16_t srcval;
1332884e6d60SXin LI
1333884e6d60SXin LI srcval = fetch_word_imm(emu);
1334884e6d60SXin LI emu->x86.R_AX = (*binop16)(emu, emu->x86.R_AX, srcval);
1335884e6d60SXin LI }
1336884e6d60SXin LI }
1337884e6d60SXin LI
1338884e6d60SXin LI static void
common_push_word_long(struct x86emu * emu,union x86emu_register * reg)1339884e6d60SXin LI common_push_word_long(struct x86emu *emu, union x86emu_register *reg)
1340884e6d60SXin LI {
1341884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1342884e6d60SXin LI push_long(emu, reg->I32_reg.e_reg);
1343884e6d60SXin LI else
1344884e6d60SXin LI push_word(emu, reg->I16_reg.x_reg);
1345884e6d60SXin LI }
1346884e6d60SXin LI
1347884e6d60SXin LI static void
common_pop_word_long(struct x86emu * emu,union x86emu_register * reg)1348884e6d60SXin LI common_pop_word_long(struct x86emu *emu, union x86emu_register *reg)
1349884e6d60SXin LI {
1350884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1351884e6d60SXin LI reg->I32_reg.e_reg = pop_long(emu);
1352884e6d60SXin LI else
1353884e6d60SXin LI reg->I16_reg.x_reg = pop_word(emu);
1354884e6d60SXin LI }
1355884e6d60SXin LI
1356884e6d60SXin LI static void
common_imul_long_IMM(struct x86emu * emu,int byte_imm)1357884e6d60SXin LI common_imul_long_IMM(struct x86emu *emu, int byte_imm)
1358884e6d60SXin LI {
1359884e6d60SXin LI uint32_t srcoffset;
1360884e6d60SXin LI uint32_t *destreg, srcval;
1361884e6d60SXin LI int32_t imm;
1362884e6d60SXin LI uint64_t res;
1363884e6d60SXin LI
1364884e6d60SXin LI fetch_decode_modrm(emu);
1365884e6d60SXin LI destreg = decode_rh_long_register(emu);
1366884e6d60SXin LI if (emu->cur_mod != 3) {
1367884e6d60SXin LI srcoffset = decode_rl_address(emu);
1368884e6d60SXin LI srcval = fetch_data_long(emu, srcoffset);
1369884e6d60SXin LI } else {
1370884e6d60SXin LI srcval = *decode_rl_long_register(emu);
1371884e6d60SXin LI }
1372884e6d60SXin LI
1373884e6d60SXin LI if (byte_imm)
1374884e6d60SXin LI imm = (int8_t)fetch_byte_imm(emu);
1375884e6d60SXin LI else
1376884e6d60SXin LI imm = fetch_long_imm(emu);
1377884e6d60SXin LI res = (int32_t)srcval * imm;
1378884e6d60SXin LI
1379884e6d60SXin LI if (res > 0xffffffff) {
1380884e6d60SXin LI SET_FLAG(F_CF);
1381884e6d60SXin LI SET_FLAG(F_OF);
1382884e6d60SXin LI } else {
1383884e6d60SXin LI CLEAR_FLAG(F_CF);
1384884e6d60SXin LI CLEAR_FLAG(F_OF);
1385884e6d60SXin LI }
1386884e6d60SXin LI *destreg = (uint32_t)res;
1387884e6d60SXin LI }
1388884e6d60SXin LI
1389884e6d60SXin LI static void
common_imul_word_IMM(struct x86emu * emu,int byte_imm)1390884e6d60SXin LI common_imul_word_IMM(struct x86emu *emu, int byte_imm)
1391884e6d60SXin LI {
1392884e6d60SXin LI uint32_t srcoffset;
1393884e6d60SXin LI uint16_t *destreg, srcval;
1394884e6d60SXin LI int16_t imm;
1395884e6d60SXin LI uint32_t res;
1396884e6d60SXin LI
1397884e6d60SXin LI fetch_decode_modrm(emu);
1398884e6d60SXin LI destreg = decode_rh_word_register(emu);
1399884e6d60SXin LI if (emu->cur_mod != 3) {
1400884e6d60SXin LI srcoffset = decode_rl_address(emu);
1401884e6d60SXin LI srcval = fetch_data_word(emu, srcoffset);
1402884e6d60SXin LI } else {
1403884e6d60SXin LI srcval = *decode_rl_word_register(emu);
1404884e6d60SXin LI }
1405884e6d60SXin LI
1406884e6d60SXin LI if (byte_imm)
1407884e6d60SXin LI imm = (int8_t)fetch_byte_imm(emu);
1408884e6d60SXin LI else
1409884e6d60SXin LI imm = fetch_word_imm(emu);
1410884e6d60SXin LI res = (int16_t)srcval * imm;
1411884e6d60SXin LI
1412884e6d60SXin LI if (res > 0xffff) {
1413884e6d60SXin LI SET_FLAG(F_CF);
1414884e6d60SXin LI SET_FLAG(F_OF);
1415884e6d60SXin LI } else {
1416884e6d60SXin LI CLEAR_FLAG(F_CF);
1417884e6d60SXin LI CLEAR_FLAG(F_OF);
1418884e6d60SXin LI }
1419884e6d60SXin LI *destreg = (uint16_t) res;
1420884e6d60SXin LI }
1421884e6d60SXin LI
1422884e6d60SXin LI static void
common_imul_imm(struct x86emu * emu,int byte_imm)1423884e6d60SXin LI common_imul_imm(struct x86emu *emu, int byte_imm)
1424884e6d60SXin LI {
1425884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1426884e6d60SXin LI common_imul_long_IMM(emu, byte_imm);
1427884e6d60SXin LI else
1428884e6d60SXin LI common_imul_word_IMM(emu, byte_imm);
1429884e6d60SXin LI }
1430884e6d60SXin LI
1431884e6d60SXin LI static void
common_jmp_near(struct x86emu * emu,int cond)1432884e6d60SXin LI common_jmp_near(struct x86emu *emu, int cond)
1433884e6d60SXin LI {
1434884e6d60SXin LI int8_t offset;
1435884e6d60SXin LI uint16_t target;
1436884e6d60SXin LI
1437884e6d60SXin LI offset = (int8_t) fetch_byte_imm(emu);
1438884e6d60SXin LI target = (uint16_t) (emu->x86.R_IP + (int16_t) offset);
1439884e6d60SXin LI if (cond)
1440884e6d60SXin LI emu->x86.R_IP = target;
1441884e6d60SXin LI }
1442884e6d60SXin LI
1443884e6d60SXin LI static void
common_load_far_pointer(struct x86emu * emu,uint16_t * seg)1444884e6d60SXin LI common_load_far_pointer(struct x86emu *emu, uint16_t *seg)
1445884e6d60SXin LI {
1446884e6d60SXin LI uint16_t *dstreg;
1447884e6d60SXin LI uint32_t srcoffset;
1448884e6d60SXin LI
1449884e6d60SXin LI fetch_decode_modrm(emu);
1450884e6d60SXin LI if (emu->cur_mod == 3)
1451884e6d60SXin LI x86emu_halt_sys(emu);
1452884e6d60SXin LI
1453884e6d60SXin LI dstreg = decode_rh_word_register(emu);
1454884e6d60SXin LI srcoffset = decode_rl_address(emu);
1455884e6d60SXin LI *dstreg = fetch_data_word(emu, srcoffset);
1456884e6d60SXin LI *seg = fetch_data_word(emu, srcoffset + 2);
1457884e6d60SXin LI }
1458884e6d60SXin LI
1459884e6d60SXin LI /* Implementation */
1460884e6d60SXin LI
1461884e6d60SXin LI /*
1462884e6d60SXin LI * REMARKS:
1463884e6d60SXin LI * Handles opcode 0x3a
1464884e6d60SXin LI */
1465884e6d60SXin LI static void
x86emuOp_cmp_byte_R_RM(struct x86emu * emu)1466884e6d60SXin LI x86emuOp_cmp_byte_R_RM(struct x86emu *emu)
1467884e6d60SXin LI {
1468884e6d60SXin LI uint8_t *destreg, srcval;
1469884e6d60SXin LI
1470884e6d60SXin LI fetch_decode_modrm(emu);
1471884e6d60SXin LI destreg = decode_rh_byte_register(emu);
1472884e6d60SXin LI srcval = decode_and_fetch_byte(emu);
1473884e6d60SXin LI cmp_byte(emu, *destreg, srcval);
1474884e6d60SXin LI }
1475884e6d60SXin LI
1476884e6d60SXin LI /*
1477884e6d60SXin LI * REMARKS:
1478884e6d60SXin LI *
1479884e6d60SXin LI * Handles opcode 0x3b
1480884e6d60SXin LI */
1481884e6d60SXin LI static void
x86emuOp32_cmp_word_R_RM(struct x86emu * emu)1482884e6d60SXin LI x86emuOp32_cmp_word_R_RM(struct x86emu *emu)
1483884e6d60SXin LI {
1484884e6d60SXin LI uint32_t srcval, *destreg;
1485884e6d60SXin LI
1486884e6d60SXin LI fetch_decode_modrm(emu);
1487884e6d60SXin LI destreg = decode_rh_long_register(emu);
1488884e6d60SXin LI srcval = decode_and_fetch_long(emu);
1489884e6d60SXin LI cmp_long(emu, *destreg, srcval);
1490884e6d60SXin LI }
1491884e6d60SXin LI
1492884e6d60SXin LI static void
x86emuOp16_cmp_word_R_RM(struct x86emu * emu)1493884e6d60SXin LI x86emuOp16_cmp_word_R_RM(struct x86emu *emu)
1494884e6d60SXin LI {
1495884e6d60SXin LI uint16_t srcval, *destreg;
1496884e6d60SXin LI
1497884e6d60SXin LI fetch_decode_modrm(emu);
1498884e6d60SXin LI destreg = decode_rh_word_register(emu);
1499884e6d60SXin LI srcval = decode_and_fetch_word(emu);
1500884e6d60SXin LI cmp_word(emu, *destreg, srcval);
1501884e6d60SXin LI }
1502884e6d60SXin LI
1503884e6d60SXin LI static void
x86emuOp_cmp_word_R_RM(struct x86emu * emu)1504884e6d60SXin LI x86emuOp_cmp_word_R_RM(struct x86emu *emu)
1505884e6d60SXin LI {
1506884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1507884e6d60SXin LI x86emuOp32_cmp_word_R_RM(emu);
1508884e6d60SXin LI else
1509884e6d60SXin LI x86emuOp16_cmp_word_R_RM(emu);
1510884e6d60SXin LI }
1511884e6d60SXin LI
1512884e6d60SXin LI /*
1513884e6d60SXin LI * REMARKS:
1514884e6d60SXin LI * Handles opcode 0x3c
1515884e6d60SXin LI */
1516884e6d60SXin LI static void
x86emuOp_cmp_byte_AL_IMM(struct x86emu * emu)1517884e6d60SXin LI x86emuOp_cmp_byte_AL_IMM(struct x86emu *emu)
1518884e6d60SXin LI {
1519884e6d60SXin LI uint8_t srcval;
1520884e6d60SXin LI
1521884e6d60SXin LI srcval = fetch_byte_imm(emu);
1522884e6d60SXin LI cmp_byte(emu, emu->x86.R_AL, srcval);
1523884e6d60SXin LI }
1524884e6d60SXin LI
1525884e6d60SXin LI /*
1526884e6d60SXin LI * REMARKS:
1527884e6d60SXin LI * Handles opcode 0x3d
1528884e6d60SXin LI */
1529884e6d60SXin LI static void
x86emuOp32_cmp_word_AX_IMM(struct x86emu * emu)1530884e6d60SXin LI x86emuOp32_cmp_word_AX_IMM(struct x86emu *emu)
1531884e6d60SXin LI {
1532884e6d60SXin LI uint32_t srcval;
1533884e6d60SXin LI
1534884e6d60SXin LI srcval = fetch_long_imm(emu);
1535884e6d60SXin LI cmp_long(emu, emu->x86.R_EAX, srcval);
1536884e6d60SXin LI }
1537884e6d60SXin LI
1538884e6d60SXin LI static void
x86emuOp16_cmp_word_AX_IMM(struct x86emu * emu)1539884e6d60SXin LI x86emuOp16_cmp_word_AX_IMM(struct x86emu *emu)
1540884e6d60SXin LI {
1541884e6d60SXin LI uint16_t srcval;
1542884e6d60SXin LI
1543884e6d60SXin LI srcval = fetch_word_imm(emu);
1544884e6d60SXin LI cmp_word(emu, emu->x86.R_AX, srcval);
1545884e6d60SXin LI }
1546884e6d60SXin LI
1547884e6d60SXin LI static void
x86emuOp_cmp_word_AX_IMM(struct x86emu * emu)1548884e6d60SXin LI x86emuOp_cmp_word_AX_IMM(struct x86emu *emu)
1549884e6d60SXin LI {
1550884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1551884e6d60SXin LI x86emuOp32_cmp_word_AX_IMM(emu);
1552884e6d60SXin LI else
1553884e6d60SXin LI x86emuOp16_cmp_word_AX_IMM(emu);
1554884e6d60SXin LI }
1555884e6d60SXin LI
1556884e6d60SXin LI /*
1557884e6d60SXin LI * REMARKS:
1558884e6d60SXin LI * Handles opcode 0x60
1559884e6d60SXin LI */
1560884e6d60SXin LI static void
x86emuOp_push_all(struct x86emu * emu)1561884e6d60SXin LI x86emuOp_push_all(struct x86emu *emu)
1562884e6d60SXin LI {
1563884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1564884e6d60SXin LI uint32_t old_sp = emu->x86.R_ESP;
1565884e6d60SXin LI
1566884e6d60SXin LI push_long(emu, emu->x86.R_EAX);
1567884e6d60SXin LI push_long(emu, emu->x86.R_ECX);
1568884e6d60SXin LI push_long(emu, emu->x86.R_EDX);
1569884e6d60SXin LI push_long(emu, emu->x86.R_EBX);
1570884e6d60SXin LI push_long(emu, old_sp);
1571884e6d60SXin LI push_long(emu, emu->x86.R_EBP);
1572884e6d60SXin LI push_long(emu, emu->x86.R_ESI);
1573884e6d60SXin LI push_long(emu, emu->x86.R_EDI);
1574884e6d60SXin LI } else {
1575884e6d60SXin LI uint16_t old_sp = emu->x86.R_SP;
1576884e6d60SXin LI
1577884e6d60SXin LI push_word(emu, emu->x86.R_AX);
1578884e6d60SXin LI push_word(emu, emu->x86.R_CX);
1579884e6d60SXin LI push_word(emu, emu->x86.R_DX);
1580884e6d60SXin LI push_word(emu, emu->x86.R_BX);
1581884e6d60SXin LI push_word(emu, old_sp);
1582884e6d60SXin LI push_word(emu, emu->x86.R_BP);
1583884e6d60SXin LI push_word(emu, emu->x86.R_SI);
1584884e6d60SXin LI push_word(emu, emu->x86.R_DI);
1585884e6d60SXin LI }
1586884e6d60SXin LI }
1587884e6d60SXin LI
1588884e6d60SXin LI /*
1589884e6d60SXin LI * REMARKS:
1590884e6d60SXin LI * Handles opcode 0x61
1591884e6d60SXin LI */
1592884e6d60SXin LI static void
x86emuOp_pop_all(struct x86emu * emu)1593884e6d60SXin LI x86emuOp_pop_all(struct x86emu *emu)
1594884e6d60SXin LI {
1595884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1596884e6d60SXin LI emu->x86.R_EDI = pop_long(emu);
1597884e6d60SXin LI emu->x86.R_ESI = pop_long(emu);
1598884e6d60SXin LI emu->x86.R_EBP = pop_long(emu);
1599884e6d60SXin LI emu->x86.R_ESP += 4; /* skip ESP */
1600884e6d60SXin LI emu->x86.R_EBX = pop_long(emu);
1601884e6d60SXin LI emu->x86.R_EDX = pop_long(emu);
1602884e6d60SXin LI emu->x86.R_ECX = pop_long(emu);
1603884e6d60SXin LI emu->x86.R_EAX = pop_long(emu);
1604884e6d60SXin LI } else {
1605884e6d60SXin LI emu->x86.R_DI = pop_word(emu);
1606884e6d60SXin LI emu->x86.R_SI = pop_word(emu);
1607884e6d60SXin LI emu->x86.R_BP = pop_word(emu);
1608884e6d60SXin LI emu->x86.R_SP += 2;/* skip SP */
1609884e6d60SXin LI emu->x86.R_BX = pop_word(emu);
1610884e6d60SXin LI emu->x86.R_DX = pop_word(emu);
1611884e6d60SXin LI emu->x86.R_CX = pop_word(emu);
1612884e6d60SXin LI emu->x86.R_AX = pop_word(emu);
1613884e6d60SXin LI }
1614884e6d60SXin LI }
1615884e6d60SXin LI /*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */
1616884e6d60SXin LI /*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */
1617884e6d60SXin LI
1618884e6d60SXin LI
1619884e6d60SXin LI /*
1620884e6d60SXin LI * REMARKS:
1621884e6d60SXin LI * Handles opcode 0x68
1622884e6d60SXin LI */
1623884e6d60SXin LI static void
x86emuOp_push_word_IMM(struct x86emu * emu)1624884e6d60SXin LI x86emuOp_push_word_IMM(struct x86emu *emu)
1625884e6d60SXin LI {
1626884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1627884e6d60SXin LI uint32_t imm;
1628884e6d60SXin LI
1629884e6d60SXin LI imm = fetch_long_imm(emu);
1630884e6d60SXin LI push_long(emu, imm);
1631884e6d60SXin LI } else {
1632884e6d60SXin LI uint16_t imm;
1633884e6d60SXin LI
1634884e6d60SXin LI imm = fetch_word_imm(emu);
1635884e6d60SXin LI push_word(emu, imm);
1636884e6d60SXin LI }
1637884e6d60SXin LI }
1638884e6d60SXin LI
1639884e6d60SXin LI /*
1640884e6d60SXin LI * REMARKS:
1641884e6d60SXin LI * Handles opcode 0x6a
1642884e6d60SXin LI */
1643884e6d60SXin LI static void
x86emuOp_push_byte_IMM(struct x86emu * emu)1644884e6d60SXin LI x86emuOp_push_byte_IMM(struct x86emu *emu)
1645884e6d60SXin LI {
1646884e6d60SXin LI int16_t imm;
1647884e6d60SXin LI
1648884e6d60SXin LI imm = (int8_t) fetch_byte_imm(emu);
1649884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1650884e6d60SXin LI push_long(emu, (int32_t) imm);
1651884e6d60SXin LI } else {
1652884e6d60SXin LI push_word(emu, imm);
1653884e6d60SXin LI }
1654884e6d60SXin LI }
1655884e6d60SXin LI
1656884e6d60SXin LI /*
1657884e6d60SXin LI * REMARKS:
1658884e6d60SXin LI * Handles opcode 0x6c and 0x6d
1659884e6d60SXin LI */
1660884e6d60SXin LI static void
x86emuOp_ins_word(struct x86emu * emu)1661884e6d60SXin LI x86emuOp_ins_word(struct x86emu *emu)
1662884e6d60SXin LI {
1663884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1664884e6d60SXin LI ins(emu, 4);
1665884e6d60SXin LI } else {
1666884e6d60SXin LI ins(emu, 2);
1667884e6d60SXin LI }
1668884e6d60SXin LI }
1669884e6d60SXin LI
1670884e6d60SXin LI /*
1671884e6d60SXin LI * REMARKS:
1672884e6d60SXin LI * Handles opcode 0x6f
1673884e6d60SXin LI */
1674884e6d60SXin LI static void
x86emuOp_outs_word(struct x86emu * emu)1675884e6d60SXin LI x86emuOp_outs_word(struct x86emu *emu)
1676884e6d60SXin LI {
1677884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
1678884e6d60SXin LI outs(emu, 4);
1679884e6d60SXin LI } else {
1680884e6d60SXin LI outs(emu, 2);
1681884e6d60SXin LI }
1682884e6d60SXin LI }
1683884e6d60SXin LI
1684884e6d60SXin LI /*
1685884e6d60SXin LI * REMARKS:
1686884e6d60SXin LI * Handles opcode 0x7c
1687884e6d60SXin LI */
1688884e6d60SXin LI static void
x86emuOp_jump_near_L(struct x86emu * emu)1689884e6d60SXin LI x86emuOp_jump_near_L(struct x86emu *emu)
1690884e6d60SXin LI {
1691884e6d60SXin LI int sf, of;
1692884e6d60SXin LI
1693884e6d60SXin LI sf = ACCESS_FLAG(F_SF) != 0;
1694884e6d60SXin LI of = ACCESS_FLAG(F_OF) != 0;
1695884e6d60SXin LI
1696884e6d60SXin LI common_jmp_near(emu, sf != of);
1697884e6d60SXin LI }
1698884e6d60SXin LI
1699884e6d60SXin LI /*
1700884e6d60SXin LI * REMARKS:
1701884e6d60SXin LI * Handles opcode 0x7d
1702884e6d60SXin LI */
1703884e6d60SXin LI static void
x86emuOp_jump_near_NL(struct x86emu * emu)1704884e6d60SXin LI x86emuOp_jump_near_NL(struct x86emu *emu)
1705884e6d60SXin LI {
1706884e6d60SXin LI int sf, of;
1707884e6d60SXin LI
1708884e6d60SXin LI sf = ACCESS_FLAG(F_SF) != 0;
1709884e6d60SXin LI of = ACCESS_FLAG(F_OF) != 0;
1710884e6d60SXin LI
1711884e6d60SXin LI common_jmp_near(emu, sf == of);
1712884e6d60SXin LI }
1713884e6d60SXin LI
1714884e6d60SXin LI /*
1715884e6d60SXin LI * REMARKS:
1716884e6d60SXin LI * Handles opcode 0x7e
1717884e6d60SXin LI */
1718884e6d60SXin LI static void
x86emuOp_jump_near_LE(struct x86emu * emu)1719884e6d60SXin LI x86emuOp_jump_near_LE(struct x86emu *emu)
1720884e6d60SXin LI {
1721884e6d60SXin LI int sf, of;
1722884e6d60SXin LI
1723884e6d60SXin LI sf = ACCESS_FLAG(F_SF) != 0;
1724884e6d60SXin LI of = ACCESS_FLAG(F_OF) != 0;
1725884e6d60SXin LI
1726884e6d60SXin LI common_jmp_near(emu, sf != of || ACCESS_FLAG(F_ZF));
1727884e6d60SXin LI }
1728884e6d60SXin LI
1729884e6d60SXin LI /*
1730884e6d60SXin LI * REMARKS:
1731884e6d60SXin LI * Handles opcode 0x7f
1732884e6d60SXin LI */
1733884e6d60SXin LI static void
x86emuOp_jump_near_NLE(struct x86emu * emu)1734884e6d60SXin LI x86emuOp_jump_near_NLE(struct x86emu *emu)
1735884e6d60SXin LI {
1736884e6d60SXin LI int sf, of;
1737884e6d60SXin LI
1738884e6d60SXin LI sf = ACCESS_FLAG(F_SF) != 0;
1739884e6d60SXin LI of = ACCESS_FLAG(F_OF) != 0;
1740884e6d60SXin LI
1741884e6d60SXin LI common_jmp_near(emu, sf == of && !ACCESS_FLAG(F_ZF));
1742884e6d60SXin LI }
1743884e6d60SXin LI
1744884e6d60SXin LI static
1745884e6d60SXin LI uint8_t(*const opc80_byte_operation[]) (struct x86emu *, uint8_t d, uint8_t s) =
1746884e6d60SXin LI {
1747884e6d60SXin LI add_byte, /* 00 */
1748884e6d60SXin LI or_byte, /* 01 */
1749884e6d60SXin LI adc_byte, /* 02 */
1750884e6d60SXin LI sbb_byte, /* 03 */
1751884e6d60SXin LI and_byte, /* 04 */
1752884e6d60SXin LI sub_byte, /* 05 */
1753884e6d60SXin LI xor_byte, /* 06 */
1754884e6d60SXin LI cmp_byte, /* 07 */
1755884e6d60SXin LI };
1756884e6d60SXin LI
1757884e6d60SXin LI /*
1758884e6d60SXin LI * REMARKS:
1759884e6d60SXin LI * Handles opcode 0x80
1760884e6d60SXin LI */
1761884e6d60SXin LI static void
x86emuOp_opc80_byte_RM_IMM(struct x86emu * emu)1762884e6d60SXin LI x86emuOp_opc80_byte_RM_IMM(struct x86emu *emu)
1763884e6d60SXin LI {
1764884e6d60SXin LI uint8_t imm, destval;
1765884e6d60SXin LI
1766884e6d60SXin LI /*
1767884e6d60SXin LI * Weirdo special case instruction format. Part of the opcode
1768884e6d60SXin LI * held below in "RH". Doubly nested case would result, except
1769884e6d60SXin LI * that the decoded instruction
1770884e6d60SXin LI */
1771884e6d60SXin LI fetch_decode_modrm(emu);
1772884e6d60SXin LI destval = decode_and_fetch_byte(emu);
1773884e6d60SXin LI imm = fetch_byte_imm(emu);
1774884e6d60SXin LI destval = (*opc80_byte_operation[emu->cur_rh]) (emu, destval, imm);
1775884e6d60SXin LI if (emu->cur_rh != 7)
1776884e6d60SXin LI write_back_byte(emu, destval);
1777884e6d60SXin LI }
1778884e6d60SXin LI
1779884e6d60SXin LI static
178006325fe0SXin LI uint16_t(* const opc81_word_operation[])
178106325fe0SXin LI (struct x86emu *, uint16_t d, uint16_t s) =
1782884e6d60SXin LI {
1783884e6d60SXin LI add_word, /* 00 */
1784884e6d60SXin LI or_word, /* 01 */
1785884e6d60SXin LI adc_word, /* 02 */
1786884e6d60SXin LI sbb_word, /* 03 */
1787884e6d60SXin LI and_word, /* 04 */
1788884e6d60SXin LI sub_word, /* 05 */
1789884e6d60SXin LI xor_word, /* 06 */
1790884e6d60SXin LI cmp_word, /* 07 */
1791884e6d60SXin LI };
1792884e6d60SXin LI
1793884e6d60SXin LI static
179406325fe0SXin LI uint32_t(* const opc81_long_operation[])
179506325fe0SXin LI (struct x86emu *, uint32_t d, uint32_t s) =
1796884e6d60SXin LI {
1797884e6d60SXin LI add_long, /* 00 */
1798884e6d60SXin LI or_long, /* 01 */
1799884e6d60SXin LI adc_long, /* 02 */
1800884e6d60SXin LI sbb_long, /* 03 */
1801884e6d60SXin LI and_long, /* 04 */
1802884e6d60SXin LI sub_long, /* 05 */
1803884e6d60SXin LI xor_long, /* 06 */
1804884e6d60SXin LI cmp_long, /* 07 */
1805884e6d60SXin LI };
1806884e6d60SXin LI
1807884e6d60SXin LI /*
1808884e6d60SXin LI * REMARKS:
1809884e6d60SXin LI * Handles opcode 0x81
1810884e6d60SXin LI */
1811884e6d60SXin LI static void
x86emuOp32_opc81_word_RM_IMM(struct x86emu * emu)1812884e6d60SXin LI x86emuOp32_opc81_word_RM_IMM(struct x86emu *emu)
1813884e6d60SXin LI {
1814884e6d60SXin LI uint32_t destval, imm;
1815884e6d60SXin LI
1816884e6d60SXin LI /*
1817884e6d60SXin LI * Weirdo special case instruction format. Part of the opcode
1818884e6d60SXin LI * held below in "RH". Doubly nested case would result, except
1819884e6d60SXin LI * that the decoded instruction
1820884e6d60SXin LI */
1821884e6d60SXin LI fetch_decode_modrm(emu);
1822884e6d60SXin LI destval = decode_and_fetch_long(emu);
1823884e6d60SXin LI imm = fetch_long_imm(emu);
1824884e6d60SXin LI destval = (*opc81_long_operation[emu->cur_rh]) (emu, destval, imm);
1825884e6d60SXin LI if (emu->cur_rh != 7)
1826884e6d60SXin LI write_back_long(emu, destval);
1827884e6d60SXin LI }
1828884e6d60SXin LI
1829884e6d60SXin LI static void
x86emuOp16_opc81_word_RM_IMM(struct x86emu * emu)1830884e6d60SXin LI x86emuOp16_opc81_word_RM_IMM(struct x86emu *emu)
1831884e6d60SXin LI {
1832884e6d60SXin LI uint16_t destval, imm;
1833884e6d60SXin LI
1834884e6d60SXin LI /*
1835884e6d60SXin LI * Weirdo special case instruction format. Part of the opcode
1836884e6d60SXin LI * held below in "RH". Doubly nested case would result, except
1837884e6d60SXin LI * that the decoded instruction
1838884e6d60SXin LI */
1839884e6d60SXin LI fetch_decode_modrm(emu);
1840884e6d60SXin LI destval = decode_and_fetch_word(emu);
1841884e6d60SXin LI imm = fetch_word_imm(emu);
1842884e6d60SXin LI destval = (*opc81_word_operation[emu->cur_rh]) (emu, destval, imm);
1843884e6d60SXin LI if (emu->cur_rh != 7)
1844884e6d60SXin LI write_back_word(emu, destval);
1845884e6d60SXin LI }
1846884e6d60SXin LI
1847884e6d60SXin LI static void
x86emuOp_opc81_word_RM_IMM(struct x86emu * emu)1848884e6d60SXin LI x86emuOp_opc81_word_RM_IMM(struct x86emu *emu)
1849884e6d60SXin LI {
1850884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1851884e6d60SXin LI x86emuOp32_opc81_word_RM_IMM(emu);
1852884e6d60SXin LI else
1853884e6d60SXin LI x86emuOp16_opc81_word_RM_IMM(emu);
1854884e6d60SXin LI }
1855884e6d60SXin LI
1856884e6d60SXin LI static
185706325fe0SXin LI uint8_t(* const opc82_byte_operation[])
185806325fe0SXin LI (struct x86emu *, uint8_t s, uint8_t d) =
1859884e6d60SXin LI {
1860884e6d60SXin LI add_byte, /* 00 */
1861884e6d60SXin LI or_byte, /* 01 *//* YYY UNUSED ???? */
1862884e6d60SXin LI adc_byte, /* 02 */
1863884e6d60SXin LI sbb_byte, /* 03 */
1864884e6d60SXin LI and_byte, /* 04 *//* YYY UNUSED ???? */
1865884e6d60SXin LI sub_byte, /* 05 */
1866884e6d60SXin LI xor_byte, /* 06 *//* YYY UNUSED ???? */
1867884e6d60SXin LI cmp_byte, /* 07 */
1868884e6d60SXin LI };
1869884e6d60SXin LI
1870884e6d60SXin LI /*
1871884e6d60SXin LI * REMARKS:
1872884e6d60SXin LI * Handles opcode 0x82
1873884e6d60SXin LI */
1874884e6d60SXin LI static void
x86emuOp_opc82_byte_RM_IMM(struct x86emu * emu)1875884e6d60SXin LI x86emuOp_opc82_byte_RM_IMM(struct x86emu *emu)
1876884e6d60SXin LI {
1877884e6d60SXin LI uint8_t imm, destval;
1878884e6d60SXin LI
1879884e6d60SXin LI /*
1880884e6d60SXin LI * Weirdo special case instruction format. Part of the opcode
1881884e6d60SXin LI * held below in "RH". Doubly nested case would result, except
1882884e6d60SXin LI * that the decoded instruction Similar to opcode 81, except that
1883884e6d60SXin LI * the immediate byte is sign extended to a word length.
1884884e6d60SXin LI */
1885884e6d60SXin LI fetch_decode_modrm(emu);
1886884e6d60SXin LI destval = decode_and_fetch_byte(emu);
1887884e6d60SXin LI imm = fetch_byte_imm(emu);
1888884e6d60SXin LI destval = (*opc82_byte_operation[emu->cur_rh]) (emu, destval, imm);
1889884e6d60SXin LI if (emu->cur_rh != 7)
1890884e6d60SXin LI write_back_byte(emu, destval);
1891884e6d60SXin LI }
1892884e6d60SXin LI
1893884e6d60SXin LI static
189406325fe0SXin LI uint16_t(* const opc83_word_operation[])
189506325fe0SXin LI (struct x86emu *, uint16_t s, uint16_t d) =
1896884e6d60SXin LI {
1897884e6d60SXin LI add_word, /* 00 */
1898884e6d60SXin LI or_word, /* 01 *//* YYY UNUSED ???? */
1899884e6d60SXin LI adc_word, /* 02 */
1900884e6d60SXin LI sbb_word, /* 03 */
1901884e6d60SXin LI and_word, /* 04 *//* YYY UNUSED ???? */
1902884e6d60SXin LI sub_word, /* 05 */
1903884e6d60SXin LI xor_word, /* 06 *//* YYY UNUSED ???? */
1904884e6d60SXin LI cmp_word, /* 07 */
1905884e6d60SXin LI };
1906884e6d60SXin LI
1907884e6d60SXin LI static
190806325fe0SXin LI uint32_t(* const opc83_long_operation[])
190906325fe0SXin LI (struct x86emu *, uint32_t s, uint32_t d) =
1910884e6d60SXin LI {
1911884e6d60SXin LI add_long, /* 00 */
1912884e6d60SXin LI or_long, /* 01 *//* YYY UNUSED ???? */
1913884e6d60SXin LI adc_long, /* 02 */
1914884e6d60SXin LI sbb_long, /* 03 */
1915884e6d60SXin LI and_long, /* 04 *//* YYY UNUSED ???? */
1916884e6d60SXin LI sub_long, /* 05 */
1917884e6d60SXin LI xor_long, /* 06 *//* YYY UNUSED ???? */
1918884e6d60SXin LI cmp_long, /* 07 */
1919884e6d60SXin LI };
1920884e6d60SXin LI
1921884e6d60SXin LI /*
1922884e6d60SXin LI * REMARKS:
1923884e6d60SXin LI * Handles opcode 0x83
1924884e6d60SXin LI */
1925884e6d60SXin LI static void
x86emuOp32_opc83_word_RM_IMM(struct x86emu * emu)1926884e6d60SXin LI x86emuOp32_opc83_word_RM_IMM(struct x86emu *emu)
1927884e6d60SXin LI {
1928884e6d60SXin LI uint32_t destval, imm;
1929884e6d60SXin LI
1930884e6d60SXin LI fetch_decode_modrm(emu);
1931884e6d60SXin LI destval = decode_and_fetch_long(emu);
1932884e6d60SXin LI imm = (int8_t) fetch_byte_imm(emu);
1933884e6d60SXin LI destval = (*opc83_long_operation[emu->cur_rh]) (emu, destval, imm);
1934884e6d60SXin LI if (emu->cur_rh != 7)
1935884e6d60SXin LI write_back_long(emu, destval);
1936884e6d60SXin LI }
1937884e6d60SXin LI
1938884e6d60SXin LI static void
x86emuOp16_opc83_word_RM_IMM(struct x86emu * emu)1939884e6d60SXin LI x86emuOp16_opc83_word_RM_IMM(struct x86emu *emu)
1940884e6d60SXin LI {
1941884e6d60SXin LI uint16_t destval, imm;
1942884e6d60SXin LI
1943884e6d60SXin LI fetch_decode_modrm(emu);
1944884e6d60SXin LI destval = decode_and_fetch_word(emu);
1945884e6d60SXin LI imm = (int8_t) fetch_byte_imm(emu);
1946884e6d60SXin LI destval = (*opc83_word_operation[emu->cur_rh]) (emu, destval, imm);
1947884e6d60SXin LI if (emu->cur_rh != 7)
1948884e6d60SXin LI write_back_word(emu, destval);
1949884e6d60SXin LI }
1950884e6d60SXin LI
1951884e6d60SXin LI static void
x86emuOp_opc83_word_RM_IMM(struct x86emu * emu)1952884e6d60SXin LI x86emuOp_opc83_word_RM_IMM(struct x86emu *emu)
1953884e6d60SXin LI {
1954884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
1955884e6d60SXin LI x86emuOp32_opc83_word_RM_IMM(emu);
1956884e6d60SXin LI else
1957884e6d60SXin LI x86emuOp16_opc83_word_RM_IMM(emu);
1958884e6d60SXin LI }
1959884e6d60SXin LI
1960884e6d60SXin LI /*
1961884e6d60SXin LI * REMARKS:
1962884e6d60SXin LI * Handles opcode 0x86
1963884e6d60SXin LI */
1964884e6d60SXin LI static void
x86emuOp_xchg_byte_RM_R(struct x86emu * emu)1965884e6d60SXin LI x86emuOp_xchg_byte_RM_R(struct x86emu *emu)
1966884e6d60SXin LI {
1967884e6d60SXin LI uint8_t *srcreg, destval, tmp;
1968884e6d60SXin LI
1969884e6d60SXin LI fetch_decode_modrm(emu);
1970884e6d60SXin LI destval = decode_and_fetch_byte(emu);
1971884e6d60SXin LI srcreg = decode_rh_byte_register(emu);
1972884e6d60SXin LI tmp = destval;
1973884e6d60SXin LI destval = *srcreg;
1974884e6d60SXin LI *srcreg = tmp;
1975884e6d60SXin LI write_back_byte(emu, destval);
1976884e6d60SXin LI }
1977884e6d60SXin LI
1978884e6d60SXin LI /*
1979884e6d60SXin LI * REMARKS:
1980884e6d60SXin LI * Handles opcode 0x87
1981884e6d60SXin LI */
1982884e6d60SXin LI static void
x86emuOp32_xchg_word_RM_R(struct x86emu * emu)1983884e6d60SXin LI x86emuOp32_xchg_word_RM_R(struct x86emu *emu)
1984884e6d60SXin LI {
1985884e6d60SXin LI uint32_t *srcreg, destval, tmp;
1986884e6d60SXin LI
1987884e6d60SXin LI fetch_decode_modrm(emu);
1988884e6d60SXin LI destval = decode_and_fetch_long(emu);
1989884e6d60SXin LI srcreg = decode_rh_long_register(emu);
1990884e6d60SXin LI tmp = destval;
1991884e6d60SXin LI destval = *srcreg;
1992884e6d60SXin LI *srcreg = tmp;
1993884e6d60SXin LI write_back_long(emu, destval);
1994884e6d60SXin LI }
1995884e6d60SXin LI
1996884e6d60SXin LI static void
x86emuOp16_xchg_word_RM_R(struct x86emu * emu)1997884e6d60SXin LI x86emuOp16_xchg_word_RM_R(struct x86emu *emu)
1998884e6d60SXin LI {
1999884e6d60SXin LI uint16_t *srcreg, destval, tmp;
2000884e6d60SXin LI
2001884e6d60SXin LI fetch_decode_modrm(emu);
2002884e6d60SXin LI destval = decode_and_fetch_word(emu);
2003884e6d60SXin LI srcreg = decode_rh_word_register(emu);
2004884e6d60SXin LI tmp = destval;
2005884e6d60SXin LI destval = *srcreg;
2006884e6d60SXin LI *srcreg = tmp;
2007884e6d60SXin LI write_back_word(emu, destval);
2008884e6d60SXin LI }
2009884e6d60SXin LI
2010884e6d60SXin LI static void
x86emuOp_xchg_word_RM_R(struct x86emu * emu)2011884e6d60SXin LI x86emuOp_xchg_word_RM_R(struct x86emu *emu)
2012884e6d60SXin LI {
2013884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2014884e6d60SXin LI x86emuOp32_xchg_word_RM_R(emu);
2015884e6d60SXin LI else
2016884e6d60SXin LI x86emuOp16_xchg_word_RM_R(emu);
2017884e6d60SXin LI }
2018884e6d60SXin LI
2019884e6d60SXin LI /*
2020884e6d60SXin LI * REMARKS:
2021884e6d60SXin LI * Handles opcode 0x88
2022884e6d60SXin LI */
2023884e6d60SXin LI static void
x86emuOp_mov_byte_RM_R(struct x86emu * emu)2024884e6d60SXin LI x86emuOp_mov_byte_RM_R(struct x86emu *emu)
2025884e6d60SXin LI {
2026884e6d60SXin LI uint8_t *destreg, *srcreg;
2027884e6d60SXin LI uint32_t destoffset;
2028884e6d60SXin LI
2029884e6d60SXin LI fetch_decode_modrm(emu);
2030884e6d60SXin LI srcreg = decode_rh_byte_register(emu);
2031884e6d60SXin LI if (emu->cur_mod != 3) {
2032884e6d60SXin LI destoffset = decode_rl_address(emu);
2033884e6d60SXin LI store_data_byte(emu, destoffset, *srcreg);
2034884e6d60SXin LI } else {
2035884e6d60SXin LI destreg = decode_rl_byte_register(emu);
2036884e6d60SXin LI *destreg = *srcreg;
2037884e6d60SXin LI }
2038884e6d60SXin LI }
2039884e6d60SXin LI
2040884e6d60SXin LI /*
2041884e6d60SXin LI * REMARKS:
2042884e6d60SXin LI * Handles opcode 0x89
2043884e6d60SXin LI */
2044884e6d60SXin LI static void
x86emuOp32_mov_word_RM_R(struct x86emu * emu)2045884e6d60SXin LI x86emuOp32_mov_word_RM_R(struct x86emu *emu)
2046884e6d60SXin LI {
2047884e6d60SXin LI uint32_t destoffset;
2048884e6d60SXin LI uint32_t *destreg, srcval;
2049884e6d60SXin LI
2050884e6d60SXin LI fetch_decode_modrm(emu);
2051884e6d60SXin LI srcval = *decode_rh_long_register(emu);
2052884e6d60SXin LI if (emu->cur_mod != 3) {
2053884e6d60SXin LI destoffset = decode_rl_address(emu);
2054884e6d60SXin LI store_data_long(emu, destoffset, srcval);
2055884e6d60SXin LI } else {
2056884e6d60SXin LI destreg = decode_rl_long_register(emu);
2057884e6d60SXin LI *destreg = srcval;
2058884e6d60SXin LI }
2059884e6d60SXin LI }
2060884e6d60SXin LI
2061884e6d60SXin LI static void
x86emuOp16_mov_word_RM_R(struct x86emu * emu)2062884e6d60SXin LI x86emuOp16_mov_word_RM_R(struct x86emu *emu)
2063884e6d60SXin LI {
2064884e6d60SXin LI uint32_t destoffset;
2065884e6d60SXin LI uint16_t *destreg, srcval;
2066884e6d60SXin LI
2067884e6d60SXin LI fetch_decode_modrm(emu);
2068884e6d60SXin LI srcval = *decode_rh_word_register(emu);
2069884e6d60SXin LI if (emu->cur_mod != 3) {
2070884e6d60SXin LI destoffset = decode_rl_address(emu);
2071884e6d60SXin LI store_data_word(emu, destoffset, srcval);
2072884e6d60SXin LI } else {
2073884e6d60SXin LI destreg = decode_rl_word_register(emu);
2074884e6d60SXin LI *destreg = srcval;
2075884e6d60SXin LI }
2076884e6d60SXin LI }
2077884e6d60SXin LI
2078884e6d60SXin LI static void
x86emuOp_mov_word_RM_R(struct x86emu * emu)2079884e6d60SXin LI x86emuOp_mov_word_RM_R(struct x86emu *emu)
2080884e6d60SXin LI {
2081884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2082884e6d60SXin LI x86emuOp32_mov_word_RM_R(emu);
2083884e6d60SXin LI else
2084884e6d60SXin LI x86emuOp16_mov_word_RM_R(emu);
2085884e6d60SXin LI }
2086884e6d60SXin LI
2087884e6d60SXin LI /*
2088884e6d60SXin LI * REMARKS:
2089884e6d60SXin LI * Handles opcode 0x8a
2090884e6d60SXin LI */
2091884e6d60SXin LI static void
x86emuOp_mov_byte_R_RM(struct x86emu * emu)2092884e6d60SXin LI x86emuOp_mov_byte_R_RM(struct x86emu *emu)
2093884e6d60SXin LI {
2094884e6d60SXin LI uint8_t *destreg;
2095884e6d60SXin LI
2096884e6d60SXin LI fetch_decode_modrm(emu);
2097884e6d60SXin LI destreg = decode_rh_byte_register(emu);
2098884e6d60SXin LI *destreg = decode_and_fetch_byte(emu);
2099884e6d60SXin LI }
2100884e6d60SXin LI
2101884e6d60SXin LI /*
2102884e6d60SXin LI * REMARKS:
2103884e6d60SXin LI * Handles opcode 0x8b
2104884e6d60SXin LI */
2105884e6d60SXin LI static void
x86emuOp_mov_word_R_RM(struct x86emu * emu)2106884e6d60SXin LI x86emuOp_mov_word_R_RM(struct x86emu *emu)
2107884e6d60SXin LI {
2108884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2109884e6d60SXin LI uint32_t *destreg;
2110884e6d60SXin LI
2111884e6d60SXin LI fetch_decode_modrm(emu);
2112884e6d60SXin LI destreg = decode_rh_long_register(emu);
2113884e6d60SXin LI *destreg = decode_and_fetch_long(emu);
2114884e6d60SXin LI } else {
2115884e6d60SXin LI uint16_t *destreg;
2116884e6d60SXin LI
2117884e6d60SXin LI fetch_decode_modrm(emu);
2118884e6d60SXin LI destreg = decode_rh_word_register(emu);
2119884e6d60SXin LI *destreg = decode_and_fetch_word(emu);
2120884e6d60SXin LI }
2121884e6d60SXin LI }
2122884e6d60SXin LI
2123884e6d60SXin LI /*
2124884e6d60SXin LI * REMARKS:
2125884e6d60SXin LI * Handles opcode 0x8c
2126884e6d60SXin LI */
2127884e6d60SXin LI static void
x86emuOp_mov_word_RM_SR(struct x86emu * emu)2128884e6d60SXin LI x86emuOp_mov_word_RM_SR(struct x86emu *emu)
2129884e6d60SXin LI {
2130884e6d60SXin LI uint16_t *destreg, srcval;
2131884e6d60SXin LI uint32_t destoffset;
2132884e6d60SXin LI
2133884e6d60SXin LI fetch_decode_modrm(emu);
2134884e6d60SXin LI srcval = *decode_rh_seg_register(emu);
2135884e6d60SXin LI if (emu->cur_mod != 3) {
2136884e6d60SXin LI destoffset = decode_rl_address(emu);
2137884e6d60SXin LI store_data_word(emu, destoffset, srcval);
2138884e6d60SXin LI } else {
2139884e6d60SXin LI destreg = decode_rl_word_register(emu);
2140884e6d60SXin LI *destreg = srcval;
2141884e6d60SXin LI }
2142884e6d60SXin LI }
2143884e6d60SXin LI
2144884e6d60SXin LI /*
2145884e6d60SXin LI * REMARKS:
2146884e6d60SXin LI * Handles opcode 0x8d
2147884e6d60SXin LI */
2148884e6d60SXin LI static void
x86emuOp_lea_word_R_M(struct x86emu * emu)2149884e6d60SXin LI x86emuOp_lea_word_R_M(struct x86emu *emu)
2150884e6d60SXin LI {
2151884e6d60SXin LI uint32_t destoffset;
2152884e6d60SXin LI
2153884e6d60SXin LI fetch_decode_modrm(emu);
2154884e6d60SXin LI if (emu->cur_mod == 3)
2155884e6d60SXin LI x86emu_halt_sys(emu);
2156884e6d60SXin LI
2157884e6d60SXin LI destoffset = decode_rl_address(emu);
215879d183e8SXin LI if (emu->x86.mode & SYSMODE_PREFIX_ADDR) {
215979d183e8SXin LI uint32_t *srcreg;
216079d183e8SXin LI
216179d183e8SXin LI srcreg = decode_rh_long_register(emu);
216279d183e8SXin LI *srcreg = (uint32_t) destoffset;
216379d183e8SXin LI } else {
216479d183e8SXin LI uint16_t *srcreg;
216579d183e8SXin LI
216679d183e8SXin LI srcreg = decode_rh_word_register(emu);
2167884e6d60SXin LI *srcreg = (uint16_t) destoffset;
2168884e6d60SXin LI }
216979d183e8SXin LI }
2170884e6d60SXin LI
2171884e6d60SXin LI /*
2172884e6d60SXin LI * REMARKS:
2173884e6d60SXin LI * Handles opcode 0x8e
2174884e6d60SXin LI */
2175884e6d60SXin LI static void
x86emuOp_mov_word_SR_RM(struct x86emu * emu)2176884e6d60SXin LI x86emuOp_mov_word_SR_RM(struct x86emu *emu)
2177884e6d60SXin LI {
2178884e6d60SXin LI uint16_t *destreg;
2179884e6d60SXin LI
2180884e6d60SXin LI fetch_decode_modrm(emu);
2181884e6d60SXin LI destreg = decode_rh_seg_register(emu);
2182884e6d60SXin LI *destreg = decode_and_fetch_word(emu);
2183884e6d60SXin LI /*
2184884e6d60SXin LI * Clean up, and reset all the R_xSP pointers to the correct
2185884e6d60SXin LI * locations. This is about 3x too much overhead (doing all the
2186884e6d60SXin LI * segreg ptrs when only one is needed, but this instruction
2187884e6d60SXin LI * *cannot* be that common, and this isn't too much work anyway.
2188884e6d60SXin LI */
2189884e6d60SXin LI }
2190884e6d60SXin LI
2191884e6d60SXin LI /*
2192884e6d60SXin LI * REMARKS:
2193884e6d60SXin LI * Handles opcode 0x8f
2194884e6d60SXin LI */
2195884e6d60SXin LI static void
x86emuOp32_pop_RM(struct x86emu * emu)2196884e6d60SXin LI x86emuOp32_pop_RM(struct x86emu *emu)
2197884e6d60SXin LI {
2198884e6d60SXin LI uint32_t destoffset;
2199884e6d60SXin LI uint32_t destval, *destreg;
2200884e6d60SXin LI
2201884e6d60SXin LI fetch_decode_modrm(emu);
2202884e6d60SXin LI if (emu->cur_mod != 3) {
2203884e6d60SXin LI destoffset = decode_rl_address(emu);
2204884e6d60SXin LI destval = pop_long(emu);
2205884e6d60SXin LI store_data_long(emu, destoffset, destval);
2206884e6d60SXin LI } else {
2207884e6d60SXin LI destreg = decode_rl_long_register(emu);
2208884e6d60SXin LI *destreg = pop_long(emu);
2209884e6d60SXin LI }
2210884e6d60SXin LI }
2211884e6d60SXin LI
2212884e6d60SXin LI static void
x86emuOp16_pop_RM(struct x86emu * emu)2213884e6d60SXin LI x86emuOp16_pop_RM(struct x86emu *emu)
2214884e6d60SXin LI {
2215884e6d60SXin LI uint32_t destoffset;
2216884e6d60SXin LI uint16_t destval, *destreg;
2217884e6d60SXin LI
2218884e6d60SXin LI fetch_decode_modrm(emu);
2219884e6d60SXin LI if (emu->cur_mod != 3) {
2220884e6d60SXin LI destoffset = decode_rl_address(emu);
2221884e6d60SXin LI destval = pop_word(emu);
2222884e6d60SXin LI store_data_word(emu, destoffset, destval);
2223884e6d60SXin LI } else {
2224884e6d60SXin LI destreg = decode_rl_word_register(emu);
2225884e6d60SXin LI *destreg = pop_word(emu);
2226884e6d60SXin LI }
2227884e6d60SXin LI }
2228884e6d60SXin LI
2229884e6d60SXin LI static void
x86emuOp_pop_RM(struct x86emu * emu)2230884e6d60SXin LI x86emuOp_pop_RM(struct x86emu *emu)
2231884e6d60SXin LI {
2232884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2233884e6d60SXin LI x86emuOp32_pop_RM(emu);
2234884e6d60SXin LI else
2235884e6d60SXin LI x86emuOp16_pop_RM(emu);
2236884e6d60SXin LI }
2237884e6d60SXin LI
2238884e6d60SXin LI /*
2239884e6d60SXin LI * REMARKS:
2240884e6d60SXin LI * Handles opcode 0x91
2241884e6d60SXin LI */
2242884e6d60SXin LI static void
x86emuOp_xchg_word_AX_CX(struct x86emu * emu)2243884e6d60SXin LI x86emuOp_xchg_word_AX_CX(struct x86emu *emu)
2244884e6d60SXin LI {
2245884e6d60SXin LI uint32_t tmp;
2246884e6d60SXin LI
2247884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2248884e6d60SXin LI tmp = emu->x86.R_EAX;
2249884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_ECX;
2250884e6d60SXin LI emu->x86.R_ECX = tmp;
2251884e6d60SXin LI } else {
2252884e6d60SXin LI tmp = emu->x86.R_AX;
2253884e6d60SXin LI emu->x86.R_AX = emu->x86.R_CX;
2254884e6d60SXin LI emu->x86.R_CX = (uint16_t) tmp;
2255884e6d60SXin LI }
2256884e6d60SXin LI }
2257884e6d60SXin LI
2258884e6d60SXin LI /*
2259884e6d60SXin LI * REMARKS:
2260884e6d60SXin LI * Handles opcode 0x92
2261884e6d60SXin LI */
2262884e6d60SXin LI static void
x86emuOp_xchg_word_AX_DX(struct x86emu * emu)2263884e6d60SXin LI x86emuOp_xchg_word_AX_DX(struct x86emu *emu)
2264884e6d60SXin LI {
2265884e6d60SXin LI uint32_t tmp;
2266884e6d60SXin LI
2267884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2268884e6d60SXin LI tmp = emu->x86.R_EAX;
2269884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_EDX;
2270884e6d60SXin LI emu->x86.R_EDX = tmp;
2271884e6d60SXin LI } else {
2272884e6d60SXin LI tmp = emu->x86.R_AX;
2273884e6d60SXin LI emu->x86.R_AX = emu->x86.R_DX;
2274884e6d60SXin LI emu->x86.R_DX = (uint16_t) tmp;
2275884e6d60SXin LI }
2276884e6d60SXin LI }
2277884e6d60SXin LI
2278884e6d60SXin LI /*
2279884e6d60SXin LI * REMARKS:
2280884e6d60SXin LI * Handles opcode 0x93
2281884e6d60SXin LI */
2282884e6d60SXin LI static void
x86emuOp_xchg_word_AX_BX(struct x86emu * emu)2283884e6d60SXin LI x86emuOp_xchg_word_AX_BX(struct x86emu *emu)
2284884e6d60SXin LI {
2285884e6d60SXin LI uint32_t tmp;
2286884e6d60SXin LI
2287884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2288884e6d60SXin LI tmp = emu->x86.R_EAX;
2289884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_EBX;
2290884e6d60SXin LI emu->x86.R_EBX = tmp;
2291884e6d60SXin LI } else {
2292884e6d60SXin LI tmp = emu->x86.R_AX;
2293884e6d60SXin LI emu->x86.R_AX = emu->x86.R_BX;
2294884e6d60SXin LI emu->x86.R_BX = (uint16_t) tmp;
2295884e6d60SXin LI }
2296884e6d60SXin LI }
2297884e6d60SXin LI
2298884e6d60SXin LI /*
2299884e6d60SXin LI * REMARKS:
2300884e6d60SXin LI * Handles opcode 0x94
2301884e6d60SXin LI */
2302884e6d60SXin LI static void
x86emuOp_xchg_word_AX_SP(struct x86emu * emu)2303884e6d60SXin LI x86emuOp_xchg_word_AX_SP(struct x86emu *emu)
2304884e6d60SXin LI {
2305884e6d60SXin LI uint32_t tmp;
2306884e6d60SXin LI
2307884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2308884e6d60SXin LI tmp = emu->x86.R_EAX;
2309884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_ESP;
2310884e6d60SXin LI emu->x86.R_ESP = tmp;
2311884e6d60SXin LI } else {
2312884e6d60SXin LI tmp = emu->x86.R_AX;
2313884e6d60SXin LI emu->x86.R_AX = emu->x86.R_SP;
2314884e6d60SXin LI emu->x86.R_SP = (uint16_t) tmp;
2315884e6d60SXin LI }
2316884e6d60SXin LI }
2317884e6d60SXin LI
2318884e6d60SXin LI /*
2319884e6d60SXin LI * REMARKS:
2320884e6d60SXin LI * Handles opcode 0x95
2321884e6d60SXin LI */
2322884e6d60SXin LI static void
x86emuOp_xchg_word_AX_BP(struct x86emu * emu)2323884e6d60SXin LI x86emuOp_xchg_word_AX_BP(struct x86emu *emu)
2324884e6d60SXin LI {
2325884e6d60SXin LI uint32_t tmp;
2326884e6d60SXin LI
2327884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2328884e6d60SXin LI tmp = emu->x86.R_EAX;
2329884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_EBP;
2330884e6d60SXin LI emu->x86.R_EBP = tmp;
2331884e6d60SXin LI } else {
2332884e6d60SXin LI tmp = emu->x86.R_AX;
2333884e6d60SXin LI emu->x86.R_AX = emu->x86.R_BP;
2334884e6d60SXin LI emu->x86.R_BP = (uint16_t) tmp;
2335884e6d60SXin LI }
2336884e6d60SXin LI }
2337884e6d60SXin LI
2338884e6d60SXin LI /*
2339884e6d60SXin LI * REMARKS:
2340884e6d60SXin LI * Handles opcode 0x96
2341884e6d60SXin LI */
2342884e6d60SXin LI static void
x86emuOp_xchg_word_AX_SI(struct x86emu * emu)2343884e6d60SXin LI x86emuOp_xchg_word_AX_SI(struct x86emu *emu)
2344884e6d60SXin LI {
2345884e6d60SXin LI uint32_t tmp;
2346884e6d60SXin LI
2347884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2348884e6d60SXin LI tmp = emu->x86.R_EAX;
2349884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_ESI;
2350884e6d60SXin LI emu->x86.R_ESI = tmp;
2351884e6d60SXin LI } else {
2352884e6d60SXin LI tmp = emu->x86.R_AX;
2353884e6d60SXin LI emu->x86.R_AX = emu->x86.R_SI;
2354884e6d60SXin LI emu->x86.R_SI = (uint16_t) tmp;
2355884e6d60SXin LI }
2356884e6d60SXin LI }
2357884e6d60SXin LI
2358884e6d60SXin LI /*
2359884e6d60SXin LI * REMARKS:
2360884e6d60SXin LI * Handles opcode 0x97
2361884e6d60SXin LI */
2362884e6d60SXin LI static void
x86emuOp_xchg_word_AX_DI(struct x86emu * emu)2363884e6d60SXin LI x86emuOp_xchg_word_AX_DI(struct x86emu *emu)
2364884e6d60SXin LI {
2365884e6d60SXin LI uint32_t tmp;
2366884e6d60SXin LI
2367884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2368884e6d60SXin LI tmp = emu->x86.R_EAX;
2369884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_EDI;
2370884e6d60SXin LI emu->x86.R_EDI = tmp;
2371884e6d60SXin LI } else {
2372884e6d60SXin LI tmp = emu->x86.R_AX;
2373884e6d60SXin LI emu->x86.R_AX = emu->x86.R_DI;
2374884e6d60SXin LI emu->x86.R_DI = (uint16_t) tmp;
2375884e6d60SXin LI }
2376884e6d60SXin LI }
2377884e6d60SXin LI
2378884e6d60SXin LI /*
2379884e6d60SXin LI * REMARKS:
2380884e6d60SXin LI * Handles opcode 0x98
2381884e6d60SXin LI */
2382884e6d60SXin LI static void
x86emuOp_cbw(struct x86emu * emu)2383884e6d60SXin LI x86emuOp_cbw(struct x86emu *emu)
2384884e6d60SXin LI {
2385884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2386884e6d60SXin LI if (emu->x86.R_AX & 0x8000) {
2387884e6d60SXin LI emu->x86.R_EAX |= 0xffff0000;
2388884e6d60SXin LI } else {
2389884e6d60SXin LI emu->x86.R_EAX &= 0x0000ffff;
2390884e6d60SXin LI }
2391884e6d60SXin LI } else {
2392884e6d60SXin LI if (emu->x86.R_AL & 0x80) {
2393884e6d60SXin LI emu->x86.R_AH = 0xff;
2394884e6d60SXin LI } else {
2395884e6d60SXin LI emu->x86.R_AH = 0x0;
2396884e6d60SXin LI }
2397884e6d60SXin LI }
2398884e6d60SXin LI }
2399884e6d60SXin LI
2400884e6d60SXin LI /*
2401884e6d60SXin LI * REMARKS:
2402884e6d60SXin LI * Handles opcode 0x99
2403884e6d60SXin LI */
2404884e6d60SXin LI static void
x86emuOp_cwd(struct x86emu * emu)2405884e6d60SXin LI x86emuOp_cwd(struct x86emu *emu)
2406884e6d60SXin LI {
2407884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2408884e6d60SXin LI if (emu->x86.R_EAX & 0x80000000) {
2409884e6d60SXin LI emu->x86.R_EDX = 0xffffffff;
2410884e6d60SXin LI } else {
2411884e6d60SXin LI emu->x86.R_EDX = 0x0;
2412884e6d60SXin LI }
2413884e6d60SXin LI } else {
2414884e6d60SXin LI if (emu->x86.R_AX & 0x8000) {
2415884e6d60SXin LI emu->x86.R_DX = 0xffff;
2416884e6d60SXin LI } else {
2417884e6d60SXin LI emu->x86.R_DX = 0x0;
2418884e6d60SXin LI }
2419884e6d60SXin LI }
2420884e6d60SXin LI }
2421884e6d60SXin LI
2422884e6d60SXin LI /*
2423884e6d60SXin LI * REMARKS:
2424884e6d60SXin LI * Handles opcode 0x9a
2425884e6d60SXin LI */
2426884e6d60SXin LI static void
x86emuOp_call_far_IMM(struct x86emu * emu)2427884e6d60SXin LI x86emuOp_call_far_IMM(struct x86emu *emu)
2428884e6d60SXin LI {
2429884e6d60SXin LI uint16_t farseg, faroff;
2430884e6d60SXin LI
2431884e6d60SXin LI faroff = fetch_word_imm(emu);
2432884e6d60SXin LI farseg = fetch_word_imm(emu);
2433884e6d60SXin LI /* XXX
2434884e6d60SXin LI *
2435884e6d60SXin LI * Hooked interrupt vectors calling into our "BIOS" will cause problems
2436884e6d60SXin LI * unless all intersegment stuff is checked for BIOS access. Check
2437884e6d60SXin LI * needed here. For moment, let it alone. */
2438884e6d60SXin LI push_word(emu, emu->x86.R_CS);
2439884e6d60SXin LI emu->x86.R_CS = farseg;
2440884e6d60SXin LI push_word(emu, emu->x86.R_IP);
2441884e6d60SXin LI emu->x86.R_IP = faroff;
2442884e6d60SXin LI }
2443884e6d60SXin LI
2444884e6d60SXin LI /*
2445884e6d60SXin LI * REMARKS:
2446884e6d60SXin LI * Handles opcode 0x9c
2447884e6d60SXin LI */
2448884e6d60SXin LI static void
x86emuOp_pushf_word(struct x86emu * emu)2449884e6d60SXin LI x86emuOp_pushf_word(struct x86emu *emu)
2450884e6d60SXin LI {
2451884e6d60SXin LI uint32_t flags;
2452884e6d60SXin LI
2453884e6d60SXin LI /* clear out *all* bits not representing flags, and turn on real bits */
2454884e6d60SXin LI flags = (emu->x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
2455884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2456884e6d60SXin LI push_long(emu, flags);
2457884e6d60SXin LI } else {
2458884e6d60SXin LI push_word(emu, (uint16_t) flags);
2459884e6d60SXin LI }
2460884e6d60SXin LI }
2461884e6d60SXin LI
2462884e6d60SXin LI /*
2463884e6d60SXin LI * REMARKS:
2464884e6d60SXin LI * Handles opcode 0x9d
2465884e6d60SXin LI */
2466884e6d60SXin LI static void
x86emuOp_popf_word(struct x86emu * emu)2467884e6d60SXin LI x86emuOp_popf_word(struct x86emu *emu)
2468884e6d60SXin LI {
2469884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2470884e6d60SXin LI emu->x86.R_EFLG = pop_long(emu);
2471884e6d60SXin LI } else {
2472884e6d60SXin LI emu->x86.R_FLG = pop_word(emu);
2473884e6d60SXin LI }
2474884e6d60SXin LI }
2475884e6d60SXin LI
2476884e6d60SXin LI /*
2477884e6d60SXin LI * REMARKS:
2478884e6d60SXin LI * Handles opcode 0x9e
2479884e6d60SXin LI */
2480884e6d60SXin LI static void
x86emuOp_sahf(struct x86emu * emu)2481884e6d60SXin LI x86emuOp_sahf(struct x86emu *emu)
2482884e6d60SXin LI {
2483884e6d60SXin LI /* clear the lower bits of the flag register */
2484884e6d60SXin LI emu->x86.R_FLG &= 0xffffff00;
2485884e6d60SXin LI /* or in the AH register into the flags register */
2486884e6d60SXin LI emu->x86.R_FLG |= emu->x86.R_AH;
2487884e6d60SXin LI }
2488884e6d60SXin LI
2489884e6d60SXin LI /*
2490884e6d60SXin LI * REMARKS:
2491884e6d60SXin LI * Handles opcode 0x9f
2492884e6d60SXin LI */
2493884e6d60SXin LI static void
x86emuOp_lahf(struct x86emu * emu)2494884e6d60SXin LI x86emuOp_lahf(struct x86emu *emu)
2495884e6d60SXin LI {
2496884e6d60SXin LI emu->x86.R_AH = (uint8_t) (emu->x86.R_FLG & 0xff);
2497884e6d60SXin LI /* undocumented TC++ behavior??? Nope. It's documented, but you have
2498884e6d60SXin LI * too look real hard to notice it. */
2499884e6d60SXin LI emu->x86.R_AH |= 0x2;
2500884e6d60SXin LI }
2501884e6d60SXin LI
2502884e6d60SXin LI /*
2503884e6d60SXin LI * REMARKS:
2504884e6d60SXin LI * Handles opcode 0xa0
2505884e6d60SXin LI */
2506884e6d60SXin LI static void
x86emuOp_mov_AL_M_IMM(struct x86emu * emu)2507884e6d60SXin LI x86emuOp_mov_AL_M_IMM(struct x86emu *emu)
2508884e6d60SXin LI {
2509884e6d60SXin LI uint16_t offset;
2510884e6d60SXin LI
2511884e6d60SXin LI offset = fetch_word_imm(emu);
2512884e6d60SXin LI emu->x86.R_AL = fetch_data_byte(emu, offset);
2513884e6d60SXin LI }
2514884e6d60SXin LI
2515884e6d60SXin LI /*
2516884e6d60SXin LI * REMARKS:
2517884e6d60SXin LI * Handles opcode 0xa1
2518884e6d60SXin LI */
2519884e6d60SXin LI static void
x86emuOp_mov_AX_M_IMM(struct x86emu * emu)2520884e6d60SXin LI x86emuOp_mov_AX_M_IMM(struct x86emu *emu)
2521884e6d60SXin LI {
2522884e6d60SXin LI uint16_t offset;
2523884e6d60SXin LI
2524884e6d60SXin LI offset = fetch_word_imm(emu);
2525884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2526884e6d60SXin LI emu->x86.R_EAX = fetch_data_long(emu, offset);
2527884e6d60SXin LI } else {
2528884e6d60SXin LI emu->x86.R_AX = fetch_data_word(emu, offset);
2529884e6d60SXin LI }
2530884e6d60SXin LI }
2531884e6d60SXin LI
2532884e6d60SXin LI /*
2533884e6d60SXin LI * REMARKS:
2534884e6d60SXin LI * Handles opcode 0xa2
2535884e6d60SXin LI */
2536884e6d60SXin LI static void
x86emuOp_mov_M_AL_IMM(struct x86emu * emu)2537884e6d60SXin LI x86emuOp_mov_M_AL_IMM(struct x86emu *emu)
2538884e6d60SXin LI {
2539884e6d60SXin LI uint16_t offset;
2540884e6d60SXin LI
2541884e6d60SXin LI offset = fetch_word_imm(emu);
2542884e6d60SXin LI store_data_byte(emu, offset, emu->x86.R_AL);
2543884e6d60SXin LI }
2544884e6d60SXin LI
2545884e6d60SXin LI /*
2546884e6d60SXin LI * REMARKS:
2547884e6d60SXin LI * Handles opcode 0xa3
2548884e6d60SXin LI */
2549884e6d60SXin LI static void
x86emuOp_mov_M_AX_IMM(struct x86emu * emu)2550884e6d60SXin LI x86emuOp_mov_M_AX_IMM(struct x86emu *emu)
2551884e6d60SXin LI {
2552884e6d60SXin LI uint16_t offset;
2553884e6d60SXin LI
2554884e6d60SXin LI offset = fetch_word_imm(emu);
2555884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2556884e6d60SXin LI store_data_long(emu, offset, emu->x86.R_EAX);
2557884e6d60SXin LI } else {
2558884e6d60SXin LI store_data_word(emu, offset, emu->x86.R_AX);
2559884e6d60SXin LI }
2560884e6d60SXin LI }
2561884e6d60SXin LI
2562884e6d60SXin LI /*
2563884e6d60SXin LI * REMARKS:
2564884e6d60SXin LI * Handles opcode 0xa4
2565884e6d60SXin LI */
2566884e6d60SXin LI static void
x86emuOp_movs_byte(struct x86emu * emu)2567884e6d60SXin LI x86emuOp_movs_byte(struct x86emu *emu)
2568884e6d60SXin LI {
2569884e6d60SXin LI uint8_t val;
2570884e6d60SXin LI uint32_t count;
2571884e6d60SXin LI int inc;
2572884e6d60SXin LI
2573884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2574884e6d60SXin LI inc = -1;
2575884e6d60SXin LI else
2576884e6d60SXin LI inc = 1;
2577884e6d60SXin LI count = 1;
2578884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2579884e6d60SXin LI /* dont care whether REPE or REPNE */
2580884e6d60SXin LI /* move them until CX is ZERO. */
2581884e6d60SXin LI count = emu->x86.R_CX;
2582884e6d60SXin LI emu->x86.R_CX = 0;
2583884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2584884e6d60SXin LI }
2585884e6d60SXin LI while (count--) {
2586884e6d60SXin LI val = fetch_data_byte(emu, emu->x86.R_SI);
2587884e6d60SXin LI store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, val);
2588884e6d60SXin LI emu->x86.R_SI += inc;
2589884e6d60SXin LI emu->x86.R_DI += inc;
2590884e6d60SXin LI }
2591884e6d60SXin LI }
2592884e6d60SXin LI
2593884e6d60SXin LI /*
2594884e6d60SXin LI * REMARKS:
2595884e6d60SXin LI * Handles opcode 0xa5
2596884e6d60SXin LI */
2597884e6d60SXin LI static void
x86emuOp_movs_word(struct x86emu * emu)2598884e6d60SXin LI x86emuOp_movs_word(struct x86emu *emu)
2599884e6d60SXin LI {
2600884e6d60SXin LI uint32_t val;
2601884e6d60SXin LI int inc;
2602884e6d60SXin LI uint32_t count;
2603884e6d60SXin LI
2604884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2605884e6d60SXin LI inc = 4;
2606884e6d60SXin LI else
2607884e6d60SXin LI inc = 2;
2608884e6d60SXin LI
2609884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2610884e6d60SXin LI inc = -inc;
2611884e6d60SXin LI
2612884e6d60SXin LI count = 1;
2613884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2614884e6d60SXin LI /* dont care whether REPE or REPNE */
2615884e6d60SXin LI /* move them until CX is ZERO. */
2616884e6d60SXin LI count = emu->x86.R_CX;
2617884e6d60SXin LI emu->x86.R_CX = 0;
2618884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2619884e6d60SXin LI }
2620884e6d60SXin LI while (count--) {
2621884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2622884e6d60SXin LI val = fetch_data_long(emu, emu->x86.R_SI);
2623884e6d60SXin LI store_long(emu, emu->x86.R_ES, emu->x86.R_DI, val);
2624884e6d60SXin LI } else {
2625884e6d60SXin LI val = fetch_data_word(emu, emu->x86.R_SI);
262606325fe0SXin LI store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
262706325fe0SXin LI (uint16_t) val);
2628884e6d60SXin LI }
2629884e6d60SXin LI emu->x86.R_SI += inc;
2630884e6d60SXin LI emu->x86.R_DI += inc;
2631884e6d60SXin LI }
2632884e6d60SXin LI }
2633884e6d60SXin LI
2634884e6d60SXin LI /*
2635884e6d60SXin LI * REMARKS:
2636884e6d60SXin LI * Handles opcode 0xa6
2637884e6d60SXin LI */
2638884e6d60SXin LI static void
x86emuOp_cmps_byte(struct x86emu * emu)2639884e6d60SXin LI x86emuOp_cmps_byte(struct x86emu *emu)
2640884e6d60SXin LI {
2641884e6d60SXin LI int8_t val1, val2;
2642884e6d60SXin LI int inc;
2643884e6d60SXin LI
2644884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2645884e6d60SXin LI inc = -1;
2646884e6d60SXin LI else
2647884e6d60SXin LI inc = 1;
2648884e6d60SXin LI
2649884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
2650884e6d60SXin LI /* REPE */
2651884e6d60SXin LI /* move them until CX is ZERO. */
2652884e6d60SXin LI while (emu->x86.R_CX != 0) {
2653884e6d60SXin LI val1 = fetch_data_byte(emu, emu->x86.R_SI);
2654884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2655884e6d60SXin LI cmp_byte(emu, val1, val2);
2656884e6d60SXin LI emu->x86.R_CX -= 1;
2657884e6d60SXin LI emu->x86.R_SI += inc;
2658884e6d60SXin LI emu->x86.R_DI += inc;
2659884e6d60SXin LI if (ACCESS_FLAG(F_ZF) == 0)
2660884e6d60SXin LI break;
2661884e6d60SXin LI }
2662884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
2663884e6d60SXin LI } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
2664884e6d60SXin LI /* REPNE */
2665884e6d60SXin LI /* move them until CX is ZERO. */
2666884e6d60SXin LI while (emu->x86.R_CX != 0) {
2667884e6d60SXin LI val1 = fetch_data_byte(emu, emu->x86.R_SI);
2668884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2669884e6d60SXin LI cmp_byte(emu, val1, val2);
2670884e6d60SXin LI emu->x86.R_CX -= 1;
2671884e6d60SXin LI emu->x86.R_SI += inc;
2672884e6d60SXin LI emu->x86.R_DI += inc;
2673884e6d60SXin LI if (ACCESS_FLAG(F_ZF))
2674884e6d60SXin LI break; /* zero flag set means equal */
2675884e6d60SXin LI }
2676884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
2677884e6d60SXin LI } else {
2678884e6d60SXin LI val1 = fetch_data_byte(emu, emu->x86.R_SI);
2679884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2680884e6d60SXin LI cmp_byte(emu, val1, val2);
2681884e6d60SXin LI emu->x86.R_SI += inc;
2682884e6d60SXin LI emu->x86.R_DI += inc;
2683884e6d60SXin LI }
2684884e6d60SXin LI }
2685884e6d60SXin LI
2686884e6d60SXin LI /*
2687884e6d60SXin LI * REMARKS:
2688884e6d60SXin LI * Handles opcode 0xa7
2689884e6d60SXin LI */
2690884e6d60SXin LI static void
x86emuOp_cmps_word(struct x86emu * emu)2691884e6d60SXin LI x86emuOp_cmps_word(struct x86emu *emu)
2692884e6d60SXin LI {
2693884e6d60SXin LI uint32_t val1, val2;
2694884e6d60SXin LI int inc;
2695884e6d60SXin LI
2696884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2697884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2698884e6d60SXin LI inc = -4;
2699884e6d60SXin LI else
2700884e6d60SXin LI inc = 4;
2701884e6d60SXin LI } else {
2702884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2703884e6d60SXin LI inc = -2;
2704884e6d60SXin LI else
2705884e6d60SXin LI inc = 2;
2706884e6d60SXin LI }
2707884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
2708884e6d60SXin LI /* REPE */
2709884e6d60SXin LI /* move them until CX is ZERO. */
2710884e6d60SXin LI while (emu->x86.R_CX != 0) {
2711884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2712884e6d60SXin LI val1 = fetch_data_long(emu, emu->x86.R_SI);
271306325fe0SXin LI val2 = fetch_long(emu, emu->x86.R_ES,
271406325fe0SXin LI emu->x86.R_DI);
2715884e6d60SXin LI cmp_long(emu, val1, val2);
2716884e6d60SXin LI } else {
2717884e6d60SXin LI val1 = fetch_data_word(emu, emu->x86.R_SI);
271806325fe0SXin LI val2 = fetch_word(emu, emu->x86.R_ES,
271906325fe0SXin LI emu->x86.R_DI);
2720884e6d60SXin LI cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
2721884e6d60SXin LI }
2722884e6d60SXin LI emu->x86.R_CX -= 1;
2723884e6d60SXin LI emu->x86.R_SI += inc;
2724884e6d60SXin LI emu->x86.R_DI += inc;
2725884e6d60SXin LI if (ACCESS_FLAG(F_ZF) == 0)
2726884e6d60SXin LI break;
2727884e6d60SXin LI }
2728884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
2729884e6d60SXin LI } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
2730884e6d60SXin LI /* REPNE */
2731884e6d60SXin LI /* move them until CX is ZERO. */
2732884e6d60SXin LI while (emu->x86.R_CX != 0) {
2733884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2734884e6d60SXin LI val1 = fetch_data_long(emu, emu->x86.R_SI);
273506325fe0SXin LI val2 = fetch_long(emu, emu->x86.R_ES,
273606325fe0SXin LI emu->x86.R_DI);
2737884e6d60SXin LI cmp_long(emu, val1, val2);
2738884e6d60SXin LI } else {
2739884e6d60SXin LI val1 = fetch_data_word(emu, emu->x86.R_SI);
274006325fe0SXin LI val2 = fetch_word(emu, emu->x86.R_ES,
274106325fe0SXin LI emu->x86.R_DI);
2742884e6d60SXin LI cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
2743884e6d60SXin LI }
2744884e6d60SXin LI emu->x86.R_CX -= 1;
2745884e6d60SXin LI emu->x86.R_SI += inc;
2746884e6d60SXin LI emu->x86.R_DI += inc;
2747884e6d60SXin LI if (ACCESS_FLAG(F_ZF))
2748884e6d60SXin LI break; /* zero flag set means equal */
2749884e6d60SXin LI }
2750884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
2751884e6d60SXin LI } else {
2752884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2753884e6d60SXin LI val1 = fetch_data_long(emu, emu->x86.R_SI);
2754884e6d60SXin LI val2 = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
2755884e6d60SXin LI cmp_long(emu, val1, val2);
2756884e6d60SXin LI } else {
2757884e6d60SXin LI val1 = fetch_data_word(emu, emu->x86.R_SI);
2758884e6d60SXin LI val2 = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
2759884e6d60SXin LI cmp_word(emu, (uint16_t) val1, (uint16_t) val2);
2760884e6d60SXin LI }
2761884e6d60SXin LI emu->x86.R_SI += inc;
2762884e6d60SXin LI emu->x86.R_DI += inc;
2763884e6d60SXin LI }
2764884e6d60SXin LI }
2765884e6d60SXin LI
2766884e6d60SXin LI /*
2767884e6d60SXin LI * REMARKS:
2768884e6d60SXin LI * Handles opcode 0xa9
2769884e6d60SXin LI */
2770884e6d60SXin LI static void
x86emuOp_test_AX_IMM(struct x86emu * emu)2771884e6d60SXin LI x86emuOp_test_AX_IMM(struct x86emu *emu)
2772884e6d60SXin LI {
2773884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2774884e6d60SXin LI test_long(emu, emu->x86.R_EAX, fetch_long_imm(emu));
2775884e6d60SXin LI } else {
2776884e6d60SXin LI test_word(emu, emu->x86.R_AX, fetch_word_imm(emu));
2777884e6d60SXin LI }
2778884e6d60SXin LI }
2779884e6d60SXin LI
2780884e6d60SXin LI /*
2781884e6d60SXin LI * REMARKS:
2782884e6d60SXin LI * Handles opcode 0xaa
2783884e6d60SXin LI */
2784884e6d60SXin LI static void
x86emuOp_stos_byte(struct x86emu * emu)2785884e6d60SXin LI x86emuOp_stos_byte(struct x86emu *emu)
2786884e6d60SXin LI {
2787884e6d60SXin LI int inc;
2788884e6d60SXin LI
2789884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2790884e6d60SXin LI inc = -1;
2791884e6d60SXin LI else
2792884e6d60SXin LI inc = 1;
2793884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2794884e6d60SXin LI /* dont care whether REPE or REPNE */
2795884e6d60SXin LI /* move them until CX is ZERO. */
2796884e6d60SXin LI while (emu->x86.R_CX != 0) {
279706325fe0SXin LI store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
279806325fe0SXin LI emu->x86.R_AL);
2799884e6d60SXin LI emu->x86.R_CX -= 1;
2800884e6d60SXin LI emu->x86.R_DI += inc;
2801884e6d60SXin LI }
2802884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2803884e6d60SXin LI } else {
2804884e6d60SXin LI store_byte(emu, emu->x86.R_ES, emu->x86.R_DI, emu->x86.R_AL);
2805884e6d60SXin LI emu->x86.R_DI += inc;
2806884e6d60SXin LI }
2807884e6d60SXin LI }
2808884e6d60SXin LI
2809884e6d60SXin LI /*
2810884e6d60SXin LI * REMARKS:
2811884e6d60SXin LI * Handles opcode 0xab
2812884e6d60SXin LI */
2813884e6d60SXin LI static void
x86emuOp_stos_word(struct x86emu * emu)2814884e6d60SXin LI x86emuOp_stos_word(struct x86emu *emu)
2815884e6d60SXin LI {
2816884e6d60SXin LI int inc;
2817884e6d60SXin LI uint32_t count;
2818884e6d60SXin LI
2819884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2820884e6d60SXin LI inc = 4;
2821884e6d60SXin LI else
2822884e6d60SXin LI inc = 2;
2823884e6d60SXin LI
2824884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2825884e6d60SXin LI inc = -inc;
2826884e6d60SXin LI
2827884e6d60SXin LI count = 1;
2828884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2829884e6d60SXin LI /* dont care whether REPE or REPNE */
2830884e6d60SXin LI /* move them until CX is ZERO. */
2831884e6d60SXin LI count = emu->x86.R_CX;
2832884e6d60SXin LI emu->x86.R_CX = 0;
2833884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2834884e6d60SXin LI }
2835884e6d60SXin LI while (count--) {
2836884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
283706325fe0SXin LI store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
283806325fe0SXin LI emu->x86.R_EAX);
2839884e6d60SXin LI } else {
284006325fe0SXin LI store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
284106325fe0SXin LI emu->x86.R_AX);
2842884e6d60SXin LI }
2843884e6d60SXin LI emu->x86.R_DI += inc;
2844884e6d60SXin LI }
2845884e6d60SXin LI }
2846884e6d60SXin LI
2847884e6d60SXin LI /*
2848884e6d60SXin LI * REMARKS:
2849884e6d60SXin LI * Handles opcode 0xac
2850884e6d60SXin LI */
2851884e6d60SXin LI static void
x86emuOp_lods_byte(struct x86emu * emu)2852884e6d60SXin LI x86emuOp_lods_byte(struct x86emu *emu)
2853884e6d60SXin LI {
2854884e6d60SXin LI int inc;
2855884e6d60SXin LI
2856884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2857884e6d60SXin LI inc = -1;
2858884e6d60SXin LI else
2859884e6d60SXin LI inc = 1;
2860884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2861884e6d60SXin LI /* dont care whether REPE or REPNE */
2862884e6d60SXin LI /* move them until CX is ZERO. */
2863884e6d60SXin LI while (emu->x86.R_CX != 0) {
2864884e6d60SXin LI emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
2865884e6d60SXin LI emu->x86.R_CX -= 1;
2866884e6d60SXin LI emu->x86.R_SI += inc;
2867884e6d60SXin LI }
2868884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2869884e6d60SXin LI } else {
2870884e6d60SXin LI emu->x86.R_AL = fetch_data_byte(emu, emu->x86.R_SI);
2871884e6d60SXin LI emu->x86.R_SI += inc;
2872884e6d60SXin LI }
2873884e6d60SXin LI }
2874884e6d60SXin LI
2875884e6d60SXin LI /*
2876884e6d60SXin LI * REMARKS:
2877884e6d60SXin LI * Handles opcode 0xad
2878884e6d60SXin LI */
2879884e6d60SXin LI static void
x86emuOp_lods_word(struct x86emu * emu)2880884e6d60SXin LI x86emuOp_lods_word(struct x86emu *emu)
2881884e6d60SXin LI {
2882884e6d60SXin LI int inc;
2883884e6d60SXin LI uint32_t count;
2884884e6d60SXin LI
2885884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2886884e6d60SXin LI inc = 4;
2887884e6d60SXin LI else
2888884e6d60SXin LI inc = 2;
2889884e6d60SXin LI
2890884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2891884e6d60SXin LI inc = -inc;
2892884e6d60SXin LI
2893884e6d60SXin LI count = 1;
2894884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2895884e6d60SXin LI /* dont care whether REPE or REPNE */
2896884e6d60SXin LI /* move them until CX is ZERO. */
2897884e6d60SXin LI count = emu->x86.R_CX;
2898884e6d60SXin LI emu->x86.R_CX = 0;
2899884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2900884e6d60SXin LI }
2901884e6d60SXin LI while (count--) {
2902884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
2903884e6d60SXin LI emu->x86.R_EAX = fetch_data_long(emu, emu->x86.R_SI);
2904884e6d60SXin LI } else {
2905884e6d60SXin LI emu->x86.R_AX = fetch_data_word(emu, emu->x86.R_SI);
2906884e6d60SXin LI }
2907884e6d60SXin LI emu->x86.R_SI += inc;
2908884e6d60SXin LI }
2909884e6d60SXin LI }
2910884e6d60SXin LI
2911884e6d60SXin LI /*
2912884e6d60SXin LI * REMARKS:
2913884e6d60SXin LI * Handles opcode 0xae
2914884e6d60SXin LI */
2915884e6d60SXin LI static void
x86emuOp_scas_byte(struct x86emu * emu)2916884e6d60SXin LI x86emuOp_scas_byte(struct x86emu *emu)
2917884e6d60SXin LI {
2918884e6d60SXin LI int8_t val2;
2919884e6d60SXin LI int inc;
2920884e6d60SXin LI
2921884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2922884e6d60SXin LI inc = -1;
2923884e6d60SXin LI else
2924884e6d60SXin LI inc = 1;
2925884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
2926884e6d60SXin LI /* REPE */
2927884e6d60SXin LI /* move them until CX is ZERO. */
2928884e6d60SXin LI while (emu->x86.R_CX != 0) {
2929884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2930884e6d60SXin LI cmp_byte(emu, emu->x86.R_AL, val2);
2931884e6d60SXin LI emu->x86.R_CX -= 1;
2932884e6d60SXin LI emu->x86.R_DI += inc;
2933884e6d60SXin LI if (ACCESS_FLAG(F_ZF) == 0)
2934884e6d60SXin LI break;
2935884e6d60SXin LI }
2936884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
2937884e6d60SXin LI } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
2938884e6d60SXin LI /* REPNE */
2939884e6d60SXin LI /* move them until CX is ZERO. */
2940884e6d60SXin LI while (emu->x86.R_CX != 0) {
2941884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2942884e6d60SXin LI cmp_byte(emu, emu->x86.R_AL, val2);
2943884e6d60SXin LI emu->x86.R_CX -= 1;
2944884e6d60SXin LI emu->x86.R_DI += inc;
2945884e6d60SXin LI if (ACCESS_FLAG(F_ZF))
2946884e6d60SXin LI break; /* zero flag set means equal */
2947884e6d60SXin LI }
2948884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
2949884e6d60SXin LI } else {
2950884e6d60SXin LI val2 = fetch_byte(emu, emu->x86.R_ES, emu->x86.R_DI);
2951884e6d60SXin LI cmp_byte(emu, emu->x86.R_AL, val2);
2952884e6d60SXin LI emu->x86.R_DI += inc;
2953884e6d60SXin LI }
2954884e6d60SXin LI }
2955884e6d60SXin LI
2956884e6d60SXin LI /*
2957884e6d60SXin LI * REMARKS:
2958884e6d60SXin LI * Handles opcode 0xaf
2959884e6d60SXin LI */
2960884e6d60SXin LI static void
x86emuOp_scas_word(struct x86emu * emu)2961884e6d60SXin LI x86emuOp_scas_word(struct x86emu *emu)
2962884e6d60SXin LI {
2963884e6d60SXin LI int inc;
2964884e6d60SXin LI uint32_t val;
2965884e6d60SXin LI
2966884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
2967884e6d60SXin LI inc = 4;
2968884e6d60SXin LI else
2969884e6d60SXin LI inc = 2;
2970884e6d60SXin LI
2971884e6d60SXin LI if (ACCESS_FLAG(F_DF)) /* down */
2972884e6d60SXin LI inc = -inc;
2973884e6d60SXin LI
2974884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_REPE) {
2975884e6d60SXin LI /* REPE */
2976884e6d60SXin LI /* move them until CX is ZERO. */
2977884e6d60SXin LI while (emu->x86.R_CX != 0) {
2978884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
297906325fe0SXin LI val = fetch_long(emu, emu->x86.R_ES,
298006325fe0SXin LI emu->x86.R_DI);
2981884e6d60SXin LI cmp_long(emu, emu->x86.R_EAX, val);
2982884e6d60SXin LI } else {
298306325fe0SXin LI val = fetch_word(emu, emu->x86.R_ES,
298406325fe0SXin LI emu->x86.R_DI);
2985884e6d60SXin LI cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
2986884e6d60SXin LI }
2987884e6d60SXin LI emu->x86.R_CX -= 1;
2988884e6d60SXin LI emu->x86.R_DI += inc;
2989884e6d60SXin LI if (ACCESS_FLAG(F_ZF) == 0)
2990884e6d60SXin LI break;
2991884e6d60SXin LI }
2992884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPE;
2993884e6d60SXin LI } else if (emu->x86.mode & SYSMODE_PREFIX_REPNE) {
2994884e6d60SXin LI /* REPNE */
2995884e6d60SXin LI /* move them until CX is ZERO. */
2996884e6d60SXin LI while (emu->x86.R_CX != 0) {
2997884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
299806325fe0SXin LI val = fetch_long(emu, emu->x86.R_ES,
299906325fe0SXin LI emu->x86.R_DI);
3000884e6d60SXin LI cmp_long(emu, emu->x86.R_EAX, val);
3001884e6d60SXin LI } else {
300206325fe0SXin LI val = fetch_word(emu, emu->x86.R_ES,
300306325fe0SXin LI emu->x86.R_DI);
3004884e6d60SXin LI cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
3005884e6d60SXin LI }
3006884e6d60SXin LI emu->x86.R_CX -= 1;
3007884e6d60SXin LI emu->x86.R_DI += inc;
3008884e6d60SXin LI if (ACCESS_FLAG(F_ZF))
3009884e6d60SXin LI break; /* zero flag set means equal */
3010884e6d60SXin LI }
3011884e6d60SXin LI emu->x86.mode &= ~SYSMODE_PREFIX_REPNE;
3012884e6d60SXin LI } else {
3013884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3014884e6d60SXin LI val = fetch_long(emu, emu->x86.R_ES, emu->x86.R_DI);
3015884e6d60SXin LI cmp_long(emu, emu->x86.R_EAX, val);
3016884e6d60SXin LI } else {
3017884e6d60SXin LI val = fetch_word(emu, emu->x86.R_ES, emu->x86.R_DI);
3018884e6d60SXin LI cmp_word(emu, emu->x86.R_AX, (uint16_t) val);
3019884e6d60SXin LI }
3020884e6d60SXin LI emu->x86.R_DI += inc;
3021884e6d60SXin LI }
3022884e6d60SXin LI }
3023884e6d60SXin LI
3024884e6d60SXin LI /*
3025884e6d60SXin LI * REMARKS:
3026884e6d60SXin LI * Handles opcode 0xb8
3027884e6d60SXin LI */
3028884e6d60SXin LI static void
x86emuOp_mov_word_AX_IMM(struct x86emu * emu)3029884e6d60SXin LI x86emuOp_mov_word_AX_IMM(struct x86emu *emu)
3030884e6d60SXin LI {
3031884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3032884e6d60SXin LI emu->x86.R_EAX = fetch_long_imm(emu);
3033884e6d60SXin LI else
3034884e6d60SXin LI emu->x86.R_AX = fetch_word_imm(emu);
3035884e6d60SXin LI }
3036884e6d60SXin LI
3037884e6d60SXin LI /*
3038884e6d60SXin LI * REMARKS:
3039884e6d60SXin LI * Handles opcode 0xb9
3040884e6d60SXin LI */
3041884e6d60SXin LI static void
x86emuOp_mov_word_CX_IMM(struct x86emu * emu)3042884e6d60SXin LI x86emuOp_mov_word_CX_IMM(struct x86emu *emu)
3043884e6d60SXin LI {
3044884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3045884e6d60SXin LI emu->x86.R_ECX = fetch_long_imm(emu);
3046884e6d60SXin LI else
3047884e6d60SXin LI emu->x86.R_CX = fetch_word_imm(emu);
3048884e6d60SXin LI }
3049884e6d60SXin LI
3050884e6d60SXin LI /*
3051884e6d60SXin LI * REMARKS:
3052884e6d60SXin LI * Handles opcode 0xba
3053884e6d60SXin LI */
3054884e6d60SXin LI static void
x86emuOp_mov_word_DX_IMM(struct x86emu * emu)3055884e6d60SXin LI x86emuOp_mov_word_DX_IMM(struct x86emu *emu)
3056884e6d60SXin LI {
3057884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3058884e6d60SXin LI emu->x86.R_EDX = fetch_long_imm(emu);
3059884e6d60SXin LI else
3060884e6d60SXin LI emu->x86.R_DX = fetch_word_imm(emu);
3061884e6d60SXin LI }
3062884e6d60SXin LI
3063884e6d60SXin LI /*
3064884e6d60SXin LI * REMARKS:
3065884e6d60SXin LI * Handles opcode 0xbb
3066884e6d60SXin LI */
3067884e6d60SXin LI static void
x86emuOp_mov_word_BX_IMM(struct x86emu * emu)3068884e6d60SXin LI x86emuOp_mov_word_BX_IMM(struct x86emu *emu)
3069884e6d60SXin LI {
3070884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3071884e6d60SXin LI emu->x86.R_EBX = fetch_long_imm(emu);
3072884e6d60SXin LI else
3073884e6d60SXin LI emu->x86.R_BX = fetch_word_imm(emu);
3074884e6d60SXin LI }
3075884e6d60SXin LI
3076884e6d60SXin LI /*
3077884e6d60SXin LI * REMARKS:
3078884e6d60SXin LI * Handles opcode 0xbc
3079884e6d60SXin LI */
3080884e6d60SXin LI static void
x86emuOp_mov_word_SP_IMM(struct x86emu * emu)3081884e6d60SXin LI x86emuOp_mov_word_SP_IMM(struct x86emu *emu)
3082884e6d60SXin LI {
3083884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3084884e6d60SXin LI emu->x86.R_ESP = fetch_long_imm(emu);
3085884e6d60SXin LI else
3086884e6d60SXin LI emu->x86.R_SP = fetch_word_imm(emu);
3087884e6d60SXin LI }
3088884e6d60SXin LI
3089884e6d60SXin LI /*
3090884e6d60SXin LI * REMARKS:
3091884e6d60SXin LI * Handles opcode 0xbd
3092884e6d60SXin LI */
3093884e6d60SXin LI static void
x86emuOp_mov_word_BP_IMM(struct x86emu * emu)3094884e6d60SXin LI x86emuOp_mov_word_BP_IMM(struct x86emu *emu)
3095884e6d60SXin LI {
3096884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3097884e6d60SXin LI emu->x86.R_EBP = fetch_long_imm(emu);
3098884e6d60SXin LI else
3099884e6d60SXin LI emu->x86.R_BP = fetch_word_imm(emu);
3100884e6d60SXin LI }
3101884e6d60SXin LI
3102884e6d60SXin LI /*
3103884e6d60SXin LI * REMARKS:
3104884e6d60SXin LI * Handles opcode 0xbe
3105884e6d60SXin LI */
3106884e6d60SXin LI static void
x86emuOp_mov_word_SI_IMM(struct x86emu * emu)3107884e6d60SXin LI x86emuOp_mov_word_SI_IMM(struct x86emu *emu)
3108884e6d60SXin LI {
3109884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3110884e6d60SXin LI emu->x86.R_ESI = fetch_long_imm(emu);
3111884e6d60SXin LI else
3112884e6d60SXin LI emu->x86.R_SI = fetch_word_imm(emu);
3113884e6d60SXin LI }
3114884e6d60SXin LI
3115884e6d60SXin LI /*
3116884e6d60SXin LI * REMARKS:
3117884e6d60SXin LI * Handles opcode 0xbf
3118884e6d60SXin LI */
3119884e6d60SXin LI static void
x86emuOp_mov_word_DI_IMM(struct x86emu * emu)3120884e6d60SXin LI x86emuOp_mov_word_DI_IMM(struct x86emu *emu)
3121884e6d60SXin LI {
3122884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3123884e6d60SXin LI emu->x86.R_EDI = fetch_long_imm(emu);
3124884e6d60SXin LI else
3125884e6d60SXin LI emu->x86.R_DI = fetch_word_imm(emu);
3126884e6d60SXin LI }
3127884e6d60SXin LI /* used by opcodes c0, d0, and d2. */
3128884e6d60SXin LI static
312906325fe0SXin LI uint8_t(* const opcD0_byte_operation[])
313006325fe0SXin LI (struct x86emu *, uint8_t d, uint8_t s) =
3131884e6d60SXin LI {
3132884e6d60SXin LI rol_byte,
3133884e6d60SXin LI ror_byte,
3134884e6d60SXin LI rcl_byte,
3135884e6d60SXin LI rcr_byte,
3136884e6d60SXin LI shl_byte,
3137884e6d60SXin LI shr_byte,
3138884e6d60SXin LI shl_byte, /* sal_byte === shl_byte by definition */
3139884e6d60SXin LI sar_byte,
3140884e6d60SXin LI };
3141884e6d60SXin LI
3142884e6d60SXin LI /*
3143884e6d60SXin LI * REMARKS:
3144884e6d60SXin LI * Handles opcode 0xc0
3145884e6d60SXin LI */
3146884e6d60SXin LI static void
x86emuOp_opcC0_byte_RM_MEM(struct x86emu * emu)3147884e6d60SXin LI x86emuOp_opcC0_byte_RM_MEM(struct x86emu *emu)
3148884e6d60SXin LI {
3149884e6d60SXin LI uint8_t destval, amt;
3150884e6d60SXin LI
3151884e6d60SXin LI /*
3152884e6d60SXin LI * Yet another weirdo special case instruction format. Part of
3153884e6d60SXin LI * the opcode held below in "RH". Doubly nested case would
3154884e6d60SXin LI * result, except that the decoded instruction
3155884e6d60SXin LI */
3156884e6d60SXin LI fetch_decode_modrm(emu);
3157884e6d60SXin LI /* know operation, decode the mod byte to find the addressing mode. */
3158884e6d60SXin LI destval = decode_and_fetch_byte_imm8(emu, &amt);
3159884e6d60SXin LI destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, amt);
3160884e6d60SXin LI write_back_byte(emu, destval);
3161884e6d60SXin LI }
3162884e6d60SXin LI /* used by opcodes c1, d1, and d3. */
3163884e6d60SXin LI static
316406325fe0SXin LI uint16_t(* const opcD1_word_operation[])
316506325fe0SXin LI (struct x86emu *, uint16_t s, uint8_t d) =
3166884e6d60SXin LI {
3167884e6d60SXin LI rol_word,
3168884e6d60SXin LI ror_word,
3169884e6d60SXin LI rcl_word,
3170884e6d60SXin LI rcr_word,
3171884e6d60SXin LI shl_word,
3172884e6d60SXin LI shr_word,
3173884e6d60SXin LI shl_word, /* sal_byte === shl_byte by definition */
3174884e6d60SXin LI sar_word,
3175884e6d60SXin LI };
3176884e6d60SXin LI /* used by opcodes c1, d1, and d3. */
3177884e6d60SXin LI static
317806325fe0SXin LI uint32_t(* const opcD1_long_operation[])
317906325fe0SXin LI (struct x86emu *, uint32_t s, uint8_t d) =
3180884e6d60SXin LI {
3181884e6d60SXin LI rol_long,
3182884e6d60SXin LI ror_long,
3183884e6d60SXin LI rcl_long,
3184884e6d60SXin LI rcr_long,
3185884e6d60SXin LI shl_long,
3186884e6d60SXin LI shr_long,
3187884e6d60SXin LI shl_long, /* sal_byte === shl_byte by definition */
3188884e6d60SXin LI sar_long,
3189884e6d60SXin LI };
3190884e6d60SXin LI
3191884e6d60SXin LI /*
3192884e6d60SXin LI * REMARKS:
3193884e6d60SXin LI * Handles opcode 0xc1
3194884e6d60SXin LI */
3195884e6d60SXin LI static void
x86emuOp_opcC1_word_RM_MEM(struct x86emu * emu)3196884e6d60SXin LI x86emuOp_opcC1_word_RM_MEM(struct x86emu *emu)
3197884e6d60SXin LI {
3198884e6d60SXin LI uint8_t amt;
3199884e6d60SXin LI
3200884e6d60SXin LI /*
3201884e6d60SXin LI * Yet another weirdo special case instruction format. Part of
3202884e6d60SXin LI * the opcode held below in "RH". Doubly nested case would
3203884e6d60SXin LI * result, except that the decoded instruction
3204884e6d60SXin LI */
3205884e6d60SXin LI fetch_decode_modrm(emu);
3206884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3207884e6d60SXin LI uint32_t destval;
3208884e6d60SXin LI
3209884e6d60SXin LI destval = decode_and_fetch_long_imm8(emu, &amt);
321006325fe0SXin LI destval = (*opcD1_long_operation[emu->cur_rh])
321106325fe0SXin LI (emu, destval, amt);
3212884e6d60SXin LI write_back_long(emu, destval);
3213884e6d60SXin LI } else {
3214884e6d60SXin LI uint16_t destval;
3215884e6d60SXin LI
3216884e6d60SXin LI destval = decode_and_fetch_word_imm8(emu, &amt);
321706325fe0SXin LI destval = (*opcD1_word_operation[emu->cur_rh])
321806325fe0SXin LI (emu, destval, amt);
3219884e6d60SXin LI write_back_word(emu, destval);
3220884e6d60SXin LI }
3221884e6d60SXin LI }
3222884e6d60SXin LI
3223884e6d60SXin LI /*
3224884e6d60SXin LI * REMARKS:
3225884e6d60SXin LI * Handles opcode 0xc2
3226884e6d60SXin LI */
3227884e6d60SXin LI static void
x86emuOp_ret_near_IMM(struct x86emu * emu)3228884e6d60SXin LI x86emuOp_ret_near_IMM(struct x86emu *emu)
3229884e6d60SXin LI {
3230884e6d60SXin LI uint16_t imm;
3231884e6d60SXin LI
3232884e6d60SXin LI imm = fetch_word_imm(emu);
3233884e6d60SXin LI emu->x86.R_IP = pop_word(emu);
3234884e6d60SXin LI emu->x86.R_SP += imm;
3235884e6d60SXin LI }
3236884e6d60SXin LI
3237884e6d60SXin LI /*
3238884e6d60SXin LI * REMARKS:
3239884e6d60SXin LI * Handles opcode 0xc6
3240884e6d60SXin LI */
3241884e6d60SXin LI static void
x86emuOp_mov_byte_RM_IMM(struct x86emu * emu)3242884e6d60SXin LI x86emuOp_mov_byte_RM_IMM(struct x86emu *emu)
3243884e6d60SXin LI {
3244884e6d60SXin LI uint8_t *destreg;
3245884e6d60SXin LI uint32_t destoffset;
3246884e6d60SXin LI uint8_t imm;
3247884e6d60SXin LI
3248884e6d60SXin LI fetch_decode_modrm(emu);
3249884e6d60SXin LI if (emu->cur_rh != 0)
3250884e6d60SXin LI x86emu_halt_sys(emu);
3251884e6d60SXin LI if (emu->cur_mod != 3) {
3252884e6d60SXin LI destoffset = decode_rl_address(emu);
3253884e6d60SXin LI imm = fetch_byte_imm(emu);
3254884e6d60SXin LI store_data_byte(emu, destoffset, imm);
3255884e6d60SXin LI } else {
3256884e6d60SXin LI destreg = decode_rl_byte_register(emu);
3257884e6d60SXin LI imm = fetch_byte_imm(emu);
3258884e6d60SXin LI *destreg = imm;
3259884e6d60SXin LI }
3260884e6d60SXin LI }
3261884e6d60SXin LI
3262884e6d60SXin LI /*
3263884e6d60SXin LI * REMARKS:
3264884e6d60SXin LI * Handles opcode 0xc7
3265884e6d60SXin LI */
3266884e6d60SXin LI static void
x86emuOp32_mov_word_RM_IMM(struct x86emu * emu)3267884e6d60SXin LI x86emuOp32_mov_word_RM_IMM(struct x86emu *emu)
3268884e6d60SXin LI {
3269884e6d60SXin LI uint32_t destoffset;
3270884e6d60SXin LI uint32_t imm, *destreg;
3271884e6d60SXin LI
3272884e6d60SXin LI fetch_decode_modrm(emu);
3273884e6d60SXin LI if (emu->cur_rh != 0)
3274884e6d60SXin LI x86emu_halt_sys(emu);
3275884e6d60SXin LI
3276884e6d60SXin LI if (emu->cur_mod != 3) {
3277884e6d60SXin LI destoffset = decode_rl_address(emu);
3278884e6d60SXin LI imm = fetch_long_imm(emu);
3279884e6d60SXin LI store_data_long(emu, destoffset, imm);
3280884e6d60SXin LI } else {
3281884e6d60SXin LI destreg = decode_rl_long_register(emu);
3282884e6d60SXin LI imm = fetch_long_imm(emu);
3283884e6d60SXin LI *destreg = imm;
3284884e6d60SXin LI }
3285884e6d60SXin LI }
3286884e6d60SXin LI
3287884e6d60SXin LI static void
x86emuOp16_mov_word_RM_IMM(struct x86emu * emu)3288884e6d60SXin LI x86emuOp16_mov_word_RM_IMM(struct x86emu *emu)
3289884e6d60SXin LI {
3290884e6d60SXin LI uint32_t destoffset;
3291884e6d60SXin LI uint16_t imm, *destreg;
3292884e6d60SXin LI
3293884e6d60SXin LI fetch_decode_modrm(emu);
3294884e6d60SXin LI if (emu->cur_rh != 0)
3295884e6d60SXin LI x86emu_halt_sys(emu);
3296884e6d60SXin LI
3297884e6d60SXin LI if (emu->cur_mod != 3) {
3298884e6d60SXin LI destoffset = decode_rl_address(emu);
3299884e6d60SXin LI imm = fetch_word_imm(emu);
3300884e6d60SXin LI store_data_word(emu, destoffset, imm);
3301884e6d60SXin LI } else {
3302884e6d60SXin LI destreg = decode_rl_word_register(emu);
3303884e6d60SXin LI imm = fetch_word_imm(emu);
3304884e6d60SXin LI *destreg = imm;
3305884e6d60SXin LI }
3306884e6d60SXin LI }
3307884e6d60SXin LI
3308884e6d60SXin LI static void
x86emuOp_mov_word_RM_IMM(struct x86emu * emu)3309884e6d60SXin LI x86emuOp_mov_word_RM_IMM(struct x86emu *emu)
3310884e6d60SXin LI {
3311884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
3312884e6d60SXin LI x86emuOp32_mov_word_RM_IMM(emu);
3313884e6d60SXin LI else
3314884e6d60SXin LI x86emuOp16_mov_word_RM_IMM(emu);
3315884e6d60SXin LI }
3316884e6d60SXin LI
3317884e6d60SXin LI /*
3318884e6d60SXin LI * REMARKS:
3319884e6d60SXin LI * Handles opcode 0xc8
3320884e6d60SXin LI */
3321884e6d60SXin LI static void
x86emuOp_enter(struct x86emu * emu)3322884e6d60SXin LI x86emuOp_enter(struct x86emu *emu)
3323884e6d60SXin LI {
3324884e6d60SXin LI uint16_t local, frame_pointer;
3325884e6d60SXin LI uint8_t nesting;
3326884e6d60SXin LI int i;
3327884e6d60SXin LI
3328884e6d60SXin LI local = fetch_word_imm(emu);
3329884e6d60SXin LI nesting = fetch_byte_imm(emu);
3330884e6d60SXin LI push_word(emu, emu->x86.R_BP);
3331884e6d60SXin LI frame_pointer = emu->x86.R_SP;
3332884e6d60SXin LI if (nesting > 0) {
3333884e6d60SXin LI for (i = 1; i < nesting; i++) {
3334884e6d60SXin LI emu->x86.R_BP -= 2;
333506325fe0SXin LI push_word(emu, fetch_word(emu, emu->x86.R_SS,
333606325fe0SXin LI emu->x86.R_BP));
3337884e6d60SXin LI }
3338884e6d60SXin LI push_word(emu, frame_pointer);
3339884e6d60SXin LI }
3340884e6d60SXin LI emu->x86.R_BP = frame_pointer;
3341884e6d60SXin LI emu->x86.R_SP = (uint16_t) (emu->x86.R_SP - local);
3342884e6d60SXin LI }
3343884e6d60SXin LI
3344884e6d60SXin LI /*
3345884e6d60SXin LI * REMARKS:
3346884e6d60SXin LI * Handles opcode 0xc9
3347884e6d60SXin LI */
3348884e6d60SXin LI static void
x86emuOp_leave(struct x86emu * emu)3349884e6d60SXin LI x86emuOp_leave(struct x86emu *emu)
3350884e6d60SXin LI {
3351884e6d60SXin LI emu->x86.R_SP = emu->x86.R_BP;
3352884e6d60SXin LI emu->x86.R_BP = pop_word(emu);
3353884e6d60SXin LI }
3354884e6d60SXin LI
3355884e6d60SXin LI /*
3356884e6d60SXin LI * REMARKS:
3357884e6d60SXin LI * Handles opcode 0xca
3358884e6d60SXin LI */
3359884e6d60SXin LI static void
x86emuOp_ret_far_IMM(struct x86emu * emu)3360884e6d60SXin LI x86emuOp_ret_far_IMM(struct x86emu *emu)
3361884e6d60SXin LI {
3362884e6d60SXin LI uint16_t imm;
3363884e6d60SXin LI
3364884e6d60SXin LI imm = fetch_word_imm(emu);
3365884e6d60SXin LI emu->x86.R_IP = pop_word(emu);
3366884e6d60SXin LI emu->x86.R_CS = pop_word(emu);
3367884e6d60SXin LI emu->x86.R_SP += imm;
3368884e6d60SXin LI }
3369884e6d60SXin LI
3370884e6d60SXin LI /*
3371884e6d60SXin LI * REMARKS:
3372884e6d60SXin LI * Handles opcode 0xcb
3373884e6d60SXin LI */
3374884e6d60SXin LI static void
x86emuOp_ret_far(struct x86emu * emu)3375884e6d60SXin LI x86emuOp_ret_far(struct x86emu *emu)
3376884e6d60SXin LI {
3377884e6d60SXin LI emu->x86.R_IP = pop_word(emu);
3378884e6d60SXin LI emu->x86.R_CS = pop_word(emu);
3379884e6d60SXin LI }
3380884e6d60SXin LI
3381884e6d60SXin LI /*
3382884e6d60SXin LI * REMARKS:
3383884e6d60SXin LI * Handles opcode 0xcc
3384884e6d60SXin LI */
3385884e6d60SXin LI static void
x86emuOp_int3(struct x86emu * emu)3386884e6d60SXin LI x86emuOp_int3(struct x86emu *emu)
3387884e6d60SXin LI {
3388884e6d60SXin LI x86emu_intr_dispatch(emu, 3);
3389884e6d60SXin LI }
3390884e6d60SXin LI
3391884e6d60SXin LI /*
3392884e6d60SXin LI * REMARKS:
3393884e6d60SXin LI * Handles opcode 0xcd
3394884e6d60SXin LI */
3395884e6d60SXin LI static void
x86emuOp_int_IMM(struct x86emu * emu)3396884e6d60SXin LI x86emuOp_int_IMM(struct x86emu *emu)
3397884e6d60SXin LI {
3398884e6d60SXin LI uint8_t intnum;
3399884e6d60SXin LI
3400884e6d60SXin LI intnum = fetch_byte_imm(emu);
3401884e6d60SXin LI x86emu_intr_dispatch(emu, intnum);
3402884e6d60SXin LI }
3403884e6d60SXin LI
3404884e6d60SXin LI /*
3405884e6d60SXin LI * REMARKS:
3406884e6d60SXin LI * Handles opcode 0xce
3407884e6d60SXin LI */
3408884e6d60SXin LI static void
x86emuOp_into(struct x86emu * emu)3409884e6d60SXin LI x86emuOp_into(struct x86emu *emu)
3410884e6d60SXin LI {
3411884e6d60SXin LI if (ACCESS_FLAG(F_OF))
3412884e6d60SXin LI x86emu_intr_dispatch(emu, 4);
3413884e6d60SXin LI }
3414884e6d60SXin LI
3415884e6d60SXin LI /*
3416884e6d60SXin LI * REMARKS:
3417884e6d60SXin LI * Handles opcode 0xcf
3418884e6d60SXin LI */
3419884e6d60SXin LI static void
x86emuOp_iret(struct x86emu * emu)3420884e6d60SXin LI x86emuOp_iret(struct x86emu *emu)
3421884e6d60SXin LI {
3422884e6d60SXin LI emu->x86.R_IP = pop_word(emu);
3423884e6d60SXin LI emu->x86.R_CS = pop_word(emu);
3424884e6d60SXin LI emu->x86.R_FLG = pop_word(emu);
3425884e6d60SXin LI }
3426884e6d60SXin LI
3427884e6d60SXin LI /*
3428884e6d60SXin LI * REMARKS:
3429884e6d60SXin LI * Handles opcode 0xd0
3430884e6d60SXin LI */
3431884e6d60SXin LI static void
x86emuOp_opcD0_byte_RM_1(struct x86emu * emu)3432884e6d60SXin LI x86emuOp_opcD0_byte_RM_1(struct x86emu *emu)
3433884e6d60SXin LI {
3434884e6d60SXin LI uint8_t destval;
3435884e6d60SXin LI
3436884e6d60SXin LI fetch_decode_modrm(emu);
3437884e6d60SXin LI destval = decode_and_fetch_byte(emu);
3438884e6d60SXin LI destval = (*opcD0_byte_operation[emu->cur_rh]) (emu, destval, 1);
3439884e6d60SXin LI write_back_byte(emu, destval);
3440884e6d60SXin LI }
3441884e6d60SXin LI
3442884e6d60SXin LI /*
3443884e6d60SXin LI * REMARKS:
3444884e6d60SXin LI * Handles opcode 0xd1
3445884e6d60SXin LI */
3446884e6d60SXin LI static void
x86emuOp_opcD1_word_RM_1(struct x86emu * emu)3447884e6d60SXin LI x86emuOp_opcD1_word_RM_1(struct x86emu *emu)
3448884e6d60SXin LI {
3449884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3450884e6d60SXin LI uint32_t destval;
3451884e6d60SXin LI
3452884e6d60SXin LI fetch_decode_modrm(emu);
3453884e6d60SXin LI destval = decode_and_fetch_long(emu);
3454884e6d60SXin LI destval = (*opcD1_long_operation[emu->cur_rh])(emu, destval, 1);
3455884e6d60SXin LI write_back_long(emu, destval);
3456884e6d60SXin LI } else {
3457884e6d60SXin LI uint16_t destval;
3458884e6d60SXin LI
3459884e6d60SXin LI fetch_decode_modrm(emu);
3460884e6d60SXin LI destval = decode_and_fetch_word(emu);
3461884e6d60SXin LI destval = (*opcD1_word_operation[emu->cur_rh])(emu, destval, 1);
3462884e6d60SXin LI write_back_word(emu, destval);
3463884e6d60SXin LI }
3464884e6d60SXin LI }
3465884e6d60SXin LI
3466884e6d60SXin LI /*
3467884e6d60SXin LI * REMARKS:
3468884e6d60SXin LI * Handles opcode 0xd2
3469884e6d60SXin LI */
3470884e6d60SXin LI static void
x86emuOp_opcD2_byte_RM_CL(struct x86emu * emu)3471884e6d60SXin LI x86emuOp_opcD2_byte_RM_CL(struct x86emu *emu)
3472884e6d60SXin LI {
3473884e6d60SXin LI uint8_t destval;
3474884e6d60SXin LI
3475884e6d60SXin LI fetch_decode_modrm(emu);
3476884e6d60SXin LI destval = decode_and_fetch_byte(emu);
347706325fe0SXin LI destval = (*opcD0_byte_operation[emu->cur_rh])
347806325fe0SXin LI (emu, destval, emu->x86.R_CL);
3479884e6d60SXin LI write_back_byte(emu, destval);
3480884e6d60SXin LI }
3481884e6d60SXin LI
3482884e6d60SXin LI /*
3483884e6d60SXin LI * REMARKS:
3484884e6d60SXin LI * Handles opcode 0xd3
3485884e6d60SXin LI */
3486884e6d60SXin LI static void
x86emuOp_opcD3_word_RM_CL(struct x86emu * emu)3487884e6d60SXin LI x86emuOp_opcD3_word_RM_CL(struct x86emu *emu)
3488884e6d60SXin LI {
3489884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3490884e6d60SXin LI uint32_t destval;
3491884e6d60SXin LI
3492884e6d60SXin LI fetch_decode_modrm(emu);
3493884e6d60SXin LI destval = decode_and_fetch_long(emu);
349406325fe0SXin LI destval = (*opcD1_long_operation[emu->cur_rh])
349506325fe0SXin LI (emu, destval, emu->x86.R_CL);
3496884e6d60SXin LI write_back_long(emu, destval);
3497884e6d60SXin LI } else {
3498884e6d60SXin LI uint16_t destval;
3499884e6d60SXin LI
3500884e6d60SXin LI fetch_decode_modrm(emu);
3501884e6d60SXin LI destval = decode_and_fetch_word(emu);
350206325fe0SXin LI destval = (*opcD1_word_operation[emu->cur_rh])
350306325fe0SXin LI (emu, destval, emu->x86.R_CL);
3504884e6d60SXin LI write_back_word(emu, destval);
3505884e6d60SXin LI }
3506884e6d60SXin LI }
3507884e6d60SXin LI
3508884e6d60SXin LI /*
3509884e6d60SXin LI * REMARKS:
3510884e6d60SXin LI * Handles opcode 0xd4
3511884e6d60SXin LI */
3512884e6d60SXin LI static void
x86emuOp_aam(struct x86emu * emu)3513884e6d60SXin LI x86emuOp_aam(struct x86emu *emu)
3514884e6d60SXin LI {
3515884e6d60SXin LI uint8_t a;
3516884e6d60SXin LI
3517884e6d60SXin LI a = fetch_byte_imm(emu); /* this is a stupid encoding. */
3518884e6d60SXin LI if (a != 10) {
3519884e6d60SXin LI /* fix: add base decoding aam_word(uint8_t val, int base a) */
3520884e6d60SXin LI x86emu_halt_sys(emu);
3521884e6d60SXin LI }
3522884e6d60SXin LI /* note the type change here --- returning AL and AH in AX. */
3523884e6d60SXin LI emu->x86.R_AX = aam_word(emu, emu->x86.R_AL);
3524884e6d60SXin LI }
3525884e6d60SXin LI
3526884e6d60SXin LI /*
3527884e6d60SXin LI * REMARKS:
3528884e6d60SXin LI * Handles opcode 0xd5
3529884e6d60SXin LI */
3530884e6d60SXin LI static void
x86emuOp_aad(struct x86emu * emu)3531884e6d60SXin LI x86emuOp_aad(struct x86emu *emu)
3532884e6d60SXin LI {
3533884e6d60SXin LI uint8_t a;
3534884e6d60SXin LI
3535884e6d60SXin LI a = fetch_byte_imm(emu);
3536884e6d60SXin LI if (a != 10) {
3537884e6d60SXin LI /* fix: add base decoding aad_word(uint16_t val, int base a) */
3538884e6d60SXin LI x86emu_halt_sys(emu);
3539884e6d60SXin LI }
3540884e6d60SXin LI emu->x86.R_AX = aad_word(emu, emu->x86.R_AX);
3541884e6d60SXin LI }
3542884e6d60SXin LI /* opcode 0xd6 ILLEGAL OPCODE */
3543884e6d60SXin LI
3544884e6d60SXin LI
3545884e6d60SXin LI /*
3546884e6d60SXin LI * REMARKS:
3547884e6d60SXin LI * Handles opcode 0xd7
3548884e6d60SXin LI */
3549884e6d60SXin LI static void
x86emuOp_xlat(struct x86emu * emu)3550884e6d60SXin LI x86emuOp_xlat(struct x86emu *emu)
3551884e6d60SXin LI {
3552884e6d60SXin LI uint16_t addr;
3553884e6d60SXin LI
3554884e6d60SXin LI addr = (uint16_t) (emu->x86.R_BX + (uint8_t) emu->x86.R_AL);
3555884e6d60SXin LI emu->x86.R_AL = fetch_data_byte(emu, addr);
3556884e6d60SXin LI }
3557884e6d60SXin LI
3558884e6d60SXin LI /* opcode=0xd8 */
3559884e6d60SXin LI static void
x86emuOp_esc_coprocess_d8(struct x86emu * emu)3560884e6d60SXin LI x86emuOp_esc_coprocess_d8(struct x86emu *emu)
3561884e6d60SXin LI {
3562884e6d60SXin LI }
3563884e6d60SXin LI /* opcode=0xd9 */
3564884e6d60SXin LI static void
x86emuOp_esc_coprocess_d9(struct x86emu * emu)3565884e6d60SXin LI x86emuOp_esc_coprocess_d9(struct x86emu *emu)
3566884e6d60SXin LI {
3567884e6d60SXin LI fetch_decode_modrm(emu);
3568884e6d60SXin LI if (emu->cur_mod != 3)
3569884e6d60SXin LI decode_rl_address(emu);
3570884e6d60SXin LI }
3571884e6d60SXin LI /* opcode=0xda */
3572884e6d60SXin LI static void
x86emuOp_esc_coprocess_da(struct x86emu * emu)3573884e6d60SXin LI x86emuOp_esc_coprocess_da(struct x86emu *emu)
3574884e6d60SXin LI {
3575884e6d60SXin LI fetch_decode_modrm(emu);
3576884e6d60SXin LI if (emu->cur_mod != 3)
3577884e6d60SXin LI decode_rl_address(emu);
3578884e6d60SXin LI }
3579884e6d60SXin LI /* opcode=0xdb */
3580884e6d60SXin LI static void
x86emuOp_esc_coprocess_db(struct x86emu * emu)3581884e6d60SXin LI x86emuOp_esc_coprocess_db(struct x86emu *emu)
3582884e6d60SXin LI {
3583884e6d60SXin LI fetch_decode_modrm(emu);
3584884e6d60SXin LI if (emu->cur_mod != 3)
3585884e6d60SXin LI decode_rl_address(emu);
3586884e6d60SXin LI }
3587884e6d60SXin LI /* opcode=0xdc */
3588884e6d60SXin LI static void
x86emuOp_esc_coprocess_dc(struct x86emu * emu)3589884e6d60SXin LI x86emuOp_esc_coprocess_dc(struct x86emu *emu)
3590884e6d60SXin LI {
3591884e6d60SXin LI fetch_decode_modrm(emu);
3592884e6d60SXin LI if (emu->cur_mod != 3)
3593884e6d60SXin LI decode_rl_address(emu);
3594884e6d60SXin LI }
3595884e6d60SXin LI /* opcode=0xdd */
3596884e6d60SXin LI static void
x86emuOp_esc_coprocess_dd(struct x86emu * emu)3597884e6d60SXin LI x86emuOp_esc_coprocess_dd(struct x86emu *emu)
3598884e6d60SXin LI {
3599884e6d60SXin LI fetch_decode_modrm(emu);
3600884e6d60SXin LI if (emu->cur_mod != 3)
3601884e6d60SXin LI decode_rl_address(emu);
3602884e6d60SXin LI }
3603884e6d60SXin LI /* opcode=0xde */
3604884e6d60SXin LI static void
x86emuOp_esc_coprocess_de(struct x86emu * emu)3605884e6d60SXin LI x86emuOp_esc_coprocess_de(struct x86emu *emu)
3606884e6d60SXin LI {
3607884e6d60SXin LI fetch_decode_modrm(emu);
3608884e6d60SXin LI if (emu->cur_mod != 3)
3609884e6d60SXin LI decode_rl_address(emu);
3610884e6d60SXin LI }
3611884e6d60SXin LI /* opcode=0xdf */
3612884e6d60SXin LI static void
x86emuOp_esc_coprocess_df(struct x86emu * emu)3613884e6d60SXin LI x86emuOp_esc_coprocess_df(struct x86emu *emu)
3614884e6d60SXin LI {
3615884e6d60SXin LI fetch_decode_modrm(emu);
3616884e6d60SXin LI if (emu->cur_mod != 3)
3617884e6d60SXin LI decode_rl_address(emu);
3618884e6d60SXin LI }
3619884e6d60SXin LI
3620884e6d60SXin LI
3621884e6d60SXin LI /*
3622884e6d60SXin LI * REMARKS:
3623884e6d60SXin LI * Handles opcode 0xe0
3624884e6d60SXin LI */
3625884e6d60SXin LI static void
x86emuOp_loopne(struct x86emu * emu)3626884e6d60SXin LI x86emuOp_loopne(struct x86emu *emu)
3627884e6d60SXin LI {
3628884e6d60SXin LI int16_t ip;
3629884e6d60SXin LI
3630884e6d60SXin LI ip = (int8_t) fetch_byte_imm(emu);
3631884e6d60SXin LI ip += (int16_t) emu->x86.R_IP;
3632884e6d60SXin LI emu->x86.R_CX -= 1;
3633884e6d60SXin LI if (emu->x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */
3634884e6d60SXin LI emu->x86.R_IP = ip;
3635884e6d60SXin LI }
3636884e6d60SXin LI
3637884e6d60SXin LI /*
3638884e6d60SXin LI * REMARKS:
3639884e6d60SXin LI * Handles opcode 0xe1
3640884e6d60SXin LI */
3641884e6d60SXin LI static void
x86emuOp_loope(struct x86emu * emu)3642884e6d60SXin LI x86emuOp_loope(struct x86emu *emu)
3643884e6d60SXin LI {
3644884e6d60SXin LI int16_t ip;
3645884e6d60SXin LI
3646884e6d60SXin LI ip = (int8_t) fetch_byte_imm(emu);
3647884e6d60SXin LI ip += (int16_t) emu->x86.R_IP;
3648884e6d60SXin LI emu->x86.R_CX -= 1;
3649884e6d60SXin LI if (emu->x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */
3650884e6d60SXin LI emu->x86.R_IP = ip;
3651884e6d60SXin LI }
3652884e6d60SXin LI
3653884e6d60SXin LI /*
3654884e6d60SXin LI * REMARKS:
3655884e6d60SXin LI * Handles opcode 0xe2
3656884e6d60SXin LI */
3657884e6d60SXin LI static void
x86emuOp_loop(struct x86emu * emu)3658884e6d60SXin LI x86emuOp_loop(struct x86emu *emu)
3659884e6d60SXin LI {
3660884e6d60SXin LI int16_t ip;
3661884e6d60SXin LI
3662884e6d60SXin LI ip = (int8_t) fetch_byte_imm(emu);
3663884e6d60SXin LI ip += (int16_t) emu->x86.R_IP;
3664884e6d60SXin LI emu->x86.R_CX -= 1;
3665884e6d60SXin LI if (emu->x86.R_CX != 0)
3666884e6d60SXin LI emu->x86.R_IP = ip;
3667884e6d60SXin LI }
3668884e6d60SXin LI
3669884e6d60SXin LI /*
3670884e6d60SXin LI * REMARKS:
3671884e6d60SXin LI * Handles opcode 0xe3
3672884e6d60SXin LI */
3673884e6d60SXin LI static void
x86emuOp_jcxz(struct x86emu * emu)3674884e6d60SXin LI x86emuOp_jcxz(struct x86emu *emu)
3675884e6d60SXin LI {
3676884e6d60SXin LI uint16_t target;
3677884e6d60SXin LI int8_t offset;
3678884e6d60SXin LI
3679884e6d60SXin LI /* jump to byte offset if overflow flag is set */
3680884e6d60SXin LI offset = (int8_t) fetch_byte_imm(emu);
3681884e6d60SXin LI target = (uint16_t) (emu->x86.R_IP + offset);
3682884e6d60SXin LI if (emu->x86.R_CX == 0)
3683884e6d60SXin LI emu->x86.R_IP = target;
3684884e6d60SXin LI }
3685884e6d60SXin LI
3686884e6d60SXin LI /*
3687884e6d60SXin LI * REMARKS:
3688884e6d60SXin LI * Handles opcode 0xe4
3689884e6d60SXin LI */
3690884e6d60SXin LI static void
x86emuOp_in_byte_AL_IMM(struct x86emu * emu)3691884e6d60SXin LI x86emuOp_in_byte_AL_IMM(struct x86emu *emu)
3692884e6d60SXin LI {
3693884e6d60SXin LI uint8_t port;
3694884e6d60SXin LI
3695884e6d60SXin LI port = (uint8_t) fetch_byte_imm(emu);
3696884e6d60SXin LI emu->x86.R_AL = (*emu->emu_inb) (emu, port);
3697884e6d60SXin LI }
3698884e6d60SXin LI
3699884e6d60SXin LI /*
3700884e6d60SXin LI * REMARKS:
3701884e6d60SXin LI * Handles opcode 0xe5
3702884e6d60SXin LI */
3703884e6d60SXin LI static void
x86emuOp_in_word_AX_IMM(struct x86emu * emu)3704884e6d60SXin LI x86emuOp_in_word_AX_IMM(struct x86emu *emu)
3705884e6d60SXin LI {
3706884e6d60SXin LI uint8_t port;
3707884e6d60SXin LI
3708884e6d60SXin LI port = (uint8_t) fetch_byte_imm(emu);
3709884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3710884e6d60SXin LI emu->x86.R_EAX = (*emu->emu_inl) (emu, port);
3711884e6d60SXin LI } else {
3712884e6d60SXin LI emu->x86.R_AX = (*emu->emu_inw) (emu, port);
3713884e6d60SXin LI }
3714884e6d60SXin LI }
3715884e6d60SXin LI
3716884e6d60SXin LI /*
3717884e6d60SXin LI * REMARKS:
3718884e6d60SXin LI * Handles opcode 0xe6
3719884e6d60SXin LI */
3720884e6d60SXin LI static void
x86emuOp_out_byte_IMM_AL(struct x86emu * emu)3721884e6d60SXin LI x86emuOp_out_byte_IMM_AL(struct x86emu *emu)
3722884e6d60SXin LI {
3723884e6d60SXin LI uint8_t port;
3724884e6d60SXin LI
3725884e6d60SXin LI port = (uint8_t) fetch_byte_imm(emu);
3726884e6d60SXin LI (*emu->emu_outb) (emu, port, emu->x86.R_AL);
3727884e6d60SXin LI }
3728884e6d60SXin LI
3729884e6d60SXin LI /*
3730884e6d60SXin LI * REMARKS:
3731884e6d60SXin LI * Handles opcode 0xe7
3732884e6d60SXin LI */
3733884e6d60SXin LI static void
x86emuOp_out_word_IMM_AX(struct x86emu * emu)3734884e6d60SXin LI x86emuOp_out_word_IMM_AX(struct x86emu *emu)
3735884e6d60SXin LI {
3736884e6d60SXin LI uint8_t port;
3737884e6d60SXin LI
3738884e6d60SXin LI port = (uint8_t) fetch_byte_imm(emu);
3739884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3740884e6d60SXin LI (*emu->emu_outl) (emu, port, emu->x86.R_EAX);
3741884e6d60SXin LI } else {
3742884e6d60SXin LI (*emu->emu_outw) (emu, port, emu->x86.R_AX);
3743884e6d60SXin LI }
3744884e6d60SXin LI }
3745884e6d60SXin LI
3746884e6d60SXin LI /*
3747884e6d60SXin LI * REMARKS:
3748884e6d60SXin LI * Handles opcode 0xe8
3749884e6d60SXin LI */
3750884e6d60SXin LI static void
x86emuOp_call_near_IMM(struct x86emu * emu)3751884e6d60SXin LI x86emuOp_call_near_IMM(struct x86emu *emu)
3752884e6d60SXin LI {
375391342c66SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
375491342c66SXin LI int32_t ip;
375591342c66SXin LI ip = (int32_t) fetch_long_imm(emu);
375691342c66SXin LI ip += (int32_t) emu->x86.R_EIP;
375791342c66SXin LI push_long(emu, emu->x86.R_EIP);
375891342c66SXin LI emu->x86.R_EIP = ip;
375991342c66SXin LI } else {
3760884e6d60SXin LI int16_t ip;
3761884e6d60SXin LI ip = (int16_t) fetch_word_imm(emu);
3762884e6d60SXin LI ip += (int16_t) emu->x86.R_IP; /* CHECK SIGN */
3763884e6d60SXin LI push_word(emu, emu->x86.R_IP);
3764884e6d60SXin LI emu->x86.R_IP = ip;
3765884e6d60SXin LI }
376691342c66SXin LI }
3767884e6d60SXin LI
3768884e6d60SXin LI /*
3769884e6d60SXin LI * REMARKS:
3770884e6d60SXin LI * Handles opcode 0xe9
3771884e6d60SXin LI */
3772884e6d60SXin LI static void
x86emuOp_jump_near_IMM(struct x86emu * emu)3773884e6d60SXin LI x86emuOp_jump_near_IMM(struct x86emu *emu)
3774884e6d60SXin LI {
3775884e6d60SXin LI int ip;
3776884e6d60SXin LI
3777884e6d60SXin LI ip = (int16_t) fetch_word_imm(emu);
3778884e6d60SXin LI ip += (int16_t) emu->x86.R_IP;
3779884e6d60SXin LI emu->x86.R_IP = (uint16_t) ip;
3780884e6d60SXin LI }
3781884e6d60SXin LI
3782884e6d60SXin LI /*
3783884e6d60SXin LI * REMARKS:
3784884e6d60SXin LI * Handles opcode 0xea
3785884e6d60SXin LI */
3786884e6d60SXin LI static void
x86emuOp_jump_far_IMM(struct x86emu * emu)3787884e6d60SXin LI x86emuOp_jump_far_IMM(struct x86emu *emu)
3788884e6d60SXin LI {
3789884e6d60SXin LI uint16_t cs, ip;
3790884e6d60SXin LI
3791884e6d60SXin LI ip = fetch_word_imm(emu);
3792884e6d60SXin LI cs = fetch_word_imm(emu);
3793884e6d60SXin LI emu->x86.R_IP = ip;
3794884e6d60SXin LI emu->x86.R_CS = cs;
3795884e6d60SXin LI }
3796884e6d60SXin LI
3797884e6d60SXin LI /*
3798884e6d60SXin LI * REMARKS:
3799884e6d60SXin LI * Handles opcode 0xeb
3800884e6d60SXin LI */
3801884e6d60SXin LI static void
x86emuOp_jump_byte_IMM(struct x86emu * emu)3802884e6d60SXin LI x86emuOp_jump_byte_IMM(struct x86emu *emu)
3803884e6d60SXin LI {
3804884e6d60SXin LI uint16_t target;
3805884e6d60SXin LI int8_t offset;
3806884e6d60SXin LI
3807884e6d60SXin LI offset = (int8_t) fetch_byte_imm(emu);
3808884e6d60SXin LI target = (uint16_t) (emu->x86.R_IP + offset);
3809884e6d60SXin LI emu->x86.R_IP = target;
3810884e6d60SXin LI }
3811884e6d60SXin LI
3812884e6d60SXin LI /*
3813884e6d60SXin LI * REMARKS:
3814884e6d60SXin LI * Handles opcode 0xec
3815884e6d60SXin LI */
3816884e6d60SXin LI static void
x86emuOp_in_byte_AL_DX(struct x86emu * emu)3817884e6d60SXin LI x86emuOp_in_byte_AL_DX(struct x86emu *emu)
3818884e6d60SXin LI {
3819884e6d60SXin LI emu->x86.R_AL = (*emu->emu_inb) (emu, emu->x86.R_DX);
3820884e6d60SXin LI }
3821884e6d60SXin LI
3822884e6d60SXin LI /*
3823884e6d60SXin LI * REMARKS:
3824884e6d60SXin LI * Handles opcode 0xed
3825884e6d60SXin LI */
3826884e6d60SXin LI static void
x86emuOp_in_word_AX_DX(struct x86emu * emu)3827884e6d60SXin LI x86emuOp_in_word_AX_DX(struct x86emu *emu)
3828884e6d60SXin LI {
3829884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3830884e6d60SXin LI emu->x86.R_EAX = (*emu->emu_inl) (emu, emu->x86.R_DX);
3831884e6d60SXin LI } else {
3832884e6d60SXin LI emu->x86.R_AX = (*emu->emu_inw) (emu, emu->x86.R_DX);
3833884e6d60SXin LI }
3834884e6d60SXin LI }
3835884e6d60SXin LI
3836884e6d60SXin LI /*
3837884e6d60SXin LI * REMARKS:
3838884e6d60SXin LI * Handles opcode 0xee
3839884e6d60SXin LI */
3840884e6d60SXin LI static void
x86emuOp_out_byte_DX_AL(struct x86emu * emu)3841884e6d60SXin LI x86emuOp_out_byte_DX_AL(struct x86emu *emu)
3842884e6d60SXin LI {
3843884e6d60SXin LI (*emu->emu_outb) (emu, emu->x86.R_DX, emu->x86.R_AL);
3844884e6d60SXin LI }
3845884e6d60SXin LI
3846884e6d60SXin LI /*
3847884e6d60SXin LI * REMARKS:
3848884e6d60SXin LI * Handles opcode 0xef
3849884e6d60SXin LI */
3850884e6d60SXin LI static void
x86emuOp_out_word_DX_AX(struct x86emu * emu)3851884e6d60SXin LI x86emuOp_out_word_DX_AX(struct x86emu *emu)
3852884e6d60SXin LI {
3853884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
3854884e6d60SXin LI (*emu->emu_outl) (emu, emu->x86.R_DX, emu->x86.R_EAX);
3855884e6d60SXin LI } else {
3856884e6d60SXin LI (*emu->emu_outw) (emu, emu->x86.R_DX, emu->x86.R_AX);
3857884e6d60SXin LI }
3858884e6d60SXin LI }
3859884e6d60SXin LI
3860884e6d60SXin LI /*
3861884e6d60SXin LI * REMARKS:
3862884e6d60SXin LI * Handles opcode 0xf0
3863884e6d60SXin LI */
3864884e6d60SXin LI static void
x86emuOp_lock(struct x86emu * emu)3865884e6d60SXin LI x86emuOp_lock(struct x86emu *emu)
3866884e6d60SXin LI {
3867884e6d60SXin LI }
3868884e6d60SXin LI /*opcode 0xf1 ILLEGAL OPERATION */
3869884e6d60SXin LI
3870884e6d60SXin LI
3871884e6d60SXin LI /*
3872884e6d60SXin LI * REMARKS:
3873884e6d60SXin LI * Handles opcode 0xf5
3874884e6d60SXin LI */
3875884e6d60SXin LI static void
x86emuOp_cmc(struct x86emu * emu)3876884e6d60SXin LI x86emuOp_cmc(struct x86emu *emu)
3877884e6d60SXin LI {
3878884e6d60SXin LI if (ACCESS_FLAG(F_CF))
3879884e6d60SXin LI CLEAR_FLAG(F_CF);
3880884e6d60SXin LI else
3881884e6d60SXin LI SET_FLAG(F_CF);
3882884e6d60SXin LI }
3883884e6d60SXin LI
3884884e6d60SXin LI /*
3885884e6d60SXin LI * REMARKS:
3886884e6d60SXin LI * Handles opcode 0xf6
3887884e6d60SXin LI */
3888884e6d60SXin LI static void
x86emuOp_opcF6_byte_RM(struct x86emu * emu)3889884e6d60SXin LI x86emuOp_opcF6_byte_RM(struct x86emu *emu)
3890884e6d60SXin LI {
3891884e6d60SXin LI uint8_t destval, srcval;
3892884e6d60SXin LI
3893884e6d60SXin LI /* long, drawn out code follows. Double switch for a total of 32
3894884e6d60SXin LI * cases. */
3895884e6d60SXin LI fetch_decode_modrm(emu);
3896884e6d60SXin LI if (emu->cur_rh == 1)
3897884e6d60SXin LI x86emu_halt_sys(emu);
3898884e6d60SXin LI
3899884e6d60SXin LI if (emu->cur_rh == 0) {
3900884e6d60SXin LI destval = decode_and_fetch_byte_imm8(emu, &srcval);
3901884e6d60SXin LI test_byte(emu, destval, srcval);
3902884e6d60SXin LI return;
3903884e6d60SXin LI }
3904884e6d60SXin LI destval = decode_and_fetch_byte(emu);
3905884e6d60SXin LI switch (emu->cur_rh) {
3906884e6d60SXin LI case 2:
3907884e6d60SXin LI destval = ~destval;
3908884e6d60SXin LI write_back_byte(emu, destval);
3909884e6d60SXin LI break;
3910884e6d60SXin LI case 3:
3911884e6d60SXin LI destval = neg_byte(emu, destval);
3912884e6d60SXin LI write_back_byte(emu, destval);
3913884e6d60SXin LI break;
3914884e6d60SXin LI case 4:
3915884e6d60SXin LI mul_byte(emu, destval);
3916884e6d60SXin LI break;
3917884e6d60SXin LI case 5:
3918884e6d60SXin LI imul_byte(emu, destval);
3919884e6d60SXin LI break;
3920884e6d60SXin LI case 6:
3921884e6d60SXin LI div_byte(emu, destval);
3922884e6d60SXin LI break;
3923884e6d60SXin LI case 7:
3924884e6d60SXin LI idiv_byte(emu, destval);
3925884e6d60SXin LI break;
3926884e6d60SXin LI }
3927884e6d60SXin LI }
3928884e6d60SXin LI
3929884e6d60SXin LI /*
3930884e6d60SXin LI * REMARKS:
3931884e6d60SXin LI * Handles opcode 0xf7
3932884e6d60SXin LI */
3933884e6d60SXin LI static void
x86emuOp32_opcF7_word_RM(struct x86emu * emu)3934884e6d60SXin LI x86emuOp32_opcF7_word_RM(struct x86emu *emu)
3935884e6d60SXin LI {
3936884e6d60SXin LI uint32_t destval, srcval;
3937884e6d60SXin LI
3938884e6d60SXin LI /* long, drawn out code follows. Double switch for a total of 32
3939884e6d60SXin LI * cases. */
3940884e6d60SXin LI fetch_decode_modrm(emu);
3941884e6d60SXin LI if (emu->cur_rh == 1)
3942884e6d60SXin LI x86emu_halt_sys(emu);
3943884e6d60SXin LI
3944884e6d60SXin LI if (emu->cur_rh == 0) {
3945884e6d60SXin LI if (emu->cur_mod != 3) {
3946884e6d60SXin LI uint32_t destoffset;
3947884e6d60SXin LI
3948884e6d60SXin LI destoffset = decode_rl_address(emu);
3949884e6d60SXin LI srcval = fetch_long_imm(emu);
3950884e6d60SXin LI destval = fetch_data_long(emu, destoffset);
3951884e6d60SXin LI } else {
3952884e6d60SXin LI srcval = fetch_long_imm(emu);
3953884e6d60SXin LI destval = *decode_rl_long_register(emu);
3954884e6d60SXin LI }
3955884e6d60SXin LI test_long(emu, destval, srcval);
3956884e6d60SXin LI return;
3957884e6d60SXin LI }
3958884e6d60SXin LI destval = decode_and_fetch_long(emu);
3959884e6d60SXin LI switch (emu->cur_rh) {
3960884e6d60SXin LI case 2:
3961884e6d60SXin LI destval = ~destval;
3962884e6d60SXin LI write_back_long(emu, destval);
3963884e6d60SXin LI break;
3964884e6d60SXin LI case 3:
3965884e6d60SXin LI destval = neg_long(emu, destval);
3966884e6d60SXin LI write_back_long(emu, destval);
3967884e6d60SXin LI break;
3968884e6d60SXin LI case 4:
3969884e6d60SXin LI mul_long(emu, destval);
3970884e6d60SXin LI break;
3971884e6d60SXin LI case 5:
3972884e6d60SXin LI imul_long(emu, destval);
3973884e6d60SXin LI break;
3974884e6d60SXin LI case 6:
3975884e6d60SXin LI div_long(emu, destval);
3976884e6d60SXin LI break;
3977884e6d60SXin LI case 7:
3978884e6d60SXin LI idiv_long(emu, destval);
3979884e6d60SXin LI break;
3980884e6d60SXin LI }
3981884e6d60SXin LI }
3982884e6d60SXin LI static void
x86emuOp16_opcF7_word_RM(struct x86emu * emu)3983884e6d60SXin LI x86emuOp16_opcF7_word_RM(struct x86emu *emu)
3984884e6d60SXin LI {
3985884e6d60SXin LI uint16_t destval, srcval;
3986884e6d60SXin LI
3987884e6d60SXin LI /* long, drawn out code follows. Double switch for a total of 32
3988884e6d60SXin LI * cases. */
3989884e6d60SXin LI fetch_decode_modrm(emu);
3990884e6d60SXin LI if (emu->cur_rh == 1)
3991884e6d60SXin LI x86emu_halt_sys(emu);
3992884e6d60SXin LI
3993884e6d60SXin LI if (emu->cur_rh == 0) {
3994884e6d60SXin LI if (emu->cur_mod != 3) {
3995884e6d60SXin LI uint32_t destoffset;
3996884e6d60SXin LI
3997884e6d60SXin LI destoffset = decode_rl_address(emu);
3998884e6d60SXin LI srcval = fetch_word_imm(emu);
3999884e6d60SXin LI destval = fetch_data_word(emu, destoffset);
4000884e6d60SXin LI } else {
4001884e6d60SXin LI srcval = fetch_word_imm(emu);
4002884e6d60SXin LI destval = *decode_rl_word_register(emu);
4003884e6d60SXin LI }
4004884e6d60SXin LI test_word(emu, destval, srcval);
4005884e6d60SXin LI return;
4006884e6d60SXin LI }
4007884e6d60SXin LI destval = decode_and_fetch_word(emu);
4008884e6d60SXin LI switch (emu->cur_rh) {
4009884e6d60SXin LI case 2:
4010884e6d60SXin LI destval = ~destval;
4011884e6d60SXin LI write_back_word(emu, destval);
4012884e6d60SXin LI break;
4013884e6d60SXin LI case 3:
4014884e6d60SXin LI destval = neg_word(emu, destval);
4015884e6d60SXin LI write_back_word(emu, destval);
4016884e6d60SXin LI break;
4017884e6d60SXin LI case 4:
4018884e6d60SXin LI mul_word(emu, destval);
4019884e6d60SXin LI break;
4020884e6d60SXin LI case 5:
4021884e6d60SXin LI imul_word(emu, destval);
4022884e6d60SXin LI break;
4023884e6d60SXin LI case 6:
4024884e6d60SXin LI div_word(emu, destval);
4025884e6d60SXin LI break;
4026884e6d60SXin LI case 7:
4027884e6d60SXin LI idiv_word(emu, destval);
4028884e6d60SXin LI break;
4029884e6d60SXin LI }
4030884e6d60SXin LI }
4031884e6d60SXin LI static void
x86emuOp_opcF7_word_RM(struct x86emu * emu)4032884e6d60SXin LI x86emuOp_opcF7_word_RM(struct x86emu *emu)
4033884e6d60SXin LI {
4034884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
4035884e6d60SXin LI x86emuOp32_opcF7_word_RM(emu);
4036884e6d60SXin LI else
4037884e6d60SXin LI x86emuOp16_opcF7_word_RM(emu);
4038884e6d60SXin LI }
4039884e6d60SXin LI
4040884e6d60SXin LI /*
4041884e6d60SXin LI * REMARKS:
4042884e6d60SXin LI * Handles opcode 0xfe
4043884e6d60SXin LI */
4044884e6d60SXin LI static void
x86emuOp_opcFE_byte_RM(struct x86emu * emu)4045884e6d60SXin LI x86emuOp_opcFE_byte_RM(struct x86emu *emu)
4046884e6d60SXin LI {
4047884e6d60SXin LI uint8_t destval;
4048884e6d60SXin LI uint32_t destoffset;
4049884e6d60SXin LI uint8_t *destreg;
4050884e6d60SXin LI
4051884e6d60SXin LI /* Yet another special case instruction. */
4052884e6d60SXin LI fetch_decode_modrm(emu);
4053884e6d60SXin LI if (emu->cur_mod != 3) {
4054884e6d60SXin LI destoffset = decode_rl_address(emu);
4055884e6d60SXin LI switch (emu->cur_rh) {
4056884e6d60SXin LI case 0: /* inc word ptr ... */
4057884e6d60SXin LI destval = fetch_data_byte(emu, destoffset);
4058884e6d60SXin LI destval = inc_byte(emu, destval);
4059884e6d60SXin LI store_data_byte(emu, destoffset, destval);
4060884e6d60SXin LI break;
4061884e6d60SXin LI case 1: /* dec word ptr ... */
4062884e6d60SXin LI destval = fetch_data_byte(emu, destoffset);
4063884e6d60SXin LI destval = dec_byte(emu, destval);
4064884e6d60SXin LI store_data_byte(emu, destoffset, destval);
4065884e6d60SXin LI break;
4066884e6d60SXin LI }
4067884e6d60SXin LI } else {
4068884e6d60SXin LI destreg = decode_rl_byte_register(emu);
4069884e6d60SXin LI switch (emu->cur_rh) {
4070884e6d60SXin LI case 0:
4071884e6d60SXin LI *destreg = inc_byte(emu, *destreg);
4072884e6d60SXin LI break;
4073884e6d60SXin LI case 1:
4074884e6d60SXin LI *destreg = dec_byte(emu, *destreg);
4075884e6d60SXin LI break;
4076884e6d60SXin LI }
4077884e6d60SXin LI }
4078884e6d60SXin LI }
4079884e6d60SXin LI
4080884e6d60SXin LI /*
4081884e6d60SXin LI * REMARKS:
4082884e6d60SXin LI * Handles opcode 0xff
4083884e6d60SXin LI */
4084884e6d60SXin LI static void
x86emuOp32_opcFF_word_RM(struct x86emu * emu)4085884e6d60SXin LI x86emuOp32_opcFF_word_RM(struct x86emu *emu)
4086884e6d60SXin LI {
4087884e6d60SXin LI uint32_t destoffset = 0;
4088884e6d60SXin LI uint32_t destval, *destreg;
4089884e6d60SXin LI
4090884e6d60SXin LI if (emu->cur_mod != 3) {
4091884e6d60SXin LI destoffset = decode_rl_address(emu);
4092884e6d60SXin LI destval = fetch_data_long(emu, destoffset);
4093884e6d60SXin LI switch (emu->cur_rh) {
4094884e6d60SXin LI case 0: /* inc word ptr ... */
4095884e6d60SXin LI destval = inc_long(emu, destval);
4096884e6d60SXin LI store_data_long(emu, destoffset, destval);
4097884e6d60SXin LI break;
4098884e6d60SXin LI case 1: /* dec word ptr ... */
4099884e6d60SXin LI destval = dec_long(emu, destval);
4100884e6d60SXin LI store_data_long(emu, destoffset, destval);
4101884e6d60SXin LI break;
4102884e6d60SXin LI case 6: /* push word ptr ... */
4103884e6d60SXin LI push_long(emu, destval);
4104884e6d60SXin LI break;
4105884e6d60SXin LI }
4106884e6d60SXin LI } else {
4107884e6d60SXin LI destreg = decode_rl_long_register(emu);
4108884e6d60SXin LI switch (emu->cur_rh) {
4109884e6d60SXin LI case 0:
4110884e6d60SXin LI *destreg = inc_long(emu, *destreg);
4111884e6d60SXin LI break;
4112884e6d60SXin LI case 1:
4113884e6d60SXin LI *destreg = dec_long(emu, *destreg);
4114884e6d60SXin LI break;
4115884e6d60SXin LI case 6:
4116884e6d60SXin LI push_long(emu, *destreg);
4117884e6d60SXin LI break;
4118884e6d60SXin LI }
4119884e6d60SXin LI }
4120884e6d60SXin LI }
4121884e6d60SXin LI
4122884e6d60SXin LI static void
x86emuOp16_opcFF_word_RM(struct x86emu * emu)4123884e6d60SXin LI x86emuOp16_opcFF_word_RM(struct x86emu *emu)
4124884e6d60SXin LI {
4125884e6d60SXin LI uint32_t destoffset = 0;
4126884e6d60SXin LI uint16_t *destreg;
4127884e6d60SXin LI uint16_t destval;
4128884e6d60SXin LI
4129884e6d60SXin LI if (emu->cur_mod != 3) {
4130884e6d60SXin LI destoffset = decode_rl_address(emu);
4131884e6d60SXin LI destval = fetch_data_word(emu, destoffset);
4132884e6d60SXin LI switch (emu->cur_rh) {
4133884e6d60SXin LI case 0:
4134884e6d60SXin LI destval = inc_word(emu, destval);
4135884e6d60SXin LI store_data_word(emu, destoffset, destval);
4136884e6d60SXin LI break;
4137884e6d60SXin LI case 1: /* dec word ptr ... */
4138884e6d60SXin LI destval = dec_word(emu, destval);
4139884e6d60SXin LI store_data_word(emu, destoffset, destval);
4140884e6d60SXin LI break;
4141884e6d60SXin LI case 6: /* push word ptr ... */
4142884e6d60SXin LI push_word(emu, destval);
4143884e6d60SXin LI break;
4144884e6d60SXin LI }
4145884e6d60SXin LI } else {
4146884e6d60SXin LI destreg = decode_rl_word_register(emu);
4147884e6d60SXin LI switch (emu->cur_rh) {
4148884e6d60SXin LI case 0:
4149884e6d60SXin LI *destreg = inc_word(emu, *destreg);
4150884e6d60SXin LI break;
4151884e6d60SXin LI case 1:
4152884e6d60SXin LI *destreg = dec_word(emu, *destreg);
4153884e6d60SXin LI break;
4154884e6d60SXin LI case 6:
4155884e6d60SXin LI push_word(emu, *destreg);
4156884e6d60SXin LI break;
4157884e6d60SXin LI }
4158884e6d60SXin LI }
4159884e6d60SXin LI }
4160884e6d60SXin LI
4161884e6d60SXin LI static void
x86emuOp_opcFF_word_RM(struct x86emu * emu)4162884e6d60SXin LI x86emuOp_opcFF_word_RM(struct x86emu *emu)
4163884e6d60SXin LI {
4164884e6d60SXin LI uint32_t destoffset = 0;
4165884e6d60SXin LI uint16_t destval, destval2;
4166884e6d60SXin LI
4167884e6d60SXin LI /* Yet another special case instruction. */
4168884e6d60SXin LI fetch_decode_modrm(emu);
416906325fe0SXin LI if ((emu->cur_mod == 3 && (emu->cur_rh == 3 || emu->cur_rh == 5)) ||
417006325fe0SXin LI emu->cur_rh == 7)
4171884e6d60SXin LI x86emu_halt_sys(emu);
4172884e6d60SXin LI if (emu->cur_rh == 0 || emu->cur_rh == 1 || emu->cur_rh == 6) {
4173884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
4174884e6d60SXin LI x86emuOp32_opcFF_word_RM(emu);
4175884e6d60SXin LI else
4176884e6d60SXin LI x86emuOp16_opcFF_word_RM(emu);
4177884e6d60SXin LI return;
4178884e6d60SXin LI }
4179884e6d60SXin LI
4180884e6d60SXin LI if (emu->cur_mod != 3) {
4181884e6d60SXin LI destoffset = decode_rl_address(emu);
4182884e6d60SXin LI destval = fetch_data_word(emu, destoffset);
4183884e6d60SXin LI switch (emu->cur_rh) {
4184884e6d60SXin LI case 3: /* call far ptr ... */
4185884e6d60SXin LI destval2 = fetch_data_word(emu, destoffset + 2);
4186884e6d60SXin LI push_word(emu, emu->x86.R_CS);
4187884e6d60SXin LI emu->x86.R_CS = destval2;
4188884e6d60SXin LI push_word(emu, emu->x86.R_IP);
4189884e6d60SXin LI emu->x86.R_IP = destval;
4190884e6d60SXin LI break;
4191884e6d60SXin LI case 5: /* jmp far ptr ... */
4192884e6d60SXin LI destval2 = fetch_data_word(emu, destoffset + 2);
4193884e6d60SXin LI emu->x86.R_IP = destval;
4194884e6d60SXin LI emu->x86.R_CS = destval2;
4195884e6d60SXin LI break;
4196884e6d60SXin LI }
4197884e6d60SXin LI } else {
4198884e6d60SXin LI destval = *decode_rl_word_register(emu);
4199884e6d60SXin LI }
4200884e6d60SXin LI
4201884e6d60SXin LI switch (emu->cur_rh) {
4202884e6d60SXin LI case 2: /* call word ptr */
4203884e6d60SXin LI push_word(emu, emu->x86.R_IP);
4204884e6d60SXin LI emu->x86.R_IP = destval;
4205884e6d60SXin LI break;
4206884e6d60SXin LI case 4: /* jmp */
4207884e6d60SXin LI emu->x86.R_IP = destval;
4208884e6d60SXin LI break;
4209884e6d60SXin LI }
4210884e6d60SXin LI }
4211884e6d60SXin LI
4212884e6d60SXin LI /*
4213884e6d60SXin LI * * Single byte operation code table:
4214884e6d60SXin LI */
4215884e6d60SXin LI static void
x86emu_exec_one_byte(struct x86emu * emu)4216884e6d60SXin LI x86emu_exec_one_byte(struct x86emu * emu)
4217884e6d60SXin LI {
4218884e6d60SXin LI uint8_t op1;
4219884e6d60SXin LI
4220884e6d60SXin LI op1 = fetch_byte_imm(emu);
4221884e6d60SXin LI
4222884e6d60SXin LI switch (op1) {
4223884e6d60SXin LI case 0x00:
4224884e6d60SXin LI common_binop_byte_rm_r(emu, add_byte);
4225884e6d60SXin LI break;
4226884e6d60SXin LI case 0x01:
4227884e6d60SXin LI common_binop_word_long_rm_r(emu, add_word, add_long);
4228884e6d60SXin LI break;
4229884e6d60SXin LI case 0x02:
4230884e6d60SXin LI common_binop_byte_r_rm(emu, add_byte);
4231884e6d60SXin LI break;
4232884e6d60SXin LI case 0x03:
4233884e6d60SXin LI common_binop_word_long_r_rm(emu, add_word, add_long);
4234884e6d60SXin LI break;
4235884e6d60SXin LI case 0x04:
4236884e6d60SXin LI common_binop_byte_imm(emu, add_byte);
4237884e6d60SXin LI break;
4238884e6d60SXin LI case 0x05:
4239884e6d60SXin LI common_binop_word_long_imm(emu, add_word, add_long);
4240884e6d60SXin LI break;
4241884e6d60SXin LI case 0x06:
4242884e6d60SXin LI push_word(emu, emu->x86.R_ES);
4243884e6d60SXin LI break;
4244884e6d60SXin LI case 0x07:
4245884e6d60SXin LI emu->x86.R_ES = pop_word(emu);
4246884e6d60SXin LI break;
4247884e6d60SXin LI
4248884e6d60SXin LI case 0x08:
4249884e6d60SXin LI common_binop_byte_rm_r(emu, or_byte);
4250884e6d60SXin LI break;
4251884e6d60SXin LI case 0x09:
4252884e6d60SXin LI common_binop_word_long_rm_r(emu, or_word, or_long);
4253884e6d60SXin LI break;
4254884e6d60SXin LI case 0x0a:
4255884e6d60SXin LI common_binop_byte_r_rm(emu, or_byte);
4256884e6d60SXin LI break;
4257884e6d60SXin LI case 0x0b:
4258884e6d60SXin LI common_binop_word_long_r_rm(emu, or_word, or_long);
4259884e6d60SXin LI break;
4260884e6d60SXin LI case 0x0c:
4261884e6d60SXin LI common_binop_byte_imm(emu, or_byte);
4262884e6d60SXin LI break;
4263884e6d60SXin LI case 0x0d:
4264884e6d60SXin LI common_binop_word_long_imm(emu, or_word, or_long);
4265884e6d60SXin LI break;
4266884e6d60SXin LI case 0x0e:
4267884e6d60SXin LI push_word(emu, emu->x86.R_CS);
4268884e6d60SXin LI break;
4269884e6d60SXin LI case 0x0f:
4270884e6d60SXin LI x86emu_exec_two_byte(emu);
4271884e6d60SXin LI break;
4272884e6d60SXin LI
4273884e6d60SXin LI case 0x10:
4274884e6d60SXin LI common_binop_byte_rm_r(emu, adc_byte);
4275884e6d60SXin LI break;
4276884e6d60SXin LI case 0x11:
4277884e6d60SXin LI common_binop_word_long_rm_r(emu, adc_word, adc_long);
4278884e6d60SXin LI break;
4279884e6d60SXin LI case 0x12:
4280884e6d60SXin LI common_binop_byte_r_rm(emu, adc_byte);
4281884e6d60SXin LI break;
4282884e6d60SXin LI case 0x13:
4283884e6d60SXin LI common_binop_word_long_r_rm(emu, adc_word, adc_long);
4284884e6d60SXin LI break;
4285884e6d60SXin LI case 0x14:
4286884e6d60SXin LI common_binop_byte_imm(emu, adc_byte);
4287884e6d60SXin LI break;
4288884e6d60SXin LI case 0x15:
4289884e6d60SXin LI common_binop_word_long_imm(emu, adc_word, adc_long);
4290884e6d60SXin LI break;
4291884e6d60SXin LI case 0x16:
4292884e6d60SXin LI push_word(emu, emu->x86.R_SS);
4293884e6d60SXin LI break;
4294884e6d60SXin LI case 0x17:
4295884e6d60SXin LI emu->x86.R_SS = pop_word(emu);
4296884e6d60SXin LI break;
4297884e6d60SXin LI
4298884e6d60SXin LI case 0x18:
4299884e6d60SXin LI common_binop_byte_rm_r(emu, sbb_byte);
4300884e6d60SXin LI break;
4301884e6d60SXin LI case 0x19:
4302884e6d60SXin LI common_binop_word_long_rm_r(emu, sbb_word, sbb_long);
4303884e6d60SXin LI break;
4304884e6d60SXin LI case 0x1a:
4305884e6d60SXin LI common_binop_byte_r_rm(emu, sbb_byte);
4306884e6d60SXin LI break;
4307884e6d60SXin LI case 0x1b:
4308884e6d60SXin LI common_binop_word_long_r_rm(emu, sbb_word, sbb_long);
4309884e6d60SXin LI break;
4310884e6d60SXin LI case 0x1c:
4311884e6d60SXin LI common_binop_byte_imm(emu, sbb_byte);
4312884e6d60SXin LI break;
4313884e6d60SXin LI case 0x1d:
4314884e6d60SXin LI common_binop_word_long_imm(emu, sbb_word, sbb_long);
4315884e6d60SXin LI break;
4316884e6d60SXin LI case 0x1e:
4317884e6d60SXin LI push_word(emu, emu->x86.R_DS);
4318884e6d60SXin LI break;
4319884e6d60SXin LI case 0x1f:
4320884e6d60SXin LI emu->x86.R_DS = pop_word(emu);
4321884e6d60SXin LI break;
4322884e6d60SXin LI
4323884e6d60SXin LI case 0x20:
4324884e6d60SXin LI common_binop_byte_rm_r(emu, and_byte);
4325884e6d60SXin LI break;
4326884e6d60SXin LI case 0x21:
4327884e6d60SXin LI common_binop_word_long_rm_r(emu, and_word, and_long);
4328884e6d60SXin LI break;
4329884e6d60SXin LI case 0x22:
4330884e6d60SXin LI common_binop_byte_r_rm(emu, and_byte);
4331884e6d60SXin LI break;
4332884e6d60SXin LI case 0x23:
4333884e6d60SXin LI common_binop_word_long_r_rm(emu, and_word, and_long);
4334884e6d60SXin LI break;
4335884e6d60SXin LI case 0x24:
4336884e6d60SXin LI common_binop_byte_imm(emu, and_byte);
4337884e6d60SXin LI break;
4338884e6d60SXin LI case 0x25:
4339884e6d60SXin LI common_binop_word_long_imm(emu, and_word, and_long);
4340884e6d60SXin LI break;
4341884e6d60SXin LI case 0x26:
4342884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_ES;
4343884e6d60SXin LI break;
4344884e6d60SXin LI case 0x27:
4345884e6d60SXin LI emu->x86.R_AL = daa_byte(emu, emu->x86.R_AL);
4346884e6d60SXin LI break;
4347884e6d60SXin LI
4348884e6d60SXin LI case 0x28:
4349884e6d60SXin LI common_binop_byte_rm_r(emu, sub_byte);
4350884e6d60SXin LI break;
4351884e6d60SXin LI case 0x29:
4352884e6d60SXin LI common_binop_word_long_rm_r(emu, sub_word, sub_long);
4353884e6d60SXin LI break;
4354884e6d60SXin LI case 0x2a:
4355884e6d60SXin LI common_binop_byte_r_rm(emu, sub_byte);
4356884e6d60SXin LI break;
4357884e6d60SXin LI case 0x2b:
4358884e6d60SXin LI common_binop_word_long_r_rm(emu, sub_word, sub_long);
4359884e6d60SXin LI break;
4360884e6d60SXin LI case 0x2c:
4361884e6d60SXin LI common_binop_byte_imm(emu, sub_byte);
4362884e6d60SXin LI break;
4363884e6d60SXin LI case 0x2d:
4364884e6d60SXin LI common_binop_word_long_imm(emu, sub_word, sub_long);
4365884e6d60SXin LI break;
4366884e6d60SXin LI case 0x2e:
4367884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_CS;
4368884e6d60SXin LI break;
4369884e6d60SXin LI case 0x2f:
4370884e6d60SXin LI emu->x86.R_AL = das_byte(emu, emu->x86.R_AL);
4371884e6d60SXin LI break;
4372884e6d60SXin LI
4373884e6d60SXin LI case 0x30:
4374884e6d60SXin LI common_binop_byte_rm_r(emu, xor_byte);
4375884e6d60SXin LI break;
4376884e6d60SXin LI case 0x31:
4377884e6d60SXin LI common_binop_word_long_rm_r(emu, xor_word, xor_long);
4378884e6d60SXin LI break;
4379884e6d60SXin LI case 0x32:
4380884e6d60SXin LI common_binop_byte_r_rm(emu, xor_byte);
4381884e6d60SXin LI break;
4382884e6d60SXin LI case 0x33:
4383884e6d60SXin LI common_binop_word_long_r_rm(emu, xor_word, xor_long);
4384884e6d60SXin LI break;
4385884e6d60SXin LI case 0x34:
4386884e6d60SXin LI common_binop_byte_imm(emu, xor_byte);
4387884e6d60SXin LI break;
4388884e6d60SXin LI case 0x35:
4389884e6d60SXin LI common_binop_word_long_imm(emu, xor_word, xor_long);
4390884e6d60SXin LI break;
4391884e6d60SXin LI case 0x36:
4392884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_SS;
4393884e6d60SXin LI break;
4394884e6d60SXin LI case 0x37:
4395884e6d60SXin LI emu->x86.R_AX = aaa_word(emu, emu->x86.R_AX);
4396884e6d60SXin LI break;
4397884e6d60SXin LI
4398884e6d60SXin LI case 0x38:
4399884e6d60SXin LI common_binop_ns_byte_rm_r(emu, cmp_byte_no_return);
4400884e6d60SXin LI break;
4401884e6d60SXin LI case 0x39:
4402884e6d60SXin LI common_binop_ns_word_long_rm_r(emu, cmp_word_no_return,
4403884e6d60SXin LI cmp_long_no_return);
4404884e6d60SXin LI break;
4405884e6d60SXin LI case 0x3a:
4406884e6d60SXin LI x86emuOp_cmp_byte_R_RM(emu);
4407884e6d60SXin LI break;
4408884e6d60SXin LI case 0x3b:
4409884e6d60SXin LI x86emuOp_cmp_word_R_RM(emu);
4410884e6d60SXin LI break;
4411884e6d60SXin LI case 0x3c:
4412884e6d60SXin LI x86emuOp_cmp_byte_AL_IMM(emu);
4413884e6d60SXin LI break;
4414884e6d60SXin LI case 0x3d:
4415884e6d60SXin LI x86emuOp_cmp_word_AX_IMM(emu);
4416884e6d60SXin LI break;
4417884e6d60SXin LI case 0x3e:
4418884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_DS;
4419884e6d60SXin LI break;
4420884e6d60SXin LI case 0x3f:
4421884e6d60SXin LI emu->x86.R_AX = aas_word(emu, emu->x86.R_AX);
4422884e6d60SXin LI break;
4423884e6d60SXin LI
4424884e6d60SXin LI case 0x40:
4425884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_a);
4426884e6d60SXin LI break;
4427884e6d60SXin LI case 0x41:
4428884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_c);
4429884e6d60SXin LI break;
4430884e6d60SXin LI case 0x42:
4431884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_d);
4432884e6d60SXin LI break;
4433884e6d60SXin LI case 0x43:
4434884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_b);
4435884e6d60SXin LI break;
4436884e6d60SXin LI case 0x44:
4437884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_sp);
4438884e6d60SXin LI break;
4439884e6d60SXin LI case 0x45:
4440884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_bp);
4441884e6d60SXin LI break;
4442884e6d60SXin LI case 0x46:
4443884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_si);
4444884e6d60SXin LI break;
4445884e6d60SXin LI case 0x47:
4446884e6d60SXin LI common_inc_word_long(emu, &emu->x86.register_di);
4447884e6d60SXin LI break;
4448884e6d60SXin LI
4449884e6d60SXin LI case 0x48:
4450884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_a);
4451884e6d60SXin LI break;
4452884e6d60SXin LI case 0x49:
4453884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_c);
4454884e6d60SXin LI break;
4455884e6d60SXin LI case 0x4a:
4456884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_d);
4457884e6d60SXin LI break;
4458884e6d60SXin LI case 0x4b:
4459884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_b);
4460884e6d60SXin LI break;
4461884e6d60SXin LI case 0x4c:
4462884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_sp);
4463884e6d60SXin LI break;
4464884e6d60SXin LI case 0x4d:
4465884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_bp);
4466884e6d60SXin LI break;
4467884e6d60SXin LI case 0x4e:
4468884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_si);
4469884e6d60SXin LI break;
4470884e6d60SXin LI case 0x4f:
4471884e6d60SXin LI common_dec_word_long(emu, &emu->x86.register_di);
4472884e6d60SXin LI break;
4473884e6d60SXin LI
4474884e6d60SXin LI case 0x50:
4475884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_a);
4476884e6d60SXin LI break;
4477884e6d60SXin LI case 0x51:
4478884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_c);
4479884e6d60SXin LI break;
4480884e6d60SXin LI case 0x52:
4481884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_d);
4482884e6d60SXin LI break;
4483884e6d60SXin LI case 0x53:
4484884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_b);
4485884e6d60SXin LI break;
4486884e6d60SXin LI case 0x54:
4487884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_sp);
4488884e6d60SXin LI break;
4489884e6d60SXin LI case 0x55:
4490884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_bp);
4491884e6d60SXin LI break;
4492884e6d60SXin LI case 0x56:
4493884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_si);
4494884e6d60SXin LI break;
4495884e6d60SXin LI case 0x57:
4496884e6d60SXin LI common_push_word_long(emu, &emu->x86.register_di);
4497884e6d60SXin LI break;
4498884e6d60SXin LI
4499884e6d60SXin LI case 0x58:
4500884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_a);
4501884e6d60SXin LI break;
4502884e6d60SXin LI case 0x59:
4503884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_c);
4504884e6d60SXin LI break;
4505884e6d60SXin LI case 0x5a:
4506884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_d);
4507884e6d60SXin LI break;
4508884e6d60SXin LI case 0x5b:
4509884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_b);
4510884e6d60SXin LI break;
4511884e6d60SXin LI case 0x5c:
4512884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_sp);
4513884e6d60SXin LI break;
4514884e6d60SXin LI case 0x5d:
4515884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_bp);
4516884e6d60SXin LI break;
4517884e6d60SXin LI case 0x5e:
4518884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_si);
4519884e6d60SXin LI break;
4520884e6d60SXin LI case 0x5f:
4521884e6d60SXin LI common_pop_word_long(emu, &emu->x86.register_di);
4522884e6d60SXin LI break;
4523884e6d60SXin LI
4524884e6d60SXin LI case 0x60:
4525884e6d60SXin LI x86emuOp_push_all(emu);
4526884e6d60SXin LI break;
4527884e6d60SXin LI case 0x61:
4528884e6d60SXin LI x86emuOp_pop_all(emu);
4529884e6d60SXin LI break;
4530884e6d60SXin LI /* 0x62 bound */
4531884e6d60SXin LI /* 0x63 arpl */
4532884e6d60SXin LI case 0x64:
4533884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_FS;
4534884e6d60SXin LI break;
4535884e6d60SXin LI case 0x65:
4536884e6d60SXin LI emu->x86.mode |= SYSMODE_SEGOVR_GS;
4537884e6d60SXin LI break;
4538884e6d60SXin LI case 0x66:
4539884e6d60SXin LI emu->x86.mode |= SYSMODE_PREFIX_DATA;
4540884e6d60SXin LI break;
4541884e6d60SXin LI case 0x67:
4542884e6d60SXin LI emu->x86.mode |= SYSMODE_PREFIX_ADDR;
4543884e6d60SXin LI break;
4544884e6d60SXin LI
4545884e6d60SXin LI case 0x68:
4546884e6d60SXin LI x86emuOp_push_word_IMM(emu);
4547884e6d60SXin LI break;
4548884e6d60SXin LI case 0x69:
4549884e6d60SXin LI common_imul_imm(emu, 0);
4550884e6d60SXin LI break;
4551884e6d60SXin LI case 0x6a:
4552884e6d60SXin LI x86emuOp_push_byte_IMM(emu);
4553884e6d60SXin LI break;
4554884e6d60SXin LI case 0x6b:
4555884e6d60SXin LI common_imul_imm(emu, 1);
4556884e6d60SXin LI break;
4557884e6d60SXin LI case 0x6c:
4558884e6d60SXin LI ins(emu, 1);
4559884e6d60SXin LI break;
4560884e6d60SXin LI case 0x6d:
4561884e6d60SXin LI x86emuOp_ins_word(emu);
4562884e6d60SXin LI break;
4563884e6d60SXin LI case 0x6e:
4564884e6d60SXin LI outs(emu, 1);
4565884e6d60SXin LI break;
4566884e6d60SXin LI case 0x6f:
4567884e6d60SXin LI x86emuOp_outs_word(emu);
4568884e6d60SXin LI break;
4569884e6d60SXin LI
4570884e6d60SXin LI case 0x70:
4571884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_OF));
4572884e6d60SXin LI break;
4573884e6d60SXin LI case 0x71:
4574884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_OF));
4575884e6d60SXin LI break;
4576884e6d60SXin LI case 0x72:
4577884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_CF));
4578884e6d60SXin LI break;
4579884e6d60SXin LI case 0x73:
4580884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_CF));
4581884e6d60SXin LI break;
4582884e6d60SXin LI case 0x74:
4583884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_ZF));
4584884e6d60SXin LI break;
4585884e6d60SXin LI case 0x75:
4586884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_ZF));
4587884e6d60SXin LI break;
4588884e6d60SXin LI case 0x76:
4589884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
4590884e6d60SXin LI break;
4591884e6d60SXin LI case 0x77:
4592884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_CF) && !ACCESS_FLAG(F_ZF));
4593884e6d60SXin LI break;
4594884e6d60SXin LI
4595884e6d60SXin LI case 0x78:
4596884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_SF));
4597884e6d60SXin LI break;
4598884e6d60SXin LI case 0x79:
4599884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_SF));
4600884e6d60SXin LI break;
4601884e6d60SXin LI case 0x7a:
4602884e6d60SXin LI common_jmp_near(emu, ACCESS_FLAG(F_PF));
4603884e6d60SXin LI break;
4604884e6d60SXin LI case 0x7b:
4605884e6d60SXin LI common_jmp_near(emu, !ACCESS_FLAG(F_PF));
4606884e6d60SXin LI break;
4607884e6d60SXin LI case 0x7c:
4608884e6d60SXin LI x86emuOp_jump_near_L(emu);
4609884e6d60SXin LI break;
4610884e6d60SXin LI case 0x7d:
4611884e6d60SXin LI x86emuOp_jump_near_NL(emu);
4612884e6d60SXin LI break;
4613884e6d60SXin LI case 0x7e:
4614884e6d60SXin LI x86emuOp_jump_near_LE(emu);
4615884e6d60SXin LI break;
4616884e6d60SXin LI case 0x7f:
4617884e6d60SXin LI x86emuOp_jump_near_NLE(emu);
4618884e6d60SXin LI break;
4619884e6d60SXin LI
4620884e6d60SXin LI case 0x80:
4621884e6d60SXin LI x86emuOp_opc80_byte_RM_IMM(emu);
4622884e6d60SXin LI break;
4623884e6d60SXin LI case 0x81:
4624884e6d60SXin LI x86emuOp_opc81_word_RM_IMM(emu);
4625884e6d60SXin LI break;
4626884e6d60SXin LI case 0x82:
4627884e6d60SXin LI x86emuOp_opc82_byte_RM_IMM(emu);
4628884e6d60SXin LI break;
4629884e6d60SXin LI case 0x83:
4630884e6d60SXin LI x86emuOp_opc83_word_RM_IMM(emu);
4631884e6d60SXin LI break;
4632884e6d60SXin LI case 0x84:
4633884e6d60SXin LI common_binop_ns_byte_rm_r(emu, test_byte);
4634884e6d60SXin LI break;
4635884e6d60SXin LI case 0x85:
4636884e6d60SXin LI common_binop_ns_word_long_rm_r(emu, test_word, test_long);
4637884e6d60SXin LI break;
4638884e6d60SXin LI case 0x86:
4639884e6d60SXin LI x86emuOp_xchg_byte_RM_R(emu);
4640884e6d60SXin LI break;
4641884e6d60SXin LI case 0x87:
4642884e6d60SXin LI x86emuOp_xchg_word_RM_R(emu);
4643884e6d60SXin LI break;
4644884e6d60SXin LI
4645884e6d60SXin LI case 0x88:
4646884e6d60SXin LI x86emuOp_mov_byte_RM_R(emu);
4647884e6d60SXin LI break;
4648884e6d60SXin LI case 0x89:
4649884e6d60SXin LI x86emuOp_mov_word_RM_R(emu);
4650884e6d60SXin LI break;
4651884e6d60SXin LI case 0x8a:
4652884e6d60SXin LI x86emuOp_mov_byte_R_RM(emu);
4653884e6d60SXin LI break;
4654884e6d60SXin LI case 0x8b:
4655884e6d60SXin LI x86emuOp_mov_word_R_RM(emu);
4656884e6d60SXin LI break;
4657884e6d60SXin LI case 0x8c:
4658884e6d60SXin LI x86emuOp_mov_word_RM_SR(emu);
4659884e6d60SXin LI break;
4660884e6d60SXin LI case 0x8d:
4661884e6d60SXin LI x86emuOp_lea_word_R_M(emu);
4662884e6d60SXin LI break;
4663884e6d60SXin LI case 0x8e:
4664884e6d60SXin LI x86emuOp_mov_word_SR_RM(emu);
4665884e6d60SXin LI break;
4666884e6d60SXin LI case 0x8f:
4667884e6d60SXin LI x86emuOp_pop_RM(emu);
4668884e6d60SXin LI break;
4669884e6d60SXin LI
4670884e6d60SXin LI case 0x90:
4671884e6d60SXin LI /* nop */
4672884e6d60SXin LI break;
4673884e6d60SXin LI case 0x91:
4674884e6d60SXin LI x86emuOp_xchg_word_AX_CX(emu);
4675884e6d60SXin LI break;
4676884e6d60SXin LI case 0x92:
4677884e6d60SXin LI x86emuOp_xchg_word_AX_DX(emu);
4678884e6d60SXin LI break;
4679884e6d60SXin LI case 0x93:
4680884e6d60SXin LI x86emuOp_xchg_word_AX_BX(emu);
4681884e6d60SXin LI break;
4682884e6d60SXin LI case 0x94:
4683884e6d60SXin LI x86emuOp_xchg_word_AX_SP(emu);
4684884e6d60SXin LI break;
4685884e6d60SXin LI case 0x95:
4686884e6d60SXin LI x86emuOp_xchg_word_AX_BP(emu);
4687884e6d60SXin LI break;
4688884e6d60SXin LI case 0x96:
4689884e6d60SXin LI x86emuOp_xchg_word_AX_SI(emu);
4690884e6d60SXin LI break;
4691884e6d60SXin LI case 0x97:
4692884e6d60SXin LI x86emuOp_xchg_word_AX_DI(emu);
4693884e6d60SXin LI break;
4694884e6d60SXin LI
4695884e6d60SXin LI case 0x98:
4696884e6d60SXin LI x86emuOp_cbw(emu);
4697884e6d60SXin LI break;
4698884e6d60SXin LI case 0x99:
4699884e6d60SXin LI x86emuOp_cwd(emu);
4700884e6d60SXin LI break;
4701884e6d60SXin LI case 0x9a:
4702884e6d60SXin LI x86emuOp_call_far_IMM(emu);
4703884e6d60SXin LI break;
4704884e6d60SXin LI case 0x9b:
4705884e6d60SXin LI /* wait */
4706884e6d60SXin LI break;
4707884e6d60SXin LI case 0x9c:
4708884e6d60SXin LI x86emuOp_pushf_word(emu);
4709884e6d60SXin LI break;
4710884e6d60SXin LI case 0x9d:
4711884e6d60SXin LI x86emuOp_popf_word(emu);
4712884e6d60SXin LI break;
4713884e6d60SXin LI case 0x9e:
4714884e6d60SXin LI x86emuOp_sahf(emu);
4715884e6d60SXin LI break;
4716884e6d60SXin LI case 0x9f:
4717884e6d60SXin LI x86emuOp_lahf(emu);
4718884e6d60SXin LI break;
4719884e6d60SXin LI
4720884e6d60SXin LI case 0xa0:
4721884e6d60SXin LI x86emuOp_mov_AL_M_IMM(emu);
4722884e6d60SXin LI break;
4723884e6d60SXin LI case 0xa1:
4724884e6d60SXin LI x86emuOp_mov_AX_M_IMM(emu);
4725884e6d60SXin LI break;
4726884e6d60SXin LI case 0xa2:
4727884e6d60SXin LI x86emuOp_mov_M_AL_IMM(emu);
4728884e6d60SXin LI break;
4729884e6d60SXin LI case 0xa3:
4730884e6d60SXin LI x86emuOp_mov_M_AX_IMM(emu);
4731884e6d60SXin LI break;
4732884e6d60SXin LI case 0xa4:
4733884e6d60SXin LI x86emuOp_movs_byte(emu);
4734884e6d60SXin LI break;
4735884e6d60SXin LI case 0xa5:
4736884e6d60SXin LI x86emuOp_movs_word(emu);
4737884e6d60SXin LI break;
4738884e6d60SXin LI case 0xa6:
4739884e6d60SXin LI x86emuOp_cmps_byte(emu);
4740884e6d60SXin LI break;
4741884e6d60SXin LI case 0xa7:
4742884e6d60SXin LI x86emuOp_cmps_word(emu);
4743884e6d60SXin LI break;
4744884e6d60SXin LI
4745884e6d60SXin LI case 0xa8:
4746884e6d60SXin LI test_byte(emu, emu->x86.R_AL, fetch_byte_imm(emu));
4747884e6d60SXin LI break;
4748884e6d60SXin LI case 0xa9:
4749884e6d60SXin LI x86emuOp_test_AX_IMM(emu);
4750884e6d60SXin LI break;
4751884e6d60SXin LI case 0xaa:
4752884e6d60SXin LI x86emuOp_stos_byte(emu);
4753884e6d60SXin LI break;
4754884e6d60SXin LI case 0xab:
4755884e6d60SXin LI x86emuOp_stos_word(emu);
4756884e6d60SXin LI break;
4757884e6d60SXin LI case 0xac:
4758884e6d60SXin LI x86emuOp_lods_byte(emu);
4759884e6d60SXin LI break;
4760884e6d60SXin LI case 0xad:
4761884e6d60SXin LI x86emuOp_lods_word(emu);
4762884e6d60SXin LI break;
4763884e6d60SXin LI case 0xae:
4764884e6d60SXin LI x86emuOp_scas_byte(emu);
4765884e6d60SXin LI break;
4766884e6d60SXin LI case 0xaf:
4767884e6d60SXin LI x86emuOp_scas_word(emu);
4768884e6d60SXin LI break;
4769884e6d60SXin LI
4770884e6d60SXin LI case 0xb0:
4771884e6d60SXin LI emu->x86.R_AL = fetch_byte_imm(emu);
4772884e6d60SXin LI break;
4773884e6d60SXin LI case 0xb1:
4774884e6d60SXin LI emu->x86.R_CL = fetch_byte_imm(emu);
4775884e6d60SXin LI break;
4776884e6d60SXin LI case 0xb2:
4777884e6d60SXin LI emu->x86.R_DL = fetch_byte_imm(emu);
4778884e6d60SXin LI break;
4779884e6d60SXin LI case 0xb3:
4780884e6d60SXin LI emu->x86.R_BL = fetch_byte_imm(emu);
4781884e6d60SXin LI break;
4782884e6d60SXin LI case 0xb4:
4783884e6d60SXin LI emu->x86.R_AH = fetch_byte_imm(emu);
4784884e6d60SXin LI break;
4785884e6d60SXin LI case 0xb5:
4786884e6d60SXin LI emu->x86.R_CH = fetch_byte_imm(emu);
4787884e6d60SXin LI break;
4788884e6d60SXin LI case 0xb6:
4789884e6d60SXin LI emu->x86.R_DH = fetch_byte_imm(emu);
4790884e6d60SXin LI break;
4791884e6d60SXin LI case 0xb7:
4792884e6d60SXin LI emu->x86.R_BH = fetch_byte_imm(emu);
4793884e6d60SXin LI break;
4794884e6d60SXin LI
4795884e6d60SXin LI case 0xb8:
4796884e6d60SXin LI x86emuOp_mov_word_AX_IMM(emu);
4797884e6d60SXin LI break;
4798884e6d60SXin LI case 0xb9:
4799884e6d60SXin LI x86emuOp_mov_word_CX_IMM(emu);
4800884e6d60SXin LI break;
4801884e6d60SXin LI case 0xba:
4802884e6d60SXin LI x86emuOp_mov_word_DX_IMM(emu);
4803884e6d60SXin LI break;
4804884e6d60SXin LI case 0xbb:
4805884e6d60SXin LI x86emuOp_mov_word_BX_IMM(emu);
4806884e6d60SXin LI break;
4807884e6d60SXin LI case 0xbc:
4808884e6d60SXin LI
4809884e6d60SXin LI x86emuOp_mov_word_SP_IMM(emu);
4810884e6d60SXin LI break;
4811884e6d60SXin LI case 0xbd:
4812884e6d60SXin LI x86emuOp_mov_word_BP_IMM(emu);
4813884e6d60SXin LI break;
4814884e6d60SXin LI case 0xbe:
4815884e6d60SXin LI x86emuOp_mov_word_SI_IMM(emu);
4816884e6d60SXin LI break;
4817884e6d60SXin LI case 0xbf:
4818884e6d60SXin LI x86emuOp_mov_word_DI_IMM(emu);
4819884e6d60SXin LI break;
4820884e6d60SXin LI
4821884e6d60SXin LI case 0xc0:
4822884e6d60SXin LI x86emuOp_opcC0_byte_RM_MEM(emu);
4823884e6d60SXin LI break;
4824884e6d60SXin LI case 0xc1:
4825884e6d60SXin LI x86emuOp_opcC1_word_RM_MEM(emu);
4826884e6d60SXin LI break;
4827884e6d60SXin LI case 0xc2:
4828884e6d60SXin LI x86emuOp_ret_near_IMM(emu);
4829884e6d60SXin LI break;
4830884e6d60SXin LI case 0xc3:
4831884e6d60SXin LI emu->x86.R_IP = pop_word(emu);
4832884e6d60SXin LI break;
4833884e6d60SXin LI case 0xc4:
4834884e6d60SXin LI common_load_far_pointer(emu, &emu->x86.R_ES);
4835884e6d60SXin LI break;
4836884e6d60SXin LI case 0xc5:
4837884e6d60SXin LI common_load_far_pointer(emu, &emu->x86.R_DS);
4838884e6d60SXin LI break;
4839884e6d60SXin LI case 0xc6:
4840884e6d60SXin LI x86emuOp_mov_byte_RM_IMM(emu);
4841884e6d60SXin LI break;
4842884e6d60SXin LI case 0xc7:
4843884e6d60SXin LI x86emuOp_mov_word_RM_IMM(emu);
4844884e6d60SXin LI break;
4845884e6d60SXin LI case 0xc8:
4846884e6d60SXin LI x86emuOp_enter(emu);
4847884e6d60SXin LI break;
4848884e6d60SXin LI case 0xc9:
4849884e6d60SXin LI x86emuOp_leave(emu);
4850884e6d60SXin LI break;
4851884e6d60SXin LI case 0xca:
4852884e6d60SXin LI x86emuOp_ret_far_IMM(emu);
4853884e6d60SXin LI break;
4854884e6d60SXin LI case 0xcb:
4855884e6d60SXin LI x86emuOp_ret_far(emu);
4856884e6d60SXin LI break;
4857884e6d60SXin LI case 0xcc:
4858884e6d60SXin LI x86emuOp_int3(emu);
4859884e6d60SXin LI break;
4860884e6d60SXin LI case 0xcd:
4861884e6d60SXin LI x86emuOp_int_IMM(emu);
4862884e6d60SXin LI break;
4863884e6d60SXin LI case 0xce:
4864884e6d60SXin LI x86emuOp_into(emu);
4865884e6d60SXin LI break;
4866884e6d60SXin LI case 0xcf:
4867884e6d60SXin LI x86emuOp_iret(emu);
4868884e6d60SXin LI break;
4869884e6d60SXin LI
4870884e6d60SXin LI case 0xd0:
4871884e6d60SXin LI x86emuOp_opcD0_byte_RM_1(emu);
4872884e6d60SXin LI break;
4873884e6d60SXin LI case 0xd1:
4874884e6d60SXin LI x86emuOp_opcD1_word_RM_1(emu);
4875884e6d60SXin LI break;
4876884e6d60SXin LI case 0xd2:
4877884e6d60SXin LI x86emuOp_opcD2_byte_RM_CL(emu);
4878884e6d60SXin LI break;
4879884e6d60SXin LI case 0xd3:
4880884e6d60SXin LI x86emuOp_opcD3_word_RM_CL(emu);
4881884e6d60SXin LI break;
4882884e6d60SXin LI case 0xd4:
4883884e6d60SXin LI x86emuOp_aam(emu);
4884884e6d60SXin LI break;
4885884e6d60SXin LI case 0xd5:
4886884e6d60SXin LI x86emuOp_aad(emu);
4887884e6d60SXin LI break;
4888884e6d60SXin LI /* 0xd6 Undocumented SETALC instruction */
4889884e6d60SXin LI case 0xd7:
4890884e6d60SXin LI x86emuOp_xlat(emu);
4891884e6d60SXin LI break;
4892884e6d60SXin LI case 0xd8:
4893884e6d60SXin LI x86emuOp_esc_coprocess_d8(emu);
4894884e6d60SXin LI break;
4895884e6d60SXin LI case 0xd9:
4896884e6d60SXin LI x86emuOp_esc_coprocess_d9(emu);
4897884e6d60SXin LI break;
4898884e6d60SXin LI case 0xda:
4899884e6d60SXin LI x86emuOp_esc_coprocess_da(emu);
4900884e6d60SXin LI break;
4901884e6d60SXin LI case 0xdb:
4902884e6d60SXin LI x86emuOp_esc_coprocess_db(emu);
4903884e6d60SXin LI break;
4904884e6d60SXin LI case 0xdc:
4905884e6d60SXin LI x86emuOp_esc_coprocess_dc(emu);
4906884e6d60SXin LI break;
4907884e6d60SXin LI case 0xdd:
4908884e6d60SXin LI x86emuOp_esc_coprocess_dd(emu);
4909884e6d60SXin LI break;
4910884e6d60SXin LI case 0xde:
4911884e6d60SXin LI x86emuOp_esc_coprocess_de(emu);
4912884e6d60SXin LI break;
4913884e6d60SXin LI case 0xdf:
4914884e6d60SXin LI x86emuOp_esc_coprocess_df(emu);
4915884e6d60SXin LI break;
4916884e6d60SXin LI
4917884e6d60SXin LI case 0xe0:
4918884e6d60SXin LI x86emuOp_loopne(emu);
4919884e6d60SXin LI break;
4920884e6d60SXin LI case 0xe1:
4921884e6d60SXin LI x86emuOp_loope(emu);
4922884e6d60SXin LI break;
4923884e6d60SXin LI case 0xe2:
4924884e6d60SXin LI x86emuOp_loop(emu);
4925884e6d60SXin LI break;
4926884e6d60SXin LI case 0xe3:
4927884e6d60SXin LI x86emuOp_jcxz(emu);
4928884e6d60SXin LI break;
4929884e6d60SXin LI case 0xe4:
4930884e6d60SXin LI x86emuOp_in_byte_AL_IMM(emu);
4931884e6d60SXin LI break;
4932884e6d60SXin LI case 0xe5:
4933884e6d60SXin LI x86emuOp_in_word_AX_IMM(emu);
4934884e6d60SXin LI break;
4935884e6d60SXin LI case 0xe6:
4936884e6d60SXin LI x86emuOp_out_byte_IMM_AL(emu);
4937884e6d60SXin LI break;
4938884e6d60SXin LI case 0xe7:
4939884e6d60SXin LI x86emuOp_out_word_IMM_AX(emu);
4940884e6d60SXin LI break;
4941884e6d60SXin LI
4942884e6d60SXin LI case 0xe8:
4943884e6d60SXin LI x86emuOp_call_near_IMM(emu);
4944884e6d60SXin LI break;
4945884e6d60SXin LI case 0xe9:
4946884e6d60SXin LI x86emuOp_jump_near_IMM(emu);
4947884e6d60SXin LI break;
4948884e6d60SXin LI case 0xea:
4949884e6d60SXin LI x86emuOp_jump_far_IMM(emu);
4950884e6d60SXin LI break;
4951884e6d60SXin LI case 0xeb:
4952884e6d60SXin LI x86emuOp_jump_byte_IMM(emu);
4953884e6d60SXin LI break;
4954884e6d60SXin LI case 0xec:
4955884e6d60SXin LI x86emuOp_in_byte_AL_DX(emu);
4956884e6d60SXin LI break;
4957884e6d60SXin LI case 0xed:
4958884e6d60SXin LI x86emuOp_in_word_AX_DX(emu);
4959884e6d60SXin LI break;
4960884e6d60SXin LI case 0xee:
4961884e6d60SXin LI x86emuOp_out_byte_DX_AL(emu);
4962884e6d60SXin LI break;
4963884e6d60SXin LI case 0xef:
4964884e6d60SXin LI x86emuOp_out_word_DX_AX(emu);
4965884e6d60SXin LI break;
4966884e6d60SXin LI
4967884e6d60SXin LI case 0xf0:
4968884e6d60SXin LI x86emuOp_lock(emu);
4969884e6d60SXin LI break;
4970884e6d60SXin LI case 0xf2:
4971884e6d60SXin LI emu->x86.mode |= SYSMODE_PREFIX_REPNE;
4972884e6d60SXin LI break;
4973884e6d60SXin LI case 0xf3:
4974884e6d60SXin LI emu->x86.mode |= SYSMODE_PREFIX_REPE;
4975884e6d60SXin LI break;
4976884e6d60SXin LI case 0xf4:
4977884e6d60SXin LI x86emu_halt_sys(emu);
4978884e6d60SXin LI break;
4979884e6d60SXin LI case 0xf5:
4980884e6d60SXin LI x86emuOp_cmc(emu);
4981884e6d60SXin LI break;
4982884e6d60SXin LI case 0xf6:
4983884e6d60SXin LI x86emuOp_opcF6_byte_RM(emu);
4984884e6d60SXin LI break;
4985884e6d60SXin LI case 0xf7:
4986884e6d60SXin LI x86emuOp_opcF7_word_RM(emu);
4987884e6d60SXin LI break;
4988884e6d60SXin LI
4989884e6d60SXin LI case 0xf8:
4990884e6d60SXin LI CLEAR_FLAG(F_CF);
4991884e6d60SXin LI break;
4992884e6d60SXin LI case 0xf9:
4993884e6d60SXin LI SET_FLAG(F_CF);
4994884e6d60SXin LI break;
4995884e6d60SXin LI case 0xfa:
4996884e6d60SXin LI CLEAR_FLAG(F_IF);
4997884e6d60SXin LI break;
4998884e6d60SXin LI case 0xfb:
4999884e6d60SXin LI SET_FLAG(F_IF);
5000884e6d60SXin LI break;
5001884e6d60SXin LI case 0xfc:
5002884e6d60SXin LI CLEAR_FLAG(F_DF);
5003884e6d60SXin LI break;
5004884e6d60SXin LI case 0xfd:
5005884e6d60SXin LI SET_FLAG(F_DF);
5006884e6d60SXin LI break;
5007884e6d60SXin LI case 0xfe:
5008884e6d60SXin LI x86emuOp_opcFE_byte_RM(emu);
5009884e6d60SXin LI break;
5010884e6d60SXin LI case 0xff:
5011884e6d60SXin LI x86emuOp_opcFF_word_RM(emu);
5012884e6d60SXin LI break;
5013884e6d60SXin LI default:
5014884e6d60SXin LI x86emu_halt_sys(emu);
5015884e6d60SXin LI break;
5016884e6d60SXin LI }
5017884e6d60SXin LI if (op1 != 0x26 && op1 != 0x2e && op1 != 0x36 && op1 != 0x3e &&
5018884e6d60SXin LI (op1 | 3) != 0x67)
5019884e6d60SXin LI emu->x86.mode &= ~SYSMODE_CLRMASK;
5020884e6d60SXin LI }
5021884e6d60SXin LI
5022884e6d60SXin LI static void
common_jmp_long(struct x86emu * emu,int cond)5023884e6d60SXin LI common_jmp_long(struct x86emu *emu, int cond)
5024884e6d60SXin LI {
5025884e6d60SXin LI int16_t target;
5026884e6d60SXin LI
5027884e6d60SXin LI target = (int16_t) fetch_word_imm(emu);
5028884e6d60SXin LI target += (int16_t) emu->x86.R_IP;
5029884e6d60SXin LI if (cond)
5030884e6d60SXin LI emu->x86.R_IP = (uint16_t) target;
5031884e6d60SXin LI }
5032884e6d60SXin LI
5033884e6d60SXin LI static void
common_set_byte(struct x86emu * emu,int cond)5034884e6d60SXin LI common_set_byte(struct x86emu *emu, int cond)
5035884e6d60SXin LI {
5036884e6d60SXin LI uint32_t destoffset;
5037884e6d60SXin LI uint8_t *destreg, destval;
5038884e6d60SXin LI
5039884e6d60SXin LI fetch_decode_modrm(emu);
5040884e6d60SXin LI destval = cond ? 0x01 : 0x00;
5041884e6d60SXin LI if (emu->cur_mod != 3) {
5042884e6d60SXin LI destoffset = decode_rl_address(emu);
5043884e6d60SXin LI store_data_byte(emu, destoffset, destval);
5044884e6d60SXin LI } else {
5045884e6d60SXin LI destreg = decode_rl_byte_register(emu);
5046884e6d60SXin LI *destreg = destval;
5047884e6d60SXin LI }
5048884e6d60SXin LI }
5049884e6d60SXin LI
5050884e6d60SXin LI static void
common_bitstring32(struct x86emu * emu,int op)5051884e6d60SXin LI common_bitstring32(struct x86emu *emu, int op)
5052884e6d60SXin LI {
5053884e6d60SXin LI int bit;
5054884e6d60SXin LI uint32_t srcval, *shiftreg, mask;
5055884e6d60SXin LI
5056884e6d60SXin LI fetch_decode_modrm(emu);
5057884e6d60SXin LI shiftreg = decode_rh_long_register(emu);
5058884e6d60SXin LI srcval = decode_and_fetch_long_disp(emu, (int16_t) *shiftreg >> 5);
5059884e6d60SXin LI bit = *shiftreg & 0x1F;
5060884e6d60SXin LI mask = 0x1 << bit;
5061884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
5062884e6d60SXin LI
5063884e6d60SXin LI switch (op) {
5064884e6d60SXin LI case 0:
5065884e6d60SXin LI break;
5066884e6d60SXin LI case 1:
5067884e6d60SXin LI write_back_long(emu, srcval | mask);
5068884e6d60SXin LI break;
5069884e6d60SXin LI case 2:
5070884e6d60SXin LI write_back_long(emu, srcval & ~mask);
5071884e6d60SXin LI break;
5072884e6d60SXin LI case 3:
5073884e6d60SXin LI write_back_long(emu, srcval ^ mask);
5074884e6d60SXin LI break;
5075884e6d60SXin LI }
5076884e6d60SXin LI }
5077884e6d60SXin LI
5078884e6d60SXin LI static void
common_bitstring16(struct x86emu * emu,int op)5079884e6d60SXin LI common_bitstring16(struct x86emu *emu, int op)
5080884e6d60SXin LI {
5081884e6d60SXin LI int bit;
5082884e6d60SXin LI uint16_t srcval, *shiftreg, mask;
5083884e6d60SXin LI
5084884e6d60SXin LI fetch_decode_modrm(emu);
5085884e6d60SXin LI shiftreg = decode_rh_word_register(emu);
5086884e6d60SXin LI srcval = decode_and_fetch_word_disp(emu, (int16_t) *shiftreg >> 4);
5087884e6d60SXin LI bit = *shiftreg & 0xF;
5088884e6d60SXin LI mask = 0x1 << bit;
5089884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
5090884e6d60SXin LI
5091884e6d60SXin LI switch (op) {
5092884e6d60SXin LI case 0:
5093884e6d60SXin LI break;
5094884e6d60SXin LI case 1:
5095884e6d60SXin LI write_back_word(emu, srcval | mask);
5096884e6d60SXin LI break;
5097884e6d60SXin LI case 2:
5098884e6d60SXin LI write_back_word(emu, srcval & ~mask);
5099884e6d60SXin LI break;
5100884e6d60SXin LI case 3:
5101884e6d60SXin LI write_back_word(emu, srcval ^ mask);
5102884e6d60SXin LI break;
5103884e6d60SXin LI }
5104884e6d60SXin LI }
5105884e6d60SXin LI
5106884e6d60SXin LI static void
common_bitstring(struct x86emu * emu,int op)5107884e6d60SXin LI common_bitstring(struct x86emu *emu, int op)
5108884e6d60SXin LI {
5109884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5110884e6d60SXin LI common_bitstring32(emu, op);
5111884e6d60SXin LI else
5112884e6d60SXin LI common_bitstring16(emu, op);
5113884e6d60SXin LI }
5114884e6d60SXin LI
5115884e6d60SXin LI static void
common_bitsearch32(struct x86emu * emu,int diff)5116884e6d60SXin LI common_bitsearch32(struct x86emu *emu, int diff)
5117884e6d60SXin LI {
5118884e6d60SXin LI uint32_t srcval, *dstreg;
5119884e6d60SXin LI
5120884e6d60SXin LI fetch_decode_modrm(emu);
5121884e6d60SXin LI dstreg = decode_rh_long_register(emu);
5122884e6d60SXin LI srcval = decode_and_fetch_long(emu);
5123884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
5124884e6d60SXin LI for (*dstreg = 0; *dstreg < 32; *dstreg += diff) {
5125884e6d60SXin LI if ((srcval >> *dstreg) & 1)
5126884e6d60SXin LI break;
5127884e6d60SXin LI }
5128884e6d60SXin LI }
5129884e6d60SXin LI
5130884e6d60SXin LI static void
common_bitsearch16(struct x86emu * emu,int diff)5131884e6d60SXin LI common_bitsearch16(struct x86emu *emu, int diff)
5132884e6d60SXin LI {
5133884e6d60SXin LI uint16_t srcval, *dstreg;
5134884e6d60SXin LI
5135884e6d60SXin LI fetch_decode_modrm(emu);
5136884e6d60SXin LI dstreg = decode_rh_word_register(emu);
5137884e6d60SXin LI srcval = decode_and_fetch_word(emu);
5138884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
5139884e6d60SXin LI for (*dstreg = 0; *dstreg < 16; *dstreg += diff) {
5140884e6d60SXin LI if ((srcval >> *dstreg) & 1)
5141884e6d60SXin LI break;
5142884e6d60SXin LI }
5143884e6d60SXin LI }
5144884e6d60SXin LI
5145884e6d60SXin LI static void
common_bitsearch(struct x86emu * emu,int diff)5146884e6d60SXin LI common_bitsearch(struct x86emu *emu, int diff)
5147884e6d60SXin LI {
5148884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5149884e6d60SXin LI common_bitsearch32(emu, diff);
5150884e6d60SXin LI else
5151884e6d60SXin LI common_bitsearch16(emu, diff);
5152884e6d60SXin LI }
5153884e6d60SXin LI
5154884e6d60SXin LI static void
common_shift32(struct x86emu * emu,int shift_left,int use_cl)5155884e6d60SXin LI common_shift32(struct x86emu *emu, int shift_left, int use_cl)
5156884e6d60SXin LI {
5157884e6d60SXin LI uint8_t shift;
5158884e6d60SXin LI uint32_t destval, *shiftreg;
5159884e6d60SXin LI
5160884e6d60SXin LI fetch_decode_modrm(emu);
5161884e6d60SXin LI shiftreg = decode_rh_long_register(emu);
5162884e6d60SXin LI if (use_cl) {
5163884e6d60SXin LI destval = decode_and_fetch_long(emu);
5164884e6d60SXin LI shift = emu->x86.R_CL;
5165884e6d60SXin LI } else {
5166884e6d60SXin LI destval = decode_and_fetch_long_imm8(emu, &shift);
5167884e6d60SXin LI }
5168884e6d60SXin LI if (shift_left)
5169884e6d60SXin LI destval = shld_long(emu, destval, *shiftreg, shift);
5170884e6d60SXin LI else
5171884e6d60SXin LI destval = shrd_long(emu, destval, *shiftreg, shift);
5172884e6d60SXin LI write_back_long(emu, destval);
5173884e6d60SXin LI }
5174884e6d60SXin LI
5175884e6d60SXin LI static void
common_shift16(struct x86emu * emu,int shift_left,int use_cl)5176884e6d60SXin LI common_shift16(struct x86emu *emu, int shift_left, int use_cl)
5177884e6d60SXin LI {
5178884e6d60SXin LI uint8_t shift;
5179884e6d60SXin LI uint16_t destval, *shiftreg;
5180884e6d60SXin LI
5181884e6d60SXin LI fetch_decode_modrm(emu);
5182884e6d60SXin LI shiftreg = decode_rh_word_register(emu);
5183884e6d60SXin LI if (use_cl) {
5184884e6d60SXin LI destval = decode_and_fetch_word(emu);
5185884e6d60SXin LI shift = emu->x86.R_CL;
5186884e6d60SXin LI } else {
5187884e6d60SXin LI destval = decode_and_fetch_word_imm8(emu, &shift);
5188884e6d60SXin LI }
5189884e6d60SXin LI if (shift_left)
5190884e6d60SXin LI destval = shld_word(emu, destval, *shiftreg, shift);
5191884e6d60SXin LI else
5192884e6d60SXin LI destval = shrd_word(emu, destval, *shiftreg, shift);
5193884e6d60SXin LI write_back_word(emu, destval);
5194884e6d60SXin LI }
5195884e6d60SXin LI
5196884e6d60SXin LI static void
common_shift(struct x86emu * emu,int shift_left,int use_cl)5197884e6d60SXin LI common_shift(struct x86emu *emu, int shift_left, int use_cl)
5198884e6d60SXin LI {
5199884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5200884e6d60SXin LI common_shift32(emu, shift_left, use_cl);
5201884e6d60SXin LI else
5202884e6d60SXin LI common_shift16(emu, shift_left, use_cl);
5203884e6d60SXin LI }
5204884e6d60SXin LI
520506325fe0SXin LI /*
520606325fe0SXin LI * Implementation
520706325fe0SXin LI */
5208884e6d60SXin LI #define xorl(a,b) ((a) && !(b)) || (!(a) && (b))
5209884e6d60SXin LI
5210884e6d60SXin LI
5211884e6d60SXin LI /*
5212884e6d60SXin LI * REMARKS:
5213884e6d60SXin LI * Handles opcode 0x0f,0x31
5214884e6d60SXin LI */
5215884e6d60SXin LI static void
x86emuOp2_rdtsc(struct x86emu * emu)5216884e6d60SXin LI x86emuOp2_rdtsc(struct x86emu *emu)
5217884e6d60SXin LI {
5218884e6d60SXin LI emu->x86.R_EAX = emu->cur_cycles & 0xffffffff;
5219884e6d60SXin LI emu->x86.R_EDX = emu->cur_cycles >> 32;
5220884e6d60SXin LI }
5221884e6d60SXin LI
5222884e6d60SXin LI /*
5223884e6d60SXin LI * REMARKS:
5224884e6d60SXin LI * Handles opcode 0x0f,0xa0
5225884e6d60SXin LI */
5226884e6d60SXin LI static void
x86emuOp2_push_FS(struct x86emu * emu)5227884e6d60SXin LI x86emuOp2_push_FS(struct x86emu *emu)
5228884e6d60SXin LI {
5229884e6d60SXin LI push_word(emu, emu->x86.R_FS);
5230884e6d60SXin LI }
5231884e6d60SXin LI
5232884e6d60SXin LI /*
5233884e6d60SXin LI * REMARKS:
5234884e6d60SXin LI * Handles opcode 0x0f,0xa1
5235884e6d60SXin LI */
5236884e6d60SXin LI static void
x86emuOp2_pop_FS(struct x86emu * emu)5237884e6d60SXin LI x86emuOp2_pop_FS(struct x86emu *emu)
5238884e6d60SXin LI {
5239884e6d60SXin LI emu->x86.R_FS = pop_word(emu);
5240884e6d60SXin LI }
5241884e6d60SXin LI
5242884e6d60SXin LI /*
5243884e6d60SXin LI * REMARKS:
5244884e6d60SXin LI * Handles opcode 0x0f,0xa1
5245884e6d60SXin LI */
5246884e6d60SXin LI #if defined(__i386__) || defined(__amd64__)
5247884e6d60SXin LI static void
hw_cpuid(uint32_t * a,uint32_t * b,uint32_t * c,uint32_t * d)5248884e6d60SXin LI hw_cpuid(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
5249884e6d60SXin LI {
5250687a306fSXin LI __asm__ volatile("cpuid"
5251884e6d60SXin LI : "=a" (*a), "=b" (*b),
5252884e6d60SXin LI "=c" (*c), "=d" (*d)
5253884e6d60SXin LI : "a" (*a), "c" (*c)
5254884e6d60SXin LI : "cc");
5255884e6d60SXin LI }
5256884e6d60SXin LI #endif
5257884e6d60SXin LI static void
x86emuOp2_cpuid(struct x86emu * emu)5258884e6d60SXin LI x86emuOp2_cpuid(struct x86emu *emu)
5259884e6d60SXin LI {
5260884e6d60SXin LI #if defined(__i386__) || defined(__amd64__)
5261884e6d60SXin LI hw_cpuid(&emu->x86.R_EAX, &emu->x86.R_EBX, &emu->x86.R_ECX,
5262884e6d60SXin LI &emu->x86.R_EDX);
5263884e6d60SXin LI #endif
5264884e6d60SXin LI switch (emu->x86.R_EAX) {
5265884e6d60SXin LI case 0:
5266884e6d60SXin LI emu->x86.R_EAX = 1;
5267884e6d60SXin LI #if !defined(__i386__) && !defined(__amd64__)
5268884e6d60SXin LI /* "GenuineIntel" */
5269884e6d60SXin LI emu->x86.R_EBX = 0x756e6547;
5270884e6d60SXin LI emu->x86.R_EDX = 0x49656e69;
5271884e6d60SXin LI emu->x86.R_ECX = 0x6c65746e;
5272884e6d60SXin LI #endif
5273884e6d60SXin LI break;
5274884e6d60SXin LI case 1:
5275884e6d60SXin LI #if !defined(__i386__) && !defined(__amd64__)
5276884e6d60SXin LI emu->x86.R_EAX = 0x00000480;
5277884e6d60SXin LI emu->x86.R_EBX = emu->x86.R_ECX = 0;
5278884e6d60SXin LI emu->x86.R_EDX = 0x00000002;
5279884e6d60SXin LI #else
5280884e6d60SXin LI emu->x86.R_EDX &= 0x00000012;
5281884e6d60SXin LI #endif
5282884e6d60SXin LI break;
5283884e6d60SXin LI default:
5284884e6d60SXin LI emu->x86.R_EAX = emu->x86.R_EBX = emu->x86.R_ECX =
5285884e6d60SXin LI emu->x86.R_EDX = 0;
5286884e6d60SXin LI break;
5287884e6d60SXin LI }
5288884e6d60SXin LI }
5289884e6d60SXin LI
5290884e6d60SXin LI /*
5291884e6d60SXin LI * REMARKS:
5292884e6d60SXin LI * Handles opcode 0x0f,0xa3
5293884e6d60SXin LI */
5294884e6d60SXin LI static void
x86emuOp2_bt_R(struct x86emu * emu)5295884e6d60SXin LI x86emuOp2_bt_R(struct x86emu *emu)
5296884e6d60SXin LI {
5297884e6d60SXin LI common_bitstring(emu, 0);
5298884e6d60SXin LI }
5299884e6d60SXin LI
5300884e6d60SXin LI /*
5301884e6d60SXin LI * REMARKS:
5302884e6d60SXin LI * Handles opcode 0x0f,0xa4
5303884e6d60SXin LI */
5304884e6d60SXin LI static void
x86emuOp2_shld_IMM(struct x86emu * emu)5305884e6d60SXin LI x86emuOp2_shld_IMM(struct x86emu *emu)
5306884e6d60SXin LI {
5307884e6d60SXin LI common_shift(emu, 1, 0);
5308884e6d60SXin LI }
5309884e6d60SXin LI
5310884e6d60SXin LI /*
5311884e6d60SXin LI * REMARKS:
5312884e6d60SXin LI * Handles opcode 0x0f,0xa5
5313884e6d60SXin LI */
5314884e6d60SXin LI static void
x86emuOp2_shld_CL(struct x86emu * emu)5315884e6d60SXin LI x86emuOp2_shld_CL(struct x86emu *emu)
5316884e6d60SXin LI {
5317884e6d60SXin LI common_shift(emu, 1, 1);
5318884e6d60SXin LI }
5319884e6d60SXin LI
5320884e6d60SXin LI /*
5321884e6d60SXin LI * REMARKS:
5322884e6d60SXin LI * Handles opcode 0x0f,0xa8
5323884e6d60SXin LI */
5324884e6d60SXin LI static void
x86emuOp2_push_GS(struct x86emu * emu)5325884e6d60SXin LI x86emuOp2_push_GS(struct x86emu *emu)
5326884e6d60SXin LI {
5327884e6d60SXin LI push_word(emu, emu->x86.R_GS);
5328884e6d60SXin LI }
5329884e6d60SXin LI
5330884e6d60SXin LI /*
5331884e6d60SXin LI * REMARKS:
5332884e6d60SXin LI * Handles opcode 0x0f,0xa9
5333884e6d60SXin LI */
5334884e6d60SXin LI static void
x86emuOp2_pop_GS(struct x86emu * emu)5335884e6d60SXin LI x86emuOp2_pop_GS(struct x86emu *emu)
5336884e6d60SXin LI {
5337884e6d60SXin LI emu->x86.R_GS = pop_word(emu);
5338884e6d60SXin LI }
5339884e6d60SXin LI
5340884e6d60SXin LI /*
5341884e6d60SXin LI * REMARKS:
5342884e6d60SXin LI * Handles opcode 0x0f,0xab
5343884e6d60SXin LI */
5344884e6d60SXin LI static void
x86emuOp2_bts_R(struct x86emu * emu)5345884e6d60SXin LI x86emuOp2_bts_R(struct x86emu *emu)
5346884e6d60SXin LI {
5347884e6d60SXin LI common_bitstring(emu, 1);
5348884e6d60SXin LI }
5349884e6d60SXin LI
5350884e6d60SXin LI /*
5351884e6d60SXin LI * REMARKS:
5352884e6d60SXin LI * Handles opcode 0x0f,0xac
5353884e6d60SXin LI */
5354884e6d60SXin LI static void
x86emuOp2_shrd_IMM(struct x86emu * emu)5355884e6d60SXin LI x86emuOp2_shrd_IMM(struct x86emu *emu)
5356884e6d60SXin LI {
5357884e6d60SXin LI common_shift(emu, 0, 0);
5358884e6d60SXin LI }
5359884e6d60SXin LI
5360884e6d60SXin LI /*
5361884e6d60SXin LI * REMARKS:
5362884e6d60SXin LI * Handles opcode 0x0f,0xad
5363884e6d60SXin LI */
5364884e6d60SXin LI static void
x86emuOp2_shrd_CL(struct x86emu * emu)5365884e6d60SXin LI x86emuOp2_shrd_CL(struct x86emu *emu)
5366884e6d60SXin LI {
5367884e6d60SXin LI common_shift(emu, 0, 1);
5368884e6d60SXin LI }
5369884e6d60SXin LI
5370884e6d60SXin LI /*
5371884e6d60SXin LI * REMARKS:
5372884e6d60SXin LI * Handles opcode 0x0f,0xaf
5373884e6d60SXin LI */
5374884e6d60SXin LI static void
x86emuOp2_32_imul_R_RM(struct x86emu * emu)5375884e6d60SXin LI x86emuOp2_32_imul_R_RM(struct x86emu *emu)
5376884e6d60SXin LI {
5377884e6d60SXin LI uint32_t *destreg, srcval;
5378884e6d60SXin LI uint64_t res;
5379884e6d60SXin LI
5380884e6d60SXin LI fetch_decode_modrm(emu);
5381884e6d60SXin LI destreg = decode_rh_long_register(emu);
5382884e6d60SXin LI srcval = decode_and_fetch_long(emu);
5383884e6d60SXin LI res = (int32_t) *destreg * (int32_t)srcval;
5384884e6d60SXin LI if (res > 0xffffffff) {
5385884e6d60SXin LI SET_FLAG(F_CF);
5386884e6d60SXin LI SET_FLAG(F_OF);
5387884e6d60SXin LI } else {
5388884e6d60SXin LI CLEAR_FLAG(F_CF);
5389884e6d60SXin LI CLEAR_FLAG(F_OF);
5390884e6d60SXin LI }
5391884e6d60SXin LI *destreg = (uint32_t) res;
5392884e6d60SXin LI }
5393884e6d60SXin LI
5394884e6d60SXin LI static void
x86emuOp2_16_imul_R_RM(struct x86emu * emu)5395884e6d60SXin LI x86emuOp2_16_imul_R_RM(struct x86emu *emu)
5396884e6d60SXin LI {
5397884e6d60SXin LI uint16_t *destreg, srcval;
5398884e6d60SXin LI uint32_t res;
5399884e6d60SXin LI
5400884e6d60SXin LI fetch_decode_modrm(emu);
5401884e6d60SXin LI destreg = decode_rh_word_register(emu);
5402884e6d60SXin LI srcval = decode_and_fetch_word(emu);
5403884e6d60SXin LI res = (int16_t) * destreg * (int16_t)srcval;
5404884e6d60SXin LI if (res > 0xFFFF) {
5405884e6d60SXin LI SET_FLAG(F_CF);
5406884e6d60SXin LI SET_FLAG(F_OF);
5407884e6d60SXin LI } else {
5408884e6d60SXin LI CLEAR_FLAG(F_CF);
5409884e6d60SXin LI CLEAR_FLAG(F_OF);
5410884e6d60SXin LI }
5411884e6d60SXin LI *destreg = (uint16_t) res;
5412884e6d60SXin LI }
5413884e6d60SXin LI
5414884e6d60SXin LI static void
x86emuOp2_imul_R_RM(struct x86emu * emu)5415884e6d60SXin LI x86emuOp2_imul_R_RM(struct x86emu *emu)
5416884e6d60SXin LI {
5417884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5418884e6d60SXin LI x86emuOp2_32_imul_R_RM(emu);
5419884e6d60SXin LI else
5420884e6d60SXin LI x86emuOp2_16_imul_R_RM(emu);
5421884e6d60SXin LI }
5422884e6d60SXin LI
5423884e6d60SXin LI /*
5424884e6d60SXin LI * REMARKS:
5425884e6d60SXin LI * Handles opcode 0x0f,0xb2
5426884e6d60SXin LI */
5427884e6d60SXin LI static void
x86emuOp2_lss_R_IMM(struct x86emu * emu)5428884e6d60SXin LI x86emuOp2_lss_R_IMM(struct x86emu *emu)
5429884e6d60SXin LI {
5430884e6d60SXin LI common_load_far_pointer(emu, &emu->x86.R_SS);
5431884e6d60SXin LI }
5432884e6d60SXin LI
5433884e6d60SXin LI /*
5434884e6d60SXin LI * REMARKS:
5435884e6d60SXin LI * Handles opcode 0x0f,0xb3
5436884e6d60SXin LI */
5437884e6d60SXin LI static void
x86emuOp2_btr_R(struct x86emu * emu)5438884e6d60SXin LI x86emuOp2_btr_R(struct x86emu *emu)
5439884e6d60SXin LI {
5440884e6d60SXin LI common_bitstring(emu, 2);
5441884e6d60SXin LI }
5442884e6d60SXin LI
5443884e6d60SXin LI /*
5444884e6d60SXin LI * REMARKS:
5445884e6d60SXin LI * Handles opcode 0x0f,0xb4
5446884e6d60SXin LI */
5447884e6d60SXin LI static void
x86emuOp2_lfs_R_IMM(struct x86emu * emu)5448884e6d60SXin LI x86emuOp2_lfs_R_IMM(struct x86emu *emu)
5449884e6d60SXin LI {
5450884e6d60SXin LI common_load_far_pointer(emu, &emu->x86.R_FS);
5451884e6d60SXin LI }
5452884e6d60SXin LI
5453884e6d60SXin LI /*
5454884e6d60SXin LI * REMARKS:
5455884e6d60SXin LI * Handles opcode 0x0f,0xb5
5456884e6d60SXin LI */
5457884e6d60SXin LI static void
x86emuOp2_lgs_R_IMM(struct x86emu * emu)5458884e6d60SXin LI x86emuOp2_lgs_R_IMM(struct x86emu *emu)
5459884e6d60SXin LI {
5460884e6d60SXin LI common_load_far_pointer(emu, &emu->x86.R_GS);
5461884e6d60SXin LI }
5462884e6d60SXin LI
5463884e6d60SXin LI /*
5464884e6d60SXin LI * REMARKS:
5465884e6d60SXin LI * Handles opcode 0x0f,0xb6
5466884e6d60SXin LI */
5467884e6d60SXin LI static void
x86emuOp2_32_movzx_byte_R_RM(struct x86emu * emu)5468884e6d60SXin LI x86emuOp2_32_movzx_byte_R_RM(struct x86emu *emu)
5469884e6d60SXin LI {
5470884e6d60SXin LI uint32_t *destreg;
5471884e6d60SXin LI
5472884e6d60SXin LI fetch_decode_modrm(emu);
5473884e6d60SXin LI destreg = decode_rh_long_register(emu);
5474884e6d60SXin LI *destreg = decode_and_fetch_byte(emu);
5475884e6d60SXin LI }
5476884e6d60SXin LI
5477884e6d60SXin LI static void
x86emuOp2_16_movzx_byte_R_RM(struct x86emu * emu)5478884e6d60SXin LI x86emuOp2_16_movzx_byte_R_RM(struct x86emu *emu)
5479884e6d60SXin LI {
5480884e6d60SXin LI uint16_t *destreg;
5481884e6d60SXin LI
5482884e6d60SXin LI fetch_decode_modrm(emu);
5483884e6d60SXin LI destreg = decode_rh_word_register(emu);
5484884e6d60SXin LI *destreg = decode_and_fetch_byte(emu);
5485884e6d60SXin LI }
5486884e6d60SXin LI
5487884e6d60SXin LI static void
x86emuOp2_movzx_byte_R_RM(struct x86emu * emu)5488884e6d60SXin LI x86emuOp2_movzx_byte_R_RM(struct x86emu *emu)
5489884e6d60SXin LI {
5490884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5491884e6d60SXin LI x86emuOp2_32_movzx_byte_R_RM(emu);
5492884e6d60SXin LI else
5493884e6d60SXin LI x86emuOp2_16_movzx_byte_R_RM(emu);
5494884e6d60SXin LI }
5495884e6d60SXin LI
5496884e6d60SXin LI /*
5497884e6d60SXin LI * REMARKS:
5498884e6d60SXin LI * Handles opcode 0x0f,0xb7
5499884e6d60SXin LI */
5500884e6d60SXin LI static void
x86emuOp2_movzx_word_R_RM(struct x86emu * emu)5501884e6d60SXin LI x86emuOp2_movzx_word_R_RM(struct x86emu *emu)
5502884e6d60SXin LI {
5503884e6d60SXin LI uint32_t *destreg;
5504884e6d60SXin LI
5505884e6d60SXin LI fetch_decode_modrm(emu);
5506884e6d60SXin LI destreg = decode_rh_long_register(emu);
5507884e6d60SXin LI *destreg = decode_and_fetch_word(emu);
5508884e6d60SXin LI }
5509884e6d60SXin LI
5510884e6d60SXin LI /*
5511884e6d60SXin LI * REMARKS:
5512884e6d60SXin LI * Handles opcode 0x0f,0xba
5513884e6d60SXin LI */
5514884e6d60SXin LI static void
x86emuOp2_32_btX_I(struct x86emu * emu)5515884e6d60SXin LI x86emuOp2_32_btX_I(struct x86emu *emu)
5516884e6d60SXin LI {
5517884e6d60SXin LI int bit;
5518884e6d60SXin LI uint32_t srcval, mask;
5519884e6d60SXin LI uint8_t shift;
5520884e6d60SXin LI
5521884e6d60SXin LI fetch_decode_modrm(emu);
5522884e6d60SXin LI if (emu->cur_rh < 4)
5523884e6d60SXin LI x86emu_halt_sys(emu);
5524884e6d60SXin LI
5525884e6d60SXin LI srcval = decode_and_fetch_long_imm8(emu, &shift);
5526884e6d60SXin LI bit = shift & 0x1F;
5527884e6d60SXin LI mask = (0x1 << bit);
5528884e6d60SXin LI
5529884e6d60SXin LI switch (emu->cur_rh) {
5530884e6d60SXin LI case 5:
5531884e6d60SXin LI write_back_long(emu, srcval | mask);
5532884e6d60SXin LI break;
5533884e6d60SXin LI case 6:
5534884e6d60SXin LI write_back_long(emu, srcval & ~mask);
5535884e6d60SXin LI break;
5536884e6d60SXin LI case 7:
5537884e6d60SXin LI write_back_long(emu, srcval ^ mask);
5538884e6d60SXin LI break;
5539884e6d60SXin LI }
5540884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
5541884e6d60SXin LI }
5542884e6d60SXin LI
5543884e6d60SXin LI static void
x86emuOp2_16_btX_I(struct x86emu * emu)5544884e6d60SXin LI x86emuOp2_16_btX_I(struct x86emu *emu)
5545884e6d60SXin LI {
5546884e6d60SXin LI int bit;
5547884e6d60SXin LI
5548884e6d60SXin LI uint16_t srcval, mask;
5549884e6d60SXin LI uint8_t shift;
5550884e6d60SXin LI
5551884e6d60SXin LI fetch_decode_modrm(emu);
5552884e6d60SXin LI if (emu->cur_rh < 4)
5553884e6d60SXin LI x86emu_halt_sys(emu);
5554884e6d60SXin LI
5555884e6d60SXin LI srcval = decode_and_fetch_word_imm8(emu, &shift);
5556884e6d60SXin LI bit = shift & 0xF;
5557884e6d60SXin LI mask = (0x1 << bit);
5558884e6d60SXin LI switch (emu->cur_rh) {
5559884e6d60SXin LI case 5:
5560884e6d60SXin LI write_back_word(emu, srcval | mask);
5561884e6d60SXin LI break;
5562884e6d60SXin LI case 6:
5563884e6d60SXin LI write_back_word(emu, srcval & ~mask);
5564884e6d60SXin LI break;
5565884e6d60SXin LI case 7:
5566884e6d60SXin LI write_back_word(emu, srcval ^ mask);
5567884e6d60SXin LI break;
5568884e6d60SXin LI }
5569884e6d60SXin LI CONDITIONAL_SET_FLAG(srcval & mask, F_CF);
5570884e6d60SXin LI }
5571884e6d60SXin LI
5572884e6d60SXin LI static void
x86emuOp2_btX_I(struct x86emu * emu)5573884e6d60SXin LI x86emuOp2_btX_I(struct x86emu *emu)
5574884e6d60SXin LI {
5575884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5576884e6d60SXin LI x86emuOp2_32_btX_I(emu);
5577884e6d60SXin LI else
5578884e6d60SXin LI x86emuOp2_16_btX_I(emu);
5579884e6d60SXin LI }
5580884e6d60SXin LI
5581884e6d60SXin LI /*
5582884e6d60SXin LI * REMARKS:
5583884e6d60SXin LI * Handles opcode 0x0f,0xbb
5584884e6d60SXin LI */
5585884e6d60SXin LI static void
x86emuOp2_btc_R(struct x86emu * emu)5586884e6d60SXin LI x86emuOp2_btc_R(struct x86emu *emu)
5587884e6d60SXin LI {
5588884e6d60SXin LI common_bitstring(emu, 3);
5589884e6d60SXin LI }
5590884e6d60SXin LI
5591884e6d60SXin LI /*
5592884e6d60SXin LI * REMARKS:
5593884e6d60SXin LI * Handles opcode 0x0f,0xbc
5594884e6d60SXin LI */
5595884e6d60SXin LI static void
x86emuOp2_bsf(struct x86emu * emu)5596884e6d60SXin LI x86emuOp2_bsf(struct x86emu *emu)
5597884e6d60SXin LI {
5598884e6d60SXin LI common_bitsearch(emu, +1);
5599884e6d60SXin LI }
5600884e6d60SXin LI
5601884e6d60SXin LI /*
5602884e6d60SXin LI * REMARKS:
5603884e6d60SXin LI * Handles opcode 0x0f,0xbd
5604884e6d60SXin LI */
5605884e6d60SXin LI static void
x86emuOp2_bsr(struct x86emu * emu)5606884e6d60SXin LI x86emuOp2_bsr(struct x86emu *emu)
5607884e6d60SXin LI {
5608884e6d60SXin LI common_bitsearch(emu, -1);
5609884e6d60SXin LI }
5610884e6d60SXin LI
5611884e6d60SXin LI /*
5612884e6d60SXin LI * REMARKS:
5613884e6d60SXin LI * Handles opcode 0x0f,0xbe
5614884e6d60SXin LI */
5615884e6d60SXin LI static void
x86emuOp2_32_movsx_byte_R_RM(struct x86emu * emu)5616884e6d60SXin LI x86emuOp2_32_movsx_byte_R_RM(struct x86emu *emu)
5617884e6d60SXin LI {
5618884e6d60SXin LI uint32_t *destreg;
5619884e6d60SXin LI
562050976055SXin LI fetch_decode_modrm(emu);
5621884e6d60SXin LI destreg = decode_rh_long_register(emu);
5622884e6d60SXin LI *destreg = (int32_t)(int8_t)decode_and_fetch_byte(emu);
5623884e6d60SXin LI }
5624884e6d60SXin LI
5625884e6d60SXin LI static void
x86emuOp2_16_movsx_byte_R_RM(struct x86emu * emu)5626884e6d60SXin LI x86emuOp2_16_movsx_byte_R_RM(struct x86emu *emu)
5627884e6d60SXin LI {
5628884e6d60SXin LI uint16_t *destreg;
5629884e6d60SXin LI
5630884e6d60SXin LI fetch_decode_modrm(emu);
5631884e6d60SXin LI destreg = decode_rh_word_register(emu);
5632884e6d60SXin LI *destreg = (int16_t)(int8_t)decode_and_fetch_byte(emu);
5633884e6d60SXin LI }
5634884e6d60SXin LI
5635884e6d60SXin LI static void
x86emuOp2_movsx_byte_R_RM(struct x86emu * emu)5636884e6d60SXin LI x86emuOp2_movsx_byte_R_RM(struct x86emu *emu)
5637884e6d60SXin LI {
5638884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA)
5639884e6d60SXin LI x86emuOp2_32_movsx_byte_R_RM(emu);
5640884e6d60SXin LI else
5641884e6d60SXin LI x86emuOp2_16_movsx_byte_R_RM(emu);
5642884e6d60SXin LI }
5643884e6d60SXin LI
5644884e6d60SXin LI /*
5645884e6d60SXin LI * REMARKS:
5646884e6d60SXin LI * Handles opcode 0x0f,0xbf
5647884e6d60SXin LI */
5648884e6d60SXin LI static void
x86emuOp2_movsx_word_R_RM(struct x86emu * emu)5649884e6d60SXin LI x86emuOp2_movsx_word_R_RM(struct x86emu *emu)
5650884e6d60SXin LI {
5651884e6d60SXin LI uint32_t *destreg;
5652884e6d60SXin LI
5653884e6d60SXin LI fetch_decode_modrm(emu);
5654884e6d60SXin LI destreg = decode_rh_long_register(emu);
5655884e6d60SXin LI *destreg = (int32_t)(int16_t)decode_and_fetch_word(emu);
5656884e6d60SXin LI }
5657884e6d60SXin LI
5658884e6d60SXin LI static void
x86emu_exec_two_byte(struct x86emu * emu)5659884e6d60SXin LI x86emu_exec_two_byte(struct x86emu * emu)
5660884e6d60SXin LI {
5661884e6d60SXin LI uint8_t op2;
5662884e6d60SXin LI
5663884e6d60SXin LI op2 = fetch_byte_imm(emu);
5664884e6d60SXin LI
5665884e6d60SXin LI switch (op2) {
5666884e6d60SXin LI /* 0x00 Group F (ring 0 PM) */
5667884e6d60SXin LI /* 0x01 Group G (ring 0 PM) */
5668884e6d60SXin LI /* 0x02 lar (ring 0 PM) */
5669884e6d60SXin LI /* 0x03 lsl (ring 0 PM) */
5670884e6d60SXin LI /* 0x05 loadall (undocumented) */
5671884e6d60SXin LI /* 0x06 clts (ring 0 PM) */
5672884e6d60SXin LI /* 0x07 loadall (undocumented) */
5673884e6d60SXin LI /* 0x08 invd (ring 0 PM) */
5674884e6d60SXin LI /* 0x09 wbinvd (ring 0 PM) */
5675884e6d60SXin LI
5676884e6d60SXin LI /* 0x20 mov reg32(op2); break;creg (ring 0 PM) */
5677884e6d60SXin LI /* 0x21 mov reg32(op2); break;dreg (ring 0 PM) */
5678884e6d60SXin LI /* 0x22 mov creg(op2); break;reg32 (ring 0 PM) */
5679884e6d60SXin LI /* 0x23 mov dreg(op2); break;reg32 (ring 0 PM) */
5680884e6d60SXin LI /* 0x24 mov reg32(op2); break;treg (ring 0 PM) */
5681884e6d60SXin LI /* 0x26 mov treg(op2); break;reg32 (ring 0 PM) */
5682884e6d60SXin LI
5683884e6d60SXin LI case 0x31:
5684884e6d60SXin LI x86emuOp2_rdtsc(emu);
5685884e6d60SXin LI break;
5686884e6d60SXin LI
5687884e6d60SXin LI case 0x80:
5688884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_OF));
5689884e6d60SXin LI break;
5690884e6d60SXin LI case 0x81:
5691884e6d60SXin LI common_jmp_long(emu, !ACCESS_FLAG(F_OF));
5692884e6d60SXin LI break;
5693884e6d60SXin LI case 0x82:
5694884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_CF));
5695884e6d60SXin LI break;
5696884e6d60SXin LI case 0x83:
5697884e6d60SXin LI common_jmp_long(emu, !ACCESS_FLAG(F_CF));
5698884e6d60SXin LI break;
5699884e6d60SXin LI case 0x84:
5700884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_ZF));
5701884e6d60SXin LI break;
5702884e6d60SXin LI case 0x85:
5703884e6d60SXin LI common_jmp_long(emu, !ACCESS_FLAG(F_ZF));
5704884e6d60SXin LI break;
5705884e6d60SXin LI case 0x86:
5706884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
5707884e6d60SXin LI break;
5708884e6d60SXin LI case 0x87:
5709884e6d60SXin LI common_jmp_long(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
5710884e6d60SXin LI break;
5711884e6d60SXin LI case 0x88:
5712884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_SF));
5713884e6d60SXin LI break;
5714884e6d60SXin LI case 0x89:
5715884e6d60SXin LI common_jmp_long(emu, !ACCESS_FLAG(F_SF));
5716884e6d60SXin LI break;
5717884e6d60SXin LI case 0x8a:
5718884e6d60SXin LI common_jmp_long(emu, ACCESS_FLAG(F_PF));
5719884e6d60SXin LI break;
5720884e6d60SXin LI case 0x8b:
5721884e6d60SXin LI common_jmp_long(emu, !ACCESS_FLAG(F_PF));
5722884e6d60SXin LI break;
5723884e6d60SXin LI case 0x8c:
572406325fe0SXin LI common_jmp_long(emu, xorl(ACCESS_FLAG(F_SF),
572506325fe0SXin LI ACCESS_FLAG(F_OF)));
5726884e6d60SXin LI break;
5727884e6d60SXin LI case 0x8d:
572806325fe0SXin LI common_jmp_long(emu, !(xorl(ACCESS_FLAG(F_SF),
572906325fe0SXin LI ACCESS_FLAG(F_OF))));
5730884e6d60SXin LI break;
5731884e6d60SXin LI case 0x8e:
573206325fe0SXin LI common_jmp_long(emu, (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF))
573306325fe0SXin LI || ACCESS_FLAG(F_ZF)));
5734884e6d60SXin LI break;
5735884e6d60SXin LI case 0x8f:
5736884e6d60SXin LI common_jmp_long(emu,
573706325fe0SXin LI !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
573806325fe0SXin LI ACCESS_FLAG(F_ZF)));
5739884e6d60SXin LI break;
5740884e6d60SXin LI
5741884e6d60SXin LI case 0x90:
5742884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_OF));
5743884e6d60SXin LI break;
5744884e6d60SXin LI case 0x91:
5745884e6d60SXin LI common_set_byte(emu, !ACCESS_FLAG(F_OF));
5746884e6d60SXin LI break;
5747884e6d60SXin LI case 0x92:
5748884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_CF));
5749884e6d60SXin LI break;
5750884e6d60SXin LI case 0x93:
5751884e6d60SXin LI common_set_byte(emu, !ACCESS_FLAG(F_CF));
5752884e6d60SXin LI break;
5753884e6d60SXin LI case 0x94:
5754884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_ZF));
5755884e6d60SXin LI break;
5756884e6d60SXin LI case 0x95:
5757884e6d60SXin LI common_set_byte(emu, !ACCESS_FLAG(F_ZF));
5758884e6d60SXin LI break;
5759884e6d60SXin LI case 0x96:
5760884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
5761884e6d60SXin LI break;
5762884e6d60SXin LI case 0x97:
5763884e6d60SXin LI common_set_byte(emu, !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)));
5764884e6d60SXin LI break;
5765884e6d60SXin LI case 0x98:
5766884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_SF));
5767884e6d60SXin LI break;
5768884e6d60SXin LI case 0x99:
5769884e6d60SXin LI common_set_byte(emu, !ACCESS_FLAG(F_SF));
5770884e6d60SXin LI break;
5771884e6d60SXin LI case 0x9a:
5772884e6d60SXin LI common_set_byte(emu, ACCESS_FLAG(F_PF));
5773884e6d60SXin LI break;
5774884e6d60SXin LI case 0x9b:
5775884e6d60SXin LI common_set_byte(emu, !ACCESS_FLAG(F_PF));
5776884e6d60SXin LI break;
5777884e6d60SXin LI case 0x9c:
577806325fe0SXin LI common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
577906325fe0SXin LI ACCESS_FLAG(F_OF)));
5780884e6d60SXin LI break;
5781884e6d60SXin LI case 0x9d:
578206325fe0SXin LI common_set_byte(emu, xorl(ACCESS_FLAG(F_SF),
578306325fe0SXin LI ACCESS_FLAG(F_OF)));
5784884e6d60SXin LI break;
5785884e6d60SXin LI case 0x9e:
5786884e6d60SXin LI common_set_byte(emu,
5787884e6d60SXin LI (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
5788884e6d60SXin LI ACCESS_FLAG(F_ZF)));
5789884e6d60SXin LI break;
5790884e6d60SXin LI case 0x9f:
5791884e6d60SXin LI common_set_byte(emu,
5792884e6d60SXin LI !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
5793884e6d60SXin LI ACCESS_FLAG(F_ZF)));
5794884e6d60SXin LI break;
5795884e6d60SXin LI
5796884e6d60SXin LI case 0xa0:
5797884e6d60SXin LI x86emuOp2_push_FS(emu);
5798884e6d60SXin LI break;
5799884e6d60SXin LI case 0xa1:
5800884e6d60SXin LI x86emuOp2_pop_FS(emu);
5801884e6d60SXin LI break;
5802884e6d60SXin LI case 0xa2:
5803884e6d60SXin LI x86emuOp2_cpuid(emu);
5804884e6d60SXin LI break;
5805884e6d60SXin LI case 0xa3:
5806884e6d60SXin LI x86emuOp2_bt_R(emu);
5807884e6d60SXin LI break;
5808884e6d60SXin LI case 0xa4:
5809884e6d60SXin LI x86emuOp2_shld_IMM(emu);
5810884e6d60SXin LI break;
5811884e6d60SXin LI case 0xa5:
5812884e6d60SXin LI x86emuOp2_shld_CL(emu);
5813884e6d60SXin LI break;
5814884e6d60SXin LI case 0xa8:
5815884e6d60SXin LI x86emuOp2_push_GS(emu);
5816884e6d60SXin LI break;
5817884e6d60SXin LI case 0xa9:
5818884e6d60SXin LI x86emuOp2_pop_GS(emu);
5819884e6d60SXin LI break;
5820884e6d60SXin LI case 0xab:
5821884e6d60SXin LI x86emuOp2_bts_R(emu);
5822884e6d60SXin LI break;
5823884e6d60SXin LI case 0xac:
5824884e6d60SXin LI x86emuOp2_shrd_IMM(emu);
5825884e6d60SXin LI break;
5826884e6d60SXin LI case 0xad:
5827884e6d60SXin LI x86emuOp2_shrd_CL(emu);
5828884e6d60SXin LI break;
5829884e6d60SXin LI case 0xaf:
5830884e6d60SXin LI x86emuOp2_imul_R_RM(emu);
5831884e6d60SXin LI break;
5832884e6d60SXin LI
5833884e6d60SXin LI /* 0xb0 TODO: cmpxchg */
5834884e6d60SXin LI /* 0xb1 TODO: cmpxchg */
5835884e6d60SXin LI case 0xb2:
5836884e6d60SXin LI x86emuOp2_lss_R_IMM(emu);
5837884e6d60SXin LI break;
5838884e6d60SXin LI case 0xb3:
5839884e6d60SXin LI x86emuOp2_btr_R(emu);
5840884e6d60SXin LI break;
5841884e6d60SXin LI case 0xb4:
5842884e6d60SXin LI x86emuOp2_lfs_R_IMM(emu);
5843884e6d60SXin LI break;
5844884e6d60SXin LI case 0xb5:
5845884e6d60SXin LI x86emuOp2_lgs_R_IMM(emu);
5846884e6d60SXin LI break;
5847884e6d60SXin LI case 0xb6:
5848884e6d60SXin LI x86emuOp2_movzx_byte_R_RM(emu);
5849884e6d60SXin LI break;
5850884e6d60SXin LI case 0xb7:
5851884e6d60SXin LI x86emuOp2_movzx_word_R_RM(emu);
5852884e6d60SXin LI break;
5853884e6d60SXin LI case 0xba:
5854884e6d60SXin LI x86emuOp2_btX_I(emu);
5855884e6d60SXin LI break;
5856884e6d60SXin LI case 0xbb:
5857884e6d60SXin LI x86emuOp2_btc_R(emu);
5858884e6d60SXin LI break;
5859884e6d60SXin LI case 0xbc:
5860884e6d60SXin LI x86emuOp2_bsf(emu);
5861884e6d60SXin LI break;
5862884e6d60SXin LI case 0xbd:
5863884e6d60SXin LI x86emuOp2_bsr(emu);
5864884e6d60SXin LI break;
5865884e6d60SXin LI case 0xbe:
5866884e6d60SXin LI x86emuOp2_movsx_byte_R_RM(emu);
5867884e6d60SXin LI break;
5868884e6d60SXin LI case 0xbf:
5869884e6d60SXin LI x86emuOp2_movsx_word_R_RM(emu);
5870884e6d60SXin LI break;
5871884e6d60SXin LI
5872884e6d60SXin LI /* 0xc0 TODO: xadd */
5873884e6d60SXin LI /* 0xc1 TODO: xadd */
5874884e6d60SXin LI /* 0xc8 TODO: bswap */
5875884e6d60SXin LI /* 0xc9 TODO: bswap */
5876884e6d60SXin LI /* 0xca TODO: bswap */
5877884e6d60SXin LI /* 0xcb TODO: bswap */
5878884e6d60SXin LI /* 0xcc TODO: bswap */
5879884e6d60SXin LI /* 0xcd TODO: bswap */
5880884e6d60SXin LI /* 0xce TODO: bswap */
5881884e6d60SXin LI /* 0xcf TODO: bswap */
5882884e6d60SXin LI
5883884e6d60SXin LI default:
5884884e6d60SXin LI x86emu_halt_sys(emu);
5885884e6d60SXin LI break;
5886884e6d60SXin LI }
5887884e6d60SXin LI }
5888884e6d60SXin LI
5889884e6d60SXin LI /*
5890884e6d60SXin LI * Carry Chain Calculation
5891884e6d60SXin LI *
5892884e6d60SXin LI * This represents a somewhat expensive calculation which is
5893884e6d60SXin LI * apparently required to emulate the setting of the OF and AF flag.
5894884e6d60SXin LI * The latter is not so important, but the former is. The overflow
5895884e6d60SXin LI * flag is the XOR of the top two bits of the carry chain for an
5896884e6d60SXin LI * addition (similar for subtraction). Since we do not want to
5897884e6d60SXin LI * simulate the addition in a bitwise manner, we try to calculate the
5898884e6d60SXin LI * carry chain given the two operands and the result.
5899884e6d60SXin LI *
5900884e6d60SXin LI * So, given the following table, which represents the addition of two
5901884e6d60SXin LI * bits, we can derive a formula for the carry chain.
5902884e6d60SXin LI *
5903884e6d60SXin LI * a b cin r cout
5904884e6d60SXin LI * 0 0 0 0 0
5905884e6d60SXin LI * 0 0 1 1 0
5906884e6d60SXin LI * 0 1 0 1 0
5907884e6d60SXin LI * 0 1 1 0 1
5908884e6d60SXin LI * 1 0 0 1 0
5909884e6d60SXin LI * 1 0 1 0 1
5910884e6d60SXin LI * 1 1 0 0 1
5911884e6d60SXin LI * 1 1 1 1 1
5912884e6d60SXin LI *
5913884e6d60SXin LI * Construction of table for cout:
5914884e6d60SXin LI *
5915884e6d60SXin LI * ab
5916884e6d60SXin LI * r \ 00 01 11 10
5917884e6d60SXin LI * |------------------
5918884e6d60SXin LI * 0 | 0 1 1 1
5919884e6d60SXin LI * 1 | 0 0 1 0
5920884e6d60SXin LI *
5921884e6d60SXin LI * By inspection, one gets: cc = ab + r'(a + b)
5922884e6d60SXin LI *
5923884e6d60SXin LI * That represents alot of operations, but NO CHOICE....
5924884e6d60SXin LI *
5925884e6d60SXin LI * Borrow Chain Calculation.
5926884e6d60SXin LI *
5927884e6d60SXin LI * The following table represents the subtraction of two bits, from
5928884e6d60SXin LI * which we can derive a formula for the borrow chain.
5929884e6d60SXin LI *
5930884e6d60SXin LI * a b bin r bout
5931884e6d60SXin LI * 0 0 0 0 0
5932884e6d60SXin LI * 0 0 1 1 1
5933884e6d60SXin LI * 0 1 0 1 1
5934884e6d60SXin LI * 0 1 1 0 1
5935884e6d60SXin LI * 1 0 0 1 0
5936884e6d60SXin LI * 1 0 1 0 0
5937884e6d60SXin LI * 1 1 0 0 0
5938884e6d60SXin LI * 1 1 1 1 1
5939884e6d60SXin LI *
5940884e6d60SXin LI * Construction of table for cout:
5941884e6d60SXin LI *
5942884e6d60SXin LI * ab
5943884e6d60SXin LI * r \ 00 01 11 10
5944884e6d60SXin LI * |------------------
5945884e6d60SXin LI * 0 | 0 1 0 0
5946884e6d60SXin LI * 1 | 1 1 1 0
5947884e6d60SXin LI *
5948884e6d60SXin LI * By inspection, one gets: bc = a'b + r(a' + b)
5949884e6d60SXin LI *
5950884e6d60SXin LI */
5951884e6d60SXin LI
595206325fe0SXin LI /*
595306325fe0SXin LI * Global Variables
595406325fe0SXin LI */
5955884e6d60SXin LI
5956884e6d60SXin LI static uint32_t x86emu_parity_tab[8] =
5957884e6d60SXin LI {
5958884e6d60SXin LI 0x96696996,
5959884e6d60SXin LI 0x69969669,
5960884e6d60SXin LI 0x69969669,
5961884e6d60SXin LI 0x96696996,
5962884e6d60SXin LI 0x69969669,
5963884e6d60SXin LI 0x96696996,
5964884e6d60SXin LI 0x96696996,
5965884e6d60SXin LI 0x69969669,
5966884e6d60SXin LI };
5967884e6d60SXin LI #define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
5968884e6d60SXin LI #define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
5969884e6d60SXin LI
5970884e6d60SXin LI
5971884e6d60SXin LI /*
5972884e6d60SXin LI * REMARKS:
5973884e6d60SXin LI * Implements the AAA instruction and side effects.
5974884e6d60SXin LI */
5975884e6d60SXin LI static uint16_t
aaa_word(struct x86emu * emu,uint16_t d)5976884e6d60SXin LI aaa_word(struct x86emu *emu, uint16_t d)
5977884e6d60SXin LI {
5978884e6d60SXin LI uint16_t res;
5979884e6d60SXin LI if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
5980884e6d60SXin LI d += 0x6;
5981884e6d60SXin LI d += 0x100;
5982884e6d60SXin LI SET_FLAG(F_AF);
5983884e6d60SXin LI SET_FLAG(F_CF);
5984884e6d60SXin LI } else {
5985884e6d60SXin LI CLEAR_FLAG(F_CF);
5986884e6d60SXin LI CLEAR_FLAG(F_AF);
5987884e6d60SXin LI }
5988884e6d60SXin LI res = (uint16_t) (d & 0xFF0F);
5989884e6d60SXin LI CLEAR_FLAG(F_SF);
5990884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
5991884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
5992884e6d60SXin LI return res;
5993884e6d60SXin LI }
5994884e6d60SXin LI
5995884e6d60SXin LI /*
5996884e6d60SXin LI * REMARKS:
5997884e6d60SXin LI * Implements the AAA instruction and side effects.
5998884e6d60SXin LI */
5999884e6d60SXin LI static uint16_t
aas_word(struct x86emu * emu,uint16_t d)6000884e6d60SXin LI aas_word(struct x86emu *emu, uint16_t d)
6001884e6d60SXin LI {
6002884e6d60SXin LI uint16_t res;
6003884e6d60SXin LI if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
6004884e6d60SXin LI d -= 0x6;
6005884e6d60SXin LI d -= 0x100;
6006884e6d60SXin LI SET_FLAG(F_AF);
6007884e6d60SXin LI SET_FLAG(F_CF);
6008884e6d60SXin LI } else {
6009884e6d60SXin LI CLEAR_FLAG(F_CF);
6010884e6d60SXin LI CLEAR_FLAG(F_AF);
6011884e6d60SXin LI }
6012884e6d60SXin LI res = (uint16_t) (d & 0xFF0F);
6013884e6d60SXin LI CLEAR_FLAG(F_SF);
6014884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6015884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6016884e6d60SXin LI return res;
6017884e6d60SXin LI }
6018884e6d60SXin LI
6019884e6d60SXin LI /*
6020884e6d60SXin LI * REMARKS:
6021884e6d60SXin LI * Implements the AAD instruction and side effects.
6022884e6d60SXin LI */
6023884e6d60SXin LI static uint16_t
aad_word(struct x86emu * emu,uint16_t d)6024884e6d60SXin LI aad_word(struct x86emu *emu, uint16_t d)
6025884e6d60SXin LI {
6026884e6d60SXin LI uint16_t l;
6027884e6d60SXin LI uint8_t hb, lb;
6028884e6d60SXin LI
6029884e6d60SXin LI hb = (uint8_t) ((d >> 8) & 0xff);
6030884e6d60SXin LI lb = (uint8_t) ((d & 0xff));
6031884e6d60SXin LI l = (uint16_t) ((lb + 10 * hb) & 0xFF);
6032884e6d60SXin LI
6033884e6d60SXin LI CLEAR_FLAG(F_CF);
6034884e6d60SXin LI CLEAR_FLAG(F_AF);
6035884e6d60SXin LI CLEAR_FLAG(F_OF);
6036884e6d60SXin LI CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
6037884e6d60SXin LI CONDITIONAL_SET_FLAG(l == 0, F_ZF);
6038884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
6039884e6d60SXin LI return l;
6040884e6d60SXin LI }
6041884e6d60SXin LI
6042884e6d60SXin LI /*
6043884e6d60SXin LI * REMARKS:
6044884e6d60SXin LI * Implements the AAM instruction and side effects.
6045884e6d60SXin LI */
6046884e6d60SXin LI static uint16_t
aam_word(struct x86emu * emu,uint8_t d)6047884e6d60SXin LI aam_word(struct x86emu *emu, uint8_t d)
6048884e6d60SXin LI {
6049884e6d60SXin LI uint16_t h, l;
6050884e6d60SXin LI
6051884e6d60SXin LI h = (uint16_t) (d / 10);
6052884e6d60SXin LI l = (uint16_t) (d % 10);
6053884e6d60SXin LI l |= (uint16_t) (h << 8);
6054884e6d60SXin LI
6055884e6d60SXin LI CLEAR_FLAG(F_CF);
6056884e6d60SXin LI CLEAR_FLAG(F_AF);
6057884e6d60SXin LI CLEAR_FLAG(F_OF);
6058884e6d60SXin LI CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
6059884e6d60SXin LI CONDITIONAL_SET_FLAG(l == 0, F_ZF);
6060884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
6061884e6d60SXin LI return l;
6062884e6d60SXin LI }
6063884e6d60SXin LI
6064884e6d60SXin LI /*
6065884e6d60SXin LI * REMARKS:
6066884e6d60SXin LI * Implements the ADC instruction and side effects.
6067884e6d60SXin LI */
6068884e6d60SXin LI static uint8_t
adc_byte(struct x86emu * emu,uint8_t d,uint8_t s)6069884e6d60SXin LI adc_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6070884e6d60SXin LI {
6071884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6072884e6d60SXin LI uint32_t cc;
6073884e6d60SXin LI
6074884e6d60SXin LI if (ACCESS_FLAG(F_CF))
6075884e6d60SXin LI res = 1 + d + s;
6076884e6d60SXin LI else
6077884e6d60SXin LI res = d + s;
6078884e6d60SXin LI
6079884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
6080884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6081884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6082884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6083884e6d60SXin LI
6084884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6085884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6086884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
6087884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6088884e6d60SXin LI return (uint8_t) res;
6089884e6d60SXin LI }
6090884e6d60SXin LI
6091884e6d60SXin LI /*
6092884e6d60SXin LI * REMARKS:
6093884e6d60SXin LI * Implements the ADC instruction and side effects.
6094884e6d60SXin LI */
6095884e6d60SXin LI static uint16_t
adc_word(struct x86emu * emu,uint16_t d,uint16_t s)6096884e6d60SXin LI adc_word(struct x86emu *emu, uint16_t d, uint16_t s)
6097884e6d60SXin LI {
6098884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6099884e6d60SXin LI uint32_t cc;
6100884e6d60SXin LI
6101884e6d60SXin LI if (ACCESS_FLAG(F_CF))
6102884e6d60SXin LI res = 1 + d + s;
6103884e6d60SXin LI else
6104884e6d60SXin LI res = d + s;
6105884e6d60SXin LI
6106884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
6107884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6108884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6109884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6110884e6d60SXin LI
6111884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6112884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6113884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
6114884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6115884e6d60SXin LI return (uint16_t) res;
6116884e6d60SXin LI }
6117884e6d60SXin LI
6118884e6d60SXin LI /*
6119884e6d60SXin LI * REMARKS:
6120884e6d60SXin LI * Implements the ADC instruction and side effects.
6121884e6d60SXin LI */
6122884e6d60SXin LI static uint32_t
adc_long(struct x86emu * emu,uint32_t d,uint32_t s)6123884e6d60SXin LI adc_long(struct x86emu *emu, uint32_t d, uint32_t s)
6124884e6d60SXin LI {
6125884e6d60SXin LI uint32_t lo; /* all operands in native machine order */
6126884e6d60SXin LI uint32_t hi;
6127884e6d60SXin LI uint32_t res;
6128884e6d60SXin LI uint32_t cc;
6129884e6d60SXin LI
6130884e6d60SXin LI if (ACCESS_FLAG(F_CF)) {
6131884e6d60SXin LI lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
6132884e6d60SXin LI res = 1 + d + s;
6133884e6d60SXin LI } else {
6134884e6d60SXin LI lo = (d & 0xFFFF) + (s & 0xFFFF);
6135884e6d60SXin LI res = d + s;
6136884e6d60SXin LI }
6137884e6d60SXin LI hi = (lo >> 16) + (d >> 16) + (s >> 16);
6138884e6d60SXin LI
6139884e6d60SXin LI CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
6140884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6141884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6142884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6143884e6d60SXin LI
6144884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6145884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6146884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
6147884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6148884e6d60SXin LI return res;
6149884e6d60SXin LI }
6150884e6d60SXin LI
6151884e6d60SXin LI /*
6152884e6d60SXin LI * REMARKS:
6153884e6d60SXin LI * Implements the ADD instruction and side effects.
6154884e6d60SXin LI */
6155884e6d60SXin LI static uint8_t
add_byte(struct x86emu * emu,uint8_t d,uint8_t s)6156884e6d60SXin LI add_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6157884e6d60SXin LI {
6158884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6159884e6d60SXin LI uint32_t cc;
6160884e6d60SXin LI
6161884e6d60SXin LI res = d + s;
6162884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
6163884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6164884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6165884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6166884e6d60SXin LI
6167884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6168884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6169884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
6170884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6171884e6d60SXin LI return (uint8_t) res;
6172884e6d60SXin LI }
6173884e6d60SXin LI
6174884e6d60SXin LI /*
6175884e6d60SXin LI * REMARKS:
6176884e6d60SXin LI * Implements the ADD instruction and side effects.
6177884e6d60SXin LI */
6178884e6d60SXin LI static uint16_t
add_word(struct x86emu * emu,uint16_t d,uint16_t s)6179884e6d60SXin LI add_word(struct x86emu *emu, uint16_t d, uint16_t s)
6180884e6d60SXin LI {
6181884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6182884e6d60SXin LI uint32_t cc;
6183884e6d60SXin LI
6184884e6d60SXin LI res = d + s;
6185884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
6186884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6187884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6188884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6189884e6d60SXin LI
6190884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6191884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6192884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
6193884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6194884e6d60SXin LI return (uint16_t) res;
6195884e6d60SXin LI }
6196884e6d60SXin LI
6197884e6d60SXin LI /*
6198884e6d60SXin LI * REMARKS:
6199884e6d60SXin LI * Implements the ADD instruction and side effects.
6200884e6d60SXin LI */
6201884e6d60SXin LI static uint32_t
add_long(struct x86emu * emu,uint32_t d,uint32_t s)6202884e6d60SXin LI add_long(struct x86emu *emu, uint32_t d, uint32_t s)
6203884e6d60SXin LI {
6204884e6d60SXin LI uint32_t lo; /* all operands in native machine order */
6205884e6d60SXin LI uint32_t hi;
6206884e6d60SXin LI uint32_t res;
6207884e6d60SXin LI uint32_t cc;
6208884e6d60SXin LI
6209884e6d60SXin LI lo = (d & 0xFFFF) + (s & 0xFFFF);
6210884e6d60SXin LI res = d + s;
6211884e6d60SXin LI hi = (lo >> 16) + (d >> 16) + (s >> 16);
6212884e6d60SXin LI
6213884e6d60SXin LI CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
6214884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6215884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6216884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6217884e6d60SXin LI
6218884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6219884e6d60SXin LI cc = (s & d) | ((~res) & (s | d));
6220884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
6221884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6222884e6d60SXin LI
6223884e6d60SXin LI return res;
6224884e6d60SXin LI }
6225884e6d60SXin LI
6226884e6d60SXin LI /*
6227884e6d60SXin LI * REMARKS:
6228884e6d60SXin LI * Implements the AND instruction and side effects.
6229884e6d60SXin LI */
6230884e6d60SXin LI static uint8_t
and_byte(struct x86emu * emu,uint8_t d,uint8_t s)6231884e6d60SXin LI and_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6232884e6d60SXin LI {
6233884e6d60SXin LI uint8_t res; /* all operands in native machine order */
6234884e6d60SXin LI
6235884e6d60SXin LI res = d & s;
6236884e6d60SXin LI
6237884e6d60SXin LI /* set the flags */
6238884e6d60SXin LI CLEAR_FLAG(F_OF);
6239884e6d60SXin LI CLEAR_FLAG(F_CF);
6240884e6d60SXin LI CLEAR_FLAG(F_AF);
6241884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6242884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6243884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
6244884e6d60SXin LI return res;
6245884e6d60SXin LI }
6246884e6d60SXin LI
6247884e6d60SXin LI /*
6248884e6d60SXin LI * REMARKS:
6249884e6d60SXin LI * Implements the AND instruction and side effects.
6250884e6d60SXin LI */
6251884e6d60SXin LI static uint16_t
and_word(struct x86emu * emu,uint16_t d,uint16_t s)6252884e6d60SXin LI and_word(struct x86emu *emu, uint16_t d, uint16_t s)
6253884e6d60SXin LI {
6254884e6d60SXin LI uint16_t res; /* all operands in native machine order */
6255884e6d60SXin LI
6256884e6d60SXin LI res = d & s;
6257884e6d60SXin LI
6258884e6d60SXin LI /* set the flags */
6259884e6d60SXin LI CLEAR_FLAG(F_OF);
6260884e6d60SXin LI CLEAR_FLAG(F_CF);
6261884e6d60SXin LI CLEAR_FLAG(F_AF);
6262884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6263884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6264884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6265884e6d60SXin LI return res;
6266884e6d60SXin LI }
6267884e6d60SXin LI
6268884e6d60SXin LI /*
6269884e6d60SXin LI * REMARKS:
6270884e6d60SXin LI * Implements the AND instruction and side effects.
6271884e6d60SXin LI */
6272884e6d60SXin LI static uint32_t
and_long(struct x86emu * emu,uint32_t d,uint32_t s)6273884e6d60SXin LI and_long(struct x86emu *emu, uint32_t d, uint32_t s)
6274884e6d60SXin LI {
6275884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6276884e6d60SXin LI
6277884e6d60SXin LI res = d & s;
6278884e6d60SXin LI
6279884e6d60SXin LI /* set the flags */
6280884e6d60SXin LI CLEAR_FLAG(F_OF);
6281884e6d60SXin LI CLEAR_FLAG(F_CF);
6282884e6d60SXin LI CLEAR_FLAG(F_AF);
6283884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6284884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6285884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6286884e6d60SXin LI return res;
6287884e6d60SXin LI }
6288884e6d60SXin LI
6289884e6d60SXin LI /*
6290884e6d60SXin LI * REMARKS:
6291884e6d60SXin LI * Implements the CMP instruction and side effects.
6292884e6d60SXin LI */
6293884e6d60SXin LI static uint8_t
cmp_byte(struct x86emu * emu,uint8_t d,uint8_t s)6294884e6d60SXin LI cmp_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6295884e6d60SXin LI {
6296884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6297884e6d60SXin LI uint32_t bc;
6298884e6d60SXin LI
6299884e6d60SXin LI res = d - s;
6300884e6d60SXin LI CLEAR_FLAG(F_CF);
6301884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6302884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6303884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6304884e6d60SXin LI
6305884e6d60SXin LI /* calculate the borrow chain. See note at top */
6306884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
6307884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
6308884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
6309884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6310884e6d60SXin LI return d;
6311884e6d60SXin LI }
6312884e6d60SXin LI
6313884e6d60SXin LI static void
cmp_byte_no_return(struct x86emu * emu,uint8_t d,uint8_t s)6314884e6d60SXin LI cmp_byte_no_return(struct x86emu *emu, uint8_t d, uint8_t s)
6315884e6d60SXin LI {
6316884e6d60SXin LI cmp_byte(emu, d, s);
6317884e6d60SXin LI }
6318884e6d60SXin LI
6319884e6d60SXin LI /*
6320884e6d60SXin LI * REMARKS:
6321884e6d60SXin LI * Implements the CMP instruction and side effects.
6322884e6d60SXin LI */
6323884e6d60SXin LI static uint16_t
cmp_word(struct x86emu * emu,uint16_t d,uint16_t s)6324884e6d60SXin LI cmp_word(struct x86emu *emu, uint16_t d, uint16_t s)
6325884e6d60SXin LI {
6326884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6327884e6d60SXin LI uint32_t bc;
6328884e6d60SXin LI
6329884e6d60SXin LI res = d - s;
6330884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6331884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6332884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6333884e6d60SXin LI
6334884e6d60SXin LI /* calculate the borrow chain. See note at top */
6335884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
6336884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
6337884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
6338884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6339884e6d60SXin LI return d;
6340884e6d60SXin LI }
6341884e6d60SXin LI
6342884e6d60SXin LI static void
cmp_word_no_return(struct x86emu * emu,uint16_t d,uint16_t s)6343884e6d60SXin LI cmp_word_no_return(struct x86emu *emu, uint16_t d, uint16_t s)
6344884e6d60SXin LI {
6345884e6d60SXin LI cmp_word(emu, d, s);
6346884e6d60SXin LI }
6347884e6d60SXin LI
6348884e6d60SXin LI /*
6349884e6d60SXin LI * REMARKS:
6350884e6d60SXin LI * Implements the CMP instruction and side effects.
6351884e6d60SXin LI */
6352884e6d60SXin LI static uint32_t
cmp_long(struct x86emu * emu,uint32_t d,uint32_t s)6353884e6d60SXin LI cmp_long(struct x86emu *emu, uint32_t d, uint32_t s)
6354884e6d60SXin LI {
6355884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6356884e6d60SXin LI uint32_t bc;
6357884e6d60SXin LI
6358884e6d60SXin LI res = d - s;
6359884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6360884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6361884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6362884e6d60SXin LI
6363884e6d60SXin LI /* calculate the borrow chain. See note at top */
6364884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
6365884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
6366884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
6367884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6368884e6d60SXin LI return d;
6369884e6d60SXin LI }
6370884e6d60SXin LI
6371884e6d60SXin LI static void
cmp_long_no_return(struct x86emu * emu,uint32_t d,uint32_t s)6372884e6d60SXin LI cmp_long_no_return(struct x86emu *emu, uint32_t d, uint32_t s)
6373884e6d60SXin LI {
6374884e6d60SXin LI cmp_long(emu, d, s);
6375884e6d60SXin LI }
6376884e6d60SXin LI
6377884e6d60SXin LI /*
6378884e6d60SXin LI * REMARKS:
6379884e6d60SXin LI * Implements the DAA instruction and side effects.
6380884e6d60SXin LI */
6381884e6d60SXin LI static uint8_t
daa_byte(struct x86emu * emu,uint8_t d)6382884e6d60SXin LI daa_byte(struct x86emu *emu, uint8_t d)
6383884e6d60SXin LI {
6384884e6d60SXin LI uint32_t res = d;
6385884e6d60SXin LI if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
6386884e6d60SXin LI res += 6;
6387884e6d60SXin LI SET_FLAG(F_AF);
6388884e6d60SXin LI }
6389884e6d60SXin LI if (res > 0x9F || ACCESS_FLAG(F_CF)) {
6390884e6d60SXin LI res += 0x60;
6391884e6d60SXin LI SET_FLAG(F_CF);
6392884e6d60SXin LI }
6393884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6394884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
6395884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6396884e6d60SXin LI return (uint8_t) res;
6397884e6d60SXin LI }
6398884e6d60SXin LI
6399884e6d60SXin LI /*
6400884e6d60SXin LI * REMARKS:
6401884e6d60SXin LI * Implements the DAS instruction and side effects.
6402884e6d60SXin LI */
6403884e6d60SXin LI static uint8_t
das_byte(struct x86emu * emu,uint8_t d)6404884e6d60SXin LI das_byte(struct x86emu *emu, uint8_t d)
6405884e6d60SXin LI {
6406884e6d60SXin LI if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
6407884e6d60SXin LI d -= 6;
6408884e6d60SXin LI SET_FLAG(F_AF);
6409884e6d60SXin LI }
6410884e6d60SXin LI if (d > 0x9F || ACCESS_FLAG(F_CF)) {
6411884e6d60SXin LI d -= 0x60;
6412884e6d60SXin LI SET_FLAG(F_CF);
6413884e6d60SXin LI }
6414884e6d60SXin LI CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
6415884e6d60SXin LI CONDITIONAL_SET_FLAG(d == 0, F_ZF);
6416884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
6417884e6d60SXin LI return d;
6418884e6d60SXin LI }
6419884e6d60SXin LI
6420884e6d60SXin LI /*
6421884e6d60SXin LI * REMARKS:
6422884e6d60SXin LI * Implements the DEC instruction and side effects.
6423884e6d60SXin LI */
6424884e6d60SXin LI static uint8_t
dec_byte(struct x86emu * emu,uint8_t d)6425884e6d60SXin LI dec_byte(struct x86emu *emu, uint8_t d)
6426884e6d60SXin LI {
6427884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6428884e6d60SXin LI uint32_t bc;
6429884e6d60SXin LI
6430884e6d60SXin LI res = d - 1;
6431884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6432884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6433884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6434884e6d60SXin LI
6435884e6d60SXin LI /* calculate the borrow chain. See note at top */
6436884e6d60SXin LI /* based on sub_byte, uses s==1. */
6437884e6d60SXin LI bc = (res & (~d | 1)) | (~d & 1);
6438884e6d60SXin LI /* carry flag unchanged */
6439884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
6440884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6441884e6d60SXin LI return (uint8_t) res;
6442884e6d60SXin LI }
6443884e6d60SXin LI
6444884e6d60SXin LI /*
6445884e6d60SXin LI * REMARKS:
6446884e6d60SXin LI * Implements the DEC instruction and side effects.
6447884e6d60SXin LI */
6448884e6d60SXin LI static uint16_t
dec_word(struct x86emu * emu,uint16_t d)6449884e6d60SXin LI dec_word(struct x86emu *emu, uint16_t d)
6450884e6d60SXin LI {
6451884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6452884e6d60SXin LI uint32_t bc;
6453884e6d60SXin LI
6454884e6d60SXin LI res = d - 1;
6455884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6456884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6457884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6458884e6d60SXin LI
6459884e6d60SXin LI /* calculate the borrow chain. See note at top */
6460884e6d60SXin LI /* based on the sub_byte routine, with s==1 */
6461884e6d60SXin LI bc = (res & (~d | 1)) | (~d & 1);
6462884e6d60SXin LI /* carry flag unchanged */
6463884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
6464884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6465884e6d60SXin LI return (uint16_t) res;
6466884e6d60SXin LI }
6467884e6d60SXin LI
6468884e6d60SXin LI /*
6469884e6d60SXin LI * REMARKS:
6470884e6d60SXin LI * Implements the DEC instruction and side effects.
6471884e6d60SXin LI */
6472884e6d60SXin LI static uint32_t
dec_long(struct x86emu * emu,uint32_t d)6473884e6d60SXin LI dec_long(struct x86emu *emu, uint32_t d)
6474884e6d60SXin LI {
6475884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6476884e6d60SXin LI uint32_t bc;
6477884e6d60SXin LI
6478884e6d60SXin LI res = d - 1;
6479884e6d60SXin LI
6480884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6481884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6482884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6483884e6d60SXin LI
6484884e6d60SXin LI /* calculate the borrow chain. See note at top */
6485884e6d60SXin LI bc = (res & (~d | 1)) | (~d & 1);
6486884e6d60SXin LI /* carry flag unchanged */
6487884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
6488884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6489884e6d60SXin LI return res;
6490884e6d60SXin LI }
6491884e6d60SXin LI
6492884e6d60SXin LI /*
6493884e6d60SXin LI * REMARKS:
6494884e6d60SXin LI * Implements the INC instruction and side effects.
6495884e6d60SXin LI */
6496884e6d60SXin LI static uint8_t
inc_byte(struct x86emu * emu,uint8_t d)6497884e6d60SXin LI inc_byte(struct x86emu *emu, uint8_t d)
6498884e6d60SXin LI {
6499884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6500884e6d60SXin LI uint32_t cc;
6501884e6d60SXin LI
6502884e6d60SXin LI res = d + 1;
6503884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6504884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6505884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6506884e6d60SXin LI
6507884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6508884e6d60SXin LI cc = ((1 & d) | (~res)) & (1 | d);
6509884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
6510884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6511884e6d60SXin LI return (uint8_t) res;
6512884e6d60SXin LI }
6513884e6d60SXin LI
6514884e6d60SXin LI /*
6515884e6d60SXin LI * REMARKS:
6516884e6d60SXin LI * Implements the INC instruction and side effects.
6517884e6d60SXin LI */
6518884e6d60SXin LI static uint16_t
inc_word(struct x86emu * emu,uint16_t d)6519884e6d60SXin LI inc_word(struct x86emu *emu, uint16_t d)
6520884e6d60SXin LI {
6521884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6522884e6d60SXin LI uint32_t cc;
6523884e6d60SXin LI
6524884e6d60SXin LI res = d + 1;
6525884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6526884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6527884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6528884e6d60SXin LI
6529884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6530884e6d60SXin LI cc = (1 & d) | ((~res) & (1 | d));
6531884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
6532884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6533884e6d60SXin LI return (uint16_t) res;
6534884e6d60SXin LI }
6535884e6d60SXin LI
6536884e6d60SXin LI /*
6537884e6d60SXin LI * REMARKS:
6538884e6d60SXin LI * Implements the INC instruction and side effects.
6539884e6d60SXin LI */
6540884e6d60SXin LI static uint32_t
inc_long(struct x86emu * emu,uint32_t d)6541884e6d60SXin LI inc_long(struct x86emu *emu, uint32_t d)
6542884e6d60SXin LI {
6543884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6544884e6d60SXin LI uint32_t cc;
6545884e6d60SXin LI
6546884e6d60SXin LI res = d + 1;
6547884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6548884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6549884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6550884e6d60SXin LI
6551884e6d60SXin LI /* calculate the carry chain SEE NOTE AT TOP. */
6552884e6d60SXin LI cc = (1 & d) | ((~res) & (1 | d));
6553884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
6554884e6d60SXin LI CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
6555884e6d60SXin LI return res;
6556884e6d60SXin LI }
6557884e6d60SXin LI
6558884e6d60SXin LI /*
6559884e6d60SXin LI * REMARKS:
6560884e6d60SXin LI * Implements the OR instruction and side effects.
6561884e6d60SXin LI */
6562884e6d60SXin LI static uint8_t
or_byte(struct x86emu * emu,uint8_t d,uint8_t s)6563884e6d60SXin LI or_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6564884e6d60SXin LI {
6565884e6d60SXin LI uint8_t res; /* all operands in native machine order */
6566884e6d60SXin LI
6567884e6d60SXin LI res = d | s;
6568884e6d60SXin LI CLEAR_FLAG(F_OF);
6569884e6d60SXin LI CLEAR_FLAG(F_CF);
6570884e6d60SXin LI CLEAR_FLAG(F_AF);
6571884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6572884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6573884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
6574884e6d60SXin LI return res;
6575884e6d60SXin LI }
6576884e6d60SXin LI
6577884e6d60SXin LI /*
6578884e6d60SXin LI * REMARKS:
6579884e6d60SXin LI * Implements the OR instruction and side effects.
6580884e6d60SXin LI */
6581884e6d60SXin LI static uint16_t
or_word(struct x86emu * emu,uint16_t d,uint16_t s)6582884e6d60SXin LI or_word(struct x86emu *emu, uint16_t d, uint16_t s)
6583884e6d60SXin LI {
6584884e6d60SXin LI uint16_t res; /* all operands in native machine order */
6585884e6d60SXin LI
6586884e6d60SXin LI res = d | s;
6587884e6d60SXin LI /* set the carry flag to be bit 8 */
6588884e6d60SXin LI CLEAR_FLAG(F_OF);
6589884e6d60SXin LI CLEAR_FLAG(F_CF);
6590884e6d60SXin LI CLEAR_FLAG(F_AF);
6591884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6592884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6593884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6594884e6d60SXin LI return res;
6595884e6d60SXin LI }
6596884e6d60SXin LI
6597884e6d60SXin LI /*
6598884e6d60SXin LI * REMARKS:
6599884e6d60SXin LI * Implements the OR instruction and side effects.
6600884e6d60SXin LI */
6601884e6d60SXin LI static uint32_t
or_long(struct x86emu * emu,uint32_t d,uint32_t s)6602884e6d60SXin LI or_long(struct x86emu *emu, uint32_t d, uint32_t s)
6603884e6d60SXin LI {
6604884e6d60SXin LI uint32_t res; /* all operands in native machine order */
6605884e6d60SXin LI
6606884e6d60SXin LI res = d | s;
6607884e6d60SXin LI
6608884e6d60SXin LI /* set the carry flag to be bit 8 */
6609884e6d60SXin LI CLEAR_FLAG(F_OF);
6610884e6d60SXin LI CLEAR_FLAG(F_CF);
6611884e6d60SXin LI CLEAR_FLAG(F_AF);
6612884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6613884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
6614884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6615884e6d60SXin LI return res;
6616884e6d60SXin LI }
6617884e6d60SXin LI
6618884e6d60SXin LI /*
6619884e6d60SXin LI * REMARKS:
6620884e6d60SXin LI * Implements the OR instruction and side effects.
6621884e6d60SXin LI */
6622884e6d60SXin LI static uint8_t
neg_byte(struct x86emu * emu,uint8_t s)6623884e6d60SXin LI neg_byte(struct x86emu *emu, uint8_t s)
6624884e6d60SXin LI {
6625884e6d60SXin LI uint8_t res;
6626884e6d60SXin LI uint8_t bc;
6627884e6d60SXin LI
6628884e6d60SXin LI CONDITIONAL_SET_FLAG(s != 0, F_CF);
6629884e6d60SXin LI res = (uint8_t) - s;
6630884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
6631884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
6632884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
6633884e6d60SXin LI /* calculate the borrow chain --- modified such that d=0.
6634884e6d60SXin LI * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
6635884e6d60SXin LI * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
6636884e6d60SXin LI * res&0xfff... == res. Similarly ~d&s == s. So the simplified
6637884e6d60SXin LI * result is: */
6638884e6d60SXin LI bc = res | s;
6639884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
6640884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6641884e6d60SXin LI return res;
6642884e6d60SXin LI }
6643884e6d60SXin LI
6644884e6d60SXin LI /*
6645884e6d60SXin LI * REMARKS:
6646884e6d60SXin LI * Implements the OR instruction and side effects.
6647884e6d60SXin LI */
6648884e6d60SXin LI static uint16_t
neg_word(struct x86emu * emu,uint16_t s)6649884e6d60SXin LI neg_word(struct x86emu *emu, uint16_t s)
6650884e6d60SXin LI {
6651884e6d60SXin LI uint16_t res;
6652884e6d60SXin LI uint16_t bc;
6653884e6d60SXin LI
6654884e6d60SXin LI CONDITIONAL_SET_FLAG(s != 0, F_CF);
6655884e6d60SXin LI res = (uint16_t) - s;
6656884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
6657884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
6658884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6659884e6d60SXin LI
6660884e6d60SXin LI /* calculate the borrow chain --- modified such that d=0.
6661884e6d60SXin LI * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
6662884e6d60SXin LI * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
6663884e6d60SXin LI * res&0xfff... == res. Similarly ~d&s == s. So the simplified
6664884e6d60SXin LI * result is: */
6665884e6d60SXin LI bc = res | s;
6666884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
6667884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6668884e6d60SXin LI return res;
6669884e6d60SXin LI }
6670884e6d60SXin LI
6671884e6d60SXin LI /*
6672884e6d60SXin LI * REMARKS:
6673884e6d60SXin LI * Implements the OR instruction and side effects.
6674884e6d60SXin LI */
6675884e6d60SXin LI static uint32_t
neg_long(struct x86emu * emu,uint32_t s)6676884e6d60SXin LI neg_long(struct x86emu *emu, uint32_t s)
6677884e6d60SXin LI {
6678884e6d60SXin LI uint32_t res;
6679884e6d60SXin LI uint32_t bc;
6680884e6d60SXin LI
6681884e6d60SXin LI CONDITIONAL_SET_FLAG(s != 0, F_CF);
6682884e6d60SXin LI res = (uint32_t) - s;
6683884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
6684884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
6685884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
6686884e6d60SXin LI
6687884e6d60SXin LI /* calculate the borrow chain --- modified such that d=0.
6688884e6d60SXin LI * substitutiing d=0 into bc= res&(~d|s)|(~d&s); (the one used for
6689884e6d60SXin LI * sub) and simplifying, since ~d=0xff..., ~d|s == 0xffff..., and
6690884e6d60SXin LI * res&0xfff... == res. Similarly ~d&s == s. So the simplified
6691884e6d60SXin LI * result is: */
6692884e6d60SXin LI bc = res | s;
6693884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
6694884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
6695884e6d60SXin LI return res;
6696884e6d60SXin LI }
6697884e6d60SXin LI
6698884e6d60SXin LI /*
6699884e6d60SXin LI * REMARKS:
6700884e6d60SXin LI * Implements the RCL instruction and side effects.
6701884e6d60SXin LI */
6702884e6d60SXin LI static uint8_t
rcl_byte(struct x86emu * emu,uint8_t d,uint8_t s)6703884e6d60SXin LI rcl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6704884e6d60SXin LI {
6705884e6d60SXin LI unsigned int res, cnt, mask, cf;
6706884e6d60SXin LI
6707884e6d60SXin LI /* s is the rotate distance. It varies from 0 - 8. */
6708884e6d60SXin LI /* have
6709884e6d60SXin LI *
6710884e6d60SXin LI * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
6711884e6d60SXin LI *
6712884e6d60SXin LI * want to rotate through the carry by "s" bits. We could loop, but
6713884e6d60SXin LI * that's inefficient. So the width is 9, and we split into three
6714884e6d60SXin LI * parts:
6715884e6d60SXin LI *
671606325fe0SXin LI * The new carry flag (was B_n) the stuff in B_n-1 .. B_0 the stuff
671706325fe0SXin LI * in B_7 .. B_n+1
6718884e6d60SXin LI *
671906325fe0SXin LI * The new rotate is done mod 9, and given this, for a rotation of n
672006325fe0SXin LI * bits (mod 9) the new carry flag is then located n bits from the MSB.
6721884e6d60SXin LI * The low part is then shifted up cnt bits, and the high part is or'd
6722884e6d60SXin LI * in. Using CAPS for new values, and lowercase for the original
6723884e6d60SXin LI * values, this can be expressed as:
6724884e6d60SXin LI *
6725884e6d60SXin LI * IF n > 0 1) CF <- b_(8-n) 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
672606325fe0SXin LI * 3) B_(n-1) <- cf 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
672706325fe0SXin LI */
6728884e6d60SXin LI res = d;
6729884e6d60SXin LI if ((cnt = s % 9) != 0) {
6730884e6d60SXin LI /* extract the new CARRY FLAG. */
6731884e6d60SXin LI /* CF <- b_(8-n) */
6732884e6d60SXin LI cf = (d >> (8 - cnt)) & 0x1;
6733884e6d60SXin LI
673406325fe0SXin LI /*
673506325fe0SXin LI * Get the low stuff which rotated into the range B_7 .. B_cnt
673606325fe0SXin LI * B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
673706325fe0SXin LI * note that the right hand side done by the mask.
673806325fe0SXin LI */
6739884e6d60SXin LI res = (d << cnt) & 0xff;
6740884e6d60SXin LI
674106325fe0SXin LI /*
674206325fe0SXin LI * now the high stuff which rotated around into the positions
674306325fe0SXin LI * B_cnt-2 .. B_0
674406325fe0SXin LI * B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
674506325fe0SXin LI * shift it downward, 7-(n-2) = 9-n positions. and mask off
674606325fe0SXin LI * the result before or'ing in.
674706325fe0SXin LI */
6748884e6d60SXin LI mask = (1 << (cnt - 1)) - 1;
6749884e6d60SXin LI res |= (d >> (9 - cnt)) & mask;
6750884e6d60SXin LI
6751884e6d60SXin LI /* if the carry flag was set, or it in. */
6752884e6d60SXin LI if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
6753884e6d60SXin LI /* B_(n-1) <- cf */
6754884e6d60SXin LI res |= 1 << (cnt - 1);
6755884e6d60SXin LI }
6756884e6d60SXin LI /* set the new carry flag, based on the variable "cf" */
6757884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6758884e6d60SXin LI /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
6759884e6d60SXin LI * the most significant bit. Blecck. */
6760884e6d60SXin LI /* parenthesized this expression since it appears to be
6761884e6d60SXin LI * causing OF to be misset */
6762884e6d60SXin LI CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
6763884e6d60SXin LI F_OF);
6764884e6d60SXin LI
6765884e6d60SXin LI }
6766884e6d60SXin LI return (uint8_t) res;
6767884e6d60SXin LI }
6768884e6d60SXin LI
6769884e6d60SXin LI /*
6770884e6d60SXin LI * REMARKS:
6771884e6d60SXin LI * Implements the RCL instruction and side effects.
6772884e6d60SXin LI */
6773884e6d60SXin LI static uint16_t
rcl_word(struct x86emu * emu,uint16_t d,uint8_t s)6774884e6d60SXin LI rcl_word(struct x86emu *emu, uint16_t d, uint8_t s)
6775884e6d60SXin LI {
6776884e6d60SXin LI unsigned int res, cnt, mask, cf;
6777884e6d60SXin LI
6778884e6d60SXin LI res = d;
6779884e6d60SXin LI if ((cnt = s % 17) != 0) {
6780884e6d60SXin LI cf = (d >> (16 - cnt)) & 0x1;
6781884e6d60SXin LI res = (d << cnt) & 0xffff;
6782884e6d60SXin LI mask = (1 << (cnt - 1)) - 1;
6783884e6d60SXin LI res |= (d >> (17 - cnt)) & mask;
6784884e6d60SXin LI if (ACCESS_FLAG(F_CF)) {
6785884e6d60SXin LI res |= 1 << (cnt - 1);
6786884e6d60SXin LI }
6787884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6788884e6d60SXin LI CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
6789884e6d60SXin LI F_OF);
6790884e6d60SXin LI }
6791884e6d60SXin LI return (uint16_t) res;
6792884e6d60SXin LI }
6793884e6d60SXin LI
6794884e6d60SXin LI /*
6795884e6d60SXin LI * REMARKS:
6796884e6d60SXin LI * Implements the RCL instruction and side effects.
6797884e6d60SXin LI */
6798884e6d60SXin LI static uint32_t
rcl_long(struct x86emu * emu,uint32_t d,uint8_t s)6799884e6d60SXin LI rcl_long(struct x86emu *emu, uint32_t d, uint8_t s)
6800884e6d60SXin LI {
6801884e6d60SXin LI uint32_t res, cnt, mask, cf;
6802884e6d60SXin LI
6803884e6d60SXin LI res = d;
6804884e6d60SXin LI if ((cnt = s % 33) != 0) {
6805884e6d60SXin LI cf = (d >> (32 - cnt)) & 0x1;
6806884e6d60SXin LI res = (d << cnt) & 0xffffffff;
6807884e6d60SXin LI mask = (1 << (cnt - 1)) - 1;
6808884e6d60SXin LI res |= (d >> (33 - cnt)) & mask;
6809884e6d60SXin LI if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
6810884e6d60SXin LI res |= 1 << (cnt - 1);
6811884e6d60SXin LI }
6812884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6813884e6d60SXin LI CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
6814884e6d60SXin LI F_OF);
6815884e6d60SXin LI }
6816884e6d60SXin LI return res;
6817884e6d60SXin LI }
6818884e6d60SXin LI
6819884e6d60SXin LI /*
6820884e6d60SXin LI * REMARKS:
6821884e6d60SXin LI * Implements the RCR instruction and side effects.
6822884e6d60SXin LI */
6823884e6d60SXin LI static uint8_t
rcr_byte(struct x86emu * emu,uint8_t d,uint8_t s)6824884e6d60SXin LI rcr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6825884e6d60SXin LI {
6826884e6d60SXin LI uint32_t res, cnt;
6827884e6d60SXin LI uint32_t mask, cf, ocf = 0;
6828884e6d60SXin LI
6829884e6d60SXin LI /* rotate right through carry */
6830884e6d60SXin LI /* s is the rotate distance. It varies from 0 - 8. d is the byte
6831884e6d60SXin LI * object rotated.
6832884e6d60SXin LI *
6833884e6d60SXin LI * have
6834884e6d60SXin LI *
6835884e6d60SXin LI * CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
6836884e6d60SXin LI *
683706325fe0SXin LI * The new rotate is done mod 9, and given this, for a rotation of n
683806325fe0SXin LI * bits (mod 9) the new carry flag is then located n bits from the LSB.
6839884e6d60SXin LI * The low part is then shifted up cnt bits, and the high part is or'd
6840884e6d60SXin LI * in. Using CAPS for new values, and lowercase for the original
6841884e6d60SXin LI * values, this can be expressed as:
6842884e6d60SXin LI *
684306325fe0SXin LI * IF n > 0
684406325fe0SXin LI * 1) CF <- b_(n-1)
684506325fe0SXin LI * 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
684606325fe0SXin LI * 3) B_(8-n) <- cf 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0)
684706325fe0SXin LI */
6848884e6d60SXin LI res = d;
6849884e6d60SXin LI if ((cnt = s % 9) != 0) {
6850884e6d60SXin LI /* extract the new CARRY FLAG. */
6851884e6d60SXin LI /* CF <- b_(n-1) */
6852884e6d60SXin LI if (cnt == 1) {
6853884e6d60SXin LI cf = d & 0x1;
6854884e6d60SXin LI /* note hackery here. Access_flag(..) evaluates to
6855884e6d60SXin LI * either 0 if flag not set non-zero if flag is set.
6856884e6d60SXin LI * doing access_flag(..) != 0 casts that into either
6857884e6d60SXin LI * 0..1 in any representation of the flags register
6858884e6d60SXin LI * (i.e. packed bit array or unpacked.) */
6859884e6d60SXin LI ocf = ACCESS_FLAG(F_CF) != 0;
6860884e6d60SXin LI } else
6861884e6d60SXin LI cf = (d >> (cnt - 1)) & 0x1;
6862884e6d60SXin LI
6863884e6d60SXin LI /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
6864884e6d60SXin LI /* note that the right hand side done by the mask This is
6865884e6d60SXin LI * effectively done by shifting the object to the right. The
6866884e6d60SXin LI * result must be masked, in case the object came in and was
6867884e6d60SXin LI * treated as a negative number. Needed??? */
6868884e6d60SXin LI
6869884e6d60SXin LI mask = (1 << (8 - cnt)) - 1;
6870884e6d60SXin LI res = (d >> cnt) & mask;
6871884e6d60SXin LI
6872884e6d60SXin LI /* now the high stuff which rotated around into the positions
6873884e6d60SXin LI * B_cnt-2 .. B_0 */
6874884e6d60SXin LI /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
6875884e6d60SXin LI /* shift it downward, 7-(n-2) = 9-n positions. and mask off
6876884e6d60SXin LI * the result before or'ing in. */
6877884e6d60SXin LI res |= (d << (9 - cnt));
6878884e6d60SXin LI
6879884e6d60SXin LI /* if the carry flag was set, or it in. */
6880884e6d60SXin LI if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
6881884e6d60SXin LI /* B_(8-n) <- cf */
6882884e6d60SXin LI res |= 1 << (8 - cnt);
6883884e6d60SXin LI }
6884884e6d60SXin LI /* set the new carry flag, based on the variable "cf" */
6885884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6886884e6d60SXin LI /* OVERFLOW is set *IFF* cnt==1, then it is the xor of CF and
6887884e6d60SXin LI * the most significant bit. Blecck. */
6888884e6d60SXin LI /* parenthesized... */
6889884e6d60SXin LI if (cnt == 1) {
6890884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
6891884e6d60SXin LI F_OF);
6892884e6d60SXin LI }
6893884e6d60SXin LI }
6894884e6d60SXin LI return (uint8_t) res;
6895884e6d60SXin LI }
6896884e6d60SXin LI
6897884e6d60SXin LI /*
6898884e6d60SXin LI * REMARKS:
6899884e6d60SXin LI * Implements the RCR instruction and side effects.
6900884e6d60SXin LI */
6901884e6d60SXin LI static uint16_t
rcr_word(struct x86emu * emu,uint16_t d,uint8_t s)6902884e6d60SXin LI rcr_word(struct x86emu *emu, uint16_t d, uint8_t s)
6903884e6d60SXin LI {
6904884e6d60SXin LI uint32_t res, cnt;
6905884e6d60SXin LI uint32_t mask, cf, ocf = 0;
6906884e6d60SXin LI
6907884e6d60SXin LI /* rotate right through carry */
6908884e6d60SXin LI res = d;
6909884e6d60SXin LI if ((cnt = s % 17) != 0) {
6910884e6d60SXin LI if (cnt == 1) {
6911884e6d60SXin LI cf = d & 0x1;
6912884e6d60SXin LI ocf = ACCESS_FLAG(F_CF) != 0;
6913884e6d60SXin LI } else
6914884e6d60SXin LI cf = (d >> (cnt - 1)) & 0x1;
6915884e6d60SXin LI mask = (1 << (16 - cnt)) - 1;
6916884e6d60SXin LI res = (d >> cnt) & mask;
6917884e6d60SXin LI res |= (d << (17 - cnt));
6918884e6d60SXin LI if (ACCESS_FLAG(F_CF)) {
6919884e6d60SXin LI res |= 1 << (16 - cnt);
6920884e6d60SXin LI }
6921884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6922884e6d60SXin LI if (cnt == 1) {
6923884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
6924884e6d60SXin LI F_OF);
6925884e6d60SXin LI }
6926884e6d60SXin LI }
6927884e6d60SXin LI return (uint16_t) res;
6928884e6d60SXin LI }
6929884e6d60SXin LI
6930884e6d60SXin LI /*
6931884e6d60SXin LI * REMARKS:
6932884e6d60SXin LI * Implements the RCR instruction and side effects.
6933884e6d60SXin LI */
6934884e6d60SXin LI static uint32_t
rcr_long(struct x86emu * emu,uint32_t d,uint8_t s)6935884e6d60SXin LI rcr_long(struct x86emu *emu, uint32_t d, uint8_t s)
6936884e6d60SXin LI {
6937884e6d60SXin LI uint32_t res, cnt;
6938884e6d60SXin LI uint32_t mask, cf, ocf = 0;
6939884e6d60SXin LI
6940884e6d60SXin LI /* rotate right through carry */
6941884e6d60SXin LI res = d;
6942884e6d60SXin LI if ((cnt = s % 33) != 0) {
6943884e6d60SXin LI if (cnt == 1) {
6944884e6d60SXin LI cf = d & 0x1;
6945884e6d60SXin LI ocf = ACCESS_FLAG(F_CF) != 0;
6946884e6d60SXin LI } else
6947884e6d60SXin LI cf = (d >> (cnt - 1)) & 0x1;
6948884e6d60SXin LI mask = (1 << (32 - cnt)) - 1;
6949884e6d60SXin LI res = (d >> cnt) & mask;
6950884e6d60SXin LI if (cnt != 1)
6951884e6d60SXin LI res |= (d << (33 - cnt));
6952884e6d60SXin LI if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
6953884e6d60SXin LI res |= 1 << (32 - cnt);
6954884e6d60SXin LI }
6955884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
6956884e6d60SXin LI if (cnt == 1) {
6957884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
6958884e6d60SXin LI F_OF);
6959884e6d60SXin LI }
6960884e6d60SXin LI }
6961884e6d60SXin LI return res;
6962884e6d60SXin LI }
6963884e6d60SXin LI
6964884e6d60SXin LI /*
6965884e6d60SXin LI * REMARKS:
6966884e6d60SXin LI * Implements the ROL instruction and side effects.
6967884e6d60SXin LI */
6968884e6d60SXin LI static uint8_t
rol_byte(struct x86emu * emu,uint8_t d,uint8_t s)6969884e6d60SXin LI rol_byte(struct x86emu *emu, uint8_t d, uint8_t s)
6970884e6d60SXin LI {
6971884e6d60SXin LI unsigned int res, cnt, mask;
6972884e6d60SXin LI
6973884e6d60SXin LI /* rotate left */
6974884e6d60SXin LI /* s is the rotate distance. It varies from 0 - 8. d is the byte
6975884e6d60SXin LI * object rotated.
6976884e6d60SXin LI *
6977884e6d60SXin LI * have
6978884e6d60SXin LI *
6979884e6d60SXin LI * CF B_7 ... B_0
6980884e6d60SXin LI *
6981884e6d60SXin LI * The new rotate is done mod 8. Much simpler than the "rcl" or "rcr"
6982884e6d60SXin LI * operations.
6983884e6d60SXin LI *
6984884e6d60SXin LI * IF n > 0 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) 2) B_(n-1) ..
6985884e6d60SXin LI * B_(0) <- b_(7) .. b_(8-n) */
6986884e6d60SXin LI res = d;
6987884e6d60SXin LI if ((cnt = s % 8) != 0) {
6988884e6d60SXin LI /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
6989884e6d60SXin LI res = (d << cnt);
6990884e6d60SXin LI
6991884e6d60SXin LI /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */
6992884e6d60SXin LI mask = (1 << cnt) - 1;
6993884e6d60SXin LI res |= (d >> (8 - cnt)) & mask;
6994884e6d60SXin LI
6995884e6d60SXin LI /* OVERFLOW is set *IFF* s==1, then it is the xor of CF and
6996884e6d60SXin LI * the most significant bit. Blecck. */
6997884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 &&
6998884e6d60SXin LI XOR2((res & 0x1) + ((res >> 6) & 0x2)),
6999884e6d60SXin LI F_OF);
7000*33b5cd53SJung-uk Kim }
7001*33b5cd53SJung-uk Kim if (s != 0) {
7002884e6d60SXin LI /* set the new carry flag, Note that it is the low order bit
7003884e6d60SXin LI * of the result!!! */
7004884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
7005884e6d60SXin LI }
7006884e6d60SXin LI return (uint8_t) res;
7007884e6d60SXin LI }
7008884e6d60SXin LI
7009884e6d60SXin LI /*
7010884e6d60SXin LI * REMARKS:
7011884e6d60SXin LI * Implements the ROL instruction and side effects.
7012884e6d60SXin LI */
7013884e6d60SXin LI static uint16_t
rol_word(struct x86emu * emu,uint16_t d,uint8_t s)7014884e6d60SXin LI rol_word(struct x86emu *emu, uint16_t d, uint8_t s)
7015884e6d60SXin LI {
7016884e6d60SXin LI unsigned int res, cnt, mask;
7017884e6d60SXin LI
7018884e6d60SXin LI res = d;
7019884e6d60SXin LI if ((cnt = s % 16) != 0) {
7020884e6d60SXin LI res = (d << cnt);
7021884e6d60SXin LI mask = (1 << cnt) - 1;
7022884e6d60SXin LI res |= (d >> (16 - cnt)) & mask;
7023884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 &&
7024884e6d60SXin LI XOR2((res & 0x1) + ((res >> 14) & 0x2)),
7025884e6d60SXin LI F_OF);
7026*33b5cd53SJung-uk Kim }
7027*33b5cd53SJung-uk Kim if (s != 0) {
7028884e6d60SXin LI /* set the new carry flag, Note that it is the low order bit
7029884e6d60SXin LI * of the result!!! */
7030884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
7031884e6d60SXin LI }
7032884e6d60SXin LI return (uint16_t) res;
7033884e6d60SXin LI }
7034884e6d60SXin LI
7035884e6d60SXin LI /*
7036884e6d60SXin LI * REMARKS:
7037884e6d60SXin LI * Implements the ROL instruction and side effects.
7038884e6d60SXin LI */
7039884e6d60SXin LI static uint32_t
rol_long(struct x86emu * emu,uint32_t d,uint8_t s)7040884e6d60SXin LI rol_long(struct x86emu *emu, uint32_t d, uint8_t s)
7041884e6d60SXin LI {
7042884e6d60SXin LI uint32_t res, cnt, mask;
7043884e6d60SXin LI
7044884e6d60SXin LI res = d;
7045884e6d60SXin LI if ((cnt = s % 32) != 0) {
7046884e6d60SXin LI res = (d << cnt);
7047884e6d60SXin LI mask = (1 << cnt) - 1;
7048884e6d60SXin LI res |= (d >> (32 - cnt)) & mask;
7049884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 &&
7050884e6d60SXin LI XOR2((res & 0x1) + ((res >> 30) & 0x2)),
7051884e6d60SXin LI F_OF);
7052*33b5cd53SJung-uk Kim }
7053*33b5cd53SJung-uk Kim if (s != 0) {
7054884e6d60SXin LI /* set the new carry flag, Note that it is the low order bit
7055884e6d60SXin LI * of the result!!! */
7056884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
7057884e6d60SXin LI }
7058884e6d60SXin LI return res;
7059884e6d60SXin LI }
7060884e6d60SXin LI
7061884e6d60SXin LI /*
7062884e6d60SXin LI * REMARKS:
7063884e6d60SXin LI * Implements the ROR instruction and side effects.
7064884e6d60SXin LI */
7065884e6d60SXin LI static uint8_t
ror_byte(struct x86emu * emu,uint8_t d,uint8_t s)7066884e6d60SXin LI ror_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7067884e6d60SXin LI {
7068884e6d60SXin LI unsigned int res, cnt, mask;
7069884e6d60SXin LI
7070884e6d60SXin LI /* rotate right */
7071884e6d60SXin LI /* s is the rotate distance. It varies from 0 - 8. d is the byte
7072884e6d60SXin LI * object rotated.
7073884e6d60SXin LI *
7074884e6d60SXin LI * have
7075884e6d60SXin LI *
7076884e6d60SXin LI * B_7 ... B_0
7077884e6d60SXin LI *
7078884e6d60SXin LI * The rotate is done mod 8.
7079884e6d60SXin LI *
7080884e6d60SXin LI * IF n > 0 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) 2) B_(7) ..
7081884e6d60SXin LI * B_(8-n) <- b_(n-1) .. b_(0) */
7082884e6d60SXin LI res = d;
7083884e6d60SXin LI if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */
7084884e6d60SXin LI /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */
7085884e6d60SXin LI res = (d << (8 - cnt));
7086884e6d60SXin LI
7087884e6d60SXin LI /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */
7088884e6d60SXin LI mask = (1 << (8 - cnt)) - 1;
7089884e6d60SXin LI res |= (d >> (cnt)) & mask;
7090884e6d60SXin LI
7091884e6d60SXin LI /* OVERFLOW is set *IFF* s==1, then it is the xor of the two
7092884e6d60SXin LI * most significant bits. Blecck. */
7093884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
7094*33b5cd53SJung-uk Kim }
7095*33b5cd53SJung-uk Kim if (s != 0) {
7096*33b5cd53SJung-uk Kim /* set the new carry flag, Note that it is the high order bit
7097884e6d60SXin LI * of the result!!! */
7098884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
7099884e6d60SXin LI }
7100884e6d60SXin LI return (uint8_t) res;
7101884e6d60SXin LI }
7102884e6d60SXin LI
7103884e6d60SXin LI /*
7104884e6d60SXin LI * REMARKS:
7105884e6d60SXin LI * Implements the ROR instruction and side effects.
7106884e6d60SXin LI */
7107884e6d60SXin LI static uint16_t
ror_word(struct x86emu * emu,uint16_t d,uint8_t s)7108884e6d60SXin LI ror_word(struct x86emu *emu, uint16_t d, uint8_t s)
7109884e6d60SXin LI {
7110884e6d60SXin LI unsigned int res, cnt, mask;
7111884e6d60SXin LI
7112884e6d60SXin LI res = d;
7113884e6d60SXin LI if ((cnt = s % 16) != 0) {
7114884e6d60SXin LI res = (d << (16 - cnt));
7115884e6d60SXin LI mask = (1 << (16 - cnt)) - 1;
7116884e6d60SXin LI res |= (d >> (cnt)) & mask;
7117884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
7118*33b5cd53SJung-uk Kim }
7119*33b5cd53SJung-uk Kim if (s != 0) {
7120*33b5cd53SJung-uk Kim /* set the new carry flag, Note that it is the high order bit
7121884e6d60SXin LI * of the result!!! */
7122884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
7123884e6d60SXin LI }
7124884e6d60SXin LI return (uint16_t) res;
7125884e6d60SXin LI }
7126884e6d60SXin LI
7127884e6d60SXin LI /*
7128884e6d60SXin LI * REMARKS:
7129884e6d60SXin LI * Implements the ROR instruction and side effects.
7130884e6d60SXin LI */
7131884e6d60SXin LI static uint32_t
ror_long(struct x86emu * emu,uint32_t d,uint8_t s)7132884e6d60SXin LI ror_long(struct x86emu *emu, uint32_t d, uint8_t s)
7133884e6d60SXin LI {
7134884e6d60SXin LI uint32_t res, cnt, mask;
7135884e6d60SXin LI
7136884e6d60SXin LI res = d;
7137884e6d60SXin LI if ((cnt = s % 32) != 0) {
7138884e6d60SXin LI res = (d << (32 - cnt));
7139884e6d60SXin LI mask = (1 << (32 - cnt)) - 1;
7140884e6d60SXin LI res |= (d >> (cnt)) & mask;
7141884e6d60SXin LI CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
7142*33b5cd53SJung-uk Kim }
7143*33b5cd53SJung-uk Kim if (s != 0) {
7144*33b5cd53SJung-uk Kim /* set the new carry flag, Note that it is the high order bit
7145884e6d60SXin LI * of the result!!! */
7146884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
7147884e6d60SXin LI }
7148884e6d60SXin LI return res;
7149884e6d60SXin LI }
7150884e6d60SXin LI
7151884e6d60SXin LI /*
7152884e6d60SXin LI * REMARKS:
7153884e6d60SXin LI * Implements the SHL instruction and side effects.
7154884e6d60SXin LI */
7155884e6d60SXin LI static uint8_t
shl_byte(struct x86emu * emu,uint8_t d,uint8_t s)7156884e6d60SXin LI shl_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7157884e6d60SXin LI {
7158884e6d60SXin LI unsigned int cnt, res, cf;
7159884e6d60SXin LI
7160884e6d60SXin LI if (s < 8) {
7161884e6d60SXin LI cnt = s % 8;
7162884e6d60SXin LI
7163884e6d60SXin LI /* last bit shifted out goes into carry flag */
7164884e6d60SXin LI if (cnt > 0) {
7165884e6d60SXin LI res = d << cnt;
7166884e6d60SXin LI cf = d & (1 << (8 - cnt));
7167884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7168884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
7169884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7170884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7171884e6d60SXin LI } else {
7172884e6d60SXin LI res = (uint8_t) d;
7173884e6d60SXin LI }
7174884e6d60SXin LI
7175884e6d60SXin LI if (cnt == 1) {
7176884e6d60SXin LI /* Needs simplification. */
7177884e6d60SXin LI CONDITIONAL_SET_FLAG(
7178884e6d60SXin LI (((res & 0x80) == 0x80) ^
7179884e6d60SXin LI (ACCESS_FLAG(F_CF) != 0)),
7180884e6d60SXin LI /* was (emu->x86.R_FLG&F_CF)==F_CF)), */
7181884e6d60SXin LI F_OF);
7182884e6d60SXin LI } else {
7183884e6d60SXin LI CLEAR_FLAG(F_OF);
7184884e6d60SXin LI }
7185884e6d60SXin LI } else {
7186884e6d60SXin LI res = 0;
7187884e6d60SXin LI CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF);
7188884e6d60SXin LI CLEAR_FLAG(F_OF);
7189884e6d60SXin LI CLEAR_FLAG(F_SF);
7190884e6d60SXin LI SET_FLAG(F_PF);
7191884e6d60SXin LI SET_FLAG(F_ZF);
7192884e6d60SXin LI }
7193884e6d60SXin LI return (uint8_t) res;
7194884e6d60SXin LI }
7195884e6d60SXin LI
7196884e6d60SXin LI /*
7197884e6d60SXin LI * REMARKS:
7198884e6d60SXin LI * Implements the SHL instruction and side effects.
7199884e6d60SXin LI */
7200884e6d60SXin LI static uint16_t
shl_word(struct x86emu * emu,uint16_t d,uint8_t s)7201884e6d60SXin LI shl_word(struct x86emu *emu, uint16_t d, uint8_t s)
7202884e6d60SXin LI {
7203884e6d60SXin LI unsigned int cnt, res, cf;
7204884e6d60SXin LI
7205884e6d60SXin LI if (s < 16) {
7206884e6d60SXin LI cnt = s % 16;
7207884e6d60SXin LI if (cnt > 0) {
7208884e6d60SXin LI res = d << cnt;
7209884e6d60SXin LI cf = d & (1 << (16 - cnt));
7210884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7211884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7212884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7213884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7214884e6d60SXin LI } else {
7215884e6d60SXin LI res = (uint16_t) d;
7216884e6d60SXin LI }
7217884e6d60SXin LI
7218884e6d60SXin LI if (cnt == 1) {
7219884e6d60SXin LI CONDITIONAL_SET_FLAG(
7220884e6d60SXin LI (((res & 0x8000) == 0x8000) ^
7221884e6d60SXin LI (ACCESS_FLAG(F_CF) != 0)),
7222884e6d60SXin LI F_OF);
7223884e6d60SXin LI } else {
7224884e6d60SXin LI CLEAR_FLAG(F_OF);
7225884e6d60SXin LI }
7226884e6d60SXin LI } else {
7227884e6d60SXin LI res = 0;
7228884e6d60SXin LI CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
7229884e6d60SXin LI CLEAR_FLAG(F_OF);
7230884e6d60SXin LI CLEAR_FLAG(F_SF);
7231884e6d60SXin LI SET_FLAG(F_PF);
7232884e6d60SXin LI SET_FLAG(F_ZF);
7233884e6d60SXin LI }
7234884e6d60SXin LI return (uint16_t) res;
7235884e6d60SXin LI }
7236884e6d60SXin LI
7237884e6d60SXin LI /*
7238884e6d60SXin LI * REMARKS:
7239884e6d60SXin LI * Implements the SHL instruction and side effects.
7240884e6d60SXin LI */
7241884e6d60SXin LI static uint32_t
shl_long(struct x86emu * emu,uint32_t d,uint8_t s)7242884e6d60SXin LI shl_long(struct x86emu *emu, uint32_t d, uint8_t s)
7243884e6d60SXin LI {
7244884e6d60SXin LI unsigned int cnt, res, cf;
7245884e6d60SXin LI
7246884e6d60SXin LI if (s < 32) {
7247884e6d60SXin LI cnt = s % 32;
7248884e6d60SXin LI if (cnt > 0) {
7249884e6d60SXin LI res = d << cnt;
7250884e6d60SXin LI cf = d & (1 << (32 - cnt));
7251884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7252884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7253884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7254884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7255884e6d60SXin LI } else {
7256884e6d60SXin LI res = d;
7257884e6d60SXin LI }
7258884e6d60SXin LI if (cnt == 1) {
725906325fe0SXin LI CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
726006325fe0SXin LI ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
7261884e6d60SXin LI } else {
7262884e6d60SXin LI CLEAR_FLAG(F_OF);
7263884e6d60SXin LI }
7264884e6d60SXin LI } else {
7265884e6d60SXin LI res = 0;
7266884e6d60SXin LI CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
7267884e6d60SXin LI CLEAR_FLAG(F_OF);
7268884e6d60SXin LI CLEAR_FLAG(F_SF);
7269884e6d60SXin LI SET_FLAG(F_PF);
7270884e6d60SXin LI SET_FLAG(F_ZF);
7271884e6d60SXin LI }
7272884e6d60SXin LI return res;
7273884e6d60SXin LI }
7274884e6d60SXin LI
7275884e6d60SXin LI /*
7276884e6d60SXin LI * REMARKS:
7277884e6d60SXin LI * Implements the SHR instruction and side effects.
7278884e6d60SXin LI */
7279884e6d60SXin LI static uint8_t
shr_byte(struct x86emu * emu,uint8_t d,uint8_t s)7280884e6d60SXin LI shr_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7281884e6d60SXin LI {
7282884e6d60SXin LI unsigned int cnt, res, cf;
7283884e6d60SXin LI
7284884e6d60SXin LI if (s < 8) {
7285884e6d60SXin LI cnt = s % 8;
7286884e6d60SXin LI if (cnt > 0) {
7287884e6d60SXin LI cf = d & (1 << (cnt - 1));
7288884e6d60SXin LI res = d >> cnt;
7289884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7290884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
7291884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7292884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7293884e6d60SXin LI } else {
7294884e6d60SXin LI res = (uint8_t) d;
7295884e6d60SXin LI }
7296884e6d60SXin LI
7297884e6d60SXin LI if (cnt == 1) {
7298884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
7299884e6d60SXin LI } else {
7300884e6d60SXin LI CLEAR_FLAG(F_OF);
7301884e6d60SXin LI }
7302884e6d60SXin LI } else {
7303884e6d60SXin LI res = 0;
7304884e6d60SXin LI CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF);
7305884e6d60SXin LI CLEAR_FLAG(F_OF);
7306884e6d60SXin LI CLEAR_FLAG(F_SF);
7307884e6d60SXin LI SET_FLAG(F_PF);
7308884e6d60SXin LI SET_FLAG(F_ZF);
7309884e6d60SXin LI }
7310884e6d60SXin LI return (uint8_t) res;
7311884e6d60SXin LI }
7312884e6d60SXin LI
7313884e6d60SXin LI /*
7314884e6d60SXin LI * REMARKS:
7315884e6d60SXin LI * Implements the SHR instruction and side effects.
7316884e6d60SXin LI */
7317884e6d60SXin LI static uint16_t
shr_word(struct x86emu * emu,uint16_t d,uint8_t s)7318884e6d60SXin LI shr_word(struct x86emu *emu, uint16_t d, uint8_t s)
7319884e6d60SXin LI {
7320884e6d60SXin LI unsigned int cnt, res, cf;
7321884e6d60SXin LI
7322884e6d60SXin LI if (s < 16) {
7323884e6d60SXin LI cnt = s % 16;
7324884e6d60SXin LI if (cnt > 0) {
7325884e6d60SXin LI cf = d & (1 << (cnt - 1));
7326884e6d60SXin LI res = d >> cnt;
7327884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7328884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7329884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7330884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7331884e6d60SXin LI } else {
7332884e6d60SXin LI res = d;
7333884e6d60SXin LI }
7334884e6d60SXin LI
7335884e6d60SXin LI if (cnt == 1) {
7336884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
7337884e6d60SXin LI } else {
7338884e6d60SXin LI CLEAR_FLAG(F_OF);
7339884e6d60SXin LI }
7340884e6d60SXin LI } else {
7341884e6d60SXin LI res = 0;
7342884e6d60SXin LI CLEAR_FLAG(F_CF);
7343884e6d60SXin LI CLEAR_FLAG(F_OF);
7344884e6d60SXin LI SET_FLAG(F_ZF);
7345884e6d60SXin LI CLEAR_FLAG(F_SF);
7346884e6d60SXin LI CLEAR_FLAG(F_PF);
7347884e6d60SXin LI }
7348884e6d60SXin LI return (uint16_t) res;
7349884e6d60SXin LI }
7350884e6d60SXin LI
7351884e6d60SXin LI /*
7352884e6d60SXin LI * REMARKS:
7353884e6d60SXin LI * Implements the SHR instruction and side effects.
7354884e6d60SXin LI */
7355884e6d60SXin LI static uint32_t
shr_long(struct x86emu * emu,uint32_t d,uint8_t s)7356884e6d60SXin LI shr_long(struct x86emu *emu, uint32_t d, uint8_t s)
7357884e6d60SXin LI {
7358884e6d60SXin LI unsigned int cnt, res, cf;
7359884e6d60SXin LI
7360884e6d60SXin LI if (s < 32) {
7361884e6d60SXin LI cnt = s % 32;
7362884e6d60SXin LI if (cnt > 0) {
7363884e6d60SXin LI cf = d & (1 << (cnt - 1));
7364884e6d60SXin LI res = d >> cnt;
7365884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7366884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7367884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7368884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7369884e6d60SXin LI } else {
7370884e6d60SXin LI res = d;
7371884e6d60SXin LI }
7372884e6d60SXin LI if (cnt == 1) {
7373884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
7374884e6d60SXin LI } else {
7375884e6d60SXin LI CLEAR_FLAG(F_OF);
7376884e6d60SXin LI }
7377884e6d60SXin LI } else {
7378884e6d60SXin LI res = 0;
7379884e6d60SXin LI CLEAR_FLAG(F_CF);
7380884e6d60SXin LI CLEAR_FLAG(F_OF);
7381884e6d60SXin LI SET_FLAG(F_ZF);
7382884e6d60SXin LI CLEAR_FLAG(F_SF);
7383884e6d60SXin LI CLEAR_FLAG(F_PF);
7384884e6d60SXin LI }
7385884e6d60SXin LI return res;
7386884e6d60SXin LI }
7387884e6d60SXin LI
7388884e6d60SXin LI /*
7389884e6d60SXin LI * REMARKS:
7390884e6d60SXin LI * Implements the SAR instruction and side effects.
7391884e6d60SXin LI */
7392884e6d60SXin LI static uint8_t
sar_byte(struct x86emu * emu,uint8_t d,uint8_t s)7393884e6d60SXin LI sar_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7394884e6d60SXin LI {
7395884e6d60SXin LI unsigned int cnt, res, cf, mask, sf;
7396884e6d60SXin LI
7397884e6d60SXin LI res = d;
7398884e6d60SXin LI sf = d & 0x80;
7399884e6d60SXin LI cnt = s % 8;
7400884e6d60SXin LI if (cnt > 0 && cnt < 8) {
7401884e6d60SXin LI mask = (1 << (8 - cnt)) - 1;
7402884e6d60SXin LI cf = d & (1 << (cnt - 1));
7403884e6d60SXin LI res = (d >> cnt) & mask;
7404884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7405884e6d60SXin LI if (sf) {
7406884e6d60SXin LI res |= ~mask;
7407884e6d60SXin LI }
7408884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
7409884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7410884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7411884e6d60SXin LI } else if (cnt >= 8) {
7412884e6d60SXin LI if (sf) {
7413884e6d60SXin LI res = 0xff;
7414884e6d60SXin LI SET_FLAG(F_CF);
7415884e6d60SXin LI CLEAR_FLAG(F_ZF);
7416884e6d60SXin LI SET_FLAG(F_SF);
7417884e6d60SXin LI SET_FLAG(F_PF);
7418884e6d60SXin LI } else {
7419884e6d60SXin LI res = 0;
7420884e6d60SXin LI CLEAR_FLAG(F_CF);
7421884e6d60SXin LI SET_FLAG(F_ZF);
7422884e6d60SXin LI CLEAR_FLAG(F_SF);
7423884e6d60SXin LI CLEAR_FLAG(F_PF);
7424884e6d60SXin LI }
7425884e6d60SXin LI }
7426884e6d60SXin LI return (uint8_t) res;
7427884e6d60SXin LI }
7428884e6d60SXin LI
7429884e6d60SXin LI /*
7430884e6d60SXin LI * REMARKS:
7431884e6d60SXin LI * Implements the SAR instruction and side effects.
7432884e6d60SXin LI */
7433884e6d60SXin LI static uint16_t
sar_word(struct x86emu * emu,uint16_t d,uint8_t s)7434884e6d60SXin LI sar_word(struct x86emu *emu, uint16_t d, uint8_t s)
7435884e6d60SXin LI {
7436884e6d60SXin LI unsigned int cnt, res, cf, mask, sf;
7437884e6d60SXin LI
7438884e6d60SXin LI sf = d & 0x8000;
7439884e6d60SXin LI cnt = s % 16;
7440884e6d60SXin LI res = d;
7441884e6d60SXin LI if (cnt > 0 && cnt < 16) {
7442884e6d60SXin LI mask = (1 << (16 - cnt)) - 1;
7443884e6d60SXin LI cf = d & (1 << (cnt - 1));
7444884e6d60SXin LI res = (d >> cnt) & mask;
7445884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7446884e6d60SXin LI if (sf) {
7447884e6d60SXin LI res |= ~mask;
7448884e6d60SXin LI }
7449884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7450884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7451884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7452884e6d60SXin LI } else if (cnt >= 16) {
7453884e6d60SXin LI if (sf) {
7454884e6d60SXin LI res = 0xffff;
7455884e6d60SXin LI SET_FLAG(F_CF);
7456884e6d60SXin LI CLEAR_FLAG(F_ZF);
7457884e6d60SXin LI SET_FLAG(F_SF);
7458884e6d60SXin LI SET_FLAG(F_PF);
7459884e6d60SXin LI } else {
7460884e6d60SXin LI res = 0;
7461884e6d60SXin LI CLEAR_FLAG(F_CF);
7462884e6d60SXin LI SET_FLAG(F_ZF);
7463884e6d60SXin LI CLEAR_FLAG(F_SF);
7464884e6d60SXin LI CLEAR_FLAG(F_PF);
7465884e6d60SXin LI }
7466884e6d60SXin LI }
7467884e6d60SXin LI return (uint16_t) res;
7468884e6d60SXin LI }
7469884e6d60SXin LI
7470884e6d60SXin LI /*
7471884e6d60SXin LI * REMARKS:
7472884e6d60SXin LI * Implements the SAR instruction and side effects.
7473884e6d60SXin LI */
7474884e6d60SXin LI static uint32_t
sar_long(struct x86emu * emu,uint32_t d,uint8_t s)7475884e6d60SXin LI sar_long(struct x86emu *emu, uint32_t d, uint8_t s)
7476884e6d60SXin LI {
7477884e6d60SXin LI uint32_t cnt, res, cf, mask, sf;
7478884e6d60SXin LI
7479884e6d60SXin LI sf = d & 0x80000000;
7480884e6d60SXin LI cnt = s % 32;
7481884e6d60SXin LI res = d;
7482884e6d60SXin LI if (cnt > 0 && cnt < 32) {
7483884e6d60SXin LI mask = (1 << (32 - cnt)) - 1;
7484884e6d60SXin LI cf = d & (1 << (cnt - 1));
7485884e6d60SXin LI res = (d >> cnt) & mask;
7486884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7487884e6d60SXin LI if (sf) {
7488884e6d60SXin LI res |= ~mask;
7489884e6d60SXin LI }
7490884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7491884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7492884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7493884e6d60SXin LI } else if (cnt >= 32) {
7494884e6d60SXin LI if (sf) {
7495884e6d60SXin LI res = 0xffffffff;
7496884e6d60SXin LI SET_FLAG(F_CF);
7497884e6d60SXin LI CLEAR_FLAG(F_ZF);
7498884e6d60SXin LI SET_FLAG(F_SF);
7499884e6d60SXin LI SET_FLAG(F_PF);
7500884e6d60SXin LI } else {
7501884e6d60SXin LI res = 0;
7502884e6d60SXin LI CLEAR_FLAG(F_CF);
7503884e6d60SXin LI SET_FLAG(F_ZF);
7504884e6d60SXin LI CLEAR_FLAG(F_SF);
7505884e6d60SXin LI CLEAR_FLAG(F_PF);
7506884e6d60SXin LI }
7507884e6d60SXin LI }
7508884e6d60SXin LI return res;
7509884e6d60SXin LI }
7510884e6d60SXin LI
7511884e6d60SXin LI /*
7512884e6d60SXin LI * REMARKS:
7513884e6d60SXin LI * Implements the SHLD instruction and side effects.
7514884e6d60SXin LI */
7515884e6d60SXin LI static uint16_t
shld_word(struct x86emu * emu,uint16_t d,uint16_t fill,uint8_t s)7516884e6d60SXin LI shld_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
7517884e6d60SXin LI {
7518884e6d60SXin LI unsigned int cnt, res, cf;
7519884e6d60SXin LI
7520884e6d60SXin LI if (s < 16) {
7521884e6d60SXin LI cnt = s % 16;
7522884e6d60SXin LI if (cnt > 0) {
7523884e6d60SXin LI res = (d << cnt) | (fill >> (16 - cnt));
7524884e6d60SXin LI cf = d & (1 << (16 - cnt));
7525884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7526884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7527884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7528884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7529884e6d60SXin LI } else {
7530884e6d60SXin LI res = d;
7531884e6d60SXin LI }
7532884e6d60SXin LI if (cnt == 1) {
7533884e6d60SXin LI CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
7534884e6d60SXin LI (ACCESS_FLAG(F_CF) != 0)), F_OF);
7535884e6d60SXin LI } else {
7536884e6d60SXin LI CLEAR_FLAG(F_OF);
7537884e6d60SXin LI }
7538884e6d60SXin LI } else {
7539884e6d60SXin LI res = 0;
7540884e6d60SXin LI CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
7541884e6d60SXin LI CLEAR_FLAG(F_OF);
7542884e6d60SXin LI CLEAR_FLAG(F_SF);
7543884e6d60SXin LI SET_FLAG(F_PF);
7544884e6d60SXin LI SET_FLAG(F_ZF);
7545884e6d60SXin LI }
7546884e6d60SXin LI return (uint16_t) res;
7547884e6d60SXin LI }
7548884e6d60SXin LI
7549884e6d60SXin LI /*
7550884e6d60SXin LI * REMARKS:
7551884e6d60SXin LI * Implements the SHLD instruction and side effects.
7552884e6d60SXin LI */
7553884e6d60SXin LI static uint32_t
shld_long(struct x86emu * emu,uint32_t d,uint32_t fill,uint8_t s)7554884e6d60SXin LI shld_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
7555884e6d60SXin LI {
7556884e6d60SXin LI unsigned int cnt, res, cf;
7557884e6d60SXin LI
7558884e6d60SXin LI if (s < 32) {
7559884e6d60SXin LI cnt = s % 32;
7560884e6d60SXin LI if (cnt > 0) {
7561884e6d60SXin LI res = (d << cnt) | (fill >> (32 - cnt));
7562884e6d60SXin LI cf = d & (1 << (32 - cnt));
7563884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7564884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7565884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7566884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7567884e6d60SXin LI } else {
7568884e6d60SXin LI res = d;
7569884e6d60SXin LI }
7570884e6d60SXin LI if (cnt == 1) {
757106325fe0SXin LI CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000)
757206325fe0SXin LI ^ (ACCESS_FLAG(F_CF) != 0)), F_OF);
7573884e6d60SXin LI } else {
7574884e6d60SXin LI CLEAR_FLAG(F_OF);
7575884e6d60SXin LI }
7576884e6d60SXin LI } else {
7577884e6d60SXin LI res = 0;
7578884e6d60SXin LI CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
7579884e6d60SXin LI CLEAR_FLAG(F_OF);
7580884e6d60SXin LI CLEAR_FLAG(F_SF);
7581884e6d60SXin LI SET_FLAG(F_PF);
7582884e6d60SXin LI SET_FLAG(F_ZF);
7583884e6d60SXin LI }
7584884e6d60SXin LI return res;
7585884e6d60SXin LI }
7586884e6d60SXin LI
7587884e6d60SXin LI /*
7588884e6d60SXin LI * REMARKS:
7589884e6d60SXin LI * Implements the SHRD instruction and side effects.
7590884e6d60SXin LI */
7591884e6d60SXin LI static uint16_t
shrd_word(struct x86emu * emu,uint16_t d,uint16_t fill,uint8_t s)7592884e6d60SXin LI shrd_word(struct x86emu *emu, uint16_t d, uint16_t fill, uint8_t s)
7593884e6d60SXin LI {
7594884e6d60SXin LI unsigned int cnt, res, cf;
7595884e6d60SXin LI
7596884e6d60SXin LI if (s < 16) {
7597884e6d60SXin LI cnt = s % 16;
7598884e6d60SXin LI if (cnt > 0) {
7599884e6d60SXin LI cf = d & (1 << (cnt - 1));
7600884e6d60SXin LI res = (d >> cnt) | (fill << (16 - cnt));
7601884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7602884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7603884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7604884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7605884e6d60SXin LI } else {
7606884e6d60SXin LI res = d;
7607884e6d60SXin LI }
7608884e6d60SXin LI
7609884e6d60SXin LI if (cnt == 1) {
7610884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
7611884e6d60SXin LI } else {
7612884e6d60SXin LI CLEAR_FLAG(F_OF);
7613884e6d60SXin LI }
7614884e6d60SXin LI } else {
7615884e6d60SXin LI res = 0;
7616884e6d60SXin LI CLEAR_FLAG(F_CF);
7617884e6d60SXin LI CLEAR_FLAG(F_OF);
7618884e6d60SXin LI SET_FLAG(F_ZF);
7619884e6d60SXin LI CLEAR_FLAG(F_SF);
7620884e6d60SXin LI CLEAR_FLAG(F_PF);
7621884e6d60SXin LI }
7622884e6d60SXin LI return (uint16_t) res;
7623884e6d60SXin LI }
7624884e6d60SXin LI
7625884e6d60SXin LI /*
7626884e6d60SXin LI * REMARKS:
7627884e6d60SXin LI * Implements the SHRD instruction and side effects.
7628884e6d60SXin LI */
7629884e6d60SXin LI static uint32_t
shrd_long(struct x86emu * emu,uint32_t d,uint32_t fill,uint8_t s)7630884e6d60SXin LI shrd_long(struct x86emu *emu, uint32_t d, uint32_t fill, uint8_t s)
7631884e6d60SXin LI {
7632884e6d60SXin LI unsigned int cnt, res, cf;
7633884e6d60SXin LI
7634884e6d60SXin LI if (s < 32) {
7635884e6d60SXin LI cnt = s % 32;
7636884e6d60SXin LI if (cnt > 0) {
7637884e6d60SXin LI cf = d & (1 << (cnt - 1));
7638884e6d60SXin LI res = (d >> cnt) | (fill << (32 - cnt));
7639884e6d60SXin LI CONDITIONAL_SET_FLAG(cf, F_CF);
7640884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7641884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7642884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7643884e6d60SXin LI } else {
7644884e6d60SXin LI res = d;
7645884e6d60SXin LI }
7646884e6d60SXin LI if (cnt == 1) {
7647884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
7648884e6d60SXin LI } else {
7649884e6d60SXin LI CLEAR_FLAG(F_OF);
7650884e6d60SXin LI }
7651884e6d60SXin LI } else {
7652884e6d60SXin LI res = 0;
7653884e6d60SXin LI CLEAR_FLAG(F_CF);
7654884e6d60SXin LI CLEAR_FLAG(F_OF);
7655884e6d60SXin LI SET_FLAG(F_ZF);
7656884e6d60SXin LI CLEAR_FLAG(F_SF);
7657884e6d60SXin LI CLEAR_FLAG(F_PF);
7658884e6d60SXin LI }
7659884e6d60SXin LI return res;
7660884e6d60SXin LI }
7661884e6d60SXin LI
7662884e6d60SXin LI /*
7663884e6d60SXin LI * REMARKS:
7664884e6d60SXin LI * Implements the SBB instruction and side effects.
7665884e6d60SXin LI */
7666884e6d60SXin LI static uint8_t
sbb_byte(struct x86emu * emu,uint8_t d,uint8_t s)7667884e6d60SXin LI sbb_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7668884e6d60SXin LI {
7669884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7670884e6d60SXin LI uint32_t bc;
7671884e6d60SXin LI
7672884e6d60SXin LI if (ACCESS_FLAG(F_CF))
7673884e6d60SXin LI res = d - s - 1;
7674884e6d60SXin LI else
7675884e6d60SXin LI res = d - s;
7676884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7677884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
7678884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7679884e6d60SXin LI
7680884e6d60SXin LI /* calculate the borrow chain. See note at top */
7681884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7682884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
7683884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
7684884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7685884e6d60SXin LI return (uint8_t) res;
7686884e6d60SXin LI }
7687884e6d60SXin LI
7688884e6d60SXin LI /*
7689884e6d60SXin LI * REMARKS:
7690884e6d60SXin LI * Implements the SBB instruction and side effects.
7691884e6d60SXin LI */
7692884e6d60SXin LI static uint16_t
sbb_word(struct x86emu * emu,uint16_t d,uint16_t s)7693884e6d60SXin LI sbb_word(struct x86emu *emu, uint16_t d, uint16_t s)
7694884e6d60SXin LI {
7695884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7696884e6d60SXin LI uint32_t bc;
7697884e6d60SXin LI
7698884e6d60SXin LI if (ACCESS_FLAG(F_CF))
7699884e6d60SXin LI res = d - s - 1;
7700884e6d60SXin LI else
7701884e6d60SXin LI res = d - s;
7702884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7703884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7704884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7705884e6d60SXin LI
7706884e6d60SXin LI /* calculate the borrow chain. See note at top */
7707884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7708884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
7709884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
7710884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7711884e6d60SXin LI return (uint16_t) res;
7712884e6d60SXin LI }
7713884e6d60SXin LI
7714884e6d60SXin LI /*
7715884e6d60SXin LI * REMARKS:
7716884e6d60SXin LI * Implements the SBB instruction and side effects.
7717884e6d60SXin LI */
7718884e6d60SXin LI static uint32_t
sbb_long(struct x86emu * emu,uint32_t d,uint32_t s)7719884e6d60SXin LI sbb_long(struct x86emu *emu, uint32_t d, uint32_t s)
7720884e6d60SXin LI {
7721884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7722884e6d60SXin LI uint32_t bc;
7723884e6d60SXin LI
7724884e6d60SXin LI if (ACCESS_FLAG(F_CF))
7725884e6d60SXin LI res = d - s - 1;
7726884e6d60SXin LI else
7727884e6d60SXin LI res = d - s;
7728884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7729884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7730884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7731884e6d60SXin LI
7732884e6d60SXin LI /* calculate the borrow chain. See note at top */
7733884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7734884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
7735884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
7736884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7737884e6d60SXin LI return res;
7738884e6d60SXin LI }
7739884e6d60SXin LI
7740884e6d60SXin LI /*
7741884e6d60SXin LI * REMARKS:
7742884e6d60SXin LI * Implements the SUB instruction and side effects.
7743884e6d60SXin LI */
7744884e6d60SXin LI static uint8_t
sub_byte(struct x86emu * emu,uint8_t d,uint8_t s)7745884e6d60SXin LI sub_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7746884e6d60SXin LI {
7747884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7748884e6d60SXin LI uint32_t bc;
7749884e6d60SXin LI
7750884e6d60SXin LI res = d - s;
7751884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7752884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
7753884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7754884e6d60SXin LI
7755884e6d60SXin LI /* calculate the borrow chain. See note at top */
7756884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7757884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
7758884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
7759884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7760884e6d60SXin LI return (uint8_t) res;
7761884e6d60SXin LI }
7762884e6d60SXin LI
7763884e6d60SXin LI /*
7764884e6d60SXin LI * REMARKS:
7765884e6d60SXin LI * Implements the SUB instruction and side effects.
7766884e6d60SXin LI */
7767884e6d60SXin LI static uint16_t
sub_word(struct x86emu * emu,uint16_t d,uint16_t s)7768884e6d60SXin LI sub_word(struct x86emu *emu, uint16_t d, uint16_t s)
7769884e6d60SXin LI {
7770884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7771884e6d60SXin LI uint32_t bc;
7772884e6d60SXin LI
7773884e6d60SXin LI res = d - s;
7774884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7775884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
7776884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7777884e6d60SXin LI
7778884e6d60SXin LI /* calculate the borrow chain. See note at top */
7779884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7780884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
7781884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
7782884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7783884e6d60SXin LI return (uint16_t) res;
7784884e6d60SXin LI }
7785884e6d60SXin LI
7786884e6d60SXin LI /*
7787884e6d60SXin LI * REMARKS:
7788884e6d60SXin LI * Implements the SUB instruction and side effects.
7789884e6d60SXin LI */
7790884e6d60SXin LI static uint32_t
sub_long(struct x86emu * emu,uint32_t d,uint32_t s)7791884e6d60SXin LI sub_long(struct x86emu *emu, uint32_t d, uint32_t s)
7792884e6d60SXin LI {
7793884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7794884e6d60SXin LI uint32_t bc;
7795884e6d60SXin LI
7796884e6d60SXin LI res = d - s;
7797884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7798884e6d60SXin LI CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
7799884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7800884e6d60SXin LI
7801884e6d60SXin LI /* calculate the borrow chain. See note at top */
7802884e6d60SXin LI bc = (res & (~d | s)) | (~d & s);
7803884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
7804884e6d60SXin LI CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
7805884e6d60SXin LI CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
7806884e6d60SXin LI return res;
7807884e6d60SXin LI }
7808884e6d60SXin LI
7809884e6d60SXin LI /*
7810884e6d60SXin LI * REMARKS:
7811884e6d60SXin LI * Implements the TEST instruction and side effects.
7812884e6d60SXin LI */
7813884e6d60SXin LI static void
test_byte(struct x86emu * emu,uint8_t d,uint8_t s)7814884e6d60SXin LI test_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7815884e6d60SXin LI {
7816884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7817884e6d60SXin LI
7818884e6d60SXin LI res = d & s;
7819884e6d60SXin LI
7820884e6d60SXin LI CLEAR_FLAG(F_OF);
7821884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7822884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7823884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7824884e6d60SXin LI /* AF == dont care */
7825884e6d60SXin LI CLEAR_FLAG(F_CF);
7826884e6d60SXin LI }
7827884e6d60SXin LI
7828884e6d60SXin LI /*
7829884e6d60SXin LI * REMARKS:
7830884e6d60SXin LI * Implements the TEST instruction and side effects.
7831884e6d60SXin LI */
7832884e6d60SXin LI static void
test_word(struct x86emu * emu,uint16_t d,uint16_t s)7833884e6d60SXin LI test_word(struct x86emu *emu, uint16_t d, uint16_t s)
7834884e6d60SXin LI {
7835884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7836884e6d60SXin LI
7837884e6d60SXin LI res = d & s;
7838884e6d60SXin LI
7839884e6d60SXin LI CLEAR_FLAG(F_OF);
7840884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7841884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7842884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7843884e6d60SXin LI /* AF == dont care */
7844884e6d60SXin LI CLEAR_FLAG(F_CF);
7845884e6d60SXin LI }
7846884e6d60SXin LI
7847884e6d60SXin LI /*
7848884e6d60SXin LI * REMARKS:
7849884e6d60SXin LI * Implements the TEST instruction and side effects.
7850884e6d60SXin LI */
7851884e6d60SXin LI static void
test_long(struct x86emu * emu,uint32_t d,uint32_t s)7852884e6d60SXin LI test_long(struct x86emu *emu, uint32_t d, uint32_t s)
7853884e6d60SXin LI {
7854884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7855884e6d60SXin LI
7856884e6d60SXin LI res = d & s;
7857884e6d60SXin LI
7858884e6d60SXin LI CLEAR_FLAG(F_OF);
7859884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7860884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7861884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7862884e6d60SXin LI /* AF == dont care */
7863884e6d60SXin LI CLEAR_FLAG(F_CF);
7864884e6d60SXin LI }
7865884e6d60SXin LI
7866884e6d60SXin LI /*
7867884e6d60SXin LI * REMARKS:
7868884e6d60SXin LI * Implements the XOR instruction and side effects.
7869884e6d60SXin LI */
7870884e6d60SXin LI static uint8_t
xor_byte(struct x86emu * emu,uint8_t d,uint8_t s)7871884e6d60SXin LI xor_byte(struct x86emu *emu, uint8_t d, uint8_t s)
7872884e6d60SXin LI {
7873884e6d60SXin LI uint8_t res; /* all operands in native machine order */
7874884e6d60SXin LI
7875884e6d60SXin LI res = d ^ s;
7876884e6d60SXin LI CLEAR_FLAG(F_OF);
7877884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
7878884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7879884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
7880884e6d60SXin LI CLEAR_FLAG(F_CF);
7881884e6d60SXin LI CLEAR_FLAG(F_AF);
7882884e6d60SXin LI return res;
7883884e6d60SXin LI }
7884884e6d60SXin LI
7885884e6d60SXin LI /*
7886884e6d60SXin LI * REMARKS:
7887884e6d60SXin LI * Implements the XOR instruction and side effects.
7888884e6d60SXin LI */
7889884e6d60SXin LI static uint16_t
xor_word(struct x86emu * emu,uint16_t d,uint16_t s)7890884e6d60SXin LI xor_word(struct x86emu *emu, uint16_t d, uint16_t s)
7891884e6d60SXin LI {
7892884e6d60SXin LI uint16_t res; /* all operands in native machine order */
7893884e6d60SXin LI
7894884e6d60SXin LI res = d ^ s;
7895884e6d60SXin LI CLEAR_FLAG(F_OF);
7896884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
7897884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7898884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7899884e6d60SXin LI CLEAR_FLAG(F_CF);
7900884e6d60SXin LI CLEAR_FLAG(F_AF);
7901884e6d60SXin LI return res;
7902884e6d60SXin LI }
7903884e6d60SXin LI
7904884e6d60SXin LI /*
7905884e6d60SXin LI * REMARKS:
7906884e6d60SXin LI * Implements the XOR instruction and side effects.
7907884e6d60SXin LI */
7908884e6d60SXin LI static uint32_t
xor_long(struct x86emu * emu,uint32_t d,uint32_t s)7909884e6d60SXin LI xor_long(struct x86emu *emu, uint32_t d, uint32_t s)
7910884e6d60SXin LI {
7911884e6d60SXin LI uint32_t res; /* all operands in native machine order */
7912884e6d60SXin LI
7913884e6d60SXin LI res = d ^ s;
7914884e6d60SXin LI CLEAR_FLAG(F_OF);
7915884e6d60SXin LI CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
7916884e6d60SXin LI CONDITIONAL_SET_FLAG(res == 0, F_ZF);
7917884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
7918884e6d60SXin LI CLEAR_FLAG(F_CF);
7919884e6d60SXin LI CLEAR_FLAG(F_AF);
7920884e6d60SXin LI return res;
7921884e6d60SXin LI }
7922884e6d60SXin LI
7923884e6d60SXin LI /*
7924884e6d60SXin LI * REMARKS:
7925884e6d60SXin LI * Implements the IMUL instruction and side effects.
7926884e6d60SXin LI */
7927884e6d60SXin LI static void
imul_byte(struct x86emu * emu,uint8_t s)7928884e6d60SXin LI imul_byte(struct x86emu *emu, uint8_t s)
7929884e6d60SXin LI {
7930884e6d60SXin LI int16_t res = (int16_t) ((int8_t) emu->x86.R_AL * (int8_t) s);
7931884e6d60SXin LI
7932884e6d60SXin LI emu->x86.R_AX = res;
7933884e6d60SXin LI if (((emu->x86.R_AL & 0x80) == 0 && emu->x86.R_AH == 0x00) ||
7934884e6d60SXin LI ((emu->x86.R_AL & 0x80) != 0 && emu->x86.R_AH == 0xFF)) {
7935884e6d60SXin LI CLEAR_FLAG(F_CF);
7936884e6d60SXin LI CLEAR_FLAG(F_OF);
7937884e6d60SXin LI } else {
7938884e6d60SXin LI SET_FLAG(F_CF);
7939884e6d60SXin LI SET_FLAG(F_OF);
7940884e6d60SXin LI }
7941884e6d60SXin LI }
7942884e6d60SXin LI
7943884e6d60SXin LI /*
7944884e6d60SXin LI * REMARKS:
7945884e6d60SXin LI * Implements the IMUL instruction and side effects.
7946884e6d60SXin LI */
7947884e6d60SXin LI static void
imul_word(struct x86emu * emu,uint16_t s)7948884e6d60SXin LI imul_word(struct x86emu *emu, uint16_t s)
7949884e6d60SXin LI {
7950884e6d60SXin LI int32_t res = (int16_t) emu->x86.R_AX * (int16_t) s;
7951884e6d60SXin LI
7952884e6d60SXin LI emu->x86.R_AX = (uint16_t) res;
7953884e6d60SXin LI emu->x86.R_DX = (uint16_t) (res >> 16);
7954884e6d60SXin LI if (((emu->x86.R_AX & 0x8000) == 0 && emu->x86.R_DX == 0x00) ||
7955884e6d60SXin LI ((emu->x86.R_AX & 0x8000) != 0 && emu->x86.R_DX == 0xFF)) {
7956884e6d60SXin LI CLEAR_FLAG(F_CF);
7957884e6d60SXin LI CLEAR_FLAG(F_OF);
7958884e6d60SXin LI } else {
7959884e6d60SXin LI SET_FLAG(F_CF);
7960884e6d60SXin LI SET_FLAG(F_OF);
7961884e6d60SXin LI }
7962884e6d60SXin LI }
7963884e6d60SXin LI
7964884e6d60SXin LI /*
7965884e6d60SXin LI * REMARKS:
7966884e6d60SXin LI * Implements the IMUL instruction and side effects.
7967884e6d60SXin LI */
7968884e6d60SXin LI static void
imul_long(struct x86emu * emu,uint32_t s)7969884e6d60SXin LI imul_long(struct x86emu *emu, uint32_t s)
7970884e6d60SXin LI {
7971884e6d60SXin LI int64_t res;
7972884e6d60SXin LI
7973884e6d60SXin LI res = (int64_t)(int32_t)emu->x86.R_EAX * (int32_t)s;
7974884e6d60SXin LI emu->x86.R_EAX = (uint32_t)res;
7975884e6d60SXin LI emu->x86.R_EDX = ((uint64_t)res) >> 32;
7976884e6d60SXin LI if (((emu->x86.R_EAX & 0x80000000) == 0 && emu->x86.R_EDX == 0x00) ||
7977884e6d60SXin LI ((emu->x86.R_EAX & 0x80000000) != 0 && emu->x86.R_EDX == 0xFF)) {
7978884e6d60SXin LI CLEAR_FLAG(F_CF);
7979884e6d60SXin LI CLEAR_FLAG(F_OF);
7980884e6d60SXin LI } else {
7981884e6d60SXin LI SET_FLAG(F_CF);
7982884e6d60SXin LI SET_FLAG(F_OF);
7983884e6d60SXin LI }
7984884e6d60SXin LI }
7985884e6d60SXin LI
7986884e6d60SXin LI /*
7987884e6d60SXin LI * REMARKS:
7988884e6d60SXin LI * Implements the MUL instruction and side effects.
7989884e6d60SXin LI */
7990884e6d60SXin LI static void
mul_byte(struct x86emu * emu,uint8_t s)7991884e6d60SXin LI mul_byte(struct x86emu *emu, uint8_t s)
7992884e6d60SXin LI {
7993884e6d60SXin LI uint16_t res = (uint16_t) (emu->x86.R_AL * s);
7994884e6d60SXin LI
7995884e6d60SXin LI emu->x86.R_AX = res;
7996884e6d60SXin LI if (emu->x86.R_AH == 0) {
7997884e6d60SXin LI CLEAR_FLAG(F_CF);
7998884e6d60SXin LI CLEAR_FLAG(F_OF);
7999884e6d60SXin LI } else {
8000884e6d60SXin LI SET_FLAG(F_CF);
8001884e6d60SXin LI SET_FLAG(F_OF);
8002884e6d60SXin LI }
8003884e6d60SXin LI }
8004884e6d60SXin LI
8005884e6d60SXin LI /*
8006884e6d60SXin LI * REMARKS:
8007884e6d60SXin LI * Implements the MUL instruction and side effects.
8008884e6d60SXin LI */
8009884e6d60SXin LI static void
mul_word(struct x86emu * emu,uint16_t s)8010884e6d60SXin LI mul_word(struct x86emu *emu, uint16_t s)
8011884e6d60SXin LI {
8012884e6d60SXin LI uint32_t res = emu->x86.R_AX * s;
8013884e6d60SXin LI
8014884e6d60SXin LI emu->x86.R_AX = (uint16_t) res;
8015884e6d60SXin LI emu->x86.R_DX = (uint16_t) (res >> 16);
8016884e6d60SXin LI if (emu->x86.R_DX == 0) {
8017884e6d60SXin LI CLEAR_FLAG(F_CF);
8018884e6d60SXin LI CLEAR_FLAG(F_OF);
8019884e6d60SXin LI } else {
8020884e6d60SXin LI SET_FLAG(F_CF);
8021884e6d60SXin LI SET_FLAG(F_OF);
8022884e6d60SXin LI }
8023884e6d60SXin LI }
8024884e6d60SXin LI
8025884e6d60SXin LI /*
8026884e6d60SXin LI * REMARKS:
8027884e6d60SXin LI * Implements the MUL instruction and side effects.
8028884e6d60SXin LI */
8029884e6d60SXin LI static void
mul_long(struct x86emu * emu,uint32_t s)8030884e6d60SXin LI mul_long(struct x86emu *emu, uint32_t s)
8031884e6d60SXin LI {
8032884e6d60SXin LI uint64_t res = (uint64_t) emu->x86.R_EAX * s;
8033884e6d60SXin LI
8034884e6d60SXin LI emu->x86.R_EAX = (uint32_t) res;
8035884e6d60SXin LI emu->x86.R_EDX = (uint32_t) (res >> 32);
8036884e6d60SXin LI
8037884e6d60SXin LI if (emu->x86.R_EDX == 0) {
8038884e6d60SXin LI CLEAR_FLAG(F_CF);
8039884e6d60SXin LI CLEAR_FLAG(F_OF);
8040884e6d60SXin LI } else {
8041884e6d60SXin LI SET_FLAG(F_CF);
8042884e6d60SXin LI SET_FLAG(F_OF);
8043884e6d60SXin LI }
8044884e6d60SXin LI }
8045884e6d60SXin LI
8046884e6d60SXin LI /*
8047884e6d60SXin LI * REMARKS:
8048884e6d60SXin LI * Implements the IDIV instruction and side effects.
8049884e6d60SXin LI */
8050884e6d60SXin LI static void
idiv_byte(struct x86emu * emu,uint8_t s)8051884e6d60SXin LI idiv_byte(struct x86emu *emu, uint8_t s)
8052884e6d60SXin LI {
8053884e6d60SXin LI int32_t dvd, div, mod;
8054884e6d60SXin LI
8055884e6d60SXin LI dvd = (int16_t) emu->x86.R_AX;
8056884e6d60SXin LI if (s == 0) {
8057884e6d60SXin LI x86emu_intr_raise(emu, 8);
8058884e6d60SXin LI return;
8059884e6d60SXin LI }
8060884e6d60SXin LI div = dvd / (int8_t) s;
8061884e6d60SXin LI mod = dvd % (int8_t) s;
8062884e6d60SXin LI if (div > 0x7f || div < -0x7f) {
8063884e6d60SXin LI x86emu_intr_raise(emu, 8);
8064884e6d60SXin LI return;
8065884e6d60SXin LI }
8066884e6d60SXin LI emu->x86.R_AL = (int8_t) div;
8067884e6d60SXin LI emu->x86.R_AH = (int8_t) mod;
8068884e6d60SXin LI }
8069884e6d60SXin LI
8070884e6d60SXin LI /*
8071884e6d60SXin LI * REMARKS:
8072884e6d60SXin LI * Implements the IDIV instruction and side effects.
8073884e6d60SXin LI */
8074884e6d60SXin LI static void
idiv_word(struct x86emu * emu,uint16_t s)8075884e6d60SXin LI idiv_word(struct x86emu *emu, uint16_t s)
8076884e6d60SXin LI {
8077884e6d60SXin LI int32_t dvd, div, mod;
8078884e6d60SXin LI
8079884e6d60SXin LI dvd = (((int32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
8080884e6d60SXin LI if (s == 0) {
8081884e6d60SXin LI x86emu_intr_raise(emu, 8);
8082884e6d60SXin LI return;
8083884e6d60SXin LI }
8084884e6d60SXin LI div = dvd / (int16_t) s;
8085884e6d60SXin LI mod = dvd % (int16_t) s;
8086884e6d60SXin LI if (div > 0x7fff || div < -0x7fff) {
8087884e6d60SXin LI x86emu_intr_raise(emu, 8);
8088884e6d60SXin LI return;
8089884e6d60SXin LI }
8090884e6d60SXin LI CLEAR_FLAG(F_CF);
8091884e6d60SXin LI CLEAR_FLAG(F_SF);
8092884e6d60SXin LI CONDITIONAL_SET_FLAG(div == 0, F_ZF);
8093884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
8094884e6d60SXin LI
8095884e6d60SXin LI emu->x86.R_AX = (uint16_t) div;
8096884e6d60SXin LI emu->x86.R_DX = (uint16_t) mod;
8097884e6d60SXin LI }
8098884e6d60SXin LI
8099884e6d60SXin LI /*
8100884e6d60SXin LI * REMARKS:
8101884e6d60SXin LI * Implements the IDIV instruction and side effects.
8102884e6d60SXin LI */
8103884e6d60SXin LI static void
idiv_long(struct x86emu * emu,uint32_t s)8104884e6d60SXin LI idiv_long(struct x86emu *emu, uint32_t s)
8105884e6d60SXin LI {
8106884e6d60SXin LI int64_t dvd, div, mod;
8107884e6d60SXin LI
8108884e6d60SXin LI dvd = (((int64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
8109884e6d60SXin LI if (s == 0) {
8110884e6d60SXin LI x86emu_intr_raise(emu, 8);
8111884e6d60SXin LI return;
8112884e6d60SXin LI }
8113884e6d60SXin LI div = dvd / (int32_t) s;
8114884e6d60SXin LI mod = dvd % (int32_t) s;
8115884e6d60SXin LI if (div > 0x7fffffff || div < -0x7fffffff) {
8116884e6d60SXin LI x86emu_intr_raise(emu, 8);
8117884e6d60SXin LI return;
8118884e6d60SXin LI }
8119884e6d60SXin LI CLEAR_FLAG(F_CF);
8120884e6d60SXin LI CLEAR_FLAG(F_AF);
8121884e6d60SXin LI CLEAR_FLAG(F_SF);
8122884e6d60SXin LI SET_FLAG(F_ZF);
8123884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
8124884e6d60SXin LI
8125884e6d60SXin LI emu->x86.R_EAX = (uint32_t) div;
8126884e6d60SXin LI emu->x86.R_EDX = (uint32_t) mod;
8127884e6d60SXin LI }
8128884e6d60SXin LI
8129884e6d60SXin LI /*
8130884e6d60SXin LI * REMARKS:
8131884e6d60SXin LI * Implements the DIV instruction and side effects.
8132884e6d60SXin LI */
8133884e6d60SXin LI static void
div_byte(struct x86emu * emu,uint8_t s)8134884e6d60SXin LI div_byte(struct x86emu *emu, uint8_t s)
8135884e6d60SXin LI {
8136884e6d60SXin LI uint32_t dvd, div, mod;
8137884e6d60SXin LI
8138884e6d60SXin LI dvd = emu->x86.R_AX;
8139884e6d60SXin LI if (s == 0) {
8140884e6d60SXin LI x86emu_intr_raise(emu, 8);
8141884e6d60SXin LI return;
8142884e6d60SXin LI }
8143884e6d60SXin LI div = dvd / (uint8_t) s;
8144884e6d60SXin LI mod = dvd % (uint8_t) s;
8145884e6d60SXin LI if (div > 0xff) {
8146884e6d60SXin LI x86emu_intr_raise(emu, 8);
8147884e6d60SXin LI return;
8148884e6d60SXin LI }
8149884e6d60SXin LI emu->x86.R_AL = (uint8_t) div;
8150884e6d60SXin LI emu->x86.R_AH = (uint8_t) mod;
8151884e6d60SXin LI }
8152884e6d60SXin LI
8153884e6d60SXin LI /*
8154884e6d60SXin LI * REMARKS:
8155884e6d60SXin LI * Implements the DIV instruction and side effects.
8156884e6d60SXin LI */
8157884e6d60SXin LI static void
div_word(struct x86emu * emu,uint16_t s)8158884e6d60SXin LI div_word(struct x86emu *emu, uint16_t s)
8159884e6d60SXin LI {
8160884e6d60SXin LI uint32_t dvd, div, mod;
8161884e6d60SXin LI
8162884e6d60SXin LI dvd = (((uint32_t) emu->x86.R_DX) << 16) | emu->x86.R_AX;
8163884e6d60SXin LI if (s == 0) {
8164884e6d60SXin LI x86emu_intr_raise(emu, 8);
8165884e6d60SXin LI return;
8166884e6d60SXin LI }
8167884e6d60SXin LI div = dvd / (uint16_t) s;
8168884e6d60SXin LI mod = dvd % (uint16_t) s;
8169884e6d60SXin LI if (div > 0xffff) {
8170884e6d60SXin LI x86emu_intr_raise(emu, 8);
8171884e6d60SXin LI return;
8172884e6d60SXin LI }
8173884e6d60SXin LI CLEAR_FLAG(F_CF);
8174884e6d60SXin LI CLEAR_FLAG(F_SF);
8175884e6d60SXin LI CONDITIONAL_SET_FLAG(div == 0, F_ZF);
8176884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
8177884e6d60SXin LI
8178884e6d60SXin LI emu->x86.R_AX = (uint16_t) div;
8179884e6d60SXin LI emu->x86.R_DX = (uint16_t) mod;
8180884e6d60SXin LI }
8181884e6d60SXin LI
8182884e6d60SXin LI /*
8183884e6d60SXin LI * REMARKS:
8184884e6d60SXin LI * Implements the DIV instruction and side effects.
8185884e6d60SXin LI */
8186884e6d60SXin LI static void
div_long(struct x86emu * emu,uint32_t s)8187884e6d60SXin LI div_long(struct x86emu *emu, uint32_t s)
8188884e6d60SXin LI {
8189884e6d60SXin LI uint64_t dvd, div, mod;
8190884e6d60SXin LI
8191884e6d60SXin LI dvd = (((uint64_t) emu->x86.R_EDX) << 32) | emu->x86.R_EAX;
8192884e6d60SXin LI if (s == 0) {
8193884e6d60SXin LI x86emu_intr_raise(emu, 8);
8194884e6d60SXin LI return;
8195884e6d60SXin LI }
8196884e6d60SXin LI div = dvd / (uint32_t) s;
8197884e6d60SXin LI mod = dvd % (uint32_t) s;
8198884e6d60SXin LI if (div > 0xffffffff) {
8199884e6d60SXin LI x86emu_intr_raise(emu, 8);
8200884e6d60SXin LI return;
8201884e6d60SXin LI }
8202884e6d60SXin LI CLEAR_FLAG(F_CF);
8203884e6d60SXin LI CLEAR_FLAG(F_AF);
8204884e6d60SXin LI CLEAR_FLAG(F_SF);
8205884e6d60SXin LI SET_FLAG(F_ZF);
8206884e6d60SXin LI CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
8207884e6d60SXin LI
8208884e6d60SXin LI emu->x86.R_EAX = (uint32_t) div;
8209884e6d60SXin LI emu->x86.R_EDX = (uint32_t) mod;
8210884e6d60SXin LI }
8211884e6d60SXin LI
8212884e6d60SXin LI /*
8213884e6d60SXin LI * REMARKS:
8214884e6d60SXin LI * Implements the IN string instruction and side effects.
8215884e6d60SXin LI */
8216884e6d60SXin LI static void
ins(struct x86emu * emu,int size)8217884e6d60SXin LI ins(struct x86emu *emu, int size)
8218884e6d60SXin LI {
8219884e6d60SXin LI int inc = size;
8220884e6d60SXin LI
8221884e6d60SXin LI if (ACCESS_FLAG(F_DF)) {
8222884e6d60SXin LI inc = -size;
8223884e6d60SXin LI }
8224884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
8225884e6d60SXin LI /* dont care whether REPE or REPNE */
8226884e6d60SXin LI /* in until CX is ZERO. */
8227884e6d60SXin LI uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
8228884e6d60SXin LI emu->x86.R_ECX : emu->x86.R_CX);
8229884e6d60SXin LI switch (size) {
8230884e6d60SXin LI case 1:
8231884e6d60SXin LI while (count--) {
8232884e6d60SXin LI store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
8233884e6d60SXin LI (*emu->emu_inb) (emu, emu->x86.R_DX));
8234884e6d60SXin LI emu->x86.R_DI += inc;
8235884e6d60SXin LI }
8236884e6d60SXin LI break;
8237884e6d60SXin LI
8238884e6d60SXin LI case 2:
8239884e6d60SXin LI while (count--) {
8240884e6d60SXin LI store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
8241884e6d60SXin LI (*emu->emu_inw) (emu, emu->x86.R_DX));
8242884e6d60SXin LI emu->x86.R_DI += inc;
8243884e6d60SXin LI }
8244884e6d60SXin LI break;
8245884e6d60SXin LI case 4:
8246884e6d60SXin LI while (count--) {
8247884e6d60SXin LI store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
8248884e6d60SXin LI (*emu->emu_inl) (emu, emu->x86.R_DX));
8249884e6d60SXin LI emu->x86.R_DI += inc;
8250884e6d60SXin LI break;
8251884e6d60SXin LI }
8252884e6d60SXin LI }
8253884e6d60SXin LI emu->x86.R_CX = 0;
8254884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
8255884e6d60SXin LI emu->x86.R_ECX = 0;
8256884e6d60SXin LI }
8257884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
8258884e6d60SXin LI } else {
8259884e6d60SXin LI switch (size) {
8260884e6d60SXin LI case 1:
8261884e6d60SXin LI store_byte(emu, emu->x86.R_ES, emu->x86.R_DI,
8262884e6d60SXin LI (*emu->emu_inb) (emu, emu->x86.R_DX));
8263884e6d60SXin LI break;
8264884e6d60SXin LI case 2:
8265884e6d60SXin LI store_word(emu, emu->x86.R_ES, emu->x86.R_DI,
8266884e6d60SXin LI (*emu->emu_inw) (emu, emu->x86.R_DX));
8267884e6d60SXin LI break;
8268884e6d60SXin LI case 4:
8269884e6d60SXin LI store_long(emu, emu->x86.R_ES, emu->x86.R_DI,
8270884e6d60SXin LI (*emu->emu_inl) (emu, emu->x86.R_DX));
8271884e6d60SXin LI break;
8272884e6d60SXin LI }
8273884e6d60SXin LI emu->x86.R_DI += inc;
8274884e6d60SXin LI }
8275884e6d60SXin LI }
8276884e6d60SXin LI
8277884e6d60SXin LI /*
8278884e6d60SXin LI * REMARKS:
8279884e6d60SXin LI * Implements the OUT string instruction and side effects.
8280884e6d60SXin LI */
8281884e6d60SXin LI static void
outs(struct x86emu * emu,int size)8282884e6d60SXin LI outs(struct x86emu *emu, int size)
8283884e6d60SXin LI {
8284884e6d60SXin LI int inc = size;
8285884e6d60SXin LI
8286884e6d60SXin LI if (ACCESS_FLAG(F_DF)) {
8287884e6d60SXin LI inc = -size;
8288884e6d60SXin LI }
8289884e6d60SXin LI if (emu->x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
8290884e6d60SXin LI /* dont care whether REPE or REPNE */
8291884e6d60SXin LI /* out until CX is ZERO. */
8292884e6d60SXin LI uint32_t count = ((emu->x86.mode & SYSMODE_PREFIX_DATA) ?
8293884e6d60SXin LI emu->x86.R_ECX : emu->x86.R_CX);
8294884e6d60SXin LI switch (size) {
8295884e6d60SXin LI case 1:
8296884e6d60SXin LI while (count--) {
8297884e6d60SXin LI (*emu->emu_outb) (emu, emu->x86.R_DX,
829806325fe0SXin LI fetch_byte(emu, emu->x86.R_ES,
829906325fe0SXin LI emu->x86.R_SI));
8300884e6d60SXin LI emu->x86.R_SI += inc;
8301884e6d60SXin LI }
8302884e6d60SXin LI break;
8303884e6d60SXin LI
8304884e6d60SXin LI case 2:
8305884e6d60SXin LI while (count--) {
8306884e6d60SXin LI (*emu->emu_outw) (emu, emu->x86.R_DX,
830706325fe0SXin LI fetch_word(emu, emu->x86.R_ES,
830806325fe0SXin LI emu->x86.R_SI));
8309884e6d60SXin LI emu->x86.R_SI += inc;
8310884e6d60SXin LI }
8311884e6d60SXin LI break;
8312884e6d60SXin LI case 4:
8313884e6d60SXin LI while (count--) {
8314884e6d60SXin LI (*emu->emu_outl) (emu, emu->x86.R_DX,
831506325fe0SXin LI fetch_long(emu, emu->x86.R_ES,
831606325fe0SXin LI emu->x86.R_SI));
8317884e6d60SXin LI emu->x86.R_SI += inc;
8318884e6d60SXin LI break;
8319884e6d60SXin LI }
8320884e6d60SXin LI }
8321884e6d60SXin LI emu->x86.R_CX = 0;
8322884e6d60SXin LI if (emu->x86.mode & SYSMODE_PREFIX_DATA) {
8323884e6d60SXin LI emu->x86.R_ECX = 0;
8324884e6d60SXin LI }
8325884e6d60SXin LI emu->x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
8326884e6d60SXin LI } else {
8327884e6d60SXin LI switch (size) {
8328884e6d60SXin LI case 1:
8329884e6d60SXin LI (*emu->emu_outb) (emu, emu->x86.R_DX,
8330884e6d60SXin LI fetch_byte(emu, emu->x86.R_ES, emu->x86.R_SI));
8331884e6d60SXin LI break;
8332884e6d60SXin LI case 2:
8333884e6d60SXin LI (*emu->emu_outw) (emu, emu->x86.R_DX,
8334884e6d60SXin LI fetch_word(emu, emu->x86.R_ES, emu->x86.R_SI));
8335884e6d60SXin LI break;
8336884e6d60SXin LI case 4:
8337884e6d60SXin LI (*emu->emu_outl) (emu, emu->x86.R_DX,
8338884e6d60SXin LI fetch_long(emu, emu->x86.R_ES, emu->x86.R_SI));
8339884e6d60SXin LI break;
8340884e6d60SXin LI }
8341884e6d60SXin LI emu->x86.R_SI += inc;
8342884e6d60SXin LI }
8343884e6d60SXin LI }
8344884e6d60SXin LI
8345884e6d60SXin LI /*
8346884e6d60SXin LI * REMARKS:
8347884e6d60SXin LI * Pushes a word onto the stack.
8348884e6d60SXin LI *
8349884e6d60SXin LI * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
8350884e6d60SXin LI */
8351884e6d60SXin LI static void
push_word(struct x86emu * emu,uint16_t w)8352884e6d60SXin LI push_word(struct x86emu *emu, uint16_t w)
8353884e6d60SXin LI {
8354884e6d60SXin LI emu->x86.R_SP -= 2;
8355884e6d60SXin LI store_word(emu, emu->x86.R_SS, emu->x86.R_SP, w);
8356884e6d60SXin LI }
8357884e6d60SXin LI
8358884e6d60SXin LI /*
8359884e6d60SXin LI * REMARKS:
8360884e6d60SXin LI * Pushes a long onto the stack.
8361884e6d60SXin LI *
8362884e6d60SXin LI * NOTE: Do not inline this, as (*emu->emu_wrX) is already inline!
8363884e6d60SXin LI */
8364884e6d60SXin LI static void
push_long(struct x86emu * emu,uint32_t w)8365884e6d60SXin LI push_long(struct x86emu *emu, uint32_t w)
8366884e6d60SXin LI {
8367884e6d60SXin LI emu->x86.R_SP -= 4;
8368884e6d60SXin LI store_long(emu, emu->x86.R_SS, emu->x86.R_SP, w);
8369884e6d60SXin LI }
8370884e6d60SXin LI
8371884e6d60SXin LI /*
8372884e6d60SXin LI * REMARKS:
8373884e6d60SXin LI * Pops a word from the stack.
8374884e6d60SXin LI *
8375884e6d60SXin LI * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
8376884e6d60SXin LI */
8377884e6d60SXin LI static uint16_t
pop_word(struct x86emu * emu)8378884e6d60SXin LI pop_word(struct x86emu *emu)
8379884e6d60SXin LI {
8380884e6d60SXin LI uint16_t res;
8381884e6d60SXin LI
8382884e6d60SXin LI res = fetch_word(emu, emu->x86.R_SS, emu->x86.R_SP);
8383884e6d60SXin LI emu->x86.R_SP += 2;
8384884e6d60SXin LI return res;
8385884e6d60SXin LI }
8386884e6d60SXin LI
8387884e6d60SXin LI /*
8388884e6d60SXin LI * REMARKS:
8389884e6d60SXin LI * Pops a long from the stack.
8390884e6d60SXin LI *
8391884e6d60SXin LI * NOTE: Do not inline this, as (*emu->emu_rdX) is already inline!
8392884e6d60SXin LI */
8393884e6d60SXin LI static uint32_t
pop_long(struct x86emu * emu)8394884e6d60SXin LI pop_long(struct x86emu *emu)
8395884e6d60SXin LI {
8396884e6d60SXin LI uint32_t res;
8397884e6d60SXin LI
8398884e6d60SXin LI res = fetch_long(emu, emu->x86.R_SS, emu->x86.R_SP);
8399884e6d60SXin LI emu->x86.R_SP += 4;
8400884e6d60SXin LI return res;
8401884e6d60SXin LI }
8402