Ich wusste nicht, wie Prozessoren funktionieren, also schrieb ich einen Software-Simulator


Vor einigen Monaten war ich plötzlich von dem Gedanken beeindruckt, dass ich keine Ahnung von den Prinzipien der Computerhardware hatte. Ich weiß immer noch nicht, wie moderne Computer funktionieren.

Ich las das Buch "Aber woher weiß er das?" Clark Scott mit einer detaillierten Beschreibung eines einfachen 8-Bit-Computers: Beginnend mit Logikgattern, RAM, Prozessortransistoren, endend mit einem arithmetisch-logischen Gerät und Eingabe-Ausgabe-Operationen. Und ich wollte das alles in Code implementieren.

Obwohl ich mich nicht so für die Physik von Mikroschaltungen interessiere, gleitet das Buch einfach entlang der Wellen und erklärt auf wundervolle Weise die elektrischen Schaltkreise und wie sich Bits im System bewegen - der Leser muss die Elektrotechnik nicht kennen. Aber Textbeschreibungen reichen mir nicht aus. Ich muss Dinge in Aktion sehen und aus meinen unvermeidlichen Fehlern lernen. Also fing ich an, Schaltkreise in Code zu implementieren. Der Weg war dornig, aber lehrreich.

Das Ergebnis meiner Arbeit finden Sie im Repository für einfache Computer : einen einfachen Taschenrechner. Er ist einfach und er rechnet.






Beispielprogramme

Der Prozessorcode ist als eine schreckliche Reihe von Logikgattern implementiert , die sich ein- und ausschalten , aber es funktioniert. Ich habe die Unit-Tests durchgeführt , und wir alle wissen, dass Unit-Tests ein unwiderlegbarer Beweis dafür sind, dass das Programm funktioniert.

Der Code verarbeitet Tastatureingaben und zeigt den Text auf dem Display mit einem sorgfältig ausgearbeiteten Glyphensatz für eine professionelle Schriftart an, die ich Daniel Code Pro nannte . Der einzige Cheat: Um das Ergebnis über die Tastatur einzugeben und auszugeben, musste ich die Kanäle über GLFW verbinden , aber ansonsten handelt es sich um eine vollständige Software-Simulation des Stromkreises.

Ich habe sogar einen unhöflichen Assembler geschrieben , der mir, gelinde gesagt, die Augen für viele Dinge geöffnet hat. Er ist nicht perfekt. In der Tat sogar ein bisschen beschissen, aber er zeigte mir Probleme, die andere Leute schon vor vielen, vielen Jahren gelöst hatten.

Aber warum machst du das?


„Dreizehnjährige bauen in Minecraft Prozessoren. Rufen Sie mich an, wenn Sie aus Telegraphenrelais eine echte CPU machen können. “

Mein mentales Modell des CPU-Geräts steckt auf der Ebene der Informatiklehrbücher für Anfänger fest. Der Prozessor für den Gameboy-Emulator, den ich 2013 geschrieben habe, sieht eigentlich nicht wie moderne CPUs aus. Selbst wenn der Emulator nur eine Zustandsmaschine (Zustandsmaschine) ist, beschreibt er den Zustand auf der Ebene der Logikgatter nicht. Fast alles kann nur mit der switch und unter Beibehaltung des Status der Register implementiert werden.

Ich möchte besser verstehen, wie alles funktioniert, da ich beispielsweise nicht weiß, wie der L1 / L2-Cache und das Pipelining aussehen, und ich bin mir nicht ganz sicher, ob ich die Artikel über die Sicherheitslücken Meltdown und Spectre verstehe. Jemand sagte, dass sie den Code so optimieren, dass er den Prozessor-Cache verwendet, aber ich weiß nicht, wie ich ihn überprüfen soll, außer um ein Wort zu nehmen. Ich bin mir nicht ganz sicher, was alle x86-Anweisungen bedeuten. Ich verstehe nicht, wie Leute Aufgaben an GPUs oder TPUs senden. Und was ist TPU im Allgemeinen? Ich weiß nicht, wie ich SIMD-Anweisungen verwenden soll.

All dies basiert auf einer Grundlage, die zuerst gelernt werden muss. Es bedeutet, zu den Grundlagen zurückzukehren und etwas Einfaches zu tun. Clark Scotts vorgenanntes Buch beschreibt einen einfachen Computer. Deshalb habe ich damit angefangen.

Ehre sei Scott! Es funktioniert!


Scotts Computer ist ein 8-Bit-Prozessor, der mit 256 Byte RAM verbunden ist und über einen 8-Bit-Systembus verbunden ist. Es verfügt über 4 Universalregister und 17 Maschinenanweisungen . Jemand hat einen visuellen Simulator für das Web erstellt : Es ist wirklich großartig. Es ist beängstigend zu denken, wie lange es gedauert hat, alle Zustände der Rennstrecke zu verfolgen!


