реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> С и asm-вставки, Локальные переменные
Xeon
сообщение Mar 30 2012, 06:05
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Всем доброго времени суток!!! Использую AVR Stidio 5. Написал программу и теперь надо её оптимизировать... некоторые расчёты уж компилятор сделал больно длинные (в смысле по количеству команд), хотя можно намного проще... Как мне известно локальные переменные обычно хранятся либо в стеке либо в регистрах... Вопрос следующий: как назначить переменной конкретный регистр или как узнать в каком регистре находится переменная, чтоб в дальнейшем иметь к ней доступ?
Go to the top of the page
 
+Quote Post
Dog Pawlowa
сообщение Mar 30 2012, 06:23
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823



Цитата(Xeon @ Mar 30 2012, 09:05) *
Всем доброго времени суток!!! Использую AVR Stidio 5. Написал программу и теперь надо её оптимизировать...

Какие способы оптимизации на С использовались?
А вообще-то на эту тему очень показателен топик:
http://www.avrfreaks.net/index.php?name=PN...ic&t=114878



--------------------
Уходя, оставьте свет...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 30 2012, 06:32
Сообщение #3


Гуру
******

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



QUOTE (Xeon @ Mar 30 2012, 09:05) *
Вопрос следующий: как назначить переменной конкретный регистр или как узнать в каком регистре находится переменная, чтоб в дальнейшем иметь к ней доступ?
Неправильный вопрос вы задаете. Спрашивать надо "как на языке С написать этот алгоритм более оптимально?". Своими благими намерениями вы будете только мешать оптимизатору и в пределе можете сделать свою программу работающей только под одной версией компилятора при строго определенном наборе ключей.
Хотите - балуйтесь:
CODE
register uint16_t Tmp __asm__(("r16"))
Чтобы узнать, в каком регистре находится переменная, надо читать листинг. Но это мало что вам даст - добавление одной строчки в другом месте программы может привести к перераспределению регистров и ваша программа работать перестанет. Это во-первых. А во-вторых - локальная переменная за время своей жизни легко может кочевать из одного регистра в другой, на стек и обратно.

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 30 2012, 06:35
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Использую оптимизацию -Оs...
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 30 2012, 07:24
Сообщение #5


Местный
***

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



Чем отличается обьявление:
Код
register uint16_t Tmp __asm__(("r16"))

от :
Код
register uint16_t Tmp asm("r16");
?
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 30 2012, 08:13
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Нашел немного инфы по asm-вставкам здесь (может кому будет полезна):
http://www.simple-devices.ru/attachments/a...AVR_04_2011.pdf
http://www.simple-devices.ru/attachments/a...AVR_05_2011.pdf

В пдфке по второй ссылке, говориться что в asm-вставку операнды можно передавать по имени, т.е. вместо:
CODE
asm(«in %0, %1» : «=r» (value) : «I» (_SFR_IO_ADDR(PORTD)) );

можно писать:
CODE
asm volatile («in [x1], [x2]» : [x1] «=r» (value) : [x2] «I» (_SFR_IO_ADDR(PORTD)) );

У меня почему то это не вышло, писал следующее:
CODE

asm volatile(
"push R0 \n"
"push R1 \n"

"muls %0, %1 \n" // загрузить синус

"pop R1 \n"
"pop R0"
:
:[SINVAL] "d" (sinVal), [COSVAL] "d" (cosVal)
);

В чём я ошибся?

Цитата(Сергей Борщ @ Mar 30 2012, 09:32) *
Хотите более надежное решение - изучите соглашение о вызовах и напишите отдельный узкий кусок программы чисто на асме или в крайнем случае на инлайн-асме, а лучше выложите свой код и возможно фуромчане насоветукют вам, как его улучшить не прибегая к извращениям. Поверьте, это возможно.

Конечно, последую Вашему совету... А у Вас не найдется, что почитать? По поводу переноса на другой компилятор... сейчас такого вопроса не стоит и скарей всего не когда и не будет.

Вот кусок коды на С который хочу заставить работать быстрей:
CODE

// вычисляем вещественную и мнимую части
int8_t sinVal = 2;// pgm_read_byte(&FsinTable[FLookignForFreq][CurVal]);
int8_t cosVal = -3;//pgm_read_byte(&FcosTable[FLookignForFreq][CurVal]);

FsummRe[FLookignForFreq] += (int32_t) (Values[CurVal]*cosVal);
FsummIm[FLookignForFreq] += (int32_t) (Values[CurVal]*sinVal);

CurVal++;
if(CurVal >= FAMOUNT_POINTS)
{
ADCA.CTRLA = 0;
Flags = ADC_CONVERSION_COMPLETE;
}
DMA.CH0.CTRLB |= (1 << 4) | (1 << 5); // clear interrupt flags

Собствненно узкое место здесь:
CODE

FsummRe[FLookignForFreq] += (int32_t) (Values[CurVal]*cosVal);
FsummIm[FLookignForFreq] += (int32_t) (Values[CurVal]*sinVal);

Здесь делаю перемножение двух знаковых одно-байтовых чисел и после всё кладу в "сумматор", так я должен делать 256 раз (выше сказанное делается 2 раза, 1 раз для FsummRe и 1 раз для FsummIm). 8x8 == 16 разрядов и поскольку всё кладу в сумматор 256 раз, то конечный результат для FsummRe и FsummIm будет 24 разрядный.

Вот, что получаю от компилятора:
CODE

FsummRe[FLookignForFreq] += (int32_t) (Values[CurVal]*cosVal);
000003EF LDS R30,0x2427 Load direct from data space
000003F1 LDI R31,0x00 Load immediate
000003F2 LDS R26,0x2431 Load direct from data space
000003F4 LDI R27,0x00 Load immediate
000003F5 SUBI R26,0xCA Subtract immediate
000003F6 SBCI R27,0xDA Subtract immediate with carry
000003F7 LD R18,X Load indirect
000003F8 CLR R19 Clear Register
000003F9 SBRC R18,7 Skip if bit in register cleared
000003FA COM R19 One's complement
000003FB LSL R30 Logical Shift Left
000003FC ROL R31 Rotate Left Through Carry
000003FD LSL R30 Logical Shift Left
000003FE ROL R31 Rotate Left Through Carry
000003FF MOVW R16,R30 Copy register pair
00000400 SUBI R16,0xD8 Subtract immediate
00000401 SBCI R17,0xDC Subtract immediate with carry
00000402 MOVW R14,R18 Copy register pair
00000403 LSL R14 Logical Shift Left
00000404 ROL R15 Rotate Left Through Carry
00000405 ADD R18,R14 Add without carry
00000406 ADC R19,R15 Add with carry
00000407 COM R19 One's complement
00000408 NEG R18 Two's complement
00000409 SBCI R19,0xFF Subtract immediate with carry
0000040A CLR R20 Clear Register
0000040B SBRC R19,7 Skip if bit in register cleared
0000040C COM R20 One's complement
0000040D MOV R21,R20 Copy register
0000040E MOVW R26,R16 Copy register pair
0000040F LD R22,X+ Load indirect and postincrement
00000410 LD R23,X+ Load indirect and postincrement
00000411 LD R24,X+ Load indirect and postincrement
00000412 LD R25,X Load indirect
00000413 SBIW R26,0x03 Subtract immediate from word
00000414 ADD R18,R22 Add without carry
00000415 ADC R19,R23 Add with carry
00000416 ADC R20,R24 Add with carry
00000417 ADC R21,R25 Add with carry
00000418 ST X+,R18 Store indirect and postincrement
00000419 ST X+,R19 Store indirect and postincrement
0000041A ST X+,R20 Store indirect and postincrement
0000041B ST X,R21 Store indirect
0000041C SBIW R26,0x03 Subtract immediate from word

Честно, особо не вникал как конкретно делает компилятор... По мне можно сделать так:
1) взять нужные значения и перемножить знаково используя MULS
2) после произвести знаковое сложение 24 разрядного "сумматора" и полученного 16 разрядного результата перемножения
По этому, как мне кажется, реализовать это дело можно намного проще и быстрее...
Жду Ваших комментариев...
Go to the top of the page
 
+Quote Post
XVR
сообщение Mar 30 2012, 08:35
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Судя по листигну компилятор не в курсе, что существует команда MULS. Вы уверены, что указали компилятору правильный тип процессора? Если да, то вы уверенны, что этот процессор поддерживает MULS?
Go to the top of the page
 
+Quote Post
Xeon
сообщение Mar 30 2012, 09:02
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Тип процессора правильный, точно... Использую XMega32 A4... По даташиту данные микроконтроллеры поддерживают команду MULS. Может на самом деле есть где нибудь у компилятора настройка по этому поводу. Сейчас посмотрю и отпишусь.

Ни чего не нашел!!!
Go to the top of the page
 
+Quote Post
XVR
сообщение Mar 30 2012, 09:16
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Вообще код странный. Там ни одного перехода нет, и умножения нет. Что то он у вас сильно развернул
А, так у вас int8_t cosVal = -3; Компилятор подставил вместо cosVal константу и развернул умножение на константу -3 в набор сложений и сдвигов. Это будет быстрее, чем MULS. Верните обратно переменную
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 30 2012, 09:22
Сообщение #10


Гуру
******

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



QUOTE (MaxiMuz @ Mar 30 2012, 10:24) *
Чем отличается обьявление:
Ничем. Они эквивалентны.

