© 1998 - Nicolas Bruyère


Commment Jouer

 

Syntaxe

Il y a actuellement 20 instructions assembleur reconnues par la machine. Une code machine est composé d'un mnémonique (ou instruction) et de un ou deux arguments représentant des adresses mémoires. Il y a trois types d'adressage : direct, relatif ou relatif indirect. Une ligne de code source (qui une fois compilée occupe une case mémoire) est donc composée ainsi :

<instruction> <type argument 1> <argument 1> <type argument 2> <argument 2>

Les arguments (<argument 1> et <argument 2>) étant des adresses, les types d'arguments sont également appelés par la suite les types d'adressage.

Types d'adressage

Les types d'adressage (types des arguments) sont représentés ainsi :

Adressage direct (ou immédiat) : #
désigne une valeur (constante) numérique. Il ne s'agit donc pas d'une adresse mais d'une valeur immédiate. Exemple #1 représente la valeur 1.

Adressage relatif : aucun symbole. (dans le tableau des instuctions, le symbole est le R)
désigne une adresse relative à l'adresse courante. Exemple : 0 est l'adresse courante, 1 est l'adresse qui suit l'adresse courante et -1 est l'adresse qui précède l'adresse courante.

Adressage relatif indirect : @
désigne une case contenant une adresse. Exemple : @1 indique que la case suivante (1) contient l'adresse relative désirée.

Si tout ceci vous semble aussi obscur que le discours d'un homme politique, sachez tout d'abord que c'est beaucoup plus honnête, et ensuite que vous pouvez jeter un oeil aux exemples et l'oeil restant au tableau ci-dessous :

0 ADD #15 5 Ajoute 15 à la valeur se trouvant 5 cases plus bas
1 ADD 4 @4 Ajoute 1 à la case pointée par la case se trouvant 4 cases plus bas
2 ... (autre instruction)
3 ... (autre instruction)
4 ... (autre instruction)
5 DAT -14 Cette case prend la valeur 1 (-14+15) après l'exécution de la case 0
6 DAT 6 DAT 6 Cette case prend la valeur 10 (6+4) après l'exécution de la case 1

En ligne 0, nous ajoutons 15 (adressage direct) à la valeur se trouvant 5 cases plus bas (adressage relatif, donc la case 5). La case 5 passe donc de DAT -14 à DAT 1.

En ligne 1, nous ajoutons la valeur se trouvant 4 cases plus bas (adressage relatif, donc la case 5), donc la valeur 1, à la case pointée par la case se trouvant 4 cases plus bas (encore la case 5) qui étant égale à 1, pointe sur la case 6 (5 + 1).

Instructions : les 20 commandements

Instruction Type Arg 1 Type Arg 2 Description
DAT Arg1 # - Instruction non exécutable qui définit une constante en mémoire
MOV Arg1 Arg2 #R@ R@ Arg2 = Arg1 (ou DAT Arg1 si #Arg1)
ADD Arg1 Arg2 #R@ R@ Arg2 = Arg2 + Arg1
SUB Arg1 Arg2 #R@ R@ Arg2 = Arg2 - Arg1
MUL Arg1 Arg2 #R@ R@ Arg2 = Arg2 * Arg1
DIV Arg1 Arg2 #R@ R@ Arg2 = Arg2 / Arg1 (plante le processus si Arg1 = 0)
MOD Arg1 Arg2 #R@ R@ Arg2 = Arg2 modulo Arg1 (plante le processus si Arg1 = 0)
MIN Arg1 R@ - Arg1 = -Arg1
AND Arg1 Arg2 #R@ R@ Arg2 = Arg2 AND Arg1 (ET logique)
OR Arg1 Arg2 #R@ R@ Arg2 = Arg2 OR Arg1 (OU logique inclusif)
XOR Arg1 Arg2 #R@ R@ Arg2 = Arg2 XOR Arg1 (OU logique exclusif)
NOT Arg1 R@ - Arg1 = NOT Arg1 (complément à 1)
JMP Arg1 R@ - Saute à l'adresse Arg1
JMZ Arg1 Arg2 R@ R@ Saute à l'adresse Arg1 si Arg2 = 0
JMG Arg1 Arg2 R@ R@ Saute à l'adresse Arg1 si Arg2 > 0
DJZ Arg1 Arg2 R@ R@ Décrémente Arg2 puis saute à l'adresse Arg1 si le résultat est nul.
CMP Arg1 Arg2 #R@ R@ Compare Arg1 et Arg2 puis saute l'instruction suivante s'ils sont différents.
FORK Arg1 R@ - Crée un processus fils en 1 (adresse suivante) et saute en Arg1
KILL - - Tue un processus au hasard (sauf lui-même)
RND Arg1 Arg2 #R@ R@ Arg2 = Nombre au hasard compris entre 0 et Arg1

La mémoire a une taille de 2048 cases. Elle est circulaire : la case 0 est "à côté" de la case 2047. La case -1 représente donc la case 2047.

Les nombres (Arg1 et Arg2) sont codés sur 32 bits et sont signés.

Cas particulier de l'instruction DAT : l'adressage est toujours direct, le symbole # est donc inutile.

Un MOV #x y crée un DAT x en y. (car le premier argument est adressé directement).

Les commentaires dans le source assembleur sont introduits par le symbole ':' Ce sont des commentaires de fin de ligne, c'est-à-dire que tout ce qui se trouve après est ignoré par le compilateur. Les lignes vides ou bien ne contenant que du commentaire sont ignorées (et donc ne provoquent pas d'erreur).

Déroulement du jeu

Les sources en assembleur sont compilés puis chargés dans la mémoire de l'ordinateur. On peut charger autant de programmes que l'on veut. Le bouton Démarrer permet de lancer l'exécution de chacun des programmes se trouvant en mémoire (un programme est également appelé processus). L'ordinateur exécute l'instruction courante du processus courant, positionne le processus courant sur l'instruction suivante (sans l'exécuter) puis passe au processus suivant (i.e. le processus suivant devient le processus courant). Quand un processus exécute l'instruction interdite (DAT xxxx), il se plante lamentablement. Les 2048 cases de la mémoire sont initialisées à DAT 0, il est donc fortement déconseillé de se balader en dehors du programme !

Etant donné qu'il s'agit d'un jeu de guerre, un programme est également appelé guerrier. L'objectif du guerrier est de balancer un DAT xxxx dans le programme adverse afin que celui-ci meure dans d'horribles souffrances (la rumeur dit que le DAT 666 est la pire).

Si le compilateur rencontre une erreur lors de la compilation du source, l'instruction en erreur est remplacée par un DAT 0 qui provoquera le plantage du programme lors de l'exécution. Une erreur peut être une instruction qui n'existe pas (exemple : SCHMURTZ) ou bien une entorse au règlement (exemple : JMP #3 car l'adressage d'un JMP doit être relatif ou relatif indirect mais en aucun cas direct !). Le compilateur ne fait pas de différence entre les majuscules et les minuscules car il a été bien élevé, vous pouvez donc écrire jMp sans vous faire jeter comme un (ou une, j'espère bien rencontrer des guerrières :-) malpropre. Une division par 0 provoque également la fin irrémédiable et sans autre forme de procès du processus fautif.

Et avant d'aller faire joujou...

Le rouleau compresseur :
Bien que les exemples soient rassemblés
ailleurs, nous allons étudier le premier exemple ici, pour illustrer le déroulement du jeu :

MOV 0 1

Eh oui, ce guerrier qui ne fait qu'une ligne est pourtant capable de remplir la mémoire. Par contre, il ne tue aucun processus, dans le sens où il les convertit en rouleau compresseur mais ne les détruit pas par un DAT quelconque.

Le premier argument est en adressage relatif (aucun symbole) et pointe sur lui-même (car égal à 0). le second argument est également relatif et pointe sur la case suivante (1). MOV 0 1 va donc copier le contenu de la case courante dans la case suivante. Comme la case courante contient un MOV 0 1, la case suivante va également contenir un MOV 0 1. Quand l'instruction a été exécutée, le processus est positionné sur la case suivante. C'est-à-dire la case dans laquelle on vient de mettre un MOV 0 1. On va donc effectuer au tour suivant un nouveau MOV 0 1 et ainsi de suite.

N'oublions pas le rouleau compresseur belge : MOV #0 1... Je vous laisse deviner ce que ceci provoque :-)

Et comme je vous sens impatient (impatiente ? :-) de jouer, je vous ai mis un lien gratuit ici.

 

[NicoLaB] [CoreWar]

© 1998 - Nicolas Bruyère