VHDL多个进程错误

时间:2016-01-05 18:07:12

标签: vhdl multiple-processes

我正在编写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;

2 个答案:

答案 0 :(得分:2)

不应使用时钟源多路复用器,而应使用Brian建议的同步时钟使能。

当时钟使能为高电平时,LFSR在自由运行时钟i_clk的上升沿向上/向下计数一步。定义是:

  • 如果i_free_run为高,则时钟启用也很高,即始终计数。
  • 如果i_free_run为低电平,则每当i_clk从低电平变为高电平时,时钟使能仅在i_next的一个时钟周期内为高电平,即i_next单步执行i_next 1}}。

由于i_clk由按钮驱动,您必须:

  • 使用i_next对按钮值进行采样,即使其与时钟同步,
  • 去抖取样按钮值。然后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; 是辩护人的输出。

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

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;

这是我的测试平台:

scp user1@123.123:/var/www/file.sql user2@456.456:/var/www/

这是模拟结果。请注意,输出信号在&#34; ...&#34;框。

simulation output

答案 1 :(得分:1)

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

使用:

  1. 两个实体或
  2. 同一实体的两种不同架构或
  3. 两个if..generate语句和一个用于切换实现的通用参数。
  4. 在您的情况下,解决方案2和3并不是那么好,因为一个使用时钟而另一个使用下一个信号。一个信号总是未使用 - &gt;实体的端口列表中填充了虚拟信号。