Makki 0 24 сентября, 2013 Опубликовано 24 сентября, 2013 · Жалоба Такая ситуация: имеем несколько вложенных друг в друга функций: main( level1 (level2 ())), полная оптимизация по скорости. При компиляции код функций уровня вложенности больше 2 просто исчезает (в дизассемблере смотрел), хоть просто возвращай переменную, хоть что угодно. Выполняется main( level1 ()) без вызова level2 () Убил часа 4 на поиск причины. Пока не добрался до function inlining. Отключил function inlining, все остальное так и оставил - помогло. Кто-нибудь знает, что это такое было??? И таки да, у меня Kickstart на 4 кб. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 122 24 сентября, 2013 Опубликовано 24 сентября, 2013 · Жалоба Возможно, компилятор видит, что результат этой функции ни на что не влияет, и значит выполнять лишний код не имеет смысла. Насчет вложенных друг в друга функций не понял. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Makki 0 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба В общем-то вызываемая функция возвращает разные заначения, сейчас покажу. Так что думаю, не то это. Исходник: //Функция проверки кадра //Возвращает 0 если все ОК //#pragma inline=forced unsigned char modbus_frame_check(void) { //Ошибки физического уровня (в usart0_received) if((usart_flags&(1<<mberr))!=0){return 1;} //Длина кадра (не менее 4 символов) unsigned char num=usart_count; if(num<4){return 2;} //Контрольная сумма num-=2; //if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;} // return num; } /************************************************************/ //Обработчик ведомого Modbus (зациклен) void modbus_slave_routine(void) { start: //Сбрасываем таймер и всё-всё-всё и ждем приема ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); TCNT1H=0; TCNT1L=0; TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); usart_count=0; usart_SP=&usart_stack[0]; //Ждем первый символ while((usart_flags&(1<<rxok))==0){;} //Ждем окончания приема кадра while((usart_flags&(1<<t15))==0){;} //Проверяем посылку if(modbus_frame_check()!=0){goto start;} //Обрабатываем посылку и готовим ответ _delay_ms(20); } И то, что в дизассемблере с включенной Function inlining: @00000096: modbus_slave_routine 276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +00000096: B100 IN R16,0x00 In from I/O location +00000097: 700F ANDI R16,0x0F Logical AND with immediate +00000098: B900 OUT 0x00,R16 Out to I/O location 277: TCNT1H=0; +00000099: E000 LDI R16,0x00 Load immediate +0000009A: BD0D OUT 0x2D,R16 Out to I/O location 278: TCNT1L=0; +0000009B: BD0C OUT 0x2C,R16 Out to I/O location 279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +0000009C: E008 LDI R16,0x08 Load immediate +0000009D: BD0E OUT 0x2E,R16 Out to I/O location 283: while((usart_flags&(1<<rxok))==0){;} +0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +0000009F: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000A1: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +000000A2: B100 IN R16,0x00 In from I/O location +000000A3: CFF2 RJMP PC-0x000D Relative jump Как видно, modbus_frame_check() вообще не вызывается. И что характерно, даже нет попытки ее компилировать (если я правильно выражаюсь) - ее просто нет. А теперь отключаем оптимизацию Function inlining - функция появилась и работает: @000000AF: modbus_frame_check 259: if((usart_flags&(1<<mberr))!=0){return 1;} +000000AF: 9B03 SBIS 0x00,3 Skip if bit in I/O register set +000000B0: C002 RJMP PC+0x0003 Relative jump 259: if((usart_flags&(1<<mberr))!=0){return 1;} +000000B1: E001 LDI R16,0x01 Load immediate +000000B2: 9508 RET Subroutine return 261: unsigned char num=usart_count; +000000B3: 91000000 LDS R16,0x0000 Load direct from data space 262: if(num<4){return 2;} +000000B5: 3004 CPI R16,0x04 Compare with immediate +000000B6: F410 BRCC PC+0x03 Branch if carry cleared 262: if(num<4){return 2;} +000000B7: E002 LDI R16,0x02 Load immediate +000000B8: 9508 RET Subroutine return 267: return num; +000000B9: 5002 SUBI R16,0x02 Subtract immediate +000000BA: 9508 RET Subroutine return @000000BB: modbus_slave_routine 272: void modbus_slave_routine(void) 273: { +000000BB: E000 LDI R16,0x00 Load immediate +000000BC: E012 LDI R17,0x02 Load immediate +000000BD: 9300015A STS 0x015A,R16 Store direct to data space +000000BF: 9310015B STS 0x015B,R17 Store direct to data space 276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +000000C1: B100 IN R16,0x00 In from I/O location +000000C2: 700F ANDI R16,0x0F Logical AND with immediate +000000C3: B900 OUT 0x00,R16 Out to I/O location 277: TCNT1H=0; +000000C4: E000 LDI R16,0x00 Load immediate +000000C5: BD0D OUT 0x2D,R16 Out to I/O location 278: TCNT1L=0; +000000C6: BD0C OUT 0x2C,R16 Out to I/O location 279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +000000C7: E008 LDI R16,0x08 Load immediate +000000C8: BD0E OUT 0x2E,R16 Out to I/O location 280: usart_count=0; +000000C9: E000 LDI R16,0x00 Load immediate +000000CA: 9300015E STS 0x015E,R16 Store direct to data space 283: while((usart_flags&(1<<rxok))==0){;} +000000CC: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +000000CD: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +000000CE: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000CF: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +000000D0: DFDE RCALL PC-0x0021 Relative call subroutine +000000D1: 2300 TST R16 Test for Zero or Minus +000000D2: F771 BRNE PC-0x11 Branch if not equal 289: _delay_ms(20); +000000D3: E30F LDI R16,0x3F Load immediate +000000D4: E91C LDI R17,0x9C Load immediate +000000D5: 5001 SUBI R16,0x01 Subtract immediate +000000D6: 4010 SBCI R17,0x00 Subtract immediate with carry +000000D7: F7E9 BRNE PC-0x02 Branch if not equal +000000D8: C000 RJMP PC+0x0001 Relative jump +000000D9: 0000 NOP No operation 291: } +000000DA: 9508 RET Subroutine return Что характерно, если из вызывающей функции удалить обнуление таймера и счетчиков, все тоже работает, только вызываемая функция заинлайнена: @00000096: modbus_slave_routine 272: void modbus_slave_routine(void) 273: { +00000096: 9110015E LDS R17,0x015E Load direct from data space 283: while((usart_flags&(1<<rxok))==0){;} +00000098: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +00000099: CFFE RJMP PC-0x0001 Relative jump 285: while((usart_flags&(1<<t15))==0){;} +0000009A: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +0000009B: CFFE RJMP PC-0x0001 Relative jump 287: if(modbus_frame_check()!=0){goto start;} +0000009C: 9903 SBIC 0x00,3 Skip if bit in I/O register cleared +0000009D: CFFA RJMP PC-0x0005 Relative jump +0000009E: 2F01 MOV R16,R17 Copy register +0000009F: 3014 CPI R17,0x04 Compare with immediate +000000A0: F3B8 BRCS PC-0x08 Branch if carry set +000000A1: 5002 SUBI R16,0x02 Subtract immediate +000000A2: F7A9 BRNE PC-0x0A Branch if not equal 289: _delay_ms(20); +000000A3: E30F LDI R16,0x3F Load immediate +000000A4: E91C LDI R17,0x9C Load immediate +000000A5: 5001 SUBI R16,0x01 Subtract immediate +000000A6: 4010 SBCI R17,0x00 Subtract immediate with carry +000000A7: F7E9 BRNE PC-0x02 Branch if not equal +000000A8: C000 RJMP PC+0x0001 Relative jump +000000A9: 0000 NOP No operation 291: } +000000AA: 9508 RET Subroutine return Вот это для меня уже вообще непостижимо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 68 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба modbus_frame_check() в том виде, в котором он приведен в примере, не может вернуть 0 ни при каких условиях. Вызов исключен законно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Makki 0 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Естественно об этом я тоже думал. Вот такой код: //Функция проверки кадра //Возвращает 0 если все ОК //#pragma inline=forced unsigned char modbus_frame_check(void) { //Ошибки физического уровня (в usart0_received) if((usart_flags&(1<<mberr))!=0){return 1;} //Длина кадра (не менее 4 символов) unsigned char num=usart_count; if(num<4){return 2;} //Контрольная сумма num-=2; //if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;} // return 0;//num; } Генерит то же самое: @00000096: modbus_slave_routine 285: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok)); +00000096: B100 IN R16,0x00 In from I/O location +00000097: 700F ANDI R16,0x0F Logical AND with immediate +00000098: B900 OUT 0x00,R16 Out to I/O location 286: TCNT1H=0; +00000099: E000 LDI R16,0x00 Load immediate +0000009A: BD0D OUT 0x2D,R16 Out to I/O location 287: TCNT1L=0; +0000009B: BD0C OUT 0x2C,R16 Out to I/O location 288: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); +0000009C: E008 LDI R16,0x08 Load immediate +0000009D: BD0E OUT 0x2E,R16 Out to I/O location 292: while((usart_flags&(1<<rxok))==0){;} +0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set +0000009F: CFFE RJMP PC-0x0001 Relative jump 294: while((usart_flags&(1<<t15))==0){;} +000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set +000000A1: CFFE RJMP PC-0x0001 Relative jump 296: if(modbus_frame_check()!=0){goto start;} +000000A2: B100 IN R16,0x00 In from I/O location +000000A3: CFF2 RJMP PC-0x000D Relative jump Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 68 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба А как объявлен usart_count? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Makki 0 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Как глобальная переменная (это видно по коду modbus_slave_routine()). unsigned char usart_count=0; А, я понял, к чему вы клоните. Тогда, похоже, компилятор даже не предполагает, что в modbus_slave_routine() между usart_count=0; и modbus_frame_check() переменная usart_count может быть изменена прерыванием. Но тогда при чем здесь Function inlining??? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 68 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Но тогда при чем здесь Function inlining??? Потому что после включения modbus_frame_check() в состав modbus_slave_routine() компилятор и обнаружил, что usart_count в modbus_frame_check() всегда равен нулю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Makki 0 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Всё, теперь мне все стало понятно. Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием... Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно. Получается что ли так: -если перед вызовом функции глобальной переменной присвоить значение, компилятор считает, что ее прерывание не изменит. -если значение не присваивать, компилятор считает, что переменная может быть изменена прерыванием. ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 68 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием... Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно. Об этом должен думать программист. Ключевое слово volatile. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Makki 0 25 сентября, 2013 Опубликовано 25 сентября, 2013 · Жалоба Ага. Все понял, как только в раздел Type qualifiers заглянул. Спасибо за наводку! Пошел читать руководство... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться