.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