|
IAR AVR (Cи). вопрос о указателе на глобальную структуру, как заставить компилятор использовать рег. Z как постоянный указатель |
|
|
|
Apr 1 2011, 12:12
|

Участник

Группа: Участник
Сообщений: 54
Регистрация: 13-01-09
Пользователь №: 43 304

|
Доброго времени суток уважаемые форумчане. На этом форуме давно, но отписываюсь не часто, практически по всем вопросам есть информация, за что всем посетителям и администрации поклон в ноги. При написании кода всегда обращаю внимание на генерируемый ассемблерный листинг, при этом не заострял внимания на указатели. Недавно обратил внимание на оч. интересный документ AVR035:Эффетивное программирование на Си для AVR (очень жалею, что давно его не прочел) В нем написан интересный способ уменьшения объема кода в случае использования множетсва глобальных переменных. Там предлагается объявить эти переменные как глобальную структуру и обращаться к каждой переменной как к элементу структуры, при этом указатель на структуру всегда используется один и тот же, а переменные считываются командой LDD r16,Z+30 (соответственно командой STD записываются обратно). плюс этой команды - использование считывания/записи со смещением, не изменяя при этом регистр Z. я попробовал повторить пример из этой Application Note, все получилось как надо: Цитата typedef struct { int hour; char min; int sec; }t; t global;
__C_task void main1(void) { t *time=&global; if(++time->sec==60) { time->sec=90; time->min=70; } } а это ассемблерный листинг, который генерируется в итоге: Цитата // 10 { // 11 t *time=&global; LDI R16, LOW(global) LDI R17, (global) >> 8 MOVW R31:R30, R17:R16 // 12 if(++time->sec==60) LDD R16, Z+2 INC R16 STD Z+2, R16 CPI R16, 60 BRNE ??main1_0 // 13 { // 14 time->sec=90; LDI R16, 90 STD Z+2, R16 // 15 time->min=70; LDI R16, 70 STD Z+1, R16 // 16 } // 17 } Обратите внимание, что указатель инициализируется сразу в регистры r30,r31 (Z-регистр) и далее вообще не изменяется, а только используется с командами LDD, STD. НО только я добавляю в цикл функцию delay, все кардинально меняется!!! Вот исходник Цитата typedef struct { int hour; char min; int sec; }t; t global; extern void delay(unsigned int);
__C_task void main1(void) { delay(107); t *time=&global; if(++time->sec==60) { time->sec=90; time->min=70; } } А вот ассемблерный листинг Цитата // 12 delay(107); FUNCALL main1, delay LOCFRAME CSTACK, 0, STACK LOCFRAME RSTACK, 2, STACK ARGFRAME RSTACK, 0, STACK LDI R16, 107 LDI R17, 0 RCALL delay // 13 t *time=&global; LDI R16, LOW(global) LDI R17, (global) >> 8 MOVW R27:R26, R17:R16 // 14 if(++time->sec==60) ADIW R27:R26, 2 LD R16, X SBIW R27:R26, 2 INC R16 ADIW R27:R26, 2 ST X, R16 SBIW R27:R26, 2 CPI R16, 60 BRNE ??main1_0 // 15 { // 16 time->sec=90; LDI R16, 90 ADIW R27:R26, 2 ST X, R16 SBIW R27:R26, 2 // 17 time->min=70; LDI R16, 70 ADIW R27:R26, 1 ST X, R16 SBIW R27:R26, 1 // 18 } // 19 } Обратите внимание, что теперь компилятору нафиг не сдался удобный регистр Z и команды LDD и STD вместе взятые. Вместо них он использует регистр X и каждый раз инкрементирует его на необходимый сдвиг, а считывает и записывает командами LD, ST, что естественно занимает больше времени чем команды LDD и STD. При оптимизации по скорости выполнения вообще заменяет указатель константой и обращается к каждому элементу структуры через команды STS LDS (занимающие в два раза больше программной памяти). Вот код функции delay: Цитата void delay(volatile unsigned int ticks) { while(ticks) ticks--; } volatile добавлен исключительно для того, чтобы компилятор не выбросил задержку из кода при оптимизации. Теперь вопрос: Объясните почему так поступает компилятор с командами LDD и STD, и как ему указать что так делать не нужно? Спасибо за внимание и понимание) p.s. Если разместил тему не в том разделе, прошу модераторов перенести ее туда, где будет актуальнее. уважаемые модераторы, изменил <codebox> на <quote> удобнее читать и есть возможность изменять цвет. в <code> нет возможности менять цвет текста.
Сообщение отредактировал ibiza11 - Apr 1 2011, 16:08
|
|
|
|
2 страниц
< 1 2
|
 |
Ответов
(15 - 22)
|
Apr 5 2011, 13:20
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Код 20 delay(107); \ 00000002 E60B LDI R16, 107 \ 00000004 E010 LDI R17, 0 \ 00000006 8308 ST Y, R16 \ 00000008 8319 STD Y+1, R17 \ ??main_0: \ 0000000A 8108 LD R16, Y \ 0000000C 8119 LDD R17, Y+1 \ 0000000E 2B01 OR R16, R17 \ 00000010 F7E1 BRNE ??main_0 \ 00000012 8108 LD R16, Y \ 00000014 8119 LDD R17, Y+1 \ 00000016 5001 SUBI R16, 1 \ 00000018 4010 SBCI R17, 0 \ 0000001A 8308 ST Y, R16 \ 0000001C 8319 STD Y+1, R17 21 t *time=&global; 22 if(++time->sec==60) \ 0000001E .... LDI R30, LOW(global) \ 00000020 .... LDI R31, (global) >> 8 \ 00000022 8103 LDD R16, Z+3 \ 00000024 8114 LDD R17, Z+4 \ 00000026 5F0F SUBI R16, 255 \ 00000028 4F1F SBCI R17, 255 \ 0000002A 8303 STD Z+3, R16 \ 0000002C 8314 STD Z+4, R17 \ 0000002E 330C CPI R16, 60 \ 00000030 E020 LDI R18, 0 \ 00000032 4010 SBCI R17, 0 \ 00000034 F429 BRNE ??main_1 23 { 24 time->sec=90; \ 00000036 E50A LDI R16, 90 \ 00000038 8303 STD Z+3, R16 \ 0000003A 8324 STD Z+4, R18 25 time->min=70; \ 0000003C E406 LDI R16, 70 \ 0000003E 8302 STD Z+2, R16 26 } 27 } От замеса зависит. ))
|
|
|
|
|
Apr 5 2011, 13:54
|

Участник

Группа: Участник
Сообщений: 54
Регистрация: 13-01-09
Пользователь №: 43 304

|
Цитата(=GM= @ Apr 5 2011, 17:45)  Есть модификация LDS/STS, занимает одно слово. Зависит от того, где в памяти размещены переменные. что за модификация? не слышал об этом ничего... можно подробнее?
|
|
|
|
|
Apr 5 2011, 14:42
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Документ doc0856i (тыц), с.96. Я не говорил, что иар туповат, я сказал "комиляторЫ иногда туповаты" (или почти всегда, в настоящее время) Вот CVAVR немного притупил Цитата(SasaVitebsk @ Apr 5 2011, 12:20)  Код delay(107); LDI R16,107 LDI R17,0 ST Y,R16 STD Y+1,R17 main0: LD R16,Y LDD R17,Y+1 OR R16,R17 BRNE main0 LD R16,Y LDD R17,Y+1 SUBI R16,1 SBCI R17,0 ST Y,R16 STD Y+1,R17 WINAVR делает задержку более элегантно Код delay(107); ldi r24,0x6B ; 107 ldi r25,0x00 ; 0 rjmp L2 ; 0xee <main+0x3c> L1: sbiw r24,0x01 ; ticks-- L2: sbiw r24,0x00 ; while(ticks) brne L1 ;
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Apr 6 2011, 05:46
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(ibiza11 @ Apr 5 2011, 17:38)  SasaVitebsk, странно, у Вас компилятор не вызвал функцию delay(), она у Вас инлайновая? При этом вполне исправно использует Z-регистр. Какой у Вас компилятор? Прошу прощения. Просто не глянул. Кинул функцию в main.c файл. Вот она и заинклудилась. )) Не прочитал, что это для вас принципиально. Исправил. Показываю Код \ In segment CODE, align 2, keep-with-next 13 __C_task void main(void) \ main: 14 { 15 delay(107); \ 00000000 E60B LDI R16, 107 \ 00000002 E010 LDI R17, 0 \ 00000004 .... RCALL delay 16 t *time=&global; 17 if(++time->sec==60) \ 00000006 .... LDI R30, LOW(global) \ 00000008 .... LDI R31, (global) >> 8 \ 0000000A 8103 LDD R16, Z+3 \ 0000000C 8114 LDD R17, Z+4 \ 0000000E 5F0F SUBI R16, 255 \ 00000010 4F1F SBCI R17, 255 \ 00000012 8303 STD Z+3, R16 \ 00000014 8314 STD Z+4, R17 \ 00000016 330C CPI R16, 60 \ 00000018 E020 LDI R18, 0 \ 0000001A 4010 SBCI R17, 0 \ 0000001C F429 BRNE ??main_0 18 { 19 time->sec=90; \ 0000001E E50A LDI R16, 90 \ 00000020 8303 STD Z+3, R16 \ 00000022 8324 STD Z+4, R18 20 time->min=70; \ 00000024 E406 LDI R16, 70 \ 00000026 8302 STD Z+2, R16 21 } 22 } \ ??main_0: \ 00000028 9508 RET Компилятор 5.11 Задержка Код 1 void delay(volatile unsigned int ticks) \ delay: 2 { \ 00000000 9722 SBIW R29:R28, 2 \ 00000002 C004 RJMP ??delay_0 3 while(ticks) ticks--; \ ??delay_1: \ 00000004 8108 LD R16, Y \ 00000006 8119 LDD R17, Y+1 \ 00000008 5001 SUBI R16, 1 \ 0000000A 4010 SBCI R17, 0 \ ??delay_0: \ 0000000C 8308 ST Y, R16 \ 0000000E 8319 STD Y+1, R17 \ 00000010 8108 LD R16, Y \ 00000012 8119 LDD R17, Y+1 \ 00000014 2B01 OR R16, R17 \ 00000016 F7B1 BRNE ??delay_1 4 } \ 00000018 9622 ADIW R29:R28, 2 \ 0000001A 9508 RET
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|