Le mystère de la touche COPY!
Je suis tombé sur cette vidéo, dans laquelle on voit que la touche COPY semble se comporter de facon étonnante, car elle ne saurait pas faire la différence entre un bon caractère et un mauvais caractere à l'écran.
Pour rappel, la fonction Copy permettait de dédoubler le curseur à l'écran, de placer ce seconde curseur n'importe ou à l'écran et de recopier ce qu'il se trouve à l'écran à cet endroit, l'emplacement du premier curseur, à partir du moment ou il s'agit d'un caractère reconnu par le firmware. Si on tentant de recopier un bout de dessin fait à l'aide de PLOT et de DRAW, on avait droit à un beep de mécontentement.
Mais alors comment expliquer ce qui est décrit comme un phénomène sidérant dans la vidéo? Rien de plus simple, il suffit d'aller jeter un œil dans la ROM! Nous allons nous baser sur une version disponible en ligne, il en existe plusieurs, celle ci est scindée en plusieurs fichiers ce qui est plus pratique:
Parmi la liste des fichiers, le premier qui attire notre regard est LineEditor.asm. Une recherche du mot 'COPY' nous mène directement à la ligne 637:
;; COPY key pressed
COPY_key_pressed:
push bc
push hl
call TXT_GET_CURSOR
ex de,hl
call get_copy_cursor_position
jr nz,_copy_key_pressed_12
ld a,b
or c
jr nz,_copy_key_pressed_25
call TXT_GET_CURSOR
ld (copy_cursor_rel_to_origin),hl
jr _copy_key_pressed_14
;;--------------------------------------------------------------------
_copy_key_pressed_12:
call TXT_SET_CURSOR
call TXT_PLACE_CURSOR
_copy_key_pressed_14:
call TXT_RD_CHAR
push af
ex de,hl
call TXT_SET_CURSOR
ld hl,(copy_cursor_rel_to_origin)
inc h
call TXT_VALIDATE
jr nc,_copy_key_pressed_23
ld (copy_cursor_rel_to_origin),hl
_copy_key_pressed_23: ;
call _shift_key__left_cursor_pressed_21
pop af
_copy_key_pressed_25:
pop hl
pop bc
jp c,edit_for_key_13
jp edit_sound_bleeper
Pour réaliser une analyse rapide, on pourra consulter la table des indirections du pack text (préfixé par TXT), que l'on peut retrouver ici. En particulier:
ADDR | CODE | Description |
---|---|---|
&BB4E | TXT_INITIALISE | Initialise the Text VDU |
&BB51 | TXT_RESET | Reset the Text VDU |
&BB5A | TXT_OUTPUT | Output a character or control code to the Text VDU |
&BB5D | TXT_WR_CHAR | Write a character onto the screen |
&BB60 | TXT_RD_CHAR | Read a character from the screen |
&BB6F | TXT_SET_COLUMN | Set cursor horizontal position |
&BB72 | TXT_SET_ROW | Set cursor vertical position |
&BB75 | TXT_SET_CURSOR | Set cursor position |
&BB78 | TXT_GET_CURSOR | Ask current cursor position |
&BB87 | TXT_VALIDATE | Check if a cursor position is within a window |
&BB8A | TXT_PLACE_CURSOR | Put a cursor blob on the screen |
&BB8D | TXT_REMOVE_CURSOR | Take a cursor blob off the screen |
&BBA5 | TXT_GET_MATRIX | Get the address of a character matrix |
&BBA8 | TXT_SET_MATRIX | Set a character matrix |
Donc Après une analyse rapide, on comprend que l'appui de la touche copie provoque la récupération de la position des 2 curseurs ( TXT_GET_CURSOR ) suivi de l'appel a TXT_RD_CHAR, suivi d'une validation ( TXT_VALIDATE ), qui si elle échoue provoque l'émission d'un son (edit_sound_bleeper) . Cette validation est essentielle, car la fonction de recopie à l'écran est utilisée pour écrire du texte qui sera analysé par l'interpréteur basic. Il est hors de question de copier des caracteres inexistants!
Le vecteur &BB60
Ce TXT_RD_CHAR semble donc être la clé de notre énigme. Une rapide recherche dans Clefs Pour Amstrad nous donne:
Bingo! C'est donc cette routine qui serait à l'origine du mystère présenté dans la vidéo. Allons voir le code de TXT_RD_CHAR, cette fois ci dans le fichier text.asm, à la ligne 720:
TXT_RD_CHAR:
push hl
push de
push bc
call scroll_window
call TXT_UNWRITE
push af
call TXT_DRAW_CURSOR
pop af
pop bc
pop de
pop hl
ret
Rien de particulier, si ce n'est l'appel à TXT_UNWRITE, qui contient cette boucle:
ld c,$00
_ind_txt_unwrite_21:
ld a,c
call TXT_GET_MATRIX
ld de,RAM_b738
ld b,$08
_ind_txt_unwrite_25:
ld a,(de)
cp (hl)
jr nz,_ind_txt_unwrite_3
inc hl
inc de
djnz _ind_txt_unwrite_25
ld a,c
cp $8f
scf
ret
_ind_txt_unwrite_35:
inc c
jr nz,_ind_txt_unwrite_21;
xor a
ret
Cette boucle compare un à un les caractères de la fonte avec le contenu de la RAM en &B738. TXT_GET_MATRIX permet de récupérer le caractère. La zone en &B738 est utilisée par une autre fonction du firmware, cette fois dans le pack Screen, SCR_REPACK (&BC56). Elle est appelée au début de TXT_UNWRITE.
En effet, il y a la une subtilité gérée par le firmware, c'est qu'en fonction du mode écran, un même caractère n'occupera pas le même nombre d'octets en RAM. Il faut donc procéder a la transformation de la ce qu'il y a à l'écran sous forme standardisée. C'est exactement le rôle de SCR_REPACK:
&B738 : Compress a character matrix to the standard form
J'invite le lecteur à aller regarder le code de SCR_REPACK à la ligne 1146 du fichier Screen.asm en guise de récréation. Nous allons ici nous contenter de regarder le contenu de a RAM en &B738, après avoir entré le caractère A dans l'éditeur Basic, selon les modes:
Il faut aussi se rendre compte que la matrice utilisée pour la comparaison tient aussi compte du fait qu'elle peut avoir été redéfinie par l'utilisateur (avec la fonction SYMBOL duBasic).
Conclusion
Il est remarquable de constater la encore la grande sophistication du firmware utilisé dans l'Amstrad. L'absence d'un véritable mode texte sur CPC a forcé les ingénieurs qui ont conçu cette machine, de mettre en œuvre toute une stratégie pour réaliser cette fonction de recopie à l'écran. Derrière cette fonction, il faut en effet récupérer les données placées sous le curseur, le convertir selon les modes utilisés, et aller comparer les caractères un a un avec la fonte système (voire la fonte redéfinie par l'utilisateur avec SYMBOL), et le cas échéant recopier le caractère.