|
Ещё раз о бутлоадере, Некоторые тонкости. |
|
|
|
 |
Ответов
(1 - 59)
|
Oct 4 2007, 09:37
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SasaVitebsk @ Oct 4 2007, 12:17)  Хотелось бы использовать незадействованные вектора бутлоадера. Например +2. Как это сделать. Если использовать pragma location, то наверняка будет linker ругаться. Конечно можно упростить задачу и использовать какой нибудь признак в EEPROM. Или портить CRC к примеру, но что-то мне не нравится такой подход. Есть некая нога, которую приложение всегда настраивает на вывод. Например выход USART или нога, на которой висит светодиод. После сброса все порты гарантировано настроены на ввод. Значит, используюя даже одну точку входа по направлению этой ноги можем судить - мы попали по сбросу или по переходу из приложения. По второму вопросу: в коде пишем Код extern void BootLoader(); В командной строке линкера добавляем -DBootLoader=0x1800 или в .xcl дописываем -DBootLoader=0x1800. Все. в приложении делаем dir_out(MANUAL_PROG); __disable_interrupt(); BootLoader(); На всякий случай в __low_level_init() лодыря сразу же запретить прерывания и переключить вектора на лодырь (если используются).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 9 2007, 07:28
|

Местный
  
Группа: Свой
Сообщений: 232
Регистрация: 26-02-07
Из: г. Зеленоград
Пользователь №: 25 669

|
Цитата(SasaVitebsk @ Oct 4 2007, 13:17)  Задумка такая.
По старту попадаем в бут. Там считаем CRC и если Ok - выходим на саму приложение. Если не Ok то переходим на сам лодырь.
В приложении по команде переходим непосредственно на лоадырь. То есть мне надо две точки входа. По сбросу и по команде. Хотелось бы использовать незадействованные вектора бутлоадера. Например +2. Как это сделать. Если использовать pragma location, то наверняка будет linker ругаться.
Конечно можно упростить задачу и использовать какой нибудь признак в EEPROM. Или портить CRC к примеру, но что-то мне не нравится такой подход.
А кто как делает? Добавлю и я свои наработки: 1. Использовать ногу процессора - метод надежный, но IMHO это будет "жирновато", ног не всегда хватает+на плате надо вешать на эту ногу резюк, кроме того в разных проектах это могут быть разные ноги. 2. Вариант с EEPROM более предпочтителен, поскольку 1-й старт после прошивки программатором BootLoader-a всегда будет на него. Тогда при отладке приложения работа будет такой: а) - загрузка приложения б) подача BootLoader-у команды передать управление на приложение, т.е. на адрес 0x0000 После отладки - прописать в EEPROM признак: сразу после Reset передавать управление на приложение. Правда здесь есть один подводный камень - зависание приложения или необходимость его коррекции. Здесь можно использовать такой метод: Если в течении, например 1-ой минуты проходит не менее 10-ти горячих рестартов, то в EEPROM устанавливается признак блокировки перехода на приложение.
--------------------
Вяжешь - вой, а поедешь - песни пой. Между "хочу" и "можно" всегда есть дистанция
|
|
|
|
|
Oct 9 2007, 10:45
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(IJAR @ Oct 9 2007, 10:28)  1. Использовать ногу процессора - метод надежный, но IMHO это будет "жирновато", ног не всегда хватает+на плате надо вешать на эту ногу резюк, кроме того в разных проектах это могут быть разные ноги. Используется нога, которая в приложении выполняет какую-либо функцию. Например выход UART или выход на светодиод. Подтяжка желательна, но это может быть штатная подтяжка (например подтяжка CS внешнего устройства или тот же светодиод). В разных проектах пишется #define MANUAL_PROG C,3,L или #define MANUAL_PROG B,0,H
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 9 2007, 11:40
|

Местный
  
Группа: Свой
Сообщений: 232
Регистрация: 26-02-07
Из: г. Зеленоград
Пользователь №: 25 669

|
Цитата(Сергей Борщ @ Oct 4 2007, 13:37)  Есть некая нога, которую приложение всегда настраивает на вывод. Например выход USART или нога, на которой висит светодиод. После сброса все порты гарантировано настроены на ввод. Значит, используюя даже одну точку входа по направлению этой ноги можем судить - мы попали по сбросу или по переходу из приложения. А какой смысл возврата в BootLoader из приложения? Как я понимаю, по Reset всегда на BL а далее разбор: пользоваться ли его услугами или сразу перейти к выполнению приложения. Может я что-то "не догоняю".
--------------------
Вяжешь - вой, а поедешь - песни пой. Между "хочу" и "можно" всегда есть дистанция
|
|
|
|
|
Oct 9 2007, 12:01
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(IJAR @ Oct 9 2007, 14:40)  А какой смысл возврата в BootLoader из приложения? Чтобы обновлять ПО по команде извне по интерфейсу связи. Это удобно как для устройств, находящихся в труднодоступных местах, так и для устройств на столе - для перепрошивки их не нужно вскрывать чтобы замкнуть джампер. Протокол связи поддерживается приложением, оно получает команду "обновление", передает управление в загрузчик, загрузчик формирует ответ "к загрузке готов" в соответствии с протоколом связи. Если же мы стартанули загрузчик принудительно или приложения нет/не сошлась контрольная сумма, то загрузчик сам ожидает команду "обновление" (и это единственная команда из всего протокола, которая в нем реализована).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 9 2007, 12:33
|

Местный
  
Группа: Свой
Сообщений: 232
Регистрация: 26-02-07
Из: г. Зеленоград
Пользователь №: 25 669

