Frequently, we want to enter and display numbers with very little arithmetic in between. Typical applications involve things like timers and clocks.
One way to do this, of course, would be to do it all in binary. We'd need to take our input and convert it to binary (this involves multiplications), and then take the results of our calculations and convert them to decimal to display them (which involves divisions).
For quite a few applications like this, it's easier to just use a number representation that's more like decimal. A couple of representations like this are "binary coded decimal" and "packed binary coded decimal". Let's talk about them.
Let's talk about BCD first. The idea is, instead of representing a number in binary, we'll represent it as an array of decimal digits. Now, to add, we can just do the following for every digit of x and y.
Case 1: the result is less than 10. The addition is correct.
Case 2: the least significant nybble gets a result greater than 9 but less than 16. We need to subtract 10 from the least significant nybble, and add 1 to the most significant nybble.
Case 3: the least significant nybble gets a result greater than 15. We need to subtract 10 from the least significant nybble (we don't need to add 1 to the most significant nybble, because we already had a carry into those bits). Note that we can't use the four bits themselves to see if we've got this case; the values in the bits aren't distinguishable from getting a 1 (for 17), 2 (for 18), or 3 (for 19) which would be the same as the first case. So, we need an extra condition code bit to keep track of whether there is a carry across the nybbles - precisely the purpose of the H bit.
There are three corresponding cases for the most significant nybble. if we consider all the possibilities, we end up with a table like this:
| Before DAA | Number Added by DAA | Carry After DAA | |||
|---|---|---|---|---|---|
| C Bit | Upper Nybble of ACCA | H Bit | Lower Nybble of ACCA | ||
| 0 | 0-9 | 0 | 0-9 | 00 | 0 |
| 0 | 0-8 | 0 | a-f | 06 | 0 |
| 0 | 0-9 | 1 | 0-3 | 06 | 0 |
| 0 | a-f | 0 | 0-9 | 60 | 1 |
| 0 | 9-f | 0 | a-f | 66 | 1 |
| 0 | a-f | 1 | 0-3 | 66 | 1 |
| 1 | 0-2 | 0 | 0-9 | 60 | 1 |
| 1 | 0-2 | 0 | a-f | 66 | 1 |
| 1 | 0-3 | 1 | 0-3 | 66 | 1 |
This, of course, looks like a mess to try to implement. Unless we have an instruction in the instruction set to do it for us - like the DAA (Decimal Adjust A) instruction! This instruction applies exactly the adjustments we described above.
Now we can add two packed BCD strings of arbitrary length (limited by memory size, of course). The central loop looks like
loop ldaa op1,x
adca op2,x
daa
staa res,x
dex
bne loop
(notice, by the way, that this same basic loop but missing the
daa instruction would let us do arbitrary precision
arithmetic.
We subtract by using 10's complement. Mom's Comptometer strikes again!