Apéndice D
Subprogramas Del Lenguaje ensamblador (Código Automático)

 

Este apéndice se escribe sobre todo para los usuarios experimentados en la programación del lenguaje ensamblador.

GW-BASIC le deja interconectar con subprogramas del lenguaje ensamblador usando la función USR y la declaración CALL.

La función USR permite que los subprogramas del lenguaje ensamblador sean llamados de la misma manera GW-BASIC que se llaman las funciones intrínsecas. Sin embargo, la declaración CALL se recomienda para los programas de interconexión de la terminología de la informática con GW-BASIC. La declaración CALL es compatible con más idiomas que la llamada de función USR, produce un código de fuente más legible, y puede pasar discusiones múltiples.

Asignación De Memoria D.1

La memoria se debe poner a un lado para un subprograma del lenguaje ensamblador (o el código automático) antes de que pueda ser cargada. Hay tres maneras recomendadas de poner el espacio a un lado para las rutinas del lenguaje ensamblador:

Si, cuando se llama un subprograma del lenguaje ensamblador, más espacio del apilado es necesario, el espacio del apilado de GW-BASIC se puede ser ahorrado, y un apilado nuevo instalar para el uso por el subprograma del lenguaje ensamblador. El espacio del apilado de GW-BASIC se debe restaurar, sin embargo, antes de volver del subprograma.

Declaración de LLAMADA D.2

CALL variablename[(arguments)]

variablename contiene la compensación en el segmento actual del subprograma que es llamado.

arguments son las variables o las constantes, separadas por las comas, que deben ser pasadas a la rutina.

Para cada parámetro en arguments, la compensación 2-byte de la localización del parámetro dentro del segmento de datos (DS) se empuja sobre el apilado.

El segmento de código del remite de GW-BASIC (CS), y la compensación (IP) se empujan sobre el apilado.

Una llamada larga a la dirección del segmento dada en la declaración pasada de DEF SEG y la compensación dada en control de las transferencias variablename a la rutina de usuario.

El segmento del apilado (SS), el segmento de datos (DS), el segmento adicional (ES), y el puntero de pila (SP) deben ser preservados.

La figura D.1 demuestra el estado del apilado a la hora de la declaración CALL:

    Cuadro 1

Figura disposición del apilado de D.1 cuando la declaración CALL se activa no demostrada

La rutina de usuario ahora tiene control. Los parámetros pueden ser referidos moviendo el puntero de pila (SP) al indicador bajo (punto de ebullición) y agregando una compensación positiva al punto de ebullición.

Sobre entrada, el segmento coloca el DS, el ES, y los SS todo el punto a la dirección del segmento que contiene el código de intérprete de GW-BASIC. El CS del registro del segmento de código contiene el valor más último provisto por DEF SEG. Si no se ha especificado ningún DEF SEG, entonces señala a la misma dirección que el DS, el ES, y SS (DEF SEG predeterminado).

La figura D.2 demuestra la condición del apilado durante la ejecución del subprograma llamado:

  Cuadro 2

Figura disposición del apilado de D.2 durante la ejecución de una declaración CALL no demostrada

Las siete reglas siguientes deben ser observadas al cifrar un subprograma:

  1. La rutina llamada puede destruir el contenido de los registros del AX, BX, CX, DX, SI, DI, y BP. No requieren la restauración sobre vuelta a GW-BASIC. Sin embargo, todo el segmento se coloca y el puntero de pila debe ser restaurado. La buena práctica de programación dicta que las interrupciones permitidas o inhabilitadas estén restauradas al estado observado sobre entrada.
  2. El programa llamado debe saber el número y la longitud de los ters del parame- pasados. Las referencias a los parámetros son positivas que las compensaciones agregadas al punto de ebullición, si se asume que la rutina llamada movieron el puntero de pila actual en el punto de ebullición; es decir, MOV BP,SP. Cuando se pasan 3 parámetros, la localización del PO está en BP+10, P1 está en BP+8, y P2 está en BP+6.
  3. La necesidad llamada de la rutina hace RETURN n (n es dos veces el número de parámetros en la lista de la discusión) para ajustar el apilado al comienzo de la secuencia que llama. También, los programas se deben definir por una declaración PROC FAR.
  4. Los valores son vueltos a GW-BASIC incluyendo en la lista de la discusión el nombre variable que recibe el resultado.
  5. Si la discusión es una secuencia, los puntos compensados del parámetro a tres octetos llamaron el descriptor de la secuencia. El octeto 0 del descriptor de la secuencia contiene la longitud de la secuencia (0 a 255). Los octetos 1 y 2, respectivamente, son los pedacitos más bajos y del alto ocho de la dirección que comienza de la secuencia en espacio de la secuencia.


    Nota

    La rutina llamada no debe cambiar el contenido de cualesquiera de los tres octetos del descriptor de la secuencia.


  6. Las secuencias se pueden alterar por rutinas de usuario, pero su longitud no debe ser cambiada. GW-BASIC no puede manipular correctamente secuencias si sus longitudes son modificadas por rutinas externas.
  7. Si el argumento es una cadena literal en el programa, el descriptor de la secuencia señala al texto del programa. Tenga cuidado de no alterar o de no destruir su programa esta manera. Para evitar resultados imprevisibles, agregue + "" al literal de cadena en el programa. Por ejemplo, la línea siguiente fuerza el literal de cadena para ser copiada en el espacio de la secuencia asignado fuera de memoria del programa:
    20 A$="BASIC"+""

    La secuencia puede entonces ser modificada sin afectar el programa.

