Le Projet Doom
Routine de rotations en code généré
La multiplication par code généré
Présentation :
La routine qui va suivre a été écrite par Victor Achiage et Clément
Pillias, selon une critique mutuelle qui la rends extremement
optimisée (on n'a pas réussit à faire plus rapide, si vous y arrivez,
faites-le nous savoir !). Son rôle est de créer le code (langage
machine) qui permettra de faire une multiplication par une valeur
fixée (que l'on nomera Alpha). Pour bien la comprendre, il
faut que vous ayez assimilé les principes du
code généré.
Utilisation :
Cette routine prends en entrée la valeur du multiplicateur
(Alpha) dans Ab, et D0 doit pointer vers
la zone mémoire où la routine sera générée. Alpha est
comprise entre 0 et 255 (un octet) et non signée. Il s'agit d'une
valeur décimale : 255 correspond en fait à 1 (la valeur n'est pas
modifiée) et 127 à 1/2 (la valeur est divisée par 2).
En sortie, D0 pointe sur la zone située après la routine
générée.
Utilisation de la routine produite :
La routine produite prends en argument une coordonée dans la map dans
Ca, et renvoie la coordonée multipliée par Alpha*16
dans Ba.
On a considéré que l'espace minimum entre deux points de la carte
pouvait être de 20 cm (ce qui est à peu près la largeur d'un mur).
Toutefois la position du joueur dans la carte doit être plus précise
que cela. L'experience des précédentes versions de Doom par Clément
Pillias (HpFool) à montré qu'une précision 16 fois supérieure était
adaptée, ce qui nécessite de rajouter 4 bits décimaux aux coordonées.
De plus l'algorithme de projection des coordonnées dans l'écran (voir
l'algo) nécessite
de faire 6 décalages vers la gauche. Ainsi on ne peut pas utiliser
les 6 bits de poids forts des coordonées. Comme pour des raisons de
rapidité il n'était pas envisageable d'utiliser des coordonnées sur
un champs plus large que A, on arive au découpage suivant
pour les coordonnées passées en argument à la routine :
- 6 bits de poids fort inutilisés (à 0).
- 10 bits pour la partie entière de la coordonée.
- 4 bits de poids faible pour la partie décimale de la
coordonnée.
Les 10 bits ne permettent pas d'obtenir des coordonées supérieures à
204.8 metres, ce qui est peu. Mais comme un mur situé au delà de cette
distance ne serait pas visible (dans la version précédente de Doom,
une limite semblable est fixée à une centaine de metres), ce n'est pas
gênant pour cette routine, et cela ne limite pas la taille des
tableaux (le coordonées peuvent être stockées dans les tableaux sur
des champs plus grands).
Implémentation :
Pour plus de rapidité, et bien que cela prenne plus de place, on a
décidé de dérouler la boucle (qui n'avait que 8 itérations : une par
bit de Alpha).
Egalement pour plus de rapidité, on effectue le moins possible
d'écritures en mémoire, c'est pour cela que l'on construit tout
d'abord le code dans Cw avant de l'écrire d'un coup. Comme
le code généré pour chaque itération est : "C+C.A" ou
"B+C.A C+C.A", ce qui se traduit en langage machine par
"C1" ou "C1C6", il y a au maximum 4 quartets générés
par itération. Dans un champ W on peut donc faire tenir 4
itérations, ce qui correspond à un des deux quartets de Alpha.
Ainsi seules deux écritures en mémoire sont nécessaires. La création
du code dans Cw se fait à l'aide de P et de
l'instruction LC (qui commence à charger les quartets à
partir du champ P).
Le code :
$ Gestion du cas particulier où Alpha vaut 255.
A+1.B
SKIPNC {
LC 101F5D $ B=C.A BSL.A RTN
DAT0=C.6 D0+6
RTN
}
$ Génération de "B=0.A"
LC 1D DAT0=C.B D0+2
$ Génération du code pour le premier quartet de Alpha
?ABIT=0.0 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.1 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.2 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.3 { LC 1C P+1 P+1 }
LC 6C
$ Ecriture du code généré en mémoire
P+1 DAT0=C.WP
CD0EX C+P+1 CD0EX $ on saute les quartets écrits.
$ Ecriture de "CSR.A BSR.A"
P=0 LC 5F6F
DAT0=C.4 D0+4
$ Génération du code pour le second quartet de Alpha
?ABIT=0.4 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.5 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.6 { LC 1C P+1 P+1 }
LC 6C P+1 P+1
?ABIT=0.7 { LC 1C P+1 P+1 }
$ pas besoin de faire un LC 6C (C+C.A) ici !
$ Ecriture du "RTN" (à la place du dernier C+C.A)
LC 10
P+1 DAT0=C.WP
$ Fin (en remettant P à 0)
P=0
RTN
La rotation.
A finir...
|