|
|
  |
Перенос кода из под ИАРа на WinAVR, возникают некоторые вопросы... |
|
|
|
Nov 30 2008, 13:13
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Привет, Rst7! Цитата(Rst7 @ Nov 29 2008, 17:53)  Да ну? Рассмотрим операцию сложения. Независимо от размера - char или int - половина возможных операндов (немного меньше, без 2n, где n - количество разрядов) приведет к переполнению. А значит - вероятность почти 50% и не зависит от размерности  Честно говоря, я ничего не понял.  Я ведь говорю не о теоретической математике, а о сугубо прикладной. Математические величины, над которыми производятся вычисления в программе, как правило, отражают реальные сущности окружающего мира. Поэтому значения этих величин первичны по отношению к программе. Исходя из них программист выбирает, в частности, разрядность, необходимую для проведения вычислений. Я имел в виду, что для представления некой величины 8-ми бит может оказаться недостаточно с большей вероятностью, чем 16, и, тем более, 32-х. К примеру, количество людей, прошедших через турникет за час - оно вполне может измеряться несколькими сотнями. А вот превысить 65 тысяч, я думаю, не сможет.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 13:22
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
RST7Не получается у меня научить гнуса правильно обращаться с битовым полем. Даже с Вашей помощью... Вот что получилось: Код typedef struct { byte frame_err: 1, ovrun_err: 1, parity_err: 1, length_err: 1, lock_err: 1, chksum_err: 1, unknown_command: 1; } USART_ERROR;
struct usart_rx_status { byte counter; byte mode; volatile bool data_available; USART_ERROR error; };
ISR(USART_RX_vect) { static byte sign[] PROGMEM = {'S','N'}; static byte length; byte data, state; USART_ERROR error; error = statusRx.error;
do { state = UCSR0A; data = UDR0; if (statusRx.data_available) { error.lock_err = TRUE; continue; } if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) { if (state & (1<<FE0)) error.frame_err = TRUE; if (state & (1<<DOR0)) error.ovrun_err = TRUE; if (state & (1<<UPE0)) error.parity_err = TRUE; statusRx.mode = RX_SEEK; statusRx.counter = 0; continue; } else { error.frame_err = 0; error.ovrun_err = 0; error.parity_err = 0; error.length_err = 0; error.lock_err = 0; error.chksum_err = 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.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; } и результат компиляции первой строчки: Код error = statusRx.error; b38: 80 91 ae 01 lds r24, 0x01AE b3c: 58 2f mov r21, r24 b3e: 52 95 swap r21 b40: 51 70 andi r21, 0x01; 1 b42: b8 2f mov r27, r24 b44: b1 70 andi r27, 0x01; 1 b46: 68 2f mov r22, r24 b48: 66 95 lsr r22 b4a: 61 70 andi r22, 0x01; 1 b4c: 78 2f mov r23, r24 b4e: 76 95 lsr r23 b50: 76 95 lsr r23 b52: 71 70 andi r23, 0x01; 1 b54: f8 2f mov r31, r24 b56: f6 95 lsr r31 b58: f6 95 lsr r31 b5a: f6 95 lsr r31 b5c: f1 70 andi r31, 0x01; 1 b5e: e8 2f mov r30, r24 b60: e2 95 swap r30 b62: e6 95 lsr r30 b64: e1 70 andi r30, 0x01; 1 b66: 08 2f mov r16, r24 b68: 02 95 swap r16 b6a: 06 95 lsr r16 b6c: 06 95 lsr r16 b6e: 01 70 andi r16, 0x01; 1 дальше в коде в основном всё осталось по-прежнему...
|
|
|
|
|
Nov 30 2008, 13:41
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 30 2008, 02:02)  Зачем часто писать явное приведение к int? Разумнее сразу иметь хотя-бы одну переменную размерности int, если обработка данных типа char приводит к образованию переполнения  Это можно. Но тогда в памяти будут храниться незначащие байты. Цитата(sonycman @ Nov 30 2008, 02:02)  Ты говоришь про общий случай. Я - про строку кода конкретной функции lcdPrintText, в которой делимое всегда лежит в пределах 0 <= d < 96. Поэтому эти выражения совершенно эквивалентны. Я говорил о правилах языка, а они пишутся именно для общего случая. Я вполне допускаю, что изменение правил дало бы для данной конкретной программы выигрыш в объеме. Вопрос в том, стоит ли этот выигрыш потери совместимости. В конце концов, если уж так хочется, можно ИМХО создать свой класс mychar, и определить для него такую математику, какую хочется. В том числе приведение к char каждого промежуточного результата. И другой язык для этого придумывать не обязательно.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 13:46
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата и результат компиляции первой строчки: Жесть. Все биты превратил в char'ы и разложил в регистрах. В конце функции, кстати, должен был собрать вместе  Выбросьте Вы, наверное, нафиг эту опенсорсную какашку. Потому как на данном этапе получить из него более лучший чем у IAR'а код не получается. И врядли когда-либо в обозримом будущем получится. Даже с учетом того, что у IAR'а иногда наблюдаются психозы с указателями. А в общем, я бы рекомнедовал купить IAR и клевать мозг его разработчикам. Потому как тогда будут заплачены денежки и есть за что бороться. Сам я в ближайшее время собираюсь по этому пути пойти. А с гнусем - Вы же сами видите, любая просьба (даже о рассмотрении серьезного бага в оптимизаторе) посылается куда подальше - ведь "никто никому не должен". Аргумент о том, что багов и пожеланий больше чем времени, не принимается - нет времени пилить напильником гнуся - не надо за него вообще браться. Как там, в StarWars - "не надо пытаться, делай - или не делай"  Пардон, если зацепил кого. Ничего личного, просто констатация факта.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Nov 30 2008, 13:57
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 30 2008, 02:56)  Имеем текст: Код typedef unsigned char byte; byte percent; byte maxRPM; byte minRPM;
percent = (maxRPM - minRPM) / 2; и результат: Код percent = (maxRPM - minRPM) / 2; 6c0: 80 85 ldd r24, Z+8; 0x08 6c2: 90 e0 ldi r25, 0x00; 0 6c4: 21 85 ldd r18, Z+9; 0x09 6c6: 82 1b sub r24, r18 6c8: 91 09 sbc r25, r1 6ca: 62 e0 ldi r22, 0x02; 2 6cc: 70 e0 ldi r23, 0x00; 0 6ce: ee d8 rcall .-3620; 0xfffff8ac <__eeprom_end+0xff7ef884> Здесь вроде нет знаковых переменных, и нет сложения. Почему не сработала оптимизация? Что именно тут можно было сделать более оптимально? Цитата(sonycman @ Nov 30 2008, 02:56)  Также есть проблемы с утилитой создания листинга avr-objdump - как видно, неправильно вычисляется адрес подпрограммы деления... А зачем вообще в данном случае использовать дизассемблирование? Почему не смотреть сразу вывод компилятора? Там хотя бы все имена символов на своих местах: Код lds r24,maxRPM ldi r25,lo8(0) lds r18,minRPM sub r24,r18 sbc r25,__zero_reg__ ldi r22,lo8(2) ldi r23,hi8(2) rcall __divmodhi4 sts percent,r22 ret А узнать адрес функции удобнее из map-файла... Цитата(sonycman @ Nov 30 2008, 02:56)  Так это как раз не компилятор, это просто библиотечные макросы. Аналогичные макросы можно сделать для любого минимально вменяемого компилятора.
Но разве есть подобные макросы для IAR? Там ведь приходится пользоваться громоздкой конструкцией с pragma и примитивными __disable_interrupt() и __enable_interrupt()... Не знаю, я IAR'ом никогда не пользовался. Даже если нет, что мешает написать? Вот в GCC тоже нет таких макросов - так сделали же...
Сообщение отредактировал alx2 - Nov 30 2008, 14:50
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 14:19
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(Rst7 @ Nov 30 2008, 17:46)  Жесть. Все биты превратил в char'ы и разложил в регистрах. В конце функции, кстати, должен был собрать вместе  Выбросьте Вы, наверное, нафиг эту опенсорсную какашку. Наверное, так и придётся поступить в конце концов. Но почему-то жаль... Цитата(alx2 @ Nov 30 2008, 17:41)  В конце концов, если уж так хочется, можно ИМХО создать свой класс mychar, и определить для него такую математику, какую хочется. А вот это очень интересно! Надо будет попробовать на досуге! Цитата(alx2 @ Nov 30 2008, 17:57)  А зачем вообще в данном случае использовать дизассемблирование? Почему не смотреть сразу вывод компилятора? Там хотя бы все имена символов на своих местах: А как помотреть? Я в эклипсе не вижу больше никаких файлов после компиляции, кроме .lss Цитата Даже если нет, что мешает написать? Мне самому просто знаний не хватит написать "извращение", подобное ATOMIC_BLOCK(). По крайней мере, на данных порах.
|
|
|
|
|
Nov 30 2008, 14:21
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 30 2008, 04:14)  В ИАРе очень удобно сделана работа с указателями на память программ и eeprom. Она совершенно не отличается от указателей на оперативку Хотелось бы видеть такое когда-нибудь и в GCC. Можно в двух словах, как это сделано в IAR? Предполагаю, что там сделаны "универсальные указатели", которые включают не только адрес, но и идентификатор адресного пространства (код/данные). Кстати, опять же, IMHO ничто не мешает определить какой-нибудь класс u_pointer, хранящий такой указатель, и все необходимые для него операции. И не надо ждать, когда авторы компилятора что-то там сделают...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 14:34
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(alx2 @ Nov 30 2008, 18:21)  Можно в двух словах, как это сделано в IAR? Предполагаю, что там сделаны "универсальные указатели", которые включают не только адрес, но и идентификатор адресного пространства (код/данные). Кстати, опять же, IMHO ничто не мешает определить какой-нибудь класс u_pointer, хранящий такой указатель, и все необходимые для него операции. И не надо ждать, когда авторы компилятора что-то там сделают... Я без понятия, как там это сделано. Но выглядит вот так: Код __no_init __eeprom byte ds1820romcodes[4][10] @ 0x0; static unsigned char ds18rom[4][10];
void ds18Init(void) { for(byte a=0;a<40;a++) { ds18rom[0][a] = ds1820romcodes[0][a]; } } Также и с обращением на чтение памяти программ: Код lcdPrintText("CPU");
void lcdPrintText(char const __flash __flash *text) { while(*text) lcdPutChar(*text++); }
|
|
|
|
|
Nov 30 2008, 14:40
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 30 2008, 03:24)  А вот доводить до ума оптимизацию, думаю, нужно. В частности, по обработке switch? Можно немного подсказать gcc, поместив промежуточный результат во временную переменную: Код void do_something(); void do_something_else(); void fff(char flags) { char tmp = flags & 0xe0; switch(tmp) { case 0x40: do_something(); break; case 0x80: do_something_else(); } } Результат компиляции: Код _Z3fffc: andi r24,lo8(-32) cpi r24,lo8(64) breq .L3 cpi r24,lo8(-128) brne .L5 rjmp .L6 .L3: rcall _Z12do_somethingv ret .L6: rcall _Z17do_something_elsev .L5: ret
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 14:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Насчёт битовых полей. Можно опять же помочь компилятору. 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
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 30 2008, 15:26
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(sonycman @ Nov 30 2008, 19:19)  А как помотреть? Я в эклипсе не вижу больше никаких файлов после компиляции, кроме .lss  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 Я этот код бредовым не нахожу...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Nov 30 2008, 15:37
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата Насчёт битовых полей. Можно опять же помочь компилятору. Это не помощь. А объезд кривого оптимизатора. По науке сам должен был структуру скопировать, а не по полям разносить. ЗЫ Приведите, чтоли, получившийся код, глянем... Цитата В последних - это в каких? Я же написал в каких. Вот собственно тут можно почитать - http://electronix.ru/forum/index.php?s=&am...st&p=499837Тут меня постарались убедить, что все хорошо - http://electronix.ru/forum/index.php?s=&am...st&p=501677Однако тоже оказалось не очень хорошо, если почитать дальше.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Nov 30 2008, 15:38
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(alx2 @ Nov 30 2008, 19:26)  gcc -S предписывает не выполнять ассемблирование. Результат компиляции будет записан в файл с расширением s (если явно не указано иное). Спасибо Цитата Кстати, я бы не рекомендовал использовать for() для обрамления критических блоков. Дело в том, что если внутри такого блока встретится return или будет выброшено исключение, третье выражение for() выполнено не будет, и прерывания так и останутся запрещены. Лучше сделать специальный класс, в конструкторе и деструкторе которого запрещать и разрешать прерывания соответственно. Но ведь ATOMIC_BLOCK() именно так и сделан?
|
|
|
|
|
  |
5 чел. читают эту тему (гостей: 5, скрытых пользователей: 0)
Пользователей: 0
|
|
|