水曜日, 3月 27, 2013JavaでJTAGコンフィギュレーションどうせやるなら徹底的にということで、今度はJTAGによるFPGAのコンフィギュレーション(回路の書き換え)に挑戦してみたいと思います。JTAGコンフィギュレーションはQuartus IIが出力するSVF形式のファイルを利用します。SVFファイルは一種のスクリプト言語になっていて、これに記述される一連のJTAG操作を実行することにより、回路の再構成が可能となります。 まずは、DE0-Nanoを接続した状態で、Jarファイル(jtag_demo.jar)をダウンロードして実行してみてください。今度は一応64ビット環境も対応しているはずですが、こちらでは未確認です。 上の画像は「Reset FPGA」「IDCODE」「Config FPGA」「Start Demo」の4つのコマンドを順次実行した結果の例です。「Reset FPGA」はFPGAのリコンフィギュレーションを強制的に実行するコマンドで、DE0-Nanoの場合はボード上のEPCS64の回路を読み込みます。「IDCODE」はデバイス(EP4CE22)の32ビットIDCODEを読み出すコマンドです。 「Config FPGA」は、SVFファイルを実行してFPGAのコンフィギュレーションを行います。SVFファイルはJarファイル内にリソースとして格納されていて、元々は1Mバイト超の巨大なファイルだったものが、30Kバイト程度に圧縮されています。実際、Jarファイルの容量の大部分は、同梱されているJNAのJarファイルです。SVF実行は必要最低限の機能しか実装していないので、例えばTDOをチェックするといった機能は省略されています。くれぐれも、DE0-Nano以外のデバイスでは実行しないでください。 最後の「Start Demo」は前回と同様のJTAG通信デモンストレーション(ただし、ボタン押下によるスピード変化や停止はなし)で、入出力データを観察することができます。実は、コンフィギュレーション前でも特にエラーもなく実行できてしまいますが、その場合は出力データがLEDに反映されることはありません。 今度はさすがにSVFの実行やGUIといったそれなりに複雑な処理がありますので、全て一本のJavaプログラムにまとめても読みにくいと思います。そこで、比較的汎用的な部分としてJTAGライブラリと基本的なGUI(JTAG.java)およびSVFの実行(SVFPlayer.java)、そしてデモアプリケーション(JTAG_Demo.java)といった構成に分割しました。 ライブラリを分離したおかげで、デモアプリケーション部分は非常にすっきりしています。JTAG.GUIクラスのインスタンスを生成すると、画面上にボタンが追加されます。実行内容はonClickメソッド内に記述しますが、SVF実行用にJTAG状態遷移メソッドstateと、SHIFT_DR/SHIFT_IR用にshiftメソッドを追加したので、生データを直接writeメソッドで書き込む必要はほとんどなくなりました。SVFPlayerクラスはJTAG.GUIの派生クラスで、生成パラメータにボタン名とSVFのリソース名を指定します。
import info.relm.JTAG; import info.relm.SVFPlayer; public class JTAG_Demo extends JTAG { public static void main(String[] args) { GUI.title("JTAG Demo for DE0-Nano"); new GUI("Reset FPGA") { public void onClick() { reset(); state("RESET", "IRSHIFT"); shift(10, 0x1); state("IREXIT1", "IRUPDATE"); text.append("Reconfiguration done.\n"); } }; new GUI("IDCODE") { public void onClick() { reset(); state("RESET", "IRSHIFT"); shift(10, 0x6); state("IREXIT1", "DRSHIFT"); readBytes(4, 0); text.append("IDCODE: " + Long.toBinaryString(0xffffffff00000000L | read(4)[0]).substring(32) + '\n'); } }; new SVFPlayer("Config FPGA", "jtag_led.svf"); new GUI("Start Demo", "Stop Demo") { public void onClick() { reset(); state("RESET", "IRSHIFT"); shift(10, 0xe); state("IREXIT1", "DRSHIFT"); shift(9, 0x100); state("DREXIT1", "DRSHIFT"); flush(); try { for (int lfsr = 1; ; Thread.sleep(10)) { readBytes(1, lfsr); shift(1, 1); state("DREXIT1", "DRSHIFT"); text.append("out: " + Integer.toBinaryString(lfsr | 256).substring(1) + "\tin: " + Integer.toBinaryString(read(1)[0] | 256).substring(1) + '\n'); if (((lfsr <<= 1) & 256) != 0) lfsr ^= 0x171; } } catch (InterruptedException e) {} shift(9, 0x100); state("DREXIT1", "DRUPDATE"); } }; } } これを使えば、わざわざQuartus IIを立ち上げなくてもFPGAのコンフィギュレーションが可能になります。もし問題が無いようでしたら、今後はこの形態でコンフィギュレーションデータを公開していきたいと思います。 |