Home UC3M
Home IT
Home / Docencia / I. Telecom. / Fundamentos de los Ordenadores II

Fundamentos de los Ordenadores II

Curso 2010-2011

Práctica 3

Arquitectura de Ordenadores


Go Up
  Repaso de utilización de la pila

En un teatro hay 3 tipos de asientos: de anfiteatro, de butacas y de "gallinero". Te han encargado que hagas el presupuesto para cambiar la tapicería de todos los asientos, así que has enviado a tu ayudante para que contara los asientos de cada tipo. Tu ayudante se confundió al introducir los números, de tal forma que en el número de asientos de butacas ha puesto el número de asientos de anfiteatro, en el de asientos de anfiteatro, el de asientos de "gallinero" y en el de asientos de "gallinero", el de asientos de butacas. El plazo para entregar el presupuesto termina mañana, así que debes subsanar su error antes de calcularlo, pero no te acuerdas de más instrucciones que de push y pop, y tampoco tienes un manual a mano.

Escribe el programa asientos.s que:

  1. Cree en el segmento de datos tres posiciones de memoria, para almacenar el número de asientos de anfiteatro, de "gallinero" y de butacas, con las etiquetas correspondientes. El valor inicial de estas posiciones será 120, 80 y 60.
  2. Imprima en pantalla, llamando a la función printf() el número inicial de asientos de anfiteatro, de "gallinero" y de butacas. Para ello puedes crear en el segmento de datos una cadena de formato con el siguiente contenido: "Hay %d asientos de anfiteatro, %d de gallinero y %d de butacas\n". Tras hacer memoria has recordado cómo se utilizan las instrucciones call y add, así que las empleas en esta parte del código.
  3. Intercambie, utilizando sólo push y pop los contenidos de las variables anteriores, para subsanar el error de tu ayudante.
  4. Imprima en pantalla, de nuevo, el contenido de estas variables, para cerciorarte de que has subsanado el error de tu ayudante.
Go Up
  Saltos y comparaciones

En este ejercicio se trabajará con instrucciones de salto. En el primer apartado se utilizarán instrucciones de salto incondicional (JMP), mientras que en el segundo se utilizarán instrucciones de salto condicional.

Apartado 1: instrucción JMP

La instrucción JMP dir_destino carga el valor dir_destino en el contador de programa (registro IP), de tal forma que la siguiente instrucción que se ejecute será la ubicada en la posición de memoria indicada, dentro del segmento de código. Normalmente, destino es una etiqueta, asociada a la instrucción a la cual se pretende saltar.

  1. Escribe el programa saltos.s, que defina cuatro bloques de código, con las etiquetas a, b, c y d (en este orden). Cada uno de estos bloques debe escribir en consola el nombre de su etiqueta, mediante llamadas a la función printf.
  2. Modifica el programa anterior, sin mover los bloques de código, para que se escriba la secuencia c, b, d, a. Utiliza la instrucción JMP.

Apartado 2: instrucciones de salto condicional

Hay una gran variedad de instrucciones de salto condicional. Estas instrucciones se basan en flags del registro de estado para decidir si se realiza el salto a la dirección especificada o, por el contrario, continúa la ejecución en la instrucción siguiente.

En este apartado realizaremos el cálculo del presupuesto de tapizar los asientos de butaca del ejercicio anterior, realizando sumas sucesivas de 8 bits (sin signo) que iremos acumulando en una posición de memoria (de 8 bits) llamada resultado (que debes declarar en el segmento de datos, de tipo int, y con un valor inicial de 0). Cuando realizamos una operación aritmética el flag Z (zero) se modifica, activándose cuando el resultado es cero, para advertir de ello al programador.

  1. Añadir al programa asientos.s el código necesario para que, sabiendo el precio del tapizado de un asiento de butaca, calcule el precio de tapizar todos los asientos de butaca utilizando instrucciones de salto condicional y la instrucción ADDB (añadimos el sufijo B a la instrucción ADD para indicar que los operandos son números de 8 bits). Utiliza direccionamiento inmediato para especificar el precio. El coste de tapizar un asiento de butaca será de 3 euros. Recuerda que ya has guardado en la posición de memoria butacas el número correcto de las mismas.
  2. Cada vez que realices una suma has de mostrar en consola un mensaje en el formato de este ejemplo:
    Me faltan por contabilizar 12 butacas; resultado parcial: 36 euros
    Utiliza la cadena de formato:
    "Me faltan por contabilizar  %d butacas; resultado parcial:%d euros\n"
      
    Una vez terminado el cálculo, se debe escribir un mensaje en consola indicando el presupuesto calculado. Utiliza la cadena de formato:
    "El presupuesto es de %d euros\n"
  3. Importante: el programa debe funcionar con cualquier número de asientos de butaca. Por tanto, no se valorarán aquellas soluciones que consistan en copiar y pegar el código tantas veces como asientos de butaca haya.

Apartado 3: cambio de coste

  1. Observad qué ocurre cuando en el programa anterior se cambia el precio de las butacas de 3 a 4 euros. ¿Cuál debería ser el coste? ¿Cuál es el resultado? ¿Por qué?

Apartado 4: desbordamiento

  1. Si la suma desborda en algún momento (es decir, supera el valor 255), el resultado almacenado será incorrecto, y el flag C (carry) se activará para advertir de ello al programador. Así, al cambiar el precio de las butacas, podemos comprobar que el resultado pasa a ser incorrecto cuando se supera 255.
  2. Modifica el código para que, si se produce este hecho, el programa en vez de seguir realizando operaciones, salte a un bloque de código nuevo en el que se imprima en consola un mensaje indicando que se ha producido desbordamiento, y finalice la ejecución del programa. Utiliza la instrucción de salto condicional que consideres adecuada. En consola se deben mostrar los mensajes con el formato del siguiente ejemplo:
       Me faltan por contabilizar 18 butacas; resultado parcial:248 euros
       Me faltan por contabilizar 17 butacas; resultado parcial:252 euros
       ¡se ha producido desbordamiento!
      
Go Up
 Subrutinas

Cuando se escribe código encapsulado en subrutinas se deben seguir las siguientes pautas que se comprobarán durante la corrección:

  1. Toda rutina debe inicializar al comenzar el puntero al bloque de activación utilizando para ello el registro %ebp.
  2. Si se precisan variables locales (es decir, memoria para guardar valores temporales que no sean strings), se deben almacenar en la cima de la pila justo encima del puntero al bloque de activación.
  3. Las rutinas deben guardar aquellos registros que se modifiquen y sólo estos. No se permite utilizar las instrucciones pusha y popa que salvan y restauran todos los registros por ser más ineficientes. La única excepción a esta regla son aquellos registros que se utilicen para devolver resultados. En este caso no es preciso salvar su contenido, puesto que la rutina debe modificar su contenido con el propio resultado a devolver.
  4. La rutina printf modifica los registros %eax, %ecx y %edx por lo que todo programa que utilice esta llamada debe considerar estos registros como utilizados.
  5. A partir de ahora la rutina main debe ser tratada igual que el resto de rutinas, por lo que se debe crear el puntero al bloque de activación al igual que cualquier otra rutina.
  6. Si una rutina se invoca desde código que no está en el mismo fichero, la etiqueta de dicha rutina debe ser declarada global para permitir su invocación desde el exterior.
  7. Durante el proceso de corrección en el examen cualquier fragmento de código es susceptible de ser probado con datos diferentes a los que constan en el enunciado. Por ejemplo, si en un problema se trabaja con un array con determinados números, durante el proceso de corrección se comprobará que el programa funcione con un conjunto diferente de números. Estos cambios nunca suponen la modificación del código entregado, simplemente de los datos.
  8. Los nombres de las etiquetas que aparecen en los enunciados deben respetarse literalmente.

Apartado 1: identificación del tipo de carácter

Estas subrutinas se codificarán en el fichero compara.s. Todas han de ser globales.

La cabecera del fichero compara.s contendrá las siguientes declaraciones (y sólo estas):

.data
.text
.global isMin,min2may,comparaCarac

Escriba una subrutina llamada isMin que, recibiendo un carácter a través de la pila, devuelva, también por la pila:

  • 0 Si es una letra minúscula
  • 1 Si es una letra mayúscula
  • -1 Si es un carácter no alfabético

Cuando se llame a esta subrutina el programa llamante debe reservar espacio en la pila para el resultado, insertar en la pila el carácter a identificar y llamar a la subrutina con la instrucción call.

Apartado 2: subrutina para convertir minúsculas en mayúsculas

Escriba una subrutina llamada min2may que, recibiendo como parámetro de entrada un carácter (cualquiera), a través del registro bl, devuelva, en el byte más bajo del acumulador (al), el carácter en mayúsculas, si procede, o el mismo carácter (si no era alfabético)

Esta subrutina debe utlizar la subrutina anterior.

Apartado 3: comparación de caracteres

Se debe codificar en el fichero llamado compara.s, una subrutina global (para que pueda ser llamada desde fuera) llamada comparaCarac que compare dos caracteres almacenados en %al y %ah. El resultado lo devuelve en %ecx. El valor devuelto en %ecx será:

  • Igual a 0: los dos caracteres son iguales
  • Igual a 1: el caracter almacenado en %al está antes (alfabéticamente) que el carácter almacenado en %ah
  • Igual a -1: el caracter almacenado en %al está después (alfabéticamente) del carácter almacenado en %ah
Se considerarán las mayúsculas y las minúsculas iguales: debe hacer uso de las subrutinas anteriores.

Para probar el correcto funcionamiento, se recomienda hacer un programa de pruebas aparte, en un fichero llamado prueba.s(es en este fichero donde estará el main).

Para compilarlo:

gcc -o programa prueba.s compara.s
Go Up
 Cadenas de caracteres

