Sprawozdanie nr 1
Symulacja działania 8051 - arytmetyka 16-to bitowa: ADD (dodawanie), SUBB(odejmowanie)
Opis:
Akumulator - jest rejestrem roboczym, najbardziej uniwersalnym ponieważ może być argumentem wielu rozkazów, w których użycie innego rejestru nie jest możliwe. Nie powinien być on używany do przechowywania danych w dłuższych sekwencjach programu, gdy prawdopodobnie będzie potrzebny do bieżących operacji w kolejnych rozkazach.
EQU - dyrektywa EQU przypisuje wyrażenie numeryczne lub symbol rejestru do specyfikowanej nazwy symbolu.
DATA- dyrektywa DATA przydziela do specyfikowanej nazwy obszar wewnętrznej pamięci RAM. Wyrażenie numeryczne musi być z zakresu 0 do 255. Symbol definiowany dyrektywą nie może być powtórnie użyty w programie.
PROG SEGMENT CODE - Definiuje segment o nazwie PROG w klasie pamięci CODE, czyli w pamięci programu. Wszystko co pojawi się w tym segmencie będzie umieszczone w jego pamięci . Po zdefiniowaniu nazwy segmentu należy go wybrać, używając dyrektywy RSEG.
CSEGAT nr – powoduje, że napisany niżej kod ma być umieszczony w pamięci programu począwszy od podanego adresu „nr” .
RSEG nazwa - rozpoczyna segment zdefiniowany przy pomocy PROG SEGMENT CODE (w przypadku naszego programu ma on nazwę PROG). Od tego momentu, znajdujący się poniżej kod zostanie umieszczony w pamięci programu. Raz rozpoczęty segment jest
ważny do czasu rozpoczęcia nowego.
JMP nazwa – powoduje przemieszczenie się (skok) do miejsca oznaczonego jako „nazwa”. ADDA,dana – dodaje wartość z komórki o adresie zastąpionym tekstem „dana” do Akumulatora, bez przeniesienia.
ADDCA,dana – dodaje wartość z komórki o adresie zastąpionym tekstem „dana” do Akumulatora, z uwzględnieniem przeniesienia.
MOV gdzie,skąd – kopiuje wartość z komórki o adresie zastąpionym tekstem „skąd” do komórki o adresie zastąpionym tekstem „gdzie”.
SUBB A,dana - odjęcie od wartości zapisanej w Akumulatorze wartość komórki pamięci „dana” Jeżeli dana>A to nastąpi pożyczka „1” z zewnątrz, co zostanie zasygnalizowane zmianą flagi cy na „1”. Jeżeli flaga cy była ustawiona na „1”, to odejmowana jest także pożyczka wykonana przez poprzednie wywołanie odejmowania (jeżeli takowe nastąpiło).
CLR C – wyzerowanie przeniesienia (będzie to najmłodszy bit wyniku) .
END - dyrektywa musi być umieszczona w ostatniej linii programu źródłowego, jest warunkiem zakończenia programu.
Dodawanie dwóch liczb 16-bitowych:
Rozkaz dodawania, którego pierwszym argumentem jest zawsze akumulator (w nim pozostaje równie wynik dodawania) jest dostępny w dwóch wariantach:
ADD - dodawanie bez przeniesienia ADDC - dodawanie z przeniesieniem (flaga CY)
Największa wartość, która może zmieścić się w 16-bitach to 256*256-1 czyli 65 535. Dodając do siebie 65 535 i 65 535 otrzymamy 131 070 – ta wartość mieści się w 17-bitach. Czyli dodawanie 16-bitowe dwóch wartości 16-bitowych daję w wyniku wartość co najwyżej 17-bitową.
Dla przykładu rozważmy dodawanie liczb 2569 i 1000 co da wynik 3569. Najpierw przekształćmy wyrażenie na system szesnastkowy:A09h x 3E8h.
|
|
|
|
|
|
|
|
|
|
|
|
Najpierw dodajemy liczby z kolumny 1's (młodsze bajty): 09 + E8 = F1. W pierwszej kolumnie może zmieścić się tylko 2-cyfrowa wartość szesnastkowa. Więc jeżeli mamy jakiś nadmiar to musimy pamiętać aby przenieść go do kolumny ze starszymi bajtami. Dodajemy teraz starsze bajty: A+3=D. Musimy pamiętać o przeniesieniu nadmiaru z kolumny 1's. W naszym przypadku takowego nie było, więc wartość wyniku nie ulegnie zmianie. Tak więc ostateczny wynik to DF1, co da 3569 w kodzie dziesiętnym.
Proces wykonywany w asemblerze będzie identyczny.
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
Nasza pierwsza liczba zostanie zawarta w R6 oraz R7, natomiast druga w R4 i R5. Wynik dodawanie trafi do R1,R2 i R3. Nasz program będzie się składał z trzech następujących kroków:
1. Dodanie młodszych bajtów R7 i R5 – pozostawienie wyniku w R3.
2. Dodanie starszych bajtów z R6 i R4, z uwzględnieniem przeniesienia – pozostawienie wyniku w R2.
3. Umieszczenie przeniesienia z kroku 2, w ostatnim bajdzie R1.
Kod programu:
PROG SEGMENT CODE ;definiuje segment nazwie PROG w klasie pamięci CODE
Stala EQU 1000 ;1000(dec)=3E8(hex) . W celu odwołania się do interesującej nas części stałej używać będziemy operatora HIGH (starszy bajt) lub LOW (młodszy bajt)
DanaL DATA 20h ;przechowuje młodszy bajt wprowadzanej liczby DanaH DATA 21h ;przechowuje starszy bajt wprowadzanej liczby WynikL DATA 30h ;przechowuje młodszy bajt wyniku
WynikH DATA 31h ;przechowuje starszy bajt wyniku
CSEGAT 0 ;kod programu będzie umieszczony w jego pamięci począwszy od adresu „0” JMP start ;skok do miejsca oznaczonego etykietą start
RSEG PROG ;rozpoczyna segment, od którego, znajdujący się poniżej kod zostanie umieszczony w pamięci programu
;W oknie pamięci „Memory 1” zapisujemy nasze dane. Do komórki o adresie D:0x20 wpisujemy młodszy bajt pierwszej liczby, a tuż obok pod adres D:0x21 starszy bajt danej liczby.
start:
MOV A,DanaL ;skopiowanie wartości z komórki o adresie zastąpionym tekstem DanaL do akumulatora A. W zakładce „Sys” widzimy właśnie tę zmianę – wartość a=0x09.
ADD A,#low(Stala) ;dodaje do Akumulatora młodszy bajt ze stałej Stala. W zakładce „Sys” widzimy zmianę wartości a na 0xf1.
MOV WynikL,A ;skopiowanie wartości z akumulatora A do komórki o adresie zastąpionym tekstem WynikL. Komórka o adresie 0x30h przyjęła wartość F1.
MOV A,DanaH ;skopiowanie wartości z komórki o adresie zastąpionym tekstem DanaH do akumulatora A. W zakładce „Sys” widzimy właśnie tę zmianę – wartość a=0x0a.
ADDC A,#high(Stala) ;dodaje do Akumulatora starszy bajt ze stałej Stala. W zakładce „Sys” widzimy zmianę wartości a na 0x0d, z uwzględnieniem przeniesienia – czyli dodaniem wartości z flagi cy – w naszym przypadku zera.
MOV WynikH,A ;kopiowanie wartości z akumulatora A do komórki o adresie zastąpionym tekstem WynikH. Komórka o adresie 0x31h przyjęła wartość 0D. END ;zakończenie wykonywania programu
Po wykonaniu programu do końca, w komórkach o adresach od D:0x30 i D:0x31 zawarty zostanie wynik z dodawania.
Odejmowanie dwóch liczb 16-bitowych:
Rozkaz odejmowania SUBB (odjemna zawsze w akumulatorze, tam równie wynik) jest wykonywany zawsze z pożyczką której funkcję pełni flaga CY. Przy prostym odejmowaniu wartości jednobajtowych należy pamiętać o zmianie wartości flagi cy na „0” (wyzerowanie) .
16-bitowe odejmowane dwóch wartości 16-bitowych da w wyniku maksymalnie liczbę 16-bitową. Na przykład od 65535 odejmijmy 1 – otrzymamy wartość 16-bitową.
Dla przykładu rozważmy odejmowanie następujących dwóch wartości dziesiętnych: 5518 – 3219 = 2299. Najpierw przekształćmy wartości na kod szesnastkowy – 158E - C93.
|
|
|
|
|
|
|
|
|
|
|
|
Najpierw odejmujemy liczby z kolumny 1's (młodsze bajty): 8E – 93. Liczba 93 jest większa niż 8E, dlatego musimy „pożyczyć” z kolumny 256's jedynkę. Tak więc wykonamy odejmowanie 18E-93 = FB. Teraz wykonujemy odejmowanie 15-C. Musimy jednak pamiętać, że „pożyczyliśmy” jedynkę z tej kolumny. Tak więc mamy 15-C-1=8. Stąd nasza ostateczna odpowiedź to 8FB, czyli 2299 w kodzie dziesiętnym.
Proces wykonywany w asemblerze będzie identyczny.
|
|
|
|
|
|
|
|
|
|
|
|
Nasza pierwsza liczba zostanie zawarta w R6 oraz R7, natomiast druga w R4 i R5. Wynik odejmowania trafi do R2 i R3. Nasz program będzie się składał z dwóch następujących kroków:
1. Odjęcie młodszych bajtów R5 od R7, pozostawienie wyniku w R3.
2. Odjęcie starszych bajtów R4 od R6, uwzględnienie „pożyczki”, pozostawienie wyniku w R2.
Kod programu:
PROG SEGMENT CODE ;definiuje segment nazwie PROG w klasie pamięci CODE
L1L DATA 20h ;przechowuje młodszy bajt wprowadzanej liczby - odjemnej L1H DATA 21h ;przechowuje starszy bajt wprowadzanej liczby - odjemnej L2L DATA 22h ;przechowuje młodszy bajt wprowadzanej liczby - odjemnik L2H DATA 23h ;przechowuje starszy bajt wprowadzanej liczby - odjemnik WL DATA 30h ;przechowuje młodszy bajt wyniku
WH DATA 31h ;przechowuje starszy bajt wyniku
CSEGAT 0 ;kod programu będzie umieszczony w jego pamięci począwszy od adresu „0” JMP start2 ;skok do miejsca oznaczonego etykietą start 2
RSEG PROG ;rozpoczyna segment, od którego, znajdujący się poniżej kod zostanie umieszczony w pamięci programu
;W oknie pamięci „Memory 1” zapisujemy nasze dane. Do komórki o adresie D:0x20 wpisujemy młodszy bajt pierwszej liczby, a tuż obok pod adres D:0x21 starszy bajt danej liczby. Kolejną liczbę zapisujemy pod adresem D:0x22 – młodszy bajt i D:0x23 – starszy bajt.
start2:
MOVA,L1L;skopiowanie wartości z komórki o adresie zastąpionym tekstem L1L do akumulatora A. W zakładce „Sys” widzimy właśnie tę zmianę – wartość a=0x8e. CLR C ;ustawienie wartości flagi cy na „0” - wyzerowanie pożyczki
SUBB A,L2L ;odjęcie od wartości zapisanej w Akumulatorze wartość z komórki pamięci L2L . Jeżeli L2L>A to nastąpi pożyczka „1” z zewnątrz, co zostanie zasygnalizowane zmianą flagi cy na „1”. Wartość akumulatora A będzie równa 0xfb.
MOVWL,A ;kopiowanie wartości z akumulatora A do komórki o adresie zastąpionym tekstem WL. Komórka o adresie0x30h przyjęła wartość FB.
MOVA,L1H ;skopiowanie wartości z komórki o adresie zastąpionym tekstem L1H do akumulatora A. W zakładce „Sys” widzimy właśnie tę zmianę – wartość a=0x15. SUBB A,L2H ;odjęcie od wartości zapisanej w Akumulatorze wartość komórki pamięci
L2H. Jeżeli flaga cy jest ustawiona na „1”, to odejmowana jest także pożyczka wykonana przez poprzednie wywołanie odejmowania. Nastąpi wyzerowanie flagi cy. Wartość akumulatora A będzie równa 0x08.
MOVWH,A ;kopiowanie wartości z akumulatora A do komórki o adresie zastąpionym tekstem WH. Komórka o adresie 0x30h przyjęła wartość 08.
END ;zakończenie wykonywania programu
Po wykonaniu programu do końca, w komórkach o adresach od D:0x30 i D:0x31 zawarty zostanie wynik odejmowania.
Podczas pisania sprawozdania korzystałem z następujących pomocy: http://www.8052.com/add16
http://www.8052.com/subb16 http://staff.iiar.pwr.wroc.pl/antoni.sterna/lab_51/programowanie_51.pdf