SlideShare ist ein Scribd-Unternehmen logo
1 von 144
Downloaden Sie, um offline zu lesen
Praktikum


                        Digitale Signalverarbeitung




Institut für Nachrichtengeräte
und Datenverarbeitung
Prof. Dr.-Ing. Peter Vary
Dsvdoc
Inhaltsverzeichnis




1 Der Signalprozessor Analog Devices ADSP-21369                                             7
   1.1   Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     7
         1.1.1   Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   7
         1.1.2   Grundstruktur der Signalprozessor-Architektur . . . . . . . . . . .        7
   1.2   Signalprozessor Analog Devices ADSP-21369 . . . . . . . . . . . . . . . .          12
         1.2.1   Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    12
         1.2.2   Datenformate . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     14
         1.2.3   Recheneinheiten und Datenregister . . . . . . . . . . . . . . . . .        15
         1.2.4   Das Programm-Steuerwerk . . . . . . . . . . . . . . . . . . . . . .        18
         1.2.5   Datenadressierung . . . . . . . . . . . . . . . . . . . . . . . . . .      24
         1.2.6   Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   27
   1.3   Entwicklungsumgebung: Visual DSP++ . . . . . . . . . . . . . . . . . . .           28
         1.3.1   Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     28
         1.3.2   Implementierung des Source-Codes . . . . . . . . . . . . . . . . .         29
   1.4   Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . .       34
         1.4.1   Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     34
         1.4.2   Programm 1: Interruptgesteuerte Ein-/Ausgabe . . . . . . . . . . .         35
         1.4.3   Programm 2: Parallele Verarbeitung von Befehlen . . . . . . . . . .        45
         1.4.4   Programm 3: Benutzung des Rahmenprogramms . . . . . . . . . .              49

2 Grundlagen MATLAB und SIMULINK                                                            53
   2.1   Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   53
   2.2   Grundlagen der digitalen Signalverarbeitung . . . . . . . . . . . . . . . . .      54
         2.2.1   Abtastung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    54
         2.2.2   Quantisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    55
   2.3   Einführung in MATLAB . . . . . . . . . . . . . . . . . . . . . . . . . . .         56
         2.3.1   Starten von MATLAB . . . . . . . . . . . . . . . . . . . . . . . .         56

                                                                                                 3
2.3.2   Benutzung von Hilfe-Funktionen       ..................                    58
             2.3.3   Verwendung von Variablen . . . . . . . . . . . . . . . . . . . . . .       60
             2.3.4   Operationen mit Vektoren und Matrizen . . . . . . . . . . . . . . .        62
             2.3.5   Elementare Funktionen . . . . . . . . . . . . . . . . . . . . . . . .      64
             2.3.6   Grafische Darstellungsmöglichkeiten . . . . . . . . . . . . . . . .         65
             2.3.7   Audiowiedergabe . . . . . . . . . . . . . . . . . . . . . . . . . . .      65
             2.3.8   Verwalten von Daten und Dateien . . . . . . . . . . . . . . . . . .        65
             2.3.9   Erstellen von Skripten und Funktionen . . . . . . . . . . . . . . . .      66
       2.4   Einführung in SIMULINK . . . . . . . . . . . . . . . . . . . . . . . . . .         67
             2.4.1   Starten von SIMULINK . . . . . . . . . . . . . . . . . . . . . . .         68
             2.4.2   Die Quellen eines SIMULINK-Modells . . . . . . . . . . . . . . .           70
             2.4.3   Die Senken eines SIMULINK-Modells . . . . . . . . . . . . . . .            71
             2.4.4   Starten einer Simulation mit Angabe von Simulationsparametern . .          71
       2.5   DSP-Debugging mit MATLAB . . . . . . . . . . . . . . . . . . . . . . . .           72
       2.6   Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . .       75
             2.6.1   Aufgabe I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    75
             2.6.2   Aufgabe II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     75
             2.6.3   Aufgabe III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    76
             2.6.4   Aufgabe IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     76
       2.7   Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . .       77
             2.7.1   Versuch A: Grundlegende MATLAB-Operationen . . . . . . . . .               77
             2.7.2   Versuch B: MATLAB-Funktionen . . . . . . . . . . . . . . . . . .           78
             2.7.3   Versuch C: DSP-Debugging mit MATLAB . . . . . . . . . . . . .              79
             2.7.4   Versuch D: Echo-Effekt mit dem DSP / Zyklischer Speicher . . . .            79
             2.7.5   (*) Versuch E: Rückfaltungen . . . . . . . . . . . . . . . . . . . .       80
             2.7.6   (*)Versuch F: Grobquantisierung . . . . . . . . . . . . . . . . . . .      81
             2.7.7   (*)Versuch G: Amplitudenmodulation mit Hüllkurvenempfang . . .             82
       Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   84

    3 Diskrete Fourier-Transformation (DFT)                                                     85
       3.1   Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   85
       3.2   Theoretische Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . .      85
             3.2.1   Definition und Eigenschaften der DFT . . . . . . . . . . . . . . . .        85
             3.2.2   Fensterfunktionen     ..........................                           87
             3.2.3   Schnelle Fourier-Transformation (FFT) . . . . . . . . . . . . . . .        93
             3.2.4   Schnelle Faltung . . . . . . . . . . . . . . . . . . . . . . . . . . .     93

4
3.3   Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . .       97
         3.3.1   Aufgabe I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    97
         3.3.2   Aufgabe II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .     98
         3.3.3   Aufgabe III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .    98
   3.4   Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
         3.4.1   Versuch A: DFT spezieller Signale . . . . . . . . . . . . . . . . . . 101
         3.4.2   Versuch B: Zero-Padding . . . . . . . . . . . . . . . . . . . . . . . 102
         3.4.3   Versuch C: Fensterung und Leckeffekt . . . . . . . . . . . . . . . . 102
         3.4.4   Versuch D: Schnelle Faltung mittels overlap add Verfahren . . . . . 103
         3.4.5   Versuch E: FFT auf dem DSP . . . . . . . . . . . . . . . . . . . . 106
         3.4.6   (*)Versuch F: Gemeinsame Transformation zweier reeller Signale . 106
         3.4.7   (*)Versuch G: Analyse von Signalen mit diskr. spektr. Komponenten 107
   Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

4 Digitale FIR- und IIR-Filter                                                             109
   4.1   Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
   4.2   Beschreibung linearer zeitdiskreter Systeme . . . . . . . . . . . . . . . . . 109
   4.3   FIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
         4.3.1   FIR-Filter mit linearer Phase . . . . . . . . . . . . . . . . . . . . . 111
         4.3.2   FIR-Filterentwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
   4.4   IIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
         4.4.1   Stabilität . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
         4.4.2   Filterstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
         4.4.3   IIR-Filterentwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
   4.5   Spezielle Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
         4.5.1   Differentiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
         4.5.2   Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
         4.5.3   Hilbert-Transformation . . . . . . . . . . . . . . . . . . . . . . . . 126
         4.5.4   Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
   4.6   Eigenschaften realer Filter . . . . . . . . . . . . . . . . . . . . . . . . . . 128
         4.6.1   FIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
         4.6.2   IIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
   4.7   Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
         4.7.1   Aufgabe 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
         4.7.2   Aufgabe 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
         4.7.3   Aufgabe 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

                                                                                                 5
4.7.4   Aufgabe 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
          4.7.5   Aufgabe 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
          4.7.6   Aufgabe 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
    4.8   Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
          4.8.1   FIR-Versuch A: Rechteck-, Hamming- und Blackman-Fenster . . . 137
          4.8.2   FIR-Versuch B: Kaiser-Fenster . . . . . . . . . . . . . . . . . . . . 137
          4.8.3   FIR-Versuch D: Differentiation . . . . . . . . . . . . . . . . . . . . 138
          4.8.4   FIR-Versuch E: FIR-Filter auf dem DSP . . . . . . . . . . . . . . . 138
          4.8.5   (*)FIR-Versuch F: Koeffizienten-Quantisierung . . . . . . . . . . . 139
          4.8.6   (*) FIR-Versuch G: Tschebyscheff-Approximation . . . . . . . . . 139
          4.8.7   IIR-Versuch A: Rekursive Differenzengleichung . . . . . . . . . . 139
          4.8.8   IIR-Versuch B: Spezielle rekursive Filter . . . . . . . . . . . . . . 140
          4.8.9   IIR-Versuch C: Sprungantwort und Einschwingzeit . . . . . . . . . 142
          4.8.10 (*)IIR-Versuch D: Vergleich verschiedener Approximationsverfahren 142
    Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144




6
Kapitel 1


                  Der Signalprozessor Analog Devices
                                        ADSP-21369




                                                                                         1.1 Grundlagen

                                                                                               1.1.1 Einleitung

Im ersten Versuch wird der Aufbau und die Programmierung des Prozessors ADSP-21369
von Analog Devices erklärt. Um einen leichten Einstieg in die Projektphase im Anschluss
zu ermöglichen, wurde am IND eine Software erstellt. Die Prinzipien dieser Software sind
im zusätzlichen Dokument „Rapid Prototyping on Embedded targets: RTProcDSP“ erläu-
tert. Durch die Software-Vorgabe wird es den Studenten ermöglicht, den Prototypen eines
neuartigen Algorithmus zu erstellen, ohne allzuviel mit den Programmierungsdetails des
Echtzeit- Betriebssystems in Kontakt zu kommen.
Zur Programmierung der Hardware bietet Analog Devices eine Entwicklungsumgebung an,
die sich Visual DSP++ nennt. Diese wird schließlich kurz vorgestellt. Mit ihrer Hilfe wer-
den im Anschluss die Übungsbeispiele simuliert bzw. emuliert.



                                               1.1.2 Grundstruktur der Signalprozessor-Architektur

In den letzten Jahren war bei Bauteilen in Hardware-Komponenten neuer Produkte eine
Spezialisierung auf den Anwendungsfall zu beobachten. Es macht keinen Sinn, für Algo-
rithmen zur reinen Signalverarbeitung die Kosten eines General-Purpose Prozessors (z.B.
Intel Pentium Prozessor) bezahlen zu müssen, wenn dieselben Algorithmen von einem Pro-
zessor ausgeführt werden können, der auf diese Art von Anwendungen spezialisiert ist.
Gleichzeitig erscheint es auch in vielen Bereichen sinnvoll, Algorithmen nicht in „Silicon“,
also Hardware, sondern in Software zu realisieren. Dadurch kann auf sich ändernde Sys-
temanforderungen bei existierenden Produkten schnell und umfassend reagiert werden, in-
dem zum Beispiel Software-Updates durchgeführt werden.
DSPs sind für Echtzeitanwendungen, z. B. im Bereich der Audio- und Videoverarbeitung,
entwickelt worden und verfügen über für ihren Einsatz angepasste Befehlssätze und Archi-
tekturen. Sie haben einen niedrigen Leistungsverbrauch und sind durch ihre Spezialisierung
in der Anschaffung sehr günstig. Ein Programmierer kann im Bereich der Signalverarbeitungs-

                                                                                                             7
Algorithmen sehr kompakten Code erzeugen, was zu einer Minimierung des Speicherbe-
    darfs in einem Produkt führt.
    Die ersten Signalprozessoren waren modular aus Bit-Slice-Elementen aufgebaut. Der damit
    verbundene hohe Aufwand beschränkte den Einsatz der digitalen Signalverarbeitung auf
    spezielle Gebiete. Erst die Entwicklung monolithisch integrierter Signalprozessoren An-
    fang der achtziger Jahre ermöglichte den Einsatz der DSV in vielen kommerziellen Berei-
    chen. Mittlerweile existiert ein breites Angebot digitaler Signalprozessoren verschiedener
    Hersteller.
    Trotz ihrer unterschiedlichen und komplexen Architekturen enthalten die heutigen Signal-
    prozessoren gemeinsame Grundstrukturen. Diese Grundstrukturen ergeben sich aus den An-
    forderungen der DSV-Algorithmen.
    Die für die DSV exemplarischen Algorithmen wie z. B. die Fourier-Transformation, die
    Korrelation und die digitale Filterung enthalten in ihrem Kern vektorielle Skalarprodukte.
    Um diese Skalarprodukte schnell berechnen zu können, sind Signalprozessoren mit einem
    Hardware-Multiplizierer ausgestattet. Diesem ist ein Addierer/Akkumulator nachgeschal-
    tet.
    Abbildung 1.1 zeigt den prinzipiellen Aufbau der Recheneinheit (Daten-ALU (Arithmetic
    Logical Unit)) am Beispiel eines 16 Bit Festkomma Signalprozessors. Die zu verarbeiten-
    den Daten werden in Eingangsregistern zwischengespeichert und dem Multiplizierer zu-
    geführt. Damit keine Genauigkeitsverluste auftreten, wird das Ergebnis der Multiplikation
    zunächst mit einer Wortbreite von 31 bzw. 32 Bit dargestellt und zum Inhalt des Ausgangs-
    registers addiert. Die mit insgesamt 40 Bit um 8 Bit größeren Wortbreiten von Addierer und
    Ausgangsregister ermöglichen die überlauffreie Addition von bis zu 28 = 256 Produkten.




                      Abbildung 1.1: Daten-ALU eines 16-Bit Signalprozessors


    Erst wenn das Ergebnis feststeht, also alle Multiplikationen und Additionen durchgeführt
    wurden, verringert ein sogenannter Barrelshifter die Ergebniswortbreite auf das ursprüng-
    liche 16 Bit Format. Dabei kann eine mathematische Rundungsoperation und eine betrags-
    mäßige Begrenzung eingeschlossen sein.
    Multiplizierer und Addierer arbeiten gleichzeitig. Das bedeutet, dass in einem Maschinen-

8
zyklus die Werte aus den Eingangsregistern multipliziert werden können und das Ergebnis
des Multiplizierers im Addierer verarbeitet werden kann. Damit werden zwei Rechenope-
rationen pro Zyklus ausgeführt. Das vektorielle Skalarprodukt y der Dimension N kann im
Prinzip in N Prozessorzyklen berechnet werden:

                       N−1
      y = x · bT =           bi · xi                                                 (1.1)
                       i=0


mit

      x = {x0 , x1 , . . . , xN−1 }                                                  (1.2)

und

      b = {b0 , b1 , . . . , bN−1 }.                                                 (1.3)

Das hier beschriebene gleichzeitige Addieren und Multiplizieren ist eines der wichtigsten
Merkmale eines Signalprozessors und wird durch spezielle multiply/accumulate-Befehle
unterstützt. Bei einigen Signalprozessoren werden die Multiplikation und die Addition in
zwei aufeinander folgenden Zyklen, d.h. im „Pipeline“ - Betrieb durchgeführt. Im Akku-
mulator wird dabei jeweils das Produktergebnis aus dem vorhergehenden Befehlszyklus
auf das Ausgangsregister aufaddiert. Da der Multiplizierer und der Akkumulator gleichzei-
tig arbeiten, dauert die Berechnung des Skalarproduktes der Dimension N insgesamt N + 1
Takte.
Selbstverständlich bietet ein DSP auch die Möglichkeit, nur zu addieren oder nur zu multi-
plizieren. Weiterhin gehören Bit-Manipulationsbefehle und logische Operationen zum Be-
fehlsrepertoire eines Signalprozessors.
Im vorgestellten Beispiel müssen nach jedem Maschinenzyklus zwei neue Eingangsdaten
bereitstehen, wenn die Daten-ALU ausgelastet werden soll. Zusätzlich muss in jedem Pro-
grammschritt ein Befehlswort gelesen werden. Das bedeutet drei Datenübertragungen pro
Zyklus. Diese hohe Übertragungrate wird durch eine sogenannte „Harvard-Architektur“ er-
möglicht. Diese Architektur verfügt im Gegensatz zur „von Neumann-Struktur“ über se-
parate Programm- und Datenspeicher sowie über separate Daten- und Adressbusse. Da-
durch sind Schreib- und Leseoperationen im Datenspeicher möglich, während gleichzeitig
Instruktionen aus dem Programmspeicher gelesen werden.
Eine Super-Harvard-Architektur bietet zusätzlich die Möglichkeit, Instruktionen in einem
Cache zwischenzuspeichern. Der betrachtete Prozessor ADSP-21369 entspricht in seinem
Aufbau einer Super-Harvard Architektur. Abbildung 1.2 zeigt das Prinzipschaltbild eines
derartigen Signalprozessors mit erweiterter Harvard-Architektur.
Neben der Daten-ALU, dem Programm- und dem Datenspeicher sind zwei weitere Kom-
ponenten zu erkennen: die Programm-Ablaufsteuerung und die Adress-ALU.
Die Adress-ALU berechnet bei dieser Architektur pro Maschinenzyklus die beiden Spei-
cheradressen der Daten für die nächste Operation der Daten-ALU. Erst dadurch wird si-
chergestellt, dass in jedem Befehlszyklus neue Daten zu den Eingangsregistern übertragen
werden können.
Der Befehlssatz der Adress-ALU ist auf die Belange der DSV abgestimmt. Hervorzuheben
ist z. B. die in der Regel verfügbare Modulo-Adressarithmetik. Bei dieser Adressierungsart

                                                                                             9
Abbildung 1.2: Prinzipielle Architektur eines digitalen Signalprozessors
                               (DSP)


     erzeugt die Adress-ALU aufeinanderfolgende Adressen innerhalb eines bestimmten Berei-
     ches. Ist das Bereichsende erreicht, so wird mit dem Bereichsanfang fortgefahren, ohne
     dass dazu zusätzliche Programmschritte notwendig sind. Diese Eigenschaft lässt sich z. B.
     vorteilhaft in Programmen nutzen, in denen Daten blockweise verarbeitet werden (Modulo-
     Adressierung, vgl. Abschnitt 1.2.5).
     Die Leistungsmerkmale der heute verfügbaren Prozessoren unterscheiden sich bezüglich

        • Arithmetik

        • Speicherkapazität

        • Geschwindigkeit

        • Architektur und Befehlssatz.

     Für eine kleine, repräsentative Auswahl aus dem derzeitigen Angebot wurden in Tabelle 1.1
     einige Angaben zum Entwicklungsstand integrierter Signalprozessoren zusammengestellt.




10
Firma           Typ            Jahr   Zyklus/Frequenz   Wortbreite   Arithmetik    Daten-RAM
 Infineon        Carmel 10xx                 4 ns/250 MHz       16 bit     Festkomma      (← Core)
                Carmel 20xx
                   (Core) a
                                                                                           32k b
                   Tricore      97-99       6 ns/167 MHz       16/32      Gleitkomma
                (MCU-DSP)
     Texas      TMS320C25       1987       80 ns/12,5 MHz       16        Festkomma       4k x 16
Instruments     TMS 320C40                  33 ns/30 MHz        32        Gleitkomma      2k x 16
                TMS 320C50                  25 ns/40 MHz        16        Festkomma       10k x 16
                TMS 320C62      1997        5 ns/200 MHz        16        Festkomma       2 x 512k
                TMS 320C67      1997        6 ns/167 MHz        32        Gleitkomma      2 x 512k
                TMS 320C64      2000       0,9 ns/1100 MHz                               (← Core)
                   (Core)
 Motorola          56001        1987       100 ns/10 MHz        24        Festkomma     2 x 512k x 24
                   56301                   12,5 ns/80 MHz       24        Festkomma      2 x 2k x 24
                   56800E       2000        5 ns/200 MHz       8-32       Festkomma      (← Core)
                (MCU-DSP)
                   56853        2001       8,3 ns/120 MHz                                   32k
  Analog        ADSP-21060      1995        25 ns/40 MHz        32        Gleitkomma       2 x 2M
 Devices        ADSP-21065L     1995        16 ns/60 MHz        32         Gleit/Fest       1M
                 2192 (Dual)    2000       6,25 ns/160 MHz      16        Festkomma      (← Core)
                 21116 ($5)     2000       10 ns/100 MHz        32        Gleitkomma
                ADSP-21369      2005       2,5 ns/400 MHz       32         Gleit/Fest       16M

 a
     CLIW and power plugs support
 b
     Caches-support

                        Tabelle 1.1: Auswahl von aktuellen und alten DSPs




                                                                                                        11
1.2 Signalprozessor Analog Devices ADSP-21369

1.2.1 Architektur

                    Zunächst soll ein Überblick über die Prozessorarchitektur und seine für den Versuch re-
                    levanten Komponenten vorgestellt werden. Abschnitt 1.2 ist als eine kurze Einführung zu
                    verstehen. Für weitere Informationen wird auf die „ADSP-2136x SHARC Programming
                    Reference“ verwiesen, die im Folgenden kurz „Handbuch“ genannt wird.
                    Der in Versuch 4 und der anschließenden Projektphase eingesetzte Signalprozessor ADSP-
                    21369 ist ein 32 Bit Gleitkommaprozessor, der bei einer Taktfrequenz von 333 MHz arbeitet
                    und 8 MB on-chip-Speicher hat (2 MB SRAM und 6 MB ROM). Er hat darüberhinaus einen
                    Cache-Speicher, der 32 Befehle halten kann, und eine große Anzahl von Registern (spezielle
                    Speicherstellen, die z. B. Operanden und Ergebnisse enthalten). Dank paralleler Ausführung
                    großer Teile der ALU werden SIMD-Befehle (Single Instruction Multiple Data) unterstützt,
                    so dass der Prozessor bei voller Auslastung 2 GFLOPS (Giga Floating Point Operations
                    per Second) verrichten kann. Multi-Prozessor-Einsatz wird durch Link Ports unterstützt.
                    Mit dem DMA (Direct Memory Access) Controller lassen sich große Datenblöcke ein- und
                    ausgeben, ohne dass die Rechenkapazität des Prozessors reduziert wird.
                    Auf der Versuchshardware ist ein solcher Prozessor vorhanden. Desweiteren befindet sich
                    auf derselben Platine ein externer Speicher (SDRAM), der Platz für 4 Mega-Wort Daten
                    beinhaltet (32-Bit Worte) sowie ein 1 MB großer nichtflüchtiger Speicher (Flash-EEPROM).
                    Zur Peripherie gehören außerdem ein AD/DA-Wandler (AD1835A), über den die Audioein-
                    und ausgabe abläuft, sowie eine UART-Schnittstelle (ADM3202 RS-232), die der Laufzeit-
                    Komunikation mit dem PC dient. Die Audiodaten werden mit einer Abtastfrequenz von bis
                    zu 96 KHz, in der Regel aber 48 KHz eingelesen (bei einem DAC sogar bis zu 192Hz) und
                    mit 16, 20 oder 24 Bit quantisiert. Die UART-Schnittstelle hat eine Datenübertragungsrate
                    von 9600 bis 115200 Baud und dient der Übergabe von Variablen vom PC an den DSP und
                    andersherum. Die einzelnen Prozessor-Kennzahlen sind in Tabelle 1.2 zusammengefasst.

                                    Prozessortyp                      ADSP-21369
                                      Datentyp                Gleitkomma (32 oder 40 Bit)
                                                              Festkomma (16 oder 32 Bit)
                                      Speicher                2 MB SRAM + 6 MB ROM
                                                         + 512 kBit SRAM + 4 Mx32 SDRAM
                                                        + 8 MBit parallel flash + 2 Mbit SPI flash
                                    Taktfrequenz                        333 MHz
                                 Analoge Ausgänge                    4 Stück, Stereo
                                 Analoge Eingänge                    1 Stück, Stereo
                                     Abtastraten            bis zu 96 kHz 16, 20 oder 24 Bit
                                Analoge Verstärkung            Vor- und Nachverstärkung
                                    Schnittstelle             UART, 16550, 115200 Baud

                                             Tabelle 1.2: Prozessor-System-Merkmale


                    Abbildung 1.3 zeigt das vereinfachte Blockschaltbild des ADSP-21369. Es handelt sich um

12
eine „Super Harvard-Architektur“ (daher SHARC) mit SIMD-Funktionalität.




                Abbildung 1.3: Vereinfachtes Blockschaltbild des ADSP-21369

Der Prozessorkern (core processor) des ADSP-21369 besteht aus zwei Verarbeitungseinhei-
ten (PEX und PEY), von denen jede aus drei Recheneinheiten (ALU, Multiplizierer, Shif-
ter) besteht sowie einem Programm-Steuerwerk, zwei Daten-Adressrechnern (DAG1 und
DAG2) mit jeweils acht Registern für indirekte Adressierung, zwei Timern, dem Befehls-
Cache und aus 16 Data-Registern im Data Register File. Darüber hinaus existieren meh-
rere Modus- und Statusregister, die die Funktion des Prozessors steuern (z. B. die Register
MODE1 und MODE2) und Aussage über Rechenergebnisse geben (z. B. das ASTAT Register).
Diese Register sind nicht in Abbildung 1.3 eingezeichnet.
Weiterhin sind in obiger Abbildung die DMA-Controller, acht full-duplex-fähige seriel-
le Schnittstellen, eine digitale Audioschnittstelle, die vier Präzisionstaktgeber (PCG), ei-
ne Eingabeschnittstelle (IDP), ein S/PDIF-Empfänger/-Sender, acht Kanäle mit jeweils ei-
nem asynchronen Abtastratenkonverter, acht serielle Schnittstellen, eine 16-bit Parallelein-
gabeschnittstelle (PDAP) und eine flexible Signal-Routing-Einheit (DAI SRU) enthält so-
wie ein Digital-Peripheral-Interface dargestellt, das drei Taktgeber, eine I2C-Schnittstelle,
zwei UARTs, zwei serielle periphere Schnittstellen (SPI) und eine flexible Signal-Routing-
Einheit (DPI SRU) enthält.
Wie oben schon erwähnt, verfügt der ADSP-21369 über SIMD-Funktionalität. Generell
wird die Verarbeitungseinheit PEX benutzt. Eine gleichzeitige Verwendung der Einheit PEY
kann durch Setzen des PEYEN-Mode-Bits im MODE1-Register aktiviert werden. Ist dies
der Fall, so werden die selben Instruktionen in beiden Verarbeitungseinheiten ausgeführt,
operieren allerdings auf verschiedenen Daten. Diese Architektur ist besonders bei rechen-
intensiven Algorithmen effizient.
Das Einschalten des SIMD-Modus’ hat auch eine Auswirkung auf die Art und Weise, wie
Daten zwischen Speicher und den beiden Verarbeitungseinheiten übertragen wird. Ist dieser
Modus aktiviert, so wird eine doppelte Datenbandbreite gebraucht, um den Rechenfluss
in beiden Einheiten aufrecht zu erhalten, so dass im SIMD-Modus mit jedem Zugriff auf

                                                                                                13
den Speicher oder die Register also zwei Datenwerte transferiert werden. Dementsprechend
               müssen die Daten auch im Speicher auf korrekte Weise abgelegt werden müssen.
               Bevor nun die Einheiten des Prozessors näher betrachtet werden, sollen erst die zur Verfü-
               gung stehenden Datenformate erwähnt werden:


1.2.2 Datenformate

               Der ADSP-21369 bietet sowohl Fest- als auch Gleitkomma-Formate an. Mit der Festkomma-
               darstellung wird eine Zahl durch 32 Bits repräsentiert. In einem Register im Data Register
               File belegen sie die obersten 32 der 40 Bits. Man unterscheidet zwischen den Darstellungen
               signed und unsigned bzw. integer und fractional. Beim signed-Format ist das ers-
               te Bit das Vorzeichenbit. Negative Zahlen werden durch das Zweierkomplement dargestellt.
               Der Wert des LSBs ist für signed integer gleich 1 bzw. für signed fractional 2−31 . So ergeben
               sich die Zahlenbereiche


                     − 231 ≤ x ≤ 231 − 1                (signed integer, SI)                           (1.4)
                                              −31
                        −1 ≤ x ≤ 1 − 2                  (signed fractional, SF).                       (1.5)


               Mit dem unsigned-Format können nur positive Zahlen dargestellt werden. Es gelten die
               Zahlenbereiche 0 ≤ x ≤ 232 − 1 (unsigned integer, UI) bzw. 0 ≤ x ≤ 1 − 2−32 (unsigned
               fractional, UF). Die Gewichte der einzelnen Bits sind in Abbildung 1.4 verdeutlicht.




                         Abbildung 1.4: Die Gewichte einzelner Bits verschiedener Festkommafor-
                                            mate bei Speicherung in einem 40-Bit Register


               Zusätzlich zu der Festkommadarstellung bietet der ADSP-21369 ein Gleitkomma-Format
               mit entweder 32 Bits oder 40 Bits an. Es besteht aus einem Vorzeichenbit s, 8 Bits für den
               Exponenten e und 23 bzw. 31 Bits für den Bruchteil f der Basis, der durch 1. f dargestellt
               wird. 1. f ist dabei eine Zahl zwischen 1 und 2 − 2−23 bzw. 1 und 2 − 2−31 . Der Wert einer
               Zahl x ergibt sich dann aus dem Zusammenhang

                     x = (−1)s · (1. f ) · 2e−127                                                      (1.6)


               Abbildung 1.5 zeigt die Bitbelegung im Speicher.
               Durch die Gleitkommadarstellung lassen sich Quantisierung und Übersteuerungsprobleme
               weitgehend vermeiden. Sie bietet sich deswegen bei der Entwicklung neuer Algorithmen
               und Prototypen an.

14
Abbildung 1.5: Gleitkomma-Formate für 32 bzw. 40 Bits



                                                               1.2.3 Recheneinheiten und Datenregister

Der Prozessorkern enthält wie in Abbildung 1.6 veranschaulicht drei unabhängige Rechen-
einheiten: eine ALU, einen Multiplizierer und einen Shifter.




                            Abbildung 1.6: Aufbau der Core Unit


Alle drei Datenformate können verarbeitet werden: 32 Bit Festkomma, 32 Bit Gleitkomma
bzw. 40 Bit Gleitkomma. Zwischen den Recheneinheiten und den Datenbussen befinden
sich die Datenregister (register file). Sie bestehen aus 16 Registern der Breite 40 Bit, in de-
nen Rechenoperanden und Ergebnisse gespeichert werden. Da alle Rechenoperationen nur
einen Prozessorzyklus benötigen, können die Ergebnisse eines Zyklus’ im darauffolgenden
Zyklus beliebig weiterverwendet werden.
Ein Register wird mit „F“ und einer Nummer 0-15 angesprochen, wenn es für Gleitkomma-
operationen verwendet wird, und mit „R“ und einer Nummer für Festkommaoperationen.
Das MR Register dient zur Speicherung eines Fixed-Point-Multiplikations Ergebnisses.

                                                                                                   15
Um einen schnellen Kontextwechsel zu ermöglichen, stehen alle Register in zweifacher
     Ausführung zur Verfügung. Die Modifikation eines entsprechenden Statusbits verursacht,
     dass alle Prozessoroperationen auf diesen „Schatten“-Registern ausgeführt werden.


     ALU

     Die ALU verfügt über eine Vielzahl arithmetischer und logischer Operationen für sowohl
     Festkomma- als auch Gleitkommadarstellungen. Für eine umfassende Liste dieser Opera-
     tionen sei auf das Handbuch verwiesen. Hier ein kleines Beispiel:

           Beispiel:
             1. Addiere den Inhalt des Registers F0 zu dem des Registers F1 und spei-
                chere das Ergebnis in F0
                F0 = F0 + F1;
              2. Nimm den Betrag von F0 und speichere das Ergebnis in F1
                 F1 = ABS F0;
              3. Nimm den maximalen Wert von R1 und R2 und speichere das Ergebnis
                 in R0
                 R0 = MAX (R1, R2);

     Alle Befehle sowie „F“ und „R“ können entweder groß oder klein geschrieben werden,
     da der Assembler Groß- und Kleinschreibung nicht unterscheidet. In dem Statusregister
     ASTAT befinden sich Flaggen, die nach dem Beenden einer ALU-Operation gesetzt wer-
     den. Z. B. wird die Flagge AZ (Bit 0) gesetzt, wenn das Ergebnis der Operation Null ist.
     Abbildung 1.7 zeigt die Bedeutung der einzelnen Bitstellen des Statusregisters ASTAT.




                            Abbildung 1.7: Aufbau des ASTAT-Registers

     Die ALU wird auch für bitbezogene Operationen wie logische AND, OR, NOR und NOT
     verwendet. Beispielsweise können mit AND einzelne Bits herausmaskiert und mit OR ein-

16
zelne Bits gesetzt werden. Außerdem kann mit XOR kontrolliert werden, in welchen Posi-
tionen sich zwei Register unterscheiden. Die logischen Operationen sind nur für Festkom-
maoperanden definiert und haben nur einen Einfluss auf die oberen 32 Bits eines Registers.
Die letzten 8 Bits werden zu Null gesetzt.




                       Abbildung 1.8: Beispiel für ALU-Operationen

Im Register MODE1 befinden sich drei Flaggen, mit denen u.a. entschieden wird, ob das
Ergebnis einer Festkommaoperation ggf. gesättigt werden soll und wie Gleitkommaresultate
gerundet werden sollen, siehe Handbuch, Abschnitt 2.5.2. Eine vollständige Beschreibung
des MODE1-Registers befindet sich im Handbuch auf den Seiten E-14 und E-15.


Multiplizierer

Mit dem Multiplizierer können Festkomma- oder Gleitkommamultiplikationen durchge-
führt werden. Das Resultat einer Festkommamultiplikation kann in einem der beiden Mul-
tiplikatorregister (MRF oder MRB) oder in einem Datenregister R0 - R15 gespeichert wer-
den. Bei Nutzung der Multiplikatorregister kann im selben Zyklus eine Addition zu oder
Subtraktion von dem letzten Inhalt des Registers vorgenommen werden.

      Beispiel:
        1. Multipliziere den Inhalt des Registers R0 mit dem von R1. Das Ergebnis
           wird zum Inhalt von MRF addiert.
           MRF = MRF + R0 · R1;

Auf diese Art und Weise kann sehr einfach eine multiply/accumulate-Operation implemen-
tiert werden.
Das Standardformat für Festkommamultiplikationen ist signed fractional. Wenn eine
andere Darstellung erwünscht ist, muss diese explizit angegeben werden. Dies erfolgt, in-
dem nach dem Befehl in Klammern die Buchstaben S oder U bzw. I oder F angefügt werden,
siehe Abschnitt 2.6.6 des Handbuches. Hierbei bezeichnen:

   • S signed
   • U unsigned
   • I integer

                                                                                            17
• F fractional

               Beide Operanden müssen entweder vom Typ integer oder fractional sein. Signed und unsi-
               gned sind mischbar.

                      Beispiel:
                        1. Die Zahlen in R1 und R2 sind beide vom Format signed fractional
                           R0 = R1 · R2; oder
                           R0 = R1 · R2 (SSF);
                         2. Die Zahlen in R1 und R2 sind beide vom Format unsigned integer
                            R0 = R1 · R2 (UUI);
                         3. Die Zahl in R1 ist unsigned fractional und die in R2 signed
                            fractional. Das Ergebnis soll abgerundet werden
                            R0 = MRF - R1 · R2(USFR);

               Eine Gleitkomma multiply/accumulate-Operation wird durch parallele Nutzung der ALU
               und des Multiplizierers durchgeführt. Dabei ist jedoch zu beachten, dass für die Addition in
               dem Beispiel der Wert in F8 zur Berechnung gewählt wird, der einen Takt zuvor bestimmt
               wurde. Weiterhin sind die zu verwendenden Register einer Begrenzung unterworfen (siehe
               hierzu auch Handbuch S. B-95).

                      Beispiel:
                        1. Berechne C := A · B + C
                           Die Werte von A, B und C liegen in F1, F2 bzw. F12.
                           F8 = F1 · F2, F12 = F8 + F12;

               Genau wie die ALU hat auch der Multiplizierer eine Wirkung auf das Statusregister. Bei-
               spielsweise kann mit dem MN-Bit im ASTAT-Register kontrolliert werden, ob das Ergebnis
               einer Multiplikation negativ ist.


               Shifter

               Der Shifter stellt die dritte Recheneinheit dar. Mit dem Shifter kann z. B. der Inhalt eines Re-
               gisters verschoben werden. Der Shifter arbeitet grundsätzlich nur in Festkommaarithmetik,
               d.h. nur mit den oberen 32 Bits eines Registers. Die letzten 8 der 40 Bits im Resultatre-
               gister werden immer zu Null gesetzt. Der Shifter hat auch eine Wirkung auf das ASTAT
               Register. Zusätzlich zu den normalen Shift-Funktionen bietet der Shifter die Möglichkeit
               zur Manipulation und zum Test einzelner Bits. Der Befehl zur Verschiebung des Inhaltes
               eines Registers heißt LSHIFT (Logic shift). Die Wirkung wird durch das folgende Beispiel
               illustriert.


1.2.4 Das Programm-Steuerwerk

               Das Programm-Steuerwerk (Program Sequencer), siehe Abbildung 1.3, steuert den Ablauf
               des Programms. Dieser ist meistens linear (sequentiell). Abweichungen von diesem linearen
               Fluss werden durch die fünf Programmstrukturen loop, jump, subroutine, interrupt
               und idle ermöglicht. Diese Strukturen sind in Abbildung 1.10 dargestellt.

18
Abbildung 1.9: Beispiel für Funktionalität des Shifters


Der Kern des Programmsteuerwerks besteht aus dem Programmzähler (Program Counter,
PC). Dieser enthält am Anfang eines Zyklus’ die Adresse des durchzuführenden Befehls
und wird während des Zyklus’ hochgezählt. Ein Sprung im Programm geschieht, indem
dem PC eine neue Adresse gegeben wird. Alle oben erwähnten Programmstrukturen beste-
hen auf die ein oder andere Weise aus Programmsprüngen. Ein Sprung erfolgt im allgemei-
nen zu einem in Assembler deklarierten „label“ (Sprungmarke).
Die Sprungmarke besteht aus einer willkürlichen, nicht reservierten Zeichenfolge gefolgt
von einem Doppelpunkt, z. B. „counter:“ oder „loop1:“. Bei Schleifen gibt die Sprungmarke
den letzten Befehl der Schleife an.
Kommentare können im Assemblerprogramm wie in C-Programmen zwischen „/*“ und
„*/“ eingebettet werden. Sie helfen später sowohl dem Programmierer als auch anderen, die
mit dem Quellencode zu tun haben, das Programm zu verstehen. Die Programmstrukturen
werden im folgenden kurz erklärt:


Loop

Eine Schleife (loop) lässt sich sehr bequem durch den loop counter (LCNTR) implementieren.
In LCNTR wird dabei zuerst die Zahl der Wiederholungen angegeben. Mit dem Befehl DO
< label > UNTIL LCE (loop counter expired) wird die Schleife ausgeführt. Das notwendige
Label < label > bezeichnet den letzten Befehl des zu iterierenden Loops.


       Beispiel:
           Zähle R0 von 0 bis 100
              R0 = 0;
              LCNTR = 100, DO counter UNTIL LCE;
       counter: R0 = R0 + 1; /* this is the last
                          instruction of the loop */


Jump

Durch einen Sprung (jump) lässt sich eine Programmverzweigung implementieren. Der
Sprung kann entweder unbedingt oder bedingt sein. Bei einem bedingten Sprung wird zu-

                                                                                             19
Abbildung 1.10: Verschiedene Programmstrukturen


     erst eine Flagge in einem Register, das u. a. vom ASTAT-Register abhängig ist, kontrolliert.
     Wenn diese Flagge eins ist, erfolgt der Programmsprung, im anderen Fall nicht.
     Unter anderem gibt es die Flaggen


                               EQ     Result equal to zero
                               NE     Result not equal to zero
                               LT     Result less than zero
                               LE     Result less than or equal to zero
                               AV     Addition overflow
                               MV     Multiplier overflow


            Beispiel:
                Wenn R0 − R1 ≤ 0, springe nach negative
                  R2 = R0 -R1;
                  IF LE JUMP negative;
            positive: ...
            negative: ...


     Mit dem JUMP-Befehl kann auch eine Schleife implementiert werden.

20
Beispiel:
                R0 = 0;
            R1 = 100;
       increase: R0 = R0 + 1;               COMP (R0,R1);
            IF NE JUMP increase;
            ...


Subroutine

Eine Subroutine kann mit einem Unterprogramm verglichen werden, zu dem jederzeit ge-
sprungen werden kann und von dem automatisch an die richtige Stelle im Hauptprogramm
wieder zurückgesprungen wird, wenn das Unterprogramm zu Ende ist. Mit dem Befehl
CALL wird der Sprung initiert und mit RTS (Return From Subroutine) wird die Subroutine
beendet. Vor dem Sprung wird die aktuelle Programmadresse auf den Stack gelegt. Durch
RTS wird sie wieder dem Programmzähler zurückgegeben. Ein CALL kann genau wie JUMP
sowohl unbedingt als auch bedingt sein.


       Beispiel:
                IF MV CALL overflow;
            ...
       overflow:
            /* multiplier overflow*/
            ...

             /* do something! */
             RTS;


Man beachte den Unterschied zwischen JUMP und CALL. Bei JUMP handelt es sich um einen
einfachen Sprung zu einer anderen Stelle im Programm, wo das Programm weiter läuft. Mit
CALL soll nur gesprungen werden, wenn durch RTS auch ein Sprung zurück gemacht wird.
Es ist wichtig, dass alle Paare CALL-RTS zusammenpassen. Wird ein Sprung durch RTS ver-
langt, ohne dass zu der Subroutine mit CALL gesprungen wurde, folgt ein Programmfehler,
weil auf dem Stack die falsche (oder gar keine) Retour-Adresse vorhanden war.


Interrupts

Interrupts stellen eine sehr flexible und effiziente Lösung für das Handhaben von Ereignis-
sen dar und müssen von jedem Assembler-Programmierer beherrscht werden. Ein Interrupt
ist ein Ereignis, das einen Sprung zu einer vordefinierten Adresse auslöst. Das Ereignis kann
entweder intern im Prozessor auftreten (z. B. ein ALU-Overflow) oder extern (z. B. wenn ein
neuer Abtastwert vorliegt). Der ADSP-21369 hat vier externe Hardware-Interrupts, inklusi-
ve eines speziellen Reset-Interrupts, und eine Vielzahl interner Interrupts, siehe Abbildung
1.11.
Für die Programmsteuerung bei Interrupts gibt es die Interruptvektortabelle, vergleiche den
beispielhaften Programmablauf in Abbildung 1.12.
Beim Auslösen eines Interrupts wird zu der dem Interrupttyp entsprechenden Adresse ge-
sprungen (Schritt 1). Im allgemeinen enthält diese Adresse den Befehl JUMP, so dass das

                                                                                               21
Interrupt Vector Table ADSP-21369

                                                         Emulator (read-only,      HIGH PRIORITY
                     0x90000 +   0x00      0     EMUI
                                                         non-maskable)

                                                         Reset (read-only
                                                 RSTI
                                 0x04      1
                                                         non-maskable)

                                                         Illegal input condition
                                            2    IICDI
                                 0x08                    detected
                                                         Status loop or mode
                                 0x0C      3             stack overflow; or PC
                                                SOVFI
                                                         stack full
                                                         Timer=0 (high
                                 0x10      4    TMZHI
                                                         priority option)

                                                SPERRI
                                 0x14                    SP error interrupt
                                           5

                                                         Hardware breakpoint
                                                BKPI
                                 0x18      6
                                                         interrupt


                                 0x1C      7              Reserved

                                 0x20      8    IRQ2I    IRQ2I asserted


                                 0x24      9    IRQ1I    IRQ1I asserted

                                 0x28      10   IRQ0I    IRQ0I asserted
                                  ...     ...     ...           ...

                                                         User Software
                                 0x98      28   SFT0I
                                                         Interrupt 0

                                                         User Software
                                 0x9C      29   SFT1I
                                                         Interrupt 1
                                                         User Software
                                 0xA0      30   SFT2I
                                                         Interrupt 2

                                                         User Software
                                 0xA4      31   SFT3I                               LOW PRIORITY
                                                         Interrupt 3



                           Abbildung 1.11: Inhalt der Interrupt-Vector-Tabelle


     Programm mit einer Interrupt-Subroutine fortfahren kann (Schritt 2). Am Ende der Interrupt-
     Subroutine wird mit RTI (Return From Interrupt) zu der Adresse im Programm zurückge-
     sprungen, die der Programmzähler enthielt, als der Interrupt ausgelöst wurde (Schritt 3).
     Bei einem externen Interrupt wird zuerst der Inhalt des ASTAT-Registers und des MODE1-
     Registers sowie die Adresse des Programmzählers (PC) vor dem Sprung auf den Stack ge-
     legt. Durch RTI werden diese Registerwerte vom Stack zurückgenommen. Für externe Inter-
     rupts und für den Timer-Interrupt ist eine Verschachtelungstiefe (nesting) von vier möglich.
     Folgendes Beispiel erläutert die Verwendung von Timer-Interrupts:


            Beispiel:
              1. Es soll ein Timer-Interrupt jede 1ms ausgelöst werden. 1ms entspricht
                 6000010 = EA6016 Zyklen bei 60 MHz, vergleiche Abschnitt 11
                 des Handbuches (zu beachten: Der Prozessor verfügt über zwei völlig
                 gleichwertige Timer-Sektionen 0 und 1)
                       /* timer interrupt address (high Prio timer IRQ)*/
                 .SEGMENT/PM pm_tmzhi;
                         JUMP timer_interrupt;
                 .ENDSEG;
                       ...

22
Abbildung 1.12: Programmablauf beim Auslösen des Interrupts IRQ1


                /* global interrupt disable*/
                 BIT CLR MODE1 IRPTEN;
                /* Timer disable and setup first*/
                 BIT CLR MODE2 TIMEN0; /* stop timer */
                 BIT SET MODE2 PWMOUT0; /* set PWMOUT modus */
                 TPERIOD0 = 0xEA5F; /* 60000 - 1 */
                /* timer interrupt enable*/
                 BIT SET IMASK TMZHI;
                /* start timer (set counter to 0)*/
                 BIT SET MODE2 TIMEN0;
                /* global interrupt enable*/
                 BIT SET MODE1 IRPTEN;
                ...
           timer_interrupt: ...
                /* Process timer-interrupt service*/
                RTI;

Beim Start oder Reset eines Programms startet der Prozessor immer bei der Adresse des
Reset-Interrupts. Diese ist für den ADSP-21369 gleich 0x90005. Dementsprechend muss
an dieser Speicherstelle ein Sprung zum Programmanfang vorhanden sein. Dies kann durch
den folgenden Programmcode erreicht werden.


                                                                                         23
Beispiel:
                              /* reset interrupt address */
                      .SEGMENT/PM pm_rti;
                          JUMP prog_start;
                      .ENDSEG;
                      ...

                              /* the program begins here */
                      prog_start: ...


               Idle

               Mit dem Befehl IDLE wird der Prozessor angehalten bis ein externer Interrupt oder ein
               Timer-Interrupt auftritt. Im Gegensatz zu einer endlosen Warteschleife, die mit dem Be-
               fehl JUMP implementiert werden kann, wird mit IDLE der Prozessor in einen „low-power“-
               Zustand versetzt. Nach dem Rücksprung aus der Interrupt-Subroutine wird die Programma-
               barbeitung mit dem Befehl fortgesetzt, der IDLE folgt.


1.2.5 Datenadressierung

               Für die Berechnung von Adressen im Programm- und Datenspeicher stehen zwei Daten-
               adressrechner (data address generators, DAG) zur Verfügung. Mit diesen wird eine indirekte
               Adressierung ermöglicht, d.h. anstatt die tatsächliche Speicherstelle im Programm anzuge-
               ben, wird sie durch den DAG berechnet.
               In jedem der zwei DAG gibt es acht Adressregister, die I-Register oder Index-Register ge-
               nannt werden. Der DAG1, der Adressen für den Datenspeicher (DM) (siehe Abschnitt 4.2.6)
               berechnet, enthält die Register I0 bis I7, während der DAG2, der Adressen für den Pro-
               grammspeicher (PM) berechnet, über die Register I8 bis I15 verfügt.
               Die Zuordnung der Adressierungs-Register zu Programm-/Datenspeicher ist durch die Tat-
               sache bedingt, dass der Programm-Speicher Adressbus nur 24 Bit breit ist. Somit sind auch
               alle Register der zweiten Adressierungslogik nur 24 Bit breit.
               Mit den zugehörigen Modify-Registern (M0-M7 für DAG1 bzw. M8-M15 für DAG2) kann eine
               Adresse vor oder nach dem Speicherzugriff hoch- oder runtergezählt (inkrementiert bzw.
               dekrementiert) werden. Hierdurch wird u.a. eine laufende Abspeicherung oder ein laufen-
               des Auslesen von Daten ermöglicht, ohne dass dem Index-Register manuell ein neuer Wert
               gegeben werden muss. Die Adressrechner werden mit den Befehlen DM bzw. PM angespro-
               chen. Diese Befehle haben zwei Argumente: ein I-Register bzw. ein M-Register oder einen
               konstanten Modify-Wert. Bei post-modify Adressierung erfolgt erst der Speicherzugriff und
               dann die Berechnung des neuen Inhalts vom I-Register. Die Syntax lautet dann DM (Ia,
               Mb) oder PM (Ic, Md), wobei a und b Zahlen zwischen 0 und 7 und c bzw. d Zahlen zwi-
               schen 8 und 15 sind. Bei pre-modify wird die neue Adresse berechnet bevor der Zugriff
               erfolgt. Hierfür wird die Syntax DM(Ma, Ib) oder PM(Mc, Id) verwendet.




24
Beispiel:
        1. Lade in R6 den Inhalt der Speicherstelle 0x0000C000 des Datenspei-
           chers.
                  R6 = DM(0x0000C000);
           oder
                  I0 = 0x0000C000;
                  R6 = DM (I0, 0);

         2. Lade in R6 den Inhalt der DM-Speicherstelle, die in I5 vorgegeben ist,
            und zähle danach die Adresse in I5 um 2 hoch
                  R6 = DM (I5, 2);
         3. Addiere die Adresse in I8 mit dem Wert in M10, und speichere danach
            den Inhalt von R0 an der neu berechneten PM-Adresse (M10 kann negativ
            sein)
                   PM (M10, I8) = R0;

      Beispiel:
        1. Berechne die Summe N der Elemente in den Speicherstellen DM(I0)
           bis DM(I0+N-1), für N=10.

            #define N 10 /* number of elements */

                    F0=DM (I0,1);
                    F1=DM(I0,1);
                    LCNTR = N-1, DO endloop UNTIL LCE;

                 /* result in F0 */
            endloop: F0 = F0 +F1, F1 = DM (I0, 1);

            Ablauf der Schleife: in DM(I0) bis DM(I0+N-1) sind die Zahlen
            a0 ... aN−1 vorhanden.
                 Iteration    LCNTR     F0        F1
             Initialisierung    N-1         a0          a1
                  i=1           N-2       a0 +a1        a2
                   ...
                                           N−2
                i = N-2          1         m=0 ak     aN−1
                                           N−1
                i = N-1          0         m=0 ak   undefiniert


Zyklische Daten-Puffer

Zyklische Daten-Puffer werden für effiziente Implementierungen von Filtern, Verzögerungs-
gliedern und anderen, in der digitalen Signalverarbeitung häufig vorkommenden Struktu-
ren eingesetzt. Die Implementierung zyklischer Daten-Puffer, sog. Ringspeicher (circular
buffer), wird durch Modulo-Adressierung erheblich erleichtert. Hierfür werden die base-
Register (B) und die length-Register (L) verwendet. Ein B-Register enthält dabei die Basi-
sadresse eines Ringspeichers und L die Anzahl der Elemente (die Länge). Das Register L0
und das Register M0 gehören immer zusammen, usw..

                                                                                             25
Abbildung 1.13: Beispiel eines zyklischen Puffers


     Nach Initialisierung der B und L-Register wird zuerst die Basisadresse dem entsprechenden
     I-Register automatisch übergeben. Bei einer post-modify Modifizierung des I-Registers (ei-
     ne pre-modify Modifizierung ist bei zyklischen Puffern nicht erlaubt) wird kontrolliert, ob
     die neue Adresse innerhalb des Bereichs zwischen B und B+L-1 liegt. Wenn dies der Fall
     ist, wird die neue Adresse behalten. Wenn sie zu groß ist, wird die Länge L subtrahiert, und
     dementsprechend wird L addiert, wenn sie kleiner als B ist. Dadurch ergibt sich immer die
     neue Adresse durch den Zusammenhang

           Ia := Ba + (Ia + Mb − Ba) mod La                                                 (1.7)

     a und b können verschiedene Zahlen aus den Bereichen 0-7 oder 8-15 sein (DM bzw PM).
     Es ist notwendig, dass |Mb| < La. Wie die Register der ALU stehen auch die Register
     der Adressierungslogik doppelt zur Verfügung, um einen schnellen Kontext Wechsel zu
     ermöglichen.

            Beispiel:
              1. Es soll ein Verzögerungsglied implementiert werden. Die Verzögerung
                 beträgt 20 Abtastwerte. Der Eingangswert ist beim Aufruf der Subrou-
                 tine delay_20 (wird mit call aufgerufen) in DM(I6) vorhanden und der
                 (verzögerte) Ausgangswert soll in DM(I7) geschrieben werden.
                        /* base address*/
                         B0 = 0x0C200;

                         /* length 2010 = 1416 */
                         L0 = 0x14;
                         ...

                       /* read oldest data from buffer */
                 delay_20: F0 = DM(I0,0):




26
/* write output data */
                   DM(I7, 0) = F0;

                  /* read input data */
                   F0 = DM (I6, 0);

                  /* put data in circular buffer,
                   * address is increased by one*/
                   DM(I0, 1) = F0;       RTS;


                                                                                           1.2.6 Speicher

Der Programm- und Datenspeicher

Der im Praktikum eingesetzte Prozessor ADSP-21369 hat 2 MB on-chip und 4 Mega Wort
externen Speicher, der grob in zwei Kategorien aufgeteilt wird: der Programmspeicher (PM
- Program Memory) und der Datenspeicher (DM - Data Memory). Die Wortbreite 32 Bit
wird für Fest- und Gleitkommadaten verwendet. Es können auch 48-Bit Wörter definiert
werden, die entweder Befehle oder 40-Bit Gleitkommadaten enthalten. Schließlich steht
auch ein 16-Bit Format für Festkommadaten zur Verfügung.
Die Aufteilung des gesamten Speichers in Segmente kann weiterhin für jede Anwendung
spezifisch bestimmt werden. Hierfür wird ein sogenanntes Link-Description-File (LDF)
angegeben, in dem Symbolen (Namen) physikalische Adressen zugeordnet werden.

   • Im Adressraum sind die internen Speicherbereiche in Blöcke aufgeteilt, weiterhin
     gibt es jeweils einen Normal-Word- und einen Short-Word-Bereich. Die vorgegebe-
     nen Adress-Grenzen müssen dementsprechend auch im Link-Description-File einge-
     halten werden, für eine genaue Zuordnung der Blöcke zu den Adressen sei auf das
     Handbuch verwiesen.
   • Der externe Speicher ist ebenfalls im Adressraum des ADSP 21369 vorgesehen, der
     schliesslich verwendete Adressbereich ist schaltungstechnisch bedingt von Adresse
     0x00200000 bis 0x08FF0000 anzusprechen, näheres hierzu kann der Beschreibung
     der EZKIT-Hardware entnommen werden. Auf dieselbe Art und Weise sind auch die
     Steuerungs- und Datenregister der anderen Peripherien (z. B. UART ADM3202) Teil
     des Adressraums (siehe wiederum Manual zu EZKIT).

Im PM können sowohl Programmbefehle als auch Daten gespeichert werden. Im Datenspei-
cher (DM) können ausschließlich Daten gespeichert werden. In sowohl PM als auch DM kön-
nen auch Wörter anderer Breiten verwendet werden. In diesem Fall ändert sich die Adres-
sierung, siehe auch hierzu Kapitel „External Memory Interface“ im Handbuch.
Instruktionen müssen über den 32 Bit breiten Programmspeicher Adressbus angefordert
werden, weshalb diese sich nur in den entsprechenden Teilen des Speichers befinden kön-
nen.


Die PM/DM-Datenbusse

Über die PM und DM Datenbusse (PMD bzw. DMD ) werden die Befehle und Daten zwischen
dem Speicher und den verschiedenen Einheiten des Prozessors verschoben. Wie im PM so-

                                                                                                      27
wohl Befehle als auch Daten gespeichert werden können, so kann der PM Datenbus Befehle
                   zum Programmrechenwerk oder auch Daten zu z. B. den Registern transportieren, jedoch
                   nicht gleichzeitig. Der parallele Datenbus ermöglicht zwei gleichzeitige Speicherzugriffe.
                   So kann im selben Zyklus sowohl ein neuer Befehl vom PM als auch ein Wert vom DM gelesen
                   werden. Hierbei wird die Adresse im PM vom Programmsteuerwerk über den PM Adressbus
                   (PMA) und die Adresse im DM über den DM Adressbus (DMA) vermittelt.
                   Alternativ können, wenn der auszuführende Befehl schon im Cache-Speicher vorhanden
                   ist, beide Datenbusse für den Transport von Daten verwendet werden. Vom PM und DM kann
                   dann jeweils ein Wert einem Register übergeben werden - alles innerhalb eines Zyklus’.
                   Dieses Verfahren wird dual data access genannt. Um dieses zu ermöglichen, empfiehlt es
                   sich immer, die zu verarbeitenden Daten zu trennen (z. B. Filterkoeffizienten im Programm-
                   speicher und Abtastwerte im Datenspeicher). Weiter muss der Befehl in der Form


                                   compute, DM read or write, PM read or write;


                   sein, zum Beispiel


                                        R0=R0+R1, DM(I1, M1)=R0, R1=PM(I8, M8);


                   Wenn der Befehl nicht im Cache-Speicher liegt, werden zusätzliche Zyklen benötigt.



1.3 Entwicklungsumgebung: Visual DSP++

1.3.1 Einführung

                   Im Laufe der letzten Jahre wurde die Hardware im Bereich Prozessoren immer weiter ent-
                   wickelt. Die heutigen Architekturen sind im allgemeinen sehr leistungsstark, und die Wahl
                   eines DSPs für einen Algorithmus wird somit auch von Faktoren jenseits der Performance
                   mitbestimmt. Zu diesen anderen Faktoren zählt insbesondere die zur Verfügung stehende
                   Software. Die „Time to market“, also der Zeitrahmen, dessen es bedarf, ein Produkt auf
                   den Markt zu bringen, kann durch guten Software-Support drastisch verkürzt werden. C-
                   Compiler gehören hierbei zum Standard.
                   Analog Devices liefert zu den Sharc-DSPs die Software Visual DSP++. In Anlehnung
                   an die Entwicklungsumgebung Visual Studio unter Windows können Algorithmen hiermit
                   schneller implementiert werden.
                   Im Folgenden soll eine kurze Einführung in die Umgebung Visual DSP++ gegeben werden:
                   Das Software-Entwicklungspaket von Analog Devices ist eine IDE (Integrated Develop-
                   ment Environment). Dazu gehören Tools zur Erstellung der Software (z. B. Editor) sowie
                   welche zur Verifikation des erstellten Software (z. B. Debugger).
                   Da die Release von Visual DSP++, die im Praktikum verwendet wird, regelmässig auf den
                   neusten Stand gebracht wird, können sich zu den im folgenden präsentierten Bildern unter
                   Umständen leichte Abweichungen ergeben.

28
Abbildung 1.14: Aufruf der Entwicklungsumgebung Visual DSP++




                                                             1.3.2 Implementierung des Source-Codes

Für die Entwicklung eines Algorithmus’ unter Visual DSP++ sowie unter allen Visual-
Umgebungen ist der Begriff Projekt von großer Bedeutung:
Ein Projekt umfasst die Gesamtheit aller zu der Implementation einer Anwendung gehö-
rigen Module. Ein Modul kann zum Beispiel eine Text-Datei sein, in der Code in einer
Programmiersprache gespeichert ist, oder eine vorkompilierte Bibliothek, auf deren Metho-
den zugegriffen wird. Die Module eines Projektes werden gegebenenfalls kompiliert und
gelinkt. Sie bilden somit die Basis für einen ausführbaren Algorithmus. Im einfachsten Fall
besteht ein Projekt aus einer Datei, die den gesamten Source-Code enthält.




Starten der Entwicklungsumgebung


Die Entwicklungsumgebung Visual DSP++ wird wie unter Windows üblich aus dem Start-
Menü gestartet (siehe Abbildung 1.14).
Die Bedienung gestaltet sich wie in den meisten Fällen sehr intuitiv. Sollte in einer vorher-
gehenden Sitzung ein Projekt bearbeitet worden sein, so erscheint dieses Projekt direkt zu
Beginn. Es können Unterfenster für das Projekt selbst (A), aber auch für Quellcode (B) bzw.
Prozessor-Zustände (z. B. Disassembly(C)) angezeigt werden (siehe Abbildung 1.15).
Im Projekt-Fenster wird angezeigt, welche Dateien alle Teil des Projekts sind. Sollte hier
noch kein Projekt angezeigt werden, so muss erst eins angelegt werden bzw. ein vorhande-
nes eingeladen werden.

                                                                                                 29
A

                                                                                 C
                                                          B




                           Abbildung 1.15: Fenster nach Programmstart


     Menüpunkte

     In Abbildung 1.15 ist zu erkennen, welche Menüpunkte es bei Visual DSP++ gibt. Die
     wichtigen Unterpunkte werden im folgenden kurz aufgelistet:

        • Menüpunkt File:
          In diesem Menüpunkt können Dateien geladen oder gespeichert werden. Dabei wer-
          den Projekte und Textdateien im gleichen Dialog ausgewählt. Desweiteren kann auf
          den DSP ein ganzes Programm bzw. in den Debugger die Symboltabelle eines Pro-
          gramms geladen werden (Unterpunkte Load ...).
          Für einen beschleunigten Zugriff stehen Links zu kürzlich geöffneten Projekten usw.
          bereit (Unterpunkte Recent ...).

        • Menüpunkt Edit:
          In diesem Menüpunkt kann Text editiert werden. Dabei stehen die üblichen Opera-
          tionen wie Copy/Paste zur Verfügung.

        • Menüpunkt Session:
          In diesem Menüpunkt kann die aktuelle Session gewählt werden. Im Falle des Prak-
          tikums dient dies insbesondere der Wahl zwischen der Emulation mithilfe des JTAG-
          Interfaces (V3+Projektphase) und der Simulation (V1+V2). Andere Sessions werden
          im Rahmen dieses Praktikums nicht verwendet.

        • Menüpunkt View:
          In diesem Menüpunkt können Fenster angezeigt bzw. nicht angezeigt werden. Ins-
          besondere kann wie in Abbildung 1.19 angedeutet (Plot) auch ein Speicherbereich
          grafisch ausgegeben werden.

30
Abbildung 1.16: File-Dialog


• Menüpunkt Projekt:
  In diesem Menüpunkt können Projekt spezifische Operationen vorgenommen wer-
  den. Abbildung 1.20 veranschaulicht die Möglichkeiten, die wichtigsten Funktionen
  im einzelnen:

     – Add to Project:
       Hiermit können einem Projekt Module hinzugefügt werden.
     – Build File:
       Hiermit können einzelne Module kompiliert werden.
     – Build Project:
       Hiermit werden alle Module eines Projekts kompiliert (sofern notwendig) und
       zusammengelinkt.
     – Rebuild all:
       Hiermit werden sämtliche Projekte wie unter Menüpunkt Build Project bearbei-
       tet, die momentan geöffnet sind.
     – Project Options:
       Compile- und Link-Options können hier spezifiziert werden.

• Menüpunkt Register:
  Dieser Menüpunkt dient dem Debuggen eines gerade auf dem DSP ablaufenden Pro-
  gramms. Es können hier Register des DSPs zur Anzeige ausgewählt werden. Für eine
  Benutzung im Rahmen des Praktikums ist insbesondere die Anzeige der inaktiven
  Register wichtig (Inactive Registers).

• Menüpunkt Memory:
  In diesem Menüpunkt können Speicherbereiche angezeigt werden. Die Daten an den

                                                                                      31
Abbildung 1.17: Edit-Dialog


           entsprechenden Speicherstellen können in verschiedenem Format dargestellt werden.
           In den meisten Fällen ist eine Darstellung im Format Two Column sinnvoll. Mit dem
           Befehl Dump können ganze Speicherbereiche auch direkt in einer Datei gespeichert
           werden. Dies ist nützlich, um Rechenergebnisse zum Beispiel mit Matlab zu verifi-
           zieren.
        • Menüpunkt Debug:
          Im Menüpunkt Debug kann der Debugger gestartet und kontrolliert werden.
        • Menüpunkt Settings:
          In diesem Menüpunkt können Einstellungen vorgenommen werden. Insbesondere
          können hier Breakpoints aufgelistet und Interrupts simuliert werden (siehe V1).


     Vorgehensweise bei der Erzeugung von Objekt-Codes (DSP Executable)

     Im Laufe der Versuche dieses Praktikums und in der anschließenden Projektphase soll das
     Rahmenprogramm erweitert und auf die Applikation angepasst werden. Hierzu sollen dem
     Projekt Module hinzugefügt werden. Nachdem dies geschehen ist, werden alle Module er-
     neut zusammengelinkt. Dabei werden eventuell aufgetretene Fehler im Ausgabefenster an-
     gezeigt. Sofern die Anwendung komplett erzeugt wurde, wird das auszuführende Programm
     direkt in den Programmspeicher des DSP geladen. Der Prozessor hält direkt an und erwartet
     weitere Instruktionen.


     Ausführen des Programms

     Zur weiteren Ausführung des geladenen Sourcecodes wird F5 gedrückt. Alle Anzeige-
     Fenster werden zu diesem Zeitpunkt deaktiviert. Sofern ein zuvor eingestellter Breakpoint

32
Abbildung 1.18: Session-Dialog


erreicht wird, hält die Ausfühung an, und alle Ausgabefenster werden aktualisiert. Mit
SHIFT-F5 kann der Prozessor auch zu jedem anderen Zeitpunkt angehalten werden.


Setzen von Breakpoints

Mit F9 kann an der Stelle der aktuellen Eingabeposition ein Breakpoint gesetzt werden.
Dies ist jedoch nur möglich, wenn der Prozessor gerade nicht im laufenden Zustand ist.


Ausführung Instruktion für Instruktion

Wenn der Prozessor angehalten wurde, sei es aufgrund von Breakpoints oder manuell, kann
mit F11 der Programmcode Schritt für Schritt abgearbeitet werden (sog. durchsteppen).
Zu bedenken ist jedoch, dass auch im angehaltenen Modus Interrupts ausgelöst werden
können. Aus diesem Grunde springt der Prozessor zumeist beim Durchgehen Instruktion
für Instruktion in die nächste Interrupt Service Routine höherer Ordnung.


Vorgehen beim Debuggen

Ein DSP-Object-Code wird wie beschrieben eingeladen. Daraufhin kann der Code gedebug-
ged werden. Zumeist wird nur ein Teilaspekt untersucht, der in einer Unterfunktion imple-
mentiert wurde. Um den zugehörigen Source-Code anzuzeigen, muss der Program-Counter
(PC) auf einer Stelle stehen, die zu der zu untersuchenden Funktion gehört.
Nach Programmstart muss hierfür der Disassembly-Output nach einem Symbol in der Funk-
tion ( z. B. Funktionsname ) durchsucht werden. Dies geschieht durch Betätigung der rech-
ten Maustaste sowie Aufruf der Goto-Funktionalität. Die Aktivierung von Browse führt zu

                                                                                            33
Abbildung 1.19: View-Dialog


                   einer Auflistung aller existierenden Symbole. Nach Auffinden des Symbols wird ein Break-
                   point gesetzt. Nun wird der Programmcode bis zum Breakpoint ausgeführt (Run, F5).



1.4 Versuchsdurchführung

1.4.1 Einführung

                   Die nun folgenden Programmbeispiele sollen schrittweise in die Programmierung des ADSP-
                   21369 einführen. Beachten Sie bitte, dass die ersten zwei Programme im Simulator-Modus
                   ausgeführt werden und erst das dritte Beispiel auf dem DSP emuliert wird. Ziel der hier
                   durchgeführten ersten beiden Versuche ist das Erlernen und Verstehen von Prinzipien Hard-
                   ware-naher Programmierung and der Funktionsweise des DSPs auf Assembler-Programm-
                   Ebene. Der dritte Versuch dient der Einarbeitung in die vorgegebene Software RTProcDSP.
                   Da dieses Programm in C/C++ programmiert wurde, geschieht von diesem Zeitpunkt an
                   auch die Programmierung der Algorithmen in C/C++. Es sei jedoch darauf verwiesen, das
                   es im Verlauf des Projekts notwendig sein kann, Fragmente der Programme in Assembler
                   zu realisieren, um die Ausführungsgeschwindigkeit des DSPs zu erhöhen. Für die Spezifi-
                   kation der Schnittstelle zwischen C/C++ und Assembler sei auf die Anleitung in der DSP
                   Literatur „C/C++ Compiler and Library Manual for Sharc Processors“ verwiesen.

                      • Im Programm 1 werden Daten interruptgesteuert ein- und ausgelesen. Die von ei-
                        ner Datei in einen Ringspeicher eingelesenen Werte können in einer Interruptroutine
                        modifiziert werden und anschließend in einen Speicherbereich ausgegeben werden.
                        Hierbei behandeln wir auch den Aufbau von Ringspeichern mit Hilfe der Modulo-
                        Adressierung.

34
Abbildung 1.20: Project-Dialog


   • Das Programm 2 zeigt die Anwendung von Befehlen für die parallele Verarbeitung
     von Multiplikations- und Additionsbefehlen anhand eines Tiefpass-Filters.

   • Zum Schluss wird das Programm RTProcDSP vorgestellt. Da es im folgenden die
     Grundlage zur Umsetzung der Projekte bildet, werden alle funktionalen Merkmale
     an kleinen Übungsbeispielen verdeutlicht.


                                               1.4.2 Programm 1: Interruptgesteuerte Ein-/Ausgabe

Der Sinn dieses Programms besteht darin, einen schnellen Einstieg in die Assemblerpro-
grammierung zu geben, insbesondere sollen zyklische Datenspeicher und die Programm-
steuerung durch Interrupts dargestellt werden.
Unter einem Interrupt (engl. für Unterbrechung) versteht man eine von dem Prozessor ge-
steuerte Unterbrechung des sequentiellen Programmablaufs. Stellen wir uns den sequenti-
ellen Programmablauf so vor, dass ein Ablaufzeiger (oder auch Program Counter) nachein-
ander die Speicherstellen anzeigt, die das Programm abarbeiten soll, dann ist ein Interrupt
eine Unterbrechung, in der der Zeiger auf eine vorher vereinbarte Speicherstelle „umge-
bogen“ wird. An dieser Stelle kann dann auch ein Verweis auf ein Unterprogramm stehen
oder direkt ein kurzes Unterprogramm vorhanden sein, das bearbeitet wird. Nach dem Ende
dieses Unterprogrammes wird der Programmcode wieder an alter Stelle aufgenommen und
weiter sequentiell bearbeitet.
Starten Sie das VisualDSP++ Environment und wählen Sie zunächst eine Session zur Pro-
zessor-Simulation aus (sollte so eine Session auf Ihrem Rechner noch nicht vorhanden sein,
kontaktieren Sie den Betreuer). Laden Sie anschliessend das Projekt V1. Um das Programm
auf dem DSP auszuführen, müssen Sie zunächst alle Dateien kompilieren und linken (Pro-

                                                                                              35
Abbildung 1.21: Register-Dialog


     ject → Build Project oder F7) und dann die Programmausführung beginnen (Debug → Run
     oder F5). Die Ausführung des Programms bleibt nun zu Beginn der _main-Routine an ei-
     nem Breakpoint stehen. Von hier aus können alle Schritte des Programms durch F11 einzeln
     ausgeführt werden.


     Programmcode von Projekt 1

     Das vorliegende Programmbeispiel V1.asm aus dem Projekt V1 liest interruptgesteuert einen
     Wert aus dem mit input angegebenen Speicherbereich in ein Register. Anschliessend wird
     dieser Wert an den mit output bezeichneten Speicherplatz weitergegeben. Es ist als ein Pro-
     grammierbeispiel anzusehen und soll später gemäß der Aufgabenstellung modifiziert wer-
     den. Es ist sinnvoll, den Programmcode parallel zu dieser Beschreibung zu lesen.
     Der physikalische Speicherplatz wird durch ein sogenanntes Link-Description-File (LDF)
     in logische Segmente aufgeteilt. Durch den Linker werden die Symbole (z. B. Namen von
     Variablen) im Programmcode mit den physikalischen Speicheradressen verbunden, wobei
     das LDF dafür die Regeln spezifiziert (in „Linker & Utilities Manual for ADSP-21xxx
     Family DSPs“ wird dieser Vorgang illustriert). Den verschiedenen Segmenten werden wei-
     terhin unterschiedliche Bedeutungen als Program- oder Datamemory zugewiesen. Zur Ver-
     anschaulichung hier nun der Auszug aus dem verwendeten Link-Description-File V1.ldf:




36
Abbildung 1.22: Debug-Dialog



ARCHITECTURE(ADSP-21369)
MEMORY
{
  seg_rth { TYPE(PM RAM) START(0x00090000) END(0x000900ff) WIDTH(48) }
  seg_pmco { TYPE(PM RAM) START(0x000902D0) END(0x000903FF) WIDTH(48) }
  seg_pm64 { TYPE(PM RAM) START(0x0004c6c0) END(0x0004dfff) WIDTH(64)          }
  seg_dm64 { TYPE(DM RAM) START(0x0005d800) END(0x0005d81f) WIDTH(64)          }
  seg_pm40 { TYPE(PM RAM) START(0x00090400) END(0x000904ff) WIDTH(48) }
  seg_dm40 { TYPE(DM RAM) START(0x000b0000) END(0x000b01ff) WIDTH(48) }
  seg_pm32 { TYPE(PM RAM) START(0x00098c00) END(0x00098cff) WIDTH(32)}
  seg_dm32 { TYPE(DM RAM) START(0x000b8400) END(0x000bafff) WIDTH(32)          }
}


Das LDF wird bearbeitet, indem mit der rechten Maustaste auf die Datei geklickt wird, um
dort dann die Option Open with Source Window zu wählen. Die symbolischen Namen der
Segmente im LDF, zum Beispiel seg_dm32, werden im Quellcode von V1.asm wiederver-
wendet, um dort Variablen einem bestimmten Speicherbereich zuzuordnen.
Eine besondere Rolle spielt das Segment seg_rth, in dem der Programmcode des Interrupt-
Vector-Tables abgelegt wird. Zugehörig findet man das Assembler-Programm in der Datei
21369_IVT.asm. Im folgenden soll nicht weiter auf das Link-Description-File eingegangen
werden, da dieses in der Regel unverändert übernommen werden kann.
Die beiden Assembler Programmcode-Dateien 21369_IVT.asm und V1.asm werden nun
einzeln erläutert. In der Datei 21369_IVT.asm werden die Instruktionen im Interrupt-Vector-
Table spezifiziert. Der Programmcode ist eine Eins-zu-Eins-Abbildung der Tabelle in Ab-
bildung 1.11. Insbesondere wird hier das auszuführende Programm angesprungen, sobald
ein Reset-Interrupt ausgelöst wurde (Zeile 15). Um eine Interrupt gesteuerte Eingabe zu
ermöglichen, ist weiterhin eine jump-Instruktion an der Position von IRQ0, Zeile 69, einge-

                                                                                              37
Abbildung 1.23: Settings-Dialog


     fügt. Diese dient dem Aufruf der Funktion _convolution bei jedem Eintritt der Interrupt-
     Ereignisses.
     In der Datei V1.asm wird der tatsächliche Programmcode der _main- Funktion sowie der
     Interrupt-Service-Routine _convolution aufgelistet. Bei Programmausführung dient die
     _main-Funktion der Initialisierung. In dieser Funktion werden die Adress-Generatoren so
     eingestellt, dass anschliessend die Einlese-Operation erfolgreich verläuft. Am Ende der
     _main-Routine versetzt sich der Prozessor in den idle-Modus, um Energy zu sparen (Zeile
     53).


     Aufgaben

        • Öffnen Sie die Datei V1.ldf im Source Window. Lokalisieren Sie die Speicher-
          Segmente und identifizieren sie die verwendeten Segmente in den beiden Programm-
          codedateien. An welcher Adresse liegt die Variable output?
        • Starten Sie die Programmausführung. Diese hält am ersten Breakpoint sofort wieder
          an. Das Programm und alle Variablen wurden zu diesem Zeitpunkt bereits in den
          Speicher geladen. Öffnen Sie die folgenden Fenster zur Betrachtung
             –   des Disassembly-Outputs und des zugehörigen Programmcodes.
             –   des relevanten Adress-Generators (DAG).
             –   des Datenspeichers
             –   der Interrupt-Register.
           Plotten Sie das Signal, das im Speicher zur Variable input gespeichert ist. Wählen
           Sie dafür die Option View → Debug Windows → Plot → New. Wählen sie den dar-
           zustellenden Speicherbereich mithilfe der Browse-Funktionalität aus. Beachten Sie,

38
dass sie das Zahlenformat (Float) und die Länge richtig einstellen. Verfizieren Sie
     die Richtigkeit der Darstellung anhand der Zahlenwerte, die sie durch Darstellung
     des Speichers (Memory → Two Column) ablesen können.

  • Führen Sie das Programm nun Schritt für Schritt bis zum Erreichen der IDLE-Instruktion
    aus (durchsteppen), indem Sie die Taste F11 bedienen. Beobachten Sie die Initia-
    lisierung der Interruptregister und der für die Verwaltung des zirkulären Speichers
    notwendigen Register. Was bedeuten die Kürzel A,D,P,F und der gelbe Pfeil?

  • Nach der Initialisierung kann das Programm mit F5 (Run) ausgeführt werden. Da wir
    uns im Simulations-Modus befinden kann ein auftretender externer Interrupt nur si-
    muliert werden. Dies geschieht durch Auswahl von Settings → Interrupts . Wählen
    Sie den Interrupt IRQ0 und eine sinnvolle Eistellung für die Interrupt-Periode, sowie
    die verbleibenden Einstellmöglichkeiten. Was bedeuten die einzelnen Parameter? Be-
    achten Sie, dass die Aktivierung des Interrupts durch Hinzufügen (ADD) geschieht.

  • Bevor Sie nun die Ausführung mit F5 weiterlaufen lassen, muss ein Breakpoint an
    der ensprechende Stelle im Interrupt Vector Table eingefügt werden. Überlegen Sie,
    an welcher Stelle dieses sinnvoll ist

  • Verändern Sie das Programm in der Interruptroutine, indem Sie den Befehl R0 = ABS
    R0; benutzen, um den Betrag des Eingangssignals am Ausgang zu erhalten. Erklären
    Sie das (unerwartete) Ergebnis.

  • Für die Experten: In der Vorgabe ist ein Speicher-Zugriffsfehler. Können Sie diesen
    identifizeren und wenn ja, wie ist er zu beheben?

Programmcode 21369_IVT.asm

// 21369 Interrupt Vector Table
//
.extern _main;
.extern _convolution;

.section/pm seg_rth;


__EMUI:           // 0x00: Emulator interrupt (highest priority, read-only, non-maskable)
           nop;
           nop;
           nop;
           nop;
__RSTI:          // 0x04: Reset (read-only, non-maskable)
         nop;    // <-- (this line is not executed)
         jump _main;
         nop;
         nop;
__IICDI:         // 0x08: Illegal Input Condition Detected
         jump (pc,0);
         jump (pc,0);
         jump (pc,0);
         jump (pc,0);

__SOVFI:           // 0x0C: Status loop or mode stack overflow or PC stack full
           jump (pc,0);
           jump (pc,0);
           jump (pc,0);


                                                                                             39
jump (pc,0);

     __TMZHI:             // 0x10: Core timer interrupt (higher priority option)
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);

     __SPERRI:              // 0x14:
             jump      (pc,0);
             jump      (pc,0);
             jump      (pc,0);
             jump      (pc,0);

     __BKPI:              // 0x18: Hardware breakpoint interrupt
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);

     __res1I:              // 0x1C: (reserved)
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);


     __IRQ2I:             // 0x20: IRQ2 is asserted
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);

     __IRQ1I:             // 0x24: IRQ1 is asserted
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);

     __IRQ0I:           // 0x28: IRQ0 is asserted
                nop;
                jump _convolution;
                rti;
                rti;

     __DAIHI:             // 0x2C: DAI interrupt (higher priority option)
     __P0I :
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);

     __SPIHI:
     __P1I :               // 0x30: SPI transmit or receive (higher priority option)
     __SPII :
              jump     (pc,0);
              jump     (pc,0);
              jump     (pc,0);
              jump     (pc,0);

     __GPTMR0I:           // 0x34: General Purpose timer 0 interrupt
     __P2I :


40
jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP1I:             // 0x38: SPORT 1 interrupt
__P3I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP3I:             // 0x3C: SPORT 3 interrupt
__P4I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP5I:             // 0x40: SPORT 5 interrupt
__P5I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP0I:             // 0x44: SPORT 0 interrupt
__P6I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP2I:             // 0x48: SPORT 2 interrupt
__P7I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__SP4I:             // 0x4C: SPORT 4 interrupt
__P8I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__EP0I:          // 0x50: External port0 interrupt. Thats the only label we’re using here
__P9I :
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);
          jump   (pc,0);

__GPTMR1I:          // 0x54: General Purpose timer 1 interrupt
__P10I :
         jump    (pc,0);
         jump    (pc,0);
         jump    (pc,0);
         jump    (pc,0);

__SP7I:             // 0x58: serial port 7 interrupt


                                                                                            41
__P11I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __DAILI:            // 0x5C: DAI interrupt (lower priority option)
     __P12I :
              jump    (pc,0);
              jump    (pc,0);
              jump    (pc,0);
              jump    (pc,0);

     __EP1I:             // 0x60: External port1 interrupt
     __P13I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __DPII:             // 0x64: DPI interrupt
     __P14I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __MTMI:             // 0x68: Memory to Memory interface interrupt
     __P15I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __SP6I:             // 0x6C: serial port 6 interrupt
     __P16I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __GPTMR2I:          // 0x70: General Purpose timer 2 interrupt
     __P17I :
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);
             jump     (pc,0);

     __SPILI:            // 0x74: SPI transmit or receive (lower priority option)
     __P18I :
     __SPIBI:
              jump    (pc,0);
              jump    (pc,0);
              jump    (pc,0);
              jump    (pc,0);

     __CB7I:             // 0x78: Circular buffer 7 overflow exception
               jump   (pc,0);
               jump   (pc,0);
               jump   (pc,0);
               jump   (pc,0);



42
__CB15I:             // 0x7C: Circular buffer 15 overflow exception
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__TMZLI:             // 0x80: Core timer interrupt (lower priority option)
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__FIXI:              // 0x84: Fixed-point overflow exception
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__FLTOI:             // 0x88: Floating-point overflow exception
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__FLTUI:             // 0x8C: Floating-point underflow exception
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);


__FLTII:             // 0x90: Floating-point invalid exception
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__EMULI:             // 0x94: Emulator low priority interrupt
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__SFT0I:             // 0x98: User software interrupt 0
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__SFT1I:             // 0x9C: User software interrupt 1
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__SFT2I:             // 0xA0: User software interrupt 2
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);
           jump   (pc,0);

__SFT3I:            // 0xA4: User software interrupt 3 (lowest priority)


                                                                             43
jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);
                jump   (pc,0);




     Programmcode V1.asm

     /*****************************************************************************
      * V1.asm
      *****************************************************************************/
     #include <def21369.h>

     .SECTION/PM seg_dm32;

     #define             SAMPLES       9

            /* Input */
                .VAR input[SAMPLES]=   -4.,-3.,-2.,-1. ,0., 1.,2.,3.,4.;

                /* Output */
                .VAR output[SAMPLES]= 0.,0.,0.,0.,0.,0.,0.,0.,0.;

     .ENDSEG;



     .SECTION/PM seg_pmco;

     /* Set the scope of the ’_main’ symbol to global. This makes the symbol
        available for reference in object files that are linked to the current
        one. Use ’.EXTERN’ to refer to a global symbol from another file.*/
     .GLOBAL _main;

     /* Declare the ’_main’ symbol. */
     _main:

                /* Set bit called IRPTEN to enable interrupts */
                BIT SET MODE1 IRPTEN;

                /* Set irq0i interrupt bit */
            BIT SET IMASK IRQ0I;

                /* set value for modify-register M0 */
            M0=1;

                /* set length of ringbuffer B0 */
            L0=@input;

                /* name buffer B0, I0 is set at the same time */
            B0=input;

                 /* set length of ringbuffer B1 */
            L1=@output;

            /* name buffer B1, set I1 */
            B1=output;

                /* Switch to low power mode and expect interrupt */
     end:


44
idle;
           JUMP end;

/* Delimit the ’_main’ symbol so the linker knows which code is associated
   with the symbol. */
._main.END:

.GLOBAL _convolution;

_convolution:
        /* put the current value of buffer addressed by I0 to register
           F0 and increase buffer with M0 */
        R0=DM(I0,M0);

           /* Here the modification for the input value can be placed:
              Calculate the absolute value (ASM insn abs) */

         /* put value from register F0 to buffer B1 and
             increase with M0 */
     DM(I1,M0)=R0;

_convolution.END:
         RTI;

.ENDSEG;



                                           1.4.3 Programm 2: Parallele Verarbeitung von Befehlen

In diesem Programm sollen die besonderen Vorzüge des DSP für eine schnelle Verarbeitung
von Signalen anhand eines Tiefpass-FIR-Filters dargestellt werden.
Das Programm realisiert eine Faltung:
               m−1
      y(n) =         a(k)x(n − k),                                                   (1.8)
               k=0

wobei a(k) die Filterkoeffizienten, x(n-k) die um k verzögerten Eingangswerte und y(n) die
berechneten Ausgangswerte sind.
Das FIR-Filter benutzt vordefinierte Eingangswerte, die in einem Puffer eingeladen sind,
und Koeffizienten, die in einer Datei abgelegt sind. Zeitlich zurückliegende Eingangswerte
werden in einem zyklischen Speicher als sogenannte States berücksichtigt.
Das Programm stellt ein Filter der Länge 23 dar, das auf 200 vordefinierte Werte angewendet
wird. Es wird durch einen Interrupt wiederholt aufgerufen.
Das zugehörige Projekt V2 ist im Verzeichnis V2 abgelegt. Zusätzlich zu den Quellcode-
Dateien werden Variablenfelder in Dateien angegeben:

   • Eine Datei mit Filterkoeffizienten fircoefs.dat
   • Eine Datei mit dem Eingabesignal rect.dat

Die Filterkoeffizienten werden bei Versuchstermin 4 (s. Kap. 4.8.4) wiederverwendet.
Ziel dieses Versuches ist, die Funktion des Programmes durch Debuggen zu verstehen. Da
der Algorithmus (vom prinzip her) bekannt ist, soll zunächst eine Referenzimplementierung
in Matlab erstellt werden, die das Verständnis des DSP Codes erleichtern soll.

                                                                                             45
Aufgaben

       • Vorarbeit: Laden Sie die Datenfelder in den Dateien fircoefs.dat und rect.dat als FIR
         Filterkoeffizienten and Eingangswerte respektive in Matlab ein. Zum Einladen dient
         der load-Befehl. Realisieren Sie das FIR Filter als Matlab Funktion und verifizieren
         Sie Ihre Version mit der filter Funktion. Realisieren Sie Ihre Funktion in der Form,
         dass die Filterzustände als Parameter mit übergeben und wieder zurückgegeben wer-
         den (analog zur filter-Funktion und der DSP Version).

       • Öffnen Sie nun das Projekt V2. Verwenden Sie den Interrupt IRQ0 wie bei der ers-
         ten Aufgabe und setzen Sie einen Breakpoint an der Stelle, von wo aus jeweils die
         _filter-Routine angesprungen wird.

       • Vollziehen Sie die Ausführung des Programms nach. Versuchen Sie, die Verarbei-
         tung von Hand (auf Papier) auszuführen. Was bedeutet der Zusatz (dB) in Zeile 99?
         Welche Variable im DSP Code entsprechen den Größen h(k), x(k) und x(k − N)?
         Was genau passiert während der Interrupt-Service-Routine? Wozu dient die XOR-
         Verknüpfung in Zeile 146? Was passiert, wenn statt der Register R8, R12 und R4
         andere Register verwendet werden? Plotten Sie inbuf und outbuf, wenn die Verar-
         beitung aller Eingangssamples beendet ist. Plotten Sie auch die Koeffizienten im Feld
         coefs.

       • Wie könnte man die FIR-Routine verkürzen, wenn eine Rechengenauigkeit von 32
         bit integer ausreicht?

     Programmcode V2

     /********************************************************
      *
      * V2.ASM                 FIR filterprogram for ADSP21369
      * Filename:                        V22.asm
      *
      * Description:
      *
      * The program shows how to effectivly perform a convolution
      * with the multiple instructions feature of the ADSP-21369
      *
      * Registers affected:
      *
      * F0     F8    I0             I1
      * F4     F12   I8         I2
      *
      * Used parameters:
      * F0 = input sample x(n)
      * R1 = number of taps in the filter minus 1
      * B0 = address of the delay line buffer
      * M0 = modify value for the delay line buffer
      * L0 = length of the delay line buffer
      * B8 = address of the coefficent buffer
      * M8 = modify value of the coefficent buffer
      * L8 = length of the coefficent buffer
      *
      ********************************************************/

     #define        SAMPLE 200                 /*number of input samples to be filtered*/
     #define        TAPS 23                         /*length of filter*/


46
#include <def21369.h>

.SECTION/PM seg_pm32;

           /*FIR coefficients stored in file */
           .VAR     coefs[TAPS]=quot;fircoefs.datquot;;
.ENDSEG;

.SEGMENT/DM seg_dm32;

           /*buffer that holds the delay line*/
           .VAR        dline[TAPS];

           /*input samples stored in file */
           .VAR        inbuf[SAMPLE] = quot;rect.datquot;;

           /*buffer that contains output coefficients*/
           .VAR        outbuf[SAMPLE];
.ENDSEG;



.SECTION/PM seg_pmco;

/* Set the scope of the ’_main’ symbol to global. This makes the symbol
   available for reference in object files that are linked to the current
   one. Use ’.EXTERN’ to refer to a global symbol from another file.*/
.GLOBAL _main;

/* Declare the ’_main’ symbol. */
_main:

           /*enable interrupts*/
           BIT SET MODE1 IRPTEN;

           /* enable circular buffering */
           BIT SET MODE1 CBUFEN;

           L0=TAPS;

           /*delay line buffer pointer initialisation*/
           B0=dline;

           /*set modify-register M0=1*/
           M0=1;

           /*set modify-register M1=1*/
           M1=1;

           L1=@inbuf;

           /*input buffer pointer initialisation*/
           B1=inbuf;

           L2=@outbuf;

           /*output buffer pointer initialisation*/
           B2=outbuf;

           L8=TAPS;



                                                                            47
/*coefficient buffer pointer initialisation*/
                B8=coefs;

                /*set modify-register M8=1*/
                M8=1;

                /*initialize delay line buffer to zero*/
                CALL fir_init (DB);

                /* Set coefficient to second filter coeff */
                MODIFY(I8,M8);

                R0=TAPS;

                /*enable interrupt IRQ0I*/
                BIT SET IMASK IRQ0I;

     done:
                /*wait for interrupt */
                JUMP done;

     fir_init:
             LCNTR=R0, DO zero1 UNTIL LCE;

     zero1:

                /*initialize the delay line to 0*/
                DM(I0,M0)=0;

                R0=SAMPLE;

                LCNTR=R0, DO zero2 UNTIL LCE;
     zero2:

                /*initialize the output buffer to 0*/
                DM(I2,M1)=0;

                RTS;

     /* Delimit the ’_main’ symbol so the linker knows which code is associated
        with the symbol. */
     ._main.END:

     .GLOBAL _filter;

     _filter:

                /* Filter one input sample. */
                CALL fir(DB);

                /* At first setup the loop counter for circular buffer */
                R1=TAPS-3;

                /* Read in h(1) (the second filter coefficient) and x(k-1) */
                R8=R8 XOR R8, F0=DM(I0,M0), F4=PM(I8,M8);

                /* ======> Call fir subroutine */

                /*result is stored in outbuf */
                DM(I2,M1)=F0;

                RTI;


48
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc
Dsvdoc

Más contenido relacionado

Was ist angesagt?

Praxisworkshop GIMP 2 - Die wichtigsten Werkzeuge
Praxisworkshop GIMP 2 - Die wichtigsten WerkzeugePraxisworkshop GIMP 2 - Die wichtigsten Werkzeuge
Praxisworkshop GIMP 2 - Die wichtigsten Werkzeugeguestadcc8ae
 
Agorum core-administrations-handbuch-6 4-0a
Agorum core-administrations-handbuch-6 4-0aAgorum core-administrations-handbuch-6 4-0a
Agorum core-administrations-handbuch-6 4-0aagorum Software GmbH
 
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...VincentS14
 
Diplomarbeit
DiplomarbeitDiplomarbeit
Diplomarbeitjim5555
 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template Libraryguestfc11c0c
 
Vergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodell
Vergleich des Scala Web-Frameworks Lift mit dem Java EE ProgrammiermodellVergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodell
Vergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodelladesso AG
 
Galileodesign elements 8_westphalen
Galileodesign elements 8_westphalenGalileodesign elements 8_westphalen
Galileodesign elements 8_westphalenWGS
 
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2VincentS14
 
Master thesis pascal_mueller01
Master thesis pascal_mueller01Master thesis pascal_mueller01
Master thesis pascal_mueller01guest39ce4e
 

Was ist angesagt? (14)

J3dboolop
J3dboolopJ3dboolop
J3dboolop
 
mabio
mabiomabio
mabio
 
Praxisworkshop GIMP 2 - Die wichtigsten Werkzeuge
Praxisworkshop GIMP 2 - Die wichtigsten WerkzeugePraxisworkshop GIMP 2 - Die wichtigsten Werkzeuge
Praxisworkshop GIMP 2 - Die wichtigsten Werkzeuge
 
Msrbas
MsrbasMsrbas
Msrbas
 
Agorum core-administrations-handbuch-6 4-0a
Agorum core-administrations-handbuch-6 4-0aAgorum core-administrations-handbuch-6 4-0a
Agorum core-administrations-handbuch-6 4-0a
 
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...
Dokumentation EMV-Messtechnik (Würth Elektronik Energy Harvesting Solution To...
 
Diplomarbeit
DiplomarbeitDiplomarbeit
Diplomarbeit
 
C++ Standard Template Library
C++ Standard Template LibraryC++ Standard Template Library
C++ Standard Template Library
 
B8 Handbuch
B8 HandbuchB8 Handbuch
B8 Handbuch
 
Ghf Skript 2009
Ghf Skript 2009Ghf Skript 2009
Ghf Skript 2009
 
Vergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodell
Vergleich des Scala Web-Frameworks Lift mit dem Java EE ProgrammiermodellVergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodell
Vergleich des Scala Web-Frameworks Lift mit dem Java EE Programmiermodell
 
Galileodesign elements 8_westphalen
Galileodesign elements 8_westphalenGalileodesign elements 8_westphalen
Galileodesign elements 8_westphalen
 
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2
Dokumentation EMV-Messtechnik (TI-PMLK Würth Elektronik Edition) - Version 2
 
Master thesis pascal_mueller01
Master thesis pascal_mueller01Master thesis pascal_mueller01
Master thesis pascal_mueller01
 

Andere mochten auch

Umwelt schonen mit intelligenter IT
Umwelt schonen mit intelligenter ITUmwelt schonen mit intelligenter IT
Umwelt schonen mit intelligenter ITkerstenr
 
Kommunikation und Zusammenarbeit in verteilten Projektteams
Kommunikation und Zusammenarbeit in verteilten ProjektteamsKommunikation und Zusammenarbeit in verteilten Projektteams
Kommunikation und Zusammenarbeit in verteilten ProjektteamsCommunardo GmbH
 
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse3cdialog
 
Luxemburg nach dem ersten weltkrieg
Luxemburg nach dem ersten weltkriegLuxemburg nach dem ersten weltkrieg
Luxemburg nach dem ersten weltkriegIsabelle Deville
 
Adobe eSeminar-Immer Im Umbruch Der Gesundheitsmarkt
Adobe eSeminar-Immer Im Umbruch Der GesundheitsmarktAdobe eSeminar-Immer Im Umbruch Der Gesundheitsmarkt
Adobe eSeminar-Immer Im Umbruch Der GesundheitsmarktGuido Schmitz
 
Klinik der Solidarität - Teil 1
Klinik der Solidarität - Teil 1Klinik der Solidarität - Teil 1
Klinik der Solidarität - Teil 1Thomas Kreiml
 
Zorn_Julie_neue Medien im Lehrplan_E2B
Zorn_Julie_neue Medien im Lehrplan_E2BZorn_Julie_neue Medien im Lehrplan_E2B
Zorn_Julie_neue Medien im Lehrplan_E2Bunilux
 
Businessstalk integro
Businessstalk integroBusinessstalk integro
Businessstalk integrointegro
 
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)Communardo GmbH
 
