<-Informática\ensamblador 80x86...
Ejemplo 2 La instalación de manejadores de interrupción es uno de los tipos de programas que más cuesta de entender o que más dudas sugiere, lo cual es comprensible en gran medida.¿cómo entenderlo?¿qué hacer si se propone un ejercicio de este estilo?....son algunas de las preguntas típicas. Para resolver estas preguntas nos vamos a basar en nuestro programa, el cual instala un manejador que se ejecutará automáticamente cada vez q se produzca la interrupción 8h (del oscilador) y que escribira un '*' en una posición determinada de la pantalla. Evidentemente esta substituira a la subrutina del oscilador pero en esta se hara una llamada a la antigua para que el reloj del sistema no deje de funcionar. Hay diversas cosas que se deben considerar en este tipo de programa: A)El manejador no es mas que un trozo de código que nosotros escribiremos y que no tendremos que llamar desde ninguna parte en nuestro programa puesto que se ejecutara automáticamente de alguna forma. B)En el ordenador,como ya se conoce,se generan una serie de interrupciones hardware cuando algún suceso externo se produce. Como ya se sabe también esto genera una interrupción de la tarea q realizaba el procesador pasando a ejecutar el código asignado a esta situado en alguna parte de la memoria que desconocemos. C)La forma en que el procesador conoce la dirección en memoria donde se encuentran cada uno de los manejadores de interrupción es por la tabla de vectores de interrupción que situada entre las direcciones 00000h y 003FFh (1 Kbyte) incluyen secuencialmente para cada uno de los 256 códigos de interrupción posibles 4 bytes para incluir el segmento y el desplazamiento, 2 bytes cada uno. ej: interrupción 8(oscilador): en la dirección 8*4 y 8*4+1 esta el dsp del manejador en la dirección 8*4+2 y 8*4+3 esta el segmento Estos vectores son modificables y son los que reescribiremos con la posición (segmento:desplazamiento) en memoria de nuestro manejador, de forma que el procesador cuando reciba una interrupcion 8 en sus patas ejecutara nuestro codigo en lugar del código por defecto.Eso si, no nos olvidaremos de llamar desde nuestro manejador al antiguo para que se sigan haciendo las funciones del reloj. D)El programa se divide principalmente en 3 partes importantes: la función instalar en la que modificaremos los vectores de interrupción después de haber guardado primero la direccion antigua, el manejador que pondrá los '*' en pantalla según las especificaciones y la función desinstalar que restaura los valores de la dirección antigua en el vector de interupción. E)Para acceder al vector de interrupción más facilmente se crea un segmento denominado vecint que mediante una etiqueta apunta a este. F)Muy importante a la hora de intalar y desinstalar los vectores de interrupción desactivar las interrupciones en el momento en el que se esten cambiando los valores del vector, podría ocurrir una situación muy poco deseada si se produjera una interrupción justo en el momento en que se haya cambiado un valor y el otro no. Luego acuerdate de habilitarlas. G)En cuanto al manejador dos aspectos muy importantes, todos los segmentos que vayamos a utilizar debemos reiniciar sus registros al principio...se ejecutará en cualquier momento, pudiendose estar ejecutandose otro programa con otros registros de segmento distintos. Al final de esta función se deberá hacer una llamada al manejador antiguo, apilando antes el registro de estado, puesto que los manejadores cuando son llamados ademas de las direcciones de retorno apilan también el registro de estado automáticamente, nosotros lo haremos manualmente. Como ultima consideración, este finalizará con IRET puesto que debe desapilar tambéin el registro de estado, no os olvideis aunque os pese es un manejador en todas sus reglas. Para la creación del ejecutable se necesita el fichero Print.obj. extrn prxy:far ;** Definición de constantes ** subir EQU 48h bajar EQU 50h izda EQU 4bh dcha EQU 4dh teclafin EQU 4fh ;** Segmento Vecint ** vecint segment at 0h org 8*4 vec8 label word ;vec8 apunta a la dirección del vector viejo. vecint ends ;** Segmento de Datos ** datos segment dirint dd ? ; Variable que almacenará la dirección antigua del manejador. cursorx db 0 cursory db 0 tecla db dcha datos ends ;** Segmento de Pila ** pila segment stack db 100 dup(0) pila ends ;** Segmento de código ** codigo segment assume ds:datos, cs:codigo, ss:pila, es:vecint ;************************************************* ;* Nombre: ppal * ;* Descripción: llama al instalador del ma- * ;* nejador de interrupción y lee teclas * ;* almacenando su valor mientras sea * ;* diferente de fin. Antes de salir llama al * ;* desinstalador del manejador. * ;************************************************* ppal proc far push ds xor ax, ax push ax mov ax, vecint mov es, ax mov ax, datos mov ds, ax call instalar ; Llamada al instalador del manejador bucle: mov ah, 0 int 16h ; Interrupción para la lectura de tecla ; En ah tecla leida ; A continuación se compara la tecla ; leida con subir, bajar,izda,dcha ;si es alguna de estas se guarda en tecla cmp ah,subir je guardar cmp ah,bajar je guardar cmp ah,izda je guardar cmp ah,dcha je guardar cmp ah,teclafin ;Comparación con teclafin (Fin) si lo es je fin ;salta a fin. jmp bucle ;Si no es ninguna de las anteriores vuelve ;a bucle, para leer otra tecla. guardar: mov tecla, ah ;Almacenamos en tecla la tecla leida. jmp bucle fin: call desinst ;Llamamos al desinstalador del manejador ret ppal endp ;************************************************* ;* Nombre: instalar * ;* Descripción: instala el manejador de * ;* nuestra interrupción que queremos que * ;* se ejecute en lugar de la INT 8. Para * ;* ello variamos los vectores de interupcion * ;************************************************* instalar proc far push ax mov ax, vec8 ;Guardamos en ax el desplazamiento del vector de interrupción 8 mov word ptr dirint,ax ;Almacenamos en dirint este desplazamiento mov ax, vec8+2 ;Guardamos en ax el segmento del vector de interrupción 8 mov word ptr dirint+2, ax ;Almacenamos en dirint el segmento cli ;Desabilitamos las interrupciones ; A continuación se instala el nuevo vector ; de interrupcion que apunta a la nueva rutina. mov ax, offset manejador; Ax guarda el desplazamiento de la rutina mov vec8, ax ; Se actualiza el desplazamiento del vector con el de ax mov vec8+2, cs ; El nuevo segmento es CS sti ;Habilitamos las interrupciones pop ax ret instalar endp ;************************************************ ;* Nombre: desinst * ;* Descripción: restaura el antiguo vector * ;* de interrupción 8. * ;************************************************ desinst proc far push ax cli ;Deshabilitamos interrupciones mov ax, word ptr dirint ;Ax contiene el desplazamiento de la interrupción 8 mov vec8, ax ;Se restaura el desplazamiento con el de Ax mov ax, word ptr dirint+2 ;Ax contiene el segmento de la interrupción 8 mov vec8+2, ax ;Se restaura el segmento con el de Ax sti ;Habilitamos interrupciones pop ax ret desinst endp ;************************************************ ;* Nombre:Manejador * ;* Descripción: Rutina que según la última * ;* tecla pulsada actualiza la posición en * ;* pantalla del cursor. * ;************************************************ manejador proc far push ax ds mov ax, datos mov ds, ax ;Reiniciamos el segmento de datos puesto que no ;sabemos cuando se invocará este procedimiento. xor ah, ah mov al, tecla ; Al contiene última tecla pulsada cmp ax, subir je arriba ; Salta a arriba si es tecla subir cmp ax, bajar je abajo ;Salta a abajp si es tecla bajar cmp ax, izda je lado_i ;Salta a lado_i si es tecla izquierda cmp ax, dcha je lado_d ;Salta a lado_d si es tecla derecha jmp final ;Salta a final con cualquier otra tecla arriba: cmp cursory,0 je mas_y ;Si cursory = 0 (arriba de pantalla) saltar a mas_y dec cursory ;Decrementamos en 1 línea jmp ver mas_y: mov cursory, 24 ;Movemos cursor a última línea jmp ver abajo: cmp cursory,24 je menos_y ;Si cursory = 24 (Abajo de la pantalla) saltar a menos_y inc cursory ; Incrementamos en 1 línea jmp ver menos_y:mov cursory,0 ;Movemos el cursor a la primera línea jmp ver lado_d: cmp cursorx,80 je mas_x ;Si cursorx = 80 (Fin de Línea) saltar a mas_x inc cursorx ;Incrementamos una posición en la línea jmp ver mas_x: mov cursorx,0 ;Movemos el cursor al principio de la línea jmp ver lado_i: cmp cursorx,0 je menos_x ;Si cursorx = 0 (Principio de Línea) saltar a menos_x dec cursorx ;Decrementamos una posición en la línea jmp ver menos_x: mov cursorx,80 ;Movemos el cursor al final de la línea ver: xor ah, ah mov al, cursorx push ax ;Apilar posición en X del cursor mov al, cursory push ax ;Apilar posición en Y del cursor mov al, '*' push ax ;Apilar caracter a ecribir en la posición call prxy ;Llamada a la función ya definida pushf ;Se apila el registro de estado call dirint ;Llamada a la interrupción 8 final: pop ds ax iret ;Retorno a ppal desapilando también el registro de estado. manejador endp codigo ends end ppal |