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:
r = 0x12 = 0001_0010
, carry = 0
ADC r, r
r = 0010_0100 = 0x24
carry = 0
ROL r
r = 0010_0100 = 0x24
carry = 0
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.
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)