Skip to content

Rilevamento fronti e corse critiche in VHDL

L’edge detector è un componente che rileva i fronti di salita (o discesa) di un segnale di ingresso SS.

Diagramma ASM dell'edge detector

Si attende che SS vada al valore opposto di quello atteso. Poi si attende che ritorni al valore specificato.

Ogni ciclo del clock, quando il segnale d’ingresso cambia di valore, l’uscita andrà a 1 per il ciclo successivo del clock. Si possono impiegare 2 busy-wait per rilevare le transizioni sugli ingressi.

Diagramma ASM del derivatore

Diagramma temporale

Problema: Se nello stesso ciclo di clock il segnale torna al valore iniziale, allora la transizione verrà persa.

Diagramma temporale con cambiamenti persi

Inoltre gli stati bb e dd non sono sensibili alle variazioni d’ingresso, quindi tutto ciò che accade in quel ciclo di clock va perso. Per risolvere questo basta aggiungere un’ulteriore condizione dopo i blocchi di stato bb e dd.

Correzione per impulso più corto di un ciclo di clock: uscite condizionate

Section titled “Correzione per impulso più corto di un ciclo di clock: uscite condizionate”

Invece di usare una macchina di Moore, dove le uscite dipendono solamente dallo stato, si può creare una macchina di Mealy, dove le uscite cambiano anche al cambiare degli ingressi.

Così cambiamo leggermente la specifica, l’uscita va a 1 immediatamente dopo il cambiamento dell’ingresso fino alla fine dello stesso ciclo di clock.

Se nello stesso ciclo di clock l’ingresso ha un impulso, l’output sarà solo 1 transizione invece delle 2 che ci si aspetterebbe (salita e discesa dell’impulso).

Gli ingressi del circuito non sono necessariamente sincronizzati con il clock. Se il cambiamento di un ingresso avviene nei pressi del fronte del clock, si possono generare comportamenti imprevisti.

Quando un segnale d’ingresso cambia, il cambiamento deve attraversare tutte le porte logiche della parte combinatoria del circuito. Se ciò avviene poco prima del fronte del clock, si può ottenere un risultato intermedio, dovuto alla propagazione non completa del segnale cambiato.

La prima soluzione consiste nel far dipendere una variabile di stato per volta dall’ingresso che viene cambiato.

In questo modo non è possibile finire in combinazioni di stati non esistenti. La transizione o avviene completamente o viene persa.

Quando non è possibile applicare questa soluzione direttamente, si può eventualmente introdurre degli stati intermedi, ciascuno differenziato per una variabile. Questo però introduce ritardi di multipli cicli di clock nel circuito e funziona solo se gli ingressi cambiano uno alla volta.

La soluzione più semplice è quella di impedire la corsa critica dall’inizio. Per fare ciò si pone un flip-flop di fronte all’ingresso che cambia. Quindi il nuovo valore sarà letto solamente all’inizio del ciclo di clock successivo.

Si introduce un ritardo anche in questo caso.

Per memorizzare valori in VHDL basta usare una variabile di tipo buffer.

entity latch is
port (d, c : in std_logic; q : buffer std_logic);
end;
architecture equazioni of latch is
begin
q <= d when c = '1' else q;
end

Si usa un multiplexer con l’uscita collegata ad uno degli ingressi.

Per il flip-flop (edge triggered) si usa l’attributo 'event', che rende il segnale 1 solo quando il valore di c cambia:

entity flip_flop is
port (d, c : in std_logic; q : buffer std_logic);
end;
architecture equazioni of flip_flop is
begin
q <= d when c = '1' and c'event else q;
end;
-- Per discriminare i 2 fronti, si possono usare le funzioni rising_edge e falling_edge:
architecture equazioni of flip_flop is
begin
q <= d when c = '1' and rising_edge(c) else q;
end;

Il circuito si comporta in maniera combinatoria se è sempre possibile assegnare un valore ai segnali senza dover ricordare quello precedente.

Bisogna quindi (quando possibile) assegnare un valore alle uscite per ogni combinazione di ingressi. Altrimenti gli strumenti di sintesi inseriranno un latch o un flip-flop per memorizzare il valore precedente.

-- Questo è un circuito esclusivamente combinatorio.
process (a, b, c) is
begin
if c = '1' then
if a = '1' or b = '1' then
y <= '1';
else
y <= '0';
end
else
y <= '0';
end;
end;
-- Se c = '0', il valore di y deve essere memorizzato (viene aggiunto un latch in automatico).
process (a, b, c) is
begin
if c = '1' then
if a = '1' or b = '1' then
y <= '1';
else
y <= '0';
end;
end;
end;
process (a, b, c) is
begin
-- Il valore di y viene sempre aggiornato. Quindi si prevengono eventuali
-- aggiunte di variabili di memoria.
y <= '0';
if c = '1' then
if a = '1' or b = '1' then
y <= '1';
end;
end;
end;
library ieee;
use ieee.std_logic_1164.all;
entity D_latch is
port (
d, clk : in std_logic;
q: out std_logic;
);
end;
architecture behavioral of D_latch is
begin
process (d, clk) is
begin
if clk = '1' then
q <= d;
end;
end;
end;
library ieee;
use ieee.std_logic_1164.all;
entity D_flip_flop is
port (
d, clk : in std_logic;
q: out std_logic;
);
end;
architecture behavioral of D_flip_flop is
begin
-- Il processo è sensibile solo al segnale clk.
process (clk) is
begin
if rising_edge(clk) then
q <= d;
end;
end;
end;