1 /////////////////////////////////////////////////////////////////////////
2 // $Id: arith32.cc,v 1.50 2007/01/26 22:12:05 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
29 #define NEED_CPU_REG_SHORTCUTS 1
32 #define LOG_THIS BX_CPU_THIS_PTR
35 #if BX_SUPPORT_X86_64==0
36 // Make life easier for merging cpu64 and cpu code.
42 void BX_CPU_C::INC_ERX(bxInstruction_c
*i
)
44 unsigned opcodeReg
= i
->opcodeReg();
46 #if defined(BX_HostAsm_Inc32)
48 asmInc32(BX_CPU_THIS_PTR gen_reg
[opcodeReg
].dword
.erx
, flags32
);
49 setEFlagsOSZAP(flags32
);
51 Bit32u erx
= ++ BX_CPU_THIS_PTR gen_reg
[opcodeReg
].dword
.erx
;
52 SET_FLAGS_OSZAP_RESULT_32(erx
, BX_INSTR_INC32
);
55 BX_CLEAR_64BIT_HIGH(opcodeReg
);
58 void BX_CPU_C::DEC_ERX(bxInstruction_c
*i
)
60 unsigned opcodeReg
= i
->opcodeReg();
62 #if defined(BX_HostAsm_Dec32)
64 asmDec32(BX_CPU_THIS_PTR gen_reg
[opcodeReg
].dword
.erx
, flags32
);
65 setEFlagsOSZAP(flags32
);
67 Bit32u erx
= -- BX_CPU_THIS_PTR gen_reg
[opcodeReg
].dword
.erx
;
68 SET_FLAGS_OSZAP_RESULT_32(erx
, BX_INSTR_DEC32
);
71 BX_CLEAR_64BIT_HIGH(opcodeReg
);
74 void BX_CPU_C::ADD_EdGd(bxInstruction_c
*i
)
76 Bit32u op2_32
, op1_32
, sum_32
;
78 op2_32
= BX_READ_32BIT_REG(i
->nnn());
81 op1_32
= BX_READ_32BIT_REG(i
->rm());
82 sum_32
= op1_32
+ op2_32
;
83 BX_WRITE_32BIT_REGZ(i
->rm(), sum_32
);
86 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
87 sum_32
= op1_32
+ op2_32
;
88 write_RMW_virtual_dword(sum_32
);
91 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
94 void BX_CPU_C::ADD_GdEEd(bxInstruction_c
*i
)
96 Bit32u op1_32
, op2_32
, sum_32
;
97 unsigned nnn
= i
->nnn();
99 op1_32
= BX_READ_32BIT_REG(nnn
);
101 read_virtual_dword(i
->seg(), RMAddr(i
), &op2_32
);
103 #if defined(BX_HostAsm_Add32)
105 asmAdd32(sum_32
, op1_32
, op2_32
, flags32
);
106 setEFlagsOSZAPC(flags32
);
108 sum_32
= op1_32
+ op2_32
;
109 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
112 BX_WRITE_32BIT_REGZ(nnn
, sum_32
);
115 void BX_CPU_C::ADD_GdEGd(bxInstruction_c
*i
)
117 Bit32u op1_32
, op2_32
, sum_32
;
118 unsigned nnn
= i
->nnn();
120 op1_32
= BX_READ_32BIT_REG(nnn
);
121 op2_32
= BX_READ_32BIT_REG(i
->rm());
123 #if defined(BX_HostAsm_Add32)
125 asmAdd32(sum_32
, op1_32
, op2_32
, flags32
);
126 setEFlagsOSZAPC(flags32
);
128 sum_32
= op1_32
+ op2_32
;
129 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
132 BX_WRITE_32BIT_REGZ(nnn
, sum_32
);
135 void BX_CPU_C::ADD_EAXId(bxInstruction_c
*i
)
137 Bit32u op1_32
, op2_32
, sum_32
;
141 sum_32
= op1_32
+ op2_32
;
145 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
148 void BX_CPU_C::ADC_EdGd(bxInstruction_c
*i
)
150 bx_bool temp_CF
= getB_CF();
152 Bit32u op2_32
, op1_32
, sum_32
;
154 op2_32
= BX_READ_32BIT_REG(i
->nnn());
157 op1_32
= BX_READ_32BIT_REG(i
->rm());
158 sum_32
= op1_32
+ op2_32
+ temp_CF
;
159 BX_WRITE_32BIT_REGZ(i
->rm(), sum_32
);
162 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
163 sum_32
= op1_32
+ op2_32
+ temp_CF
;
164 write_RMW_virtual_dword(sum_32
);
167 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD_ADC32(temp_CF
));
170 void BX_CPU_C::ADC_GdEd(bxInstruction_c
*i
)
172 bx_bool temp_CF
= getB_CF();
174 Bit32u op1_32
, op2_32
, sum_32
;
176 op1_32
= BX_READ_32BIT_REG(i
->nnn());
179 op2_32
= BX_READ_32BIT_REG(i
->rm());
182 read_virtual_dword(i
->seg(), RMAddr(i
), &op2_32
);
185 sum_32
= op1_32
+ op2_32
+ temp_CF
;
187 BX_WRITE_32BIT_REGZ(i
->nnn(), sum_32
);
189 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD_ADC32(temp_CF
));
192 void BX_CPU_C::ADC_EAXId(bxInstruction_c
*i
)
194 bx_bool temp_CF
= getB_CF();
196 Bit32u op1_32
, op2_32
, sum_32
;
200 sum_32
= op1_32
+ op2_32
+ temp_CF
;
204 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD_ADC32(temp_CF
));
207 void BX_CPU_C::SBB_EdGd(bxInstruction_c
*i
)
209 bx_bool temp_CF
= getB_CF();
211 Bit32u op2_32
, op1_32
, diff_32
;
213 op2_32
= BX_READ_32BIT_REG(i
->nnn());
216 op1_32
= BX_READ_32BIT_REG(i
->rm());
217 diff_32
= op1_32
- (op2_32
+ temp_CF
);
218 BX_WRITE_32BIT_REGZ(i
->rm(), diff_32
);
221 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
222 diff_32
= op1_32
- (op2_32
+ temp_CF
);
223 write_RMW_virtual_dword(diff_32
);
226 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB_SBB32(temp_CF
));
229 void BX_CPU_C::SBB_GdEd(bxInstruction_c
*i
)
231 bx_bool temp_CF
= getB_CF();
233 Bit32u op1_32
, op2_32
, diff_32
;
235 op1_32
= BX_READ_32BIT_REG(i
->nnn());
238 op2_32
= BX_READ_32BIT_REG(i
->rm());
241 read_virtual_dword(i
->seg(), RMAddr(i
), &op2_32
);
244 diff_32
= op1_32
- (op2_32
+ temp_CF
);
246 BX_WRITE_32BIT_REGZ(i
->nnn(), diff_32
);
248 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB_SBB32(temp_CF
));
251 void BX_CPU_C::SBB_EAXId(bxInstruction_c
*i
)
253 bx_bool temp_CF
= getB_CF();
255 Bit32u op1_32
, op2_32
, diff_32
;
259 diff_32
= op1_32
- (op2_32
+ temp_CF
);
263 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB_SBB32(temp_CF
));
266 void BX_CPU_C::SBB_EdId(bxInstruction_c
*i
)
268 bx_bool temp_CF
= getB_CF();
270 Bit32u op2_32
, op1_32
, diff_32
;
275 op1_32
= BX_READ_32BIT_REG(i
->rm());
276 diff_32
= op1_32
- (op2_32
+ temp_CF
);
277 BX_WRITE_32BIT_REGZ(i
->rm(), diff_32
);
280 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
281 diff_32
= op1_32
- (op2_32
+ temp_CF
);
282 write_RMW_virtual_dword(diff_32
);
285 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB_SBB32(temp_CF
));
288 void BX_CPU_C::SUB_EdGd(bxInstruction_c
*i
)
290 Bit32u op2_32
, op1_32
, diff_32
;
292 op2_32
= BX_READ_32BIT_REG(i
->nnn());
295 op1_32
= BX_READ_32BIT_REG(i
->rm());
296 diff_32
= op1_32
- op2_32
;
297 BX_WRITE_32BIT_REGZ(i
->rm(), diff_32
);
300 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
301 diff_32
= op1_32
- op2_32
;
302 write_RMW_virtual_dword(diff_32
);
305 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB32
);
308 void BX_CPU_C::SUB_GdEd(bxInstruction_c
*i
)
310 Bit32u op1_32
, op2_32
, diff_32
;
311 unsigned nnn
= i
->nnn();
313 op1_32
= BX_READ_32BIT_REG(nnn
);
316 op2_32
= BX_READ_32BIT_REG(i
->rm());
319 read_virtual_dword(i
->seg(), RMAddr(i
), &op2_32
);
322 #if defined(BX_HostAsm_Sub32)
324 asmSub32(diff_32
, op1_32
, op2_32
, flags32
);
325 setEFlagsOSZAPC(flags32
);
327 diff_32
= op1_32
- op2_32
;
328 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB32
);
331 BX_WRITE_32BIT_REGZ(nnn
, diff_32
);
334 void BX_CPU_C::SUB_EAXId(bxInstruction_c
*i
)
336 Bit32u op1_32
, op2_32
, diff_32
;
340 diff_32
= op1_32
- op2_32
;
344 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB32
);
347 void BX_CPU_C::CMP_EdGd(bxInstruction_c
*i
)
349 Bit32u op2_32
, op1_32
;
351 op2_32
= BX_READ_32BIT_REG(i
->nnn());
354 op1_32
= BX_READ_32BIT_REG(i
->rm());
357 read_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
360 #if defined(BX_HostAsm_Cmp32)
362 asmCmp32(op1_32
, op2_32
, flags32
);
363 setEFlagsOSZAPC(flags32
);
365 Bit32u diff_32
= op1_32
- op2_32
;
366 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_COMPARE32
);
370 void BX_CPU_C::CMP_GdEd(bxInstruction_c
*i
)
372 Bit32u op1_32
, op2_32
;
374 op1_32
= BX_READ_32BIT_REG(i
->nnn());
377 op2_32
= BX_READ_32BIT_REG(i
->rm());
380 read_virtual_dword(i
->seg(), RMAddr(i
), &op2_32
);
383 #if defined(BX_HostAsm_Cmp32)
385 asmCmp32(op1_32
, op2_32
, flags32
);
386 setEFlagsOSZAPC(flags32
);
388 Bit32u diff_32
= op1_32
- op2_32
;
389 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_COMPARE32
);
393 void BX_CPU_C::CMP_EAXId(bxInstruction_c
*i
)
395 Bit32u op1_32
, op2_32
;
400 #if defined(BX_HostAsm_Cmp32)
402 asmCmp32(op1_32
, op2_32
, flags32
);
403 setEFlagsOSZAPC(flags32
);
405 Bit32u diff_32
= op1_32
- op2_32
;
406 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_COMPARE32
);
410 void BX_CPU_C::CWDE(bxInstruction_c
*i
)
412 /* CWDE: no flags are effected */
413 Bit32u tmp
= (Bit16s
) AX
;
417 void BX_CPU_C::CDQ(bxInstruction_c
*i
)
419 /* CDQ: no flags are affected */
420 if (EAX
& 0x80000000) {
428 // Some info on the opcodes at {0F,A6} and {0F,A7}
429 // On 386 steps A0-B0:
432 // On 486 steps A0-B0:
433 // {OF,A6} = CMPXCHG 8
434 // {OF,A7} = CMPXCHG 16|32
436 // On 486 >= B steps, and further processors, the
437 // CMPXCHG instructions were moved to opcodes:
438 // {OF,B0} = CMPXCHG 8
439 // {OF,B1} = CMPXCHG 16|32
441 void BX_CPU_C::CMPXCHG_XBTS(bxInstruction_c
*i
)
443 BX_INFO(("CMPXCHG_XBTS: Generate #UD exception"));
447 void BX_CPU_C::CMPXCHG_IBTS(bxInstruction_c
*i
)
449 BX_INFO(("CMPXCHG_IBTS: Generate #UD exception"));
453 void BX_CPU_C::XADD_EdGd(bxInstruction_c
*i
)
455 #if (BX_CPU_LEVEL >= 4) || (BX_CPU_LEVEL_HACKED >= 4)
457 Bit32u op2_32
, op1_32
, sum_32
;
459 /* XADD dst(r/m), src(r)
460 * temp <-- src + dst | sum = op2 + op1
461 * src <-- dst | op2 = op1
462 * dst <-- tmp | op1 = sum
465 op2_32
= BX_READ_32BIT_REG(i
->nnn());
468 op1_32
= BX_READ_32BIT_REG(i
->rm());
469 sum_32
= op1_32
+ op2_32
;
470 // and write destination into source
471 // Note: if both op1 & op2 are registers, the last one written
472 // should be the sum, as op1 & op2 may be the same register.
473 // For example: XADD AL, AL
474 BX_WRITE_32BIT_REGZ(i
->nnn(), op1_32
);
475 BX_WRITE_32BIT_REGZ(i
->rm(), sum_32
);
478 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
479 sum_32
= op1_32
+ op2_32
;
480 write_RMW_virtual_dword(sum_32
);
481 /* and write destination into source */
482 BX_WRITE_32BIT_REGZ(i
->nnn(), op1_32
);
485 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
487 BX_INFO (("XADD_EdGd not supported for cpulevel <= 3"));
492 void BX_CPU_C::ADD_EEdId(bxInstruction_c
*i
)
494 Bit32u op2_32
, op1_32
, sum_32
;
498 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
500 #if defined(BX_HostAsm_Add32)
502 asmAdd32(sum_32
, op1_32
, op2_32
, flags32
);
503 setEFlagsOSZAPC(flags32
);
505 sum_32
= op1_32
+ op2_32
;
506 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
509 write_RMW_virtual_dword(sum_32
);
512 void BX_CPU_C::ADD_EGdId(bxInstruction_c
*i
)
514 Bit32u op2_32
, op1_32
, sum_32
;
517 op1_32
= BX_READ_32BIT_REG(i
->rm());
519 #if defined(BX_HostAsm_Add32)
521 asmAdd32(sum_32
, op1_32
, op2_32
, flags32
);
522 setEFlagsOSZAPC(flags32
);
524 sum_32
= op1_32
+ op2_32
;
525 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD32
);
528 BX_WRITE_32BIT_REGZ(i
->rm(), sum_32
);
531 void BX_CPU_C::ADC_EdId(bxInstruction_c
*i
)
533 bx_bool temp_CF
= getB_CF();
535 Bit32u op2_32
, op1_32
, sum_32
;
540 op1_32
= BX_READ_32BIT_REG(i
->rm());
541 sum_32
= op1_32
+ op2_32
+ temp_CF
;
542 BX_WRITE_32BIT_REGZ(i
->rm(), sum_32
);
545 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
546 sum_32
= op1_32
+ op2_32
+ temp_CF
;
547 write_RMW_virtual_dword(sum_32
);
550 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, sum_32
, BX_INSTR_ADD_ADC32(temp_CF
));
553 void BX_CPU_C::SUB_EdId(bxInstruction_c
*i
)
555 Bit32u op2_32
, op1_32
, diff_32
;
560 op1_32
= BX_READ_32BIT_REG(i
->rm());
561 diff_32
= op1_32
- op2_32
;
562 BX_WRITE_32BIT_REGZ(i
->rm(), diff_32
);
565 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
566 diff_32
= op1_32
- op2_32
;
567 write_RMW_virtual_dword(diff_32
);
570 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_SUB32
);
573 void BX_CPU_C::CMP_EdId(bxInstruction_c
*i
)
575 Bit32u op2_32
, op1_32
;
580 op1_32
= BX_READ_32BIT_REG(i
->rm());
583 read_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
586 #if defined(BX_HostAsm_Cmp32)
588 asmCmp32(op1_32
, op2_32
, flags32
);
589 setEFlagsOSZAPC(flags32
);
592 diff_32
= op1_32
- op2_32
;
593 SET_FLAGS_OSZAPC_32(op1_32
, op2_32
, diff_32
, BX_INSTR_COMPARE32
);
597 void BX_CPU_C::NEG_Ed(bxInstruction_c
*i
)
599 Bit32u op1_32
, diff_32
;
602 op1_32
= BX_READ_32BIT_REG(i
->rm());
604 BX_WRITE_32BIT_REGZ(i
->rm(), diff_32
);
607 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
609 write_RMW_virtual_dword(diff_32
);
612 SET_FLAGS_OSZAPC_RESULT_32(diff_32
, BX_INSTR_NEG32
);
615 void BX_CPU_C::INC_Ed(bxInstruction_c
*i
)
620 op1_32
= BX_READ_32BIT_REG(i
->rm());
622 BX_WRITE_32BIT_REGZ(i
->rm(), op1_32
);
625 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
627 write_RMW_virtual_dword(op1_32
);
630 SET_FLAGS_OSZAP_RESULT_32(op1_32
, BX_INSTR_INC32
);
633 void BX_CPU_C::DEC_Ed(bxInstruction_c
*i
)
638 op1_32
= BX_READ_32BIT_REG(i
->rm());
640 BX_WRITE_32BIT_REGZ(i
->rm(), op1_32
);
643 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
645 write_RMW_virtual_dword(op1_32
);
648 SET_FLAGS_OSZAP_RESULT_32(op1_32
, BX_INSTR_DEC32
);
651 void BX_CPU_C::CMPXCHG_EdGd(bxInstruction_c
*i
)
653 #if (BX_CPU_LEVEL >= 4) || (BX_CPU_LEVEL_HACKED >= 4)
654 Bit32u op2_32
, op1_32
, diff_32
;
657 op1_32
= BX_READ_32BIT_REG(i
->rm());
660 read_RMW_virtual_dword(i
->seg(), RMAddr(i
), &op1_32
);
663 diff_32
= EAX
- op1_32
;
665 SET_FLAGS_OSZAPC_32(EAX
, op1_32
, diff_32
, BX_INSTR_COMPARE32
);
667 if (diff_32
== 0) { // if accumulator == dest
669 op2_32
= BX_READ_32BIT_REG(i
->nnn());
672 BX_WRITE_32BIT_REGZ(i
->rm(), op2_32
);
675 write_RMW_virtual_dword(op2_32
);
679 // accumulator <-- dest
683 BX_INFO(("CMPXCHG_EdGd: not supported for cpulevel <= 3"));
688 void BX_CPU_C::CMPXCHG8B(bxInstruction_c
*i
)
690 #if (BX_CPU_LEVEL >= 5) || (BX_CPU_LEVEL_HACKED >= 5)
691 Bit32u op1_64_lo
, op1_64_hi
, diff
;
694 BX_INFO(("CMPXCHG8B: dest is not memory location (#UD)"));
698 read_virtual_dword(i
->seg(), RMAddr(i
), &op1_64_lo
);
699 read_RMW_virtual_dword(i
->seg(), RMAddr(i
) + 4, &op1_64_hi
);
701 diff
= EAX
- op1_64_lo
;
702 diff
|= EDX
- op1_64_hi
;
704 if (diff
== 0) { // if accumulator == dest
708 write_RMW_virtual_dword(ECX
);
709 write_virtual_dword(i
->seg(), RMAddr(i
), &EBX
);
714 // accumulator <-- dest
720 BX_INFO(("CMPXCHG8B: not supported for cpulevel <= 4"));