zltigo 1 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Оптимизации, мать их так :( Ну еще можете заняться индивидуальным террором - прагмами указывать разные ключи оптимизации для разных кусков текста. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Ну еще можете заняться индивидуальным террором - прагмами указывать разные ключи оптимизации для разных кусков текста. Да, порой приходится переставлять/расписывать операторы/операнды в случае особо коряво скомпилированного кода. Наверное, никак пока не привыкну к компиляторам после чисто ассемблерного программирования... :( В данном случае проблема не велика, конечно, просто стало интересно, как на это смотрит остальное сообщество. Может быть, только у меня такая "шняга"? :) ЗЫ: Вот зачем надо было вводить второй стёк для данных? В листинге не нашёл ни единой команды push/pop. Целый регистр-указатель под это угробили. А потом конечно, пихаем сначала r16:r17 в Z, юзаем его, затем пихаем в него r18:r19 и т.д, вместо естественной работы с двумя указателями... Ужас :( Обработчики прерываний (в виде единой функции!) с длиннющим сохранением регистров на стёк, когда на асме обошёлся бы парой-тройкой... Порой больно смотреть на такое разбазаривание ресурсов проца... :( Но начинаю привыкать к С, уже лень становится писать что-либо на асме... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Оптимизации, мать их так Ну попробуйте такой вариант - #pragma optimize=no_cse __x bool usartSendData(const byte *buffer, byte length) { byte a, len; if (length > sizeof(tx_buffer) || length == 0) { statusTx.length_err = TRUE; return FALSE; } while (statusTx.length); while ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length); len = length; a = sizeof(tx_buffer) - statusTx.pointer; if (length > a) { byte *p=tx_buffer + statusTx.pointer; len -= a; for (;a > 0;a--) *p++ = *buffer++; statusTx.pointer = 0; } statusTx.pointer += len; { byte *p=tx_buffer + statusTx.pointer;; for (;len > 0;len--) *p++ = *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)); } #pragma optimize=no_cse __z 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; pBuffer = comm_buffer + USART_PREFFIX; *pBuffer++ = command; *pBuffer++ = length; // copymem_P(pBuffer, (fbyte __flash *)pointer, length); a=length; { byte *p=pBuffer; fbyte __flash* text; text = (fbyte __flash*)pointer; do { *p++ = *text++; } while(--a); *p=CalculateCRC(pBuffer, length); } break; default: return FALSE; } pBuffer = comm_buffer; *pBuffer++ = 'S'; *pBuffer = 'N'; return usartSendData(comm_buffer, length + USART_FRONTEND); } Тут много магии - отдельные указатели (почему-то иногда очень плохо у IAR'а по ходу выполнения функции переменные перемещаются по регистрам), no_cse... А в общем итоге видимо проблема заключается в том, что использование структур и двух указателей сразу приводит к нехватке регистровых пар. Видимо, тут GCC был бы на высоте. Обработчики прерываний (в виде единой функции!) с длиннющим сохранением регистров на стёк, когда на асме обошёлся бы парой-тройкой... Если какие-то функции другие вызываются - будет сохранение всех scratch-регистров, если нет - все будет хорошо. Вот зачем надо было вводить второй стёк для данных? Вот GCC не делает второй стек для данных. Все хорошо, пока переменные одной функции помещаются в регистрах. Как только надо исполнить стековую переменную - начинается мрак, там такой код для пролога/эпилога, что с непривычки за голову хватаешься... Тут конечно, надо бы было сделать 2 комманды при разработке ядра, LDD r,SP+disp и STD SP+disp,r и пару комманд увеличения/уменьшения указателя стека - и тогда бы здорово помогло... Но поезд ушел 10 лет назад :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Ну попробуйте такой вариант ... Если какие-то функции другие вызываются - будет сохранение всех scratch-регистров, если нет - все будет хорошо. ... Вот GCC не делает второй стек для данных. Все хорошо, пока переменные одной функции помещаются в регистрах. Как только надо исполнить стековую переменную - начинается мрак, там такой код для пролога/эпилога, что с непривычки за голову хватаешься... Тут конечно, надо бы было сделать 2 комманды при разработке ядра, LDD r,SP+disp и STD SP+disp,r и пару комманд увеличения/уменьшения указателя стека - и тогда бы здорово помогло... Но поезд ушел 10 лет назад :) Спасибо Дмитрий, попробую :) Насчёт прерываний - в том то и дело, что каких-либо вызовов функций нет, а сохраняется по 7-9 регистров на CSTACK. Возможно, слишком громоздкий код получается, конечно. По стеку понятно, для большого кол-ва переменных это будет выгодно, наверное, хотя у себя я пока не наблюдал подгрузку данных с регистра Y... ЗЫ: Хочу передать Вам большой респект, как кодеру известной в своё время команды Codebusters :) До сих пор помню Satisfaction megademo, сколько раз тогда запускал её и любовался эффектами и музыкой... Приятно, что этот форум посещают подобные вам люди :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Да, чудесным образом лишние инструкции исчезли! :a14: Как я понял, всё это путём небольшого изменения порядка следования команд, введения дополнительных указателей/или переменных для исключения лишних вычислений и парочкой прагм... Да-а, башку можно сломать от такого напряга B) В общем вот что получилось в итоге: bool usartSendData(const byte *buffer, byte length) { byte a, len; if (length > sizeof(tx_buffer) || length == 0) { statusTx.length_err = TRUE; return FALSE; } while (statusTx.length); while ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length); len = length; a = sizeof(tx_buffer) - statusTx.pointer; if (length > a) { byte *p=tx_buffer + statusTx.pointer; len -= a; for (;a > 0;a--) *p++ = *buffer++; statusTx.pointer = 0; } a = len; byte *p=tx_buffer + statusTx.pointer; for (;a > 0;a--) *p++ = *buffer++; statusTx.pointer += len; statusTx.length = length; UCSR0B |= 1 << UDRIE0; statusTx.length_err = FALSE; return TRUE; } #pragma optimize=no_cse __z 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; pBuffer = comm_buffer + USART_PREFFIX; *pBuffer++ = command; *pBuffer++ = length; a=length; byte *p; p = pBuffer; fbyte __flash* text; text = (fbyte __flash*)pointer; while(a--) *p++ = *text++; *p = CalculateCRC(pBuffer, length); break; default: return FALSE; } pBuffer = comm_buffer; *pBuffer++ = 'S'; *pBuffer = 'N'; return usartSendData(comm_buffer, length + USART_FRONTEND); } Все три цикла копирования стали просто идеальными! Причём первая функция сохраняет "стройность" и без "прагмы" и "__x". Магия? :rolleyes: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 1 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Да-а, башку можно сломать от такого напряга B) В общем-то не слишком и сложно, если подумать, то не сложнее писания врукопашную на ASM. Опыт и навыки естественно нужны. Проблемы только с переносимостью между компиляторами :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 19 мая, 2008 Опубликовано 19 мая, 2008 · Жалоба Тут много магии - отдельные указатели (почему-то иногда очень плохо у IAR'а по ходу выполнения функции переменные перемещаются по регистрам), no_cse... А в общем итоге видимо проблема заключается в том, что использование структур и двух указателей сразу приводит к нехватке регистровых пар. Видимо, тут GCC был бы на высоте.О, это именно то о чем я твержу уже очень давно но все почему-то относятся к этому скептически, IAR действительно дуреет когда количество источников/приемников данных в близлежащем коде >2, причем обращение к структурам у него часто идет как обращение к источнику/приемнику данных. При этом выбор того что будет адресоваться через регистровую пару зависит от порядка обращения в исходнике. У Gcc с этим чуть по лучше, правда, если уж совсем по-честному, иногда лишние movw тоже бывают, но лечится обычно просто заведением локальных указателей без всяких прагм. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Проблемы только с переносимостью между компиляторами делаем так - #ifndef __IAR_SYSTEMS_ICC__ #define __x #define __z #define __z_x #define __x_z #endif И нет проблемы ;) У Gcc с этим чуть по лучше Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах?Это да, стараюсь до стекового фрейма не доводить... если нужен листинг не для сборки а для посмотреть: avr-objdump -S proname.elf >progname.lst Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба делаем так - #ifndef __IAR_SYSTEMS_ICC__ #define __x #define __z #define __z_x #define __x_z #endif И нет проблемы ;) Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса? Это что, зашито мёртво в любой компилер? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
singlskv 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса?Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить пустое место. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sonycman 0 20 мая, 2008 Опубликовано 20 мая, 2008 · Жалоба Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить пустое место. А, понятно, то есть просто выключаем эту фичу... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Andreas1 1 21 мая, 2008 Опубликовано 21 мая, 2008 · Жалоба Еще непонятки с оптимизацией, правда в IAR AVR 4.30 3 варианта одного и того-же 54 *ptr=b; \ 00000026 8310 ST Z, R17 55 ptr-=7; 56 if(*(ptr++)!=0xE0) return;//ptr++; \ 00000028 9737 SBIW R31:R30, 7 \ 0000002A 01DF MOVW R27:R26, R31:R30 \ 0000002C 9631 ADIW R31:R30, 1 \ 0000002E 910C LD R16, X \ 00000030 3E00 CPI R16, 224 \ 00000032 F459 BRNE ??RSRecByte_0 57 if(*(ptr++)!=0x00) return;//ptr++; \ 00000034 9101 LD R16, Z+ \ 00000036 2300 TST R16 \ 00000038 F441 BRNE ??RSRecByte_0 54 *ptr=b; \ 00000022 8310 ST Z, R17 55 // ptr-=7; 56 if(*(ptr++)!=0xE0) return;//ptr++; \ 00000024 9101 LD R16, Z+ \ 00000026 3E00 CPI R16, 224 \ 00000028 F459 BRNE ??RSRecByte_0 57 if(*(ptr++)!=0x00) return;//ptr++; \ 0000002A 9101 LD R16, Z+ \ 0000002C 2300 TST R16 \ 0000002E F441 BRNE ??RSRecByte_0 54 *ptr=b; \ 00000022 8310 ST Z, R17 55 ptr-=7; \ 00000024 9737 SBIW R31:R30, 7 56 if(*(ptr)!=0xE0) return;ptr++; \ 00000026 9101 LD R16, Z+ \ 00000028 3E00 CPI R16, 224 \ 0000002A F471 BRNE ??RSRecByte_0 57 if(*(ptr)!=0x00) return;ptr++; \ 0000002C 9101 LD R16, Z+ \ 0000002E 2300 TST R16 \ 00000030 F459 BRNE ??RSRecByte_0 Кроме того появляется сохранение/восстановление R26:27. Вроде немного, но совершенно непонятная разница. Получается, лучше дробить длинные выражения по кускам? В общем-то не слишком и сложно, если подумать, то не сложнее писания врукопашную на ASM. Опыт и навыки естественно нужны. К сожалению, опыт приходится наживать свой и только мало-мало чужого, в отличие от писюкового программизма. Нет литературы, ориентированной на оптимальное написание на С. P.S. Это пока только заготовка void RSRecByte(){ if(!IsRecByteRS())return; byte b=GetByteRS(); if(RSStatus==RS_RECCMD){//ïðèåì êîìàíäû byte *ptr=RSRecCmdBuffer; for(byte i=0;i<7;i++,ptr++)*ptr=*(ptr+1); *ptr=b; ptr-=7; if(*ptr!=0xE0) return;ptr++; if(*ptr!=0x00) return;ptr++; if(*ptr!=SysNum) return;ptr++; if(*ptr!=0x01) return;ptr++; RSStatus=1; }else{//ïðèåì äàííûõ } } Знать-бы какие подсказки компилер понимает :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 21 мая, 2008 Опубликовано 21 мая, 2008 · Жалоба 3 варианта одного и того-же Местные телепаты требуют полностью функцию ;) Желательно, с обрамлением, чтобы можно было собрать. А, просмотрелся... Вы уже асилили подсказать компилятору.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 121 21 мая, 2008 Опубликовано 21 мая, 2008 · Жалоба P.S. Это пока только заготовка А попробуйте что-то вроде if(RSStatus==RS_RECCMD) { memcpy(RSRecCmdBuffer, &RSRecCmdBuffer, 7); RSRecCmdBuffer[7] = b; memcpy - intrinsic, компилятор может ее реализовать эффективнее, чем компилируя ваш цикл. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться