Перейти к содержанию
    

Проблема с inline в EWAVR

Такая ситуация: имеем несколько вложенных друг в друга функций: main( level1 (level2 ())), полная оптимизация по скорости.

При компиляции код функций уровня вложенности больше 2 просто исчезает (в дизассемблере смотрел), хоть просто возвращай переменную, хоть что угодно.

Выполняется main( level1 ()) без вызова level2 ()

Убил часа 4 на поиск причины. Пока не добрался до function inlining.

Отключил function inlining, все остальное так и оставил - помогло.

 

Кто-нибудь знает, что это такое было???

 

И таки да, у меня Kickstart на 4 кб.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, компилятор видит, что результат этой функции ни на что не влияет, и значит выполнять лишний код не имеет смысла. Насчет вложенных друг в друга функций не понял.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем-то вызываемая функция возвращает разные заначения, сейчас покажу. Так что думаю, не то это.

Исходник:

 

//Функция проверки кадра
//Возвращает 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

 

Вот это для меня уже вообще непостижимо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

modbus_frame_check() в том виде, в котором он приведен в примере, не может вернуть 0 ни при каких условиях. Вызов исключен законно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Естественно об этом я тоже думал. Вот такой код:

 

//Функция проверки кадра
//Возвращает 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как глобальная переменная (это видно по коду modbus_slave_routine()).

unsigned char usart_count=0;

 

А, я понял, к чему вы клоните.

Тогда, похоже, компилятор даже не предполагает, что в modbus_slave_routine() между

usart_count=0;

и

modbus_frame_check()

переменная usart_count может быть изменена прерыванием.

 

Но тогда при чем здесь Function inlining???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но тогда при чем здесь Function inlining???

Потому что после включения modbus_frame_check() в состав modbus_slave_routine() компилятор и обнаружил, что usart_count в modbus_frame_check() всегда равен нулю.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё, теперь мне все стало понятно. Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием...

Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно.

 

Получается что ли так:

-если перед вызовом функции глобальной переменной присвоить значение, компилятор считает, что ее прерывание не изменит.

-если значение не присваивать, компилятор считает, что переменная может быть изменена прерыванием.

 

?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием...

Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно.

Об этом должен думать программист. Ключевое слово volatile.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ага. Все понял, как только в раздел Type qualifiers заглянул. Спасибо за наводку! Пошел читать руководство...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...