<-Informática\ensamblador 80x86...
Ejemplo 2
Para la creación del ejecutable se necesita el fichero Print.obj.
¿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. 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