You are on page 1of 6

Gua bsica introductoria sobre interrupciones Escrito por Nicols Rozas Salgado

Objetivo: El objetivo de esta gua es dar un pantallazo o una idea bsica sobre lo que es una interrupcin y dar algunos ejemplos bsicos sobre cmo utilizarlas. Esta gua no intenta ser una gua didctica o educativa, sino dar una pequea idea a aquellas personas que deseen saber aunque sea un poco sobre interrupciones. Advertencias: Ten cuidado antes de utilizar interrupciones! No utilices llamados a interrupciones si no tienes la seguridad sobre lo que har el llamado! Utilizar incorrectamente una interrupcin puede causar bloqueos en la PC, resultados no predecibles e incluso daos a nivel de hardware y software. Si deseas utilizar interrupciones hazlo bajo tu propio riesgo. Desarrollo: Qu es una interrupcin? Una interrupcin es una pequea subrutina que instala un programa o un sistema. Establecer una subrutina como interrupcin permite que otros programas puedan utilizarla simplemente llamndola. En una PC existen 256 interrupciones, enumeradas desde 00 a FF (255 en hexadecimal). Muchas de estas interrupciones son utilizadas por el BIOS y por DOS para brindar a las aplicaciones diversas funciones (Por ejemplo, el BIOS llama a INT 09 cada vez que se pulsa una tecla, INT 10 es utilizado por BIOS para dar a las aplicaciones que la llamen servicios de video, a INT 1C 18.2 veces por segundo e INT 21 es utilizado por DOS para brindar sus servicios como abrir archivos, utilizar carpetas, cambiar la hora, etc; INT 33 brinda todos los servicios para utilizar el ratn, entre otros). Puedo llamar a una interrupcin? Cmo utilizarla? S. Muchos de los servicios de interrupciones estn hechos para que cualquier aplicacin pueda utilizarla. Para utilizarla debemos recurrir a los registros bsicos del CPU (AX, BX, CX, DX, etc). Como manera de convencin se establece que con AX se especifica el valor de la funcin que se desea utilizar, los dems registros se usarn de acuerdo a los requerimientos de la funcin a llamar. En Pascal estos registros de CPU no pueden ser accedidos directamente excepto que se utilice lenguaje "Assembler", pero la unidad DOS incluye un tipo de variables denominada "Registers" que en conjunto con el procedimiento "Intr" permite llamar a una interrupcin con los valores de registros puesta en la variable de tipo "Registers". El tipo "Registers" corresponde a un "Record" (Registro) cuyos campos equivalen a los registros internos de la CPU mencionados anteriormente. Veamos un ejemplo muy sencillo de ello: Uses Dos; Var Regs: Registers; Begin Regs.Ax:= 1; Regs.Bx:= 4; Regs.Cx:= 3; End. Para poder utilizar una funcin debemos saber en qu interrupcin est alojada, qu valor de AX la identifica dentro de esa interrupcin y qu parmetros son utilizados (Si utiliza BX, CX, DX, etc). Hay que tener MUCHO CUIDADO con el uso de los registros y de las interrupciones pues el uso incorrecto de ellos puede causar daos, por favor utilzalo con precaucin. Tanto el valor de la interrupcin como el valor utilizado en AX se brindan en formato hexadecimal como convencin, as que cuando leas informacin de una interrupcin en particular y ves valores en AX debes comprender que estn dados en hexadecimal a menos que est indicado que est escrito en otro formato numrico.

Como forma de ejemplo utilizaremos funciones de la INT 33 (Interrupcin del ratn o "Mouse") y nombraremos algunos valores de AX que correspondern a las funciones disponibles. INT 33 AX = 1 Hace visible el puntero del ratn INT 33 AX = 2 Oculta el puntero del ratn Escribiremos dos procedimientos, uno que utilice la primera funcin y el otro que realice la segunda funcin.

{Aqu comienza el programa} Uses Dos; Procedure Ver_Cursor_Mouse; Var Regs: Registers; Begin Regs.Ax:= 1; Intr($33,Regs); {Llama a la interrupcin del ratn} End; Procedure Ocultar_Cursor_Mouse; Var Regs: Registers; Begin Regs.Ax:= 2; Intr($33,Regs); {Llama a la interrupcin del ratn} End; Begin Ver_Cursor_Mouse; ReadLn; Ocultar_Cursor_Mouse; End. {Aqu termina}

Este programa mostrar el puntero del ratn, esperar a que presiones ENTER, oculta el puntero y sale. La interrupcin del ratn tambin brinda otras opciones, como por ejemplo saber qu botones del mouse estn siendo presionados. Para ello se utiliza AX = 3, esta funcin devuelve en el registro BL el valor del botn que est presionado actualmente. Estos son los valores posibles para BL: 0 - Ninguno de los botones 1 - Botn izquierdo 2 - Botn derecho 4 - Botn del medio Los valores en BL pueden aparecer sumados, por ejemplo si BL es 6 es porque los botones derecho y del medio estn presionados al mismo tiempo (2+4). Vamos a hacer una funcin que devuelva el valor del botn presionado y basndonos en ello haremos un programa que muestre el puntero hasta que los botones iquierdo y derecho estn presionados al mismo tiempo. Vamos a utilizar el programa anterior.

