Die kurze Antwort
Die Schritte zum Decodieren und Ausführen des Befehls werden parallel zum nächsten Schritt des vorherigen Befehls ausgeführt. Diese Technik wird als Pipelining bezeichnet. Siehe Auf RISC-Prozessoren weiter unten.
Eine RISC-Architektur mit einem einzigen Problem weist aufgrund der Wartezustände und der Zeit, die für Lade- / Speicheroperationen benötigt werden, die auf den Speicher treffen, im Durchschnitt etwas weniger als einen Befehl pro Zyklus auf, als nur registriert zu werden. Delay Slots geben Ihnen einen architektonischen Haken, mit dem Sie einen Teil dieser Zeit zurückbekommen können. Siehe Auf RISC-Prozessoren weiter unten.
Ein Befehlszyklus ist die Zeitdauer, die zum Ausführen eines Befehls benötigt wird. Dies hängt von der Architektur und (in einigen Fällen) von den Anweisungen ab. Zum Beispiel dauern die meisten Anweisungen auf so etwas wie einem MIPS R2000 / 3000 einen Zyklus. Anweisungen mit Speicherzugriff (Laden / Speichern, Verzweigen) dauern mehr als einen Zyklus, obwohl die Verzögerungsschlitze bedeuten, dass Sie möglicherweise etwas anderes (möglicherweise nur eine NOP) im Verzögerungsschlitz ausführen können. Architekturen ohne Pipeline können Befehlszyklen mit mehreren Taktzyklen aufweisen, die häufig mit dem Adressierungsmodus variieren. Siehe Informationen zu RISC-Prozessoren, traditionellen CISC-Architekturen und festverdrahteten Architekturen weiter unten.
Designs mit mehreren Ausgaben können dieses Konzept etwas verwischen, indem mehr als eine Anweisung parallel ausgeführt wird.
CISC-Prozessoren können Anweisungen haben, die unterschiedlich lange dauern. Die genaue Anzahl der Taktzyklen hängt von der Architektur und den Anweisungen ab. Die unterschiedliche Anzahl von Taktzyklen, die in CISC-ISAs verwendet werden, ist einer der Gründe, warum es schwierig ist, sie in Architekturen mit hoher Pipeline-Auslastung zu integrieren. Siehe traditionelle CISC-Architekturen weiter unten.
Die längere Antwort
Bei einem einzelnen MIPS-, SPARC- oder anderen CPU-Problem werden alle Anweisungen (zur ersten Annäherung) in einem Zyklus ausgegeben, obwohl sie einen sogenannten Verzögerungsschlitz haben können.
Auf RISC-Prozessoren
In diesem Zusammenhang ist eine Single-Issue-CPU eine CPU, in der keine On-the-Fly-Abhängigkeitsanalyse und keine parallele Ausgabe von Anweisungen durchgeführt wird, wie dies bei modernen CPUs der Fall ist, dh, sie haben nur eine Ausführungseinheit, in der die Anweisungen ausgeführt werden die Reihenfolge, in der sie aus dem Memoty gelesen werden. Dazu später mehr.
Bei den meisten älteren RISC-Prozessoren handelt es sich um Single-Issue-Prozessoren, die in eingebetteten Systemen immer noch weit verbreitet sind. Ein 32-Bit-Single-Issue-Integer-RISC-Kern kann in etwa 25.000 bis 30.000 Gattern implementiert werden. Daher weisen CPU-Kerne dieses Typs einen sehr geringen Stromverbrauch und eine sehr geringe Stellfläche auf. Dadurch können sie einfach und kostengünstig in SOC-Produkte (System-on-Chip) integriert werden.
RISC-CPU-Designs werden in Pipelines ausgeführt. Die Verarbeitung des Befehls erfolgt in mehreren Schritten, wobei jeder Befehl in jedem Taktzyklus über die Pipeline zur nächsten Stufe weitergeleitet wird. In den meisten Fällen führt eine Single-Issue-Pipeline-CPU ungefähr einen Befehl pro Taktzyklus aus.
Einige Architekturen verfügen über Anweisungen wie Verzweigen oder Laden / Speichern aus dem Speicher, bei denen der zusätzliche Zyklus, den der Speicherzugriff benötigt, für den Code sichtbar ist.
Beispielsweise wird in einem SPARC V7 / V8- Entwurf der nächste Befehl nach einer Verzweigung tatsächlich ausgeführt, bevor die Verzweigung selbst stattfindet. Normalerweise fügen Sie eine NOP in den Slot nach dem Zweig ein, aber Sie können eine andere Anweisung hinzufügen, wenn Sie etwas Nützliches finden.
Die MIPS R2000 / R3000- Architektur hatte einen ähnlichen Verzögerungsschlitz in den Lade- / Speicheranweisungen. Wenn Sie einen Wert aus dem Speicher geladen haben, wird er für einen weiteren Zyklus nicht im Register angezeigt. Sie könnten eine NOP in den Steckplatz einfügen oder etwas anderes tun, wenn Sie etwas Nützliches finden, das nicht von der gerade ausgegebenen Ladeoperation abhängt.
Wenn der Speicher langsamer als die CPU war, was häufig der Fall war, erhalten Sie möglicherweise zusätzliche Wartezustände bei Speicherzugriffen. Wartezustände frieren die CPU für einen oder mehrere Taktzyklen ein, bis der Speicherzugriff abgeschlossen ist. In der Praxis bedeuten diese Wartezustände und die zusätzliche Zeit für Speicherzugriffe, dass die CPU-Entwürfe mit einer Ausgabe im Durchschnitt etwas weniger als einen Befehl pro Taktzyklus ausführen. Verzögerungsslots bieten Ihnen einige Möglichkeiten, Code zu optimieren, indem Sie während einer Speicheroperation einen anderen Befehl ausführen.
Traditionelle CISC-Prozessoren
CISC-Prozessoren waren Entwürfe, bei denen Anweisungen unterschiedlich lange dauern konnten. Oft waren komplexere Anweisungen direkt in der Hardware implementiert, die in Software auf einer RISC-CPU ausgeführt werden mussten.
Die meisten Mainframe-Architekturen und nahezu alle PC-Designs bis zum M68K und Intel 386 waren herkömmliche CISC-CPUs mit Mikrocodierung. Diese Designs waren pro Takt langsamer und verwendeten mehr Gates als RISC-CPUs.
Microcode
Ein Beispiel für eine mikro Architektur (MOS 6502) kann in Emulation zu sehen hier . Der Mikrocode ist oben im Bild zu sehen.
Der Mikrocode steuert den Datenfluss und die in der CPU aktivierten Aktionen, um Anweisungen auszuführen. Durch Durchlaufen der Schritte im Mikrocode können Sie die Teile einer CPU aktivieren, Daten durch ALUs bewegen oder andere Schritte ausführen. Wiederverwendbare Komponenten in der CPU können über mehrere Taktzyklen koordiniert werden, um einen Befehl auszuführen. Im Falle des 6502 könnten einige Pipeline-Aktionen auch vom Mikrocode ausgeführt werden.
Mikrocodierte Konstruktionen verwendeten weniger Silizium als festverdrahtete Chips, wobei möglicherweise mehrere Taktzyklen erforderlich waren, um einen Befehl zu vervollständigen. Abhängig vom Design würden diese CPUs pro Befehl unterschiedlich viel Zeit in Anspruch nehmen.
Festverdrahtete Architekturen
Festverdrahtete Designs (die sich mit dem Mikrocode nicht unbedingt gegenseitig ausschließen) führen einen Befehl synchron aus oder haben möglicherweise ihre eigenen Koordinatoren, um etwas über mehrere Taktzyklen hinweg zu tun. Sie sind in der Regel schneller auf Kosten dedizierterer Hardware und daher in der Implementierung teurer als ein mikrocodiertes Design mit äquivalenter Funktionalität.
Ein berühmtes Beispiel dafür war die ursprüngliche Amdahl 470/6-CPU , die bei bestimmten IBM System / 370-Modellen als Ersatz für die CPU diente. Die Amdahl-CPU war ein festverdrahtetes Design zu einer Zeit, als die 370-CPUs von IBM stark auf Mikrocode basierten. Die Amdahl-CPU war etwa dreimal schneller als die IBM-CPUs, die sie ersetzten.
Unnötig zu erwähnen, dass IBM nicht amüsiert war und dies zu einem Gerichtsstreit führte, der IBM zwang, ihre Mainframe-Architektur zu öffnen, bis die Einverständniserklärung vor einigen Jahren auslief.
Typischerweise war ein festverdrahteter Entwurf dieses Typs immer noch nicht so schnell wie eine RISC-CPU, da die unterschiedlichen Befehlszeiten und -formate nicht so viel Spielraum für das Pipelining boten wie ein RISC-Entwurf.
Designs mit mehreren Ausgaben
Bei den meisten modernen CPUs handelt es sich um Architekturen mit mehreren Problemen , die mehr als einen Befehl gleichzeitig in einem einzelnen Thread verarbeiten können. Der Chip kann eine dynamische Abhängigkeitsanalyse des eingehenden Befehlsstroms durchführen und Befehle parallel ausgeben, wenn keine Abhängigkeit vom Ergebnis einer vorherigen Berechnung besteht.
Der Durchsatz dieser Chips hängt davon ab, wie viel Parallelität im Code erzielt werden kann, aber die meisten modernen CPUs berechnen auf den meisten Codes mehrere Befehle pro Zyklus.
Moderne Intel- und andere x86 / X64-ISA-CPUs verfügen über eine Schicht, die den CISC-Befehlssatz der alten Schule in Mikrobefehle umwandelt , die über einen RISC-ähnlichen Kern mit mehreren Problemen weitergeleitet werden können. Dies fügt einen zusätzlichen Aufwand hinzu, der auf CPUs mit ISAs, die für das Pipelining ausgelegt sind (z. B. RISC-Architekturen wie ARM oder PowerPC), nicht vorhanden ist.
VLIW entwirft
VLIW-Designs, von denen das Intel Itanium vielleicht das bekannteste ist, haben sich nie als Mainstream-Architekturen etabliert, aber IIRC gibt es eine Reihe von DSP-Architekturen, die diese Art von Design verwenden. Ein VLIW-Entwurf macht Mehrfachausgaben mit einem Anweisungswort explizit, das mehr als eine Anweisung enthält, die parallel ausgegeben wird.
Diese waren abhängig von guten optimierenden Compilern, die Abhängigkeiten und Möglichkeiten für Parallelität identifizierten und Befehle in die mehreren für jedes Befehlswort verfügbaren Slots ablegten.
VLIW-Architekturen eignen sich gut für numerische Anwendungen, da Matrix- / Array-Operationen häufig Möglichkeiten für eine umfassende Parallelität bieten. Der Itanium hatte eine Zeit lang einen Nischenmarkt für Supercomputing-Anwendungen, und es gab mindestens eine Supercomputer-Architektur - den Multiflow TRACE -, der unter Verwendung eines ISA dieses Typs hergestellt wurde.
Speicher und Caching
Moderne CPUs sind viel, viel schneller als Speicher. Daher können direkte Lesevorgänge aus dem Speicher Hunderte von Wartezuständen erzeugen, die die CPU blockieren, bis der Speicherzugriff abgeschlossen ist. Das Caching, das jetzt in mehreren Ebenen ausgeführt wird, enthält die zuletzt verwendeten Speicherorte im Cache. Da CPUs in der Regel die meiste Zeit damit verbringen, Code in Schleifen auszuführen, erhalten Sie gute Trefferquoten bei der Wiederverwendung von Speicherorten, die Sie kürzlich verwendet haben. Diese Eigenschaft wird als Referenzort bezeichnet.
Wo Sie Referenzpunkte erhalten, kann die CPU nahezu mit optimaler Geschwindigkeit arbeiten. Cache-Fehler bis zur nächsten Ebene führen zu einer Reihe von Wartezuständen. Cache-Fehler im Hauptspeicher können Hunderte verursachen.
Somit kann der tatsächliche Durchsatz von CPU-Chips stark von der Effizienz von Speicherzugriffsmustern abhängen. Es wurden ganze Bücher darüber geschrieben, wie man Code dafür optimiert, und es ist ein komplexes Thema für sich.