Chciałbyś pewnie zaprojektować własny procesor, który działałby tak jak prawdziwy, prawda? Nie jest to tak trudne i abstrakcyjne, jakby ci się wydawało. Wystarczy rozumieć zasadę działania podstawowych układów z których zbudowany jest ten układ. Spokojnie, wszystko po kolei omówimy. Dzisiaj zajmiemy się jedną z dwóch głównych części CPU – modułem ścieżki danych.

Czym jest ścieżka danych?

Procesor jest przeznaczony do jakiegoś celu – zwykle wykonywania obliczeń. Mikroprocesor musi być też uniwersalny, powinien móc realizować dowolne kombinacje rozkazów, jakie wprowadzi na jego wejście programista. Za dekodowanie rozkazów i sterowanie „całym procesorem” odpowiada moduł kontrolera. Natomiast moduł ścieżki danych odpowiada za wykonywanie faktycznych obliczeń. Wewnątrz ścieżki danych znajdują się rejestry, w których przechowywane są wyniki obliczeń, dane wejściowe, tymczasowe i cokolwiek innego, czego zażyczy sobie programista. Znajdują się tu także sumatory, jednostki arytmetyczno-logiczne które służą do przeprowadzania różnych operacji i działań. Ostatnim ważnym komponentem są multipleksery, które sterują „przepływem” informacji i zarządzają co gdzie powinno trafić.

W normalnym CPU ścieżka danych jest sprzężona z kontrolerem i pozostałymi elementami procesora. My nie chcemy komplikować sprawy. W tym artykule będziemy zajmowali się wyłącznie ścieżką danych.

Jak działa procesor/ścieżka danych?

Używasz komputera na co dzień, a więc wiesz że procesor posiada coś takiego jak taktowanie. Jest to, najprościej sprawę ujmując – zmiana wartości sygnału na przeciwny co pewien czas. CPU jest układem synchronicznym, a więc cała jego praca zależy właśnie od zegara. Kiedy chcemy wysterować jakiś układ, np.: zapisać coś do rejestru, to wykonujemy to „w pewnym okienku”, którego miejsce określone jest przez sygnał zegarowy. Wykonywanie akcji przez różne komponenty CPU może odbywać się w dwóch różnych momentach: albo przy narastającym albo przy opadającym zboczu zegara. My nie musimy być aż tacy dokładni. Wystarczy wiedzieć, że na wykonanie każdej operacji, takiej jak wysterowanie multipleksera czy zapisanie wyników do rejestru potrzebujemy co najmniej jednego cyklu zegara. Cykle oznaczamy za pomocą literki t i cyfry oznaczającej numer analizowanego cyklu. Np.: t0 zawiera wszystkie instrukcje, które wykonywane są przy pierwszym takcie zegara. t1 – przy drugim. I tak dalej …

Poznałeś już podstawowe rozkazy w procesorze x86, takie jak mov. (Jeśli nie, zapraszam tutaj) Otóż wykonanie tych rozkazów przez ścieżkę danych wcale nie jest proste. Każdy z nich składa się z jednej lub większej ilości mikrooperacji. To one są składową rozkazu. Wydając rozkaz mov EAX,100 tak naprawdę każemy kontrolerowi „tak wysterować” ścieżkę danych za pomocą powiązanych z rokazem mov mikrooperacji, aby wartość 100 została zapisana do rejestru EAX.

Nauczymy się tworzyć mikrooperacje, a więc niejako „zastąpimy” moduł kontrolera CPU. Dowiemy się, jak wykonywanie rozkazów wygląda „od środka”.

Z jakich komponentów korzysta ścieżka danych?

Oczywiście, z tranzystorów … A tak na poważnie, to mamy kilka komponentów które musisz znać i rozumieć zasadę ich działania.

Rejestr

Symbol rejestru

