Страница 98 из 400

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вс авг 07, 2011 18:45:34
sinobi
То есть организуется массив и уже массив проверяется с буфером.А я то думал чтоб пошагово по парно байты сравнивать

Код: Выделить всё

                    Save2:        
                            Cpi   R27, SER2		
		Brne Save2			
		Cpi   R26, SER1
		Brne Save2		
		Cpi   R25, SER0
		Brne Save2
			
		Cpi   R28, BUT 
		Brne Save2

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вс авг 07, 2011 18:57:07
sinobi
Вот может ихз этого понятно будет как я сравнивать пытаюсь

Код: Выделить всё

Save:						; Циклический буфер, последний принятый бит = последнему биту в массиве
		Rol R28					; BUT1
		Rol R27					; SER3
		Rol R26					; SER2
		Rol R25					; SER1
		Rol R24					; HOP4
		Rol R23					; HOP3
		Rol R22					; HOP2
		Rol R21					; HOP1
		Bld R28,0				; Записать текущий бит
		Clc						; Снять флаг переноса
		Inc   Size				; Плюс один бит
		Cpi   Size, 64			; Приняли весь пакет?
		Brne  SaveQuit			; Нет, выйти

								; А тут мы приняли все 64 бита!

		Clr   Temp				; Очистить переменную адреса, она у нас Temp
		Mov   Time, R21			; Скопировать в R17(она по совместительству Time) R21
		Rcall SaveByte			; Сохранить байт в EEPROM!
		Inc   Temp				; И так для всех 64 бит или 8 байт
		Mov   Time, R22
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R23
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R24
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R25
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R26
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R27
		Rcall SaveByte
		Inc   Temp
		Mov   Time, R28
		Rcall SaveByte


Save2:
		Cpi   R27, SER2			
		Brne Save2			 
		Cpi   R26, SER1
		Brne Save2		
		Cpi   R25, SER0
		Brne Save2
			
		Cpi   R28, BUT 
		Brne Save2

тут уже не работает у меня код ----------------------------------
		Sbi   DDRB,  LED		; LED - на вывод
		Sbi   PORTB, LED		; Зажечь зеленый светодиод!
		Do: Rjmp Do				; И больше ничего не делать, до нажатия кнопки сброса
	SaveQuit:
		Reti
	

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вс авг 07, 2011 19:03:10
DX168B
Метод с массивами хорош тем, что так можно сравнить любое количество значений. Будь то 4 значения или 255 значений. Ну и используются для этого всего 3 регистра РОН (не считая регистровых пар Y и Z)

И ещё, Ваш код можно (вернее, нужно!) оптимизировать. Опять же, вместо километра одинаковых действий, можно сделать всего один цикл с адресацией через регистровые пары (это последние 6 регистров РОН) Старайтесь использовать ОЗУ а не рабочие регистры.

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вс авг 07, 2011 19:45:22
sinobi
DX168B писал(а):Метод с массивами хорош тем, что так можно сравнить любое количество значений. Будь то 4 значения или 255 значений. Ну и используются для этого всего 3 регистра РОН (не считая регистровых пар Y и Z)

И ещё, Ваш код можно (вернее, нужно!) оптимизировать. Опять же, вместо километра одинаковых действий, можно сделать всего один цикл с адресацией через регистровые пары (это последние 6 регистров РОН) Старайтесь использовать ОЗУ а не рабочие регистры.
Дак вот не моя программа то пытаюсь вникнуть и модифицировать под свои нужды.

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вс авг 07, 2011 20:55:56
IfoR
ИМХО, раз уж на то пошло (сравнение переменных в памяти), то можно сделать так (вспомнив один приёмчик одного человека):

Код: Выделить всё

.Equ SER0=0xCC
.Equ SER1=0x87
.Equ SER2=0x7F
.Equ BUT=0x9B

.dseg
buffer: .byte 4
; ...

