80386-Mikrocode disassembliert
(reenigne.org)- Das 80386-Mikrocode-ROM umfasst 94.720 Bit und ist damit deutlich größer als die 10.752 Bit des 8086, wodurch Bildumwandlung und Verifikation wesentlich schwieriger waren
- Aus hochauflösenden Die-Bildern wurden durch die Kombination aus Bildverarbeitung, neuronalen Netzen und menschenunterstützter Automatisierung innerhalb weniger Tage binäre Blobs extrahiert und gegengeprüft
- Im Verlauf der Disassemblierung wurden nach und nach das μ-op-Array, Bit-Felder, Muster zum Befehlsende sowie die Struktur von Befehlsdecoder und Protection-Test-PLA sichtbar
- Der 80386 besitzt für alle Befehle passenden Mikrocode; viele Routinen dienen weniger dem Algorithmus selbst als der Konfiguration von Multiplikations-/Divisions-Hardware und Barrel Shifter
- Bei der Verarbeitung der IO-Berechtigungsbitmap im Protected Mode wurde ein möglicher Fehler entdeckt: Bei 4-Byte-Portzugriffen scheinen nur die ersten drei Adressen geprüft zu werden, bestätigt ist das aber noch nicht
Extraktion und Disassemblierung des 80386-Mikrocodes
- Nach 8086 microcode disassembled stellte Ken Shirriff hochauflösende Bilder des Mikrocode-ROMs des 80386 bereit, aber das 80386-ROM ist mit 94.720 Bit viel größer als das des 8086 mit 10.752 Bit, wodurch Umwandlung und Verifikation deutlich schwieriger wurden
- Für den 8086 gab es ein Patent mit der Gesamtstruktur und einigen Codefragmenten, also Anhaltspunkte für die Suche; beim 80386 handelte es sich dagegen fast um eine vollständige Blackbox, sodass es schwierig war, in einem großen Binärblock Struktur zu finden
- Auf Discord führten GloriousCow, Smartest Blob und andere die Arbeit fort, aus hochauflösenden Bildern des 80386-Die den Mikrocode zu extrahieren; die zentrale Hürde war die Umwandlung von Bild → Binärdaten → verständlichem Mikrocode
- Durch die Kombination aus Bildverarbeitung, neuronalen Netzen und menschenunterstützter Automatisierung wurden innerhalb weniger Tage binäre Blobs aus den Bildern extrahiert und gegengeprüft
Strukturen, die beim Disassemblieren sichtbar wurden
- Auch nach der Binärextraktion war die Disassemblierung nicht einfach; durch das Abgleichen verschiedener Muster wurde herausgefunden, wie die Daten so umzuordnen sind, dass auf einer Achse die μ-ops und auf der anderen die μ-op-Bits liegen
- Nicht verwendete μ-op-Blöcke an einem Ende lieferten einen Hinweis auf die Lesereihenfolge der μ-ops
- Beim Aufteilen der μ-op-Bits in mehrere Felder half die Erfahrung aus der Arbeit am 8086-Mikrocode dabei, Felder für Quell- und Zielregister zu identifizieren
- Da der 80386 ALU-Operationen in 2 Zyklen ausführen kann, war ein Feld nötig, das den zweiten Eingang der ALU angibt, damit im ersten Zyklus beide Operanden in die ALU geladen und im zweiten Zyklus das Ergebnis an das Ziel gesendet werden kann
- Wiederkehrende Muster wurden als Markierungen für das Ende eines Befehls vermutet und später als korrekt bestätigt
- Ken trug dazu bei, interne Verschaltungen nachzuvollziehen, indem er verschiedene Leitungen und Logikbits im 80386-Die verfolgte; neu aufgedeckte Strukturen wurden wiederum zu Hinweisen für die Interpretation anderer Mikrocodefragmente mit denselben Bausteinen
- Zusammen mit dem Mikrocode wurden auch der aus mehreren kleinen PLAs bestehende Befehlsdecoder und die Protection-Test-PLA entschlüsselt, wodurch sich 386-Befehle mit Mikrocodefragmenten verknüpfen ließen
Die vom 8086 abweichende Ausführungsweise des 80386
- Der 80386 ist bei den meisten Befehlen pro Zyklus deutlich schneller als der 8086 und verwendet dafür mehr Transistoren
- Mehrere Algorithmen, die beim 8086 noch in Mikrocode implementiert waren, werden beim 80386 praktisch von Hardware-Beschleunigern übernommen
- Ein erheblicher Teil des 80386-Mikrocodes dient weniger dem Algorithmus selbst als der Konfiguration von Beschleunigern wie Multiplikations-/Divisions-Hardware, Barrel Shifter und Protection-Test-Einheit
- Ein großer Teil der Disassemblierungsarbeit bestand darin, zu verstehen, wie diese Beschleuniger-Schnittstellen mit dem Mikrocode verbunden sind
Mikrocode-Einstiegspunkte und Befehlsverarbeitung
- Es gibt 215 Einstiegspunkte in den Mikrocode aus dem Decoding-ROM, deutlich mehr als die 60 des 8086
- Die höhere Zahl liegt nicht nur an neuen Befehlen, sondern auch daran, dass derselbe Befehl je nach Operandenart Register oder Speicher, CPU-Modus Real Mode oder Protected Mode und Nutzung eines REP-Präfixes von unterschiedlichen Routinen verarbeitet wird
- Die vollständige Liste aller Einstiegspunkte steht in der Datei
fields.txt; enthalten sind außerdem Subroutinen und gemeinsam genutzter Code - Viele Mikrocode-Routinen auf oberster Ebene erledigen nur wenig Arbeit und springen dann in Routinen, die mit anderen Einstiegspunkten geteilt werden, sodass sich ihre Bedeutung nicht allein aus ihrer Größe ableiten lässt
- Da der Befehlsdecoder bei der Wahl der zu verwendenden Routine nicht nur den Opcode heranzieht, lässt sich die Struktur auch nicht einfach über die Anzahl der von einem Einstiegspunkt verarbeiteten Opcodes beschreiben
Alle Befehle werden per Mikrocode verarbeitet
- Anders als der 8086 oder moderne CPUs führt der 80386 immer μ-ops aus, und für jeden Befehl existiert entsprechender Mikrocode
- Es wurde bestätigt, dass es keine Befehle gibt, die nicht per Mikrocode verarbeitet werden
Nicht verwendeter Code und Spuren der Ausnahmebehandlung
- Die Routinen von
0x849bis0x856sind in der Mikrocode-Disassemblierung alsunused?markiert und scheinen keine verknüpften Einstiegspunkte zu haben - Ihre genaue Funktion ist nicht vollständig gesichert, sie weisen jedoch viele Gemeinsamkeiten mit den
#PF-(PAGE_FAULT-)Routinen von0x8e9bis0x8f5auf - Beide Routinen setzen zunächst den letzten Fehlercode der Paging Unit und führen dann zu interrupt 0x0e weiter
- Der Unterschied besteht darin, dass diese Routinen
CR2nicht mit der fehlerhaften linearen Adresse, sondern mit einem unbekannten Wert aus der Paging Unit setzen - Der übrige Mikrocode scheint für die Implementierung des dokumentierten CPU-Verhaltens ausgelegt zu sein; Routinen, die mit der ICE-(In-Circuit-Emulator-)Hardware für Low-Level-Debugging interagieren, entsprechen undokumentiertem Verhalten
Versteckte Funktionen und möglicher Fehler in der IO-Berechtigungsbitmap
- Es lässt sich noch nicht sicher bestätigen, weil es noch nicht auf echter 386-Hardware getestet wurde, aber in der Verarbeitung der IO-Berechtigungsbitmap, die einige Protected-Mode-Betriebssysteme nutzten, um User-Mode-Prozessen eingeschränkten Zugriff auf IO-Ports zu erlauben, könnte ein Fehler stecken
- Bei einem 4-Byte-Portzugriff scheint der Mikrocode nur die Berechtigungsbits der ersten drei Adressen zu prüfen
- Führt ein Prozess einen solchen Zugriff an der Grenze eines erlaubten IO-Port-Bereichs aus, könnte der Zugriff auf das letzte Byte fälschlich erfolgreich sein und so Hardware-Register erreichen, die das Betriebssystem für Benutzerzugriffe nicht vorgesehen hat
- Dieser Bug wäre ein sehr spezieller Sonderfall und hätte ohne die Mikrocode-Disassemblierung leicht unentdeckt bleiben können; bemerkenswert wäre allerdings, dass ein Sicherheitsfehler in einer seit über 40 Jahren weit verbreiteten Hardware bisher nicht entdeckt worden wäre
- Es ist auch möglich, dass dieses Verhalten nur in bestimmten CPU-Versionen existierte oder dass die Interpretation der Routine falsch ist und die Hardware tatsächlich korrekt arbeitet
- Dieser Mikrocode scheint nicht von einer frühen Version des 80386 zu stammen; von den Befehlen
XBTSundIBTSgibt es außer im Decoder keine Spuren
Lernmaterial und Download-Orte
- Der Artikel zur internen Struktur des 80386 von nand2mario ist ein nützlicher Ausgangspunkt, um die Disassemblierung zu verstehen
- 80386 Multiplication and Division
- 80386 Barrel shifter
- 80386 Protection
- 80386 Memory Pipeline
- Die Disassemblierungsergebnisse können aus dem x86 microcode repository auf GitHub heruntergeladen werden
parts.txterklärt die Rolle der anderen Dateien, undmicrocode_10.txtist die Datei, die direkt die Mikrocode-Disassemblierung selbst enthält
1 Kommentare
Hacker-News-Kommentare
Ich frage mich, wie man aus hochauflösenden Die-Bildern den Mikrocode rekonstruieren kann.
Mich würde auch interessieren, ob der Prozess darin besteht, jeden Transistor zu identifizieren und die Schaltung zu modellieren, und ob das Ergebnis in einer Form wie Verilog vorliegt.
Danach wurden 0 und 1 klassifiziert; eine 1 ließ sich visuell durch das Vorhandensein eines Transistors und eine Lücke im Polysilizium erkennen.
Aufgrund der Eigenschaften von Intel-Mikrocode konnte man annehmen, dass es deutlich mehr 0en als 1en gibt, also wurde das Vorhandensein eines Transistors als 1 gewertet.
Es gibt zwar Tools, die das mit Farbschwellen automatisch verarbeiten, aber Teile des Mosaiks waren unscharf und Staub verursachte viele falsche 1-Bits, sodass das nicht gut funktionierte.
Stattdessen wurde ein Convolutional Neural Network darauf trainiert, extrahierte Bitbereiche als 0/1 zu klassifizieren, und das Ergebnis wurde zur Kontrolle mit weißen/schwarzen Rechtecken mit 50 % Transparenz über das ursprüngliche Mosaik gelegt.
Danach wurden mehrere Tage lang mühsam Fehler überprüft, und am Ende erhielten wir ein rohes zweidimensionales Bit-Array; der nächste Schritt besteht darin, daraus Mikrocode-Wörter zu extrahieren.
https://youtu.be/HwEdqAb2l50?si=VFLed64PZvpCHfy1
„Das Foto oben zeigt einen Teil des Mikrocode-ROMs. Unter dem Mikroskop ist der Inhalt des Mikrocode-ROMs sichtbar, und man kann die Bits auslesen, je nachdem, ob sich an jeder Position ein Transistor befindet oder nicht.“
https://www.righto.com/2020/06/a-look-at-die-of-8086-process...
Verwandter laufender Thread: z386: An Open-Source 80386 Built Around Original Microcode - https://news.ycombinator.com/item?id=48248014 - Mai 2026, 22 Kommentare
Als ich vor ein paar Tagen den reenigne-Blog geprüft habe, dachte ich noch: „Hm, seit 2020 gibt es keine neuen Beiträge.“ Umso schöner, dass er wieder aktiv ist.
Besonders interessant ist auch, dass der Blog 33 Jahre zurückreicht.
Ein gutes Buch, das Mikroprogrammierung von Grund auf erklärt: https://www.amazon.com/Computation-Structures-Optical-Electr...
Ein kostenloses PDF lässt sich auch leicht finden.
Der Aufwand, der nötig ist, um diesen Mikrocode zu reverse-engineeren, ist beeindruckend, und es ist ein großartiger Artikel, der tief in die 386-Architektur eintaucht.
Wenn man sich eine tatsächliche Mikrocode-Implementierung ansieht, wirkt es weniger mysteriös, wie alte Prozessoren komplexe Operationen verarbeitet haben.
Beim 386 gab es über die 22-jährige Produktionszeit viele kleine Änderungen, daher ist es wichtig zu wissen, aus welcher 386-Revision dieser Code stammt.
9B5 BIST1 -> TMPD 0x0303 PASS29B6 SIGMA -> EDX9B7 BIST2 -> TMPE TMPD XOR9B8 SIGMA 0x3ddc0c2c XOR9B9 SIGMA -> EAX BOOTUP_JUMP JFPUOK0x303bedeutet Familie 3, Modell 0, Stepping-ID 3.Die dafür nötige Blackbox-Analyse ist enorm schwierig, aber wenn man Erfolg hat, dürfte das unglaublich spannend und lohnend sein.
Es fühlt sich befriedigend an, dass ich an der Uni schwierige Fächer belegt habe, um solche Artikel verstehen zu können, und auch, dass HN mich damals 2015 zu solcher Denkweise angeregt hat.
Auch wenn ich Low-Level-Programmierwissen heute kaum noch nutze, habe ich bei jedem solchen Artikel das Gefühl, dass mein Bewusstsein reicher wird, was großartig ist.
Für Menschen, die keinen guten Zugang zur Hochschule haben, empfehle ich nand2tetris.org.
Es hilft auch, einfache ältere Entwürfe wie RISC oder den Transputer zu studieren; der 80386 liegt am entgegengesetzten Ende dieses Spektrums.
Er ist unnötig komplex geworden, weil alte schlechte Designs und Abwärtskompatibilität mitgeschleppt wurden.
Um Chipdesign zu lernen, braucht man nicht zwingend eine Universität; ein paar Vorträge von Alan Kay oder ein Blick in Computerdesign-Unterlagen auf Bitsavers sind ebenfalls gute Einstiege.
Ich habe Morphle Logic entwickelt, womit sich Gate-Level-Designs einfacher als mit FPGA simulieren und Stand 2026 für unter 200 Dollar in Transistoren auf einem Chip umsetzen lassen.
Das könnte letztlich zu größeren, schnelleren und günstigeren integrierten Wafer-Scale-Supercomputern führen.
https://github.com/fiberhood/MorphleLogic/blob/main/README_M...
https://www.youtube.com/watch?v=vbqKClBwFwI
https://www.youtube.com/watch?v=f1605Zmwek8
http://bitsavers.informatik.uni-stuttgart.de/pdf/xerox/alto/...
Diese Einfachheit selbst ist eine hervorragende Lektion und sehr inspirierend, aber die Elektrotechnikvorlesungen, die ich in den 1990ern an der Uni hatte, behandelten ähnlich wie nand2tetris, wie CPUs der 8086-Klasse aufgebaut werden, erklärten aber zusätzlich, wie Mikrocode funktioniert.
Ein interner Programmzähler lief dort eine Tabelle von Steuerwörtern entlang, und jedes Bit koordinierte direkt einen steuerbaren Teil der CPU.
In unseren Simulatoren implementierte jede Person einen Befehl; ich hatte DEC, also den Dekrement-Befehl.
In gewisser Weise könnte man die Instruktionen von nand2tetris auch als Mikrocode sehen.
Die Befehlsbits steuern die Hardware direkt, und das erste Bit wählt zwischen zwei Befehlstypen, daher gibt es nur einen Codeschritt pro Befehl.
Mikrocode dagegen erlaubt, dass ein Befehl aus einer beliebigen Anzahl von Mikrocode-Schritten besteht.
In Ben Eaters Videos zu seiner 8-Bit-CPU auf dem Breadboard werden das 4-Bit-Opcode der Instruktion und ein Schrittzähler verwendet, um ein ROM zu indizieren, das daraus das Steuerwort bestimmt.
Dieses ROM ersetzt einen Teil, der auch aus hinreichend komplexen Logikgattern aufgebaut werden könnte, und weil man die Elektronik direkt anfassen und Probleme lösen muss, ist das ein guter nächster Schritt in Richtung Hardware.
Schade ist nur, dass es dort nur 16 Byte RAM gibt, sodass sich wie bei nand2tetris schwerer höhere Abstraktionsebenen aufbauen lassen.
An diesem Punkt kann man entweder mit einem besseren Design neu anfangen, auf eine PCB wechseln oder zu einem 6502-Projekt übergehen und dann Timer, CPU, ROM, RAM, I/O, UART usw. als zusammenhängendes System betrachten, bevor man schließlich zu Mikrocontrollern übergeht, in denen all das bereits integriert ist.
Wenn man lesen möchte, wie man eine CPU aus Logikgattern baut: Charles Petzolds Code erklärt es langsam und wurde vor Kurzem überarbeitet, während Danny Hillis’ The Pattern on the Stone schneller vorangeht.
Die 2. Auflage von Code verwendet einen 4-Bit-Zykluszähler und fest verdrahtete Logikgatter, um das Verhalten jedes Zyklus zu bestimmen, und setzt für einen Teil der Logik Dioden-Arrays ein; ich frage mich, ob man das auch als Mikrocode ansehen sollte.