QUOTE (Xeon @ Mar 30 2012, 11:13) *
В пдфке по второй ссылке, говориться что в asm-вставку операнды можно передавать по имени
Да, можно. Смотрите:
CODE
    uint8_t Tmp;
    bpm_driver::state * pTmp;

    asm volatile (
//        pTmp = get_update_src();
        "PUSH %[tmp]                \r\n"
        "IN %[tmp], %[sreg]         \r\n"
        "PUSH %[tmp]                \r\n"
        "PUSH %A[ptr]               \r\n"
        "PUSH %B[ptr]               \r\n"
        "LDS  %A[ptr], %[state]     \r\n"
        "LDS  %B[ptr], %[state]+1     \r\n"
        :[ptr]"=z"(pTmp), [tmp]"=r"(Tmp)
        :[sreg] "I" (_SFR_IO_ADDR(SREG))
        ,[state]"m"(bpm_driver::pState)
     );


QUOTE (Xeon @ Mar 30 2012, 11:13) *
У меня почему то это не вышло, писал следующее:
По симптомам "у меня не вышло" можно поставить лишь один диагноз: "значит что-то делали неправильно". Объясните, что вы хотели сделать и что получили?

QUOTE (Xeon @ Mar 30 2012, 11:13) *
Вот кусок коды на С который хочу заставить работать быстрей:
CODE
    FsummRe[FLookignForFreq] += (int32_t) (Values[CurVal]*cosVal);
В этой строке приведение типа либо абсолютно лишнее либо используется не там, где нужно. Как объявлено Values?

Выложите всю функцию со всеми объявлениями в виде одного файла, который можно компилить отдельно и экспериментировать.
QUOTE (Xeon @ Mar 30 2012, 12:02) *
Тип процессора правильный, точно... Использую XMega32 A4... По даташиту данные микроконтроллеры поддерживают команду MULS. Может на самом деле есть где нибудь у компилятора настройка по этому поводу.
С хмегами не работал и не собираюсь, но, возможно, компилятор не очень свежий и еще не умеет гененрить MULS.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 30 2012, 12:17
Сообщение #11


Местный
***

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



если всеже будет обьявлять регистровые переменные как "register uint16_t Tmp asm("r16");" или "register uint16_t Tmp __asm__(("r16"))" пишите перед этим квалификатор volatile , меньше ошибок с исчезновением операций будет.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 30 2012, 14:17
Сообщение #12


Гуру
******

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



QUOTE (MaxiMuz @ Mar 30 2012, 15:17) *
пишите перед этим квалификатор volatile , меньше ошибок с исчезновением операций будет.
Вы в который раз топчетесь по одним и тем же граблям (уже однажды разбирали в одной из ваших веток, и вы сами смотрели листинг и убеждались). НЕ РАБОТАЕТ в gcc volatile register. В сообщении 30 той ветки было решение.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 31 2012, 07:12
Сообщение #13


Местный
***

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



Цитата(Сергей Борщ @ Mar 30 2012, 17:17) *
НЕ РАБОТАЕТ в gcc volatile register. В сообщении 30 той ветки было решение.

как раз volatile решил проблему
Go to the top of the page
 
+Quote Post
Xeon
сообщение Apr 1 2012, 05:59
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524



Привожу исходники: Прикрепленный файл  sources.rar ( 4.77 килобайт ) Кол-во скачиваний: 74

Немного опишу: первоночальная цель - нужно найти некоторые частоты используя преобразование Фурье, всякие вызовы подобные _DebugMes, _DebugByte и др. - это макросы для вывода в консоль... В ADC.c я делаю 255 измерений и после каждого измерения срабатывает прерывание от DMA и внем я вычисляю вещественную и мнимую части. Почему DMA - просто когда я пробовал без него получалось, что в присудствее задержки распространения АЦП при частоте 250КГц АЦП делал 50000 выборок в секунду, при 500КГц 100000 выборок в секунду, а мне надо мерить сигнал в 100КГц, значит по Найквисту/Котельникову частота выборок в два раза больше, т.е. 200 килосемплов/секунда. Сделав через DMA получилось, что от задержке распространения избавился (может я не прав, но сигнал который дискретизую очень похож на то, что вижу на осциле). К тому же DMA позволило производить измерения, когда на АЦП подаю 1МГц, без DMA не работало. В файлике FTransform.c собственно само преобразование, вобщем там на мой взгляд все довольно тривиально... Если вдруг будет, что не понятно распишу всё подробней...

Сообщение отредактировал Xeon - Apr 1 2012, 06:01
Go to the top of the page
 
+Quote Post
XVR
сообщение Apr 1 2012, 08:46
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



А вы все таки откомпилируйте реальный код и посмотрите, что вам сделал компилятор. В вашем asm листинге, который вы приводили, к собственно умножению относилось только 6 комманд. Остальное к индексации 2х массивов

И уровень оптимизаций поставьте побольше: -O3 например


Кстати, таблицы у вас весьма специфичные sm.gif Они действительно состоят только из 0 и -127? Если да, то вам стоит задуматься об изменении алгоритма - там вообще умножения не нужны
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 17:49
Рейтинг@Mail.ru


Страница сгенерированна за 0.01514 секунд с 7
ELECTRONIX ©2004-2016