AVR Asembler. Podstawowe operacje arytmetyczne.

AVR Asembler. Podstawowe operacje arytmetyczne.

W tym 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.

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ść.

List. 1. Przykłady realizacji funkcji dodawania
;deklaracje zmiennych
.def    A1 = R16        ;młodszy (A1)
.def    A2 = R17        ;i starszy (A2) bajt zmiennej A
.def    B1 = R18        ;młodszy (B1)
.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 będzie zapamiętany
                  ;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

;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

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 isbci. 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.

List. 2. Przykłady realizacji funkcji odejmowania
;deklaracje zmiennych
.def    A1 = R16        ;młodszy (A1)

.def    A2 = R17        ;i starszy (A2) bajt zmiennej A
.def    B1 = R18        ;młodszy (B1)
.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 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. 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

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.

List. 3. Porównywanie liczb
;deklaracje zmiennych
.def    A1 = R16        ;młodszy (A1)
.def    A2 = R17        ;i starszy (A2) bajt zmiennej A
.def    B1 = R18        ;młodszy (B1)
.def    B2 = R19        ;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 zawiera rozkaz porównania-tu bez flagi
    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
zmiennej temp
    cpc    B2,temp        ;i porównania starszego bajtu z tą zmienną
    ret

Znajomość 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

j.bogusz@easy-soft.net.pl

http://www.tomaszbogusz.blox.pl/

Dodaj nowy komentarz

Zawartość pola nie będzie udostępniana publicznie.