¿Por qué este patrón VHDL simple para un registro de desplazamiento no funciona como se espera?

8

A primera vista, esperaría que el código fuente de VHDL a continuación se comporte como un registro de desplazamiento. En eso q, con el tiempo estaría

"UUUU0", "UUU00", "UU000", "U0000", "00000", ....

pero en su lugar, siempre es U después de cinco (o más) ciclos de reloj consecutivos.

¿Por qué es esto?

Este código es en realidad una versión mucho más simplificada de una simulación mucho más complicada. Pero demuestra los síntomas que veo.

Exhibe este resultado interesante e inesperado durante la simulación tanto con ModelSim como con ActiveHDL, no he probado otros simuladores y (en segundo lugar, a una explicación de la causa) me gustaría saber si otros actúan de la misma manera.

Para responder a esta pregunta correctamente, debes entender que:

  • Sé que esta no es la mejor manera de implementar un registro de turnos
  • Sé que para la síntesis de RTL esto debería tener un reinicio.
  • Sé que una matriz de std_logic es un std_logic_vector.
  • Sé del operador de agregación, & .

Lo que también he encontrado:

  • Si la asignación temp(0)<='0'; se mueve dentro del proceso, funciona.
  • Si el bucle se desenvuelve (ver código comentado), funciona.

Reitero que esta es una versión muy simplificada de un diseño mucho más complicado (para una CPU canalizada), configurada para mostrar simplemente los resultados inesperados de la simulación. Los tipos de señales reales son solo una simplificación. Por este motivo, debe considerar sus respuestas con el código en el formulario tal como está.

Mi conjetura es que el optimizador del motor de simulación VHDL está equivocado (o quizás según las especificaciones) y no se molesta en ejecutar las expresiones dentro del bucle ya que no hay señales fuera de cambio, aunque puedo refutar esto colocando el bucle sin envolver en un bucle.

Así que espero que la respuesta a esta pregunta tenga más que ver con los estándares para la simulación VHDL de la sintaxis VHDL no explícita y cómo los motores de simulación VHDL hacen sus optimizaciones, en lugar de si el código dado es la mejor manera de hacer algo o no. .

Y ahora al código que estoy simulando:

 library ieee;
 use ieee.std_logic_1164.all;   

 entity test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
 end entity;

 architecture example of test_simple is
    type   t_temp is array(4 downto 0) of std_logic;
    signal temp : t_temp;
 begin

    temp(0) <= '0';

    p : process (clk)
    begin               
        if rising_edge(clk) then
            for i in 1 to 4 loop
                    temp(i) <= temp(i - 1);
            end loop;

            --temp(1) <= temp(0);   
            --temp(2) <= temp(1);
            --temp(3) <= temp(2);
            --temp(4) <= temp(3);
        end if;
    end process p;
    q <= temp(4);
 end architecture;

Y el banco de pruebas:

library ieee;
use ieee.std_logic_1164.all;

entity Bench is
end entity;

architecture tb of bench is

component test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
end component;

signal clk:std_logic:='0';
signal q:std_logic;     
signal rst:std_logic;

constant freq:real:=100.0e3;

begin                       
    clk<=not clk after 0.5 sec / freq;

    TB:process
    begin
        rst<='1';
        wait for 10 us;
        rst<='0';
        wait for 100 us;
        wait;
    end process;

     --Note: rst is not connected
    UUT:test_simple  port map (clk=>clk,q=>q) ;
end architecture;
    
pregunta Jason Morgan

1 respuesta

7

Tiene que ver con lo que se puede evaluar fácilmente en el momento de la elaboración, formalmente, lo que se denomina "expresión local estática". Esta es una regla de apariencia oscura, pero merece una reflexión: a la larga tiene sentido, y su simulador es bastante correcto para alertarlo al generar resultados no obvios.

Ahora, temp(1) puede evaluarse en tiempo de compilación (incluso antes que el tiempo de elaboración) y puede generar un controlador en el bit 1 de "temp".

Sin embargo, temp(i) implica un poco más de trabajo para las herramientas. Dada la naturaleza trivial de los límites del bucle aquí (1 a 4) es obvio para nosotros los humanos que no se puede controlar la temperatura (0) y que lo que está haciendo es seguro. Pero imagine que los límites eran las funciones lower(foo) to upper(bar) en un paquete declarado en otro lugar ... ahora, lo más que puede decir con certeza es que temp está controlado, por lo que la expresión "estática localmente" es temp .

Y eso significa que el proceso está restringido por estas reglas para controlar todo temp , momento en el que tiene varios controladores en temp(0) : la conducción del proceso (sin valor inicial, es decir, 'u') y la externa %código%. Así que, naturalmente, los dos conductores se resuelven en "U".

La alternativa sería una "pequeña regla hacky" (opinión) de que si los límites del bucle fueran constantes, haga una cosa, pero si se declararan como otra cosa, haga otra cosa, y así sucesivamente ... cuanto más Hay pocas reglas extrañas, cuanto más complejo se vuelve el lenguaje ... en mi opinión, no hay una mejor solución.

    
respondido por el Brian Drummond

Lea otras preguntas en las etiquetas