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...

email