sonycman 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Всем привет. Не даёт покоя один момент в коде программы. Вкратце - есть прога на С, которую компилирует IAR C/C++ Compiler for AVR 5.10A/W32 (5.10.1.5). Оптимизация на макс. скорость. Вот фрагмент сгенерированного кода: 159 for (a = length; a>0; a--) \ 00000028 2F01 MOV R16, R17 160 { 161 *pBuffer++ = *text++; \ ??usartSendCommand_4: \ 0000002A 01F9 MOVW R31:R30, R19:R18 \ 0000002C 9115 LPM R17, Z+ \ 0000002E 019F MOVW R19:R18, R31:R30 \ 00000030 931D ST X+, R17 162 } \ 00000032 950A DEC R16 \ 00000034 F7D1 BRNE ??usartSendCommand_4 Вот думаю, для чего надо выполнять каждую итерацию цикла команды MOVW? Почему бы не выполнять их один раз перед/после цикла? Не подскажете, уважаемые, каким образом образумить тупонький компилятор? :07: А то запарил он повсюду создавать подобную конструкцию... ЗЫ: вспомнил, что по ИАРу есть отдельная ветка, если нужно, то пусть модераторы перекинут тему туда, извиняюсь... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Diz 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Может, попробовать через стандартную memcpy ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Может, попробовать через стандартную memcpy ? А через неё можно обращаться к флэш? Небольшие кусочки данных было бы выгоднее кидать самому, через простой цикл, только без заморочек компилера... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Похоже указатель *text объявлен как volatile. Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Похоже указатель *text объявлен как volatile. Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом. Нет, не volatile. Вот объявления: char const __flash* text; unsigned char *pBuffer; Пробовал объявлять и просто как unsigned char *text, всё побоку... Можно, конечно, написать цикл на асме, если это было-бы критично, но не понятен смысл такой примитивной вставки комманд MOVW компилятором. Ещё коммерческий, называется... Больше на любительскую поделку похоже :) ЗЫ:А memcpy, похоже, не работает с флэш памятью. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Diz 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Если не ошибаюсь, в IAR для флеша есть memcpy_P. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба с флэш работает memcpy_P(). её объявление содержится в progmem.h, как и для других flash-версий стандартных функций. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба Если не ошибаюсь, в IAR для флеша есть memcpy_P. с флэш работает memcpy_P(). её объявление содержится в progmem.h, как и для других flash-версий стандартных функций. Спасибо! Интересно, вписал подобный цикл чисто для проверки прямо в тело main() - проблемы нет, лишние комманды исчезли... :05: Попробую всю подпрограмму переместить в файл с main()... ...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW... Как же этого избежать??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 18 мая, 2008 Опубликовано 18 мая, 2008 · Жалоба ...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW... Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить: #pragma inline=forced Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
IgorKossak 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Если речь идёт конкретно об IAR и функция не может быть однозначно заменена библиотечной типа memcpy_P(), то посмотрите в сторону атрибутов __x, __x_z ... описанных в \avr\doc\iccavr.htm Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить: #pragma inline=forced Так их и нет, этих мелких функций. Строчка с копированием находится внутри большой функции, инлайнить нечего... Если речь идёт конкретно об IAR и функция не может быть однозначно заменена библиотечной типа memcpy_P(), то посмотрите в сторону атрибутов __x, __x_z ... описанных в \avr\doc\iccavr.htm ...попробовал вот так: __x_z void copymem_P(fbyte __flash* source, byte* dest, byte len) { while(len--) { *dest++ = *source++; } } ...но получилось тоже самое: 92 copymem_P(text, pBuffer, length); \ 00000022 2F01 MOV R16, R17 \ 00000024 01DF MOVW R27:R26, R31:R30 \ 00000026 9614 ADIW R27:R26, 4 \ ??usartSendCommand_4: \ 00000028 950A DEC R16 \ 0000002A 01F9 MOVW R31:R30, R19:R18 \ 0000002C 9115 LPM R17, Z+ \ 0000002E 019F MOVW R19:R18, R31:R30 \ 00000030 931D ST X+, R17 \ 00000032 F7D1 BRNE ??usartSendCommand_4 Эх, от этих MOVW, похоже, никуда не деться, так сказать, издержки компиляции Зато заметил, что при установке уровня оптимизации по скорости на средний - получаем наконец желаемое: 94 for (a = length; a>0; a--) \ 00000024 2F08 MOV R16, R24 \ 00000026 C003 RJMP ??usartSendCommand_4 95 { 96 *pBuffer++ = *text++; \ ??usartSendCommand_5: \ 00000028 9115 LPM R17, Z+ \ 0000002A 931D ST X+, R17 97 } \ 0000002C 950A DEC R16 \ ??usartSendCommand_4: \ 0000002E 2300 TST R16 \ 00000030 F7D9 BRNE ??usartSendCommand_5 но тут уже другие участки кода становятся не идеальными... Интересно, можно ли как-то получить красивый код такого цикла при высоком уровне оптимизации? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба ...попробовал вот так: из этого никак не могло ..но получилось тоже самое: Приведите Вашу функцию целиком Забыл - желательно так, чтобы ее можно было откомпилить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба из этого никак не могло Приведите Вашу функцию целиком Забыл - желательно так, чтобы ее можно было откомпилить. Почему же не могло? Инлайн функция... Проект специально собрал простой, для теста, всего два файла: main.h typedef unsigned long dword; typedef unsigned short word; typedef unsigned char byte; typedef char const __flash fbyte; #define USART_TEXT 10 #define FALSE 0 #define TRUE 1 #define BAUD(x) (QUARTZ/(16UL*x)-1) #define RX_SEEK 0 #define RX_RUNNING 1 #define USART_PREFFIX 2 #define USART_HEADER (USART_PREFFIX + 2) #define USART_FRONTEND (USART_HEADER + 1) #define USART_MAXDATALENGTH (sizeof(comm_buffer) - USART_FRONTEND) #define USART_TEXT 10 static struct usart_rx_status { byte counter: 8; byte mode: 8; volatile bool data_available: 1; bool frame_err: 1; bool ovrun_err: 1; bool parity_err: 1; bool length_err: 1; bool lock_err: 1; } statusRx; static struct usart_tx_status { byte pointer: 8; byte queue: 8; byte length: 8; // volatile bool tx_active: 1; // bool frame_err: 1; // bool ovrun_err: 1; // bool parity_err: 1; bool length_err: 1; // bool lock_err: 1; } statusTx; static byte rx_buffer[16]; static byte tx_buffer[32]; static byte comm_buffer[sizeof(tx_buffer)]; #pragma inline = forced __x_z void copymem_P(fbyte __flash* source, byte* dest, byte len); byte CalculateCRC(const byte *arr, byte size); bool usartSendCommand(byte command, const void* pointer = 0, byte length = 0); и main.cpp #include <ioavr.h> #include <inavr.h> #include <iom88.h> #include <pgmspace.h> #include "main.h" #include <string.h> __x_z void copymem_P(fbyte __flash* source, byte* dest, byte len) { while(len--) { *dest++ = *source++; } } byte CalculateCRC(const byte *arr, byte size) { byte crc = 0; byte bits; while(size--) { bits = *arr++; for(byte k=0; k<8; k++) { if ((bits ^ crc)&0x01) { crc >>= 1; crc ^= 0x8c; } else { crc >>= 1; } bits >>= 1; } } return crc; } bool usartSendData(const byte *buffer, byte length) { byte a, len; byte *pBuffer; if (length > sizeof(tx_buffer) || length == 0) { statusTx.length_err = TRUE; return FALSE; } while (statusTx.length); // memcpy(tx_buffer, buffer, length); while ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length); len = length; a = sizeof(tx_buffer) - statusTx.pointer; if (length > a) { len -= a; pBuffer = tx_buffer + statusTx.pointer; for (;a > 0;a--) *pBuffer++ = *buffer++; statusTx.pointer = 0; } pBuffer = tx_buffer + statusTx.pointer; statusTx.pointer += len; for (;len > 0;len--) *pBuffer++ = *buffer++; statusTx.length = length; UCSR0B |= 1 << UDRIE0; statusTx.length_err = FALSE; return TRUE; } bool usartSendString(fbyte __flash *pointer) { return usartSendCommand(USART_TEXT, (const void*)pointer, strlen_P(pointer)); } bool usartSendCommand(byte command, const void* pointer, byte length) { byte a; byte *pBuffer; switch (command) { case USART_TEXT: if (!length || length > USART_MAXDATALENGTH) return FALSE; fbyte __flash* text; text = (fbyte __flash*)pointer; pBuffer = comm_buffer + USART_PREFFIX; *pBuffer++ = command; *pBuffer++ = length; // copymem_P(text, pBuffer, length); for (a = length; a>0; a--) { *pBuffer++ = *text++; } *pBuffer = CalculateCRC(pBuffer - length, length); break; default: return FALSE; } pBuffer = comm_buffer; *pBuffer++ = 'S'; *pBuffer = 'N'; return usartSendData(comm_buffer, length + USART_FRONTEND); } int main() { usartSendString("some text"); return 0; } Проц - мега88, опции проекта: --string_literals_in_flash и установить галочку Enable bit definitions in include files... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 1 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба ...попробовал вот так: __x_z void copymem_P(fbyte __flash* source, byte* dest, byte len) { while(len--) { *dest++ = *source++; } } так в данном случае надо __z_x или поменять местами указатели на флеш и память! потому что у вас получается указатель на флеш в X, а он должен быть в Z Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба так в данном случае надо __z_x или поменять местами указатели на флеш и память! потому что у вас получается указатель на флеш в X, а он должен быть в Z Поменял местами. Толку всё равно нет: \ ??usartSendCommand_4: \ 00000028 950A DEC R16 \ 0000002A 01F9 MOVW R31:R30, R19:R18 \ 0000002C 9115 LPM R17, Z+ \ 0000002E 019F MOVW R19:R18, R31:R30 \ 00000030 931D ST X+, R17 \ 00000032 F7D1 BRNE ??usartSendCommand_4 Вообще эта инлайн функция была приведена чисто для проверки, а так она там и даром не нужна. Как видно, конечный код в случае использования функции практически не отличается от цикла вида: *pBuffer++ = *text++; И MOVW никуда не уходят. Оптимизации, мать их так :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться