# 1.SREG **SREG** - это регистр состояния в AVR. Это **8-разрядный регистр**, в котором каждый бит (разряд) отображает состояние какой-либо операции (или результата операции). Каждый бит (флаг) доступен как для чтения, так и для записи. **При инициализации все биты равны нулю.** 1) Флаг I (бит 7): **Global Interrupt Enable** (Флаг глобального разрешения прерываний) [Прерывания](/Tun8u1j-QJSgYGSeV2K34Q) Для включения прерываний флаг I должен быть установлен. Затем управление включением отдельных прерываний выполняется в отдельных регистрах управления. Если флаг I сброшен, ни одно из прерываний не включено, независимо от настроек отдельного прерывания. Флаг I очищается аппаратным обеспечением после завершения прерывания (автоматически сбрасывается), а устанавливается инструкцией RETI для включения последующих прерываний. Флаг I также может быть установлен и очищен инструкциями SEI и CLI, как описано в документации. Благодаря автоматическому сбросу этого флага во время выполнения подпрограммы обработки прерывания запрещается (и исключается) возникновение других прерываний. Если бы это не делалось, то могло бы возникнуть очень большое количество рекурсивных вызовов (что в итоге привело бы к зависанию). Разрешаются прерывания обычно вручную при возврате из обработчика прерываний. 2) Флаг T (бит 6): **Bit Copy Storage** (Хранение Копируемого Бита) - Инструкции копирования бита (Bit Copy), то есть инструкции BLD (Bit LoaD) и BST (Bit STore), используют флаг T как источник или приёмник при операциях с битом. Бит из регистра в Регистре Файла (Register File) можно скопировать в бит Т с помощью инструкции BST, а состояние флага Т можно скопировать в бит регистра Регистра Файла при помощи команды BLD. Предназначен для хранения временной инфы просто потому что ты так захотел 3) Флаг H (бит 5): **Half Carry Flag** (Флаг половинного переноса) Флаг полупереноса H указывает на полуперенос в некоторых арифметических операциях. Полуперенос полезен в арифметике BCD Работает как флаг обычного переноса, но при переносе из младшей половины байта (из 3 бита) 4) Флаг S (бит 4): **Sign Bit** (Флаг знака) S = N (+) V (исключающее или между флагами N и V) Флаг S равен итогу операции исключающего или между флагом отрицательного результата N и флагом переполнения V. 5) Флаг V (бит 3): **Two’s Complement Overflow Flag** (Флаг переполнения дополнительного кода) - Флаг V поддерживает арифметику дополнения до двух. Чтобы применять те же самые байты и слова для представления отрицательных чисел, существует специальная операция, которая называется дополнение до двух. > [name=Дарья Воронская] Вот тут мне кажется нужно будет побольше погуглить, вообще не ясно. Ок, существует специальная операция. Какая? 6) Флаг N (бит 2): **Negative Flag** (Флаг отрицательного значения) Флаг N указывает на то, что результат арифметической или логической операции был отрицательным. *Что тогда сохраняется в регистре, куда ты закинул разницу?* 7) Флаг Z (бит 1): **Zero Flag** (Флаг нуля) Флаг Z указывает на то, что результат арифметической или логической операции равен нулю. 8) Флаг C (бит 0): **Carry Flag** (Флаг переноса) Устанавливается, если во время выполнения операции был перенос из старшего разряда результата; > Тупая особенность - команда inc не может установить флаг переноса ### Теория, которую давал Селезнёв 1) Флаг I (бит 7): **Global Interrupt Enable** (Флаг глобального разрешения прерываний) В данном регистре устанавливается значение 1, для того, чтобы осуществить векторы прерывания. 2) Флаг T (бит 6): **Bit Copy Storage** (Хранение Копируемого Бита) Регистр сохранения копии Бита 3) Флаг H (бит 5): **Half Carry Flag** (Флаг половинного переноса) Значение в регистре переваливает за 256 4) Флаг S (бит 4): **Sign Bit** (Флаг знака) Значение устанваливается в 1, когда выполняется функция нигатива 5) Флаг V (бит 3): **Two’s Complement Overflow Flag** (Флаг переполнения дополнительного кода) - Переполнение за 512 6) Флаг N (бит 2): **Negative Flag** (Флаг отрицательного значения) Показывает отрицательное значение 7) Флаг Z (бит 1): **Zero Flag** (Флаг нуля) Показывает, что в регистре нет значеий 8) Флаг C (бит 0): **Carry Flag** (Флаг переноса) Переполнение за 1024 > [name=Дарья Воронская] как оно может быть переполнением за 1024, если у нас 8битные регистры, которые дай боже 255 сохранят? ## Синтаксис ### Установка значений: **cl<flag_name>** - очистить флаг *(читай полностью как clear <flag_name>)* **se<flag_name>** - установить флаг *(читай полностью как set <flag_name>)* например, `cli, clv, sen, ses` для флага T используют команды `bst, bld`, но команды `clt, set` так же присутствуют можно очистить значение конкретного флага SREG через `bcrl <flag_index>` можно установить значение конкретного флага через `bset <flag_index>` Внимательней - очередность флагов идет в обратную сторону с 7 до 0, тобишь I - это 7, а C - 0. Имхо, проще использовать cl, se команды можно устанавливать значение всему регистру SREG через `out SREG, rName` ### Получение значений: просто так 1 командой значение флага SREG не получить **(НЕ ФАКТ, НО В ДАТАШИТЕ НЕ ВИЖУ)**, но есть конкретные команды для условных переходов, которые можно использовать например после `CP, CPI, SUB или SUBI`: ```cp= brbc <flag_index>, <branch_name> ; Перейти если флаг очищен brbs <flag_index>, <branch_name> ; Перейти если флаг установлен ``` легче запомнить через c - cleared, s - set как и в случае с cl, se есть команды для конкретных флагов, но они по какому-то ебанутому принципу работают и их хрен запомнишь, но чаще всего работает схема BR<flag_name><C/S> ```cp= BRCC, BRCS BRHC, BRHS BRTC, BRTS BRVC, BRVS ``` для остальных другое ```cp= BREQ ; если Z = 1 ( == после вычитания) - eq типа equals BRNE ; если Z = 0 ( != после вычитания) BRSH ; если C = 0 (больше или равно без знака) - да, оно равно BRCC BRLO ; если C = 1 ( < без учета знака после вычинатия) - да, оно равно BRCS BRLT ; если S = 0 ( < с учетом знака после вычитания) BRGE ; если S = 1 ( >= с учетом знака после вычитания) BRMI ; если N = 1 (может использоваться для определения, какое число больше другого - если в результате вычитания у нас минус)- mi - типа минус BRPL ; если N = 0 (так же используется для определения, какое число больше другого - если в результате вычитания у нас плюс) = pl типа плюс BRID ; если I = 0 BRIE ; если I = 1 ``` можно получить значение всего регистра SREG через `in rName, SREG` ### Пример кода для сравнения чисел ```cp= subi r26, $50 ; Вычесть $50 из r26 brpl positive ; Перейти если r26 положителен (r26 был > 50) positive: nop ; Перейти по назначению ``` ### Примеры кода флаг I ```cp= in r16, SREG ; Сохранить значения SREG cli ; Отключить прерывания на время синхронизации sbi EECR, EEMPE ; Начать запись в EEPROM sbi EECR, EEPE out SREG, r16 ; Восстановить значения SREG (I-bit) ``` ```cp= sei ; Установить флаг глобального разрешения прерываний sleep ; Спящий режим в ожидании прерывания ; Примечание: переход в спящий режим ; перед ожиданием какого-либо прерывания ``` ### Примеры кода флаг T Копирование бита ```cp= bst r1, 2 ; Сохранить бит 2 регистра r1 во флаге T bld r0, 4 ; Загрузить T в бит 4 регистра r0 Пример. Скопировать из регистра r16 в регистр r19 пятый бит, не изменяя содержимое регистра r16. Без использования флага T: in r16,PINA mov r17,r16 andi r17,0x20 or r19,r17 ;запись в r16 любого числа ;копирование r16 в любой свободный РОН (r17) ;выделение 5-го бита в r17 ;логическое ИЛИ r19 и r17 С использованием флага T: in r16,PINA bst r16,5 bld r19,5 ;запись в r16 любого числа ;копирование 5-го бита в SREG ;копирование содержимого флага T в 5-й бит r19 ``` ### примеры кода флага H ```cp= add r2, r3 ; Сложить r3 с r2 cln ; Очистить флаг отрицательного значения Пример. Организовать бегущий огонь в младшем полубайте PORTC. ldi r16,0xFF out DDRC,r16 ldi r16,0x01 main: out PORTC,r16 lsl r16 brhc main ldi r16,0x01 rjmp main ;в r16 записывается значение 0хFF ;порт С инициализируется на вывод информации ;в r16 записывается единица младшего разряда ;значение r16 выводится на PORTC ;r16 сдвигается влево на один разряд ;если флаг H снят, то переход на main ;иначе в r16 записывается 0x01 ;и осуществляется переход на main ``` > [name=Дарья Воронская] Почему cln для флага H ### Примеры кода флаг S ```cp= add r2, r3 ; Сложить r3 с r2 cls ; Очистить флаг знака ``` ### Примеры кода флаг V ```cp= add r2, r3 ; Сложить r3 с r2 clv ; Oчистить флаг переполнения main: in r16,PINA in r17,PINC add r16,r17 brvc m1 brcs m2 ldi r16,0x7F rjmp m1 m2: ldi r16,0x80 m1: out PORTD,r16 rjmp main ;ввод первого числа А ;ввод второго числа В ;сложение А и В ;если нет переполнения (флаг V=0), то ;осуществляется переход на m1 ;иначе проверка флага переноса. Если флаг C=1, ;то осуществляется переход на m2 ;если переноса нет, то результат – ;максимальное число +127 (0111 1111) ;далее – переход на m1 ;если флаг переноса С=1, то результат – ;минимальное число -128 (1000 0000). ;по метке m1 – вывод результата на PORTD ; и возврат на main ``` ### Примеры кода флаг N ```cp= add r2, r19 ; Сложить r19 с r2 sen ; Установить флаг отрицательного значения main: in r16,PINA in r17,PINC cp r16,r17 brmi m1 sbi PORTD,0 rjmp main m1: cbi PORTD,0 rjmp main ;ввод числа А ;ввод числа В ;сравнение чисел А и В вычитанием А-В ;если при этом установлен флаг N, то ;осуществляется переход на m1 ;иначе устанавливается разряд PORTD0 ;и идет возврат на main ;по метке m1 очищается разряд PORTD0 ;и идет возврат на main ``` ### Примеры кода флаг Z ```cp= add r2, r19 ; Сложить r19 с r2 sez ; Установить флаг нулевого значения main: in r16,PINA in r17,PINC cp r16,r17 breq m1 cbi PORTD,0 rjmp main m1: sbi PORTD,0 rjmp main ;ввод первого числа ;ввод второго числа ;сравнение r16 и r17 проведением операции ;вычитания r16-r17. При равенстве выставляется ;флаг Z ;при Z=1 осуществляется переход на метку m1 ;иначе бит PORTD0 очищается ;и идет возврат на main ;при переходе на m1 устанавливается бит PORTD0 ;и идет возврат на main ``` ### Примеры кода флаг C ```cp= add r0, r0 ; Сложить r0 с самим собой clc ; Очистить флаг переноса Пример. Прибавить к числу 0xFE произвольное 8-разрядное число. Результат – шестнадцатиразрядное число. clr r18 ldi r16,0xFE ldi r17,0x05 mov r20,r16 add r20,r17 adc r21,r18 ;очистка регистра r18 ;запись в r16 значения 0xFE ;запись любого числа в r17 ;копирование r16 в r20 ;сложение r20 и r17 ;если при этом возникает перенос, то в r21 ;прибавляется ;0x01. Таким образом результат ;формируется в r21:r20 ```