1 /////////////////////////////////////////////////////////////////////////
2 // $Id: ctrl_xfer16.cc,v 1.37 2007/07/09 15:16:11 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
28 #define NEED_CPU_REG_SHORTCUTS 1
31 #define LOG_THIS BX_CPU_THIS_PTR
34 void BX_CPU_C::RETnear16_Iw(bxInstruction_c
*i
)
39 BX_CPU_THIS_PTR show_flag
|= Flag_ret
;
44 if (return_IP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
)
46 BX_ERROR(("retnear_iw: IP > limit"));
47 exception(BX_GP_EXCEPTION
, 0, 0);
52 Bit16u imm16
= i
->Iw();
54 if (BX_CPU_THIS_PTR sregs
[BX_SEG_REG_SS
].cache
.u
.segment
.d_b
) /* 32bit stack */
59 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_RET
, EIP
);
62 void BX_CPU_C::RETnear16(bxInstruction_c
*i
)
67 BX_CPU_THIS_PTR show_flag
|= Flag_ret
;
72 if (return_IP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
)
74 BX_ERROR(("retnear: IP > limit"));
75 exception(BX_GP_EXCEPTION
, 0, 0);
80 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_RET
, EIP
);
83 void BX_CPU_C::RETfar16_Iw(bxInstruction_c
*i
)
88 invalidate_prefetch_q();
91 BX_CPU_THIS_PTR show_flag
|= Flag_ret
;
97 if (protected_mode()) {
98 BX_CPU_THIS_PTR
return_protected(i
, imm16
);
107 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
109 if (BX_CPU_THIS_PTR sregs
[BX_SEG_REG_SS
].cache
.u
.segment
.d_b
)
115 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_RET
,
116 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);
119 void BX_CPU_C::RETfar16(bxInstruction_c
*i
)
123 invalidate_prefetch_q();
126 BX_CPU_THIS_PTR show_flag
|= Flag_ret
;
129 #if BX_CPU_LEVEL >= 2
130 if ( protected_mode() ) {
131 BX_CPU_THIS_PTR
return_protected(i
, 0);
139 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
142 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_RET
,
143 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);
146 void BX_CPU_C::CALL_Aw(bxInstruction_c
*i
)
151 BX_CPU_THIS_PTR show_flag
|= Flag_call
;
154 new_EIP
= EIP
+ (Bit32s
) i
->Id();
155 new_EIP
&= 0x0000ffff;
157 #if BX_CPU_LEVEL >= 2
158 if (new_EIP
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
)
160 BX_ERROR(("CALL_Aw: new_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].limit"));
161 exception(BX_GP_EXCEPTION
, 0, 0);
165 /* push 16 bit EA of next instruction */
169 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_CALL
, EIP
);
172 void BX_CPU_C::CALL16_Ap(bxInstruction_c
*i
)
177 invalidate_prefetch_q();
180 BX_CPU_THIS_PTR show_flag
|= Flag_call
;
186 #if BX_CPU_LEVEL >= 2
187 if (protected_mode()) {
188 BX_CPU_THIS_PTR
call_protected(i
, cs_raw
, disp16
);
193 push_16(BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
);
194 push_16((Bit16u
) EIP
);
195 EIP
= (Bit32u
) disp16
;
196 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
199 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_CALL
,
200 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);
203 void BX_CPU_C::CALL_Ew(bxInstruction_c
*i
)
208 BX_CPU_THIS_PTR show_flag
|= Flag_call
;
212 op1_16
= BX_READ_16BIT_REG(i
->rm());
215 read_virtual_word(i
->seg(), RMAddr(i
), &op1_16
);
218 #if BX_CPU_LEVEL >= 2
219 if (op1_16
> BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].cache
.u
.segment
.limit_scaled
)
221 BX_ERROR(("CALL_Ew: IP out of CS limits!"));
222 exception(BX_GP_EXCEPTION
, 0, 0);
229 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_CALL
, EIP
);
232 void BX_CPU_C::CALL16_Ep(bxInstruction_c
*i
)
237 invalidate_prefetch_q();
240 BX_CPU_THIS_PTR show_flag
|= Flag_call
;
244 BX_INFO(("CALL_Ep: op1 is a register"));
245 exception(BX_UD_EXCEPTION
, 0, 0);
248 read_virtual_word(i
->seg(), RMAddr(i
), &op1_16
);
249 read_virtual_word(i
->seg(), RMAddr(i
)+2, &cs_raw
);
251 if ( protected_mode() ) {
252 BX_CPU_THIS_PTR
call_protected(i
, cs_raw
, op1_16
);
256 push_16(BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
);
260 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
263 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_CALL
,
264 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);
267 void BX_CPU_C::JMP_Jw(bxInstruction_c
*i
)
269 Bit32u new_EIP
= EIP
+ (Bit32s
) i
->Id();
270 new_EIP
&= 0x0000ffff;
271 branch_near32(new_EIP
);
272 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_JMP
, new_EIP
);
275 void BX_CPU_C::JCC_Jw(bxInstruction_c
*i
)
279 switch (i
->b1() & 0x0f) {
280 case 0x00: /* JO */ condition
= get_OF(); break;
281 case 0x01: /* JNO */ condition
= !get_OF(); break;
282 case 0x02: /* JB */ condition
= get_CF(); break;
283 case 0x03: /* JNB */ condition
= !get_CF(); break;
284 case 0x04: /* JZ */ condition
= get_ZF(); break;
285 case 0x05: /* JNZ */ condition
= !get_ZF(); break;
286 case 0x06: /* JBE */ condition
= get_CF() || get_ZF(); break;
287 case 0x07: /* JNBE */ condition
= !get_CF() && !get_ZF(); break;
288 case 0x08: /* JS */ condition
= get_SF(); break;
289 case 0x09: /* JNS */ condition
= !get_SF(); break;
290 case 0x0A: /* JP */ condition
= get_PF(); break;
291 case 0x0B: /* JNP */ condition
= !get_PF(); break;
292 case 0x0C: /* JL */ condition
= getB_SF() != getB_OF(); break;
293 case 0x0D: /* JNL */ condition
= getB_SF() == getB_OF(); break;
294 case 0x0E: /* JLE */ condition
= get_ZF() || (getB_SF() != getB_OF()); break;
295 case 0x0F: /* JNLE */ condition
= (getB_SF() == getB_OF()) && !get_ZF(); break;
297 condition
= 0; // For compiler...all targets should set condition.
302 Bit32u new_EIP
= EIP
+ (Bit32s
) i
->Id();
303 new_EIP
&= 0x0000ffff;
304 branch_near32(new_EIP
);
305 BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID
, new_EIP
);
307 #if BX_INSTRUMENTATION
309 BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID
);
314 void BX_CPU_C::JZ_Jw(bxInstruction_c
*i
)
317 Bit32u new_EIP
= EIP
+ (Bit32s
) i
->Id();
318 new_EIP
&= 0x0000ffff;
319 branch_near32(new_EIP
);
320 BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID
, new_EIP
);
322 #if BX_INSTRUMENTATION
324 BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID
);
329 void BX_CPU_C::JNZ_Jw(bxInstruction_c
*i
)
332 Bit32u new_EIP
= EIP
+ (Bit32s
) i
->Id();
333 new_EIP
&= 0x0000ffff;
334 branch_near32(new_EIP
);
335 BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID
, new_EIP
);
337 #if BX_INSTRUMENTATION
339 BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID
);
344 void BX_CPU_C::JMP_Ew(bxInstruction_c
*i
)
349 op1_16
= BX_READ_16BIT_REG(i
->rm());
352 read_virtual_word(i
->seg(), RMAddr(i
), &op1_16
);
355 Bit32u new_EIP
= op1_16
;
356 branch_near32(new_EIP
);
357 BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_JMP
, new_EIP
);
360 /* Far indirect jump */
362 void BX_CPU_C::JMP16_Ep(bxInstruction_c
*i
)
367 invalidate_prefetch_q();
370 /* far indirect must specify a memory address */
371 BX_INFO(("JMP_Ep(): op1 is a register"));
372 exception(BX_UD_EXCEPTION
, 0, 0);
375 read_virtual_word(i
->seg(), RMAddr(i
), &op1_16
);
376 read_virtual_word(i
->seg(), RMAddr(i
)+2, &cs_raw
);
378 #if BX_CPU_LEVEL >= 2
379 if ( protected_mode() ) {
380 BX_CPU_THIS_PTR
jump_protected(i
, cs_raw
, op1_16
);
386 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
389 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_JMP
,
390 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);
393 void BX_CPU_C::IRET16(bxInstruction_c
*i
)
395 Bit16u ip
, cs_raw
, flags
;
397 invalidate_prefetch_q();
400 BX_CPU_THIS_PTR show_flag
|= Flag_iret
;
403 BX_CPU_THIS_PTR nmi_disable
= 0;
406 // IOPL check in stack_return_from_v86()
407 iret16_stack_return_from_v86(i
);
411 #if BX_CPU_LEVEL >= 2
412 if (BX_CPU_THIS_PTR cr0
.get_PE()) {
419 BX_ERROR(("IRET: top 6 bytes of stack not within stack limits"));
420 exception(BX_SS_EXCEPTION
, 0, 0);
427 load_seg_reg(&BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
], cs_raw
);
429 write_flags(flags
, /* change IOPL? */ 1, /* change IF? */ 1);
432 BX_INSTR_FAR_BRANCH(BX_CPU_ID
, BX_INSTR_IS_IRET
,
433 BX_CPU_THIS_PTR sregs
[BX_SEG_REG_CS
].selector
.value
, EIP
);