LUT als RAM
● LUT mit Latche kann als RAM benutzt
werden (distributed RAM)
● Nur kleine RAM-Blöcke
RAM16X1S
O D WE
WCLK A0 A1 A2 A3
RAM32X1S
O DWE A0WCLK A1 A2 A3 A4
RAM16X2S
O1 D0 WE WCLK A0 A1 A2 A3 D1
O0
=
=
LUT
LUT
or
LUT
RAM16X1D
SPO D
WE WCLK A0 A1 A2 A3 DPRA0 DPO DPRA1 DPRA2 DPRA3
or
LUT als Schieberegister
● LUT kann als Schieberegister
konfiguriert werden
● Damit lass sich kleinere FIFOs realisieren
D Q
CE
D Q
CE
D Q
CE
D Q
CE
LUT CEIN
CLK
DEPTH[3:0]
LUT
=
OUTExkurs: Spezielle Speicher
● Dual Port RAM (Zweitorspeicher)
▪ Logisch durch Controller (halbe Geschwindigkeit),
„gleichzeitiges“ Lesen/Lesen und
Schreiben/Schreiben unabhängig voneinander (Konflikte muss der Controller abfangen)
▪ Analog durch zwei getrennte Zugriffsleitungen für Schreiben und Lesen
• Macht getrennte Takte möglich (asynchrones RAM)
● FIFO (=First In First Out)
▪ Schieberegister + Lese-Pointer (Zeiger)
▪ Mit DP-RAM + zwei getrennten Zeigern
▪ FIFO + asynchrones DP-RAM = Clock Domain
Crossing
Moderne FPGAs haben…..
● Embedded RAM (block RAM)
● Multi-Gigabit Transceiver
▪ Serielle Datenübertragung mit Gbit/s
● Eingebettete Prozessoren
● IP-cores (z.B. PCIe)
● Clock-Manager
Digitalelektronik
Kapitel 3
3.3: Programmierung
Design-Flow
● „Design Entry“
▪ Schematic
• …wie Vorlesung bisher
▪ Hochsprache
• Z.B. VHDL
● Implementierung
▪ Tools von Hersteller
● Simulation
● Download
▪ Kabel oder externer Bus
XC4000 XC4000
XC4000
Design
● Ausgabe von Design Entry: Netlist (z.B. EDIF)
● Hersteller-Tools: Netlist einlesen und auf Logikblöcke abbilden
● Placement
● Routing
● Optimieren
VHDL
● Very high speed integrated circuit Hardware Description Laguage (Textbasiert)
● „Top-Down“-Ansatz
● Sprache für Implementierung und Simulation
VHDL
● Begleitung vom Design-Entry…
● …bis zum Timing- Analyse
● Mehrere
Simulationsschritte
Grundkonzept
● ENTITY
● Definiert Ein- und
Ausgänge („Black-Box“)
● ARCHITECTURE
● Implementierung(en)
Modul
Libraries
●
LIBRARYIEEE;
use
IEEE.std_logic_1164.all;
use
IEEE.std_logic_unsigned.all;
ENTITY
● ENTITY modellname IS
GENERIC parameterliste PORT interface
deklarationen END modellname;
● Beispiel:
● ENTITY und IS
PORT (ein1: IN std_logic;
ein2: IN std_logic;
aus: OUT std_logic);
END und;
ARCHITECTURE
● ARCHITECTURE und_arch OF und IS SIGNAL myaus: std_logic;
BEGIN
myaus <= ein1 and ein2;
aus <= myaus;
END und_arch;
● Statements zwischen BEGIN und END werden parallel abgearbeitet…
▪ …wenn es sich um nebenläufige Befehle handelt, wie:
▪
Einzelne Prozesse (mehr dazu später)▪
Concurrent Signal Assignment▪
D.h. “Signalverkabelung”Exkurs: C vs. VHDL
● In C:
a = 3;
b = 2;
c = a+b;
● ist nicht:
c = a+b;
a = 3;
b = 2;
● In VHDL:
a <= '0';
b <= '1';
c <= a and b;
● ist gleich:
c <= a and b;
a <= '0';
b <= '1';
...wie bei einer
elektrischen Schaltung
Beispiel: Halbaddierer
● ENTITY halbaddierer IS
PORT ( a: IN std_logic;
b: IN std_logic;
sum: OUT std_logic;
carry: OUT std_logic);
END halbaddierer;
● ARCHITECTURE halbaddierer_arch OF halbaddierer IS
BEGIN
sum <= a xor b after 5 ns;
carry <= a and b after 5 ns;
END halbaddierer_arch;
GENERICs
● Simulation erfolgt über TESTBENCH
● „after“-Statement wird nur in Simulation benutzt
● Mit GENERIC können Parameter übergeben werden, Beispiel:
● In ENTITY:
▪ GENERIC (delay: TIME);
● In ARCHITECURE:
▪ a <= b and c after delay;
● Mit GENERIC können aber auch Bauvorschriften definiert werden
▪ Z.B. Busbreite
Hierarchie
● Wiederverwendung des Halbaddierers in Volladdierer:
● ENTITY volladdierer IS
PORT (in1, in2, c_in: IN std_logic;
sum: OUT std_logic;
c_out: OUT std_logic);
END volladdierer;
Hierarchie
●
ARCHITECTURE volladdierer_arch OF volladdierer ISsignal s1,s2,s3: std_logic;
COMPONENT halbaddierer IS
PORT
(a: IN std_logic;
b: IN
std_logic;
sum: OUT
std_logic;
carry: OUT
std_logic);
END COMPONENT;
BEGIN
H1: halbaddierer port map(IN1, IN2, s1, s3);
H2: halbaddierer port map(s1, c_in, sum, s2);
c_out <= s2
or s3;END volladdierer_arch;
Prozesse
[label:] process [(sensitivity_list)]
[declarations]
begin
{sequential_statement}
end process [label];
● In der Simulation eine Schleife, die ständig neu “ausgeführt” wird
● Optional (für Simulation): sensitivity_list: der Prozess wird neu ausgeführt, wenn sich ein Signal in dieser Liste ändert
● In der Hardware (FPGA): der Inhalt ist eine Bauvorschrift, keine Beschreibung des späteren Echtzeitverhaltens
● name: process(a,b) begin
if (a='1') and (b='1') then x <= '1';
else
x <= '0';
end if;
end;
begin x <= '0';
if (a='1') and (b='1') then x <= '1';
end if;
end;
Prozesse
[label:] process [(sensitivity_list)]
[declarations]
begin
{sequential_statement}
end process [label];
● Ganz schlecht:
● name: process(a,b) begin
if (a='1') and (b='1') then x <= '1';
end if;
end;
Logik nicht vollständig:
Produziert Latche:
Immer Default definieren!
(vorher oder per else)
Synchrone Prozesse (Flip Flop I)
entity flip_flop is
Port (CLK : in STD_LOGIC;
Reset : in STD_LOGIC;
Enable : in STD_LOGIC;
D : in STD_LOGIC;
Q : out STD_LOGIC);
end flip_flop;
architecture flip_flop_arch of flip_flop is
signal current_Q : STD_LOGIC;
signal next_Q : STD_LOGIC;
begin
Q <= current_Q;
...
Achtung: „out“-Signal kann nicht wieder eingelesen
werden:
Immer zusätzlich internes Signal (hier: „current_Q“)
verwenden
Flip-Flop II
process (CLK) begin
if rising_edge(CLK) then current_Q <= next_Q;
end if;
end process;
process (D, current_Q, Enable, Reset) begin
next_Q <= current_Q;
if (Reset = '1') then next_Q <= '0';
elsif (Enable = '1') then next_Q <= D;
else
next_Q <= current_Q;
end if;
end process;
end flip_flop_arch;
Synchroner Teil
Kombinatorischer Teil
Unser Flip-Flop ist ein
„Mini“-Zustandsautomat
Zustandsspeicher
„0“, „1“, „2“, „3“ Flip-Flops
Übergangsregeln
Wenn „0“, dann „1“
Wenn „1“, dann „2“
Wenn „3“, dann „4“
Wenn „4“, dann „0“
Kombinatorische Logik
Ausgabe
Eingänge (D, Reset,
Enable)
current_Q next_Q
Zustandsspeicher
„0“, „1“, „2“, „3“ Flip-Flops
Übergangsregeln
Wenn „0“, dann „1“
Wenn „1“, dann „2“
Wenn „3“, dann „4“
Wenn „4“, dann „0“
Kombinatorische Logik
Ausgabe
Kombinatorische Logik
Eingänge
current_state next_state
„Anweisungen“, z.B. Leuchten
einer LED
„Anweisungen“, z.B. Leuchten
einer LED
if
Ampelanlage - Aufgabenstellung
● Zwei kreuzende Straßen
▪ Hauptstraße (1) soll „Grün“ haben
▪ Nebenstraße (2) soll „Rot“ haben, bis Auto wartet
● Berücksichtigung von Fußgängern
▪ Beide Straßen „Rot“ für Fußgängerphase
● Eingänge
▪ Auto wartet A=1
▪ Fußgänger wartet F=1
Ampelanlage - Zustandsdiagramm
Grün
A=0 ∧F=0
Gelb
A=1 ∨F=1
RotF
F=1
F=0
RotA
RotGelbF
Grün2
Gelb2
Zustand Ampel1 Ampel2 Fußgänger
Grün Gelb RotF
RotGelbF RotA
Grün2
Gelb2
3-Prozess-
Zustandsautomat
Kombinatorischer Teil (Übergänge)
type ampel_state is (gruen, gelb, rotf, rotgelbf, rota, gruen2, gelb2);
signal current_ampel, next_ampel: ampel_state;
process (current_ampel, f, a) begin
next_ampel <= current_ampel;
case current_ampel is when gruen =>
if (a = ‘1‘ or f = ‘1‘) then next_ampel <= gelb;
end if;
when gelb =>
if (f = ‘1‘) then
next_ampel <= rotf;
else
next_ampel <= rota;
end if;
Kombinatorischer Teil (Übergänge)
…..
when rotf =>
next_ampel <= rotgelbf;
when rotgelbf =>
next_ampel <= gruen;
when rota =>
next_ampel <= gruen2;
when gruen2 =>
next_ampel <= gelb2;
when gelb2 =>
next_ampel <= gruen;
end case;
end process;
Synchroner Teil
process (clk) begin
if (rising_edge(clk)) then
current_ampel <= next_ampel;
end if;
end process;
Kombinatorischer Teil (Ausgangssignale)
process (current_ampel) begin
hauptstrasse_rote_lampe <= ‘0‘;
hauptstrasse_gelbe_lampe <= ‘0‘;
hauptstrasse_gruene_lampe <= ‘0‘;
case current_ampel is when gruen =>
hauptstrasse_gruene_lampe <= ‘1‘;
…
end case;
end process;
2-Prozess-
Zustandsautomat
Kombinatorischer Teil (Übergänge + Ausgänge)
process (current_ampel, f, a) begin
next_ampel <= current_ampel;
hauptstrasse_rote_lampe <= ‘0‘;
hauptstrasse_gelbe_lampe <= ‘0‘;
hauptstrasse_gruene_lampe <= ‘0‘;
case current_ampel is when gruen =>
hauptstrasse_gruene_lampe <= ‘1‘;
if (a = ‘1‘ or f = ‘1‘) then next_ampel <= gelb;
end if;
…..
2-Prozess-
Zustandsautomat mit Registrierung der
Ausgänge
Schnelle Ausgangsregistrierung
Zustandsspeicher
„0“, „1“, „2“, „3“ Flip-Flops
Übergangsregeln
Wenn „0“, dann „1“
Wenn „1“, dann „2“
Wenn „3“, dann „4“
Wenn „4“, dann „0“
Ausgabe
Eingänge
Kombinatorische Flip-Flops
Logik
next_ff
current_ff
if
Kombinatorischer Teil
(mit Registrierung der Ausgänge)
signal next_hauptstrasse_rote_lampe,
current_hauptstrasse_rote_lampe : std_logic;
process (current_ampel, f, a) begin
next_ampel <= current_ampel;
next_hauptstrasse_rote_lampe <= ‘0‘;
next_hauptstrasse_gelbe_lampe <= ‘0‘;
next_hauptstrasse_gruene_lampe <= ‘0‘;
case current_ampel is when gruen =>
if (a = ‘1‘ or f = ‘1‘) then
next_hauptstrasse_gelbe_lampe <= ‘1‘;
next_ampel <= gelb;
end if;
…
Synchroner Teil
(mit Registrierung der Ausgänge)
process (clk) begin
if (rising_edge(clk)) then
current_ampel <= next_ampel;
current_hauptstrasse_rote_lampe <=
next_hauptstrasse_rote_lampe;
current_hauptstrasse_gelbe_lampe <=
next_hauptstrasse_gelbe_lampe;
current_hauptstrasse_gruene_lampe <=
next_hauptstrasse_gruene_lampe;
…
end if;
end process;
hauptstrasse_gruene_lampe <=
current_hauptstrasse_gruene_lampe;
…
Separate Verschaltung des Ausgangs (out)
Kombination von Zustandsautomaten
3-Prozess-
Zustandsautomat
Kombination von Zustandsmaschinen
● Zustandsautomat „Start/Stop“ gibt Signal F an Zustandsautomat „Ampel“
● „Ampel“ gibt Reset-Signal an „Start/Stop“ wenn Fußgängerlicht grün zeigt (=neuer Ausgang)
Start/Stop Fx
Ampel F
Reset
=1 wenn
Fußgängerampel grün
Kombination von Zustandsmaschinen
● Fußgänger drückt die Taste F während der Auto-Schleife? Signal kann verloren gehen…
● Lösung: Fußgänger drückt auf Schalter (Signal Fx) , Warte-Licht geht an (neuer
Zustandsautomat)
Aus
Aktiviert
Fx=0
Fx=0
Reset=0 Reset=1
Entity
Die Entity könnte so aussehen (die Ausgänge für die Ampelfarben wurden der Einfachheit halber weggelassen).
Fx ist das Signal des Fußgängers (Knopf des Drückers), a des Autos, SignalKommt ist das Leuchtsignal auf dem Drücker
entity ampelanlage is
port (clk: in std_logic;
Fx : in std_logic;
a : in std_logic
signalkommt : out std_logic);
end entity;
Deklarationen
In der Architecture nach „IS“ stehen die Definitionen für beide Automaten. Wir brauchen auch noch die Definition von f, da das kein Input ist, sondern nur der
„Verdrahtung zwischen den beiden Automaten dient (Ausgang von Drücker, Eingang von Ampelschaltung)
architecture ampelanlage_arch of ampelanlage is
type ampel_state is (gruen, gelb, rotf, rotgelbf, rota, gruen2, gelb2);
signal current_ampel, next_ampel: ampel_state;
type druecker_state is (an, aus);
signal current_druecker, next_druecker: druecker_state;
signal f : std_logic;
begin
Kombinatorischer Teil (Übergänge)
Nach „begin“ kommt der kombinatorische Teil des Ampel-Automaten. Der sieht genauso aus wie vorher. f ist aber kein Eingang, sondern internes Signal (der Automat weiß das aber nicht und es spielt für dessen Funktion auch keine Rolle):
process (current_ampel, f, a) begin
next_ampel <= current_ampel;
case current_ampel is when gruen =>
if (a = ‘1‘ or f = ‘1‘) then next_ampel <= gelb;
end if;
when gelb =>
if (f = ‘1‘) then
next_ampel <= rotf;
else
next_ampel <= rota;
end if;
Kombinatorischer Teil (Übergänge)
…..
when rotf =>
next_ampel <= rotgelbf;
when rotgelbf =>
next_ampel <= gruen;
when rota =>
next_ampel <= gruen2;
when gruen2 =>
next_ampel <= gelb2;
when gelb2 =>
next_ampel <= gruen;
end case;
end process;
Kombinatorischer Teil (Übergänge)
Dann muss noch der kombinatorische Teil für den Drücker kommen. Dieser fragt den Zustand des anderen Ampelautomaten ab und hält f=1 bis dieser wieder in der Fußgänger-Grün-Phase ist (dann kann der Drücker gelöscht werden):
process (current_druecker, Fx) begin
next_druecker <= current_druecker;
f <= ‘0‘;
case current_druecker is when aus =>
if (Fx = ‘1‘) then
next_druecker <= an;
end if;
when an =>
f <= ‘1‘;
if (ampel_state = gruen);
next_druecker <= aus;
end if;
Synchroner Teil
Beide synchrone Teile können kombiniert werden:
process (clk) begin
if (rising_edge(clk)) then
current_ampel <= next_ampel;
current_druecker <= next_druecker;
end if;
end process;
Irgendwo muss „signalkommt“ noch verdrahtet werden (die Reihenfolge der Prozesse und der Verdrahtungen spielt keine Rolle). „f“ darf man nicht nach außen legen, da es im Ampelautomaten wieder benutzt wird und das bei out- signalen des Ports nicht geht:
signalkommt <= f;
Anmerkungen
Die Zustandsautomaten kommunizieren mit Signalen (die …states sind auch Signale)
Die Herausforderung ist die Selektion der richtigen Signale. Hier müssen wir current_ampel nehmen da das das registrierte Signal ist (sonst handelt man sich Ärger wegen des Timings ein).
Dieses kommt aber ein Takt später, so dass der Drückerautomat erst reagiert, wenn der Fußgänger schon grün hat. Da der Drückerautomat (Moore!) auch nochmal einen Takt braucht um dann in „aus“ zu gehen, geht der
Drückerautomat erst nach der Grün-Phase aus.
Bei der Ampel ist das egal, bei einem Bussystem müsste man sich überlegen, wie man vorausschauender plant, z.B. indem schon die vorhergehende
Gelbphase abfragt. Das macht es aber komplizierter, falls Zustandsautomaten verzweigen, da dann für verschiedene Fälle 1-2 Takte vorher geplant werden muss.