AVR. Учебный курс. Флаги и условные переходы

Есть в AVR (да и, пожалуй, во всех остальных процессорах) особый регистр SREG. О нем я несколько раз упоминал в прошлых статьях, но не вдавался в подробности. Чтож, пришло время рассказать, что же это же SREG такой и зачем он нужен.

SREG это регистр состояния ядра. Он так называется Status Register. В этом регистре находится независимых битов — флажков. Которые могут быть либо 1 либо 0, в зависимости от выполненных в прошлом операций.

И вот по тому какие флаги стоят, можно понять что произошло с процессором и что нам дальше делать.

Например, если флаг Z (Zero) выставлен в 1, значит в ходе вычисления предыдущей математической операции в результате образовался ноль.

А если выставлен флаг С (Carry — заем, перенос), то мы из меньшего числа отняли большее, или же прибавили такое число, что результат стал больше 255.

А теперь подробней по каждому флагу.

  • I — флаг разрешения прерываний. Когда установлен в 1 — прерывания разрешены.
  • T — пользовательский флаг. Можно юзать по своему назначению.
    Кроме того, есть две команды которые позволяют в этот бит записать любой бит любого из 32 регистров общего назначения R0-R31 (далее буду их звать РОН). Это команды BLD Rn,bit и BST Rn,bit

  • H — флаг полупереноса. Это если произошел заем бита из старшей половины байта в младшую. То есть когда из числа 0001 0111 пытаются вычести 0000 1000, то происходит заем бита из более старшего разряда, так как младшая тетрада уменьшаемого меньше чем младшей тетрады вычитаемого. Используется этот флаг в некоторых математических операциях.
  • S — флаг знака. 1 — значит минус. При вычислении чисел со знаком он возникает если после арифметической операции возник отрицательный результат. Флаг S = V XOR N.
  • V — Флаг переполнения дополнительного кода. Это если мы считаем число в дополнительном коде со знаком и оно вылезло за пределы регистра.
    Число в дополнительном коде с заемом — самая естественная форма представления числа во вселенной! Вот возьмем, например, число -61 как его получить? Ну не знаем мы про отрицательные числа! Просто! Вычтем его из нуля 00 — 61 = 39 Во как! Заняли из старшего разряда! Не похоже, да? Хорошо, проверим столбиком:
    61
    +
    39

    00 А единичка не влезла в разрядность!

    ЧТД!!! (с) Лохов С.П. (Наш преподаватель по ассемблеру в универе)

    Вот двоичный доп код работает точно по такому же принципу. А в процессоре есть команды для перевода числа из в доп код за одну команду.

  • N — флаг отрицательного значения. Если в результате арифметической операции 7 бит результата стал 1, то этот флаг тоже станет 1.
  • Z — флаг нуля. Если в результате какой либо операции получился ноль, то вылазит этот флаг. Чертовски удобно для всех целей!
  • С — флаг переноса. Если в результате операции произошел выход за границы байта, то выставляется этот флаг. Вообще самый юзаемый флаг после Z и I. Что только с ним не творят, как только не юзают.

Флаги, кроме автоматической установки, можно устанавливать и сбрасывать вручную. Для этого есть команды

SE* для установки и CL* для сброса. Вместо звездочки подставляется нужный флаг, например, CLI — запрет прерываний.

В даташите, в разделе Instruction Set Summary, написано какая команда что делает и на какие флаги влияет.

Пример:

1
2
3
4
5
INC 	Rd 	Increment 			Rd = Rd + 1 		Z,N,V 	
DEC 	Rd 	Decrement 			Rd = Rd − 1  		Z,N,V 	
TST 	Rd 	Test for Zero or Minus 		Rd = Rd AND Rd  	Z,N,V 	
CLR 	Rd 	Clear Register 			Rd = Rd XOR Rd	Z,N,V 	
SER 	Rd 	Set Register 			Rd = $FF 		None

Команда INC прибавляет к регистру 1, но несмотря на то, что она может добить регистр до переполнения, флаг переполнения С она не ставит. Такая особенность.