Rejestr przechowuje pojedynczą liczbę. Komponent ten może mieć różną pojemność: 8, 16 lub 32 bity. W projektach na studiach najczęściej będziesz używał 8 i 16 bitowych rejestrów. Rozmiar rejestru zależy od architektury procesora. Jeśli tworzymy procesor 8 bitowy, stosujemy rejestry 8 bitowe.

Ale jest wyjątek od tej reguły. Jeśli w założeniach zostało powiedziane: zastosuj rejestry 16 bitowe, to stosujemy 16 bitowe bez względu na wszystkie inne czynniki.

Zauważyłeś pewnie patrząc na symbol, że rejestr posiada wejście, wyjście oraz nóżkę oznaczoną symbolem LD. Musisz wiedzieć, że to co podamy na wejście rejestru zostanie do niego zapisane dopiero wtedy, kiedy na pin LD podamy jedynkę. Nowy wynik zostanie podany na wyjście rejestru dopiero w następnym cyklu zegara. Musimy o tym pamiętać przy sterowaniu. Jeśli mamy potrzebę zapisania czegoś do rejestru, to kolejne operacje należy przenieść do następnego cyklu zegara.

Multiplekser

symbol multipleksera

Jaka jest rola multipleksera? Posiada on parę wejść i jedno wyjście. Pozwala on na „przekazanie” jednego z wejść na wyjście. W ścieżce danych może pełnić wiele funkcji i jest bardzo często występującym komponentem.

Wejścia numerowane są od zera, patrząc na górę multipleksera. Czyli pierwsze wejście od góry ma numer 0, drugie 1, trzecie 2 itd. Jeśli chcemy „przepisać” wartość drugiego wejścia multipleksera na jego wyjście, ustawiamy wartość pinu ADR na 1. Jeśli posiadalibyśmy multiplekser czterowejściowy i chcielibyśmy przekazać ostatnie wejście na wyjście multipleksera, wtedy ustawilibyśmy pin ADR na wartość 3.

Pamiętaj: multiplekser działa natychmiastowo. Oznacza to, że w przeciwieństwie do rejestru możesz sterować kilkoma multiplekserami w jednym cyklu zegarowym.

Multiplekser ma brata nazywającego się demultiplekserem. Zasada działania demultipleksera jest bardzo podobna. Komponent ten działa „niejako” na odwrót. Demultiplekser posiada tylko jedno wejście i kilka wyjść. Jego zadaniem jest przepisanie tego wejścia na konkretne wyjście.

Sumator

symbol sumatora

Sumator jest najprostszym układem. Jego celem jest dodanie dwóch liczb do siebie. Jest układem asynchronicznym, a więc działa natychmiastowo. Posiada zawsze dwa wejścia i zawsze jedno wyjście. Nie musimy nic sterować. Po prostu to co wstawimy na wejście zostanie zsumowane i od razu przekazane na wyjście.

Najprostsza ścieżka danych i jej omówienie

Przykład pierwszy (A=WE)

Na schemacie powyżej widzimy najprostszą możliwą ścieżkę danych. (Rysunek został pobrany z instrukcji dostępnej pod tym adresem).

Załóżmy, że chcemy wykonać operację A=WE. Co to znaczy? Oznacza to, że chcemy zapisać to co zostało podane na wejściu układu do rejestru A.

Jesteśmy w bloczku oznaczonym literami WE. Musimy przedostać się do rejestru A. Jaką ścieżką możemy pójść? Górna, biegnąca przez ADR3 odpada, gdyż możemy nią dotrzeć tylko do sumatora. Pozostaje dolna, biegnąca przez multiplekser ADR1 i demultiplekser ADR2. Konstruujemy pierwszy cykl.

Multiplekser ADR1 powinien przekazać swoje pierwsze wejście na wyjście. Ustawiamy ADR1 na 0.

Znajdujemy się teraz pomiędzy ADR1 i ADR2. Co musimy zrobić aby dostać się do rejestru A? Jesteśmy już bardzo blisko.

