Устанавливает ли AVR вычитание равных чисел SREG C-флаг? - PullRequest
0 голосов
/ 04 июня 2019

Краткая справка: Инструкция BRLO (Разветвление если ниже) указывается 1. ... выполнить ветвь, если C-flag == 1; 2. ... выполнить ветвление, если Rd

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

Предположим, что я не прав: где я все испортил?

Спасибо

1 Ответ

1 голос
/ 06 июня 2019

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

...