VHDL - Problema con la simulación del banco de pruebas - Modelsim PE Student 10.4

Soy muy nuevo en VHDL y tengo un problema con el tiempo de simulación en Modelsim PE Student Edition 10.4.

Escribí algunos archivos para un modelo RTL como multiplexor, demultiplexor y registro.

Para probar mi código, traté de implementar un banco de pruebas para cada archivo. La simulación para el multiplexor y demultiplexor funciona bastante bien, pero el banco de pruebas para los registros parece simular para siempre. Siempre que trato de simular no pasa nada y la simulación no termina en ningún punto. Traté de mirar las formas de onda pero no cambian.

A continuación te enviaré el código correspondiente a mi 4x1-MUX (que simula bastante bien) y el código de mi registro de 12 bits con reinicio síncrono (que no simula correctamente).

Realmente no puedo encontrar el problema en este código.

-- multiplexer for 4 inputs with 12 bit data width to 1 output with 12 bit data width
entity MULTIPLEXER_4TO1_12BIT is
       port (
             SELECT_IN: in bit_vector (1 downto 0);
             D_IN_0: in bit_vector (11 downto 0);
             D_IN_1: in bit_vector (11 downto 0);
             D_IN_2: in bit_vector (11 downto 0);
             D_IN_3: in bit_vector (11 downto 0);
             D_OUT: out bit_vector (11 downto 0)
            );
end MULTIPLEXER_4TO1_12BIT;

architecture RTL of MULTIPLEXER_4TO1_12BIT is
       begin 
            D_OUT <= D_IN_0 when SELECT_IN = "00" else
                     D_IN_1 when SELECT_IN = "01" else
                     D_IN_2 when SELECT_IN = "10" else
                     D_IN_3;
end RTL; 



 -- testbench for multiplexer for 4 inputs with 12 bit data width to 1  output with 12 bit data width
entity TESTBENCH_MULTIPLEXER_4TO1_12BIT is
end TESTBENCH_MULTIPLEXER_4TO1_12BIT;

architecture BEHAVIOUR of TESTBENCH_MULTIPLEXER_4TO1_12BIT is
      signal SELECT_IN: bit_vector (1 downto 0) := "00";
      signal D_IN_0, D_IN_1, D_IN_2, D_IN_3, D_OUT : bit_vector (11 downto 0) := B"0000_0000_0000"; 
      begin
           UUT: entity work.MULTIPLEXER_4TO1_12BIT port map (SELECT_IN, D_IN_0, D_IN_1, D_IN_2, D_IN_3, D_OUT); 
           tb: process
               begin 
                    D_IN_0 <= B"0000_0000_0000";
                    D_IN_1 <= B"0001_0001_0001";
                    D_IN_2 <= B"0110_0110_0110";
                    D_IN_3 <= B"1111_1111_1111";

                    SELECT_IN <= "00";
                    wait for 2 ns;
                    SELECT_IN <= "01";
                    wait for 2 ns;
                    SELECT_IN <= "10";
                    wait for 2 ns;
                    SELECT_IN <= "11";
                    wait for 2 ns; 

                    assert false report "end of simulation" severity failure; 
              end process tb;
end BEHAVIOUR;





-- register with 12 bit data width and synchronous reset
entity REG_SYNC_12BIT is
       port (
             D_IN: in bit_vector (11 downto 0);
             CLK: in bit;
             EN: in bit;
             RST: in bit;
             D_OUT: out bit_vector (11 downto 0)
            );
end REG_SYNC_12BIT; 

architecture RTL of REG_SYNC_12BIT is
             begin 
                  process
                         begin 
                              if (rising_edge (CLK)) then 
                                 if (RST = '0') then
                                    D_OUT <= B"0000_0000_0000"; 
                                 else
                                    if (EN = '1') then
                                       D_OUT <= D_IN;
                                    end if;
                                 end if;
                              end if;
                         end process;
end RTL;


-- testbench for register with 12 bit data width and synchronous reset

entity TESTBENCH_REG_SYNC_12BIT is
end TESTBENCH_REG_SYNC_12BIT;

