ISIM（Xilinx製HDLシミュレータ）をBATファイルで起動して使用する方法

# まえおき
XilinxのFPGA開発環境（ISE）に含まれているHDLのシミュレータ（ISIM）を、コマンドラインから起動する手順について紹介します。

# メリット
ISIMは、ISEからGUI操作で起動するのが簡単な方法ですが、コマンドラインから起動することにより以下ののうなメリットがあります。

* ISEによる予備処理が不要（起動までが少し早くなる）
* ISEを立ち上げなくて良い
* 多重起動が可能（ISEから起動すると１本しかSIMが走らない）
* ログだけ落として終了できるので、BATで流すことで何本ものSIMを自動で実行できる。


# 環境
* Windows7
* ISE14.7

# 手順
全体てきな流れは以下のとおりで、これを実現するスクリプトをBATとTCLで記述していきます。

1. パスを通す
2. Verilog/VHDLをコンパイルする
3. シミュレーション実行ファイルを生成する
4. 実行ファイルを起動する
5. シミュレーション時刻を進める
6. シミュレーション実行ファイルを終了させる



# パスを通す

ISEのアイコンを”右クリック”→"プロパティ"とすすむと下図のように"リンク先"が表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/897fcc3a-797f-6d3e-9363-4a80ce2cd0f8.png)

ISE14.7とくにカスタムしないでインストールした場合は↓のようになっていると思います。
前半に書いてあるバッチファイルで環境変数を設定した後、ISEを起動していることが分かります。

```
C:\Xilinx\14.7\ISE_DS\settings64.bat C:\Xilinx\14.7\ISE_DS\ISE\bin\nt64\ise.exe
```

# コンパイル
パスを通すと以下のコマンドが使用可能になりますので、HDLファイルをコンパイルしてゆきます。

コマンド|説明
---|---
vhpcomp|VHDLファイルをコンパイルする
vlogcomp|Verilogファイルをコンパイルする



バッチファイルのあるディレクトリを見に行くと、32bit用と64bit用のバッチファイルがありますので、環境に合わせた方のファイルの中身を見ます。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/10502416-96c9-dd97-6c95-6e5edcc47c35.png)



バッチファイルの中身は↓のようになっています。

```bat:setting64.bat
@echo off
REM Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved.

REM Set current working directory
set XIL_SCRIPT_LOC=%~dp0
REM Remove trailing slash
set XIL_SCRIPT_LOC=%XIL_SCRIPT_LOC:~0,-1%
REM Call settings file for each product
set xlnxInstLocList=
set xlnxInstLocList=%xlnxInstLocList% common
set xlnxInstLocList=%xlnxInstLocList% EDK
set xlnxInstLocList=%xlnxInstLocList% PlanAhead
set xlnxInstLocList=%xlnxInstLocList% ISE
for %%d in (%xlnxInstLocList%) do (
	if EXIST %XIL_SCRIPT_LOC%\%%d\.settings64.bat (
		call %XIL_SCRIPT_LOC%\%%d\.settings64.bat
	)
)
REM Unset XIL_SCRIPT_LOC
set XIL_SCRIPT_LOC=
REM Execute command if any
if "%1" neq "" (
   if /i "%~x1" == ".bat" (
      call %*
   ) else (
      start %*
   )
)
REM Unset xlnxInstLocList
set xlnxInstLocList=
```

ちょっとややこしい感じですね。。。
サブフォルダの"common","EDK","PlanAhead","ISE"の中にある"settings64.bat"を順次実行しているので、中身が気になる方は、”隠しファイルを表示”して、見てみてください。


__要点だけまとめます__
環境変数の"PATH"に以下４つを加えてやればOKということらしいです。

* C:\Xilinx\14.7\ISE_DS\ISE\bin\nt
* C:\Xilinx\14.7\ISE_DS\ISE\lib\nt
* C:\Xilinx\14.7\ISE_DS\ISE\～～～\DocNav
* C:\Xilinx\14.7\ISE_DS\ISE\

なので、作成するバッチファイルの冒頭には↓の記述を入れます。共通部分を一度"Xilinx"という変数に入れていますが、
これが、__ISEのアイコンのプロパティで参照していたBatファイルのあるディレクトリ__になるようにします。

```bat
set XILINX=C:\Xilinx\14.7\ISE_DS\ISE
set PATH=%XILINX%\bin\nt;%XILINX%\lib\nt;%XILINX%\..\..\..\DocNav;%PATH%
```

# コンパイル
パスを通した後は以下のコマンドが使用可能になりますので、HDLファイルをコンパイルしてゆきます。

