Salta al contenuto
Note per Studenti Simulazione, testbench, vincoli di temporizzazione e flusso su FPGA

Simulazione, testbench, vincoli di temporizzazione e flusso su FPGA

In questa pagina 6

Dopo aver scritto un circuito 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 →, VHDL - logica combinatoriaUna logica combinatoria in VHDL si descrive con assegnazioni concorrenti (semplici, condizionate when-else con priorità, selezionate with-select senza priorità) o con processi sensibili a tutti gli ingressi (if/elsif, case). Nel processo ogni uscita va assegnata in tutti i rami e la lista di sensibilità deve contenere tutti i segnali letti: altrimenti la sintesi inferisce un latch (memoria). L'aritmetica si fa con unsigned/signed di numeric_std (to_unsigned, to_integer, resize, conversioni di tipo) e con un bit in più per il riporto. Cicli for e istruzioni generate creano hardware replicato (non cicli nel tempo). La descrizione strutturale istanzia componenti con component e port map (per posizione o per nome, anche con generic map), e permette di costruire sistemi gerarchici.VHDL - logica combinatoria →, VHDL - logica sequenziale e registriIn VHDL la logica sequenziale si descrive con processi sensibili al clock. Un registro D (flip-flop sul fronte) si scrive process(clk) con if rising_edge(clk); un latch è un processo sensibile al livello (if clk='1' then q<=d) senza altri rami. Il reset è sincrono se testato dentro rising_edge(clk) (la lista di sensibilità contiene solo clk), asincrono se testato prima, con RST nella lista di sensibilità (if rst='1' then ... elsif rising_edge(clk)). Registri a n bit con generic, registri a scorrimento (con load), contatori (up/down, con enable) si ottengono con la stessa struttura. In un progetto sincrono tutti i registri usano lo stesso clock (nessun clock generato da logica: si usano abilitazioni), i segnali esterni asincroni come i pulsanti si campionano con uno o più flip-flop (debouncing) e le cifre di un display si multiplexano con un contatore.VHDL - logica sequenziale e registri →) bisogna verificarlo e portarlo sulla scheda. Questa nota raccoglie il flusso completo, dal testbench al bitstream, e i vincoli di temporizzazione.

Flusso di progetto su FPGA

  1. Descrizione del circuito in VHDL (e dei vincoli).
  2. Simulazione funzionale (comportamentale): il simulatore a eventi esegue il codice senza tener conto dei ritardi; verifica la correttezza logica.
  3. Sintesi: il codice è tradotto in una rete di primitive della FPGA (LUT, flip-flop, multiplexer, blocchi RAM e DSP: FPGA - LUT, slice e risorse della famiglia 7Una FPGA è una matrice di blocchi logici configurabili (CLB) immersi in una griglia di interconnessioni programmabili, con risorse dedicate: block RAM, blocchi DSP, gestione del clock (MMCM, PLL), blocchi di I/O e transceiver. La memoria di configurazione è SRAM. L'elemento base è la LUT: una memoria SRAM con 2^k celle che realizza una qualsiasi funzione di k ingressi (i segnali di selezione del multiplexer sono gli ingressi della funzione). Nella famiglia 7 di Xilinx un CLB ha 2 slice; uno slice ha 4 LUT a 6 ingressi (ciascuna divisibile in due LUT a 5), multiplexer larghi F7/F8 (funzioni a 7-8 ingressi), una catena di riporto veloce, 4 flip-flop/latch più 4 flip-flop. Nei SLICEM la LUT può essere usata come RAM distribuita o registro a scorrimento (SRL32), nei SLICEL solo come logica.FPGA - LUT, slice e risorse della famiglia 7 →); si ottiene lo schema circuitale (RTL e netlist) e una stima delle risorse usate.
  4. Implementazione: piazzamento (assegnazione delle primitive alle risorse fisiche) e instradamento (connessioni nella griglia di routing). Qui sono noti i ritardi reali, perché nelle FPGA dominano le interconnessioni.
  5. Analisi di temporizzazione (statica) sul progetto implementato e simulazione post-implementazione con i ritardi.
  6. Generazione del bitstream (i bit di configurazione, Dispositivi logici programmabili - PROM, PLA, PAL e CPLDUn componente logico programmabile (PLD) è un circuito integrato a catalogo la cui funzione logica viene fissata da una programmazione che altera la struttura del circuito (non va confusa con la programmazione software di un microprocessore). I meccanismi sono fusibili, antifusibili (una volta), EPROM/EEPROM/Flash (reversibili e non volatili) e celle SRAM (reversibili ma volatili). Le architetture semplici (SPLD) sono due piani AND-OR: PROM (AND fisso, cioè un decoder di tutti i mintermini, OR programmabile), PLA (entrambi programmabili, dimensione indipendente dal numero di ingressi, più lenta) e PAL (AND programmabile, OR fisso, più veloce). I CPLD sono matrici di blocchi SPLD con interconnessioni programmabili, le FPGA hanno molti blocchi logici piccoli (LUT + registro) in una griglia di interconnessioni complessa, configurata da SRAM.Dispositivi logici programmabili - PROM, PLA, PAL e CPLD →) e programmazione della scheda.
  7. Verifica sulla scheda del comportamento reale e miglioramenti.

In laboratorio si usa un ambiente integrato (Vivado) con la scheda Nexys (dispositivo Artix-7): un progetto "RTL" con i file sorgente, il file dei vincoli (XDC) con la mappa dei collegamenti della scheda (pin dei switch, LED, pulsanti, display, clock), e un clock di sistema a 100 MHz100\ \mathrm{MHz}. Il percorso di lavoro non deve contenere spazi.

Testbench

Un testbench è un modulo VHDL senza porte che contiene il circuito sotto test (UUT, unit under test), genera i segnali di ingresso e osserva le uscite. Non è sintetizzabile: usa costrutti solo di simulazione (wait for, after, file, assert).

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity seven_tb is end entity;            -- nessuna porta

architecture BHV of seven_tb is
  component bin2seven_seg is               -- interfaccia del circuito sotto test
    port (data_in  : in  std_logic_vector(3 downto 0);
          point_in : in  std_logic;
          data_out : out std_logic_vector(7 downto 0));
  end component;
  signal A   : unsigned(3 downto 0) := "0000";
  signal B   : std_logic;
  signal C   : std_logic_vector(7 downto 0);
  signal CLK : std_logic := '0';
begin
  -- generatore di clock: periodo 20 ns
  Clock: process
  begin
    wait for 10 ns;
    CLK <= not CLK;
  end process;

  -- stimolo: A conta ad ogni fronte
  process (CLK)
  begin
    if rising_edge(CLK) then A <= A + 1; end if;
  end process;

  P1: bin2seven_seg port map (data_in => std_logic_vector(A), point_in => B, data_out => C);

  B <= '1' after 20 ns;                     -- ingresso che cambia a un istante dato
end BHV;

Elementi:

Si esaminano le forme d'onda (valori dei segnali nel tempo) e i messaggi: gli errori tipici trovati sono uscite 'U' (non inizializzate: manca un reset), 'X' (conflitti: due driver sullo stesso segnale) e latch non voluti.

Vincoli di temporizzazione

I vincoli dicono agli strumenti quali prestazioni raggiungere e come sono collegati i pin:

  • vincoli fisici: assegnazione dei segnali di ingresso/uscita ai pin della scheda (standard elettrico compreso);
  • vincolo di clock: create_clock -period 10.0 [get_ports clk] per un clock a 100 MHz100\ \mathrm{MHz};
  • vincoli sui ritardi di ingresso/uscita (rispetto al clock esterno).

L'analisi statica di temporizzazione controlla ogni cammino tra due registri (e da/verso i pin) con gli stessi vincoli visti per il registro (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 →):

  • slack di setup: slacksetup=T−(tc-q+tlogica+trouting−tskew+tsu)\text{slack}_{setup}=T-\big(t_{c\text{-}q}+t_{logica}+t_{routing}-t_{skew}+t_{su}\big); se ≥0\ge0 il cammino rispetta il periodo di clock TT; il minimo su tutti i cammini è il WNS (worst negative slack). Il cammino con lo slack minore è il cammino critico.
  • slack di hold: slackhold=tc-q+tcd,logica+trouting−tskew−thold≥0\text{slack}_{hold}=t_{c\text{-}q}+t_{cd,logica}+t_{routing}-t_{skew}-t_{hold}\ge0 (indipendente da TT).
  • Frequenza massima: fmax=1/(T−WNS)f_{max}=1/(T-WNS) se WNS<TWNS<T.

Esempio. T=10 nsT=10\ \mathrm{ns} (100 MHz100\ \mathrm{MHz}). Un cammino ha tc-q=0,5t_{c\text{-}q}=0{,}5, logica e routing 7,87{,}8, tsu=0,4t_{su}=0{,}4 (ns\mathrm{ns}): ritardo totale 8,7 ns8{,}7\ \mathrm{ns}, slack +1,3 ns+1{,}3\ \mathrm{ns}, fmax=1/8,7 ns=115 MHzf_{max}=1/8{,}7\ \mathrm{ns}=115\ \mathrm{MHz}. Se il cammino fosse lungo 11,2 ns11{,}2\ \mathrm{ns}: slack −1,2 ns-1{,}2\ \mathrm{ns}: la frequenza di 100 MHz100\ \mathrm{MHz} non è raggiungibile, fmax=89 MHzf_{max}=89\ \mathrm{MHz}.

Come si chiude la temporizzazione (slack negativo): ridurre la profondità logica (meno LUT in cascata), inserire registri di pipeline (accorciano ogni cammino; costo: latenza), usare le risorse dedicate (catena di riporto, DSP), restringere il piazzamento, ridurre la frequenza. Un clock lento e abilitazioni (clock enable) evitano di generare clock con la logica.

Sintesi e inferenza

La sintesi riconosce nei costrutti VHDL le primitive: if rising_edge(clk) →\to flip-flop; assegnazione condizionata completa →\to multiplexer e LUT; + su unsigned →\to catena di riporto; memoria con lettura/scrittura sincrona →\to block RAM; moltiplicazioni →\to DSP. I segnali non usati vengono eliminati. Un latch compare per un'assegnazione incompleta in un processo combinatorio (VHDL - logica combinatoriaUna logica combinatoria in VHDL si descrive con assegnazioni concorrenti (semplici, condizionate when-else con priorità, selezionate with-select senza priorità) o con processi sensibili a tutti gli ingressi (if/elsif, case). Nel processo ogni uscita va assegnata in tutti i rami e la lista di sensibilità deve contenere tutti i segnali letti: altrimenti la sintesi inferisce un latch (memoria). L'aritmetica si fa con unsigned/signed di numeric_std (to_unsigned, to_integer, resize, conversioni di tipo) e con un bit in più per il riporto. Cicli for e istruzioni generate creano hardware replicato (non cicli nel tempo). La descrizione strutturale istanzia componenti con component e port map (per posizione o per nome, anche con generic map), e permette di costruire sistemi gerarchici.VHDL - logica combinatoria →).

Esempi di laboratorio

Errori comuni

  • Dimenticare di inizializzare i segnali del testbench (uscite 'U').
  • Cercare di sintetizzare codice con wait for o after.
  • Confrontare solo la simulazione funzionale: la correttezza dei tempi va verificata dopo l'implementazione.
  • Interpretare uno slack positivo come "il circuito funziona": serve anche lo slack di hold e il rispetto degli ingressi esterni.
  • Creare un clock con un contatore e usarlo come clock di altri registri.

Versione ripasso

  • Flusso: VHDL →\to simulazione funzionale →\to sintesi (LUT, FF, DSP, BRAM) →\to implementazione (piazzamento + instradamento) →\to analisi di temporizzazione / simulazione post-implementazione →\to bitstream →\to programmazione e verifica sulla scheda (Vivado, Nexys/Artix-7, clock 100100 MHz).
  • Testbench: entity senza porte; UUT (component + port map); clock con wait for T/2; clk <= not clk;; stimoli con after/wait; assert ... report ... severity (note, warning, error, failure); file con textio; non sintetizzabile. Segni di errore: 'U', 'X', latch.
  • Vincoli: pin della scheda e create_clock -period 10 (100100 MHz).
  • Temporizzazione: setup =T−(tc-q+tlogica+trouting−tskew+tsu)=T-(t_{c\text{-}q}+t_{logica}+t_{routing}-t_{skew}+t_{su}); WNS = minimo; hold =tc-q+tcd+trouting−tskew−thold=t_{c\text{-}q}+t_{cd}+t_{routing}-t_{skew}-t_{hold} (indip. da TT); fmax=1/(T−WNS)f_{max}=1/(T-WNS) (8,78{,}7 ns: 115115 MHz; slack −1,2-1{,}2 ns: 8989 MHz). Rimedi: meno LUT in cascata, pipeline, catena di riporto, DSP.
  • Inferenza: rising_edge →\to FF; + →\to carry chain; memoria sincrona →\to BRAM; assegnazione incompleta →\to latch.
  • Errori: segnali non inizializzati; sintesi di wait/after; solo simulazione funzionale; hold ignorato; clock da contatore.

Teoria collegata