|
Цитата(Сергей Борщ @ Oct 9 2007, 16:01)  Чтобы обновлять ПО по команде извне по интерфейсу связи. Это удобно как для устройств, находящихся в труднодоступных местах, так и для устройств на столе - для перепрошивки их не нужно вскрывать чтобы замкнуть джампер. Протокол связи поддерживается приложением, оно получает команду "обновление", передает управление в загрузчик, загрузчик формирует ответ "к загрузке готов" в соответствии с протоколом связи. Если же мы стартанули загрузчик принудительно или приложения нет/не сошлась контрольная сумма, то загрузчик сам ожидает команду "обновление" (и это единственная команда из всего протокола, которая в нем реализована). Логично! Но есть один недостаток: приложение должно поддерживать протокол (иметь возможно лишний программный код) . А если приложение пишет другой программист, не разработчик BL или вообще в другой конторе (например у потребителя устройства). Ему же надо все описать, что он должен сделать.
--------------------
Вяжешь - вой, а поедешь - песни пой. Между "хочу" и "можно" всегда есть дистанция
|
|
|
|
|
Oct 9 2007, 14:33
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(IJAR @ Oct 9 2007, 15:33)  Но есть один недостаток: приложение должно поддерживать протокол (иметь возможно лишний программный код). Да, есть такое. Но если какой-то интерфейс с внешним миром есть, обычно поверх него есть и какой-то протокол. Добавить в него одну команду обычно несложно. Если интерфейса нет (точнее он не выведен наружу) - ну остается джампер на плате. Цитата(IJAR @ Oct 9 2007, 15:33)  А если приложение пишет другой программист, не разработчик BL или вообще в другой конторе (например у потребителя устройства). Ему же надо все описать, что он должен сделать. Да. Описываю так: 1) запретить прерывания 2)настроить ногу X на вывод. 3) перейти по адресу 0x1800. В общем главное - что мы друг друга поняли.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 9 2007, 23:55
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Сергей, всётаки по коду не уложился в 2к. Со своим WakeUp-ом. Там ещё некоторые приколы есть. У меня должно осуществляться обновление прямо в сети. Соответственно при обновлении требуется сверять серийный номер устройства. Его я не хочу записывать в лоадер, дабы лоадер унифицированный был. Поэтому при перепрошивке вытаскиваю номер перепрошиваю и сохраняю номер.  Короче впрямую в 2к не влез. В связи с тем, что сам протокол Wake, если работать ч/з прерывания, практически не связан с лоадером - переписал его на ASM. Думаю так влезу. Но вот возник вопрос. там есть конструкция в лоадере если помнишь. typedef union { struct { uint8_t m_rxBuffer[BUFFER_SIZE]; // Receive buffer uint8_t m_pageBuffer[PAGE_SIZE]; // Page is assembled here before // getting programmed to flash mem } part1; #define rxBuffer sharedbufs.part1.m_rxBuffer Честно говоря смысл её не всосал. Чтобы к одному и тому же участку памяти под разными именами обращаться, что ли. Но у меня с ней проблемы на ASM. Не могу понять как на ASM указать адрес начала буфера приёмного (rxBuffer)??? Сори.  Разобрался. Просто как-то в голове не укладывается как в ассемблере имена структур фигурируют. Понятно что потом линкер их к адресам приводит, но всё равно несколько диковато.
|
|
|
|
|
Oct 10 2007, 10:58
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SasaVitebsk @ Oct 10 2007, 02:55)  Сергей, всётаки по коду не уложился в 2к. Со своим WakeUp-ом. Ты пытаешься засунуть в загрузчик еще какие-то команды кроме UpdateFirmware? У меня Wake-подобный протокол, я сделал так: Код static unsigned char busReceiveByte(void) { uint8_t c = UART_getchar(); if(c == CTL) c = UART_getchar() ^ 0x20; return c; } __C_task void main(void) { ....... if(!dir(MANUAL_PROG)) { uint8_t command[7]; command[0] = 0xC0; // Begin Of Frame uint16_t Tmp = SerialNo(); command[1] = Tmp; command[2] = Tmp >> 8; command[3] = 0xFF; uint8_t *ptr = &command[1]; Tmp = 0xFFFF; Tmp = CRC_XMODEM (*ptr++, Tmp); Tmp = CRC_XMODEM (*ptr++, Tmp); Tmp = CRC_XMODEM (*ptr++, Tmp); command[4] = ~Tmp; command[5] = ~(Tmp >> 8); command[6] = 0xC1; // End Of Frame uint8_t idx = 0; do { uint8_t c = busReceiveByte();
if(c != command[idx]) idx = 0; else idx++; } while(idx < sizeof(command)); // wait for EOM } busReplyByte(ERROR_OK); Т.е. я формирую образ всей команды и сравниваю проходящий поток с образцом. Сгенерить образец гораздо проще, чем реализовывать весь конечный автомат приема. Увы, это проходит только для одной команды. Цитата(SasaVitebsk @ Oct 10 2007, 02:55)  Соответственно при обновлении требуется сверять серийный номер устройства. Его я не хочу записывать в лоадер, дабы лоадер унифицированный был. Поэтому при перепрошивке вытаскиваю номер перепрошиваю и сохраняю номер.  У меня в области загрузчика есть функция Код #pragma segment="GET_SERIAL" #pragma location="GET_SERIAL" __root uint16_t SerialNo(void) { return ~0;} При прошивке я указываю AvRealу -c?serno2=1826,serno.txt и он автоматически при программировании подставляет в эту функцию уникальные номера. Номер хранится в загрузчике и не может быть случайно стерт с приложением. Функцию SerialNo() можно вызвать и из приложения, поэтому и приложение становится независимым от серийника. Функция занимает 6 байт, что меньше чем код для чтения 16-битной константы из флеш с помощью LPM Цитата(SasaVitebsk @ Oct 10 2007, 02:55)  Честно говоря смысл её не всосал. Чтобы к одному и тому же участку памяти под разными именами обращаться, что ли. Именно так. Для улучшения читабельности. Т.е. "сейчас мы работаем с этим блоком как с буфером приема" Цитата(SasaVitebsk @ Oct 10 2007, 02:55)  Сори.  Разобрался. Просто как-то в голове не укладывается как в ассемблере имена структур фигурируют. Понятно что потом линкер их к адресам приводит, но всё равно несколько диковато.  Ну, если не на плюсах писать, то имена как и у обычных переменных. А вот к полям из ассемблера, увы, только вручную указывая смещение от начала структуры.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 10 2007, 13:35
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Сергей Борщ @ Oct 10 2007, 13:58)  Ты пытаешься засунуть в загрузчик еще какие-то команды кроме UpdateFirmware? У меня Wake-подобный протокол, я сделал так: Пытаюсь Сергей.  Вчера в 3 часа ночи получил результат 2232.  Если бы надо было байт 50 выжать ещё бы попытался, а так буду пробовать в обход. Я видишь ли с прерываниями завязался. Возможно придётся отказаться. Только вектора занимают 112 байт. Можно конечно их под себя подмять. Короче буду думу думать. Жалко выделять 4к если нехватает совсем чуть чуть. Спасибо за рекомендации. Разбираюсь. Пользуюсь. Помагает.
|
|
|
|
|
Oct 10 2007, 15:46
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SasaVitebsk @ Oct 10 2007, 16:35)  Пытаюсь Сергей. . Интересно, какие? Мне пока в голову приходила всего одна команда, полезная в загрузчике - запрос версии. Приложение отвечает свою версию, загрузчик отвечает 0. Тогда центральный узел понимает, что приложение ёк и его надо перешить обязательно. А по ответу приложения о версии центральный узел может определять - нужно ли апгрейдить. Планирую реализовать. Думаю, что второй массив с образцом команды и поиск по нему как в примере выше не сильно раздует код. А на какие запросы у тебя отвечает загрузчик? Цитата(SasaVitebsk @ Oct 10 2007, 16:35)  Только вектора занимают 112 байт. Можно конечно их под себя подмять. "Не только мона, но и нуна!" А как в .xcl сегменты распределяются? Я отдаю под код все после последнего используемого вектора: Код // Interrupt vectors -Z(CODE)INTVEC=1800-1825 // Code memory -Z(CODE)NEAR_F,HUGE_F,SWITCH,INITTAB,DIFUNCT,CODE=1802-1FFF -Z(CODE)GET_SERIAL,GET_AREA#1802-1FFF Хм. Скопировал сюда и призадумался - зачем указываю 0x1802, ведь 0x1800 всегда занят... Можно писать 1800-1FFF. Цитата(SasaVitebsk @ Oct 10 2007, 16:35)  Жалко выделять 4к если нехватает совсем чуть чуть. "Вам то хорошо..." (с) "Операция "С Новым Годом"". Вот если бы было 2 и не больше, как в m8, это бы еще сильнее стимулировало
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 10 2007, 16:42
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Сергей Борщ @ Oct 10 2007, 18:46)  ... А на какие запросы у тебя отвечает загрузчик?" ... При наличии в сети разных устройств кроме текущей версии нужно знать еще и тип устройства, чтобы прошивку от БМВ не прошить в Боинг То есть желательно иметь команду запроса типа устройства по данному адресу. Но мы тоже экономили команды, и тип устройства содержится в нулевой странице по фиксированному адресу - то есть сравнивает типы устройств бутлоадер, и он уникальный для каждого типа устройств (если контроллер одинаковый - отличие в строке символов, определяющей тип).
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Oct 10 2007, 16:57
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Dog Pawlowa @ Oct 10 2007, 19:42)  При наличии в сети разных устройств кроме текущей версии нужно знать еще и тип устройства, чтобы прошивку от БМВ не прошить в Боинг  А, ну да. У меня тип отвечается вместе с версией, поэтому я о нем и не подумал. Хорошо, все необходимые данные загрузчик может отдавать в одном ответе. Обзовем это "запросом конфигурации". Какие еще команды должен поддерживать загрузчик? И понятное дело - для разных типов и даже для одного типа, но несовместимых версий железа разные ключи шифрования, так что БМВ не взлетит
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 12 2007, 11:04
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Waso @ Oct 12 2007, 11:36)  Я планирую через ftp заливать (декриптовать находу) бинарник в свободную часть флеши и, после успешной проверки CRC, переписывать reset-вектор чтобы он указывал на начало этого бинарника. Это очень плохая идея - переписывать вектора. Потому что обязательно в этот момент произойдет сбой питания и устройство окажется неработоспособным. Вектор сброса должен указывать на неизменяемую часть кода (бутлодер), который определяет куда передать управление дальше. Для остальных векторов я использую ремап. Цитата(Waso @ Oct 12 2007, 11:36)  А бутлодер нужен, насколько я понимаю, чтобы переписывать прошивку поверх старой, и данные при этом брать из внешнего источника. Вовсе нет - бутлодер - это общее название (части)программы, предназначенной для обновления прошивки.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 16 2007, 18:01
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Oct 10 2007, 17:35)  Вчера в 3 часа ночи получил результат 2232.  Если бы надо было байт 50 выжать ещё бы попытался, а так буду пробовать в обход. Я видишь ли с прерываниями завязался. Возможно придётся отказаться. Только вектора занимают 112 байт. Можно конечно их под себя подмять. Короче буду думу думать. Жалко выделять 4к если нехватает совсем чуть чуть. SasaVitebsk, а Вы принципиально не будете пробовать Gcc ? Стало интересно, посмотрел на исходники, ну этот код, особенно aes.c просто предназначен для компилирования gcc  на Iar там принципиально хуже... P.S. Еще очень порадовало обращение к EEPROM переменным через функции писанные на асм... Интересно, почему на Iar не воспользовались __eeprom ???
|
|
|
|
|
Oct 16 2007, 20:58
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
2 singlskv. Не планирую переходить на GCC. Работы завались и времени на изучение новых пакетов банально не хватает. Тем более, что я пробовал с ним работать вначале. Мне не понравилось, что по сути это не один продукт а десятки слабоинтегрированных фичей. Я, безусловно, не претендую даже на коментарии к этому продукту. Просто высказываю своё первое впечатление. Я уже обратил внимание, что есть специалисты, которым такое построение нравится. Они берут компилятор с одного источника линкер с другого, редактор с третьего а отладчик с четвёртого. Наверное это правильно. Возможно я до этого дойду, но пока - не готов. __eeprom пользуюсь. Ассемблерный файл spm выкинул и пользуюсь IARовскими приблудами. Благо Сергей Борщ предложил свой вариант. Спасибо ему. Кто-нибудь прогу по расчёту CRC от IAR смог повторить? Что-то у меня в лоб не заработало, а подбирать на CRC - гиблый номер. Легче свою сварганить. Я пробовал так. Вроде именно так они рекомендуют. Не причёсывал. Чтобы максимально близко к данному варианту было. Потом перепишу. Код #define POLY 0x11021
inline unsigned long crc16(int bit, unsigned long oldcrc) { unsigned long newcrc = (oldcrc << 1) ^ bit; if (oldcrc & 0x80000000) newcrc ^= POLY; return newcrc; }
__C_task void main(void) { __disable_interrupt();
#ifdef CRC_CHECK // Считаем CRC всей памяти флэш unsigned long crc = 0; unsigned char i,j; unsigned char APPFLASH *p = (unsigned char APPFLASH *)0x000000; unsigned char APPFLASH *n = (unsigned char APPFLASH *)MEM_SIZE; do { j= *p++; for(i=0;i<8;i++) { crc = crc16(j & 1,crc); j>>=1; } } while (--n); // Если секция программ повреждена // то переходим к загрузке в бутлоадер if (crc) ((void (*)())loader)(); // Переходим на сам загрузчик #endif ((void (*)())0x0000)(); // Если с CRC всё нормально, то перейдём в начало // секции программ }
|
|
|
|
|
Oct 17 2007, 09:56
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(singlskv @ Oct 16 2007, 21:01)  Стало интересно, посмотрел на исходники, ну этот код, особенно aes.c просто предназначен для компилирования gcc  Ну так а что на "посмотрел" остановились? Попробуйте откомпилировать gcc, увидите, что без основательной "правки напильником" gcc дает в полтора раза бОльший код. И максимальная разница как раз на aes.c. Цитата(SasaVitebsk @ Oct 16 2007, 23:58)  0x80000000 великовато. Должно быть что-то около 0x10000. Попробуй такой вариант: Код /* uint16_t CRC (uint16_t crc, uint8_t data) { static const unsigned short crcPoly = 0x1021; crc ^= (uint16_t)data << 8; for(uint8_t i = 0; i < 8; i++) { if ( crc & (1<<15) ) { crc <<= 1; crc ^= crcPoly; } else crc <<= 1; } return crc; } */
uint16_t CRC(uint16_t crc, uint8_t data) { static const unsigned short crcPoly = 0x1021; uint32_t m = ((uint32_t)crc << 8) | data; for (uint8_t i = 0; i < 8; i++) if ((m <<= 1) & 0x1000000) m ^= ((uint32_t)crcPoly << 8);
return (uint16_t)(m >> 8); } Первый вариант эффективнее на 8/16-битной архитектуре, второй - на 32-битной. Считает сразу весь байт.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 17 2007, 20:29
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Oct 17 2007, 00:58)  __eeprom пользуюсь. Ассемблерный файл spm выкинул и пользуюсь IARовскими приблудами. Благо Сергей Борщ предложил свой вариант. Спасибо ему. Ну если Вы так оптимизируете свой код, то в 2K точно будет сложно влезть... Цитата Кто-нибудь прогу по расчёту CRC от IAR смог повторить? Что-то у меня в лоб не заработало, а подбирать на CRC - гиблый номер. Легче свою сварганить. По расчету CRC16 опять же гляньте как это реализованно в Gcc, там есть встроенная функция тактов на 40 (по длинне правда с циклом не сравнивал, меня скорость обычно больше волнует). Цитата(Сергей Борщ @ Oct 17 2007, 13:56)  Ну так а что на "посмотрел" остановились? Попробуйте откомпилировать gcc, увидите, что без основательной "правки напильником" gcc дает в полтора раза бОльший код. И максимальная разница как раз на aes.c. Кто бы спорил ? Там вобще все написано левой ногой, и то что Iar справился соптимизировать этот код лучше, еще ни о чем не говорит. Я говорил лишь о том что данный алгоритм больше подходит для Gcc, и Ваш пост: Цитата(Сергей Борщ @ Oct 4 2007, 16:42)  Да. Проц - мега8. ключ 256 бит. компилятор - 4.10B. Объем кода - 1974, но есть куда ужимать. Та же мега8, WinAVR, 1888, но другой протокол команды входа в программирование и сильное ужимание. косвенно это подтверждает.
|
|
|
|
|
Oct 17 2007, 20:57
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Oct 18 2007, 00:47)  Т.е. IAR даже "алгоритм больше подхоящий для GCC" скомпилировал лучше  . Но это "ни о чем не говорит"  . Жаль  Опять вырывем фразу из контекста ? В этом Вы несомненно мастер !!! Хотите посоревноваться в оптимизации кода ? или просто поболтать ?
|
|
|
|
|
Oct 17 2007, 21:12
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Oct 17 2007, 23:57)  Опять вырывем фразу из контекста ? Контекста? Контекста собственно и не наблюдается вообще никакого. Только совет использовать GNU по причине того, что aes.c и GNU якобы созданы друг для друга. Цитата Хотите посоревноваться в оптимизации кода ? Можете начинать, если хотите. Понаблюдаю. Объект aes.c есть. Цель - достичь минимального обьема кода - поставлена. Цитата или просто поболтать ? Вот как раз против болтовни и хотелось выступить.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 17 2007, 21:53
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Oct 18 2007, 01:12)  Контекста? Контекста собственно и не наблюдается вообще никакого. Только совет использовать GNU по причине того, что aes.c и GNU якобы созданы друг для друга. Можете начинать, если хотите. Понаблюдаю. Объект aes.c есть. Цель - достичь минимального обьема кода - поставлена. Дык понаблюдаю или поучаствую ??? Цитата Вот как раз против болтовни и хотелось выступить. Те кто только наблюдают, и высказывают свое мнение в стиле, "а IAR все равно круче", ИМХО, как раз и занимаются болтовней... Готовы поучаствовать ? Кажись Вы уже этот исходник уже используете ? Скомпилируйте его для какой-нить меги и выложите сюда. Я соптимизрую для Gcc и тоже выложу сюда.
|
|
|
|
|
Oct 17 2007, 22:04
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Oct 18 2007, 00:53)  Скомпилируйте его для какой-нить меги и выложите сюда. Легко. Тупо без затей взял из атмеловского AN Код aes.c iccavr.exe D:\ARM_WORK\0\0BACKUP\loader.9\0\Source Code\IAR\aes.c --cpu=m128 -ms -o D:\ARM_WORK\0\0BACKUP\loader.9\0\Source Code\IAR\Release\Obj\ --diag_suppress Pe1053 -y --initializers_in_flash -z9 --no_tbaa --cross_call_passes=1 -DENABLE_BIT_DEFINITIONS -e -I D:\IAR\Embedded Workbench\avr\INC\ -I D:\ IAR\Embedded Workbench\avr\INC\CLIB\ --eeprom_size 4096 IAR Atmel AVR C/C++ Compiler V4.30A/W32, Evaluation Version Copyright 1996-2007 IAR Systems. All rights reserved. 1 096 bytes of CODE memory (+ 7 bytes shared) 522 bytes of DATA memory Цитата(singlskv @ Oct 18 2007, 00:53)  Я соптимизрую для Gcc и тоже выложу сюда. Нет уж, для начала оставте в неприкосновенности. Потом, можете хоть ручками на ASM переписывать
Прикрепленные файлы
aes.rar ( 3.51 килобайт )
Кол-во скачиваний: 57
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 17 2007, 22:24
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Oct 18 2007, 02:04)  Легко. Тупо без затей взял из атмеловского AN Нет уж, для начала оставте в неприкосновенности. Потом, можете хоть ручками на ASM переписывать  Ок, не обещаю что очень быстро выложу результаты(работать тоже иногда нужно  ) а портировать просто на Gcc без изменения кода там тоже прилично... для адекватного сравнения предлягаю добавить минимальную прогу которая будет вызывать aesInit() и aesDecrypt() для какого-нить буфера.
|
|
|
|
|
Oct 17 2007, 22:35
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Oct 18 2007, 01:24)  а портировать просто на Gcc без изменения кода там тоже прилично... В aes.c ничего специфичного для какого-либо компилятора. Изменения в исходнике практически не нужны. Откомпилируйте только его - 5 минут работы. Примеры: Код wcc -omsn -d0 -s aes.c Open Watcom C16 Optimizing Compiler Version 1.7 Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved. Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details. aes.c: 387 lines, included 124, 0 warnings, 0 errors Code size: 1308 Код iccarm.exe D:\ARM_WORK\LOADER\AES\aes.c -lC D:\ARM_WORK\LOADER\Works\List\ --remarks --diag_suppress Pe1422,Pe1375 -o D:\ARM_WORK\LOADER\ Works\Obj\ --endian little --cpu ARM7TDMI-S -e --require_prototypes --fpu None --dlib_config D:\ARM_WORK\LOADER\RESOURCE\dlib_cfg.h -I D:\ARM_WORK\ LOADER\AES\ -I D:\ARM_WORK\LOADER\FLASH\ -I D:\ARM_WORK\LOADER\..\common\INCLUDE\ -I D:\ARM_WORK\LOADER\ -I D:\IAR\Embedded Workbench 5\ ARM\INC\ --cpu_mode thumb -Ohz IAR ARM ANSI C/C++ Compiler V5.10.2.372/W32 EVALUATION Copyright 1999-2007 IAR Systems. All rights reserved. 1 076 bytes of CODE memory 36 bytes of CONST memory 532 bytes of DATA memory
Сообщение отредактировал zltigo - Oct 18 2007, 07:38
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 17 2007, 22:55
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Oct 18 2007, 02:35)  В aes.c ничего специфичного для какого-либо компилятора. Изменения в исходнике практически не нужны. Откомпилируйте только его - 5 минут работы. Пример: Код Open Watcom C16 Optimizing Compiler Version 1.7 Portions Copyright (c) 1984-2002 Sybase, Inc. All Rights Reserved. Source code is available under the Sybase Open Watcom Public License. See http://www.openwatcom.org/ for details. aes.c: 387 lines, included 124, 0 warnings, 0 errors Code size: 1429 Не, тока завтра смогу, там нужно __flash на PROGMEM менять аккуратненько.... сегодня я уже не в силах этим заниматься ...
|
|
|
|
|
Oct 18 2007, 19:35
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(singlskv @ Oct 17 2007, 23:29)  Ну если Вы так оптимизируете свой код, то в 2K точно будет сложно влезть... По расчету CRC16 опять же гляньте как это реализовано в Gcc, там есть встроенная функция тактов на 40 (по длинне правда с циклом не сравнивал, меня скорость обычно больше волнует). Уважаемый. Бут оптимизируется по коду. В программе встречается 1 вызов п/п чтения EEPROM и 1 вызов записи. Библиотеки на Яре написаны на Асме. Я их смотрел, и честно говоря в 5 операторах ассемблера не нашёл ничего из ряда вон. Да и был бы очень удивлён если бы нашёл. Так ответьте мне причём здесь применение данных п/п к оптимизации. Совершенно очевидно что на этих двух вызовах можно сэкономить ну от силы пару байтов. Речь вначале шла о сотне! То же касается и CRC16. Я не спрашивал как её написать оптимально. Я не думаю, что написанное мной на ассемблере будет хуже вашего. Во всяком случае значительно. Я просто интересовался как именно IAR генерит CRC. Я переписал на АСМ весь свой WAKE протокол и думаю всётаки влезть в 2к. Переписал потому, что всё это реализовано по прерываниям и логически вообще не связано с самим бутом. Подытоживая всё выше сказанное, хочется чтобы вы более конкретно обдумывали свои посты. ========================================== Теперь по существу вопроса. Пишу это, так как только на этой странице уже поднимался вопрос по генерации CRC IARом. И думаю люди будут как и я пытаться его использовать. Для тех кто интересуется сообщаю следующее. При размещении CRC по разным адресам сам CRC не меняется. Из чего я делаю вывод (возможно некорректный, но это то что первое приходит в голову), что CRC считается только CODE области и размещается где указано. Это не позволяет мне его использовать так как я хочу. Наверное есть опция какая-то, но я не разобрался. Решил написать программу, которая будет считать CRC и вставлять её в нужное место прямо в HEX файле. Постораюсь написать её максимально универсально, причесать и выложить на форуме AVR для использования желающими. Ещё один момент - прога CREATE из набора идущего к AES. В ней есть хомут. При размещении данных (CRC) в последних двух ячейках секции пользователя CREATE начинает кричать оверлапинг. При размещении CRC на две ячейки меньше, выполняет операцию, но в прошивке вы получите дополнительно два байта мусора. Исходники там приведены, но я не стал разбираться, так как всё равно не чем её откомпилить. В принципе это не страшно, просто поясняю для того, кто пойдёт по моим стопам.  У меня - всё работает. Спасибо всем тем кто принял участие в обсуждении. Особенное спасибо Сергей Борщ за, просто неоценимую, конкретную помощь знающего человека. Тему не закрываю, возможно ещё что возникнет. Влезу или не влезу, для любопытных - напишу позже.  .
|
|
|
|
|
Oct 18 2007, 20:40
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(SasaVitebsk @ Oct 18 2007, 22:35)  так как всё равно не чем её откомпилить. Dev C++В комплекте исходников идут и файлы проекта под этот компилятор. Цитата(SasaVitebsk @ Oct 18 2007, 22:35)  Ещё один момент - прога CREATE из набора идущего к AES. В ней есть хомут. При размещении данных (CRC) в последних двух ячейках секции пользователя CREATE начинает кричать оверлапинг. При размещении CRC на две ячейки меньше, выполняет операцию, но в прошивке вы получите дополнительно два байта мусора. Естественно, потому что CREATE сама считает CRC (по полиному 0x8005) и располагает его в последних двух байтах секции приложения. Поэтому меня несколько ввело в замешательство ваше желание считать CRC при помощи линкера. При этом CREATE кoрректо считает все свободные ячейки заполненными 0xFFFF, в то время как линкер считает, что все свободные места между сегментами заполнены нулями.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 18 2007, 22:05
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(SasaVitebsk @ Oct 18 2007, 22:35)  Наверное есть опция какая-то, но я не разобрался. Естественно CRC вполне управляемо. Цитата Решил написать программу, которая будет.... Сергей тоже пошел по такому пути не желая  разбиратся с линкером. Я пользую линкер. Цитата Исходники там приведены, но я не стал разбираться, так как всё равно не чем её откомпилить. Исходники страшноваты, но GCC компилит. Я из них многое выкинул и дополнил.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 18 2007, 22:48
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
To zltigo и SasaVitebsk, признаю, погорячился насчет перевода всего бутлодера под Gcc и cравнения с IAR. Просто после более подробного изучения кода стало понятно что его нужно переписывать с нуля, а это займет прилично времени... Цитата(SasaVitebsk @ Oct 18 2007, 23:35)  Речь вначале шла о сотне! Ну а чтобы было понятно о чем была речь приведу небольшой пример по оптимизации этого кода: Было: Код void InvMixColumn( byte * column ) { byte r0, r1, r2, r3;
r0 = column[1] ^ column[2] ^ column[3]; r1 = column[0] ^ column[2] ^ column[3]; r2 = column[0] ^ column[1] ^ column[3]; r3 = column[0] ^ column[1] ^ column[2];
column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0); column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0); column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0); column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);
r0 ^= column[0] ^ column[1]; r1 ^= column[1] ^ column[2]; r2 ^= column[2] ^ column[3]; r3 ^= column[0] ^ column[3];
column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0); column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0); column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0); column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);
r0 ^= column[0] ^ column[2]; r1 ^= column[1] ^ column[3]; r2 ^= column[0] ^ column[2]; r3 ^= column[1] ^ column[3];
column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0); column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0); column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0); column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);
column[0] ^= column[1] ^ column[2] ^ column[3]; r0 ^= column[0]; r1 ^= column[0]; r2 ^= column[0]; r3 ^= column[0];
column[0] = r0; column[1] = r1; column[2] = r2; column[3] = r3; } Стало: Код void InvMixColumn( byte * column ) { byte r0, r1, r2, r3; byte co0 = column[0],co1=column[1],co2=column[2],co3=column[3]; byte bpoly = BPOLY;
r0 = co1 ^ co2 ^ co3; r1 = co0 ^ co2 ^ co3; r2 = co0 ^ co1 ^ co3; r3 = co0 ^ co1 ^ co2;
co0 = (co0 << 1) ^ (co0 & 0x80 ? bpoly : 0); co1 = (co1 << 1) ^ (co1 & 0x80 ? bpoly : 0); co2 = (co2 << 1) ^ (co2 & 0x80 ? bpoly : 0); co3 = (co3 << 1) ^ (co3 & 0x80 ? bpoly : 0);
r0 ^= co0 ^ co1; r1 ^= co1 ^ co2; r2 ^= co2 ^ co3; r3 ^= co0 ^ co3;
co0 = (co0 << 1) ^ (co0 & 0x80 ? bpoly : 0); co1 = (co1 << 1) ^ (co1 & 0x80 ? bpoly : 0); co2 = (co2 << 1) ^ (co2 & 0x80 ? bpoly : 0); co3 = (co3 << 1) ^ (co3 & 0x80 ? bpoly : 0);
r0 ^= co0 ^ co2; r1 ^= co1 ^ co3; r2 ^= co0 ^ co2; r3 ^= co1 ^ co3;
co0 = (co0 << 1) ^ (co0 & 0x80 ? bpoly : 0); co1 = (co1 << 1) ^ (co1 & 0x80 ? bpoly : 0); co2 = (co2 << 1) ^ (co2 & 0x80 ? bpoly : 0); co3 = (co3 << 1) ^ (co3 & 0x80 ? bpoly : 0);
co0 ^= co1 ^ co2 ^ co3; r0 ^= co0; r1 ^= co0; r2 ^= co0; r3 ^= co0;
column[0] = r0; column[1] = r1; column[2] = r2; column[3] = r3; } Это примерно 120байтов экономии только на одной функции  Спросите причем сдесь GCC ? Ну если спросите, тогда и отвечу...
|
|
|
|
|
Oct 19 2007, 07:37
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(singlskv @ Oct 19 2007, 02:48)  Ну а чтобы было понятно о чем была речь приведу небольшой пример по оптимизации этого кода: Было: ... Стало: ... Это примерно 120байтов экономии только на одной функции  Ради прикола взял два этих куска и откомпилил. То что было, переименовал в InvMixColumn2. На IAR AVR с максимальной оптимизацией по скорости получил: InvMixColumn2(unsigned char *) 320 InvMixColumn(unsigned char *) 332 Т.е., на 12 лишних байт вы соптимизировали  Мораль сей басни - оптимизировать низкоуровневые вещи должен компилятор, ему то в 95% случаев надо эту оптимизацию и доверить...
Прикрепленные файлы
test.txt ( 24.39 килобайт )
Кол-во скачиваний: 157
|
|
|
|
|
Oct 19 2007, 08:01
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Непомнящий Евгений @ Oct 19 2007, 10:37)  На IAR AVR с максимальной оптимизацией по скорости получил: Попробуйте по размеру, думаю эффект будет побольше, даже для IAR. Цитата(Непомнящий Евгений @ Oct 19 2007, 10:37)  Мораль сей басни - оптимизировать низкоуровневые вещи должен компилятор, ему то в 95% случаев надо эту оптимизацию и доверить... Не совcем так - при этом надо ему явно НЕ мешать, что встречается очень часто, особенно при портировании.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 19 2007, 15:08
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Непомнящий Евгений @ Oct 19 2007, 11:37)  Т.е., на 12 лишних байт вы соптимизировали  Мораль сей басни - оптимизировать низкоуровневые вещи должен компилятор, ему то в 95% случаев надо эту оптимизацию и доверить... Цитата(Непомнящий Евгений @ Oct 19 2007, 12:33)  Если максимальная оптимизация по размеру, то первый вариант весит 312 байт, второй - 192. Тут действительно вылезают обещанные singlskv 120 байт. А осадок то остался... © (не мой)  На самом деле в первом варианте "по скорости", IAR просто переклинило по какой-то только ему ведомой причине. Так иногда бывает с компиляторами.
|
|
|
|
|
Oct 21 2007, 17:28
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Oct 21 2007, 00:07)  По сравнению с вариантом от Сергей Борщ, любезно им предоставленном мне, проигрыш вашего варианта оптимизации на этой подпрограмме составил 26 байт. Хотя честно говоря я не понимаю почему. Я оптимизировал прерывания примерно вашим способом. Видимо знаний компилятора недостаточно. Мой вариант, это еще был не "мой" вариант, к реальной оптимизации я просто не приступал так, показал направление .... Вам нравится IAR ? Хорошо, будет для IAR: Код 143 144 __z void InvMixColumn1( byte * column ,byte bpoly_); 145
\ In segment CODE, align 2, keep-with-next 146 __z void InvMixColumn(byte *column) \ InvMixColumn: 147 { 148 InvMixColumn1( column ,BPOLY); \ 00000000 E10B LDI R16, 27 \ 00000002 REQUIRE InvMixColumn1 \ 00000002 ; // Fall through to label InvMixColumn1 149 }
\ In segment CODE, align 2, keep-with-next 150 __z void InvMixColumn1( byte * column ,byte bpoly) \ InvMixColumn1: 151 { 152 byte r0, r1, r2, r3; 153 byte co0 = column[0],co1=column[1],co2=column[2],co3=column[3]; \ 00000000 8110 LD R17, Z \ 00000002 8121 LDD R18, Z+1 \ 00000004 8132 LDD R19, Z+2 \ 00000006 8143 LDD R20, Z+3 154 byte tmp; 155 156 r0 = co1 ^ co2 ^ co3; \ 00000008 2F53 MOV R21, R19 \ 0000000A 2752 EOR R21, R18 \ 0000000C 2754 EOR R21, R20 157 r1 = co0 ^ co2 ^ co3; \ 0000000E 2F63 MOV R22, R19 \ 00000010 2761 EOR R22, R17 \ 00000012 2764 EOR R22, R20 158 tmp = r0 ^ r1; \ 00000014 2F76 MOV R23, R22 \ 00000016 2775 EOR R23, R21 159 r2 = tmp ^ co3; \ 00000018 2E04 MOV R0, R20 \ 0000001A 2607 EOR R0, R23 160 r3 = tmp ^ co2; \ 0000001C 2E13 MOV R1, R19 \ 0000001E .... RCALL ?Subroutine0 161 162 co0 = (tmp=co0) << 1; 163 if ((tmp & 0x80)==0x80) co0 ^= bpoly; 164 co1 = (tmp=co1) << 1; 165 if ((tmp & 0x80)==0x80) co1 ^= bpoly; 166 co2 = (tmp=co2) << 1; 167 if ((tmp & 0x80)==0x80) co2 ^= bpoly; 168 co3 = (tmp=co3) << 1; 169 if ((tmp & 0x80)==0x80) co3 ^= bpoly; 170 171 r0 ^= co0 ^ co1; \ ??CrossCallReturnLabel_0: \ 00000020 2F72 MOV R23, R18 \ 00000022 2771 EOR R23, R17 \ 00000024 2757 EOR R21, R23 172 r1 ^= co1 ^ co2; \ 00000026 2F73 MOV R23, R19 \ 00000028 2772 EOR R23, R18 \ 0000002A 2767 EOR R22, R23 173 r2 ^= co2 ^ co3; \ 0000002C 2F74 MOV R23, R20 \ 0000002E 2773 EOR R23, R19 \ 00000030 2607 EOR R0, R23 174 r3 ^= co0 ^ co3; \ 00000032 2F74 MOV R23, R20 \ 00000034 2771 EOR R23, R17 \ 00000036 .... RCALL ?Subroutine0 175 176 co0 = (tmp=co0) << 1; 177 if ((tmp & 0x80)==0x80) co0 ^= bpoly; 178 co1 = (tmp=co1) << 1; 179 if ((tmp & 0x80)==0x80) co1 ^= bpoly; 180 co2 = (tmp=co2) << 1; 181 if ((tmp & 0x80)==0x80) co2 ^= bpoly; 182 co3 = (tmp=co3) << 1; 183 if ((tmp & 0x80)==0x80) co3 ^= bpoly; 184 185 r0 ^= co0 ^ co2; \ ??CrossCallReturnLabel_1: \ 00000038 2F73 MOV R23, R19 \ 0000003A 2771 EOR R23, R17 \ 0000003C 2757 EOR R21, R23 186 r1 ^= co1 ^ co3; \ 0000003E 2F74 MOV R23, R20 \ 00000040 2772 EOR R23, R18 \ 00000042 2767 EOR R22, R23 187 r2 ^= co0 ^ co2; \ 00000044 2F73 MOV R23, R19 \ 00000046 2771 EOR R23, R17 \ 00000048 2607 EOR R0, R23 188 r3 ^= co1 ^ co3; \ 0000004A 2F74 MOV R23, R20 \ 0000004C 2772 EOR R23, R18 \ 0000004E .... RCALL ?Subroutine0 189 190 co0 = (tmp=co0) << 1; 191 if ((tmp & 0x80)==0x80) co0 ^= bpoly; 192 co1 = (tmp=co1) << 1; 193 if ((tmp & 0x80)==0x80) co1 ^= bpoly; 194 co2 = (tmp=co2) << 1; 195 if ((tmp & 0x80)==0x80) co2 ^= bpoly; 196 co3 = (tmp=co3) << 1; 197 if ((tmp & 0x80)==0x80) co3 ^= bpoly; 198 199 tmp=co0 ^ co1 ^ co2 ^ co3; \ ??CrossCallReturnLabel_2: \ 00000050 2721 EOR R18, R17 \ 00000052 2723 EOR R18, R19 \ 00000054 2724 EOR R18, R20 200 201 column[0] = tmp ^ r0; \ 00000056 2752 EOR R21, R18 \ 00000058 8350 ST Z, R21 202 column[1] = tmp ^ r1; \ 0000005A 2762 EOR R22, R18 \ 0000005C 8361 STD Z+1, R22 203 column[2] = tmp ^ r2; \ 0000005E 2602 EOR R0, R18 \ 00000060 8202 STD Z+2, R0 204 column[3] = tmp ^ r3; \ 00000062 2612 EOR R1, R18 \ 00000064 8213 STD Z+3, R1 205 } \ 00000066 9508 RET
\ In segment CODE, align 2, keep-with-next \ ?Subroutine0: \ 00000000 2617 EOR R1, R23 \ 00000002 2F71 MOV R23, R17 \ 00000004 0F11 LSL R17 \ 00000006 FB77 BST R23, 7 \ 00000008 F40E BRTC ??Subroutine0_0 \ 0000000A 2710 EOR R17, R16 \ ??Subroutine0_0: \ 0000000C 2F72 MOV R23, R18 \ 0000000E 0F22 LSL R18 \ 00000010 FB77 BST R23, 7 \ 00000012 F40E BRTC ??Subroutine0_1 \ 00000014 2720 EOR R18, R16 \ ??Subroutine0_1: \ 00000016 2F73 MOV R23, R19 \ 00000018 0F33 LSL R19 \ 0000001A FB77 BST R23, 7 \ 0000001C F40E BRTC ??Subroutine0_2 \ 0000001E 2730 EOR R19, R16 \ ??Subroutine0_2: \ 00000020 2F74 MOV R23, R20 \ 00000022 0F44 LSL R20 \ 00000024 FB77 BST R23, 7 \ 00000026 F40E BRTC ??Subroutine0_3 \ 00000028 2740 EOR R20, R16 \ ??Subroutine0_3: \ 0000002A 9508 RET ИТОГО: 150 байтов программного кода (уже в 2 раза лучше чем оригинал  ) И если еще чуть напрячь мозг, то можно на 20-30 байт сократить...
|
|
|
|
|
Oct 22 2007, 15:24
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 16-02-07
Пользователь №: 25 414

|
Цитата(singlskv @ Oct 21 2007, 21:28)  __z void InvMixColumn(...) Поясните, пожалуйста, назначение "__z" (и источник информации) - в описании на компилятор 4.30A("Help>AVR>AVR C/C++ Compiler Reference Guide")не нашёл ничего подобного. Без использования "__z"код "прибавляет в весе" 4 байта.
|
|
|
|
|
Oct 22 2007, 16:43
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(SasaVitebsk @ Oct 22 2007, 14:43)  С другой стороны, как я вижу, и как вы сами доказываете - вполне можно пользоваться любым инструментом. Надо просто его хорошо знать. Методы такого рода оптимизации основаны на знании как именно сам компилятор генерит код. С другой стороны, такая оптимизация достаточно зависима от компилятора. Эээ... попробую пояснить почему я Вас агитировал за Gcc. Конечно у IAR оптимизатор написан чуть лучше чем у Gcc(в среднем), и на "плохом" коде это всегда сказывается. Дальше все зависит от конкретной задачки и от модели компиляции разными компиляторами. У IAR AVR есть одно принципиальное отличие от других компиляторов, он использует регистровую пару Y под стек и на этом очень часто превосходит другие компиляторы, но, задачки то разные бывают... Посмотрев исходники я увидел что в данной проге очень часто нужно >2 указателей одновременно. Соответственно преимущество для таких задач будет иметь компилятор у которого больше регистровых пар в распоряжении, а это Gcc а не IAR. Просто посмотрите на листинги первоначального варианта кода и количество использования в них инструкций типа mov X/Z, R(xx):R(xx+1) и mov R(xx):R(xx+1), X/Z
|
|
|
|
|
Oct 23 2007, 14:02
|
Участник

Группа: Новичок
Сообщений: 18
Регистрация: 16-02-07
Пользователь №: 25 414

|
Цитата(Сергей Борщ @ Oct 22 2007, 19:33)  Было в каком-то из .html... Спасибо за ответ. Найду и почитаю.
|
|
|
|
|
Nov 9 2009, 14:11
|
■ ■ ■ ■
    
Группа: Свой
Сообщений: 1 100
Регистрация: 9-08-06
Пользователь №: 19 443

|
Не стал создавать новую тему, поэтому здесь. Можно ли заставить работать(не получается пока) приложение скомпилированное с такими настройками линкера Код define symbol __ICFEDIT_intvec_start__ = 0x00000000; /*-Memory Regions-*/ define symbol __ICFEDIT_region_ROM_start__ = 0x00000044; define symbol __ICFEDIT_region_ROM_end__ = 0x0007FFFF; define symbol __ICFEDIT_region_RAM_start__ = 0x40000040; define symbol __ICFEDIT_region_RAM_end__ = 0x4000FFFF; если расположить его по адресу скажем 0х1000? Скопировал вектора, сделал ремап, передал управление на 0-вой адрес. Переходит разумеется не туда... Если я к тому что лежит с 0х40000020-го адреса прибавляю число 0х1000 то после сброса переходит туда куда надо  но приложение всё равно не работает.
--------------------
Делай что должен и будь что будет.
|
|
|
|
|
Feb 27 2010, 09:55
|
Местный
  
Группа: Свой
Сообщений: 404
Регистрация: 3-12-04
Из: Новосибирск
Пользователь №: 1 304

|
Есть вопрос по прерываниям в bootloader и application. Итак, контроллер atmega8. Карта памяти: 0x0000 - 0x13FF: Application 0x1400 -0x17FF: Common memory (здесь храняться общие функции, доступные из application & bootloader) 0x1800 - 0x1FFF: Bootloader. В bootloader используется одно прерывание от таймера2 по сравнению. Контроллер программируется Avreal и стартует с Bootloader, проверяется CRC, если все ок, то переход на application. Также есть возможность запуска bootloader из application. Итак, программирую контроллер только прошивкой загрузчика: все хорошо, прерывание работает. Теперь, программирую контроллер с общей прошивкой (приложение+загрузчик): загрузчик запускается, отрабатывает и передает управление приложению. Затем из приложения вызываю загрузчик и вижу, что прерывание не работает. В загрузчике и приложении использую разные low_level_init, причем в загрузчике устанавливаю IVSEL, а в приложении сбрасываю. Может у кого было подобное?
|
|
|
|
|
Feb 28 2010, 20:09
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(KSN @ Feb 28 2010, 20:56)  Отправил повторно..... Moderator: Для обильной личной переписки существует служба личных сообщений. Заодно напоминаю, что кросспосты на форуме запрещены. Личная переписка удалена.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|