ask1, Edukacja, studia, Semestr IV, Architektura Systemów Komputerowych, Wyklad


Literatura do przedmiotu

"Architektura systemów komputerowych"

  1. Stallings W.: Organizacja i architektura systemu komputerowego. Warszawa WNT 2000.

  1. Schmit L.: Procesory Pentium. Narzędzia optymalizacji. Warszawa wyd. Mikom 1997.

  1. Chalk B.S.: Organizacja i architektura komputerów. Warszawa WNT 1998.

  1. Kruk: Turbo-asembler. Wyd. Mikom 2000.

  1. Dudek A.: Jak pisać wirusy. Warszawa wyd. Read Me 1994.

  1. Komorowski W.: Instrumenta computatoria (wybrane architektury komputerów). Gliwice wyd. Helion 2000.

  1. Bach M.J.: Budowa systemu operacyjnego UNIX. Warszawa: WNT 1995.

  1. Silberschatz A., Galvin P.: Podstawy systemów operacyjnych. WNT 2000.

  1. Haviland K., i inni: Unix Programowanie systemowe. Warszawa Wyd. RM 1999.

  1. Petzold C.: Programowanie Windows 95. Warszawa 1998.

  1. Stevens W.R.: Programowanie zastosowań sieciowych w systemie Unix. Warszawa: WNT 1996.

  1. Wall K.: Linux — programowanie w przykładach. Warszawa: wyd. Mikom 2000.

Rozwój konstrukcji komputerów i oprogramowania

1834 Babbage — projekt urządzenia "Analytical Engine"

1854 Boole: "Laws of thought"

1930 Laboratorium firmy Bell: komputer elektromechaniczny

1938 Urządzenie liczące w pełni elektroniczne "Colossus" (Turing, Flowers, Newman)

1941 Kalkulator elektromechaniczny (K. Zuse), mnożenie 3 s

1942 - 1946 pierwsze komputery elektroniczne

1944 MARK I (H. Aiken), Harvard University

1945 ENIAC

1945 koncepcje J. von Neumanna

1948 Opracowanie tranzystora

1949 Rozwój oprogramowania: biblioteki podprogramów, asembler

1951 Komputer EDVAC (von Neumann) — program przechowywany w pamięci

1954 Język programowania FORTRAN

1954 IBM 650 — pierwszy komputer produkowany masowo

1955 Pierwszy komputer tranzystorowy

1958 Język Algol

1958 komputery tzw. drugiej generacji (tranzystorowe)

1958 Komputer Atlas z pamięcią wirtualną

1959 Komputer PDP-1

1962 Systemy z podziałem czasu

1968 komputery tzw. trzeciej generacji (układy scalone)

1969 System Unix

lata 70 minikomputery

1971 Procesor Intel 4004

1972 Język C

1977 Komputery osobiste: Apple, Commodore

1980 komputery osobiste

1981 Komputer IBM PC (16 KB RAM)

1982 Turbo-Pascal

1985 Język C++

1990 System Windows 3.0

1995 Język Java

Komputery w Polsce

1958 Komputer XYZ (Zakład Aparatów Matematycznych PAN)

1960 Komputer ZAM 2

1960 Język programowania SAKO

1964 Komputery ZAM 21

1972 Komputery ODRA (Elwro Wrocław)

1975 Komputer Momik

Procesory rodziny Intel x86

8086/88 1978

80286 1982

386 1985

486 1989

Pentium 1993

Pentium III 1999

Pentium 4 2000

Model komputera wg von Neumanna

w roku 1945 matematyk amerykański von Neumann wraz ze współpracownikami zaproponował pewien model wykonywania obliczeń — mimo upływu wielu lat prawie wszystkie współczesne komputery ogólnego przeznaczenia stanowią realizację tego modelu;

0x01 graphic

zasadniczą i centralną część każdego komputera stanowi procesor jego własności decydują o pracy całego komputera;

procesor steruje podstawowymi operacjami komputera, wykonuje operacje arytmetyczne i logiczne, przesyła i odbiera sygnały, adresy i dane z jednego podzespołu komputera do drugiego; procesor pobiera kolejne instrukcje programu i dane z pamięci głównej (operacyjnej) komputera, przetwarza je i ewentualnie odsyła wyniki do pamięci;

komunikacja ze światem zewnętrznym realizowana jest za pomocą urządzeń wejścia/wyjścia;

do budowy współczesnych komputerów używane są elementy elektroniczne — inne rodzaje elementów (np. mechaniczne) są znacznie wolniejsze (o kilka rzędów); ponieważ elementy elektroniczne pracują pewnie i stabilnie jako elementy dwustanowe, informacje przechowywane i przetwarzane przez komputer mają postać ciągów zerojedynkowych;

  1. pamięć współpracująca z procesorem musi być dostatecznie szybka, tak by oczekiwanie na odczytanie potrzebnych informacji nie powodowało przestojów w pracy procesora;

  2. ponieważ wszelkie przetwarzane informacje mają charakter binarny, więc także program przechowywany w pamięci musi być zakodowany w postaci binarnej;

instrukcje (rozkazy) przekazywane do procesora mają postać jednego lub kilku bajtów o ustalonej zawartości; i tak na przykład przekazanie procesorowi Pentium (lub jego poprzednikowi) instrukcji w formie bajtu 01000010 spowoduje zwiększenie liczby umieszczonej w (opisanym dalej) rejestrze EDX o 1, natomiast przekazanie bajtu 01001010 zmniejszenie tej liczby o 1; często polecenia przekazywane procesorowi składają się z kilku bajtów, np. bajty 10000000  11000111  00100101 są traktowane przez procesor jako polecenie dodania liczby 37 do liczby znajdującej się w rejestrze BH;

Pamięć główna (operacyjna)

w trakcie pracy procesor komunikuje się z pamięcią operacyjną, wykonując operacje zapisu i odczytu danych, a także pobierając kolejne instrukcje do wykonania;

poszczególne komórki pamięci są ponumerowane od 0 — numer komórki pamięci nazywany jest jej adresem;

0x01 graphic

pojedynczy bajt umożliwia tylko zapisywanie liczb nie przekraczających 255; tworzone są więc zespoły bajtów:

16-bitowe słowa,

32-bitowe podwójne słowa,

64-bitowe poczwórne słowa,

w miarę potrzeby tworzy się także większe zespoły bajtów;

producenci procesorów ustalają konwencję numeracji bitów w bajtach i słowach — numeracja przyjęta m. in. w procesorze Pentium pokazana jest na rysunku;

0x01 graphic

Rejestry ogólnego przeznaczenia w procesorze Pentium

w trakcie wykonywania obliczeń często wyniki pewnych operacji stają się danymi dla kolejnych operacji — w takim przypadku nie warto odsyłać wyników do pamięci operacyjnej, a lepiej przechować te wyniki w komórkach pamięci wewnątrz procesora; komórki pamięci wewnątrz procesora zbudowane są w postaci rejestrów (ogólnego przeznaczenia);

początkowo wszystkie rejestry ogólnego przeznaczenia były 16-bitowe i oznaczone AX, BX, CX, DX, SI, DI, BP, SP, F; wszystkie te rejestry w procesorze 386 i wyższych zostały rozszerzone do 32 bitów i oznaczone dodatkową literą E na początku, np. EAX, EBX, ECX, itd.;

rejestry 16-bitowe są nadal dostępne, np. młodsza część rejestru EAX nazywa AX, a młodsza część rejestru EBX nazywa się BX; ponadto w kilku rejestrach wyodrębniono mniejsze rejestry 8-bitowe, oznaczone AL, AH, BL, BH, itd.; omawiane tu rejestry pokazane są na rysunku:


31

15

7 0

EAX

AX

AH

AL

31

15

7 0

EBX

BX

BH

BL

31

15

7 0

ECX

CX

CH

CL

31

15

7 0

EDX

DX

DH

DL

31

15

7 0

ESI

SI

31

15

7 0

EDI

DI

31

15

7 0

EBP

BP

31

15

7 0

ESP

SP


Rejestr znaczników

0x01 graphic

Najczęściej używane znaczniki są następujące:

CF (ang. carry) znacznik przeniesienia do znacznika tego wpisywane jest przeniesienie (pożyczka) z najbardziej znaczącego bitu;

PF (ang. parity) znacznik parzystości znacznik ten ustawiany jest w stan 1, gdy osiem najmłodszych bitów wyniku operacji arytmetycznej lub logicznej zawiera parzystą liczbę jedynek;

AF (ang. auxiliary carry) znacznik przeniesienia pomocniczego, używany w operacjach na liczbach zakodowanych w systemie dwójkowo-dziesiętnym (BCD);

ZF (ang. zero) znacznik zera znacznik ten ustawiany jest w stan 1, gdy wynik operacji arytmetycznej lub logicznej jest równy 0 i zerowany w przypadku przeciwnym;

SF (ang. sign) znacznik reprezentujący znak wyniku obliczenia;

TF (ang. trap) pułapka znacznik ten umożliwia krokowe wykonywanie programu (używany przez debuggery);

IF (ang. interrupt enable) zezwolenie na przerwanie znacznik ten włącza lub wyłącza system przerwań; jeśli znacznik IF zawiera 0, to przerwania sprzętowe są ignorowane aż do chwili, gdy IF zawierać będzie 1; zawartość znacznika IF nie wpływa na wykonywanie przerwań programowych;

DF (ang. direction) znacznik kierunku stan tego znacznika wpływa na sposób wykonywania operacji na łańcuchach znaków;

OF (ang. overflow) znacznik nadmiaru.

Rejestry segmentowe

w trakcie wykonywania programu rejestry segmentowe zawierają adresy początkowe obszarów pamięci, w których umieszczone instrukcje (rozkazy) i dane; zastosowanie tych rejestrów omawiane jest dalej.


15 0

CS

15 0

DS

15 0

ES

15 0

SS

15 0

FS

15 0

GS


Procesory Pentium i ich poprzednicy

w komputerze IBM PC, który stanowił pierwowzór całej rodziny, zastosowano procesor 8088 firmy Intel; w coraz to nowszych konstrukcjach komputerów miejsce tego procesora zajmowały kolejno procesory 80286, 80386, 80486 (ściśle: i486) i Pentium, pojawiające się zazwyczaj co 4 lata; każdy z nich charakteryzuje się coraz większą szybkością i złożonością;

jednak podstawowy zestaw operacji, zdefiniowany dla procesora 8086/88, dostępny jest w każdym z ww. procesorów — oznacza, to że programy dla komputera IBM PC opracowane na początku lat osiemdziesiątych mogą być wykonywane także w komputerze wyposażonym w procesor Pentium 4;

projekt procesora 8086/88, opracowany w końcu lat siedemdziesiątych, przewidywał, że procesor ten współpracować będzie z pamięcią główną (operacyjną) zawierającą co najwyżej 220 = 1 048 576 bajtów; po kilku latach okazało się, że taki rozmiar pamięci jest już niewystarczający i zachodzi konieczność zastąpienia dotychczas używanego procesora przez inny, umożliwiający współpracę z znacznie większą pamięcią;

jednak wprowadzenie całkowicie nowego typu procesora mogłoby nie zostać zaakceptowane przez użytkowników komputerów, których dotychczasowe oprogramowanie stałoby się bezużyteczne — w tej sytuacji postanowiono skonstruować procesor posiadający możliwość pracy w dwóch trybach:

w trybie "starym", który nazywany jest trybem rzeczywistym (ang. real mode), procesor zachowuje się podobnie do swojego poprzednika 8086/88;

w trybie "nowym", określany jako tryb chroniony procesor stosuje inne techniki adresowania pamięci, co pozwala zainstalować w komputerze pamięć główną o rozmiarze do 4 GB (gigabajtów);

przełączenie między trybami wykonywane jest w sposób programowy;

tryb chroniony w ograniczonym zakresie został wprowadzony w procesorze 80286, i szerzej rozwinięty w procesorach 386 i następnych; z punktu widzenia programowania istotne zmiany pojawiły się wraz z procesorem 386; rozszerzenia wprowadzone w 486 i w Pentium tylko w niewielkim stopniu zmieniły zasady programowania — wydaje się jednak, że rozwój omawianej tu rodziny procesorów skupia się głównie na czynnościach wewnętrznych, niedostępnych na poziomie programowania;

nowym elementem przetwarzania dostępnym w procesorach Pentium są zestawy operacji MMX i SSE, które znacznie przyśpieszają przetwarzanie danych multimedialnych.

Wykonywanie programów w trybie rzeczywistym i chronionym

w chwili obecnej użytkowane są zarówno programy dostosowane do trybu chronionego (głównie w środowisku Windows), jak też spotyka się jeszcze programy dostosowane do trybu rzeczywistego (w systemie DOS);

można więc przypuszczać, że uruchomienie na poziomie systemu Windows zwykłego programu, normalnie pracującego w systemie DOS, wymaga przełączenia procesora do trybu rzeczywistego;

takie przełączenie jest wprawdzie możliwe, ale wiąże się z tymczasową utratą przywilejów systemu Windows w stosunku do zwykłego programu — z tego względu w procesorach Pentium (i w jego poprzednikach) zdefiniowano specjalny tryb pracy oznaczony symbolem V86, który można uważać za podtryb trybu chronionego;

w trybie V86, mimo że stanowi on odmianę trybu chronionego, procesor z punktu widzenia wykonywanego programu zachowuje się prawie dokładnie tak samo jak w trybie rzeczywistym;

tak więc programy "DOSowe" wywoływane na poziomie systemu Windows są wykonywane w trybie V86, a nie w trybie rzeczywistym (chociaż zazwyczaj nie zdają sobie z tego sprawy);

niektóre programy nie tolerują jednak trybu V86 i wymagają przełączenia procesora do trybu rzeczywistego — w systemie Windows wymaga to wybrania opcji "tryb MS-DOS".

Segmentacja

w trakcie wykonywania pewnego programu (w trybie rzeczywistym) przez krótki odcinek czasu obserwowano stany linii adresowych pamięci głównej i odczytano poniższe wartości:

0010 0011 1011 1011 1101 (23BBD)

0001 1101 0000 0111 0100 (1D074)

0010 0011 1011 1011 1111 (23BBF)

0010 0011 1011 1100 0010 (23BC2)

0010 0011 1011 1011 1101 (23BBD)

0001 1101 0000 0111 1000 (1D078)

0010 0011 1011 1011 1111 (23BBF)

0010 0011 1011 1100 0010 (23BC2)

0010 0011 1011 1011 1101 (23BBD)

0001 1101 0000 0111 1100 (1D07C)

łatwo zauważyć, że podane adresy skupiają się w dwóch obszarach:

0010 0011 1011 1011 1101

0001 1101 0000 0111 0100

0010 0011 1011 1011 1111

0010 0011 1011 1100 0010

0010 0011 1011 1011 1101

0001 1101 0000 0111 1000

0010 0011 1011 1011 1111

0010 0011 1011 1100 0010

0010 0011 1011 1011 1101

0001 1101 0000 0111 1100

ponieważ w trakcie wykonywania programu pobierane są kolejne instrukcje programu, umieszczone często w sąsiednich lokacjach pamięci, więc adresy określające położenie rozkazów w pamięci (generowane przez procesor) będą miały zbliżone wartości — można przypuszczać, że lewa kolumna zawiera te właśnie adresy;

jednocześnie procesor generuje także adresy danych, które także mają skłonność do skupiania się (zasada lokalności); można więc przypuszczać, że adresy podane w prawej kolumnie określają położenie danych;

zauważmy, że zarówno w przypadku adresów rozkazów jak i danych, znaczna część początkowych bitów adresu jest jednakowa w kolejnych odwołaniach do pamięci; zatem istnieje możliwość rozdzielenia obu rodzajów adresów na dwie części: stałą, która w ogóle nie zmienia się w trakcie wykonywania programu lub zmienia się bardzo rzadko, i zmienną, która ulega zmianom;

przy takim podziale wskazanie położenia danej w pamięci czy też położenia rozkazu wymaga podania mniejszej liczby bitów, wskutek czego programy stają się krótsze, zajmują mniej miejsca w pamięci i zwykle wykonują się szybciej; oczywiście procesor we trakcie obliczania adresu lokacji pamięci musi każdorazowo wyznaczyć sumę części stałej i zmiennej;

części stałe adresów przechowywane są w specjalnych rejestrach, w procesorze Pentium nazywanych rejestrami segmentowymi: CS, DS, ES, FS, GS i SS;

zawartość rejestru segmentowego można traktować jako wskazanie pewnego adresu bazowego w pamięci, wskazującego początek obszaru danych (w Pentium rejestr DS, ang. data segment) lub wskazującego początek obszaru zawierającego instrukcje (rozkazy) programu (w Pentium rejestr CS, ang. code segment);

w takim ujęciu adresy pamięci używane przez programy określają tylko położenie danej lub instrukcji poprzez podanie odległości, liczonej w bajtach, od adresu bazowego — odległość ta nazywana jest przesunięciem lub offsetem;

zatem adres zawarty w instrukcji nie zawiera adresu fizycznego danej, czyli nie wskazuje bezpośrednio jej położenia, lecz jedynie odległość danej od pewnego adresu bazowego w pamięci komputera;

przykładowo, jeśli instrukcja (rozkaz) wykonująca pewne działanie na zmiennej a zawiera adres tej zmiennej, to adres tej zmiennej wyrażony poprzez odległość tej zmiennej, liczoną w bajtach, od pewnego ustalonego adresu bazowego; zatem wyznaczenie adresu fizycznego zmiennej a wymaga obliczenia sumy adresu bazowego i przesunięcia; w procesorze Pentium suma ta wyznaczana jest w specyficzny sposób.

0x01 graphic

Dostęp do pamięci operacyjnej w trybie rzeczywistym

zwykle pamięć operacyjna zainstalowana w komputerze ma organizację bajtową; każdy bajt ma przyporządkowany adres, nazywany adresem fizycznym, który w trybie rzeczywistym procesora Pentium ma długość 20 bitów, a w trybie chronionym — 32 bitów;

ustalona dla danego procesora liczba bitów, na których zapisywany jest adres bajtu pamięci stanowi długość adresu;

długość adresu określa od razu rozmiar zainstalowanej pamięci:

jeśli adres ma 20 bitów, to liczba możliwych różnych adresów zapisanych na 20 bitach wynosi 220 = 1 048 576 bajtów (1 MB);

jeśli adres ma 32 bity, to liczba możliwych różnych adresów zapisanych na 32 bitach wynosi 232 = 4 294 967 296 bajtów (4 GB);

Tryb rzeczywisty

Tryb chroniony

Liczba adresów generowanych przez procesor

220 = 1 048 576

232 = 4 294 967 296

Liczba linii adresowych

20

32

w wielu przypadkach wartość przesunięcia (offsetu) zapisana jest bezpośrednio w postaci liczby 16- lub 32-bitowej wewnątrz ciągu bajtów tworzących aktualnie wykonywaną instrukcję; w bardziej złożonych przypadkach, gdy stosowane są modyfikacje adresowe, przesunięcie obliczane jest w inny sposób;

ponieważ w trybie rzeczywistym procesora Pentium adresy fizyczne są 20-bitowe, należałoby więc przypuszczać, że rejestry segmentowe są rejestrami 20-bitowymi; konstruktorzy procesora ograniczyli jednak długość tych rejestrów do 16 bitów, przyjmując jednocześnie założenie, że w obliczeniach adresów zawartość jednego z ww. rejestrów segmentowych jest rozszerzana do 20 bitów poprzez dopisanie czterech zer z prawej strony;

przyjęto także, że w trybie rzeczywistym przesunięcie (offset) jest liczbą 16-bitową;

przy podanych założeniach sposób obliczania adresu fizycznego ilustruje poniższy rysunek:

0x01 graphic

zauważmy, że dopisanie czterech zer z prawej strony liczby dwójkowej oznacza po prostu mnożenie przez 16; zatem adres fizyczny w trybie rzeczywistym określa formuła:

adres fizyczny = zaw. rej. segmentowego 16 + przesunięcie

obliczanie adresu fizycznego w trybie rzeczywistym ilustruje poniższy rysunek:

0x01 graphic

w praktyce programowania (w trybie rzeczywistym) zazwyczaj nie podaje się 20-bitowego adresu fizycznego instrukcji lub danej, ale adres ten wyraża się w postaci dwóch liczb szesnastkowych rozdzielonych dwukropkiem; pierwsza z tych liczb określa wskazuje początek segmentu, w którym znajduje omawiany obiekt, druga zaś określa przesunięcie wewnątrz segmentu, tj. odległość obiektu od początku segmentu (wyrażona w bajtach);

przykładowo, 32-bitowy programowy licznik czasu BIOSu umieszczony jest w lokacji pamięci o adresie 40H:6CH, tzn. w lokacji pamięci o adresie fizycznym 40H 16 + 6CH = 46CH; mówimy, że adres lokacji pamięci został wyrażony w postaci segment : offset.

Obliczanie adresu fizycznego w trybie chronionym

sposób obliczania adresu fizycznego w trybie chronionym jest bardziej złożony;

adres bazowy nie jest zawarty w jednym z rejestrów segmentowych, ale w deskryptorze segmentu;

w procesie tym istotną rolę pełni tablica adresowa, zwana Globalną Tablicą Deskryptorów, w skrócie GDT; tablica GDT zawiera opisy segmentów programu przedstawione w formie 8-bajtowych bloków, zwanych deskryptorami;

pole "indeks" w aktualnie używanym rejestrze segmentowym wskazuje na jeden z deskryptorów w Globalnej Tablicy Deskryptorów (GDT) — na tej podstawie procesor pobiera z deskryptora 32-bitowy adres segmentowy, który zostaje zsumowany z przesunięciem (offsetem);. obliczona suma ma postać adresu 32-bitowego, który czasami nazywany jest adresem liniowym; z kolei adres ten zostaje poddany transformacji przez mechanizm stronicowania, w wyniku czego uzyskiwany jest 32-bitowy adres fizyczny.

0x01 graphic

Cykl rozkazowy

główną właściwością procesora jest zdolność do wykonywania obliczeń, m.in. zdolność do wykonywania działań arytmetycznych na liczbach;

w celu wykonania potrzebnych obliczeń procesor musi sukcesywnie otrzymywać informacje o kolejnych czynnościach, które mają zostać wykonane; instrukcje (rozkazy) przekazywane do procesora mają postać jednego lub kilku bajtów o ustalonej zawartości;

znaczenie różnych bajtów stanowiących instrukcje (rozkazy) zostało ustalone przez projektantów konkretnego typu procesora i jest powszechnie dostępne w literaturze technicznej; tak więc rozmaite czynności, które może wykonywać procesor, zostały zakodowane w formie ustalonych kombinacji zer i jedynek, składających się na jeden lub kilka bajtów;

zakodowany ciąg bajtów umieszcza się w pamięci operacyjnej komputera, a następnie poleca się procesorowi odczytywać z pamięci i wykonywać kolejne instrukcje; w rezultacie procesor wykonana szereg operacji, w wyniku których uzyskamy wyniki końcowe programu;

