Klasyczny potok RISC — Classic RISC pipeline

W historii sprzętu komputerowego niektóre wczesne jednostki centralne procesora komputerowego (RISC CPU) o zredukowanym zestawie instrukcji wykorzystywały bardzo podobne rozwiązanie architektoniczne, obecnie nazywane klasycznym potokiem RISC . Tymi procesorami były: MIPS , SPARC , Motorola 88000 , a później hipotetyczny procesor DLX wymyślony dla edukacji.

Każdy z tych klasycznych skalarnych projektów RISC pobiera i próbuje wykonać jedną instrukcję na cykl . Główną wspólną koncepcją każdego projektu jest pięciostopniowy potok instrukcji wykonania . Podczas pracy każdy stopień potoku działa na jednej instrukcji na raz. Każdy z tych etapów składa się z zestawu przerzutników do utrzymywania stanu oraz logiki kombinacyjnej, która działa na wyjściach tych przerzutników.

Klasyczny pięcioetapowy potok RISC

Podstawowy pięciostopniowy potok w maszynie RISC (IF = Instruction Fetch , ID = Instruction Decode, EX = Execute, MEM = Dostęp do pamięci, WB = Register write back). Oś pionowa to kolejne instrukcje; oś pozioma to czas. Tak więc w zielonej kolumnie najwcześniejsza instrukcja jest w fazie WB, a najnowsza instrukcja jest w trakcie pobierania instrukcji.

Pobieranie instrukcji

Instrukcje znajdują się w pamięci, której odczyt zajmuje jeden cykl. Może to być dedykowana pamięć SRAM lub pamięć podręczna instrukcji . Termin „opóźnienie” jest często używany w informatyce i oznacza czas od rozpoczęcia operacji do jej zakończenia. W ten sposób pobieranie instrukcji ma opóźnienie jednego cyklu zegara (jeśli używa się jednocyklowej pamięci SRAM lub jeśli instrukcja znajdowała się w pamięci podręcznej). W ten sposób, podczas etapu Instruction Feetch , 32-bitowa instrukcja jest pobierana z pamięci instrukcji.

Program Counter lub PC, to rejestr, który zawiera adres, który jest prezentowany w pamięci rozkazów. Na początku cyklu adres jest prezentowany w pamięci instrukcji. Następnie w trakcie cyklu instrukcja jest odczytywana z pamięci instrukcji i jednocześnie wykonywane są obliczenia w celu określenia następnego komputera. Obliczenie następnego PC odbywa się poprzez zwiększenie PC o 4 i wybranie, czy wziąć go jako następny PC, czy alternatywnie wziąć wynik obliczenia rozgałęzienia/skoku jako następny PC. Zwróć uwagę, że w klasycznym RISC wszystkie instrukcje mają tę samą długość. (To jest jedna rzecz, która odróżnia RISC od CISC ). W oryginalnych projektach RISC rozmiar instrukcji wynosi 4 bajty, więc zawsze dodaj 4 do adresu instrukcji, ale nie używaj PC + 4 w przypadku wziętej gałęzi, skoku lub wyjątku (patrz opóźnione gałęzie poniżej ). (Zauważ, że niektóre nowoczesne maszyny używają bardziej skomplikowanych algorytmów ( przewidywanie rozgałęzień i przewidywanie celu rozgałęzienia ), aby odgadnąć następny adres instrukcji.)

Dekodowanie instrukcji

Inną rzeczą, która odróżnia pierwsze maszyny RISC od wcześniejszych maszyn CISC, jest to, że RISC nie ma mikrokodu . W przypadku mikrokodowanych instrukcji CISC, po pobraniu z pamięci podręcznej instrukcji, bity instrukcji są przesuwane w dół potoku, gdzie prosta logika kombinacyjna na każdym etapie potoku wytwarza sygnały sterujące dla ścieżki danych bezpośrednio z bitów instrukcji. W tych projektach CISC bardzo mało dekodowania jest wykonywane na etapie tradycyjnie nazywanym etapem dekodowania. Konsekwencją tego braku dekodowania jest to, że więcej bitów instrukcji musi być użytych do określenia, co robi instrukcja. To pozostawia mniej bitów na takie rzeczy, jak indeksy rejestru.

Wszystkie instrukcje MIPS, SPARC i DLX mają co najwyżej dwa wejścia rejestru. Podczas etapu dekodowania indeksy tych dwóch rejestrów są identyfikowane w instrukcji, a indeksy są prezentowane w pamięci rejestrów jako adres. W ten sposób dwa wymienione rejestry są odczytywane z pliku rejestru . W projekcie MIPS akt rejestrowy zawierał 32 wpisy.

W tym samym czasie odczytywany jest plik rejestru, logika wydania instrukcji na tym etapie określa, czy potok jest gotowy do wykonania instrukcji na tym etapie. Jeśli nie, logika problemu powoduje zatrzymanie zarówno etapu pobierania instrukcji, jak i etapu dekodowania. W cyklu przeciągnięcia, przerzutniki wejściowe nie akceptują nowych bitów, dlatego w tym cyklu nie są wykonywane żadne nowe obliczenia.

Jeśli dekodowana instrukcja jest rozgałęzieniem lub skokiem, adres docelowy rozgałęzienia lub skoku jest obliczany równolegle z odczytem pliku rejestru. Warunek rozgałęzienia jest obliczany w następnym cyklu (po wczytaniu pliku rejestru), a jeśli rozgałęzienie zostanie podjęte lub jeśli instrukcja jest skokiem, do komputera PC w pierwszym etapie przypisywany jest cel rozgałęzienia, a nie zwiększony PC, który został obliczony. Niektóre architektury wykorzystywały jednostkę arytmetyczno-logiczną (ALU) na etapie wykonywania, kosztem nieco zmniejszonej przepustowości instrukcji.

Etap dekodowania zakończył się dość dużą ilością sprzętu: MIPS ma możliwość rozgałęzienia, jeśli dwa rejestry są równe, więc po odczytaniu pliku rejestru działa szeregowo 32-bitowe drzewo AND, tworząc bardzo długą ścieżkę krytyczną. etap (co oznacza mniej cykli na sekundę). Ponadto obliczenia celu rozgałęzienia generalnie wymagały 16-bitowego dodawania i 14-bitowego inkrementatora. Rozwiązanie gałęzi na etapie dekodowania umożliwiło uzyskanie kary za błędne przewidywanie gałęzi w jednym cyklu. Ponieważ gałęzie były bardzo często zabierane (a tym samym błędnie przewidywane), bardzo ważne było utrzymanie tej kary na niskim poziomie.

Wykonać

Etap Execute to miejsce, w którym następuje faktyczne obliczenie. Zazwyczaj ten etap składa się z ALU, a także z przesuwnika bitowego. Może również zawierać mnożnik i dzielnik wielu cykli.

Jednostka ALU jest odpowiedzialna za wykonywanie operacji logicznych (i, lub nie, nand, nor, xor, xnor), a także za wykonywanie dodawania i odejmowania liczb całkowitych. Oprócz wyniku, jednostka ALU zazwyczaj dostarcza bity stanu, takie jak czy wynik był równy 0 lub czy wystąpiło przepełnienie.

Przesuwnik bitów odpowiada za przesunięcie i obroty.

Instrukcje na tych prostych maszynach RISC można podzielić na trzy klasy opóźnień w zależności od typu operacji:

  • Operacja rejestru-rejestru (opóźnienie pojedynczego cyklu): dodawanie, odejmowanie, porównywanie i operacje logiczne. Podczas etapu wykonania dwa argumenty zostały przekazane do prostej jednostki ALU, która wygenerowała wynik pod koniec etapu wykonania.
  • Odniesienie do pamięci (opóźnienie dwóch cykli). Wszystkie wczytywania z pamięci. Podczas etapu wykonywania, ALU dodała dwa argumenty (rejestr i stałe przesunięcie), aby pod koniec cyklu wytworzyć adres wirtualny.
  • Instrukcje dotyczące wielu cykli (wiele cykli opóźnień). Mnożenie i dzielenie liczb całkowitych oraz wszystkie operacje zmiennoprzecinkowe . Podczas etapu wykonania, operandy tych operacji były podawane do wielocyklowego zespołu mnożenia/dzielenia. Reszta potoku mogła kontynuować wykonywanie, podczas gdy jednostka mnożenia/dzielenia wykonywała swoją pracę. Aby uniknąć komplikowania etapu zapisu zwrotnego i logiki wydania, instrukcja multicycle zapisywała swoje wyniki do oddzielnego zestawu rejestrów.

