0

説明:

110 または (2) 1 と (1) 0 の任意の組み合わせを検出する 5 ステート シーケンシャル ステート マシンのテスト ベンチを生成しようとしています。既にコードを記述しています。下記参照。間違っているテスト ベンチに問題があります。考えられるすべてのシーケンスと、シーケンスから外れた入力の組み合わせをテストしたいと考えています。

ミーリー マシンに必要なものを実現するための優れたテスト ベンチの例を教えてください。

vhdl コード:

library IEEE;
use IEEE.STD_LOGIC_1164.all;

entity state is
port( clk, x : in std_logic;
      z : out std_logic
      );
end entity;

architecture behavioral of state is
type state_type is (s0,s1,s2,s3,s4);
signal state,next_s: state_type;

------------------------------------------------------------------------------

begin
process (state,x)
begin
if clk='1' and clk'event then

case state is
 when s0 =>
   if(x ='0') then
     z <= '0';
     next_s <= s4;
   else
     z <= '0';
     next_s <= s1;
   end if;

 when s1 => --when current state is "s1"
   if(x ='0') then
     z <= '0';
     next_s <= s3;
   else
     z <= '0';
     next_s <= s2;
   end if;

 when s2 =>  --when current state is "s2"
   if(x ='0') then
     z <= '1';
     next_s <= s0;
   else
     z <= '0';
     next_s <= s0;
   end if;

 when s3 =>  --when current state is "s3"
   if(x ='0') then
     z <= '0';
     next_s <= s0;
   else
     z <= '1';
     next_s <= s0;
   end if;

 when s4 => --when current state is s4
   if (x = '0') then
     z <= '0';
     next_s <= s0;
   else
     z <= '0';
     next_s <= s3;
   end if;
end case;
end if;

end process;
end behavioral;

テスト ベンチ コード:

library ieee;
use ieee.std_logic_1164.all;

-- Add your library and packages declaration here ...

entity state_tb is
end state_tb;

architecture TB_ARCHITECTURE of state_tb is
-- Component declaration of the tested unit
component state
port(
    clk : in STD_LOGIC;
    x : in STD_LOGIC;
    z : out STD_LOGIC );
end component;

-- Stimulus signals - signals mapped to the input and inout ports of tested entity
signal clk : STD_LOGIC;
signal x : STD_LOGIC;
-- Observed signals - signals mapped to the output ports of tested entity
signal z : STD_LOGIC;

-- Add your code here ...

begin

-- Unit Under Test port map
UUT : state
    port map (
        clk => clk,
        x => x,
        z => z
    );

-- CLOCK STIMULI
CLOCK: process
begin
CLK <= not clk after 20 ns;
wait for 40 ns;
end process; 

-- X input STIMULI
X_Stimuli: process
begin
X <= not x after 40 ns;
wait for 80 ns;
end process;

end TB_ARCHITECTURE;

configuration TESTBENCH_FOR_state of state_tb is
for TB_ARCHITECTURE
    for UUT : state
        use entity work.state(behavioral);
    end for;
end for;
end TESTBENCH_FOR_state;
4

2 に答える 2

2

これらは、例のFSMコードとテストベンチコードの両方にいくつかの問題がありますが、主な問題は、FSMをテストするには、入力値のシーケンスを適用して出力を確認する必要がないことです. 入力信号を 1 と 0 の間で切り替えることはできません。そのため、ここにいくつかのアドバイスがあります。

  • 最初に、任意の入力シーケンスを検出する汎用 FSM が必要か、単一のシーケンスのみを検出する FSM が必要かを決定する必要があります (コードは 2 番目のオプションを示しています)。
  • テストでは時間ディメンションを考慮する必要があります。あなたのものはクロック回路です。つまり、各テストには数クロックサイクルかかります。
  • 考えられるすべての入力シーケンスをテストするには、引数として受け取るプロシージャを作成することをお勧めします。
    • FSM への 4 つの入力値のシーケンス (std_logic_vector の場合もあります)
    • 期待される 4 つの出力値のシーケンス
    • (オプション) FSM が通過すると予想される 4 つの状態のシーケンス

手順は次のようになります。

    procedure test_sequence(
        input_sequence: std_logic_vector;
        expected_output_sequence: std_logic_vector
    ) is begin
        for i in input_sequence'range loop
            x <= input_sequence(i);
            wait until rising_edge(clk);
            assert z = expected_output_sequence(i);
        end loop;
    end;

次に、メインのテスト プロセスで、次を使用して 1 つのシーケンスをテストできます。

test_sequence(
    input_sequence => "110",
    expected_output_sequence => "001"
);

その他の提案:

  • テストを容易にし、シミュレーションと合成の間の不一致を防ぐために、リセット信号を追加する必要があります。
  • あなたの場合、設定は必要ありません。コードから削除できます
  • 現在の状態を更新しないため、FSM コードは不完全です
  • 使用しているようなテストベンチでは、DUT への入力として使用される信号 (x および clk) を初期化する必要があります。

上記の手順は、プロセスの宣言領域内にある必要があることに注意してください。何かのようなもの:

main_test_process: process is

    procedure test_sequence(
        input_sequence: std_logic_vector;
        expected_output_sequence: std_logic_vector
    ) is begin
        for i in input_sequence'range loop
            x <= input_sequence(i);
            wait until rising_edge(clk);
            assert z = expected_output_sequence(i);
        end loop;
    end;

begin

    test_sequence( input_sequence => "000", expected_output_sequence => "000");
    test_sequence( input_sequence => "001", expected_output_sequence => "000");
    --  (add any other input sequences here...)
    test_sequence( input_sequence => "110", expected_output_sequence => "001");

    std.env.finish;

end process;

動作するはずです。

于 2014-03-01T12:14:23.187 に答える
1

ステートマシンには、2 のシーケンスに戻ってs0正しく検出する前に、2 つまたは 3 つ1のステップを含む次の可能なサイクルがあります。

Case (x1,x2,x3) States  (z1,z2,z3)
  0    0,0,0     4,0,... 0,0,...   (starts again at s0)             
  1    0,0,1     4,0,... 0,0,...   (starts again at s0)             
  2    0,1,0     4,3,0   0,0,0     (covered by your TB)         
  3    0,1,1     4,3,0   0,0,1              
  4    1,0,0     1,3,0   0,0,0              
  5    1,0,1     1,3,0   0,0,1     (covered by your TB)         
  6    1,1,0     1,2,0   0,0,1              
  7    1,1,1     1,2,0   0,0,0              

私が見ているように、あなたは次のように刺激しています

          __    __    __    __    __
clk    __|  |__|  |__|  |__|  |__|  |__...
             _____       _____       _____ 
x      _____|     |_____|     |_____|     |...

つまり、x=1 の各セクションにはちょうど 1 つの立ち上がりクロックがあるため、0101010... パターンのシーケンスのみをテストしているため、ステートマシンは上の表でマークされた 2 つのパスのいずれかに進みます。これは、他の 6 つの可能なパスがテストベンチで実行されないことを意味します。

このステートマシンには限られた数のパスしかないため、上記の 8 つの可能性のあるケースを基本的に繰り返す徹底的なテストをお勧めします。これは、3 ビット カウンターを使用して簡単に実装できます。したがって、次の形式でシーケンスを作成します

reset
test-case 0 (sequence 0,0,0)
reset
test-case 1 (and so on)

そのためには、エンティティにリセットを追加する必要がありますstates0または、ステートマシンを変更してゼロ入力のままにすることもできます。0,0,0その後、いつでものシーケンスでリセットできます。

于 2014-03-01T12:18:46.737 に答える