1 /////////////////////////////////////////////////////////////////////////
2 // $Id: shift16.cc,v 1.47 2008/08/08 09:22:48 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (C) 2001 MandrakeSoft S.A.
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 /////////////////////////////////////////////////////////////////////////
28 #define NEED_CPU_REG_SHORTCUTS 1
31 #define LOG_THIS BX_CPU_THIS_PTR
33 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwM(bxInstruction_c
*i
)
35 Bit16u op1_16
, op2_16
, result_16
;
36 Bit32u temp_32
, result_32
;
40 /* op1:op2 << count. result stored in op1 */
41 if (i
->b1() == 0xa4) // 0x1a4
46 count
&= 0x1f; // use only 5 LSB's
48 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
50 /* pointer, segment address pair */
51 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
55 op2_16
= BX_READ_16BIT_REG(i
->nnn());
57 /* count < 32, since only lower 5 bits used */
58 temp_32
= ((Bit32u
)(op1_16
) << 16) | (op2_16
); // double formed by op1:op2
59 result_32
= temp_32
<< count
;
61 // hack to act like x86 SHLD when count > 16
63 // when count > 16 actually shifting op1:op2:op2 << count,
64 // it is the same as shifting op2:op2 by count-16
65 result_32
|= (op1_16
<< (count
- 16));
68 result_16
= (Bit16u
)(result_32
>> 16);
70 write_RMW_virtual_word(result_16
);
72 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
74 cf
= (temp_32
>> (32 - count
)) & 0x1;
75 of
= cf
^ (result_16
>> 15); // of = cf ^ result15
76 SET_FLAGS_OxxxxC(of
, cf
);
79 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwR(bxInstruction_c
*i
)
81 Bit16u op1_16
, op2_16
, result_16
;
82 Bit32u temp_32
, result_32
;
86 /* op1:op2 << count. result stored in op1 */
87 if (i
->b1() == 0xa4) // 0x1a4
92 count
&= 0x1f; // use only 5 LSB's
96 op1_16
= BX_READ_16BIT_REG(i
->rm());
97 op2_16
= BX_READ_16BIT_REG(i
->nnn());
99 /* count < 32, since only lower 5 bits used */
100 temp_32
= ((Bit32u
)(op1_16
) << 16) | (op2_16
); // double formed by op1:op2
101 result_32
= temp_32
<< count
;
103 // hack to act like x86 SHLD when count > 16
105 // when count > 16 actually shifting op1:op2:op2 << count,
106 // it is the same as shifting op2:op2 by count-16
107 result_32
|= (op1_16
<< (count
- 16));
110 result_16
= (Bit16u
)(result_32
>> 16);
112 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
114 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
116 cf
= (temp_32
>> (32 - count
)) & 0x1;
117 of
= cf
^ (result_16
>> 15); // of = cf ^ result15
118 SET_FLAGS_OxxxxC(of
, cf
);
121 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwM(bxInstruction_c
*i
)
123 Bit16u op1_16
, op2_16
, result_16
;
124 Bit32u temp_32
, result_32
;
128 if (i
->b1() == 0xac) // 0x1ac
133 count
&= 0x1f; /* use only 5 LSB's */
135 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
137 /* pointer, segment address pair */
138 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
142 op2_16
= BX_READ_16BIT_REG(i
->nnn());
144 /* count < 32, since only lower 5 bits used */
145 temp_32
= (op2_16
<< 16) | op1_16
; // double formed by op2:op1
146 result_32
= temp_32
>> count
;
148 // hack to act like x86 SHRD when count > 16
150 // when count > 16 actually shifting op2:op2:op1 >> count,
151 // it is the same as shifting op2:op2 by count-16
152 result_32
|= (op1_16
<< (32 - count
));
155 result_16
= (Bit16u
) result_32
;
157 write_RMW_virtual_word(result_16
);
159 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
161 cf
= (op1_16
>> (count
- 1)) & 0x1;
162 of
= ((result_16
<< 1) ^ result_16
) >> 15; // of = result14 ^ result15
163 SET_FLAGS_OxxxxC(of
, cf
);
166 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwR(bxInstruction_c
*i
)
168 Bit16u op1_16
, op2_16
, result_16
;
169 Bit32u temp_32
, result_32
;
173 if (i
->b1() == 0xac) // 0x1ac
178 count
&= 0x1f; /* use only 5 LSB's */
182 op1_16
= BX_READ_16BIT_REG(i
->rm());
183 op2_16
= BX_READ_16BIT_REG(i
->nnn());
185 /* count < 32, since only lower 5 bits used */
186 temp_32
= (op2_16
<< 16) | op1_16
; // double formed by op2:op1
187 result_32
= temp_32
>> count
;
189 // hack to act like x86 SHRD when count > 16
191 // when count > 16 actually shifting op2:op2:op1 >> count,
192 // it is the same as shifting op2:op2 by count-16
193 result_32
|= (op1_16
<< (32 - count
));
196 result_16
= (Bit16u
) result_32
;
198 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
200 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
202 cf
= (op1_16
>> (count
- 1)) & 0x1;
203 of
= ((result_16
<< 1) ^ result_16
) >> 15; // of = result14 ^ result15
204 SET_FLAGS_OxxxxC(of
, cf
);
207 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_Ew(bxInstruction_c
*i
)
209 Bit16u op1_16
, result_16
;
211 unsigned bit0
, bit15
;
218 /* op1 is a register or memory reference */
220 op1_16
= BX_READ_16BIT_REG(i
->rm());
223 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
224 /* pointer, segment address pair */
225 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
228 if ((count
& 0x0f) == 0) {
230 bit0
= (op1_16
& 0x1);
231 bit15
= (op1_16
>> 15);
232 // of = cf ^ result15
233 SET_FLAGS_OxxxxC(bit0
^ bit15
, bit0
);
238 count
&= 0x0f; // only use bottom 4 bits
240 result_16
= (op1_16
<< count
) | (op1_16
>> (16 - count
));
242 /* now write result back to destination */
244 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
247 write_RMW_virtual_word(result_16
);
250 bit0
= (result_16
& 0x1);
251 bit15
= (result_16
>> 15);
252 // of = cf ^ result15
253 SET_FLAGS_OxxxxC(bit0
^ bit15
, bit0
);
256 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_Ew(bxInstruction_c
*i
)
258 Bit16u op1_16
, result_16
;
260 unsigned bit14
, bit15
;
267 /* op1 is a register or memory reference */
269 op1_16
= BX_READ_16BIT_REG(i
->rm());
272 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
273 /* pointer, segment address pair */
274 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
277 if ((count
& 0x0f) == 0) {
279 bit14
= (op1_16
>> 14) & 1;
280 bit15
= (op1_16
>> 15) & 1;
281 // of = result14 ^ result15
282 SET_FLAGS_OxxxxC(bit14
^ bit15
, bit15
);
287 count
&= 0x0f; // use only 4 LSB's
289 result_16
= (op1_16
>> count
) | (op1_16
<< (16 - count
));
291 /* now write result back to destination */
293 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
296 write_RMW_virtual_word(result_16
);
299 bit14
= (result_16
>> 14) & 1;
300 bit15
= (result_16
>> 15) & 1;
301 // of = result14 ^ result15
302 SET_FLAGS_OxxxxC(bit14
^ bit15
, bit15
);
305 void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_Ew(bxInstruction_c
*i
)
307 Bit16u op1_16
, result_16
;
316 count
= (count
& 0x1f) % 17;
318 /* op1 is a register or memory reference */
320 op1_16
= BX_READ_16BIT_REG(i
->rm());
323 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
324 /* pointer, segment address pair */
325 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
331 result_16
= (op1_16
<< 1) | getB_CF();
333 else if (count
==16) {
334 result_16
= (getB_CF() << 15) | (op1_16
>> 1);
337 result_16
= (op1_16
<< count
) | (getB_CF() << (count
- 1)) |
338 (op1_16
>> (17 - count
));
341 /* now write result back to destination */
343 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
346 write_RMW_virtual_word(result_16
);
349 cf
= (op1_16
>> (16 - count
)) & 0x1;
350 of
= cf
^ (result_16
>> 15); // of = cf ^ result15
351 SET_FLAGS_OxxxxC(of
, cf
);
354 void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_Ew(bxInstruction_c
*i
)
356 Bit16u op1_16
, result_16
;
365 count
= (count
& 0x1f) % 17;
367 /* op1 is a register or memory reference */
369 op1_16
= BX_READ_16BIT_REG(i
->rm());
372 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
373 /* pointer, segment address pair */
374 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
379 result_16
= (op1_16
>> count
) | (getB_CF() << (16 - count
)) |
380 (op1_16
<< (17 - count
));
382 /* now write result back to destination */
384 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
387 write_RMW_virtual_word(result_16
);
390 cf
= (op1_16
>> (count
- 1)) & 0x1;
391 of
= ((result_16
<< 1) ^ result_16
) >> 15; // of = result15 ^ result14
392 SET_FLAGS_OxxxxC(of
, cf
);
395 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_Ew(bxInstruction_c
*i
)
397 Bit16u op1_16
, result_16
;
399 unsigned of
= 0, cf
= 0;
406 count
&= 0x1f; /* use only 5 LSB's */
408 /* op1 is a register or memory reference */
410 op1_16
= BX_READ_16BIT_REG(i
->rm());
413 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
414 /* pointer, segment address pair */
415 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
421 result_16
= (op1_16
<< count
);
422 cf
= (op1_16
>> (16 - count
)) & 0x1;
423 of
= cf
^ (result_16
>> 15); // of = cf ^ result15
429 /* now write result back to destination */
431 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
434 write_RMW_virtual_word(result_16
);
437 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
438 SET_FLAGS_OxxxxC(of
, cf
);
441 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_Ew(bxInstruction_c
*i
)
443 Bit16u op1_16
, result_16
;
452 count
&= 0x1f; /* use only 5 LSB's */
454 /* op1 is a register or memory reference */
456 op1_16
= BX_READ_16BIT_REG(i
->rm());
459 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
460 /* pointer, segment address pair */
461 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
466 result_16
= (op1_16
>> count
);
468 /* now write result back to destination */
470 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
473 write_RMW_virtual_word(result_16
);
476 cf
= (op1_16
>> (count
- 1)) & 0x1;
477 // note, that of == result15 if count == 1 and
478 // of == 0 if count >= 2
479 of
= ((result_16
<< 1) ^ result_16
) >> 15;
481 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
482 SET_FLAGS_OxxxxC(of
, cf
);
485 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_Ew(bxInstruction_c
*i
)
487 Bit16u op1_16
, result_16
;
495 count
&= 0x1f; /* use only 5 LSB's */
497 /* op1 is a register or memory reference */
499 op1_16
= BX_READ_16BIT_REG(i
->rm());
502 bx_address eaddr
= BX_CPU_CALL_METHODR(i
->ResolveModrm
, (i
));
503 /* pointer, segment address pair */
504 op1_16
= read_RMW_virtual_word(i
->seg(), eaddr
);
510 if (op1_16
& 0x8000) {
511 result_16
= (op1_16
>> count
) | (0xffff << (16 - count
));
514 result_16
= (op1_16
>> count
);
517 cf
= (op1_16
>> (count
- 1)) & 0x1;
520 if (op1_16
& 0x8000) {
527 cf
= (result_16
& 0x1);
530 SET_FLAGS_OSZAPC_LOGIC_16(result_16
); /* handle SF, ZF and AF flags */
531 /* signed overflow cannot happen in SAR instruction */
532 SET_FLAGS_OxxxxC(0, cf
);
534 /* now write result back to destination */
536 BX_WRITE_16BIT_REG(i
->rm(), result_16
);
539 write_RMW_virtual_word(result_16
);