PROCESADOR DIDACTICO
ANDREA CRISTINA CAMACHO
UNIVERSIDAD DE LOS ANDES
FACULTAD DE INGENIERIA
DEPARTAMENTO DE ELECTRONICA
BOGOTA CUNDINAMARCA
2005
PROCESADOR DIDACTICO
ANDREA CRISTINA CAMACHO
Trabajo de grado para optar al título de
Ingeniero Electrónico
Director
FREDY SEGURA
Ingeniero Electrónico
UNIVERSIDAD DE LOS ANDES
FACULTAD DE INGENIERIA
DEPARTAMENTO DE ELECTRONICA
BOGOTA CUNDINAMARCA
2005
CONTENIDO
Pág.
INTRODUCCION
4
1.
MARCO TEORICO
5
1.1
DEFINICION DEL PROBLEMA
5
1.2
MODELO
DEL
PROCESADOR
6
1.2.1
Set
de
instrucciones
7
1.2.2 Construcción del camino de datos
9
1.2.3 Construcción de la Unidad de Control
12
1.2.4 Construcción de la Unidad de Control de la ALU
13
1.3
SEGMENTACION DE LA ARQUITECTURA
14
2.
DESCRIPCION DE LA ARQUITECTURA EN VHDL
15
2.1
Descripción
de
librerías
y
paquetes
17
2.2
Descripción de las fases de segmentación
24
2.3
Descripción de los registros de segmentación
41
2.4
Modulo
ASIGNACIÓN
_
SALIDAS 44
2.5
Modulo
MIPS
47
3.
DESCRIPCION
DE
LAS
TARJETAS
51
3.1
Tarjeta
de
Programación
51
3.2
Tarjeta
de
Visualización
59
4.
RESULTADOS
62
CONCLUSIONES
63
INTRODUCCION
Este documento presenta la descripción de diseño descendente seguida para crear el Procesador
Didáctico; un sistema digital hardware/software para diversas aplicaciones pero que
esencialmente se ha construido con el propósito de que se convierta en una herramienta didáctica
que facilite el aprendizaje de arquitecturas de procesador. Con este fin el Procesador Didáctico
esencialmente emula el flujo de datos en tiempo real de un pequeño procesador de 8 bits y un set
reducido de instrucciones basado en la arquitectura MIPS[1].
El sistema esta compuesto básicamente por un diseño arquitectural modelado en VHDL y dos
tarjetas electrónicas que proporcionan el hardware necesario para su implementación y el
seguimiento del flujo de datos en tiempo real de programas construidos en base al set reducido de
instrucciones.
La Tarjeta de Programación basada en un dispositivo de lógica programable (FPGA) aporta el
hardware mínimo para programar la FPGA a través del puerto paralelo del computador por medio
de JTAG, circuiteria de reloj y pruebas, comunicación serial RS-232 y puertos de expansión para
conectar la FPGA con otros sistemas, mientras que la de Visualización cuenta con componentes
como leds y displays que despliegan las señales mas elementales que permiten comprender el
proceso de ejecución de los programas a nivel de microinstrucciones.
En este documento se comentaran las etapas de desarrollo del proyecto, partiendo del estudio de
la arquitectura básica y las modificaciones hechas tanto para optimizar el funcionamiento como el
rendimiento.
Seguidamente se describirá el diseño de las tarjetas impresas, partiendo así el total del proyecto
en dos fases de diseño; una fase de diseño arquitectural y otra fase de diseño de hardware.
Por ultimo se plantea una practica a realizar con el Procesador Didáctico, se evalúa el
funcionamiento del sistema y se dan sugerencias para futuros proyectos.
El documento se divide en cinco capítulos: el capítulo uno contextualiza al lector sobre el
planteamiento del problema, resalta la importancia de la arquitectura MIPS y plantea el modelo
arquitectural del procesador.
El segundo capítulo describe el diseño en VHDL de los diferentes módulos que conforman la
arquitectura y las modificaciones hechas al modelo arquitectural del capitulo uno para optimizar
el funcionamiento y aumentar el rendimiento.
El capitulo tres describe el diseño de las tarjetas de Programación y Visualización.
Finalmente se encuentran los resultados y conclusiones.
1. MARCO
TEORICO
1.1 DEFINICION DEL PROBLEMA
La comprensión y diseño de diferentes arquitecturas basadas en procesador siempre ha sido
objeto de estudio para su aplicación en distintas ramas, sin embargo en la Universidad de los
Andes no se cuenta con herramientas que faciliten la aplicación de los conocimientos adquiridos
en esta área y que puedan hacer practico y didáctico el aprendizaje.
El Procesador Didáctico se propone como una herramienta de apoyo para el aprendizaje de
materias como arquitectura del computador y sistemas digitales; sin embargo por ser un sistema
versátil podrá ser utilizado para muchas otras aplicaciones electrónicas.
El sistema completo esta conformado por el Core de un procesador de 8 bits y 8 instrucciones
básicas, modelado en VHDL, y dos tarjetas electrónicas.
Figura 1: Descripción del sistema.
Para desarrollar el Core del procesador se selecciono como arquitectura base para el estudio la
arquitectura MIPS (Microprocessor without interlocked pipeline stages), desarrollada por John L.
Hennessy en 1984. Es un con arquitectura RISC desarrollado por MIPS Computer Systems Inc.
Los disenos MIPS son usados en la linea de productos de computador SGI, y han encontrado un
amplio uso en sistemas embebidos, sietemas CE de Windows, y enrutadores Cisco. Las consolas
del Nintendo 64, Sony PlayStation uno y dos y la versión portable usan procesadores MIPS.
A finales de los 90’s se estimaba que uno de cada tres chips RISC era producido en base a un
diseno MIPS.
El procesador MIPS es un modelo clásico de estudio y ofrece un repertorio de instrucciones fácil
de comprender e implementar. El diseño modelado trata de guardar la mayor consistencia posible
con la descripción hecha por Hennessy y Patterson de esta arquitectura [2].
[2] La interfaz hardware/software. DAVID A. PATTERSON-JOHN L. HENNESY. Mc. Graw
Hill. Segunda edición en español - 1995.
La Tarjeta de Programación basada en un dispositivo de lógica programable (FPGA) aporta el
hardware mínimo para programar la FPGA, a través del puerto paralelo del computador por medio
de JTAG, circuiteria de reloj y pruebas, comunicación serial RS-232 y puertos de expansión para
conectar la FPGA con otros sistemas.
La Tarjeta de Visualización conformada principalmente por un arreglo de dispositivos de
entrada/salida como leds, displays siete segmentos y switches, ha sido creada como una tarjeta de
expansión de la tarjeta de Programación para desplegar las señales de esta.
Las tarjetas electrónicas también pueden usarse para muchas aplicaciones electrónicas, sin
embargo su propósito principal, especialmente para la de Visualización es servir como
herramienta para la docencia. En esta aplicación en particular, la tarjeta de Programación es
configurada por medio de JTAG desde el computador a través del cable paralelo, con la
arquitectura diseñada. La tarjeta de Visualización despliega las señales de salida de la de
Programación permitiendo comprender el proceso de ejecución de los programas en tiempo real a
nivel de microinstrucciones.
El Procesador Didáctico pretende ser una ayuda didáctica para la mejor comprensión del
funcionamiento interno de un procesador. Su modelaje en VHDL ofrece mayor facilidad a
posibles modificaciones, ya que permite hacer cambios modulares, lo que posibilita la
reutilización del código permitiendo desarrollar nuevos modelos arquitecturales y verificar su
funcionamiento.
Este permitiría a profesores y asistentes de laboratorio diseñar prácticas donde se apliquen los
conocimientos teóricos adquiridos en clase.
Los estudiantes podrán aprender tanto en base a la práctica como rediseñando, simulando,
sintetizando y descargando sus diseños en base a la arquitectura MIPS planteada, para comprobar
físicamente su correcto funcionamiento y crear diferentes diseños arquitecturales.
1.2 MODELO DEL PROCESADOR
Para el desarrollo del proyecto como primera medida se hizo un estudio teórico de la arquitectura
MIPS, con el que se obtuvieron nociones elementales acerca de su funcionamiento y
construcción, permitiendo definir el set reducido de instrucciones que se incluirán en el
Procesador Didáctico y construir el camino de datos y las unidades de control en base a los
componentes arquitecturales necesarios para cada instrucción.
El procesador consta de dos componentes principales que deben diseñarse de acuerdo a las
instrucciones que se implementaran en el. El Camino de Datos realiza las operaciones aritméticas
y lógicas; mientras el Control le indica a este y a la Memoria lo que deben hacer de acuerdo a las
instrucciones.
1.2.1 Set de instrucciones.
Para poder dar órdenes al procesador hay que hablar en su lenguaje. El lenguaje que la maquina
entiende se denomina Repertorio o Set de Instrucciones y esta conformado por las instrucciones
que se implementaran en el procesador.
El repertorio de instrucciones MIPS incluye aproximadamente 140 instrucciones en total entre
instrucciones aritméticas, lógicas, de manipulación de constantes, de comparación, de salto y
bifurcación, de carga, almacenamiento, de desplazamiento de datos, instrucciones de punto
flotante, de excepciones e interrupciones. Sin embargo en este proyecto solo se implementaran
las ocho instrucciones más básicas para hacer un procesador de baja complejidad y de fácil
entendimiento.
Existen diferentes tipos de instrucciones que puede realizar un procesador, dependiendo de los
elementos que se usen dentro del camino de datos y de la información que se requiera procesar.
Las instrucciones a nivel de lenguaje maquina están codificadas en 32 bits que se agrupan en
diferentes campos formando diferentes formatos. Las instrucciones Aritmético-Lógicas, agrupan
estos 32 bits en 6 campos dando origen a la primera clase de formato de instrucciones: el Tipo R.
Figura 2: Formato de instrucciones Tipo R.
Definición de los campos:
• OP: operación de la instrucción. Igual a cero para todas las operaciones Tipo R.
• RS: primer registro del operando fuente.
• RT: segundo registro del operando fuente.
• RD: registro destino; obtiene el resultado de la operación.
• Shamt: cantidad de desplazamiento para corrimientos.
• Function: selecciona la variante de la operación del campo OP.
Entre las instrucciones de este formato, se seleccionaron para ser implementadas en el
Procesador Didáctico las siguientes:
• Suma con desbordamiento: add.
Sintaxis: add rd,rs,rt
Función: rd ← rs+rt
Si hay desbordamiento no se produce la operación.
• Resta con desbordamiento: sub
Sintaxis: sub rd,rs,rt Función: rd ← rs-rt
Si hay desbordamiento no se produce la operación.
• Producto lógico: and
Sintaxis: and rd,rs,rt Función: rd ← rs AND rt
• Suma lógica: or
Sintaxis: or rd,rs,rt Función: rd ← rs OR rt
• Comparación si menor que con signo: slt
Sintaxis: slt rd,rs,rt Función: Si rs < rt rd ← 1
La comparación supone que tanto rs como rt contienen sendos datos con signo en
complemento a 2.
Los operandos de las instrucciones aritméticas provienen de una serie limitada de posiciones
especiales de almacenamiento de datos de 8 bits denominadas registros. Como solo se realizan
operaciones entre registros, el procesador debe incluir instrucciones que transfieran datos entre la
memoria y los registros.
Instrucciones de transferencia de datos:
• Carga de una palabra de memoria en un registro: lw
Función:
rt
← Mem ( direccion + rs )
Carga en el registro rt el contenido de la posición de memoria direccion + rs.
• Almacenamiento en memoria del contenido de un registro: sw
Función: Mem (direccion + rs ) ← rt
Almacena el contenido del registro rt en la posición de memoria cuya dirección viene dada
por direccion + rs
Las instrucciones de transferencia de datos necesitan un nuevo formato, ya que deben especificar
dos registros y una dirección. Un registro para cargar o almacenar el dato en los registros o en la
memoria respectivamente y otro para calcular la dirección de acceso a memoria sumándolo al
campo dirección de la instrucción.
Si la dirección utilizara uno de los campos de 5 bits del formato, estaría limitada a 32 posiciones
de memoria.
Formato instrucciones tipo I:
Figura 3: Formato de instrucciones Tipo I.
Los formatos se distinguen por los valores del primer campo (OP), que generalmente se conoce
como Código de operación (opcode). Este indica al procesador si tratar la ultima mitad de la
instrucción como 3 campos (tipo R) o como un solo campo (tipo I).
Para que el procesador pueda tomar decisiones y ejecutar diferentes instrucciones basándose en
los datos de entrada y en los valores obtenidos de algún cálculo, se deben incluir instrucciones
para toma de decisiones e instrucciones de salto condicional.
Instrucción para control de flujo:
• Ramificación condicional si igual: beq
Sintaxis: beq rs, rt, dirección
Función: Si rs = rt PC ← PC + dirección
Para lograr comparar los diferentes campos que caracterizan las instrucciones incluidas se
presenta a continuación un resumen de las ocho instrucciones:
Instrucción Tipo OP [31-26] RS [25-21] RT [20-16] RD [15-11] SHAMT [10-6] FUNCT [5-0] DIR [15-0] ADD R 0 REG REG REG 0 0x 21 o 33 N.A
SUB R 0 REG REG REG 0 0x 22 o 34 N.A AND R 0 REG REG REG N.A 0x 24 o 36 N.A OR R 0 REG REG REG N.A 0x 25 o 37 N.A SLT R 0 REG REG REG N.A 0x2A o 42 N.A
LW I 0x23 REG REG N.A N.A N.A DIR
SW I 0x2B REG REG N.A N.A N.A DIR
BEQ I 4 REG REG N.A N.A N.A DIR
Tabla 1: Instrucciones del Procesador Didáctico.
1.2.2 Construcción del camino de datos.
El Camino de datos es un conjunto de elementos de almacenamiento y cálculo junto con los
buses de datos que los interconectan y las señales de control que regulan su funcionamiento.
Para ejecutar cualquier instrucción se necesita una Memoria para que contenga y suministre las
instrucciones de un programa. La dirección de acceso a la memoria de instrucciones será
especificada por el contador de programa,
este es un registro que contiene la dirección de la
instrucción actual que se esta ejecutando y debe incrementarse para que apunte a la siguiente
instrucción en cada ciclo de reloj.
Para implementar las instrucciones descritas previamente en el Set de instrucciones, se necesita
prácticamente lo mismo. Para cada instrucción, los dos primeros pasos son idénticos:
• Enviar el contador de programa (PC) a una memoria que contenga el código para buscar la
instrucción.
• Leer uno o dos registros utilizando los campos de la instrucción para seleccionar los registros a
leer.
Después de estos dos pasos las acciones requeridas para completar la instrucción, dependen del
tipo de instrucción. Sin embargo todos los tipos de instrucciones utilizan la ALU después de leer
los registros. Las de referencia a memoria para calcular una dirección efectiva, las
aritmético-lógicas para la ejecución del código de operación y las de salto para realizar comparaciones.
Después de utilizar la ALU, las acciones requeridas para completar los diferentes tipos de
instrucciones difieren. Una instrucción de referencia a memoria necesitara acceder a la memoria
que contenga el dato para completar un almacenamiento o una carga. Una aritmético-lógica
deberá escribir el resultado de la ALU en un registro. Finalmente para una instrucción de salto,
puede ser necesario cambiar la dirección de la siguiente instrucción según el resultado de la
comparación.
Para comenzar a diseñar el camino de datos partimos examinando los principales componentes
necesarios para ejecutar cada tipo de instrucción.
Las instrucciones aritmético-lógicas (tipo R) se realizan entre registros y deben acceder al archivo
de registros para leer los dos operandos a procesar (RT y RD) y para guardar el resultado de la
operación realizada en la ALU en otro registro (RS). En la figura 4 se muestra el camino de datos
para este tipo de instrucción.
Figura 4: Camino de datos para las instrucciones Tipo R.
Si consideramos las instrucciones de carga y almacenamiento. Estas instrucciones calculan una
dirección de acceso a memoria sumando el registro base (RT) al campo de dirección de 16 bits de
la instrucción.
En un almacenamiento el valor que se va a almacenar debe ser leído del archivo de registros (RS)
y almacenado en la dirección de memoria calculada. Si es una carga, el valor debe ser leído de
memoria y copiado en el registro (RS).
A continuación se puede observar el nuevo camino de datos para adicionar las instrucciones de
carga y almacenamiento.
Figura 5: Camino de datos incluyendo Lw y Sw
Como se comparten los elementos del camino de datos para los diferentes tipos de instrucciones,
se necesitan múltiples conexiones a la entrada de un mismo elemento y una señal de control para
seleccionar las entradas. Un multiplexor debe agregarse en cada elemento compartido del camino
de datos.
Se puede ver que se adiciona un multiplexor para decidir en que registro escribir. El registro
destino para una instrucción de carga se encuentra codificado en la cadena de bits del 20-16 (RT),
mientras que para una tipo R esta del 15-11 (RD). Se debe incluir otro multiplexor en la segunda
entrada de la ALU, ya que esta es o un registro (si se trata de una instrucción tipo R) o el campo
dirección de la instrucción en caso de una instrucción de memoria (Lw o Sw). Uno mas debe
agregarse ya que el valor escrito en el registro proviene de la ALU para una instrucción tipo R o
de memoria para una instrucción de carga.
La instrucción beq (Tipo I) tiene dos registros que se comparan para saber si son iguales y un
desplazamiento de 16 bits. Esta instrucción utiliza la ALU para la comparacion de los operandos
de los registros y adicionalmente necesita calcular la direccion de salto, por lo que es necesario
un sumador para hacer las dos operaciones simultaneamente.
Cuando los dos registros son iguales (RS=RT) la señal de salida Zero de la ALU se pone a ‘1’. Si
esta condicion se cumple y la operación que se esta llevando a cabo es Beq, el PC cambia su
valor a la dirección de destino de salto (PC+1+Direccion) y se dice que se realiza el salto. De lo
contrario, el PC incrementado (PC+1) debe sustituir al PC actual. Esta decision se toma en el
multiplexor adicionado el cual es controlado por la senal PCSrc proveniente de la unidad de
Control, que describiremos mas adelante.
Figura 6: Camino de datos incluyendo la instrucción Beq.
1.2.3 Construcción de la unidad de control.
La unidad de control genera las señales de que gobiernan el funcionamiento del procesador
dependiendo del código de operación (OP) de la que instrucción que se este leyendo de la
memoria de instrucciones. Esta debe tomar este campo (Instrucción[31-26]) y generar una señal
de escritura para cada elemento de estado, el control para cada multiplexor y el bloque que
controla la ALU.
Descripción de las señales de control:
• PCSrc: Selecciona el nuevo valor del PC entre su valor inmediato y la dirección de salto
• ALUSr: Selecciona el segundo operando de la ALU, entre el segundo registro leído del
archivo de registros y los 16 bits del campo dirección de la instrucción.
• AluOp: Indica la operación a realizar en la ALU.
• RegDst: Selecciona la dirección de registro a escribir RT o RD.
• Branch: Indica que la operación que se esta realizando en Beq.
• RegWrite: Habilita la escritura del bloque de registros.
• MemRead: Habilita la lectura de la memoria.
• MemWrite: Habilita la escritura de la memoria.
• MemtoReg: Selecciona el dato a escribir en el bloque de registros. El resultado de la ALU o el
dato leído de la memoria.
La inicialización de las líneas de control salvo PCSrc dependen solamente del campo de código
de operación de 6 bits OP. La unidad de control no puede inicializar la señal PCSrc basándose en
el campo de código de operación ya que esta debería inicializarse si la operación es saltar sobre
igual (Branch=1) y si los dos registros son iguales (Zero=1). Por esto se hace una AND entre
estas dos señales provenientes de la Unidad de Control y la ALU respectivamente.
La siguiente tabla define el valor que debe tener cada señal de control para cada instrucción
según el código de operación:
Tabla 2: Señales de control dependiendo del campo OP.
1.2.4 Construcción de la Unidad de Control de la ALU
La unidad de control de la ALU administra las funciones de esta en base al campo function
(Instrucción[5-0]) y la señal de control de 2 bits ALUOP provenientes de la unidad de control
principal, generando una señal de control de 3 bits que selecciona la operación a realizar en la
ALU.
En la Tabla 3 puede verse la correspondencia entre el campo function de la instrucción, la señal
de control ALUOp, la señal de control de la ALU y la operación que esta realiza.
1.2 Segmentación de la arquitectura.
La ejecución de las instrucciones la podemos separa en varias etapas:
• IF: Búsqueda de la instrucción.
• ID: Decodificación de la instrucción y búsqueda de registros.
• EX: Ejecución de la operación (instrucciones ALU) y calculo de la dirección efectiva
(para accesos a memoria).
• MEM: Logica para decision de saltos y acceso a memoria.
• WB: Escritura de los resultados en el archivo de registros
Se puede segmentar el camino de datos dividiendo la arquitectura en estas 5 etapas por medio de
registros que pasan los valores de una etapa a otra en cada ciclo de reloj, de tal forma que se
realicen 5 instrucciones en cada ciclo de reloj en vez de una, aumentando el rendimiento de la
maquina para la ejecución de un programa. La segmentacion de la arquitectura puede observarse
en la figura 7.
Figura 7: Arquitectura Segmentada.
Los registros de segmentacion pasan tanto los datos procesados de una etapa a la otra, asi como
las senales de control, distribuyendo los datos sincronicamente en cada flanco de subida de reloj.
2. DESCRIPCION DE LA ARQUITECTURA EN VHDL
Se modelo un procesador MIPS de 8 bits con set reducido de 8 instrucciones y se utilizo la
herramienta ISE de Xilinx para la síntesis y simulación del código en VHDL.
VHDL fue el lenguaje de descripción de hardware que se empleo para la descripción de la
arquitectura, esencialmente por las ventajas que ofrece. Es un lenguaje estándar que se puede
utilizar en diferentes herramientas, permite modelar en todos los niveles de diseño, acepta el uso
de librerías con componentes comúnmente utilizados y es independiente de la tecnología.
Además da la facilidad de hacer un diseño en base a componentes que pueden verificarse y
cambiarse independientemente del resto, permitiendo una simulación rápida y constante que
repercute directamente en la obtención de un menor tiempo de diseño. Todo esto hace que sea
más fácil para el estudiante reutilizar la arquitectura planteada para crear nuevas opciones
arquitecturales.
El desarrollo de la arquitectura diseñada se llevo a cabo siguiendo un proceso de diseño
descendente, dividiendo la arquitectura reiteradamente en unidades funcionales más pequeñas
que facilitaron la verificación para luego unificarlas formando el diseño completo de la
arquitectura MIPS reducida.
Los módulos definidos tratan de guardar la mayor proporción posible con el camino de datos
descrito previamente. Sin embargo el modelo diseñado cambia un poco debido a que fue
necesario incluir un modulo de Anticipación de datos y dos multiplexores para poder realizar
operaciones contiguas que utilicen los mismos registros de datos. Con estos bloques se reducen
los errores por dependencia de datos, los cuales podrían presentarse cuando una instrucción lee
un dato para operarlo mientras otra esta escribiéndolo.
En la figura 9 puede verse la nueva arquitectura segmentada con las unidades de corrección
adicionadas.
Para corregir los errores por dependencia de datos, la unidad de Anticipación recibe como
entradas los campos RS y RT del registro de segmentación ID/EX que especifican que registros
van a leerse, las señal de control RegWrite y el registro destino de los registros de segmentación
EX/MEM y MEM/WB que definen que registro va a escribirse. Con estas entradas la unidad de
anticipación revisa si puede presentarse un error por dependencia de datos al coincidir los
registros de lectura y escritura al estar habilitada la señal RegWrite y anticipa las señales
requeridas, haciendo posible poder tomar las entradas de la ALU desde cualquier registro de
segmentación y no necesariamente del ID/EX, utilizando resultados temporalmente en lugar de
esperar a que se escriban los registros.
Los multiplexores de la ALU seleccionan o los valores normales de los registros o uno de los
valores anticipados.
Las condiciones para anticipar un dato y localizar la ubicación del resultado son:
• Riesgo EX:
Si (EX/MEM.RegWrite = 1)
Si (EX/MEM.EscribirRegistro = ID/EX.LeerRegistro1) => AluSelA = 01.
Si (EX/MEM.EscribirRegistro = ID/EX.LeerRegistro2) => AluSelB = 01.
• Riesgo MEM:
Si (MEM/WB.RegWrite = 1)
Si (MEM/WB.EscribirRegistro = ID/EX.LeerRegistro1)=> AluSelA = 10.
Si (MEM/WB.EscribirRegistro = ID/EX.LeerRegistro2)=> AluSelB = 10
Figura 9: Arquitectura segmentada con control de riesgos.
En la siguiente tabla puede observarse la relación entre las señales de control de los multiplexores
de anticipación y los operandos de la ALU. Debe recordarse que el operador uno de la ALU
viene especificado directamente por el Multiplexor A, mientras que el B genera el resultado que
será utilizado por otro multiplexor que seleccionara el segundo operador de entrada a la ALU
entre este dato y el campo dirección de la instrucción.
Control Mux Fuente Procedencia de los operándos AluSelA=00 ID/EX Operador1 proviene de los registros normales AluSelA=01 EX/MEM Se anticipa del resultado anterior de la ALU
AluSelA=10 MEM/WB Se anticipa de la memoria de datos o un resultado anterior de la ALU AluSelB=00 ID/EX Operador2 proviene de los registros normales
AluSelB=01 EX/MEM Se anticipa del resultado anterior de la ALU
AluSelB=10 MEM/WB Se anticipa de la memoria de datos o un resultado anterior de la ALU
DESCRIPCION DE LOS MODULOS
El procesador descrito en VHDL esta conformado básicamente por nueve módulos que
interconectados por medio de señales integran la arquitectura; y un modulo de acople a la tarjeta
de Visualización que transforma las señales binarias de la arquitectura en datos apropiados para
ser desplegados en dicha tarjeta.
Los nueve módulos que conforman la arquitectura son las 5 etapas de segmentación y los cuatro
registros de segmentación que las unen.
A continuación se describirán los submodulos que conforman las etapas de segmentación, los
registros de segmentación, el modulo de acople para visualizar las señales y los paquetes de
funciones, tipos de variables y constantes creadas para realizar la arquitectura.
Todos los módulos deben incluir las siguientes librerías:
• library IEEE;
o
use IEEE.STD_LOGIC_1164.ALL;
o
use IEEE.STD_LOGIC_ARITH.ALL;
o
use IEEE.STD_LOGIC_UNSIGNED.ALL;
• library UNISIM;
o
use UNISIM.VComponents.all;
• USE WORK.CONSTANTES.ALL;
• USE WORK.TIPOS_variables.ALL;
• USE WORK.FUNCIONES.ALL;
Las ultimas tres librerías han sido creadas para definir las constantes, variables globales y las
funciones que se implementaran para realizar el procesador en VHDL.
2.1 DESCRIPCION DE LIBRERIAS Y PAQUETES
2.1.1 Paquete de constantes: define los parámetros de los componentes de almacenamiento:
memoria de instrucciones, banco de registros y memoria de datos.
PACKAGE Constantes IS
CONSTANT DATA_Dirs: NATURAL := 3; --DIRECIONES EN MEMORIA DE DATOS
CONSTANT INST_Dirs: NATURAL := 8; --DIRECCIONES EN MEMORIA DE INSTRUCIONES CONSTANT NUM_Regs: NATURAL := 8; --Numero de registros en el banco de registros.
END Constantes;
2.1.2 Paquete de tipos de variables: define los tipos de variables que se van a usar en el diseño.
library IEEE;
use IEEE.STD_LOGIC_1164.all; USE WORK.Constantes.ALL; PACKAGE tipos_variables IS
-- PALABRAS DEL PROCESADOR --Tipo para las instrucciones:
SUBTYPE WORD_INST IS STD_LOGIC_VECTOR (31 DOWNTO 0);
--Tipo para los datos: El rango que se pueden representar son -127 al +127, ya que el BIT 7 es el de signo. SUBTYPE WORD IS STD_LOGIC_VECTOR ( 7 DOWNTO 0); --RANGO NUMEROS(-127, +127)
SUBTYPE WORD_1 IS STD_LOGIC_VECTOR(0 DOWNTO 0); SUBTYPE WORD_2 IS STD_LOGIC_VECTOR( 1 DOWNTO 0); SUBTYPE WORD_3 IS STD_LOGIC_VECTOR( 2 DOWNTO 0); SUBTYPE WORD_4 IS STD_LOGIC_VECTOR( 3 DOWNTO 0); SUBTYPE WORD_5 IS STD_LOGIC_VECTOR( 4 DOWNTO 0); SUBTYPE WORD_6 IS STD_LOGIC_VECTOR( 5 DOWNTO 0); SUBTYPE WORD_7 IS STD_LOGIC_VECTOR( 6 DOWNTO 0); SUBTYPE WORD_12 IS STD_LOGIC_VECTOR( 11 DOWNTO 0); SUBTYPE WORD_14 IS STD_LOGIC_VECTOR( 13 DOWNTO 0); SUBTYPE WORD_16 IS STD_LOGIC_VECTOR( 15 DOWNTO 0); SUBTYPE WORD_21 IS STD_LOGIC_VECTOR( 20 DOWNTO 0); SUBTYPE WORD_24 IS STD_LOGIC_VECTOR( 23 DOWNTO 0); SUBTYPE WORD_28 IS STD_LOGIC_VECTOR( 27 DOWNTO 0); SUBTYPE WORD_32 IS STD_LOGIC_VECTOR( 31 DOWNTO 0); SUBTYPE WORD_40 IS STD_LOGIC_VECTOR( 39 DOWNTO 0);
-- Memorias y banco de registros.
TYPE MEM_INST_WORD IS ARRAY (0 TO INST_Dirs-1) OF WORD_INST; TYPE MEM_DATOS_WORD IS ARRAY (0 TO DATA_Dirs-1) OF WORD; TYPE REGISTROS IS ARRAY (0 TO NUM_Regs-1) OF WORD; --BUSES DE CONTROL DE LAS ETAPAS DE SEGMENTACION SUBTYPE CTRL_EX IS WORD_4;
SUBTYPE CTRL_M IS WORD_3; SUBTYPE CTRL_WB IS WORD_2; END tipos_variables;
2.1.3 Paquete de funciones: contiene las funciones para conversión de datos.
PACKAGE FUNCIONES IS
FUNCTION Bin_IntC2(W: WORD) RETURN INTEGER; FUNCTION Bin_Int (W: WORD) RETURN INTEGER; FUNCTION C2 (A: WORD) RETURN WORD;
FUNCTION Int_BinC2(N: INTEGER) RETURN WORD; FUNCTION Int_Bin (N: INTEGER) RETURN WORD;
FUNCTION WORD_5_INT (CADENA: WORD_5) RETURN INTEGER; FUNCTION VISUALIZAR_1_DISPLAY (A: WORD) RETURN WORD_7; FUNCTION VISUALIZAR_2_DISPLAYS (A: WORD_6) RETURN WORD_14; FUNCTION VISUALIZAR_3_DISPLAYS (A: WORD) RETURN WORD_21; FUNCTION VISUALIZAR_INST (A: WORD_12) RETURN WORD_14;
PACKAGE BODY FUNCIONES IS
---FUNCION BINARIO A ENTERO EN COMPLEMENTO A 2--- FUNCTION Bin_IntC2 (W: WORD) RETURN INTEGER IS
VARIABLE AuxN: INTEGER; BEGIN
IF W(7) = '0' THEN
RETURN(Bin_Int(W));
ELSE
AuxN := Bin_Int(C2(W));
AuxN := AuxN - (2*ABS(AuxN));
RETURN(AuxN);
END IF;
END;
---FUNCION BINARIO A ENTERO--- FUNCTION Bin_Int (W: WORD) RETURN INTEGER IS
VARIABLE AuxN: INTEGER; BEGIN
AuxN := 0;
FOR i IN 6 DOWNTO 0 LOOP IF W(i) = '1' THEN
AuxN := AuxN + (2**i);
END IF;
END LOOP; RETURN(AuxN); END;
---FUNCION COMPLEMENTO A 2--- FUNCTION C2 (A: WORD) RETURN WORD IS
VARIABLE AuxW: WORD; VARIABLE I: INTEGER; BEGIN
FOR i IN 7 DOWNTO 0 LOOP AuxW(i) := NOT A(i); END LOOP;
AuxW := AuxW + 1; RETURN (AuxW);
END;
---FUNCION ENTERO A BINARIO--- FUNCTION Int_Bin (N: INTEGER) RETURN WORD IS
VARIABLE AuxW: WORD; VARIABLE AuxN: INTEGER; BEGIN
AuxN := N;
FOR i IN 6 DOWNTO 0 LOOP
IF ( AuxN >= (2**i)) THEN
AuxW(i) := '1';
AuxN := AuxN - (2**i);
ELSE AuxW(i) := '0'; END IF; END LOOP; RETURN (AuxW); END;
---FUNCION ENTERO A BINARIO EN COMPLEMENTO A 2--- FUNCTION Int_BinC2 (N: INTEGER) RETURN WORD IS
BEGIN IF N>0 THEN RETURN(Int_Bin(N)); ELSE RETURN(C2(Int_Bin(ABS(N)))); END IF; END;
---FUNCION DE CADENA DE 5 BITS A ENTERO--- FUNCTION WORD_5_INT (CADENA: WORD_5) RETURN INTEGER IS VARIABLE AuxW: WORD_5;
VARIABLE AuxN: INTEGER; BEGIN
AuxW := CADENA;
FOR i IN 4 DOWNTO 0 LOOP
IF AuxW(i) = '1' then
AuxN := AuxN + 2**(i);
ELSE AuxN := AuxN; END IF; END LOOP; RETURN (AuxN); END;
---FUNCION DE CONVERSIO DE UN DATO PARA SER VISUALIZADO EN UN DISPLAY--- FUNCTION VISUALIZAR_1_DISPLAY (A: WORD) RETURN WORD_7 IS
BEGIN CASE A IS WHEN "00000000" => RETURN "0111111"; WHEN "00000001" => RETURN "0000110"; WHEN "00000010" => RETURN "1011011"; WHEN "00000011" => RETURN "1001111"; WHEN "00000100" => RETURN "1100110"; WHEN "00000101" => RETURN "1101101"; WHEN "00000110" => RETURN "1111101"; WHEN "00000111" => RETURN "0000111"; WHEN OTHERS => RETURN "0111111";
END CASE;
END;
---FUNCION DE CONVERSIO DE UN DATO PARA SER VISUALIZADO EN DOS DISPLAYS--- FUNCTION VISUALIZAR_2_DISPLAYS (A: WORD_6) RETURN WORD_14 IS
BEGIN CASE A IS
WHEN "000000" => RETURN "01111110111111"; --0 WHEN "000001" => RETURN "01111110000110";--1 WHEN "000010" => RETURN "01111111011011"; --2 WHEN "000011" => RETURN "01111111001111"; --3 WHEN "000100" => RETURN "01111111100110"; --4 WHEN "000101" => RETURN "01111111101101"; --5 WHEN "000110" => RETURN "01111111111101"; --6 WHEN "000111" => RETURN "01111110000111"; --7 WHEN "001000" => RETURN "01111110111111"; --8 WHEN "001001" => RETURN "01111110000110"; --9 WHEN "001010" => RETURN "00001100111111"; --10 WHEN "001011" => RETURN "00001100000110"; --11 WHEN "001100" => RETURN "00001101011011"; --12 WHEN "001101" => RETURN "00001101001111"; --13 WHEN "001110" => RETURN "00001101100110"; --14 WHEN "001111" => RETURN "00001101101101"; --15 WHEN "010000" => RETURN "00001101111101"; --16 WHEN "010001" => RETURN "00001100000111"; --17
WHEN "010010" => RETURN "00001100111111"; --18 WHEN "010011" => RETURN "00001100000110"; --19 WHEN "010100" => RETURN "10110110111111"; --20 WHEN "010101" => RETURN "10110110000110"; --21 WHEN "010110" => RETURN "10110111011011"; --22 WHEN "010111" => RETURN "10110111001111"; --23 WHEN "011000" => RETURN "10110111100110"; --24 WHEN "011001" => RETURN "10110111101101"; --25 WHEN "011010" => RETURN "10110111111101"; --26 WHEN "011011" => RETURN "10110110000111"; --27 WHEN "011100" => RETURN "10110110111111"; --28 WHEN "011101" => RETURN "10110110000110"; --29 WHEN "011110" => RETURN "10011110111111"; --30 WHEN "011111" => RETURN "10011110000110"; --31 WHEN "100000" => RETURN "10011111011011"; --32 WHEN "100001" => RETURN "10011111001111"; --33 WHEN "100010" => RETURN "10011111100110"; --34 WHEN "100011" => RETURN "10011111101101"; --35 WHEN "100100" => RETURN "10011111111101"; --36 WHEN "100101" => RETURN "10011110000111"; --37 WHEN "100110" => RETURN "10011110111111"; --38 WHEN "100111" => RETURN "10011110000110"; --39 WHEN "101000" => RETURN "11001100111111"; --40 WHEN "101001" => RETURN "11001100000110"; --41 WHEN "101010" => RETURN "11001101011011"; --42 WHEN "101011" => RETURN "11001101001111"; --43 WHEN "101100" => RETURN "11001101100110"; --44 WHEN "101101" => RETURN "11001101101101"; --45 WHEN "101110" => RETURN "11001101111101"; --46 WHEN "101111" => RETURN "11001100000111"; --47 WHEN "110000" => RETURN "11001100111111"; --48 WHEN "110001" => RETURN "11001100000110"; --49 WHEN "110010" => RETURN "11011010111111"; --50 WHEN "110011" => RETURN "11011010000110"; --51 WHEN "110100" => RETURN "11011011011011"; --52 WHEN "110101" => RETURN "11011011001111"; --53 WHEN "110110" => RETURN "11011011100110"; --54 WHEN "110111" => RETURN "11011011101101"; --55 WHEN "111000" => RETURN "11011011111101"; --56 WHEN "111001" => RETURN "11011010000111"; --57 WHEN "111010" => RETURN "11011010111111"; --58 WHEN "111011" => RETURN "11011010000110"; --59 WHEN "111100" => RETURN "11111010000110"; --60 WHEN "111101" => RETURN "11111010000110"; --61 WHEN "111110" => RETURN "11111011011011"; --62 WHEN "111111" => RETURN "11111011001111"; --63 WHEN OTHERS => RETURN "01111110111111";
END CASE; END;
---FUNCION DE CONVERSION DE UN DATO PARA SER VISUALIZADO EN TRES DISPLAYS--- FUNCTION VISUALIZAR_3_DISPLAYS (A: WORD) RETURN WORD_21 IS
BEGIN
CASE A(6 DOWNTO 0) IS
WHEN "0000000"=>RETURN "011111101111110111111";--0 WHEN "0000001" => RETURN "011111101111110000110"; --1 WHEN "0000010" => RETURN "011111101111111011011"; --2 WHEN "0000011" => RETURN "011111101111111001111"; --3 WHEN "0000100" => RETURN "011111101111111100110"; --4 WHEN "0000101" => RETURN "011111101111111101101"; --5 WHEN "0000110" => RETURN "011111101111111111101"; --6 WHEN "0000111" => RETURN "011111101111110000111"; --7 WHEN "0001000" => RETURN "011111101111110111111"; --8 WHEN "0001001" => RETURN "011111101111110000110"; --9 WHEN "0001010" => RETURN "011111100001100111111"; --10 WHEN "0001011" => RETURN "011111100001100000110"; --11 WHEN "0001100" => RETURN "011111100001101011011"; --12 WHEN "0001101" => RETURN "011111100001101001111"; --13 WHEN "0001110" => RETURN "011111100001101100110"; --14 WHEN "0001111" => RETURN "011111100001101101101"; --15 WHEN "0010000" => RETURN "011111100001101111101"; --16 WHEN "0010001" => RETURN "011111100001100000111"; --17 WHEN "0010010" => RETURN "011111100001100111111"; --18 WHEN "0010011" => RETURN "011111100001100000110"; --19 WHEN "0010100" => RETURN "011111110110110111111"; --20 WHEN "0010101" => RETURN "011111110110110000110"; --21 WHEN "0010110" => RETURN "011111110110111011011"; --22 WHEN "0010111" => RETURN "011111110110111001111"; --23 WHEN "0011000" => RETURN "011111110110111100110"; --24
WHEN "0011001" => RETURN "011111110110111101101"; --25 WHEN "0011010" => RETURN "011111110110111111101"; --26 WHEN "0011011" => RETURN "011111110110110000111"; --27 WHEN "0011100" => RETURN "011111110110110111111"; --28 WHEN "0011101" => RETURN "011111110110110000110"; --29 WHEN "0011110" => RETURN "011111110011110111111"; --30 WHEN "0011111" => RETURN "011111110011110000110"; --31 WHEN "0100000" => RETURN "011111110011111011011"; --32 WHEN "0100001" => RETURN "011111110011111001111"; --33 WHEN "0100010" => RETURN "011111110011111100110"; --34 WHEN "0100011" => RETURN "011111110011111101101"; --35 WHEN "0100100" => RETURN "011111110011111111101"; --36 WHEN "0100101" => RETURN "011111110011110000111"; --37 WHEN "0100110" => RETURN "011111110011110111111"; --38 WHEN "0100111" => RETURN "011111110011110000110"; --39 WHEN "0101000" => RETURN "011111111001100111111"; --40 WHEN "0101001" => RETURN "011111111001100000110"; --41 WHEN "0101010" => RETURN "011111111001101011011"; --42 WHEN "0101011" => RETURN "011111111001101001111"; --43 WHEN "0101100" => RETURN "011111111001101100110"; --44 WHEN "0101101" => RETURN "011111111001101101101"; --45 WHEN "0101110" => RETURN "011111111001101111101"; --46 WHEN "0101111" => RETURN "011111111001100000111"; --47 WHEN "0110000" => RETURN "011111111001100111111"; --48 WHEN "0110001" => RETURN "011111111001100000110"; --49 WHEN "0110010" => RETURN "011111111011010111111"; --50 WHEN "0110011" => RETURN "011111111011010000110"; --51 WHEN "0110100" => RETURN "011111111011011011011"; --52 WHEN "0110101" => RETURN "011111111011011001111"; --53 WHEN "0110110" => RETURN "011111111011011100110"; --54 WHEN "0110111" => RETURN "011111111011011101101"; --55 WHEN "0111000" => RETURN "011111111011011111101"; --56 WHEN "0111001" => RETURN "011111111011010000111"; --57 WHEN "0111010" => RETURN "011111111011010111111"; --58 WHEN "0111011" => RETURN "011111111011010000110"; --59 WHEN "0111100" => RETURN "011111111111010000110"; --60 WHEN "0111101" => RETURN "011111111111010000110"; --61 WHEN "0111110" => RETURN "011111111111011011011"; --62 WHEN "0111111" => RETURN "011111111111011001111"; --63 WHEN "1000000" => RETURN "011111111111011100110"; --64 WHEN "1000001" => RETURN "011111111111011101101"; --65 WHEN "1000010" => RETURN "011111111111011111101"; --66 WHEN "1000011" => RETURN "011111111111010000111"; --67 WHEN "1000100" => RETURN "011111111111010111111"; --68 WHEN "1000101" => RETURN "011111111111010000110"; --69 WHEN "1000110" => RETURN "011111100001110111111"; --70 WHEN "1000111" => RETURN "011111100001110000110"; --71 WHEN "1001000" => RETURN "011111100001111011011"; --72 WHEN "1001001" => RETURN "011111100001111001111"; --73 WHEN "1001010" => RETURN "011111100001111100110"; --74 WHEN "1001011" => RETURN "011111100001111101101"; --75 WHEN "1001100" => RETURN "011111100001111111101"; --76 WHEN "1001101" => RETURN "011111100001110000111"; --77 WHEN "1001110" => RETURN "011111100001110111111"; --78 WHEN "1001111" => RETURN "011111100001110000110"; --79 WHEN "1010000" => RETURN "011111101111110111111"; --80
WHEN "1010001" => RETURN "011111101111110000110"; --81 WHEN "1010010" => RETURN "011111101111111011011"; --82 WHEN "1010011" => RETURN "011111101111111001111"; --83 WHEN "1010100" => RETURN "011111101111111100110"; --84 WHEN "1010101" => RETURN "011111101111111101101"; --85 WHEN "1010110" => RETURN "011111101111111111101"; --86 WHEN "1010111" => RETURN "011111101111110000111"; --87 WHEN "1011000" => RETURN "011111101111110111111"; --88 WHEN "1011001" => RETURN "011111101111110000110"; --89 WHEN "1011010" => RETURN "011111100001100111111"; --90 WHEN "1011011" => RETURN "011111100001100000110"; --91 WHEN "1011100" => RETURN "011111100001101011011"; --92 WHEN "1011101" => RETURN "011111100001101001111"; --93 WHEN "1011110" => RETURN "011111100001101100110"; --94 WHEN "1011111" => RETURN "011111100001101101101"; --95 WHEN "1100000" => RETURN "011111100001101111101"; --96 WHEN "1100001" => RETURN "011111100001100000111"; --97 WHEN "1100010" => RETURN "011111100001100111111"; --98 WHEN "1100011" => RETURN "011111100001100000110"; --99 WHEN "1100100" => RETURN "000011001111110111111"; --100 WHEN "1100101" => RETURN "000011001111110000110"; --101 WHEN "1100110" => RETURN "000011001111111011011"; --102 WHEN "1100111" => RETURN "000011001111111001111"; --103 WHEN "1101000" => RETURN "000011001111111100110"; --104 WHEN "1101001" => RETURN "000011001111111101101"; --105 WHEN "1101010" => RETURN "000011001111111111101"; --106 WHEN "1101011" => RETURN "000011001111110000111"; --107 WHEN "1101100" => RETURN "000011001111110111111"; --108 WHEN "1101101" => RETURN "000011001111110000110"; --109 WHEN "1101110" => RETURN "000011000001100111111"; --110 WHEN "1101111" => RETURN "000011000001100000110"; --111 WHEN "1110000" => RETURN "000011000001101011011"; --112 WHEN "1110001" => RETURN "000011000001101001111"; --113 WHEN "1110010" => RETURN "000011000001101100110"; --114 WHEN "1110011" => RETURN "000011000001101101101"; --115 WHEN "1110100" => RETURN "000011000001101111101"; --116 WHEN "1110101" => RETURN "000011000001100000111"; --117 WHEN "1110110" => RETURN "000011000001100111111"; --118 WHEN "1110111" => RETURN "000011000001100000110"; --119 WHEN "1111000" => RETURN "000011010110110111111"; --120 WHEN "1111001" => RETURN "000011010110110000110"; --121 WHEN "1111010" => RETURN "000011010110111011011"; --122 WHEN "1111011" => RETURN "000011010110111001111"; --123 WHEN "1111100" => RETURN "000011010110111100110"; --124 WHEN "1111101" => RETURN "000011010110111101101"; --125 WHEN "1111110" => RETURN "000011010110111111101"; --126 WHEN "1111111" => RETURN "000011010110110000111"; --127 WHEN OTHERS => RETURN "011111101111110111111"; END CASE;
---FUNCION PARA VISUALIZAR LA INSTRUCCIÓN EN DOS DISPLAYS--- FUNCTION VISUALIZAR_INST (A: WORD_12) RETURN WORD_14 IS
BEGIN
If A(11 downto 6)="000000" then return VISUALIZAR_2_DISPLAYS(A(5 downto 0));
Else return VISUALIZAR_2_DISPLAYS(A(11 downto 6));
end if;
END;
END FUNCIONES;
2.2 DESCRIPCION DE LAS FASES DE SEGMENTACION
2.2.1 FASE IF.
Esta fase recibe como señales de entrada la dirección de salto calculada en la fase EX y la
condición de salto calculada en la fase MEM. Con estas señales el mux que selecciona el nuevo
valor del PC, decide si el nuevo valor del PC será el PC incrementado o el valor de salto.
Con el valor del contador de programa establecido, se lee de la memoria de instrucciones la
instrucción a realizar.
Figura 10: Fase IF
2.2.1.1 Modulo PC:
Este deja simplemente pasar el nuevo valor del PC en cada ciclo de reloj.
Entity PC is
Port ( CLK , RESET : IN STD_LOGIC; Selec_PC : IN WORD; P_C : OUT WORD); End PC;
architecture A of PC is
Begin PROCESS (CLK, RESET, Selec_PC) variable v : WORD;
Begin
IF RESET = '1' THEN --Si se resetea el procesador, el contador de programa vuelve a cero
V := "00000000";
ELSE
IF (CLK'EVENT AND CLK = '1') THEN --Se actualiza el nuevo valor del PC
V := Selec_PC;
END IF;
P_C <= V;
End process;
end A;
2.2.1.2 Componente MemInstruc:
Este bloque contiene las instrucciones en lenguaje maquina a ser ejecutadas por el procesador. La
memoria de instrucciones es leída de acuerdo con el valor del Contador de programa, que
especifica la dirección de la instrucción a ser realizada.
ENTITY MemInstruc IS
PORT ( Reset : IN STD_LOGIC; Dir : IN WORD;
InstSal : OUT WORD_INST); END MemInstruc;
ARCHITECTURE A OF MemInstruc IS SIGNAL Memoria: MEM_INST_WORD; SIGNAL DIREC: INTEGER;
BEGIN
DIREC <= Bin_IntC2(DIR); --Convierte el valor de el acmpo dirección a un binario en complemento a 2 PROCESS (DIREC, Memoria, Reset )
BEGIN
IF (reset='1') then Se inicializa la Memoria
Memoria(0) <= "10001100000001100000000000000000"; --LW rs=0 rt=6 dir=0
Memoria(1) <= "00000000001000110011100000100010"; --RESTA rs=1 rt=3 rd=7 Memoria(2) <= "10101100000000100000000000000000"; --SW rs=0 rt=2 dir=0 Memoria(3) <= "00000000100000110010100000101010"; --SLT rs=4 rt=3 rd=5 Memoria(4) <= "00000000100000000000100000000111"; --XX Operación no existente Memoria(5) <= "10101100000000100000000000000100"; --SW rs=0 rt=2 dir=4 Memoria(6) <= "00000000110001000001000000100101"; --OR rs=6 rt=4 rd=2 Memoria(7) <= "00010000101000000000000000000010"; --BEQ rs=5 rt=0 dir=2
InstSal <="00000000000000000000000000000000"; ELSE
if (DIREC>=0)AND(DIREC<INST_Dirs) THEN InstSal <= Memoria(ABS(DIREC));
else InstSal <="00000000000000000000000000000000"; End if; END IF; END PROCESS; END A;
2.2.1.3 Componente PC_Add:
Incrementa el valor del PC actual. Recibe como entrada el valor del Contador de programa y lo
incrementa para que apunte en la siguiente dirección secuencial para leer la correspondiente
instrucción a ejecutar del componente Memoria de instrucciones.
Como se ha construido una memoria de instrucciones de 8 posiciones de 32 bits, este componente
se cerciora de poder aumentar el valor del PC para no salirse del rango entre 0 y 7.
Entity PC_Add is
architecture A of PC_Add is
SIGNAL VAR : WORD; SIGNAL P_C : INTEGER; BEGIN Process(CLK, RESET, PC, VAR)
BEGIN
P_C <= Bin_IntC2(PC);
IF RESET='1' THEN VAR <= "00000000";
ELSE
IF (CLK'EVENT AND CLK='1') THEN
if (P_C>=0 AND P_C<=6)then VAR <= PC + 1;
else VAR <= "00000000"; end if; END IF; END IF; PC4<=VAR; End Process; end A;
2.2.1.4 Componente Mux_PC:
Selecciona el nuevo valor del PC a ser utilizado en el siguiente ciclo de reloj. Si la señal de
control del multiplexor se encuentra activa el nuevo PC será la dirección de salto calculada en la
fase EX o el valor actual incrementado en uno.
Entity mux_PC is
Port ( RESET : IN STD_LOGIC; PCSrc : IN STD_LOGIC; Salto_PC : IN WORD; PC4 : IN WORD; selec_PC : OUT WORD);
end mux_PC;
architecture A of mux_PC is
begin PROCESS (RESET, PCSrc, Salto_PC, PC4) variable var: WORD;
Begin
IF RESET='1' THEN VAR := "00000000";
ELSE
if PCSrc='1' then VAR := Salto_PC;
else VAR := PC4; end if; END IF; selec_PC<=var; End process; end A;
2.2.1.5 Componente Fase IF:
Este componente es simplemente la interconexión de los submodulos previamente descritos.
ENTITY FASE_IF IS
PORT ( Clk, RESET : IN STD_LOGIC; Salto_PC : IN WORD; PCSrc : IN STD_LOGIC;
OUT_PC, OUT_PC4 : INOUT WORD; OUT_INST : OUT WORD_INST ); END FASE_IF;
COMPONENT MUX_PC
PORT ( RESET, PCSrc : IN STD_LOGIC; Salto_PC : IN WORD; PC4 : IN WORD;
COMPONENT PC_Add
PORT ( CLK, RESET : IN STD_LOGIC; PC : IN WORD;
PC4 : OUT WORD); END COMPONENT;
COMPONENT PC
PORT ( CLK : IN STD_LOGIC; RESET : IN STD_LOGIC; Selec_PC : IN WORD;
P_C : OUT WORD); END COMPONENT;
COMPONENT MemInstruc
PORT ( Reset : IN STD_LOGIC; Dir : IN WORD;
InstSal : OUT WORD_INST); END COMPONENT;
SIGNAL selec_PC : WORD; BEGIN
Component_1 : MUX_PC PORT MAP ( RESET, PCSrc, Salto_PC, OUT_PC4, selec_PC);
Component_2 : PC PORT MAP ( CLK, RESET, selec_PC, OUT_PC);
Component_3 : PC_add PORT MAP ( CLK, RESET, Selec_PC, OUT_PC4);
Component_4 : MemInstruc PORT MAP ( RESET, OUT_PC, OUT_INST);
END A;
2.2.2. FASE ID
Recibe como entradas la instrucción a decodificar, las señales de escritura del bloque de registros,
la dirección de registro a escribir y el dato. Y genera los datos para la etapa de ejecución EX
leídos del archivo de registros, las señales de control para las siguientes etapas y separa la
información de los campos que conforman la instrucción.
El banco de registros es un bloque construido en base a un arreglo con posiciones de datos de 8
bits. La unidad de control esta implementada por medio de un case, que dependiendo de el campo
OP genera el control para las etapas restantes.
Figura 11: Fase ID
2.2.2.1 Componente Decodificacion_Inst:
Este modulo separa los diferentes campos de la instrucción leída de memoria en la fase IF.
entity Decodificacion_Inst is
port ( Inst : IN WORD_INST;
RS, RT, RD : OUT WORD_5; Dir : OUT WORD_16; OUT_Cod_Op : OUT WORD_6; OUT_Cod_FUNC : OUT WORD_6);
architecture A of Decodificacion_Inst is begin PROCESS (Inst)
BEGIN
OUT_Cod_Op <= INST(31 DOWNTO 26);
RS <= INST(25 DOWNTO 21); --RS (LEER REG 1)
RT <= INST(20 DOWNTO 16); --RT (LEER REG 2)
RD <= INST(15 DOWNTO 11); DIR <= INST(15 DOWNTO 0);
OUT_Cod_FUNC <= INST(5 DOWNTO 0); END PROCESS;
End A;
2.2.2.2 Componente Control:
Crea las señales de control por etapas, para todos los elementos que conforman el camino de
datos dependiendo solamente del código de operación de la instrucción (ver tabla 2).
ENTITY Control IS
PORT ( RESET : IN STD_LOGIC; OpCode : IN WORD_6;
EX : OUT CTRL_EX; M : OUT CTRL_M; WB : OUT CTRL_WB ); END Control;
ARCHITECTURE A OF Control IS
SIGNAL RegDst, AluScr, MemToReg, RegWrite, MemRead, MemWrite, Branch: STD_LOGIC; SIGNAL AluOp: WORD_2;
BEGIN PROCESS(OpCode,RESET) BEGIN
CASE RESET IS
WHEN '1'=> RegDst <= '0'; AluScr <= '0'; MemToReg <= '0'; RegWrite <= '0'; MemRead <= '0'; MemWrite <= '0'; Branch <= '0'; AluOp <= "00";
WHEN '0'=>
CASE OpCode IS
WHEN "000000" => --FORMATO R
RegDst <= '1'; AluScr <= '0'; MemToReg <= '0';
RegWrite <= '1'; MemRead <= '0'; MemWrite <= '0';
Branch <= '0'; AluOp <= "10";
WHEN "100011" => --LW
RegDst <= '0'; AluScr <= '1'; MemToReg <= '1';
RegWrite <= '1'; MemRead <= '1'; MemWrite <= '0';
Branch <= '0'; AluOp <= "00";
WHEN "101011" => --SW
RegDst <= '1'; AluScr <= '1'; MemToReg <= '1';
RegWrite <= '0'; MemRead <= '0'; MemWrite <= '1'; Branch <= '0'; AluOp <= "00";
WHEN "000100" => --BEQ
RegDst <= '1'; AluScr <= '0'; MemToReg <= '1';
RegWrite <= '0'; MemRead <= '0'; MemWrite <= '0';
WHEN OTHERS=>
RegDst <= '0'; AluScr <= '0'; MemToReg <= '0';
RegWrite <= '0'; MemRead <= '0'; MemWrite <= '0';
Branch <= '0'; AluOp <= "00";
END CASE;
WHEN OTHERS => RegDst <= '0'; AluScr <= '0'; MemToReg <= '0';
RegWrite <= '0'; MemRead <= '0'; MemWrite <= '0';
Branch <= '0'; AluOp <= "00"; END CASE;
EX(0) <= RegDst;
EX(2 DOWNTO 1) <= AluOp; EX(3) <= AluScr; M(0) <= Branch; M(1) <= MemRead; M(2) <= MemWrite; WB(0) <= RegWrite; WB(1) <= MemToReg; END PROCESS; END A;
2.2.2.3 Componente BancoRegistros:
Contiene los registros de 8 bits que se utilizaran para cargar datos de memoria y guardar el
resultado de las operaciones.
Se construyo por medio de un vector de 8 posiciones de 8 bits, los cuales se inicializan con el
dato de la ubicación que ocupan dentro del arreglo, es decir el registro cero contendrá el valor
cero y el registro ocho contendrá el valor 7. Este bloque podrá ser leído en cualquier momento,
pero su escritura esta restringida a cada flanco de subida del reloj y a la activación de la señal
escribir registros RegWrite.
ENTITY BancoRegistros IS
PORT ( Clk, RESET, RegWrite : IN STD_LOGIC; Leer_Reg1, Leer_Reg2 , Reg_Esc : IN WORD_5; Dato_Esc: IN WORD; Dato1,Dato2 : OUT WORD);
END BancoRegistros;
ARCHITECTURE A OF BancoRegistros IS SIGNAL Registros_MATRIX: REGISTROS;
SIGNAL IND_Read_1, IND_Read_2, IND_Write: INTEGER; BEGIN
PROCESS(RESET, Clk, Leer_Reg1, Leer_Reg2, REGISTROS_MATRIX,RegWrite, Reg_Esc, Dato_Esc) BEGIN
IND_Read_1 <= WORD_5_INT(Leer_Reg1); IND_Read_2 <= WORD_5_INT(Leer_Reg2); IND_Write <= WORD_5_INT(Reg_Esc);
IF RESET='1' THEN --se inicializan los registros del 0 al 7 con los números de posición FOR i IN 0 TO Num_Regs-1 LOOP
Registros_MATRIX(i)<=CONV_STD_LOGIC_VECTOR(i,8);
ELSE -- Escritura
IF (CLK'event AND CLK='1' AND RegWrite='1' AND Reg_Esc>= 0 AND Reg_Esc<Num_Regs) THEN Registros_MATRIX(ABS(IND_Write))<=Dato_Esc;
End if;
-- Lectura
IF (Leer_Reg1>=0) AND (Leer_Reg1<Num_Regs) THEN
Dato1<=Registros_MATRIX(ABS(IND_Read_1)); ELSE Dato1<="00000000"; End if; IF (Leer_Reg2>=0)AND(Leer_Reg2<Num_Regs) THEN Dato2<=Registros_MATRIX(ABS(IND_Read_2)); ELSE Dato2<="00000000"; END IF; END IF; END PROCESS; END A;
2.2.2.4 Componente Fase ID:
En este componente se interconectan los submodulos que lo conforman.
ENTITY FASE_ID IS
PORT( Clk : IN STD_LOGIC; --Clock
RESET : IN STD_LOGIC; --RESET EXTERNO
RegWrite : IN STD_LOGIC; --Escribir Registros
Reg_to_write : IN WORD_5; --Registro a escribir
Dato_a_escr : IN WORD; --Dato a escribir
Inst : IN WORD_INST; --Instrucción
Out_EX : OUT CTRL_EX; --señales de fase EX
Out_M : OUT CTRL_M; --señales de fase MEM
Out_WB : OUT CTRL_WB; --señales de fase WB
Dato1,Dato2 : OUT WORD; --Datos leídos
RD : OUT WORD_5 --campos RD
RT,RS : INOUT WORD_5; --campos RT,RS
Dir : OUT WORD_16; --campos Dirección
OUT_FUNC : OUT WORD_6); --campo function
END FASE_ID;
ARCHITECTURE A OF Fase_ID IS COMPONENT Decodificacion_Inst
PORT( Inst : IN WORD_INST; RS, RT, RD : OUT WORD_5; Dir : OUT WORD_16; OUT_Cod_Op : OUT WORD_6; OUT_Cod_FUNC : OUT WORD_6); END COMPONENT;
COMPONENT Control
PORT( RESET : IN STD_LOGIC; OpCode : IN WORD_6; EX : OUT CTRL_EX;
M : OUT CTRL_M; WB : OUT CTRL_WB); END COMPONENT;
COMPONENT BancoRegistros
PORT ( Clk : IN STD_LOGIC; RESET : IN STD_LOGIC; RegWrite : IN STD_LOGIC;
Leer_Reg1, Leer_Reg2 : IN WORD_5; Reg_Esc : IN WORD_5; Dato_Esc : IN WORD; Dato1,Dato2 : OUT WORD); END COMPONENT;
SIGNAL Cod_Op: WORD_6; BEGIN
COMPONENT1: Decodificacion_Inst
PORT MAP ( Inst, RS, RT, RD, Dir, Cod_Op, OUT_FUNC); COMPONENTE2: BancoRegistros
PORT MAP ( Clk, RESET, RegWrite, RS, RT, Reg_to_write, Dato_a_escr, Dato1, Dato2); COMPONENTE3: Control
PORT MAP ( RESET, Cod_Op, Out_EX, Out_M, Out_WB); END A;
2.2.3 FASE EX.
Esta conformada por ocho módulos: cuatro multiplexores, un sumador, la ALU y las unidades de
control de la ALU y de anticipación.
Figura 12: Fase EX
2.2.3.1 Componente DIR_Salto:
Es un sumador que calcula la dirección de salto del contador de programa, sumando el valor
inmediato del PC con el campo dirección de la instrucción.
Entity DIR_SALTO is
port ( PC4 : IN WORD; Dir : IN WORD_16; DirSalto : OUT WORD);
end DIR_SALTO;
architecture A of DIR_SALTO is Begin PROCESS (Dir,PC4) VARIABLE VAR:WORD_16; BEGIN
--CALCULO DIR. DE SALTO VAR := (Dir + PC4);
IF (VAR <= "0000000000000111") THEN DIRSALTO <= VAR(7 DOWNTO 0); ELSE DIRSALTO <= PC4; END IF; END PROCESS; end A;
2.2.3.2 Componente MUX_A:
Multiplexor que selecciona el primer operando de la ALU. Este puede ser el primer dato leído la
unidad de registros o algún valor anticipado cómo el resultado de la ALU o el Dato a escribir en
el banco de registros del anterior ciclo de reloj.
Entity MUX_A is
PORT ( SEL_A : IN WORD_2; Dato1Reg, DATO_MEM_memoria, DATO_WB_dato_esc : IN WORD; Operador_A : OUT WORD);
end MUX_A;
architecture A of MUX_A is
begin PROCESS(SEL_A, Dato1Reg, DATO_MEM_memoria, DATO_WB_dato_esc) begin
CASE SEL_A IS
WHEN "00" => Operador_A <= DATO1Reg;
WHEN "01" => Operador_A <= DATO_MEM_memoria; WHEN "10" => Operador_A <= DATO_WB_dato_esc; WHEN OTHERS => Operador_A <= "10000000";
END CASE;
END PROCESS;
end A;
2.2.3.3 Componente MUX_B:
Multiplexor que selecciona una opción para el primer operando de la ALU, que después podrá ser
seleccionado en el siguiente multiplexor. Este puede ser el segundo dato leído la unidad de
registros o algún valor anticipado cómo el resultado de la ALU o el Dato a escribir en el banco de
registros del anterior ciclo de reloj.
Entity MUX_B is
PORT ( SEL_B : IN WORD_2; Dato2Reg, DATO_MEM_memoria, DATO_WB_dato_esc : IN WORD; Operador_B : OUT WORD);
architecture A of MUX_B is
Begin PROCESS(SEL_B, Dato2Reg, DATO_MEM_memoria, DATO_WB_dato_esc) begin
CASE SEL_B IS
WHEN "00" => Operador_B <= DATO2Reg;
WHEN "01" => Operador_B <= DATO_MEM_memoria ; WHEN "10" => Operador_B <= DATO_WB_dato_esc; WHEN OTHERS => Operador_B <= "10000000";
END CASE;
END PROCESS; End A;
2.2.3.4 Componente MUX_ALU:
Multiplexor que selecciona el segundo operando de la ALU entre el valor proporcionado por el
componente MUX_B y el campo dirección.
Entity mux_ALU is
PORT ( ALUScr : IN STD_LOGIC; Operador_B : IN WORD;
DIR : IN WORD_16; OP2Alu : OUT WORD);
end mux_ALU;
architecture A of mux_ALU is begin
PROCESS (ALUScr, Dir, Operador_B) --SELECCION DE ENTRADA A LA ALU VARIABLE VAR: WORD_16;
BEGIN
IF (ALUScr='0') THEN
VAR := "00000000" & Operador_B; --DATO2 ES MUX_ANT_B
ELSE VAR := Dir;
END IF;
OP2Alu <= VAR(7 DOWNTO 0); END PROCESS;
end A;
2.2.2.5 Componente ALU:
La Unidad Aritmético Lógica se construyo en base a estamentos IF y CASE dependiendo del la
señal de control de la ALU (ver tabla 3) , con la que se escoge la operación a realizar. Para
establecer la señal Zero, se observa el resultado y se pone la bandera a ‘1’ si este es cero
(“00000000”).
ENTITY Alu IS
PORT ( A,B : IN WORD; Control : IN WORD_3; RESULT : INOUT WORD; Zero : OUT STD_LOGIC); END Alu;
ARCHITECTURE A OF Alu IS BEGIN
PROCESS (A,B,Control) variable R : WORD;
BEGIN
CASE CONTROL IS
WHEN "000" => R:= (A AND B); -- AND WHEN "001" => R:= (A OR B); -- OR
WHEN "010" => R:= (A + B); -- SUMA
WHEN "110" => R:= (A - B); -- RESTA
WHEN "111" => -- SET ON LESS THAN
IF (A < B) THEN R:= "00000001"; ELSE R:= "00000000"; END IF; WHEN OTHERS => R:= "10000000"; END CASE; RESULT <= R; END PROCESS;
PROCESS(RESULT) BEGIN -- Cálculo de la salida Zero. IF RESULT = "000000000" THEN Zero <= '1'; ELSE Zero <= '0'; END IF; END PROCESS; END A;
2.2.3.6 Componente MUX_REG_DST:
Selecciona el registro que va a ser escrito dependiendo de la operación a ser realizada. Para una
operación tipo R será seleccionado el registro especificado en el campo RD, mientras que para la
de transferencia de datos será el del campo RT.
Entity MUX_REG_DST is
port ( RegDst : IN STD_LOGIC; RD, RT : IN WORD_5;
Reg_Esc : OUT WORD_5);
end MUX_REG_DST; architecture A of MUX_REG_DST is begin PROCESS (RegDst, RD, RT) BEGIN IF (RegDst='0') THEN Reg_Esc <= RT; ELSE Reg_Esc <= RD; END IF; END PROCESS; end A;