Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
11 years ago

VHDL and Transposed Fir

Hello guys ,

I'm implementing a transposed fir filter in vhdl in which only the sum are pipelined.

The code I wrote up (using this (http://www.google.it/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0cdaqfjac&url=http%3a%2f%2fwww4.hcmut.edu.vn%2f~hoangtrang%2flecture%2520note%2fdsp%2520on%2520fpga%2fdsp_fpga_ch%252010%2520-%2520fir%2520filter%2520design.pdf&ei=a76eu6uummnp4qt88yggba&usg=afqjcnhr62rzy5-5rvzgccd0nxqz9xaoow&bvm=bv.68911936,d.bge)) until now is the one below:


LIBRARY lpm; 
    USE lpm.lpm_components.ALL;
LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;
    USE ieee.numeric_std.all;
    
ENTITY transposed_fir_test IS
GENERIC (W1 : INTEGER := 16; -- Input bit width
            W2 : INTEGER := 32; -- Multiplier bit width 
            W3 : INTEGER := 35; -- Adder width
            W4 : INTEGER := 16; -- Output bit width
            L : INTEGER := 15;  -- Filter length
            Mpipe : INTEGER := 0-- Pipeline steps of multiplier
);
PORT ( clk : IN STD_LOGIC;
         Load_x : IN STD_LOGIC;
         x_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
         c_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
         y_out : OUT STD_LOGIC_VECTOR(W4-1 DOWNTO 0));
END transposed_fir_test;
ARCHITECTURE fpga OF transposed_fir_test IS
    SUBTYPE N1BIT IS STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
    SUBTYPE N2BIT IS STD_LOGIC_VECTOR(W2-1 DOWNTO 0);
    SUBTYPE N3BIT IS STD_LOGIC_VECTOR(W3-1 DOWNTO 0);
    TYPE ARRAY_N1BIT IS ARRAY (0 TO L-1) OF N1BIT;
    TYPE ARRAY_N2BIT IS ARRAY (0 TO L-1) OF N2BIT;
    TYPE ARRAY_N3BIT IS ARRAY (0 TO L-1) OF N3BIT;
    SIGNAL x : N1BIT;
    SIGNAL y : N3BIT;
    SIGNAL c : ARRAY_N1BIT; -- Coefficient array
    SIGNAL p : ARRAY_N2BIT; -- Product array
    SIGNAL a : ARRAY_N3BIT; -- Adder array
    BEGIN
        
        
        Load: PROCESS ------> Load data or coefficient
            BEGIN
                WAIT UNTIL clk = '1';
                IF (Load_x = '0') THEN
                    c(L-1) <= c_in; -- Store coefficient in register
                    FOR I IN L-2 DOWNTO 0 LOOP -- Coefficients shift one
                        c(I) <= c(I+1);
                    END LOOP;
                    
                ELSE
                    x <= x_in; -- Get one data sample at a time
                END IF;
            END PROCESS Load;
        
        
        SOP: PROCESS (clk) ------> Compute sum-of-products
            BEGIN
                IF rising_edge(clk) THEN
                    FOR I IN 0 TO L-2 LOOP -- Compute the transposed
                        a(I) <= std_logic_vector(signed(p(I)) + signed(a(I+1))); -- filter adds
                    END LOOP;
                        a(L-1) <=std_logic_vector(resize(signed(p(L-1)),W3)); -- First TAP has
                END IF;                                                                      -- only a register
                y <= a(0);
        END PROCESS SOP;
        -- Instantiate L pipelined multiplier
        MulGen: FOR I IN 0 TO L-1 GENERATE
        Muls: lpm_mult -- Multiply p(i) = c(i) * x;
            GENERIC MAP ( LPM_WIDTHA => W1, LPM_WIDTHB => W1,
                              LPM_PIPELINE => Mpipe,
                              LPM_REPRESENTATION => "SIGNED",
                              LPM_WIDTHP => W2,
                              LPM_WIDTHS => W2)
            PORT MAP ( dataa => x,
                            datab => c(I), result => p(I));
        END GENERATE;
y_out <=y(W3-1 DOWNTO W3-W4);
END fpga;

By the way using a delta-stimulus of 32767 and this set of coeff: [32437,31463,29888,27779,25230,22351,19269,16118,13036,10157,7608,5500,3924,2950,2621] I get the following output:

[X,X,X,X,X,1576,1396,1204,1007,814,634,475,343,245,184,163,0]

So it seems I miss the first ouptut samples of the filter and a scaled output..

Any suggestions ??

ty !

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    to get initial values correctly you need to set accumulators to zero start.

    you are scaling by discarding 19 bits. Is that what you wanted?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    to get initial values correctly you need to set accumulators to zero start.

    you are scaling by discarding 19 bits. Is that what you wanted?

    --- Quote End ---

    Yep, those X's are related to the initial values of the C matrix.

    As long as I need only 16 bit I have to take only the MSbs at the output. The magnitude is ok. I was a little confused because the very first values at the output of the filter where not shown due to the lack of initialization of the C matrix.

    One curiosity, now the filter coefficient are uploaded at the same clock of the input signal. By the way I want to control the coefficient uploading with a different clock (I want to set the coefficient via NIOS PIOs).

    I've thought to use a first pio to load the coefficient into c_in and a secondo pio to get the c_in loaded (so it acts like the clock of the previus code). I ended up with this code:

    -- This is a generic FIR filter generator
    -- It uses W1 bit data/coefficients bits
    LIBRARY lpm; -- Using predefined packages
        USE lpm.lpm_components.ALL;
    LIBRARY ieee;
        USE ieee.std_logic_1164.ALL;
        USE ieee.numeric_std.all;
        
    ENTITY transposed_fir_test IS ------> Interface
    GENERIC (W1 : INTEGER := 16; -- Input bit width
                W2 : INTEGER := 32; -- Multiplier bit width 2*W1
                W3 : INTEGER := 35; -- Adder width = W2+log2(L)-1
                W4 : INTEGER := 16; -- Output bit width
                L : INTEGER := 15;  -- Filter length
                Mpipe : INTEGER := 0-- Pipeline steps of multiplier
    );
    PORT ( clk : IN STD_LOGIC;
             rst : IN STD_LOGIC;
             Load_x : IN STD_LOGIC;
             x_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
             c_in : IN STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
             wr_clk : IN STD_LOGIC;
             y_out : OUT STD_LOGIC_VECTOR(W4-1 DOWNTO 0));
    END transposed_fir_test;
    ARCHITECTURE fpga OF transposed_fir_test IS
        SUBTYPE N1BIT IS STD_LOGIC_VECTOR(W1-1 DOWNTO 0);
        SUBTYPE N2BIT IS STD_LOGIC_VECTOR(W2-1 DOWNTO 0);
        SUBTYPE N3BIT IS STD_LOGIC_VECTOR(W3-1 DOWNTO 0);
        TYPE ARRAY_N1BIT IS ARRAY (0 TO L-1) OF N1BIT;
        TYPE ARRAY_N2BIT IS ARRAY (0 TO L-1) OF N2BIT;
        TYPE ARRAY_N3BIT IS ARRAY (0 TO L-1) OF N3BIT;
        SIGNAL x : N1BIT;
        SIGNAL y : N3BIT;
        SIGNAL c : ARRAY_N1BIT; -- Coefficient array
        SIGNAL p : ARRAY_N2BIT; -- Product array
        SIGNAL a : ARRAY_N3BIT; -- Adder array
        BEGIN
            x <= x_in;
            
            Load: PROCESS(wr_clk,Load_x) ------> Load data or coefficient
                BEGIN
                    if(rising_edge(wr_clk)) then
                        IF (Load_x = '0') THEN
                            c(L-1) <= c_in; -- Store coefficient in register
                            FOR I IN L-2 DOWNTO 0 LOOP -- Coefficients shift one
                                c(I) <= c(I+1);
                            END LOOP;
                        ELSE
                            ;
                        END IF;
                    end if;
                END PROCESS Load;
            
            
            SOP: PROCESS (clk) ------> Compute sum-of-products
                BEGIN
                    IF rising_edge(clk) THEN
                        FOR I IN 0 TO L-2 LOOP -- Compute the transposed
                            a(I) <= std_logic_vector(signed(p(I)) + signed(a(I+1))); -- filter adds
                        END LOOP;
                        a(L-1) <=std_logic_vector(resize(signed(p(L-1)),W3)); -- First TAP has
                    END IF;                                                                      -- only a register
                    y <= a(0);
            END PROCESS SOP;
            -- Instantiate L pipelined multiplier
            MulGen: FOR I IN 0 TO L-1 GENERATE
            Muls: lpm_mult -- Multiply p(i) = c(i) * x;
                GENERIC MAP ( LPM_WIDTHA => W1, LPM_WIDTHB => W1,
                                  LPM_PIPELINE => Mpipe,
                                  LPM_REPRESENTATION => "SIGNED",
                                  LPM_WIDTHP => W2,
                                  LPM_WIDTHS => W2)
                PORT MAP ( dataa => x,
                                datab => c(I), result => p(I));
            END GENERATE;
            
            y_out <=y(W3-1 DOWNTO W3-W4);
            
    END fpga;

    Any suggestions ?

    What can I do if I want to intialize to 0's the C matrix while resetting ?

    ty !
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    to initilaise use := (others => (others => '0'));

    your dividing by 2^19 may not be right for unity gain. Your output will be scaled somewhere above or below unity
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thank you kaz !

    I have never understand if that type initialization is true also during the power up .. could you confirm it ?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Thank you kaz !

    I have never understand if that type initialization is true also during the power up .. could you confirm it ?

    --- Quote End ---

    yes it is supported as initial values on registers at powerup