Why does the Z80 include the RLD and RRD instructions?

The Z80 has an instruction `RLD`, which apparently treats the lower 4 bits in the accumulator and the full 8 bits in `(HL)` as a twelve bit integer which it then rotates left by 4 bits. The carry flag does not participate in the rotation and the rest of the accumulator is left alone.

Correspondingly, there's an `RRD`.

Why would the designers put something like that in? I don't imagine it's was a simple by-product of some other part of the design, but I can't think of a use-case which the other shift/rotate instructions wouldn't do a reasonably good job at.

• I think because of BCD math like you might use to implement a decimal calculator, but that's just a guess. Great question! – Wayne Conrad May 29 '18 at 15:38

Two BCD digit rotate instructions (RRD and RLD) allow a digit in the accumulator to be rotated with the two digits in a memory location pointed to by register pair HL (See Figure 10). These instructions allow for efficient BCD arithmetic.

Given that `DAA` exists for addition and subtraction, I'm going to hazard a guess that the motivation was long multiplication and division, permitting the shift-a-digit step with A acting as carry.

E.g. to derive long multiplication from first principles:

``````3 * 29
= 3 * (2 * 10 + 9)
= (3 * 2) * 10 + 3 * 9
``````

`RLD` will give you the `* 10` step.

If it were `3 * 2983471` there'd be six `* 10` steps, manipulating what becomes a four-byte answer.

If it were `23 * 2983471` then that'd be twice as much work, to get `2 * 2983471`, multiply that by ten, then calculate and add in `3 * 2983471`. So twelve `* 10` steps.

I'd also be likely to have obtained the `2` in isolation by a divide-by-ten step. Which `RRD` would help with.

RLD and RRD are simple 4-bit shifts of BCD-coded values. As they are shifting by one decimal digit right or left, they effectively result in a multiplication (or division) by 10 (assumed A is 0) when used repeatedly on a multi-digit BCD value or a multiplication by 10 plus an addition of the lower digit in A. A acts as a sort of "decimal carry" in this operation.

You can use this in a multiplication (or division) routine for decimals parallel to the pen-and-paper method you learned at school.

Multiplying a multi-digit packed BCD number at `DATA` by 10, with the byte count (half the number of decimal digits) in `COUNT`, would look like the below:

``````        LD      HL, DATA
LD      B, COUNT
XOR     A
ROTAT:  RLD
INC     HL
DJNZ    ROTAT
``````

Outside of BCD-coded decimals, you could be using these commands to scroll a ZX Spectrum screen left or right by 4 pixels, for example.

• Probably worth mentioning that your example assumes little-endian BCD. IOW, `RLD` should start at the right-hand end, using `A` to hold the intermediate carries as `HL` moves leftwards through the number; conversely, a `RRD` loop starts at the left-hand end and works rightwards. – Toby Speight Mar 27 '19 at 15:39

These instructions appear to be useful for converting between BCD numbers and their printed representation. They would also be useful for printing numbers in hexadecimal format. accessing a BCD or hex value 4 bits at a time corresponds to one input or output character.

• I think their main usefulness would be when shifting multi-byte quantities, both in the case where one wants a shift by four, and also in the cases where one wants a shift by 3 or 5 [as might occur fairly often when working with floating-point numbers], since shifting by 4 and then shifting one bit forward or backward would be faster than shifting left 3 times or moving data forward a byte and shifting backward 3 times. – supercat May 29 '18 at 15:48
• @Ken Would you be able to put some code together to illustrate what you mean? – OmarL May 29 '18 at 15:52
• @Wilson I am unfortunately not a Z80 programmer, but the idea is similar to code given in other answers: loop through a number 4 bits at a time and do something with the 'current' 4-bit 'digit'. to convert a BCD digit to ASCII you would add 48, so that 0 becomes ASCII '0' (48+0 = 0) and 9 becomes ASCII '9' (48+9 = 57). Converting ASCII to BSD you would do the reverse, subtracting 48. – Ken Gober May 30 '18 at 15:28

I think the primary usage case for something like that would be shifting a multi-byte quantity left or right by four bits. One could rotate a 56-bit value (e.g. the mantissa of a floating-point value) left by 4 bits by doing something like:

``````    ld h,myThing >> 8  ; Assume it doesn't cross a page boundary
ld bc,4
and a ; Clear carry
loop:
ld l,myThing & 255
rl (hl)
inc l
rl (hl)
inc l
rl (hl)
inc l
rl (hl)
inc l
rl (hl)
inc l
rl (hl)
inc l
rl (hl)
djnz loop
``````

but it could be done much faster as:

``````    ld h,myThing >> 8  ; Assume it doesn't cross a page boundary
xor a  ; Could use "ld a,0" if carry was important for some reason

ld l,myThing & 255
rld (hl)
inc l
rld (hl)
inc l
rld (hl)
inc l
rld (hl)
inc l
rld (hl)
inc l
rld (hl)
inc l
rld (hl)
``````

I'm not sure the value of that is greater than the value of other features that could have been provided for the same amount of effort and silicon, but I think something like the above would be the intended usage pattern. Still, the feature would have value either in cases where things are being shifted by exactly four bits, or in performance-sensitive code (like floating-point math) where values may need to be shifted by N bits and it would not be uncommon for N to be 3, 4, or 5. I'm not sure exactly how big the thing to be shifted would need to be to make such optimizations worthwhile, but the requirement that objects be stored in RAM might limit the value of such optimizations when shifting smaller things. If a 32-bit value needed to be shifted, the first approach could be changed to:

``````    ld hl,(myThing)
ld de,(myThing+2)
ld bc,4
and a ; Clear carry
loop: