Papiercomputer


Was ist das?

Der Know-how-Computer oder WDR-Papiercomputer besteht aus bedrucktem Papier. Er hat einen "Programmspeicher" in den man schriftlich ein Programm in einer fiktiven Assemblersprache aus nur fünf Befehlen eintragen kann.

Zur Ausführung des Programms verwendet man einen Kugelschreiber als Programmzeiger und Streichhölzer in "Registern" auf dem Papier um die aktuellen Werte darzustellen.

Mit diesem Spielzeug kann man programmiererisch denken lernen, ohne einen elektronischen Computer zur Verfügung zu haben. Somit diente dieser "Computer" als pädagogische Hilfe im Bereich der Informatik.

Der Computer wurde von Wolfgang Back und Ulrich Rohde entwickelt und in der Fernsehsendung WDR Computerclub im Jahre 1983 erstmals vorgestellt. Eine abgeleitete Version des Papier-Computers wird als Know How Computer in Namibia im Schulunterricht verwendet.

Diese Seite nimmt das Konzept und stellt es vollkommen auf den Kopf. Unter Verwendung von modernen Rechner mit graphischen Displays führen wir ein Programm in einer Umgebung aus, die dutzende von Schichten entfernt vom Assembler der zugrundeliegenden CPU ist. Mit diesen Mitteln stellen wir den Papiercomputer dar und erlauben die automatische Ausführung der mechanischen Schritte. Dabei erhalten wir die Optik von Papier-Layout, Kugelschreiber und Streichholz-Registern.

Architektur und Sprache

Der Papiercomputer (im Folgenden "PC" genannt) verfügt über einen konzeptionell unbegrenzt großen Programmspeicher, danke Alan. Die Zellen des Programmspeichers sind von 0..n durchnumeriert und jede Zelle nimmt genau einen Befehl in der PC-Assemblersprache auf.

Ein Programmablauf beginnt immer an der Adresse 0. Die Registerinhalte werden beim Reset nicht verändert, man kann sie also zur Eingabe von Daten verwenden. Man darf aber auch nicht voraussetzen, daß sie irgendwie initialisiert wären. Der PC hat kein RAM, zur Speicherung stehen nur die Register zur Verfügung.

PC-Assembler besteht aus genau fünf Befehlen:

Mnemonic Befehl Erklärung
jmp [addr] Jump to address Setzt den Programmzeiger auf die angegebene Adresse.
isz [register] Is zero Prüft den Inhalt des angegebenen Registers auf Null. Enthält es Null wird der Programmzeiger um zwei erhöht, sonst nur um eins. Bei einer Null wird also der folgende Befehl übersprungen.
inc [register] Increment Erhöht das angegebene Register um eins und den Programmzeiger um eins.
dec [register] Decrement Verringert das angebene Register um eins und erhöht den Programmzeiger um eins. Weil in einem Register nicht weniger als Null Streichhölzer liegen können, wird der Wert dann unverändert gelassen.
stp Stop Hält den Papiercomputer an. Das Programm ist beendet.

Programmierung

Der PC kann direkt in seinem Programmspeicher programmiert werden. Dazu gibt man die Befehle einfach direkt in die Zellen ein während der PC steht. Auf diese Weise kann man sogar ein Programm während des Betriebs verändern, wenn man den PC so lange anhält. Davon wird aber abgeraten...

Eine Alternative Möglichkeit besteht darin, Programme direkt in die URL zu schreiben. Diese Programme sind in ihrer Länge begrenzt, aber jeder kann sie als Link notieren und den PC direkt damit starten. Ein solcher Link kann aussehen wie dieser für ein Programm, das Register A löscht.

Bedienung

Der PC hat Schaltflächen mit denen man ihn einen einzelnen Schritt ausführen oder das Programm automatisch bis zum Ende oder einem Fehler ablaufen lassen kann.

Er zeigt seinen aktuellen Status in Form der Kugelschreiber-Position am Programmspeicher und der Streichhölzer in den Registern an. Wenn er wegen eines Fehlers oder einer stp-Anweisung anhält zeigt er dies in einem Statusdisplay an.

Wird als Schrittzeit 0 eingegeben und Run geklickt, so läuft der PC so schnell er kann und aktualisiert die Anzeige der Register erst am Ende des Programms.

Die Reset-Taste setzt den PC zurück, so daß als nächstes der Befehl an Programmspeicher-Position 0 ausgeführt wird. Progammspeicher und Registerinhalte bleiben dabei unangetastet.

Mit Clear Program wird der Programmspeicher gelöscht.

Der Computer

Control panel
step delay  ms Status:  paused
Program
# Befehl  
0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
 
Registers
Name Value
A 
B 
C 
D 
E 
F 
G 
H 
X 
Y 

Level Up

Der virtuelle Papiercomputer kann eine Ebene höher als der Papier-Papiercomputer programmiert werden. Er verfügt nämlich über einen Assembler (das Programm, nicht die Sprache).

Eingabe für den Assembler ist Text in seinem Eingabefeld, die Ausgabe erfolgt direkt in den Programmspeicher des PC. Zusätzlich zu den fünf PC-Assemblerbefehlen kann das Assemblerprogramm auch noch folgende Konstrukte verstehen und "übersetzen":

Konstrukt Funktion Erklärung
Leerzeilen No Operation Leerzeilen im Text werden vom Assemblerprogramm einfach ignoriert. Man kann sie also verwenden um den Programmtext zu in Abschnitte zu gliedern.
;[kommentar] Kommentar Text von einem Semikolon bis zum Ende der Zeile ist ein Kommentar und wird vom Assemblerprogramm ignoriert. Wenn die Zeile ausschließlich aus Kommentar besteht, siehe Leerzeile.
[label]: Label Weil es schwierig ist, in einem Programm mit Leerzeilen und Kommentaren Sprungziele als Adressen anzugeben kann das Assemblerprogramm symbolische Namen durch die richtigen Addressen ersetzen. Als Nebeneffekt kann man so ein Programm besser lesen und muss nicht alle Adressen neu auszählen wenn man mal etwas verändert.
Ein solches Label wird am Anfang einer Zeile deklariert und kann dann anstelle einer numerischen Addresse in jmp-Befehlen verwendet werden. Labelnamen sind Worte ohne Leerzeichen die nicht mit einem Registernamen oder einer Zahl verwechselt werden können.
Assembler 

Beispielprogramme

Die Beispielprogramme sind für den PC-Assembler geschrieben und können direkt in ihn geladen, assembliert und dann gestartet werden.

