1706f2543Smrg/****************************************************************************
2706f2543Smrg*
3706f2543Smrg*						Realmode X86 Emulator Library
4706f2543Smrg*
5706f2543Smrg*            	Copyright (C) 1996-1999 SciTech Software, Inc.
6706f2543Smrg* 				     Copyright (C) David Mosberger-Tang
7706f2543Smrg* 					   Copyright (C) 1999 Egbert Eich
8706f2543Smrg*
9706f2543Smrg*  ========================================================================
10706f2543Smrg*
11706f2543Smrg*  Permission to use, copy, modify, distribute, and sell this software and
12706f2543Smrg*  its documentation for any purpose is hereby granted without fee,
13706f2543Smrg*  provided that the above copyright notice appear in all copies and that
14706f2543Smrg*  both that copyright notice and this permission notice appear in
15706f2543Smrg*  supporting documentation, and that the name of the authors not be used
16706f2543Smrg*  in advertising or publicity pertaining to distribution of the software
17706f2543Smrg*  without specific, written prior permission.  The authors makes no
18706f2543Smrg*  representations about the suitability of this software for any purpose.
19706f2543Smrg*  It is provided "as is" without express or implied warranty.
20706f2543Smrg*
21706f2543Smrg*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22706f2543Smrg*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23706f2543Smrg*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24706f2543Smrg*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25706f2543Smrg*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26706f2543Smrg*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27706f2543Smrg*  PERFORMANCE OF THIS SOFTWARE.
28706f2543Smrg*
29706f2543Smrg*  ========================================================================
30706f2543Smrg*
31706f2543Smrg* Language:		ANSI C
32706f2543Smrg* Environment:	Any
33706f2543Smrg* Developer:    Kendall Bennett
34706f2543Smrg*
35706f2543Smrg* Description:  This file contains the code to implement the primitive
36706f2543Smrg*				machine operations used by the emulation code in ops.c
37706f2543Smrg*
38706f2543Smrg* Carry Chain Calculation
39706f2543Smrg*
40706f2543Smrg* This represents a somewhat expensive calculation which is
41706f2543Smrg* apparently required to emulate the setting of the OF and AF flag.
42706f2543Smrg* The latter is not so important, but the former is.  The overflow
43706f2543Smrg* flag is the XOR of the top two bits of the carry chain for an
44706f2543Smrg* addition (similar for subtraction).  Since we do not want to
45706f2543Smrg* simulate the addition in a bitwise manner, we try to calculate the
46706f2543Smrg* carry chain given the two operands and the result.
47706f2543Smrg*
48706f2543Smrg* So, given the following table, which represents the addition of two
49706f2543Smrg* bits, we can derive a formula for the carry chain.
50706f2543Smrg*
51706f2543Smrg* a   b   cin   r     cout
52706f2543Smrg* 0   0   0     0     0
53706f2543Smrg* 0   0   1     1     0
54706f2543Smrg* 0   1   0     1     0
55706f2543Smrg* 0   1   1     0     1
56706f2543Smrg* 1   0   0     1     0
57706f2543Smrg* 1   0   1     0     1
58706f2543Smrg* 1   1   0     0     1
59706f2543Smrg* 1   1   1     1     1
60706f2543Smrg*
61706f2543Smrg* Construction of table for cout:
62706f2543Smrg*
63706f2543Smrg* ab
64706f2543Smrg* r  \  00   01   11  10
65706f2543Smrg* |------------------
66706f2543Smrg* 0  |   0    1    1   1
67706f2543Smrg* 1  |   0    0    1   0
68706f2543Smrg*
69706f2543Smrg* By inspection, one gets:  cc = ab +  r'(a + b)
70706f2543Smrg*
71706f2543Smrg* That represents alot of operations, but NO CHOICE....
72706f2543Smrg*
73706f2543Smrg* Borrow Chain Calculation.
74706f2543Smrg*
75706f2543Smrg* The following table represents the subtraction of two bits, from
76706f2543Smrg* which we can derive a formula for the borrow chain.
77706f2543Smrg*
78706f2543Smrg* a   b   bin   r     bout
79706f2543Smrg* 0   0   0     0     0
80706f2543Smrg* 0   0   1     1     1
81706f2543Smrg* 0   1   0     1     1
82706f2543Smrg* 0   1   1     0     1
83706f2543Smrg* 1   0   0     1     0
84706f2543Smrg* 1   0   1     0     0
85706f2543Smrg* 1   1   0     0     0
86706f2543Smrg* 1   1   1     1     1
87706f2543Smrg*
88706f2543Smrg* Construction of table for cout:
89706f2543Smrg*
90706f2543Smrg* ab
91706f2543Smrg* r  \  00   01   11  10
92706f2543Smrg* |------------------
93706f2543Smrg* 0  |   0    1    0   0
94706f2543Smrg* 1  |   1    1    1   0
95706f2543Smrg*
96706f2543Smrg* By inspection, one gets:  bc = a'b +  r(a' + b)
97706f2543Smrg*
98706f2543Smrg****************************************************************************/
99706f2543Smrg
100706f2543Smrg#include <stdlib.h>
101706f2543Smrg
102706f2543Smrg#define	PRIM_OPS_NO_REDEFINE_ASM
103706f2543Smrg#include "x86emu/x86emui.h"
104706f2543Smrg
105706f2543Smrg#if defined(__GNUC__)
106706f2543Smrg# if defined (__i386__) || defined(__i386) || defined(__AMD64__) || defined(__amd64__)
107706f2543Smrg#  include "x86emu/prim_x86_gcc.h"
108706f2543Smrg# endif
109706f2543Smrg#endif
110706f2543Smrg
111706f2543Smrg/*------------------------- Global Variables ------------------------------*/
112706f2543Smrg
113706f2543Smrgstatic u32 x86emu_parity_tab[8] =
114706f2543Smrg{
115706f2543Smrg	0x96696996,
116706f2543Smrg	0x69969669,
117706f2543Smrg	0x69969669,
118706f2543Smrg	0x96696996,
119706f2543Smrg	0x69969669,
120706f2543Smrg	0x96696996,
121706f2543Smrg	0x96696996,
122706f2543Smrg	0x69969669,
123706f2543Smrg};
124706f2543Smrg
125706f2543Smrg#define PARITY(x)   (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
126706f2543Smrg#define XOR2(x) 	(((x) ^ ((x)>>1)) & 0x1)
127706f2543Smrg
128706f2543Smrg/*----------------------------- Implementation ----------------------------*/
129706f2543Smrg
130706f2543Smrg/****************************************************************************
131706f2543SmrgREMARKS:
132706f2543SmrgImplements the AAA instruction and side effects.
133706f2543Smrg****************************************************************************/
134706f2543Smrgu16 aaa_word(u16 d)
135706f2543Smrg{
136706f2543Smrg	u16	res;
137706f2543Smrg	if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
138706f2543Smrg		d += 0x6;
139706f2543Smrg		d += 0x100;
140706f2543Smrg		SET_FLAG(F_AF);
141706f2543Smrg		SET_FLAG(F_CF);
142706f2543Smrg	} else {
143706f2543Smrg		CLEAR_FLAG(F_CF);
144706f2543Smrg		CLEAR_FLAG(F_AF);
145706f2543Smrg	}
146706f2543Smrg	res = (u16)(d & 0xFF0F);
147706f2543Smrg	CLEAR_FLAG(F_SF);
148706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
149706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
150706f2543Smrg	return res;
151706f2543Smrg}
152706f2543Smrg
153706f2543Smrg/****************************************************************************
154706f2543SmrgREMARKS:
155706f2543SmrgImplements the AAA instruction and side effects.
156706f2543Smrg****************************************************************************/
157706f2543Smrgu16 aas_word(u16 d)
158706f2543Smrg{
159706f2543Smrg	u16	res;
160706f2543Smrg	if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
161706f2543Smrg		d -= 0x6;
162706f2543Smrg		d -= 0x100;
163706f2543Smrg		SET_FLAG(F_AF);
164706f2543Smrg		SET_FLAG(F_CF);
165706f2543Smrg	} else {
166706f2543Smrg		CLEAR_FLAG(F_CF);
167706f2543Smrg		CLEAR_FLAG(F_AF);
168706f2543Smrg	}
169706f2543Smrg	res = (u16)(d & 0xFF0F);
170706f2543Smrg	CLEAR_FLAG(F_SF);
171706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
172706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
173706f2543Smrg	return res;
174706f2543Smrg}
175706f2543Smrg
176706f2543Smrg/****************************************************************************
177706f2543SmrgREMARKS:
178706f2543SmrgImplements the AAD instruction and side effects.
179706f2543Smrg****************************************************************************/
180706f2543Smrgu16 aad_word(u16 d)
181706f2543Smrg{
182706f2543Smrg	u16 l;
183706f2543Smrg	u8 hb, lb;
184706f2543Smrg
185706f2543Smrg	hb = (u8)((d >> 8) & 0xff);
186706f2543Smrg	lb = (u8)((d & 0xff));
187706f2543Smrg	l = (u16)((lb + 10 * hb) & 0xFF);
188706f2543Smrg
189706f2543Smrg	CLEAR_FLAG(F_CF);
190706f2543Smrg	CLEAR_FLAG(F_AF);
191706f2543Smrg	CLEAR_FLAG(F_OF);
192706f2543Smrg	CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
193706f2543Smrg	CONDITIONAL_SET_FLAG(l == 0, F_ZF);
194706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
195706f2543Smrg	return l;
196706f2543Smrg}
197706f2543Smrg
198706f2543Smrg/****************************************************************************
199706f2543SmrgREMARKS:
200706f2543SmrgImplements the AAM instruction and side effects.
201706f2543Smrg****************************************************************************/
202706f2543Smrgu16 aam_word(u8 d)
203706f2543Smrg{
204706f2543Smrg    u16 h, l;
205706f2543Smrg
206706f2543Smrg	h = (u16)(d / 10);
207706f2543Smrg	l = (u16)(d % 10);
208706f2543Smrg	l |= (u16)(h << 8);
209706f2543Smrg
210706f2543Smrg	CLEAR_FLAG(F_CF);
211706f2543Smrg	CLEAR_FLAG(F_AF);
212706f2543Smrg	CLEAR_FLAG(F_OF);
213706f2543Smrg	CONDITIONAL_SET_FLAG(l & 0x80, F_SF);
214706f2543Smrg	CONDITIONAL_SET_FLAG(l == 0, F_ZF);
215706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
216706f2543Smrg    return l;
217706f2543Smrg}
218706f2543Smrg
219706f2543Smrg/****************************************************************************
220706f2543SmrgREMARKS:
221706f2543SmrgImplements the ADC instruction and side effects.
222706f2543Smrg****************************************************************************/
223706f2543Smrgu8 adc_byte(u8 d, u8 s)
224706f2543Smrg{
225706f2543Smrg	register u32 res;   /* all operands in native machine order */
226706f2543Smrg	register u32 cc;
227706f2543Smrg
228706f2543Smrg	if (ACCESS_FLAG(F_CF))
229706f2543Smrg		res = 1 + d + s;
230706f2543Smrg	else
231706f2543Smrg		res = d + s;
232706f2543Smrg
233706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
234706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
235706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
236706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
237706f2543Smrg
238706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
239706f2543Smrg	cc = (s & d) | ((~res) & (s | d));
240706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
241706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
242706f2543Smrg	return (u8)res;
243706f2543Smrg}
244706f2543Smrg
245706f2543Smrg/****************************************************************************
246706f2543SmrgREMARKS:
247706f2543SmrgImplements the ADC instruction and side effects.
248706f2543Smrg****************************************************************************/
249706f2543Smrgu16 adc_word(u16 d, u16 s)
250706f2543Smrg{
251706f2543Smrg	register u32 res;   /* all operands in native machine order */
252706f2543Smrg	register u32 cc;
253706f2543Smrg
254706f2543Smrg	if (ACCESS_FLAG(F_CF))
255706f2543Smrg		res = 1 + d + s;
256706f2543Smrg	else
257706f2543Smrg		res = d + s;
258706f2543Smrg
259706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
260706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
261706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
262706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
263706f2543Smrg
264706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
265706f2543Smrg	cc = (s & d) | ((~res) & (s | d));
266706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
267706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
268706f2543Smrg	return (u16)res;
269706f2543Smrg}
270706f2543Smrg
271706f2543Smrg/****************************************************************************
272706f2543SmrgREMARKS:
273706f2543SmrgImplements the ADC instruction and side effects.
274706f2543Smrg****************************************************************************/
275706f2543Smrgu32 adc_long(u32 d, u32 s)
276706f2543Smrg{
277706f2543Smrg	register u32 lo;	/* all operands in native machine order */
278706f2543Smrg	register u32 hi;
279706f2543Smrg	register u32 res;
280706f2543Smrg	register u32 cc;
281706f2543Smrg
282706f2543Smrg	if (ACCESS_FLAG(F_CF)) {
283706f2543Smrg		lo = 1 + (d & 0xFFFF) + (s & 0xFFFF);
284706f2543Smrg		res = 1 + d + s;
285706f2543Smrg		}
286706f2543Smrg	else {
287706f2543Smrg		lo = (d & 0xFFFF) + (s & 0xFFFF);
288706f2543Smrg		res = d + s;
289706f2543Smrg		}
290706f2543Smrg	hi = (lo >> 16) + (d >> 16) + (s >> 16);
291706f2543Smrg
292706f2543Smrg	CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
293706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
294706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
295706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
296706f2543Smrg
297706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
298706f2543Smrg	cc = (s & d) | ((~res) & (s | d));
299706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
300706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
301706f2543Smrg	return res;
302706f2543Smrg}
303706f2543Smrg
304706f2543Smrg/****************************************************************************
305706f2543SmrgREMARKS:
306706f2543SmrgImplements the ADD instruction and side effects.
307706f2543Smrg****************************************************************************/
308706f2543Smrgu8 add_byte(u8 d, u8 s)
309706f2543Smrg{
310706f2543Smrg	register u32 res;   /* all operands in native machine order */
311706f2543Smrg	register u32 cc;
312706f2543Smrg
313706f2543Smrg	res = d + s;
314706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x100, F_CF);
315706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
316706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
317706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
318706f2543Smrg
319706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
320706f2543Smrg	cc = (s & d) | ((~res) & (s | d));
321706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
322706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
323706f2543Smrg	return (u8)res;
324706f2543Smrg}
325706f2543Smrg
326706f2543Smrg/****************************************************************************
327706f2543SmrgREMARKS:
328706f2543SmrgImplements the ADD instruction and side effects.
329706f2543Smrg****************************************************************************/
330706f2543Smrgu16 add_word(u16 d, u16 s)
331706f2543Smrg{
332706f2543Smrg	register u32 res;   /* all operands in native machine order */
333706f2543Smrg	register u32 cc;
334706f2543Smrg
335706f2543Smrg	res = d + s;
336706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x10000, F_CF);
337706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
338706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
339706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
340706f2543Smrg
341706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
342706f2543Smrg	cc = (s & d) | ((~res) & (s | d));
343706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
344706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
345706f2543Smrg	return (u16)res;
346706f2543Smrg}
347706f2543Smrg
348706f2543Smrg/****************************************************************************
349706f2543SmrgREMARKS:
350706f2543SmrgImplements the ADD instruction and side effects.
351706f2543Smrg****************************************************************************/
352706f2543Smrgu32 add_long(u32 d, u32 s)
353706f2543Smrg{
354706f2543Smrg	register u32 lo;	/* all operands in native machine order */
355706f2543Smrg	register u32 hi;
356706f2543Smrg	register u32 res;
357706f2543Smrg	register u32 cc;
358706f2543Smrg
359706f2543Smrg	lo = (d & 0xFFFF) + (s & 0xFFFF);
360706f2543Smrg	res = d + s;
361706f2543Smrg	hi = (lo >> 16) + (d >> 16) + (s >> 16);
362706f2543Smrg
363706f2543Smrg	CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
364706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
365706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
366706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
367706f2543Smrg
368706f2543Smrg    /* calculate the carry chain  SEE NOTE AT TOP. */
369706f2543Smrg    cc = (s & d) | ((~res) & (s | d));
370706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
371706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
372706f2543Smrg
373706f2543Smrg    return res;
374706f2543Smrg}
375706f2543Smrg
376706f2543Smrg/****************************************************************************
377706f2543SmrgREMARKS:
378706f2543SmrgImplements the AND instruction and side effects.
379706f2543Smrg****************************************************************************/
380706f2543Smrgu8 and_byte(u8 d, u8 s)
381706f2543Smrg{
382706f2543Smrg	register u8 res;    /* all operands in native machine order */
383706f2543Smrg
384706f2543Smrg	res = d & s;
385706f2543Smrg
386706f2543Smrg	/* set the flags  */
387706f2543Smrg	CLEAR_FLAG(F_OF);
388706f2543Smrg	CLEAR_FLAG(F_CF);
389706f2543Smrg	CLEAR_FLAG(F_AF);
390706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
391706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
392706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
393706f2543Smrg	return res;
394706f2543Smrg}
395706f2543Smrg
396706f2543Smrg/****************************************************************************
397706f2543SmrgREMARKS:
398706f2543SmrgImplements the AND instruction and side effects.
399706f2543Smrg****************************************************************************/
400706f2543Smrgu16 and_word(u16 d, u16 s)
401706f2543Smrg{
402706f2543Smrg    register u16 res;   /* all operands in native machine order */
403706f2543Smrg
404706f2543Smrg    res = d & s;
405706f2543Smrg
406706f2543Smrg    /* set the flags  */
407706f2543Smrg	CLEAR_FLAG(F_OF);
408706f2543Smrg	CLEAR_FLAG(F_CF);
409706f2543Smrg	CLEAR_FLAG(F_AF);
410706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
411706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
412706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
413706f2543Smrg    return res;
414706f2543Smrg}
415706f2543Smrg
416706f2543Smrg/****************************************************************************
417706f2543SmrgREMARKS:
418706f2543SmrgImplements the AND instruction and side effects.
419706f2543Smrg****************************************************************************/
420706f2543Smrgu32 and_long(u32 d, u32 s)
421706f2543Smrg{
422706f2543Smrg	register u32 res;   /* all operands in native machine order */
423706f2543Smrg
424706f2543Smrg	res = d & s;
425706f2543Smrg
426706f2543Smrg	/* set the flags  */
427706f2543Smrg	CLEAR_FLAG(F_OF);
428706f2543Smrg	CLEAR_FLAG(F_CF);
429706f2543Smrg	CLEAR_FLAG(F_AF);
430706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
431706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
432706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
433706f2543Smrg	return res;
434706f2543Smrg}
435706f2543Smrg
436706f2543Smrg/****************************************************************************
437706f2543SmrgREMARKS:
438706f2543SmrgImplements the CMP instruction and side effects.
439706f2543Smrg****************************************************************************/
440706f2543Smrgu8 cmp_byte(u8 d, u8 s)
441706f2543Smrg{
442706f2543Smrg	register u32 res;   /* all operands in native machine order */
443706f2543Smrg	register u32 bc;
444706f2543Smrg
445706f2543Smrg	res = d - s;
446706f2543Smrg	CLEAR_FLAG(F_CF);
447706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
448706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
449706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
450706f2543Smrg
451706f2543Smrg	/* calculate the borrow chain.  See note at top */
452706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
453706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
454706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
455706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
456706f2543Smrg	return d;
457706f2543Smrg}
458706f2543Smrg
459706f2543Smrg/****************************************************************************
460706f2543SmrgREMARKS:
461706f2543SmrgImplements the CMP instruction and side effects.
462706f2543Smrg****************************************************************************/
463706f2543Smrgu16 cmp_word(u16 d, u16 s)
464706f2543Smrg{
465706f2543Smrg	register u32 res;   /* all operands in native machine order */
466706f2543Smrg	register u32 bc;
467706f2543Smrg
468706f2543Smrg	res = d - s;
469706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
470706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
471706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
472706f2543Smrg
473706f2543Smrg	/* calculate the borrow chain.  See note at top */
474706f2543Smrg    bc = (res & (~d | s)) | (~d & s);
475706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
476706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
477706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
478706f2543Smrg	return d;
479706f2543Smrg}
480706f2543Smrg
481706f2543Smrg/****************************************************************************
482706f2543SmrgREMARKS:
483706f2543SmrgImplements the CMP instruction and side effects.
484706f2543Smrg****************************************************************************/
485706f2543Smrgu32 cmp_long(u32 d, u32 s)
486706f2543Smrg{
487706f2543Smrg	register u32 res;   /* all operands in native machine order */
488706f2543Smrg	register u32 bc;
489706f2543Smrg
490706f2543Smrg	res = d - s;
491706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
492706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
493706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
494706f2543Smrg
495706f2543Smrg	/* calculate the borrow chain.  See note at top */
496706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
497706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
498706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
499706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
500706f2543Smrg	return d;
501706f2543Smrg}
502706f2543Smrg
503706f2543Smrg/****************************************************************************
504706f2543SmrgREMARKS:
505706f2543SmrgImplements the DAA instruction and side effects.
506706f2543Smrg****************************************************************************/
507706f2543Smrgu8 daa_byte(u8 d)
508706f2543Smrg{
509706f2543Smrg	u32 res = d;
510706f2543Smrg	if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
511706f2543Smrg		res += 6;
512706f2543Smrg		SET_FLAG(F_AF);
513706f2543Smrg	}
514706f2543Smrg	if (res > 0x9F || ACCESS_FLAG(F_CF)) {
515706f2543Smrg		res += 0x60;
516706f2543Smrg		SET_FLAG(F_CF);
517706f2543Smrg	}
518706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
519706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
520706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
521706f2543Smrg	return (u8)res;
522706f2543Smrg}
523706f2543Smrg
524706f2543Smrg/****************************************************************************
525706f2543SmrgREMARKS:
526706f2543SmrgImplements the DAS instruction and side effects.
527706f2543Smrg****************************************************************************/
528706f2543Smrgu8 das_byte(u8 d)
529706f2543Smrg{
530706f2543Smrg	if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
531706f2543Smrg		d -= 6;
532706f2543Smrg		SET_FLAG(F_AF);
533706f2543Smrg	}
534706f2543Smrg	if (d > 0x9F || ACCESS_FLAG(F_CF)) {
535706f2543Smrg		d -= 0x60;
536706f2543Smrg		SET_FLAG(F_CF);
537706f2543Smrg	}
538706f2543Smrg	CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
539706f2543Smrg	CONDITIONAL_SET_FLAG(d == 0, F_ZF);
540706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
541706f2543Smrg	return d;
542706f2543Smrg}
543706f2543Smrg
544706f2543Smrg/****************************************************************************
545706f2543SmrgREMARKS:
546706f2543SmrgImplements the DEC instruction and side effects.
547706f2543Smrg****************************************************************************/
548706f2543Smrgu8 dec_byte(u8 d)
549706f2543Smrg{
550706f2543Smrg    register u32 res;   /* all operands in native machine order */
551706f2543Smrg    register u32 bc;
552706f2543Smrg
553706f2543Smrg    res = d - 1;
554706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
555706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
556706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
557706f2543Smrg
558706f2543Smrg	/* calculate the borrow chain.  See note at top */
559706f2543Smrg	/* based on sub_byte, uses s==1.  */
560706f2543Smrg	bc = (res & (~d | 1)) | (~d & 1);
561706f2543Smrg	/* carry flag unchanged */
562706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
563706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
564706f2543Smrg	return (u8)res;
565706f2543Smrg}
566706f2543Smrg
567706f2543Smrg/****************************************************************************
568706f2543SmrgREMARKS:
569706f2543SmrgImplements the DEC instruction and side effects.
570706f2543Smrg****************************************************************************/
571706f2543Smrgu16 dec_word(u16 d)
572706f2543Smrg{
573706f2543Smrg    register u32 res;   /* all operands in native machine order */
574706f2543Smrg    register u32 bc;
575706f2543Smrg
576706f2543Smrg    res = d - 1;
577706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
578706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
579706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
580706f2543Smrg
581706f2543Smrg    /* calculate the borrow chain.  See note at top */
582706f2543Smrg    /* based on the sub_byte routine, with s==1 */
583706f2543Smrg    bc = (res & (~d | 1)) | (~d & 1);
584706f2543Smrg    /* carry flag unchanged */
585706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
586706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
587706f2543Smrg	return (u16)res;
588706f2543Smrg}
589706f2543Smrg
590706f2543Smrg/****************************************************************************
591706f2543SmrgREMARKS:
592706f2543SmrgImplements the DEC instruction and side effects.
593706f2543Smrg****************************************************************************/
594706f2543Smrgu32 dec_long(u32 d)
595706f2543Smrg{
596706f2543Smrg    register u32 res;   /* all operands in native machine order */
597706f2543Smrg    register u32 bc;
598706f2543Smrg
599706f2543Smrg    res = d - 1;
600706f2543Smrg
601706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
602706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
603706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
604706f2543Smrg
605706f2543Smrg    /* calculate the borrow chain.  See note at top */
606706f2543Smrg	bc = (res & (~d | 1)) | (~d & 1);
607706f2543Smrg	/* carry flag unchanged */
608706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
609706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
610706f2543Smrg	return res;
611706f2543Smrg}
612706f2543Smrg
613706f2543Smrg/****************************************************************************
614706f2543SmrgREMARKS:
615706f2543SmrgImplements the INC instruction and side effects.
616706f2543Smrg****************************************************************************/
617706f2543Smrgu8 inc_byte(u8 d)
618706f2543Smrg{
619706f2543Smrg	register u32 res;   /* all operands in native machine order */
620706f2543Smrg	register u32 cc;
621706f2543Smrg
622706f2543Smrg	res = d + 1;
623706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
624706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
625706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
626706f2543Smrg
627706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
628706f2543Smrg	cc = ((1 & d) | (~res)) & (1 | d);
629706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
630706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
631706f2543Smrg	return (u8)res;
632706f2543Smrg}
633706f2543Smrg
634706f2543Smrg/****************************************************************************
635706f2543SmrgREMARKS:
636706f2543SmrgImplements the INC instruction and side effects.
637706f2543Smrg****************************************************************************/
638706f2543Smrgu16 inc_word(u16 d)
639706f2543Smrg{
640706f2543Smrg	register u32 res;   /* all operands in native machine order */
641706f2543Smrg	register u32 cc;
642706f2543Smrg
643706f2543Smrg	res = d + 1;
644706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
645706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
646706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
647706f2543Smrg
648706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
649706f2543Smrg	cc = (1 & d) | ((~res) & (1 | d));
650706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
651706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
652706f2543Smrg	return (u16)res;
653706f2543Smrg}
654706f2543Smrg
655706f2543Smrg/****************************************************************************
656706f2543SmrgREMARKS:
657706f2543SmrgImplements the INC instruction and side effects.
658706f2543Smrg****************************************************************************/
659706f2543Smrgu32 inc_long(u32 d)
660706f2543Smrg{
661706f2543Smrg	register u32 res;   /* all operands in native machine order */
662706f2543Smrg	register u32 cc;
663706f2543Smrg
664706f2543Smrg	res = d + 1;
665706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
666706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
667706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
668706f2543Smrg
669706f2543Smrg	/* calculate the carry chain  SEE NOTE AT TOP. */
670706f2543Smrg	cc = (1 & d) | ((~res) & (1 | d));
671706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
672706f2543Smrg	CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
673706f2543Smrg	return res;
674706f2543Smrg}
675706f2543Smrg
676706f2543Smrg/****************************************************************************
677706f2543SmrgREMARKS:
678706f2543SmrgImplements the OR instruction and side effects.
679706f2543Smrg****************************************************************************/
680706f2543Smrgu8 or_byte(u8 d, u8 s)
681706f2543Smrg{
682706f2543Smrg	register u8 res;    /* all operands in native machine order */
683706f2543Smrg
684706f2543Smrg	res = d | s;
685706f2543Smrg	CLEAR_FLAG(F_OF);
686706f2543Smrg	CLEAR_FLAG(F_CF);
687706f2543Smrg	CLEAR_FLAG(F_AF);
688706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
689706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
690706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
691706f2543Smrg	return res;
692706f2543Smrg}
693706f2543Smrg
694706f2543Smrg/****************************************************************************
695706f2543SmrgREMARKS:
696706f2543SmrgImplements the OR instruction and side effects.
697706f2543Smrg****************************************************************************/
698706f2543Smrgu16 or_word(u16 d, u16 s)
699706f2543Smrg{
700706f2543Smrg	register u16 res;   /* all operands in native machine order */
701706f2543Smrg
702706f2543Smrg	res = d | s;
703706f2543Smrg	/* set the carry flag to be bit 8 */
704706f2543Smrg	CLEAR_FLAG(F_OF);
705706f2543Smrg	CLEAR_FLAG(F_CF);
706706f2543Smrg	CLEAR_FLAG(F_AF);
707706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
708706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
709706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
710706f2543Smrg	return res;
711706f2543Smrg}
712706f2543Smrg
713706f2543Smrg/****************************************************************************
714706f2543SmrgREMARKS:
715706f2543SmrgImplements the OR instruction and side effects.
716706f2543Smrg****************************************************************************/
717706f2543Smrgu32 or_long(u32 d, u32 s)
718706f2543Smrg{
719706f2543Smrg	register u32 res;   /* all operands in native machine order */
720706f2543Smrg
721706f2543Smrg	res = d | s;
722706f2543Smrg
723706f2543Smrg	/* set the carry flag to be bit 8 */
724706f2543Smrg	CLEAR_FLAG(F_OF);
725706f2543Smrg	CLEAR_FLAG(F_CF);
726706f2543Smrg	CLEAR_FLAG(F_AF);
727706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
728706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
729706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
730706f2543Smrg	return res;
731706f2543Smrg}
732706f2543Smrg
733706f2543Smrg/****************************************************************************
734706f2543SmrgREMARKS:
735706f2543SmrgImplements the OR instruction and side effects.
736706f2543Smrg****************************************************************************/
737706f2543Smrgu8 neg_byte(u8 s)
738706f2543Smrg{
739706f2543Smrg    register u8 res;
740706f2543Smrg    register u8 bc;
741706f2543Smrg
742706f2543Smrg	CONDITIONAL_SET_FLAG(s != 0, F_CF);
743706f2543Smrg	res = (u8)-s;
744706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
745706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
746706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
747706f2543Smrg	/* calculate the borrow chain --- modified such that d=0.
748706f2543Smrg	   substitutiing d=0 into     bc= res&(~d|s)|(~d&s);
749706f2543Smrg	   (the one used for sub) and simplifying, since ~d=0xff...,
750706f2543Smrg	   ~d|s == 0xffff..., and res&0xfff... == res.  Similarly
751706f2543Smrg	   ~d&s == s.  So the simplified result is: */
752706f2543Smrg	bc = res | s;
753706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
754706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
755706f2543Smrg	return res;
756706f2543Smrg}
757706f2543Smrg
758706f2543Smrg/****************************************************************************
759706f2543SmrgREMARKS:
760706f2543SmrgImplements the OR instruction and side effects.
761706f2543Smrg****************************************************************************/
762706f2543Smrgu16 neg_word(u16 s)
763706f2543Smrg{
764706f2543Smrg	register u16 res;
765706f2543Smrg	register u16 bc;
766706f2543Smrg
767706f2543Smrg	CONDITIONAL_SET_FLAG(s != 0, F_CF);
768706f2543Smrg	res = (u16)-s;
769706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
770706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
771706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
772706f2543Smrg
773706f2543Smrg	/* calculate the borrow chain --- modified such that d=0.
774706f2543Smrg	   substitutiing d=0 into     bc= res&(~d|s)|(~d&s);
775706f2543Smrg	   (the one used for sub) and simplifying, since ~d=0xff...,
776706f2543Smrg	   ~d|s == 0xffff..., and res&0xfff... == res.  Similarly
777706f2543Smrg	   ~d&s == s.  So the simplified result is: */
778706f2543Smrg	bc = res | s;
779706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
780706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
781706f2543Smrg	return res;
782706f2543Smrg}
783706f2543Smrg
784706f2543Smrg/****************************************************************************
785706f2543SmrgREMARKS:
786706f2543SmrgImplements the OR instruction and side effects.
787706f2543Smrg****************************************************************************/
788706f2543Smrgu32 neg_long(u32 s)
789706f2543Smrg{
790706f2543Smrg	register u32 res;
791706f2543Smrg	register u32 bc;
792706f2543Smrg
793706f2543Smrg	CONDITIONAL_SET_FLAG(s != 0, F_CF);
794706f2543Smrg	res = (u32)-s;
795706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
796706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
797706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
798706f2543Smrg
799706f2543Smrg	/* calculate the borrow chain --- modified such that d=0.
800706f2543Smrg	   substitutiing d=0 into     bc= res&(~d|s)|(~d&s);
801706f2543Smrg	   (the one used for sub) and simplifying, since ~d=0xff...,
802706f2543Smrg	   ~d|s == 0xffff..., and res&0xfff... == res.  Similarly
803706f2543Smrg	   ~d&s == s.  So the simplified result is: */
804706f2543Smrg	bc = res | s;
805706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
806706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
807706f2543Smrg	return res;
808706f2543Smrg}
809706f2543Smrg
810706f2543Smrg/****************************************************************************
811706f2543SmrgREMARKS:
812706f2543SmrgImplements the NOT instruction and side effects.
813706f2543Smrg****************************************************************************/
814706f2543Smrgu8 not_byte(u8 s)
815706f2543Smrg{
816706f2543Smrg	return ~s;
817706f2543Smrg}
818706f2543Smrg
819706f2543Smrg/****************************************************************************
820706f2543SmrgREMARKS:
821706f2543SmrgImplements the NOT instruction and side effects.
822706f2543Smrg****************************************************************************/
823706f2543Smrgu16 not_word(u16 s)
824706f2543Smrg{
825706f2543Smrg	return ~s;
826706f2543Smrg}
827706f2543Smrg
828706f2543Smrg/****************************************************************************
829706f2543SmrgREMARKS:
830706f2543SmrgImplements the NOT instruction and side effects.
831706f2543Smrg****************************************************************************/
832706f2543Smrgu32 not_long(u32 s)
833706f2543Smrg{
834706f2543Smrg	return ~s;
835706f2543Smrg}
836706f2543Smrg
837706f2543Smrg/****************************************************************************
838706f2543SmrgREMARKS:
839706f2543SmrgImplements the RCL instruction and side effects.
840706f2543Smrg****************************************************************************/
841706f2543Smrgu8 rcl_byte(u8 d, u8 s)
842706f2543Smrg{
843706f2543Smrg    register unsigned int res, cnt, mask, cf;
844706f2543Smrg
845706f2543Smrg    /* s is the rotate distance.  It varies from 0 - 8. */
846706f2543Smrg	/* have
847706f2543Smrg
848706f2543Smrg       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
849706f2543Smrg
850706f2543Smrg       want to rotate through the carry by "s" bits.  We could
851706f2543Smrg       loop, but that's inefficient.  So the width is 9,
852706f2543Smrg       and we split into three parts:
853706f2543Smrg
854706f2543Smrg       The new carry flag   (was B_n)
855706f2543Smrg       the stuff in B_n-1 .. B_0
856706f2543Smrg       the stuff in B_7 .. B_n+1
857706f2543Smrg
858706f2543Smrg       The new rotate is done mod 9, and given this,
859706f2543Smrg       for a rotation of n bits (mod 9) the new carry flag is
860706f2543Smrg       then located n bits from the MSB.  The low part is
861706f2543Smrg       then shifted up cnt bits, and the high part is or'd
862706f2543Smrg       in.  Using CAPS for new values, and lowercase for the
863706f2543Smrg       original values, this can be expressed as:
864706f2543Smrg
865706f2543Smrg       IF n > 0
866706f2543Smrg       1) CF <-  b_(8-n)
867706f2543Smrg       2) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0
868706f2543Smrg       3) B_(n-1) <- cf
869706f2543Smrg       4) B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1))
870706f2543Smrg	 */
871706f2543Smrg	res = d;
872706f2543Smrg	if ((cnt = s % 9) != 0) {
873706f2543Smrg        /* extract the new CARRY FLAG. */
874706f2543Smrg        /* CF <-  b_(8-n)             */
875706f2543Smrg        cf = (d >> (8 - cnt)) & 0x1;
876706f2543Smrg
877706f2543Smrg        /* get the low stuff which rotated
878706f2543Smrg           into the range B_7 .. B_cnt */
879706f2543Smrg        /* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0  */
880706f2543Smrg        /* note that the right hand side done by the mask */
881706f2543Smrg		res = (d << cnt) & 0xff;
882706f2543Smrg
883706f2543Smrg        /* now the high stuff which rotated around
884706f2543Smrg           into the positions B_cnt-2 .. B_0 */
885706f2543Smrg        /* B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1)) */
886706f2543Smrg        /* shift it downward, 7-(n-2) = 9-n positions.
887706f2543Smrg           and mask off the result before or'ing in.
888706f2543Smrg         */
889706f2543Smrg        mask = (1 << (cnt - 1)) - 1;
890706f2543Smrg        res |= (d >> (9 - cnt)) & mask;
891706f2543Smrg
892706f2543Smrg        /* if the carry flag was set, or it in.  */
893706f2543Smrg		if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
894706f2543Smrg            /*  B_(n-1) <- cf */
895706f2543Smrg            res |= 1 << (cnt - 1);
896706f2543Smrg        }
897706f2543Smrg        /* set the new carry flag, based on the variable "cf" */
898706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
899706f2543Smrg        /* OVERFLOW is set *IFF* cnt==1, then it is the
900706f2543Smrg           xor of CF and the most significant bit.  Blecck. */
901706f2543Smrg        /* parenthesized this expression since it appears to
902706f2543Smrg           be causing OF to be misset */
903706f2543Smrg        CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
904706f2543Smrg							 F_OF);
905706f2543Smrg
906706f2543Smrg    }
907706f2543Smrg	return (u8)res;
908706f2543Smrg}
909706f2543Smrg
910706f2543Smrg/****************************************************************************
911706f2543SmrgREMARKS:
912706f2543SmrgImplements the RCL instruction and side effects.
913706f2543Smrg****************************************************************************/
914706f2543Smrgu16 rcl_word(u16 d, u8 s)
915706f2543Smrg{
916706f2543Smrg	register unsigned int res, cnt, mask, cf;
917706f2543Smrg
918706f2543Smrg	res = d;
919706f2543Smrg	if ((cnt = s % 17) != 0) {
920706f2543Smrg		cf = (d >> (16 - cnt)) & 0x1;
921706f2543Smrg		res = (d << cnt) & 0xffff;
922706f2543Smrg		mask = (1 << (cnt - 1)) - 1;
923706f2543Smrg		res |= (d >> (17 - cnt)) & mask;
924706f2543Smrg		if (ACCESS_FLAG(F_CF)) {
925706f2543Smrg			res |= 1 << (cnt - 1);
926706f2543Smrg		}
927706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
928706f2543Smrg		CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
929706f2543Smrg							 F_OF);
930706f2543Smrg	}
931706f2543Smrg	return (u16)res;
932706f2543Smrg}
933706f2543Smrg
934706f2543Smrg/****************************************************************************
935706f2543SmrgREMARKS:
936706f2543SmrgImplements the RCL instruction and side effects.
937706f2543Smrg****************************************************************************/
938706f2543Smrgu32 rcl_long(u32 d, u8 s)
939706f2543Smrg{
940706f2543Smrg	register u32 res, cnt, mask, cf;
941706f2543Smrg
942706f2543Smrg	res = d;
943706f2543Smrg	if ((cnt = s % 33) != 0) {
944706f2543Smrg		cf = (d >> (32 - cnt)) & 0x1;
945706f2543Smrg		res = (d << cnt) & 0xffffffff;
946706f2543Smrg		mask = (1 << (cnt - 1)) - 1;
947706f2543Smrg		res |= (d >> (33 - cnt)) & mask;
948706f2543Smrg		if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
949706f2543Smrg			res |= 1 << (cnt - 1);
950706f2543Smrg		}
951706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
952706f2543Smrg		CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
953706f2543Smrg							 F_OF);
954706f2543Smrg	}
955706f2543Smrg	return res;
956706f2543Smrg}
957706f2543Smrg
958706f2543Smrg/****************************************************************************
959706f2543SmrgREMARKS:
960706f2543SmrgImplements the RCR instruction and side effects.
961706f2543Smrg****************************************************************************/
962706f2543Smrgu8 rcr_byte(u8 d, u8 s)
963706f2543Smrg{
964706f2543Smrg	u32	res, cnt;
965706f2543Smrg	u32	mask, cf, ocf = 0;
966706f2543Smrg
967706f2543Smrg	/* rotate right through carry */
968706f2543Smrg    /*
969706f2543Smrg       s is the rotate distance.  It varies from 0 - 8.
970706f2543Smrg       d is the byte object rotated.
971706f2543Smrg
972706f2543Smrg       have
973706f2543Smrg
974706f2543Smrg       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
975706f2543Smrg
976706f2543Smrg       The new rotate is done mod 9, and given this,
977706f2543Smrg       for a rotation of n bits (mod 9) the new carry flag is
978706f2543Smrg       then located n bits from the LSB.  The low part is
979706f2543Smrg       then shifted up cnt bits, and the high part is or'd
980706f2543Smrg       in.  Using CAPS for new values, and lowercase for the
981706f2543Smrg       original values, this can be expressed as:
982706f2543Smrg
983706f2543Smrg       IF n > 0
984706f2543Smrg       1) CF <-  b_(n-1)
985706f2543Smrg       2) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n)
986706f2543Smrg       3) B_(8-n) <- cf
987706f2543Smrg       4) B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0)
988706f2543Smrg	 */
989706f2543Smrg	res = d;
990706f2543Smrg	if ((cnt = s % 9) != 0) {
991706f2543Smrg        /* extract the new CARRY FLAG. */
992706f2543Smrg        /* CF <-  b_(n-1)              */
993706f2543Smrg        if (cnt == 1) {
994706f2543Smrg            cf = d & 0x1;
995706f2543Smrg            /* note hackery here.  Access_flag(..) evaluates to either
996706f2543Smrg               0 if flag not set
997706f2543Smrg               non-zero if flag is set.
998706f2543Smrg               doing access_flag(..) != 0 casts that into either
999706f2543Smrg			   0..1 in any representation of the flags register
1000706f2543Smrg               (i.e. packed bit array or unpacked.)
1001706f2543Smrg             */
1002706f2543Smrg			ocf = ACCESS_FLAG(F_CF) != 0;
1003706f2543Smrg        } else
1004706f2543Smrg            cf = (d >> (cnt - 1)) & 0x1;
1005706f2543Smrg
1006706f2543Smrg        /* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_n  */
1007706f2543Smrg        /* note that the right hand side done by the mask
1008706f2543Smrg           This is effectively done by shifting the
1009706f2543Smrg           object to the right.  The result must be masked,
1010706f2543Smrg           in case the object came in and was treated
1011706f2543Smrg           as a negative number.  Needed??? */
1012706f2543Smrg
1013706f2543Smrg        mask = (1 << (8 - cnt)) - 1;
1014706f2543Smrg        res = (d >> cnt) & mask;
1015706f2543Smrg
1016706f2543Smrg        /* now the high stuff which rotated around
1017706f2543Smrg           into the positions B_cnt-2 .. B_0 */
1018706f2543Smrg        /* B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0) */
1019706f2543Smrg        /* shift it downward, 7-(n-2) = 9-n positions.
1020706f2543Smrg           and mask off the result before or'ing in.
1021706f2543Smrg         */
1022706f2543Smrg        res |= (d << (9 - cnt));
1023706f2543Smrg
1024706f2543Smrg        /* if the carry flag was set, or it in.  */
1025706f2543Smrg		if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
1026706f2543Smrg            /*  B_(8-n) <- cf */
1027706f2543Smrg            res |= 1 << (8 - cnt);
1028706f2543Smrg        }
1029706f2543Smrg        /* set the new carry flag, based on the variable "cf" */
1030706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1031706f2543Smrg        /* OVERFLOW is set *IFF* cnt==1, then it is the
1032706f2543Smrg           xor of CF and the most significant bit.  Blecck. */
1033706f2543Smrg        /* parenthesized... */
1034706f2543Smrg		if (cnt == 1) {
1035706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
1036706f2543Smrg								 F_OF);
1037706f2543Smrg		}
1038706f2543Smrg	}
1039706f2543Smrg	return (u8)res;
1040706f2543Smrg}
1041706f2543Smrg
1042706f2543Smrg/****************************************************************************
1043706f2543SmrgREMARKS:
1044706f2543SmrgImplements the RCR instruction and side effects.
1045706f2543Smrg****************************************************************************/
1046706f2543Smrgu16 rcr_word(u16 d, u8 s)
1047706f2543Smrg{
1048706f2543Smrg	u32 res, cnt;
1049706f2543Smrg	u32	mask, cf, ocf = 0;
1050706f2543Smrg
1051706f2543Smrg	/* rotate right through carry */
1052706f2543Smrg	res = d;
1053706f2543Smrg	if ((cnt = s % 17) != 0) {
1054706f2543Smrg		if (cnt == 1) {
1055706f2543Smrg			cf = d & 0x1;
1056706f2543Smrg			ocf = ACCESS_FLAG(F_CF) != 0;
1057706f2543Smrg		} else
1058706f2543Smrg			cf = (d >> (cnt - 1)) & 0x1;
1059706f2543Smrg		mask = (1 << (16 - cnt)) - 1;
1060706f2543Smrg		res = (d >> cnt) & mask;
1061706f2543Smrg		res |= (d << (17 - cnt));
1062706f2543Smrg		if (ACCESS_FLAG(F_CF)) {
1063706f2543Smrg			res |= 1 << (16 - cnt);
1064706f2543Smrg		}
1065706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1066706f2543Smrg		if (cnt == 1) {
1067706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
1068706f2543Smrg								 F_OF);
1069706f2543Smrg		}
1070706f2543Smrg	}
1071706f2543Smrg	return (u16)res;
1072706f2543Smrg}
1073706f2543Smrg
1074706f2543Smrg/****************************************************************************
1075706f2543SmrgREMARKS:
1076706f2543SmrgImplements the RCR instruction and side effects.
1077706f2543Smrg****************************************************************************/
1078706f2543Smrgu32 rcr_long(u32 d, u8 s)
1079706f2543Smrg{
1080706f2543Smrg	u32 res, cnt;
1081706f2543Smrg	u32 mask, cf, ocf = 0;
1082706f2543Smrg
1083706f2543Smrg	/* rotate right through carry */
1084706f2543Smrg	res = d;
1085706f2543Smrg	if ((cnt = s % 33) != 0) {
1086706f2543Smrg		if (cnt == 1) {
1087706f2543Smrg			cf = d & 0x1;
1088706f2543Smrg			ocf = ACCESS_FLAG(F_CF) != 0;
1089706f2543Smrg		} else
1090706f2543Smrg			cf = (d >> (cnt - 1)) & 0x1;
1091706f2543Smrg		mask = (1 << (32 - cnt)) - 1;
1092706f2543Smrg		res = (d >> cnt) & mask;
1093706f2543Smrg		if (cnt != 1)
1094706f2543Smrg			res |= (d << (33 - cnt));
1095706f2543Smrg		if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
1096706f2543Smrg			res |= 1 << (32 - cnt);
1097706f2543Smrg		}
1098706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1099706f2543Smrg		if (cnt == 1) {
1100706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
1101706f2543Smrg								 F_OF);
1102706f2543Smrg		}
1103706f2543Smrg	}
1104706f2543Smrg	return res;
1105706f2543Smrg}
1106706f2543Smrg
1107706f2543Smrg/****************************************************************************
1108706f2543SmrgREMARKS:
1109706f2543SmrgImplements the ROL instruction and side effects.
1110706f2543Smrg****************************************************************************/
1111706f2543Smrgu8 rol_byte(u8 d, u8 s)
1112706f2543Smrg{
1113706f2543Smrg    register unsigned int res, cnt, mask;
1114706f2543Smrg
1115706f2543Smrg    /* rotate left */
1116706f2543Smrg    /*
1117706f2543Smrg       s is the rotate distance.  It varies from 0 - 8.
1118706f2543Smrg       d is the byte object rotated.
1119706f2543Smrg
1120706f2543Smrg       have
1121706f2543Smrg
1122706f2543Smrg       CF  B_7 ... B_0
1123706f2543Smrg
1124706f2543Smrg       The new rotate is done mod 8.
1125706f2543Smrg       Much simpler than the "rcl" or "rcr" operations.
1126706f2543Smrg
1127706f2543Smrg       IF n > 0
1128706f2543Smrg       1) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0)
1129706f2543Smrg       2) B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n)
1130706f2543Smrg	 */
1131706f2543Smrg    res = d;
1132706f2543Smrg	if ((cnt = s % 8) != 0) {
1133706f2543Smrg		/* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) */
1134706f2543Smrg		res = (d << cnt);
1135706f2543Smrg
1136706f2543Smrg		/* B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n) */
1137706f2543Smrg		mask = (1 << cnt) - 1;
1138706f2543Smrg		res |= (d >> (8 - cnt)) & mask;
1139706f2543Smrg
1140706f2543Smrg		/* set the new carry flag, Note that it is the low order
1141706f2543Smrg		   bit of the result!!!                               */
1142706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1143706f2543Smrg		/* OVERFLOW is set *IFF* s==1, then it is the
1144706f2543Smrg		   xor of CF and the most significant bit.  Blecck. */
1145706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 &&
1146706f2543Smrg							 XOR2((res & 0x1) + ((res >> 6) & 0x2)),
1147706f2543Smrg							 F_OF);
1148706f2543Smrg	} if (s != 0) {
1149706f2543Smrg		/* set the new carry flag, Note that it is the low order
1150706f2543Smrg		   bit of the result!!!                               */
1151706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1152706f2543Smrg	}
1153706f2543Smrg	return (u8)res;
1154706f2543Smrg}
1155706f2543Smrg
1156706f2543Smrg/****************************************************************************
1157706f2543SmrgREMARKS:
1158706f2543SmrgImplements the ROL instruction and side effects.
1159706f2543Smrg****************************************************************************/
1160706f2543Smrgu16 rol_word(u16 d, u8 s)
1161706f2543Smrg{
1162706f2543Smrg    register unsigned int res, cnt, mask;
1163706f2543Smrg
1164706f2543Smrg	res = d;
1165706f2543Smrg	if ((cnt = s % 16) != 0) {
1166706f2543Smrg		res = (d << cnt);
1167706f2543Smrg		mask = (1 << cnt) - 1;
1168706f2543Smrg		res |= (d >> (16 - cnt)) & mask;
1169706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1170706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 &&
1171706f2543Smrg							 XOR2((res & 0x1) + ((res >> 14) & 0x2)),
1172706f2543Smrg							 F_OF);
1173706f2543Smrg	} if (s != 0) {
1174706f2543Smrg		/* set the new carry flag, Note that it is the low order
1175706f2543Smrg		   bit of the result!!!                               */
1176706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1177706f2543Smrg	}
1178706f2543Smrg	return (u16)res;
1179706f2543Smrg}
1180706f2543Smrg
1181706f2543Smrg/****************************************************************************
1182706f2543SmrgREMARKS:
1183706f2543SmrgImplements the ROL instruction and side effects.
1184706f2543Smrg****************************************************************************/
1185706f2543Smrgu32 rol_long(u32 d, u8 s)
1186706f2543Smrg{
1187706f2543Smrg    register u32 res, cnt, mask;
1188706f2543Smrg
1189706f2543Smrg	res = d;
1190706f2543Smrg	if ((cnt = s % 32) != 0) {
1191706f2543Smrg		res = (d << cnt);
1192706f2543Smrg		mask = (1 << cnt) - 1;
1193706f2543Smrg		res |= (d >> (32 - cnt)) & mask;
1194706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1195706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 &&
1196706f2543Smrg							 XOR2((res & 0x1) + ((res >> 30) & 0x2)),
1197706f2543Smrg							 F_OF);
1198706f2543Smrg	} if (s != 0) {
1199706f2543Smrg		/* set the new carry flag, Note that it is the low order
1200706f2543Smrg		   bit of the result!!!                               */
1201706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
1202706f2543Smrg	}
1203706f2543Smrg	return res;
1204706f2543Smrg}
1205706f2543Smrg
1206706f2543Smrg/****************************************************************************
1207706f2543SmrgREMARKS:
1208706f2543SmrgImplements the ROR instruction and side effects.
1209706f2543Smrg****************************************************************************/
1210706f2543Smrgu8 ror_byte(u8 d, u8 s)
1211706f2543Smrg{
1212706f2543Smrg    register unsigned int res, cnt, mask;
1213706f2543Smrg
1214706f2543Smrg    /* rotate right */
1215706f2543Smrg    /*
1216706f2543Smrg       s is the rotate distance.  It varies from 0 - 8.
1217706f2543Smrg       d is the byte object rotated.
1218706f2543Smrg
1219706f2543Smrg       have
1220706f2543Smrg
1221706f2543Smrg       B_7 ... B_0
1222706f2543Smrg
1223706f2543Smrg       The rotate is done mod 8.
1224706f2543Smrg
1225706f2543Smrg       IF n > 0
1226706f2543Smrg       1) B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n)
1227706f2543Smrg       2) B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0)
1228706f2543Smrg	 */
1229706f2543Smrg	res = d;
1230706f2543Smrg	if ((cnt = s % 8) != 0) {           /* not a typo, do nada if cnt==0 */
1231706f2543Smrg        /* B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0) */
1232706f2543Smrg        res = (d << (8 - cnt));
1233706f2543Smrg
1234706f2543Smrg        /* B_(8-(n+1)) .. B_(0)  <-  b_(7) .. b_(n) */
1235706f2543Smrg        mask = (1 << (8 - cnt)) - 1;
1236706f2543Smrg        res |= (d >> (cnt)) & mask;
1237706f2543Smrg
1238706f2543Smrg        /* set the new carry flag, Note that it is the low order
1239706f2543Smrg           bit of the result!!!                               */
1240706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
1241706f2543Smrg		/* OVERFLOW is set *IFF* s==1, then it is the
1242706f2543Smrg           xor of the two most significant bits.  Blecck. */
1243706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
1244706f2543Smrg	} else if (s != 0) {
1245706f2543Smrg		/* set the new carry flag, Note that it is the low order
1246706f2543Smrg		   bit of the result!!!                               */
1247706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
1248706f2543Smrg	}
1249706f2543Smrg	return (u8)res;
1250706f2543Smrg}
1251706f2543Smrg
1252706f2543Smrg/****************************************************************************
1253706f2543SmrgREMARKS:
1254706f2543SmrgImplements the ROR instruction and side effects.
1255706f2543Smrg****************************************************************************/
1256706f2543Smrgu16 ror_word(u16 d, u8 s)
1257706f2543Smrg{
1258706f2543Smrg    register unsigned int res, cnt, mask;
1259706f2543Smrg
1260706f2543Smrg	res = d;
1261706f2543Smrg	if ((cnt = s % 16) != 0) {
1262706f2543Smrg		res = (d << (16 - cnt));
1263706f2543Smrg		mask = (1 << (16 - cnt)) - 1;
1264706f2543Smrg		res |= (d >> (cnt)) & mask;
1265706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
1266706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
1267706f2543Smrg	} else if (s != 0) {
1268706f2543Smrg		/* set the new carry flag, Note that it is the low order
1269706f2543Smrg		   bit of the result!!!                               */
1270706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
1271706f2543Smrg	}
1272706f2543Smrg	return (u16)res;
1273706f2543Smrg}
1274706f2543Smrg
1275706f2543Smrg/****************************************************************************
1276706f2543SmrgREMARKS:
1277706f2543SmrgImplements the ROR instruction and side effects.
1278706f2543Smrg****************************************************************************/
1279706f2543Smrgu32 ror_long(u32 d, u8 s)
1280706f2543Smrg{
1281706f2543Smrg	register u32 res, cnt, mask;
1282706f2543Smrg
1283706f2543Smrg	res = d;
1284706f2543Smrg	if ((cnt = s % 32) != 0) {
1285706f2543Smrg		res = (d << (32 - cnt));
1286706f2543Smrg		mask = (1 << (32 - cnt)) - 1;
1287706f2543Smrg		res |= (d >> (cnt)) & mask;
1288706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
1289706f2543Smrg		CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
1290706f2543Smrg	} else if (s != 0) {
1291706f2543Smrg		/* set the new carry flag, Note that it is the low order
1292706f2543Smrg		   bit of the result!!!                               */
1293706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
1294706f2543Smrg	}
1295706f2543Smrg	return res;
1296706f2543Smrg}
1297706f2543Smrg
1298706f2543Smrg/****************************************************************************
1299706f2543SmrgREMARKS:
1300706f2543SmrgImplements the SHL instruction and side effects.
1301706f2543Smrg****************************************************************************/
1302706f2543Smrgu8 shl_byte(u8 d, u8 s)
1303706f2543Smrg{
1304706f2543Smrg	unsigned int cnt, res, cf;
1305706f2543Smrg
1306706f2543Smrg	if (s < 8) {
1307706f2543Smrg		cnt = s % 8;
1308706f2543Smrg
1309706f2543Smrg		/* last bit shifted out goes into carry flag */
1310706f2543Smrg		if (cnt > 0) {
1311706f2543Smrg			res = d << cnt;
1312706f2543Smrg			cf = d & (1 << (8 - cnt));
1313706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1314706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
1315706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1316706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1317706f2543Smrg		} else {
1318706f2543Smrg			res = (u8) d;
1319706f2543Smrg		}
1320706f2543Smrg
1321706f2543Smrg		if (cnt == 1) {
1322706f2543Smrg			/* Needs simplification. */
1323706f2543Smrg			CONDITIONAL_SET_FLAG(
1324706f2543Smrg									(((res & 0x80) == 0x80) ^
1325706f2543Smrg									 (ACCESS_FLAG(F_CF) != 0)),
1326706f2543Smrg			/* was (M.x86.R_FLG&F_CF)==F_CF)), */
1327706f2543Smrg									F_OF);
1328706f2543Smrg		} else {
1329706f2543Smrg			CLEAR_FLAG(F_OF);
1330706f2543Smrg		}
1331706f2543Smrg	} else {
1332706f2543Smrg		res = 0;
1333706f2543Smrg		CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF);
1334706f2543Smrg		CLEAR_FLAG(F_OF);
1335706f2543Smrg		CLEAR_FLAG(F_SF);
1336706f2543Smrg		SET_FLAG(F_PF);
1337706f2543Smrg		SET_FLAG(F_ZF);
1338706f2543Smrg    }
1339706f2543Smrg	return (u8)res;
1340706f2543Smrg}
1341706f2543Smrg
1342706f2543Smrg/****************************************************************************
1343706f2543SmrgREMARKS:
1344706f2543SmrgImplements the SHL instruction and side effects.
1345706f2543Smrg****************************************************************************/
1346706f2543Smrgu16 shl_word(u16 d, u8 s)
1347706f2543Smrg{
1348706f2543Smrg    unsigned int cnt, res, cf;
1349706f2543Smrg
1350706f2543Smrg	if (s < 16) {
1351706f2543Smrg		cnt = s % 16;
1352706f2543Smrg		if (cnt > 0) {
1353706f2543Smrg			res = d << cnt;
1354706f2543Smrg			cf = d & (1 << (16 - cnt));
1355706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1356706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1357706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1358706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1359706f2543Smrg		} else {
1360706f2543Smrg			res = (u16) d;
1361706f2543Smrg		}
1362706f2543Smrg
1363706f2543Smrg		if (cnt == 1) {
1364706f2543Smrg			CONDITIONAL_SET_FLAG(
1365706f2543Smrg									(((res & 0x8000) == 0x8000) ^
1366706f2543Smrg									 (ACCESS_FLAG(F_CF) != 0)),
1367706f2543Smrg									F_OF);
1368706f2543Smrg        } else {
1369706f2543Smrg			CLEAR_FLAG(F_OF);
1370706f2543Smrg        }
1371706f2543Smrg    } else {
1372706f2543Smrg		res = 0;
1373706f2543Smrg		CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
1374706f2543Smrg		CLEAR_FLAG(F_OF);
1375706f2543Smrg		CLEAR_FLAG(F_SF);
1376706f2543Smrg		SET_FLAG(F_PF);
1377706f2543Smrg		SET_FLAG(F_ZF);
1378706f2543Smrg	}
1379706f2543Smrg	return (u16)res;
1380706f2543Smrg}
1381706f2543Smrg
1382706f2543Smrg/****************************************************************************
1383706f2543SmrgREMARKS:
1384706f2543SmrgImplements the SHL instruction and side effects.
1385706f2543Smrg****************************************************************************/
1386706f2543Smrgu32 shl_long(u32 d, u8 s)
1387706f2543Smrg{
1388706f2543Smrg	unsigned int cnt, res, cf;
1389706f2543Smrg
1390706f2543Smrg	if (s < 32) {
1391706f2543Smrg		cnt = s % 32;
1392706f2543Smrg		if (cnt > 0) {
1393706f2543Smrg			res = d << cnt;
1394706f2543Smrg			cf = d & (1 << (32 - cnt));
1395706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1396706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1397706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1398706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1399706f2543Smrg		} else {
1400706f2543Smrg			res = d;
1401706f2543Smrg		}
1402706f2543Smrg		if (cnt == 1) {
1403706f2543Smrg			CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
1404706f2543Smrg								  (ACCESS_FLAG(F_CF) != 0)), F_OF);
1405706f2543Smrg		} else {
1406706f2543Smrg			CLEAR_FLAG(F_OF);
1407706f2543Smrg		}
1408706f2543Smrg	} else {
1409706f2543Smrg		res = 0;
1410706f2543Smrg		CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
1411706f2543Smrg		CLEAR_FLAG(F_OF);
1412706f2543Smrg		CLEAR_FLAG(F_SF);
1413706f2543Smrg		SET_FLAG(F_PF);
1414706f2543Smrg		SET_FLAG(F_ZF);
1415706f2543Smrg	}
1416706f2543Smrg	return res;
1417706f2543Smrg}
1418706f2543Smrg
1419706f2543Smrg/****************************************************************************
1420706f2543SmrgREMARKS:
1421706f2543SmrgImplements the SHR instruction and side effects.
1422706f2543Smrg****************************************************************************/
1423706f2543Smrgu8 shr_byte(u8 d, u8 s)
1424706f2543Smrg{
1425706f2543Smrg	unsigned int cnt, res, cf;
1426706f2543Smrg
1427706f2543Smrg	if (s < 8) {
1428706f2543Smrg		cnt = s % 8;
1429706f2543Smrg		if (cnt > 0) {
1430706f2543Smrg			cf = d & (1 << (cnt - 1));
1431706f2543Smrg			res = d >> cnt;
1432706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1433706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
1434706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1435706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1436706f2543Smrg		} else {
1437706f2543Smrg			res = (u8) d;
1438706f2543Smrg		}
1439706f2543Smrg
1440706f2543Smrg		if (cnt == 1) {
1441706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
1442706f2543Smrg		} else {
1443706f2543Smrg			CLEAR_FLAG(F_OF);
1444706f2543Smrg		}
1445706f2543Smrg	} else {
1446706f2543Smrg		res = 0;
1447706f2543Smrg		CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF);
1448706f2543Smrg		CLEAR_FLAG(F_OF);
1449706f2543Smrg		CLEAR_FLAG(F_SF);
1450706f2543Smrg		SET_FLAG(F_PF);
1451706f2543Smrg		SET_FLAG(F_ZF);
1452706f2543Smrg	}
1453706f2543Smrg	return (u8)res;
1454706f2543Smrg}
1455706f2543Smrg
1456706f2543Smrg/****************************************************************************
1457706f2543SmrgREMARKS:
1458706f2543SmrgImplements the SHR instruction and side effects.
1459706f2543Smrg****************************************************************************/
1460706f2543Smrgu16 shr_word(u16 d, u8 s)
1461706f2543Smrg{
1462706f2543Smrg	unsigned int cnt, res, cf;
1463706f2543Smrg
1464706f2543Smrg	if (s < 16) {
1465706f2543Smrg		cnt = s % 16;
1466706f2543Smrg		if (cnt > 0) {
1467706f2543Smrg			cf = d & (1 << (cnt - 1));
1468706f2543Smrg			res = d >> cnt;
1469706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1470706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1471706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1472706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1473706f2543Smrg		} else {
1474706f2543Smrg			res = d;
1475706f2543Smrg		}
1476706f2543Smrg
1477706f2543Smrg		if (cnt == 1) {
1478706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
1479706f2543Smrg        } else {
1480706f2543Smrg			CLEAR_FLAG(F_OF);
1481706f2543Smrg        }
1482706f2543Smrg	} else {
1483706f2543Smrg		res = 0;
1484706f2543Smrg		CLEAR_FLAG(F_CF);
1485706f2543Smrg		CLEAR_FLAG(F_OF);
1486706f2543Smrg		SET_FLAG(F_ZF);
1487706f2543Smrg		CLEAR_FLAG(F_SF);
1488706f2543Smrg		CLEAR_FLAG(F_PF);
1489706f2543Smrg    }
1490706f2543Smrg	return (u16)res;
1491706f2543Smrg}
1492706f2543Smrg
1493706f2543Smrg/****************************************************************************
1494706f2543SmrgREMARKS:
1495706f2543SmrgImplements the SHR instruction and side effects.
1496706f2543Smrg****************************************************************************/
1497706f2543Smrgu32 shr_long(u32 d, u8 s)
1498706f2543Smrg{
1499706f2543Smrg	unsigned int cnt, res, cf;
1500706f2543Smrg
1501706f2543Smrg	if (s < 32) {
1502706f2543Smrg		cnt = s % 32;
1503706f2543Smrg		if (cnt > 0) {
1504706f2543Smrg			cf = d & (1 << (cnt - 1));
1505706f2543Smrg			res = d >> cnt;
1506706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1507706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1508706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1509706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1510706f2543Smrg        } else {
1511706f2543Smrg            res = d;
1512706f2543Smrg        }
1513706f2543Smrg        if (cnt == 1) {
1514706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
1515706f2543Smrg        } else {
1516706f2543Smrg			CLEAR_FLAG(F_OF);
1517706f2543Smrg        }
1518706f2543Smrg    } else {
1519706f2543Smrg        res = 0;
1520706f2543Smrg		CLEAR_FLAG(F_CF);
1521706f2543Smrg		CLEAR_FLAG(F_OF);
1522706f2543Smrg		SET_FLAG(F_ZF);
1523706f2543Smrg		CLEAR_FLAG(F_SF);
1524706f2543Smrg		CLEAR_FLAG(F_PF);
1525706f2543Smrg    }
1526706f2543Smrg    return res;
1527706f2543Smrg}
1528706f2543Smrg
1529706f2543Smrg/****************************************************************************
1530706f2543SmrgREMARKS:
1531706f2543SmrgImplements the SAR instruction and side effects.
1532706f2543Smrg****************************************************************************/
1533706f2543Smrgu8 sar_byte(u8 d, u8 s)
1534706f2543Smrg{
1535706f2543Smrg	unsigned int cnt, res, cf, mask, sf;
1536706f2543Smrg
1537706f2543Smrg	res = d;
1538706f2543Smrg	sf = d & 0x80;
1539706f2543Smrg    cnt = s % 8;
1540706f2543Smrg	if (cnt > 0 && cnt < 8) {
1541706f2543Smrg		mask = (1 << (8 - cnt)) - 1;
1542706f2543Smrg		cf = d & (1 << (cnt - 1));
1543706f2543Smrg		res = (d >> cnt) & mask;
1544706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1545706f2543Smrg		if (sf) {
1546706f2543Smrg			res |= ~mask;
1547706f2543Smrg		}
1548706f2543Smrg		CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
1549706f2543Smrg		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1550706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1551706f2543Smrg    } else if (cnt >= 8) {
1552706f2543Smrg        if (sf) {
1553706f2543Smrg            res = 0xff;
1554706f2543Smrg			SET_FLAG(F_CF);
1555706f2543Smrg			CLEAR_FLAG(F_ZF);
1556706f2543Smrg			SET_FLAG(F_SF);
1557706f2543Smrg			SET_FLAG(F_PF);
1558706f2543Smrg		} else {
1559706f2543Smrg			res = 0;
1560706f2543Smrg			CLEAR_FLAG(F_CF);
1561706f2543Smrg			SET_FLAG(F_ZF);
1562706f2543Smrg			CLEAR_FLAG(F_SF);
1563706f2543Smrg			CLEAR_FLAG(F_PF);
1564706f2543Smrg		}
1565706f2543Smrg	}
1566706f2543Smrg	return (u8)res;
1567706f2543Smrg}
1568706f2543Smrg
1569706f2543Smrg/****************************************************************************
1570706f2543SmrgREMARKS:
1571706f2543SmrgImplements the SAR instruction and side effects.
1572706f2543Smrg****************************************************************************/
1573706f2543Smrgu16 sar_word(u16 d, u8 s)
1574706f2543Smrg{
1575706f2543Smrg    unsigned int cnt, res, cf, mask, sf;
1576706f2543Smrg
1577706f2543Smrg    sf = d & 0x8000;
1578706f2543Smrg    cnt = s % 16;
1579706f2543Smrg	res = d;
1580706f2543Smrg	if (cnt > 0 && cnt < 16) {
1581706f2543Smrg        mask = (1 << (16 - cnt)) - 1;
1582706f2543Smrg        cf = d & (1 << (cnt - 1));
1583706f2543Smrg        res = (d >> cnt) & mask;
1584706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1585706f2543Smrg        if (sf) {
1586706f2543Smrg            res |= ~mask;
1587706f2543Smrg        }
1588706f2543Smrg		CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1589706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1590706f2543Smrg		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1591706f2543Smrg    } else if (cnt >= 16) {
1592706f2543Smrg        if (sf) {
1593706f2543Smrg            res = 0xffff;
1594706f2543Smrg			SET_FLAG(F_CF);
1595706f2543Smrg			CLEAR_FLAG(F_ZF);
1596706f2543Smrg			SET_FLAG(F_SF);
1597706f2543Smrg			SET_FLAG(F_PF);
1598706f2543Smrg        } else {
1599706f2543Smrg            res = 0;
1600706f2543Smrg			CLEAR_FLAG(F_CF);
1601706f2543Smrg			SET_FLAG(F_ZF);
1602706f2543Smrg			CLEAR_FLAG(F_SF);
1603706f2543Smrg			CLEAR_FLAG(F_PF);
1604706f2543Smrg        }
1605706f2543Smrg    }
1606706f2543Smrg	return (u16)res;
1607706f2543Smrg}
1608706f2543Smrg
1609706f2543Smrg/****************************************************************************
1610706f2543SmrgREMARKS:
1611706f2543SmrgImplements the SAR instruction and side effects.
1612706f2543Smrg****************************************************************************/
1613706f2543Smrgu32 sar_long(u32 d, u8 s)
1614706f2543Smrg{
1615706f2543Smrg    u32 cnt, res, cf, mask, sf;
1616706f2543Smrg
1617706f2543Smrg    sf = d & 0x80000000;
1618706f2543Smrg    cnt = s % 32;
1619706f2543Smrg	res = d;
1620706f2543Smrg	if (cnt > 0 && cnt < 32) {
1621706f2543Smrg        mask = (1 << (32 - cnt)) - 1;
1622706f2543Smrg		cf = d & (1 << (cnt - 1));
1623706f2543Smrg        res = (d >> cnt) & mask;
1624706f2543Smrg		CONDITIONAL_SET_FLAG(cf, F_CF);
1625706f2543Smrg        if (sf) {
1626706f2543Smrg            res |= ~mask;
1627706f2543Smrg        }
1628706f2543Smrg		CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1629706f2543Smrg		CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1630706f2543Smrg		CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1631706f2543Smrg    } else if (cnt >= 32) {
1632706f2543Smrg        if (sf) {
1633706f2543Smrg            res = 0xffffffff;
1634706f2543Smrg			SET_FLAG(F_CF);
1635706f2543Smrg			CLEAR_FLAG(F_ZF);
1636706f2543Smrg			SET_FLAG(F_SF);
1637706f2543Smrg			SET_FLAG(F_PF);
1638706f2543Smrg		} else {
1639706f2543Smrg			res = 0;
1640706f2543Smrg			CLEAR_FLAG(F_CF);
1641706f2543Smrg			SET_FLAG(F_ZF);
1642706f2543Smrg			CLEAR_FLAG(F_SF);
1643706f2543Smrg			CLEAR_FLAG(F_PF);
1644706f2543Smrg		}
1645706f2543Smrg	}
1646706f2543Smrg	return res;
1647706f2543Smrg}
1648706f2543Smrg
1649706f2543Smrg/****************************************************************************
1650706f2543SmrgREMARKS:
1651706f2543SmrgImplements the SHLD instruction and side effects.
1652706f2543Smrg****************************************************************************/
1653706f2543Smrgu16 shld_word (u16 d, u16 fill, u8 s)
1654706f2543Smrg{
1655706f2543Smrg	unsigned int cnt, res, cf;
1656706f2543Smrg
1657706f2543Smrg	if (s < 16) {
1658706f2543Smrg		cnt = s % 16;
1659706f2543Smrg		if (cnt > 0) {
1660706f2543Smrg			res = (d << cnt) | (fill >> (16-cnt));
1661706f2543Smrg			cf = d & (1 << (16 - cnt));
1662706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1663706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1664706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1665706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1666706f2543Smrg		} else {
1667706f2543Smrg			res = d;
1668706f2543Smrg		}
1669706f2543Smrg		if (cnt == 1) {
1670706f2543Smrg			CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
1671706f2543Smrg								  (ACCESS_FLAG(F_CF) != 0)), F_OF);
1672706f2543Smrg		} else {
1673706f2543Smrg			CLEAR_FLAG(F_OF);
1674706f2543Smrg		}
1675706f2543Smrg	} else {
1676706f2543Smrg		res = 0;
1677706f2543Smrg		CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
1678706f2543Smrg		CLEAR_FLAG(F_OF);
1679706f2543Smrg		CLEAR_FLAG(F_SF);
1680706f2543Smrg		SET_FLAG(F_PF);
1681706f2543Smrg		SET_FLAG(F_ZF);
1682706f2543Smrg	}
1683706f2543Smrg	return (u16)res;
1684706f2543Smrg}
1685706f2543Smrg
1686706f2543Smrg/****************************************************************************
1687706f2543SmrgREMARKS:
1688706f2543SmrgImplements the SHLD instruction and side effects.
1689706f2543Smrg****************************************************************************/
1690706f2543Smrgu32 shld_long (u32 d, u32 fill, u8 s)
1691706f2543Smrg{
1692706f2543Smrg	unsigned int cnt, res, cf;
1693706f2543Smrg
1694706f2543Smrg	if (s < 32) {
1695706f2543Smrg		cnt = s % 32;
1696706f2543Smrg		if (cnt > 0) {
1697706f2543Smrg			res = (d << cnt) | (fill >> (32-cnt));
1698706f2543Smrg			cf = d & (1 << (32 - cnt));
1699706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1700706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1701706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1702706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1703706f2543Smrg		} else {
1704706f2543Smrg			res = d;
1705706f2543Smrg		}
1706706f2543Smrg		if (cnt == 1) {
1707706f2543Smrg			CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
1708706f2543Smrg								  (ACCESS_FLAG(F_CF) != 0)), F_OF);
1709706f2543Smrg		} else {
1710706f2543Smrg			CLEAR_FLAG(F_OF);
1711706f2543Smrg		}
1712706f2543Smrg	} else {
1713706f2543Smrg		res = 0;
1714706f2543Smrg		CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
1715706f2543Smrg		CLEAR_FLAG(F_OF);
1716706f2543Smrg		CLEAR_FLAG(F_SF);
1717706f2543Smrg		SET_FLAG(F_PF);
1718706f2543Smrg		SET_FLAG(F_ZF);
1719706f2543Smrg	}
1720706f2543Smrg	return res;
1721706f2543Smrg}
1722706f2543Smrg
1723706f2543Smrg/****************************************************************************
1724706f2543SmrgREMARKS:
1725706f2543SmrgImplements the SHRD instruction and side effects.
1726706f2543Smrg****************************************************************************/
1727706f2543Smrgu16 shrd_word (u16 d, u16 fill, u8 s)
1728706f2543Smrg{
1729706f2543Smrg	unsigned int cnt, res, cf;
1730706f2543Smrg
1731706f2543Smrg	if (s < 16) {
1732706f2543Smrg		cnt = s % 16;
1733706f2543Smrg		if (cnt > 0) {
1734706f2543Smrg			cf = d & (1 << (cnt - 1));
1735706f2543Smrg			res = (d >> cnt) | (fill << (16 - cnt));
1736706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1737706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1738706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1739706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1740706f2543Smrg		} else {
1741706f2543Smrg			res = d;
1742706f2543Smrg		}
1743706f2543Smrg
1744706f2543Smrg		if (cnt == 1) {
1745706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
1746706f2543Smrg        } else {
1747706f2543Smrg			CLEAR_FLAG(F_OF);
1748706f2543Smrg        }
1749706f2543Smrg	} else {
1750706f2543Smrg		res = 0;
1751706f2543Smrg		CLEAR_FLAG(F_CF);
1752706f2543Smrg		CLEAR_FLAG(F_OF);
1753706f2543Smrg		SET_FLAG(F_ZF);
1754706f2543Smrg		CLEAR_FLAG(F_SF);
1755706f2543Smrg		CLEAR_FLAG(F_PF);
1756706f2543Smrg    }
1757706f2543Smrg	return (u16)res;
1758706f2543Smrg}
1759706f2543Smrg
1760706f2543Smrg/****************************************************************************
1761706f2543SmrgREMARKS:
1762706f2543SmrgImplements the SHRD instruction and side effects.
1763706f2543Smrg****************************************************************************/
1764706f2543Smrgu32 shrd_long (u32 d, u32 fill, u8 s)
1765706f2543Smrg{
1766706f2543Smrg	unsigned int cnt, res, cf;
1767706f2543Smrg
1768706f2543Smrg	if (s < 32) {
1769706f2543Smrg		cnt = s % 32;
1770706f2543Smrg		if (cnt > 0) {
1771706f2543Smrg			cf = d & (1 << (cnt - 1));
1772706f2543Smrg			res = (d >> cnt) | (fill << (32 - cnt));
1773706f2543Smrg			CONDITIONAL_SET_FLAG(cf, F_CF);
1774706f2543Smrg			CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1775706f2543Smrg			CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1776706f2543Smrg			CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1777706f2543Smrg		} else {
1778706f2543Smrg			res = d;
1779706f2543Smrg		}
1780706f2543Smrg		if (cnt == 1) {
1781706f2543Smrg			CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
1782706f2543Smrg        } else {
1783706f2543Smrg			CLEAR_FLAG(F_OF);
1784706f2543Smrg        }
1785706f2543Smrg	} else {
1786706f2543Smrg		res = 0;
1787706f2543Smrg		CLEAR_FLAG(F_CF);
1788706f2543Smrg		CLEAR_FLAG(F_OF);
1789706f2543Smrg		SET_FLAG(F_ZF);
1790706f2543Smrg		CLEAR_FLAG(F_SF);
1791706f2543Smrg		CLEAR_FLAG(F_PF);
1792706f2543Smrg    }
1793706f2543Smrg	return res;
1794706f2543Smrg}
1795706f2543Smrg
1796706f2543Smrg/****************************************************************************
1797706f2543SmrgREMARKS:
1798706f2543SmrgImplements the SBB instruction and side effects.
1799706f2543Smrg****************************************************************************/
1800706f2543Smrgu8 sbb_byte(u8 d, u8 s)
1801706f2543Smrg{
1802706f2543Smrg    register u32 res;   /* all operands in native machine order */
1803706f2543Smrg    register u32 bc;
1804706f2543Smrg
1805706f2543Smrg	if (ACCESS_FLAG(F_CF))
1806706f2543Smrg		res = d - s - 1;
1807706f2543Smrg	else
1808706f2543Smrg		res = d - s;
1809706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1810706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
1811706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1812706f2543Smrg
1813706f2543Smrg	/* calculate the borrow chain.  See note at top */
1814706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1815706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
1816706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
1817706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1818706f2543Smrg	return (u8)res;
1819706f2543Smrg}
1820706f2543Smrg
1821706f2543Smrg/****************************************************************************
1822706f2543SmrgREMARKS:
1823706f2543SmrgImplements the SBB instruction and side effects.
1824706f2543Smrg****************************************************************************/
1825706f2543Smrgu16 sbb_word(u16 d, u16 s)
1826706f2543Smrg{
1827706f2543Smrg    register u32 res;   /* all operands in native machine order */
1828706f2543Smrg    register u32 bc;
1829706f2543Smrg
1830706f2543Smrg	if (ACCESS_FLAG(F_CF))
1831706f2543Smrg        res = d - s - 1;
1832706f2543Smrg    else
1833706f2543Smrg        res = d - s;
1834706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1835706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1836706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1837706f2543Smrg
1838706f2543Smrg	/* calculate the borrow chain.  See note at top */
1839706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1840706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
1841706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
1842706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1843706f2543Smrg	return (u16)res;
1844706f2543Smrg}
1845706f2543Smrg
1846706f2543Smrg/****************************************************************************
1847706f2543SmrgREMARKS:
1848706f2543SmrgImplements the SBB instruction and side effects.
1849706f2543Smrg****************************************************************************/
1850706f2543Smrgu32 sbb_long(u32 d, u32 s)
1851706f2543Smrg{
1852706f2543Smrg	register u32 res;   /* all operands in native machine order */
1853706f2543Smrg	register u32 bc;
1854706f2543Smrg
1855706f2543Smrg	if (ACCESS_FLAG(F_CF))
1856706f2543Smrg        res = d - s - 1;
1857706f2543Smrg    else
1858706f2543Smrg        res = d - s;
1859706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1860706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1861706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1862706f2543Smrg
1863706f2543Smrg	/* calculate the borrow chain.  See note at top */
1864706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1865706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
1866706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
1867706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1868706f2543Smrg	return res;
1869706f2543Smrg}
1870706f2543Smrg
1871706f2543Smrg/****************************************************************************
1872706f2543SmrgREMARKS:
1873706f2543SmrgImplements the SUB instruction and side effects.
1874706f2543Smrg****************************************************************************/
1875706f2543Smrgu8 sub_byte(u8 d, u8 s)
1876706f2543Smrg{
1877706f2543Smrg	register u32 res;   /* all operands in native machine order */
1878706f2543Smrg	register u32 bc;
1879706f2543Smrg
1880706f2543Smrg	res = d - s;
1881706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1882706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
1883706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1884706f2543Smrg
1885706f2543Smrg	/* calculate the borrow chain.  See note at top */
1886706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1887706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
1888706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
1889706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1890706f2543Smrg	return (u8)res;
1891706f2543Smrg}
1892706f2543Smrg
1893706f2543Smrg/****************************************************************************
1894706f2543SmrgREMARKS:
1895706f2543SmrgImplements the SUB instruction and side effects.
1896706f2543Smrg****************************************************************************/
1897706f2543Smrgu16 sub_word(u16 d, u16 s)
1898706f2543Smrg{
1899706f2543Smrg    register u32 res;   /* all operands in native machine order */
1900706f2543Smrg    register u32 bc;
1901706f2543Smrg
1902706f2543Smrg    res = d - s;
1903706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1904706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
1905706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1906706f2543Smrg
1907706f2543Smrg	/* calculate the borrow chain.  See note at top */
1908706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1909706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
1910706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
1911706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1912706f2543Smrg	return (u16)res;
1913706f2543Smrg}
1914706f2543Smrg
1915706f2543Smrg/****************************************************************************
1916706f2543SmrgREMARKS:
1917706f2543SmrgImplements the SUB instruction and side effects.
1918706f2543Smrg****************************************************************************/
1919706f2543Smrgu32 sub_long(u32 d, u32 s)
1920706f2543Smrg{
1921706f2543Smrg	register u32 res;   /* all operands in native machine order */
1922706f2543Smrg	register u32 bc;
1923706f2543Smrg
1924706f2543Smrg	res = d - s;
1925706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1926706f2543Smrg	CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
1927706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1928706f2543Smrg
1929706f2543Smrg	/* calculate the borrow chain.  See note at top */
1930706f2543Smrg	bc = (res & (~d | s)) | (~d & s);
1931706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
1932706f2543Smrg	CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
1933706f2543Smrg	CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
1934706f2543Smrg	return res;
1935706f2543Smrg}
1936706f2543Smrg
1937706f2543Smrg/****************************************************************************
1938706f2543SmrgREMARKS:
1939706f2543SmrgImplements the TEST instruction and side effects.
1940706f2543Smrg****************************************************************************/
1941706f2543Smrgvoid test_byte(u8 d, u8 s)
1942706f2543Smrg{
1943706f2543Smrg    register u32 res;   /* all operands in native machine order */
1944706f2543Smrg
1945706f2543Smrg    res = d & s;
1946706f2543Smrg
1947706f2543Smrg	CLEAR_FLAG(F_OF);
1948706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
1949706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
1950706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1951706f2543Smrg    /* AF == dont care */
1952706f2543Smrg	CLEAR_FLAG(F_CF);
1953706f2543Smrg}
1954706f2543Smrg
1955706f2543Smrg/****************************************************************************
1956706f2543SmrgREMARKS:
1957706f2543SmrgImplements the TEST instruction and side effects.
1958706f2543Smrg****************************************************************************/
1959706f2543Smrgvoid test_word(u16 d, u16 s)
1960706f2543Smrg{
1961706f2543Smrg	register u32 res;   /* all operands in native machine order */
1962706f2543Smrg
1963706f2543Smrg	res = d & s;
1964706f2543Smrg
1965706f2543Smrg	CLEAR_FLAG(F_OF);
1966706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
1967706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
1968706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1969706f2543Smrg	/* AF == dont care */
1970706f2543Smrg	CLEAR_FLAG(F_CF);
1971706f2543Smrg}
1972706f2543Smrg
1973706f2543Smrg/****************************************************************************
1974706f2543SmrgREMARKS:
1975706f2543SmrgImplements the TEST instruction and side effects.
1976706f2543Smrg****************************************************************************/
1977706f2543Smrgvoid test_long(u32 d, u32 s)
1978706f2543Smrg{
1979706f2543Smrg	register u32 res;   /* all operands in native machine order */
1980706f2543Smrg
1981706f2543Smrg	res = d & s;
1982706f2543Smrg
1983706f2543Smrg	CLEAR_FLAG(F_OF);
1984706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
1985706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
1986706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
1987706f2543Smrg	/* AF == dont care */
1988706f2543Smrg	CLEAR_FLAG(F_CF);
1989706f2543Smrg}
1990706f2543Smrg
1991706f2543Smrg/****************************************************************************
1992706f2543SmrgREMARKS:
1993706f2543SmrgImplements the XOR instruction and side effects.
1994706f2543Smrg****************************************************************************/
1995706f2543Smrgu8 xor_byte(u8 d, u8 s)
1996706f2543Smrg{
1997706f2543Smrg	register u8 res;    /* all operands in native machine order */
1998706f2543Smrg
1999706f2543Smrg	res = d ^ s;
2000706f2543Smrg	CLEAR_FLAG(F_OF);
2001706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
2002706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
2003706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
2004706f2543Smrg	CLEAR_FLAG(F_CF);
2005706f2543Smrg	CLEAR_FLAG(F_AF);
2006706f2543Smrg	return res;
2007706f2543Smrg}
2008706f2543Smrg
2009706f2543Smrg/****************************************************************************
2010706f2543SmrgREMARKS:
2011706f2543SmrgImplements the XOR instruction and side effects.
2012706f2543Smrg****************************************************************************/
2013706f2543Smrgu16 xor_word(u16 d, u16 s)
2014706f2543Smrg{
2015706f2543Smrg	register u16 res;   /* all operands in native machine order */
2016706f2543Smrg
2017706f2543Smrg	res = d ^ s;
2018706f2543Smrg	CLEAR_FLAG(F_OF);
2019706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
2020706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
2021706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
2022706f2543Smrg	CLEAR_FLAG(F_CF);
2023706f2543Smrg	CLEAR_FLAG(F_AF);
2024706f2543Smrg	return res;
2025706f2543Smrg}
2026706f2543Smrg
2027706f2543Smrg/****************************************************************************
2028706f2543SmrgREMARKS:
2029706f2543SmrgImplements the XOR instruction and side effects.
2030706f2543Smrg****************************************************************************/
2031706f2543Smrgu32 xor_long(u32 d, u32 s)
2032706f2543Smrg{
2033706f2543Smrg	register u32 res;   /* all operands in native machine order */
2034706f2543Smrg
2035706f2543Smrg	res = d ^ s;
2036706f2543Smrg	CLEAR_FLAG(F_OF);
2037706f2543Smrg	CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
2038706f2543Smrg	CONDITIONAL_SET_FLAG(res == 0, F_ZF);
2039706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
2040706f2543Smrg	CLEAR_FLAG(F_CF);
2041706f2543Smrg	CLEAR_FLAG(F_AF);
2042706f2543Smrg	return res;
2043706f2543Smrg}
2044706f2543Smrg
2045706f2543Smrg/****************************************************************************
2046706f2543SmrgREMARKS:
2047706f2543SmrgImplements the IMUL instruction and side effects.
2048706f2543Smrg****************************************************************************/
2049706f2543Smrgvoid imul_byte(u8 s)
2050706f2543Smrg{
2051706f2543Smrg	s16 res = (s16)((s8)M.x86.R_AL * (s8)s);
2052706f2543Smrg
2053706f2543Smrg	M.x86.R_AX = res;
2054706f2543Smrg	if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) ||
2055706f2543Smrg		((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) {
2056706f2543Smrg		CLEAR_FLAG(F_CF);
2057706f2543Smrg		CLEAR_FLAG(F_OF);
2058706f2543Smrg	} else {
2059706f2543Smrg		SET_FLAG(F_CF);
2060706f2543Smrg		SET_FLAG(F_OF);
2061706f2543Smrg	}
2062706f2543Smrg}
2063706f2543Smrg
2064706f2543Smrg/****************************************************************************
2065706f2543SmrgREMARKS:
2066706f2543SmrgImplements the IMUL instruction and side effects.
2067706f2543Smrg****************************************************************************/
2068706f2543Smrgvoid imul_word(u16 s)
2069706f2543Smrg{
2070706f2543Smrg	s32 res = (s16)M.x86.R_AX * (s16)s;
2071706f2543Smrg
2072706f2543Smrg	M.x86.R_AX = (u16)res;
2073706f2543Smrg	M.x86.R_DX = (u16)(res >> 16);
2074706f2543Smrg	if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) ||
2075706f2543Smrg		((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFF)) {
2076706f2543Smrg		CLEAR_FLAG(F_CF);
2077706f2543Smrg		CLEAR_FLAG(F_OF);
2078706f2543Smrg	} else {
2079706f2543Smrg		SET_FLAG(F_CF);
2080706f2543Smrg		SET_FLAG(F_OF);
2081706f2543Smrg	}
2082706f2543Smrg}
2083706f2543Smrg
2084706f2543Smrg/****************************************************************************
2085706f2543SmrgREMARKS:
2086706f2543SmrgImplements the IMUL instruction and side effects.
2087706f2543Smrg****************************************************************************/
2088706f2543Smrgvoid imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s)
2089706f2543Smrg{
2090706f2543Smrg#ifdef	__HAS_LONG_LONG__
2091706f2543Smrg	s64 res = (s64)(s32)d * (s32)s;
2092706f2543Smrg
2093706f2543Smrg	*res_lo = (u32)res;
2094706f2543Smrg	*res_hi = (u32)(res >> 32);
2095706f2543Smrg#else
2096706f2543Smrg	u32	d_lo,d_hi,d_sign;
2097706f2543Smrg	u32	s_lo,s_hi,s_sign;
2098706f2543Smrg	u32	rlo_lo,rlo_hi,rhi_lo;
2099706f2543Smrg
2100706f2543Smrg	if ((d_sign = d & 0x80000000) != 0)
2101706f2543Smrg		d = -d;
2102706f2543Smrg	d_lo = d & 0xFFFF;
2103706f2543Smrg	d_hi = d >> 16;
2104706f2543Smrg	if ((s_sign = s & 0x80000000) != 0)
2105706f2543Smrg		s = -s;
2106706f2543Smrg	s_lo = s & 0xFFFF;
2107706f2543Smrg	s_hi = s >> 16;
2108706f2543Smrg	rlo_lo = d_lo * s_lo;
2109706f2543Smrg	rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16);
2110706f2543Smrg	rhi_lo = d_hi * s_hi + (rlo_hi >> 16);
2111706f2543Smrg	*res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
2112706f2543Smrg	*res_hi = rhi_lo;
2113706f2543Smrg	if (d_sign != s_sign) {
2114706f2543Smrg		d = ~*res_lo;
2115706f2543Smrg		s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16);
2116706f2543Smrg		*res_lo = ~*res_lo+1;
2117706f2543Smrg		*res_hi = ~*res_hi+(s >> 16);
2118706f2543Smrg		}
2119706f2543Smrg#endif
2120706f2543Smrg}
2121706f2543Smrg
2122706f2543Smrg/****************************************************************************
2123706f2543SmrgREMARKS:
2124706f2543SmrgImplements the IMUL instruction and side effects.
2125706f2543Smrg****************************************************************************/
2126706f2543Smrgvoid imul_long(u32 s)
2127706f2543Smrg{
2128706f2543Smrg	imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s);
2129706f2543Smrg	if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) ||
2130706f2543Smrg		((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFF)) {
2131706f2543Smrg		CLEAR_FLAG(F_CF);
2132706f2543Smrg		CLEAR_FLAG(F_OF);
2133706f2543Smrg	} else {
2134706f2543Smrg		SET_FLAG(F_CF);
2135706f2543Smrg		SET_FLAG(F_OF);
2136706f2543Smrg	}
2137706f2543Smrg}
2138706f2543Smrg
2139706f2543Smrg/****************************************************************************
2140706f2543SmrgREMARKS:
2141706f2543SmrgImplements the MUL instruction and side effects.
2142706f2543Smrg****************************************************************************/
2143706f2543Smrgvoid mul_byte(u8 s)
2144706f2543Smrg{
2145706f2543Smrg	u16 res = (u16)(M.x86.R_AL * s);
2146706f2543Smrg
2147706f2543Smrg	M.x86.R_AX = res;
2148706f2543Smrg	if (M.x86.R_AH == 0) {
2149706f2543Smrg		CLEAR_FLAG(F_CF);
2150706f2543Smrg		CLEAR_FLAG(F_OF);
2151706f2543Smrg	} else {
2152706f2543Smrg		SET_FLAG(F_CF);
2153706f2543Smrg		SET_FLAG(F_OF);
2154706f2543Smrg	}
2155706f2543Smrg}
2156706f2543Smrg
2157706f2543Smrg/****************************************************************************
2158706f2543SmrgREMARKS:
2159706f2543SmrgImplements the MUL instruction and side effects.
2160706f2543Smrg****************************************************************************/
2161706f2543Smrgvoid mul_word(u16 s)
2162706f2543Smrg{
2163706f2543Smrg	u32 res = M.x86.R_AX * s;
2164706f2543Smrg
2165706f2543Smrg	M.x86.R_AX = (u16)res;
2166706f2543Smrg	M.x86.R_DX = (u16)(res >> 16);
2167706f2543Smrg	if (M.x86.R_DX == 0) {
2168706f2543Smrg		CLEAR_FLAG(F_CF);
2169706f2543Smrg		CLEAR_FLAG(F_OF);
2170706f2543Smrg    } else {
2171706f2543Smrg		SET_FLAG(F_CF);
2172706f2543Smrg		SET_FLAG(F_OF);
2173706f2543Smrg    }
2174706f2543Smrg}
2175706f2543Smrg
2176706f2543Smrg/****************************************************************************
2177706f2543SmrgREMARKS:
2178706f2543SmrgImplements the MUL instruction and side effects.
2179706f2543Smrg****************************************************************************/
2180706f2543Smrgvoid mul_long(u32 s)
2181706f2543Smrg{
2182706f2543Smrg#ifdef	__HAS_LONG_LONG__
2183706f2543Smrg	u64 res = (u64)M.x86.R_EAX * s;
2184706f2543Smrg
2185706f2543Smrg	M.x86.R_EAX = (u32)res;
2186706f2543Smrg	M.x86.R_EDX = (u32)(res >> 32);
2187706f2543Smrg#else
2188706f2543Smrg	u32	a,a_lo,a_hi;
2189706f2543Smrg	u32	s_lo,s_hi;
2190706f2543Smrg	u32	rlo_lo,rlo_hi,rhi_lo;
2191706f2543Smrg
2192706f2543Smrg	a = M.x86.R_EAX;
2193706f2543Smrg	a_lo = a & 0xFFFF;
2194706f2543Smrg	a_hi = a >> 16;
2195706f2543Smrg	s_lo = s & 0xFFFF;
2196706f2543Smrg	s_hi = s >> 16;
2197706f2543Smrg	rlo_lo = a_lo * s_lo;
2198706f2543Smrg	rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16);
2199706f2543Smrg	rhi_lo = a_hi * s_hi + (rlo_hi >> 16);
2200706f2543Smrg	M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
2201706f2543Smrg	M.x86.R_EDX = rhi_lo;
2202706f2543Smrg#endif
2203706f2543Smrg
2204706f2543Smrg	if (M.x86.R_EDX == 0) {
2205706f2543Smrg		CLEAR_FLAG(F_CF);
2206706f2543Smrg		CLEAR_FLAG(F_OF);
2207706f2543Smrg	} else {
2208706f2543Smrg		SET_FLAG(F_CF);
2209706f2543Smrg		SET_FLAG(F_OF);
2210706f2543Smrg    }
2211706f2543Smrg}
2212706f2543Smrg
2213706f2543Smrg/****************************************************************************
2214706f2543SmrgREMARKS:
2215706f2543SmrgImplements the IDIV instruction and side effects.
2216706f2543Smrg****************************************************************************/
2217706f2543Smrgvoid idiv_byte(u8 s)
2218706f2543Smrg{
2219706f2543Smrg    s32 dvd, div, mod;
2220706f2543Smrg
2221706f2543Smrg	dvd = (s16)M.x86.R_AX;
2222706f2543Smrg	if (s == 0) {
2223706f2543Smrg		x86emu_intr_raise(0);
2224706f2543Smrg        return;
2225706f2543Smrg	}
2226706f2543Smrg	div = dvd / (s8)s;
2227706f2543Smrg	mod = dvd % (s8)s;
2228706f2543Smrg	if (abs(div) > 0x7f) {
2229706f2543Smrg		x86emu_intr_raise(0);
2230706f2543Smrg		return;
2231706f2543Smrg	}
2232706f2543Smrg	M.x86.R_AL = (s8) div;
2233706f2543Smrg	M.x86.R_AH = (s8) mod;
2234706f2543Smrg}
2235706f2543Smrg
2236706f2543Smrg/****************************************************************************
2237706f2543SmrgREMARKS:
2238706f2543SmrgImplements the IDIV instruction and side effects.
2239706f2543Smrg****************************************************************************/
2240706f2543Smrgvoid idiv_word(u16 s)
2241706f2543Smrg{
2242706f2543Smrg	s32 dvd, div, mod;
2243706f2543Smrg
2244706f2543Smrg	dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX;
2245706f2543Smrg	if (s == 0) {
2246706f2543Smrg		x86emu_intr_raise(0);
2247706f2543Smrg		return;
2248706f2543Smrg	}
2249706f2543Smrg	div = dvd / (s16)s;
2250706f2543Smrg	mod = dvd % (s16)s;
2251706f2543Smrg	if (abs(div) > 0x7fff) {
2252706f2543Smrg		x86emu_intr_raise(0);
2253706f2543Smrg		return;
2254706f2543Smrg	}
2255706f2543Smrg	CLEAR_FLAG(F_CF);
2256706f2543Smrg	CLEAR_FLAG(F_SF);
2257706f2543Smrg	CONDITIONAL_SET_FLAG(div == 0, F_ZF);
2258706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
2259706f2543Smrg
2260706f2543Smrg	M.x86.R_AX = (u16)div;
2261706f2543Smrg	M.x86.R_DX = (u16)mod;
2262706f2543Smrg}
2263706f2543Smrg
2264706f2543Smrg/****************************************************************************
2265706f2543SmrgREMARKS:
2266706f2543SmrgImplements the IDIV instruction and side effects.
2267706f2543Smrg****************************************************************************/
2268706f2543Smrgvoid idiv_long(u32 s)
2269706f2543Smrg{
2270706f2543Smrg#ifdef	__HAS_LONG_LONG__
2271706f2543Smrg	s64 dvd, div, mod;
2272706f2543Smrg
2273706f2543Smrg	dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
2274706f2543Smrg	if (s == 0) {
2275706f2543Smrg		x86emu_intr_raise(0);
2276706f2543Smrg		return;
2277706f2543Smrg	}
2278706f2543Smrg	div = dvd / (s32)s;
2279706f2543Smrg	mod = dvd % (s32)s;
2280706f2543Smrg	if (abs(div) > 0x7fffffff) {
2281706f2543Smrg		x86emu_intr_raise(0);
2282706f2543Smrg		return;
2283706f2543Smrg	}
2284706f2543Smrg#else
2285706f2543Smrg	s32 div = 0, mod;
2286706f2543Smrg	s32 h_dvd = M.x86.R_EDX;
2287706f2543Smrg	u32 l_dvd = M.x86.R_EAX;
2288706f2543Smrg	u32 abs_s = s & 0x7FFFFFFF;
2289706f2543Smrg	u32 abs_h_dvd = h_dvd & 0x7FFFFFFF;
2290706f2543Smrg	u32 h_s = abs_s >> 1;
2291706f2543Smrg	u32 l_s = abs_s << 31;
2292706f2543Smrg	int counter = 31;
2293706f2543Smrg	int carry;
2294706f2543Smrg
2295706f2543Smrg	if (s == 0) {
2296706f2543Smrg		x86emu_intr_raise(0);
2297706f2543Smrg		return;
2298706f2543Smrg	}
2299706f2543Smrg	do {
2300706f2543Smrg		div <<= 1;
2301706f2543Smrg		carry = (l_dvd >= l_s) ? 0 : 1;
2302706f2543Smrg
2303706f2543Smrg		if (abs_h_dvd < (h_s + carry)) {
2304706f2543Smrg			h_s >>= 1;
2305706f2543Smrg			l_s = abs_s << (--counter);
2306706f2543Smrg			continue;
2307706f2543Smrg		} else {
2308706f2543Smrg			abs_h_dvd -= (h_s + carry);
2309706f2543Smrg			l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
2310706f2543Smrg				: (l_dvd - l_s);
2311706f2543Smrg			h_s >>= 1;
2312706f2543Smrg			l_s = abs_s << (--counter);
2313706f2543Smrg			div |= 1;
2314706f2543Smrg			continue;
2315706f2543Smrg		}
2316706f2543Smrg
2317706f2543Smrg	} while (counter > -1);
2318706f2543Smrg	/* overflow */
2319706f2543Smrg	if (abs_h_dvd || (l_dvd > abs_s)) {
2320706f2543Smrg		x86emu_intr_raise(0);
2321706f2543Smrg		return;
2322706f2543Smrg	}
2323706f2543Smrg	/* sign */
2324706f2543Smrg	div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000));
2325706f2543Smrg	mod = l_dvd;
2326706f2543Smrg
2327706f2543Smrg#endif
2328706f2543Smrg	CLEAR_FLAG(F_CF);
2329706f2543Smrg	CLEAR_FLAG(F_AF);
2330706f2543Smrg	CLEAR_FLAG(F_SF);
2331706f2543Smrg	SET_FLAG(F_ZF);
2332706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
2333706f2543Smrg
2334706f2543Smrg	M.x86.R_EAX = (u32)div;
2335706f2543Smrg	M.x86.R_EDX = (u32)mod;
2336706f2543Smrg}
2337706f2543Smrg
2338706f2543Smrg/****************************************************************************
2339706f2543SmrgREMARKS:
2340706f2543SmrgImplements the DIV instruction and side effects.
2341706f2543Smrg****************************************************************************/
2342706f2543Smrgvoid div_byte(u8 s)
2343706f2543Smrg{
2344706f2543Smrg	u32 dvd, div, mod;
2345706f2543Smrg
2346706f2543Smrg	dvd = M.x86.R_AX;
2347706f2543Smrg    if (s == 0) {
2348706f2543Smrg		x86emu_intr_raise(0);
2349706f2543Smrg        return;
2350706f2543Smrg    }
2351706f2543Smrg	div = dvd / (u8)s;
2352706f2543Smrg	mod = dvd % (u8)s;
2353706f2543Smrg	if (div > 0xff) {
2354706f2543Smrg		x86emu_intr_raise(0);
2355706f2543Smrg        return;
2356706f2543Smrg	}
2357706f2543Smrg	M.x86.R_AL = (u8)div;
2358706f2543Smrg	M.x86.R_AH = (u8)mod;
2359706f2543Smrg}
2360706f2543Smrg
2361706f2543Smrg/****************************************************************************
2362706f2543SmrgREMARKS:
2363706f2543SmrgImplements the DIV instruction and side effects.
2364706f2543Smrg****************************************************************************/
2365706f2543Smrgvoid div_word(u16 s)
2366706f2543Smrg{
2367706f2543Smrg	u32 dvd, div, mod;
2368706f2543Smrg
2369706f2543Smrg	dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX;
2370706f2543Smrg	if (s == 0) {
2371706f2543Smrg		x86emu_intr_raise(0);
2372706f2543Smrg        return;
2373706f2543Smrg    }
2374706f2543Smrg	div = dvd / (u16)s;
2375706f2543Smrg	mod = dvd % (u16)s;
2376706f2543Smrg	if (div > 0xffff) {
2377706f2543Smrg		x86emu_intr_raise(0);
2378706f2543Smrg		return;
2379706f2543Smrg	}
2380706f2543Smrg	CLEAR_FLAG(F_CF);
2381706f2543Smrg	CLEAR_FLAG(F_SF);
2382706f2543Smrg	CONDITIONAL_SET_FLAG(div == 0, F_ZF);
2383706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
2384706f2543Smrg
2385706f2543Smrg	M.x86.R_AX = (u16)div;
2386706f2543Smrg	M.x86.R_DX = (u16)mod;
2387706f2543Smrg}
2388706f2543Smrg
2389706f2543Smrg/****************************************************************************
2390706f2543SmrgREMARKS:
2391706f2543SmrgImplements the DIV instruction and side effects.
2392706f2543Smrg****************************************************************************/
2393706f2543Smrgvoid div_long(u32 s)
2394706f2543Smrg{
2395706f2543Smrg#ifdef	__HAS_LONG_LONG__
2396706f2543Smrg	u64 dvd, div, mod;
2397706f2543Smrg
2398706f2543Smrg	dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
2399706f2543Smrg	if (s == 0) {
2400706f2543Smrg		x86emu_intr_raise(0);
2401706f2543Smrg		return;
2402706f2543Smrg	}
2403706f2543Smrg	div = dvd / (u32)s;
2404706f2543Smrg	mod = dvd % (u32)s;
2405706f2543Smrg	if (abs(div) > 0xffffffff) {
2406706f2543Smrg		x86emu_intr_raise(0);
2407706f2543Smrg		return;
2408706f2543Smrg	}
2409706f2543Smrg#else
2410706f2543Smrg	s32 div = 0, mod;
2411706f2543Smrg	s32 h_dvd = M.x86.R_EDX;
2412706f2543Smrg	u32 l_dvd = M.x86.R_EAX;
2413706f2543Smrg
2414706f2543Smrg	u32 h_s = s;
2415706f2543Smrg	u32 l_s = 0;
2416706f2543Smrg	int counter = 32;
2417706f2543Smrg	int carry;
2418706f2543Smrg
2419706f2543Smrg	if (s == 0) {
2420706f2543Smrg		x86emu_intr_raise(0);
2421706f2543Smrg		return;
2422706f2543Smrg	}
2423706f2543Smrg	do {
2424706f2543Smrg		div <<= 1;
2425706f2543Smrg		carry = (l_dvd >= l_s) ? 0 : 1;
2426706f2543Smrg
2427706f2543Smrg		if (h_dvd < (h_s + carry)) {
2428706f2543Smrg			h_s >>= 1;
2429706f2543Smrg			l_s = s << (--counter);
2430706f2543Smrg			continue;
2431706f2543Smrg		} else {
2432706f2543Smrg			h_dvd -= (h_s + carry);
2433706f2543Smrg			l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
2434706f2543Smrg				: (l_dvd - l_s);
2435706f2543Smrg			h_s >>= 1;
2436706f2543Smrg			l_s = s << (--counter);
2437706f2543Smrg			div |= 1;
2438706f2543Smrg			continue;
2439706f2543Smrg		}
2440706f2543Smrg
2441706f2543Smrg	} while (counter > -1);
2442706f2543Smrg	/* overflow */
2443706f2543Smrg	if (h_dvd || (l_dvd > s)) {
2444706f2543Smrg		x86emu_intr_raise(0);
2445706f2543Smrg		return;
2446706f2543Smrg	}
2447706f2543Smrg	mod = l_dvd;
2448706f2543Smrg#endif
2449706f2543Smrg	CLEAR_FLAG(F_CF);
2450706f2543Smrg	CLEAR_FLAG(F_AF);
2451706f2543Smrg	CLEAR_FLAG(F_SF);
2452706f2543Smrg	SET_FLAG(F_ZF);
2453706f2543Smrg	CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
2454706f2543Smrg
2455706f2543Smrg	M.x86.R_EAX = (u32)div;
2456706f2543Smrg	M.x86.R_EDX = (u32)mod;
2457706f2543Smrg}
2458706f2543Smrg
2459706f2543Smrg/****************************************************************************
2460706f2543SmrgREMARKS:
2461706f2543SmrgImplements the IN string instruction and side effects.
2462706f2543Smrg****************************************************************************/
2463706f2543Smrgvoid ins(int size)
2464706f2543Smrg{
2465706f2543Smrg	int inc = size;
2466706f2543Smrg
2467706f2543Smrg	if (ACCESS_FLAG(F_DF)) {
2468706f2543Smrg		inc = -size;
2469706f2543Smrg	}
2470706f2543Smrg	if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2471706f2543Smrg        /* dont care whether REPE or REPNE */
2472706f2543Smrg        /* in until CX is ZERO. */
2473706f2543Smrg		u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
2474706f2543Smrg					 M.x86.R_ECX : M.x86.R_CX);
2475706f2543Smrg        switch (size) {
2476706f2543Smrg          case 1:
2477706f2543Smrg            while (count--) {
2478706f2543Smrg				store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
2479706f2543Smrg									(*sys_inb)(M.x86.R_DX));
2480706f2543Smrg				M.x86.R_DI += inc;
2481706f2543Smrg            }
2482706f2543Smrg            break;
2483706f2543Smrg
2484706f2543Smrg          case 2:
2485706f2543Smrg            while (count--) {
2486706f2543Smrg				store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
2487706f2543Smrg									(*sys_inw)(M.x86.R_DX));
2488706f2543Smrg				M.x86.R_DI += inc;
2489706f2543Smrg            }
2490706f2543Smrg            break;
2491706f2543Smrg          case 4:
2492706f2543Smrg            while (count--) {
2493706f2543Smrg				store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
2494706f2543Smrg									(*sys_inl)(M.x86.R_DX));
2495706f2543Smrg				M.x86.R_DI += inc;
2496706f2543Smrg                break;
2497706f2543Smrg            }
2498706f2543Smrg        }
2499706f2543Smrg		M.x86.R_CX = 0;
2500706f2543Smrg		if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2501706f2543Smrg			M.x86.R_ECX = 0;
2502706f2543Smrg        }
2503706f2543Smrg		M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2504706f2543Smrg    } else {
2505706f2543Smrg        switch (size) {
2506706f2543Smrg          case 1:
2507706f2543Smrg			store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
2508706f2543Smrg								(*sys_inb)(M.x86.R_DX));
2509706f2543Smrg            break;
2510706f2543Smrg          case 2:
2511706f2543Smrg			store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
2512706f2543Smrg								(*sys_inw)(M.x86.R_DX));
2513706f2543Smrg            break;
2514706f2543Smrg          case 4:
2515706f2543Smrg			store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
2516706f2543Smrg								(*sys_inl)(M.x86.R_DX));
2517706f2543Smrg            break;
2518706f2543Smrg        }
2519706f2543Smrg		M.x86.R_DI += inc;
2520706f2543Smrg    }
2521706f2543Smrg}
2522706f2543Smrg
2523706f2543Smrg/****************************************************************************
2524706f2543SmrgREMARKS:
2525706f2543SmrgImplements the OUT string instruction and side effects.
2526706f2543Smrg****************************************************************************/
2527706f2543Smrgvoid outs(int size)
2528706f2543Smrg{
2529706f2543Smrg    int inc = size;
2530706f2543Smrg
2531706f2543Smrg	if (ACCESS_FLAG(F_DF)) {
2532706f2543Smrg        inc = -size;
2533706f2543Smrg    }
2534706f2543Smrg	if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2535706f2543Smrg        /* dont care whether REPE or REPNE */
2536706f2543Smrg        /* out until CX is ZERO. */
2537706f2543Smrg		u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
2538706f2543Smrg					 M.x86.R_ECX : M.x86.R_CX);
2539706f2543Smrg        switch (size) {
2540706f2543Smrg          case 1:
2541706f2543Smrg            while (count--) {
2542706f2543Smrg				(*sys_outb)(M.x86.R_DX,
2543706f2543Smrg						 fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
2544706f2543Smrg				M.x86.R_SI += inc;
2545706f2543Smrg            }
2546706f2543Smrg            break;
2547706f2543Smrg
2548706f2543Smrg          case 2:
2549706f2543Smrg            while (count--) {
2550706f2543Smrg				(*sys_outw)(M.x86.R_DX,
2551706f2543Smrg						 fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
2552706f2543Smrg				M.x86.R_SI += inc;
2553706f2543Smrg            }
2554706f2543Smrg            break;
2555706f2543Smrg          case 4:
2556706f2543Smrg            while (count--) {
2557706f2543Smrg				(*sys_outl)(M.x86.R_DX,
2558706f2543Smrg						 fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
2559706f2543Smrg				M.x86.R_SI += inc;
2560706f2543Smrg                break;
2561706f2543Smrg            }
2562706f2543Smrg        }
2563706f2543Smrg		M.x86.R_CX = 0;
2564706f2543Smrg		if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2565706f2543Smrg			M.x86.R_ECX = 0;
2566706f2543Smrg        }
2567706f2543Smrg		M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2568706f2543Smrg    } else {
2569706f2543Smrg        switch (size) {
2570706f2543Smrg          case 1:
2571706f2543Smrg			(*sys_outb)(M.x86.R_DX,
2572706f2543Smrg					 fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
2573706f2543Smrg            break;
2574706f2543Smrg          case 2:
2575706f2543Smrg			(*sys_outw)(M.x86.R_DX,
2576706f2543Smrg					 fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
2577706f2543Smrg            break;
2578706f2543Smrg          case 4:
2579706f2543Smrg			(*sys_outl)(M.x86.R_DX,
2580706f2543Smrg					 fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
2581706f2543Smrg            break;
2582706f2543Smrg        }
2583706f2543Smrg		M.x86.R_SI += inc;
2584706f2543Smrg    }
2585706f2543Smrg}
2586706f2543Smrg
2587706f2543Smrg/****************************************************************************
2588706f2543SmrgPARAMETERS:
2589706f2543Smrgaddr	- Address to fetch word from
2590706f2543Smrg
2591706f2543SmrgREMARKS:
2592706f2543SmrgFetches a word from emulator memory using an absolute address.
2593706f2543Smrg****************************************************************************/
2594706f2543Smrgu16 mem_access_word(int addr)
2595706f2543Smrg{
2596706f2543SmrgDB(	if (CHECK_MEM_ACCESS())
2597706f2543Smrg	  x86emu_check_mem_access(addr);)
2598706f2543Smrg	return (*sys_rdw)(addr);
2599706f2543Smrg}
2600706f2543Smrg
2601706f2543Smrg/****************************************************************************
2602706f2543SmrgREMARKS:
2603706f2543SmrgPushes a word onto the stack.
2604706f2543Smrg
2605706f2543SmrgNOTE: Do not inline this, as (*sys_wrX) is already inline!
2606706f2543Smrg****************************************************************************/
2607706f2543Smrgvoid push_word(u16 w)
2608706f2543Smrg{
2609706f2543SmrgDB(	if (CHECK_SP_ACCESS())
2610706f2543Smrg	  x86emu_check_sp_access();)
2611706f2543Smrg	M.x86.R_SP -= 2;
2612706f2543Smrg	(*sys_wrw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w);
2613706f2543Smrg}
2614706f2543Smrg
2615706f2543Smrg/****************************************************************************
2616706f2543SmrgREMARKS:
2617706f2543SmrgPushes a long onto the stack.
2618706f2543Smrg
2619706f2543SmrgNOTE: Do not inline this, as (*sys_wrX) is already inline!
2620706f2543Smrg****************************************************************************/
2621706f2543Smrgvoid push_long(u32 w)
2622706f2543Smrg{
2623706f2543SmrgDB(	if (CHECK_SP_ACCESS())
2624706f2543Smrg	  x86emu_check_sp_access();)
2625706f2543Smrg	M.x86.R_SP -= 4;
2626706f2543Smrg	(*sys_wrl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w);
2627706f2543Smrg}
2628706f2543Smrg
2629706f2543Smrg/****************************************************************************
2630706f2543SmrgREMARKS:
2631706f2543SmrgPops a word from the stack.
2632706f2543Smrg
2633706f2543SmrgNOTE: Do not inline this, as (*sys_rdX) is already inline!
2634706f2543Smrg****************************************************************************/
2635706f2543Smrgu16 pop_word(void)
2636706f2543Smrg{
2637706f2543Smrg	register u16 res;
2638706f2543Smrg
2639706f2543SmrgDB(	if (CHECK_SP_ACCESS())
2640706f2543Smrg	  x86emu_check_sp_access();)
2641706f2543Smrg	res = (*sys_rdw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP);
2642706f2543Smrg	M.x86.R_SP += 2;
2643706f2543Smrg	return res;
2644706f2543Smrg}
2645706f2543Smrg
2646706f2543Smrg/****************************************************************************
2647706f2543SmrgREMARKS:
2648706f2543SmrgPops a long from the stack.
2649706f2543Smrg
2650706f2543SmrgNOTE: Do not inline this, as (*sys_rdX) is already inline!
2651706f2543Smrg****************************************************************************/
2652706f2543Smrgu32 pop_long(void)
2653706f2543Smrg{
2654706f2543Smrg    register u32 res;
2655706f2543Smrg
2656706f2543SmrgDB(	if (CHECK_SP_ACCESS())
2657706f2543Smrg	  x86emu_check_sp_access();)
2658706f2543Smrg	res = (*sys_rdl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP);
2659706f2543Smrg	M.x86.R_SP += 4;
2660706f2543Smrg    return res;
2661706f2543Smrg}
2662706f2543Smrg
2663706f2543Smrg/****************************************************************************
2664706f2543SmrgREMARKS:
2665706f2543SmrgCPUID takes EAX/ECX as inputs, writes EAX/EBX/ECX/EDX as output
2666706f2543Smrg****************************************************************************/
2667706f2543Smrgvoid cpuid (void)
2668706f2543Smrg{
2669706f2543Smrg    u32 feature = M.x86.R_EAX;
2670706f2543Smrg
2671706f2543Smrg#ifdef X86EMU_HAS_HW_CPUID
2672706f2543Smrg    /* If the platform allows it, we will base our values on the real
2673706f2543Smrg     * results from the CPUID instruction.  We limit support to the
2674706f2543Smrg     * first two features, and the results of those are sanitized.
2675706f2543Smrg     */
2676706f2543Smrg    if (feature <= 1)
2677706f2543Smrg	hw_cpuid(&M.x86.R_EAX, &M.x86.R_EBX, &M.x86.R_ECX, &M.x86.R_EDX);
2678706f2543Smrg#endif
2679706f2543Smrg
2680706f2543Smrg    switch (feature) {
2681706f2543Smrg    case 0:
2682706f2543Smrg        /* Regardless if we have real data from the hardware, the emulator
2683706f2543Smrg	 * will only support upto feature 1, which we set in register EAX.
2684706f2543Smrg	 * Registers EBX:EDX:ECX contain a string identifying the CPU.
2685706f2543Smrg	 */
2686706f2543Smrg        M.x86.R_EAX = 1;
2687706f2543Smrg#ifndef X86EMU_HAS_HW_CPUID
2688706f2543Smrg        /* EBX:EDX:ECX = "GenuineIntel" */
2689706f2543Smrg        M.x86.R_EBX = 0x756e6547;
2690706f2543Smrg        M.x86.R_EDX = 0x49656e69;
2691706f2543Smrg        M.x86.R_ECX = 0x6c65746e;
2692706f2543Smrg#endif
2693706f2543Smrg        break;
2694706f2543Smrg    case 1:
2695706f2543Smrg#ifndef X86EMU_HAS_HW_CPUID
2696706f2543Smrg        /* If we don't have x86 compatible hardware, we return values from an
2697706f2543Smrg	 * Intel 486dx4; which was one of the first processors to have CPUID.
2698706f2543Smrg	 */
2699706f2543Smrg        M.x86.R_EAX = 0x00000480;
2700706f2543Smrg        M.x86.R_EBX = 0x00000000;
2701706f2543Smrg        M.x86.R_ECX = 0x00000000;
2702706f2543Smrg        M.x86.R_EDX = 0x00000002;	/* VME */
2703706f2543Smrg#else
2704706f2543Smrg        /* In the case that we have hardware CPUID instruction, we make sure
2705706f2543Smrg	 * that the features reported are limited to TSC and VME.
2706706f2543Smrg	 */
2707706f2543Smrg        M.x86.R_EDX &= 0x00000012;
2708706f2543Smrg#endif
2709706f2543Smrg        break;
2710706f2543Smrg    default:
2711706f2543Smrg        /* Finally, we don't support any additional features.  Most CPUs
2712706f2543Smrg	 * return all zeros when queried for invalid or unsupported feature
2713706f2543Smrg	 * numbers.
2714706f2543Smrg	 */
2715706f2543Smrg        M.x86.R_EAX = 0;
2716706f2543Smrg        M.x86.R_EBX = 0;
2717706f2543Smrg        M.x86.R_ECX = 0;
2718706f2543Smrg        M.x86.R_EDX = 0;
2719706f2543Smrg        break;
2720706f2543Smrg    }
2721706f2543Smrg}
2722706f2543Smrg
2723