Вы не можете использовать CMP
инструкции непосредственно, так как флаги не являются действительными операндами для х86. Они используются неявно с помощью определенных инструкций.
Проще всего использовать только a conditional branch. Это работает аналогично инструкции JE
, с которой вы уже знакомы, за исключением того, что она разветвляется на основе значения флага переноса (CF), вместо флага нуля (ZF), такого как JE
.
Чтобы условно разветвиться на статусе флага переноса (CF), вы должны использовать JC
или JNC
. JC
будет ветвиться, если флаг переноса установлен (CF == 1), тогда как JNC
будет ветвиться, если флаг переноса равен не set (CF == 0). Мнемоника для этих опкодами просто "J UMP, если С Arry" и "J UMP, если N OT C Arry".
jc CarryFlagIsSet ; jump if CF == 1
; else fall through: code for CF == 0 goes here
Или по-другому:
jnc CarryFlagIsNotSet ; jump if CF == 0
; else fall through: code for CF == 1 goes here
Таким образом, в соответствии с вашим примером, что-то вроде:
shr num, 1 ; put least significant bit in CF
jc num_was_odd ; (or jnc LSBNotSet aka num_was_even)
Но as Peter Cordes points out in a comment код у вас есть почти наверняка неправильно, так как идентичный код будет выполнен независимо от того, берется ли ветка. Другими словами, назначение ветки эквивалентно провальному коду. Вы, вероятно, хотите иметь что-то подобное:
TOPOFLOOP:
LEA DX, MSG
MOV AH, 09H
INT 21H
MOV AH, 01H
INT 21H
MOV NUM, AL
SHR NUM, 1
JC TOPOFLOOP ; keep looping as long as CF == 1
; otherwise, if CF == 0, fall through to FINISH
; (use JNC to reverse the logic)
FINISH:
MOV AH, 4CH
INT 21H
RET
(за исключением, что это гораздо быстрее работать на enregistered значения, чем один, хранящиеся в памяти, поэтому, если возможно, вы должны поместить NUM
в регистре также. , коды операций с ассемблером и регистры нечувствительны к регистру, поэтому вы можете так же легко написать код в нижнем регистре. Я думаю, что это проще вводить и читать легче, но оно чисто стилистично и поэтому зависит от вас.)
Если вы хотите написать нераспакованный код (который почти всегда улучшает если вы можете найти достаточно умный способ написать код), вы можете использовать SBB
instruction. Если оба операнда являются одним и тем же регистром, это установит этот регистр на -1, если флаг переноса установлен (CF == 1), или установите этот регистр на 0, если флаг переноса не установлен (CF == 0). Это работает, потому что SBB
фактически выполняет операцию DEST = (DEST - (SRC + CF))
. Когда DEST
и SRC
- это то же значение, это эквивалентно DEST = -CF
.
В тех случаях, когда было бы удобнее иметь значение зеркало CF регистра один раз, это может быть объединено с NEG
instruction:
; Perform operation that will set CF.
...
; Set AX to the same value as CF.
sbb ax, ax ; CF == 1 then AX = -1; otherwise, AX = 0
neg ax ; AX == -1 then AX = 1; otherwise, AX = 0
В некоторых случаях можно даже использовать ADC
instruction аналогичным образом , Это выполняет операцию DEST = DEST + SRC + CF
. Когда DEST
и SRC
равны нулю, это эквивалентно DEST = CF
. Хитрость о том, что регистр назначения должен быть либо предварительно обнулить перед флаг переноса получает набор, или обнулить таким образом, что флаг переноса не влияет:
; Pre-zero AX in preparation for later use of ADC.
xor ax, ax
; Perform operation that will set CF.
; (NOTE: Cannot modify AX register here, nor AL nor AH!)
...
; Set AX to the same value as CF.
adc ax, ax
; Perform operation that will set CF.
...
; Zero AX in such a way that flags are not clobbered.
mov ax, 0
; Set AX to the same value as CF.
adc ax, ax
Обратите внимание, что если вы хотите сохранить значение CF
в памяти, вы можете использовать следующую форму ADC
:
adc DWORD PTR [value], 0
на более современных архитектурах, вы можете использовать либо SETC
или CMOVC
(или SETNC
/CMOVNC
для обратной логики - мнемоники такие же, как JC
/JNC
). Это, как правило, еще более быстрые способы написания нераспространяемого кода; однако на 8086 не имеется ни одного из них. Conditional set (SETcc
) instructions были представлены с 386, а conditional moves (CMOVcc
) были представлены с процессором Pentium Pro.
Используйте 'jc'. См. [Эту документацию] (https://stackoverflow.com/documentation/x86/5808/control-flow/20470/conditional-jumps#t=201612261956377395382). –
Или используйте 'sbb cx, cx', чтобы установить CX в 0 или -1, если это более полезно. –
Также обратите внимание, что у вас есть ветка назад. Целью ветви для принятого случая является тот же адрес, что и для неудачного неудачного случая. Вы должны «jnc top_of_loop». Или, если вы на самом деле зацикливаете биты в регистре, вы должны «shr al, 1' /' jnz top_of_loop', чтобы продолжать цикл, пока не осталось никаких ненулевых битов. SHR устанавливает ZF в соответствии с результатом, а также CF в соответствии с последним разрядом. (Почему вы храните память и затем меняете это. Гораздо быстрее просто сдвинуть 'al'.) –