La Place des Développeurs multipilcation 16 bits assembleur solutions pour multiplier 2 valeurs 16 bits en assembleur
Visiteur
Vagabond
Message : 0
Bonjour à tous,
Suite au sujet sur la mise au carré en assembleur Z80, je me suis intéressé à trouver un moyen de multiplier deux valeurs en assembleur d'une manière plus efficace qu'en faisant une boucle d'additions.
Je suis tombé sur la multiplication égyptienne et cela m'a tout de suite interpelé car cette méthode utilise les puissances de 2, ce que la machine sait faire très rapidement. Regardez ici :Technique_de_la_multiplication_dans_l_egypte_antique
Voici donc le code assembleur Z80 que j'ai pondu, mettant en œuvre cette méthode avec les opérations possibles sur les registres 16 bits :
Voici du code BASIC pour appeler cette routine :
En cas de débordement je positionne l'indicateur de signe négatif et renvoie un résultat à 0, bien sûr on peut coder un autre comportement.
Exemple en 8 bits également :
Suite au sujet sur la mise au carré en assembleur Z80, je me suis intéressé à trouver un moyen de multiplier deux valeurs en assembleur d'une manière plus efficace qu'en faisant une boucle d'additions.
Je suis tombé sur la multiplication égyptienne et cela m'a tout de suite interpelé car cette méthode utilise les puissances de 2, ce que la machine sait faire très rapidement. Regardez ici :Technique_de_la_multiplication_dans_l_egypte_antique
Voici donc le code assembleur Z80 que j'ai pondu, mettant en œuvre cette méthode avec les opérations possibles sur les registres 16 bits :
Code ASM :
;--------------------------------------------------------- ; Multiplication 16 bits BC x HL, resultat dans DE ; base sur le principe de la multiplication egyptienne ; si debordement : indicateur signe positionne ;--------------------------------------------------------- ; .FILENAME "MLT16B" .BASIC ; type de fichier .ORG 0C000h ; le programme commence en C000h .START DEBUT ; point d'entree du programme DEBUT: NOP ; ; chargement des registres a partir des emplacements ; memoire NB1 et NB2 LD BC,[NB1] LD HL,[NB2] CALL MLT16 LD [RESULT],DE RET ; routine de multiplication MLT16: XOR A LD D,A LD E,A ; DE = 0 MLTBCL: LD A,C OR B ; tant que BC > 0 JR Z,MLTFIN SRL B ; BC = BC / 2 RR C JR NC,MLTPAIR ; si BC n'est pas divisible par 2 EX DE,HL ADD HL,DE ; DE = DE + HL JR C,MLTDBR ; debordement EX DE,HL MLTPAIR: ADD HL,HL ; HL = HL x 2 JR MLTBCL ; boucle MLTDBR: XOR A LD D,A LD E,A ; DE = 0 OR 080h ; debordement : positionne l'indicateur de signe MLTFIN: RET .ORG 0C100h ; les donnees commencent en C100h NB1: DW 00100h NB2: DW 00020h RESULT: DW 0h
Voici du code BASIC pour appeler cette routine :
Code TEXT :
10 CLEAR 100,&HC000 20 BLOAD "MLT16B.BIN" 30 FOR A=255 TO 255 STEP 1 40 FOR B=254 TO 260 STEP 1 50 POKE &HC100,(A AND 255) 55 POKE &HC101,(A AND &HFF00)/256 60 POKE &HC102,(B AND 255) 70 POKE &HC103,(B AND &HFF00)/256 100 DEFUSR0=&HC000 110 X=USR0(0) 210 PRINT "A="A" B="B" RES="A*B" "PEEK(&HC105)*256+PEEK(&HC104) 280 NEXT B 290 NEXT A
En cas de débordement je positionne l'indicateur de signe négatif et renvoie un résultat à 0, bien sûr on peut coder un autre comportement.
Exemple en 8 bits également :
Code ASM :
;--------------------------------------------------------- ; .FILENAME "MLT8B" .BASIC ; type de fichier .ORG 0C000h ; les donnees du programme commencent en C000h .START DEBUT ; point d'entree du programme DEBUT: NOP ; LD BC,[NB1] ; multiplication 8 bits de b par c, résultat dans a ; place du code : 14 octets ; si debordement ? ... a faire ; XOR A BOUCLE: DEC B INC B ; tant que b > 0 JR Z,FINM SRL B ; b = b / 2 JR NC,PAIR ; si b n'est pas divisible par 2 ADD A,C ; alors a = a + c PAIR: SLA C ; c = c x 2 JR BOUCLE ; fin tant que FINM: LD [RESULT],A RET NB1: DB 11 NB2: DB 12 RESULT: DB 0
Cette technique est effectivement la plus rapide en assembleur.
Elle est utilisée depuis longtemps : http://sgate.emt.bme.hu/patai/publications/z80guide/part4.html
Optimisation :
Elle est utilisée depuis longtemps : http://sgate.emt.bme.hu/patai/publications/z80guide/part4.html
Optimisation :
Code :
Fast 16-bit multiplication
The following solution for this problem is a direct rewrite of the second multiplication routine (the one which did HL=H*E), therefore I am not commenting it too much:
Mul16: ; This routine performs the operation DEHL=BC*DE
ld hl,0
ld a,16
Mul16Loop:
add hl,hl
rl e
rl d
jp nc,NoMul16
add hl,bc
jp nc,NoMul16
inc de ; This instruction (with the jump) is like an "ADC DE,0"
NoMul16:
dec a
jp nz,Mul16Loop
ret
MSX1: Daewoo DPC-200 / Yamaha CX5M
MSX2: Sony HB-F9P
MSXVR
Vidéo: V9990 (GFX-9)
Audio: MSX-Music (FM-PAC) / MSX-Audio (Audiowave) / OPL4 (Monster Sound FM Blaster) / OPNB (Neotron)
Répondre
Vous n'êtes pas autorisé à écrire dans cette catégorie