i386: improved handling of override prefixes after a rep instruction [Gabriele Gorla]

This commit is contained in:
Michaël Banaan Ananas 2009-09-14 12:30:36 +00:00
parent d14a2d2c32
commit d84af18926

View File

@ -1016,31 +1016,62 @@ static void I386OP(repeat)(i386_state *cpustate, int invert_flag)
{ {
UINT32 repeated_eip = cpustate->eip; UINT32 repeated_eip = cpustate->eip;
UINT32 repeated_pc = cpustate->pc; UINT32 repeated_pc = cpustate->pc;
UINT8 opcode = FETCH(cpustate); UINT8 opcode; // = FETCH(cpustate);
UINT32 eas, ead; UINT32 eas, ead;
UINT32 count; UINT32 count;
INT32 cycle_base = 0, cycle_adjustment = 0; INT32 cycle_base = 0, cycle_adjustment = 0;
UINT8 prefix_flag=1;
UINT8 *flag = NULL; UINT8 *flag = NULL;
if( cpustate->segment_prefix ) {
eas = i386_translate(cpustate, cpustate->segment_override, cpustate->sreg[CS].d ? REG32(ESI) : REG16(SI) );
} else {
eas = i386_translate(cpustate, DS, cpustate->sreg[CS].d ? REG32(ESI) : REG16(SI) );
}
ead = i386_translate(cpustate, ES, cpustate->sreg[CS].d ? REG32(EDI) : REG16(DI) );
if( opcode == 0x66 ) { do {
repeated_eip = cpustate->eip;
repeated_pc = cpustate->pc;
opcode = FETCH(cpustate);
switch(opcode) {
case 0x26:
cpustate->segment_override=1;
cpustate->segment_prefix=ES;
break;
case 0x2e:
cpustate->segment_override=1;
cpustate->segment_prefix=CS;
break;
case 0x36:
cpustate->segment_override=1;
cpustate->segment_prefix=SS;
break;
case 0x3e:
cpustate->segment_override=1;
cpustate->segment_prefix=DS;
break;
case 0x64:
cpustate->segment_override=1;
cpustate->segment_prefix=FS;
break;
case 0x65:
cpustate->segment_override=1;
cpustate->segment_prefix=GS;
break;
case 0x66:
cpustate->operand_size ^= 1; cpustate->operand_size ^= 1;
repeated_eip = cpustate->eip; break;
repeated_pc = cpustate->pc; case 0x67:
opcode = FETCH(cpustate);
}
if( opcode == 0x67 ) {
cpustate->address_size ^= 1; cpustate->address_size ^= 1;
repeated_eip = cpustate->eip; break;
repeated_pc = cpustate->pc; default:
opcode = FETCH(cpustate); prefix_flag=0;
} }
} while (prefix_flag);
if( cpustate->segment_prefix ) {
// FIXME: the following does not work if both address override and segment override are used
eas = i386_translate(cpustate, cpustate->segment_override, cpustate->sreg[cpustate->segment_prefix].d ? REG32(ESI) : REG16(SI) );
} else {
eas = i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI) );
}
ead = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI) );
switch(opcode) switch(opcode)
{ {
@ -1107,7 +1138,7 @@ static void I386OP(repeat)(i386_state *cpustate, int invert_flag)
break; break;
} }
if( cpustate->sreg[CS].d ) { if( cpustate->address_size ) {
if( REG32(ECX) == 0 ) if( REG32(ECX) == 0 )
return; return;
} else { } else {
@ -1124,7 +1155,7 @@ static void I386OP(repeat)(i386_state *cpustate, int invert_flag)
I386OP(decode_opcode)(cpustate); I386OP(decode_opcode)(cpustate);
CYCLES_NUM(cycle_adjustment); CYCLES_NUM(cycle_adjustment);
if (cpustate->sreg[CS].d) if (cpustate->address_size)
count = --REG32(ECX); count = --REG32(ECX);
else else
count = --REG16(CX); count = --REG16(CX);