Quand on fait des démos, il arrive souvent que l'on doive multiplier les y par la taille d'une ligne et ensuite d'y ajouter la valeur de x.
int offset = (320*y)+x;
ce qui se traduit en assembleur par quelque chose du genre:
; Cycles : 386 | 486 mov ax,[y] ; 4 | 1 mov bx,320 ; 2 | 1 mul bx ; 22 | 26 add ax,[x] ; 6 | 1 ; Total = 34 | 29
sauf que… cela prends du temps:
Si, sur un 386, un mov prends relativement peu de temps (~ 4 cycles d'horloge) et un add (~2 cycles), un mul est BEAUCOUP plus couteux (jusqu'à 22 cycles sur un 386sx).
on le voit, le 486 est plus optimisé pour les fonctions mov et add, mais le mul est encore plus lourd; heureusement que les 486 sont généralement plus rapide que les 386.
alors qu'un 386 dispose d'instructions simples mais puissantes shld/shrd qui ne demandent que 3 cycles pour s'executer.
on peut donc ré-écrire le code 'c':
int offset = (y<<6)+(y<<8)+x;
le code précédent peut donc s'écrire:
; Cycles : 386 | 486 mov ax,[y] ; 4 | 1 mov bx,ax ; 2 | 1 xor dx,dx ; 2 | 1 shld ax,dx,6 ; 3 | 2 shld bx,dx,8 ; 3 | 2 add ax,bx ; 3 | 1 add ax,[x] ; 6 | 2 ; Total = 21 | 10
on “gagne” presque 40% du temps sur un 386, et 65% sur un 486; ce sont des gains énormes, surtout quand on calcule la position (offset) de centaines de points par frame.
si vous désirez, avoir une résolution différentes, et tant que vous êtes en chained mode (càd que un octet représente un point directement dans la mémoire), vous pouvez utiliser cette fonction; il faut “juste” adapter les shift values:
mul | bitshift |
---|---|
80 | (y«6)+(y«4) |
320 | (y«6)+(y«8) |
640 | (y«9)+(y«7) |
Tutoriaux disponible