По-моему всё очевидно и давно разжевано.
Ассемблер (ASM) для AVR в вопросах и ответах
- Сообщения: 606
- Зарегистрирован: Вт июн 25, 2013 18:45:07
Дело в том, что CPC практически не используется без CP. Если бы флаг Z у CPC изменялся всегда, то нельзя бы было эту инструкцию использовать по прямому назначению для сравнения чисел большой разрядности. Например, сравните 0x5000 0x5050. Сначала СР сравним младшие байты, Z=0, а потом СРС сравним старшие. Если бы CPC выдавала зеро флаг только основываясь на текущем результате, то мы бы имели Z=1, что означало бы равенство неравных 16-битных чисел, а так Z=0*Z = 0*1 = 0, и это правильно.
По-моему всё очевидно и давно разжевано.
По-моему всё очевидно и давно разжевано.
- Реклама
Понятно, что шина 8 битная, но в примере сравнивается 16 битное число, ну это в принципе не важно, пусть будет сколько угодно команд сравнения n-битного числа, решающая команда все равно последняя, последняя это та, после которой вы собираетесь что-то сделать по условию, именно последняя команда устанавливает результирующие флаги. Можно проверить сбросив или установив флаг нуля, т.к. про него разговор, перед последней командой сравнения, результат на выходе будет одинаковый.Z_h_e писал(а):Так нет в AVR 16 битных регистров, ибо шина 8ми битная.
Попробуйте написать код сравнения чисел (т.е. из первого вычесть второе) , пускай будут они равны 0x0100 и 0x0001 и сделать переход по неравенству. Сколько у Вас будет команд, если флаг Z меняется "классически" не только для CP, но и CPC?
Для примера: в первом и втором случае на выходе ничего не изменится, в данном случае нельзя трогать только флаг переноса.
Код: Выделить всё
; Compare r3:r2 with r1:r0
cp r2,r0 ; Compare low byte
clz
cpc r3,r1 ; Compare high byte
brne noteq ; Branch if not equalКод: Выделить всё
; Compare r3:r2 with r1:r0
cp r2,r0 ; Compare low byte
sez
cpc r3,r1 ; Compare high byte
brne noteq ; Branch if not equalЯ Вам же не зря предложил сравнить два числа. 0x0100 и 0x0001.
Предположим команды СP и CPC устанавливают флаг одинаково и всегда.
Напишу код сравнения, но без регистров, а сразу значение из них.
Результат первой команды: Z=0,C=1
Результат второй, которая почему то решила устанавливать флаги так же как первая: Z=1, C=0
Результат третей, это прыжок , как будто бы 16ти битные числа равны, а они не равны.
Вот потому команда CPC умеет только сбрасывать Z если не равно, и оставлять его предыдущим значением если равно. Это и позволяет сравнивать большие числа малым числом команд.
Предположим команды СP и CPC устанавливают флаг одинаково и всегда.
Напишу код сравнения, но без регистров, а сразу значение из них.
Код: Выделить всё
CP 0x00,0x01
CPC 0x01,0x00
breq RAVNOРезультат второй, которая почему то решила устанавливать флаги так же как первая: Z=1, C=0
Результат третей, это прыжок , как будто бы 16ти битные числа равны, а они не равны.
Вот потому команда CPC умеет только сбрасывать Z если не равно, и оставлять его предыдущим значением если равно. Это и позволяет сравнивать большие числа малым числом команд.
Ну почему же? Как бы ни менялся этот флаг у этих команд, он на их результаты никак не влияет. CPC при выполнении учитывает только флаг С, ну а то, что она ещё и на Z влияет, не важно, т.к. его для вычислений не использует.Z_h_e писал(а):Если бы флаг Z у команды CPC изменялся также как и у CP,т.е. всегда.
То весь Ваш код был бы не рабочим.
P.S. Тут лучше, конечно, BRCC/BRCS использовать вместо BREQ/BRNE, вообще игнорируя Z, который при сравнении многобайтовых слов, в принципе, не нужен.
Только повторить написанное.
Вот так устанавливает флаг Z команда CPC
Z= R7 ¯ • R6 ¯ • R5 ¯ • R4 ¯• R3 ¯ • R2 ¯ • R1 ¯ • R0 ¯ • Z
Если бы флаг Z устанавливался всегда командой CPC, без учета его предыдущего значения флага Z, то связкаZ_h_e писал(а):Смысл данного выражения в том, что команды типа SBC, CPC сбрасывают Z, если результат не равен нулю, а если результат нулевой, то во флаг Z будет записано его предыдущее состояние.
Код: Выделить всё
СP
CPC
CPC
...Я даже привел пример с конкретным числом.
Как на равенство проверять с помощью флага С?P.S. Тут лучше, конечно, BRCC/BRCS использовать вместо BREQ/BRNE, вообще игнорируя Z, который при сравнении многобайтовых слов, в принципе, не нужен.
- Реклама
А до этого что было нелогично?
Да, тут я с BREQ/BRNE, пожалуй, несколько ошибся. Одного флага будет недостаточно, например, для чисел вроде 0x5678 и 0x5531 (младшие байты не равны, старшие отличаются на 1) будет ошибочно воспринято равенство. 0x78..0x31 установят C, а 0x56..0x55+1 ошибочно его снимут.Z_h_e писал(а): Как на равенство проверять с помощью флага С?
- Сообщения: 31
- Зарегистрирован: Сб сен 17, 2016 18:56:30
Выше в этой ветке я приводил ещё пример использования особенности флага С.dimmer писал(а): В Атмелевском файле AVR202.asm представлена идиома "Negate a 16-bit Register Variable":на самом деле можно сделать короче:Код: Выделить всё
com ng1l com ng1h subi ng1l,low(-1) sbci ng1h,high(-1)Код: Выделить всё
neg ng1h neg ng1l sbci ng1h,0
Как проверять на равенство... да много байтев...
адрес массива в указатель (X,Y,Z)
какой-нить счетчик количества байт cntb...
ну и покатились...
как-то и без срс и размер массива побольше...
примерно таким же манером и по регистровому файлу пройтись можно
одначе собственно по случаю размещения данных в регистровом файле конструкция с срс более оптимальна...

