概要
バージョン:Vivado 2019.1
xsim(Vivadoシミュレータ)使用上のバッドノウハウ
いろいろ言いたいことはあるけど、無償で制限無しの混合言語シミュレーションが出来るのであまり文句は言わない
VHDL-2008のサポート範囲がVivado合成とxsimで違う!、その上どちらかがもう一方のサブセット/スーパーセットという関係でもないので、気を付ける必要がある。
シミュレーションなんてしない、実機デバッグとVivadoロジアナさえあれば万事OKという人は、Vivado合成の方がVHDL-2008のサポート範囲が広いはずなのでご自由に。
そもそもVHDL使うなんて変態か、という意見はごもっとも。でも俺はVHDLが好きだ。(downtoなんて書かせるのと、チン…じゃなくてcomponent宣言を除いて)
使えるはずの記述はModelSim Intel 10.5bで確認
但しModelSimもエラーチェックが緩い所があり、本来エラーにすべき記述がスルーされてしまう事もあるのでModelSimが絶対正しいとは限らない。
to_string()が使えない (VHDL-2008)
未サポートというエラーになる
ERROR: [XSIM 43-4187] (中略) : The "Vhdl 2008 to_string Operator" is not supported yet for simulation.
合成でも同様。まあ、合成では使わないけど
ERROR: [Synth 8-5883] invalid operator type for expression
ieee.std_logic_1164で宣言される以下の変換関数は使えるが、to_bstringだけは使えない
to_stringへのエイリアスで宣言されているため
function TO_OSTRING (VALUE : STD_ULOGIC_VECTOR) return STRING; -- 8進文字列に変換 OK
function TO_HSTRING (VALUE : STD_ULOGIC_VECTOR) return STRING; --16進文字列に変換 OK
alias TO_BSTRING is TO_STRING [STD_ULOGIC_VECTOR return STRING]; --2進文字列に変換
--実体はto_stringなのでNG
integer,timeのようなscalar型ならto_stringはT'image(x)で代用可能
variable i : integer;
variable t : time;
...
report integer'image(i);
report time'image(t);
型によってto_stringと使い分けを考えるのが面倒なので、自分はパッケージを作ってそこでto_string()として実装してる。
package sim_pkg is
function to_string(v: integer) return string;
function to_string(v: time) return string;
package body sim_pkg is
function to_string(v: integer) return string is
begin
return integer'image(v);
end;
function to_string(v: time) return string is
begin
return time'image(v);
end;
end;
std.env.resolution_limitが-12psを返す (VHDL-2008)
Xilinxフォーラム xsim:VHDL-2008 function resolusion_limit returns -12 ps
VHDL-2008で追加されたresolusion_limitは >0 な時間を返すはずが、あろうことか負の時間である-12psを返す
そのため、シミュレータでの最小時間だけ待つ下記のコードが実行時エラーになる
use std.env.all;
...
wait for resolution_limit; --エラー wait for -12 ps になる
下記で代用可
delay_length'succ(delay_length'low)
厳密には正しくないかもしれないが、ModelSimでも複数のResolution設定で動作した
宣言部以外で'subtypeにさらにattributeを適用するとエラー
コンパイルは出来るが、エラボレーションでEXCEPTION_ACCESS_VIOLATIONが発生して内部エラーになってしまう
合成でもエラーになるので、そもそも'subtypeがちゃんとサポートされていないらしい
variable cnt : natural range 0 to 3;
subtype cnt_t : cnt'subtype; --cntの型になる 合成でもOK
constant cnt_t_high : integer := cnt_t'high; --OK:3
constant cnt_high : integer := cnt'subtype'high; --OK:3 ここでは使える
--合成では unsupported attribute でエラーになる
...
if (cnt = cnt_t'high) --OK
if (cnt = cnt'subtype'high) --エラー
cnt := cnt'subtype'high; --エラー
'subtypeで何がしたいかというと、ローカル変数で宣言した分周カウンタのカウント終了値をローカル変数の宣言から取り出したい
process
variable cnt : natural range 0 to 2; --分周カウンタ 2で終了
begin
wait until rising_edge(CLK);
--cnt = 2と書かずに済む
--cntの宣言を変更すれば条件も合わせて変わる
if (cnt = cnt'subtype'high) then
CLK_div <= not CLK_div; --分周クロック反転
cnt := 0;
else
cnt := cnt + 1;
end if;
end;
ちゃんと定数を宣言すれば同じ事は出来るし、本来こうすべきだけどテストベンチのような書き捨てのコードで楽をしたい
process
constant end_cnt : natural := 2; --分周カウンタ終了値
variable cnt : natural range 0 to end_cnt;
begin
wait until rising_edge(CLK);
if (cnt = end_cnt) then
CLK_div <= not CLK_div; --分周クロック反転
cnt := 0;
else
cnt := cnt + 1;
end if;
end;
順次処理領域でsignalに対して選択代入文が使えない (VHDL-2008 xsim制限)
xsimでは未サポートというエラーになる。合成はOK。
ERROR: [XSIM 43-4187] (中略) : The "Vhdl 2008 Sequential Conditional Signal Assignment" is not supported yet for simulation.
エラー出してくれるだけマシかもね。以前(2018.1くらいの頃)だと恐怖のInternal Errorでコンパイラが落ちて、どこに問題があるのかも分からなかったから。
architecture rtl of tb is
begin
q <= a when (sel = '0') else b; --同時処理領域では以前から使える
process (all)
variable v: sig_logic;
begin
v := a when (sel = '0') else b; --変数代入は出来る
q <= a when (sel = '0') else b; --信号代入はエラー ERROR: [XSIM 43-4187]
end process;
end;
variableが波形ウインドウに追加出来ない (xsim制限)
[AR#63628:Vivado シミュレータでの VHDL 変数トレースのサポートについて](Vivado シミュレータでの VHDL 変数トレースのサポートについて)
いつかサポートされると良いな
分周カウンタなんかはprocessのローカル変数にしたい
process
variable cnt : natural range 0 to 3; --分周カウンタ variableなので波形が見られない
begin
wait until rising_edge(CLK);
if (cnt = 3) then
CLK_div <= not CLK_div; --分周クロック反転
cnt := 0;
else
cnt := cnt + 1;
end if;
end;
ローカル変数というか、スコープを限定したオブジェクトはブロックのローカルsignalで代用可能、しかし記述が増える
block_label: block
signal cnt : natural range 0 to 3; --ブロックのローカルsignalに変更 波形が見られる
begin
process begin
wait until rising_edge(CLK);
if (cnt = 3) then
CLK_div <= not CLK_div; --分周クロック反転
cnt <= 0;
else
cnt <= cnt + 1;
end if;
end;
end block;