Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Стиль программирования на Си
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
defunct
Цитата(Сергей Борщ @ Apr 2 2008, 14:34) *
Ну как же? локальную переменную типа char для цикла в puts так и хочется обозвать заглавной C.

кому как, во всех реализациях, что я встечал параметр put'ов описан прописной "c" или (чаще) "ch".
и лок. переменную почему бы не назвать одним из этих имен. ;>
ReAl
Цитата(defunct @ Apr 2 2008, 14:15) *
Это я в курсе smile.gif
Дело принципа и привычки, от ++ в глазах рябит.
Фух, а то я уж, виноват, подумал, что это способ уменьшения размера глюкодрома по причине врождённой глюкавости операторов ++ --.
Привычки - это нормально, ненормально когда их оправдывают высокими соображениями smile.gif
defunct
Цитата(ReAl @ Apr 2 2008, 14:40) *
Фух, а то я уж, виноват, подумал, что это способ уменьшения размера глюкодрома по причине врождённой глюкавости операторов ++ --.

Я виноват что смайлик забыл поставить после "ни ни" smile.gif
zltigo
Цитата(ReAl @ Apr 2 2008, 14:55) *
По поводу смешанных проектов - никто не мешает весь С-текст держать в отдельных файлах, компилировать в С-режиме со всеми функциональными макросами, а потом линковать с С++ - программой, скомпилированной в С++ режиме.

Да? А как вызывать "С++" функции из "С"? Через псевдосишные сишные обертки? - нет спасибо..
sKWO
Позволю небольшой отрывок кода, извиняюсь что немного прерываю...
доступ к флагам
Код
/****************************************************************************
Системные флаги
****************************************************************************/
#define System_Flags GPIOR0
enum
    {
        KEY_VALID     = (1 << 0),
        NEED_FLASH    = (1 << 1),
        SOUND_ENABLE  = (1 << 2)
    };

void  main (void){
  if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH;
  if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE;
};

тот же код но с препроцессором
Код
#define System_Flags GPIOR0
#define KEY_VALID  (1 << 0)
#define NEED_FLASH  (1 << 1)
#define SOUND_ENABLE (1 << 2)
void  main (void){
  if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH;
  if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE;
};

Даёт одинаковый код smile.gif
Код
//   18   if(System_Flags & KEY_VALID) System_Flags &= ~NEED_FLASH;
        SBIC    0x1E, 0x00
        CBI     0x1E, 0x01
//   19   if(System_Flags & NEED_FLASH) System_Flags &= ~SOUND_ENABLE;
??main_0:
        SBIC    0x1E, 0x01
        CBI     0x1E, 0x02
SasaVitebsk
Вот об этом я и говорю - богатство выбора в рамках языка.

При написании сложных операторов с большим количеством операций по типу ++/-- могут быть грабли. Они достаточно подробно описаны даже в учебниках. Но, как мне кажется, не стоит перегружать операторы. Это неудобно для отладки к примеру и ухудшает читаемость. С другой стороны, совершенно очевидно, что компилятору по барабану написали ли вы формулу одним оператором или тремя. Качество сгенерированного кода не ухудшится
_Pasha
Цитата(ReAl @ Apr 2 2008, 15:40) *
...способ уменьшения размера глюкодрома по причине врождённой глюкавости операторов ++ --.
Привычки - это нормально, ненормально когда их оправдывают высокими соображениями smile.gif


Есть совершенно нормальный предел восприятия кракозябров, ибо ни Вы, ни я не начинали учить буквы с "Hello, world!" Т.е. чистая психология восприятия. Поэтому, когда мне закинут в уши мысль типа : " зато на Паскале написана масса давно и надежно работающих программ для NASA" - я поверю. Потому что в Паскале нет возможности извратить язык и сделать нечто подобное тому, что описано в первых постах.
singlskv
Цитата(SasaVitebsk @ Apr 2 2008, 22:34) *
С другой стороны, совершенно очевидно, что компилятору по барабану написали ли вы формулу одним оператором или тремя. Качество сгенерированного кода не ухудшится

Более того, при написании 3мя операторами оно может и существенно улучшиться 07.gif
если знаешь как правильно разбить эти 3 оператора на нужное количество строк...
zltigo
Цитата(SasaVitebsk @ Apr 2 2008, 21:34) *
... совершенно очевидно, что компилятору по барабану написали ли вы формулу одним оператором или тремя. Качество сгенерированного кода не ухудшится

Компиляторы умнеют, но тем не менее пока не умнее Вас и на подсказку вполне вероятно, ответят лучшим кодом.


Цитата(singlskv @ Apr 2 2008, 22:19) *
Более того, при написании 3мя операторами оно может и существенно улучшиться 07.gif
если знаешь как правильно разбить эти 3 оператора на нужное количество строк...

Вы знаете? Тогда пример в студию......

Цитата(_Pasha @ Apr 2 2008, 21:53) *
Поэтому, когда мне закинут в уши мысль типа...

smile.gif ну зачем-же гордится своей наивностью?
SasaVitebsk
Хотя я в NASA не работал, но по слухам там не применялся Pascal. Вроде бы Modula или что-то подобное. Знаю точно, что чисто объектно ориентированный язык. И именно из соображений безопасности и защищённости. На данный момент, вроде проскакивали сообщения, что принято решение о применении C++ в качестве базового языка.
singlskv
Цитата(zltigo @ Apr 2 2008, 23:30) *
Вы знаете? Тогда пример в студию......
Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск:
Код
#include <avr/io.h>

volatile unsigned char al=0xFF;
volatile unsigned char ah=0xFF;
volatile unsigned char Pb,Pc,Pd;

int main()
{
  unsigned char pb,pc,pd;

  unsigned char tmpl = al;
  unsigned char tmph = ah;

//------------ Вариант N1 ("правильный")
  pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2);
  pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6);
  pd = tmpl <<2;
//----- сохраняем результат
  Pb = pb;
  Pc = pc;
  Pd = pd;


  tmpl = al;
  tmph = ah;

//------------ Вариант N2 ("неправильный :) ")
  pd = (tmpl << 2);
  pc = tmph & 0b01111100;
  pc >>= 1;
  pb = (tmph & 0b10000000);
  pb |= (pc & 0b00111000);
  pc &= 0b00000110;
  pc >>= 1;
  pb |= pc;
  pc = (tmph&0b00000011);
  pc <<= 2;
  pd = tmpl >> 6;
  pc |= pd;
  pd = tmpl << 2;
//----- сохраняем результат
  Pb = pb;
  Pc = pc;
  Pd = pd;

//---------------------------

  while (1);

}

результат компиляции:
Код
pb = (tmph & 0b10000000) | ((tmph & 0b01110000) >> 1) | ((tmph & 0b00001100) >> 2);
  6c:    24 2f           mov    r18, r20
  6e:    33 27           eor    r19, r19
  70:    c9 01           movw    r24, r18
  72:    80 77           andi    r24, 0x70; 112
  74:    90 70           andi    r25, 0x00; 0
  76:    95 95           asr    r25
  78:    87 95           ror    r24
  7a:    40 78           andi    r20, 0x80; 128
  7c:    48 2b           or    r20, r24
  7e:    c9 01           movw    r24, r18
  80:    8c 70           andi    r24, 0x0C; 12
  82:    90 70           andi    r25, 0x00; 0
  84:    95 95           asr    r25
  86:    87 95           ror    r24
  88:    95 95           asr    r25
  8a:    87 95           ror    r24
  8c:    48 2b           or    r20, r24
  pc = ((tmph & 0b00000011) << 2) | ((tmpl & 0b11000000) >> 6);
  8e:    23 70           andi    r18, 0x03; 3
  90:    30 70           andi    r19, 0x00; 0
  92:    22 0f           add    r18, r18
  94:    33 1f           adc    r19, r19
  96:    22 0f           add    r18, r18
  98:    33 1f           adc    r19, r19
  9a:    85 2f           mov    r24, r21
  9c:    99 27           eor    r25, r25
  9e:    36 e0           ldi    r19, 0x06; 6
  a0:    96 95           lsr    r25
  a2:    87 95           ror    r24
  a4:    3a 95           dec    r19
  a6:    e1 f7           brne    .-8      ; 0xa0 <main+0x44>
  a8:    28 2b           or    r18, r24
  pd = tmpl <<2;
  aa:    55 0f           add    r21, r21
  ac:    55 0f           add    r21, r21

Код
  pd = (tmpl << 2);
  pc = tmph & 0b01111100;
  c2:    24 2f           mov    r18, r20
  c4:    2c 77           andi    r18, 0x7C; 124
  pc >>= 1;
  c6:    26 95           lsr    r18
  pb = (tmph & 0b10000000);
  c8:    94 2f           mov    r25, r20
  ca:    90 78           andi    r25, 0x80; 128
  pb |= (pc & 0b00111000);
  cc:    82 2f           mov    r24, r18
  ce:    88 73           andi    r24, 0x38; 56
  d0:    98 2b           or    r25, r24
  pc &= 0b00000110;
  d2:    26 70           andi    r18, 0x06; 6
  pc >>= 1;
  d4:    26 95           lsr    r18
  pb |= pc;
  d6:    92 2b           or    r25, r18
  pc = (tmph&0b00000011);
  d8:    24 2f           mov    r18, r20
  da:    23 70           andi    r18, 0x03; 3
  pc <<= 2;
  dc:    22 0f           add    r18, r18
  de:    22 0f           add    r18, r18
  pd = tmpl >> 6;
  e0:    85 2f           mov    r24, r21
  e2:    82 95           swap    r24
  e4:    86 95           lsr    r24
  e6:    86 95           lsr    r24
  e8:    83 70           andi    r24, 0x03; 3
  pc |= pd;
  ea:    28 2b           or    r18, r24
  pd = tmpl << 2;
  ec:    55 0f           add    r21, r21
  ee:    55 0f           add    r21, r21


ИТОГО:
"Правильный" 21 слов 58 тактов
"Неправильный" 17 слов 23 такта

Выводы делаем сами 07.gif
AlexKLm
На СИ, правильно когда по-больше зелени (#define), а на C++, а тем более шарпе, - когда этого по-меньше. Шучу. Важно чтобы программа работала, менее важно - как она написана. Если расчитывать что кому-то придется в этом коде разбираться, то желательно писать коментарии. Даже самому приходится иногда разбирая старый код вспоминать что же там имелось ввиду. Мне нравится стиль Microsoft, лучше трудно придумать.
zltigo
Цитата(singlskv @ Apr 2 2008, 23:31) *
Да пожалуйста, WinAvr20060421, на IAR тоже как-то проверял, чуть получше но тоже не блеск:

Ну и где обещанная экономия от
Цитата
...правильно разбить эти 3 оператора на нужное количество строк...

Налицо ДВА РАЗНЫХ АЛГОРИТМА, а не описание одного и того-же "разным количеством строк".
Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум.
Цитата
Выводы делаем сами

Сделал smile.gif



Цитата(AlexKLm @ Apr 3 2008, 00:22) *
Мне нравится стиль Microsoft, лучше трудно придумать.

Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля.
singlskv
Цитата(zltigo @ Apr 3 2008, 01:47) *
Налицо ДВА РАЗНЫХ АЛГОРИТМА,
с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений,
+ если Вы не обратили внимание, во втором варианте операции на одну больше smile.gif
Цитата
Кроме того, посмею предположить, что под нормально оптимизирующим компилятором разница будет в пару команд максимум.
покажите результат компиляции...
zltigo
Цитата(singlskv @ Apr 3 2008, 00:55) *
покажите результат компиляции...

А самому? Думаете поленюсь copy-paste и убрать отрыжки древних ассемблеров не имеющих препроцессоров? Ладно:
Код
//   19 void m1(void)
m1:
//   20 {
//   21 unsigned char pb,pc,pd;
//   22
//   23 unsigned char tmpl = al;
        LDI     R30, LOW(al)
        LDI     R31, (al) >> 8
        LD      R19, Z
//   24 unsigned char tmph = ah;
        LDD     R16, Z+1
//   25
//   26 //------------ Вариант N1 ("правильный")
//   27   pb = ( tmph & 0x80 )|( (tmph & 0x70) >> 1 )|( (tmph & 0xC0) >> 2 );
//   28   pc = ((tmph & 0x03) << 2 )|( (tmpl & 0xC0) >> 6 );
//   29   pd = tmpl <<2;
//   30
//   31 //----- сохраняем результат
//   32   Pb = pb;
        MOV     R18, R16
        ANDI    R18, 0x80
        MOV     R17, R16
        ANDI    R17, 0x70
        ASR     R17
        OR      R18, R17
        MOV     R17, R16
        ANDI    R17, 0xC0
        LSR     R17
        LSR     R17
        OR      R18, R17
        STD     Z+2, R18
//   33   Pc = pc;
        ANDI    R16, 0x03
        LSL     R16
        LSL     R16
        LDI     R17, 4
        MUL     R19, R17
        OR      R16, R1
        STD     Z+3, R16
//   34   Pd = pd;
        LSL     R19
        LSL     R19
        STD     Z+4, R19
//   35
//   36 }
        RET



//   38 void m2(void)
m2:
//   39 {
//   40
//   41 unsigned char pb,pc,pd;
//   42
//   43 unsigned char tmpl = al;
        LDI     R30, LOW(al)
        LDI     R31, (al) >> 8
        LD      R20, Z
//   44 unsigned char tmph = ah;
        LDD     R18, Z+1
//   45
//   46 //------------ Вариант N2 ("неправильный :) ")
//   47       pd = (tmpl << 2);
//   48
//   49     pc = tmph & 0x7C;
//   50       pc >>= 1;
        MOV     R17, R18
        ANDI    R17, 0x7C
        LSR     R17
//   51
//   52     pb = (tmph & 0x80);
//   53       pb |= (pc & 0x38);
//   54       pc &= 0x06;
//   55       pc >>= 1;
//   56       pb |= pc;
//   57       pc = tmph & 0x03;
//   58       pc <<= 2;
//   59       pd = tmpl >> 6;
//   60       pc |= pd;
//   61       pd = tmpl << 2;
//   62 //----- сохраняем результат
//   63   Pb = pb;
        MOV     R19, R18
        ANDI    R19, 0x80
        MOV     R16, R17
        ANDI    R16, 0x38
        OR      R19, R16
        ANDI    R17, 0x06
        LSR     R17
        OR      R19, R17
        STD     Z+2, R19
//   64   Pc = pc;
        ANDI    R18, 0x03
        LSL     R18
        LSL     R18
        LDI     R16, 4
        MUL     R20, R16
        OR      R18, R1
        STD     Z+3, R18
//   65   Pd = pd;
        LSL     R20
        LSL     R20
        STD     Z+4, R20
//   66 }
        RET

P.S.
Получилось, что все ухищрения яйца выеденного не стоят....
ReAl
Цитата(singlskv @ Apr 2 2008, 23:55) *
с ОДИНАКОВЫМ результатом, и принципиально не различающимся методом вычислений,
Но тем не менее разных алгоритма :-)
Кстати, если переписать это так, как привычно мне wink.gif - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют smile.gif ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование"
Код
__asm__ volatile ("nop" ::); // так удобнее искать потом границы фрагментов

  tmpl = al;
  tmph = ah;

  pb = (tmph & 0b10000000) | ((tmph >> 1) & 0b00111000) | ((tmph >> 2) & 0b00000011);
  pc = ((tmph << 2) & 0b00001100) | ((tmpl >> 6) & 0b00000011);
  pd = tmpl <<2;
//-----
  Pb = pb;
  Pc = pc;
  Pd = pd;
__asm__ volatile ("nop" ::);
то особой разницы-то и под gcc не видно...

Код
/* #APP */
    nop
/* #NOAPP */
    lds r19,al
    lds r25,ah
    mov r18,r25
    lsr r18
    andi r18,lo8(56)
    mov r24,r25
    lsr r24
    lsr r24
    andi r24,lo8(3)
    or r18,r24
    mov r24,r25
    andi r24,lo8(-128)
    or r18,r24
    lsl r25
    lsl r25
    andi r25,lo8(12)
    mov r24,r19
    swap r24
    lsr r24
    lsr r24
    andi r24,lo8(3)
    or r25,r24
    lsl r19
    lsl r19
    sts Pb,r18
    sts Pc,r25
    sts Pd,r19
/* #APP */
    nop
/* #NOAPP */
    lds r20,al
    lds r25,ah
    mov r24,r25
    andi r24,lo8(124)
    lsr r24
    mov r19,r24
    andi r19,lo8(56)
    mov r18,r25
    andi r18,lo8(-128)
    or r19,r18
    andi r24,lo8(6)
    lsr r24
    or r19,r24
    andi r25,lo8(3)
    lsl r25
    lsl r25
    mov r24,r20
    swap r24
    lsr r24
    lsr r24
    andi r24,lo8(3)
    or r25,r24
    sts Pb,r19
    sts Pc,r25
    lsl r20
    lsl r20
    sts Pd,r20
.L2:
    rjmp .L2


Цитата(zltigo @ Apr 2 2008, 23:51) *
Трудно придумать стиль в котором больше жертв принесено стилю ради собственно абсолютно формального стиля.
+1
У меня мозги в трубочку сворачиваются и через уши вылазят, когда я вижу идентификаторы в стиле
ВЗБЗД взбздНуть;
Их трудно произнести и, как следствие, ими трудно мыслить. Зато вылет за правый край экрана даже при отступах по 2 символа (о ужас дельфийский) гарантирован даже на операторах средней сложности.
Итого народ пишет исключительно простые, но софт от этого ни компактнее, ни лучше не становится. Как, впрочем, не становится лучше и обычный текст, не содержащий совершенно сложноподчинённых предложений, а состоящий из одних простых ("зато нет глюкодрома с запятыми" smile.gif ).
singlskv
Цитата(zltigo @ Apr 3 2008, 02:08) *
и убрать отрыжки древних ассемблеров не имеющих препроцессоров?
это не отрыжки, это удобство для данной конкретной задачки,
по битикам видно что куда попадает, но это просто специфика...
Кстати Вы вот так и ошиблись при переводе из двоичного представления в 16x
вот так:
(tmph & 0b10000000)......(tmph & 0b01110000).......(tmph & 0b00001100 )
сразу же видно что взяли нужные битики,
а вот так нифига не видно:
( tmph & 0x80 )........(tmph & 0x70)..........(tmph & 0xC0 )

Цитата
А самому?
Код
........
Я же говорю, пробовал, раньше код был намного хуже.
Какая версия ?
С таким выходом - убедили!
ReAl
Цитата(singlskv @ Apr 3 2008, 00:37) *
Я же говорю, пробовал, раньше код был намного хуже.
Какая версия ?
Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный" wink.gif и "неправильный"
Код
/* #APP */
    nop
/* #NOAPP */
    lds r21,al
    lds r20,ah
    mov r25,r20
    andi r25,lo8(-128)
    mov r24,r20
    lsr r24
    andi r24,lo8(56)
    or r25,r24
    mov r24,r20
    lsr r24
    lsr r24
    andi r24,lo8(3)
    or r25,r24
    lsl r20
    lsl r20
    andi r20,lo8(12)
    mov r24,r21
    swap r24
    lsr r24
    lsr r24
    andi r24,0x3
    or r20,r24
    lsl r21
    lsl r21
    sts Pb,r25
    sts Pc,r20
    sts Pd,r21
/* #APP */
    nop
/* #NOAPP */
    lds r21,al
    lds r20,ah
    mov r18,r20
    andi r18,lo8(124)
    lsr r18
    mov r25,r20
    andi r25,lo8(-128)
    mov r24,r18
    andi r24,lo8(56)
    or r25,r24
    andi r18,lo8(6)
    lsr r18
    or r25,r18
    mov r18,r20
    andi r18,lo8(3)
    lsl r18
    lsl r18
    mov r24,r21
    swap r24
    lsr r24
    lsr r24
    andi r24,0x3
    or r18,r24
    lsl r21
    lsl r21
    sts Pb,r25
    sts Pc,r18
    sts Pd,r21
.L2:
    rjmp .L2


У меня на компе и 20060421 до сих пор стоит, на всякий случай.
singlskv
Цитата(ReAl @ Apr 3 2008, 02:32) *
Кстати, если переписать это так, как привычно мне wink.gif - сначала сдвиги, потом маскирования (так как сдвиги С часто компилируются в ассемблерные сдвиги с последующим маскированием, маскирования, разделённые сдвигом, часто остаются, хотя они и ихбыточные, а вот два маскирования подряд компиляторы как правило объединяют smile.gif ), да и мне лично проще анализировать "сначала сдвиг, потом маскирование"
Так собственно мы и сделали одно и тоже но разными средствами
Цитата(ReAl @ Apr 3 2008, 02:46) *
Мой вариант - 20071221, но и на 20060421 полный паритет между вариантами "мой самый правильный" wink.gif и "неправильный"
Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами,
а 20060421 ну никак не хотел ко мне привыкать smile.gif


Цитата(ReAl @ Apr 3 2008, 02:46) *
У меня на компе и 20060421 до сих пор стоит, на всякий случай.
OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос:
http://electronix.ru/forum/index.php?showtopic=26519
Никто так ничего толком и не ответил,
пару раз неприятно натыкался,
кроме как ручной тасовкой команд решения не знаю...
ReAl
Цитата(singlskv @ Apr 3 2008, 00:55) *
Так собственно мы и сделали одно и тоже но разными средствами
Так я и не говорю, что сделано что-то совсем другое (в отличие от варианта в 10 строк), просто неболшое переупорядочивание операций под мою голову smile.gif

Цитата(singlskv @ Apr 3 2008, 00:55) *
Мне просто почему-то удобнее мыслить сначала маскированием а потом сдвигами,
Если выделяется какое-то битовое поле в "целочисленную переменную", то "сначала сдвиг" показывает, где поле начиналось, а "потом маскирование" это просто число единичек справа, равное длине поля, т.е.
Код
fld = (var >> field_start) & ((1 << field_len) - 1);

А если сначала маскирование, то выражение становится запутаннее. Поскольку мне чаще приходилось именно получать нужные поля начиная с 0-ого бита переменной, в которую они заносились - мне привычнее такой вариант.

Кстати, господа хорошие, что-то мне кажется, что этот вариант:
Код
  unsigned char tmph = ah;
  unsigned int tmp = (tmph<<8) | al;
  tmp <<= 2;
  
  pb = tmph & 0b10000000;
  tmph >>= 1;
  pb  |= tmph & 0b00111000;
  tmph >>= 1;
  pb |= tmph & 0b00000011;
  
//-----
  Pb = pb;
  Pc = (tmp>>8) & 0x0F;
  Pd = tmp;
Самый понятный с точки зрения "а что, собственно, делается".
И даже несмотря на традиционно плохонькую реализацию в gcc склеивания слова из двух байтов и выделения старшего байта слова (после оптимизатора остаются рудименты "integer promotion") - он находится "где-то там же" по длине.
Код
    lds r20,ah
    lds r24,al
    mov r18,r20; во аж сколько заняло
    ldi r19,lo8(0);   unsigned int tmp = (tmph<<8) | al;
    mov r19,r18;
    clr r18;
    ldi r25,lo8(0);
    or r18,r24;
    or r19,r25;
    lsl r18
    rol r19
    lsl r18
    rol r19
    mov r24,r20
    lsr r24
    mov r25,r24
    andi r25,lo8(56)
    andi r20,lo8(-128)
    or r25,r20
    lsr r24
    andi r24,lo8(3)
    or r25,r24
    sts Pb,r25
    mov r24,r19; а это недочищенный хвосты
    clr r25;  (tmp>>8) & 0x0F;
    andi r24,lo8(15)
    sts Pc,r24
    sts Pd,r18
Если бы оптимизатор был тут немного умнее, или если применить макрос-вставку
Код
#define HILOTO16(hi, lo) ({ \
    unsigned int __result; \
    __asm__ ( " mov %B0,%1 \n" : "=r" (__result) : "r" (hi), "0" (lo) ); \
    __result; })
...
...
  tmph = ah;
  unsigned int tmp = HILOTO16(tmph, al);
  tmp <<= 2;
  
  pb = tmph & 0b10000000;
  tmph >>= 1;
  pb  |= tmph & 0b00111000;
  tmph >>= 1;
  pb |= tmph & 0b00000011;
  
//-----
  Pb = pb;
  Pc = (tmp>>8) & 0x0F;
  Pd = tmp;


То по сравнению с "неправильным", казалось бы "уоптимизированным вусмерть" и практически непонятным вариантом выходит гораздо короче:
Код
    lds r25,ah
    lds r18,al  ;
/* #APP */
     mov r19,r25; это то, что вышло из макроса HILOTO16(),
/* #NOAPP */; правильный оптимизатор должен был бы сделать так же.
    lsl r18
    rol r19
    lsl r18
    rol r19
    mov r24,r25
    lsr r24
    mov r20,r24
    andi r20,lo8(56)
    andi r25,lo8(-128)
    or r20,r25
    lsr r24
    andi r24,lo8(3)
    or r20,r24
    sts Pb,r20
    mov r24,r19; это уж ладно
    clr r25;
    andi r24,lo8(15)
    sts Pc,r24
    sts Pd,r18



Цитата(singlskv @ Apr 3 2008, 01:25) *
OFF: Кстати, может быть у Вас есть ответ на вот этот вопрос:
http://electronix.ru/forum/index.php?showtopic=26519
Никто так ничего толком и не ответил,
пару раз неприятно натыкался,
кроме как ручной тасовкой команд решения не знаю...
Ответ таков - если это жутко критичное по скорости место - вписать ассемблерную вставку и забыть. Иначе - забить. Ну хуже оптимизаторы, чем они в принципе могут быть, хуже. Если постоянно копаться в выдаче компилятора и страдать от недооптимизации - то лучше перейти на асм.

Кстати, в большинстве случаев -Os для AVR даёт лучше код, чем -O2 :-)
zltigo
Цитата(singlskv @ Apr 3 2008, 01:37) *
это не отрыжки, это удобство для данной конкретной задачки,
по битикам видно что куда попадает, но это просто специфика...

Да ничего не видно, при "видно" не ошибся-бы,даже в 2 часа ночи...
А тут даже на 8bit глазоломка, а уж на 32 smile.gif
Цитата
сразу же видно что взяли нужные битики,

Более-менее видно когда такое написано,хоть на ASM, хоть на C, как минимум так:
Код
( tmph & BIT7 )........(tmph & (BIT6|BIT5|BIT4))..........

а вобще надо давать осмысленные имена
Код
( tmph & B_SIGN )........(tmph & M_LEVEL)..........

Цитата
Я же говорю, пробовал, раньше код был намного хуже.
Какая версия ?

IAR 5.10, но, полагаю, и на 4.x будет тот-же результат.
SasaVitebsk
Вот я и говорю, что результат практически тот же при оптимизации, а при отладке неудобно большие громоздкие формулы (в приведенных примерах вполне нормальные). Поэтому здоровую формулу, с возможностью неоднозначного вычисления (точнее требующую специального разбора порядка вычисления), лучше разбить на пару однозначных. Компилятору всё равно, а человеку удобнее.
ReAl
Цитата(SasaVitebsk @ Apr 3 2008, 09:23) *
Вот я и говорю, что результат практически тот же при оптимизации, а при отладке неудобно большие громоздкие формулы (в приведенных примерах вполне нормальные). Поэтому здоровую формулу, с возможностью неоднозначного вычисления (точнее требующую специального разбора порядка вычисления), лучше разбить на пару однозначных. Компилятору всё равно, а человеку удобнее.
Я бы сказал, что как раз этому критерию приведенный пример не отвечает абсолютно. "неправильный" вариант гораздо труднее для понимания, и чем первый "правильный", и чем мой с 16-битной переменной. Микс из элементарных операций с разными переменными, который нужно много раз прочесть туда-назад, чтобы понять в чём дело.
Он выглядит скорее как "а вот я умнее компилятора и напишу на С, но как бы на асме (всё равно не имея всех асмовых возможностей, кстати) и оно будет компактнее и работать быстрее", а не как "в таком виде оно понятнее человеку".
defunct
Цитата(ReAl @ Apr 3 2008, 01:45) *
Кстати, в большинстве случаев -Os для AVR даёт лучше код, чем -O2 :-)

в большинстве случаев == всегда.


Цитата(SasaVitebsk @ Apr 3 2008, 09:23) *
Поэтому здоровую формулу, с возможностью неоднозначного вычисления (точнее требующую специального разбора порядка вычисления), лучше разбить на пару однозначных. Компилятору всё равно, а человеку удобнее.

+1000
_Pasha
Кто о чем, а вшивый - о бане...
Пробегала книжка C style guide 1994.
Это про NASA smile.gif
sKWO
Цитата(zltigo @ Apr 2 2008, 22:30) *
Компиляторы умнеют, но тем не менее пока не умнее Вас и на подсказку вполне вероятно, ответят лучшим кодом.

К примеру с чем связано столько заморочек в ВИН АВР?
Макрос доступа к битам порта средствами ВИН АВР, например
sbi(PORTB, 5);
Подняв несколька файлов и сделав соответствующие подстановки получаем
следующее ( адрес порта Б к примеру 0x08)
Код
((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) ))   |=(1 << (5)))

средствами ИАР это дело обстоит намного проще и находится в одном файле avr_macros.h
Код
/* Set BIT in ADDRESS */
#define SETBIT(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT)))
sensor_ua
Цитата
средствами ИАР это дело обстоит намного проще

А как насчёт то же применить в WinAVR? Неужели этот макрос там не будет работать? Вы хоть попробовать-то пытались?
sKWO
Цитата(sensor_ua @ Apr 7 2008, 13:58) *
А как насчёт то же применить в WinAVR? Неужели этот макрос там не будет работать? Вы хоть попробовать-то пытались?

Да, я немного не про то. Конечно он будет работать. Это и такому дураку как я понятно smile.gif

Попробуйте в ИАР вот так и объясните почему, а то мне дураку не ясно
Допустим нужно установить в единицу четвёртый бит порта ну пускай Б
Настроим его как выход, назовём его HELS
Код
#define HELSp B
#define HELSb 4
CLRDDR(HELS);// направление
SETPORT(HELS);// бит 4 порта Б единичка
sensor_ua
Не очень понял, что Вы хотите, но на телесистемах на днях обсуждался вариант доступа только по имени.
Код
typedef volatile uint8_t * port_t;

typedef struct Port_Bit{
  port_t Port;
  unsigned char Bit;
}Port_Bit;

void CLRDDR(const Port_Bit * pb){
  *(pb->Port-1) &= ~(1 << pb->Bit);
}
void SETPORT(const Port_Bit * pb){
  *(pb->Port) |= 1 << pb->Bit;
}

Port_Bit dHELS={&PORTB, 4};
const Port_Bit * HELS = &dHELS;
sKWO
спасибо за инфу!!
ReAl
Цитата(sKWO @ Apr 7 2008, 13:40) *
К примеру с чем связано столько заморочек в ВИН АВР?
Макрос доступа к битам порта средствами ВИН АВР, например
sbi(PORTB, 5);
Подняв несколька файлов и сделав соответствующие подстановки получаем
следующее ( адрес порта Б к примеру 0x08)
Код
((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) ))   |=(1 << (5)))
средствами ИАР это дело обстоит намного проще и находится в одном файле avr_macros.h
Код
/* Set BIT in ADDRESS */
#define SETBIT(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT)))
Средствами WinAVR это "всё" тоже было одной практически такой же строкой
Код
#define sbi(port, bit) (port) |= (1 << (bit))
Зачем её было раскручивать? Какая разница что там, если оно всё равно компилируется в одну такую же команду ассемблера, что и у IAR ?

Ведь для SETBIT(PORTB,5) вы же у IAR не раскручивали, что такое PORTB и не сравнивали с WinAVR?
А он выглядит так

WinAVR:
Код
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + 0x20)
...
#define PORTB    _SFR_IO8(0x18)
Кстати, что-то Ваш вариант раскрутки sbi(port,bit) длинноват, выходит короче
Код
( *(volatile uint8_t *)((0x08) + 0x20) )    |=(1 << (5))


IAR:
Код
#define __BYTEBITS(_NAME,_A,_B,_C,_D,_E,_F,_G,_H) \
unsigned char _NAME ## _ ## _A:1, \
              _NAME ## _ ## _B:1, \
              _NAME ## _ ## _C:1, \
              _NAME ## _ ## _D:1, \
              _NAME ## _ ## _E:1, \
              _NAME ## _ ## _F:1, \
              _NAME ## _ ## _G:1, \
              _NAME ## _ ## _H:1;

#define SFR_B_BITS(_NAME, _ADDR, _A,_B,_C,_D,_E,_F,_G,_H) \
    __io union { \
      unsigned char   _NAME;           /* The sfrb as 1 byte */ \
      struct {                        /* The sfrb as 8 bits */ \
        __BYTEBITS(_NAME, _A,_B,_C,_D,_E,_F,_G,_H) \
      };  \
    } @ _ADDR;

#define SFR_B(_NAME, _ADDR) SFR_B_BITS(_NAME, _ADDR, \
                                    Bit0,Bit1,Bit2,Bit3,Bit4,Bit5,Bit6,Bit7)
...

SFR_B(PORTB,  0x18)
Так что у IAR просто наворочено в другом месте, до которого просто Вы не добрались :-)
Как лучше - тяжело сказать. Вариант IAR позволяет написать
Код
SPMCR.SPMIE = 1;
вместо
Код
SPMCR |= (1 << SPMIE);
или
SPMCR |= _BV(SPMIE);

зато не позволяет сделать то, что позволяет avr-gcc
(к чему это приводит - см, например, http://electronix.ru/forum/index.php?s=&am...st&p=377042 )
Код
#if defined(SPMCSR)
#  define SPM_CONTROL_REG SPMCSR
#elif defined(SPMCR)
#  define SPM_CONTROL_REG SPMCR
#else
#  error "SPM control register not defined"
#endif

...

SPM_CONTROL_REG |= (1 << SPMIE);
Таким образом для всех кристаллов, у которых есть либо SPMCR либо SPMCSR - можно обойтись несколькими строками кода и получить исходник, компилирующийся для всего. У IAR для этого придётся персонально проверять типы процесоров через
Код
#if defined(__AT90Mega88__) || defined(__AT90Mega168__) || ...

А всё потому, что PORTB да SPMCR у avr-gcc это макросы препроцессора, а у IAR - переменные-вложенные агрегаты, прибитые гвозядми к адресам, поэтому их наличие или отсутствие препроцессор не видит и нельзя сделать условную компиляцию просто проверив наличие имени регистра.


Цитата(sKWO @ Apr 7 2008, 14:07) *
Допустим нужно установить в единицу четвёртый бит порта ну пускай Б
Настроим его как выход, назовём его HELS
Код
#define HELSp B
#define HELSb 4
CLRDDR(HELS);// направление
SETPORT(HELS);// бит 4 порта Б единичка
Это вообще уже лет 10 не так делается.

Код
#define LED1 B,0,L   /* светодиод анодом на питание, зажигаем низким уровнем - L */
#define LED2 D,1,H   /* светодиод катодом на землю, зажигаем высоким  уровнем */
#define KEY1 C,2,L  /* кнопка на землю, при нажатии низкий уровень */
#define KEY2 A,3,H /*  кнопка на питание, при нажатии высокий уровень */
...
  // теперь не глядя на полярности сигналов пишем ON, чтобы включить, а включается
  // нулём или единичкой - макрос разбирается
  DRIVER(LED1,OUT);
  DRIVER(LED2,OUT);
  DRIVER(KEY1,IN);
  DRIVER(KEY1,PULLUP); // к примеру тут обходимся внутренней подтяжкой
  DRIVER(KEY2,IN);
  DRIVER(KEY2,HIZ);   // а тут внешняя подтяжка на землю
...
  if( ACTIVE(KEY1) ) {
    ON(LED1);
    OFF(LED2);
  }

  if( ACTIVE(KEY2) ) OFF(LED1);

  if( flag) ) CPL(LED2); // проинвертировали ногу


Называется "макросы Аскольда Волкова", модифицировалось уже под разные процессоры и компиляторы всеми кому не лень. Вот мой вариант:
sKWO
Цитата(ReAl @ Apr 7 2008, 22:43) *
Называется "макросы Аскольда Волкова", модифицировалось уже под разные процессоры и компиляторы всеми кому не лень.

C макросами ядерного физика Аскольда Волкова давно знаком, удобная вещь, когда-то на Телесисах
он его представлял, собственно как и его модификацию которую выложил Сергей Борщ.
Конечно же их использую.

Цитата(ReAl @ Apr 7 2008, 22:43) *
А всё потому, что PORTB да SPMCR у avr-gcc это макросы препроцессора, а у IAR - переменные-вложенные агрегаты, прибитые гвозядми к адресам, поэтому их наличие или отсутствие препроцессор не видит и нельзя сделать условную компиляцию просто проверив наличие имени регистра.

За это большое спасибо!


Цитата(ReAl @ Apr 7 2008, 22:43) *
длинноват, выходит короче
Код
( *(volatile uint8_t *)((0x08) + 0x20) )    |=(1 << (5))

Код
в файле sfr_def.h находим
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
дальше
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
дальше
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _SFR_ADDR(sfr) _SFR_MEM_ADDR(sfr)  
#define _SFR_MEM_ADDR(sfr) ((uint16_t) &(sfr))
получаем
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
подставляем
#define sbi(sfr, bit) (   (*(volatile uint8_t *)(   ((uint16_t) &(sfr))   ))   |= _BV(bit))
смотрим в  pgmspace.h  _BV
#define _BV(bit) (1 << (bit))
видим
#define sbi(sfr, bit)  ((*(volatile uint8_ t *)(((uint16_t) &(sfr)) ))   |=  (1 << (bit)))
всё хорошо получается или чёта провтыкал?
имеем следующее
((*(volatile uint8_t *)(((uint16_t) &(PORTB )) ))   |=  (1 << (5)))
ну и остаётся за малым подставить знач порта
допустим
#define PORTB  _SFR_IO8(0x08)
находим _SFR_IO8 в файле sfrdefs.h
#define _SFR_IO8(io_addr) _MMIO_BYTE ((io_addr) + 0x20)
соответственно _SFR_IO8(0x08) есть_MMIO_BYTE((0x08) + 0x20)
а  _MMIO_BYTE((0x08) + 0x20) есть (*(volatile uint8_t *)((0x08) + 0x20))
отсюда и получается
((*(volatile uint8_t *)(((uint16_t) &((*(volatile uint8_t *)((0x08) + 0x20)))) ))   |=(1 << (5)))

Выходит разные версии компилят , наверное smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.