dimmer
"0 - число" не одно и то же, что "число - 0"...
ежли уж "сокращать"
так используя то, что система команд АВР для двухбайтовых значений надурняк предоставляет
разместив ng1h:ng1l где-нибудь в парах R25:R24, R27:R26, R29:R28 или R31:R30.
НО... поскольку последние три индекс-указатели, то для двухбайтовых и прочих фоуксов весьма напрашивается R25:R24 с выделением этой пары с отметкой "псевдобазовый регистр"...

адрес массива в указатель (X,Y,Z)
какой-нить счетчик количества байт cntb...
ну и покатились...
Код: Выделить всё
loop_cp:
ld r16,x+
ld r17,y+
spse r16,r17
rjmp error
dec cntb
brne loop_cp
return ; or rjmp adr
error:
обрабатываем ошибкупримерно таким же манером и по регистровому файлу пройтись можно
Код: Выделить всё
cpse r16,r17
rjmp error
cpse r14,r15
rjmp error
нормальное завершение...dimmer
"0 - число" не одно и то же, что "число - 0"...
ежли уж "сокращать"
Код: Выделить всё
com ng1l
com ng1h
subi ng1l,low(-1)
sbci ng1h,high(-1)Код: Выделить всё
com ng1l
com ng1h
adiw ng1l,1НО... поскольку последние три индекс-указатели, то для двухбайтовых и прочих фоуксов весьма напрашивается R25:R24 с выделением этой пары с отметкой "псевдобазовый регистр"...
- Сообщения: 31
- Зарегистрирован: Сб сен 17, 2016 18:56:30
Мой вариант работает с любой парой регистров старшей половины. Не вижу смысла делать себе тесно. А что такое "псевдобазовый регистр"?
Команда CPSE сравнивает регистры, НЕ меняя флаги. Бывает полезно. По мне, лучше определить конец массива, по которому определять окончание процедуры. Тогда и счетчик cntb не нужен.BOB51 писал(а):Как проверять на равенство... да много байтев...
адрес массива в указатель (X,Y,Z)
какой-нить счетчик количества байт cntb...
ну и покатились...как-то и без срс и размер массива побольше...Код: Выделить всё
loop_cp: ld r16,x+ ld r17,y+ CPSE R16,R17 ;имелась в виду spse r16,r17 rjmp error dec cntb brne loop_cp return ; or rjmp adr error: обрабатываем ошибку
Код: Выделить всё
loop_cp:
ld r6,x+
ld r7,y+
CP R6,R7
BRNE ERROR ;здесь ставится любой(ые) BRxx
CPI YL,LOW(BUFER_END)
BRLO loop_cp
; dec cntb
; brne loop_cp
return ; or rjmp adr
error:
обрабатываем ошибку- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Это в случае когда массив не пересекает переход старшего байта через 0, а это в общем случае неверно. Тем более для ассемблерной вставки, когда массив ей предоставляется языком высокого уровня и неизвестно заранее куда он его распределил.
А в таком случае придется проверять оба байта, то есть нет выигрыша ни по скорости, ни по ОЗУ. Выигрыш будет либо при ручном распределении памяти, либо если размер массива больше 256 байт, либо на младших моделях, где меньше 256 байт ОЗУ.
А в таком случае придется проверять оба байта, то есть нет выигрыша ни по скорости, ни по ОЗУ. Выигрыш будет либо при ручном распределении памяти, либо если размер массива больше 256 байт, либо на младших моделях, где меньше 256 байт ОЗУ.
Код: Выделить всё
ldi temp, high(BUF_END)
cpi YL, low(BUF_END)
cpc YH,temp
brne loop_cpЕсли Вы про флаг C, то в данном циклическом алгоритме он и не нужен. Достаточно определить любую пару неравных регистров (или ее не найти), чтобы понять равные ли области памяти или нет. Так что алгоритм с командой CPSE в цикле рабочий.COKPOWEHEU писал(а):Это в случае когда массив не пересекает переход старшего байта через 0, а это в общем случае неверно.
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Можно еще глупость спрошу?
просто, когда я задаю здесь вопросы, то их надо написать, а когда пишешь, то их приходится понятно формулировать, а когда понятно формулируешь, часто ответ сам находится. .
Короче, можно ли в АВР загрузить в ОЗУ некоторый массив данных (довольно много, но определенный) из ФЛЕШа, а потом его тупо с какого-либо адреса начать читать и с легкой обработкой выдавать ПОБИТНО (последовательно) в порт? Или вообще без обработки отдавать ПОБИТНО в порт? Ну, например, пошли нули, то и вывод порта в нуле, пошли единицы - переключился в единицу...
понимаю, что это не СТМ32, у которого всякие DMI или как их там...
просто, когда я задаю здесь вопросы, то их надо написать, а когда пишешь, то их приходится понятно формулировать, а когда понятно формулируешь, часто ответ сам находится. .
Короче, можно ли в АВР загрузить в ОЗУ некоторый массив данных (довольно много, но определенный) из ФЛЕШа, а потом его тупо с какого-либо адреса начать читать и с легкой обработкой выдавать ПОБИТНО (последовательно) в порт? Или вообще без обработки отдавать ПОБИТНО в порт? Ну, например, пошли нули, то и вывод порта в нуле, пошли единицы - переключился в единицу...
понимаю, что это не СТМ32, у которого всякие DMI или как их там...
Станислав
Конечно можно. Вот моя подпрограмма для печати строки, находящейся во флеш. Вам нужно делать также, только полученные данные не печатать, а помещать в ОЗУ.СКАЗОЧНИК писал(а):Короче, можно ли в АВР загрузить в ОЗУ некоторый массив данных (довольно много, но определенный) из ФЛЕШа, а потом его тупо с какого-либо адреса начать читать и с легкой обработкой выдавать ПОБИТНО (последовательно) в порт? Или вообще без обработки отдавать ПОБИТНО в порт?
Спойлер
Код: Выделить всё
;Подпрограмма вывода строки, хранящейся в программной памяти
;В регистровой паре Z начало строки, в регистре R19 адрес первой позиции вывода в строке дисплея
PRNSTR: push R18 ;
lsl ZL ;Умножить адрес начала строки на 2, так как доступ нужно
rol ZH ;осуществлять побайтно
PRNS1: lpm R18,Z+ ;Занести в R18 байт из памяти программ, содержащий код выводимого символа
cpi R18,$0 ;Сравнение с нулем - кодом конца строки
brne PRNS2 ;Если принят не нуль, то переход на метку PRNS1
pop R18
ret ;Строка напечатана, выход из подпрограммы
PRNS2: rcall PRNSYM ;Печать символа, хранящегося в R18, в позицию, адрес которой в R19
inc R19 ;Увеличение адреса для вывода следующего символа
rjmp PRNS1 ;Возврат на метку PRNSTRНаписать подпрограмму, выдвигающую байт побитно в порт (на один из выводов порта) элементарноСКАЗОЧНИК писал(а):Ну, например, пошли нули, то и вывод порта в нуле, пошли единицы - переключился в единицу...
Только надо протокол продумать - нужны ли старт-стоповые биты и т.д.
Ежли сразу из флешки - скорость значительно ниже максимально возможной.
Это ежли только при внешнем параллельном ОЗУ (флешка с параллельным доступом) - тогда еще вписаться в максимум скорости можно.
СКАЗОЧНИК
Речь как я понял о тех же WS2812B?
я ж вроде уже ссыль на исходник того алгоритма давал...
Там побитовая передача ШИМ 1/3-2/3 причем желательно без накопления "лишнего времени".
И никаких стартовых/стоповых - гонится массив по три байта на каждый светик без каких-либо разделителей и/или разрывов передачи.
Весьма тоскная задачка...

Это ежли только при внешнем параллельном ОЗУ (флешка с параллельным доступом) - тогда еще вписаться в максимум скорости можно.
СКАЗОЧНИК
Речь как я понял о тех же WS2812B?
я ж вроде уже ссыль на исходник того алгоритма давал...
Там побитовая передача ШИМ 1/3-2/3 причем желательно без накопления "лишнего времени".
И никаких стартовых/стоповых - гонится массив по три байта на каждый светик без каких-либо разделителей и/или разрывов передачи.
Весьма тоскная задачка...
Да, про них...
Вашу реализацию уже изучал. Для меня замудрено.
Смысл ихнего протокола понимаю и скорости тоже. Сейчас попробую реализовать сам, посчитать все задержки, такты, циклы... А потом уже дальше с вопросами приду.
Вашу реализацию уже изучал. Для меня замудрено.
Смысл ихнего протокола понимаю и скорости тоже. Сейчас попробую реализовать сам, посчитать все задержки, такты, циклы... А потом уже дальше с вопросами приду.
Станислав
Не надо ничего там менять - программно более оптимальный вариант не получится - скорость там на пределе возможного (разве что только частоту еще до 20МГц поднять - рассчет велся/проверялся под 16МГц для внутреннего RC генератора) там в одном из последних слотов и так все такты выбраны.
Можно как в "типовых решениях" грузить рутину на SPI или USART -но там предварительное дробление для каждого байта и выбор лапок ограничен аппаратными "традициями".

Можно как в "типовых решениях" грузить рутину на SPI или USART -но там предварительное дробление для каждого байта и выбор лапок ограничен аппаратными "традициями".



