1

VHDL の宿題を書いていますが、理解できない奇妙な動作が発生します。

コンセプトは以下。乱数の生成に使用される LFSR が必要です。LFSR は、I_CLK または I_NEXT 入力によって駆動できます。LFSR が I_CLK によって駆動される場合、その出力で乱数を自動的に生成する必要がありますが、I_NEXT 入力によって駆動される場合、I_NEXT 値を手動で 0 から 1 に変更して数値を生成する必要があります。次の問題があります。コード。プロセスの 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;
4

2 に答える 2

2

クロック ソース マルチプレクサを使用する代わりに、Brian も提案しているように、同期クロック イネーブルを使用する必要があります。

クロック イネーブルが High の場合、LFSR はフリーランニング クロックの立ち上がりエッジで 1 ステップ カウント アップ/ダウンしi_clkます。定義は次のとおりです。

  • が高い場合i_free_run、クロック イネーブルも高い、つまり常にカウントします。
  • がローの場合、クロック イネーブルはローからハイに変化するたびi_free_runに 1 クロック サイクルだけハイになります。i_clki_nexti_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;

そしてこれがシミュレーション結果です。「...」ボックスで出力信号が急速に変化することに注意してください。

シミュレーション出力

于 2016-01-06T08:29:25.800 に答える