シフトレジスタのこの単純なVHDLパターンが期待どおりに機能しないのはなぜですか


8

一見すると、以下のVHDLソースコードがシフトレジスタとして動作することが予想されます。そのqでは、時間が経つと

"UUUU0", "UUU00", "UU000", "U0000", "00000", ....

ただし、常にU5(以上)の連続したクロックサイクルの後です。

どうしてこれなの?

このコードは、実際にははるかに複雑なシミュレーションを大幅に簡略化したものです。しかし、それは私が見る症状を示しています。

ModelSimとActiveHDLの両方でのシミュレーション中に、この興味深い予想外の結果が示されます。他のシミュレーターを試したことがなく、(原因の説明として)他のシミュレーターが同じように動作するかどうかを知りたいと思っています。

この質問に適切に回答するには、次のことを理解する必要があります。

  • これはシフトレジスタを実装する最良の方法ではないことを知っています
  • RTL合成の場合、これにはリセットが必要です。
  • std_logicの配列はstd_logic_vectorです。
  • 集計演算子を知ってい&ます。

私が見つけたもの:

  • 割り当てtemp(0)<='0';がプロセス内で移動された場合、機能します。
  • ループがラップされていない場合(コメント付きのコードを参照)、ループは機能します。

これは、予想外のシミュレーション結果を純粋に表示するように構成された(パイプラインCPUの)より複雑な設計の非常に簡略化されたバージョンであることを繰り返します。実際の信号タイプは単なる簡略化です。このため、フォームのコードをそのまま使用して回答を検討する必要があります。

私の推測では、VHDLシミュレーションエンジンのオプティマイザーは誤って(または仕様に従って)ループ内の信号を変更しないため、ループ内で式を実行する必要がありませんが、ループにラップされていないループを配置することでこれを反証することができます。

したがって、この質問への答えは、コード例が何かを行う最善の方法であるかどうかではなく、VHDLシミュレーションの標準ではないVHDL構文の標準と、VHDLシミュレーションエンジンが最適化をどのように行うかであると思います。

そして今私がシミュレートしているコードに:

 library ieee;
 use ieee.std_logic_1164.all;   

 entity test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
 end entity;

 architecture example of test_simple is
    type   t_temp is array(4 downto 0) of std_logic;
    signal temp : t_temp;
 begin

    temp(0) <= '0';

    p : process (clk)
    begin               
        if rising_edge(clk) then
            for i in 1 to 4 loop
                    temp(i) <= temp(i - 1);
            end loop;

            --temp(1) <= temp(0);   
            --temp(2) <= temp(1);
            --temp(3) <= temp(2);
            --temp(4) <= temp(3);
        end if;
    end process p;
    q <= temp(4);
 end architecture;

そしてテストベンチ:

library ieee;
use ieee.std_logic_1164.all;

entity Bench is
end entity;

architecture tb of bench is

component test_simple is
    port (
        clk : in  std_logic;
        q   : out std_logic
    );                   
end component;

signal clk:std_logic:='0';
signal q:std_logic;     
signal rst:std_logic;

constant freq:real:=100.0e3;

begin                       
    clk<=not clk after 0.5 sec / freq;

    TB:process
    begin
        rst<='1';
        wait for 10 us;
        rst<='0';
        wait for 100 us;
        wait;
    end process;

     --Note: rst is not connected
    UUT:test_simple  port map (clk=>clk,q=>q) ;
end architecture;

最初に信号宣言でtempを初期化してみてください。vhdlシミュレーターは、どこで初期化するかについて奇抜です
Matt

temp(0)リテラル定数に関連付けられた「イベント」がないため、シミュレータはへの同時割り当てを無視しているように見えます。内部に割り当てを置くと、processそれを機能させるクロックイベントとの関連付けが作成されます。after割り当てに句を追加することは、潜在的な回避策になるだろうかと思います。
Dave Tweed

回答:


7

これは、詳細な作成時に簡単に評価できるもの、正式には「ローカル静的式」と呼ばれるものに関係しています。これは曖昧に見えるルールですが、ある程度の検討に値します。最終的にはある程度の意味があり、明白でない結果を生成することでシミュレータが警告を出すのは非常に正確です。

現在は、temp(1)コンパイル時(エラボレーション時より前でも)に評価でき、「temp」のビット1でドライバーを生成できます。

ただし、temp(i)ツールにはもう少し作業が必要です。ここでのループ境界の些細な性質(1〜4)を考えると、temp(0)を駆動できず、実行していることは安全であることは人間には明らかです。しかし、境界がlower(foo) to upper(bar)別の場所で宣言されたパッケージ内の関数であると想像してみてください...今、確実に言えることは、temp駆動されることです。つまり、「ローカルに静的な」式はtempです。

つまり、プロセスはこれらのルールによって制約され、のすべてを駆動しtempます。この時点で、複数のドライバーがオンにtemp(0)なります-プロセス駆動(初期値なし、つまり 'u')と外部temp(0) <= '0';。したがって、当然のことながら、2つのドライバーは「U」に解決されます。

代替案は、「ハッキーリトルルール」(意見)であり、ループの境界が定数の場合、1つのことを行いますが、それらが別のものとして宣言されている場合、別のことを行う、など...より奇妙な小さなルールそこには、言語がより複雑になります...私の意見では、より良い解決策ではありません。


良い答え(+1)ですが、「ハッキーリトルルール」の特徴付けには同意しません。シミュレーションの要点は、実際のハードウェアの動作を表すことです。私は、個々のモジュールの独立したコンパイルによって作成された制約を理解し、私は、ルールはその何もするべきであると考えることができ、コンパイル時に評価されるべきであることを。これははるかに一般的な規則であり、システムが「最小の驚き」の原則を順守するのに役立ちます。ツールがそれらの評価を実行しないようにすることは、私にとって「ハック」に感じられます。
Dave Tweed

公正なコメント-たとえば、Adaはこのようなルールについてはるかに複雑で(かつ正式に表現して)、ユーザーにはるかに単純なビューを提示します(CのWTF係数なし!)。VHDLはもともとAdaから単純化された(IMOは少し離れすぎている)。しかし、おそらくそれは...最適化のこの種のを許可したときに(ここでのように)明確に安全とそうでない場合は、それを禁止するルールエイダの「冷凍タイプ」を採用できた
ブライアン・ドラモンドを

ブライアンに感謝します。あなたの言うことは確かに理にかなっています。多くのあいまいなルールではなく、1つの単純なルールの考え方も理にかなっているようです。この動作はすべてのシミュレーターに当てはまる(そして実際に指定されている)と思いますか、それとも私が試した2つだけですか?
Jason Morgan

2
別のことをするものを見つけたら、それに対してバグを報告します!VHDLの最大の批判者が好意的に言うことの1つは、他の言語(Verilogだけでなく)が保証しない場合でも、一貫したシミュレーション結果が保証されることです。(そうですが、時々その欠点も私を悩ませます!)
Brian Drummond

1
クイックフィックス実験:私の答えが正しい場合、「temp(0)<= 'Z';」をドライブできます。したがって、プロセス内ではファントムドライバーを「切断」し、外部ドライバーは機能します...
Brian Drummond
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.