Register A nullen   
; Dieses Programm nullt das Register AwhileA: isz A ; Ist A=0?jmp decA      ; Nein, weiter bei decAjmp done      ; Ja, Sprung zum EndedecA: dec A   ; A um eins verringernjmp whileA    ; Sprung zum Anfang, wieder testen.done:stp           ; Fertig.
Register A nach Register B kopieren   
; Dieses Programm kopiert das Register A nach B; Es benutzt dabei das Register X und zerstört den Wert, der; dort gespeichert sein könnte.; Zuerst wird B ausgenullt.whileB: isz B ; Ist B=0?jmp decB      ; Nein, weiter bei decBjmp clearX    ; Ja, Sprung zum nächsten AbschnittdecB: dec B   ; B um eins verringernjmp whileB    ; Sprung zum Anfang, wieder testen.; Dann wird das temporär genutzte Register; X genullt.clearX:isz Xjmp decXjmp processAdecX:dec Xjmp clearX; Wir kopieren den Wert aus A nach X und CprocessA:isz A			; Ist A=0?jmp inc			; Nein, weiter bei incjmp restoreA	; Ja. Weiter zur Wiederherstellung von Ainc:dec Ainc Binc Xjmp processA; Wir restaurieren den Wert in A aus X.restoreA:isz Xjmp incAjmp doneincA:inc Adec Xjmp restoreAdone:stp           ; Fertig.
C=A+B mit Überschreiben   
; Dieses Programm addiert die Werte in Register A und B und; speichert das Ergebnis in Register C. Dabei werden A und B; ausgenullt. Das macht das Programm gegenüber der erhaltenden; Addition (nächstes Beispiel) viel kürzer und braucht keine; Zusatzregister.; Im ersten Schritt wird das Zielregister C ausgenullt.clearC:isz Cjmp decCjmp processAdecC:dec Cjmp clearC; Wir kopieren den Wert aus A nach CprocessA:isz Ajmp incjmp processBinc:dec Ainc Cjmp processA; Jetzt kopieren wir den Wert aus B nach C.; In C steht nachher die Summe.processB:isz Bjmp inc2jmp doneinc2:dec Binc Cjmp processB; Fertig.done: stp;
C=A+B   
; Dieses Programm addiert die Werte in Register A und B und; speichert das Ergebnis in Register C. Es benutzt dabei das Register X; und zerstört den Wert, der dort gespeichert sein könnte.; Im ersten Schritt wird das Zielregister C ausgenullt.clearC:isz Cjmp decCjmp clearXdecC:dec Cjmp clearC; Dann wird X genullt.clearX:isz Xjmp decXjmp processAdecX:dec Xjmp clearX; Wir kopieren den Wert aus A nach X und CprocessA:isz Ajmp incjmp restoreAinc:dec Ainc Xinc Cjmp processA; Jetzt steht A in X und C, aber A=0; Wir restaurieren den Wert in A aus X.restoreA:isz Xjmp incAjmp processBincA:inc Adec Xjmp restoreA; Jetzt kopieren wir den Wert aus B nach X und C; X ist 0, wird also wieder eine Sicherheitskopie.; Und in C steht nachher die Summe.processB:isz Bjmp inc2jmp restoreBinc2:dec Binc Xinc Cjmp processB; Wir restaurieren den Wert in B aus X.restoreB:isz Xjmp incBjmp doneincB:inc Bdec Xjmp restoreB; Fertig.done: stp;
C=A-B mit Überschreiben   
; Dieses Programm brechnet A - B und speichert das Ergebnis in; Register C. Ist B größer als A ist das Ergebnis 0. Dabei wird; A ausgenullt und B auch verändert. Das macht das Programm gegenüber; der erhaltenden Subtraktion (nächstes Beispiel) viel kürzer und; braucht keine Zusatzregister.; Im ersten Schritt wird das Zielregister C ausgenullt.clearC:isz Cjmp decCjmp processAdecC:dec Cjmp clearC; Wir kopieren den Wert aus A nach CprocessA:isz Ajmp incjmp processBinc:dec Ainc Cjmp processA; Jetzt ziehen wir den Wert aus B von C ab.; In C steht nachher die Differenz oder 0.processB:isz Bjmp checkCjmp donecheckC:; Optimierung: Falls C vor B 0 wird können wir; aufhören. Als Nebeneffekt enthält B dann außerdem; B-A, aber das war nicht gesucht.isz Cjmp decjmp donedec:dec Cdec Bjmp processB; Fertig.done: stp;
C=A-B   
; Dieses Programm berechnet die Differenz von A und B und; speichert sie in Register C. Ist B größer als A, so ist; das Ergebnis 0 . Es benutzt dabei das Register X; und zerstört den Wert, der dort gespeichert sein könnte.; Im ersten Schritt wird das Zielregister C ausgenullt.clearC:isz Cjmp decCjmp clearXdecC:dec Cjmp clearC; Dann wird X genullt.clearX:isz Xjmp decXjmp processAdecX:dec Xjmp clearX; Wir kopieren den Wert aus A nach X und CprocessA:isz Ajmp incjmp restoreAinc:dec Ainc Xinc Cjmp processA; Jetzt steht A in X und C, aber A=0; Wir restaurieren den Wert in A aus X.restoreA:isz Xjmp incAjmp processBincA:inc Adec Xjmp restoreA; Jetzt kopieren wir den Wert aus B nach X und; verringern dabei C. X startet bei 0, wird also; wieder eine Sicherheitskopie. Und in C steht; nachher die Differenz.processB:isz Bjmp checkCjmp restoreBcheckC:isz Cjmp decjmp restoreBdec:dec Binc Xdec Cjmp processB; Wir restaurieren den Wert in B aus X.restoreB:isz Xjmp incBjmp doneincB:inc Bdec Xjmp restoreB; Fertig.done: stp;
C=A*B   
; Dieses Programm berechnet das Produkt der Werte in Register A; und B und speichert das Ergebnis in Register C. Es benutzt dabei; die Register X und Y und überschreibt Werte, die dort gespeichert; sein könnten.; Der verwendete Algorithmus ist wiederholtes Addieren: A wird B mal; zu C addiert. Damit die Begister A und B am Ende ihre Werte behalten; haben addieren wir auf dem Rückweg aus dem temporären Register.; Es gibt hier Optimierungsansätze, aber die machen das Programm; länger...; Im ersten Schritt wird das Zielregister C ausgenullt.clearC:isz Cjmp decCjmp clearXdecC:dec Cjmp clearC; Dann wird X genullt, es soll den temporären Wert von A halten.clearX:isz Xjmp decXjmp clearYdecX:dec Xjmp clearX; Dann wird Y genullt, es soll den temporären Wert von B halten.clearY:isz Yjmp decYjmp loopBdecY:dec Yjmp clearY; Für jedes Streichholz in B kopieren wir jetzt A nach X und dann; wieder zurück. Auf dem Rückweg schreiben wir auch in C. So ist am; Ende jedes Durchgangs A wieder auf dem alten Wert, X wieder 0 und; C um einmal A erhöht.loopB:isz Bjmp copyAXjmp restoreBcopyAX:isz Ajmp incXjmp copyXAincX:dec Ainc Xjmp copyAXcopyXA:isz Xjmp addjmp decBadd:inc Ainc Cdec Xjmp copyXAdecB:dec Binc Yjmp loopB; Wir restaurieren den Wert in B aus Y.restoreB:isz Yjmp incBjmp doneincB:inc Bdec Yjmp restoreB; Fertig.done: stp;
C=A/B   
; Dieses Programm berechnet die Division.; Register C erhält den ganzzahligen Quotienten C = ⌊A/B⌋ und Register; den Rest D = A mod B.; Es verwendet die Register X, Y und Z für temporäre Daten und; überschreibt die Daten darin.; Ist B = 0 wird C = 0 und D = 0 ausgegeben.; 0 => CclearC:isz Cjmp decCjmp clearDdecC:dec Cjmp clearC; 0 => DclearD:isz Djmp decDjmp checkBdecD:dec Djmp clearDcheckB:; Falls B=0 ist sind wir hier schon fertig.isz Bjmp clearXjmp done;; 0 => XclearX:isz Xjmp decXjmp loopCopyAXdecX:dec Xjmp clearX; A => XloopCopyAX:isz Ajmp doCopyAXjmp clearYdoCopyAX:dec Ainc Xjmp loopCopyAX; 0 => YclearY:isz Yjmp decYjmp loopCopyBYZdecY:dec Yjmp clearY; B => YloopCopyBYZ:isz Bjmp doCopyBYZjmp loopDivdoCopyBYZ:inc Ydec Bjmp loopCopyBYZ; Jetzt haben wir C = 0 und so vorbereitet für den Quotienten; Das Ergebnisregister D für den Rest ist auch 0. A ist nach X; umgefüllt und B ist auch 0, sein Wert wurde nach Y umgefüllt.; Y werden wir für die wiederholte Subtraktion verwenden.; Hier steigen wir wieder ein, so lange X noch Streichhölzer hat,; also der Dividend nicht ganz verbraucht ist.loopDiv:; Wir legen Streichhölzer aus Z nach B und gleichzeitig aus X; zurück nach A.; Damit subtrahieren wir den Quotienten einmal vom Ergebnis.; Falls uns die Streichhölzer in X reichen erhöhen wir den Quotienten; einmal und legen sie für die nächste Iteration aus B zurück nach; Z.; Gehen unterwegs die Streichhölzer in X aus hat B jetzt den Rest. Wir; legen diese zurück nach Z und D damit am Ende der Rest in D steht.isz Xjmp sub1jmp doneDivsub1:; Müssen wir noch Divisor abziehen?isz Yjmp doSub1jmp doneSub1doSub1:; Haben wir noch Dividend übrig von dem wir abziehen können?isz Xjmp havejmp haveNothave:; Ein Streichholz aus X nach Adec Xinc A; Ein Streichholz aus Y nach Bdec Yinc Bjmp sub1; Einmal erfolgreich den ganzen Divisor abgezogen.doneSub1:; Quotient erhöheninc C; B zurück nach Y für die nächste Runde.loopRestoreY:isz Bjmp doRestoreYjmp loopDivdoRestoreY:dec Binc Yjmp loopRestoreYhaveNot:; Der Dividend ist uns ausgegangen. Der Rest ist jetzt in B.; Wir füllen ihn von dort ins Ergebnis nach D um und gleichzeitig; zurück nach Y.loopRestoreYD:isz Bjmp doRestoreYDjmp doneDivdoRestoreYD:dec Binc Yinc Djmp loopRestoreYDdoneDiv:; Wir sind fast fertig: Der ganze Dividend ist zurück nach A gewandert.; Der Quotient ist im Ergebnisregister C, und der Rest in D. Es fehlt nur; noch den Divisor von Y zurück nach B zu schieben.loopRestoreB:isz Yjmp doRestoreBjmp donedoRestoreB:inc Bdec Yjmp loopRestoreB; Fertig.done: stp;

Was kann der Papiercomputer?

Kurze Antwort: Kommt drauf an, wieviel Papier man hat.

Lange Antwort: Alles, was ein Computer im Allgemeinen berechnen kann.

Obwohl der PC nur fünf Befehle kennt und nicht einmal wirklich rechnen, sondern eigentlich nur vorwärts und rückwärts zählen kann, ist er Turing-vollständig[1]. Das bedeutet, er kann alles berechnen, was überhaupt berechenbar ist. Jedenfalls wenn man ihm genug Papier und Register gibt.

[1]: Ohne Beweis. Der PC kann entscheiden und verzweigen, das führt zur starken Intuition der TV. Wem das nicht reicht, möge den geneigten Leser geben und mir einen Beweis schicken.

20 Gedanken zu „Papiercomputer“

  1. Unglaublich informativ! Dankedanke für diese Implementation für die Verschmierung!
    Ich werde mich gleich direkt zuhause an die Rechner schmeißen und fröhlich
    drauf losprogrammieren 🙂

    Public void Abmelden()
    {
    LG CC
    }

    Antworten
  2. Noch nicht getestet aber sehr interessant. Kenne es noch von damals und wiederentdeckt. Gibt es das denn eigentlich auch in englisch? I lebe und arbeite in UK und bin hier beim RPI Club. Was mich noch interessieren wuerde ist, ueber ein serielles Interface etwas externes zu verbinden , und sozusagen die LED anzuschalten und einen Taster abzufragen. Geht das? Vielleicht zur Info ein aehnliches Projekt TPS von Burkhard Kainka und Willie Klaas http://elektronik-labor.de/Lernpakete/TPS/TPS20.html

    Antworten
  3. Was für ein Wahnsinn! Super toller Computer. Billig, sogar kostenlos und man kann ihn überall mit hinnehmen. Wer braucht schon einen Laptop, wenn man auch einen Papiercomputer ausdrucken könnte. Praktisch und sowieso viel besser. Ich bin begeistert. werde ich all meinen 17 Kindern zu Weihnachten schenken.

    Antworten
  4. Eine wunderbare Gabe des Schöpfers! Ich konnte somit endlich Minecraft programmieren. Vielen Dank mein Leben hat wieder einen Sinn, ich war schon kurz davor es zu beenden. Ranald sei mit dir.

    Antworten
  5. Servus! Ich habe folgende Verständnisprobleme:
    1. Der Stift wird einmal als "Programmzähler", ein andermal als "Programmzeiger" bezeichnet. Das stiftet m. E. unnötig Verwirrung (pun not intended).
    2. Die Abkürzung "PC" wird nicht aufgelöst.

    Antworten
    • Vielen Dank für das detaillierte Feedback!

      Ich habe zu "Programmzeiger" vereinheitlicht. Obwohl man ja in Mikroprocessoren oft "program counter" zu dem entsprechenden Register sagt, finde ich dass der Stift eher ein Zeiger als ein Zähler ist.

      Und PC als Abkürzung für "Papiercomputer" stand schon unter "Architektur und Sprache". Ich habe das ein bisschen ausführlicher formuliert.

      Antworten
  6. Dank an meinen Lehrer (TangaTiger) für dieses wunderbare konztruckt. Ich möchte jetzt nichts lieber als aus dem Fenster zu springen. Vielen dank für diese Schulstunde TT.
    LG dein Bester Schüler

    Antworten

Schreibe einen Kommentar zu Arneg Antworten abbrechen