Schaltung mit allen Komponenten des Scott-Prozessors. Copyright 2009-2016. Siegbert Filbinger und John Clark Scott

Das Buch begleitet Sie auf dem Weg von bescheidenen Logikgattern zu Bits im Speicher und in den Registern und überlagert dann die Komponenten, bis Sie etwas Ähnliches wie im obigen Diagramm erhalten. Ich empfehle dringend, das Buch zu lesen, auch wenn Sie bereits mit den Konzepten vertraut sind. Nur nicht die Kindle-Version, da es manchmal schwierig ist, Diagramme zu vergrößern und den „Leser“ auf dem Bildschirm zu zerlegen. Meiner Meinung nach ist dies ein langjähriges Kindle-Problem.

Mein Computer unterscheidet sich von der Scott-Version mit der Ausnahme, dass ich ihn auf 16 Bit aktualisiert habe, um den verfügbaren Speicher zu erhöhen, da das Speichern nur von Glyphen für die ASCII-Tabelle den größten Teil der 8-Bit-Maschine von Scott beansprucht und nur sehr wenig Platz für nützlichen Code lässt.

Mein Entwicklungsprozess


Im Allgemeinen verlief die Entwicklung nach diesem Schema: Text lesen, Diagramme studieren und dann versuchen, sie in einer universellen Programmiersprache zu implementieren, und definitiv keine speziellen Werkzeuge zum Entwerfen integrierter Schaltkreise verwenden. Ich habe den Simulator auf Go geschrieben, nur weil ich mit dieser Sprache ein wenig vertraut bin. Skeptiker können sagen: "Dumm! Könnten Sie nicht VHDL oder Verilog oder LogSim oder etwas anderes lernen ? Aber zu diesem Zeitpunkt hatte ich bereits meine Bits, Bytes und Logikgatter geschrieben und war zu tief gestürzt. Vielleicht werde ich das nächste Mal diese Sprachen lernen und verstehen, wie viel Zeit ich verschwendet habe, aber das sind meine Probleme.

In einer großen Schaltung werden eine Reihe von Booleschen Werten einfach im Computer übertragen, sodass jede Sprache geeignet ist, die mit der Booleschen Algebra vertraut ist.

Das Anwenden eines Schemas auf diese Booleschen Werte hilft uns (Programmierern), die Bedeutung abzuleiten und vor allem zu entscheiden, welche Reihenfolge der Bytes das System verwendet, und sicherzustellen, dass alle Komponenten Daten auf dem Bus in der richtigen Reihenfolge übertragen.

Es war sehr schwer umzusetzen. Aus Gründen der Verzerrung habe ich eine Darstellung mit umgekehrter Bytereihenfolge gewählt, aber beim Testen von ALU konnte ich nicht verstehen, warum die falschen Zahlen herauskamen. Meine Katze hörte viel, viele nicht druckbare Ausdrücke.

Die Entwicklung verlief nicht schnell: Vielleicht dauerte es ein oder zwei Monate meiner Freizeit. Aber wenn nur der Prozessor den Vorgang erfolgreich abgeschlossen hat 2+2=5Ich war im siebten Himmel mit Glück.

Alles lief wie gewohnt, bis es zu I / O kam. Das Buch schlug ein Systemdesign mit einer einfachen Tastatur und einer Anzeigeschnittstelle vor, um Daten in die Maschine einzugeben und das Ergebnis auszugeben. Nun, wir sind schon so weit gegangen , es macht keinen Sinn, auf halbem Weg anzuhalten. Ich habe mir zum Ziel gesetzt, das Tippen auf der Tastatur und das Anzeigen von Buchstaben auf dem Display zu implementieren.

Peripheriegeräte


Peripheriegeräte verwenden eine Adaptervorlage als Hardwareschnittstelle zwischen der CPU und der Außenwelt. Es ist wahrscheinlich leicht zu erraten, dass diese Vorlage aus dem Software-Design stammt.


Wie E / A-Adapter mit dem GLFW-Fenster verbunden werden

Mit dieser Trennung stellte sich heraus, dass es recht einfach war, die Tastatur und das Display mit einem Fenster zu verbinden, in dem GLFW ausgeführt wird. Tatsächlich habe ich nur den größten Teil des Codes aus meinem Emulator gezogen und ein wenig geändert, damit die Go-Kanäle als E / A-Signale funktionieren.

Wir starten den Computer




Dies ist wahrscheinlich der schwierigste Teil, zumindest der umständlichste. Es ist schwierig, in Assembler mit solch einem begrenzten Satz von Anweisungen zu schreiben, und in meinem groben Assembler ist es noch schlimmer, weil Sie nur sich selbst täuschen können.

Das größte Problem bestand darin, mit vier Registern zu jonglieren, sie zu verfolgen, indem Daten aus den Registern abgerufen und vorübergehend im Speicher gespeichert wurden. Dabei fiel mir ein, dass der Gameboy-Prozessor ein Stapelzeigerregister zum bequemen Laden und Laden von Registern hat. Leider hat dieser Computer keinen solchen Luxus, so dass Sie ständig manuell Daten in den und aus dem Speicher übertragen mussten.

Ich beschloss, Zeit mit nur einer CALL Pseudoanweisung zu verbringen, um eine Funktion aufzurufen und dann zum Punkt zurückzukehren. Ohne dies sind Anrufe nur eine Ebene tiefer verfügbar.

Da der Computer keine Interrupts unterstützt, musste ich außerdem einen schrecklichen Abrufcode für den Tastaturstatus implementieren. Das Buch beschreibt die Schritte, die zum Implementieren von Interrupts erforderlich sind, dies erschwert jedoch die Schaltung erheblich.

Aber hör auf zu jammern, ich habe immer noch vier Programme geschrieben , und die meisten von ihnen verwenden einen allgemeinen Code zum Rendern von Schriftarten, Tastatureingaben usw. Dies ist kein Betriebssystem, aber es gibt ein Verständnis dafür, was ein einfaches Betriebssystem tut.

Es war nicht einfach. Der schwierigste Teil des Textschreiberprogramms besteht darin, richtig herauszufinden, wann zu einer neuen Zeile gesprungen werden muss oder was passiert, wenn Sie die Eingabetaste drücken.

 main-getInput: CALL ROUTINE-io-pollKeyboard CALL ROUTINE-io-drawFontCharacter JMP main-getInput 
Der Hauptzyklus des Textschreiberprogramms

Ich habe mich nicht darum gekümmert, die Rücktaste und die Modifizierertasten zu implementieren. Aber mir wurde klar, wie viel Arbeit die Entwicklung von Texteditoren erfordert und wie mühsam sie ist.

Schlussfolgerungen


Es war ein lustiges und sehr nützliches Projekt für mich. Während der Assembler-Programmierung hätte ich die folgenden Logikgatter fast vergessen. Ich ging in die oberen Abstraktionsebenen.

Obwohl dieser Prozessor sehr einfach und weit von der CPU in meinem Laptop entfernt ist, scheint mir das Projekt viel gelehrt zu haben, insbesondere:

  • Wie sich Bits zwischen allen Komponenten über den Bus bewegen.
  • Wie funktioniert einfache ALU?
  • Wie eine einfache Fetch-Decode-Execute-Schleife aussieht.
  • Dass eine Maschine ohne Stapelzeigerregister und Stapelkonzept - scheiße ist.
  • Das Auto ohne Unterbrechungen ist auch scheiße.
  • Was ist Assembler und was macht es?
  • Wie Peripheriegeräte mit einem einfachen Prozessor interagieren.
  • Wie einfache Schriftarten funktionieren und wie sie auf dem Display angezeigt werden.
  • Wie ein einfaches Betriebssystem aussehen könnte.

Also, was kommt als nächstes? Das Buch besagt, dass seit 1952 niemand mehr solche Computer hergestellt hat. Das bedeutet, dass ich das Material der letzten 67 Jahre studieren muss. Es wird eine Weile dauern. Ich kann sehen, dass das x86-Handbuch 4.800 Seiten lang genug ist, um vor dem Schlafengehen angenehm und einfach zu lesen.

Vielleicht werde ich ein wenig mit dem Betriebssystem, der C-Sprache, verwöhnt, ich werde den Abend mit dem PiDP-11-Baukasten und einem Lötkolben beenden und dann dieses Ding aufgeben. Ich weiß nicht, wir werden sehen.

Im Ernst, ich denke darüber nach, die RISC-Architektur zu untersuchen, möglicherweise RISC-V. Es ist wahrscheinlich am besten, mit frühen RISC-Prozessoren zu beginnen, um deren Herkunft zu verstehen. Moderne Prozessoren haben viel mehr Funktionen: Caches und mehr, ich möchte sie verstehen. Es gibt viel zu lernen.

Wird dieses Wissen in meinem Hauptberuf nützlich sein? Vielleicht nützlich, wenn auch unwahrscheinlich. Auf jeden Fall gefällt es mir, also spielt es keine Rolle. Danke fürs Lesen!

Source: https://habr.com/ru/post/de453158/


All Articles