You are on page 1of 7

Janusz Paszyński 16.01.

2008
I6Y1S1

Architektura Systemów
Komputerowych
Sprawozdanie z zajęć Laboratoryjnych
Temat: Hazardy danych. Przykłady hazardów RAW.
1. Zadanie
Na podstawie biblioteki input.s zaprojektować (algorytm, opis) i zaimplementować dla
komputera WinDLX moduł in.s, zawierający procedurę czytaj, która będzie wykonywać
poprawne wczytywanie liczby całkowitej, ewentualnie poprzedzonej znakiem „+” lub „ – „.
Zaprojektować (algorytm, opis) i zaimplementować program Osiem.s, który:

a. przy wykorzystaniu procedury czytaj wypisze komunikat „1 liczba calkowita (moze byc
ze znakiem) =„ i wczyta pierwszą z pięciu liczb całkowitych jako danych wejściowych do
programu.

b. Kolejno wypisze komunikat jak w punkcie 2a, zwiększając kolejno numer wczytywanej
liczby całkowitej i wczyta przy wykorzystaniu procedury czytaj kolejne 4 liczby całkowite ze
znakiem. Wczytane liczby mają być przechowane w zmiennych typu .word o nazwach tab1,
tab2 ... tab5 (uwaga: nie w rejestrach GPR). Wartości liczb zostaną na zajęciach podane
przez prowadzącego.

c. Student(/ka) samodzielnie przygotuje pokaz uruchomienia programu z ustawieniem


breakpointa tak, aby w okienku podglądu zawartości pamięci operacyjnej można było
sprawdzić, czy wszystkie wczytane liczby rzeczywiście są poprawnie wczytane,
przekonwertowane i zapamiętane.

2. Algorytm procedury czytaj


1. wypisz zachętę
2. pobierz do R14 adres struktury do zapisania pobranego ciągu
3. pobierz ciąg z klawiatury poprzez TRAP 0
4. załaduj do R2 adres pierwszego znaku w buforze
5. załaduj do R3 pierwszy znak
6. wykonaj R3 xor 43 wynik do R6
7. jeśli R6 jest 0 skocz do ‘12’
8. wykonaj R3 xor 45 wynik do R6
9. jeśli R6 jest 0 skocz do ‘11’
10. jeśli R6 nie zero skocz do ‘13’
11. załaduj do R6 -1
12. wykonaj R2 + 1 wynik do R2
13. załaduj do R3 bajt spod adresu z R2
14. porównaj R3 z 10 wynik do R5
15. jeśli R5 nie jest 0 skocz ‘21’
16. odejmij R3 kod znaku ‘0’, wynik do R3
17. pomnóż R1 razy 10, wynik do R1
18. dodaj R3 do R1, wynik do R1
19. zwiększ R2 o 1, wynik do R2
20. skocz do ‘13’
21. wykonaj R6*R6 i wynik do R6
22. wykonaj R6 xor 1, wynik do R6
23. jeśli R6 nie jest 0 skocz do ‘26’
24. załaduj do R6 -1
25. pomnóż R1 razy R6, wynik do R1
26. skocz do adres z R31

Kod zapisanego powyżej algorytmu z uwzględnieniem zachowania stanu rejestrów R2-R6 na


czas wykonania algorytmu:

.data
ReadBuffer: .space 80
ReadPar: .word 0,ReadBuffer,80

PrintfPar: .space 4

SaveR2: .space 4
SaveR3: .space 4
SaveR4: .space 4
SaveR5: .space 4
SaveR6: .space 4

.text

.global czytaj
czytaj:
sw SaveR2,r2
sw SaveR3,r3
sw SaveR4,r4
sw SaveR5,r5
sw SaveR6,r6

sw PrintfPar,r1
addi r14,r0,PrintfPar
trap 5

addi r14,r0,ReadPar
trap 3

addi r2,r0,ReadBuffer
addi r1,r0,0
addi r4,r0,10 ;Decimal system

lbu r3,0(r2)
xor r6,r3,43
beqz r6,gotuj
xor r6,r3,45
beqz r6,ujemna
bnez r6,Loop
ujemna:
addi r6,r0,-1
gotuj:
addi r2,r2,1
add r1,r1,r3
addi r2,r2,1 ;increment pointer
j Loop

Finish: mult r6,r6,r6


xor r6,r6,1
bnez r6,dalej
addi r6,r0,-1
mult r1,r1,r6
dalej:
lw r2,SaveR2
lw r3,SaveR3
lw r4,SaveR4
lw r5,SaveR5
jr r31 ; Return

3. Program realizujący zadanie


Dzięki wykorzystaniu zewnętrznej procedury ‘czytaj’ program jest krótki i zawiera tylko
jedną pętlę.

Deklaracja danych:
.data
licz: .byte 1
text: .asciiz " liczba calkowita (moze byc ze znakiem) ="
tab1: .word 1
tab2: .word 1
tab3: .word 1
tab4: .word 1
tab5: .word 1

W programie użyty został wyłącznie jeden napis, którego treść jest stała. Przed nim jednak
znajduje się liczba zmieniana iteracyjnie. Do jej zapisania wykorzystany zostaje jeden bajt
przed statycznym napisem. W ten sposób zmienne ‘licz’ i ‘text’ tworzą jedną wiadomość dla
użytkownika – promet. Zadeklarowane dalej zmienne tab1-tab5 typu word to kolejne komórki
tablicy przeznaczone na zapisanie przyjętych liczb.