Next Generation Internet Open Source
Next Generation Internet Open SourceNext Generation Internet Open Source
Next Generation Internet Open SourceAndreas Mertens
 
Whitepaper "Fotos im Onlinemarketing"
Whitepaper "Fotos im Onlinemarketing"Whitepaper "Fotos im Onlinemarketing"
Whitepaper "Fotos im Onlinemarketing"Thomas Hendele
 
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)CCD 2011: Dokumentieren im Wiki (Tobias Anstett)
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)Communardo GmbH
 
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?AppRadar - Wie zufrieden Sind Ihre App-Nutzer?
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?aperto move
 
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...Michael Gebert
 
Nature In Berriz
Nature In BerrizNature In Berriz
Nature In Berrizmarivisu
 
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...Telekom MMS
 

Andere mochten auch (20)

Dsvdoc
DsvdocDsvdoc
Dsvdoc
 
Umwelt schonen mit intelligenter IT
Umwelt schonen mit intelligenter ITUmwelt schonen mit intelligenter IT
Umwelt schonen mit intelligenter IT
 
Kommunikation und Zusammenarbeit in verteilten Projektteams
Kommunikation und Zusammenarbeit in verteilten ProjektteamsKommunikation und Zusammenarbeit in verteilten Projektteams
Kommunikation und Zusammenarbeit in verteilten Projektteams
 
Dsvdoc
DsvdocDsvdoc
Dsvdoc
 
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse
"Mehrwert Contact Center" von Necla Haskioglu-Larsch und Dirk Harder, Enghouse
 
Luxemburg nach dem ersten weltkrieg
Luxemburg nach dem ersten weltkriegLuxemburg nach dem ersten weltkrieg
Luxemburg nach dem ersten weltkrieg
 
Adobe eSeminar-Immer Im Umbruch Der Gesundheitsmarkt
Adobe eSeminar-Immer Im Umbruch Der GesundheitsmarktAdobe eSeminar-Immer Im Umbruch Der Gesundheitsmarkt
Adobe eSeminar-Immer Im Umbruch Der Gesundheitsmarkt
 
Klinik der Solidarität - Teil 1
Klinik der Solidarität - Teil 1Klinik der Solidarität - Teil 1
Klinik der Solidarität - Teil 1
 
Haiti
HaitiHaiti
Haiti
 
Zorn_Julie_neue Medien im Lehrplan_E2B
Zorn_Julie_neue Medien im Lehrplan_E2BZorn_Julie_neue Medien im Lehrplan_E2B
Zorn_Julie_neue Medien im Lehrplan_E2B
 
Businessstalk integro
Businessstalk integroBusinessstalk integro
Businessstalk integro
 
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)
CCD 2011: Management Prozesse mit JIRA unterstützen (Ilja Hauß)
 
Apps für Kultureinrichtungen
Apps für KultureinrichtungenApps für Kultureinrichtungen
Apps für Kultureinrichtungen
 
Next Generation Internet Open Source
Next Generation Internet Open SourceNext Generation Internet Open Source
Next Generation Internet Open Source
 
Whitepaper "Fotos im Onlinemarketing"
Whitepaper "Fotos im Onlinemarketing"Whitepaper "Fotos im Onlinemarketing"
Whitepaper "Fotos im Onlinemarketing"
 
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)CCD 2011: Dokumentieren im Wiki (Tobias Anstett)
CCD 2011: Dokumentieren im Wiki (Tobias Anstett)
 
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?AppRadar - Wie zufrieden Sind Ihre App-Nutzer?
AppRadar - Wie zufrieden Sind Ihre App-Nutzer?
 
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...
Delphi-Studie Crowdfunding 2020 - Komplement oder Substitut für die Finanzind...
 
Nature In Berriz
Nature In BerrizNature In Berriz
Nature In Berriz
 
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...
Vom Callcenter zum Business Interactive Center. Hochwertiger Service auf alle...
 

Ähnlich wie Dsvdoc

Bachelorarbeit paul gerber.pdf
Bachelorarbeit paul gerber.pdfBachelorarbeit paul gerber.pdf
Bachelorarbeit paul gerber.pdfwissem hammouda
 
Team Oldenburger Robo-Fußball – Abschlussbericht der Projektgruppe 2010
Team Oldenburger Robo-Fußball – Abschlussbericht  der Projektgruppe  2010Team Oldenburger Robo-Fußball – Abschlussbericht  der Projektgruppe  2010
Team Oldenburger Robo-Fußball – Abschlussbericht der Projektgruppe 2010Johannes Diemke
 
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...Sascha Jonas
 
Informationsvisualisierung Im Semantic Web1
Informationsvisualisierung Im Semantic Web1Informationsvisualisierung Im Semantic Web1
Informationsvisualisierung Im Semantic Web1brisvegas1
 
Einsteiger zertifizierung des LPI
Einsteiger zertifizierung des LPIEinsteiger zertifizierung des LPI
Einsteiger zertifizierung des LPIMichael M. Bosbach
 
Das "Privacy Handbuch"
Das "Privacy Handbuch"Das "Privacy Handbuch"
Das "Privacy Handbuch"Dominik Wind
 
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista Johannes Hohenbichler
 
agorum core-benutzer-handbuch-6 4-0
agorum core-benutzer-handbuch-6 4-0agorum core-benutzer-handbuch-6 4-0
agorum core-benutzer-handbuch-6 4-0agorum Software GmbH
 
Modulhandbuch 2008
Modulhandbuch 2008Modulhandbuch 2008
Modulhandbuch 2008guest995aa7
 
53045 ba dpt 3000 v6.17
53045 ba dpt 3000 v6.1753045 ba dpt 3000 v6.17
53045 ba dpt 3000 v6.17Teo Dor
 
Blockchain-based access right management for private data in decentralized cl...
Blockchain-based access right management for private data in decentralized cl...Blockchain-based access right management for private data in decentralized cl...
Blockchain-based access right management for private data in decentralized cl...ArtemEger
 
Creation ii v0.93 vorläufig
Creation ii v0.93 vorläufigCreation ii v0.93 vorläufig
Creation ii v0.93 vorläufigmarkktoo
 

Ähnlich wie Dsvdoc (20)

Dsvdoc
DsvdocDsvdoc
Dsvdoc
 
Dsvdoc
DsvdocDsvdoc
Dsvdoc
 
Dsvdoc
DsvdocDsvdoc
Dsvdoc
 
Mocek Thesis
Mocek ThesisMocek Thesis
Mocek Thesis
 
Bachelorarbeit paul gerber.pdf
Bachelorarbeit paul gerber.pdfBachelorarbeit paul gerber.pdf
Bachelorarbeit paul gerber.pdf
 
Handbuch
HandbuchHandbuch
Handbuch
 
Team Oldenburger Robo-Fußball – Abschlussbericht der Projektgruppe 2010
Team Oldenburger Robo-Fußball – Abschlussbericht  der Projektgruppe  2010Team Oldenburger Robo-Fußball – Abschlussbericht  der Projektgruppe  2010
Team Oldenburger Robo-Fußball – Abschlussbericht der Projektgruppe 2010
 
Diplomarbeit
DiplomarbeitDiplomarbeit
Diplomarbeit
 
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...
Entwicklung eines Frameworks zum automatisierten Handel eines Multi-Broker-PA...
 
Informationsvisualisierung Im Semantic Web1
Informationsvisualisierung Im Semantic Web1Informationsvisualisierung Im Semantic Web1
Informationsvisualisierung Im Semantic Web1
 
Laz Infos Svn0082
Laz Infos Svn0082Laz Infos Svn0082
Laz Infos Svn0082
 
Einsteiger zertifizierung des LPI
Einsteiger zertifizierung des LPIEinsteiger zertifizierung des LPI
Einsteiger zertifizierung des LPI
 
Das "Privacy Handbuch"
Das "Privacy Handbuch"Das "Privacy Handbuch"
Das "Privacy Handbuch"
 
OSG Volume Rendering
OSG Volume RenderingOSG Volume Rendering
OSG Volume Rendering
 
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
Stack- und Heap-Overflow-Schutz bei Windows XP und Windows Vista
 
agorum core-benutzer-handbuch-6 4-0
agorum core-benutzer-handbuch-6 4-0agorum core-benutzer-handbuch-6 4-0
agorum core-benutzer-handbuch-6 4-0
 
Modulhandbuch 2008
Modulhandbuch 2008Modulhandbuch 2008
Modulhandbuch 2008
 
53045 ba dpt 3000 v6.17
53045 ba dpt 3000 v6.1753045 ba dpt 3000 v6.17
53045 ba dpt 3000 v6.17
 
Blockchain-based access right management for private data in decentralized cl...
Blockchain-based access right management for private data in decentralized cl...Blockchain-based access right management for private data in decentralized cl...
Blockchain-based access right management for private data in decentralized cl...
 
Creation ii v0.93 vorläufig
Creation ii v0.93 vorläufigCreation ii v0.93 vorläufig
Creation ii v0.93 vorläufig
 

Dsvdoc

  • 1. Praktikum Digitale Signalverarbeitung Institut für Nachrichtengeräte und Datenverarbeitung Prof. Dr.-Ing. Peter Vary
  • 3. Inhaltsverzeichnis 1 Der Signalprozessor Analog Devices ADSP-21369 7 1.1 Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.1.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.1.2 Grundstruktur der Signalprozessor-Architektur . . . . . . . . . . . 7 1.2 Signalprozessor Analog Devices ADSP-21369 . . . . . . . . . . . . . . . . 12 1.2.1 Architektur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 1.2.2 Datenformate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 1.2.3 Recheneinheiten und Datenregister . . . . . . . . . . . . . . . . . 15 1.2.4 Das Programm-Steuerwerk . . . . . . . . . . . . . . . . . . . . . . 18 1.2.5 Datenadressierung . . . . . . . . . . . . . . . . . . . . . . . . . . 24 1.2.6 Speicher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 1.3 Entwicklungsumgebung: Visual DSP++ . . . . . . . . . . . . . . . . . . . 28 1.3.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 1.3.2 Implementierung des Source-Codes . . . . . . . . . . . . . . . . . 29 1.4 Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.4.1 Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.4.2 Programm 1: Interruptgesteuerte Ein-/Ausgabe . . . . . . . . . . . 35 1.4.3 Programm 2: Parallele Verarbeitung von Befehlen . . . . . . . . . . 45 1.4.4 Programm 3: Benutzung des Rahmenprogramms . . . . . . . . . . 49 2 Grundlagen MATLAB und SIMULINK 53 2.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 2.2 Grundlagen der digitalen Signalverarbeitung . . . . . . . . . . . . . . . . . 54 2.2.1 Abtastung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 2.2.2 Quantisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 2.3 Einführung in MATLAB . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 2.3.1 Starten von MATLAB . . . . . . . . . . . . . . . . . . . . . . . . 56 3
  • 4. 2.3.2 Benutzung von Hilfe-Funktionen .................. 58 2.3.3 Verwendung von Variablen . . . . . . . . . . . . . . . . . . . . . . 60 2.3.4 Operationen mit Vektoren und Matrizen . . . . . . . . . . . . . . . 62 2.3.5 Elementare Funktionen . . . . . . . . . . . . . . . . . . . . . . . . 64 2.3.6 Grafische Darstellungsmöglichkeiten . . . . . . . . . . . . . . . . 65 2.3.7 Audiowiedergabe . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 2.3.8 Verwalten von Daten und Dateien . . . . . . . . . . . . . . . . . . 65 2.3.9 Erstellen von Skripten und Funktionen . . . . . . . . . . . . . . . . 66 2.4 Einführung in SIMULINK . . . . . . . . . . . . . . . . . . . . . . . . . . 67 2.4.1 Starten von SIMULINK . . . . . . . . . . . . . . . . . . . . . . . 68 2.4.2 Die Quellen eines SIMULINK-Modells . . . . . . . . . . . . . . . 70 2.4.3 Die Senken eines SIMULINK-Modells . . . . . . . . . . . . . . . 71 2.4.4 Starten einer Simulation mit Angabe von Simulationsparametern . . 71 2.5 DSP-Debugging mit MATLAB . . . . . . . . . . . . . . . . . . . . . . . . 72 2.6 Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 2.6.1 Aufgabe I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 2.6.2 Aufgabe II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 2.6.3 Aufgabe III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 2.6.4 Aufgabe IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 2.7 Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 2.7.1 Versuch A: Grundlegende MATLAB-Operationen . . . . . . . . . 77 2.7.2 Versuch B: MATLAB-Funktionen . . . . . . . . . . . . . . . . . . 78 2.7.3 Versuch C: DSP-Debugging mit MATLAB . . . . . . . . . . . . . 79 2.7.4 Versuch D: Echo-Effekt mit dem DSP / Zyklischer Speicher . . . . 79 2.7.5 (*) Versuch E: Rückfaltungen . . . . . . . . . . . . . . . . . . . . 80 2.7.6 (*)Versuch F: Grobquantisierung . . . . . . . . . . . . . . . . . . . 81 2.7.7 (*)Versuch G: Amplitudenmodulation mit Hüllkurvenempfang . . . 82 Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 3 Diskrete Fourier-Transformation (DFT) 85 3.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.2 Theoretische Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 3.2.1 Definition und Eigenschaften der DFT . . . . . . . . . . . . . . . . 85 3.2.2 Fensterfunktionen .......................... 87 3.2.3 Schnelle Fourier-Transformation (FFT) . . . . . . . . . . . . . . . 93 3.2.4 Schnelle Faltung . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 4
  • 5. 3.3 Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 3.3.1 Aufgabe I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 3.3.2 Aufgabe II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 3.3.3 Aufgabe III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 3.4 Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 3.4.1 Versuch A: DFT spezieller Signale . . . . . . . . . . . . . . . . . . 101 3.4.2 Versuch B: Zero-Padding . . . . . . . . . . . . . . . . . . . . . . . 102 3.4.3 Versuch C: Fensterung und Leckeffekt . . . . . . . . . . . . . . . . 102 3.4.4 Versuch D: Schnelle Faltung mittels overlap add Verfahren . . . . . 103 3.4.5 Versuch E: FFT auf dem DSP . . . . . . . . . . . . . . . . . . . . 106 3.4.6 (*)Versuch F: Gemeinsame Transformation zweier reeller Signale . 106 3.4.7 (*)Versuch G: Analyse von Signalen mit diskr. spektr. Komponenten 107 Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 4 Digitale FIR- und IIR-Filter 109 4.1 Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 4.2 Beschreibung linearer zeitdiskreter Systeme . . . . . . . . . . . . . . . . . 109 4.3 FIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 4.3.1 FIR-Filter mit linearer Phase . . . . . . . . . . . . . . . . . . . . . 111 4.3.2 FIR-Filterentwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 4.4 IIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 4.4.1 Stabilität . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 4.4.2 Filterstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119 4.4.3 IIR-Filterentwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 4.5 Spezielle Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 4.5.1 Differentiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 4.5.2 Integration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 4.5.3 Hilbert-Transformation . . . . . . . . . . . . . . . . . . . . . . . . 126 4.5.4 Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 4.6 Eigenschaften realer Filter . . . . . . . . . . . . . . . . . . . . . . . . . . 128 4.6.1 FIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 4.6.2 IIR-Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 4.7 Vorbereitende Aufgaben . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.7.1 Aufgabe 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.7.2 Aufgabe 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 4.7.3 Aufgabe 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 5
  • 6. 4.7.4 Aufgabe 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 4.7.5 Aufgabe 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 4.7.6 Aufgabe 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 4.8 Versuchsdurchführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 4.8.1 FIR-Versuch A: Rechteck-, Hamming- und Blackman-Fenster . . . 137 4.8.2 FIR-Versuch B: Kaiser-Fenster . . . . . . . . . . . . . . . . . . . . 137 4.8.3 FIR-Versuch D: Differentiation . . . . . . . . . . . . . . . . . . . . 138 4.8.4 FIR-Versuch E: FIR-Filter auf dem DSP . . . . . . . . . . . . . . . 138 4.8.5 (*)FIR-Versuch F: Koeffizienten-Quantisierung . . . . . . . . . . . 139 4.8.6 (*) FIR-Versuch G: Tschebyscheff-Approximation . . . . . . . . . 139 4.8.7 IIR-Versuch A: Rekursive Differenzengleichung . . . . . . . . . . 139 4.8.8 IIR-Versuch B: Spezielle rekursive Filter . . . . . . . . . . . . . . 140 4.8.9 IIR-Versuch C: Sprungantwort und Einschwingzeit . . . . . . . . . 142 4.8.10 (*)IIR-Versuch D: Vergleich verschiedener Approximationsverfahren 142 Literaturverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 6
  • 7. Kapitel 1 Der Signalprozessor Analog Devices ADSP-21369 1.1 Grundlagen 1.1.1 Einleitung Im ersten Versuch wird der Aufbau und die Programmierung des Prozessors ADSP-21369 von Analog Devices erklärt. Um einen leichten Einstieg in die Projektphase im Anschluss zu ermöglichen, wurde am IND eine Software erstellt. Die Prinzipien dieser Software sind im zusätzlichen Dokument „Rapid Prototyping on Embedded targets: RTProcDSP“ erläu- tert. Durch die Software-Vorgabe wird es den Studenten ermöglicht, den Prototypen eines neuartigen Algorithmus zu erstellen, ohne allzuviel mit den Programmierungsdetails des Echtzeit- Betriebssystems in Kontakt zu kommen. Zur Programmierung der Hardware bietet Analog Devices eine Entwicklungsumgebung an, die sich Visual DSP++ nennt. Diese wird schließlich kurz vorgestellt. Mit ihrer Hilfe wer- den im Anschluss die Übungsbeispiele simuliert bzw. emuliert. 1.1.2 Grundstruktur der Signalprozessor-Architektur In den letzten Jahren war bei Bauteilen in Hardware-Komponenten neuer Produkte eine Spezialisierung auf den Anwendungsfall zu beobachten. Es macht keinen Sinn, für Algo- rithmen zur reinen Signalverarbeitung die Kosten eines General-Purpose Prozessors (z.B. Intel Pentium Prozessor) bezahlen zu müssen, wenn dieselben Algorithmen von einem Pro- zessor ausgeführt werden können, der auf diese Art von Anwendungen spezialisiert ist. Gleichzeitig erscheint es auch in vielen Bereichen sinnvoll, Algorithmen nicht in „Silicon“, also Hardware, sondern in Software zu realisieren. Dadurch kann auf sich ändernde Sys- temanforderungen bei existierenden Produkten schnell und umfassend reagiert werden, in- dem zum Beispiel Software-Updates durchgeführt werden. DSPs sind für Echtzeitanwendungen, z. B. im Bereich der Audio- und Videoverarbeitung, entwickelt worden und verfügen über für ihren Einsatz angepasste Befehlssätze und Archi- tekturen. Sie haben einen niedrigen Leistungsverbrauch und sind durch ihre Spezialisierung in der Anschaffung sehr günstig. Ein Programmierer kann im Bereich der Signalverarbeitungs- 7
  • 8. Algorithmen sehr kompakten Code erzeugen, was zu einer Minimierung des Speicherbe- darfs in einem Produkt führt. Die ersten Signalprozessoren waren modular aus Bit-Slice-Elementen aufgebaut. Der damit verbundene hohe Aufwand beschränkte den Einsatz der digitalen Signalverarbeitung auf spezielle Gebiete. Erst die Entwicklung monolithisch integrierter Signalprozessoren An- fang der achtziger Jahre ermöglichte den Einsatz der DSV in vielen kommerziellen Berei- chen. Mittlerweile existiert ein breites Angebot digitaler Signalprozessoren verschiedener Hersteller. Trotz ihrer unterschiedlichen und komplexen Architekturen enthalten die heutigen Signal- prozessoren gemeinsame Grundstrukturen. Diese Grundstrukturen ergeben sich aus den An- forderungen der DSV-Algorithmen. Die für die DSV exemplarischen Algorithmen wie z. B. die Fourier-Transformation, die Korrelation und die digitale Filterung enthalten in ihrem Kern vektorielle Skalarprodukte. Um diese Skalarprodukte schnell berechnen zu können, sind Signalprozessoren mit einem Hardware-Multiplizierer ausgestattet. Diesem ist ein Addierer/Akkumulator nachgeschal- tet. Abbildung 1.1 zeigt den prinzipiellen Aufbau der Recheneinheit (Daten-ALU (Arithmetic Logical Unit)) am Beispiel eines 16 Bit Festkomma Signalprozessors. Die zu verarbeiten- den Daten werden in Eingangsregistern zwischengespeichert und dem Multiplizierer zu- geführt. Damit keine Genauigkeitsverluste auftreten, wird das Ergebnis der Multiplikation zunächst mit einer Wortbreite von 31 bzw. 32 Bit dargestellt und zum Inhalt des Ausgangs- registers addiert. Die mit insgesamt 40 Bit um 8 Bit größeren Wortbreiten von Addierer und Ausgangsregister ermöglichen die überlauffreie Addition von bis zu 28 = 256 Produkten. Abbildung 1.1: Daten-ALU eines 16-Bit Signalprozessors Erst wenn das Ergebnis feststeht, also alle Multiplikationen und Additionen durchgeführt wurden, verringert ein sogenannter Barrelshifter die Ergebniswortbreite auf das ursprüng- liche 16 Bit Format. Dabei kann eine mathematische Rundungsoperation und eine betrags- mäßige Begrenzung eingeschlossen sein. Multiplizierer und Addierer arbeiten gleichzeitig. Das bedeutet, dass in einem Maschinen- 8
  • 9. zyklus die Werte aus den Eingangsregistern multipliziert werden können und das Ergebnis des Multiplizierers im Addierer verarbeitet werden kann. Damit werden zwei Rechenope- rationen pro Zyklus ausgeführt. Das vektorielle Skalarprodukt y der Dimension N kann im Prinzip in N Prozessorzyklen berechnet werden: N−1 y = x · bT = bi · xi (1.1) i=0 mit x = {x0 , x1 , . . . , xN−1 } (1.2) und b = {b0 , b1 , . . . , bN−1 }. (1.3) Das hier beschriebene gleichzeitige Addieren und Multiplizieren ist eines der wichtigsten Merkmale eines Signalprozessors und wird durch spezielle multiply/accumulate-Befehle unterstützt. Bei einigen Signalprozessoren werden die Multiplikation und die Addition in zwei aufeinander folgenden Zyklen, d.h. im „Pipeline“ - Betrieb durchgeführt. Im Akku- mulator wird dabei jeweils das Produktergebnis aus dem vorhergehenden Befehlszyklus auf das Ausgangsregister aufaddiert. Da der Multiplizierer und der Akkumulator gleichzei- tig arbeiten, dauert die Berechnung des Skalarproduktes der Dimension N insgesamt N + 1 Takte. Selbstverständlich bietet ein DSP auch die Möglichkeit, nur zu addieren oder nur zu multi- plizieren. Weiterhin gehören Bit-Manipulationsbefehle und logische Operationen zum Be- fehlsrepertoire eines Signalprozessors. Im vorgestellten Beispiel müssen nach jedem Maschinenzyklus zwei neue Eingangsdaten bereitstehen, wenn die Daten-ALU ausgelastet werden soll. Zusätzlich muss in jedem Pro- grammschritt ein Befehlswort gelesen werden. Das bedeutet drei Datenübertragungen pro Zyklus. Diese hohe Übertragungrate wird durch eine sogenannte „Harvard-Architektur“ er- möglicht. Diese Architektur verfügt im Gegensatz zur „von Neumann-Struktur“ über se- parate Programm- und Datenspeicher sowie über separate Daten- und Adressbusse. Da- durch sind Schreib- und Leseoperationen im Datenspeicher möglich, während gleichzeitig Instruktionen aus dem Programmspeicher gelesen werden. Eine Super-Harvard-Architektur bietet zusätzlich die Möglichkeit, Instruktionen in einem Cache zwischenzuspeichern. Der betrachtete Prozessor ADSP-21369 entspricht in seinem Aufbau einer Super-Harvard Architektur. Abbildung 1.2 zeigt das Prinzipschaltbild eines derartigen Signalprozessors mit erweiterter Harvard-Architektur. Neben der Daten-ALU, dem Programm- und dem Datenspeicher sind zwei weitere Kom- ponenten zu erkennen: die Programm-Ablaufsteuerung und die Adress-ALU. Die Adress-ALU berechnet bei dieser Architektur pro Maschinenzyklus die beiden Spei- cheradressen der Daten für die nächste Operation der Daten-ALU. Erst dadurch wird si- chergestellt, dass in jedem Befehlszyklus neue Daten zu den Eingangsregistern übertragen werden können. Der Befehlssatz der Adress-ALU ist auf die Belange der DSV abgestimmt. Hervorzuheben ist z. B. die in der Regel verfügbare Modulo-Adressarithmetik. Bei dieser Adressierungsart 9
  • 10. Abbildung 1.2: Prinzipielle Architektur eines digitalen Signalprozessors (DSP) erzeugt die Adress-ALU aufeinanderfolgende Adressen innerhalb eines bestimmten Berei- ches. Ist das Bereichsende erreicht, so wird mit dem Bereichsanfang fortgefahren, ohne dass dazu zusätzliche Programmschritte notwendig sind. Diese Eigenschaft lässt sich z. B. vorteilhaft in Programmen nutzen, in denen Daten blockweise verarbeitet werden (Modulo- Adressierung, vgl. Abschnitt 1.2.5). Die Leistungsmerkmale der heute verfügbaren Prozessoren unterscheiden sich bezüglich • Arithmetik • Speicherkapazität • Geschwindigkeit • Architektur und Befehlssatz. Für eine kleine, repräsentative Auswahl aus dem derzeitigen Angebot wurden in Tabelle 1.1 einige Angaben zum Entwicklungsstand integrierter Signalprozessoren zusammengestellt. 10
  • 11. Firma Typ Jahr Zyklus/Frequenz Wortbreite Arithmetik Daten-RAM Infineon Carmel 10xx 4 ns/250 MHz 16 bit Festkomma (← Core) Carmel 20xx (Core) a 32k b Tricore 97-99 6 ns/167 MHz 16/32 Gleitkomma (MCU-DSP) Texas TMS320C25 1987 80 ns/12,5 MHz 16 Festkomma 4k x 16 Instruments TMS 320C40 33 ns/30 MHz 32 Gleitkomma 2k x 16 TMS 320C50 25 ns/40 MHz 16 Festkomma 10k x 16 TMS 320C62 1997 5 ns/200 MHz 16 Festkomma 2 x 512k TMS 320C67 1997 6 ns/167 MHz 32 Gleitkomma 2 x 512k TMS 320C64 2000 0,9 ns/1100 MHz (← Core) (Core) Motorola 56001 1987 100 ns/10 MHz 24 Festkomma 2 x 512k x 24 56301 12,5 ns/80 MHz 24 Festkomma 2 x 2k x 24 56800E 2000 5 ns/200 MHz 8-32 Festkomma (← Core) (MCU-DSP) 56853 2001 8,3 ns/120 MHz 32k Analog ADSP-21060 1995 25 ns/40 MHz 32 Gleitkomma 2 x 2M Devices ADSP-21065L 1995 16 ns/60 MHz 32 Gleit/Fest 1M 2192 (Dual) 2000 6,25 ns/160 MHz 16 Festkomma (← Core) 21116 ($5) 2000 10 ns/100 MHz 32 Gleitkomma ADSP-21369 2005 2,5 ns/400 MHz 32 Gleit/Fest 16M a CLIW and power plugs support b Caches-support Tabelle 1.1: Auswahl von aktuellen und alten DSPs 11
  • 12. 1.2 Signalprozessor Analog Devices ADSP-21369 1.2.1 Architektur Zunächst soll ein Überblick über die Prozessorarchitektur und seine für den Versuch re- levanten Komponenten vorgestellt werden. Abschnitt 1.2 ist als eine kurze Einführung zu verstehen. Für weitere Informationen wird auf die „ADSP-2136x SHARC Programming Reference“ verwiesen, die im Folgenden kurz „Handbuch“ genannt wird. Der in Versuch 4 und der anschließenden Projektphase eingesetzte Signalprozessor ADSP- 21369 ist ein 32 Bit Gleitkommaprozessor, der bei einer Taktfrequenz von 333 MHz arbeitet und 8 MB on-chip-Speicher hat (2 MB SRAM und 6 MB ROM). Er hat darüberhinaus einen Cache-Speicher, der 32 Befehle halten kann, und eine große Anzahl von Registern (spezielle Speicherstellen, die z. B. Operanden und Ergebnisse enthalten). Dank paralleler Ausführung großer Teile der ALU werden SIMD-Befehle (Single Instruction Multiple Data) unterstützt, so dass der Prozessor bei voller Auslastung 2 GFLOPS (Giga Floating Point Operations per Second) verrichten kann. Multi-Prozessor-Einsatz wird durch Link Ports unterstützt. Mit dem DMA (Direct Memory Access) Controller lassen sich große Datenblöcke ein- und ausgeben, ohne dass die Rechenkapazität des Prozessors reduziert wird. Auf der Versuchshardware ist ein solcher Prozessor vorhanden. Desweiteren befindet sich auf derselben Platine ein externer Speicher (SDRAM), der Platz für 4 Mega-Wort Daten beinhaltet (32-Bit Worte) sowie ein 1 MB großer nichtflüchtiger Speicher (Flash-EEPROM). Zur Peripherie gehören außerdem ein AD/DA-Wandler (AD1835A), über den die Audioein- und ausgabe abläuft, sowie eine UART-Schnittstelle (ADM3202 RS-232), die der Laufzeit- Komunikation mit dem PC dient. Die Audiodaten werden mit einer Abtastfrequenz von bis zu 96 KHz, in der Regel aber 48 KHz eingelesen (bei einem DAC sogar bis zu 192Hz) und mit 16, 20 oder 24 Bit quantisiert. Die UART-Schnittstelle hat eine Datenübertragungsrate von 9600 bis 115200 Baud und dient der Übergabe von Variablen vom PC an den DSP und andersherum. Die einzelnen Prozessor-Kennzahlen sind in Tabelle 1.2 zusammengefasst. Prozessortyp ADSP-21369 Datentyp Gleitkomma (32 oder 40 Bit) Festkomma (16 oder 32 Bit) Speicher 2 MB SRAM + 6 MB ROM + 512 kBit SRAM + 4 Mx32 SDRAM + 8 MBit parallel flash + 2 Mbit SPI flash Taktfrequenz 333 MHz Analoge Ausgänge 4 Stück, Stereo Analoge Eingänge 1 Stück, Stereo Abtastraten bis zu 96 kHz 16, 20 oder 24 Bit Analoge Verstärkung Vor- und Nachverstärkung Schnittstelle UART, 16550, 115200 Baud Tabelle 1.2: Prozessor-System-Merkmale Abbildung 1.3 zeigt das vereinfachte Blockschaltbild des ADSP-21369. Es handelt sich um 12
  • 13. eine „Super Harvard-Architektur“ (daher SHARC) mit SIMD-Funktionalität. Abbildung 1.3: Vereinfachtes Blockschaltbild des ADSP-21369 Der Prozessorkern (core processor) des ADSP-21369 besteht aus zwei Verarbeitungseinhei- ten (PEX und PEY), von denen jede aus drei Recheneinheiten (ALU, Multiplizierer, Shif- ter) besteht sowie einem Programm-Steuerwerk, zwei Daten-Adressrechnern (DAG1 und DAG2) mit jeweils acht Registern für indirekte Adressierung, zwei Timern, dem Befehls- Cache und aus 16 Data-Registern im Data Register File. Darüber hinaus existieren meh- rere Modus- und Statusregister, die die Funktion des Prozessors steuern (z. B. die Register MODE1 und MODE2) und Aussage über Rechenergebnisse geben (z. B. das ASTAT Register). Diese Register sind nicht in Abbildung 1.3 eingezeichnet. Weiterhin sind in obiger Abbildung die DMA-Controller, acht full-duplex-fähige seriel- le Schnittstellen, eine digitale Audioschnittstelle, die vier Präzisionstaktgeber (PCG), ei- ne Eingabeschnittstelle (IDP), ein S/PDIF-Empfänger/-Sender, acht Kanäle mit jeweils ei- nem asynchronen Abtastratenkonverter, acht serielle Schnittstellen, eine 16-bit Parallelein- gabeschnittstelle (PDAP) und eine flexible Signal-Routing-Einheit (DAI SRU) enthält so- wie ein Digital-Peripheral-Interface dargestellt, das drei Taktgeber, eine I2C-Schnittstelle, zwei UARTs, zwei serielle periphere Schnittstellen (SPI) und eine flexible Signal-Routing- Einheit (DPI SRU) enthält. Wie oben schon erwähnt, verfügt der ADSP-21369 über SIMD-Funktionalität. Generell wird die Verarbeitungseinheit PEX benutzt. Eine gleichzeitige Verwendung der Einheit PEY kann durch Setzen des PEYEN-Mode-Bits im MODE1-Register aktiviert werden. Ist dies der Fall, so werden die selben Instruktionen in beiden Verarbeitungseinheiten ausgeführt, operieren allerdings auf verschiedenen Daten. Diese Architektur ist besonders bei rechen- intensiven Algorithmen effizient. Das Einschalten des SIMD-Modus’ hat auch eine Auswirkung auf die Art und Weise, wie Daten zwischen Speicher und den beiden Verarbeitungseinheiten übertragen wird. Ist dieser Modus aktiviert, so wird eine doppelte Datenbandbreite gebraucht, um den Rechenfluss in beiden Einheiten aufrecht zu erhalten, so dass im SIMD-Modus mit jedem Zugriff auf 13
  • 14. den Speicher oder die Register also zwei Datenwerte transferiert werden. Dementsprechend müssen die Daten auch im Speicher auf korrekte Weise abgelegt werden müssen. Bevor nun die Einheiten des Prozessors näher betrachtet werden, sollen erst die zur Verfü- gung stehenden Datenformate erwähnt werden: 1.2.2 Datenformate Der ADSP-21369 bietet sowohl Fest- als auch Gleitkomma-Formate an. Mit der Festkomma- darstellung wird eine Zahl durch 32 Bits repräsentiert. In einem Register im Data Register File belegen sie die obersten 32 der 40 Bits. Man unterscheidet zwischen den Darstellungen signed und unsigned bzw. integer und fractional. Beim signed-Format ist das ers- te Bit das Vorzeichenbit. Negative Zahlen werden durch das Zweierkomplement dargestellt. Der Wert des LSBs ist für signed integer gleich 1 bzw. für signed fractional 2−31 . So ergeben sich die Zahlenbereiche − 231 ≤ x ≤ 231 − 1 (signed integer, SI) (1.4) −31 −1 ≤ x ≤ 1 − 2 (signed fractional, SF). (1.5) Mit dem unsigned-Format können nur positive Zahlen dargestellt werden. Es gelten die Zahlenbereiche 0 ≤ x ≤ 232 − 1 (unsigned integer, UI) bzw. 0 ≤ x ≤ 1 − 2−32 (unsigned fractional, UF). Die Gewichte der einzelnen Bits sind in Abbildung 1.4 verdeutlicht. Abbildung 1.4: Die Gewichte einzelner Bits verschiedener Festkommafor- mate bei Speicherung in einem 40-Bit Register Zusätzlich zu der Festkommadarstellung bietet der ADSP-21369 ein Gleitkomma-Format mit entweder 32 Bits oder 40 Bits an. Es besteht aus einem Vorzeichenbit s, 8 Bits für den Exponenten e und 23 bzw. 31 Bits für den Bruchteil f der Basis, der durch 1. f dargestellt wird. 1. f ist dabei eine Zahl zwischen 1 und 2 − 2−23 bzw. 1 und 2 − 2−31 . Der Wert einer Zahl x ergibt sich dann aus dem Zusammenhang x = (−1)s · (1. f ) · 2e−127 (1.6) Abbildung 1.5 zeigt die Bitbelegung im Speicher. Durch die Gleitkommadarstellung lassen sich Quantisierung und Übersteuerungsprobleme weitgehend vermeiden. Sie bietet sich deswegen bei der Entwicklung neuer Algorithmen und Prototypen an. 14
  • 15. Abbildung 1.5: Gleitkomma-Formate für 32 bzw. 40 Bits 1.2.3 Recheneinheiten und Datenregister Der Prozessorkern enthält wie in Abbildung 1.6 veranschaulicht drei unabhängige Rechen- einheiten: eine ALU, einen Multiplizierer und einen Shifter. Abbildung 1.6: Aufbau der Core Unit Alle drei Datenformate können verarbeitet werden: 32 Bit Festkomma, 32 Bit Gleitkomma bzw. 40 Bit Gleitkomma. Zwischen den Recheneinheiten und den Datenbussen befinden sich die Datenregister (register file). Sie bestehen aus 16 Registern der Breite 40 Bit, in de- nen Rechenoperanden und Ergebnisse gespeichert werden. Da alle Rechenoperationen nur einen Prozessorzyklus benötigen, können die Ergebnisse eines Zyklus’ im darauffolgenden Zyklus beliebig weiterverwendet werden. Ein Register wird mit „F“ und einer Nummer 0-15 angesprochen, wenn es für Gleitkomma- operationen verwendet wird, und mit „R“ und einer Nummer für Festkommaoperationen. Das MR Register dient zur Speicherung eines Fixed-Point-Multiplikations Ergebnisses. 15
  • 16. Um einen schnellen Kontextwechsel zu ermöglichen, stehen alle Register in zweifacher Ausführung zur Verfügung. Die Modifikation eines entsprechenden Statusbits verursacht, dass alle Prozessoroperationen auf diesen „Schatten“-Registern ausgeführt werden. ALU Die ALU verfügt über eine Vielzahl arithmetischer und logischer Operationen für sowohl Festkomma- als auch Gleitkommadarstellungen. Für eine umfassende Liste dieser Opera- tionen sei auf das Handbuch verwiesen. Hier ein kleines Beispiel: Beispiel: 1. Addiere den Inhalt des Registers F0 zu dem des Registers F1 und spei- chere das Ergebnis in F0 F0 = F0 + F1; 2. Nimm den Betrag von F0 und speichere das Ergebnis in F1 F1 = ABS F0; 3. Nimm den maximalen Wert von R1 und R2 und speichere das Ergebnis in R0 R0 = MAX (R1, R2); Alle Befehle sowie „F“ und „R“ können entweder groß oder klein geschrieben werden, da der Assembler Groß- und Kleinschreibung nicht unterscheidet. In dem Statusregister ASTAT befinden sich Flaggen, die nach dem Beenden einer ALU-Operation gesetzt wer- den. Z. B. wird die Flagge AZ (Bit 0) gesetzt, wenn das Ergebnis der Operation Null ist. Abbildung 1.7 zeigt die Bedeutung der einzelnen Bitstellen des Statusregisters ASTAT. Abbildung 1.7: Aufbau des ASTAT-Registers Die ALU wird auch für bitbezogene Operationen wie logische AND, OR, NOR und NOT verwendet. Beispielsweise können mit AND einzelne Bits herausmaskiert und mit OR ein- 16
  • 17. zelne Bits gesetzt werden. Außerdem kann mit XOR kontrolliert werden, in welchen Posi- tionen sich zwei Register unterscheiden. Die logischen Operationen sind nur für Festkom- maoperanden definiert und haben nur einen Einfluss auf die oberen 32 Bits eines Registers. Die letzten 8 Bits werden zu Null gesetzt. Abbildung 1.8: Beispiel für ALU-Operationen Im Register MODE1 befinden sich drei Flaggen, mit denen u.a. entschieden wird, ob das Ergebnis einer Festkommaoperation ggf. gesättigt werden soll und wie Gleitkommaresultate gerundet werden sollen, siehe Handbuch, Abschnitt 2.5.2. Eine vollständige Beschreibung des MODE1-Registers befindet sich im Handbuch auf den Seiten E-14 und E-15. Multiplizierer Mit dem Multiplizierer können Festkomma- oder Gleitkommamultiplikationen durchge- führt werden. Das Resultat einer Festkommamultiplikation kann in einem der beiden Mul- tiplikatorregister (MRF oder MRB) oder in einem Datenregister R0 - R15 gespeichert wer- den. Bei Nutzung der Multiplikatorregister kann im selben Zyklus eine Addition zu oder Subtraktion von dem letzten Inhalt des Registers vorgenommen werden. Beispiel: 1. Multipliziere den Inhalt des Registers R0 mit dem von R1. Das Ergebnis wird zum Inhalt von MRF addiert. MRF = MRF + R0 · R1; Auf diese Art und Weise kann sehr einfach eine multiply/accumulate-Operation implemen- tiert werden. Das Standardformat für Festkommamultiplikationen ist signed fractional. Wenn eine andere Darstellung erwünscht ist, muss diese explizit angegeben werden. Dies erfolgt, in- dem nach dem Befehl in Klammern die Buchstaben S oder U bzw. I oder F angefügt werden, siehe Abschnitt 2.6.6 des Handbuches. Hierbei bezeichnen: • S signed • U unsigned • I integer 17
  • 18. • F fractional Beide Operanden müssen entweder vom Typ integer oder fractional sein. Signed und unsi- gned sind mischbar. Beispiel: 1. Die Zahlen in R1 und R2 sind beide vom Format signed fractional R0 = R1 · R2; oder R0 = R1 · R2 (SSF); 2. Die Zahlen in R1 und R2 sind beide vom Format unsigned integer R0 = R1 · R2 (UUI); 3. Die Zahl in R1 ist unsigned fractional und die in R2 signed fractional. Das Ergebnis soll abgerundet werden R0 = MRF - R1 · R2(USFR); Eine Gleitkomma multiply/accumulate-Operation wird durch parallele Nutzung der ALU und des Multiplizierers durchgeführt. Dabei ist jedoch zu beachten, dass für die Addition in dem Beispiel der Wert in F8 zur Berechnung gewählt wird, der einen Takt zuvor bestimmt wurde. Weiterhin sind die zu verwendenden Register einer Begrenzung unterworfen (siehe hierzu auch Handbuch S. B-95). Beispiel: 1. Berechne C := A · B + C Die Werte von A, B und C liegen in F1, F2 bzw. F12. F8 = F1 · F2, F12 = F8 + F12; Genau wie die ALU hat auch der Multiplizierer eine Wirkung auf das Statusregister. Bei- spielsweise kann mit dem MN-Bit im ASTAT-Register kontrolliert werden, ob das Ergebnis einer Multiplikation negativ ist. Shifter Der Shifter stellt die dritte Recheneinheit dar. Mit dem Shifter kann z. B. der Inhalt eines Re- gisters verschoben werden. Der Shifter arbeitet grundsätzlich nur in Festkommaarithmetik, d.h. nur mit den oberen 32 Bits eines Registers. Die letzten 8 der 40 Bits im Resultatre- gister werden immer zu Null gesetzt. Der Shifter hat auch eine Wirkung auf das ASTAT Register. Zusätzlich zu den normalen Shift-Funktionen bietet der Shifter die Möglichkeit zur Manipulation und zum Test einzelner Bits. Der Befehl zur Verschiebung des Inhaltes eines Registers heißt LSHIFT (Logic shift). Die Wirkung wird durch das folgende Beispiel illustriert. 1.2.4 Das Programm-Steuerwerk Das Programm-Steuerwerk (Program Sequencer), siehe Abbildung 1.3, steuert den Ablauf des Programms. Dieser ist meistens linear (sequentiell). Abweichungen von diesem linearen Fluss werden durch die fünf Programmstrukturen loop, jump, subroutine, interrupt und idle ermöglicht. Diese Strukturen sind in Abbildung 1.10 dargestellt. 18
  • 19. Abbildung 1.9: Beispiel für Funktionalität des Shifters Der Kern des Programmsteuerwerks besteht aus dem Programmzähler (Program Counter, PC). Dieser enthält am Anfang eines Zyklus’ die Adresse des durchzuführenden Befehls und wird während des Zyklus’ hochgezählt. Ein Sprung im Programm geschieht, indem dem PC eine neue Adresse gegeben wird. Alle oben erwähnten Programmstrukturen beste- hen auf die ein oder andere Weise aus Programmsprüngen. Ein Sprung erfolgt im allgemei- nen zu einem in Assembler deklarierten „label“ (Sprungmarke). Die Sprungmarke besteht aus einer willkürlichen, nicht reservierten Zeichenfolge gefolgt von einem Doppelpunkt, z. B. „counter:“ oder „loop1:“. Bei Schleifen gibt die Sprungmarke den letzten Befehl der Schleife an. Kommentare können im Assemblerprogramm wie in C-Programmen zwischen „/*“ und „*/“ eingebettet werden. Sie helfen später sowohl dem Programmierer als auch anderen, die mit dem Quellencode zu tun haben, das Programm zu verstehen. Die Programmstrukturen werden im folgenden kurz erklärt: Loop Eine Schleife (loop) lässt sich sehr bequem durch den loop counter (LCNTR) implementieren. In LCNTR wird dabei zuerst die Zahl der Wiederholungen angegeben. Mit dem Befehl DO < label > UNTIL LCE (loop counter expired) wird die Schleife ausgeführt. Das notwendige Label < label > bezeichnet den letzten Befehl des zu iterierenden Loops. Beispiel: Zähle R0 von 0 bis 100 R0 = 0; LCNTR = 100, DO counter UNTIL LCE; counter: R0 = R0 + 1; /* this is the last instruction of the loop */ Jump Durch einen Sprung (jump) lässt sich eine Programmverzweigung implementieren. Der Sprung kann entweder unbedingt oder bedingt sein. Bei einem bedingten Sprung wird zu- 19
  • 20. Abbildung 1.10: Verschiedene Programmstrukturen erst eine Flagge in einem Register, das u. a. vom ASTAT-Register abhängig ist, kontrolliert. Wenn diese Flagge eins ist, erfolgt der Programmsprung, im anderen Fall nicht. Unter anderem gibt es die Flaggen EQ Result equal to zero NE Result not equal to zero LT Result less than zero LE Result less than or equal to zero AV Addition overflow MV Multiplier overflow Beispiel: Wenn R0 − R1 ≤ 0, springe nach negative R2 = R0 -R1; IF LE JUMP negative; positive: ... negative: ... Mit dem JUMP-Befehl kann auch eine Schleife implementiert werden. 20
  • 21. Beispiel: R0 = 0; R1 = 100; increase: R0 = R0 + 1; COMP (R0,R1); IF NE JUMP increase; ... Subroutine Eine Subroutine kann mit einem Unterprogramm verglichen werden, zu dem jederzeit ge- sprungen werden kann und von dem automatisch an die richtige Stelle im Hauptprogramm wieder zurückgesprungen wird, wenn das Unterprogramm zu Ende ist. Mit dem Befehl CALL wird der Sprung initiert und mit RTS (Return From Subroutine) wird die Subroutine beendet. Vor dem Sprung wird die aktuelle Programmadresse auf den Stack gelegt. Durch RTS wird sie wieder dem Programmzähler zurückgegeben. Ein CALL kann genau wie JUMP sowohl unbedingt als auch bedingt sein. Beispiel: IF MV CALL overflow; ... overflow: /* multiplier overflow*/ ... /* do something! */ RTS; Man beachte den Unterschied zwischen JUMP und CALL. Bei JUMP handelt es sich um einen einfachen Sprung zu einer anderen Stelle im Programm, wo das Programm weiter läuft. Mit CALL soll nur gesprungen werden, wenn durch RTS auch ein Sprung zurück gemacht wird. Es ist wichtig, dass alle Paare CALL-RTS zusammenpassen. Wird ein Sprung durch RTS ver- langt, ohne dass zu der Subroutine mit CALL gesprungen wurde, folgt ein Programmfehler, weil auf dem Stack die falsche (oder gar keine) Retour-Adresse vorhanden war. Interrupts Interrupts stellen eine sehr flexible und effiziente Lösung für das Handhaben von Ereignis- sen dar und müssen von jedem Assembler-Programmierer beherrscht werden. Ein Interrupt ist ein Ereignis, das einen Sprung zu einer vordefinierten Adresse auslöst. Das Ereignis kann entweder intern im Prozessor auftreten (z. B. ein ALU-Overflow) oder extern (z. B. wenn ein neuer Abtastwert vorliegt). Der ADSP-21369 hat vier externe Hardware-Interrupts, inklusi- ve eines speziellen Reset-Interrupts, und eine Vielzahl interner Interrupts, siehe Abbildung 1.11. Für die Programmsteuerung bei Interrupts gibt es die Interruptvektortabelle, vergleiche den beispielhaften Programmablauf in Abbildung 1.12. Beim Auslösen eines Interrupts wird zu der dem Interrupttyp entsprechenden Adresse ge- sprungen (Schritt 1). Im allgemeinen enthält diese Adresse den Befehl JUMP, so dass das 21
  • 22. Interrupt Vector Table ADSP-21369 Emulator (read-only, HIGH PRIORITY 0x90000 + 0x00 0 EMUI non-maskable) Reset (read-only RSTI 0x04 1 non-maskable) Illegal input condition 2 IICDI 0x08 detected Status loop or mode 0x0C 3 stack overflow; or PC SOVFI stack full Timer=0 (high 0x10 4 TMZHI priority option) SPERRI 0x14 SP error interrupt 5 Hardware breakpoint BKPI 0x18 6 interrupt 0x1C 7 Reserved 0x20 8 IRQ2I IRQ2I asserted 0x24 9 IRQ1I IRQ1I asserted 0x28 10 IRQ0I IRQ0I asserted ... ... ... ... User Software 0x98 28 SFT0I Interrupt 0 User Software 0x9C 29 SFT1I Interrupt 1 User Software 0xA0 30 SFT2I Interrupt 2 User Software 0xA4 31 SFT3I LOW PRIORITY Interrupt 3 Abbildung 1.11: Inhalt der Interrupt-Vector-Tabelle Programm mit einer Interrupt-Subroutine fortfahren kann (Schritt 2). Am Ende der Interrupt- Subroutine wird mit RTI (Return From Interrupt) zu der Adresse im Programm zurückge- sprungen, die der Programmzähler enthielt, als der Interrupt ausgelöst wurde (Schritt 3). Bei einem externen Interrupt wird zuerst der Inhalt des ASTAT-Registers und des MODE1- Registers sowie die Adresse des Programmzählers (PC) vor dem Sprung auf den Stack ge- legt. Durch RTI werden diese Registerwerte vom Stack zurückgenommen. Für externe Inter- rupts und für den Timer-Interrupt ist eine Verschachtelungstiefe (nesting) von vier möglich. Folgendes Beispiel erläutert die Verwendung von Timer-Interrupts: Beispiel: 1. Es soll ein Timer-Interrupt jede 1ms ausgelöst werden. 1ms entspricht 6000010 = EA6016 Zyklen bei 60 MHz, vergleiche Abschnitt 11 des Handbuches (zu beachten: Der Prozessor verfügt über zwei völlig gleichwertige Timer-Sektionen 0 und 1) /* timer interrupt address (high Prio timer IRQ)*/ .SEGMENT/PM pm_tmzhi; JUMP timer_interrupt; .ENDSEG; ... 22
  • 23. Abbildung 1.12: Programmablauf beim Auslösen des Interrupts IRQ1 /* global interrupt disable*/ BIT CLR MODE1 IRPTEN; /* Timer disable and setup first*/ BIT CLR MODE2 TIMEN0; /* stop timer */ BIT SET MODE2 PWMOUT0; /* set PWMOUT modus */ TPERIOD0 = 0xEA5F; /* 60000 - 1 */ /* timer interrupt enable*/ BIT SET IMASK TMZHI; /* start timer (set counter to 0)*/ BIT SET MODE2 TIMEN0; /* global interrupt enable*/ BIT SET MODE1 IRPTEN; ... timer_interrupt: ... /* Process timer-interrupt service*/ RTI; Beim Start oder Reset eines Programms startet der Prozessor immer bei der Adresse des Reset-Interrupts. Diese ist für den ADSP-21369 gleich 0x90005. Dementsprechend muss an dieser Speicherstelle ein Sprung zum Programmanfang vorhanden sein. Dies kann durch den folgenden Programmcode erreicht werden. 23
  • 24. Beispiel: /* reset interrupt address */ .SEGMENT/PM pm_rti; JUMP prog_start; .ENDSEG; ... /* the program begins here */ prog_start: ... Idle Mit dem Befehl IDLE wird der Prozessor angehalten bis ein externer Interrupt oder ein Timer-Interrupt auftritt. Im Gegensatz zu einer endlosen Warteschleife, die mit dem Be- fehl JUMP implementiert werden kann, wird mit IDLE der Prozessor in einen „low-power“- Zustand versetzt. Nach dem Rücksprung aus der Interrupt-Subroutine wird die Programma- barbeitung mit dem Befehl fortgesetzt, der IDLE folgt. 1.2.5 Datenadressierung Für die Berechnung von Adressen im Programm- und Datenspeicher stehen zwei Daten- adressrechner (data address generators, DAG) zur Verfügung. Mit diesen wird eine indirekte Adressierung ermöglicht, d.h. anstatt die tatsächliche Speicherstelle im Programm anzuge- ben, wird sie durch den DAG berechnet. In jedem der zwei DAG gibt es acht Adressregister, die I-Register oder Index-Register ge- nannt werden. Der DAG1, der Adressen für den Datenspeicher (DM) (siehe Abschnitt 4.2.6) berechnet, enthält die Register I0 bis I7, während der DAG2, der Adressen für den Pro- grammspeicher (PM) berechnet, über die Register I8 bis I15 verfügt. Die Zuordnung der Adressierungs-Register zu Programm-/Datenspeicher ist durch die Tat- sache bedingt, dass der Programm-Speicher Adressbus nur 24 Bit breit ist. Somit sind auch alle Register der zweiten Adressierungslogik nur 24 Bit breit. Mit den zugehörigen Modify-Registern (M0-M7 für DAG1 bzw. M8-M15 für DAG2) kann eine Adresse vor oder nach dem Speicherzugriff hoch- oder runtergezählt (inkrementiert bzw. dekrementiert) werden. Hierdurch wird u.a. eine laufende Abspeicherung oder ein laufen- des Auslesen von Daten ermöglicht, ohne dass dem Index-Register manuell ein neuer Wert gegeben werden muss. Die Adressrechner werden mit den Befehlen DM bzw. PM angespro- chen. Diese Befehle haben zwei Argumente: ein I-Register bzw. ein M-Register oder einen konstanten Modify-Wert. Bei post-modify Adressierung erfolgt erst der Speicherzugriff und dann die Berechnung des neuen Inhalts vom I-Register. Die Syntax lautet dann DM (Ia, Mb) oder PM (Ic, Md), wobei a und b Zahlen zwischen 0 und 7 und c bzw. d Zahlen zwi- schen 8 und 15 sind. Bei pre-modify wird die neue Adresse berechnet bevor der Zugriff erfolgt. Hierfür wird die Syntax DM(Ma, Ib) oder PM(Mc, Id) verwendet. 24
  • 25. Beispiel: 1. Lade in R6 den Inhalt der Speicherstelle 0x0000C000 des Datenspei- chers. R6 = DM(0x0000C000); oder I0 = 0x0000C000; R6 = DM (I0, 0); 2. Lade in R6 den Inhalt der DM-Speicherstelle, die in I5 vorgegeben ist, und zähle danach die Adresse in I5 um 2 hoch R6 = DM (I5, 2); 3. Addiere die Adresse in I8 mit dem Wert in M10, und speichere danach den Inhalt von R0 an der neu berechneten PM-Adresse (M10 kann negativ sein) PM (M10, I8) = R0; Beispiel: 1. Berechne die Summe N der Elemente in den Speicherstellen DM(I0) bis DM(I0+N-1), für N=10. #define N 10 /* number of elements */ F0=DM (I0,1); F1=DM(I0,1); LCNTR = N-1, DO endloop UNTIL LCE; /* result in F0 */ endloop: F0 = F0 +F1, F1 = DM (I0, 1); Ablauf der Schleife: in DM(I0) bis DM(I0+N-1) sind die Zahlen a0 ... aN−1 vorhanden. Iteration LCNTR F0 F1 Initialisierung N-1 a0 a1 i=1 N-2 a0 +a1 a2 ... N−2 i = N-2 1 m=0 ak aN−1 N−1 i = N-1 0 m=0 ak undefiniert Zyklische Daten-Puffer Zyklische Daten-Puffer werden für effiziente Implementierungen von Filtern, Verzögerungs- gliedern und anderen, in der digitalen Signalverarbeitung häufig vorkommenden Struktu- ren eingesetzt. Die Implementierung zyklischer Daten-Puffer, sog. Ringspeicher (circular buffer), wird durch Modulo-Adressierung erheblich erleichtert. Hierfür werden die base- Register (B) und die length-Register (L) verwendet. Ein B-Register enthält dabei die Basi- sadresse eines Ringspeichers und L die Anzahl der Elemente (die Länge). Das Register L0 und das Register M0 gehören immer zusammen, usw.. 25
  • 26. Abbildung 1.13: Beispiel eines zyklischen Puffers Nach Initialisierung der B und L-Register wird zuerst die Basisadresse dem entsprechenden I-Register automatisch übergeben. Bei einer post-modify Modifizierung des I-Registers (ei- ne pre-modify Modifizierung ist bei zyklischen Puffern nicht erlaubt) wird kontrolliert, ob die neue Adresse innerhalb des Bereichs zwischen B und B+L-1 liegt. Wenn dies der Fall ist, wird die neue Adresse behalten. Wenn sie zu groß ist, wird die Länge L subtrahiert, und dementsprechend wird L addiert, wenn sie kleiner als B ist. Dadurch ergibt sich immer die neue Adresse durch den Zusammenhang Ia := Ba + (Ia + Mb − Ba) mod La (1.7) a und b können verschiedene Zahlen aus den Bereichen 0-7 oder 8-15 sein (DM bzw PM). Es ist notwendig, dass |Mb| < La. Wie die Register der ALU stehen auch die Register der Adressierungslogik doppelt zur Verfügung, um einen schnellen Kontext Wechsel zu ermöglichen. Beispiel: 1. Es soll ein Verzögerungsglied implementiert werden. Die Verzögerung beträgt 20 Abtastwerte. Der Eingangswert ist beim Aufruf der Subrou- tine delay_20 (wird mit call aufgerufen) in DM(I6) vorhanden und der (verzögerte) Ausgangswert soll in DM(I7) geschrieben werden. /* base address*/ B0 = 0x0C200; /* length 2010 = 1416 */ L0 = 0x14; ... /* read oldest data from buffer */ delay_20: F0 = DM(I0,0): 26
  • 27. /* write output data */ DM(I7, 0) = F0; /* read input data */ F0 = DM (I6, 0); /* put data in circular buffer, * address is increased by one*/ DM(I0, 1) = F0; RTS; 1.2.6 Speicher Der Programm- und Datenspeicher Der im Praktikum eingesetzte Prozessor ADSP-21369 hat 2 MB on-chip und 4 Mega Wort externen Speicher, der grob in zwei Kategorien aufgeteilt wird: der Programmspeicher (PM - Program Memory) und der Datenspeicher (DM - Data Memory). Die Wortbreite 32 Bit wird für Fest- und Gleitkommadaten verwendet. Es können auch 48-Bit Wörter definiert werden, die entweder Befehle oder 40-Bit Gleitkommadaten enthalten. Schließlich steht auch ein 16-Bit Format für Festkommadaten zur Verfügung. Die Aufteilung des gesamten Speichers in Segmente kann weiterhin für jede Anwendung spezifisch bestimmt werden. Hierfür wird ein sogenanntes Link-Description-File (LDF) angegeben, in dem Symbolen (Namen) physikalische Adressen zugeordnet werden. • Im Adressraum sind die internen Speicherbereiche in Blöcke aufgeteilt, weiterhin gibt es jeweils einen Normal-Word- und einen Short-Word-Bereich. Die vorgegebe- nen Adress-Grenzen müssen dementsprechend auch im Link-Description-File einge- halten werden, für eine genaue Zuordnung der Blöcke zu den Adressen sei auf das Handbuch verwiesen. • Der externe Speicher ist ebenfalls im Adressraum des ADSP 21369 vorgesehen, der schliesslich verwendete Adressbereich ist schaltungstechnisch bedingt von Adresse 0x00200000 bis 0x08FF0000 anzusprechen, näheres hierzu kann der Beschreibung der EZKIT-Hardware entnommen werden. Auf dieselbe Art und Weise sind auch die Steuerungs- und Datenregister der anderen Peripherien (z. B. UART ADM3202) Teil des Adressraums (siehe wiederum Manual zu EZKIT). Im PM können sowohl Programmbefehle als auch Daten gespeichert werden. Im Datenspei- cher (DM) können ausschließlich Daten gespeichert werden. In sowohl PM als auch DM kön- nen auch Wörter anderer Breiten verwendet werden. In diesem Fall ändert sich die Adres- sierung, siehe auch hierzu Kapitel „External Memory Interface“ im Handbuch. Instruktionen müssen über den 32 Bit breiten Programmspeicher Adressbus angefordert werden, weshalb diese sich nur in den entsprechenden Teilen des Speichers befinden kön- nen. Die PM/DM-Datenbusse Über die PM und DM Datenbusse (PMD bzw. DMD ) werden die Befehle und Daten zwischen dem Speicher und den verschiedenen Einheiten des Prozessors verschoben. Wie im PM so- 27
  • 28. wohl Befehle als auch Daten gespeichert werden können, so kann der PM Datenbus Befehle zum Programmrechenwerk oder auch Daten zu z. B. den Registern transportieren, jedoch nicht gleichzeitig. Der parallele Datenbus ermöglicht zwei gleichzeitige Speicherzugriffe. So kann im selben Zyklus sowohl ein neuer Befehl vom PM als auch ein Wert vom DM gelesen werden. Hierbei wird die Adresse im PM vom Programmsteuerwerk über den PM Adressbus (PMA) und die Adresse im DM über den DM Adressbus (DMA) vermittelt. Alternativ können, wenn der auszuführende Befehl schon im Cache-Speicher vorhanden ist, beide Datenbusse für den Transport von Daten verwendet werden. Vom PM und DM kann dann jeweils ein Wert einem Register übergeben werden - alles innerhalb eines Zyklus’. Dieses Verfahren wird dual data access genannt. Um dieses zu ermöglichen, empfiehlt es sich immer, die zu verarbeitenden Daten zu trennen (z. B. Filterkoeffizienten im Programm- speicher und Abtastwerte im Datenspeicher). Weiter muss der Befehl in der Form compute, DM read or write, PM read or write; sein, zum Beispiel R0=R0+R1, DM(I1, M1)=R0, R1=PM(I8, M8); Wenn der Befehl nicht im Cache-Speicher liegt, werden zusätzliche Zyklen benötigt. 1.3 Entwicklungsumgebung: Visual DSP++ 1.3.1 Einführung Im Laufe der letzten Jahre wurde die Hardware im Bereich Prozessoren immer weiter ent- wickelt. Die heutigen Architekturen sind im allgemeinen sehr leistungsstark, und die Wahl eines DSPs für einen Algorithmus wird somit auch von Faktoren jenseits der Performance mitbestimmt. Zu diesen anderen Faktoren zählt insbesondere die zur Verfügung stehende Software. Die „Time to market“, also der Zeitrahmen, dessen es bedarf, ein Produkt auf den Markt zu bringen, kann durch guten Software-Support drastisch verkürzt werden. C- Compiler gehören hierbei zum Standard. Analog Devices liefert zu den Sharc-DSPs die Software Visual DSP++. In Anlehnung an die Entwicklungsumgebung Visual Studio unter Windows können Algorithmen hiermit schneller implementiert werden. Im Folgenden soll eine kurze Einführung in die Umgebung Visual DSP++ gegeben werden: Das Software-Entwicklungspaket von Analog Devices ist eine IDE (Integrated Develop- ment Environment). Dazu gehören Tools zur Erstellung der Software (z. B. Editor) sowie welche zur Verifikation des erstellten Software (z. B. Debugger). Da die Release von Visual DSP++, die im Praktikum verwendet wird, regelmässig auf den neusten Stand gebracht wird, können sich zu den im folgenden präsentierten Bildern unter Umständen leichte Abweichungen ergeben. 28
  • 29. Abbildung 1.14: Aufruf der Entwicklungsumgebung Visual DSP++ 1.3.2 Implementierung des Source-Codes Für die Entwicklung eines Algorithmus’ unter Visual DSP++ sowie unter allen Visual- Umgebungen ist der Begriff Projekt von großer Bedeutung: Ein Projekt umfasst die Gesamtheit aller zu der Implementation einer Anwendung gehö- rigen Module. Ein Modul kann zum Beispiel eine Text-Datei sein, in der Code in einer Programmiersprache gespeichert ist, oder eine vorkompilierte Bibliothek, auf deren Metho- den zugegriffen wird. Die Module eines Projektes werden gegebenenfalls kompiliert und gelinkt. Sie bilden somit die Basis für einen ausführbaren Algorithmus. Im einfachsten Fall besteht ein Projekt aus einer Datei, die den gesamten Source-Code enthält. Starten der Entwicklungsumgebung Die Entwicklungsumgebung Visual DSP++ wird wie unter Windows üblich aus dem Start- Menü gestartet (siehe Abbildung 1.14). Die Bedienung gestaltet sich wie in den meisten Fällen sehr intuitiv. Sollte in einer vorher- gehenden Sitzung ein Projekt bearbeitet worden sein, so erscheint dieses Projekt direkt zu Beginn. Es können Unterfenster für das Projekt selbst (A), aber auch für Quellcode (B) bzw. Prozessor-Zustände (z. B. Disassembly(C)) angezeigt werden (siehe Abbildung 1.15). Im Projekt-Fenster wird angezeigt, welche Dateien alle Teil des Projekts sind. Sollte hier noch kein Projekt angezeigt werden, so muss erst eins angelegt werden bzw. ein vorhande- nes eingeladen werden. 29
  • 30. A C B Abbildung 1.15: Fenster nach Programmstart Menüpunkte In Abbildung 1.15 ist zu erkennen, welche Menüpunkte es bei Visual DSP++ gibt. Die wichtigen Unterpunkte werden im folgenden kurz aufgelistet: • Menüpunkt File: In diesem Menüpunkt können Dateien geladen oder gespeichert werden. Dabei wer- den Projekte und Textdateien im gleichen Dialog ausgewählt. Desweiteren kann auf den DSP ein ganzes Programm bzw. in den Debugger die Symboltabelle eines Pro- gramms geladen werden (Unterpunkte Load ...). Für einen beschleunigten Zugriff stehen Links zu kürzlich geöffneten Projekten usw. bereit (Unterpunkte Recent ...). • Menüpunkt Edit: In diesem Menüpunkt kann Text editiert werden. Dabei stehen die üblichen Opera- tionen wie Copy/Paste zur Verfügung. • Menüpunkt Session: In diesem Menüpunkt kann die aktuelle Session gewählt werden. Im Falle des Prak- tikums dient dies insbesondere der Wahl zwischen der Emulation mithilfe des JTAG- Interfaces (V3+Projektphase) und der Simulation (V1+V2). Andere Sessions werden im Rahmen dieses Praktikums nicht verwendet. • Menüpunkt View: In diesem Menüpunkt können Fenster angezeigt bzw. nicht angezeigt werden. Ins- besondere kann wie in Abbildung 1.19 angedeutet (Plot) auch ein Speicherbereich grafisch ausgegeben werden. 30
  • 31. Abbildung 1.16: File-Dialog • Menüpunkt Projekt: In diesem Menüpunkt können Projekt spezifische Operationen vorgenommen wer- den. Abbildung 1.20 veranschaulicht die Möglichkeiten, die wichtigsten Funktionen im einzelnen: – Add to Project: Hiermit können einem Projekt Module hinzugefügt werden. – Build File: Hiermit können einzelne Module kompiliert werden. – Build Project: Hiermit werden alle Module eines Projekts kompiliert (sofern notwendig) und zusammengelinkt. – Rebuild all: Hiermit werden sämtliche Projekte wie unter Menüpunkt Build Project bearbei- tet, die momentan geöffnet sind. – Project Options: Compile- und Link-Options können hier spezifiziert werden. • Menüpunkt Register: Dieser Menüpunkt dient dem Debuggen eines gerade auf dem DSP ablaufenden Pro- gramms. Es können hier Register des DSPs zur Anzeige ausgewählt werden. Für eine Benutzung im Rahmen des Praktikums ist insbesondere die Anzeige der inaktiven Register wichtig (Inactive Registers). • Menüpunkt Memory: In diesem Menüpunkt können Speicherbereiche angezeigt werden. Die Daten an den 31
  • 32. Abbildung 1.17: Edit-Dialog entsprechenden Speicherstellen können in verschiedenem Format dargestellt werden. In den meisten Fällen ist eine Darstellung im Format Two Column sinnvoll. Mit dem Befehl Dump können ganze Speicherbereiche auch direkt in einer Datei gespeichert werden. Dies ist nützlich, um Rechenergebnisse zum Beispiel mit Matlab zu verifi- zieren. • Menüpunkt Debug: Im Menüpunkt Debug kann der Debugger gestartet und kontrolliert werden. • Menüpunkt Settings: In diesem Menüpunkt können Einstellungen vorgenommen werden. Insbesondere können hier Breakpoints aufgelistet und Interrupts simuliert werden (siehe V1). Vorgehensweise bei der Erzeugung von Objekt-Codes (DSP Executable) Im Laufe der Versuche dieses Praktikums und in der anschließenden Projektphase soll das Rahmenprogramm erweitert und auf die Applikation angepasst werden. Hierzu sollen dem Projekt Module hinzugefügt werden. Nachdem dies geschehen ist, werden alle Module er- neut zusammengelinkt. Dabei werden eventuell aufgetretene Fehler im Ausgabefenster an- gezeigt. Sofern die Anwendung komplett erzeugt wurde, wird das auszuführende Programm direkt in den Programmspeicher des DSP geladen. Der Prozessor hält direkt an und erwartet weitere Instruktionen. Ausführen des Programms Zur weiteren Ausführung des geladenen Sourcecodes wird F5 gedrückt. Alle Anzeige- Fenster werden zu diesem Zeitpunkt deaktiviert. Sofern ein zuvor eingestellter Breakpoint 32
  • 33. Abbildung 1.18: Session-Dialog erreicht wird, hält die Ausfühung an, und alle Ausgabefenster werden aktualisiert. Mit SHIFT-F5 kann der Prozessor auch zu jedem anderen Zeitpunkt angehalten werden. Setzen von Breakpoints Mit F9 kann an der Stelle der aktuellen Eingabeposition ein Breakpoint gesetzt werden. Dies ist jedoch nur möglich, wenn der Prozessor gerade nicht im laufenden Zustand ist. Ausführung Instruktion für Instruktion Wenn der Prozessor angehalten wurde, sei es aufgrund von Breakpoints oder manuell, kann mit F11 der Programmcode Schritt für Schritt abgearbeitet werden (sog. durchsteppen). Zu bedenken ist jedoch, dass auch im angehaltenen Modus Interrupts ausgelöst werden können. Aus diesem Grunde springt der Prozessor zumeist beim Durchgehen Instruktion für Instruktion in die nächste Interrupt Service Routine höherer Ordnung. Vorgehen beim Debuggen Ein DSP-Object-Code wird wie beschrieben eingeladen. Daraufhin kann der Code gedebug- ged werden. Zumeist wird nur ein Teilaspekt untersucht, der in einer Unterfunktion imple- mentiert wurde. Um den zugehörigen Source-Code anzuzeigen, muss der Program-Counter (PC) auf einer Stelle stehen, die zu der zu untersuchenden Funktion gehört. Nach Programmstart muss hierfür der Disassembly-Output nach einem Symbol in der Funk- tion ( z. B. Funktionsname ) durchsucht werden. Dies geschieht durch Betätigung der rech- ten Maustaste sowie Aufruf der Goto-Funktionalität. Die Aktivierung von Browse führt zu 33
  • 34. Abbildung 1.19: View-Dialog einer Auflistung aller existierenden Symbole. Nach Auffinden des Symbols wird ein Break- point gesetzt. Nun wird der Programmcode bis zum Breakpoint ausgeführt (Run, F5). 1.4 Versuchsdurchführung 1.4.1 Einführung Die nun folgenden Programmbeispiele sollen schrittweise in die Programmierung des ADSP- 21369 einführen. Beachten Sie bitte, dass die ersten zwei Programme im Simulator-Modus ausgeführt werden und erst das dritte Beispiel auf dem DSP emuliert wird. Ziel der hier durchgeführten ersten beiden Versuche ist das Erlernen und Verstehen von Prinzipien Hard- ware-naher Programmierung and der Funktionsweise des DSPs auf Assembler-Programm- Ebene. Der dritte Versuch dient der Einarbeitung in die vorgegebene Software RTProcDSP. Da dieses Programm in C/C++ programmiert wurde, geschieht von diesem Zeitpunkt an auch die Programmierung der Algorithmen in C/C++. Es sei jedoch darauf verwiesen, das es im Verlauf des Projekts notwendig sein kann, Fragmente der Programme in Assembler zu realisieren, um die Ausführungsgeschwindigkeit des DSPs zu erhöhen. Für die Spezifi- kation der Schnittstelle zwischen C/C++ und Assembler sei auf die Anleitung in der DSP Literatur „C/C++ Compiler and Library Manual for Sharc Processors“ verwiesen. • Im Programm 1 werden Daten interruptgesteuert ein- und ausgelesen. Die von ei- ner Datei in einen Ringspeicher eingelesenen Werte können in einer Interruptroutine modifiziert werden und anschließend in einen Speicherbereich ausgegeben werden. Hierbei behandeln wir auch den Aufbau von Ringspeichern mit Hilfe der Modulo- Adressierung. 34
  • 35. Abbildung 1.20: Project-Dialog • Das Programm 2 zeigt die Anwendung von Befehlen für die parallele Verarbeitung von Multiplikations- und Additionsbefehlen anhand eines Tiefpass-Filters. • Zum Schluss wird das Programm RTProcDSP vorgestellt. Da es im folgenden die Grundlage zur Umsetzung der Projekte bildet, werden alle funktionalen Merkmale an kleinen Übungsbeispielen verdeutlicht. 1.4.2 Programm 1: Interruptgesteuerte Ein-/Ausgabe Der Sinn dieses Programms besteht darin, einen schnellen Einstieg in die Assemblerpro- grammierung zu geben, insbesondere sollen zyklische Datenspeicher und die Programm- steuerung durch Interrupts dargestellt werden. Unter einem Interrupt (engl. für Unterbrechung) versteht man eine von dem Prozessor ge- steuerte Unterbrechung des sequentiellen Programmablaufs. Stellen wir uns den sequenti- ellen Programmablauf so vor, dass ein Ablaufzeiger (oder auch Program Counter) nachein- ander die Speicherstellen anzeigt, die das Programm abarbeiten soll, dann ist ein Interrupt eine Unterbrechung, in der der Zeiger auf eine vorher vereinbarte Speicherstelle „umge- bogen“ wird. An dieser Stelle kann dann auch ein Verweis auf ein Unterprogramm stehen oder direkt ein kurzes Unterprogramm vorhanden sein, das bearbeitet wird. Nach dem Ende dieses Unterprogrammes wird der Programmcode wieder an alter Stelle aufgenommen und weiter sequentiell bearbeitet. Starten Sie das VisualDSP++ Environment und wählen Sie zunächst eine Session zur Pro- zessor-Simulation aus (sollte so eine Session auf Ihrem Rechner noch nicht vorhanden sein, kontaktieren Sie den Betreuer). Laden Sie anschliessend das Projekt V1. Um das Programm auf dem DSP auszuführen, müssen Sie zunächst alle Dateien kompilieren und linken (Pro- 35
  • 36. Abbildung 1.21: Register-Dialog ject → Build Project oder F7) und dann die Programmausführung beginnen (Debug → Run oder F5). Die Ausführung des Programms bleibt nun zu Beginn der _main-Routine an ei- nem Breakpoint stehen. Von hier aus können alle Schritte des Programms durch F11 einzeln ausgeführt werden. Programmcode von Projekt 1 Das vorliegende Programmbeispiel V1.asm aus dem Projekt V1 liest interruptgesteuert einen Wert aus dem mit input angegebenen Speicherbereich in ein Register. Anschliessend wird dieser Wert an den mit output bezeichneten Speicherplatz weitergegeben. Es ist als ein Pro- grammierbeispiel anzusehen und soll später gemäß der Aufgabenstellung modifiziert wer- den. Es ist sinnvoll, den Programmcode parallel zu dieser Beschreibung zu lesen. Der physikalische Speicherplatz wird durch ein sogenanntes Link-Description-File (LDF) in logische Segmente aufgeteilt. Durch den Linker werden die Symbole (z. B. Namen von Variablen) im Programmcode mit den physikalischen Speicheradressen verbunden, wobei das LDF dafür die Regeln spezifiziert (in „Linker & Utilities Manual for ADSP-21xxx Family DSPs“ wird dieser Vorgang illustriert). Den verschiedenen Segmenten werden wei- terhin unterschiedliche Bedeutungen als Program- oder Datamemory zugewiesen. Zur Ver- anschaulichung hier nun der Auszug aus dem verwendeten Link-Description-File V1.ldf: 36
  • 37. Abbildung 1.22: Debug-Dialog ARCHITECTURE(ADSP-21369) MEMORY { seg_rth { TYPE(PM RAM) START(0x00090000) END(0x000900ff) WIDTH(48) } seg_pmco { TYPE(PM RAM) START(0x000902D0) END(0x000903FF) WIDTH(48) } seg_pm64 { TYPE(PM RAM) START(0x0004c6c0) END(0x0004dfff) WIDTH(64) } seg_dm64 { TYPE(DM RAM) START(0x0005d800) END(0x0005d81f) WIDTH(64) } seg_pm40 { TYPE(PM RAM) START(0x00090400) END(0x000904ff) WIDTH(48) } seg_dm40 { TYPE(DM RAM) START(0x000b0000) END(0x000b01ff) WIDTH(48) } seg_pm32 { TYPE(PM RAM) START(0x00098c00) END(0x00098cff) WIDTH(32)} seg_dm32 { TYPE(DM RAM) START(0x000b8400) END(0x000bafff) WIDTH(32) } } Das LDF wird bearbeitet, indem mit der rechten Maustaste auf die Datei geklickt wird, um dort dann die Option Open with Source Window zu wählen. Die symbolischen Namen der Segmente im LDF, zum Beispiel seg_dm32, werden im Quellcode von V1.asm wiederver- wendet, um dort Variablen einem bestimmten Speicherbereich zuzuordnen. Eine besondere Rolle spielt das Segment seg_rth, in dem der Programmcode des Interrupt- Vector-Tables abgelegt wird. Zugehörig findet man das Assembler-Programm in der Datei 21369_IVT.asm. Im folgenden soll nicht weiter auf das Link-Description-File eingegangen werden, da dieses in der Regel unverändert übernommen werden kann. Die beiden Assembler Programmcode-Dateien 21369_IVT.asm und V1.asm werden nun einzeln erläutert. In der Datei 21369_IVT.asm werden die Instruktionen im Interrupt-Vector- Table spezifiziert. Der Programmcode ist eine Eins-zu-Eins-Abbildung der Tabelle in Ab- bildung 1.11. Insbesondere wird hier das auszuführende Programm angesprungen, sobald ein Reset-Interrupt ausgelöst wurde (Zeile 15). Um eine Interrupt gesteuerte Eingabe zu ermöglichen, ist weiterhin eine jump-Instruktion an der Position von IRQ0, Zeile 69, einge- 37
  • 38. Abbildung 1.23: Settings-Dialog fügt. Diese dient dem Aufruf der Funktion _convolution bei jedem Eintritt der Interrupt- Ereignisses. In der Datei V1.asm wird der tatsächliche Programmcode der _main- Funktion sowie der Interrupt-Service-Routine _convolution aufgelistet. Bei Programmausführung dient die _main-Funktion der Initialisierung. In dieser Funktion werden die Adress-Generatoren so eingestellt, dass anschliessend die Einlese-Operation erfolgreich verläuft. Am Ende der _main-Routine versetzt sich der Prozessor in den idle-Modus, um Energy zu sparen (Zeile 53). Aufgaben • Öffnen Sie die Datei V1.ldf im Source Window. Lokalisieren Sie die Speicher- Segmente und identifizieren sie die verwendeten Segmente in den beiden Programm- codedateien. An welcher Adresse liegt die Variable output? • Starten Sie die Programmausführung. Diese hält am ersten Breakpoint sofort wieder an. Das Programm und alle Variablen wurden zu diesem Zeitpunkt bereits in den Speicher geladen. Öffnen Sie die folgenden Fenster zur Betrachtung – des Disassembly-Outputs und des zugehörigen Programmcodes. – des relevanten Adress-Generators (DAG). – des Datenspeichers – der Interrupt-Register. Plotten Sie das Signal, das im Speicher zur Variable input gespeichert ist. Wählen Sie dafür die Option View → Debug Windows → Plot → New. Wählen sie den dar- zustellenden Speicherbereich mithilfe der Browse-Funktionalität aus. Beachten Sie, 38
  • 39. dass sie das Zahlenformat (Float) und die Länge richtig einstellen. Verfizieren Sie die Richtigkeit der Darstellung anhand der Zahlenwerte, die sie durch Darstellung des Speichers (Memory → Two Column) ablesen können. • Führen Sie das Programm nun Schritt für Schritt bis zum Erreichen der IDLE-Instruktion aus (durchsteppen), indem Sie die Taste F11 bedienen. Beobachten Sie die Initia- lisierung der Interruptregister und der für die Verwaltung des zirkulären Speichers notwendigen Register. Was bedeuten die Kürzel A,D,P,F und der gelbe Pfeil? • Nach der Initialisierung kann das Programm mit F5 (Run) ausgeführt werden. Da wir uns im Simulations-Modus befinden kann ein auftretender externer Interrupt nur si- muliert werden. Dies geschieht durch Auswahl von Settings → Interrupts . Wählen Sie den Interrupt IRQ0 und eine sinnvolle Eistellung für die Interrupt-Periode, sowie die verbleibenden Einstellmöglichkeiten. Was bedeuten die einzelnen Parameter? Be- achten Sie, dass die Aktivierung des Interrupts durch Hinzufügen (ADD) geschieht. • Bevor Sie nun die Ausführung mit F5 weiterlaufen lassen, muss ein Breakpoint an der ensprechende Stelle im Interrupt Vector Table eingefügt werden. Überlegen Sie, an welcher Stelle dieses sinnvoll ist • Verändern Sie das Programm in der Interruptroutine, indem Sie den Befehl R0 = ABS R0; benutzen, um den Betrag des Eingangssignals am Ausgang zu erhalten. Erklären Sie das (unerwartete) Ergebnis. • Für die Experten: In der Vorgabe ist ein Speicher-Zugriffsfehler. Können Sie diesen identifizeren und wenn ja, wie ist er zu beheben? Programmcode 21369_IVT.asm // 21369 Interrupt Vector Table // .extern _main; .extern _convolution; .section/pm seg_rth; __EMUI: // 0x00: Emulator interrupt (highest priority, read-only, non-maskable) nop; nop; nop; nop; __RSTI: // 0x04: Reset (read-only, non-maskable) nop; // <-- (this line is not executed) jump _main; nop; nop; __IICDI: // 0x08: Illegal Input Condition Detected jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SOVFI: // 0x0C: Status loop or mode stack overflow or PC stack full jump (pc,0); jump (pc,0); jump (pc,0); 39
  • 40. jump (pc,0); __TMZHI: // 0x10: Core timer interrupt (higher priority option) jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SPERRI: // 0x14: jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __BKPI: // 0x18: Hardware breakpoint interrupt jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __res1I: // 0x1C: (reserved) jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __IRQ2I: // 0x20: IRQ2 is asserted jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __IRQ1I: // 0x24: IRQ1 is asserted jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __IRQ0I: // 0x28: IRQ0 is asserted nop; jump _convolution; rti; rti; __DAIHI: // 0x2C: DAI interrupt (higher priority option) __P0I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SPIHI: __P1I : // 0x30: SPI transmit or receive (higher priority option) __SPII : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __GPTMR0I: // 0x34: General Purpose timer 0 interrupt __P2I : 40
  • 41. jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP1I: // 0x38: SPORT 1 interrupt __P3I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP3I: // 0x3C: SPORT 3 interrupt __P4I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP5I: // 0x40: SPORT 5 interrupt __P5I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP0I: // 0x44: SPORT 0 interrupt __P6I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP2I: // 0x48: SPORT 2 interrupt __P7I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP4I: // 0x4C: SPORT 4 interrupt __P8I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __EP0I: // 0x50: External port0 interrupt. Thats the only label we’re using here __P9I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __GPTMR1I: // 0x54: General Purpose timer 1 interrupt __P10I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP7I: // 0x58: serial port 7 interrupt 41
  • 42. __P11I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __DAILI: // 0x5C: DAI interrupt (lower priority option) __P12I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __EP1I: // 0x60: External port1 interrupt __P13I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __DPII: // 0x64: DPI interrupt __P14I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __MTMI: // 0x68: Memory to Memory interface interrupt __P15I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SP6I: // 0x6C: serial port 6 interrupt __P16I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __GPTMR2I: // 0x70: General Purpose timer 2 interrupt __P17I : jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SPILI: // 0x74: SPI transmit or receive (lower priority option) __P18I : __SPIBI: jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __CB7I: // 0x78: Circular buffer 7 overflow exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); 42
  • 43. __CB15I: // 0x7C: Circular buffer 15 overflow exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __TMZLI: // 0x80: Core timer interrupt (lower priority option) jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __FIXI: // 0x84: Fixed-point overflow exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __FLTOI: // 0x88: Floating-point overflow exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __FLTUI: // 0x8C: Floating-point underflow exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __FLTII: // 0x90: Floating-point invalid exception jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __EMULI: // 0x94: Emulator low priority interrupt jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SFT0I: // 0x98: User software interrupt 0 jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SFT1I: // 0x9C: User software interrupt 1 jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SFT2I: // 0xA0: User software interrupt 2 jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); __SFT3I: // 0xA4: User software interrupt 3 (lowest priority) 43
  • 44. jump (pc,0); jump (pc,0); jump (pc,0); jump (pc,0); Programmcode V1.asm /***************************************************************************** * V1.asm *****************************************************************************/ #include <def21369.h> .SECTION/PM seg_dm32; #define SAMPLES 9 /* Input */ .VAR input[SAMPLES]= -4.,-3.,-2.,-1. ,0., 1.,2.,3.,4.; /* Output */ .VAR output[SAMPLES]= 0.,0.,0.,0.,0.,0.,0.,0.,0.; .ENDSEG; .SECTION/PM seg_pmco; /* Set the scope of the ’_main’ symbol to global. This makes the symbol available for reference in object files that are linked to the current one. Use ’.EXTERN’ to refer to a global symbol from another file.*/ .GLOBAL _main; /* Declare the ’_main’ symbol. */ _main: /* Set bit called IRPTEN to enable interrupts */ BIT SET MODE1 IRPTEN; /* Set irq0i interrupt bit */ BIT SET IMASK IRQ0I; /* set value for modify-register M0 */ M0=1; /* set length of ringbuffer B0 */ L0=@input; /* name buffer B0, I0 is set at the same time */ B0=input; /* set length of ringbuffer B1 */ L1=@output; /* name buffer B1, set I1 */ B1=output; /* Switch to low power mode and expect interrupt */ end: 44
  • 45. idle; JUMP end; /* Delimit the ’_main’ symbol so the linker knows which code is associated with the symbol. */ ._main.END: .GLOBAL _convolution; _convolution: /* put the current value of buffer addressed by I0 to register F0 and increase buffer with M0 */ R0=DM(I0,M0); /* Here the modification for the input value can be placed: Calculate the absolute value (ASM insn abs) */ /* put value from register F0 to buffer B1 and increase with M0 */ DM(I1,M0)=R0; _convolution.END: RTI; .ENDSEG; 1.4.3 Programm 2: Parallele Verarbeitung von Befehlen In diesem Programm sollen die besonderen Vorzüge des DSP für eine schnelle Verarbeitung von Signalen anhand eines Tiefpass-FIR-Filters dargestellt werden. Das Programm realisiert eine Faltung: m−1 y(n) = a(k)x(n − k), (1.8) k=0 wobei a(k) die Filterkoeffizienten, x(n-k) die um k verzögerten Eingangswerte und y(n) die berechneten Ausgangswerte sind. Das FIR-Filter benutzt vordefinierte Eingangswerte, die in einem Puffer eingeladen sind, und Koeffizienten, die in einer Datei abgelegt sind. Zeitlich zurückliegende Eingangswerte werden in einem zyklischen Speicher als sogenannte States berücksichtigt. Das Programm stellt ein Filter der Länge 23 dar, das auf 200 vordefinierte Werte angewendet wird. Es wird durch einen Interrupt wiederholt aufgerufen. Das zugehörige Projekt V2 ist im Verzeichnis V2 abgelegt. Zusätzlich zu den Quellcode- Dateien werden Variablenfelder in Dateien angegeben: • Eine Datei mit Filterkoeffizienten fircoefs.dat • Eine Datei mit dem Eingabesignal rect.dat Die Filterkoeffizienten werden bei Versuchstermin 4 (s. Kap. 4.8.4) wiederverwendet. Ziel dieses Versuches ist, die Funktion des Programmes durch Debuggen zu verstehen. Da der Algorithmus (vom prinzip her) bekannt ist, soll zunächst eine Referenzimplementierung in Matlab erstellt werden, die das Verständnis des DSP Codes erleichtern soll. 45
  • 46. Aufgaben • Vorarbeit: Laden Sie die Datenfelder in den Dateien fircoefs.dat und rect.dat als FIR Filterkoeffizienten and Eingangswerte respektive in Matlab ein. Zum Einladen dient der load-Befehl. Realisieren Sie das FIR Filter als Matlab Funktion und verifizieren Sie Ihre Version mit der filter Funktion. Realisieren Sie Ihre Funktion in der Form, dass die Filterzustände als Parameter mit übergeben und wieder zurückgegeben wer- den (analog zur filter-Funktion und der DSP Version). • Öffnen Sie nun das Projekt V2. Verwenden Sie den Interrupt IRQ0 wie bei der ers- ten Aufgabe und setzen Sie einen Breakpoint an der Stelle, von wo aus jeweils die _filter-Routine angesprungen wird. • Vollziehen Sie die Ausführung des Programms nach. Versuchen Sie, die Verarbei- tung von Hand (auf Papier) auszuführen. Was bedeutet der Zusatz (dB) in Zeile 99? Welche Variable im DSP Code entsprechen den Größen h(k), x(k) und x(k − N)? Was genau passiert während der Interrupt-Service-Routine? Wozu dient die XOR- Verknüpfung in Zeile 146? Was passiert, wenn statt der Register R8, R12 und R4 andere Register verwendet werden? Plotten Sie inbuf und outbuf, wenn die Verar- beitung aller Eingangssamples beendet ist. Plotten Sie auch die Koeffizienten im Feld coefs. • Wie könnte man die FIR-Routine verkürzen, wenn eine Rechengenauigkeit von 32 bit integer ausreicht? Programmcode V2 /******************************************************** * * V2.ASM FIR filterprogram for ADSP21369 * Filename: V22.asm * * Description: * * The program shows how to effectivly perform a convolution * with the multiple instructions feature of the ADSP-21369 * * Registers affected: * * F0 F8 I0 I1 * F4 F12 I8 I2 * * Used parameters: * F0 = input sample x(n) * R1 = number of taps in the filter minus 1 * B0 = address of the delay line buffer * M0 = modify value for the delay line buffer * L0 = length of the delay line buffer * B8 = address of the coefficent buffer * M8 = modify value of the coefficent buffer * L8 = length of the coefficent buffer * ********************************************************/ #define SAMPLE 200 /*number of input samples to be filtered*/ #define TAPS 23 /*length of filter*/ 46
  • 47. #include <def21369.h> .SECTION/PM seg_pm32; /*FIR coefficients stored in file */ .VAR coefs[TAPS]=quot;fircoefs.datquot;; .ENDSEG; .SEGMENT/DM seg_dm32; /*buffer that holds the delay line*/ .VAR dline[TAPS]; /*input samples stored in file */ .VAR inbuf[SAMPLE] = quot;rect.datquot;; /*buffer that contains output coefficients*/ .VAR outbuf[SAMPLE]; .ENDSEG; .SECTION/PM seg_pmco; /* Set the scope of the ’_main’ symbol to global. This makes the symbol available for reference in object files that are linked to the current one. Use ’.EXTERN’ to refer to a global symbol from another file.*/ .GLOBAL _main; /* Declare the ’_main’ symbol. */ _main: /*enable interrupts*/ BIT SET MODE1 IRPTEN; /* enable circular buffering */ BIT SET MODE1 CBUFEN; L0=TAPS; /*delay line buffer pointer initialisation*/ B0=dline; /*set modify-register M0=1*/ M0=1; /*set modify-register M1=1*/ M1=1; L1=@inbuf; /*input buffer pointer initialisation*/ B1=inbuf; L2=@outbuf; /*output buffer pointer initialisation*/ B2=outbuf; L8=TAPS; 47
  • 48. /*coefficient buffer pointer initialisation*/ B8=coefs; /*set modify-register M8=1*/ M8=1; /*initialize delay line buffer to zero*/ CALL fir_init (DB); /* Set coefficient to second filter coeff */ MODIFY(I8,M8); R0=TAPS; /*enable interrupt IRQ0I*/ BIT SET IMASK IRQ0I; done: /*wait for interrupt */ JUMP done; fir_init: LCNTR=R0, DO zero1 UNTIL LCE; zero1: /*initialize the delay line to 0*/ DM(I0,M0)=0; R0=SAMPLE; LCNTR=R0, DO zero2 UNTIL LCE; zero2: /*initialize the output buffer to 0*/ DM(I2,M1)=0; RTS; /* Delimit the ’_main’ symbol so the linker knows which code is associated with the symbol. */ ._main.END: .GLOBAL _filter; _filter: /* Filter one input sample. */ CALL fir(DB); /* At first setup the loop counter for circular buffer */ R1=TAPS-3; /* Read in h(1) (the second filter coefficient) and x(k-1) */ R8=R8 XOR R8, F0=DM(I0,M0), F4=PM(I8,M8); /* ======> Call fir subroutine */ /*result is stored in outbuf */ DM(I2,M1)=F0; RTI; 48