AVR8 assign bit in assembly

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?

• If it doesn't matter if the I/O-pin briefly toggles (when it is already low and it is to stay low), then you could remove the first sbrc. – jippie Nov 25 '13 at 14:02
• One trick is to write the code in C, then check if the compiler comes up with a smart trick that you didn't think of yet. – jippie Nov 25 '13 at 14:05
• @jippie, glitches in the output are not acceptable. – johnfound Nov 25 '13 at 15:11

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.