.cseg
; ...
; Где-то в основной программе
     ldi     YL, low(buffer)     ; загружаем адрес сравниваемой переменной
     ldi     YH, high(buffer)
     rcall     compare          ; вызываем функцию сравнения.
     .db     SER0, SER1, SER2, BUT    ; Это второй параметр-константа функции сравнения
     breq     on_led           ; Если числа равны, то включаем светодиод
; ...

; где-то ниже
; функция сравнения 4-байтного числа
; в Y хранится адрес сравниваемого числа в ОЗУ
compare:
     pop     ZH     ; грузим адрес константы во FLASH
     pop     ZL
     clc               ; сбрасываем флаг переноса
     rcall     compareByte     ; сравниваем 4 байта
     rcall     compareByte
     rcall     compareByte
     rcall     compareByte
     ijmp             ; Z теперь указывает на следующую команду. На неё и переходим.

compareByte:
     ld     R0, Y+
     lpm     R1, Z+
     cpc     R0, R1
     ret
Во-о-от... Компактно и без использования старших регистров. :tea: :)

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 03:16:56
sinobi
Большое спасибо-постараюсь применить :))

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 15:17:33
avreal
IfoR писал(а):

Код: Выделить всё

; в Y хранится адрес сравниваемого числа в ОЗУ
compare:
     pop     ZH     ; грузим адрес константы во FLASH
     pop     ZL
     clc               ; сбрасываем флаг переноса
     rcall     compareByte     ; сравниваем 4 байта
     rcall     compareByte
     rcall     compareByte
     rcall     compareByte
     ijmp             ; Z теперь указывает на следующую команду. На неё и переходим.
Вот тут немного неточно - надо перейти сначала от слов к байтам и потом вернуться назад. Поскольку тут всегда чётное количество байтов после вызова, возвращаться можно без округления вверх.

Код: Выделить всё

; в Y хранится адрес сравниваемого числа в ОЗУ
compare:
     pop     ZH     ; грузим адрес константы во FLASH
     pop     ZL
     lsl     ZL    ;; Переходим от слов к байтам
     rol     ZH
     clc               ; сбрасываем флаг переноса
     rcall     compareByte     ; сравниваем 4 байта
     rcall     compareByte
     rcall     compareByte
     rcall     compareByte
     lsr    ZH    ;; Переходим от байтов к словам
     rol    ZL
     ijmp             ; Z теперь указывает на следующую команду. На неё и переходим.
Ещё один приёмчик есть.
Вместо

Код: Выделить всё

    . . .
     rcall     compareByte     ; сравниваем 4 байта
     rcall     compareByte
     rcall     compareByte
     rcall     compareByte
     ijmp 
    . . .

compareByte:
     ld     R0, Y+
     lpm     R1, Z+
     cpc     R0, R1
     ret
Можно написать

Код: Выделить всё

    . . .
     rcall     compareByte_4     ; сравниваем 4 байта
     ijmp 
    . . .

compareByte_4:
    rcall  compareByte_2
compareByte_2:
    rcall  compareByte
compareByte:
     ld      R0, Y+    //*
     lpm     R1, Z+    //*
     cpc     R0, R1    //*
     ret
Это сожрет немного больше стека и будет дольше выполняться, зато ещё немного короче :-)
Рассмотрим вызов в точку compareByte_2
На стеке лежит адрес возврата туда, откуда это вызвали. Но тут же делается вызов rcall compareByte и на стеке при выполнении compareByte лежит два адреса возврата. Выполняются помеченные строки и ret по последнему сохранённому на стеке адресу возвращает на точку после rcall compareByte. Т.е. -- опять на начало compareByte. Помеченные строки выполняются еще раз, но теперь ret использует следующий адрес на стеке и возвращает в исходне место в программе. Т.е. вызов в точку compareByte_2 займёт на стеке два слова, а не одно, но выполнит тело подпрограммы compareByte два раза.
Аналогично, вызов в точку compareByte_4 займёт на стеке три слова, а не одно, как для rcall compareByte, но зато выполнит тело четыре раза. Добавление еще метки compareByte_8 и соответствующего вызова добавит ещё один уровень, будет 4 слова на стеке и 8-кратное выполнение.
Для сравнения 10 байт тогда надо будет написать

