ensamblaje de AVR: la forma más rápida de incrementar dos bytes combinados

5

¿Cuál podría ser la forma más rápida de incrementar dos bytes combinados en el ensamblador (asumiendo que estoy trabajando en una CPU de 8 bits)? Actualmente estoy haciendo esto:

OVF1_handler: ; TIMER1 overflow ISR

lds r21, timerhl ; load low byte into working register; 2 cycles
add r21, counter_inc ; add 1 to working register (value of counter_inc is 1); 1 cycle

brbs 0, OVF1_handler_carry ; branch if bit 0 (carry flag bit) of SREG is set; 1 cycle if false . 2 cycles if true
sts timerhl, r21 ; otherwise write value back to variable; 2 cycles
reti ; we're done

OVF1_handler_carry: ; in case of carry bit is set
    sts timerhl, r21 ; write value of low byte back to variable; 2 cycles

    lds r21, timerhh ; load high byte into working register; 2 cycles
    inc r21 ; increment it by 1 (no carry check needed here); 1 cycle
    sts timerhh, r21 ; write value of high byte back to variable; 2 cycles

reti ; we're done

Así que en suma hay

255 * (2+1+1+2) + (2+1+2+2+2+1+2) = 1542 cycles

para contar de 0 a 256 (255 veces (2 + 1 + 1 + 2) porque no hay desbordamiento más 1 vez (2 + 1 + 2 + 2 + 2 + 1 + 2) cuando se produce un desbordamiento).

¿Mi cálculo es correcto y hay una manera más rápida?

    
pregunta arminb

1 respuesta

4

Confía un poco más en tu compilador. Escriba el código en C, compílelo y mire el desensamblaje. No estoy seguro de qué cadena de herramientas utilizas, pero avr-gcc crea un código bastante bien optimizado.

lds     r24 , lowbyte   ; 2 clocks
lds     r25 , highbyte  ; 2 clocks
adiw    r24 , 0x01      ; 2 clocks - Add Immediate to Word (= 16 bit)
sts     lowbyte  , r24  ; 2 clocks
sts     highbyte , r25  ; 2 clocks

Puede desensamblar el archivo .elf con el siguiente comando (siempre que use la cadena de herramientas gcc):

avr-objdump -C -d $(src).elf

Por cierto: es probable que debas presionar los registros usados para que se apilen de antemano y hacerlos saltar después (2 ciclos cada uno). También recuerde que una interrupción (incluido reti ) dura al menos 8 ciclos de reloj, aparte de las instrucciones que se están ejecutando.

; TIMER1_OVF            ;  4 clocks
push    r24             ;  2 clocks
IN      r24 , SREG      ;  1 clock  - save CPU flags
push    r24             ;  2 clocks
push    r25             ;  2 clocks
; do the addition above - 10 clocks
pop     r25             ;  2 clocks
pop     r24             ;  2 clocks
OUT     SREG , r24      ;  1 clock
pop     r24             ;  2 clocks
reti                    ;  4 clocks
; total 32 clock ticks
    
respondido por el jippie

Lea otras preguntas en las etiquetas