Demultiplekser ADR2 musi przekazać swoje wejście na pierwsze wyjście, abyśmy trafili do rejestru A. Ustawiamy więc ADR2 na 0.

To jeszcze nie koniec. Musimy zapisać to co trafiło na wejście rejestru A. Możemy to zrobić ustawiając LDA na wartość 1.

Podsumujmy nasze rozważania. Zapiszmy kroki które poczyniliśmy wyżej w postaci cykli:
t0: ADR1=0, ADR2=0
t1: LDA=1

Przykład drugi (B=B+WE)

Ścieżka danych

Wykonamy teraz nieco trudniejsze zadanie. Spróbujemy do rejestru B zapisać sumę wartości zapisanej w rejestrze B i wartości podanej przez wejście WE.

Pierwszy cel który znajduje się na horyzoncie to dotarcie do sumatora. Jaką drogę możemy obrać?

Pierwszą przeszkodą jest multiplekser ADR3. Musimy ustawić ADR3 na zero, gdyż WE znajduje się na pierwszym wejściu multipleksera. Wartość z multipleksera trafia do sumatora.

Wartość z rejestru B trafia bezpośrednio do sumatora. Nie musimy nic robić.

A więc t0: ADR3=0. Dotarliśmy do sumatora, który zsumował nam te dwie wartości. Znajdujemy się w bloczku Rwy. Rwy jest też rejestrem, który zwany jest rejestrem buforowym. Zapobiega on pętli asynchronicznej. Co to jest? Dowiesz się niebawem, kiedy będziemy projektowali takie układy.

Tymczasem musimy przejść przez ten rejestr. Rejestr jak rejestr, musimy ustawić jego pin LD na 1. Pamiętamy, że rejestry powinniśmy ustawiać w oddzielnych cyklach.

t1: LDRwy=1

Tworzymy cykl t2. Dotarliśmy do ADR1, tylko tym razem wchodzimy do niego dolnym pinem. Wnioskujemy, że musimy ustawić jego wartość na 1. ADR2 także musimy ustawić na jeden, gdyż drugi, dolny pin jest połączony z rejestrem B, do którego powinniśmy zapisać wynik.

Viola: Dotarliśmy do celu. Ostatni cykl: t3, będzie zawierał tylko jedną instrukcję: LDB=1. Potwierdzamy, że chcemy zapisać do tego rejestru to co do niego doprowadziliśmy.

Podsumujmy nasze cykle:
t0: ADR3=0
t1: LDRwy=1
t2: ADR1=1, ADR2=1
t3: LDB=1

Zadanie domowe

Rozumiesz już jak działa ścieżka danych, prawda? Dla przećwiczenia możesz wymyślić sobie inne rozkazy i spróbować zaprojektować mikrooperacje do nich. Poniżej podaję kilka pomysłów:
1. A=WE+B
2. WY=A+B
3. WY=A
4. WY=B

Podsumowując

Dowiedzieliśmy się jak działa ścieżka danych. Nauczyliśmy się także jak napisać podstawowe mikrooperacje. W następnym artykule przedstawię proces projektowania prostej ścieżki danych.

Chcesz być na bieżąco z moimi artykułami, prawda? Kliknij więc ten czerwono-biały dzwoneczek w lewym dolnym rogu ekranu. Będziesz dzięki temu otrzymywał powiadomienia o nowych wpisach i artykułach.

Jeśli zauważyłeś jakiś błąd, masz jakieś uwagi – śmiało: pisz. Jestem otwarty na wszelką krytykę.


Jeden komentarz

  1. Przydatny i dobrze zrobiony artykuł, bardzo pomocny w zrozumieniu projektowania. Czy zamierzasz napisać coś o kodowaniu instrukcji mikroprocesora i ich minimalizowaniu? Kompletnie nie mam pojęcia jak to się robi i po co, myślę że nie tylko mi by to pomogło w zrozumieniu. Pozdrawiam.

    fan

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *