(→Aufsummieren in einer Schleife) |
(→Aufsummieren in einer Schleife) |
||
Zeile 73: | Zeile 73: | ||
Function Sum_n_loop(byval N As Integer) As Integer | Function Sum_n_loop(byval N As Integer) As Integer | ||
− | |||
− | |||
− | |||
− | |||
Sum_n_loop = 0 | Sum_n_loop = 0 | ||
− | + | While N > 0 | |
− | While | + | Sum_n_loop = Sum_n_loop + N |
− | + | Decr N | |
− | + | ||
− | Sum_n_loop = Sum_n_loop + | + | |
− | + | ||
Wend | Wend | ||
− | |||
− | |||
End Function | End Function | ||
− | |||
</pre> | </pre> | ||
}} | }} | ||
Zeile 114: | Zeile 104: | ||
| | | | ||
<pre> | <pre> | ||
− | + | ||
− | + | ;--------------------------------------------------------- | |
− | + | ; Function Sum_n_loop(byval N As Integer) As Integer | |
− | : | + | ;--------------------------------------------------------- |
− | + | L_0x00B4: | |
− | + | ||
− | + | ;--------------------------------------------------------- | |
− | + | ; Sum_n_loop = 0 | |
− | + | ;--------------------------------------------------------- | |
− | + | ||
− | : | + | LDI r24,0x00 ; clear |
− | : | + | LDI r25,0x00 ; |
− | : | + | LDD XL,Y + 2 ; return value addr (softstack) |
− | : | + | LDD XH,Y + 3 |
− | : | + | ST X+,r24 ; |
− | : | + | ST X,r25 |
− | : | + | |
− | : | + | L_0x00C0: |
− | : | + | |
+ | ;--------------------------------------------------------- | ||
+ | ; While N > 0 | ||
+ | ;--------------------------------------------------------- | ||
+ | LDD XL,Y + 0 ; argument addr (softstack) | ||
+ | LDD XH,Y + 1 | ||
+ | LD r16,X+ ; load r16:r17 | ||
+ | LD r17,X | ||
+ | CPI r16,0x00 ; LOW <> 0 ? | ||
+ | LDI r21,0x00 | ||
+ | CPC r17,r21 ; HIGH <> 0 ? | ||
+ | BRLT L_0x00D6 ; branch lower ->function exit | ||
+ | BREQ L_0x00D6 ; branch equal ->function exit | ||
+ | JMP L_0x00DA ; continue | ||
+ | L_0x00D6: | ||
+ | JMP L_0x0102 ; jmp function exit | ||
+ | |||
+ | L_0x00DA: | ||
+ | ;--------------------------------------------------------- | ||
+ | ; Sum_n_loop = Sum_n_loop + N | ||
+ | ;--------------------------------------------------------- | ||
+ | LDD XL,Y + 2 ; summ_n_loop | ||
+ | LDD XH,Y + 3 | ||
+ | LD r16,X+ ; into r16:r17 | ||
+ | LD r17,X | ||
+ | LDD XL,Y + 0 ; N | ||
+ | LDD XH,Y + 1 | ||
+ | LD r20,X+ ; into r20:r21 | ||
+ | LD r21,X | ||
+ | ADD r16,r20 ; add r16, r20 | ||
+ | ADC r17,r21 ; add+cy r17, r21 | ||
+ | LDD XL,Y + 2 ; | ||
+ | LDD XH,Y + 3 | ||
+ | ST X+,r16 ; store sum | ||
+ | ST X,r17 | ||
+ | ;--------------------------------------------------------- | ||
+ | ; Decr N | ||
+ | ;--------------------------------------------------------- | ||
+ | LDD XL,Y + 0 | ||
+ | LDD XH,Y + 1 | ||
+ | CALL L_0x0114 | ||
+ | ;--------------------------------------------------------- | ||
+ | ; Wend | ||
+ | ;--------------------------------------------------------- | ||
+ | JMP L_0x00C0 ; reenter loop | ||
+ | ;--------------------------------------------------------- | ||
+ | L_0x0102: | ||
+ | RET ; end function | ||
+ | ;--------------------------------------------------------- | ||
+ | ; library function : decrement integer | ||
+ | ;--------------------------------------------------------- | ||
+ | L_0x0114: | ||
+ | LD ZL,X+ | ||
+ | LD ZH,X | ||
+ | SBIW ZL,0x0001 | ||
+ | ST X,ZH | ||
+ | ST -X,ZL | ||
+ | RET | ||
</pre> | </pre> | ||
+ | '''Remark''': Das reine Register-rechnen (GCC) macht Bascom nicht. Er arbeitet immer im SRAM , brav mit Load & Store. (PicNick) | ||
}} | }} | ||
Version vom 24. April 2006, 18:50 Uhr
Ein wichtiges Merkmal eines Compilers ist die Güte des erzeugten Codes. Immerhin will man seine Hardware optimal nutzen, und die geschriebenen Programme sollen möglichst wenig Laufzeit brauchen und möglichst wenig Speicher – also RAM und Flash – belegen.
Ein Vergleich der erzeugten Codes ist jedoch nicht einfach, denn ein Problem kann bereits innerhalb ein und der selben Programmiersprache auf sehr unterschiedliche Art und Weisen formuliert oder gelöst werden.
Dieser Artikel versucht ansatzweise einen Codevergleich weit verbreiteter AVR-Compiler anhand sehr einfacher Aufgaben, die "geradeaus" und ohne Umschweife programmiert wurden.
Ein Vergleich der Programmierung von Hardware-Komponenten und Peripherie wie Timer-, UART- oder I2C-Module scheint dabei weniger interessant, denn obwohl die Codes zum Steuern dieser Komponente in unterschiedlichen Sprachen recht verschieden aussehen, werden sie doch auf die selben Maschinen-Codes abgebildet, die sich im wesentlichen auf das Setzen und Lesen von Registern (SFRs) reduzieren. Neben diesen für jedes Programm essenziellen Abschnitten, besteht ein Programm aber zum großen Teil aus hardwareunabhängigen Aufgaben wie Registerverwaltung, Funktionsaufrufen, Schleifen, Abfragen, Zuweisungen, Parameterübergaben, Abfragen, Arithmetik, etc.
Interessanter erscheint ein Vergleich einfacher Aufgaben, die erkennen lassen, wie gut ein Compiler in der Lage ist, die Ressourcen eines Mikrocontrollers zu nutzen bzw. zu schonen.
Inhaltsverzeichnis
Rahmenbedingungen
- avr-gcc
- Die Assembler-Ausgaben wurden mit der Optimierungsstufe "auf Größe optimieren" (-Os) für einen ATmega8 erstellt. GCC-Version war 3.4.x. Andere Optimierungsstufen haben wenig bis keinen Einfluss auf den erzeugtenCode. Codes für andere Controller der ATmega-Familie unterscheiden sich praktisch nicht vom ATmega8-Code.
Summe der ersten n Zahlen
Berechnet wird die Summe der ersten n Zahlen:
- [math] \operatorname{sum}(n) \,=\, \sum_{k=1}^n k \,=\, 1 + 2 + \ldots + n [/math]
Die Zahl n wird als 16-Bit Zahl angegeben und das Ergebnis als 16-Bit-Zahl berechnet. Ein eventueller Überlauf wird nicht beachtet.
Der Code wird jeweils als eigene Funktion implementiert, um Abhängigkeiten vom umliegenden Code zu vermeiden.
Für diese Berechnung gibt es mehrere Möglichkeiten.
Aufsummieren in einer Schleife
Quellcodes:
|
|
Compilat:
|
|
Berechnung mit rekursiver Funktion
Quellcodes:
|
|
Compilat:
|
|
Berechnung durch Formel
Quellcodes:
|
|
Compilat:
|
|
Interrupt-Routinen
Auch diese Beispiele machen nicht viel. Das erste zählt nur eine 16-Bit Variable hoch, das zweite macht nichts weiter, als ein Funktionsaufruf.
Eine Variable hochzählen
Quellcodes:
|
|
Compilat:
|
|
Eine Funktion aufrufen
Quellcodes:
|
|
Compilat:
|
|
Sortieren mit Bubble-Sort
Zum Abschluss noch ein komplexeres Beispiel: Ein Array mit 8-Bit-Werten soll mit Bubble-Sort der Größe nach sortiert werden.
Im Array wird nach dem größten Wert gesucht und dieser ans Ende getauscht. Danach macht man den Teilbereich, in dem man das Maximum sucht, um 1 kleiner, bis man fertig ist. Die größten Zahlen wandern wie Blasen nach oben, daher der Name Bubble-Sort für diesen Sortier-Algorithmus.
Variablen:
- n Array-Größe
- a das Array
- i Größe der Teilbereichs
- j Laufvariable durch den Teilbereich
Quellcodes:
|
|
Compilat:
|
|
Die Codes wurden etwas nachkommentiert und -formatiert, um besser den Zusammenhang mit der Quelle durchblicken zu können.