sobre el código del filtro fir

2

Debajo hay un filtro de 4 toques. Eso significa que el orden del filtro es 4 y por lo tanto tiene 4 coeficientes. La entrada es firmada tipo de 8 bits de ancho. La salida también es de tipo firmado con 16 bits de ancho. El diseño contiene dos archivos. Uno es el archivo principal con todas las multiplicaciones y sumadores definidos en él, y otro para definir la operación D flip flop.

El archivo principal se muestra a continuación:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity fir_4tap is
port(   Clk : in std_logic; --clock signal
        Xin : in signed(7 downto 0); --input signal
        Yout : out signed(15 downto 0)  --filter output
        );
end fir_4tap;

architecture Behavioral of fir_4tap is

component DFF is 
   port(
      Q : out signed(15 downto 0);      --output connected to the adder
      Clk :in std_logic;      -- Clock input
      D :in  signed(15 downto 0)      -- Data input from the MCM block.
   );
end component;  

signal H0,H1,H2,H3 : signed(7 downto 0) := (others => '0');
signal MCM0,MCM1,MCM2,MCM3,add_out1,add_out2,add_out3 : signed(15 downto 0) := (others => '0');
signal Q1,Q2,Q3 : signed(15 downto 0) := (others => '0');

begin

--filter coefficient initializations.
--H = [-2 -1 3 4].
H0 <= to_signed(-2,8);
H1 <= to_signed(-1,8);
H2 <= to_signed(3,8);
H3 <= to_signed(4,8);

--Multiple constant multiplications.
MCM3 <= H3*Xin;
MCM2 <= H2*Xin;
MCM1 <= H1*Xin;
MCM0 <= H0*Xin;

--adders
add_out1 <= Q1 + MCM2;
add_out2 <= Q2 + MCM1;
add_out3 <= Q3 + MCM0;

--flipflops(for introducing a delay).
dff1 : DFF port map(Q1,Clk,MCM3);
dff2 : DFF port map(Q2,Clk,add_out1);
dff3 : DFF port map(Q3,Clk,add_out2);

--an output produced at every positive edge of clock cycle.
process(Clk)
begin
    if(rising_edge(Clk)) then
        Yout <= add_out3;
    end if;
end process;

end Behavioral;

El código VHDL para el componente DFF se proporciona a continuación:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity DFF is 
   port(
      Q : out signed(15 downto 0);      --output connected to the adder
      Clk :in std_logic;      -- Clock input
      D :in  signed(15 downto 0)      -- Data input from the MCM block.
   );
end DFF;

architecture Behavioral of DFF is 

signal qt : signed(15 downto 0) := (others => '0');

begin 

Q <= qt;

process(Clk) 
begin 
  if ( rising_edge(Clk) ) then 
    qt <= D;
  end if;       
end process; 

end Behavioral;

He escrito un pequeño código de banco de pruebas para probar el diseño. Contiene 8 entradas de prueba que se aplican en serie al módulo de filtro. Vea abajo:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY tb IS
END tb;

ARCHITECTURE behavior OF tb IS 

   signal Clk : std_logic := '0';
   signal Xin : signed(7 downto 0) := (others => '0');
   signal Yout : signed(15 downto 0) := (others => '0');
   constant Clk_period : time := 10 ns;

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.fir_4tap PORT MAP (
          Clk => Clk,
          Xin => Xin,
          Yout => Yout
        );

   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin        
      wait for Clk_period*2;
        Xin <= to_signed(-3,8); wait for clk_period*1;
        Xin <= to_signed(1,8); wait for clk_period*1;
        Xin <= to_signed(0,8); wait for clk_period*1;
        Xin <= to_signed(-2,8); wait for clk_period*1;
        Xin <= to_signed(-1,8); wait for clk_period*1;
        Xin <= to_signed(4,8); wait for clk_period*1;
        Xin <= to_signed(-5,8); wait for clk_period*1;
        Xin <= to_signed(6,8); wait for clk_period*1;
        Xin <= to_signed(0,8);

      wait;
   end process;

END;

La pregunta principal es que el resultado de la simulación es bueno y si este código funcionará en el dispositivo fpga virtex 4. Estoy usando el software xilinx y este software tiene generadores de ip core pero no los estoy usando porque quiero obtener una buena codificación práctica.

    
pregunta kannan

3 respuestas

5

Agregue a su banco de pruebas un proceso de monitoreo que vigile la salida y la compare con el valor esperado, lo que permite los retrasos a través del filtro.