Зато она ставит флаги нуля, отрицательного значения и переполнения доп кода. Как инкремент может дать нуль? Элементарно, прибавив к -1 +1. Минус 1 в двоичной знаковой арифметике = FF. FF+1=1 00 ,но 1 не влезла в разрядность, поэтому 00 Логично же? :)

Или хотим мы, например, узнать в каком регистре число больше в R17 или R18

Нет ничего проще — к нашим услугам команда CP (нет, не детское порно, а Compare). Эта команда, у себя в уме, из R17 вычитает R18 при этом содержимое регистров не меняется, а меняются только флаги. И если, например, выскочил флаг С, значит при R17-R18 произошел заем, а значит R18 больше R17. Если флаг С не появился, то значит R17 больше чем R18. А коли у нас выскочил нуль, то значения равны. Есть еще команда CPI Rn,### работает также, но сравнивает регистр (только старшую группу) с произвольным числом. Используется чаще.

1
	CP R17,R18

А потом смотрим флаги. И дальше в ход вступают команды условных переходов из группы BRANCH (ветвление). BR**

И вот в этом месте товарищей из ATMEL надо хватать за ноги и бить головой об стену. Потому что я не понимаю на кой хрен было так все запутывать, изобретая команды которых реально нет?

Суди сам. Флагов у нас 8, соответственно должно быть 16 возможных бранчей. 8 по условию — флаг есть, 8 по условию — флага нет. Бранчевых команд же у нас аж 20 штук.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
BRBC #   	переход если бит # в регистре SREG=0
BRBS #  	переход если бит # в регистре SREG=1
 
BRCS 		переход если С=1 
BRCC		переход если С=0
 
BREQ 		переход если Z=1
BRNE 		переход если Z=0
 
BRSH		переход если С=0
BRLO		переход если С=1
 
BRMI		переход если N=1
BRPL 		переход если N=0
 
BRGE 		переход если S=0
BRLT 		переход если S=1
 
BRHC 		переход если H=0
BRHS 		переход если H=1
 
BRTC 		переход если T=0
BRTS 		переход если T=1
 
BRVS 		переход если V=1
BRVC 		переход если V=0
 
BRID 		переход если I=0
BRIE 		переход если I=1

Однако, если глубоко копнуть, поглядеть на реальные коды команд, то окажется, что BRCS=BRLO и BRCC=BRSH — у них вообще одинаковый код.

А таких команд как BRBS # и BRBC # вообще не существует. Это всего лишь иносказательная запись всех остальных бранчей, в зависимости от номера бита #.

А таких команд синонимов там дофига :)
Так что гордое «131 Powerful Instructions – Most Single-clock Cycle Execution» на самом деле является не более чем гнилым маркетинговым высером. Нет там 131 команды! Есть 131 мнемоника, а это несколько разные вещи. Потому как ты помидор не обзови — картошкой он от этого не станет.

Правда, возможным оправданием такого поведения может служить то, что, дескать, так удобней — в зависимости от ситуации подставлять ту мнемонику которая написана более логично.

Может быть, но как по мне — только ситуацию запутывают. Из-за этого я после ассемблера С51 долго плевался на систему команд AVR, потом привык и ничо так, вкатило.

Итак, как работает любой из бранчей (да, тому кто придумал переименовать родимый J** в BR** я тоже ежедневно посылаю лучи поноса, надеюсь в сортире он себе уже кабинет обустроил).

Проверяется условие и если оно верное делается переход.

Например, на входе у нас значение.

  • Если значение = 1, то делаем действие А
  • Если значение = 2, то делаем действие Б
  • А если значение меньше 13, то делаем действие ЦЭ
  • Во всех остальных случаях не делаем ничего

Нет ничего проще, пусть значение приходит через регистр R16

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
		CPI	R16,1		; Сравниваем R16 с 1
		BREQ	ActionA		; Переход если равно (EQual, Z=1)
					; Если не равно, то идем дальше
 
		CPI 	R16,2		; Сравниваем R16 с 2
		BREQ	ActionB		; Переход если равно 
					; Если не равно, то идем дальше
 
		CPI	R16,13		; Сравниваем R16. т.е. R16-13
		BRCS	ActionC		; Если возник перенос, значит R16 меньше 13
					; Если не возник - идем дальше
		RJMP	NoAction	; Переход на выход
 
