Architektura Komputerów/Wykład 4: Struktura modelu programowego: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Akokno (dyskusja | edycje)
Nie podano opisu zmian
Akokno (dyskusja | edycje)
Nie podano opisu zmian
 
(Nie pokazano 1 pośredniej wersji utworzonej przez tego samego użytkownika)
Linia 3: Linia 3:
|valign="top" width="500px"|[[Grafika:ASK_M4_S01.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S01.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}


Linia 10: Linia 10:
|valign="top" width="500px"|[[Grafika:ASK_M4_S02.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S02.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 16: Linia 16:
|valign="top" width="500px"|[[Grafika:ASK_M4_S03.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S03.png]]
|valign="top"|  
|valign="top"|  
...
Użytkowy  model programowy – to zbiór zasobów logicznych komputera widzianych przez programistę lub kompilator. Model programowy nie ma jednoznacznego i bezpośredniego związku z implementacją, czyli budową procesora i komputera. Istnieje wiele rodzin komputerów czy procesorów o wspólnym modelu programowym i wielu odmiennych implementacjach. Przykładem może to być rodzina x86 (zapoczątkowana w 1976 roku) lub IBM zSeries, wywodząca się z lat 60-tych XX wieku.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 22: Linia 22:
|valign="top" width="500px"|[[Grafika:ASK_M4_S04.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S04.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 28: Linia 28:
|valign="top" width="500px"|[[Grafika:ASK_M4_S05.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S05.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 34: Linia 34:
|valign="top" width="500px"|[[Grafika:ASK_M4_S06.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S06.png]]
|valign="top"|  
|valign="top"|  
...
Rejestry procesora mogą pełnić różne role w programach.
 
Akumulatorem nazywamy rejestr, który może być użyty jako argument źródła i równocześnie przeznaczenia dla operacji arytmetycznej lub logicznej.
 
Rejestr służący do uzyskania adresu danej umieszczonej w pamięci nazywa się ogólnie rejestrem adresowym. Jeśli rejestr może być użyty w trybie adresowania rejestrowym pośrednim, jest on nazywany rejestrem bazowym.
 
Rejestr może również służyć do odliczania iteracji pętli. Rejestr przewidziany do takiego zastosowania nazywa się licznikiem pętli.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 40: Linia 46:
|valign="top" width="500px"|[[Grafika:ASK_M4_S07.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S07.png]]
|valign="top"|  
|valign="top"|  
...
istnieje wiele różnych koncepcji organizacji zestawu rejestrów – począwszy od architektur bezrejestrowych a skończywszy na architekturach z bardzo dużym zestawem rejestrów o liczebności przekraczającej 100.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 46: Linia 52:
|valign="top" width="500px"|[[Grafika:ASK_M4_S08.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S08.png]]
|valign="top"|  
|valign="top"|  
...
Architektury bezrejestrowe, określane również mianem „pamięć-pamięć”, nie przechowują danych w rejestrach procesora. Procesor jest wyposażony w kilka rejestrów, które służą wyłącznie do przechowywania adresów.
 
Szczególną postacią architektury bezrejestrowej jest architektura MOVE. W architekturach tego typu procesor wykonuje tylko jedną lub co najwyżej kilka instrukcji, których argumentami mogą być wyłącznie stałe lub adresy pamięci. operacje arytmetyczne i logiczne są realizowane poprzez przesłania do specjalnych lokacji pamięci, służących jako rejestry argumentów. Adresy tych lokacji są używane do wyboru operacji wykonywanej przez jednostkę arytmetyczną.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 52: Linia 60:
|valign="top" width="500px"|[[Grafika:ASK_M4_S09.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S09.png]]
|valign="top"|  
|valign="top"|  
...
Architektury z minimalnym zestawem rejestrów posiadają jeden lub dwa akumulatory i jeden lub dwa rejestry adresowe. niemal wszystkie instrukcje wymagają odwołania do pamięci, ale jeden z argumentów instrukcji zwykle znajduje się w rejestrze. Generowanie kodu dla takich procesorów jest proste, ale uzyskany program wykonuje się stosunkowo wolno wskutek dużej liczby odwołań do pamięci.
 
Architektury tego typu nie są stosowane w komputerach uniwersalnych, były one natomiast popularne w mikrokontrolerach.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 58: Linia 68:
|valign="top" width="500px"|[[Grafika:ASK_M4_S10.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S10.png]]
|valign="top"|  
|valign="top"|  
...
Rysunek przedstawia zestaw rejestrów jednostki wykonawczej mikrokontrolera rodziny HC08. Argumenty i zmienne lokalne procedur są tu adresowana względem wskaźnika stosu, a wielofunkcyjny rejestr HX służy jako rozszerzenie akumulatora dla operacji mnożenia i dzielenia, rejestr adresowy i licznik pętli. Podstawowym akumulatorem jest rejestr A.
 
Mały zestaw rejestrów wymusza umieszczanie niektórych zmiennych roboczych (tymczasowych) w pamięci.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 64: Linia 76:
|valign="top" width="500px"|[[Grafika:ASK_M4_S11.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S11.png]]
|valign="top"|  
|valign="top"|  
...
W architekturach z małym zestawem rejestrów specjalizowanych mamy do czynienia z zestawem kilku rejestrów, niekiedy częściowo uniwersalnych, które są argumentami domyślnymi wielu specyficznych instrukcji.
 
Ponieważ kompilator używa czasem instrukcji, których argumenty muszą być umieszczone w konkretnych rejestrach, rejestry nie mogą być użyte do przechowywania danych programu (argumentów i zmiennych lokalnych procedur). Służą one jedynie do przechowywania tymczasowych wyników obliczeń oraz jako argumenty instrukcji, z którymi są domyślnie związane.
 
Pomimo, że pojemność zestawu rejestrów jest znacząca, kompilator nie jest w stanie efektywnie korzystać z rejestrów.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 70: Linia 86:
|valign="top" width="500px"|[[Grafika:ASK_M4_S12.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S12.png]]
|valign="top"|  
|valign="top"|  
...
Rysunek przedstawia zestaw podstawowych rejestrów jednostki stałopozycyjnej 16-bitowej wersji architektury x86, zapoczątkowanej modelem Intel 8086 w 1976 roku. Poszczególne 16-bitowe rejestry są „przywiązane” do niektórych instrukcji. Tylko cztery rejestry mogą być używane jako adresowe.
 
Stosunkowo najbardziej uniwersalnymi rejestrami są SI i DI, ale ich użycie jest ograniczone przez fakt, że nie jest dostępny ich najmniej znaczący bajt. Niektóre bardziej zaawansowane kompilatory dla x86 używały tych dwóch rejestrów do alokacji zmiennych lokalnych procedury.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 76: Linia 94:
|valign="top" width="500px"|[[Grafika:ASK_M4_S13.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S13.png]]
|valign="top"|  
|valign="top"|  
...
W architekturach z małym zestawem rejestrów uniwersalnych mamy do czynienia z zestawem około 8 rejestrów, z których przynajmniej 5 daje się użyć w dowolnym charakterze – jako akumulatory lub rejestry adresowe.
 
Przykładem jest tu 32-bitowa wersja x86, zapoczątkowana przez model 80386 w roku 1985. Rejestry  odziedziczone po wersji 16-bitowej zostały rozszerzone do 32 bitów. Wprowadzono również nowy zestaw trybów adresowania, umożliwiający wykorzystanie do adresowania wszystkich rejestrów. Wprowadzenie nowych instrukcji mnożenia umożliwiło zmniejszenie „przywiązania rejestrów do instrukcji. W ten sposób, pomimo, że na pierwszy rzut oka model programowy wygląda bardzo podobnie do wcześniejszych wersji, kompilator może używać rejestrów znacznie elastyczniej niż we wcześniejszych procesorach tej rodziny.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 82: Linia 102:
|valign="top" width="500px"|[[Grafika:ASK_M4_S14.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S14.png]]
|valign="top"|  
|valign="top"|  
...
W architekturach z dużym zestawem rejestrów mamy do czynienia z wieloma rejestrami, które mogł pełnić dowolną rolę. Umożliwia to kompilatorom używanie rejestrów do przekazywania argumentów wywołania i zmiennych lokalnych procedury.
 
Odwołania do pamięci zostają skupione w prologu i epilogu procedury, gdzie zachodzi przeładowanie ramki stosu pomiędzy rejestrami i stosem w pamięci.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 88: Linia 110:
|valign="top" width="500px"|[[Grafika:ASK_M4_S15.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S15.png]]
|valign="top"|  
|valign="top"|  
...
W niektórych architekturach bardzo duży zestaw rejestrów jest używany do zbuforowania wewnątrz procesora wierzchołka stosu umieszczonego w pamięci. W ten sposób uzyskuje się znaczną redukcję liczby odwołań do pamięci, również w prologu i epilogu procedury.
 
Ponieważ zestaw rejestrów mieści kilka ramek stosu, odwołania do pamięci zachodzą przy przepełnieniu lub niedopełnieniu stosu w rejestrach, co ma miejsce raz na kilka poziomów wywołań procedur.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 94: Linia 118:
|valign="top" width="500px"|[[Grafika:ASK_M4_S16.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S16.png]]
|valign="top"|  
|valign="top"|  
...
W architekturach ze stosowym zestawem rejestrów rejestry są zorganizowane w postaci niewielkiego stosu. Ponieważ operacje są domyślnie wykonywane na wierzchołku stosu, procesory o takich zestawach rejestrów mają zwykle instrukcje bezargumentowe lub jednoargumentowe.
 
Taka architektura zestawu rejestrów znacząco upraszcza konstrukcję kompilatora, jest ona jednak bardzo trudna do efektywnej realizacji przy typowych współczesnych strukturach jednostek wykonawczych.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 100: Linia 126:
|valign="top" width="500px"|[[Grafika:ASK_M4_S17.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S17.png]]
|valign="top"|  
|valign="top"|  
...
Drugim elementem modelu programowego jest zestaw trybów adresowania. Samo pojęcie trybu adresowania ma dwa znaczenia.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 106: Linia 132:
|valign="top" width="500px"|[[Grafika:ASK_M4_S18.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S18.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 112: Linia 138:
|valign="top" width="500px"|[[Grafika:ASK_M4_S19.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S19.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 118: Linia 144:
|valign="top" width="500px"|[[Grafika:ASK_M4_S20.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S20.png]]
|valign="top"|  
|valign="top"|  
...
Można zauważyć, że w celu umożliwienia efektywnej implementacji języków wysokiego poziomu procesor powinien posiadać trzy tryby adresowania.
 
Tryb natychmiastowy służy do ładowania do rejestrów stałych, w tym również adresów danych statycznych. Tryb rejestrowy bezpośredni umożliwia użycie zawartości rejestru jako argumentu operacji. Do adresowania danych w pamięci wystarczy jeden z trybów rejestrowych pośrednich. W ten sposób uzyskujemy możliwość adresowania zmiennym adresem, wyliczonym uprzednio w rejestrze. Adresowanie danych stałym adresem może być potraktowane jako szczególny przypadek adresowania ze zmiennym adresem. Najwygodniejszym trybem adresowania pamięci jest tryb rejestrowy pośredni z przemieszczeniem.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 124: Linia 152:
|valign="top" width="500px"|[[Grafika:ASK_M4_S21.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S21.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 130: Linia 158:
|valign="top" width="500px"|[[Grafika:ASK_M4_S22.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S22.png]]
|valign="top"|  
|valign="top"|  
...
Tryby rejestrowe pośrednie z bazą w liczniku instrukcji umożliwiają adresowanie danych względem adresu bieżącej instrukcji. Mogą one być używane do adresowania danych wplecionych w kod i logicznie należących do kodu programu (np. tablice adresów). W procesorach 64-bitowych tryby te umożliwiają ograniczenie długości adresów absolutnych zawartych w zapisie instrukcji, gdyż dane, przynajmniej statyczne, są zwykle położone niezbyt daleko od kodu programu. (W przeciwnym razie zamiast 32-bitowych przemieszczeń względem PC do adresowania danych należałoby używać 64-bitowych adresów absolutnych.)
 
Problem obliczania zmieniających się z każdą instrukcją przemieszczeń danych liczonych względem PC przejmuje na siebie asembler.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 136: Linia 166:
|valign="top" width="500px"|[[Grafika:ASK_M4_S23.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S23.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 142: Linia 172:
|valign="top" width="500px"|[[Grafika:ASK_M4_S24.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S24.png]]
|valign="top"|  
|valign="top"|  
...
 
|}
|}
<hr width="100%">
<hr width="100%">
Linia 148: Linia 178:
|valign="top" width="500px"|[[Grafika:ASK_M4_S25.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S25.png]]
|valign="top"|  
|valign="top"|  
...
W trybach pamięciowych pośrednich jeden z elementów adresu jest pobierany z pamięci, a uzyskany adres jest wykorzystywany do odwołania do danej w pamięci. Odwołanie do danej wymaga więc dwukrotnego sięgnięcia do pamięci.
 
W trybach pamięciowych pośrednich występują dwa adresy efektywne, do obliczenia których można korzystać z operacji indeksowania lub dodawania przemieszczenia. Pierwszy adres, wyznaczony z jednego z omówionych wcześniej trybów adresowania pamięci, jest używany do odczytania wartości, służącej jako adres bazowy dla drugiego adresu. Do pozyskanego w ten sposób adresu bazowego można następnie dodać przemieszczenie lub przeskalowaną zawartość rejestru indeksowego.
 
Tryby pamięciowe pośrednie były charakterystyczne dla złożonych architektur CISC. Obecnie są one rzadko spotykane, gdyż opisana sekwencja operacji może być łatwo, a zarazem w sposób bardziej elastyczny, zrealizowana na drodze programowej.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 154: Linia 188:
|valign="top" width="500px"|[[Grafika:ASK_M4_S26.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S26.png]]
|valign="top"|  
|valign="top"|  
...
Model operacji warunkowych jest trzecim składnikiem modelu programowego. Współczesne procesory implementują jeden z trzech modeli opisanych w dalszym ciągu wykładu.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 160: Linia 194:
|valign="top" width="500px"|[[Grafika:ASK_M4_S27.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S27.png]]
|valign="top"|  
|valign="top"|  
...
Model ze znacznikami wprowadza dwufazową realizację operacji warunkowych, przy czym instrukcje procesora realizujące obie fazy mogą być rozsunięte w czasie.
 
W pierwszej fazie w wyniku wykonania operacji arytmetycznej lub logicznej zostają ustawione znaczniki – jednobitowe rejestry atrybutów wyniku. W drugiej fazie następuje wykonanie operacji zależne od stanu znaczników.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 166: Linia 202:
|valign="top" width="500px"|[[Grafika:ASK_M4_S28.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S28.png]]
|valign="top"|  
|valign="top"|  
...
W poszczególnych architekturach występuje od dwóch do sześciu znaczników. typowa liczba znaczników wynosi 4.Dwa ostatnie – przeniesienie pomocnicze i parzystość, występują głównie w architekturach wywodzących się z lat 70-tych XX wieku.
 
Znacznik przeniesienia pomocniczego wspomaga realizację operacji na liczbach zapisanych w kodzie BCD. Przechowuje on wartość przeniesienia pomiędzy tetradami pojedynczego bajtu reprezentującymi cyfry dziesiętne.
 
Znacznik parzystości był używany do podstawowej kontroli poprawności transmisji danych znakowych w kodzie ASCII, w tym do kontroli danych odczytywanych z taśm perforowanych. Nawet w procesorach 32- i 64-bitowych znacznik parzystości zawsze dotyczy wyłącznie najmniej znaczącego bajtu wyniku operacji.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 172: Linia 212:
|valign="top" width="500px"|[[Grafika:ASK_M4_S29.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S29.png]]
|valign="top"|  
|valign="top"|  
...
Ponieważ w różnych architekturach obowiązują różne konwencje ustawiania znaczników, rozpoczynając programowanie procesora w asemblerze należy dokładnie zapoznać się z dokumentacją poszczególnych instrukcji.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 178: Linia 218:
|valign="top" width="500px"|[[Grafika:ASK_M4_S30.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S30.png]]
|valign="top"|  
|valign="top"|  
...
Instrukcja warunkowa realizuje drugą fazę operacji warunkowej w modelu ze znacznikami. Jest to instrukcja, której sposób wykonania zależy od wartości znaczników. Instrukcja warunkowa specyfikuje warunek wykonania. Jeśli warunek (wyrażenie logiczne na znacznikach) jest spełniony, instrukcja wykonuje zadaną operację (np. skok lub przesłanie). W przeciwnym razie instrukcja wykonuje się jako pusta.
 
Instrukcja ustawienia danej (np. SETcc w x86) wpisuje do rejestru wartość logiczną warunku wyrażoną jako stałą całkowitą.
 
W niektórych architekturach większość instrukcji jest wykonywanych jako warunkowe.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 184: Linia 228:
|valign="top" width="500px"|[[Grafika:ASK_M4_S31.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S31.png]]
|valign="top"|  
|valign="top"|  
...
Warunek wykonania jest jednym z predefiniowanych w danej architekturze wyrażeń logicznych na znacznikach. Poszczególne warunki mają swoje nazwy mnemoniczne.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 190: Linia 234:
|valign="top" width="500px"|[[Grafika:ASK_M4_S32.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S32.png]]
|valign="top"|  
|valign="top"|  
...
Rysunek przedstawia rozmieszczenie znaczników w rejestrze stanu procesorów rodziny x86.
|}
|}
<hr width="100%">
<hr width="100%">
Linia 196: Linia 240:
|valign="top" width="500px"|[[Grafika:ASK_M4_S33.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S33.png]]
|valign="top"|  
|valign="top"|  
...
Tabela zawiera nazwy symboliczne warunków dostępnych w x86 i specyfikację odpowiadających im wyrażeń logicznych na znacznikach.
 
Należy zwrócić uwagę na istnienie wielu nazw tych samych warunków, co ułatwia ich użycie w programach.
 
Stosowane w nazwach warunków skróty A, B, G i L (above, below, greater, less) oznaczają odpowiednio relacje większości i mniejszości dla liczb bez znaku (A, B) i ze znakiem (G, L).
|}
|}
<hr width="100%">
<hr width="100%">
Linia 202: Linia 250:
|valign="top" width="500px"|[[Grafika:ASK_M4_S34.png]]
|valign="top" width="500px"|[[Grafika:ASK_M4_S34.png]]
|valign="top"|  
|valign="top"|  
...
W modelu operacji warunkowych bez znaczników operacja warunkowa jest realizowana przez pojedynczą instrukcję. instrukcja ta ewaluuje wartość logiczną relacji, a następnie wykonuje jakąś czynność, jeśli relacja jest spełniona.
 
Taki model operacji warunkowych jest prosty i wydajny w implementacji. jest on stosowany w prostych architekturach RISCowych.
|}
<hr width="100%">
{| border="0" cellpadding="4" width="100%"
|valign="top" width="500px"|[[Grafika:ASK_M4_S35.png]]
|valign="top"|
Model z predykatami jest spotykany w nowych architekturach o dużej równoległości wykonania instrukcji, dużych zestawach rejestrów i wysokich kosztach skoków. praktycznie jedyną architekturą komercyjną implementującą ten model jest IA-64.
|}
|}

Aktualna wersja na dzień 16:32, 10 paź 2006




Użytkowy model programowy – to zbiór zasobów logicznych komputera widzianych przez programistę lub kompilator. Model programowy nie ma jednoznacznego i bezpośredniego związku z implementacją, czyli budową procesora i komputera. Istnieje wiele rodzin komputerów czy procesorów o wspólnym modelu programowym i wielu odmiennych implementacjach. Przykładem może to być rodzina x86 (zapoczątkowana w 1976 roku) lub IBM zSeries, wywodząca się z lat 60-tych XX wieku.




Rejestry procesora mogą pełnić różne role w programach.

Akumulatorem nazywamy rejestr, który może być użyty jako argument źródła i równocześnie przeznaczenia dla operacji arytmetycznej lub logicznej.

Rejestr służący do uzyskania adresu danej umieszczonej w pamięci nazywa się ogólnie rejestrem adresowym. Jeśli rejestr może być użyty w trybie adresowania rejestrowym pośrednim, jest on nazywany rejestrem bazowym.

Rejestr może również służyć do odliczania iteracji pętli. Rejestr przewidziany do takiego zastosowania nazywa się licznikiem pętli.


istnieje wiele różnych koncepcji organizacji zestawu rejestrów – począwszy od architektur bezrejestrowych a skończywszy na architekturach z bardzo dużym zestawem rejestrów o liczebności przekraczającej 100.


Architektury bezrejestrowe, określane również mianem „pamięć-pamięć”, nie przechowują danych w rejestrach procesora. Procesor jest wyposażony w kilka rejestrów, które służą wyłącznie do przechowywania adresów.

Szczególną postacią architektury bezrejestrowej jest architektura MOVE. W architekturach tego typu procesor wykonuje tylko jedną lub co najwyżej kilka instrukcji, których argumentami mogą być wyłącznie stałe lub adresy pamięci. operacje arytmetyczne i logiczne są realizowane poprzez przesłania do specjalnych lokacji pamięci, służących jako rejestry argumentów. Adresy tych lokacji są używane do wyboru operacji wykonywanej przez jednostkę arytmetyczną.


Architektury z minimalnym zestawem rejestrów posiadają jeden lub dwa akumulatory i jeden lub dwa rejestry adresowe. niemal wszystkie instrukcje wymagają odwołania do pamięci, ale jeden z argumentów instrukcji zwykle znajduje się w rejestrze. Generowanie kodu dla takich procesorów jest proste, ale uzyskany program wykonuje się stosunkowo wolno wskutek dużej liczby odwołań do pamięci.

Architektury tego typu nie są stosowane w komputerach uniwersalnych, były one natomiast popularne w mikrokontrolerach.


Rysunek przedstawia zestaw rejestrów jednostki wykonawczej mikrokontrolera rodziny HC08. Argumenty i zmienne lokalne procedur są tu adresowana względem wskaźnika stosu, a wielofunkcyjny rejestr HX służy jako rozszerzenie akumulatora dla operacji mnożenia i dzielenia, rejestr adresowy i licznik pętli. Podstawowym akumulatorem jest rejestr A.

Mały zestaw rejestrów wymusza umieszczanie niektórych zmiennych roboczych (tymczasowych) w pamięci.


W architekturach z małym zestawem rejestrów specjalizowanych mamy do czynienia z zestawem kilku rejestrów, niekiedy częściowo uniwersalnych, które są argumentami domyślnymi wielu specyficznych instrukcji.

Ponieważ kompilator używa czasem instrukcji, których argumenty muszą być umieszczone w konkretnych rejestrach, rejestry nie mogą być użyte do przechowywania danych programu (argumentów i zmiennych lokalnych procedur). Służą one jedynie do przechowywania tymczasowych wyników obliczeń oraz jako argumenty instrukcji, z którymi są domyślnie związane.

Pomimo, że pojemność zestawu rejestrów jest znacząca, kompilator nie jest w stanie efektywnie korzystać z rejestrów.


Rysunek przedstawia zestaw podstawowych rejestrów jednostki stałopozycyjnej 16-bitowej wersji architektury x86, zapoczątkowanej modelem Intel 8086 w 1976 roku. Poszczególne 16-bitowe rejestry są „przywiązane” do niektórych instrukcji. Tylko cztery rejestry mogą być używane jako adresowe.

Stosunkowo najbardziej uniwersalnymi rejestrami są SI i DI, ale ich użycie jest ograniczone przez fakt, że nie jest dostępny ich najmniej znaczący bajt. Niektóre bardziej zaawansowane kompilatory dla x86 używały tych dwóch rejestrów do alokacji zmiennych lokalnych procedury.


W architekturach z małym zestawem rejestrów uniwersalnych mamy do czynienia z zestawem około 8 rejestrów, z których przynajmniej 5 daje się użyć w dowolnym charakterze – jako akumulatory lub rejestry adresowe.

Przykładem jest tu 32-bitowa wersja x86, zapoczątkowana przez model 80386 w roku 1985. Rejestry odziedziczone po wersji 16-bitowej zostały rozszerzone do 32 bitów. Wprowadzono również nowy zestaw trybów adresowania, umożliwiający wykorzystanie do adresowania wszystkich rejestrów. Wprowadzenie nowych instrukcji mnożenia umożliwiło zmniejszenie „przywiązania rejestrów do instrukcji. W ten sposób, pomimo, że na pierwszy rzut oka model programowy wygląda bardzo podobnie do wcześniejszych wersji, kompilator może używać rejestrów znacznie elastyczniej niż we wcześniejszych procesorach tej rodziny.


W architekturach z dużym zestawem rejestrów mamy do czynienia z wieloma rejestrami, które mogł pełnić dowolną rolę. Umożliwia to kompilatorom używanie rejestrów do przekazywania argumentów wywołania i zmiennych lokalnych procedury.

Odwołania do pamięci zostają skupione w prologu i epilogu procedury, gdzie zachodzi przeładowanie ramki stosu pomiędzy rejestrami i stosem w pamięci.


W niektórych architekturach bardzo duży zestaw rejestrów jest używany do zbuforowania wewnątrz procesora wierzchołka stosu umieszczonego w pamięci. W ten sposób uzyskuje się znaczną redukcję liczby odwołań do pamięci, również w prologu i epilogu procedury.

Ponieważ zestaw rejestrów mieści kilka ramek stosu, odwołania do pamięci zachodzą przy przepełnieniu lub niedopełnieniu stosu w rejestrach, co ma miejsce raz na kilka poziomów wywołań procedur.


W architekturach ze stosowym zestawem rejestrów rejestry są zorganizowane w postaci niewielkiego stosu. Ponieważ operacje są domyślnie wykonywane na wierzchołku stosu, procesory o takich zestawach rejestrów mają zwykle instrukcje bezargumentowe lub jednoargumentowe.

Taka architektura zestawu rejestrów znacząco upraszcza konstrukcję kompilatora, jest ona jednak bardzo trudna do efektywnej realizacji przy typowych współczesnych strukturach jednostek wykonawczych.


Drugim elementem modelu programowego jest zestaw trybów adresowania. Samo pojęcie trybu adresowania ma dwa znaczenia.




Można zauważyć, że w celu umożliwienia efektywnej implementacji języków wysokiego poziomu procesor powinien posiadać trzy tryby adresowania.

Tryb natychmiastowy służy do ładowania do rejestrów stałych, w tym również adresów danych statycznych. Tryb rejestrowy bezpośredni umożliwia użycie zawartości rejestru jako argumentu operacji. Do adresowania danych w pamięci wystarczy jeden z trybów rejestrowych pośrednich. W ten sposób uzyskujemy możliwość adresowania zmiennym adresem, wyliczonym uprzednio w rejestrze. Adresowanie danych stałym adresem może być potraktowane jako szczególny przypadek adresowania ze zmiennym adresem. Najwygodniejszym trybem adresowania pamięci jest tryb rejestrowy pośredni z przemieszczeniem.



Tryby rejestrowe pośrednie z bazą w liczniku instrukcji umożliwiają adresowanie danych względem adresu bieżącej instrukcji. Mogą one być używane do adresowania danych wplecionych w kod i logicznie należących do kodu programu (np. tablice adresów). W procesorach 64-bitowych tryby te umożliwiają ograniczenie długości adresów absolutnych zawartych w zapisie instrukcji, gdyż dane, przynajmniej statyczne, są zwykle położone niezbyt daleko od kodu programu. (W przeciwnym razie zamiast 32-bitowych przemieszczeń względem PC do adresowania danych należałoby używać 64-bitowych adresów absolutnych.)

Problem obliczania zmieniających się z każdą instrukcją przemieszczeń danych liczonych względem PC przejmuje na siebie asembler.




W trybach pamięciowych pośrednich jeden z elementów adresu jest pobierany z pamięci, a uzyskany adres jest wykorzystywany do odwołania do danej w pamięci. Odwołanie do danej wymaga więc dwukrotnego sięgnięcia do pamięci.

W trybach pamięciowych pośrednich występują dwa adresy efektywne, do obliczenia których można korzystać z operacji indeksowania lub dodawania przemieszczenia. Pierwszy adres, wyznaczony z jednego z omówionych wcześniej trybów adresowania pamięci, jest używany do odczytania wartości, służącej jako adres bazowy dla drugiego adresu. Do pozyskanego w ten sposób adresu bazowego można następnie dodać przemieszczenie lub przeskalowaną zawartość rejestru indeksowego.

Tryby pamięciowe pośrednie były charakterystyczne dla złożonych architektur CISC. Obecnie są one rzadko spotykane, gdyż opisana sekwencja operacji może być łatwo, a zarazem w sposób bardziej elastyczny, zrealizowana na drodze programowej.


Model operacji warunkowych jest trzecim składnikiem modelu programowego. Współczesne procesory implementują jeden z trzech modeli opisanych w dalszym ciągu wykładu.


Model ze znacznikami wprowadza dwufazową realizację operacji warunkowych, przy czym instrukcje procesora realizujące obie fazy mogą być rozsunięte w czasie.

W pierwszej fazie w wyniku wykonania operacji arytmetycznej lub logicznej zostają ustawione znaczniki – jednobitowe rejestry atrybutów wyniku. W drugiej fazie następuje wykonanie operacji zależne od stanu znaczników.


W poszczególnych architekturach występuje od dwóch do sześciu znaczników. typowa liczba znaczników wynosi 4.Dwa ostatnie – przeniesienie pomocnicze i parzystość, występują głównie w architekturach wywodzących się z lat 70-tych XX wieku.

Znacznik przeniesienia pomocniczego wspomaga realizację operacji na liczbach zapisanych w kodzie BCD. Przechowuje on wartość przeniesienia pomiędzy tetradami pojedynczego bajtu reprezentującymi cyfry dziesiętne.

Znacznik parzystości był używany do podstawowej kontroli poprawności transmisji danych znakowych w kodzie ASCII, w tym do kontroli danych odczytywanych z taśm perforowanych. Nawet w procesorach 32- i 64-bitowych znacznik parzystości zawsze dotyczy wyłącznie najmniej znaczącego bajtu wyniku operacji.


Ponieważ w różnych architekturach obowiązują różne konwencje ustawiania znaczników, rozpoczynając programowanie procesora w asemblerze należy dokładnie zapoznać się z dokumentacją poszczególnych instrukcji.


Instrukcja warunkowa realizuje drugą fazę operacji warunkowej w modelu ze znacznikami. Jest to instrukcja, której sposób wykonania zależy od wartości znaczników. Instrukcja warunkowa specyfikuje warunek wykonania. Jeśli warunek (wyrażenie logiczne na znacznikach) jest spełniony, instrukcja wykonuje zadaną operację (np. skok lub przesłanie). W przeciwnym razie instrukcja wykonuje się jako pusta.

Instrukcja ustawienia danej (np. SETcc w x86) wpisuje do rejestru wartość logiczną warunku wyrażoną jako stałą całkowitą.

W niektórych architekturach większość instrukcji jest wykonywanych jako warunkowe.


Warunek wykonania jest jednym z predefiniowanych w danej architekturze wyrażeń logicznych na znacznikach. Poszczególne warunki mają swoje nazwy mnemoniczne.


Rysunek przedstawia rozmieszczenie znaczników w rejestrze stanu procesorów rodziny x86.


Tabela zawiera nazwy symboliczne warunków dostępnych w x86 i specyfikację odpowiadających im wyrażeń logicznych na znacznikach.

Należy zwrócić uwagę na istnienie wielu nazw tych samych warunków, co ułatwia ich użycie w programach.

Stosowane w nazwach warunków skróty A, B, G i L (above, below, greater, less) oznaczają odpowiednio relacje większości i mniejszości dla liczb bez znaku (A, B) i ze znakiem (G, L).


W modelu operacji warunkowych bez znaczników operacja warunkowa jest realizowana przez pojedynczą instrukcję. instrukcja ta ewaluuje wartość logiczną relacji, a następnie wykonuje jakąś czynność, jeśli relacja jest spełniona.

Taki model operacji warunkowych jest prosty i wydajny w implementacji. jest on stosowany w prostych architekturach RISCowych.


Model z predykatami jest spotykany w nowych architekturach o dużej równoległości wykonania instrukcji, dużych zestawach rejestrów i wysokich kosztach skoków. praktycznie jedyną architekturą komercyjną implementującą ten model jest IA-64.