 Okay, willkommen zu meinem Vortrag, wie man einen Emulator schreibt. Hier eine schöne AI-generierte Stitelblatt für den Vortrag. Ja, die Folien sind auf Englisch, aber ich glaube, ich werde auf Deutsch reden. Gestern habe ich es genau anders rumgemacht, da habe ich auf Englisch geredet und die Folien waren Deutsch. Okay, also erstmal eine kleine Einleitung. Ich denke, wahrscheinlich die meisten hier im Raum haben irgendwie schon mal einen Emulator benutzt oder vielleicht sogar auch selbst eingeschrieben. Aber ich weiß noch, als ich das erste Mal irgendwelche Emulatoren ausprobiert habe, war das total magisch, dass man auf einmal, weiß ich nicht, Gameboy oder Playstation-Spiele auf seinem Computer spielen konnte. Und später habe ich mich dann für das Unix-Betriebssystem interessiert und wollte dann mal das ursprüngliche Unix laufen lassen. Weil man hat ja einen Riesenzo von Unix-System, aber ich wollte das originale Alte. Und dann habe ich halt irgendwann herausgefunden, man kann eine PDP-11 emulieren und das Unix ausprobieren. Das war irgendwie so faszinierend, dass mich das nie so richtig losgelassen hat. Und ja, ich werde euch ein bisschen berichten von meinen Erfahrungen und was ich so für Emulatoren geschrieben habe und was es für verschiedene Techniken gibt und ja, und das ein bisschen demonstrieren und ein bisschen reflektieren. Also, was gibt es für Gründe, Systeme zu emulieren? Der erste Grund ist, man hat die Maschine nicht oder man will sie nicht benutzen, vielleicht frisst sie zu viel Strom oder irgendwas, oder man hat zu viele Maschinen, man interessiert sich für diverse Maschinen, man kann die nicht alle haben, vielleicht gibt es die Maschinen auch gar nicht mehr, vielleicht gab es nur eine, jemals, das ist hier ein Bild vom Worldwind, ein Teil vom Worldwind, den gab es nur einmal, jetzt gibt es hier nicht mehr, wenn man den benutzen will, muss man ihn emulieren. Das ist auch der zweite Punkt schon, also irgendwie so die Rettung und Aufbewahrung und irgendwie am Leben erhalten von Systemen, um zum Beispiel alte Software auszuführen, die es gab. Ein anderer Punkt kann sein, dass man eine Maschine sehr genau verstehen will. Ich habe hier mal als Beispiel so ein Ausschnitt aus einem Schaltplan der PDP6 gebracht, wo so ein Flip-Flop irgendwie drin ist, mit verschiedenen Signalen, die das auf 0 oder auf 1 setzen. Wenn man sich mit einer Maschine sehr im Detail beschäftigt oder wenn man die genau verstehen will, dann ist es gut, ein Emulator zu schreiben, weil man dann gezwungen wird, sozusagen jedes Detail zu durchdenken. Oder man will vielleicht Software schreiben in Maschinsprache für verschiedene Rechner und will natürlich irgendwie das ausprobieren können und um so ein Gefühl dafür zu kriegen, wie das ist, für diese Maschine zu programmieren. Und dann kann man eben auch die Maschine emulieren. Oder vielleicht gab es irgendwann mal eine Idee für irgendein Computer, die aber nie realisiert wurde und man würde trotzdem gerne mal ausprobieren, wie das so wäre, wenn es den Computer gäbe. Da schreibt man Emulator. Oder man will selbst irgendwie ein Computer bauen und um das auszuprobieren, ob die Ideen funktionieren, die man sich überlegt hat, kann man natürlich erstmal ein Emulator schreiben, um als ersten Schritt sozusagen. Was kann man für Sachen emulieren? Also erstmal einen ganzen Computer, hier mal so ein Beispiel von der PDP10, das ist halt ein großes System und dann emuliert man da halt alles, was da so dran hängt. Das ist jetzt nur ein Beispiel. Also zum Beispiel Spielkonsolen sind extrem beliebte Systeme zu emulieren, weil die halt auch von der Peripherie relativ simpel sind. Man hat halt in der Regel irgendwie ein Bildschirm und irgendwie ein Spielkontroller oder sowas. Man braucht keine Festplatten, kein Netzwerk, zumindest bei älteren Konsolen nicht und alles Mögliche nicht. Also das sind ein paar Beispiele. Man kann aber auch Teile von Computern einfach nur emulieren. Zum Beispiel jetzt irgendwie nur ein Terminal. Also jeder, der Linux schon mal benutzt hat, kennt hier irgendwie so ein Terminal-Emulator. Das macht halt sowas ähnliches wie ein VT100, was halt eine echte Maschine ist. Aber ja, man benutzt halt keine Terminals mehr als eigene Geräte, sondern es gibt halt Programme wie ein Terminal-Emulator oder auch ein Teletype, da will man vielleicht, also ein Fernschreiber, will man vielleicht irgendwie die Klänge auch noch abbilden oder irgendwas. Oder zum Beispiel sehr beliebt irgendwelche Peripherie nur zu emulieren, zum Beispiel so eine SCSI-Platte oder sowas. Also ich habe hier mal so ein Bild von einem SCSI-Emulator, eine SD-Karte rein und dann halt so ein SCSI-Anschluss, weil die Platten funktionieren ja auch gerne mal nicht mehr. Oder zum Beispiel man emuliert nur den Userspace eines Programms, also eines Prozessors. Also wenn das Programm für ein Betriebssystem geschrieben ist, dann okay, dann muss man den Prozessor irgendwie emulieren, aber man muss nicht die ganze Peripherie unter Umständen emulieren, sondern wenn das einfach nur mit dem Betriebssystem spricht, reicht es diese Schnittstelle zu emulieren, also das Betriebssystem und die ganze echte Hardware kann einem egal sein. Also das sind so ein paar Beispiele. Und das grundlegende Problem in der Emulation ist eigentlich, die Hardware, die man emulieren will, ist von Natur aus parallel. Da passiert alles Mögliche gleichzeitig und wenn man das irgendwie sequenziell haben will, da muss man sozusagen für arbeiten, dass man das kriegt. Ich habe das versucht, ein bisschen in diesem Diagramm darzustellen und Software ist genau das Gegenteil. Ein Programm ist halt einen Schritt nach dem anderen, der ausgeführt wird und das irgendwie zu parallelisieren, ist schwierig. Und eine Simulation oder Emulation, das ist die nächste Folie, ist im Grunde das Problem, wir wollen ein paralleles System irgendwie sequenziell modellieren. Also das würde ich sagen, ist so die Grundproblematik des Ganzen. Dann ein bisschen das Begriffliches, Emulation und Simulation, da gibt es so zwei Arten, wie man den, diesen Unterschied, also wie man diese Begriffe belegt sozusagen, ist nicht so wahnsinnig wichtig, aber es vielleicht trotzdem ganz gut mal darüber nachzudenken. Also die eine Definition kommt von IBM, als sie das System 360 rausgebracht haben und sie Programme für ihre alten Rechner dort noch ausführen wollten, haben sie halt Programme geschrieben, die haben sie Simulator genannt, die halt die Programme für andere Architekturen auf der 360 ausgeführt haben. Und sie haben aber rausgefunden, dass das, wenn man das rein ins Software macht, nicht so effizient ist, wie gesagt, das Problem paralleles System sequenziell modellieren. Und sie haben, sind dann dazu gekommen, die Hardware zu benutzen, um die Simulation effizienter zu machen, also Hardware Unterstützung im Mikrokode, glaube ich war es damals. Und das haben sie dann Emulation genannt, also reine Softwarelösung versus Hardware Unterstützung. Heutzutage ist, glaube ich, diese dichotomie eher nicht mehr gemacht. Man redet eher von Simulationen, also ganz allgemein, halt modelliert man irgendein System, um was darüber zu lernen, das irgendwie zu analysieren oder was auch immer, indem man halt den internen Zustand und das Verhalten dieses Systems simuliert. Also zum Beispiel Wettersimulation und eine Computersimulation ist halt auch eine Simulation, aber von einem Computer eben. Und Emulation ist bei dieser Begrifflichkeit eher ein funktionale Sache, dass ich also das Ding, was ich emuliere, wegschmeißen kann und meine Emulation da einsetzen kann. Also zum Beispiel ein Flugsimulator ist keine Emulation, weil wenn ich jetzt im Flugsimulator noch Timbuktu fliege, bleibe ich trotzdem zu Hause. Ein Emulator, ja, guten Flug-Emulator, weiß ich nicht, Flugzeug-Emulator vielleicht über ein Helikopter oder so, aber die müssen sich nicht ausschließen. Also wenn meine Simulation zum Beispiel schnell genug ist, dann kann das auch ein brauchbarer Emulator sein. Okay, und es gibt verschiedene Ansätze jetzt an die Emulation. Also das geht so ein bisschen von High-Level zu Low-Level jetzt. Also das Erste ist, man kann sich angucken, wie funktioniert mein System, also was sehe ich sozusagen, was das macht und ich behandle das eigentlich als Blackbox, das macht halt das irgendwie intern, weiß ich nicht, wie und ich baue das halt irgendwie nach. Also einfach selber Funktionalität irgendwie für außensichtbar. Eine Ebene drunter wäre dann, oder halt die Ebene drunter, die geht dann beliebig tief quasi, ist ich interessiere mich dafür, was passiert wirklich in der Maschine, also nicht nur was macht sie, sondern wie macht sie das, indem ich also den internen Zustand modelliere und halt wirklich sehr genau abbilde, was in der Maschine intern passiert. Das sieht man oft, da sieht man oft den Begriff Cycle Accurate. Es ist ein bisschen schwierig, was ist genau ein Cycle überhaupt, also da gibt es halt verschiedene eben, wie genau man das machen kann. Ein Aspekt zum Beispiel wäre, wenn man ein Computer hat, der Mikrokode über Mikrokode halt implementiert ist, dass man diesen originalen Mikrokode implementiert. Das sieht man relativ selten aktuell, weil es eben nicht sehr schnell ist, aber zum Beispiel auf dem FPGA oder sowas ist das möglich und da kommen wir schon zu dem nächsten Punkt. Also es gibt Hardware-Beschreibungssprachen, HDL, WRLock und VHDL sind da die beiden Bekannten und es gibt eben Geräte, FPGAs, die nicht in Programmen sequenziell ausführen, sondern die halt tatsächlich ein paralleles System sind, in dem ich halt sagen kann, das ist meine Schaltung, jetzt sei mal bitte diese Schaltung und dann kann man eben Hardware mit Hardware simulieren, was eigentlich ganz gut funktioniert. Man könnte natürlich noch eine Ebene druntergehen und irgendwie so auf der elektrischen Ebene irgendwelche Spannungen und so simulieren, das wäre glaube ich ein bisschen zu viel des Guten, aber vielleicht machen das auch irgendwelche Leute. Und dann gibt es noch eine andere Technik, die ist ein bisschen was anderes, Just-in-Time-Kompilierung oder Übersetzung, wo man den Maschinencode für eine Maschine übersetzt für die Maschine auf der Emulator läuft, sodass ich also nicht jeden Befehl einzeln angucken muss, jedes Mal wenn ich ihn ausführe und dann das entsprechende Tour, sondern ich übersetzt den einmal in das, was meine Maschine versteht. Und für dann den nativen Code auf der Maschine aus. Das ist sehr schnell natürlich, ist aber ein bisschen schwierig, das genauso zu analysieren. Zum Beispiel kann man auf verschiedenen Architekturen in die Mitte eines Befehls reinspringen und dann sieht man halt anderes Verhalten oder es gibt selbst modifizierenden Code. Also das ist ein Thema, wo rüber ich jetzt nicht weiter reden werde, aber das ist für zum Beispiel PlayStation 2-Emulator oder so was, geht das quasi ohne gar nicht, weil es dann viel zu langsam wäre. So, meine Erfahrung, damit ihr, also ihr werdet es wahrscheinlich merken, ich konzentriere mich viel so auf alte Computer und weniger irgendwie so auf Spielkonsolen oder so. Also ich habe verschiedene Emulatoren geschrieben angefangen, das erste Ding, was ich geschrieben habe, war eine PDP-11 in C, später dann auch noch einen anderen C-Emulator und auch der FPGA-Implementation, werde ich auch Teile von zeigen, um das zu demonstrieren, die verschiedenen Ebenen, auf denen man das machen kann. Dann PDP-6 habe ich auf so einer sehr niedrigen Ebene simuliert in C und dann auch eine FPGA, läuft auch auf eine FPGA, die Verilock-Version, ähnlich für die PDP-10, habe ich nicht mal eine C-Version, habe ich nur Verilock geschrieben, dann TX0, einer der ersten transistorbasierten Computer, habe ich auch ein C- und Verilock implementiert, Worldwind 1, ist ja auch hier in Stand zu, werde ich auch was zu sagen, habe ich auch simuliert, E-S24, kein Mensch, es heißt Elektronsaldera 24 von Nixdorf, dann gab es ein Projekt, den nachzubauen und ins Heinz-Nixdorf-Forum zu stellen und da war ich in dem Projekt auch ein bisschen beteiligt und habe eine Simulation dafür geschrieben und rausgefunden, wie dieses Ding überhaupt funktioniert und war, glaube ich, ein bisschen hilfreich fürs Projekt. Dann eine PDP-1 habe ich jetzt erst vor kurzem tatsächlich geschrieben in C für eben auch den Stand, also meinen Stand diesmal, für die PDP-1, ich habe auch eine Verilock-Simulation davon, ich habe auch noch ein paar andere Sachen, die mehr so, also die Linken sind halt so ein bisschen was Ernsthaftes und die Rechten sind eher so ein bisschen Rumspielerei, also PDP-5 und PDP-8, 12-Bit-Systeme, den PDP-8-Simulator werde ich auch gleich noch zeigen, 65.02 habe ich auch mal gemacht, aber nie wirklich getestet und vielleicht auch noch mal irgendwas, was ich jetzt vergessen habe, was zu nichts groß um geworden ist. Okay, wie sieht der Prozess aus, wie man einen Emulator schreibt? Ja, okay, also die Folie ist jetzt nicht, bringt jetzt nicht so viele Einsichten vielleicht, also man muss natürlich erstmal rausfinden, wie funktioniert die Maschine, was macht die überhaupt? Und das kann schon ein Problem sein, also insbesondere bei alten Maschinen hat man oft das Glück, dass die sehr gut dokumentiert sind, auch auf Hardware-Ebene, sodass man sehr genau analysieren kann, was die macht, aber die Dokumentation ist nicht unbedingt immer verfügbar. Und dann muss man eventuell auch die Sachen irgendwie reverse-engineeren oder sich halt, ja, irgendwas, irgendeine Fantasie, irgendwas ausdenken dazu. Und das ist auch, also über die Zeit würde ich sagen, verändert sich die Art der Dokumentation, also irgendwie so ein Mikroprozessor, da wird man jetzt natürlich nicht die Schaltung irgendwie finden, weil die Schaltung war halt dokumentiert, damit man die reparieren kann. Ein Mikroprozessor kann man hier halt nicht reparieren, da funktioniert der Chip oder funktioniert nicht mehr oder weniger. Deswegen findet man da oft zum Beispiel nicht so Details. Okay, also man muss rausfinden, was die Maschine macht. Dann ist es sehr hilfreich, wenn man irgendwelche Testprogramme hat, so Diagnostics wurden früher oft mit den Computern, also gab es halt von den entsprechenden Hersteller, die halt testen, dass die Maschine ordentlich funktioniert. Die fangen aber auch nicht immer alles ab. Also man kann sich da nicht darauf verlassen, dass man das perfekt gemacht hat, nur weil die Diagnostics funktionieren. Und manchmal hat man natürlich auch keine, man kann dann seine eigenen schreiben oder man führt einfach Programme aus, die man hat. Und hoffte halt, wenn man genug Programme hat, wie genug die Systeme halt irgendwie, also alle möglichen Funktionen des Prozessors ausprobieren und also benutzen, dass man dann irgendwann ein ziemlich gut funktionierenden Emulator hat. Ja, dann überlegt man sich wahrscheinlich, wie man halt so programmiert, wenn überlegt sich halt irgendwie so eine Architektur irgendwie für das Programm und dann fängt man halt an zu programmieren. Und das hängt auch so ein bisschen ab von dem System. Also zum Beispiel, wenn man jetzt ein System hat, wo man irgendwie ein Bus hat, an dem verschiedene Sachen dranhängen, dann will man vielleicht diesen Bus irgendwie simulieren oder vielleicht ist das alles einfach direkt in den Prozessor drin. Dann hat man halt vielleicht keinen Bus. Also es kommt sehr auf die Maschine an, wie man das dann genau macht. Es gibt schon so ein paar Grundstrukturen, die wahrscheinlich auch noch sehen werden. Es gibt Schwierigkeiten und Herausforderungen, die man hat. Also ich habe hier mal so ein Beispiel für, das kommt eigentlich erst unten. Also okay, correctness habe ich es mal genannt, das ist natürlich sehr allgemein. Also natürlich muss das Ding irgendwie das Richtige tun. Aber ja, manchmal weiß man gar nicht genau, wie das richtige Verhalten ist. Es gibt manchmal sehr, sehr komische Edge Cases, wo, werde ich auch gleich ein Beispiel zeigen, die vielleicht auch kein respektabler Programmierer jemals ausnutzen würde. Aber naja, vielleicht ist es ja doch mal passiert. So was wird manchmal auch benutzt, um irgendwie das genaue Modell einer Maschine rauszufinden, wenn die sich an irgendeiner Stelle ganz komisch verhält. Und dann kann man da vielleicht das Modell rausfinden oder zum Beispiel ein Kopierschutz kann rausfinden, ob irgendwie das Spiel oder was auf einer Originalkonsole läuft, wenn die Konsole halt in irgendeiner Stelle was ganz Komisches tut. Ja, gut. Und das ist vor allem deswegen schwierig, weil man zumindest bei vielen Computern, die jetzt nicht uralt sind, mit Geschwindigkeit ein Problem hat. Imulation ist grundsätzlich eine relativ langsame Angelegenheit. Und wenn man jetzt irgendwie so aktuelle Systeme, also zum Beispiel so was wie eine PlayStation 2 simulieren will, die auch noch massiv parallel ist mit mehreren Prozessoren, dann müssen diese ganzen Dinge auch irgendwie synchronisiert werden. Und Timing Probleme gibt es halt auch, also deswegen vorhin war schon mal so Cycle Accurate ein Stichwort. Wenn zu jedem Takt irgendwie man den genauen Zustand der Maschine weiß und ausrechnen kann, ja, dann ist alles schön, aber ja, vielleicht hat man ja nicht einen Takt, sondern irgendwie verschiedene Sachen laufen mit verschiedenen Takten oder es gibt gar keinen zentralen Takt. Und es ist eher Asynchronen, also es gibt viele Sachen, die passieren können. Und ja, das ist dann immer so eine Abwägung, wie genau mache ich meine Sache und wie schnell will ich das aber auch haben. Und das kann dann natürlich auch zu Fehlern führen. Wie gesagt, also die Geschwindigkeit ist ein Problem und die Genauigkeit. Und ganz große Sache ist natürlich so analoge Sachen. Also ich habe hier so ein Beispiel mal für so ein CRT Shader, wenn ich einfach nur die Pixel von irgendwas auf dem Bildschirm, so auf einem LCD irgendwie so als Quadrate mehr oder weniger anzeige, dann sieht das halt nicht aus wie auf einem Fernseher, wie halt die Konsole, also so wie das die Programmierer oder die Macher irgendeines Spiels vielleicht, was die halt getargetet haben sozusagen. Und sowas zu simulieren kann auch sehr schwierig sein. Und generell so alle Peripheriesachen sind immer richtig ätzend. Also CPUs gehen meistens recht angenehm zu simulieren und die Peripheries dann, wo man die Kopfschmerzen kriegt. So User Interfaces geht auch noch so ein bisschen in die Challenges Kategorie. Also so ein konventionellen Computer, so mit Bildschirm, Maus, Tastatur, Gamepad, was auch immer, das kann man mehr oder weniger genauso abbilden halt mit einem Computer, den man halt hat. Aber wenn man jetzt ältere Maschinen emuliert, also sozusagen das, was mich interessiert, dann hat man eben sowas wie also irgendwelche physischen Medien, so Lochstreifen, Lochkarten, Magnetband, die man halt auch einlegen will und wie man halt sehen will, wie sich das dann irgendwie bewegt. Oder, ja, hatte ich auch schon gesagt, so irgendwie so ein Fernschreiber, der dann ganz laut irgendwie klackert und wo dann das Papier so oben rauskommt. Oder so Light Pants oder Light Guns, sieht man ja auch an dem Worldwindstand drüben. Kann man natürlich irgendwie mit der Maus simulieren. Na ja, ist aber irgendwie nicht das Gleiche. Oder eben Front Panels und so Blinkenlights Geschichten. Also ich habe hier oben mal das Extrembeispiel von der IBM 36090, glaube ich, gezeigt. Ja, wenn man sowas haben will, sieht es schwierig aus. Ja, und so ein paar mögliche Lösungen irgendwie sind halt, man sagt halt, ja, okay, ich mache das halt irgendwie mit einem, ja, konventionellen Interface, also ein grafisches Programm oder Kommando-Zeilen-Ding. Also für Paper Tape sage ich dann halt einfach irgendwie, gebe ich dann halt ein, irgendwie so Mount und dann irgendein Dateinamen oder so. Ist halt nicht dasselbe, wie das Paper Tape einzulegen, aber funktioniert halt. Oder zum Beispiel jetzt bei Front Panels, wie gesagt, an unserem Stand so nachbauten von, zumindest von Teilen davon, dass man das so ein bisschen nachempfinden kann. Oder andere Möglichkeit, habe ich auch schon ausprobiert, da unten Screenshot aus meinem Programm in Virtual Reality. Also das ist jetzt ein Bild von einem PDP6 Modell, was ich gemacht habe. Und das ist über das Netzwerk an einen Emulator, an meinen Emulator angeschlossen. Und wenn man die Maschine startet, dann blinken da halt die Lampen und man kann die Schalter bedienen und so weiter. Das Problem ist aber da, okay, man hat dann irgendwie diese komischen Controller in der Hand und es fehlt trotzdem die Haptik, die Schalter auch und runter zu machen. Das ist auch noch keine perfekte Lösung. Okay, aber das zu dem Thema, also ist auch ein Problem. Was benutzt man für Tools? Also erstmal so Programmiersprache ist eigentlich erstmal egal. Also weil Programmiersprache ist halt Touring vollständig in der Regel und damit kann man alles machen, was man will. Einige eignen sich natürlich besser, gerade mit Hinblick auf Geschwindigkeit. Also so C, C++ sind traditionell sehr beliebt und jetzt auch Rust in seit einiger Zeit. Dann ist ein Assembler ganz praktisch, einfach um Testcode sich selbst zu schreiben und einzelne Befehle irgendwie zu testen. Oder auch größere Programme, also keine Riesenprogramme vielleicht, aber so irgendwas zum Testen halt. Und dann so Traces heißt, dass man quasi nach jedem Befehl irgendwie den Zustand der Maschine ausgibt. Alle Register zum Beispiel. Und dann halt guckt irgendwie, wenn man jetzt irgendwo ein Fehler hat, was an welcher Stelle läuft schief. Das benutzt man oft bei Software-Emulationen. Wenn man das jetzt auf so eine Hardware-Ebene nachbaut, so ein Varylog für FPGAs oder sowas, dann hier diese Waveforms ganz gerne. Das habe ich da oben rechts, wo man also sieht, also das ist jetzt von der TX0 Simulation von mir. Da oben habe ich mal so die acht Zeitpulse, die ein Zyklus hat gezeigt und man sieht halt, wie das so nach und nach runterrat hat. Und darunter sieht man die Register, die sich dann also zu verschiedenen Zeitpunkten irgendwie ändern. Und hier ist noch so ein Flip-Flop, der Cycle-Flip-Flop. Also wenn der Null ist zum Beispiel, dann holt er ein Befehl aus dem Speicher und hier rechts, wenn der Eins ist, dann wird der Befehl ausgeführt. Das sind also so Methoden, um das so ein bisschen unter Kontrolle zu kriegen. Dann gibt es hier noch, habe ich einfach als Beispiel mal rausgegriffen, für jemanden, der einen sehr schönen Debugger geschrieben hat, wo man also hier so ein Disassembly-Ansicht hat und hier die Register der CPU sieht und natürlich den Bildschirm. Also das ist ein PC-Emulator. Also der macht das auch sehr genau, hat auch irgendwelche Buszyklen analysiert und so weiter. Also das ist relativ neuer Emulator, aber das ist mal so ein Beispiel eben für so ein etwas größeres und mächtigeres Debugging-Interface. Meine Sachen sind meistens relativ minimalistisch. Ein anderes nützliches Tool, wenn man jetzt zum Beispiel VeryLog Simulation schreibt, ist VeryLater, der übersetzt die Hardware-Beschreibung zu C++ und dann kann man das halt ausführen und auch interaktiv benutzen, auch wenn es in der Regel wahrscheinlich zu langsam sein wird. Aber es ist trotzdem praktisch, wenn man eben interaktiv mit irgendwie einem Emulator was machen kann und nicht nur hier so ein Wave-Dump irgendwie hat, wo man dann die einzelnen Signale angucken muss. Aber je nachdem, also je nachdem, an welchem Problem man gerade arbeitet, bietet sich halt das eine oder das andere an. Okay, ich glaube, das kommt später. Ich will jetzt erstmal ein bisschen Beispiele machen und zwar will ich, also die PDP8 eignet sich einfach perfekt, um einen Emulator zu erklären, weil das ist, glaube ich, der simpelste Computer, den man irgendwie sich vorstellen kann, nicht ganz, aber ist halt ein echter Computer vor allem und ist wirklich einfach. Ja, jetzt geht es so ein bisschen in, also, ja, so irgendwie Computer-Engineering also wie halt so ein Computer funktioniert. Und im Grunde ist der Speicher, also das zentrale Element des Computers, das habe ich da rechts, also es ist eine 12-Bit Maschine, dafür steht die 12, alles ist 12-Bit breit. Und der Speicher wird halt einfach adressiert, also an jeder Zelle im Speicher steht halt irgendein Wort drin und die Zelle wird ausgewählt, die Speicherzelle vom Memory-Address-Register, also MA, das geht einfach in die Tabelle sozusagen rein und dann steht da ein Wort und dieses Wort kann ich dann in den Memory-Buffer laden oder von dem Memory-Buffer das Wort in den Speicher schreiben. So kann ich also schon mal mit dem Speicher was machen. So wenn ich jetzt ein Programm ausführen will, dann gibt es noch ein Register, was halt mitzählt sozusagen, an welchem Befehl wir uns gerade befinden, welcher Befehl als nächstes ausgeführt wird, das ist der Program-Counter PC und weil ich ja den Befehl aus dem Speicher holen muss, also das ist so eine ganz klassische von Neumann Architektur hier, weil ich den Befehl aus dem Speicher holen muss, muss ich natürlich den Program-Counter irgendwann mal in das Memory-Address-Register reinkriegen, deswegen habe ich da den Feier gesetzt. Und für zum Beispiel einen Sprung, wenn ich irgendwo hinspringen will, und also nicht nur einfach sequenzial ausführen, sondern an irgendeine andere beliebige Stelle springen will, muss ich ja irgendwie aus dem Befehl, das Sprungziel in den Program-Counter kriegen. Und das geht natürlich über das MB-Register und deswegen geht da der Fall nach oben in den Program-Counter rein. Umgekehrt, wenn ich ein Subroutine-Sprung machen will, von dem ich also wieder zurückkehren will, von wo ich hergekommen bin, dann muss ich mir den Program-Counter merken, von dem ich losgesprungen bin. Deswegen geht der Fall von PC in MB rein, sodass ich den dann in den Speicher schreiben kann. Und dann gibt es noch den arithmetischen Teil sozusagen, der jetzt hier ganz simpel ausgefallen ist, bei der PDP8, das ist also ein Akkumulator. Und der ist verbunden mit dem Memory-Buffer, da kann ich also zum Beispiel den MB, kann ich auf den Akkumulator drauf addieren, oder ich kann ein Bit-Weises und machen, oder ich kann den Akkumulator in den Memory-Buffer tun, damit ich dann den in den Speicher schreiben kann. Und der Akkumulator ist eigentlich 13-Bits, also das höchststellige Bit, heißt das Link-Bit L. Aber die beiden werden so ein bisschen separat behandelt an einigen Stellen, dass dieses Link-Bit und die 12 unteren Bits, deswegen ist das separat. Und das hier ist das Switch-Register bei der PDP8, also die Schalter vorne an der Konsole. Ja, und der Befehl übrigens, also um welchen Befehl es sich handelt, da gibt es normalerweise so ein Instruction-Register für, und das geht dann in die ganze Steuer-Logik rein, und da werden dann die Signale generiert, die dann ins System gehen, und dann halt diese ganze Sache steuern. Dann ist hier mal, also ich will da jetzt nicht ins Detail gehen, aber der Befehlssatz der PDP8 gezeigt, also wir haben grundsätzlich acht Befehle, das sind diese acht hier, also ein Bit-Weises und eine Addition, dann eines, was zum Speicher dazu addiert und den nächsten Befehl überspringt, wenn das Ergebnis 0 wird, dann kann ich den Akkumulator und den Speicher tun, und das setzt auch gleichzeitig den Akkumulator auf 0, dann kann ich so ein Subroutine Sprung machen, wo ich mir die ursprüngliche Adresse merke, von der ich komme, und dann den Befehl danach ausführe, einen Sprung, der das nicht macht, einfach nur ein normaler Sprung, dann was für IO-Transfer, also da gehe ich jetzt nicht drauf ein, und dann gibt es noch so ein Operate-Befil, der dann hier rechts nochmal aufgeschlüsselt ist, wo dann einzelne Bits, einzelne Funktionen haben. Und da ist zum Beispiel ein interessantes Beispiel, also es gibt hier diese rarer und rall Bits, und wenn eins davon gesetzt ist, dann wird das Link-Bit und der Akkumulator, werden alle Bits einmal rotiert, nach links oder nach rechts, und das Ganze, wenn ich dann das Bit-10 hier noch setze, passiert das Ganze zweimal, aber wer hält mich denn davon ab, zum Beispiel einfach die beiden Bits zu setzen, nach rechts und nach links? Dann rotiere ich ja in zwei Richtungen gleichzeitig. Was bedeutet denn das? Und das ist jetzt ein schönes Beispiel für diese seltsamen Edge-Cases. Ich glaube nicht, dass die Handbücher für die ursprüngliche PDP-8 und für die PDP-5, die dieselbe Architektur hat, dass sie das irgendwie erklären, was da passiert, ist es aber definiert. Also man kann, wenn man in die Schaltung guckt, und dann sich anguckt, wie da ein Flip-Flop funktioniert und so weiter, kann man tatsächlich rausfinden, was da passiert. Und tatsächlich unterscheiden sich, alle PDP-8-Modelle voneinander, die machen alle was anderes. Aber das ist halt selbst vor so einer simplen Architektur, stößt man, kann man auf solche Sachen stoßen. Und natürlich hat man dann irgendwie Ehrgeiz und will das richtig machen. Also man muss kein Ehrgeiz haben, aber ich hab den. Und jetzt würde ich einfach mal zeigen, wie dieser Emulator aussieht, wie so ein Code aussieht. Also ich habe es in C geschrieben und vielleicht, na, ich erkläre es vielleicht erstmal, also das ist jetzt in so einer mehr oder weniger High-Level, mit so einem High-Level-Ansatz geschrieben. Also ich moduliere hier jetzt nicht den internen Zustand allzu genau. Es ist schon daran angelehnt, aber das würde anders aussehen, wenn man das machen würde. Also hier das oben, das hier können wir so ein bisschen ignorieren. Wir gucken erstmal nur auf das hier. Das andere hat was mit Interots zu tun. Und der erste Teil hier zum Beispiel, der holt sich den einen Befehl aus dem Speicher. Also wie ich gesagt habe, der Program Counter geht in das Memory Address-Register, dann wird der Program Counter um eins erhöht, denn dann, ich will ja danach den nächsten Befehl haben. Dann hole ich mir den Befehl aus dem Speicher. Und jetzt schreibe ich die oberen drei Bits, also ich, also es sind 12 Bits insgesamt, dann nehme ich die unteren neun weg. Und also die sieben ist halt 1, 1, 1. Und dadurch kriege ich die drei Bits in dieses Instruction-Register. Und hier muss ich noch was erklären. Also einige Befehle nehmen halt hier so eine Adresse. Also die anderen Bits nach dem Opcode sind eine Adresse, die auch noch ein bisschen komisch kodiert ist, weil die eigentlich zwölf Bits lang ist, aber der Befehl ist ja schon zwölf Bits, das passt also nicht. Das ist halt so ein Hack irgendwie, dass man doch noch so ein bisschen damit klarkommt. Aber die IO und Operate Befehle, die interpretieren diese unteren Bits nicht als Adresse. Das heißt, also wir sehen hier 0 bis 5, nehmen eine Adresse, 6 und 7 nicht. Und das ist genau das, was hier ist. Also wenn wir kleiner als 6 sind, dann rechne ich mich irgendwie die Adresse aus. Das ist die Funktion. Das hier oben ist jetzt nur, um diese acht Bits zu zwölf Bits umzurechnen. Das ist jetzt nicht so wichtig, wie das genau funktioniert. Und dann gibt es aber noch das Indirektions-Bit. Das heißt also, ich habe die Adresse nicht im Befehl kodiert, sondern der Befehl kodiert die Adresse, wo die Adresse steht. Und da muss ich halt noch ein Speicherzyklus mehr machen. Und das habe ich halt hier mal so aufgeschrieben. Und wenn ich jetzt ein Befehl habe, also wir sehen es hier and hat und ist sie, oder wie man das ausspricht, benutzen, benutzen das, was im Speicher steht hier. Also hier halten unten, hier ein Plus, und hier wird eins addiert. Und die anderen schreiben entweder nur oder benutzen den gar nicht. Das heißt also, bei kleiner 3 hole ich mir dann das Wort, was ich, also da, so, hole ich mir das Wort aus dem Speicher, an dem ich halt interessiert war. Ja, und dann kann ich mir angucken, was haben wir denn für den Befehl? Also, und hier, also ich habe das Link-Bit und die Akkumulator-Bits in einer Variable. Ach so, übrigens die Variable ist, damit hätte ich vielleicht anfangen sollen. Also hier oben habe ich einfach Variablen. Ich habe das jetzt einfach mal als globale Variablen gemacht. Eigentlich ist es schöner, das in eine Struktur zu verpacken und so, aber das ist jetzt egal. Einfach als Variablen deklariert. Also Akkumulator-Programm-Counter, Memory-Address, Memory-Buffer Instruction-Register, Switch-Register. Und dann hier so ein Array von 4K für den Speicher. Und dann hier ist noch ein bisschen IO-Kram. Ich weiß nicht, wie sehr ich darauf eingehen will. Aber so, und im Akkumulator ist eben dieses Link-Bit drin. Deswegen, also wenn ich jetzt ein And machen will, mit Weisens und benutze ich halt einfach den C-Operator und dafür. Und mache das und vom Akkumulator und MB. Ich muss hier oben das Bit noch, das Link-Bit setzen, damit das nicht verschwindet. Weil der MB ist nur 12-Bit und der Akkumulator ist 13-Bit. Eine Addition, einfach mal einen Plus. Und ich gucke aber, dass ich oben nicht zu viele Bits irgendwie kriege. Also ich will nur die, also das in Oktaal im Übrigen. Also eine Ziffer sind immer drei Bits. Also ich nehme hier unten die 12 Bits raus. Und dann noch das Link-Bit. Und das schreibe ich dann in der Akkumulator. Das inkrementiert halt die Speicherzelle. Und wenn sie null wird, wird der Program-Counter inkrementiert. Und dann schreibe ich das Ergebnis zurück. Und so weiter, und so weiter. Und hier die Operate-Gruppe ist nochmal ganz lustig. Also hier machen halt verschiedene einzelne Bits. Lösen halt hier verschiedene Operationen aus. Also hier wird der Akkumulator auf null gesetzt. Hier wird das Link-Bit auf null gesetzt. Hier wird der Akkumulator umgedreht. Also aus null wird eins, aus eins wird null. Und hier wird das Link-Bit umgedreht. Hier wird der Akkumulator um eins erhöht. Und dann kommt der lustige Spaß hier mit diesen Rotationen. Und das hier ist das Verhalten, was die PDP8i macht. Was ich hier mal emuliert habe. Nämlich die linke und die rechte Rotationen werden einfach bittweise verodert. Was die straight 8 macht. Also die Ursprünche ist völlig seltsam. Das ist jetzt aber nicht ganz so wichtig, glaube ich. Und ja, so kann man das dann halt machen. Und das ist einfach eine Funktion. Die habe ich mal INST genannt für Instruction. Und dann habe ich hier so eine Schleife. Also solange die Maschine läuft, führe ich halt diese Funktion immer wieder aus. Und alle so 1000 Befehle gucke ich mal einmal, ob ich irgendwie IEO machen muss. Und wenn man das jetzt hier kompiliert, ich habe es gerade gemacht. Und hier ist ein Speicherabzug von einem Programm, Focal. Das ist eine Programmiersprache. Und wenn man das jetzt ausführt, das ist jetzt schon der Prompt von dem Programm. Und ich habe hier so eine coole Demo. Die kann man hier eingeben. Und dann du 0101. Also unser cooles PDP8-Programm läuft. Und die ganze Datei sind 277 Zeilen. Also nicht viel. Man kann also, wenn die Schriftart ein bisschen kleiner wäre, dann passt wahrscheinlich diese Funktion, die einen Befehl ausführt auf Einbildschirm. Ja, ich kann aber jetzt nicht viel mehr mit Focal machen. Ich kenne die Sprache eigentlich nicht. Ich wollte nur irgendeine Demo haben. Okay, also das war jetzt zum Beispiel für, wie man so wahrscheinlich daran geht, wenn man einen Emulator schreibt, einfach mal sozusagen das machen, was die Maschine macht, egal wie sie es jetzt genau macht. So, dann, was haben wir als Nächstes? Ich glaube, den Worldwind wollte ich zeigen. Nämlich als Beispiel dafür, dass die Dokumentation manchmal sehr unvollständig sein kann. Also der Worldwind hat 32 Befehle oder bis zu 32, die waren nicht immer alle implementiert. Und ich habe hier mal so eine Tabelle von 1950, irgendwie aus Januar 1950. Da lief die Maschine gerade ein paar Monate, hatte noch nicht mal Speicher. Man konnte 32 Worte mit Schaltern setzen. Und es gab 5 Flipflop-Register, die man halt schreiben konnte. Das war alles an Speicher. Und zuverlässig lief es ja auch noch nicht. Und hier oben sieht man also mal, man kann das nicht so gut lesen, aber das sind hier die Namen der Befehle. Und dann steht jetzt hier für jeden Befehl, ist sozusagen immer das Kästchen ausgefüllt, wenn dieser Kontrollpuls in die Maschine geht. Also da kann man nicht mal die Zahl lesen. Das ist einfach jeder Kontrollpuls hat einfach eine Zahl, sozusagen Namen. Und dann sieht man also, was weiß ich, hier bei 40 zum Zeitpuls 1 wird das Programmregister ausgelesen. Also das heißt, das wird dann auf den Bus gelegt. Der Worldwind hat so einen internen Bus, wo alles drüber geht. Und dann wird das Programmregister da halt drauf gelegt. Und zwar nur beim SP-Befehl. Okay, wenn man jetzt ein Simulator schreiben will, so wie ich das machen wollte, kann man sich natürlich jetzt denken, okay, nehme ich halt diese Tabelle und implementiere mir irgendwie diese ganzen Kontrollpulse, wenn man das eben auf so einer tieferen Ebene machen will. Also wirklich den internen Zustand und die interne Funktionsweise der Maschine nachbauen will. Ja, dann könnte ich das mir vorstellen, dass ich das so mache. Das Problem ist, 1950 ist relativ früh. Die Maschine war so richtig in Benutzung, sage ich mal, ab 53. Und da war der Befehlstatt schon ein bisschen erweitert und vielleicht auch verändert. Das Problem ist, für 53 habe ich diese Tabelle nicht. Ich habe stattdessen was anderes. Leider nur ein Ausschnitt habe ich davon. Und zwar wird da erklärt, was für jeden Befehl, also hier sieht man diese Zeitpulse, 1, 2, 3, 4, 5, 6, 7, 8, und dann wieder von vorne. Und man sieht also, was erst mal für jeden Befehl passiert. Also das nennt die Programming. Das heißt also so viel wie der Befehl wird aus dem Speicher geholt. Und dann für verschiedene Befehle, also clear and add, multiply, round off, divide, shift, write, transfer to storage. Also für fünf Befehle wird dann nochmal im Einzelnen erklärt, was zu jedem Zeitpuls genau passiert in der Maschine. Und hier sind diese Namen sozusagen dieser Kontrollpulse auch zu sehen. Aber wie gesagt, die Maschine hat halt 32 Befehle und nicht fünf. Hier oben wird dann auch gesagt, ja okay, also subtract and add ist halt fast genau wie clear and subtract meine ich, ist fast so ähnlich wie clear and add. Multiply and round off ist fast so wie multiply and hold, also und round off. Und shift write und shift left, kann man sich auch vorstellen, dass das ungefähr gleich funktionieren wird. Aber einige Sachen fehlen halt einfach. Und ich wollte das aber auf dieser Ebene simulieren eigentlich. Aber ich hatte halt die Informationen nicht. Und dann habe ich halt geguckt, naja, habe ich halt verglichen diese Befehle. Was passiert hier in 1900? Ich glaube, das ist so 54. Und was passiert halt 1950? Und mal gucken, genau, ich habe mir hier so Textarteien angelegt, wo ich dann einfach für jeden Befehl aufgeschrieben habe. Genau, das ist sogar noch das Original von 1950, habe ich jetzt aufgeschrieben, also okay, clear and add macht halt das. Und dann habe ich geguckt, so ich mal clear and add hier. Ach so, nee, das musste ich ja nicht rekonstruieren. Aber nee, erst mal, man sieht, es ist nicht identisch. Also es ist sehr ähnlich, aber nicht identisch. Und dann habe ich halt verstanden, wie sich diese Maschine ein bisschen verändert hat. Und habe dann rekonstruiert, wie die anderen Befehle wohl funktioniert haben müssen. Und habe mir dann hier auch so, falsche Datei, habe mir dann hier halt reingeschrieben, irgendwie so irgendwelche Sachen, die vielleicht nicht passieren müssen, aber könnten. Und zu welchem Zeitpuls diese Sachen passieren, weiß man auch nicht unbedingt. Hier SF zum Beispiel, wer weiß. Ja, aber dann habe ich halt mir, oops, ich habe zu viele Sachen hier auf, das ist fürchterlich. Aber das ist, ja, das ist eigentlich nicht schön. Ich habe eine bessere Datei, Moment. Was ist das? Nee, ich finde die Datei jetzt glaube ich nicht. Aber ich hatte mir halt diese Tabelle sozusagen gemacht für 1954 oder so, 53 glaube ich. Und einfach mit ein bisschen Textbearbeitung habe ich dann das hier raus generiert für meinen C-Emulator. Und da steht dann für jeden Kontrollpuls, eben für welche Befehle der gilt, einfach als Bitmass gekodiert. Und der Emulator führt jetzt tatsächlich hier die einzelnen Zeitpulse aus. Also hier zählt damit, welcher Zeitpuls gerade kommt. Und dann habe ich hier eine Funktion für jeden Puls. Und also zum Beispiel TP5 ist relativ übersichtlich. Ja, also wenn jetzt irgendwie Paar ausgelesen werden will oder soll und auf den Bus gelegt werden soll, dann passiert das. Wenn ich CS einlesen will, vom Bus passiert das und so weiter und so weiter. Diesen Code versteht man natürlich überhaupt nicht. Also man muss halt wissen, wie die Maschine funktioniert. Also wenn man die auf so einer niedrigen Ebene simuliert, muss man halt ganz anders denken, als wenn man jetzt irgendwie hier, wo war es, wenn man halt sowas macht. Das ist im Grunde leicht verständlich. Aber ja, aber das macht halt auch Spaß. Und das ist halt sehr genau. Und ach so, jetzt könnte ich sogar noch ein bisschen das demonstrieren. Ich habe... Tja, wo habe ich jetzt das? Ich glaube, ich kann... Also auch ein Beispiel für... Man baut sich einfach seine eigene Replika. Muss ich das hier irgendwie umstellen jetzt für... Ah, sehr schön. Ja, ich glaube, ich starte das ganze Ding einfach mal. Okay, also man drückt auf den Startkopf. Mehr mache ich jetzt hier gar nicht eigentlich. Kann wieder zurück. Und was ich jetzt ausführe, ist so ein Lorentz-Attraktor. Den habe ich in Worldwind Assembly geschrieben. Und das wird jetzt hier auf meinem Simulator halt ausgeführt. Und das Display ist auch eine Simulation von mir. Das simuliert so ein P7-Leuchtmittel auf einer Röhre, was eigentlich aus zwei Schichten besteht, aus einem ganz hellen, bläulichen oder was sehr kurzlebig ist und aus einem langlebigem gelb-grünlichen. Und deswegen faded das dann halt so aus. Und das führt tatsächlich auch in eine ziemlich genau original Geschwindigkeit aus. Also wenn man das Programm jetzt auf dem echten Worldwind noch laufen lassen könnte, würde das wahrscheinlich sehr ähnlich aussehen. Also Geschwindigkeit. Und je nachdem, was Sie für Röhren dort hatten, vielleicht keine P7-Röhren sieht es vielleicht anders aus. Aber dasselbe Programm können wir, glaube ich, auch drüben sehen. Ich weiß nicht, ob es noch läuft, aber gestern lief es auf dem Oszilloskop. Sehr schön. Ja, also das zum Beispiel für eine Low-Level-Simulation. Aber in C, mal gucken, wie viel Zeit habe ich noch. Ich will vielleicht noch ein bisschen was zu Verilog und so weiter sagen. Und Waveforms. Jetzt Beispiel PDP-11. Also was ich in Verilog mache, ist sozusagen, ich schreibe die Schaltung genau nach und simuliere die in Hardware. Und ich habe hier mal so eine Beispielseite. Also hier ist so ein 7481-Chip, die Alu ganz klassisch. Und da kommen halt die beiden Operanten so von links rein und von unten die Steuersignale. Also Alus ist nicht etwa das literische Wort für Bier, sondern das ist die Einstellung für die Alu. Und das Ergebnis kann ich dann irgendwie in so ein Register reintun und so weiter. Und also die Stelle mit der Alu hier in meinem Verilog-Code sieht halt dann mal so aus. Also eine Alu ist 4-Bit, die PDP-11 hat 16-Bit, das heißt, ich brauche 4 davon. Und hier sieht man eben, wie man diese Module einfach instanziert und dann die Drähte sozusagen legt. Das ist halt auch nicht lesbar in der Art, wie der PDP-8-Emulator es war. Aber man kriegt eben potenziell sehr genaues raus. Und hier ist dann halt die Alu mal implementiert. Also guckt man sich halt an, wie die funktioniert. Sehr spannend übrigens. Und ja, das kann halt alles mögliche. Addition, Subtraktion, Bitweise, Geschichten und so weiter. Aber das nur so als Beispiel, wie der Verilog-Code aussieht. Und wie man dann das Ganze eben debuggt und analysiert, kann man hier sehen. Sehr unübersichtlich. Mal gucken, ich wollte, ja genau, hier sieht man es. Also hier sieht man also die P1, P2, P3-Dinger. Das sind die Takte, die in der Maschine alles auslösen. Also das ist halt auch, wie gesagt, kein, also nicht jeder Computer hat einen zentralen Takt. Also heutzutage vielleicht schon, aber damals nicht unbedingt. Und die ist mikrokodiert. Also das ist eine Simulation, die halt den Mikrokode ausführt. Und je nach Mikrokode Wort wird halt zum Beispiel passiert nur P1 oder nur P2 zum Beispiel. Oder P2 und P3. Also man sieht hier, dass das nicht regelmäßig ist. Weil hängt halt von dem Mikrokode Wort ab, was da jetzt, wie diese Takte genau durch System gehen. Und hier oben sieht man den ganz gut zu den Datenfahrt. Also hier zum Beispiel, das Ergebnis der Alu, kann man gucken. Und dann sieht man hier das Ding irgendwie und sieht dann, wie sich die, wie sich über die Zeit dann die Werte ändern. Und da oben kann man also sehen, zu welcher Zeit der Simulation man sich gerade befindet. Also das hier ist irgendwie so Nanosekundenauflösung. Und da oben steht dann halt so ein Mikrosekunden, wann halt was passiert. Und das ist natürlich eine sehr schöne und genaue Sache. Ja, also auf der Ebene halt ein Computer zu simulieren, da findet man dann auch noch mal Sachen, an die man gar nicht gedacht hatte. Es gab zum Beispiel einen, einen, einen Ding, was ich gefunden hatte, wo die Diagnostics mir ein Fehler gegeben haben. Also meine Simulation war falsch. Und zwar, weil ein, ich habe dann rausgefunden, ein Mikrokodbefehl wurde abgebrochen, der zu dem Zeitpunkt noch nicht hätte abgebrochen werden sollen. Was daran lag, dass ich die Memory Management Unit simuliert habe. Aber nicht, also das heißt, da müssen Adresse, müssen Adressen addiert werden und getestet werden, ob die in einem richtigen Bereich sind. Und das kostet ein bisschen Zeit. Und deswegen ist die Verzögerung, mit der ich die Adresse dann auf den Bus lege. Also hier unten sieht man übrigens auch die Buszyklen, wo dann die Adresse und die Daten auf dem Bus liegen. Aber diese Verzögerung musste länger gemacht werden. Und dadurch wurde der Mikrokodbefehl, der konnte noch zu Ende laufen mit der Memory Management Unit. Aber ich hatte nicht das längere Delay simuliert. Das heißt, meiner wurde vorher abgebrochen. Und dann gab es halt so einen kleinen Unterschied zwischen der echten Maschine und meiner Simulation. Und ich bin wahrscheinlich auch der erste, der das vielleicht entweder jemals oder irgendwie seit den 70er Jahren gemerkt hat, dass es einen Unterschied gibt bei diesem Trap Verhalten, je nachdem, ob die Maschine die Memory Management Unit drin hat oder nicht. Das sind also auch wieder so extreme Edge Cases. Und die sieht man halt aber auch erst, wenn man eben auf so einer Ebene die Maschine simuliert. Okay, wir kommen jetzt zum Ende, glaube ich, und nochmal zurück zu den Folien. Also wenn man jetzt selber einen Emulator schreiben will, wie fängt man an? Eine Methode ist man, oder die beste Methode ist wahrscheinlich erst mal was Einfaches sich rauszusuchen. Also Chip 8 ist so eine Fantasie-Konsole, die wird gerne empfohlen, anfängern. Persönlich, finde ich, muss man das nicht machen. Man kann auch einen richtigen Computer simulieren. Zum Beispiel eine PDP 8 ist auch sogar wahrscheinlich einfacher als Chip 8. Es ist halt nicht so grafisch. Chip 8 hat ein bisschen Grafik. Aber es ist egal, man kann sich da irgendwas aussuchen. Dann sind so Mikroprozessoren sehr beliebt und Spiele-Konsolen. Also wenn man jetzt zum Beispiel 6502, damit kann man jetzt ein NES simulieren oder weiß ich nicht, Apple II oder ich meine, das wissen die Anwesenden hier wahrscheinlich, was man damit machen kann. Oder mit einem 8080 oder Z80 oder sowas dazwischen eigentlich, kann man Game Boy simulieren mit einem 8080 zum Beispiel Space Invaders. Das hat bis auf die CPU und den Bildschirm fast nichts weiter. Also ist noch so ein bisschen weitere Logik. Man hat ein schönes Ergebnis, was man relativ schnell erreichen kann. Aber am besten ist man sucht sich einfach die Maschine aus, die man irgendwie mag und kennt und die man näher kennenlernen will und die einem irgendwie Spaß macht. Und jetzt noch eine kleine Liste, natürlich komplett unvollständig. Also Immulatoren, die man sich vielleicht mal angucken könnte oder sollte. Also SIM-H, heißt eigentlich jetzt Open-SIM-H, ist für Mini-Computer und Mainframes. Also diese ganzen PDPs zum Beispiel, IBM 360 und alle möglichen Sachen. Also wenn man zum Beispiel UNIX ausprobieren will, so ist SIM-H das Ding. Dann gibt es noch Mame, also ursprünglich zumindest für so Arcade-Automaten, aber es macht auch viele andere Sachen. Auch zum Beispiel eine VT-102-Emulation, also Terminal-Emulator. Dann Dolphin, das ist relativ bekannt, weil die auch irgendwie einen ganz guten Blog irgendwie haben, wo sie ihre Verbesserung und ihre Reverse-Engineering Sachen publizieren. Der macht Gamecube und Wii. Dann PlayStation 2 ist irgendwie so die erfolgreichste Spielekonsole aller Zeiten und hardwaremäßig auch echt interessant. Deswegen habe ich das mal dazu getan, PCS-X2. Dann B-SNES ist noch relativ bekannt, weil das einen starken Fokus auf Genauigkeit gelegt hat. Es gibt noch viele, viele andere. Eigentlich habe ich jetzt alles gesagt, was ich wollte. Wenn jetzt noch Kommentare oder Fragen sind, können wir das gerne machen. Alles erschlagen.