ROR

From C64-Wiki
Jump to navigationJump to search

ROR (short for "ROtate Right") is the mnemonic for a machine language instruction which "rotates" the bits in either the accumulator or a specified address in RAM, one bit position towards the "right", or least significant, "end" of the byte. The most significant bit, is set to the value in the carry flag. Similarly, what was the least significant bit in the byte prior to the shifting, will subsequently be "rotated" into the carry flag.

If the byte affected by the operation is taken as an unsigned 8-bit integer, the ROR operation in some sense halves the number, leaving a result of seven bits in the accumulator, whereas carry will hold the "remainder" of the "division". Dividing signed integers by two in this way requires programming efforts to keep the sign bit from "wandering into" the other bits, causing erratic results.

It is interesting to note that whereas ADC and SBC do not come in "flavours" which do not take an incoming carry or borrow, both ROR and its counterpart, ROL, are complemented by the instructions ASL and LSR, which "fills the vacant bit" with a zero. Historically, ASL and LSR was implemented in the very first 65xx CPUs, whereas ROL and ROR were only available in CPUs manufactured after a certain date.

The shifting instructions (LSR and ASL) therefore differ from the rotating instructions (ROR and ROL) only in their handling of carry as input to the instruction. The shifting instructions ignore carry on input, always shifting a zero (0) bit into the operand. The rotate instructions always "shift" the value in carry into the operand. Both types of instructions store the bit value leaving the operand in carry.

The following example shows how to right-shift an integer spanning several bytes, or effectively dividing it by two:

LSR Num+n   ;Shift most significant byte right by one bit, shifting the least significant bit into carry
ROR Num+n-1 ;Rotate the next byte, using the value in carry and replacing carry with lowest bit
...
ROR Num     ;Rotate the most significant byte, using the value in carry and replacing carry with the remainder.

Addressing modes[edit | edit source]

Opcode Addressing
mode
Assembler
format
Length
in bytes
Number of
cycles
Dec Hex
106 6A Accumulator ROR 1 2
110 6E Absolute ROR nnnn 3 6
126 7E Absolute,X ROR nnnn,X 3 7
102 66 Zeropage ROR nn 2 5
118 76 Zeropage,X ROR nn,X 2 6

ROR supports the five addressing modes shown in the table at right. In the assembler formats listed, nn represents a single-byte (8-bit) figure, and nnnn is a two-byte (16-bit) address.

CPU flags[edit | edit source]

ROR affects 3 of the CPU's status flags:

  • The negative flag is set if the result is negative, i.e. has its most significant bit set.
  • The zero flag is set if the result is zero, or cleared if it is non-zero.
  • The carry flag is set or cleared depending on the result.


Examples[edit | edit source]

Arithmetic shift right

Some CPU architecture's instruction set has an arithmetic right shift, which keeps the state of the sign (top) bit. This shift is used to divide a signed value by two. The 6502 CPU family lacks an instruction like ASR; LSR doesn't work because it shifts the sign bit to the right, then clears it.

To implement this, we need carry set according to the sign bit, then we can use ROR.
CMP #$80 performs this task; if the value is less than $80, carry is cleared, otherwise (for negative values) it's set:

; Arithmetic shift right A
CMP #$80
ROR

If the operand is in memory, we just use ASL to move the sign bit into carry:

; Arithmetic shift right Value
LDA Value
ASL
ROR Value