[[dtpr_versuch_2]]

This is an old revision of the document!


Die erste Schaltung

Dieser Versuch behandelt kombinatorische und arithmetische Schaltungen.

Binär zu 7-Segment Umsetzung

Die erste Schaltung ist eine Binär zu 7-Segment Umkodierung “bin2seg”. Mit einer 7-Segment Anzeige lassen sich die Ziffern 0-9 und mit etwas Phantasie auch die Buchstaben a-f darstellen. Die Anzeige dient dazu die Zahlen in der Schaltung in einer dezimalen, lesbaren Form anzuzeigen. Mit den Buchstaben a-f lässt sich dann eine 4-Bit Zahl auch als hexadezimale Zahl darstellen.

Der Eingang der Schaltung ist eine vorzeichenlose 4-Bit Binärzahl und der Ausgang ist ein Vektor mit sieben Leitungen, die die einzelnen Segmente ansteuern. Zu jeder Binärzahl muss deshalb die geeignete Ansteuerung der LEDs in der 7-Segment Anzeige gefunden werden. Wenn also der Eingang auf “0000” liegt, dann sollen die LEDs so angesteuert werden, dass eine 0 in der Anzeige erscheint. Eine Testbench und ein Gerüst für die Schaltung ist hier:

Binär zu 7-Segment Kodierer Code

Die Schaltung ist in einen Toplevel “top” eingefügt, der die Signalnamen gemäß den Konventionen auf dem Board hat. Also SW für die Schalter und HEX0 für die erste 7-Segment Anzeige. Der Toplevel ist so aufgebaut, dass die Schalter 3-0 an den Eingang des Umsetzers geführt werden.

Das Ziel der Gesamtschaltung ist es, dass eine 4-Bitzahl an den Schaltern SW(3-0) eingestellt werden kann und die entsprechende Ziffer an der 7-Segmentanzeige HEX0 ausgegeben wird.

Process und Case Statement

In der VHDL Beschreibung für “bin2seg” sind die Konstrukte “process” und “case” neu.

Der Prozess
  signal a,b,c,d : std_ulogic; 
 
  name_p: process(c,d)
  begin
    a <= '1';
    b <= c;
    if d = '1' then
      a <= c;
    else
      a <= not c;
    end if; 
  end process;

Alle Anweisungen in einem Prozess werden hintereinander ausgeführt, aber alle Signalzuweisungen werden erst am Ende des Prozesses aktiv! Es ist auch immer nur die letzte Zuweisung relevant. Dies ist also fundamental anders als beispielsweise in einem C Code. Dort wird jede Anweisung sofort ausgeführt. In diesem Beispiel ist also die Reihenfolge von “a⇐'1'” und “b⇐c” gleichgültig. “b” ändert sich also nicht zeitlich später als a. Allerdings ist die Anweisung “a⇐'1'” nicht relevant, da am Ende des Prozesses der Wert von “c” oder “not c” zugewiesen wird.

Wichtige Regeln für die Synthese
  • Ein Prozess wie oben dargestellt führt zu rein kombinatorischer Logik mit den Eingängen c und d und den Ausgängen a und b
  • Alle Eingänge müssen oben in der “sensitivity list” (= Parameter des Prozesses) angegeben sein.
  • Jedem Ausgangssignal muss in jedem Durchlauf des Prozesses ein Wert zugewiesen werden. Wenn dies nicht befolgt wird, entstehen bei der Synthese Latches
  • Ein Ausgangssignal darf in dem Prozess nicht gelesen werden, da dann eine kombinatorische Loop entsteht.
How to make and avoid a latches

Durch diesen Code entsteht bei der Synthese ein Latch:

  signal a,b,c : std_ulogic; 
 
  name_p: process(b,c)
  begin
    if b = '1' then
      a <= c;
    end if; 
  end process;

Solche Latches sind in der Regel nicht gewollt. Deshalb sind Default Zuweisungen am Anfang des Prozesses ein guter Weg um solche Latches auszuschließen.

Die Case Anweisung
  signal a,b : std_ulogic; 
  signal number_i : std_ulogic_vector(3 downto 0);
 
  trans_p: process(number_i)
  begin
    a <= '0';
    b <= '0';
    case number_i is 
      when "0000" => a <= '1';
                     b <= '0';
      when "0001"|"1000" => b <= '1';
      when others => b <= '0';	
    end case;
  end process;

Mit der Case Anweisung können abhängig vom Wert eines Signals unterschiedliche Anweisungen ausgeführt werden. Es müssen alle möglichen Werte des Signals aufgeführt werden. Um dies sicherzustellen, ist die “others” Variante vorgeschrieben. Mehrere Alternativen können durch “|” zusammengefasst werden.

In diesem Beispiel wird b der Wert '1' zugewiesen, wenn number_i “0001” oder “1000” ist.

Die Typen signed und unsigned: Zahlendarstellungen

In der “bin2seg” Schaltung wird der Typ “unsigned” verwendet. Der Typ “unsigned” leitet sich von dem Typen “std_logic_vector” ab, der im ersten Versuch eingeführt wurde. “std_logic_vector” stellt einen Bus dar und die einzelnen Leitungen des Busses können Werte annehmen, die in einer Schaltung vorkommen können. Das sind beispielsweise '0', '1' oder auch 'U' für undefined.

Auch “signed” und “unsigned” sind also Busse mit einzelnen Leitungen, die jeweils typische Schaltungszustände annehmen können. Es wird jedoch der Typ “signed” oder “unsigned” verwendet, um zu kennzeichnen, dass dieser Bus eine Zahl darstellt. Wenn ein Bus als “signed” oder “unsigned” definiert wird, dann kann man mathematische Operatoren auf den Bus anwenden, die sich auf einen Bus vom Typ “std_logic_vector” nicht anwenden lassen, da sie keinen Sinn ergeben. Die “signed” und “unsigned” Typen sind im package numeric_std definiert.

Operatoren und Zuweisungen für signed und unsigned

Für die Typen “signed” und “unsigned” sind unter anderem folgende Operatoren und Zuweisungen definiert:

signal a,b,c : unsigned(7 downto 0); -- Ebenso mit signed
signal vergleich : Boolean;          -- Der Typ Boolean kann die Werte "true" oder "false" annehmen
 
c <= a + b; 
c <= a + 1; -- Addition mit einer Zahl
c <= a - b;
c <= a - 1; 
c <= "00000000";
c <= "10101010"; 
 
vergleich <= a > b;  -- Dem Signal "vergleich" wird das Ergebnis des Vergleichs zugewiesen
vergleich <= a < b;
vergleich <= a <= b; 
vergleich <= a >= b; 
vergleich <= a = b; 
vergleich <= a > 5;

Diese Operatoren können auch mit Zahlen (integer) als Operanden durchgeführt werden. Einem “signed” oder “unsigned” Bus kann jedoch keine Zahl direkt zugewiesen werden.

In der Schaltung “bin2seg” ist der Eingang “number_i” vom Typen “unsigned”. In der Testbench ist das Signal “number” vom Typ “unsigned”. In der Testbench wird auch die Addition verwendet.

Typumwandlungen signed, unsigned

“signed” und “unsigned” sind direkt vom Typen “std_logic_vector” abgeleitet. Man kann deshalb durch einfache casts diese Typen ineinander umwandeln. Das geht so:

signal a : signed (7 downto 0); 
signal b : unsigned (7 downto 0);
signal c : std_ulogic_vector(7 downto 0);
 
a <= signed(b); 
a <= signed(c);
b <= unsigned(a);
b <= unsigned(c);
c <= std_ulogic_vector(a);
c <= std_ulogic_vector(b);

Bei diesen Umwandlungen wird nur der Typ umdefiniert. Es ändert sich nichts am Zustand der Leitungen, d.h. hier wird keine Schaltung o.ä. generiert.

Aufgaben Teil 1

  1. Laden Sie die drei VHDL Dateien aus Binär zu 7-Segment Kodierer Code in ein Verzeichnis “v2”.
  2. Starten Sie Modelsim und erstellen Sie ein neues Projekt
  3. Simulieren Sie die Schaltung und vollziehen Sie die Funktion nach.
  4. Ergänzen Sie die Schaltung in der Datei “bin2seg.vhd” um eine vollständige Kodierung zu erstellen.
  5. Simulieren Sie die Schaltung erneut und prüfen Sie die Funktion
  6. Starten Sie Quartus und erstellen Sie ein Projekt
  7. Synthetisieren Sie die Schaltung

Die Additionsschaltung

Wenn die 7-Segment Anzeige läuft, dann kann die Schaltung um eine Additionsschaltung erweitert werden. Das Ziel der Schaltung ist es, an den Schaltern zwei 4-Bit unsigned Zahlen einzugeben und die Summe der beiden Zahlen zu berechnen. Die Summanden und die Summe soll auf der 7-Segment Anzeige ausgegeben werden.

Code für die Additionsschaltung

In dieser Schaltung werden zwei vorzeichenlose Zahlen addiert und das Ergebnis ausgegeben.

Aufgaben Teil 2

  1. Erzeugen Sie ein neues Verzeichnis “p2”
  2. Laden Sie den Code für die Additionsschaltung in das Verzeichnis “p2”
  3. Starten Sie Modelsim und machen Sie ein neues Projekt mit den Dateien top_tb.vhd, top.vhd, adder.vhd und bin2seg.vhd
  4. Erweitern Sie die Schaltung “top” und instantiieren Sie den Addierer in der Schaltung “top”
  5. Schließen Sie den Eingang a an die Schalter 3-0 und den Eingang b an die Schalter 8-5 an. Schließen Sie den Ausgang des Addierers an das Signal “sum” an.
  6. Instantiieren sie einen zusätzlichen bin2seg Coder für die Anzeige der Summe verbinden Sie den Ausgang des Addierers mit dem Eingang des bin2seg Coders. Verwenden Sie hierzu das signal “sum”. (adder → sum → bin2seg)
  7. Simulieren Sie die Schaltung und prüfen Sie die Funktion
  8. Synthetisieren Sie die Schaltung mit Quartus

Die Abstimmungsschaltung

Diese Schaltung soll eine LED einschalten, wenn mehr als die Hälfte der Schalter SW eingeschaltet sind. Insgesamt gibt es zehn Schalter. Grundsätzlich lässt sich diese Aufgabe analog wie die Kodierschaltung für die 7-Segment Anzeige lösen:

signal schalter : std_ulogic_vector(9 downto 0); 
signal led : std_ulogic; 
 
process(schalter)
begin
  case schalter is
    when "1111110000"|
         "1111101000"|
         "1111100100"|
         -- many more here
         "0000111111" => led <= '1';
    when others => led <= '0';
  end case; 
end process; 

Das Problem sind die zehn Schalter…

Deshalb sollen zunächst die eingeschalteten Schalter für fünf Schalter gezählt werden. Dazu wird eine Schaltung “cntsw” verwendet, die fünf Schalter als Eingang hat und einen Ausgang cnt_o mit 3-Bit. Am Ausgang ist die Anzahl der eingeschalteten Schalter abzulesen. Wenn also am Eingang beispielsweise “01011” anliegt, dann kommt am Ausgang der Wert “011” (=3) heraus.

Code für die Abstimmungsschaltung

Dann wird diese Schaltung zweimal instantiiert und jeweils für die Schalter SW(4..0) und SW(9..5) eingesetzt. Das Zählergebnis für die Schaltergruppen wird dann addiert. Anhand der Summe der eingeschalteten Schalter, soll dann die LEDR(0) eingeschaltet b.z.w. ausgeschaltet werden.

Tip:

Für das Einschalten der LED können Sie ein if…then…else Konstrukt verwenden:

signal zahl : unsigned(9 downto 0);
signal led  : std_ulogic; 
 
process(zahl)
begin
  if zahl > 354 then
    led <= '1';
  else
    led <= '0';
  end if;
end process; 

Aufgaben Teil 3

  1. Erstellen Sie ein neues Verzeichnis p3
  2. Laden Sie die VHDL Dateien aus dem Code für die Abstimmungsschaltung in Ihr Verzeichnis
  3. Vervollständigen Sie die Schaltung “cntsw” und schließen Sie die Schaltung korrekt in der Schaltung top an.
  4. Prüfen Sie die Funktion der Schaltung im Simulator
  5. Bauen Sie eine Schaltung “decide”, die die Summe der beiden Schalterzähler berechnet und auf Basis dieser Summe die LED einschaltet.
  6. Verschalten Sie die “decide” Schaltung korrekt in der Schaltung “top”
  7. Prüfen Sie die Schaltung im Simulator.
  8. Synthetisieren Sie die Schaltung für das FPGA
  • dtpr_versuch_2.1395850139.txt.gz
  • Last modified: 2014/03/26 17:08
  • by beckmanf