Z80 Assembly – BCD numbers
In this chapter of Z80 Assembly, we will learn how to work with numbers larger than 16 bits.
Translated with DeepL.
Table of contents
What are BCD numbers?
BCD numbers are represented in a natural way, as we would see them; the hexadecimal 99 represents the decimal 99.
To achieve this, a byte can represent numbers from 0 to 99 by dividing the byte into two nibbles (4 bits). Each nibble can represent numbers from 0 to 9.
In this way, the hexadecimal 10, which in decimal is 16, in BCD represents the decimal 10. In other words, we see hexadecimal numbers as if they were decimal numbers.
How to use them?
To represent a 10-digit number, 5 bytes are needed. An extra byte can be used to indicate the position of the decimal point, in order to work with decimals. BCD numbers are used to operate with numbers of more than 16 bits.
When operating with BCD numbers, the DAA (Decimal Adjust Accumulator) instruction must be taken into account. DAA makes adjustments to the results of operations with BCD numbers, and works as follows:
- Check bits 0, 1, 2 and 3. If they contain a non-BCD digit (greater than 9) or the H flag is set, add or subtract, depending on the operation, 06h (0000 0110b) to the byte.
- Check bits 4, 5, 6 and 7. If they contain a non-BCD digit (greater than 9) or the C flag is set, add or subtract, depending on the operation, 60h (0110 0000b) to the byte.
Thus, if we have $09 and add $01, the result is $0A. After executing DAA, the result is $10. After each arithmetic instruction, increment or decrement, DAA must be executed.
ld a, $09 ; A = $09
inc a ; A = $0A
daa ; A = $10
dec a ; A = $0F
daa ; A = $09
add a, $03 ; A = $0C
daa ; A = $12
sub $03 ; A = $0F
daa ; A = $09
How do you paint them?
The way to obtain the ASCII code of each nibble (four bits) is relatively simple.
The routine shown below receives a BCD number in register B and displays it on the screen.
; -----------------------------------------------------
; Prints a BCD number on the screen.
; Input: B -> BCD number to be printed.
; Alters the value of the AF register.
; -----------------------------------------------------
PrintBCD:
ld a, b ; Loads in A the number to print
and $f0 ; Keeps the upper nibble
rrca
rrca
rrca
rrca ; Rotates it four times to move it to the lower nibble
add a, '0' ; Adds the ASCII of the 0 to get the ASCII of the number
rst $10 ; Display the number on the screen (ZX Spectrum)
; call $bb5a ; Display the number on the screen (Amstrad CPC)
ld a, b ; Reloads the number to be printed in A
and $0f ; Keeps the bottom nibble
add a, '0' ; Adds the ASCII of the 0 to get the ASCII of the number
rst $10 ; Display the number on the screen (ZX Spectrum)
; call $bb5a ; Displays the number on the screen (Amstrad CPC)
ret ; Exits
RST $10, in ZX Spectrum, prints on screen the character corresponding to the Ascii code loaded in register A. CALL $BB5A does the same in Amstrad CPC.
Conclusion
Working with this type of encoding is relatively simple and allows us to work with large numbers. In exchange, we need more bytes and more processing time.
You can also visit the rest of tutorials:
And remember, if you use it, don’t just copy it, try to understand it and adapt it to your needs.