Wir alle betrachten die CPU als das "Gehirn" eines Computers, aber was bedeutet das eigentlich? Was passiert mit Milliarden von Transistoren, damit Ihr Computer funktioniert? In dieser neuen vierteiligen Miniserie konzentrieren wir uns auf das Design von Computerhardware, das die Ein- und Ausgänge eines Computers umfasst.

Diese Reihe wird sich mit Computerarchitektur, Prozessorschaltungsdesign, VLSI (Very Large Scale Integration), Chipherstellung und zukünftigen Trends im Computerbereich befassen. Wenn Sie schon immer an Details zur Funktionsweise von Prozessoren interessiert waren, legen Sie los, denn genau das möchten Sie wissen, um loszulegen.

Wir beginnen auf einem sehr hohen Niveau damit, was ein Prozessor tut und wie Bausteine ​​in einem funktionierenden Design zusammenpassen. Dies umfasst Prozessorkerne, Speicherhierarchie, Verzweigungsvorhersage und mehr. Zunächst benötigen wir eine grundlegende Definition der CPU-Funktionen. Die einfachste Erklärung ist, dass eine CPU einer Reihe von Anweisungen folgt, um an einer Reihe von Eingängen zu arbeiten. Dies kann beispielsweise darin bestehen, einen Wert aus dem Speicher zu lesen, ihn dann einem anderen Wert hinzuzufügen und das Ergebnis schließlich an einem anderen Ort zu speichern. Es kann auch etwas komplexeres sein, wie das Teilen von zwei Zahlen, wenn das Ergebnis der vorherigen Berechnung größer als Null ist.

Wenn Sie ein Programm wie ein Betriebssystem oder ein Spiel ausführen möchten, ist das Programm selbst eine Reihe von Anweisungen, die die CPU ausführen muss. Diese Anweisungen werden aus dem Speicher in einen einfachen Prozessor geladen und einzeln ausgeführt, bis das Programm beendet ist. Während Softwareentwickler ihre Programme in Hochsprachen wie C ++ oder Python schreiben, kann der Prozessor dies nicht verstehen. Es versteht nur Einsen und Nullen, daher brauchen wir eine Möglichkeit, den Code in diesem Format darzustellen.




Programme werden zu einer Reihe von Anweisungen auf niedriger Ebene zusammengestellt. Assemblersprache Als Teil der Instruction Set Architecture (ISA). Dies ist der Befehlssatz, den die CPU verstehen und ausführen soll. Einige der häufigsten ISAs sind x86, MIPS, ARM, RISC-V und PowerPC. So wie sich die Syntax zum Schreiben einer Funktion in C ++ von einer Funktion unterscheidet, die in Python dasselbe tut, hat jede ISA eine andere Syntax.




Diese ISAs können in zwei Hauptkategorien unterteilt werden: feste Länge und variable Länge. RISC-V ISA verwendet Anweisungen mit fester Länge. Dies bedeutet, dass bestimmt wird, welcher Befehlstyp eine bestimmte Anzahl vordefinierter Bits in jedem Befehl ist. Dies unterscheidet sich von x86 mit Anweisungen mit variabler Länge. In x86 können Anweisungen auf unterschiedliche Weise und mit unterschiedlicher Anzahl von Bits für verschiedene Teile codiert werden. Aufgrund dieser Komplexität ist der Befehlsdecoder auf x86-CPUs normalerweise der komplexeste Teil des gesamten Entwurfs.

Anweisungen mit fester Länge ermöglichen aufgrund ihrer normalen Natur eine einfachere Dekodierung, begrenzen jedoch die Gesamtzahl der Anweisungen, die ein ISA unterstützen kann. Gängige Versionen der RISC-V-Architektur haben ungefähr 100 Direktiven. Obwohl es sich um Open Source handelt, ist es x86-proprietär und niemand weiß, wie viele Direktiven es gibt. Die Leute glauben normalerweise, dass es mehrere tausend x86-Anweisungen gibt, aber die genaue Anzahl ist nicht öffentlich verfügbar. Trotz der Unterschiede zwischen ISAs verfügen alle im Wesentlichen über dieselbe Grundfunktionalität.







