VHDLで「ドントケア」信号を指定するにはどうすればよいですか。


11

ロジックデザインコースでは、たとえば、カルノーマップまたはQuine–McCluskeyアルゴリズムを使用することにより、ロジック関数を最小化することが可能であることを学びました。また、それを学んだ「Do n't Care」値が最小化の可能性を高める。

たとえば、レジ​​スタファイルを取得します。するときの信号は本当に重要ではありません信号です。したがって、「Do n't Care」値を割り当てて、次のようなロジックでより最適化できるようにする必要があります。write_addresswrite_datawrite_enable'0'これらの信号を駆動(レジスタファイル自体ではない)でます。

合成ツールで可能な最適化の余地を増やすために、VHDLでこのような「Do n't Care」値を指定する正しい方法は何ですか?


これまでのところ、次のような適切なものを見つけました。しかし、私はそれぞれのアプローチの長所と短所が何であるか本当にわかりません:

  • 単に信号を割り当てない。これはうまくいくようです。ただしrecord、レコード定数を完全に指定する必要があるため(少なくともModelsimでそう指示されているため)、何らかのタイプの「何もしない定数」を定義する場合は機能しないことがわかりました。
  • std_logic_1164パッケージには、値定義'-' -- Don't careのためにstd_ulogic。これは、明示的な「ドントケア」に対する意味的に正しい選択のように見えますが、どこでも使用されたことはありません(無関係なVHDL-2008 case?コンストラクトを除く)。
  • Modelsimはこの値'X'を使用して未定義の信号を表示します。しかし、合成ツールが明示的なものを理解しているかどうかはわかりません'X'割り当てを「ドントケア」としてません。

わかりやすくするために過度に簡略化したコードスニペットを示します。ここでは、ドントケア信号を初期化しました。 '-'ます。

ご覧のとおり、信号にcontrol.reg_write_addressは3つの異なる値を設定できます:"----"instruction(11 downto 8);およびinstruction(3 downto 0);。これ'-'は、「ドントケア」と解釈される場合、2入力マルチプレクサに合成されると予想されます。の(others => '0')代わりにを使用して信号を初期化した'-'場合、ツールは代わりに3入力マルチプレクサーを生成する必要があります。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package mytypes is
    type control_signals_t is record
        write_enable  : std_logic;
        write_address : std_ulogic_vector(3 downto 0);
        read_address  : std_ulogic_vector(3 downto 0);
    end record;

    -- All members of this constant must be fully specified.
    -- So it's not possible to simply not assign a value.
    constant CONTROL_NOP : control_signals_t := (
        write_enable  => '0',
        write_address => (others => '-'),
        read_address  => (others => '-')
    );
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library cfx;
use cfx.mytypes.all;

entity control_unit is
    port(
        instruction : in  std_ulogic_vector(15 downto 0);
        write_data  : out std_ulogic_vector(15 downto 0);
        ctrl        : out control_signals_t
    );
end entity;

architecture rtl of control_unit is
begin
    decode_instruction : process(instruction) is
    begin
        -- Set sensible default values that do nothing.
        -- Especially all "write_enable" signals should be '0'.
        -- Everything else is mostly irrelevant (don't care).
        ctrl       <= CONTROL_NOP;
        write_data <= (others => '-');

        if instruction(15 downto 12) = "1100" then
            -- Load 8 bit of data into the register file
            ctrl.write_enable  <= '1';
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
            ctrl.write_address <= instruction(11 downto 8);
        elsif instruction(15 downto 8) = "11111001" then
            -- Load 4 bit of data into the register file
            write_data         <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
            ctrl.write_address <= instruction(3 downto 0);
        elsif instruction(15 downto 8) = "10110101" then
            -- Read from the register file. Don't use the write signals at all.
            ctrl.read_address <= instruction(3 downto 0);
        end if;
    end process;
end architecture;

あなたがして何をしようとして上手の込んだでしたwrite_addresswrite_data?どのような最適化が行われますか?
fru1tbat 14

この例が、私が達成したいことをより明確にすることを願っています。
フリッツ14

回答:


9

より詳細な回答を提供するためにLRMの専門家に任せますが、要するに、あなたのアプローチは有効でなければなりません-Quartusの最新バージョンで簡単なテストを実行し、'-'想定どおりに処理します-生成されるロジックが削減されます出力がデフォルトに設定されている場合は期待どおりです'-''X'ちなみに動作します)。リストしたアプローチの詳細:

  • もちろん、ラッチが必要ない場合は、信号を割り当てないことは実際の例のオプションではありません。クロック処理されたプロセスの場合は、多少改善されますが、必要のない場合でも有効になります。ここにあなたの意図が欠けているのかもしれません。

  • '-'前述のように、セマンティックおよび実用的な理由から、おそらく最良のオプションです。

  • 「未定義」の意味に依存します。'X'技術的には「不明」です。'U'ModelSimが"X"16進表現として表示する未初期化信号用です。'X'ただし、上で述べたように、動作するようです。

別の代替方法は、最適化を自分で行い、明示的にテストされるケースを1つ削除することです。

if instruction(15 downto 8) = "11111001" then
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 4)), 16));
else
  write_data <= std_ulogic_vector(resize(signed(instruction(7 downto 0)), 16));
end if;

ただし、これには重大な欠点(主にコードの明確性に関連する)があり、おそらくより理想的なソリューションを選ぶでしょう。

ちなみに、'-'はで一般的に使用さstd_match()れます。たとえば、デコードに使用することを検討します。

if std_match(instruction(15 downto 8), "1100----") then

ただし、その時点では、おそらくを使用する方が良いでしょうcase?


6

要するに、それは正当なVHDLであり、通常は合成ツールでサポートされています。

ただし、使用されていることはほとんどありません。理由は本当にわかりません。あなたのコードは、それを使用する意味がある場合の良い例のように思えます。

ただし、注意すべき欠点が1つあります。合成では、ドントケアが関係する出力を駆動する関数は、合成の実行によって異なる可能性があります。これにより、合成の確定性が低くなります。do n't careとして定義された出力が(誤って)使用された場合、これによりエラーを見つけにくくすることができます。

ツールサポート

少なくとも次のツールはドントケアを受け入れ、最適化の可能性を利用します。

  • ザイリンクス(参照:「XSTユーザーガイド」)
  • アルテラ(参照:「推奨されるHDLコーディングスタイル」)
  • Synplify(参照:「Synplifyリファレンスマニュアル」)

ザイリンクスとアルテラは扱います'-'し、'X'など気にしない、Synplifyのは、それらを治療し、さらにう'U''W'気にしないと(弱いです)。


1
その欠点の別のアプリケーションがありました。コードは次のように見えたため、シミュレーションでは機能しましたが、FPGAでは機能しませんでしたif signal = '1' then a; else b; end if;。残念ながらsignalありませんでした10けど-。だから、シミュレーションでは、else枝が実行されましたが、ハードウェアで-あることが判明1...真の分岐が実行されたので、
フリッツ

ええ、似たようなバグがシミュレーションを通過しますが、ほとんどの場合、'U'シミュレーションの開始時に一般的なsが使用され、elseコードブロックの実行につながります。'U'並行ブール式の動作と同様に、条件を何とかして伝播させることができれば素晴らしいでしょう。
カール

そのバグを見つけた後、私はいつものようなもの書くようにしましたif signal = '1' then output <= '1'; elsif signal='0' then output <= '0'; else output <= '-'; end if;。そして、私はすべてのレジスタやメモリに次を追加しました:assert not is_X(write_enable) report "we=" & str(A_write_enable) severity ERROR;if write_enable = '1' then assert not is_X(write_addr) report "write_addr=str(write_addr) severity ERROR; end if;。プラスと同じwrite_data。一緒に、それはこれらのエラーのほとんどすべてをキャッチするはずです。
フリッツ

それは方法ですが、それは私にとってあまりにも冗長です。VHDL言語内でこの可能性を望みます。
カール

1
はい、VHDLは少し冗長ですが、それはVHDLの方法です。:D一方、それはまた非常に明示的であり、私の背後で「黒魔術」を行いません。これは非常に素晴らしいことです(PythonのZenは「明示的は暗黙的よりも優れています」)。
フリッツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.