Hallo,
Auf http://www.rn-wissen.de/index.php/Avr-gcc/Interna#Registerverwendung
steht: 1 | R0, R18 – R27, R30, R31
| 2 | können durch Funktionsaufrufe verändert werden, ohne restauriert zu werden
|
Ich habe noch keinen Code im Netz gesehen (in Assemblerfunktionen), der
die diese Register nutzt ohne sie zu sichern. Muss man sie nun sichern
oder nicht? r0 muss man auf keinem Fall sichern, oder?
Sollte man sie sichern müssen:
Wenn ein Byte an eine Funktion in r24 übergeben wird, darf man das
zugehörige zerstören (r25)?
Samuel K. schrieb:
> Muss man sie nun sichern oder nicht?
Nein, außer die Funktion ist eine ISR.
Samuel K. schrieb:
> r0 muss man auf keinem Fall sichern, oder?
Außer die Funktion ist eine ISR.
Stefan Ernst schrieb:
> Samuel K. schrieb:
>> Muss man sie nun sichern oder nicht?
>
> Nein, außer die Funktion ist eine ISR.
>
> Samuel K. schrieb:
>> r0 muss man auf keinem Fall sichern, oder?
>
> Außer die Funktion ist eine ISR.
Ach du schon wieder ;)
Danke für die Antwort. Dass es in der ISR nicht erlaubt ist, ist klar.
Da hat der Compiler schließlich kaum Einfluss.
Samuel K. schrieb:
1 | > R0, R18 – R27, R30, R31
| 2 | > können durch Funktionsaufrufe verändert werden, ohne restauriert zu
| 3 | > werden
|
> Ich habe noch keinen Code im Netz gesehen (in Assemblerfunktionen), der
> die diese Register nutzt ohne sie zu sichern.
Das Zitat bezieht sich auf die Registerverwendung im avr-gcc. Wenn ein
Assembler-Code nicht mit avr-gcc zusammenarbeitet, dann braucht er sich
um dessen ABI auch keine Gedanken zu machen.
Übrigens gibt's auch entsprechende Codebeispiele:
AVR Arithmetik: Wurzel
http://www.mikrocontroller.net/articles/AVR_Arithmetik/Sinus_und_Cosinus_(CORDIC)#cordic-asm.S
Johann L. schrieb:
> Das Zitat bezieht sich auf die Registerverwendung im avr-gcc. Wenn ein
> Assembler-Code nicht mit avr-gcc zusammenarbeitet, dann braucht er sich
> um dessen ABI auch keine Gedanken zu machen.
Ja ich meinte Assemblerfunktionen in C-Programmen.
Kann man avrgcc sagen, dass er nicht so viele Register für (bestimmte)
Funktionen bereitstellen soll? Ich habe eine Funktion in meinem
Programm, welche nur Funktionen aufruft (50% Asm-Funktionen). Am Anfang
dieser Funktion sichert avrgcc erstmal ein Haufen Low-Register. Meine
Funktion brauchen gar nicht so viele Register - das push/pop ist für die
Katz.
Samuel K. schrieb:
> Am Anfang
> dieser Funktion sichert avrgcc erstmal ein Haufen Low-Register. Meine
> Funktion brauchen gar nicht so viele Register - das push/pop ist für die
> Katz.
Er sichert nur die Register, dir er in der Funktion selbst verwendet.
Fürs Sichern der Register einer aufgerufenen Funktion ist diese selbst
verantwortlich.
Ausnahme: Es handelt sich um einen Interrupt-Handler. Da er nicht weiss,
welche der Scratch-Register in den aufgerufenen Funktionen verwendet
werden, muss er alle davon sichern. Das sind aber überwiegend
High-Register.
Beispiel: 1 | extern void callee (int);
| 2 |
| 3 | void caller (int n)
| 4 | {
| 5 | callee (n);
| 6 | callee (n+1);
| 7 | callee (2);
| 8 | }
|
Ob callee in asm implementiert ist oder in C ist dem Compiler egal. For
einen ATmega8 und mit rößenoptimierung wird das übersetzt zu 1 | caller:
| 2 | push r28
| 3 | push r29
| 4 | movw r28,r24
| 5 | rcall callee
| 6 | movw r24,r28
| 7 | adiw r24,1
| 8 | rcall callee
| 9 | ldi r24,lo8(2)
| 10 | clr r25
| 11 | pop r29
| 12 | pop r28
| 13 | rjmp callee
|
Da werden keine low-Register gesichert. Allerdings muss n gesichert
werden (hier in Y), weil es den ersten Funktionsaufruf überleben muss.
Avrgcc sichert hier 7 Register, obwohl er ohne Probleme r0, r18, r26,
r27, r30, r31 benutzen dürfte, da diese in den Funktionen nicht benötigt
werden.
Theoretisch müsste er dann nur 1 Register sichern.
1 | 2b6: bf 92 push r11
| 2 | 2b8: cf 92 push r12
| 3 | 2ba: df 92 push r13
| 4 | 2bc: ef 92 push r14
| 5 | 2be: ff 92 push r15
| 6 | 2c0: 0f 93 push r16
| 7 | 2c2: 1f 93 push r17
| 8 | 2c4: d8 2e mov r13, r24
| 9 | uint32_t value = div16u(Game.player[player].time, 60);
| 10 | 2c6: e8 2f mov r30, r24
| 11 | 2c8: f0 e0 ldi r31, 0x00 ; 0
| 12 | 2ca: ee 0f add r30, r30
| 13 | 2cc: ff 1f adc r31, r31
| 14 | 2ce: ee 0f add r30, r30
| 15 | 2d0: ff 1f adc r31, r31
| 16 | 2d2: eb 57 subi r30, 0x7B ; 123
| 17 | 2d4: ff 4f sbci r31, 0xFF ; 255
| 18 | 2d6: 87 81 ldd r24, Z+7 ; 0x07
| 19 | 2d8: 90 85 ldd r25, Z+8 ; 0x08
| 20 | 2da: 6c e3 ldi r22, 0x3C ; 60
| 21 | 2dc: 70 e0 ldi r23, 0x00 ; 0
| 22 | 2de: 34 df rcall .-408 ; 0x148 <div16u>
| 23 | 2e0: 7b 01 movw r14, r22
| 24 | 2e2: 8c 01 movw r16, r24
| 25 | uint16_t v1 = bin2bcd8(value & 0xFF);
| 26 | 2e4: 86 2f mov r24, r22
| 27 | 2e6: 44 df rcall .-376 ; 0x170 <bin2bcd8>
| 28 | 2e8: b8 2e mov r11, r24
| 29 | 2ea: c9 2e mov r12, r25
| 30 | uint16_t v2 = bin2bcd8((value >> 16) & 0xFF);
| 31 | 2ec: 78 01 movw r14, r16
| 32 | 2ee: 00 27 eor r16, r16
| 33 | 2f0: 11 27 eor r17, r17
| 34 | 2f2: 8e 2d mov r24, r14
| 35 | 2f4: 3d df rcall .-390 ; 0x170 <bin2bcd8>
| 36 | 2f6: 18 2f mov r17, r24
|
Samuel K. schrieb:
> da diese in den Funktionen nicht benötigt werden.
Das weiss der Compiler aber nicht. Der kennt nur die von dir zitierte
Konvention, dergemäss eine aufgerufene Funktion bestimmte Register nicht
sichern muss. Folglich muss er davon ausgehen, dass alle diese Register
durch einen Aufruf verändert werden. Und muss für Daten, die einen
Aufruf überleben sollen, andere Register verwenden. Das sind dann
notwendigerweise solche, die er selbst sichern muss.
Es gibt eine Option, mit der für die PUSH/POP-Orgien Laufzeitfunktionen
verwendet werden. Kostet Zeit, bringt aber bei grösseren Programmen
einen Platzgewinn.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|