Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
244
Добавлен:
23.03.2016
Размер:
253.42 Кб
Скачать

СПРАВОЧНЫЙ МАТЕРИАЛ

Книга по работе

 

 

 

 

 

Роман Абраш

 

 

 

 

 

 

 

 

 

 

 

 

 

с WinAVR и AVR Studio

 

 

 

 

 

г. Новочеркасск

 

 

 

 

E-mail: arv@radioliga.com

 

 

 

 

 

 

 

 

Входные операнды должны быть определены как доступ-

 

 

Продолжение. Начало в №1-12/2010; №1-4/2011

 

 

 

 

 

 

ные только для чтения (без символа-модификатора). Одна-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ко, в случае, когда единственный операнд используется и

Операнды оператора asm()

 

 

 

как входное и как выходное значение, существует способ

Параметры оператора asm, используемые в качестве опе-

 

обойти это ограничение: необходимо вместо символа опе-

рандов инструкций ассемблера, обозначаются, как было сказа-

 

ранда использовать номер соответствующего операнда в ин-

но ранее, определенными символами, помещаемыми в двой-

 

струкции:

 

 

 

 

 

 

 

ные кавычки (см. таблицу 4).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

В таблице 4 перечислены все допустимые символы для обо-

 

asm volatile(«swap %0» : «=r» (value) : «0» (value));

 

значения параметров. Обнаружив такой символ, компилятор само-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

стоятельно подставит вместо него соответствующее значение из

 

Пример показывает, как переменная value используется

числа допустимых. При этом могут быть странные на первый взгляд

 

в качестве входного значения и в нее же помещается ре-

ошибки, если символ выбран программистом неверно. Например,

 

зультат ассемблерной команды, меняющей тетрады байта.

программист применил для операнда-приемника инструкции ORI

 

“0” – это номер операнда команды SWAP. Такая запись ука-

символ “r”. Компилятор может выбрать для этого любой регистр из

 

зывает компилятору использовать для операнда-приемника

числа имеющихся в его распоряжении в текущий момент. При этом

 

результата то же самое значение, что было выбрано для опе-

может быть выбран и регистр, например, r3, что приведет к ошибке,

 

ранда-источника. Однако следует знать, что компилятор

т.к. для инструкции ORI допустимо применять только регистры из

 

может выбрать одно и то же значение и для источника и для

старшей половины. Компилятор может выбрать и «правильный»

 

приемника, даже если это явно не указано. Обычно это не

регистр, и это может привести к сомнениям: почему ранее работав-

 

опасно, но может быть фатальным, если значение операн-

шая без ошибок ассемблерная вставка вдруг стала вызывать ошиб-

 

да-результата модифицируется другими ассемблерными ин-

ку. Поэтому правильным выбором для ORI будет символ “d”.

 

струкциями до выполнения сохранения результата операто-

В таблице 5 приведены все инструкции ассемблера, требу-

 

ра asm.

 

 

 

 

 

 

 

ющие операндов, с указанием подходящих им символов. Одна-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ко, эти требования недостаточно строгие, т.к. не ограничивают,

 

asm volatile(«in %0,%1»

«\n\t»

 

 

 

например, диапазон номеров битов от 0 до 7 и т.п.

 

 

«out %1, %2»

«\n\t»

 

 

 

 

 

: «=&r» (input)

 

 

 

Любой символ может предваряться символом-модификатором:

 

 

 

 

 

 

 

: «I» (_SFR_IO_ADDR(port)), «r» (output)

 

= – обозначает, что операнд только для записи. Использу-

 

 

);

 

 

 

 

 

ется для операндов результата.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+ – обозначает, что операнд для записи и чтения.

 

 

 

 

 

 

Таблица 5

& – обозначает, что для вывода должен использоваться но-

 

 

 

 

 

 

вый регистр.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Инструкция

 

Символы операндов

Инструкция

Символы операндов

 

 

Используемые для результата операнды всегда должны быть

 

 

 

 

 

 

 

 

 

 

 

 

adc

 

r, r

 

add

r, r

 

 

только для записи и иметь вид «леводопустимого выражения».

 

 

 

 

 

 

 

 

 

 

 

 

 

adiw

 

w, I

 

and

r, r

 

 

Компилятор не проверяет совместимость типов операнда и при-

 

 

 

 

сваемого ему значения.

 

 

 

andi

 

d, M

 

asr

r

 

 

 

 

 

 

Таблица 4

 

bclr

 

I

 

bld

r, I

 

 

 

 

 

 

 

 

 

brbc

 

I, label

 

brbs

I, label

 

Символ

Что обозначает

Допустимые

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

значения

 

 

bset

 

I

 

bst

r, I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

a

Старшие регистры без указателей

r16 … r23

 

 

cbi

 

I, I

 

cbr

d, I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

b

Базовые регистровые пары – указатели

y, z

 

 

com

 

r

 

cp

r, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

d

Старшие регистры

r16 … r31

 

 

cpc

 

r, r

 

cpi

d, M

 

 

 

 

 

 

 

 

 

 

 

 

 

 

e

Регистровые пары – указатели

x, y, z

 

 

cpse

 

r, r

 

dec

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

q

Указатель стека

SPH:SPL

 

 

elpm

 

t, z

 

eor

r, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

r

Любой регистр

r0 … r31

 

 

in

 

r, I

 

inc

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

t

Вспомогательный регистр

r0

 

 

ld

 

r, e

 

ldd

r, b

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w

Специальный старший регистр

r24, r26, r28, r30

 

 

ldi

 

d, M

 

lds

r, label

 

 

 

 

 

 

 

 

 

 

 

 

 

 

x

Регистровая пара X

x (r27:r26)

 

 

lpm

 

t, z

 

lsl

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

y

Регистровая пара Y

y (r29:r28)

 

 

lsr

 

r

 

mov

r, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

z

Регистровая пара Z

z (r31:r30)

 

 

movw

 

r, r

 

mul

r, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

G

Kонстанта в формате с плавающей точкой

0.0

 

 

neg

 

r

 

or

r, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I

6-битовое положительное число (константа)

0 … 63

 

 

ori

 

d, M

 

out

I, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

J

6- битовое отрицательное число (константа)

-63 … 0

 

 

pop

 

r

 

push

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

K

Целочисленная константа

2

 

 

rol

 

r

 

ror

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

L

Целочисленная константа

0

 

 

sbc

 

r, r

 

sbci

d, M

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

l

Младшие регистры

r0 … r15

 

 

sbi

 

I, I

 

sbic

I, I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

M

Однобайтная константа

0 … 255

 

 

sbiw

 

w, I

 

sbr

d, M

 

 

 

 

 

 

 

 

 

 

 

 

 

 

N

Целочисленная константа

-1

 

 

sbrc

 

r, I

 

sbrs

r, I

 

 

 

 

 

 

 

 

 

 

 

 

 

 

O

Целочисленная константа

8, 16, 24

 

 

ser

 

d

 

st

e, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

P

Целочисленная константа

1

 

 

std

 

b, r

 

sts

label, r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Q

Адрес памяти по указателю Y или Z со смещением

 

 

 

sub

 

r, r

 

subi

d, M

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

R

Целочисленная константа

-6 to 5

 

 

swap

 

r

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5 7

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Радиолюбитель – 05/2011

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

СПРАВОЧНЫЙ МАТЕРИАЛ

 

В этом примере сначала осуществляется считывание порта

 

 

То есть вопреки всему ранее сказанному надо использовать

 

port, а затем другое значение в этот же самый порт выводится.

 

нижний регистр для указания младшего байта операнда! Это про-

 

Компилятор вполне может выбрать для ввода и вывода один и

 

блема реализации компилятора GCC текущей версии40.

 

тот же регистр, например, r5, при этом значение r5, считанное

 

 

 

 

 

 

 

 

 

 

первой командой еще до того, как будет записано эпилогом в

 

 

Зависимости оператора asm()

 

переменную output, будет изменено значением, загруженным

 

 

Как было сказано, последним элементом оператора asm мо-

 

из переменной input для вывода во второй команде. Чтобы это-

 

жет быть список зависимостей. Этот список может отсутствовать

 

го избежать, применен модификатор &, который указывает ком-

 

вместе с отделяющим его двоеточием. Однако если внутри ас-

 

пилятору выбрать для операнда источника обязательно другой

 

семблерной вставки программист использует значения регистров,

 

регистр, т.е. не совпадающий ни с одним из выбранных для дру-

 

не указанных в списках операндов, он обязан уведомить компиля-

 

гих операндов “r”.

 

 

 

тор об этом. В этом случае в код пролога будет добавлены коман-

 

Нередка ситуация, когда ассемблерная вставка должна ма-

 

ды сохранения перечисленных в этом списке регистров, а в коде

 

нипулировать числами более одного байта. В этом случае воз-

 

эпилога эти значения будут восстановлены в прежнем виде.

 

никает проблема с обращением к нескольким байтам, состав-

 

 

Например, при помощи следующего кода осуществляется ато-

 

ляющим один операнд. Для обозначения регистров, в которых

 

марное увеличение 8-битной переменной:

 

хранится значение переменной, используются дополнительные

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

символы – заглавные латинские символы «A», «B», «C» и т.д.

 

asm volatile(

 

 

 

 

 

 

 

Такая запись указывает компилятору выбрать очередной ре-

 

 

«cli»

 

«\n\t»

 

 

 

 

 

 

«ld r24, %a0»

«\n\t»

 

 

 

 

гистр для хранения очередного байта, составляющего перемен-

 

 

 

 

 

 

 

 

«inc r24»

 

«\n\t»

 

 

 

 

ную. Младший байт соответствует символу «А», более старшие

 

 

«st %a0, r24»

«\n\t»

 

 

 

 

последовательно назначаются для «В», «С» и т.д. Программист

 

 

«sei»

 

«\n\t»

 

 

 

 

 

:

 

 

 

 

 

 

 

может использовать соответственно «%A0» для обращения к

 

 

 

 

 

 

 

 

 

 

: «e» (ptr)

 

 

 

 

 

 

младшему байту первого операнда, «%A1» – младшему байту

 

 

: «r24»

 

 

 

 

 

 

 

второго операнда и т.д.

 

 

 

);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

В этом примере производится перестановка байтов в 16-бит-

 

 

Примечательно в этом примере то, что используется указа-

 

ной переменной value:

 

 

 

 

 

 

 

 

тель для обращения к переменной, иначе сохранение значения

 

 

 

 

 

 

 

asm volatile(«mov __tmp_reg__, %A0» «\n\t»

 

 

произошло бы только в коде эпилога, который будет добавлен пос-

 

 

«mov %A0, %B0»

«\n\t»

 

 

ле команды разрешения прерывания, т.е. это уже нарушило бы

 

 

«mov %B0, __tmp_reg__» «\n\t»

 

 

условие атомарности ассемблерной вставки. А с использованием

 

 

: «=r» (value)

 

 

 

 

 

 

 

 

указателя переменная обновляется до разрешения прерываний.

 

 

: «0» (value)

 

 

 

 

 

);

 

 

 

 

Более правильным было бы в этом случае использовать

 

 

 

 

 

 

__tmp_reg__ вместо r24:

 

 

 

 

 

Перестановка байтов 32-битного переменной value:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

asm volatile(

 

 

 

 

 

 

 

 

 

 

 

 

 

«cli»

«\n\t»

 

 

 

 

 

 

asm volatile(«mov __tmp_reg__, %A0» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

«ld __tmp_reg__, %a0»

«\n\t»

 

 

 

 

 

«mov %A0, %D0»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

«inc __tmp_reg__»

 

«\n\t»

 

 

 

 

 

«mov %D0, __tmp_reg__» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

«st %a0, __tmp_reg__»

«\n\t»

 

 

 

 

 

«mov __tmp_reg__, %B0» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

«sei»

«\n\t»

 

 

 

 

 

 

 

«mov %B0, %C0»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

:

 

 

 

 

 

 

 

 

«mov %C0, __tmp_reg__» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

: «e» (ptr)

 

 

 

 

 

 

 

: «=r» (value)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

: «0» (value)

 

 

 

);

 

 

 

 

 

 

 

 

 

);

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Вышеприведенные примеры имеют одну неприятную особен-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Для обозначения операнда, используемого и как источник, и

 

ность: их нельзя использовать в участках программы, где преры-

 

как приемник результата, разумно использовать модификатор «+»:

 

вания уже запрещены, т.к. эти вставки принудительно разрешают

 

 

 

 

 

 

прерывания. Казалось бы, эту проблему легко решить при помо-

 

 

 

 

 

 

 

asm volatile(«mov __tmp_reg__, %A0» «\n\t»

 

 

щи локальной переменной:

 

 

 

 

 

 

«mov %A0, %D0»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

«mov %D0, __tmp_reg__» «\n\t»

 

 

{

 

 

 

 

 

 

 

 

 

«mov __tmp_reg__, %B0» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

uint8_t s;

 

 

 

 

 

 

 

 

«mov %B0, %C0»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

asm volatile(

 

 

 

 

 

 

 

«mov %C0, __tmp_reg__» «\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

«in %0, __SREG__»

 

«\n\t»

 

 

: «+r» (value)

 

 

 

 

 

 

 

 

 

 

 

«cli»

 

 

 

«\n\t»

 

 

);

 

 

 

 

 

 

 

 

 

 

 

 

 

«ld __tmp_reg__, %a1»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«inc __tmp_reg__»

 

«\n\t»

 

Непредвиденная проблема может возникнуть еще и в случае,

 

 

 

 

 

«st %a1, __tmp_reg__»

«\n\t»

 

если осуществляется работа с указателем, т.е. регистровой парой.

 

 

«out __SREG__, %0»

 

«\n\t»

 

 

 

: «=&r» (s)

 

 

 

 

 

 

Предположим, программист использует следующее определения

 

 

 

 

 

 

 

 

 

 

: «e» (ptr)

 

 

 

 

 

 

операнда:

 

 

 

 

);

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

«e» (ptr)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

К сожалению, это не так, хотя и выглядит правильно. Ассемблер-

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Допустим, компилятор избрал для хранения этого операнда

 

ный код модифицирует переменную, на которую указывает указа-

 

 

тель ptr. Но загрузка значения указателя в регистровую пару осу-

 

регистровую пару Z, т.е. %A0 соответствует ZL (r30), а %B0 – ZH

 

 

(r31). Однако компилятор вызовет ошибку, если программист ис-

 

ществляется в коде пролога, который выполняется еще до запре-

 

 

щения прерываний, т.е. вполне значение указателя может быть из-

 

пользует обращение к этой паре так:

 

 

 

менено на этом этапе. Разумеется, в этом случае результат работы

 

 

 

 

 

 

 

ld

r24, Z

 

 

 

ассемблерной вставки непредсказуем. Более того, при оптимиза-

 

 

 

 

ции значение указателя вообще может оказаться не в ОЗУ, а в ре-

 

 

 

 

 

 

 

Чтобы компилятор сгенерировал правильный код, необходи-

 

гистрах. Самое меньшее, что можно в этом случае сделать, это

 

 

применить специальный элемент списка зависимостей вставки

 

мо использовать только такую конструкцию:

 

 

 

memory:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ld

r24, %a0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5 8

 

 

 

 

 

 

41 На момент написания книги это соответствует версии GCC 4.3.хх

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Радиолюбитель – 05/2011

 

 

 

 

 

 

 

 

 

 

 

 

 

СПРАВОЧНЫЙ МАТЕРИАЛ

{

 

 

 

 

 

 

«dec %1»

«\n\t»

 

 

 

 

 

 

 

«brne L_dl1%=»

«\n\t»

 

uint8_t s;

 

 

 

 

 

 

 

 

 

: «=&w» (cnt)

 

 

asm volatile(

 

 

 

 

 

 

 

 

 

 

: «r» (ms), «r» (delay_count)

 

«in %0, __SREG__»

«\n\t»

 

 

 

 

 

 

 

);

 

 

 

«cli»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

«ld __tmp_reg__, %a1»

«\n\t»

 

 

 

}

 

 

 

«inc __tmp_reg__»

«\n\t»

 

 

 

 

 

 

 

 

 

 

 

 

 

 

«st %a1, __tmp_reg__»

«\n\t»

 

 

 

Пример демонстрирует реализацию функции задержки про-

«out __SREG__, %0»

«\n\t»

 

 

 

 

 

 

граммным циклом на заданное количество миллисекунд. В функ-

: «=&r» (s)

 

 

 

 

: «e» (ptr)

 

 

 

 

ции используется глобальная переменная delay_count, которая

: «memory»

 

 

 

 

должна содержать значение тактовой частоты, деленное на 4000,

);

 

 

 

 

 

 

 

 

 

 

 

 

причем это значение должно быть присвоено этой переменной до

}

 

 

 

 

 

 

 

 

 

 

 

 

обращений к функции. Как было показано ранее, функция исполь-

 

 

 

 

 

 

 

Это укажет компилятору учесть при оптимизации тот факт, что

 

зует локальную переменную для сохранения значения используе-

 

мых регистров.

 

 

ассемблерная вставка использует память, которую нельзя модифици-

 

 

 

 

Следующий пример показывает, как реализуется возврат зна-

ровать. Но наиболее простой и удобный способ все-таки состоит в

 

 

чения из ассемблерной функции:

том, чтобы использовать volatile при определении указателя ptr:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

volatile uint_t *ptr;

 

 

 

 

uint16_t inw(uint8_t port)

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

uint16_t result;

 

 

Это обеспечит правильное поведение как самой ассемблерной

 

 

 

 

asm volatile (

 

 

вставки, так и оптимизатора в ее отношении.

 

 

 

«in %A0,%1» «\n\t»

 

 

 

 

 

«in %B0,(%1) + 1»

 

 

Примечание. Случаи действительной необходимости в указании

 

 

 

 

: «=r» (result)

 

 

списка зависимостей достаточно редки. Почти всегда есть возмож-

 

: «I» (_SFR_IO_ADDR(port))

 

ность избежать их, обеспечив компилятору больше свободы в оптими-

 

);

 

 

 

 

return result;

 

 

зации кода.

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

Макросы на ассемблере

 

 

 

 

 

 

 

 

 

 

Функция inw возвращает 16-разрядное число, считанное из

Для многократного использования ассемблерных вставок в раз-

 

 

пары «смежных» портов ввода-вывода. port определяет «младший»

личных проектах имеет смысл разместить их в заголовочном файле в

 

 

порт.

 

 

виде макросов. AVR-LIBC содержит немалое количество таких фай-

 

 

 

 

 

 

 

 

лов, найти которые можно в директории avr/include. Однако такое ис-

 

Соглашения об именах Си и ассемблера

пользование ассемблерных вставок может вызвать предупреждения

 

По умолчанию GCC использует одинаковые имена переменных

компилятора для режима соответствия ANSII-стандарту. Чтобы избе-

 

 

и функций для Си и для ассемблера. Однако программист может

жать предупреждений, достаточно писать __asm__ вместо asm и

 

 

изменить эту ситуацию при помощи особой формы оператора asm:

__volatile__ вместо volatile – это полные синонимы.

 

 

 

 

 

 

Более заметная проблема ассемблерных вставок в виде макро-

 

unsigned long value asm(«clock») = 3686400;

 

сов связана с использованием меток. Макрос – это ведь просто под-

 

 

 

 

 

 

 

 

 