ActionA:	NOP
		NOP			; Делаем наш экшн
		NOP
		RJMP	NoAction	; Выходим, чтобы не влезть в ActionB
 
 
ActionB:	NOP
		NOP			; Делаем наш экшн
		NOP
		RJMP	NoAction	; Выходим, чтобы не влезть в ActionC
 
 
ActionC:	NOP
		NOP			; Делаем наш экшн
		NOP
 
NoAction:	NOP
 
 
; Вместо NOP, разумеется, должны быть какие-нибудь полезные команды.

Сложно? Вот и я думаю, что делать нефиг :))))) Ничуть не сложней чем на Си забабахать из if then конструкцию или switch-case какой-нибудь.

Бег по граблям
У команд BR*** есть правда весьма ощутимое западло. Дальнобойность их составляет всего 63 команды. Т.е. это относительный переход. Поначалу ты этого не заметишь — короткая программа обычно не допускает переходов дальше 63.

Но вот, со временем, твоя программа распухнет, появится дофига кода и дальности бранча перестанет хватать. Вроде бы все работало, а добавил пару команд — и компилятор начал ругаться злыми словами — Error out of range или что то в этом духе. Как быть?

Перехватываться через промежуточные переходы. Т.е. находим ближайший к нам безусловный переход за который контроллер, как бы не старался залезть не сможет.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
ActionA:	NOP
		NOP			
		NOP
		RJMP	NoAction	
 
		NOP		; То есть если я вот тут поставлю островок
				; то он никогда не выполнится. Т.к. сверху 
				; Процессор перепрыгнет сразу по RJMP
				; А снизу вход будет сразу же на ActionB
 
ActionB:	NOP
		NOP			
		NOP
		RJMP	NoAction	
 
 
И вот, в этом островке, мы создаем капсулу телепортер такого вида:
 
 
ActionA:	NOP
		NOP			
		NOP
		RJMP	NoAction	
 
;-----------------------------------
Near:		JMP	FarFar_away
;------------------------------------
 
 
ActionB:	NOP
		NOP			
		NOP
		RJMP	NoAction

Т.е. бранчу теперь достаточно дострелить до островка Near, а там дальнобойный JMP зашлет его хоть в бутсектор на другой конец флеша.

В случае большой программы, чтобы не плодить островки, его лучше сделать один, сразу после пачки CP.

Test & Skip
Кроме Branch‘ей есть еще один тип команд: проверка — пропуск.
Работает она по принципу “Проверяем условие, если справедливо — пропускаем следующую команду”
Запомнить просто, первая буква это Skip — пропуск. Вторая условие — С=Clear, т.е. 0 S=Set, т.е. 1. Соответственно S**C пропуск если сброшено. S**S пропуск если установлено.

Команды SBRC/SBRS

Указываешь ей какой РОН, и какой номер бита в этом регистре надо проверить. И если условие верное, то следующая команда будет пропущена.

Пример:

1
2
3
4
5
6
7
8
9
10
11
12
	SBRC 	R16,3	; Если бит 3 в регистре R16 = 0, то прыжок через команду, на NOP
 
	RJMP	bit_3_of_R16_Not_Zer0
 
	NOP
 
 
	SBRS 	R16,3	; Если бит 3 в регистре R16 = 1, то прыжок через команду, на NOP
 
	RJMP	bit_3_of_R16_Zer0
 
	NOP

Аналогичная команда

SBIC/SBIS Но проверяет она не биты регистров РОН, а биты регистров периферийных устройств. Те самые,что идут в памяти между блоком РОН и оперативкой. Но есть у ней ограничение — она может проверить только первые 1F регистров ввода вывода. Если заглянешь в m16def.inc (для мега16, для других МК в их файл дефайнов)

