Section courante

A propos

Section administrative du site

Sous-programmes de langage d'assemblage (code machine)

Cette page est écrite principalement pour les utilisateurs expérimentés dans la programmation en langage assembleur. Le GW-BASIC vous permet d'interfacer avec les sous-routines du langage d'assemblage en utilisant la fonction USR et l'instruction CALL.

La fonction USR permet aux sous-programmes du langage assembleur d'être appelés de la même manière que les fonctions intrinsèques GW-BASIC. Cependant, l'instruction CALL est recommandée pour interfacer des programmes en langage machine avec GW-BASIC. L'instruction CALL est compatible avec plus de langages que l'appel de fonction USR, produit un code source plus lisible et peut transmettre plusieurs paramètres.

Allocation de mémoire

L'espace mémoire doit être réservé pour un sous-programme en langage assembleur (ou code machine) avant de pouvoir le charger. Il existe trois méthodes recommandées pour réserver de l'espace pour les routines en langage assembleur :

Si, lorsqu'un sous-programme en langage assembleur est appelé, plus d'espace de pile est nécessaire, l'espace de pile GW-BASIC peut être enregistré et une nouvelle pile configurée pour être utilisée par le sous-programme en langage assembleur. L'espace de pile GW-BASIC doit être restauré, cependant, avant de quitter le sous-programme.

Instruction CALL

CALL variablename[(arguments)]

variablename contient le déplacement dans le segment courant du sous-programme appelé.

arguments sont les variables ou constantes, séparées par des virgules, devant être passées à la routine.

Pour chaque paramètre dans les arguments, le déplacement de 2 octets de l'emplacement du paramètre dans le segment de données (DS) est poussé sur la pile.

Le segment de code d'adresse de retour (CS) de GW-BASIC et le déplacement (IP) sont poussés sur la pile.

Un long appel à l'adresse de segment donnée dans la dernière instruction DEF SEG et le décalage donné dans variablename transfèrent le contrôle à la routine de l'utilisateur.

Le segment de pile (SS), le segment de données (DS), le segment supplémentaire (ES) et le pointeur de pile (SP) doivent être conservés.

La figure suivante montre l'état de la pile au moment de l'instruction CALL :

La routine de l'utilisateur a maintenant le contrôle. Les paramètres peuvent être référencés en déplaçant le pointeur de pile (SP) vers le pointeur de base (BP) et en ajoutant un décalage positif à BP.

Lors de l'entrée, les registres de segment DS, ES et SS pointent tous vers l'adresse du segment contenant le code interpréteur GW-BASIC. Le registre de segment de code CS contient la dernière valeur fournie par DEF SEG. Si aucun DEF SEG n'a été spécifié, il pointe alors vers la même adresse que DS, ES et SS (le DEF SEG par défaut).

La figure suivante montre l'état de la pile lors de l'exécution du sous-programme appelé :

Les sept règles suivantes doivent être respectées lors du codage d'un sous-programme :

Voici un exemple :

  1. 100 DEF SEG=&H2000
  2. 110 ACC=&H7FA
  3. 120 CALL ACC(A,B$,C)
  4. .
  5. .
  6. .

La ligne 100 définit le segment sur 2000 hexadécimal. La valeur de la variable ACC est ajoutée à l'adresse en tant que mot bas après que la valeur DEF SEG s'est déplacer à gauche de quatre bits (c'est une fonction du microprocesseur, pas de GW-BASIC). Ici, ACC est défini sur &H7FA, de sorte que l'appel à ACC exécute le sous-programme à l'emplacement 2000:7FA hexadécimal.

Lors de l'entrée, seuls 16 octets (huit mots) restent disponibles dans l'espace de pile alloué. Si le programme appelé nécessite un espace de pile supplémentaire, le programme utilisateur doit réinitialiser le pointeur de pile sur un nouvel espace alloué. Assurez-vous de restaurer le pointeur de pile ajusté au début de la séquence d'appel lors du retour à GW-BASIC.

La séquence suivante en langage assembleur illustre l'accès aux paramètres passés et l'entreposage d'un résultat de retour dans la variable C.

Note

  1. MOV BP,SP     ; Obtient la position actuelle de la pile dans BP
  2. MOV BX,8[BP] ; Obtient l'adresse de la description B$
  3. MOV CL,[BX]     ; Obtient la longueur de B$ en CL
  4. MOV DX,1[BX] ; Obtient l'adresse du descripteur de chaîne de caractères B$ dans DX
  5. MOV SI,10[BP] ; Obtient l'adresse de A en SI
  6. MOV DI,6[BP] ; Obtient le pointeur vers C dans DI
  7. MOVSW         ; Entrepose la variable A dans 'C'
  8. RET 6         ; Restaure la pile ; Retour

Appels de fonction USR

Bien que l'instruction CALL soit la méthode recommandée pour appeler les sous-routines du langage d'assemblage, l'appel de fonction USR est toujours disponible pour la compatibilité avec les programmes écrits précédemment. Voici sa syntaxe :

USR[n](argument)

n est un nombre compris entre 0 et 9 spécifiant la routine USR appelée (voir instruction DEF USR). Si n est omis, USR0 est supposé.

argument est une expression numérique ou de chaîne de caractères.

Dans GW-BASIC, une instruction DEF SEG doit être exécutée avant un appel de fonction USR pour garantir que le segment de code pointe vers la sous-routine appelée. L'adresse de segment donnée dans l'instruction DEF SEG détermine le segment de départ du sous-programme.

Pour chaque appel de fonction USR, une instruction DEF USR correspondante doit avoir été exécutée pour définir le déplacement d'appel de fonction USR. Ce déplacement et l'adresse DEF SEG actuellement active déterminent l'adresse de début du sous-programme.

Lorsque l'appel de la fonction USR est effectué, le registre AL contient l'indicateur de type de numéro (NTF), spécifiant le type d'argument donné. La valeur NTF peut être l'une des suivantes :

Valeur NTF Spécification
2 un entier sur deux octets (format complément à deux)
3 une chaîne de caractères
4 un nombre à virgule flottante de simple précision
8 un nombre à virgule flottante de double précision

Si l'argument d'un appel de fonction USR est un nombre (AL<>73), la valeur de l'argument est placée dans l'accumulateur à virgule flottante (FAC). Le FAC a une longueur de 8 octets et se trouve dans le segment de données GW-BASIC. Le registre BX pointera sur le cinquième octet du FAC. La Figure suivante montre la représentation de tous les types de numéros GW-BASIC dans le FAC :

Si l'argument est un nombre à virgule flottante simple précision :

Si l'argument est un entier :

Si l'argument est un nombre à virgule flottante double précision :

Si l'argument est une chaîne de caractères (indiquée par la valeur 3 stockée dans le registre AL), la paire de registres (DX) pointe sur trois octets appelés le descripteur de chaîne de caractères. L'octet 0 du descripteur de chaîne de caractères contient la longueur de la chaîne de caractères (0 à 255). Les octets 1 et 2, respectivement, sont les huit bits inférieurs et supérieurs de l'adresse de début de chaîne de caractères dans le segment de données GW-BASIC.

Si l'argument est un littéral de chaîne de caractères dans le programme, le descripteur de chaîne de caractères pointe vers le texte du programme. Veillez à ne pas modifier ou détruire des programmes de cette manière (voir l'instruction CALL précédente).

Généralement, la valeur renvoyée par un appel de fonction USR est du même type (entier, chaîne de caractères, simple précision ou double précision) que l'argument lui ayant été transmis. Les registres qui doivent être conservés sont les mêmes que dans l'instruction CALL.

Un retour lointain est nécessaire pour quitter le sous-programme USR. La valeur retournée doit être entreposée dans le FAC.

Programmes appellant des programmes en langage d'assemblage

Cette section contient deux exemples de programmes GW-BASIC qui :

Le segment de code et le déplacement vers le premier sous-programme sont entreposés dans le vecteur d'interruption à 0:100H.

L'exemple 1 appelle une sous-routine en langage assembleur :

  1. 10 DEF SEG=0
  2. 100 CS=PEEK(&H102)+PEEK(&H103)*256
  3. 200 OFFSET=PEEK(&H100)+PEEK(&H101)*256
  4. 250 DEF SEG
  5. 300 C1%=2:C2%=3:C3%=0
  6. 400 TWOSUM=OFFSET
  7. 500 DEF SEG=CS
  8. 600 CALL TWOSUM(C1%,C2%,C3%)
  9. 700 PRINT C3%
  10. 800 END

La sous-routine en langage assembleur appelée dans le programme ci-dessus doit être assemblée, liée et convertie en un fichier .COM. Le programme, lorsqu'il est exécuté avant l'exécution du programme GW-BASIC, restera en mémoire jusqu'à ce que l'alimentation du système soit coupée ou que le système soit redémarré.

  1. 0100            org 100H
  2. 0100            double segment
  3.                 assume cs:double
  4. 0100 EB 17 90   start: jmp start1
  5. 0103            usrprg proc far
  6. 0103 55         push bp
  7. 0104 8B EC      mov bp,sp
  8. 0106 8B 76 08   mov si,[bp]+8        ;obtenir l'adresse du paramètre b
  9. 0109 8B 04      mov ax,[si]          ;obtenir la valeur de b
  10. 010B 8B 76 0A   mov si,[bp]+10       ;obtenir l'adresse du paramètre a
  11. 010E 03 04      add ax,[si]          ;ajouter la valeur de a à la valeur de b
  12. 0110 8B 7E 06   mov di,[bp]+6        ;obtenir l'adresse du paramètre c
  13. 0113 89 05      mov di,ax            ;entrepose la somme dans le paramètre c
  14. 0115 5D         pop bp
  15. 0116 ca 00 06   ret 6
  16. 0119            usrprg endp
  17.                                      ;Programme pour mettre la procédure en mémoire et rester résident. Le déplacement et le segment sont entreposés à l'emplacement 100-103H.
  18. 0119            start1:
  19. 0119 B8 00 00   mov ax,0
  20. 011C 8E D8      mov ds,ax            ;segment de données à 0000H
  21. 011E BB 01 00   mov bx,0100H         ;pointeur vers le vecteur int 100H
  22. 0121 83 7F 02 0 cmp word ptr [bx],0
  23. 0125 75 16      jne quit             ;programme déjà exécuté, quitter
  24. 0127 83 3F 00   cmp word ptr2 [bx],0
  25. 012A 75 11      jne quit             ;programme déjà exécuté quitter
  26. 012C B8 01 03 R mov ax,offset usrprg
  27. 012F 89 07      mov [bx],ax          ;déplacement de programme
  28. 0131 8C c8      mov ax,cs
  29. 0133 89 47 02   mov [bx+2],ax        ;segments de données
  30. 0136 0E         push cs
  31. 0137 1F         pop ds
  32. 0138 BA 0141 R  mov dx,offset veryend
  33. 013B CD 27      int 27h
  34. 013D            quit:
  35. 013D CD 20      int 20h
  36. 013F            veryend:
  37. 013F            double ends
  38.                 end start

L'exemple 2 place la sous-routine du langage assembleur dans la zone spécifiée :

  1. 10 I=0:JC=0
  2. 100 DIM A%(23)
  3. 150 MEM%=VARPTR(A%(1))
  4. 200 FOR I=1 TO 23
  5. 300 READ JC
  6. 400 POKE MEM%,JC
  7. 450 MEM%=MEM%+1
  8. 500 NEXT
  9. 600 C1%=2:C2%=3:C3%=0
  10. 700 TWOSUM=VARPTR(A%(1))
  11. 800 CALL TWOSUM(C1%,C2%,C3%)
  12. 900 PRINT C3%
  13. 950 END
  14. 1000 DATA &H55,&H8b,&Hec &H8b,&H76,&H08,&H8b,&H04,&H8b,&H76
  15. 1100 DATA &H0a,&H03,&H04,&H8b,&H7e,&H06,&H89,&H05,&H5d
  16. 1200 DATA &Hca,&H06,&H00


Dernière mise à jour : Vendredi, le 15 septembre 2017