Discrepancia entre el esquema RTL y la simulación de comportamiento en Vivado

0

Tengo un problema extraño con una simple simulación de VHDL de Vivado (2015.3).

Este código:

library ieee;
use ieee.std_logic_1164.all;

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

architecture Behavioral of pulse is
    signal ff0 : std_logic := '0';
    signal ff1 : std_logic := '0';
begin
    process (clk, ff0, ff1)
    begin
        if rising_edge(clk) then
            ff0 <= d;
            ff1 <= ff0;
        end if;
        q <= ff0 and not ff1;
    end process;
end Behavioral;

produce este esquema RTL:

Elpropósitoessimplementetomarunpulsodeentradad,quepuedetenerunaduracióndemúltiplesciclosdereloj,ygenerarunpulsodeunsolocicloq.Muybasico.Lasimulaciónseveasí:

Sicambioelcódigoparausarsolovariablesdeproceso,lasimulaciónfalla:

(nota:elcódigodeabajoesunaprácticaterrible.Noesalgoquehagaoperativamente,nialgoquerecomiendo.Tenerdoscláusulasifrising_edge(clk)enunsoloprocesoesalgoqueencontré,yahorasoytratandodecomprendersusimplicaciones,yporquécreaunacontradicciónentrelosresultadosdelasimulacióndecomportamientoylasíntesisreal.)

libraryieee;useieee.std_logic_1164.all;entitypulseisport(d:instd_logic;clk:instd_logic;q:outstd_logic);endpulse;architectureBehavioralofpulseisbeginprocess(clk)variableff0:std_logic:='0';variableff1:std_logic:='0';beginifrising_edge(clk)thenff0:=d;endif;ifrising_edge(clk)thenff1:=ff0;endif;q<=ff0andnotff1;endprocess;endBehavioral;

Enlaarquitecturadevariables,lasvariablesseconviertenenseñalesyaqueestánencláusulasdecondiciónderelojseparadas.Porlotanto,lasdosimplementacionesdeberíanser,literalmente,lasmismas.

LosesquemasdeRTLdepre-síntesisdeambasarquitecturassonidénticos(segúnloproducidoporVivadoysemuestraarriba),asíqueamenosquemefaltealgo,lassimulacionestambiéndeberíanserlo.

edición1:

Losesquemasdepost-síntesisdeambasarquitecturastambiénsonidénticos.Ambossevenasí:

edición2:Heconfirmadoque"Simulaciones funcionales post-síntesis" producen resultados idénticos para ambas arquitecturas.

Para "Simulaciones de comportamiento" (es decir, simulación antes de la síntesis), mi pregunta sigue en pie.

Para completar, aquí está el código de simulación:
library ieee;
use ieee.std_logic_1164.all;

library UNISIM;
use UNISIM.VComponents.all;

entity pulse_sim is
end pulse_sim;

architecture Behavioral of pulse_sim is

    -- Sim component 
    component pulse is
    port (
        d   : in  std_logic;
        clk : in  std_logic;
        q   : out std_logic );
    end component;

    -- Test signals
    signal d   : std_logic := '0';
    signal clk : std_logic := '1';
    signal q   : std_logic := '0';

    -- Clock constants
    constant PERIOD : time := 10 ns;  -- 100 MHz

begin

    -- DUT instance
    UUT: pulse 
    port map (
        d   => d,
        clk => clk,
        q   => q );

    -- run clock
    clk <= not clk after PERIOD/2;

    -- test process
    process
    begin
        d <= '1' after 30 ns,
             '0' after 80 ns,
             '1' after 120 ns,
             '0' after 150 ns;
        wait;
    end process;

end Behavioral;
pregunta Blair Fonville

2 respuestas

0

El problema es que está utilizando variables de forma incorrecta para lo que está tratando de lograr. En VHDL, cuando maneja señales en un proceso, las señales mantendrán sus valores hasta que el proceso finalice, y cualquiera que sea la asignación FINAL de esa señal mientras se ejecuta el proceso, es lo que el valor mantendrá.

Aquí hay un ejemplo:

   signal signalA : integer := 4;

   SignalExampleProcess : process(clk)
    begin
      if(rising_edge(clk)) then
         signalA <= 0;            --Signal A value is still 4
         signalA <= signalA + 1;  --Signal A value is still 4
         signalA <= signalA + 1;  --Signal A value is still 4. This is the last assignment that "hit" signalA for this process
      end if; --rising_edge(clk)
    end process SignalExampleProcess;  -- Update signalA value to 5 upon process exit.

Al inicio del proceso, la señalA era el valor 4 (este era el valor de precarga en el área de declaración de la señal). Así que al final de este proceso, la señal A será igual a 5. Después del siguiente ciclo de reloj, la señal A será 6. y así sucesivamente. Veamos el mismo ejemplo usando variables:

   VariableExampleProcess : process(clk)
      variable variableA : integer := 4;
    begin
      if(rising_edge(clk)) then
        variableA := 0;                --variableA value is 0
        variableA := variableA + 1;    --variableA value is 1
        variableA := variableA + 1;    --variableA value is 2
      end if; --rising_edge(clk)
    end process VariableExampleProcess; --variableA holds last value upon process exit

Note que esta vez, la variable A es igual a 2 al final. Las variables pueden contener valores intermedios a medida que el intérprete de lenguaje analiza el proceso. Tenga en cuenta que si observa la variable A en un analizador lógico, solo verá que tiene el valor 4 al restablecerse y luego el valor 2 en el siguiente ciclo de reloj. Los valores intermedios solo se utilizan para DESCRIBIR el comportamiento lógico previsto.

Así que volvamos a su ejemplo:

architecture Behavioral of pulse is
begin
    process (clk)
        variable ff0 : std_logic := '0';
        variable ff1 : std_logic := '0';
    begin
        if rising_edge(clk) then
            ff0 := d;                --ff0's value will now be d, ff0 == d
        end if;
        if rising_edge(clk) then
            ff1 := ff0;              --ff1's value will now be ff0, ff1 == d
        end if;
        q <= ff0 and not ff1;   --ff1 and ff0 always contain the same value, q will always be low.
    end process;
end Behavioral;

Tengo la impresión de que obtuviste un esquema RTL válido basado en el hecho de que tienes dos declaraciones "if (rising_edge (clk))" en un proceso. No puedo recordar si esto es ilegal o no en VHDL, pero diría que es inusual y probablemente está probando los casos de vanguardia de Vivado. Si lo hago uno "if (rising_edge (clk)) y luego" formulo ambas asignaciones de variables, me da lo que esperaría: un registro.

Y para el registro, ModelSim también se comporta de manera idéntica a tu simulación de Vivado:

    
respondido por el user2913869
0

Descubrí que tener dos cláusulas de condición de reloj dentro del proceso parece confundir al simulador (aunque no es un problema para la síntesis, razón por la cual funciona la simulación posterior a la síntesis).

Si cambio el proceso a:

process (clk)
    variable ffs : std_logic_vector(1 downto 0) := b"00";
begin
    if rising_edge(clk) then
        ffs := ffs(0) & d;
    end if;
    q <= ffs(0) and not ffs(1);
end process;

funciona como se esperaba.

Esencialmente, al fusionar las dos variables std_logic en un std_logic_vector , puedo actualizar ambos valores en una única cláusula if rising_edge(clk) then y aún mantener la inferencia de registro.

Sin embargo, con respecto a la pregunta original, todavía no entiendo por qué la simulación de comportamiento está en conflicto con el esquema RTL. Entonces, por favor considera la pregunta aún abierta.

    
respondido por el Blair Fonville

Lea otras preguntas en las etiquetas