4.5 Viteză de execuție: limbaj de programare

Programarea DSP poate fi împărțită în trei niveluri de sofisticare: Asamblare, Compilare și Specificarea aplicației. Pentru a înțelege diferența dintre aceste trei, trebuie să începem cu elementele de bază ale electronicii digitale. Toate microprocesoarele se bazează pe un set de registre binare interne, adică un grup de flip-flop-uri care pot stoca o serie de unu și zerouri. De exemplu, microprocesorul 8088, nucleul PC-ului original IBM, are patru registre de uz general, fiecare compus din 16 biți. Acestea sunt identificate prin numele: AX, BX, CX și DX. Există și nouă registre suplimentare cu scopuri speciale, numite SI, DI, SP, BP, CS, DS, SS, ES și IP. De exemplu, IP, indicatorul de instrucțiuni, ține evidența locului în care se află următoarea instrucțiune în memorie.

Să presupunem că scrieți un program pentru a aduna numerele: 1234 și 4321. Când începe programul, adresa IP conține adresa unei secțiuni de memorie care conține un model de unu și zerouri, așa cum se arată în Tabelul 4-3. Deși pare mai lipsit de sens la majoritatea oamenilor, acest model de unu și zero conține toate comenzile și datele necesare pentru a finaliza sarcina. De exemplu, atunci când microprocesorul întâlnește modelul de biți: 00000011 11000011, îl interpretează ca o comandă pentru a prelua cei 16 biți stocați în registrul BX, îi adună în binar la cei 16 biți stocați în registrul AX și stochează rezultatul în registrul AX. Acest nivel de programare se numește cod mașină și este doar un fir deasupra celor care lucrează cu circuite electronice reale.

Deoarece lucrul în binar va conduce în cele din urmă la nebunie chiar și pe cel mai răbdător inginer, acestor modele de unu și zerouri le sunt atribuite nume depinzând de funcția pe care o efectuează. Acest nivel de programare se numește asamblare, iar un exemplu este prezentat în Tabelul 4-4. Deși un program de asamblare este mult mai ușor de înțeles, este fundamental același cu cel al programării în cod mașinii, deoarece există o corespondență unu-la-unu între comenzile programului și acțiunea efectuată în microprocesor. De exemplu: ADD AX, BX se traduce la: 00000011 11000011. Un program numit un asamblator este folosit pentru a converti codul de asamblare în Tabelul 4-4 (numit cod sursă) în modele de unu și zerouri afișate în Tabelul 4-3 (numit cod obiect sau cod executabil). Acest cod executabil poate fi rulat direct pe microprocesor. Evident, programarea de asamblare necesită o înțelegere amplă a construcției interne a microprocesorului particular pe care intenționați să îl utilizați.

Tabelul 4-3 Un program cod-mașină pentru adunarea 1234 și 4321.

Acesta este cel mai jos nivel de programare: manevrarea directă a electronicii digitale. (Coloana din dreapta este o continuare a coloanei din stânga).

Tabelul 4-4 Un program de asamblare pentru adunarea 1234 cu 4321.

Un asamblor este un program care convertește un program de asamblare într-un cod mașină.

Programarea de asamblare implică manipularea directă a electronicii digitale: registre, locații de memorie, biți de stare etc. Următorul nivel de sofisticare poate manipula variabile abstracte fără a se face referire la hardware-ul particular. Acestea se numesc limbaje compilate sau de nivel înalt. Există o duzină de utilizare obișnuită, cum ar fi: C, BASIC, FORTRAN, PASCAL, APL, COBOL, LISP etc. Tabelul 4-5 prezintă un program BASIC pentru adunarea lui 1234 și 4321. Programatorul cunoaște doar variabilele A, B și C și nimic despre hardware.

Tabelul 4-5 Un program BASIC pentru adunarea 1234 cu 4321.

Un compilator este un program care convertește acest tip de cod sursă de înalt-nivel în cod mașină.

Un program numit compilator este folosit pentru a transforma codul sursă de nivel înalt direct în cod mașină. Acest lucru necesită compilatorul să atribuie locații de memorie hardware fiecărei variabile abstracte la care face referire. De exemplu, prima dată când compilatorul întâlnește variabila A în Tabelul 4-5 (linia 100), înțelege că programatorul folosește acest simbol pentru a însemna o variabilă în virgulă mobilă cu simplă precizie. Corespunzător, compilatorul desemnează patru octeți de memorie care vor fi folosiți doar pentru a ține valoarea acestei variabile. La fiecare timp ulterior, când un A apare în program, calculatorul știe să actualizeze valoarea celor patru octeți după cum este necesar. De asemenea, compilatorul rupe expresii matematice complicate, cum ar fi:..............., în aritmetică mai elementară. Microprocesoarele știu doar să adune, să scadă, să înmulțească și să împartă. Orice mai complicat trebuie făcut ca o serie de astfel de operații elementare.

Limbajele de nivel înalt izolează programatorul de hardware. Acest lucru face ca programarea să fie mult mai ușoară și permite ca codul sursă să fie transportat între diferite tipuri de microprocesoare. Cel mai important, programatorul care folosește un limbaj compilat nu trebuie să știe nimic despre funcționarea internă a calculatorului. Un alt programator și-a asumat această responsabilitate, cel care a scris compilatorul.

Cele mai multe compilatoare funcționează prin transformarea întregului program în codul mașinii înainte de a fi executat. O excepție la acest lucru este un tip de compilator numit interpretor, din care interpreter BASIC este cel mai frecvent exemplu. Un interpretor convertește o singură linie de cod sursă în codul mașinii, execută acel cod mașină și apoi trece la următoarea linie de cod sursă. Aceasta oferă un mediu interactiv pentru programe simple, deși viteza de execuție este extrem de lentă (cred că un factor de 100).

Cel mai înalt nivel de sofisticare a programării se găsește în pachetele de aplicații pentru DSP. Acestea vin într-o varietate de forme și sunt adesea furnizate pentru a susține hardware specific. Să presupunem că ați cumpărat un microprocesor DSP nou dezvoltat pentru a încorpora în proiectul dvs. curent. Aceste dispozitive au adesea o mulțime de funcții încorporate pentru DSP: intrări analogice, ieșiri analogice, I/O digitale, filtre antialias și de reconstrucție etc. Întrebarea este: cum îl programați? În cel mai rău caz, producătorul vă va oferi un asamblor și vă așteptați să aflați arhitectura internă a dispozitivului. Într-un scenariu mai tipic, un compilator C va fi furnizat, permițându-vă să programați fără a fi deranjați de modul în care microprocesorul funcționează.

În cel mai bun caz, producătorul va furniza un pachet software sofisticat pentru a ajuta la programare: biblioteci de algoritmi, rutine pre-scrise pentru I/O, instrumente de depanare etc. Puteți să conectați icon-urile pentru a forma sistemul dorit într-un display grafic ușor de utilizat. Lucrurile pe care le manevrați sunt căi de semnal, algoritmi pentru procesarea semnalelor, parametrii I/O analogice, etc. Când sunteți mulțumit de schemă, aceasta este transformată în cod mașină adecvat pentru execuție în hardware. Alte tipuri de pachete de aplicații sunt utilizate cu procesarea imaginilor, analiza spectrală, instrumentația și controlul, proiectarea filtrelor digitale etc. Aceasta este forma viitorului.

Distincția dintre aceste trei niveluri poate fi foarte neclară. De exemplu, majoritatea limbajelor conformate vă permit să manipulați direct hardware-ul. De asemenea, un limbaj de nivel înalt cu o bibliotecă de funcții DSP bine aprovizionată este foarte aproape de a fi un pachet de aplicații. Poanta acestor trei categorii este să înțelegeți ce manipulați: (1) hardware, (2) variabile abstracte, sau (3) proceduri și algoritmi întregi.

Există, de asemenea, un alt concept important în spatele acestor clasificări. Când folosiți un limbaj de nivel înalt, vă bazați pe programatorul care a scris compilatorul pentru a înțelege cele mai bune tehnici de manipulare hardware. În mod similar, atunci când utilizați un pachet de aplicații, vă bazați pe programatorul care a scris pachetul pentru a înțelege cele mai bune tehnici DSP. Aici este un hop: acești programatori nu au văzut niciodată problema cu care aveți de-a face. Prin urmare, ei nu vă pot oferi întotdeauna o soluție optimă. Deoarece operați pe un nivel superior, vă așteptați ca codul mașină final să fie mai puțin eficient în ceea ce privește utilizarea memoriei, viteza și precizia.

