- update sector count before calling write completion function (SF patch #2144692)
[bochs-mirror.git] / cpu / arith64.cc
blob10b7f6900d4da22362f2816a305bbea2424e515c
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: arith64.cc,v 1.57 2008/09/05 21:43:12 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
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
29 #include "bochs.h"
30 #include "cpu.h"
31 #define LOG_THIS BX_CPU_THIS_PTR
33 #if BX_SUPPORT_X86_64
35 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqGqM(bxInstruction_c *i)
37 Bit64u op1_64, op2_64, sum_64;
39 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
41 /* pointer, segment address pair */
42 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
43 op2_64 = BX_READ_64BIT_REG(i->nnn());
44 sum_64 = op1_64 + op2_64;
45 write_RMW_virtual_qword(sum_64);
47 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
50 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GqEqR(bxInstruction_c *i)
52 Bit64u op1_64, op2_64, sum_64;
54 op1_64 = BX_READ_64BIT_REG(i->nnn());
55 op2_64 = BX_READ_64BIT_REG(i->rm());
56 sum_64 = op1_64 + op2_64;
57 BX_WRITE_64BIT_REG(i->nnn(), sum_64);
59 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
62 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_RAXId(bxInstruction_c *i)
64 Bit64u op1_64, op2_64, sum_64;
66 op1_64 = RAX;
67 op2_64 = (Bit32s) i->Id();
68 sum_64 = op1_64 + op2_64;
70 /* now write sum back to destination */
71 RAX = sum_64;
73 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
76 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqGqM(bxInstruction_c *i)
78 bx_bool temp_CF = getB_CF();
80 Bit64u op1_64, op2_64, sum_64;
82 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
84 /* pointer, segment address pair */
85 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
86 op2_64 = BX_READ_64BIT_REG(i->nnn());
87 sum_64 = op1_64 + op2_64 + temp_CF;
88 write_RMW_virtual_qword(sum_64);
90 SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
93 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GqEqR(bxInstruction_c *i)
95 bx_bool temp_CF = getB_CF();
97 Bit64u op1_64, op2_64, sum_64;
99 op1_64 = BX_READ_64BIT_REG(i->nnn());
100 op2_64 = BX_READ_64BIT_REG(i->rm());
101 sum_64 = op1_64 + op2_64 + temp_CF;
103 /* now write sum back to destination */
104 BX_WRITE_64BIT_REG(i->nnn(), sum_64);
106 SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
109 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_RAXId(bxInstruction_c *i)
111 bx_bool temp_CF = getB_CF();
113 Bit64u op1_64, op2_64, sum_64;
115 op1_64 = RAX;
116 op2_64 = (Bit32s) i->Id();
117 sum_64 = op1_64 + op2_64 + temp_CF;
119 /* now write sum back to destination */
120 RAX = sum_64;
122 SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
125 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqGqM(bxInstruction_c *i)
127 bx_bool temp_CF = getB_CF();
129 Bit64u op1_64, op2_64, diff_64;
131 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
133 /* pointer, segment address pair */
134 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
135 op2_64 = BX_READ_64BIT_REG(i->nnn());
136 diff_64 = op1_64 - (op2_64 + temp_CF);
137 write_RMW_virtual_qword(diff_64);
139 SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
142 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GqEqR(bxInstruction_c *i)
144 bx_bool temp_CF = getB_CF();
146 Bit64u op1_64, op2_64, diff_64;
148 op1_64 = BX_READ_64BIT_REG(i->nnn());
149 op2_64 = BX_READ_64BIT_REG(i->rm());
150 diff_64 = op1_64 - (op2_64 + temp_CF);
152 /* now write diff back to destination */
153 BX_WRITE_64BIT_REG(i->nnn(), diff_64);
155 SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
158 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_RAXId(bxInstruction_c *i)
160 bx_bool temp_CF = getB_CF();
162 Bit64u op1_64, op2_64, diff_64;
164 op1_64 = RAX;
165 op2_64 = (Bit32s) i->Id();
166 diff_64 = op1_64 - (op2_64 + temp_CF);
168 /* now write diff back to destination */
169 RAX = diff_64;
171 SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
174 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdM(bxInstruction_c *i)
176 bx_bool temp_CF = getB_CF();
178 Bit64u op1_64, op2_64, diff_64;
180 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
182 /* pointer, segment address pair */
183 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
184 op2_64 = (Bit32s) i->Id();
185 diff_64 = op1_64 - (op2_64 + temp_CF);
186 write_RMW_virtual_qword(diff_64);
188 SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
191 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdR(bxInstruction_c *i)
193 bx_bool temp_CF = getB_CF();
195 Bit64u op1_64, op2_64, diff_64;
197 op1_64 = BX_READ_64BIT_REG(i->rm());
198 op2_64 = (Bit32s) i->Id();
199 diff_64 = op1_64 - (op2_64 + temp_CF);
200 BX_WRITE_64BIT_REG(i->rm(), diff_64);
202 SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
205 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqGqM(bxInstruction_c *i)
207 Bit64u op1_64, op2_64, diff_64;
209 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
211 /* pointer, segment address pair */
212 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
213 op2_64 = BX_READ_64BIT_REG(i->nnn());
214 diff_64 = op1_64 - op2_64;
215 write_RMW_virtual_qword(diff_64);
217 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
220 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GqEqR(bxInstruction_c *i)
222 Bit64u op1_64, op2_64, diff_64;
224 op1_64 = BX_READ_64BIT_REG(i->nnn());
225 op2_64 = BX_READ_64BIT_REG(i->rm());
226 diff_64 = op1_64 - op2_64;
228 /* now write diff back to destination */
229 BX_WRITE_64BIT_REG(i->nnn(), diff_64);
231 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
234 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_RAXId(bxInstruction_c *i)
236 Bit64u op1_64, op2_64, diff_64;
238 op1_64 = RAX;
239 op2_64 = (Bit32s) i->Id();
240 diff_64 = op1_64 - op2_64;
242 /* now write diff back to destination */
243 RAX = diff_64;
245 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
248 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqGqM(bxInstruction_c *i)
250 Bit64u op1_64, op2_64, diff_64;
252 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
254 op1_64 = read_virtual_qword_64(i->seg(), eaddr);
255 op2_64 = BX_READ_64BIT_REG(i->nnn());
256 diff_64 = op1_64 - op2_64;
258 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
261 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GqEqR(bxInstruction_c *i)
263 Bit64u op1_64, op2_64, diff_64;
265 op1_64 = BX_READ_64BIT_REG(i->nnn());
266 op2_64 = BX_READ_64BIT_REG(i->rm());
267 diff_64 = op1_64 - op2_64;
269 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
272 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_RAXId(bxInstruction_c *i)
274 Bit64u op1_64, op2_64, diff_64;
276 op1_64 = RAX;
277 op2_64 = (Bit32s) i->Id();
278 diff_64 = op1_64 - op2_64;
280 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
283 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CDQE(bxInstruction_c *i)
285 /* CWDE: no flags are affected */
286 RAX = (Bit32s) EAX;
289 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CQO(bxInstruction_c *i)
291 /* CQO: no flags are affected */
293 if (RAX & BX_CONST64(0x8000000000000000))
294 RDX = BX_CONST64(0xffffffffffffffff);
295 else
296 RDX = 0;
299 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqM(bxInstruction_c *i)
301 Bit64u op1_64, op2_64, sum_64;
303 /* XADD dst(r/m), src(r)
304 * temp <-- src + dst | sum = op2 + op1
305 * src <-- dst | op2 = op1
306 * dst <-- tmp | op1 = sum
309 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
311 /* pointer, segment address pair */
312 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
313 op2_64 = BX_READ_64BIT_REG(i->nnn());
314 sum_64 = op1_64 + op2_64;
315 write_RMW_virtual_qword(sum_64);
317 /* and write destination into source */
318 BX_WRITE_64BIT_REG(i->nnn(), op1_64);
320 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
323 void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqR(bxInstruction_c *i)
325 Bit64u op1_64, op2_64, sum_64;
327 /* XADD dst(r/m), src(r)
328 * temp <-- src + dst | sum = op2 + op1
329 * src <-- dst | op2 = op1
330 * dst <-- tmp | op1 = sum
333 op1_64 = BX_READ_64BIT_REG(i->rm());
334 op2_64 = BX_READ_64BIT_REG(i->nnn());
335 sum_64 = op1_64 + op2_64;
337 // and write destination into source
338 // Note: if both op1 & op2 are registers, the last one written
339 // should be the sum, as op1 & op2 may be the same register.
340 // For example: XADD AL, AL
341 BX_WRITE_64BIT_REG(i->nnn(), op1_64);
342 BX_WRITE_64BIT_REG(i->rm(), sum_64);
344 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
347 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdM(bxInstruction_c *i)
349 Bit64u op1_64, op2_64, sum_64;
351 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
353 /* pointer, segment address pair */
354 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
355 op2_64 = (Bit32s) i->Id();
356 sum_64 = op1_64 + op2_64;
357 write_RMW_virtual_qword(sum_64);
359 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
362 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdR(bxInstruction_c *i)
364 Bit64u op1_64, op2_64, sum_64;
366 op1_64 = BX_READ_64BIT_REG(i->rm());
367 op2_64 = (Bit32s) i->Id();
368 sum_64 = op1_64 + op2_64;
369 BX_WRITE_64BIT_REG(i->rm(), sum_64);
371 SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
374 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdM(bxInstruction_c *i)
376 bx_bool temp_CF = getB_CF();
378 Bit64u op1_64, op2_64, sum_64;
380 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
382 /* pointer, segment address pair */
383 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
384 op2_64 = (Bit32s) i->Id();
385 sum_64 = op1_64 + op2_64 + temp_CF;
386 write_RMW_virtual_qword(sum_64);
388 SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
391 void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdR(bxInstruction_c *i)
393 bx_bool temp_CF = getB_CF();
395 Bit64u op1_64, op2_64, sum_64;
397 op1_64 = BX_READ_64BIT_REG(i->rm());
398 op2_64 = (Bit32s) i->Id();
399 sum_64 = op1_64 + op2_64 + temp_CF;
400 BX_WRITE_64BIT_REG(i->rm(), sum_64);
402 SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
405 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdM(bxInstruction_c *i)
407 Bit64u op1_64, op2_64, diff_64;
409 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
411 /* pointer, segment address pair */
412 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
413 op2_64 = (Bit32s) i->Id();
414 diff_64 = op1_64 - op2_64;
415 write_RMW_virtual_qword(diff_64);
417 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
420 void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdR(bxInstruction_c *i)
422 Bit64u op1_64, op2_64, diff_64;
424 op1_64 = BX_READ_64BIT_REG(i->rm());
425 op2_64 = (Bit32s) i->Id();
426 diff_64 = op1_64 - op2_64;
427 BX_WRITE_64BIT_REG(i->rm(), diff_64);
429 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
432 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdM(bxInstruction_c *i)
434 Bit64u op1_64, op2_64, diff_64;
436 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
438 op1_64 = read_virtual_qword_64(i->seg(), eaddr);
439 op2_64 = (Bit32s) i->Id();
440 diff_64 = op1_64 - op2_64;
442 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
445 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdR(bxInstruction_c *i)
447 Bit64u op1_64, op2_64, diff_64;
449 op1_64 = BX_READ_64BIT_REG(i->rm());
450 op2_64 = (Bit32s) i->Id();
451 diff_64 = op1_64 - op2_64;
453 SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
456 void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqM(bxInstruction_c *i)
458 Bit64u op1_64;
460 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
462 /* pointer, segment address pair */
463 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
464 op1_64 = - (Bit64s)(op1_64);
465 write_RMW_virtual_qword(op1_64);
467 SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
470 void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqR(bxInstruction_c *i)
472 Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
473 op1_64 = - (Bit64s)(op1_64);
474 BX_WRITE_64BIT_REG(i->rm(), op1_64);
476 SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
479 void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqM(bxInstruction_c *i)
481 Bit64u op1_64;
483 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
485 /* pointer, segment address pair */
486 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
487 op1_64++;
488 write_RMW_virtual_qword(op1_64);
490 SET_FLAGS_OSZAPC_INC_64(op1_64);
493 void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqR(bxInstruction_c *i)
495 Bit64u rrx = ++BX_READ_64BIT_REG(i->rm());
496 SET_FLAGS_OSZAPC_INC_64(rrx);
499 void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqM(bxInstruction_c *i)
501 Bit64u op1_64;
503 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
505 /* pointer, segment address pair */
506 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
507 op1_64--;
508 write_RMW_virtual_qword(op1_64);
510 SET_FLAGS_OSZAPC_DEC_64(op1_64);
513 void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqR(bxInstruction_c *i)
515 Bit64u rrx = --BX_READ_64BIT_REG(i->rm());
516 SET_FLAGS_OSZAPC_INC_64(rrx);
519 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqM(bxInstruction_c *i)
521 Bit64u op1_64, op2_64, diff_64;
523 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
525 /* pointer, segment address pair */
526 op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
527 diff_64 = RAX - op1_64;
528 SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
530 if (diff_64 == 0) { // if accumulator == dest
531 // dest <-- src
532 op2_64 = BX_READ_64BIT_REG(i->nnn());
533 write_RMW_virtual_qword(op2_64);
535 else {
536 // accumulator <-- dest
537 RAX = op1_64;
541 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqR(bxInstruction_c *i)
543 Bit64u op1_64, op2_64, diff_64;
545 op1_64 = BX_READ_64BIT_REG(i->rm());
546 diff_64 = RAX - op1_64;
547 SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
549 if (diff_64 == 0) { // if accumulator == dest
550 // dest <-- src
551 op2_64 = BX_READ_64BIT_REG(i->nnn());
552 BX_WRITE_64BIT_REG(i->rm(), op2_64);
554 else {
555 // accumulator <-- dest
556 RAX = op1_64;
560 void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG16B(bxInstruction_c *i)
562 Bit64u op1_64_lo, op1_64_hi, diff;
564 bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
566 bx_address laddr = get_laddr64(i->seg(), eaddr);
568 if (laddr & 0xf) {
569 BX_ERROR(("CMPXCHG16B: not aligned memory location (#GP)"));
570 exception(BX_GP_EXCEPTION, 0, 0);
573 // check write permission for following write
574 op1_64_lo = read_RMW_virtual_qword_64(i->seg(), eaddr);
575 op1_64_hi = read_RMW_virtual_qword_64(i->seg(), eaddr + 8);
577 diff = RAX - op1_64_lo;
578 diff |= RDX - op1_64_hi;
580 if (diff == 0) { // if accumulator == dest
581 // dest <-- src (RCX:RBX)
582 write_RMW_virtual_qword(RCX);
583 // write permissions already checked by read_RMW_virtual_qword_64
584 write_virtual_qword_64(i->seg(), eaddr, RBX);
585 assert_ZF();
587 else {
588 clear_ZF();
589 // accumulator <-- dest
590 RAX = op1_64_lo;
591 RDX = op1_64_hi;
595 #endif /* if BX_SUPPORT_X86_64 */