ToMmY_hun
ToMmY_hun

Reputation: 77

VHDL Multiple Processes error

I am writing a VHDL homework, which produces a strange behavior, which I do not understand.

The concept is the following. There should be an LFSR which is used to generate random numbers. The LFSR could be driven by I_CLK or by I_NEXT input. If the LFSR is driven by the I_CLK, it should automatically generate random numbers on its output, but if its driven by the I_NEXT input, it should generate number by changing the I_NEXT value manually from 0 to 1. I have a problem with the following code. If I comment out one of the processes, the LFSR works fine but if all the processes are enabled, it just do not work at all. Could you help me figure out the problem? I think it should be a design error, but I do not know what is wrong with my design.

entity LFSR_v2 is

Generic (
            width       :   positive    :=  31;
            tap_1       :   positive    :=  30;
            tap_2       :   positive    :=  27                
        );

Port ( 
           i_enable     :   in    std_logic;
           i_reset      :   in    std_logic;
           i_clk        :   in    std_logic;

           i_next       :   in    std_logic;           
           i_free_run   :   in    std_logic;
           i_load       :   in    std_logic;
           i_direction  :   in    std_logic;

           o_number     :   out   std_logic_vector (width -1 downto 0);
           i_seed       :   in    std_logic_vector (width -1 downto 0)      

       );

end LFSR_v2;



architecture Behavioral of LFSR_v2 is

signal internal_number  :   std_logic_vector(width -1 downto 0);


begin

-------------------------------------------------------------------------------------------
-- FREE RUNNING PROCESS
--
-- In Free Running mode the LFSR switches its state on every rising edge of the i_clk input.
-------------------------------------------------------------------------------------------
next_number_free_run : process(i_clk, i_reset)
--variable fileline : line;
--variable gen_num  : integer;

    begin 

        if rising_edge(i_clk) then      

            --------------------------------------
            -- NORMAL MODE
            -- enable   =   1
            -- reset    =   0
            --------------------------------------
            if (i_enable = '1' and i_free_run = '1') then


                -- Internal number to the output
                o_number <= internal_number;

                -----------------------------
                -- RESET
                -----------------------------
                if(i_reset = '1') then
                    if(i_direction = '1') then
                        internal_number <= (OTHERS => '1');
                    else
                        internal_number <= (OTHERS => '0');
                    end if;  
                else
                    ------------------------------
                    -- LOAD SEED
                    -- load = 1
                    ------------------------------
                    if(i_load = '1') then
                        internal_number <= i_seed;
                    else     
                        --------------------------------------
                        -- GENERATE NEXT NUMBER - FREE RUNNING
                        -- load = 0
                        -- free_run = 1
                        -------------------------------------                       
                        if(i_direction = '1') then
                            internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
                        else
                            internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
                        end if;

                        ----------------------------------------
                        -- FILE LOGGING
                        ----------------------------------------
                        --gen_num := to_integer(internal_number);
                        --write(fileline, gen_num);
                        --writeline(MyFile, fileline); 

                    end if;

                end if;                       

            end if;

        end if;

    end process next_number_free_run;


    ---------------------------------------------------------------------------------
    -- MANUAL RUNNING PROCESS
    -- 
    -- In this mode the LFSR does not use the input clock to generate the next number.  
    -- Number can be generated by creating a 0 -> 1 signal change on the i_next input.
    ---------------------------------------------------------------------------------
    next_number_man_run : process(i_next, i_reset)
        --variable fileline : line;
        --variable gen_num  : integer;

            begin 

               if rising_edge(i_next) then      

                    --------------------------------------
                    -- NORMAL MODE
                    -- enable   =   1
                    -- reset    =   0
                    --------------------------------------
                    if (i_enable = '1' and i_free_run = '0') then

                        -- Internal number to the output
                        o_number <= internal_number;

                        -----------------------------
                        -- RESET
                        -----------------------------
                        if(i_reset = '1') then
                            if(i_direction = '1') then
                                internal_number <= (OTHERS => '1');
                            else
                                internal_number <= (OTHERS => '0');
                            end if;
                        else
                            ------------------------------
                            -- LOAD SEED
                            -- load = 1
                            ------------------------------
                            if(i_load = '1') then
                                internal_number <= i_seed;
                            else     
                                --------------------------------------
                                -- GENERATE NEXT NUMBER - FREE RUNNING
                                -- load = 0
                                -- free_run = 1
                                -------------------------------------                       
                                if(i_direction = '1') then
                                    internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xnor internal_number(tap_2));
                                else
                                    internal_number <= internal_number(width - 2 downto 0) & (internal_number(tap_1) xor internal_number(tap_2));
                                end if;

                                ----------------------------------------
                                -- FILE LOGGING
                                ----------------------------------------
                                --gen_num := to_integer(internal_number);
                                --write(fileline, gen_num);
                                --writeline(MyFile, fileline); 

                            end if;



                        end if;                       

                    end if;

                end if;

            end process next_number_man_run;

end Behavioral;

Test bench for the code:

    ----------------------------
    -- TEST SEED INIT
    ----------------------------

        -- ENABLE OFF -> SEED SHOULD NOT BE INITIALIZED
        s_enable    <=  '0';
        s_reset     <=  '0';
        s_free_run  <=  '0';
        s_load      <=  '1';
        s_next      <=  '0';
        s_direction <=  '0';

        s_seed   <=  (OTHERS => '1');
        wait for 20 ns;

        -- ENABLE ON -> SEED SHOULD BE INITIALIZED
        s_enable    <=  '1';
        s_reset     <=  '0';

        s_next      <=  '0';
        s_free_run  <=  '0';
        s_load      <=  '1';
        s_direction <=  '0';

        s_seed   <=  (OTHERS => '1');
        wait for 20 ns;

        -- DRIVE MANUAL
        s_next      <=  '1';
        wait for clk_period /2;
        s_next      <=  '0';
        wait for clk_period /2;
        s_next      <=  '1';
        wait for clk_period /2;
        s_next      <=  '0';
        wait for clk_period /2;

Upvotes: 1

Views: 596

Answers (2)

Martin Zabel
Martin Zabel

Reputation: 3659

Instead of using a clock source multiplexer, you should use a synchronous clock-enable as also suggested by Brian.

When the clock enable is high, the LFSR counts up/down one step at the rising edge of the free-running clock i_clk. The definition is:

  • If i_free_run is high, then the clock enable is also high, i.e. counting always.
  • If i_free_run is low, then the clock enable is only high for one clock cycle of i_clk every time i_next has changed from low to high, i.e., single step with i_next.

As i_next is driven by a button, you must:

  • sample the button value with i_clk, i.e., make it synchronous to clock,
  • debounce the sampled button value. i_next is then the output of the debouncer.

I have applied this method to your code. To limit the code size, I have shortened the implementation to just one direction and no initialization with a seed. You have to put in your full implementation as indicated. Please note, that you have to initialize the LFSR with all zero when counting up with XNOR.

library ieee;
use ieee.std_logic_1164.all;

entity LFSR_v2 is
    Generic (
        width       :   positive    :=  31;
        tap_1       :   positive    :=  30;
        tap_2       :   positive    :=  27                
        );
    Port ( 
        i_enable     :   in    std_logic;
        i_reset      :   in    std_logic;
        i_clk        :   in    std_logic;
        i_next       :   in    std_logic;           
        i_free_run   :   in    std_logic;
--        i_load       :   in    std_logic;
--        i_direction  :   in    std_logic;
--        i_seed       :   in    std_logic_vector (width -1 downto 0)
        o_number     :   out   std_logic_vector (width -1 downto 0)
        );
end LFSR_v2;

architecture Behavioral of LFSR_v2 is
    signal internal_number : std_logic_vector(width -1 downto 0);
    signal clock_enable    : std_logic;
    signal next_old        : std_logic := '0';  -- old value of "i_next"
begin

    -- calculate clock enable
    clock_enable <= '1' when i_free_run = '1' else
                    i_next and not next_old;

    process(i_clk)                      -- no i_reset here!
    begin 
        if rising_edge(i_clk) then
            next_old <= i_next;         -- save old value for edge detection

            -- This should be outside of the clock-enable block or even a concurrent statement
            o_number <= internal_number;

            if (clock_enable = '1' and i_enable = '1') then    -- "i_enable" as in original code

                ---------------------------------------------------------------
                -- Replace the following short implementation with your full
                -- implementation
                ---------------------------------------------------------------
                if(i_reset = '1') then
                    internal_number <= (OTHERS => '0');  -- must be all zero for XNOR below!
                else
                    internal_number <= internal_number(width - 2 downto 0) &
                                       (internal_number(tap_1) xnor internal_number(tap_2));
                end if;                       
            end if;
        end if;
    end process;
end Behavioral;

This is my testbench:

library ieee;
use ieee.std_logic_1164.all;

entity LFSR_v2_tb is
end LFSR_v2_tb;

architecture sim of LFSR_v2_tb is
    component LFSR_v2
        generic (
            width : positive;
            tap_1 : positive;
            tap_2 : positive);
        port (
            i_enable    : in  std_logic;
            i_reset     : in  std_logic;
            i_clk       : in  std_logic;
            i_next      : in  std_logic;
            i_free_run  : in  std_logic;
            o_number    : out std_logic_vector (width -1 downto 0));
    end component;

    -- component generics
    constant width : positive := 31;
    constant tap_1 : positive := 30;
    constant tap_2 : positive := 27;

    -- component ports
    signal i_enable    : std_logic;
    signal i_reset     : std_logic;
    signal i_clk       : std_logic := '1';
    signal i_next      : std_logic;
    signal i_free_run  : std_logic;
    signal o_number    : std_logic_vector (width -1 downto 0);

begin  -- sim
    DUT: LFSR_v2
        generic map (
            width => width,
            tap_1 => tap_1,
            tap_2 => tap_2)
        port map (
            i_enable    => i_enable,
            i_reset     => i_reset,
            i_clk       => i_clk,
            i_next      => i_next,
            i_free_run  => i_free_run,
            o_number    => o_number);

  -- clock generation
  i_clk <= not i_clk after 10 ns;

  -- waveform generation
  WaveGen_Proc : process
  begin
      i_free_run <= '1';                -- start with a free-running clock
      i_reset    <= '1';
      i_enable   <= '1';                -- must be high even for reset
      i_next     <= '0';
      wait until rising_edge(i_clk);

      i_reset    <= '0';                -- now let the LFSR toogle on i_clk
      wait until rising_edge(i_clk);
      wait until rising_edge(i_clk);
      wait until rising_edge(i_clk);

      i_free_run <= '0';                -- change to single step mode
      wait until rising_edge(i_clk);
      wait until rising_edge(i_clk);
      wait until rising_edge(i_clk);

      for i in 1 to 3 loop              -- 3 single steps
          i_next <= '1';                    -- do single step
          wait until rising_edge(i_clk);
          wait until rising_edge(i_clk);
          wait until rising_edge(i_clk);
          i_next <= '0';
          wait until rising_edge(i_clk);
          wait until rising_edge(i_clk);
          wait until rising_edge(i_clk);
      end loop;  -- i

      i_free_run <= '1';                -- change back to free-running clock
      wait until rising_edge(i_clk);
      wait;
  end process WaveGen_Proc;
end sim;

And this is the simulation result. Please note, that the output signal changes rapidly at the "..." boxes.

simulation output

Upvotes: 2

Paebbels
Paebbels

Reputation: 16211

You can not implement two different designs in one entity.

Use either:

  1. two entities or
  2. two different architectures of the same entity or
  3. two if..generate statements and a generic parameter to switch the implementations.

Solutions 2 and 3 are not so good in your case, because one uses a clock and the other a next signal. One signal is always unused -> the port list of the entity is filled with dummy signals.

Upvotes: 1

Related Questions