Tercera Práctica - Universidad de Las Palmas de Gran Canaria

Anuncio
Buses y Periféricos 2010/2011
Práctica 3. Ensamblador
Reloj
Descripción
El objetivo de esta práctica es utilizar las interrupciones de BIOS y MSDOS para
presentar un reloj en pantalla. Se hará uso del sistema de interrupciones del procesador
para obtener una referencia temporal basada en el reloj del sistema y además
instalaremos el programa como residente para que su funcionamiento no interfiera con
la interacción entre el usuario y el sistema de comandos.
Requerimientos
En un recuadro situado en la esquina superior derecha [según se mira] de la pantalla se
mostrará un pequeño recuadro en el interior del cual aparecerán seis dígitos
emparejados dos a dos y separados, cada pareja, por dos puntos. La pareja de más a la
izquierda mostrará la hora, la pareja central los minutos y la de más a la derecha los
segundos.
Esta imagen estará actualizándose constantemente incluso durante la ejecución de otros
programas que podremos invocar desde el sistema de comandos sin ningún
impedimento.
El programa, antes de iniciar el reloj deberá solicitar al usuario el estado inicial de los
datos horarios. Y además deberá introducirse una opción que desinstale el reloj para que
deje de mostrarse.
Procedimiento:
Para proporcionar una referencia temporal para nuestro reloj necesitaremos instalar una
función en la interrupción 1Ch. Esta interrupción la genera el sistema 18’2 veces por
segundo. Tendremos que escribir una rutina que actualice un contador cada vez que sea
disparada. Cuando este contador alcance la cuenta de 18 habrá transcurrido
aproximadamente un segundo y es el momento de actualizar el reloj.
Se invocará entonces a otra rutina que se encargará de actualizar los datos del reloj y
volver a escribir toda la información en pantalla.
1
Buses y Periféricos 2010/2011
Práctica 3. Ensamblador
El programa principal inicializará los datos del reloj – pidiendo por teclado al usuario
estos datos – e instalará la función de interrupción en sus vector correspondiente y luego
tendrá que dejar el código de estas funciones residente en memoria antes de salir de la
ejecución dejando el sistema funcionando.
El programa principal también tendrá una opción – que deberá preguntar al usuario
[excelencia: o bien leer como parámetro de la línea de comandos] – para desinstalar la
función, para lo cual deberá restaurar el contenido del vector de interrupción a su valor
original.
Documentación:
Instalar una función en un vector de interrupción implica guardar en la posición del
vector correspondiente la dirección de la rutina. La dirección de una rutina (y de hecho
cualquier dirección de memoria) viene especificada con un formato segmentado:
segmento:desplazamiento. Cada campo tiene 16 bits. El segmento (x16) indica el
comienzo de una zona en memoria y el desplazamiento indica cuantos bytes hay que
desplazarse a partir de esa dirección. Dada la dirección simbólica de la rutina (nombre)
el segmento se obtiene con la directiva SEG aplicada al nombre de la rutina y el
desplazamiento con la directiva OFFSET aplicada al nombre de la rutina.
Obtenidos estos datos hay que instalarlos en el vector correspondiente. Para facilitarlo
hay una llamada al sistema operativo que lo hace:
(buscar en internet int 21h, ejemplo:
http://www.esimez.ipn.mx/computacionv/Hojas/INT%2021H%20Y%2010%20H.pdf)
La función en concreto es la 25h. En los parámetros se suministra el segmento en el
registro DS y el desplazamiento en DX. El vector de interrupción donde cargarlo debe ir
en AL.
Antes de instalar la nueva función en el vector debemos prever que ese vector se esté
utilizando previamente por otra aplicación por lo que convendría recuperar la dirección
que hubiera ya instalada, la localizáramos en memoria y saltáramos a ella después de
haber realizado nuestras acciones. Para recuperar la dirección que hubiere previamente
en el vector de interrupción se utiliza la función 35h.
La parte del programa que actualiza los datos del reloj necesitará escribir en pantalla en
una localización concreta. Para ello utilizaremos interrupciones de la BIOS (int 10h)
(http://www.uv.tietgen.dk/staff/mlha/PC/Prog/ASM/INT/INT10.htm).
2
En
concreto,
Buses y Periféricos 2010/2011
Práctica 3. Ensamblador
tendremos que posicionar el cursor con la función 02h, recordar siempre inicializar el
registro BH a la página 0, en DH y DL colocaremos el número de fila y columna donde
localizaremos el cursor. Trabajaremos con una pantalla de 80 columnas por 25 filas.
La ejecución de la rutina de interrupción no debe interferir con el programa que se esté
ejecutando actualmente por lo que antes de cambiar el cursor de su posición actual a la
de nuestra aplicación, tendremos que guardar esa posición para restaurarla luego, antes
de salir de la interrupción. Para leer la posición del cursor usaremos la función 03h y
para escribir en la posición actual de cursor un carácter usaremos la función 0Ah. (Sería
bonito que el reloj apareciera en colorines)
El programa principal tiene que solicitar datos de teclado y para ello tendrá que
imprimir un texto de pantalla, volvemos a usar aquí las funciones de DOS, int 21h, con
la función 09h para imprimir un texto y la función 08h.
Por último el programa principal debe dejar el código y los datos de la rutina de
interrupción residente en memoria, de manera que al salir esa zona quede protegida por
el sistema operativo (necesario puesto que cada vez que se dispare la interrupción se irá
a buscar allí el código a ejecutar) De ello hablamos en la siguiente sección.
Siguiente Sección: programas residentes
Cuando ejecutamos un programa el sistema operativo carga su código ejecutable en una
zona de memoria e inicia su ejecución. Cuando esta termina debe invocar un retorno al
sistema operativo para que este retome el control del sistema. Hay varias maneras de
hacerlo, una es invocando a la función 4Ch (int 21h). Para nuestros propósitos nosotros
buscaremos una manera más complicada.
En la zona de memoria en la que se instala nuestro programa, precediendo a los datos y
el código ejecutable hay 100h bytes de información de control. Los primeros dos bytes
son en realidad una instrucción que retorna el control al sistema operativo (int 20h).
Para poder ejecutar esa instrucción tendríamos que conseguir hacer un saldo hacia ella
como última acción de nuestro código. Lo haremos colocando un RETF. Un retf es un
retorno de rutina (llamado largo), que lee de la pila el desplazamiento y segmento de la
dirección hacia la que tiene que retornar. Como primera acción de nuestro programa
debemos instalar en la pila esos datos. El segmento se encuentra en el registro DS y el
desplazamiento
es
simplemente
un
3
0
por
lo
tanto
Buses y Periféricos 2010/2011
Práctica 3. Ensamblador
las primeras instrucciones que debe
y la última
ejecutar nuestro programa son
retf
esto debería funcionar.
push ds
mov ax,0
push ax
Ahora bien, si queremos dejar nuestro programa residente en lugar de salir con int 20h
debemos hacerlos con int 27h, CS debe estar apuntando al comienzo de la sección de
datos de control (llamada PSP) y DX debe contener el número de bytes que deseamos
dejar residentes a partir del comienzo de segmento (incluyendo la sección de 100h datos
de control). El procedimiento será cambiar el segundo byte de la sección de control, que
contiene un 20h, por un 27h. Colocar un puntero al final de la sección de código que
queremos dejar residente y antes de ejecutar el retf cargarlo en el registro dx.
Desinstalación y liberación de memoria.
Por “desinstalar” el reloj se quiere decir que éste debe dejar de funcionar y desaparecer
de pantalla. Para que deje de funcionar basta con quitar la dirección del programa que lo
mantiene activo de la interrupción 1Ch. Con esto deja de dispararse el programa y
dejará de refrescarse la imagen del reloj en pantalla. Es importante dejar en la
interrupción 1Ch la dirección del programa que había antes (en realidad un salto a una
localización donde hay una instrucción IRET, si nadie más ha manipulado la
interrupción)
Aunque ya se ha “desinstalado”, la zona de memoria reservada sigue estando reservada
y habría que decirle al sistema operativo que la libere. Para ellos convendría invocar a la
función 49h de la Int 21h facilitándole el segmento de la zona PSP de la sección de
memoria a liberar. Esta información es la que hemos guardado al principio del programa
(que originalmente estaba en DS al inicio de la ejecución) así que tendríamos que
almacenarla en alguna parte accesible luego para poder disponer de ella.
Una ultima cosa: Nuestro programa va a constar en esta ocasión de un único
segmento de código, no crearemos un segmento de datos ni tampoco un segmento de
pila. Los datos los localizaremos dentro del segmento de código, preferiblemente antes
del código ejecutable, confiaremos al sistema la inicialización del segmento de pila.
4
Buses y Periféricos 2010/2011
Práctica 3. Ensamblador
Evaluación
Niveles de dificultad
1. El reloj queda instalado y residente (mínimo requerido)
2. Se añade una opción de desinstalar y deja de funcionar cuando se invoca con
ella.
3. Se utiliza la línea de comandos para pasarle parámetros al programa
4. Se comprueba antes de desinstalar que lo que hay colgado de la interrupción es
nuestra rutina.
5. Tras desinstalar se libera memoria.
6. Es posible instalar varias copias del reloj y que todas se mantengan en
funcionamiento (encadenamiento de interrupciones)
El alumno debe realizar el programa siguiendo las indicaciones, pero aportando su
propia iniciativa. Se exige que el programa cumpla los requisitos, pero se admiten
variantes del procedimiento siempre que sirvan para aportar conocimientos y no para
evitar la adquisición de estos. Se valorará un programa bien diseñado, ordenado en
términos de uso de procedimientos, macros, comentarios. Cada instrucción empleada
en el programa debe estar justificada, el alumno debe ser capaz de explicar en la
defensa el porqué y el para qué de cada línea de código.
La memoria justificativa del trabajo no es un simple comentario de las instrucciones,
sino un informe explicando funcionalmente el programa realizado, las dificultades, los
defectos, las posibles variantes y mejoras.
Bibliografía.
Se encuentran en Internet multitud de páginas que describen cada una de las
interrupciones BIOS y MSDOS. Así como tutoriales de introducción al ensamblador.
Rodríguez Rosello, Miguel Angel
8088-8086/8087 : programación ensamblador en entorno MS DOS / Miguel Angel Rodríguez-Roselló
Norton, Peter
Guía del programador en ensamblador para IBM PC, XT, AT y compatibles / Peter Norton, John Socha ;
[traducción, José Félix Rábago]
[1ª ed.]
Padrón Morales, Gabino
Guía de programación en lenguaje ensamblador
Las Palmas de Gran Canaria : Universidad de Las Palmas de Gran Canaria, Escuela Universitaria de
Informática, 1994
5
Descargar