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バスに対してスレーブである場合に利用します。

DIP

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つの通信サイクルを終えます。

BCT

BCTADDR

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を指定。