31.01.2014, 16:00
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Godzilla82 Вы меня не поняли. Я писал все переменные в памяти.
В первом листинге переменные находятся в регистрах.
Установите галочку чтобы компилятор располагал переменные в памяти и дайте, пожалуйста распечатку без volatile. Нужен только без volatile. Остальное я уже увидел.
Заранее благодарю.
|
|
|
|
31.01.2014, 16:07
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: CodeVisionAVR 2.60
int a,b,c,d:
Автоматически располагать переменные в регистрах - выключено
Код:
|
;for(;;)
_0x4:
;{
;if(a == 100) PINA |= 1;
LDS R26,_a
LDS R27,_a+1
CPI R26,LOW(0x64)
LDI R30,HIGH(0x64)
CPC R27,R30
BRNE _0x6
SBI 0x19,0
;b = 2000;
_0x6:
LDI R30,LOW(2000)
LDI R31,HIGH(2000)
STS _b,R30
STS _b+1,R31
;b += PINA;
IN R30,0x19
LDS R26,_b
LDS R27,_b+1
LDI R31,0
ADD R30,R26
ADC R31,R27
STS _b,R30
STS _b+1,R31
;for(i=0; i‹200; i++) {
LDI R17,LOW(0)
_0x8:
CPI R17,200
BRSH _0x9
;if(b › TCNT1) {
IN R30,0x2C
IN R31,0x2C+1
LDS R26,_b
LDS R27,_b+1
CP R30,R26
CPC R31,R27
BRSH _0xA
;PINA |= 2;
SBI 0x19,1
;break;
RJMP _0x9
;}
;}
_0xA:
SUBI R17,-1
RJMP _0x8
_0x9:
;if(c == 75) PINA |= 4;
LDS R26,_c
LDS R27,_c+1
CPI R26,LOW(0x4B)
LDI R30,HIGH(0x4B)
CPC R27,R30
BRNE _0xB
SBI 0x19,2
;if(d == 1) PINA |= 8;
_0xB:
LDS R26,_d
LDS R27,_d+1
SBIW R26,1
BRNE _0xC
SBI 0x19,3
;}
_0xC:
RJMP _0x4 |
|
|
|
|
31.01.2014, 16:46
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Ну что я скажу ... Из того, что я вижу - вы правы. Действительно смысла в volatile в CV нет никакого, при таком коддинге. (( Это максимальная оптимизация? Или я, применительно к CV, глупость спросил?
Ваши рассказы о том, что он угадывает мои желания, мягко говоря, не совсем соответствуют тому, что я вижу.
Например:
Код:
|
;b = 2000;
_0x6:
LDI R30,LOW(2000)
LDI R31,HIGH(2000)
STS _b,R30 ; Он неугадал. Согласно исходного текста, я об этом не просил.
STS _b+1,R31
;b += PINA;
IN R30,0x19
LDS R26,_b ; соответственно полная бессмыслица.
LDS R27,_b+1
LDI R31,0
ADD R30,R26
ADC R31,R27
STS _b,R30
STS _b+1,R31 |
Итого в двух сишных операторах получаем +8 тактов +16 байт оверхеда.
IAR этот оверхед включит, только при условии volatile.
То есть по сути - вы правы, только я не понимаю смысла вашей радости. Это соответствует моему видению ситуации или глобальная неэффективность или применение volatile обязательно. CV выбрал первое.
Теперь про угадывание.
Не должно быть никакого угадывания. Вы должны донести компилятору, свою идею. Именно для этой цели создан язык программирования. Все элементы языка нацелены на то, чтобы передать компилятору смысл того, что я хочу сделать. Чем ниже уровень языка, тем выше эффективность результирующего кода, но при этом больше конструкций детализирующих задачу. Язык Си - язык среднего уровня. Поэтому детализаций много. Это не плохо и не хорошо. Это данность. Хотите более высокоуровневый язык - пожалуйста пользуйтесь им. Насколько мне не изменяет склероз, в Basic вообще нет разделения на int и float. По крайней мере в первоначальных версиях было так. Это для примера.
Поймите. Речь ведь не всегда идёт о программе из 10 строчек. А если у меня 70 тыс строк и порядка 600 файлов? А если приложение обращается к переменной в бутлоадере, которой вообще нет в проекте? А если я использую шаблоны конфигурирования или сценарии написанные на скриптах и потом компилирую, или некоторые модули написаны на другом языке программирования? Компилятор не может охватить весь ваш замысел и согласно стандарту языка, не должен это делать! Согласно стандарту, каждая процедура является самостоятельной единицей, не связанной с другой. Компилятор не следит за проектом! Объединение в результирующий проект осуществляет линкер. Компилятор не может знать что и в каком потоке выполняется. Может у вас 2 ядра. 1 процедура выполняется в одном - другая в другом. Или 32 как в пропеллере. Таким образом компилятор не знает как ведёт себя глобальная переменная! Требуется дополнительное указание. И страшного тут ничего нет, в рамках данного языка.
Надеюсь я объяснил понятно.
|
|
|
|
31.01.2014, 20:51
|
|
Почётный гражданин KAZUS.RU
Регистрация: 29.10.2006
Сообщений: 1,446
Сказал спасибо: 99
Сказали Спасибо 317 раз(а) в 233 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Сообщение от SasaVitebsk
|
Например:
[CODE];b = 2000;
_0x6:
LDI R30,LOW(2000)
LDI R31,HIGH(2000)
STS _b,R30 ; Он неугадал. Согласно исходного текста, я
об этом не просил.
STS _b+1,R31
|
Почему не просил? Вы в исходном тексте присвоили переменной b значение 2000. Что он и сделал. Переменная в памяти? Вот он в памяти и поменял значение.
Сообщение от SasaVitebsk
|
Код:
|
;b += PINA;
IN R30,0x19
LDS R26,_b ; соответственно полная бессмыслица.
LDS R27,_b+1
LDI R31,0
ADD R30,R26
ADC R31,R27
STS _b,R30
STS _b+1,R31 |
|
Почему бессмыслица? Он действует согласно указаниям. Да, не оптимально. Но действует правильно. Согласно тому, что написнао в коде Си.
|
|
|
|
01.02.2014, 01:14
|
|
Почётный гражданин KAZUS.RU
Регистрация: 10.01.2007
Сообщений: 3,412
Сказал спасибо: 65
Сказали Спасибо 664 раз(а) в 443 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Сообщение от olc0267
|
Дело не в printf. tempora намекал, что sizeof() в CV работает некорректно.
|
Поздравляю, это правильный ответ.
Сообщение от olc0267
|
Но, судя по тому, что у Вас всё заработало нормально в версии 2.0.3, то баг этот уже несколько лет как пофиксен.
|
Он был пофиксен даже раньше, но в CV " место багов пусто не бывает" - на смену этому пришло несколько новых.
Сообщение от olc0267
|
tempora ведь не говорит, какая у него версия CV. Или говорил где-то?
|
Дело не в номере версии, а в том, что (цитирую оттуда же):
Сообщение от tempora
|
Вспоминать все глюки CvAvr нет ни желания, ни возможности (поисковики - в помощь), но их более чем достаточно, чтобы перестать признавать в нем компилятор.
Да еще состав этих глюков с каждой новой версией меняется - это уж и вовсе "для настоящих джигитов".
|
Сообщение от olc0267
|
Интересно, какой объём памяти занимает такая конструкция - sizeof(xlattable)/sizeof(*xlattable)? Что хорошо в ПК, не всегда хорошо в МК. Я бы не поленился конкретно в этом случае константу вбить, и фиг с ней, с универсальностью кода.
|
Никакого объёма sizeof не занимает, так как вычисляется на этапе компиляции, а в коде присутствует именно константа, которую хотели вставить вы. Так что, " фиг с ней, с универсальностью кода" - это плохой ход.
Сообщение от SasaVitebsk
|
Согласно стандарту, каждая процедура является самостоятельной единицей, не связанной с другой. Компилятор не следит за проектом!
|
Мало того, если он и попытается это сделать, ему это не поможет, так как:
1. содержимого библиотек он не видит и не знает, что там будет происходить,
2. существуют такие переменные, которые меняются вовсе не программой - тут даже точное знание действий, выполняемых в библиотеке не поможет,
3. существуют порты ввода/вывода, содержимое которых и вовсе меняется откуда-то снаружи контроллера.
__________________
There's always more than one way to skin a cat.
|
|
|
|
01.02.2014, 10:31
|
|
Почётный гражданин KAZUS.RU
Регистрация: 06.08.2008
Адрес: Ярославль
Сообщений: 1,505
Сказал спасибо: 115
Сказали Спасибо 1,314 раз(а) в 548 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Цитата:
|
Надеюсь я объяснил понятно.
|
Да мне не нужно это объяснять, я не вчера родился. Вы говорите об общих вещах, а я - о частных случаях.
А в частных случаях:
1. volatile инструктирует компилятор не предпринимать никаких оптимизаций к переменной. В случае программирования AVR - перечислите по пальцам, что может сделать компилятор с глобальной переменной, кроме размещения в регистре?
Имхо, конкретно в этом случае, во всех компиляторах всё перевёрнуто с ног на голову. По умолчанию не нужно пихать глобальные переменные в регистры. Если программисту понадобится, он может объявить переменную как register. В CV есть такая возможность - всё запретить, а разрешать по мере надобности.
2.
Код:
|
void del ( int volatile a)
{
while (a) --a;
} |
С точки зрения стандарта языка здесь нет ошибки. Но один компилятор совсем выкинул этот код, а другой более уважительно отнёсся к программисту. Если человек написал - значит, ему так надо. И он попытался сделать всё от него зависящее, причём более грамотно, чем тот другой компилятор. Чем и заслужил моё ответное уважение.
Последний раз редактировалось olc0267; 01.02.2014 в 19:16.
|
|
|
|
01.02.2014, 19:27
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Сообщение от olc0267
|
Да мне не нужно это объяснять, я не вчера родился.
|
Оказывается, пояснять надо. Если глобальная переменная находится в регистре, то нет смысла её объявлять volatile. То есть вы считаете с точностью до наоборот. Проблема только с тем, если переменная как раз таки находится в памяти. Но с памятью не выполняются операции. И перед выполнением компилятор перегружает эту переменную в рабочие регистры. А при оптимизации может с этими регистрами долго работать без обновления. В приведенном мной примере:
Код:
|
for(char i=0; i‹200; i++)
{
if(b › TCNT1)
{
PINA |= 2;
break;
}
} |
компилятор по-разному должен обработать этот цикл. Если это статическая переменная, то он должен загрузить значение b в промежуточную пару рабочих регистров и сравнивать в цикле с текущим значением таймера. Если переменная b меняется, например, в прерывании, то каким образом объяснить это компилятору?!!! Тогда он должен каждый раз загружать переменную b до сравнения.
Вот для этих целей и вводится квалификатор volatile.
Цитата:
|
С точки зрения стандарта языка здесь нет ошибки. Но один компилятор совсем выкинул этот код, а другой более уважительно отнёсся к программисту.
|
Уважительно отнёсся к программисту тот компилятор который выкинул код. С точки зрения стандарта языка, здесь нет ошибки, - просто нет смысла. Задача компилятора построить программу так, чтобы она занимала как можно меньше памяти и выполнялась как можно быстрее. Это не ассемблер. Обратите внимание что одну и ту же программу откомпилировали на разных компиляторах и получили разное время выполнения. А вы хотите сделать задержку средствами языка. У вас сам подход неверный. Кто вам мешает применить конструкцию типа:
for(;--a;a==0) TCNT0;
Последний раз редактировалось SasaVitebsk; 01.02.2014 в 19:30.
|
|
|
|
01.02.2014, 21:50
|
|
Почётный гражданин KAZUS.RU
Регистрация: 06.08.2008
Адрес: Ярославль
Сообщений: 1,505
Сказал спасибо: 115
Сказали Спасибо 1,314 раз(а) в 548 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Сообщение от SasaVitebsk
|
Оказывается, пояснять надо. Если глобальная переменная находится в регистре, то нет смысла её объявлять volatile.
|
В регистр она попадёт после того, как я её не объявил volatile. А уж если попала, тогда действительно бесполезно объявлять. Потому и говорю, что нарушаете причинно-следственную связь.
Сообщение от SasaVitebsk
|
И перед выполнением компилятор перегружает эту переменную в рабочие регистры.
|
А то я не знаю.
Сообщение от SasaVitebsk
|
for(;--a;a==0) TCNT0;
|
Вы хотели сказать
for(;a==0;--a) TCNT0;
Сейчас попробую и это откомпилить.
Последний раз редактировалось olc0267; 01.02.2014 в 21:54.
|
|
|
|
01.02.2014, 22:29
|
|
Почётный гражданин KAZUS.RU
Регистрация: 06.08.2008
Адрес: Ярославль
Сообщений: 1,505
Сказал спасибо: 115
Сказали Спасибо 1,314 раз(а) в 548 сообщении(ях)
|
Re: CodeVisionAVR 2.60
сделано.
Если я напишу так
Код:
|
#include ‹avr/io.h›
void del(int a)
{
for(; a==0; --a) ;
}
int main(void)
{
while(1)
{
del(100);
}
} |
компилятор Atmel Studio опять ничего не делает.
Если добавлю ещё команду
Код:
|
for(; a==0; --a) TCNT0; |
( с точки зрения здравой логики - нахрена я обязан это делать?)
то получается
Код:
|
void del(int a)
{
for(; a==0; --a) TCNT0;
6c: 89 2b or r24, r25
6e: 09 f4 brne .+2 ; 0x72 ‹del+0x6›
70: 82 b7 in r24, 0x32 ; 50
72: 08 95 ret
00000074 ‹main›:
int main(void)
{
while(1)
{
del(100);
74: 84 e6 ldi r24, 0x64 ; 100
76: 90 e0 ldi r25, 0x00 ; 0
78: 0e 94 36 00 call 0x6c ; 0x6c ‹del›
7c: fb cf rjmp .-10 ; 0x74 ‹main›
0000007e ‹_exit›:
7e: f8 94 cli |
Уже лучше. Но как человек в здравом уме должен догадаться, что так нужно сделать? Это прописано в стандарте языка Си? Это считать багом, или фичей компилятора?
Смотрим, что делает СV.
Код:
|
_del:
; 0000 001C for(; a==0; --a) TCNT0;
; a -› Y+0
_0x4:
000048 81e8 LD R30,Y
000049 81f9 LDD R31,Y+1
00004a 9730 SBIW R30,0
00004b f439 BRNE _0x5
00004c b7e2 IN R30,0x32
00004d 81e8 LD R30,Y
00004e 81f9 LDD R31,Y+1
00004f 9731 SBIW R30,1
000050 83e8 ST Y,R30
000051 83f9 STD Y+1,R31
000052 cff5 RJMP _0x4
_0x5:
; 0000 001D }
000053 9622 ADIW R28,2
000054 9508 RET
.....
; 0000 008E while (1)
_0x6:
; 0000 008F {
; 0000 0090 del(100);
000083 e6e4 LDI R30,LOW(100)
000084 e0f0 LDI R31,HIGH(100)
000085 93fa ST -Y,R31
000086 93ea ST -Y,R30
000087 dfc0 RCALL _del
; 0000 0091
; 0000 0092 }
000088 cffa RJMP _0x6
; 0000 0093 }
_0x9:
000089 cfff RJMP _0x9
.CSEG
.CSEG
;END OF CODE MARKER
__END_OF_CODE: |
Но если я уберу TCNT0, то будет следующее
Код:
|
.CSEG
_del:
; 0000 001C for(; a==0; --a) ;
; a -› Y+0
_0x4:
000048 81e8 LD R30,Y
000049 81f9 LDD R31,Y+1
00004a 9730 SBIW R30,0
00004b f421 BRNE _0x5
00004c 9731 SBIW R30,1
00004d 83e8 ST Y,R30
00004e 83f9 STD Y+1,R31
00004f cff8 RJMP _0x4
_0x5:
; 0000 001D }
000050 9622 ADIW R28,2
000051 9508 RET |
Компилятор СV послушно делает всё что ему скажут. И не выпендривается.
Быть может, в этом причина "глючности" CV? Программисты сами глючат, а валят всё на компилятор.
Последний раз редактировалось olc0267; 01.02.2014 в 22:50.
|
|
|
|
01.02.2014, 22:56
|
|
Почётный гражданин KAZUS.RU
Регистрация: 10.01.2007
Сообщений: 3,412
Сказал спасибо: 65
Сказали Спасибо 664 раз(а) в 443 сообщении(ях)
|
Re: CodeVisionAVR 2.60
Сообщение от olc0267
|
с точки зрения здравой логики - нахрена я обязан это делать?
|
Смешной вопрос. ![Смешно](images/smilies/icon_lol.gif) Неужто никогда не встречались с девайсами, чтение из регистра которых сопровождается некоторыми действиями в них?
__________________
There's always more than one way to skin a cat.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 02:13.
|
|