То увидишь там это:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
.equ	UBRRH	= 0x20
.equ	UCSRC	= 0x20
.equ	EEARL	= 0x1e <-- а выше уже хрен :(
.equ	EEARH	= 0x1f <-- до сих можно обращаться через эти команды
.equ	EEDR	= 0x1d <-- ну и до нуля вниз.
.equ	EECR	= 0x1c
.equ	PORTA	= 0x1b
.equ	DDRA	= 0x1a
.equ	PINA	= 0x19
.equ	PORTB	= 0x18
.equ	DDRB	= 0x17
.equ	PINB	= 0x16
.equ	PORTC	= 0x15
.equ	DDRC	= 0x14
.equ	PINC	= 0x13
.equ	PORTD	= 0x12
.equ	DDRD	= 0x11
.equ	PIND	= 0x10
.equ	SPDR	= 0x0f
.equ	SPSR	= 0x0e
.equ	SPCR	= 0x0d
.equ	UDR	= 0x0c
.equ	UCSRA	= 0x0b
.equ	UCSRB	= 0x0a
.equ	UBRRL	= 0x09
.equ	ACSR	= 0x08
.equ	ADMUX	= 0x07
.equ	ADCSRA	= 0x06
.equ	ADCH	= 0x05
.equ	ADCL	= 0x04
.equ	TWDR	= 0x03
.equ	TWAR	= 0x02
.equ	TWSR	= 0x01
.equ	TWBR	= 0x00

Вот все это богатство твое. Проверяй не хочу :))))

А мне мало! Я хочу дальше!!! Что делать???
А дальше жизнь наша трудна и опасна. Чуть вправо,чуть влево — взрыв и ошметки. Страшно?

На самом деле ничего такого. Просто нам придется заюзать битмаски. И будет это не в одну команду, а в три.

Например, надо нам проверить состояние третьего бита в регистре UCSRC. Как видишь, это выше чем 1F Так что тест-скип не прокатит. Не беда, делай как я!

1
2
3
4
5
6
7
8
	IN	R16, UCSRC	; Хватаем байт из регистра, целиком.
	ANDI	R16,1<<3	; Накладываем на него маску 00001000
				; В результате, все байты кроме третьего
				; Обнулятся. А третий каким был таким и
				; останется. Был нулем - будет нуль и будет Z
				; Не был нулем, не будет Z флага. =))))
 
	BREQ	Bit_3_of_R16_Equal_Zero

Говорил же в три команды уложимся =)

А можно проверять и не по одному биту сразу. Накладывай нужные маски, оставляй только нужные биты. А дальше смотри какие числа эти биты могут образовать и сравнивай напрямую с этими числами через CPI. Красота!!!

Ладно, к битмаскам мы еще не раз вернемся. Это мощнейшее средство, но пока, не влезая в периферию, его не прочуешь. А до периферии мы еще не до росли. Всему свое время.

В следующей статье я тебе буду взрывать мозг индексными табличными переходами. Сходи лучше воздухом подыши предварительно. Такие вещи надо раскуривать со свежими мозгами

47 thoughts on “AVR. Учебный курс. Флаги и условные переходы”

  1. Начал изучать прерывания опять же на С. И вот какое дело, обработчик прерываний у меня срабатывает когда на линии PB5 меняется уровень, в обработчеке у меня простой код если PB5 = 0 и PB6= 0 то пишу ноль, исли PB6=1 пишу еденицу. Так вот за 100 ms
    у меня проходит 100 едениц и нулей. Суть в чем если я просто посылаю по UART, то принимаю все биты. Но стоит мне записать биты в массив, а потом перевести их в число, как на выходе я получаю какую то биллиберду. Я вот думаю успевает ли выполнится обработчик прерывания, до возникновения другого прерывания? Или может я что не так делаю???

    Тьфу ты не туда написал, как удалить не знаю ((

    1. Посчитай такты за который выполняется обработчик прерывания. Прикинь время на выполнение. С учетом кварца. Потом позырь на то с какой скоростью у тебя прерывания вызваются — нет ли затыка.

  2. Что то совсем у меня худо с прерываниями. Такое ощущений что программа постоянно перезапускается. Вот допустим в главной функции если после всей инициализации поставить UDR = ‘S’, при включении у меня, валится это S всех щелей. Что такое немогу ни как разобратся, отключаю прерывания, все нормально работает. Но вроде обработчик не вызывается до тех пор пока уровень не изменится на ножке PB5. Чудеса да и только)

  3. чего-то я не пойму, флаг S и N одно и то же? ведь оба знак показывают
    S это что главный флаг знака, а V и N частные случаи?
    как вообще определить отрицательность числа по двоичноми коду, ведь может быть положительное число с 1 в 7 бите

    1. По одним только флагам никогда ничего сказать определенно нельзя.

      Только в контексте предыдущей выполненной команды. А вот уже она выставляет флаги в зависимости от результатов операции.

      Знак у двоичного числа тоже никак нельзя определить в отрыве от контекста.

  4. Читал статью — возник вопрос:
    «BRMI переход если N=1
    BRPL переход если N=1»
    — как это прокоментируешь???
    p.s. спасибо за сайт!!!

  5. Опечатка похоже

    BREQ ActionA ; Переход если равно (EQual, Z=0)

    Они равны если Z=1 ведь вроде? т.е. когда из одного другое вычитаешь получаешь ноль, и Z устанавливается в ноль (Zero).

  6. Списибо. Только вот никак понять не могу, что же atmel имели в виду, когда в справке для команд ветвления написали описания типа «if(Z==1) PC = PC + k + 1». После такого логично предположить, что написав «BRCS 1» я увеличу PC на 2 в случае, если флаг поднят? Однако в эмуляторе в PC заносится 1.

  7. SBIC/SBIS Но проверяет она не биты регистров РОН, а биты регистров периферийных устройств. Те самые,что идут в памяти между блоком РОН и оперативкой. Но есть у ней ограничение — она может проверить только первые 1F регистров ввода вывода. Если заглянешь в m16def.inc (для мега16, для других МК в их файл дефайнов).
    Я смотрел в справочнике Микроконтроллеры AVR семейства Mega.djvu ( http://narod.ru/disk/7773184001/Микроконтроллеры%20AVR%20семейства%20Mega.djvu.html ) стр.237 SBIC/SBIS, ограничения там к сожалению не указаны. Не подскажете как называется Ваш справочник где указаны ограничения в командах? (по возможности где можно скачать).

    1. Прочитал где то в даташите. А вообще это понятно из двоичного кода команды, взятого в Евтсифееве из приложения. Там битами ХХХХ обозначены адреса, так что там всего пять битов адреса приходится на адрес порта, из этого следует, что адрес может быть от 00000 до 11111 т.е. от 0 до 1F

  8. DI HALT, можешь подсказать?
    У меня в программе 2 прерывания(2 таймера)
    программа крутиться в основном цикле из условных переходов BR и SBIC
    Так вот с BR проблем нет, а вот с sbis — непонятки.
    Вот кусок кода, вроде ни чего такого страшного, просто считываются биты с портов ввода-вывода(внешне подтянутые через 10к к земле, внутренняя подтяжка отключена ну и кнопка обычная на плюс)

    sbic pinc, 5 ;условный переход «кнопка режима»
    jmp mode
    sbic pinc, 4 ;условный переход «войти в настройки»
    jmp settings
    sbic pinc, 3 ;усл.пер. «спать»
    jmp sleep_on

    так вот почему-то у меня срабатывают (редко 1-2 раза в день) эти переходы и программа перебрасывается на выполнение. Ставил светодиоды дополнительные и заменял jmp на sbi, что бы быть уверенным что программа именно от туда выпрыгивает, так вот они загораются. то есть почему-то идет ложное считывание.
    Что может быть?
    Условия разные пробовал, питал от лаб. ИП, USB, даже в воздухе подвешивал и чуть ли не медным тазом накрывал.

    1. А точно ложное считывание? может что реально какая помеха дрыгает ногой? Если глюк периодически, то может его генерирует твоя же плата. Попробуй частоту понизить радикально и посмотреть что будет.

      1. Вчера ночью отключил прерывание одного из таймеров, уже 24 часа ни какого сбоя и ложного срабатывания. то есть работает как надо

        Но это ведь странно? такие переходы ведь не зависят ни от флагов(хотя я их сохраняю перед прерыванием), ни от чего вообще не зависят кроме конкретно указанного бита. да? Или есть какие-то заковырки?

        Щас попробую вернуть прерывания, изменить частоту(была 8 внутрениия), ножки четко на землю посажу без всяких резюков, что б уж наверняка не колыхалась.

        1. А атомарного доступа нигде нет? Т.е. нигде не получается, что прерывание вклинивается в обработку двубайтной переменной между первым и вторым байтом, а потом, в результате, заносится не то. А регистры сохраняешь которые в прерывании используются?

          1. да не(
            Нет ни чего такого…. в цикле у меня только условные переходы и ни какие регистры кроме флагового не используются, но его я сохраняю. С от него зависимыми br переходами собственно проблем и не было…

          2. >>>>>>
            Эмм… так вот, я изменил частоту на 4МГц и намертво повесил все кнопки на землю, за 24 часа проблем не было.
            Далее изменил частоту на 8МГц, кнопки так и остались висеть на земле, ложно сработали ВСЕ sbiс переходы! :(
            Вообще не понимаю, изменил только частоту :(

          3. ах да, оставил на ночь, утром проснулся и обнаружил что они сработали, то есть где-то за 6 часов…

          4. я отключал один таймер, тупо закомментил его иннициализацию и он не запустился само собой — ложных срабатываний не было.

            То есть отключил одно из прерываний — переходы работали правильно…

            Но блин, не пойму почему так… реально же бред :(

          5. да ну…

            ну меняет оно флаги, но я их сохраняю, записывает иногда данные в озу, все регистры у прерывания свои, больше ни где не испозуются.
            да и какая разница если эти переходы не зависят ни от чего этого.

            в общем пичаль. перепишу прогу лучше как-нибудь подругому.

            1. А то, что у тебя может быть срыв стека, например, и прога из прерывания возвращается не по тем адресам и может попасть, например, между условий. Переходы не глючат. У меня, например, никогда не было такого, чтобы sbic прощелкал когда не надо.

              Опять же как ты их сохраняешь? Какие регистры у прерывания свои?

          6. Срыва нет, там стек попросу не используется внутри прерывания…
            Ну РОН… щас точно сказать не могу, но там 3-4 средних и 1 низкий, используются они только в прерывании и нигде больше, во всяком случае мне так кажется, может я конечно чего не углядел после полной перечитки кода, но вряд ли…

            флаги сохраняю в начале и загружаю в конце

            1. Ну да, конечно. А как тогда возврат делается? Стек в прерываниях используется всегда. Покажи как флаги сохраняешь-загружаешь

          7. Эм, я знаю что возврат через стек делается) я имел ввиду что в самой программе прерывания(т.е. до reti), я стек ни как не использую.

            мб вообще весь код кинуть? куда только?

  9. В примере мелкая опечатка (мелочь, но так как это не просто текст, а пример, то может немного озадачить)

    ; В результате, все байты кроме третьего
    ; Обнулятся. А третий каким был таким и

    Там, я так понял, имеются в виду биты.

  10. да,и указывать в макросе только адресса
    переходов или подпрограмм.(если я Вас правильно понял)
    к примеру макрос ,который ожидает значение в пределах 0х30-0х3А
    (аски коды цифр ) на командах brlo и brsh

    1. Его, можно, кстати, попробовать условным сделать. Т.е. если шаг укладывается в пределах, то использовать br** если нет, то через проброс сквозь Rjmp. Но я не знаю хватит ли макропроцессору на это мозгов, он тут очень ограниченный. Условия поддерживает, но сможет ли сам вычислить смещение?

      1. Вы имеете ввиду ,проверка условия и сразу экшен ,?
        (если так ,то в экшене может испортится полученное значение для проверки, нужно будет его сохранять)

        если нетрудно напишите вашу мысль в коде(примерно)
        а я проверю

        1. Ненен я имею ввиду сделать универсальный макрос на .if директивах и проверку адреса средствами препоцессора компилятора и если требуется длинный переход компилятор сам подставит вашу конструкцию, а если короткий, то воткнет просто br** почитайте справку по компилятору avrasm и описание директив компиляции (справка вызывается в авр студио по F1)

  11. ANDI R16,1<<3
    Можно ли в этой строчке "1<<3" заменить на "0b00001000".
    Да и как вообще преобразовать двоичное число в такой вид?

    1. Можно, но зачем? Так проще и потом можно вместо цифры писать будет имя бита. А суть записи в том, что мы 1 ставим на третий разряд. Это операция сдвига на языке препроцессора компилятора.

  12. DI HALT, можешь подсказать по флагу V ? Классически переполнение контролируется по не правильному знаку результата (когда результат вычисления вылазит за разрядную сетку). Но когда я например в АВР СТУДИО на АВРе складываю два отрицательных числа -240 + -50 = -290. Результат явно вылазит за разрядную сетку (т.к. в АВР при арифметических операциях используется диапазон представления чисел +255 — -256 отриц. числа в кодах дополнения до 2 без знакового разряда). При этом (по правилам контроля переполнения )знак результата должен быть + и выставляться флаг V. Реально в sreg устанавливается флаг N т.е. минус результата и флаг V не устанавливается???!!! Аналогичный пример вычитания чисел +240 — -100 = +390. При этом знак результата должен быть минус и выставляться флаг V. Но реально в sreg устанавливается только флаг половинного переноса, а результат + и флаг V не устанавливается???!!! Получается что АВР не контролирует переполнение при арифметических операциях???!!! Или я что-то не правильно понял? Уважаемый DI HALT, если я что-то не правильно понял можешь показать на конкретном примере как АВР контролирует переполнение при арифметических операциях(т.е. выставляется флаг V)?

    И еще я заметил что АВР как-то хитро понимает отрицательные числа.Знакового разряда нет — под диапазон чисел отводятся все 8 бит РОН. Например сложить -15(0хF1) + -5(0хFB) = -20(0хEC) это все равно что сложить 241(0хF1) + 251(0хFB) = 236(0хEC) плюс перенос.В первом и во втором случае операнды, результат и флаги(S,N,V) абсолютно одинаковы!

  13. «Например, надо нам проверить состояние третьего бита в регистре UCSRC. Как видишь, это выше чем 1F Так что тест-скип не прокатит. Не беда, делай как я!»
    Почему не прокатит? Если записать значение порта в РОН, а потом применить SBRC/SBRS. Или я что-то не догнал )

  14. «В случае большой программы, чтобы не плодить островки, его лучше сделать один, сразу после пачки CP»
    Di HALT, не разжуете по поводу «пачки CP»? Что это? Четыре строки сохранения стека?

  15. Задолго до знакомства с Вашей статьей решил «переписать» потихоньку одну из конструкций, написанной на Bascom, на Асм. Типа, asm-вставка. Нарвался на грабли с BR**. Вышел из ситуации через RJMP. В железе работает шикарно!
    Суть в чем… Использовалась команда BRLO. Писал и симулировал в Bascom. Так вот, команда отказывалась перескакивать на место «приземления», если между ней и местом «посадки» было больше 48 команд. Именно команд! Считал строки с командами сразу после BRLO. Вы же, с помощью Евстифеева, утверждаете о 63 командах. Где истина?
    Подозреваю, что, скорее всего, не 63 КОМАНДЫ, а 63 ТАКТА. Возможно такое?
    P.S. К сожалению, в данный момент не могу проверить эту теорию.

    1. Atmel-0856-AVR-Instruction-Set-Manual.pdf

      Conditional relative branch. Tests the Signed Flag (S) and branches relatively to PC if S is cleared. If the
      instruction is executed immediately after any of the instructions CP, CPI, SUB, or SUBI, the branch will
      occur if and only if the signed binary number represented in Rd was greater than or equal to the signed
      binary number represented in Rr. This instruction branches relatively to PC in either direction (PC — 63 ≤
      destination ≤ PC + 64). Parameter k is the offset from PC and is represented in two’s complement form.
      (Equivalent to instruction BRBC 4,k.)

      Т.е. явно сказано в документации, что переход осуществляется на PC +/- 64 инструкции. Просто некоторые команды могут быть на два слова. А не на 1 и занимать две ячейки по счетчику PC

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha