architektura - kapitanat.pl
Transkrypt
architektura - kapitanat.pl
architektura IA-64 Maciej Mazur Wstęp.......................................................................................................................................... 3 Główne idee IA-64 ..................................................................................................................... 3 Zgodność z IA-32 oraz PA-RISC ___________________________________________________ 3 64 bitowość ____________________________________________________________________ 4 Współpraca Kompilatora z procesorem_______________________________________________ 5 Równoległość wykonania instrukcji (ILP) ____________________________________________ 5 Mechanizmy zastosowane w architekturze IA-64 .................................................................... 6 EPIC czyli paczkowanie instrukcji __________________________________________________ 6 Cechy zestawu instrukcji __________________________________________________________ 9 Rejestry ______________________________________________________________________ 11 Rejestry rotujące _______________________________________________________________ 22 Spekulatywne wykonywanie kodu oraz spekulatywny dostęp do pamięci ___________________ 24 Skoki (zapobieganie, przewidywanie, unikanie) _______________________________________ 27 Pierwszy procesor IA-64 Itanium ........................................................................................... 29 Rozkład rejestrów w Itanium______________________________________________________ 29 Instrukcje procesora Itanium ______________________________________________________ 32 Otoczenie procesora Itanium ______________________________________________________ 32 Przewidywania dotyczące procesorów opartych na IA-64 ..................................................... 32 Porównanie Itanium z innymi procesorami ___________________________________________ 32 Oprogramiowanie dedykowane dla IA-64____________________________________________ 32 Kolejne procesory IA-64 _________________________________________________________ 33 Słownik..................................................................................................................................... 34 Zakończenie ............................................................................ Błąd! Nie zdefiniowano zakładki. 2 Wstęp W roku 1988 firmy Intel oraz HP nawiązały współpracę, której owocem jest nowa architektura procesora nazwana IA-64. Procesory z tej rodziny, są w pełni 64 bitowe i zapewniają pełną kompatybilność z architekturami IA-32 znanej także pod nazwą x86, oraz PA-RISC. Pierwszym procesorem który ma być stworzony na bazie IA-64 jest Itanium, (zwany dawniej Meced) który przygotowywany jest przez firmę Intel. Architektura Ia-64 została zaprojektowana, aby przezwyciężyć dotychczasowe ograniczenia stworzone przez tradycyjne architektury, oraz nie stawiać barier w przyszłości. Aby to osiągnąć IA-64 ma w sobie całą listę innowacji technicznych wspomagających równoległość wykonywania instrukcji. Te innowacje to przede wszystkim: spekulatywne wykonywanie kodu, predykaty, wielka liczba rejestrów, rotujące rejestry, zaawansowana technologia przewidywania i zapobiegania skokom, oraz wiele innych. W tej architekturze wykorzystuje się 64 bitowe adresowanie pamięci, co jest wymagane przy rosnącym zapotrzebowaniu na pamięć przez obecne programy. Architektura IA-64 posiada innowacyjną jednostkę zmiennoprzecinkową oraz inne udogodnienia, aby zaspokoić zapotrzebowanie na wielką moc obliczeniową stawiane przez takie aplikacje jak CAD/CAE lub naukowe aplikacje numeryczne Architektura IA-64 jest bardzo nowoczesną architekturą, chociaż czerpie dużo z istniejących już rozwiązań. IA-64 cechuje się własnościami, które pozwalają utrzymać osiągi na wysokim poziomie, jednocześnie usuwają bariery, dla późniejszego zwiększenia osiągów. Architektura IA-64 opiera się na następujących zasadach: • Równoległe wykonanie kodu - mechanizm współpracy pomiędzy kompilatorem, oraz procesorem - grupowanie zasobów dla zwiększenia korzyści równoległości instrukcji - duża liczba różnorodnych rejestrów - wsparcie dla wielu zespołów wykonujących • Cechy które podnoszą korzyści równoległego wykonywania instrukcji - spekulatywne wykonywanie kodu - predykaty (które usuwają skoki) - programowe "unrolowanie" krótkich pętli • Inne ważne cechy które podwyższają efektywność wykonywania programów - specjalne wsparcie dla modularności oprogramowania - wysoka wydajność jednostki zmiennoprzecinkowej - instrukcje typowo multimedialne Główne idee IA-64 Zgodność z IA-32 oraz PA-RISC Architektura IA-64 została tak zaprojektowana, aby była kompatybilna dotychczasowymi rozwiązaniami takimi jak IA-32 oraz PA-RISC. Ponieważ architektura PA-RISC jest w miarę nowoczesną architekturą, nie mającą takiego balastu starych rozwiązań jak IA-32, to nie ma większych problemów z zachowaniem kompatybilności. Większy problem to zgodność z IA32. Pamiętając, że pierwsze procesory tego typu były projektowane w zamierzchłych jak na dzisiejsze technologie czasach, niosą one ze sobą wiele rozwiązań z którymi nie da się w prosty sposób utrzymać kompatybilności. Inżynierowie projektujący architekturę IA-64 3 zdecydowali się na swego rodzaju sprzętowy emulator. Procesor z rodziny IA-64 może być przestawiony w tryb pracy IA-32 i zachowywać się zupełnie jak procesor z serii x86. Za punkt odniesienia uznano procesor Pentium III Xeon. Trzy specjalne instrukcje oraz przerwania zostały zdefiniowane, aby zapewnić przestawienie się procesora pomiędzy zestawem instrukcji IA-32 a IA-64. Te instrukcje to: - jmpe (instrukcja IA-32) – Skok do jakiejkolwiek instrukcji IA-64, czyli zmiana zestawu instrukcji na IA-64 - br.ia (instrukcja IA-64) – Skok do instrukcji IA-32, zmiana zestawu instrukcji na IA-64 - przerwania które przestawiają procesor do stanu IA-64 i obsługują w tym trybie żądanie. - rfi (instrukcja IA-64) – "return form interruption" powrót z przerwania. Instrukcja ta została zdefiniowana do powrotu do zestawu IA-32 lub IA-64 Instrukcje jmpe oraz br.ia dostarczają niskopoziomowego mechanizmu do przejścia pomiędzy zestawami instrukcji. Te dwie instrukcji są zwykle włączane do kodu, aby zaimplementować potrzeby linkowania oraz wywoływania dynamicznego lub statycznego zlinkowanych bibliotek. Problem odpowiednich rejestrów rozwiązano w dwojaki sposób. Główne rejestry zostały dodane specjalnie dla trybu IA-32, chociaż oczywiście można z nich korzystać w trybie 64bitowym. Rejestry te znajdują się jako odpowiednie Rejestry Aplikacyjne. Dodatkowo rejestry ogólnego przeznaczenia, oraz zmienno-przecinkowe są odpowiednio mapowane do pracy w trybie IA-32. Przykładem może być mapowanie rejestrów SIMD, które są mapowane w rejestrach zmiennoprzecinkowych. Dane każdego 128-bitowe rejestru SIMD znajdują się fizycznie w dwóch 82-bitowych rejestrach zmiennoprzecinkowych po 64 bity w każdym. Zarówno Intel jak i Hewlett-Packard podkreślają, iż jedynie programy kompilowane z myślą o IA-64 będą w stanie spożytkować nowe cechy architektury, jednakże obydwaj producenci twierdzą iż programy napisane z myślą o istniejących już systemach będą działać na IA-64. Dla dodatkowej pewności HP oferuje specjalne narzędzia pod nazwą Software Transition Kit. Ten zespół programów umożliwia przetestowanie istniejącego oprogramowania pod kątem używalności na IA-64, a także ewentualne jego uzdatnienie. Narzędzie to jak na razie jest pomyślane do pracy z programami kompilowanymi z języków C, C++, Fortran, oraz Cobol. Microsoft zapewnia, iż w nowym systemie Windows dla IA-64, (który ma się ukazać w tym samym terminie co pierwszy procesor IA-64) będą działać wszystkie programy napisane dla dzisiejszego Windowsa, a aby wykorzystać cechy nowego procesora należy tylko ponownie skompilować źródła bez żadnych poprawek. 64 bitowość Dzisiejsze 32-bitowe architektury najczęściej mogą adresować do 4 GB pamięci operacyjnej. Jest też tak w przypadku 32-bitowych produktów Intela. To całkowicie wystarcza przy dzisiejszych wymaganiach głównych aplikacji. Jednak rozwój oprogramowania szczególnie wielkich baz danych kontynuuje wzrost zapotrzebowania na pamięć. Szacuje się iż, rozmiar pamięci operacyjnej będzie szybko zwiększał się w kolejnych generacjach komputerów. W odpowiedzi na zapotrzebowanie architektury 64-bitowe zwiększają zdolności systemów do adresowania wielkich przestrzeni pamięci operacyjnej. Różnica w osiągach może być widoczna dla aplikacji których zapotrzebowanie na pamięć będzie większe niż owe 4 GB. Przykładami aplikacji które w najbliższym czasie mogą przełamać taką granicę mogą być wielkie bazy danych, serwery różnorodnych usług internetowych, oraz nowa linia aplikacji 4 biznesowych. Cena pamięci stale maleje, co powoduje, że wkrótce, będzie opłacalne posiadanie pamięci operacyjnej liczonej w dziesiątkach gigabajtów. Połączenie takiej ilości pamięci oraz 64-bitowej szyny adresowej będzie pozwalało na znaczące polepszenie osiągów w wielu systemach. IA-64 nie jest pierwszą architekturą która używa 64-bitowego adresowania. Dzisiejsze RISCowe architektury takie jak HP’s PA-RISC, Sun UltraSPARC, Compaq Alpha, oraz IBM PowerPC, są już 64-bitowe. Ale „64-bitowość” to tylko element sukcesu, potrzebne jest również wsparcie do obsługi wielkich rozmiarów pamięci (a to nie tylko szeroka szyna adresowa). IA-64 będzie posiadała wszystkie potrzebne cechy aby pracować z tak dużą przestrzenią pamięciową, a cechy te to: dostosowany sprzęt, system operacyjny, oraz oprogramowanie które będzie potrafiło korzystać z takich zdolności systemu. Współpraca Kompilatora z procesorem Kluczową ideą cechującą architekturę IA-64 to przesunięcie wszystkich możliwych zadań z procesora do kompilatora. Takie podejście daje możliwość takiego przygotowania kodu wykonywalnego, którego procesor nie będzie musiał już analizować. Dzisiejsze procesory analizują kod w poszukiwaniu sposobów wykonania go równolegle, lub aby przewidzieć możliwe w najbliższym czasie skoki. Podejście bazujące na przerzuceniu tych zadań do kompilatora, powoduje możliwość lepszego przeanalizowania kodu. Kompilator ma do dyspozycji kod źródłowy, a nie tylko wykonywalny, oraz dużo więcej czasu na obliczenia. Mechanizmy zastosowane w procesorach są tak skonstruowane, aby praca poświęcona na analizę była z nawiązką wyrównana przez oszczędności które są poczynione, gdyż inaczej jest to nie opłacalne. Kompilator nie ma takiego ograniczenia. Jedynym problemem jest właściwe przekazanie informacji z kompilatora do procesora. IA zawiera mechanizmy takie jak: pola template w paczkach instrukcji, wskazówki co do przewidywania skoków, oraz podpowiedzi jakie dane ładować do cache, które pozwalają kompilatorowi na optymalne przygotowywanie kodu wykonywalnego. Dodatkowo IA pozwala skompilowanemu programowi na zarządzanie zasobami procesora korzystając z informacji czasu wykonania. Taki mechanizm pozwala na zminimalizowania opóźnień systemu związanymi ze skokami oraz niecelnymi zapisami danych do cache. Każdy zapis oraz odczyt z pamięci w IA ma 2 bitowe pole podpowiedzi w cache, w którym kompilator koduje przewidywaną częstotliwość dostępu do tej porcji danych. Niektóre dane które mogą być wykorzystywane tylko raz przez cały czas wykonywania programu, natomiast inne mogą być potrzebne bardzo często. Pole przewidywanej częstotliwości dostępu służy właśnie do tego, aby procesor na tej podstawie decydował o ewentualnym załadowaniu części pamięci do cache. Taka technika pozwala na lepsze zarządzanie pamięcią cache, zredukowanie chybionych zapisów do pamięci, szczególnie iż w obecnym czasie zwiększają się dysproporcje pomiędzy szybkością pamięci cache oraz zwykłej. Równoległość wykonania instrukcji (ILP) Wzrost osiągów mikroprocesorów osiąga się poprzez zwiększanie częstotliwości zegara, oraz przez zwiększanie ilości wykonanej pracy w jednym cyklu zegarowym. Procesory IA-64 będą zwiększać ilość wykonanej pracy w jednym cyklu zegara poprzez możliwość zwiększenia korzyści z wewnętrznej równoległości wykonywania. Dzisiejsze mikroprocesory już czerpią korzyści z równoczesnego wykonywania instrukcji. Wiele typów procesorów dynamicznie planuje wykonanie równoległe obserwując zależności występujące w strumieniu instrukcji. Taki sposób grupowania instrukcji do równoległego wykonania wyraźnie podwyższa osiągi 5 procesora, ale nie jest oczywiste czy wychodzenie ponad standardowe dzisiejsze cztero drożne wykonanie jest warte swojego nakładu pracy. Jeśli wierzyć zapewnieniom IA-64 będzie w stanie działać znakomicie powyżej czterokrotnym równoczesnym wykonywaniem. Będzie to możliwe oczywiście nie z istniejącymi binariami. Taka równoległość jest możliwa przy pomocy kompilatorów które będą w stanie bardziej dokładnie przeanalizować kod źródłowy pod kątem równoległego wykonania. Dodatkowo być może bardziej popularne staną się języki programowania które umożliwiają programiście najbardziej optymalne zaplanowanie równoległego wykonania. Dzisiejsze języki programowania odzwierciedlają naturę konwencjonalnych komputerów. Problemy które mają naturę równoległą (na przykład operacje na macierzach) są dzisiaj reprezentowane poprzez wielokrotnie zagnieżdżone pętle. Zaawansowane kompilatory dla maszyn z równoległym przetwarzaniem (na przykład dzisiejsze superkomputery) potrafią z powrotem przekształcić takie pętle na równoległa reprezentację problemu. Umożliwia to znaczne zyski na szybkości w komputerach równoległych lub wektorowych. Nic jednak nie da takich pożytku z równoległego wykonania jak generowanie binariów z kodu źródłowego w którym równoległość jest już jasno wyrażona. Nie powodowałoby to niepożądanego zjawiska polegającego na linearyzowania problemów przez programistę, po czym te problemy zostają powtórnie (z tym, że już maszynowo) przekształcane do pierwotnej struktury. Taka prawidłowość oczywiście tyczy się również architektury IA-64. Co prawda Intel oraz HP będą prowadzić wspaniałe wsparcie dla istniejącego oprogramowania, poprzez sprzętową zgodność, ale nie ma co się spodziewać ze to oprogramowanie będzie czerpać większe korzyści z równoległości zaimplementowanej w IA-64 (co tyczy się nie tylko równoległości, ale również innych zaawansowanych mechanizmów zawartych w IA-64). Kod źródłowy zrekompilowany dla potrzeb IA-64 będzie zapewne działać dużo lepiej, jednakże można oczekiwać iż tylko wyraźne wyrażenie równoległości przez programistę będzie powodowało pełne wykorzystanie równoległości w IA-64. Instruction Level Parallelism (ILP) czyli równoległość wykonywania instrukcji, to możliwość wykonywania wielu instrukcji w tym samym czasie. Architektura IA-64 pozwala na grupowanie niezależnych od siebie instrukcji w paczki (po 3 instrukcje). Dla zwielokrotnienia efektu równoległości można przygotować wiele paczek dla jednego cyklu zegarowego. O takie przygotowanie kodu do wykonania troszczy się kompilator. Wyposażony w dużą liczbę zasobów do równoległego wykonywania instrukcji, procesor IA-64 pozwala kompilatorowi zaplanować pracę w przód, oraz zaplanować równoczesne wątki do obliczeń. Kompilatory dla tradycyjnych architektur są często ograniczone w swoich możliwościach wykorzystania informacji o możliwym równoległym wykonywaniu kodu, ponieważ te informacje nie zawsze musiały być prawdziwe. IA-64 pozwala kompilatorowi na wykorzystanie tych informacji, bez obawy o poprawność wykonania programu. W tradycyjnych architekturach procedury ograniczają osiągi dopóki potrzebne rejestry nie zostaną zwolnione i zostaną tam załadowane potrzebne dane. Natomiast IA-64 pozwala kompilatorowi na takie przygotowanie kodu, że operacje na rejestrach można zaplanować wcześniej. Mechanizmy zastosowane w architekturze IA-64 EPIC czyli paczkowanie instrukcji Po ostatniej rewolucji w dziedzinie zestawu instrukcji jaka nastąpiła w roku 1980 kiedy to powstał Reduced Instruction Set Computing (RISC), Intel oraz Hewlett-Packard przygotowali 6 nowy zestaw instrukcji IA-64. Zbliżyli się oni tym sposobem do ideału procesora wykonującego operacje równolegle. Główną ideą przyświecającą technologii EPIC jest grupowanie instrukcji w paczki, która to paczka jest ładowana cala w jednym takcie zegara. Co prawda idea grupowania instrukcji w paczki zastosowana w IA-64 znana już była z procesorów typu VLIW, jednak metoda zastosowana w architekturze IA-64 wydaje się być wiele lepsza. Procesory VLIW (Very Long Instruction Word) były pierwszą architekturą, opracowaną z założeniem, że kod maszynowy ma być w taki sposób przygotowany, że instrukcje mają sobie wzajemnie nie przeszkadzać. Takie instrukcje były grupowane w paczki. Istniały dwa rozwiązania, pierwsze procesory miały ustaloną długość paczki, w kolejnych długość paczki zmieniała się. Procesory tego typu nie upowszechniły się ponieważ na drodze stanęły problemy które architektura VLIW nie była w stanie przezwyciężyć. Głównym problemem był nadmierny rozrost kodu spowodowany niemożnością grupowania instrukcji które są współzależne i jedna korzysta z wyników drugiej. Problemom tego typu zapobiegano poprzez stosowanie szczelin paczkach. Tak więc w jednym cyklu zegarowym procesor dostawał w najgorszym przypadku jedną instrukcję, a dalej pustkę, gdyż długość paczki była stała. Zastosowano inne rozwiązanie tego problemu, a mianowicie zmienną długość paczki. Niestety pojawił się kolejny problem, nie wiadomo czy nie poważniejszy od poprzedniego. Przy zmiennej ilości instrukcji w paczkach kompilator tak układał instrukcje, że były one dedykowane dla konkretnego procesora. Zdarzało się tak zwykle przy dużych paczkach, z dużą ilością instrukcji. Instrukcje te niekiedy były konkretnie dedykowane do określonych jednostek wykonawczych w procesorze. To zmuszało do rekompilacji programów nawet dla kolejnego procesora z serii. Dodatkowo wykluczone zostało przez to przetwarzanie oparte na wielu procesorach bez uprzedniej rekompilacji kodu. Obecnie technologię VLIW stosuje się raczej tylko w specjalizowanych procesorach (na przykład Texas Instruments DSP C6201), lub technologia ta jest stosowana tylko w specjalnych jednostkach wewnątrz procesorów. IA-64 idzie dalej niż poprzednie (CISC, RISC, VLIW) zestawy instrukcji i niosąc ze sobą nowe cechy które zostały nazwane EPIC (czyli Explicitly Paralel Instruction Computing) co po polsku można przetłumaczyć Przetwarzanie Wyraźnie Równolegle. Ta strategia powinna dać procesorom serii IA-64 palmę pierwszeństwa wśród wszystkich innych zestawów instrukcji. Co prawda technika Epic jest podobna do VLIW, ale IA-64 redukuje dwie niedogodności czyli brak skalowalności oraz duże rozrost kodu powstającego przy kompilowaniu programów dla procesorów VLIW. Owe problemy pokonano zaopatrując procesory oparte na architekturze IA-64 w takie cechy jak: bardzo duża liczba rejestrów (około 4 razy więcej niż typowy procesor RISC) bezpośredni dostęp do wszystkich rejestrów przez oprogramowanie, co eliminuje potrzebę mapowania rejestrów, oraz przyspieszony dostęp do cache. Kiedy jest zapotrzebowanie na dostęp do danych spekulatywne ładowanie może całkowicie zniwelować opóźnienie spowodowane przez dostęp do cache, nawet jeśli w międzyczasie odbywają się skoki. Poza tym niektóre skoki mogą być w ogóle wyeliminowane całkowicie poprzez stosowanie predykatów. Główną rolę w metodzie EPIC odgrywa kompilator. Nowoczesny kompilator analizuje program pod kątem wyszukiwania przeszkód dla równoległego wykonywania instrukcji, a później układa instrukcje dla optymalnego wykorzystania procesora. Dzieje się to już w niektórych dzisiejszych kompilatorów dla superskalarnych procesorów, jednak większość obecnych kompilatorów dla architektur CISC lub RISC przygotowuje kod "szeregowo" nie analizując powiązań między instrukcjami. Zadanie zaplanowania równoległości pozostaje 7 procesorowi, który ponownie analizuje kod instrukcja po instrukcji, aby w końcu móc wykonać je równolegle. Dzisiejszy zestaw instrukcji typu CISC czy RISC nie daje możliwości na transfer danych dotyczących sposobu równoległego wykonania od kompilatora do procesorem, tak aby zaplanować wcześniej sposób wykonania. Istnieje wiele wad takiego rozwiązania, po pierwsze kompilator ma wiele czasu na poszukiwanie najlepszego sposobu, a po drugie praca wykonywana by była tylko raz przy tworzeniu kodu maszynowego. Przeniesienie tych zadań do procesora powoduje, iż praca musi być wykonywana przy każdorazowym wykonaniu programu, co gorsza niekiedy wielokrotnie. Dodatkowo procesor traci na dodatkową analizę swoją cenną moc obliczeniową, a co za tym idzie marnuje zyski z równoległego wykonania. Główną ideą przyświecające technologii EPIC jest grupowanie instrukcji w paczki (bundles). Uniknięto tutaj problemu nadmiernego rozrostu kodu stosując unikalny format paczki w której znajdują się instrukcje. Paczka ma długość 128 bitów i zawiera 3 instrukcje oraz tzw. template. Każda instrukcja ma długość 41 bitów, template natomiast 5 bitów. Format paczki instrukcji 127 87 86 46 45 5 4 0 instrukcja 1 instrukcja 2 instrukcja 3 template 41 41 41 5 Dane zawarte w template sygnalizują czy instrukcje w paczce mogą być wykonywane jednocześnie, lub czy jest przymus wykonanie jednej lub więcej szeregowo w związku np. z konfliktem rejestrów. Template informuje jednocześnie czy paczka może być wykonana jednocześnie z następną z kolei paczką. Daje to możliwość układania paczek w łańcuchy tworząc grupy instrukcji dowolnej długości. Ściśle rzecz biorąc zdefiniowany jest tak zwany stop który odgranicza instrukcje które mogą być wykonane razem od tych które mają czekać na zwolnienie zasobów. I tak jeśli wszystkie bity w template są w stanie niskim to nie ma żadnych „stopów” na przeszkodzie, jeśli wartość pola template wynosi 1 to stop znajduje się po 3 instrukcji (następna paczka musi czekać), jeśli wynosi 2 to stop znajduje się po 2 instrukcji i tak dalej analogicznie. Ogólna zasada mówi, że jeżeli najmniej znaczący bit w template ma wartość zero to paczka nie może być wykonywana równolegle z następną w kolejce. Dodatkowo informacje w template informują o typie jednostki wykonującej tą instrukcje. Jeśli wartość pola template wynosi 0 to znaczy, że pierwsza instrukcja ma być przetwarzana przez jednostkę zarządzającą pamięcią, a druga oraz trzecia przez jednostkę arytmetyki stałoprzecinkowej. Niestety na 5 bitach nie da się zakodować wszystkich możliwości ułożenia stopów, wraz z określeniem jaka jednostka wykonawcza ma zajmować się daną instrukcją. Tabela przedstawiająca zaimplementowane kombinacje: Template 0 1 2 3 4 5 6 00 01 02 03 04 05 06 instrukcja 1 instrukcja 2 instrukcja 3 M M M M M M I I I I L L I I I I X X 8 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F M M M M M M M M M M M M M M M M F F M M I I B B I I I I I I F F B B B B B B M M B B M M B B B B M M F F B B legenda: M – (Memory unit) jednostka zarządzająca pamięcią I – (Integer ALU) stałoprzecinkowa jednostka arytmetyczno-logiczna F – (Floating-point unit) zmiennoprzecinkowa jednostka arytmetyczno-logiczna B – (Branch unit) jednostka wykonująca skoki L – (Long Imidate Integer) jednostka stałoprzecinkowa, ale instrukcje tak zaznaczone zajmują dwa miejsca w paczce, są to instrukcji rozszerzone nieużywane wartości pola template, są to wartości zarezerwowane, ich wystąpienie powoduje Generalny Błąd Ochrony „stop” po danej instrukcji Taki układ danych w paczce jaki posiada IA-64 jest bardziej złożony niż czysty VLIW jednakże pozwala na stworzenie rodziny kompatybilnych binarnie procesorów, a takie rozwiązanie jest dużo lepsze niż ewentualne późniejsze dodawanie specjalnych układów w procesorach które będą transformować kod od nowych wymagań. Paczki instrukcji w programie wykonywalnym są ułożone od najmniejszego do największego adresu. Instrukcje w paczce o mniejszym adresie są uważane za poprzedzające instrukcje z paczki o większym adresie. Kolejność bajtów w każdej paczce w pamięci to tzw. little-endian. Cechy zestawu instrukcji Każda instrukcja jak to zostało zauważone przy okazji omawiania paczkowania instrukcji ma długość 41 bitów. Istnieją jednakże tak zwane instrukcje rozszerzone (extended) które 9 zajmują 82 bity czyli dwa miejsca w paczce instrukcji. Instrukcje w IA-64 są podzielone na 6 kategorii. Każda instrukcja może być wykonana przez jeden lub więcej typów jednostek wykonawczych. Tabela przedstawiająca powiązania pomiędzy typem instrukcji a jednostką wykonawczą, do która wykonuje daną instrukcję. Typ instrukcji Typ jednostki wykonawczej Opis A stałoprzecinkowa arytmetyczno-logiczna stałoprzecinkowa lub zarządzająca pamięcią I stałoprzecinkowa, nie arytmetyczno-logiczna stałoprzecinkowa M operująca na pamięci zarządzająca pamięcią F zmiennoprzecinkowa zmiennoprzecinkowa B skok zarządzająca skokami rozszerzona stałoprzecinkowa L+X Ogólnie format instrukcji kodowany za pomocą 41 bitów można przedstawić za pomocą następującego schematu: 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 opcode misc pole3 pole2 pole1 qp 0-5 qp – (qualifying predicate register source) - pole zawierające adres odpowiedniego rejestru predykatów 6-12 pole1 – pole które jest w większości typów instrukcji wykorzystywane do przechowywania adresu źródłowego lub docelowego odpowiedniego rejestru (ogólnego przeznaczenia lub zmiennoprzecinkowego). Inaczej jest w przypadku instrukcji skoków, pole to jest wtedy dodatkowo podzielone. Pierwsze 3 bity zajmuje zakodowany typ skoku, lub adres źródłowy albo docelowy rejestru skoków, następne 3 bity są ignorowane, a ostatni bit pola zawiera kod operacji wcześniejszego pobierania. Jeszcze inaczej interpretuje się to pole w przypadku instrukcji porównania. Wtedy pierwsze 6 bitów to adres docelowego rejestru skoków, a ostatni bit kod komplementarnej relacji porównania 13-19 pole2 – pole to jest przez większą część instrukcji używane do przechowywania adresu źródłowego lub docelowego odpowiedniego rejestru (ogólnego przeznaczenia lub zmiennoprzecinkowego). W przypadku instrukcji alokacji w polu tym zapisana jest wielkość ramki. W tym polu mogą się także znajdować w zależności od instrukcji takie informacje jak: pozycja bitu testowego, lub bitu uzyskanego, przewidziana najbliższa maska 20-26 pole3 – pole to jest przez większą część instrukcji używane do przechowywania adresu źródłowego lub docelowego odpowiedniego rejestru (ogólnego przeznaczenia, zmiennoprzecinkowego lub aplikacyjnego). Instrukcje 10 multimedialne wykorzystują to pole do zakodowanie stanu licznika przesunięć. Może być to pole także wykorzystane do zapisania najbliższej przewidzianej maski, pozycji bitu testowego 27-36 misc – pole różnego przeznaczenia, w tym polu mogą znajdować się najróżniejsze informacje. Przykładem może być: rozszerzenie pola opcode, różne flagi wykorzystywane przez instrukcje, licznik przesunięć, podpowiedzi przy instrukcjach skoku, itp. 37-40 opcode – (major opcode) główny kod instrukcji, opisany niżej dokładniej Każde 4 ostatnie bity (37:40) w instrukcji to tak zwany główny kod instrukcji (major opcode). główny kod instrukcji 0 00 1 01 2 02 3 03 4 04 5 05 6 06 7 07 8 08 9 09 10 0A 11 0B 12 0C 13 0D 14 0E 15 0F I/A M/A Misc mem mgnt mem mgnt Deposit Shift/Test bit MM Mpy/Shift ALU/MM ALU Add Imm Int Ld +Reg/getf Int Ld/St + Imm FP Ld/St+Reg/setf FP Ld.St+lmm ALU/MM ALU Add Imm Compare Compare Compare Compare Compare Compare typ instrukcji F B L+X FP misc FP misc Misc/indi branch indirect call Nop misc FP Compare FP Class IP-rel branch IP-relative call movl fma fma fms fms fnma fnma fselect/xma Nieużywane pola głównego kodu (czyli puste miejsca w tabeli) można interpretować na trzy sposoby: instrukcja jest interpretowana jako NOP zarezerwowana wartość pola, wystąpienie takiej wartości powoduje generowanie błędu generowanie błędu, jeśli rejestr predykatowy specyfikowany przez pole qp instrukcji (bity 0:5) ma wartość 1, lub interpretowanie instrukcji jako NOP w przeciwnym wypadku Rejestry Architektura IA-64 jest tak pomyślana aby większość zasobów procesora udostępniać bezpośrednio oprogramowaniu. Nie jest inaczej z rejestrami. Ilość rejestrów jest jedną z kluczowych cech IA-64 która odróżnia tą architekturę od procesorów IA-32, a także od procesorów RISCowych. Co prawda nowe procesory RISCowe mają już dużą fizyczną liczbę rejestrów, ale i tak liczba rejestrów pomyślana dla IA-64 jest dużo większa. Istnieje wiele 11 zalet dużej liczby rejestrów, główną zaletą jest to iż nie trzeba się często odwoływać do pamięci operacyjnej. Kompilator ma dostęp do całego zestawu rejestrów, co umożliwia mu śmielszą optymalizację kodu. Przykładem może być technika „wyrolowywania” pętli. W porównaniu z IA-32 duży zestaw rejestrów zmiennoprzecinkowych powiada dodatkową zaletę, a mianowicie eliminuje niepożądany mechanizm stosu zmiennoprzecinkowego. W programach dla x86 większość operacji zmiennoprzecinkowych mogło operować jedynie na szczycie ośmioelementowego stosu, co zmuszało na częste używanie bezcelowego w IA-64 instrukcji fxch (exchange witch top of stack) czyli wymiany szczytu stosu rejestrów. Już procesory które mają tylko 32 rejestry zmiennoprzecinkowe nie doznają tej niedogodności, a pierwsza implementacja IA-64 ma nieć tych rejestrów aż 128. Wadami wielkiej liczby rejestrów są: zajmowanie fizycznie dużej ilości miejsca w procesorze, ale nie wydaje się to znaczącą wadą, gdyż pierwsza implementacja IA-64 będzie wykonana w technologii 18 mikronów. Główną wadą takiej ilości jest zwiększenie długości każdej instrukcji związanej z adresacją rejestrów. Przegląd rejestrów dostępnych w architekturze IA-64: Rejestry Ogólnego Przeznaczenia GR (General Purpose Registers) Są to 64-bitowe rejestry które mogą być wykorzystywane do przechowywania wszystkiego rodzaju danych. Są one jednak zwykle używane przy obliczeniach stałoprzecinkowych, oraz multimedialnych. Rejestry te są podzielone na dwie części statyczną oraz stosową. Część statyczna zajmuje jedną czwartą całego zestawu jest dostępna bezpośrednio przez oprogramowanie. Część stosowa zajmująca pozostałą pulę to rejestry rotujące są one dostępne poprzez tzw. rejestry RRB (Rotating Register Base, zwane także Register Rename Base) które wskazują od którego numeru rejestry stosowe są wolne i można z nich korzystać. Pierwszy rejestr ogólnego przeznaczenia jest rejestrem specjalnym i jest tylko do odczytu, ma on zawsze wartość 0. Próba zapisu danych do rejestru zerowego powoduje wygenerowanie błędu. Rejestry NaT (Not a Thing registers) Są to 1-bitowe rejestry z których każdy jest dodatkiem do odpowiedniego rejestru ogólnego przeznaczenia. Jeden bit zawarty w tych rejestrach ma za zadanie informować czy dane zawarte w rejestrach ogólnego przeznaczenia są poprawne. Wykonywanie spekulatywnych operacji przez procesor IA-64 daje możliwość nietrafnego załadowania rejestru. Bity NaT informują właśnie o poprawności danych związanym z tym mechanizmem. Rejestry Zmiennoprzecinkowe FP (Floating point registers) Są to 82-bitowe zmiennoprzecinkowe rejestry które są używane przy obliczeniach zmiennoprzecinkowych. Rejestry te są podzielone na dwie części. Pierwsza część zajmująca jedną czwartą zestawu nazwana jest częścią statyczną Rejestry od 8 do 31 są używane w trybie IA-32 jako rejestry zmiennoprzecinkowe, oraz multimedialne znane z procesorów IA-32. Reszta rejestrów nazwana jest częścią rotująca. Część to jest dynamicznie przydzielana oprogramowaniu aby przyspieszyć wykonywanie pętli. Pierwsze dwa rejestry są tylko do odczytu i mają wartość +0.0 oraz +1.0. Jeśli któryś z tych rejestrów jest używany jako rejestr docelowy jakiejś operacji to generowany jest błąd. Rejestry te nie są wyposażone w dodatkowe bity typu NaT, jest jednak możliwość sygnalizowania niepoprawności danych związanych z mechanizmem spekulatywnego dostępu do danych. Specjalna wartość NaTVal (Not a Thing Value) jest wpisywana do odpowiedniego rejestru gdy dane nie zostały trafnie przewidziane do załadowania. 12 Format rejestru FP: 81 80 64 63 0 znak wykładnik część znacząca 1 17 64 pole znaczące – (significand) w polu tym znajdują się cyfry znaczące liczby. Bit 63 jest częścią całkowitą liczby, natomiast pozostałe bity są częścią ułamkowa. wykładnik – (exponent) w tym przechowywany jest wykładnik liczby. Jeśli wszystkie bity wynoszą 1 to stan taki interpretowany jest jako nieskończoność. Jeśli wszystkie bity wynoszą 0, oraz wszystkie bity pola znaczącego są równe zero, oznacza to iż liczba wynosi 0. Natomiast w przypadku jeśli wszystkie bity tego pola wynoszą 0 natomiast pole znaczące nie wynosi zero to stan taki interpretuje tak że liczba jest typu IEEE double-extended real (pseudo)denormal znak – (sign) pole to określa czy liczba jest dodatnia (bit wynosi 0) czy ujemna (bit wynosi 1) Wartość zawarta w tym rejestrze można wyrazić: - przy założeniu, że wykładnik jest różny od zera (-1)(znak) · 2(wykładnik - 65535) · (część_znacząca[63].część_znacząca[62:0]) - przy założeniu, że wykładnik jest równy zero (-1)(znak) · 2(- 16382) · (część_znacząca[63].część_znacząca[62:0]) Rejestry Aplikacyjne AR (Application Registers) są rejestry różnego przeznaczenia, włączając w to rejestry specjalnego przeznaczenia, rejestry kontrolne, oraz rejestry, które zostały dodane do architektury IA-64 dla zachowania zgodności z architekturą IA-32. Rejestry aplikacyjne mogą być adresowane tylko przez jednostkę zarządzającą pamięcią (M-unit) albo przez stałoprzecinkową jednostkę arytmetyczno-logiczną (ALU). Tabela przedstawiająca listę wszystkich rejestrów aplikacyjnych: Numer rejestru AR 0-7 AR 8-15 AR 16 AR 17 AR 18 AR 19 Nazwa Opis KR 0-7 Rejestry jądra Zarezerwowane Rejestr konfiguracji stosu rejestrów Wskaźnik powrotu Wskaźnik powrotu dla pamięci Rejestr kolekcji rejestrów NaT RSC BSP BSPSTORE RNAT typ jednostki wykorzystuj ącej rejestr M M M M M M 13 AR 20 AR 21 AR 22-23 AR 24 AR 25 AR 26 AR 27 AR 28 AR 29 AR 30 AR 31 AR 32 AR 33-35 AR 36 AR 37-39 AR 40 AR 41-43 AR 44 AR 45-47 AR 48-63 AR 64 AR 65 AR 66 AR 67-111 AR 112-127 FCR EFLAG CSD SSD CFLG FSR FIR FDR CCV UNAT FPSR ITC PFS LC EC Zarezerwowane Rejestr kontroli zmiennoprzecinkowej Zarezerwowane Rejestr flag aplikacji Rejestr segmentowy programu Rejestr segmentowy stosu Rejestr flag kontrolnych Rejestr statusu zmiennoprzecinkowego Rejestr instrukcji zmiennoprzecinkowych Rejestr danych zmiennoprzecinkowych Zarezerwowane Rejestr porównania oraz wymiany Zarezerwowane Rejestr kolekcji użytkownika rejestrów NaT Zarezerwowane Rejestr statusu operacji zmiennoprzecinkowych Zarezerwowane Licznik przedziałów czasowych Zarezerwowane Ignorowane Poprzedni stan funkcji Licznik pętli Licznik instrukcji końcowych Zarezerwowane Ignorowane M M M M M M M M M M M M M M M M M M M M lub I I I I I M lub I Rejestry jądra (KR 0-7 – AR 0-7) (Kernel Registers) Osiem dostępnych dla użytkownika rejestrów. Są to rejestry 64 bitowe. Ich zadaniem jest przekazywanie informacji z systemu operacyjnego do aplikacji. Rejestry te mogą być czytane przez wszystkie poziomy uprzywilejowania, ale zapisywane mogą być jedynie przez najbardziej uprzywilejowany poziom. Rejestry KR 0, KR 1, oraz KR 2 są także używane do trzymania dodatkowych informacji przeznaczonych dla zestawu instrukcji IA-32. Dzieje się to wtedy kiedy aktywnym jest zestaw instrukcji IA-32. Rejestr konfiguracji stosu rejestrów (RSC – AR 16) (Register Stack Configuration Register) Jest to 64-bitowy rejestr używany do kontroli operacji na stosie rejestrów wykonywanych przez RSE (Register Stack Engine) architektury IA-64. format rejestru RSC: 63 30 29 rv 34 16 15 loadrs 14 5 rv 11 4 be 1 3 2 1 pl 2 0 mode 2 mode – (tryb) pole to kontroluje w jaki sposób RSE zapisuje oraz odczytuje ramki na/ze stosu gdy pole to jest ustawione w postaci 00 RSE pracuje leniwie (emforced lazy) 10 oznacza tryb intensywnego odczytu (load intensive) 01 oznacza tryb intensywnego odczytu (stroe intensive) 11 oznacza tryb szybki (eager) 14 pl – (privilege level) pole to określa w jakim poziomie uprzywilejowanie ma pracować RSE be – (big endian) pole to kontroluje sposób zapisu oraz odczytu danych przez RSE. Jeśli bit ten jest ustawiony w pozycji 1 to znaczy że dostęp odbywa się według kolejności big-endian, natomiast jeśli w pozycji 0 to znaczy, że według kolejności little-endian loadrs – pole to jest używane przez instrukcję loadrs do synchronizacji RSE rv – (reserved) pole zarezerwowane Wskaźnik powrotu (BSP – AR 17) (Backing Store Pointer) Jest to 61 bitowy rejestr. Rejestr jest tylko do odczytu, przechowuje on adres miejsca w pamięci w którym jest zapisane miejsce rejestru GR 32 z aktualnej ramki stosu. Co prawda rejestr ten zajmuje całe 64 bity, ale 3 bity są ignorowane. Format rejestru BSP 63 3 2 0 pointer ig 61 3 Wskaźnik powrotu dla pamięci (BSPSTORE – AR 18) (Backing Store Pointer for Memoru Strores) Jest to 61 bitowy rejestr. W rejestrze tym przechowywane są informacje o miejscu pamięci w którym RSE zapisze następną ramkę stosu. Format rejestru BSPSTORE 63 3 2 0 pointer ig 61 3 Rejestr kolekcji rejestrów NaT (RNAT – AR 19) (RSE NaT Collection Register). Jest to 64 bitowy rejestr który jest używany przez RSE do tymczasowego przechowywania wartości rejestrów NaT. Dane są do tego rejestru zapisywane kiedy RSE zapisuje następną ramkę stosu. Bit 63 zawsze przy czytaniu zwraca zero i ignorowane są wszystkie próby zapisu do niego. Format rejestru RNAT 63 62 0 ig RSE NaT Collection 1 63 REJESTRY IA-32 (AR 21-30) Rejestry IA-32 zostały dodane w celu zapewnienia kompatybilności z architekturą IA-32. Jest to zestaw rejestrów w których znajdują się rejestry znane z procesorów serii x86. 15 Rejestr FCR (AR 21) – w rejestrze tym znajdują się znane z IA-32 rejestry FCW, oraz MXCSR. Rejestr EFLAG (AR 24) – rejestr ten odpowiada rejestrowi o takiej samej nazwie w IA-32 Rejestr CSD (AR 25) – rejestr ten odpowiada rejestrowi o takiej samej nazwie w IA-32 mimo iż istnieje lekka modyfikacja formatu Rejestr SSD (AR 26) – rejestr ten odpowiada rejestrowi o takiej samej nazwie w IA-32 mimo iż istnieje lekka modyfikacja formatu Rejestr CFLG (AR 27) – w rejestrze tym znajdują się rejestry CR0/CR4 znane z IA-32. Rejestr FSR (AR 28) – w rejestrze tym znajdują się rejestry FSW, FTW, MXCSR znane z IA32. Rejestr FIR (AR 29) w rejestrze tym znajdują się rejestry FOP, FIP, FCS znane z IA-32. Rejestr FDR (AR 30) w rejestrze tym znajdują się rejestry FEA, FDS znane z IA-32. Rejestr porównania oraz wymiany(CCV – AR 32) (Compare and Exchange Value Register) Jest to 64-bitowy rejestr który zawiera dane używane przez instrukcję cmpxchg. Rejestr kolekcji użytkownika rejestrów NaT (UNAT – AR 36) (User Nat Collection Register) Jest to 64-bitowy rejestr który jest używany do tymczasowego przechowywania wartości rejestrów NaT. Dane do tego rejestry są zapisywane kiedy zostają wykonane instrukcje ld8.fill oraz ld8.spill Rejestr statusu operacji zmiennoprzecinkowych (FPSR – AR 40) (Floating-point Status Register). Jest to 64-bitowy rejestr w którym przechowywane są informacje o operacjach zmiennoprzecinkowych. Za pomocą tego rejestru można dynamicznie kontrolować te operacje. Rejestr ten jest podzielony na 5 pól, jednym jest pole które opisuje sposób obsługi błędów, oraz 4 zestawy informacji statusowych (1 główny zestaw oraz 3 alternatywne). Format rejestru FPSR: 63 58 57 45 44 32 31 19 18 6 5 0 rv sf3 sf2 sf1 sf0 traps 6 13 13 13 13 6 traps – (zapadki) bity w tym polu sygnalizują odpowiadające tym bitom błędy będą generowane sf0 – (status field 0) główne pole statusu sf1 – (status field 1) alternatywne pole statusu nr 1 sf2 – (status field 2) alternatywne pole statusu nr 2 sf3 – (status field 3) alternatywne pole statusu nr 3 rv – (reserved ) pole zarezerwowane Format pola traps: 5 4 3 2 1 0 id ud od zd dd vd 1 1 1 1 1 1 vd – bit w stanie wysokim blokuje wystąpienie błędu IEEE – Invalid Operation 16 dd – bit w stanie wysokim blokuje wystąpienie błędu – Denormal/Unnormal Operand zd – bit w stanie wysokim blokuje wystąpienie błędu IEEE – Zero Divide od – bit w stanie wysokim blokuje wystąpienie błędu IEEE – Overflow ud – bit w stanie wysokim blokuje wystąpienie błędu IEEE – Underflow id – bit w stanie wysokim blokuje wystąpienie błędu IEEE – Inexact Każda instrukcja arytmetyczna wykonująca operacje zmiennoprzecinkowe ma specyfikator pola statusu. Specyfikator ten określa które z 4 pól statusu będzie używane do kontroli nad daną instrukcją. Format pola statusu: 12 11 10 9 8 7 6 i u o z d v td 5 rc 4 3 pc 2 1 1 1 1 1 1 1 2 2 1 0 wre ftz 1 1 ftz – (Flush-To-Zero) tryb czyszczenia do zera wre – (Widest Range Exponent) wielkość wykładnika pc – (Precision Control) kontrola precyzji rc – (Rounding Control) kontrola zaokrąglania 00 td – (Traps disabled) tryb w którym zapadki (traps) są zablokowane, nie dotyczy głównego pola statusu. v – (invalid operation) d – (Denornal/unnormal) z – (Zero divide) bity te sygnalizują pojawienie się błędu który jest włączony w polu traps o – (Overflow) u – (Underflow) i – (Inexact) Licznik przedziałów czasowych (ITC – AR 44) (Interval Time Counter) Jest to 64 bitowy rejestr w którym liczone są kolejne takty zegara. Aplikacje mogą bezpośrednio odczytywać ten licznik i w ten sposób dokonywać obliczeń wykorzystujących pomiar czasu, lub mierzących jakieś osiągi. System może zabronić dostępu do tego rejestru dla nieuprzywilejowanych aplikacji. Kiedy dostęp jest zabroniony, odczyt tego rejestru (z poziomów nieuprzywilejowanych) powoduje błąd. Dane do tego rejestru mogą być zapisywane jedynie przez najbardziej uprzywilejowany poziom. Rejestr ten jest równoważny rejestrowi TSC (Time Stamp Counter) znanego z IA-32 i może być odczytywany za pomocą instrukcji rdtsc (read time stamp counter). System może zabronić dostępu także w przypadku korzystania z trybu IA-32. W tym przypadku kiedy następuje wykonanie instrukcji rdstc (z poziomów nieuprzywilejowanych) powoduje błąd. Poprzedni stan funkcji (PFS – AR 64) (Previous Function State) Rejestr ten zawiera wiele pól, które określają poprzedni stan układu rejestrów. Wartości do tych pól są kopiowane automatycznie przy wywołaniu z odpowiednich rejestrów, dla przyspieszenia wywoływań procedur. 17 Kiedy instrukcja br.call jest wykonana pola są inicjowane nowymi wartościami, a poprzednia wartości PFS są tracone. Kiedy wywoływana jest instrukcja br.ret odpowiednie pola są z powrotem kopiowane do odpowiednich rejestrów. Format rejestru PFS 63 62 61 58 57 52 51 38 37 0 ppl rv pec rv pfm 2 4 6 14 38 pfm – (Previous Frame Marker) jest to odpowiednik Oznaczenia Aktualnej Ramki Stosu (CFM). Pole to tak jak rejestr CFM jest dodatkowo podzielone na pola: RRB.PR, RRB.FR, RRB.GR, SOR, SOL, SOF pec – (Previous Epilog Count) jest to odpowiednik rejestru EC, (nie biorąc pod uwagę części ignorowanej tego rejestru) ppl – (Previous Privilege Level) jest to odpowiednik pola pl w rejestrze konfiguracji stosu rejestrów (RSC). Operacja przywracania wartości z tego pola do oryginalnego miejsca może spowodować zmianę aktualnego poziomu uprzywilejowania rv – (Reserved) pola zarezerwowane Licznik pętli (LC – AR 65) (Loop Count) Jest to rejestr 64-bitowy. Rejestr ten wykorzystuje się do zliczania przebiegów pętli. Wartość zawarta w tym rejestrze jest zmniejszana o 1 przy każdym skoku wykonywanym w pętli w której jest określona ilość przebiegów. Licznik instrukcji końcowych (EC – AR 66) (Epilog Count) Jest to rejestr którego 6 bitów jest używane do zliczania ostatnia część (epilog) pętli. Epilog jest to ostatnia część pętli w której potok instrukcji nie jest już pełny, lecz powoli opróżnia się (ostatnia instrukcja pętli została już załadowana). Rejestr ten jest wykorzystywany w mechanizmie „wyrolowywania” pętli Format rejestru EC 63 6 5 0 ig epilog count 58 6 Rejestry Predykatów PR (predicate registers) są to 1 bitowe rejestry które kontrolują warunkowe wykonywanie instrukcji oraz skoków. Są one używane do przechowywania rezultatów porównań. Rejestry predykatów są podzielona na dwie części. Pierwsza jest nazwana statyczną i zajmuje jedną czwartą całej liczby. Pozostała część rejestrów nazwana jest częścią rotującą. Rejestry te są dynamicznie przydzielane oprogramowaniu, podczas wykonania pętli. Pierwszy rejestr jest tylko do odczytu i ma zawsze wartość prawda. Kiedy ten rejestr jest używany jako cel zapisu jakiegoś wyniku, to wynik ten jest tracony. 18 Rejestry Skoków BR (Branch registers) są to 64-bitowe rejestry które są używane do specyfikowania docelowego adresu skoku. Umożliwiają sprawniejsze działanie jednostki przewidywania skoków, oraz wykonywania skoków. Wskaźnik Instrukcji IP (Instruction pointer) Jest to rejestr 64 bitowy. W rejestrze tym przechowywany jest adres paczki instrukcji w której znajduje się aktualnie wykonywania instrukcja IA-64. Rejestr IP może być odczytywany bezpośrednio, jednakże nie może być bezpośrednio zapisywany. Rejestr ten jest inkrementowany, kiedy paczka zostanie wykonana. Rejestr jest inicjowany nową wartością, w przypadku wykonania skoku. Oznaczenie Aktualnej Ramki Stosu CFM (Current Frame Marker) Jest to zespół podrejestrów o łącznej długości 38 bitów. Każda ramka rejestrów jest powiązana ze rejestrem oznaczenia ramki. W tym rejestrze przechowywane są dane na temat aktualnego stanu ramki stosu. Rejestr ten nie może być bezpośrednio odczytywany, ani nie można do niego bezpośrednio nic zapisać, z poziomu aplikacji. Rejestr ten podzielony jest na podrejestry, które zawierają informacje na temat długości niektórych elementów ramki stosu, oraz trzy rejestry zmiany RRB (Rotating Register Base), które są używane przy rotowaniu rejestrów. Format rejestru CFM: 37 32 31 25 24 18 17 14 13 7 6 0 RRB.PR RRB.FR RRB.GR SOR SOL SOF 6 7 7 4 7 7 RRB.PR (Rotate Register Base for Predicate Registers) – podstawa rotujących rejestrów predykatowych (6 bitów) RRB.FR (Rotate Register Base for Floating-point Registers) – podstawa rotujących rejestrów zmiennoprzecinkowych (7 bitów) RRB.GR (Rotate Register Base for General Registers) – podstawa rotujących rejestrów ogólnego przeznaczenia (7 bitów) SOR (Size Of Rotating portion of stack frame) – długość rotującej części ramki stosu dodatkowo można obliczyć ilość rotujących rejestrów który wynosi 8*SOR (4 bity) SOL (Size Of Locals portion of stack frame) – długość lokalnej części ramki stosu (7 bitów) SOF (Size Of stack Frame) – całkowita długość ramki stosu (7 bitów) Przy wywołaniu rejestr CFM jest kopiowany do pola PFM (Previous Frame Marker) w rejestrze PFS (Previous Function State). Nowe wartości zapisywane do rejestru CFM tworzą nową ramkę stosu. Wszystkie pola RRB są inicjowane wartością 0. Rejestry PMD (Performance Monitor Data) Jest to zestaw 64 bitowych rejestrów zawierających dane na temat osiągów komputera. Rejestry te mogą być edytowane tylko przez uprzywilejowane programy, które mają dostęp do niskich poziomów uprzywilejowania. Wartości rejestrów 19 PMD mogą być bezpośrednio odczytywane bez pomocy aplikacji. System operacyjny jest upoważniony do strzeżenia skonfigurowanych przez użytkownika rejestrów. Jeśli rejestry te czytamy z poziomów które nie są wystarczająco uprzywilejowane to rejestry te zwracają zero. Rejestry te są używane do lepszej informacji o osiągach procesora, działają zarówno dla zestawu instrukcji IA-64 jak i IA-32. Rejestry PMD są podzielone na dwie części. Pierwsza część to tzw. rejestry (PMC) w których znajdują się informacje używane do konfiguracji. Reszta to właściwe rejestry PMD. Znajdują się w nich jedynie dane dotyczące osiągów. Rejestr Maski Użytkownika UM (User Mask) Jest 6 bitów flag które informują o aktualnych ustawieniach procesora. Maska użytkownika jest częścią rejestru stanu procesora (PSR). Są one dostępne przez aplikacje napisane dla IA-64. Format rejestru Maski Użytkownika: 5 4 mfh mfl 1 1 3 2 1 0 ac up be rv 1 1 1 1 rv – (reserved) pole zarezerwowane be – (big endian enable) pole to kontroluje sposób zapisu oraz odczytu z/do pamięci. Jeśli bit jest ustawiony w pozycji 1 znaczy to ze dostęp do pamięci jest według metody big-endian, natomiast jeśli bit jest ustawiony w pozycji 0 oznacza to dostęp do pamięci według metody little-endian. Bit ten jest ignorowany jeśli procesor pracuje w trybie IA-32. W tym trybie dostęp do pamięci jest zawsze ustawiony jako little-endian up – (user performance monitor enable) pole to kontroluje dostęp do rejestrów PMD dla użytkownika. Jeśli bit jest ustawiony w pozycji 1 znaczy to, że rejestry PMD są aktywne, natomiast jeśli bit ma wartość 0 znaczy to, że rejestry PMD są zablokowane ac – (alignment check) pole to kontroluje kiedy będzie generowany błąd ustawienia danych w pamięci. Wartość 1 tego bitu powoduje generowanie błędu przy każdym nieustawionym dostępie do pamięci, natomiast ustawienie tego bitu w pozycji 0 powoduje, że nieustawiony dostęp do pamięci może powodować błąd, ale nie musi. mfl – (Mark Floating-point Lower) Ten bit sygnalizuje dostęp do statycznej części rejestrów zmiennoprzecinkowych. Bit ten jest ustawiany w pozycji wysokiej wtedy gdy jakakolwiek instrukcja która używała statycznej części rejestrów zmiennoprzecinkowych zakończyła swoje działanie. Bit ten nie jest nigdy automatycznie zerowany, aby sprawdzić następne odwołanie do statycznej części rejestrów zmiennoprzecinkowych należy wcześniej wpisać do tej części maski użytkownika zero. mfh – (Mark Floating-point Higher) Ten bit sygnalizuje dostęp do rotującej części rejestrów zmiennoprzecinkowych. Bit ten jest ustawiany w pozycji wysokiej wtedy gdy jakakolwiek instrukcja która używała rotującej części rejestrów zmiennoprzecinkowych zakończyła swoje działanie. Bit ten nie jest nigdy automatycznie zerowany, aby sprawdzić następne odwołanie do rotującej części rejestrów zmiennoprzecinkowych należy wcześniej wpisać do tej części maski użytkownika zero. 20 Rejestry Identyfikacji Procesora CPUID (Procesor Identification) Są to rejestry które identyfikują konkretny egzemplarz procesora, każdy rejestr ma po 64 bity. Rejestry te są podzielone na dwie grupy. Pierwsza grupa nazwana stała (fixed region), która zajmuje rejestry od 0 do 4, oraz grupa zwana zmienna (variable region), czyli rejestry od 5 w górę. Zapis do rejestrów identyfikacji procesora jest niemożliwy ponieważ nie ma instrukcji które by umożliwiały taką operację. Informacja o producencie procesora jest umieszczona w pierwszym oraz drugim rejestrze CPUID. W rejestrze tym wyspecyfikowana jest nazwa producenta zapisana w formacie ASCII. Sumarycznie długość napisu nie może przekraczać 16 bajtów, gdyż każdy rejestr ma długość 64 bitów, co w sumie daje wartość 16 bajtów na nazwę producenta. Bity które są po ostatnim znaku aż do końca drugiego rejestru wynoszą zero. Numer seryjny procesora jest umieszczony w rejestrze o numerze 2. Jeżeli konkretny model procesora posiada numer seryjny to rejestr ten zwraca 64 bitowy numer seryjny, w przeciwnym wypadku rejestr ten jest zablokowany i odwołanie do niego zwraca zero. Jeżeli numer seryjny istnieje to jest powiązany z 32-bitową informacją o wersji procesora, która jest zawarta w rejestrze o numerze 3. format rejestru CPUID.[3] 63 40 39 32 31 24 23 16 15 8 7 0 rv archerev family model revision number 24 8 8 8 8 8 number – numer ostatniego zaimplementowanych w danym procesorze rejestru CPUID, wartość ta jest o jeden mniejsza niż wynosi liczba wszystkich rejestrów CPUID revision – numer poprawki procesora, liczba ta mówi nam do jakiego wydania należy dany procesor model – numer ten reprezentuje model procesora, jest to numer unikalny wśród procesorów danej rodziny family – numer rodziny procesorów, jest to unikalny numer i nie może się powtarzać archrev – (architecture revision) jest to numer który mówi nam ile było zmian architektury do czasu wyprodukowania danego procesora rv – (reserved) pole zarezerwowane Kombinacja 64 bitowego numeru seryjnego wraz z 32 bitową informacją o wersji jest wartością unikalną i nie może się powtarzać wśród procesorów IA-64. W rejestrze CPUID o numerze 4 mają znajdować się informacje o cechach procesora wykonanego w architekturze IA-64. Jest to zestaw flag które pokazują czy dana cecha jest zaimplementowana w konkretnym procesorze. Kiedy bit wynosi 1 znaczy to, że procesor obsługuje daną czynność, w przeciwnym przypadku wartość wynosi zero. Rejestr ten nie zawiera cech zestawu instrukcji IA-32. Na dzień dzisiejszy istnieje specyfikacja jedynie jednego bitu z tego rejestru. Bit ten znajduje się w polu o numerze 0 i informuje czy procesor obsługuje instrukcję brl (Long BRanch) czyli tak zwanego długiego skoku. 21 Rejestry rotujące Przydzielanie rejestrów zaimplementowane w oprogramowaniu Jedną z kluczowych koncepcji zastosowanych w IA-64, jest idea przeniesienia części zadań dotychczas wykonywanych bezpośrednio w procesorze do oprogramowania. Jednym z przykładów jest przydzielanie zestawu rejestrów. Większość procesorów dla serwerów sama mapuje małą liczbę logicznych rejestrów (8-32) z większej liczby fizycznych rejestrów (na przykład ponad 80 jak to ma miejsce w procesorze Alpha 21264). Ponieważ oprogramowanie ma dostęp jedynie do rejestrów logicznych, sprzęt musi przydzielać oraz przeliczać dostęp używając dodatkowej tablicy. To znacznie wydłuża czas wykonania potoku instrukcji, oraz często także jego wielkość. IA-64 eliminuje ten mechanizm z procesora i swój wielki zestaw udostępnia bezpośrednio dla oprogramowania. Takie postępowanie jest korzystniejsze w większości przypadków, za wyjątkiem krótkich pętli. W tej krótkiej sekwencji kodu która jest wykonywana wiele razu iteracyjnie, może być niewystarczająca liczba instrukcji, aby zrównoważyć czas ładowania instrukcji. To może powodować niepożądane przestoje. W innych procesorach problem ten rozwiązano zamieniając kolejność instrukcji, tak aby w wolnym czasie wykonać trochę niezależnego kodu. Dodatkowe instrukcje mogą powodować konflikty rejestrów, gdyż instrukcje z pętli mogą wskazywać na te same rejestry, na które wskazują dodatkowe instrukcje. Problem konfliktów jest rozwiązywany właśnie przez sprzętowe przydzielanie rejestrów logicznych. W IA-64 problem będzie rozwiązywany, przez „wyrolowywanie" pętli w oprogramowaniu. Ta technika kompilacji zwielokrotnia instrukcje pętli, często kilka razy, aby powstała wystarczająca ilość instrukcji. Dla przykładu kopiująca pamięć pętla: for(i=0;i<n;i++) *b++=*a++; po wyrolowaniu może wyglądać tak m=n/3; for(i=0;i<m;i++){ *b++=*a++; *b++=*a++; *b++=*a++; } Każdy zestaw z zwielokrotnionych przebiegów pętli jednakże może wymagać oddzielnego zestawu rejestrów, aby zapobiegać kolizjom. Z tego powodu, IA-64 ma bardzo dużo dostępnych rejestrów. Wadą takiego rozwiązania jest to, iż duplikowanie instrukcji może powodować ogromny rozrost wielkości kodu. Rotujące Rejestry nie powodują rozrostu kodu Aby zredukować rozrost wielkości kodu IA-64 używa mechanizmu "rotujących rejestrów". Technika ta dzieli zestaw rejestrów na 2 części. Jedna czwarta ogólnej liczby rejestrów (stałoprzecinkowych, zmiennoprzecinkowych i predykatów) jest zarezerwowana dla zmiennych globalnych. Reszta czyli trzy czwarte "rotuje" czyli jest kolejno przydzielana. Dostęp do nich jest poprzez przesunięcie którego wartość jest przechowywana w specjalnych rejestrach RRB. 22 RRB (rotating register base – podstawa rotujących rejestrów) trzy rejestry - RRB.GR (RRB.general register) – dla rejestrów ogólnego przeznaczenia o długości 7 bitów - RBB.FR (RRB.floating-point register) – dla rejestrów zmiennoprzecinkowych o długości 7 bitów - RBB.PR (RRB.predicate register) – dla rejestrów predykatów o długości 6 bitów Do operacji na tych rejestrach zdefiniowano specjalne instrukcje: - clrrrb (clear RBB) – czyszczenie wszystkich rejestrów RRB clrrrb.pr (clear RBB predicate) – czyszczenie rejestru RRB.PR br.ctop – dekrementacja rejestru RRB gdy warunek pętli jest umieszczony szczycie ciała pętli, o stałej liczbie przebiegów (counted loop). br.wtop – dekrementacja rejestru RRB gdy warunek pętli jest umieszczony szczycie ciała pętli, gdzie liczba przebiegów zależy od warunku (while loop). br.cexit – dekrementacja rejestru RRB gdy warunek pętli jest umieszczony końcu ciała pętli, , o stałej liczbie przebiegów (counted loop). br.wexit – dekrementacja rejestru RRB gdy warunek pętli jest umieszczony końcu ciała pętli, gdzie liczba przebiegów zależy od warunku (while loop). na na na na Specjalna instrukcja CR.CTOP zmniejsza każdorazowo odpowiedni rejestr jeden na końcu każdego przebiegu pętli, pozwalając instrukcjom z następnego przebiegu używać następnego zestawu rejestrów. Nazwa rotowanie bierze się stąd, iż jeśli wartości zawarta w rejestrach RRB wskazuje na ostatni rejestr to następną porcją są rejestry z dołu, wygląda na to jakby rejestry były zamknięte w koło i aktywna była część, która porusza się ruchem rotującym. Instrukcje w pętli można podzielić na trzy fazy: instrukcje początkowe (prolog), instrukcje środka (kernel), oraz instrukcje końcowe (epilog). Za kryterium podziału uważa się zapełnienie potoku instrukcji do wykonania. Podczas wykonywania instrukcji początkowych potok nie jest kompletny, dopiero zapełnia się, podczas wykonywania instrukcji środkowych, potok jest pełny. Jak łatwo się domyślić podczas trwania fazy epilogu potok się opróżnia. Rotowanie rejestrów predykatów daje możliwość wychwycenia instrukcji które są wykonywane na początku (prologu) wykonywania pętli, oraz tych na których pętla kończy swoje działanie (epilogu). Jeżeli te instrukcje zostaną na dodatek wcześniej właściwie przewidziane to rotowanie rejestrów predykatowych umożliwia wykonanie tych instrukcji tylko raz. Instrukcji startowych na początku przebiegu, oraz końcowych na końcu. Daje to ogromne korzyści, gdyż potok cały czas jest pełny. Niekiedy może się zdarzyć, że instrukcje początkowe pętli są potrzebne później przy inicjowaniu kolejnych przydziałów rejestrów predykatowych, jednakże można je wykonać początkowo także dla jeszcze nie potrzebnych rejestrów, co całkowicie eliminuje te instrukcje ze ścieżki krytycznej programu. Wystrzegając się krzyżowania się zestawu rejestrów, oraz usprawnieniu procesu rotowania projektanci IA64 dodali kilka specjalnych rejestrów. Tymi rejestrami (oprócz rejestrów RRB) specjalnymi są: - LC (loop count – licznik pętli) 64-bitowy rejestr który jak sama nazwa wskazuje zawiera informacje który przebieg pętli właśnie się wykonuje EC (epilogue count – licznik instrukcji końcowych) 6-bitowy rejestr kontrolujący wykonanie instrukcji kończących pętlę. 23 Użycie specjalnych rejestrów pozwala instrukcji CR.CTOP wykonać wiele operacji prościej i szybciej niż w tradycyjnych procesorach które mapują rejestry. Metoda przydzielania rejestrów w IA-64 pozwala na rozwiązanie problemu krótkich pętli. Można to oczywiście było zrobić całkowicie w kompilatorze, jednakże powodowałoby to duży rozrost kodu. Technika rotujących rejestrów powoduje konieczność większej komplikacji (dodanie kilku rejestrów, oraz instrukcji operujących na nich) przy budowie procesora, jednakże ta komplikacja jest mniejsza niż w przypadku koncepcji mapowania rejestrów i udostępniania tylko tylu ile jest w danej chwili potrzebne. Wydawać by się mogło iż wychwytywanie instrukcji początkowych oraz końcowych może być niekorzystne w pętlach które wykonują niewielką liczbę przebiegów. Powodem mogłyby być nadmierne koszy związanych z analizą kodu przy poszukiwaniu prologu i epilogu, które mogą być później nie zrekompensowane przez zyski z jednego potoku. Te obawy są bezpodstawne, gdyż dla procesora opartego na architekturze IA-64 już dla kilku przebiegów zyski szybkości są widoczne. W dzisiejszych rozwiązaniach rzadko stosuje się technikę wyrolowywania pętli, za wyjątkiem programów numerycznych w których przetwarzanie długie tablice amortyzuje narzut związany przetwarzaniem końca oraz początku pętli Spekulatywne wykonywanie kodu oraz spekulatywny dostęp do pamięci Są dwa typy spekulacji związane z mechanizmami procesora. Spekulatywne wykonanie kodu, oraz spekulatywny dostęp do danych. W obydwu, kompilator paczkuje instrukcje w taki sposób aby operacje opóźniające ścieżkę krytyczną danego problemu były wykonywane wcześniej. Kompilator będzie ustawiał instrukcje spekulatywne, jeżeli jest powód aby mieć nadzieję iż taka spekulacja będzie korzystna. Aby osiągnąć korzyść muszą byś spełnione dwa warunki: prawdopodobieństwo potrzeby poprawiania działania kompilatora jest znikomo małe, oraz wcześniejsze wykonanie jakiejś operacji umożliwia późniejszą optymalizację (ILP) Spekulatywne wykonywanie kodu (Control speculation) Idea spekulatywnego wykonywania kodu to optymalizacja wykonania programu przez kompilator która polega na wcześniejszym wykonaniu instrukcji lub grupy instrukcji, zanim przebieg programu dotrze do miejsca normalnego wykonania tych instrukcji. W przypadku zastosowania tego mechanizmu instrukcje są już wykonane w tym momencie gdy dopiero miały być załadowane. Technika to pozwala na zwiększenie efektów z równoległego wykonywania instrukcji (ILP), oraz zaoszczędzenie czasu przy wykonywaniu instrukcji które zajmują dużo mocy procesora. W efekcie całkowity czas wykonania programu skraca się. Istnieje możliwość nietrafnego wykonania instrukcji, spowodowana skokiem do innej części kodu, niż ta która została już wykonana. Jeśli dane nie zostały prawidłowo przewidziane to istnieje mechanizm który zapisuje takie zdarzenie. Sygnalizacja polega na wstawieniu specjalnego znacznika do docelowego rejestru, w którym znajdują się rezultaty wykonanych spekulatywnie instrukcji. Znaczniki te są inaczej reprezentowane w rejestrach ogólnego przeznaczenia a inaczej w rejestrach zmiennoprzecinkowych. Z rejestrami ogólnego przeznaczenia skojarzony jest specjalny bit NaT (Not a Thing). Jeśli w ten bit ma wartość 1 oznacza to, iż dane w odpowiednim rejestrze ogólnego przeznaczenia nie mogą być wykorzystane. W rejestrach zmiennoprzecinkowych wystąpienie nieprawidłowo załadowanych instrukcji które korzystały z tych rejestrów jest sygnalizowane przez specjalną wartość umieszczaną w tym rejestrze zwaną NaTVal (Not a Thing Value) 24 Aby lepiej zilustrować działanie spekulatywnego wykonania kodu można podać następujący przykład: if(a>b) instrukcja1; else instrukcja2; Jeśli kompilator spodziewa się, że warunek (a>b) będzie prawdziwy to nakazuje wykonanie instrukcja1 wcześniej, zanim ten warunek będzie sprawdzany. W normalnym przypadku instrukcja1 była by wykonana dopiero kiedy warunek (a>b) będzie sprawdzony i okaże się prawdziwy, może się również zdarzyć taka sytuacja, że instukcja1 nie byłaby w ogóle wykonana. Jeśli kompilator użył techniki spekulatywnego wykonania kodu, pozostaje później jedynie czy warunek rzeczywiście został prawidłowo przewidziany Wszystkie instrukcje zostały na dwie kategorie: spekulatywne (te które można używać spekulatywnie) oraz nie-spekulatywne (te które nie można). Nie-spekulatywne instrukcje nie powodują późniejszego sprawdzania czy naprawdę miały być wykonane (nie są później ustawiane wartości NaT). Stosowanie takich instrukcji wcześniej zanim jest znane miejsce ich wykonania jest niebezpieczne. Instrukcje spekulatywne są wyposażone w mechanizmy sprawdzania i można je bezpiecznie stosować zanim znane jest miejsce ich wykonania. Ładowanie do rejestrów ogólnego przeznaczenie, oraz zmiennoprzecinkowych jest możliwe za pomocą instrukcji spekulatywnych (ld.s, ldf.s, ldfp.s) jak i nie-spekulatywnych (ld, ldf, ldfp). Sprawdzanie czy dane w rejestrach są poprawne wykonuje się za pomocą instrukcji chk.s. Instrukcja ta powinna być wykonana zanim zostanie osiągnięty punkt gdzie spekulatywnie wykonane instrukcje miały miejsce pierwotnie. Instrukcja ta testuje wystąpienie znacznika niepoprawności danych. Jeśli ten nie jest znaleziony to spekulatywne wykonanie zakończyło się sukcesem i dalej przebieg programu toczy się normalnie. Jeśli jednak znacznik taki jest to spekulatywne wykonanie zakończyło się niepowodzeniem i instrukcje muszą zostać powtórzone. Spekulatywny dostęp do pamięci (Data speculation) Spekulatywny dostęp do danych nazywany jest także zaawansowanym ładowaniem (advanced loads) W dzisiejszych systemach procesor działa zwykle o wiele szybciej niż pamięć. Spodziewane jest tylko pogłębienie tej przepaści. W ten sposób opóźnienie w dostępie do danych jest poważnym problemem dla dzisiejszych systemów. Aby zredukować niekorzystny wpływ takiego wąskiego gardła tradycyjne architektury stosują pozwalają kompilatorowi oraz procesorowi na zaplanowanie wcześniejszego ładowania danych z pamięci, niż to jest rzeczywiście potrzebne. Niestety dla dzisiejszych systemów barierą która nie pozwala zawsze zastosować tą technikę są skoki. Spekulatywny dostęp do danych polega na przeprowadzeniu ładowania danych z pamięci zanim zostanie wykonane zapisanie do pamięci które rzeczywiście ma poprzedzać ładowanie. Jedynym warunkiem użycia tego mechanizmu jest to aby relacja między adresem pod który zapisujemy dane, a adresem skąd ładujemy dane była wyznaczona niedwuznacznie. Nie ma bariery skoków, dane mogą być ładowane do pamięci nawet przed skokiem za którym pamięć może być potrzebna. Za takim postępowaniem kryją się problemy. Jeżeli nie zostanie prawidłowo przewidziana pamięć do załadowania, zostaną załadowane dane które nie są poprawne. Trzeba jakoś poradzić sobie z takim problemem, gdyż w przeciwnym wypadku mogą wystąpić poważne błędy jeśli taki błąd zostanie 25 zignorowany. Istniały do tej pory dwa podejścia do zaistniałej sytuacji. Dodanie specjalnego sprawdzania błędów, niestety taka alternatywa, niweluje dotychczasowe zyski szybkościowe, lub tzw. „work without net” czyli ryzykowanie wystąpienia katastrofalnych niewykrywalnych błędów, poprzez wyłączenie dodatkowej kontroli. IA-64 wybiera tzw. złoty środek, oferując nowe rozwiązanie. Podstawową ideą tego rozwiązania jest to iż, do danych połączony jest bit NaT (Not a Thing) który informuje czy błąd został wygenerowany podczas ładowania danych czy nie. Ten bit wskazuje, ze dane przechodzące różne operacje np.: arytmetyczne, przemieszczenia, były sprawdzone przez tzw. instrukcję chk. (instrukcja ta została tak zaprojektowana, że nie zabiera dodatkowego czasu procesora.) Taka taktyka sprawia, że kompilator może śmiało ładować spekulatywnie dane przed czasem, bez płacenia niepotrzebnej kary przy wyjątkowych sytuacjach. Jest to znakomita korzyść w porównaniu z dotychczasowymi rozwiązaniami, gdzie traci się albo na dodatkowym sprawdzaniu błędów, albo naraża się na ryzyko. Używanie bitu NaT oraz sprawdzania dodatkowego, bez użycia głównej mocy obliczeniowej procesora pozwala na używanie spekulatywnego dostępu do pamięci bardzo efektywnie. Dodatkową korzyścią z bitu NaT jest to, że może on być używany do sygnalizowania strukturalnych błędów jakie można znaleźć w językach C/C++. Ponieważ kompilator może zaplanować wykonanie instrukcji chk kiedy chce, możliwe jest bezpieczne odwlekanie wystąpienia błędów, aż do najlepszego momentu na obsłużenie ich. Taka technika wspierająca strukturalną obsługę błędów jest jedną z kluczowych cech IA-64 i gwarantuje stabilność systemu. Mechanizm obsługi błędów polega na następującym algorytmie: IA-64 trzyma ścieżki wszystkich ładowań, które są zaplanowane przed możliwymi konfliktami zapisu w specjalnej tablicy. Tablica ta jest nazwana ALAT (Advanced Load Addres Table – tablica adresów zaawansowanego ładowania). Kiedy napotkany jest zapis do pamięci który powoduje konflikt z danymi zapisanymi w tablicy, to ten zapis jest usuwany z tablicy. Natomiast sposób sprawdzania załadowanych danych polega na przeglądnięciu tablicy. Brak wpisu w tablicy sygnalizuje ze wartość należy ponownie załadować, aby osiągnąć poprawny rezultat. Metoda z tablicą ładowań jest unikalna i pozwala ładować dane na tyle wcześniej, aby opóźnienie w dostępie do pamięci zostało praktycznie w całości zniwelowane. Podobnie jak przy spekulatywnym wykonywaniu kodu tak i przy spekulatywnym dostępie do pamięci instrukcje są podzielone na dwie kategorie. Pierwsza kategoria to ta które bezpiecznie można używać przy spekulatywnym dostępie do pamięci, natomiast druga to taka która nie zawiera mechanizmu sprawdzania poprawności załadowanych danych. Korzyści ze spekulatywnego dostępu do danych są oczywiste, procesor nie musi czekać na dane, a trzeba zauważyć, że dostęp do fizycznej pamięci ram jest wolny w porównaniu z szybkością procesora. Badania prowadzone nad tą technologią czyli nad spekulatywnym wykonywaniem kodu, oraz spekulatywnym dostępem do pamięci wykazały następujące wnioski. W ogólnych zastosowaniach technika to poprawia osiągi procesora o 79% w porównaniu z systemami nie posiadającymi spekulatywnych mechanizmów. Największe korzyści z zastosowania spekulatywnego wykonywania kodu, oraz spekulatywnego dostępu do pamięci można zauważyć dla programów które wymagają częstego dostępu do cache. Takie zachowanie jest typowe na przykład dla systemów operacyjnych czy wielkich baz danych. 26 Skoki (zapobieganie, przewidywanie, unikanie) Procesory IA-64 posiadają rejestry predykatów, każdy po 1 bicie. Większość instrukcji procesorów IA-64 zawiera pole predykatu. Idea zastosowania predykatów polega na wykonywaniu instrukcji tylko wtedy gdy wyróżniony rejestr predykatowy zawiera wartość prawda. Wartości w rejestrach predykatowych są wytwarzane przez instrukcję CPM która porównuje wartości dwóch rejestrów (używając rozmaitych sposobów porównań), lub przez instrukcję TBIT (test bit). Pojedyncza instrukcja CPM lub TBIT zapisuje wynik swojego działania w jednym rejestrze predykatowym, oraz automatycznie zapisuje negacje wyniku w innym rejestrze predykatowym. Taki mechanizm pozwala bardzo efektywnie wykonać częstą konstrukcję IF-THEN-ELSE, przy niewielkim nakładzie pracy przypadającym na każdy blok, a co najważniejsze unika się skoków które występują w takiej konstrukcji w liczbie 2, z czego 1 jest bardzo trudny do przewidzenia. dla przykładu RISC lub CISC IA-64 instr 1 instr 2 instr 1 instr 2 IF cmp(a==b) jump_equ e1 THEN instr3 instr4 jump e2 (PR1) (PR1) instr3 instr4 e1: instr5 instr6 (PR2) (PR2) instr5 instr6 e2: instr7 instr8 ELSE PR1,PR2 ←cmp(a==b) instr7 instr8 Jak widać technika zastosowana w IA-64 całkowicie eliminuje oba skoki, nie ma więc obawy związanej z przestojami spowodowanymi przez nietrafione przewidywanie skoków, oprócz tego wielkość kodu różni się w porównaniu z tradycyjnymi architekturami na korzyść IA-64. Dodatkową zaletą jest możliwość wykonania kodu równolegle, co nie jest możliwe przy konwencjonalnym wykonaniu kodu. Technika predykatów była już znana wcześniej, ale nigdy w tak ogólnym przypadku. Niektóre istniejące procesory (np. Alpha, Sparc v9, MIPS IV) mają podobne mechanizmy, które oferowały niektóre dobrodziejstwa stosowania predykatów, ale tylko w przypadku instrukcji MOV. Metoda predykatów zastosowana w IA-64 pozwala na stosowanie jej w każdym z typów instrukcji. Jednak nie wszystkie skoki mogą być wyeliminowane przy zastosowaniu predykatów. 27 Powołując się na badania Uniwersytetu z Illinois można stwierdzić, że ponad połowa wszystkich skoków może być wyeliminowana, oraz 43% wszystkich skoków które tradycyjnie były by błędnie przewidziane. Eliminacja takiej ilości skoków powinno zwiększyć osiągi procesora o około 5 do 10 %. Podstawowa instrukcja skoku w IA-64 używa 21- bitowego względnego przesunięcia. Celem skoku musi być pierwsza instrukcja w paczce. Pozwala to na skoki do instrukcji które są oddalone od siebie nie dalej niż 16 MB. Wyrównanie celu skoku do początku paczki powoduje uproszczenie jednostki wykonującej skoki, oraz pozwala na rozszerzenie zasięgu skoku, powoduje jednak rozrost kodu, związany z dodaniem średnio jednej instrukcji NOP na jeden skok. Skoki związane z instrukcjami warunkowymi zostały rozwiązane za pomocą rejestrów predykatowych, natomiast skoki związane z wywoływaniem procedur, powrotem z nich oraz podobne używają specjalnego zestawu rejestru zwanych rejestrami skoków (branch registers). Rejestry te są używane (zamiast rejestrów stałoprzecinkowych w tradycyjnych rozwiązaniach) do przechowywania docelowego adresu skoku. Takie rozwiązanie pozwala na uniknięcie używania stosu wywołań/powrotów gdzie zwykle przyjęło się przetrzymywać adres powrotny. W przewidywaniu skoków bardzo pomocny jest rejestr LC (licznik pętli) który zawiera liczbę przebiegów pętli które jeszcze mają być wykonane. Większość tradycyjnych jednostek przewidywania skoków błędnie przewidywało ostatni kończący wykonanie pętli skok. Zadanie to w IA-64 wydaje się łatwe. Jednostka przewidywania skoków poprawnie przewidzi ten skok patrząc właśnie na wartość w rejestrze LC. Ponieważ w danej chwili spodziewany jest jedynie jeden skok związany z pętlą, istnieje tylko jeden licznik pętli. Innym mechanizmem który jest pomocny przy przewidywaniu skoków to 2-bitowe pole zawarte w instrukcji skoku (hint) w którym kompilator daje wskazówkę procesorowi. Pierwszy bit pokazuje czy jest większe prawdopodobieństwo na wykonanie skoku czy nie. Niektóre skoki prawie zawsze prowadzą w jedną stronę, co powoduje iż kompilator może sugerować ten kierunek. Drugi bit sygnalizuje czy informacja o skoku powinna być przechowywana czy też jednostka przewidywania skoków powinna zignorować ten skok zwalniając miejsce dla bardziej skomplikowanych skoków. Procesor ma zawsze ostatnie słowo w procesie przewidywania skoków i może zignorować sugestie zawarte w instrukcjach. Kombinacja programowego oraz sprzętowego przewidywania, wraz z dodatkowymi wskazówkami (typu rejestr LC) powinna dać lepsze rezultaty niż dotychczasowe tylko sprzętowe rozwiązania. Tak jak niektóre procesory RISCowe (np. PA-RISC), IA-64 może wykonywać w jednym cyklu zegarowym porównanie, oraz instrukcję skoku. Jest jednak różnica w osiąganiu tego celu. PA-RISC posiada specjalną instrukcję porównaj-i-skocz, IA-64 zamiast łączyć instrukcję porównania (która dodatkowo zapełnia rejestry predykatowe) z instrukcją skoku, układa te dwie instrukcje w jednej paczce, przy czym instrukcja skoku musi być ostatnią z instrukcji. W specjalnym przypadku dwie instrukcje skoku mogą być położone w jednej paczce. Powstaje wtedy tzw. rozgałęziony skok (multiway branch). Również taki układ skoków może zostać wykonany w jednym cyklu. Sprawdzany jest wtedy warunek oraz wyznaczany skok do wykonania (jeśli o ogóle któryś ma zostać wykonany) 28 Pierwszy procesor IA-64 Itanium Pierwszym procesorem który będzie wykonany w architekturze IA-64 będzie Itanium. Producentem tego procesora będzie firma Intel. Procesor jest znany także znany pod nazwą Merced. Nazwa Merced była to robocza nazwa tego procesora, jednak forma Intel zdecydowała się na zmianę nazwy tego produktu przy wypuszczeniu na rynek. Procesor spodziewany jest na rynku w połowie 2000 roku. Procesor ten dedykowany będzie do pracy w serwerach i stacjach roboczych. Rozkład rejestrów w Itanium W procesorze Itanium ilość rejestrów przedstawia się następująco: Rejestry ogólnego przeznaczenia – 128 sztuk, adresowane od rejestru GR[0], który jest tylko do odczytu, do rejestru GR[127]. Rejestry od GR[0] do GR[31] to rejestry statyczne, natomiast rejestry od GR[32] do GR[127] to rejestry rotujące Rejestry NaT – 128 sztuk, po jednym rejestrze NaT do każdego rejestru ogólnego przeznaczenia. Rejestry Zmiennoprzecinkowe – 128 sztuk, adresowane od rejestru FP[0], który wraz z rejestrem FP[1] są tylko do odczytu. Rejestry od FP[0] do FP[31] to rejestry statyczne, natomiast rejestry od FP[32] do FP[127] to rejestry rotujące. Rejestry Aplikacyjne – 128 sztuk Rejestry Predykatów – 64 sztuki. Rejestr PR[0] jest tylko do odczytu. Rejestry od PR[0] do PR[15] to rejestry statyczne, natomiast od PR[16] do PR[63] to rejestry rotujące. Rejestry Skoków – 8 sztuk. Wskaźnik Instrukcji – Jeden 64-bitowy rejestr. Oznaczenie Aktualnej Ramki Stosu – Zestaw rejestrów zajmujący 38 bitów. Rejestry PMD – 18 sztuk. Rejestry od 0 do 3 to tzw. rejestry statusu przepełnienia (Performance Contuer Overflow Status Registers). Rejestry 4-7 to tzw. rejestry ogólne rejestry badania osiągów (Preformance Contuer Configuration/Data Registers), w rejestrach tych znajdują się zarówno części związane z konfiguracją (PMC) jak i właściwe rejestry PMD przechowujące dane. Rejestry 8-9 to rejestry (Opcode Match Registers) Rejestry 10-11 to tzw. rejestry konfiguracji zdarzeń systemowych (Instruction/Data Event Addres Configuration Registers) Rejestry danych zdarzeń systemowych zajmują (jeśli procesor jest w tym trybie badania konfiguracji) miejsca 0-3 oraz 17. Rejestr 12 to tzw. rejestr konfiguracji skoków krokowych (Branch Trace Buffer Confguration Register) Rejestru danych skoków krokowych zajmują (jeśli procesor jest w tym trybie badania konfiguracji) miejsca 8-16 Rejestr 13 to tzw. rejestr sprawdzania zasięgu adresu (IA-64 Instruction Address Range Check Register) 29 Rejestr Maski Użytkownika – Jeden rejestr składający się z pięciu 1-bitowych flag. Rejestry Identyfikacji Procesora – 5 rejestrów. Liczba podstawowych rejestrów raczej będzie taka sama także i w innych procesorach serii IA-64. Gdyby się wzrosła ilość rejestrów ogólnego przeznaczenia, lub zmiennoprzecinkowych, musiałoby to pociągać za sobą zmianę długości instrukcji, ponieważ zestaw 128 bitowych rejestrów jest adresowany za pomocą 7 bitów, gdyby ta liczba wzrosła adres musiałby zawierać co najmniej 8 bitów co by wiązało się ze zwiększeniem długości instrukcji o średnio 3 bity. W procesorach innych niż Itanium prawdopodobne są jednakże rozszerzenia w zestawie Rejestrów Aplikacyjnych który to zestaw posiada wiele pól ignorowanych lub zarezerwowanych. Możliwa jest także zmiana ilości rejestrów identyfikacji procesora, gdzie nawet explicite jest podane ile tych rejestrów posiada odpowiedni procesor w cpuid[3]. Do tej pory nie zdołaliśmy się zorientować w ile rejestrów PMD został wyposażony procesor Itanium. Wracając jeszcze do rejestrów, lub części rejestrów, które są zarezerwowane, lub ignorowane, to takie miejsca występują nie tylko w rejestrach Aplikacyjnych i miejsca te mogą być w przyszłości wykorzystane. 30 31 Instrukcje procesora Itanium W procesorze Itanium zaimplementowano następujące instrukcje w kolejności alfabetycznej: (Mega) Otoczenie procesora Itanium Istnieje już prototyp chipsetu który będzie zarządzał działaniem otoczenia procesora Itanium. Chipset ten posiada kodową nazwę 460GX. Układ ten będzie zawierał cechy które są wymagane w komputerach do poważnych zastosowań, takich jak serwery, czy stacje robocze wielkiej mocy. Dla przykładu wszystkie magistrale systemowe, oraz wszystkie rodzaje pamięci (w tym cache) będą chronione przed przekłamaniami danych. Nieprawidłowe dane będą jeśli to możliwe poprawiane, w przeciwnym wypadku będą zaznaczane jako niepoprawne, co będzie powodowało zastopowanie odpowiedniego procesu, bez zastopowania całego systemu. Możliwe jest także wykrycie nieprawidłowej części pamięci i wyłączenie jej z dalszej pracy systemu. Chipset umożliwia także prace większej ilości procesorów Itanium jednocześnie. W takiej konfiguracji każdy procesor jest sprawdzany przez pozostałe, co minimalizuje możliwość wystąpienia błędu. Chipset 460GX umożliwia stosowanie techniki tzw. hot-plugging/hot-swapping czyli możliwość podłączania, oraz zmieniania sprzętu podczas pracy systemu. Tyczy się to zarówno pamięci masowej jak i urządzeń PCI oraz AGP. Magistrala AGP jest tutaj standardowo w wersji 4x. Użycie 460GX umożliwia pracę z pamięcią operacyjną nie przekraczającą 16 GB. Dostęp do tej pamięci jest poprzez magistralę której przepustowość ograniczona jest przez 3.2 GB/s. Przewidywania dotyczące procesorów opartych na IA-64 Porównanie Itanium z innymi procesorami Co prawda jest jeszcze za wcześnie aby obiektywnie stwierdzić czy pierwszy procesor oparty na architekturze IA-64 będzie konkurencyjny dla innych procesorów na rynku w momencie pojawienia się go na rynku. Intel szacuje, że Itanium będzie więcej niż konkurencyjnym produktem w porównaniu z obecnymi architekturami RISC. Jest jednak jasne iż wybór alternatywnych architektur będzie większy. Wśród innych znaczących producentów procesorów przeznaczonych dla serwerów oraz stacji roboczych warto zwrócić uwagę na IBM który zamierza znacząco zwiększyć moc swoich procesorów PowerPC, zmieniając materiał do wyrobu swoich chipów na miedź. Sun kontynuuje wzrost swojego udziału na rynku serwerów Unixowych swoją generacją procesorów UltraSPARC. Także Compaq nie poddaje się i zamierza wprowadzić na rynek nowy procesor Alpha EV7 (niemal w tym samym czasie co Intel Itanium). Procesor ten jest projektowany do pracy w częstotliwościach powyżej 1Ghz. Co ciekawsze Hewlett-Packard zamierza kontynuować ulepszanie swoich systemów opartych na procesorach PA-RISC dopóki procesory IA-64 całkowicie nie zdeklasują tych systemów. A warto zauważyć, że Hewlett-Packard jest współprojektantem architektury IA-64. Oprogramowanie dedykowane dla IA-64 Mimo tego wszystkiego większość sprzedawców systemów zamierza zaangażować się we wspieranie architektury IA-64 a nawet późniejsze przestawienie się z architektury RISC na 32 IA-64. Do tej pory IBM, Sun, HP, oraz Compaq zapowiedzieli stworzenie swoich wersji UNIXa działających na platformie IA-64. Dodatkowo praktycznie gotowe jest już jądro systemu Linux mające działać na nowej platformie Intela. Także inni producenci systemów bacznie przyglądają się nowej technologii. Dotyczy to zarówno producentów systemów UNIXowych, jak i innych. Microsoft zapowiedział wypuszczenie Windowsa dla procesora Itanium, praktycznie tuż po premierze samego procesora. Bardzo podobnie ma się rzecz w przypadku systemu NetWare firmy Novell. Co prawda nowy procesor Itanium jest dedykowany do zadań profesjonalnych, to Intel bardzo liczy na implementację najpopularniejszego obecnie w zadaniach domowych oraz biurowych systemu czyli Windows firmy Microsoft. System ten posiada bogaty zestaw oprogramowania, oraz jest bardzo rozpowszechniony, to stanowi jego niezaprzeczalne zalety. Intel stoi na stanowisku, iż architektura którą on zaprojektował pozwala na uruchamianie istniejących aplikacji typu IA-32 w nowym systemie Windows. Microsoft jednakże sygnalizuje, że większość, jeżeli nie wszystkie aplikacje napisane dla IA-32 będą wymagać jedynie rekompilowania aby skorzystać ze wszystkich cech IA-64. Tak więc jeśli ktoś chce się przesiąść z IA-32 na procesor Itanium to powinien liczyć się ze zmianą systemu oraz z potrzebą zakupienia nowych wersji aplikacji Itanium pierwszy procesor IA-64 jest przez wiele korporacji postrzegany jako następny procesor w ich planach zmiany sprzętu. Zmiana istniejących komputerów na nowe z procesorem Itanium, jak zapewnia wiele niezależnych źródeł powinno znacznie zwiększyć moc sprzętu. Dodatkową zaletą jest to, iż zapowiada się iż produkt Intela będzie dosyć popularny, a co za tym idzie jego cena na pewno będzie znacznie niższa niż dzisiejsze superkomputery. Podobnie rzecz się ma z wszelkiego rodzaju serwisem, który będzie tańszy, oraz bardziej dostępny. Kolejne procesory IA-64 Itanium nie jest jedynym procesorem nad którym pracują inżynierowie Intela. Licząc, że Itanium wejdzie na rynek w zaplanowanym terminie czyli w połowie roku 2000, należy przypuszczać, iż teraz procesor jest już gotowy. Zapowiadane są już kolejne procesory zbudowane na podstawie architektury IA-64. Najbliższymi po Itanium procesorami które mają wyjść na rynek to McKinley, oraz Willamette. McKinley – to procesor który ma być następcą Itanium. Debiut tego procesora spodziewany jest na połowę roku 2001, jednak znając dotychczasowe prace Intela można się spodziewać opóźnienia tego terminu do początku 2002. Procesor ten tak jak Itanium będzie dedykowany dla komputerów dużej mocy, oraz wszelkiego rodzaju serwerów. Willamette – procesor ten spodziewany jest w roku 2001. Jest to ukłon Intela w stronę prywatnych użytkowników komputerów których nie stać na procesory typu Itanium. Będzie to uproszczona konstrukcja, spełniająca jednakże wymagania zastosowań domowych oraz małych biur. Deerfield – kolejny procesor Intela zbudowany w technologii IA-64 zapowiadany na połowę roku 2002. Madison – procesor Intela zapowiadany na rok 2003. 33 Słownik ALAT - (Advanced Load Address Table) tablica adresów zaawansowanego ładowania, jest ona używana w mechanizmie obsługi błędów związanych ze spekulatywnym dostępie do pamięci. W tablicy tej trzymane są ścieżki wszystkich spekulatywnych ładowań. Bundle – paczka w której umieszcza się instrukcje zaplanowane do załadowania w jednym cyklu zegara. Paczka taka ma wielkość 128 bitów. W takiej paczce mieszczą się trzy instrukcje po 41 bity każda, oraz 5-bitowe pole tzw. template. CISC – (Complex Instruction Set Computing) Architektura cechująca się szerokim zestawem złożonych instrukcji, małym zestawem rejestrów. Instrukcje mają różną długość i są wykonywane w różnej ilości cykli zegarowych. Przykładem procesorów wykonanej w tej architekturze jest seria IA-32. EPIC – (Explicitly Paralell Instruction Computing) „przetwarzanie wyraźnie równoległe” Architektura cechująca się grupowaniem instrukcji w paczki (bundles), które to instrukcje można wykonać równolegle. Instrukcje mają stałą długość, ilość rejestrów jest duża. IA-32 – (Intel Architecture 32-bit) Dzisiejsza podstawowa architektura Intela. Jest to 32bitowa architektura CISC, zwana również pod nazwą x86. Itanium – Pierwszy procesor zrealizowany w architekturze IA-64. Procesor ten ma pojawić się na rynku w połowie 2000 roku, jego producentem jest firma Intel. Merced – Kodowa nazwa pierwszego procesora IA-64. Rynkowa nazwa tego procesora brzmi Itanium. NaT – (Not a Thing) Rejestry które mówią, że dane w rejestrach ogólnego przeznaczania, nie są poprawne, odpowiednikiem tego rozwiązania w rejestrach zmiennoprzecinkowych są wartości NaTValue. PA-RISC – (Architecture Precision RISC) Architektura procesorów produkowanych przez firmę Hewlett-Packard. Znana także jako HP-PA RISCowych RISC – (Reduced Instruction Set Computing) Architektura cechująca się niewielkim zestawem prostych instrukcji, oraz dużym zestawem rejestrów. Instrukcje mają stałą długość i są wykonywane w jednym cyklu zegarowym. Przykładem procesorów wykonanych w tej architekturze jest sera PA-RISC. VLIW – (Very Long Instruction Word) – pierwsza architektura pomyślana z myślą o grupowaniu instrukcji przeznaczonych do równoległego wykonania. 34