Generación de reloj adecuada para bancos de pruebas VHDL

7

En muchos bancos de prueba veo el siguiente patrón para la generación de reloj:

process
begin
    clk <= '0';
    wait for 10 NS;
    clk <= '1';
    wait for 10 NS;
end process;

En otros casos veo:

clk <= not clk after 10 ns;

Se dice que lo último es mejor, porque se programa antes de que se ejecute cualquier proceso y, por lo tanto, las señales que se cambian de forma síncrona con el borde del clk se manejan correctamente. Las siguientes secciones del LRM pueden parecer compatibles con esta teoría:

Página 169: 12.6.4 El ciclo de simulación   Un ciclo de simulación consta de los siguientes pasos:

  • b) Se actualiza cada señal explícita activa en el modelo. (Los eventos pueden se producen en las señales como resultado.)

Estas deben ser las señales con un nuevo valor proyectado, como las señales retrasadas por el after .

  • d) Para cada proceso P, si P es actualmente sensible a una señal S y si se ha producido un evento en S en este ciclo de simulación, luego P se reanuda.

Esa sería la mayor parte de la lógica a simular

  • e) Cada proceso no pospuesto que se ha reanudado en la simulación actual el ciclo se ejecuta hasta que se suspende.

Y ahora se ejecutan todos los procesos que están suspendidos por wait for .

TL; DR:

  • ¿El método after siempre es superior al método wait for ?
  • ¿Ayuda a evitar que los problemas configuren de forma síncrona las señales de entrada?
pregunta Karsten Becker

2 respuestas

6

No se puede culpar al simulador por actuar a veces como si el reloj ocurriera justo después o justo antes de que cambie la entrada, si asigna clk y entradas usando wait for . Preguntar si un estilo es superior o inferior al otro es, de alguna manera, la pregunta incorrecta. Debe especificar el comportamiento de una manera no ambigua, si desea una salida determinista y no ambigua.

Lo que he hecho durante años y me ha funcionado perfectamente (para diseños sincrónicos) es asignar las entradas que los preceden con wait until rising_edge(clk) o wait until falling_edge(clk) . Cómo generar el clk deja de ser importante. Para los bancos de pruebas simples, after one-liner hace el trabajo de manera agradable y sucinta, pero no ofrece la flexibilidad de un process con wait for o wait until .

Tengo un pequeño procedimiento simple que me ha servido bien:

procedure wait_until_rising_edges(signal clk : in std_logic; n : in integer) is
begin
    for i in 1 to n loop
        wait until rising_edge(clk);
    end loop;
end procedure;

Que mantengo en un tb_pkg.vhd que siempre use en bancos de pruebas.

Un ejemplo de uso podría ser:

some_stim_proc : process
begin
    some_signal <= '0';
    wait_until_rising_edges(clk,900);
    some_signal <= '1';
    wait_until_rising_edges(clk,100);
end process;

Algunos diseñadores asignan sus señales de estímulo en el borde opuesto a lo que la unidad bajo prueba es sensible. Personalmente no me gusta hacer esto porque no es así como se simulará el resto del circuito, donde las señales cambian en el borde del 'disparador'. Pero ciertamente no hay nada de malo en ese enfoque. El procedimiento anterior también se puede utilizar para ello.

    
respondido por el apalopohapa
3

Leí este hilo hace mucho tiempo, pero no tuve tiempo de responder hasta que me retiré.

Es interesante ver las formas en que diferentes personas crean sus relojes de banco de pruebas y los criterios que se utilizan para juzgar qué tan "buenos" son. Para mí, miraba el código y preguntaba: ¿qué tan versátil es? ¿Qué tan difícil es modificar si la velocidad del reloj cambia? ¿O si quiero usar el banco de pruebas en una simulación de compuerta con anotación inversa?

Este es mi largo camino para asegurar que las modificaciones sean fáciles y el banco de pruebas sea versátil:

La frecuencia de reloj, el tiempo de configuración de los datos y los tiempos de retención de los datos deben definirse como genéricos o constantes, por ejemplo:

generic (
  CLK_CYCLE_TIME  : time     := 10 ns;
  CLK_HIGH_TIME   : time     := 5 ns;
  DATA_SETUP_TIME : time     := 4 ns;
  DATA_HOLD_TIME  : time     := 4 ns;

Luego, genere bordes para el banco de pruebas que se usará para proporcionar datos, eliminar datos y para el aumento de reloj y los "eventos" de caída de reloj:

begin
  -- generate events for data setup, clock rise, data hold and clock fall times:
  data_setup_event <= transport not data_setup_event after CLK_CYCLE_TIME;
  clk_rise_event   <= transport     data_setup_event after DATA_SETUP_TIME;
  clk_fall_event   <= transport     clk_rise_event   after CLK_HIGH_TIME;
  data_hold_event  <= transport     clk_rise_event   after DATA_HOLD_TIME;

  -- actual clock signal generation:
  clk_gen_p:process is
  begin
    wait on clk_rise_event;
    clk <= '1';
    wait on clk_fall_event;
    clk <= '0';
  end process;

Se puede aplicar el estímulo (caminando una entrada con el protocolo vld / rdy utilizado para este ejemplo):

  apply_stimulus_p : process is
    variable v_walking_one : std_logic_vector(i_dat'range) := std_logic_vector(to_unsigned(1, i_dat'length));
  begin
    wait on data_setup_event;
    rst <= '1';
    wait on data_hold_event;
    rst <= '0';

    for i in 0 to TCOUNT-1 loop
      wait on data_setup_event;
      i_vld       <= '1';
      i_dat       <= v_walking_one;
      i_side_pipe <= std_logic_vector(to_unsigned(i, i_side_pipe'length));

      wait on clk_rise_event;
      while i_rdy /= '1' loop
        wait on clk_rise_event;
      end loop;

      wait on data_hold_event;
      i_vld       <= '0';
      i_dat       <= (others => 'X');
      i_side_pipe <= (others => 'X');

      -- rotate the walking one:
      v_walking_one := rotate_right(v_walking_one);
    end loop;
    wait;
  end process;

Todas las transiciones de datos de entrada están alejadas del borde del reloj activo (ascendente). Incluso atrapa errores como una inversión extra en el reloj.

Es elegante, legible, versátil y fácilmente modificable. No hay literales que dependan de la frecuencia del reloj o del ancho de los datos. Así es como lo escribiría.

    
respondido por el J. Corona

Lea otras preguntas en las etiquetas