architecture BEHAVIOUR of TESTBENCH_REG_SYNC_12BIT is
             signal D_IN, D_OUT: bit_vector (11 downto 0) := B"0000_0000_0000";
             signal CLK, EN: bit := '0'; 
             signal RST: bit := '1';

             begin
                  UUT: entity work.REG_SYNC_12BIT port map (D_IN, CLK, EN, RST, D_OUT); 
                  tb: process 
                             begin 
                                  EN <= '1'; 
                                  D_IN <= B"1111_1111_1111";
                                  wait for 4 ns;
                                  CLK <= '1';
                                  wait for 2 ns;
                                  D_IN <= B"0000_1111_1111";
                                  wait for 2 ns;
                                  CLK <= '1';
                                  wait for 10 ns; 

                                  assert false report "end of simulation" severity failure; 
                             end process tb;
end BEHAVIOUR;
¿Quisiste decir que tu CLKen el segundo ejemplo solo se establecería alto? Sería más habitual tener sentencias que lo asignen alternativamente a '0'y '1'.
Acabo de configurar CLK alto para probar si mi banco de pruebas funciona correctamente. Pero tienes razón, por supuesto. La señal CLK tiene que ser alterna.

Respuestas (1)

Hay algunos errores típicos que debe comprender y evitar primero.

Al crear su proceso instanciando su registro, no especificó ninguna lista de sensibilidad. (Si no sabe qué es, verifique allí ). Dado que su proceso está sincronizado con su reloj, CLKdebe colocarlo en la lista de sensibilidad.

Otra cosa que podría ser útil (es más una sugerencia que un error real) es poner cualquiera de las señales de reinicio de su registro de forma asíncrona (al menos en el proceso) y si lo desea sincrónico, aún puede sincronizarlo en el nivel superior . Se necesitarán menos elementos para implementar esto.

 process (RST, CLK)
        begin 
             if (RST = '0') then

                D_OUT <= B"0000_0000_0000"; 

             elsif (rising_edge (CLK)) then     

                if (EN = '1') then
                   D_OUT <= D_IN;
                end if;

             end if;
 end process;

Luego, en su banco de pruebas, como comentó @scary_jeff, no hizo que su reloj cambiara de estado. Entonces su rising_edgecondición solo es válida una vez. Para evitar esto te sugiero que siempre crees un proceso aparte generando tu reloj.

clk_gen : process (CLK)
begin

     clk <= not clk after clk_period/2;

end process;

(No olvides inicializar tu reloj)

Como realmente no especificó qué problema tuvo en la simulación, no puedo ayudar más por ahora, pero debería probar esto primero y volver con más información.

¿Por qué un reinicio asíncrono usa menos recursos? Solo estoy familiarizado con los FPGA de Xilinx, pero en estos, el uso es idéntico para cualquier tipo de reinicio, con la advertencia de que los reinicios asíncronos no se pueden fusionar con otra lógica si las herramientas quieren utilizar el pin SR de un registro para reducir el uso de LUT. ¿Tal vez es diferente en el mundo ASIC?
Bueno, supongo que hoy en día la mayoría de los sintetizadores pueden simplificarlo, pero en mi opinión, es preferible usar esta sintaxis para garantizar que realmente use el pin de reinicio dedicado.
Un restablecimiento asíncrono puede usar menos recursos en algunas arquitecturas que carecen de un SET/RST dedicado (lenguaje Xilinx para conjunto/borrado síncrono). Pero esto es raro, si no existe, para el FPGA actual (Xilinx y Altera recomiendan reinicios sincrónicos). Los FF en las partes de Xilinx y Altera tienen restablecimientos y borrados sincrónicos y asincrónicos (aunque es posible que no necesariamente se usen todos juntos). Además, el dominio set/rst también puede impulsar el uso de la lógica.
Muchas gracias por tus consejos. Como usted recomendó, agregué las señales CLK y RST a la lista de sensibilidad y cambié el registro a reinicio asíncrono. Ahora la simulación se ejecuta correctamente. ¡Gracias, rockero! :)