# Arithmetics & boolean algebra

## Arithmetics

### Adding, larger adding, and more adding

Let's talk a bit more about `add`

, shall we? It actually comes in two flavors: the `add a, X`

we just saw, which does 8-bit addition, but rumors speak of a mythical 16-bit variant: `add hl, X`

. This one has two major differences: one, **only the Z flag is updated**; two, unlike the 8-bit flavor, **X cannot be an immediate value**!

There exists an instruction that is basically `add`

but with an added twist: `adc`

. This instruction **ad**ds with **c**arry. What does it mean? Well, where `add a, X`

was doing `a = a + X`

, `adc a, X`

does `a = a + X + carry (either 0 or 1)`

. If you're wondering how that's useful, we're going to use it to emulate `add hl, $XXXX`

!

; Add $1337 to hl ; Note: destroys A, that means "alters its value" ld a, l add a, $37 ; Process the low 8 bits... ld l, a ; Store back ld a, h adc a, $13 ; Process the upper 8 bits, counting the carry that may have stemmed from the low 8 bits ld h, a

Let's run though this again, but supposing HL = $CAFE.

; hl = $CAFE ld a, l add a, $37 ; A = $37 + $FE = $35, and Carry set ld l, a ; hl = $CA35 ld a, h adc a, $13 ; A = $13 + $CA + 1 (carry set) = $DE ld h, a ; hl = $DE35

If you take your calculator out, you'll notice that this is the correct result! Using `add`

instead of `adc`

would have yielded $DD35 instead, which is wrong. Basically, the purpose of `adc`

is to simplify carrying out multi-byte additions. You saw an application above, here is another.

; Guess what this does? ld a, c add a, [hl] ; Remember, [hl] is basically an 8-bit register, so you CAN do this! ld c, a inc hl ld a, b adc a, [hl] ld b, a dec hl ; That's right -- this is basically `add bc, [hl]`. Neat, huh?

If you remember what I said about endianness, this is basically the reason why little-endian is more practical: you have to process (and therefore read and/or write) the low byte(s) first to be able to ripple the carry to the upper byte(s). Thus, we store the lower byte first. It may be a little awkward at first, but I promise you get used to it.

Oh, and by the way, `adc hl, X`

doesn't exist. Get used to it -- there's basically just `add hl, X`

as far as 16-bit operations are concerned. I miss my Z80 extended opcodes... ;-;

### The other way around

Okay, great, I can add, but what if I wanted to **sub**tract? Well, as the bold characters may have made you guess, `sub`

is right there for you! It has the same syntax as `add a, X`

, and - *what a surprise!* - `sub hl, X`

doesn't exist. It also affects the Z and C flags, although it's worth mentioning how C works there.

ld a, 3 ld b, 2 sub a, b ; A = $01, Z reset, C reset sub a, b ; A = $FF, Z reset, C set sub a, $FF ; A = $00, Z set, C reset sub a, 0 ; A = $00, Z set, C reset

As you can see, C is set when a borrow/underflow occurs. Note that other CPUs, such as the 6502 family, use an inverted meaning - C is *reset* when a borrow occurs. It's less intuitive (cue a swath of "oops"-level bugs), but it's more practical in some cases.

Oh, and by the way, there's also `sbc a, X`

. It works the same way as `adc a, X`

(`a = a - X - carry`

), and there's no `sbc hl, X`

, PLEASE STOP INSISTING

### Comparing

When you want to **c**om**p**are two values, you use `cp a, X`

. `cp`

is extremely straightforward -- it's `sub`

, but it doesn't write the result back to `a`

. If you're wondering what it's useful for aside for wasting time, you didn't notice that it *still affects flags*! As such, it's the preferred operator for, well, comparisons.

The cool part about `cp`

is that you can test both equality cases (==, !=) and two inequality cases (<, >=) using only one `cp`

. Don't believe me?

ld a, 42 cp a, 10 ; 42 - 10 = 32, C reset (42 >= 10), Z reset (42 != 10) ; Notice how you can chain comparisons? That comes in handy at times cp a, 57 ; 42 - 57 = 241, C set (42 < 57) , Z reset (42 != 57) cp a, 42 ; 42 - 42 = 0, C reset (42 >= 42), Z set (42 == 42)

### Where mah `mul`

and `div`

?

Tough luck, the GBz80 does not have any multiplication or division capabilities. You can be clever about multiplication, though, using one simple trick: `add a, a`

basically multiplies `a`

by two! (This makes multiplying by powers of two much more efficient, btw). You could also multiply by 6 using this:

ld b, a add a, a ; *2 add a, b ; *3 add a, a ; *6

We will program, in a later section, a function that performs multiplication. Don't worry.

## Boolean algebra

Now, we can add and subtract. But we're dealing with bits, too, and maybe I'll want to manipulate them as well? Well, boolean algebra has got you covered. There are three operations that you need to know about: `and`

, `or`

and `xor`

.

Let's begin by what they have in common. They all operate on the `a`

register, basically like `add a, X`

. Each of these operations work bit by bit -- they're binary operations, not logical operations. All three of them reset the C flag, always, and modify the Z flag as you'd expect.

### AND

This operation takes each bit of both operands, and sets the corresponding bit of the result if and only if both bits are set.

ld a, %01010011 ld b, %00110101 and a, b ; A %0101 0011 ; B %0011 0101 ; ---------- ; A and B %0001 0001 ; Now, a = $11

This is pretty useful for "masking out" (resetting) some flags/bits, and to test if some bits are zero (since the Z flag will be set accordingly).

### OR

This operation takes each bit of both operands, and sets the corresponding bit of the result if and only if any of both bits is set.

ld a, %01010011 ld b, %00110101 or a, b ; A %0101 0011 ; B %0011 0101 ; ---------- ; A or B %0111 0111 ; Now, a = $77

This is pretty useful for setting some flags/bits. This is used less frequently than `and`

, but still.

### XOR

This operation takes each bit of both operands, and sets the corresponding bit of the result if and only if both bits differ.

ld a, %01010011 ld b, %00110101 xor a, b ; A %0101 0011 ; B %0011 0101 ; ---------- ; A xor B %0110 0110 ; Now, a = $66

This is pretty useful to invert some flags/bits. This is heavily used instead of counters for "flip-flop" states (now you know why a lot of games have two-frame animations!).

## Binary Coded Decimal (BCD)

Remember how I quickly skimmed over the H and N flags? Let's talk about them. But first, we need to talk about ~~parallel universes~~ what BCD is. When you store a number, say 42, you'd usually store it raw -- 42, 0x2A, %00101010. BCD is storing each digit in each nibble -- $42, %01000010. It *is* less efficient, but much more practical for decimal displaying (instead of dividing by 10, you `and a, $0F`

). Therefore, BCD is better for displaying, but not for calculating: $59 + $01 = $60 and not $5A.

Luckily, there's an instruction that does just that: `daa`

performs **d**ecimal **a**djustment on the **a**ccumulator (the `a`

) register. It acts depending on the H, N and C flags, *and* the accumulator's contents. On a surface level, it basically adjusts the contents of the `a`

register to match the result of the BCD operation.

ld a, $39 add a, $01 ; A = $3A daa ; Perform M.A.G.I.C ; A = $40

Let it be known that `daa`

may set the C flag (for example if A was $99 in the example above instead of $39), and alters Z and H. If you don't care about how it works, you can safely skip the rest of this section. But if you want the nitty-gritty, then here we go.

First, let's describe how the H and N flags work. H is the **h**alf-carry, and it works **exactly** the same way as the carry (even depending on the instruction!), but taking only the lower 4 bits into account. So, for example, when adding $08 to $39, H is set, because there's is an overflow in the low 4 bits (they go from $9 to $1). N tells whether the previous operation was "positive" (flag reset) or "negative" (flag set). For example, `add a, X`

resets that flag, and `sub a, X`

sets it. This is because the adjusting depends on the last operation that occurred.

If H is set or the lower 4 bits of A contain a non-BCD digit ($A-$F), then an implicit `add a, $06`

is performed (this includes modifying the C flag). Then if C is set or the upper 4 bits of A contain a non-BCD digit, an implicit `add a, $60`

is performed, including modifying the C flag. (Note: I believe the H flag isn't modified by this second `add`

, but I'm not sure.) **But,** if the N flag was set, instead of `add`

, the operations performed are instead `sub`

s. (Note: I think that's how it's done, but I'm unsure.)