# BCD math

Ever need to display a number on screen but you don't want to deal with slow divisions? (especially with large numbers) Then you should look into BCD, which stores numbers in a way that makes it easy to extract the digits.

BCD is ideal for anything that'd be on screen like score, lives, ammo, seconds, etc.

- What's BCD?
- Extracting the digits
- Adding byte-sized numbers
- Adding larger numbers
- Substraction
- Checking if result fits

## What's BCD?

BCD (Binary Coded Decimal) is a way to store decimal numbers that uses four bits per digit (10 out of the 16 possible combinations are used). The advantage is that you can split away the digits with only bit shifting (instead of slow divisions), making it ideal for values that need to be displayed on screen (like score).

To figure out the BCD equivalent of a number, just take the number in
decimal and write it as hexadecimal. For example, `1234`

in
BCD would be `$1234`

.

## Extracting the digits

The idea behind BCD is that each digit is exactly four bits. You can
extract each digit by shifting (or rotating) four bits, then doing an
`and`

with `$0F`

(which will mask out the bottom
four bits). This example goes through all digits of a 32-bit BCD number
(which can hold 8 digits):

```
; d0.l = BCD number
```**moveq** #8-1, d7
Loop:
; Push the next digit into the
; bottom bits and mask them out
**rol.l** #4, d0
**move.w** d0, d1
**and.w** #$0F, d1
; Now d1.w contains the digit
; Do whatever you need to do
**dbf** d7, Loop

## Adding byte-sized numbers

68000 can do BCD operations! Albeit on a per-byte basis.

The `abcd`

instruction lets you add two BCD bytes. This is
good enough if you only need two digits. First you need to clear the
flags (later you'll understand why). Then use the `abcd`

instruction on two data registers (e.g. `d0`

and `d1`

) much like you'd do with normal additions:

` `**and** #0, ccr ; Clear flags
**abcd** d1, d0 ; Add numbers

Sadly, the `abcd`

instruction is rather limited, so you can't
add fixed values as-is... you'll need to store the value into a register
then do the above:

` `**moveq** #1, d1 ; Number to add
**and** #0, ccr ; Clear flags
**abcd** d1, d0 ; Add numbers

## Adding larger numbers

The above won't help with larger numbers (like score). For that, there's
another variant of `abcd`

that uses memory instead. Of course
you need the numbers in RAM for this.

Take two address registers (e.g. `a0`

and `a1`

)
and make them point to the first byte *after* the numbers. Then
clear the flags, and use `abcd`

for as many bytes as needed,
like in the example below (which is for 32-bit numbers):

` `**lea** (Number1+4), a0
**lea** (Number2+4), a1
**and** #0, ccr ; Clear flags
**abcd** -(a1), -(a0) ; Add first two digits
**abcd** -(a1), -(a0) ; Add next two digits
**abcd** -(a1), -(a0) ; Add next two digits
**abcd** -(a1), -(a0) ; Add last two digits

(now you can see why you need to clear the flags: the carry is also added)

## Substraction

Substraction works the same way but you use `sbcd`

instead of
`abcd`

. That's all.

## Checking if result fits

If you need to check if the result is too large to fit (or too small,
if substracting), all you need to do is check the carry flag after you're
done with it (with `bcc`

or `bcs`

). If carry is set,
it means the result doesn't fit and you should do something.

Simple example on how to prevent score from going back to zero:

` `**lea** (Score+4), a0
**lea** (Points+4), a1
; Add points to the score
**and** #0, ccr
**abcd** -(a1), -(a0)
**abcd** -(a1), -(a0)
**abcd** -(a1), -(a0)
**abcd** -(a1), -(a0)
; Check if score went beyond the limit
; If so, force it back to the maximum
**bcc** ScoreOk
**move.l** #$99999999, (Score)
ScoreOk: