3

背景: 3 つの行列を乗算するための動作ファイルを作成しようとしています。最初に入力行列を読み取ってから中間行列を出力できるかどうかを確認して、デバッグしようとしています。

動作ファイル:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

entity DCT_beh is
    port (
            Clk :           in std_logic;
            Start :         in std_logic;
            Din :           in INTEGER;
            Done :          out std_logic;
            Dout :          out INTEGER
          );
 end DCT_beh;

architecture behavioral of DCT_beh is 
begin
    process
            type RF is array ( 0 to 7, 0 to 7 ) of INTEGER;

            variable i, j, k        : INTEGER;
            variable InBlock        : RF;
            variable COSBlock       : RF;
            variable TempBlock      : RF;
            variable OutBlock       : RF;
            variable A, B, P, Sum   : INTEGER; 

    begin

            COSBlock := ( 
    ( 125,  122,    115,    103,    88,     69,     47,     24  ),
    ( 125,  103,    47,     -24,    -88,    -122,   -115,   -69  ),
    ( 125,  69,     -47,    -122,   -88,    24,     115,    103  ),
    ( 125,  24,     -115,   -69,    88,     103,    -47,    -122  ),
    ( 125,  -24,    -115,   69,     88,     -103,   -47,    122  ),
    ( 125,  -69,    -47,    122,    -88,    -24,    115,    -103  ),
    ( 125,  -103,   47,     24,     -88,    122,    -115,   69  ),
    ( 125,  -122,   115,    -103,   88,     -69,    47,     -24  )
                    );

--Starting
    wait until Start = '1';
        Done <= '0';

--Read Input Data
    for i in 0 to 7 loop
        for j in 0 to 7 loop    
            wait until Clk = '1' and clk'event;
            InBlock(i,j) := Din;
        end loop;
    end loop;

--TempBlock = COSBLOCK * InBlock 

    for i in 0 to 7 loop
        for j in 0 to 7 loop
            Sum := 0;
            for k in 0 to 7 loop
                A := COSBlock( i, k ); 
                B := InBlock( k, j ); 
                P := A * B; 
                Sum := Sum + P; 
                if( k = 7 ) then 
                TempBlock( i, j ) := Sum;
                end if;
            end loop;
        end loop;
    end loop;


--Finishing 

    wait until Clk = '1' and Clk'event;
    Done <= '1';

--Output Data

    for i in 0 to 7 loop
        for j in 0 to 7 loop
            wait until Clk = '1' and Clk'event;
            Done <= '0';
            Dout <=  tempblock(i,j);
        end loop;
    end loop;
end process;      
 end behavioral;

テストベンチ ファイル:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;

 ENTITY lab4b_tb IS
 END lab4b_tb;

ARCHITECTURE behavior OF lab4b_tb IS 

-- Component Declaration for the Unit Under Test (UUT)

COMPONENT DCT_beh
PORT(
     Clk : IN  std_logic;
     Start : IN  std_logic;
     Din : IN  INTEGER;
     Done : OUT  std_logic;
     Dout : OUT  INTEGER
    );
END COMPONENT;


   --Inputs
   signal Clk : std_logic := '0';
   signal Start : std_logic := '0';
   signal Din : INTEGER;

--Outputs
   signal Done : std_logic;
   signal Dout : INTEGER;

   -- Clock period definitions
   constant Clk_period : time := 10 ns;

 BEGIN

-- Instantiate the Unit Under Test (UUT)
   uut: DCT_beh PORT MAP (
      Clk => Clk,
      Start => Start,
      Din => Din,
      Done => Done,
      Dout => Dout
    );

   -- Clock process definitions
   Clk_process :process
   begin
    Clk <= '0';
    wait for Clk_period/2;
    Clk <= '1';
    wait for Clk_period/2;
  end process;


  -- Stimulus process
  stim_proc: process

