|
|
  |
Проблема с inline в EWAVR, Оптимизация Function inlining режет код |
|
|
|
Sep 25 2013, 11:54
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163

|
В общем-то вызываемая функция возвращает разные заначения, сейчас покажу. Так что думаю, не то это. Исходник: CODE //Функция проверки кадра //Возвращает 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: CODE @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 - функция появилась и работает: CODE @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 Что характерно, если из вызывающей функции удалить обнуление таймера и счетчиков, все тоже работает, только вызываемая функция заинлайнена: CODE @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 Вот это для меня уже вообще непостижимо.
|
|
|
|
|
Sep 25 2013, 12:20
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163

|
Естественно об этом я тоже думал. Вот такой код: CODE //Функция проверки кадра //Возвращает 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; }
Генерит то же самое: CODE @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
|
|
|
|
|
Sep 25 2013, 12:39
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163

|
Как глобальная переменная (это видно по коду modbus_slave_routine()). unsigned char usart_count=0;
А, я понял, к чему вы клоните. Тогда, похоже, компилятор даже не предполагает, что в modbus_slave_routine() между usart_count=0; и modbus_frame_check() переменная usart_count может быть изменена прерыванием.
Но тогда при чем здесь Function inlining???
|
|
|
|
|
Sep 25 2013, 13:28
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163

|
Всё, теперь мне все стало понятно. Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием... Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно.
Получается что ли так: -если перед вызовом функции глобальной переменной присвоить значение, компилятор считает, что ее прерывание не изменит. -если значение не присваивать, компилятор считает, что переменная может быть изменена прерыванием.
?
|
|
|
|
|
Sep 25 2013, 14:05
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163

|
Ага. Все понял, как только в раздел Type qualifiers заглянул. Спасибо за наводку! Пошел читать руководство...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|