avrasm-arytmetyka.pdf

(65 KB) Pobierz
305452942 UNPDF
http://www.easy-soft.tsnet.pl/
AVR Asembler:
Operacje arytmetyczne.
W dzisiejszym odcinku kursu nieco odbiegniemy od prezentowanych wcześniej sposobów wykorzystywania
zasobów mikrokontrolera. Każda aplikacja musi czasami dodać, odjąć lub porównać jakieś wartości. Tworząc ją
w języku wysokiego poziomu wszystko jest proste: deklarujemy typy zmiennych A i B a następnie prosty zapis
A+B rozwiązuje problem. W asemblerze nie jest niestety tak łatwo.
Operacje arytmetyczne w asemblerze AVR.
W lekturze dzisiejszego odcinka przydadzą się zdobyte wcześniej informacje na temat bitów wskazujących lub
inaczej flag. Szczególnej uwadze polecam zachowanie się flag C (przeniesienia) i Z (zera) bardzo użytecznych w
prezentowanych dziś przykładach procedur.
Dodawanie liczb: 8+8 bitów, 16+16 bitów, 16+8 bitów.
Do realizacji dodawania służą rozkazy add oraz adc. Ten pierwszy nie uwzględnia bitu przeniesienia, ten drugi
bierze go pod uwagę. Jak pamiętamy, bit przeniesienia sygnalizuje sytuację, w której wynik nie mieści się w
rejestrze go przechowującym. Wówczas to flaga C przyjmuje wartość logiczną 1. Rozkaz adc powoduje, że
wartość flagi C dodawana jest do bajtu jako bit znajdujący się na najmłodszej jego pozycji. Na listingu 1
przedstawiono wybrane implementacje funkcji dodawania. Są to: dodawanie dwóch liczb 8 bitowych ( add_8_8 ),
dodawanie dwóch liczb 16 bitowych ( add_16_16) , dodawanie liczby 16 i 8 bitowej ( add_16_8 ) oraz dodanie
stałej o długości 16 bitów do zmiennej 16 bitowej ( add_16_const ). Realizacja pierwszych trzech funkcji
dodawania jest bardzo prosta. Młodsze bajty dodaje się przy pomocy add . Operacje wykonywane na starszych
bajtach muszą już uwzględniać stan flagi C, która może być ustawiona przez wcześniej wykonane dodawanie
młodszych bajtów licz. Umożliwia to rozkaz adc . Dodawanie liczby 16 i 8 bitowej może spowodować sytuację, w
której wynik przekroczy rozmiar pojedynczego bajtu. Dlatego też rozkaz rol wprowadza flagę C na pozycję
najmłodszego bitu starszego bajtu wyniku.
Na uwagę zasługuje funkcja dodawania stałej do zmiennej - obie o długości 16 bitów. Lista rozkazów AVR nie
oferuje rozkazu dodawania stałej do zmiennej z przeniesieniem, więc dodawanie zostało przeprowadzone przez
... odejmowanie liczb ujemnych. Radzę zapamiętać tę metodę na przyszłość.
;deklaracje zmiennych
.def A1 = R16
;młodszy (A1)
.def A2 = R17
;i starszy (A2) bajt zmiennej A
.def B2 = R19
;i starszy (B2) bajt zmiennej B
;dodawanie dwóch liczb 8-bitowych,
;pierwsza liczba w A1,druga w B1
;wynik przechowywany w A2:A1
add_8_8:
clr A2 ;zerowanie rejestru, w którym zapamiętany będzie starszy bajt wyniku
add A1,B1 ;dodanie zmiennych bez uwzględnienia flagi C
rol A2 ;wprowadzenie flagi przeniesienia jako wartości liczbowej
ret
;dodawanie dwóch liczb 16-bitowych
;pierwsza liczba w A2:A1, druga w B2:B1
;wynik przechowywany w A2:A1 + flaga C
add_16_16:
add A1,B1 ;dodanie młodszych bajtów liczby bez uwzględnienia flagi C
adc A2,B2 ;dodanie starszych bajtów liczby z uwzględnieniem flagi C
ret
;powrót do wywołania z ustawioną lub nie flagą C
;dodawanie liczby 16 i 8-bitowej
;pierwsza liczba w A2:A1, druga w B2
;wynik przechowywany w A2:A1
add_16_8:
clr B2
call add_16_16
ret
J.Bogusz „AVR Asembler: Operacje arytmetyczne”
STRONA 1/3
.def B1 = R18
;młodszy (B1)
305452942.002.png
http://www.easy-soft.tsnet.pl/
;dodawanie stałych od długości 16 bitów do zmiennej 16-bitowej
;zmienna w A2:A1, stała zdefiniowana po dyrektywie .equ
;wynik przechowywany w A2:A1 + flaga C
.equ ccc = $18A0
add_16_const:
subi A1,low(-ccc) ;dodaj młodszy bajt (A1-(-ccc)=A1+ccc)
sbci A2,high(-ccc) ;dodaj starszy bajt z przeniesieniem
ret
Listing 1. Przykłady realizacji funkcji dodawania
Odejmowanie liczb: 8-8 bitów, 16-16 bitów, 16-8 bitów.
Na listingu 2 przedstawiono funkcje realizujące odejmowanie liczb. Analogicznie do dodawania, zdefiniowane są
funkcje odejmujące liczbę 8 bitową od 8 bitowej, 8 od 16, 16 od 16 oraz odejmują stałą od zmiennej. W
przypadku odejmowania nie ma problemu braku odpowiedniego rozkazu, toteż procedura może być
zrealizowana bez żadnych „sztuczek”. Do realizacji odejmowania służą rozkazy sub oraz sbc i sbci. Ten pierwszy
nie uwzględnia bitu przeniesienia, dwa następne wykonują działanie z uwzględnieniem przeniesienia. Rozkaz
sbci odejmuje od zmiennej stałą podaną jako jeden z parametrów wywołania.
;deklaracje zmiennych
.def A1 = R16
;młodszy (A1)
.def A2 = R17
;i starszy (A2) bajt zmiennej A
.def B2 = R19
;i starszy (B2) bajt zmiennej B
;odejmowanie dwóch liczb 8-bitowych,
;pierwsza liczba w A1,druga w B1
;wynik przechowywany w A2:A1
sub_8_8:
clr A2 ;wyzerowanie starszego bajtu wyniku
sub A1,B1 ;wykonanie operacji dla młodszych bajtów
rol A2 ;wprowadzenie flagi C na pozycję najmłodszego bitu msb wyniku
ret
;odejmowanie dwóch liczb 16-bitowych
;pierwsza liczba w A2:A1, druga w B2:B1
;wynik przechowywany w A2:A1 + flaga C
sub_16_16:
sub A1,B1 ;wykonanie operacji dla młodszych bajtów
sbc A2,B2 ;wykonanie operacji dla starszych bajtów z uwzględnieniem flagi C
ret
;odejmowanie od liczby 16 liczby 8-bitowej
;pierwsza liczba w A2:A1, druga w B2
;wynik przechowywany w A2:A1
sub_16_8:
sub A1,B1 ;wykonanie operacji dla młodszych bajtów
sbci A2,0 ;uwzględnienie przeniesienia
ret
;odejmowanie od zmiennej o długości 16 bitów stałych o długości 16 bitów
;zmienna w A2:A1, stała zdefiniowana po dyrektywie .equ
;wynik przechowywany w A2:A1 + flaga C
.equ ccc = $18A0
sub_16_const:
subi A1,low(ccc) ;odejmij młodszy bajt
sbci A2,high(ccc) ;odejmij starszy bajt z przeniesieniem
ret
Listing 2. Przykłady realizacji funkcji odejmowania
J.Bogusz „AVR Asembler: Operacje arytmetyczne”
STRONA 2/3
.def B1 = R18
;młodszy (B1)
305452942.003.png 305452942.004.png
http://www.easy-soft.tsnet.pl/
Porównywanie liczb: 8 i 8 bitów, 16 i 16 bitów.
Listing 3 zawiera operacje porównania liczb. Co prawda można prezentowane funkcje zastąpić przez
odejmowanie, jednak listing 3 to również próba pokazania w jaki sposób używa się rozkazów porównań
oferowanych przez język asembler AVR. Podobnie jak poprzednio, również rozkazy porównań ustawiają flagi Z i
C. Tak więc do porównania dwóch liczb bez uwzględnienia stanu flagi przeniesienia służy rozkaz cp , natomiast
porównanie z uwzględnieniem stanu flagi C przeprowadza rozkaz cpc. W przypadku porównania stałej ze
zmienną istnieje pewne niekonsekwencja: o ile można bowiem porównać stałą i zmienną z pominięciem stanu
flagi C, o tyle brak jest rozkazu uwzględniającego przeniesienie przy porównaniu stałej i zmiennej. Dlatego też
konieczne jest wykorzystanie zmiennej temp , do której załadowana zostanie stała do porównania.
;deklaracje zmiennych
.def A1 = R16
;młodszy (A1)
.def A2 = R17
;i starszy (A2) bajt zmiennej A
.def B1 = R18
;i starszy (B2) bajt zmiennej B
;porównanie dwóch liczb 8-bitowych zapamiętanych w zmiennych A1 i B1
;jeśli liczby są równe, ustawiana jest flaga Z
cp_8_8:
cp A1,B1 ;lista rozkazów AVR zawiera rozkaz porównania-tu bez flagi C
ret
;porównanie dwóch liczb 16-bitowych
;jeśli liczby są równe, ustawiana jest flaga Z
cp_16_16:
cp A1,B1 ;porównanie młodszych bajtów
cpc A2,B2 ;porównanie starszych bajtów ale z uwzględnieniem flagi C
ret
;porównanie liczby 16-bitowej i stałej o długości 16 bitów
;jeśli liczby są równe, ustawiana jest flaga Z
.equ ccc = $18A0
.def temp R20
cp_16_const:
cpi A1,low(ccc) ;porównanie młodszych bajtów
ldi temp,high(ccc) ;nie istnieje wariant cpc dla stałych stąd konieczność użycia
cpc B2,temp
;zmiennej temp i porównania starszego bajtu z tą zmienną
Znajomość podstawowych sposobów wykonywania podstawowych działań umożliwia budowę innych funkcji np.
mnożenia (przez dodawanie) czy dzielenia (przez odejmowanie). Umożliwia również konwersję liczb
szesnastkowych na dziesiętne – jest to zagadnienie bardzo często spotykane wśród pytań zadawanych przez
początkujących programistów na grupach tematycznych.
Jacek Bogusz
jacek.bogusz@easy-soft.tsnet.pl
J.Bogusz „AVR Asembler: Operacje arytmetyczne”
STRONA 3/3
.def B2 = R19
;młodszy (B1)
ret
Listing 3. Porównywanie liczb
305452942.005.png 305452942.001.png
Zgłoś jeśli naruszono regulamin