variable i, j : INTEGER;
variable cnt : INTEGER;

  begin     
     -- hold reset state for 100 ns.

     wait for 100 ns;   

        start <= '1'; 
        wait for clk_period; 
        start <= '0';

    for cnt in 0 to 63 loop
        wait until clk = '1' and clk'event;
            din <= cnt;
        end loop;

        --wait for 100 ns;

        --start <= '1';
        --wait for clk_period;
        --start <= '0';

        --for i in 0 to 63 loop
          -- wait for clk_period;
            --if (i < 24) then
                --din <= 255;
            --elsif (i > 40) then
                --din <= 255;
            --else
                --din <= 0;
            --end if;
        --end loop;


  wait;
  end process;

END;

start = 1 のときに私がしていることから、行列は入力ブロックに読み込まれます。この場合、マトリックスは 0 から 63 までの一意のインクリメンタル値で埋められます。次に、done = 1 の場合、アウトブロックを出力します。これは乗算されたアウト マトリックスです。問題は、私のシミュレーションで、最終的な行列にあるはずの値が正しい順序になっていないことです。たとえば、次の行には、乗算された行列 tempblock の最初の行が含まれています。

 14464.000  15157.000  15850.000  16543.000  17236.000  17929.000  18622.000  19315.000

私のシミュレーションの写真でわかるように、これらの値のいくつかを取得しますが、信号は奇妙な大きな値になります。

din(0), din(1), din(2)...din(n) が inputblock(0,0), inputblock(0,1), inputblock(0, 2) など。しかし、動作ファイルを徹底的に調べたところ、問題は見られませんでした。テストベンチの設計方法に何か問題がありますか?

テストベンチ: 一番下の信号は符号なしの値です

編集:これを出力するのに助けが必要です

        din<=0;


    for i in 0 to 63 loop
        wait until clk = '1' and clk'event;
        if i = 0 then
            Start <= '1','0' after clk_period;
            end if;
            if (i < 24) then
                din <= 255;
            elsif (i > 40) then
                din <= 255;
            else
                din <= 0;
            end if;

    end loop;

回答のコードに似ていると思いましたが、まったく同じ問題に遭遇しました。これはどのように修正されますか?これが現在出力されているものの写真です。正しい値はありますが、1 クロック周期だけシフトされています。 ここに画像の説明を入力

最終編集:自分で解決しました。問題はループ境界にありました。

4

1 に答える 1

2

これがモデルの動作バージョンのように見えるもので、テストベンチです

追加(および更新)

行列の倍数をリアルタイム (クロック) で処理する場合、行列の乗算にかかったクロック数だけ DONE が遅れることがわかります。追加されたレジスタ ファイルの利点を示すために、任意に 2 つのクロックを選択しました。

コードの興味深い部分についてコメントします。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

 ENTITY lab4b_tb IS
 END lab4b_tb;

ARCHITECTURE behavior OF lab4b_tb IS 

   signal Clk:      std_logic   := '0';  -- no reset
   signal Start:    std_logic   := '0';  -- no reset
   signal Din:      INTEGER     := 0;     -- no reset

   signal Done : std_logic;
   signal Dout : INTEGER;

   constant Clk_period : time := 10 ns;

BEGIN

   uut: entity work.DCT_beh -- DCT_beh 
       PORT MAP (
           Clk => Clk,
           Start => Start,
           Din => Din,
           Done => Done,
           Dout => Dout
      );

CLOCK: 
    process
    begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
    end process;

STIMULUS: 
    process
        variable i, j : INTEGER;
        variable cnt : INTEGER;
    begin     

         wait until clk = '1' and clk'event;  -- sync Start to clk

FIRST_BLOCK_IN:
        Start <= '1','0' after 11 ns;  --issued same time as datum 0
        for i in 0 to 63 loop
                if (i < 24) then
                    din <= 255;
                elsif (i > 40) then
                    din <= 255;
                else
                    din <= 0;
                end if;
                wait until clk = '1' and clk'event;
        end loop;
SECOND_BLOCK_N:
        Start <= '1','0' after 11 ns;  -- with first datum
        for cnt in 0 to 63 loop
            din <= cnt; 
            wait until clk = '1' and clk'event;
        end loop;
        din <= 0;  -- to show the last input datum clearly

        wait;
    end process;

END ARCHITECTURE;

2 つの入力ブロックは、新しいブロック値と、最初の出力ブロックのインデックスを提供する元のブロック値です。2 番目のブロックも最初と同じ回答を示し、DONE ハンドシェイクを検証します。

注 開始は、各ブロックの最初のデータムと同時です。

また、クロックの立ち下がりエッジで最初のスタートが表示されないように、入力スティミュラスをクロック境界で開始するように調整しました。

非同期で生成されたパルスがある場合、それらはクロック エッジで生成されていないため、クロック エッジで確実に見られるように 1 ナノ秒延長しました。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

entity DCT_beh is
    port (
        Clk :           in std_logic;
        Start :         in std_logic;
        Din :           in INTEGER;
        Done :          out std_logic;
        Dout :          out INTEGER
      );

 end DCT_beh;

architecture behavioral of DCT_beh is 
    type RF is array ( 0 to 7, 0 to 7 ) of INTEGER;
    signal OutBlock:            RF;
    signal InBlock:             RF;
    signal internal_Done:       std_logic := '0';  -- no reset
    signal Input_Ready:         std_logic := '0';  -- no reset
    signal done_detected:       std_logic := '0';  -- no reset
    signal input_rdy_detected:  std_logic := '0';  -- no reset
    signal last_out:            std_logic := '0';  -- no reset

begin
INPUT_DATA:
    process
    begin
        wait until Start = '1';
        --Read Input Data
        for i in 0 to 7 loop
            for j in 0 to 7 loop    
                wait until Clk = '1' and clk'event;
                InBlock(i,j) <= Din;
                if i=7 and j=7 then
                    Input_Ready <= '1', '0' after 11 ns;  
                end if;
            end loop;
        end loop;
    end process;

WAIT_FOR_InBlock:
    process
    begin   
        wait until clk = '1' and clk'event;
        input_rdy_detected <= Input_Ready;  
        --InBlock valid after the following rising edge of clk
    end process;

TRANSFORM:
    process 
            variable InpBlock       : RF;
            constant COSBlock       : RF :=
            ( 
                ( 125,   122,   115,    103,    88,     69,     47,      24  ),
                ( 125,   103,    47,    -24,   -88,   -122,   -115,     -69  ),
                ( 125,    69,   -47,   -122,   -88,     24,    115,     103  ),
                ( 125,    24,  -115,    -69,    88,    103,    -47,    -122  ),
                ( 125,   -24,  -115,     69,    88,   -103,    -47,     122  ),
                ( 125,   -69,   -47,    122,   -88,    -24,    115,    -103  ),
                ( 125,  -103,    47,     24,   -88,    122,   -115,      69  ),
                ( 125,  -122,   115,   -103,    88,    -69,     47,     -24  )
            );
            variable TempBlock      : RF;
            variable A, B, P, Sum   : INTEGER; 
    begin

        if input_rdy_detected = '0' then
            wait until input_rdy_detected = '1';
        end if;

        InpBlock := InBlock;  -- Broadside dump or swap

--TempBlock = COSBLOCK * InBlock  

-- arbitrarily make matrix multiple 2 clocks long      
      wait until clk = '1' and clk'event;  -- 1st xfm clock

        for i in 0 to 7 loop
            for j in 0 to 7 loop
                Sum := 0;
                for k in 0 to 7 loop
                    A := COSBlock( i, k ); 
                    B := InpBlock( k, j ); 
                    P := A * B; 
                    Sum := Sum + P; 
                    if( k = 7 ) then 
                        TempBlock( i, j ) := Sum;
                    end if;
                end loop;
            end loop;
        end loop;

  --  Done issued in clk cycle of last TempBlock( i, j )  := Sum;

        internal_Done <= '1', '0' after 11 ns;  
        wait until clk = '1' and clk'event;  -- 2nd xfrm clk   
        -- OutBlock available after last TempBlock value stored   

        OutBlock <= TempBlock;   -- Broadside dump or swap
    end process;

Done_BUFFER:
    Done <= internal_Done;


WAIT_FOR_OutBlock:
    process
    begin
        wait until clk = '1' and clk'event;
        done_detected <= internal_Done;
        -- Done can come either before the first output_data transfer
        -- or during the last output data transfer
        -- this gives us the clock delay to finish the last xfm transfer to 
        -- TempBlock( i, j)
        -- Technically part of the output process but was too cumbersome to write
    end process;

OUTPUT_DATA:
    process
    begin
        -- OutBlock is valid after clock edge when Done is true
        for i in 0 to 7 loop
            for j in 0 to 7 loop

                if i = 0 and j = 0 then

                    if done_detected = '0' then
                        wait until done_detected = '1';
                    end if; 
                end if;  

                Dout <=  OutBlock(i,j);                        
                wait until clk = '1' and clk'event;
            end loop;
        end loop;
    end process;

end behavioral;

RF の型定義は、シグナルを介したプロセス間通信を可能にするために、アーキテクチャ宣言部分に移動されました。入力ループ、行列乗算、出力ループは独自のプロセスにあります。また、プロセス間ハンドシェイク (Input_Ready および input_Done (Done)) 用のプロセスを追加し、シグナル input_rdy_detect および done_detect を追加しました。

プロセスが 64 クロックを取ることができる場合、最後のデータ プロセス (Input_Ready および潜在的に Done) を示す信号は、ダウンストリーム プロセスの最後のデータ トランザクション中に実行されます。そうしないとコーディングが非常に面倒になり、フリップフロップが必要になります。

入力プロセスと乗算プロセスの間に追加の RF があり、行列乗算がリアルタイムで実行される場合に同時操作を可能にします (この例では 2 クロックかかります。波形を引き延ばしすぎたくありませんでした)。

ハンドシェークの遅延の一部はコーディング スタイルに関連しているようで、input_rdy_detect および done_detect フリップフロップで解決されています。

最初の波形図は、変換プロセスに現在かかる 2 つのクロックに続く最初の出力データを示しており、A マーカーと B マーカーの間に示されています。

2 つのクロック マトリックス乗算

Done の直後に続く最初の出力データが 78540 であり、波形スクリーン キャプチャに示されている 110415 ではないことがわかります。私たちの 1 人が間違った値を示しています。このバージョンの DCT_beh は、最後のデータが読み込まれた後にのみ、RF 値の転送を厳密に強制します。

入力プロセスと乗算プロセスの間のハンドシェイクをクリーンアップする前に、110415 の値を取得しました。OutBlock の TempBlock を介してトレースするのは大変な作業です。

さて、良いニュースです。2 番目の入力ブロックは元の刺激から取得され、入力値は出力転送の優れた指標になります。これらの出力データ値はすべて正しく表示されます。

2 番目のブロックが完了し、2 番目のブロックの出力の開始

シグナル input_rdy_detect と done_detect は、それぞれのダウン ストリーム プロセスで最初のトランザクションを表示します。2 番目の入力ブロックの最後で混乱を避けるために、後続の din 信号の割り当てを 0 に追加しました。

これはあなたのものに近いスクリーン キャプチャです。ズームを選択することはできません。代わりに逐次近似を使用します。

ここに画像の説明を入力

シミュレーションを 1955 ns まで実行するだけで、出力されている 2 番目のブロックの最後のデータを取得できます。

これは、OS X 10.8.4 を実行している Mac で、Tristan Gingold の ghdl と Tony Bybell の gtkwave を使用して行われました。

于 2013-08-30T12:07:45.687 に答える