Lezione 11 Lezione 11 Sommario Materiale di riferimento • Sistemi di sviluppo (assembler, linker, debugger) • Librerie di funzioni e applicazioni • Simulatori software • In Circuit Emulators (ICE) • Programmazione delle memorie EPROM • Scelta del linguaggio di programmazione: alcune considerazioni. 1. A. Clements, "The principles of computer hardware", Oxford, 2000, cap. 7, pagg. 369397. Simone Buso - Microcontrollori e DSP - Lezione 11 2. P. Lapsley, J. Bier, A. Shoham, E.A. Lee, "DSP Processor Fundamentals - Architectures and Features", IEEE Press, New York, 1997, capp. 16, 17. 3. J. B. Peatman, "Design with Microcontrollers", McGraw - Hill, 1988, cap. 8, pp. 424-472. 1 Simone Buso - Microcontrollori e DSP - Lezione 11 Sistemi di sviluppo Sistemi di sviluppo Lo sfruttamento ottimale delle risorse messe a disposizione dai moderni mC e DSP richiede l’uso di adeguati sistemi di sviluppo. Un sistema di sviluppo è un insieme di strumenti software e hardware che rende possibile la prima realizzazione e il debugging di un programma per mC o DSP. I sistemi di sviluppo sono spesso complessi, talvolta costosi e di qualità variabile. La scelta di un certo mC o DSP per la realizzazione di un prodotto, non può prescindere dalla valutazione del suo sistema di sviluppo. Tradizionalmente, lo sviluppo di codice per mC e DSP (in particolare a virgola fissa) è stato sempre compiuto nel linguaggio assembly del processore, per massimizzarne il grado di ottimizzazione (i.e. minimizzare il numero di linee di codice scritte). Simone Buso - Microcontrollori e DSP - Lezione 11 Questa è una attività piuttosto laboriosa e molto dispendiosa in termini di tempo, il che implica elevati costi di sviluppo. La disponibilità di buoni strumenti di appoggio può quindi fare grande differenza in termini di produttività, abbreviando i tempi di sviluppo. 3 Simone Buso - Microcontrollori e DSP - Lezione 11 Sistemi di sviluppo Sistemi di sviluppo Un sistema di sviluppo tipico si compone di alcuni elementi fondamentali: 1. assemblatore; 2. linker; 3. librerie di sub-routine (non sempre); 4. monitor/debugger; 5. simulatore (non sempre); 6. emulatori di tipo In Circuit (non sempre); 7. scheda di sviluppo o di valutazione. Tutti questi sono di norma specifici per il processore considerato ( ⇒ costo). Il sistema di sviluppo per un certo processore è di solito messo a disposizione dallo stesso produttore del chip. Tuttavia esistono aziende specializzate nella realizzazione di sistemi di sviluppo (dette “terze parti”), che offrono i propri prodotti per numerosi processori di diversa provenienza. Simone Buso - Microcontrollori e DSP - Lezione 11 2 4 Un esempio di produttore che propone ottimi sistemi di sviluppo proprietari è TI, seguita da AD, Microchip, Renesas …. Altri, per esempio Philips, si affidano esclusivamente a terze parti per i sistemi di sviluppo (es. LP2129). 5 Simone Buso - Microcontrollori e DSP - Lezione 11 6 1 Sistemi di sviluppo Assemblatori Il software del sistema di sviluppo è di solito concepito per operare su un comune PC e non richiede risorse particolari. Tutti i sistemi di sviluppo più evoluti, dotati di un ambiente grafico di interfaccia, presuppongono la disponibilità di un sistema operativo tristemente noto. Per gli utenti di Linux, sono raramente disponibili ambienti di sviluppo grafici completi, ma solo i programmi principali, che devono essere gestiti dall’utente (per ora, 2004). L’assemblatore è un programma che esegue la traduzione del codice dal linguaggio assembly al linguaggio macchina propri del processore di interesse. Il codice binario deve poi di norma essere collegato ad altro codice oggetto (linker) e opportunamente “rilocato” in modo da poter essere eseguito dal processore. Spesso l’assemblatore consente di definire delle macro, ovvero dei blocchi di codice che saranno espansi solo nella compilazione del programma finale (non sono subroutine!): in questo caso si parla di macro-assemblatore. Simone Buso - Microcontrollori e DSP - Lezione 11 7 Simone Buso - Microcontrollori e DSP - Lezione 11 Assemblatori Linker Ulteriore caratteristica di molti assemblatori è la disponibilità di funzioni di controllo che permettono di realizzare l’assemblaggio in modo condizionato. Il linker è un programma che si occupa di collegare diversi codici oggetto prodotti dall’assemblatore, nonché eventuali librerie di funzioni, in un unico codice eseguibile. Valutando alcune meta-variabili, il programma assemblatore è in grado di decidere se assemblare o meno alcune parti di codice. Questo può essere molto utile per sviluppare piccole varianti di un codice complesso, senza dover creare molte copie simili dello stesso programma. Tipico è il suo uso nei programmi per il controllo di apparati in catena chiusa. Simone Buso - Microcontrollori e DSP - Lezione 11 Per fare ciò il linker provvede anche a rilocare il codice, assegnando le posizioni di memoria di pertinenza per ciascun elemento del codice sorgente. Tutto ciò può anche essere fatto a mano dal programmatore, ma in realtà ogni sistema di sviluppo di un certo pregio prevede un linker. 9 Simone Buso - Microcontrollori e DSP - Lezione 11 Linker Linker Il linker opera la rilocazione dei componenti del codice oggetto sulla base di una mappa della memoria che deve essere fornita dall’utente. Il sistema di sviluppo di solito include alcuni file detti “di architettura” standard, dove viene data una mappa di memoria per uso generico, usata dal linker come default. In caso di esigenze particolari, il programmatore può modificare la mappa, secondo modalità che possono essere più o meno intuitive, a seconda del processore considerato. Compito del linker è anche quello di produrre la cosidetta tabella dei simboli, che associa nomi simbolici alle locazioni di memoria citate nel programma (i.e. alle variabili del programma). Simone Buso - Microcontrollori e DSP - Lezione 11 8 10 Questo permette, in fase di debugging, di trovare nel codice disassemblato i nomi simbolici delle variabili e non i loro indirizzi di memoria, migliorandone molto la leggibilità. Infine, il linker permette spesso all’utente la creazione e gestione di librerie di funzioni. 11 Simone Buso - Microcontrollori e DSP - Lezione 11 12 2 Librerie di funzioni Librerie di funzioni Non è raro che, insieme al software che costituisce il sistema di sviluppo vero e proprio, siano fornite anche raccolte di funzioni di uso comune, già ottimizzate e testate per il processore di interesse. Queste costituiscono una risorsa in grado di abbreviare di molto i tempi di sviluppo di una nuova applicazione, anche se, talora, la loro affidabilità non è completa (⇒ le funzioni vanno sempre provate!). E’ importante sapere che alcuni produttori forniscono solo librerie di codice oggetto. Le librerie possono essere di tipo funzionale o applicativo. Le prime consistono in semplici segmenti di codice che realizzano funzioni elementari (e.g. prodotto di matrici, regolatore PI con anti wind-up, etc.). Simone Buso - Microcontrollori e DSP - Lezione 11 Le librerie applicative sono invece raccolte di applicazioni complete (e.g. modulazione vettoriale, gestione di un modem, etc.). Queste ultime sono più spesso vendute da terze parti, ma anche certi produttori di chip ne rendono disponibili alcune (gratis). 13 Simone Buso - Microcontrollori e DSP - Lezione 11 Debugger Debugger Il debugger è un programma che permette all’utente di verificare il suo codice, una volta che questo è stato trasferito sul processore di interesse. I principali tipi di debugger sono: • a linea di comando; • a finestre di soli caratteri; • a finestre grafiche (tipo Windows). Il terzo è sicuramente il tipo oggi più comune, mentre i primi due sono piuttosto “antichi”. Il primo tipo è il più semplice da usare, ma è anche poco adatto ad analizzare programmi complessi. Spesso il debugger è parte componente di un programma più complesso (simulatore o emulatore del processore), ma può comunque esistere anche come programma separato. Ci sono debugger di complessità e potenza molto varie. Trattandosi dello strumento più importante a disposizione del programmatore, deve essere valutato attentamente. Simone Buso - Microcontrollori e DSP - Lezione 11 Il secondo è un’evoluzione del primo: consente solo di visualizzare più informazioni insieme. 15 Simone Buso - Microcontrollori e DSP - Lezione 11 Debugger Simulatore Oltre che per la veste grafica, i debugger si diversificano soprattutto per le funzioni offerte all’utente, le più comuni delle quali sono le seguenti: • debugging simbolico; • debugging a livello sorgente (source level); • modalità di visualizzazione dei dati; • possibilità di tracciare grafici di dati; • osservazione delle variabili (watch); • disassemblatore; • capacità di eseguire script o macro. Il simulatore è un programma che riproduce, su un diverso processore (e.g. su un PC), il funzionamento di un mC o DSP, con una certa accuratezza, fino al livello delle istruzioni. Simone Buso - Microcontrollori e DSP - Lezione 11 14 16 Il simulatore consente quindi di sviluppare il codice oggetto per una applicazione e controllarne il funzionamento su una riproduzione software del dispositivo finale. Tale riproduzione comprende di solito i registri interni, la memoria, le periferiche del mC o DSP reale. Spesso il simulatore è disponibile prima del chip vero e proprio. 17 Simone Buso - Microcontrollori e DSP - Lezione 11 18 3 Simulatore Simulatore L’accuratezza di un simulatore si riferisce ai due aspetti seguenti. Accuratezza funzionale. Il simulatore agevola in modo sostanziale lo sviluppo di una nuova applicazione: la sua disponibilità tra gli strumenti di sviluppo non è quindi un aspetto trascurabile. Riguarda la verosimiglianza dei risultati ottenuti elaborando un certo insieme di dati nel simulatore rispetto al dispositivo reale: alle volte lo stesso programma produce risultati diversi da quelli ottenuti in simulazione quando viene effettivamente portato sul processore (⇒ necessità di un emulatore). I principali limiti di un simulatore possono risiedere nella velocità, nell’accuratezza, nella completezza e nel livello di integrazione con il debugger. Ovviamente, la velocità di un simulatore è molto minore di quella del dispositivo reale (di almeno 3 ordini di grandezza). Tuttavia esistono simulatori più o meno veloci. Simone Buso - Microcontrollori e DSP - Lezione 11 Accuratezza nella temporizzazione. Riguarda la capacità di riprodurre la tempistica reale di un processore tenendo conto, ad esempio, del funzionamento della pipeline. 19 Simone Buso - Microcontrollori e DSP - Lezione 11 Simulatore Simulatore La completezza di un simulatore si riferisce alla sua capacità di riprodurre non solo il core del processore, ma anche le sue periferiche. Esistono simulatori che riproducono solo il funzionamento della CPU e non tengono conto delle periferiche, o ne danno una rappresentazione estremamente semplificata. Questi simulatori sono sostanzialmente inutili, in quanto non consentono di verificare il funzionamento di una applicazione completa. L’integrazione tra simulatore e debugger permette di esaminare il codice simulato come se fosse caricato sul processore reale. Il simulatore deve quindi permettere al debugger ad esempio di inserire breakpoints nel codice, di operare in modalità single step, di registrare i tempi di permanenza (profiling) del processore in certe regioni del programma, di contare il numero di cicli di clock compresi tra due punti del programma. Le ultime due opzioni sono molto utili quando si sviluppi codice per DSP. Altri offrono invece una riproduzione fedele della CPU e anche delle sue periferiche. Simone Buso - Microcontrollori e DSP - Lezione 11 21 Simulatore Simone Buso - Microcontrollori e DSP - Lezione 11 20 22 Esempio di sistema di sviluppo La più recente evoluzione della simulazione nel settore dei DSP riguarda la co-simulazione hardware/software. Questa permette di integrare in un unico flusso di simulazione sia la parte hardware che il codice di interesse in modo da garantire la massima accuratezza. L’avvento dei core DSP venduti su licenza ha spinto gli utilizzatori a cercare di minimizzare la probabilità di errori di progetto già dalle prime fasi dello sviluppo, quando ancora il dispositivo reale non esiste. Simone Buso - Microcontrollori e DSP - Lezione 11 23 Simone Buso - Microcontrollori e DSP - Lezione 11 24 4 Emulatore Emulatore L’emulatore è un circuito che sostituisce il processore reale nel sistema finale (i.e. sulla scheda PCB), permettendo l’esecuzione e il debugging del codice dell’applicazione in condizioni di reale utilizzo (⇒ ICE). Un emulatore richiede sempre la disponibilità di un PC di appoggio per la gestione del software di controllo. Questo permette di eseguire il programma in modalità single step e di visualizzare o editare il contenuto dei registri e della memoria, mentre il programma viene eseguito. Simone Buso - Microcontrollori e DSP - Lezione 11 Normalmente un emulatore non consente di riprodurre il funzionamento del processore alla sua massima velocità, ma solo ad una frazione di questa. Ci sono in realtà emulatori che sono effettivamente real-time, ovvero supportano la piena velocità del processore. In tal caso però spesso sono limitati nelle funzioni disponibili (breakpoints, watch, etc.). Tutto dipende dal tipo di architettura con cui è realizzato l’emulatore. 25 Simone Buso - Microcontrollori e DSP - Lezione 11 Emulatore Emulatore Fino ad alcuni anni fa (fine anni ‘90) la più comune architettura per gli ICE era quella basata su circuiti adattatori. Si tratta di speciali connettori aventi lo stesso pin-out del processore vero e proprio, collegati a un PC attraverso un opportuno circuito (detto ICE adaptor). Questo contiene una versione speciale del processore, corredata di hardware aggiuntivo per le funzioni di debugging. Il sistema era costoso e complesso, ma permetteva l’emulazione real-time. I DSP e mC più moderni dispongono di risorse hardware interne dedicate al debugging e di una particolare porta seriale per accedere a tali risorse. L’accesso a tale porta avviene, di solito, secondo lo standard IEEE 1149.1, detto JTAG. Con l’ausilio ancora di un circuito adattatore, ora piuttosto semplice, è possibile connettere un PC direttamente alla porta di debugging del dispositivo sotto test, mentre esegue la sua applicazione finale. Il programma monitor può così interagire con il processore. Simone Buso - Microcontrollori e DSP - Lezione 11 27 Emulatore 28 Emulatore L’emulazione via JTAG consente di evitare la rimozione del processore dalla scheda applicazione, e risolve ogni problema di adattamento elettrico del connettore alla scheda stessa, che era tipico degli emulatori precedenti. Inoltre, il numero di poli del connettore che collega la scheda sotto test al PC è molto minore (la porta di debugging ha di solito 5 pin) e la comunicazione procede a velocità molto inferiore a quella del processore. L’introduzione di moduli di debugging on chip aumenta il costo di ciascuna unità di un dato processore, quindi le funzionalità di questi moduli è ridotta al minimo essenziale. Ne consegue che le prestazioni di questo tipo di emulatori sono inferiori a quelle offerte dagli emulatori con adattatore. In particolare, il tracing real-time di istruzioni e pin non è di solito possibile con gli emulatori JTAG. La trasmissione dei dati verso il PC di appoggio avviene infatti per via seriale, quindi a velocità relativamente bassa. La soluzione è quindi molto più economica. Simone Buso - Microcontrollori e DSP - Lezione 11 Simone Buso - Microcontrollori e DSP - Lezione 11 26 29 Simone Buso - Microcontrollori e DSP - Lezione 11 30 5 Emulatore Emulatore Il tracing real time del programma richiede la disponibilità di buffer ad alta velocità che registrino e trasmettano il contenuto dei registri e del bus indirizzi della memoria programmi, mentre l’applicazione reale è in esecuzione. Più comune è l’uso di breakpoints real-time che permettono di arrestare l’esecuzione del programma al raggiungimento di una prefissata istruzione, oppure al momento dell’accesso ad una certa posizione di memoria o intervallo di posizioni di memoria. Simone Buso - Microcontrollori e DSP - Lezione 11 Infine, alcuni emulatori permettono solo di gestire break-point di tipo non real-time. Questi possono essere applicati soltanto durante la modalità di debugging single-step, quando l’esecuzione del programma di applicazione avanza di una istruzione alla volta. In questo caso, le condizioni di arresto dell’esecuzione possono essere anche molto complesse, perché vengono valutate quando il passo di programma è già stato compiuto e il processore è libero. 31 Memorie EPROM Il sistema di sviluppo trasferisce, per via seriale, il programma alla memoria FLASH sfruttando il fatto che lo stesso chip del processore incorpora tutta l’elettronica necessaria alla programmazione. Il processo è quindi relativamente veloce (può comunque richiedere tempi dell’ordine dei secondi). Da non trascurare il fatto che le memorie FLASH sono soggette ad un certo degrado ad ogni ciclo di scrittura, quindi è possibile che il chip usato per lo sviluppo debba essere sostituito dopo qualche tempo. Se questo processo avviene su memoria EPROM, come era tipico un tempo, tende ovviamente ad essere molto lento (la cancellazione richiede l’uso della lampada UV). Fortunatamente, questo modo di procedere è quasi completamente scomparso, grazie all’introduzione di memorie EEPROM o, oggi più comunemente, FLASH a bordo dei chip. 33 Simone Buso - Microcontrollori e DSP - Lezione 11 Memorie EPROM Linguaggi ad alto livello L’uso di un emulatore con adattatore, quando disponibile, agevola anche questo aspetto dello sviluppo, in quanto il codice da testare è, di norma, contenuto in RAM. Per tutti i DSP e per molti mC sono disponibili sistemi di sviluppo che supportano linguaggi ad alto livello (e.g. linguaggio C). I vantaggi che derivano dalla programmazione ad alto livello sono: 1. tempi di sviluppo più rapidi; 2. semplicità di manutenzione del codice; 3. portabilità. Il processo di scrittura/cancellazione diventa quindi virtualmente istantaneo. I recenti progressi nella tecnologia delle memorie EEPROM ha comunque ridotto notevolmente i tempi morti e aumentato la vita utile dei chip, rendendo di fatto molto pratico lo sviluppo di applicazioni su chip dotati di memoria FLASH. Simone Buso - Microcontrollori e DSP - Lezione 11 32 Memorie EPROM Il processo di sviluppo di una applicazione richiede numerosi accessi alla memoria del processore per il trasferimento di nuove versioni del codice e il loro test. Simone Buso - Microcontrollori e DSP - Lezione 11 Simone Buso - Microcontrollori e DSP - Lezione 11 34 Lo svantaggio principale è legato all’aumento delle dimensioni del codice e alla perdita di velocità nell’esecuzione. 35 Simone Buso - Microcontrollori e DSP - Lezione 11 36 6 Linguaggi ad alto livello Linguaggi ad alto livello A seconda del tipo di applicazione, gli svantaggi derivanti dall’uso di linguaggi ad alto livello possono essere più o meno importanti. Il linguaggio più comunemente supportato per la programmazione di mC e DSP è il C, per la sua semplicità e relativa popolarità. Esistono inoltre ottimi compilatori C per uso generico completamente gratuiti (es. GNU C Compiler GCC della Free Software Foundation) che vengono spesso adattati ai mC e DSP più popolari. L’adattamento include ad esempio la possibilità di definire variabili a virgola fissa, oppure complesse (reale+immaginario), o di inserire segmenti in assembly nel programma … Nelle applicazioni dove non è necessaria la massima potenza di calcolo oppure le frequenze di campionamento sono relativamente basse, è sicuramente possibile sviluppare codice in C. Nelle applicazioni di signal processing o controllo real-time ad alte prestazioni questa soluzione spesso può non essere accettabile. Talora si ricorre ad approcci di tipo combinato. Simone Buso - Microcontrollori e DSP - Lezione 11 37 Linguaggi ad alto livello Il problema principale dei compilatori C per mC o DSP è che tendono a generare codice poco efficiente, sia dal punto di vista della velocità di esecuzione che dal punto di vista dell’uso della memoria. In particolare per le architetture meno recenti, la realizzazione di un compilatore che sfrutti in modo ottimale le risorse di un DSP o mC risulta molto difficile. Si tratta di processori ottimizzati per la massima efficienza, non per garantire facilità di programmazione. 39 Linguaggi ad alto livello Simone Buso - Microcontrollori e DSP - Lezione 11 40 Linguaggi ad alto livello Un buon compilatore dovrebbe essere in grado di gestire in modo efficiente: • memorie multiple o variamente segmentate; Un ulteriore problema riguarda la gestione della memoria on chip. Nei mC e DSP questa è una risorsa estremamente preziosa (i.e. la quantità disponibile è molto piccola, di solito alcuni kbyte). • pochi registri con funzioni specifiche (non intercambiabili tra loro); • set di istruzioni non ortogonali (i.e. ricchi di eccezioni e casi speciali nell’uso dei registri o nell’indirizzamento dei dati); • combinazioni speciali di istruzioni che permettano l’esecuzione in parallelo; • risorse hardware specifiche. Simone Buso - Microcontrollori e DSP - Lezione 11 38 Linguaggi ad alto livello Alcuni produttori rendono disponibili anche compilatori C++ o per linguaggi più “esotici” (e.g. Ada) per i propri DSP o mC. Più spesso però sono terze parti ad offrire questi prodotti. Comunque vengono offerte (gratis o, più spesso, a pagamento) consistenti librerie di funzioni e di applicazioni, in modo analogo a quanto accade per il linguaggio assembly. Inoltre, i sistemi di sviluppo che includono un compilatore C permettono di ri-utilizzare le librerie in assembly disponibili. Simone Buso - Microcontrollori e DSP - Lezione 11 Simone Buso - Microcontrollori e DSP - Lezione 11 41 Un problema classico di molti compilatori è che suppliscono alla mancanza di registri usando locazioni di memoria. Questo porta ad esaurire la quantità disponibile (il codice eseguibile non sta nella memoria a disposizione), oltre che a un ulteriore riduzione dell’efficienza (velocità). Simone Buso - Microcontrollori e DSP - Lezione 11 42 7 Linguaggi ad alto livello Linguaggi ad alto livello Infine, i compilatori C normalmente non gestiscono variabili reali a virgola fissa. Su processori a virgola fissa, questo costringe all’emulazione dell’aritmetica a virgola mobile, il che risulta estremamente inefficiente. Questi problemi, che sono propri dei DSP e dei mC, ma non dei processori per uso generico (PC), hanno sempre reso la programmazione in C poco adatta allo sviluppo di prodotti basati su questi dispositivi. L’alternativa è lavorare con variabili di tipo intero e operare a mano gli shift necessari al riallineamento dei dati dopo certe operazioni, il che è comunque inefficiente. Ciò è particolarmente vero per i DSP a virgola fissa e i mC, meno per i DSP a virgola mobile, che tendono ad avere architetture più prossime a quelle dei processori per PC, con molti registri e set di istruzioni più ortogonali. Sono inoltre usati in applicazioni dove il costo è un fattore meno critico. In alcuni casi, però, i compilatori sono stati ottimizzati dal produttore in modo da consentire di definire variabili a virgola fissa. Simone Buso - Microcontrollori e DSP - Lezione 11 43 Simone Buso - Microcontrollori e DSP - Lezione 11 Linguaggi ad alto livello Linguaggi ad alto livello E’ importante che il sistema di sviluppo basato sul C includa anche un debugger ad alto livello. Il compilatore C da solo non è quindi sufficiente per iniziare lo sviluppo di una applicazione. Il programmatore sarebbe infatti costretto ad esaminare il codice assembly prodotto dal compilatore con un debugger di basso livello, con sicure difficoltà di interpretazione e perdite di tempo. Il debugger di alto livello è però spesso incluso nel pacchetto del sistema di sviluppo. DSP e mC di più recente progettazione tendono ad avere architetture più semplici da gestire per un compilatore, adottando in pieno la filosofia RISC (i.e. molti registri, set di istruzioni ortogonali). Tendono inoltre ad offrire potenze di calcolo molto alte, per cui la programmazione in linguaggio C può diventare praticabile. Nell’uso industriale, attualmente, la programmazione in assembly è comunque molto più diffusa rispetto all’uso del C. Simone Buso - Microcontrollori e DSP - Lezione 11 45 Simone Buso - Microcontrollori e DSP - Lezione 11 44 46 Sistemi operativi Ancora meno frequente, ma comunque non impossibile, è la disponibilità di sistemi operativi completi per DSP o mC. L’uso di un sistema operativo facilita la gestione di processi complessi, che richiedano l’intervento coordinato di programmi diversi. Ancora una volta sono i DSP a virgola mobile ad essere più adatti a questo uso, molto meno quelli a virgola fissa (o i mC). Esistono comunque sistemi operativi per DSP (serie ADSP-21xx o Motorola 5600x, a virgola fissa) e mC (e.g. basati su ARM7). Simone Buso - Microcontrollori e DSP - Lezione 11 47 8