コマンド|説明
---|---
vhpcomp|VHDLファイルをコンパイルする
vlogcomp|Verilogファイルをコンパイルする

コンパイル対象のソースファイルは"-f"オプションを使用することで、外部ファイルに記述できますので、
-fオプションを使用して、以下のようにBATファイルに記述します。

```bat
set VHDL_LIST=.\src\SIM_LIST_vhd.txt
set VERILOG_LIST=.\src\SIM_LIST_v.txt
vhpcomp -work work -f %VHDL_LIST%
vlogcomp -work work -f %VERILOG_LIST%
```


# 実行ファイル作成
"fuse"コマンドを使用することで、work空間にあるコンパイル済ライブラリから、実行ファイルを生成します。
引数には、__work.<テストベンチトップ階層名>__を与えます。

```bat
fuse work.%TB_NAME%
```

# シミュレーション実行
fuseコマンドで生成したexeファイルを実行し、シミュレーションを走らせます。
fuseコマンドで-oオプション(生成する実行ファイル名の指定)をしなかった場合__"x.exe"__という実行ファイルが生成されていますので、これを実行します。

今回使用しているオプション（引数）は以下３つです。

* -tclbatch
    * ISIM実行時の処理を記述したTCLスクリプトを読み込ませることができます
* -log
    * 実行時のログを落とすファイル名を指定できます
* -gui
    * このオプションをつけるとGUIを起動してシミュレーションを行います（波形が見える） 

```bat
x.exe -tclbatch %TCL_OPTION% -log tmp.log -gui
```

# TCLスクリプト
TCLスクリプトの例を紹介します。
U0階層（検証対象モジュールのTOP階層）の波形を全表示し5us時刻を進める場合の例です。

```tcl
#エラー時の対応設定
onerror {resume}

#波形を追加(U0の階層すべてHEXで表示)
wave add /U0 -radix hex

#シミュレーションを実行
run 5us;

#ＣＵＩで走らせるなら最後exiしておく(ＧＵＩなら落としたくないのでコメントアウト)
#exit
```
TCLスクリプトの書き方について、今回説明は省略しますが、詳細はISIMのユーザーガイドに書いてあります。


# 作成例

ここまで紹介した内容をもとに作成したbatファイル（SimRun.bat）を↓に紹介します。
これを実行することで、ISEを使用しないでISIMによるシミュレーションを実行することが可能です。

```bat:SimRun.bat
@echo off

rem 対象のVHDLファイルを指すリスト
set VHDL_LIST=.\src\SIM_LIST_vhd.txt

rem 対象のVerilogファイルを指すリスト
set VERILOG_LIST=.\src\SIM_LIST_v.txt

rem SIM実行時に読み込ませるTCLファイル
set TCL_OPTION=.\src\SIM_OPTION.tcl

rem テストベンチTOP階層名
set TB_NAME=EdgeDet_tb

rem -------------------------------------------------------------
rem ①パスを通す
rem 変数（XILINX）にISEの起動BATファイルのあるパスを入れる
rem -------------------------------------------------------------
set XILINX=C:\Xilinx\14.7\ISE_DS\ISE
set PATH=%XILINX%\bin\nt;%XILINX%\lib\nt;%XILINX%\..\..\..\DocNav;%PATH%

rem -------------------------------------------------------------
rem ②コンパイル
rem VHDLは "vhpcomp" Verilogは "vlogcomp"を実行する。
rem -workオプションでワークディレクトリ名を指定(指定しないを勝手にworkになる)
rem -f オプションで指定したテキストファイルに書いてあるファイルを参照
rem -------------------------------------------------------------
vhpcomp -work work -f %VHDL_LIST%
vlogcomp -work work -f %VERILOG_LIST%

rem -------------------------------------------------------------
rem ③実行ファイル生成
rem -oオプションで実行ファイル名を指定（指定しないとx.exeになる）
rem -------------------------------------------------------------
fuse work.%TB_NAME%

rem -------------------------------------------------------------
rem ④シミュレーションを実行
rem -tclbatch  :実行オプションを記述してあるTCLファイルを読み込ませる
rem -log       :ログをダンプするファイル名
rem -gui       :GUIで走らせる
rem             CUIで実行する場合はtclの最後でexitする必要がある
rem -------------------------------------------------------------
x.exe -tclbatch %TCL_OPTION% -log tmp.log -gui

rem rename	tmp.log %TESTBENCH_NAME%_%File%.txt
rem	---------------------------------------------
rem 要らないファイルを消す
rem del:ファイル削除 rd:ディレクトリ削除 /q:確認なし
rem	---------------------------------------------
 del /Q fuse.log
 del /Q fuse.xmsgs 
 del /Q fuseRelaunch.cmd 
 del /Q isim.wdb 
 del /Q x.exe
 del /Q tmp.log
 rd  /s /q isim

pause
```

# 作成例の動作環境

* 任意のディレクトリに先ほどの”SimRun.bat”を置く

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/240d3a4a-8eb7-1542-fd01-b164d1c6f30b.png)

* サブディレクトリとしれ"src"フォルダを作成し、以下5つのファイルを置く

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/34321e01-da4e-5707-a523-c269199d7223.png)


【Verilogのファイルを列挙したリスト】

```text:SIM_LIST_v.txt
.\src\EdgeDet_tb.v
```

【VHDLのファイルを列挙したリスト】

```text:SIM_LIST_vhd.txt
.\src\EdgeDet.vhd
```

【検証対象回路】

```vhdl:EdgeDet.vhd
library ieee;
use ieee.std_logic_1164.all;

entity EdgeDet is
	port(
	i_clk	:in		std_logic	;--クロック
	i_rst	:in		std_logic	;--リセット(Hリセット)
	i_src	:in		std_logic	;--ソース信号
	o_rise	:out	std_logic	;--立上りエッジ
	o_fall	:out	std_logic	);--立下りエッジ
end entity;


architecture rtl of EdgeDet is
	signal	buf_ff	:std_logic_vector(0 to 2)	;--Ｄフリップフロップ
	signal	rise	:std_logic					;--立上り検出パルス
	signal	fall	:std_logic					;--立下り検出パルス
begin

	process(i_clk,i_rst)begin
		if(i_rst='1')then
			buf_ff	<="000";
			rise	<='0';
			fall	<='0';
		elsif(Rising_edge(i_clk))then
			--Ｄフリップフロップ
			buf_ff(0)	<=i_src;
			buf_ff(1)	<=buf_ff(0);
			buf_ff(2)	<=buf_ff(1);
			
			--立上り検出
			if(buf_ff(1 to 2) ="10")then
				rise	<='1';
			else
				rise	<='0';
			end if;
			
			--立下り検出
			if(buf_ff(1 to 2) ="01")then
				fall	<='1';
			else
				fall	<='0';
			end if;
			
		end if;
	end process;
	
	o_rise	<=rise;
	o_fall	<=fall;
	
end architecture;
```

【テストベンチ】

```verilog:EdgeDet.v
`timescale 1ns/1ps

module EdgeDet_tb();
	
	reg		i_clk	=1'b0	;
	reg		i_rst	=1'b1	;
	reg		i_src	=1'b0	;
	wire	o_rise			;
	wire	o_fall			;
	
	//検証対象モジュール
	EdgeDet
	U0	//インスタンス名はTCLスクリプトで共通化するためでU0に統一する
	(.i_clk		(i_clk	)
	,.i_rst		(i_rst	)
	,.i_src		(i_src	)
	,.o_rise	(o_rise	)
	,.o_fall	(o_fall	)
	);
	
	//クロック
	always#5 i_clk=~i_clk;
	
	//リセット
	initial #26 i_rst=1'b0;
	
	//入力信号
	initial begin
		#320;
		i_src=1'b1;
		#500;
		i_src=1'b0;
		#450;
		i_src=1'b1;
		#300;
		i_src=1'b0;
		#300;
		$stop;
	end

endmodule
```

【TCLスクリプト】

```tcl:SIM_OPTION.tcl
#エラー時の対応設定
onerror {resume}

#波形を追加(U0の階層すべてHEXで表示)
wave add /U0 -radix hex

#シミュレーションを実行
run 5 us;

#ＣＵＩで走らせるなら最後exiしておく(ＧＵＩなら落としたくないのでコメントアウト)
#exit
```


# シミュレーションの実行
作成した”SimRun.bat”をコマンドプロンプトから叩くか、ダブルクリックすることで、一連の処理が流れます。


* 実行時の応答

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/6fce54a6-fbb1-d4a0-ef15-f1afda451721.png)


* GUIで起動した画面
![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/53964f7c-8f1d-67be-31f7-d01cc983c61d.png)


# 多重起動時の注意点
* 実行時のルートディレクトリそれぞれ別のところにする。

# 連続実行時の高速化方法
回路は変更せずに、__テスト条件だけ変更してSIMを繰り返す場合__は、実行ファイルをそのまま使用することが可能です。
よって、fuseまでの処理は１回のみで x.exeの実行を繰り返し行うことで済みますので、コンパイル時間分が短縮できます。

※ただし、変更する条件は外部ファイルに記述しておき、実行時に読み込むような構成にする必要があります。