- Division in z80 assembly
- 10 Oct 2012 07:36:39 am
- Last edited by Xeda112358 on 13 Nov 2012 04:12:21 pm; edited 2 times in total

(sorry for the horrible formatting, I couldn't figure out how to make a monospaced font)

In z80 assembly, the division algorithms you might have seem probably seem unintuitive. But guess what? They are usually a variation on long division that you learned in school, but modified for binary. In my experience, math in binary is so much easier and faster than in base 10, so here is an example. Let's try to divide 85 by 3:

(Note: 3=11b and 85=1010101b. The math in this example is all done in binary)

We have a remainder of 1, and the quotient is 11100 which is 28. 28*3=84, add 1 and you have 85. Now how do we implement this in pseudocode?

P is the numerator

Q is the denominator

(we are essentially doing P/Q, then)

Let B be the number of bits

Let C be the remainder between each step

Let A be the accumulator

But what would this look like in assembly? Here is an example:

This works, but can we optimise it for the z80? Of course! Note that the registers E and C are 8 bits. Since we are shifting a bit out of E each time, we can use that doubly as an accumulator. here is what I mean:

This routine is pretty good for D/E/ How good? 14 bytes and 344+3b cycles (where b is at most 8) This can basically execute over 17000 times a second at 6MHz, over 43000 at 15MHz.

I hope this helps people!

In z80 assembly, the division algorithms you might have seem probably seem unintuitive. But guess what? They are usually a variation on long division that you learned in school, but modified for binary. In my experience, math in binary is so much easier and faster than in base 10, so here is an example. Let's try to divide 85 by 3:

(Note: 3=11b and 85=1010101b. The math in this example is all done in binary)

**Code:**```
```

________

11|1010101

Now you check if 11≤1. It isn't, so you have a zero:

0_______

11|1010101

Now you check if 11≤10. It isn't, so you have another zero:

00______

11|1010101

Now you check if 11≤101. It is, so you subtract 101-11 to get 10.

001_____

11|1010101

10

Now you check if 11≤100. It is, so you subtract 100-11 to get 1.

0011____

11|1010101

10

1

Now you check if 11≤11. It is, so you subtract 11-11 to get 0.

00111___

11|1010101

10

1

0

Now you check if 11≤00. It isn't, so you put a zero up top.

001110__

11|1010101

10

1

0

Now shift in the last bit, a 1.Since 11≤01 is not true, we have a zero.

0011100_

11|1010101

10

1

0

We have a remainder of 1, and the quotient is 11100 which is 28. 28*3=84, add 1 and you have 85. Now how do we implement this in pseudocode?

P is the numerator

Q is the denominator

(we are essentially doing P/Q, then)

Let B be the number of bits

Let C be the remainder between each step

Let A be the accumulator

**Code:**```
```

0→C

0→A

Loop:

A<< (I mean to say, shift A left, also the same as multiply by 2)

Q<<C (I mean to say, shift Q left, shifting the carry into C

If C≤P

C-P→C

A++ (increment A. Since A was multiplied by 2, the last bit would be zero. This sets it to 1)

B--

If B

Goto Loop

But what would this look like in assembly? Here is an example:

**Code:**```
```

;we will do D/E

xor a ;0→C we let A be the remainder

ld bc,0800h ;8→B, 0→A We let C be the accumulator

Loop:

sla c ;A<<

rl e \ rla ;Q<<C

cp d ;If C≤P

jr nc,$+4

sub d ;C-P→C

inc c ;A++

djnz Loop ;B-- \ If B \ Goto Loop

ret

This works, but can we optimise it for the z80? Of course! Note that the registers E and C are 8 bits. Since we are shifting a bit out of E each time, we can use that doubly as an accumulator. here is what I mean:

**Code:**```
```

;we will do D/E

xor a ;0→C we let A be the remainder

ld b,8 ;8→B we will let Q be the accumulator

Loop:

rl e \ rla ;Q<<C, also A<<

cp d ;If C≤P

jr nc,$+4

sub d ;C-P→C

inc e ;A++

djnz Loop ;B-- \ If B \ Goto Loop

ret

This routine is pretty good for D/E/ How good? 14 bytes and 344+3b cycles (where b is at most 8) This can basically execute over 17000 times a second at 6MHz, over 43000 at 15MHz.

I hope this helps people!