Kody ISA --- Skąd pochodzą?

13

Gdy inżynierowie projektują architekturę zestawu instrukcji, zgodnie z jaką procedurą lub protokołem, jeśli w ogóle, postępują zgodnie z instrukcją, wskazując określone kody binarne. Na przykład, jeśli mam ISA, który mówi, że 10110 jest instrukcją ładowania, skąd ta liczba binarna pochodzi? Czy został modelowany z tabeli stanów dla skończonej maszyny stanów reprezentującej operację ładowania?

Edycja: po przeprowadzeniu dalszych badań uważam, że to, o co staram się zapytać, dotyczy tego, w jaki sposób przypisywane są kody dla różnych instrukcji procesora. ADD może być oznaczony kodem operacyjnym 10011; instrukcja ładowania może być oznaczona jako 10110. Jaki proces myślowy polega na przypisywaniu tych kodów binarnych do zestawu instrukcji?

Steven
źródło
8
Monte Dalrymple, „Projektowanie mikroprocesorów za pomocą Verilog HDL”, zapewnia bardzo szczegółowe podejście do projektowania procesora Z80 i na tej podstawie sądzę, że wiele się nauczyłeś. Istnieje jednak wiele rozważań, które należy podjąć w związku z konkretnym wyborem, w tym analiza statystyczna innych zestawów instrukcji, wyników kompilatora itp. Polecam jednak zacząć od tej książki. Mimo, że zaczyna się od znanego projektu, wprowadza go w intymne szczegóły i myślę, że wybrałbyś kilka rzeczy. Dobra książka.
jonk
A może pytasz o konstrukcję silnika wykonawczego i zastanawiasz się, w jaki sposób mogą się w to bić bity instrukcji? Nie jestem pewien z twojego sformułowania.
jonk
2
Ktoś inny zadaje to pytanie. To musi być wtorek.
Ignacio Vazquez-Abrams,
5
@ Steven Pomyśl o tym. Jeśli ty miał zaprojektować ISA, co by pan zastanowić? Jeśli Twoje instrukcje nie były tej samej długości, w jaki sposób możesz wybrać krótsze lub dłuższe słowa instrukcji, dla których instrukcje? Jeśli miał zaprojektować etap dekodowania , czego można chcieć dla ISA wyglądać? Myślę, że pytanie jest niepotrzebnie obszerne (a zatem prawie niemożliwe do udzielenia pełnej odpowiedzi), ale możesz je znacznie poprawić, wkładając w to więcej własnych przemyśleń i zadając dokładne pytanie, które nie wymagałoby od nas napisania książki, aby odpowiedzieć to.
Marcus Müller,
4
Specyfikacje RISC-V mówią o decyzjach projektowych podjętych na wszystkich poziomach, w tym sporo o kodowaniu instrukcji maszynowych. (Jest to niezwykłe w przypadku instrukcji procesora; RISC-V to ćwiczenie akademickie pierwsze, a architektura procesora drugie, w przeciwieństwie do większości.)
zwolnij

Odpowiedzi:

6

W wielu przypadkach wybór jest dość arbitralny lub oparty na „gdziekolwiek najlepiej pasuje”, gdy ISA rosną z czasem. Jednak MOS 6502 jest wspaniałym przykładem układu, w którym projekt ISA był pod silnym wpływem próby wyciśnięcia jak najwięcej z ograniczonych tranzystorów.

Obejrzyj ten film wyjaśniający, w jaki sposób 6502 został poddany inżynierii wstecznej , szczególnie od 34:20.

6502 to 8-bitowy mikroprocesor wprowadzony w 1975 roku. Chociaż miał o 60% mniej bramek niż Z80, był dwa razy szybszy i chociaż był bardziej ograniczony (pod względem rejestrów itp.), Nadrobił to elegancki zestaw instrukcji.

Zawiera tylko 3510 tranzystorów, które zostały ręcznie wyciągnięte przez mały zespół ludzi czołgających się po dużych plastikowych arkuszach, które później optycznie się zmniejszyły, tworząc różne warstwy 6502.

Jak widać poniżej, 6502 przekazuje dane opcode i timing instrukcji do ROM dekodowania, a następnie przekazuje je do komponentu „logiki losowej kontroli”, którego celem jest prawdopodobnie unieważnienie wyjścia ROM w pewnych skomplikowanych sytuacjach.

Schemat blokowy 6502

O 37:00 na wideo widać tabelę ROM z dekodowaniem, która pokazuje, jakie warunki muszą spełniać wejścia, aby uzyskać „1” dla danego wyjścia sterującego. Możesz go również znaleźć na tej stronie .

Widać, że większość rzeczy w tej tabeli ma X w różnych pozycjach. Weźmy na przykład

011XXXXX 2 X RORRORA

Oznacza to, że pierwsze 3 bity kodu operacji muszą mieć wartość 011, a G musi wynosić 2; Nie ma niczego ważniejszego. Jeśli tak, dane wyjściowe o nazwie RORRORA zostaną spełnione. Wszystkie kody ROR zaczynają się od 011; ale są też inne instrukcje, które zaczynają się od 011. Prawdopodobnie muszą one zostać odfiltrowane przez jednostkę „logiki losowej kontroli”.

Zasadniczo więc wybrano kody, aby instrukcje, które musiały robić to samo, miały ze sobą coś wspólnego. Możesz to zobaczyć, patrząc na tabelę opcode ; wszystkie instrukcje OR zaczynają się od 000, wszystkie instrukcje Store zaczynają się od 010, wszystkie instrukcje korzystające z adresowania zerowej strony mają postać xxxx01xx. Oczywiście niektóre instrukcje nie wydają się „pasować”, ponieważ celem nie jest posiadanie całkowicie normalnego formatu opcode, ale raczej dostarczenie potężnego zestawu instrukcji. I dlatego konieczna była „logika losowej kontroli”.

Na stronie, o której wspomniałem powyżej, napisano, że niektóre wiersze wyjściowe w pamięci ROM pojawiają się dwukrotnie: „Zakładamy, że zostało to zrobione, ponieważ nie mieli możliwości routowania wyjścia niektórych wierszy tam, gdzie chcieli, więc umieścili ten sam wiersz w innym wierszu lokalizacja ponownie ”. Mogę sobie tylko wyobrazić, jak inżynierowie ręcznie rysują te bramy jeden po drugim i nagle uświadamiają sobie wadę projektu i próbują wymyślić sposób, aby uniknąć ponownego rozpoczęcia całego procesu.

Artelius
źródło
22

To zależy, ile lat ma ISA.

Na początku projektowania ręcznego, a tym bardziej, gdy procesory były montowane z dyskretnej logiki, projekt logiki byłby na pierwszym miejscu i został znacznie zminimalizowany, a następnie wzorce bitowe ISA byłyby tymi wartościami, które byłyby wymagane, aby uczynić to minimum praca logiczna.

Może więc istnieć szczególny wzorzec sygnałów sterujących, które umożliwiają niektórym multiplekserom połączenie wyjścia ALU z wejściem pliku rejestru GP, kilka innych sygnałów sterujących, które instruują ALU, aby dodawać, odejmować, ORAZ, LUB itd., A także kilka adresuj bity do pliku rejestru. Te trzy grupy sygnałów utworzą pola w instrukcji. Każda grupa będzie trzymana razem, a ich szczegółowe znaczenie wynika z projektu tej jednostki (ALU itp.), Ale grupy mogą być w dowolnej kolejności, aż do zaprojektowania dekodera instrukcji. (x86 jest na tyle stary, że można go wykryć, jeśli spojrzysz w odpowiednie miejsce - nie był to całkowicie nowy projekt, ale pochodzi ze starszego 8080)

Późniejsze ISA można „wyczyścić” i uczynić bardziej regularnym i prostszym w użyciu, ze sprzętem do translacji między nimi a faktycznymi sygnałami sterującymi na poziomie sprzętu, czasami za pomocą „mikrokodu”. Są to tak zwane „CISC” lub „Kodowanie zestawu instrukcji złożonych”. Przedrostek instrukcji „Rep” x86 jest tego prostym przykładem - powoduje kilkakrotne powtórzenie poniższej instrukcji, co pozwala uniknąć konieczności zapisywania pętli FOR.

Później (w latach 80.) nastąpił powrót do prostszego stylu kodowania bezpośredniego (RISC - kodowanie zestawu instrukcji zredukowanych), które można zobaczyć w procesorach ARM. Było to spowodowane niewielkim rozmiarem układów ASIC w tym czasie i chęcią zainstalowania na nich 32-bitowych procesorów, stąd nie było wolnej mocy na złożone dekodery zestawu instrukcji, aby obniżyć cały procesor do około 20 000 bramek. (Nastąpił także tymczasowy wzrost wydajności, ponieważ ludzie nie opracowali jeszcze technik, aby przyspieszyć dekodery CISC - to miało miejsce około 1995 roku z Pentium Pro)

W dzisiejszych czasach nie ma to znaczenia - procesory czytają kilka instrukcji na raz i poświęcają miliony tranzystorów na ich dekodowanie, porządkowanie i wykonywanie jak największej liczby naraz, aby przyspieszyć programy napisane dla najstarszych styl ISA.

Brian Drummond
źródło
2
Nie jestem pewien, czy naprawdę nazwałbym CISC „łatwiejszym w użyciu”. To może być pierwotna intencja, ale 30 lat później są one swoistą antytezą „łatwego w użyciu” (przynajmniej w porównaniu do ISA RISC).
tonysdg,
2
Są aspekty, w których były łatwiejsze w użyciu ... albo regularność (ortogonalność była dużym tematem) w przeszłości, gdy kompilatory były programami stosunkowo trywialnymi, lub poprzez bezpośrednie wspieranie operacji wyższego poziomu, wymagających mniejszego tłumaczenia z kompilatora. Ale to było dawno temu i każdy ocalały CISC ma tak wiele warstw poprawek oprócz oryginalnego zestawu instrukcji. Kompilatory również zmieniły się nie do poznania - wówczas około tysiąca przejść optymalizacyjnych wykonywanych przez gcc byłoby nie do pomyślenia. To, co było „łatwe” wtedy i teraz ma bardzo niewielki związek.
Brian Drummond,
4
To rozróżnienie zostało zarówno zatarte (zestawy „RISC” dodające więcej instrukcji), jak i zastąpione przez nowe, jeszcze bardziej złożone architektury, takie jak VLIW; naprawdę jedynym konsensusem jest to, że x86 (16 i 32 bity) jest trudny w użyciu
pjc50
1
@tonysdg: Trudno korzystać z RISC i trudno używać CISC. Dobrym porównaniem „przyjazności dla programistów” jest porównanie 68k vs ARM. ARM został zaprojektowany dla kompilatora, więc trzeba było wykonać wiele pracy ręcznej, aby uzyskać dane z pamięci RAM i zapisać ją ponownie w pamięci RAM. 68k został zaprojektowany dla programistów asemblera i pozwala bezpośrednio operować na danych w pamięci RAM. Jeśli spojrzysz na 68k ISA, zobaczysz, że przypomina on nowoczesny RISC ISA z jednym wyjątkiem - możesz operować bezpośrednio na pamięci RAM, podczas gdy RISC pozwala tylko na rejestry.
slebetman
1
Mikrokod jest przede wszystkim atrybutem CISC. Jednak można zaimplementować CISC bez mikrokodu: dekoder instrukcji byłby bardziej skomplikowany. Zobaczysz także niektóre CISC od Pentium-Pro opisane wewnętrznie jako RISC; tłumaczenie każdej instrukcji CISC na jedną lub więcej wewnętrznych operacji RISC: inna nazwa mikrokodu (chociaż różnice są rozmazane w superskalarnych jednostkach wykonawczych)
Brian Drummond
9

Jeśli zgrupujesz podobne instrukcje razem, pojawią się wzorce. Jest to bardzo oczywiste w ARM, gdzie instrukcja ISA faktycznie pokazuje, który bit słowa instrukcji odpowiada funkcji, wyborowi rejestru itp. Ale można to również wywnioskować dla X86 .

Ostatecznie część „funkcyjna” opcodów przechodzi do jakiegoś dekodera binarnego do pojedynczego, który faktycznie aktywuje określoną funkcję lub sekwencję operacji potokowych. Zazwyczaj nie są one powiązane z zawartością jakiejkolwiek maszyny stanów, chyba że rozważamy instrukcje o zmiennej długości, które wymagają maszyny stanu do dekodowania.

pjc50
źródło
Mówisz w zasadzie, że szukają najniższej możliwej liczby tranzystorów w układzie. Całkowicie się zgadzam w kontekście pytania OP, w którym nie stać ich na setki dodatkowych tranzystorów na porządniejszy zestaw instrukcji. Procesory z milionem tranzystorów nie mają prawie tak ważnego powodu, aby się tym przejmować, ale oczywiście wielu zachowuje je ze względu na kompatybilność wsteczną.
Harper - Przywróć Monikę
@Harper Jest jeszcze powód, ponieważ chociaż tranzystory są mniejsze, nadal mają swój rozmiar - a tymczasem częstotliwość taktowania znacznie wzrosła. Tak więc dekoder instrukcji, który jest zbyt duży, może nadal stanowić wąskie gardło pod względem wydajności (jeden z powodów, dla których wiele procesorów zdecydowało się na wcześniejsze instrukcje dekodowania). Nie chodzi tylko o liczbę tranzystorów, ale o częstotliwość taktowania w połączeniu z obszarem matrycy. Rozpowszechnianie informacji wciąż wymaga czasu i chociaż współczesne procesory nie działają z prędkością światła, nie są wystarczająco daleko od ograniczenia prędkości, aby spodziewać się znacznej poprawy.
Luaan,
@Luaan: Właściwie „co robimy z tymi wszystkimi tranzystorami” jest obecnie prawdziwym pytaniem. Spójrz na wszystkie rzucane obecnie skrzynki L2 / L3. To ciche przyznanie, że nie mamy lepszego zastosowania dla wszystkich milionów tranzystorów. Najnowsze pamięci Xeon poświęcają ponad 2 miliardy tranzystorów do buforowania!
MSalters
6

Ktoś w pewnym momencie usiadł i zdefiniował ich.

Dobry ISA sprawi, że dekoder będzie tak prosty, jak to możliwe.

Na przykład za pomocą instrukcji ALU możesz pozwolić, aby niektóre bity kodu operacji były wysyłane bezpośrednio do linii kontrolnych ALU.

maniak zapadkowy
źródło
Dziękujemy wszystkim za doskonałe odpowiedzi. Wszyscy pomogliście mi zrozumieć to znacznie lepiej.
Steven
4
W rzeczywistości należy wziąć pod uwagę kilka czynników innych niż prostota dekodera. W zależności od okoliczności i zamierzonego zastosowania inne (np. Gęstość kodu) mogą być ważniejsze niż prostota dekodera. W nowoczesnym procesorze gęstość kodu prawdopodobnie w większości przypadków przewyższa prostotę dekodera .
Jerry Coffin,
5

Zazwyczaj dzielisz ISA na grupy funkcyjne. Ma to sens (zarówno dla optymalizacji logiki, jak i dla zachowania porządku), że pary komplementarne są różnicowane pojedynczą zmianą bitu (ładunek względem magazynu) i że istnieje pewna hierarchia bitów, która wpływa na drzewo decyzyjne.

Na koniec dnia dowolna alokacja bitów dla bloku funkcyjnego (w przeciwieństwie do umieszczania pól „danych” w instrukcji będzie miała niewielki wpływ na ogólną wydajność projektu - ale masz wiele możliwości wyboru, w jaki sposób „zoptymalizuj” kodowanie ISA w zależności od tego, co uważasz za ważny parametr.

Sean Houlihane
źródło
1

Kodowanie instrukcji jest brzydkim kompromisem pomiędzy.

Upraszczając dekodowanie, potrzebujesz prostego zestawu pól, z których każde może być osobno dekodowane i kierowane do oddzielnej części silnika wykonawczego.

Pakowanie jak największej funkcjonalności w ograniczony rozmiar słowa instrukcji. Prowadzi to do takich rzeczy, jak specjalne stałe formaty, które mogą kodować różne wspólne liczby.

Kompatybilność do przodu i do tyłu. Jeśli przypiszesz funkcjonalność do każdego możliwego kodu operacji, nie będziesz mieć możliwości późniejszego rozszerzenia architektury. Jeśli dodajesz do istniejącej architektury, musisz umieścić nowe instrukcje w zapasowych kodach operacyjnych.

Peter Green
źródło
1

Znakomita (choć nieco przestarzała) Randy Hyde Art of Assembly jest szczegółowo opisana w zestawie instrukcji x86 w rozdziale 3.3.4. Jednostka sterująca i zestawy instrukcji .

Programy we wczesnych systemach komputerowych (sprzed Von Neumanna) były często „na stałe” podłączone do obwodów. Oznacza to, że okablowanie komputera określiło, jaki problem rozwiąże komputer. Aby zmienić program, trzeba było przełączyć okablowanie. Bardzo trudne zadanie. Kolejnym postępem w projektowaniu komputerów był programowalny system komputerowy, który umożliwił programistom łatwe „ponowne okablowanie” systemu komputerowego za pomocą sekwencji gniazd i przewodów wtykowych. Program komputerowy składał się z zestawu rzędów otworów (gniazd), przy czym każdy rząd reprezentował jedną operację podczas wykonywania programu. Programista może wybrać jedną z kilku instrukcji, podłączając przewód do określonego gniazda dla żądanej instrukcji.

Następnie demonstruje dość chwytliwy i wyczerpujący sposób, w jaki pierwsza para wtyczek oznacza instrukcję, kolejne wtyczki kodują źródło i miejsce docelowe. Oczywiście dzisiaj nikt już nie „podłącza”, ale w przypadku naprawdę starych ISA bity w kodzie operacyjnym w zasadzie wykonują tę samą pracę, co wcześniej wtyczki.

W efekcie powstaje coś takiego:

wprowadź opis zdjęcia tutaj

DevSolar
źródło
Dziękujemy za link od Hyde! Jest to bardzo pouczające i wydaje się, że ma doskonały styl nauczania.
Steven