Код: Выделить всё

    rcall compareByte_8
    rcall comapreByte_2
Таким образом можно разменивать память данных на память кода. Когда в данных куча свободного места, а в коде несколько слов сэкономить -- за счастье.

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 16:48:01
sinobi
Да сложновато пока для меня,но буду вникать :))

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 19:50:01
IfoR
avreal, да, точно. Спасибо за поправку. :)

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 20:56:54
avreal
Да, «чуть не забыл»™
Строка

Код: Выделить всё

     clc               ; сбрасываем флаг переноса
после сдвига адреса в ZH:ZL влево для перехода от слов к байтам в этом месте не нужна.
Если адрес кода, вызывающего данную подпрограмму, лежит в пределах младших 64 Кбайт, то старший бит адреса слова гарантированно нулевой, слов-то 32 К. И командой ROL ZH бит С будет занулён.

Для мега128* нужно будет бит С после ROL ZH перенести в RAMPZ и использовать ELPM, потом обнулить C.
Для мега256* нужно будет еще позаботиться о EIND для IJMP в конце.
Впрочем, для 128 и 256-килобайтных кристаллов загадить программную память на ассемблере -- это нужно уметь :)))

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 22:08:36
Мастер Ломастер
avreal писал(а):зато ещё немного короче :-)
а если оформить в виде макроса, то совсем хорошо будет :)

Код: Выделить всё

.macro compare4byte; формат: compare4byte ramaddr, const
   ldi     YL, low(@0)     ; загружаем адрес сравниваемой переменной
   ldi     YH, high(@0)
   rcall   compare         ; вызываем функцию сравнения.
   .dd     @1                 ; Это второй параметр-константа функции сравнения
.endm
пример использования

Код: Выделить всё

   .dseg
var1:   .byte   4
   .cseg
   compare4byte   var1, 0x12345678

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 22:54:49
IfoR
Ахтунг! Подстава! Команды сдвига в конце сбрасывает SREG! Все труды функции насмарку! :facepalm: :cry:

Итак. С учётом всех поправок, представляю следующий вариант:

Код: Выделить всё

.macro cpsli; формат: cpsli ramaddr, const
   ldi     YL, low(@0)     ; загружаем адрес сравниваемой переменной
   ldi     YH, high(@0)
   rcall   compare         ; вызываем функцию сравнения.
   .dd     @1                 ; Это второй параметр-константа функции сравнения
.endm

.Equ SER0=0xCC
.Equ SER1=0x87
.Equ SER2=0x7F
.Equ BUT=0x9B

.dseg
buffer: .byte 4
; ...

.cseg
; ...
; Где-то в основной программе
     cpsli    buffer, (SER0<<24) | (SER1<<16) | (SER2<<8) | BUT
     breq     on_led           ; Если числа равны, то включаем светодиод
; ...

; где-то ниже
; функция сравнения 4-байтного числа
; в Y хранится адрес сравниваемого числа в ОЗУ
compare:
     pop     ZH     ; грузим адрес константы во FLASH
     pop     ZL
     adiw     Z, 2     ; перепрыгиваем через 2 байта
     push     ZL     ; грузим адрес следующей команды
     push     ZH
     sbiw     Z, 2
     lsl     ZL    ;; Переходим от слов к байтам
     rol     ZH
     rcall     compareByte2     ; сравниваем 4 байта
compareByte2:
     rcall     compareByte
compareByte:
     ld     R0, Y+
     lpm     R1, Z+
     cpc     R0, R1
     ret    ; этот ret многое значит...

