|
WinAVR: Cовмещение Си и ассемблера |
|
|
|
Feb 19 2012, 14:58
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Непонимаю смысл вставки: Код asm volatile("" : "+r" (Cnt_Dl)); В конкретном случае проблема "заоптимизации" решается вставкой volatile перед register uint16_t Cnt_Dl asm("r18");Так что в данном случае квалификатор работает, посмотрю как будет дальше ...
|
|
|
|
|
Feb 19 2012, 17:51
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (MaxiMuz @ Feb 19 2012, 16:58)  Непонимаю смысл вставки: CODE asm volatile("" : "+r" (Cnt_Dl)); Она говорит о том, что в результате этой вставки значение Cnt_Dl изменится и, следовательно, компилятор должен использовать новое значение, а не полагаться на знание старого. QUOTE (MaxiMuz @ Feb 19 2012, 16:58)  В конкретном случае проблема "заоптимизации" решается вставкой volatile перед register uint16_t Cnt_Dl asm("r18"); Удивительный человек. В документации ясно сказано - volatile совместно с register работает непредсказуемо, использовать такую связку нельзя. Нет же, мы аккуратно разложим грабли и любовно отполируем ручку, видимо, чтобы получить по лбу побольнее. Добавлено: извиняюсь, полистал документацию и не нашел явного упоминания запрета связки register volatile. Гугля по фразе "gcc register volatile" выдает кучу ссылок на формы и баг-репорты gcc, но ни одной ссылки на документацию. Пройдя по этим ссылкам можно узнать, что эта связка не работает, что компилятор по -Wall и/или -Wextra должен на такую конструкцию выдавать проедупреждение "volatile register variables don%'t work as you might wish" и что лечить это не собираются.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 19 2012, 18:19
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Сергей Борщ @ Feb 19 2012, 20:13)  Удивительный человек. В документации ясно сказано - volatile совместно с register работает непредсказуемо, использовать такую связку нельзя. Нет же, мы аккуратно разложим грабли и любовно отполируем ручку, видимо, чтобы получить по лбу побольнее. Где именно это сказанно в документации ?? Согласитесь что применительно к программе-компилятору слово "непредсказуемо" имеет условный смысл! Программа работает по определенному алгоритму , и пусть этот работа этого алгоритма не задокументирована. Но нельзя сказать что здесь имеет место случайность  .. Так вот я сейчас провожу исследование  , как именно влияет на задействование (оптимизацию ) регистровых переменных применение или неприменение volatile . За что конечно не могу сказать спасибо создателям этого компилятора. Но тем не менее уже проследил некоторые закономерности работы. Испробованы пока не все случаи... Хочу потом все это оформить в удобочитаемую форму. Если вам будет интересно , я первому сообщу как будет готово. п.с. Да действительно соглашусь , volatile применительно к регис.перем. не хрена ни работает так, как описано в официальной документации. Пока единственное что могу добавить что его применение здесь всеже в некоторых случаях оправданно.
|
|
|
|
|
Feb 20 2012, 08:54
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
QUOTE (MaxiMuz @ Feb 20 2012, 02:19)  Где именно это сказанно в документации ?? Согласитесь что применительно к программе-компилятору слово "непредсказуемо" имеет условный смысл! Программа работает по определенному алгоритму , и пусть этот работа этого алгоритма не задокументирована. Но нельзя сказать что здесь имеет место случайность  .. Почему же? Программа компилятор - тоже программа, также может быть написана абы как. Она может принимать решения в зависимости от контекста - Вашей программы. Вот и получается случайность.
--------------------
Выбор.
|
|
|
|
|
Feb 21 2012, 19:40
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(haker_fox @ Feb 20 2012, 11:54)  Она может принимать решения в зависимости от контекста - Вашей программы. Вот и получается случайность. Контекста какого ? названия переменных, количество их упоминания, или всеже использование р.п. в стандартных конструкциях (for, if, case, и т.д.) , в выражениях присваивания или же в мат.выражениях ? Сейчас столкнулся с следующей проблемой! в заголовочном файле пишу: Код #ifdef __ASSEMBLER__ ...... # define GenCnt r19 ...... #else /* !ASSEMBLER */ ...... register uint8_t GenCnt asm("r19"); ...... #endif /* ASSEMBLER */ компилятор мне говорит что переменная, обьявленная в Си, может быть затерта. Но я так понимаю это относится именно к Сишному куску программы. Заглянул в код , а там в Ассемблерном куске регистор r19 везде заменен на r16 , который уже используется совместно в другом месте! После того как я заменил Makefile на файл из стандарт.папки asmdemo все нормально скомпилировалось. На что следует обратить внимание в этом файле ? Что может влиять на использование регистровых переменных в асме ?
|
|
|
|
|
Feb 22 2012, 06:08
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 15-12-11
Пользователь №: 68 876

