概要
バージョン: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;