el banco de pruebas VHDL no emite / imprime advertencias por violaciones de tiempo

0

Aquí está mi situación: quiero simular un contador de 11 bits preestablecido formado por tres contadores binarios CD74AC161 chips. También quiero que la simulación detecte violaciones de tiempo (tiempo de configuración, tiempo de espera, etc.).

Primero, modelé el CD74AC161 de esta manera:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- entity declaration
entity cd74ac161 is
    generic ( constant DATA_WIDTH : integer := 4 );
    port    ( clk    : in std_logic;            -- clock signal
              clr_n  : in std_logic;            -- async clear signal
              load_n : in std_logic;            -- load/preset signal
              enp    : in std_logic;            -- enable
              ent    : in std_logic;
              rco    : out std_logic;
              d      : in std_logic_vector (DATA_WIDTH - 1 downto 0);
              q      : out std_logic_vector (DATA_WIDTH - 1 downto 0) );

    -- TODO: add detailed timing constants
    constant T_PD   : delay_length := 16 ns;    -- Propagation delay
    constant T_PW   : delay_length := 4.8 ns;   -- minium clock pulse width
    constant T_SUA  : delay_length := 4.4 ns;   -- setup time for data input
    constant T_SC   : delay_length := 5.3 ns;   -- setup/recovery time load/clear
end entity cd74ac161;

-- rtl architecture to check metastability
architecture rtl of cd74ac161 is
    signal intern : std_logic_vector (DATA_WIDTH - 1 downto 0) := (others => 'X');
begin

    -- clear or preset counter
    intern <= (others => '0')
                    when clr_n = '0' else
              d
                    when load_n = '0' else
              std_logic_vector(unsigned(intern) + 1)
                    when (rising_edge(clk) and enp = '1' and ent = '1');

    -- update RCO
    rco <= '1' after T_PD when (intern = X"f" and ent = '1') else '0' after T_PD;

    -- update output
    q <= intern after T_PD;

    -- check metastability for rising edge of clock
    checkMetaStability : process is
    begin
        -- wait for rising edge clock
        wait until rising_edge(clk);

        -- check clk pulse width
        assert clk'delayed'stable(T_PW)
            report "CLK pulse width too short!"
            severity warning;

        -- check clk recovery time
        assert clr_n'stable(T_SC)
            report "/CLEAR changed during recovery time!"
            severity warning;

        -- check data setup time
        assert d'stable(T_SUA)
            report "Data input changed during setup time!"
            severity warning;

        -- check load signal setup time
        assert load_n'stable(T_SC)
            report "/LOAD signal changed during setup time!"
            severity warning;
    end process checkMetaStability;

end architecture rtl;

Y aquí está su banco de pruebas:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- entity declaration
entity cd74ac161_tb is
end entity cd74ac161_tb;

-- test bench architecture
architecture testbench of cd74ac161_tb is
    signal clk    : std_logic := '0';            -- clock signal
    signal clr_n  : std_logic := 'X';            -- async clear signal
    signal load_n : std_logic := 'X';            -- load/preset signal
    signal enp    : std_logic := 'X';            -- enable
    signal ent    : std_logic := 'X';
    signal rco    : std_logic := 'X';
    signal d      : std_logic_vector (3 downto 0) := (others => 'X');
    signal q      : std_logic_vector (3 downto 0) := (others => 'X');
    -- stop signal
    signal finished : std_logic := '0';
begin

dut : entity work.cd74ac161(rtl)
    port map ( clk => clk,
               clr_n => clr_n,
               load_n => load_n,
               enp => enp,
               ent => ent,
               rco => rco,
               d => d,
               q => q );

-- clk generator
clk <= not clk after 50 ns when finished /= '1' else '0';


-- test signals
stimulus : process is
begin
    -- wait for three clock cycles
    clr_n <= '1';
    load_n <= '1';
    enp <= '0';
    ent <= '0';
    wait for 300 ns;

    -- preload
    load_n <= '0';
    d <= X"a";
    wait for 100 ns;

    -- clear counter
    load_n <= '1';
    clr_n  <= '0';
    wait for 100 ns;

    -- preload
    load_n <= '0';
    clr_n  <= '1';
    d <= X"b";
    wait for 100 ns;
    -- wait for 144 ns;

    -- count up
    load_n <= '1';
    enp <= '1';
    ent <= '1';
    wait for 1000 ns;

    -- inhibt for 500 ns
    enp <= '0';
    wait for 500 ns;

    -- clear counter
    load_n <= '1';
    clr_n  <= '0';
    wait for 100 ns;

    -- count up
    load_n <= '1';
    clr_n <= '1';
    enp <= '1';
    ent <= '1';
    wait for 1000 ns;

    -- WARNING: THESE SIGNALS VIOLATE METASTABILITY
    -- violate clear recovery
    wait until falling_edge(clk);
    clr_n <= '0';
    wait for 46 ns;
    clr_n <= '1';

    -- violate load setup
    wait until falling_edge(clk);
    load_n <= '0';
    wait for 46 ns;
    load_n <= '1';

    -- violate data setup
    wait until falling_edge(clk);
    d <= X"e";
    wait for 47 ns;
    d <= X"f";

    wait until falling_edge(clk);
    -- --------------------------------------------

    -- stop clock and wait forever
    finished <= '1';
    wait for 100 ns;
    wait;
end process stimulus;

end architecture testbench;

Esto hasta ahora funciona como se esperaba. El proceso checkMetastability detecta las violaciones de tiempo que las fuerzas del banco de pruebas y recibo tres advertencias por dicho proceso.

Ahora, quiero combinar tres de esos chips en un contador de 11 bits como este:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wasp_records_pkg.all;

-- entity declaration
entity addr_counter is
    generic ( constant ADDR_WIDTH : integer := 11);
    port    ( clk        : in std_logic;
              counter_in : in t_addr_counter ( d(ADDR_WIDTH -1 downto 0) );
              addr_out   : out std_logic_vector (ADDR_WIDTH - 1 downto 0) );  -- signals to display on LEDs
end entity addr_counter;

-- structural architecture
architecture structure of addr_counter is
    -- additional/auxiliar control signals
    signal load_inv : std_logic := 'X';    -- inverted load_addr signal
    -- internal signals
    signal rco_ct0_ct1 : std_logic := 'X';  -- RCO signal from counter0 to counter1
    signal rco_ct1_ct2 : std_logic := 'X';  -- RCO signal from counter1 to counter2
begin

    -- additional/auxiliar signals
    -- TODO: replace with gate for correct delay
    load_inv <= not counter_in.load;

    -- bits 11 downto 8
    addr_counter2 : entity work.cd74ac161(rtl)
        port map ( clk    => clk,
                   clr_n  => counter_in.clr_n,
                   load_n => load_inv,
                   enp    => rco_ct1_ct2,
                   ent    => rco_ct1_ct2,
                   rco    => open,
                   d(3)   => '0',
                   d(2 downto 0) => counter_in.d(ADDR_WIDTH - 1 downto 8),
                   q(2 downto 0) => addr_out(ADDR_WIDTH - 1 downto 8) );

    -- -- bits 7 downto 4
    addr_counter1 : entity work.cd74ac161(rtl)
        port map ( clk    => clk,
                   clr_n  => counter_in.clr_n,
                   load_n => load_inv,
                   enp    => rco_ct0_ct1,
                   ent    => rco_ct0_ct1,
                   rco    => rco_ct1_ct2,
                   d      => counter_in.d(7 downto 4),
                   q      => addr_out(7 downto 4) );

    -- -- bits 3 downto 0
    addr_counter0 : entity work.cd74ac161(rtl)
        port map ( clk    => clk,
                   clr_n  => counter_in.clr_n,
                   load_n => load_inv,
                   enp    => '0',
                   ent    => '0',
                   rco    => rco_ct0_ct1,
                   d      => counter_in.d(3 downto 0),
                   q      => addr_out(3 downto 0) );

end architecture structure;

( Nota : soy consciente de que este modelo no se ajusta correctamente cuando el contador alcanza el valor máximo; aún no lo he implementado. Como es la señal para contar, falta enp y ent de addr_counter0 solo se conectaron a '0' , por lo que el contador solo se puede preajustar a partir de ahora. No creo que esto se relacione con mi problema, pero quería mencionarlo de manera completa. q(3) de addr_counter2 no está conectado, pero por alguna razón, a GHDL no le importa. Una vez más, la recuperación aún no está implementada.)

Los tres archivos funcionan hasta ahora. Aquí está el registro utilizado en el archivo de arriba:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package wasp_records_pkg is

-- input of control switches
type t_control_panel is record
    deposit     : std_logic;
    examine     : std_logic;
end record t_control_panel;

-- interface for address counter module
type t_addr_counter is record
    load        : std_logic;        -- signal to load new address/data from input
    clr_n       : std_logic;        -- clear the counter to zero
    -- control_in  : t_control_panel;
    d           : std_logic_vector; -- address/data input
end record t_addr_counter;

end package wasp_records_pkg;

Ahora, el banco de pruebas para addr_counter es donde las cosas se deshacen:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wasp_records_pkg.all;

-- entity declaration
entity addr_counter_tb is
end entity addr_counter_tb;

-- test bench architecture
architecture testbench of addr_counter_tb is
    signal sys_clk, clr_n, load_addr, next_addr : std_logic := '0';
    signal addr_in, addr_out  : std_logic_vector (10 downto 0) := (others => 'X');
    -- stop clock generator
    signal finished : std_logic := '0';
begin

    dut : entity work.addr_counter(structure)
        port map ( clk              => sys_clk,
                   counter_in.load  => load_addr,
                   counter_in.clr_n => clr_n,
                   counter_in.d     => addr_in,
                   addr_out         => addr_out );

    -- clock generator
    sys_clk <= not sys_clk after 100 ns when finished /= '1' else '0';

    stimulus : process is
        constant CLK_CYC : delay_length := 200 ns;
    begin

        -- wait for 3 clock cycles
        clr_n <= '1';
        wait for 3 * CLK_CYC;
        wait for CLK_CYC / 2;
        --
        -- -- load $1f0 address
        -- THIS SOULD VIOLATE SETUP TIME FOR load_addr SIGNAL
        addr_in <= B"001_1111_0000";
        load_addr <= '1';
        wait for  CLK_CYC;
        load_addr <= '0';

        -- wait forever
        finished <= '1';
        wait for 3 * CLK_CYC;
        wait;

    end process stimulus;

end architecture testbench;

La señal load_addr cambia al mismo tiempo que aumenta el reloj del sistema, por lo que esto debería ser una infracción de tiempo de configuración, pero mi simulador, GHDL, no imprime una advertencia como lo hace con el banco de pruebas para el CD74AC161 chip.

¿Qué me estoy perdiendo? Nuevamente, todos los archivos funcionan como se esperaba, excepto que no recibo una advertencia por violaciones de tiempo en el banco de pruebas para addr_counter entidad.

Intenté simular esto en Vivado, pero aparentemente, Vivado no admite la simulación de registros sin restricciones .

Estoy usando GHDL 0.36-dev en Arch Linux.

EDIT : pensé que podría ser que GDHL no emita mensajes de submodelos / -componentes; así que "encajoné" el CD74AC161 y ejecuté exactamente el mismo banco de pruebas que el CD74AC161:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- entity declaration
entity blackbox is
    generic ( constant DATA_WIDTH : integer := 4 );
    port    ( clk    : in std_logic;            -- clock signal
              clr_n  : in std_logic;            -- async clear signal
              load_n : in std_logic;            -- load/preset signal
              enp    : in std_logic;            -- enable
              ent    : in std_logic;
              rco    : out std_logic;
              d      : in std_logic_vector (DATA_WIDTH - 1 downto 0);
              q      : out std_logic_vector (DATA_WIDTH - 1 downto 0) );

end entity blackbox;

-- rtl architecture to check metastability
architecture rtl of blackbox is
    signal load_inv : std_logic := 'X';
    signal rco_ct0_ct1 : std_logic := 'X';
begin


    -- additional/auxiliar signals
    -- TODO: replace with gate for correct delay
    load_inv <= not load_n;

    -- -- bits 3 downto 0
    addr_counter0 : entity work.cd74ac161(rtl)
        port map ( clk    => clk,
                   clr_n  => clr_n,
                   load_n => load_inv,
                   enp    => '0',
                   ent    => '0',
                   rco    => rco_ct0_ct1,
                   d      => d(3 downto 0),
                   q      => q(3 downto 0) );

end architecture rtl;

Esto también imprime correctamente las advertencias de GHDL, como espero / deseo. Entonces no puede ser eso.

    
pregunta georgjz

0 respuestas

Lea otras preguntas en las etiquetas