Пиша виртуална машина за моя собствен асемблер, искам да мога да задам флаговете за пренасяне, паритет, нула, знак и препълване, както са зададени в архитектурата x86-64, когато извършвам операции като добавяне.
Бележки:
- Използвам Microsoft Visual C++ 2015 & Intel C++ Compiler 16.0
- Компилирам като Win64 приложение.
- Моята виртуална машина (в момента) прави аритметика само на 8-битови цели числа
- Не се интересувам (в момента) от други флагове (напр. AF)
Текущото ми решение използва следната функция:
void update_flags(uint16_t input)
{
Registers::flags.carry = (input > UINT8_MAX);
Registers::flags.zero = (input == 0);
Registers::flags.sign = (input < 0);
Registers::flags.overflow = (int16_t(input) > INT8_MAX || int16_t(input) < INT8_MIN);
// I am assuming that overflow is handled by trunctation
uint8_t input8 = uint8_t(input);
// The parity flag
int ones = 0;
for (int i = 0; i < 8; ++i)
if (input8 & (1 << i) != 0) ++ones;
Registers::flags.parity = (ones % 2 == 0);
}
Което като допълнение бих използвал, както следва:
uint8_t a, b;
update_flags(uint16_t(a) + uint16_t(b));
uint8_t c = a + b;
РЕДАКТИРАНЕ: За да изясня, искам да знам дали има по-ефективен/изчистен начин да направя това (като например чрез директен достъп до RFLAGS) Също така моят код може да не работи за други операции (напр. умножение)
РЕДАКТИРАНЕ 2 Сега актуализирах кода си до следното:
void update_flags(uint32_t result)
{
Registers::flags.carry = (result > UINT8_MAX);
Registers::flags.zero = (result == 0);
Registers::flags.sign = (int32_t(result) < 0);
Registers::flags.overflow = (int32_t(result) > INT8_MAX || int32_t(result) < INT8_MIN);
Registers::flags.parity = (_mm_popcnt_u32(uint8_t(result)) % 2 == 0);
}
Още един въпрос, дали кодът ми за флага за пренасяне ще работи правилно?, Искам също да бъде зададен правилно за „заеми“, които се появяват по време на изваждане.
Забележка: Асемблерният език, който виртуализирам, е по мой собствен дизайн, предназначен да бъде прост и базиран на реализацията на Intel на x86-64 (т.е. Intel64), така че бих искал тези флагове да се държат почти по същия начин.
input < 0
никога няма да бъде вярно, защотоinput
е без знак и OF ще зависи от операндите, а не само от резултата. Например 8-битова операция0x7f + 0x02 = 0x81
ще доведе доOF = 1
, но0x82 + 0xff = 0x81
ще доведе доOF = 0
. Този код е грешен, така че някои кодове, които задават флагове правилно, са по-чисти от този начин. - person MikeCAT   schedule 26.03.2016