Перейти к содержанию

SREG — регистр состояния AVR

Каждая арифметическая команда AVR оставляет след в восьми битах регистра SREG: был ли перенос, ноль ли результат, отрицательный ли он. По этим флагам работают условные переходы, а старший бит — глобальное разрешение прерываний.

Обновлено Редакция GAW

SREG (Status Register) — восьмибитный регистр состояния ядра AVR. Его биты отражают результат последней арифметической или логической команды, и условные переходы проверяют их без отдельной команды сравнения; старший бит управляет прерываниями. Регистр лежит в пространстве ввода-вывода по адресу 0x3F (0x5F в адресах памяти данных), все биты доступны на чтение и запись, после сброса равны нулю (DS40002061B, разд. 7.3.1).

Флаги

БитФлагЗначение
7Iглобальное разрешение прерываний
6Tхранение бита для команд BST и BLD
5Hполуперенос из бита 3 — для двоично-десятичной арифметики
4Sзнак: S = N ⊕ V
3Vпереполнение в дополнительном коде
2Nотрицательный результат — старший бит
1Zнулевой результат
0Cперенос из старшего бита

Флаги обновляет каждая команда АЛУ — какие именно, указано в описании команды в AVR Instruction Set Manual. Например, ADC (сложение с переносом) меняет H, S, V, N, Z и C, и пара add r2,r0 / adc r3,r1 складывает 16-битные числа: перенос младших байтов попадает в старшие через флаг C (DS40002198B, разд. 6.1).

Условные переходы

СравнениеЗнаковоеБеззнаковое
больше или равноBRGE: S = 0BRSH: C = 0
меньшеBRLT: S = 1BRLO: C = 1
равно / не равноBREQ: Z = 1 / BRNE: Z = 0те же

По разд. 4 DS40002198B. Для знаковых чисел проверяют S, а не N: при переполнении старший бит результата врёт, а S его исправляет. Для многобайтного сравнения служит CPC — у него флаг Z не устанавливается, а только сохраняется, если результат ноль: после цепочки CP, CPC, CPC флаг Z равен единице, только если совпали все байты.

Флаг I и прерывания

При входе в прерывание аппаратура сбрасывает флаг I, а команда RETI снова его устанавливает, поэтому обработчики по умолчанию не вкладываются друг в друга. Команды SEI и CLI ставят и снимают флаг программно. После CLI прерывания запрещены сразу, а после SEI следующая команда выполняется раньше любого ожидающего прерывания — на этом построены пары «SEI; SLEEP» (разд. 7.7).

Сам SREG при входе в прерывание не сохраняется. Компилятор C сохраняет его в прологе обработчика, а при написании на ассемблере это делают вручную. Тот же приём — основа критической секции: копию SREG делают до CLI и записывают обратно в конце, чтобы вернуть флаг I в прежнее состояние:

uint8_t sreg = SREG;   /* save the I flag */
cli();
/* timed sequence or shared data */
SREG = sreg;           /* restore, do not force sei() */

Набор команд, которые меняют флаги, и их длительности собраны в статье «Система команд AVR», устройство ядра и регистрового файла — в статье «Архитектура AVR».

Частые вопросы

Нужно ли сохранять SREG в обработчике прерывания?

Да, если обработчик меняет флаги: по даташиту ATmega328P регистр состояния не сохраняется автоматически при входе в прерывание и не восстанавливается при выходе. Компилятор C делает это сам в прологе и эпилоге обработчика, а на ассемблере сохранение — обязанность программиста. Иначе прерывание, пришедшее между сравнением и условным переходом, испортит флаги основной программы.

Чем флаг S отличается от флага N?

N — просто старший бит результата. S — это N, исправленный на переполнение: S = N ⊕ V. Если вычитание двух знаковых чисел переполнило 8 бит, старший бит результата неверен, а S всё равно показывает правильный знак разности. Поэтому знаковые переходы BRGE и BRLT проверяют именно S.

Почему для сохранения флага I копируют весь SREG, а не вызывают SEI в конце?

Потому что секция может выполняться и при уже запрещённых прерываниях — например, внутри другой критической секции. Копия SREG до CLI и запись её обратно возвращают флаг I в прежнее состояние, каким бы оно ни было. Так сделан пример с записью EEPROM в даташите ATmega328P.

Источники

  1. Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P megaAVR Data Sheet (DS40002061B, 2020) — разд. 7.3: регистр состояния содержит сведения о результате последней арифметической команды, обновляется после всех операций АЛУ, что часто избавляет от отдельных команд сравнения; не сохраняется автоматически при входе в прерывание и не восстанавливается при возврате — это делает программа; разд. 7.3.1: адрес 0x3F (0x5F), все биты чтение-запись, начальное значение 0; бит 7 I — глобальное разрешение прерываний, сбрасывается аппаратно при входе в прерывание и устанавливается командой RETI, управляется командами SEI и CLI; бит 6 T — хранение бита для BLD и BST; бит 5 H — полуперенос, полезен в двоично-десятичной арифметике; бит 4 S = N ⊕ V; бит 3 V — переполнение в дополнительном коде; бит 2 N — отрицательный результат; бит 1 Z — нулевой результат; бит 0 C — перенос; разд. 7.7: после CLI прерывания запрещены немедленно, после SEI следующая команда выполняется раньше ожидающих прерываний; пример сохранения SREG вокруг временной последовательности записи EEPROM (in r16, SREG; cli; …; out SREG, r16); разд. 7.7.1: реакция на прерывание — не меньше четырёх тактов
  2. Microchip. AVR Instruction Set Manual (DS40002198B, 2021) — разд. 4 Conditional Branch Summary: BRGE (Rd ≥ Rr) — S = 0, BRLT — S = 1, знаковые; BRSH — C = 0, BRLO — C = 1, беззнаковые; BRNE — Z = 0, BREQ — Z = 1; BRCC/BRCS, BRPL/BRMI, BRVC/BRVS — простые проверки C, N, V; флаги — результат предыдущей команды, после CP, CPI, SUB, SUBI переход соответствует столбцу Common Test; разд. 6.1 ADC: H — перенос из бита 3, V — переполнение в дополнительном коде, N = R7, Z — результат 0x00, C — перенос из старшего бита, пример add r2,r0 / adc r3,r1 для 16-битного сложения; разд. 6.46 CPC: флаг Z сохраняет прежнее значение, если результат ноль, и сбрасывается иначе

Нашли ошибку?