Sur une machine avec un « vrai » mode texte, lorsqu’on affiche du texte, le micro-processeur se contente de copier les codes ASCII de chaque caractère dans zone définie de la mémoire vidéo, et le processeur graphique se charge de convertir ces codes ASCII en caractères visibles sur l’écran.
Le ZX-Spectrum, comme plusieurs micros de la même époque, ne dispose pas d’un mode d’affichage par caractères « matériel ». Cela veut dire que lorsqu’on affiche du texte, celui-ci est affiché en mode graphique par le micro-processeur.
C’est légèrement plus lent car il faut au minimum modifier 8 octets dans la mémoire vidéo au lieu d’un seul(*), mais en général ça ne se remarque pas trop.
Un avantage est qu’on peut sans problème mélanger texte et graphiques à l’écran, mais il peut être compliqué pour un programme de retrouver quel caractère se trouve à une position donnée de l’écran.
Certains micros, comme le TRS-80 Model 100(**) conservent une « fausse » ram vidéo qui contient le code ASCII de chaque caractère affiché. Le micro-processeur doit toujours « dessiner » chaque caractère en entier en mode graphique, mais si on veut savoir quel caractère se trouve à une position donnée il suffit de lire cette mémoire vidéo pour trouver son code ASCII(***).
Sur le ZX-Spectrum ce n’est pas le cas.
Il y a pourtant une fonction BASIC appelée SCREEN$
qui renvoie le caractère affiché à une position donnée de l’écran.
Comment cette fonction procède-t-elle pour retourner cette information ?
Je soupçonnais la présence d’une zone mémoire conservant les caractères affichés comme pour le Model 100, mais cela ne fonctionnait pas avec les caractères redéfinissables.
En effet le ZX-Spectrum dispose de 21 caractères redéfinissables (codes ASCII entre 144 et 164). Après un reset, ces caractères contiennent les graphiques des caractères « A » à « U ».
Si on entre les deux lignes suivantes :
PRINT CHR$ 144
PRINT ASC SCREEN$(0,0)
nous récupérons un « A » (le graphique par défaut du caractère 144) suivi de la valeur… 65 ! (le code ASCII du « vrai » A).
Que ce passe-t-il donc ?
Pour vérifier j’ai écrit le petit programme ci-dessous :
Ce programme affiche un « F » dans la première case de l’écran (à la position 0,0), lit le code ASCII correspondant avec SCREEN$(0,0)
(70, valeur ASCII de F) puis traces 1 pixel dans cette même case avant de relire son code ASCII (maintenant 0 puisque ce caractère n’existe pas) avant de tracer une droite pour transformer le caractère « F » en « E », puis de lire une dernière fois la valeur de SCREEN$(0,0)
, qui est maintenant 69 (c’est à dire le code ASCII du « E »).
Est-ce que cette fonction reconnaît vraiment dynamiquement tous les symboles du jeu de caractères du ZX-Spectrum ?
Je pensais qu’une simple implémentation serait d’utiliser une fonction de hashage sur les 8 octets qui composent l’image du caractère, puis de regarder dans une table de lookup pour trouver le code ASCII correspondant à l’image, mais après avoir regardé le code source de cette fonction, il semble qu’elle compare effectivement les 8 octets de l’image avec les images du jeu de caractère !
Cette reconnaissance fonctionne pour toutes les couleurs, ce qui peut poser quelques problèmes. En effet, à cause de cette fonctionnalité, SCREEN$
retourne la même valeur pour un espace et pour un bloc graphique plein, mais heureusement il y a des solutions pour contourner ce problème.
Décidément, ce bon vieux ZX-Spectrum est plein de surprises dès qu’on le regarde d’un peu plus près.
(*) Plus si l’affichage est en couleurs
(**) Sur lequel je suis en train de taper cet article :o)
(***) Ca lui sert aussi à redessiner l’écran après un scrolling vertical