<=<=<=<=

6

La problématique mémoire Considerations about memory
Un des problèmes que l'on rencontre sur les ordinateurs 8 bits (en général) est qu'il n'y a aucune gestion de la mémoire.

La gestion mémoire est normalement dévolue au système d'exploitation qui se trouve en ROM, et qui permet de faire des programmes pouvant être installé et exécutés n'importe où en mémoire, gérant les demandes de mémoire et l'accès au périphériques.

En simplifiant, on peut dire que sans gestion de la mémoire les programmes se retrouvent compilés pour fonctionner à une adresse spécifique et lisent et écrivent en mémoire à des emplacements précis choisis par le programmeur. Le résultat est qu'il est quasiment impossible d'utiliser simultanément plusieur programmes car on ne peut pas éviter les conflits (souvenez vous de tous ces petits programmes utilitaires permettant de renuméroter les programmes basic, d'avoir des labels, etc... qui étaient tous prévus pour être installés en $400 ou en $9800, s'écrasant ainsi les un les autres ou empechant d'utiliser le lecteur de disquette) .

Donc comment peut on faire des programmes sympa sans gestion mémoire ?

Pour le moment, nous mettrons de coté le fait d'avoir plusieurs programmes en mémoire en même temps. L'objectif est d'avoir nos propres programmes fonctionnant correctement dans toutes les situations.
One of the main trouble on the 8 bits computers is (in general) the lack of memory management.

The memory management consist in various functions of the OS (Operating System, often in ROM, sometimes called BIOS (Basic Input Output System)), that allows program to run from any place in memory, requesting for memory allocation, and stuff like that.

Without memory management, each program is compiled at a fixed adress (I'm simplyfing), and read/write datas at locations that the programer decides. The result is it's often impossible to have many different programs in memory without conflicts. (Just have to remember all your littles tools for improving BASIC programming: RENUMEROTATION, LABELS, and other cool routines, that ALL must be placed in $400 in memory... Grrrr... And, as the Disk OS uses the $400 adress too...).

So, how to create a cool program without that ?

For the moment, we will forget the idea of many different programs in memory at the same time. Our objective is just to have our own program working properly in any cases.
Cartographie mémorielle The memory map
Avant que je ne commence à expliquer les subtilitées de la gestion mémoire sur l'oric, veuillez consulter le tableau suivant qui présente l'organisation de la mémoire sur un Oric 48k en mode TEXT. (Le mode HIRES présente quelques différences, mais non significative pour la compréhension).
Toutes les adresses indiquées sont en héxadécimal, quand aux tailles elles sont en octets.
Before I start explaining the subtelties of memory management, please read the table below that describes the memory organization in a standard 48kb Oric in TEXT mode. (It's a little bit different in HIRES, but not so much)
Adresses are in hexadecimal, and sizes are indicated in bytes.
START NAME END SIZE
C000 Read Only Memory (ROM)
Contains the BASIC interpreter and all graphics/sound/math code

Mémoire morte (MEM)
Contient l'intérpréteur BASIC ainsi ques toutes les routines graphiques, sonores et mathématiques
FFFF 16384
BFE0 FREE MEMORY
This area is free.

MEMOIRE LIBRE
Ces quelques octets ne sont pas utilisés
BFFF 32
BB80 SCREEN
40*28 character mode
Line 0 is the status line

ECRAN
Composé de 40 lignes de 28 caractères.
La ligne 0 est appelée "ligne d'état".
BFDF 1120
B800 ALTERNATE CHAR SET
Mozaic char set in a 2x3 matrix for semi-graphics drawing. Can be redefined

CARACTERES SEMIGRAPHIQUES
Ce jeu est composé de 64 caractères formés d'une matrice de 2x3 pixels permetant de faire des graphisme en "moyenne résolution".
Ces caractères peuvent être redéfinis par l'utilisateur.
BB7F 896
B400 STANDARD CHAR SET
Contains the font displayed on screen. Can be redefined. Characters of ASCII code less than 32 can only be displayed in HIRES mode using the CHAR commande since those values are display attributes in TEXT mode !

JEU DE CARACTERES STANDARD
Contient la définition graphique des 128 caractères normalement affichables en mode TEXT. A noter que les caractères dont le code est inférieur à 32 ne peuvent être visualisés qu'en mode HIRES avec la commande CHAR, car en mode TEXT ils correspondent à des codes de controle vidéo !
Ces caractères peuvent être redéfinis par l'utilisateur.
B7FF 1024
9800 GRABABLE MEMORY
This area is unused in TEXT mode, but by default is reserved by the BASIC in order to allow the use of HIRES mode. To use it from BASIC, you need to use the GRAB command.

MEMOIRE RECUPERABLE
Cette zone est inutilisée en mode TEXT, mais le BASIC la protège afin de permettre l'utilisation du mode HIRES. Pour l'utiliser en BASIC, il faut utiliser la commande GRAB.
B3FF 7168
500 FREE MEMORY
This zone is entirelly available to your programs.

MEMOIRE LIBRE
Toute cette zone est entièrement disponible pour vos programmes.
97FF 37632
400 Page 4
Is officially used only by the DOS. In reality most little utility programs are conceived to be used in page 4. DOS uses this location to put a piece of code that redirect BASIC commands to the BASIC ROM or to the overlay memory.

N'est utilisé officiellement que par le DOS. En pratique la majorité des petits programmes utilitaires sont conçus pour s'exécuter en page 4. La place y est très chere, et les conflits fréquents. Le DOS y place un code permettant de filtrer les instructions BASIC à appeller en ROM et celles à exécuter en mémoire OVERLAY.
4FF 256
300 Page 3
This is the input-output area. Those 256 bytes are linked to the expansion bus of the oric and are used to communicate with the external peripherals. This is no real memory.

C'est la zone des entrées-sorties. Ces 256 octets sont cablés sur le bus de l'Oric et permettent d'accéder aux divers périphériques. Ce n'est pas de la mémoire directement accessible.
3FF 256
200 Page 2
Contains run time variables used by the BASIC interpreter as well as interupt handlers.

Contient les variables utilisées par l'interpréteur basic, ainsi que les pointeurs sur les routines d'interruption.
2FF 256
100 Page 1
This area is used by the 6502 as the stack. It's non movable.

C'est la zone que le 6502 utilise comme pile. Elle ne peut être déplacée.
1FF 256
0 Page 0
This 256 bytes area can be optimaly used by the 6502 processor contrary to the other part of the memory. It also allow the use of specific adressing modes. The C Library and the system use a part of this area.

Cette zone de 256 octets peut être accédée par le 6502 plus rapidement que le reste de la mémoire. Elle permet aussi d'utiliser des modes d'adressages spécifiques. Pour cette raison le système et la librairie C s'en servent pour effectuer une partie de leurs opérations.
FF 256
Oric 48k - TEXT
Gestion de la mémoire en BASIC Memory management in BASIC
Si vous programmez en BASIC, la gestion mémoire est simple. Quand vous utilisez une variable, un tableau ou une chaine de caractère, l'intérpréteur du BASIC situé en ROM trouve une place en mémoire pour vous, et voila.

Si vous n'avez pas besoin du mode haute résolution, l'utilisation de la commande GRAB vous libérera 7168 octets de plus. Si vous avez besoin d'installer des routines en assembleur (généralement stockées en DATA) et si vous êtes sur cassette, vous pouvez allors utiliser la mémoire située en $400 vu que le DOS n'est pas présent.

Si ca ne suffit pas, il vous reste la possibilité d'écraser la zone mémoire située de $B800 à $BB7F qui normalement contient les caractères alternés.
If you're programming in BASIC, the memory management is evident. When you use a variable, array, or string the BASIC interpreter located in ROM finds a room in memory, and that's all.

If you don't need to use the HIRES mode, you can use the GRAB instruction that will gives you the 7168 bytes of memory that are normaly reserved for storing the extra amount of memory required by HIRES graphics. If you need to use some assembly routs (usally loaded in DATAs), and your program is on TAPE, you can scratch memory in $400 since the DOS is not present.

If it's not enough, and if you don't need the alternate char-set, you can scratch memory located from $B800 to $BB7F.
Gestion de la mémoire en C Memory management in C
Si vous programmez en C, vous pourrez utiliser malloc et free. Ces fonctions existent, mais en général ce n'est pas une très bonne idée de les utiliser sur un ordinateur 8 bit. Il vaut mieux évaluer correctement la taille des données, et les allouer statiquement dans le programme.

Vous pouvez éventuellement allouer un gros bloc de mémoire, et positionner des pointeurs dans cette zone. La raison est que le code C compilé prend beaucoup de place, et que l'on a peu de mémoire à perdre. Chaque appel a malloc et free prend énormément de mémoire car il faut passer les paramètres à la fonction et stocker le pointeur obtenu. Si l'on ne fait qu'une seule alloc ce n'est plus que de la manipulation de pointeur.

Soyez prudent avec les données statiques ! Chaque fois que vous faites quelque chose comme printf("hello world");, vous rajoutez une chaine de caractère en mémoire, ce qui au final peut prendre beaucoup de place.
If you're programming in C, you can use mallocs/free. These functions are implemented, but in general it's not really good to use on an 8 bit computer. It's a better idea to know the size of your datas, and to allocate them in static in the program.

You can eventually do a BIG MALLOC, and have pointers at different positions in that buffer. The reason ? The compiled C is hungry in memory, and memory cannot be waste. Each time you call the malloc/free functions, it takes plenty of 6502 instructions, for pushing values, calling the function, and storing the returning value. If you do only a single malloc, it's only a question of adding values from pointer to pointer.

Be carefull with static informations ! Each time you use stuff like printf("hello world");, you're storing a new character string in memory, and this can take a lot of room.
Gestion de la mémoire en assembleur Memory management in machine code
Si vous codez en 6502, il serait bon que vous pensiez sérieusement à l'allocation des choses en mémoire car cela à de sérieuses conséquences en terme d'optimisation !

Entre autre, cela permet ceci:
  • Ne pas avoir de pénalités lors de l'utilisation de l'adressage indexé
  • Ne pas avoir de pénalités lors des sauts conditionels
  • Pouvoir utiliser de l'arithmétique sur 8 bits au lieu de 16
  • Pouvoir faire du code automodifié plus performant
Par exemple, si vous utilisez le mode d'adressage indexé, vous devez savoir que si la valeur de l'index vous fais changer de page vous serez alors pénalisé d'un cycle d'horloge. Si vous choisissez une adresse de base qui est allignée sur un multiple de 256 octets vous serez sur de ne jamais avoir ce probleme. Alors dès que possible essayez de faire en sorte d'utiliser des adresses qui finissent par $00...

Toujours pas persuadé ? Bon, en général le mode d'adressage le plus utilisé (après le mode immédiat et le mode absolu) est l'adressage indexé (LDA $adress,x ou bien encore STA $adress,y). Si vous la valeur de l'index vous fait sauter de page, ces instructions prendront 5 cycles pour s'exécuter au lieu de 4. Statistiquement si vous ne faites pas attention, 50% des accès seront désalignés ce qui se traduit par une perte sensible d'efficacité. Dans le pire des cas, si l'adresse de base se trouve 1 octet avant la fin d'une page, cela veut dire que quasiment tous les acces seront pénalisés !
Pour alligner un bloc de données sur un multiple de 256 octets, il suffit de faire ceci:
.dsb 256-(*&255)
If you're coding in 6502 it's good for you to carefully think about memory allocation because it allows a lot of speed optimisations !

Among those optimisation we can list the following:
  • No cycle penalty when using indexed adressing
  • No cycle penalty when using branch instructions
  • Using 8bit arithmetic instead of 16bits
  • Faster self modifying code
For instance, if you use indexed adressing, if you the index makes you cross a page boundary your are penalized by one clock cycle. If you manage to make the base adress being on a page boundary, you are sure to never cross a page. So try to allign your buffers on a adress that finishes by $00...

You're thinking it's not impressive ? Hum. In general, the most often used adressing mode (after immediate and absolute) is the LDA $adress,x or STA $adress,y. If the lower byte of the adress is equal to 0, all indexations with X and Y register will require 4 clock cycle. If it is not alligned, all access crossing the page boudary will take 5 clock cycle.
So, imagine you want to do a program that requires access to a table, your code will be considerably faster if you do this simple optimisation. In that case, the good idea is too put all the n*256 bytes tables consecutively in memory. Doing that, the waste of memory due to the alligment will be reduced.
To allign data on a 256 bytes boudary, this simple instruction will do the trick:
.dsb 256-(*&255)

SOS !!!Contact...Informations...