Портал для радиолюбителей и разработчиков электроники · с 2003 годаРеклама на сайте
Найти компонент, схему или даташит

Даташиты, справочник отечественных приборов, схемы с разбором и живой форум

Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей...

 
Опции темы

Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Непрочитано 14.07.2010, 01:40  
kison
Почётный гражданин KAZUS.RUN
 
Регистрация: 13.12.2004
Сообщений: 3,168
Сказал спасибо: 11
Сказали Спасибо 691 раз(а) в 503 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от Godzilla82 Посмотреть сообщение
Это при том, что некоторые говорят, что в CodeVision всё работает медленно и печально...
Вы видимо удивитесь, но
Код:
PORTD |= (1‹‹PD4); //GCC
PORTD.4 = 1; //CV
Работают ровно одинаковое время.
Возьмите нормальный тест.
Ну например
Код:
volatile unsigned char ii = 0;
volatile double a = 5.0;
volatile double b = 25.0;

volatile double c;

void CalcC(void)
{
c = a * b;
}

int		main(void)
{

CalcC();

while(1)
	{
	ii++;
	}
}
Сколько тактов в CV выполняется CalcC? GCC - 156.
Тоже вроде простейший тест. Под мегу 8.
Вообще посмотрите https://kazus.run/forums/showthread.php?t=13936
Я там похожей фигней занимался. Правда тестировался ИАР в основном в сравнении с GCC, но кое где и для CV результаты есть.
Кстати - посмотрите листинг от CV с Вашим примером. CV count держит в регистрах! Т.е. переменная совсем не глобальная. Попробуйте добавить обработчик прерывания, где будет использоваться count. И померяйте такты снова. Это кстати офигенный хомут, код из под CV не верный! И еще - для увеличения/уменьшения count служит
Код:
000083 01f1      	MOVW R30,R2
000084 9631      	ADIW R30,1
                 _0xB:
000085 011f      	MOVW R2,R30
Но нигде в коде R31 не обнулялся! Там при включении мусор может быть. В железе ес-но, не в симуляторе. Да и вообще непонятно есть ли старший байт у count или нет. CV похоже на эту переменную просто забил.
И собирайте с отладочной инфой, шагать по дизассемблеру не комфортно.
И версию CV огласите - чтоб пересобрать можно было.
Реклама:

Последний раз редактировалось kison; 14.07.2010 в 02:32.
kison вне форума  
Непрочитано 14.07.2010, 03:58  
Godzilla82
Почётный гражданин KAZUS.RUN
 
Регистрация: 29.10.2006
Сообщений: 1,449
Сказал спасибо: 99
Сказали Спасибо 318 раз(а) в 234 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от kison Посмотреть сообщение
Кстати - посмотрите листинг от CV с Вашим примером. CV count держит в регистрах! Т.е. переменная совсем не глобальная. Попробуйте добавить обработчик прерывания, где будет использоваться count. И померяйте такты снова.
...
Но нигде в коде R31 не обнулялся! Там при включении мусор может быть. В железе ес-но, не в симуляторе. Да и вообще непонятно есть ли старший байт у count или нет. CV похоже на эту переменную просто забил.
И собирайте с отладочной инфой, шагать по дизассемблеру не комфортно.
И версию CV огласите - чтоб пересобрать можно было.
Есть реальная железка. В ней по прерыванию от USI передаются данные count. Передаёт оба байта. И старший, и младший. И количество тактов там - 20/28. И всё работает корректно.

По большому счёту, мне абсолютно пофиг, где и в чём хранит CVAVR значение переменной count. Факт в том, что в данном случае код, который даёт CVAVR работает быстрее на 5 тактов. Это на 15% быстрее WinAVR...

Ладно, может это и не существенно. Но! CVAVR предсказуем и даёт стабильный результат, не зависящий от оптимизации. Чего нельзя сказать про WinAVR. Там приходится шаманить...

Вот есть функции отправки/приёма байта по SPI (для меги 64):
Код:
void SPI_Write_Byte (unsigned char byte)
{
SPDR = byte;
while (!(SPSR & _BV(7)));
}

