2011年11月8日火曜日

コマンドラインで配置配線のススメ

XILINXのFPGA合成ツールの話です。

ここではise12を使う事を前提に記事を書いてます。
すでにise13.3がリリースされている今なぜise12なの?と思うかもしれませんが、諸事情でise12を使い続けているから仕方がないのです。

これから書く内容はise13ではPlanAhedが使えるツールに進化していて、もう必要ないよって事かもしれませんが、僕の個人的な予想ではise13でもまだコマンドラインを使い続ける必要があるかなと思ってます



通常の開発ではWindowsなりLinuxなりの ISE上でGUIベースのツールを使って開発しますが、あえてCUIベースで論理合成から配置配線までを行います。

コマンドラインで開発を行う目的は以下の3点です

1. 論理合成処理時間短縮
2. 複数の配置配線を同時に行う
3. 完了の通知を行いたい

1) 一番大きなメリットは論理合成の処理時間短縮ですが、大規模な設計で合成処理に1時間近くかかるような場合に、モジュール別の合成を行うことで1/5から1/10の時間短縮ができる可能性があります。
ISEではモジュール別の合成がサポートされていないので、大規模なプロジェクトの場合ちょっとしたソースの変更でも論理合成にかなりの時間が必要になります。
そこで、ソースを大きなブロックで分けて論理合成をすることで、変更の無いモジュールの合成を完全に防ぐ事にします。
PlanAheadのパーティションを使用して配置配線もモジュール毎に固定して行えば時間短縮になりそうですが、試したところあまりよい結果は出ていません。配置配線はスマートガイドを利用するのが一番効果が出ています

2) ISEではワンボタンクリックで全ての処理が自動で出来ますが、処理中は殆どの処理が禁止状態になります。コマンドラインではファイルの競合に気をつけさえすれば、配置配線を同時に実行したり、配置配線中にチップスコープのプローブ作成や、論理合成の実行も自由に行えます。
配置配線中にHDLソースのバグを見つけたときに今の処理を中止して最初からやり直すか、とりあえず結果を見てから論理合成をするか...悩む事が結構ありますが、迷わず別のスレッドで論理合成を実行できます。

コマンドラインだと出力するファイル名を直接指定するので、Makeファイルさえ作っておけば、埋め込むチップスコープのファイル毎に別のbitファイル名にする事等が簡単にできます。逆にGUIではファイルの名前をかえるのは手間がかかります

3)一回の論理合成から配置配線完了まで2時間も3時間もかかる場合に処理が完了したことに気がつかないでいたり、途中でエラー終了していたことに気がつかないで時間を無駄にしてしまうことがあります。
そこで処理の終了時に指定アドレスにメールを送るようにスクリプトを組み込むことで、配置配線完了と同時にメールで通知を受け取ることが出来ます。

そのほかにスクリプトさえ作っておけばバージョン番号をソースに埋め込んだり、bitファイルに埋め込んだりが自動でできたりします


コマンドラインで開発するデメリットは
1. 準備が面倒
2. 構成の変更が面倒
3. 合成エラーとエディタの連携が出来ない
3. サマリーの出力が出来ない?合成結果のタイミング解析等が面倒

デメリットは実行環境を作るのにはGUIでの操作に比べるとかなり手間がかかるといったところです。実際HDLの依存関係をリストするなんて事はGUIでやったほうが早いので、一旦ISEでプロジェクトを作成して必要な設定をコピペする事にします。
ソースを解析してソースツリーを作るようなスクリプトを書くという手もあります

僕はiseでプロジェクトを作って、GUIが便利なところはiseを使って、デバック時の合成をコマンドラインで行うような運用をしています

topの論理合成makefile例。
モジュール毎の階層ディレクトリを作って論理合成は階層毎のmakefileで行います。チップスコープを使いした場合は
make cps_bit CPS_PROJ=cps_test
と実行すると最終的には
top_module_cps_test_download.bit ファイルが出来上がります


TOPHDL      = top_module
CURRENT_DIR = ../module
CPS_PROJ    = test
SRC_DIR     = ../iseproject/hdl
UCS_FLAG    =  -uc $(SRC_DIR)/top/top_module.ucf 
CORE_FLAG   = -sd $(SRC_DIR)/coregen_v6
EDK_DIR     = $(SRC_DIR)/../system
DEVICE_TYPE = xc6vlx130t
DEVICE_NAME = $(DEVICE_TYPE)-1-ff784
SMARTGUIDE  = no
MTFLAG      = -mt off
MAPFLAG     = -w -logic_opt off -ol high -t 1 -xt 0 -register_duplication off -global_opt off $(MTFLAG) -ir off -pr off -lc off -power off

