Studio, sintesi e implementazione di un timer digitale su FPGA · contatore che controlla...
Transcript of Studio, sintesi e implementazione di un timer digitale su FPGA · contatore che controlla...
Studio, sintesi e implementazione di un
timer digitale su FPGA
Introduzione Il seguente progetto ha come obiettivo lo studio, la sintesi e la successiva
implementazione di un timer su una FPGA.
Le FPGA (field programmable gate array) sono dispositivi programmabili costituiti
da un array blocchi logici configurabili (CBL), disposti secondo una matrice
bidimensionale, collegati tra loro attraverso delle opportune interconnessioni.
Tali blocchi logici contengono delle Look-up Table basate su Ram statica che
implementano una generica funzione logica o possono essere usate come elementi di
memoria SRAM o come registri. Oltre ai CLB, gli elementi essenziali di una FPGA
sono:
• Blocchi di input/output (IOB). La loro funzione è interfacciare la logica
interna con i pin di I/O del dispositivo, configurare il flusso dei dati come
ingresso, uscita o bidirezionale, adattare i pin di I/O agli standard più diffusi
(TTL, CMOS).
• Digital Clock Manager (DCM). Distribuiscono i segnali di clock all’interno
della FPGA, inoltre, permettono di moltiplicare o dividere la frequenza di
clock, di variare la fase e di correggere eventuali problemi di clock skew.
• Blocchi moltiplicatori. Calcolano il prodotto di due numeri a 18 bit.
Il numero di tali componenti e il tipo di specifiche di ciascun componente variano in
base al modello di FPGA utilizzato.
Al fine di svolgere una determinata funzione, è necessario programmare la FPGA con
un software che ha il compito di creare le interconnessioni tra i vari componenti.
Come linguaggio di programmazione è stato usato Verilog che permette di descrivere
i circuiti digitali secondo vari livelli di astrazione (in ordine dal più basso al più alto):
• Switch level : il sistema è descritto a livello dei transistor.
• Gate level: il sistema è descritto in termini di porte logiche con le loro relative
interconnessioni.
• Register Transfer level: l’hardware è descritto attraverso un modello formato
da reti combinatorie il cui compito è la trasformazione e l’elaborazione dei
dati e da registri cui spetta il compito di memorizzare tali valori nelle fasi
intermedie delle elaborazioni.
• Behavioural level: è il livello più alto di astrazione e descrive il sistema
mediante algoritmi e funzioni la cui sintassi è simile al C.
Nei circuiti integrati particolarmente complessi, spesso, si preferisce usare una
tipologia mista che comprende i due livelli di astrazione più alti (RTL e Behaviour
level) attraverso i quali si ottiene una completa descrizione del funzionamento di un
circuito e in seguito si utilizzano dei software automatici che generano la descrizione
dello stesso in termini di reti composte da porte logiche elementari.
Obiettivo del Progetto L’obiettivo del progetto consiste nel progettare un timer dalle caratteristiche elencate:
• Abbia una risoluzione al centesimo di secondo.
• Abbia un display a quattro cifre con il seguente formato [00:00] (decine di
secondi, secondi, decimi di secondo, centesimi di secondo).
• Sia controllato da un pulsante di Start/Pausa, e uno di Clear.
Per affrontare lo studio di un circuito digitale complesso si segue una strategia di
progettazione di tipo Top-down ovvero, si scompone un sistema fisico in più blocchi
ognuno dei quali può contenere al suo interno dei sotto-moduli appartenenti ad un
livello più basso di gerarchia. Ognuno di essi è studiato separatamente e implementato
in un blocco logico ben definito. Pertanto, si è deciso di scomporre il progetto del
circuito in tre blocchi fondamentali:
• Logica di controllo.
• Logica di conteggio.
• Logica di visualizzazione.
Logica di controllo Il modulo della logica di controllo è responsabile di tutte le operazioni di controllo del
timing come l’inizializzazione, lo stop, la ripresa e l’azzeramento del conteggio in
base ai segnali ricevuti dall’utente. E’ possibile costruire un diagramma degli stati
(modello di Moore) sulla base delle seguenti considerazioni. Per prima cosa la logica
di controllo ha due ingressi con i quali l’utente può interagire con la macchina: un
pulsante di Start, e un pulsante di Clear, indicati con i1, i2 che rappresentano
rispettivamente i segnali di start e azzera.
Schema della logica di controllo
Inoltre esso dispone di un segnale di reset (asincrono) che pone il circuito in uno stato
iniziale S0 (o di riposo detto IDLE). Tutte le operazioni sono scandite dal fronte di
salita di un segnale di clock.
Diagramma a stati della macchina di controllo Tabella degli stati
In uscita alla logica di controllo vi sono due segnali u1, u2 che rappresentano
rispettivamente il segnale di enable, e il segnale di clear, entrambi responsabili del
controllo del modulo di conteggio.
Dunque, la logica di controllo ha essenzialmente sei stati:
• Lo stato di IDLE, in cui la macchina si trova al momento dell’accensione
quando riceve un segnale di RESET, oppure dopo uno stato di CLEAR, in
seguito al rilascio del pulsante di CLEAR. In questa fase i contatori non sono
abilitati al conteggio (u1=0) e sono azzerati (u2=1).
• Lo stato di RUN, in cui la macchina si trova nel momento in cui viene premuto
il tasto START e viene generato un segnale di start (i1=1). In questo nuovo
stato, le uscite si portano rispettivamente a u1=1 e u2=0, ovvero, il conteggio è
abilitato. Tuttavia la macchina rimane in questo stato solamente se la
condizione i1=1 (il tasto START è premuto) continua ad essere verificata. Per
risolvere tale inconveniente, si crea uno stato intermedio RUN1 che ha le
stesse caratteristiche del precedente, in cui la macchina si porta nel momento
in cui il tasto viene rilasciato. Se nessun tasto viene premuto, la macchina
rimane in questo stato per un tempo indefinito.
• Se nella fase di RUN1 viene nuovamente premuto il tasto START (i1=1), la
macchina si porterà in uno stato di PAUSA, in cui i contatori vengono
“congelati” nella loro posizione, portando il segnale di enable a zero (u1=0).
Anche qui, per le stesse ragioni spiegate in precedenza, si inserisce uno stato
supplementare PAUSA1 in cui la macchina si porta una volta che il pulsante di
START è stato rilasciato (i1=0). A questo punto la macchina rimane
indefinitamente in questo stato se nessun pulsante viene premuto (i1=0, i2=0).
Stati S0 IDLE S1 RUN S2 RUN1 S3 PAUSA S4 PAUSA1 S5 CLEAR
In questo stato vi sono due possibilità: se viene nuovamente premuto START,
la macchina si porta nello stato RUN, e il conteggio riprende dal punto in cui
si era fermato.
• Lo stato di CLEAR, in cui la macchina si trova quando nello stato di PAUSA1
viene premuto il tasto di CLEAR e viene generato un segnale di azzera (i2=1).
In questa fase il conteggio continua ad essere fermo (u1=0) ma i contatori
vengono azzerati (u2=1). Una volta rilasciato il pulsante (i2=0), la macchina si
riporta nello stato di riposo.
Logica di conteggio Il modulo della logica di conteggio ha la funzione di generare l’informazione
temporale da un segnale di clock la cui frequenza è settata a 1KHz. La struttura del
modulo è la seguente: oltre ai segnali di clock e di reset, in comune con il modulo di
controllo, esso riceve in ingresso i due segnali di enable e di clear, mentre in uscita
fornisce l’informazione ai quattro display in formato BCD per un totale di sedici linee
dati. Il modulo è formato da cinque contatori ognuno dei quali divide la frequenza del
contatore precedente per dieci, in modo che il contatore D possa contare i centesimi,
il contatore C i decimi di secondo, il contatore B i secondi, e infine il contatore A le
decine di secondi.
Schema del blocco di conteggio Schema logico del contatore
Ogni contatore presenta dieci stati identificati dalla notazione Si con i da 0 a 9,
ognuno dei quali identifica l’uscita corrispondente al valore decimale rappresentato.
Diagramma degli stati di un contatore decimale
Ogni contatore ha in ingresso (oltre ai segnali di clock e reset) il segnale di enable_in
che se abilitato (enable_in=1) porta la macchina nello stato successivo, in presenza di
una transizione positiva del segnale di clock, fino al raggiungimento dello stato S9. In
questo stato viene attivata l’uscita del contatore enable_out per poi essere disattivata
nell’istante in cui si riporta in S0. Quando enable_out=1, il contatore posto in cascata,
il cui ingresso enable_in è collegato all’uscita enable_out del contatore precedente, è
abilitato al conteggio. Pertanto, ogni 10 conteggi, il contatore successivo incrementa
di una unità, e quest’ultimo una volta raggiunti i 10 conteggi, farà incrementare il
contatore posto in cascata di una unità, e così via.
Logica di visualizzazione Il modulo di visualizzazione è responsabile della decodifica dei segnali BCD
provenienti dalle uscite dei contatori e dell’invio di tali informazioni ai quattro
display a sette segmenti. Dalle specifiche della scheda utilizzata emerge che ogni
display è ad anodo comune e condivide assieme agli altri le otto linee dati (sette per i
segmenti più una per il punto che sarà trascurata). Pertanto, l’informazione deve
essere inviata ai display tramite le otto linee di dati collegati ai catodi, mentre
l’accensione di un determinato display avviene contemporaneamente se il relativo
anodo è a livello logico basso. Per tale ragione è dunque necessario implementare un
circuito addizionale che controlli con l’opportuna temporizzazione l’invio della parola
corretta ad ognuno dei display. Se l’accensione di ogni display avviene con una
frequenza superiore rispetto a quella massima percepibile dall’occhio umano, si ha il
cosiddetto fenomeno di persistenza della visione, secondo il quale il cervello
interpreta i display come se fossero costantemente accesi.
Schema del modulo di visualizzazione
Entrando più nel dettaglio, si può vedere come il modulo sia composto da un
contatore che controlla contemporaneamente un multiplexer e un anode decoder
rispettivamente a quattro ingressi e a quattro uscite. Per tale ragione se ne deduce che
quattro stati sono sufficienti per controllare entrambi i dispositivi.
Schema della logica di visualizzazione
Contatore Il contatore riceve in ingresso il segnale di clock, la cui frequenza è pari a 1KHz, e un
segnale di reset che lo riporta eventualmente in uno stato iniziale S0. Presenta due
uscite attraverso le quali può scambiare la parola binaria a 2bit con il multiplexer e
l'anode decoder. Dopo un fronte di salita del clock, la macchina si porta dallo stato S0
a quello successivo S1 (e così via), caratterizzato da una differente configurazione
delle uscite (indicata in tabella). Essendo il contatore a 2 bit, dopo quattro periodi di
clock, il contatore si riporta nello stato iniziale S0.
Multiplexer, anode decoder, decoder BCD
La necessità di utilizzare un multiplexer nasce dal fatto che, sulla piattaforma di
sviluppo, sono presenti solamente sette linee in comune per comandare i catodi.
Collegando le uscite BCD dei quattro contatori agli ingressi del decoder, ognuna di
queste verrà selezionata di volta in volta e ripresentata in uscita per un tempo pari alla
durata di un periodo di clock. La parola a due bit generata dal contatore comanda gli
ingressi del decoder, in modo tale che in un tempo di 4 ms pari cioè a quattro periodi
di clock, tutte le parole siano state inviate ai display.
Modellazione dei blocchi logici tramite Verilog Il percorso che porta dalla descrizione astratta di un circuito digitale fino alla sua
effettiva implementazione su chip può essere suddiviso in varie fasi. Il primo passo
consiste nella descrizione dei modelli circuitali, mediante un linguaggio ad alto livello
come Verilog attraverso uno dei tanti programmi commerciali come NCVerilog di
Cadence. In questa fase sono prima descritti separatamente i blocchi elementari e
contatore stati uscite
S0 0 0 S1 0 1 S2 1 0 S3 1 1
Diagramma a stati del contatore tabella degli stati
successivamente istanziati nel modulo Timer che rappresenta il modulo a livello
gerarchico più alto.
Macchina a stati finiti
Il seguente programma ha la funzione di simulare la macchina a stati descritta in
precedenza.
`timescale 1ns/100ps // imposta la scala temporale e la relativa precisione module FSM (enable, clear, start, azzera, clock, reset); // definisce il modulo output enable, clear; //definisce uscite input start, azzera, clock, reset; //definisce entrate reg enable, clear; // dichiara varibili registro reg [2:0] stato; // dichiara variabile stato a 3bit parameter IDLE=0, RUN=1, RUN1=2, PAUSA=3, PAUSA1=4, CLEAR=5; always @(posedge clock or posedge reset) // esegue il modulo ogni volta che si presenta una if (reset) //transizione L->H di clock o di reset begin stato<=IDLE; enable<=0; clear<=1; end else begin case(stato) IDLE: begin enable<=0; clear<=1; if(start) stato<=RUN; end RUN
begin enable<=1; clear<=0; if(~start) stato<=RUN1; end RUN1 begin enable<=1; clear<=0; if(start) stato<=PAUSA; end PAUSA begin enable<=0; //blocca il conteggio clear<=0 if(~start) stato<=PAUSA1; // se il pulsante di start è rilasciato rimani in stato di pausa(PAUSA1) end PAUSA1 begin enable<=0; //il conteggio rimane bloccato clear<=0; if(start) stato<=RUN; // se il pulsante di start è premuto torna in RUN if(azzera) stato<=CLEAR; end CLEAR: begin enable<=0; // il conteggio rimane ancora bloccato clear<=1; if(~azzera) stato<=IDLE; end endcase // chiude case end // chiude begin endmodule // chiude module
Modulo Prescaler
La piattaforma di sviluppo FPGA è dotata di un oscillatore al quarzo la cui frequenza
è pari a 50MHz. Per abbassare tale valore alla frequenza utile ai fini del progetto
(1kHz) è necessario implementare un modulo di Clock Prescaler che ha il compito di
svolgere tale funzione. Tale modulo presenta in ingresso il segnale proveniente
dall'oscillatore Clk50 e un segnale di reset e presenta in uscita il segnale di clock. Per
ottenere un periodo di 1!" è dunque necessario moltiplicare il periodo di 20ns per un
fattore 50 ∙ 10!. L'operazione è effettuata attraverso un contatore che conta i fronti di
salita del segnale Clk50 mentre il segnale di clock è a zero (o uno). Una volta
raggiunto il fronte di salita numero 25000 (pari a metà dei cicli di clock effettuati in
un periodo) il segnale di clock è ribaltato e rimane in questo valore per altri 24999
fronti di salita. In questa maniera si ottiene un segnale il cui periodo è proprio quello
cercato. `timescale 1ns/100ps // imposta la scala temporale e la relativa precisione module clkPrescaler(clock,reset,Clk50); //definisce il modulo output clock; input reset, Clk50; reg[17:0] counter; // registro da 18 bit per contare fino a 25000 conteggi reg clock; always @(posedge Clk50 or posedge reset) //esegue il blocco in presenza di una transizione L-> H di Clk50 o del segnale di //reset begin if(reset) // in presenza di un segnale di reset begin counter<=0; // metti il contatore a zero
clock<=0; // e metti il segnale di clock a zero end else begin if(counter==24999) //se il conteggio arriva 24999 begin clock<=~clock; // ribalta il segnale counter<=0; // e metti il conteggio a zero end else counter<=counter+1; // incrementa il contatore end // chiudi begin end // chiudi begin endmodule // chiudi module
Modulo contatore decimale Il seguente programma simula un blocco elementare predisposto al conteggio di una
cifra decimale. Per tale ragione la variabile count è un registro a 4 bit ed è perciò
necessario introdurre nel programma delle strutture di controllo, che riportino count a
0 dopo aver assunto il valore decimale 9, o in ogni caso se vi è un segnale di reset o di
clear.
`timescale 1ns/100ps // imposta la timeline temporale e la relativa precisione module Decimal_counter (count,enable_out,clock,reset,clear,enable_in); output[3:0] count; // vettore dati output enable_out; input clock,reset,clear,enable_in; //il valore di enable_out è 1 se contemporaneamente assign enable_out=count==9 && enable_in; // si verifica la condizione count==9 e enable_in è pari a 1 always @(posedge clock or posedge reset) reg[3:0] count; reg enable_out,clear; begin //b1 if(reset||clear) count<=0;
contatore decimale
clock prescaler
else begin //b2 if(enable_in) begin //b3 if(count==9) count<=0; else count<=count+1; end // chiudo begin 3 end// chiudo begin2 end // chiudo begin1 endmodule // chiudo module
Modulo Decoder BCD/ display 7 segmenti
Il seguente modulo converte l'uscita del multiplexer out_mux (numero binario in
formato BCD) in una parola binaria di 7 bit di lunghezza CAT. Attraverso il costrutto
case, a seconda del valore di out_mux, è possibile scrivere in CAT la parola binaria
corrispondente alla cifra decimale. La corrispondenza segue la codifica riportata nella
tabella seguente.
Codifica display 7 segmenti ad anodo comune
In figura vi è il principio di funzionamento di ciascun diodo led. Se ANi è a livello
logico basso, il transistor PNP è in saturazione e pertanto se il catodo si trova a 0!
allora il diodo led è polarizzato direttamente e risulta acceso .
Circuito di polarizzazione di un segmento led Display a sette segmenti
carattere a b c d e f g 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 2 0 0 1 0 0 1 0 3 0 0 0 0 1 1 0 4 1 0 0 1 1 0 0 5 0 1 0 0 1 0 0 6 0 1 0 0 0 0 0 7 0 0 0 1 1 1 1 8 0 0 0 0 0 0 0 9 0 0 0 0 1 0 0
`timescale 1ns/100ps // imposta la timeline temporale e la relativa precisione module bcd(CAT, out_mux); output[6:0] CAT; // vettore dati uscita per pilotare i catodi input[3:0] out_mux; // vettore di 4 bit reg[6:0] CAT; always @(out_mux) begin case(out_mux) // il carattere _ non è interpretato dal compilatore 0:CAT <=7'b00_00_00_1; 1:CAT <=7'b10_01_11_1; 2:CAT <=7'b00_10_01_0; 3:CAT <=7'b00_00_11_0 4:CAT <=7'b10_01_10_0; 5:CAT <=7'b01_00_10_0; 6:CAT <=7'b01_00_00_0; 7:CAT <=7'b00_01_11_1; 8:CAT <=7'b00_00_00_0; 9:CAT <=7'b00_00_10_0; endcase end // chiudo begin endmodule // chiudo modulo
Modulo Display Controller Tale modulo è responsabile, attraverso i tre blocchi always, della simulazione del
contatore, del multiplexer e del decoder anodico. La variabile count è definita come
un registro a 2 bit ed è inizializzata a 0 dal segnale di reset. Contemporaneamente
viene selezionata dal multiplexer la parola presente all'ingresso inA, mentre le uscite
del decoder assumono la configurazione 0111. In seguito, sul fronte di salita di un
nuovo impulso di clock, count incrementa di una unità, parallelamente viene
selezionata la parola presente all'ingresso inB, e viene acceso il secondo display. E
cosi via, fino a quando, durante il quarto ciclo di clock, quando count è pari a 3, un
ulteriore incremento di una unità lo riporta a zero, ripetendo così il ciclo.
`timescale 1ns/100ps // imposta la timeline temporale e la relativa precisione module display_controller(inA,inB,inC,inD,clock,reset,CAT,AN); output[6:0] CAT; output[3:0] AN; input[3:0] inA,inB,inC,inD; input clock,reset; reg[3:0] AN; wire[6:0] CAT;
display controller
modulo BCD
reg[3:0] out_mux; reg [1:0] count; bcd decoderbcd(.CAT(CAT),.out_mux(out_mux)); //creo un'istanza di un decoder BCD all'interno del display controller always @(posedge clock or posedge reset) if (reset) count<=0; else count<=count+1; always @(count or inA or inB or inC or inD) // ad ogni cambiamento della variabile count case(count) // seleziona una delle quattro parole in ingresso 0:out_mux <= inA; 1:out_mux <= inB; 2:out_mux <= inC; 3:out_mux <= inD; endcase always @(count) // ad ogni cambiamento della variabile count accende un diverso display attivandolo case (count) // ponendo l'uscita interessata a livello logico basso 0:AN <= 4'b01_11; 1:AN <= 4'b10_11; 2:AN <= 4'b11_01; 3:AN <= 4'b11_10; endcase endmodule
Modulo TIMER
Il modulo TIMER racchiude tutte le istanze dei moduli precedenti tra cui i cinque
contatori decimali: un divisore di frequenza che divide il clock da 1kHz a 100Hz, i
contatori relativi alle quattro cifre, il modulo di clock prescaler, e il modulo di
controllo dei display. Una volta instanziati, i moduli sono collegati tra loro attraverso
dei wire, i quali provvedono anche a collegare il modulo con i pin esterni.
`timescale 1ns/100 ps module TIMER(CAT,AN,Clk50,start,azzera,reset); output[6:0] CAT; output[3:0] AN; input start,azzera,Clk50,reset; wire enable,clear,clock; wire[3:0] inA,inB,inC,inD; wire enable_in_A,enable_in_B,enable_in_C,enable_in_D; module FSM TIMER(.enable(enable),.clear(clear),.start(start),.azzera(azzera),.clock(clock),.reset(reset));
ANODE DECODER MULTIPLEXER
contatore uscite ingressi selezionati
uscite AN0 AN1 AN2 AN3 inA inB inC inD
0 0 0 1 1 1 selected 0 1 1 0 1 1 selected 1 0 1 1 0 1 selected 1 1 1 1 1 1 selected
modulo Timer
Decimal_counter Dcounter (.count(), .enable_out(enable_in_D), .clock(clock), .reset(reset), .clear(clear), .enable_in(enable)); Decimal_counter Dcounter_D (.count(inD), .enable_out(enable_in_C), .clock(clock), .reset(reset), .clear(clear), .enable_in(enable_in_D)); Decimal_counter Dcounter_C (.count(inC), .enable_out(enable_in_B), .clock(clock), .reset(reset), .clear(clear), .enable_in(enable_in_C)); Decimal_counter Dcounter_B (.count(inB), .enable_out(enable_in_A), .clock(clock), .reset(reset), .clear(clear), .enable_in(enable_in_B)); Decimal_counter Dcounter_A (.count(inA), .enable_out(), .clock(clock), .reset(reset), .clear(clear), .enable_in(enable_in_A)); display_control DisplayControl (.AN(AN), .CAT(CAT), .clock(clock), .reset(reset), .inA(inA), .inB(inB), .inC(inC), .inD(inD)); clkPrescaler Prescaler (.clock(clock), .reset(reset), .Clk50(Clk50)); endmodule
Simulazione funzionale
Una volta termina la scrittura dei programmi, si effettua una prima simulazione il cui
scopo è verificare che il codice scritto funzioni secondo le specifiche di progetto. Tale
simulazione è realizzata istanziando dei moduli di Test Bench (il cui codice è simile ai
programmi già visti) all'interno dei quali sono istanziati i moduli da testare (UUT unit
under test), per mezzo di opportuni segnali detti stimoli. Solitamente un modulo di
test contiene un blocco initial in quanto, a differenza del blocco always che viene
ripetuto ciclicamente, questo viene eseguito una volta sola per tutta la durata della
simulazione. Inoltre nel modulo di test compaiono dei Task che sono delle direttive
per salvare il database di simulazione in un file, oppure visualizzarlo in forma grafica.
Esempio di codice per generare un segnale di reset con durata pari a 20ns.
… reg reset; initial begin reset=0; // creo un segnale di reset con durata pari a 10 ns. #20 reset=1; // aspetta 20 ns e poni reset a 1. #10 reset=0; // aspetta 10 ns e poni reset a 0. end
Blocco always per la generazione di un clock a 50MHz …. reg clock; always begin #10 clock=~clock; //dopo 10 ns ribalta il segnale di clock end
Esempio di modulo di test bench
Blocco initial per visualizzare il valore di clock (in formato binario) e la variabile
count (in formato decimale) e l’istante (mediante il task $time) in cui tali valori sono
calcolati. initial begin $monitor($time, “clock=%b, count=%d”, clock, count); end Comando per bloccare la simulazione dopo 100 ns `timescale 1ns/100 ps initial begin #100 $finish end
Processo di Sintesi
Il processo di sintesi, attraverso il software FPGA Compiler II di Synopsys, traduce il
codice Verilog in una descrizione a livello di porte logiche (netlist). In questa fase si
crea un nuovo progetto nel quale vengono aggiunti tutti i file sorgenti relativi ai
moduli, specificando infine il modulo Top Level. Successivamente si selezionano le
specifiche relative alla FPGA da programmare, che in questo caso sono:
• Produttore: Xilinx
• Famiglia: Spartan 3
• Dispositivo: XC3S200FT256
• Speedgrade: -4
Una volta selezionate le caratteristiche del dispositivo, è possibile scegliere se
ottimizzare il circuito per area occupata o per velocità. Nel nostro caso, è stata scelta
quest’ultima opzione. Il software provvede quindi a creare la netlist ottimizzata (file
.EDIF) che servirà per la fase successiva di Place and Route e a generare dei file
Verilog tramite i quali, attraverso una nuova simulazione funzionale, si può verificare
la correttezza del sistema descritto dalla netlist stessa.
Flusso di Progetto
Processo di implementazione
In questa fase, attraverso il tool dedicato presente nell’ISE design suite di Xilinx, si
assegnano gli ingressi e le uscite dei moduli agli elementi fisici presenti sulla scheda
come switch, display a quattro cifre, e oscillatore, specificando anche i vincoli
temporali richiesti. L'informazione è immagazzinata all'interno di un file di estensione
".UCF". Una volta definiti i vincoli, il software svolge un’operazione di traduzione
(Translating), in cui è creata una nuova netlist che tiene conto delle informazioni
appena acquisite generando un file ".NGD". In seguito, attraverso il processo di
Mapping si stabilisce la corrispondenza tra i componenti virtuali del disegno e i
componenti della FPGA (celle di logica, celle di I/O) e viene creato un file ".NCD"
(Native Circuit Description) .
Nome I/O Pin CAT 0 Output N16 CAT 1 Output F13 CAT 2 Output R16 CAT 3 Output P15 CAT 4 Output N15 CAT 5 Output G13 CAT 6 Output E14 AN 0 Output E13 AN 1 Output F14 AN 2 Output G14 AN 3 Output D14 Clk50 Input T9 start Input M14
azzera Input M13 reset Input L14
Tabella delle connessioni
In seguito, durante l'operazione di Place and Route i componenti sono piazzati
all'interno dei blocchi logici tenendo conto dei vincoli temporali, della lunghezza
delle connessioni, e della disponibilità delle risorse di instradamento disponibili.
Mentre, nella fase di Route, il software analizza il miglior instradamento possibile tra
i vari blocchi per soddisfare i requisiti temporali richiesti.
Analisi statica dei ritardi
Prima di passare alla fase successiva, attraverso il tool Xilinx Timing Analyzer, con il
quale è possibile analizzare in dettaglio tutti i ritardi dei segnali all’interno della rete,
e a verificare che i ritardi lungo dei determinati percorsi siano compatibili con i
vincoli temporali imposti dalle specifiche.
Processo di Programmazione
Prima di essere caricato su FPGA, il disegno completo deve essere convertito in un
formato compatibile dal chip. Attraverso il tool BitGen, il file (.NCD) viene
convertito in una sequenza di bit bitstream . Il file così ottenuto (.BIT) può essere ora
caricato, tramite cavo parallelo JTAG3, su chip FPGA, attraverso il tool Impact.
Verifica sperimentale
Nell’ultima fase è stato possibile verificare sperimentalmente il corretto
comportamento del timer così implementato, attraverso i pulsanti di start e clear. Tale
verifica ha dato esito positivo.