unsigned char SPI_Read_Byte (void)
{
SPDR = 0;
while (!(SPSR & _BV(7)));
return(SPDR);
}
При включении оптимизации код перестаёт работать. До уровня ассемблера и команд не вникал. Но момент неприятный.
А без оптимизации размер кода возрастает в разы, не говоря уже про быстродействие... Вот уж действительно, печально: быстро (не работает), медленно (от чего само по себе не весело)

P.S. CodeVision AVR v1.25.9

Последний раз редактировалось Godzilla82; 14.07.2010 в 04:04.
Godzilla82 вне форума  
Непрочитано 14.07.2010, 06:13  
kison
Почётный гражданин KAZUS.RUN
 
Регистрация: 13.12.2004
Сообщений: 3,168
Сказал спасибо: 11
Сказали Спасибо 691 раз(а) в 503 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от Godzilla82 Посмотреть сообщение
Есть реальная железка. В ней по прерыванию от USI передаются данные count. Передаёт оба байта. И старший, и младший. И количество тактов там - 20/28. И всё работает корректно.
Конечно разместив count в регистрах можно сэкономить. Пока в программе две-три переменных. Стоит же ей чуть подрасти, и тактов станет резко больше.
Ну вот Вам такой же вариант под GCC
Код:
**************************************************  **/

#define F_CPU 10000000UL
#include ‹avr/io.h›
#include ‹util/delay.h›

register volatile unsigned int count asm("r4"); 

int main(void)
{
char a;
char b;
char c=1;
char d=0;
char t;
char pa=0;
char pb=0;

PORTA=0x00;
DDRA=0x00;
PORTB=0x00;
DDRB=0x00;
PORTD=0x00;
DDRD=0x01;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK=0x00;
USICR=0x00;
ACSR=0x80;

count = 0;
begin:
PORTD=c;
t=PINB;
a=(t & 0b00010000);
b=(t & 0b00100000) ›› 1;
if (a!=pa) {
           pa=a;
           if (a!=b) count++;
           else      count--;
           }
if (b!=pb) {
           pb=b;
           if (a!=b) count--;
           else      count++;
           }
PORTD=d;
goto begin;
}
Количество тактов оцените сами - на Os оптимизации.

Сообщение от Godzilla82 Посмотреть сообщение
При включении оптимизации код перестаёт работать.
Ну причина явно в другом месте. Такие функции оптимизатору не интересны, что без оптимизации, что с ней - код одинаковый.
ЗЫ. Ночами нужно спать - я выше ошибся. Обнулять то надо R3, а не R31. А R3 действительно получает 0.
kison вне форума  
Непрочитано 14.07.2010, 11:15  
SasaVitebsk
Гражданин KAZUS.RUN
 
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
SasaVitebsk на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от kison Посмотреть сообщение
Кстати - посмотрите листинг от CV с Вашим примером. CV count держит в регистрах! Т.е. переменная совсем не глобальная. Попробуйте добавить обработчик прерывания, где будет использоваться count. И померяйте такты снова. Это кстати офигенный хомут, код из под CV не верный! И еще - для увеличения/уменьшения count служит
Тогда всё понятно. А то думаю, чё за лажа.
Сделал такой вариант
Код:
/**************************************************  ***
Chip type           : ATtiny2313
Clock frequency     : 10,000000 MHz
Memory model        : Tiny
External SRAM size  : 0
Data Stack size     : 32
**************************************************  ***/

#include ‹iotiny2313.h›
#include "inavr.h"
#include "stdio.h"
#include "stdint.h"

// Энкодер
#define ENC_P_PIN		4
#define ENC_N_PIN		5
#define ENC_PIN			PINB
#define ENC_PORT		PORTB
#define ENC_DDR			DDRB
#define ENC_P			(ENC_PIN & (1‹‹ENC_P_PIN))
#define ENC_N			(ENC_PIN & (1‹‹ENC_N_PIN))
#define ENC_MASKA		((1‹‹ENC_P_PIN) | (1‹‹ENC_N_PIN))
#define ENC_B			(ENC_PIN & ENC_MASKA)


char P4;
char P5;
char a=1;
char b=0;

signed char const __flash sw[16] =
  {
	0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0
  };

volatile 
unsigned int count=0;

