1
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – jippie Nov 25 '13 at 14:02
  • \$\begingroup\$ 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. \$\endgroup\$ – jippie Nov 25 '13 at 14:05
  • \$\begingroup\$ @jippie, glitches in the output are not acceptable. \$\endgroup\$ – johnfound Nov 25 '13 at 15:11
2
\$\begingroup\$

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.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.