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