Устанавливает ли вычитание AVR одинаковых чисел C-флаг SREG?

Краткая предыстория: инструкция BRLO (переход, если ниже) имеет значение 1. ... выполнить переход, если C-флаг == 1; 2. ... выполнить переход, если Rd ‹ Rr (из инструкции CP)

Мой вопрос: я буду использовать 4-битные числа для демонстрации. Предположим, что Rd = Rs = 3 = 0011. Из пункта 2 выше ответвление НЕ должно происходить. Инструкция CP выполняет Rd - Rr. ЕСЛИ мы используем дополнение до двух для вычитания, мы имеем 0011 - 0011 = 0011 + 1100 + 0001 = 0000 С C-флагом = 1. Следовательно, пункт 1 выше противоречит пункту 2.

Предположим, что я ошибаюсь: где я накосячил?

Спасибо


person Sheepwall    schedule 04.06.2019    source источник
comment
x-x не устанавливает CF, так как нет переполнения. Да, добавление установило бы его, и есть некоторые архитектуры, где значение CF действительно перевернуто для вычитания. АВР не входит в их число. См. также ссылку на набор команд, в которой говорится: [CF] Установить, если абсолютное значение содержимого Rr больше, чем абсолютное значение Rd; в противном случае очищается.   -  person Jester    schedule 04.06.2019


Ответы (1)


Короче говоря, операции, дающие один и тот же результат, не всегда являются эквивалентными операциями. Итак, ваше предположение, что 0011 - 0011 = 0011 + 1100 + 0001 и будет иметь одинаковое значение флага переноса - неверно

Хотя A + (~B + 1) дает вам тот же результат, что и A - B, это не то же самое, и флаги не будут обновляться таким же образом.

На самом деле, вы забыли одну вещь. В вашем примере:

0011 + 1100 + 0001 = 0000 - неправильно. Потому что 0011 + 1100 + 0001 = 10000

Вы забываете, что 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 означает, что произошло переполнение со знаком. Их эксклюзив или комбинация говорит о том, что большее число со знаком вычитается из меньшего.

person AterLux    schedule 06.06.2019