void main(void)
{
  char	pnew, pold, cnt;
  
CLKPR=0x80;
CLKPR=0x00;

PORTA=0x00;
DDRA=0x00;
PORTB=0x00;
DDRB=0x00;
PORTD=0x00;
DDRD=0x01;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK=0x00;
USICR=0x00;
ACSR=0x80;

pold=ENC_B ›› 2;
for( ; ; )
{
  PORTD=a;
  pnew=__swap_nibbles(ENC_B);
  cnt = sw[pnew|pold];
  if(cnt)
  {
	count += cnt;
	pold = pnew‹‹2;
  }
  PORTD=b;
}
}
Результат компиляции IARом меня вполне удовлетворяют, но вижу в листинге некоторые вещи, которые явно увеличивают время исполнения:
Код:
     76            PORTD=a;
   \                     ??main_0:
   \   0000004A   ....               LDI     R30, count
   \   0000004C   8102               LDD     R16, Z+2
   \   0000004E   BB02               OUT     0x12, R16
.....
     84            PORTD=b;
   \                     ??main_1:
   \   00000080   ....               LDI     R30, count
   \   00000082   8103               LDD     R16, Z+3
   \   00000084   BB02               OUT     0x12, R16
Здесь, например видно, что IAR честно поступает с глобальной переменной (a и b). Если CV размещает как угодно, то тогда понятен выигрыш. Но я ведь, это смогу сделать и на IAR, только честным путём, слегка модифицируя листинг.
Как только я вношу переменные a и b в качестве локальных, то получаю:
Код:
     76            PORTD=a;
   \                     ??main_0:
   \   0000004A   E001               LDI     R16, 1
   \   0000004C   BB02               OUT     0x12, R16
....
   \                     ??main_1:
   \   0000007C   E000               LDI     R16, 0
   \   0000007E   BB02               OUT     0x12, R16
Count делать в качестве локальной - нельзя, равно как и размещать их в регистрах. Это очевидный бред. Иначе вы не сможете до неё достучаться в прерывании.
Можно конечно сделать финт ушами, если прога состоит из пару страниц текста.
Выглядеть это будет так:
Код:
/**************************************************  ***
Chip type           : ATtiny2313
Clock frequency     : 10,000000 MHz
Memory model        : Tiny
External SRAM size  : 0
Data Stack size     : 32
**************************************************  ***/

#include ‹iotiny2313.h›
#include "inavr.h"
#include "stdio.h"
#include "stdint.h"

// Ýíêîäåð
#define ENC_P_PIN		4
#define ENC_N_PIN		5
#define ENC_PIN			PINB
#define ENC_PORT		PORTB
#define ENC_DDR			DDRB
#define ENC_P			(ENC_PIN & (1‹‹ENC_P_PIN))
#define ENC_N			(ENC_PIN & (1‹‹ENC_N_PIN))
#define ENC_MASKA		((1‹‹ENC_P_PIN) | (1‹‹ENC_N_PIN))
#define ENC_B			(ENC_PIN & ENC_MASKA)


char P4;
char P5;

signed char const __flash sw[16] =
  {
	0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0
  };

volatile 
 __regvar __no_init unsigned int count @14;

void main(void)
{
  char	pnew, pold, cnt;
  char a=1;
  char b=0;
  
CLKPR=0x80;
CLKPR=0x00;

PORTA=0x00;
DDRA=0x00;
PORTB=0x00;
DDRB=0x00;
PORTD=0x00;
DDRD=0x01;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK=0x00;
USICR=0x00;
ACSR=0x80;

count = 0;
pold=ENC_B ›› 2;
for( ; ; )
{
  PORTD=a;
  pnew=__swap_nibbles(ENC_B);
  cnt = sw[pnew|pold];
  if(cnt)
  {
	count += cnt;
	pold = pnew‹‹2;
  }
  PORTD=b;
}
}
В результате
// 140 bytes of CODE memory (+ 4 bytes shared)
// 2 bytes of DATA memory (+ 30 bytes shared)

По тактам - следующее 21/26
Вложения:
Тип файла: zip xxx.zip (380 байт, 37 просмотров)
SasaVitebsk вне форума  
Непрочитано 14.07.2010, 11:53  
kison
Почётный гражданин KAZUS.RUN
 
Регистрация: 13.12.2004
Сообщений: 3,168
Сказал спасибо: 11
Сказали Спасибо 691 раз(а) в 503 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от SasaVitebsk Посмотреть сообщение
По тактам - следующее 21/26
Вариант, что я дал выше с регистровым count - 16/23
Код:
@0000004D: begin
51:       PORTD=c;
+0000004D:   E081        LDI     R24,0x01         Load immediate
+0000004E:   BB82        OUT     0x12,R24         Out to I/O location
52:       t=PINB;
+0000004F:   B386        IN      R24,0x16         In from I/O location
53:       a=(t & 0b00010000);
+00000050:   2F98        MOV     R25,R24          Copy register
+00000051:   7190        ANDI    R25,0x10         Logical AND with immediate
54:       b=(t & 0b00100000) ›› 1;
+00000052:   9586        LSR     R24              Logical shift right
+00000053:   7180        ANDI    R24,0x10         Logical AND with immediate
55:       if (a!=pa) {
+00000054:   1793        CP      R25,R19          Compare
+00000055:   F051        BREQ    PC+0x0B          Branch if equal
57:                  if (a!=b) count++;
+00000056:   1798        CP      R25,R24          Compare
+00000057:   F021        BREQ    PC+0x05          Branch if equal
+00000058:   9408        SEC                      Set Carry
+00000059:   1C41        ADC     R4,R1            Add with carry
+0000005A:   1C51        ADC     R5,R1            Add with carry
+0000005B:   C003        RJMP    PC+0x0004        Relative jump
58:                  else      count--;
+0000005C:   9408        SEC                      Set Carry
+0000005D:   0841        SBC     R4,R1            Subtract with carry
+0000005E:   0851        SBC     R5,R1            Subtract with carry
+0000005F:   2F39        MOV     R19,R25          Copy register
60:       if (b!=pb) {
+00000060:   1782        CP      R24,R18          Compare
+00000061:   F059        BREQ    PC+0x0C          Branch if equal
62:                  if (a!=b) count--;
+00000062:   1798        CP      R25,R24          Compare
+00000063:   F029        BREQ    PC+0x06          Branch if equal
+00000064:   9408        SEC                      Set Carry
+00000065:   0841        SBC     R4,R1            Subtract with carry
+00000066:   0851        SBC     R5,R1            Subtract with carry
+00000067:   2F28        MOV     R18,R24          Copy register
+00000068:   C004        RJMP    PC+0x0005        Relative jump
63:                  else      count++;
+00000069:   9408        SEC                      Set Carry
+0000006A:   1C41        ADC     R4,R1            Add with carry
+0000006B:   1C51        ADC     R5,R1            Add with carry
+0000006C:   2F29        MOV     R18,R25          Copy register
65:       PORTD=d;
+0000006D:   BA12        OUT     0x12,R1          Out to I/O location
+0000006E:   CFDE        RJMP    PC-0x0021        Relative jump
Сообщение от SasaVitebsk Посмотреть сообщение
Count делать в качестве локальной - нельзя, равно как и размещать их в регистрах. Это очевидный бред. Иначе вы не сможете до неё достучаться в прерывании.
Можно конечно сделать финт ушами, если прога состоит из пару страниц текста.
CV из прерывания доступ все же имеет. Там нет линкера и исходник один файл. Берет переменную прямо из регистров. Так что для маленьких проектов типа полный контроль. Для средних и больших - уже просто помойка. Более того, CV даже по указателю умудряется работать с регистровыми переменными, хотя стандарт Си говорит что это невозможно.
kison вне форума  
Непрочитано 14.07.2010, 18:21  
Godzilla82
Почётный гражданин KAZUS.RUN
 
Регистрация: 29.10.2006
Сообщений: 1,449
Сказал спасибо: 99
Сказали Спасибо 318 раз(а) в 234 сообщении(ях)
Godzilla82 на пути к лучшему
Сообщение Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от kison Посмотреть сообщение
Ну вот Вам такой же вариант под GCC[/code]
Количество тактов оцените сами - на Os оптимизации.
WinAVR 2010... Разница тактов 15/16... странно, да? При отключении оптимизации код вообще не работает. То есть, до PORTD=1 не доходит

Сообщение от SasaVitebsk Посмотреть сообщение
Сделал такой вариант
...
По тактам - следующее 21/26
Ну вот терь хоть в симуляторе запускается
Спасибо, а можете теперь объяснить поподробнее, что вы сделали?

Последний раз редактировалось Godzilla82; 14.07.2010 в 18:25.
Godzilla82 вне форума  
Непрочитано 14.07.2010, 18:39  
kison
Почётный гражданин KAZUS.RUN
 
Регистрация: 13.12.2004
Сообщений: 3,168
Сказал спасибо: 11
Сказали Спасибо 691 раз(а) в 503 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от Godzilla82 Посмотреть сообщение
WinAVR 2010... Разница тактов 15/16... странно, да?
Разница между чем и чем?
Сообщение от Godzilla82 Посмотреть сообщение
При отключении оптимизации код вообще не работает.
Листинг в студию. Циклов там нет, так что подвиснуть ничего не может. Точку останова ставьте одну, в начале вечноо цикла. Например на PORTD=c;
Если же Вы ставите две, то результаты у Вас выходят меньше на время команды RJMP - на 2 такта. У меня WinAvr20071221.
kison вне форума  
Непрочитано 14.07.2010, 18:40  
testerplus
Прописка
 
Регистрация: 26.01.2009
Сообщений: 249
Сказал спасибо: 23
Сказали Спасибо 102 раз(а) в 61 сообщении(ях)
testerplus на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от SasaVitebsk Посмотреть сообщение
Код:
count = 0;
pold=ENC_B ›› 2;
for( ; ; )
{
  PORTD=a;
  pnew=__swap_nibbles(ENC_B);
  cnt = sw[pnew|pold];
  if(cnt)
  {
	count += cnt;
	pold = pnew‹‹2;
  }
  PORTD=b;
}
}
Обратите внимание на выбранные строки: из-за них код будет работать только на соседних ножках 4 и 5. Какой смысл было выносить их номера в константы-то? Ведь пройдет год - и понадобится нам перенести один из входов с 4-ой на 3-ю, замените Вы определение, тогда программа и упадет, а Вы уже и "помнить забудете", что в программе есть привязка.
testerplus вне форума  
Непрочитано 14.07.2010, 18:49  
Godzilla82
Почётный гражданин KAZUS.RUN
 
Регистрация: 29.10.2006
Сообщений: 1,449
Сказал спасибо: 99
Сказали Спасибо 318 раз(а) в 234 сообщении(ях)
Godzilla82 на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от kison Посмотреть сообщение
Разница между чем и чем?

Листинг в студию. Циклов там нет, так что подвиснуть ничего не может. Точку останова ставьте одну, в начале вечноо цикла. Например на PORTD=c;
Если же Вы ставите две, то результаты у Вас выходят меньше на время команды RJMP - на 2 такта. У меня WinAvr20071221.
Я смотрю в VMLAB осциллографом. Компилил на 2010... Ещё раз говорю, с включённой оптимизацией 15/16 тактов (без изменений сигнала с датчика/при изменении сигналов с датчиков)...

В общем, как ни крути, быстрее 25 тактов не прыгнешь. Может, у кого есть более быстрый алгоритм?

Последний раз редактировалось Godzilla82; 14.07.2010 в 18:55.
Godzilla82 вне форума  
Непрочитано 14.07.2010, 19:23  
kison
Почётный гражданин KAZUS.RUN
 
Регистрация: 13.12.2004
Сообщений: 3,168
Сказал спасибо: 11
Сказали Спасибо 691 раз(а) в 503 сообщении(ях)
kison на пути к лучшему
По умолчанию Re: Может ли меняться логика откомпилированной программы при использовании разных режимов оптимизации?

Сообщение от Godzilla82 Посмотреть сообщение
Я смотрю в VMLAB осциллографом.
Ну так листинг то дайте. Интересно же посмотреть в чем проблемы.
Сообщение от Godzilla82 Посмотреть сообщение
В общем, как ни крути, быстрее 25 тактов не прыгнешь
Возьмите не последнюю версию компилятора. Я же дал - 16/23. Это меньше 25-ти.
kison вне форума  
 
Опции темы

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход


Часовой пояс GMT +4, время: 11:35.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.