Zum Inhalt springen
Zurück zur Themenübersicht

Technische Informatik

Vom Halbaddierer zum von-Neumann-Rechner

Wie aus zwei Gattern ein Addierwerk wird und warum die Idee, Programme wie Daten zu speichern, alles verändert hat.

Benötigte Grundlagen

Dieses Vorwissen brauchst du für das Kapitel. Schau kurz nach, wenn dir etwas davon nicht mehr präsent ist, sonst leg direkt los.

Einführung

Bis hierher stehen zwei Dinge nebeneinander: Rechnen mit auf der einen Seite, und Schaltterme auf der anderen.

Dieses Kapitel verbindet beides. Aus zwei Gattern wird ein Halbaddierer, aus zwei Halbaddierern ein Volladdierer, aus mehreren Volladdierern ein Rechenwerk, das ganze Zahlen addiert.

Und dann kommt der Schritt, der aus einer Rechenmaschine einen Computer macht. Er besteht nicht aus mehr Bauteilen, sondern aus einer Idee: Das Programm steht im selben Speicher wie die . Was daraus folgt, prägt jeden Rechner bis heute.

Das kannst du nach diesem Kapitel

  • den Halbaddierer aus seiner herleiten.

  • erklären, warum ein Volladdierer nötig ist und wie er aus Halbaddierern entsteht.

  • die Bestandteile der von-Neumann-Architektur und ihre Aufgaben benennen.

  • den Befehlszyklus beschreiben und ein Programm gedanklich abarbeiten.

  • Vorteile und Grenzen des Architekturprinzips beurteilen, darunter den Flaschenhals (Vertiefung).

Kurz aufgefrischt

Vorausgesetzt werden die und die aus Schaltalgebra, die aus Rechnen mit Dualzahlen sowie , Prozessor, Speicher und Bus aus Aufbau von Informatiksystemen.

Neu ist, wie beides zusammenhängt: Wie werden aus Gattern Rechenwerke, und wie wird aus einem Rechenwerk ein Computer?

Der Halbaddierer

Gesucht ist eine Schaltung, die zwei addiert. Ergebnis sind zwei Bits: die Summe ss und der cc.

aabbsscc
0000
0110
1010
1101

Die letzte Zeile ist der interessante Fall: 1+1=1021 + 1 = 10_2, also Summe 0 mit Übertrag 1.

Jetzt wendet man einfach das Verfahren aus dem vorigen Kapitel an, für jede Ausgangsspalte einzeln.

Für ss: Einsen in den Zeilen 0101 und 1010, also

s=(aˉ∧b)∨(a∧bˉ)=a⊕bs = (\bar{a} \land b) \lor (a \land \bar{b}) = a \oplus b

Das ist genau XOR.

Für cc: Eine Eins in Zeile 1111, also

c=a∧bc = a \land b

Der ganze Halbaddierer besteht damit aus einem XOR- und einem . Bemerkenswert daran ist nicht die Schaltung, sondern der Weg: Niemand musste sie sich ausdenken. Die Tabelle stand fest, das DNF-Verfahren lieferte den Rest.

Der Halbaddierer: zwei Gatter

abSumme s=1Übertrag c&s

Zwei , mehr braucht die Addition zweier nicht. Bemerkenswert ist dabei nicht die Schaltung, sondern der Weg dorthin: Niemand musste sie sich ausdenken. Die stand fest, und das DNF-Verfahren aus dem vorigen Kapitel lieferte für jede Ausgangsspalte einzeln das Ergebnis, für die Summe s=(aˉ∧b)∨(a∧bˉ)s = (\bar{a} \land b) \lor (a \land \bar{b}), was genau XOR ist, und für den c=a∧bc = a \land b, was genau UND ist. Prüfe den interessanten Fall nach: Bei a=b=1a = b = 1 liefert XOR eine 00 und UND eine 11, zusammen also 10210_2, und 1+1=21 + 1 = 2 stimmt.

Warum „halb“?

Warum „halb"?

Der Halbaddierer hat nur zwei Eingänge. Beim schriftlichen Addieren mehrstelliger Zahlen kommt aber an jeder Stelle außer der ersten noch der der vorigen Stelle hinzu:

  1 1 1        ← Überträge
  0 1 1 1
