Search code examples
randomnumbersvhdlgeneratorlfsr

Pseudo Random Number Generator using LFSR in VHDL


I'm having a bit of trouble creating a prng using the lfsr method. Here is my code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity pseudorng is
Port ( clock : in STD_LOGIC;
       reset : in STD_LOGIC;
       Q : out STD_LOGIC_VECTOR (7 downto 0);
       check: out STD_LOGIC);

       constant seed: STD_LOGIC_VECTOR(7 downto 0) := "00000001";
end pseudorng;

architecture Behavioral of pseudorng is

signal temp: STD_LOGIC;
signal Qt: STD_LOGIC_VECTOR(7 downto 0);

begin

PROCESS(clock)
BEGIN

IF rising_edge(clock) THEN
IF (reset='1') THEN Qt <= "00000000";
ELSE Qt <= seed; 
END IF;
temp <= Qt(4) XOR Qt(3) XOR Qt(2) XOR Qt(0);
--Qt <= temp & Qt(7 downto 1);

END IF;
END PROCESS;

check <= temp;
Q <= Qt;

end Behavioral;

Here is the simulation I have ran: prng sim

Firstly, the check output is just there so I can monitor the output of the temp signal. Secondly, the line that is commented out is what is causing the problem.

As can be seen from the simulation, on the first rising edge of the clock, the Qt signal reads the seed. However, and this is my question, for some reason the temp signal only XORs the bits of the Qt signal on the second rising edge of the clock. It remains undefined on the first clock pulse. Why is that? If it operated on the first rising edge right after the Qt signal reads the seed, then I could uncomment the line that shifts the bits and it would solve my problem. Any help would be much appreciated!

Here is the test bench if anyone cares:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity tb_pseudorng is
end tb_pseudorng;

architecture bench of tb_pseudorng is

COMPONENT pseudorng
      Port ( clock : in STD_LOGIC;
      reset : in STD_LOGIC;
      Q : out STD_LOGIC_VECTOR (7 downto 0);
      check: out STD_LOGIC);
END COMPONENT;

signal clock1: STD_LOGIC;
signal reset1: STD_LOGIC;
signal Q1: STD_LOGIC_VECTOR(7 downto 0);
signal check1: STD_LOGIC;

begin

mapping: pseudorng PORT MAP(
clock => clock1,
reset => reset1,
Q => Q1,
check => check1);

clock: PROCESS
BEGIN
clock1<='0'; wait for 50ns;
clock1<='1'; wait for 50ns;
END PROCESS;

reset: PROCESS
BEGIN
reset1<='0'; wait for 900ns;
END PROCESS; 

end bench;

Solution

  • I made some slight modifications to what you had (you are pretty much there though); I don't think the LFSR would step properly otherwise. I added an enable signal to the LFSR so you can effectively control when you want it to step. Resulting sim is here.

    Just as a sidenote, you could also include a load and seed inputs if you wanted to seed the LFSR with a different value (instead of making it const).

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    entity pseudorng is
    Port ( clock : in STD_LOGIC;
           reset : in STD_LOGIC;
           en : in STD_LOGIC;
           Q : out STD_LOGIC_VECTOR (7 downto 0);
           check: out STD_LOGIC);
    
    --       constant seed: STD_LOGIC_VECTOR(7 downto 0) := "00000001";
    end pseudorng;
    
    architecture Behavioral of pseudorng is
    
    --signal temp: STD_LOGIC;
    signal Qt: STD_LOGIC_VECTOR(7 downto 0) := x"01";
    
    begin
    
    PROCESS(clock)
    variable tmp : STD_LOGIC := '0';
    BEGIN
    
    IF rising_edge(clock) THEN
       IF (reset='1') THEN
       -- credit to QuantumRipple for pointing out that this should not
       -- be reset to all 0's, as you will enter an invalid state
          Qt <= x"01"; 
       --ELSE Qt <= seed;
       ELSIF en = '1' THEN
          tmp := Qt(4) XOR Qt(3) XOR Qt(2) XOR Qt(0);
          Qt <= tmp & Qt(7 downto 1);
       END IF;
    
    END IF;
    END PROCESS;
    -- check <= temp;
    check <= Qt(7);
    Q <= Qt;
    
    end Behavioral;
    

    And tb:

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    entity tb_pseudorng is
    end tb_pseudorng;
    
    architecture bench of tb_pseudorng is
    
    COMPONENT pseudorng
          Port ( clock : in STD_LOGIC;
          reset : in STD_LOGIC;
          en : in STD_LOGIC;
          Q : out STD_LOGIC_VECTOR (7 downto 0);
          check: out STD_LOGIC);
    END COMPONENT;
    
    signal clock1: STD_LOGIC;
    signal reset1: STD_LOGIC;
    signal Q1: STD_LOGIC_VECTOR(7 downto 0);
    signal check1: STD_LOGIC;
    signal en : STD_LOGIC;
    
    begin
    
    mapping: pseudorng PORT MAP(
    clock => clock1,
    reset => reset1,
    en => en,
    Q => Q1,
    check => check1);
    
    clock: PROCESS
    BEGIN
       clock1 <= '0'; wait for 50 ns;
       clock1 <= '1'; wait for 50 ns;
    END PROCESS;
    
    reset: PROCESS
    BEGIN
       reset1 <= '0';
       en <= '1';
       wait for 900 ns;
    END PROCESS;
    
    end bench;