<-Précédent | Retour à l'accueil | Contact : etienne"point"sauvage"at"gmail.com | Suivant-> |
Il n'y a pas à dire, le mode protégé, c'est violent. Au chapitre précédent, on a retrouvé les interruptions. Lesquelles malheureusement sont vides. Retrouver l'entrée clavier, ce serait pas mal.
Lors de l'appui sur une touche, le PIC déclenche l'interruption à laquelle est branchée l'IRQ1. Doit s'ensuivre une discussion protocolaire avec le processeur afin de transmettre au processeur les connaissances du PIC.
Pour faire ça convenablement, nous allons écrire l'interruption déclenchée par l'IRQ1. Pour écrire une interruption, on ne se soucie pas du contexte, il est sauvegardé par l'instruction INT. On va commencer par interdire les interruptions : cli
. Ensuite, on demande au PIC s'il est disponible pour un échange fructueux :
.attendBuffer: in al, 0x64 ; lire statut test byte al,1 ; bus de sortie prêt ? jz .attendBuffer ; non => boucler
Ce qui signifie qu'on attend sagement qu'il y ait un octet avec le bit de poids faible à 1 sur le port 0x64, signifiant qu'il y a une entrée clavier à lire. Une fois qu'on est sûr qu'il y a une touche à traiter, on peut magnanimement en prendre connaissance :
in al, 0x60 ;Lit la touche pressée cmp al, 224 ;224 est un code spécial, ça veut dire qu'il y a autre chose derrière, mais pour l'instant on s'en fiche je .attendBuffer ;On va donc lire la suite
Le caractère se trouve sur un autre port, le port 0x60. Ensuite, le traitement commence, et pour cela, il nous faut un peu d'histoire. Le circuit qui gère le clavier n'est pas tout jeune. Il est standard, éprouvé, et vient de gens dont la principale motivation n'était pas le rendu typographique. De base, le clavier envoyait un octet qui donnait à la fois la touche concernée et son état : pressée ou relâchée. Cela fait deux codes par touche, sur un octet. On peut donc avoir 128 touches différentes. Il faut aussi savoir qu'au niveau où nous sommes, on parle de touche et non de caractère : la touche 23 a été relâchée, que celle-ci soit un 'A', un 'é' ou F4. Il a été remarqué que ce 128 pouvait être une limite un peu basse. Le code de touche a été étendu -voilà pourquoi on peut encore entendre qu'un ordinateur actuel possède un clavier étendu- sur deux octets. Pour marquer l'utilisation de code étendu, le premier octet prend des valeurs spéciales, dont 224, celle testée ici. Les codes clavier étendu ont été si bien faits que quand on ne prend pas en compte le mode étendu, le code signifie quand même quelque chose, caractéristique que nous mettons à profit ici en "oubliant" le code 224.
Pou la suite, j'ai un peu joué quand même. Après tout, on a bien le droit de se faire plaisir. Je me suis dit que j'allais stocker une carte de toutes les touches appuyées. Comme ça, si vous voulez savoir à n'importe quel moment si une touche est appuyée, un coup d'oeil sur cette carte et vous saurez si Shift ou Ctrl sont pressées. Mais si vous voulez faire "A + 3 + ,", c'est aussi possible. Pour ce faire, on a besoin de stocker 128 bits, un bit (pressée : oui ou non) par touche gérée par ce qu'il faut bien appeler un gestionnaire de clavier. 128 bits, c'est 16 octets: touchesActives: dd 0, 0, 0, 0
. La prochaine étape consiste donc à mettre le bit de la touche traitée à la valeur convenable. Première étape, trouver l'octet concerné dans la table :
mov bl, al shr bl, 3; On divise le code par 8 pour savoir dans quel octet il se situe push eax ; On sauve le caractère dans la pile mov cl, 8 div cl ; On le divise par 8 mov cl, ah ; Pour une division par 8 bits, le reste est dans AH pop eax mov edx, 1 shl dl, cl add ebx, touchesActives ;C'est l'adresse de l'octet contenant ce qui nous intéresse cmp al, 128 ;Les touches appuyées ont un code inférieur à 128, les touches relâchées, c'est le même code qu'appuyées plus 128 jb .stockeActif sub al, 128 sub ebx, 128/8 not dl and byte[ebx], dl jmp .suite .stockeActif: or byte[ebx], dl ; Un OU met le bit à 1, un NOT AND le mettra à 0 mov [derniereTouche], al
A noter dans ce morceau de code : l'utilisation de la position du reste d'une division en fonction de la taille des opérandes, chose à laquelle il faut toujours faire attention. SHL (et sa copine SHR ne peuvent décaler que d'un nombre constant ou du contenu du registre C. La différence de traitement entre touche pressée/touche relâchée est faite en un seul endroit, ce qui donne un code un peu contre-intuitif (pourquoi cette soustraction de 128/8 sur ebx ?). Notez l'utilisation du AND pour mettre des bits à 0 et du OR pour les mettre à 1. On termine, en cas de touche pressée, par la stocker en mémoire, afin que d'autres sous-programmes puissent y accéder. C'est grossier, vu qu'on stocke aussi les modificateurs, et je suis quasiment certain qu'un bon gestionnaire de clavier utilise un buffer circulaire.
Il reste à accuser réception, remettre les interruptions en place et quitter (ici, en appelant l'interruption PIC qui ne fait rien) :
.suite: in al, 0x61 or al, 130 out 0x61, al ;Dit à l'ordi qu'une touche a été pressée and al, 127 out 0x61, al ;Reinitialisation terminée sti jmp interruptionPICMaitreParDefaut
Car, suite à l'étape précédente, nous avons bien la dernière touche tapée, mais nous n'avons aucune idée du caractère auquel elle correspond. Nous allons avoir besoin d'une table de conversion qui fera la correspondance entre numéro de touche et caractère sérigraphié sur la touche. Voici cette table : traductionASCII: db '.','.','1','2','3','4','5','6','7','8','9','0','.','+','.','.','a','z','e','r','t','y','u','i','o','p','^','$',13,'.','q','s','d','f','g','h','j','k','l','m','%','.','.','*','w','x','c','v','b','n',',',';',':','!';54 caratères gérés
La position du caractère dans cette table est son numéro de touche.
Vous vous souvenez de cette routine de lecture de caractères ? Oui, nous avons progressé, depuis, mais nous ne l'avons plus depuis le passage en mode protégé. Il faut la refaire.
L'idée est de commencer par vider le simili-tampon que nous avons dans la routine d'interruption. Ensuite, nous lirons le contenu de ce tampon. L'octet ainsi récupéré nous donne l'index à lire dans le tableau de conversion, et nous avons ainsi notre caractère.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; litChaine ;; ;;------------------------------------------------------------------;; ;; Ecrit dans la chaîne pointée par EDI les caractères écrits au ;; ;; clavier, jusqu'à un retour chariot. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; litChaine: push eax push ebx xor eax, eax mov byte [derniereTouche], 0 mov esi, edi .attend_clavier: cmp byte [derniereTouche], 0 jz .attend_clavier mov al, [derniereTouche] mov byte [derniereTouche], 0 mov ebx, traductionASCII add ebx, eax mov al, [ebx] stosb cmp al, 13 je .fin_attend_clavier mov al, 0 stosb call afficheChaine dec edi dec esi jmp .attend_clavier .fin_attend_clavier: pop ebx pop eax ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Fin litChaine ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
L'ensemble du code, depuis le chapitre 8, se trouve ici :
Tuto8