vhdl
D-Flip-Flops (DFF) und Latches
Suche…
Bemerkungen
D-Flip-Flops (DFF) und Latches sind Speicherelemente. Ein DFF tastet seine Eingabe an der einen oder anderen Flanke des Taktgebers ab (nicht bei beiden), während ein Latch auf der einen Ebene seiner Freigabe und auf der anderen Ebene transparent ist. Die folgende Abbildung veranschaulicht den Unterschied:
Die Modellierung von DFFs oder Latches in VHDL ist einfach, es gibt jedoch einige wichtige Aspekte, die berücksichtigt werden müssen:
Die Unterschiede zwischen VHDL-Modellen von DFFs und Latches.
Beschreiben der Flanken eines Signals.
So beschreiben Sie synchrones oder asynchrones Setzen oder Zurücksetzen.
D-Flip-Flops (DFF)
In allen Beispielen:
-
clk
ist die uhr, -
d
ist die Eingabe, -
q
ist die Ausgabe, -
srst
ist ein aktiversrst
Reset, -
srstn
ist ein aktiver niedriger synchroner Reset, -
arst
ist ein aktiver hoher asynchroner Reset. -
arstn
ist ein aktiver niedriger asynchroner Reset. -
sset
ist ein aktiversset
Satz, -
ssetn
ist ein aktiver niedriger synchroner Satz. -
aset
ist ein aktiver hoher asynchroner Satz. -
asetn
ist ein aktiver niedriger asynchroner Satz
Alle Signale sind vom Typ ieee.std_logic_1164.std_ulogic
. Die verwendete Syntax führt zu korrekten Syntheseergebnissen bei allen Logiksynthesizern. Weitere Informationen zur alternativen Syntax finden Sie im Beispiel zur Erkennung der Taktflanke.
Uhr mit steigender Flanke
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
Fallende rand uhr
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
Anstiegsflankentakt, synchron aktiver High-Reset
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Takt mit steigender Flanke, asynchroner aktiver High-Reset
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Fallender Flankentakt, asynchroner aktiver Low-Reset, synchroner aktiver High-Satz
process(clk, arstn)
begin
if arstn = '0' then
q <= '0';
elsif falling_edge(clk) then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
Takt mit steigender Flanke, asynchroner aktiver High-Reset, asynchroner aktiver Low-Satz
Hinweis: Set hat höhere Priorität als Reset
process(clk, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Latches
In allen Beispielen:
-
en
ist das Freigabesignal, -
d
ist die Eingabe, -
q
ist die Ausgabe, -
srst
ist ein aktiversrst
Reset, -
srstn
ist ein aktiver niedriger synchroner Reset, -
arst
ist ein aktiver hoher asynchroner Reset. -
arstn
ist ein aktiver niedriger asynchroner Reset. -
sset
ist ein aktiversset
Satz, -
ssetn
ist ein aktiver niedriger synchroner Satz. -
aset
ist ein aktiver hoher asynchroner Satz. -
asetn
ist ein aktiver niedriger asynchroner Satz
Alle Signale sind vom Typ ieee.std_logic_1164.std_ulogic
. Die verwendete Syntax führt zu korrekten Syntheseergebnissen bei allen Logiksynthesizern. Weitere Informationen zur alternativen Syntax finden Sie im Beispiel zur Erkennung der Taktflanke.
Aktiv hoch aktivieren
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
Aktiv low aktivieren
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
Active-High-Freigabe, synchrones Active-High-Reset
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Active-High-Freigabe, asynchroner Active-High-Reset
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Aktiv-Low-Freigabe, asynchrones Active-Low-Reset, synchrones Active-High-Set gesetzt
process(en, d, arstn)
begin
if arstn = '0' then
q <= '0';
elsif en = '0' then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
Aktive Hochfreigabe, asynchroner aktiver Hochreset, asynchroner aktiver Niedrigsatz
Hinweis: Set hat höhere Priorität als Reset
process(en, d, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Taktflankenerkennung
Die Kurzgeschichte
Mit VHDL 2008 und wenn der Typ der Uhr bit
, boolean
, ieee.std_logic_1164.std_ulogic
oder ieee.std_logic_1164.std_logic
, kann eine Taktflankenerkennung für die steigende Flanke codiert werden
-
if rising_edge(clock) then
-
if clock'event and clock = '1' then -- type bit, std_ulogic or std_logic
-
if clock'event and clock then -- type boolean
und für fallende Kante
-
if falling_edge(clock) then
-
if clock'event and clock = '0' then -- type bit, std_ulogic or std_logic
-
if clock'event and not clock then -- type boolean
Dies wird sich erwartungsgemäß sowohl für die Simulation als auch für die Synthese verhalten.
Hinweis: Die Definition einer steigenden Flanke eines Signals vom Typ
std_ulogic
ist etwas komplexer als die einfache,if clock'event and clock = '1' then
. Beispielsweise hat die Standard-rising_edge
Funktion eine andere Definition. Selbst wenn es für die Synthese wahrscheinlich keinen Unterschied macht, könnte es einen für die Simulation ergeben.
Die Verwendung der Standardfunktionen rising_edge
und falling_edge
wird dringend falling_edge
. Bei früheren Versionen von VHDL die Verwendung dieser Funktionen erfordert explizit die Verwendung von Standardpaketen zu deklarieren (zB ieee.numeric_bit
für Typ - bit
) oder sogar in einem benutzerdefinierten Paket zu definieren.
Hinweis: Verwenden Sie nicht die Standardfunktionen
rising_edge
undfalling_edge
, um Flanken von Nicht-Taktsignalen zu erkennen. Einige Synthesizer können daraus schließen, dass das Signal eine Uhr ist. Hinweis: Das Erkennen einer Flanke eines Nichttaktsignals kann häufig durch Abtasten des Signals in einem Schieberegister und Vergleichen der abgetasteten Werte in verschiedenen Stufen des Schieberegisters erfolgen.
Die lange Geschichte
Bei der Modellierung von D-Flip-Flops (DFF) ist es wichtig, die Erkennung der Flanken eines Taktsignals richtig zu beschreiben. Eine Kante ist definitionsgemäß ein Übergang von einem bestimmten Wert zu einem anderen. Zum Beispiel können wir die ansteigende Flanke eines Signals vom Typ bit
(der Standard-VHDL-Aufzählungstyp, der zwei Werte akzeptiert: '0'
und '1'
) als Übergang von '0'
nach '1'
. Für den Typ boolean
wir es als Übergang von false
nach true
.
Häufig werden komplexere Typen verwendet. Der Typ ieee.std_logic_1164.std_ulogic
ist beispielsweise ebenso wie bit
oder boolean
ein Aufzählungstyp, hat aber 9 statt 2:
Wert | Bedeutung |
---|---|
'U' | Nicht initialisiert |
'X' | Forcieren unbekannt |
'0' | Niedriger Pegel erzwingen |
'1' | Hohe Ebene erzwingen |
'Z' | Hohe Impedanz |
'W' | Schwach unbekannt |
'L' | Schwaches niedriges Niveau |
'H' | Schwaches hohes Niveau |
'-' | Kümmere dich nicht |
Das Definieren einer ansteigenden Flanke für einen solchen Typ ist etwas komplexer als für bit
oder boolean
. Wir können zum Beispiel entscheiden, dass es sich um einen Übergang von '0'
nach '1'
. Wir können aber auch entscheiden, dass es sich um einen Übergang von '0'
oder 'L'
zu '1'
oder 'H'
.
Hinweis: Es ist diese zweite Definition ist , dass der Standard für den uses
rising_edge(signal s: std_ulogic)
Funktion in definiertenieee.std_logic_1164
.
Bei der Erörterung der verschiedenen Möglichkeiten zum Erkennen von Kanten ist es daher wichtig, die Art des Signals zu berücksichtigen. Es ist auch wichtig, das Modellierungsziel zu berücksichtigen: nur Simulation oder Logiksynthese? Lassen Sie uns das an einigen Beispielen veranschaulichen:
Anstiegsflanke DFF mit Typbit
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
Aus reiner Simulationssemantik betrachtet, modelliert der Prozess P1
eine durch eine steigende Flanke ausgelöste DFF. Die Zuordnung q <= d
wird genau dann ausgeführt, wenn:
-
clock
geändert (dies ist, was die Empfindlichkeitsliste ausdrückt) und - Der aktuelle Wert der
clock
ist'1'
.
Da clock
vom Typ bit ist und type bit nur die Werte '0'
und '1'
, haben wir genau dies als steigende Flanke eines Signals vom Typ bit definiert. Jeder Simulator behandelt dieses Modell wie erwartet.
Hinweis: Bei Logik-Synthesizern sind die Dinge etwas komplexer, wie wir später sehen werden.
Anstiegsflanke DFF mit asynchronem aktivem High-Reset und Typbit
Um einen asynchronen aktiven High-Reset unserer DFF hinzuzufügen, könnte man Folgendes versuchen:
signal clock, reset, d, q: bit;
...
P2_BOGUS: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' then
q <= d;
end if;
end process P2_BOGUS;
Das funktioniert aber nicht . Die Bedingung für die q <= d
Zuweisung q <= d
sollte lauten: eine steigende Flanke der clock
beim reset = '0'
. Was wir modelliert haben, ist jedoch:
-
clock
oderreset
oder beides geändert und -
reset = '0'
und -
clock = '1'
Das ist nicht dasselbe: Wenn sich reset
von '1'
auf '0'
ändert '0'
während clock = '1'
die Zuweisung ausgeführt, solange es keine steigende Flanke der clock
.
Tatsächlich gibt es keine Möglichkeit, dies in VHDL ohne die Hilfe eines Signalattributs zu modellieren:
P2_OK: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' and clock'event then
q <= d;
end if;
end process P2_OK;
Das clock'event
ist das Signal Attribut event
zu signalisieren angewandt clock
. Es wird als boolean
ausgewertet und true
nur dann zu, wenn sich der Signaltakt während der clock
geändert hat, die gerade der aktuellen Ausführungsphase vorausging. Dank diesem Prozess P2_OK
jetzt perfekt, was wir in der Simulation (und Synthese) wollen.
Synthese-Semantik
Viele Logiksynthesizer erkennen Signalflankendetektionen basierend auf syntaktischen Mustern, nicht auf der Semantik des VHDL-Modells. Mit anderen Worten, sie berücksichtigen, wie der VHDL-Code aussieht, und nicht, welches Verhalten er modelliert. Eines der Muster, die sie alle kennen, ist:
if clock = '1' and clock'event then
Selbst im Beispiel des Prozesses P1
sollten wir es verwenden, wenn unser Modell für alle Logiksynthesizer synthetisierbar sein soll:
signal clock, d, q: bit;
...
P1_OK: process(clock)
begin
if clock = '1' and clock'event then
q <= d;
end if;
end process P1_OK;
Der Teil and clock'event
der Bedingung ist mit der Sensitivitätsliste völlig überflüssig, aber da einige Synthesizer es benötigen ...
std_ulogic
DFF mit asynchronem aktivem High-Reset und Typ std_ulogic
In diesem Fall kann das Ausdrücken der ansteigenden Flanke der Uhr und der Rücksetzbedingung kompliziert werden. Wenn wir die Definition einer ansteigenden Flanke beibehalten, die wir oben vorgeschlagen haben, und wenn wir annehmen, dass der Reset aktiv ist, wenn er '1'
oder 'H'
, wird das Modell zu:
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4: process(clock, reset)
begin
if reset = '1' or reset = 'H' then
q <= '0';
elsif clock'event and
(clock'last_value = '0' or clock'last_value = 'L') and
(clock = '1' or clock = 'H') then
q <= d;
end if;
end process P4;
Hinweis:
'last_value
ist ein weiteres'last_value
, das den Wert zurückgibt, den das Signal vor der letzten Wertänderung hatte.
Hilfsfunktionen
Der VHDL 2008-Standard bietet mehrere Hilfsfunktionen, um die Erkennung von Signalflanken zu vereinfachen, insbesondere bei mehrwertigen Aufzählungsarten wie std_ulogic
. Das Paket std.standard
definiert die Funktionen rising_edge
und falling_edge
für die Typen bit
und boolean
ieee.std_logic_1164
Paket ieee.std_logic_1164
definiert sie für die Typen std_ulogic
und std_logic
.
Hinweis: Bei früheren Versionen von VHDL muss die Verwendung dieser Funktionen die Verwendung von Standardpaketen (z. B. ieee.numeric_bit für Typbit) explizit deklarieren oder sogar in einem Benutzerpaket definieren.
Gehen wir die vorherigen Beispiele noch einmal durch und verwenden Sie die Hilfsfunktionen:
signal clock, d, q: bit;
...
P1_OK_NEW: process(clock)
begin
if rising_edge(clock) then
q <= d;
end if;
end process P1_OK_NEW;
signal clock, d, q: bit;
...
P2_OK_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P2_OK_NEW;
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P4_NEW;
Hinweis: In diesem letzten Beispiel haben wir auch den Test beim Zurücksetzen vereinfacht. Floating, hochohmige Resets sind ziemlich selten und in den meisten Fällen funktioniert diese vereinfachte Version für Simulation und Synthese.