Мне кажется, тут прям есть элементы рекурсии. :)
По расчётам такой макрос будет выполняться 68 тактов.
Размер: 13 слов
Использует R0, R1, Y и Z
Берёт 3 слова в стеке.

Сможем сделать лучше? :)

Кстати, все заметили, что для правильной работы функции при количественном сравнении значений, все значения нужно хранить в обратном порядке байт (в памяти сначала идут младшие байты)? :)
Эх... Если бы можно было бы сделать "lpm R1, -Z", то можно было бы безболезненно переписать функцию под прямой порядок. Был вариант поменять "cpc R0, R1" на "cpc R1, R0", но как оказалось, это не правильно.

P.S. lol ли, но симулятор AVR Studio при попытки прогнать этот макрос по F10 неправильно выходит из макроса. Т.е. он из него вообще не выходит, т.е. не останавливается на следующей команде. :))) Ньда, данные после команды - для него это слишком. :)

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Пн авг 08, 2011 23:54:08
avreal
IfoR писал(а):Ахтунг! Подстава! Команды сдвига в конце сбрасывает SREG! Все труды функции насмарку! :facepalm: :cry:
А-а-а!!! Точно!
IfoR писал(а):Кстати, все заметили, что для правильной работы функции при количественном сравнении значений, все значения нужно хранить в обратном порядке байт (в памяти сначала идут младшие байты)? :)
Эх... Если бы можно было бы сделать "lpm R1, -Z", то можно было бы безболезненно переписать функцию под
Зато можно сделать LD R0,-Y
Так что добавить ADIW Y, 4 где-то ещё перед POP ZH и идти по оперативной памяти назад, а по флешу вперёд.

Код: Выделить всё

     ld     R0, -Y
     lpm     R1, Z+
     cpc     R0, R1
upd: Но это только если сравнение только на равенство нужно. Если на больше-меньше, то, конечно, шара не катит.

upd2: Никто не мешает в макросе не .dd написать, а .db с выделением четрырёх байт в нужном порядке

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:03:33
IfoR
Дык это-то я уже прикинул, другое дело, что в обратном порядке всё равно придется хранить константу во флеш. Технически, конечно, без разницы, но при писании кода... Хотя, что если написать макрос, типа такого:

Код: Выделить всё

#define _(x) ((x&0xFF)<<24 | ((x>>8)&0xFF)<<16 | ((x>>16)&0xFF)<<8 | (x>>24)) 
Тогда можно писать так:

Код: Выделить всё

cpsli     buffer, _(0x123456FE)
P.S.
По поводу апдейта. Ну да, или в макрос:

Код: Выделить всё

.macro cpli; формат: cpli ramaddr, const
   ldi     YL, low(@0)     ; загружаем адрес сравниваемой переменной
   ldi     YH, high(@0)
   rcall   compare         ; вызываем функцию сравнения.
   .db     @1&0xFF, (@1>>8)&0xFF, (@1>>16)&0xFF, @1>>24                 ; Это второй параметр-константа функции сравнения
.endm

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:04:46
DX168B
Это типа упражнения по шифрованию ПО для МК? :))) :))) :))) :)))
Ну надо же - такой изврат. :))) Хотя, иногда бывает нужным. :)

Засунуть массив данных посреди программы, после команды вызова, за тем достать адрес возврата из стека, через который за тем обратиться к массиву, и в конце, как прошлись по массиву, косвенным переходом вернуться к следующей инструкции после массива. Для новичков это нереальная ЖЕСТЬ. Так как мозг взорвёт по полной. :))) :beer:

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:26:14
avreal
Да какое там шифрование...
Банальная экономия кода :-)
Хотя у дизассемблера тоже крыша поедет, это надо грамотному дизассемблеру подсказать «а это данные». Ну, сначала самому допереть.

