Generación variable de onda / reloj de banco de pruebas VHDL

1

Un banco de pruebas para una subentidad en mi sistema actualmente define un proceso auxiliar para generar una forma de onda similar a un reloj al mando del proceso de estímulo principal. Una versión simplificada es:

shared variable gen_period : time := 10 us;
signal gen_all : boolean := false;  -- wavegen enabled
signal gen_A : boolean := false;    -- run this signal
signal A_in : std_logic;            -- manual input (wavegen disabled)
signal A_gen : std_logic;           -- generated output (internal)
signal A_out : std_logic;           -- final output
...
A_generate: process
    if gen_A then
        A_gen <= '1';
        wait for gen_period/2;
        A_gen <= '0';
        wait for gen_period/2;
    else
        A_gen <= '0';
        wait for 1 ns;
    end if;
end process;

A_out <= A_gen when gen_all else A_in;

El sistema completo tiene algunas señales más, pero esta es la idea básica. gen_all se aplica a todas las señales y permite que se aplique un patrón de señal manual cuando está deshabilitado, mientras que gen_A es básicamente un reloj habilitado para esa señal específica. La otra característica importante es que el período del reloj es variable.

Poner todo esto junto significa que el proceso principal de estímulo del banco de pruebas puede generar bordes manualmente o simplemente puede solicitar un tren de pulsos en un intervalo específico y luego esperar un tiempo más largo (típicamente gen_period * N ) para generar pulsos múltiples. Funciona bastante bien.

Ahora, aunque estoy interesado en generalizar esto un poco, en particular para crear una instancia de varios generadores independientes en el banco de pruebas para un diseño de alto nivel que contenga múltiples componentes originales. Sin embargo, estoy teniendo problemas para encontrar la manera correcta de hacerlo.

Mi primer intento fue envolver el código de arriba en su propia entidad, declarando todo menos A_gen como puertos de la entidad. Hacer esto requiere cambiar gen_period de una variable a una señal, ya que los puertos AFAIK deben ser señales.

Lamentablemente, de nuevo en el proceso de estímulo original del banco de pruebas, cada vez que intentaba asignar un nuevo período tenía que hacer esto como una asignación de señal, que no tuvo efecto hasta más tarde. Además, las llamadas wait for gen_period * 5 parecían estar usando el valor original para gen_period en lugar de uno solo asignado. (Este no es un comportamiento sorprendente para las señales, pero en este caso no es deseado).

¿Hay una mejor manera de encapsular esta funcionalidad y conservar el comportamiento instantáneo de la variable? El código solo se utilizará en un banco de pruebas, por lo que no necesita ser sintetizable. Estoy usando Xilinx ISim.

(Me doy cuenta de que puedo hacer un for .. generate para crear instancias múltiples en el banco de pruebas de nivel superior, pero esto no me permite compartir el código entre bancos de pruebas separados, lo que también es conveniente para evitar la duplicación).

Puedo vivir teniendo solo una instancia de la variable gen_period compartida entre todos los generadores en el banco de pruebas de alto nivel, pero preferiría tener una por instancia de generador.

Como las respuestas parecen estar enfocadas en "reloj" en lugar de "forma de onda", parece que necesito aclarar el uso un poco más. Esto está dentro de un banco de pruebas:

stim_proc : process
begin
    -- (reset and other setup instructions here)

    -- generate "slow" pulse train
    gen_all <= true;
    gen_period := 250 ns;
    gen_A <= true;
    wait for gen_period * 20;
    gen_A <= false;
    wait for gen_period;
    -- (perform tests on logic for slow pulses here)

    -- generate "fast" pulse train
    gen_period := 10 ns;
    gen_A <= true;
    wait for gen_period * 50;
    gen_A <= false;
    wait for gen_period;
    -- (perform tests on logic for fast pulses here)

    -- generate asymmetric pulses
    gen_all <= false;
    A_in <= '1';
    wait for 100 ns;
    A_in <= '0';
    wait for 200 ns;
    A_in <= '1';
    wait for 150 ns;
    A_in <= '0';
    wait for 50 ns;
    -- (perform tests on logic for asymmetric pulses here)

    -- etc
end process;

