Obligement - L'Amiga au maximum

Vendredi 06 juin 2025 - 13:19  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : AMOS - La mémoire
(Article écrit par Jean Monos et extrait de off-soft.com - mars 2016)


Introduction

Voici un petit article qui traite la mémoire avec le langage de programmation AMOS. Enfin, une partie de la mémoire. AMOS est un super langage pour l'Amiga. Il permet de créer facilement des jeux ou d'autres applications, il fait très bien le café à vrai dire mais tout cela a un prix : il est gourmand en "mémoire" et nous pouvons difficilement gérer cela. J'ai dit difficilement, pas impossible !

On entend souvent dire, dans d'autres langages de programmation, que "c'est lourd, il faut déclarer les variables", alors qu'avec AMOS, pas besoin. C'est vrai, avec AMOS et les vieux BASIC en général, nous n'avons pas vraiment besoin de déclarer nos variables contrairement au langage C qui nous embête à faire cela.

Mais c'est quoi déclarer une variable ? En langage C, pour reprendre cet exemple, déclarer une variable c'est réserver de la mémoire pour mémoriser sa valeur ! Si vous avez besoin d'une variable pour entrer une valeur entre 1 et 10, vous allez juste créer une variable avec son espace minimal qui est d'un octet. Pas plus. Mais cette variable ne pourra pas dépasser "255". En fait, le maximum de bits mémorisés dans ce type de variable sera de 8 bits (11111111), si vous avez besoin d'une plus grande valeur, il faut changer son "typage" tout simplement. Cela veut dire au final que vous maîtrisez l'espace utilisé par vos variables à l'octet près (exemple : déplacer une variable type 16 bits (Int)...), et donc de la place qu'utilise votre programme.

Avec AMOS, il y a trois types de variables :
  • Les Integer (les nombres entiers : les valeurs rondes sans virgule comme 1, 12, 98...).
  • Les Real (les nombres réels : ou Float, les valeurs avec des virgules comme 10,2 ou 8,5).
  • Les String (chaîne de caractères, pas les sous-vêtements :-)).
La place que prend la variable "String" dépend de son contenu. La place que prend les deux autres types de variables numériques, que ce soit des Integer ou Real, c'est 4 octets. Si vous voulez placer seulement la valeur 2 dans une variable, c'est 4 octets quand même. Bonjour la gestion de la mémoire !

Et pour les tableaux, c'est pareil : il faut multiplier la valeur maximum des dimensions + 1 (car oui, il ne faut pas oublier la case 0) et il faut multiplier par 4 octets (les cases des tableaux de chaîne sont variables). Par exemple, un tableau Dim Tb(99,99) = 100*100*4 = 40 000 octets (40 ko).

Outch, cela commence à peser lourd. Ce n'est pas dramatique non plus, les Amiga ont quand même de la mémoire (512, 1024 ou 2048 ko suivant les versions, sans ajout de mémoire externe). Nous sommes loin des 64 ko du C64. Mais bon, gagner de la place, il le faut. En plus de cela, il faut ajouter la place mémoire des icônes, des fenêtres, des BOB.

Tenez, pour une fenêtre à afficher. Voici la formule mathématique pour savoir combien ça pompe : (Hauteur x Largeur x coefficient du plan)/8.

Le coefficient du plan est :
  • 1 pour une fenêtre de 2 couleurs.
  • 2 pour une fenêtre de 4 couleurs.
  • 3 pour une fenêtre de 8 couleurs.
  • 4 pour une fenêtre de 16 couleurs.
  • 5 pour une fenêtre de 32 couleurs.
  • 6 pour une fenêtre de 64 ou de 4096 couleurs.
Donc, pour du 320x256 en 16 couleurs, cela nous donne : (320*256*4)/8 = 40 960 octets.

Faites le calcul pour de plus grandes fenêtres...

J'écris cet article non pas pour dire "bouh, AMOS, c'est nul", mais pour montrer une autre zone de variables à travailler et qui peut être utile pour plein de choses : travailler directement dans la mémoire de votre Amiga ! Ne vous inquiétez pas, nous n'allons pas parler de langage machine à proprement parler. Juste de la mémoire.

La base

Bon, avant de partir, nous allons voir une petite base. Qu'est-ce que la mémoire d'un ordinateur (en général) ?
  • La mémoire est un endroit où nous pouvons stocker des valeurs numériques. Seulement des valeurs numériques ! Le texte est transformé en valeur numérique avant d'être stocké dans la case mémoire (en principe une case mémoire par lettre).
  • La mémoire d'un ordinateur, c'est comme un tableau, elle est découpée en case.
  • Une case permet de mémoriser une valeur entre 0 et 255.
  • Chaque case porte un numéro entre 0 à x (cases) qui représente son adresse (c'est virtuel hein, ce n'est pas gravé dessus).
En informatique, nous travaillons le plus souvent sous trois formes d'écriture pour les valeurs :
  • La base de 2. Soit c'est 0, soit c'est 1. C'est le système binaire.
  • La base de 16, notée avec nos chiffres entre 0 et 9 et complétée avec des lettres de A à F. C'est le système hexadécimal.
  • La base de 10, que nous connaissons tous. C'est notre système décimal.
Sans oublier trois autres termes techniques importants :
  • Un bit, c'est le système binaire. C'est soit 0 ou 1. Bit avec un "i".
  • Un octet, c'est la réunion de 8 bits. En système décimal, un octet est donc une valeur entre 0 et 255. Donc une case mémoire vaut 1 octet.
  • Un byte (avec un "y"). Attention à celui-là. Souvent, cela veut dire 1 octet (8 bits) dans beaucoup de systèmes informatiques. Mais ce n'est pas toujours le cas.
Voici l'introduction de l'article sur Wikipédia : le byte, anglicisme de symbole B, ou multiplet, est la plus petite unité adressable d'un ordinateur. Aujourd'hui, les bytes de 8 bits se sont généralisés en informatique, alors qu'en télécommunications, ils peuvent contenir 8 ou 9 bits. Mais jusque dans les années 1970, il existait des processeurs avec des bytes de 6, 7, 8 ou 9 bits, et il existe aujourd'hui pour la programmation des automates ou équipements industriels simples des processeurs très robustes utilisant des mémoires adressables par quantité de 4 bits voire 1 bit. En revanche, un octet, comme son nom l'indique, est un byte d'exactement 8 bits.

Peek et Poke