становка текста, поэтому в случае использования обычных меток в

 

Это определение вынудит компилятор использовать имя clock

ассемблерныхвставкахвозможнопоявлениеодинаковыхметоквраз-

 

вместо его значения. Такая «подмена» имеет смысл только для

личных участках программы, что недопустимо. Для избежания этого

 

глобальных (статических) или внешних переменных, так как локаль-

следуетиспользоватьособыйсинтаксисметокдляассемблерныхвста-

 

ные переменные не имеют символьных имен для ассемблера. Кро-

вок: в определении метки используется сочетание «%=», которое на

 

ме того, локальные переменные могут быть помещены в регистры.

этапе компиляции заменяется на некий уникальный номер, таким об-

 

Программист может назначить локальной переменной опреде-

разом, гарантируя уникальность всех меток. Вот, например, как реа-

 

ленный регистр:

 

 

лизован один из макросов в iomacros.h:

 

 

 

 

 

 

 

 

 

 

void Count(void)

 

 

 

 

 

 

 

 

 

 

 

#define loop_until_bit_is_clear(port,bit)

\

 

 

{

 

 

 

 

 

register unsigned char counter asm(«r3»);

 

__asm__ __volatile__ (

\

 

 

 

 

 

 

 

 

 

«L_%=: « «sbic %0, %1» «\n\t»

\

 

 

... какие то действия ...

 

«rjmp L_%=»

 

\

 

 

 

 

 

 

asm volatile(«clr r3»);

 

 

: /* no outputs */

\

 

 

 

 

 

 

... какие то действия ...

 

: «I» (_SFR_IO_ADDR(port)),

 

 

 

 

 

 

 

 

 

«I» (bit)

 

 

 

 

}

 

 

 

)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

В этом примере показано, как заставить компилятор поместить

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Метка L_%= будет заменена на что-то типа L_1234, при-

 

локальную переменную counter в регистр r3. Однако, это не «веч-

чем это будет гарантированно уникальная метка.

 

ное» закрепление: если оптимизатор компилятора сочтет, что зна-

 

 

 

 

 

 

 

чение переменной более не требуется сохранять, назначение реги-

Функции на ассемблере

 

 

 

стра r3 может быть переопределено. Если программист закрепляет

Макрос с ассемблерной вставкой будет приводить к появлению

 

слишком много регистров за переменными, компилятор может ис-

одного и того же кода каждый раз при использовании макроса. Для

 

черпать ресурсы регистров для компиляции остального кода. Кро-

многих критичных к размеру памяти приложений это неприемлемо.

 

ме этого, принудительное назначение регистра переменной чаще

В этом случае логичнее реализовать С-функцию целиком на ас-

 

приводит к ухудшению эффективности кода вместо ожидаемой его

семблере.

 

 

 

 

оптимизации.

 

 

 

 

 

 

 

 

 

Существует и способ изменить имя функции:

void delay(uint8_t ms)

 

 

 

 

 

 

 

 

 

 

 

 

{

 

 

 

 

 

 

extern long Calc(void) asm («CALCULATE»);

 

uint16_t cnt;

 

 

 

 

 

 

 

 

 

 

 

 

 

asm volatile (

 

 

 

 

 

 

 

 

 

 

 

 

Вышеприведенный пример заставит компилятор при обраще-

«\n»

 

 

 

 

«L_dl1%=:»

«\n\t»

 

 

 

нии к функции Calc() генерировать инструкцию вызова функции

«mov %A0, %A2»

«\n\t»

 

 

 

 

 

 

CALCULATE.

 

 

«mov %B0, %B2»

«\n»

 

 

 

 

 

«L_dl2%=:»

«\n\t»

 

 

 

 

 

 

 

«sbiw %A0, 1»«\n\t»

 

 

 

 

 

 

 

 

«brne L_dl2%=»

«\n\t»

 

 

 

 

 

Окончание следует.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

5 9

Радиолюбитель – 05/2011

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Соседние файлы в папке Книга по работе с WinAVR и AVR Studio