	OPTIMISATION EN ASSEMBLEUR: LES WAITSTATES du 68030.


	Voici quelques dparts d'ides pour rendre plus rapide une routine
assembleur sans modifier les instructions utilises. A priori, ceci semble
impossible puisque chaque instruction possde son temps d'excution bien
dfini. Pourtant, voyons l'exemple ci dessous:

	move.l (a6)+,d0
	rol.l d0
	swap d0
	move.l d0,(a5)+

	Ds la deuxime ligne, le programme n'est pas optimis! En effet,
l'opration de lecture dans D0 n'est pas encore termine lorsque le
processeur anticipe l'instruction suivante (rol.l d0), mais l, il doit
attendre car il a besoin de la valeur D0 pour continuer: d'o l'insertion
de quelques 'waitstates'.


	Supposons que les 4 lignes de code plus haut soient  rpter un
grand nombre de fois, une premire ide serait de faire 4 boucles en une
afin de ne pas passer trop souvent sur l'instruction de comptage:

boucle:
	move.l (a6)+,d0		; une fois
	rol.l d0
	swap d0
	move.l d0,(a5)+
	move.l (a6)+,d0		; deux fois
	rol.l d0
	swap d0
	move.l d0,(a5)+
	move.l (a6)+,d0		; trois fois
	rol.l d0
	swap d0
	move.l d0,(a5)+
	move.l (a6)+,d0		; quatre fois
	rol.l d0
	swap d0
	move.l d0,(a5)+
	subq.l #1,d7		; d7 comme compteur
	bne.s boucle

	Nous allons profiter du nombre de registres du processeur pour
amliorer ce code et 'placer' des instructions l o on aurait eu des
'waitstates'!:

boucle:
	move.l (a6)+,d0
	move.l (a6)+,d1
	move.l (a6)+,d2
	move.l (a6)+,d3
  ; utilisation diffre des registres , ainsi
  ; ils sont  jour lorsqu'on s'en sert
  ; pas besoin de 'waitstates'
	rol.l d0
	rol.l d1
	rol.l d2
	rol.l d3
  ; mme chose
	swap d0
	swap d1
	swap d2
	swap d3
  ; et encore
	move.l d0,(a5)+
	move.l d1,(a5)+
	move.l d2,(a5)+
	move.l d3,(a5)+
	subq.l #1,d7
	bne.s boucle

	Malheureusement, en testant la vitesse de ce code, on s'apperoit
qu'il est PLUS LENT que le prcdent!!! Qu'avons nous chang pour qu'il
ait tant ralenti (puisqu'une partie quand mme a t acclre) ?
	C'est la fin de la boucle qui forme le boulet: une opration
d'criture ne peut avoir lieu que si la prcdente est compltement
termine! Et nous avons maintenant 4 oprations d'criture en (a5)+
successives! Un nombre dramatique de 'waitstates' sont insrs... Il faut
alors jouer l'entrelacement un peu plus finement et tenter de sparer  la
fois les lectures en mmoire de l'utilisation des registres et sparer les
oprations d'critures entre-elles:

boucle:
	move.l (a6)+,d0
	move.l (a6)+,d1
	move.l (a6)+,d2
	move.l (a6)+,d3
  ; utilisation diffre des registres
	rol.l d0
	swap d0
	rol.l d1
  ; et sparation des instructions d'criture
	move.l d0,(a5)+
	swap d1
	rol.l d2
	move.l d1,(a5)+
	swap d2
	rol.l d3
	move.l d2,(a5)+
	swap d3
	move.l d3,(a5)+
	subq.l #1,d7
	bne.s boucle

	Cette boucle est de meilleure qualit puisqu'on arrive  passer
des instructions ' l'oeil' sur des temps qui seraient de toutes faons
perdus en cycles d'attente.

Les rsultats sur mon TT
------------------------

	Sans l'utilisation du cache du 68030, il n'y a aucune
amlioration mesurable. Avec le cache:
	* 10% de temps en moins en TT Ram
	* 25% de temps en moins en ST Ram!!! (avis aux possesseurs de
	Falcons)

	Gardons  l'esprit que nous avons conserv EXACTEMENT les mmes
instructions, elles ont simplement t rordonnes!
	Petit dtail amusant: la premire version (celle n'utilisant que
D0) tourne plus vite en TT-Ram qu'en ST-Ram, jusqu'ici tout est normal.
Par contre, la version optimise tourne PLUS VITE en ST-Ram qu'en TT-Ram
(2"97 contre 3"37...). Il y aurait une mthode plus spcifique  la TT-Ram
que a ne m'tonnerait pas...


La conclusion
-------------

	On rservera ce travail pour une ultime optimisation lorsque
l'algorithme est sans failles, car le code devient brusquement moins
lisible! Mais, avouez que, en gardant le mme algorithme, obtenir -25% sur
le temps (c'est  dire +33% de vitesse), on aurait tort de s'en priver!

	Guillaume Tello
	gtello@planete.net