Estos son los simples; hay algunos más complejos que involucran múltiples señales que ocurren simultáneamente, pero eso no es realmente importante para esta pregunta. El punto importante es que esto es todo el código secuencial y tanto la generación de pulsos como la espera deben actuar en el último período establecido, no en ningún valor retrasado.

    
pregunta Miral

2 respuestas

2

Podría usar un procedimiento con un parámetro de salida. El procedimiento se puede declarar en un paquete y llamar con diferentes parámetros para diferentes señales de 'reloj'.

Aquí hay un ejemplo de un clock_gen procedure desde VHDL-extras :

subtype duty_cycle is real range 0.0 to 1.0;

procedure clock_gen( signal Clock : out std_ulogic; signal Stop_clock : in boolean;
  constant Clock_period : in delay_length; constant Duty : duty_cycle := 0.5 ) is
  constant HIGH_TIME : delay_length := Clock_period * Duty;
  constant LOW_TIME  : delay_length := Clock_period - HIGH_TIME;
begin
  Clock <= '0';

  while not Stop_clock loop
    wait for LOW_TIME;
    Clock <= '1';
    wait for HIGH_TIME;
    Clock <= '0';
  end loop;
end procedure;

El período de entrada constante se puede intercambiar con una variable para entornos de simulación.

Ejemplo de uso:

architecture rtl of my_entity is
  signal SimStop      : boolean     := false;
  signal my_clock1    : std_ulogic;
  signal my_clock2    : std_ulogic;
begin

  clock_gen(my_clock1, SimStop, 10.000 ns);
  clock_gen(my_clock2, SimStop,  6.666 ns);

  -- ...

  process
  begin
    --
    -- some stimuli
    --

    wait for 10 ns;
    SimStop := true;
    wait;
  end process;
end architecture;

Ejemplo para generar una forma de onda con una forma de onda genérica:

type T_TIME_VECTOR is array(NATURAL range <>) of TIME;

constant myWaveform : T_TIME_VECTOR  := (
  -- generate "slow" pulse train
  20 * 250 ns,
  250 ns,
  -- generate "fast" pulse train
  50 * 10 ns,
  10 ns
);

procedure generateWaveform(signal Wave : out BOOLEAN; Waveform: T_TIME_VECTOR; InitialValue : BOOLEAN) is
  variable State : BOOLEAN := InitialValue;
begin
  Wave <= State;
  for i in Waveform'range loop
    wait for Waveform(i);
    State := not State;
    Wave  <= State;
  end loop;
end procedure;

signal mySignal : BOOLEAN;

-- begin of architecture
generateWaveform(mySignal, myWaveform);
    
respondido por el Paebbels
1

También puede definir el generador de reloj como una entidad. En lugar de tratar de asignar gen_period como señal, intente definirlo como genérico en la definición de entidad como se muestra a continuación:

entity clock_gen is
   generic (
       gen_period : time := 10 us  
   );
   port (  
       signal gen_all : boolean := false;  -- wavegen enabled
       signal gen_A : boolean := false;    -- run this signal
       signal A_in : std_logic;            -- manual input (wavegen disabled)
       signal A_gen : std_logic;           -- generated output (internal)
       signal A_out : std_logic            -- final output  
   );  
end entity clock_gen;

Ahora, cuando intenta crear una instancia de la entidad en su módulo de nivel superior, le permitirá definir el parámetro gen_period por separado para cada instancia de clock_gen . El valor predeterminado del parámetro se considerará 10 us si no se menciona por separado durante la instanciación. A continuación se muestran dos ejemplos de uso en arquitectura:

gen1: clock_gen  
   generic map (gen_period => 100 us)  
   port map (  
     gen_all => <some_port1>;
     gen_A   => <some_port2>;
     A_in    => <some_port3>;
     A_gen   => <some_port4>;
     A_out   => <some_port5> 
  );
gen2: clock_gen  
   generic map (gen_period => 1 us)  
   port map (  
     gen_all => <some_port1>;
     gen_A   => <some_port2>;
     A_in    => <some_port3>;
     A_gen   => <some_port4>;
     A_out   => <some_port5> 
  );' 

Si tiene varias instancias de clock_gen con el mismo gen_period , incluso puede llamar a la creación de instancias dentro de un procedimiento for ... generate en su código.

    
respondido por el Avin

Lea otras preguntas en las etiquetas