assemblycpu-architectureavrinstruction-setcarryflag

Difference between AVR's "ADC r18, r18" and "ROL r18"


AVR has both ADC (Add with Carry) and ROL (Rotate Left through Carry) instructions.
However, it seems to me like ROL is not needed at all, and ADC r, r fulfills the same purpose.

As far as I can tell, both ADC r, r and ROL r result in (r << 1) | carry. For both, the carry is set to the MSB of the operand.

Here's an example:

Intuitively, adding the register to itself is multiplying it by two, which is the same as a left-shift by one. ADC also adds the carry, which becomes the new LSB of the result.

So, what is ROL even for then? Are there any semantic differences between ROL r and ADC r, r?
I believe the same argument could be made for ROR and SBC as well.


Solution

  • There's no difference; the docs even say rol Rd is just an alias for adc Rd,Rd, so it's the same opcode, just a convenience alias for asm source to more clearly convey the semantic meaning for human readers.
    http://content.alexandria.atmel.com/webhelp/GUID-0B644D8F-67E7-49E6-82C9-1B2B9ABE6A0D-en-US-1/GUID-61A4FA30-4426-42D7-B199-0EBF064BF9E1.html

    But sbc same,same isn't a rotate right; carry propagates low to high (right to left) for both subtraction and addition.
    sbc same,same is x-x - carry setting the register to 0 or -1, depending only on Carry.


    Looking at a different ISA gives an interesting contrast of ISA design choices:
    x86 does have a separate opcode for RCL r/m (rotate through carry) vs. ADC r, r/m. Being a CISC machine, it allows up to one explicit memory operand for most instructions, so adc dword [ebx], [ebx] isn't encodeable so rcl dword [ebx], 1 isn't redundant. AVR is a RISC so all computation instructions can only use register operands.
    x86 also allows counts other than 1 for shifts/rotates, including runtime-variable, but those are separate opcodes from the rotate-by-implicit-1 opcode. (Original 8086 didn't have rotate by immediate count, only 1 or CL)