vhdl
Dフリップフロップ(DFF)およびラッチ
サーチ…
備考
Dフリップフロップ(DFF)およびラッチはメモリ要素である。 DFFは、クロックの一方または他方のエッジで入力をサンプリングします(両方ではない)一方、ラッチはイネーブルの1つのレベルでトランスペアレントであり、他方では記憶されます。次の図は、その違いを示しています。
VHDLのDFFやラッチのモデリングは簡単ですが、考慮する必要がある重要な側面がいくつかあります。
DFFとラッチのVHDLモデルの違い。
信号のエッジを記述する方法。
同期または非同期のセットまたはリセットを記述する方法。
Dフリップフロップ(DFF)
すべての例で:
-
clk
は時計です、 -
d
は入力であり、 -
q
は出力、 -
srst
はアクティブハイの同期リセットで、 -
srstn
はアクティブロー同期リセット、 -
arst
はアクティブハイの非同期リセットであり、 -
arstn
はアクティブローの非同期リセットで、 -
sset
はアクティブな高同期セットで、 -
ssetn
はアクティブロー同期セットで、 -
aset
はアクティブな高非同期セットであり、 -
asetn
はアクティブローの非同期セットです
すべての信号は、タイプieee.std_logic_1164.std_ulogic
です。使用されるシンタックスは、すべてのロジックシンセサイザで正しい合成結果につながるシンタックスです。代わりのシンタックスについては、 クロックエッジ検出の例を参照してください。
立ち上がりエッジクロック
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;
立ち下がりエッジクロック
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;
立ち上がりエッジクロック、同期アクティブハイリセット
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
立ち上がりエッジ・クロック、非同期アクティブ・ハイ・リセット
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
立ち下がりエッジクロック、非同期アクティブローリセット、同期アクティブハイセット
process(clk, arstn)
begin
if arstn = '0' then
q <= '0';
elsif falling_edge(clk) then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
立ち上がりエッジクロック、非同期アクティブハイリセット、非同期アクティブローセット
注:setはリセットよりも優先度が高い
process(clk, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;
ラッチ
すべての例で:
-
en
はイネーブル信号、 -
d
は入力であり、 -
q
は出力、 -
srst
はアクティブハイの同期リセットで、 -
srstn
はアクティブロー同期リセット、 -
arst
はアクティブハイの非同期リセットであり、 -
arstn
はアクティブローの非同期リセットで、 -
sset
はアクティブな高同期セットで、 -
ssetn
はアクティブロー同期セットで、 -
aset
はアクティブな高非同期セットであり、 -
asetn
はアクティブローの非同期セットです
すべての信号は、タイプieee.std_logic_1164.std_ulogic
です。使用されるシンタックスは、すべてのロジックシンセサイザで正しい合成結果につながるシンタックスです。代わりのシンタックスについては、 クロックエッジ検出の例を参照してください。
アクティブハイイネーブル
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;
アクティブローイネーブル
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;
アクティブハイイネーブル、同期アクティブハイリセット
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;
アクティブハイイネーブル、非同期アクティブハイリセット
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
アクティブローイネーブル、非同期アクティブローリセット、同期アクティブハイセット
process(en, d, arstn)
begin
if arstn = '0' then
q <= '0';
elsif en = '0' then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;
アクティブハイイネーブル、非同期アクティブハイリセット、非同期アクティブローセット
注:setはリセットよりも優先度が高い
process(en, d, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;
クロックエッジ検出
短編小説
Whith VHDL 2008、クロックの種類がbit
であれば、 boolean
、 ieee.std_logic_1164.std_ulogic
またはieee.std_logic_1164.std_logic
、クロックエッジ検出を立ち上がりエッジでコーディングすることができます
-
if rising_edge(clock) then
-
if clock'event and clock = '1' then -- type bit, std_ulogic or std_logic
-
if clock'event and clock then -- type boolean
立ち下がりエッジ
-
if falling_edge(clock) then
-
if clock'event and clock = '0' then -- type bit, std_ulogic or std_logic
-
if clock'event and not clock then -- type boolean
これは、シミュレーションと合成の両方に対して、期待どおりに動作します。
注:
std_ulogic
タイプの信号の立ち上がりエッジの定義は、if clock'event and clock = '1' then
よりも少し複雑です。例えば、標準のrising_edge
関数は、異なる定義を持っています。おそらく合成のための差異を作らなくても、それはシミュレーションのために作ることができる。
rising_edge
およびfalling_edge
標準関数の使用を強く推奨します。以前のバージョンのVHDLでは、これらの関数を使用するために、標準パッケージの使用を明示的に宣言する必要があるかもしれません(eg ieee.numeric_bit
bit
)。
注:
rising_edge
およびfalling_edge
標準関数を使用して、非クロック信号のエッジを検出しないでください。いくつかのシンセサイザーは、信号がクロックであると結論づけることができます。ヒント:非クロック信号のエッジを検出するには、シフトレジスタの信号をサンプリングし、シフトレジスタのさまざまなステージでサンプリングされた値を比較することがよくあります。
長い話
Dフリップフロップ(DFF)のモデリングでは、クロック信号のエッジの検出を適切に記述することが不可欠です。エッジは定義上、特定の値から別の値への遷移です。例えば、我々は、型の信号の立ち上がりエッジに定義することができbit
(2つの値をとり、標準VHDL列挙型'0'
と'1'
から遷移として) '0'
に'1'
。 boolean
型のtrue
、 false
からtrue
への遷移として定義することができます。
多くの場合、より複雑な型が使用されます。たとえば、 ieee.std_logic_1164.std_ulogic
型は、 bit
またはboolean
ように列挙型ですが、2ではなく9つの値があります。
値 | 意味 |
---|---|
'U' | 未初期化 |
'X' | 強制不明 |
'0' | 強制的に低レベル |
'1' | 強制的に高レベル |
'Z' | 高インピーダンス |
'W' | 弱い不明 |
'L' | 弱い低レベル |
'H' | 弱い高レベル |
'-' | 気にしない |
このような型の立ち上がりエッジを定義するのは、 bit
またはboolean
場合よりbit
複雑です。たとえば、 '0'
から'1'
へ'1'
移行であると判断できます。しかし、それが'0'
または'L'
から'1'
または'H'
への移行であると決定することもできます。
注:これは、標準のために使用するこの2番目の定義である
rising_edge(signal s: std_ulogic)
で定義された関数ieee.std_logic_1164
。
エッジを検出するさまざまな方法を検討するときは、信号の種類を検討することが重要です。モデリングの目標を考慮に入れることも重要です:シミュレーションのみか論理合成か?これをいくつかの例で説明しましょう。
タイプ・ビットの立ち上がりエッジDFF
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;
技術的には、純粋なシミュレーションセマンティクスの観点から、プロセスP1
は立ち上がりエッジトリガDFFをモデル化します。実際、 q <= d
割り当ては、次の場合にのみ実行されます。
-
clock
(これは感度のリストが表現するものです)に変更し、 -
clock
の現在の値は'1'
です。
clock
はタイプ・ビットであり、タイプ・ビットは値'0'
と'1'
しか持たないので、これはビット・タイプの信号の立ち上がりエッジとして定義したものです。どんなシミュレーターでもこのモデルを処理できます。
注:ロジックシンセサイザーの場合、後で説明するように、状況は少し複雑です。
非同期アクティブ・ハイ・リセットおよびタイプ・ビットを備えた立ち上がりエッジDFF
私たちのDFFに非同期アクティブハイリセットを追加するために、次のようなものを試すことができます:
signal clock, reset, d, q: bit;
...
P2_BOGUS: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' then
q <= d;
end if;
end process P2_BOGUS;
しかし、 これは機能しません 。実行されるq <= d
割当ての条件は、 clock
立上りエッジ、 reset = '0'
なければなりません。しかし、我々がモデル化したのは、
-
clock
またはreset
または両方が変更され、 -
reset = '0'
および -
clock = '1'
これは同じではありません: clock = '1'
'0'
間にreset
が'1'
から'0'
変化すると、 clock
立ち上がりエッジではない間に割り当てが実行されます。
実際、信号属性の助けを借りずにVHDLでこれをモデル化する方法はありません。
P2_OK: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' and clock'event then
q <= d;
end if;
end process P2_OK;
clock'event
は、信号clock
適用される信号属性event
です。 boolean
として評価され、現在の実行フェーズの直前の信号更新フェーズで信号clock
変更された場合にのみtrue
となります。これにより、プロセスP2_OK
はシミュレーション(および合成)で必要なものを完全にモデル化するようになりました。
合成セマンティクス
多くのロジックシンセサイザは、VHDLモデルのセマンティクスではなく、構文パターンに基づいて信号エッジ検出を識別します。言い換えれば、彼らはVHDLコードがどんな振る舞いをしているのかを考えません。それらがすべて認識するパターンの1つは次のとおりです。
if clock = '1' and clock'event then
したがって、プロセスP1
の例でも、すべてのロジックシンセサイザでモデルを合成できるようにするには、それを使用する必要があります。
signal clock, d, q: bit;
...
P1_OK: process(clock)
begin
if clock = '1' and clock'event then
q <= d;
end if;
end process P1_OK;
条件のand clock'event
部分は感度リストと完全に冗長ですが、シンセサイザーにはそれが必要なため...
非同期アクティブ・ハイ・リセットとタイプstd_ulogic
持つ立ち上がりエッジDFF
この場合、クロックの立ち上がりエッジやリセット条件の表現が複雑になることがあります。上記で提案した立ち上がりエッジの定義を保持し、リセットが'1'
または'H'
場合にアクティブであると考えると、モデルは次のようになります。
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4: process(clock, reset)
begin
if reset = '1' or reset = 'H' then
q <= '0';
elsif clock'event and
(clock'last_value = '0' or clock'last_value = 'L') and
(clock = '1' or clock = 'H') then
q <= d;
end if;
end process P4;
注:
'last_value
は、最後の値が変更される前の信号の値を返す別の信号属性です。
ヘルパー関数
VHDL 2008標準では、特にstd_ulogic
などの複数値の列挙型の場合、信号エッジの検出を簡素化するためのいくつかのヘルパ関数が用意されています。 std.standard
パッケージは、 bit
およびboolean
型のrising_edge
およびfalling_edge
関数を定義し、 ieee.std_logic_1164
パッケージはstd_ulogic
およびstd_logic
型でそれらを定義します。
注:以前のバージョンのVHDLでは、これらの関数を使用するために、標準パッケージの使用を明示的に宣言する必要があるかもしれません(eg ieee.numeric_bit in bit)。
前の例を再訪し、ヘルパー関数を使用しましょう:
signal clock, d, q: bit;
...
P1_OK_NEW: process(clock)
begin
if rising_edge(clock) then
q <= d;
end if;
end process P1_OK_NEW;
signal clock, d, q: bit;
...
P2_OK_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P2_OK_NEW;
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P4_NEW;
注:この最後の例では、リセットに関するテストも簡素化しました。フローティングで高インピーダンスのリセットは非常にまれで、ほとんどの場合、この単純化されたバージョンはシミュレーションと合成に適しています。