Su estilo VHDL es mejor que algunos, incluso mejor que algunos ejemplos de libros de texto que he visto, pero aún así: algunos comentarios:

  1. Uso de asignación nombrada en lugar de posicional para el "dff" Las instancias de componentes salvarán la posible confusión entre las entradas. y salidas para cualquiera que intente seguir la tubería. Esto no Realmente importa aquí, porque:

  2. puedes eliminar los dffs por completo; reemplazarlos con lineas de la forma Q1 <= MCM3; en el mismo proceso cronometrado que Yout <= add_out3; que simplifica enormemente todo el filtro.

  3. Puede reducir el número de funciones de conversión al hacer tipos de enteros H0..3; y si son constantes, hazlas constantes! Como se define la multiplicación entre un signo y un entero, no se requieren otros cambios.

    type coefficient is new integer range -128 .. 127;
    constant H0 : coefficient := -2;

  4. Pierde los paréntesis redundantes en if ( rising_edge(Clk) ) then , ¡esto no es C!

  5. El principio DRY también se aplica a VHDL ... hay varias maneras de aplicarlo al banco de pruebas: mi elección sería un procedimiento local.

   stim_proc: process

      procedure Input(D : in integer range -128 .. 127) is
      begin
         Xin <= to_signed(D,8); 
         wait for clk_period*1;
      end Input;

   begin        
      wait for Clk_period*2;
        Input(-3);
        Input( 1);
    
respondido por el Brian Drummond
2

La tarea

La tarea en cuestión es verificar que el comportamiento de su dispositivo, la entidad fir_4tap , coincida con una especificación determinada. Asumiré entonces que su filtro debe coincidir con la siguiente ecuación:

$$ y = \ sum_ {n = 0} ^ {3} b_n \ cdot x_n $$

Necesitamos una referencia

Lo primero que necesitamos es un modelo de referencia con el que podamos comparar el diseño RTL. Entonces, comencemos con una función VHDL que coincide con el comportamiento de la ecuación:

function filter_kernel( x : real_vector(0 to 3); b : real_vector(0 to 3)) return real is
    variable y : real := 0.0;
begin
    for n in x'range loop
        y:= y + b(n) * x(n);
    end loop;
    return y;
end function filter_kernel;

Con nuestra función de referencia en su lugar, necesitamos envolverla en un proceso cronometrado para poder compararla con el diseño RTL:

    reference_model : process is
       variable x : real_vector(0 to 3) := (others => 0.0);
       variable y_ref : real;
    begin
        wait until falling_edge(clk);
        y_ref := filter_kernel(x, b);
    end process reference_model;

Conéctalo todo junto

Y por último, necesitamos conectarlo a una fuente de estímulo y comparar la salida con nuestro diseño RTL. Llamémoslo nuestro banco de pruebas:

entity testbench is
end entity testbench;

architecture bench of testbench is
    constant b : real_vector(0 to 3) := (1.0, 0.0, 0.0, 0.0);
    signal clk : std_ulogic := '0';
    signal x : signed(7 downto 0);
    signal y : signed(15 downto 0);
begin
    clk <= not clk after 10 ns;

    device_under_test : fir_4tap(clk => clk, Xin => x, Yout => y);

    reference_model : process is
       variable x : real_vector(0 to 3) := (others => 0.0);
       variable y_ref : real;
       variable RV : RandomPType; -- See http://www.osvvm.org for details.
    begin
        wait until falling_edge(clk);

        fir_filter : y_ref := filter_kernel(x, b);

        update_x : x := RV.RandReal & x(0 to 2);

        compare_outputs : assert y_ref = to_real(sfixed(y));
    end process reference_model;
end architecture bench;

Resumen

Y eso es básicamente todo lo que hay que hacer:

  1. Necesitas una referencia. Podría ser un modelo VHDL como en este caso, o podría ser datos de un archivo.
  2. Necesitas una forma de generar estímulo. Esto también podría ser datos aleatorios como aquí, o un conjunto de datos dorado.
  3. Debe comparar su diseño con el modelo de referencia. Preferiblemente esto debería ser manejado automáticamente por su banco de pruebas.

Hay mucho más que aprender acerca de la verificación, pero al menos debería comenzar. A continuación, quizás agregue más casos de prueba:

  • ¿Necesita probar más conjuntos de coeficientes?
  • ¿Te importa la saturación y el desbordamiento?
  • ¿Prueba la tubería de la manija del banco?
  • ¿Quizás desee extraer datos para visualizar la respuesta del filtro?

Como ve, hay mucho más trabajo por hacer. Buena suerte!

    
respondido por el trondd
-2

¡Pruébalo! Sinceramente, es la respuesta. No existe una técnica para saber si un código funcionará o no en un dispositivo físico, especialmente si pensamos en restricciones externas como la integridad de la señal de PCB, las ubicaciones de los pines, los relojes y velocidades disponibles, el ancho de banda, los tiempos de retardo, etc.

    
respondido por el Joan

Lea otras preguntas en las etiquetas