1. Reprezentacje danych na poziomie maszynowym: kodowanie liczb całkowitych i
rzeczywistych oraz znaków (zasady reprezentacji i standardy kodowania)
Liczby całkowite mogą być reprezentowane jako unsigned (bez znaku) lub signed (ze
znakiem). Liczby całkowite bez znaku są zapisywane w naturalnym kodzie binarnym. Największa
liczba jaką można w ten sposób zapisać na n-bitach wynosi 2^n - 1.
Liczby całkowite ze znakiem reprezentowane są w kodzie uzupełnienia dwójkowego U2.
Najstarszy bit jest bitem znaku, gdzie 0 oznacza liczbę dodatnią, a 1 ujemną. Pozostałe bity służą do
zapisu liczby. Liczbę dodatnią tworzy się tak jak w przypadku liczb całkowitych bez znaku,
maksymalna wartość to 2^(n-1) - 1. Liczba ujemną można zapisać kilkoma metodami np. poprzez
inwersje bitów liczby przeciwnej i dodanie do rezultatu jedynki. Najmniejsza liczba całkowita
ujemna jaką można zapisać na n bitach to -2^(n-1).
Standard kodowania liczb zmiennoprzecinkowych to IEEE 754. W zapisie tym można
wyróżnić bit znaku, cechę i mantysę. Rozróżniane są także dwa formaty znormalizowany i
zdenormalizowany. Ten drugi format służy do zapisu liczb bliskich zeru, pierwszy do zapisu
wszystkich pozostałych.
Znaki reprezentowane są w standardzie ASCII lub rozszerzonym standardzie UNICODE. W
ASCII każdy znak ma odpowiadający mu 7-bitowy kod binarny. Same znaki mają kody od 32 do
126. Pozostałe są przypisane do różnych poleceń sterujących. W kodzie maszynowym znaki, są
zapisywane na 8 bitach, więc 8 bit posłużył do powstania wielu rozszerzeń kodu ASCII. Istnieje
także 32 bitowy standard UNICODE, który w założeniu ma zawierać znaki wszystkich pism
używanych na świecie.
2. Automatyzacja arytmetycznych i logicznych operacji na danych: budowa i działanie ALU
ALU (Aritmetic Logic Unit) – to układ cyfrowy którego zadaniem jest wykonywanie
operacji arytmetycznych i logicznych. Projektowaliśmy ALU na zajęciach laboratoryjnych z
Techniki Cyfrowej. Wyposażone było w dwa 8-bitowe wejścia danych i 3-bitowe wejście kodu
operacji oraz w trzy wyjścia, tzn. 8-bitowe wyjście danych(wynik operacji) i 1- bitowe
sygnalizatory przeniesienia i przepełnienia(cout i overflow).
Na tak zaprojektowane ALU składały się 8-bitowe extender i sumator. Extender był
zbudowany z 8 1-bitowych abextenderów, które w oparciu o kod operacji i bity wejściowe A i B
wyznaczały wyjściowe wartości A i B zgodnie z zaprojektowaną tablicą prawdy, oraz układu
kombinacyjnego, który na podstawie kodu operacji zwracał 1 bądź 0. Dwie 8-bitowe liczby i bit cin
przygotowane przez extender trafiały do sumatora, który gdzie ustalane były wartości wyjść.
3. Automatyzacja dekodowania: dekoder, budowa, działanie, zastosowanie
Dekoder to układ kombinacyjny, który przyjmując na wejściu liczbę n-bitową, ustawia dokładnie
jedno z 2^n wyjść na wartość 1. Dla przykładu 4-bitowy dekoder posiadałby 2^4 czyli 16 wyjść.
Najprościej zbudować go z 4 bramek NOT i 16 bramek AND. Każda bramka AND ma 4 wejścia i
każdej kombinacji 4-bitów wejściowych będzie odpowiadało jedno z wyjść.
4. Automatyzacja procesów przełączania w procesorze: multiplekser, demultiplekser
Multiplekser to układ cyfrowy posiadający 2^n wejść danych, jedno wyjście danych i n
wejść sterujących. Umożliwia on przeniesienie sygnału z wybranego wejścia na wyjście układu.
Multiplekser można zrealizować przy pomocy n bramek NOT , 2^n bramek AND i jednej bramki
OR. Dla każdej kombinacji wejść sterujących wybierane jest inne wejście z którego dane pojawiają
się na wyjściu układu.
Demultiplekser posiada jedno wejście danych, n wejść sterujących i 2^n wyjść danych.
Działa on odwrotnie do multipleksera. Dla każdej kombinacji wejść sterujących wybierane jest inne
wyjście na którym pojawią się dane podane na wejściu.
5. Podstawowe elementy pamięciowe: budowa, działanie, zastosowanie
6. Reprezentacja rozkazów na poziomie języka maszynowego
Posługiwanie się językiem natywnym procesora jest bardzo niewygodne dla człowieka,
znacznie łatwiej posługiwać się skrótami mnemonicznymi, które łatwiej zapamiętać i nie ma
problemu z ich rozróżnieniem. Każda architektura jest wyposażona w swój własny zestaw
instrukcji. W przypadku architektury IA-32 można je podzielić na rozkazy arytmetyczno-logiczne,
rozkazy przesłań i dostępu do pamięci oraz rozkazy zmieniające domyślny przepływ sterowania.
7. Semantyka rozkazów arytmetycznych i logicznych
8. Semantyka rozkazów przesłań i dostępu do pamięci
9. Semantyka rozkazów zmieniających domyślny przepływ sterowania: skoki, skoki ze śladem
10. Podstawowy cykl pracy procesora: rola jednostki sterującej, maszynowa interpretacja
rozkazów
Podstawowy cykl pracy procesora to sekwencja wykonywania etapów np.: pobranie instrukcji (IF),
dekodowanie (Decode), pobranie operandów (OF), Wykonanie (Execute), Zapis do rejestru (WB)
lub zapis do pamięci (MEM).
11. Maszynowa interpretacja wybranych rozkazów typu: arytmetyczno-logicznego, przekazywania
sterowania, w tym wołania procedury i powrotu
12. Reprezentacja struktur (danych i sterowania) języka C na poziomie języka maszynowego
Tablice to struktury których pola są danymi tego samego typu. Mogą to być typy proste lub
złożone. Mając zadeklarowaną tablicę w segmencie .data lub .bss, można pobrać adres jej
pierwszego elementu. Jeśli jest to tablica znaków to dodając do tego adresu 1 otrzymamy adres
drugiego elementu, dodając 2 adres trzeciego elementu itd. Gdyby była to tablica liczb typu int to
adres kolejnych elementów dostajemy dodając do adresu 4.
Struktury są bardzo podobne do tablic jednak ich pola nie muszą być tego samego typu.
Ustalając adres danego pola trzeba wiedzieć ile bajtów zajmują pola wcześniejsze tak by dodać do
adresu pierwszego elementu odpowiedni offset.
Unie to kolejna podobna struktura jednak w tym przypadku przesunięcie między polami
wynosi zawsze 0.
Instrukcję sterującą if najprościej zbudować używając instrukcji porównania CMP i któregoś
z wielu skoków warunkowych. Jeśli mamy np. instrukcję if (n>10) {instrukcje do wykonania},
możemy zapisać n w akumulatorze, porównać n z liczbą 10 instrukcją CMP EAX, 10 i zapisać
instrukcję skoku warunkowego JG Instrukcje_do_wykonania(jeśli n większe od 10 skocz do
Instrukcje_do_wykonania).
Podobnie można postąpić w przypadku instrukcji while z tym, że w tym przypadku jeśli
instrukcje wykonują się dopóki warunek jest prawdziwy więc po skoku warunkowym i wykonaniu
się bloku Instrukcje_do_wykonania musi być instrukcja skoku bezwarunkowego do miejsca w
którym sprawdzany jest warunek dla pętli while.
Pętlę for wygodnie jest zaimplementować przy pomocy instrukcji loop. Wystarczy nazwać
część programu przeznaczoną na pętle np. „petla:”, zapisać w rejestrze ECX ilość powtórzeń pętli,
licznik obiegów pętli można przechowywać w którymś z innych rejestrów uniwersalnych. Pozostaje
tylko napisanie instrukcji które mają być wykonane w pętli, po nich instrukcję „LOOP petla”, która
dekrementuje wartość rejestru ECX i wykonuje skok do początku pętli. Pętla zakończy się w
momencie gdy ECX osiągnie wartość 0.
13. Rekord aktywacji procedury na poziomie języka maszynowego
Rekord aktywacji procedury tworzony jest na stosie. Najpierw odkładane są kolejno
argumenty procedury, zaczynając od ostatniego, a później ślad powrotu czyli adres instrukcji
następującej po Call nazwa_procedury W miarę odkładania elementów na stos dekrementowany
jest wskaźnik wierzchołka stosu ESP.
14. Realizacja na poziomie maszynowym przekazywania parametrów do procedur: przez
wartość, przez referencję.
Parametry procedur są składnikami rekordów aktywacji. W zależności od sposobu
przekazania argumentów(&-referencja, brak &-przez wartość) na stosie odkładane są wartości
argumentu bądź jego adres. Przekazanie argumentu przez wartość oznacza, że na stosie zostanie
odłożona wartość argumentu (liczba, znak, ...). Przy przekazywaniu przez referencję na stosie
zapisywany jest adres zmiennej, przy pomocy którego można się do niej odwoływać. Oznacza to,
że w pierwszym przypadku mamy do czynienia z kopią naszej zmiennej, której wartość istnieje na
stosie dopóki istnieje rekord aktywacji. W drugim przypadku poprzez adres modyfikowana będzie
oryginalna wartość zmiennej.
15. Reprezentacja zmiennych lokalnych i globalnych na poziomie języka maszynowego
Zmienne lokalne i globalne reprezentowane są binarnie. Lokalne odkładane są na stosie, a
rezerwuje się jedekrementując wskaźnik ramki stosu EBP o liczbę bajtów potrzebną na nasze
zmienne. Adresy tych zmiennych ustala się równiez przy pomocy EBP. Zmienne globalne z
nadanymi wartościami początkowymi (zainicjalizowane) znajdują się w segmencie .data, a
niezainicjalizowane w segmencie.bss.
Mogą to być zmienne typu prostego jak:
- liczba całkowita bez znaku - reprezentowana w naturalnym kodzie dwójkowym
- liczba całkowita ze znakiem - reprezentowana w kodzie uzupełnienia dwójkowego U2
- liczba typu float - reprezentowana zgodnie ze standardem IEEE 754 w formatach
znoramlizowanym lub zdenormalizowanym
- znaki - zapiswane w standardach ASCII bądź UNICODE
- łańcuch znaków
- tablica - zawiera pola z elementami tego samego typu, tworzona pod określonym adresem, a do
poszczególnych elementów można się odwołać dodając odpowiednią wartość przesunięcia (offset)
do adresu bazowego
- struktura - reprezentowana podobnie jak tablica z tym że jej pola mogą być różnych typów, mogą
nawet też być typu złożonego
- unia - adres unii jest adresem wszystkich jej pól jednocześnie, nie ma między nimi przesunięcia.
16. Architektura IA-32: struktura procesora, lista rozkazów, tryby adresowania
17. Architektura MIPS 32: struktura procesora, lista rozkazów, tryby adresowania
18. Architektura RISC vs. CISC
RISC - Reduced Instruction Set Computer:
– duży zestaw rejestrów (>= 32)
– instrukcje trójargumentowe
– rzadkie odwołania do pamięci
– proste tryby adresowania
– proste kodowanie instrukcji(stała długość)
– prosta i szybka jednostka wykonawcza
– przykłady: MIPS, SPARC, ARM
CISC – Complex Instruction Set Computer:
– rejestry przechowują jedynie adresy i tymczasowe wyniki pośrednie
– dane(operandy) w pamięci(lokalne na stosie)
– operandy o różnych długościach 1, 2 , 4, 8 bajtowe
– instrukcje z języka wysokiego poziomu zamieniane na jedną lub kilka instrukcji
maszynowych
– długość argumentu zakodowana w instrukcji
– bogaty repertuar trybów adresowania
– zwykle instrukcje dwuargumentowe
problemy:
– złożoność jednostki wykonawczej
– częste odwołania do pamięci
– instrukcje o zmiennej długości: złożona specyfikacja argumentów
– wielofazowe wykonanie instrukcji
19. 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.
20. Organizacja pamięci: rejestrów, pamięci głównej, kieszeniowej
21. 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 liczb trzeba do
adresu dodać odpowiednią liczbę określającą o którą część chodzi.
22. 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.
23. 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.
24. Przerwania i wyjątki: zasada przekazywania sterowania do programu obsługi
25. Organizacja systemu wejścia-wyjścia
Porty wejściowe lub wyjściowe są widoczne w przestrzeni adresowej podobnie do komórek
pamięci.