Revenir au plan du site
Divisions en assembleur Z80
Le Z80 est un processeur 8 bits, il n'est pas capable de réaliser nativement des divisions ou des multiplications. Voici une petite compilation de routines de division (wikiti, Z80 heaven, grauw, cpcwiki)
division 8 x 8 non signée => C
c_divise_par_d ; résultat dans le registre C
ld b,8
xor a
.loop
sla c
rla
cp d
jr c,.skip
inc c
sub d
djnz .loop
ret
|
division 16 x 8 non signée => C
hl_divise_par_c ; résultat dans HL, et le reste dans A
ld b,16
xor a
.loop
add hl,hl
rla
cp c
jr c,.skip
inc l
sub c
.skip
djnz .loop
ret
|
division 16 x 16 non signée => A:C
bc_divise_par_de ; résultat dans A:C, et le reste dans HL
ld hl,0
ld a,b
ld b,16
.loop
sll c
rla
adc hl,hl
sbc hl,de
jr nc,$+4
add hl,de
dec c
djnz .loop
ret
|
division 32 x 32 non signée BC':BC / DE':DE => IY:IX + remainder BC':BC
Suite au cours sur les divisions, voici la routine optimisée avec la méthode naïve. Si on compare avec des méthodes classiques, elle est beaucoup plus rapide (genre, beaucoup, presque 10 fois plus rapide) quand le résultat est petit et 50% plus lent quand le résultat est trèèèès grand.
Selon vos cas d'usage et les besoins en mantisse, utilisez l'une ou l'autre. J'ai comparé avec celle de
[ Zeda ], seule
que j'ai finalement trouvée (Merci Prodatron!) permettant de diviser deux nombres 32 bits.
Par ailleurs, le code n'utilise pas de mémoire vive et repose uniquement sur les registres.
; Z80 division 32 bits unsigned
div32unsigned
; input :
; dividende in BC':BC
; divisor in DE':DE
; output :
; result in IY :IX
; remainder in BC':BC
;
; this function is suitable for ROM usage (no memory is used)
; this function can be enhanced to not use STACK (remove the RET and add a JR at the end)
; known limitation => divisor on 31 bits maximum
; speed depends on result size
; (expect from 100 nops for a small quotient to 2000 nops for a big quotient)
; find max iterations to do and prepare divisor
xor a
jr .firstIterationQbit
.findMaxQbit
sla de : exx : rl de : exx ; divisor x 2
.firstIterationQbit
inc a : ld hl,bc : or a : sbc hl,de : exx : ld hl,bc : sbc hl,de : exx : jp nc,.findMaxQbit ; compare dividende to divisor
.maxQ cp 1 : jr z,.noadjust : exx : srl de : exx : rr de : dec a : .noAdjust
; initialise quotient
ld ix,0
ld iy,0
; iterate using binary
jr .firstIteration
; compute quotient with almost ALL registers available
.computeQuotientBit
add iy,iy : add ix,ix : jr nc,.NextIteration : inc yl ; shift quotient
.firstIteration
or a ; reset Carry for next SBC
.NextIteration
ld hl,bc : sbc hl,de : exx : ld hl,bc : sbc hl,de : jp c,.bit0 ; cannot substract => 0
.bit1
; update remainder + shift divisor
ld bc,hl : srl de : exx : rr de : ld bc,hl
inc xl ; inject bit to quotient
dec a : jr nz,.computeQuotientBit
ret
.bit0
; do not touch remainder, shift and loop
srl de : exx : rr de ; shift divisor
dec a : jr nz,.computeQuotientBit
ret
|
Vous pouvez jeter un oeil dans les liens pour trouver encore plus de routines différentes, en particulier sur les sites de calculatrices Texas Instrument.