vhdl
D-Flip-Flops (DFF) et loquets
Recherche…
Remarques
D-Flip-Flops (DFF) et les loquets sont des éléments de mémoire. Un DFF échantillonne son entrée sur l'un ou l'autre bord de son horloge (pas les deux), tandis qu'un verrou est transparent à un niveau de son activation et mémorisé sur l'autre. La figure suivante illustre la différence:
Modéliser des DFF ou des verrous dans VHDL est facile mais il y a quelques aspects importants à prendre en compte:
Les différences entre les modèles VHDL de DFF et les verrous.
Comment décrire les bords d'un signal.
Comment décrire un ensemble ou des réinitialisations synchrones ou asynchrones.
D-Flip-Flops (DFF)
Dans tous les exemples:
-
clk
est l'horloge, -
d
est l'entrée, -
q
est la sortie, -
srst
est une réinitialisation active haute synchrone, -
srstn
est une réinitialisation active synchrone basse, -
arst
est une réinitialisation asynchrone active, -
arstn
est une réinitialisation asynchrone active, -
sset
est un ensemble haute synchrone actif, -
ssetn
est un ensemble synchrone actif, -
aset
est un ensemble haut asynchrone actif, -
asetn
est un ensemble bas asynchrone actif
Tous les signaux sont de type ieee.std_logic_1164.std_ulogic
. La syntaxe utilisée est celle qui permet de corriger les résultats de synthèse avec tous les synthétiseurs logiques. Veuillez vous reporter à l'exemple de détection du bord de l' horloge pour une discussion sur la syntaxe alternative.
Horloge de bord montante
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
Horloge de bord tombant
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
Horloge à front montant, réinitialisation active synchrone
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Horloge de bord montante, réinitialisation active asynchrone
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Horloge à front descendant, asynchrone active à faible réinitialisation, synchrone active synchrone
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;
Horloge de bord montante, asynchrone active haute réinitialisation, bas active asynchrone
Remarque: set a une priorité plus élevée que 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;
Loquets
Dans tous les exemples:
-
en
est le signal d'activation, -
d
est l'entrée, -
q
est la sortie, -
srst
est une réinitialisation active haute synchrone, -
srstn
est une réinitialisation active synchrone basse, -
arst
est une réinitialisation asynchrone active, -
arstn
est une réinitialisation asynchrone active, -
sset
est un ensemble haute synchrone actif, -
ssetn
est un ensemble synchrone actif, -
aset
est un ensemble haut asynchrone actif, -
asetn
est un ensemble bas asynchrone actif
Tous les signaux sont de type ieee.std_logic_1164.std_ulogic
. La syntaxe utilisée est celle qui permet de corriger les résultats de synthèse avec tous les synthétiseurs logiques. Veuillez vous reporter à l'exemple de détection du bord de l' horloge pour une discussion sur la syntaxe alternative.
Active haute active
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
Actif bas actif
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
Activation haute active, réinitialisation active synchrone
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Activation haute active, réinitialisation active asynchrone
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Actif bas actif, asynchrone actif à faible réinitialisation, ensemble haut actif synchrone
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;
Activation haute active, asynchrone active réinitialisation élevée, bas active asynchrone
Remarque: set a une priorité plus élevée que 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;
Détection de bord d'horloge
La petite histoire
Avec VHDL 2008 et si le type de l’horloge est bit
, boolean
, ieee.std_logic_1164.std_ulogic
ou ieee.std_logic_1164.std_logic
, une détection de bord d’horloge peut être codée pour le front montant
-
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
et pour front descendant
-
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
Cela se comportera comme prévu, à la fois pour la simulation et la synthèse.
Note: la définition d'un front montant sur un signal de type
std_ulogic
est un peu plus complexe que le simpleif clock'event and clock = '1' then
.rising_edge
exemple, la fonction standard d'rising_edge
contient une définition différente. Même si cela ne fera probablement pas de différence pour la synthèse, cela pourrait en faire une pour la simulation.
L'utilisation des fonctions standard rising_edge
et falling_edge
est fortement encouragée. Avec les versions précédentes de VHDL, l'utilisation de ces fonctions peut nécessiter de déclarer explicitement l'utilisation de packages standard (par exemple ieee.numeric_bit
pour le type bit
) ou même de les définir dans un package personnalisé.
Remarque: n'utilisez pas les fonctions standard
rising_edge
etfalling_edge
pour détecter les contours des signaux hors horloge. Certains synthétiseurs pourraient conclure que le signal est une horloge. Astuce: la détection d'un front sur un signal hors horloge peut souvent être effectuée en échantillonnant le signal dans un registre à décalage et en comparant les valeurs échantillonnées à différents stades du registre à décalage.
La longue histoire
Décrire correctement la détection des bords d'un signal d'horloge est essentiel lors de la modélisation de D-Flip-Flops (DFF). Une arête est, par définition, une transition d'une valeur particulière à une autre. Par exemple, on peut définir le front montant d'un signal de type bit
(le type énuméré VHDL standard qui prend deux valeurs: '0'
et '1'
) comme transition de '0'
à '1'
. Pour le type boolean
nous pouvons le définir comme une transition de false
à true
.
Souvent, des types plus complexes sont utilisés. Le type ieee.std_logic_1164.std_ulogic
, par exemple, est également un type énuméré, tout comme bit
ou boolean
, mais il a 9 valeurs au lieu de 2:
Valeur | Sens |
---|---|
'U' | Non initialisé |
'X' | Forçage inconnu |
'0' | Forcer le bas niveau |
'1' | Forcer haut niveau |
'Z' | Haute impédance |
'W' | Faible inconnu |
'L' | Faible niveau bas |
'H' | Faible niveau élevé |
'-' | Ne t'en fais pas |
Définir un front montant sur un tel type est un peu plus complexe que pour bit
ou boolean
. Nous pouvons, par exemple, décider que c'est une transition de '0'
à '1'
. Mais on peut aussi décider que c'est une transition de '0'
ou 'L'
à '1'
ou 'H'
.
Note: c'est cette seconde définition que le standard utilise pour la fonction
rising_edge(signal s: std_ulogic)
définie dansieee.std_logic_1164
.
Lorsque vous discutez des différentes manières de détecter les contours, il est donc important de prendre en compte le type de signal. Il est également important de prendre en compte l'objectif de modélisation: simulation uniquement ou synthèse logique? Illustrons ceci sur quelques exemples:
Bord montant DFF avec bit de type
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
Techniquement, du point de vue de la sémantique de simulation, le processus P1
modélise un DFF déclenché par un front montant. En effet, l'attribution q <= d
est exécutée si et seulement si:
-
clock
changé (c'est ce que la liste de sensibilité exprime) et - la valeur actuelle de l'
clock
est'1'
.
Comme l' clock
est de type bit et que le type bit n'a que des valeurs '0'
et '1'
, c'est exactement ce que nous avons défini comme un front montant d'un signal de type bit. Tout simulateur traitera ce modèle comme prévu.
Note: Pour les synthétiseurs logiques, les choses sont un peu plus complexes, comme nous le verrons plus tard.
Front montant DFF avec réinitialisation active asynchrone et bit de type
Pour ajouter une réinitialisation active asynchrone à notre DFF, on pourrait essayer quelque chose comme:
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;
Mais cela ne fonctionne pas . La condition pour que l'attribution q <= d
à exécuter soit: un front montant de l' clock
tandis que reset = '0'
. Mais ce que nous avons modélisé est:
-
clock
oureset
ou à la fois changé et -
reset = '0'
et -
clock = '1'
Ce qui n'est pas la même chose: si la reset
passe de '1'
à '0'
alors que clock = '1'
l'assignation sera exécutée alors qu'il ne s'agit pas d' un front montant de l' clock
.
En fait, il n'y a aucun moyen de modéliser cela dans VHDL sans l'aide d'un attribut de signal:
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;
Le clock'event
est l'attribut de signal event
appliqué pour signaler l' clock
. Il est évalué comme un boolean
et il est true
si et seulement si l' clock
signal a changé pendant la phase de mise à jour du signal qui a juste précédé la phase d'exécution en cours. Grâce à cela, le processus P2_OK
modélise parfaitement ce que nous voulons en simulation (et en synthèse).
Sémantique de synthèse
De nombreux synthétiseurs logiques identifient les détections de fronts de signal basées sur des schémas syntaxiques et non sur la sémantique du modèle VHDL. En d'autres termes, ils considèrent ce à quoi ressemble le code VHDL, et non son comportement. L'un des modèles qu'ils reconnaissent tous est:
if clock = '1' and clock'event then
Donc, même dans l'exemple du processus P1
nous devrions l'utiliser si nous voulons que notre modèle soit synthétisable par tous les synthétiseurs logiques:
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;
La partie and clock'event
partie and clock'event
de la condition sont complètement redondantes avec la liste de sensibilité mais comme certains synthétiseurs en ont besoin ...
DFF de front montant avec réinitialisation active asynchrone et type std_ulogic
Dans ce cas, l'expression du front montant de l'horloge et la condition de réinitialisation peuvent devenir compliquées. Si nous retenons la définition d'un front que nous avons proposée ci-dessus et si nous considérons que la réinitialisation est active si elle est '1'
ou 'H'
, le modèle devient:
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;
Remarque:
'last_value
est un autre attribut de signal qui renvoie la valeur que le signal avait avant la dernière modification de valeur.
Fonctions d'aide
La norme VHDL 2008 offre plusieurs fonctions d'assistance pour simplifier la détection des std_ulogic
de signal, en particulier avec les types énumérés à plusieurs valeurs tels que std_ulogic
. Le package std.standard
définit les fonctions rising_edge
et falling_edge
sur les types bit
et boolean
et le package ieee.std_logic_1164
les définit sur les types std_ulogic
et std_logic
.
Remarque: avec les versions précédentes de VHDL, l'utilisation de ces fonctions peut nécessiter de déclarer explicitement l'utilisation de packages standard (par exemple, ieee.numeric_bit pour le type bit) ou même de les définir dans un package utilisateur.
Revenons aux exemples précédents et utilisons les fonctions d'aide:
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;
Remarque: dans ce dernier exemple, nous avons également simplifié le test lors de la réinitialisation. Flottant, haute impédance, les réinitialisations sont assez rares et, dans la plupart des cas, cette version simplifiée fonctionne pour la simulation et la synthèse.