| 
    
    
			
  
  
  
  
    
  
    
    
      
      
  
  
  
  
 
      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.
 |