Getting Started: FPGAs Hello World!

L’intento di questo articolo non  é  di fornire  una guida al VHDL,  ma un workflow dallo schematico al bitstream attraverso l’ISE Design Suite di Xilinx rispondendo alle domande di chi compra un nuovo FPGA e non sa da dove iniziare.

FPGARegistratevi al sito Xilinx e createvi un account e scaricate Xilinx ISE Design Suite  per Windows o Linux, nel mio caso sto utilizzando la versione 14.7. Decomprimete il file scaricato e installate la suite scegliendo il Webpack che ha la licenza per studenti.

Step 1 – Creare un nuovo progetto

a) Aprite Xilinx ISE Design Suite e create un nuovo progetto.
b) File -> New project.
c) Nominate  il progetto  ad esempio ledBlink e scegliete il percorso d’installazione.

xilinx-1

d) I dati inerenti al vostro FPGA gli  trovate anche direttamente sulla board, una volta compilato il Project Settings cliccate Next.

artix7Nel mio caso sto utilzzando una FPGA Board Nexys4 Artix-7 acquistata presso il vendor italiano Mirifica.

xilinx-2

Step 2 – Utilizzo dello schematico

a) Facciamo Right click su  xc7a100t-1csg324 e selezioniamo  New Source.
b) Infine selezioniamo “Schematic” nominandolo ad esempio “sch_ledBlink” e clickiamo “Next” e “Finish”.

schematic_file

c) Realizzando per primo lo schematico questo verrà impostato  in automatico come Top Module.

topModuleDiventando così  la nostra work-area dove inseguito andremo ad utilizzare  il “simbolo” del blink-led che realizzeremo nel prossimo step a partire dal codice VHDL.

sch_ledBlink
Work-Area

Step 3 – VHDL Module

a) Facciamo Right click su  “sch_ledBlink″ e selezioniamo  “New Source”.
sch_newsource
b) Infine selezioniamo “VHDL Module” nominandolo ledBlink e clickiamo “Next” e “Finish”

vhdlModule

VHDL e linguaggi di programmazione

A volte l’approccio di chi ha esperienza  con un linguaggio di alto livello (c# , Java etc) è di considerare il VHDL come un qualsiasi altro linguaggio, scordandosi però che non si sta “programmando” ma “descrivendo” hardware. In particolare, vi sono due caratteristiche che differenziano il VHDL rispetto ai linguaggi di programmazione convenzionali:

  • lo svolgimento parallelo di più operazioni.
  • la gestione dei tempi di propagazione dei segnali all’interno dei circuiti digitali

Questi due punti sono interessanti se pensate all’implementazione di reti neurali artificiali (ANN) su FPGA considerando che l’architettura di Von Neumann su cui si basano i computer è seriale invece una delle peculiarità delle ANN era il loro essere parallele e distribuite. Qui trovate l’implementazione di un perceptron su FPGA utilizzando Matlab e System Generator.

Entity e architecture

Una descrizione di un componente  VHDL richiede una entity declaration (riga 6-12) e un’architecture body (riga 14-34), la prima inerente all’interfaccia (interface) del componente quindi alle porte di input e output. La seconda invece definisce la funzione dei componenti. Inoltre possono esistere diverse  possibili architetture per la stessa entity.

How it works

Perché il nostro led lampeggi abbiamo bisogno di dividere la frequenza di clock del FPGA attraverso un contatore binario, ma di quanti bits? Non dobbiamo contare fino a $$100 MHz$$, ma fino a $$50 MHz$$ in modo che il nostro led si accenda e si spenga.
Rappresentando il numero intero di $$50 MHz$$ in codifica binaria:

$${50.000.000}_{10} = { {‭0010 1111 1010 1111 0000 1000 0000‬}}_{2}$$

notiamo così che l’array standard logic avrà bisogno di un minimo di 27 bits.

Il contatore viene incrementato sul fronte di salita del clock fino a quando non è minore del valore  $$ { { 10111110101111000010000000 }_{ 2 } }$$ ed infine resettato.

Library

Come nei linguaggi di programmazione possiamo utilizzare delle librerie e dei packages che aggiungono funzionalità al VHDL standard. I package e le librerie sono moduli che possono contenere porzioni di codice isolate dal resto della descrizione con lo scopo di rendere il codice riutilizzabile. Le entity, le architecture, i package, i package body e la configuration prendono il nome di design units. Un modello praticamente è fatto di design units al cui interno si costruisce la descrizione dettagliata del sistema. Ad esempio la LIBRARY IEEE contiene i seguenti packages:

  • std_logic_1164 che definisce la std_logic e relative funzioni
  • std_logic_arith funzioni aritmetiche
  • std_logic_signed funzioni aritmetiche su numeri con segno
  • std_logic_unsigned per quelli senza segno

I package contengono quindi le definizioni di tutti i tipi di variabili, degli operatori aritmetici e relazionali nonché alcune funzioni di importanza rilevante, come quelle di conversione (in interi, in std_logic e std_logic_vector, in interi con o senza segno, in bit e bit_vector).

Entity declaration

Il design entity inizia con la dichiarazione dell’entity definendone innanzitutto il nome che però non deve contenere spazi bianchi e caratteri speciali o iniziare con numeri. Se doveste usare un editor esterno , ad esempio SublimeText, il nome della entity e del file dovranno coincidere quando importate il file .vhd in un progetto su ISE Design. Con l’istruzione Port dichiariamo le porte di input e output dell’interfaccia.
L’entitity definisce quindi le porte con cui il nostro sistema comunica con il mondo esterno.

Notiamo come dopo la dichiarazione dell’ultimo segnale non va messo il punto e virgola (;), ma nell’ultima parantesi rotonda chiusa a indicare il fatto che è l’ultima dichiarazione dell’entity.
Spesso la entity viene paragonata ad una scatola nera (black box) visto che ne vediamo solo gli ingressi e le uscite , ma non il funzionamento interno. Più semplicemente immaginiamoci un simbolo di uno schematico e chiediamoci quali saranno gl’ingressi e le uscite del nostro sistema?

blackBox
L’entity è come una black-box

Nel nostro caso vogliamo far lampeggiare un Led, quindi avremmo come input il clock (riga 10) e come output il led (riga 11).

Architecture body

Dopo aver definito l’interfaccia di una design entity, si passa alla descrizione di un’architettura cioè al funzionamento interno del sistema .
L’architettura è composta da un header e da un body che inizia con la keyword begin ed è la parte  dove si inseriscono le istruzioni descrittive ed è un’area concorrente cioè dove le istruzioni, a prescindere dall’ordine di scrittura, possono essere eseguite parallelamente. Esiste però anche anche un’area sequenziale , dichiarata dal costrutto process, al cui interno le istruzioni vengono eseguite nell’ordine di scrittura.

Process

Il process body, nonostante sia un insieme di istruzioni sequenziali (sequential staments),  viene considerato come un’unica operazione concorrente ed è alla base delle descrizioni comportamentali. Solo alle istruzioni  sequenziali sono concesse le assegnazioni <= in quanto l’assegnazione di un signale viene considerata sequenziale all’interno di un processo. All’interno di un processo è possibile definire dei tipi, delle costanti, delle variabili che sono locali al processo e quindi invisibili ad altri processi o statements concorrenti dell’architettura.

Un processo è composto da tre parti:
sensitivity list ovvero la lista dei segnali in grado di attivare il processo in caso di un evento nei segnali di ingresso.
–  dichiarazione dei tipi, di sottotipi, delle costanti che hanno solo visibilità locale.
process body che rappresenta il comportamento del process.

Prima abbiamo importato la libreria standard IEEE 1164 che ci permette di utilizzare le due funzioni: rising_edge() e falling_edge() che assumono valore true quando il segnale utilizzato come argomento delle funzioni effettua un fronte di salita o di discesa.

Step 4 – Create Schematic Symbol

Nella barra laterale di ISE Design Suite selezioniamo il codice VHDL da convertire in Simbolo e  in seguito a selezionare per aggiungerlo al nostro schematico. Per sicurezza converebbe anche fare prima un Check Syntax.

create symbol

In basso alla barra laterale di sinistra abbiamo diverse tab come Design, Files, Libraries, noi andremo a clicckare su Symbols dove selezioneremo dalla path del nostro progetto il simbolo appena realizzato.

symbols

In categories ritroveremo la path d’installazione del nostro progetto selezionandola su Symbols apparirà il simbolo appena creato.

symbols2Ora dobbiamo solo clickare su ledBlink e trascianare il simbolo sopra l’area di lavoro. Dovreste ottenere un risultato analogo al mio:

symbol-schematic

Come best practice mia personale quando inserisco I/O Marker scelgo di dare nomi in minuscolo per gli input e in maiuscolo per gli Output. Così facendo è più facile distinguerli scrivendo l’user contraits file UCF.

Step 5 – Implementation Contraits File

a) Facciamo Right click su xc7a100t-1csg324 e selezioniamo  New Source infine  “Implementation Constraints File”  e nominiamolo ad esempio “pinMapBlink”.
b) Premiamo Next e poi Finish.

xilinx-6

In questo file imposteremo  il pin-map del FPGA come gl’inputs, gli outputs ed il clock. Ci sono altri modi per farlo come ad esempio l’utilizzo di PlanAhead Design, ma preferisco questo metodo perché con pochi in-outputs è il più veloce.
Ora da Nexys 4 Resource Center dovete scaricare dalla sezione “Design Reosurces”  l’user contrait file per avere la location dei pins,ad esempio il led si trova nella location “U3”.

Step 6 – Sintesi

La sintesi ,detta anche compilazione, è il passaggio da una descrizione ad alto livello (comportamentale) ad una a bassa livello (net-list) ossia a livello di gates anche attraverso l’utilizzo del sintetizzatore di altre aziende non limitando la portabilità del VHDL. Infine l’elaborato della sintesi prende il nome di net-list attraverso un programma di place e routing, è in grado di generare il codice bitstream da inserire nel FPGA.

Step 7 – Upload del codice

Per l’implementazione del bit-code su FPGA vi consiglio il framework di Digilent Adept 2  selezionando il file con estensione .bit che avete generato dopo la sintesi che troverete nella path folder d’installazione del progetto.

digilentAdept

Step 8 – Hello world!

Ed ecco il risultato finale con il led che lampeggia nella locazione (U3) che avevamo scelto nel nostro contraits file.

index

Volendo sapere per quanto tempo il led rimane acceso o spento ci basta calcolare:

$${ 2 }^{ 26 }=67.108.864$$,  26 è il valore dei bits del contatore

Ora dobbiamo dividere il risultato ottenuto per la frequenza di clock del FPGA cioè 100.000.000 di oscillazioni al secondo

$$ 67.108.864/100.000.000=0,67108864 $$ $$\simeq$$ 0,6 secondi

Moltiplichiamo il risultato

$$0,67108864\ast 2=1,34217728 $$ $$\simeq$$ 1,3 secondi, avendo così il periodo.

Se controlliamo il led dovremmo vedere che lampeggia una volta ogni 1,3 secondi (spento-acceso o acceso-spento) e 2,7 secondi per un loop completo (da spento-spento o da acceso-acceso). E la frequenza?

$$f=\frac { 1 }{ T } =\frac { 1 }{ 1,34217728 } = 0,74 Hz\simeq$$

 

Bibliografia

Nexys
[1] Nexys 4, Digilent
[2] Nexys 4 Reference Manual, Digilent

FPGAs
[1] Volnei A. Pedroni,Circuit Design with VHDL, MIT Press Ltd, 2004
[2] Volnei A. Pedroni, Digital electronics and design with VHDL, Morgan Kaufmann, 2008
[3] Volnei A. Pedroni, Circuit Design and Simulation with VHDL, MIT Press, 2010
[4] Gina Smith, FPGAs 101: Everything you need to know to get started,Newnes, 2010