WOJSKOWA AKADEMIA TECHNICZNA
Architektura i organizacja komputerów II
Sprawozdanie z pracy laboratoryjnej
Nr 1
Student : Adrian Kępa
Grupa : I3X6S1
Nr : 14
Data : 14.03.2014r.
[1] Rozkazy przesłań
a) LB – Load byte - rozkaz ten teoretycznie powinien przesłać jeden bajt
(8 bitów) z pamięci do podanego rejestru.
Kod programu:
.data
bajt_A: .byte 2
.text
lb r1, bajt_A
trap 0
Spodziewany wynik działania tego rozkazu to załadowanie bajtu "bajt_A" o wartości 2 do rejestru r1. W tym wypadku rozkaz został wykonany poprawnie, w rezultacie liczba 2 znalazła się w rejestrze r1.
Kod programu:
.data
bajt_A: .word 2
.text
lb r1, bajt_A
trap 0
W tym wypadku student przeoczył fakt, że zadeklarował "bajt_A" jako słowo a próbuje wykonać rozkaz LB – Load byte – służący do wczytania bajtu, nie słowa. W efekcie rejestr r1 pozostanie niezmieniony, rozkaz nie będzie wykonany.
b) SW – Store word - rozkaz ten teoretycznie powinien zapamiętać argument będący słowem w drugiej zmiennej.
Kod programu:
.data
liczba_A: .word 50
liczba_B: .space 0
.text
lw r1, liczba_A
sw liczba_B, r1
lw r2, liczba_B
trap 0
Powyższy program działa zgodnie z przewidywaniami. Na początku, zostaje wczytana wartość ze zmiennej "liczba_A" do rejestru r1. Potem przy użyciu rozkazu SW, zawartość rejestru r1 zostaje zapamiętana w zmiennej "liczba_B".
Na koniec na potrzeby sprawdzenia, przesyłam zmienną "liczba_B" do rejestru r2 w celu łatwego sprawdzenia działania programu. Rejestr r2 ma wartość 50, czyli tyle ile wartość zmiennej "liczba_B". Dowodzi to tego, że rozkaz przechowania słowa został poprawnie wykonany, słowo zostało zapamiętane w zmiennej "liczba_B".
Kod programu:
.data
liczba_A: .word 50
liczba_B: .space 0
.text
lw r1, liczba_A
sw liczba_B, r1
lw r2, liczba_B
trap 0
[2] Rozkazy arytmetyczne i logiczne
a) ADDI – Add immediate – w teorii, rozkaz ten do zawartości rejestru będącego drugim argumentem, dodaje liczbę i zapisuje w innym rejestrze tą sumę.
Kod programu:
.data
.text
addi r1, r0, #256
trap 0
Spodziewany przebieg działania tego rozkazu to dodanie liczby dziesiętnej 256 do zawartości rejestru r0 (zawsze 0) i zapisanie wyniku w rejestrze r1 czyli w rejestrze r1 powinna znajdować się liczba 256. W tym wypadku praca programu przebiega pomyślnie, do rejestru r1 zostaje przesłana liczba 256.
Kod programu:
.data
.text
addi r0, r1, #256
trap 0
Program nie zostanie wykonany zgodnie z przewidywaniem gdyż autor pomylił kolejność dwóch pierwszych argumentów lub poprostu nie zdaje sobie sprawy z tego, że nie da się zmienić wartości rejestru r0. Pierwszy argument rozkazu ADDI jest miejscem do którego należy zapisać sumę - w tym przypadku zawartości r1 + 256(dec) lecz suma ta nigdy nie znajdzie się w rejestrze r0.
Próba wykonania programu powoduje również pojawienie się ostrzeżenia informującego nas o tym, iż rejest r0 został użyty jako miejsce zapisu sumy zawartości rejestru r1 i 256.
b) AND – Rozkaz obliczający iloczyn logiczny dwóch argumentów.
Kod programu:
.data
.text
addi r1, r0, #1
addi r2, r0, #0
and r3, r1, r2
trap 0
Na początku "sztucznie" wypełniono rejestry r1 i r2 nadając im początkowe wartości 1 i 0. Program zadziałał zgodnie z przewidywaniami. Rozkaz AND sprawdził czy obydwa argumenty – zawartości rejestrów r1 i r2 – mają wartość logiczną "prawda". Tak nie jest, dlatego też zgodnie z działaniem rozkazu iloczynu logicznego AND w rejestrze przeznaczonym na zapis wyniku – r3, znajdzie się 0.
Dla wartości rejestrów ze zbioru {0,1} rozkaz zachowuje się zgodnie z przewidywaniami. Natomiast dla innych liczb, w rejestrze wynikowym nie znajdzie się wartość logiczna 0 lub 1, tylko normalna liczba często różniąca się od 0 i 1. Nie jestem pewien czemu taka sytuacja ma miejscę. Zdawało mi się, że liczba w rejestrach > 0 zostanie potraktowana poprostu jako logiczna prawda.
[3] Rozkazy skoków
a) BEQZ – Branch GPR equal to zero – Rozkaz sprawdza, czy zawartość rejestru podanego jako argument jest równa zero. Jeśli tak to wykonuje skok do etykiety podanej jako drugi argument a w przeciwnym wypadku nic nie robi. Pozwala to "omijać" wykonywanie pewnych partii kodu w sytuacjach gdy tego potrzebujemy.
Kod programu:
.data
num_A: .word #5
num_B: .word #10
num_C: .word #0
.text
lw r1, num_A
lw r2, num_B
lw r3, num_C
beqz r3, objazd
add r4, r1, r2
objazd:
trap 0
Program zostanie wykonany zgodnie z przewidywaniami. Rozkaz beqz zostaje wykonany pomyślnie, przyrównuje zawartość rejestru r3 do 0. Przyrównanie to zwraca wartość logiczną więc wykonany zostaje skok do etykiety "objazd" co powoduje z kolei pominięcie rozkazu dodawania ADD. Dla dodatkowego sprawdzenia czy rzeczywiście rozkaz ADD nie został wykonany, sprawdzam, że wartość rejestru r4 zostaje nadal równa zero.
W wypadku gdy słowo "num_C" jest różne od zera, zostaje później wczytane do rejestru r3, który to będzie warunkował wykonanie lub nie, rozkazu skoku warunkowego. W przypadku różności od zera, wykonane zostanie dodawanie add zawartości rejestrów r1 i r2. Zatem spodziewany wynik to liczba 15 w rejestrze r4 i tak dzieje się w rzeczywistości.
b) Trap – Wynikiem działania tego rozkazu jest przekazanie sterowania do systemu.
Kod programu:
.data
.text
trap 0
Przewidujemy, że program zostanie wykonany i efektem będzie pomyślne zakończenie. Tak też się dzieję, gdyż trap z argumentem 0 służy do zakończenia programu.
Kod programu
.data
.text
trap 4
W tym przypadku student zapewne chciał wpisać trap 5 lub trap 3 lecz niestety wpisał liczbę pomiędzy. Efektem tego będzie poprawna kompilacja programu, lecz po uruchomieniu, nigdy się on nie zakończy(tzn, będzie działał tak długo jak pozwolą na to zasoby komputera)
[4] Rozkazy zmiennoprzecinkowe
a) SUBF – Subtract single precision float – Zadaniem tego rozkazu jest wykonanie różnicy na dwóch liczbach typu float i zapisanie wyniku w rejestrze.
(W tym przypadku wykorzystujemy rejestry dla liczb zmiennoprzecinkowych)
Kod programu:
.data
liczba_1: .float 8.30
liczba_2: .float 2.20
.text
lf f1, liczba_1
lf f2, liczba_2
subf f3, f1, f2
trap 0
Powyższy program działa zgodnie z przewidywaniami. Rozkaz SUBF zostaje wykonany poprawnie, jego zadaniem jest odjęcie zawartości rejestru f2 od zawartości rejestru f1. Wynikiem tego działania jest 6.1 i taka też liczba zostaje przesłana do rejestru wynikowego f3.
Kod programu:
.data
liczba_1: .float 8.30
liczba_2: .float 2,20
.text
lf f1, liczba_1
lf f2, liczba_2
subf f3, f1, f2
trap 0
Powyższy przypadek ilustruje jak duże konsekwencje może mieć drobna literówka. Student pomylił się i zamiast użyć kropki do oddzielenia części całkowitej liczby od jej części ułamkowej, użył przecinka.
Efektem jest brak wyniku w rejestrze wynikowym f3, ponadto w rejestrze f2 do którego została wczytana błędnie zadeklarowana wartość rejestru, wczytane zostało tylko 2. Świadczy to o tym, że część ułamkowa po przecinku została w tym przypadku pominięta.
b) GEF – Greater or equal float – Rozkaz ten porównuje wartości rejestrów które podane są mu jako argumenty. Jeżeli pierwszy rejestr jest większy lub równy od wartości drugiego rejestru to rejestr FPSR zostaje ustawiony na 1.
Kod programu:
.data
num_1: .float 9.0
num_2: .float 2.0
.text
lf f1, num_1
lf f2, num_2
gef f1, f2
trap 0
Program działa w sposób przewidywalny. Rozkaz porównania GEF ustawi flagę FPSR na 1 gdyż zawartość rejestru f1 jest w tym przypadku większa od wartości rejestru f2.
W przypadku gdyby pierwszy argument rozkazu GEF nie był większy lub równy drugiemu argumentowi, rejestr FPSR pozostanie zerem.
Wnioski
Przy pisaniu programów do użytku w programie WinDLX należy zwracać uwagę na specyficzną składnię języka. Należy nauczyć się, że do oddzielenia części całkowitej od części ułamkowej liczb używamy kropki a nie przecinka. Trzeba także zwracać uwagę na poprawną kolejność argumentów w rozkazach oraz także wiedzieć czego się spodziewać po wykonaniu każdego rozkazu, gdzie szukać wyników jego pracy.