はじめに
VHDL-2008で導入されたforce/releaseとexternalについて解説します。
force/releaseについては、2021/Q3までは一般人が無償で使えるシミュレータ(Vivado シミュレータ/ModelSim Intel Starter)では次のような理由で使う機会はあまりありませんでした。
- Vivadoではバージョン2021.2現在force/releaseは未サポート
- ModelSim Intel Starterは10,000ステートメント制限のため、現実的にはモジュール単体でのシミュレーションに限られる
ところが、2021/11月に5,000インスタンスまで実行できるIntelがQuesta Intel Starterを出してくれたおかげでVHDLでも大きなデザインをシミュレーションできるようになり、force/releaseがより実用的になりました。
Questa Intel Starterのインスタンス数については、Questa Intel Starterの制限を確認するを参照下さい。
external nameはVivadoでも以前から使用可能です。
どんな機能?
どちらもシミュレーションで使用する機能です。
シミュレーションなんかしないという悪い子には縁の無い機能です。
force/release
Verilogにあるforce/releaseと同じです。
階層内にあるsignal/portの値を強制的に任意に上書きする機能です。
external name
別のentity階層にあるオブジェクトを参照する機能です。
Verilogでuut.data_rcv.valid
のように.
で階層を区切って参照する機能と同じです。
使い方
force/release
順序処理領域(process/procedure内)で予約語force
を付けてsignal/portに代入する事で、任意の値を一時的に上書きします。
上書き後に対象の信号に対して予約後release
を代入すると、上書きを解除します。
signal CLK : std_logic;
signal valid : std_logic; --CLKの↑エッジで変化する信号
--テストベンチのスティミュラス
process begin
--CLK↓エッジでvalid=1になるのを待つ
wait until falling_edge(CLK) and valid = '1';
data <= force '0'; --'0'を上書きする
wait until falling_edge(CLK); --次のCLKの↓エッジを待つ
data <= release; --上書きを解放
end process
注意すべき点はrelease
実行のタイミングで その時点での本来の値に戻る という事です。
例えば上記のコードで、validがCLKの2サイクルアサートされる場合の波形は以下のようになります。
CLK :_|^|_|^|_|^|_|^|_|^|_|^|
本来の
valid:_____|^^^^^^^|__________
force:-------|___|------------
forceされた
valid:_____|^|___|^|__________
現実的にはこの例のように同じ階層の信号に対してforceする事は無いと思います。
forceは下位の階層の信号に対して実行する事で本来の価値を発揮します。
階層内の信号は次のexternal nameで参照する事が可能です。
external name
以下のようなシミュレーション階層があるとします
+<testbench>---------------+
| +<uut>----------------+ |
| | +<rcv (data_rcv)>-+ | |
| | | | | |
| | +-----------------+ | |
| +---------------------+ |
+--------------------------+
--rcvのentity
entity data_rcv
port (
valid : out std_logic
);
end;
architecture rtl of data_rcv is
signal valid_tmp : std_logic;
begin
proc_rcv: process
variable cnt : integer;
begin
...
end process;
end rtl;
最上位のtestbenchから、下位階層rcvのオブジェクトを以下のように参照できます。
<<
と>>
で囲まれた部分がexternal nameです。
wait until falling_edge(CLK) and <<signal uut.rcv.valid_tmp : std_logic>> = '1';
<<signal uut.rcv.valid_tmp : std_logic>> <= force '0';
wait until falling_edge(CLK);
<<signal uut.rcv.valid_tmp : std_logic>> <= release;
見て分かる通り、非常に長くて煩わしいです。VHDLの型に厳格な性格が滲み出ていますね。
ですので、普通はaliasで別名を付けて参照します。
alias rcv_valid_tmp is <<signal uut.rcv.valid_tmp : std_logic>>; --rcv_valid_tmpとする
wait until falling_edge(CLK) and rcv_valid_tmp = '1'; --rcv_valid_tmpで参照可能
rcv_valid_tmp <= force '0';
external nameで参照可能なオブジェクトは同時処理領域のconstant, signal, variableです。
同時処理領域とは要するにarchitecture直下の事で、process内部で宣言されたconstant, variableは参照できません。
alias cnt is <<variable uut.rcv.proc_rcv.cnt : integer>>; --エラー process内は参照不可
portはsignalと同じ扱いなので、signalとして参照可能です。
alias rcv_valid is <<signal uut.rcv.valid : std_logic>>;
まとめ
VHDL-2008でのシミュレーションで使用可能な以下の2つの機能を説明しました。
- force/releaseでVerilogのforce/releaseと同様の機能を実現できます
- external nameでVerilogと同様に階層内のオブジェクトを参照できます