VHDL: asignar una señal de matriz en un bucle genera efectos secundarios

4

No entiendo por qué el siguiente código vhdl no simula como creo que debería.

test_pipe_1 (0) se asigna en el proceso pr1, pero la simulación (tanto Aldec como GHDL) muestra que test_pipe_1 (0) es 'U' todo el tiempo.

OTH, test_pipe_2 (0) funciona de manera diferente en Aldec vs GHDL. En Aldec, la señal se asigna como se espera ('Z' @ 0 s, '0' @ 500 ns, '1' @ 1 us, etc.).

En GHDL, se ve el comportamiento extraño ('Z' @ 0 seg, 'U' @ 500 ns). No hay un controlador 'U' para la señal test_pipe_2 (0).

Mi sensación es que esta es una función de definición de idioma, pero no puedo entender qué y por qué.

¿Alguna idea?

library ieee;
use ieee.std_logic_1164.all;

entity vhdl_loop_assignment is
end;

architecture testing of vhdl_loop_assignment is
    signal test_d0: std_logic;
    signal test_pipe_1: std_logic_vector(9 downto 0);
    signal test_pipe_2: std_logic_vector(9 downto 0) := (others => 'Z');
    signal clk: std_logic;
begin
    test_1: process(clk)
    begin
        if rising_edge(clk) then
            l: for n in 0 to 8 loop
                test_pipe_1(n+1) <= test_pipe_1(n);
            end loop;
            -- test_pipe_1(0) <= 'Z'; -- If this is uncommented, starts working as expected.
        end if;
    end process;

    test_2: process(clk'delayed(300 ns))
    begin
        if rising_edge(clk'delayed(300 ns)) then
            l: for n in 0 to 8 loop
                test_pipe_2(n+1) <= test_pipe_2(n);
            end loop;
        end if;
    end process;

    pr1: process(clk)
    begin
        if rising_edge(clk) then
            if test_d0 /= '0' then
                test_d0 <= '0';
                test_pipe_1(0) <= '0';
                test_pipe_2(0) <= '0';
            else
                test_d0 <= '1';
                test_pipe_1(0) <= '1';
                test_pipe_2(0) <= '1';
            end if;
        end if;
    end process;

    pr2: process
    begin
        clk <= '0';
        wait for 500 ns;
        clk <= '1';
        wait for 500 ns;
    end process;
end;
    
pregunta Topi Rinkinen

1 respuesta

3

Esta es una pregunta interesante. Algo que entendí intuitivamente, pero no sabía la razón por la cual. Gracias a tu pregunta, investigué y aprendí algo nuevo.

Parece que test_pipe_1(0) tiene solo 1 controlador (en pr1 ). Sin embargo, cuando simulo su código en Modelsim (¡felicitaciones por el MCVE!), Veo 2 controladores: pr1 y test_1 . Por ejemplo:

# vsim -c work.vhdl_loop_assignment 
# Start time: 07:28:12 on Jun 06,2016
# Loading std.standard
# Loading std.textio(body)
# Loading ieee.std_logic_1164(body)
# Loading work.vhdl_loop_assignment(testing)
VSIM 1> run 20 us
VSIM 2> drivers test_pipe_1(0)
# Drivers for /vhdl_loop_assignment/test_pipe_1(0):
#    U  : Signal /vhdl_loop_assignment/test_pipe_1(0)
#      1 : Driver /vhdl_loop_assignment/pr1
#      U : Driver /vhdl_loop_assignment/test_1
# 

Ahora, cuando eliminas el comentario de test_pipe_1(0) <= 'Z'; , esto controla todos los valores en test_pipe_1 . Y como test_pipe_1 se construye a partir de tipos resueltos, se invoca la función de resolución y la 'Z' se resuelve con el controlador en pr1 . Para aclarar, aquí están sus 2 casos:

Sin test_pipe_1(0) <= 'Z'; , tiene el ejemplo anterior. Tanto '1' como 'U' se manejan en test_pipe_1(0) , que se resuelve en 'U' .

Con test_pipe_1(0) <= 'Z'; , obtienes los siguientes controladores:

# vsim -c work.vhdl_loop_assignment 
# Start time: 07:33:24 on Jun 06,2016
# Loading std.standard
# Loading std.textio(body)
# Loading ieee.std_logic_1164(body)
# Loading work.vhdl_loop_assignment(testing)
VSIM 1> run 20 us
VSIM 2> drivers test_pipe_1(0)
# Drivers for /vhdl_loop_assignment/test_pipe_1(0):
#    1  : Signal /vhdl_loop_assignment/test_pipe_1(0)
#      1 : Driver /vhdl_loop_assignment/pr1
#      Z : Driver /vhdl_loop_assignment/test_1
#

Ahora, obtienes '1' y 'Z' en test_pipe_1(0) . Y la función de resolución se resuelve en un '1' . Y es por esto que tu código comienza a funcionar.

Aparte de eso, si hubiera cambiado a std_ulogic_vector , su simulación no se habría compilado o fallado durante la elaboración.

Por último, a la causa raíz: varios controladores. El problema es que los controladores se crean durante la elaboración y los índices en las construcciones for ... loop no se determinan hasta la ejecución. Por lo tanto, los simuladores crean un controlador para cada elemento individual en test_pipe_1 en el proceso test_1 durante la elaboración. Lo admito, aunque sabía que algo estaba mal, no tenía claro por qué. Tuve que cavar alrededor para averiguar por qué.

Desde el LRM VHDL (Sección 12.4.4):

  

La elaboración de una declaración de proceso procede de la siguiente manera:    a) Se elabora la parte declarativa del proceso.    b) Se crean los controladores requeridos por la declaración de proceso.    c) La transacción inicial de fi nida por el valor predeterminado asociado con cada señal escalar controlada por la declaración de proceso se inserta en el controlador correspondiente.

Entonces, primero se elabora el proceso. En este punto, el simulador no sabe qué bits de test_pipe_1 tendrán controladores (el rango de for ... loop aún no se ha evaluado). Por lo tanto, crea todos los controladores requeridos de acuerdo con 12.4.4b.

Ahora, en VHDL LRM (Sección 12.5):

  

Hay tres casos particulares en los que la elaboración ocurre dinámicamente durante la simulación. Estas areas   sigue:

     

a) La ejecución de una sentencia de bucle con un esquema de iteración implica la elaboración de la especificación del parámetro de bucle antes de la ejecución de las sentencias encerradas en el bucle (consulte 8.9). Esta elaboración crea el parámetro de bucle y evalúa el rango discreto.

El for ... loop se elabora 'antes de la ejecución' del bucle.

Entonces, su solución es 1) deshacerse del bucle for o 2) separar las señales.

Por lo tanto, aquí hay un pellizco para tu publicación original. Agregué una señal test_pipe_1_0_in para que sea el valor que entrará en test_pipe_1 (suponiendo que este valor y test_d0 no estén relacionados, aunque en este ejemplo están claramente relacionados. En su lugar, podría usar test_d0 y obtener el mismo resultado.).

library ieee;
use ieee.std_logic_1164.all;

entity vhdl_loop_assignment is
end;

architecture testing of vhdl_loop_assignment is
    signal test_d0: std_logic;
    signal test_pipe_1: std_logic_vector(9 downto 0);
    signal test_pipe_1_0_in : std_logic;
    signal clk: std_logic;
begin
    test_1: process(clk)
    begin
        if rising_edge(clk) then
            l: for n in 0 to 8 loop
                test_pipe_1(n+1) <= test_pipe_1(n);
            end loop;
            test_pipe_1(0) <= test_pipe_1_0_in;
        end if;
    end process;

    pr1: process(clk)
    begin
        if rising_edge(clk) then
            if test_d0 /= '0' then
                test_d0 <= '0';
                test_pipe_1_0_in <= '0';
            else
                test_d0 <= '1';
                test_pipe_1_0_in <= '0';
            end if;
        end if;
    end process;

    pr2: process
    begin
        clk <= '0';
        wait for 500 ns;
        clk <= '1';
        wait for 500 ns;
    end process;
end;

Espero que ayude.

    
respondido por el PlayDough

Lea otras preguntas en las etiquetas