forked from hacknology/website
Leerzeichen entfernt
parent
5b21cd91c9
commit
1d049b200e
|
@ -1,40 +1,38 @@
|
|||
---
|
||||
|
||||
title: HE32, Rust & "the NAND2TETRIS experience"
|
||||
author: kaqu
|
||||
status: Aktiv
|
||||
difficulty: no
|
||||
time: ~1h
|
||||
date: 2022-08-26
|
||||
date: 2022-08-27
|
||||
image: HE32_Overview.png
|
||||
keywords: NAND2TETRIS, jack, hack
|
||||
keywords: nand2tetris, jack, hack
|
||||
---
|
||||
|
||||
{{< image alt="Showtime" src="HE32_Overview.png" size="1920x1080 q90">}}
|
||||
|
||||
|
||||
## Motivation ##
|
||||
|
||||
Vor einem Vierteljahr habe ich das Buch "The Elements of Computing Systems" (Nisan/Schocken,
|
||||
wichtig: 2.Auflage!) geschenkt bekommen und die ca. 300 Seiten gleich in einem Rutsch durchgelesen.
|
||||
wichtig: 2.Auflage!) geschenkt bekommen und die ca. 300 Seiten gleich in einem Rutsch durchgelesen.
|
||||
Faszinierend, insbesondere wenn ich mich an mein eher rudimentäres Verständnis meines alten
|
||||
Dragon-Books erinnere (dort werden im Wesentlichen die Grundlagen für die Nutzung von
|
||||
lex & yacc gelegt - heute: flex & bison). Ich habe damals nach ca. 3/4 des Buches aufgehört ...
|
||||
Dragon-Books erinnere (dort werden im Wesentlichen die Grundlagen für die Nutzung von
|
||||
lex & yacc gelegt - heute: flex & bison). Ich habe damals nach ca. 3/4 des Buches aufgehört ...
|
||||
|
||||
<div class="pure-g">
|
||||
{{<image alt="Cover1" src="BookCover.jpg" size="400x240 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{<image alt="Cover2" src="BookCoverOld.jpg" size="400x240 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Cover1" src="BookCover.jpg" size="400x240 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Cover2" src="BookCoverOld.jpg" size="400x240 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
</div>
|
||||
|
||||
Das neuere Buch ist ursprünglich aus dem - in der angelsächsischen Welt - recht bekannten
|
||||
"Nand-to-Tetris"-Kurs entstanden.
|
||||
"Nand-to-Tetris"-Kurs entstanden.
|
||||
Weitere Infos & Unterlagen können auf der zugehörigen [Website](https://www.nand2tetris.org/) abgerufen werden.
|
||||
|
||||
|
||||
## 1. Der Kurs ##
|
||||
|
||||
Inhaltlich geht es in 12 Kapiteln vom NAND-Gatter bis zur einfachen 'Betriebssystem'-Erstellung
|
||||
(die auf der [Website](https://www.nand2tetris.org/course) unter 'Projects' abgerufen werden).
|
||||
|
||||
- Die ersten fünf Kapitel befassen sich mit dem Aufbau einer 'eigenen' CPU, Speicherelementen
|
||||
etc. aus einfachsten NAND-Gattern und deren Zusammenschaltung zum 'Hack'-Computer!
|
||||
- Kapitel 6 behandelt die Erstellung eines passenden Assemblers,
|
||||
|
@ -48,44 +46,44 @@ es hier eigentlich um eine Kombination von BIOS & Standard-Library geht.
|
|||
Das Geniale: Der Schwierigkeitsgrad bleibt immer akzeptabel, gerade für das Selbststudium!
|
||||
Man merkt an vielen Stellen, wie die Rückfragen der Studenten im Laufe der Jahre in den Text
|
||||
zurückgeflossen sind. Praktisch alle Problemstellen (für das Verständnis) werden sehr
|
||||
detailliert erläutert.
|
||||
detailliert erläutert.
|
||||
Technisch werden im Software-Teil ab Kapitel 6 immer recht enge API-Vorgaben gemacht,
|
||||
jedoch ist man frei in der Wahl der Programmiersprache zur Realisierung (*ich habe meine Lösung zeitsparend
|
||||
in Python erstellt - natürlich hier nicht veröffentlicht, schließlich soll sich jeder seine
|
||||
Lösung selbst erarbeiten!*).
|
||||
Lösung selbst erarbeiten!*).
|
||||
Mitgeliefert werden alle notwendigen Emulatoren und Hilfsmittel um die Ergebnisse mit den korrekten
|
||||
Lösungen automatisiert zu vergleichen (auf der [Website](https://www.nand2tetris.org/software) unter 'Software').
|
||||
|
||||
Ich habe zwei Monate für den ganzen Kurs gebraucht. Für die ersten 10 Kapitel einen Monat, für die
|
||||
restlichen zwei noch einmal einen ganzen Monat (der Schwierigkeitsgrad steigt zwar kaum an, jedoch
|
||||
baut sich immer mehr Wissen auf, d.h. die Komplexität nimmt zu).
|
||||
baut sich immer mehr Wissen auf, d.h. die Komplexität nimmt zu).
|
||||
|
||||
Meine Empfehlung: Pädagogisch wertvoll!
|
||||
|
||||
|
||||
## 2. Ausführung ##
|
||||
|
||||
### 2.1 Hardware & Assembler ##
|
||||
Zunächst wird im Hardware-Teil eine [ISA](https://de.wikipedia.org/wiki/Befehlssatzarchitektur) definiert,
|
||||
|
||||
Zunächst wird im Hardware-Teil eine [ISA](https://de.wikipedia.org/wiki/Befehlssatzarchitektur) definiert,
|
||||
d.h. man 'baut' analog zu einer echten CPU eine Theoretische, die 'Hack'-CPU mit dem 'Hack'-Befehlssatz
|
||||
(in einer Kurs-spezifischen [HDL](https://de.wikipedia.org/wiki/Hardwarebeschreibungssprache)). Diese wird
|
||||
im beigestellten Simulator mittels Testscript verifiziert.
|
||||
Das sieht dann ungefähr so aus:
|
||||
|
||||
<div class="pure-g">
|
||||
{{<image alt="HDL Code Sample" src="hdl_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{<image alt="HDL Simulator" src="hdl_simulator.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="HDL Code Sample" src="hdl_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="HDL Simulator" src="hdl_simulator.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
</div>
|
||||
|
||||
Das IS sieht wie folgt aus:
|
||||
|
||||
{{<image alt="IS Overview" src="hack_is.png" size="1024x640 q90">}}
|
||||
{{< image alt="IS Overview" src="hack_is.png" size="1024x640 q90">}}
|
||||
|
||||
Hierfür ist ein Assembler zu erstellen, der als Output 16-Bit Code (als 'Binär-Text') generiert, z.Bsp. wie folgt:
|
||||
|
||||
<div class="pure-g">
|
||||
{{<image alt="Assembly Sample" src="asm_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{<image alt="Machine Code Sample" src="machine_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Assembly Sample" src="asm_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Machine Code Sample" src="machine_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
</div>
|
||||
|
||||
### 2.2 VM / IL ###
|
||||
|
@ -94,8 +92,8 @@ Zunächst macht man sich mit einer vordefinierten IL (Intermediate language) fü
|
|||
vertraut. Hierzu kann der beigestellte VM-Emulator genutzt werden:
|
||||
|
||||
<div class="pure-g">
|
||||
{{<image alt="VM Code Sample" src="vm_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{<image alt="VM Emulator" src="vm_emulator.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="VM Code Sample" src="vm_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="VM Emulator" src="vm_emulator.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
</div>
|
||||
|
||||
Als nächstes wird ein Übersetzer erstellt, von VM-Code zu Assembly Language. Wenn man diesen mit dem unter
|
||||
|
@ -109,17 +107,17 @@ Sogar Objekte können bereits angelegt werden!
|
|||
|
||||
Hier mal die formale Definition:
|
||||
|
||||
{{<image alt="Jack Grammar" src="jack_grammar.png" size="1920x1080 q90">}}
|
||||
{{< image alt="Jack Grammar" src="jack_grammar.png" size="1920x1080 q90">}}
|
||||
|
||||
Praktisch sieht der Code z.Bsp. so aus:
|
||||
|
||||
{{<image alt="Jack Code Sample" src="jack_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Jack Code Sample" src="jack_code.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
|
||||
Auch hierfür ist - unter Anleitung - ein Compiler zu erstellen. Dieser erzeugt aus Jack dann VM-Code:
|
||||
|
||||
<div class="pure-g">
|
||||
{{<image alt="Jack Code" src="jack_code_main.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{<image alt="VM Code" src="vm_code_main.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="Jack Code" src="jack_code_main.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
{{< image alt="VM Code" src="vm_code_main.png" size="640x480 q90" class="pure-u-1 pure-u-md-1-2" >}}
|
||||
</div>
|
||||
|
||||
Sieht doch gar nicht so kompliziert aus!
|
||||
|
@ -137,7 +135,6 @@ Garbage Collection Strategie - wirklich lehrreich!
|
|||
|
||||
Bei Screen- und Output-Modul befasst man sich mit Bildschirmspeicher und Character-Generierung, wie zu C64-Zeiten ...
|
||||
|
||||
|
||||
## 3. Ein kleines Defizit und dessen Beseitigung ##
|
||||
|
||||
### 3.1 Von 16-Bit zu 32-Bit Worten ###
|
||||
|
@ -166,26 +163,26 @@ Mit **Kresse** hab' ich eine Wette laufen: Jedes Jahr mindestens eine neue Sprac
|
|||
verkündet hat, das auch [Rust](https://en.wikipedia.org/wiki/Rust_(programming_language)) im Linux Kernel genutzt
|
||||
werden darf, fand ich, das es Zeit ist hier mal nachzurüsten.
|
||||
|
||||
**Xperimental**: *Mach lieber [Go](https://en.wikipedia.org/wiki/Go_(programming_language)),
|
||||
**Xperimental**: *Mach lieber [Go](https://en.wikipedia.org/wiki/Go_(programming_language)),
|
||||
Rust ist wie C++ (reichlich überladen ...). Hätte ich mal auf ihn gehört!*
|
||||
|
||||
Was mir auch nicht gleich klar war: Rust ist eine funktionale Sprache (wie Scheme, Lisp, Haskell u.ä.), es sieht
|
||||
nur optisch wie eine Prozedurale aus.
|
||||
|
||||
Bis Kapitel 17 (inkl., von insgesamt 21) habe ich mich durch das [Rust-Manual](https://doc.rust-lang.org/stable/book/)
|
||||
Bis Kapitel 17 (inkl., von insgesamt 21) habe ich mich durch das [Rust-Manual](https://doc.rust-lang.org/stable/book/)
|
||||
vorgearbeitet, dann habe ich die Arbeit am HE32-Projekt in Rust aufgenommen ('Hack'-Emulator 32-Bit) - und bin
|
||||
gleich am indirekten Vector-Zugriff gescheitert (ein solideres Verständnis von 'RefCell' hätte geholfen -
|
||||
Danke **Vespasian**)!
|
||||
Auch hatte ich zunächst für parallele Threads geplant und vorsichtshalber eine Menge mit Arc & Mutex hantiert -
|
||||
gleich am indirekten Vector-Zugriff gescheitert (ein solideres Verständnis von 'RefCell' hätte geholfen -
|
||||
Danke **Vespasian**)!
|
||||
Auch hatte ich zunächst für parallele Threads geplant und vorsichtshalber eine Menge mit Arc & Mutex hantiert -
|
||||
überflüssigerweise & eine echte Performance-Bremse.
|
||||
|
||||
Weil eine neue Sprache lernen ja immer eine Unterforderung ist (💀!), habe ich mich zwecks Komplexitätssteigerung
|
||||
auch gleich für eine GUI-Lösung entschieden 🏋 (hier sieht man noch, das die GUI-Landschaft für Rust im Fluß
|
||||
auch gleich für eine GUI-Lösung entschieden 🏋 (hier sieht man noch, das die GUI-Landschaft für Rust im Fluß
|
||||
ist - nach einiger Web-Recherche habe ich mich für [Qt5 mit ritual](https://rust-qt.github.io/) entschieden).
|
||||
|
||||
Eigentlich soll Rust ja 'sicher' im Hinblick auf Speicherzugriffe sein, schade auch, das für Qt5 dann große Teile
|
||||
wieder auf 'unsafe' gedreht werden (müssen) 🖕 ...
|
||||
Wenigstens läßt sich der Timer-Event von Qt gut nutzen!
|
||||
wieder auf 'unsafe' gedreht werden (müssen) 🖕 ...
|
||||
Wenigstens lässt sich der Timer-Event von Qt gut nutzen!
|
||||
Nicht so gut funktioniert das Einklinken in die Event-Schleife zwecks Abfangen der Tastatur und Weiterreichung
|
||||
an die Emulation (das Symbol wird nicht richtig aufgelöst - ist zumindest nicht auffindbar?!).
|
||||
Daher habe ich das Modul ('crate' in Rust-Terminologie) device_query dafür genutzt.
|
||||
|
@ -195,20 +192,19 @@ Nach einigen Performance-Optimierungen läuft der HE32 jetzt ganz passabel. Nur
|
|||
System-Bibliotheken anzupassen: In Math.multiply musste die Bitzahl erhöht werden und Sys.wait musste an
|
||||
die neue Abarbeitungsgeschwindigkeit angepasst werden.
|
||||
|
||||
{{<image alt="HE32 running Pong" src="he32_run_pong.png" size="1920x1080 q90">}}
|
||||
{{< image alt="HE32 running Pong" src="he32_run_pong.png" size="1920x1080 q90">}}
|
||||
|
||||
Die [Quellen zu HE32](https://git.hacknology.de/projekte/HE32) finden sich wie gehabt auf dem hacKNology git-server.
|
||||
|
||||
|
||||
## 4. Was kann man - ganz praktisch - an Erkenntnissen gewinnen? ##
|
||||
|
||||
- Der Kurs empfiehlt sich unbedingt für Ingenieure oder Naturwissenschaftler. Wer im Informatik-Studium nur die
|
||||
'Fertigprodukte' Flex und Bison kennengelernt hat, jedoch interessiert ist am Eigenbau, ist hier ebenfalls richtig.
|
||||
Ist schon ein tolles Gefühl, wenn man eine 'eigene' Compiler-Toolchain gebaut hat!
|
||||
Ist schon ein tolles Gefühl, wenn man eine 'eigene' Compiler-Toolchain gebaut hat!
|
||||
- Der Compilerbau hat seit den 80ern Fortschritte gemacht: Die Erfindung einer zwischengeschalteten VM/IL erlaubt
|
||||
eine deutliche Komplexitätsreduzierung, man muß eben nicht mehr direkt aus der Hochsprache Assembly-Code für die
|
||||
Zielplattform generieren.
|
||||
Ok, schneller wird's nicht - Performance ist allerdings heutzutage nicht mehr so das Problem.
|
||||
Zielplattform generieren.
|
||||
Ok, schneller wird's nicht - Performance ist allerdings heutzutage nicht mehr so das Problem.
|
||||
Außerdem erlaubt das Konzept die Aufteilung in Frontend/VM/Backend - und als Frontend
|
||||
können dann bei Bedarf verschiedene Hochsprachen Verwendung finden, als Backend sind unterschiedliche Targets
|
||||
mit vertretbarem Aufwand machbar (siehe hierzu z.Bsp.: [LLVM](https://llvm.org/)).
|
||||
|
@ -216,18 +212,16 @@ mit vertretbarem Aufwand machbar (siehe hierzu z.Bsp.: [LLVM](https://llvm.org/)
|
|||
- 💡Eine CPU mit nur zwei Registern (ohne PC) muss extrem viel über den Stack abwickeln. Sowohl in der Emulation wie
|
||||
auch in der Realität (externer Speicherzugriff!) ist das SEHR langsam. Hier gilt also: Viel(e Register) hilft viel!
|
||||
|
||||
|
||||
## 5. Ausblick ##
|
||||
|
||||
Man könnte z.Bsp. mit einer CPU mit mehr Registern (oder auch einem CPU-lokalen Teil-Stack?) experimentieren ... 🤔
|
||||
Ebenfalls denkbar: Höherwertige CPU-Befehle (womit wir bei der alten RISC/CISC Diskussion angekommen wären!).
|
||||
Man könnte z.Bsp. mit einer CPU mit mehr Registern (oder auch einem CPU-lokalen Teil-Stack?) experimentieren ... 🤔
|
||||
Ebenfalls denkbar: Höherwertige CPU-Befehle (womit wir bei der alten RISC/CISC Diskussion angekommen wären!).
|
||||
Man sieht: Der Kurs macht Lust auf mehr ...
|
||||
|
||||
VM: Ein VM-Emulator in Rust wird schneller als die derzeitige Java-Variante sein. Wenigstens ist der mitgelieferte
|
||||
VM-Emulator langsamer als HE32, er müsste aber eigentlich schneller sein (wg. der enorm reduzierten Anzahl
|
||||
VM-Emulator langsamer als HE32, er müsste aber eigentlich schneller sein (wg. der enorm reduzierten Anzahl
|
||||
höherwertiger Befehle die sich aber immer noch gut/schnell emulieren lassen).
|
||||
|
||||
🗣 Wenn ich ihn richtig verstanden habe, will **Vespasian** eine verbesserte HE32-Version gestützt auf das Tokio-Framework
|
||||
entwickeln (oder eine qemu-Version implementieren, die den Assembler-Code wieder auf VM-Code wandelt - oder so ähnlich?).
|
||||
entwickeln (oder eine qemu-Version implementieren, die den Assembler-Code wieder auf VM-Code wandelt - oder so ähnlich?).
|
||||
Beides um die Performance nochmal richtig zu steigern. Ich bin gespannt ...
|
||||
|
||||
|
|
Loading…
Reference in New Issue