ze względu na to, że posługiwanie się w procesie kodowania programu wartościami zero-jedynkowymi byłoby bardzo kłopotliwe, wprowadzono skróty literowe (tzw. mnemoniki) dla poszczególnych instrukcji (rozkazów) procesora; i tak podane wcześniej instrukcje 01000010 i 01001010 zastępuje się mnemonikami INC  EDX (ang. increment zwiększenie) i DEC  EDX (ang. decrement zmniejszenie);

oczywiście, mnemoniki są niezrozumiałe dla procesora i przed wprowadzeniem programu do pamięci muszą być zamienione na kody zero-jedynkowe programy dokonujące takiej konwersji nazywane są asemblerami;

proces pobierania kolejnych instrukcji z pamięci operacyjnej i ich wykonywania musi być precyzyjnie zorganizowany, tak by natychmiast po wykonaniu kolejnej instrukcji procesor pobierał z pamięci następną; aby pobrać tę instrukcję, procesor musi oczywiście znać jej położenie w pamięci operacyjnej — informacje o położeniu kolejnej instrukcji są umieszczone w specjalnym rejestrze, nazywanym wskaźnikiem instrukcji;

31

15

7 0

EIP

IP

w procesorach Pentium wskaźnik instrukcji jest rejestrem 32-bitowym oznaczonym symbolem EIP; w trybie rzeczywistym używana jest młodsza część tego rejestru oznaczona IP (ang. instruction pointer).

0x08 graphic

czynności wykonywane przez procesor w trakcie pobierania i wykonywania poszczególnych rozkazów powtarzane są cyklicznie, a cały proces nosi nazwę cyklu rozkazowego;

0x01 graphic

w procesorach Pentium adres fizyczny lokacji w pamięci operacyjnej, jeśli procesor pracuje w trybie rzeczywistym, wyznaczany jest poprzez sumowanie pomnożonej przez 16 zawartości rejestru segmentowego i przesunięcia (offsetu); zasada ta odnosi się także do operacji pobierania kolejnych instrukcji z pamięci;

w trakcie realizacji programu kolejna instrukcja (rozkaz) do wykonania pobierana jest z komórki pamięci o adresie, który wskazany jest przez sumę:

pomnożonej przez 16 zawartości rejestru segmentowego CS i

zawartości wskaźnika instrukcji IP;

jeśli wykonywana instrukcja (rozkaz) nie jest instrukcją sterującą, to w trakcie jej wykonywania zawartość wskaźnika instrukcji IP jest zwiększana o liczbę bajtów zajmowanych przez tę instrukcję; przykładowo, jeśli omawiana wcześniej instrukcja dodawania zajmuje 3 bajty, to w trakcie jej wykonywania rejestr IP zostanie zwiększony o 3; w rezultacie, po wykonaniu każdej instrukcji rejestry CS:IP wskazują położenie kolejnej instrukcji do wykonania;

podane tu zasady odnoszą się do trybu rzeczywistego w przypadku trybu chronionego ogólne zasady są te same, ale stosowane są inne, bardziej skomplikowane reguły wyznaczania adresu fizycznego.

Instrukcje (rozkazy) sterujące i niesterujące

podstawowe operacje przetwarzania: przesyłanie, operacje arytmetyczne i logiczne, przesunięcia, itd., realizują instrukcje (rozkazy) określane jako niesterujące; charakterystyczną cechą tej klasy instrukcji jest to, że nie zmieniają one naturalnego porządku wykonywania rozkazów, co oznacza, że po wykonaniu rozkazu z tej klasy procesor rozpoczyna wykonywać rozkaz bezpośrednio przylegający w pamięci do rozkazu właśnie wykonanego; zatem kolejna zawartość rejestru EIP jest obliczana wg formuły:

EIP EIP + <liczba bajtów aktualnie wykonywanej instrukcji>

dodatkową cechą instrukcji wykonujących operacje arytmetyczne i logiczne w procesorze Pentium jest to, że ustawiają one niektóre bity w rejestrze znaczników w zależności od wyniku operacji; przykładowo, jeśli wynik operacji wynosi 0, to znacznik zera ZF przyjmuje wartość 1; w miarę potrzeby stan tych znaczników może być testowany przez (opisane dalej) instrukcje sterujące;

jednak ww. instrukcje, mimo że posiadają kluczowe znaczenie dla kodowania algorytmów, wykonywane są po kolei, a więc są niewystarczające dla zakodowania wielu algorytmów, np. rozwiązywania równania kwadratowego;

w trakcie rozwiązywania równania kwadratowego wyznacza się pewien wynik pośredni, zwany wyróżnikiem (delta), którego wartość determinuje sposób dalszych obliczeń. — m.in. zwykle rezygnujemy z dalszych działań, jeśli obliczony wyróżnik ma wartość ujemną;

przekładając ten problem na poziom instrukcji procesora można stwierdzić, że w przypadku ujemnego wyróżnika należy zmienić naturalny porządek ("po kolei") wykonywania instrukcji i spowodować, by procesor pominął ("przeskoczył") dalsze obliczenia;

można to bardzo łatwo zrealizować, jeśli do rejestru IP zostanie dodana odpowiednio duża liczba (np. dodanie liczby 143 oznacza, że procesor pominie wykonywanie instrukcji zawartych w kolejnych 143 bajtach pamięci operacyjnej); oczywiście, takie pominięcie znacznej liczby instrukcji powinno nastąpić tylko w przypadku, gdy obliczony wyróżnik był ujemny;

potrzebne są więc specjalne instrukcje, które w zależności od własności uzyskanego wyniku (np. czy jest ujemny) zmienią zawartość rejestru EIP, dodając lub odejmując jakąś liczbę, albo też zmienią zawartość EIP w konwencjonalny sposób — instrukcje takie nazywane są instrukcjami sterującymi (skokowymi);

instrukcje sterujące warunkowe na ogół nie wykonują żadnych obliczeń, ale tylko sprawdzają, czy uzyskane wyniki mają oczekiwane własności; w zależności od rezultatu sprawdzenia wykonywanie programu może być kontynuowane przy zachowaniu naturalnego porządku instrukcji albo też porządek ten może być zignorowany poprzez przejście do wykonywania instrukcji znajdującej się w odległym miejscu pamięci operacyjnej;

istnieją też instrukcje sterujące, zwane bezwarunkowymi, których jedynym zadaniem jest zmiana porządku wykonywania instrukcji (nie wykonują one żadnego sprawdzenia); w procesorach Pentium niektóre instrukcje sterujące bezwarunkowe zmieniają także rejestr CS;

w procesorze Pentium rozmaite instrukcje sterujące testują zawartość pojedynczych bitów w rejestrze znaczników, a niekiedy obliczają pewne wyrażenia logiczne określone na tych bitach; dla każdej instrukcji sterującej (warunkowej) określono testowany warunek, np. dla instrukcji sterującej:

jz warunek jest spełniony, gdy znacznik ZF = 1;

jnz warunek jest spełniony, gdy znacznik ZF = 0;

ja warunek jest spełniony, gdy znaczniki CF = 0 i ZF = 0;

w zależności od tego czy warunek jest spełniony czy nie, do wskaźnika instrukcji EIP wpisywane są inne wartości, jak podano poniżej;

Obliczanie EIP przez instrukcje sterujące

1. gdy testowany warunek jest spełniony:

EIP EIP + <liczba bajtów aktualnie wykonywanej instrukcji> +

+ <zawartość pola adresowego instrukcji>

2. gdy testowany warunek nie jest spełniony

EIP EIP + <liczba bajtów aktualnie wykonywanej instrukcji>

33

11

33

14

0x01 graphic



Wyszukiwarka