Короче говоря, операции, которые дают одинаковый результат, не всегда эквивалентны операциям. Итак, ваше предположение, что 0011 - 0011 = 0011 + 1100 + 0001 и будет иметь одинаковое значение флага переноса - неверно
Хотя A + (~ B + 1) дает тот же результат, что и A - B, это не то же самое и не будет обновлять флаги таким же образом.
На самом деле, вы забыли одну вещь. В вашем примере:
0011 + 1100 + 0001 = 0000
- неправильно. Потому что 0011 + 1100 + 0001 = 1 0000
Вы забываете, что A + (~ B + 1) равно A - B только при рассмотрении дополнения к двум переполнение .
Теперь вы можете видеть, что флаг переноса будет очень противоположным в обеих операциях. Фактически, A + ~ B + 1 будет иметь переполнение (при первом или втором добавлении) тогда и только тогда, когда у A - B нет заимствования (недостаточного).
При выполнении добавления флаг C означает, что произошло переполнение, т. Е. Его следует выполнять слева от самого левого бита.
т.е. если вы добавляете:
0110
+ 1101
----
10011
^^^^ the result
^ the carry flag
Это означает, что если вы выполняете сложение на более длинном номере, состоящем из нескольких регистров, вы должны добавить один в верхнюю часть. Э.Г.
add r16, r18 // adds r18 to r16, C flag is set only when overflow happened
adc r17, r19 // adds r19 to r18, and add one if C flag is set. updates the C flag by the overflow again
// in result r17:r16 = r17:r16 + r19:r18
При выполнении вычитания флаг C означает, что заимствование произошло слева от крайнего левого бита, и поэтому старшую часть числа следует уменьшить на единицу
* * - borrow positions
0110
- 1101
----
0001
^ carry flag is set when borrowed at left from the leftmost positions.
В ассемблере у вас есть инструкция sbc
, которая делает вычитание как инструкция sub
, но уменьшает результат на единицу, если установлен флаг переноса
sub r16, r18 // subtracts r18 from r16, C flag is set only when underflow happened
sbc r17, r19 // subtracts r19 from r18, and subtracts one more if C flag is set. updates the C flag by the underflow again
// in result r17:r16 = r17:r16 - r19:r18
Итак, отвечая на ваш вопрос: когда вы вычитаете число из самого себя, значение флага переноса сбрасывается, потому что не происходило потери значения.
Архитектура AVR имеет простую механику ветвления. Он имеет 8 флаговых битов, и каждая инструкция ветвления делает переход в зависимости от значения только одного бита из них.
Итак, BRLO
и BRCS
оба являются мнемониками для одного и того же машинного кода, который создает ветвление, если установлен флаг переноса. Флаг переноса устанавливается только при вычитании более высокого значения без знака из более низкого.
Если вы хотите сделать сравнение со знаком, то вы должны использовать инструкцию BRLT
, которая смотрит на флаг S
, что соответствует исключающему ИЛИ флагов N
и V
. Флаг N
устанавливается, когда результатом операции является отрицательное число со знаком (установлен старший бит). Флаг V
означает, что произошло переполнение со знаком. Их эксклюзив или комбинация говорят, что большее число со знаком вычиталось из меньшего.