Вот может ихз этого понятно будет как я сравнивать пытаюсь
Код:
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
тут уже не работает у меня код ---------- Sbi DDRB, LED ; LED - на вывод Sbi PORTB, LED ; Зажечь зеленый светодиод! Do: Rjmp Do ; И больше ничего не делать, до нажатия кнопки сброса SaveQuit: Reti
Заголовок сообщения: Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Вс авг 07, 2011 19:03:10
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52 Сообщений: 4468 Откуда: Главный Улей России (Moscow)
Рейтинг сообщения:0
Метод с массивами хорош тем, что так можно сравнить любое количество значений. Будь то 4 значения или 255 значений. Ну и используются для этого всего 3 регистра РОН (не считая регистровых пар Y и Z)
И ещё, Ваш код можно (вернее, нужно!) оптимизировать. Опять же, вместо километра одинаковых действий, можно сделать всего один цикл с адресацией через регистровые пары (это последние 6 регистров РОН) Старайтесь использовать ОЗУ а не рабочие регистры.
_________________ I am DX168B and this is my favourite forum on internet!
Метод с массивами хорош тем, что так можно сравнить любое количество значений. Будь то 4 значения или 255 значений. Ну и используются для этого всего 3 регистра РОН (не считая регистровых пар Y и Z)
И ещё, Ваш код можно (вернее, нужно!) оптимизировать. Опять же, вместо километра одинаковых действий, можно сделать всего один цикл с адресацией через регистровые пары (это последние 6 регистров РОН) Старайтесь использовать ОЗУ а не рабочие регистры.
Дак вот не моя программа то пытаюсь вникнуть и модифицировать под свои нужды.
.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
Во-о-от... Компактно и без использования старших регистров.
; в 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 теперь указывает на следующую команду. На неё и переходим.
Это сожрет немного больше стека и будет дольше выполняться, зато ещё немного короче Рассмотрим вызов в точку 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
Таким образом можно разменивать память данных на память кода. Когда в данных куча свободного места, а в коде несколько слов сэкономить -- за счастье.
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
после сдвига адреса в ZH:ZL влево для перехода от слов к байтам в этом месте не нужна. Если адрес кода, вызывающего данную подпрограмму, лежит в пределах младших 64 Кбайт, то старший бит адреса слова гарантированно нулевой, слов-то 32 К. И командой ROL ZH бит С будет занулён.
Для мега128* нужно будет бит С после ROL ZH перенести в RAMPZ и использовать ELPM, потом обнулить C. Для мега256* нужно будет еще позаботиться о EIND для IJMP в конце. Впрочем, для 128 и 256-килобайтных кристаллов загадить программную память на ассемблере -- это нужно уметь
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
.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 неправильно выходит из макроса. Т.е. он из него вообще не выходит, т.е. не останавливается на следующей команде. Ньда, данные после команды - для него это слишком.
Ахтунг! Подстава! Команды сдвига в конце сбрасывает SREG! Все труды функции насмарку!
А-а-а!!! Точно!
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 с выделением четрырёх байт в нужном порядке
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Последний раз редактировалось avreal Вт авг 09, 2011 00:04:11, всего редактировалось 1 раз.
Дык это-то я уже прикинул, другое дело, что в обратном порядке всё равно придется хранить константу во флеш. Технически, конечно, без разницы, но при писании кода... Хотя, что если написать макрос, типа такого:
Заголовок сообщения: Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Вт авг 09, 2011 00:04:46
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52 Сообщений: 4468 Откуда: Главный Улей России (Moscow)
Рейтинг сообщения:0
Это типа упражнения по шифрованию ПО для МК? Ну надо же - такой изврат. Хотя, иногда бывает нужным.
Засунуть массив данных посреди программы, после команды вызова, за тем достать адрес возврата из стека, через который за тем обратиться к массиву, и в конце, как прошлись по массиву, косвенным переходом вернуться к следующей инструкции после массива. Для новичков это нереальная ЖЕСТЬ. Так как мозг взорвёт по полной.
_________________ I am DX168B and this is my favourite forum on internet!
Да какое там шифрование... Банальная экономия кода Хотя у дизассемблера тоже крыша поедет, это надо грамотному дизассемблеру подсказать «а это данные». Ну, сначала самому допереть.
Но я никогда с этой целью такие фокусы не применял. «банальная экономия»
_________________ Лень в виде мании величия: «ты гений, зачем стараться?». В виде комплекса: «всё равно не выйдет, зачем упираться?». Как логика: «если достаточно, зачем знать и уметь больше?». Цель одна: остановить. Не любит тепло работающих мышц и шум работающего мозга.
Заголовок сообщения: Re: Ассемблер (ASM) для AVR в вопросах и ответах
Добавлено: Вт авг 09, 2011 00:30:04
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52 Сообщений: 4468 Откуда: Главный Улей России (Moscow)
Рейтинг сообщения:0
Ну это понятно. Но всётаки, как вы верно подметили, дизассемблер в ступор упадёт. Как бы, два зайца одним выстрелом. И экономия и защита от шаловливых ручек. Хотя, внутрисхемная отладка быстро всё разъяснит, что и как.
_________________ I am DX168B and this is my favourite forum on internet!
Последний раз редактировалось DX168B Вт авг 09, 2011 00:32:44, всего редактировалось 1 раз.
.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 всего лишь подредактировать своё сообщение (последнее сообщение в теме, но новых сообщений не было), как меня опять перекинуло! Соответственно, если новых нет (или никто не обновляет пост), то всё нормально. У кого нить такое наблюдается?
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения