|
С и asm-вставки, Локальные переменные |
|
|
|
Mar 30 2012, 06:32
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Mar 30 2012, 07:24
|

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

|
Чем отличается обьявление: Код register uint16_t Tmp __asm__(("r16")) от : Код register uint16_t Tmp asm("r16"); ?
|
|
|
|
|
Mar 30 2012, 08:13
|
Частый гость
 
Группа: Участник
Сообщений: 140
Регистрация: 21-04-11
Пользователь №: 64 524

|
Нашел немного инфы по asm-вставкам здесь (может кому будет полезна): http://www.simple-devices.ru/attachments/a...AVR_04_2011.pdfhttp://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 разрядного результата перемножения По этому, как мне кажется, реализовать это дело можно намного проще и быстрее... Жду Ваших комментариев...
|
|
|
|
|
Mar 30 2012, 09:22
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Mar 30 2012, 14:17
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Mar 31 2012, 07:12
|

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

|
Цитата(Сергей Борщ @ Mar 30 2012, 17:17)  НЕ РАБОТАЕТ в gcc volatile register. В сообщении 30 той ветки было решение. как раз volatile решил проблему
|
|
|
|
|
Apr 1 2012, 05:59
|
Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|