Pag. 9
Nel capitolo 4 viene formulata la proposta di un metodo di design per le applicazioni
concorrenti MML, basato sugli oggetti ed esteso alla decomposizione gerarchica.
Dapprima si analizza il linguaggio MML al fine di individuare gli oggetti
riconoscibili nel modello di design. Segue la descrizione del metodo, con la
definizione della notazione, del procedimento di design e delle regole base del
metodo. Si offre infine un esempio reale di utilizzo del metodo.
Nel capitolo 5 si procede ad una formalizzazione della struttura dell'applicazione
MOOD, con la costruzione di una grammatica federata ad attributi.
Il capitolo 6 analizza alcune attività correlate al design: la generazione di codice e di
documentazione, specificando le funzionalità che vengono poi implementate
nell'ambiente MOOD.
Il capitolo 7 affronta brevemente l'aspetto del riuso dei componenti MOOD/MML e la
gestione di una libreria di componenti riusabili.
Il capitolo 8 è dedicato alla presentazione dell'ambiente di sviluppo realizzato,
privilegiando gli aspetti legati alla specifica dei requisiti (detailed e architectural
design). Infine il capitolo 9 offre una breve panoramica sul funzionamento del sistema
come implementato.
Per inciso e completezza si ricorda che è stata anche svolta una indagine preliminare
sulla possibilità di estendere il linguaggio MML nella direzione dell'orientamento ad
oggetti. Questa ipotesi è stata poi scartata a favore dello sviluppo del metodo di
design orientato agli oggetti proposto nella tesi.
Il progetto è stato sviluppato presso i laboratori di TXT Ingegneria Informatica grazie
all'interesse degli ingg. Stefano Genolini e Andrea Di Maio. Ringrazio gli ingg.
Giorgio Bossi, Carlo Cappelli, Luca Cicognani, per l'aiuto prestato durante la fase di
implementazione del progetto.
Pag. 10
CAPITOLO 2
Nella prima parte di questo capitolo viene descritto brevemente l'ambiente di
sviluppo software MME (Multiple Microprocessor programming Environment
[MME88]). Nella seconda parte invece vengono descritti i costrutti linguistici
principali di MML (Multiple Microprocessor programming Language [MML91]).
Pag. 11
2.1. Origini del progetto MME
La storia di MME comincia all'inizio degli anni ottanta, con il primo progetto sul
linguaggio MML. In quel periodo, la nuova disponibilità di macchine
multiprocessore rese attuale l'esigenza di strumenti programmativi adeguati. MML
nacque proprio come una proposta per colmare l'assenza, a livello commerciale, di tali
strumenti.
Quella prima versione di MML fu sviluppata da un consorzio di aziende e di istituti
universitari, nell'ambito del progetto finalizzato per l'informatica del CNR. Tra le
partecipanti si ricordano le aziende: ZELTRON (poi TXT), CISE, TELETTRA; tra gli
enti universitari: Dip.Elettronica del Politecnico di Milano, Dip.Elettronica
Informatica e Sistemistica dell'Università di Bologna, Istituto di Matematica
Applicata dell'Università di Genova, Dip.Informatica e Sistemistica della Università
di Pavia, Dip.Elettronica del Politecnico di Torino, CSISEI-CNR e LMA-CNR
[Boari84].
Dopo la fine del progetto CNR, le attività di revisione e sviluppo di MML
proseguirono con il contributo finanziario di IMI ed ENEL, presso i laboratori di
CISE e di TXT Ingegneria Informatica. Oggi, anche se i principi fondamentali di quel
progetto sono rimasti inalterati, la struttura del linguaggio, la piattaforma di sviluppo
e il supporto all'esecuzione sono radicalmente cambiati ed i vari tools sono stati
riorganizzati in un unico ambiente di sviluppo, detto MME (multiple microprocessor
programming environment) [Crespi91].
L'ambiente MME si propone così come un sistema in grado di coprire tutte le fasi di
sviluppo del progetto, dalla specifica ad alto livello della applicazione, fino alla sua
allocazione ed al testing sulla architettura target.
2.2. Principi generali del progetto MME
MME è un ambiente di sviluppo per la realizzazione di progetti software e hardware,
basati sull'approccio host/target. Esso si rivolge tipicamente ad applicazioni di tipo
industriale, come, ad esempio, la realizzazione di sistemi di controllo per impianti ed
apparecchiature complesse.
Le architetture, per cui queste applicazioni vengono implementate, sono realizzate
utilizzando la vasta gamma di componenti hardware presenti sul mercato e quindi
Pag. 12
possono essere molto diverse tra loro. Inoltre, possono anche essere distribuite su più
processori interconnessi
1
.
Se da un lato però esiste grande disponibilità e flessibilità dello hardware utilizzabile
nelle diverse applicazioni, dall'altro vi è la carenza di adeguati sistemi di supporto alla
progettazione del software. I sistemi di sviluppo presenti in commercio infatti
presentano i seguenti limiti [NED92]:
1. sono molto legati al tipo di architettura target per cui sono realizzati e alla
famiglia di componenti fisici utilizzati. Generalmente, sono forniti dai produttori
di hardware come ambienti dedicati allo sviluppo di software per un certo
processore o per una certa linea di processori. Di conseguenza non é possibile
riorientare le applicazioni su architetture diverse, se non cambiando l'ambiente
di sviluppo stesso
2. generalmente sono carenti nel supporto alla distribuzione. Solamente in tempi
recenti cominciano ad essere disponibili strumenti per sviluppare applicazioni su
tali architetture. Anche questi ambienti tuttavia risentono del limite evidenziato
al punto precedente in quanto le reti descritte di solito devono essere omogenee,
cioè devono contenere solo processori della stessa famiglia
3. generalmente non coprono tutte le fasi di sviluppo dell'applicazione, ma
forniscono solo funzionalità limitate, riducendosi per esempio al solo cross
compilatore per un certo target. Inoltre, non sono strumenti integrati, cioè la
gestione del progetto nella sua globalità e il controllo della correttezza di
interazione tra le varie fasi sono lasciati all'utente
A differenza dei molti sistemi di sviluppo esistenti, MME si propone come
l'alternativa in grado di risolvere i suddetti problemi.
MME si presenta infatti come un ambiente di sviluppo in grado di coprire tutte le fasi
della realizzazione di un'applicazione, dalla specifica ad alto livello, fino alla
allocazione ed al testing sulla architettura target. Inoltre, tutte le fasi di progetto sono
integrate tra loro in un ambiente interattivo che supporta e guida l'utente. E' previsto
anche il supporto per l'attività di gruppo, vengono cioé forniti gli strumenti necessari
per gestire e coordinare il lavoro di diversi programmatori su di uno stesso progetto.
Il linguaggio di programmazione supportato da MME, MML, permette la
multiprogrammazione su un'architettura distribuita. Le singole unità concorrenti
(sequenze) possono comunicare tra loro tramite chiamata a procedura remota (RPC) e
1
Ciò potrebbe essere necessario per vari motivi: ad esempio per aumentare la potenza di elaborazione di un sistema, oppure per
aumentarne la tolleranza ai guasti duplicando le varie unità critiche, o ancora semplicemente per una esigenza fisica (spaziale) di
distribuzione
Pag. 13
la gestione della comunicazione tra sequenze é completamente trasparente al
programma applicativo in quanto viene gestita dal supporto esecutivo del linguaggio.
Inoltre, MME non é legato ad alcuna particolare architettura target o famiglia di
dispositivi; sono invece disponibili vari componenti utilizzabili per descrivere una
architettura hardware. Allo stato attuale MME supporta la linea Motorola 68000,
Digital LSI11 ed é in via di sviluppo l'estensione per Intel X86. E' inoltre possibile
riorientare una applicazione precedentemente sviluppata su una nuova architettura
hardware, con un impatto minimo sul software precedentemente prodotto.
2.3. Descrizione dell'ambiente di sviluppo MME
La progettazione di una applicazione si può dividere in varie fasi:
1. analisi dei requisiti dell'applicazione e definizione di massima dell'architettura
hardware e software
2. definizione della struttura del programma applicativo che realizza l'applicazione,
in termini di unità concorrenti e di divisione in moduli
3. implementazione delle varie unita del programma descritte al punto precedente,
usando un linguaggio ad alto livello
4. specifica dello hardware che dovrà eseguire il programma
5. compilazione del codice prodotto al punto 3 e allocazione del codice ottenuto sul
target descritto al punto 4
6. downloading del codice assoluto sul target
7. monitoraggio dell'esecuzione e debugging, sia su host che direttamente su target
A parte la prima fase, non supportata, l'ambiente MME fornisce strumenti per coprire
ogni altro passo dello sviluppo della applicazione. Nella sua versione attuale, MME é
costituito da un insieme di strumenti comunicanti tra loro tramite un database
comune, in cui sono raggruppate tutte le informazioni riguardanti un particolare
progetto.
Si sottolinea che le fasi elencate possono essere eseguite in un ordine diverso da
quello proposto, anche se quest'ultimo risulta essere il più frequente. In particolare, la
realizzazione di un programma (fasi 2 e 3) non necessariamente deve precedere o
seguire la descrizione dello hardware (fase 4) mentre entrambe dovranno essere
precedenti alla allocazione su target (fase 5).
Viene ora fornita una breve descrizione degli strumenti forniti da MME per il
supporto delle fasi precedentemente elencate. La struttura di MME è rappresentata in
figura 2.1.
Pag. 14
Definizione della struttura software della applicazione
Questa fase nell'ambiente MME viene attualmente realizzata definendo il cosiddetto
program sheet. Il program sheet é un documento di specifica ad alto livello
dell'applicazione software. In particolare, una applicazione viene descritta come un
insieme di unità concorrenti, le sequenze. Per ogni sequenza se ne specificano i
moduli componenti, le procedure remote rese disponibili per la comunicazione con le
altre sequenze, le eventuali procedure di risposta alle interruzioni e le chiamate di
procedure remote. E' anche possibile definire famiglie di sequenze, cioè sequenze che
saranno istanziate più volte.
È a questo livello che si inserirà lo strumento sviluppato nella tesi (MOOD).
Lo strumento fornito per analizzare il program sheet é il PSA (Program Sheet
Analyzer). Il PSA controlla la correttezza delle dichiarazioni effettuate e memorizza
nel database integrato nell'ambiente MME le informazioni che consentiranno il
controllo della congruenza tra l'implementazione del progetto e la sua definizione
fatta nel program sheet.
Pag. 15
Source
Modules
Program
Sheet
Editor
translated
files
MML to C
Target boards
SIC
MME
DATA
BASE
PSA
MTC
LoaderExecutable files
Debugger
Interactive
facility
NED
RUM
Interactive
facility
Glossary
Information flow
Tool
Files
Figura 2.1: Struttura di MME
Nel PSA non si fa alcun riferimento allo hardware su cui sarà eseguito il codice
prodotto, quindi la specifica della struttura hardware é separata dalla specifica del
programma.
Pag. 16
Sviluppo delle varie unità del programma precedentemente specificato
Come già accennato in precedenza MME fornisce il supporto necessario al lavoro di
gruppo. Infatti una volta definito il Program Sheet di una certa applicazione, più
progettisti possono dedicarsi contemporaneamente alla implementazione dei vari
moduli. MME fornisce una struttura di lavoro gerarchica, in cui il singolo
programmatore vede solamente la sua area di lavoro (user area), in cui sviluppa la sua
parte di progetto. Questa viene poi integrata in una area comune (area di release) che
alla fine conterrà il progetto finale. Tale caratteristica di MME é qui solo accennata e
si rimanda a [MME88] per una descrizione più dettagliata. Si ricorda solamente lo
strumento usato per gestire il progetto è MUMPSE (MUlti Micro Programming
Support Environment).
MUMPSE è lo strumento attraverso il quale il singolo utente accede a MME. Tramite
MUMPSE può infatti utilizzare ogni singolo strumento dell'ambiente per produrre la
parte di applicazione che gli è stata assegnata. MUMPSE si occupa di controllare ed
integrare sia il lavoro di più progettisti su di una stessa applicazione, sia la corretta
esecuzione ed interazione dei vari tool di MME. In particolare è MUMPSE che
assicura che le regole di precedenza di esecuzione descritte in figura 2.1 siano
rispettate.
I vari moduli realizzati usando MML, come prima fase del processo di compilazione,
vengono tradotti in linguaggio C da un altro strumento dell'ambiente MME: MTC
(MML to C). Il C funge in questo caso da linguaggio intermedio, che sarà
successivamente tradotto da un cross compiler nel codice oggetto della macchina
destinataria.
Si noti che l'utilizzo del linguaggio C permette una facile riorientabilità delle
applicazioni. Per utilizzare un nuovo processore in MME basterà avere il compilatore
C adatto ed il supporto run time necessario ad MML. Poiché il linguaggio C è molto
diffuso ed il supporto run time MML è standard e necessita solo di poche funzionalità
di base, i costi per introdurre una nuova linea di processori nell'ambiente risultano
essere contenuti.
La coerenza tra i vari moduli compilati e la descrizione della architettura fornita dal
PSA viene controllata da un altro strumento della linea, il SIC (Sequence Interface
Controller).
Definizione dell'architettura e configurazione della rete target
La descrizione della rete target avviene tramite NED (Network Descriptor), uno
strumento interattivo basato su OSF/Motif.
Pag. 17
Qualsiasi architettura target può essere descritta con NED in modo gerarchico. Ad un
primo livello, l'architettura di rete può essere definita in termini di nodi e collegamenti
tra essi. Ad un livello successivo, per ogni nodo e collegamento definito nella rete
possono essere descritte le varie proprietà quali:
° la composizione del nodo in termini di CPU, memorie e dispositivi
° per ogni componente, i suoi propri specifici requisiti, quali dimensione,
indirizzo, interrupts ...
dove i dispositivi (devices) non sono altro che insiemi di porte ed interruzioni presenti
in libreria. Specificando il nome del device si evita di descrivere tutta la lista di porte
ed interruzioni. Lo strumento dispone di un database personalizzabile di componenti
base, che può essere arricchito, descrivendo differenti tipi di componenti.
Completato l'inserimento, NED esegue alcuni controlli per garantire che la rete
descritta sia consistente. Una volta terminata correttamente la specifica della rete, nel
database sono presenti tutte le informazioni necessarie all'uso della stessa nel resto
dell'ambiente.
Allocazione del codice prodotto
Per realizzare questa fase devono essere presenti il codice intermedio dei moduli che
si vogliono allocare (ottenuto da MTC) e una descrizione consistente della rete
ottenuta con NED. Questa fase é individuale, cioé ogni singolo progettista può fare
l'allocazione dei suoi moduli producendo codice assoluto.
Lo strumento che implementa questa fase é RUM (Resource Utilization Monitor).
RUM è un tool interattivo (basato su OSF/Motif) che permette all'utente di scegliere
l'allocazione dei moduli software sulle risorse hardware. Con esso in particolare é
possibile:
• stabilire su quale processore sarà eseguita una sequenza. Solo in questo momento
viene risolto il legame tra i vari processori descritti da NED e le sequenze
descritte nel Program Sheet.
• assegnare i valori a particolari costanti dichiarate nei programmi MML, dette
differite: il loro valore non viene specificato nel codice ma deve essere noto in
fase di allocazione. In genere le costanti differite sono usate per non specificare
all'interno dei programmi delle informazioni che dipendono dallo hardware, come
per esempio l'indirizzo delle porte di input/output.
• allocare esplicitamente dei moduli nei banchi di memoria.
• dimensionare direttamente stack e heap dei nodi.
• generare il codice oggetto rilocabile.
• collegare i vari moduli generati al punto precedente e il supporto esecutivo, in
modo da ottenere il codice che verrà poi scaricato su target. Il supporto esecutivo
Pag. 18
é disponibile per ogni tipo di processore supportato e fornisce le primitive per la
gestione delle sequenze e la comunicazione .
Caricamento su macchine destinatarie
L'utente realizza tale fase tramite il comando Loader, che consente, in maniera
interattiva, di scaricare il programma generato da RUM sul target attraverso una linea
seriale oppure tramite un programmatore di EPROM.
Monitoraggio su target e debugging
MME fornisce gli strumenti per il controllo e il debugging dell'applicazione sia su
target (TADES: TArget DEbugging Support) sia quando questa viene simulata sulla
macchina host (HODES: HOst DEbugging Support).
TADES é un insieme di moduli appositi aggiunti ai nuclei allocati sui nodi della rete
target che consentono di tracciare le operazioni dell'ambiente di allocazione, mentre
HODES é un debugger simbolico presente sulla macchina host, che consente di
accedere al codice sorgente, alle informazioni contenute nel database e fornisce la
possibilità di simulare via software le interruzioni.
SIC
Loader
NEDPSA
RUM
MTC
Glossary
Tool
Requires
Figura 2.2: Precedenza tra gli strumenti di MME
La simulazione dei programmi MML sulla macchina host viene compiuta tramite lo
strumento NESSIE (NEtwork Software SImulator Environment). Il programma viene
distribuito su un insieme di nodi virtuali connessi da canali virtuali, secondo le
informazioni fornite dall'utente durante la fase di allocazione (RUM). Ogni nodo
virtuale è equipaggiato con il supporto run-time ed i protocolli di MML, cosicchè il
Pag. 19
comportamento simulato del programma MML è identico a quello che avrebbe sul
target. Si possono testare anche le procedure di gestione degli interrupts, simulando la
ricezione degli stessi.
In figura 2.2 è rappresentata la relazione di precedenza tra gli strumenti MME, in base
ai dati prodotti e forniti da essi.
2.4. Il linguaggio MML
MML é un linguaggio ad alto livello, basato sulla definizione ANSI del Pascal, con
estensioni per quanto riguarda la modularità, il supporto alla concorrenza, le
operazioni di I/O. In questo paragrafo sono sottolineati solo quegli aspetti di MML
che vengono ripresi nel capitolo 4 per quanto riguarda il metodo di design. Per una
descrizione completa si rimanda a [MML91].
Un programma MML é costituito da un insieme di unità ad esecuzione parallela,
chiamate sequenze, che comunicano tra loro tramite il meccanismo di chiamata a
procedura remota, secondo una variante del modello dei Distributed Processes di
Brinch Hansen che realizza un rendez-vous esteso. Una sequenza può essere costituita
da più moduli, ognuno dei quali raggruppa dichiarazioni di tipi, variabili e procedure
correlati tra loro, per permettere per esempio di realizzare dati astratti. Ogni modulo
presenta una interfaccia, in cui vengono descritte le entità esportate e una
implementazione, che può essere scritta in MML ma anche in altri linguaggi di
programmazione (per ora C ed Assembler). MML presenta inoltre la possibilità di
gestire le interruzioni ad alto livello, usando le interrupt procedures, scritte dall'utente.
Una interrupt procedure viene attivata in maniera asincrona rispetto alla normale
esecuzione del programma, a fronte dell'arrivo di un segnale di interruzione al
processore che esegue la sequenza cui essa appartiene.
Il programma MML è suddiviso in due livelli:
1. specifica del programma:
è la descrizione del programma, a livello alto di astrazione. Il programma
viene visto come un insieme di entità concorrenti (sequences), dotate di
interfaccia e intercomunicanti tramite chiamate di procedure remote. Questo
livello trova espressione nel Program Sheet
2. livello codice:
è l'insieme dei moduli che implementano le sequenze dichiarate nel program
sheet. Si può trattare di moduli completamente specificati oppure solo
abbozzati (stub modules)
Pag. 20
A seconda del livello di descrizione considerato, si trovano due diverse entità:
sequenze e moduli. Da questa differenziazione di livelli, nasce la possibilità di
compilare il singolo modulo, separatamente dal resto dell'applicazione. Ciò permette
di distribuire facilmente lo sviluppo di una applicazione tra programmatori diversi, il
che è di fondamentale importanza nella produzione industriale di software.
Segue una breve descrizione dei costrutti linguistici di MML.
Il program sheet
Nel program sheet vengono dichiarate le sequenze, con le relative sincronizzazioni.
Inoltre, vi sono i dati globali (tipi e costanti), visibili agli altri moduli. La sua struttura
linguistica è la seguente:
program <program name>
const <constants declaration>
type <types declaration>
family <family name>
. . . . . .
sequence <sequence name>
. . . . . .
end.
Ogni sequenza ed ogni famiglia (sequenza istanziabile più volte, in fase di
allocazione) vengono descritte, nel program sheet, con un opportuno campo. I tipi e le
costanti globali possono essere utilizzati dalle varie sequenze.
La sequenza
La sequenza è l'unità concorrente di MML. Supporta la comunicazione con le altre
sequenze implementando le procedure remote. Si sincronizza con esse eseguendo
delle chiamate di procedure remote. Viene implementata da un insieme di moduli. La
sua struttura linguistica appare composta da varie regions, ognuna delle quali descrive
una proprietà della sequenza. La regione owns elenca i moduli privati della sequenza,
Pag. 21
mentre la shares elenca quelli condivisi con altre sequenze. La regione starts in
contiene il nome del modulo che inizializza la sequenza. La regione supplies elenca le
procedure remote offerte alle altre sequenze. La regione calls elenca le chiamate alle
altre sequenze. Infine, la regione serves elenca le procedure di risposta ad interrupt
fornite dalla sequenza verso l'esterno e la handles il nome del gestore delle eccezioni
per la sequenza.
MML supporta una speciale categoria di sequenze, la famiglia (family). Si tratta di un
insieme di sequenze, derivate da un'unica definizione e perciò avente le stesse
proprietà. Il numero di sequenze che compongono la famiglia è un parametro, nel
program sheet, il cui valore potrà essere specificato in un secondo momento (fase di
allocazione delle sequenze sul target).
sequence <sequence name>
owns <modules name>
shares <modules name>
starts in <module name>
supplies <remote procedures name>
calls <remote procedure calls>
serves <driver procedures>
handles <exception handler name>
end.
Il modulo
Il modulo rappresenta l'unità di compilazione. Ciò significa che può essere compilato
separatamente dagli altri moduli che compongono l'applicazione, purché esistano il
program sheet e gli stubs di questi ultimi, definenti il legame tra le varie parti di
codice. Possiede una interfaccia, contenente variabili, costanti, tipi e procedure ed
utilizzabile da altri moduli (appartenenti alla stessa sequenza). Un modulo consiste di
(almeno) due files:
• interfaccia (file con estensione ".mi" ):
contiene la descrizione del modulo in termini di costanti, variabili, procedure
ecc.. visibili agli altri moduli che lo utilizzano
Pag. 22
• corpo del modulo (file con estensione ".m" ):
in tale file è contenuto il codice sorgente MML, che implementa quanto
descritto nell'interfaccia
In MME è possibile costruire applicazioni utilizzando linguaggi diversi da MML.
L'interfaccia verso altri linguaggi è module based, cioè il programmatore può
includere in un programma MML alcuni moduli scritti utilizzando un linguaggio
esterno (foreign modules).
Ogni modulo, all'interno della sequenza, può importare l'intera interfaccia di un altro
modulo appartenente alla stessa sequenza, mediante l'istruzione:
#import <module name>
Nel modulo possono essere implementate varie procedure di diverso tipo, quali:
• procedure remote
• procedure driver
• gestori di eccezioni
• procedure internal (ad uso privato del modulo)
• procedure external (esportata dal modulo, nell'interfaccia)
Per permettere la compilazione dell'intero programma MML e la generazione del
codice assoluto prima della completa codifica di tutti i moduli, in MML viene definito
lo stub module. Lo stub module è uno scheletro di quello che sarà il modulo finale: il
suo scopo principale è quello di fissare tutte le relazioni tra le sequenze, dichiarate nel
program sheet, in modo che sia possibile compilare ciascun modulo separatamente. Il
modulo stub ha il seguente formato:
module module_name
var <parameter> : <parametertype>;
(* per ogni parametro delle RPCs della sequenza *)
<parameter> := <parameter initial value>;
(* per ogni parametro delle RPCs della sequenza implementata dal
modulo *)
call <sequence_name> . <procedure_name> (<parameters>)
(* per ogni RPC *)