sposoby zwiekszania efektywnosci pracy systemu
15. Rozwiązania zapewniające zwiększenie efektywności procesora
Kolejka instrukcji
Pobieranie instrukcji z rejestru instrukcji IR do dalszego przetwarzania (dekodowania, wykonania) odbywa się z różna prędkością w zależności od:
- trybu adresowania,
- liczby argumentów,
- czasu ich pobierania z pamięci,
- liczby taktów zegara w jakich wykonywana jest instrukcja.
Również w różnym tempie odbywa się dostarczanie instrukcji do rejestru rozkazów IR w zależności od obciążenia szyny danych. Mogą zatem powstawać sytuacje, w których dekoder instrukcji czeka na instrukcję w IR a układ pobierania instrukcji nie może jej na czas dostarczyć bo szyna danych jest akurat zajęta innymi transmisjami albo sytuacje w których szyna i pamięć są gotowe i mogą dostarczyć instrukcję, natomiast procesor jest jeszcze zajęty przetwarzaniem instrukcji poprzedniej.
W obu przypadkach jest konieczność wstrzymania pracy bloków nie mających i trzeba wygenerować martwe cykle ich pracy, tzn. czynności polegające na nie zrobieniu nic w danym cyklu zegara.
Aby martwych cykli pracy pamięci i ALU było jak najmniej stosuje się kolejkę instrukcji.
Ponieważ obciążenie bloku wykonawczego procesora oraz pamięci zmienia się dynamicznie i raz jedno jest większe raz drugie, duże korzyści daje zamienienie rejestru IR na wielopozycyjny bufor instrukcji i stworzenie w nim kolejki instrukcji. Gdy ALU pracuje akurat wolniej a szyna dostarcza instrukcje szybciej kolejka się zapełnia kilkoma instrukcjami. Gdy później szyna stanie się z jakiegoś powodu wolniejsza w stosunku do ALU, instrukcje będą pobierane z kolejki i nie nastąpi przestój w pracy ALU.
Ilustruje to rys. 15.1.
Rys 15.1. Schemat układu obsługującego kolejkę instrukcji
Kolejka ma pięć pozycji. Dekoder aktualnie dekoduje instrukcję „instrukcję 0” pierwszej odczytywanej pozycji kolejki, a instrukcje następne „instrukcja 1”, „instrukcja 2”, „instrukcja 3”, „instrukcja 4” zostały pobrane i oczekują w kolejce. Rejestr PC wskazuje adres „instrukcji 4”, która została ostatnio pobrana. Gdy zakończy się dekodowanie „instrukcji 0”, zostanie ona usunięta z kolejki, a na zwolnione miejsce zostanie wpisana „instrukcja 5” w ten sposób, że rejestr PC zwiększy się o 1 i wystawi adres „instrukcji 5”. Sprawdzaniem stanu kolejki i uzupełnianiem jej w razie wolnego miejsca przez zwiększanie PC i kolejki zajmuje się specjalny blok włączony pomiędzy szynę a bufor kolejki w pamięci FIFO zwany Blokiem Wyprzedzającego Wprowadzania Instrukcji (BWWI).
Cykl pracy kolejki wygląda zatem następująco:
- jeżeli kolejka posiada wolne miejsca, Blok Wyprzedzającego Wprowadzania Instrukcji (BWWI) wprowadza na nie kolejne instrukcje w tempie wyznaczonym przez zegar (max 1 instr./takt), ale ograniczonym również przez obciążenie szyny,
- równocześnie jeżeli kolejka zawiera instrukcje, są one pobierane do dekodowania w tempie wyznaczonym przez pracę dekodera.
Zanim przedstawione zostanie, jak wprowadzenie kolejki instrukcji odbija się na procesie pobierania instrukcji należy przypomnieć, że w skład cyklu instrukcyjnego procesora wchodzi 5 faz:
- pobranie instrukcji (PI),
- dekodowanie instrukcji (DI),
- obliczenie adresu argumentów i pobranie argumentów (OA+PA),
- wykonanie instrukcji (WI),
- zapamiętanie wyników (ZW).
Wśród nich trzy fazy PI, PA i ZW wymagają wykonania dostępów do pamięci.
Dostępy te są najkrytyczniejsze w całym cyklu instrukcyjnym ponieważ zajmują i obciąża szynę adresową i danych.
Wymienione 5 faz rozłożonych na trzy bloki:
- pamięć i układy adresujące,
- dekoder,
- ALU
rozkłada się w czasie w sposób pokazany na rys. 15.2.
Pomiędzy trzema dostępami do pamięci występują dwa martwe cykle pamięci (MCP), pomiędzy wykonaniami instrukcji występują martwe cykle ALU (MCA).
Rys 15.2. Fazy wykonania cyklu instrukcyjnego bez kolejki instrukcji
Jeżeli szyna jest mało obciążona i transmisje adresu do pamięci oraz instrukcji i danych z pamięci nie wymaga oczekiwania na zwolnienie szyny, to pobranie instrukcji odbywa się w jednym takcie. Wówczas w każdym martwym cyklu pamięci układ wyprzedzającego wprowadzania instrukcji może dokonać co najmniej jednego pobrania następnej instrukcji do kolejki. Otrzymujemy schemat pokazany na rys. 15.3.
Rys 15.3. Fazy wykonania cyklu instrukcyjnego z jednotaktowym wykonaniem instrukcji pierwszej (WI1) przy kolejce instrukcji
Może wystąpić również sytuacja, w której wykonanie instrukcji pierwszej (WI1) trwa więcej taktów zegara i wówczas pojawia się więcej martwych cykli, które można przeznaczyć na pobranie większej liczby instrukcji, np. PI3 i PI4, jak pokazuje rys. 15.4. Przypadkom z rys.15.3 i 15.4. towarzyszyć będzie zapełnianie kolejki.
Rys 15. 4. Fazy wykonania cyklu instrukcyjnego z dwutaktowym WI1 przy kolejce instrukcji
Jeżeli jednak na rys.15.3 szyna będzie przeciążona i po zażądaniu pobrania drugiej instrukcji przez Blok Wyprzedzającego Wprowadzania Instrukcji nie nastąpi przesłanie, ale oczekiwanie na zwolnienie szyny, np. przez jeden takt, to nie uda się zapełnić kolejki. PI2 nie zmieści się w żadnym z jednotaktowych martwych cykli pamięci (nie tylko PI2 i PI3 będą opóźnione, ale także pobrania argumentu PA1 i zapisania wyniku ZW1). Kolejka instrukcji nie będzie się zapełniała, a w realizacjach w których dekoder i ALU nie czekają na zakończenie cyklu instrukcyjnego (potokowych), lecz pobierają następne dane kolejka będzie wręcz malała.
Jeżeli w kodzie programu pojawi się instrukcja skoku JMP (zwykła lub warunkowa) lub wywołanie podprogramu CALL wówczas mechaniczne pobieranie przez BWWI do kolejki kolejnych instrukcji za instrukcja skoku jest problematyczne.
Najprostszy układ BWWI nie bada typu instrukcji pobieranej. Kolejka jest zapełniana kolejno instrukcjami: „instrukcja 1”, JMP, „Instrukcja 2”, „Instrukcja 3”, .... Gdy JMP dojdzie do dekodowania i dekoder stwierdzi skok, zostanie on wykonany, następuje przerwa w pracy procesora, kolejka zostanie opróżniona z instrukcji „Instrukcja 2”, „Instrukcja 3”,... i zacznie się jej ponowne zapełnianie instrukcjami wyznaczonymi przez skok (lub podprogram). Ta przerwa znacznie spowalnia działanie procesora, bo skoki są częstym elementem programu.
Sytuacje można poprawić jeżeli BWWI będzie rozpoznawał instrukcję JMP po jej wprowadzeniu i przełączy się na pobieranie następnych instrukcji za skokiem.
Jeszcze trudniejsza sytuacja występuje jeżeli skok jest warunkowy i zajdzie tylko w przypadku odpowiedniej wartości zmiennej określonej argumentem instrukcji skoku. Wówczas opróżnianie kolejki może nastąpić dopiero po wyliczeniu przez ALU wartości tego argumentu. Jeśli z wartości argumentu wynika, że skok nastąpi, kolejka i dekoder są opróżniane, i zacznie się nowe zapełnianie kolejki instrukcjami za skokiem.
Osobnym problemem jest dobór długości kolejki. Jeżeli kolejka jest krótka, wówczas nawet przy niewielkiej przewadze szybkości pobierania instrukcji nad szybkością dekodowania i wykonywania (tzn. gdy szyna mało obciążona działa szybko a procesor wykonuje długie instrukcje i działa wolno) łatwo się zapełnia i przestaje spełniać swoja rolę. Z drugiej strony, gdy kolejka jest długa, wówczas Blok Wyprzedzającego Wprowadzania Instrukcji przez większość czasu swojej pracy ma do czynienia z kolejką nie zapełnioną i stale pobiera instrukcje do kolejki obciążając nadmiernie szynę. Powoduje to globalne spowolnienie systemu.
Jak widać obydwie sytuacje są niekorzystne i należy dobrać kompromisowa długość kolejki. W praktyce stosuje się na ogół kolejkę, która zawiera kilka pozycji.
Przetwarzanie potokowe
W przetwarzaniu omawianym wyżej, w czasie jednego cyklu instrukcyjnego cały procesor zajmował się tylko jedna instrukcją. Gdy dekoder dekodował, układ pobierania już zakończył pracę, a układ adresowania i pobierania danych oczekiwał na wynik pracy poprzednika. Było to tzw. przetwarzanie szeregowe (patrz rys.15.5.).
Rys 15.5. Wykonywanie faz cyklu instrukcyjnego w sposób szeregowy
W przetwarzaniu tym wynik otrzymujemy w fazie ZW, co następuje jeden raz w każdym cyklu instrukcyjnym.
Wielką zaletą takiego przetwarzania jest to, że dopuszcza dowolne uzależnienia rejestrowe instrukcji później wykonywanej od wcześniej wykonywanej, np. wynik obliczony w WI1 i zapisany w ZW1 może być argumentem następnej instrukcji pobieranym w fazie PA2.
Inną możliwością jest przetwarzanie równolegle, w którym wszystkie odpowiadające sobie fazy wszystkich zrównoleglonych instrukcji są wykonywane równocześnie, jak pokazuje rys. 15.6.
Rys.15.6. Wykonywanie faz cyklu instrukcyjnego w sposób równoległy
System wymaga zwielokrotnienia sprzętu i daje w jednym cyklu instrukcyjnym tyle wyników ilekrotnie zrównoleglono sprzęt. Jednak nie dopuszcza on wzajemnych uzależnień rejestrowych instrukcji, wynik jednej nie może być argumentem innej.
Najczęściej stosowany obecnie jest system przetwarzania potokowego, w którym jeżeli cykl instrukcyjny jest podzielony na 5 faz, to rozpoczęcie przetwarzania następnej instrukcji następuje z opóźnieniem względem poprzedniej o 1/5 cyklu, czyli np. jeden takt zegara. Pokazuje to rys. 15.7.
Rys.15.7. Wykonywanie faz cyklu instrukcyjnego w sposób potokowy
W systemie tym otrzymanie i zapis wyniku ZW następuje co 1/5 cyklu instrukcyjnego, a wiec mamy pięć wyników w czasie jednego cyklu. System ten w zasadzie nie wymaga zwielokrotnienia sprzętu a jedynie zapewnienia, aby każdy z pięciu podukładów procesora mógł niezależnie od innego wykonywać dowolną fazę cyklu podczas gdy pozostałe będą wykonywać pozostałe fazy.
Przetwarzanie potokowe w formie ogólnej stawia duże wymagania sprzętowi, bo występuje w niej jednoczesność faz PI, PA i ZW wymagających dostępu do pamięci. Okazuje się to bardzo trudne w klasycznej architekturze von Neumanna. W praktyce w różnych architekturach istnieją różne ograniczone wersje tego przetwarzania.
Architektura Harvard
W klasycznym przetwarzaniu potokowym korzystanie z dostępu do pamięci może powodować przeciążenie szyny adresowej i opóźnień pobierania i zapisu. Aby zmniejszyć to obciążenie stosowana jest architektura Harvard. Polega ona na tym, że rozdzielone zostają obszary adresowania instrukcji oraz danych i dostępy do instrukcji oraz danych. Pokazuje to rys. 15.8.
Architektura systemu dzieli się na trzy układy:
- układ obsługujący instrukcje (licznik rozkazów, bufor pobierania instrukcji i pamięć programu),
- układ obsługujący dane (dekoder, generator adresów danych, rejestry i pamięć danych),
- układ wykonawczy (ALU i blok sterowania).
Rys 15.8. Architektura Harvard
W tych trzech układach wyróżnić można pięć bloków, które mogą pracować niezależnie:
- blok pobierania instrukcji (PI),
- blok dekodowania instrukcji (DI),
- blok obliczania adresów danych (AG),
- blok pobierania danych i zapisywania wyników (PA),
- blok wykonania operacji (WI)
co implikuje możliwość uruchomienia pięciu potoków (patrz rys. 15.9.):
- licznik rozkazów wystawia na szynę adresów instrukcji kolejne adresy, pamięć programu zwraca instrukcje na szynę instrukcji i zostają one zapisane do bufora pobierania instrukcji aż do zapełnienia kolejki,
- dekoder pobiera instrukcje z bufora instrukcji i dekoduje je,
- blok obliczania adresów określa adresy danych i zapisuje je w rejestrach adresowych,
- adresy danych są wystawiane na szynę adresów danych, pamięć danych zwraca dane na szynę danych i zostają one zapisane do rejestrów danych (w potoku tym zamiast pobierania argumentów może być również wykonany zapis zawartości rejestrów do pamięci),
- ALU pobiera dane z rejestrów, wykonuje operacje i wynik zapisuje w rejestrze.