Jetzt können wir unseren Computer einschalten und etwas starten. Die Ausführung eines Befehls besteht tatsächlich aus einigen grundlegenden Teilen, die sich aus vielen Phasen eines Prozessors zusammensetzen.




Der erste Schritt besteht darin, die Anweisung aus dem Speicher in die CPU zu bringen, um den Lauf zu starten. Im zweiten Schritt wird der Befehl dekodiert, damit die CPU verstehen kann, um welche Art von Befehl es sich handelt. Es gibt viele Typen wie arithmetische Befehle, Verzweigungsbefehle und Speicherbefehle. Sobald die CPU erfährt, welche Art von Befehl sie ausführt, werden die Operanden des Befehls aus dem Speicher oder den internen Registern in der CPU gesammelt. Wenn Sie die Nummer A zur B-Nummer hinzufügen möchten, können Sie nicht hinzufügen, ohne die A- und B-Werte wirklich zu kennen. Die meisten modernen Prozessoren sind 64 Bit, was bedeutet, dass die Größe jedes Datenwerts 64 Bit beträgt.




Nachdem die CPU die Operanden für den Befehl hat, geht sie zur Ausführungsstufe über, in der die Verarbeitung bei der Eingabe erfolgt. Dies kann das Hinzufügen von Zahlen, eine logische Manipulation der Zahlen oder das unveränderte Übergeben der Zahlen sein. Sobald das Ergebnis berechnet ist, muss möglicherweise auf den Speicher zugegriffen werden, um das Ergebnis zu speichern, oder die CPU behält den Wert möglicherweise in einem ihrer internen Register. Nachdem das Ergebnis gespeichert wurde, aktualisiert die CPU den Status der verschiedenen Elemente und fährt mit der nächsten Anweisung fort.

Diese Erklärung ist natürlich eine wesentliche Vereinfachung, und die meisten modernen Prozessoren unterteilen diese wenigen Stufen in 20 oder weniger Stufen, um die Effizienz zu steigern. Dies bedeutet, dass der Prozessor zwar mehrere Anweisungen in jedem Zyklus startet und beendet, für jede Anweisung jedoch 20 oder mehr Zyklen erforderlich sein können, um von Anfang bis Ende abgeschlossen zu werden. Dieses Muster wird oft als Pipeline bezeichnet, da das Befüllen der Pipeline einige Zeit in Anspruch nimmt und die Flüssigkeit vollständig durchläuft. Wenn sie jedoch gefüllt ist, erhalten Sie eine konstante Leistung.

Der gesamte Zyklus, den eine Anweisung durchläuft, ist ein sehr strenger choreografierter Prozess, aber möglicherweise enden nicht alle Anweisungen gleichzeitig. Beispielsweise kann das Einfügen sehr schnell erfolgen, während das Aufteilen oder Laden aus dem Speicher Hunderte von Zyklen dauern kann. Anstatt den gesamten Prozessor anzuhalten, wenn ein langsamer Befehl beendet ist, laufen die meisten modernen Prozessoren nicht mehr in Ordnung. Dies bedeutet, dass sie bestimmen, welcher Befehl zu einem bestimmten Zeitpunkt am nützlichsten ist, und andere Anweisungen puffern, die nicht bereit sind. Wenn der aktuelle Befehl noch nicht fertig ist, kann der Prozessor im Code vorwärts springen, um zu sehen, ob etwas anderes bereit ist.

Neben der ungewöhnlichen Ausführung sind typische moderne Prozessoren, superskalare Architektur. Dies bedeutet, dass der Prozessor zu jedem Zeitpunkt in jeder Phase der Pipeline viele Anweisungen gleichzeitig ausführt. Darüber hinaus warten möglicherweise Hunderte von anderen darauf, mit ihrer Ausführung zu beginnen. Um viele Befehle gleichzeitig ausführen zu können, verfügen sie über mehrere Kopien jeder Pipeline-Stufe innerhalb der Prozessoren. Wenn ein Prozessor feststellt, dass die beiden Befehle zur Ausführung bereit sind, und anstatt darauf zu warten, dass sie separat beendet werden, werden beide gleichzeitig ausgeführt, wenn keine Abhängigkeit zwischen ihnen besteht. Eine häufige Anwendung hierfür ist das Simultaneous Multithreading (SMT), auch als Hyper-Threading bekannt. Während Intel- und AMD-Prozessoren derzeit bidirektionales SMT unterstützen, hat IBM Chips entwickelt, die Acht-Wege-SMT unterstützen.

Um diese sorgfältig choreografierte Ausführung zu erreichen, verfügt ein Prozessor zusätzlich zum Basiskern über viele zusätzliche Elemente. Es gibt Hunderte von separaten Modulen in einem Prozessor, die jeweils einem bestimmten Zweck dienen, aber wir werden die Grundlagen behandeln. Die zwei größten und nützlichsten sind Cache- und Zweigprädiktoren. Zusätzliche Strukturen, die wir nicht behandeln, umfassen Dinge wie das Neuordnen von Puffern, Aufzeichnungsalias-Tabellen und Reservierungsstationen.

Der Zweck von Caches kann verwirrend sein, da sie häufig Daten wie RAM oder SSD speichern. Was Caches auszeichnet, sind Zugriffslatenzen und -geschwindigkeiten. Obwohl RAM extrem schnell ist, ist es für die CPU eine sehr langsame Größenordnung. RAM kann Hunderte von Zyklen dauern, um mit Daten zu antworten, und der Prozessor hängt und tut nichts. Wenn sich die Daten nicht im RAM befinden, kann der Zugriff auf Daten auf einer SSD Zehntausende von Zyklen dauern. Ohne Caches kamen unsere Prozessoren zum Stillstand.

Prozessoren haben normalerweise drei Cache-Ebenen. Speicherhierarchie. Der L1-Cache ist der kleinste und schnellste, der L2-Cache in der Mitte und der L3-Cache der größte und langsamste. Über den Caches in der Hierarchie befinden sich kleine Datensätze, in denen während der Berechnung ein einzelner Datenwert gespeichert wird. Diese Datensätze sind in der Reihenfolge ihrer Größe die schnellsten Speichergeräte in Ihrem System. Wenn ein Compiler das übergeordnete Programm in die Kompilierungssprache konvertiert, bestimmt er, wie diese Register am besten verwendet werden können.

Wenn die CPU Daten aus dem Speicher anfordert, prüft sie zunächst, ob diese Daten im L1-Cache gespeichert sind. In diesem Fall kann in wenigen Zyklen schnell auf Daten zugegriffen werden. Wenn es nicht verfügbar ist, überprüft die CPU L2 und sucht dann nach dem L3-Cache. Caches werden normalerweise transparent für den Kernel implementiert. Der Kernel fordert nur einige Daten zu einer bestimmten Speicheradresse an und antwortet auf jeder Ebene in seiner Hierarchie. Größe und Latenz nehmen normalerweise um Größenordnungen zu, wenn wir zu den späteren Phasen der Speicherhierarchie übergehen. Wenn die CPU die gesuchten Daten in keinem der Caches finden kann, wird sie schließlich nur dann in den Hauptspeicher (RAM) verschoben.

In einem typischen Prozessor verfügt jeder Kern über zwei L1-Caches: einen für Daten und einen für Anweisungen. L1-Caches sind insgesamt etwa 100 Kilobyte groß und die Größe kann je nach Chip und Generation variieren. Jede Architektur verfügt normalerweise über einen L2-Cache, einige Architekturen können jedoch von zwei Kernen gemeinsam genutzt werden. L2-Caches sind normalerweise mehrere hundert Kilobyte groß. Schließlich gibt es einen einzelnen L3-Cache, der etwa zehn Megabyte umfasst und von allen Kernen gemeinsam genutzt wird.

Wenn ein Prozessor Code ausführt, werden die Anweisungen und Datenwerte, die er am häufigsten verwendet, zwischengespeichert. Dies beschleunigt die Ausführung erheblich, da der Prozessor nicht ständig für die benötigten Daten in den Hauptspeicher wechseln muss. Wir werden im zweiten und dritten Teil dieser Serie mehr darüber sprechen, wie diese Speichersysteme tatsächlich implementiert sind.

Neben den Caches ist einer der anderen wichtigen Bausteine ​​eines modernen Prozessors korrekt Zweigprädiktor. Verzweigungsanweisungen ähneln "if" -Anweisungen eines Prozessors. Wenn die Bedingung wahr ist, wird eine Reihe von Befehlen ausgeführt, und wenn die Bedingung falsch ist, wird eine Folge von Befehlen ausgeführt. Beispielsweise möchten Sie möglicherweise zwei Zahlen vergleichen. Wenn sie gleich sind, können Sie eine Funktion ausführen, und wenn sie unterschiedlich sind, können Sie eine andere Funktion ausführen. Diese Verzweigungsanweisungen sind sehr häufig und können etwa 20% aller Anweisungen in einem Programm ausmachen.

Oberflächlich betrachtet scheinen diese Verzweigungsanweisungen kein Problem zu sein, aber es kann sehr schwierig sein, einen Prozessor richtig zu machen. Es ist sehr wichtig zu wissen, dass die CPU zu jedem Zeitpunkt zehn oder zwanzig Befehle gleichzeitig ausführen kann welche Anweisungen zur Durchführung. Es kann 5 Schleifen dauern, um festzustellen, ob der aktuelle Befehl ein Zweig ist, und weitere 10 Schleifen, um festzustellen, ob die Bedingung erfüllt ist. Während dieser Zeit hat der Prozessor möglicherweise Dutzende zusätzlicher Anweisungen ausgeführt, ohne zu wissen, ob es sich um korrekte Anweisungen handelt.

Um dieses Problem zu lösen, verwenden alle modernen Hochleistungsprozessoren eine Technik namens Spekulation. Dies bedeutet, dass der Prozessor den Verzweigungsanweisungen folgt und vorhersagt, ob die Verzweigung erfasst wird oder nicht. Wenn die Vermutung richtig ist, hat der Prozessor begonnen, nachfolgende Anweisungen auszuführen, was zu einem Leistungsgewinn führt. Wenn die Vermutung falsch ist, stoppt der Prozessor die Ausführung, entfernt alle falschen Anweisungen, die er ausgeführt hat, und startet am richtigen Punkt.

Diese Zweigprädiktoren sind einige der frühesten Formen des maschinistischen Lernens, da der Prognostiker das Verhalten von Zweigen allmählich lernt. Wenn er zu viel falsch vermutet, lernt er das richtige Verhalten. Jahrzehntelange Forschungen zu Verzweigungsvorhersagetechniken haben bei modernen Prozessoren zu einer Genauigkeit von mehr als 90% geführt.

Spekulationen bieten zwar enorme Leistungssteigerungen, decken jedoch auch Schwachstellen auf, obwohl der Prozessor vorgefertigte Anweisungen ausführen kann, anstatt auf ausgelastete Anweisungen zu warten. Der berühmte Spectre-Angriff nutzt Fehler bei der Vorhersage und Spekulation von Zweigen aus. Der Angreifer verwendet speziell gestalteten Code, um den Prozessor zu zwingen, spekulativ Code auszuführen, der Speicherwerte verliert. Einige Aspekte der Spekulation mussten neu gestaltet werden, um sicherzustellen, dass die Daten nicht verloren gehen konnten, was zu einem leichten Leistungsabfall führte.

Die in modernen Prozessoren verwendete Architektur hat in den letzten Jahrzehnten einen langen Weg zurückgelegt. Innovationen und intelligentes Design haben zu mehr Leistung und einer besseren Nutzung der zugrunde liegenden Hardware geführt. CPU-Hersteller sind streng geheim über die Technologien in ihren Prozessoren, daher ist es unmöglich, genau zu wissen, was im Inneren vor sich geht. Die Grundlagen der Funktionsweise von Computern sind jedoch auf allen Prozessoren standardisiert. Intel kann seine versteckte Sauce hinzufügen, um die Cache-Trefferquote zu erhöhen, oder AMD kann einen erweiterten Zweigschätzer hinzufügen, aber beide erledigen dieselbe Aufgabe.

Dieser erste Blick und diese Übersicht deckten die meisten Grundlagen der Funktionsweise von Prozessoren ab. Im nächsten Abschnitt werden wir erläutern, wie die Komponenten, die in die CPU gelangen, aufgebaut sind. Dazu gehören Logikgatter, Takt, Energieverwaltung, Schaltpläne und mehr. Beobachten Sie uns weiter.

Empfohlene Lektüre:

Masthead Kredit: Nahaufnahme der elektronischen Leiterplatte von Raimuda