Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Перенос кода из под ИАРа на WinAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2, 3
Rst7
Цитата
Наверное, так и придётся поступить в конце концов. Но почему-то жаль...


Я где-то с регулярностью в полгода посматриваю, что происходит на гнусевом фронте. Пробую собирать какие-то куски своего кода и каждый раз убеждаюсь, что качество кодогенерации прилично уступает IAR'у. Ну уступает и уступает. Хрен с ним.

Однако последние версии гнуся просто убили (что WinAVR последний, что сборка klen'а) - это я про полный бред, который он делает из do{*src++=*dst++;}while(--l); если l имеет тип unsigned char. Вот на исследовании этого бага я и настаиваю.
AHTOXA
Насчёт битовых полей. Можно опять же помочь компилятору.
CODE
typedef unsigned char byte;
typedef union
{
byte error;
struct
{
byte frame_err: 1,
ovrun_err: 1,
parity_err: 1,
length_err: 1,
lock_err: 1,
chksum_err: 1,
unknown_command: 1;
}flags;
} USART_ERROR;

struct usart_rx_status
{
byte counter;
byte mode;
volatile unsigned char data_available;
USART_ERROR error;
};

struct usart_rx_status statusRx;
byte rx_buffer[22];

#define RX_SEEK 1
#define RX_RUNNING 2

SIGNAL(SIG_USART0_RECV)
{
static byte sign[] PROGMEM = {'S','N'};
static byte length;
byte data, state;
USART_ERROR error;
error.error = statusRx.error.error;

do
{
state = UCSR0A;
data = UDR0;
if (statusRx.data_available)
{
error.flags.lock_err = TRUE;
continue;
}
if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0)))
{
if (state & (1<<FE0)) error.flags.frame_err = TRUE;
if (state & (1<<DOR0)) error.flags.ovrun_err = TRUE;
if (state & (1<<UPE0)) error.flags.parity_err = TRUE;
statusRx.mode = RX_SEEK;
statusRx.counter = 0;
continue;
}
else
{
error.error = 0;
}
switch(statusRx.mode)
{
case RX_SEEK:
if (statusRx.counter < sizeof(sign))
{
if (data == pgm_read_byte(sign[statusRx.counter]))
{
statusRx.counter++;
}
else
{
statusRx.counter = 0;
}
}
else
{
statusRx.counter = 0;
if (data >= sizeof(rx_buffer) || data == 0)
{
error.flags.length_err = TRUE;
break;
}
rx_buffer[statusRx.counter++] = data;
length = ++data;
statusRx.mode = RX_RUNNING;
}
break;
case RX_RUNNING:
rx_buffer[statusRx.counter++] = data;
length--;
if (!length)
{
statusRx.data_available = TRUE;
statusRx.mode = RX_SEEK;
statusRx.counter = 0;
}
break;
}

}while(UCSR0A & (1<<RXC0));
statusRx.error = error;
}


И получается:
Код
function __vector_18 size 125 (93)

Это для winavr 20071221
alx2
Цитата(sonycman @ Nov 30 2008, 19:19) *
А как помотреть? Я в эклипсе не вижу больше никаких файлов после компиляции, кроме .lss 07.gif
gcc -S предписывает не выполнять ассемблирование. Результат компиляции будет записан в файл с расширением s (если явно не указано иное).
Цитата(sonycman @ Nov 30 2008, 19:19) *
Мне самому просто знаний не хватит написать "извращение", подобное ATOMIC_BLOCK().
По крайней мере, на данных порах.
Тем интереснее будет посмотреть, как это сделано например в avrlibc (именно там я эти макросы нашел). В простейшем случае это дает инструкцию cli при входе в блок и sei при выходе.

Кстати, я бы не рекомендовал использовать for() для обрамления критических блоков. Дело в том, что если внутри такого блока встретится return или будет выброшено исключение, третье выражение for() выполнено не будет, и прерывания так и останутся запрещены. Лучше сделать специальный класс, в конструкторе и деструкторе которого запрещать и разрешать прерывания соответственно. В этом случае будет гарантия, что деструктор выполнится при любом выходе из блока...

Цитата(Rst7 @ Nov 30 2008, 19:47) *
...полный бред, который он делает из do{*src++=*dst++;}while(--l); если l имеет тип unsigned char.
В последних - это в каких? Имеющийся у меня gcc-4.3.1 сгенерил вот это:
Код
.L2:
        ld r24,Z+
        st X+,r24
        subi r20,lo8(-(-1))
        brne .L2
Я этот код бредовым не нахожу...
Rst7
Цитата
Насчёт битовых полей. Можно опять же помочь компилятору.


Это не помощь. А объезд кривого оптимизатора. По науке сам должен был структуру скопировать, а не по полям разносить.

ЗЫ Приведите, чтоли, получившийся код, глянем...

Цитата
В последних - это в каких?


Я же написал в каких. Вот собственно тут можно почитать - http://electronix.ru/forum/index.php?s=&am...st&p=499837

Тут меня постарались убедить, что все хорошо - http://electronix.ru/forum/index.php?s=&am...st&p=501677

Однако тоже оказалось не очень хорошо, если почитать дальше.
sonycman
Цитата(alx2 @ Nov 30 2008, 19:26) *
gcc -S предписывает не выполнять ассемблирование. Результат компиляции будет записан в файл с расширением s (если явно не указано иное).

Спасибо smile.gif
Цитата
Кстати, я бы не рекомендовал использовать for() для обрамления критических блоков. Дело в том, что если внутри такого блока встретится return или будет выброшено исключение, третье выражение for() выполнено не будет, и прерывания так и останутся запрещены. Лучше сделать специальный класс, в конструкторе и деструкторе которого запрещать и разрешать прерывания соответственно.

Но ведь ATOMIC_BLOCK() именно так и сделан?
Petka
Цитата(alx2 @ Nov 30 2008, 18:26) *
Кстати, я бы не рекомендовал использовать for() для обрамления критических блоков. Дело в том, что если внутри такого блока встретится return или будет выброшено исключение, третье выражение for() выполнено не будет, и прерывания так и останутся запрещены. Лучше сделать специальный класс, в конструкторе и деструкторе которого запрещать и разрешать прерывания соответственно. В этом случае будет гарантия, что деструктор выполнится при любом выходе из блока...


Макрос на базе for применять можно. Только нужно его обернуть ещё в один for. тогда return тоже будет корректно обрабатываться. Пример я уже приводил в этом топике.
AHTOXA
Цитата(alx2 @ Nov 30 2008, 20:26) *
В последних - это в каких?


вот тут описано.


Цитата(Rst7 @ Nov 30 2008, 20:28) *
Это не помощь. А объезд кривого оптимизатора. По науке сам должен был структуру скопировать, а не по полям разносить.


Ну если не понимает, то почему бы не подсказать? По крайней мере, это даёт результатsmile.gif

Цитата(Rst7 @ Nov 30 2008, 20:28) *
ЗЫ Приведите, чтоли, получившийся код, глянем...


Пожалуйста:
CODE

17 .section .text.__vector_18,"ax",@progbits
18 .global __vector_18
19 .type __vector_18, @function
20 __vector_18:
21 .LFB2:
22 .LSM0:
23 /* prologue: frame size=0 */
24 0000 1F92 push __zero_reg__
25 0002 0F92 push __tmp_reg__
26 0004 0FB6 in __tmp_reg__,__SREG__
27 0006 0F92 push __tmp_reg__
28 0008 1124 clr __zero_reg__
29 000a 2F93 push r18
30 000c 3F93 push r19
31 000e 4F93 push r20
32 0010 5F93 push r21
33 0012 6F93 push r22
34 0014 7F93 push r23
35 0016 8F93 push r24
36 0018 9F93 push r25
37 001a AF93 push r26
38 001c EF93 push r30
39 001e FF93 push r31
40 /* prologue end (size=16) */
41 .LSM1:
42 0020 5091 0000 lds r21,statusRx+3
43 .LVL0:
44 0024 A091 0000 lds r26,length.1644
45 .LVL1:
46 0028 4091 0000 lds r20,statusRx
47 002c 7091 0000 lds r23,statusRx+1
48 .LVL2:
49 .L2:
50 .LSM2:
51 0030 9BB1 in r25,43-0x20
52 .LSM3:
53 0032 6CB1 in r22,44-0x20
54 .LVL3:
55 .LSM4:
56 0034 8091 0000 lds r24,statusRx+2
57 0038 8823 tst r24
58 003a 01F0 breq .L3
59 .LSM5:
60 003c 5061 ori r21,lo8(16)
61 003e 00C0 rjmp .L5
62 .L3:
63 .LSM6:
64 0040 292F mov r18,r25
65 0042 30E0 ldi r19,lo8(0)
66 0044 C901 movw r24,r18
67 0046 8C71 andi r24,lo8(28)
68 0048 9070 andi r25,hi8(28)
69 004a 892B or r24,r25
70 004c 01F0 breq .L6
71 .LSM7:
72 004e 24FD sbrc r18,4
73 0050 5160 ori r21,lo8(1)
74 .L8:
75 .LSM8:
76 0052 23FD sbrc r18,3
77 0054 5260 ori r21,lo8(2)
78 .L10:
79 .LSM9:
80 0056 22FF sbrs r18,2
81 0058 00C0 rjmp .L28
82 005a 5460 ori r21,lo8(4)
83 005c 00C0 rjmp .L28
84 .L6:
85 .LSM10:
86 005e 50E0 ldi r21,lo8(0)
87 .LSM11:
88 0060 7130 cpi r23,lo8(1)
89 0062 01F0 breq .L14
90 0064 7230 cpi r23,lo8(2)
91 0066 01F4 brne .L5
92 0068 00C0 rjmp .L15
93 .L14:
94 .LSM12:
95 006a 4230 cpi r20,lo8(2)
96 006c 00F4 brsh .L16
97 .LBB2:
98 .LSM13:
99 006e E42F mov r30,r20
100 .LVL4:
101 0070 F0E0 ldi r31,lo8(0)
102 0072 E050 subi r30,lo8(-(sign.1643))
103 0074 F040 sbci r31,hi8(-(sign.1643))
104 0076 E081 ld r30,Z
105 0078 F0E0 ldi r31,lo8(0)
106 /* #APP */
107 007a E491 lpm r30, Z
108
109 .LVL5:
110 /* #NOAPP */
111 .LBE2:
112 007c 6E17 cp r22,r30
113 007e 01F4 brne .L27
114 .LSM14:
115 0080 4F5F subi r20,lo8(-(1))
116 0082 00C0 rjmp .L5
117 .L16:
118 .LSM15:
119 0084 862F mov r24,r22
120 0086 8150 subi r24,lo8(-(-1))
121 0088 8531 cpi r24,lo8(21)
122 008a 00F0 brlo .L20
123 .LSM16:
124 008c 58E0 ldi r21,lo8(8)
125 .L27:
126 008e 40E0 ldi r20,lo8(0)
127 0090 00C0 rjmp .L5
128 .L20:
129 .LSM17:
130 0092 6093 0000 sts rx_buffer,r22
131 .LSM18:
132 0096 A62F mov r26,r22
133 0098 AF5F subi r26,lo8(-(1))
134 .LVL6:
135 009a 41E0 ldi r20,lo8(1)
136 009c 72E0 ldi r23,lo8(2)
137 009e 00C0 rjmp .L5
138 .LVL7:
139 .L15:
140 .LSM19:
141 00a0 E42F mov r30,r20
142 .LVL8:
143 00a2 F0E0 ldi r31,lo8(0)
144 00a4 E050 subi r30,lo8(-(rx_buffer))
145 00a6 F040 sbci r31,hi8(-(rx_buffer))
146 00a8 6083 st Z,r22
147 00aa 4F5F subi r20,lo8(-(1))
148 .LSM20:
149 00ac A150 subi r26,lo8(-(-1))
150 .LVL9:
151 .LSM21:
152 00ae 01F4 brne .L5
153 .LSM22:
154 00b0 81E0 ldi r24,lo8(1)
155 00b2 8093 0000 sts statusRx+2,r24
156 .LVL10:
157 .L28:
158 00b6 40E0 ldi r20,lo8(0)
159 00b8 71E0 ldi r23,lo8(1)
160 .LVL11:
161 .L5:
162 .LSM23:
163 00ba 5F99 sbic 43-0x20,7
164 00bc 00C0 rjmp .L2
165 00be A093 0000 sts length.1644,r26
166 00c2 4093 0000 sts statusRx,r20
167 00c6 7093 0000 sts statusRx+1,r23
168 .LSM24:
169 00ca 5093 0000 sts statusRx+3,r21
170 /* epilogue: frame size=0 */
171 00ce FF91 pop r31
172 00d0 EF91 pop r30
173 00d2 AF91 pop r26
174 00d4 9F91 pop r25
175 00d6 8F91 pop r24
176 00d8 7F91 pop r23
177 00da 6F91 pop r22
178 00dc 5F91 pop r21
179 00de 4F91 pop r20
180 00e0 3F91 pop r19
181 00e2 2F91 pop r18
182 00e4 0F90 pop __tmp_reg__
183 00e6 0FBE out __SREG__,__tmp_reg__
184 00e8 0F90 pop __tmp_reg__
185 00ea 1F90 pop __zero_reg__
186 00ec 1895 reti
187 /* epilogue end (size=16) */
188 /* function __vector_18 size 125 (93) */
Rst7
Цитата
Кстати, я бы не рекомендовал использовать for() для обрамления критических блоков....


Все понятно, рука кодера дрогнет и все сломается. Не применяйте return, break для выхода из такой критической секции. Зато есть плюс - continue приводит к корректному выходу из этого блока. Приятный бонус smile.gif

И самое главное - критическая секция из for - она портабельна. А вот в гнусе это реализовано благодаря дополнительным костылям, которые не соответствуют стандартам

Цитата
Пожалуйста:
CODE....


А ниче так. До IAR'а правда не дотянул. ЧТД smile.gif
Petka
Цитата(Rst7 @ Nov 30 2008, 18:48) *
А вот в гнусе это реализовано благодаря дополнительным костылям, которые не соответствуют стандартам


Ещё раз справшиваю, почему не делать так:

Код
#include <avr/interrupt.h>
#include <util/atomic.h>

uint8_t get_SREG_and_CLI() { uint8_t s = SREG; cli(); return s; }

#define ATOMIC_CODE()   for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp) for(int iter2=0; iter2 < 1; iter2++)


Портабельно, без костылей, хошь на Яре, хоть на Гнусе. И вроде всё правильно отрабатывается?
sonycman
Цитата(Petka @ Nov 30 2008, 19:56) *
Ещё раз справшиваю, почему не делать так:

Код
#include <avr/interrupt.h>
#include <util/atomic.h>

uint8_t get_SREG_and_CLI() { uint8_t s = SREG; cli(); return s; }

#define ATOMIC_CODE()   for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp) for(int iter2=0; iter2 < 1; iter2++)


Портабельно, без костылей, хошь на Яре, хоть на Гнусе. И вроде всё правильно отрабатывается?

А разве при встрече return в теле второго for будет выполняться SREG=__temp?
demiurg_spb
Цитата(Petka @ Nov 30 2008, 18:42) *
Макрос на базе for применять можно. Только нужно его обернуть ещё в один for. тогда return тоже будет корректно обрабатываться.
Расскажите пожалуйста для чего нужна конструкция из нескольких вложенных циклов. Я всегда считал, что return обрывает выполнение процедуры независимо от его местоположения (как аналог инструкции ret на asm). А тут с Ваших слов должно быть другое поведение. Может я чего не знаю о return. Хочется устранить пробелы...
Rst7
Цитата
Ещё раз справшиваю, почему не делать так:


Во-первых надо зафорсить инлайн get_SREG_and_CLI. И сделать ее static. Во вторых - введение второго цикла спасает только от break. От return ничего не спасает. Тогда в чем глубокий смысл? Неужели кодер, который понимает и знает, зачем ему в данный момент критическая секция, не сможет уследить за своими шаловливыми руками, дабы те не всунули break или return? wink.gif

А так все конечно отлично. Спору нет.
demiurg_spb
Цитата(Rst7 @ Nov 30 2008, 19:21) *
введение второго цикла спасает только от break. От return ничего не спасает.
Уфф. Отлеглоsmile.gif
Petka
Цитата(demiurg_spb @ Nov 30 2008, 19:17) *
А тут с Ваших слов должно быть другое поведение. Может я чего не знаю о return. Хочется устранить пробелы...

Сорри, извиняюсь. Ступил. Я конечно-же о break. Конечно-же от return не спасёт.

Тут ко мне идиотская идея пришла:

Код
goto 10
ATOMIC_CODE(){
  func1();
10:
  func2();
  goto 30;
  func3();
}
30:


Будет-ли такое работать?
singlskv
Цитата(Rst7 @ Nov 30 2008, 18:48) *
А ниче так. До IAR'а правда не дотянул. ЧТД smile.gif
Ну раз уж тут IAR vs GCC...
Не могли бы Вы собрать вот этот примерчик под IAR:
Код
#define ARR_SIZE 100

unsigned char src1[ARR_SIZE],src2[ARR_SIZE],dst[ARR_SIZE];

void copy_xor(unsigned char *dst, unsigned char *src1, unsigned char *src2, unsigned char count)
{

  if (count)
  {
    do
    {
      *dst++ = *src1++ ^ *src2++;
    } while (--count);
  }
}

int main(void)
{

  copy_xor(dst, src1, src2, ARR_SIZE);

  while (1);
  return 0;
}

и посчитать сколько МЦ циклов это займет под IAR: copy_xor(dst, src1, src2, ARR_SIZE);
под gcc это занимает 1026МЦ включая передачу параметров... smile.gif
Rst7
Цитата(singlskv @ Nov 30 2008, 22:18) *
Ну раз уж тут IAR vs GCC...
Не могли бы Вы собрать вот этот примерчик под IAR:

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

PS Давайте тогда 4 указателя сделаем, чтобы и гнусь обгадился smile.gif
PPS На самом деле даже на IAR'е можно сделать код, который не очень проиграет этому.

PPPS Кстати, а слабо конкретно этот код собрать последним гнусем. А то в связи с багом это черевато тем, что будет очень ужасно smile.gif
demiurg_spb
Цитата(Petka @ Nov 30 2008, 23:11) *
Тут ко мне идиотская идея пришла:
Код
goto 10
ATOMIC_CODE(){
  func1();
10:
  func2();
  goto 30;
  func3();
}
30:
Будет-ли такое работать?
На мой взгляд не будет: goto заменится на jmp/rjmp и всё...
singlskv
Цитата(Rst7 @ Nov 30 2008, 23:35) *
Я знаю, что будет не очень хорошо. Потому что в гнусе есть еще один указатель. Занятие отдельного указателя под стек конечно ухудшает код в таком случае. Но на самом деле, наверняка можно убрать необходимость третьего указателя, но тут надо рассматривать функцию в общем контексте.
Ну дык это будет всегда когда данные будут из >2источников (структур, массивов, итд)
Цитата
PS Давайте тогда 4 указателя сделаем, чтобы и гнусь обгадился smile.gif
для 4:
Код
void copy_xor(unsigned char *dst, unsigned char *src1, unsigned char *src2, unsigned char *src3, unsigned char count)
{

  if (count)
  {
    do
    {
      *dst++ = *src1++ ^ *src2++ ^ *src3++;
    } while (--count);
  }
}
1740 МЦ, а сколько на IAR ?
Цитата
PPS На самом деле даже на IAR'е можно сделать код, который не очень проиграет этому.
А это как ? Если копировать побайтно...

Цитата
PPPS Кстати, а слабо конкретно этот код собрать последним гнусем. А то в связи с багом это черевато тем, что будет очень ужасно smile.gif
А вот это без меня smile.gif я сижу на gcc3.4.6 (winavr20060421) и никуда пока не собираюсь,
пускай по граблям ходют другие...
sonycman
Если заставить разрабов ИАРа довести до ума работу с указателями, то в гнусе не останется больше ничего привлекательного...
Может, не надо, а? smile.gif
aesok
avr-gcc 4.4

Код
void copy_xor(unsigned char *    dst, unsigned char *    src1, unsigned char *    src2, unsigned char count)
{

  if (count)
  {
    do
    {
      *dst++ = *src1++ ^ *src2++;
    } while (--count);
  }
}


-Os
Код
void copy_xor(unsigned char *    dst, unsigned char *    src1, unsigned char *    src2, unsigned char count)
{
  ce:    ef 92           push    r14
  d0:    ff 92           push    r15
  d2:    0f 93           push    r16
  d4:    1f 93           push    r17
  d6:    cf 93           push    r28
  d8:    df 93           push    r29

  if (count)
  da:    22 23           and    r18, r18
  dc:    c9 f0           breq    .+50; 0x110 <copy_xor+0x42>

#define ARR_SIZE 100

unsigned char src1[ARR_SIZE],src2[ARR_SIZE],dst[ARR_SIZE];

void copy_xor(unsigned char *    dst, unsigned char *    src1, unsigned char *    src2, unsigned char count)
  de:    21 50           subi    r18, 0x01; 1
  e0:    30 e0           ldi    r19, 0x00; 0
  e2:    2f 5f           subi    r18, 0xFF; 255
  e4:    3f 4f           sbci    r19, 0xFF; 255
  e6:    e0 e0           ldi    r30, 0x00; 0
  e8:    f0 e0           ldi    r31, 0x00; 0

  if (count)
  {
    do
    {
      *dst++ = *src1++ ^ *src2++;
  ea:    7c 01           movw    r14, r24
  ec:    ee 0e           add    r14, r30
  ee:    ff 1e           adc    r15, r31
  f0:    8a 01           movw    r16, r20
  f2:    0e 0f           add    r16, r30
  f4:    1f 1f           adc    r17, r31
  f6:    eb 01           movw    r28, r22
  f8:    ce 0f           add    r28, r30
  fa:    df 1f           adc    r29, r31
  fc:    d8 01           movw    r26, r16
  fe:    0c 91           ld    r16, X
100:    18 81           ld    r17, Y
102:    10 27           eor    r17, r16
104:    d7 01           movw    r26, r14
106:    1c 93           st    X, r17
108:    31 96           adiw    r30, 0x01; 1
    } while (--count);
10a:    e2 17           cp    r30, r18
10c:    f3 07           cpc    r31, r19
10e:    69 f7           brne    .-38; 0xea <copy_xor+0x1c>
  }
}
110:    df 91           pop    r29
112:    cf 91           pop    r28
114:    1f 91           pop    r17
116:    0f 91           pop    r16
118:    ff 90           pop    r15
11a:    ef 90           pop    r14
11c:    08 95           ret


-Os -fno-ivopts
Код
void copy_xor(unsigned char *    dst, unsigned char *    src1, unsigned char *    src2, unsigned char count)
{
  ce:    cf 93           push    r28
  d0:    df 93           push    r29
  d2:    fc 01           movw    r30, r24
  d4:    db 01           movw    r26, r22
  d6:    ea 01           movw    r28, r20

  if (count)
  d8:    22 23           and    r18, r18
  da:    31 f0           breq    .+12; 0xe8 <copy_xor+0x1a>
  {
    do
    {
      *dst++ = *src1++ ^ *src2++;
  dc:    99 91           ld    r25, Y+
  de:    8d 91           ld    r24, X+
  e0:    89 27           eor    r24, r25
  e2:    81 93           st    Z+, r24
    } while (--count);
  e4:    21 50           subi    r18, 0x01; 1
  e6:    f8 cf           rjmp    .-16; 0xd8 <copy_xor+0xa>
  }
}
  e8:    df 91           pop    r29
  ea:    cf 91           pop    r28
  ec:    08 95           ret


Вы не умеете его готовить.

Анатолий.
sonycman
Но всё же даже у гнуса бывают косяки с указателями.
И всего-то с двумя:
Код
    case    USART_SEND_DATA_EX:
        length    =    4 + 4 + 4 + 20;
        *pb++    =    length + 1;
        *pb++    =    command;
        *pb++    =    temperature.cpu;
        *pb++    =    temperature.gpu;
        *pb++    =    temperature.amb;
        *pb++    =    temperature.hdd;
        *pb++   =   fan_speed[FAN_CPU];
        *pb++   =   fan_speed[FAN_SIDE];
        *pb++   =   fan_speed[FAN_REAR];
        *pb++   =   fan_speed[FAN_FRONT];
        *pb++    =    cpuFan.GetManualStatus();
        *pb++    =    rearFan.GetManualStatus();
        *pb++    =    sideFan.GetManualStatus();
        *pb++    =    frontFan.GetManualStatus();
        *pb++    =    cpuFan.minRPM;
        *pb++    =    cpuFan.maxRPM;
        *pb++    =    cpuFan.minCELSIUS;
        *pb++    =    cpuFan.maxCELSIUS;
        *pb++    =    cpuFan.stopCELSIUS;
        *pb++    =    rearFan.minRPM;
        *pb++    =    rearFan.maxRPM;
        *pb++    =    rearFan.minCELSIUS;
        *pb++    =    rearFan.maxCELSIUS;
        *pb++    =    rearFan.stopCELSIUS;
        *pb++    =    sideFan.minRPM;
        *pb++    =    sideFan.maxRPM;
        *pb++    =    sideFan.minCELSIUS;
        *pb++    =    sideFan.maxCELSIUS;
        *pb++    =    sideFan.stopCELSIUS;
        *pb++    =    frontFan.minRPM;
        *pb++    =    frontFan.maxRPM;
        *pb++    =    frontFan.minCELSIUS;
        *pb++    =    frontFan.maxCELSIUS;
        *pb++    =    frontFan.stopCELSIUS;

код получается сплошняком из LDS/STS, так как адреса переменных (члены классов) статические и гнус таким образом "оптимизирует".
После того, как я перевёл приёмник в локальные переменные (пришлось водрузить буффер на стёк), код немного улучшился:
Код
   case    USART_SEND_DATA_EX:
        length    =    4 + 4 + 4 + 20;
        *pb++    =    length + 1;
    1320:    81 e2           ldi    r24, 0x21; 33
    1322:    8b 83           std    Y+3, r24; 0x03
        *pb++    =    command;
    1324:    0c 83           std    Y+4, r16; 0x04
        *pb++    =    temperature.cpu;
    1326:    80 91 62 01     lds    r24, 0x0162
    132a:    8d 83           std    Y+5, r24; 0x05
        *pb++    =    temperature.gpu;
    132c:    80 91 63 01     lds    r24, 0x0163
    1330:    8e 83           std    Y+6, r24; 0x06
        *pb++    =    temperature.amb;
    1332:    80 91 64 01     lds    r24, 0x0164
    1336:    8f 83           std    Y+7, r24; 0x07
        *pb++    =    temperature.hdd;
    1338:    80 91 65 01     lds    r24, 0x0165
    133c:    88 87           std    Y+8, r24; 0x08
        *pb++   =   fan_speed[FAN_CPU];
    133e:    80 91 9d 01     lds    r24, 0x019D
    1342:    89 87           std    Y+9, r24; 0x09
        *pb++   =   fan_speed[FAN_SIDE];
    1344:    80 91 9e 01     lds    r24, 0x019E
    1348:    8a 87           std    Y+10, r24; 0x0a
        *pb++   =   fan_speed[FAN_REAR];
    134a:    80 91 9f 01     lds    r24, 0x019F
    134e:    8b 87           std    Y+11, r24; 0x0b
        *pb++   =   fan_speed[FAN_FRONT];
    1350:    80 91 a0 01     lds    r24, 0x01A0
    1354:    8c 87           std    Y+12, r24; 0x0c
        *pb++    =    cpuFan.GetManualStatus();
    1356:    8f e0           ldi    r24, 0x0F; 15
    1358:    92 e0           ldi    r25, 0x02; 2
    135a:    83 d8           rcall    .-3834   ; 0x462 <CFanRegulatorBase::GetManualStatus()>
    135c:    8d 87           std    Y+13, r24; 0x0d
        *pb++    =    rearFan.GetManualStatus();
    135e:    8c e1           ldi    r24, 0x1C; 28
    1360:    92 e0           ldi    r25, 0x02; 2
    1362:    7f d8           rcall    .-3842   ; 0x462 <CFanRegulatorBase::GetManualStatus()>
    1364:    8e 87           std    Y+14, r24; 0x0e
        *pb++    =    sideFan.GetManualStatus();
    1366:    89 e2           ldi    r24, 0x29; 41
    1368:    92 e0           ldi    r25, 0x02; 2
    136a:    7b d8           rcall    .-3850   ; 0x462 <CFanRegulatorBase::GetManualStatus()>
    136c:    8f 87           std    Y+15, r24; 0x0f
        *pb++    =    frontFan.GetManualStatus();
    136e:    86 e3           ldi    r24, 0x36; 54
    1370:    92 e0           ldi    r25, 0x02; 2
    1372:    77 d8           rcall    .-3858   ; 0x462 <CFanRegulatorBase::GetManualStatus()>
    1374:    88 8b           std    Y+16, r24; 0x10
        *pb++    =    cpuFan.minRPM;
    1376:    80 91 18 02     lds    r24, 0x0218
    137a:    89 8b           std    Y+17, r24; 0x11
        *pb++    =    cpuFan.maxRPM;
    137c:    80 91 17 02     lds    r24, 0x0217
    1380:    8a 8b           std    Y+18, r24; 0x12
        *pb++    =    cpuFan.minCELSIUS;
    1382:    80 91 1a 02     lds    r24, 0x021A
    1386:    8b 8b           std    Y+19, r24; 0x13
        *pb++    =    cpuFan.maxCELSIUS;
    1388:    80 91 19 02     lds    r24, 0x0219
    138c:    8c 8b           std    Y+20, r24; 0x14
        *pb++    =    cpuFan.stopCELSIUS;
    138e:    80 91 1b 02     lds    r24, 0x021B
    1392:    8d 8b           std    Y+21, r24; 0x15
        *pb++    =    rearFan.minRPM;
    1394:    80 91 25 02     lds    r24, 0x0225
    1398:    8e 8b           std    Y+22, r24; 0x16
        *pb++    =    rearFan.maxRPM;
    139a:    80 91 24 02     lds    r24, 0x0224
    139e:    8f 8b           std    Y+23, r24; 0x17
        *pb++    =    rearFan.minCELSIUS;
    13a0:    80 91 27 02     lds    r24, 0x0227
    13a4:    88 8f           std    Y+24, r24; 0x18
        *pb++    =    rearFan.maxCELSIUS;
    13a6:    80 91 26 02     lds    r24, 0x0226
    13aa:    89 8f           std    Y+25, r24; 0x19
        *pb++    =    rearFan.stopCELSIUS;
    13ac:    80 91 28 02     lds    r24, 0x0228
    13b0:    8a 8f           std    Y+26, r24; 0x1a
        *pb++    =    sideFan.minRPM;
    13b2:    80 91 32 02     lds    r24, 0x0232
    13b6:    8b 8f           std    Y+27, r24; 0x1b
        *pb++    =    sideFan.maxRPM;
    13b8:    80 91 31 02     lds    r24, 0x0231
    13bc:    8c 8f           std    Y+28, r24; 0x1c
        *pb++    =    sideFan.minCELSIUS;
    13be:    80 91 34 02     lds    r24, 0x0234
    13c2:    8d 8f           std    Y+29, r24; 0x1d
        *pb++    =    sideFan.maxCELSIUS;
    13c4:    80 91 33 02     lds    r24, 0x0233
    13c8:    8e 8f           std    Y+30, r24; 0x1e
        *pb++    =    sideFan.stopCELSIUS;
    13ca:    80 91 35 02     lds    r24, 0x0235
    13ce:    8f 8f           std    Y+31, r24; 0x1f
        *pb++    =    frontFan.minRPM;
    13d0:    80 91 3f 02     lds    r24, 0x023F
    13d4:    88 a3           std    Y+32, r24; 0x20
        *pb++    =    frontFan.maxRPM;
    13d6:    80 91 3e 02     lds    r24, 0x023E
    13da:    89 a3           std    Y+33, r24; 0x21
        *pb++    =    frontFan.minCELSIUS;
    13dc:    80 91 41 02     lds    r24, 0x0241
    13e0:    8a a3           std    Y+34, r24; 0x22
        *pb++    =    frontFan.maxCELSIUS;
    13e2:    80 91 40 02     lds    r24, 0x0240
    13e6:    8b a3           std    Y+35, r24; 0x23
        *pb++    =    frontFan.stopCELSIUS;
    13e8:    80 91 42 02     lds    r24, 0x0242
    13ec:    8c a3           std    Y+36, r24; 0x24
    13ee:    10 e2           ldi    r17, 0x20; 32
    13f0:    04 c0           rjmp    .+8      ; 0x13fa <usartSendCommand(unsigned char, void const*)+0x1ea>

но всё равно не хватило сообразительности задействовать второй указатель.

ИАР без проблем юзает здесь два указателя даже со статическим буффером pb... smile.gif
singlskv
Цитата(sonycman @ Dec 1 2008, 00:52) *
но всё равно не хватило сообразительности задействовать второй указатель.
ИАР без проблем юзает здесь два указателя даже со статическим буффером pb... smile.gif
http://electronix.ru/forum/index.php?showt...mp;#entry506246

ну сделайте и обращение к структуре не статическим
Сергей Борщ
Цитата(aesok @ Nov 30 2008, 23:45) *
-Os -fno-ivopts
....
Вы не умеете его готовить.
Не могли бы вы более развернуто прокомментировать этот эффект? Как видно, отключение одной из оптимизаций привело к существенному улучшению кода. Разве в компиляторе не предусмотрен анализ результатов оптимизации? Т.е. если после какой-либо оптимизации код стал хуже по основоному критерию (-Os), то не выполнять эту оптимизацию на данном участке кода. Просто интересно.


Цитата(sonycman @ Nov 30 2008, 23:21) *
Если заставить разрабов ИАРа довести до ума работу с указателями, то в гнусе не останется больше ничего привлекательного...
Скорее наоборот. Если в avr-gcc появится возможность полноценной работы с указателями на разные адресные пространства, то в ИАРе, учитывая его цену, не останется ничего привлекательного для тех, кто стоит перед выбором.
sonycman
Цитата(singlskv @ Dec 1 2008, 02:08) *
ну сделайте и обращение к структуре не статическим

Как? Если создавать копию структуры на стёке - то это опять лишнее место и время.
А как ещё можно сделать переменные класса динамическими без лишнего гиморроя?

Цитата(Сергей Борщ @ Dec 1 2008, 05:21) *
Скорее наоборот. Если в avr-gcc появится возможность полноценной работы с указателями на разные адресные пространства, то в ИАРе, учитывая его цену, не останется ничего привлекательного для тех, кто стоит перед выбором.

Но ведь GCC и так работает с указателями часто лучше, чем IAR?
Зато посмотрите, как он хромает при работе с битовыми полями... sad.gif
Rst7
Цитата
А это как ? Если копировать побайтно...


Ну Вы же должны знать главное правило в программировании. Это я насчет соотношения время/размер:
Код
void copy_xor_fast(unsigned char *    dst, unsigned char *    src1, unsigned char *    src2, unsigned char count)
{
  while(count&3)
  {
    *dst++=*src1++^*src2++;
    count--;
  }
  if (count)
  do
  {
    unsigned char v0,v1,v2,v3;
    v0=*src1++;
    v1=*src1++;
    v2=*src1++;
    v3=*src1++;
    v0^=*src2++;
    v1^=*src2++;
    v2^=*src2++;
    v3^=*src2++;
    *dst++=v0;
    *dst++=v1;
    *dst++=v2;
    *dst++=v3;
  }
  while(count-=4);
}


Время в функции 888 тактов.
singlskv
Цитата(Rst7 @ Dec 1 2008, 09:53) *
Ну Вы же должны знать главное правило в программировании. Это я насчет соотношения время/размер:
я имел в виду побайтово, те байт за проход цикла, но даже здесь
Цитата
void copy_xor_fast(unsigned char *dst, unsigned char *src1, unsigned char *src2, unsigned char count)
Время в функции 888 тактов.
у gcc 809 тактов.
Rst7
Цитата
я имел в виду


А я имею в виду, что скорее всего Ваш пример высосан из пальца, чисто для того, чтобы показать узкое место IAR'а.
aesok
Цитата(Сергей Борщ @ Dec 1 2008, 04:21) *
Не могли бы вы более развернуто прокомментировать этот эффект?


Я не знаю этот проход оптимизации, он заменил тело цикла:
*dst++ = *src1++ ^ *src2++;

на:
;; MEM[base: dst + ivtmp.11] = [bit_xor_expr] MEM[base: src2 + ivtmp.11] ^ MEM[base: src1 + ivtmp.11];
;; ivtmp.11 = ivtmp.11 + 1;

Предположив что выполнять в теле цикла 3 сложения регистров и одно сложение с константой выгоднее, чем 4 сложения с константой.

Вот что говориться про это проход:
Код
/* This pass tries to find the optimal set of induction variables for the loop.
   It optimizes just the basic linear induction variables (although adding
   support for other types should not be too hard).  It includes the
   optimizations commonly known as strength reduction, induction variable
   coalescing and induction variable elimination.  It does it in the
   following steps:

   1) The interesting uses of induction variables are found.  This includes

      -- uses of induction variables in non-linear expressions
      -- addresses of arrays
      -- comparisons of induction variables

   2) Candidates for the induction variables are found.  This includes

      -- old induction variables
      -- the variables defined by expressions derived from the "interesting
     uses" above

   3) The optimal (w.r. to a cost function) set of variables is chosen.  The
      cost function assigns a cost to sets of induction variables and consists
      of three parts:

      -- The use costs.  Each of the interesting uses chooses the best induction
     variable in the set and adds its cost to the sum.  The cost reflects
     the time spent on modifying the induction variables value to be usable
     for the given purpose (adding base and offset for arrays, etc.).
      -- The variable costs.  Each of the variables has a cost assigned that
     reflects the costs associated with incrementing the value of the
     variable.  The original variables are somewhat preferred.
      -- The set cost.  Depending on the size of the set, extra cost may be
     added to reflect register pressure.

      All the costs are defined in a machine-specific way, using the target
      hooks and machine descriptions to determine them.

   4) The trees are transformed to use the new variables, the dead code is
      removed.
  
   All of this is done loop by loop.  Doing it globally is theoretically
   possible, it might give a better performance and it might enable us
   to decide costs more precisely, but getting all the interactions right
   would be complicated.  */


Больше информации о этом проходе, а также о том можно ли его более точно настроить для AVR можно попытаться найти в файле tree-ssa-loop-ivopts.c

Цитата(Сергей Борщ @ Dec 1 2008, 04:21) *
Как видно, отключение одной из оптимизаций привело к существенному улучшению кода. Разве в компиляторе не предусмотрен анализ результатов оптимизации?


Нет. Есть порядка 200 проходов, большая часть из которых являются оптимизирующими, друга часть служебными. Для каждого уровня оптимизации существует свой набор проходов. Каждая платформа может модифицировать эти наборы под себя. Пользователь может дополнительно включать отключать проходы с помощью ключей -f*.

Анализатором выступает разработчик/пользователь.

Анатолий.
sonycman
Заметил интересную особенность GCC по работе с виртуальными функциями.

Есть базовый класс с одной виртуальной функцией:
Код
class    CFanRegulatorBase    {
...
    virtual void pwmOutputValue(byte value) {};
...
};

и четыре производных класса:
Код
class    CCpuRegulator : public CFanRegulatorBase    {
...
    void pwmOutputValue(byte value);
...
};

То есть каждый класс имеет свою уникальную функцию pwmOutputValue.
Для чего компилятор создаёт в памяти таблицу с адресами для каждой такой функции.

В ИАР для этого отводится 2*5 (четыре функции производных классов плюс одна базового) байт памяти программ.

В GCC - почему-то 6*5 байт памяти данных. Не понятно, почему именно шесть байт в таблице, и не совсем понятно, почему именно в оперативке - 30 байт это не мало...

Пока что получается, что ИАР компилирует код более компактный как по ROM, так и по RAM...
singlskv
Цитата(Rst7 @ Dec 1 2008, 12:44) *
А я имею в виду, что скорее всего Ваш пример высосан из пальца, чисто для того, чтобы показать узкое место IAR'а.
Неа, он взят из реальной проги, вот кусок:
Код
    if (wrtype & 0x02)     // AND или XOR
    {
      if (wrtype & 0x04)     // XOR , wrtype==6
      {
        do {
          tmp1=*pS++;        // данные для записи
          tmp2=*pD;          // данные из базы
          tmp1 ^= tmp2;
          *pD++=tmp1;        // переносим в базу
          *pB++=tmp1;        // заполняем данные ответа
        } while (--len);
      }
      else                   // AND , wrtype==2
      {
        do {
          tmp1=*pS++;        // данные для записи
          tmp2=*pD;          // данные из базы
          tmp1 &= tmp2;
          *pD++=tmp1;        // переносим в базу
          *pB++=tmp1;        // заполняем данные ответа
        } while (--len);
      }
    }
    else                   // REP или OR
    {
      if (wrtype & 0x04)     // OR  , wrtype==4
      {
        do {
          tmp1=*pS++;        // данные для записи
          tmp2=*pD;          // данные из базы
          tmp1 |= tmp2;
          *pD++=tmp1;        // переносим в базу
          *pB++=tmp1;        // заполняем данные ответа
        } while (--len);
      }
      else                   // REP , wrtype==0
      {
        do {
          tmp1=*pS++;        // данные для записи
          *pD++=tmp1;        // переносим в базу
          *pB++=tmp1;        // заполняем данные ответа
        } while (--len);
      }
    }

И IARу плохеет на таком коде, а gcc делает почти 1 в 1 с асм.
Сергей Борщ
Цитата(aesok @ Dec 1 2008, 18:37) *
Есть порядка 200 проходов, большая часть из которых являются оптимизирующими, друга часть служебными. Для каждого уровня оптимизации существует свой набор проходов. Каждая платформа может модифицировать эти наборы под себя. Пользователь может дополнительно включать отключать проходы с помощью ключей -f*.
Спасибо, очень познавательно.
ARV
Цитата(singlskv @ Dec 2 2008, 00:40) *
И IARу плохеет на таком коде, а gcc делает почти 1 в 1 с асм.
если в этом коде внутрь цикла do перенести анализ ваших переменных (может, даже вместо if использовать switch), то он станет и короче, да и оттранслируется лучше. ведь разница в четырех ветках всего лишь в способе изменения tmp1....
Rst7
Цитата
если в этом коде внутрь цикла do перенести анализ ваших переменных (может, даже вместо if использовать switch), то он станет и короче, да и оттранслируется лучше. ведь разница в четырех ветках всего лишь в способе изменения tmp1....


Ну-ну. Код как раз грамотно написан, вынесены из циклов проверки.

Цитата(aesok @ Dec 1 2008, 18:37) *
Вот что говориться про это проход:
....


Все понятно. Я так и предполагал, что это векторизация, не знал только, что можно отключить.

Цитата
а также о том можно ли его более точно настроить для AVR


Ну так для AVR можно сразу выключить эту оптимизацию, потому как нет нативной поддержки в системе комманд. Это будет самая грамотная настройка smile.gif

Цитата
И IARу плохеет на таком коде, а gcc делает почти 1 в 1 с асм.


Плохеет. Спору нет.

Теперь давайте я попробую проявить телепатические способности wink.gif

Приведенный код - это, видимо, разнообразная печаталка символов на графический дисплей? Если да, то имеет смысл развернуть циклы для ускорения, все-таки это самое узкое место в гуйне. А при развороте проигрыша у IAR'а - ну отсилы несколько процентов. Что на общем фоне повышения производительности - так и не заметно.

А вот другого плана алгоритм - я тут попробовал собрать свою процедуру md5, оптимизированную под AVR... Гнусь сдался по всем параметрам - по размеру кода, по скорости, по требуемому стеку (собственно, взаимосвязь проста - ниасилил разложить все что можно в регистрах, полез в стек и сдался).
ARV
Цитата(Rst7 @ Dec 2 2008, 10:25) *
Ну-ну. Код как раз грамотно написан, вынесены из циклов проверки.

позволю себе не согласиться. я сделал такую: "обертку" показанного участка
Код
#include <avr/io.h>

volatile uint8_t wrtype, tmp1, tmp2, len;
volatile uint8_t *pD, *pB, *pS;

int main(void){
   while(1){
      // здесь приведенный участок кода 1 в 1
   }
}

скомпилировал эту программку для atmega128 с опцией -Os, в итоге получил 638 байт программного кода.

затем я модифицировал код, как говорил:
Код
int main(void){
while(1){
   do{
        tmp1=*pS++;      
        tmp2=*pD;    
        if (wrtype & 0x02)  
            if (wrtype & 0x04)  
                tmp1 ^= tmp2;
            else
                tmp1 &= tmp2;
        else
            if (wrtype & 0x04)  
                tmp1 |= tmp2;
          *pD++=tmp1;      
          *pB++=tmp1;      
     } while(--len);  
}}
как я понимаю, логика сохранилась полностью (надеюсь, я не ошибся).
результат компиляции: 360 байт памяти программ.

Разница существенная, не так ли? а замедление скорости работы, думаю, явно не в 2 раза smile.gif
Rst7
Цитата
а замедление скорости работы, думаю, явно не в 2 раза


Больше чем в 2 smile.gif
ARV
Цитата(Rst7 @ Dec 2 2008, 11:15) *
Больше чем в 2 smile.gif

ну, вполне возможно, что и так, я не смотрел листинг. 2 команды среди 4-х - это существенно... но иногда размер имеет большее значение, чем быстрота smile.gif
_Pasha
Цитата(Rst7 @ Dec 2 2008, 12:15) *
Больше чем в 2 smile.gif

Оно и понятно: Надо tmp1 tmp2 в теле do-while объявлять, для начала.
Код
      if (wrtype & 0x02)  
  88:    80 91 02 01     lds    r24, 0x0102
  8c:    81 ff           sbrs    r24, 1
  8e:    08 c0           rjmp    .+16    ; 0xa0 <main+0x34>
            if (wrtype & 0x04)  
  90:    80 91 02 01     lds    r24, 0x0102
  94:    82 ff           sbrs    r24, 2
  96:    02 c0           rjmp    .+4     ; 0x9c <main+0x30>
                tmp1 ^= tmp2;
  98:    92 27           eor    r25, r18
  9a:    06 c0           rjmp    .+12    ; 0xa8 <main+0x3c>
            else
                tmp1 &= tmp2;
  9c:    92 23           and    r25, r18
  9e:    04 c0           rjmp    .+8     ; 0

Тормоза ушли. Можно дальше точить.
ЗЫ мега48, исходный размер около 260 байт, после локализации переменных 216
ARV
Цитата(_Pasha @ Dec 2 2008, 11:40) *
Оно и понятно: Надо tmp1 tmp2 в теле do-while объявлять, для начала.
...
Тормоза ушли. Можно дальше точить.
нет предела совершенству smile.gif в любой программе имеется хотя бы одна ошибка... извините за оффтоп...
_Pasha
Цитата(ARV @ Dec 2 2008, 12:48) *
нет предела совершенству smile.gif

Не хвастовства ради, гляньте, что получится при компиляции
Код
int main(void){
while(1){
  uint8_t * pD1 = pD;
  uint8_t * pS1 = pS;
  uint8_t * pB1 = pB;
   do{
   uint8_t tmp1=*pS1++;      
   uint8_t tmp2=*pD1;    
   uint8_t tmp3 = wrtype;

     tmp1 = (tmp3 & 0x02)?
       ((tmp3 & 0x04)? (tmp1 ^ tmp2):(tmp1 & tmp2))
      :((tmp3 & 0x04)? (tmp1 | tmp2):(tmp1));
    
          *pD1++=tmp1;      
          *pB1++=tmp1;      
     } while(--len);
   pB = pB1;
   pS = pS1;
   pD = pD1;
      
}}

Исходные те же
Должно получиться: ручной работы асм один в один.
Вывод: как все сложно в работе с глобальными переменными ! sad.gif
ARV
Цитата(_Pasha @ Dec 2 2008, 12:51) *
Не хвастовства ради, гляньте, что получится при компиляции
Исходные те же
Должно получиться: ручной работы асм один в один.
Вывод: как все сложно в работе с глобальными переменными ! sad.gif
а смысл? и так понятно, что по размеру это существенно оптимальнее... а вот сравнить с результатом IAR-а - это интересно, ведь с высказывания, что
Цитата
И IARу плохеет на таком коде, а gcc делает почти 1 в 1 с асм.
все началось... вот и поглядеть, плохеет ли ему в этом случае, или нет.
_Pasha
Цитата(ARV @ Dec 2 2008, 14:40) *
плохеет ли ему в этом случае, или нет.

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


Именно. Так что пробовать бестолку. И так могу сказать, что будет.

Другое дело, что ресурс в виде объема флеша сейчас не самое страшное, а вот получить быстродействующий прибор - это совсем другое (лично меня бесит смотреть на приборы, на которых видно, как экран обновляется, или у которых тормоза после нажатия на кнопку). И решить это можно, не очень проиграв в объемах.
singlskv
Цитата(Rst7 @ Dec 2 2008, 10:25) *
Все понятно. Я так и предполагал, что это векторизация, не знал только, что можно отключить.
Ну так для AVR можно сразу выключить эту оптимизацию, потому как нет нативной поддержки в системе комманд. Это будет самая грамотная настройка smile.gif
Вот это одна из причин почему я не перелезаю с gcc3.4.6 на 4.x.x.
Почему-то когда gcc стал переползать на 4.x.x в каждой новой версии свои приколы
и без хорошего знания "спецключиков" и без проверки "а что же получилось..."
работать сложно.
Цитата
Плохеет. Спору нет.
Теперь давайте я попробую проявить телепатические способности wink.gif
Приведенный код - это, видимо, разнообразная печаталка символов на графический дисплей? Если да, то имеет смысл развернуть циклы для ускорения, все-таки это самое узкое место в гуйне. А при развороте проигрыша у IAR'а - ну отсилы несколько процентов. Что на общем фоне повышения производительности - так и не заметно.
Не угадали, это обмен по UART или I2C на довольно большой скорости (~350Кбит/c)
в условиях довольно жесткого реалтайма (такт 500 мкс.) и копирование нужно сделать
в пределах 1 такта и еще много чего...
конечно циклы можно было и подразвернуть, но обошлось и так причем с некоторым запасом...
Цитата
А вот другого плана алгоритм - я тут попробовал собрать свою процедуру md5, оптимизированную под AVR... Гнусь сдался по всем параметрам - по размеру кода, по скорости, по требуемому стеку (собственно, взаимосвязь проста - ниасилил разложить все что можно в регистрах, полез в стек и сдался).
Да, бывает что гнусь дуреет на алгоритмах когда нужно много регистров,
ну или на сложной арифметике какой... и тогда нужно бить выражения на части.
Но пример конечно был про то что не всегда он так уж плох, а иногда очень
даже лучше..


Цитата(ARV @ Dec 2 2008, 13:40) *
а смысл? и так понятно, что по размеру это существенно оптимальнее... а вот сравнить с результатом IAR-а - это интересно, ведь с высказывания, что все началось... вот и поглядеть, плохеет ли ему в этом случае, или нет.
Господа "оптимизаторы", я по-моему сразу дал понять что разговор о скорости
выполнения при сохранении разумных размеров...

Вынос проверок за циклы, вложенные(двоичный поиск) if вместо switch(16бит) итд,
в данном конкретном случае только для достижения скорости.
Ну и конечно все переменные которые участвуют в этом коде локальные.
ReAl
Кстати, о ключиках.
Вынос проверок за цикл с дублированием тела цикла без проверки для каждой ветви осуществляется ключиком
-funswitch-loops
хотя, конечно, при ручном выносе код получше выходит.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.