La multiplication en assembleur
(comment ça marche ?)

I.) Bein oui comment ça marche, puisque le SATURN (microprocesseur) ne sait faire que des additions ?

Près-requis :

Tout d'abord, il faut savoir quel type de multiplication on veut réaliser. En effet, il y a deux possibilités :

- les deux nombres à multiplier sont inconnus.
( dans ce cas, on affaire à un algorithme général dont on trouve plusieurs exemplaires en ROM).
- seul l'un des deux nombres n'est pas connu.
(dans ce cas, notre multiplication sera adaptée à la situation donc plus rapide que la méthode générale).

Les décalages et rotations:

.Le mieux est de commencer par un exemple.
soit A , le nombre binaire suivant 110010 réalisons l'opération suivante A+A

  110010		0+0             --> 0 
+ 110010		0+1 et 1+0      --> 1
-----------		1+1             --> 0 et une retenue
 1100100 
.On remarque que lorsque l'on ajoute un nombre à lui même ( donc qu'on le multiplie par deux ) et bien il suffit en binaire de décaler tous les bits qui le composent vers la gauche et rajouter un zéro à droite.
Ce principe marche aussi dans l'autre sens à savoir que si l'on décale tous les bits qui le composent vers la droite en supprimant le bit le plus à droite, on réalise une division par deux.

Sur la HP, on peut donc réaliser :
- une multiplication par 2 avec l' instruction A=A+A.champs ( de même pour B,C et D ).
- une division par 2 avec l'instruction ASRB ( dans le cas du registre A ).

Ainsi par extension pour faire une multiplication par 4 du registre C limité au champs A:
C=C+C.A C=C+C.A suffit !!!

Là on a traité le cas de l'addition au niveau binaire or dans la HP on parle aussi en quartets c'est à dire en groupe de quatre bits (ce qui donne un nombre hexadécimal).
Que se passe-t-il lorsque l'on réalise un décalage d'un quartet vers la gauche (ajout d'un 0 à droite)? soit le nombre hexadécimal suivant #1Ch

|   1|   C|
|0001|1100|
et
|   1|   C|   0|
|0001|1100|0000| il quatre décalages binaires donc une multiplication par 2*2*2*2 =16
Sur la HP, on peut donc réaliser :
- une multiplication par 16 avec l' instruction ASL.champs ( de même pour B,C et D ).
- une division par 16 avec l'instruction ASR.champs ( dans le cas du registre A ).

2.) Cas où seul l'un des deux nombres n'est pas connu

.Utilisation par exemple dans les programmes de jeux où l'on a un grob qui regroupe tous les sprites ( les personnages de Hpbubble par exemple ;D)
et bien on donne un code qui représente la position chaque personnage dans ce grob ainsi 0 -> bubble, 1-> le robo, 2-> le vampire ....
.Bref au moment de l'afficher il faut retrouver sa position dans le grob or tous ont la même taille. Il suffit donc de multiplier le code avec la taille
Bon là j'ai pas été très clair parce que j'ai voulu faire simple avec du compliqué sans en avoir le temps (QC lundi)

Concrètement ça donne quoi?

.Imaginons que l'on veuille multiplier un nombre se trouvant que le registre A par 33
rappel de ce que l'on peut faire :
-multiplier par 2 (A+A)
-multiplier par 16 (ASL)
-des additions, car il ne faut pas oublier qu'une multiplication et une série d'addition

bien voyons comment on peut faire 33 avec nos outils basiques :

33=1+1+.. (33).. +1        trop long
33=2*2* ..(16).. *2+1      trop long
33=16*2+1                  ah pas mal!!! 
Le truc c'est de regarder quel est le multiple de 16 le plus proche ici 33/16=2.06 c'est 32=2*16
puis d'ajuster 33-32=1
le programme est donc :
         % le nombre à multiplier se trouve dans A
C=A.W    % on le sauve en vu de l'addition finale
ASL.W    % ici A=A*16
A=A+A.W  % ici A=A*16*2
A=A+C.W  % enfin A=A*16*2+1
         % et voila A contient A*33
         % avec ce programme on utilise entièrement les registres ( champs W ) 
         % aussi l'astuce consiste à réduire ce champ si possible pour gagner en vitesse
De même mais avec une petite astuce

.Imaginons que l'on veuille multiplier un nombre se trouvant que le registre A par 254
on commence par voir combien de fois on peut faire la multiplication par 16, on a 254/16=15.875 il faut faire 240=16*15 puis on ajuste 254=16*15+2*2

C=A.W    % on le sauve en vu de l'ajustement
ASL.W    % ici A=A*16
B=A.W  
A=A+B.W
   ...
(15 fois)
   ...
A=A+B.W  % ici A=A*240
C=C+C.W  % ici C=C*2 ou A=A*2 puisque A=C (première ligne)
C=C+C.W  % ici C=C*4 ou A=A*4
A=A+C.W  % enfin A=A*16*15+A*4
.Mais il y tout de même un problème car on doit faire 15 fois l'instruction ASL
Hé oui il faut penser autrement et si on faisait 254=16*16-4 pas bête hein ?..?
C=A.W    % on le sauve en vu de l'ajustement
ASL.W    % ici A=A*16
ASL.W    % ici A=A*256
C=C+C.W  % ici C=C*2 ou A=A*2 puisque A=C (premiere ligne)
C=C+C.W  % ici C=C*4 ou A=A*4
A=A-C.W  % enfin A=A*16*15-A*4
. Et voila le travail!!!!

3.) Cas où aucun des deux nombres est connu

.Utilisation bon bein c'est une grande partie des multiplications pour tout ce qui est calcul mathématique

Programmes en ROM

. Pour ce type d'opération on trouve pas mal d'exemples en ROM prenons par exemple l'adresse 03991
utilisable dans vos programmes en assembleur avec l'instruction GOSBVL 03991
Celle ci prend comme argument A et C puis renvoie A*C dans B ( seulement le champs A de chaque registre est utilisé )

*03991
B=0.A               %
?A!=0.A -> OK       % si c'est une multiplication par zéro
RTN                 % on retourne directement zéro

*OK                 % sinon on continue
?CBIT=0.0 -> PAIRE  % test si le multiplicateur est pair
B=B+A.A             % on l'additione une fois pour se retrouver avec un multiplicateur pair
RTNC                % fin si débordement ( nombre trop grand >1048575 ou  #FFFFFh )
CBIT=0.0            % multiplicateur pair
*PAIR               %
?C!=0.A -> NONNUL   % teste si la multiplication est finie ( C=0 plus de multiplicateur) 
RTN                 %
*NONNUL             % ce n'est pas le cas 
CSRB.A              % on divise C par 2
A=A+A.A             % on multiplie A par 2
GONC OK             % on boucle 
RTN                 % sauf si débordement           
explications de ce programme

. le point d'exclamation signifie que le saut ne se fait pas. !(-> saut)

EX:
A=4 et C=3
B=0.A ?A!=0.A -> OK ?CBIT=0.0 !(-> PAIR) B=4 C=2 ?C!=0.A -> NONNUL
C=1 A=8 -> OK ?CBIT=0.0 !(-> PAIR) B=12 C=0 ?C!=0.A !(->NONNUL)
RTN et B=12

EX:
A=4 et C=6
B=0 C=3 A=8 B=8 C=2 C=1 A=16 B=8+16=24 C=0 RTN
4.) Comment extraire un programme en ROM

. La méthode ne marche pas dans tout les cas ....

pour extraire le programme ci-dessus faire :

256 ATTACH
#03991h
DUP
100 +
ASM->
et voila !!!
en fait on demande à la HP de décompiler le programme se trouvant entre #03991h et #03991h +100= #039F5h
si le programme n'est pas complet il faut mettre un nombre plus grand que 100.

5.) Les adresses en ROM

#03991h A*C --> B , champs A
... à dire vrai j'en connaissais deux trois sur HP48 mais il me semble qu'elles ne sont plus valablent sur Hp49
#11642h A*C --> B , champs A
#53EE4h A*W --> B , champs W

si vous en avez d'autres envoyez moi un mail pour que je complète merci


Pfff 2 heures et demi de boulot :p, il est fatigué le gandalf Samedi 25 novembre 2000 (17:40)
En plus avec ma manie de me taper tout le code HTML ....