Se debe codificar en el fichero llamado compara.s, una subrutina llamada comparaCadena que compare dos cadenas (considerando mayúsculas igual a minúsuculas)
Esta subrutina DEBE hacer uso de la subrutina comparaCarac (modifica esta subrutina para que no tenga en cuenta caracteres mayúsuculas y minúsculas).
Esta subrutina recibe dos parámetros, las direcciones de las cadenas a comparar, por pila y devuelve, también por pila, el siguiente resultado:

  • Igual a 0: las dos cadenas son iguales
  • Igual a 1: la cadena 1 está antes (alfabéticamente) que la cadena 2
  • Igual a -1: la cadena 1 está después (alfabéticamente) de la cadena 2
Tanto los parámetros como el resultado se pasan por pila. Una vez guardado en la pila el registro EBP al principio de la subrutina, la pila debe contener los siguientes datos:
Dirección Contenido
ESP EBP
ESP+4 @ret
ESP+8 @cadena 1
ESP+12 @cadena 2
ESP+16 espacio reservado para el resultado

La cabecera del fichero compara.s tendrá las siguientes declaraciones (y sólo estas):

.data
.text
.global isMin,min2may,comparaCarac,comparaCadena
Go Up
  Matrices

Apartado 1: Potencia de números enteros

Escribe el programa potencia.s que halle el resultado de calcular la potencia de un número entero. Para ello, programe la rutina iterativa potencia, en el fichero subPotencia.s, que recibe como parámetros dos números enteros x y n (base y exponente, respectivamente) y devuelve como resultado x^n.

Utiliza la siguiente definición de datos:

    bases:      .int 4, 3, 5, 1, 0
    exps:       .int 0, 5, 2, 20, 4
    longitud:	.int 5			# Número de datos a procesar 
    
de modo que el programa presente por pantalla:
    unix$ potencia
    4 ^ 0 = 1
    3 ^ 5 = 243
    5 ^ 2 = 25
    1 ^ 20 = 1
    0 ^ 4 = 0
    unix$
    

Importante:

  • El programa principal y la subrutina deben escribirse en ficheros distintos (potencia.s y subPotencia.s, respectivamente)
  • Tanto los parámetros como el resultado se pasan por pila. Una vez guardado en la pila el registro EBP al principio de la subrutina, la pila debe contener los siguientes datos:
    Dirección Contenido
    ESP EBP
    ESP+4 @ret
    ESP+8 base
    ESP+12 exponente
    ESP+16 espacio reservado para el resultado
  • No es necesario controlar si se produce desbordamiento.
  • El programa principal debe repetir el proceso utilizando:
    1. Direccionamiento registro indirecto
    2. Direccionamiento base + índice
    3. Direccionamiento base + índice escalado
    4. Direccionamiento desplazamiento + índice escalado
    Es decir, debe repetirse 4 veces la salida anterior, una por cada modo de direccionamiento.
  • Procura respetar el formato de salida especificado. Para separar los resultados de los distintos modos de direccionamiento, simplemente deja una línea en blanco.

Apartado 2: Impresión de una matriz por pantalla

Se dispone de un programa ensamblador que manipula una matriz de números enteros cuyas dimensiones están almacenadas en las etiquetas filas y columnas:

filas:    .int 3
columnas: .int 5

Los datos de la matriz están almacenados a partir de la posición de memoria matriz como una secuencia de enteros que representa la matriz almacenada fila tras fila. Por ejemplo, la matriz de tres filas y cinco columnas cuyos elementos son los números obtenidos al tomar los índices de fila y columna se almacena:

matriz: .int -11, 12, 13, 14, 15, 21, -22, 23, -24, 25, 31, 32, -33, -34, 35

Se pide:

  • Escribir la subrutina absoluto, que calcule el valor absoluto de un número entero. La rutina recibe como parámetro un número entero, en el registro %eax. Y devuelve como resultado su valor absoluto, también a través de %eax.
  • Escribir la subrutina imprimir, que presenta la matriz por pantalla mostrando su estructura por filas y columnas. Es decir, para el ejemplo anterior, la salida por pantalla debe ser:
    11 12 13 14 15
    21 22 23 24 25
    31 32 33 34 35
    
    Esta subrutina recibe como parámetros, por pila:
    • Dirección inicial de la matriz a imprimir (1er. parámetro, en la cima de la pila)
    • Número de filas (2o. parámetro)
    • Número de columnas (3er. parámetro)
  • Escribir el programa ensamblador que imprima la matriz inicial por pantalla, usando la rutina anterior. Sustituya cada número por su valor absoluto, con la rutina programada previamente. Y, por último, vuelva a presentar la matriz resultante.
-11 12 13 14 15
21 -22 23 -24 25
31 32 -33 -34 35
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35

El programa debe funcionar para cualquier tamaño de matriz. Se recomienda probar el programa utilizando los datos de la matriz dada y alterando el valor de las filas y columnas (siempre que su producto no sobrepase 15) y comprobar que por pantalla se imprime de forma correcta.

Go Up

Localización | Personal | Docencia | Investigación | Novedades | Intranet
inicio | mapa del web | contacta

Last Revision: