Introduzione
Lo scopo di questo lavoro è il confronto delle prestazioni di un componente
integrato realizzato da Atmel, un’architettura biprocessore chiamata DIOPSIS
740, con un processore ARM7TDMI. Il DIOPSIS 740 e` un’architettura
multiprocessore (basato su CPU ARM e un DSP) capace di ottenere ottime
performance sul processamento con numeri
complessi e floating point, ma
anche versatile e semplice da programmare attraverso il codice C con delle
opportune estensioni. Diopsis740 è dunque un chip dual-core asimmetrico, che
utilizza un micro-controllore ARM, flessibile e versatile per ogni tipo di
applicazione, per il controllo e un processore floating point, che assicura una
grande velocità di calcolo ed un’accurata precisione, per il processamento DSP.
Date le sue caratteristiche, il sistema risulta specialmente adatto per applicazioni
riguardanti l’audio, le immagini e le comunicazioni, ovvero in tutti gli ambiti
dove e` importante implementare algoritmi ad elevata complessità. Lo scopo
della Tesi e` stato quello di sviluppare un’applicazione che evidenziasse
le
capacità e le limitazioni del D740. Il lavoro svolto ha attraversato diverse fasi:
in una prima fase, prettamente teorica, sono state studiate attentamente sia
l’architettura in esame che la tecnica di Dithering di Steinberg, in modo da aver
chiaro quale fosse il problema da risolvere e quali le risorse per procedere
all’implementazione dell’algoritmo risolutore. Successivamente si e` passati alla
scrittura del codice C da eseguire sul chip. Infine, sono stati eseguiti dei test per
raccogliere dei risultati che consentissero di valutarne l’architettura, confrontando
le prestazioni con quelle del semplice processore ARM.
Nel capitolo 1 verrà presentata l’architettura del sistema DIOPSIS 740 che, in
prima approssimazione, e` possibile rappresentare come un apparato dotato di due
processori, un DSP (Digital Signal Processing) e un ARM (Advanced Risc
Machine). Queste due CPU possono comunicare tra loro tramite una memoria
condivisa e diverse tecniche di sincronizzazione (polling ed interrupting).
1
Introduzione
Successivamente sarà
spiegato come
utilizzare
gli strumenti di
sviluppo,
simulazione e test messi a disposizione da Atmel e come gestire l’architettura.
Dunque verranno introdotte le tecnologie utilizzate in laboratorio per lo
svolgimento del progetto, con una panoramica sia sugli strumenti hardware, che
software. Verranno così descritti il processore Diopsis740, la scheda JTST su cui
questo e` montato e l’ambiente di sviluppo MADE.
Nel capitolo 2 saranno introdotte le basi matematiche necessarie a comprendere
il funzionamento dell’algoritmo anche mediante esempi di possibili applicazioni.
Dunque sarà affrontato il problema sia dal punto di vista teorico che pratico, in
maniera semplice ma completa.
Nel capitolo 3 verrà descritto il cuore del lavoro, ovvero sarà presentato al lettore
l’algoritmo
di
Dithering
(Generazione
dell’Immagine
ditherata
tramite
l’Algoritmo di Steinberg), che si e` scelto di implementare per mostrare le
potenzialita` del DIOPSIS 740, dando particolare enfasi alla possibilità
di
parallelizzare il processo.
Fornite le nozioni base necessarie a comprendere i vari passi che compongono
l’algoritmo, nello stesso capitolo saranno esposte e spiegate le fasi del profiling
eseguito sul programma di test creato in ambiente standard, necessarie a
comprendere le tempistiche di esecuzione dei vari blocchi componenti l’algoritmo
e determinare il miglior partizionamento dell’applicazione sui due processori.
Successivamente, nello stesso capitolo, sarà esposta la fase di porting
dell’algoritmo da ambiente standard (Ansi C) al linguaggio di programmazione di
DIOPSIS 740 (sottoinsieme modificato di C). Saranno spiegati i punti più
significativi del codice e verranno descritti i problemi incontrati e come sono stati
risolti.
2
Introduzione
Il capitolo 4 esporrà l’analisi dei risultati dei test simulati direttamente su
Made attraverso l’algoritmo implementato. Inoltre verrà fatto un confronto fra i
risultati ottenuti con il Diopsis e quelli ottenuti con una simulazione
dell’algoritmo in Matlab, per poter poi calcolare attraverso uno specifico Software
Arm Developer Suite, atto a simulare il programma in C, i relativi cicli di clock
utilizzati dallo stesso e quindi le prestazioni in termini computazionali
dell’algoritmo svolto.
Infine, nel capitolo 5 saranno riassunte le conclusioni a cui si e` giunti dopo tutte
le fasi di progetto e simulazione riportando i risultati oggettivi di tutti i test
effettuati. Inoltre si discuterà dei possibili sviluppi futuri riguardanti il lavoro
svolto.
3
Capitolo 1
Introduzione al sistema
In questa sezione sarà presentata e descritta in dettaglio l’architettura del
chip DIOPSIS 740, dei componenti che lo costituiscono e delle tecniche di
sincronizzazione tra i due processori, ARM e mAgic, che sono il cuore di tutto il
sistema. Prima di poter sviluppare un’applicazione che possa sfruttare
completamente le potenzialità
del DIOPSIS 740 e` necessario studiarne
l’architettura e gli strumenti necessari alla sua programmazione.
1.1 Architettura DIOPSIS 740
Struttura generale del sistema
In Figura 1.1 si può vedere una foto del DIOPSIS 740 di Atmel (Dual Inter
Operating Processors for SIlicon Systems), un sistema biprocessore dotato di una
generica CPU RISC a 32 bit (ARM) accoppiata ad un processore DSP ottimizzato
per lavorare con numeri floating point a 40 bit e complessi (mAgic). DIOPSIS
740 (chiamato anche D740) combina quindi la flessibilità del controllore ARM
all’enorme potenza di calcolo del DSP. In particolare mAgic (il DSP VLIW
ad alte prestazioni) e` il cuore dell’architettura e può calcolare 1 giga-operazioni
floating point al secondo a bassa frequenza (100MHz) e ottenere ottime
prestazioni nel calcolo della FFT (Fast Fourier Transform). Il processore ARM
serie 7 fa invece parte della famiglia dei microcontrollori a 32 bit RISC(Reduced
Instruction Set Computer) che, oltre alla semplicità di programmazione, offre
buone prestazioni ed un basso consumo energetico. Grazie a queste
caratteristiche, il chip e` particolarmente adatto per una vasta gamma di
applicazioni, dall’audio professionale, ai sistemi sonar e radar ed alle applicazioni
di
processamento
delle
immagini
che
4
lavorano
con
enormi
vettori.
CAPITOLO 1. Introduzione al Sistema
Figura 1.1: DIOPSIS 740
In questo sistema il processore ARM lavora da master, mentre magic da slave. E’
quindi ARM che ha il controllo delle periferiche di I/O della scheda su cui è
montato ed è sempre ARM che comanda l’accensione di magic, per cui non è
possibile creare delle applicazioni che facciano uso del solo DSP. La
comunicazione tra i due processori è affidata al MAAR (mAgic ARm interface),
un’interfaccia grazie alla quale è possibile l’accesso del processore ARM alla
memoria del DSP. Per sincronizzare i due processori è quindi possibile utilizzare
questa interfaccia, oppure i meccanismi di interrupt che vengono generati da ARM
a magic e viceversa. Per descrivere in dettaglio l’architettura interna del chip è
utile osservare con attenzione la Figura 1.2 che offre una visione d’insieme dello
schema interno del chip,
mettendo in evidenza le parti necessarie alla
comprensione del funzionamento del sistema. Verranno ora passati in rassegna i
componenti principali di questo prodotto fornendo una descrizione approfondita
dell’architettura e del funzionamento di ARM e magic.
5
CAPITOLO 1. Introduzione al Sistema
1.1.1 L’ ARM System
In Figura 1.2 è possibile vedere la CPU ARM inserita nel contesto del
D740. L’insieme del microcontrollore ARM7TDMI e delle sue periferiche è
indicato da
Figura 1.2: SCHEMA INTERNO DIOPSIS 740
Atmel come ARM System. Oltre che dalla CPU ARM, l’ARM System è
composto
anche
da
due
bus
principali
che
rispettano
le
specifiche
AMBA:l’Advanced System Bus (ASB) e l’Advanced Peripheral Bus (APB).
L’ASB è il bus principale ad alte prestazioni del sistema, quello cioè in grado di
mettere in comunicazione ARM e le memorie interne del DIOPSIS, oltre che alle
eventuali memorie esterne. L’altro bus (APB) offre delle prestazioni minori
poichè è quello che si interfaccia con le periferiche connesse al sistema. In Figura
1.3 è possibile vedere uno schema esplicativo di come sono interconnessi questi
bus al microcontrollore ARM serie7. In Figura 1.4 è possibile vedere uno schema
complesso dell’Architettura del D740 e nello specifico di come sono interconnessi
questi bus al microcontrollore ARM serie 7.
6
CAPITOLO 1. Introduzione al Sistema
Figura 1.3: ARM System
Figura 1.4: Architettura D740
7
CAPITOLO 1. Introduzione al Sistema
In particolare ARM7TDMI fa parte della famiglia degli Advanced RISC Machines
(ARM) composta da microcontrollori General Purpose a 32 bit a tre stati di
pipeline, FETCH, DECODE, EXECUTE. Come tutti i processori RISC segue
un’architettura basata sulla macchina di Von Newman, con un Bus riservato ai
dati e uno alle istruzioni. Essendo un microcontrollore General Purpose presenta
la flessibilità necessaria per supportare le operazioni di I/O e per eseguire quelle
parti di un programma che non sono critiche dal punto di vista della computazione
matematica. In aggiunta, l’ARM mette a disposizione delle interfacce SPI e
USART, nonchè un sistema di watchdog e delle interfacce per la conversione A/D
e D/A specifica per segnali audio. Da un punto di vista della memoria l’ARM è
equipaggiato con un banco a 37 registri a 32bit e 6 registri di stato. Esistono
anche 32Kbyte di memoria RAM montata direttamente sul chip, adatta ad
ottimizzare le routine critiche real-time. La struttura di ARM, come già detto, è
basata sul set di istruzioni denominato RISC (Reduced Instruction Set Computer).
Questo set di istruzioni e il suo meccanismo di decodifica è molto più semplice di
quello dei processori CISC(Complex Instruction Set Computer). Questa semplicità
risulta determinante nelle applicazioni real-time e in quelle in cui è importante
avere un alto throughtput in termini d’istruzioni. Inoltre la peculiarità di questo
processore è di lavorare secondo la strategia architetturale THUMB: ogni
istruzione THUMB a 16 bit ha una corrispondente istruzione ARM a 32 bit. Le
istruzioni a 16 bit sono espanse a run-time, in modo da avere delle performance di
un’architettura a 32 bit con una densità di codice a 16 bit (in modo da risparmiare
memoria e costi computazionali). Il processore ARM è costruito attorno a 37
registri a 32 bit e a sei registri di stato, e può operare in 7 modi diversi:
• USER: modo normale di funzionamento
• FiQ (Fast interrupt Request): connesso al segnale di HALT del processore
mAgic,consente una sincronizzazione basata su interrupt
8
CAPITOLO 1. Introduzione al Sistema
• IRQ: modo usato per la gestione generale di interrupt
• Supervisor: modalità protetta, usata dal sistema operativo
• Abort Mode: usato per l’interruzione di operazioni appena decodificate
• System: simile al modo Supervisor, è una modalità privilegiata per il sistema
operativo
• Undefined: usato quando viene eseguita un’operazione indefinita
ARM in particolare si interfaccia al mondo esterno attraverso i bus e le sue
periferiche inizializzandole all’avvio. Per funzionare però è necessario che carichi
anche un ambiente che gli permetta la gestione delle periferiche. Su DIOPSIS 740
è quindi possibile caricare vari tipi di sistema operativo a seconda delle esigenze.
Con particolari applicazioni che possono ad esempio essere quei sistemi
embedded che devono eseguire sempre le stesse operazioni in real-time, il sistema
operativo non è nemmeno necessario. Sarà dunque l’applicazione che si
incaricherà di gestire anche tutte le operazioni di I/O. Nel caso di studio, Atmel ha
fornito l’ambiente di sviluppo per DIOPSIS 740 con due sistemi operativi a
seconda dell’utilizzo che si vuole fare del chip: eCos e mArmOs. Le due versioni
si distinguono per l’applicazione che dovranno gestire, in particolare eCos è
ottimizzato per le applicazioni più complesse come per esempio quelle che
dovranno gestire il multithreading, mArmcOs invece è ottimizzato per gestire
quei processi critici che hanno bisogno di funzionare principalmente in real-time.
Per l’applicazione che si vuole implementare la scelta è ovviamente ricaduta sul
primo sistema operativo citato, cioè eCos.
9
CAPITOLO 1. Introduzione al Sistema
1.1.2 mAgic
Il
processore
DSP
(Digital Signal
Processing),
chiamato
in
questa
architettura mAgic, è la vera innovazione del DIOPSIS 740. Esso infatti è pensato
per l’esecuzione delle parti strettamente matematiche che richiedono una notevole
potenza di calcolo ed un’alta precisione. L’architettura di mAgic è un’estensione
dell’architettura Harvard per DSP floating point ed è basata su istruzioni di tipo
VLIW(Very Long Instruction Word), opera dunque secondo lo standard IEEE 754,
che prevede un formato a 40 bit per i numeri in virgola mobile, ed uno a 32 bit per
gli interi. Le istruzioni VLIW sono istruzioni a 128 bit e, a differenza delle
normali istruzioni macchina, sono divise in più campi ciascuno dei quali dà un
comando a una delle parti parallele che costituiscono il DSP stesso. Ottimizzando
in modo corretto le VLIW è dunque possibile sfruttare al meglio il parallelismo
fornito dal sistema di pipeline di mAgic. Può essere infatti possibile, attraverso
metodologie di stima, ottimizzare il consumo energetico per istruzione con il
conseguente abbassamento di potenza dissipata. Il fatto di poter gestire la
suddivisione delle istruzioni nei vari stadi di pipeline al tempo di
progettazione/compilazione, presenta anche il vantaggio di un’esecuzione più
efficiente del codice in quanto mAgic non si deve anche preoccupare di
schedulare le operazioni assembler nella pipeline, come invece accade in ogni
altro processore non VLIW.
Architettura e Caratteristiche
La caratteristica fondamentale di questo DSP è quella di avere l’architettura
progettata per gestire direttamente numeri in floating point a 40 bit. Questa
caratteristica si traduce in un’enorme velocità nelle computazioni matematiche di
questo tipo,offrendo anche una notevole precisione nei calcoli (31 bit di mantissa),
pur non essendo la massima precisione raggiungibile da un sistema informatico.
Grazie a queste caratteristiche mAgic risulta
10
particolarmente adatto
per
CAPITOLO 1. Introduzione al Sistema
applicazioni che fanno un uso intensivo di numeri in virgola mobile, complessi e
grandezze vettoriali a due dimensioni. Offre inoltre elevate prestazioni nel calcolo
della Fast Fourier Transform–FFT e nelle Operazioni di processamento delle
immagini. Per quanto riguarda la memoria, oltre a quella per memorizzare le
VLIW, mAgic è equipaggiato con altri banchi di memoria dati a 40bit, affiancati
opportunamente tra loro in modo tale da poter rappresentare i numeri complessi.
Esiste inoltre una coppia di pagine di memoria condivisa con l’ARM (chiamata
PARM) e un’altra coppia dedicata al buffering dei dati provenienti da eventuali
memorie collegate esternamente al chip. Infine è a disposizione sul chip anche un
banco di 256 registri complessi (che possono essere visti come 512 registri a 40
bit). La gestione della memoria, in particolare quella condivisa tra i due
processori, essendo alla base del metodo di sincronizzazione del progetto, sarà
ripresa in seguito con maggiore dettaglio (Capitolo 3). Nonostante la sua
architettura sia abbastanza distante da quella di un processore general purpose,
mAgic può
essere programmato attraverso un sottoinsieme opportunamente
modificato del linguaggio C, e questo lo rende versatile ed adattabile a molte
applicazioni. Le differenze sostanziali dal C standard sono la mancanza delle
librerie per gestire l’I/O (prerogativa di ARM) e la presenza di altre librerie che
invece implementano le funzioni matematiche tipiche dei DSP. Analizzando
invece la qualità di questo DSP è importante notare le sue elevate prestazioni.
Può infatti processare a bassa frequenza (100MHz) 1.5 GOPS (1.0 GFLOPS) per
ogni singolo ciclo di clock. In particolare magic può eseguire in un singolo ciclo
di clock (a 100Mhz) 4 moltiplicazioni floating point, 3 addizioni floating point e 3
sottrazioni floating point, oppure 4 moltiplicazioni floating point, 3 addizioni
floating point, 3 sottrazioni floating point, 2 accessi alla memoria, 2
aggiornamenti degli indirizzi e 1 accesso a DMA. Il campo di applicazione per cui
è stato sviluppato questo nuovo DSP è essenzialmente quello audio in cui è
sovrana la necessità di operare in un dominio complesso (Supporto nativo per i
numeri complessi) o nel dominio delle frequenze (alte prestazioni nel calcolo della
FFT) cioè offre buone prestazioni nei calcoli matematici.
11
CAPITOLO 1. Introduzione al Sistema
La semplicità di programmazione però non sbarra la strada ad ogni altro tipo di
applicazione che abbia bisogno di una notevole capacità di calcolo in floating
point, numeri complessi, vettoriale o in generale un’accurata precisione.
Funzionamento di mAgic
Il funzionamento di mAgic è particolare. Esistono infatti due stati in cui il DSP si
può trovare: Run Mode e System Mode. Nel primo caso il DSP è effettivamente
funzionante ed esegue le istruzioni memorizzate nella memoria per le VLIW. In
questa situazione l’unica memoria che mAgic ed ARM condividono è la PARM.
Nel secondo caso il DSP non è operativo e tutte le memorie dello stesso sono
mappate nella memoria a 32 bit dell’ARM. Questa condizione permette all’ARM
di predisporre l’ambiente d’esecuzione per mAgic, caricando nella memoria
dedicata alle VLIW il codice che dovrà essere eseguito dal DSP quando entrerà in
Run-Mode e, nella memoria dati, i dati che dovranno essere processati. In figura
1.5, è riportato lo schema a blocchi dell’architettura mAgic DSP.
Figura 1.5: Schema a blocchi di mAgic DSP
12
CAPITOLO 1. Introduzione al Sistema
1.1.3 Gestione della memoria
Verrà ora descritta più nel dettaglio come DIOPSIS gestisce effettivamente la sua
memoria. In Figura 1.6 si può osservare l’intera mappa di memoria vista da
mAgic durante il suo funzionamento in System Mode. Durante il funzionamento in
Run-Mode cambia solo il fatto che mAgic può direttamente accedere solo alla
memoria PARM. Tutta la memoria di mAgic è costituita da coppie di banchi con
celle a 40 bit. Queste celle possono essere usate singolarmente per salvare
variabili scalari intere o float, oppure a coppie per salvare variabili vettoriali o
complesse sempre intere o float. Nel caso delle variabili complesse la parte reale
viene salvata nel banco di sinistra, mentre quella immaginaria in quello di destra.
La memoria di mAgic è poi ulteriormente suddivisa in 5 pagine (come si vede
dalla Figura 1.6).
Figura 1.6: Mappa di memoria di mAgic
13
CAPITOLO 1. Introduzione al Sistema
Le prime 3 di esse (P0, P1 e P2) costituiscono la memoria dati che il DSP usa per
istanziare le sue variabili locali e lo stack. Ciascuna delle tre pagine è costituita da
2048 coppie di celle. La pagina P3 (della medesima dimensione) è utilizzata come
buffer verso un’eventuale memoria esterna al DIOPSIS. Esistono apposite
istruzioni per attivare un trasferimento di dati da tale memoria esterna al buffer e
viceversa, con tecnica DMA. La pagina P4 costituisce invece quella zona di
memoria che è condivisa con l’ARM anche mentre mAgic è in esecuzione e che
pertanto permette lo scambio d’informazioni tra i due processori, ovviamente con
opportune tecniche di sincronizzazione. Quest’ultimo banco di memoria è
costituito da sole 512 celle ed è soprannominato memoria PARM. Quando il
DSP non è operativo (System Mode), la sua memoria è mappata in quella di
ARM in modo che quest’ultimo possa predisporre l’ambiente per il
funzionamento di mAgic. Il processore ARM infatti non ha limitazioni
sull’accesso della memoria di mAgic. Nella seguente Figura 1.7 si può vedere uno
schema di come si presenta l’intero sistema nel momento in cui l’ARM System
predispone l’ambiente per l’esecuzione di mAgic.
Figura 1.7: mAgic in System Mode
14
CAPITOLO 1. Introduzione al Sistema
Per quanto riguarda il processore ARM invece, esso ha una visione tradizionale
della memoria dati, tranne per il fatto che una parte di essa non corrisponde
direttamente a memoria fisica, ma è riservata al mappaggio delle varie pagine del
mAgic. Dunque sintetizzando quanto detto il mAgic dispone di 4 blocchi di
memoria on-chip:

Program Memory: la memoria di programma è una memoria a singola porta
da 8k parole da 128 bit, e contiene le VLIW da eseguire. Quando mAgic si
trova in System Mode, ARM può accedervi liberamente e scrivervi istruzioni
da eseguire. Quando invece mAgic è in Run-Mode, ARM non ha nessun
accesso a questa memoria, e le istruzioni possono essere caricate in memoria
grazie a un trasferimento DMA da memoria esterna.

Data Memory: è la parte della memoria del mAgic in cui vengono salvati i
dati interni. E’ una memoria a doppia porta costituita da tre pagine, ciascuna
da 4K parole da 40 bit per un totale di 12K parole. La struttura a doppia porta
è stata scelta per permettere a mAgic di lavorare in maniera veloce con i
numeri complessi e in generale su tutte le applicazioni con caratteristiche
simmetriche (come per esempio un’applicazione stereo). Infatti è possibile
accedere simultaneamente ai due banchi di memoria per un totale di 4
operazioni a ciclo: due letture e due scritture.

Buffer memory: è una memoria interna aggiuntiva, anch’essa doppia porta,
con una dimensione di 2k parole da 40 bit sia per la parte destra che per la
parte sinistra.

PARM memory: questa parte di memoria a doppia porta è utilizzata per lo
scambio di dati tra i due processori, quando mAgic si trova in modalità RunMode. Sebbene sia fondamentale per qualsiasi applicazione che faccia uso sia
delle periferiche della scheda sia del processore mAgic, questa memoria
15
CAPITOLO 1. Introduzione al Sistema
consta di sole 512 parole da 40 bit, sia per la parte destra che per la parte
sinistra, per un totale di 1k parole. Inoltre, l’accesso di questa memoria da
parte di ARM è limitato dalla grandezza del bus ARM, dando una velocità di
soli 4 bytes per ciclo, contro i 10 bytes per ciclo da parte di mAgic.
Gestione della memoria a livello C
Lo scambio di dati tra i due processori è una delle parti di maggiore importanza
nello sviluppo di un’applicazione, e va curata con attenzione. Non a caso, i
maggiori ostacoli incontrati durante questo lavoro di tesi, si riferiscono proprio a
questa problematica. Tutta la memoria di mAgic è mappata all’interno della
memoria ARM, permettendo a quest’ultimo di accedere, in lettura e scrittura, alla
memoria del DSP. In particolare ARM ha accesso a queste zone della memoria
mAgic:
• memoria dati interna (pagine P0, P1 e P2, banchi destro e sinistro)
• memoria Buffer (pagina P3, banchi destro e sinistro)
• memoria PARM (pagina P4, banchi destro e sinistro)
Le possibilità di accesso di ARM alle zona di memoria sopra descritte dipendono
però dal modo di funzionamento del mAgic. In particolare ARM può accedere:
• alla memoria dati interna mAgic, solo se quest’ultimo si trova in System Mode
• alla memoria buffer mAgic, solo se quest’ultimo si trova in System Mode
• alla memoria PARM, sia che mAgic si trovi in System Mode, sia che si trovi in
16
CAPITOLO 1. Introduzione al Sistema
Run-Mode. Quando una variabile viene dichiarata all’interno del codice mAgic,
è possibile decidere in che zona di memoria salvarla.
Consideriamo come esempio una variabile intera num :
• int num attribute
((memory page(3))) Questa dichiarazione consente di
salvare la variabile nella memoria buffer.
• int num attribute
((memory page(4))) Questa dichiarazione consente di
salvare la variabile nella memoria condivisa PARM.
Se alla variabile non viene dato nessun attributo, questa viene salvata di default
nella memoria dati interna. Inoltre, tutti gli indirizzi delle variabili allocate nel
mAgic vengono salvate a compile-time sul file symbols.h, incluso nel
codice ARM. In questo modo ARM può accedere facilmente alla memoria di
mAgic, sotto le condizioni descritte sopra. Il codice sottostante mostra come ARM
accede alla variabile mode dichiarata in memoria PARM:
Long long *mode&(((longlong*)(MaarPARML_BASE))[p4_mode]);
Più precisamente per quanto riguarda la gestione della memoria a livello C
esistono delle opportune estensioni al C di mAgic e ARM che permettono di
indicare in quale pagina di memoria il compilatore deve allocare le variabili. In
particolare le dichiarazioni delle variabili globali nel codice mAgic possono essere
dettagliate usando il costrutto __attribute__((parametro)), dove il campo
parametro può indicare la pagina di memoria in cui allocare la variabile o il
banco (destro o sinistro). Più precisamente si può chiedere al compilatore di
posizionare la variabile nelle pagine 0 (memoria dati), 3 (buffer con memoria
esterna) o 4 (memoria condivisa) rispettivamente con i seguenti stralci di codice:
__attribute__((memory_page(p0)))
17
CAPITOLO 1. Introduzione al Sistema
__attribute__((memory_page(p3)))
__attribute__((memory_page(p4)))
Non specificando nulla il compilatore userà la pagina 0.
Figura 1.8: Mappa memoria ARM
Per posizionare la variabile nel banco sinistro o destro della pagina specificata si
usano invece rispettivamente:
__attribute__((left_memory))
__attribute__((right_memory))
in questo caso il valore di default è left memory. Oltre alle variabili scalari intere e
float, come già detto, mAgic supporta variabili complesse e vettoriali. Esse vanno
dichiarate come le variabili scalari facendole precedere dal modificatore di tipo
__complex__oppure __vector__.
18
CAPITOLO 1. Introduzione al Sistema
Figura 1.9: Esempio allocazione memoria
Anche per questo tipo di variabili si può specificare la pagina desiderata (come
visto sopra), mentre non ha alcun senso specificare il banco di memoria in quanto
questo tipo di variabili occupa sempre una cella nel banco sinistro e la cella
corrispondente nel banco destro. Per meglio chiarire la situazione segue ora un
frammento di codice dichiarativo ed uno schema di come il compilatore allocherà
la memoria (Figura 1.7).
int v1;
float v2 __attribute__((memory_page(0)));
int v3 __attribute__((memory_page(0))) __attribute__((right_memory));
int v4 __attribute__((memory_page(4))) __attribute__((right_memory));
__complex__ float v5 __attribute__((memory_page(4)));
int v6 __attribute__((left_memory));
__vector__ int v7[2];
int v8[3] __attribute__((memory_page(4))) __attribute__((right_memory));
19
CAPITOLO 1. Introduzione al Sistema
Una volta dichiarate, con gli opportuni attributi e/o modificatori, le variabili
possono essere utilizzate nel codice mAgic come normali variabili globali. Per
quanto riguarda l’ARM, questo viene programmato in un C completamente
standard e non esistono particolari attributi o limitazioni per la definizione di
variabili. L’unico punto critico riguarda l’accesso alle variabili condivise con
mAgic attraverso il mapping di memoria descritto precedentemente. Esistono
delle macro predefinite che contengono il puntatore alla cella base delle varie
memorie di mAgic mappate nella memoria dell’ARM. Le più
importanti di
queste costanti sono MaarPARML BASE, MaarPARMR BASE, MaarDML BASE,
MaarDMR BASE, che puntano rispettivamente all’inizio dei banchi sinistro e
destro della memoria condivisa PARM e della memoria DATI (pagina 0). In fase
di compilazione, MCC (Magic C Compiler) genera, oltre ai file oggetto del codice
mAgic, un file di inclusione (.h), che dovrebbe essere incluso nei file sorgenti
relativi all’ARM. In questo file sono definite delle costanti, una per ogni variabile
globale definita nel codice mAgic, che hanno come valore l’offset della relativa
variabile rispetto alla base della memoria in cui essa si trova. Tali costanti hanno
un nome nella forma px nomeVariabile, dove x indica la pagina di memoria(0, 3 o
4), mentre nome variabile è esattamente il nome della variabile dichiarata nel
sorgente di mAgic. Per capire l’istruzione necessaria a recuperare una variabile da
una delle memorie di mAgic è necessario capire meglio come le celle a 40 bit del
mAgic vengano mappate su quelle a 32 bit dell’ARM.
Figura 1.10: Mappaggio delle celle di mAgic su quelle di ARM
20
CAPITOLO 1. Introduzione al Sistema
Come si può vedere dalla Figura 1.10 ogni cella a 40 bit viene mappata su due
locazioni a 32 bit. I 32 bit meno significativi della parola a 40 bit vengono visti
dall’ARM sulla prima delle due word. I rimanenti 8 bit vengono invece visti nel
byte più basso della seconda word. I tre byte più significativi di quest’ultima
parola sono posti a 0. I passi che ARM deve logicamente compiere per recuperare
una variabile dalle memorie condivise sono quindi i seguenti:
• Recuperare il puntatore della cella base in cui la pagina di memoria di mAgic,
dove si trova la variabile, è mappata. Questo può essere fatto attraverso le
costanti predefinite viste in precedenza(esempio: MaarPARMR BASE).
• Convertire il puntatore recuperato al passo precedente al tipo unsigned long
long* in modo tale da vedere la memoria come un array costituito da celle a 64
bit (le due word in cui i 40 bit sono mappati).
• Aggiungere al puntatore l’offset della variabile a cui si vuole accedere,
che come già detto sarà definito nell’include generato al momento della
compilazione del codice mAgic.
• Recuperare il valore contenuto nelle due word puntate dal puntatore così
costruito ed effettuare un opportuno cast al tipo di dato richiesto.
I passi precedenti possono essere eseguiti con un’unica istruzione C. Si supponga
ad esempio di voler recuperare la variabile intera NomeVariabile contenuta nella
memoria PARM nel banco di sinistra. Basterà usare la seguente istruzione:
variabile_recuperata=_((int)(((volatileunsignedlonglong*)MaarPARML _BASE)
[ p4_VarName]));
21
CAPITOLO 1. Introduzione al Sistema
Aspetti avanzati dello scambio di variabili tra ARM e mAgic
Nel caso si vogliano passare variabili intere tra i due processori, tutto funziona
come appena descritto. Se però si vogliono scambiare variabili di tipo float o
variabili vettoriali, bisogna considerare un ulteriore aspetto. Nel caso di valori
vettoriali (o complessi) bisogna semplicemente tenere conto del fatto che in ARM
non esiste un tipo nativo vettoriale, e dunque sarà necessario recuperare
singolarmente le due componenti del vettore, prelevandone una dal banco di
sinistra e una dal banco di destra. Se ad esempio si sta lavorando con numeri
complessi (parte Reale+parte Immaginaria), si dovrà procedere nel modo
seguente. Supponiamo innanzitutto che nel codice mAgic sia stata dichiarata una
variabile prova:
__complex__ int prova __attribute__((memory_page(4)));
Per recuperare le componenti reale e complessa lato ARM, si potrà usare il
codice seguente:
parteReale=_((int)(((volatile unsigned long long*)MaarPARML_BASE)
[ p4_prova]));
parteImmag=_((int)(((volatile unsigned long long*)MaarPARMR_BASE)
[ p4_prova]));
Nel caso di valori float invece la questione e` un po’ più delicata, in quanto
bisogna tener conto della differenza di rappresentazione di numeri in virgola
mobile tra i due processori. Si noti che nel caso di numeri interi il problema non si
pone perchè mAgic utilizza solo i 32 bit più bassi dei 40 a disposizione, che
quindi vengono mappati esattamente sulla prima delle due word della memoria
dell’ARM.
22
CAPITOLO 1. Introduzione al Sistema
Il DSP in questa architettura rappresenta i numeri float con la notazione standard
IEEE 754 a 40 bit, l’ARM invece rispetta lo standard IEEE a 32 bit (cosa
intuitiva, ma che inizialmente non era nota perchè non documentata). In Figura
1.11 sono mostrati i dettagli delle due rappresentazioni e come risultano mappate
una sull’altra.
Figura 1.11: Rappresentazione dei float
Per recuperare il valore float corretto è sostanzialmente necessario troncare la
mantissa della word a 40 bit, eliminando gli 8 bit meno significativi. Questo
procedimento si può fare con uno shift di 8 bit a destra della prima parola a 32
bit che l’ARM vede. Successivamente è necessario adattare la seconda parola
facendo un ulteriore shift, ma di 24 bit verso sinistra. A questo punto facendo un
OR delle due parole così modificate si arriva alla rappresentazione IEEE a 32bit
voluta. Da un punto di vista del codice C è molto più semplice realizzare il
procedimento descritto poco fa vedendo le due parole a 32 bit come un unico
intero a 64 bit (cioè di tipo long long), shiftare quest’ultimo di 8 bit a
destra ottenendo così nei 32 bit meno significativi che restano come il numero
floating point cercato. Il frammento di codice seguente realizza questa operazione:
23
CAPITOLO 1. Introduzione al Sistema
unsigned long long temp;
unsigned int temp2;
float convertito;
temp = (((unsigned long long int *) MaarPARML_BASE) [nomeVar]);
temp2 = (int) (temp >> 8);
convertito = *((float *) \&temp2);
Per meglio comprendere il funzionamento di questa routine e` utile guardare il
codice implementato per compiere questo scambio, sia in un senso (scambio di
float da mAgic ad ARM), che nell’altro (scambio di float da ARM a
mAgic),creato per avere sempre a disposizione la possibilità di scambiarsi valori
float tra i due processori.
float ConvertiFloat40To32(unsigned long long parReadData) {
unsigned long tIntConversion;
float tFloatConversion;
tIntConversion = (unsigned long) (parReadData >> 8); tFloatConversion = *((float
*) &tIntConversion); return tFloatConversion;
}
unsigned long long ConvertiFloat32To40(float parReadData) {
unsigned long long tIntConversion;
tIntConversion = *((unsigned long long *) &parReadData);
tIntConversion = (tIntConversion << 8);
return tIntConversion
24
CAPITOLO 1. Introduzione al Sistema
Questo procedimento è stato ideato “ad hoc” poichè l’architettura non è
progettata per scambiare direttamente i valori float tra i due processori. Durante
lo sviluppo dell’applicazione non è stato subito chiaro il procedimento da seguire
per effettuare questo scambio poichè nella documentazione fornita da Atmel è
spesso citato il fatto che mAgic rappresenti i float su 40bit, ma da nessuna parte è
specificato che ARM rappresenta i float con la notazione standard a 32 bit.
Durante la fase di simulazione si è quindi deciso di eseguire dei test sulle due
rappresentazioni per arrivare a una routine di conversione. I risultati ottenuti in un
primo momento sono stati abbastanza contrastanti. Per effettuare il test e
verificare la rappresentazione si inserivano dei valori da mAgic, si è deciso di
calcolare la rappresentazione (a mano, bit a bit) di ogni valore immesso da mAgic
e lo si andava a leggere con ARM stampando a video il risultato a mezzo delle
printf() rese disponibili da eCos. A questo punto si verificava la coerenza del
valore visualizzato con quello calcolato a mano. Inizialmente il risultato ottenuto
fu strano perchè sembrava che ARM non rappresentasse i valori in virgola mobile
a eccesso 127 su 8 bit, ma a eccesso 1023 su 11 bit. Questo risultato sembrava
insensato poichè non si riusciva a capire perché usare tanti bit per l’esponente a
discapito della precisione, ma comunque sembrava giusto poiché le printf
visualizzavano i giusti valori. In seguito è stato contattato un tecnico di Atmel per
chiedere spiegazioni su questa strana rappresentazione, e la risposta fu in primo
luogo che ARM rappresenta i float in normale notazione IEEE standard, ma in
secondo luogo che il risultato ottenuto a mezzo delle printf non era un errore da
imputare alla qualità del test ideato, ma un errore dovuto all’implementazione
delle printf in eCos. DIOPSIS 740 è essenzialmente un sistema biprocessore che
non è dotato di grandi quantità di memoria o di periferiche che gli permettono
l’input/output dei dati. Per questo scopo è necessario che esso sia installato su
una scheda che gli permetta di configurarsi e comunicare con il mondo esterno.
25
CAPITOLO 1. Introduzione al Sistema
In particolare, per i fini di ricerca e sviluppo, Atmel ha messo a disposizione una
board chiamata JTST(Jig Test for D740). Sulla scheda sono presenti delle
memorie SSRAM e FLASH aggiuntive a quelle interne al chip, quattro codec
audio a 20 bit, e varie periferiche di input/output tra cui una USB 2.0, due seriali
RS232, due linee seriali SPI e quattro connettori audio in ingresso e quattro in
uscita.
1.2
Introduzione all’ambiente di sviluppo simulazione e test
Prima di passare su scheda è però possibile scrivere e simulare i programmi
nell’ambiente di sviluppo dedicato al D740, sempre fornito da Atmel, e
chiamato MADE (Multicore Application Development Enviroment). L’ambiente
mette a disposizione degli sviluppatori un editor C/Assembler e i relativi
compilatori. Permette di eseguire ed effettuare il debug dei programmi sia sul
simulatore che direttamente sulla JTST. MADE mette inoltre a disposizione
un’interfaccia che permette di avere sempre sotto controllo lo stato del DIOPSIS
e delle sue memorie interne, sia che esso sia reale o simulato. Sono forniti inoltre i
due sistemi operativi (e-Cos e marmOS) su cui le applicazioni vengono eseguite.
Il programmatore deve solo decidere che sistema operativo usare (se necessario)
ed è poi MADE che provvede a caricarlo sulla JTST o sul simulatore prima di
lanciare l’applicazione.
1.2.1 Scheda di test JTST
La scheda che permette il montaggio del DIOPSIS 740 per testarne le sue
caratteristiche è la JTST, Jig Test for D740. La board, visibile in Figura 1.12, è
particolarmente orientata alle applicazioni Audio e di processamento delle
Immagini (adatte allo sfruttamento delle risorse dei processori DSP).
26
CAPITOLO 1. Introduzione al Sistema
Questa scheda è composta ovviamente da un chip DIOPSIS 740, ma interfacciato
a delle memorie aggiuntive e alle periferiche di input/output.
Figura 1.12:La scheda JTST
La JTST è semplicemente una scheda di test che cerca di mettere a disposizione
degli sviluppatori la miglior connettività possibile tra DIOPSIS e il mondo
esterno. Le applicazioni finali non saranno dunque eseguite su questa board, ma
su delle schede ottimizzate per l’applicazione che devono eseguire. Per
conoscenza in Figura 1.13 è possibile vedere il chip D740 montato su una scheda
di tipo industriale. Nel caso del progetto descritto in questo documento la JTST è
utilizzata solo teoricamente. Nello specifico la JTST (figura 1.3) è una scheda
prototipale a basso costo che offre le risorse adeguate al fine di testare al meglio le
potenzialità del Diopsis740 in una vasta gamma di applicazioni. Essa è
provvista di:
27
infatti
CAPITOLO 1. Introduzione al Sistema
• memoria SSRAM per mAgic, FLASH e SRAM per ARM
• 4 ingressi e 4 uscite audio stereo
• due porte seriali RSS232/LVTTL, utilizzate per il caricamento dei programmi e
per il controllo tramite Hyper Terminal.
• 1 porta USB 2.0 a 12 Mbps
• un display a 7 segmenti
• due regolatori di tensione 5V/3.3V e 5V/1.8V
• un pulsante di reset, per cancellare il programma dalla memoria FLASH della
scheda e caricare un semplice bootloader
Figura 1.13: DIOPSIS 740 Installato su una reale scheda di tipo industriale
28
CAPITOLO 1. Introduzione al Sistema
1.2.2 Ambiente di sviluppo MADE
MADE è lo strumento messo a disposizione da Atmel per lo sviluppo di
applicazioni per DIOPSIS 740.
Mette a disposizione degli sviluppatori un
compilatore assembler ed uno C, un potente editor e allo stesso tempo un
ambiente di simulazione dotato degli strumenti per effettuare il debug. All’avvio
dell’applicazione l’utente può scegliere se utilizzare la modalità Cycle Accurate
Simulator o la modalità DIOPSIS target, come in Figura 1.15. Le due modalità si
distinguono dall’utilizzo che si vuole fare dell’applicazione. Nel primo caso
MADE simulerà il DIOPSIS 740 offrendo svariate caratteristiche di debug, nel
secondo caso invece sarà il tramite per editare, compilare e scaricare
effettivamente su scheda la propria applicazione. E` importante notare che un
progetto compilato in una modalità non può funzionare nell’altra e viceversa
poichè le librerie incluse nel progetto sono differenti. Ovviamente nella modalità
“simulatore” l’ambiente simulerà via software l’architettura del DIOPSIS.
L’esecuzione delle applicazioni risulterà quindi molto molto lenta. E` quindi
consigliabile testare sul simulatore il funzionamento dell’algoritmo e lasciare
l’effettiva elaborazione numerica dei dati alla scheda. Una volta avviato MADE la
schermata che si propone all’utilizzatore è quella mostrata in Figura 1.15
L’interfaccia è suddivisa principalmente in cinque pannelli:
1. Pannello dell’editor: in questa parte si trova l’editor di testo SCiTe, con il
quale è possibile scrivere i programmi da far eseguire al processore. L’editor
può
essere anche spostato ed ingrandito,
per consentire una migliore
visualizzazione del codice.
2. Pannello di progetto: in questo pannello è possibile visualizzare, grazie ad
una comoda struttura ad albero, tutti i file che compongono il progetto. E’
possibile aggiungere o rimuovere file dalla parte di ARM che da mAgic.
29
CAPITOLO 1. Introduzione al Sistema
Figura 1.14: Diagramma a blocchi della JTST
Figura 1.15: Avvio di MADE
3. Pannello delle risorse: in questo pannello è possibile ispezionare il contenuto
della memoria dei due processori, specificando l’indirizzo dal quale partire e
quante celle analizzare.
4. Pannello di output: in questa zona vengono visualizzati i messaggi prodotti
dal compilatore, dal debugger e dall’applicazione corrente.
30
CAPITOLO 1. Introduzione al Sistema
Figura 1.16: L’interfaccia grafica di MADE
5. Pannello di controllo: questo pannello consente di controllare l’esecuzione
dell’applicazione sia quando il MADE è in modalità simulazione, sia quando
il PC è collegato alla JTST. E’ possibile caricare l’applicazione sulla
scheda, far partire il programma o fermarlo. Attraverso l’uso di questi pannelli
è possibile avere il totale controllo della propria applicazione. Quando si crea
un nuovo progetto, MADE offre all’utente la possibilità di scegliere che
tipo di applicazione si intende andare a sviluppare. Nello specifico si può
scegliere tra:

“DIOPSIS
Application”:
un’applicazione
completa per
il
DIOPSIS740 che sfrutti entrambi i processori a disposizione;

“ARM Executable”: un programma eseguibile esclusivamente da ARM;
31
chip
CAPITOLO 1. Introduzione al Sistema

“ARM Library”: un file di libreria per ARM;

“mAgic Executable”: un programma eseguibile dedicato a mAgic;

“mAgic Library”: una libreria per il processore mAgic.
Da questo pannello, visibile in Figura 1.17 si accede alla creazione di un nuovo
progetto. Da qui si può scegliere il tipo di applicazione da creare, la cartella in
cui sarà salvata e se dovrà prevederà l’uso di un sistema operativo tra quelli
forniti oppure no. Premuto il pulsante “Create” verranno generati i file di progetto
e l’editor si predisporrà di default su un file sorgente C per ARM (il file è un main
standard). A questo punto la gestione del progetto sarà nelle mani del
programmatore che potrà, attraverso i numerosi strumenti a disposizione,
aggiungere file, librerie o editare del nuovo codice al proprio progetto. Per
eseguire i programmi sviluppati in MADE è sufficiente, una volta creati i
sorgenti, compilare il progetto, caricarlo sul simulatore (o sulla board) ed
eseguirlo.
Figura 1.17: Pannello Nuovo Progetto
Questo procedimento può essere agevolmente fatto utilizzando la barra superiore
di MADE (in Figura 1.18). Attraverso il pulsante 6 si compila il progetto.
32
CAPITOLO 1. Introduzione al Sistema
Nel pannello in basso sarà possibile leggere i messaggi della compilazione e gli
eventuali errori. Finita la fase di compilazione sarà necessario attraverso il
pulsante 4 caricare il progetto nel simulatore o sulla board. A questo punto
attraverso i pulsanti 3, 2, 1 si potrà eseguire, resettare o stoppare l’esecuzione del
programma. Con il pulsante 5 si entrerà invece nella modalità “step”, utile per
compiere il debug passo-passo. I pulsanti appena descritti sono presenti anche nel
pannello denominato “Target Control Panel” in basso a destra;
pannello sarà
con questo
anche possibile avere un controllo più dettagliato sullo stato
d’esecuzione del programma in modalità “Cycle Accurate Simulator”.
Figura 1.18: Barra Strumenti
In particolare si potranno vedere i cicli di clock aumentare durante l’esecuzione.
Durante la simulazione sarà possibile visualizzare l’output nel relativo pannello
nella sezione sotto l’editor (“Output Panel”) in particolare nella scheda
denominata Output. Per quanto riguarda l’utilizzo di MADE non in modalità
simulatore ma “Diopsis Target”, poco cambia a patto di tener conto di alcuni
piccoli dettagli. In primo luogo è necessario avere connessa fisicamente al
computer la scheda JTST attraverso un canale seriale. Caricato e compilato il
progetto come applicazione che dovrà funzionare direttamente su scheda, è
sufficiente connettere anche MADE al dispositivo attraverso il pulsante F11
(accessibile anche dal menu` Target-Connect to the Target) dopo aver impostato
la velocità della porta seriale secondo le proprie esigenze. L’ultimo passo da
compiere prima di premere il tasto “play” e verificare il funzionamento della
propria applicazione è scaricare il sistema operativo e gli
memorie di DIOPSIS.
33
eseguibili nelle
CAPITOLO 1. Introduzione al Sistema
Questo passaggio è automaticamente fatto dall’ambiente di sviluppo premendo il
tasto “Load” (tasto numero 4 della Figura 1.16). A questo punto operando
direttamente su scheda si dovrà tener inoltre conto che non saranno disponibili
tutte le funzionalità di debug presenti offerte dal simulatore, come ad esempio il
pannello “output”: le eventuali printf del programma saranno visualizzabili
dall’utilità GDBDialog che intercetterà tutte le comunicazioni dal DIOPSIS verso
l’esterno. Per le utilità avanzate di debug e compilazione si rimanda il lettore alla
guida ufficiale di MADE fornita da Atmel insieme all’ambiente.
1.3 Conclusioni
In questa sezione è stata presa in esame e analizzata l’architettura del chip
DIOPSIS 740. Inoltre sono stati descritti senza entrare troppo nel dettaglio gli
strumenti necessari a sviluppare applicazioni per questo componente. Il sistema è
montato sulla scheda JTST, che gli fornisce diverse risorse per lo sviluppo delle
più svariate applicazione. L’ambiente di sviluppo MADE consente di scrivere
facilmente applicazioni per il chip, curandole in ogni fase, dalla scrittura ai test.
Tutto questo è necessario per introdurre il lettore ai capitoli successivi che
permetteranno di capire la tecnica di sincronizzazione tra le due CPU che resta il
nucleo centrale dell’applicazione che si è sviluppata poichè è quella parte che
rende possibile il reale multithreading tra i due processori durante l’esecuzione
dell’Algoritmo di Processamento (e quindi durante l’utilizzo massimo del DSP).
34
Capitolo 2
L’Applicazione
In questo capitolo verranno presentate le strutture matematiche necessarie a
comprendere con sufficiente chiarezza il calcolo su vettori. Verrà cioè fornita
la
base dell’Algoritmo che si è voluto implementare, cioè la generazione
dell’immagine modificata attraverso l’Algoritmo di Dithering sviluppata da
Steinberg.
2.1 Dithering
Immagini in scala di grigio: di solito ciascun pixel viene rappresentato da un
byte (8 bit) e può quindi assumere 256 diverse tonalità di grigio, dal nero
(solitamente lo zero) al bianco (solitamente 255). Benchè le immagini in scala di
grigio non siano particolarmente piacevoli alla vista (meglio il colore) sono
ancora ampiamente usate in visione artificiale, sostanzialmente per la maggiore
semplicità di elaborazione e poichè il colore porta, in molti casi, ben poca
informazione. In grafica non vengono praticamente mai utilizzate.
Immagini in colore vero: di solito ciascun pixel viene rappresentato da tre byte
(24 bit), uno per ciascun colore RGB, permettendo così di visualizzare tutti i
possibili colori teoricamente rappresentabili su di un monitor (in realtà i colori
effettivamente distinguibili su di un monitor sono meno). Esistono varianti a 32
bit, cioè 4 byte, nei quali il byte aggiuntivo porta, ad esempio, informazioni sulla
trasparenza e formati ridotti a 16 o 15 bit, quasi indistinguibili su di un monitor
rispetto a 24 bit.
35
CAPITOLO 2. L’Applicazione
2.2 Tecniche di Dithering nelle immagini a colori
Perché il color management
Ogni strumento riproduce i colori in modo differente : monitor dei computer,
camere digitali, scanners, stampanti differiscono tra di loro e da loro stessi nel
corso del tempo, per cui il colore è altamente device-dependent. Inoltre ogni
strumento ha un proprio gamut di colore che rappresenta la sua capacità di
catturare e mostrare un range di varietà di colori. Per permettere ad un'immagine
di essere mostrata identicamente su diversi display si rende necessario il color
management. Poiché molti strumenti non sono predisposti per riprodurre
immagini nei colori reali, il numero di essi deve essere ridotto ad una palette
limitata. Esiste tuttavia una classe di algoritmi (definiti Dithering), che riduce
l'influenza di tali effetti e preserva l'aspetto dell'immagine originale, controllando
la distribuzione di intensità.
Concetti base necessari alla trattazione del Dithering
Risoluzione
Per risoluzione dell'immagine si intende il numero di pixel contenuti in ciascun
pollice(unità di misura di spazio usata nel mondo anglosassone), indicata
dall'abbreviazione "ppi" che in inglese significa appunto pixel per inch. La
risoluzione determina il dettaglio di un'immagine. Più il numero di pixel per
pollice è alto, più l'immagine è nitida. Un altro fattore da tenere presente è che la
risoluzione si misura in pixel per pollice lineare e non pollice quadrato. Ad
esempio: un immagine ad una risoluzione di 72 ppi avrà 72 pixel in orizzontale e
72 pixel in verticale, che corrispondono a 5184 pixel per ogni pollice quadrato
dell'immagine.
36
CAPITOLO 2. L’Applicazione
Pixel depht
Il numero di colori differenti in un'immagine è detto " Color resolution", dove per
risoluzione si intende "finezza", "precisione", ossia un'indicazione del livello di
dettaglio in un segnale digitale. La profondità di colore di un'immagine, detta
anche profondità di bit, determina tanto la dimensione del file che l'intervallo
dinamico (sfumature) dalle zone scure a quelle chiare, nonché il numero massimo
di colori presenti.
Color depht = Bit depht (numero di bit per pixel)
Numero di colori= 2^bit depht
Tavolozza (a colori indicizzati o su canali colore)
Colore RGB: anche conosciuto come “true color” usa 8 bit (da 0 a 255) per ogni
componente di Rosso, Verde e Blu fino a formare una palette di pixel su 24 bit
che permette l’esistenza di 16,7 milioni di colori. In modo approssimativo
rappresenta il range visuale che l’occhio umano è in grado di distinguere.
Colore indicizzato: oltre al colore diretto , si usa come alternativa su computer a
bassa risoluzione e sul Web il colore indicizzato. Lo schermo di un monitor può
mostrare milioni di colori che possono essere rappresentati da valori su 24 bit,
tuttavia talvolta la video RAM non è sufficiente a mostrare un’immagine a pieno
schermo con 3 byte per pixel, inoltre un’immagine con colori su 24 bit può essere
troppo pesante sia per essere memorizzata che trasmessa. Se per qualsiasi motivo
ci si trova costretti ad utilizzare un solo byte per pixel (come nel caso di GIF) e
non 3, abbiamo a disposizione solo una gamma di 256 colori per ogni immagine.
Poiché un set di 256 colori standard risulta restrittivo si utilizzano colori
indicizzati ossia una palette di 256 valori che contiene solo quelli specifici per
ogni immagine.
37
CAPITOLO 2. L’Applicazione
Quando questa viene visualizzata, per ogni valore su un byte memorizzato nel
pixel, il sistema grafico cerca nella palette il colore corrispondente e lo mostra. In
breve, invece di usare 8 bit per ogni valore RGB, li si utilizzano per tenere un
indice in una tabella con 256 elementi, ognuno dei quali sarebbe memorizzato su
24 bit senza questo espediente; dunque invece di memorizzare il valore del colore
su 3 bytes si memorizza un indice che punta ad un elemento della tabella di 16
milioni di colori. Questa tabella si chiama palette o Color Lookup Table; un
valore di colore “logico” non identifica un colore in modo assoluto, ma solo
relativo alla palette; inoltre se, come spesso accade nelle pagine Web, più
immagini con palette diverse devono comparire nella stessa finestra, occorre
ridimensionare ulteriormente il numero di colori (con una palette Web safe di 216
colori, si può essere sicuri che essa venga riprodotta dai Web browsers su ogni
sistema che usa colori su 8 bit). Si deve sottolineare che un file con immagine
deve anche contenere la palette insieme ai dati sull’immagine, ma nel complesso
il peso di questa viene ridotto di un terzo perché da 24 bit per i colori si passa ad
8. Ciò comporta ovviamente che i colori eliminati dell’immagine di partenza
(come una fotografia) vengano sostituiti con quelli della palette, pertanto si
presentano due metodi d’azione.
1. Color reduction. E’ il processo di riduzione del numero di colori presenti in
un’ immagine per migliorare la sua visualizzazione su display o il trattamento
generico del file, in modo da diminuire le esigenze di memorizzazione dello
stesso. Generalmente l’immagine di partenza è su 24 bit RGB (ossia può avere
fino a 16 milioni di colori) , quella finale può avere 256 colori codificati su 8 bit.
Il metodo più semplice prevede di sostituire il valore del colore di ogni singolo
pixel con l’indice CLUT del colore più simile; ciò può essere dannoso perché
molti colori vengono distorti, i dettagli possono andare persi quando due colori
simili sono rimpiazzati da uno stesso, possono comparire bande o effetti artificiali
(questi fenomeni sgradevoli sono descritti con il nome “posterizzazione”).
38
CAPITOLO 2. L’Applicazione
Esistono vari algoritmi per applicare la color reduction:
• Standard
L’algoritmo standard per la riduzione dei colori usa una tecnica semplice di bitshifting, ossia prende ogni colore RGB su 24 bit e sposta a destra ogni
componente in modo da eliminare le 16 cifre meno significative. Il risultato è una
rappresentazione su 8 bit, di cui 3 vanno al rosso, 3 al verde e 2 al blu; lo
svantaggio è che usando questa palette standard molti colori utili ad un’immagine
possono mancare e altri meno utili possono essere presenti. Per superare
quest’inefficienza si utilizzano palette ottimizzate.
• Basato su “popolarità”
I colori da inserire nella palette sono scelti in base alla frequenza con cui
compaiono nell’immagine originale; selezionare i colori più frequenti non è però
sempre una buona scelta.
• Median Cut
Si fraziona opportunamente lo spazio colore RGB e si selezionano i colori della
palette in modo più accurato.
2. Un metodo più fine è quello di sostituire aree di un singolo colore con trame di
diversi colori, in modo che la loro mescolanza ottica sul nostro occhio produca
l’effetto di un colore che non è in realtà presente. Ad esempio possiamo simulare
un’area di colore arancio, pur non avendolo a disposizione nella palette, colorando
alcuni pixel nell’area con il giallo e alcuni con il rosso; tutto ciò però funziona
meglio con una buona risoluzione.
39
CAPITOLO 2. L’Applicazione
Tale processo si chiama Dithering ed è un’estensione dell’halftoning, usato per
stampare immagini in scala di grigi su stampanti che possono solo produrre
puntini neri (oltre ai bianchi dello sfondo). L’ halftoning è un metodo per la
creazione di ombre utilizzando un unico colore. Variando la grandezza o la
densità dei punti l’occhio può percepire un’ombra tra un colore solido e quello
dello sfondo. L’halftoning digitale usa un’immagine bitmap o raster in cui ogni
elemento monocromatico può essere colorato oppure no. Le figure 2.5 mostrano
diversi modi per distribuire il bianco e il nero su un blocco di pixel 4x4; se i pixel
fossero abbastanza piccoli, ad una certa distanza queste trame apparirebbero come
diverse tonalità di grigio.
Figura 2.1: Immagine e Pixel in bianco-nero
Se ogni pixel può essere di uno dei 256 colori della palette associata
all’immagine, invece che solo bianco e nero, le trame possono simulare milioni di
colori; in questo caso si parla propriamente di dithering.
40
CAPITOLO 2. L’Applicazione
2.3 IL DITHERING
A livello fisico il processo di dithering è basato sulle caratteristiche psicofisiche
del sistema visivo umano. Esso crea infatti l'impressione di un terzo colore
regolando i colori dei pixel adiacenti, permettendo ad un'immagine di essere resa
sullo schermo o su un qualsiasi display con meno colori di quelli che essa
possedeva originariamente. Gli algoritmi di dithering sfruttano questo fenomeno,
ridistribuendo i valori dei pixel in modo che l'intensità media in piccole aree
dell'immagine
processata
risulti
approssimativamente
uguale
a
quella
dell'immagine originale (in scala di grigi nel caso di figure in bianco e nero). Esso
è generalmente usato in situazioni in cui il set di colori nell’immagine originale è
diverso da quelli disponibili per il rendering. Per le immagini web esso serve per
la conversione in GIF o quando il browser tenta di visualizzarla su un display che
ha solo 256 colori, perché essi possono non corrispondere a quelli dell’immagine
originale. In breve il dithering è dunque una tecnica che permette ad una bitmap di
apparire in più colori di quelli di cui essa è in realtà costituita.
- se la bitmap contiene solo bianchi e neri, il dithering può essere usato per creare
l'illusione del grigio.
- se la bitmap prevede una palette di colori, il dithering può creare l'illusione di
mostrare più colori di ciò che contiene la palette.
Tecniche di Dithering
Le tecniche di dithering possono essere classificate in base alla natura delle trame
che esse generano e al tipo di configurazione dei pixel che esse producono.
41
CAPITOLO 2. L’Applicazione
Trame:
- periodiche se generate da processi determinati a priori basati su griglie regolari;
si parla di threshold dithering in quanto ogni pixel dell’immagine originale viene
confrontato con una soglia prestabilita per decidere quale colore esistente deve
sostituire il suo colore di partenza ( es. ordered dithering).
- aperiodiche se generate con processi non predefiniti (es. error diffusion, ove
l’errore di arrotondamento di ogni pixel è propagato sui vicini e compensato).
Tipi di configurazione dei pixel:
- dispersed se tendono a distribuire livelli di grigio coprendo aree di varie
dimensioni(es. error diffusion che simula le tradizionali tecniche di stampa per
strumenti ad alta risoluzione).
- clustered se concentrano i pixel in piccoli gruppi.
2.3.1 AVERAGE DITHERING
In generale il dithering basato sulle soglie, o Threshold dithering, prevede che
ogni valore di pixel p sia confrontato con una soglia t. Se p<t, allora p è sostituito
con a, altrimenti con b, dove a e b sono i colori disponibili. Nel caso dell’Average
Dithering la soglia è uguale ovunque, nel caso ad esempio dell’Ordered Dithering,
come vedremo, essa sarà location dependent. L’Average Dithering è dunque un
algoritmo basato su due livelli. Per un'immagine di tipo "halftone" il
procedimento consiste nello scegliere un determinato livello di grigio costante, in
particolare il valor medio dei pixel dell'immagine, e nell'usarlo come un valore
soglia globale tramite il quale scegliere se un pixel deve essere quantizzato come
0 o come 1.
42
CAPITOLO 2. L’Applicazione
Tutti i pixel il cui livello di intensità è al di sopra del valor medio (che è la soglia)
sono quantizzati come 1, gli altri come 0; in pratica i toni intermedi sono sostituiti
dal colore più vicino. Il metodo è facile da implementare ma presenta uno
svantaggio: l'effetto della quantizzazione è piuttosto evidente; si possono ottenere
pertanto risultati migliori utilizzando soglie location dependent, dove una trama è
ripetuta più volte sulle aree dell’immagine.
Figura 2.2: Average Dithering
43
CAPITOLO 2. L’Applicazione
Nella Tesi proposta faremo riferimento agli Algoritmi di Dithering di tipo
Steinberg :
2.3.2 ORDERED DITHERING
Esso prevede l'utilizzo di una matrice ( chiamata threshold matrix) di valori come
soglia in base alla quale discriminare i pixel, replicandola su tutta l'immagine. Un
esempio di matrice potrebbe essere questa 3x3:
1
6
7
7
1
5
4
2
9.
Se il valore del pixel (scalato in un range tra 0 e 9) è inferiore al numero nella
cella corrispondente della matrice, il pixel è colorato di nero, altrimenti di bianco.
Usando queste trame fisse i colori solidi vengono enfatizzati e i bordi risultano più
netti. Il vantaggio di questo metodo è che il dithering di un pixel non influenza
quello dei pixel circostanti; si tratta infatti di un dithering localizzato, di un point
process, molto utile se occorre lavorare su sequenze animate di immagini. Esso
può produrre sia clustered dots ( raggruppamenti, concentrazioni di puntini)
oppure dispersed dots ( puntini distribuiti su aree più grandi); il risultato dipende
ovviamente dai coefficienti utilizzati e dunque dalla particolare configurazione
delle matrici. In generale le trame che favoriscono la concentrazione dei puntini
( di tipo clustered) dovrebbero essere usate per strumenti che tendono a sfocare le
immagini ( non a caso il dithering ordinato è applicato dalla maggior parte dei
giornali). Questo algoritmo, come l’average e il random, finora osservati
soprattutto in applicazioni su immagini in scala di grigi, può essere facilmente
esteso anche su immagini a colori. Semplicemente si separa ogni pixel d’origine
nelle sue componenti RGB e ad ognuna di esse viene applicata la matrice del
dithering, separatamente; poi si riassemblano le componenti risultanti per
determinare il pixel colorato finale.
44
CAPITOLO 2. L’Applicazione
E’ importante precisare che questo funziona solo se la palette è stata scelta
accuratamente in modo che possa contenere qualsiasi combinazione si possa
originare riassemblando alla fine le componenti risultanti: questa palette si chiama
“uniform color map” ed è molto meno fine delle palette ottimizzate.
Figura 2.3: Ordered Dithering
2.3.3 ERROR DIFFUSION DITHERING
Questa tecnica genera i risultati migliori tra tutti i metodi classici ed è la più lenta;
ci sono molte varianti di questo metodo, e più sono accurate ed efficaci, più sono
lente da applicare. L'algoritmo è basato sulla dispersione dell'errore cromatico,
semplice da descrivere. Per un punto dell'immagine, dapprima si cerca il colore
disponibile nella palette, più vicino a quello originale. Si calcola la differenza tra
il valore nell'immagine e quello a disposizione (= errore cromatico), poi lo si
divide e distribuisce sui pixel circostanti che non sono ancora stati considerati.
Quando successivamente ci si occupa di questi si aggiunge loro l'errore ottenuto
dai pixel precedenti , si confronta il valore ottenuto con quelli nel range
disponibile, si sceglie e si continua come prima.
CAPITOLO 2. L’Applicazione
45
Affrontiamo ora il discorso di come funziona matematicamente la distribuzione
degli errori. Denotiamo i valori corretti di una linea di pixels con k1, k2, k3…e i
valori arrotondati che l’errore cromatico e1 del primo pixel è e1=r1-k1 e negli
errori successivi ei di ogni successivo pixel l’errore di quello precedente viene
compensato. Nel nostro caso i valori di colore disponibili sono r=0,3,6,9.
Immediatamente si sceglie per k1=1 il valore r1=0 tra i disponibili, perciò
e1=r1-k1=-1.
r2
sarà
il
valore
arrotondato
di
(k2-e1)=1-(-1)=2
per
arrotondamento r2=3; il nuovo e2=r2-(k2-e1)=3-(1+1)=1. Il procedimento
basilare si segue per tutti i pixel della linea ripetendo le stesse operazioni:
e: -1 1 0 1... e = errore cromatico
r: 0 3 0 3... r = v. arrotondato (visualizzato al termine)
Tuttavia per ottenere risultati più accurati l’errore si può distribuire anche su più
pixel adiacenti ( e non solo su quello immediatamente a destra), utilizzando pesi
normalizzati. E' importante sottolineare che se si sta applicando il dithering ad
un 'immagine in bianco e nero che verrà visualizzata su un display in scala di
grigi, l'operazione di trovare il colore più vicino si riduce ad un semplice
confronto con una soglia. Per le immagini a colori, ciò comporta invece far
corrispondere il colore in input con il colore più simile a quello consentito
dall'hardware , che può essere difficile da individuare a seconda della palette a
disposizione. In breve l’error diffusion dithering genera meno artefatti, i bordi e i
colori delle figure appaiono più morbidi ( e talvolta sfocati). Un altro vantaggio è
dato dal fatto che si possono scegliere i colori da una color map ottimizzata e non
si è vincolati a quella standard come nell’ordered dithering. Ciò è reso possibile
dal fatto che nel caso di un output a colori, l’errore viene scisso nelle sue
componenti RGB e tali componenti di errore vengono distribuite sui pixel
adiacenti.
CAPITOLO 2. L’Applicazione
46
2.4
FLOYD-STEINBERG
Il filtro di diffusione dell'errore più conosciuto è quello di Floyd-Steinberg :
Figura 2.4: Tabella Floyd-Steinberg(Diffusion error pixel)
In questo filtro la X rappresenta il pixel che si sta considerando, ed i numeri,
chiamati pesi, rappresentano la proporzione di errore distribuito al pixel in quella
posizione. In questo caso il pixel immediatamente alla destra riceve i 7/16
dell'errore ( il divisore è 16 perché la somma dei pesi è 16), il pixel direttamente
sotto riceve i 5/16..e così via. Quando si fa lo scanning della linea da destra verso
sinistra la matrice si ribalta, in questo modo si evita l’impressione di direzionalità
data da bande artificiali.
Figura 2.5: Dithering Floyd-Steinberg
47
CAPITOLO 2. L’Applicazione
Un altro esempio di Dithering di FLOYD-STEINBERG:
Dithering esempio: 8 colori
Figura 2.6: Dithering dell’Immagine a Colori con Floyd-Steinberg
Gli algoritmi Jarvis- Judice – Ninke e quello di Stucki si applicano a porzioni di
spazio più ampie, dunque ad un maggior numero di pixels per estendere l’errore
di quantizzazione. In tutti i casi comunque i coefficienti degli errori da distribuire
sono fissi.
Figura 2.7: Tabella di altre Matrici di Error Diffusion(Jarvis e Stucki)
48
CAPITOLO 2. L’Applicazione
2.4.1 Problemi sul Dithering
- Alcuni tra i metodi elencati possono produrre l'illusione di bande artificiali in
aree colorate; ciò può risultare problematico quando le immagini processate
contengono elementi naturali (come le fotografie) e tende a divenire evidente
quando si utilizzano strumenti con risoluzione abbastanza limitata.
- Il dithering è un'operazione ad una sola via: una volta che l'immagine è stata
trattata con questo processo, sebbene essa possa apparire come una buona
riproduzione dell'originale, l'informazione è persa definitivamente. Inoltre, una
volta processato, l’elemento grafico può essere difficile da editare. Perciò le
immagini dovrebbero essere preparate e archiviate a pieni colori e poi essere
sottoposte al dithering solo nel momento in cui esse devono essere mostrate sul
display o stampate su/con uno strumento che non supporta tutti i colori necessari.
Comunque nella pratica le limitazioni di reti, memorie e formati di file grafici
comportano spesso, nonostante gli svantaggi citati, la necessità di archiviare le
immagini già in modalità "dithered".
- Le immagini "dither" contengono molti dettagli che non si possono comprimere
al meglio, soprattutto in formati quali LZW o Run-Lenght. In alcuni casi dunque
può comportare l'utilizzo di meno memoria e meno banda il fatto di archiviare e
trasmettere le immagini a pieni colori piuttosto che in modalità "dithered". Sarà
poi il device finale ad occuparsi di eventuali processi di dithering , se
necessari,come nel caso di immagini in formato png nel web publishing.
49
CAPITOLO 2. L’Applicazione
2.5 Applicazioni pratiche
La più comune applicazione del dithering è mostrare in modo più accurato gli
elementi grafici che contengono un range di colori più ampio di quello di cui
dispone l’hardware che li deve visualizzare. Ad esempio il dithering può essere
usato per mostrare una fotografia contenente milioni di colori su un hardware
video che può solo rendere 256 colori per volta. In una situazione come questa, in
cui l’hardware del display del computer è il limite primario alla color depht
(risoluzione del colore), il dithering è impiegato nei software come i web
browsers. Specificatamente per tali applicazioni è stata identificata una “web safe
color palette”. Un’altra applicazione utile per il dithering si ha in situazioni in cui
il formato del file grafico è il fattore limitante. In particolare il noto formato GIF è
vincolato all’uso di 256 colori o meno. In tali casi i software di editing grafico
sono responsabili di effettuare il dithering sull’immagine prima di salvarla in
questi formati di compressione.
50
Capitolo 3
Descrizione del sistema globale
In questo Capitolo è descritto come descrivere il problema della generazione
dell’immagine Ditherata, in particolare sarà esposta l’architettura del sistema
globale (System User - DIOPSIS 740). Sarà inoltre presentato lo schema di
funzionamento dell’algoritmo e la sua prima implementazione in MatLab ed in
ambiente standard (ANSI C) per individuare i blocchi principali che lo
costituiscono. Sarà inoltre esposta la tecnica di sincronizzazione tra i due
processori che si è ideata. Questa parte sarà il cuore di tutto il progetto poichè
sarà la base per ottenere il vero parallelismo tra le due CPU.
3.1 Architettura globale del sistema
Come già citato in precedenza, l’applicazione che si è deciso di implementare
consiste nella realizzazione dell’algoritmo che genera l’immagine Ditherata di
Floyd-Steinberg. Questa soluzione permetterà, attraverso l’algoritmo ideato, di
mettere in evidenza al meglio le caratteristiche di funzionamento in
multithreading dei due processori ARM e mAgic sfruttando le piene potenzialità
dell’architettura messa a disposizione dal D740. L’idea è che ogni qual volta
un’applicazione in esecuzione su un computer general purpose (System User)
abbia bisogno di calcolare delle somme o operazioni di tipo logico al fine di
ottenere dall’immagine originale quella ditherata, anzichè calcolarle da se
(operazione molto dispendiosa per un normale processore da un punto di vista
computazionale), deleghi il compito al DIOPSIS 740. Per meglio comprendere la
difficoltà di calcolo di un immagine ditherata per una normale CPU di un pc
general purpose è opportuno mostrare una semplice analisi della complessità di
un frammento di codice dell’algoritmo globale, in particolare il ciclo principale
che genera il Dithering di un semplice pixel con l’algoritmo di Steinberg.
51
CAPITOLO 3. Descrizione del Sistema Globale
Analizzando il seguente listato in MatLab ed i relativi cicli for scritti in pseudocodice si possono fare le dovute ipotesi sulla complessità di calcolo.
for each y from top to bottom
for each x from left to right
oldpixel := pixel[x][y]
newpixel := find_closest_palette_color(oldpixel)
pixel[x][y] := newpixel
quant_error := oldpixel - newpixel
pixel[x+1][y] := pixel[x+1][y] + 7/16 * quant_error
pixel[x-1][y+1] := pixel[x-1][y+1] + 3/16 * quant_error
pixel[x][y+1] := pixel[x][y+1] + 5/16 * quant_error
pixel[x+1][y+1] := pixel[x+1][y+1] + 1/16 * quant_error
find_closest_palette_color(oldpixel) = (oldpixel + 128) / 256
Figura 3.1: Pseudo Codice dell’ Algoritmo Floyd-Steinberg
A questo punto è facile intuire che se si considera la complessità del
calcolo nel senso di ricostruzione dell’immagine (le due dimensione in pixel
dell’immagine) il problema diventa a questo punto quadratico. Per la verifica di
queste teorie ci si rifarà al capitolo 4 che proporrà delle analisi quantitative su dei
test effettuati in fase di simulazione su Made. La Figura 3.1 che rappresenta
l’algoritmo globale che si vuole ottenere, indica la soluzione proposta per il
problema della generazione dell’immagine Ditherata utilizzando l’architettura
D740. L’immagine originale sarà fornita direttamente dal Matlab che elaborerà
l’istruzione o il codice in Ansi C del vettore che la rappresenta su cui poi sarà
effettuata l’operazione di Dithering. La Figura 3.2 mostra i passi di esecuzione
dell’Algoritmo. Il
processore
ARM
52
considererà
la richiesta
delegando
CAPITOLO 3. Descrizione del Sistema Globale
a sua volta il calcolo vero e proprio del Dithering (essenzialmente costituito da
operazioni su elementi del vettore) al Magic del DSP. Mentre questi elabora i dati,
l’ARM inizierà a prelevare i risultati della computazione. E’ a questo punto
evidente come l’applicazione sfrutti da un lato la presenza contemporanea dei due
processori del DIOPSIS 740 (multithreading),e dall’altro la potenza di calcolo del
DSP (mAgic). Un primo approccio alla Programmazione si è fatto realizzando
l’applicazione del Dithering
di Steinberg attraverso MatLab testandone la
velocità di esecuzione del programma. Successivamente si è passato alla
realizzazione in C dello stesso Programma per poi alla fine inserirlo come codice
nel Software Made. Il nucleo di questa elaborazione in parallelo si concentra nella
gestione della memoria condivisa PARM, successivamente descritta.
I passi Progettuali sono così caratterizzati:
 Realizzazione di un Programma in MatLab chiamato ‘vettore’ che
consente di ricavare come istruzione di codice Ansi C il vettore che
rappresenta l’immagine su cui applicare il Dithering Floyd-Steinberg
realizzato.
 Realizzazione dell’Algoritmo di Dithering Floyd-Steinberg in MatLab partendo dall’Algoritmo in Pseudo-Codice.
 Realizzazione dello stesso Algoritmo sopra descritto in Linguaggio
Ansi C .
 Infine rielaborazione dell’Algoritmo di Dithering Floyd-Steinberg
nell’apposito Linguaggio di Made cioè proprio del simulatore
Diopsis 740 che altro non è che un’ estensione dell’Ansi C stesso.
53
CAPITOLO 3. Descrizione del Sistema Globale
3.2 Realizzazione del programma (in MatLab)
Una volta definita qual’era l’applicazione da realizzare, acquisite le conoscenze
necessarie su come possa essere Ditherata un’immagine, si è iniziato il lavoro di
stesura di un programma in MatLab in grado di fare le stesse cose che dovrà
eseguire il DIOPSIS 740. I Listati di MatLab risultano essere i seguenti:
 Programma ‘vettore’ .
 Programma di Dithering Floyd-Steinberg.
L’Algoritmo di Floyd-Steinberg risulta essere:
54
CAPITOLO 3. Descrizione del Sistema Globale
L’Algoritmo di Generazione del Vettore Immagine da Ditherare risulta:
55
CAPITOLO 3. Descrizione del Sistema Globale
3.3 Realizzazione del programma (in C standard)
Dopo la prima parte di Realizzazione del Programma in MatLab si è iniziato il
lavoro di stesura di un programma in Linguaggio Ansi C per computer generalpurpose in grado di fare le stesse cose che dovrà eseguire il DIOPSIS 740. Il
Programma in C contiene sei file:
1. Inizio.c
2. Dithering.c
3. Quattro_somme.c
4. Globale.h
5. Dithering.h
6. Quattro_somme.h
Il File Inizio.c risulta essere il file contenente il Main che richiamerà la funzione
di Dithering di Steinberg da utilizzare:
56
CAPITOLO 3. Descrizione del Sistema Globale
57
CAPITOLO 3. Descrizione del Sistema Globale
58
CAPITOLO 3. Descrizione del Sistema Globale
59
CAPITOLO 3. Descrizione del Sistema Globale
Il File Dithering.c risulta essere l’algoritmo di Floyd-Steinberg utilizzato:
60
CAPITOLO 3. Descrizione del Sistema Globale
Il file Quattro_somme.c risulta essere una funzione richiamata nel Dithering.c che
consente di comprendere come l’Algoritmo di Dithering descritto sopra lavori su
operazioni o istruzioni semplici relativamente ai singoli pixel:
Il file Globale.h richiama i file dove sono contenuti i prototipi di funzioni e le
librerie dell’Ansi C utilizzate:
61
CAPITOLO 3. Descrizione del Sistema Globale
Il file Dithering.h risulta comprendere il Prototipo della funzione Dithering()
richiamata dal main:
Il file Quattro_somme.h risulta comprendere il Prototipo della funzione stessa
richiamata dalla funzione di Dithering:
3.4 Principali blocchi che costituiscono l’algoritmo
Acquisite le conoscenze base per lo sviluppo dell’applicazione, il passo
successivo è stato quello della divisione del carico di lavoro contenuto in questi
blocchi, esso sarà il cuore dell’applicazione e permetterà di sfruttare al meglio le
funzionalità
di multithreading e calcolo complesso o vettoriale offerte
dall’architettura. La descrizione approfondita del partizionamento del programma
tra i due processori (ARM e mAgic) sarà quindi descritta nella sezione relativa al
profiling dell’algoritmo.
Principali blocchi:
1. Passaggio del vettore immagine dall’ambiente Ansi C al Software di
simulazione di Made;
2. Generazione delle matrici necessarie affinchè l’algoritmo creato possa
operare sull’immagine originaria per ditherarla attraverso la procedura
specifica di Floyd-Steinberg;
3. Mappaggio di ciascun pixel dell’immagine;
4. Calcolo del Dithering Floyd-Steinberg(usando l’algoritmo descritto
precedentemente);
62
CAPITOLO 3. Descrizione del Sistema Globale
5. Generazione dell’immagine Ditherata e salvataggio di quest’ultima su di un
file con estensione ‘.m’ propria del Software MatLab per poterne
visualizzare i risultati ottenuti.
In prima approssimazione, senza aver ancora effettuato del profiling
sull’implementazione
dell’algoritmo,
si
può
dedurre
quali
saranno
computazionalmente i blocchi più dispendiosi, cioè quello relativo al mappaggio
dei pixel e, logicamente, quello relativo al calcolo effettivo dell’immagine
Ditherata. Sia da subito chiaro che il calcolo dell’immagine ditherata sarà
destinato al DSP, non si può
ancora dire nulla sugli altri blocchi poichè è
necessaria una fase di profiling per decidere un buon partizionamento.
3.5 Partizionamento dell’algoritmo sui due processori
Sulla base dei risultati della precedente fase di profiling, si è decisa la migliore
suddivisione dei diversi blocchi tra ARM e mAgic, in modo tale da ottenere il
massimo vantaggio dalla presenza contemporanea dei due processori (multithrad)
e di sfruttare totalmente la potenza di calcolo del DSP mAgic. Come mostrato
nella sezione precedente, le metriche prese in considerazione per definire questa
suddivisione sono state essenzialmente il tempo d’esecuzione dei vari blocchi
(misurati su comuni pc),il numero ed il tipo di istruzioni eseguite considerando
due possibili partizionamenti dell’algoritmo stesso. L’obiettivo era quello di
eseguire su mAgic il maggior numero il operazioni possibili, lasciando ad ARM la
computazione di calcoli interi , facendo anche in modo che tutto si svolgesse in
parallelo. Per quanto riguarda le fasi la prima soluzione consiste nel lasciare ad
ARM l’operazione di creazione delle Matrici su cui eseguire poi il Dithering,
dedicando completamente mAgic alla fase di calcolo dell’Algoritmo stesso.
Intuitivamente il fatto di mettere la fase di generazioni delle Matrici su ARM
può essere
giustificata dal fatto che, pur usando
63
numeri
interi,
tale
CAPITOLO 3. Descrizione del Sistema Globale
fase non è particolarmente pesante. Una soluzione alternativa a quella appena
descritta consiste nello spostare la fase di generazioni delle Matrici su mAgic per
poter sfruttare al meglio l’architettura a 40 bit del DSP. Nel primo caso infatti
mAgic si troverebbe a lavorare con dei valori interi calcolati su 32 bit perdendo
quindi in precisione avendo a disposizione registri a 40 bit. Quale delle due
soluzioni sia la migliore potrà essere deciso solo implementandole entrambe su
scheda ed effettuando un confronto approfondito sui tempi d’esecuzione. La
spiegazione a questo problema è trattata nel Capitolo 4 che fa proprio riferimento
all’analisi dei dati ottenuti sperimentalmente con il programma implementato su
Made. In ognuno dei casi, per effettuare il partizionamento sfruttando
completamente le potenzialità multitrheading è necessario utilizzare la memoria
condivisa PARM in un modo particolare, cioè come una coda ciclica.
3.6 Descrizione del metodo di sincronizzazione
Le tecniche di sincronizzazione che sono previste per i due processori sono
polling e interrupting. Per quanto riguarda il secondo metodo (interrupting), il
procedimento e` complicato da gestire, ma essenzialmente consiste nello scambio
di particolari segnali tra i due processori (segnali di interrupt) ogni qual volta uno
dei due richieda l’intervento dell’altro. Questo tipo di gestione può garantire
prestazioni elevate, ma per l’applicazione che si è deciso di sviluppare (che
impegna i due processori per eseguire sempre le stesse operazioni) non è
necessaria, pertanto è stato scelto il metodo di polling. L’idea
base
della
sincronizzazione per ottenere un reale multithreading del D740 consiste
nell’utilizzare la memoria condivisa PARM come se fosse una coda ciclica. In
pratica si considera un numero finito di celle di memoria nella PARM (non
necessariamente tutte quelle a disposizione) e le si utilizzano sequenzialmente
puntandole con degli indici. Una volta raggiunta la fine della memoria si
ricomincia dall’inizio ( alternando il segno degli indici da positivo a negativo a
seconda della pagina
identificata). ARM si incarica di mettere in memoria
64
CAPITOLO 3. Descrizione del Sistema Globale
i dati da processare e prelevarli alla fine della computazione di mAgic. mAgic da
parte sua deve verificare che nella memoria vi siano dati pronti da processare, in
caso affermativo li carica
nei propri registri ed effettua la computazione
scrivendo i risultati nella stessa cella di memoria da cui ha letto i dati. Il principio
di funzionamento a regime dovrebbe essere quello di avere ARM sempre più
“avanti” di mAgic poiché quest’ultimo deve compiere l’oneroso calcolo del
Dithering;
Figura 3.2:Ulteriore disposizione dei banchi di memoria ARM
ARM invece si deve solo preoccupare di mappare i pixel da questa particolare
configurazione di memoria. Per una migliore chiarezza d’ora in poi quando si farà
riferimento a “una cella” di memoria si intenderà la coppia banco destro - banco
sinistro, necessaria a contenere i valori complessi. Una “pagina” invece si
riferisce all’insieme delle celle. Questo modo di gestire i dati e tenere
sincronizzate le CPU si basa su un semplice controllo dello stato degli indicipuntatori che fanno riferimento alle celle di memoria e all’attivazione o messa in
attesa dei processori. In particolare la sostanziale differenza tra i due metodi di
partizionamento sta nelle operazioni
65
CAPITOLO 3. Descrizione del Sistema Globale
che compiono le due CPU. Nel primo caso ARM si occupa della generazione
delle matrici che poi si utilizzeranno in magic
mentre mAgic si occupa
esclusivamente del calcolo dell’Algoritmo di Dithering, nel secondo caso invece
ARM non gestisce nulla, la generazione delle matrici ed il calcolo dell’algoritmo
di Dithering sono compiti delegati a
mAgic.
A
livello di codice
questa
differenza è esigua, si tratta infatti di far eseguire dei blocchi di programma a
un processore piuttosto che all’altro semplicemente spostandoli dal sorgente di
ARM a quello di mAgic.
3.7 Porting in ambiente MADE-Simulazione e JTST
Uno volta terminata la fase di profiling e decisa la suddivisione dell’algortimto,
l’ultimo passo prima di andare effettivamente su scheda e verificare il corretto
funzionamento dell’applicazione, è quello di scrivere il codice capace di
funzionare nell’ambiente di simulazione MADE. Lo stesso codice poi verrà
trasferito su JTST e quindi nel DIOPSIS 740. La principale difficoltà consiste
nell’attuare il meccanismo della coda ciclica descritto precedentemente. La fase di
porting in MADE permette anche di osservare il corretto funzionamento del
metodo di scambio di valori float tra ARM e mAgic. Il simulatore a disposizione
infatti emula in ogni dettaglio l’architettura e il funzionamento del reale chip
D740.
L’unica sostanziale differenza è
la velocità
di calcolo: essendo un
simulatore che riproduce via software le caratteristiche di un componente
hardware, risulta molto limitato in termini di prestazioni e queste ultime
dipendono molto dalla potenza del PC su cui è
in esecuzione MADE e
dall’ambiente che lo supporta. Tutte le analisi di tipo quantitativo (ad esempio le
tempistiche d’esecuzione) non sono da considerarsi attendibili. In questa fase
infatti tutte le configurazioni d’ingresso che si sono testate per verificare il
corretto funzionamento dell’algoritmo non sono mai state “reali” nel senso che
venivano introdotti valori che permettessero di verificare l’esattezza delle funzioni
66
CAPITOLO 3. Descrizione del Sistema Globale
senza attendere troppo tempo per la conclusione della computazione. Si è cercato
di limitare quindi la dimensione delle immagini (che non saranno comunque
effettivamente generate) e il numero di iterazioni da considerare. L’Algoritmo di
Dithering in questa fase non è direttamente visibile. Un’altra funzione analoga
nel programma di test in ANSI C (quello su cui si è effettuato il profiling)
permette il confronto dei dati in output per verificare la correttezza del
funzionamento. Su simulatore infatti non si riesce a simulare il funzionamento
della porta USB della JTST collegata a una porta USB di un normale personal
computer. Per quanto riguarda il funzionamento su scheda JTST basta avere a
disposizione il programma creato per il simulatore con le dovute modifiche sul
collegamento USB e quindi sull’invio dei dati. Come spiegato nel capitolo 1 in
cui sono descritti i tool di sviluppo, MADE permette di compilare un progetto o
per funzionare sul simulatore (Cycle Accurate Simulator) o per funzionare su
scheda JTST (DIOPSIS Target).
In quest’ultimo caso però
bisogna che il
computer che ha in esecuzione MADE sia collegato alla JTST attraverso un
canale seriale per l’amministrazione della scheda.
3.8 Conclusioni
In questo capitolo si è analizzato come si è voluto implementare l’algoritmo
di
Dithering di Floyd-Steinberg soffermandoci sulle scelte progettuali,
comparandole con le varie opportunità. . Nei prossimi capitoli saranno presentati i
risultati sperimentali ottenuti dall’analisi dell’algoritmo sviluppato sul simulatore
Made.
67
Capitolo 4
Analisi dei risultati
In questo capitolo verranno proposti i test a cui è stata sottoposta l’applicazione
ed i risultati ottenuti, analizzando per prima la simulazione dell’algoritmo con
Matlab ed il Software Arm Development suite. Inoltre in questa sezione si
produrranno
i
risultati sperimentali ottenuti eseguendo il programma sul
simulatore di MADE e sul Software Arm Development suite e quindi direttamente
sul programma implementato in linguaggio Ansi C. Questi risultati vorranno
quindi dimostrare l’effettiva bontà dell’applicazione sviluppata nel senso dello
sfruttamento dell’architettura messa a disposizione dal D740 e nel senso del
funzionamento in multithreading, dimostrando quindi la possibilità di avere i due
processori in esecuzione realmente in parallelo senza perdita di prestazioni.
4.1 Simulazione in ambiente MADE
Il simulatore MADE, descritto nel capitolo 1 si propone di fornire agli
sviluppatori un’interfaccia che riproduca fedelmente l’architettura del DIOPSIS
740. In questo modo i progettisti possono implementare e provare il
funzionamento delle applicazioni senza aver direttamente a disposizione i
componenti hardware e senza rischiare di danneggiarli. A livello di prestazioni il
simulatore messo a disposizione da MADE è molto scarso in quanto si tratta di un
componente software che emula l’hardware del D740. E’ quindi sconsigliato
caricare il simulatore di pesanti computazioni matematiche, ma utilizzarlo
unicamente con lo scopo di verificare la funzionalità degli algoritmi ideati. Per
questa ragione il simulatore, anche nel caso di studio, è stato utilizzato solamente
per testare l’effettivo corretto funzionamento dell’algoritmo di generazione di
Dithering Floyd-Steinberg, e la corretta sincronizzazione dei due processori.
68
CAPITOLO 4. Analisi dei Risultati
Un’altra limitazione dell’utilizzo del simulatore è che riproduce solo il chip
D740, non la scheda di test JTST. Tutte le operazioni che utilizzano quindi le
periferiche e i dispositivi presenti sulla board potranno essere verificate solo
implementando
il
progetto
direttamente
sulla
scheda.
Nello
sviluppo
dell’applicazione presa in esame, si è potuto mettere in atto il meccanismo
dell’utilizzo della memoria condivisa PARM, dimostrandone il suo corretto
funzionamento. I sorgenti editati che costituiscono il progetto compilabile da
MADE sono essenzialmente i sei file C e fanno riferimento al codice che deve
eseguire ARM ed a quello che deve eseguire mAgic. Nel nostro caso si è supposto
che Arm raccoglie solo i dati opportunamente trattati dal magic attraverso
l’algoritmo di Dithering e stampa a video il risultato dell’operazione; quindi è
solo Magic che provvede all’intera esecuzione dell’Algoritmo. Il cuore di esso
(cioè i numerosi calcoli nel dominio complesso e vettoriale) sono prerogativa
del DSP mAgic.
Per una più
accurata descrizione del partizionamento si
manda il lettore al capitolo 3 che espone i diversi metodi di partizionamento del
codice e ne motiva le scelte implementative. Per i motivi sopracitati in questa fase
non è possibile avere un’analisi approfondita del corretto funzionamento
dell’applicazione. Si è potuto constatare unicamente la perfetta sincronizzazione
dei due processori e la corretta generazione dell’immagine Ditherata. E’ da notare
che il progetto compilato su simulatore non sarà per niente differente da quello
che si andrà
a compilare per la scheda JTST, l’unica differenza consisterà nei
parametri dell’immagine da generare. Su scheda saranno infatti impostati valori
che renderanno possibile anche un’analisi quantitativa dell’esecuzione del
programma.
69
CAPITOLO 4. Analisi dei Risultati
4.2 Confronto tra Diopsis e Personal Computer
Appena si esegue l’applicazione su hardware questa risulta molto più
veloce
rispetto a quella eseguita sul simulatore (come da aspettativa), tanto che su
quest’ultimo, non è
neppure possibile visualizzare i risultati poichè la
computazione è troppo veloce per le printf che dovrebbero dare indicazioni sullo
stato d’esecuzione. Con queste premesse è subito chiaro come l’algoritmo scelto
si sposa bene con l’architettura a disposizione. La generazione di un’immagine su
un normale PC di media potenza con determinati parametri è sempre più lenta
della stessa immagine generata con DIOPSIS. Da notare però è il fatto che più
l’immagine è semplice (cioè minore è il dettaglio che si vuole visualizzare
dunque minore è il numero di righe e colonne che si vuole considerare), più la
tempistica d’esecuzione del Personal Computer si avvicina a quella della scheda
che monta D740. E` subito chiaro (e lo si era supposto fin dall’inizio) che
l’utilizzo del chip D740 offre i maggiori benefici in quelle applicazioni dove è
necessario un elevato livello di dettaglio o nell’elaborazioni di immagini di grandi
dimensioni. Il primo caso si riferisce a quelle applicazioni dove bisogna entrare
nell’infinitamente piccolo. In parole povere cioè quando si zooma un particolare
dell’immagine. Nel caso di figure più grandi non c’e` bisogno di fare un esempio,
e` intuitivo capire che maggiore sarà il numero di pixel da calcolare maggiore
sarà il tempo necessario al calcolo. L’analisi che prevede il confronto tra le
prestazioni di un comune PC General Purpose e il sistema costituito da DIOPSIS
è quindi presto fatta. Non è possibile valutare quantitativamente il miglioramento
di prestazioni poichè l’algoritmo eseguito su un normale computer è sensibile
alla potenza del processore montato, alla memoria a disposizione e, in generale, al
livello di carico del sistema operativo.
70
CAPITOLO 4. Analisi dei Risultati
4.2.1 Analisi delle prestazioni dei diversi partizionamenti
Nel capitolo 3 sono stati descritti in dettaglio i due diversi metodi di
partizionamento dell’algoritmo.
diverse
In questa sezione si vogliono analizzare le
prestazioni, i metodi individuati e determinare quindi quale sia la
migliore scelta progettuale. Come prima cosa sarà analizzato il partizionamento
“finto”, cioè
quello che prevede l’esecuzione di tutto l’algoritmo sul solo
processore ARM, giusto per dimostrare l’effettivo sfruttamento dell’architettura in
relazione all’altro caso in questione. Con questa soluzione infatti la computazione
risulta essere molto lenta. A parità
di parametri iniziali la generazione
dell’algoritmo di Dithering con la sola CPU ARM è
più lenta di quella eseguita
sul Personal Computer. Questo risultato è da considerarsi quasi scontato poiché
ARM è una CPU RISC a 32 bit molto versatile ma con poca potenza in campo
matematico. Non implementa infatti alcun tipo di coprocessore matematico
(presente invece nei processori CISC dei Personal Computer), ma d’altra parte la
funzione per cui è stato progettato non è assolutamente quella di compiere
calcoli e gestire valori floating point e/o vettoriali.
Confronto tra i due partizionamenti ARM-mAgic
Molto più importante e sicuramente più valido è il confronto tra le prestazioni
dell’applicazione sviluppata analizzando i due partizionamenti tra il processore
ARM e il DSP mAgic. In questo caso si è supposto che Arm si occuperà solo
della stampa a video della matrice opportunamente Ditherata, mentre Magic ha il
compito più oneroso cioè quello di gestire l’intero Algoritmo. Questo tipo di
partizionamento aumenterà il numero di iterazioni da compiere, aumenta così il
carico di lavoro del DSP che quindi risulta più
lento nel calcolo, ma può
concentrarsi ad eseguire solo quello. Il collo di bottiglia del sistema risulta quindi
essere il DSP, che però è utilizzato esclusivamente per compiere le operazioni
per cui è stato progettato, cioè calcoli floating point in campo complesso e/o
71
CAPITOLO 4. Analisi dei Risultati
vettoriali. In generale l’esecuzione dell’Algoritmo da parte del Magic è
sicuramente più veloce rispetto a quello eseguito dalla sola Arm. In definitiva il
miglior metodo di partizionamento dipende molto dalle esigenze dell’utilizzatore,
ma per l’applicazione che si è sviluppata, che si proponeva di dimostrare
l’effettiva possibilità di utilizzare parallelamente i due processori, il migliore
metodo resta comunque il secondo. Infatti è in quest’ultimo caso che si è notata la
migliore tempistica di esecuzione di calcoli da parte del Magic.
4.3 Calcolo cicli di clock dell’Algoritmo
Per
effettuare l’analisi e dunque il calcolo dei cicli di clock impiegati dal
programma complessivo realizzato con Linguaggio (Ansi C) ed opportunamente
implementato sul Simulatore Made si è utilizzato il Software Arm developer suite
che permette a seconda dell’architettura Arm utilizzata di calcolare o più
precisamente testare l’Algoritmo implementato dandoci indicazioni sui cicli di
clock necessari al funzionamento dell’intera applicazione. Nello specifico ci si è
soffermati sul calcolare i cicli di clock necessari
ad effettuare l’operazione
elementare di somma su singoli bit presente nell’algoritmo di Dithering di FloydSteinberg applicato su immagini in scala di grigio, per poter comprendere al
meglio fino a quale limite il Diopsis740 potesse spingersi. Inizieremo ad
analizzare come si può settare ed utilizzare il Software Arm Developer Suite.
4.3.1 Software Arm Developer Suite
Prima di utilizzare tale Software è opportuno creare il progetto con i file C
implementati e utilizzati dal Simulatore Made. Una volta eseguita tale operazione
è possibile Compilare il progetto dalla schermata del Software come in figura 4.1.
72
CAPITOLO 4. Analisi dei Risultati
Tramite questa procedura il Compilatore otterrà il codice Assembler ottimizzato
su cui poi effettuare il Testing e nel nostro caso ci fornirà i cicli di clock necessari
ad eseguire l’intero programma. Tutto questo però dopo un’opportuna fase di
settaggio che serve a specificare il processore Arm che si è utilizzato e quindi nel
caso in questione quello che utilizza Made.
Figura 4.1: Finestra di Compilazione Software Arm
Una volta fatto il DebugRel dell’Applicazione sviluppata in linguaggio Ansi C è
possibile accedere alla schermata AXD come in figura 4.2. Tale programma
utilizza l’immagine creata del codice Assembler e quindi del programma C
compilato. Prima dell’esecuzione del Testing sull’immagine si setta tramite il
pulsante ‘Option’ e poi ‘Configure Target’ il processore Arm specifico utilizzato
cioè quello del Simulatore Made dell’Atmel che risulterà essere l’ ARM7TDMI
come in figura 4.3.
73
CAPITOLO 4. Analisi dei Risultati
Figura 4.2: Finestra AXD per la fase di Testing
Figura 4.3: ARMulator Configuration
74
CAPITOLO 4. Analisi dei Risultati
Una volta terminata la fase di settaggio dell’AXD è opportuno caricare
l’immagine premendo con il tasto destro sull’ARM7TDMI
in questo modo
comparirà il codice Assembler del programma prima compilato su cui verranno
poi effettuati gli opportuni test come in Figura 4.4.
Figura 4.4: Codice Assembler di AXD
Per visualizzare i cicli di clock necessari ad eseguire l’intero programma lo si fa
tramite l’opportuna combinazione di tasti ‘Execute’ e poi ‘Go’. Fatto questo si
apre la finestra per visualizzare i Cicli di clock impiegati dal programma tramite
‘System Views’ e poi ‘Debbuger Internals’ come in figura 4.5. Si è fornita una
descrizione molto veloce dell’utilizzo del Software che mi permette di ottenere i
risultati finali da analizzare.
75
CAPITOLO 4. Analisi dei Risultati
Figura 4.5: Debugger Internals
4.4 Analisi dei Risultati
Si è utilizzato il codice Assembler compilato dal Software Arm developer suite
come visto in figura 4.4 per effettuare il Debug al fine di analizzare quanti cicli di
clock necessita l’algoritmo per eseguire le quattro somme che sono poi alla base
del calcolo del Dithering. In figura 4.6 è mostrato il codice assembler
dell’operazione quattro somme di cui si forniranno i risultati. Per lo specifico
processore utilizzato, dunque l’ARM7TDMI,
c’è una corrispondenza tra
istruzioni assembler elencate e cicli di clock necessarie ad eseguirle. Bisogna
ricordare che il processore Arm è in grado di trasferire ,da o in memoria, un
76
CAPITOLO 4. Analisi dei Risultati
qualsiasi sottoinsieme dei sedici registri con una singola istruzione. Di seguito si
definirà tale corrispondenza:
LDR: necessita di 3 cicli di clock
ADD: necessita di 1 ciclio di clock
STR: necessita di 2 cicli di clock
Figura 4.6: Codice Assembler per operazioni quattro_somme
Si può dunque constatare che per ogni quattro somme dell’algoritmo di Dithering
applicate ai singoli pixel dell’immagine da modificare sono necessari 24 cicli di
clock. Quindi in base alla dimensione dell’immagine su cui lavorare si ottengono
valori di cicli di clock utilizzati per eseguire l’operazione diversi. In figura 4.7 si è
calcolato il peso dell’operazione corrispondenti ai cicli di clock ed
dimensione dell’immagine e si è stimato anche
il costo computazionale
dell’operazione in relazione all’intero algoritmo implementato.
77
alla
CAPITOLO 4. Analisi dei Risultati
Figura 4.7: Risultati ottenuti sull’Arm7TDMI
Com’è possibile vedere dalla figura 4.7 l’onere computazionale delle quattro
somme è mediamente dello 0,35%
per un numero di pixel dell’immagine
variabile tra 25 e 40000 elementi. Inoltre si può notare come all’aumentare dei
numeri di elementi o dei pixel costituenti l’immagine il peso computazionale delle
quattro somme cresce anche se in maniera non rilevante.
Ora si effettua lo stesso calcolo sui cicli di clock attraverso l’algoritmo
implementato sul processore mAgic di Made per farne un confronto con i risultati
appena ottenuti su Arm. Per far ciò si utilizzerà una specifica funzione del
compilatore Made, ‘mAgic Disasm’ che consentirà di analizzare direttamente le
istruzioni VLIW e calcolare, come nel precedente caso, il numero di cicli di clock
impiegati per effettuare le quattro somme. La figura 4.9 evidenzia proprio la
finestra di Made dove sono presenti le istruzioni VLIW. Ricordando che magic
può eseguire in un singolo ciclo di clock (a 100Mhz) 4 moltiplicazioni floating
point, 3 addizioni floating point e 3 sottrazioni floating point, oppure 4
moltiplicazioni floating point, 3 addizioni floating point, 3 sottrazioni floating
point, 2 accessi alla memoria, 2 aggiornamenti degli indirizzi e 1 accesso a DMA,
dalla Tabella VLIW si evince che per eseguire le quattro operazioni elementari di
somma il mAgic necessita solo di 16 cicli di Clock e dunque di soli quattro cicli
78
CAPITOLO 4. Analisi dei Risultati
di clock per somma. Dalla figura 4.8 si evidenziano
e
confrontano
sia i
risultati ottenuti dall’ARM7TDMI sia quelli di mAgic nell’eseguire le operazione
di quattro somme. Inoltre la Tabella evidenzia il guadagno computazionale
ottenuto da mAgic.
Figura 4.8: Confronto dei risultati ottenuti con ARM7TDMI e mAgic
Figura 4.9: Istruzioni VLIW di mAgic
79
CAPITOLO 4. Analisi dei Risultati
4.5 Conclusioni
Questo capitolo si è preposto come obiettivo quello di analizzare i risultati dei test
effettuati sull’algoritmo implementato su Made, mostrando le caratteristiche delle
varie soluzioni e in particolare dell’esecuzione dell’operazione di quattro somme
presenti nell’algoritmo di Dithering sul processore Magic e su quello Arm.
Tramite il Software Arm Developer Suite si è stimato quanti cicli di Clock
necessita l’operazione sopra descritta e lo stesso lo si è fatto per l’algoritmo
implementato in mAgic sfruttando la tabella di istruzione VLIW.
80
Capitolo 5
Conclusioni e sviluppi futuri
L’obiettivo principale di questo lavoro è il confronto tra le prestazioni
dell’architettura Diopsis740 e Arm7 attraverso l’implementazione di un algoritmo
di Dithering per immagini in scala di grigio. Il D740 si è rivelato adatto alle
applicazioni in cui è necessario operare con velocità su imponenti flussi di dati.
In primo luogo si è proposta di dimostrare la capacità di mAgic di accelerare le
prestazioni di Arm7. E` stata prima di tutto presentata e descritta l’architettura del
sistema e gli strumenti necessari a comprenderla ed a farla funzionare. In seguito
è stato descritto l’algoritmo implementato per raggiungere lo scopo del lavoro di
tesi dando particolare enfasi a come poter mettere in crisi il processore avendogli
dato un numero enorme di dati su cui lavorare e quindi si è cercato di testarne i
punti deboli. Tutto questo lo si è fatto poiché il Diopsis740 è stato ideato proprio
per sfruttare al meglio le caratteristiche di multithreading. L’algoritmo di
Dithering, studiato, ha dimostrato di essere una tecnica semplice e abbastanza
efficace, forse più utile ai fini di studio delle caratteristiche di un’applicazione
DSP. La più comune applicazione del dithering è mostrare in modo più accurato
gli elementi grafici che contengono un range di colori più ampio di quello di cui
dispone l’hardware che li deve visualizzare. Ad esempio il dithering può essere
usato per mostrare una fotografia contenente milioni di colori su un hardware
video che può solo rendere 256 colori per volta. In una situazione come questa, in
cui l’hardware del display del computer è il limite primario alla color depht
(risoluzione del colore), il dithering è impiegato nei software come i web
browsers. Un’altra applicazione utile per il dithering si ha in situazioni in cui il
formato del file grafico è il fattore limitante. In particolare il noto formato GIF è
vincolato all’uso di 256 colori o meno. In tali casi i software di editing grafico
sono responsabili di effettuare il dithering sull’immagine prima di salvarla in
questi formati di compressione.
81
CAPITOLO 5. Conclusioni e sviluppi futuri
Nel nostro caso partendo da un’immagine in scala di grigio con un range di valori
tra 0 e 255, si è potuto giungere per mezzo dell’operazione di Dithering ad
un’immagine a soli due bit, con conseguente diminuzione di spazio in memoria.
C’è da dire che possono essere effettuati molti miglioramenti alla tecnica, come
per esempio l’introduzione dei meccanismi di pre e post-processing, o l’utilizzo di
matrici per l’error diffusion più accurate e quindi più grandi e dispendiose da un
punto di vista computazionale. L’applicazione prodotta lascia aperta la strada a
nuovi studi, ricerche e miglioramenti. Completato il lavoro di progettazione, su
simulatore, si è voluta dare un’analisi dei risultati ottenuti calcolando tramite il
Software Arm Developer Suite il numero dei cicli di clock necessario
all’esecuzione dell’Algoritmo sviluppato ed in particolare ci si è soffermati ad
analizzare i
cicli
di
clock
necessari
ad effettuare le operazioni
elementari di somma presente nella funzione di Dithering stessa. La stessa
operazione la si è fatta facendo funzionare l’algoritmo su mAgic questo per
comprendere meglio come il mAgic di Diopsis lavori sui singoli bit ma in
particolar modo si sono ricavati i risultati ottenuti tramite questi due modi di
operare per effettuarne un confronto e per mettere in luce le peculiarità in termini
di prestazioni computazionali di mAgic. Per quanto riguarda i lavori futuri in
primo luogo ci sarebbe la completa implementazione direttamente su scheda
affrontando nello specifico l’implementazione della comunicazione USB tra la
scheda JTST e il computer general purpose che la utilizza come periferica. Inoltre
si potrebbe per mezzo di tale modifica passare direttamente il vettore che
rappresenta l’immagine originale, su cui applicare l’Algoritmo di Dithering
implementato, direttamente ad ARM. Bisogna ricordare che sono infatti presenti
dei bachi nel driver di controllo fornito da Atmel che non permette un corretto
funzionamento della porta USB
del dispositivo. Il
driver
fornito
infatti,
permette la corretta comunicazione via USB tra la JTST e il Personal Computer
solo se vengono incluse nei file di progetto delle librerie di eCos che però non
sono a disposizione nella versione fornita da Atmel per lo sviluppo di questo
progetto.
82
CAPITOLO 5. Conclusioni e sviluppi futuri
Un’altra possibile estensione potrebbe essere quella di pensare di trovare
un’applicazione reale che possa sfruttare le caratteristiche del D740 che questo
lavoro di tesi ha voluto portare alla luce, cioè
sfruttare le caratteristiche di
multithreading offerte dalla presenza contemporanea di due CPU nello stesso
componente integrato per elaborazioni su immagini. Oltre alle conclusioni
tecniche sull’efficienza del sistema oggetto di studio e della tecnica di
generazione dell’immagine Ditherata, vorrei spendere qualche riga in più per
commentare il lavoro svolto. Per la prima volta infatti mi sono trovato di fronte a
un problema tecnico completo, formato da una prima parte di studio delle
risorse con cui lavorare, una seconda parte di progettazione e tutto sommato il
lavoro è
stato svolto in tranquillità , seppur con qualche difficoltà tecnica. La
maggior soddisfazione è stata quella di aver prodotto un’applicazione utile e
funzionante, riuscendo ad applicare le conoscenze acquisite nel corso di questi tre
anni di studi nell’ambito dell’informatica, dell’elettronica digitale, della logica dei
sistemi hardware e della teoria dei segnali.
83
Bibliografia
[1] Microsoft Software Development Network (MSDN - October 2001) and the
online release of MSDN http://msdn.microsoft.com/
[2] DIOPSIS 740 Dual Core DSP Atmel Documentation, 7001A-DPS-09/04,
Maggio 2004.
[3] MADE User Guide,MADE Multicore Application Development Environment
(draft), Settembre 2004.
[4] JTST User Guide, JTST AT572D740-DK1 DIOPSIS 740 DEVELOPMENT
KIT, Maggio 2004.
[5] Atmel R . DIOPSIS R 740 Dual-core DSP. Documento PDF (doc7001.pdf).
[6] Atmel R . mAgic C Compiler, User Guide. Documento PDF (doc7005.pdf).
[7] Atmel R . mAgic DSP Instruction Set. Documento PDF (doc7002.pdf).
[8] Atmel R . JTST AT572D740-DK1 DIOPSIS R 740 Development Kit. Documento PDF (doc7003.pdf).
[9] Atmel R . MADE Multicore Application Development Environment. Documento PDF (doc7003.pdf).
[10] Atmel R . DSP library. Documento PDF (doc7007.pdf).
[11] H.Schildt,C++:The Complete Reference, 4th Edition (Paperback),McGraw-
84
Hill Osborne Media, Novembre 2002.
[12] IEEE,The Institute of Electrical and Electronics Engineer http://www.ieee.org
[13] E.R. Altman, K. Ebcioglu, Full System Binary Translation: RISC to VLIW,
IBM Research Report RC23262, Yorktown Heights, NY, March 2000.
[14] M. Falcetti, M. Marelli, A. Margara, Detailed Report - Nameless for Atmel
DSP-Contest 2005, Agosto 2005.
[15] M. Falcetti, M. Marelli, A. Margara, Documento di Progetto RLA - Diopsis
DSP Contest 2005, Luglio 2005.
[16] Emberee, Paul M. C Algorithms for Real Time DSP pagg. 186 - 237.
[17] Nick E.ord. Digital Image Processing: a practical introduction using Java.
Addison-Wesley, 2000.
[18] V. Tagliasco P. Morasso. Eidologia Informatica: immagini e computer. NIS
La Nouva Italia Scienti.ca, 1984.
[19] W.K. Pratt. Digital Image Processing. John Wiley & Sons, 1991.
[20] J.C. Russ. The Image Processing Handbook. IEEE Press, 1999.
85
86
87