CODING ★ LES NOTIONS EN MÉMOIRE ★

Les Notions en MémoiresMenu - Soft - Basic
Les nouveaux venus à la micro-informatique se sentent un peu "perdus" dès qu'on parle de la mémoire d'un micro. Et comme c'est un sujet incontournable, on est bien obligé de se "faire une petite idée sur la question"... juste le stricte nécessaire... et c'est là que l'on part avec des idées fausses. Lesquelles vous conduiront forcément un jour à un échec cuisant et... mémorable. Que diriez-vous si nous partions sur des bases saines ?

Dans chacun de nos paragraphes, on démarrera au "niveau zéro", puis on prendra un peu d'altitude. Donc, si vous êtes déjà "pas mal informé", survolez vite les débuts ; si vous êtes tout à fait débutant, n'hésitez pas à "décrocher" et passez au paragraphe suivant, dès qu'une douleur se précise sous le cuir chevelu (ou chauve, au choix...).

LA NOTION D'OCTET

L'octet est l'unité de base de l'informatique. Une lettre, un chiffre, un signe de ponctuation, même un espace (ou blanc) occupent UN octet ; le mot AMSTRAD représente donc sept octets, déjà... On a donc intérêt à en avoir le plus possible de disponibles dans notre machine. L'origine de ce mot vient qu'il représente huit BITS : le bit est un potentiel électrique valant 1 ou 0 (physiquement 5 ou zéro volt). Ces huit bits ne peuvent représenter que 256 combinaisons possibles, de 0 à 255.

Un octet est avant tout une valeur numérique. Ainsi, pour le mot AMSTRAD, c'est en fait la suite des "codes ASCII" des lettres qui composent ce mot : 65, 77, 83, 84, 82, 65 et 68. Quand vous tapez A$ = "AMSTRAD" ces sept octets vont être logés quelque part dans la mémoire du micro. En revanche, si vous sauvegardez A$ sur disquette ou sur cassette, ces petits octets seront reproduits sur support magnétique. La mémoire du micro est "volatile" (si on éteint), on l'appelle aussi "mémoire vive" ou "RAM". Elle est limitée sur CPC à 65.535 octets. Sur une disquette, on peut stocker jusqu'à 182.272 octets par face ; elle est plus stable, on l'appelle communément la "mémoire de masse".
Et le kilo-cctet ? La farce est qu'il vaut 1024 octets. Ne croyez pas que les Anglais soient à l'origine de cette unité ! On a choisi 1024 parce que c'est le multiple de 256 qui est le plus proche de 1000 et, de ce fait, 1000 ferait figure de multiple bâtard et d'emploi scabreux.

LA NOTION D'ADRESSE

Si on fait B$ = "SORACOM", ces sept octets sont logés à une certaine "adresse mémoire", que nous ignorons. Faisons ensuite PRINT B$. Le micro consulte son "Registre des variables". Il y trouve B$ = variable de type chaîne, de longueur sept, logée à partir de l'adresse 36721. Puis il en fait une copie à l'écran, sous forme de caractères puisqu'il s'agit de représenter une chaîne. Or, ces fameuses adresses ne peuvent être comprises qu'entre zéro et 65535 (= 64 kilo octets) et ce, que vous ayez un CPC 464, 664, 6128 ou un PCW 8512. Pourquoi ? Parce que ces appareils sont équipés d'un micro-processeur Z80 qui, lui, ne peut adresser que sur deux octets, soit 64 Ko. En voici la raison.

Représentons la mémoire adressable comme une grille (genre grille de bataille navale) de 256 sur 256. Donc, on désigne l'adresse d'un octet par ses positions "horizontale" (un octet) et "verticale" (un second octet). Or, notre Z80 (une "puce" silicium à 50 francs TTC) ne sait travailler que sur 8 bits (= 10 octets). Il ne peut donc adresser que sur 256x256 (= 65536 cases mémoires). Certains vont s'écrier "et mes 128 Ko de mon 6128 ? Et mes 512 Ko de mon PCW 8512 ?". Du vent ! Tout ce qui est supérieur à 64 Ko, c'est du "disque virtuel", c'est-à-dire de la mémoire de masse mais d'accès ultra rapide. Nuance... De nos jours, le kilo-octet est devenu très bon marché (je parle de ses composants électroniques), tandis qu'un microprocesseur travaillant sur 16 bits coûte environ 150 francs de plus qu'un Z80. D'où votre indignation ! "Pourauoi cette mesquinerie de 150 francs qui limite ma mémoire disponible avec cette trottinette de Z80 ?" Parce que l'exploitation d'un micro-processeur 16 bits coûte beaucoup plus cher. Pour vous en convaincre, comparez l'intérieur d'un CPC et celui d'un compatible IBM-PC.

Pourquoi ces adresses en hexadecimal ??

&BB06, &A000 est un type d'écriture de nombres qui déplaît aux débutants. Ça fait un peu code secret, voire un peu snobinard du genre "Do you speak Hexa ?". Vous préféreriez l'écriture normale (dite en décimal), alors sachez que si tel programmeur utilise des adresses en hexa, c'est pour simplifier son travail. Tout particulièrement parce qu'elles sont plus faciles à retenir. Exemple de quelques adresses importantes : &A000, &BB06, &BB4E, &C000. Elles donnent en décimal 40960, 47878, 47950, 49152 : aussi difficile à retenir que des numéros de téléphone ! Le préfixe HEXADECI signifie SEIZE., parce que l'on dispose de 16 symboles : les chiffres 0 à 9 et les lettres A à F (elles prennent la suite des chiffres : A = 10 ; F = 15). Pour écrire un nombre corresv pondant à 1 octet, on utilise 2 symboles : &0A = 10 ; &FF = 255. Comme pour une adresse mémoire, il nous faut deux octets ("horizontal" et "vertical"), on les juxtapose ; exemple &0AFF (qui vaut &0A multiplié par 256 plus &FF, soit 2560 + 255 = 2815). Et voici la preuve que c'est logique : souvenez-vous de vos parties de 'bataille navale" : pour désigner une case, on dit "Tir en D5" ; préféreriez -vous "case numéro 35" ? Le but de ce paragraphe n'était pas de vous convertir à un usage définitif de la notation en hexadécimal, mais de la rendre moins antipathique à certains d'entre vous.

Les concepteurs d'un micro-ordinateur sont les seuls à décider comment ces 64 Ko vont être organisés, répartis. Ainsi, le plan de la mémoire d'un CPC ne ressemble en aucune manière à ceux des Oric Atmos, MSX, Spectrum, Commodore 64, Apple Ile, etc. Je dirais même que ce plan est très astucieux, d'où des performances qui ont contribué à l'anéantissement commercial de ses concurrents à l'époque de son lancement (janvier 1985).
Voici le plan très schématique de l'adresse : 49152(&C000) à 65535 (&FFFF), le "sommet", c'est la zone réservée à l'écran. Nous y reviendrons. La zone située juste au-dessous est réservée au fonctionnement du CPC ; elle est protégée, on ne doit pas y "écrire". Tout "en bas" de la mémoire se trouve une autre zone protégée, très petite, de 0 à 367.

Pour programmer, il nous reste donc une zone oui va de 368 (&0170) jusqu'au "plancner" de la grande zone réservée, lequel se trouve "aux alentours" de 43000. Pourquoi cette imprécision ? Parce que cela varie avec le modèle de CPC. Pour connaître cette adresse exacte, tapez :

PRINT HIMEM

HIMEM vient de HIGH MEMORY, le haut de la mémoire disponible. Exemple, sur un CPC 464, le HIMEM est de 43903, mais si on l'équipe du lecteur de disquettes DD1, le HIMEM tombe à 42619. Attendez-vous à des valeurs inférieures avec les CPC 664 et 6128. La quantité d'octets disponibles est donc de HIMEM-368. Mais il y a un moyen plus simple de le savoir. Tapez :
print fre(0)

Le cas du basic mbm

Dans les CPC, le BASIC est "résident", c'est-à-dire qu'il est dans un circuit électronique de type "EPROM" : c'est une mémoire de 32 Ko indélébile, que l'on peut seulement lire, d'où son autre nom de "ROM" (= Read Only Memory). En somme, c'est un assemblage de miniprogrammes permanents, totalisant 32 Ko qui s'ajoutent aux 64 Ko de "mémoire vive" (ou RAM). Mais comment est-ce possible ? Considérez cette EPROM comme étant une "disquette en silicium" : lorsque vous faites appel à une fonction BASIC, le système va la chercher dans l'EPROM et exécute ce mini-programme en assembleur. NOTA : cette technique fut considérée à l'époque comme révolutionnaire, car avant le CPC, les micros chargeaient en RAM la totalité du BASIC de l'EPROM (à la mise sous tension). De ce fait, il restait peu de Ko disponibles pour programmer (25 à 32 Ko). Revenons à notre plan de la mémoire : chargeons un programme BASIC par LOAD. Il va se loger dans le bas de la mémoire à partir de l'adresse 368. Si nous faisons un PRINT FRE(O), nous lisons une valeur plus faible. Normal, c'est ce qu'il reste entre le bout du programme et le HIMEM. OK ? Faisons RUN.

Notre programme va forcément créer des variables dont les valeurs vont être stockées en RAM. Où ça ? Sous le HIMEM. Elles s'empilent par le haut. Le FRE(O) diminue donc, car la zone des octets disponibles a un plancher fixe (la fin du programme chargé) et un plafond qui ne cesse de descendre à mesure que e nouvelles variables sont mémorisées.

NOTA : ce logement des variables au plafond fut lui aussi révolutionnaire, car les BASIC plus anciens (y compris le GWBASIC des compatibles PC) entassent leurs variables au-dessus du programme (plafond fixe, plancher montant). Défaut, si à la suite d'un BREAK, on modifie une ligne du programme toutes les variables sont perdues. Ce qui n'est pas le cas des CPC.

Peek et poke

PEEK permet de lire la valeur de l'octet situé à l'adresse indiquée. POKE fixe la valeur de l'octet à l'adresse indiquée. Faites un RESET de votre micro et tapez PRINT PEEK (12000). Réponse zéro. Normal, la mémoire disponible est encore vide. Puis entrez :

POKE 12000,145
PRINT PEEK (12000)

Réponse 145

Remarquez que l'adresse est mise entre parenthèses dans PEEK et pas dans POKE. Pourquoi ? Parce que PEEK est "fonction" BASIC (qui renseigne sans rien changer), tout comme PRINT LEFT$ (A$,2) qui ne change pas la valeur de A$. En revanche, POKE est une "instruction" BASIC (= commande) qui modifie quelque chose, tout comme RENUM 1000,423. Or, vous remarquerez que les paramètres des "fonctions" se mettent entre parenthèses, ce qui n'est pas le cas des "instructions". (Une exception, MID$ qui est utilisé à la fois comme fonction et instruction). Vous pouvez demander des PRINT PEEK dans n'importe quelle zone, même dans les protégées, ce n'est pas défendu et c'est sans risque. En revanche, un POKE d'une valeur quelconque "là où il ne faut pas" peut avoir des conséquences inattendues. Mais sans dommages pour le micro ; un RESET remettra tout en ordre.
Il est possible (= accepté) de faire des POKE dans les zones dites protégées, mais à vos risques et périls. Exemple POKE 47956,1 et plus rien ne s'affiche à l'écran, même pas le curseur. Les paramètres de PEEK ou POKE peuvent indifféremment être en décimal ou hexadécimal.

LA MÉMOIRE D'ECRAN

Faites CLS puis POKE 59000,255. Un petit trait rouge apparaît en bas à droite de l'écran. Faites ensuite PRINT PEEK (&C000), réponse 240. C'est le début de l'écran, l'angle supérieur gauche. Or, suite à votre CLS, il s'y trouve le "R" de "Ready", plus exactement le haut de cette lettre. Alors, faisons POKE 59000,240 et notre tiret rouge est en effet remplacé par un tiret jaune. Un circuit électronique spécial a pour rôle d'explorer (lire) la zone mémoire allouée à l'écran (=16 Ko) et de l'illustrer sur le moniteur. L'illustrer comment ? Le "plan mémoire de l'écran" est assez complexe. L'auteur a décrit cela dans CPC n° 1 page 28 et dans l'ouvrage "Mieux programmer sur Amstrad", chapitre XV (SORACOM). Il est facile de sauvegarder sur disquette ou sur cassette votre écran actuel.

SAVE "ECRAN",B,&C000,&4000

Le B signifie que l'on sauvegarde une zone de la mémoire (du Binaire), depuis &C000 et sur une longueur de &4000 (= 16384 octets).
En faisant CAT, vous lisez ECRAN.BIN 17 Ko. Puis faites CLS:LOAD"ECRAN' ' et vous retrouvez votre image sauvegardée. Elle apparaît en "store vénitien" (25 bandes s'élargissant), car le plan mémoire de l'écran est discontinu.

HlMEM ET MEMORY

La valeur que prend HIMEM lors de la mise sous tension est vraiment l'adresse utilisable la plus haute. En revanche, on peut l'abaisser sans problème et ce, par la commande MEMORY. Essayez : MEMORY 35000 puis PRINT HIMEM Réponse 35000. Autre petite démonstration "parlante". Faites un RESET (CTRL-SHIFT-ESC) puis : H = HIMEM

MEMORY H - 8000
MEMORY HIMEM + 8000

On a pu ramener le HIMEM à sa valeur initiale, mais si à présent on demande MEMORY HIMEM + 1 alors là refus net avec message "memory full" ( = mémoire pleine).
Autre cas : faisons MEMORY 35000. Au delà de cette valeur, nous venons de créer une zone qui sera à l'abri des LOAD, des RUN, NEW et CLEAR. Chargeons un programme TRUC1 .BAS qui va placer par des POKE des résultats précieux à partir de l'adresse 35001. Ensuite, lançons un second programme par RUN "TRUC2" qui aura besoin des résultats précédents. Il les récupérera par des PEEK.

Exemple :
FOR N = 1 TO 2000:R(N) = PEEK (35000 + N):NEXT

C'est beaucoup plus rapide que si l'on avait stocké ces résultats intermédiaires en enregistrant un fichier séquentiel ! (Temps d'écriture par TRUC1 + temps
de lecture par TRUC2). Seul un RESET pourrait effacer ces valeurs "polcées". Dans TRUC1, on aurait pu aussi stocker des chaînes, exemple simple :

FOR N = 1 TO 20 : '(LEN(A$) = 20)
POKE 35000 + N, ASC (MID$(A$,N,1))
NEXT

Que TRUC2 récupérera par

A$ = "":FOR N = 1 TO 20
A$ = A$ + CHR$(PEEK(35000+N))
NEXT

Garbage et valeurs mortes

Si on déclare V$ = "BORDEAUX" puis V$ = "PAU" puis V$ = "LYON", les anciennes valeurs Bordeaux et Pau sont oubliées par le BASIC, mais pas par la mémoire ! Ces cadavres de variables mortes occupent toujours les mêmes "cases-octets" dans la RAM ; mais leurs adresses ont été oubliées, "écrasées" par les adresses successives de V$. Conséquence le FRE(O) diminue et, si l'on n'y prend pas garde, c'est le blocage du système, car la pile des variables (le "plafond") est venu toucher le "plancher" (le programme BASIC). Rien n'est perdu I Le BASIC déclenche de lui-même un "GARBAGE", c'est-à-dire qu'il va éliminer les variables mortes en "remontant" ainsi les variables en cours. On obtiendrait la même chose par PRINT FRE ("")

Un seul défaut, mais détaille, cette opération peut demander 15 à 30 minutes... pendant lesquelles le clavier semble inerte. Ce grand ménage terminé, le programme reprend son-cours automatiquement là où il l'avait laissé. Rien de tel qu'un petit programme démo (listing n° 1 "CIMETIERE") pour vous sensibiliser à ce phénomène : la chaîne A$ de largeur 120 caractères (= 3 lignes en MODE!) prend 224 valeurs différentes. Cette plaisanterie a consommé 26906 octets I Un autre mange-mémoire est la formation d'une chaîne par concaténation. Remplacez la ligne 40 par : 40 A$ = A$ + CHR$(C) Cette chaîne A$ de largeur 224 nous a coûté à elle seule 25450 octets !

10 ' CIMETIERE
20 M0=FRE(0):PRINT M0
30 FOR C=32 TO 255
40 A*=STRING$(120,C)
50 NEXT
60 M1=FRE(0) :PRINT M1
70 PRINT"Perte =" ;M0-M1;"octets"

42083
15177

Perte = 26906 octets

La farce de L'openout

Lorsqu'on programme OPENOUT ou OPENIN pour écrire ou charger un fichier, il se produit à notre insu un curieux phénomène farceur et dont le manuel ne parle pas. Le système se réserve 4 Ko pour ce genre de transfert RAM/mémoire de masse, une zone qu'il veut SOUS la grande zone protégée. Alors, il abaisse le HIMEM de 4 Ko, en repoussant vers le bas toutes les variables stockées. Après le CLOSEOUT ou CLOSEIN, c'est le mouvement inverse ! S'il y a peu de variables, c'est quasi instantané, s'il yen a beaucoup, ce "mouvement d'accordéon" peut demander plusieurs minutes ! Pire encore, il y a risque de perte du nom du fichier à l'écriture, qui peut ainsi être remplacé par un morceau d'une des chaînes sauvegardées ! Très drôle...

C'est pour se mettre à l'abri de cette farce qu'il faut que tout programme utilisant OPENIN ou OPENOUT commence par cette ligne :

30 OPENOUT"BIDON":MEMORY HIMEM-1:CLOSEOUT

Explications : on provoque cette sauvegarde bidon pour que le système abaisse son HIMEM de 4 Ko. Là on le FIXE par MEMORY HIMEM-1. Comme il n'y a pas encore de variables stockées, c'est instantané.

Dès lors, nos variables iront se stocker sous ce HIMEM surbaissé et les OPENOUT et OPENIN réels pourront se créer leur tampon de 4 Ko sans avoir à repousser et remonter nos variables. Donc plus d'attente et plus de risques de perte du nom du fichier. Vous pensez que cette manœuvre nous coûte 4 Ko de mémoire disponible en moins. C'est vrai, mais comme de toute façon le système nous en priverait lors de chaque OPENOUT ou OPENIN, autant s'en priver tout de suite. Ce qui évite le risque d'un garbade en pleine sauvegarde... (ce qu'il m'était arrivé lors de mes débuts sur CPC 464). NOTA : si vous déclarez un SYMBOL AFTER, il faut le faire AVANT l'OPENOUT "BIDON", c'est je pense la seule exception à cette règle.

Chargement de programmes en binaire

Lorsque vous programmez un LOAD d'un .BIN, celui-ci va se loger à partir de son adresse départ. Imaginons TRUC.BIN de longueur 300 octets qui débute à l'adresse 39000 : il est prudent de faire un MEMORY 38999 afin que les variables BASIC aillent en dessous. Sans cette précaution, elles iront sous le HIMEM vers 42000, et lorsque l'on arrivera à 39300, il y aura plantage avec message "memory full"... Variables BASIC et programmes en langage machine n'aiment pas cohabiter ; il faut éviter leur contact par un HIMEM situé sous l'adresse départ la plus basse. On lance une routine .BIN par CALL adresse départ, exactement comme pour un GOSUB. La fin d'un programme en binaire est un code spécial qui agit comme un RETURN. Donc après un CALL, il y a retour automatique à la suite du programme BASIC. Certaines routines de l'EPROM BASIC sont chargées dans la zone réervée ; ce sont les adresses qui commencent par &BB et &BD. Certaines ne demandent aucun paramètre et n'ont pas d'équivalent en BASIC, d'où un usage courant en BASIC.

Citons :

CALL &BB06 bloque le programme en attendant une touche (idem CALL &BB18)
CALL &BB4E efface les caractères définis par SYMBOL
CALL &BB03 vide le buffer clavier CALL &BD19 rend l'animation moins saccadée
CALL 0 = reset

Incompatibilités de logiciels

AMSTRAD avait pourtant prévenu les éditeurs de logiciels de ne pas utiliser certaines zones de la RAM, notamment les quelques kilo-octets situés sous le HIMEM du 464. Ces recommandations n'ont pas toujours été respectées. Conséquences : les premiers jeux sur cassettes qui ne peuvent tourner sur un CPC équipé d'un lecteur de disquettes. Tous ces logiciels sur disquettes qui tournaient sur 464, mais pas sur 664 ou 6128 et encore moins sur le 6128 AZERTY. Certains concepteurs de logiciels ont bien tort de se croire astucieux...

Conclusion

Toutes ces notions nous éviterons quelques avatars. Elles sont souvent superficielles mais suffisantes pour comprendre le pourquoi de telle recommandation ou de tel ennui. Si vous débutez en BASIC, donc avec des programmes très courts, il n'est pas indispensable de connaître le plan et les caprices de la mémoire. Mais vous ne serez pas toujours débutant, vous vous lancerez dans des programmes atteignant les 10 Ko, alors là, il est indispensable de bien posséder ces notions, sinon gare aux surprises...

CPC n°34 , MAI 1988

★ ANNÉE: 1988
★ AUTEUR: Michel ARCHAMBAULT

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding » A bug in the CPC464 (Computing with the Amstrad)
» Coding » Basic - Table de References Croisees des Variables Basic (CPC Revue)
» Coding » Basic - Mallard Basic To CPC Basic (The Amstrad User)
» Coding » Improper Argument Kaput !
» Coding » Basic Memorisez l'Ecran du CPC
» Coding » Bug , petit bug (CPC 464) (Microstrad)
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 310 millisecondes et consultée 2225 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.