Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
4.1 Introducción
Diseñaremos una implementación que incluya un subconjunto con las instrucciones mas
importantes:
No se incluye al repertorio completo por que la idea principal consiste en conocer los
principios aplicados en la creación de un camino de datos y el diseño del control. La
implementación de las demás instrucciones puede hacerse en forma similar.
Un vistazo de la implementación
1. Enviar el contador del programa (PC) a la memoria que contiene el código y atrapar
la instrucción desde esa memoria.
2. Leer uno o dos registros, usando los campos de la instrucción para seleccionar los
registros a leer. Para la instrucción de carga solo se requiere la lectura de un
registro, pero para las demás instrucciones es necesaria la lectura de dos de ellos.
Después de estos dos pasos, las acciones requeridas para completar la instrucción dependen
de la clase de instrucción. Sin embargo, a pesar de ser instrucciones diferentes, en el paso
siguiente las tres instrucciones utilizan la unidad aritmético lógica (ALU). Las instrucciones
de referencia a memoria usan la ALU para el cálculo de una dirección; las instrucciones
aritmético lógicas para la ejecución de la operación y los brincos para la comparación.
Como se puede ver, la simplicidad y regularidad del repertorio de instrucciones simplifica
la implementación haciendo la ejecución similar en diferentes clases de instrucciones.
Después de usar la ALU, las acciones requeridas para completar la instrucción son
distintas en cada clase. Las instrucciones de referencia a memoria harán el acceso para la
escritura de un dato (en el caso de los almacenamientos) o para su lectura (en el caso de las
cargas). Las instrucciones aritmético lógicas escribirán el resultado en un registro y las
instrucciones de brincos, tal vez requieran cambiar el valor del contador del programa para
continuar con la siguiente instrucción, de acuerdo al resultado de la comparación.
Los elementos que no son combinacionales son elementos que contienen estado, es decir,
tienen alguna forma de almacenamiento interno. Se les conoce como elementos de estado
por que por medio de estos elementos se caracteriza completamente el comportamiento de
la máquina. Por ejemplo, si salvamos los elementos de estado, justo antes de retirar la
alimentación de la máquina y les restauramos su valor al reactivar la alimentación, podría
parecer que la potencia nunca se perdió; por que el estado de la máquina se ha conservado.
En la figura 4.1, las memorias de datos e instrucciones, así como los registros son
elementos de estado.
Un elemento de estado tiene al menos dos entradas y una salida. Las entradas requeridas
son: el valor del dato a ser escrito en el elemento y una entrada de reloj, la cual determina
cuando el valor del dato va a ser escrito. La salida del elemento de estado proporciona el
valor que fue escrito en el ciclo de reloj mas cercano. Un ejemplo simple de un elemento de
estado es un flip-flop tipo D; su salida puede leerse en cualquier momento, sin embargo, la
señal de reloj determina cuando se hará la escritura.
A los elementos lógicos que contienen estado también se les denomina secuenciales por
que sus salidas dependen de sus entradas así como también de su estado contenido
internamente. Por ejemplo, en la figura 4.1, la salida de la unidad funcional de los registros
depende del número de registro suministrado, así como del dato que fue escrito
previamente en cada registro.
Metodología de Reloj
Una metodología de reloj define cuando las señales pueden ser leídas y cuando pueden ser
escritas. Es importante especificar los tiempos de lectura y escritura por que, si una señal es
leída al mismo tiempo en que se va a escribir, el valor de la lectura podría corresponder al
viejo valor, al nuevo valor que será escrito o a alguna mezcla de los dos. Una metodología
de reloj debe plantearse para prevenir esas circunstancias; definitivamente no se pueden
tener situaciones impredecibles.
Los dispositivos actuales utilizan una metodología disparada por flancos, lo que significa
que cualquier valor que se almacenará en la máquina se actualizará solamente durante el
flanco de reloj. Entonces, los elementos de estado actualizarán sus almacenamientos
internos solamente sobre el flanco de reloj. Debido a que los elementos de estado
determinan el comportamiento del sistema, cualquier circuito combinacional toma sus
entradas como las salidas de alguno de los elementos de estado, y sus salidas las dirige a
otro elemento de estado, para que se escriban en el siguiente ciclo de reloj.
En la figura 4.2 se muestra a dos elementos de estado conectados por un bloque de lógica
combinacional. Todas las señales deben propagarse desde el elemento de estado 1 y a
través de la lógica combinacional, alcanzarán al elemento de estado 2, en el tiempo que
tarda el ciclo de reloj. La longitud del ciclo de reloj debe incluir la lectura de los elementos
de estado 1 y el tiempo suficiente para que el circuito lógico combinacional produzca sus
salidas a partir de sus entradas.
Fig. 4.2 La lógica combinacional, los elementos de estado y la duración del ciclo de reloj
están directamente relacionados.
Por simplicidad, para aquellos elementos de estado que se modificarán en todos los ciclos
de reloj, no se colocarán las señales de control específicas, por que su habilitación para la
escritura puede tomarse directamente de la señal de reloj. Por lo tanto, solo colocaremos las
señales de control en aquellos elementos cuya escritura dependerá de alguna instrucción
particular.
Una metodología disparada por flancos permite la lectura del contenido de un registro,
enviar su valor a través de una lógica combinacional y escribir ese registro en el mismo
ciclo de reloj, como se muestra en la figura 4.3. No importa si suponemos que la escritura
se hará durante el flanco de subida o de bajada, dado que las entradas al bloque de lógica
combinacional no podrán cambiar, excepto en el flanco elegido. Al emplear esta
metodología, no hay retroalimentación dentro del ciclo.
Fig. 4.3 Una metodología disparada por flancos permite a un elemento de estado ser leído y escrito en el
mismo ciclo de reloj sin dejar datos indeterminados para algún valor.
Iniciamos con una implementación simple que utiliza un solo ciclo de reloj para cada
instrucción y sigue el esquema general mostrado en la figura 4.1. En este primer diseño,
cada instrucción inicia su ejecución sobre el flanco de reloj y la completa sobre el siguiente
flanco de reloj.
Este enfoque es fácil de entender, sin embargo no es práctico, por que todas las
instrucciones tardarán el mismo intervalo de tiempo, lo que significa que las instrucciones
mas lentas determinan la duración del ciclo de reloj. Mas adelante se estudiará un segundo
enfoque en el cual la ejecución de una instrucción requerirá de múltiples ciclos de reloj, de
manera que se podrá usar un reloj con una duración menor y las instrucciones mas lentas
requerirán de una cantidad mayor de ciclos que las instrucciones mas rápidas.
Iniciaremos el diseño examinado los principales componentes requeridos para cada clase de
instrucción. En principio, necesitamos un lugar para almacenar las instrucciones, un
registro que nos indique la instrucción que se está ejecutando y algún medio que nos
permita avanzar a la siguiente instrucción. En la figura 4.4 se muestran estos tres
elementos. Los dos primeros son elementos de estado, una memoria y un registro, mientras
que para calcular la dirección de la siguiente instrucción se utilizará un sumador, por medio
del cual se sumará 4 al registro del contador del programa (este elemento mas simple que
una ALU, puesto que solo realiza la operación de la suma).
Fig. 4.4 Dos elementos de estado son necesarios para almacenar y accesar a las instrucciones, y un sumador
es necesario para calcular la dirección de la siguiente instrucción.
La conexión de los elementos de la figura 4.4 se muestran en la figura 4.5, el contenido del
contador del programa corresponde a la dirección de la instrucción que se está ejecutando,
por lo que se conecta al bus de direcciones de la memoria de instrucciones. La dirección de
la siguiente instrucción se obtiene sumando 4 al contador del programa. En estos elementos
de estado no se muestran sus señales de control, por que serán acertados en todos los
flancos de reloj elegidos. Este es el hardware que ejecuta la búsqueda y captura de la
instrucción (ciclo de fetch).
Los 32 registros del procesador son almacenados en una estructura a la que llamaremos
Archivo de Registros. Esta estructura contiene una colección de registros en la que
cualquier registro puede ser leído o escrito especificando el número de registro en el
archivo. El archivo de registros mantiene el estado de la máquina. Además, necesitaremos
de una ALU que opere sobre los datos leídos desde los registros.
Debido a que las instrucciones tipo R tienen 3 operandos, para cada instrucción
necesitamos leer dos palabras desde el archivo de registros y escribir un dato en un registro
del archivo. Las entradas al archivo de registros deben incluir los números de los registros a
leer y el número del registro a escribir, así como el dato que se escribirá en el registro
especificado. La lectura se realiza en cada flanco del reloj, sin embargo la escritura solo se
realiza en algunas instrucciones, por lo tanto, se debe incluir una entrada de control que
habilite la escritura de un dato en un registro. Las salidas del archivo de registros
corresponden a los dos datos leídos. En la figura 4.6 (a) se muestra al archivo de registros,
las entradas que corresponden al número de registro son de 5 bits, la entrada del dato a
escribir es de 32 bits y la habilitación es de 1 bit.
La ALU que se muestra en la figura 4.6 (b) tiene 3 entradas de control y su comportamiento
es el descrito en la sección 3.5. Las entradas de los operandos son de 32 bits y el resultado
producido también lo es.
En la figura 4.7 se muestra la conexión del archivo de registros con la ALU, hasta este
momento solo hemos considerado instrucciones tipo R, por lo que los datos obtenidos del
archivo de registros se conectan directamente a las entradas de la ALU y el resultado
producido, se dirige hacia la entrada de datos del archivo de registros. Este es el camino de
los datos necesario para le ejecución de instrucciones tipo R.
Fig. 4.6 El archivo de registros y la ALU son los elementos necesarios para implementar las instrucciones
tipo-R.
Además del archivo de registros y de la ALU, para soportar estas instrucciones necesitamos
de otros elementos: una memoria de datos, la cual nos permitirá lecturas (para cargas) y
escrituras (para almacenamientos) y un módulo de extensión de signo; el cual en su entrada
tendrá una palabra de 16 bits y la extenderá en signo para completar una palabra de 32 bits.
Fig. 4.8 Los dos elementos necesarios para implementar las cargas y almacenamientos,
además de los elementos mostrados en la figura 4.6.
Fig. 4.9 El camino de los datos para cargas y almacenamientos, hace un acceso a registros seguido por el
cálculo de una dirección de memoria, para después leer o escribir en la memoria, y en el caso de una carga,
concluir con la escritura de un registro.
Además de calcular la dirección destino del brinco, se debe determinar cual será la
siguiente instrucción a ejecutarse, de acuerdo a la igualdad o desigualdad entre los
registros. Si los contenidos de los registros son iguales el brinco debe realizarse, por lo que
el contador del programa deberá ser sustituido por la dirección calculada. Pero si no son
iguales, el brinco no se realizará por lo que se continuará con la instrucción ubicada en la
dirección siguiente a la dirección del brinco.
Entonces, el camino de los datos debe realizar las dos operaciones: Calcular la dirección
destino del brinco y comparar los contenidos de los registros. En la figura 4.10 se muestra
el camino de los datos para los brincos; con la ALU se realiza una resta entre el contenido
de los dos registros, de manera que el brinco queda condicionado a la puesta en alto la
bandera de zero. Con otro sumador se obtendrá la dirección destino del brinco. En la
instrucción se incluye al desplazamiento en 16 bits, éste se extiende en signo y luego, para
que corresponda a un desplazamiento de palabras, se desplaza a la izquierda dos lugares, lo
cual equivale a multiplicar por 4. El valor resultante es el que se sumará a PC + 4, el
resultado de la suma es la dirección destino del brinco.
Fig. 4.10 El camino de los datos para un brinco condicional, la ALU evalúa la condición del salto y otro
sumador calcula la dirección destino del salto, con relación al valor actual del contador del programa.
En esta sección se pretende realizar una implementación completa - camino de los datos y
control - para las instrucciones: cargar palabra (lw), almacenar palabra (sw), brincar sobre
igual (beq) y las instrucciones aritmético lógicas: add, sub, and, or y slt. Al final se
incorporará la instrucción de salto (j).
En las figuras 4.5, 4.7, 4.9 y 4.10 se mostraron algunas piezas del camino de datos para las
instrucciones individuales, ahora se combinaran todas estas piezas para tener un único
camino de los datos. Debe tomarse en cuenta que se trata de una implementación que
ejecutará todas las instrucciones en 1 ciclo de reloj. Esto significa que los recursos en el
camino de los datos no pueden ser usados mas de una vez por instrucción, de manera que
cualquier elemento que se requiera mas de una vez, deberá ser duplicado. Por lo tanto,
necesitamos de una memoria de instrucciones separada de la memoria de datos. Aunque
algunos elementos necesitan duplicarse, también tenemos que diferentes elementos serán
compartidos por diferentes flujos de instrucciones.
Al compartir elementos, pueden requerirse múltiples conexiones a una entrada. Para ello se
utilizarán multiplexores, y será el control el que determine cual de los datos fluirá a cada
entrada.
Primero combinaremos las instrucciones Tipo-R con las instrucciones de acceso a memoria
(figuras 4.7 y 4.9). Ambas instrucciones utilizan a la ALU y el primer operando en ambos
casos es el dato escrito en el registro 1, obtenido del archivo de registros, sin embargo el
segundo operando difiere para las dos instrucciones: En el caso de las instrucciones tipo-R
el segundo operando es el dato escrito en el registro 2, obtenido del archivo de registros.
Mientras que para los accesos a memoria, el segundo operando es una constante extendida
en signo. Por lo que es necesario un multiplexor en la entrada del segundo operando de la
ALU.
Fig. 4.11 Combinando el camino de los datos para una instrucción de acceso a memoria y el de las
instrucciones tipo-R.
Para completar el camino de los datos, debemos agregar la parte necesaria para los brincos,
que se muestra en la figura 4.10. Al agregar estos elementos, será necesario el uso de un
multiplexor a la entrada del PC, para poder seleccionar entre PC + 4 y el resultado de haber
sumado a PC + 4 una constante. En la figura 4.13 se muestra al camino de los datos
obtenido hasta el momento, el cual puede ejecutar instrucciones tipo-R, cargas,
almacenamientos y brincos sobre igual.
Fig. 4.13 Un camino de los datos que combina los elementos requeridos
por diferentes clases de instrucciones MIPS.
Ahora que hemos completado el camino de los datos podemos agregar la unidad de control.
La unidad de control deberá tener la habilidad de generar las señales de escritura para cada
elemento de estado, la selección de cada multiplexor y el control de la ALU; a partir de las
entradas que definan al tipo de instrucción (opcode). Sin embargo las instrucciones
aritmético-lógicas comparten el mismo opcode, de manera que para simplificar las cosas,
diseñaremos por separado el control de la ALU y luego diseñaremos el resto de la unidad
de control.
Control de la ALU
Recordemos que la ALU tiene tres entradas de control y que sólo cinco de las ocho
combinaciones posibles son utilizadas. En la tabla 3.5 se definió el comportamiento de la
ALU, la cual se repite en la tabla 4.1 por conveniencia.
La selección entre cada una de estas cinco funciones dependerá de la clase de instrucción.
Para cargas y almacenamientos se requiere que la ALU realice una suma para calcular la
dirección de la localidad de memoria a la que se realizará el acceso. Para instrucciones
aritmético lógicas la ALU realizará una suma, resta, AND, OR o ajuste sobre menor que,
dependiendo del campo de función que se encuentra en los 6 bits menos significativos en
esta clase de instrucciones. Para el salto sobre igual la ALU necesita realizar una resta.
Como un primer paso realizaremos una pequeña unidad de control que tenga una entrada de
2 bits a la que denominaremos ALUOp. Con esta entrada se determinará si la ALU
realizará una suma (ALUOp = 00) para cargas y almacenamientos, una resta (ALUOp = 01)
para brincos sobre igual o si la operación quedará determinada por el campo de función
(ALUOp = 10) para instrucciones tipo-R. La salida de este Control de la ALU será de 3 bits
y se conectará directamente con las líneas de control de la ALU.
En la tabla 4.2 se muestra el comportamiento de la ALU basado en las entradas de dos bits
(ALUOp) y en los 6 bits del campo de función. La unidad de control principal generará los
valores para ALUOp.
Este estilo de usar diferentes niveles de decodificación (p. Ej., la unidad de control
principal genera los bits ALUOp, los cuales son usados como entradas al control de la ALU
para generar las señales que controlan a la ALU) es una técnica de implementación común.
El usar múltiples niveles de control reduce el tamaño del control principal, por que el
control principal ya no necesitará como entrada al campo de función, solamente al código
de operación (opcode), con ello se aumenta su velocidad de respuesta considerablemente.
La tabla 4.2 nos muestra que para el diseño del control de la ALU se deben considerar los 6
bits del campo de función. Sin embargo, esto nos lleva a diseñar un circuito combinacional
con 8 entradas y 3 salidas. Si construimos la tabla de verdad considerando todas las
combinaciones, tendremos una tabla muy grande en la que muchas de las combinaciones en
realidad no importan por que no van a ocurrir. Entonces, para hacer un diseño simple (con
pocas compuertas), a partir de la tabla 4.2 observaremos las condiciones necesarias y
suficientes para generar cada una de las entradas de la ALU. En la tabla 4.3 se muestra a los
3 bits del control de la ALU en función de ALUOp y el campo de función; se han colocado
X en aquellos valores que no son determinantes para definir la operación.
Entonces, observando las condiciones mínimas para la generación de cada salida tenemos
que:
Sal0 = ALUOp1xF3 + ALUOp1xF0
Sal1 = ALUOp1’xALUOp0’ + ALUOp0 + ALUOp1xF2’
Sal2 = ALUOp0 + ALUOp1xF1
Estas ecuaciones van a funcionar en el caso de que solo se consideren estas combinaciones;
ya que si se incrementan las operaciones, el campo de función introducirá nuevas
combinaciones y las ecuaciones puede no cumplirse.
Ahora que contamos con un control para la ALU, es posible realizar el control principal;
para ello es conveniente repasar los formatos de las instrucciones que se están
considerando:
0 rs rt rd shamt funct
31-26 25-21 20-16 15-11 10-6 5-0
35 o 43 rs rt dirección
31-26 25-21 20-16 15-0
4 rs rt dirección
31-26 25-21 20-16 15-0
Algunas observaciones relacionadas con los formatos y que pueden ser importantes para el
diseño del hardware son:
El código de operación (opcode), está siempre contenido en los bits 31-26. A este
campo lo referiremos como Op[5-0].
Los dos registros a ser leídos están siempre especificados por los campos rs y rt, en las
posiciones 25-21 y 20-16. Esto para las instrucciones tipo-R, brincos sobre igual y los
almacenamientos.
El registro base para las instrucciones de cargas y almacenamientos es rs y está en los
bits 25-21.
Los 16 bits de desplazamiento para brincos sobre igual, cargas y almacenamientos están
siempre en las posiciones 15-0.
El registro destino está en uno de dos lugares. Para las cargas está en los bits de
posición 20-16 (rt), mientras que para instrucciones tipo-R su posición es 15-11 (rd).
Entonces necesitamos un multiplexor para seleccionar el campo que corresponda al
registro que se escribirá de acuerdo a la operación.
La unidad de control ajustará el valor de todas las señales dependiendo del código de
operación (opcode), con excepción de la señal PCSrc. Esta señal deberá acertarse cuando se
trate de un brinco condicional, sólo si el resultado de la comparación es verdadero. Por lo
que a la entrada de la señal PCSrc colocaremos una AND de dos entradas, una de ellas
provendrá de la bandera zero (producida por la ALU) y la otra la generará la unidad de
control siempre que se trate de un brinco, a esta última señal la denominaremos branch.
En la tabla 4.5 mostramos el valor que deberá colocarse a las señales de control, en función
del opcode. Se presentan algunos casos en los que el valor de la señal no importa, por
ejemplo, si no se escribirá en un registro, no importa de donde provenga el dato. Para la
tabla 4.5, en relación a las memorias y al archivo de registros, se consideró que acertado
equivale a 1.
Fig. 4.15 El camino de los datos con la unidad de control.
Tabla 4.5 El valor de las señales de control queda determinado por el código de operación.
Para el diseño del control, es necesario recordar los códigos de operación para cada una de
las instrucciones bajo consideración, esto se muestra en la tabla 4.6.
Con base en las tablas 4.5 y 4.6 se obtiene directamente el circuito del control, el cual se
muestra en la figura 4.16.
Inputs
Op5
Op4
Op3
Op2
Op1
Op0
Outputs
R-format Iw sw beq
RegDst
ALUSrc
MemtoReg
RegWrite
MemRead
MemWrite
Branch
ALUOp1
ALUOpO
Fig. 4.16 Implementación del control.
Implementación de los Saltos
4 dirección
31-26 25-0
Los 4 bits mas significativos del valor de PC + 4 (estos son los bits 31-28 de la
dirección secuencialmente continúa al salto).
Debe agregarse un multiplexor mas, por medio del cual se podrá seleccionar entre PC + 4 y
el valor obtenido de la concatenación anterior. En la figura 4.17 se muestra el hardware
agregado para el camino de los datos para el salto, así como la nueva señal de control para
la selección del valor correcto para el PC.
Una implementación de este estilo tiene un CPI igual a 1 (Ciclos por Instrucción) y puesto
que no sabemos cual es la instrucción que se estará ejecutando, hasta que inicie su
ejecución, todos los ciclos de reloj deberán ser del mismo tamaño. Por lo que el tamaño del
ciclo de reloj estará determinado por la ruta mas larga posible en la máquina. Esta ruta
ciertamente es para una instrucción de carga, la cual utiliza cinco unidades funcionales en
serie: La memoria de instrucciones, el archivo de registros, la ALU, la memoria de datos y
nuevamente el archivo de registros. Esta instrucción determinará el tamaño del ciclo.
Las instrucciones que podrían ser rápidas, como los saltos que aunque solo ocupan la
memoria de instrucciones, tardarán lo mismo que las cargas. Entonces, aunque el CPI es
igual a 1, el rendimiento de esta implementación no es muy bueno dado que diferentes
clases de instrucciones podrían ejecutarse en menos tiempo.
Instruction [25-0] Jump Address [31-0]
Shift 1
Left 2 M
0 u
M x
u 0
PC + 4[31-28]
x
1
Shift
Left 2 PCSrc
4
RegDst
Jump
Branch
MemRead
Instruction [31-26]
MemtoReg
ALUOp
MemWrite
ALUSrc
RegWrite
Fig. 4.17 El camino de los datos con la unidad de control, soporta la ejecución de instrucciones tipo-R, cargas, almacenamientos, brincos y saltos.
TAREA 8
Para los problemas del 1 al 4 de esta tarea se sugiere que se imprima la figura 4.17 para
realizar lo que se pide en cada punto.
1. Suponiendo que los registros $t0 y $t1 tienen los valores 30 y 40 respectivamente, al
ejecutarse la instrucción: add $t2, $t1, $t0. En la figura 4.17, resaltar las líneas que estarán
activas durante la ejecución de esta instrucción y escribir el valor de cada una de las líneas
activas (para las del camino de los datos usar color rojo y verde para las de control).
2. Este ejercicio es similar al anterior, pero ahora se trata de la instrucción: beq $t1, $t2, et1
y debemos suponer que tanto $t1 y $t2 tienen el dato 33, que la instrucción esta ubicada en
la dirección 4000diez y que la etiqueta está ubicada 10 instrucciones antes de la que se está
evaluando.
4. Esta pregunta es similar a la anterior, pero ahora se trata de soportar a la instrucción jal.
5. Se nos propone que la señal de control MemtoReg sea eliminada. Por lo que el
multiplexor que tiene como entrada a MemtoReg deberá usar la señal de control MemRead
¿Trabajará el hardware con las modificaciones propuestas? ¿Por qué?