|
здравствуй те уважаемые форумчане! Перехожу на Си, ничего не понимаю, поэтому не судите строго задача: по приходу данных по UART генерируется прерывание по "завершению приема" и загорается светодиод. В симуляции прерывание происходит а то что внутри {} игнорируется, в чем можетбыть причина? ISR ( USART_RX_vect ) { switch(UDR) { LED_PORT &= ~ (1<<LED2);break; } }
Полный код программы прилагаю.
|
|
|
|
|
Feb 22 2012, 06:42
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 15-12-11
Пользователь №: 68 876

|
Оказывается в конструкции switch строка выполняется только после меток case или default ! Спасибо за внимание!
|
|
|
|
|
Feb 22 2012, 06:43
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 15-12-11
Пользователь №: 68 876

|
Оказывается в конструкции switch строка выполняется только после меток case или default ! Спасибо за внимание!
Сообщение отредактировал slavik.ksu - Feb 22 2012, 06:43
|
|
|
|
|
Feb 22 2012, 07:49
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Смотря что имеется ввиду под словом «выполняется» Код #include <stdint.h>
uint8_t foo(uint8_t u) { switch (u) { static uint8_t s = 20; case 0: return u+s; case 1: ++s; case 2: return u-s; default: break; } // s = 0; // Низзя! Тут s не видно, она внутри блока swicth return 0; } Код foo: /* prologue: function */ /* frame size = 0 */ cpi r24,lo8(1) breq .L4 cpi r24,lo8(1) brlo .L3 cpi r24,lo8(2) breq .L11 ldi r24,lo8(0) ret .L3: lds r24,s.1215 ret .L4: lds r25,s.1215 subi r25,lo8(-(1)) sts s.1215,r25 sub r24,r25 ret .L11: lds r25,s.1215 sub r24,r25 ret
.data s.1215: .byte 20 Где-то уже писал — не могу найти... switch — это такой оптимизированный условный goto в кучу меток. Все метки должны быть внутри одного выражения (statement) Цитата(C99) 6.8.4 Selection statements Syntax 1 selection-statement: if ( expression ) statement if ( expression ) statement else statement switch ( expression ) statement Как видим, особой разницы между if ( expression ) statement и swicth ( expression ) statement не наблюдается. Кто такой statement — смотрим отдельно Цитата 6.8 Statements and blocks statement: labeled-statement /* сюда входит метка case */ compound-statement ...
Цитата 6.8.2 Compound statement compound-statement: { block-item-listopt } block-item-list: block-item block-item-list block-item block-item:
declaration /* в любом compound statement, включая switch-евый, может быть declaration */ statement
Если выражение простое (не составное), то и switch может выглядеть вообще так: Код uint8_t moo(uint8_t u) { // if ( u == 0 || u == 3 || u == 5 ) return 0; switch(u) case 0: case 3: case 5: return 0;
return 1; } Код moo: cpi r24,lo8(3) breq .L14 cpi r24,lo8(5) breq .L14 tst r24 brne .L17 .L14: ldi r24,lo8(0) ret .L17: ldi r24,lo8(1) ret Тут несколько разных путей поставить нельзя, так как ';' ограничивает выражение и следующий case окажется за пределами switch. Поэтому swicth «чуть реже, чем всегда» применяется с составными (compound statement), заключающими отдельные statement в фигурные скобки. А в начале такого блока может и до метки что-то стоять. Главное, чтобы смысл в этом был. Как в примере выше — статическая переменная.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Feb 22 2012, 07:50
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Сергей Борщ @ Feb 22 2012, 02:53)  Я никогда не использовал регистровые переменные, но часто читал о магическом ключике компилятора -ffixed-reg. Проблема не в Си коде , а данный ключик я так понимаю относится именно к Си. Воодщемполностью заголовочный файл: Код #ifdef __ASSEMBLER__ # define sreg_save r2 # define LedTne r4 # define GenCnt r18 # define Cnt_Dl_low r16 # define Cnt_Dl_hi r17 #else /* !ASSEMBLER */ register uint8_t sreg_save asm("r2"); register uint8_t LedTne asm("r4"); register uint8_t GenCnt asm("r18"); volatile register uint16_t Cnt_Dl asm("r16"); #endif /* ASSEMBLER */ Часть листинга с кодами включающий ассемблерную вставку: Код 000000a2 <__vector_6>: ;_____________________________________________________ ;_______ Прерывание по сопадению каждые 64 такта .global TIM0_COMPA_vect TIM0_COMPA_vect: in sreg_save, _SFR_IO_ADDR(SREG) a2: 2f b6 in r2, 0x3f; 63 tst LedTne a4: 44 20 and r4, r4 brne tca1 a6: 11 f4 brne .+4 ; 0xac <tca1> cbi _SFR_IO_ADDR(PORTB),Led a8: c0 98 cbi 0x18, 0; 24 rjmp tca2 aa: 01 c0 rjmp .+2 ; 0xae <tca2>
000000ac <tca1>: tca1: dec LedTne ac: 4a 94 dec r4
000000ae <tca2>: tca2: inc GenCnt; увеличение глав.счетчика ae: 03 95 inc r16 cpi GenCnt,0xff b0: 0f 3f cpi r16, 0xFF; 255 brne tca3; продолжение ... b2: 41 f4 brne .+16 ; 0xc4 <tca3> ldi GenCnt , 0; b4: 00 e0 ldi r16, 0x00; 0 lds LedTne,BufLed;обновление буфера яркости св.ди. b6: 40 90 60 00 lds r4, 0x0060 tst LedTne; проверка на 0 ! ba: 44 20 and r4, r4 breq tca4 bc: 09 f0 breq .+2 ; 0xc0 <tca4> sbi _SFR_IO_ADDR(PORTB),Led be: c0 9a sbi 0x18, 0; 24
000000c0 <tca4>: ;___ Фоновые счетчики: tca4: subi Cnt_Dl_low,1 c0: 01 50 subi r16, 0x01; 1 sbci Cnt_Dl_hi,0; уменьшение на 1. c2: 10 40 sbci r17, 0x00; 0
000000c4 <tca3>: tca3: out _SFR_IO_ADDR(SREG), sreg_save c4: 2f be out 0x3f, r2; 63 reti c6: 18 95 reti Если внимательно посмотреть на команды с регистром GenCnt , вместо обьявленного r18 везде стоит r16. Рег. перем. sreg_save, LedTne, GenCnt в Си-программе никак не используются и регистры им соответствующие незадействованы. Так понимаю подмена регистра может происходить из за какихто настроек Ассемблера, в чем может быть дело ?
Сообщение отредактировал MaxiMuz - Feb 22 2012, 07:57
|
|
|
|
|
Feb 22 2012, 10:02
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(MaxiMuz @ Feb 22 2012, 10:50)  Так понимаю подмена регистра может происходить из за какихто настроек Ассемблера, в чем может быть дело ? Все, разобрался в чем дело ! Оказывается после редактирования заголовочного файла , чтобы изменения касающиеся Ассемблерной части вступили в силу, нужно сам файл (*.S) обновить ! Я еще не разобрался в механизме сборки hex-кода , но похоже что файл *.o берется линковщиком для сборки, а как раз он не был обновлен, и тупо подставлялась старая часть асм-кода. Вообще былобы интересно почитать (желательно на руском) о механизме получения hex файла. Уважаемый slavik.ksu! , то что вы пишете конечно интересно , но хотелось чтобы в этой теме задавались вопросы касаемые именно совмесного использования Ассмеблера в WinAVR.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|