Care limbaj de programare ar trebui să utilizați? Asta depinde de cine ești și ce ai de gând să faci. Cei mai mulți oameni de știință și programatori folosesc C (sau cel mai avansat C ++). Putere, flexibilitate, modularitate; C are tot. C este atât de popular, întrebarea devine: De ce ar programa cineva aplicația lor DSP în altceva decât C? Trei răspunsuri vin în minte. În primul rând, DSP a crescut atât de rapid încât unele organizații și indivizi sunt blocați în modul de utilizare a altor limbaje, cum ar fi FORTRAN și PASCAL. Acest lucru este valabil mai ales în cazul agențiilor militare și guvernamentale care sunt lent de schimbat. În al doilea rând, unele aplicații necesită cea mai mare eficiență, posibilă numai prin programe de asamblare. Acest lucru se încadrează în categoria "o viteză puțin mai mare pentru mult mai multă muncă". În al treilea rând, C nu este un limbaj deosebit de ușor de stăpânit, mai ales pentru programatorii cu program part-time. Aceasta include o gamă largă de ingineri și oameni de știință care, ocazional, au nevoie de tehnici DSP pentru a sprijini activitățile lor de cercetare sau de proiectare. Acest grup se orientează adesea spre BASIC din cauza simplității sale.

De ce a fost ales BASIC pentru această lucrare? Această lucrare este despre algoritmi, nu despre stilul de programare. Ar trebui să vă concentrați asupra tehnicilor DSP și să nu fiți distrași de ciudățeniile unui anumit limbaj. De exemplu, toate programele din această lucrare au numere de linie. Acest lucru facilitează descrierea modului în care programul funcționează: "linia 100 face acest lucru, linia 110 face acest lucru - și asta", etc. Desigur, probabil că niciodată nu veți utiliza numere de linie în programele dvs. reale. Poanta este că învățarea DSP are cerințe diferite decât utilizarea DSP. Există multe cărți pe piață care oferă un cod sursă excelent pentru algoritmi DSP. Dacă pur și simplu căutați cod pre-scris pentru a-l copia în programul dvs., vă aflați în locul greșit.

Compararea vitezei de execuție a hardware-ului sau a software-ului este o sarcină ingrată; indiferent de rezultat, cel ce a pierdut va plânge că meciul a fost nedrept! Programatorii cărora le plac limbajelele de nivel înalt (cum ar fi oamenii de știință tradiționali de calculatoare) vor susține că asamblarea este cu doar 50% mai rapid decât codul compilat, dar de cinci ori mai multe probleme. Cei care preferă asamblarea (de obicei, oameni de știință și ingineri hardware) vor susține invers: asamblarea este de cinci ori mai rapidă, dar numai cu 50% mai greu de utilizat. Ca și în majoritatea controverselor, ambele părți pot oferi date selective pentru a-și susține afirmațiile.

De regulă, așteptați ca o subrutină scrisă în asamblare să fie între 1,5 și 3,0 ori mai rapidă decât programul comparabil de nivel înalt. Singura modalitate de a cunoaște valoarea exactă este scrierea codului și efectuarea testelor de viteză. Deoarece calculatoarele personale cresc în viteză cu aproximativ 40% în fiecare an, scrierea unei rutine în asamblare este echivalentă cu aproximativ un salt de doi ani în domeniul tehnologiei hardware.

Majoritatea programatorilor profesioniști sunt mai degrabă jigniți de ideea utilizării asamblării și glumesc dacă sugerați BASIC. Rațiunea lor este destul de simplă: asamblarea si BASIC descurajează folosirea unor practici bune de software. Codul bun ar trebui să fie portabil (capabil să treacă de la un tip de computer la altul), modular (rupt într-o structură de subrutină bine definită) și ușor de înțeles (numeroase comentarii și nume de variabile descriptive). Structura slabă a asamblării și BASIC face dificilă realizarea acestor standarde. Acest lucru este agravat de faptul că persoanele care sunt atrase de asamblare și BASIC au adesea puțină instruire formală în structura și documentația corespunzătoare a software-ului.

Iubitorii asamblării răspund la acest atac cu o replică proprie. Să presupunem că scrieți un program în C și concurentul dvs. scrie același program în asamblare. Impresia primului utilizator final va fi că programul dvs. este junk (gunoi), deoarece este de două ori mai lent. Nimeni nu ar sugera că scrieți programe mari în asamblare, doar acele porțiuni ale programului care necesită execuție rapidă. De exemplu, multe funcții în bibliotecile de programe DSP sunt scrise în asamblare și apoi accesate din programe mai mari scrise în C. Chiar și cel mai neschimbat purist de software va folosi codul de asamblare, atâta timp cât nu trebuie să-l scrie.

Secțiunea următoare: Viteză de execuție: Hardware