Salta al contenuto
Note per Studenti VHDL - logica sequenziale e registri

VHDL - logica sequenziale e registri

In questa pagina 9

Un circuito sequenziale ha uno stato memorizzato in registri (Latch, registri e parametri temporaliUn circuito sequenziale ha uno stato memorizzato in due modi: retroazione positiva (due inverter in anello, bistabile, i latch statici) o immagazzinamento di carica (circuiti dinamici). Un latch è sensibile al livello del clock (trasparente quando il clock è attivo, memorizza quando non lo è), un registro (flip-flop) è sensibile al fronte e si realizza con due latch sulle fasi opposte (master-slave). Il latch SR a porte NOR/NAND non ammette la combinazione S = R = 1 perché passando da lì alla memoria lo stato finale è imprevedibile. Parametri temporali del registro: ritardo clock-uscita t_c-q, tempo di setup t_su (dato stabile prima del fronte), tempo di hold t_hold (dato stabile dopo il fronte). Periodo minimo: T_min = t_c-q + t_p,logic(max) + t_su; vincolo di hold: t_cd,reg + t_cd,logic > t_hold. La pipeline spezza la logica con registri per aumentare la frequenza (a spese della latenza).Latch, registri e parametri temporali →). In VHDL (VHDL - struttura, tipi di dato e processiVHDL è un linguaggio di descrizione dell'hardware: un listato non è una sequenza di istruzioni eseguite da un processore ma la descrizione di un circuito, che la sintesi traduce in uno schema (LUT, flip-flop, multiplexer). Ogni modulo ha una entity (interfaccia: port con modo in, out, inout e tipo; eventuali generic) e una architecture (parte dichiarativa: segnali, costanti, componenti; parte assertiva dopo begin: assegnazioni concorrenti e processi). Le istruzioni nell'architecture sono concorrenti: l'ordine in cui sono scritte non conta. Un process esegue le proprie istruzioni in modo sequenziale quando un segnale della lista di sensibilità cambia. Segnali (<=, aggiornati alla fine del delta cycle, definiti nella parte dichiarativa) e variabili (:=, immediate, solo dentro il processo) hanno semantica diversa. Tipi: bit, boolean, integer, std_logic (a 9 valori, tra cui 'Z', 'X', 'U'), std_logic_vector, unsigned e signed (numeric_std).VHDL - struttura, tipi di dato e processi →) si descrive con processi sensibili al clock. L'hardware inferito dipende dalla forma del codice: si seguono schemi standard.

Latch e flip-flop D

Latch (sensibile al livello, trasparente per clk=1clk=1): il processo ha sensibilità su dd e clkclk e non assegna qq quando clk=0clk=0 (il valore precedente è mantenuto):

vhdl
process (d, clk)
begin
  if clk = '1' then q <= d; end if;
end process;

Flip-flop D (sul fronte di salita): la sensibilità è solo clk e l'assegnazione è dentro rising_edge(clk):

vhdl
process (clk)
begin
  if rising_edge(clk) then q <= d; end if;
end process;

(equivalente: if clk'event and clk = '1'). Flip-flop T: if rising_edge(clk) then if t = '1' then qi <= not qi; end if; end if; con un segnale interno qi (un'uscita out non si legge) e q <= qi;.

La differenza tra latch e registro, dal punto di vista del codice, è la presenza di rising_edge: un if sul livello descrive un latch (sensibile al livello), un if su rising_edge(clk) un registro (sensibile al fronte).

Reset sincrono e asincrono

  • Sincrono: il reset è valutato dentro il ramo del fronte di clock, quindi ha effetto solo al fronte successivo; la lista di sensibilità contiene solo clk:
vhdl
process (clk)
begin
  if rising_edge(clk) then
    if rst = '1' then q <= '0';
    else q <= d;
    end if;
  end if;
end process;
  • Asincrono: il reset ha priorità ed è valutato fuori dal fronte: agisce subito, a prescindere dal clock; rst è nella lista di sensibilità:
vhdl
process (rst, clk)
begin
  if rst = '1' then q <= '0';
  elsif rising_edge(clk) then q <= d;
  end if;
end process;

Il primo codice della lista implementa un reset sincrono, il secondo asincrono (per esempio A<='0' dentro if rising_edge(CLK) è un reset sincrono). Nelle FPGA i flip-flop hanno entrambi gli ingressi (set/reset sincrono o asincrono secondo la configurazione). Il reset asincrono non è sincronizzato con il clock: il suo rilascio vicino a un fronte può violare setup/hold (si sincronizza il rilascio con un flip-flop).

Registro a nn bit

vhdl
entity regn is
  generic (n : integer := 16);
  port (d        : in  std_logic_vector(n-1 downto 0);
        res, clk : in  std_logic;
        q        : out std_logic_vector(n-1 downto 0));
end regn;

architecture bhv of regn is
begin
  process (res, clk)
  begin
    if res = '1' then q <= (others => '0');
    elsif rising_edge(clk) then q <= d;
    end if;
  end process;
end bhv;

Con un enable (ce) si aggiorna solo quando serve: elsif rising_edge(clk) then if ce = '1' then q <= d; end if; end if; (nelle FPGA il flip-flop ha un ingresso di enable dedicato).

Registro a scorrimento

vhdl
process (clk)
begin
  if rising_edge(clk) then
    if load = '1' then
      qi <= r;                              -- caricamento parallelo
    else
      qi(qi'right) <= w;                    -- ingresso seriale
      for i in 1 to qi'left loop
        qi(i) <= qi(i-1);                   -- ogni bit prende il precedente
      end loop;
    end if;
  end if;
end process;
q <= qi;

Poiché qi è un segnale, le assegnazioni nel ciclo for leggono i valori precedenti al fronte: tutti i bit scorrono insieme di una sola posizione (Registri dinamici, C2MOS, TSPC e registri a scorrimentoI registri dinamici memorizzano il bit come carica su un nodo capacitivo in alta impedenza: meno transistor e commutazioni più rapide dei registri statici, ma il dato si perde (serve un clock minimo) e il master-slave con gate di trasmissione è sensibile alla sovrapposizione dei clock (race). Il registro C2MOS (clocked CMOS) usa inverter con transistor di clock in serie: è insensibile alla sovrapposizione dei clock (0-0 e 1-1) se i fronti sono ripidi, perché durante la sovrapposizione ciascuno stadio può solo caricare o solo scaricare il nodo, mai propagare. Il TSPC usa una sola fase di clock (nessun clock invertito) e permette di inglobare logica nei latch. Un registro a scorrimento è una cascata di registri D: a ogni fronte il dato avanza di una posizione (conversione serie-parallelo, ritardi, FIFO); il collegamento diretto richiede t_c-q > t_hold.Registri dinamici, C2MOS, TSPC e registri a scorrimento →). Con una variabile il dato attraverserebbe tutto il registro in un colpo.

Contatore (laboratorio)

Contatore a 4 bit crescente o decrescente secondo un ingresso, con reset sincrono:

vhdl
signal cnt : unsigned(3 downto 0);
...
process (clk)
begin
  if rising_edge(clk) then
    if rst = '1' then
      cnt <= (others => '0');
    elsif up = '1' then
      cnt <= cnt + 1;               -- avvolge da 15 a 0
    else
      cnt <= cnt - 1;
    end if;
  end if;
end process;
led <= std_logic_vector(cnt);

Per rendere visibile il conteggio sui LED (con clock a 100 MHz100\ \mathrm{MHz}) serve rallentarlo: non si crea un secondo clock con la logica, ma una abilitazione (clock enable) generata da un contatore divisore: if tick = '1' then cnt <= cnt + 1; end if;, con tick a 11 per un solo ciclo ogni 2252^{25} periodi (circa 0,34 s0{,}34\ \mathrm s).

Segnali asincroni: debouncing

La pressione di un pulsante produce rimbalzi (bouncing) di durata tipica minore di 10 ms10\ \mathrm{ms}: più transizioni ravvicinate che un circuito veloce conta come più pressioni. Si risolve con il debouncing: il segnale del pulsante viene campionato con un opportuno segnale di clock e uno o più flip-flop, con un clock lento (per esempio un campionamento ogni circa 1010–20 ms20\ \mathrm{ms}) o con un contatore che accetta il nuovo valore solo se rimane stabile per un tempo maggiore dei rimbalzi. Prima di usare un ingresso asincrono nel dominio del clock lo si fa passare per due flip-flop in serie (sincronizzatore) per ridurre la probabilità di metastabilità (Latch, registri e parametri temporaliUn circuito sequenziale ha uno stato memorizzato in due modi: retroazione positiva (due inverter in anello, bistabile, i latch statici) o immagazzinamento di carica (circuiti dinamici). Un latch è sensibile al livello del clock (trasparente quando il clock è attivo, memorizza quando non lo è), un registro (flip-flop) è sensibile al fronte e si realizza con due latch sulle fasi opposte (master-slave). Il latch SR a porte NOR/NAND non ammette la combinazione S = R = 1 perché passando da lì alla memoria lo stato finale è imprevedibile. Parametri temporali del registro: ritardo clock-uscita t_c-q, tempo di setup t_su (dato stabile prima del fronte), tempo di hold t_hold (dato stabile dopo il fronte). Periodo minimo: T_min = t_c-q + t_p,logic(max) + t_su; vincolo di hold: t_cd,reg + t_cd,logic > t_hold. La pipeline spezza la logica con registri per aumentare la frequenza (a spese della latenza).Latch, registri e parametri temporali →).

Display a 7 segmenti multiplexati

Gli otto display della scheda condividono le stesse linee dei segmenti (catodi) e hanno anodi distinti: due display diversi non possono visualizzare cifre diverse nello stesso istante. Si usa la tecnica stroboscopica: si accende un display alla volta, ciclicamente, con la cifra corretta, abbastanza in fretta da apparire accesi tutti insieme. Un contatore a kk bit (con i 33 bit più significativi che pilotano un decoder 3→83\to8 per gli anodi e i bit più bassi che contano il tempo) gestisce la rotazione. Il tempo di accensione non deve essere né troppo lungo (sfarfallio, flicker) né troppo corto (luminosità bassa): con fclk=100 MHzf_{clk}=100\ \mathrm{MHz} l'intero ciclo vale 2kTclk2^kT_{clk}, e si sceglie tra 1 ms1\ \mathrm{ms} e 16 ms16\ \mathrm{ms}: k=17,…,20k=17,\dots,20 (1,31 ms1{,}31\ \mathrm{ms} per k=17k=17, 10,5 ms10{,}5\ \mathrm{ms} per k=20k=20); con k=19k=19 ogni display resta acceso 5,24/8=0,66 ms5{,}24/8=0{,}66\ \mathrm{ms}. Un valore binario da mostrare in decimale si converte in BCD con il double dabble (Rappresentazione dei numeri e dell'informazioneUn'informazione digitale è una stringa di bit. Numeri senza segno: N bit rappresentano 0…2^N − 1; in esadecimale ogni cifra raggruppa 4 bit. Numeri con segno: complemento a due (range −2^(N−1)…2^(N−1) − 1; si nega invertendo i bit e sommando 1; il bit più significativo è il segno e l'estensione di segno lo replica). Il BCD codifica ogni cifra decimale con 4 bit (0…9) e si ottiene dal binario con l'algoritmo double dabble (shift a sinistra, e +3 a ogni gruppo maggiore di 4 prima dello shift). Il codice Gray cambia un solo bit tra valori consecutivi. I numeri frazionari si trattano in virgola fissa (4 bit di parte frazionaria = multipli di 1/16), i caratteri in ASCII, gli errori con un bit di parità.Rappresentazione dei numeri e dell'informazione →).