Les personnes qui ont travaillé sur du 8 bits connaissent ce couple ô combien important pour programmer. Le Poke (qui permet d'injecter une valeur dans la mémoire) et son copain Peek (qui fait l'inverse, il permet de lire une valeur d'une case mémoire).

Leur utilité sur les 8 bits ? Injecter du code machine directement en BASIC dans la mémoire ou le plus souvent s'adresser à la mémoire vidéo. Tricher aussi sur les jeux, non ?

Le BASIC AMOS possède aussi ces deux fonctions. Chouette, non ? Un petit test, lire la première case mémoire et voir sa valeur. Voici donc les deux fonctions de base à connaître pour lire et écrire une valeur en mémoire.

Peek(Adresse)

Exemple : Peek(12)

Poke adresse,valeur

Exemple : Poke 12,255

Attention à ne pas "poker" partout, car cela peut générer de l'instabilité. Par exemple, faites quelque chose du genre :

For X=0 to 65
Poke X,255
Next

...et vous avez des chances de faire badaboum ! L'Amiga va se bloquer, et nous devons redémarrer.

Nous allons faire plus ou moins un abus de langage et une vulgarisation technique de l'Amiga. Contrairement aux machines 8 bits, le système d'exploitation de l'Amiga, tout comme Windows, travaille dynamiquement sa mémoire. En gros, vous avez besoin de mémoriser une variable, le système dit : "attends mon coco, je te prépare une adresse où tu peux mettre ton chiffre. Voici l'adresse."

Entre-temps, un autre programme sollicite le système, il répond : "toi, tu as besoin d'un espace pour mémoriser ça, j'ai cette case mémoire pour toi qui est libre, tu la prends." Bref en gros, ce n'est pas vraiment vous qui décidez où mettre vos données. C'est le système ! C'est le véritable chef d'orchestre.

Quand vous utilisez une variable en AMOS, c'est pareil. AMOS et le système d'exploitation collaborent pour trouver des espaces libres mais ce n'est pas vous qui les choisissez. Alors, pour travailler votre mémoire manuellement comme nous voulons le faire, cela peut être compliqué car, si vous utilisez une case mémoire qui est réservée pour un autre programme, badaboum ! (il y en a qui ont essayé, mais ils ont eu des problèmes !).

Ce que nous allons faire, c'est de dire à notre super système préféré de réserver de l'espace pour nous ! Un espace bien à nous, pour que personne d'autre puisse y toucher ! Et AMOS sait le faire. Ce sont les fameuses "bank" de mémoire. Eh oui, si vous utilisez des musiques, des BOB, des sprites, les icônes, etc. Vous faites cela. Indirectement, mais c'est la même chose.

AMOS Professionnel peut réserver 65 535 banks de mémoire différentes. Attention, les quatre premières sont réservées pour des utilisations natives à AMOS.
  • La bank 1 est réservée aux sprites.
  • La bank 2 est réservée aux icônes.
  • La bank 3 est réservée aux musiques.
  • La bank 4 est réservée au système AMAL.
Il faut également savoir qu'existe deux types de banks. Les banks de type Data, qui sont des banks de mémoire qui restent en mémoire dans l'éditeur d'AMOS (comme les objets et les icônes par exemple) et les banks de type Works (travail) qui sont volatiles, les donnés sont zappées une fois le programme terminé.

Il y a aussi deux types de mémoire, la mémoire Chip et la mémoire Fast. Ici, c'est lié à la conception matérielle de l'Amiga. Souvent, la mémoire Fast provient des extensions de mémoire. "Print Fast Free" et "Print Chip Free" permettent de voir ce que vous avez (en octet).

Pour cet exemple, nous allons travailler des données pour un joueur. Sa position X, sa position Y et son nombre de PV. Ce qui nous fait donc trois variables théoriques, soit 12 octets avec le système du BASIC. En passant par les cases mémoire, cela ne fait que trois octets (si nous ne dépassons pas 255 bien sûr).

Nous allons donc réserver un espace de travail de trois octets. La formule est :

Reserve As Work numéros_de_bank, longueur
Reserve As Work 10, 3

Remplacez "Work" par "Data" si vous voulez que cela reste en mémoire, dans le code source comme les icônes, dans les objets, etc.

Voilà, le système de l'Amiga vient de nous réserver trois octets pour nous. Aucun autre programme ne devrait y toucher.

Nous allons pouvoir "poker" et "peeker" dedans. Chouette, non ? Mais avant, il faut savoir où se trouvent nos trois octets que le système nous a réservés. Nous avons une fonction pour ça en AMOS :

Start(Numeros_bank)
print Start(10)

Cela devrait nous donner l'adresse de départ des trois octets que nous avons réservés. Nous allons vérifier le contenu des trois adresses pour voir si cela contient quelque chose (note : "10" c'est notre exemple car nous avons réservé la bank 10. Si vous utilisez la bank 50, mettez 50, pas 10).

For X=0 to 2
print peek(Start(10)+X)
Next

Voilà une belle routine de lecture pour nos trois octets. Maintenant, nous pouvons la travailler avec Poke. Nous allons dire qu'il se trouve aux coordonnées 12/14 avec 99PV. Donc nous allons faire :

Rem ** Travail sur la bank **

Rem Réserver la bank 10 avec 3 octets
Reserve As Work 10,3

Rem Adresse de départ de la bank 10 pour voir un peu où c'est.
Print Start(10)

Rem Mémorisation. Le +1,+2 permet d'aller à une autre case mémoire
Poke Start(10),12
Poke Start(10)+1,14
Poke Start(10)+2,99

Rem Lecture
For X=0 to 2
print peek(Start(10)+X)
Next

A la lecture des cases mémoire, nous avons bien les valeurs enregistrées.

Nous pouvons mémoriser l'adresse de départ "Start(10)" dans une variable pour plus de commodité. Il faudra faire "Poke Variable,12 : Poke Variable+4,14...". Il y a d'autres types pour enregistrer tout cela.

Sauvegarder la bank

Il existe deux méthodes pour sauvegarder une bank. La méthode simple :

Save "Nom.abk",numeros_bank

Boum, la bank que vous voulez est sauvegardée. L'extension ".abk" indique que c'est une bank de mémoire. Dans notre exemple, je peux faire :

Save "PJ.abk",10

Et pour son chargement, je fais un simple :

load "PJ.abk" ,10

Tada ! Sauf qu'il y a un petit problème. Dans mon exemple pour trois octets, cela sauvegarde un fichier de 23 octets. Il y a un "header" (en-tête) dans le fichier avec des informations qui alourdissent un peu la note (numéro de bank, type de bank, etc.).

Nous pouvons économiser le header avec la commande Bsave (et Bload) : Bsave "Fichier.ce_que_vous_voulez", adresse_début TO Adresse de fin :

Bsave "PJ.BIN",Start(10) TO Start(10)+3

Note : pour trois octets, cette fois-ci, c'est bel et bien Adresse +3 et non +2.

Et voilà, nous avons un beau fichier de trois octets.

Au chargement, un Bload "PJ.BIN",Start(10) en ayant réservé une bank numéro 10 de trois octets, et le tour est joué !

D'autres commandes

AMOS présente d'autres commandes dans son arsenal. En voici quelques-unes :
  • Erase numeros_bank : permet d'effacer une bank en mémoire.
  • Erase All : permet d'effacer toutes les banks en mémoire.
  • Erase temp : efface les banks de type "Works".
  • List Bank : liste les banks avec le format suivant : "Numeros bank, C ou F (Chip/Fast), Type, Adresse de départ, Longueur".
  • Lenght(Numeros_Bank) : permet de connaître la longueur de la bank.
D'autres fonctions de lecture/écriture

L'Amiga n'est pas une machine 8 bits. Elle est capable de manipuler des grands nombres. Voici d'autres fonctions à connaître pour travailler la mémoire.

Il est possible de lire une valeur sur deux octets. Un petit :

print Deek(start (10))

...et cela va nous afficher dans notre exemple la valeur 3086 (et non 1214 ou 1412).

Les deux octets sont considérés comme une seule valeur de 16 bits (il n'y pas de notion de poids faible et de poids fort).

La fonction inverse pour "poker" une valeur 16 bits, c'est :

Doke,adresse,valeur

Cette fois-ci, nous ne sommes pas limités entre 0 et 255 mais entre 0 et 65 535.

Et "Leek" et "Loke" permettent, eux, de travailler sur quatre octets, comme les variables du BASIC.

Bin/hexa/décimal

Nous parlons mémoire mais si je ne parle pas de nos trois systèmes de base, cela ne va pas le faire. A un moment ou à un autre, vous allez être bloqué.

Débutons avec le système décimal. C'est celui que nous connaissons le plus, car nous l'utilisons à 99% dans la vie de tous les jours. Le système décimal contient 10 valeurs numériques : 0, 1, 2, 3, 4, 5, 6, 7, 8 et 9. Une fois à 9, pour aller plus loin, nous repassons à 0 et nous ajoutons 1 au chiffre qui se trouve à sa gauche. Donc 10, puis 11, 12, 13, 14, 15, 16, 17, 18 et 19.

Il faut faire de même avec 20, 30, 40, 50, 60, 70, 80 et 90. Et à 99, nous repassons le chiffre à 0, nous ajoutons 1 au chiffre à gauche. Comme c'est un 9, nous le repassons aussi à 0 et nous ajoutons 1 au chiffre à gauche, ce qui fait 100.

Vous devez rigoler en lisant cela. C'est tellement naturel pour nous, mais ce que je viens d'expliquer, c'est un socle commun pour toutes les bases.

Voyons le système binaire qui ne contient que deux valeurs, 0 et 1. Nous allons utiliser la même méthode que pour le système décimal. Nous ajoutons 1 à notre chiffre. Si la valeur avant l'addition est à son maximum, nous revenons à sa valeur minimum possible et nous ajoutons 1 au chiffre de sa gauche, et nous continuons.

Donc : 0 et 1. Nous sommes au maximum et si nous rajoutons 1 ? Nous repassons à 0 et nous ajoutons 1 au chiffre de gauche et comme c'est 0, ça vaut 1. Et la suite :
  • 10 et 11.
  • 100, 101, 110 et 111.
  • 1000, 1001, 1010, 1011, 1100, 1101 et 1111.
  • etc.
Et l'hexadécimal ? C'est pareil ! L'hexadécimal est une base de 16. Nous l'écrivons avec des chiffres et des lettres :
  • 0 => 0
  • 1 => 1
  • 2 => 2
  • 3 => 3
  • 4 => 4
  • 5 => 5
  • 6 => 6
  • 7 => 7
  • 8 => 8
  • 9 => 9
  • 10 => A
  • 11 => B
  • 12 => C
  • 13 => D
  • 14 => E
  • 15 => F
Ce qui donne 16 valeurs avec 0 en tant que minimum et F en tant que maximum. Comme les autres bases, une fois à F, nous ajoutons 1, nous repassons à 0 et nous ajoutons 1 au chiffre de gauche :
  • F+1 = 10.
  • FF+1 = 100.
  • EFF+1 = F00.
  • etc.
Cela fait trois bases. Donc nous savons que 1 octet = 8 bits = 255 en décimal = FF en hexadécimal.

Petit fait amusant, dans nos 8 bits, nous pouvons les découper en 2 : 4 bits et 4 bits. C'est pareil en hexadécimal, 4 bits (1111) donne 15 en décimal (16 possibilités, n'oubliez pas le 0, en hexadécimal), F c'est aussi 15 en décimal. C'est pour cela que l'hexadécimal est pratique. Nous pouvons lire facilement les quatre premiers bits et les quatre seconds bits. C'est pratique quand nous devons découper un octet.

Exemple : 11110111. Ceci est un octet qui représente une valeur de 247. En hexadécimal, cela fait F7, si je découpe en deix, F et 7, F=15 en décimal et 7 reste 7 en décimal. Regardons nos quatre premiers bits, 1111, cela fait bien 15 donc F. Et les quatre suivants, 0111, cela fait 7, donc 7 en hexadécimal et, du coup, 7 en décimal.

Conversion avec AMOS

AMOS possède des fonctions pour convertir les trois systèmes.

Quand vous écrivez quelque chose du genre :

print 10+2

...AMOS sait très bien que vous travaillez en système décimal. Idem pour les variables. Et pour utiliser peek et poke, AMOS fait les conversions tout seul.

Mais voilà, des fois, il faut travailler dans les deux autres bases et savoir convertir tout cela. Je voudrais savoir comment écrire 2 en système binaire. La fonction est "Bin$(Valeur)". Petit piège, pour faire apparaître la valeur binaire, il faut utiliser les chaînes de caractères.

B$=Bin$(2)
Print B$
=>%10

En AMOS, un "nombre binaire" est précédé par le sigle des pourcentages (%). C'est la convention en AMOS. Cette convention peut changer suivant les langages, les assembleurs, les tutoriels, etc.

Et l'inverse ? Je sais que %10 = 2 mais j'ai besoin de la placer dans une variable. Regardez cet exemple :

B$ = "%10" : Rem Nous mémorisons %10 en tant que chaîne dans la variable B$
Print B$ : Rem Nous vérifions que cela annonce bien %10 ;
Print Val(B$) : Rem Oh magie, cela affiche 2

Donc un D=Val(B$) ou D=Val("%10") va bien convertir la chaîne %10 en valeur numérique. Ceci dit, faire tout cela directement fonctionne. B=%10 donne bien 2 à B. Notons que dans Peek et Poke, nous pouvons utiliser directement l'écriture %10 sans utiliser Val (toutes les fonctions d'ailleurs, c'est juste pour lire directement une valeur binaire qu'il faut passer par les strings).

Pour l'hexadécimal, c'est pareil. Au lieu d'être Bin$, c'est Hex$. Le sigle avec AMOS pour l'écriture hexadécimal, c'est le dollar ($) comme les strings. $FF pour 255. Les règles sont les mêmes pour le système binaire.

Petite note pour Bin$(Valeur,X) : "X" permet de sortir les "X" bits à partir de la droite. Cela marche de façon identique avec Hex$. Par exemple :

B=%1000
Print Bin$(B,2)
=>%00

...car les deux bits de droite, c'est 0.

Allons plus loin

Bon, c'est bien beau, j'ai parlé de bank mémoire, sa petite manipulation, les trois bases qui sont utilisées majoritairement en informatique, mais pour quoi faire concrètement ? Voici quelques exemples.

Son système de sauvegarde, simple et rapide

L'idée est toute simple. Les données à mémoriser ne sont pas dans les variables du BASIC mais directement dans une banque de données. Comme ça, au moment de la sauvegarde et du chargement, tout est prêt. Cela évite des boucles pour placer/déplacer les valeurs dans Variables<=>Adresse, ou Variables<=>Fichier. Il y a un gain de temps, de programmation, mais il faut une bonne dose d'organisation !

Gagner de la place mémoire en général

Voici l'exemple du tableau : je veux faire une carte ("map" en anglais) de 100 cases sur 100 cases. Pour mémoriser cette carte, je place l'id des tuiles ("tiles" en anglais) dans un tableau. Comme ça, je sais qu'en 0-0, ça me donne la tuile 6 et j'affiche en 0-0 la tuile 6. C'est pratique mais c'est gourmand en place mémoire : 100*100*4 en octet, ce qui fait environ 40 ko de mémoire.

Imaginez tout ça en banque de mémoire ? Le même rapport 100 cases sur 100 cases, nous ne le multiplions pas par 4 mais nous gardons seulement la case d'octet. Cela fait 10 ko de mémoire pour la carte ! (un vrai gain, non ?).

En plus, nous pouvons facilement décharger/charger des cartes en mémoire avec le même système que les sauvegardes ! Bien sûr, il faut faire une routine pour savoir reposer les tuiles/se positionner au bon endroit du tableau, bref il y a quand même un peu de boulot.

Décomposer un octet

Nous n'avons que 16 tuiles dans notre jeu. Cela serait bête d'utiliser 1 octet complet pour mémoriser seulement une case mémoire. Nous pouvons bien sûr utiliser les quatre premiers bits pour la première tuile et les quatre suivants pour la seconde tuile.

Il y a plusieurs méthodes. Vous vous souvenez l'histoire des hexadécimaux avec le binaire ? Un octet, c'est deux chiffres hexadécimaux. En les décomposant, nous pouvons avoir la première partie d'une tuile puis l'autre. C'est pratique.

Nous pouvons créer aussi des routines où les cartes sont codées sur 7 bits et la 8e donne l'information si nous pouvons, ou pas, marcher sur ces tuiles. La fonction "BTST(Valeur, Numéro_Bit)" permet simplement de tester si un bit vaut 0 ou -1 (ce qui veut dire 1). Le numéro des bits vont de 0 à 7 en partant de droite.

C'est la fin

Voilà, vous avez toutes les cartes en main pour exploiter directement la mémoire de votre Amiga en AMOS et économiser un peu de place.

Vous pouvez retrouver d'autres informations aux pages 05,09,01 (Memory Bank) et 14,A,01 (Code Machine) du manuel d'AMOS professionnel.


[Retour en haut] / [Retour aux articles]


Soutenez le travail de l'auteur