segment kodu:
.text
.global main
main:
addi r8,r0,1
addi r2,r0,tab1
loop:
addi r9,r8,48
xor r7,r8,5
sb licz,r9
addi r1,r0,licz
jal czytaj
sw 0(r2),r1
addi r8,r8,1
addi r2,r2,4
bnez r7,loop
nop
koniec:
trap 0

Pierwsze dwie linie kodu odpowiadają za przygotowanie pierwszego znaku prometu. Na


początek do R8 ładowana jest cyfra 1. Następnie do R2 zostaje załadowany adres pierwszej
komórki tablicy przeznaczonej do przechowywania pobranych liczb.

Pętla, zaczynająca się od etykiety ‘loop’, zawiera na początku operację konwersji cyfry z R8
na jej kod ASCII. Jest to wykonane poprzez dodanie do niej kodu cyfry ‘0’, wynoszącego 48.
Wynik zostaje zapisany do R9. Konwersja w ten sposób jest możliwa dzięki temu, że znaki w
tablicy ASCII są pogrupowane. Następnie r8 zostaje porównany z liczbą 5, co jest warunkiem
dozoru pętli. Jest to wykonane poprzez funkcję logiczną xor, zaś jej wynik zostaje zapisany
do R7. Następnie zapisujemy bajt do zmiennej licz z rejestru R9. Po tych operacjach jest
gotowy prompt.

Procedura czytaj jest wywoływana poprzez skok ze śladem do etykiety ‘czytaj’, która jest
zadeklarowana jako ‘.global’. Przed jej wywołaniem należy przygotować w rejestrze R1 adres
tekstu do wyświetlenia jako prompt. W przeciwieństwie do wywołania TRAP 3 czytaj
przyjmuje adres bezpośrednio do bufora, a nie do ‘pojemnika’ z buforem. Przyjmuje więc
bezpośredni adres. W przypadku tego programu do procedury czytaj wysyłamy nie adres
tekstu statycznego, ale adres o 1 mniejszy w celu wysłania także iteratora.

Po powrocie z procedury ‘czytaj ‘ słowo spod R1 zapisujemy do tabeli. Adres do aktualnie


pustej komórki tabeli przechowywany jest w R2. Po zapisaniu słowa poprzez SW (store
word) zwiększamy iterator (R8) o 1, oraz adres komórki w tabeli(R2) o 4 (długość słowa
maszynowego DLX).
Na koniec pętli zostaje wykonany test R7. Jeśli nie jest 0 wykonujemy następny przebieg
pętli.

Powyższy program przypomina program w języku wysokopoziomowym z wykorzystaniem


pętli do…while.
4. Wynik uruchomienia
W wyniku uruchomienia uzyskujemy:

Dla wpisanych powyżej danych po zakończeniu programu zawartość pamięci w obszarze


danych programu:
Wydaje się, że wartości w komórkach nie odpowiadają rzeczywistości. Komputer DLX
używa kodu uzupełnieniowego do 2 do kodowania liczb w pamięci, zaś w podglądzie liczby
te są dekodowane jako liczby bez znaku. W wyniku tego w pamięci pozornie nie ma ani
jednej liczby ujemnej.

5. Forwarding i hazardy danych typu RAW, a liczba cykli


Liczba cykli w programie komunikującym się z użytkownikiem (jak powyższy) jest zależna
od danych wejściowych. Jest możliwe jednak oszacowanie górnej i dolnej granicy cykli.

Przy wyłączonym forwardingu program został wykonany w ciągu 501 cykli dla liczb: 1,4,-
1,+2,-500. W programie wystąpiło wstrzymanie z powodu hazardu RAW w sumie na 174
cykli, co oznacza w sumie 34.73% wszystkich cykli. Znaczna strata wynika z faktu, że
mnożenia zostały wykonane wewnątrz jednostki zmiennopozycyjnej, na której występuje
opóźnienie 5ciu cykli.

Przy włączonym forwardingu program został wykonany w ciągu 418 cykli. W programie
wystąpiło wstrzymanie z powodu hazardów RAW w sumie na 128 cykli, co stanowi 30.62%
wszystkich cykli.

Po włączeniu forwardingu program został wykonany szybciej o około 17%. Jest to jednak test
tylko dla jednego zestawu przypadkowych danych. Konieczne byłoby wykonanie większej
liczby testów, aby stwierdzić jak bardzo może zostać przyspieszony ten program po
włączeniu forwardingu.

6. Wnioski
Program z włączonym forwarding’iem jest bez wątpienia szybszy. Nie jest to jednak jedyna
metoda przyspieszenia algorytmu. Mimo tego, że większość operacji stałopozycyjnych jest
wykonywana w ciągu 5ciu cykli, to jednak niektóre wykonywane są w taki sam sposób i z
takimi samymi opóźnieniami co przy liczbach zmiennopozycyjnych. Oznacza to, że można
zoptymalizować program zmieniając część wymagających działań na inne, lub zmieniając ich
kolejność.

Istotne jest także, aby umieszczać jak najmniej instrukcji skoków, ponieważ jeśli skok będzie
efektywny konieczne jest opróżnienie całego potoku. Od razu widać, że bardzo częste skoki
wykonywane prawie jeden po drugim znacznie zmniejszają wydajność programu, aczkolwiek
zyskują na efektywności.

You might also like