SPR2.DOC

(44 KB) Pobierz
1

 

Podstawy Techniki Mikroprocesorowej

Laboratorium

 

 

 

 

 

Ćwiczenie nr 2

 

 

 

Temat:  DODAWANIE LICZB WIELOBAJTOWYCH

 

 

 

 

 

 

Wykonali:               1. Grzegorz Kałużny

              2. Piotr Jeziorski

 

 

Kierunek:              informatyka                                                         Rok studiów: II

 

 

 

 

 

Prowadzący:                             mgr Marcin Biliński

 

 

 

 

 

 

 

 

 

 

1.              WSTĘP

 

Żeby prawidłowo wykonywać ćwiczenia związane z dodawaniem liczb wielobajtowych, jak również z operacjami na stosie należy dobrze opanować strukturę pamięci zestawu dydaktycznego oraz ściśle z nią związane tryby adresowania dostępne w mikrokontrolerze. Zestaw 80535 znajdujący się w laboratorium daje użytkownikowi do dyspozycji następujące tryby adresowe:

1.     rejestrowy : MOV R0,A
adresem jest tu numer (nazwa) rejestru

2.     rejestrowy pośredni : MOV @R0,A
adresem argumentu jest zawartość rejestru

3.     bezpośredni : MOV A,01H
adres argumentu stanowi drugi lub drugi i trzeci bajt rozkazu

4.     natychmiastowy : MOV A,#0
argument znajduje się w drugim lub w trzecim bajcie rozkazu

5.     indeksowy : MOV X A,@DPTR
względem rejestru adresowego DPTR

 

Zewnętrzna pamięć podzielona jest na pamięć danych i programu. Pamięć programu składa się z 8kB EPROM, w której znajduje się program monitora (jego część pracująca w ZD535) oraz 31kB RAM, do której przegrywany jest program użytkownika. Wielkość pamięci danych wynosi 2kB.

 

2.    Przebieg ćwiczenia.

 

Zadanie 1.

 

Zadaniem pierwszego programu było dodawanie dwóch liczb dwubajtowych L1 i L2, których wartości były zadeklarowane w programie. 

 

Listing :

 

$lab535.inc

        SUMA    EQU 30H ;deklaracja adresu SUMY liczb L1 i L2

 

        ORG 0           ;miejsce umieszczenia kodu programu

main:

        MOV R1,#SUMA    ;przeslanie do R1 adresu SUMA 30H

        MOV DPTR,#L1    ;przeslanie do DPTR adresu liczby L1

        MOV A,#0        ;zaladowanie do A wartosci indeksu adresowego

        MOVC A,@A+DPTR  ;przeslanie z pamieci programu z komorki

                        ;o adresie (A+DPTR) do akumulatora /wartosc L1/

        MOV R0,A        ;zaladowanie tej wrtosci do R0

        MOV A,#0        ;zaladowanie do A indeksu pamieci

        MOV DPTR,#L2    ;zaladowanie do DPTR adresu liczby L2

        MOVC A,@A+DPTR  ;przeslanie z pamieci programu do akumulatora

        ADD A,R0        ;dodanie zawartosci akumulatora i R0 wynik w A

        MOV @R1,A       ;przeslanie wyniku do komorki pamieci o adresie

                        ;znajdujacym sie w R0/jest to komorka SUMA/

        MOV DPTR,#L1    ;przeslanie do DPTR adresu liczby L1

        MOV A,#1        ;indeks pamieci zwiekszony o 1 /nastepna komorka
                                                        ;pamieci/

MOVC A,@A+DPTR  ;przeslanie zawartosci komorki (A+DPTR) do A jest drugi
                                          ;bajt L1

        MOV R0,A        ;drugi bajt L1 przeslany do R0

        MOV A,#1        ;ustawienie indeksu pamici w akumulatorze

        MOV DPTR,#L2    ;przeslanie do DPTR adresu L2

        MOVC A,@A+DPTR  ;wyslanie do A wartosci drugiego bajtu liczby L2

                        ;z pamieci programu o adresie (A+DPTR)

        ADDC A,R0       ;dodanie drugich bajtow liczby L1 (R0) i liczby L2 (A)

                        ;z uwzglednieniem przeniesienia z poprzedniego dodawania

        INC R1          ;zwiekaszenie adresu wyniku znajdujacego sie w R1

        MOV @R1,A       ;przeslanie wyniku dodawania drugich bajtow do komorki

                        ;pamieci o adresie znajdujacym sie w R1

        CALL RETURN

 

L1:     DB    0AAH,0AAH

L2:     DB     88H, 88H

END                      ;koniec programu

 

 

Wartości tych liczb zostały zadeklarowane w programie, więc aby móc odczytać w trakcie działania programu liczby L1 i L2 należało korzystać z instrukcji MOVC A, @A+DPTR. Instrukcja przesyła zawartość komórki pamięci programu o adresie będącym sumą zawartości akumulatora (8-bitowa liczba dwójkowa) i zawartości 16-bitowego rejestru bazowego DPTR do akumulatora. W  rejestrze DPTR można przechowywać adres bazowy (adres do początku liczby), natomiast zwiększając zawartość akumulatora można odwoływać się do kolejnych komórek pamięci (kolejnych bajtów liczby), adresując akumulator względem rejestru DPTR. Rejestry R0 i R1 służyły jako wskaźniki na pamięć z danymi liczbami (zawierały adresy do bajtów dodawanych liczb), a następnie zawierały poszczególne bajty liczb L1 i L2. Podczas dodawania pierwszych bajtów liczb L1 i L2 korzystałem z instrukcji ADD A, @R0. Instrukcja ta dodaje zawartość akumulator i zawartość komórki pamięci wskazywanej przez R0, wynik  zostaje zwrócony w akumulatorze oraz w przypadku przeniesienia następną pozycję instrukcja ta zmienia stan znacznika CARRY w rejestrze PSW, natomiast nie uwzględnia ona stanu tego wskaźnika podczas operacji dodawania. Inaczej jest w instrukcji ADDC A, @R0, której użyłem dodając drugie bajty liczb. Instrukcja ta podczas operacji dodawania uwzględnia stan wskaźnika CARRY, czyli umożliwia uwzględnienie przeniesienia z poprzedniej pozycji. Działanie tej instrukcji opisuje wyrażenie: A = A + (R0) + CY. Wynik operacji dodawania jest zwrócony do pamięci danych do komórki o adresie 30H. Do adresowania rejestrowego pośredniego (np. MOV @R0,A) można wykorzystywać tylko rejestry R0 i R1. dlatego też chcąc przesłać wynik dodawania do komórki adresie 30H i 31H wykorzystałem rejestr R1.

 

 

Zadanie 2.

 

Zadaniem drugiego programu było dodawanie dwóch liczb dwubajtowych . Program powinien zawierać procedurę, dla której argumentami będą: adresy pierwszych bajtów dwóch liczb wielobajtowych, adres pierwszego bajtu ich sumy, długość w bajtach składników. program powinien wstępnie wrzucać na stos potrzebne adresy i dopiero wtedy wywoływać procedurę sumowania. Czyli argumenty dla procedury zastaną przesłane przez stos.

 

Listing :

 

$LAB535.INC

 

        N       EQU 16          ;deklaracja dlugosci bajtowej liczb

        L1      EQU 30H         ;deklaracja adresu pierwszej liczby

        L2      EQU 30H+N       ;deklaracja adresu drugiej liczby

        SUMA    EQU 30H+N+N     ;deklaracja adresu sumy liczb L1 i L2

 

        ORG 0                   ;ustawienie w pamieci miejsca programu

 

        MOV R3,#N              ;przeslanie do R3 ilosci bajtow N liczby

PUSH 3                 ;wyslanie N na stos

        MOV R2,#SUMA           ;wyslanie na stos adresow pierwszych bajtow

        PUSH 2                 ;SUMY wyniku operacji L1+L2

        MOV R1,#L2             ;wyslanie na stos adresow pierwszych bajtow

        PUSH 1                 ;liczby L2

        MOV R0,#L1             ;wyslanie na stos adresow pierwszych bajtow

        PUSH 0                 ;liczby L1

        CALL SUMUJ             ;wywolanie procedury DODAJ

        CALL RETURN

 

SUMUJ:  POP 5            ;zdjecie ze stosu starszego bajtu PC

        POP 6            ;zdjecie ze stosu mlodszy bajtu PC

        POP 0            ;zdjecie ze stosu adresu L1 do R0

        POP 1            ;zdjecie ze stosu adresu L2 do R1

        POP 2            ;zdjecie ze stosu adresu SUMA do R2

        POP 3            ;zdjecie ze stosu N do R3

        CLR C            ;zerowanie przeniesienia przed pierwszym dodawaniem

 

  ET1:  MOV A,@R0       ;przeslanie do A zawarto sci komorki adresowanej

                        ;przez R0 - bajtu liczby L1

        ADDC A,@R1      ;dodanie z uwzglednieniem przeniesienia bajtu liczby

                        ;L1 (A) z bajtem liczby L2 adresowanej przez R1

        MOV 4,1         ;przeslanie zawartosci R1 do R4 (rejestr pomocniczy)

        MOV 1,2         ;przeslanie zawartosci R2 do R1 (adres wyniku SUMA)

        MOV @R1,A       ;wyslanie wyniku z A do komorki o adresie z R1 - SUMA

        MOV 1,4         ;odtworzenie zawartosci R1 jako adresu liczby L2

        INC R0          ;zwiekszenie adresu do L1 /nastepny bajt tej liczby/

        INC R1          ;zwiekszenie adresu do L2 /nastepny bajt tej liczby/

        INC R2          ;zwiekszenie adresu do SUMY /nastepny bajt tej liczby/

        DJNZ R3,ET1    ;powtarzaj petle ET1 tyle razy ile jest bajtow N liczb

 

        PUSH 6          ;zwrot na stos starszego bajtu PC

        PUSH 5          ;zwrot na stos mlodszego bajtu PC

        RET             ;powrot z procedury

