Meine kleinen Relais: Brainfuck Computer ist Magie

Einführung


Es war einmal, als alles groß war und ich klein, las ich Wojciechowskis Buch "Electronic Toys", um die darin beschriebenen Geräte zum Leben zu erwecken. So wurde im bereits fernen Jahr 2008 aus mehreren zehn elektromagnetischen Relais eine 4-Bit-ALU ( RCVM1 - Relay Digital Computing Machine - Version 1 ) zusammengesetzt, die addieren und subtrahieren kann. Und dann dachte ich - und was ist, wenn ich eine wesentlich größere Anzahl von Relais zusammenbaue und einen vollwertigen Relaiscomputer baue? Es dauerte nur 8 Jahre, um das Relais hier und da langsam bis zur erforderlichen Anzahl zusammenzubauen, und ich begann zu erstellen.


Lassen Sie mich Ihnen Ihr Projekt vorstellen, um eine zweite Version eines digitalen Relay-Computers mit dem Codenamen „BrainfuckPC“ zu erstellen - einen 16-Bit-Computer mit Von Neumann-Architektur und einer Reihe von Anweisungen für die Brainfuck-Sprache. Die Designarbeiten sind abgeschlossen und ich bin gerade dabei, dieses Monster herzustellen.


1 Technische Daten


  • Adressbusbreite: 16 Bit
  • Adressierung: Wort für Wort, 16 Bit / Wort
  • Speicherkapazität: 64 Kiloslov (128 KB)
  • Datenbusbreite: 16 Bit
  • Einheitlicher Adressraum für Code und Daten (Von Neumann Architecture)
  • Taktfrequenz (Design): 100 Hz, 1 Befehl / Zyklus
  • Befehlssatz: Brainfuck ++
  • Anzahl der Relais (Ausführung): 792
  • Verwendete Relais: Reedschalter, RES55 (1p), RES64 (1z)

Details gerollt


Allgemeines Arbeitsprinzip


Betrachten Sie die verallgemeinerte Struktur eines Computers:



Abbildung 1: Verallgemeinerte Computerstruktur


Das zentrale Element ist der Addierer, und zwar nicht einfach, sondern mit paralleler Übertragung. Warum dies erforderlich ist - werde ich weiter unten erläutern.


Das Programm und die Daten werden in einem Speicherblock gespeichert. Der Zugriff auf sie erfolgt an der Adresse, die im IP-Befehlsregister oder im AP-Adressregister aufgezeichnet ist, basierend auf dem, was wir jetzt lesen möchten - Daten an der im AP angegebenen Adresse oder dem Befehl, der an der IP-Adresse aufgezeichnet ist.


Um dieses Turing-Band zu bedienen (und die Programmiersprache Brainfuck identifiziert es genau), müssen wir in der Lage sein, eine von drei Aktionen auszuführen:


  • Ändern Sie den Wert in der aktuellen Datenzelle, dh führen Sie Add / Sub-Operationen aus. In Brainfuck kann der Wert in der Zelle nur um eins geändert werden, d. H. +1 oder -1. Bei einem vollwertigen Addierer ist es jedoch eine Sünde, lange Ketten ++++++++++++++ (------------) nicht zu einer Operation zusammenzufassen. AP + = N ( AP- = N) beschleunigt den Prozess erheblich Berechnungen. (Vergessen Sie auch nicht, [-] (oder [+]) in * AP = 0 umzuwandeln);
  • Ändern Sie die Nummer der aktuell ausgewählten Datenzelle. Das heißt, durch den Datenspeicher gehen (AP ++, AP--);
  • Ändern Sie die Nummer der aktuellen Anweisung. Zuerst müssen wir nach jedem Befehl den Wert im IP-Register um eins erhöhen. Ändern Sie zweitens diesen Wert, wenn der Code Verzweigungen enthält (standardmäßig zum Organisieren von Schleifen). Es gibt nur ein Steuerflag - Z. Dementsprechend gibt es die Befehle JumpIfZero und JumpIfNotZero.

Insgesamt müssen wir in der Lage sein, einem Eingang des Addierers den Wert eines der folgenden drei Blöcke zu liefern - AP-Register, IP-Register, DATA-Bus. Wir werden dies durch ein temporäres Register tun, in dem wir einen der erforderlichen Werte speichern und den gewünschten mit 16-Bit-Schlüsseln verbinden.


Bei der zweiten Eingabe des Addierers geben wir eine Zahl ein, um die sich einer dieser Werte in Plus oder Minus ändern soll. Aufgrund der begrenzten Breite des Befehls können Sie ihn nur um eine + -12-Bit-Nummer ändern. Für Brainfuck ist dies jedoch mehr als genug ("genug für alle", ja).
Wir werden diese 12 Bits aus dem Befehlsregister entnehmen. Bei Vorhandensein solcher Befehle ist dies natürlich, da einige Teams den Addierer überhaupt nicht verwenden. Vergessen Sie nicht, dass negative Zahlen im erweiterten Code bereitgestellt werden, wobei zusätzliche Dateien eingereicht werden. Einheitentransfereingang (d. h. A + invB + 1)


Das Berechnungsergebnis wird sofort dort geladen, wo wir es erhalten haben. Aufgrund des temporären Registers können wir dies schmerzlos tun.


Weitere Details (ich würde sogar sagen langweilig) zur Architektur finden Sie in diesem Video:



Befehlssatz


Nachdem ich ein allgemeines schematisches Diagramm gezeichnet hatte, das 8 grundlegende Brainfuck-Anweisungen implementieren konnte, stellte ich fest, dass es ein viel größeres Potenzial hat. Aus diesem Grund habe ich einen breiteren Befehlssatz entwickelt, der mit Brainfuck kompatibel ist, für den jedoch jeder Brainfuck-Quellbefehl zu einem 16-Bit-Computerbefehl kompiliert werden muss.


Allgemeine Beschreibung der Anweisungen


Alle Anweisungen sind 16-Bit. Aus mehreren Teilen geformt.


  • Bits 15, 14, 13 - bestimmen die Unterrichtsklasse
  • Bit 12 - Vorzeichenbit für Vorzeichenanweisungen
  • Bits 11-0 - enthalten die unteren 12 Bits des vorzeichenbehafteten int-a. Die höchstwertigen 4 Bits werden gemäß dem Wert des 12. Bits gebildet.

Anweisungstabelle


BedienungsanleitungOpcodeBedienungEntspricht BrainfuckBeschreibung
füge m16 hinzu0X XXAP ← AP + m16'+' (M16 mal wiederholen)Fügt die Basis zum aktuellen Wert der ausgewählten Zelle hinzu
sub m161X XXAP ← AP - m16'-' (m16 mal wiederholen)Dementsprechend subtrahiert es die Basis von
ada m162X XXAP ← AP + m16'>' (M16 mal wiederholen)Erhöht den Wert der Adresse
Anzeigen m163X XXAP ← AP - m16'<' (M16 mal wiederholen)Verringert den Adresswert.
jz m164X XX(* AP == 0)? IP ← IP + m16: IP ← IP'['Gehen Sie zu IP + m16, wenn der Wert der aktuellen Zelle Null ist
jz m165X XX(* AP == 0)? IP ← IP - m16: IP ← IPNeinGehen Sie zu IP - m16, wenn der Wert der aktuellen Zelle Null ist
jnz m166X XX(* AP! = 0)? IP ← IP + m16: IP ← IPNeinGehen Sie zu IP + m16, wenn der Wert der aktuellen Zelle nicht Null ist
jnz m167X XX(* AP! = 0)? IP ← IP - m16: IP ← IP']'Gehen Sie zu IP - m16, wenn der Wert der aktuellen Zelle nicht Null ist
und m168X XXAP ← AP UND m16NeinLogisches UND mit einer positiven Zahl
und m169X XXAP ← AP UND m16NeinLogisches UND mit einer negativen Zahl (jemand anderes muss die hohen 4 Bits bilden)
oder m16aX XXAP ← AP ODER m16NeinLogisches ODER mit positiver Konstante
oder m16bX XXAP ← AP ODER m16NeinLogisches ODER mit negativer Konstante
inc0 00* AP ← CIN','Lesen Sie ein m8-Zeichen von der Konsole. Wenn der Eingabepuffer leer ist, warten Sie darauf.
rausc0 01COUT ← * AP'.'M8-Zeichen auf die Konsole drucken
clr.apd0 01AP ← 0NeinAP-Register löschen. Der Befehl ermöglicht die Kombination
clr.ipd0 02IP ← 0NeinIP-Register löschen. Der Befehl ermöglicht die Kombination
clr.dpd0 04* AP ← 0'[+]' oder '[-]'Speicherzelle löschen. Der Befehl ermöglicht die Kombination
set.apd0 10AP ← * APNeinSchreiben Sie den aktuellen Wert in das AP-Register
set.ipd0 20IP ← * APNeinSchreiben Sie den aktuellen Wert in das IP-Register
get.ap.d1 00* AP ← APNeinLesen Sie den aktuellen Wert aus dem AP-Register
get.ip.d2 00* AP ← IPNeinLesen Sie den aktuellen Wert aus dem IP-Register
mode.b8e1 00Nein8-Bit-Aktivierung (1)
mode.b16e2 00Nein16-Bit-Aktivierung
haltf0 00NeinMaschine anhalten

  • AP - Adressregister
  • IP - Anweisungsregister
  • * AP - Aktueller Speicherort
  • CIN - Konsoleneingang
  • COUT - Konsolenausgabe

  1. Wenn der 8-Bit-Modus aktiviert ist, arbeitet der Addierer im 16-Bit-Modus weiter. Bedingte Anweisungen (nämlich Testen des Werts der aktuellen Speicherzelle auf Gleichheit mit Null) werden jedoch 8-Bit. ( AP & 0x00FF == 0)? und ( AP & 0x00FF! = 0)? Die bisherige Eingabe und Ausgabe der Konsole hat beschlossen, immer 8-Bit zu belassen. Nicht in Unicode zum Drucken am Ende?