Но я никогда с этой целью такие фокусы не применял. «банальная экономия»

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:30:04
DX168B
Ну это понятно. Но всётаки, как вы верно подметили, дизассемблер в ступор упадёт. :)
Как бы, два зайца одним выстрелом. И экономия и защита от шаловливых ручек. Хотя, внутрисхемная отладка быстро всё разъяснит, что и как. :)

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:31:09
IfoR
Итак, теперь более корректная функция:

Код: Выделить всё

.macro cpsli; формат: cpsli ramaddr, const
   ldi     YL, low(@0)     ; загружаем адрес сравниваемой переменной
   ldi     YH, high(@0)
   rcall   compare         ; вызываем функцию сравнения.
   .db     @1&0xFF, (@1>>8)&0xFF, (@1>>16)&0xFF, @1>>24                 ; Это второй параметр-константа функции сравнения
.endm

.Equ SER0=0xCC
.Equ SER1=0x87
.Equ SER2=0x7F
.Equ BUT=0x9B

.dseg
buffer: .byte 4
; ...

.cseg
; ...
; Где-то в основной программе
     cpsli    buffer, (SER0<<24) | (SER1<<16) | (SER2<<8) | BUT
     breq     on_led           ; Если числа равны, то включаем светодиод
; ...

; где-то ниже
; функция сравнения 4-байтного числа
; в Y хранится адрес сравниваемого числа в ОЗУ
compare:
     pop     ZH     ; грузим адрес константы во FLASH
     pop     ZL
     adiw     Z, 2     ; перепрыгиваем через 2 байта
     push     ZL     ; грузим адрес слудующей команды
     push     ZH
     sbiw	Z, 2
     adiw	Y, 4
     lsl     ZL    ;; Переходим от слов к байтам
     rol     ZH
     rcall     compareByte2     ; сравниваем 4 байта
compareByte2:
     rcall     compareByte
compareByte:
     ld     R0, -Y
     lpm     R1, Z+
     cpc     R0, R1
     ret    ; этот ret многое значит..
Что-то меня это операчии +2, -2 напрягают. Что-то много их. :)

DX168B, в ассемблере нет извращений. :)

Кстати, тут вспомнил один приём антидизассемблеринга применяющийся в x86: команда внутри команды. Суть в том, что каким нибуть переходом (желательно косвенным и неявным) происходит переход не на саму какую-нить безобидную команду, после которой находится код для отвода глаз, а куда-то в её центр, а там, например, переход на скрытый код внутри мусора. Естественно, дизассемблер такое фиг найдёт сам. Да и самому это не так просто заметить. Думаю, на AVR так же можно спрятать rjmp внутри какой нибудь lds. :))

На правах оффтопа. Люди, у вас эта тема нормально работает? Дело в том, что у меня такой глюк. Когда я жму на кнопочку "новые сообщения" для этой темы, меня часто бросает не на последнюю страницу, где эти сообщения, а на 2-3 страницы назад на их начало. Иногда бывает, что перебрасывает правильно. Такое же бы бывает, если я просто обновляю страницу, когда на этой же появляется новое сообщение. Меня так же ни за что перекидывает на 2-3 страницы назад и приходится возвращаться.
Мало того, только что заметил, достаточно было DX168B всего лишь подредактировать своё сообщение (последнее сообщение в теме, но новых сообщений не было), как меня опять перекинуло! :shock:
Соответственно, если новых нет (или никто не обновляет пост), то всё нормально.
У кого нить такое наблюдается?

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:34:30
DX168B
Да, кстати.... у меня такой же прикол именно с этой темой. Надо написать админам в Жалобы и предложения.

Ifor
Я процитировал ваш пост и разместил его в теме.

Re: Ассемблер (ASM) для AVR в вопросах и ответах

Добавлено: Вт авг 09, 2011 00:44:58
IfoR
Да, я уже писал. Мне разрешили поофтопить на эту тему здесь в поисках соиглючников. :)
Тот пост оставь. :)