( tovis | 2015. 04. 27., h – 12:47 )

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.