Ejemplos:

100 DEF SEG=&H2000
110 ACC=&H7FA
120 CALL ACC(A,B$,C)
.
.
.

 

Línea 100 sistemas el segmento a la tuerca hexagonal 2000. El valor del ACUMULADOR variable se agrega en la dirección mientras que la palabra baja después de que el valor DEF SEG izquierdo-se cambie de puesto cuatro pedacitos (ésta es una función del microprocesador, no de GW-BASIC). Aquí, el ACUMULADOR se fija a &H7FA, de modo que la llamada al ACUMULADOR ejecute el subprograma en la tuerca hexagonal de la localización 2000:7FA.

Sobre entrada, solamente 16 octetos (ocho palabras) siguen siendo disponibles dentro del espacio asignado del apilado. Si el programa llamado requiere el espacio adicional del apilado, después el programa de usuario debe reajustar el puntero de pila a un nuevo espacio asignado. Sea seguro restaurar el puntero de pila ajustado al comienzo de la secuencia que llama en vuelta a GW-BASIC.

La secuencia siguiente del lenguaje ensamblador demuestra el acceso de los parámetros pasados y el almacenaje de un resultado de vuelta en la C variable.


Nota

El programa llamado debe saber el tipo variable para los parámetros numéricos pasados. En estos ejemplos, la instrucción siguiente copia solamente dos octetos:

MOVSW

Esto es adecuado si las variables A y C son número entero. Sería necesario copiar cuatro octetos si eran simple precisión, o la copia ocho octetos si eran doble precisión.



MOV BP,SP Consigue la posición actual del apilado en el punto de ebullición
MOV BX,8[BP] Consigue la dirección de la descripción de B$
MOV CL,[BX] Consigue la longitud de B$ en CL
MOV DX,1[BX] Consigue la dirección del descriptor de la secuencia de B$ en DX
MOV SI,10[BP] Consigue la dirección de A en el SI
MOV DI,6[BP] Consigue el indicador a C en DI
MOVSW Almacena la variable A en ' C '
RET 6 Apilado de los restores; vueltas(returns)


Llamadas De Función De D.3 USR

Aunque la declaración CALL es la manera recomendada de llamar subprogramas del lenguaje ensamblador, la llamada de función de USR todavía está disponible para la compatibilidad con programas anterior-escritos.

Sintaxis:

USR[n](argument)

n es un número a partir de la 0 a 9 que especifica la rutina de USR que es llamada (véase la declaración DEF USR). Si se omite n, se asume USR0.

argument es cualquier expresión numérica o de la secuencia.

En GW-BASIC una declaración DEF SEG se debe ejecutar antes de una llamada de función USR para asegurarse de que el segmento de código señala al subprograma que es llamado. La dirección del segmento dada en la declaración DEF SEG determina el segmento que comienza del subprograma.

Para cada llamada de función USR, una declaración correspondiente DEF USR se debe haber ejecutado para definir la compensación de la llamada de función USR. Esta compensación y la dirección actualmente activa DEF SEG determinan la dirección que comienza del subprograma.

Cuando se hace la llamada de función USR, el AL del registro contiene el tipo bandera ( NTF) del número, que especifica el tipo de discusión dado. El valor de NTF puede ser uno del siguiente:

Valor de NTF Especifica
2 un número entero de dos bytes (dos complementan formato)
3 una secuencia
4 un número de simple precision con coma flotante
8 un número de doble precisión con coma flotante

Si la discusión de una llamada de función de USR es un número (AL<>73), el valor de la discusión se pone en el acumulador floating-point (FAC). El FAC tiene 8 octetos de largo y está en el segmento de datos de GW-BASIC. El registro BX señalará en el quinto octeto del FAC. La figura demostraciones de D.3 la representación de todo el número de GW-BASIC mecanografía adentro el FAC:

  Cuadro 3

La figura número de D.3 mecanografía adentro el acumulador de la coma flotante no demostrado

Si la discusión es una solo-precision floating-point numere:

Si la discusión es un número entero:

Si la discusión es una floating-point de precisión doble numere:

Si la discusión es una secuencia (indicada por el valor 3 almacenado en el registro del AL) los puntos del par del registro (DX) a tres octetos llamados el descriptor de la secuencia. El octeto 0 del descriptor de la secuencia contiene la longitud de la secuencia (0 a 255). Los octetos 1 y 2, respectivamente, son los pedacitos más bajos y superiores-ocho de la dirección que comienza de la secuencia en el segmento de datos de GW-BASIC.

Si la discusión es un literal de cadena en el programa, el descriptor de la secuencia señala al texto del programa. Tenga cuidado de no alterar o de no destruir programas esta manera (véase la declaración CALL precedente).

Generalmente, el valor vuelto por una llamada de función USR es el mismo tipo (número entero, secuencia, sola precisión, o precisión doble) que la discusión que le fue pasada. Los registros que deben ser preservados están iguales que en la declaración CALL.

Un lejos return se requiere para salir del subprograma USR. El valor vuelto se debe almacenar en el FAC.


D.4 Programas que CALL Lenguaje Programa ensamblador

Esta sección contiene dos programas de la muestra GW-BASIC que

El segmento y la compensación de código a la primera rutina se almacena en vector de la interrupción en 0:100H.

El ejemplo 1 llama un subprograma del lenguaje ensamblador:

Ejemplo 1

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

El subprograma del lenguaje ensamblador llamado en el programa antedicho se debe montar, ligar, y convertir a un archivo del COM. Seguirá habiendo el programa, cuando está ejecutado antes del funcionamiento del programa de GW-BASIC, en memoria hasta que la energía del sistema se da vuelta apagado, o se reanuda el sistema.

 

0100            org 100H
0100            double segment
                assume cs:double
0100 EB 17 90   start: jmp start1
0103            usrprg proc far
0103 55         push bp
0104 8B EC      mov bp,sp
0106 8B 76 08   mov si,[bp]+8        ;get address of parameter b
0109 8B 04      mov ax,[si]          ;get value of b
010B 8B 76 0A   mov si,[bp]+10       ;get address of parameter a
010E 03 04      add ax,[si]          ;add value of a to value of b
0110 8B 7E 06   mov di,[bp]+6        ;get address of parameter c
0113 89 05      mov di,ax            ;store sum in parameter c
0115 5D         pop bp
0116 ca 00 06   ret 6
0119            usrprg endp
                                     ;Program to put procedure in
                                     ;memory and remain resident. The
                                     ;offset and segment are stored
                                     ;in location 100-103H.
0119            start1:
0119 B8 00 00   mov ax,0
011C 8E D8      mov ds,ax            ;data segment to 0000H
011E BB 01 00   mov bx,0100H         ;pointer to int vector 100H
0121 83 7F 02 0 cmp word ptr [bx],0
0125 75 16      jne quit             ;program already run, exit
0127 83 3F 00   cmp word ptr2 [bx],0
012A 75 11      jne quit             ;program already run exit
012C B8 01 03 R mov ax,offset usrprg
012F 89 07      mov [bx],ax          ;program offset
0131 8C c8      mov ax,cs
0133 89 47 02   mov [bx+2],ax        ;data segment
0136 0E         push cs
0137 1F         pop ds
0138 BA 0141 R  mov dx,offset veryend
013B CD 27      int 27h
013D            quit:
013D CD 20      int 20h
013F            veryend:
013F            double ends
                end start

 

 

El ejemplo 2 pone el subprograma del lenguaje ensamblador en el área especificada:

Example 2

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