Search code examples
vhdl

PRBS Generator module in VHDL


Here i am posting a snapshot of prbs

My code for prbs module is

-- Module Name:    prbs - Behavioral 
-- Project Name:   modulator

-- Description: 
--To make it of N bit replace existing value of N with desired value of N
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity prbs is
    Port ( pclock : in  STD_LOGIC;
            preset : IN std_logic := '0';
           prbsout : out  STD_LOGIC);
end prbs;

architecture Behavioral of prbs is

COMPONENT dff is
    PORT(
        dclock : IN std_logic;
        dreset : IN std_logic;
        din : IN std_logic ;          
        dout : OUT std_logic 
        );
    END COMPONENT;


signal dintern : std_logic_vector (4 downto 1); --Change value of N to change size of shift register
signal feedback : std_logic := '0';

begin

instdff : dff port map (pclock , preset , feedback , dintern(1));
genreg : for i in 2 to 4 generate --Change Value of N Here to generate that many instance of d flip flop
begin
instdff : dff port map ( pclock , preset , dintern(i-1) , dintern(i));
end generate genreg;

main : process(pclock)

begin
    if pclock'event and pclock = '1' then   
            if preset = '0'  then
                if dintern /= "0" then

                    feedback <= dintern(1) xor dintern(3); -- For N equals four;
                    --feedback <= dintern(4) xor dintern(5) xor dintern(6) xor dintern(8); -- For N equals eight;
                    --feedback <= dintern(11) xor dintern(13) xor dintern(14) xor dintern(16); -- For N equals sixteen;
                    --feedback <= dintern(1) xor dintern(2) xor dintern(22) xor dintern(32); -- For N equals thirty two                     

                else
                feedback <= '1';
                end if;
            end if;                                     
    end if; 
end process main;

prbsout <= dintern(4) ; --Change Value of N Here to take output to top entity 

end Behavioral;

In it i am instantiating a d flip flop module

d ff module code

----------------------------------------------------------------------------------
-- Module Name:    dff - Behavioral 
-- Project Name: 
-- Description: 
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity dff is
    Port ( dclock : in  STD_LOGIC ;
           dreset : in  STD_LOGIC ;
           din : in  STD_LOGIC;
           dout : out  STD_LOGIC);
end dff;

architecture Behavioral of dff is

begin
process(dclock)

begin
    if dclock'event and dclock = '1' then
        if dreset = '0' then
            dout <= din;
      else
            dout <= '1';
        end if;
    end if;
end process;


end Behavioral;

But i am not getting desired output. In top level entity i am getting always 1 at prbsout signal.

When i try to simulate then prbsout signal becomes undefined.

What i am missing?


Solution

  • The prbs module reset at preset does not apply to the feedback signal, probably because the intention was to use the initial value of 0 assigned in the declaration of the feedback signal. However, since the dff modules uses synchronous reset, and the dintern signal will be undriven U at start, and since then next value for feedback is calculated using dintern(1) in an xor, the feedback will get undefined right after start, and can't recover, even if a lengthy reset is applied. See waveform from ModelSim below.

    Before preset applied to feedback

    An immediate fix for the reset issue is to apply reset for feedback also in the main process:

    ...
    else  -- preset /= '0'
      feedback <= '0';
    ...
    

    Now at least reset works, and can make the prbs generate a sequence. See waveform below.

    After preset applied to feedback

    Just a few additional comments to the code, while at it:

    • Instead of dclock'event and dclock = '1' you can use rising_edge(dclock), which I think must reader will find easier to understand, and it is less error prone

    • For most tools, it is unnecessary to make a separte module just for a flip-flop, like the dff module, since the tools can infer flip-flop directly from the process even when advanced expressions are used for signal assignments are used.

    But, I don't think the output is what you actually want. Based on your design, and the selected taps for the LFSR, it looks like you want to generate maximum length LFSR sequences, that is sequences with a length of 2 ** N - 1 for a LFSR register being N bits long.

    The principles of LFSR and the taps to for feedback generation is described on Wikipedia: Linear feedback shift register.

    However, since the feedback signal is generated as a flip-flop, it becomes part of the LSFR shift register, thus adds a bit to the length, but the tap values are based on the dintern part of the LFSR only, the taps will be wrong. Selecting the wrong bits will result in a LFSR sequence that is less than then maximum sequence, and you can also see that in the simulation output, where the sequence is only 6 cycles long, even through the dintern(4 downto 1) + feedback together makes a 5 bit register.

    So a more thorough rewrite of the prbs module is required, if what you want is to generate maximum length PRBS sequences, and below is an example of how the prbs module can be written:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity prbs_new is
      generic(
        BITS : natural);
      port(
        clk_i  : in  std_logic;
        rst_i  : in  std_logic;
        prbs_o : out std_logic);
    end entity;
    
    
    library ieee;
    use ieee.numeric_std.all;
    
    architecture syn of prbs_new is
    
      signal lfsr : std_logic_vector(BITS downto 1);  -- Flip-flops with LFSR state
    
      function feedback(slv : std_logic_vector) return std_logic is  -- For maximum length LFSR generation
      begin
        case slv'length is
          when  3     => return slv( 3) xor slv( 2);
          when  4     => return slv( 4) xor slv( 3);
          when  8     => return slv( 8) xor slv( 6) xor slv( 5) xor slv(4);
          when 16     => return slv(16) xor slv(15) xor slv(13) xor slv(4);
          when 32     => return slv(32) xor slv(22) xor slv( 2) xor slv(1);
          when others => report "feedback function not defined for slv'lenght as " & integer'image(slv'length)
                         severity FAILURE;
                         return 'X';
        end case;
      end function;
    
    begin
    
      process (clk_i, rst_i) is
      begin
        if rising_edge(clk_i) then
          if unsigned(lfsr) /= 0 then
            lfsr <= lfsr(lfsr'left - 1 downto lfsr'right) & feedback(lfsr);  -- Left shift with feedback in
          end if;
        end if;
        if rst_i = '1' then  -- Asynchronous reset
          lfsr <= std_logic_vector(to_unsigned(1, BITS));  -- Reset assigns 1 to lfsr signal
        end if;
      end process;
    
      prbs_o <= lfsr(BITS);  -- Drive output
    
    end architecture;
    

    Comments to ´prbs_new´ module

    • Generic BITS is added so diffrent LFSR length can be made from the same code.

    • Ports are named with "_i" for inputs and "_o" for outputs, since this naming convension is very useful when tracing signals at a toplevel with multiple modules.

    • The VHDL standard package ieee.numeric_std is used instead of the non-standard package ieee.std_logic_unsigned.

    • Asynchronous reset is used instead of synchronous reset and initial value in the signal declaration.

      • The advantage over synchronous reset is that asynchronous reset typical applies to a dedicated input on the flip-flops in FPGA and ASIC technology, and not in the potentially timing critical data path, whereby the design can be faster.

      • The advantage over initial value in the signal declation is that FPGA and ASIC technologies are more likely to be able to implement this; there are cases where initial values are not supported. Also functional reset makes restart possible in a test bench without having to reload the simulator.

    • There is no check for an all-0 value of the lfsr signal in the process, since the lfsr will never get an all-0 value if proper maximum length taps are used, and the lfsr signal is reset to a non-0 value.