VHDL 多进程错误

VHDL Multiple Processes error

我正在写一个 VHDL 作业,它产生了一个我不明白的奇怪行为。

概念如下。应该有一个用于生成随机数的 LFSR。 LFSR 可以由 I_CLK 或 I_NEXT 输入驱动。如果 LFSR 由 I_CLK 驱动,它应该在其输出上自动生成随机数,但如果它由 I_NEXT 输入驱动,它应该通过手动更改 I_NEXT 值来生成随机数从 0 到 1。我对以下代码有疑问。如果我注释掉其中一个进程,LFSR 工作正常,但如果启用所有进程,它就根本不起作用。你能帮我找出问题所在吗?我觉得应该是设计错误,但不知道我的设计有什么问题。

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 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;

您不能在一个实体中实现两种不同的设计。

使用其中之一:

  1. 两个实体或
  2. 同一实体的两种不同架构或
  3. 两个 if..generate 语句和一个用于切换实现的通用参数。

解决方案 2 和 3 在您的情况下不太好,因为一个使用时钟,另一个使用下一个信号。一个信号始终未使用 -> 实体的端口列表中充满了虚拟信号。

您应该使用同步 clock-enable 而不是使用时钟源多路复用器,正如 Brian 所建议的那样。

当时钟使能为高电平时,LFSR 在free-running 时钟i_clk 的上升沿计数up/down 一步。定义是:

  • 如果i_free_run为高,则时钟使能也为高,即始终计数。
  • 如果i_free_run为低电平,则每次i_next从低电平变为高电平时,时钟使能只高i_clk一个时钟周期,即单步i_next.

由于i_next是由按钮驱动的,您必须:

  • i_clk对按钮值进行采样,即使其与时钟同步,
  • 去抖采样按钮值。 i_next 然后是去抖动器的输出。

我已将此方法应用到您的代码中。为了限制代码大小,我已将实现缩短到仅一个方向,并且没有使用种子进行初始化。您必须按照指示进行完整实施。请注意,当使用 XNOR 计数时,您必须将 LFSR 初始化为全零。

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;

这是我的测试平台:

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;

这是模拟结果。请注意,输出信号在“...”框中快速变化。