Assembler kontra C
Még mindig az ujjgyakorlatoknál tartok. A topik első harmadában mutattam a timer interrupt kiszolgáló assembly rutint:
.global TIMER0_COMP_vect
TIMER0_COMP_vect:
PUSH R24
IN R24, _SFR_IO_ADDR(SREG)
PUSH R24
PUSH R25
//------
LDS R24, (tick_counter)
LDS R25, (tick_counter) + 1
ADIW R24, 0x0001
STS tick_counter, R24
STS tick_counter+1, R25
//------
POP R25
POP R24
OUT _SFR_IO_ADDR(SREG), R24
POP R24
RETI
Most (nem)csak kíváncsiságból megcsináltam C -ből:
ISR (TIMER0_COMP_vect)
{
tick_counter++;
}
Nagyon bonyolult lett :) Ime az assembly lista:
ISR (TIMER0_COMP_vect)
{
7c: 1f 92 push r1
7e: 0f 92 push r0
80: 0f b6 in r0, 0x3f ; 63
82: 0f 92 push r0
84: 11 24 eor r1, r1
86: 8f 93 push r24
88: 9f 93 push r25
tick_counter++;
8a: 80 91 60 00 lds r24, 0x0060
8e: 90 91 61 00 lds r25, 0x0061
92: 01 96 adiw r24, 0x01 ; 1
94: 90 93 61 00 sts 0x0061, r25
98: 80 93 60 00 sts 0x0060, r24
}
9c: 9f 91 pop r25
9e: 8f 91 pop r24
a0: 0f 90 pop r0
a2: 0f be out 0x3f, r0 ; 63
a4: 0f 90 pop r0
a6: 1f 90 pop r1
Összesen, 4 push/pop felesleg van - azaz 8 ciklus. Az esetek jó részében ez elhanyagolható, de van néhány amikor nem.
Még nem túrtam bele eléggé a kód befolyásolás lehetőségeibe, de nem tudom jó ötlet-e C szintről beletúrni. Az r0,r1 a avr-libc által használt regiszterek, így ha bővül (valamiért) az interrupt kiszolgáló rutin és ebben használatba veszi a regisztereket akkor baj is lehet.
Azaz ha valamilyen esetben nem elfogadható a 8 ciklus veszteség, akkor inkább assemblyben írnám meg az interrrupt rutint.
* Én egy indián vagyok. Minden indián hazudik.