politecnico di milano
Transcript
politecnico di milano
POLITECNICO DI MILANO
FACOLTÁ DI INGEGNERIA
CORSO DI LAUREA IN INGEGNERIA INFORMATICA
Realizzazione di un algoritmo di controllo per la
riconfigurabilità dinamica di moduli SystemC
Relatore:
Correlatore:
Fabrizio Ferrandi
Marco Santambrogio
Tesi di Laurea di
Andrea Campana
Matricola n. 657904
Anno Accademico 2004/2005
Dedicato alla mia famiglia,
a tutti i miei amici, e a tutte le
persone che mi hanno aiutato
a realizzare questo lavoro
1
2
INDICE
1. Introduzione
1.1. Struttura
2. Stato dell’arte
2.1. SystemC
2.1.1. Introduzione
2.1.2. Descrizione di SystemC
2.2. Riconfigurabilità
2.2.1. FPGA
2.2.2. Riconfigurabilità dinamica
2.2.3. Caronte
2.2.3.1. Metodologia
2.2.3.2. Descrizione dell’architettura
2.3. Progetto PandA
2.3.1. Struttura
2.3.2. Flusso di sviluppo
3. Sviluppo dell’algoritmo
3.1. Strutture di PandA utilizzate
3.1.1. La struttura tree
3.1.2. La struttura circuit
3.2. Implementazione dell’algoritmo
3.2.1. Descrizione del funzionamento
3.2.2. Struttura dell’algoritmo
3.2.3. Caso d’uso e scenari di applicazione
4. Risultati sperimentali
5. Conclusioni e sviluppi futuri
Bibliografia
Ringraziamenti
3
Indice delle figure e dei diagrammi
Numero di
riferimento
1.1
1.2
2.1
2.2
2.3
2.4
2.5
3.1
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
3.10
4.1
Descrizione
Confronto tra SystemC e sistemi di model…
Struttura dei componenti di SystemC
Struttura logica dell’FPGA
Flusso di sviluppo di Caronte
Architettura di Caronte
Rappresentazione di una Blackbox
Flusso di sviluppo del progetto PandA
Struttura di collegamento tra due generici nodi
Struttura del circuit
Classe Manager_control
Caso d’uso della classe
Dichiarazione di un oggetto manager_control
Esecuzione della funzione execute_control
Esecuzione della funzione firstof
Esecuzione della funzione next_module
Esecuzione della funzione size_of_group
Esecuzione della num_groups
Codice di prova
Numero della
pagina
9
10
14
18
21
22
26
28
30
33
36
37
38
39
39
40
41
43
Indice tabelle
Numero di
riferimento
3.1
Descrizione
Numero della
pagina
45
Risultati delle prove
4
5
Capitolo 1
Introduzione
Nel campo della realizzazione di sistemi digitali, sono stati sviluppati diversi
sistemi per poter modellizzare le architetture hardware tramite delle descrizioni, in
particolare sono nati linguaggi che permettono queste descrizioni, i quali
utilizzano applicazioni per la simulazione o la sintesi di questi modelli, per
arrivare ad eseguire delle simulazioni virtuali o delle prove di funzionamento.
Questi sistemi forniscono inoltre la possibilità di compiere riconfigurazioni di ciò
che si è descritto, vale a dire che è possibile effettuare delle modifiche di ciò che si
è inizialmente sviluppato, apportando dei cambiamenti o realizzando un’altro
modello da zero, utilizzando lo stesso sistema di modellizzazione.
Inoltre è possibile eseguire riconfigurazioni di queste descrizioni, mentre si sta
eseguendo una simulazione del modello, questo metodo di riconfigurazione viene
denominato riconfigurabilità dinamica.
Attraverso determinate metodologie si selezionano quali moduli devono essere
riconfigurati all’interno del modello. A questo punto nasce un problema, quello di
definire quali parti del modello sono compatibili tra loro, cioè quali di queste parti
sono intercambiabili, quando si effettua la riconfigurazione.
In questo caso si considera un modello costituito da moduli SystemC, infatti, lo
scopo dell’algoritmo presentato in questo documento di tesi è di eseguire una
classificazione in base dei moduli scritti con linguaggio di alto livello (il SystemC),
in base alle compatibilità riscontrate tra loro.
Per compatibilità di due o più moduli s’intende che questi abbiano lo stesso numero
di porte d’uscita, inoltre queste porte devono essere in corrispondenza biunivoca
rispetto al tipo.
In pratica si considerano compatibili due moduli se hanno lo stesso numero di porte
e che queste abbiano lo stesso tipo, eseguiti questi confronti otteniamo come
risultato un insieme di gruppi di moduli, divisi in base alla compatibilità.
Questa applicazione è stata sviluppata per essere inserita in contesto più grande, in
particolare in un sistema che utilizza la riconfigurabilità dinamica, infatti
l’algoritmo serve per trovare facilmente quali moduli sono compatibili tra loro per
poterli sostituire all’interno del processo di riconfigurazione.
All’interno di questa documentazione saranno date maggiori spiegazioni sul
funzionamento e lo sviluppo di questo algoritmo.
6
1.1 Struttura
La presente tesi è suddivisa nei seguenti capitoli:
• Capitolo1 Introduzione alla tesi.
• Capitolo2 Propone il contesto di base del lavoro di tesi, descrivendo in
particolare cos’è il SystemC, cosa significa riconfigurabilità ed è spiegato
che
cos’è
il
progetto
PandA.
• Capitolo3 Descrizione dell’algoritmo e delle strutture dati utilizzate.
• Capitolo4 Descrizione
dell’algoritmo.
dei
test
effettuati,
• Capitolo5 Conclusioni e possibili sviluppi futuri.
7
sull’implementazione
Capitolo 2
Stato dell’arte
In questo capitolo sono presentati alcuni strumenti utilizzati all’interno
dell’algoritmo, verrà descritta la libreria SystemC, successivamente definita la
riconfigurabilità, infine sarà data una presentazione del progetto PandA.
2.1 SystemC
SystemC [1] è una libreria di classi del linguaggio C++, la quale estende questo
linguaggio, andando a crearne uno nuovo che prende il nome da questa libreria.
Si introduce questa libreria per capire che cos’è un modulo scritto in SystemCe
come viene descritto un componente hardware.
Nei seguenti paragrafi viene descritto come funziona questa libreria e quale è il suo
obiettivo, presentando alcune sue strutture di base.
2.1.1 Introduzione
Il SystemC è una di libreria che estende il linguaggio C++, viene utilizzata per la
creazione di modelli software, architetture hardware e per interfacce
Hardware/software per la progettazione a livello di sistema [2].
Tale libreria può essere utilizzata all’interno dei classici ambienti di sviluppo C++
per poter creare un modello Hw/Sw a livello di sistema.
Questo dà la possibilità agli sviluppatori di creare un modello di un hardware che si
vuole sviluppare, attraverso questo linguaggio, in questo modo è possibile eseguire
questo modello in un sistema di simulazione per valutare il suo funzionamento.
Oppure è possibile sintetizzare il modello per vedere il suo reale comportamento,
questo permette la creazione di prototipi descritti con questo linguaggio, senza
realizzare direttamente l’architettura.
L’ Open SYSTEMC Initiative (OSCI), l’organizzazione che per prima propose
l’uso di questo linguaggio, scelse il C++ per questi due motivi:
• il primo è che il C++ risulta essere un ottimo linguaggio per gli algoritmi
software e per la specifica delle interfacce, perché fornisce l’astrazione
necessaria per la parte di controllo e per quella dei dati per sviluppare una
descrizione
del
sistema
compatta
ed
efficiente.
8
Inoltre questo linguaggio è già conosciuto dai progettisti, quindi risulta
essere
più
familiare.
• Il secondo motivo è che il C++ è un linguaggio orientato ad oggetti, quindi
può essere facilmente esteso con l’aggiunta di nuove classi.
2.1.2 Descrizione di SystemC
Grazie all’estendibilità offerta dal C++ è stato possibile integrare questa libreria
con quelle standard per ottenere un nuovo linguaggio.
Questo linguaggio offre un insieme di funzioni in più che permettono
l’elaborazione di costrutti hardware, a differenza però del VHDL e del Verilog
(sistemi per la descrizione dello hardware), il SystemC fornisce la possibilità di
progettare ad un livello più alto.
Figura 1.1 : Confronto tra SystemC e sistemi di modellizzazione dell’hardware
Nella Figura 1.1 viene confrontato il SystemC e alcuni linguaggio di specifica
dell’hardware, in particolare si può notare come il SystemC riesce a coprire tutti
passaggi dai requisiti di progetto, fino al RTL (Register Transfer Level), cioè alla
specifica dei registi.
9
Figura 1.2 : Struttura dei componenti di SystemC
La Figura 1.2 delinea come è composta una struttura hardware descritta con il
linguaggio SystemC, qui di seguito saranno presentati alcuni di questi componenti
dandone una descrizione generale per quelli di maggiore importanza.
Sc_Module: un modulo SystemC è un blocco con cui questo linguaggio partiziona
il design da ottenere, permettendo di spezzare un sistema complesso in diversi
sottosistemi più semplici, in pratica il modulo non è altro che il contenitore di base
di questo linguaggio.
Ecco come si definisce un modulo:
#include <systemc.h>
SC_MODULE(module_name) {
MODULE_BODY
};
All’interno di un modulo è possibile definire e dichiarare i seguenti elementi:
-
Porte
Costruttori
Distruttori
Processi
10
- Funzioni
- Istanze di dati
- Istanze di canali
I moduli SystemC sono molto simili alle classi del linguaggio C++, infatti possono
contenere funzioni, variabili, costruttori e distruttori di classe.
In particolare i costruttori di classe in SystemC prendono il nome di SC_CTOR, e
possono
eseguire
le
seguenti
operazioni:
-
Inizializzano e/o allocano sotto strutture;
Collegano tra loro diverse sotto strutture;
Registrano processi con il kernel del SystemC;
Provvedono a una sensibilità statica;
Eseguono operazioni definite dal programmatore che li costruisce;
Sc_process: Un processo SystemC è un componente tipo funzione o metodo della
classe di un sc_module che viene evocato dallo scheduler nella simulazione
SystemC.
Questo processo è definito come l’unità base di questa libreria.
Ecco un prototipo di un processo SystemC:
void PROCESS_NAME(void);
Il processo SystemC non ha bisogno di argomenti e non ritorna nessun valore.
Il più semplice tipo di processo è l’sc_thread, concettualmente simile al thread dei
linguaggi software, infatti è un metodo per eseguire in parallelo più processi in
maniera tale che più operazioni possono essere effettuate in concorrenza (eseguite
nello stesso tempo) rispetto ad altre.
Per poter registrare un processo come sc_thread deve essere dichiarato all’interno
del costruttore del modulo.
In particolare visto l’uso di sistemi di concorrenza (con i thread), all’interno di
questo linguaggio sono definite delle nozioni di tempo come ad esempio:
SC_SEC // secondi SC_MS // millisecondi SC_US // microsecondi
SC_NS // nanosecondi SC_PS // picosecondi SC_FS // femtosecondi
Un caso più importante in cui sono utilizzate queste nozioni di tempo è l’Sc_start():
metodo chiave che definisce l’inizio della simulazione del modulo SystemC.
Se non è definito nessun argomento continua la simulazione all’infinito, se invece è
indicato un valore ad esempio sc_start (max_sc_time) continua la simulazione fino
a max_sc_time.
Per precisare meglio, in questo caso la simulazione è eseguita per un minuto:
sc_start(60.0,SC_SEC).
11
Un concetto importante introdotto nel linguaggio C++ è la definizione di classe
astratta, tale definizione sta ad indicare una classe non è utilizzata direttamente, ma
usata tramite la derivazione di sotto-classi che ereditano da questa.
Per essere più precisi le classi astratte contengono solo funzioni virtuali, cioè
funzioni di cui non esiste un’implemetazione, e ogni classe che eredita dalla classe
astratta deve riscrivere le funzioni astratte.
In altre parole le classi derivate devono fornire l’ implementazione delle funzioni
virtuali.
Nel caso del SystemC un’interfaccia è una classe astratta che deriva da sc_interface
e definisce solo dichiarazioni virtuali di metodi che fanno riferimento a canali e
porte.
Un canale in SystemC è una classe che implementa una o più interfacce ed eredita
da sc_channel o sc_prim_channel, esso implementa tutti i metodi ereditati dalle
classi di interfacce, usando le interfacce stesse per eseguire la connessione.
Date le definizioni di interfacce e di canali, è possibile dare ora la definizione di
porta, visto che è una classe che eredita da un’interfaccia SystemC.
Le porte permettono l’accesso da e verso esterno dei moduli attraverso dei canali,
in particolare questa è la sintassi per definire una porta in SystemC:
sc_port<interface> portname;
Dove interface indica la classe da cui deriva la porta, quindi che tipo di oggetto
deriva, e portname è il nome che si assegna alla porta.
Ecco un semplice esempio di dichiarazione delle porte:
SC_MODULE(stereo_amp) {
sc_port<sc_fifo_in_if<int> > soundin_p;
sc_port<sc_fifo_out_if<int> > soundout_p;
};
Esistono diverse interfacce con cui vengono istanziate le porte, in particolare nel
lavoro svolto dall’algoritmo qui presentato si fa riferimento al tipo con cui sono
definite le porte, infatti, come già premesso, l’algoritmo deve valutare se più
moduli hanno lo stesso numero di porte con lo stesso tipo, per definire se questi
moduli sono compatibili.
Oltre a questi costrutti il SystemC come ogni linguaggio, ha diversi tipi con cui è
possibile definire variabili segnali porte ecc… .
Rispetto ai classici tipi del C++ che sono tutti supportati dalla libreria (in alcuni
casi aggiungendo il prefisso sc), ne sono aggiunti altri, in particolare sono inseriti
tipi per la descrizione di circuiti logici, come ad esempio sc_bit, sc_logic, sc_lv
ecc.. che permettono l’espressione di variabili tipiche dei circuiti hardware, ma non
previsti nel C++.
12
2.2 Riconfigurabilità
In questa sezione verrà descritto il significato di riconfigurabilità, partendo da un
esempio di architettura hardware riconfigurabile (l’FPGA), per poi arrivare alla
descrizione della riconfigurabilità dinamica parziale.
Prima di tutto è necessario definire cosa s’intende per configurazione, in particolare
nel campo dei circuiti logici.
La configurazione di un circuito indica quali componenti lo creano, in che modo
sono collegati tra loro, e quali segnali riceve o invia all’esterno.
In pratica la configurazione indica come è fatto e come si comporta il circuito
costruito.
Per poter arrivare a definire la riconfigurabilità, è necessario introdurre un esempio
di architettura hardware che può accettare diverse configurazioni, l’FPGA che
verrà presentata nel prossimo paragrafo.
2.2.1 FPGA
L’FPGA (field programmable array) è un array di blocchi logici programmabili,
infatti è possibile programmare una configurazione dei blocchi logici in modo che
eseguano un determinato componente.
Infatti, l’FPGA è una classe di integrati che possono essere riconfigurati per la
progettazione di un circuito digitale.
Grazie a questa opportunità di realizzare diverse configurazioni, le FPGA vengono
sempre di più utilizzate nel campo della prototipazione, cioè nella creazione di
prototipi di integrati che verranno poi realizzati con tecnologie standard.
Inoltre le FPGA vengono spesso utilizzate per progetti di piccole dimensioni ma
che richiedono un’elevata potenza di calcolo.
Come già descritto in precedenza, l’FPGA è un integrato formato da diversi
elementi, ecco un analisi dei singoli elementi, mostrati in figura 2.2, che
compongono una FPGA:
Blocchi logici configurabili (CLB Configurable Logic Block);
Blocchi perimetrali per funzioni di I/O (IOB);
Blocchi di memoria RAM;
Risorse riconfigurabili per l’interconnessione tra i vari blocchi;
13
Figura 2.1 : Struttura logica dell’FPGA
Qui di seguito sarà data una descrizione degli elementi che compongono una
FPGA:
I blocchi logici programmabili, o più semplicemente CLB (Configurable
Logic
Block),
sono
il
cuore
di
una
FPGA.
Una CLB è composta da un numero fissato di unità logiche chiamate anche
celle logiche. A loro volta le celle logiche sono composte da un generatore fi
funzioni a 4 bit di ingresso, un flip-flop e alcuni circuiti aggiuntivi;
Gli IOB (input output block) sono i blocchi logici che hanno come funzione
la comunicazione dei blocchi interni con il mondo esterno, permettono
l’interfacciamento dei pin esterni con la logica interna all’integrato.
Infatti ogni blocco è collegato con un pin esterno che può essere configurato
come
uscita
ingresso
o
pin
bidirezionale;
La RAM interna è organizzata a blocchi, e può essere configurata sia per
indirizzamento che per temporizzazioni di accesso;
I vari blocchi logici possono essere collegati tra loro tramite interconnessioni
riconfigurabili.
Grazie a questa architettura è possibile realizzare diversi circuiti solamente
programmando di volta in volta la struttura che vogliamo realizzare all’interno
dell’integrato.
14
Visto che la logica interna è realizzata caricando dati da una memoria esterna
all’integrato dell’FPGA, è così possibile poter cambiare questa logica a seconda
delle esigenze.
Questo spiega come l’FPGA è un’architettura riconfigurabile infatti è possibile
inserire all’interno di questo integrato diverse configurazioni di circuiti logici,
grazie alla sua struttura generica.
Inoltre grazie a software forniti dai costruttori delle FPGA è possibile creare
modelli di architetture hardware, e configurare un integrato perchè realizzi questa
architettura.
La stragrande maggioranza delle applicazioni che sono implementate su una FPGA
usano una sola configurazione allocata sul dispositivo.
Questo sta a significare che tale applicazione non potrà avere variazione, mentre
esegue l’implementazione, quindi ha una configurazione per cui il suo modo di
“comportarsi” non cambi nel tempo, ciò significa che il circuito non subirà
variazioni mentre funziona.
Un’altra strategia di utilizzo di questi integrati, consiste nell’implementare un
applicazione con più configurazioni sulla stessa FPGA, con questo tipo di
approccio l’applicazione viene suddivisa in operazioni che possono non essere
eseguite contemporaneamente.
Questo nuovo approccio di utilizzo delle FPGA viene detta riconfigurabilità
dinamica.
2.2.2 Riconfigurabilità dinamica
Con il termine di riconfigurabilità dinamica si intende la possibilità di eseguire la
riconfigurazione dei blocchi logici di una FPGA, mentre le parti dell’applicazioni
non coinvolte continuano a rimanere attive, quindi si esegue una o più modifiche
mentre l’applicazione viene eseguita.
La riconfigurazione può essere distinta in altri due modi, in base a chi esegue le
modifiche sull’applicazione, e esattamente sono:
- la riconfigurazione interna: che prevede che sia parte della logica
interna all’FPGA ad effettuare le modifiche sulla configurazione.
Questo determina che sia la parte fissa (quella che non viene
modificata durante la riconfigurazione) ad effettuare questa
operazione;
- la riconfigurazione esterna: questa necessita di un dispositivo esterno
che si occupi delle modifiche da effettuare sulla logica, inoltre deve
effettuare un controllo in modo che non sia modificata la parte di
logica che è attualmente in esecuzione;
15
Grazie alle possibilità offerte da una FPGA di poterla configurare più volte, si
ottiene una grande flessibilità nella progettazione di un hardware, con la possibilità
di realizzare un grande numero di diversi sistemi riconfigurabili.
Infatti è possibile distinguere la progettazione di un sistema riconfigurabile
dinamicamente in due diversi modelli:
- Riconfigurazione totale;
- Riconfigurazione parziale;
Il primo modello identifica un sistema di progettazione se vogliamo effettuare delle
modifiche alla descrizione oppure se vogliamo realizzarne una nuova, è necessario
riscrivere completamente il modello sviluppato, infatti, si deve cambiare
completamente la configurazione implementata sull’FPGA.
Il secondo modello di sviluppo per applicazioni riconfigurabili, prevede la
possibilità di riconfigurare una parte della FPGA, mentre la parte restante non
viene intaccata.
La possibilità introdotta dalle FPGA di riconfigurare parzialmente l’applicazione in
esecuzione risulta essere utile per applicazioni che richiedono il caricamento di
diverse configurazioni sulla stessa area del dispositivo oppure che necessitano di
flessibilità per cambiare parti della configurazione attuale.
Per le attuali schede FPGA si possono delineare due differenti modelli di
riconfigurazione parziale, e sono i seguenti:
- basata sui moduli [4]: questo tipo di riconfigurazione si sofferma in
particolare
sulla
riconfigurazione
dei
moduli.
I quali costituiscono il progetto dell’architettura completa, grazie
all’utilizzo di uno speciale bus che preserva la comunicazioni tra i
moduli che sono direttamente o indirettamente coinvolti nelle
riconfigurazione.
- basata sulla differenza [4]: questa riconfigurazione può essere ottenuta
modificando l’architettura e generando un flusso di bit di
configurazione ottenuto dalla differenza dei due design.
Metodo che può risultare molto più rapido grazie al fatto che il flusso
di bit può essere molto piccolo.
2.2.5 Caronte
In questa sezione viene presentata la metodologia conosciuta con il nome di
Caronte, che è un flusso di progettazione di architetture che utilizzano la
riconfigurabiulità dinamica.
16
Questa metodologia è un esempio di applicazione dell’approccio di
riconfigurabilità parziale basato sui moduli. In particolare verrà prima di tutto
definita come funziona la metodologia, dopodichè viene introdotta la sua
architettura e i suoi componenti.
2.2.5.1 Metodologia
Caronte è una metodologia [5] di progettazione che permette di implementare una
specifica definita con un linguaggio di alto livello su un sistema parzialmente e
dinamicamente riconfigurabile.
Questa metodologia presenta molte caratteristiche, tra le più importanti possiamo
sottolineare:
- l’utilizzo della riconfigurazione parziale dinamica;
- l’uso di un metodo di riconfigurazione interna (un microprocessore
della FPGA gestisce le riconfigurazioni attraverso un componente
hardware, in modo da ridurre i tempi di riconfigurazione);
- l’uso di un sistema operativo, LINUX, facilitando in questo modo la
riconfigurazione, tramite l’utilizzo di un device driver, che permettono
la gestione di sistemi complessi con molteplici operazioni;
Questa metologia non sostituisce il flusso standard di progettazione anzi si va ad
inserire all’interno di esso migliorandolo grazie alle possibilità introdotte da
Caronte stesso (vedi Figura 2.3).
17
Figura 2.2 : Flusso di sviluppo di Caronte
Dalla figura 2.3 si può notare che Caronte accetta ciò che è stato svolto nelle fasi
precedenti (quella di descrizione del sistema, e quella di analisi e partizionamento
del sistema), introducendo tre sottofasi comprese in questa metodologia.
Qui di seguito vengono presentate le tre sottofasi di Caronte:
9 HW-SSP, (Hardware Static System Photo Phase);
9 Design;
9 Creazione dei bitstream;
18
Vengono ora date le descrizioni di ogni singola sottofase di Caronte:
fase HW-SSP: lo scopo di questa fase è la realizzazione di foto statiche del
sistema, che sono delle descrizioni di EDK (programma utilizzato nello
sviluppo di una applicazione da inserire in una FPGA) che verranno
riconfigurate
a
tempo
di
esecuzione.
Questo insieme di descrizioni è composto da una parte di sistemi che
condividono una porzione fissa della configurazione, ma si differenziano
per quanto riguarda la parte riconfigurabile;
fase Design: questa fase prende come input le foto statiche realizzate da
quella precedente e raccoglie informazioni per elaborare tutti i bitstream.
Il tutto per poter implementare la configurazione interna e stabilire l’area dei
vari componenti che devono essere inseriti all’interno della struttura (questa
operazione e facilitata dal programma con sui si elaborano le applicazioni da
inserire in una FPGA);
fase di Creazione dei bitstream: in questa fase vengono creati tutti i bitstream
necessari per implementare l’applicazione su una FPGA;
In pratica Caronte riceve in ingresso un’applicazione partizionata e composta da
black box (vedi descrizione nel paragrafo successivo), che deve essere
implementata su una FPGA.
Da queste realizza delle foto statiche delle possibili configurazioni, da queste
elabora i bitstream per definire le aree in cui saranno inseriti, infine elabora gli altri
bitstream che permetteranno i definire il passaggio (a tempo di esecuzione) da una
configurazione a quella successiva.
19
2.2.5.2 Descrizione dell’architettura
L’architettura di Caronte essendo parzialmente riconfigurabile è composto da due
differenti parti:
una parte fissa che non si modifica quando avviene la riconfigurazione;
una parte riconfigurabile;
La parte fissa è realizzata attraverso i seguenti componenti (fondamentalmente
simile a una architettura di Von Neumann):
ICAP Internal Configuration Access Port: serve per leggere/scrivere
una configurazione dalla/per la B-RAM per/da una BlackBox;
IPCM IP-Core Manager: è un modulo hardware che costituisce una sorta di
ponte tra il lato software dell’architettura, il kernel del sistema operativo e il
lato
hardware,
le
BlackBox;
Memoria : usata per conservare tutti i bitstream parziali, che contengono le
informazioni
e
i
dati
necessari
per
la
riconfigurazione;
Bus: vengono utilizzati per la struttura di comunicazione, in particolare sono
di due tipi distinti:
o IBM CoreConnect;
o bus macro;
Processore: usato per fornire un supporto fisico per il codice eseguibile;
Controllore degli Interrupt: usato dal processore e dalle BlackBox per
dialogare tra di loro;
20
L’architettura può essere rappresentata nel seguente modo:
Figura 2.3 : Architettura di Caronte
Analizzando la figura 2.4 si può notare che sono state descritte tutte le componenti
fisse, mancano da descrivere quelle del lato riconfigurabile le black box:
Le black box sono i moduli dell’architettura che devono essere riconfigurati,
corrispondono alla logica circuitale racchiusa in determinate aree
dell’integrato che può essere modificata senza interferire con le altre
componenti
dell’architettura.
Esse includono i nodi, e implementano le interfacce di comunicazione tra
nodo e sistema, inoltre l’interfaccia può contenere temporaneamente al suo
interno una quantità di dati, in maniera tale che possano essere conservati
durante
la
riconfigurazione.
La blackbox non è altro che un guscio virtuale, infatti realizza l’astrazione
che permette di considerare la riconfigurazione di diversi componenti logici
su un’area dell’FPGA di dimensioni conosciute.
21
Ecco una rappresentazione grafica della black box:
Figura 2.4 : Rappresentazione di una Blackbox
22
2.2.6 Descrizione del progetto PandA
In questo paragrafo verrà introdotto il progetto PandA descrivendo che finalità ha e
quale il suo obiettivo.
In particolare introducendo il flusso di progetto di PandA che parte da una specifica
di alto livello fino ad ottenere una struttura che serve come base di partenza per la
fase di analisi del sistema orientate al partizionamento hardware/software e per la
fase di sintesi di alto livello.
2.2.6.1 Struttura
ll progetto PandA [6] è stato realizzato all’interno del Dipartimento di Elettronica e
Informazione del Politecnico di Milano.
Questo progetto ha come obiettivo la realizzazione di framework composto da
svariate parti tra cui la più importante è un’applicazione di sintesi di alto livello
che, partendo da una descrizione di un linguaggio (come C, C++ o SystemC),
generi un codice sintetizzabile a livello RTL.
Per poter raggiungere questo obiettivo si è deciso di sviluppare questo progetto con
una struttura modulare ([7] [8]).
Infatti è composto da diversi sottoprogetti che interagiscono tra loro, ecco qui di
seguito i moduli con cui si è scelto di suddividere questo progetto:
Modulo
per
la
gestione
di
descrizioni
comportamentali:
traduce una descrizione comportamentale delle specifiche del sistema scritta in
C, C++ o SYSTEMC in una struttura intermedia ad albero.
Come gia descritto nel paragrafo 2.1 il SystemC è un’estensione del linguaggio
di programmazione C++, per questo viene sfruttato un parser C++ esistente, il
compilatore GNU GCC. I vantaggi derivanti dall’uso di un tale compilatore
sono:
¾ Il GCC è predisposto per la compilazione di numerosi linguaggi, quali C,
C++, Java, Fortran, ObjectiveC, ecc… che dopo la prima fase di
parsificazione
sono
gestiti
in
modo
uniforme.
Questo permette di poter fornire a PandA le specifiche del sistema in uno
qualunque di questi linguaggi.
¾ Dalla versione 3.5 del GCC viene fornita la possibilità di salvare su un file la
struttura ad albero della rappresentazione intermedia del codice.
¾ La portabilità : nel caso di variazioni al codice GCC in future versioni, sarà
necessario effettuare solo piccole modifiche per riadattare la parte di PandA
che si interfaccia al compilatore.
23
Il modulo per la gestione di descrizioni comportamentali riconosce dalla
struttura intermedia del GCC le estensioni introdotte dalla descrizione del
linguaggio SystemC ed estrae le informazioni necessarie per creare un’ulteriore
struttura ad albero più semplice da manipolare per le successive fasi di
progettazione.
Modulo per la gestione di grafi, tecnologia e di descrizioni strutturali:
partendo dalla struttura intermedia creata dal modulo per la descrizione
comportamentale produce ulteriori descrizioni del sistema:
9 Specifica del sistema rappresentata come CDFG (Control Data Flow Graph);
9 Descrizione della tecnologia usata e dei vincoli per il sistema;
9 Descrizione dello schema strutturale del sistema.
Questo strato permette quindi lo sviluppo di analisi e metriche. Inoltre permette
anche una progettazione mirata allo hardware/software co-design.
Modulo
per
la
sintesi
ad
alto
livello:
Mira a sviluppare un sintetizzatore che produca il controllore e il data-path, che
sono i risultati di una classica sintesi ad alto livello data in ingresso una
specifica del sistema. I due algoritmi di scheduling attualmente implementati
sono:
¾ scheduling basato su liste
¾ scheduling basato sulla programmazione lineare.
Modulo
per
la
riconfigurabilità:
:
L’ultimo modulo che viene inserito all’interno di PandA, cerca di sviluppare un
sistema che permetta di sintetizzare moduli descritti in un linguaggio di alto
livello, usando il sistema di riconfigurabilità parziale e dinamica (descritta nel
paragrafo 2.2).
24
2.2.6.2 Flusso di Sviluppo
Il flusso di sviluppo del progetto PandA ([7] [8]), come presentato dalla figura 2.4,
ha come punto di partenza una descrizione della specifica del sistema ad alto livello
effettuata attraverso i linguaggi C, C++, SystemC.
Attraverso l’uso del compilatore GNU GCC modificato in modo opportuno [9], è
possibile compilare una descrizione di un linguaggio di alto livello producendo in
uscita un file ASCII.
Questo risultato intermedio viene parsificato, mediante un’opportuna grammatica,
e viene creata la struttura di tipo tree.
Questa struttura è la base di partenza per la fase di analisi del sistema orientate al
partizionamento hardware/software e per la fase di sintesi di alto livello.
Dalla rappresentazione del tree vengono estrapolate due tipologie di strutture dati
che rappresentano altrettante raffigurazioni intermedie del linguaggio col quale è
stata scritta la specifica iniziale, permettendo così un’analisi del sistema più
semplice.
Le due tipologie sono:
• IR Graph: Strutture dati basate su grafi che descrivono le dipendenze
dati e quelle di controllo;
• IR Circuit: Struttura dati per la rappresentazione di reti di moduli, tale
struttura descrive le interconnessioni fra moduli.
Il passo successivo a queste strutture intermedie è la sintesi di alto livello di ciò che
è contenuto nelle strutture elaborate, in particolare in questo caso si è utilizzata la
struttura circuit per effettuare delle elaborazioni di alto livello
25
Figura 2.5 : Flusso di sviluppo del progetto PandA
26
Capitolo 3
Sviluppo dell’algoritmo
In questo capitolo verrà descritto lo sviluppo dell’algoritmo presentato in questo
lavoro di tesi, descrivendo il funzionamento la struttura e delineando i principali
casi d’uso.
Per poter arrivare a questa descrizione è necessario prima definire le due strutture
create all’interno del progetto PandA che sono state utilizzate nella realizzazione di
questo algoritmo.
3.1 Descrizione delle strutture di PandA utilizzate
Come già descritto nel capitolo precedente il progetto PandA (vedi paragrafo 2.6)
mira a sviluppare un framework per la realizzazione di un flusso di sviluppo di
hardware e software codesign.
Ma in particolare nell’algoritmo che viene qui presentato sono state utilizzate le
due strutture ([7] [8] [9]) del progetto PandA:
• la struttura tree : struttura base di PandA;
• la struttura circuit : una evoluzione del tree;
3.1.1 La struttura tree
La struttura tree, nonostante il suo nome, è un grafo i cui nodi sono istanze di classi
C++, e gli archi sono definiti come riferimenti tra coppie di nodi, questa struttura è
utilizzata per la rappresentazione di strutture di alto livello all’interno del progetto
PandA.
La classe base con cui è costruita questa struttura è la classe tree_node, classe
astratta utilizzata come interfaccia principale per la definizione e la manipolazione
di tutte le altre classi, infatti ogni puntatore alla classe tree_node nasconde in realtà
l’istanza di una sotto-classe.
Per qualsiasi classe istanziata vengono fornite alcune funzioni get_kind() e
get_kind_text() che restituiscono la vera classe istanziata per ogni nodo.
Utilizzando la prima funzione verrà restituito un valore enumerativo, mentre
utilizzando la seconda funzione verrà restituita una stringa.
Ogni nodo del tree è identificato in maniera univoca tramite un valore numerico
chiamato “indice”, questo valore non appartiene però al nodo stesso, ma è inserito
in un altro tipo di nodo, il tree_reindex, presente sull’arco che collega una coppia
di nodi qualsiasi (come viene presentato nell’Figura 3.1).
27
Figura 3.1 : Struttura di collegamento tra due generici nodi
Tramite il riferimento ad un oggetto chiamato tree_manager, è possibile navigare in
questa struttura, perché esso può contenere le seguenti strutture dati:
9 Un vettore contenente il riferimento ad uno specifico nodo, estratto
attraverso l’indice numerico che lo identifica, evitando una costosa e
complicata esplorazione dell’intero grafo per ritrovare un nodo;
9 Un vettore che contiene i riferimenti alle dichiarazione di funzioni;
9 Una mappa che lega i nodi contenuti nel vettore sopra descritto con i nodi
che corrispondono all’implementazione delle funzioni;
Il tree può essere utilizzata per descrivere una struttura di moduli scritti con il
linguaggio SystemC, da questa struttura è possibile arrivare alla rappresentazione
di questi moduli usando un’altra struttura, il circuit, che sarà presentata nel
paragrafo seguente.
28
3.1.1 La struttura circuit
La struttura chiamata circuit è la rappresentazione di uno schema strutturale di un
circuito descritto da una specifica SystemC, creata apposta in modo che sia in
grado di contenere informazioni su moduli, canali, segnali e porte.
Per evitare replicazioni di informazioni si è scelto di realizzare questa struttura
come involucro intorno al tree.
In ogni nodo della struttura che descrive il circuito è riportato l’indice del nodo del
tree che rappresenta quell’oggetto, e attraverso il tree_manager è possibile
accedervi e estrarre i dati utili.
La base per tutti gli oggetti del circuit è c_object, in cui è presente il nome
dell’oggetto (id), il tipo dell’oggetto (type), l’identificatore numerico
corrispondente all’indice del tree (treenode) ed il riferimento al componente padre
(owner). Quest’ultimo indica effettivamente il componente che contiene l’oggetto,
nel caso di moduli e segnali, oppure indica il componente a cui appartiene
l’oggetto, nel caso di una porta.
Ogni modulo contiene vettori di porte di ingresso (in_ports) e di uscita (out_ports),
per la connessione con segnali e canali, e generiche (get_ports), per la connessione
di canali.
Inoltre contiene i riferimenti ai componenti interni del modulo (int_comp), ai canali
(int_chan) ed ai segnali (int_sign) definiti nel modulo.
La classe interface raggruppa le caratteristiche comuni tra Psignal e channel,
Psignal corrisponde al segnale descritto mediante il SystemC, mentre channel
corrisponde al canale.
Ogni interfaccia contiene il vettore di porte bound_ports collegate alla linea di
comunicazione, sia essa un segnale o un canale.
La figura 3.2 presenta le classi principali che costituiscono la struttura circuit, che
sono state precedentemente descritte.
29
Figura 3.2 : Struttura delle classi del circuit
Definite queste due strutture (tree e circuit) è possibile descrivere il perché sono
state utilizzate.
In particolare sono state scelte queste strutture per la possibilità di semplificare la
ricerca e la rappresentazione di un insieme di moduli SystemC collegati tra loro,
che è già offerta e implementata all’interno di queste strutture.
Inoltre sono già forniti alcuni strumenti che permettono la navigazione all’interno
del grafo ottenuto, infatti è possibile convertire facilmente un modulo scritto con il
SystemC in una rappresentazione di tipo tree, per poterla poi convertire in circuit.
Quest’ultima operazione si effettua tramite una classe fornita all’interno della
struttura tree chiamata tree_to _circuit_manager.
Questa operazione di conversione dal tree al circuit viene effettuata per poter
sfruttare le capacita di riconoscere moduli, canali e porte fornite dalla struttura
circuit.
Tutto ciò è stato utilizzato nell’algoritmo sviluppato in questa tesi, perché
l’obiettivo principale è di effettuare confronti tra moduli scritti in SystemC e il tree
e il circuit forniscono un aiuto valido alla realizzazione di questo lavoro.
30
3.2 Implementazione dell’algoritmo
Nei paragrafi seguenti sarà presentato il funzionamento dell’algoritmo di controllo
per la riconfigurabilità dinamica di moduli SystemC, descrivendo quali operazioni
deve effettuare, come è strutturato e quali sono i casi d’uso in cui è utilizzato.
3.2.1 Implementazione dell’algoritmo
Per arrivare a descrivere l’algoritmo qui presentato, in particolare come funziona e
perché deve eseguire particolari elaborazioni, è stato necessario definire alcuni
argomenti per descrivere il contesto e il sistema in cui deve esser inserito.
Questo algoritmo deve esser integrato all’interno di un flusso di sviluppo che
prevede l’utilizzo della riconfigurabilità dinamica, infatti nasce per dare supporto
all’interno di un flusso i sviluppo fi un sistema riconfigurabile
Il fine di questa applicazione è di dare, a chi lo utilizza, degli strumenti per poter
valutare la compatibilità di moduli SystemC, per poterli sostituire tra loro quando
viene effettuata la riconfigurazione.
Introdotti le motivazioni che hanno portato alla realizzazione di questa
applicazione è possibile delineare ora quale sia il funzionamento di essa, in
particolare l’algoritmo prende il riferimento a una struttura descritta in tree
(struttura che deve essere un’insieme di moduli scritti in SystemC), e ne ricava la
conseguente struttura circuit.
Attraverso le funzioni progettate per le strutture tree e circuit, l’algoritmo recupera
il riferimento ad un primo modulo della struttura (controllando che sia veramente
un modulo), ripete questa operazione per il modulo successivo (i moduli nel circuit
sono memorizzati in maniera sequenziale), e ne esegue un confronto di base tra
questi due moduli.
In pratica estrapola il numero di porte di uscita con le quali i moduli si
interfacciano verso l’esterno (vedi paragrafo 2.1), attraverso i rispettivi riferimenti
dei moduli.
Esegue un confronto dei valori così ottenuti, e in base al fatto che i due moduli
abbiano lo stesso numero di porte o meno l’algoritmo si comporta nei due seguenti
modi:
- nel caso il numero di porte sia uguale : inizia a confrontare ciclicamente il
tipo delle porte del primo modulo con quelle del secondo, se si ha una
corrispondenza tra i due moduli, cioè se le porte del secondo modulo hanno
gli stessi tipi di quelle del secondo, si può affermare che i moduli sono
compatibili tra loro, tenendo memoria che i due moduli confrontati sono
simili;
31
- nel caso in cui il numero di porte sia diverso : l’algoritmo prende un terzo
modulo dalla struttura, inserendo quello già confrontato in un insieme di
moduli non compatibili, e ripete il controllo sul numero di porte;
Alla fine si otterrà un primo gruppo di moduli compatibili tra loro, e un’insieme di
moduli di cui non è ancora possibile sapere niente sulla loro compatibilità, tranne il
fatto che non siano simili ai moduli del gruppo ottenuto.
Dopodichè l’algoritmo passa a ripetere le azioni descritte in precedenza, partendo
stavolta dal primo dei moduli che risultavano essere incompatibili, escludendo i
moduli appartenenti al primo gruppo.
Si otterrà così un secondo gruppo di moduli compatibili tra loro e un’insieme di
moduli ancora non compatibili.
Eseguendo queste operazioni ciclicamente fino ad esaurire tutti i moduli
dell’insieme, alla fine si ottiene un numero N di gruppi, composti da moduli
compatibili tra loro, fatto ciò vengono memorizzati i gruppi in modo che si possano
eseguire determinate operazioni su ogni gruppo.
Da questo insieme è possibile estrapolare informazioni utili per definire quali sono
i moduli più adatti nella riconfigurazione.
Per definire meglio l’algoritmo, viene proposto qui di seguito un esempio che
descrive il funzionamento:
avendo un struttura tree composta dai seguenti moduli SystemC:
A con porte di uscita sc_port<alfa>a1 sc_port<beta>a2
B con porte di uscita sc_port<beta>b1 sc_port<alfa>b2
C con porte di uscita sc_port<gamma>c1 sc_port<alfa>c2
D con porte di uscita sc_port<gamma>d1 sc_port<alfa>d2
Tenendo conto che alfa, beta e gamma sono dei possibili tipi per le porte, già
definiti nel linguaggio, oppure definiti dall’utente, otterremo come risultato
dell’algoritmo due gruppi, uno formato dai moduli A e B, l’altro formato dai
moduli C e D.
Questo perché anche se sono tutti con lo stesso numero di porte, i tipi delle porte
del primo gruppo sono diversi rispetto a quelle del secondo gruppo (perché deve
esistere una corrispondenza totale tra i tipi delle porte e non parziale come in
questo caso).
32
3.2.2 Struttura dell’algoritmo
Per poter implementare l’algoritmo si è utilizzato come linguaggio di sviluppo il
C++ [10], andando a creare una classe di questo linguaggio che implementasse
l’applicazione. In altre parole si è realizzata una classe con determinate funzioni
che eseguono il sistema di confronto e classificazione di questo algoritmo.
Ecco il diagramma che rappresenta la classe Manager_control (nome della classe
che realizza l’implementazione dell’algoritmo):
Figura 3.3 : Classe Manager_control
La figura 3.3 introduce solo gli attributi e le funzioni di maggior importanza per
permettere di presentare il funzionamento generale della classe, infatti sono stati
omessi parametri e funzioni utili solo all’interno della classe e non necessarie a chi
utilizza la classe stessa.
Qui di seguito vengono date le descrizioni degli attributi e le funzioni introdotti da
questa classe:
ATTRIBUTI:
- vector <int> Num_group : vettore costruito dinamicamente atto a contenere
in ogni cella la dimensione di un gruppo;
33
- vector <module *> Groups : vettore che contiene in ogni cella il
riferimento ad un singolo modulo, ordinate per appartenenza a gruppi.
Nel seguente esempio viene data una spiegazione di come è formato:
Se la struttura è composta da 7 moduli che hanno i seguenti nomi:
A,
B,
C,
D,
E,
F,
G
sapendo che formano tra loro 3 gruppi di compatibilità suddivisi in questo
modo:
o A, C, D appartengono al gruppo 1;
o B, F appartengono al gruppo 2;
o E, G appartengono al gruppo 3;
verranno quindi memorizzati i riferimenti nel vettore nella sequenza
che segue: A C D B F E G;
- int Current_module : indica l’ultimo valore della cella di groups a cui si è
acceduto;
FUNZIONI:
- Manager_control () / ~Manager_control () : costruttore e distruttore di
default della classe, il costruttore serve per istanziare un oggetto di tipo
Manager_control quando ne viene dichiarato uno nuovo allocando in
memoria i parametri di quell’oggetto, viceversa il distruttore serve per
rilasciare tutta la memoria occupata dall’oggetto, se viene invocato questo
comando;
- execute_control (tree_manager *tm) : funzione principale della classe,
quando viene eseguita bisogna passargli un riferimento ad un tree_manager,
dopodichè esegue delle operazioni cicliche per confrontare i moduli estratti
tramite
il
tree_manager
passato.
Infine memorizza i riferimenti dei moduli trovati nel vettore groups in base
alle compatibilità riscontrate;
- firstof (int i) : restituisce un riferimento ad un modulo, in particolare il
primo modulo del gruppo i;
- next_module () : restituisce un riferimento ad un modulo successivo
all’ultimo richiesto (Current_module), nel caso di partenza, cioè nel caso in
cui non sono state effettuate altre precedenti richieste, restituisce il primo
modulo
del
primo
gruppo;
- size_of_group (int i) : restituisce il valore della dimensione del gruppo i;
34
- num_groups () : restituisce il numero di gruppi presenti;
Queste sono alcune delle funzioni e parametri utilizzate da questa
implementazione, e possibile introdurne altre, ma questo ne verrà discusso
all’interno delle conclusioni tratte da questo lavoro.
35
3.2.3 Caso d’uso e scenari di applicazioni
Qui di seguito verranno presentati gli scenari e il caso di uso di questo algoritmo,
tramite l’utilizzo di diagrammi d’uso e diagrammi sequenziali.
In figura 3.4 viene descritto il caso d’uso della classe manager_control:
Figura 3.4 : Caso d’uso della classe
L’Figura 3.4 introduce quali classi vengono usate dalla classe Manager_control (in
particolare la classe tree e circuit le loro sottoclassi), quando viene fatta una
richiesta da un utente esterno, che in questo caso risulta essere una o più
applicazioni che fa o fanno uso della classe.
Definito il caso d’uso della classe Manager_control verranno ora presentati alcuni
scenari di utilizzo della classe.
Gli scenari descritti qui di seguito presentano i comportamenti della classe in base
alle richieste effettuate dall’applicazione esterna che le ha invocate.
36
Figura 3.5 : Dichiarazione di un oggetto manager_control
L’Figura precedente (3.5) descrive graficamente cosa avviene quando si crea un
nuovo oggetto di tipo Manager_control, in pratica si richiama il costruttore della
classe, il quale a sua volta non fa altro che allocare in memoria tutte le variabili
necessarie all’oggetto, per poi essere utilizzate, alla fine il costruttore restituisce a
chi lo ha chiamato il riferimento alla memoria allocata.
Considerando eseguita la dichiarazione di un oggetto di tipo manager_control
(necessario per poter utilizzare tutte le funzioni contenute nella classe), vengono
presentati adesso altri scenari di funzionamento della classe omettendo questa
dichiarazione per evitare la ripetizione della stessa informazione.
37
Figura 3.6 : Esecuzione della funzione execute_control
Nell’Figura 3.6 viene data una descrizione delle operazioni che vengono effettuate
se si esegue una execute_control su un oggetto Manager_control, passandogli un
riferimento ad un tree_manager.
In pratica tramite il tree_manager e il circuit_manager (che viene costruito
all’interno della execute_control) trova i riferimenti ai moduli SystemC e inizia a
fare i confronti con 2 moduli alla volta, ripetendo ciclicamente le operazioni,
esauriti i moduli da confrontare e memorizzati i gruppi di compatibilità ottenuti,
termina la sua esecuzione.
Gli scenari presentati da questo punto in avanti necessitano dell’esecuzione degli
scenari nelle immagini 3.5 e 3.6, perché si verifichino correttamente.
38
Figura 3.7 : Esecuzione della funzione firstof
Nella figura 3.7 viene presentata l’esecuzione della funzione firstof, la quale
restituisce al chiamante il riferimento al primo modulo del i-esimo gruppo
selezionato.
Figura 3.8 : Esecuzione della funzione next_module
39
La funzione descritta nell’Figura precedente (3.8) non fa altro che restituire al
chiamante il riferimento al modulo successivo rispetto all’ultimo selezionato, solo
se il modulo successivo è nello stesso gruppo del precedente altrimenti restituisce il
riferimento al primo modulo del primo gruppo.
Figura 3.9 : Esecuzione della funzione size_of_group
L’Figura 3.9 da una raffigurazione dell’esecuzione della funzione size_of_group, la
quale restituisce al chiamante la dimensione del gruppo i-esimo selezionato.
40
Figura 3.10 : Esecuzione della num_groups
L’Figura 3.10 rappresenta l’esecuzione della funzione num_groups, che restituisce
al chiamante il numero di gruppi che sono a disposizione.
Con questi diagrammi sono stati presentati gli scenari più importanti della classe
che implementa l’algoritmo, descrivendo le funzioni di maggior utilità e il
comportamento che hanno quando queste vengono eseguite.
41
Capitolo 4
Risultati sperimentali
Al fine di valutare se il comportamento della classe Manager_control sia
esattamente uguale a quella dell’algoritmo, è stato necessario eseguire delle prove
sperimentali.
Per realizzare ciò si è dovuto creare una nuova applicazione, scritta in linguaggio
C++, che includa la classe Manager_control e richieda di eseguire le operazioni
fornite dalla classe stessa al fine di valutare i risultati restituiti dalla classe.
Oltre a ciò è necessario disporre di svariati esempi di moduli scritti con un
linguaggio SystemC da inserire in questo programma di prova, moduli che devono
essere compilati con il compilatore treegcc contenuto all’interno di PandA.
Si è scelto questo tipo di test per questa classe perché l’applicazione in cui deve
essere inserita è ancora in fase di sviluppo e quindi incompleta, inoltre perché
risultava più semplice fare il test sulla singola classe invece che sul sistema
completo.
Nella figura 4.1 viene dato un esempio di applicazione che effettua dei test sulla
classe Manager_control.
In particolare parte dall’inclusione delle librerie necessarie (tra cui quella che della
classe dell’algoritmo), dopodichè si inizia l’applicazione costruendo il riferimento
al file che contiene i moduli SystemC tramite il tree_manager.
A questo punto si dichiara un oggetto della classe Manager_control, in questo
modo viene richiamato il costruttore della classe, e così d’ora in poi è possibile,
tramite questo oggetto, richiamare tutte le funzioni pubbliche della classe stessa.
Nell’esempio presentato si esegue una execute_control, funzione che controlla il i
moduli SystemC, memorizzando un insieme di gruppi di compatibilità.
Dopo l’esecuzione di questa funzione è possibile effettuare tutte le altre funzioni
disponibili descritte nel capitolo precedente, come ad esempio ottenere un
riferimento a un modulo di un gruppo o sapere quanti gruppi sono stati ottenuti,
oppure quanti moduli sono presenti all’interno di un gruppo.
42
Figura 4.1 : Codice di prova
I risultati del comportamento della classe dipendono da quanti moduli sono
contenuti all’interno del file che si va ad analizzare, infatti, non possibile fare delle
valutazioni sul tempo, perché il tempo di esecuzione di questo algoritmo varia in
base al numero di moduli e al numero delle porte contenute in un modulo.
Queste prove sono servite a determinare se il comportamento dell’algoritmo risulta
corretto, specialmente in alcuni casi di esecuzione particolari.
43
In particolare si è voluto valutare il funzionamento nei seguenti casi:
1. Caso di funzionamento standard : caso in cui viene eseguito l’algoritmo con
un insieme di moduli SystemC e alcuni di questi moduli presentano della
compatibilità, in pratica si è valutato se il comportamento dell’algoritmo in
un
caso
standard
risultasse
corretto;
2. Caso con zero moduli : caso in cui viene passato all’algoritmo un
tree_manager, il quale fa riferimento ad una struttura priva di moduli.
Questo per valutare il comportamento in uno dei casi “estremi” disponibili;
3. Caso con “N” moduli incompatibili : questo caso è quello in cui l’algoritmo
riceve un tree con N moduli, ma nessuno di questi presenta compatibilità.
Infatti in questo caso l’applicazione deve restituire un insieme di N gruppi
ognuno
formato
da
un
solo
modulo;
4. Caso con moduli privi di porte di uscita : in questo caso l’algoritmo crea un
solo gruppo dove sono contenuti tutti i moduli, perché sono ritenuti tra loro
tutti
compatibili.
Infatti hanno tutti lo stesso numero di porte di uscita (“0”);
Tutti questi casi sono serviti per valutare bene il comportamento dell’algoritmo nei
casi estremi, perché non bastava solo valutare il solo caso standard ma anche i
possibili casi non previsti dalle specifiche di partenza.
Per effettuare queste prove sono stati utilizzati esempi disponibili insieme alla
libreria SystemC [1] e alcuni esempi contenuti all’interno di PandA.
In particolare si è utilizzato l’esempio di un modello di un canale di trasmissione
tratto dalla raccolta di esempi di SYSTEMC 2.1, che descrive un produttore e un
consumatore uniti da un semplice canale realizzato attraverso una coda FIFO.
Moduli rilevati (per i moduli comportamentali sono riportati anche i processi
corrispondenti):
9 Modulo top;
9 Modulo producer con processo main di tipo thread;
9 Modulo consumer con processo main di tipo thread;
Come risultato si sono ottenuti due gruppi di moduli, il primo formato dal solo
modulo producer, perché è l’unico modulo che presenta una porta di uscita, il
secondo gruppo formato dagli altri due moduli, considerati compatibili tra loro
perché entrambi non presentano porte di uscita.
44
L’esempio precedente (quello del canale di trasmissione) è stato utile per testare il
caso di funzionamento standard della classe, ma sono state effettuate altre prove,
come riportato dalla tabella 3.1, utilizzando esempi forniti dalla libreria SystemC
versione 2.1 e altri presi da quelli presenti in PandA
Modello hardware
Canale trasmissione
dati
Filtro digitale
Filtro digitale con
struttura gerarchica
Arbitro
Esempio di PCI
Quantità Quantità di
totale di gruppi
moduli
riscontrati
Numero massimo
di moduli per
gruppo
Tempo di
esecuzione
(in secondi)
3
2
2
18
3
3
1
12
5
3
3
33
5
3
3
3
2
1
49
15
Tabella 3.1 Risultati delle prove
I tempi ottenuti sono dipendenti dal numero di moduli e dal numero di porte,
inoltre è necessario anche affermare che questi valori dipendono dall’ambiente e
dalla architettura in cui si è provata la classe.
In particolare il personal computer su cui si sono effettuate le prove descritte in
precedenza ha la seguente architettura hardware:
Portatile Acer® Travelmate™ 2702WLMi
Processore Intel® Pentium® IV a 3GHz
Ati® Mobility™ Radeon™ 64Mb di RAM condivisa
512Mb di RAM DDR
60Gb HDD
Sistema operativo Windows® XP™ Home Edition
Tutti i marchi commerciali e i marchi registrati sono di proprietà delle rispettive aziende
45
Capitolo 5
Conclusioni e sviluppi futuri
In questa tesi è stato presentato un algoritmo di controllo per la riconfigurabilità
dinamica di moduli SystemC, che serve a confrontare moduli scritti in SystemC.
La realizzazione di questa applicazione ha presentato alcune difficoltà nella sua
progettazione, in particolare le problematiche più elevate sono dipese dal contesto
in cui va inserito l’algoritmo e delle conoscenze necessarie per sviluppare
l’algoritmo, l’implementazione ha invece presentato meno inconvenienti.
Ecco quali sono state le difficoltà incontrate nelle progettazione dell’algoritmo:
- Comprendere il funzionamento della libreria SystemC, anche se non
utilizzata direttamente nell’algoritmo, ma per comprendere l’utilità, avere
nozioni di base per capire che cos’è un modulo e come funziona;
- Prendere conoscenza del funzionamento delle strutture sviluppate all’interno
del progetto PandA (vedi tree e circuit), in particolare come queste strutture
forniscono i dati e i riferimenti ai moduli da confrontare;
- Apprendere nozioni di un linguaggio di alto livello come il C++ (conoscenze
non ancora acquisite nelle precedenti esperienze di programmazione);
- Comprendere effettivamente quali erano le specifiche e definire come deve
funzionare l’algoritmo e studiare la sequenza più adatta per confrontare i
moduli, questo prima di provare a implementare in software l’algoritmo;
Risolte queste problematiche si è passato a progettare l’implementazione
dell’algoritmo, che non ha presentato grosse difficoltà, tranne nelle fasi di test
specialmente nei casi in cui non erano state poste alcune ipotesi o nei casi non
previsti inizialmente ma che bisognava tenere in considerazione.
Risolte infine le problematiche di sviluppo del software si è potuto ottenere
un’implementazione atta allo scopo prefissato.
A questo punto è possibile introdurre alcuni possibili sviluppi e miglioramenti
effettuabili su questo algoritmo, in particolare è possibile effettuare miglioramenti
sul codice dell’implementazione come miglioramenti nell’esecuzione dei confronti,
oppure nel sistema di memorizzare i riferimenti.
In pratica si può fare un’ottimizzazione del codice per migliorare le prestazioni
temporali e l’utilizzo della memoria da parte dell’applicazione.
46
Inoltre è possibile ampliare il metodo di confronto tra i moduli, infatti in questo
caso si è scelto di definire due moduli compatibili tra loro solo se hanno lo stesso
numero di porte di uscita e queste porte hanno gli stessi tipi.
Infatti è possibile definire altre metriche di confronto oltre a quella presa in
considerazione,
come
quella
nel
seguente
esempio:
• Avendo il modulo A con 2 porte, una di tipo “alfa” e una di tipo “beta”,
avendo un altro modulo B con 1 porta di tipo “beta” si potrebbe dire che il
modulo A e il modulo B siano compatibili in modo stretto, cioè A potrebbe
sostituire B nel sistema di riconfigurabilità (il contrario non sarebbe valido).
Questo è un esempio possibile di aggiunta effettuabile a questo algoritmo
ampliando la possibilità di confronto sui moduli, ma possono essere definite altri
metodi per confrontare i moduli.
Inoltre si possono definire altre nuove funzioni e parametri, utili a ampliare le
capacità di ricerca dell’algoritmo o di risposta a determinate richieste di un’altra
applicazione, come funzioni di ricerca di un modulo attraverso il passaggio del
riferimento o ritornare il valore dei tipi delle porte di uscita di un determinato
gruppo.
47
48
Bibliografia
[1] SystemC 2.0 User’s Guide website: http:// www.systemc.org/
[2] SystemC - From The Ground Up
David C. Black and Jack Donovan Eklectic Ally, Inc.
[3] Xilinx ”Virtex Series Configuration Architecture User Guide”.
[4] Xilinx, ”Two Flows for Partial Reconfiguration: Module Based
andDifference Based”.
[5] Fabrizio Ferrandi, Marco D. Santambrogio e Donatella Sciuto, ”A design
Methodology for Dynamic Reconfiguration: the Caronte architecture”
The12th Reconfigurable Architectures Workshop, RAW (2005).
[6] Documentazione su PandA panda.pdf
http://savane.elet.polimi.it/
[7] Calcolo di metriche di vicinanza orientate al
hardware/software partendo da specifiche SystemC
Tesi di laurea di Katia Turati
Politecnico di Milano - Laboratorio di MicroArchitetture
partizionamento
[8] Una metodologia per il riconoscimento el’estrazione di informazioni mirate
al partizionamento hardware / software partendo da specifiche SystemC
Tesi di Giacomo Galbiati
Politecnico di Milano - Laboratorio di MicroArchitetture
[9] Documentazione di PANDA su strutture tree e circuit
http://savane.elet.polimi.it/
[10] “Borland C++ 3.0 guida alla programmazione” Borland
49
50
Ringraziamenti
Per concludere questa tesi vorrei fare alcuni ringraziamenti, nei confronti di molte
persone che mi hanno sostenuto e in parte aiutato.
Prima di tutto voglio ringraziare la mia famiglia, che nonostante i tanti problemi
avuti nel periodo in cui è stato redatto questo testo, mi hanno sempre aiutato e
sostenuto, specialmente mio padre e mia madre, ma soprattutto mio fratello e mia
sorella.
Inoltre voglio ringraziare tutti miei amici che mi hanno dato consigli a aiuti per
sviluppare e progettare questo algoritmo, in questo caso voglio ringraziare Fabrizio
(grazie mille per le discussioni su MSN, per i consigli, e per molte altre cose…),
Simone e Davide (grazie per gli aiuti e il supporto), Willy (sei stato di aiuto,
impegnati e migliora il tuo inglese, so che ce la farai!!!), inoltre voglio anche
ringraziare gli amici che non mi hanno dato un aiuto diretto ma un sostegno morale
mentre realizzavo questo lavoro, in particolare Pierfranco (Trovo insopportabile la
tua mancanza di fede!!! [Starwars episodio IV]), Tiziano, Monica e Giulio (grazie
mille per avermi regalato la possibilità di disegnare Pac-man), Luca e Vale (per
tutti i tornei passati e futuri…), Andrea (le tue mail sono sempre divertenti, un
ottimo scacciapensieri in momenti stressanti), e tutti quelli che non ho citato ma
che sono sempre di aiuto.
Voglio poi ringraziare tutti i ragazzi del laboratorio di microarchitetture che sono
stati sempre disponibili nel dare alcune informazioni utili, tra loro in particolare
Carlo (grazie mille per i consigli).
Inoltre voglio citare l’ing. Santambrogio per avermi seguito ed aiutato in questo
lavoro e per avermi dato consigli per la fase di stesura di questa tesi (grazie
Santa!!! Ci vediamo in micro!!!), voglio anche ringraziare il professor Ferrandi che
mi ha aiutato a realizzare questa tesi.
Infine un grazie va anche a tutti i miei compagni di un università di questi 3 anni
per aver passato insieme a me svariate difficoltà tra periodi di esami, stressanti
lezioni, e progetti estenuanti, tra cui cito il Rosso, Beppe, il Namero Corrado e
molti altri…..
Un grazie a tutti quanti……
Da parte di Andrea
51