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?
źródło
Odpowiedzi:
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.
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
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.
źródło
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.
źródło
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.
źródło
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.
źródło
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.
źródło
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.
źródło
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 .
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:
źródło