lh 8
lq on
ps off
cw 12
Z-80 Instructions RLD and RRD
po 8
The Z-80 instructions RLD and RRD are a pair of instructions �
that a poorly understood by most programmers. Although they �
appear a little strange and perhaps rather useless at first �
glance, they are particularly useful for the manipulation of BCD �
numbers. A single RLD or RRD instruction will usually replace �
several lines of 8080 code.
Let me give you some examples of the use of these �
instructions. Suppose that we have a large packed BCD number (2 �
digits per byte) stored in memory at BCDNUM. The number is �
BCDLEN long, so the last 2 digits are stored at BCDNUM + BCDLEN �
-1. If we wish to print this number, we must first convert it to �
ASCII. The following code would accomplish this, assuming that �
ECHO is a subroutine which sends the contents of the accumulator, �
A, to the screen while preserving all registers, including A:
LD HL,BCDNUM ; Point to the the start of the number
LD B,BCDLEN ; Set up a counter
LD A,30H ; Prepare A for ASCII print
BCDLP: RLD ; Shift the high nibble of (HL) to
; the low nibble of A and the low
; nibble of (HL) to the high nibble
; of (HL)
CALL ECHO ; Print the digit
RLD ; Now shift the high nibble (the previous
; low nibble) of (HL) to A
CALL ECHO ; Print that one
RLD ; Restore the original packed number
INC HL ; Point the the next two digits
DJNZ BCDLP ; Loop until done
These instructions can also be used to align operands for �
BCD floating point arithmatic (and are much faster than code �
using single bit shifts). Suppose that you wish to shift the �
number in the previous example right by one nibble and insert a �
zero in the high order nibble. Following will accomplish this �
quite easily:
XOR A ; Clear accumulator
LD HL,BCDNUM ; Point to the number
LD B,BCDLEN ; Our counter again
SHIFTLP: RRD ; Shift low nibble of A to high nibble
; of (HL), high nibble of (HL) to low
; nibble of (HL) and low nibble of
; (HL) to A
INC HL ; Point to next byte
DJNZ SHIFTLP ; Loop til done
This routine effectively divides our BCD number by 10.
pa
Actually, a more useful (though slightly more complex) example is �
a routine to allow keyboard input of a decimal number which is �
then converted to BCD format:
XOR A ; Clear accumulator
LD HL,BCDNUM ; Point to storage for number
LD B,BCDLEN ; Our ubiquitous counter!
CLEARLP: LD (HL),A ; Clear entire buffer to 0
INC HL
DJNZ CLEARLP
LD B,BCDLEN ; Reset counter
LD C,2 ; Need 2 ASCII per BCD digit
LD HL,BCDNUM+BCDLEN ; Point to least significant
NXTDIGIT: CALL GETCH ; Routine to get 1 ASCII char
; from keyboard (preserves
; HL and BC)
CP CR ; Carriage return?
RET Z ; If so, all done
ADDLP: RLD ; Shift digit
DEC C ; Done 2 digist?
JR NZ,NXTDIGIT ; If not, go get another
LD C,2 ; Else, reset digit counter
DEC HL ; adjust pointer
DJNZ NXTDIGIT ; and loop til buffer is full
This routine is somewhat flawed in that it only allows the �
input of an even number of digits, but I think that you get the �
idea.
The ability to do decimal shifts allows decimal �
multiplication and division to be done fairly easily. Multi-�
plication is done similar to the way that it is done on paper. �
Multiplier digits are tested from right to left and the multipli-�
cand added to a product (which is zeroed before the process �
starts). At the end of each multiply step, the multiplicand is �
shifted left, like the indentation of the successive product �
lines when multiplying with pencil and paper (some of us old guys �
still remember the time before computers and calculators were �
readily available!). Of course, decimal multiplication done this �
way is quite slow (each RLD or RRD instruction takes 5 M cycles �
and 18 T states), so if a lot of it is needed, it is probably �
faster to convert to binary, multiply with a binary routine and �
then convert the answer back to BCD. Readers are left to figure �
the details out for themselves (it's too long for inclusion �
here). If you are really interested, contact me and I can �
probably supply an example.
Ian Cottrell, Sysop
The Information Centre RCP/M+
Ottawa, ON, Canada
(613) 952-2289