FPGA SoC

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

Libro_FPGA_gottardo_2017

Il libro ti testo di riferimento per il corso è -> First step on FPGA Xilinx

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

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

RedPitaya Register memory map 

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:

  1. Vivado High-Level Synthesis
  2. Vivado Simulator
  3. Vivado IP Integrator
  4. 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:

1- lanciare Vivado

Clicchiamo su “Create New Project” , forniamo un nome e una cartella di destinazione per il nuovo progetto.

2 - mome e locazione progetto

Il progetto creato sarà di tipo RTL.

3 - Tipo progetto RTL

selezioniamo la corretta versione del chip ZYNQ montato nella RedPitaya. (potrà variare in funzione della board di sviluppo che avete disponibile).

4 - Selezione Zynq montato nella RedPitaya

viene mostrato il summary (riassunto) del progetto che stiamo impostando.

5 - Summary del progetto impostato

Agiamo su “Finish” per attivare la creazione del progetto. Si apre l’ambiente di sviluppo che si comporrà di alcune sezioni principali:

  1. 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.
  2. 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.
  3. sezione “Design Runs” in cui vediamo le azioni intraprese a la situazione in tempo reale del progetto in realizzazione.
  4. 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.

6 - Ambiente Vivado

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

7 - Project setting_

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.

8 - confermare come top module

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“.

9 - Create block design_

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.

10 - Aggiungi_nuovo_IPtop_module

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.

11 - Search 1

digitando “zynq” si applica un filtro come mostrato sotto. Qui selezioniamo la prima voce “ZYNQ7 Processing System”.

12 - Select top module

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.

13 - standard Zynq

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.

14 - Run Automation

Vengono automaticamente connesse le periferiche AXI alle DDR e al bus dei PORT di IO.

15 - Run Automation done

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.

16 - zynq processor

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).

17 - zynq processor apply presets

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.

selected_peripherals_pitaya

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.

18 - zynq processor apply presets

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.

review1

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

n -create and pakager IP

Il nuovo IP lo vogliamo creare come nuova periferica AXI 4, quindi mettiamo lo spunto dove mostrato nella prossima figura.

21 -create nex AXI4

Agiamo su next e diamo un nome coerente al progetto che stiamo sviluppando al nuovo IP, nel nostro esempio Micro_GT_AND_logicIP.

22 -create new IP logico con nome

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.

23 -create new IPAXI_lite

Il nuovo IP va creato spuntando il menu “edit IP” ovvero la seconda voce.

24 -create new IPAXI_lite

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.

25 -Add port in top new IP

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

addsourrces_IP

Agiamo su Create files  … selezionare VHDL…non mettere local project

addsourrces_IP_path

definisce_porte

verrà posto inizialmente fuori dalla gerarchia

fuori gerarchia

doppio click sul nuvo file per entrare nel VHDL

Aggiungere le porte al file top level module

definizioneP

aggiungere il ocmponente al top level module

componente aggiunto

sotto va creata l’istanza

istanza

Al salvataggio il file del beheviural entra correttamente nella gerarchia

gerarchia corretta

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.

behavioral del file and logic

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.

IP repaccato

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:

rete_interna

Agiamo sul segno “+” del nostro IP visibile in alto, con nome and_logic_inst

and_logic

Possiamo quindi procedere con la creazione del file bitstream riversabile nella scheda usando winScp e Putty.

winscp

scaricare le immagine per vederle nelle dimensioni reali.

putty

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.

  — Users to add parameters here
  — User parameters ends
— Do not modify the parameters beyond this line
——————————————————————-
 port (
— Users to add ports here
  — User ports ends
— Do not modify the ports beyond this line
—————————————————————–
— Add user logic here
— User logic ends
end arch_imp;
——————————————————————
Istanzieremo in queste sezioni le porte di ingresso e la porta di uscita dell’operatore logico AND che vogliamo realizzare nel nostro nuovo IP.
port (
— 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
…… qui sono dichiarate le altre porte ad esempio l’AXI fino ad incontrare il comando  “);
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.
Nell’ultima sezione di commento andiamo a specificare la funzione logica tra le porte usando la sintassi VHDL, in questo caso un semplice AND tra i segnali.
 — Add user logic here
gt_porta_out <= gt_porta1_in AND gt_porta2_in;
— User logic ends
Non serve modificare l’area  — Users to add parameters here perché non sono stati definiti novi parametri nella definizione dell’IP.
merge
Cliccando su “Merge changes” compaiono le nuove porte
nuove porte
eseguire merge change per ogni voce che mostra una modifica presente
 Agendo su customization gui vediamo l’IP con le nuove porte.
new ip
Review and package –repakage IP
Si chiuderà la nuova istanza e si torna all’istanza del top module
Tasto destro inserisci new IP, e indichaimo il nome del nuovo modulo.
review2
procediamo facendo RUN Connection Automation
review3
Compare la nuova conformazione del design, a cui è connesso il nuovo IP ma con le porte scollegate.
design1
ora colleghiamo le porte dell’IP alle porte fisiche dello ZYNQ facendo make external sui pin.
TOOL “validate design” per vedere se il design è accettato dal vivado.
Ora definiamo i contraints.
è tempo di creare il wrapper
Clicchiamo su “Diagram” -> Sources allo scopo di creare il wrapper.
create wrapper
let vivado autoupdate
create wrapper1
Portiamoci su “Open elaborated” design. nel menù “RTL analysis”. del flow navigator.
Se nella barra degli strumenti, all’incirca a metà, compare “I/O Planning”, verrà visualizzato quanto sotto.
Se nel tentativo di passare all’analisi RTL, viene esposto un errore di tipo “missing Top Module”, cliccare con il tasto destro del mouse il primo file di tipo vhd che compare nella sezione “Source” –> “Hierarchy” , il quale supponendo correttamente eseguiti i passaggi fino qui descritti, indicherà la dicitura “wrapper-STRUCTURE”. Nello scroll menu che così compare, selezionare “Herarchy Uptade” –> “Automatic Update And Compile Order”, si aprirà una finestra in cui andrà selezionato la modalità automatic top module.
In questo modo si ha accesso all’area RTL Analysis.
Device RTL0
Device RTL1
Ci viene mostrato il chip selezionato all’atto della creazione del progetto, in pianta, suddiviso in banchi e con i vincoli “contraints” dei pin non re locabili quali ad esempio le masse e le alimentazioni.
Sulla barra in basso selezioniamo “I/O Ports”.
Nel menù “Scalar Ports” possiamo assegnare i pin logici ai pin fisici dello ZYNQ portando i segnali a disposizione nella scheda elettronica.
Device RTL4
Ora ci si deve adattare ai vincoli della scheda di destinazione, supponendo si tratti una RedPitaya ci si deve procurare il pinout dell’extension connector E1, in cui sono portati i pin dello ZYNQ.
Extension connector
Attenzione!!! Le tensioni tollerate sono a 3V3 e una valore di cinque Volt potrebbe danneggiare il sistema.
Potremmo ora definire gli ingressi in due maniere:
  1. 16 punti single ended.
  2. 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.

Extension connector E1

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.

Device RTL5

Assegniamo i tre pin come detto prima. Si ottiene:

Device RTL7

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.

Device RTL6

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.

Device RTL8

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”.

bitstream

Il sistema chiede di chiudere le operazione sul design con un salvataggio prima di procedere alla creazione della synthesis e del Bitstream.

bitstream1

In alto a destra compare in posizione poco visibile la segnalazione che il processo di creazione è in corso:

bitstream2

Se la creazione del file è andata a buon fine Vivado risponde con:

bitstream3

e compare la finestra:

bitstream ok

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

RTL = Register Transfer Level. Se selezioniamo “Default Layout” vedremo una sorta di schema elettrico, in realtà è il medesimo device visualizzato con il livello di dettaglio più esterno.
Device RTL2
Nella modalità di visualizzazione “Floor Planing” vediamo la disposizione del silicio impegnata dal nostro design.
Device RTL3
Occupazione delle risorse.
All’interno dello ZYNQ potrebbe essere di interesse vedere quante risorse ha impegnato il programma che abbiamo realizzato nell’area FPGA. E’ disponibile una finestra informativa che mostra i seguenti componenti:
  1. LUT =look up table, o elemento base composto di celle elementari. ha una composizione piuttosto standard e contiene una rete combinatoria.
  2. LUTRAM = elementi di memoria di interconnessione tra le LUT utilizzate.
  3. FF = Flip Flop.
  4. IO = punti di collegamento con il mondo esterno.
  5. BUFG = Buffer di collegamento con gli IO oppure i bus.

post implementation

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.

simul 1

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.

edit IP pakeger 1

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.

edit IP pakeger 2

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.

temp sim Nel flow navigator, nella sezione Simulation, agiamo su Run Simulation.

sim2

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.

sim3

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.

  1. doppia freccia a sinistra -> Riavvolgi la simulazione che attiviamo per un certo tempo.
  2. Lancia la simulazione
  3. imposta il tempo di simulazione ovvero una finestra temporale in cui visualizare e registrare gli eventi.
  4. 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”.

sim4

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.

sim5

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.

sim6

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.

sim7

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:

  1. Dichiarazione
  2. Istanza
  3. Mappatura

Le entità che verranno create hanno due sezioni che devo coesistere ed essere cooerenti.

  1. Behavioural in cui si definisce l’architettura architecture.
  2. 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 ;