Corso G-Tronic di programmazione FPGA con SoC.
Da gennaio 2017 è stato attivato presso la G-Tronic Robotics Didactic Division il corso di programmazione dei sistemi basati su FPGA e ARM multicore SoC (system on chip).
Esempio di creazione di un custom IP in ambiente Vivado xilinx 2015.4
La scheda di riferimento, in attesa che venga progettata una piattaforma Micro-GT basata su ZYNQ è la RedPitaya. Questa ha dei vincoli hardware (contraints) e dei preset che abilitano sul processore xc7z010clg400-1 le periferiche in uso e disabilitano quelle non connesse all’hardware di contorno.
Il file di preset è questo ->red_pitaya_rfxpreset
Il libro ti testo di riferimento per il corso è -> First step on FPGA Xilinx
E’ disponibile un tutorial acquistabile gratuitamente a condizioni Amazon (carta del docente, bonus cultura o App18). -> Tutorial FPGA libretto
Configurazioni e primi passi -> Corso FPGA SoC
Acquisire nozioni VHDL e il glossario -> pagina delle nozioni base e glossario termini
File .LIC -> .Xilinx File AXI_write ->axi_write Teoria AXI -> pagina AXI
- Esempio come serializzare dati a alta velocità -> Acquisire ADC a 2MHZ
- Esempio implementazione funzioni logiche ->playboard
- Procedura guidata creazione progetto per Pitaya.
- red-pitaya-notes-master (file TCL con molti esempi)
- immagini progetto read_write_AXI
- documentazione generica componenti_sequenziali
MDSPlus librerie Pitaya MDSplus è un sistema di monitoraggio e acquisizione dati utilizzato nella ricerca in ambito di fusione termo nucleare controllata. Ho ricompilato queste librerie in ambiente Linux e messe a disposizione dei gruppi di ricerca che ne potessero avere bisogno.
Programma di test del bus AXI lite -> scarica template uso AXI lite
Isolated hig speed ADC Full project.
On this page is presents a project of an electrically isolated interface from the machine to be used in industrial or research environments. Go to the page
Vivado by Xilinx.
Il sistema di sviluppo IDE è il Vivado 2015.4, sviluppato in TCL, un linguagio di Scripting che impartisce direttive a un interprete inline. Vivado è scaricabile dal sito ufficiale in varie forme, ad esempio WebPack e con licenze anche gratuite. Questi è in grado di effettuare lo sviluppo del design e visualizzarlo in modalità IP block design, la sintesi della rete, e la simulazione. Le componenti principali sono:
- Vivado High-Level Synthesis
- Vivado Simulator
- Vivado IP Integrator
- Vivado TCL Store
Il TCL è un linguaggio di Scripting che permette di sviluppare oggetti di Vivado o anche nuove funzionalità dell’IDE. D’altro canto ogni funzione standard di Vivado può essere evocata dalla console TCL anche in pipeline così che è possibile memorizzare un intero design o ricostruire un intero design semplicemente passando alla console tutto il file di script. Idem per quanto riguarda i preset dei sistemi centrali and esempio al configurazione dello ZYNQ, o il caricamento dei vincoli hardware dovuto allo schema della scheda di destinazione, come presenza di pullup, detti constraints.
Il Vivado presentato in questo sito e utilizzato ai corsi FPGA & SoC della G-Tronic Robotics (vedi calendario o chiedi informazioni via mail) è in grado di sviluppare per i device Ultrascale, Virtex-7, Kintex-7, Artix-7, and Zynq-7000.
La famiglia ZYNQ7000 è utilizzata nella board RedPitaya, presa come riferimento per i nostri corsi fino a che non sarà disponibile un prodotto Micro-GT.
IP = Intellectual property, è un blocchetto grafico che contiene un’implementazione di codice funzionale scritto in Verilog oppure VHDL che può essere agganciato a un’architettura più grande mostrata nella sezione “Block design” della piattaforma di sviluppo software Vivado.
RTL = register transfer level
Focus: Vogliamo realizzare l’AND logico tra due ingressi fisici del chip ZYNQ, internamente connessi alla sezione FPGA, e sincronizzarli a un segnale di clock interno generato nella sezione ARM multicore allo scopo di produrre il risultato logico combinatorio in un pin fisico di uscita a cui sia connesso un LED. Useremo la RedPitaya.
Fase 1) Creazione del Top module e preset.
Creiamo un nuovo progetto. La pagina iniziale ha questo aspetto:
Clicchiamo su “Create New Project” , forniamo un nome e una cartella di destinazione per il nuovo progetto.
Il progetto creato sarà di tipo RTL.
selezioniamo la corretta versione del chip ZYNQ montato nella RedPitaya. (potrà variare in funzione della board di sviluppo che avete disponibile).
viene mostrato il summary (riassunto) del progetto che stiamo impostando.
Agiamo su “Finish” per attivare la creazione del progetto. Si apre l’ambiente di sviluppo che si comporrà di alcune sezioni principali:
- il Flow navigator che suddivide in 7 passi lo sviluppo del progetto ovvero la creazione della struttura e la sua manipolazione nella prima voce “Project manager”, una sezione in cui è possibili inserire e manipolare nuovi IP e vedere la struttura di interconnessione “IP Integrator”, una sezione in cui è possibile simulare anche un IP alla volta il funzionamento della rete sviluppata “Simulation”, una sezione in cui è possibile vedere l’implementazione della rete rete sia in forma di circuito multifilare che a blocchi come superficie interna del silicio impegnato o come possibilità di connessione dei segnali ai pin esterni “RTL Analysis”, un’azione di “Synthesis” in cui avviene una compilazione dei vari codici degli IP, un’area di implementazione in cui viene realizzata la rete logica, anche separatamente per gli IP componenti del design “Implementation”, Un’ultima sezione, “Program and Debug” in cui si genera il file in formato bitstream, da inserire nel chip di destinazione e che gestisce e utilizza le board di sviluppo ad esempio la Zed board, consigliata da Xilix.
- Nel project manager abbiamo disponibili le sezioni in cui verrà mostrata una gerarchia a cui si devono attenere le parti componenti del progetto, gestita a cura del progettista.
- sezione “Design Runs” in cui vediamo le azioni intraprese a la situazione in tempo reale del progetto in realizzazione.
- In basso al centro è possibile attivare la console TCL, a cui passare dei file batch che lanciano sequenze che Vivado può eseguire per ricreare un design salvato da un altro progettista, messages, log, reports, Design Runs.
L’immagine sovrastante è visualizzabile nelle dimensioni reali. Alla voce Project Manager clicchiamo si “Project Setting”. Qui impostiamo il linguaggio di creazione come VHDL.
Attenzione: Il linguaggio qui selezionato sarà il medesimo per tutti i blocchi e sorgenti inseriti nella gerarchia da questo livello in poi. Se successivamente si tenta di modificare il linguaggio, ad esempio da Verilog a VHDL, di uno degli IP di gerarchia inferiore viene segnalato un errore la cui correzione richiede di cambiare prima il linguaggio del progetto TOP ovvero dei livelli gerarchici superiori.
Dobbiamo fornire un nome per il top_module, è buona norma che ricordi il nome del progetto seguito dal suffisso top_module.
agire su:Tools -> Project Settings
Il modulo che stiamo creando è il primo e il sistema si accorge che non ne esistono altri. ci viene chiesta conferma della volontà di inserire questo come nodo principale del nostro progetto. Confermiamo.
Portiamoci alla voce IP Integrator del flow navigator e clicchiamo su “Create block Design”. Creiamo l’IP dando un nome coerente Micro-GT_FPGA_AND (sostituendo il default design_1) e instanziandolo in “local to project“.
Si rientra nell’istanza principale di Vivado e nell’editor Diagram mi viene permesso di inserire il nuovo IP che diventerà il top ovvero il processore ZYNQ.
Si apre la finestra di ricerca nelle librerie degli IP che siamo interessati a inserire nel design, in questo momento il top_module ovvero lo ZYNQ.
digitando “zynq” si applica un filtro come mostrato sotto. Qui selezioniamo la prima voce “ZYNQ7 Processing System”.
Alla conferma viene inserito il chip ZYNQ che abbiamo richiesto e osserviamo la comparsa di una voce “Run Block Automation” che è di fatto una procedura automatizzata per connettere le parti essenziali alle periferiche di default tramite il bus AXI.
Questo IP però non è configurato come da hardware disponibile, viene quindi distribuito un file di preset che permette di portare questo ZYNQ alla situazione di quello installato nella Pitaya abilitando o disabilitando le periferiche usate o non usate. Assomiglia un po’ al concetto dei constraints ma questa è una configurazione interna al chip mentre i constraints sono relativi a collegamenti dei GPIO verso l’esterno e ai livelli/protocolli utilizzati.
Clicchiamo su “Run block automation” e confermiamo le impostazioni proposte relative alle porte attualmente attive.
Vengono automaticamente connesse le periferiche AXI alle DDR e al bus dei PORT di IO.
Nota bene: La connessione dell’unica periferica AXI attiva “M_AXI_GP0_ACLK” va impostata a mano puntando con il mouse sul segnale di clock FCLK_CLK0 e trascinando nella destinazione del segnale, come mostrato in figura.
Aggiungere i “Preset” tramite il file di configurazione fornito dal costruttore della board in uso.
Il file di preset è questo ->red_pitaya_rfxpreset
un altro file di impostazione generico -> ps7_init
doppio click sull’IP del TOP_Module, diveterà marrone, si apre la finestra Zynq processing system (5.5) in cui è presente il comando preset.
si apre la tendina mostrata in figura con cui possiamo caricare il file di preset che nella sostanza è una procedura TCL. (approfondimenti nel libro di testo indicato a inizio pagina).
Confermando il caricamento del file potremmo già osservare le impostazioni fisiche ad esempio esplorando le voci di “Peripherls I/O pins” , “Clock Configuration”, “MIO Configuration”, ecc. Questa esperienza viene lasciata al visitatore del sito come utile esercizio.
Se l’operazione va a buon fine vedremo comparire degli “spunti” sulle periferiche abilitate dal file caricato come mostrato sotto.
Dopo l’esecuzione della procedura automatica l’IP del TOP module cambia aspetto perché ora mette a disposizione anche altre porte, segnali e periferiche che nella versione di default non erano abilitate.
Per analogia a quanto visto in precedenza le periferiche AXI vanno connesse almeno a un segnale di clock al fine di evitare errori di compilazione, syntesis ecc.
Nota bene: Lo stesso clock “FCLK_CLK0” nel presente esempio piloterà le 4 periferiche AXI che risultano citate, e quindi introdotte nell’IP, nel file di preset indicato in precedenza. Effettuiamo i collegamenti cliccando prima sul FCLK_CLK0 e trascinando con lo strumento matita sul lato sinistro dell’IP (per quattro volte).
Solo in caso di redpitaya con sue specifiche funzioni (non caricare per progetti custom)
Notiamo che non sono presenti file di “Constrains”. Dobbiamo aggiungere questo file cliccando con il tasto destro del mouse sulla cartella vuota “Constrains”, selezionando “Add Sources”. Nella successiva finestra selezionare “add or create constrains”, premere il tasto “next” e aggiungere il file con estensione “.xdc”.
Scarica il file di constrains standard della Pitaya ->red_pitaya_2015.4
Fase 2) Creazione di un custom IP.
Nei precedenti passaggi abbiamo predisposto il sistema all’aggancio di nuovi altri moduli in cui implementare in VHDL le funzioni logiche di nostro interesse o anche cose più complesse. Per il momento limitiamoci a volere eseguire un AND logico tra due ingressi e produrre un’uscita su un PIN a cui è collegato un LED della Pitaya.
Sul menù “Tools” clicchiamo su “Create and package IP”
Il nuovo IP lo vogliamo creare come nuova periferica AXI 4, quindi mettiamo lo spunto dove mostrato nella prossima figura.
Agiamo su next e diamo un nome coerente al progetto che stiamo sviluppando al nuovo IP, nel nostro esempio Micro_GT_AND_logicIP.
Ora creiamo la connessione basata su interfaccia AXI lite la quale avrà solo 4 registri che saranno parametrizzabili dal tool di lancio “AXI_write” che useremo nella console Linux quando manderemo in esecuzione il progetto sulla Pitaya.
Il nuovo IP va creato spuntando il menu “edit IP” ovvero la seconda voce.
Agendo su finish si apre una nuova istanza di Vivado. Entrati nel nuovo IP dovremo aprire i suoi sorgenti per aggiungere le porte e l’istanza di queste porte (non è questo il blocco che fungerà da wrapper).
Facciamo tasto destro sul file principale denominato “arch_imp”, add sources, mettere il pallino su “Add or create design sources”, -> next -> create file, definire il nome del nuovo sorgente con aggiunta behaviural.
Come file location scegliere il progetto attivo
Facciamo doppio click sul file indicato nella foto (il primo nella gerarchia), vengono mostrati i sorgenti.
Ora dobbiamo aggiungere al sorgente la definizione delle nuove porte abbinate al behevioral.
Agire su “add sources” del flow navigator:
nuovamente agiamo su add or create defign sources
Agiamo su Create files … selezionare VHDL…non mettere local project
verrà posto inizialmente fuori dalla gerarchia
doppio click sul nuvo file per entrare nel VHDL
Aggiungere le porte al file top level module
aggiungere il ocmponente al top level module
sotto va creata l’istanza
Al salvataggio il file del beheviural entra correttamente nella gerarchia
il sorgente del file contenete il Behavioral (quello più interno nella gerarchia) conterrà questo sorgente minimo in cui non può mancare il comportamento, ovvero la logica ovvero il behavioral.
fare “Review and Package” delle varie voci da aggiornare (eventuali merge changes); Verrà proposto di chiudere l’istanza alla fine del salvataggio con revisione. Potremmo decidere di lasciarla aperta ma il risultato sarà un aggiornamento dell’ IP in copia temporanea. Se invece chiudiamo l’istanza il nuovo IP verrà salvato nella cartella “ip_repo” selezionata come default nelle impostazioni del progetto e la copia temporanea rimossa. L’effetto del lavoro in copia temporanea si manifesta con la mancanza delle nuove porte, visualizzate nella grafica del nuovo IP. Eseguendo la giusta procedura, al momento dell’aggiunta del nuovo IP nel Block Design noteremo invece la presenza delle nuove porte di input/output.
Colleghiamo il pin-out del nuovo IP a delle connessioni fisiche interne con il comando “make external” eseguibile semplicemente con control+t in ogni pin di input/output (attenzione: non modificare ne bus ne pin AXI…).
Aggiorniamo il catalogo IP agendo su refresh ip catalogue, e successivamente premere rerun al fine di visualizzare lo stato corretto attuale del design.
Andiamo così nel block design, tasto destro sul nodo principale (con icona gialla), create HDL wrapper; noteremo la creazione di un nuovo sorgente, posizionato in radice della struttura nel cui nome compare la voce “wrapper”.
Dopo il synthesis dovrebbe comparire la realizzazione interna della rete logica, con l’aspetto simile a questo:
Agiamo sul segno “+” del nostro IP visibile in alto, con nome and_logic_inst
Possiamo quindi procedere con la creazione del file bitstream riversabile nella scheda usando winScp e Putty.
scaricare le immagine per vederle nelle dimensioni reali.
Ora, chiudendo con due jumper i primi due pin in basso del connettore E1 della Pitaya 1 con 3 ovvero 3v3 con DIO0_P (collegato al pin G17), e il pin 2 con 4 ovvero l’altro 3v3 con DIO0_N (collegato al pin G18) vedremo accendersi il LED 0 collegato al pin F16 dello Zynq. Funziona!.
Scarica il progetto testato -> porte_logiche
Torniamo a questioni teoriche e di programmazione:
Il Vivado suggerisce, con sezioni di commento, i punti in cui inserire le customizzazioni del codice VHDL.
— Do not modify the parameters beyond this line
— Users to add ports here
— Do not modify the ports beyond this line
— Users to add ports here
gt_porta1_in : in std_logic;
gt_porta2_in : in std_logic;
gt_porta_out : out std_logic;
— User ports ends
end Micro_GT_AND_logicIP_v1_0;” nota: con ); si chiude l’area di dichiarazione delle porte. Questo è già presente nel codice VHDL prima dell’inserimento delle nostre nuove porte tra i commenti che fanno da guida per lo user.
gt_porta_out <= gt_porta1_in AND gt_porta2_in;
— User logic ends
![merge](http://www.gtronic.it/test/wp-content/uploads/2017/01/merge.png)
![nuove porte](http://www.gtronic.it/test/wp-content/uploads/2017/01/nuove-porte.png)
![new ip](http://www.gtronic.it/test/wp-content/uploads/2017/01/new-ip.png)
![review2](http://www.gtronic.it/test/wp-content/uploads/2017/01/review2.png)
![review3](http://www.gtronic.it/test/wp-content/uploads/2017/01/review3.png)
![design1](http://www.gtronic.it/test/wp-content/uploads/2017/01/design1.png)
![create wrapper](http://www.gtronic.it/test/wp-content/uploads/2017/01/create-wrapper.png)
![create wrapper1](http://www.gtronic.it/test/wp-content/uploads/2017/01/create-wrapper1.png)
![Device RTL0](http://www.gtronic.it/test/wp-content/uploads/2017/01/Device-RTL0.png)
![Device RTL1](http://www.gtronic.it/test/wp-content/uploads/2017/01/Device-RTL1.png)
![Device RTL4](http://www.gtronic.it/test/wp-content/uploads/2017/01/Device-RTL4.png)
![Extension connector](http://www.gtronic.it/test/wp-content/uploads/2017/01/Extension-connector.png)
- 16 punti single ended.
- 8 punti differential digital I/O.
Facciamo attenzione perché il databook specifica chiaramente “all DIOx_y pins are LVCMOS33 asb max rating are: min -0,40V max 3v3 +0.55V. Nella colonna FPGA pin number è specificata la locazione di collegamento del pin come visibile nella sezione RTL di Vivado. E’ proprio in “RTL Analysis” che viene generato il file .XDC che contiene i constrants. Se carichiamo nel nostro progetto il file red_pitaya_2015.4 di fatto assegniamo i pin del connettore E1 (quello di sinistra) come da tabella sottostante.
I led disponibili si trovano al pin out dello ZYNQ indicato con:
- LED 0 -> F16
- LED 1 -> F17
- LED 2 -> G15
- LED 3 -> H15
- LED 4 -> K14
- LED 5 -> G14
- LED 6 -> J15
- LED 7 -> J14
Collegare i pin logici ai pin fisici dello ZYNQ.
La tabella fornita nel sito della RedPitaya indica con una lettera e un numero i pin del connettore di estensione E1, ad esempio DIO_P -> G17 e DIO_N -> G18. entrambi a 3V3.
Alcune uscite sono vincolate in single ended (ovvero il riferimento del segnale è la massa della scheda) e portate a LED, ad esempio, il LED 0 della Pitaya si trova all’indirizzo fisico F16.
Assegniamo i tre pin come detto prima. Si ottiene:
Nota bene: è importante definire nei segnali di input se la loro azione sarà diretta (normal 0 -> present 1) oppure invertita (normali 1 -> present 0). Nel primo caso metteremo alla voce “PULL Type” un PULLDOWN, mentre nell’uscita andrà totalmente rimosso “NONE” per ovvie questioni elettriche. Dato che non stiamo realizzando linee di trasmissione non metteremo dei carichi di terminazione di linea su “FP_VTT_50”. Ingrandisci l’immagine sovrastante per vedere bene le impostazioni.
E poi salviamo la configurazione in un file che rappresenta i nostri nuovi vincoli ovvero i constraints.
Come vediamo sopra il file dei constraints avrà estensione XDC.
E’ scaricabile dal sito della redpitaya il suo specifico file di constraints.
Se ci riportiamo nel block design vedremo l’esistenza del nuovo file dei constraints.
Siamo pronti per effettuare sia la simulazione che la generazione del file bitstream da caricare nello ZYNQ. Vediamo prima altre visualizzazione della configurazione interna nel menù RTL.
In “flow navigator” andiamo ad agire su “Generate Bitstream”.
Il sistema chiede di chiudere le operazione sul design con un salvataggio prima di procedere alla creazione della synthesis e del Bitstream.
In alto a destra compare in posizione poco visibile la segnalazione che il processo di creazione è in corso:
Se la creazione del file è andata a buon fine Vivado risponde con:
e compare la finestra:
Alla fine siamo pronti per inserire il file “.bit” prodotto nello ZYNQ. Dovremmo quindi loggarci alla scheda usando unWinScP e con Putty lanciare l’esecuzione eventualmente parametrizzando con il tool Linux AXI write.
Altre visualizzazione di RTL
![Device RTL2](http://www.gtronic.it/test/wp-content/uploads/2017/01/Device-RTL2.png)
![Device RTL3](http://www.gtronic.it/test/wp-content/uploads/2017/01/Device-RTL3.png)
- LUT =look up table, o elemento base composto di celle elementari. ha una composizione piuttosto standard e contiene una rete combinatoria.
- LUTRAM = elementi di memoria di interconnessione tra le LUT utilizzate.
- FF = Flip Flop.
- IO = punti di collegamento con il mondo esterno.
- BUFG = Buffer di collegamento con gli IO oppure i bus.
Simulazione.
La simulazione è possibile tramite i tools integrati in Vivado che permettono un’analisi piuttosto realistica anche per i segnali a alta velocità sia nella sezione FPGA che nella regione di interconnessione ARM->FPGA via bus AXI. Gli IP possono (a volte devono) essere testati singolarmente. In questo caso vanno impostati come TOP module del sotto progetto.
Per simulare l’IP che genera l’AND logico, costruito sopra, entriamo in block design e editiamo in IP pakager il blocchetto interessato.
In basso a destra, Edit in IP packager del blocco Micro_GT_AND_logicIP_0
Attenzione: A questo punto delle volte viene segnalato un errore, probabilmente perché ci sono nel Vivado delle impostazioni che delegano solo il sistema a fare l’update della gerarchia e quindi di fatto la copia temporanea dell’IP che vogliamo simulare risulta protetta in scrittura. Se la simulazione non dovesse partire lanciamo una nuova istanza con un nuovo nome, ad esempio Micro_GT_AND_logicIP_0_sim1
Nella cartella temporanea vedremo comparire una copia della parte di progetto che mandiamo in simulazione ovvero dello specifico IP. Essendo una copia potremmo anche cancellarla alla fine della simulazione.
impostiamo come TOP module il blocco che vogliamo simulare, attenzione che i sorgenti disponibili potrebbero essere più di uno, in genere sono almeno 2 perché il primo implementa l’interfacciamento AXI con il livello superiore di IP, ad esempio lo ZYMQ mentre il secondo implementa la logica con cui abbiamo customizzato l’IP che realizza la nostra funzione logica.
nell’immagine sotto mostriamo anche la cartella temporanea in cui siano presenti le due istanze della stessa simulazione aperta in IP pakager impostando un nome diverso ovvero sim1.
Nel flow navigator, nella sezione Simulation, agiamo su Run Simulation.
Run behavioral simulation per creare l’ambiente di simulazione.
L’ambiente mostra tutte le porte e i segnali impostabili o internamente generati all’IP. La parte più complessa è quella relativa alla gestione dell’AXI, ma tre i vari pin compariranno anche quelli con cui abbiamo customizzato il nostro IP.
Ingrandire l’immagine usando il tasto destro del mouse o salvandola locale.
Nella lista delle porte, le prime due sono gli input della nostra logica AND implementata nella sezione FPGA. La terza porta è l’uscita che abbiamo configurato come il primo LED della scheda RedPitaya.
Le frecce azzurre hanno il seguente significato.
- doppia freccia a sinistra -> Riavvolgi la simulazione che attiviamo per un certo tempo.
- Lancia la simulazione
- imposta il tempo di simulazione ovvero una finestra temporale in cui visualizare e registrare gli eventi.
- Le lenti di ingrandimento porteranno i segnali nel corretto fattore di scala dato che nell’area FPGA posso arrivare a commutazione dell’ordine del nano secondo.
Impostiamo i segnali virtualizzati in input, ad esempio forziamo dei clock. Tasto destro sulla pima variabile e andiamo alla voce “force clock”.
Impostiamo questi valori (esemplificativi) per l primo input della porta AND. Questo significa che all’ingresso abbiamo posto uno stimolo da onda quadra (duty cycle del 50%) con un periodo di 100ns.
Impostiamo il secondo segnale in quadratura (sfasato di 90 gradi) e con un periodo doppio. Lo scopo e quello di poter valutare la logica AND nel pin di uscita.
Lanciare la simulazione agendo sulla freccia azzurra. Potremmo impostare per quanto tempo è attivo e dovremmo agire sulle icone lenti di ingrandimento per dare il giusto zoom. L’effetto finale è nell’immagine sottostante.
Il primo diagramma temporale oscilla con periodo 100ns ed è il primo ingresso della porta AND. Il secondo ha periodo doppio. La sola intersezione dei due segnali di ingresso soddisfa la funzione booleana AND e fa oscillare il terzo diagramma temporale che rappresenta l’uscita.
Sintassi VHDL.
Un codice VHDL, pensato per prodotti Xilinx, è una struttura gerarchica che descrive un design da implementare tramite il processo di syntesis nella superficie del silicio del circuito integrato.
Il nodo principale sarà detto top level o wrapper, nel caso di sistemi SoC ZYNQ7000 sarà la struttura dei core ARM a cui interfacciare via bus AXI la sezione FPGA.
Le librerie principali sono le seguenti e compaiono all’inizio di ogni programma VHDL:
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
La progettazione comporta tre parti di implementazione software:
- Dichiarazione
- Istanza
- Mappatura
Le entità che verranno create hanno due sezioni che devo coesistere ed essere cooerenti.
- Behavioural in cui si definisce l’architettura architecture.
- Structural in cui si descrivono le porte port e segnali signal impiegati nell’architettura.
I commenti in linguaggio VHDL seguono il doppio meno ad esempio:
— Questa riga è un commento.
I segnali, definiti in VHDL, sono delle variabili che possono essere combinati tra loro tramite gli operatori logici nella lista. Possono essere dichiarati come standard logic.
- AND
- OR
- NOR
- NAND
- XOR
- XNOR
- NOT
Definiamo i segnali con i nomi identificativi segnale1 e segnale2, ecco alcuni esempi di applicazione delle funzioni logiche.
NOT segnale1
Segnale1 AND segnale2
(NOT segnal21) AND (segnale2 XOR (segnale3 OR (NOT segnale4)) XOR segnale5);
Il costrutto if si applica a espressioni booleane, la valutazione dell’espressione non richiede le parentesi tonde
if segnale1 then
uscita <= ‘1’; — associa il valore true al segnale booleano in uscita
end if;
ecco un esempio di come associare un vettore di booleani con la valutazione di una singola condizione, oppure attivare un if multiplo:
if condizione1 = ‘1’ then
out_vector <= “001”
elsif condizion2 = ‘1’ then
out_vector <= “110”
— altre condizioni
else
out_vector <= “000”
end if;
Esiste il costrutto case e opera in maniere simile a quanto avviene in C. Si può applicare ad esempio ad un flusso di dati di una trasmissione attraverso un buffer o analogamente nel buffer di una tastiera.
case scancode is
when buffer”14″ => –buffer è il nome della variabile non una parola chiave
integer_signal <= 1;
when buffer”18″ =>
integer_signal <= 2;
when buffer”19″ | buffer”20″ | buffer”21″ =>
integer_signal <= 3;
when others =>
integer_signal <= 0;
end case;
L’assegnazione delle variabili avviene tramite il costrutto := mentre l’assegnazione dei segnali avviene tramite il costrutto <= |
Esempio di assegnazione del valore a una variabile booleana chiamata flag. Il valore da assegnare a una variabile potrà anche arrivare da un segnale.
flag := true;
variabile_temporanea(3 downto 0) := segnale_vettore(7 downto 4);
I processi.
I processi sono generalmente la struttura portante di un comportamento di un’entità. L’attivazione avviene tramite il collegamento a segnali di clock ai quali vengono sincronizzati. L’attivazione avviene quando un segnale subisce una variazione oppure dipende dalla variazione di un altro segnale a cui è correlato. Le dipendenze sono citate nella lista di sensibilità dei processi.
output_process: process(segnale_stato)
begin
if segnale_stato = ‘1’ then
output_vector <= “010”;
else
output_vector <= “101”;
end if;
end process;
Istanza delle componenti, sono delle evocazioni con il relativo lancio in esecuzione delle entità ed avviene in questo modo:
AND_ent_1: AND_entity –con significato di attivazione di una copia dell’entità AND.
port map(
input_1 => input_1_sig,
input_2 => input_2_sig,
output => output_sig
);
I tipi di dato.
Il tipo di dato più comune in VHDL è lo std_logic che è dfinito nella libreria std_logic_1164 della IEEE. Il suo impiego comporta la rappresentazione dei due stati booleani ‘1’ o ‘0’ con l’aggiunta dello stato di alta impedenza ‘z’ comun nelle logiche digitali.
I vettori sono rappresentati con la definizione di std_logic_vector che in VHDL definisce un bus. A tutti gli effetti è un array di std_logic ovvero di bits accumunati da un unico punto di accesso.
std_logic_signal <= ‘1’;
std_logic_signal <= ‘0’;
sl_vector_signal_8 <= “11110000”; — an 8 bit vector
sl_vector_signal_8 <= x”F0″; — equivalent to above
sl_vector_signal_8 <= sl_vector_signal_16(15 downto 8);
— you can assign from part of a larger vector
std_logic_signal <= sl_vector_signal_8(5) — access a single bit
sl_vector_signal_8 <= (others => ‘0’) — set all bits to ‘0’
il booleano differisce dallo std_logic perché funge da variabile interna o costante interna come mostrato sotto:
constant FLAG: boolean := false;
variable flag_monitor: boolean := true;
Definizione di valori numerici.
La definizione dei valori numerici in VHDL può avvenire in due diversi modi, la prima è quella di definire un std_logic_vector in cui inputare una rappresentazione binaria o esadecimale, la seconda è quella di allocare il dato nella memoria evitando cosi di rappresentarlo in linee e locazioni di silicio tramite un bus.
Entità.
Le entità sono l’effettiva interfaccia tra il nuovo modulo di cui si sta implementando il design e quanto preesistente ad esempio il top module. si definiscono in questa maniera:
entity is rete_combinatoria
end entity
Gli elementi dell’entity sono 2 due le porte e i generic, vediamo come si definiscono.
Definizione delle porte.
il costrutto port definisce i punti di ingresso e uscita del nuovo design. Sono l’effettiva interfaccia di collegamento e la dichiarazione e impostazione è contemplata “nell’architettura” che esiste come costrutto “architetture”. Le porte possono essere raccolte in un bus che funge da PORT. Ad esempio:
enable: in std_logic;
data_bus: out std_logic_vector(7 downto 0);
il costrutto generic dichiara dei segnali in maniera simile a come avviene nei linguaggi di programmazione procedurali. L’assegnazione del tipo avviene per assunzione dalla gerarchia in cui compare il costrutto.
bus_width: integer := 8;
my_boolean: boolean := false;
un esempio di dichiarazione di un’entità con le sue porte è questa, si noti che l’ultimo elemento dichiarato non presenta il punto e virgola perché è solo l’ultimo elemento di una lista di parametri e non un comando o richiamo di funzione:
entity or_entity is
port(
input_1: in std_logic;
input_2: in std_logic;
output: out std_logic
);
end or_entity;
L’architettura è un contenitore di entità il cui esempio più semplice può essere:
architecture AND_entity_arch of AND_entity is
begin
output <= input_1 and input_2; –esegue l’AND dei segnali alle porte e calcola l’uscita
end architecture;
I segnali
La dichiarazione dei segnali segue la sintassi:
signal port_i : std_logic;
signal bus_signal: std_logic_vector(15 downto 0);
signal count: integer range 0 to 31;
Dichiarazione di costanti.
— state values
constant state_1 : std_logic_vector := “01”;
constant state_2 : std_logic_vector := “10”;
constant addr_max: integer := 1024; — maximum address value
Dichiarazione di funzioni.
function sign_extend (narrow_bus: std_logic_vector(15 downto 0))
return std_logic_vector(31 downto 0) is
variable output: std_logic_vector(31 downto 0);
begin
output(15 downto 0) <= narrow_bus(15 downto 0);– lower 16 are the same
output(31 downto 16) <= (others => narrow_bus(15));– upper 16 are sign-extension of MSB
return output;
end sign_extend;
Dichiarazione delle componenti delle entità.
component or_entity is
port(
input_1: in std_logic;
input_2: in std_logic;
output: out std_logic
);
end component;
Dichiarazione di variabili.
variable count_v: integer range 0 to 15;
variable data_v: std_logic_vector(7 downto 0);
variable condition_v: boolean;
Dichiarazione di tipi.
type enum_type is (a, b, c, …, z);
type int_array is array(3 downto 0) of integer;
type sl_vector_array is array(0 to 15) of std_logic_vector;
Dichiarazione di sottotipi.
subtype addr_int is integer range 0 to 65535;
subtype sub_enum_type is enum_type range a to m;
il behavioural (comportamento)
Qui viene descritto il comportamento dell’architettura del la logica la quale come impostazione di base definisce le porte su cui opera.
–behaviural
architecture Porta_AND of AND_1 is
begin
output <= input_1 or input_2;
end Porta_AND;
–structural
architecture Porta_AND of AND_1 is
component or_entity
port(
output: out std_logic;
input_1: in std_logic;
input_2: in std_logic
); end component;
begin
or_1: or_entity
port map(
output => o,
input_1 => i_1,
input_2 => i_2
);
end Porta_AND ;