+ 0 0 1 1
---------
  1 0 1 0

An der zweiten Stelle sind drei zu addieren: 11, 11 und der eingehende Übertrag 11. Der Halbaddierer kann das nicht; er reicht nur für die niederwertigste Stelle. Daher der Name.

Der Volladdierer

Der Volladdierer hat drei Eingänge: aa, bb und den eingehenden ceinc_{\text{ein}}. Ausgänge sind wieder Summe ss und ausgehender Übertrag causc_{\text{aus}}.

aabbceinc_{\text{ein}}sscausc_{\text{aus}}
00000
00110
01010
01101
10010
10101
11001
11111

Man liest die Tabelle als Abzählen: ss ist 1, wenn eine ungerade Anzahl der Eingänge 1 ist; causc_{\text{aus}} ist 1, wenn mindestens zwei Eingänge 1 sind. Die zweite Bedingung kennst du bereits aus dem vorigen Kapitel.

Statt die aufzustellen, baut man ihn aus zwei Halbaddierern:

a ──┐
    ├─[HA 1]─ s1 ──┐
b ──┘        c1    ├─[HA 2]─ s   (Summe)
                   │
c_ein ─────────────┘   c2

c_aus = c1 OR c2

Warum das stimmt: Der erste Halbaddierer addiert a+ba + b und liefert die Zwischensumme s1s_1 und den Übertrag c1c_1. Der zweite addiert dazu ceinc_{\text{ein}} und liefert die endgültige Summe ss und einen zweiten Übertrag c2c_2.

Ein ausgehender Übertrag entsteht, wenn bei einer der beiden Additionen einer aufgetreten ist, also caus=c1∨c2c_{\text{aus}} = c_1 \lor c_2. Dass niemals beide zugleich auftreten, sieht man so: Liefert der erste Halbaddierer c1=1c_1 = 1, so waren a=b=1a = b = 1 und damit s1=0s_1 = 0; der zweite Halbaddierer addiert dann 0+cein0 + c_{\text{ein}} und kann keinen Übertrag erzeugen.

Der Volladdierer, alle acht Fälle

abc einsc aus0000000110010100110110010101011100111111

Acht Zeilen, weil drei Eingänge 23=82^3 = 8 Kombinationen haben. Lies die Tabelle nicht Zeile für Zeile, sondern als Abzählen: Die Summe ss ist genau dann 1, wenn eine ungerade Anzahl der drei Eingänge 1 ist. Das ist XOR über drei Eingänge. Und der ausgehende causc_{\text{aus}} ist genau dann 1, wenn mindestens zwei Eingänge 1 sind. Die zweite Bedingung kennst du bereits: Es ist die Funktion „mindestens zwei von drei“ aus dem vorigen Kapitel, samt ihrer vereinfachten Schaltung. So hängen die Kapitel zusammen, hier taucht als Übertragslogik wieder auf, was dort als Beispiel für das Vereinfachen diente.

Der Volladdierer aus zwei Halbaddierern

abc eins₁=1c₁&s=1c₂&c aus≥1s

Statt die für acht Zeilen aufzustellen, baut man ihn aus zwei Halbaddierern, und das Bild zeigt genau das: Die ersten beiden sind der eine (sie addieren a+ba + b), die nächsten beiden der andere (sie addieren ceinc_{\text{ein}} hinzu). Das ODER am Ende fasst die beiden zusammen. Warum das stimmt: Der erste Halbaddierer liefert die Zwischensumme s1s_1 und den Übertrag c1c_1; der zweite addiert ceinc_{\text{ein}} dazu und liefert die endgültige Summe ss und einen zweiten Übertrag c2c_2. Ein Übertrag kann dabei höchstens einmal entstehen, nie in beiden Halbaddierern zugleich, deshalb genügt am Ende ein ODER und es braucht keinen dritten Übertrag.

Der Paralleladdierer

Schaltet man nn Volladdierer hintereinander und verbindet jeweils causc_{\text{aus}} mit dem ceinc_{\text{ein}} des nächsten, entsteht ein Addierwerk für nn-stellige :

 a3 b3      a2 b2      a1 b1      a0 b0
  │  │       │  │       │  │       │  │
 ┌┴──┴┐     ┌┴──┴┐     ┌┴──┴┐     ┌┴──┴┐
 │ VA │←────│ VA │←────│ VA │←────│ HA │
 └──┬─┘     └──┬─┘     └──┬─┘     └──┬─┘
    s3         s2         s1         s0

An der niederwertigsten Stelle genügt ein Halbaddierer, weil dort kein hereinkommt.

Damit ist der Bogen geschlagen: Aus einem Gattertyp entsteht über ein Halbaddierer, daraus ein Volladdierer, daraus ein Rechenwerk. Und weil im vorigen Kapitel gezeigt wurde, dass sich Subtraktion, Multiplikation und Division auf Addition und Verschieben zurückführen lassen, kann dieses Werk alle vier Grundrechenarten.

Eine Grenze zeigt sich hier bereits: Der Übertrag muss von rechts nach links durchlaufen, bevor die letzte Stelle stimmt. Bei 64 summieren sich diese Laufzeiten. Deshalb benutzen echte Prozessoren aufwendigere Bauformen, die den Übertrag vorausberechnen; das Prinzip bleibt aber dasselbe.

Die von-Neumann-Architektur

Ein Addierwerk allein ist noch kein Computer. Frühe Rechenmaschinen wurden für jede neue Aufgabe umgesteckt; die Verkabelung war das Programm, und ein Wechsel dauerte Tage.

1945 formulierte John von Neumann das Prinzip, das das beendete:

Programm und stehen im selben Speicher. Ein Befehl ist ein Bitmuster wie jedes andere.

Die Architektur besteht aus fünf Teilen:

TeilAufgabe
Rechenwerkführt Rechnungen und Vergleiche aus
Steuerwerkholt Befehle, entschlüsselt sie, steuert alles Übrige
Speicherenthält Programm und Daten, adressiert
Eingabewerkbringt Daten hinein
Ausgabewerkgibt Ergebnisse aus

Rechenwerk und Steuerwerk zusammen bilden den Prozessor. Verbunden ist alles über Busse: Adressbus (wohin?), Datenbus (was?), Steuerbus (lesen oder schreiben?).

Du erkennst das aus Klasse 9 wieder, nun aber mit der entscheidenden Ergänzung, wo das Programm steht.

Der Aufbau, und was daraus folgt

CPU (Prozessor)DatenbusWerteAdressbusAdressenSteuerbusSignaleRechenwerkALU, rechnet undvergleichtSteuerwerkholt und deutetBefehleSpeicherProgrammund DatenEingabeTastatur,SensorAusgabeBildschirm,Drucker

Vier Bausteine und ein Bus. Das ist der Rechner, auf dem heute noch fast alles läuft. Die entscheidende Idee steckt im Speicher: Dort liegen Programm und , im selben Speicher, in derselben Form. Daraus folgt unmittelbar, was Rechner von Rechenmaschinen unterscheidet: Ein Programm kann ein anderes Programm als Daten lesen, verändern und starten. Genau darauf beruhen Übersetzer, Betriebssysteme und Virenscanner und, wie du im Halteproblem gesehen hast, auch der Beweis, dass manches unmöglich ist. Dieselbe Idee hat aber einen Preis: Weil alles durch denselben Bus muss, wartet das Rechenwerk oft auf den Speicher. Das ist der von-Neumann-Flaschenhals.

Der Befehlszyklus

Das Steuerwerk wiederholt unablässig denselben Ablauf:

1. Holen. Der Befehlszähler enthält die Adresse des nächsten Befehls. Der Befehl wird aus dem Speicher geladen. 2. Entschlüsseln. Das Steuerwerk erkennt, welche Operation gemeint ist. 3. Ausführen. Rechenwerk oder Speicher führen aus. 4. Befehlszähler erhöhen und von vorn beginnen.

Ein Sprungbefehl verändert einfach den Befehlszähler. Genau daraus entstehen und : Eine Wiederholung ist nichts anderes als ein Sprung zurück auf eine frühere Adresse, verbunden mit einer Bedingung.

Was aus der Idee folgt

Die Speicherung des Programms als hat weitreichende Konsequenzen:

Ein Programmwechsel ist ein Speicherinhalt, kein Umbau. Derselbe Rechner leistet Textverarbeitung und Bildbearbeitung.

Programme können Programme verarbeiten. Übersetzer lesen Quelltext und schreiben Maschinencode, beides sind Daten. Ohne dieses Prinzip gäbe es keine Programmiersprachen im heutigen Sinn. Auch der Halteproblem-Beweis aus der theoretischen Informatik lebt genau davon, dass ein Programm ein Programm als Eingabe nimmt.

Es gibt keinen Schutz von Natur aus. Wenn Befehle und Daten ununterscheidbar sind, kann eine zu große Eingabe Speicher überschreiben, in dem Befehle stehen. Genau darauf beruht eine ganze Familie von Angriffen. Heutige Systeme markieren Speicherbereiche deshalb ausdrücklich als „nicht ausführbar", aber das ist eine nachträgliche Absicherung und keine Eigenschaft der Architektur.

Vertiefung: der von-Neumann-Flaschenhals

Dieser Abschnitt gehört zum erhöhten Anforderungsniveau.

Weil Befehle und denselben Speicher und denselben Bus benutzen, können sie nicht gleichzeitig übertragen werden. Der Prozessor wartet also regelmäßig auf den Speicher. Das nennt man den von-Neumann-Flaschenhals.

Er ist über die Jahrzehnte schärfer geworden, denn Prozessoren wurden weit schneller als Speicher. Ein heutiger Prozessorkern kann in der Zeit eines einzigen Hauptspeicherzugriffs mehrere hundert Rechenschritte ausführen.

Gegenmaßnahmen:

  • Zwischenspeicher (Cache) direkt im Prozessor, klein und sehr schnell.
  • Getrennte Busse für Befehle und Daten (Harvard-Architektur), verbreitet in Mikrocontrollern und innerhalb moderner Prozessoren.
  • Mehrere Kerne und Fließbandverarbeitung, um Wartezeiten zu überbrücken.

🔴 Beachte, dass keine dieser Maßnahmen das Prinzip aufhebt. Sie mildern die Folgen. Die von-Neumann-Architektur ist deshalb kein überholtes Modell, sondern die Grundlage praktisch jedes heutigen Rechners, ergänzt um Technik, die ihre bekannteste Schwäche abfedert.

Den Halbaddierer aus der Tabelle herleiten

Leite die Schaltterme für ss und cc aus der des Halbaddierers her.

  1. 1

    Wichtig zuerst: Die Schaltung hat zwei Ausgänge, also stellt man zwei Terme auf, jeden für seine Spalte. Das ist der Schritt, der am häufigsten vergessen wird.

  2. 2

    Spalte ss: Einsen in den Zeilen a=0,b=1a=0,b=1 und a=1,b=0a=1,b=0. Die lautet s=(aˉ∧b)∨(a∧bˉ)s = (\bar{a} \land b) \lor (a \land \bar{b}).

  3. 3

    Dieser Term ist genau die Definition von XOR, also s=a⊕bs = a \oplus b. Statt drei Gattern (zwei NOT, zwei AND, ein OR) genügt damit ein XOR-Gatter.

  4. 4

    Spalte cc: Nur eine Eins, in der Zeile a=1,b=1a=1,b=1. Die DNF hat einen einzigen Term: c=a∧bc = a \land b.

  5. 5

    Zusammen: ein XOR und ein AND, beide auf dieselben zwei Eingänge geschaltet.

  6. 6

    Probe an der kritischen Zeile a=1a=1, b=1b=1: s=1⊕1=0s = 1 \oplus 1 = 0 und c=1∧1=1c = 1 \land 1 = 1. Zusammen gelesen ist das 102=210_2 = 2, und 1+1=21 + 1 = 2 stimmt.

s=a⊕bs = a \oplus b und c=a∧bc = a \land b. Zwei , hergeleitet ohne einen einzigen Einfall.

Ein Programm im Befehlszyklus abarbeiten

Ein einfacher Rechner hat einen Akkumulator (Rechenregister). Arbeite dieses Programm ab. Im Speicher steht an Adresse 20 der Wert 7 und an Adresse 21 der Wert 5.

Adresse  Befehl
  0      LADE   20      ; Akkumulator := Inhalt von Adresse 20
  1      ADDIERE 21     ; Akkumulator := Akkumulator + Inhalt von 21
  2      SPEICHERE 22   ; Adresse 22 := Akkumulator
  3      STOPP
  1. 1

    Ausgangslage: Befehlszähler = 0, Akkumulator undefiniert, Speicher: [20]=7[20] = 7, [21]=5[21] = 5.

  2. 2

    Zyklus 1: Holen: Adresse 0 wird gelesen, der Befehl LADE 20\texttt{LADE 20} steht im Befehlsregister. Entschlüsseln: Es ist ein Ladebefehl. Ausführen: Der Speicher liefert [20]=7[20] = 7, der Akkumulator wird 7. Zähler erhöhen: auf 1.

  3. 3

    Zyklus 2: ADDIERE 21\texttt{ADDIERE 21}. Das Rechenwerk addiert [21]=5[21] = 5 zum Akkumulator: 7+5=127 + 5 = 12. Zähler auf 2.

  4. 4

    Zyklus 3: SPEICHERE 22\texttt{SPEICHERE 22}. Der Akkumulator wird nach Adresse 22 geschrieben, also [22]=12[22] = 12. Zähler auf 3.

  5. 5

    Zyklus 4: STOPP\texttt{STOPP}. Der Zyklus endet.

  6. 6

    Beobachtung: Für jeden einzelnen Befehl laufen vier Schritte ab, und mehrfach wird der Speicher angesprochen, einmal für den Befehl und einmal für die . Genau hier liegt der Flaschenhals: Beide Zugriffe teilen sich denselben Bus und können nicht gleichzeitig erfolgen.

[22]=12[22] = 12. Vier Befehle, vier vollständige Zyklen, und pro Zyklus mindestens zwei Speicherzugriffe über denselben Bus.

Typischer Fehler

„Der Halbaddierer heißt so, weil er nur die Hälfte der addiert."

Er addiert vollständige Bits, und zwar zwei davon. Was ihm fehlt, ist der eingehende .

Sieh dir an, was beim schriftlichen Addieren an einer mittleren Stelle passiert. Dort treffen drei Bits zusammen: die beiden Ziffern und der Übertrag aus der Stelle rechts davon. Der Halbaddierer hat aber nur zwei Eingänge und kann den dritten gar nicht entgegennehmen.

Er ist deshalb nur an einer Stelle einsetzbar, nämlich der niederwertigsten, denn dort kommt kein Übertrag herein. Für jede weitere Stelle braucht man einen Volladdierer mit drei Eingängen.

Ein zweiter, verwandter Irrtum ist die Annahme, ein Volladdierer sei „zwei Halbaddierer nebeneinander". Er ist zwei Halbaddierer hintereinander, plus ein ODER-Gatter für die beiden Überträge. Die Reihenfolge ist wesentlich: Der erste addiert a+ba + b, der zweite fügt den Übertrag hinzu.

Merkhilfe: halb = zwei Eingänge, voll = drei Eingänge. Danach ergibt sich alles Übrige von selbst.

Übung 1

leicht

a) Gib die des Halbaddierers an. b) Welche zwei braucht er? c) Warum genügt er für mehrstellige Addition nicht? d) Nenne die fünf Bestandteile der von-Neumann-Architektur.

Tipp anzeigen

Zu c): Was kommt beim schriftlichen Addieren an jeder Stelle außer der ersten hinzu?

Lösung anzeigen

a)

aabbsscc
0000
0110
1010
1101

b) Ein XOR-Gatter für die Summe (s=a⊕bs = a \oplus b) und ein AND-Gatter für den (c=a∧bc = a \land b).

c) Weil er nur zwei Eingänge hat. Beim schriftlichen Addieren kommt an jeder Stelle außer der niederwertigsten der Übertrag der vorigen Stelle hinzu, also ein drittes . Dafür braucht man einen Volladdierer.

d) Rechenwerk, Steuerwerk, Speicher, Eingabewerk, Ausgabewerk. Rechenwerk und Steuerwerk bilden zusammen den Prozessor.

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    a) Die Tabelle aus der Dualaddition ableiten, nicht auswendig lernen

    Man schreibt einfach auf, was beim dualen Addieren zweier Bits herauskommt: 0+0=00+0 = 0; 0+1=10+1 = 1; 1+0=11+0 = 1; 1+1=1021+1 = 10_2, also Summe 0 mit Übertrag 1. Genau das steht in den Spalten ss und cc.

  2. 2

    b) Zwei Gatter und warum ausgerechnet diese

    Ein XOR-Gatter für die Summe (s=a⊕bs = a \oplus b) und ein AND-Gatter für den Übertrag (c=a∧bc = a \land b). Man erkennt sie, indem man die Spalten mit den bekannten Gattertabellen vergleicht.

    s=a⊕bs = a \oplus b, c=a∧bc = a \land b

  3. 3

    c) Warum der Halbaddierer für mehrstellige Zahlen nicht reicht

    Weil er nur zwei Eingänge hat. Beim schriftlichen Addieren kommt an jeder Stelle außer der niederwertigsten der Übertrag der vorigen Stelle hinzu, also ein drittes Bit. Dafür braucht man einen Volladdierer.

  4. 4

    d) Die fünf Bestandteile der von-Neumann-Architektur

    Rechenwerk, Steuerwerk, Speicher, Eingabewerk, Ausgabewerk. Rechenwerk und Steuerwerk bilden zusammen den Prozessor.

Übung 2

mittel

a) Stelle die des Volladdierers auf. b) Beschreibe in Worten, wann s=1s = 1 und wann caus=1c_{\text{aus}} = 1 gilt. c) Erkläre, wie ein Volladdierer aus zwei Halbaddierern entsteht. d) Wie viele Volladdierer und wie viele Halbaddierer braucht ein Addierwerk für 8-stellige ?

Tipp anzeigen

Zu b): Zähle, wie viele der drei Eingänge auf 1 stehen.

Lösung anzeigen

a) Acht Zeilen:

aabbceinc_{\text{ein}}sscausc_{\text{aus}}
00000
00110
01010
01101
10010
10101
11001
11111

b) s=1s = 1 genau dann, wenn eine ungerade Anzahl der drei Eingänge auf 1 steht, also bei einem oder bei drei. caus=1c_{\text{aus}} = 1 genau dann, wenn mindestens zwei Eingänge auf 1 stehen. Die zweite Bedingung ist genau die „mindestens zwei von drei"-Funktion aus dem vorigen Kapitel, also caus=(a∧b)∨(a∧cein)∨(b∧cein)c_{\text{aus}} = (a \land b) \lor (a \land c_{\text{ein}}) \lor (b \land c_{\text{ein}}).

c) Der erste Halbaddierer addiert a+ba + b und liefert die Zwischensumme s1s_1 und den c1c_1. Der zweite addiert s1+ceins_1 + c_{\text{ein}} und liefert die endgültige Summe ss sowie einen zweiten Übertrag c2c_2. Der ausgehende Übertrag ist caus=c1∨c2c_{\text{aus}} = c_1 \lor c_2.

Dass ein ODER genügt, liegt daran, dass c1c_1 und c2c_2 nie gleichzeitig 1 sind: Ist c1=1c_1 = 1, so waren a=b=1a = b = 1, also s1=0s_1 = 0; der zweite Halbaddierer addiert dann 0+cein0 + c_{\text{ein}} und kann keinen Übertrag erzeugen.