In diesem Video habe ich ausführlich (aber wenig verstanden) darüber gesprochen, was jede Anweisung tut und welchen Brainfuck-Anweisungen sie entspricht:



Paralleladdierer


Relaiscomputer sollten nicht nur Relais sein, sondern auch schnell. Wie jeder andere Computer wird auch mein Computer eine Synchronmaschine sein, die mit einem Taktgenerator ausgestattet ist. Natürlich möchte ich keine Taktzyklen verschwenden und versuchen, jede Operation in einen Zyklus zu integrieren - das heißt, für die ansteigenden und abfallenden Flanken des Synchrongenerators kann ich einen neuen Befehl laden und ausführen. Gleichzeitig ist es wünschenswert, dass alle Befehle für den gleichen Zeitraum ausgeführt werden.


Jedes Relais hat eine bestimmte Verzögerung bei Betrieb und Freigabe, die wir für 1 herkömmliche Zeiteinheit (cu) benötigen. Wenn wir das Relais RES22 verwenden, 1u.e. entspricht 12-15 ms (informativ), RES64 - 1,3 ms (informativ). Die teuerste (und häufigste) Operation in meinem Auto ist der Addierer.
An sich ist es recht einfach und schnell, aber "es gibt eine Einschränkung", die in der Methode zur Berechnung und Übertragung des Übertragungssignals liegt.



Abbildung 2: Serial Transfer Addierer.


Anfangs wollte ich einen sequentiellen Carry-Addierer verwenden. Bei einem solchen Addierer hängt jede nachfolgende Entladung vom Zustand des Entladungsübertragungssignals des aktuellen ab. Infolgedessen schwankt die Dauer des Berechnungsvorgangs zwischen 2 cu - N * 2 cu, wobei N die Anzahl der Ziffern ist. Infolgedessen hat ein sequentieller 16-Bit-Übertragsaddierer eine maximale Verzögerung von 32 cu


Parallel Carry Addierer bieten maximale Leistung. Ihnen fehlen die Ausbreitungsprozesse von Übertragungen von Entladung zu Entladung. In jeder Kategorie werden gleichzeitig Ausgabewerte generiert:



Abbildung 3: Paralleler Carry-Addierer


Die Fähigkeit, einen Addierer mit den angegebenen Eigenschaften zu erstellen, basiert auf der Reproduktion der Summen- und Übertragungsfunktionen, die unabhängig vom Ort der Entladung im Entladungsnetz nur von den Werten der Terme abhängen. Der Haken ist, dass das parallele Übertragungsschema selbst mit jeder nachfolgenden Entladung komplizierter wird. Hier sehen Sie, was passiert:



Abbildung 4: (Was in Form von LaTeX-Formeln hätte sein sollen, aber nicht) Die Gleichung zur Berechnung des Übertragungssignals für die Bits. Wo ki=ai cdotbi- bitweise Und, hi=ai+bi- bitweise ODER


Infolgedessen ist die Implementierung einer parallelen Migration ziemlich teuer. Es kann jedoch angemerkt werden, dass die nächste Entlastung die Gleichung zur Berechnung der vorherigen enthält (es sollte ein Mem „okay ??“ mit Nicolas Cage geben), daher reicht es im Prinzip aus, ein Transferberechnungsschema nur für die vorrangige Entlastung zu erstellen und den Rest daraus zu sammeln, sofern Abschluss der Zwischenergebnisse.



Abbildung 5: Vollständiges Diagramm eines 16-Bit-Paralleladdierers


In Abbildung 5 sind die ersten beiden Spalten die Addierer selbst. Dann gibt es die Blöcke 2AND und 2OR, die Zwischenwerte von h und k bilden, die in 4 gezeigt sind. Ihre Anwesenheit veranlasste mich, die Liste der Befehle um logische Operationen der Addition und Multiplikation zu erweitern, für die ich nur ein paar Latches und den entsprechenden Mikrocode hinzufügen muss.


Alles andere sind 5AND-Blöcke, die auf 4 RES64-Relais basieren und so verlötet werden können, dass ein Modul beispielsweise als 2AND + 3AND verwendet werden kann. Bei diesen Blöcken wird jeder logische UND-Schritt über eine Diode ausgegeben, mit der Sie Zwischenübertragungssignale sammeln können.


Geschätzte Signalausbreitungszeit: Addierer bewältigen 1 cu, zu diesem Zeitpunkt werden Signale an den Ausgängen von 2AND / 2OR-Blöcken erzeugt, dann 1 cu - Durch Multiplikation in 5AND-Blöcken führt die logische Addition von Dioden nicht zu einer Verzögerung. Nun, der letzte für die Neuberechnung des Addierers ausgegeben.


Insgesamt 3 cu gegenüber 32 oder nicht mehr als 4,5 ms für den Addierer.


Register


Es gibt vier 16-Bit-Spezialregister in der Maschine. Keine RONs. Nur enge Bindung, nur Hardcore! Es besteht aus D-Flip-Flops, jedes D-Flip-Flop ist ein separates Modul auf 4 RES55-Relais mit folgender Schaltung:



Abbildung 6: Schematische Darstellung des D-Flip-Flop-Moduls. Irgendwo gibt es noch einen Stecker, aber hier ist es nicht wichtig, weil alles signiert ist.


Daten kommen an den Dateneingang, dessen Relais bestimmt, wohin das Synchronisationssignal geleitet wird - um den Trigger zurückzusetzen oder zu installieren (wofür zwei weitere Relais verantwortlich sind, eines mit Selbsthemmung). Das vierte Relais erhält den Schaltausgang Q. Eine sehr nützliche Funktion.


Speicherkarte



Abbildung 7: Speicherkarte. Plattenabmessungen 315x200mm


Ein sehr komplexes und wichtiges Element, obwohl die Speicherschaltung selbst einen kleinen Teil der gesamten Füllung des Blocks ausmacht. Die Aufgabe dieser Karte besteht zum einen darin, 64 Kiloslovos des gesamten Speichers von Programmen und Daten zu transportieren. Es besteht aus zwei 64-KByte-Cache-Chips. Die über die Schutzschaltungen und den Schalter eingegebene Adresse ist mit dem Computeradressbus verbunden, und auf der Datenbusseite ein komplexes System aus Eingangspuffer und Ausgangstreiber, ebenfalls mit dem Schalter. Für das Lesen und Schreiben in den Speicher sind zwei Zeilen W / R und Sync verantwortlich. Der erste wählt, was wir tun werden, der zweite - wird es tatsächlich tun.


Und während diese Synchronisierung selbst nicht vorhanden ist, lebt die Speicherkarte natürlich ihr eigenes Leben. Auf dem Render sehen Sie zwei 16x16 LED-Matrizen. Diese Anzeige zeigt einen Speicherbereich. Eine Art VideoRAM, das übrigens programmgesteuert bestimmt wird. Fragt den Speicherchip ab und steuert den Ausgang des Atmega1280-Mikrocontrollers.


