IPGEN: UN FRAMEWORK PER LA
GENERAZIONE AUTOMATICA DI
IP-CORE PER FPGA
12 ottobre 2006
P OLITECNICO DI M ILANO
FACOLTÀ DI I NGEGNERIA
C ORSO DI L AUREA IN I NGEGNERIA I NFORMATICA
IPGEN: UN FRAMEWORK PER LA GENERAZIONE
AUTOMATICA DI IP-CORE PER FPGA
Relatore:
Prof. Donatella SCIUTO
Correlatore: Ing. Marco Domenico SANTAMBROGIO
Tesi di Laurea di:
Matteo Murgida
Matricola n. 662247
Alessandro Panella
Matricola n. 661986
A NNO ACCADEMICO 2005-2006
Love is the dance of Eternity. (Dream Theater)
Matteo
I know someday you’ll have a beautiful life,
I know you’ll be a star... (Pearl Jam)
Alessandro
Indice
Riassunto
3
1
Premesse
7
1.1
Scenario operativo . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.1.1
Progettazione modulare dello hardware . . . . . . . . . .
8
1.1.2
IP-Core . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
1.1.2.1
Definizione . . . . . . . . . . . . . . . . . . .
9
1.1.2.2
Dal core all’IP-Core . . . . . . . . . . . . . . .
10
1.1.3
Sistemi riconfigurabili . . . . . . . . . . . . . . . . . . .
12
1.1.4
Riconfigurabilità dinamica parziale: il flusso di Caronte .
13
1.1.4.1
Architettura hardware di Caronte . . . . . . . .
16
1.1.4.2
Da Caronte a YaRA . . . . . . . . . . . . . . .
17
Strumenti utilizzati . . . . . . . . . . . . . . . . . . . . . . . . .
20
1.2.1
Xilinx EDK
. . . . . . . . . . . . . . . . . . . . . . . .
20
1.2.2
Xilinx ISE . . . . . . . . . . . . . . . . . . . . . . . . .
21
1.2.3
MentorGraphics ModelSim . . . . . . . . . . . . . . . .
23
1.2
2
Approcci precedenti
27
2.1
OCP Socket e CoreCreator . . . . . . . . . . . . . . . . . . . . .
27
2.2
Interface Adaptor Logic . . . . . . . . . . . . . . . . . . . . . . .
29
2.3
EDK Create/Import Peripheral Wizard . . . . . . . . . . . . . . .
30
2.4
ImpulseC CoDeveloper . . . . . . . . . . . . . . . . . . . . . . .
31
2.5
Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
v
3
Infrastrutture di comunicazione
33
3.1
IBM CoreConnect OPB . . . . . . . . . . . . . . . . . . . . . . .
34
3.1.1
OPB PSelect . . . . . . . . . . . . . . . . . . . . . . . .
37
3.1.2
OPB IPIF . . . . . . . . . . . . . . . . . . . . . . . . . .
39
3.1.2.1
I Servizi . . . . . . . . . . . . . . . . . . . . .
40
3.1.2.2
Decodifica degli indirizzi . . . . . . . . . . . .
41
3.1.2.3
IPIC . . . . . . . . . . . . . . . . . . . . . . .
42
3.1.2.4
Modalità di utilizzo . . . . . . . . . . . . . . .
44
Wishbone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
3.2.1
Le interfacce . . . . . . . . . . . . . . . . . . . . . . . .
45
3.2.2
Protocollo di comunicazione . . . . . . . . . . . . . . . .
47
3.2.3
Tipi di connessione . . . . . . . . . . . . . . . . . . . . .
48
3.2
4
Metodologia
51
4.1
Motivazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
4.1.1
IPGen nel flusso di Caronte . . . . . . . . . . . . . . . .
52
Struttura dell’IP-Core generato . . . . . . . . . . . . . . . . . . .
53
4.2.1
Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
4.2.2
Stub . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
4.2.3
IP-Core . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
Workflow di IPGen . . . . . . . . . . . . . . . . . . . . . . . . .
57
4.3.1
Lettura . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
4.3.2
Scrittura . . . . . . . . . . . . . . . . . . . . . . . . . . .
58
Confronti con gli altri approcci . . . . . . . . . . . . . . . . . . .
59
4.2
4.3
4.4
5
Implementazione
65
5.1
Struttura del programma . . . . . . . . . . . . . . . . . . . . . .
65
5.2
Utilizzo e funzionamento del framework . . . . . . . . . . . . . .
69
5.2.1
Inizializzazione . . . . . . . . . . . . . . . . . . . . . . .
70
5.2.2
Fase di lettura . . . . . . . . . . . . . . . . . . . . . . . .
70
5.2.3
Scelta dell’interfaccia e fase di scrittura . . . . . . . . . .
71
5.2.4
Terminazione . . . . . . . . . . . . . . . . . . . . . . . .
75
5.3
5.4
6
7
Caratteristiche delle descrizioni VHDL generate . . . . . . . . . .
75
5.3.1
Visione d’insieme . . . . . . . . . . . . . . . . . . . . . .
75
5.3.2
Istanziazione dei componenti e mappaggio delle porte . .
78
5.3.3
Processi di lettura e scrittura . . . . . . . . . . . . . . . .
79
5.3.4
Gestione dei generic . . . . . . . . . . . . . . . . . . . .
81
5.3.5
Gestione di porte con dimensione maggiore di 32 bit . . .
83
Come scrivere un core interfacciabile automaticamente . . . . . .
85
5.4.1
Requisiti concettuali . . . . . . . . . . . . . . . . . . . .
86
5.4.2
Requisiti pratici . . . . . . . . . . . . . . . . . . . . . . .
87
Risultati sperimentali
89
6.1
Test di prestazione . . . . . . . . . . . . . . . . . . . . . . . . .
89
6.2
Test di funzionamento . . . . . . . . . . . . . . . . . . . . . . . .
95
Conclusione e sviluppi futuri
99
Bibliografia
101
Ringraziamenti
103
Elenco delle figure
1.1
Struttura di un IP-Core . . . . . . . . . . . . . . . . . . . . . . .
11
1.2
Il flusso di lavoro di Caronte . . . . . . . . . . . . . . . . . . . .
15
1.3
L’architettura hardware di Caronte . . . . . . . . . . . . . . . . .
17
1.4
Collegamento tra un modulo fisso e uno riconfigurabile nell’architettura di Caronte . . . . . . . . . . . . . . . . . . . . . . . .
18
1.5
L’architettura di YaRA . . . . . . . . . . . . . . . . . . . . . . .
19
1.6
Workspace di Project Navigator . . . . . . . . . . . . . . . . . .
22
1.7
Workspace di ModelSim. . . . . . . . . . . . . . . . . . . . . . .
24
2.1
Schema dell’IP-Core secondo l’approccio OCP . . . . . . . . . .
29
3.1
Set di segnali visti all’interfaccia con un componente slave . . . .
35
3.2
Schema dei servizi e dei segnali IPIF . . . . . . . . . . . . . . . .
39
3.3
Le interfacce Wishbone lato master e lato slave . . . . . . . . . .
45
3.4
Schema della connessione “Data Flow” . . . . . . . . . . . . . .
48
3.5
Schema della connessione “Shared Bus Interconnection” . . . . .
49
3.6
Schema della connessione “Crossbar Interconnection” . . . . . .
50
4.1
Flusso di creazione delle HW-SSP . . . . . . . . . . . . . . . . .
54
4.2
Struttura di un core interfacciato con OPB . . . . . . . . . . . . .
55
4.3
Struttura di un core interfacciato con Wishbone . . . . . . . . . .
55
4.4
Flusso operativo del reader . . . . . . . . . . . . . . . . . . . . .
58
4.5
Flusso operativo del writer . . . . . . . . . . . . . . . . . . . . .
59
4.6
Confronto degli IP-Core risultanti utilizzando differenti approcci .
61
ix
5.1
Class diagram di IPGen . . . . . . . . . . . . . . . . . . . . . . .
66
5.2
Esempio dell’output video di IPGen . . . . . . . . . . . . . . . .
72
5.3
Flusso di creazione dei file in uscita . . . . . . . . . . . . . . . .
74
5.4
Sequence diagram dell’esecuzione di IPGen . . . . . . . . . . . .
76
5.5
Diverse strutture di file generati . . . . . . . . . . . . . . . . . . .
78
5.6
Dichiarazione e istanziazione del core di un addizionatore binario
a 32 bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
5.7
Esempio di processo di lettura dei registri . . . . . . . . . . . . .
81
5.8
Esempio di processo di scrittura dei registri . . . . . . . . . . . .
82
5.9
Processo di lettura per un core avente una uscita da 128 bit . . . .
83
5.10 Processo di scrittura per un core avente un ingresso da 96 bit . . .
85
6.1
Occupazione percentuale di overhead introdotto da IPGen . . . . .
92
6.2
Occupazione dello stub generato per i “dummy core” . . . . . . .
94
6.3
Simulazione di un IP-Core con interfaccia PSelect . . . . . . . . .
95
6.4
Simulazione di un IP-Core con interfaccia OPB IPIF . . . . . . .
96
6.5
Simulazione di un IP-Core con interfaccia Wishbone . . . . . . .
96
Riassunto
L’obiettivo di questo lavoro di tesi è stato lo sviluppo di un framework, denominato IPGen, in grado di creare automaticamente l’interfaccia di comunicazione
per core scritti in linguaggio VHDL. L’interfacciamento viene realizzato incapsulando il core ricevuto in input in una struttura, chiamata IP-Core, che contenga la logica necessaria affinchè esso possa dialogare correttamente con gli altri
componenti del sistema nel quale viene inserito.
Il beneficio primario che l’utilizzo di IPGen apporta in fase di progettazione
di un componente hardware consiste nel fatto che lo sviluppatore è libero di
concentrare interamente i propri sforzi nell’implementazione della logica funzionale, anzichè occupare parte del tempo nella realizzazione della logica di comunicazione, in quanto quest’ultima viene generata automaticamente in modo
estremamente rapido.
Questa caratteristica permette di incrementare il livello di automatismo nella
progettazione di sistemi modulari, ovvero architetture composte da una molteplicità di componenti, ciascuno dei quali svolge una funzionalità specifica ed è
in grado di interagire con gli altri moduli attraverso un’opportuna infrastruttura di comunicazione. Tale metodologia di progettazione permette la creazione
di sistemi dinamicamente riconfigurabili, tipicamente implementati su dispositivi
riprogrammabili come le FPGA. La funzionalità di un sistema di questo tipo può
essere modificata mentre esso è operativo, senza alcuna interruzione apparente,
intercambiando alcuni dei moduli che lo compongono.
Il progetto di ricerca D.R.E.S.D. (Dynamic Reconfigurability in Embedded
System Design), condotto all’interno del Laboratorio di Microarchitetture del Po3
Riassunto
litecnico di Milano, si occupa dello studio e dello sviluppo di tali architetture, e
costituisce il contesto all’interno del quale il software è stato concepito.
Caronte è un flusso di progettazione realizzato in seno a D.R.E.S.D. per la
creazione di sistemi dinamicamente riconfigurabili. Dal momento che il flusso di
Caronte riceve una specifica di alto livello, la quale viene analizzata e partizionata
generando i moduli che andranno a comporre l’architettura, è necessario creare
in breve tempo le interfacce per tali componenti. È questa la motivazione che ha
portato alla realizzazione di IPGen.
Nonostante il framework sia stato concepito come parte integrante del flusso
di Caronte, esso mantiene inalterata la propria identità di software stand-alone, in
quanto il suo utilizzo permette un notevole risparmio di tempo e risorse ogniqualvolta si debba creare un componente hardware.
Nel Capitolo 1 sono fornite alcune nozioni di base utili a tracciare un quadro
dell’ambito in cui IPGen si colloca. Innanzitutto viene mostrata una panoramica
sulla progettazione modulare dello hardware e ne viene descritto il componente fondamentale: l’IP-Core. Dopo aver analizzato i vari tipi di sistemi riconfigurabili, vengono introdotti il flusso di Caronte per la riconfigurabilità dinamica
parziale e la sua evoluzione YaRA. Successivamente vengono presentati gli strumenti utilizzati durante lo sviluppo del framework: Xilinx EDK, Xilinx ISE e
MentorGraphics ModelSim.
Nel Capitolo 2 vengono discussi gli approcci relativi al problema dell’interfacciamento di moduli hardware, fornendo in tal modo importanti termini di
paragone con i quali confrontare la metodologia proposta.
Nel Capitolo 3 vengono descritte dettagliatamente le interfacce attualmente
supportate da IPGen. In primo luogo viene esposto il funzionamento del bus OPB
e delle due interfacce che permettono di connettersi ad esso: PSelect ed IPIF.
Viene poi presentato il bus Wishbone, componente che sta alla base dell’innovazione apportata da YaRA.
Nel Capitolo 4 viene introdotto IPGen spiegando la metodologia che è alla
base del suo funzionamento. Dapprima sono esposte le motivazioni che hanno
portato allo sviluppo del framework; successivamente viene delineata la struttura
4
Riassunto
dell’IP-Core costituente l’output del tool e il flusso di esecuzione che porta alla
sua generazione. Il capitolo termina fornendo alcuni confronti con gli approcci
esposti nel capitolo 2.
Nel Capitolo 5 il framework viene presentato dal punto di vista implementativo, iniziando dalla descrizione delle classi che lo compongono. Nel seguito
vengono illustrati l’utilizzo e il funzionamento di IPGen e vengono descritte le
caratteristiche dei file da esso generati. Infine sono enunciate alcune convenzioni
alle quali il progettista si deve attenere durante la creazione di un core affinché
esso sia interfacciabile tramite il programma.
Nel Capitolo 6 sono mostrati i risultati sperimentali che validano il lavoro
svolto, ottenuti tramite test di prestazione e di funzionamento.
Il Capitolo 7 conclude l’elaborato ponendo le basi per sviluppi futuri.
5
Capitolo 1
Premesse
IPGen è un software pensato per rendere la creazione di componenti hardware
più veloce ed efficiente. Esso è stato concepito per essere integrato in un flusso
di sviluppo di sistemi hardware, denominato Caronte [1, 2]. Quest’ultimo permette la progettazione di architetture che siano “dinamicamente riconfigurabili”,
la cui funzionalità possa essere cioè modificata a run-time, senza interruzioni nel
flusso di lavoro del dispositivo. Al fine di agevolare la comprensione degli argomenti trattati in questo testo si procede in questo capitolo con la descrizione
dello scenario nel quale il framework si colloca, fornendo un insieme di nozioni
e definizioni utili al lettore. Nella prima parte vine descritto l’ambiente nel quale
il software presentato si trova ad operare, cioè quello della riconfigurabilità dinamica, mentre nella seconda parte si descrivono brevemente gli strumenti software
utilizzati durante lo svolgimento del lavoro di tesi.
1.1
Scenario operativo
Il settore nel quale IPGen è stato concepito è quello dei sistemi hardware embedded, ovvero sistemi elettronici progettati appositamente per una determinata
applicazione. Una tipologia particolare di questi è costituita dai sistemi riconfigurabili, generalmente implementati su supporti fisici riprogrammabili, come le
FPGA (Field Programmable Gate Array). La funzionalità di ogni singolo dispo7
CAPITOLO 1. PREMESSE
sitivo di questo tipo può essere modificata un numero indeterminato di volte, in
modo tale da conferire a queste architetture un’elevatissima flessibilità. Uno dei
segmenti di ricerca attivi in questo ambito riguarda la potenzialità di questi dispositivi di essere riconfigurati mentre operano, senza alcuna interruzione apparente.
Questo tipo di riconfigurazione viene eseguita suddividendo il sistema in blocchi,
ognuno dei quali può essere modificato senza interrompere la normale esecuzione
degli altri. All’interno di questi blocchi vengono collocati dei moduli, denominati IP-Core, che svolgono il compito per il quale sono stati progettati, secondo i
principi della progettazione modulare.
Questa sezione descrive in modo dettagliato lo scenario qui accennato, presentando dapprima il metodo di progettazione modulare dello hardware e successivamente il componente fondamentale di questa metodologia, l’IP-Core. Si
prosegue con una panoramica sui sistemi riconfigurabili e con la descrizione di
Caronte, il flusso di lavoro per la riconfigurabilità dinamica sviluppato all’interno del Laboratorio di Microarchitetture del quale il tool costituisce un passaggio
fondamentale.
1.1.1
Progettazione modulare dello hardware
La progettazione modulare (Modular-Based Design) [3] è una metodologia di
sviluppo che identifica un sistema hardware come un insieme di moduli, ognuno
dei quali espleta una determinata funzionalità. Queste componenti, sviluppate
separatamente, vengono poi interconnesse mediante un’opportuna infrastruttura
di comunicazione, tipicamente un bus o degli allacciamenti “punto a punto”. I
vantaggi che questa metodologia comporta sono molteplici:
• un sistema può essere sviluppato da un team di individui che lavorano indipendentemente su moduli differenti, i quali vengono assemblati in un
secondo momento. Questo lavoro parallelo permette di risparmiare molto
tempo e risorse;
• permette di modificare solo una parte di un sistema, lasciando il resto inalterato;
8
CAPITOLO 1. PREMESSE
• getta le fondamenta per il riutilizzo dello hardware: i moduli creati costituiscono un’entità a sé stante, e possono perciò essere inseriti in sistemi
diversi.
Esiste una prassi di massima da seguire per ottenere una buona architettura modulare, eccone i punti più significativi:
1. creazione di una architettura di alto livello (top-level design) che contenga
le informazioni sui moduli e le modalità di comunicazione;
2. implementazione dei moduli nel linguaggio scelto (di solito VHDL o Verilog), che può essere svolta da persone diverse;
3. assemblaggio dei moduli all’interno del top-level design.
Ognuno dei moduli che compongono un sistema di questo tipo viene denominato IP-Core, il quale costituisce l’output di IPGen ed è argomento della sezione
seguente.
1.1.2
IP-Core
L’obiettivo di IPGen è costruire IP-Core. È dunque estremamente importante
conoscere ciò a cui questo termine si riferisce. Viene dapprima fornita una definizione
formale del termine, per proseguire con la descrizione della struttura interna di
questo “oggetto”.
1.1.2.1
Definizione
Il termine “IP-Core” (Intellectual Property-Core) indica [4, 5] un’entità logica
riutilizzabile, impiegata sia nella creazione di logiche “statiche” (ASIC) che nelle
schede riprogrammabili (come le FPGA, vedere sezione 1.1.3). In altre parole, un
IP-Core è un’unità che, all’interno di un sistema hardware più ampio, svolge un
determinato compito. Come esprime il termine stesso, un IP-Core è una proprietà
intellettuale: vale a dire che esso è una risorsa che può essere posseduta da un
9
CAPITOLO 1. PREMESSE
singolo o da una società, oppure può essere messa a disposizione di chiunque la
voglia utilizzare (spesso si parla di open cores).
Una usuale classificazione degli IP-Core è la seguente:
• Hard cores, implementazioni fisiche della progettazione della proprietà intellettuale;
• Firm (semi-hard) cores, che contengono informazioni sul proprio posizionamento ma possono essere esportate su varie architetture;
• Soft cores, definibili come una rete di porte logiche e registri, implementata
spesso in un linguaggio di descrizione dell’hardware come VHDL.
Un IP-Core può costituire sia un componente master, per esempio la stessa CPU,
oppure un componente slave, che deve essere “utilizzato” da un master1 . Esso può inoltre rappresentare entità come un bus o porta seriale, e quindi costituire una infrastruttura di comunicazione tra altri IP-Core. Nel seguito si farà
riferimento soltanto a IP-Core di tipo slave; inoltre, con il termine IP-Core ci si
riferirà esclusivamente ai soft cores, cioè quelli che possono essere istanziati su
una FPGA.
L’analogia tra le componenti della progettazione modulare (sezione 1.1.1) e
IP-Core è immediata: gli IP-Core costituiscono infatti i moduli che compongono
un sistema hardware progettato modularmente.
Nel prossimo paragrafo viene descritta la struttura generale di un IP-Core.
1.1.2.2
Dal core all’IP-Core
Con il termine core si intende il “cuore elaborativo” di un componente, cioè la
parte di logica interna che ne costituisce la funzionalità vera e propria. Il core
è dunque la porzione distintiva e caratteristica che rappresenta la vera e propria
1I
dispositivi che possono essere connessi ad un bus si dividono in master e slave. I primi sono
componenti attivi, ovvero possono decidere quando iniziare un trasferimento di dati; i secondi
sono passivi, in quanto rimangono in attesa di una richiesta di trasferimento [6].
10
CAPITOLO 1. PREMESSE
“proprietà intellettuale” del componente. In realtà, per essere inserito efficacemente all’interno di un sistema più grande, un core deve essere dotato di un’interfaccia verso l’esterno. Questa interfaccia permette ad esso di accedere al canale
di comunicazione (per esempio un bus) e dialogare con gli altri componenti dell’architettura. Per questo motivo, con il termine IP-Core d’ora in poi si farà riferimento ad un blocco logico dotato di un’opportuna interfaccia, adatto ad essere
inserito in un sistema che adotti l’infrastruttura di comunicazione per il quale esso
è stato progettato.
In pratica, un IP-Core è costituito da un “guscio” esterno che racchiude il
core ed un’opportuna interfaccia di comunicazione, come mostrato in figura 1.1.
Spesso un core, quando contenuto in questo tipo di struttura, viene indicato con
l’espressione user logic, proprio per rimarcare il fatto che è questa la parte che
viene effettivamente implementata dall’utente e ne costituisce una proprietà intellettuale.
Figura 1.1: Struttura di un IP-Core
Nella prossima sezione vengono introdotti i sistemi riconfigurabili, all’interno
dei quali gli IP-Core rivestono un ruolo fondamentale in quanto costituiscono,
nella architettura presa in esame, i blocchi che possono essere intercambiati per
fornire la capacità al sistema di evolversi.
11
CAPITOLO 1. PREMESSE
1.1.3
Sistemi riconfigurabili
Una branca relativamente nuova della progettazione hardware si occupa di sistemi riconfigurabili, ovvero sistemi che, al contrario delle tradizionali architetture
ASIC (Application-specific Integrated Circuit), permettono di essere modificati
dopo essere stati prodotti. Essi prendono dunque il nome di sistemi riconfigurabili. In questo ambito i dispositivi più diffusi sono le FPGA (Field Programmable
Gate Array) che, grazie ad un complesso sistema di porte logiche, possono essere riprogrammate ogni qual volta è necessario far svolgere loro un particolare
compito.
Non esiste un’unica direzione secondo cui intendere la riconfigurabilità di un
sistema; si possono infatti identificare i seguenti parametri:
• Riconfigurabilità interna: il flusso di riconfigurazione è gestito da un componente interno alla FPGA da riconfigurare;
• Riconfigurabilità esterna: la riconfigurazione è gestita da un componente
esterno alla FPGA da riconfigurare.
Si può inoltre fare una distinzione tra:
• Riconfigurabilità totale: è il caso in cui la FPGA viene interamente riconfigurata;
• Riconfigurabilità parziale: secondo questa modalità, soltanto una parte della FPGA viene modificata, mentre l’altra non è interessata dal processo di
riconfigurazione.
Quest’ultima classificazione necessita di un’ulteriore esplicazione: se si opera su
una rete di più FPGA, invece che su di un singolo chip, la riconfigurabilità è totale
se si analizza una singola FPGA ma può risultare parziale se il punto di vista è
quello della rete nel suo insieme.
Su tali basi si aggiunge un ulteriore grado di libertà: tali architetture possono essere riconfigurate anche a run-time, cioè mentre sono operative, senza
12
CAPITOLO 1. PREMESSE
interrompere il flusso di lavoro. Tale processo prende il nome di riconfigurabilità dinamica, che si contrappone alla tradizionale riconfigurabilità statica, effettuata soltanto quando la FPGA non è operativa. Risulta evidente che la riconfigurabilità dinamica effettuata su un solo chip deve essere parziale, in modo
da non interromperne l’esecuzione. Il tipo di riconfigurazione che viene presa
in esame nel seguito è la Riconfigurabilità Dinamica Parziale (Partial Dynamic
Reconfiguration).
Xilinx introduce [7] due differenti flussi per implementare la riconfigurabilità
dinamica parziale: l’approccio module-based e quello difference-based .
• Module-based partial reconfiguration. Questo approccio si basa sulla
progettazione modulare dello hardware (sezione 1.1.1), e prevede la definizione
di moduli riconfigurabili, cioè porzioni delimitate di FPGA la cui dimensione è invariante durante l’esecuzione, che possono essere riconfigurate a
run-time senza interferire con il funzionamento degli altri moduli e quindi
del sistema complessivo. Per rendere tale procedimento possibile, è necessario definire una architettura di livello “top” (top-level architecture) in cui
ogni modulo è visto come una “scatola nera” (black-box). La logica al livello top deve limitarsi alla descrizione delle black box (senza conoscenza del
loro contenuto) e di una infrastruttura fissa di comunicazione, i bus macro.
• Difference-based partial reconfiguration. Nelle architetture in cui si rende
necessario riconfigurare blocchi logici di dimensioni significative, è richiesta la riconfigurazione module-based. Se invece si devono attuare cambiamenti piccoli, per esempio una porta di Input/Output, è consigliabile utilizzare l’approccio difference based. In questi casi, si modifica il file di configurazione (NGC) dove è necessario e si produce un bitstream che contiene
solamente le differenze tra la configurazione attuale e quella precedente.
1.1.4
Riconfigurabilità dinamica parziale: il flusso di Caronte
In questa sezione viene presentato Caronte, un workflow di sviluppo per architetture riconfigurabili [1, 2] sviluppato all’interno del Laboratorio di Microarchitet13
CAPITOLO 1. PREMESSE
ture. Tale metodologia è in parte basata su EDK, presentato nella sezione 1.2.1,
e adotta dunque uno strumento già largamente utilizzato nello sviluppo di architetture per FPGA, sfruttandone le caratteristiche che lo rendono adatto alla
realizzazione di sistemi riconfigurabili. Caronte intende la riconfigurabilità come
ridefinizione di uno o più componenti all’interno dell’architettura, è dunque profondamente legato alla riconfigurazione per moduli (sezione 1.1.3): ogni modulo che viene intercambiato viene denominato blocco riconfigurabile. Il flusso di
lavoro di Caronte è mostrato in figura 1.2, e include le seguenti fasi:
• HW-SSP Phase. Durante la fase Hardware Static System Photo viene identificato un insieme di sistemi completi ognuno dei quali rappresenta un passo nel processo di riconfigurazione. L’idea è quella di considerare il sistema
nel tempo come una sequenza di foto statiche. Queste sono tutte identiche
per quanto riguarda la parte statica del sistema, mentre differiscono per il
contenuto di almeno una Black Box (vedere sezione 1.1.4.1);
• Design Phase. Obiettivo di questa fase è quello di raccogliere tutte le informazioni richieste per il calcolo dei bitstream necessari per implementare
la riconfigurabilità su di una FPGA. A tal proposito viene utilizzato EDK,
adottando una approccio modular based (sezione 1.1.1), fino a produrre la
descrizione dei sistemi in VHDL. Un problema da tenere in considerazione è la natura dinamica dell’architettura realizzata, in particolare per quanto riguarda la comunicazione sia tra i moduli riconfigurabili, sia tra essi
e la parte fissa del sistema. Per questo vengono utilizzate delle particolari linee di comunicazione chiamate bus macro, che rimangono inalterate
durante la riconfigurazione, e sono dunque comuni a tutte le SSP che compongono l’evoluzione del sistema. Bisogna inoltre determinare a priori la
dimensioni di ogni porzione fisica di FPGA destinata ad accogliere i moduli
riconfigurabili;
• Bitstream Creation Phase. Vengono creati tutti i bitstream necessari per
la mappatura fisica dell’architettura su FPGA. Questi vengono chiamati bitstream parziali in quanto non contengono l’informazione sull’intero siste14
CAPITOLO 1. PREMESSE
ma, ma solo sulle porzioni che vengono modificate tra due passi successivi,
e vengono pertanto calcolati come differenza tra due bitstream completi di
configurazione.
Figura 1.2: Il flusso di lavoro di Caronte
Un problema cruciale è la decisione di quali parti di un sistema hardware coinvolgere nella riconfigurazione e quali invece lasciare fissi sulla FPGA. Bisogna
inoltre determinare quali blocchi riconfigurabili andranno in una determinata porzione
di FPGA (la partizione del chip deve essere fissata a priori e non può essere modificata) e quali in altre. Si tratta di questioni molto delicate che vanno trattate con
particolare attenzione, avendo l’obiettivo di raggiungere il miglior compromesso
tra occupazione e prestazioni dell’architettura.
15
CAPITOLO 1. PREMESSE
1.1.4.1
Architettura hardware di Caronte
La struttura hardware alla base del funzionamento del flusso di Caronte è suddivisa in due parti: quella fissa e quella riconfigurabile (figura 1.3). La prima è schematicamente rappresentabile come una tradizionale macchina di VonNeumann controllata da un processore anch’esso interno al chip (soft-processor).
In questa parte si trovano i seguenti componenti: l’Interrupt Controller, l’ICAP
(necessario per leggere da memoria e scrivere nella specifica Black Box i moduli riconfigurabili) e l’IP-Core Manager (IPCM), una sorta di ponte tra il lato
software e il lato hardware. Sempre collocato sulla parte fissa si trova il bus di
comunicazione, tipicamente della famiglia CoreConnect (vedere il capitolo 3).
La parte riconfigurabile, o dinamica, è invece costituita da un insieme di Black
Box. EDK definisce un componente come una qualsiasi parte di un sistema, per
esempio un bus, una periferica o un processore. Da questo punto di vista anche
una Black Box può essere considerata un componente, anche se questo è riduttivo:
in realtà una Black Box è una porzione di FPGA di dimensione fissa che può essere completamente riconfigurata senza interferire con il normale funzionamento
della restante parte del chip, come se fosse un guscio entro il quale collocare i moduli. Dal punto di vista dell’implementazione essa è costituita da due parti: una
interna, e cioè l’IP-Core che costituisce il modulo riconfigurabile, e una esterna,
che fornisce l’interconnessione tra la logica interna e i bus macro.
La modalità di comunicazione all’interno di uno scenario come quello appena
descritto include tre casi: innanzitutto si ha il collegamento tradizionale tra due
moduli fissi tramite un bus, tipicamente CoreConnect OPB; inoltre è necessario
supportare la connessione tra un blocco fisso e uno riconfigurabile, come pure
tra due blocchi entrambi riconfigurabili. Tutto questo considerando il fatto che
nella parte dinamica i collegamenti sono realizzati tramite bus macro, necessari per creare un canale stabile che supporti la riconfigurazione delle Black Box.
Per avere una corretta visione del quadro è utile immaginare di “percorrere” il
collegamento tra un modulo fisso e uno riconfigurabile (figura 1.4): il modulo fisso è dotato di un’interfaccia verso il bus adottato dall’architettura (si considera,
senza perdere generalità, OPB). Una volta raggiunto il “confine” tra parte fissa e
16
CAPITOLO 1. PREMESSE
Figura 1.3: L’architettura hardware di Caronte
riconfigurabile è necessario passare attraverso i bus macro, che fortunatamente,
essendo semplicemente delle linee fisiche presenti sulla FPGA non possiedono un
protocollo di comunicazione, e possono quindi essere semplicemente allacciati ai
segnali OPB. Si deve ora “penetrare” nella Black Box per giungere all’IP-Core:
anche qui sarà sufficiente un semplice mappaggio tra bus macro e segnali entranti
nell’IP-Core: esso è dotato di un interfaccia OPB, in modo da non richiedere la
presenza di un bridge che traduca tra due protocolli di comunicazione differenti.
Per quanto riguarda il collegamento di due moduli riconfigurabili il procedimento
è analogo a prima, con la differenza che in questo caso il punto di partenza è un
IP-Core all’interno di una Black Box, quindi si passa al bus macro e infine ad
un’altra Black Box.
1.1.4.2
Da Caronte a YaRA
L’architettura proposta, pur essendo valida, soffre di alcune limitazioni, soprattutto se utilizzata in un contesto di riconfigurabilità dinamica. La prima di queste
è il fatto che la comunicazione tra moduli fisicamente non contigui sulla FPGA
può avvenire solamente se i moduli che si frappongo tra la sorgente e la desti17
CAPITOLO 1. PREMESSE
Figura 1.4: Collegamento tra un modulo fisso e uno riconfigurabile nell’architettura di
Caronte
nazione ritrasmettono i dati inalterati. Questo problema implica pesanti effetti
sulla riconfigurazione, dato che se uno dei moduli attraverso il quale il canale
di comunicazione deve passare viene riconfigurato, la comunicazione dovrà essere interrotta; ciò rappresenta un collo di bottiglia nelle prestazioni del sistema
e limita il campo di applicazione dove Caronte può essere effettivamente utilizzato. Un altro forte limite sta nel fatto che lo standard CoreConnect imposto da
IBM prevede che per ogni IP-Core istanziato all’interno di un sistema vengano
replicate tutte le linee di bus. In questo modo ogni IP-Core aggiunto occupa ben
più dello spazio necessario al suo effettivo funzionamento e ciò impone un vincolo estremamente restrittivo alla scalabilità del sistema, il quale non potrà essere
composto da un numero elevato di IP-Core.
Per questi motivi è stata creata YaRA (Yet another Reconfigurable Architecture); anche in questo caso il sistema è composto da una parte fissa ed una riconfigurabile ma, a differenza di Caronte, presenta un’infrastruttura di comunicazione
diversa. La nuova architettura si presenta come in figura 1.5.
La parte fissa è suddivisa a sua volta in due sottosistemi. Il primo di questi
adotta un bus di comunicazione di tipo PLB, il quale connette componenti quali un
processore PowerPC, un BRAM Controller per controllare l’accesso alle memorie
BRAM presenti sulla FPGA e l’ICAP. Il secondo sottosistema utilizza invece un
bus OPB, dove sono presenti IP-Core che variano da un particolare sistema all’altro, ma per i quali non è prevista alcuna riconfigurazione (per esempio una porta
seriale). Per collegare queste due parti è presente un bridge tra PLB e OPB. La
18
CAPITOLO 1. PREMESSE
Figura 1.5: L’architettura di YaRA
parte riconfigurabile è dotata di connessioni di tipo Wishbone (sezione 3.2), che è
esente dagli svantaggi che emergono utilizzando il bus OPB.
Il cuore dell’innovazione nel passaggio da Caronte e YaRA è stata la creazione,
all’interno del Laboratorio di Microarchitetture, del componente OPB to Wishbone Bridge che permette il collegamento tra la parte fissa e quella riconfigurabile.
I moduli riconfigurabili devono rispettare alcuni requisiti: devono essere compatibili con il protocollo Wishbone e devono occupare lo stesso numero di CLB2 , che
deve essere necessariamente un multiplo di 8 ed essere scelto in modo da contenere il più grande dei moduli utilizzati dal sistema nelle sue riconfigurazioni.
Queste limitazioni hanno lo scopo di garantire l’intercambiabilità dei moduli per
poterli sostituire senza problemi nel processo di riconfigurazione.
2 CLB:
Configurable Logic Block. Nell’architettura di una FPGA sono i blocchi logici atomici
attraverso i quali viene realizzata la logica combinatoria che si vuole implementare nel dispositivo.
Ogni cella è dotata di ingressi dati e di controllo attraverso i quali può essere riprogrammata
con la funzione logica desiderata. Il numero di CLB è una delle unità di misura per la stima
dell’occupazione di un dato modulo nel chip.
19
CAPITOLO 1. PREMESSE
1.2
Strumenti utilizzati
In questa sezione vengono presentati i software che sono stati utilizzati nello svolgimento del lavoro di tesi. Il primo di questi è Xilinx EDK, che permette la
creazione di sistemi per FPGA; esso è ampiamente utilizzato all’interno del flusso di Caronte e costituisce uno degli ambienti principali di utilizzo degli IP-Core
generati dal IPGen. Successivamente è descritto Xilinx ISE, il quale costituisce
uno strumento di sviluppo e sintesi di architetture hardware, utilizzato in questo
lavoro per la sintesi degli IP-Core generati. L’ultimo software presentato è MentorGraphics Modelsim, che consente di effettuare simulazioni sui componenti implementati; esso è stato indispensabile per effettuare i test di funzionamento dei
componenti creati.
1.2.1
Xilinx EDK
Embedded Development Kit (EDK) [8], prodotto da Xilinx, è un framework composto da numerosi tool che permette di creare un sistema embedded completo
implementabile su una FPGA. EDK permette infatti di realizzare sia l’architettura
hardware del sistema sia la componente software. Dal punto di vista hardware
è necessaria la creazione di una piattaforma embedded che consista di uno o più
processori e moduli (spesso denominati anche periferiche) collegati ad un bus,
adottando perciò un approccio alla progettazione di tipo modulare (sezione 1.1.1);
EDK descrive questa piattaforma hardware in un file MHS (Microprocessor Hardware Specification). Dall’altro lato vi è la realizzazione di una piattaforma software, cioè l’insieme di driver per i moduli ed eventualmente di un sistema operativo per l’architettura creata; questo è descritto in un file MSS (Microprocessor
Software Specification).
L’interfaccia grafica di EDK è XPS (Xilinx Platform Studio), che integra strumenti aventi vario scopo e utilizzo, dalla creazione del sistema hardware alle funzionalità di test e debugging. Con XPS è possibile generare e modificare i file
MPS e MHS, creare una visualizzazione schematica dell’architettura realizzata e
accedere a numerosi tool che compongono la suite EDK I principali sono:
20
CAPITOLO 1. PREMESSE
• Base System Builder (BSB): wizard che permette la facile e veloce creazione
di un sistema funzionante, o la realizzazione di un sistema base personalizzabile per progetti più complessi;
• Platform Generator (Platgen): permette di tradurre la descrizione della piattaforma software in una netlist HDL che può essere implementata su una
FPGA. In particolare invoca XST (mostrato nella sezione seguente) per la
sintesi degli IP-Core utilizzati;
• Create and Import Peripheral Wizard: vedere sezione 2.3;
• Library Generator (Libgen): configura la piattaforma software, comprese le
applicazioni che si vogliono utilizzare, gestendo il file MSS.
Una caratteristica importante di EDK è che, nel costruire un’architettura collegando insieme vari IP-Core, esso non analizza il contenuto di ciascun componente,
ma si interessa solamente dei segnali di Input/Output di ciascuno di essi; in questo
modo è possibile creare dei moduli costituiti solamente dal “guscio” esterno, contenenti un parte della logica di comunicazione, che verranno poi “riempiti” successivamente con IP-Core appropriati. È proprio questa considerazione che sta
alla base della metodologia di riconfigurabilità dinamica presentata nella sezione
1.1.4.
1.2.2
Xilinx ISE
Integrated Software Environment (ISE), anch’esso prodotto da Xilinx, è un insieme di tool che permette di effettuare il design e la sintesi di un’architettura
descritta tramite linguaggi come VHDL (Very high speed integrated circuit Hardware Description Language) o Verilog. Nel seguito ci si riferirà sempre a VHDL
poiché è il linguaggio riconosciuto dal tool presentato in questa tesi, nonostante
gli strumenti Xilinx permettano di utilizzare anche Verilog.
L’interfaccia grafica di questo pacchetto di software si chiama Project Navigator, tramite il quale è possibile accedere a tutte le funzionalità implementative
offerte da ISE. Come si può vedere in figura 1.6, l’area di lavoro è divisa in quattro
21
CAPITOLO 1. PREMESSE
Figura 1.6: Workspace di Project Navigator
settori:
• un editor di testo (riquadro A), in cui è possibile modificare i file sorgenti
del progetto da sintetizzare. Sempre nella stessa finestra possono essere
visualizzati i risultati di sintesi (Design Summary);
• una finestra (riquadro B) in cui è rappresentata la struttura del progetto, in
termini di moduli e librerie utilizzate;
• una finestra (riquadro C) da cui si possono lanciare le funzioni;
• una shell (riquadro D) dove viene visualizzato il log delle operazioni effettuate dal programma.
Le funzioni incluse in ISE sono divise in gruppi, e sono qui di seguito presentate.
Il primo gruppo (Design Utilities) comprende alcune utilità come la chiamata al
simulatore (in questo caso ModelSim, sezione 1.2.3). Si trovano poi le funzionalità
User Constraints, che permettono di impostare dei vincoli prestazionali di spazio
22
CAPITOLO 1. PREMESSE
e di tempo al sistema creato. Il gruppo successivo è Synthesize - XST, necessario per compilare e sintetizzare il codice VHDL. Queste funzionalità utilizzano il
tool XST [9], che, partendo dal VHDL, crea una netlist descritta in un file NGC,
effettuando una mappatura del codice sorgente su una rete logica composta da
blocchi combinatori, sequenziali e interconnessioni tra di essi. Il processo di sintesi è estremamente complesso, e ciò è dovuto in buona parte alla ottimizzazioni
spaziali (area occupata) e temporali (maximum delay time) effettuate. Come si
può vedere nel capitolo 6, queste influenzano in modo determinante le prestazioni
del tool oggetto di questa tesi. Sempre nell’ambito di sintesi XST si trova View
RTL Schematic, che fornisce una visualizzazione schematica dei blocchi logici
che costituiscono il sistema. Un altro gruppo di funzionalità è Implement Design,
che mappa la rete risultante dal processo di sintesi su di una FPGA, il cui modello
e versione vengono decisi a priori.
1.2.3
MentorGraphics ModelSim
ModelSim è uno strumento di editing, simulazione e debug di sistemi hardware
descritti in un linguaggio HDL. Esso permette di simulare il comportamento di
un’architettura hardware visualizzandone numericamente e graficamente il comportamento. L’interfaccia grafica del software [10] consiste di varie finestre che
danno accesso alle varie parti del sistema da simulare e ai numerosi tool disponibili. Si possono effettuare due tipi di simulazione: la simulazione step-by-step,
che permette di procedere un’istruzione alla volta direttamente sul codice sorgente, e la simulazione wave, di più alto livello, che procede in base ad un’unità
temporale definita dall’utente. Quest’ultima modalità è quella che è stata utilizzata nella fase di test di questo progetto, e nel seguito del documento salvo esplicita
specificazione si farà implicitamente riferimento ad essa.
In fase di simulazione, l’interfaccia si presenta come in figura 1.7. Le parti
principali che la compongono sono:
• Workspace (riquadro A): consente un rapido accesso al progetto, permetten23
CAPITOLO 1. PREMESSE
Figura 1.7: Workspace di ModelSim.
do di visualizzare rapidamente la struttura del sistema, le librerie utilizzabili
ed i file VHDL che compongono il progetto;
• Objects (riquadro B): mostra il nome e il valore dei segnali del modulo corrente, ossia quello selezionato nella visualizzazione “struttura” del
Workspace. Da questo pannello si può forzare il valore dei segnali (solitamente quelli di input) e impostare il segnale di clock, per procedere poi alla
simulazione vera e propria;
• Wave (riquadro C): permette di visualizzare i risultati della simulazione.
Questo pannello è suddiviso a sua volta in tre parti
– Pathway Pane: visualizza i segnali e il relativo percorso, partendo dal
livello top dell’architettura;
– Value Pane: visualizza il valore dei segnali all’istante indicato dal
cursore nel Wave pane;
– Wave pane: visualizza graficamente l’andamento temporale dei segnali.
24
CAPITOLO 1. PREMESSE
• Transcript (riquadro D): tiene traccia della history del flusso del programma
e fornisce un’interfaccia da linea di comando.
Si può avviare la simulazione direttamente dal Project Navigator di ISE. A questo
punto è necessario impostare solitamente alcuni segnali, forzandoli al valore desiderato. Inoltre è necessario configurare, se presente, il segnale di clock. Dopo
aver determinato il parametro run length corrispondente alla lunghezza del periodo di simulazione, è possibile procedere, un periodo alla volta, alla simulazione
vera e propria.
25
Capitolo 2
Approcci precedenti
Prima di iniziare a descrivere il software realizzato, si vogliono presentare brevemente alcuni approcci esistenti al problema dell’interfacciamento dei core. Tale
analisi risulta molto utile sotto due punti di vista: innanzitutto essa permette di
pervenire ad una migliore comprensione dei benefici apportati da questo lavoro
nell’ambito della progettazione modulare; in secondo luogo si ottiene una visione
più nitida dello scenario di applicazione, con l’effetto di delineare in modo più
chiaro la collocazione del framework, sia in una dimensione “verticale” (nel flusso di design) che “orizzontale” (all’interno dell’architettura). Si inizia con una
descrizione di OCP Socket e di Interface Adaptor Logic, standard proposti per le
interfacce dei core, per poi passare alla presentazione del tool Import Peripheral
Wizard che fa parte di Xilinx EDK (presentato nella sezione 1.2.1). Si prosegue
con un accenno al framework CoDeveloper sviluppato da ImpulseC. Considerazioni circa la bontà degli approcci presentati e confronti con IPGen verranno
discusse nella sezione 4.4.
2.1
OCP Socket e CoreCreator
L’Open Core Protocol (OCP) [11, 12] è un progetto sviluppato inizialmente dall’organizzazione Virtual Socket Interface Alliance (VSIA), e passato successivamente sotto il controllo di OCP International Partnership (OCP-IP). L’obiettivo
27
CAPITOLO 2. APPROCCI PRECEDENTI
primario di tale progetto è quello di fornire un supporto condiviso per il riuso
degli IP-Cores in sistemi differenti. Il riutilizzo di componenti porta con sé numerosi benefici, primo tra tutti la diminuzione del tempo richiesto nello sviluppo
di un sistema hardware, con un ovvio incremento della produttività.
L’approccio è basato sulla proposta di uno standard per l’interfacciamento dei
core all’interno del sistema ospite. Il Socket OCP è alla base di tale metodologia:
si tratta di un componente di interfacciamento molto flessibile, progettato per essere utilizzato sia da moduli di tipo master che di tipo slave. Esso offre un’ampia
gamma di servizi allo sviluppatore, che può scegliere di utilizzarli o meno tramite
un opportuno file di specifica. Sempre in un’ottica di diffusione su larga scala dello standard proposto, OCP-IP ha sviluppato un bus che si sposa perfettamente con
le caratteristiche del Socket OCP. Ovviamente, se si vuole rendere tale componente effettivamente portabile anche su sistemi che utilizzano una infrastruttura di comunicazione differente, è necessario utilizzare un “bus wrapper”, che implementa
la connessione tra il particolare mezzo trasmissivo e il Socket OCP. Si avranno
dunque numerosi wrapper, uno per ogni infrastruttura di comunicazione. Non è
dunque escluso che ci si possa trovare nella condizione di dovere implementare
personalmente tale componente, in quanto esso potrebbe non esistere. Seguendo
questa metodologia si ottiene dunque un IP-Core stratificato su tre livelli, come
mostrato in figura 2.1. Si noti che è proprio il concetto di stratificazione (layering) che sta alla base di questo approccio: essa permette infatti di disaccoppiare
in modo preciso la funzionalità logica del core dalla connessione con il sistema.
Come detto precedentemente, lo sviluppatore ha la possibilità di scegliere
quali servizi offerti dal Socket OCP utilizzare, sulla base delle caratteristiche del
proprio componente. Tale scelta viene implementata tramite un file di specifica
RTL, che può risultare di difficile implementazione da parte di sviluppatori non
esperti di linguaggio RTL.
Per ovviare a questo problema OCP fornisce un tool denominato CoreCreator, che permette di creare in modo automatico, dopo aver selezionato le opzioni
desiderate, un pacchetto costituente il nuovo IP-Core con Socket OCP integrato.
Questo tool permette anche di validare in modo automatico la compatibilità del
28
CAPITOLO 2. APPROCCI PRECEDENTI
Figura 2.1: Schema dell’IP-Core secondo l’approccio OCP
core con lo standard OCP.
2.2
Interface Adaptor Logic
In [13] e [14] viene descritta una metodologia sostanzialmente molto simile a
quella mostrata nella precedente sezione. Anche in questo caso l’attenzione è focalizzata sul riutilizzo degli IP-Core, obiettivo raggiungibile mediante una rigida
separazione tra interfaccia di comunicazione e logica funzionale. A connettere le
due parti si trova un blocco denominato Interface Adaptor Logic (IAL), che ha il
pregio, a detta degli autori, di essere molto più leggero del Socket OCP. Anche
in questo caso dunque si ha un’architettura strutturata su tre livelli: la connessione con il mezzo di comunicazione (corrispondente al “bus wrapper” di OCP),
il blocco IAL e il core che implementa la funzionalità.
Il modulo IAL ha la caratteristica di presentare un set molto esiguo di porte
per quanto riguarda la connessione “lato core”; meno porte implicano necessariamente meno vincoli da rispettare, e questo è sicuramente un aspetto positivo di
questa interfaccia. Ciò nonostante l’interesse per questo approccio sembra essere
scemato, in quanto attualmente non si trovano corrispondenze reali per quelli che
nei due articoli presi in esame sono presentati come sviluppi futuri, in primis la
29
CAPITOLO 2. APPROCCI PRECEDENTI
creazione di “IAL Generator”, uno strumento software che sarebbe stato in grado
di generare automaticamente un IP-Core completo di interfaccia IAL.
2.3
EDK Create/Import Peripheral Wizard
Uno dei tool che compone la suite EDK (sezione 1.2.1) è Create/Import Peripheral
Wizard [8]. L’obiettivo di tale strumento è quello di aiutare lo sviluppatore nel realizzare IP-Core che siano compatibili con EDK. Si compone, come dice il nome,
di due parti: la creazione di un nuovo componente (create) e l’importazione di un
componente già esistente (import).
Per quanto riguarda la creazione di un nuovo componente, il tool offre un
generatore automatico del template nel quale porre il codice che descrive la funzionalità dell’IP-Core che si vuole creare. Per template si intende la descrizione
dell’IP-Core priva della parte di logica che esprime il comportamento del modulo. Sostanzialmente, riprendendo la figura 1.1, il tool crea automaticamente il
file VHDL che contiene l’istanza dell’interfaccia e della “user logic”. Per quanto concerne quest’ultima, viene generato un secondo file VHDL contenente la
dichiarazione di entity, mentre la parte implementativa (architecture) è vuota ed
è appunto la porzione che va inserita da parte dello sviluppatore. Essendo stato
sviluppato nell’ambito di EDK, che adotta come canali di comunicazione i bus
della famiglia IBM CoreConnect (sezione 3), il tool permette di utilizzare soltanto due interfacce: OPB IPIF e PLB IPIF. Siccome un’interfaccia di tipo IPIF offre
molti servizi, l’utente può scegliere, in fase di creazione del template, quali di
questi servizi utilizzare per il proprio modulo. In questo modo vengono automaticamente impostati i parametri relativi a tali servizi all’interno del file VHDL
che contiene l’istanza dell’interfaccia. Per quanto riguarda il file predisposto a
contenere la logica propria del modulo, esso presenta porte di input/output fisse
(IPIC), e i segnali provenienti da queste devono essere opportunamente trattati
all’interno della logica dell’utente.
La funzione di importazione degli IP-Core, invece, prende in input il codice
VHDL già completo che rappresenta un IP-Core e lo correda di alcuni file che lo
30
CAPITOLO 2. APPROCCI PRECEDENTI
rendono un componente realmente inseribile in un sistema EDK. Sostanzialmente
vengono creati due file:
• Peripheral Analyze Order (PAO), che definisce l’ordine dei file HDL necessari alla sintesi del componente;
• Microprocessor Peripheral Definition (MPD), nel quale si trovano tutte le
porte e i parametri dell’IP-Core importato, in modo che esso sia trattato in
modo corretto da EDK.
Il Create/Import Peripheral Wizard è dunque un utile strumento nell’ambito di lavoro di EDK, in quanto permette di facilitare e velocizzare il flusso di inserimento
di un nuovo modulo all’interno di un sistema. La sua utilità è però molto ridotta
al di fuori di tale ambiente, proprio perché si tratta di uno strumento sviluppato
ad-hoc.
2.4
ImpulseC CoDeveloper
Il framework CoDeveloper [15], prodotto da Impulse Accelerated Technologies,
è una complessa piattaforma di sviluppo che permette di gestire la creazione di sistemi misti hardware e software (hardware-software codesign), sintetizzando una
specifica di alto livello. Questa specifica è implementata in linguaggio C, utilizzando le librerie ImpulseC fornite con il programma. Durante il processo di sintesi
di un componente si può selezionare, tra molte alternative, quale sarà l’architettura ospite, in modo da implementare nel codice VHDL prodotto un’interfaccia
opportuna; per esempio si può scegliere un’interfaccia di tipo OPB IPIF (vedere
capitolo 3). Il punto di forza di questa metodologia sta nel fatto che, generando
essa stessa il codice VHDL da utilizzare come “core”, nel processo di creazione
dell’interfaccia dispone di un set di segnali conosciuti che si collegano in modo meccanico all’insieme dei segnali dell’interfaccia. Complessivamente, questo
framework è uno strumento molto valido che, se utilizzato in modo opportuno,
può produrre un risparmio di tempo notevole nello sviluppo di sistemi integrati
hardware e software.
31
CAPITOLO 2. APPROCCI PRECEDENTI
2.5
Conclusioni
Dopo avere analizzato le caratteristiche di questi approcci, è opportuno sottolinearne pregi e difetti, in modo da fornire un valido sistema di confronto con la
metodologia proposta in questo documento.
OCP Socket è uno standard progettato molto dettagliatamente che ha sicuramente buone possibilità di affermarsi, soprattutto perchè è sostenuto da una reale
organizzazione che si occupa della sua diffusione. Ciò nonostante, affinchè un
core sia effettivamente portabile su sistemi esistenti che non adottano il bus OCP,
è necessario introdurre un ulteriore livello di logica (il bus wrapper) che appesantisce il modulo hardware. Oltre a quanto detto lo strumento di generazione automatica che viene proposto, ovvero CoreCreator, è in grado di generare
l’interfaccia di comunicazione solamente per la connessione al bus OCP.
Interface Adaptor Logic, pur essendo più leggera, soffre degli stessi difetti di
OCP Socket, in quanto anche in questo caso è necessario implementare opportuni
bus wrapper per l’effettiva portabilità dei componenti. Inoltre tale progetto sembra
essere stato abbandonato, siccome non si trovano riferimenti a sviluppi ulteriori.
EDK Create/Import Peripheral Wizard è un tool molto utile per importare core
in un sistema EDK, ma non offre una reale soluzione per l’interfacciamento di
core già esistenti, in quanto si limita a fornire un template per le interfacce OPB
IPIF e PLB IPIF.
Infine, Impulse CoDeveloper rappresenta un framework molto valido per quanto riguarda la sintesi di sistemi a partire da specifiche di alto livello, ed ha il pregio
di supportare numerose infrastrutture di comunicazione. Ciò nonostante, la funzionalità che offre l’interfacciamento automatico è applicabile solamente ai core
generati dal software a partire dalla specifica, i quali presentano un insieme di
porte sempre identico. Poiché si il set di sagnali da gestire è conosciuto a priori,
la creazione dell’interfaccia risulta essere un compito meccanico.
32
Capitolo 3
Infrastrutture di comunicazione
Il software presentato in questo lavoro di tesi ha la finalità di interfacciare i core
dati in input con il resto del sistema nel quale si troveranno ad operare. Per questo
motivo prima di descrivere il framework vengono illustrate le infrastrutture di
comunicazione che IPGen supporta ad oggi.
La prima architettura che viene presentata utilizza il bus OPB (On-chip Peripheral Bus) assieme alle interfacce implementate da Xilinx per rendere più semplice l’interfacciamento dei core con il bus; queste sono due e si chiamano PSelect
e IP-Core Interface (IPIF) nella versione OPB. Successivamente viene data una
breve descrizione del bus Wishbone, il quale fornisce la stessa funzionalità del
precedente, ma a differenza di questo non presenta delle interfacce già sviluppate
da terzi per facilitarne l’uso. Esso fornisce infatti un protocollo di facile utilizzo, e
una logica per gestire la comunicazione molto meno complessa da implementare.
Sono state scelte queste particolari architetture in quanto, come visto nella
sezione 1.1.4, OPB viene utilizzato nel flusso di Caronte, mentre Wishbone in
quello di YaRA. Questo permette al software di essere adottato fin da subito come
parte integrante di questi due flussi, mostrandone le potenzialità in un contesto che
mira al maggiore automatismo ottenibile in fase di progettazione hardware. Nel
capitolo 5 viene spiegato come IPGen possa essere ampliato al fine di contemplare
sempre più infrastrutture.
33
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
3.1
IBM CoreConnect OPB
La progettazione modulare dello hardware, sezione 1.1.1, permette di ottenere sistemi composti da tanti moduli ognuno con funzionalità proprie e ben distinte. Un
sistema nel quale tutti questi componenti vengono integrati all’interno dello stesso chip viene chiamato System-on-Chip (SoC) [16]. In uno scenario come questo
sorge l’esigenza di una infrastruttura di comunicazione che sia efficiente e permetta in modo relativamente semplice di connettere tra di loro componenti le cui
funzionalità sono state sviluppate separatamente le une dalle altre. CoreConnect
[17] è un’architettura realizzata da IBM composta da tre bus e dai loro protocolli
di comunicazione, che ha lo scopo di fornire un’infrastruttura di comunicazione
tra i vari moduli di un SoC. I tre bus che compongono l’architettura sono:
• Processor Local Bus (PLB): bus a 64 bit pensato per dispositivi che necessitano di prestazioni elevate e bassa latenza, utilizzato prevalentemente per
connessioni dirette al processore, che può essere PowerPC o Microblaze;
• On-Chip Peripheral Bus (OPB): bus a 32 bit utilizzato per sgravare il PLB
da una parte del traffico dati e per evitare colli di bottiglia nel sistema. Viene
utilizzato comunemente per applicazioni con minori necessita prestazionali.
• Device Control Register (DCR): bus sussidiario utile a ridurre il carico dei
due bus precedenti.
Il bus supportato da IPGen ed utilizzato in Caronte è OPB. Le caratteristiche
fondamentali di questo bus sono [18, 19]:
• Un protocollo completamente sincrono con 32 bit dedicati al bus dati e
altrettanti per il bus indirizzi;
• Dimensione del bus dinamica per permettere trasmissioni di dati inferiori a
32 bit (byte steering);
• Un protocollo che consente l’invio di segmenti sequenziali di dati (burst);
• Supporto per più di un OPB Master contemporaneamente.
34
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.1: Set di segnali visti all’interfaccia con un componente slave
In figura 3.1 è mostrato il set di segnali visti all’interfaccia di un componente di
tipo slave, per i quali il framework garantisce l’interfacciamento. Si precisa che
tali segnali sono da considerarsi attivi alti e, secondo la specifica del bus, devono
essere campionati sul fronte di salita del clock.
Vengono ora spiegate le funzionalità di questi segnali (tra parentesi quadre
verrà indicata la larghezza in bit dei segnali).
• Segnali in ingresso nel componente.
– OPB_Clk [1]: segnale di clock;
– OPB_Rst [1]: segnale di reset;
– OPB_Abus [32]: bus indirizzi, contiene l’indirizzo del registro sul
quale si vuole effettuare un’operazione di lettura/scrittura; l’indirizzo
presente sul bus è da considerarsi valido solo se il segnale OPB_select
è attivo;
35
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
– OPB_BE [4]: segnale Byte Enable che permette la trasmissione di
particolari byte di dati presi da un registro, quando non è necessaria la
trasmissione dell’intero registro;
– OPB_DBus [32]: bus dati in scrittura comandato dal master, il contenuto del bus rimande valido finché il master non riceve il segnale di
acknowledgement di scrittura avvenuta con successo;
– OPB_RNW [1]: segnale Read Not Write, ha lo scopo di indicare la
direzione del trasferimento dati in corso; se il segnale è posto a 1 il
Master sta compiendo un’operazione di lettura sullo slave, al contrario
se è posto a 0 è in corso un’operazione di scrittura;
– OPB_Select [1]: segnale di select, indica che vi è un trasferimento
in corso lungo la linea dati; inoltre valida il contenuto dei segnali
OPB_ABus, OPB_BE, OPB_RNW e OPB_seqAddr. Rimane attivo finchè il master non riceve un segnale di acknowledgement o di
transfer retry;
– OPB_seqAddr [1]: segnale di trasferimento sequenziale, indica allo
slave che il trasferimento successivo avverrà nella stessa direzione e
sull’indirizzo successivo all’attuale. Questo segnale non implica l’utilizzo del protocollo “burst”. Questa modalità di comunicazione, che
non verrà approfondita in questo testo, è utile per l’invio in cicli di
clock successivi di uno stesso dato più grosso della capacità del bus e
quindi spezzato in pacchetti più piccoli.
• Segnali uscenti dal componente (il prefisso “<Sln>_” indica l’appartenenza
del segnale ad un generico slave):
– <Sln>_DBus [32]: bus dati in lettura comandato dallo Slave, il contenuto rimane valido finchè il segnale <Sln>_xferAck non viene sollevato e riportato a 0;
– <Sln>_xferAck [1]: segnale OPB Transfer Acknowledge, sollevato
dallo slave per indicare il completamento di un’operazione di comunicazione tra il master e lo slave. Esso rimane attivo per un ciclo di
36
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
clock per ogni operazione da notificare. Nel caso di un’operazione di
scrittura significa che lo slave ha correttamente accettato il dato, nel
caso di lettura significa che lo slave ha posto sul bus dati in uscita il
dato richiesto dal master. Inoltre questo segnale deve essere attivato
non oltre 16 cicli di clock dal momento in cui OPB_select viene posto
a 1, altrimenti questo ritardo verrà interpretato come timeout;
– <Sln>_retry [1]: segnale di retry, viene utilizzato per indicare una
situazione in cui lo slave temporaneamente non può portare a termine
un’operazione I/O richiesta dal master. È un segnale molto utile nella
prevenzione di possibili deadlock nell’arbitraggio del bus;
– <Sln>_toutSup [1]: segnale con il quale viene indicata l’impossibilità
di effettuare un’operazione richiesta dal master prima dello scadere
dei 16 cicli di clock dall’attivazione di OPB_select. Il segnale deve
rimanere a 1 finchè l’operazione prorogata non viene completata;
– <Sln>_errAck [1]: segnale utilizzato per notificare al master un errore
di lettura o scrittura.
Oltre ai segnali elencati, possono essere utilizzati dei segnali opzionali che dipendono dalla funzionalità specifica del modulo, un esempio di tali segnali sono quelli
di interrupt.
3.1.1
OPB PSelect
La prima interfaccia implementata da Xilinx che viene descritta è OPB PSelect.
Essa consiste in un unico file (pselect.vhd) che svolge la sola funzione di Address
Decoding Logic, ovvero gestisce semplicemente la codifica degli indirizzi corrispondenti ai registri del componente dove il Master del bus andrà a leggere o
scrivere. Per questo motivo viene utilizzata assieme a core che non hanno esigenze particolari quali gestione di interrupt e di registri con dimensione differente da
32 bit.
Si spiega il comportamento del’interfaccia PSelect analizzando i suoi generic,
ovvero le costanti che possono essere impostate dal progettista secondo le esi37
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
genze della funzionalità del core, e i suoi segnali di I/O. I generic di pselect.vhd
sono:
• C_AB: generic di tipo intero che identifica il numero dei bit più significativi
del bus indirizzi; questi bit sono identificativi del modulo slave mentre i
rimanenti corrispondono ai registri presenti all’interno di uno slave. Da ciò
si deduce che aumentando il numero dei bit significativi si diminuisce lo
spazio da dedicare ai registri interni.
• C_AW: generic di tipo intero corrispondente alla larghezza dal bus indirizzi
in numero di bit. Questo valore per OPB deve essere sempre uguale a 32;
• C_BAR: generic di tipo std_logic_vector che indica il base address del componente, se i bit dell’indirizzo chiamato dal master identificati dal C_AB
corrispondono ai bit del C_BAR, anch’essi identificati dal C_AB, allora
significa che il master ha chiamato proprio il componente al quale la pselect
appartiene, in questo caso viene posto ad 1 il segnale PS.
Di seguito vengono descritti i segnali:
• A: segnale di input avente la stessa larghezza del bus indirizzi (C_AW),
questo segnale dovrà essere connesso al segnale OPB_ABus;
• Avalid: segnale in input da un bit che dovrà essere connesso con il segnale
OPB_select;
• PS: segnale in output da un bit chiamato Peripheral Select, per la descrizione
vedere il generico C_BAR.
Se il componente da interfacciare richiede una maggiore varietà e complessità di servizi offerti, questa logica di decodifica indirizzi risulterà scomoda ed
incompleta, pertanto si dovrà ricorrere OPB IPIF, descritta nella prossima sezione.
38
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.2: Schema dei servizi e dei segnali IPIF
3.1.2
OPB IPIF
Xilinx, oltre a PSelect, ha sviluppato OPB IPIF (IP-Core Interface) [20], un’interfaccia più completa che offre una codifica degli indirizzi maggiormente comoda
e funzionale, e molti servizi aggiuntivi che PSelect non fornisce. In figura 3.2 si
può vedere uno schema che identifica i vari servizi di cui IPIF è composta, oltre
ai suoi vari segnali sia lato core che lato bus. Mediante l’uso dei generic è data
possibilità allo sviluppatore di attivare o disattivare una parte di questi servizi a
seconda delle necessità dell’IP-Core che si vuole interfacciare; in questo caso il
valore di tali generic è assegnato in modo automatico da parte di IPGen. La parte
dell’interfaccia che rappresenta l’insieme dei segnali direttamente connessi al core
viene chiamata IP-Core InterConnect (IPIC).
39
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
3.1.2.1
I Servizi
Prima di analizzare in dettaglio il meccanismo di codifica degli indirizzi ed il significato dei vari segnali IPIC, viene fornita una panoramica dei vari moduli che
compongono l’interfaccia. L’elemento base di IPIF è lo Slave Attachment; esso è infatti il responsabile della mediazione diretta tra il bus e IPIC, gestisce il
protocollo di comunicazione con OPB e fornisce le porte di I/O per tutti i segnali indispensabili alla comunicazione con il bus. Un servizio opzionale interno allo Slave Attachment è il Burst Support, il quale permette di utilizzare una
modalità di trasferimento dati che consente velocità elevate con accesso a indirizzi
sequenziali.
Un secondo componente è il Byte Steering, che permette la trasmissione in
entrambe le direzioni di dati con una larghezza inferiore di quella del bus (32
bit). Grazie a questo componente possono essere letti o scritti solo alcuni byte
dei registri interessati grazie alla sua capacità di instradare questi blocchi nelle
corrette byte lanes del bus.
Oltre a questi due servizi, presenti in ogni configurazione di IPIF, vi sono i
servizi opzionali. Fa parte di questo gruppo il servizio Hardware/Software Reset.
Esso è aggiuntivo rispetto al normale evento di reset sollevato quando il segnale OPB_Rst viene reso attivo, infatti permette un reset dell’IP-Core eseguito dal
processore via software, scrivendo un particolare valore chiave all’interno del registro dedicato a questo particolare servizio. Inoltre H/S Reset è accompagnato
dall’istanziazione di un particolare registro chiamato MIR (Module Information
Register) contenente le informazioni indicanti la configurazione di default del modulo; tramite questo registro l’IP-Core può essere riportato in uno stato di partenza
“sicuro” prestabilito dal progettista.
Un’altra funzionalità che può essere attivata riguarda la gestione degli interrupt. L’Interrupt Service Controller mette a disposizione un componente che
è in grado di ricevere le varie richieste di interrupt, sia da parte del core che
dall’interfaccia stessa, e di collassarle in un unico segnale che verrà portato a
OPB.
Infine vi sono i servizi di Write FIFO e Read FIFO. Questi vengono utilizzati
40
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
quando l’IP-Core necessita di “bufferizzare” i dati, e possono essere attivati indipendentemente l’uno dall’altro a seconda delle direzioni (lettura/scrittura) nelle
quali vi è la necessità di un buffer.
IPGen è in grado di sfruttare l’address decoding di IPIF insieme a tutte le sue
funzioni di base; tra i possibili sviluppi futuri del software vi è il pieno supporto ai restanti servizi di IPIF. Si noti comunque che alcuni di questi servizi vengono implementati automaticamente da porzioni di logica generate dal software.
Per esempio esso è in grado di gestire segnali con dimensioni maggiori di 32 bit
tramite un particolare protocollo descritto dettagliatamente nella sezione 5.3.5. Il
motivo di queste scelte è da ricercare nel fatto che spesso i servizi messi a disposizione da IPIF comportano un overhead non trascurabile e la gestione di essi
risulta in molti casi molto macchinosa.
3.1.2.2
Decodifica degli indirizzi
IPIF gode di un sistema di decodifica degli indirizzi che rende molto agevole l’identificazione dei vari registri all’interno di un core per operazioni di lettura e
scrittura. Poiché l’interfaccia deve essere flessibile e potersi integrare a qualsiasi
tipo di core, questa decodifica avviene raggruppando i vari registri interni al core
in Address Ranges ognuno dei quali ha delle proprietà ben definite che coinvolgono tutti i registri appartenenti ad uno stesso range. IPIF è in grado di trattare
adeguatamente i diversi “range” poiché questi vengono definiti in apposite Address Range Definitions. Queste vengono dichiarate all’interno di un set di cinque
array di generic caratterizzati dal prefisso “C_ARD”:
• C_ARD_ID_ARRAY: array che associa un numero intero di identificazione
ad ogni address range;
• C_ARD_ADDR_RANGE_ARRAY: in questo array vengono dichiarati, a
coppie, il base address e l’high address di ogni address range;
• C_ARD_DWIDTH_ARRAY: qui viene specificata la dimensione dei singoli registri appartenenti allo stesso address range, ovviamente tutti i registri di uno stesso address range avranno la stessa dimensione. Grazie a
41
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
queste informazioni IPIF sarà in grado di operare byte steering su registri di
dimensione inferiore a quella del bus OPB;
• C_ARD_NUM_CE_ARRAY: la codifica di indirizzi di IPIF permette di assegnare un Chip Enable (CE) per ogni registro di un address range. Questo
rappresenta una caratteristica molto utile nell’interfacciamento di un core
in quanto, come descritto nel prossimo paragrafo, permette una gestione dei
registri più semplice e intuitiva;
• C_ARD_DEPENDENT_PROPS_ARRAY: in questo array vengono dichiarate
proprietà dei registri che dipendo dal particolare tipo di address range di
appartenenza.
È importante sottolineare che l’impostazione di questi parametri all’interno di
IPIF viene svolta in automatico da IPGen. Il risultato di questa decodifica viene
propagato al core attraverso alcuni dei segnali uscenti da IPIC, che viene descritto
nel paragrafo seguente.
3.1.2.3
IPIC
IPIC è la parte dell’interfaccia rivolta verso il core; attraverso i suoi molteplici
segnali permette al core di comunicare con l’interfaccia e quindi con il bus. Di
seguito sono mostrati brevemente i segnali più importanti.
• Segnali in uscita da IPIC:
– Bus2IP_Clk: segnale che trasmette il clock di sistema dal bus al core;
– Bus2IP_Reset: segnale che trasmette al core il segnale di reset di
sistema;
– Bus2IP_Data: bus dati in scrittura sui registri del core, la grandezza è
variabile e dipende da come è stata impostata l’interfaccia;
– Bus2IP_Addr: di grandezza 32 bit, è una copia esatta dell’indirizzo
che arriva ad IPIF tramite il bus indirizzi di OPB;
42
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
– Bus2IP_RNW: questo segnale identifica se un’operazione è di scrittura (0) o di lettura (1);
– Bus2IP_CS: la grandezza di questo segnale dipende dal numero di
voci presenti nell’array di generic C_ARD_ID_ARRAY ed ha la funzione di abilitare un address range per permettere di effettuare operazioni su di esso.
– Bus2IP_RdCE: la grandezza in questo caso rappresenta il numero totale di registri di tutto il dispositivo; vi sarà al più un 1 e rappresenta il
registro sul quale verrà effettuata l’operazione di lettura;
– Bus2IP_WrCE: identico al precedente, utilizzato per le operazioni di
scrittura;
• Segnali in ingresso ad IPIC:
– IP2Bus_IntrEvent: segnale con grandezza dipendente dal numero di
interrupt che sono stati dichiarati, tramite un apposito generic, e che
l’Interrupt Service Controller è stato eventualmente predisposto a gestire;
– IP2Bus_Data: bus dati in lettura dei registri del core, la dimensione
viene fissata a priori nel momento in cui viene configurata l’interfaccia;
– IP2Bus_Ack: segnale di acknowledge, per una transazione di scrittura,
il dato viene considerato correttamente scritto quando il clock è sul
fronte di salita e questo segnale è attivo;
– IP2Bus_Retry: questo segnale è reso attivo quando l’IP-Core non è
stato in grado di completare un’operazione e chiede che essa venga
riproposta da parte del Master;
– IP2Bus_Error: segnale che, se posto ad 1, indica un errore verificatosi
durante l’operazione corrente;
43
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Oltre ai segnali sopra elencati vi sono set di segnali per la gestione dei registri
Read FIFO e Write FIFO e per il supporto del protocollo di Burst, questi segnali ed
i relativi servizi non sono attualmente supportati da IPGen e rientrano nei possibili
sviluppi futuri del tool.
3.1.2.4
Modalità di utilizzo
IPIF, ed in particolare la sua logica di decodifica degli indirizzi, può essere sfruttata dal progettista seguendo due modelli o modalità di utilizzo. Il primo di questi
modelli si chiama Register Model. Il progettista opta per questo modo d’uso
quando vuole utilizzare appieno la logica di decodifica offerta dall’interfaccia e
prevede, come descritto sopra, l’assegnamento ad ogni registro interno al core di
un bit di Chip Enable (CE) che lo identificherà univocamente. In questo caso
le operazioni sul core vengono pilotate dai segnali Bus2IP_CE, Bus2IP_RdCE e
Bus2IP_WrCE a seconda della tipologia di registro utilizzato in un dato momento. Vi possono essere registri di sola lettura, di sola scrittura o entrambe. IPGen è
stato programmato per fare uso di questa modalità per la gestione dei registri.
La seconda modalità si chiama Memory Model o SRAM Model. In questo caso
si fa uso della codifica tramite Chip Select (CS); l’informazione data da tale segnale, che identifica gli address range e non più i singoli registri, deve essere accompagnata dall’informazione sul tipo di operazione da effettuare (lettura/scrittura) e
dai bit di indirizzo per identificare il punto nell’address range dove effettuare l’operazione. Questo secondo modello è più di “basso livello” e, pur avendo il pregio
di lasciare più libertà d’azione nello spazio degli indirizzi, si presta meno ad essere automatizzato rispetto al precedente, quindi il suo utilizzo nel framework è
stato scartato prediligendo il register model.
3.2
Wishbone
Viene analizzata ora il secondo tipo di infrastruttura, costituita dal bus Wishbone
e dai suoi protocolli [21]. Questo bus è stato implementato da Silicore per fornire
un canale di comunicazione ai vari moduli di un SoC, e così come il precedente ha
44
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.3: Le interfacce Wishbone lato master e lato slave
il grande pregio di essere di dominio pubblico e di poter quindi essere utilizzato
nel design di circuiti integrati senza l’obbligo di pagarne la licenza d’uso. Un altro
punto di forza di Wishbone sta nella sua semplicità d’uso, infatti non sono state
sviluppate delle interfacce dedicate, come per OPB, proprio perché non ve ne è
la necessità. E’ stato definito da Silicore uno standard per l’utilizzo di questo bus
che descrive in dettaglio il modo in cui i componenti devono essere interfacciati,
il protocollo per lo scambio di informazioni tra master e slave, e quattro tipologie
di modalità di interconnessione tra master e slave. Vengono dapprima descritti
i segnali di interfaccia del master e dello slave e a seguire le varie tipologie di
connessione.
3.2.1
Le interfacce
Vi sono due tipologie di interfaccia, una per il componente master ed una per lo
slave, queste devono essere adottate da tutti i componenti del sistema che fa uso di
Wishbone. Le due interfacce sono molto simili la tra di loro, dato che si differenziano solamente per la direzione dei segnali che le compongono. In figura 3.3
sono indicati i vari segnali; con il prefisso “_I” vengono indicati i segnali entranti,
mentre con “_O” quelli uscenti. Di seguito vengono descritti questi segnali dal
punto di vista del master:
45
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
• RST_I: segnale di reset del sistema, se sollevato indica al componente di
ritornare al suo stato iniziale;
• CLK_I: clock di sistema;
• ADR_O: rappresenta il bus indirizzi di Wishbone; può avere dimensione
variabile fino ad un massimo di 32 bit e viene utilizzato dal master per
indicare al sistema il registro di un particolare slave;
• DAT_I: bus dati da 32 bit, in ingresso;
• DAT_O: bus dati da 32 bit, in uscita;
• WE_O: segnale Write Enable, indica se l’operazione corrente è di scrittura
o di lettura. Segnale alto indica scrittura da parte del master su un registro
di uno slave, mentre segnale basso indica lettura da registro.
• SEL_O: indica quali dei byte che compongono il bus dati sono da considerarsi validi. Poiché il bus dati ha grandezza 4 byte, questo segnale è
costituito da 4 bit, uno per ogni byte selezionabile;
• STB_O: segnale sollevato indica che tutti i segnali di controllo sono pronti
e stabili. Da questo momento può iniziare una fase di lettura o scrittura;
• ACK_I: indica la fine di un processo completato correttamente da parte
dello slave;
• ERR_I: indica un malfunzionamento dello slave con conseguente esito negativo di un’operazione;
• RTY_I: se posto ad 1 lo slave non è temporaneamente disponibile, il master
dovrà ricontattarlo in un secondo momento;
• CYC_O: indica l’inizio di un ciclo di controllo da parte del master.
Non viene fornito l’elenco dei segnali slave poiché è identico a meno dei versi di
I/O. Fanno eccezione a questa regola i segnali di clock e reset, essendo entranti
per entrambe le interfacce.
46
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
3.2.2
Protocollo di comunicazione
I segnali sopra citati vengo utilizzati seguendo un protocollo di comunicazione, di
questo protocollo vengono mostrate le parti fondamentali, ovvero i cicli di lettura
da slave e scrittura su slave.
• Ciclo di lettura:
1. Il master pone ad 1 il segnale CYC_O, in questo modo prende il
controllo del bus;
2. Pone sul bus indirizzi ADR_O l’indirizzo dello slave interessato dal
ciclo di lettura, contemporaneamente pone a 0 il segnale WE_O;
3. Solleva STB_O ad indicare che tutti i segnali sono correttamente impostati e stabili, l’operazione di lettura può avere inizio;
4. Lo slave indirizzato precedentemente controlla che i segnali CYC_I e
STB_I siano alti, scrive sul bus dati in uscita DAT_O il dato richiesto,
che verrà letto dal master dal proprio ingresso DAT_I;
5. Lo slave innalza ACK_O;
6. Quando il master rileva su ACK_I il segnale di acknowledgement durante il seguente fronte di salita del clock legge il dato presente su
DAT_I;
7. Il master abbassa CYC_O e STB_O;
8. Quando lo slave rileva il passaggio a 0 dei segnali abbassati al punto
precedente, pone il proprio ACK_O a 0.
• Ciclo di scrittura:
1. Il master pone ad 1 il segnale CYC_O, in questo modo prende il
controllo del bus;
2. Pone sul bus indirizzi ADR_O l’indirizzo dello slave interessato dal
ciclo di scrittura, contemporaneamente pone a 1 il segnale WE_O e
scrive il dato da trasmettere su DAT_O;
47
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.4: Schema della connessione “Data Flow”
3. Solleva STB_O ad indicare che tutti i segnali sono correttamente impostati e stabili, l’operazione di scrittura può avere inizio;
4. Lo slave indirizzato aspetta che i segnali CYC_I e STB_I vengano
alzati, successivamente legge il dato su DAT_I;
5. A questo punto lo slave pone ACK_O ad 1;
6. Riconosciuto l’ack, il master tiene il dato sul bus dati fino al successivo
fronte di salita del clock;
7. Il master abbassa CYC_O e STB_O;
8. Quando lo slave rileva il passaggio a 0 dei segnali CYC_O e STB_O,
abbassa il proprio segnale di ack.
3.2.3
Tipi di connessione
I vari componenti di un SoC possono essere connessi, tramite Wishbone, seguendo
quattro modalità di connessione. La scelta tra le varie tipologie dipende dalla
complessità del sistema e dagli IP-Core presenti al suo interno. Segue una breve
descrizione di questi tipi di connessione in ordine di complessità.
• Point to Point: questa è la connessione più semplice e consiste in un collegamento punto a punto tra un solo master con un solo slave. La semplicità
di questo sistema fa si che non sia richiesta nè un logica di decodifica degli
indirizzi nè un meccanismo di collision detection sul bus.
48
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.5: Schema della connessione “Shared Bus Interconnection”
• Data Flow: sfrutta il principio della connessione punto a punto precedentemente illustrato, ma in questo caso è consentito collegare una serie di
IP-Core contenenti una coppia Master-Slave in cascata tra di loro. Questa
configurazione, mostrata in figura 3.4, è molto utile in applicazioni dove un
flusso di informazioni deve subire molte elaborazioni successive, ognuna
delle quali necessita dell’output della precedente. In questo caso vi è la necessità di una semplice logica di decodifica di indirizzi per indirizzare i dati
al componente corretto.
• Shared Bus Interconnection: questo scenario rispecchia la configurazione
più tipica di interconnessione, ovvero il bus condiviso tra i vari componenti (figura 3.5), ovviamente è obbligatoria la presenza di una logica di
decodifica di indirizzi e di un sistema di collision detection.
• Crossbar Interconnection: si tratta della tipologia più complessa di connessione. Anziché avere un unico bus condiviso, permette la comunicazione
tra differenti coppie master-slave contemporaneamente tramite una rete di
49
CAPITOLO 3. INFRASTRUTTURE DI COMUNICAZIONE
Figura 3.6: Schema della connessione “Crossbar Interconnection”
connessioni tra componenti e degli switch che fisicamente allacciano e sganciano le linee di comunicazione tra di loro. Una possibile combinazione
viene mostrata in figura 3.6.
Tra le varie alternative proposte, il framework fa uso della Shared Bus Interconnection. Per sfruttare la condivisione del bus, l’interfaccia generata da IPGen
contiene una logica di decodifica degli indirizzi che permette di rilevare la volontà del master di effettuare un’operazione sull’IP-Core, oltre ad identificarne un
particolare registro.
L’architettura che fa uso di questo tipo di connessione deve avere uno spazio
di indirizzamento ad 8 bit di cui: i primi 3 da sinistra costituiscono il Core Address mentre i restanti 5 compongono il Register Address. Da ciò si deduce che
potranno essere istanziati un massimo di 8 core nel sistema e ciascun core avrà
non più di 32 registri. La logica di decodifica confronta il Core Address con i 3
bit più significativi del base address dell’IP-Core, se questi coincidono significa
che il master vuole interagire con l’IP-Core. A questo punto viene identificato il
corretto registro confrontando i bit del Register Address con gli indirizzi assegnati
a ciascuna porta del core.
50
Capitolo 4
Metodologia
Questo capitolo ha la finalità di fornire una descrizione di IPGen dal punto di vista
metodologico. Nel paragrafo seguente vengono spiegate le motivazioni che hanno
spinto alla creazione di un software per l’interfacciamento automatico, assieme
agli obiettivi preposti alla sua realizzazione. Successivamente è mostrato come
IPGen si possa collocare in un contesto più ampio, costituito dal workflow di
Caronte (sezione 1.1.4). Dopo aver descritto in dettaglio la struttura degli IPCore generati, illustrandone i vari componenti, viene descritto il procedimento
metodico che il programma compie per passare dall’input dell’utente al risultato
finale. Il capitolo si conclude con un confronto tra la metodologia proposta da
questo lavoro e quelle adottate dagli approcci precedenti (sezione 2) al problema
dell’interfacciamento automatico, evidenziando differenze, analogie e possibili
integrazioni.
4.1
Motivazioni
Il processo di realizzazione di un sistema hardware richiede lo sviluppo di molti
prototipi prima di poter arrivare ad un risultato soddisfacente e quindi ad un sistema che può essere messo sul mercato. La fase di progettazione quindi può far si
che il time-to-market del prodotto si allunghi notevolmente, con un conseguente
ritardo per chi lo dovrà commercializzare o utilizzare per attività di ricerca. Buona
51
CAPITOLO 4. METODOLOGIA
parte del tempo impiegato nello sviluppo di un prototipo deriva dal problema di far
comunicare i componenti costituenti il sistema complessivo tra di loro mediante
un’opportuna infrastruttura di comunicazione, per esempio un bus.
L’interfacciamento dei moduli è una fase molto ripetitiva e poco creativa per
il progettista, il quale ha come principale obiettivo lo sviluppo di un componente
in quanto risolutore di un problema o comunque esecutore di una preposta funzionalità. Da questo punto di vista l’interfacciamento risulta essere un problema con
il quale ci si deve per forza confrontare, ma costituisce un collo di bottiglia nel
processo di sviluppo di un sistema hardware. Essendo esso però molto ripetitivo
è un’operazione che può essere automatizzata.
Ogni singolo componente di un’architettura è un IP-Core nel quale, come visto
nella sezione 1.1.2.2, possono essere ben distinte la parte funzionale, il core, e la
parte costituente l’interfaccia verso il resto del sistema. Se ci fosse un meccanismo
che, dato il core, riuscisse a creare l’interfaccia in modo automatico, il tempo
speso da parte del progettista nell’implementazione di questa verrebbe azzerato.
Questo è l’intento di IPGen.
Grazie a questo strumento il progettista può implementare la sua funzionalità senza curarsi della tipologia di architettura nella quale andrà ad inserirsi il
suo componente finale. In questo modo viene aumentato il grado di riusabilità di
un core, in quanto esso potrà essere inserito e riutilizzato in una molteplicità di
sistemi differenti. Esso rimarrà sempre inalterato, sarà la parte relativa all’interfacciamento ad essere rigenerata ogni volta in modo automatico dal software, in
base alle necessità e alle scelte progettuali riguardanti l’architettura ospite. Tutto
questo senza perdite di tempo da parte del progettista.
4.1.1
IPGen nel flusso di Caronte
IPGen ha un ruolo fondamentale nel flusso di Caronte, essendo necessario durante
la fase di generazione delle Foto Statiche (HW-SSP, vedere sezione 1.1.4). Questo
processo può essere completamente automatizzato tramite due fasi, descritte in
figura 4.1:
52
CAPITOLO 4. METODOLOGIA
• IPGen Phase. In questa fase viene utilizzato IPGen, che prende i singoli core e li trasforma in IP-Core aggiungendovi l’interfaccia opportuna
e rendendoli quindi pronti ad essere inseriti in una Static Photo.
• EDK System Creator Phase. EDK System Creator [22] è uno strumento sviluppato all’interno del Politecnico di Milano che permette di inserire
un IP-Core in un’architettura compatibile con EDK in modo automatico.
Questo programma riceve in ingresso l’IP-Core da inserire e il sistema
nel quale verrà integrato, assieme ad un file di configurazione contenente
gli indirizzi fisici che determinano l’allocazione dell’IP-Core sulla FPGA.
Fondamentalmente EDK System Creator esegue due operazioni:
– importa l’IP-Core settando tutti i parametri in modo tale che esso possa
essere trattato come un componente EDK;
– inserisce l’IP-Core nell’architettura ricevuta in input dal programma.
In questo caso il sistema ospite è costituito da un’architettura come quella
descritta nella sezione 1.1.4.1, le cui black box sono completamente vuote,
denominato EDK general system. Grazie ad un opportuno file di configurazione contenente le informazioni sulle varie HW-SSP da generare, è
possibile rendere la creazione di queste ultime completamente automatica.
Come si può notare l’uso congiunto di IPGen e EDK System Creator permette di ottenere un rilevante risparmio di tempo grazie ad un elevato automatismo
dell’intero processo.
4.2
Struttura dell’IP-Core generato
Nonostante la struttura di un IP-Core generato da IPGen cambi a seconda del tipo
di bus con il quale esso viene interfacciato, il principio base comune è quello
di incapsulare il core dato in input dall’utente all’interno di un componente più
grande che lo istanzi assieme alla logica di interfacciamento.
53
CAPITOLO 4. METODOLOGIA
Figura 4.1: Flusso di creazione delle HW-SSP
Come si può osservare da un confronto tra le figure 4.2 e 4.3, poiché OPB
richiede l’istanziazione di un’interfaccia che è un vero e proprio componente diverso rispetto al core di partenza, vi saranno due livelli di incapsulamento nell’IPCore generato in output, mentre per quanto riguarda il bus Wishbone ne avremo
soltanto uno. Viene ora fornita una descrizione di queste due diverse strutture
partendo dal livello più basso fino ad arrivare al top level.
4.2.1
Core
Esso è l’input fornito dall’utente ad IPGen e rappresenta il cuore del componente,
ovvero la funzionalità che esso svolge. Nel core si trovano i registri e la logica atti
ad espletare la funzionalità propria del componente, senza riferimenti all’infrastruttura di comunicazione. Proprio per questo esso è la parte riusabile dell’IP-Core
in quanto è indipendente dal sistema nel quale verrà inserito. Per quanto detto non
vi è alcuna differenza strutturale tra i core in figura 4.2 e 4.3.
54
CAPITOLO 4. METODOLOGIA
Figura 4.2: Struttura di un core interfacciato con OPB
Figura 4.3: Struttura di un core interfacciato con Wishbone
55
CAPITOLO 4. METODOLOGIA
4.2.2
Stub
Questo componente viene generato separatamente dalla struttura dell’IP-Core solo in caso di interfacciamento OPB; nel caso Wishbone le funzionalità presenti in
questo livello vengono integrate all’interno del top level. La necessità di questo
componente aggiuntivo nasce dal fatto che la connessione con OPB richiede l’uso di un’interfaccia complessa che è un componente a parte rispetto alla logica contenuta nel core. Lo Stub permette al core e all’interfaccia di comunicare
correttamente; in particolare esso istanzia il core e fornisce la logica che consente di sfruttare i segnali IPIC (vedi sezione 3.1.2.3) per effettuare le procedure di scrittura, lettura, sollevamento di interrupt ed elaborazione dei segnali
di acknowledgement.
Esso si comporta come un demultiplexer per i segnali provenienti dal sistema verso il core e come un multiplexer per i segnali diretti nel verso opposto;
questo comportamento viene ottenuto mappando opportunamente le linee dati in
ingresso/uscita sulle porte del core utilizzando i segnali derivanti dalla decodifica degli indirizzi attuata dall’interfaccia, ottenendo in questo modo un corretto
indirizzamento nei vari registri.
4.2.3
IP-Core
Con il termine IP-Core si intende il top level di un componente interfacciato;
esso rappresenta ciò che viene visto da parte del sistema. Per i motivi visti in
precedenza, è diverso a seconda del bus adottato dal sistema nel quale dovrà essere
inserito.
Nel caso di bus OPB è infatti necessaria l’istanziazione di una delle due interfacce CoreConnect descritte nella sezione 3.1 e dello stub. I segnali provenienti
dal bus sono in contatto con una di queste due interfacce, che tramite i loro servizi
forniscono allo Stub le informazioni necessarie a compiere tutte le operazioni sul
core.
Nell’interfacciamento con bus Wishbone invece il top level integra tutte le funzioni che nel caso precedente sono incluse nello Stub; questo è possibile poiché,
56
CAPITOLO 4. METODOLOGIA
come descritto nella sezione 3.2.3, questo tipo di collegamento non ha bisogno di
una logica di decodifica particolarmente elaborata e viene quindi integrata direttamente da IPGen senza necessità di componenti esterni. In definitiva, la descrizione
di un IP-Core in questo secondo tipo di interfacciamento conterrà la definizione
di tutte le porte che si rivolgono verso il sistema, l’istanziazione del core dato
in input dall’utente, la logica di decodifica degli indirizzi necessaria ad attuare i
processi di lettura e scrittura, e il mappaggio dei segnali tra core e bus.
4.3
Workflow di IPGen
Per generare un IP-Core partendo dalla funzionalità descrittà nel core, IPGen percorre un workflow diviso in due fasi principali; esse sono sequenziali e sono (in
ordine di esecuzione) la fase di lettura e quella di scrittura. La prima di esse si
occupa di ricevere e scansionare il core dato in input dall’utente, mentre la seconda si occupa della generazione dei file che descrivono l’IP-Core in output. Come
verrà visto più in dettaglio nella sezione 5.1, ognuna di queste fasi viene svolta
da un componente del framework dedicato: avremo quindi il reader per la fase di
lettura ed il writer per quella di scrittura.
4.3.1
Lettura
In figura 4.4 è schematizzato il flusso della fase di lettura eseguita dal “reader”
all’inizio dell’esecuzione di IPGen. Questo componente, in base al percorso del
file VHDL dato in input, dopo averne verificato l’esistenza, dà inizio ad una procedura chiamata clean phase. Essa viene eseguita da un modulo sussidiario al
reader chiamato cleaner, il quale legge la dichiarazione della entity del core e la
pulisce da eventuali commenti VHDL che potrebbero generare problemi di parsing nella fase successiva. Il reader quindi prosegue il suo flusso lavorando sulla
dichiarazione pulita precedentemente, effettuandone il parsing e, nel caso in cui
riconosca una dichiarazione ben formata, crea la lista dei segnali descritti in essa.
La stessa operazione viene eseguita nella sezione di dichiarazione dei generic, in
cui viene creata una lista contenente tutte le informazioni relative ad essi. A questo
57
CAPITOLO 4. METODOLOGIA
Figura 4.4: Flusso operativo del reader
punto viene richiesto all’utente quale modalità di interfacciamento desidera per il
suo core; avvenuta questa scelta il programma ha tutte le informazioni necessarie
alla generazione dell’IP-Core. Se i passi descritti fino ad ora terminano senza errori, il reader passa il controllo del flusso di esecuzione e le liste precedentemente
salvate al “writer” predisposto a generare l’interfaccia selezionata.
4.3.2
Scrittura
Il tipo di writer che entra in funzione a questo punto dipende dal tipo di interfaccia selezionato dall’utente. Sono stati infatti implementati tre writer separati,
ognuno dedicato alla generazione di una delle interfacce descritte. Pur essendo
componenti a sé stanti, seguono lo stesso tipo di workflow. Il writer legge le informazioni elaborate nella fase precedente: il path del core, le liste dei segnali e dei
generic, e il nome della entity specificata nel core; in base a questi dati crea un file
58
CAPITOLO 4. METODOLOGIA
Figura 4.5: Flusso operativo del writer
VHDL per ogni livello della struttura dell’IP-Core da generare così come è stata descritta in precedenza. Tutti i dettagli implementativi di questa fase vengono
trattati nel capitolo 5.
4.4
Confronti con gli altri approcci
Avendo mostrato la metodologia proposta da questa tesi, è possibile a questo punto effettuare dei confronti tra la nostra soluzione e quelle descritte nel capitolo
59
CAPITOLO 4. METODOLOGIA
2. Vengono presi inizialmente in considerazione i primi due approcci, cioè OCP
Socket e IAL, come già detto molto simili tra loro. Il primo punto fondamentale
da analizzare è l’intento che sta alla base delle diverse metodologie: si può dire
che l’obiettivo primario di questi due approcci è il riutilizzo degli IP-Core, tramite
il quale è possibile creare delle librerie di moduli utilizzabili in applicazioni e contesti architetturali differenti, con il risultato di velocizzare il flusso di lavoro per lo
sviluppo di sistemi hardware e disporre di IP-Core solidi e funzionanti. Per quanto riguarda IPGen, l’obiettivo primario è invece quello di velocizzare la creazione
degli IP-Core, soprattutto nell’ambito della riconfigurabilità dinamica. Il risultato
che si spera di ottenere è quello di un flusso completamente automatizzato che,
partendo da specifiche di alto livello, produca un sistema dinamicamente riconfigurabile passando tramite il workflow di Caronte (sezione 1.1.4). All’interno di
questo processo IPGen è necessario per generare in un tempo brevissimo e in modo completamente automatizzato gli IP-Core necessari. In ogni caso, il software
sviluppato è utilizzabile con ottimi risultati anche in un’ottica di riutilizzo degli
IP-Core, in quanto esso è in grado di generare interfacce differenti per core che
sono generali, non essendo dipendenti dall’architettura che li ospita.
Dopo avere mostrato questa lieve discrepanza di intenti, si può notare che tutti
questi approcci adottano un metodo che si basa sulla stessa considerazione: per
ottenere un core che sia portabile su sistemi differenti è necessario stratificare la
struttura dell’IP-Core. La stratificazione implica infatti un disaccoppiamento tra
il core e l’architettura ospitante. Proprio in quest’ottica è possibile definire due
tipologie di componenti: core-centric, i quali sono indipendenti dall’infrastruttura di comunicazione, e bus-centric, nei quali il collegamento con un particolare
mezzo trasmissivo è integrato e spesso impossibile da isolare e sostituire. Ovviamente è la prima categoria di core che i diversi approcci utilizzano come punto di
partenza per raggiungere i propri obiettivi.
Da un punto di vista metodologico, si vede chiaramente come IPGen si collochi ad un livello architetturale differente rispetto a OCP e IAL. Infatti, mentre il
primo si occupa di generare un IP-Core che opera mediante interfacce già esistenti
e diffuse, i secondi propongono uno standard di interfaccia nuovo, da diffondere
60
CAPITOLO 4. METODOLOGIA
il più possibile. Adottando però un’interfaccia comune, è necessario adottare dei
convertitori logici che colleghino in modo opportuno i segnali di comunicazione
dell’IP-Core con quelli molto spesso diversi del bus: tali componenti vengono
chiamati bus wrapper. Si perviene quindi alla seguente considerazione: se per
allacciare un IP-Core ad una particolare infrastruttura di comunicazione si rende
obbligatorio nella nostra metodologia implementare un writer opportuno (se non
già esistente), mentre negli altri due approcci è necessario scrivere un bus wrapper. Nonostante questa apparente equità, emerge a questo punto un dato a favore
di IPGen: esso è infatti in grado di generare automaticamente lo stub, il quale
contiene logica che non costituisce un overhead, in quanto comunque necessaria
alla comunicazione con un bus; gli altri due approcci introducono invece un componente aggiuntivo, il bus wrapper, che appesantisce necessariamente l’IP-Core
risultante. Quanto spiegato si può vedere chiaramente in figura 4.6. Inoltre la
funzione svolta dallo stub deve essere implementata manualmente dallo sviluppatore adottando una della altre due metodologie, incrementando quindi il tempo di
creazione del core.
Figura 4.6: Confronto degli IP-Core risultanti utilizzando differenti approcci
61
CAPITOLO 4. METODOLOGIA
Dato che, come è stato appena mostrato, IPGen e OCP/IAL operano a livelli differenti, si può addirittura considerare una potenziale integrazione tra i due
differenti approcci: è infatti possibile pensare di creare un writer per IPGen che
adotta, per esempio, il Socket OCP.
Viene ora preso in considerazione EDK Create/Import Peripheral Wizard. Come
già detto, quest’ultimo opera solamente con le interfacce OPB IPIF e PLB IPIF, in
quanto è orientato ad interagire con EDK, che adotta i bus della famiglia CoreConnect. Questo strumento possiede dunque una ristretta area di applicazione. Inoltre,
esso non si occupa in nessun modo dell’interfacciamento di core già esistenti con
uno specifico bus, poiché l’unica funzione significativa che offre è quella di generare un template vuoto nel quale collocare manualmente ed in un secondo momento la descrizione VHDL della funzionalità. Quello che invece IPGen fa è generare
l’interfaccia prendendo in ingresso il core, fornendo in uscita un prodotto completo. Anche in questo caso si può delineare in modo semplice un’integrazione tra
le due metodologie: un core generato automaticamente dal framework con interfaccia OPB IPIF può essere importato in un sistema EDK tramite la funzionalità
“import” fornita da EDK Create/Import Peripheral Wizard.
Impulse CoDeveloper offre la possibilità di generare l’interfaccia per collegare
il componente sintetizzato a una varietà di architetture molto vasta. In tal senso
esso si dimostra uno strumento molto versatile. Ciò nonostante, esso lavora, come
detto in precedenza, su moduli hardware che esso stesso genera, sintetizzandoli a
partire da una specifica C di alto livello. In generale dunque, il valore di questo
software non è da ricercare tanto nell’interfacciamento dei moduli, operazione
che a questo punto risulta quasi meccanica e banale, quanto nella capacità di sintetizzare una specifica di alto livello in un sistema integrato hardware e software
in un tempo breve e in modo semplice per l’utente. Ovviamente una limitazione
ineliminabile di questa metodologia risiede nel fatto che l’utente deve apprendere
l’utilizzo delle librerie ImpulseC per scrivere il codice della specifica. Volendo effettuare un confronto con IPGen, si può affermare che quest’ultimo è stato progettato tenendo conto di un core in ingresso che sia veramente “generico”, ossia non
presenti necessariamente un determinato set di porte. Questo perché, pur essendo
62
CAPITOLO 4. METODOLOGIA
stato pensato come componente integrante di un flusso che prende in ingresso una
specifica di alto livello e genera un sistema dinamicamente riconfigurabile, esso
mantiene comunque intatta la propria identità di software stand-alone.
63
Capitolo 5
Implementazione
Questo capitolo è dedicato alla descrizione degli aspetti implementativi di IPGen,
ossia il modo in cui la metodologia descritta nel capitolo 4 viene messa in pratica. Per una migliore comprensione, si è deciso di organizzare la trattazione in
quattro sezioni. Si inizia con la descrizione della struttura del programma, ossia
la presentazione del framework dal punto di vista dell’ingegneria del software.
Successivamente è mostrato il funzionamento del software, cioè l’interazione con
l’utente e i passi compiuti per generare il codice VHDL in uscita. Proprio quest’ultimo è l’argomento della sezione 5.3, nella quale si descrive in dettaglio l’output
prodotto dal programma. L’ultima sezione presenta alcune linee guida da seguire
per realizzare un core VHDL che sia interfacciabile con successo tramite IPGen.
5.1
Struttura del programma
La struttura software di IPGen ricalca praticamente in tutto la metodologia sulla
quale si fonda, descritta nel precedente capitolo. Il programma è stato implementato con il linguaggio C++. L’impiego di tale linguaggio ha permesso di conferire
una struttura modulare al software, la quale è la chiave dell’espandibilità del software: sarà sufficiente aggiungere una nuova classe per espanderne la funzionalità.
Viene quindi analizzata l’organizzazione delle classi che compongono IPGen, il
cui class diagram è mostrato in figura 5.1.
65
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.1: Class diagram di IPGen
Il software possiede innanzitutto una classe Main, adibita all’inizializzazione
del programma, alla creazione delle istanze di classi necessarie e alla chiamata dei
relativi metodi.
La classe Signal definisce il tipo “segnale”, indispensabile affinché il reader
possa creare un lista contenente i segnali di input/output del core per potere poi
implementare un’opportuna interfaccia. La classe possiede molti metodi qui di
seguito elencati e brevemente spiegati:
• in(). Restituisce “true” se il segnale costituisce un ingresso del core;
• out(). Restituisce “true” se il segnale costituisce una uscita del core;
• vector(). Restituisce “true” se il segnale è di tipo std_logic_vector;
• name(). Restituisce il nome del segnale;
• type(). Restituisce il tipo del segnale (std_logic oppure std_logic_vector);
• direction(). Restituisce la direzione del segnale (“in” oppure “out”);
66
CAPITOLO 5. IMPLEMENTAZIONE
• initial(). Nel caso in cui il segnale sia di tipo std_logic_vector,
restituisce l’indice iniziale del vettore;
• final(). Nel caso in cui il segnale sia di tipo std_logic_vector,
restituisce l’indice finale del vettore;
• length(). Nel caso in cui il segnale sia di tipo std_logic_vector,
restituisce la lunghezza del vettore;
• to(). Nel caso in cui il segnale sia di tipo std_logic_vector, restituisce la direzione di ordinamento del vettore (to oppure downto).
Si potrebbe dire che alcuni tra i metodi elencati siano ridondanti in quanto sembrano fornire la stessa informazione. In effetti è così, ma l’apparente ridondanza
è giustificata dalla diversità dell’ambito in cui tali metodi vengono invocati. Per
esempio, se in una espressione condizionale è necessario verificare il fatto che il
segnale sia un vettore, è molto più comodo utilizzare il metodo vector(), il
quale restituisce una variabile booleana, che invocare il metodo type() ed effettuare un confronto sulla stringa ottenuta. Se invece è richiesto di scrivere sul
file destinazione il tipo di segnale, sarà molto comodo invocare type() rispetto
a verificare il tipo tramite il metodo vector().
Per quanto concerne la classe Generic, la quale descrive appunto il tipo “generic”, ossia un parametro della descrizione VHDL, tale oggetto possiede degli attributi che possono essere ottenuti invocando i seguenti metodi:
• name(). Restituisce il nome del generic;
• type(). Restituisce il tipo del generic;
• def(). Restituisce, se assegnato, il valore di default del generic.
Verranno ora presentate le classi che rappresentano il cuore dell’applicazione. La
classe Reader costituisce l’oggetto adibito a leggere il file VHDL la cui locazione
è fornita in ingresso e a riconoscerne sostanzialmente la dichiarazione di entity,
costruendo una lista di segnali e una lista di generic. Sono presenti i seguenti
metodi:
67
CAPITOLO 5. IMPLEMENTAZIONE
• read(). Tramite questa funzione viene avviato il processo di lettura;
• getList(). Restituisce la lista di Signal costruita dal metodo read();
• getListg(). Restituisce la lista di Generic costruita dal metodo read();
• getComponent(). Restituisce il nome del componente, cioè quello che
appare nella dichiarazione di entity.
La classe Writer rappresenta l’oggetto che effettua la creazione e la scrittura dei
file VHDL in uscita. Come si vede nel diagramma, non vi è un’unica classe Writer: è infatti presente una classe per ogni interfaccia supportata dal framework. Al
momento il programma è in grado di generare core con tre differenti tipi di interfaccia (vedere sezione 3): OPB PSelect, OPB IPIF e Wishbone. Ognuna di questa
classi è figlia di un’unica classe astratta, denominata appunto Writer, in modo
da mantenere una struttura identica e permettere in questo modo una maggiore
espandibilità tramite l’aggiunta di Writer per nuove interfacce. Vi sono dunque
tre classi: PSelect_Writer, IPIF_Writer e Wishbone_Writer, ognuna delle quali
definisce per “override” il metodo write() della classe madre. Si noti invece
che la classe Reader è unica, e non cambia passando da un tipo di interfaccia ad un
altro, in quanto il processo di lettura del file in ingresso e di costruzione delle liste
è identico qualunque sia il tipo di infrastruttura di comunicazione che si vuole
adottare. In sintesi, se si vuole aggiungere supporto per una nuova interfaccia,
è sufficiente scrivere un’opportuna classe _Writer e aggiungere la scelta di tale
interfaccia come opzione all’interno della classe Main.
L’ultima classe che si trova in figura è Cleaner. Essa fornisce due importanti
metodi per la gestione dei file VHDL, che sono:
• CleanComments(std:string Component). Questo metodo è necessario per pulire il file VHDL in ingresso da commenti che possono risultare
molto fastidiosi in fase di lettura della entity. Per esempio tra due linee che
contengono dichiarazioni di porte potrebbe trovarsi un commento: questo,
se non identificato come tale ed eliminato, potrebbe essere interpretato come
una dichiarazione di porta generando una palese situazione di errore. Il
68
CAPITOLO 5. IMPLEMENTAZIONE
metodo CleanComment opera nel seguente modo: apre il file VHDL identificato dalla stringa in ingresso e ne scansiona la entity in cerca di commenti,
producendo in uscita una stringa contenente la stessa dichiarazione di entity
priva di eventuali commenti. Si noti che non è necessario fornire in uscita tutto il contenuto del file VHDL, in quanto la sezione che interessa al
reader è solamente quella in cui si trovano la descrizione delle porte e degli
eventuali generic.
• CleanGenerics(). Anche questo metodo opera sul file VHDL che descrive il core. Si occupa dell’identificazione dei generic presenti e provvede
a cancellarne l’eventuale valore di default. Questa operazione è necessaria
poichè, se il valore di default venisse lasciato indicato nel core, esso genererebbe una discrepanza di valori con il dato impostato dall’esterno. È
molto importante sottolineare il fatto che questo metodo non sovrascrive il
file originale ma crea un ulteriore file contenente il codice senza i valori di
dafault dei generic. Questo perché in tal modo il core fornito dall’utente
viene preservato completamente intatto.
Nella prossima sezione verrà descritto come queste classi e i relativi metodi vengono utilizzati nel flusso di lavoro di IPGen.
5.2
Utilizzo e funzionamento del framework
IPGen non è dotato per il momento di interfaccia grafica (GUI), ed è quindi accessibile solamente da riga di comando. Il motivo per il quale non è stata data la
priorità allo sviluppo di una GUI per il tool è semplice: esso è nato come componente del flusso di lavoro di Caronte e dunque viene invocato direttamente da tale
framework, senza bisogno di una interfaccia grafica indipendente. L’implementazione di questa è comunque in cantiere per sviluppi futuri, in quanto l’utilità del
framework si è dimostrata notevole anche al di fuori dell’ambito nativo, al punto
che esso potrebbe essere visto come un software a sé stante.
69
CAPITOLO 5. IMPLEMENTAZIONE
Il flusso di esecuzione del software è stato suddiviso per chiarezza in quattro
fasi, che sono:
• inizializzazione;
• fase di lettura;
• scelta dell’interfaccia e fase di scrittura;
• terminazione.
Ognuna di queste sarà descritta dettagliatamente nei prossimi paragrafi.
5.2.1
Inizializzazione
Per invocare IPGen l’utente digita la stringa ./ipgen seguita dal percorso del
file VHDL che descrive il core da interfacciare. Se tale percorso non viene fornito,
o è inesistente, viene generato immediatamente un messaggio di errore. Se invece
il file indicato esiste, viene creato un oggetto di tipo Reader e uno di tipo Cleaner,
del quale viene invocato il metodo cleanComments, che apre il file in esame, e
genera una stringa contenente la entity del core priva di eventuali commenti. Tale
stringa viene poi passata al Reader invocando su di esso il metodo read. Si noti
che a questo punto si è preferito utilizzare una stringa, piuttosto che un ulteriore
file, soprattutto per motivi di efficienza: è infatti noto che un accesso alla RAM,
possibile se si utilizza una stringa, è molto meno dispendioso che un accesso su
disco, necessario in caso fosse stato utilizzato un file di passaggio.
5.2.2
Fase di lettura
A questo punto è il Reader a controllare l’esecuzione: esso analizza la stringa in
ingresso in cerca della parola chiave “entity”, che indica l’inizio delle dichiarazioni
di interesse. Una volta trovata sonda la presenza di eventuali generic, verificando
la presenza della parola chiave “generic”, a cui seguono le dichiarazioni di questi
parametri. Se essa è presente il Reader procede riga per riga, inserendo in un’opportuna lista di oggetti di tipo Generic i parametri identificati, sicuro sul fatto che
70
CAPITOLO 5. IMPLEMENTAZIONE
non possano esserci dei commenti che lo conducano a una condizione di errore. In
un file VHDL i generic possono essere presenti o meno. Al contrario un core deve
per forza possedere delle porte di input/output, e quindi il Reader deve trovare
la parola chiave “port”, che precede la dichiarazione di tali segnali. Se questa
non viene identificata il Reader si blocca e genera un messaggio di errore. Se invece il file è corretto le linee seguenti vengono scansionate e i segnali identificati
vengono inseriti in una lista di oggetti di tipo Signal. Durante questo processo
il Reader scrive a video il nome e le caratteristiche di tutte le porte identificate,
offrendo così all’utente la possibilità di verificarne la correttezza. Una volta conclusa la lettura della stringa fornita dal Cleaner, il controllo passa di nuovo al
main il quale stampa a video le dimensioni complessive (in byte) degli ingressi e
delle uscite del core, invocando sul Reader i metodi getSpaceIn e getSpaceOut.
In figura 5.2 è mostrato un esempio dell’output video di IPGen. In questo caso
il core fornito è un addizionatore avente oltre ai segnali di clock, di interrupt e di
reset, due operandi di 32 bit in ingresso e una uscita, sempre di 32 bit.
5.2.3
Scelta dell’interfaccia e fase di scrittura
A questo punto dell’esecuzione viene chiesto all’utente di scegliere il tipo di interfaccia da integrare nell’IP-Core. Al momento il software supporta tre tipi di
interfaccia: OPB PSelect, OPB IPIF e Wishbone. Nel caso particolare in cui venga scelta l’interfaccia verso il bus Wishbone, viene chiesto all’utente di indicare il
numero di bit che vanno a costituire l’indirizzo che identifica l’IP-Core all’interno
del sistema (vedere capitolo 3), corrispondente a tre nel caso di architettura YaRA.
Una volta effettuata questa eventuale scelta, viene creata un’istanza del particolare writer in base alla preferenza dell’utente e su di esso si invoca il metodo
write, che prende in ingresso il Reader e il Cleaner precedentemente creati. In
questa sezione non verranno trattati singolarmente i tre tipi di Writer, in quanto il
flusso di esecuzione è sostanzialmente lo stesso. Si può suddividere l’esecuzione
del metodo write in tre fasi: inizializzazione, creazione dello stub e creazione
dell’IP-Core.
71
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.2: Esempio dell’output video di IPGen
72
CAPITOLO 5. IMPLEMENTAZIONE
• Per “inizializzazione” si intendono una serie di operazioni che precedono
la scrittura vera e propria: innanzitutto viene invocata la funzione cleanGenerics(). Essa analizza il file VHDL che descrive il core e produce in uscita
un nuovo file, identico a quello letto ma privo dell’eventuale valore di default dei generic, qualora essi fossero presenti. Nella sezione 5.3.4 verrà
spiegato nel dettaglio il motivo della necessità di tale operazione. Successivamente vengono caricate la lista di segnali e la lista di generic, invocando
sul reader i metodi getList e getListg, le quali vengono salvate in due opportune variabili. L’ultima tra le operazioni di inizializzazione, necessaria se è
stata selezionato l’interfaccimento con IPIF, è il calcolo della lunghezza del
vettore di Chip Enable (CE, vedere sezione 3.1.2).
• A questo punto tutto è pronto per iniziare la scrittura del file VHDL che
descrive lo stub. Questo è composto da una struttura fissa, nella quale si
innestano alcune parti variabili, che cambiano a seconda del core da interfacciare. La tecnica impiegata è stata dunque quella di creare una costante
contenente una stringa che corrisponde alla struttura fissa. Questa viene
caricata in memoria dal metodo write, che la legge carattere per carattere e
simultaneamente scrive i caratteri letti nel file VHDL in uscita. All’interno
della stringa, laddove vi è la necessità di inserire una parte di descrizione
che dipende dal particolare core in ingresso, è presente un identificatore,
“#”, seguito da un carattere. Quando, durante la lettura della stringa, il Writer incontra tale identificatore, il flusso di esecuzione entra in un costrutto
di tipo case. A seconda del carattere letto dopo “#”, viene scritta nel file in
uscita un’opportuna sezione, per esempio la dichiarazione o l’istanziazione
del core, utilizzando le informazioni che pervengono in larga parte dalle
liste provenienti dal Reader. Una volta eseguite le istruzioni corrispondenti
all’opzione selezionata all’interno del costrutto case, il Writer riprende normalmente il ciclo di lettura da stringa e scrittura su file, fino alla successiva
occorrenza dell’identificatore “#”. La scrittura dello stub termina ovviamente quando viene raggiunta la fine della stringa. In figura 5.3 è mostrato
schematicamente il flusso di esecuzione corrispondente alla tecnica appena
73
CAPITOLO 5. IMPLEMENTAZIONE
descritta.
Figura 5.3: Flusso di creazione dei file in uscita
• Il file VHDL che descrive l’IP-Core, ossia la top-architecture del componente interfacciato, viene creato in modo del tutto analogo allo stub. Si utilizza infatti un’altra stringa costante, che contiene la parte fissa del codice
che descrive l’IP-Core. Anche in questo caso è necessario creare delle parti
dipendenti dal core da interfacciare, e quindi è presente un costrutto case
che funziona allo stesso modo di quello descritto nel precedente paragrafo.
Si tenga però presente che per generare un’interfaccia verso il bus Wishbone
non è necessario creare questo secondo file, in quanto lo stub, che a questo
punto verrà chiamato esso stesso IP-Core, presenta come porte di ingresso e
uscita esattamente i segnali del bus Wishbone. Quindi tale IP-Core non utilizza un’interfaccia che costituisce un modulo da istanziare (come avviene
74
CAPITOLO 5. IMPLEMENTAZIONE
invece per PSelect o IPIF), e lo stub svolge tutte le funzioni richieste ai fini
di supportare un corretto protocollo di comunicazione.
5.2.4
Terminazione
Se non vengono riscontrati errori, il processo di scrittura si conclude e il controllo
passa di nuovo al main, il quale termina l’esecuzione di IPGen. L’intero processo
di esecuzione del software (nel caso si adotti un’interfaccia “da istanziare”, per
esempio IPIF, e quindi rispettando la struttura classica dell’IP-Core come presentata in figura 1.1) è sinteticamente mostrato nel sequence diagram UML di figura
5.4. In questo diagramma, le etichette collegate da frecce tratteggiate al termine
dell’esecuzione dei metodi cleanGenerics e write indicano la creazione dei file il
cui nome è riportato all’interno dell’etichetta stessa.
5.3
Caratteristiche delle descrizioni VHDL generate
In questa sezione verranno presentate le caratteristiche delle descrizioni VHDL
prodotte da IPGen. Alcune di queste caratteristiche sono comuni a tutte le interfacce, mentre altre si differenziano a seconda della tipologia dell’infrastruttura di
comunicazione selezionata dall’utente. La trattazione è suddivisa in ambiti funzionali; per ognuno di questi si mostreranno le eventuali differenze presenti tra i
tre diversi tipi di interfacce.
5.3.1
Visione d’insieme
In generale, i file VHDL prodotti da IPGen rispecchiano la struttura dell’IPCore come mostrata in figura 4.2. L’output del programma è infatti solitamente
composto da tre file:
• La descrizione VHDL del core, denominata nomecomponente_core.vhd,
dove “nomecomponente” va sostituito con il nome reale del componente
75
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.4: Sequence diagram dell’esecuzione di IPGen
che viene interfacciato. Questo file è sostanzialmente uguale a quello che
viene fornito dall’utente, dal quale si differenzia soltanto per l’assenza del
valore di default di eventuali generic. Il motivo di tale scelta è spiegato nella
sezione 5.3.4.
• La descrizione VHDL dello stub, denominata nomecomponente_stub.vhd.
Questo file rappresenta, come dice il nome, lo stub dell’IP-Core generato, ossia la parte di logica che permette la comunicazione tra il core e
l’interfaccia.
• La descrizione VHDL dell’IP-Core, denominata nomecomponente_IPCore.vhd.
Questo file descrive l’IP-Core nel suo complesso. Esso è la top architecture
del componente, indicando con questo termine la parte di logica più ester76
CAPITOLO 5. IMPLEMENTAZIONE
na, cioè quella che viene vista dal bus, all’interno della quale sono istanziate
le parti che compongono l’IP-Core. Volendo utilizzare l’IP-Core, tutto ciò
che importa è il set di segnali che questo file presenta come porte di ingresso e uscita; sono infatti questi segnali, e solo questi, che rientrano nel file
Microprocessor Peripheral Definition (MPD, vedere sezione 2.3) utilizzato
da EDK per gestire correttamente un IP-Core che si vuole inserire in un
sistema.
Il file che rappresenta la vera e propria interfaccia di comunicazione non è presente
tra gli output del software, in quanto, come già scritto, IPGen si avvale di interfacce già esistenti e diffuse. Per citare un esempio, i file che descrivono le interfacce
OPB IPIF e OPB PSelect, fanno parte della libreria di core fornita da Xilinx con il
framework EDK. La struttura dei file sopra illustrata non è però sempre identica,
in quanto esistono delle situazioni che potremmo definire “degeneri”. È questo il
caso dell’interfaccia verso il bus Wishbone: interfacciando un core verso questo
bus, infatti, non è necessario introdurre un ulteriore componente (l’interfaccia di
cui si è scritto prima) tra lo stub e il bus, in quanto i segnali di ingresso e uscita
dello stub coincidono già con i segnali del bus Wishbone. Tutta la logica necessaria per implementare un collegamento che permetta la corretta comunicazione
dell’IP-Core con gli altri componenti del sistema è contenuta nello stub, in quanto
non sono richiesti ulteriori mappaggi tra segnali. Per questi motivi lo stub viene
a coincidere con l’IP-Core stesso, e quindi si avranno solamente due file in uscita: nomecomponente_core.vhd e nomecomponente_IPCore.vhd. In figura 5.5 è
mostrata sia la struttura generale che quella che è stata definita “degenere”.
Si descrive ora brevemente il funzionamento dell’IP-Core generato facendo
riferimento alla struttura dell’IP-Core generale. I segnali del bus si collegano, in
fase di “placement” del componente all’interno di un sistema, alle omonime porte
presenti in ingresso e in uscita dall’IP-Core. Si noti che la dichiarazione delle
porte dell’IP-Core non cambia a seconda del core interfacciato, in quanto esse
corrispondono ai segnali del bus adottato. Questi vengono filtrati da quella che è
stata chiamata interfaccia, che li elabora per generare un set di segnali solitamente
più semplice da gestire, offrendo spesso una varietà di servizi, come quelli visti nel
77
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.5: Diverse strutture di file generati
caso di OPB IPIF (sezione 3.1.2). I segnali generati dall’interfaccia costituiscono
le porte dello stub, il quale viene istanziato all’interno dell’IP-Core e svolge le
funzionalità descritte nel capitolo 4. All’interno di questo componente, a sua
volta, è istanziato il core, ossia la funzionalità implementata dall’utente con il
proprio set particolare di porte. Nelle seguenti sezioni sarà fornita una descrizione
più dettagliata del funzionamento descritto.
5.3.2
Istanziazione dei componenti e mappaggio delle porte
Come affermato nel paragrafo 5.3.1, all’interno dell’IP-Core vengono istanziati
l’interfaccia e lo stub. Nel caso di infrastrutture complesse, come OPB IPIF, il
mappaggio delle porte dell’interfaccia è abbastanza complicato; trattandosi comunque di una parte di logica fissa, cioè non dipendente dal particolare core,
esso non deve essere effettuato ogni volta. Inoltre l’interfaccia suddetta presenta numerosi parametri da impostare, i quali determinano l’utilizzo o meno di un
determinato servizio offerto. Ad eccezione della decodifica degli infirizzi, al momento si è scelto di non adottare alcun servizio opzionale implementato in OPB
IPIF, poiché questi comportano spesso un overhead di occupazione non ridotto, il
che andrebbe ad aumentare l’area occupata e il tempo necessario alla riconfigurazione del componente nell’ambito di un’architettura quale Caronte. Nel futuro
si potrebbe attrezzare IPGen del supporto necessario a offrire all’utente la possi78
CAPITOLO 5. IMPLEMENTAZIONE
bilità di utilizzare o meno un determinato servizio. Per quanto riguarda lo stub,
anch’esso presenta, per ogni singolo tipo di interfaccia, un set di porte standard,
che non varia (nel caso di OPB IPIF esso è composto dai segnali IPIC). Quindi
l’istanziazione di esso risulta semplice e soprattutto fissa.
Diversamente da quanto appena scritto riguardo l’istanziazione dell’interfaccia e dllo stub, l’inserimento del core all’interno dello stub è più problematico,
in quanto non si conoscono a priori le porte del core. Queste, come descritto
nella sezione 5.2, vengono salvate dal reader in un’opportuna lista, utilizzata dal
writer per effettuare la dichiarazione del core nello stub. Per ogni porta del core
diversa dal segnale di clock, di reset e di interrupt (vedere sezione 5.4.2), viene
creato nello stub un corrispondente registro denominato register_nomesegnale,
dove “nomesegnale” è ovviamente il nome attribuito alla particolare porta, avente
tipo e dimensione del segnale del core corrispondente. Sono tali registri che vengono collegati alle porte del core in fase di istanziazione dello stesso, come si vede
nell’esempio di figura 5.6.
La gestione di questi registri all’interno dello stub è l’argomento della prossima sezione.
5.3.3
Processi di lettura e scrittura
I registri creati all’interno dello stub devono essere opportunamente gestiti. Infatti, come precedentemente spiegato, lo stub deve svolgere una funzione di demultiplexer verso l’interno (dalla linea dati del bus ai vari registri) e multiplexer
verso l’esterno (dai registri alla linea dati del bus). Queste funzionalità vengono
svolte da due processi implementati nello stub: il processo di lettura, denominato reg_read_process, e il processo di scrittura, denominato reg_write_process.
Adottando la terminologia usata nell’ambito dei componenti logici sopra citati, si
può dire che il segnale di selezione corrisponde alla linea indirizzi del bus, o a
un suo derivato. Utilizzando OPB IPIF, per esempio, si dispone dei due vettori di
selezione Bus2IP_RdCE e Bus2IP_WrCE (vedere sezione 3.1.2), che fungono da
surrogati della linea indirizzi, ma ne permettono un’interpretazione più intuitiva.
Nel seguito si farà riferimento senza perdere generalità al caso OPB IPIF.
79
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.6: Dichiarazione e istanziazione del core di un addizionatore binario a 32 bit
Il processo di lettura è costituito sostanzialmente da un costrutto di tipo case,
il quale viene attivato ad ogni fronte di salita del clock. Quando un bit del vettore read_reg_select, che corrisponde all’ingresso Bus2IP_RdCE, è posto a ’1’,
significa che è necessario porre sul bus la corrispondente uscita del core, rappresentata all’interno dello stub dal registro a cui è mappata. Nel caso particolare in
cui l’uscita che si vuole leggere è costituita da un segnale di tipo std_logic, tale valore viene posto per convenzione sul bit meno significativo (Least Significant Bit LSB) del bus dati, cioè quello più a destra. Se il segnale è di tipo std_logic_vector
ed ha lunghezza inferiore a 32 bit, che è la dimensione del bus dati nei tre tipi di
interfaccia supportati, anche in questo caso, per convenzione, il valore viene posto
sui bit più a destra della linea dati del bus. Il caso di segnali con dimensione maggiore di 32 bit è più complesso e viene esposto nella sezione 5.3.5. Un esempio
chiarificatore è mostrato in figura 5.7.
80
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.7: Esempio di processo di lettura dei registri
Il processo di scrittura è molto simile a quello di lettura. Anche in questo caso
si ha un costrutto case il cui segnale di selezione è reg_write_select, corrispondente all’ingresso Bus2IP_WrCE. In modo analogo a quanto detto per il processo
di lettura, i registri aventi lunghezza minore di 32 bit prelevano il proprio valore
dai bit meno significativi del bus dati. Nel processo di scrittura, è presente anche
la parte riguardante il reset dei registri in ingresso. Semplicemente, si controlla
all’inizio del processo se l’ingresso Bus2IP_Reset è attivo, e, in caso affermativo, si procede ponendo a zero il contenuto dei registri di scrittura dello stub. Un
esempio è mostrato in figura 5.8.
5.3.4
Gestione dei generic
Se nel core sono presenti dei generic, essi possono possedere un valore di default.
Tale valore, se lasciato indicato nel core, potrebbe essere fonte di errori o problemi
di interpretazione. Infatti, dato che un generic è un parametro che si può impostare
81
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.8: Esempio di processo di scrittura dei registri
quando l’IP-Core viene collocato in un sistema (per esempio tramite EDK), il
framework deve essere in grado di propagare verso l’esterno, dal punto di vista
della consueta struttura del componente, tale parametro; in questo modo il generic
è impostabile agendo sul file che descrive l’IP-Core. Ora, impostando dall’esterno
un valore per un determinato generic, potrebbe darsi che esso sia differente dal
valore di default indicato nel core.
Per ovviare a questo problema, IPGen sfrutta un meccanismo molto semplice:
salva una lista dei generic in fase di lettura, e in fase di scrittura effettua due
mappaggi consecutivi per ognuno di essi prima dal core allo stub, e poi dallo stub
all’IP-Core. Inoltre esso genera, come scritto in precedenza, un file uguale al
core, ma privo dei valori di default di eventuali generic; tali valori vengono poi
indicati ragionevolmente nella dichiarazione dello stesso generic a livello di IP82
CAPITOLO 5. IMPLEMENTAZIONE
Core. Sembrerebbe inutilmente dispendioso creare una copia quasi identica di un
file, ma effettivamente questa scelta si rivela sensata: grazie ad essa infatti il file
originale viene preservato in tutto e per tutto, rendendo possibile il suo riutilizzo
in un altro ambito.
5.3.5
Gestione di porte con dimensione maggiore di 32 bit
Figura 5.9: Processo di lettura per un core avente una uscita da 128 bit
Per consentire ad IPGen di essere applicabile ad una maggiore varietà di core,
si è deciso di implementare un supporto per i segnali di tipo std_logic_vector
aventi dimensione maggiore della linea dati del bus, che in tutti e tre i casi di
interesse corrisponde a 32 bit. Dopo attente analisi, è stato adottato il seguente
meccanismo di comunicazione: ogni segnale “grande” viene segmentato in registri di dimensione uguale a 32 bit, ad eccezione dell’ultimo, che può avere una
dimensione compresa tra 1 e 32 bit, in quanto la lunghezza segnali non è necessariamente multipla di 32. Ad ogni segmento viene associato un indirizzo; per
accedere in lettura o scrittura a ciascun pezzo del segnale, il driver che gestisce
l’IP-Core deve quindi fornire l’indirizzo preciso del registro corrispondente.
Per quanto riguarda il processo di lettura, esso non si discosta molto da quanto
presentato nella sezione 5.3.3. In figura 5.9 si può vedere un esempio di processo
di lettura per un core avente un segnale di lunghezza 128 bit.
La questione è nettamente più complessa per quanto riguarda la scrittura di
83
CAPITOLO 5. IMPLEMENTAZIONE
tali segnali. Questo perché se un core possiede un ingresso, per esempio, di 64
bit, esso si aspetta certamente di riceverlo tutto in una volta, e non scaglionato in
segmenti da 32 bit. Per rispettare questa condizione IPGen crea all’interno dello
stub, per ogni ingresso del core più grande di 32 bit, i seguenti segnali, il cui
utilizzo viene spiegato successivamente:
• il consueto registro, denominato register_nomesegnale;
• un segnale di tipo std_logic_vector, denominato buffer_nomesegnale, avente
dimensione pari a quella dell’ingresso del core;
• un segnale di tipo intero, denominato count_nomesegnale;
• un segnale di tipo std_logic, denominato ready_nomesegnale.
Nel processo di scrittura, in presenza di un segnale “grande”, viene generata una
sorta di macchina a stati, la quale pone al driver il vincolo di rispettare obbligatoriamente la sequenzialità nella trasmissione del segnale, la quale può avvenire
anche in modo non consecutivo. In pratica, all’indirizzo di ogni segmento del
segnale viene assegnato un numero intero partendo da 0; se, quando si riceve l’nesimo segmento, il contatore count_nomesegnale ha un valore pari alla posizione
del segmento all’interno del segnale, cioè n, il valore in ingresso viene correttamente copiato nella giusta posizione all’interno di buffer_nomesegnale. In caso
contrario il contatore viene annullato e il buffer posto interamente a ’0’, effettuando perciò un reset della comunicazione. Quando l’ultimo segmento del segnale
viene correttamente ricevuto, viene posto al valore ’1’ il flag ready_nomesegnale,
in modo che un opportuno controllore possa, nel ciclo di clock successivo, copiare l’intero contenuto del buffer in registro_nomesegnale e riazzerare il flag. Un
esempio di questa operazione è mostrato in figura 5.10, nella quale si considera
un segnale di lunghezza pari a 96 bit.
Il meccanismo appena descritto non è al momento stato implementato per
quanto riguarda l’interfaccia OPB PSelect, mentre è supportato utilizzando OPB
IPIF e Wishbone.
84
CAPITOLO 5. IMPLEMENTAZIONE
Figura 5.10: Processo di scrittura per un core avente un ingresso da 96 bit
5.4
Come scrivere un core interfacciabile automaticamente
In questa sezione vengono analizzati quelli che sono i requisiti che un core deve
possedere, affinché la creazione del relativo IP-Core tramite IPGen possa avvenire
con successo. Questi requisiti si dividono in due gruppi:
• requisiti concettuali, la cui inosservanza non genera errori nel flusso di
esecuzione di IPGen;
85
CAPITOLO 5. IMPLEMENTAZIONE
• requisiti pratici, riconosciuti dal framework, la cui inosservanza blocca effettivamente l’esecuzione dello stesso.
5.4.1
Requisiti concettuali
Si tratta in realtà di un unico principio fondamentale da tenere a mente, e non di
una serie di regole da seguire. Sostanzialmente, si può dire che lo sviluppatore del
core, cioè colui che ne scrive la descrizione in VHDL, deve occuparsi solamente
della funzionalità svolta dal componente che sta implementando, senza curarsi, in
nessun modo, della connessione di questo con il sistema in cui verrà inserito. In
altre parole, tutta e sola la funzionalità reale che il componente svolge va descritta nel core, lasciando ad altri il compito di occuparsi del collegamento con una
particolare infrastruttura di comunicazione. Portando il discorso ad un livello più
pratico, si può affermare che l’insieme degli ingressi e delle uscite del core non
deve contenere elementi in qualche modo riconducibili al collegamento dell’IPCore nel sistema, in quanto la logica necessaria a tale scopo viene interamente
creata da IPGen. Viene presentato un esempio per esplicare meglio quanto si intende dire: si prenda il caso in cui si voglia realizzare un addizionatore binario
con operandi di 32 bit. In tal caso, è ovvio che gli ingressi saranno costituiti dagli
addendi, e da eventuali segnali di clock (se il componente è sincrono) e di reset. Le uscite saranno invece il risultato e eventualmente un interrupt, utilizzabile
ad esempio per segnalare un overflow. Come si vede, non si fa in nessun modo
riferimento alla linea dati del bus o agli indirizzi dei registri che permettono di effettuare operazioni di lettura scrittura sul componente. Questo è possibile poiché
è lo stub, generato automaticamente, che si occupa di questioni quali lo smistamento degli operandi in ingresso, provenienti da un’unica linea dati del bus, o la
lettura del risultato in uscita, il quale va posto sulla stessa linea dati.
Se un core contenente porzioni di logica necessari alla comunicazione con il
sistema viene dato in ingresso ad IPGen, si ottiene un prodotto non sintatticamente
scorretto, ma contenente inutili e dannose ridondanze. Un tale IP-Core risulta
necessariamente inutilizzabile, sia a causa dei ritardi introdotti da inutili livelli di
comunicazione, sia perché non si assicura un corretto collegamento tra ingressi del
86
CAPITOLO 5. IMPLEMENTAZIONE
core e segnali provenienti dal bus. Per citare un caso, si consideri un core avente
un segnale in ingresso che rappresenta l’indirizzo posto sul bus. Tale segnale
non verrebbe in nessun modo riconosciuto e verrebbe collegato, come un ingresso
“normale”, alla linea dati del bus, anziché a quella degli indirizzi.
Il requisito fondamentale qui discusso non pone in realtà alcun vincolo allo sviluppatore, che anzi si trova sgravato dalla necessità di implementare una
porzione di logica generabile automaticamente. Si noti inoltre che questo requisito costituisce la base per il riuso degli IP-Core, in quanto un componente che non
contiene accenni al sistema in cui verrà posto è necessariamente “universale”.
5.4.2
Requisiti pratici
Si passa ora all’analisi dei requisiti cosiddetti “pratici”. In primo luogo un core
può possedere due tipologie di porte corrispondenti due gruppi di segnali:
• Segnali custom: sono segnali propri della funzionalità implementata, come,
ad esempio, gli ingressi di una funzione;
• Segnali standard: sono porte solitamente presenti in tutti i core implementati. Svolgono funzioni standard (da qui il nome) come il segnale di clock,
quello di reset e quello di interrupt. Solitamente a questo tipo di segnali
vengono assegnate linee dedicate del bus.
Le porte appartenenti al secondo tipo devono essere gestite in modo specifico dallo stub, per permettere un collegamento corretto con le corrispondenti linee del
bus. Sarebbe infatti un errore, per esempio, non riconoscere come tale il segnale di clock e collegarlo alla linea dati del bus, come se fosse un segnale custom,
in quanto il bus possiede una linea separata per la trasmissione di questo particolare segnale. Quindi, affinché il writer sia in grado riconoscere tali segnali, è
necessario introdurre delle condizioni di nomenclatura, elencate qui di seguito:
• Il segnale di clock deve essere denominato “clk”;
• Il segnale di reset deve essere denominato “reset”;
87
CAPITOLO 5. IMPLEMENTAZIONE
• Il segnale di interrupt deve essere denominato “intr”.
Oltre a queste convenzioni, ci sono altre due regole da seguire. IPGen gestisce solamente core aventi porte di tipo std_logic e std_logic_vector; altri tipi
non sono supportati. Se un core possiede al suo interno segnali di altro tipo, spetta
allo sviluppatore implementare la logica di conversione dal tipo in esame e uno
dei due tipi prima menzionati. Siccome ciò avviene in realtà in pochi casi, poiché
solitamente il livello di astrazione utilizzato scrivendo codice VHDL è piuttosto basso, sarebbe ingiustificatamente oneroso scrivere una parte di software che
generi in automatico la logica per effettuare queste conversioni, considerando anche che l’insieme dei tipi utilizzabili nella dichiarazione di porte e segnali interni è
potenzialmente infinito. Infine, il software non supporta al momento dichiarazioni
del tipo:
port1, port2 :
std_logic;
Tale dichiarazione va sviluppata nel modo consueto:
port1 :
std_logic;
port2 :
std_logic;
Non vi sono altri vincoli da rispettare per scrivere un core gestibile da IPGen.
88
Capitolo 6
Risultati sperimentali
Sono stati effettuati numerosi test con l’obiettivo di validare in pratica IPGen.
Questi test sono stati condotti con due strumenti: ISE Project Navigator e ModelSim, entrambi presentati nella sezione 1.2. Essi si possono suddividere in due
categorie: test di prestazione e di funzionamento. Nei primi sono stati valutati
parametri quali il tempo di esecuzione del software e l’area occupata sulla FPGA
dagli IP-Core generati, mentre i secondi hanno come obiettivo la dimostrazione
dell’effettivo funzionamento delle soluzioni adottate.
6.1
Test di prestazione
Per valutare le prestazioni di IPGen e degli IP-Core prodotti, si è scelto di focalizzare l’attenzione sull’interfaccia OPB IPIF. Questa è una scelta che non toglie
assolutamente generalità al discorso. Anzi, addirittura potremmo identificare tale
interfaccia come il “caso pessimo” in quanto, come si evince dal capitolo 3, essa
è l’infrastruttura di comunicazione più complessa da gestire e che comporta un
maggiore overhead in termini di area occupata sulla FPGA.
Sono stati attentamente analizzati due parametri:
• Il tempo di esecuzione del software, espresso in millisecondi, che descrive
la bontà del software;
89
CAPITOLO 6. RISULTATI SPERIMENTALI
• L’area occupata dall’IP-Core sulla FPGA, espressa in numero di slice, che
esprime una caratteristica non del software, bensì del codice VHDL generato.
In una prima sessione sono stati utilizzati otto core, partendo da componenti molto
semplici e leggeri a core piuttosto complessi. Essi sono qui di seguito elencati:
• Un semplice Counter, che conta da 0 al valore in ingresso n;
• Un Adder con operandi da 32 bit con controllo di overflow;
• Uno Squarer, che calcola il quadrato del numero binario in ingresso;
• Un contatore di frequenza;
• Un lettore hardware di file con filesystem di tipo FAT16;
• Una Division Unit;
• Una Unità Aritmetico Logica (ALU);
• Una Floating Point Unit (FPU), che esegue operazione su numeri binari
espressi in floating point.
All’interno della tabella 6.1 sono mostrati i risultati ottenuti nell’ambiente di
sviluppo ISE Project Navigator, simulando la collocazione degli IP-Core su una
FPGA Xilinx VirtexIIPro xc2vp7, con l’unica eccezione della FPU, per la quale,
a causa della notevole dimensione, è stata virtualmente utilizzata una VirtexIIPro
xc2vp30.
In primo luogo è stata effettuata la sintesi con XST del core preso singolarmente. Successivamente, è stato sintetizzato lo stub, e infine l’IP-Core. Prima di
analizzare i dati mostrati in tabella è necessario fare una premessa sul funzionamento di XST. Come descritto in [23], esso effettua in fase di sintesi di un IP-Core
importanti ottimizzazioni, con l’obiettivo di raggiungere un compromesso tra la
massimizzazione della frequenza di utilizzo e la minimizzazione dell’area occupata. Tale processo si basa fondamentalmente su due operazioni: la duplicazione
90
CAPITOLO 6. RISULTATI SPERIMENTALI
Counter
Adder
Squarer
F. Counter
FFR-Fat16
Div Unit
ALU
FPU
Core (# slice)
26
35
63
85
168
317
997
5394
Stub (# slice)
19
37
26
29
91
39
48
-123
Core+Stub (# slice)
45
72
89
114
259
356
1045
5271
IPIF (# slice)
39
62
24
35
80
60
17
153
IP-Core (# slice)
84
134
113
149
339
416
1065
5424
Overhead (# slice)
58
99
50
64
171
111
68
30
69,05
73,88
44,22
42,95
50,44
26,68
6,38
0,01
33
96
11
34
42
80
140
115
53
60
55
59
64
60
67
59
Overhead %
Dimensione delle
porte (bit)
Tempo (ms)
Tabella 6.1: Risultato dei test sugli otto core utilizzati
di registri (per minimizzare il “tempo di attraversamento” e quindi aumentare la
frequenza di utilizzo), e l’eliminazione di registri ridondanti o inutilizzati (per
minimizzare l’area occupata).
A livello teorico, è ragionevole supporre che l’interfaccia IPIF necessiti di
una quantità di area costante per tutti gli IP-Core; in realtà, proprio a causa delle
ottimizzazioni operate dallo strumento di sintesi, questo non si verifica. Ciò nonostante, l’area occupata dalla IPIF non mostra alcun trend particolare, quindi si
può escludere che essa dipenda in qualche modo dalla dimensione o dalla complessità del core interfacciato. È altresì intuitivo aspettarsi che, al crescere della
dimensione del core istanziato, l’occupazione percentuale di overhead introdotto
da IPGen, relativa alla dimensione totale dell’IP-Core, decresce in modo netto,
come è mostrato in figura 6.1. Dalla tabella emerge un dato senz’altro “strano”:
la dimensione dello stub insieme al core è in un caso minore di quella del core
stesso; ancora una volta questo è un effetto del processo di ottimizzazione operato
da XST.
Viene valutato ora il tempo di esecuzione del software; per ottenere una misura
il più reale possibile, tale dato è costituito dalla media di dieci tempi ottenuti
da altrettante esecuzioni del framework per ogni core. Si nota facilmente che
esso è indipendente dalla dimensione e dalle porte dei core e risulta con buona
approssimazione costante.
91
CAPITOLO 6. RISULTATI SPERIMENTALI
Figura 6.1: Occupazione percentuale di overhead introdotto da IPGen
Successivamente è stata condotta una seconda sessione di test. Sono stati utilizzati, in qualità di core da dare in ingresso a IPGen, dei dummy core opportunamente implementati. Per dummy core si intende una descrizione VHDL contenente, nella parte architetturale, il livello minimo di logica necessaria a far sì
che le porte dichiarate nella entity siano effettivamente utilizzate. Molto spesso si
tratta di un semplice assegnamento tra uscite e ingressi. Anche se questi non descrivono funzionalità utili e reali, offrono in fase di test numerosi vantaggi: infatti,
si possono condurre delle prove “mirate” a verificare l’efficacia o meno del framework in una data situazione, semplicemente scrivendo un dummy core adeguato.
Inoltre, possedendo una logica molto semplice (addirittura inesistente nella quasi
totalità dei casi), essi sono meno soggetti alle pesanti ottimizzazioni operate in
fase di sintesi da XST.
Il fatto che un dummy core abbia di per sé un’occupazione di area quasi sempre nulla non rappresenta un risvolto negativo: infatti è stato mostrato nella precedente sessione che i parametri considerati non dipendono in alcun modo dalla
dimensione del core. Tra le misure considerate non appare la dimensione del92
CAPITOLO 6. RISULTATI SPERIMENTALI
l’interfaccia IPIF: tale scelta deriva sia da una considerazione teorica già espressa
sopra, cioè che l’occupazione della IPIF dovrebbe essere costante, sia dal risultato
pratico ottenuto precedentemente, ossia la mancanza di correlazione tra complessità del core e occupazione dell’interfaccia. Ci si riferirà quindi solamente allo
stub, la cui dimensione dovrebbe ragionevolmente cambiare al variare del numero
e della larghezza dei segnali di ingresso e uscita dal core.
Per valutare a fondo le prestazioni di IPGen, sono stati creati nove dummy
core. I risultati dei test si possono vedere nella tabella 6.2, mentre in figura 6.2
si può osservare l’andamento dell’occupazione (espresso in numero di slice) dello stub al variare del dummy core considerato. Per esprimere i dati di interesse
di ciascun componente, cioè le porte di ingresso e di uscita, è stata adottata la
seguente simbologia: il primo numero rappresenta la quantità delle porte e il numero tra parentesi indica la dimensione in bit del segnale. Per esempio, “2 x (64)”
significa che il core ha (in ingresso o in uscita) due porte di dimensione pari a 64
bit.
dummy01
dummy02
dummy03
dummy04
dummy05
dummy06
dummy07
dummy08
dummy09
Porte in
Porte out
Tempo (ms)
Core (slice)
Stub (slice)
1 x (1)
1 x (32)
2 x (1)
2 x (32)
4 x (32)
2 x (64)
1 x (128)
1 x (64)
3 x (64)
1 x (1)
1 x (32)
2 x (1)
2 x (32)
4 x (32)
2 x (64)
1 x (128)
3 x (64)
1 x (64)
42,7
44,2
42,9
45,7
45,9
44,3
55,3
44,2
58,3
0
0
0
0
0
0
0
0
37
2
37
4
69
107
196
193
115
252
Tabella 6.2: Risultato dei test sui “dummy core”
Vengono ora fatte alcune considerazioni sui risultati ottenuti. Innanzitutto si
può notare che l’overhead di logica costituito dallo stub è molto basso quando gli
ingressi e le uscite del core sono segnali costituiti da un singolo bit. Si nota anche
che, al raddoppiare del numero di porte di dimensione 32 bit (si considerino i core
dummy02, dummy04 e dummy05), l’occupazione dello stub risulta anch’essa quasi
raddoppiata. Un altro risultato rilevante é il seguente: osservando i componenti
93
CAPITOLO 6. RISULTATI SPERIMENTALI
Figura 6.2: Occupazione dello stub generato per i “dummy core”
dummy05 e dummy06 si vede che, a parità di dimensione complessiva in bit sia
degli ingressi che delle uscite, la dimensione dello stub è molto maggiore nel caso
in cui si utilizzino segnali più grandi di 32 bit. Tale risultato è frutto del meccanismo particolare implementato per la gestione di questi segnali, soprattutto quelli
in ingresso (si veda la sezione 5.3.5). Proprio per verificare questa affermazione,
sono stati creati dummy08 e dummy09, che utilizzano porte da 64 bit. Il primo
presenta un segnale in scrittura e tre in lettura, mentre il secondo ne è il duale,
possedendo tre ingressi e una sola uscita. Lo stub di dummy08 ha un’occupazione
che, come era lecito aspettarsi, è minore di quello di dummy06 e maggiore di dummy05. La dimensione dello stub di dummy09 è invece maggiore di quella di tutti
gli altri essendo l’unico core che presenta bene tre ingressi di dimensione 64 bit.
Per quanto riguarda i tempi di esecuzione, essi sono pressoché costanti, anche
se rivelano un leggero trend crescente all’aumentare del numero e della dimensione dei porte di ingresso dei core.
94
CAPITOLO 6. RISULTATI SPERIMENTALI
6.2
Test di funzionamento
Con l’intento di validare la metodologia proposta, è stato necessario effettuare
alcune simulazioni del funzionamento degli IP-Core generati dal framework, condotte utilizzando ModelSim (sezione 1.2.3). Il core scelto per verificare il corretto funzionamento dei componenti generati è un addizionatore a 32 bit, il quale
possiede due ingressi, gli addendi, e un’uscita, il risultato. Sono necessarie quindi
due operazioni di scrittura e una di lettura al fine di compiere un ciclo completo di applicazione del modulo. Sono stati simulati i tre IP-Core generati con le
interfacce supportate.
Figura 6.3: Simulazione di un IP-Core con interfaccia PSelect
In primo luogo viene considerato l’IP-Core che integra l’interfaccia PSelect
sul bus OPB, la cui simulazione è mostrata nel grafico temporale in figura 6.3,
dove i segnali che rappresentano dati o indirizzi sono espressi per chiarezza in
codifica esadecimale. Il valore iniziale dell’indirizzo presente sul bus corrisponde
al base address assegnato al componente in fase di istanziazione nel sistema. in
quanto il primo registro è posizionato all’interno dello spazio di indirizzamento
dell’IP-Core in posizione zero. In tal modo, essendo l’ingresso opb_rnw posto
a zero (indicando così un’operazione di scrittura), il contenuto della linea dati
entrante viene copiato nel registro corrispondente al primo addendo. In modo
identico viene successivamente scritto il valore del secondo operando, il cui registro si trova all’indirizzo 4. A questo punto il core computa la somma che viene
letta dal master, innalzando il segnale opb_rnw e ponendo sulla linea indirizzi il
valore 0, che corrisponde in fase di lettura al registro contenente il risultato.
95
CAPITOLO 6. RISULTATI SPERIMENTALI
Figura 6.4: Simulazione di un IP-Core con interfaccia OPB IPIF
La simulazione dell’IP-Core interfacciato tramite OPB IPIF è raffigurata in
figura 6.4; il procedimento di scrittura/lettura è sostanzialmente simile a quello di
PSelect. Si noti che in questo caso lo stub, per gestire i registri, utilizza i vettori di
CE forniti da IPIF. Inoltre, durante la fase di lettura del risultato, si vede che esso
viene posto sul segnale IPIC IP2Bus_data sul fronte di discesa del clock; questo
è necessario poiché, se tale valore venisse scritto durante il fronte di salita, la IPIF
non farebbe in tempo a elaborarlo e verrebbe perso in tal modo un intero ciclo di
lettura, corrispondente generalmente a tre cicli di clock.
Figura 6.5: Simulazione di un IP-Core con interfaccia Wishbone
L’interfacciamento con Wishbone (figura 6.5) si dimostra meno complesso dei
precedenti. In questo caso il valore della linea indirizzi del bus è espressa in codifica binaria, in quanto composta da soli 8 bit. Dopo aver impostato il valore dei
parametri necessari a inizializzare la comunicazione (secondo il protocollo de96
CAPITOLO 6. RISULTATI SPERIMENTALI
scritto nella sezione 3.2), si procede con la fase di scrittura dei registri in ingresso,
innalzando il segnale we_i e ponendo a “011” il valore dei primi tre bit del segnale
adr_i, che corrispondente al numero identificativo dell’IP-Core all’interno del sistema. Assegnando in successione i valori “00000” e “00001” ai cinque bit meno
significativi di adr_i, il valore presente nel bus dati viene copiato nei registri corrispondenti agli ingressi del core. Per leggere la somma, il master abbassa we_i e
scrive l’indirizzo opportuno, in modo tale che il risultato il risultato venga copiato
sulla linea dati in uscita dall’IP-Core.
97
Capitolo 7
Conclusione e sviluppi futuri
Durate la fase di progettazione di un sistema embedded, la realizzazione delle
interfacce dei componenti che devono dialogare tra di loro mediante un’opportuna
infrastruttura di comunicazione è la parte meno creativa e più meccanica di tutto
il processo. Questo lavoro di tesi è stato concepito per sgravare il progettista da
questo lavoro ripetitivo, migliorando il time-to-market del dispositivo prodotto
e dando la possibilità all’utente di focalizzare la propria attenzione sulla parte
realmente funzionale della propria architettura: il core.
IPGen, per come è stato concepito, ha una struttura interna fortemente modularizzata (sezione 5.1). Questo aspetto permette al framework di essere espanso
senza la necessità di modificare porzioni consistenti di codice già scritto. In futuro potranno essere implementati nuovi writer al fine di supportare un maggior
numero di bus assieme alle loro interfacce.
Come mostrato nel capitolo 6, IPGen è uno strumento già funzionante con
discrete prestazioni. Si può dire con tutta sicurezza che esso rappresenta una vera e
propria novità all’interno del settore della progettazione di IP-Core. Infatti, come
si può vedere nel capitolo 2 e nella sezione 4.4, non esiste un altro strumento che
attualmente offra funzionalità analoghe. Inoltre, sebbene IPGen è stato pensato
per essere impiegato all’interno di un flusso di riconfigurabilità dinamica, esso è in
realtà un software indipendente, che può essere utilizzato ogniqualvolta si debba
creare un IP-Core. Ovviamente, l’ampiezza del campo di utilizzo del software
99
CAPITOLO 7. CONCLUSIONE E SVILUPPI FUTURI
dipende dal numero delle interfacce supportate.
Allo stato attuale, esso supporta il bus OPB con interfacce PSelect, IPIF e
Wishbone. L’interfaccia OPB PSelect viene sfruttata dal software utilizzando
tutte le funzionalità che essa mette a disposizione. Ciò non vale per IPIF, della
quale IPGen sfrutta le capacità di decodifica degli indirizzi, ma non i servizi aggiuntivi quali Interrupt Service Controller e registri FIFO. Il bus Wishbone viene
supportato in modalità Point-to-Point e Shared Bus, mentre le ulteriori tipologie di connessione non vengono utilizzate. Quindi, sebbene IPGen garantisca
un interfacciamento sia con OPB che con Wishbone, possibili sviluppi comprendono, oltre all’aggiunta del supporto a altre eventuali interfacce, l’ampliamento e
l’irrobustimento del supporto a questi bus.
Al fine di allargare il campo di applicazione del framework, è in fase di studio
l’implementazione del supporto per l’interfacciamento di IP-Core di tipo master,
e in particolare di componenti con accesso diretto alla memoria (DMA).
100
Bibliografia
[1] Alberto Donato, Fabrizio Ferrandi, Massimo Redaelli, Marco D. Santambrogio, and Donatella Sciuto. Caronte: A complete methodology for the
implementation of partially dynamically self-reconfiguring systems on fpga
platforms. In FCCM, pages 321–322, 2005.
[2] Fabrizio Ferrandi, Marco D. Santambrogio, and Donatella Sciuto. A design methodology for dynamic reconfiguration: The caronte architecture. In
IPDPS, 2005.
[3] Xilinx Inc. Development System Reference Guide. Xilinx, Inc., 2001.
[4] Semiconductor intellectual property core. Wikipedia, the free encyclopedia.
[5] IP core. Whatis.com, the leading IT encyclopedia and learning center.
[6] Andrew S. Tanenbaum. Structured Computer Organization - 4th Edition.
Prentice Hall, 1999.
[7] Xilinx Inc.
Two flows for Partial Reconfiguration: Module Based or
Difference Based. Technical Report XAPP290, Xilinx Inc., September 2004.
[8] Xilinx Inc. Embedded System Tools Reference Manual. Xilinx Inc., 2005.
[9] Xilinx Inc. XST User Guide. Xilinx Inc., 2005.
[10] MentorGraphics. ModelSim GUI Reference. MentorGraphics, 2004.
[11] OCP-IP Association. The importance of Sockets in SOC Design.
101
[12] OCP-IP Association. Open Core Protocol Specification 2.1.
[13] Tien-Lung Lee and Neil W. Bergmann. An Interface Methodology for Retargettable Fpga Peripherals. In Engineering of Reconfigurable Systems and
Algorithms, pages 167–173, 2003.
[14] Tien-Lung Lee and Neil W. Bergmann.
Interfacing Methodologies for
IP Re-use in Reconfigurable System-On-Chip. Microelectronics: Design,
Technology and Packaging, Vol. 5274, 2004.
[15] Impulse Accelerated Technologies.
Impilse CoDeveloper User Guide.
Impulse Accelerated Technologies, 2006.
[16] System-on-chip. Wikipedia, the free encyclopedia.
[17] IBM corporation.
The CoreConnect Bus Architecture, white paper.
International Business Machines Corporation., 2004.
[18] IBM Corporation.
On-Chip Peripheral Bus, Architecture Specification
version 2.1.
[19] Xilinx Inc.
Designing Custom OPB Slave Peripherals for MicroBlaze.
Xilinx, Inc., 2002.
[20] Xilinx Inc. OPB IPIF (v3.01a). Xilinx, Inc., 2004.
[21] Silicore OPENCORES.ORG.
WISHBONE system-on-chip (SoC) inter-
connection architecture for portable IP cores. September 2002. Revision:
B.3.
[22] F. Ferrandi, G. Ferrara, R. Palazzo, V. Rana, and M. D. Santambrogio. Vhdl
to fpga automatic ipcore generation: A case study on xilinx design flow.
In 20th IEEE International Parallel and Distributed Processing Symposium
(IPDPS’06) - Reconfigurable Architecture Workshop - RAW, 2005.
[23] Hitesh Patel. Synthesis and Implementation Strategies to Accelerate Design
Performance. Xilinx White Paper 229, 2005.
102
Ringraziamenti
È stata dura, ma ce l’abbiamo fatta.
Sono passati tre anni dall’inizio di questo percorso, e abbiamo finalmente raggiunto la prima tappa fondamentale. Tre lunghi anni che hanno comportato molte
fatiche e preoccupazioni, ma non solo; fortunatamente abbiamo incontrato tanta gente, tanti amici che hanno contribuito a rendere questo cammino molto ma
molto più sereno e divertente: Alessio, Cesco, Malex, Marco, Paco, Pasca, Ste,
Supremo e tutti gli altri con cui abbiamo trascorso questo periodo. Il primo
ringraziamento va a loro.
Questa tesi non sarebbe mai esistita se non ci fosse stata una persona a istruirci,
spronarci e motivarci. Un grazie di cuore a Santa!!!, che ci ha fatto capire come
lavorando in gruppo si possano ottenere grandi risultati. A proposito di gruppo, ci
teniamo a ringraziare tutti i ragazzi di DRESD, in particolare Matteo e Vincenzo
per l’aiuto che ci hanno dato.
Matteo
Innanzitutto un grazie immenso alla mia famiglia, grazie per il sostegno che mi
dà ogni giorno e grazie per tutti i principi che mi ha insegnato nel corso di questi
22 anni. Questa tesi è il mio ringraziamento per tutto questo.
Voglio ringraziare tanto, infinitamente, colei che mi è vicina da due anni, che mi
ha aiutato, consolato, spronato nei momenti difficili, grazie a lei sono diventato
migliore. Ste, ti voglio bene.
103
E adesso è arrivato il momento di ringraziare un uomo che è venuto dalle Valli
per allietare e rendere produttiva ogni mia giornata! Con Alessandro ho condiviso
esperienze di studio, di lavoro, di festa, di estremo divertimento. Grazie per aver
condiviso con me queste esperienze di vita.
Infine voglio ringraziare tutti i miei amici, soprattutto perchè nonostante le mie
sparizioni per (anche lunghi) periodi di tempo, mi fanno comunque sentire sempre la loro amicizia ed ogni volta che ci ritroviamo siamo sempre legatissimi,
come se trascorressimo assieme ogni ora del nostro tempo.
Alessandro
Ho tante persone da ringraziare... inizio da coloro che mi hanno supportato e
sopportato per tutto questo tempo: i miei genitori. Grazie veramente di cuore per
tutto quello che avete fatto e fate per me. Restando in ambito familiare, è doveroso
ringraziare il bassista più virtuoso della Valle Seriana: mio fratello Massimo, colui
che mi ha avvicinato alla Musica, compagna fidata di sempre.
E poi, come dimenticare la Compagnia (sì, con la C maiuscola)? Grazie per tutti i
week-end "shalli" che abbiamo passato insieme, non sapete quanto abbiano contribuito al raggiungimento di questo risultato.
E inoltre vorrei ringraziare ma veramente dibbruno il mio egregio collega Matteo,
validissimo compagno di studi e soprattutto grande amico.
Infine desidero ringraziare la persona meravigliosa che mi sta vicino da quattro
anni e che mi ha reso migliore: grazie amore mio, grazie di tutto.
104
Tesi scritta in LATEX 2ε
Stampata il 21 Settembre 2006
Scarica

ipgen: un framework per la generazione automatica di ip