{Aqu comienza el programa}

Uses Dos; Function Que_Boton: Integer; Var Regs: Registers; Begin Regs.Ax:= 3; Intr($33,Regs); {Llama a la interrupcin del ratn} Que_Boton:= Regs.Bl; {La funcin devolver el valor alojado en BL} End; Procedure Ver_Cursor_Mouse; Var Regs: Registers; Begin Regs.Ax:= 1; Intr($33,Regs); {Llama a la interrupcin del ratn} End; Procedure Ocultar_Cursor_Mouse; Var Regs: Registers; Begin Regs.Ax:= 2; Intr($33,Regs); {Llama a la interrupcin del ratn} End; Begin WriteLn('Este es un ejemplo para utilizar interrupciones con el raton.'); WriteLn('Presiona los botones izquierdo y derecho al mismo tiempo para salir.'); Ver_Cursor_Mouse; Repeat Until Que_Boton = 3; Ocultar_Cursor_Mouse; End. {Aqu termina}

La INT 33 es una interrupcin establecida por un gestor, es decir, por un programa que se instala en memoria y sirve para gestionar el ratn. Puede ocurrir que ese gestor no est instalado en el momento de la ejecucin del programa, en esos casos las funciones para utilizar el ratn no pueden ser utilizadas. Para saber si se puede utilizar los servicios de la INT 33 especifica AX = 0 y llama a la interrupcin, si AX sigue valiendo 0 despus de la llamada es porque el gestor no est instalado, si vale distinto de cero es porque se encuentra instalado y estn disponibles los servicios. Basndonos en esta informacin haremos una funcin que averigue si el servicio de INT 33 est disponible. Uses Dos; Function Hay_Mouse: Boolean; Var Regs: Registers; Begin Regs.Ax:= 0; Intr($33,Regs); If Regs.Ax <> 0 Then Hay_Mouse:= True Else Hay_Mouse:= False; End; Begin If Hay_Mouse Then WriteLn('Las funciones del raton estan disponibles.') Else WriteLn('No hay funciones del raton disponibles - El raton no esta instalado.'); End.

Utilizando llamados de interrupciones que requieren bferes:

Ya entendiendo cmo funciona bsicamente una interrupcin podemos hablar ahora de otra utilidad que tienen las interrupciones: La transmisin de datos entre una aplicacin y otra por medio de bferes de memoria. Muchas veces es necesario enviar gran cantidad de datos a una interrupcin (o tambin recibir informacin en bloque de ella) y no nos alcanza con tener solo registros de 16 bits. Por ejemplo, para escribir un mensaje por pantalla a travs de DOS o bien recibir informacin sobre el controlador de video VESA es necesario trabajar con un bfer que ser llenado por la interrupcin (En caso de recibir) o leida por ella en caso de enviar datos. Para ello se pueden utilizar dos registros de CPU que nos permiten especificar la posicin en memoria del bfer. Si en este momento te preguntas cmo se organiza la memoria de una PC, recuerda que toda PC tiene un chip de 1 MB de memoria RAM llamada "memoria base". Esta memoria es la utilizada por el BIOS y tambin por DOS (El cual la administra y almacena en ella las aplicaciones que se ejecuten). Imagina que el chip de memoria base est dividida en 65536 bloques de 16 bytes cada uno. Estos bloques se los denominan "segmentos". El BIOS se reserva muchos segmentos para uso propio, y el resto lo administra DOS con el nombre de "memoria convencional". Cuando se ejecuta un programa, el cdigo del programa es almacenado en memoria convencional y el resto es utilizado por la aplicacin misma. Pero no alcanza con saber solo el segmento que queremos usar: Tambin debemos especificar cuntos bytes nos debemos "desplazar" desde el inicio del segmento para acceder a una posicin especfica en la memoria RAM: A este "corrimiento" se lo llama "desplazamiento" o tambin "Offset". Volviendo a los registros, uno de los registros es utilizado generalmente para especificar segmentos de memoria, mientras que con un segundo registro indicamos desplazamiento que se debe realizar desde el inicio del segmento indicado en el primer registro. En la mayora de los casos se suele utilizar los pares ES y DI, o DS y DX, o ES y BP. Nota: Siempre hay que utilizar el par que la interrupcin requiera (En las referencias se dan los nombres de los registros que se utilizan para indicar bferes separndolos uno de otro a travs de dos puntos ":", como por ejemplo ES:DI, DS:DX o ES:BP) Veamos un ejemplo: Imprimir una palabra en pantalla utilizando DOS. Especificar: AH = 9 DS:DX = un puntero a un string que termine con el smbolo "$" Llamar a INT 21h. La llamada no devuelve nada en los registros. Como vimos recin, DS:DX significa que DS es utilizado como valor de segmento y DX es el desplazamiento. Supongamos que lo que queremos imprimir est almacenado en una variable de tipo "String". Pues Cmo obtener el segmento y el desplazamiento de esa variable para pasarlos a la interrupcin? En Pascal existen dos funciones, una es "Seg" y la otra es "Ofs". "Seg(x)" te devuelve el valor del segmento de la variable "x" mientras que "Ofs(x)" te devuelve el valor de desplazamiento de la variable "x". (Es importante destacar que el tipo de la variable "x" puede ser cualquiera: Un "String", un "Char", un "Integer", un "Real", etc) Sabiendo esto, veamos entonces cmo quedara implementado: Uses Dos; Var Regs: Registers;

S: String; Begin Write('Escribe la palabra a imprimir a traves de DOS: '); ReadLn(S); S:= S + '$'; {No olvidar que la llamada requiere que haya un $ al final} Regs.Ah:= 9; Regs.Ds:= Seg(S[1]); Regs.Dx:= Ofs(S[1]); Intr($21,Regs); {Llama a la interrupcin de DOS} End. Notas: 1- Fue necesario especificar S[1] pues en S[1] est la primera letra del "String", no olvidar que en Pascal se utiliza la posicin S[0] para guardar la longitud del "String". 2- Lo que hace la llamada es imprimir lo que est en un bfer especificado en DS:DX (Nuestro bfer es en este caso la variable de tipo "String") y avanza DX (y DS si es necesario) hasta encontrar un smbolo $, entonces sin imprimir ese smbolo la interrupcin finaliza. Cuando la interrupcin devuelve direcciones de memoria: Cuando la llamada a la interrupcin devuelve una direccin de memoria (en lugar de recibirla de la aplicacin que la llama, como en el ejemplo anterior) debemos modificar el puntero que tendr los datos para que apunte a esa direccin de memoria dada por la interrupcin. Veamos el siguiente ejemplo: AH = $62 Llamar a INT 21h Devuelve: BX conteniendo el segmento del proceso actual. Nota: El proceso actual se crea siempre en BX:0 (No hay desplazamiento)

Lo que hace esta llamada es devolver la direccin del PSP actual del programa (PSP significa "Prefijo de segmento del programa", es una pequea area de datos que crea DOS antes del segmento real del programa y en donde se guarda entre otras cosas el tamao del programa en memoria, el arreglo para la apertura y uso de archivos, y la linea de parmetros actual). En este caso utilizaremos el PSP para obtener la linea de parmetros utilizados en el momento de llamar al programa. DOS guarda la linea de parmetros a partir de la posicin $80 del PSP, y segn la documentacin de DOS, en la posicin $80 se guarda la longitud de la cadena y lo que sigue es la cadena en s. Esto nos da a pensar que el formato utilizado es como el formato del tipo "String" en Pascal. Pero no podemos utilizar una simple variable de tipo "String" para que apunte a la linea de parmetros del PSP, debemos hacerlo a travs de una "variable puntero de tipo String" para que se apunte en este caso a la linea de parmetros del PSP, es decir utilizando: Var S: ^String; {No es un "String" sino un puntero de tipo "String", notar el ^ al principio} A travs de la funcin "Ptr" podemos modificar la direccin de memoria adonde est apuntando el puntero para que apunte en nuestro ejemplo al rea del PSP. La funcin requiere dos parmetros, uno es el segmento y otro es el desplazamiento a asignarle (Para nuestro ejemplo el segmento ser BX y el desplazamiento es $80 adonde est la linea de parmetros). Lo que devuelve es un puntero que apunta a la direccin especificada, y lo que debemos hacer es asignarle ese valor devuelto a la

variable puntero "S". Con toda esta informacin podemos ya elaborar la aplicacin: Uses Dos; Var S: ^String; Regs: Registers; Begin Regs.Ah:= $62; Intr($21,Regs); S:= Ptr(Regs.Bx,$80); If S^ = '' Then Begin WriteLn('Debes especificar parmetros al programa.'); WriteLn('Desde Turbo Pascal ve a "Run" y luego a "Parameters", y'); WriteLn('escribe por ejemplo "Hola a todos". Luego presiona CTRL-F9 para ejecutar.'); WriteLn; WriteLn('Si lo ejecutas desde la linea de comandos y el programa'); WriteLn('se llama "prueba" escribe como ejemplo "prueba hola a todos"'); End Else WriteLn('La linea de parmetros contiene: ',S^); End. Ya que S est apuntando a la linea de parmetros, si modificas S^ estars modificando la linea de parmetros almacenada en el PSP. Por ello debes tener mucho cuidado en no modificar por accidente el PSP ni tampoco otros valores de importancia utilizados por DOS, ya que su modificacin inapropiada puede llevar a errores de asignacin de memoria y posteriores bloqueos del sistema.

You might also like