Auf dieser Seite kannst du sehen wie mit den den konfigurierbaren Logikblöcken komplexere Schaltungen umgesetzt werden. Die Schaltungen sind interaktiv, das bedeutet, du kannst die Eingänge der Schaltung ändern und die Ausgänge reagieren direkt darauf.
Interaktive Schaltungssimulation
Aufbau Logikblock
Auf der linken Seite ist nochmal der Aufbau eines vereinfachten Logikblockes zu sehen. Dabei sind die wichtigsten Bestandteile:
- 3 Eingänge A, B, C
- 2 Ausgänge X, Y, Z
- 2 Multiplexer
- D-Flip-Flop
- Look Up Table
Wenn man den Cursor auf die Look-Up-Table hält, taucht eine 🔍 auf und man kann sich das Bauteil in einem Extra Fenster anzeigen lassen. In diesem Beispiel wurde die LUT mit einem einfachen Speicherbaustein implementiert; mit einem weiteren Klick darauf kann man sich den Inhalt des Speichers angucken und ihn auch ändern.
Ähnlich wie bei PLAs oder ROMs wird der Eingang der LUT als Adresse im Speicher interpretiert und der Ausgang ist das was an der Adresse gespeichert ist. Somit kann ein Speicherbaustein eine beliebige logische Funktion implementieren. Zusammen mit dem Zustand der Multiplexer (MuxConf1 und MuxConf2) wird hier die Funktionsweise des Logikblockes festgelegt.
Damit unsere Schaltungen im weiteren Verlauf auch übersichtlich bleiben verpacken wir unseren Logikblock in ein eigenes Schaltsymbol. Dieses hat alle Eingänge A-C, die Ausgänge X, Y und auch noch einen Eingang für unser getaktes D-Flip-Flop.
Wir können aber trtozdem noch mit der 🔍 in den Baustein hineingucken und die Schaltungs uns ansehen.
1 Bit Addierer
Jetzt wollen wir tatsächlich mal eine Schaltung mit unserem Logikblock implementieren. Unser LB hat drei Eingänge und zwei Ausgänge. Zufällig hat ein Volladdierer genau die gleiche Anzahl von Ein- und Ausgängen.
Zur Erinnerung: ein Volladdierer kann zwei Binärzahlen mit Übertrag addieren. Der zusätzliche Eingang ist hier der sogenannte Carry-In (cin) und der Übertragsausgang wird auch Carry-Out (cout) bezeichnet. Die Wahrheitstabelle für ein Volladdierer sieht wie folgt aus:
cin | B | A | sum | cout |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
Diese Tabelle beschreibt also wie sich die Ausgänge zu den Eingängen verhalten.
Damit der Logikblock als Volladdierer funktioniert müssen wir nun zwei Dinge tun:
- Die Multiplexer richtig konfigurieren
- Den Speicher der LUT richtig füllen
Die Multiplexer sind in unserem Beispiel schon richtig konfiguriert und sorgen dafür, dass die cin Leitung mit dem C-Eingang der LUT verbunden ist und der Y-Ausgang auch richtig weitergeleitet wird.
Der Speicher der LUT ist noch nicht ganz korrekt gefüllt: wenn du in der Schaltung links mal alle möglichen Belegungen für die Eingänge ausprobierst wirst du feststellen dass wenn alle Eingänge 1 bzw. HIGH sind, beide Ausgänge 0 bzw. LOW sind, was laut Wahrheitstabelle nicht richtig ist.
Deine Aufgabe
Versuche den Inhalt des Speichers so anzupassen, dass der Logikblock die logische Funktion eines Volladdierers implementiert.
Genereller Hinweis: im Memeory Contents-Fenster kann man zum besseren Verständnis die Darstellung des Speichers auf binär (bin) stellen.
-
Lösungshinweis Öffne das Memory Contents Fester der LUT und beobachte was passiert, wenn du die Eingänge aus- und anschaltest
-
Lösung Im Memeory Content muss an der letzten Stelle eine 11 stehen.
4 Bit Addierer
Nachdem wir jetzt einen einfachen 1 Bit Addierer mit unserem Logikblock umgesetzt haben können wir auch mehrere LB, die alle gleich konfiguriert sind, hintereinander schalten um z.B. einen 4 Bit Addierer zu bekommen.
Dafür müssen wir jeweils den Übertragsausgang (cout / Y) an den Cin / C Eingang des nächsten Volladdierers anschließen.
Deine Aufgabe
Füge in der Schaltung links die fehlenden Verbindung zwischen den Logikblöcken hinzu. Um zu testen, ob deine Verbindungen richtig sind kannst du bei A und B zwei Zahlen eingeben, die addiert werden sollen und bei sum wird dir das Ergebnis angezeigt.
Zähler
Bisher haben wir die Speicherfunktionalität von unserem Logikblock komplett ignoriert, das soll sich jetzt ändern. In dem nächsten Beispiel
Auf der linken Seite ist wieder der einfach Logikblock dargestellt. Zum ersten Mal kommt jetzt auch der clock-Eingang zum Einsatz, der das D-Flip-Flip taktet.
Wenn man in den Logikblock hineinguckt sieht man, dass der rechte Multiplexer so konfiguriert ist, dass am Ausgang Y das Signal vom D-Flip-Flop anliegt. Somit kann der Logikblock seinen gespeicherten Zustand auch an andere Logikblöcke weiterleiten.
Da nur bis eins zählen langweilig ist können wir hier auch mehrere von unseren 1-bit Zählern miteinander verschalten. Damit kann man dann z.B. einen 4-Bit Zähler wie links implementieren.
Dabei benutzen alle Logikblöcke die Selbe clock um alle D-Flip-Flops im gleichen Takt zu halten. Desweiteren teilen sich alle Logikblöcke die reset-Leitung mit dem der Zähler auf 0 zurück gesetzt werden kann.
Aussicht
Dieser kurzer Abschnitt soll jetzt einen kurzen Überblick darüber geben, wie man mit einfachen Logikblöcken Schaltnetzte und Schaltwerke implementiert, die komplexere Funktionalität haben. In den Beispielen hier haben wir nie mehr als vier Logikblöcke verwendet. In realen FPGAs die Anzahl von den Logikblöcke drei- bis fünfstellig.
Zusätzlich sind die einzelnen Logikblöcke durch viele Ein- und Ausgänge und mehrerer LUTs deutlich komplexer. Darum würde es noch viel komplizierter sein diese Logikblöcke per Hand zu konfigurieren und die Verbindungen per Hand zu setzen. Darum beschreibt man die zu realisierende Schaltung mittels einer Hardwarebeschreibungssprache und ein Kompilierer übersetzt diese dann in die Konfiguration für den FPGA.