Für sim enden die Aufgaben des Mikrocontrollers nicht dort. Konsoleneingabe und -ausgabe hängen daran. Wo es ausgegeben wird - ich habe mich noch nicht entschieden, daher sind der USB-Serial-Konverter für eine normale Konsole und ESp8266 für Wi-Fi auf der Platine geschieden. Letzteren zufolge in den dringendsten Plänen eine Webseite mit der Möglichkeit, Programme für den Computer in den Speicher und die Konsole selbst herunterzuladen. Ja, zu den Aufgaben von MK gehört auch das erstmalige Laden des Programms in den Arbeitsspeicher, für den es vollen Zugriff auf den Arbeitsspeicher hat, sowie ein kleines 1-Mbit-EEPROM-In zum Speichern von Programmen.



Abbildung 8: Schematische Darstellung einer Speicherkarte. Mikrocontroller- und Blockdiagramme nicht gezeigt


Logikblock


Ich habe keine Ahnung, wie er am Ende aussehen wird. Die neueste Version ist auf der allgemeinen Computerschaltung vorhanden, aber ich mag es nicht. Höchstwahrscheinlich werde ich einen 12-stufigen Sequenzer bauen und mit Hilfe von Tasten Signale an einzelne Blöcke senden.



Abbildung 9: Alles um 16-Bit-Blöcke herum ist ein Logikblock


Bau


Der Aufbau der Maschine ist modular, Blockrahmen. Das KDPV zeigt deutlich, wie sich die Befüllung der Maschine befindet. Aber das Wichtigste zuerst:


Modul


Das Grundelement des Computers ist ein 60 x 44 mm großes Modul mit einem 16-poligen Stecker, der 4 Relais, deren Kabelbaum und 4 LEDs trägt, um Folgendes anzuzeigen:



Abbildung 10: 3D-Modell des Moduls


Module verschiedener Typen:


  1. 1-Bit-Addierer mit Übertragung - 16 Stück;
  2. 5AND-Modul für parallele Übertragungsschaltung - 32 Stück;
  3. D-Flip-Flop-Modul - 64 Stück pro Register plus ein wenig Logik;
  4. Modul 4x2AND_SW zum Organisieren von Latches. Es gibt nur 4 Schließrelais;
  5. 4x2AND-Modul zum Organisieren von Latches. Es gibt 3 von 4 Relais mit einem Wechselkontakt. Bei 4 Relais war nicht genügend Ausgangsstift vorhanden.
  6. Das Modul ist eine Diode, 8 Dioden D226D. So organisieren Sie ein ODER mit mehreren Eingängen
  7. Mit dem Universalmodul 2AND / 2OR können Sie 2AND-NOT, 2OR-NOT, 4AND, 4AND-NOT, 4OR, 4OR-NOT und eine beliebige Kombination erstellen. Basierend auf 4 Relais mit Schaltkontakten und gemeinsamen Punkten;

Da ich, obwohl ich einen Block der Steuerlogik gefunden habe, bereits abgelehnt habe, kenne ich nicht die genaue Anzahl der Module jedes Typs. Ich werde es auf der Straße herausfinden. Die geschätzte Anzahl der Module beträgt 192 Stück.


Blockieren


Wir nehmen eine 150x200mm Platine, löten 32 Stecker mit 16 Pins darauf, aber keine einfachen, aber zum Einwickeln und Installieren unserer Module darauf in einer 8x4 Matrix, um einen solchen Block zu erhalten:



Abbildung 11: Block


In meinem Auto gibt es 6 solcher Blöcke - zwei Blöcke pro Addierer, zwei Blöcke pro Register und zwei Blöcke pro Logik. Ich kratzte Rüben über ein paar weitere Riegelblöcke, aber wenn sie es sind, dann sind sie flach und verlötet


Die Runduminstallation wurde gewählt, weil: Erstens kann sich die Schaltung jeder Basisplatine ändern, obwohl sie im Voraus bekannt ist, und ist fehleranfällig. Zweitens ist es im Prinzip unmöglich, den Logikblock beim ersten Mal korrekt zu trennen. Wenn für den Registerblock alles klar ist und Sie beispielsweise mit einer Synchronisationsleitung einen Fehler machen können, müssen Sie die Logik tausend und einmal wiederholen. Es ist viel besser, wenn Sie jede Komponente des Logikblocks schrittweise erfassen. Drittens ein rein mechanischer Faktor - es ist physikalisch unmöglich, diese Blöcke auf einem zweilagigen Brett zu trennen :) 16-Bit-Reifen divergieren in viele Richtungen, die sich wiederholt überschneiden.


Insgesamt enthält jede Einheit 32 Module mit einer Gesamtzahl von 128 Relais. Die Leistung jeder Einheit beträgt 5V 2A.


Computer


Auf einem großen Rahmen mit Abmessungen von 640 x 480 mm (tatsächlich etwas mehr, aber die Anzahl ist wunderschön) befinden sich sechs Relaisblöcke und eine Speicherplatine:



Abbildung 12: Position der Maschinenblöcke


Der gesamte Computer wird in einen Holzrahmen aus Edelholz mit Glas vorne und hinten eingesetzt.


Herstellung


Trotz des aktuellen Datums existiert das Projekt tatsächlich :-) Und es befindet sich nicht in der aktivsten, aber noch in der Herstellungsphase.


Relais


Ich habe sie In großer Zahl, aber das Problem ist, dass es dreihundert von mehr als tausend Lagerbeständen gibt - ein Relais mit 27 Volt und 5 Volt RES55 reicht mir möglicherweise nicht aus. Ich kann das Ausmaß der Katastrophe nicht endgültig abschätzen, aber ich denke, dass das Problem beim nächsten Mal, wenn ich diese Höllenmaschine einsammle, aufgrund der Wiederauffüllung von außen verschwinden wird.



Abbildung 13: Relaisreserven 800 Relais - neu, erfolgreich auf dem Mitsa-Radiomarkt für einen Cent beschlagnahmt


Eine der Nachschubquellen sind die DAC-Relaisplatinen aus Labornetzteilen. Hier sind diese:



Abbildung 14: Karten von Netzteilen, die auf dem Funkmarkt gekauft wurden (nein, das bin ich nicht)


Leiterplatten


Ich habe beschlossen, alle Leiterplatten selbst zu machen. Ich habe 300 Dollar an die Chinesen geklemmt und seit 4 Monaten arbeite ich daran, die Rohlinge mit Fotolack zu bedecken, durchscheinend, zu ätzen, mit einer Lötmaske zu bedecken, zu entwickeln, zu bohren und zu fräsen.



Abbildung 15: Geätzte Platten verschiedener Art


Ich mache Platten in Platten, 9 Module auf einer 200x150mm Platte. 30 Platten geätzt und beim Auftragen einer Lötmaske aufgeklebt. Ich werde in keiner Weise anfangen. Die Lötmaske meines FSR-8000 ist blau, zweikomponentig und ich habe mich bereits zuvor damit befasst.


200150 — , .


(- ) . .


, 3- .



16: 3D- DIY 2020CNC


175 . , + 3-. , — .


:



Programme


, . ( ) Elf. , ( ). //TODO — , .


: . , . . Segmentation Fault!


, . — . leBrainfuck , .
, , Brainfuck . +-<>, [-] . , . , .


. 8 . :



— 10 . LLVM 0,9 . Intel Vtune Amplifier 120 10 .


. , 3 brainfuck-. 100 50 347 — .. , ! , , . .


, , ,



.



-6 , , . — , . — . - — 30-40 - 6 .


????777



Referenzen


openSource. :


  1. https://github.com/radiolok/RelayComputer2 - ein Repository mit schematischen Diagrammen und Leiterplattenlayouts. Einen Link zum Firmware-Repository der Speicherplatine werde ich später hinzufügen
  2. https://github.com/radiolok/RelayComputer2/blob/master/roadmap.md Ich werde diese Seite mit der Projekt-Roadmap, auf der wichtige Änderungen aufgezeichnet werden, separat vermerken.
  3. https://hackaday.io/project/18599-brainfuck-relay-computer Auf dieser Seite veröffentliche ich detaillierte Berichte darüber, was getan wurde. Je nach kritischer Masse werden sie zu einem Artikel über GT.
  4. https://github.com/radiolok/bfutils Compiler und Emulator.

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


All Articles