For developer
この章ではFPGA firmware (以下FW) 開発者向けの情報を説明します。
HULはFPGAにKintex7を採用しているため、Xilinx Vivadoを用いて開発を行うことが推奨されます。搭載されているKintex7 160Tは有償のライセンスでなくとも開発が可能なサイズのFPGAのため、無償版のVivado Design Suite WebPACKを用いて開発を行うことが出来ます。
Vivadoの新しいバージョンが出たら積極的に更新するべきですが、いつ行うかは慎重に判断してください。KEKの内田さんいわくISEのころに比べVivadoは格段にバージョンアップに対する安定度が増して、基本的に新しいバージョンにクリティカルなバグが報告されていない限り移行したほうがよいとの事ですが、タイミング的に際どい調整をしている回路では合成結果が変わる可能性があるため、開発途上でバージョン更新をすることはお勧めしません。なので、Vivadoは積極的にバージョン更新させるが、動作確認できていないfirmwareがある状態では行わないほうがよい、というのが基本方針になると思います。
Vivadoは合成時に大量のメモリを消費します。最低でも8GB以上、複数RUNを同時に走らせる場合16GB以上の物理メモリが搭載されていることが望ましいです。また、複雑なfirmwareでは合成に時間がかかります。例えば、HUL MH-TDCは論理合成から配置配線完了までThinkPad X230 (Core i7-3520M (2.9 GHz)搭載) 上で物理メモリを3 GB消費して約30分かかります。単純にCPUパワーとメモリ量が合成にかかる時間を短縮するので、ラップトップPCで開発するのか?それとも専用のワークサーバー上で行うのか?は自分にとっての利便性と相談して決めてください。Xilinxの開発ツールは本来CUIで使うことが想定されており、VivadoもTCLと呼ばれるスクリプト言語で合成フローを制御できます。そのため、Makefileなど書いてしまえばLinuxサーバで並列にジョブを処理することも可能です。TULの頃と比べ巨大なfirmwareを開発可能になっているので、安いラップトップで済ませようというのはお勧めしません。
Vivado projectに関して
要素 | コメント |
---|---|
ターゲットFPGA | xc7k160tfbg676-1 |
使用言語 | VHDL IPを生成した際のテンプレートに記述される言語になります。 言語は混在可能なので追記は他言語でも可。ただし既存モジュールはラップする必要あり。 |
デフォルトライブラリ名 | mylib |
合成のストラテジー | Vivado synthesize Default |
命名規則
Gitlab上のhul-officialにFWを上げる可能性がある場合,著者の命名規則に揃えるようお願いいたします。
SiTCPやIP catalogを使って生成したIPについて
SiTCPは株式会社Bee Beans Technologiesから提供されているライブラリです。詳しい情報はここから入手してください。
SiTCPは企業から提供されているライブラリであるためgitlab上のFWには同梱されていません。Cloneした後以下のようにSiTCPというディレクトリを生成し、その中にライブラリファイルを追加してください。HULのプロジェクトはSiTCPというディレクトリを見に行くように設定されているので、VivadoでXPRファイルを開く前にこの作業をすますとエラーが出ずに済みます。SiTCPディレクトリは.gitignoreによって除外されています。何かの手違いでSiTCPライブラリがGit管理下に入ってしまったFWはhul-officialへはmerge出来ませんので注意してください。
HUL_Skelton.git
├── HUL_Skelton.cache
├── HUL_Skelton.hw
├── HUL_Skelton.ip_user_files
├── HUL_Skelton.runs
├── HUL_Skelton.sim
├── HUL_Skelton.srcs
└── SiTCP
IP catalogで生成したIPに対してはVivadoからIP containerという機能が利用できるようになりましたが、IP生成物のアーカイブであるためファイルサイズが大きいです。このままだとGitリポジトリを圧迫するので、HULのFWではcore containerは利用しないでください。
HUL firmwareの内部構造について
Top level entity ports
FPGAのtop level entityのポート (つまりFPGAの足) の説明を行います。
信号名 | 信号規格 | コメント |
---|---|---|
CLKOSC | LVCMOS33 | 基板上の発振器からの50 MHzクロック入力です。 |
PROB_B_ON | LVCMOS33 | この信号がLowになるとFPGAはSPI Flashから自分自身を再コンフィグレーションします。FPGAの動作がおかしい時などに利用し、電源のOn/Offに相当する強力なコマンドです。 通常時はhighでないといけません。電源投入時にhigh状態を維持できていないとコンフィギュレーションが終わらないので注意が必要です。 |
User I/O | ||
LED | LVCMOS33 | フロントパネル上部に取り付けられた4つのLEDにつながっています。 |
DIP | LVCMOS33 | DIPスイッチの入力信号です。この信号は負論理になっており、電気的には下図のようになっています。High状態を作るためにはIOBのプルアップが必要なので、忘れずに設定してください。 |
USER_RST_B | LVCMOS33 | SW3を押した際の1 ms程度のパルス入力です。この信号は負論理です。 |
NIMIN | LVCMOS33 | フロントパネルのNIM入力信号です。 |
NIMOUT | LVCMOS33 | フロントパネルのNIM出力信号です。 |
PHY/EEPROM | ||
サンプルプロジェクトでPHYとEEPROMにカテゴライズされている信号は他のプロジェクトでもその通りに接続してください。また、PHYを未初期化にしないためにもSiTCPは全てのプロジェクトで実装したほうがよいでしょう。 | ||
フロント差動入力 | ||
MAIN_IN_U | LVCMOS33 | フロントパネルの固定信号入力線、上側のコネクタです。 |
MAIN_IN_D | LVCMOS33 | フロントパネルの固定信号入力線、下側のコネクタです。 |
メザニンスロット | ||
MZN_SIG_Up/n | VCCO=1.8Vまでの差動・単一端信号 | メザニンコベースコネクタ上側に接続されて信号線です。この信号線の信号規格、入出力方向はメザニンカードによって決まります。これらの信号線はHPバンクに配線されているのでVCCOは1.8Vです。そのため、HPバンクで利用可能な差動信号、および1.8Vまでのシングルエンド信号がサポートされますが、特別な理由がない限りLVDS信号規格を利用してください。 入力なのか出力なのか、双方向ポートを使うのか、浮き配線の処理などはファームウェア開発者が適切に行ってください。 |
MZN_SIG_Dp/n | VCCO=1.8Vまでの差動・単一端信号 | 同上です。 |
J0バス信号 | ||
J0RS | LVCMOS33 | J0バスのS1-7番を読み出しポートです。HUL controllerがJ0バスに対してスレーブの場合使用します。この信号を使ってMTMからのトリガーやタグ情報を受け取ります。 |
J0DS | LVCMOS33 | J0バスのS1-7番を駆動するポートです。HUL controllerがJ0バスに対してマスタである場合に使用します。 |
J0RC | LVCMOS33 | J0バスのC1-2信号を読み出すポートです。J0C線はBUSY処理専用です。J0バスではLowでBUSYとなります。C1と2は全く同じ信号が流れているはずなので、モジュール内部ではC1と2をORして使ってください。この線はHUL controllerがJ0バスに対してバスマスタの場合に利用します。 |
J0DC | LVCMOS33 | J0バスのC1-2信号を駆動するポートです。J0C線はオープンコレクタORになっており、LowでBUSYを示します。C1と2には同様の信号を入力してください。この信号線はHUL controllerがJ0バスに対してスレーブである場合に利用します。 |
SiTCP
SiTCPのコアには2種類のクロックを供給する必要があります。1つはシステムクロックでこのクロックに同期してSiTCPはTCPとUDPのデータを送受信します。システムクロックには下限の周波数があり、100 Mbps時は最低25 MHz、30 MHz以上推奨、GbE時は最低125MHz、130MHz以上推奨となります。もうひとつはPHYをデータ通信する際のクロックです。100 Mbps時はPHYから送られてくるtx clkを接続してください。GbE時はFPGA内部などで生成した125 MHz (gtx clk) のクロックを接続してください。Gtx clkは良い精度で125 MHzである必要があります。HUL controllerで使用しているPHYでは100 ppmしか猶予がないので、間違えずに設定してください。
Local bus controller
Local bus controller(BCT)はRCNPの味村さんが書いたソースコードを著者が再利用しています。BCTは外部インターフェース(External Bus)の生のタイミングやデータ線を隠蔽して、FPGA内部のローカルモジュール管理(Local Bus)を独立に行うためのバスインターフェースです。External Busは通信方法によって様々なタイミングやデータ長を持つため、それらの違いをBCTが吸収することでLocal Bus以降のソースコードの再利用性が高まります。また、モジュール追加に対して少ないコードの変更で対応可能です。BCTとソフトウェアのFPGAModuleクラスは対の関係になっており、著者の開発するシステムでは共通ライブラリになります。他者のプロジェクトでもこれらを再利用することをお勧めします。
BCTのバス通信シーケンスを下図に示します。BCTがバス通信サイクルを始める起点はexternal bus(SiTCP RBCP)のWEかREがhighとなった時点です。この時点でexternal busには有効なアドレスとデータが流れているためそれらをBCTに格納します。この際に、external busから受け取った情報をlocal bus用に再配置します。External busのアドレスとlocal busのモジュールIDおよびローカルアドレスの関係は下図の通りです。ソフト側からはRBCPのアドレスが再配置されている事は分からないようになっています。BCTはGetDestでモジュールIDからこの通信がBCTで内部処理しなければいけないのか、FPGAのほかのモジュールへ接続したいのかを判断します。BCTがターゲットの場合FPGAのPROB_B_ONの駆動やリセットの発行を行ったり、FWバージョンを獲得できたりします。他のモジュールがターゲットの場合モジュールIDから接続先のインデックスが決定されます。次にSetBusでアドレスとデータがlocal busにブロードキャストされ、更に次のConnectにおいて指定したインデックスのWEかREのみがhigh状態になります。ここでBCTはFPGA内部の指定したモジュールを噛んだ状態になり、モジュールからの応答待ちになります。接続先のモジュールは自分のWEかREがhighになった段階でバスサイクルの処理を始めます。適切な処理を行った後readyをhighにしてバスサイクルの終了をBCTへ要求します。BCTはreadyを受け取ると終了処理に入り、最後にexternal busに対してacknowledgeを返して1つの通信サイクルを終えます。
Local bus addressと多バイト読み出し(書き込み)
Local busを介した読み出し場合8-bitずつしか読み出すことができない為、4バイトのレジスタであれば4回RBCP通信を行う必要があります。HULでは12ビットのローカルアドレスのうち上位8ビットをレジスタをIDするために利用し、下位4ビット何バイト目かを指すために利用します。例えば、モジュールインデックスが0x8のローカルモジュール内に、16ビット幅のレジスタAとBが存在する場合BCTとRBCPのアドレスは以下の様になります。
BCT address | RBCP address | コメント |
---|---|---|
0x000 | 0x8000'0000 | レジスタAの1バイト目 (下位8ビット) |
0x001 | 0x8001'0000 | レジスタAの2バイト目 (上位8ビット) |
0x010 | 0x8010'0000 | レジスタBの1バイト目 (下位8ビット) |
0x011 | 0x8011'0000 | レジスタBの2バイト目 (上位8ビット) |
多バイト読み出しをさせる場合のローカルモジュール側のHDLの例を以下に示します。
when kReadLength(kNonMultiByte'range) =>
if( addrLocalBus(kMultiByte'range) = k1stbyte) then
reg_length_read(7 downto 0) <= dataLocalBusIn;
elsif( addrLocalBus(kMultiByte'range) = k2ndbyte) then
reg_length_read(kWidthRead-1 downto 8) <= dataLocalBusIn(kWidthRead-1-8 downto 0);
else
end if;
hul_software
に同梱されているFPGAModule
クラスでは多バイト読み書きをサポートしており、BCTアドレスの下位4ビットは自動でインクリメントされます。
Local Busへモジュールを追加する
ローカルモジュールを追加する場合、次の点を変更してください。
defBus.vhd内部の変数
項目 | コメント |
---|---|
kNumModules | BCTを除いたローカルモジュール数を指定 |
Module ID | kMidから始まるIDを追加。 RBCP addressで指定する番地となる。連番である必要はない。 |
Leaf | Local busのインデックスを決めるためのIDを追加。 連番である必要があります。 |
BusController.vhd内部
ステートマシンでGetDest状態のelse構文以下で、追加したモジュールのwhen構文を追加。
toplevel.vhd内部
モジュールを実体化させてLocalBusを接続。配列のインデックスには新しいLeaf IDを指定。