Podstawy
Co to jest procesor?
Tłumaczę to bez akademickich schematów — od pojedynczego przełącznika po kartę graficzną i układy ASIC.
film wkrótce na YouTubeTen artykuł nie będzie o procesorze w sposób akademicki, gdzie rozrysowuje się schematy i mówi o jednostce sterującej czy ALU. Chcę po prostu wyjaśnić, co to jest i czym się to je.
Procesory najczęściej przedstawia się na schematach, które wyglądają mniej więcej tak:

I tutaj od razu widać, że nic nie widać. Jak ktoś się na tym zna, to rozumie, co jest narysowane — ale jak ktoś nie do końca wie, co to jest procesor, to taki schemat totalnie nic mu nie powie.
Wyobraźcie sobie, że macie gościa ze średniowiecza i chcecie mu wytłumaczyć, co to jest samochód, więc rozrysowujecie mu, że są diesle, że są samochody na benzynę, elektryczne, a w ogóle to jeszcze są motocykle, autobusy, tiry i tak dalej. Taki gość ze średniowiecza może się tylko pogubić, co to w ogóle jest.
Dlatego chcę podejść do tego od innej strony. A jak ktoś później będzie chciał wejść w schematy budowy procesora i w to, jak to dokładnie działa — to sobie to sam dorzuci.
Mój własny schemat
No dobra, ale jakiś schemat w końcu zrobię. Tak będzie wyglądał mój schemat:

Co tu widzimy? Zwykły przełącznik. Każdy z takich guzików ma dwa stany, 0 i 1. A teraz wyobraźcie sobie, że procesor nie ma dwóch takich przełączników jak na obrazku, tylko mnóstwo — naprawdę sporo. I o ile człowiek może przełączyć taki przełącznik ręcznie kilka razy na sekundę, to procesor robi to mega, mega szybko.
Jeśli procesor ma na przykład 1 GHz, to znaczy, że jednym takim przełącznikiem jest w stanie przełączyć miliard razy na sekundę. Tak to mniej więcej działa — w dużym uproszczeniu oczywiście.
Dlaczego potrzebujemy warstw abstrakcji
Tu pojawia się dość ciekawa analogia, znowu z fizyką i elektronami. Wyobraźcie sobie, że siedzicie na krześle. Krzesło składa się tak naprawdę z atomów i elektronów, między którymi w zasadzie jest całkowita pustka. Spróbujcie sobie wyobrazić, jak to jest, że siedzicie na tych atomach i elektronach — to jest poza wyobrażeniem ludzkiego umysłu.
Podobnie jest z tymi przełącznikami: jest ich tak dużo i działają tak szybko, że to w ogóle nie są liczby, które jesteśmy w stanie pojąć. Dlatego na przełączanie tych przełączników napisaliśmy jakieś funkcje pomocnicze, na tych funkcjach pomocniczych kolejne funkcje pomocnicze, i tak dalej — takich warstw jest naprawdę dużo. Po to, żebyśmy jako ludzie w ogóle byli w stanie tego typu układy robić.
Jak procesor wykonuje instrukcje
Jak to wygląda w samym procesorze? Procesor wykonuje instrukcje jedna po drugiej. Możemy to sobie zamodelować w Google Docsie i dodać np. 4 instrukcje (tych podstawowych jest tak naprawdę kilkanaście, a wszystkich razem — kilkadziesiąt):

00— dodawanie01— odejmowanie10— zamiana na zera11— zamiana na jedynki
I teraz do procesora wprowadzamy takie instrukcje jedna po drugiej, w kółko, w nieskończoność — i to jest tak sprytnie zrobione, że cała elektronika po prostu w ten sposób działa.
Jak to wygląda w praktyce? Do procesora nie trafiają słowa „dodaj” czy „odejmij”, tylko ciąg zer i jedynek. Powiedzmy, że w naszym modelu liczby mają po 8 bitów. Chcę, żeby procesor dodał liczbę 100 i liczbę 1111, potem dodał jeszcze dwie inne liczby, a na końcu zamienił wynik na same zera. Do procesora wchodzą więc kolejno takie bity:
00000001000000111100000000100000001110Dla nas to nieczytelna kaszka, ale procesor wie, jak to czytać. Pierwsze dwa bity zawsze interpretuje jako instrukcję. Jeśli to instrukcja dodawania, to wie, że zaraz po niej przyjdą dwie liczby, więc bierze kolejne 8 + 8 bitów. Potem znowu dwa bity traktuje jako następną instrukcję i tak dalej. Rozpisane wygląda to tak:
00 00000100 00001111 → 00 = dodawanie: 100 + 1111 = 10011
00 00000010 00000011 → 00 = dodawanie: 10 + 11 = 101
10 → 10 = zamiana na zera: wynik = 00000000Trzecia instrukcja to 10, czyli zamiana na zera. Ona nie potrzebuje żadnych liczb, więc procesor nie czyta po niej nic więcej, tylko swoimi przełącznikami zamienia ostatni wynik na same zera — a potem zapisuje go gdzieś w pamięci.
Bo oprócz tego, że procesor zamienia zera na jedynki i wykonuje operacje, musi też mieć gdzieś miejsce, żeby te operacje zapisywać. Taka pamięć bardzo często jest wbudowana w sam układ procesora — oprócz tego, że gdzieś w komputerze mamy osobny RAM, sam procesor, blisko swoich układów przełączających, też ma własne, małe pamięci, które pozwalają mu wykonywać operacje jak najszybciej.
Każdy procesor działa tak samo
I w zasadzie dokładnie tak, jak w powyższym modelu z dokumentu Google'a, działa każdy procesor. Dla mnie to kiedyś było zupełnie niezrozumiałe — wydawało mi się, że pecety czy MacBooki mają jakieś zupełnie inne procesory niż mikrokontrolery, na przykład taki tutaj:

A to jest dokładnie ta sama zasada działania, co w procesorze Intela, który siedzi w każdym pececie.
Taki procesor zawsze startuje tak samo. Start oznacza po prostu moment, w którym podajemy mu zasilanie. Wtedy procesor zagląda pod konkretny adres pamięci i zawsze bierze stamtąd pierwszą instrukcję. Potem bierze kolejną, następną, następną, a na końcu skacze z powrotem do początkowej i tak leci w kółko.
Czy można zrobić bare-metal na Intelu i MacBooku z M1
Skoro tak to działa, to pytanie: czy moglibyśmy na takiego Intela albo na MacBooka z procesorem M1 „zgrać” sobie jakiś własny program, taki jak ten z naszego modelu w dokumencie Google?
Właśnie o to chodzi w bare-metal, czyli programowaniu „na gołym metalu”. Normalnie nasz program nie rozmawia z procesorem bezpośrednio — pomiędzy jest system operacyjny, czyli Windows, macOS czy Linux. To system startuje pierwszy, zarządza pamięcią i dopiero on uruchamia nasze aplikacje. W bare-metal nie ma żadnego systemu operacyjnego. Nasz program zapisujemy dokładnie pod tym adresem pamięci, od którego procesor zaczyna po podaniu zasilania. Procesor startuje, bierze pierwszą instrukcję — i jest to od razu instrukcja naszego programu.
Teoretycznie moglibyśmy. MacBooki mają to oczywiście zabezpieczone, żeby ktoś tak po prostu nie zrobił — Intel jest do tego dużo bardziej otwarty, a mikrokontroler taki jak D1 mini (z układem ESP8266) zwykle ma to wszystko udokumentowane tak, żeby było to jak najłatwiejsze. Ale zasada działania jest zawsze taka sama — nawet jeśli mamy jakieś urządzenie typu pralka z wyświetlaczem, czymkolwiek trzeba sterować, to tam też po prostu siedzi sobie procesor. Praktycznie wszystkie tego typu urządzenia działają na bardzo, bardzo podobnej zasadzie.
Dlaczego urządzenia są takie skomplikowane
To skąd w takim razie ta cała złożoność? Najłatwiej to zrozumieć, próbując samodzielnie zbudować taki układ w głowie (nie na płytce — tego akurat bym sam nie potrafił zrobić). Chodzi o model myślowy, który pozwala zrozumieć, jak można się za to zabrać i czemu te wszystkie układy mniej więcej tak wyglądają.
Wyobraźmy sobie, że mamy nasz dokument Google'a z instrukcjami. Wiadomo, że to nie zadziała samo z siebie — chcemy te instrukcje jakoś wprowadzić do prawdziwego procesora. Jak to zrobić? Trzeba by mieć np. klawiaturę — nawet taką z samym 0 i 1 — która po wciśnięciu klawisza w jakiś magiczny sposób przekazuje to do procesora.
Klawiatura i procesory pomocnicze
Tylko że klawiatura ma mnóstwo klawiszy. Gdybyśmy chcieli połączyć każdy z nich osobnym przewodem bezpośrednio do procesora, zabrakłoby nóżek, zanim zabrakłoby klawiszy.
Dlatego realizuje się to inaczej: klawiatura ma w środku swój własny, mały procesorek, który komunikuje się z klawiszami, odbiera to, co użytkownik wpisał, i przekazuje to dalej umówionym sygnałem do głównego procesora.
A jak wygląda samo wysyłanie? Można to sobie wyobrazić trochę jak alfabet Morse'a — długi sygnał to jedynka, krótki to zero. Dajemy sobie jedną „nóżkę”, łączymy nią jeden procesor z drugim i wysyłamy nią sygnały w odpowiednim czasie (realne procesory robią to oczywiście dużo szybciej niż raz na sekundę, ale chodzi o samą ideę).
Dzięki temu mamy już dwa procesory i jakiś sposób, żeby wprowadzać dane z naszej modelowej klawiatury. Tylko że pojawia się kolejny problem: jeśli chcę napisać program do dodawania na głównym procesorze, to oprócz samego dodawania muszę jeszcze ogarnąć temat protokołu komunikacyjnego — tego całego „alfabetu Morse'a”, czyli np. UART-a.
Dlatego bierze się do tego jeszcze jeden, osobny procesor — i mamy ich już trzy. Jego zadaniem jest odbierać sygnał z klawiatury (która w praktyce komunikuje się nie prostym UART-em, tylko dużo bardziej złożonym protokołem USB) i przekazywać to dalej do głównego procesora, który nie musi się w ogóle przejmować zawiłościami USB.
Czyli z prostego pomysłu „chcę coś wkliknąć i wrzucić do procesora” zrobiły nam się już trzy procesory.
Wyświetlacz i miliony pikseli
Kolejny problem: w komputerach, telefonach itd. mamy wyświetlacz — to najfajniejsza opcja, żeby coś pokazać. Jeśli mamy prosty wyświetlacz kilkusegmentowy (taki jak na kuchence gazowej, pokazujący godzinę), to segmentów jest z grubsza 8 i w miarę łatwo nimi sterować.
Problem zaczyna się, gdy pikseli mamy naprawdę dużo — a w obrazie np. 2K jest ich już miliony. Nie da się tego wszystkiego połączyć bezpośrednio „nóżkami” do procesora. Do tego dochodzi fakt, że te miliony pikseli trzeba przeliczyć naraz, i to w dodatku odpowiednio skompresować i rozkompresować. Nie chcę wchodzić w szczegóły, ale clue jest takie, że to bardzo dużo małych, drobnych operacji przeliczających — bo takie kilka milionów pikseli dzieli się na małe kwadraciki (np. 16 na 16), każdy liczy się na kilka sposobów, a potem łączy w całość.
Karta graficzna — setki małych procesorów
Zwykły procesor sobie z tym nie radzi — mimo że ma miliardy przełączników (tranzystorów) i robi to mega szybko, to ogrom tych obliczeń jest dla niego zbyt duży, żeby wszystko działało płynnie. No i nie o to chodzi, żeby główny procesor zajmował się tylko tym.
Dlatego do takich zadań używa się np. karty graficznej, która w środku ma dajmy na to 200 mniejszych procesorów naraz. Główny procesor mówi wtedy do karty graficznej: „masz tu te 16 na 16 pikseli, ogarnij to” — i to samo mówi drugiemu, trzeciemu procesorowi karty. Te procesory liczą swoją część i odsyłają wynik z powrotem.
Tylko że znowu: po co głównemu procesorowi gadać bezpośrednio z każdym z tych (czasem setek) małych procesorów karty graficznej z osobna? Lepiej, żeby był do tego jeszcze jeden, pośredniczący procesor, który komunikuje się z tą całą resztą i raportuje do głównego.
Procesory są do siebie podobne, ASIC i akceleratory
Na dobrą sprawę takie skomplikowane układy jak pecety czy telefony to po prostu określona liczba procesorów połączonych ze sobą. I można powiedzieć, że te procesory są do siebie bardzo podobne — podobnie jak tir jest podobny do samochodu. Wiadomo, że to trochę co innego, ale zasada działania jest ta sama.
W tym sensie można by powiedzieć, że temat procesorów jest zamknięty — ale jest jeszcze jedna ciekawa rzecz: układy dedykowane, czyli ASIC (albo np. akceleratory, jak akcelerator wideo).
Procesor to urządzenie uniwersalne — do wszystkiego. Mogę na nim napisać program do dodawania, mogę do odejmowania. Ale jak coś jest do wszystkiego, to czasem jest do niczego — z procesorami tak akurat nie jest, ale są układy wyspecjalizowane tylko do jednej, konkretnej rzeczy: wrzucamy do nich jakiś sygnał, a one zawsze zwracają przetworzony sygnał, robiąc swoje funkcje i operacje w środku.
Takie układy są znacznie, znacznie bardziej wydajne od zwykłych procesorów — minus jest taki, że da się ich użyć tylko do jednej rzeczy. Można to sobie wyobrazić jako procesor zaprogramowany raz i „wypalony” w krzemie (to spore uproszczenie, bo nie tak dokładnie się to robi — ale jako model myślowy działa dobrze).
Adres startowy i bare-metal na MacBooku
Jest jeszcze jedna rzecz, o której sam kiedyś w ogóle nie wiedziałem, a warto ją sobie uświadomić, żeby dobrze zrozumieć działanie procesora: kiedy komputer startuje, czyli dostaje napięcie, zawsze sprawdza, co jest zapisane pod konkretnym adresem pamięci (numer tego adresu zależy od procesora) — i to jest wyryte fabrycznie: procesor ma się włączyć i zacząć wykonywać program właśnie od tego miejsca.
Dlatego — wracając do pytania o bare-metal — nawet w przypadku MacBooka z procesorem M1, gdybyśmy znali ten konkretny adres i ominęli zabezpieczenia Apple'a, to teoretycznie moglibyśmy sobie na takim MacBooku uruchomić własny program, np. do dodawania czy odejmowania.
