Señales de control

Anuncio
Fundamentos de los Computadores
Guión de la práctica 4. Fecha de entrega:
● Grupo A: 15/Enero
● Grupo B: 14/Enero
● Grupo C: 13/Enero
Objetivo de la práctica
En esta práctica se terminará la construcción del microprocesador ARC. La ruta de datos ya está
diseñada: sus componentes se desarrollaron en las prácticas anteriores (ALU, banco de registros
y PC). Ahora sólo hace falta crear la unidad de control y juntar todos los componentes para
tener ARC funcionando. Normalmente, la integración de todas las partes suele ser la parte de un
proyecto que más problemas genera.
Unidad de control
Se va a implementar una unidad de control cableada. Se utilizará un autómata con 4 estados.
•
•
•
•
RESET: estado al que se pasa cuando se recibe un reset asíncrono (activo a nivel bajo). Al
liberarse el reset, pasa incondicionalmente al estado de captura
CAPTURA: se obtiene la próxima instrucción desde la memoria, y se escribe en el registro de
instrucciones (IR). A continuación pasa siempre al estado de ejecución.
EJECUCIÓN: se decodifica y se ejecuta la instrucción, esto es, se actualiza el registro de
resultado, los flags y el PC. A continuación pasa siempre al estado de escritura.
ESCRITURA: se escriben los resultados de la instrucción, bien en el banco de memoria o en
la memoria. A continuación pasa siempre al estado de captura.
A partir del estado actual, de la instrucción en ejecución (los contenidos del registro IR) y de los
flags, se irán generando todas las señales de control. Estas señales son:
•
•
•
•
•
•
•
•
•
•
•
•
•
•
IR_WE: habilitación de carga para el registro de instrucciones (IR). Se activa en el estado de
captura.
MEM_REQ: indica un acceso a memoria en el ciclo actual. Se activa en el estado de captura,
y en el de escritura cuando la instrucción sea un load o un store
MEM_WRITE: indica que el acceso a memoria señalado por MEM_REQ es de escritura. Se
activa en el estado de escritura, cuando haya un store.
PC_JUMP: se debe activar cuando haya una instrucción jmpl
PC_CALL: se debe activar cuando haya una instrucción call
PC_BRANCH: se debe activar cuando haya una instrucción de branch que sea efectiva (el
valor de los flags se corresponda con es esperado por la instrucción en particular, p.ej. para
be esta señal se activará solo si FLAG_Z vale uno)
PC_UPDATE: se activa siempre al pasar por el estado de ejecución
RD_FROM_SETHI: indica que la entrada al banco de registros se hace desde los datos
inmediatos provenientes de la instrucción, que se pondrán en las posiciones más
significativas. Se debe activar cuando haya una instrucción sethi
RD_FROM_MEM: indica que la entrada al banco de registros se hace desde la memoria. Se
debe activar cuando haya una instrucción load.
REGS_WE: se debe activar al pasar por el estado de escritura, siempre que no se trate de
una instrucción de store o de branch
RD_ADDR: se debe utilizar el valor apuntado en la propia instrucción, salvo para el call, que
siempre usa el registro 15.
ALU_FUNC: se puede obtener como IR(24)&IR(21 downto 19), salvo en jmpl, load y store,
que se debe fijar siempre el código de la suma.
ALU_IMM: indica que para la operación de la ALU se emplea el dato inmediato presente en la
instrucción. Se corresponde con IR(13).
FLAGS_WE: se debe activar en el estado de ejecución sólo para las instrucciones tipo cc,
que actúan sobre los códigos de condición.
•
•
•
RESULT_FROM_PC: indica que el registro de resultado se debe cargar no con los datos
provenientes de la ALU, sino con el PC. Se activa con las instrucciones call y jmpl.
RESULT_WE: carga del registro de resultado, se activa siempre en el estado de ejecución
ADDR_FROM_PC: salvo en las instrucciones de acceso a memoria, load y store, esta señal
estará activada para indicar que los datos para el bus de direcciones provienen del PC.
Implementar el microprocesador ARC
Una vez que se tienen todos los componentes, se deben juntar en el módulo ARC.VHD tal y
como indica en el esquema situado al final de este guión.
Para ello, se utilizará diseño jerárquico, donde los componentes que se instanciarán son:
•
•
•
•
ALU.VHD (Prácticas anteriores)
REGS.VHD (Prácticas anteriores)
REG-PC.VHD (Prácticas anteriores)
CTRL.VHD (apartado anterior)
Mientras que el resto de componentes (registro de resultado, registro de estado (flags) y diversos
multiplexores) se crearán empleando procesos y/o asignaciones concurrentes. Esto es
porque son componentes muy sencillos, y probablemente no valga la pena utilizar diseño
jerárquico en ellos.
El microprocesador, ARC.VHD, tendrá la siguiente interfaz:
entity ARC is
port(
end ARC;
CLK
nRST
DATA_IN
DATA_OUT
ADDR
WRITE
MEM_WAIT
REQ
);
:
:
:
:
:
:
:
:
in STD_LOGIC;
in STD_LOGIC;
in STD_LOGIC_VECTOR(31 downto 0);
out STD_LOGIC_VECTOR(31 downto 0);
out STD_LOGIC_VECTOR(31 downto 0);
out STD_LOGIC;
in STD_LOGIC
out STD_LOGIC
Donde:
•
CLK es el reloj del sistema
•
nRST es la señal del reset.
DATA_IN y DATA_OUT son los buses de datos de entrada y salida respectivamente
ADDR es el bus de direcciones
WRITE es la señal que indica que el ciclo actual de acceso a la memoria es de escritura
REQ indica que en el ciclo actual hay un acceso a la memoria
MEM_WAIT: Indica que la memoria está ocupada
•
•
•
•
•
El protocolo de acceso a la memoria es síncrono. Tras el flanco de subida que da comienzo a un
ciclo de reloj, el microprocesador sube REQ para indicar que quiere acceder a la memoria. Si el
acceso va a ser de lectura, se deja la señal WRITE a 0. La memoria prepara el dato y lo deja en
DATA_IN, de tal manera que en el siguiente flanco de reloj el microprocesador lo capturará. Sin
embargo, si el ciclo es de escritura, se pone a 1 la señal WRITE y se deja el dato de salida en
DATA_OUT. La memoria lo guardará en el siguiente ciclo de reloj. Todo esto está resuelto con la
codificación que se ha hecho de la unidad de control, por lo que en un principio no hay que hacer
nada nuevo.
Como probarlo todo
Para probar el microprocesador se proporcionan dos archivos adicionales, ARC_TB.VHD y
MEM.VHD. El primero es un sistema completo, que incluye ARC, las memorias y procesos para
generar el reloj y el reset. Por otro lado, MEM.VHD es un sencillo modelo de memoria.
Las pruebas se harán ejecutando un programa en el microprocesador, y viendo con el visor de
formas de onda (Waveform Viewer) que los resultados son correctos. Por supuesto, también se
puede modificar el código del testbench para observar estos resultados de una manera
automatizada, pero esto no es necesario. Se deja al criterio del diseñador. Los pasos son los
siguientes:
•
Crear el programa de pruebas, ensamblarlo y ejecutarlo en el ensamblador, y comprobar
que en efecto funciona como se espera.
• Renombrar el archivo .bin como prog.bin (es el nombre que espera MEM.VHD) y copiarlo
en el directorio del proyecto de ModelSim
• Ejecutar la simulación VHDL, y comprobar que los resultados son los esperados
Esto es así porque la memoria se inicia a sí misma con los contenidos del archivo prog.bin, de
tal manera que el microprocesador cuando empiece a leer de ella (a partir de la posición 0)
comenzará a ejecutar el programa.
Para comprobar que el microprocesador funciona correctamente, se recomienda hacer al menos
dos pruebas:
•
•
Una que ejecute varias veces cada instrucción, para ver que cada una por separado
funciona bien
Otra ya más completa, que sea ejecutar un algoritmo sencillo, para ver que programas
completos funcionan bien. Un ejemplo típico de esto es la serie de Fibonacci, o
multiplicar/dividir dos números, etc...
Microprocesador básico vs microprocesador avanzado
El ensamblador no sólo soporta las instrucciones básicas de ARC:
•
sethi, be, bcs, bneg, bvs, ba, call, jmpl, addcc, andcc, subcc, orcc, orncc, xorcc, srl
Sino que soporta otras más:
•
add, sub, and, or, orn, xor, bne, bcc, bpos, bvc, sll, sra
Los nuevos códigos de operación son:
Instrucción
add
sub
and
or
orn
sll
sra
srl
OP3
000000
000100
000001
000010
000110
100101
100111
100110
Instrucción
bne
bcc
bpos
bvc
COND
01001
01101
01110
01111
Las instrucciones de salto en este caso son efectivas cuando su correspondiente flag es 0 (p.ej,
bne salta cuando FLAG_Z es cero)
Ejercicios
•
Ejercicio obligatorio: Implementar el microprocesador ARC, y probar su correcto
funcionamiento. Se deberán entregar los siguientes archivos
o ARC_TB.VHD
o MEM.VHD
o ARC.VHD
o ALU.VHD
o REGS.VHD
o CTRL.VHD
o REG-PC.VHD
o Cualquier otro código VHDL que se haya desarrollado, aunque lo más habitual es
que con los archivos anteriores sea suficiente para implementar ARC
completamente.
o Programa de prueba de todas las instrucciones, instr.asm
o Programa de prueba de funcionalidad total, func.asm (serie de fibonacci,
multiplicación de dos números, etc...)
•
Ejercicio optativo: Implementar ARC teniendo en cuenta para que pueda ejecutar el
conjunto de instrucciones avanzado.
Todos estos archivos se deben comprimir en un ZIP llamado FCO_4_Y_ZZ.ZIP (donde Y es el
turno y Z es el grupo), que se debe dejar en el área de entrega de prácticas de la web de la
Escuela, como se hizo con el resto de prácticas.
PC_JUMP
nRST
PC_BRANCH
CLK
PC_CALL
PC_UPDATE
DATA_IN
IR[21..0] & "0000000000"
MEM_REQ
RD_FROM_SETHI
RD_FROM_SETHI
IR[31..0]
MEM_WRITE
RD_FROM_MEM
CTRL
REGS_WE
RD_FROM_MEM
RD_ADDR
REGS_WE
CLK
WE
REGS
RS1
ALU_FUNC
ALU_IMM
FLAG_N
RD_IN
RD_ADDR
RD_ADDR
RS1_ADDR
IR[18..14]
RS2_ADDR
IR[4..0]
RD_OUT
FLAG_Z
FLAGS_WE
FLAG_V
RESULT_FROM_PC
FLAG_C
RESULT_WE
ADDR_FROM_PC
IR_WE
RS2
SXT(IR[12..0])
DATA_OUT
DATA_IN
ALU_IMM
IR
CLK
OP1
OP2
ALU
RES
N
Z
FUNC
V
ALU_FUNC
C
FLAGS
WE
FLAGS_WE
CLK
PC_UPDATE
FLAG_C
FLAG_V
FLAG_Z
FLAG_N
nRST
JUMP_ADDR
UPDATE
nRST
PC
ADDR_FROM_PC
JUMP
BRANCH
CALL
PC
RESULT_WE
CLK
IR[29..0]
SHORT_DISP LONG_DISP
CLK
RESULT_FROM_PC
ADDR
IR_WE
IR[31..0]
IR[21..0]
RESULT WE
WE
PC_JUMP
PC_BRANCH
PC_CALL
Descargar