Architektura IA-32: struktura procesora, lista rozkazów, tryby adresowania
W skład procesora IA-32 wchodzą:
· Zestaw rejestrów roboczych
· Jednostka arytmetyczno-logiczna (ALU)
· Układ sterowania
· Blok pobierania instrukcji
· Blok dekodowania instrukcji
· Multipleksery i dekodery
· Jednostka MMU (zarządzania pamięcią)
· Kontroler przerwań. Lista rozkazów:
· Arytmetyczno-logiczne: add, sub, div, idiv, mul, imul, inc, Dec, cmp, sal, sar, rol, ror, neg, not, and, or, xor, shl, shr
· Skoki I sterowanie przepływem: call, jmp, je, jz, jp, jpe, ret, jnz, jnp, jpo, ja, jae, jb, jbe, jna, jnae, jnb, jnbe, jc, Janc,
· Przesłaniowe: mov, xchc, stc, clc, cmc, std, cld, sti, cli, push, pushf, pusha, pop, popa, popf, cbw, cwd, cwde, in, out
· Inne: nop, lea, int
IA-32 to architektura typu CISC - Complex instruction set computer - zatem różne rozkazy mogą mieć różną długość. IA-32
używa kilku różnych trybów adresowania:
· Tryby odnoszące się do pamięci:
o Natychmiastowy - operand znajduje się w polu instrukcji
o Rejestrowy pośredni - operand znajduje się w rejestrze procesora
· Tryby pośrednie:
o Operand w pamięci, a jego adres w rejestrze
o Rejestrowy prosty - adres w rejestrze
o Rejestrowy prosty z przemieszczeniem: adres = zawartość rejestru + stała z instrukcji. Np. [eax + 4]
o Dwurejestrowy pośredni - adresem jest suma zawartości dwóch rejestrów
· Tryby bezpośrednie - dana jest w pamięci, adres w instrukcji
Architektura MIPS 32: struktura procesora, lista rozkazów, tryby adresowania
MIPS 32 jest architekturą potokową. W skład procesora wchodzą:
· Pamięć instrukcji
· Blok pobierania instrukcji
· Blok dekodowania instrukcji
· 31 rejestrów roboczych
· Rejestry potokowe
· Jednostka ALU
· Jednostka sterujaca
· Pamięć danych
Architektura RISC vs. CISC
CISC
- Duża lista rozkazów
- Niektóre rozkazy potrzebują kilku cykli na wykonanie
- występowanie rozkazów złożonych i specjalistycznych
- duża liczba trybów adresowania
- mniejsza częstotliwość taktowania procesora
- powolne działanie dekodera rozkazów ze względu na ich
złożoność i ilość
x86, M6800, AMD
RISC
- Zredukowana liczba rozkazów
- Zredukowana liczba trybów adresowania
- Ograniczenie komunikacji między pamięcią a procesorem
- Zwiększenie liczby rejestrów (nawet do 192, 256)
- Dzięki przetwarzaniu potokowemu wszystkie instrukcje
wykonują się w jednym cyklu maszynowym.
Struktura procesora: elementy i ich współdziałanie
Procesor składa się z:
- ALU
- zestawu rejestrów
- wewnętrznych ścieżek danych
- zewnętrznych ścieżek danych
- jednostki sterującej.
Zadaniem ALU jest wykonywanie prostych operacji arytmetyczno-logicznych na
operandach dostarczonych na wejście i wygenerowanie wyniku.
Zestaw rejestrów czy to uniwersalnych czy konkretnego przeznaczenia jest potrzebny do
przechowywania adresów, pośrednich wyników tymczasowych.
Konwencje reprezentacji danych wielobajtowych w pamięci adresowanej bajtowo
Dane wielobajtowe, które mają zostać umieszczone w pamięci adresowanej bajtowo są
dzielone na bajty i umieszczane pod kolejnymi adresami. Są dwie konwencje ułożenia bajtów w
pamięci: Little Endian i Big Endian.
W konwencji LittleEndian pod najmniejszym adresem zapisany jest najmłodszy(najmniej
znaczący) bajt(zapis do pamięci od prawej do lewej). Jest to konwencja naturalna dla komputera na
tomiast dla człowieka wydaje się nieco dziwna. Jeśli chcemy uzyskać dostęp do mniej znaczący
części(bajta, 2 bajtów) np. liczby całkowitej 64 bitowej to jest to bardzo wygodna konwencja, gdyż
część ta ma ten sam adres co cała liczba.
W konwencji BigEndian pod najmniejszym adresem zapisany jest najstarszy bajt(zapis do
pamięci od lewej do prawej). Konwencja ta jest bardziej zrozumiała dla człowieka, ale mniej
wygodna dla komputera. Tu w przypadku dostępu do mniej znaczących części
Potokowe przetwarzanie instrukcji: koncepcja procesora potokowego i przykładowe
realizacje
Wykonanie rozkazu przez procesor jednocyklowy jest sekwencją etapów: pobranie intrukcji,
dekodowania, pobrania operandów, wykonania i zapisu wyniku do rejestru bądź pamięci. Zarówno
instrukcje tworzące program jak, też ich poszczególne etapy są wykonywane kolejno, a czas
wykonania programu jest sumą czasów wykonania tego wszystkiego. Podczas gdy wykonywany
jest jeden etap, bloki odpowiedzialne za pozostałe etapy są bezczynne. Największe straty czasowe
mają miejsce gdy procesor jest na etapie dostępu do pamięci. Takie przetwarzanie powoduje duże
straty czasu procesora, dlatego powstała koncepcja procesora potokowego.
W przetwarzaniu potokowym instrukcje są wykonywane kolejno lub współbieżnie.
Poszczególne etapy różnych instrukcji są natomiast wykonywane jednocześnie. Przykładowo gdy
zostanie pobrana instrukcja pierwsza i przechodzi na etap dekodowania, to w tym czasie pobierana
jest druga instrukcja. Pierwsza przechodzi na etap pobrania operandów, druga jest dekodowana i
może być już pobrana trzecia instrukcja itd. Wyraźnie widać, że „głębokość” potoku uzależniona
jest od liczby etapów wykonania instrukcji. Przetwarzanie potokowe umożliwia wytworzenie
wyniku raz na cykl nie raz na kilka cykli jak było to w przypadku procesorów jedno cyklowych.
Struktury wieloprocesorowe
Systemy wieloprocesorowe dzielimy na systemy ze wspólną pamięcią i systemy rozproszone (z systemem połączeń). System z
przesyłaniem komunikatów: N niezależnych procesorów, z których każdy wykonuje własny program. Procesory koordynują pracę
wymieniając komunikaty przez sieć połączeń. System ze wspólną pamięcią: dowolny procesor ma dostęp do dowolnego modułu
pamięci poprzez sieć połączeń. Konflikty przy dostępie do pamięci sprawiają, że wydajność takiego rozwiązania jest ograniczona:
max 4 CPU u Intela.
Rola jednostki zarządzania pamięcią
Jednostka MMU realizuje następujące funkcje:
· Sprzętowa relokacja - zapewnia identyczny wygląd przestrzeni adresowej dla wszystkich procesów
· Ochrona - zabezpieczenie przed odczytem lub modyfikacją kodu i danych nie należących do danego procesu
· Dynamiczna alokacja i dealokacja - powiększanie i zmniejszanie przestrzeni adresowej procesu w czasie jego pracy
· Wirtualizacja - uniezależnienie dostępności pamięci od fizycznej konfiguracji komputera i bieżącego stopnia
wykorzystania pamięci
Hazardy w procesorach potokowych
W przetwarzaniu potokowym mogą wystąpić zależności pomiędzy instrukcjami powodujące
blokady potoku, zwane konfliktami przetwarzania lub po prostu hazardami. Hazardy można
podzielić na trzy zasadnicze grupy:
- konflikty sterowania - zaburzenia sekwencji przetwarzania przy rozgałęzieniach (skokach),
można je minimalizować prognozując rozgałęzienia.
- konflikty danych - użycie tej samej danej przez 2 kolejne instrukcje, gdy wynik drugiej
instrukcji zależy od wartości wytworzonej przez instrukcję poprzednią. Wyróżnia się 4
rodzaje konfliktów danych: RAR(odczyt po odczycie), RAW(odczyt po zapisie), WAR (zpis
po odczycie), WAW(zapis po zapisie). Konflikt RAR występuje w potoku superskalarnym.
Jego usunięcie wymaga dwuportowego dostępu do rejestrów. Metodą zmniejszania strat
wywołanych konfliktem RAW jest skrót (bypass) na ścieżkach przepływu danych. Konflikty
typu „zapis po ...” rozwiązuje się używając do zapisu kilku rejestrów, których wartości są
nieistotne. Równocześnie trzeba śledzić ważność rejestrów i na bieżąco je indeksować.
- konflikty strukturalne (konflikty dostępu) - niemożność spełnienia jednoczesnych żądań
dostępu do unikatowego zasobu ( np. pamięci głównej, pamięci podręcznej, pliku
rejestrowego). Minimalizacja konfliktów strukturalnych wymaga rozbudowy układów, a to
zwiększa koszty procesora i pamięci, a także komplikuje sterowanie.
Kodowanie i dekodowanie rozkazów w typowych architekturach MIPS i IA-32
Aby rozkazy były zrozumiałe dla procesora, należy je zakodować w postaci liczb binarnych. Rozkazy IA-32 mają różną długość,
natomiast MIPS 3000 mają długość 32 bitów. Kod rozkazu jest zwykle podzielony na pola o szczególnym dla procesora znaczeniu.
W pierwszej kolejności koduje się rozkaz, czyli typ działania które ma zostać wykonane. Następnie operandy, które mogą być
adresami lub danymi immediate. Dla łatwiejszego zapisu, używa się notacji szesnastkowej. Postać taką nazywa się kodem
maszynowym. Kodowaniem instrukcji dla architektury IA-32 zajmuje się specjalny program, nazywany asemblerem. W architekturze tej,
rozkazy mogą mieć długość od 1 do nawet kilkunastu bajtów. W celu skrócenia długości rozkazów przyjęto, że pierwszy z argumentów określa również miejsce przeznaczenia, a także tylko jeden z argumentów może odwoływać się do pamięci.
Schemat kodu każdej instrukcji IA-32 możemy podzielić na kilka części: 1. Prefiksy instrukcji (opcjonalne) - do 4 bajtów dodatkowych informacji o instrukcji
2. Kod operacji - 1 do 3 bajtów
3. Bajt ModR/M - służy do określenia położenia operandów
4. Bajt SIB - tylko w przypadku złożonych odwołań do pamięci
5. Pole przesunięcia
6. Dane stałe
Instrukcje MIPS mają zawsze tą samą długość. Zostały opisane w pytaniu nr 6. Należy pamiętać że rozkazy dekodowane są przez układ logiczny, zwany dekoderem rozkazów. Dekoder określa typ rozkazu i
wysyła odpowiednie sygnały sterujące.
Mechanizm podziału pracy procesora: współbieżne wykonywanie programów
Podział czasu polega na tym, że procesor jest przydzielany procesom znajdującym się w pamięci komputera w małych porcjach,
"kwantach". Gdy kwant czasu się kończy, procesor jest przydzielany kolejnemu oczekującemu procesowi. Kwanty czasu są na
tyle małe, że użytkownicy mają wrażenie płynnej interakcji z komputerem. Jednocześnie, dzięki temu, że jeden użytkownik nie
jest w stanie cały czas obciążać procesora, każdy z użytkowników ma wrażenie, że ma do dyspozycji dużą część mocy
obliczeniowej komputera.
Przetwarzanie współbieżne (ang. concurrent computing) - przetwarzanie oparte na współistnieniu wielu wątków lub procesów,
operujących na współdzielonych danych. Wątki uruchomione na tym samym procesorze są przełączane w krótkich przedziałach
czasu, co sprawia wrażenie, że wykonują się równolegle. Przetwarzanie współbieżne znajduje szerokie zastosowanie w
serwerach, które muszą obsługiwać liczne żądania od różnych klientów. Gdyby serwer działał sekwencyjnie, jedno duże żądanie
sparaliżowałoby pracę serwera - pozostałe żądania czekałyby na swoją kolej, aż tamto zostanie ukończone. Jednoczesna praca
na współdzielonych danych może doprowadzić do utraty ich spójności, dlatego konieczne jest stosowanie różnych
mechanizmów synchronizacyjnych, np. semaforów i monitorów. Niektóre języki programowania (np. Erlang, Ada) powstały z
myślą o tworzeniu systemów współbieżnych i zawierają silne wsparcie dla komunikacji lub synchronizacji wątków już na
poziomie języka.
Przerwania diagnostyczne
Przerwanie to sygnał powodujący zmianę przepływu sterowania, niezależnie od aktualnie wykonywanego programu. Pojawienie
się przerwania powoduje wstrzymanie aktualnie wykonywanego programu i wykonanie przez procesor kodu procedury obsługi
przerwania (ang. interrupt handler). Przerwanie jest sytuacją wyjątkową i asynchroniczną. Wystąpienie przerwania powoduje
przekazanie sterowania do systemu operacyjnego. Przerwanie może wywołać np.: zmiana stanu urządzenia. Należy wtedy
wywołać procedurę obsługi przerwania. Przerwania diagnostyczne to pułapki oraz błędy programowe i sprzętowe.
Pułapki - przerwania wykonywane przez instrukcję. Pułapki mogą być wywołaniami usług systemu operacyjnego, sygnalizacją
błędnego wykonania instrukcji, lub pułapkami śledzenia, wykonującymi przerwanie kiedy PC osiągnie daną wartość. Pułapki
mogą być przechwycone przez użytkownika, który może zdefiniować ich obsługę w języku wysokiego poziomu.
Błędy - są przerwaniami generowanymi przez CPU, MMU, lub inne urządzenia (także peryferyjne). Generowane są kiedy wykryty
zostanie błąd transmisji, zdekodowano niedozwoloną instrukcję, odwołanie do pamięci jest błędne, lub gdy naruszone zostaną
zasady ochrony procesora, urządzeń oraz pamięci.
Obsługa przerwań (sytuacji wyjątkowych) polega na przekazaniu sterowania do SO. Rozpoznanie przerwania: po otrzymaniu
sygnału przerwania CPU wysyła do kontrolera przerwań sygnał IntACK. W odpowiedzi urządzenie wystawia na magistralę
adresową identyfikator przerwania. Jest on wykorzystywany jako offset tablicy adresów procedur obsługi przerwań. Adres
procedury obsługi jest wpisywany do PC. Zapamiętanie kontekstu procesora: zapisanie stanu rejestrów które mogą być
zmodyfikowane przez procedurę obsługi. W CISC kopiowanie na stos, w RISC do zestawu rejestrów lustrzanych. Kontekst
procesora jest rekonstruowany po powrocie z procedury obsługi.
Hierarchia pamięci: rola rejestrów, pamięci kieszeniowej, problem spójności danych
W systemach komputerowych ogólnego przeznaczenia wykształciła się następująca hierarchia pamięci:
REJESTRY PROCESORA -> PAMIĘĆ KIESZENIOWA (L1, L2, L3) -> PAMIĘĆ OPERACYJNA
Rejestry są podstawowymi elementami pamięciowymi w procesorze. Dostęp do nich trwa najkrócej. Maja jednak małą
pojemność. Są wykorzystywane do wszelkich operacji na danych jakie wykonuje procesor. Pamięć kieszeniowa nie jest widoczna
w użytkowym modelu programowym. Pełni ona rolę buforu dla pamięci operacyjnej. W dzisiejszych czasach ze względu na
dysproporcje pomiędzy wydajnością procesora a pamięci operacyjnej jest niezbędna. Przy każdym odwołaniu do pamięci
następuje sprawdzenie, czy poszukiwane dane znajdują się w kieszeni. Jeżeli tak - dane zostają odczytane z kieszeni, a odwołanie
RAM jest zbędne. Skraca to znacznie czas odwołania do pamięci. Jeżeli natomiast danych nie ma w kieszeni, zostają one
odczytane z RAMu i przesłane do procesora. Przy okazji są one wysyłane do kieszeni (jeżeli była ona pełna, coś zostaje z niej
usunięte). Przy wystąpieniu następnego odwołania do tych danych będą one już w kieszeni, gotowe to szybkiego odczytania.
Rozróżniamy kieszenie:
· Pełno asocjacyjne: obecnie nie stosowana ze względu na małe pojemności i bardzo dużą trudność w implementacji. Nie
posiada adresów - wyszukiwanie w niej realizowane na zasadzie porównywania danych w kieszeni z wzorcem
dostarczonym z zewnątrz.
· Bezpośrednio adresowane: na bazie zwykłej pamięci RAM i jednego komparatora. Szybka, prosta i wydajna, lecz ma
najmniej intuicyjne działanie.
· Zbiorowo-asocjacyjna: powstaje przez połączenie pewnej liczby kieszeni bezpośrednio adresowanych zwanych blokami.
W każdym cyklu dostępu następuje wyszukiwanie pojedynczej linii każdego z bloków. Zestaw linii wybieranych w
każdym cyklu nazywany jest zbiorem, a każdy zbiór zachowuje się jak mała pamięć pełno asocjacyjna.
· Do 2000 roku stosowane były pamięci inkluzywne: dane zawarte w kieszeniach wyższego poziomu były obecne również
w niższej.
· Po 2000 zastosowano pamięci wyłączne: kieszeń wyższego poziomu napełniana jest obiektami wyłącznie usuwanymi z
pamięci poziomu niższego.
Ze względu na to, że pojedyncza kieszeń nie jest w stanie zniwelować różnic w wydajności procesora i RAMu, powstała
hierarchia pamięci kieszeniowych L1 -> L2 -> L3, z których każda następna (dalej od procesora) ma większą pojemność, ale
dłuższy czas dostępu do danych.
Opisaną powyżej hierarchię pamięci musi cechować spójność - każdy dostęp do adresu pamięci musi zwrócić tę samą wartość,
bez względu w której warstwie kieszeni jest ona aktualnie przechowywana. Problem z utrzymaniem spójności powstaje gdy
istnieje więcej niż jedna ścieżka dostępu do hierarchii pamięci, np.:
· Istnieją oddzielne kieszenie dla danych i dla kodu (jak w architekturze Harvard-Princeton)
· Istnieje system wieloprocesorowy, w którym każdy procesor ma swoją kieszeń L1, a dalsza hierarchia jest wspólna
· Procesor z kieszenią i sterownik I/O wykonujący bezpośrednie dostępy do pamięci, bez korzystania z kieszeni
Istnieją metody utrzymywania spójności:
· Unieważnienie całej kieszeni przy wykryciu odwołania zewnętrznego (stosowane dawniej, przy małych kieszeniach)
· Unieważnienie linii potencjalnie zawierających odwołanie pod zewnętrzny adres (w pojemnościach do kilku KB)
· Unieważnienie programowe całej kieszeni (ograniczone zastosowanie z powodu spadku wydajności)
· Selektywna zmiana stanu linii po stwierdzeniu zgodności adresu przesłania między kieszeniami (współcześnie używane,
wydajne, ale złożone w realizacji): stany linii:
o M - modified - linia ważna, zawartość nieaktualna
o E - exclusive - linia ważna, zawartość identyczna
o I - invalid - linia nieważna
o S - shared - linia ważna, identyczna kopia z pamięcią u wszystkich
o O - owned - linia ważna, jednakowa kopia u wszystkich, zawartość pamięci nie aktualna
.