Dostęp do pamięci

Jeśli potrzebny jest dostęp do pamięci danych, odbywa się to na tym etapie.

Na tym etapie, instrukcje z latencją pojedynczego cyklu po prostu mają swoje wyniki przekazywane do następnego etapu. To przekazywanie zapewnia, że ​​zarówno instrukcje jednego, jak i dwóch cykli zawsze zapisują swoje wyniki na tym samym etapie potoku, dzięki czemu można użyć tylko jednego portu zapisu do pliku rejestru i jest on zawsze dostępny.

Do bezpośredniego zmapowanego i wirtualnie oznaczonego buforowania danych, zdecydowanie najprostszego z wielu organizacji buforowania danych , używane są dwie pamięci SRAM , jedna przechowująca dane, a druga przechowująca tagi.

Odpisać

Na tym etapie zarówno instrukcje pojedynczego cyklu, jak i dwa cykle zapisują swoje wyniki w pliku rejestru. Zauważ, że dwa różne etapy uzyskują dostęp do pliku rejestru w tym samym czasie -- etap dekodowania odczytuje dwa rejestry źródłowe, w tym samym czasie, gdy etap zapisu zwrotnego zapisuje rejestr docelowy poprzedniej instrukcji. W przypadku prawdziwego krzemu może to stanowić zagrożenie (patrz poniżej, aby uzyskać więcej informacji na temat zagrożeń). Dzieje się tak, ponieważ jeden z rejestrów źródłowych odczytywanych w dekodowaniu może być taki sam, jak rejestr docelowy zapisywany w trybie writeback. Kiedy tak się dzieje, te same komórki pamięci w pliku rejestru są jednocześnie odczytywane i zapisywane. Na krzemie wiele implementacji komórek pamięci nie będzie działać poprawnie podczas jednoczesnego odczytu i zapisu.

Zagrożenia

Hennessy i Patterson ukuli termin „ zagrożenie” dla sytuacji, w których instrukcje w potoku dałyby błędne odpowiedzi.

Zagrożenia strukturalne

Zagrożenia strukturalne występują, gdy dwie instrukcje mogą próbować użyć tych samych zasobów w tym samym czasie. Klasyczne potoki RISC pozwoliły uniknąć tych zagrożeń poprzez replikację sprzętu. W szczególności instrukcje rozgałęzienia mogły wykorzystać jednostkę ALU do obliczenia adresu docelowego rozgałęzienia. Gdyby jednostka ALU została użyta w tym celu na etapie dekodowania, instrukcja ALU, po której następuje rozgałęzienie, spowodowałaby, że obie instrukcje próbowałyby użyć jednostki ALU jednocześnie. Ten konflikt można łatwo rozwiązać, projektując na etapie dekodowania wyspecjalizowany dodatek docelowy gałęzi.

Zagrożenia danych

Zagrożenia związane z danymi pojawiają się, gdy instrukcja, zaplanowana na ślepo, usiłuje wykorzystać dane, zanim dane będą dostępne w pliku rejestru.

W klasycznym potoku RISC zagrożeń danych można uniknąć na dwa sposoby:

Rozwiązanie A. Pomijanie

Pomijanie jest również znane jako przekazywanie operandów .

Załóżmy, że procesor wykonuje następujący fragment kodu:

SUB r3,r4 -> r10     ; Writes r3 - r4 to r10
AND r10,r3 -> r11    ; Writes r10 & r3 to r11

Etapy pobierania i dekodowania instrukcji wysyłają drugą instrukcję jeden cykl po pierwszym. Spływają w dół rurociągu, jak pokazano na tym schemacie:

Zagrożenie danych potoku.svg

W naiwnym potoku , bez uwzględnienia zagrożeń, zagrożenie danych postępuje w następujący sposób:

W cyklu 3 SUBinstrukcja oblicza nową wartość dla r10. W tym samym cyklu ANDoperacja jest dekodowana, a wartość r10jest pobierana z pliku rejestru. Jednak SUBinstrukcja nie zapisała jeszcze swojego wyniku do r10. Zwrot tego następuje zwykle w cyklu 5 (zielona ramka). Dlatego wartość odczytana z pliku rejestru i przekazana do jednostki ALU (w fazie Execute AND, czerwone pole) jest niepoprawna.

Zamiast tego musimy przekazać dane, które zostały obliczone z SUBpowrotem do etapu Execute (tj. do czerwonego kółka na diagramie) ANDoperacji, zanim zostaną one normalnie zapisane. Rozwiązaniem tego problemu jest para multiplekserów obejściowych. Te multipleksery znajdują się na końcu etapu dekodowania, a ich wyjścia z klapką są wejściami do jednostki ALU. Każdy multiplekser wybiera pomiędzy:

  1. Port odczytu pliku rejestru (tj. wyjście etapu dekodowania, jak w naiwnym potoku): czerwona strzałka
  2. Obecny potok rejestru ALU (do obejścia o jeden stopień): niebieska strzałka
  3. Bieżący potok rejestru etapu dostępu (który jest albo wartością załadowaną, albo przekazanym wynikiem ALU, zapewnia pominięcie dwóch etapów): fioletowa strzałka. Zauważ, że wymaga to przekazania danych wstecz o jeden cykl. W takim przypadku należy wstawić bąbelek, aby zatrzymać ANDoperację do momentu, gdy dane będą gotowe.

Logika etapu dekodowania porównuje rejestry zapisane przez instrukcje w etapie wykonania i dostępu potoku z rejestrami odczytanymi przez instrukcje w etapie dekodowania i powoduje, że multipleksery wybierają najnowsze dane. Te multipleksery obejściowe umożliwiają potoku wykonywanie prostych instrukcji tylko z opóźnieniem jednostki ALU, multipleksera i przerzutnika. Bez multiplekserów opóźnienie zapisu, a następnie odczytu pliku rejestru musiałoby być zawarte w opóźnieniach tych instrukcji.

Należy pamiętać, że dane mogą być przekazywane tylko do przodu w czasie — danych nie można pominąć z powrotem do wcześniejszego etapu, jeśli nie zostały jeszcze przetworzone. W powyższym przypadku dane są przekazywane dalej (do czasu, gdy ANDjest gotowy do rejestracji w ALU, SUBjest już obliczony).

Przekazywanie danych (jeden etap).svg

Rozwiązanie B. Blokada rurociągu

Weź jednak pod uwagę następujące instrukcje:

LD  adr    -> r10
AND r10,r3 -> r11

Dane odczytane z adresu adrznajdują się w pamięci podręcznej dopiero po etapie dostępu do pamięci LDinstrukcji. Do tego czasu ANDinstrukcja przechodzi już przez jednostkę ALU. Rozwiązanie tego problemu wymagałoby przekazania danych z pamięci wstecz w czasie do danych wejściowych do jednostki ALU. To jest niemożliwe. Rozwiązaniem jest opóźnienie ANDinstrukcji o jeden cykl. Zagrożenie danych jest wykrywany w etapie dekodowania i etapy pobierania i dekodowania są wstrzymane - są zapobiega marszczeniu wejścia i dlatego pozostają w tym samym stanie po cyklu. Kolejne etapy wykonywania, dostępu i zapisu zwrotnego zawierają dodatkową instrukcję braku operacji (NOP) wstawioną między instrukcje LDi AND.

Ten NOP jest nazywany pęcherzykiem rurociągu , ponieważ unosi się w rurociągu, jak pęcherzyk powietrza w rurze wodnej, zajmując zasoby, ale nie dając użytecznych wyników. Sprzęt do wykrywania zagrożenia danych i blokowania potoku do czasu jego usunięcia nazywa się blokadą potoku .

Omijanie wstecz w czasie Problem rozwiązany za pomocą bańki
Przekazywanie danych (dwuetapowy, błąd).svg Przekazywanie danych (dwa etapy).svg

Jednak blokada potoku nie musi być używana z żadnym przekazywaniem danych. Pierwszy przykład, po którym SUBnastępuje, ANDi drugi przykład, LDpo którym następuje, ANDmożna rozwiązać przez zatrzymanie pierwszego etapu o trzy cykle, aż do uzyskania zapisu zwrotnego, a dane w pliku rejestru są poprawne, powodując pobranie prawidłowej wartości rejestru przez ANDetap Decode. Powoduje to spory spadek wydajności, ponieważ procesor spędza dużo czasu na przetwarzaniu niczego, ale można zwiększyć szybkość zegara, ponieważ jest mniej logiki przekazywania, na którą trzeba czekać.

To zagrożenie związane z danymi można dość łatwo wykryć, gdy kod maszynowy programu zostanie napisany przez kompilator. Maszyna Stanford MIPS polegała na kompilatorze, aby dodać instrukcje NOP w tym przypadku, zamiast mieć obwody do wykrywania i (bardziej wyczerpujące) zatrzymywania pierwszych dwóch etapów potoku. Stąd nazwa MIPS: Microprocessor without Interlocked Pipeline Stages. Okazało się, że dodatkowe instrukcje NOP dodane przez kompilator rozszerzyły pliki binarne programu na tyle, że zmniejszył się współczynnik trafień w pamięci podręcznej instrukcji. Sprzęt do stajni, choć drogi, został ponownie wprowadzony do późniejszych projektów, aby poprawić wskaźnik trafień w pamięć podręczną instrukcji, w którym to momencie akronim nie miał już sensu.

Zagrożenia kontrolne

Zagrożenia kontrolne są powodowane przez warunkowe i bezwarunkowe rozgałęzienia. Klasyczny potok RISC rozwiązuje rozgałęzienia na etapie dekodowania, co oznacza, że ​​cykl rozwiązywania rozgałęzień trwa dwa cykle. Są trzy implikacje:

  • Powtarzanie rozwiązywania rozgałęzień przechodzi przez sporo obwodów: odczyt pamięci podręcznej instrukcji, odczyt pliku rejestru, obliczenie stanu rozgałęzienia (co obejmuje 32-bitowe porównanie na procesorach MIPS) i multiplekser adresów następnych instrukcji.
  • Ponieważ cele rozgałęzienia i skoku są obliczane równolegle do odczytu rejestru, programy ISA RISC zazwyczaj nie mają instrukcji, które rozgałęziają się do rejestru + adres przesunięcia. Obsługiwany jest skok do rejestracji.
  • W każdej pobranej gałęzi instrukcja bezpośrednio po gałęzi jest zawsze pobierana z pamięci podręcznej instrukcji. Jeśli ta instrukcja zostanie zignorowana, na każdy pobrany oddział IPC przypada jeden cykl , który jest odpowiednio wysoki.

Istnieją cztery schematy rozwiązania tego problemu z wydajnością za pomocą oddziałów:

  • Przewiduj nie zajęte: Zawsze pobieraj instrukcję po rozgałęzieniu z pamięci podręcznej instrukcji, ale wykonuj ją tylko wtedy, gdy gałąź nie jest zajęta. Jeśli odgałęzienie nie zostanie zajęte, rurociąg pozostaje pełny. Jeśli gałąź jest zajęta, instrukcja jest opróżniana (oznaczona jako NOP) i traci się szansę jednego cyklu na zakończenie instrukcji.
  • Rozgałęzienie prawdopodobne: Zawsze pobieraj instrukcję po rozgałęzieniu z pamięci podręcznej instrukcji, ale wykonuj ją tylko wtedy, gdy gałąź została podjęta. Kompilator może zawsze wypełnić gniazdo opóźnienia gałęzi na takiej gałęzi, a ponieważ gałęzie są częściej brane niż nie, takie gałęzie mają mniejszą karę IPC niż poprzedni rodzaj.
  • Branch Delay Slot : Zawsze pobieraj instrukcję po gałęzi z pamięci podręcznej instrukcji i zawsze ją wykonuj, nawet jeśli gałąź jest zajęta. Zamiast pobierać karę IPC za część gałęzi, które zostały wzięte (być może 60%) lub nie (być może 40%), gniazda opóźnienia gałęzi pobierają karę IPC za te gałęzie, w których kompilator nie mógł zaplanować gniazda opóźnienia gałęzi. Projektanci SPARC, MIPS i MC88K zaprojektowali rozgałęzione gniazdo opóźnienia w swoich ISA.
  • Przewidywanie rozgałęzień : Równolegle z pobieraniem każdej instrukcji zgadnij, czy instrukcja jest rozgałęzieniem lub skokiem, a jeśli tak, zgadnij cel. W cyklu po rozgałęzieniu lub skoku pobierz instrukcję do zgadywanego celu. Jeśli odgadnięcie jest błędne, opróżnij nieprawidłowo pobrany cel.

Opóźnione gałęzie były kontrowersyjne, po pierwsze dlatego, że ich semantyka jest skomplikowana. Opóźniona gałąź określa, że ​​skok do nowej lokalizacji następuje po następnej instrukcji. Ta następna instrukcja jest tą, która jest nieuchronnie ładowana przez pamięć podręczną instrukcji po gałęzi.

Opóźnione gałęzie zostały skrytykowane jako kiepski krótkoterminowy wybór w projektowaniu ISA:

  • Kompilatorzy zazwyczaj mają pewne trudności ze znalezieniem logicznie niezależnych instrukcji do umieszczenia po rozgałęzieniu (instrukcja po rozgałęzieniu nazywana jest szczeliną opóźniającą), więc muszą wstawić NOP do szczelin opóźniających.
  • Procesory superskalarne , które pobierają wiele instrukcji na cykl i muszą mieć jakąś formę przewidywania rozgałęzień, nie korzystają z rozgałęzień opóźnionych. Alpha ISA pominięte oddziały opóźniony, jak to było przeznaczone dla superskalarnych procesorów.
  • Najpoważniejszą wadą oddziałów opóźnionych jest dodatkowa złożoność kontroli, jaką wiążą się z nimi. Jeśli instrukcja szczeliny opóźniającej przyjmuje wyjątek, procesor musi zostać zrestartowany w gałęzi, a nie w następnej instrukcji. Wyjątki mają wtedy zasadniczo dwa adresy, adres wyjątku i adres restartu, a generowanie i rozróżnianie między nimi we wszystkich przypadkach było źródłem błędów w późniejszych projektach.

Wyjątki

Załóżmy, że 32-bitowy RISC przetwarza instrukcję ADD, która dodaje dwie duże liczby, a wynik nie mieści się w 32 bitach.

Najprostszym rozwiązaniem, dostarczanym przez większość architektur, jest arytmetyka pakowania. Liczby większe niż maksymalna możliwa zakodowana wartość mają swoje najbardziej znaczące bity odcinane, dopóki się nie zmieszczą. W zwykłym systemie liczb całkowitych 3000000000+3000000000=6000000000. Z 32-bitową arytmetyczną zawijania bez znaku, 3000000000+3000000000=1705032704 (6000000000 mod 2^32). To może nie wydawać się strasznie przydatne. Największą zaletą arytmetyki zawijania jest to, że każda operacja ma dobrze zdefiniowany wynik.

Ale programista, zwłaszcza jeśli programuje w języku obsługującym duże liczby całkowite (np. Lisp lub Scheme ), może nie chcieć arytmetyki zawijania. Niektóre architektury (np. MIPS) definiują specjalne operacje dodawania, które rozgałęziają się do specjalnych lokalizacji po przepełnieniu, zamiast zawijania wyniku. Za rozwiązanie problemu odpowiada oprogramowanie w lokalizacji docelowej. Ta specjalna gałąź nazywana jest wyjątkiem. Wyjątki różnią się od zwykłych oddziałów tym, że adres docelowy nie jest określony przez samą instrukcję, a decyzja oddziału jest uzależniona od wyniku instrukcji.

Najczęstszym rodzajem wyjątku widocznego w oprogramowaniu na jednej z klasycznych maszyn RISC jest nietrafienie TLB .

