vhdl
D-flip-flop (DFF) e fermi
Ricerca…
Osservazioni
D-Flip-Flops (DFF) e latch sono elementi di memoria. Un DFF campiona il suo input su uno o sull'altro bordo del suo clock (non su entrambi) mentre un latch è trasparente su un livello della sua abilitazione e memorizza sull'altro. La seguente figura illustra la differenza:
La modellazione di DFF o latch in VHDL è semplice, ma ci sono alcuni aspetti importanti che devono essere presi in considerazione:
Le differenze tra i modelli VHDL di DFF e latch.
Come descrivere i bordi di un segnale.
Come descrivere set o reset sincroni o asincroni.
D-flip-flop (DFF)
In tutti gli esempi:
-
clk
è l'orologio, -
d
è l'input, -
q
è l'output, -
srst
è un reset high sincrono attivo, -
srstn
è un reset sincrono basso attivo, -
arst
è un'alta reset asincrono attivo, -
arstn
è un reset asincrono basso attivo, -
sset
è un set high sincrono attivo, -
ssetn
è un set basso sincrono attivo, -
aset
è un set asincrono attivo alto, -
asetn
è un set asincrono basso attivo
Tutti i segnali sono di tipo ieee.std_logic_1164.std_ulogic
. La sintassi utilizzata è quella che porta a risultati di sintesi corretti con tutti i sintetizzatori logici. Si prega di consultare l'esempio di rilevamento del bordo dell'orologio per una discussione sulla sintassi alternativa.
Orologio a bordo in aumento
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
Orologio a caduta
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
Orologio con fronte di salita, reset alto sincrono attivo
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Orologio con fronte di salita, reset alto attivo asincrono
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Orologio con fronte di discesa, reset basso attivo asincrono, set attivo sincrono alto
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;
Orologio con fronte di salita, reset alto attivo asincrono, set basso attivo asincrono
Nota: il set ha una priorità più alta del 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;
Chiusure
In tutti gli esempi:
-
en
è il segnale di abilitazione, -
d
è l'input, -
q
è l'output, -
srst
è un reset high sincrono attivo, -
srstn
è un reset sincrono basso attivo, -
arst
è un'alta reset asincrono attivo, -
arstn
è un reset asincrono basso attivo, -
sset
è un set high sincrono attivo, -
ssetn
è un set basso sincrono attivo, -
aset
è un set asincrono attivo alto, -
asetn
è un set asincrono basso attivo
Tutti i segnali sono di tipo ieee.std_logic_1164.std_ulogic
. La sintassi utilizzata è quella che porta a risultati di sintesi corretti con tutti i sintetizzatori logici. Si prega di consultare l'esempio di rilevamento del bordo dell'orologio per una discussione sulla sintassi alternativa.
Attiva alta abilita
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
Attiva basso attivo
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
Abilitazione alta attiva, reset alto attivo sincrono
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Attiva alta attiva, reset alto attivo asincrono
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Attiva basso attivo, reset basso attivo asincrono, set attivo sincrono alto
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;
Abilitazione alta attiva, reset alto attivo asincrono, set basso attivo asincrono
Nota: il set ha una priorità più alta del 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;
Rilevamento del bordo dell'orologio
Il racconto
Con VHDL 2008 e se il tipo di clock è bit
, boolean
, ieee.std_logic_1164.std_ulogic
o ieee.std_logic_1164.std_logic
, è possibile codificare un rilevamento del fronte di clock per il fronte di salita
-
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
e per la caduta
-
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
Questo si comporterà come previsto, sia per la simulazione che per la sintesi.
Nota: la definizione di un fronte di salita su un segnale di tipo
std_ulogic
è un po 'più complessa della sempliceif clock'event and clock = '1' then
. La funzionerising_edge
standard, ad esempio, ha una definizione diversa. Anche se probabilmente non farà alcuna differenza per la sintesi, potrebbe farne uno per la simulazione.
L'uso delle funzioni standard rising_edge
e falling_edge
è fortemente incoraggiato. Con le versioni precedenti di VHDL l'uso di queste funzioni potrebbe richiedere di dichiarare esplicitamente l'uso di pacchetti standard (ad es. ieee.numeric_bit
per il bit
tipo) o persino di definirli in un pacchetto personalizzato.
Nota: non utilizzare le funzioni standard
rising_edge
efalling_edge
per rilevare i bordi dei segnali senza orologio. Alcuni sintetizzatori potrebbero concludere che il segnale è un orologio. Suggerimento: il rilevamento di un fronte su un segnale senza orologio può essere spesso effettuato campionando il segnale in un registro a scorrimento e confrontando i valori campionati in diverse fasi del registro a scorrimento.
La lunga storia
Descrivere correttamente il rilevamento dei bordi di un segnale di clock è essenziale quando si modella D-Flip-Flops (DFF). Un bordo è, per definizione, una transizione da un particolare valore a un altro. Ad esempio, possiamo definire il fronte di salita di un segnale di tipo bit
(il tipo enumerato VHDL standard che prende due valori: '0'
e '1'
) come transizione da '0'
a '1'
. Per tipo boolean
possiamo definirlo come una transizione da false
a true
.
Spesso vengono utilizzati tipi più complessi. Il tipo ieee.std_logic_1164.std_ulogic
, ad esempio, è anche un tipo enumerato, proprio come bit
o boolean
, ma ha 9 valori anziché 2:
Valore | Senso |
---|---|
'U' | non inizializzata |
'X' | Forzare sconosciuto |
'0' | Forzando basso livello |
'1' | Forzare alto livello |
'Z' | Alta impedenza |
'W' | Debole sconosciuto |
'L' | Basso livello debole |
'H' | Alto livello debole |
'-' | Non importa |
Definire un fronte di salita su un tipo di questo tipo è un po 'più complesso rispetto a bit
o boolean
. Ad esempio, possiamo decidere che è una transizione da '0'
a '1'
. Ma possiamo anche decidere che si tratta di una transizione da '0'
o 'L'
a '1'
o 'H'
.
Nota: è questa seconda definizione che lo standard usa per la funzione
rising_edge(signal s: std_ulogic)
definita inieee.std_logic_1164
.
Quando si discutono i vari modi per rilevare i bordi, è quindi importante considerare il tipo di segnale. È anche importante prendere in considerazione l'obiettivo della modellizzazione: solo simulazione o sintesi logica? Cerchiamo di illustrare questo su alcuni esempi:
DFF con fronte di salita con bit di tipo
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
Tecnicamente, su un punto di vista della semantica di pura simulazione, il processo P1
modella un DFF attivato dal fronte di salita. In effetti, l'assegnazione q <= d
viene eseguita se e solo se:
-
clock
modificato (questo è ciò che esprime la lista di sensibilità) e - il valore corrente
clock
è'1'
.
Poiché l' clock
è di tipo bit e tipo bit ha solo valori '0'
e '1'
, questo è esattamente ciò che abbiamo definito come un fronte di salita di un segnale di tipo bit. Qualsiasi simulatore gestirà questo modello come ci aspettiamo.
Nota: per i sintetizzatori logici, le cose sono un po 'più complesse, come vedremo in seguito.
DFF con fronte di salita con reset alto attivo asincrono e bit di tipo
Per aggiungere un reset alto attivo asincrono al nostro DFF, si potrebbe provare qualcosa come:
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;
Ma questo non funziona . La condizione per l'assegnazione q <= d
da eseguire dovrebbe essere: un fronte di salita clock
mentre reset = '0'
. Ma ciò che abbiamo modellato è:
-
clock
oreset
o entrambi cambiati e -
reset = '0'
e -
clock = '1'
Il che non è la stessa: se reset
cambia da '1'
a '0'
, mentre clock = '1'
l'assegnazione verranno eseguiti anche se non è un fronte di salita di clock
.
In realtà, non c'è modo di modellarlo in VHDL senza l'aiuto di un attributo di segnale:
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;
Il clock'event
è l' event
attributo del segnale applicato al clock
segnale. Valuta come boolean
ed è true
se e solo se il clock
segnale clock
cambiato durante la fase di aggiornamento del segnale che ha appena preceduto la fase di esecuzione corrente. Grazie a questo, il processo P2_OK
ora modella perfettamente ciò che vogliamo nella simulazione (e nella sintesi).
Semantica di sintesi
Molti sintetizzatori logici identificano i rilevamenti del bordo del segnale basati su modelli sintattici, non sulla semantica del modello VHDL. In altre parole, considerano come si presenta il codice VHDL e non come si comporta. Uno dei modelli che tutti riconoscono è:
if clock = '1' and clock'event then
Quindi, anche nell'esempio del processo P1
dovremmo usarlo se vogliamo che il nostro modello sia sintetizzabile da tutti i sintetizzatori logici:
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 parte relativa alla condizione di and clock'event
è completamente ridondante con la lista di sensibilità ma come alcuni sintetizzatori ne hanno bisogno ...
DFF con fronte di salita con reset alto attivo asincrono e tipo std_ulogic
In questo caso, esprimere il fronte di salita dell'orologio e la condizione di reset può diventare complicato. Se manteniamo la definizione di un fronte di salita che abbiamo proposto sopra e se consideriamo che il reset è attivo se è '1'
o 'H'
, il modello diventa:
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;
Nota:
'last_value
è un altro attributo del segnale che restituisce il valore che il segnale aveva prima dell'ultima modifica del valore.
Funzioni di supporto
Lo standard VHDL 2008 offre diverse funzioni di supporto per semplificare il rilevamento dei fronti del segnale, in particolare con tipi enumerati multivalore come std_ulogic
. Il pacchetto std.standard
definisce le funzioni rising_edge
e falling_edge
sui tipi bit
e boolean
e il pacchetto ieee.std_logic_1164
li definisce sui tipi std_ulogic
e std_logic
.
Nota: con le versioni precedenti di VHDL l'uso di queste funzioni potrebbe richiedere di dichiarare esplicitamente l'uso di pacchetti standard (ad esempio ieee.numeric_bit per il bit di tipo) o persino di definirli in un pacchetto utente.
Cerchiamo di rivisitare gli esempi precedenti e utilizzare le funzioni di supporto:
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;
Nota: in questo ultimo esempio abbiamo anche semplificato il test sul reset. I ripristini flottanti ad alta impedenza sono piuttosto rari e, nella maggior parte dei casi, questa versione semplificata funziona per la simulazione e la sintesi.