Regole per un progetto sincrono

Errori comuni

  • Scrivere if clk = '1' invece di rising_edge(clk): si ottiene un latch, non un registro.
  • Mettere rst nella lista di sensibilità ma testarlo dentro rising_edge (non è asincrono) o viceversa.
  • Usare un segnale come riporto o come stato intermedio nello stesso ciclo aspettandosi il valore appena assegnato.
  • Dimenticare che in VHDL cnt + 1 richiede unsigned (non std_logic_vector).
  • Generare un clock lento con un contatore e usarlo come clock: meglio un clock enable.

Versione ripasso

  • Latch: process(d,clk) if clk='1' then q<=d (livello); FF D: process(clk) if rising_edge(clk) then q<=d (fronte); FF T con segnale interno.
  • Reset sincrono: rst dentro rising_edge(clk), sensibilità solo clk; asincrono: if rst='1' ... elsif rising_edge(clk), sensibilità rst, clk, priorità e effetto immediato; rilascio da sincronizzare.
  • Registro nn bit: generic(n), (others=>'0'), enable ce.
  • Shift register: segnale qi, for i in 1 to qi'left loop qi(i)<=qi(i-1), load parallelo; con segnale scorre di una posizione.
  • Contatore: unsigned, cnt<=cnt+1/-1, avvolge; rallentare con clock enable (tick ogni 2252^{25} cicli).
  • Debouncing: rimbalzi <10<10 ms; campionare con clock lento e uno o più FF; sincronizzatore a 2 FF per ingressi asincroni.
  • Display multiplexati: un display alla volta, ciclicamente; 2kTclk∈[1,16]2^kT_{clk}\in[1,16] ms a 100100 MHz (k=17…20k=17\ldots20); BCD con double dabble.
  • Regole: un solo clock, rising_edge in ogni processo sequenziale, uscite assegnate in tutti i rami nei combinatori.
  • Errori: if clk='1' = latch; reset mal posizionato; segnale immediato; + su std_logic_vector; clock da logica.

Esercizi su questo argomento

Teoria collegata