JTAG to Avalon Master Bridgeを使ったバスコントロール
バスアーキテクチャの学習というハードル
2013年も1月が終わろうとしていますが、今年初記事です。(笑
74シリーズで論理設計した経験があり、HDLをある程度習得しているなら単体モジュールをFPGA内に作り込むのはさほど困難な事ではないと思われます。
問題となるのは、このような単体モジュール群が複数あり、それぞれがデータストリームやレジスタを共有する必要が出た場合。(必ずと言っていいほどこの状況になりますが。。)
個々のモジュールを協調または排他動作させるアービタが必要になります。
FPGAベンダもこれらの問題を解決するツールを用意していますが、ソフトマクロCPUという形を取り、バスマスタを隠蔽しています。
このような形を取ると、各モジュールをすべてソフトウェアで制御(場合によってはRTOSも載せる)する必要があります。ソフトウェア開発者には受け入れやすくなる一方、構成によってはバスアービタがノイマンボトルネックの影響をもろに被る可能性があります。加えて、大抵の場合ソフトマクロCPUは同規模のゲート数をもつハードCPUより消費電力が高く、最高速度はそれに劣ります。
ではなぜこのような構成を取るのでしょうか。
主な理由は、バスマスタのみをツール側で用意したとしても、開発者はまずそのバスアーキテクチャの全容を理解し、デバッグ手法、カバレッジの妥当性を1から学習調査しなければならなくなり、ハードルが高くなるからです。
この問題に解決手法があるのか無いのかずっと考えていたのですが…
AlteraのQsysが提供するAvalonバスの場合、バスマスタがNios IIである必要は全くありません。
現状ではSystem Consoleが使えるJTAG to Avalon Master Bridge, SPI slave to Avalon Master Coreなどがあります。よって、SPIからバスを制御できるのです。例えばArduinoやmbedのSPIをバスマスタとして繋げてもOKです。これによりソフトマクロCPUのインプリメントの回避や、バスアーキテクチャの学習といったハードルがぐっと下がる事になります。
コンソールもQsys側で用意されているので、独自仕様シェルを作らなくても大丈夫です。
AvalonバスはQsys(またはSOPC Builder)で提供している内部バスインタフェースで、
- 単一方向ストリームデータを扱うのに適している Avalon-ST
- メモリマッピングされた空間上でリードライトするのに適した Avalon-MM
があります。詳細はここでは省略致します。
使ってみる
今回はAvalon-MMバスインタフェース上に、Qsysで提供されている
をマッピングしました。
SDRAMのアドレス: 0x0000_0000 ~ 0x01ff_ffff に配置
PIOのアドレス: 0x0200_0000 ~ 0x0200_000f に配置
ALTPLLのアドレス: 0x0400_0000 ~ 0x0400_000f に配置
ハードウェアはDE0 nanoです。これにあわせてモジュールの設定を行います。
・SDRAMコントローラの設定
AlteraのユーザーズガイドでもSDRAMにPLLでクロックを与える際、Avalon-MMシステムクロックとSDRAMとのクロック位相に関してはボードごとに試行錯誤が必要である旨が書かれています
(ユーザーズガイド p.32)
今回はDE0 nanoサンプルプロジェクトに従い、SDRAMに供給するクロックの位相を-60°としています。
PresetsをCustom
データ幅:16bit
Row:13bit
Column:9bit
のみ変更
・PIOの設定
DirectionでOutputにチェック
・ALTPLL
Speed GradeはFPGAに依存し6、入力クロック50MHz、c0は2倍、c1(SDRAM用クロック)も2倍で、かつ位相は-60°
詳細は、下に示すスクリーンキャプチャをご覧下さい。
このキットで用意されているDE0_NANO_GOLDEN_TOPをひな形としてQsysの生成したモジュール群をインスタンシエートしました。
DE0_nano.vのStructural codingと書かれている部分にQsysが示したインスタンシエート例HDL Exampleをもとに以下を追記します。
//======================================================= // Structural coding //======================================================= qsys_test u0 ( .clk_clk (CLOCK_50), // clk.clk .sdram_0_wire_addr (DRAM_ADDR), // sdram_0_wire.addr .sdram_0_wire_ba (DRAM_BA), // .ba .sdram_0_wire_cas_n (DRAM_CAS_N), // .cas_n .sdram_0_wire_cke (DRAM_CKE), // .cke .sdram_0_wire_cs_n (DRAM_CS_N), // .cs_n .sdram_0_wire_dq (DRAM_DQ), // .dq .sdram_0_wire_dqm (DRAM_DQM), // .dqm .sdram_0_wire_ras_n (DRAM_RAS_N), // .ras_n .sdram_0_wire_we_n (DRAM_WE_N) , // .we_n .pio_0_external_connection_export (LED) , // pio_0_external_connection.export .altpll_0_areset_conduit_export (1'b0), // altpll_0_areset_conduit.export .altpll_0_locked_conduit_export (), // altpll_0_locked_conduit.export .altpll_0_phasedone_conduit_export (), // altpll_0_phasedone_conduit.export .altpll_0_c1_clk (DRAM_CLK) // altpll_0_c1.clk );
コンパイルを行い、生成されたsofファイルをFPGAにダウンロードします。
Programmerを終了させ、Qsysに戻りSystem Consoleを立ち上げます。
マスターにhogeというインスタンス名を与え、サービスを起動します
% set hoge [lindex [get_service_paths master] 0] % open_service master $hoge
ためしにPIO(LED)にデータをライトします。アドレスは0x02000000ですので、
% master_write_32 $hoge 0x02000000 0xAA
LEDは下のように点灯します
% master_write_32 $hoge 0x02000000 0x55
今度は下のようになります。
SDRAMのR/Wを確認します。アドレス0x00000000に0xFFAAをライトし、その後リードします
% master_write_32 $hoge 0x00000000 0xFFAA % master_read_32 $hoge 0x00000000 1
無事、読み込めました。
■参考
システム・コンソールを使用した H/W デバッグ環境構築例
Qsysを使ってみた - Sim's blog
[FPGA][DE0]QsysのJtagデバッガでLチカしてみた - GeekleBoard