NGCS = \
  system.ngc \
  module1.ngc \
  module2.ngc \
  top_module.ngc

export SRC_DIR

ifeq ($(SMARTGUIDE),yes)
 SMART_OPT= -smartguide $(TOPHDL)_guide.ncd
else
ifeq ($(SMARTGUIDE),no)
 SMART_OPT=
else
 SMART_OPT= -smartguide $(TOPHDL)_$(SMARTGUIDE)_guide.ncd
endif
endif

.PHONY: all clean synthesize bit par cps_edit cps_build cps_bit

all: synthesize bit

clean:
 $(MAKE) -C module1 TARGET=$@
 $(MAKE) -C module2 TARGET=$@
 $(MAKE) -C top_module TARGET=$@
 del /Q *.ngc

synthesize: 
 $(MAKE) -C module1
 $(MAKE) -C module2
 $(MAKE) -C top_module
 cp -a $(EDK_DIR)/implementation/system.ngc ./

bit: $(TOPHDL).bit

par: $(TOPHDL).twx

$(TOPHDL).ngd : $(NGCS) synthesize
 cp -a $(EDK_DIR)/implementation/system_bd.bmm ./edkBmmFile.bmm
 cp -a $(EDK_DIR)/implementation/system.ngc ./
 ngdbuild -intstyle silent -dd _ngo -sd ipcore_dir -nt timestamp $(UCS_FLAG) $(CORE_FLAG) -bm edkBmmFile.bmm -p $(DEVICE_NAME) $(TOPHDL).ngc $(TOPHDL).ngd  

$(TOPHDL)_map.ncd : $(TOPHDL).ngd
 map -intstyle silent -p $(DEVICE_NAME) $(MAPFLAG) $(SMART_OPT) -o $(TOPHDL)_map.ncd $(TOPHDL).ngd $(TOPHDL).pcf 

$(TOPHDL).ncd : $(TOPHDL)_map.ncd
 par -w -intstyle silent -ol high $(MTFLAG) $(SMART_OPT) $(TOPHDL)_map.ncd $(TOPHDL).ncd $(TOPHDL).pcf 

$(TOPHDL).twx : $(TOPHDL).ncd
 trce -intstyle silent -v 3 -s 1 -n 3 -fastpaths -xml $(TOPHDL).twx $(TOPHDL).ncd -o $(TOPHDL).twr $(TOPHDL).pcf 

$(TOPHDL).bit : $(TOPHDL).ncd
 bitgen -intstyle silent -f $(TOPHDL).ut $(TOPHDL).ncd 

$(TOPHDL)_download.bit : $(TOPHDL)_top.bit
 bitinit -bm edkBmmFile_bd.bmm -p $(DEVICE_NAME) $(EDK_DIR)/system.mhs -pe microblaze_0 $(EDK_DIR)/hrboot/hrboot.elf -bt $(TOPHDL).bit -o $(TOPHDL)_download.bit -log bitinit.log

update_bit: $(TOPHDL)_download.bit

## Chip scope inserter ##
$(CPS_PROJ).cdc :
 inserter -intstyle ise -mode initial -proj $(CPS_PROJ).cdc -p $(DEVICE_TYPE) -output_dir $(CURRENT_DIR)/_ngo -ise_project_dir $(CURRENT_DIR)

cps_edit: $(CPS_PROJ).cdc
 inserter -intstyle ise -mode setup -proj $(CPS_PROJ).cdc -ise_project_dir $(CURRENT_DIR) -dd _ngo -p $(DEVICE_NAME) $(TOPHDL).ngc $(TOPHDL)_$(CPS_PROJ)_cs.ngc
 inserter -intstyle ise -mode insert -ise_project_dir $(CURRENT_DIR) -proj $(CURRENT_DIR)/$(CPS_PROJ).cdc -intstyle ise -dd $(CURRENT_DIR)/_ngo -uc $(CURRENT_DIR)/example_top.ucf -uc $(CURRENT_DIR)/gtx_right_top.ucf -uc $(CURRENT_DIR)/vp8408_peripheral_cpu_side.ucf  -sd $(CURRENT_DIR)/../ipcore_dir -p xc6vhx380t-ff1924-1 $(CURRENT_DIR)/$(TOPHDL).ngc $(TOPHDL)_$(CPS_PROJ)_cs.ngc

$(TOPHDL)_$(CPS_PROJ)_cs.ngc: $(CPS_PROJ).cdc $(NGCS)
 inserter -intstyle ise -mode insert -ise_project_dir $(CURRENT_DIR) -proj $(CURRENT_DIR)/$(CPS_PROJ).cdc -intstyle ise -dd $(CURRENT_DIR)/_ngo -uc $(CURRENT_DIR)/$(TOPHDL).ucf -sd $(CURRENT_DIR)/../ipcore_dir -p xc6vhx380t-ff1924-1 $(CURRENT_DIR)/$(TOPHDL).ngc $(TOPHDL)_$(CPS_PROJ)_cs.ngc

$(TOPHDL)_$(CPS_PROJ).ngd: synthesize $(TOPHDL)_$(CPS_PROJ)_cs.ngc
 cp -a $(EDK_DIR)/implementation/system_bd.bmm ./edkBmmFile.bmm
 cp -a $(EDK_DIR)/implementation/system.ngc ./
 ngdbuild -intstyle silent -dd _ngo -sd ipcore_dir -nt timestamp $(UCS_FLAG) $(CORE_FLAG) -bm edkBmmFile.bmm -p $(DEVICE_NAME) $(TOPHDL)_$(CPS_PROJ)_cs.ngc $(TOPHDL)_$(CPS_PROJ).ngd  


$(TOPHDL)_map_$(CPS_PROJ).ncd : $(TOPHDL)_$(CPS_PROJ).ngd
 map -intstyle silent -p $(DEVICE_NAME) $(MAPFLAG) $(SMART_OPT) -o $(TOPHDL)_map_$(CPS_PROJ).ncd $(TOPHDL)_$(CPS_PROJ).ngd $(TOPHDL)_$(CPS_PROJ).pcf 
 cat $(TOPHDL)_map_$(CPS_PROJ).mrp | grep Total

$(TOPHDL)_$(CPS_PROJ).ncd : $(TOPHDL)_map_$(CPS_PROJ).ncd
 par -w -intstyle silent -ol high $(MTFLAG) $(SMART_OPT) $(TOPHDL)_map_$(CPS_PROJ).ncd $(TOPHDL)_$(CPS_PROJ).ncd $(TOPHDL)_$(CPS_PROJ).pcf 
 cat $(TOPHDL)_$(CPS_PROJ).par | grep Total

$(TOPHDL)_$(CPS_PROJ).twx : $(TOPHDL)_$(CPS_PROJ).ncd
 trce -intstyle silent -v 3 -s 1 -n 3 -fastpaths -xml $(TOPHDL)_$(CPS_PROJ).twx $(TOPHDL)_$(CPS_PROJ).ncd -o $(TOPHDL)_$(CPS_PROJ).twr $(TOPHDL)_$(CPS_PROJ).pcf 

$(TOPHDL)_$(CPS_PROJ).bit : $(TOPHDL)_$(CPS_PROJ).ncd
 bitgen -intstyle silent -f $(TOPHDL).ut $(TOPHDL)_$(CPS_PROJ).ncd 

$(TOPHDL)_$(CPS_PROJ)_download.bit : $(TOPHDL)_$(CPS_PROJ).bit
 bitinit -bm edkBmmFile_bd.bmm -p $(DEVICE_NAME) $(EDK_DIR)/system.mhs -pe microblaze_0 $(EDK_DIR)/hrboot/hrboot.elf -bt $(TOPHDL)_$(CPS_PROJ).bit -o $(TOPHDL)_$(CPS_PROJ)_download.bit -log bitinit.log

cps_bit: $(TOPHDL)_$(CPS_PROJ)_download.bit

cps_update_bit: $(TOPHDL)_$(CPS_PROJ)_download.bit

モジュール別のmakefile
*.prj ファイルを生成したり、*.xstファイルをテンプレートファイルから改編したりします。
この例には記述していませんが、topモジュールはi/oポートのインサートを許可してサブモジュールはi/oポートのインサートを禁止したりする必要があります

TOPHDL      = module1

SRC = \
  ../$(SRC_DIR)/module1/source1.vhd \
  ../$(SRC_DIR)/module1/source2.vhd \
  ../$(SRC_DIR)/module1/module1.vhd

.PHONY: all clean
all: xst/projnav.tmp $(TOPHDL).prj $(TOPHDL).xst $(TOPHDL).ngc 

clean:
 del *.ngc

xst/projnav.tmp:
 mkdir -p xst/projnav.tmp

$(TOPHDL).prj :
 echo #$(TOPHDL) > $(TOPHDL).prj
 @for SRC_ in $(SRC); do \
  (echo vhdl work $$SRC_ >> $(TOPHDL).prj) ;\
 done

$(TOPHDL).xst :
 sed -e s/%TARGET%/$(TOPHDL)/g ../template.xst > $(TOPHDL).xst

$(TOPHDL).ngc : $(SRC)
 xst -intstyle silent -ifn "$(TOPHDL).xst" -ofn "$(TOPHDL).syr"
 cp -a $(TOPHDL).ngc ..\

0 件のコメント: