(Este enunciado será explicado en la primera clase que corresponda a cada grupo)
Funcionamiento
La prueba consiste en la realización de una serie de procedimientos en ENSAMBLADOR que van a ser llamados desde unos programas en C que se proporcionan. Para que los diferentes ejercicios se puedan realizar de forma independiente (sin necesidad de haber hecho otro), se proporciona una librería donde ya están hechos. Según se realicen los distintos procedimientos por parte del alumno deben ser sustituidos los que se proporcionan en la librería por los realizados por el alumno.
Los
ejercicios consisten en la creación de una serie de procedimientos que una vez
realizados deberán sustituir a los existentes en la librería pra1.lib
compilada en modelo LARGE. Se proporciona también un fuente en C, pra1.c
. Este código realiza las pruebas de los procedimientos comprobando la devolución
de errores, creando un fichero denominado log.txt con los errores no
detectados o mal calculados. Si este fichero está vacío es que se controlan
todos los errores.
Se
recomienda no usar el entorno del TurboC sino compilar los fuentes en C y
enlazar con el comando tcc. Las compilaciones en ensamblador se
realizarán con el comando tasm y para meter y sacar módulos de
la librería el comando tlib. Cualquiera de estos comandos,
ejecutados sin parámetros, indican cómo deben ser usados. Las depuraciones
podrán realizarse con el TurboDebugger (td) si se utilizan las
banderas de compilación adecuadas. Es importante recordar el uso de las
banderas -ml en C y /mx en ensamblador así como la
declaración PUBLIC de los procedimientos en ensamblador.
Para
facilitar el desarrollo se incluye un ejemplo de un procedimiento escrito en
ensamblador, paleta.asm.
La
definición detallada de todos los procedimientos que hay que diseñar, de sus
parámetros y sus valores de retorno se encuentra en pra1.h.
Se incluye un fichero ejecutable que muestra el uso de todos los procedimientos
y el resultado que se debe obtener tras cambiar todos los objetos de la
librería entregada por los de los alumnos. pra1.exe
Los ficheros prac1.c y pra1.h NO SE DEBEN MODIFICAR.
Un ejemplo de la secuencia de comandos a ejecutar para añadir el código de paleta.asm (suponer pareja 7 del turno 3a *) sería:
tasm /mx 3a07p1pp.asm Se ensambla el fuente y se crea el objeto, 3a07p1.obj, siempre que no haya errores.
tlib pra1.lib -paleta +3a07p1pp Se extrae el objeto original PALETA y se incluye el nuevo
tcc -ml pra1.c pra1.lib Se crea el ejecutable pra1.exe. Se ejecuta y si no funciona se pasa a la depuración. Para ello es necesario hacer el proceso anterior con las banderas correspondientes
En
el anexo se muestra información sobre cómo acceder a la descripción de los
caracteres y sobre el modo de pantalla MCGA.
Un resumen de los procedimientos que se tienen que diseñar en ensamblador es:
Nombre del Procedimiento | Fichero Fuente * | Nombre del objeto en la librería ** | Comentarios |
void modo_mcga() | xxxxxxmc.asm | M_MCGA | Para poner el modo se utilizará la interrupción 10h con AH=0 y AL=13h para el modo MCGA y AL=3h para el modo normal o texto |
void modo_normal() | xxxxxxmn.asm | M_NORMAL | |
int Pixel (int x, int y, int color) | xxxxxxpi.asm | PIXEL | Debe ponerse el pixel accediendo directamente a la memoria y sin usar interrupciones |
int Recta (int xi, int yi, int xf, int yf, int indice_color) | xxxxxxre.asm | RECTA | Algoritmo para pintar la recta: Recta.pdf |
xxxxxxpp.asm | PALETA | ||
int Caracter (int Caracter, int x, int y, int color) | xxxxxxca.asm | CARACTER | Para poner los distintos pixels del carácter es necesario llamar al procedimiento Pixel. Se aconseja utilizar las instrucciones lógicas de rotación o desplazamiento de bits |
int Texto (P_MIBYTE texto, int x, int y, int indice_color) |
xxxxxxte.asm | TEXTO | |
int ComparaMemoria (P_MIBYTE memoria_uno, P_MIBYTE memoria_dos, int longitud) | xxxxxxcm.asm | COMPMEM | Deben utilizarse, obligatoriamente las instrucciones de cadena en ensamblador. Los procedimientos devolverán los valores IGUAL o DISTINTO definidos en pract1.h |
int ComparaTexto(P_MIBYTE texto_uno, P_MIBYTE texto_dos) | xxxxxxct.asm | COMPCAD | |
P_MIBYTE CopiaMemoria(P_MIBYTE memoria_fuente, P_MIBYTE memoria_destino, int longitud) |
xxxxxxc2.asm | COPIAMEM | |
P_MIBYTE CopiaTexto(P_MIBYTE texto_fuente, P_MIBYTE texto_destino) |
xxxxxxc3.asm | COPIATXT | |
int LongitudTexto(P_MIBYTE texto) | xxxxxxlt.asm | LONGTXT |
* Sustituir las xxxxxx por el nombre correspondiente a cada pareja según está descrito en las normas, es decir, grupo_pareja_práctica_orden.asm. Por ejemplo, 3a07p1pi.asm sería el nombre para el procedimiento Pixel de la práctica 1 de la pareja 7 del turno 3a (jueves mañana)
** Para obtener el nombre de los objetos basta con ejecutar tlib pra1.lib, pra1.lst. Con esto se crea un fichero de texto, pra1.lst donde figura el nombre del objeto y el de los procedimientos declarados como públicos
Se puede hacer una primera versión de los procedimientos que no incluyan el control de errores y añadírselo una vez que funcione, aunque en general ese control permitirá poder depurar de una manera más sencilla.
Para
inicializar el modo de vídeo MCGA (320x200x256) se utiliza una llamada a la
interrupción 10h. Ahora hemos de comprender como gestiona el ordenador esos
pixels que escribimos en pantalla.
La dirección
A000:0000 es el principio del segmento de VideoRAM, es decir, es donde la MCGA
guarda los datos de las imágenes gráficas que dibuja en el monitor. Si
escribimos algún valor en este segmento, la próxima vez que la tarjeta gráfica
redibuje la pantalla (lo hace entre 50 y 70 veces por segundo) el valor que
hemos escrito aparecerá en pantalla en forma de punto.
Para
pintar un pixel basta con escribir en la posición de memoria correspondiente,
el índice de color que queremos para que la tarjeta gráfica lo represente
durante el próximo retrazado. El modo MCGA es el modo gráfico más sencillo en
este sentido pues es un modo de 8 bits por pixel.
Esto quiere decir
que cada número del 0 al 255 se corresponde con un color. Por defecto, el 0 es
el negro, el 1 el azul, y así hasta llegar al 255. Entre el 0 y el 255
disponemos de gamas de azules, verdes, amarillos, etc..., que componen la paleta
por defecto de la MCGA.
Que este modo gráfico sea de un byte por pixel significa que al escribir un byte en este segmento de memoria, su equivalente en pantalla será un pixel, que aparecerá automáticamente en cuanto el haz de electrones pase por esa posición al refrescar la imagen. En la figura adjunta tenemos una representación de cómo está organizada la VideoRAM en el modo 13h (MCGA).
Como puede verse, al
byte 0 le corresponde el pixel (0,0) (el primero de la pantalla); al byte 1 le
corresponde el pixel (1,0), al byte número 320 le correspondería el pixel
(0,1), (primer pixel de la línea 1, porque hay 320 pixels de resolución
horizontal) y así hasta el byte 63.999 del segmento, que corresponde a la
posición (319,199). Depende del offset en que coloquemos el byte, el punto
aparecerá en distinta posición en el monitor (cada byte es un pixel individual
en la pantalla).
El segmento de la
VideoRAM se comporta en este modo de video como si fuera una larga línea de
pixels de manera que al llegar al final de una línea horizontal de pantalla, el
siguiente byte de la VideoMemoria es el que continúa en la siguiente línea de
pantalla. De ahí el término direccionamiento lineal: es como si la pantalla
fuera un array unidimensional desde 0 a 64.000 donde cada 320 bytes estamos
situados en una nueva línea de pantalla (el byte 320 es el primer pixel de la
segunda línea). Así, durante el retrazado la tarjeta únicamente tiene que
dedicarse a leer bytes (todos ellos consecutivos) y representarlos en pantalla.
Algunos links sobre el modo MCGA
Modos gráficos. El Universo Digital
La idea se basa en
explorar la tabla de caracteres empleada internamente por el ordenador. Esta
tabla se encuentra en la memoria ROM, a partir de la dirección F000:FA6E. La
forma de cada carácter está descrita por 8 bytes, cada uno de los cuales
representa una fila, según se muestra a continuación:
Carácter |
............ |
Representación
en ROM
0011 1110 = 3EH |
|||||||||
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
||||
. |
|
|
|
|
|
|
|
||||
|
La
figura representa el número '0', el conjunto de 8 bytes forma una retícula de
64 bits. Los bits que están a '1' definen el contorno del carácter, es decir,
los puntos que habrá que iluminar en una pantalla para conseguir una
representación del carácter.
La
tabla de todos los caracteres del 0 al 127 está ordenada según el código
ASCII. Por tanto, para acceder a un carácter concreto habrá que sumar a la
posición inicial (F0000:FA6EH) un desplazamiento que será igual al número
ASCII del carácter multiplicado por 8, puesto que, como ya sabemos, cada carácter
está representado mediante 8 bytes consecutivos.
Una vez que se
conoce la dirección donde está almacenada la representación del carácter que
se quiere imprimir, se toman los datos byte a byte (fila a fila) y se va
examinando cada uno de los bits individuales. Si el bit correspondiente es '0',
el procedimiento escribirá un espacio en la pantalla, mientras que si el bit
examinado es un '1', se escribirá un carácter grueso (
). Al
terminar de escribir una fila habrá que colocar el cursor en la posición
correspondiente a la primera columna de la siguiente fila, y volver a repetir la
operación hasta terminar de explorar las 8 filas.
Plazo de entrega : La presentación y evaluación de esta práctica será la indicada en el calendario, según el grupo (ver calendario ).