d) Sieben Volladdierer und einen Halbaddierer. An der niederwertigsten Stelle kommt kein Übertrag herein, dort genügt ein Halbaddierer; die übrigen sieben Stellen brauchen je einen Volladdierer.

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    Teil a): Systematisch alle acht Zeilen

    Drei Eingänge ergeben 23=82^3 = 8 Zeilen. Man zählt dual von 000000 bis 111111 und trägt für jede Zeile die Summe der drei ein: 0, 1, 2 oder 3.

    2^3 = 8

    Zwischenergebnis

    Summe 2 heißt s=0,c=1s=0, c=1; Summe 3 heißt s=1,c=1s=1, c=1.

    Die Summe der drei Bits als Dualzahl gelesen ist genau caussc_{\text{aus}}s. Bei Summe 3 also 11211_2, bei Summe 2 also 10210_2.

  2. 2

    Teil b): Das Muster benennen statt aufzählen

    Man sucht die gemeinsame Eigenschaft der Zeilen mit Ergebnis 1, statt sie einzeln aufzuzählen. Für ss ist es die ungerade Anzahl, für causc_{\text{aus}} die Mindestanzahl zwei.

    Zwischenergebnis

    ss: ungerade Anzahl · causc_{\text{aus}}: mindestens zwei.

  3. 3

    Teil c): Die Reihenfolge ist entscheidend

    Zwei Halbaddierer hintereinander, nicht nebeneinander: Der erste addiert a+ba+b, der zweite fügt den eingehenden Übertrag hinzu.

    Zwischenergebnis

    caus=c1∨c2c_{\text{aus}} = c_1 \lor c_2.

  4. 4

    Teil d): Die unterste Stelle ist der Sonderfall

    Man zählt die Stellen und prüft, an welcher kein Übertrag hereinkommt. Das ist genau die niederwertigste.

    8\ \text{Stellen} = 1\ \text{HA} + 7\ \text{VA}

    Zwischenergebnis

    Ein Halbaddierer, sieben Volladdierer.

    Man darf auch überall Volladdierer verwenden und den untersten ceinc_{\text{ein}} fest auf 0 legen. Das ist verbreitet, weil dann alle Bausteine gleich sind, und genau dieser Eingang wird bei der Subtraktion auf 1 gelegt, um das „+1" des Zweierkomplements zu erzeugen.

Übung 3

schwer

a) Erkläre das von-Neumann-Prinzip und nenne zwei Folgen daraus. b) Warum ermöglicht erst dieses Prinzip Übersetzer und Programmiersprachen? c) (Vertiefung) Was ist der von-Neumann-Flaschenhals, und mit welchen Mitteln begegnet man ihm? d) Ein Mikrocontroller verwendet die Harvard-Architektur mit getrennten Speichern für Programm und . Nenne einen Vorteil und einen Nachteil gegenüber von Neumann.

Tipp anzeigen

Zu b): Was ist ein Quelltext für den Übersetzer, und was erzeugt dieser?

Lösung anzeigen

a) Prinzip: Programm und Daten stehen im selben Speicher; ein Befehl ist ein Bitmuster wie jedes andere und wird über seine Adresse angesprochen.

Folge 1: Ein Programmwechsel ist bloß ein anderer Speicherinhalt, kein Umbau der Verkabelung. Derselbe Rechner erledigt beliebige Aufgaben, und genau das unterscheidet einen Computer von einer Rechenmaschine.

Folge 2: Es gibt keinen natürlichen Schutz zwischen und Daten. Eine zu große Eingabe kann Speicher überschreiben, in dem Befehle stehen; darauf beruht eine ganze Familie von Angriffen. Heutige Systeme markieren Bereiche als nicht ausführbar, aber das ist eine nachträgliche Absicherung.

b) Weil ein Übersetzer ein Programm ist, das ein anderes Programm als Daten liest und ein drittes Programm als Daten schreibt. Genau das ist nur möglich, wenn Programme im selben Speicher stehen wie alles andere und wie gewöhnliche Bitmuster gelesen und geschrieben werden können. Bei einer Maschine, deren Programm in der Verkabelung steckt, gäbe es nichts zu lesen und nichts zu schreiben. Dasselbe Prinzip trägt auch den Halteproblem-Beweis, in dem ein Programm sich selbst als Eingabe bekommt.

c) Befehle und Daten teilen sich denselben Speicher und denselben Bus, können also nicht gleichzeitig übertragen werden. Der Prozessor wartet deshalb regelmäßig auf den Speicher, und da Prozessoren über die Jahrzehnte deutlich schneller wurden als Speicher, hat sich das verschärft.

Gegenmittel: schneller Zwischenspeicher (Cache) im Prozessor; getrennte Wege für Befehle und Daten innerhalb des Prozessors; Fließbandverarbeitung und mehrere Kerne, um Wartezeiten zu überbrücken. Keines dieser Mittel beseitigt den Flaschenhals, alle mildern ihn.

d) Vorteil: Befehl und Daten lassen sich gleichzeitig holen, weil getrennte Busse vorhanden sind. Das ist schneller und, was bei Steuerungsaufgaben mindestens ebenso zählt, zeitlich besser vorhersagbar. Außerdem kann ein Programmfehler in den Daten den Programmspeicher nicht überschreiben, was die Sicherheit erhöht.

Nachteil: Die Aufteilung ist starr. Ein Programm kann sich nicht selbst verändern oder nachladen, und ungenutzter Programmspeicher lässt sich nicht für Daten verwenden. Für einen Mikrocontroller mit fester Aufgabe ist das gleichgültig, für einen Universalrechner wäre es hinderlich. Deshalb sind Universalrechner nach außen von-Neumann-Maschinen und benutzen die Harvard-Idee nur intern, etwa bei getrennten Zwischenspeichern für Befehle und Daten.

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    a) Das Prinzip und die erste Folge: der Rechner wird universell

    Prinzip: Programm und Daten stehen im selben Speicher; ein Befehl ist ein Bitmuster wie jedes andere und wird über seine Adresse angesprochen. Folge 1: Ein Programmwechsel ist bloß ein anderer Speicherinhalt, kein Umbau der Verkabelung. Derselbe Rechner erledigt beliebige Aufgaben.

  2. 2

    a) Die zweite Folge: kein natürlicher Schutz zwischen Code und Daten

    Folge 2: Es gibt keinen natürlichen Schutz zwischen Code und Daten. Eine zu große Eingabe kann Speicher überschreiben, in dem Befehle stehen; darauf beruht eine ganze Familie von Angriffen. Heutige Systeme markieren Bereiche als nicht ausführbar. Das ist aber eine nachträgliche Absicherung.

  3. 3

    b) Warum erst dieses Prinzip Übersetzer ermöglicht

    Weil ein Übersetzer ein Programm ist, das ein anderes Programm als Daten liest und ein drittes Programm als Daten schreibt. Genau das ist nur möglich, wenn Programme im selben Speicher stehen wie alles andere und wie gewöhnliche Bitmuster gelesen und geschrieben werden können.

  4. 4

    c) (Vertiefung) Der von-Neumann-Flaschenhals und die Gegenmittel

    Befehle und Daten teilen sich denselben Speicher und denselben Bus, können also nicht gleichzeitig übertragen werden. Der Prozessor wartet deshalb regelmäßig auf den Speicher und da Prozessoren über die Jahrzehnte deutlich schneller wurden als Speicher, hat sich das verschärft.

  5. 5

    d) Harvard-Architektur: ein Vorteil und ein Nachteil

    Vorteil: Befehl und Daten lassen sich gleichzeitig holen, weil getrennte Busse vorhanden sind, schneller und, was bei Steuerungsaufgaben ebenso zählt, zeitlich besser vorhersagbar. Außerdem kann ein Programmfehler in den Daten den Programmspeicher nicht überschreiben. Nachteil: Die Aufteilung ist starr, ein Programm kann sich nicht selbst verändern oder nachladen, und ungenutzter Programmspeicher lässt sich nicht für Daten verwenden.

Zusammenfassung

Der Halbaddierer entsteht aus seiner mit demselben DNF-Verfahren wie jede andere Schaltung: s=a⊕bs = a \oplus b und c=a∧bc = a \land b, also ein XOR und ein AND. „Halb" heißt er, weil ihm der eingehende fehlt und er deshalb nur an der niederwertigsten Stelle einsetzbar ist; der Volladdierer mit drei Eingängen entsteht aus zwei hintereinandergeschalteten Halbaddierern, deren Überträge mit ODER verbunden werden, weil sie nie zugleich auftreten. Aus nn solchen Bausteinen wird ein Addierwerk, und da Subtraktion, Multiplikation und Division auf Addieren und Verschieben zurückgehen, genügt das für alle vier Grundrechenarten. Zum Computer wird eine solche Maschine erst durch das von-Neumann-Prinzip, nach dem Programm und im selben Speicher stehen; daraus folgen der Befehlszyklus aus Holen, Entschlüsseln, Ausführen und Erhöhen, die Möglichkeit von Übersetzern und Programmiersprachen, aber auch das Fehlen einer natürlichen Trennung zwischen und Daten. Weil beide denselben Bus benutzen, entsteht der von-Neumann-Flaschenhals, den Zwischenspeicher, getrennte interne Wege und mehrere Kerne mildern, ohne ihn aufzuheben.