vhdl
D-Flip-Flops (DFF) och spärrar
Sök…
Anmärkningar
D-Flip-Flops (DFF) och spärrar är minneselement. En DFF samplar sin ingång på den ena eller den andra kanten av sin klocka (inte båda) medan en spärr är transparent på en nivå av dess aktivering och memorering på den andra. Följande figur illustrerar skillnaden:
Det är enkelt att modellera DFF: er eller spärrar i VHDL men det är några viktiga aspekter som måste beaktas:
Skillnaderna mellan VHDL-modeller av DFF: er och spärrar.
Hur man beskriver kanterna på en signal.
Hur man beskriver synkron eller asynkron uppsättning eller återställning.
D-Flip-Flops (DFF)
I alla exempel:
-
clk
är klockan, -
d
är ingången, -
q
är utgången, -
srst
är en aktiv hög synkron återställning, -
srstn
är en aktiv lågsynkron återställning, -
arst
är en aktiv hög asynkron återställning, -
arstn
är en aktiv låg asynkron återställning, -
sset
är en aktiv högsynkronuppsättning, -
ssetn
är en aktiv lågsynkronuppsättning, -
aset
är en aktiv hög asynkron uppsättning, -
asetn
är en aktiv låg-asynkron uppsättning
Alla signaler är av typen ieee.std_logic_1164.std_ulogic
. Syntaxen som används är den som leder till korrekta syntesresultat med alla logiska synteser. Se exempel på klockkantdetektering för en diskussion om alternativ syntax.
Stigande klocka
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
Fallande kantklocka
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
Stigande klocka, synkron aktiv hög återställning
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Stigande klocka, asynkron aktiv hög återställning
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
Fallande kantklocka, asynkron aktiv låg återställning, synkron aktiv höguppsättning
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;
Stigande klocka, asynkron aktiv hög återställning, asynkron aktiv låg inställning
Obs: set har högre prioritet än återställning
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
I alla exempel:
-
en
är aktiveringssignalen, -
d
är ingången, -
q
är utgången, -
srst
är en aktiv hög synkron återställning, -
srstn
är en aktiv lågsynkron återställning, -
arst
är en aktiv hög asynkron återställning, -
arstn
är en aktiv låg asynkron återställning, -
sset
är en aktiv högsynkronuppsättning, -
ssetn
är en aktiv lågsynkronuppsättning, -
aset
är en aktiv hög asynkron uppsättning, -
asetn
är en aktiv låg-asynkron uppsättning
Alla signaler är av typen ieee.std_logic_1164.std_ulogic
. Syntaxen som används är den som leder till korrekta syntesresultat med alla logiska synteser. Se exempel på klockkantdetektering för en diskussion om alternativ syntax.
Aktiv hög aktivering
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
Aktiv låg aktivering
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
Aktiv hög aktivering, synkron aktiv hög återställning
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
Aktiv hög aktivering, asynkron aktiv hög återställning
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
Aktiv låg aktivering, asynkron aktiv låg återställning, synkron aktiv hög uppsättning
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;
Aktiv hög aktivering, asynkron aktiv hög återställning, asynkron aktiv låg inställning
Obs: set har högre prioritet än återställning
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;
Klockkantdetektering
Den korta historien
Med VHDL 2008 och om klocktypen är bit
, boolean
, ieee.std_logic_1164.std_ulogic
eller ieee.std_logic_1164.std_logic
, kan en ieee.std_logic_1164.std_logic
kodas för stigande kant
-
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
och för fallande kant
-
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
Detta kommer att bete sig som förväntat, både för simulering och syntes.
Obs: definitionen av en stigande kant på en signal av typen
std_ulogic
är lite mer komplex än den enklaif clock'event and clock = '1' then
. Standardenrising_edge
funktion, till exempel, har en annan definition. Även om det förmodligen inte kommer att göra någon skillnad för syntesen, kan det göra en för simulering.
Användning av rising_edge
och falling_edge
uppmuntras starkt. Med tidigare versioner av VHDL användningen av dessa funktioner kan kräva att uttryckligen förklara användningen av standardpaket (t.ex. ieee.numeric_bit
för typ bit
) eller till och med att definiera dem i en anpassad paket.
Obs:
rising_edge
falling_edge
standardfunktionernarising_edge
ochfalling_edge
för att upptäcka kanter på icke-klocksignaler. Vissa synthesizers kan dra slutsatsen att signalen är en klocka. Tips: detektering av en kant på en icke-klocksignal kan ofta göras genom att sampla in signalen i ett skiftregister och jämföra samplade värden i olika steg i skiftregistret.
Den långa berättelsen
Att korrekt beskriva detekteringen av kanterna på en klocksignal är avgörande vid modellering av D-Flip-Flops (DFF). En kant är per definition en övergång från ett visst värde till ett annat. Till exempel kan vi definiera stigningen på en signal av bit
(den standardiserade VHDL-typen som tar två värden: '0'
och '1'
) som övergången från '0'
till '1'
. För typ boolean
vi definiera det som en övergång från false
till true
.
Ofta används mer komplexa typer. ieee.std_logic_1164.std_ulogic
är till exempel också en uppräknad typ, precis som bit
eller boolean
, men har 9 värden istället för 2:
Värde | Menande |
---|---|
'U' | oinitierad |
'X' | Tvinga okänt |
'0' | Tvinga låg nivå |
'1' | Tvinga hög nivå |
'Z' | Hög impedans |
'W' | Svag okänd |
'L' | Svag låg nivå |
'H' | Svag hög nivå |
'-' | Bryr sig inte |
Att definiera en stigande kant på en sådan typ är lite mer komplex än för bit
eller boolean
. Vi kan till exempel bestämma att det är en övergång från '0'
till '1'
. Men vi kan också bestämma att det är en övergång från '0'
eller 'L'
till '1'
eller 'H'
.
Obs: det är denna andra definition som standarden använder för den
rising_edge(signal s: std_ulogic)
-funktionen definierad iieee.std_logic_1164
.
När man diskuterar olika sätt att upptäcka kanter är det alltså viktigt att beakta signalens typ. Det är också viktigt att ta hänsyn till modelleringsmålet: endast simulering eller logisk syntes? Låt oss illustrera detta med några exempel:
Rising edge DFF med typbit
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
Tekniskt sett, på ren simuleringssemantik synvinkel, process P1
modellerar en stigande kant utlöst DFF. Faktum är att q <= d
tilldelningen utförs om och bara om:
-
clock
ändrats (detta är vad känslighetslistan uttrycker) och -
clock
nuvarande värde är'1'
.
Eftersom clock
är av typbit och typbit har bara värden '0'
och '1'
, är det exakt vad vi definierade som en stigande kant av en signal av typbit. Varje simulator hanterar den här modellen som vi förväntar oss.
Obs: För logiska synthesizers är sakerna lite mer komplexa, som vi kommer att se senare.
Rising edge DFF med asynkron aktiv hög återställning och typbit
För att lägga till en asynkron aktiv hög återställning till vår DFF kan man prova något som:
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;
Men detta fungerar inte . Villkoret för att q <= d
tilldelningen ska utföras ska vara: en stigande clock
medan reset = '0'
. Men det vi modellerade är:
-
clock
ellerreset
eller båda ändrade och -
reset = '0'
och -
clock = '1'
Vilket är inte detsamma: om reset
ändras från '1'
till '0'
medan clock = '1'
kommer tilldelningen att utföras medan det inte är en stigande clock
.
Det finns faktiskt inget sätt att modellera detta i VHDL utan hjälp av ett signalattribut:
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;
Den clock'event
är signalattribut event
tillämpas på clock
. Det utvärderas som en boolean
och det är true
om och endast om clock
ändras under signaluppdateringsfasen som bara föregick den nuvarande genomförandefasen. Tack vare detta P2_OK
process P2_OK
nu perfekt vad vi vill ha i simulering (och syntes).
Syntesemantik
Många logiska syntetisatorer identifierar signalkantsdetekteringar baserade på syntaktiska mönster, inte på semantiken i VHDL-modellen. Med andra ord överväger de hur VHDL-koden ser ut, inte vilket beteende den modellerar. Ett av mönstren som de alla känner igen är:
if clock = '1' and clock'event then
Så även i exemplet med process P1
bör vi använda den om vi vill att vår modell ska syntetiseras av alla logiska synteser:
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;
Den and clock'event
delen av tillståndet är helt överflödigt med känslighetslistan men eftersom vissa synthesizers behöver det ...
Rising edge DFF med asynkron aktiv hög återställning och typ std_ulogic
I detta fall kan det bli komplicerat att uttrycka klockans stigande kant och återställningstillståndet. Om vi behåller definitionen av en stigande kant som vi föreslog ovan och om vi anser att återställningen är aktiv om den är '1'
eller 'H'
blir modellen:
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;
Obs:
'last_value
är ett annat'last_value
som returnerar värdet som signalen hade innan den senaste värdeförändringen.
Hjälparfunktioner
VHDL 2008-standarden erbjuder flera hjälpfunktioner för att förenkla upptäckten av signalkanter, särskilt med flera värderade uppräknade typer som std_ulogic
. std.standard
paketet definierar rising_edge
och falling_edge
på typer bit
och boolean
och paketet ieee.std_logic_1164
definierar dem på typerna std_ulogic
och std_logic
.
Obs: med tidigare versioner av VHDL kan användningen av dessa funktioner kräva att de uttryckligen förklarar användningen av standardpaket (t.ex. ieee.numeric_bit för typbit) eller till och med för att definiera dem i ett användarpaket.
Låt oss gå igenom de tidigare exemplen och använda hjälpfunktionerna:
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;
Obs! I detta sista exempel förenklar vi också testet på återställningen. Flytande, hög impedans, återställningar är ganska sällsynta och i de flesta fall fungerar denna förenklade version för simulering och syntes.