Wyjątki różnią się od rozgałęzień i skoków, ponieważ te inne zmiany przepływu sterowania są rozwiązywane na etapie dekodowania. Wyjątki są rozwiązywane na etapie zapisywania zwrotnego. Po wykryciu wyjątku następujące instrukcje (wcześniejsze w potoku) są oznaczane jako nieważne, a gdy przepływają do końca potoku, ich wyniki są odrzucane. Licznik programu jest ustawiony na adres specjalnego programu obsługi wyjątków, a rejestry specjalne są zapisywane z lokalizacją i przyczyną wyjątku.

Aby ułatwić (i szybko) programowi naprawienie problemu i ponowne uruchomienie programu, procesor musi zrobić dokładny wyjątek. Dokładny wyjątek oznacza, że ​​wszystkie instrukcje aż do instrukcji z wyjątkiem zostały wykonane, a instrukcja z wyjątkiem i wszystko po niej nie zostało wykonane.

Aby wziąć precyzyjne wyjątki, CPU musi zobowiązać się do zmian w oprogramowaniu stan widoczny w celu programu. Zatwierdzenie w kolejności odbywa się bardzo naturalnie w klasycznym potoku RISC. Większość instrukcji zapisuje swoje wyniki do pliku rejestru na etapie zapisu zwrotnego, a więc te zapisy następują automatycznie w kolejności programu. Instrukcje dotyczące przechowywania zapisują jednak swoje wyniki w kolejce danych sklepu na etapie dostępu. Jeżeli instrukcja przechowywania przyjmuje wyjątek, wpis kolejki danych przechowywania jest unieważniany tak, że nie jest później zapisywany w pamięci podręcznej SRAM danych.

Obsługa chybień w pamięci podręcznej

Czasami pamięć podręczna danych lub instrukcji nie zawiera wymaganych danych lub instrukcji. W takich przypadkach procesor musi zawiesić działanie, aż pamięć podręczna będzie mogła zostać wypełniona niezbędnymi danymi, a następnie musi wznowić wykonywanie. Problem wypełniania pamięci podręcznej wymaganymi danymi (i potencjalnie zapisywania z powrotem do pamięci linii wykluczonej pamięci podręcznej) nie jest specyficzny dla organizacji potoku i nie jest tutaj omawiany.

Istnieją dwie strategie radzenia sobie z problemem zawieszania/wznawiania. Pierwszy to globalny sygnał straganu. Ten sygnał, gdy jest aktywowany, zapobiega przejściu instrukcji w dół potoku, zazwyczaj poprzez bramkowanie zegara do przerzutników na początku każdego etapu. Wadą tej strategii jest duża liczba przerzutników, więc globalny sygnał przeciągnięcia zajmuje dużo czasu. Ponieważ maszyna na ogół musi zatrzymać się w tym samym cyklu, w którym identyfikuje stan wymagający utknięcia, sygnał utyku staje się ścieżką krytyczną ograniczającą prędkość.

Inną strategią obsługi zawieszania/wznawiania jest ponowne użycie logiki wyjątków. Maszyna przyjmuje wyjątek od naruszającej instrukcji, a wszystkie dalsze instrukcje są unieważniane. Gdy pamięć podręczna zostanie wypełniona niezbędnymi danymi, instrukcja, która spowodowała brak pamięci podręcznej, zostanie ponownie uruchomiona. Aby przyspieszyć obsługę braków w pamięci podręcznej danych, instrukcję można zrestartować, tak aby jej cykl dostępu następował jeden cykl po zapełnieniu pamięci podręcznej danych.

Zobacz też

Bibliografia

  • Hennessy, John L.; Patterson, David A. (2011). Architektura komputerowa, podejście ilościowe (wyd. 5). Morgana Kaufmanna. Numer ISBN 978-0123838728.
  1. ^ Patterson, Dawid. „RISC I: komputer VLSI z ograniczonym zestawem instrukcji” . Cytowanie dziennika wymaga |journal=( pomoc )
  2. ^ Patterson, Dawid. „RISC I: komputer VLSI z ograniczonym zestawem instrukcji” . Cytowanie dziennika wymaga |journal=( pomoc )