UNIVERSIDAD POLITÉCNICA DE VICTORIA

MAESTRÍA EN INGENIERÍA

ESPECIALIDAD: MECATRÓNICA

ASIGNATURA: PROCESADORES DIGITALES

CATEDRÁTICO: DR. MARCO AURELIO NUÑO MAGANDA

ALUMNO: JOSUÉ HELÍ JIMÉNEZ ARTEAGA

REPORTE DE PRÁCTICA: 07

DATAPATH PIPELINE DEL PROCESADOR MIPS
INTRODUCCIÓN Se implementará el datapath pipeline del procesador MIPS básico, pero solo ejecutará instrucciones de acceso a memoria, por lo que se simplificará toda la lógica de control necesaria, así como los elementos de almacenamiento que no sean utilizados para el proyecto propuesto. El diseño realizado se verificará utilizando testbenches, almacenando en un archivo de texto las instrucciones codificadas en binario de un programa que emplee las instrucciones soportadas en la implementación. El “pipelining” es una técnica de implementación en la cual múltiples instrucciones se superponen durante la ejecución. Dicha técnica mejora el desempeño incrementando el rendimiento por instrucción (throughput), pero sin disminuir el tiempo de ejecución de cada instrucción individualmente. Todas las instrucciones MIPS tienen la misma longitud, lo que hace mucho más fácil captar cada instrucción en la primera etapa y decodificarla en la segunda. MIPS solo tiene pocos formatos de instrucción, donde los campos de registros fuente están localizados en la misma posición en cada instrucción. La segunda etapa puede estar leyendo el archivo de registros al mismo tiempo que se determina qué tipo de instrucción fue leída. Los operandos de memoria solo aparecen en instrucciones de carga y almacenamiento en MIPS. Se puede usar la etapa de ejecución para calcular la dirección de memoria y después accederla en la siguiente etapa. En la última etapa, los datos solicitados pueden ser transferidos entre el procesador y la memoria. (1)

Figura 1. Diagrama a bloques del datapath pipeline

(2)

1

En la figura 1 es mostrado el diagrama a bloques del datapath pipeline del procesador MIPS, indicando las señales de control. Estas señales son transferidas a las siguientes etapas para definir el comportamiento de los elementos contenidos en cada una.

DESARROLLO Dado que solo se ejecutarán instrucciones de acceso a memoria, y de carga inmediata, se simplificará el diseño a realizar, quedando como se muestra en la figura 2. Las dos ALU solo realizarán operaciones de suma, por lo que no se necesitará un bloque de control de ALU. Al contador de programa solo se incrementará en 1 ya que las instrucciones estarán almacenadas en líneas consecutivamente numeradas.

Figura 2. Simplificaciones hechas al datapath pipeline

El bloque de control simplificado solo para instrucciones de acceso a memoria y carga de inmediato se define a continuación:

Entrada

Salida

Op5 Op4 Op3 Op2 Op1 Op0 MemToReg RegWrite MemRead MemWrite LW SW LI (ORI) 1 1 0 0 0 0 0 1 1 0 0 1 1 1 0 1 1 1 1 0 0 1 0 1 1 0 0 0 1 0

2

A continuación se muestran los códigos de las instrucciones soportadas por el modelo de datapath pipeline de esta práctica:

lw Rt, offset(Rs) Rt = Memoria[Rs + offset] OpCode Rs Rt Offset 1 0 0 0 1 1 s s s s s t t t t t i i i i i i i i i i i i i i i I

ori Rt, Rs, Inmediato Rt <= Rs OR Inmediato OpCode Rs Rt Inmediato 0 0 1 1 0 1 s s s s s t t t t t i i i i i i i i i i i i i i i i

sw Rt, offset(Rs) Memoria[Rs + offset] = Rt OpCode Rs Rt Offset 1 0 1 0 1 1 s s s s s t t t t t i i i i i i i i i i i i i i i I

Para implementar la instrucción LI a partir de ORI, se utiliza como Rs el registro $0, cuyo contenido es 0. Y para no hacer más modificaciones a la ALU, se usó la operación de suma, ya que en este caso, se obtiene el mismo resultado. Contando solo con las tres instrucciones anteriores, se realizarán programas sencillos que ayudarán a comprobar la funcionalidad del diseño implementado del datapath pipeline. Estos programas estarán almacenados en archivos de texto (.TXT), organizados de una instrucción de 32 bits por línea. El bloque de Memoria de Instrucciones almacenará cada línea obtenida del archivo de texto indicado. Cada ciclo de reloj, una nueva instrucción será leída.

3

RESULTADOS En un diseño de datapath pipeline, a cada instrucción le toma en total 5 ciclos de reloj para ejecutarse. Cada instrucción comenzará a ejecutarse un ciclo de reloj después de la anterior, de manera que no habrá que esperar a que termine una por completo (5 ciclos) antes de empezar a ejecutar la siguiente. Prueba: Invertir el orden de valores guardados en registros Archivo: InvertirValores.txt Descripción: 1. Se cargan valores inmediatos en los registros 1 a 4 2. Se almacena el contenido de cada registro en una localidad de memoria 3. Se carga el contenido de la memoria nuevamente en los registros, pero en orden inverso.

Figura 3. Se invierte el contenido de los registros.

En la figura 3 se observa que hasta el quinto ciclo es cuando se termina de ejecutar la primera instrucción, en la que se carga al registro 1 con el valor 1. En el ciclo siguiente se termina de ejecutar la carga del registro 2, y así sucesivamente. En el octavo ciclo coincide la carga del registro 4, y al mismo tiempo se está almacenando en memoria el contenido del registro 1. En los ciclos siguientes se cargan las demás localidades de memoria con el contenido del registro respectivo. A partir del décimo tercer ciclo, se carga en los registros el contenido de las memorias de la siguiente manera: en el registro 4, el contenido de la memoria 0; en el registro 3, el de la memoria 1; en el registro 2, el de la memoria 2; y en el registro 1, el de la memoria 3. Quedando invertido el orden de los valores en los registros, con respecto al orden inicial de carga inmediata.

Prueba: Desplazar valores entre registros Archivo: Desplazamiento.txt Descripción: 1. Se cargan valores inmediatos en los registros 1 a 4 2. Se almacena el contenido de cada registro en una localidad de memoria 3. Se empieza a cargar el contenido de la primera memoria en cada uno de los registros 4. Ahora se carga el contenido de la segunda memoria en cada registro. Y así sucesivamente hasta haber cargado el contenido de cada memoria.
4

Figura 4. Se desplazan valores entre registros.

En la figura 4, nuevamente se observa que la primera carga se concluye en el quinto ciclo; a partir de ese instante, se empiezan a cargar los registros siguientes. Cuando se carga el último registro considerado, coincide con la carga de la primera localidad de memoria, y en ese momento, comienza ahora la carga de valores en memoria. Una vez terminado el almacenamiento en memoria, se comienza a cargar el contenido de la primera memoria en cada uno de los registros. Después, se carga el contenido de la segunda; luego de la tercera, y finaliza cargando el contenido de la cuarta localidad de memoria en cada uno de los registros.

CONCLUSIONES Durante la simulación se pudo comprobar cómo se transferían los datos entre las etapas del datapath pipeline, tomando cinco ciclos de reloj para completar la ejecución de una instrucción. Utilizando esta técnica, la instrucción siguiente no tuvo que esperar a que la anterior terminara de ejecutarse, sino que ésta empezaba tan solo un ciclo después. De manera que para ejecutar dos instrucciones completas, se requieren de seis ciclos en total, aun cuando a cada una le lleva cinco para ser completada. Se llegó también a la conclusión de que para determinar el número total de ciclos para ejecutar un programa de N instrucciones, se emplea la siguiente fórmula: Total de ciclos = (N – 1) + 5 Lo que se pudo comprobar con los testbenches empleados. El programa de invertir valores consta de 12 instrucciones y le tomó 16 ciclos de reloj ser ejecutado por completo. El programa del desplazamiento de valores es de 24 instrucciones y se necesitaron 28 ciclos para finalizar su ejecución.

REFERENCIAS
(1) (2)

Patterson, David A..: Computer Organization and Design, Elsevier, 3a Ed. Diapositivas: Computer Architecture – A Pipelined Datapath
http://homedir.jct.ac.il/~citron/aca/aca-lec5/aca-lec5.ppt

5

ANEXOS Código fuente del programa Archivo: ProgCounter.vhd

-- LIBRERIAS UTILIZADAS library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_UNSIGNED.all; use IEEE.STD_LOGIC_ARITH.all; entity ProgCounter is port( Clk : in STD_LOGIC; AdrIn : in STD_LOGIC_VECTOR(4 downto 0); AdrOut : out STD_LOGIC_VECTOR(4 downto 0) ); end ProgCounter; architecture ProgCounter_arq of ProgCounter is begin -- CONTADOR DE PROGRAMA process (Clk) begin if Clk'event and Clk='1' then if (AdrIn’delayed = "UUUUU" or AdrIn > "11111") then -- PONE EL PC EN 00000 SI ES LA PRIMERA VEZ QUE SE EJECUTA EL PROGRAMA, -- O SI YA TERMINO AdrOut <= "00000"; else AdrOut <= AdrIn; end if; end if; end process; end ProgCounter_arq;

6

Archivo: ALU.vhd
-- LIBRERIAS UTILIZADAS library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_UNSIGNED.all; use IEEE.STD_LOGIC_ARITH.all; entity ALU is generic( BITS: integer := 32 -- CANTIDAD DE BITS DE LOS DATOS ); port( A : in STD_LOGIC_VECTOR(BITS-1 downto 0); B : in STD_LOGIC_VECTOR(BITS-1 downto 0); Result : out STD_LOGIC_VECTOR(BITS-1 downto 0) ); end ALU; architecture ALU_arq of ALU is begin -- ALU. SOLO SE IMPLEMENTARAN SUMAS process(A,B) begin Result <= A + B; end process; end ALU_arq;

Archivo: RegTmp.vhd
-- LIBRERIA UTILIZADA library IEEE; use IEEE.STD_LOGIC_1164.all; entity RegTmp is generic( BITS: integer := 32 -- CANTIDAD DE BITS DEL REGISTRO ); port( D : in STD_LOGIC_VECTOR(BITS-1 downto 0); Clk : in STD_LOGIC; Q : out STD_LOGIC_VECTOR(BITS-1 downto 0) ); end RegTmp; architecture RegTmp_arq of RegTmp is begin process (Clk) begin if (Clk'event and Clk='1') then Q <= D; end if; end process; end RegTmp_arq;

7

Archivo: InstrMemory.vhd
-- LIBRERIAS UTILIZADAS library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_UNSIGNED.all; use IEEE.STD_LOGIC_ARITH.all; use IEEE.NUMERIC_STD.all; use STD.TEXTIO.all; use IEEE.STD_LOGIC_TEXTIO.all; entity InstrMemory is port( ReadAddress: in std_logic_vector(4 downto 0); Clk: in std_logic; Instruccion : out STD_LOGIC_VECTOR(31 downto 0) ); end InstrMemory; architecture InstrMemory_arq of InstrMemory is file file_in: text is in "testbench.txt"; begin x1: process (ReadAddress, Clk) -- CADA LINEA DEL ARCHIVO variable line_in: line; -- UNA LINEA DE PROGRAMA variable input_tmp: std_logic_vector(31 downto 0); -- PARA IR ALMACENANDO EL PROGRAMA EN MEMORIA variable Address: integer range 0 to 255 := 0; -- CELDA DE 32 BITS DE MEMORIA DE PROGRAMA subtype memo is std_logic_vector(31 downto 0); -- 32 CELDAS DE 32 BITS type memoArray is array(0 to 31) of memo; -- MEMORIA DE INSTRUCCIONES variable memoria: memoArray; begin l1: while not(endfile(file_in)) loop -- LEE UNA LINEA DEL ARCHIVO readline(file_in, line_in); -- ALMACENA ESA LINEA EN input_tmp read(line_in, input_tmp); -- GUARDA EN MEMORIA UNA LINEA DE PROGRAMA memoria(Address) := input_tmp; Address := Address + 1; end loop l1; if ((Clk'event and Clk='1') or ReadAddress'event) then -- LEE INSTRUCCION EN MEMORIA Instruccion <= memoria(conv_integer(ReadAddress)); end if; end process; end InstrMemory_arq;

8

Archivo: Registros.vhd
-- LIBRERIAS UTILIZADAS library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_ARITH.all; use IEEE.STD_LOGIC_UNSIGNED.all; entity Registros is port( RegWrite : in STD_LOGIC; -- RegWrite. HABILITA LA ESCRITURA RReg1 : in STD_LOGIC_VECTOR(4 downto 0); -- READ REGISTER 1 RReg2 : in STD_LOGIC_VECTOR(4 downto 0); -- READ REGISTER 2 WReg : in STD_LOGIC_VECTOR(4 downto 0); -- WRITE REGISTER WData : in STD_LOGIC_VECTOR(31 downto 0); -- WRITE DATA RData1 : out STD_LOGIC_VECTOR(31 downto 0); -- READ DATA 1 RData2 : out STD_LOGIC_VECTOR(31 downto 0) -- READ DATA 2 ); end Registros; architecture Registros_arq of Registros is type regArray is array(0 to 31) of std_logic_vector(31 downto 0); -- 32 REGISTROS signal registro: regArray; -- MEMORIA DE REGISTROS begin process (RReg1, RReg2, WData, WReg) begin registro(0) <= "00000000000000000000000000000000"; -- REGISTRO $ZERO if (RReg1'event or RReg1 /= “UUUUU”) then -- LEE LO QUE HAY EN LA DIRECCION RREG1 RData1 <= registro(conv_integer(RReg1)); end if; if (RReg2'event or RReg2 /= “UUUUU”) then -- LEE LO QUE HAY EN LA DIRECCION RREG2 RData2 <= registro(conv_integer(RReg2)); end if; if (RegWrite = '1') then -- ESCRIBE WDATA EN LA DIRECCION WREG registro(conv_integer(WReg)) <= WData; end if; end process; end Registros_arq;

9

Archivo: Control.vhd
-- LIBRERIA UTILIZADA library IEEE; use IEEE.STD_LOGIC_1164.all; entity Control is port( OpCode : in STD_LOGIC_VECTOR(5 downto 0); Outputs : out STD_LOGIC_VECTOR(3 downto 0) ); end Control; architecture Control_arq of Control is begin -- FORMATO DE LA SALIDA: -3 2 1 0 -- MemToReg RegWrite MemRead MemWrite Outputs <= "1110" when (OpCode = "100011") else -- LW "0001" when (OpCode = "101011") else -- SW "0100" when (OpCode = "001101") else -- ORI (LI) "XXXX"; end Control_arq;

Archivo: SignExt.vhd
-- LIBRERIA UTILIZADA library IEEE; use IEEE.STD_LOGIC_1164.all; entity SignExt is port( A : in STD_LOGIC_VECTOR(15 downto 0); B : out STD_LOGIC_VECTOR(31 downto 0) ); end SignExt; architecture SignExt_arq of SignExt is begin -- EXTENSION DE SIGNO B <= "1111111111111111"&A(15 downto 0) when (A(15) = '1') else "0000000000000000"&A(15 downto 0); end SignExt_arq;

10

Archivo: DataMemory.vhd
-- LIBRERIAS UTILIZADAS library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_ARITH.all; use IEEE.STD_LOGIC_UNSIGNED.all; entity DataMemory is port( MemWrite : in STD_LOGIC; -- HABILITA ESCRITURA MemRead : in STD_LOGIC; -- HABILITA LECTURA Address : in STD_LOGIC_VECTOR(4 downto 0); -- DIRECCION WData : in STD_LOGIC_VECTOR(31 downto 0); -- WRITE DATA RData : out STD_LOGIC_VECTOR(31 downto 0) -- READ DATA ); end DataMemory; architecture DataMemory_arq of DataMemory is -- 32 CELDAS DE 32 BITS type memoArray is array(0 to 31) of std_logic_vector(31 downto 0); signal memoria: memoArray; -- MEMORIA DE DATOS begin process (Address, MemWrite, WData) begin if (MemWrite = '1') then -- ESCRIBE WDATA EN LA DIRECCION ADDRESS memoria(conv_integer(Address)) <= WData; end if; if (MemRead = '1') then -- LEE LO QUE HAY EN LA DIRECCION ADDRESS RData <= memoria(conv_integer(Address)); end if; end process; end DataMemory_arq;

Archivo: Mux2a1.vhd
-- LIBRERIA UTILIZADA library IEEE; use IEEE.STD_LOGIC_1164.all; entity Mux2a1 is generic( BITS: integer := 32 -- CANTIDAD DE BITS DE LOS DATOS ); port( A : in STD_LOGIC_VECTOR(BITS-1 downto 0); B : in STD_LOGIC_VECTOR(BITS-1 downto 0); S : in STD_LOGIC; C : out STD_LOGIC_VECTOR(BITS-1 downto 0) ); end Mux2a1; architecture Mux2a1_arq of Mux2a1 is begin -- MULTIPLEXOR 2 A 1 C <= B when (S = '1') else A; end Mux2a1_arq;

11

Archivo: Datapath.vhd
-- LIBRERIA UTILIZADA library IEEE; use IEEE.STD_LOGIC_1164.all; entity Datapath is port( Clk : in STD_LOGIC ); end Datapath; architecture Datapath_arq of Datapath is signal AdrIn, AdrOut,AdrInIF, WregWB, WregEX, WregMEM: std_logic_vector (4 downto 0); signal InstruccionIF, InstruccionID, WDReg, RData1ID, RData2ID, RData1EX, RData2EX, ExtendidoID, ExtendidoEX, ResultEX, RData2MEM, RData3MEM, ResultMEM, ResultWB, RData3WB: std_logic_vector (31 downto 0); signal CtrID, CtrEX, CtrMEM, CtrWB: std_logic_vector(3 downto 0); begin -- ETAPA INSTRUCTION FETCH (IF) PC1: entity work.ProgCounter (ProgCounter_arq) port map (Clk, AdrIn, AdrOut); AL1: entity work.ALU (ALU_arq) generic map (BITS => 5) port map (AdrOut, "00001", AdrIn); IM1: entity work.InstrMemory (InstrMemory_arq) port map (AdrOut,Clk, InstruccionIF); RT1: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (InstruccionIF, Clk, InstruccionID); -- ETAPA INSTRUCTION DECODE (ID) CT1: entity work.Control (Control_arq) port map (InstruccionID(31 downto 26), CtrID); RG1: entity work.Registros (Registros_arq) port map (CtrWB(2),InstruccionID(25 downto 21), InstruccionID(20 downto 16), WregWB, WDReg, RData1ID, RData2ID); SE1: entity work.SignExt (SignExt_arq) port map (InstruccionID(15 downto 0), ExtendidoID); RT2: entity work.RegTmp (RegTmp_arq) generic map (BITS => 4) port map (CtrID, Clk, CtrEX); RT3: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (RData1ID, Clk, RData1EX); RT4: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (RData2ID, Clk, RData2EX); RT5: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (ExtendidoID, Clk, ExtendidoEX); RT6: entity work.RegTmp (RegTmp_arq) generic map (BITS => 5) port map (InstruccionID(20 downto 16), Clk, WregEX); -- ETAPA EXECUTION (EX) AL2: entity work.ALU (ALU_arq) generic map (BITS => 32) port map (RData1EX, ExtendidoEX, ResultEX); RT7: entity work.RegTmp (RegTmp_arq) generic map (BITS => 4) port map (CtrEX, Clk, CtrMEM); RT8: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (ResultEX, Clk, ResultMEM); RT9: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (RData2EX, Clk, RData2MEM); RTA: entity work.RegTmp (RegTmp_arq) generic map (BITS => 5) port map (WregEX, Clk, WregMEM);

12

-- ETAPA MEMORY (MEM) DM1: entity work.DataMemory (DataMemory_arq) port map (CtrMEM(0), CtrMEM(1), ResultMEM(4 downto 0), RData2MEM, RData3MEM); RTB: entity work.RegTmp (RegTmp_arq) generic map (BITS => 4) port map (CtrMEM, Clk, CtrWB); RTC: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (RData3MEM, Clk, RData3WB); RTD: entity work.RegTmp (RegTmp_arq) generic map (BITS => 32) port map (ResultMEM, Clk, ResultWB); RTE: entity work.RegTmp (RegTmp_arq) generic map (BITS => 5) port map (WregMEM, Clk, WregWB); -- ETAPA WRITE BACK (WB) MX1: entity work.Mux2a1 (Mux2a1_arq) generic map (BITS => 32) port map (ResultWB, RData3WB, CtrWB(3), WDReg); end Datapath_arq;

13

TESTBENCHES Archivo: InvertirValores.txt
00 01 02 03 04 05 06 07 08 09 0A 0B 00110100000000010000000000000001 00110100000000100000000000000010 00110100000000110000000000000011 00110100000001000000000000000100 10101100000000010000000000000000 10101100000000100000000000000001 10101100000000110000000000000010 10101100000001000000000000000011 10001100000001000000000000000000 10001100000000110000000000000001 10001100000000100000000000000010 10001100000000010000000000000011 LI LI LI LI SW SW SW SW LW LW LW LW $1, $2, $3, $4, $1, $2, $3, $4, $4, $3, $2, $1, 1 2 3 4 0($0) 1($0) 2($0) 3($0) 0($0) 1($0) 2($0) 3($0)

Archivo: Desplazamiento.txt
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 00110100000000010000000000000001 00110100000000100000000000000010 00110100000000110000000000000011 00110100000001000000000000000100 10101100000000010000000000000001 10101100000000100000000000000010 10101100000000110000000000000011 10101100000001000000000000000100 10001100000000010000000000000001 10001100000000100000000000000001 10001100000000110000000000000001 10001100000001000000000000000001 10001100000000010000000000000010 10001100000000100000000000000010 10001100000000110000000000000010 10001100000001000000000000000010 10001100000000010000000000000011 10001100000000100000000000000011 10001100000000110000000000000011 10001100000001000000000000000011 10001100000000010000000000000100 10001100000000100000000000000100 10001100000000110000000000000100 10001100000001000000000000000100 LI LI LI LI SW SW SW SW LW LW LW LW LW LW LW LW LW LW LW LW LW LW LW LW $1, $2, $3, $4, $1, $2, $3, $4, $1, $2, $3, $4, $1, $2, $3, $4, $1, $2, $3, $4, $1, $2, $3, $4, 1 2 3 4 1($0) 2($0) 3($0) 4($0) 1($0) 1($0) 1($0) 1($0) 2($0) 2($0) 2($0) 2($0) 3($0) 3($0) 3($0) 3($0) 4($0) 4($0) 4($0) 4($0)

14

Sign up to vote on this title
UsefulNot useful