Electronic – AVR8 assign bit in assembly

assemblyavr

I want to simply assign (copy) a bit in the IO register from some other register bit (or flag, or as a result of some comparison). Now I am using following (PORTD[2] := r0[3]):

    sbrc r0, 3      ; Skip if Bit in Register is Cleared
    sbi  PORTD, 2   ; Set Bit in I/O Register
    sbrs r0, 3      ; Skip if Bit in Register is Set
    cbi  PORTD, 2   ; Clear Bit in I/O Register

But is it optimal? Is there better way? How to make it with other sources – some flag for example C or T?

Best Answer

On many AVRs, this can be made faster (but not smaller) via the status register's T bit:

bst  r0, 3      ; Store bit 3 of r0 into T
in   r2, PORTD  ; Read the current value of PORTD
bld  r2, 2      ; Load bit 2 of r1 from T
out  PORTD, r2  ; Write the updated value back to PORTD

This requires only 4 cycles (vs. 5: either 2+0+1+2 or 1+2+2+0) and always updates PORTD at the fourth cycle regardless of the bit value.

Caveats:

  • If an ISR updates PORTD between the in and out instructions, that update will be reverted by the out.
  • Another CPU register is required if r0's value must be preserved (r2 in this example, but it can be any).
  • XMEGA and Reduced Core AVR devices have single-cycle cbi and sbi instructions, so there's no speed difference on those targets.
Related Topic