Układ sterujący (część 2)
1
Przedmioty prowadzone w ramach
Programu Rozwoju WSFiZ w Białymstoku realizowane są w ramach
Programu Operacyjnego Kapitał Ludzki, Priorytet IV Szkolnictwo wyższe i nauka, Poddziałanie 4.1.1
Wzmocnienie potencjału dydaktycznego uczelni, współfinansowanego ze środków
Europejskiego Funduszu Społecznego (POKL.04.01.01-00-030/08)
8.
Układ sterujący (część 2)
Spis treści
8.4
Przykłady
Aby zaprezentować przykładową sekwencję mikrorozkazów pamiętanych w pamięci sterującej
przyjmiemy pewien możliwie prosty model procesora. Dla tego modelu podamy listę wszystkich
możliwych sygnałów sterujących i posługując się nimi spróbujemy utworzyć sekwencję
mikrorozkazów realizujących kilka kluczowych fragmentów cyklu rozkazowego procesora.
Przyjmijmy zatem, że procesor wygląda tak, jak został opisany w rozdziale 7, z tą różnicą, że
ma on tylko 4 rejestry ogólnego przeznaczenia (R0 – R3) oraz ALU, które jest w stanie wykonać
16 operacji. Z ALU współpracuje 1 akumulator oznaczany dalej jako ACC. Posiada ponadto
rejestry: PC, IR, PSW, MAR, MDR. Numery rejestrów Ri (i=1..3) będą kodowane na 2 bitach, a
numery rozkazów dla ALU na 4, co zakłada użycie 2 dekoderów (pierwszy, nazywany 2/4 – 2
wejścia, 4 wyjścia; drugi: 4/16 – 4 wejścia, 16 wyjść). Do opisu jego działania potrzebne będą
następujące mikrooperacje (w pierwszej kolumnie, dla każdej operacji wypisane są numery bitów
odpowiadających w słowie sterującym za dokładnie tą mikrooperację):
Bity
mikrooperacje
1-2
zakodowany numer rejestru ogólnego przeznaczenia
3
rejestr ogólnego przeznaczenia: czytaj
4
rejestr ogólnego przeznaczenia: ładuj
5
IR ładuj
6
IR czytaj
7
PC ładuj
8
PC czytaj
9
MDR ładuj
10
MDR czytaj
11
MAR ładuj
Układ sterujący (część 2)
2
Bity
mikrooperacje
12
Zaczekaj na pamięć
13-16
kod operacji ALU
17
Pamięć czytaj
18
Pamięć pisz
19
Zwiększ zawartość PC
20
ACC czytaj
21
ACC ładuj
Tak więc, potrzebna jest nam 21-bitowa pamięć i słowo sterujące. Na rysunku 8.10 (patrz niżej)
pokazany jest schemat procesora, który będzie używany w dalszej części wykładu. Czerwone
linie symbolizują linie sygnałowe, czarne – przepływ wszystkich pozostałych informacji.
Spróbujmy użyć opisanego modelu procesora i listy mikrooperacji do opisania fazy pobrania
rozkazu. Składa się ona z następujących kroków:
1. Umieść zawartość PC na szynie (PC: czytaj);
2. Wyślij do pamięci rozkaz: czytaj;
3. Zwiększ zawartość PC;
4. Zaczekaj na pamięć, aż wykona rozkaz;
5. Umieść zawartość MDR na szynie (MDR: czytaj) i załaduj z niej IR (IR ładuj).
IR
ACC
pamięć
Układ
zrobione
sterowania
ALU
PC
PSW
MAR
do/z pamięci
MDR
Rejestry ogólnego
przeznaczenia
Rysunek 8.10. Schemat procesora używany w przykładach z rozdziału 8.
Układ sterujący (część 2)
3
Zawartość pamięci sterującej odpowiadająca wymienionym czynnościom pokazana jest poniżej;
dla łatwiejszego odczytu 21 bitów pogrupowano po 4, ostatnia grupa liczy ich 5.
1
5
9
13
17 21
0000 0001 0010 0000 00000
PC → MAR
0000 0000 0000 0000 10000
pamięć: czytaj
0000 0000 0000 0000 00100
zwiększ PC
0000 0000 0001 0000 00000
zaczekaj na pamięć
0000 1000 0100 0000 00000
MDR → IR
Analiza powyższych zapisów wskazuje, że niektóre mikrooperacje można pogrupować w jednym
słowie sterującym zmniejszając tym samym rozmiar zużytej pamięci. I tak dla fazy pobrania
sekwencja może być skrócona do 3 mikrorozkazów:
1
5
9
13
17 21
0000 0001 0010 0000 10000
PC → MAR;
pamięć: czytaj;
0000 0000 0001 0000 00100
zwiększ PC;
zaczekaj na pamięć;
0000 1000 0100 0000 00000
MDR → IR
Jako przykład rozważmy realizację prostego rozkazu ‘dodaj’ (mnemonik: ADD) w kontekście
dodania zawartości rejestrów R1 i R2 i zapisania wyniku w rejestrze R3. Zgodnie z
wcześniejszymi ustaleniami dotyczącymi pracy ALU układ sterowania spowoduje dodanie
zawartość akumulatora do liczby będącej na szynie i zapamięta wynik w akumulatorze. A oto
kompletna lista kolejnych kroków:
1. Umieść zawartość R1 na szynie (R1: czytaj) i załaduj z niej akumulator (ACC: ładuj);
2. Umieść zawartość R2 na szynie i prześlij do ALU rozkaz „dodaj”;
3. Umieść zawartość akumulatora na szynie (ACC: czytaj) i załaduj z niej R3.
Odpowiadająca liście sekwencja mikrorozkazów (załóżmy, że kod ADD jest 0001):
1
5
9
13
17 21
0110 0000 0000 0000 00001
R1 → ACC;
1000 0000 0000 0001 00000
R2 na szynę;
ALU: ADDW
1101 0000 0000 0000 00010
ACC → R3
Logicznym zakończeniem tej serii przykładów będzie pokazanie sekwencji mikrorozkazów
zapamiętującej zawartość rejestru R3 pod adresem przechowywanym w rejestrze R0. Tak jak
poprzednio pokażemy najpierw listę kroków:
1. Umieść zawartość R0 na szynie (R0: czytaj) i załaduj z niej MAR (MAR: ładuj);
2. Umieść zawartość R3 na szynie (R3: czytaj) i załaduj z niej MDR (MDR: ładuj); Wyślij do
pamięci rozkaz: pisz; Zaczekaj na pamięć, aż wykona rozkaz;
Odpowiadająca liście sekwencja mikrorozkazów:
Układ sterujący (część 2)
4
1
5
9
13
17 21
0010 0000 0010 0000 00001
R0 → MAR;
1110 0000 1001 0000 01100
R3 → MDR;
pamięć: pisz;
zwiększ PC;
zaczekaj na pamięć;
8.5 Skoki w mikroprogramach
Wydaje się zupełnie oczywiste, że jeżeli w pamięci sterującej występują powtarzające się
sekwencje mikrorozkazów, to należy wprowadzić rozwiązania, które pozwoliłyby aby taka
sekwencja pamiętana była tylko raz. Dobrym przykładem jest sekwencja pobierania kolejnego
rozkazu z pamięci operacyjnej omówiona w poprzednim podrozdziale.
Wchodzi ona w skład każdego cyklu rozkazowego, a więc pamiętanie jej tylko raz powinno
wydatnie zmniejszyć ilość zużytej pamięci. W związku z tym pożądana struktura pamięci
sterującej powinna być taka jak na rysunku 8.11 (patrz niżej).
Sięgnij po następny rozkaz
3
1
BNEQ
ADDW2
2
MOVL
Rysunek 8.11. Położenie sekwencji różnych rozkazów w pamięci sterującej.
Szare prostokąty obrazują miejsca przechowywania ciągów mikrooperacji realizujących
przykładowe rozkazy procesora oraz sekwencję pobierającą kolejny rozkaz z pamięci
operacyjnej. Jej umiejscowienie na początku pamięci sterującej jest również przykładowe. Liczby
w kółkach numerują kolejne etapy wykonywania fragmentu programu składającego się np. z
dwóch kolejnych instrukcji: ADDW2 i MOVL. Przeanalizujmy szczegóły realizacji tych etapów.
Rozpoczynamy od sięgnięcia po następny rozkaz. Kolejne mikrorozkazy tej sekwencji
wskazywane są przez μPC, którego zawartość zwiększana jest każdorazowo o 1. Na końcu tej
sekwencji widomo, że kolejnym rozkazem jest ADDW2. W tym momencie niezbędny jest skok
do tego adresu w pamięci, gdzie znajduje się pierwszy mikrorozkaz z sekwencji realizującej
ADDW2 (etap 1 na rysunku 8.11). Po wykonaniu tego rozkazu konieczny jest skok do adresu
rozpoczynającego sekwencję pobierania kolejnego rozkazu (etap 2 na rysunku 8.11). Po jej
Układ sterujący (część 2)
5
wykonaniu wiadomo, że jest to rozkaz MOVL, stąd skok (etap 3 na rysunku 8.11) do tego adresu
w pamięci, gdzie znajduje się pierwszy mikrorozkaz z sekwencji realizującej MOVL.
Obraz ten można komplikować dalej chociażby przez uwzględnienie sekwencji mikroinstrukcji
zapamiętujących obliczony wynik w pamięci operacyjnej jako sekwencji wydzielonej. Skok do
niej wykonywany by był po każdej instrukcji, która po wykonaniu obliczeń chciałaby zapamiętać
wynik w pamięci. Ona sama (omawiana sekwencja) kończyłaby się skokiem do adresu
rozpoczynającego sekwencję pobierania kolejnego rozkazu.
Skoki realizowane w obu sekwencjach (pobierania kolejnego rozkazu i zapamiętywanie
wyniku w pamięci) są przykładami skoków bezwarunkowych pod adres, który może „wskazać”
jedynie właśnie wykonywana mikroinstrukcja. Tylko na jej poziomie znajduje się wiedza o
kontekście (np. czy to jest ostatnia mikroinstrukcja w sekwencji). Oznacza to, że należy
przewidzieć możliwość pamiętania w mikroinstrukcji adresu kolejnej mikroinstrukcji.
Inna jest sytuacja wtedy, kiedy należy skoczyć pod adres mikroinstrukcji rozpoczynającej ciąg
realizujący kolejny rozkaz procesora. Taki adres dostarcza GAP, który ma zapisane początkowe
adresy mikroinstrukcji wszystkich instrukcji procesora. Jest to również skok bezwarunkowy.
Aby móc realizować nieco bardziej złożone algorytmy należy również zaimplementować
możliwość wykonywania skoków warunkowych. Wystarczy przypomnieć sobie np. algorytmy
mnożenia liczb całkowitych, w których kolejne kroki warunkowane były wartością określonych
bitów.
Aby spełnić wszystkich wspomniane wymagania do słowa sterującego dodano cały szereg
bitów zgrupowanych w dwa pola: pole wyboru warunku i pole następnego adresu. Pierwsze z
nich składa się z dwóch bitów, oznaczanych przez s
0
i s
1
co pozwala zakodować cztery różne
sytuacje:
s
0
s
1
Akcja
0 0
Zwiększ μPC o 1 (standardowy wybór następnego mikrorozkazu)
0 1
Skocz do następnego adresu o ile spełniony jest warunek
1 0
Skocz do adresu wskazanego przez GAP
1 1
Skocz bezwarunkowo do następnego adresu
Określenie „następny adres” oznacza adres zapisany w polu następnego adresu. Warunek
oznacza pewien zewnętrzny w stosunku do układu sterowania warunek. Zostanie on
sprecyzowany za chwilę.
Na rysunku 8.12 (patrz niżej) pokazano schemat układu sterowania, w którym uwzględnione są
możliwości wynikające z istnienia dodatkowych pól w słowie sterującym (na oznaczenie
multipleksera użyto skrótu MPLX).
Pogrubione szare linie symbolizują jednoczesne przesyłanie tylu bitów, ile liczy sobie słowo
sterujące. Cienkie linie przesyłają pojedyncze bity.
Układ sterujący (część 2)
6
GAP
Następny adres
1
0
MPLX1
0 0
M
P 1 warunek
μPC
Zwiększ/Ładuj
L
0 1
X 2 1
2
3 1
Pamięć sterująca
Słowo sterujące
s
0
s
1
...
Sygnały sterujące
Rysunek 8.12. Układ sterowania uwzględniający pole następnego adresu.
Zwróćmy uwagę na mikrolicznik programu μPC
.
Dochodzi do niego sygnał sterujący
Zwiększ/Ładuj (Zwiększ = 0; Ładuj = 1), który wyznacza tryb działania licznika. W trybie
„Zwiększ” licznik działa w tzw. trybie inkrementacji, czyli po każdej mikrooperacji zwiększa
swoją wartość o 1 wskazując adres następnej mikrooperacji. Jest to standardowy sposób jego
działania. W trybie „Ładuj” przechowywany w nim adres ładowany jest z multipleksera MPLX1,
który działa tu jako selektor całej grupy bitów. W zależności od sterowania może on przepuścić
na swoje wyjście albo adres pochodzący z Generatora Adresu Początkowego GAP albo adres
pochodzący z pola następnego adresu bieżącego słowa sterującego.
Rozważmy każdą z 4 sytuacji odpowiadającym różnym kombinacjom wartości s
0
i
s
1
:
1. s
0
s
1
= 00. Multiplekser MPLX2 przenosi na swoje wyjście sygnał z wejścia nr 0. Jego zerowa
wartość powoduje, że μPC działa w trybie inkrementacji. W rezultacie z pamięci sterującej
wybierana jest kolejna mikroinstrukcja.
2. s
0
s
1
= 01. Multiplekser MPLX2 przenosi na swoje wyjście warunek (jego wartość może być
„fałsz” czyli 0 lub „prawda” czyli 1). Ponieważ s
1
= 1 to multiplekser MPLX1 wysterowany
jest tak, że przenosi na swoje wyjście adres określony przez pole następnego adresu w
bieżącym słowie sterującym. W rezultacie, jeżeli warunek jest prawdziwy, to μPC będzie
załadowany z pola następnego adresu i do tego adresu zostanie wykonany skok. Jeżeli
Układ sterujący (część 2)
7
natomiast warunek nie jest prawdziwy, to μPC będzie działał w trybie inkrementacji i
zostanie wybrana następna mikrooperacja.
3. s
0
s
1
= 10. Multiplekser MPLX2 przenosi na swoje wyjście sygnał z wejścia nr 2. Jego
wartość 1 powoduje, że μPC działa w trybie „Ładuj”. Jednocześnie s
1
= 0 wysterowuje
multiplekser MPLX1 w ten sposób, że przenosi on na swoje wyjście adres z GAP. W
rezultacie wykonany zostaje bezwarunkowy skok do mikrooperacji wskazanej przez adres
pochodzący z GAP.
4. s
0
s
1
= 11. Multiplekser MPLX2 przenosi na swoje wyjście sygnał z wejścia nr 3. Jego wartość
1 powoduje, że μPC działa w trybie „Ładuj”. Ponieważ s
1
= 1 to multiplekser MPLX1
wysterowany jest tak, że przenosi na swoje wyjście adres określony przez pole następnego
adresu w bieżącym słowie sterującym. W rezultacie wykonany zostaje bezwarunkowy skok
do mikrooperacji wskazanej przez adres pochodzący z pola następnego adresu.
Dodanie dwóch nowych grup bitów wymaga uporządkowania numeracji bitów w słowie
sterującym. Załóżmy, że pamięć sterująca ma 1K słów, co oznacza, że jej adresy liczą 10 bitów.
Ustalmy, że pole następnego adresu zajmie bity 22 – 31, a pole wyboru warunku bity 32 i 33. Np.
mikroinstrukcja umieszczająca na szynie zawartość rejestru R3 i wyznaczająca mikroinstrukcję
pamiętaną pod adresem 251 = (0011111011)
2
jako następną mikroinstrukcję wygląda
następująco:
1 5 9 13 17 22 32
↓ ↓ ↓ ↓ ↓ ↓ ↓
1110 0000 0000 0000 00000 0011111011 11
Inny przykład: oto mikroinstrukcje realizujące rozkaz MOVW (R2), R3 przy założeniu, że
sekwencja sięgnięcia po następny rozkaz rozpoczyna się od adresu 5 = (0000000101)
2
:
1010 0000 0011 0000 10000 0000000000 00
(R2 na szynę, załaduj MAR, pamięć czytaj, zaczekaj na pamięć)
1101 0000 0100 0000 00000 0000000101 11
(MDR na szynę, załaduj R3, załaduj 5 do μPC).
Znajomość adresu sekwencji sięgnięcia po następny rozkaz była konieczna, bo po realizacji
rozkazu MOVW należy sięgnąć po kolejny rozkaz.
8.6
Implementacja skoków warunkowych
W multiplekserze MPLX2 na rysunku 8.12 (patrz wyżej) wejście nr 2 zostało określone jako
„warunek”. Funkcjonowanie tego warunku zostało omówione w punkcie 2 dla bitów pola wyboru
warunku s
0
s
1
= 01. Teraz zajmiemy się naturą owego warunku: skąd on pochodzi i jaki jest jego
związek z rozkazami procesora.
Zaczniemy od uwagi, że w rozdziale 7.5 Wybrane instrukcje wymieniono całą grupę instrukcji
skoków. Wszystkie one uzależnione były od wartości bitów N, Z, V i C słowa stanu programu
PSW. Przypomnijmy, że bity te – nazywane flagami – oznaczają odpowiednio: wynik ujemny,
wynik zerowy, nadmiar i przeniesienie, przy czym każda z wymienionych sytuacji dotyczy
ostatnio wykonanej operacji ALU. Nie powinno więc być zaskoczeniem, że nasz „warunek”
będzie definiowany jako wystąpienie 0 lub 1 właśnie na wymienionych bitach. Ponieważ w
prezentowanej tu, uproszczonej implementacji układu sterowania jesteśmy w stanie uwzględnić
Układ sterujący (część 2)
8
tylko 1 warunek, to najprostszym rozwiązaniem jest wybór jednej z flag przy pomocy
dodatkowego multipleksera o 4 wejściach (po jednym dla każdej z flag) i dwóch wejściach
sterujących a
0
i a
1
. Na rysunku 8.13 zaprezentowano połączenie multipleksera MPLX2 układu
sterowania z dodatkowym, trzecim z kolei, multiplekserem wyboru flagi MPLX3 i z tym
fragmentem słowa stanu programu, gdzie znajdują się flagi N, Z, V i C.
MPLX3
fragment PSW
MPLX2
0
N
0
1
Z
1
Warunek
2
V
2
3
C
3
a
0
a
1
s
0
s
1
Rysunek 8.13. Układ łączący flagi PSW z „warunkiem” w układzie sterowania
Bity a
0
i a
1
definiują kolejne pole, które musimy dodać do słowa sterującego (nazywamy je
polem wyboru flagi). Przypiszmy im numery 34 i 35 (są to numery kolejnych wolnych bitów).
Zgodnie z sugestią zawartą na rysunku 8.13 będą one wybierać flagi zgodnie z następującą
tabelą:
a
0
a
1
Flaga
0 0
N
0 1
Z
1 0
V
1 1
C
W rozdziale 7.6 Tryby adresowania został opisany format rozkazu skoku. Układ kolejnych
bajtów w pamięci operacyjnej, na których zapisano ten rozkaz wygląda tak, jak na rysunku
poniżej:
Kod rozkazu skoku
Tryb adresowy
Przesunięcie adresu
docelowego
Dla przykładu przyjmijmy, że rozważanym rozkazem jest BEQL, który wykonuje skok, jeżeli
ustawiona jest flaga Z. Pierwsza z mikroinstrukcji realizujących ten rozkaz (załóżmy, że jest ona
zapisana pod adresem 364) musi zbadać wartość tej flagi i jeżeli jest ona ustawiona wykonać
skok do sekwencji mikroinstrukcji, które odczytają z pamięci wartość przesunięcia (do tej pory
nie mówiliśmy o takiej sekwencji, ale założenie, że ona istnieje jest zupełnie realistyczne,
ponieważ jest ona wykorzystywana w wielu rozkazach; jej kod podamy jeszcze w tym
podrozdziale). Załóżmy, że adres początkowy omawianej sekwencji wynosi
592 = (10010 10000)
2
. Poniżej opisano odpowiednie mikrooperacje:
Układ sterujący (część 2)
9
1. Sprawdź wartość flagi Z, jeżeli jest równa 1 skocz do sekwencji pobierającej przesunięcie,
jeżeli jest równa 0 – zwiększ μPC o jeden.
2. Skocz do sekwencji pobierającej następny rozkaz.
Pole wyboru flagi a
0
a
1
= 01 pozwala wybrać flagę Z. Przypadkowo te same wartości dla pola
wyboru warunku (s
0
s
1
= 01) ustawiają wybór skoku warunkowego, tzn. skoku do adresu
wskazanego przez pole następnego adresu o ile wejściowy warunek jest prawdziwy. Jeżeli nie
jest, to μPC wskaże adres następnej mikroinstrucji (365), a ta powinna spowodować skok do
sekwencji pobierającej kolejny rozkaz z pamięci operacyjnej. Zawartość odpowiednich słów
pamięci sterującej wygląda następująco (założono dodatkowo, że sekwencja sięgnięcia po
następny rozkaz rozpoczyna się od adresu 5 = (0000000101)
2
:
Numer
Pole następnego Pole wyboru warunku
komórki
adresu
Pole wyboru flagi
pamięci
364
0000 0000 0000 0000 0000 10010 10000 01 01
592
Wybierz flagę Z
wybierz skok warunkowy
365
0000 0000 0000 0000 0000 00000 00101 11 00
5
wybierz skok bezwarunkowy
pod adres wskazany w polu
następnego adresu
Pozostało nam omówić sekwencję pobierania przesunięcia, czyli reakcję na spełniony
warunek, która zgodnie z ustaleniami zapisana jest od adresu 592. Kolejne, zapisane tam
mikrooperacje powinny wykonać następujące czynności:
1. Umieść zawartość PC na szynie (PC: czytaj) i załaduj z niej MAR (MAR: ładuj); wyślij do
pamięci rozkaz: czytaj; zwiększ PC;
2. Umieść zawartość PC na szynie (PC: czytaj) załaduj z niej ACC (ACC: ładuj); zaczekaj na
pamięć, aż wykona rozkaz;
3. Umieść zawartość MDR na szynie (MDR: czytaj) i prześlij do ALU rozkaz „dodaj” (w MDR
jest przesunięcie, a w ACC bieżąca wartość PC);
4. Umieść zawartość ACC na szynie (ACC: czytaj) i załaduj z niej PC (PC: ładuj); Skocz do
sekwencji pobierającej następny rozkaz.
Mikrokody odpowiadające opisanym mikrooperacjom przedstawione są poniżej (przypomnijmy,
że zgodnie z przyjętymi wcześniej założeniami: kod rozkazu „dodaj” jest równy 1 = (0001)
2
, a
mikrokody zapamiętane są począwszy od adresu 592):
1 5 9
13 17 22
32 34
592
0000 0001 0010 0000 10100 00000 00000 00 00
593
0000 0001 0001 0000 00001 00000 00000 00 00
594
0000 0000 0100 0001 00000 00000 00000 00 00
595
0000 0010 0000 0000 00010 00000 00101 11 00
Układ sterujący (część 2)
10
Na rysunku 8.14 naszkicowane są wszystkie opisane kroki.
Sięgnij po następny rozkaz
1
2b
BEQL
2a
3
Sięgnij po przesunięcie
Rysunek 8.14. Położenie sekwencji różnych rozkazów w pamięci sterującej.
Po rozpoznaniu rozkazu BEQL (krok 1) wykonywane są mikrooperacje, które w szczególności
badają wartość flagi Z. Jeżeli jest ona ustawiona (warunek jest spełniony), to wykonany jest skok
do mikrooperacji odczytania z pamięci operacyjnej przesunięcia (krok 2a), wyliczenia
efektywnego adresu rozkazu, od którego rozpoczyna się kod programu wykonywanego po
wykonaniu rozkazu BEQL i skoku do sekwencji sięgającej po ten rozkaz (krok 3). Natomiast
jeżeli flaga nie jest ustawiona to wykonany jest skok do mikrooperacji odczytania z pamięci
kolejnego, po BEQL, rozkazu programu (krok 2b).