* * *
Programmation : Initiation à l'assembleur 68030
* * *

 Pour continuer cette initiation, je vais vous parler des nombres à virgule fixe. C'est un moyen rapide de représenter les nombres non entiers pour des calculs rapides mais hélas peu précis (dans une certaine limite). Le principe de base de ces nombres à virgules fixes est le suivant : représenter les nombres décimaux multipliés par une puissance de 2. Ainsi ils deviennent entiers! La partie décimale est donc codée sur un certain de nombre de bits (qui dépend de la précision que l'on veut obtenir), et la partie entière sur le reste des bits. Si l'on veut avoir 8 bits pour la partie décimale (l'erreur est majorée par 1/256 soit 0.004 (1/256 = 0.0039)), il suffit de multiplier par 256 ce nombre. Ainsi la représentation dans ce cas de 3.1415927 est :

3.1415927 x 28 = 804.24772

 qui est arrondi à 804. Pour la conversion inverse, il suffit de diviser le nombre par la puissance de 2 :
804/28 = 3.140625

Il y a bien une perte de précision, mais pour certain calcul, ils sont négligeables (calcul 3D...). Après la représentation, passons à l'utilisation :


 L'addition/soustraction

 Si l'on pose le calcul sur papier, cela nous donne :

3.1415927 x 28 + 2.7182818 x 28 = 5.8598745 x 28

  Soit le résultat dans la représentation correcte. Le raisonnement est le même pour la soustraction (au signe près). Ces différentes opérations s'effectuent simplement grâce aux opérations add et sub du 68030.


 La multiplication

 Commençons par la multiplication d'un nombre entier avec un nombre à virgule fixe, nous avons :
3.145927 x 28 x 2 = 6.2831853 x 28

 Donc si l'on multiplie par un nombre entier, alors le résultat se trouve sous la bonne représentation. Pour la multiplication de deux nombres à virgule fixe, nous avons :

 3.1415927 x 28 x 1 x 28 = 3.1415927 x 216

Aie! Multiplier par 1 un nombre, ne donne plus ce nombre? Le problème qui survient est le suivant : les deux nombres sont multipliés par une puissance de 2, et le résultat se trouve multiplié par deux fois cette puissance de 2. Pour retrouver le résultat correct, il faut le diviser par cette puissance de 2. Passons à la division :


 Division

 La division par un nombre entier, ne pose pas de problème :

 3.145927 x 28 / 2 = 1.5707963 x 28

 Pour la division d'un nombre entier, nous avons le problème suivant :

  2 / 3.145927 x 28 = 0.6366197 / 28

 Soit le résultat, mais divisé par notre puissance de 2. Il faut donc multiplier le dividende par deux fois notre puissance de 2 pour obtenir le résultat correct, et non une fois le résultat, car il y aurait pendant la division un arrondissage à l'entier inférieur : grosse perte de précision. Et maintenant la cerise sur le gâteau : la division de deux nombres à virgules fixes :

  3.145927 x 28 / 2.7182818 x 28 = 1.1557273

  Re aie, le résultat n'est toujours pas dans la bonne représentation, il faut donc multiplier par notre puissance de 2 le dividende pour obtenir un résultat correct (et non le résultat pour les mêmes raisons que précédemment). Bon voyons du côté assembleur, comment cela va se déroulé :

 Après la théorie, passons à l'exemple de cet article :
génération d'ensemble de Malderbrot. Ce petit programme permet de générer des dessins comme celui qui se trouve sous l'article. D'ailleurs ce dernier est généré grâce à ce programme.

 La représentation des nombres sur 32 bits est la suivante :

 Donc pour convertir un nombre décimal en nombre dans bonne la représentation, il suffit de multiplier par 224 soit 16777216. Pour faire l'inverse, il suffit de le diviser par ce même nombre.

 Bon voyons comment va se dérouler les différentes opération :


L'addition/soustraction


Sans commentaire


La multiplication

 Le résultat a pour partie entière : 16 bits, et pour partie décimale 48 bits. Il faut diviser le résultat sur 64 bits par 224, et obtenir le résultat correct dans le mot long de poids faible. Mais il y a une autre manière de voir, plus simple, si l'on multiplie par 28 le mot de poids fort, les 24 bits de poids forts de ce mot contiennent le résultat. Il suffit de les compléter par les 8 bits de poids fort du mot long de poids faible. Ce qui nous donne pour une multiplication :

move.l d5,d2
muls.l d5,d3:d2
* d3:d2 = Zx x Zx en 248
* soit 16 bits en entiers
* dans le mot long de poids
* fort, donc on multiplie par
* 28 pour obtenir le poids
* fort correct dans d3
asl.l #8,d3
* mais il nous manque 8 bits
swap d2
* qui se trouve dans les
* poids forts
lsr.w #8,d2
* de d2
move.b d2,d3
* d3 contient donc Zx x Zx

Rq. : Au lieu de faire swap d2 puis lsr.w #8,d2, on peut aussi faire rol.l #8,d2 pour avoir le même résultat (dans l'octet de poids faible)! Tous les chemins mènent à Rome!

 Comme dans l'exemple fournit, il n'y a pas de division, vous n'aurez pas droit à la division, nah!

  Le principe de calcul d'un ensemble de Malderbrot est le suivant :
  On regarde à partir de quand une suite diverge, à chaque point du plan. Cette suite est la suivante :

Zx(n+1) = Zx(n) x Zx(n) - Zy(n) x Zy(n) + Cx
Zy(n+1) = 2 x Zx(n) x Zy(n) + Cy

Avec Zx(0)=Cx et Zy(0)=Cy, Cx = X x Xscale + Xleft, et Cy = Y x Yscale + Ytop. Xscale et Yscale représente le pas de déplacement en x et y dans le plan. Ainsi le point de coordonnées (X,Y) (à l'écran), aura la suite initialisée à Cx et Cy suivant ses coordonnées X et Y à l'écran. Donc sur une ligne Cy reste constant, et il suffit d'ajouter Yscale à Cy pour passer à la ligne suivante, de la même manière pour Cx, sauf que l'on ajoute à tous les coups Xscale. Le programme est un peu plus costaud que les autres, on commence par définir le mode Vidéo (Video_mode (qui n'est que pour RGB, le changer par %100011100 pour un VGA)), ainsi que la taille d'un écran. Ces définitions sont utiles pour le fichier principa.s (cf. Falk'mag 4 : plasma).  Puis la largeur et la hauteur de l'écran. Enfin des constantes pour notre routine : la puissance de 2 par laquelle il faut multiplier les nombres décimaux (MATH_offset), la largeur de calcul, l'include de fichier qui contient les coordonnées de la zone qui va être calculée. La directive include permet d'inclure un fichier dans le source, c'est à dire de remplacer la ligne include "toto", par le fichier toto. Ensuite vient le calcul de mag (largeur de la zone à calculer sur le plan), xscale/yscale (pas de déplacement sur le plan).

 Ensuite il y a l'inclusion du fichier principa.s. Ce dernier s'occupe du changement de résolution, d'appeler prg_init une fois, et de faire une boucle tant que la touche espace n'a pas étée frappée. Dans cette boucle, il y a l'appel de la routine qui ne calcul qu'une ligne de l'ensemble de Malderbrot.

  Pour plus d'explications sur l'affichage des points, voir Falk'mag #1 qui traite des routines de points en True Color et 256 couleurs. Ici s'achève les explications, regardez le source qui est bien commenté!

 Il y a aussi une routine qui permet d'extraire une palette d'un fichier GIF, alors à vos programme de dessin et dégradé! Bon courage et bon code!

Golio Junior