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.
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.
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
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
Las siete reglas siguientes deben ser observadas al cifrar un subprograma:
Nota
La rutina llamada no debe cambiar el contenido de cualesquiera de los tres octetos del descriptor de la secuencia.
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) |
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.
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
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.
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:
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:
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