zm_sansanТут бы профессиональное что-то выложить, но видимо тут нет специалистов. Есть вузы в которых это подробно проходят. Если задаться вопросом то книги можно найти.
На пальцах попробую описать. Тоже в свое время как и автор интересовался этим вопросом.
Почти каждая операция выставляет флаги.
Сравнение происходит в 2 стадии.
1) Вначале выполняется операция сравнения результат заносится в регистр и выставляются флаги.
2) Затем на основе флагов выполняется условный переход.
1.1) В качестве операции сравнения обычно применяют вычитание или булевую операцию "И"
1.2) флаги существует 3-4 основных флага.
- флаг нуля;
- Флаг переноса/заёма
- флаг переполнения;
- флаг знак числа(+,-).
Выставление флага выполняется при помощи булевых операций.
К примеру флаг нуля выставляется при помощи "или не".
К примеру нам надо сравнить 2 числа на равенство. Загружаем числа в регистры вычитаем одно из другого. Процессор выставляет флаги, а после выполняется сравнение.
Код на языке высокого уровня
Код:
if a=b then
begin
...
end;
...
Этот код преобразованный в ассемблер
Код:
mov al,Byte PTR [0001] ;// загружаем байт в регистр
mov bl,Byte PTR [0002] ;// загружаем второй байт в другой регистр
sub al,bl ;// вычитание
jz begin ;// условный переход
;// jz и je обозначение одной команды, которая выполняется при zf=0
jmp end ;// безусловный переход
begin: ;// метка
...
end: ;// метка
...
Вот как это выглядит в эмуляторе
Код:
// Команда вычитания 8 битых чисел.
function SUB8(a,b:UInt8):UInt16;
begin
Result:=a-b;
_ZF:=Ord(Boolean(not Result)); // Флаг нуля
_SF:=(Result shr 7) and 1; // Флаг знак числа
_PF:=Result and 1; // Флаг чётности(означает чёт или нечет)
_OF:= ((a xor b) and (a xor Result)) shr 7; // Флаг переполнения
_CF:=Result shr 8; // Флаг заёма или флаг переноса
_AF:=((a xor b xor Result) shr 4) and 1; // Вспомогательный Флаг переполнения в x86 используется для десятичной арифметике
end;
// Команда условного перехода.
procedure JccNear16(ofs:Word; cc:Byte);
var Flag:Boolean;
begin
Flag:=False;
case сс of
0:Flag:=(_of=1); // JO
1:Flag:=not(_of=1); // JNO
2:Flag:=(_cf=1); // JB
3:Flag:=not(_cf=1); // JAE
4:Flag:=(_zf=1); // JZ или JE или "="
5:Flag:=not(_zf=1); // JNZ или JNE или "<>"
6:Flag:=(_cf=1) and (_zf=1); // JBE
7:Flag:=not((_cf=1) and (_zf=1)); // JNA
8:Flag:=(_sf=1); // JS
9:Flag:=not (_sf=1); // JNS
$A:Flag:=(_pf=1); // JP
$B:Flag:=not (_pf=1); // JNP
$C:Flag:=(_sf<>_of); // JL
$D:Flag:=(_sf=_of); // JGE
$E:Flag:=(_zf=1) or (_sf<>_of); // JLE
$F:Flag:=not (_zf=1) or (_sf<>_of); // JG
end;
if Flag then
NewRegs._EIP:=(NewRegs._EIP+ofs) and $FFFF;
end;
Схемно реализовать не трудно. На логических элементах и сумматорах.
Сумматор в свою очередь реализуется, опять таки на логических элементах.
Вычитание можно сделать по разному. Если числа в дополненном коде. То можно изменить знак числа и выполнить сложение
Было:
Стало:
Изменение знака для чисел в дополненном коде можно сделать как.