MSX Village forum

La Place des Développeurs multipilcation 16 bits assembleur solutions pour multiplier 2 valeurs 16 bits en assembleur

Visiteur

Vagabond

Rang

Avatar

Message : 0

Le 29/09/2017 à 10h47
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 :
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
 
   
Metalion Membre non connecté

Conseiller Municipal

Rang

Avatar

Inscrit le : 23/12/2009 à 15h32

Messages: 1503

Le 01/10/2017 à 18h08
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 :

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