Introduction

Ce didacticiel est destiné aux nouveaux utilisateurs de la Simple Virtual Machine.

Dans ce didacticiel, vous allez commencer à manipuler la mémoire de la machine virtuelle.

Le temps de lecture de ce didacticiel est estimé à 15 minutes si l'écriture d'une application simple a déjà été étudiée.

Mise en place

Pour commencer, créez le canevas de l'application dans le fichier exécutable memoire.svm en utilisant ce code :

#!/usr/bin/env svm
DESCRIPTION
Memory examples
END
LOG
DEBUG "Memory" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:memory INT*5, STR*3
		:debug BREAK
	END
END

Structure de la mémoire

Adresses mémoire constantes

Pour commencer, lancez l'application sans arguments ni options en mode débugueur, puis ouvrez la fenêtre mémoire :

Memory
Memory - K main - P application
AddressTypeValue
&0INT
&1INT
&2INT
&3INT
&4INT
&5STR
&6STR
&7STR
AliasPointer
Address:
Display
Aliases
P
Focus
Back
Clear

Le premier tableau présente la structure de la mémoire. En particulier, la première colonne contient un symbole & suivi d'un entier. Cette représentation indique que l'entier n'est pas un entier ordinaire, mais une adresse mémoire.

La mémoire utilise des adresses mémoire pour référencer les valeurs enregistrées en son sein.

Les adresses sont notées avec le symbole & suivi d'un entier positif.

Types

La seconde colonne contient pour chaque adresse un type. Ce type indique la nature de la valeur qui pourra être enregistrée à cette adresse, et va permettre d'éviter des opérations illégales sur les valeurs.

Dans l'application exemple, les adresses &0 à &4 peuvent contenir une valeur entière, et les autres une valeur textuelle.

Opérations mémoire

Ecriture en mémoire

La première opération importante sur la mémoire consiste à écrire une valeur à une certaine adresse. L'instruction -> est l'instruction d'écriture en mémoire.

Modifiez le code pour obtenir :

#!/usr/bin/env svm
DESCRIPTION
Memory examples
END
LOG
DEBUG "Memory" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:memory INT*5, STR*3
		17 -> &2
		3 -> &0
		"a" -> &6
		"z" -> &7
		:debug BREAK
	END
END

Lancez l'application en mode débugueur, puis ouvrez la fenêtre mémoire :

Memory
Memory - K main - P application
AddressTypeValue
&0INT3
&1INT
&2INT17
&3INT
&4INT
&5STR
&6STR"a"
&7STR"z"
AliasPointer
Address:
Display
Aliases
P
Focus
Back
Clear

Pour chaque instruction d'écriture en mémoire, on obtient bien la valeur indiquée à gauche du signe -> écrite à l'adresse mémoire indiquée à droite du même signe.

Pour qu'une écriture en mémoire réussisse, elle doit remplir deux conditions :

  1. l'adresse doit exister au préalable dans la mémoire (on parle d'adresse définie),
  2. le type de la valeur écrite doit correspondre au type associé à l'adresse.

Dans le cas contraire, une erreur est générée.

Une écriture en mémoire s'écrit dans le code : valeur -> adresse.

L'adresse doit être définie et la valeur doit avoir le même type que celui associé à l'adresse mémoire où elle est écrite.

Lecture mémoire

La seconde opération importante de la mémoire est la lecture d'une valeur à une adresse donnée. La lecture en mémoire n'est pas une instruction, mais l'opérateur @ (en anglais, ce symbole est souvent prononcé "at" signifiant entre autres "à cet endroit") suivi d'une adresse mémoire et peut être placé quasiment partout où une valeur est attendue.

Modifiez le code jusqu'à obtenir :

#!/usr/bin/env svm
DESCRIPTION
Memory examples
END
LOG
DEBUG "Memory" STYLE "default"
PLUGIN "svmcom.so"
PLUGIN "svmint.so"
PLUGIN "svmstr.so"
PROCESS "application"
	CODE "main" INLINE
		:memory INT*5, STR*3
		17 -> &2
		3 -> &0
		"a" -> &6
		"z" -> &7
		:int.mul @&2 @&0 -> &4
		:str.join "," { @&6 @&7 } -> &5
		:debug BREAK
	END
END

Lancez l'application dans le débugueur, et ouvrez la fenêtre mémoire :

Memory
Memory - K main - P application
AddressTypeValue
&0INT3
&1INT
&2INT17
&3INT
&4INT51
&5STR"a,z"
&6STR"a"
&7STR"z"
AliasPointer
Address:
Display
Aliases
P
Focus
Back
Clear

Dans cet exemple, l'instruction :int.mul a réalisé la multiplication des entiers situés aux adresses &0 et &2, puis a écrit le résultat à l'adresse &4. De même, l'instruction :str.join a calculé la concaténation des chaines de texte situées aux adresses &6 et &7 en ajoutant une virgule entre les deux, puis a écrit le résultat à l'adresse &5.

Cette syntaxe permet de lire plusieurs valeurs en mémoire pour les passer en paramètre à des instructions, ce qui s'avère très pratique pour de nombreux calculs.

Pour réussir, une lecture en mémoire doit remplir trois conditions :

  1. l'adresse où est lue la valeur doit être définie,
  2. le type associé à l'adresse doit être conforme au type attendu (il doit être identique au type d'une valeur qui aurait été mise directement à la place de la lecture en mémoire),
  3. l'adresse doit contenir une valeur (on parle d'adresse initialisée).

Une lecture en mémoire peut se substituer à quasiment toute valeur dans le code, et s'écrit avec le symbole @ suivi de l'adresse où la valeur doit être lue.

L'adresse où la valeur est lue doit être initialisée et le type associé à l'adresse doit être conforme à celui attendu dans le contexte de la lecture en mémoire.

Conclusion

Vous venez de voir comment manipuler la mémoire de la machine virtuelle de manière extrêmement basique.

Dans un didacticiel ultérieur, nous introduirons tout un ensemble d'outils pour calculer les adresses, ce qui permettra un accès à la mémoire bien plus avancé et bien plus puissant.