END                     ;koniec programu

 

              Dane do operacji sumowania pobierane są z pamięci danych począwszy od adresu 30H. W pamięci tej znajdują się pierwszy argument dodawania, drugi argument dodawania i po wykonaniu programu wynik też jest przesyłany do tej pamięci, pod adres odpowiadający stałej SUMA. Na początku adresy argumentów,  wyniku i długości argumentów zostają przesłane na stos. W ten sposób następuje przekazanie parametrów do procedury. Do przesłania wartości rejestrów na stos używam instrukcji PUSH ad, gdzie ad jest adresem bezpośrednim rejestrów wewnętrznych procesora. Następnie program wywołuje procedurę SUMA.

Procedura SUMA na swym początku zapamiętuje w rejestrach R5 i R6 zawartość licznika rozkazów PC, zdejmując go ze stosu (na stos PC został przesłany przez instrukcję wywołującą procedurę CALL). Po tym procedura pobiera ze stosu argumenty do dalszych obliczeń: adresy do dodawanych liczb L1 i L2 oraz adres wyniku i długość dodawanych argumentów. Ze względu na konstrukcje stosu kolejność zdejmowania ze stosu jest odwrotna od kolejności wkładania na stos. Do zdejmowania ze stosu używam instrukcji POP ad, gdzie ad jest adresem bezpośrednim rejestru. Ze względu na to że dodawanie odbywa się w pętli i wykorzystuje instrukcję ADDC A,@R1 (dodanie z uwzględnieniem stanu wskaźnika przeniesienia CARRY) przed pierwszym wykonaniem pętli zeruję stan wskaźnika przeniesienia CARRY instrukcją CLR C. Dalsza część procedury dodaje w pętli poszczególne bity dodawanych argumentów wykorzystując adresy do nich. Jak już wspomniałem przy tym dodawaniu uwzględnia stan wskaźnika przeniesienia. W pętli obliczeniowej po instrukcji dodawania wynik jest przekazywany do pamięci, a następnie inkrementowane są rejestry zawierające adresy argumentów, po to aby przy kolejnym wykonywaniu pętli instrukcje odwoływały się do następnych bajtów argumentów i wyniku. Pętla dodająca wykonywana jest tyle razy ile bajtów mają argumenty. Warunek realizujący pętlę DJNZ R3,ET1 zapewnia nam to pod warunkiem, że rejestr R3 zawiera licznik (liczbę bajtów argumentów). na koniec procedura zwraca na stos pobraną na samym początku zawartość licznika rozkazów PC. Wykonywane jest to po to aby instrukcja kolejna, czyli powrotu z procedury RET, mogła korzystać ze stosu z argumentów jakie zostały tam złożone przez instrukcję CALL.      

 

 

1.     Wnioski.

 

Ćwiczenie pozwoliło spostrzec różnice między pamięcią programu i pamięcią danych. Podstawową różnicą , jest sposób odwoływania się do tych różnych pamięci. Do odwoływania się do pamięci programu służy instrukcja MOVC, w której występuje adresowanie indeksowe, względem rejestru adresowego DPTR lub licznika rozkazów z przesunięciem w akumulatorze. Natomiast do pamięci danych możemy odwoływać się na wiele różnych sposobów, m.in.

·        w sposób bezpośredni, podając bezpośredni adres komórki pamięci,

·        w sposób rejestrowy pośredni, podając rejestr w którym znajduje się adres argumentu,

·        w sposób rejestrowy, podając jako adres numer rejestru.

Wykonując ćwiczenie musieliśmy korzystać z instrukcji arytmetycznych, które korzystały ze wskaźnika CARRY  rejestru PSW. Zauważyliśmy różnice między działaniem instrukcji dodającej, która to może korzystać ze wskaźnika CARRY jako argument operacji dodawania (instrukcja ADDC), bądź też nie korzysta ze wskaźnika CARRY podczas dodawania (instrukcja ADD). Obie te instrukcje natomiast używają tego wskaźnika aby poprawnie podać wynik operacji dodawania.     

Poznaliśmy również zasady określające korzystanie ze stosu. Ze względu na strukturę tego obiektu, podczas korzystania z operacji z nim związanych należało przestrzegać kilku podstawowych zasad:

·        zdejmując argumenty ze stosu należy czynić to w odwrotnej kolejności niż się ja składało na stosie,

·        należy uwzględniać wpływ innych instrukcji (takich jak: CALL, RET, RETI, PUSH, POP) na zawartość na stosie,

·        zawsze trzeba być świadomym zawartości stosu w zakresie wykorzystywanym przez program (istotna jest kolejność argumentów na stosie).

 

Ćwiczenie pokazało nam w jaki sposób tworzyć procedury ,przekazywać parametry do procedur oraz w jaki sposób móc odwoływać się do wyników działania procedur. Istotny dla obu tych zagadnień jest stos jako bezpieczne miejsce przekazywania danych.     

 

Zgłoś jeśli naruszono regulamin