Insegnamenti di Sistemi Elettronici Dedicati 1 (Corso di Laurea in Ingegneria Elettronica) Sistemi Elettronici Digitali1 (Corso di Laurea Specialistica in Ingegneria delle Telecomunicaizoni) DSP Digital Signal Processors Edizione 2004 Rodolfo Zunino 1. Introduzione: caratteristiche descrittive dei DSP L’elaborazione dei segnali digitali rappresenta i segnali analogici del mondo reale con una sequenza discreta di numeri discreti ed elabora tali numeri per estrarre informazioni od operare trasformazioni su questi segnali. La famiglia di processori che realizzano tali operazioni sono noti come DSP (Digital Signal Processors). Possiamo convertire i segnali analogici in digitali attraverso un processo di conversione A/D, elaborare i segnali con i DSP e, se questo è necessario, portare i segnali di nuovo in uscita nel mondo analogico attraverso una conversione D/A. Rispetto ad un sistema analogico, i sistemi elettronici digitali sono maggiormente insensibili al rumore provocato da cambiamenti di temperatura, umidità o da altri fattori. Altri vantaggi rispetto ad un sistema analogico riguardano la facile riprogrammabilità per altre applicazioni e la predicibilità dei risultati, caratteristiche tipiche dei sistemi digitali. Nell’ambito del Signal Processing, i DSP offrono il supporto ottimizzato a ben precisi algoritmi di riferimento; in quanto tali, i DSP possono esser visti come componenti dedicati alla classe di algoritmi numerici per l’elaborazione di segnali digitali. Un DSP unisce velocità e potenza di calcolo per elaborare i dati in tempo reale. Questa sua capacità lo rende perfetto per applicazioni che non possono tollerare ritardi nelle risposte del sistema. Non è sempre vero che un DSP è meno potente di un microprocessore: infatti, anche se la sua frequenza di clock (~200MHz) è notevolmente inferiore a quella dei microprocessori classici, il DSP per le applicazioni per cui è stato pensato si rivela più veloce di microprocessori come il Pentium. In generale, si dice che il DSP è un componente dedicato, application dependent, mentre il microprocessore è un general purpose. Prestazioni Infatti un microprocessore general purpose può essere estremamente performante nel processo di database e nell’elaborazione di fogli elettronici, ma avere invece delle difficoltà nell’elaborare segnali audio e video in real time. Questo compito può essere svolto efficacemente da un DSP, che non ripone le sue potenzialità in una frequenza di clock elevata, ma in un’architettura diversa da quella di un microprocessore. Criteri di progetto Dato un progetto possono essere diverse le opzioni di scelta, visto che più di un processore può implementare le funzioni richieste. Quindi la soluzione progettuale opportuna sta nel scegliere il migliore DSP fra quelli disponibili. Ciò si ottiene valutando la performance, le dimensioni, la potenza consumata, le caratteristiche, il software ed i tools che ottimizzano i tempi di sviluppo, tenendo sotto controllo i costi. Esiste un tempo di longevità maggiore per i DSP rispetto ai microprocessori. Dopo più di vent'anni dalla loro comparsa, i DSP continuano ad essere processori competitivi: essi sono al centro dell'elaborazione digitale dei segnali. La clock rate di un DSP è limitata dalla potenza che può essere consumata e dall’architettura di sviluppo: la lunghezza delle linee di bus di una scheda è limitata per non trasformare tali linee in antenne indesiderate. Viene limitata la frequenza (es. 200MHz → 40MHz). Nel DSP le schede sono molto compatte: questo può essere facilmente comprensibile, dato il tipo di applicazioni in cui i DSP sono utilizzati (un esempio per tutti è il telefono cellulare). Se prevale l’aspetto controllistico e non l’elaborazione si parla di microcontrollori. 2 Ulteriori differenze tra i DSP ed i microprocessori: • Sample rate: definisce la massima frequenza di campionamento (ad es. 44KHz del CD), dipende dal segnale che deve essere elaborato. Assieme alla complessità dell’algoritmo determina la velocità del DSP. • Rappresentazione numerica: a interi (16 bit), oppure a floating point (32 bit). Le operazioni aritmetiche come addizioni e moltiplicazioni sono il cuore degli algoritmi dei DSP. Di conseguenza, la scelta della rappresentazione numerica ha una profonda influenza sul comportamento e sulle prestazioni degli stessi DSP. Esistono DSP che non trattano la rappresentazione in virgola mobile, ma lavorano solo con grandezze in virgola fissa. • I DSP costano in genere qualche decina di dollari: sono spesso inseriti in sistemi per i quali è determinante avere un prezzo contenuto, come i telefoni cellulari o i modem. Il costo dei DSP, così come il loro mercato, è molto differenziato. Si parla comunque di lotti di produzione, come per i microprocessori. • D/A : • Bisogna pure considerare che un DSP è di solito molto longevo (anche 20 anni), nonché molto affidabile, grazie al lavoro di testing. Tutt’altro discorso vale per i microprocessori. capacità di avere un’interfaccia digitale/analogica 1.1 Che cosa fa un DSP: caratteristiche operative MAC: moltiplicazione + addizione simultaneamente La maggior parte degli algoritmi per l’elaborazione dei segnali richiede un’operazione di moltiplicazione ed addizione del tipo: A = ( B×C )+ D Questa operazione, multiply and accumulate, in un DSP viene effettuata in un solo ciclo di clock. L’operazione di MAC è utile in algoritmi che prevedono il calcolo di prodotti fra vettori, come accade per i filtri digitali e per le trasformate di Fourier. Per poter disporre di questa caratteristica, i DSP presentano moltiplicatore ed accumulatore integrati nella stessa unità aritmetica, chiamata datapath. Accesso multiplo in memoria Un’altra caratteristica importante dei DSP è la capacità di compiere più accessi in memoria in uno stesso ciclo di istruzione. Questo permette al processore di caricare simultaneamente un’istruzione ed i suoi operandi, oppure di salvare in memoria il risultato dell’operazione precedente. Tutto questo grazie alla presenza di due bus indirizzi e due bus dati: aumenta il throughput, ovvero il tasso di emissione di dati in uscita rispetto al flusso di dati in ingresso. 3 Set di istruzioni specifico Per far sì che le operazioni aritmetiche siano calcolate alla massima velocità e che in una singola istruzione siano specificati più operandi, i DSP fanno ricorso ad un set di istruzioni specifico. Questo set riguarda i modi di indirizzamento (addressing modes). I DSP incorporano unità di generazione degli indirizzi, address generation units, che gestiscono la formazione del nuovo indirizzo in parallelo all’esecuzione delle istruzioni aritmetiche. Loop control in hardware Gli algoritmi dei DSP contengono frequentemente istruzioni che devono essere ripetute. Invece di aggiornare un contatore o di eseguire un salto di istruzione all’inizio del loop, i DSP risolvono questo problema via hardware. Esistono infatti delle strutture hardware che effettuano il controllo dei loop: alcune permettono di ripetere per un numero fissato di volte una singola istruzione, altre ripetono un blocco di istruzioni un certo numero di volte (Single- e Multi-Instruction Hardware Loops). I/O interface Per conseguire gli obiettivi di costi contenuti ed alte performance in I/O, molti DSP incorporano una o più interfacce seriali o parallele; inoltre essi utilizzano il direct memory access (DMA). Spesso le interfacce sono direttamente collegate ai convertitori A/D e D/A. Esistono diversi modi di lavorare con un DSP: 1) Evaluation board • Scheda (kit) a basso costo a scopo tutorial • Si interfaccia di solito via parallela • Bassa clock rate (comunque apprezzabile: 20-40 MHz) • Facile da usare (come di solito anche il compilatore fornito insieme ad essa) Il limite dell’evaluation board non è la clock rate bassa, ma soprattutto la connessione via parallela che determina un basso throughput. 2) Scheda professionale • Interfaccia PCI • Elevata clock rate • Facile da usare • Lavora come un coprocessore • Da 1000-1500 € in su Alcune sono espandibili: si può sostituire il DSP o lavorare con multiprocessore. Deve essere ben interfacciata con il computer, dato che un coprocessore deve rispettare le esigenze di calcolo dell’unità host.. 3) Scheda custom • Costo elevatissimo… Hardware: non nel progetto, ma nel testing, molto impegnativo. Software: se si passa alla fase 3 vuol dire che il passo 2 non basta. • Spazio ridotto La scheda custom serve per realizzare un prototipo: il prodotto finale sarà diverso da questo (nessuna pista di testing, …). 4 4) DSP core embedding • Realizzato su chip e non su scheda Il DSP core embedding si usa da parte di un’azienda, quando il layout di un DSP è utilizzato come sottosistema del proprio processore (es. telefoni cellulari). Una via di mezzo fra 3 e 4 è quella di inserire un DSP in un MultiChip Module (MCM). I DSP servono all’industria di consumer electronics; queste sono alcune delle applicazioni: Audio production, audio consumer, wireless communications, motor control, radar, sonar, biomedical, voice over internet, satellite communications, digital cell phones, digital cameras, digital TV, speech processing, seismic processing, instruments, music effects, music synthesis. I maggiori produttori mondiali di DSP sono Texas Instruments, Analog Devices, Motorola. ST Microelectronics, presente in Italia, produce DSP per un mercato advanced ma in un certo qual modo di nicchia. 5 2. Rappresentazione Numerica I processori DSP possono essere raggruppati in due categorie, a seconda della rappresentazione numerica adottata: • Virgola fissa (fixed point) • Virgola mobile (floating point) I DSP in virgola fissa sono caratterizzati dal rappresentare un numero in un intervallo fissato con precisione finita. Valori tipici per la rappresentazione ad interi sono 16, 24 e 32 bit. Le principali caratteristiche di questi processori: • Minore complessità rispetto ai floating point • Costo minore dell’hardware • Maggiore velocità per applicazioni dedicate I DSP in virgola mobile sono più recenti di quelli in virgola fissa ed esprimono i numeri impiegando una mantissa combinata con un esponente. Questo metodo di rappresentazione comporta: • • • • • • • Complessità superiore nell’architettura VLSI Precisione maggiore Facilità di gestione software Tempo di sviluppo minore Si commettono errori proporzionali alla grandezza dei numeri Alto rapporto signal / noise Intervallo di rappresentazione dinamico L’intervallo di rappresentazione varia caso per caso: • • • 16 bit: l’intervallo di rappresentazione va da -32768 a +32767 (per grandezze unsigned, da 0 a +65535 ). 32 bit (fixed point): l’intervallo di rappresentazione va da 0 a 4 × 109. 32 bit (floating point): l’intervallo va da 1.2 × 10-38 a 3.4 × 1038. Per i DSP a floating point si parla di 32 bit ( 24 per la mantissa e 8 per l’esponente ). In un DSP non è garantita la coesistenza di ottimizzazione per floating point ed interi. Si può definire il concetto di precisione: precisione = max valore rappresentato max errore commesso in quantizzazione Al numeratore c’è il massimo valore rappresentato (diverso da quello rappresentabile). In virgola mobile tale rapporto è costante, perché i gap fra due numeri consecutivi sono proporzionali alla grandezza dei numeri in questione: ci sono piccoli gap fra numeri piccoli e grandi gap fra numeri grandi. Questo effetto è dovuto al fatto che i valori rappresentati in virgola mobile non sono ugualmente spaziati fra gli estremi dell’intervallo di rappresentazione, come avviene invece per i 6 fixed point. In virgola fissa la precisione cambia, perché non si riesce a sfruttare appieno la dinamica dei registri. Il rimedio per curare l’errore di precisione è quello di operare un rescaling: si fa coincidere il massimo valore rappresentato con il massimo valore rappresentabile. Spesso le applicazioni DSP trattano segnali analogici, che devono essere convertiti in digitale. Il segnale analogico, continuo e variabile con precisione infinita, deve essere convertito in una serie discreta di misure che devono essere a loro volta rappresentate con valori digitali. Questo processo dà luogo a distorsione nella rappresentazione delle grandezze, chiamata errore di quantizzazione. Il rumore di quantizzazione Quando il segnale analogico è convertito in digitale la precisione è limitata dal numero di bit disponibile. La caratteristica del segnale deve essere rappresentata con una funzione a gradini, introducendo degli errori non lineari e dipendenti dal segnale. A tutto ciò si devono aggiungere gli errori dovuti alla precisione limitata nei calcoli aritmetici all’interno del processore. Inoltre si commettono errori anche nella fase di conversione D/A in uscita. Un modo di descrivere il problema è considerare un’aggiunta di rumore al segnale, attribuendo gli errori di quantizzazione alla presenza di random noise. Valutiamo il signal / noise ratio introdotto dalle due diverse rappresentazioni numeriche; Sia ∆n il gap percentuale tra l’n-mo numero ed il suo consecutivo. Nel caso floating-point, lo scarto assoluto tra un numero ed il suo immediato consecutivo e’ proporzionale al valore del numero (i due numeri hanno pari esponente e differiscono per un bit nella mantissa). Escludiamo gli effetti dovuti a coppie di numeri consecutivi in cui si hanno transizioni di esponente, quindi possiamo dire che l’effetto della quantizzazione sulla precisione dipende solo dalla mantissa. Se questa, come vedremo, viene rappresentata tipicamente con 23 bits, il gap percentuale è costante e vale 1 1 ∆( FP ) = 2 − 23 ⇒ 7 < ∆( FP ) < 6 10 10 il che indica che un numero floating-point è rappresentato (mantissa) con una precisione di circa 7 cifre decimali. Diverso è il caso dei numeri a virgola fissa, in cui lo scarto assoulto tra due numeri consecutivi è costante (uguale a 1), e quindi il gap percentuale dipende dal valore rappresentato: ∆( INT ) = 1 V (dove V è il valore rappresentato) Siamo interessati a studiare l’errore di quantizzazione, εq. In ogni intervallo tra due numeri consecutivi, il suo andamento nell’intervallo tra due numeri consecutivi è lineare: ½ n∆n n(1 - ∆/2) εq n (1+ ∆/2) - ½ n∆n 7 e la sua distribuzione statistica sarà uniforme nell’intervallo considerato, con valore 1/n∆n. Il rumore di quantizzazione, in ogni intervallo considerato ha media nulla: E{εq}= 0. Se ora calcoliamo la varianza di εq, si può derivare che: ∆n 2 ∆n 2 { } ∫ x p(x )dx = ∆1 ∫ x dx = ∆12 . { } σ q2 = E ε q2 − E 2 {ε q } = E ε 2q = 2 − 2 ∆n 2 n − 2 n ∆n 2 Normalmente si studia la deviazione standard dell’errore di quantizzazione, data dalla radice quadrata della varianza: 1 σq ≈ ∆n 3 Ne risulta la deviazione standard dell’errore di quantizzazione è proporzionale al gap percentuale. Nel caso dei numeri floating point, quindi, la deviazione standard dell’errore di quantizzazione è costante entro ogni intervallo, e vale approssimativamente 1 parte su trenta milioni: 1 σ (qFP ) ≈ 10 − 6 ( numeri a 32 bit ) 3 Nel caso dei numeri interi il calcolo e più complesso; per numeri a 16 bit (i più usati nella pratica attuale) si ottiene: σ (qINT ) = 10 − 4 ( numeri a 16 bit ) Guardando la deviazione standard ci sono due-tre ordini di grandezza a favore della rappresentazione floating point. Esempio: TAP nei Filtri FIR Siano x1, x2, … i campioni del segnale, e c1, c2, … i coefficienti pesati: y = x1 c1 + x2 c2 + … x (n) x1c1 x ∆ + C1 x …. C2 ∆ La qualità di un filtro FIR è data dal numero di TAP, ad esempio ce ne possono essere 500: lungo la catena l’errore si somma ad ogni TAP, per 500 volte. 8 L’errore di quantizzazione in un DSP è un fattore strutturale, quello che si può e si deve fare è tenerne conto nello sviluppo dell’algoritmo per evitare la propagazione degli errori dovuta ad un’inefficiente implementazione delle operazioni. Vale infatti la seguente proprietà, dovuta all’aumento nella dinamica numerica introdotta dalle operazioni (soprattutto dalle moltiplicazioni): Legge di conservazione dei bit In generale, quando si moltiplicano due numeri interi di lunghezza n-bit, per rappresentare il risultato senza introdurre errori occorrono 2n-bit. Esempio: Una semplice moltiplicazione che introduce errore può essere: 7-bit × 7-bit → risultato 14-bit → rescaling su 7 → quantizzazione ed errore Si può ottenere una compensazione dell’errore grazie agli accumulatori a precisione estesa (extended precision) presenti nel DSP: • • Per gli interi a 16 bit → accumulatore da 32-40 bit Per i floating point a 32 bit → accumulatore da 80 bit Il range esteso elimina l’errore di round-off (arrotondamento) quando l’accumulazione è in svolgimento. L’unico momento in cui permane il round-off noise è quando l’accumulatore viene scalato e caricato in memoria. Viene fatto ricorso a tutti questi accorgimenti per mantenere la massima dinamica possibile. Standard di rappresentazione Il formato più comune per la rappresentazione dei numeri fixed point è il Qn format. Questo standard, che incorpora le potenzialità offerte dalla notazione in complemento a 2, è molto utile per rappresentare le frazioni e i numeri decimali: n indica il numero di bit dopo la virgola, che è implicita. Per rappresentare i numeri in Q15 sono necessari 16 bit: uno per il segno. Esempio: Sia dato il numero binario 10111101 in formato Q7 e si voglia trovare l’equivalente in decimale: posizione peso Bit 7 segno Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 -1 -2 -3 -4 -5 -6 2 2 2 2 2 2 Bit 0 -7 2 Il numero è negativo, perché il most significant bit, che è il bit del segno, è posto a 1. 10111101 è in complemento a 2 01000010 è in complemento a 1 (si invertono tutti i bit) 01000011 è unsigned (si aggiunge 1) 0(segno) + 1(1/2) + 0(1/4) + 0(1/8) + 0(1/16) + 0(1/32) + 1(1/64) + 1(1/128) = 0.5234375 Dato che il numero è negativo, 10111101 in formato Q7 equivale a –0.5234375 in decimale. Vi sono diversi standard per i numeri floating point: l’ IEEE 754 , che definisce il formato per la singola precisione a 32 bit e per la doppia precisione a 64 bit, è il più usato. In un DSP a 32 bit che segue l’IEEE 754, 23 bit sono usati per la mantissa, 8 bit per l’esponente, un bit è quello di segno. 9 Esempio: Sia dato il numero a 32-bit IEEE 754: 111000010101011000000000000000 1 bit di segno: il numero è negativo 7 6 1 11000010 esponente = 2 + 2 + 2 = 194 -1 -3 -5 -6 10101100000000000000000 mantissa = 1 + 2 + 2 + 2 + 2 = 1.687 (194 - 127) 20 Il numero decimale equivalente è -1.685 × 2 = -2.49031044995 × 10 Criteri di scelta progettuale fra rappresentazione ad interi e floating point: 1) La scelta è determinata dalla precisione del segnale di ingresso (data entry), ovvero dal dato in arrivo dal convertitore A\D, ovvero dalle specifiche del convertitore date dall’applicazione. Un buon criterio di scelta è: < 12bit → interi > 14bit → floating point Esempio: segnale TV digitale, 32 bit (RGB + intensità, 8 bit ciascuno) → interi segnale audio, qualità studio, 20-24 bit → probabilmente floating point 2) La scelta è determinata dalla complessità dell’algoritmo: se è semplice e non modifica la statistica del segnale, si pensa ai fixed point Esempio: SORT: non c’è modificazione dei dati → semplice FFT: contiene prodotti, modifica la dinamica dei dati 3) → difficile La scelta è determinata dal costo: i floating point costano circa 2-3 volte più dei fixed point. Quando viene scelta la rappresentazione ad interi, il costo del prodotto si riduce, ma probabilmente il costo di sviluppo si incrementa per la complessità maggiore (punto 2). Con la scelta dei floating point si ha il ragionamento inverso. Esempio: Una statistica del 1999 sugli utilizzatori di DSP in applicazioni industriali rappresentava così la situazione: il 33% hanno già scelto i DSP il 50% pensano di passare ai DSP il 17% rimangono sui microprocessori Di quelli che hanno già scelto i DSP: il 33% lavorano con i floating point il 66% lavorano con gli interi Di quelli che lavorano con gli interi: il 50% vogliono passare ai floating point il 50% sono soddisfatti così 10 3. Caratteristiche Hardware 3.1 Architettura classica di un DSP Tutti i processori digitali sono costituiti da alcuni moduli fondamentali: • Unità di elaborazione per operazioni aritmetiche e logiche (ALU) • Memorie per conservare i dati e le istruzioni dei programmi • Bus per trasferire in modo efficiente i dati e le istruzioni da una memoria ad una ALU e viceversa. Le usuali operazioni compiute da un processore sono quelle di prelevare dati ed istruzioni dalla memoria, elaborarli ed infine ritornare in memoria per salvarvi il risultato dell’elaborazione. L’equivalente di una ALU in un DSP è il DATAPATH, che può essere definito come il percorso logico aritmetico compiuto dai dati. Esempio: Datapath Fixed point Legge di conservazione dei bit Il prodotto di due numeri di dimensione n-bit dà come risultato un numero di dimensione 2n-bit. Caso 1: virgola implicita a destra x 7 x 7 virgola implicita a destra virgola implicita a destra x x 14 concordi in segno mi tengo i 7 bit meno significativi (mantengo la precisione) Se i primi 7 bit non sono concordi in segno dovrò operare un rescaling. Caso 2: virgola implicita a sinistra x 7 x virgola implicita a sinistra 7 virgola implicita a sinistra x x 14 mi tengo questi bit 11 Overflow Operando in fixed point, ad ogni operazione bisogna che il programmatore consideri l’eventualità che si verifichi il caso di overflow o di underflow. Il tipico strumento per rimediare a questa eventualità è un accumulatore esteso, ma si deve avere anche dell’hardware dedicato: vi devono essere unità che gestiscono tutto in hardware. Tipicamente i DSP non possono permettersi di segnalare overflow senza curarsene e prendere degli accorgimenti, perché in caso di applicazioni critiche non si può interrompere l’esecuzione di un’elaborazione. Nei DSP se un numero va in overflow l’Hardware Saturation Overflow vi sostituisce il massimo numero rappresentabile. Esempio: Dimensione dell’accumulatore = 100; senza overflow saturation 40 +20 + 50 = 115 mod 100 = 15; di fatto: errore = 100 Esempio: Dimensione dell’accumulatore = 100; con overflow saturation 40 + 20 + 50 = 115 saturated 100 = 100; di fatto, errore = 15 Si ha sempre un’approssimazione per difetto: nello scalamento, nella normalizzazione, nella gestione dell’overflow. Questo fatto comporta l’introduzione di un bias statistico: la media diventa positiva e non nulla. Esempio: Si può pensare al caso dell’offset di un amplificatore, che genera in uscita una rampa che satura a 5 volt: si ha un errore costante che si amplifica. Arrotondamento hardware • round to nearest: • convergent rounding: Arrotondamento al più vicino in hardware (selezionabile) [0 0,5) [0,5 1] si ha offset perché 0.5 Æ 1 Quando il numero che deve essere arrotondato si trova a metà fra i due estremi, si guarda il bit meno significativo: 0 Æ arrotondamento per difetto 1 Æ arrotondamento per eccesso Nei datapath floating point scompare tutta una serie di problemi, ad esempio si riducono le complicanze dovute ad overflow. 12 3.2 Architetture di memoria Tradizionalmente nei microprocessori è utilizzata un'architettura di tipo Von Neumann. Questo tipo di architettura contiene una singola memoria ed un singolo bus per il trasferimento dei dati da e verso la CPU. Lo schema di Von Neumann è abbastanza soddisfacente se bisogna eseguire le operazioni richieste in modo seriale: questo è il caso più comune nei microprocessori. Quando però si ha bisogno di incrementare la velocità dei processi, si deve far ricorso ad un altro tipo di architettura, denominata Harvard. Un'architettura di tipo Harvard dispone sia di memorie che di bus separati per dati ed istruzioni. Un'istruzione di programma ed un dato possono essere caricati simultaneamente, incrementando le prestazioni rispetto alla configurazione a singolo bus del caso Von Neumann. La maggior parte dei DSP odierni implementa questa architettura dual bus: Il nome di Super Harvard Architecture è associato ad un ulteriore miglioramento in termini di throughput del'architettura Harvard. Queste maggiori prestazioni si ottengono tipicamente aggiungendo una cache per le istruzioni nella CPU, il che virtualmente rende disponibili al core del DSP tre bus; naturalmente il termine Super Harvard si può applicare anche al caso di tre effettivi bus disponibili. Nel processore SHARC di Analog Devices le prestazione dell’architettura sono ulteriormente potenziate inserendo un controller di I/O connesso alla data memory (vedi Figura seguente). Nell’architettura Harvard l’uso di due memorie, una per i dati ed una per le istruzioni, determina un incremento dei pin del processore. Si deve infatti indirizzare uno spazio di memoria maggiore. Per risparmiare pin a bordo di un DSP può essere implementata una memoria, mentre il collegamento alla memoria esterna è demandato ad un unico bus. 13 Multiple Access Memory La struttura Harvard permette di compiere accessi multipli in memoria. Questi accessi possono essere sequenziali: in un ciclo di clock si compiono due fetch. Se il DSP-core accede simultaneamente a due banchi di memoria usando due bus indipendenti si ottengono quattro accessi in memoria per ciclo di clock. Un’altra tecnica per implementare una struttura Harvard, al fine di incrementare il numero di accessi in memoria, è quella di usare memorie multiporte. Una memoria multiporte dispone di più set di indirizzi e connessioni indipendenti, in modo da permettere un accesso parallelo in memoria. Il tipo più comune di memoria multiporte è la dual-port memory, che permette due accessi simultanei. Esempio: Interfaccia di una videocamera A/D FPGA DUAL PORT RAM DSP L’uso di una dual-port RAM consente, durante un ciclo di processo, di digitalizzare tramite FPGA i dati in ingresso dal sensore mentre si elaborano quelli acquisiti nel ciclo precedente. Si deve considerare quale tipo di memoria utilizzare se si vuole montarla sulla board insieme al DSP. • Ram dinamica: • Ram statica: Più economica Più complessa Con circuito di refresh Più costosa Più semplice e veloce Acceleratori hardware La memoria è composta da registri e da cache: le cache di programma sono memorie veloci che contengono le istruzioni più probabili. Esse vengono utilizzate per diminuire il numero di accessi in memoria. I DSP supportano a livello hardware diversi tipi di cache di programma: Repeat buffer • single instruction • multiple instruction Il fatto che le istruzioni (for, …) siano implementate in hardware nella cache di programma fa in modo che si liberi il program bus. Si ha un vantaggio architetturale: è possibile mettere dei dati nella program memory (usarla come data memory). Un limite del repeat buffer è che non ci possono essere jump, goto, chiamate a subroutine. Single-sector cache Un blocco di memoria che contiene un pezzo di programma (qualunque pezzo, non per forza un loop: ovviamente un pezzo di programma autoconsistente). 14 Multiple-sector cache A differenza della single-sector cache, questa cache può memorizzare due o più pezzi indipendenti di programma. Quando bisogna caricare nella cache un nuovo settore, l’algoritmo utilizzato per scegliere quale settore sostituire è l’LRU (least-recent-used). Esempio: N Calcolo di z = ∑ a [ i ]∗ b [ i ] i Con un assembler-like: load CONT N int a, b LOOP load *a, *b mpy r1*r2 sum z=z+r1*r2 a++, b++ CONT-if (CONT>0) GOTO LOOP Con un repeat buffer: move #a, r0 move #b, r1 move #N-1, mo Å registro interno del repeat buffer CLR a, x : (r0) +, x0 y : (r1) +, y0 Å a e b sono su due bus diversi, in un colpo solo faccio tre cose rep mac mac #length-1 x0, y0, a x : (r0) +, x0 y : (r1) +, y0 x0, y0, a Å il loop viene eseguito in hardware Å a = a+x+y Å clean-up finale, fuori dal loop Nel secondo caso, il loop viene eseguito in hardware, liberando il program bus: non devo aggiornare un contatore oppure effettuare un salto all’inizio del loop. La prima istruzione MAC viene ripetuta con la massima efficienza per length-1 volte. La seconda istruzione MAC è esterna al loop: viene eseguita una volta sola. Wait states Gli stati di attesa sono un artificio hardware con cui si ritarda l’esecuzione dei processi di un DSP, nell’attesa di accedere alla memoria. Quando la memoria è disponibile c’è un messaggio di memory acknowledgement. I wait states si possono avere in tre casi: • • • multiple access: a e b sullo stesso bus; slow memory; bus sharing: problema sul bus, che risulta occupato con altre periferiche; 15 Se lo schema architetturale è il seguente: RAM RAM DMA FPGA DSP Gli eventuali conflitti dovranno essere risolti da bus arbiter (semafori): si avranno interrupt, buffer per time sharing… Quando si attiva il canale DMA, il DSP utilizza la sua RAM, altrimenti non si ricavano benefici da questo tipo di schema architetturale. Nei DSP le cache sono ottimizzate per eseguire le istruzioni, non per fare accesso ai dati. Modi di indirizzamento • • • • • • • • • Implicito: Immediato: Diretto in memoria: Diretto a registri: Indiretto via registro Indiretto via registro: Indiretto via registro indice: Modulo addressing: Bit reversal: (non devo specificarlo) (registro = #) A = DM(1000) A=x ∗ y si legge il dato puntato dall’indirizzo contenuto nel registro con pre/post incremento/decremento base + offset buffer ciclico 00101101 Æ 10110100 usato nel calcolo della FFT L’ultimo modo di indirizzamento, bit reversal, mostra come possono essere specializzati i processori DSP. L’indirizzamento bit reversal si ha quando un insieme di valori deve essere riordinato invertendo l’ordine dei bit dell’indirizzo: • • In ogni indirizzo si inverte l’ordine dei bit I dati vengono spostati in modo che i corrispondenti nuovi indirizzi abbiano un ordine crescente Questa operazione è richiesta nel calcolo della Fast Fourier Transform: è facile vedere come i DSP siano progettati per calcolare efficientemente questa trasformata. 16 3.3 Pipeline Una istruzione normalmente non viene eseguita in un ciclo di clock, ma in un processo che viene generalmente scomposto in quattro fasi: a) b) c) d) Fetch Decode Fetch Execute dell’istruzione dell’opcode read / write sui dati ALU / MAC, parte aritmetica Queste sono quattro fasi logiche, non necessariamente sequenziali. Esempio: Se un’istruzione I1 comporta l’esecuzione di tutte le quattro fasi, l’istruzione seguente I2, secondo lo schema qui riportato, dovrà attendere quattro cicli di clock prima di andare in fetch. 1 a 2 3 4 I1 b 5 I2 I1 c I1 d I1 Il 75% delle risorse è fermo ed inutilizzato: supponendo un clock di 20 ns, si ricava un modesto throughput di un output ogni 80 ns. Invece di procedere sequenzialmente si può pensare di compiere più operazioni in modo parallelo. Le istruzioni sono eseguite concorrenzialmente, ognuna in una diversa fase della pipeline. Esempio: a b c d 1 2 3 4 5 I1 I2 I3 I4 I5 I1 I2 I3 I4 I1 I2 I3 I1 I2 Trascurando la parte in basso a sinistra (prologo), in questo esempio si ha un uso massimamente efficiente delle risorse. Considerando il clock sempre di 20 ns, si ha un throughput a regime di un’uscita ogni 20 ns. L’efficienza del sistema dipende da quanto sono lunghi prologo ed epilogo rispetto a quanto è lungo il ciclo. 17 Esempio: Interlock a 1 2 3 I1 I2 I3 I1 I2 I3 I1 I2 I2 I1 I2 b c d 4 5 6 In c5 si verifica un conflitto tra I3 ed I2, che ha bisogno di 2 cicli di clock per completare la propria fase r/w. Il problema del conflitto si risolve con l’interlocking: a 1 2 3 4 5 6 7 I1 I2 I3 I4Æ I4 I5 I6 I1 I2 I3Æ I3 I4 I5 I1 I2 I2 I3 I4 I1 I2 NOP I3 b c d L’interlocking risolve il problema, ma è difficile calcolarne l’efficienza: se I3 non avesse avuto bisogno della fase c non si sarebbe introdotto un nop (no operation code). Patologie derivanti dall’utilizzo di pipeline Pipeline Hazard Quando le stesse risorse hardware vengono richieste contemporaneamente da due diverse istruzioni, o quando un dato viene modificato da un’istruzione mentre un’altra lo richiede in lettura, si verificano dei casi di pipeline hazard: rispettivamente si parla di hazard strutturali e di hazard sui dati. Un hazard è una situazione in cui è impossibile prevedere come evolverà il processo, dato che le varie fasi appartenenti a diverse istruzioni operano concorrenzialmente. Esempio: Le istruzioni sono composte da tre fasi: a) fetch b) decode c) execute Inizialmente sia: R0 = 5678 MOV MOV #1234, R0 x: (R0), x0 (I1) (I2) 18 a 1 2 I1 I2 b I1 c 3 4 I2 I1 I2 Si verifica un caso di hazard, perché l’address generation unit indirizza ancora a 5678, invece del nuovo valore di indirizzo 1234, nel momento in cui la seconda istruzione va in decode. Un tipo di soluzione può essere quello di interporre un NOP fra le due istruzioni: MOV NOP MOV #1234, R0 (I1) x: (R0), x0 (I2) Un’altra soluzione è quella di operare un interlock: a 1 2 3 I1 I2 I2 I1 I1 b c 4 I1 In questo caso l’interlock viene comunque sempre fatto, rallentando sempre la pipeline: è però un trade-off. Branching effect Il branch è un’istruzione che comunica al processore di eseguire un salto ad un nuovo indirizzo, dal quale iniziare una nuova fase di fetch. Questo provoca un rallentamento nella pipeline, oltre a problemi di gestione delle istruzioni già “fetchate”. Esempio: Quando un’istruzione di branch raggiunge la fase di decode nella pipeline, il processore si accorge di dover saltare ad un nuovo indirizzo, ma l’istruzione successiva (qui I2) è già stata in fetch. a b c d 1 2 BR I2 3 4 5 6 N1 BR N1 BR BR NOP NOP 19 Bisogna riconoscere i salti il più presto possibile nella pipe. Se un salto è di tipo incondizionato, cioè viene comunque eseguito, questo avviene in fase di decode. Per un salto di tipo condizionato la situazione è più difficile, perché deve essere verificata una condizione dopo che l'istruzione è stata decodificata e questo richiede un tempo maggiore. Si deve poi individuare l'indirizzo di salto e caricarlo. Se l'indirizzo deve essere calcolato seguendo un qualche metodo di indirizzamento, sarà richiesto un ciclo aggiuntivo. Quando si incontra un branch la pipeline deve essere svuotata, perché le istruzioni successive che sono già passate dalla fase fetch non possono terminare il loro ciclo. In questa situazione si ha un pipe-flush. Se si vogliono sfruttare anche i cicli di clock del branch, bisogna che il programmatore inserisca delle istruzioni che possano essere eseguite negli “slot” rimasti liberi. BRD I2 I3 I4 #ADD… Con questi inserimenti è come se il branch venisse eseguito in ritardo, si parla di delayed branch. 20 3.4 Architettura VLIW ( Very Long Instruction Word ) Un DSP VLIW ha un’architettura interna di tipo parallelo caratterizzata dalla presenza di più unità funzionali indipendenti. Si può raggiungere un alto livello di performance utilizzando l’instruction level parallelism ed il data level parallelism. L’instruction level parallelism permette di processare più operazioni in un singolo ciclo di clock. Con il data level parallelism una singola unità di esecuzione è separata in porzioni di dati più piccole. Il parallelismo contribuisce ad avere un throughput massimo. Esempio: Architettura VLIW con unità funzionali (process units) indipendenti 32 bit opcode 1 opcode 2 P.U.1 P.U.2 opcode N P.U.N Process Units Registri, cache, RAM Effetti dell’architettura Vliw sulle prestazioni: Instruction Level Parallelism L’esecuzione dei programmi può essere velocizzata se le operazioni di tipo RISC, come load, store, moltiplicazioni ed addizioni vengono eseguite in parallelo su unità funzionali differenti. Ogni istruzione contiene un operation code per ogni unità funzionale, ed ogni unità riceve il proprio code simultaneamente Esempio: Calcolo di y = a1 x1 + a 2 x 2 + a3 x3 RISC 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. VLIW fetch fetch fetch fetch mpy mpy fetch fetch add mpy add a1 x1 a2 x2 a1x1 = z1 a2x2 = z2 a3 x3 y = z1 + z2 z3 = a3x3 y = y + z3 1. 2. 3. 4. 5. fetch a1 fetch x1 fetch a2 fetch x2 mpy a1x1 fetch a3 fetch x3 mpy a2x2 add z1, z2 mpy a3x3 add z3, y Lo speed-up è 11/5 > 2 : con la VLIW si impiega meno della metà dei cicli di clock del caso RISC. 21 Data Level Parallelism La velocità d’esecuzione dei programmi può essere incrementata anche partizionando le operazioni: una singola unità aritmetica viene scomposta per poi eseguire la stessa operazione su parti più piccole di dato. Esempio: Partitioned Add Due array da 64 bit devono essere sommati. Ogni unità da 64 bit viene scomposta in otto piccole unità di 8 bit, per poter eseguire otto operazioni in parallelo. Questo è un caso di partitioned-add, dove si ha la stessa istruzione , un’addizione, su tanti byte diversi. D7 D0 B7 B0 D7+B7 Esempio: D6+B6 Partitioned Add (2) Si prenda l’operazione da svolgere: In linguaggio C: char int for D0+B0 r r r r r r c = a + b , con a , b , c ∈ IR128 . a[128], b[128], c[128]; i; (i=0; i<128; i++) c[i]=a[i]+b[i] Si hanno 3 × 128 cicli di clock. Lo stesso codice può essere eseguito facendo uso di partitioned_add long int for a[16], b[16], c[16]; // long da 64 bit i; (i=0; i<16; i++) c[i]=partitioned_add (a[i], b[i]) In questo caso i cicli di clock sono 3 × 16. In questo esempio la performance è stata incrementata di un fattore 8, grazie al data level parallelism. Siccome il numero di iterazioni del loop decresce anch’esso di un fattore 8, si ha un ulteriore aumento della performance. Il processore può supportare il Data Level Parallelism se dispone di un’architettura adatta. Per poter sfruttare questo parallelismo si deve utilizzare un apposito set di istruzioni. Il prezzo da pagare nell’eseguire queste istruzioni è il tempo di latenza (latency), che non è uguale a 1. 22 Set di istruzioni • • SIMD Simple Instruction Multiple Data Gruppi di istruzioni a) Partitioned (aritmetico/logiche) b) Σ instructions (inner-product, SAM-Sum Absolute Module, SAD-Sum Absolute Difference) c) partitioned_select (min/max, conditional select) d) formatting (shuffle) e) multimedia specific Esempio: Motion Compensation nel DSP −1 min r ∑ p i − pi ( x ) x i All’interno del modulo c’è un’operazione di SAD. 23 4. La programmazione dei DSP La programmazione dei DSP coincide con il mapping di un dispositivo. Requisiti • Conoscenza approfondita dell’algoritmo • Conoscenza dell’architettura del DSP (A questo punto si può supporre che si sia già scelta la famiglia di DSP adatta) • Conoscenza del set di istruzioni del DSP Strumenti tecnologici a disposizione 1. Un ottimale set di istruzioni (Che consenta l’implementazione dell’Instruction Level Parallelism e del Data Level Parallelism) 2. Pipelining 3. Loop unrolling 4. Evitare istruzioni del tipo if, then, else… 5. Scegliere fra rappresentazione ad interi e floating point 6. Uso della DMA (Direct Access Memory) Analizziamo voce per voce: 1. Ottimale set di istruzioni Esempio: char for Look-Up Table x[128], y[128]; (i=0; i<128; i++) y[i]=LUT (x[i]) Supponiamo di avere 3 cicli di clock per ogni campione (3 clock/sample). Vogliamo utilizzare il parallelismo fornito dal DSP (Il DSP a cui si fa riferimento è il MAP1000): load 32 v0 v1 v2 v3 expand 8 v0 16 v1 16 expand 16 v0 32 v1 32 v2 16 v3 16 expand 16 v2 32 v3 32 24 v0 32 v1 32 load 16 v2 32 load 16 lut 32 0 load 16 lut 32 1 load 16 lut 32 2 compress 32 lut 16 0 v3 32 lut 32 3 compress 32 lut 16 1 lut 16 2 lut 16 3 compress 16 lut8 lut8 lut8 lut8 store 32 Si hanno 6 accessi in RAM esterna e 6 accessi ai registri interni. Tutto avviene in 6 cicli di clock: 6 clock / 4 sample = 1.5 clock / sample 2. Pipelining: vedi pag.16 3. Loop unrolling Il loop unrolling sfrutta la pipe per accorciare il tempo di esecuzione del programma. Esempio: for (i=0; i<N; i+=2) y[i] = x[i] × k; Non è possibile effettuare l’assegnamento prima di eseguire la moltiplicazione. Ottimizziamo: for (i=0; i<N; i+=2){ y[i] = x[i] × k; y[i+1] = x[i+1] × k; } Se la pipe fosse a tre livelli, nel ciclo for bisogna aggiungere un’istruzione y[i+2], e così via. 4. Evitare istruzioni del tipo if, then, else… Esempio: for (i-0; i<N; i++) if (x[i]>y[i]) s = s+x[i]; else s = s+y[i]; Supponiamo di programmare in C, altrimenti programmando in Assembler il compilatore deve avere delle librerie intrinsic. 25 Ottimizziamo: Load 64 (x) 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit 8 bit + + + + + + + Load 64 (y) 8 bit Compare (x,y) + Registro Select (Registro, x, y) Max (x,y) S Sum (S, select) Si ha parallelismo massimo uguale a 8, dovuto alla VLIW (8 char alla volta). Un altro parallelismo, maggiore di questo, è dovuto al Data Level Parallelism. 5. Scegliere fra interi e floating point: vedi pag.9 6. Uso della DMA: Double-buffering PERIPHERAL DSP I/O DMA MEMORY Ho bisogno di un’architettura DMA e di una memoria dual port, o di due banchi di memoria indipendenti. A livello software devo implementare il ping-pong del buffer per sincronizzarlo con l’esterno. 26 Algoritmi: Calcolo della FFT La Butterfly (farfalla) è l’elemento base del diagramma di flusso che descrive il calcolo di una FFT. Essa prende in ingresso due numeri complessi e li converte in altri due numeri complessi in questo modo: Diagramma corrispondente della butterfly FFT: L: A: M: S: load add/subtract multiply store : negate L1 Ra A1 S1 A2 Ia L2 Rb A3 M1 A5 S2 Ib A4 L3 M2 A6 M3 M4 Per eseguire con un calcolatore sequenziale 6 addizioni ( 3N log 2 N ), 4 moltiplicazioni ( 2 N log 2 N ), 6 load, 4 store, occorrono molti cicli di clock. Invece in un DSP A1 e A2 sono parallelizzabili, così come A5 e A6. Inoltre le operazioni di load si riducono a 3, mentre le istruzioni store diventano 2, grazie alla lunghezza della instruction word (es.16bit). 27 Algoritmi: Calcolo della DCT (blocchetti 8 × 8) (2 j + 1)π u f ⋅ cos (2 j + 1)π r c (r ) 7 c(u ) cos ∑ ij 16 16 r =0 2 n =0 2 7 ω ij = ∑ ω ij i, j = 0,...,7 valore nello spazio trasformato c (r ), c (u ) 2 2 1 r, u = 0 else Per implementare questa DCT è necessario eseguire 16 somme, 26 moltiplicazioni, 16 load, 8 write. La versione ottimizzata sul C80 della Texas Instruments costa 104 cicli di clock: è un buon risultato, visto che solo per leggere i dati in ingresso si spendono 64 cicli di clock. Algoritmi: Filtro FIR Un filtro FIR è un’altra implementazione tipica dei DSP, come si è visto finore, dato che il calcolo richiesto in un filtro FIR consiste banalmente in prodotti scalari. Algoritmi: Calcolo dell’inversa della radice quadrata mediante Newton-Raphson L’uso di librerie matematiche agevola ilcompito del programmatore ma talvolta può rendere estremamente inefficiente il codice. Questo di solito accade quando la funzione che si vuole calcolare non è direttamente rappresentata in termini di semlici potenze delle grandeze di ingresso. Un esempio tipico è la funzione y(x ) = 1 x Questo calcolo è in effetti assai frequente in applicazioni di signal processing, perché per esempio compare nelle FFT inverse ed in molte operazioni di normalizzazione. In prima istanza, uno potrebbe implementare la y(x) in linguaggio C con le seguenti istruzioni: #include <math.h> . . double y, x; . . y=1./sqrt(x) ; Tuttavia un’analisi computazionale del codice di cui sopra mostra che esso richiede una chiamata a funzione di libreria matematica (il cui costo può essere ignoto a priori, salvo approfondite ricerche nella documentazione, con la conclusione che risulta molto elevato), ed una divisione, operazione di solito invisa ai progettisti hardware perché onerosa e fonte di errori. 28 Esiste in effetti un metodo iterativo per calcolare la y(x) con solo somme e prodotti (e quindi, estremamente DSP-friendly). L’algoritmo definisce una funzione costo di approssimazione: 1 g(y) = x − 2 y Se si esclude il caso banale x=0 y=0 facilmente verificabile ed evitabile a priori, lo zero della funzione g(y) (ovvero il valore di y per cui g si annulla) è la soluzione al problema in esame. Si applica a tal fine il metodo iterativo di Newton-Raphson (NR), che ad ogni iterazione scende verso lo zero secondo la derivata prima della funzione stessa. Si ha che: dg 2 = dy y 3 Per applicare NR, si inizia in un punto di tentativo y0; ad ogni iterazione yn, si intercetta l’asse y con la retta tracciata dal gradiente in yn, il nuovo punto yn+1 così trovato diventa il punto di partenza della prossima iterazione. 0 − g ( yn ) 2 = g ′( y n ) = 3 y n+1 − y n yn risolvendo per yn+1 si ottiene: y n+1 = ( 1 y n 3 − y n2 x 2 ) che come richiesto contiene solo somme e moltiplicazioni. A meno di casi patologici, se il punto iniziale y0 non è troppo distante dalla soluzione l’algoritmo converge in meno di una decina di passi. Algoritmi: Calcolo dell’inversa della radice quadrata medinate Look-Up Tables Un altro sistema per calcolare 1/√x prevede di scomporre l’intervallo di interesse (nel nostro caso, per semplicità si considera il range [0,1]) e calcolare la funzione non lineare nei punti di confine fra le diverse regioni. I valori intermedi potranno essere calcolati come interpolazione lineare lungo la retta che connette tali estremi. A tal finesarà sufficiente il valore dell’intercetta della retta sull’asse x e la pendenza (coefficiente angolare) della retta stessa. Pertanto per ogni intervallo dovremo momorizzare due valori. Nel caso particolare della funzione x-½ , il trucco consiste nel dividere il range [0,1] in intervalli non uniformi ma ripartiti secondo una scala logaritmica, ovvero dicotomica. La figura seguente illustra la strategia di scomposizione. 29 f(x) 0 1/16 1/8 1/4 1/2 1 x Per implementare la funzione non lineare si utilizza quindi una LUT (look-up table), che memorizza i dati relativi agli intervalli spaziati logaritmicamente. Come anticipato sopra, per ogni intervallino si prendono pendenza e intercetta delle rette y = mx + n Nela scomposizione di cui sopra in quattro intervalli, otteniamo dunque questa tabella: Intervallo 1 1 ÷ 3 4 2 2 1 1 ÷ 8 4 1 1 ÷ 4 2 1 ÷1 2 m 4( 2 − 1) n (2 − 2 ) / 4 2( 2 − 2 ) ( 2 − 1) / 2 2( 2 − 1) (2 − 2 ) / 2 (2 − 2 ) ( 2 − 1) Il notevole vantaggio di questa tecnica è il fatto che la tabella memorizza di fatto solo due valori: • (2 − 2 ) • ( 2 − 1) oportunamente moltiplicati o divisi. Ma tali moltiplicazioni o divisioni riguardano solamente potenze di 2, e sono quindi facilmente implementabili da banali ed operazioni aritmetiche. La LUT diventa quattro volte più piccola ed è virtualmente indipendente dalla precisione nella rappresentazione dei valori contenuti. 30 Algoritmi: Calcolo dell’inversa Con lo stesso procedimento mostrato sopra si può anche calcolare l’inversa y(x) = 1/x di un numero con solo somme e prodotti. La funzione costo da definire e la sua derivata sono: g(y) = x − g ′( y ) = 1 ; y 1 ; y2 Applicando Newton-Raphson come visto in precedenza la formula iterativa di somme/prodotti diventa: y n+1 = 2 y n (1 − y n x ) . Questo metodo consente dunque di calcolare un rapporto fra due numeri attraverso solo moltiplicazioni e somme iterate: a 1 = a⋅ b b Vva detto tuttavia che le considerazioni fatte a suo tempo a proposito dell’intervallo di convergenza sono in questo caso più stringenti. In altre parole è assai più critica, in questo caso, la scelta del punto iniziale da cui far partire le iterazioni di Newton-Raphson. Tecniche di programmazione dei DSP: C versus Assembler In un DSP tutte le istruzioni possono essere condizionabili, quando il problema si complica è necessaria una particolare cura nella programmazione. Se si lavora in assembler bisogna che il programmatore conosca molto approfonditamente l’architettura sulla quale il suo algoritmo dovrà essere implementato. Lavorando invece in C++ si può sperare, con buoni motivi, nella efficienza del compilatore: il C++ disaccoppia la persona che si preoccupa di sviluppare l’algoritmo da quella che deve pensare all’architettura del DSP. Mostriamo come lo stesso problema può essere risolto nei diversi linguaggi e a diverso livello. Esempio: Prodotto scalare (Dot product) s = ∑ xi y i i 1) Programma in C per DSP: #define L 20 float dm x[L]; float pm y[L]; float s; main( ) { int n ; for ( n=d; n<L; n++) s += x[n] ∗ y[n]; } 31 2) Traduzione in assembler del programma 1 per il DSP SHARC (Analog Devices): il2 = _y i4 = _x lcntr = 20 do (pc, 4) until lce f2 = dm (i4, m6) f4 = pm (il2, ml4) f8 = f2 ∗ f4 fl2 = fl2 + f8 Legenda: lcntr: lce: f2,f4,…: 20 do ( ): (pc, 4): repeat buffer; l counter entità; registri interni; ripeti 20 volte; sono 4 istruzioni; Il costo del programma è di 20 ∗ 4 = 80 cicli di clock. 3) Traduzione ottimizzata in assembler dello stesso programma: il2 = _y i4 = _x f2 = dm (i4), f4 = pm (il2) f8 = f2 ∗ f4, f2 = dm (i4) lcntr = 18 do (pc, 1) fl2 = fl2 + f8, f8 = f2 ∗ f4, f2 = dm (i4), f4 = pm(il2) fl2 = fl2 + f8, f8 = f2 ∗ f4 fl2 = fl2 + f8 1 1 18 1 1 Il costo del programma ottimizzato è di 1+1+18+1+1 = 22 cicli di clock. I DSP, come altre applicazioni scientifiche ed ingegneristiche, sono programmati in linguaggio assembler oppure in C/C++. I programmi scritti in assembler possono essere eseguiti più velocemente, mentre i programmi in C sono più facili da sviluppare. Criteri di scelta progettuale fra linguaggio C e Assembler 1) Quanto è complicato il programma? Se il programma è articolato e complesso, bisognerà probabilmente usare il C. Se invece il programma è piccolo e non presenta particolari complessità, la scelta migliore sarà l’assembler. 2) Serve massimizzare la velocità del DSP? Se la risposta è sì, la migliore performance si potrà ottenere solo facendo uso dell’assembler. Quando la velocità non è determinante, si può considerare l’uso del linguaggio C. 3) Quanti programmatori lavorano al progetto? Se il progetto deve essere condiviso da più di due programmatori, probabilmente la scelta si orienterà verso il C. 4) Incide di più il costo del prodotto oppure il costo di sviluppo? Se pesa maggiormente il costo del prodotto si sceglierà l’assembler. Si opterà invece per il C se il costo di sviluppo si rivela critico. 32 5) Esperienza del programmatore software. Se il programmatore software è molto esperto in assembler, lo sceglierà per il suo lavoro con i DSP. 6) Consigli della casa produttrice. Questo punto è molto importante. Infatti le indicazioni della casa produttrice possono già da sole determinare la nostra scelta. Un buon compromesso è quello di costruire l’architettura software in C, mentre nelle situazioni critiche utilizzare l’assembler. Esempio: C versus Assembler 1) Chi programma i microprocessori... Nel 90% dei casi utilizza il C, nel rimanente10% si serve dell’assembler. 2) Chi programma i DSP... Nel 55% dei casi utilizza il C, mentre nel 45% lavora con l’assembler 3) Nelle applicazioni che generano un guadagno netto molto alto... Solo il 30% si serve del C, mentre ben il 70% dei programmatori lavora con il linguaggio assembler. 33 5. Misura delle prestazioni di un DSP Quando si tratta di misurare le prestazioni di un microprocessore, spesso si citano termini come MIPS, MFLOPS, MMACS. Dal punto di vista dell’utilizzatore bisogna tenere in considerazione il contesto delle applicazioni che vengono utilizzate e per le quali il DSP è stato realizzato. MIPS: Milioni di istruzioni al secondo Forse fra tutti gli indici è il meno utile: viene misurato contando il numero di istruzioni eseguite da un certo insieme di programmi. Il risultato viene poi diviso per il tempo di esecuzione. Sfortunatamente il valore che viene riportato sui vari data sheets si riferisce ad un MIPS di picco. MFLOPS: Milioni di floating point operations al secondo Il numero di operazioni floating point che un DSP può eseguire al secondo fornisce un’indicazione sulla potenza di elaborazione del dispositivo. Questa è un’informazione interessante: il problema sta nel modo di calcolare questo valore. Infatti un’operazione MAC esegue tre operazioni diverse in un solo ciclo di clock: quando viene considerata tre volte invece di una sola, le prestazioni risultano migliori, ma è solo un’apparenza. MMACS: Milioni di operazioni MAC al secondo Questo valore è abbastanza utile, anche se non fornisce indicazioni sulle applicazioni associate al DSP. Però si trova raramente sui data sheets. Application Cube Dimensione codice MIPS Power (Potenza dissipata) Un altro modo di valutare le performance di un DSP è costruire un application cube come quello mostrato qui sopra. Nell’esempio vengono posti a confronto diversi parametri da ottimizzare, come MIPS, dimensione del codice e potenza dissipata. L’aspetto più utile di questo tipo di rappresentazione è quello di rendere visiva la collocazione di un DSP nello spazio tridimensionale determinato dalle misure dei parametri scelti. Benchmarking La strategia migliore da adottare quando si utilizzano i benchmark è quella di testare i DSP eseguendo le applicazioni per le quali è stato progettato. Le indicazioni che si possono trarre da queste analisi, per quanto accurate, non forniscono comunque informazioni su quelle che saranno le prestazioni in caso di processo di segnali in tempo reale, quando il flusso di dati fra DSP e componenti esterni diventerà un problema. 34 Esempio: Funzione Complex FFT a 1024 campioni FIR (per TAP): delay + mpy + add IIR (per biquad) Divide (x/y) Inverse square root ( 1 x ) Tempi Cicli di clock 0.46 ms 25 ns 100 ns 150 ns 225 ns 18.221 1 4 6 9 In generale con i benchmark non si possono confrontare adeguatamente due DSP, ma si può operare una scelta fra diverse famiglie di DSP. Naturalmente bisogna innanzitutto considerare quali sono i specifici ambiti di utilizzo indicati dal produttore per ciascun DSP o famiglia di DSP. Esempio: Benchmark di un DSP SHARC, di Analog Devices Il throughput di un particolare algoritmo di un DSP può essere ricavato dividendo la frequenza di clock, in questo esempio 40 MHz, per il numero richiesto di cicli di clock per campione. I DSP appartenenti alla famiglia SHARC possono eseguire un’operazione MAC in un singolo ciclo di clock. Siccome molti filtri FIR utilizzano fra 25 e 400 coefficienti, sono necessari da 25 a 400 cicli di clock perché ogni campione sia processato. Per ottenere il throughput del filtro dividiamo la frequenza di clock, 40 MHz, per questi valori: otteniamo una data rate massima compresa fra 100K e 1.6M sample/secondo. In caso di fitri IIR, i coefficienti sono da 5 a 17. Siccome questi loop sono relativamente brevi, dobbiamo sommare un piccolo overhead, circa tre cicli per campione. I cicli di clock necessari diventano compresi fra 8 e 20, sempre perché sia processato un singolo campione. Il throughput massimo corrispondente varia fra 1.8M e 3.1M sample/secondo. Il calcolo di una FFT a 1024 campioni richiede in questo DSP 18221 cicli di clock, circa 0.46 ms a 40 MHZ. Per calcolare il throghput è comodo considerare questo dato in termini di 17.8 cicli di clock per campione. Una FFT a 256 campioni richiede 14.2 cicli di clock per campione, mentre una FFT a 4096 campioni ne richiede 21.4. In generale possiamo considerare un range che varia fra 10 e 22 cicli di clock per campione. Il corrispondente throughput risulta essere fra 1.8M e 3.3M sample/secondo. La convoluzione della FFT è un modo veloce per calcolare i filtri FIR. In un caso tipico essa richiede 60 cicli di clock per essere eseguita, determinando un throughput dei dati di circa 660k sample/secondo. La convoluzione della FFT in 2 dimensioni, richiesta nell’elaborazione delle immagini, in un caso tipico è associata ad un throughput di 260k sample/secondo. 35 6. Un’introduzione ai DSP TMS320C6000 In questo capitolo introduciamo alcune caratteristiche dei processori appartenenti alla famiglia di DSP TMS320C6000, ed in particolare del C62 (fixed point) e del C67 (floating point). Questi DSP della Texas Instruments sono attualmente fra i più veloci in commercio: con 8 istruzioni da 32 bit per ciclo raggiungono i 4800 MIPS di picco. I clock variano fra 150 e 250Mhz. Presentano un’architettura chiamata VelociTi Advanced Very Long Instruction Word, o Advanced VLIW, composta di otto unità funzionali indipendenti: • • • 4 ALU in virgola fissa e mobile 2 ALU in virgola fissa 2 Moltiplicatori in virgola fissa e mobile Il DSP core è costituito da 32 registri general purpose di 32 bit , mentre la compattazione delle istruzioni permette di ridurre la dimensione del codice. Sono supportati i dati ad 8, 16, 32 bit, mentre le moltiplicazioni ad interi 32bit × 32bit possono restituire il risultato a 32 bit oppure a 64 bit. L’hardware support è in grado di elaborare operazioni floating point in singola (32 bit) oppure doppia precisione (64 bit) Altre caratteristiche sono la presenza di 1M bit di SRAM on-chip, 512 Kb di cache interna per il codice (16K per 32 bit per istruzione), 512 Kb di dual access memory interna per i dati. L’interfaccia con la memoria esterna è a 32 bit: la memoria è indirizzabile a 32 bit, circa 4 Giga. Nel caso del ‘6201 e del ‘6701 la memoria on-chip consiste di blocchi di 64 Kb configurabili dal programmatore come cache oppure come spazio mappato in memoria. 36 Il fetch delle istruzioni prevede la generazione fino ad 8 istruzioni a 32 bit: grazie all’architettura VLIW il fetch avviene realizzato a 256 bit, grandezza del bus della program memory interna al DSP. Il pacchetto di fetch ha dimensione fissa, a differenza del pacchetto di esecuzione che può avere dimensione variabile. Il bit meno significativo di ogni istruzione viene utilizzato per indicare se la prossima istruzione da eseguire fa parte o meno del pacchetto di esecuzione corrente, o se invece deve essere eseguita nel ciclo di clock successivo. Se il pacchetto di esecuzione supera il confine di fetch, il pacchetto di fetch successivi è riempito di NOP (interlock). Architettura del DSP core Le unità funzionali del DSP core sono suddivise in due datapath, ognuno dei quali contiene quattro unità ed un register file. Il primo datapath contiene le unità .L1, .S1, .M1 e .D1, mentre il secondo contiene le unità .D2, .M2, .S2, .L2. I due register file contengono ciascuno sedici registri general purpose a 32 bit. Le quattro unità funzionali di ogni datapath possono essere suddivise a scelta del programmatore fra i corrispondenti sedici registri. Inoltre ogni datapath dispone di un bus dati attraverso il quale può connettersi con i registri dell’altro datapath, dai quali può ad esempio leggere un operando. I 32 registri general purpose sono a 32 bit, ma possono supportare dati fino a 40 bit. 37 Indice 1. Introduzione: caratteristiche descrittive dei DSP 1.1 Che cosa fa un DSP: caratteristiche operative 2 3 2. Rappresentazione Numerica 6 3. Caratteristiche Hardware 10 3.1 Architettura classica di un DSP 10 3.2 Architetture di memoria 12 3.3 Pipeline 16 3.4 Architettura VLIW ( Very Long Instruction Word ) 20 4. La programmazione dei DSP 23 5. Misura delle prestazioni di un DSP 32 6. Un’introduzione ai DSP TMS320C6000 34 38