Difference between revisions of "Z80 Routines:Math:Multiplication"

From WikiTI
Jump to: navigation, search
(16*16 multiplication)
Line 89: Line 89:
 
    
 
    
 
   ret
 
   ret
 +
</nowiki>
 +
 +
=== 24*24 multiplication ===
 +
 +
The following routine multiplies bcd by ehl and places the result in bcdehl. It uses 2 bytes of ram, but those can be substituted for IX half registers. (By thepenguin77)
 +
 +
<nowiki>
 +
multDBCbyEHL:
 +
 +
push de
 +
push hl
 +
 +
ld ix, $8000
 +
ld (ix), l
 +
xor a
 +
ld h, a
 +
ld l, a
 +
 +
call do8Bits
 +
 +
ld (ix+1), a
 +
pop af
 +
ld (ix), a
 +
push de
 +
ld a, (ix+1)
 +
 +
call do8Bits
 +
 +
ld (ix+1), a
 +
pop af ;least sig number
 +
ex de, hl
 +
ex (sp), hl ;D and 2nd least sig in for new number
 +
ld (ix), l
 +
pop hl ;D and 2nd least sig
 +
push af ;least sig number
 +
push hl ;2nd least sig number
 +
ex de, hl
 +
ld a, (ix+1)
 +
 +
call do8Bits
 +
 +
ld b, a
 +
ld c, h
 +
ld d, l
 +
pop hl
 +
ld a, l
 +
pop hl
 +
ld h, a
 +
ret
 +
 +
;####
 +
;input: DBC = 1 number
 +
; AHL = running number
 +
; (ix) = to multiply by
 +
;output: AHLE = output
 +
; E is done
 +
; DBC = 1 number
 +
 +
do8Bits:
 +
ld (ix+1), 8
 +
loop:
 +
srl (ix)
 +
jr nc, skip
 +
 +
add hl, bc
 +
adc a, d
 +
skip:
 +
rra
 +
rr h
 +
rr l
 +
rr e
 +
dec (ix+1)
 +
jr nz, loop
 +
ret
 
  </nowiki>
 
  </nowiki>
  

Revision as of 16:54, 8 December 2011


Introduction

All these routines use the restoring multiplication algorithm, adapted to the z80 architecture to maximize speed. They can easily be unrolled to gain some speed.

Unsigned versions

8*8 multiplication

The following routine multiplies h by e and places the result in hl

mult_h_e
   ld	l, 0
   ld	d, l

   sla	h		; optimised 1st iteration
   jr	nc, $+3
   ld	l, e
   
   ld b, 7
_loop:
   add	hl, hl          
   jr	nc, $+3
   add	hl, de
   
   djnz	_loop
   
   ret
 

16*8 multiplication

The following routine multiplies de by a and places the result in ahl (which means a is the most significant byte of the product, l the least significant and h the intermediate one...)

mult_a_de
   ld	c, 0
   ld	h, c
   ld	l, h

   add	a, a		; optimised 1st iteration
   jr	nc, $+4
   ld	h,d
   ld	l,e

   ld b, 7
_loop:
   add	hl, hl
   rla
   jr	nc, $+4
   add	hl, de
   adc	a, c            ; yes this is actually adc a, 0 but since c is free we set it to zero and so we can save 1 byte and up to 3 T-states per iteration
   
   djnz	_loop
   
   ret
 

16*16 multiplication

The following routine multiplies bc by de and places the result in dehl.

mult_de_bc
   ld	hl, 0

   sla	e		; optimised 1st iteration
   rl	d
   jr	nc, $+4
   ld	h, b
   ld	l, c

   ld	a, 15
_loop:
   add	hl, hl
   rl	e
   rl	d
   jr	nc, $+6
   add	hl, bc
   jr	nc, $+3
   inc	de
   
   dec	a
   jr	nz, _loop
   
   ret
 

24*24 multiplication

The following routine multiplies bcd by ehl and places the result in bcdehl. It uses 2 bytes of ram, but those can be substituted for IX half registers. (By thepenguin77)

multDBCbyEHL:
	
	push	de
	push	hl
	
	ld	ix, $8000
	ld	(ix), l
	xor	a
	ld	h, a
	ld	l, a

	call	do8Bits

	ld	(ix+1), a
	pop	af
	ld	(ix), a		
	push	de
	ld	a, (ix+1)

	call	do8Bits

	ld	(ix+1), a
	pop	af		;least sig number
	ex	de, hl
	ex	(sp), hl	;D and 2nd least sig in for new number
	ld	(ix), l
	pop	hl		;D and 2nd least sig
	push	af		;least sig number
	push	hl		;2nd least sig number
	ex	de, hl
	ld	a, (ix+1)

	call	do8Bits

	ld	b, a
	ld	c, h
	ld	d, l
	pop	hl
	ld	a, l
	pop	hl
	ld	h, a
	ret

;####
;input: DBC = 1 number
;	AHL = running number
;	(ix) = to multiply by
;output: AHLE = output
;	E is done
;	DBC = 1 number

do8Bits:
	ld	(ix+1), 8
loop:
	srl	(ix)
	jr	nc, skip

	add	hl, bc
	adc	a, d
skip:
	rra	
	rr	h
	rr	l
	rr	e
	dec	(ix+1)
	jr	nz, loop
	ret
 

Signed versions

8*8 multiplication

16*8 multiplication