domingo, 28 de abril de 2013

ALU y Camino de datos


Este tema está dedicado al funcionamiento y diseño de la Unidad Aritmético Lógica y de los componentes necesarios que permiten a la misma funcionar correctamente. La ALU es un elemento fundamental de los computadores actuales, se integra dentro de la CPU y necesita de dos elementos fundamentales para poder operar, registros y buses. Los objetivos que se buscaban con la realización de la práctica eran aprender de forma básica como opera este elemento, aprender a manejarnos en el software de simulación (Logisim) y realizar ciertas operaciones básicas para comprender cómo se comporta el ordenador con cada instrucción.


Como ya sabemos, la ALU es un circuito digital que se encarga de realizar operaciones aritméticas (como una suma o una división) y lógicas (como una conjunción ―AND― o una disyunción ―OR―). La ALU que hemos diseñado es muy simple. Contiene cuatro operadores (suma, negador, desplazamiento y conjunción) y se apoya en un bus compartido y cuatro registros auxiliares (tres de uso general y un cuarto para almacenar uno de los operandos), además de un banco de registros (también con cuatro).


La práctica comenzó realizando ejercicios básicos, como un circuito decodificador de 2 bits en binario, la implementación de un bus compartido bidireccional de 8 bits (con un display) y registros con control de triestado, tal y como se puede ver en las capturas.








El siguiente problema consistía en crear un banco de registros. Para que la tarea no fuera demasiado tediosa, el banco propuesto tendría únicamente cuatro registros. Como iba a implantarse en un bus compartido, debía disponer de señales de control de triestado, además del selector del registro con el que se quería operar y la señal de carga, unido a la entrada y salida de datos.



Al crear el decodificador que selecciona los buffers triestados teníamos un problema, y es que nuestro circuito mostraba error cada vez que la entrada de habilitación del decodificador (TB) estaba desconectada. El problema se solucionó porque detectamos que se trataba de un error de conexión, ocurría lo mismo que ocurre cuando se te olvida conectar algún pin. Investigando en las referencias de las librerías de Logisim (menu de Ayuda) averiguamos que el atributo "Disabled Output" estaba incorrectamente seleccionado. Tiene dos posibles valores, "Floating", que hace como si cada linea quedara desconectada del resto de elementos, y "Zero" que introduce un 0 lógico constante mientras la entrada de habilitación del decodificador está desactivada. Debimos seleccionar "Zero" para que empezara a funcionar correctamente.

Para que a la hora de conectar todos estos circuitos fuera sencillo y simple identificarlos, usamos la herramienta de creación de bloques (subcircuitos) de Logisim. No fue difícil entender su funcionamiento y el gran potencial de esta característica. La apariencia del banco quedó como se puede ver en la imágen siguiente.



Otra de las cosas que nos supuso más problema a la hora de crear el banco es que Logisim no permite crear un pin que sea a la vez de entrada y de salida, por lo que tuvimos que crear un hilo de entrada (izquierda) distinto al de salida (derecha). Esto no significó mucho esfuerzo, lo que nos llevó más tiempo fue determinar por qué nuestro banco no funcionaba correctamente cuando usábamos el bloque antes de separar la entrada y la salida.

La última implementación fue la de la ALU. El circuito debía contar con cuatro operadores (suma, negación, conjunción y desplazamiento). Cada una de estas operaciones debían estar integradas, tomando y devolviendo los datos por unos mismos hilos. Para ello, todas las entradas se conectan a cada uno de los operadores, y la salida se selecciona mediante un multiplexor cuyo selector será de 2 bits para poder seleccionar nuestras cuatro operaciones. Así, el selector 00 identifica la suma, el 01 identifica la conjunción, el 10 hace referencia a la negación y el 11 selecciona el desplazamiento. Nuestro circuito quedó como se puede ver en la imagen de abajo.



Siguiendo el mismo procedimiento que con el banco, nos dispusimos a diseñar el bloque que representaría la ALU, y que nos permitiría aunar todos los circuitos de manera clara.


Así, con todos los componentes ya implementados, nos dispusimos a conectar el camino de datos y todos nuestros componentes, creando un circuito capaz de realizar operaciones, es decir, una Unidad Aritmético Lógica totalmente funcional.


Para que se note la diferencia de claridad que se obtiene al usar el diagrama de bloques (subcircuitos), hemos realizado el mismo circuito sin usar dicha herramienta, quedando como se puede ver abajo.



Lo último que nos quedaba por hacer era comprobar su funcionamiento. Para ello, realizamos ciertas operaciones y comprobamos que el resultado era el esperado.

  1. Cargar en el registro R0 el dato 0x1F
  2. Cargar en el registro R1 el dato 0x21
  3. Cargar en el registro R2 el dato 0x4A
  4. Cargar en el registro R3 el dato 0x35
  5. Sumar R1 y R2 y almacenarlo en Raux0
  6. Hacer la operación AND entre R0 y R3 y almacenarlos en Raux1
  7. Desplazar dos veces en registro R1 y almacenarlo en el registro Raux2
  8. Llevar R2 al acumulador y complementar su valor. El resultado almacenarlo en R0
De los tres últimos, hemos realizado el cronograma tal y como nos indicaba el guión de prácticas.


CLCK
BUS 0x1f 0x35 0x15 0x21 0x90 0x48 0x35 0xca
SB 00 11 01 11 00
CB
TRB
CRaux0
TRaux0
CRaux1
TRaux1
CRaux2
TRaux2
CA
OP 01 11 11 10
CTmp
TTmp
A 0x1f 0x21 0x90 0x35
R0 0x1f 0xca
R1 0x21
R2 0x4a
R3 0x35
Raux0
Raux1 0x15
Raux2 0x48
RTmp 0x15 0x90 0x48 0xca

Comentarios sobre la práctica.
  • Se trata de una práctica no muy compleja pero que ayuda enormemente a comprender el funcionamiento de la ALU y el camino de datos.
  • Es muy sencillo aprender a usar Logisim, sin embargo, hubiera sido de gran ayuda que se nos hubiera explicado la forma de trabajar con bloques diseñados (subcircuitos), ya que es una herramienta muy potente del programa que permite integrar un circuito en un único elemento, añadiendo claridad al circuito principal y mejorando mucho la visibilidad.
  • Algunas características a tener en cuenta (como la propiedad "Disabled Output" del decodificador del banco) deberían indicarse de forma que el alumno supiera cual era el error y como solucionarlo, sin tener que gastar tiempo de la práctica en investigar qué ocurre.
  • Deberían haberse sincronizado mejor la prueba presencial con esta práctica, ya que realizar los últimos ejercicios es muy útil para comprender correctamente el funcionamiento y ver los errores más comunes que se suelen cometer al realizar el cronograma, ya que puedes interactuar con el simulador para comprobar que lo que has hecho funciona como debe.
Preguntas frecuentes.
  • ¿Cómo añado texto a cada elemento para identificar lo que es?
    La mayoría de los componentes de Logisim tienen un atributo llamado "Etiqueta". Si lo seleccionas, podrás ver esta casilla en la barra lateral. El texto que escribas ahí se verá reflejado al lado del componente. También puedes modificar su posición con el desplegable llamado "Posición de la Etiqueta". Si tu componente no tiene dicho atributo, siempre puedes recurrir a la herramienta "Texto" de la barra superior.
  • ¿Por qué me aparecen líneas naranjas al conectar diferentes componentes?
    Probablemente los anchos de cada componente y del bus que los une sean distintos. Recuerda que si tus componentes tienen de ancho, por ejemplo, 8 bits, tu bus también debe tener el mismo ancho. Puedes modificar este atributo en la barra lateral que aparece al seleccionar dicho componente.
  • ¿Por qué mis líneas se vuelven rojas cuando activo ciertos componentes?
    Si estas ante un bus compartido, el problema más común es que ya haya algún dispositivo que esté usándolo. Recuerda que debes trabajar con buffers triestado en este tipo de bus, por lo que puedes comprobar si ya tienes alguno de ellos activo.
  • ¿Cómo uso la herramienta de diseño de subcircuitos?
    Esta herramienta es muy fácil de usar. Una vez que hayas finalizado la implementación del circuito, haz clic en el botón identificado como "Edit viewed circuit's subcircuit appearance". Te aparecerá un diseño preeliminar con los distintos pines que has usado. Si pulsas en cada pin, te aparecerá una miniatura donde puedes ver con cual se corresponde. Con las herramientas de dibujo de la barra superior puedes crear tu componente. Lo único que tendrás que hacer después será colocar todos los pines encima de tu diseño e identificarlos correctamente.
  • Ya tengo el diseño, ¿cómo los conecto en un solo circuito?
    Tienes que crear un nuevo circuito. Para ello, pulsa en el botón "Añadir circuito". Una vez que lo tengas, simplemente selecciona el circuito anterior y arrástralo hasta el área de trabajo como si de otro componente se tratase. También puedes cambiar su orientación el barra de atributos.
  • ¿Cómo puedo crear un pin de entrada/salida en mi diseño?
    Logisim no permite esta opción. Estás obligado a crear dos pines,  uno de entrada y otro de salida, aunque luego puedes unirlos externamente.
  • Tengo un problema al crear el banco de registros. El decodificador que acciona los triestados no actúa correctamente y mi circuito muestra un error.
    Tienes que cambiar un atributo del decodificador que selecciona los buffers triestado. "Disabled Output" debe valer "Zero" (por defecto "Floating"). Este atributo especifica lo que debe valer cada pin del decodificador cuando éste está desactivado. "Floating" se interpreta como la desconexión de las salidas, como si el cable no estuviera conectado. Cuando seleccionamos "Zero", cada salida actuará como si tuviera un 0 lógico constante conectado a ella.


Realizado por Manuel Francisco y Javier Béjar.

viernes, 19 de abril de 2013

Ensamblador

Introducción
Este tema de la asignatura está dedicado a ensamblador, un lenguaje de bajo nivel, y más concretamente, al ensamblador del MIPS (R2000/R3000). Se trata de un lenguaje con pocas instrucciones, fácil de aprender (con ciertos conocimientos previos) y muy polivalente, ya que es una arquitectura bastante usada. El objetivo de las prácticas de este tema era conocer un poco las bases del lenguaje, y aprender a realizar pequeños algoritmos con un fin muy concreto. Como conclusión, podemos asegurar que es un tema bastante interesante para tratar incluso más a fondo, ya que ayuda a comprender de cierta forma cómo funcionan los computadores y lo que ocurre cuando programamos en lenguajes de más alto nivel.

Una vez introducida la práctica, comenzémos con la presentación de su transcurso:

Día 1, práctica 1:
Tras los primeros pasos con MARS, y tras familiarizarnos con su entorno, procedemos a la modificación de un programa que realiza la sucesión de fibonacci.
Dicha modificación  consiste en que la sucesión se realice con los tres números anteriores, en lugar de con los dos.



Esta actividad, apenas resultó difícil, gracias a nuestros conocimientos previos de programación y a la previa familiarización previa con MARS y el lenguaje ensamblador MIPS.

Día 2, práctica 1:
En este día, nos dispusimos a la realización de la relación de ejercicios, los problemas: 1,2,3,4,5, que se detallarán a continuación:

Nos dieron el código puesto anteriormente para realizar cambios sobre el, en los proximos cuatro problemas,  y familiarizarnos mas aun con este lenguaje.

En este 1er problema, teníamos que realizar un cambio para cargar los valores de array media, en lugar de array_byte.
El 2º problema, es prácticamente igual que el anterior, sustituimos array_byte por array_palabra. Lo que tuvimos que cambiar en el problema 1 y en el 2 fueron los bits de desplazamiento a la hora de manejar los elementos del array.
El problema 3, trata de escribir los elementos impares del array tratado (array_media).

El problema 4, es muy parecido al anterior, pero en lugar de mostrar los elementos impares, mostramos los elementos pares del array tratado (array_palabra), separados por una coma.
En el problema 5, ya no teníamos que modificar código, por primera vez, escribíamos un programa por nosotros mismos, sin un guión ya establecido en cuanto a código se refiere.
Este programa, realiza la suma de dos valores almacenados en memoria,y el resultado lo guardamos en un espacio de memoria reservado anteriormente.

Día 3, práctica 1:

En esta práctica, se procede a la realización de los ejercicios 6-11, que a continuación describimos.
Para el ejercicio numero 6 necesitamos de un código previo sobre el cual trabajaremos:


La modificación consiste en almacenar el resultado de la suma de los elementos del array  en una variable denominada "SUMA". En dicha modificación nos dimos cuenta de que la instrucción de la línea 14 del código que ya estaba escrito y que debíamos usar como modelo, contenía un error, y tuvimos que cambiarla para que el funcionamiento del programa fuera correcto.
En el problema numero 7, sólo tenemos que realizar la asignación en memoria de un array.



En el ejercicio a resolver número 8, se realiza la copia del array numero 1, al array numero 2, realizando un desplazamiento de dos posiciones de memoria. 

 El ejercicio número 9, es uno de los que su realización ha conllevado mayor esfuerzo. Dicho programa, muestra el número mayor encontrado dentro de un array ya definido, así como la posición en la cual se encuentra.
En el problema 10, diseñamos un código que pedía al usuario la introducción de dos valores por teclado, para posteriormente realizar su suma, y mostrar el resultado por pantalla.

El ejercicio 11 consiste en la realización de un bucle, que muestre por pantalla el valor de un array almacenado en memoria.

Comentarios sobre la practica:
-La práctica nos ha resultado interesante puesto que nos ha ayudado a comprender el funcionamiento de la maquina a un nivel que desconocíamos  aunque nos hayamos encontrado alguna dificultad que pudimos resolver al poco tiempo.
-También volver a comentar la errata del código previamente dado al problema 6 en la línea 14, cambiamos la instrucción "ble" por "blt" ya que el índice del array comienza en '0'.
-Podrían haber sido dichas practicas mas llevaderas realizándose de manera mas interactiva.

FAQ's:
¿Qué es MARS?
-Es un entorno interactivo de desarrollo ligero (IDE), especialmente diseñado para el lenguaje ensamblador MIPS.

¿Qué instrucción de salto incondicional debo usar para recorrer el vector?
-Depende de tu código. La instrucción blt significa branch if less than, por lo que se usará como el operador estrictamente menor. La instrucción ble significa branch if less or equal than, por lo que se usará como el operador menor o igual. Al iterar una matriz o vector, como el índice empieza en 0, usaremos (en condiciones normales) la instrucción de salto condicional blt.

Mi programa no se ensambla con los últimos cambios, ¿a que se debe?
-Probablemente, no hayas guardado la ultima modificación antes de ensamblarlo.

Quiero ver que ha ocurrido hasta un punto del programa ya diseñado, ¿cómo se hace?
En la parte izquierda de la ventana "Execute", aparecerán unos checkboxs bajo el nombre de "bkpt", esto quiere decir, "Break points", o lo que es lo mismo, puntos de interrupción.
Marcando esas casillas, conseguirás detener la ejecución del programa cuando llegue a dicha instrucción.

¿Cómo puedo seguir la ejecución de mi programa paso a paso en MARS?
Puedes seguir la ejecución paso a paso, incluso controlar la velocidad de ejecución  en la barra superior derecha del programa.


Realizado por: 
-Francisco Alejandro Naranjo Castañeda
-Eduardo García Ruiz