Arty A7でAXIバス簡略仕様でDDR3 SDRAMへ読み書きしてみる

# 始めに

Arty A7(T35)を入手して3年余り。少しずつ部品を書き溜めていますが、そろそろ付属しているDRAMへのアクセスを始めようと考えました。最終的には少しずつ機能拡張をしているRISC-V([my-riscv-rv32i](https://github.com/yoshiki9636/my-riscv-rv32i))のデータRAMとしてDRAMを使うところにあります。現在データRAMとして使用しているBRAM領域はそのままキャッシュにしてDRAMのデータを読み書きできることが最終目標になります。さらにインストラクションRAMもキャッシュ化することを考えると、データ転送はバス化することが得策と考えました。いくつかのバスを検討し、[AXIバス](https://developer.arm.com/documentation/ihi0022/latest/)を参考にして、プロトコルをパクり、必要な機能のみをサブセットとして実装してみることにしました。このサブセットtiny_axiは、バースト長を固定した単純なリードとライトができだけに機能を絞り、これをArty A7に搭載されているSDRAM I/FであるMIGと接続してアクセスを確認するまでを行いました。実はMIGではAXIバスインターフェースが実装されており、それを使えばよいのですが、バススピードが固定され、例えばDDR3を333MHzで動作させる場合でその1/4の周波数である83.33MHｚとなってしまいます。実は前記RISC-Vコアは80MHzくらいの動作で、さらにシストリックアレイ([my-systolic](https://github.com/yoshiki9636/my-systolic))を接続すると50MHz動作となるため、バスとして使えない、または各マネージャ側で非同期渡りが発生することになるため、使用をあきらめました。なので、MIGにアクセスするI/F部分でクロックを非同期渡りとして、バスは50MHzで動作させることとしました。
　MIGの使用方法及び非同期FIFOを使用したクロック渡りについては、すでに[ACRi blog](https://www.acri.c.titech.ac.jp/wordpress/archives/6048)で紹介されていますが、これを改変するよりも、自分で作ってみるを目標に、このページのMIG設定方法を参考に動作環境を整えました。このページではランダム値のライト＆リードで動作を確認するとなっているのですが、自分の好きな値をリードライトしたいので、my-riscv-rv32iで使用している自作のUARTモニタを改造して、DRAMへの値の書き込みとダンプをできるようにして、その間をtiny_axiで接続するという形式にしました。一応動作をしたので、これでひとまずは公開することにしました。
 なお、AXI部分はAXIバスの仕様書を基に、不要な機能をごっそり取り去って作成しました。以下の仕様の章に未サポートのリストを示しますが、基本的なリードライトのみサポートと表現したほうが早そうな気がします。また、接続試験は自身のmanagerとsubordinate（まだこれらの呼び方がピンとこない）間でのみのため、ほかのモデルのAXIバスのものとの接続保障はありません。

# レポジトリ

・[tiny_axi](https://github.com/yoshiki9636/tiny_axi)　AXIバスモデルおよびMIGへのI/F回路モデル

# 仕様
・32bit幅4バースト固定　128bitデータごとのアクセス（アドレスの下4bitは0固定)
・現在のバス部分動作周波数は130MHz程度
・Byte strobeをサポート
・基本のRead/Writeのみで、以下の特殊機能関連の信号はカット
・burst attribute はfixed固定
・user req未サポート
・Domain未サポート
・snoop未サポート
・stash未サポート
・trace未サポート
・loop back未サポート
・MMU 未サポート
・PBHA　未サポート
・Subsystem ID DRAMのみなので、0固定
・ATOP　アトミックは未サポートでnon-atomic(0)固定
・MPAM 未サポート
・Uniq ID未サポート
・CMO　未サポート
・Memory encription 未サポート

# 使用方法

・まずは[tiny_axi](https://github.com/yoshiki9636/tiny_axi)をgit cloneしてください。
・tiny_axiに入ってください。
・./ssimディレクトリを作成し、以下のファイルをコピーしてください。
　　① ./buslogics/*.v
　　② ./mig/*.v
　　③ ./mon/*.v
　　④ ./io/lchika.v
　　⑤ ./fpga/fpga_dram_top.v
・vivadoを立ち上げて、新規RTLプロジェクトを作り、上記ファイルをすべて登録してください。
・合成制約ファイルとして、./syn/riscv_io_pins.xdcを登録してください。
・プロジェクトが立ち上がったら、まずはクロック生成をします。
　　① IP Catalog　⇒　FPGA Futures and Design ⇒　Clocking ⇒　Clocking Wizardを立ち上げます。
　　② input clockとして100MHzを設定
　　③ output clockとして3ポート設定　：　clk_out1 200MHz、　clock_out2 166.66667MHz、 clock_out3 50MHz
　　④ OKを押して完了させる
・次にMIGを生成します。手順は[ACRi blog MIG を使って DRAM メモリを動かそう (3)](https://www.acri.c.titech.ac.jp/wordpress/archives/7284)の手順で行います。詳細は割愛しますのでそちらを参照してください。前記ブログの内容から以下のパラメータを変更します。
　　①　System Reset Polarity : ACTIVE LOW
　　②　ピンの確認を行うファイルは./syn/Arty_C_mig.ucfを使用してください。このピンチェックで落ちる場合は、どこか設定が間違っています。
　　③　最終的に許諾をすればMIGが生成されます。
・クロックとMIGを生成したら、Run Synthesis、　Run Implementation、　Generate Bitstreamの順に実行します。
・出来上がったBitstreamをArty A7に書き込みます。これでAarty A7上で本実験の論理が動作します。クロックが正常動作していれば、Lチカが動作しているはずです。（単にmclkが動作していることを確認しているだけです。）

・tera termを立ち上げます。シリアルから、Arty A7が接続されているCOM(筆者の環境ではCOM4)を選択します。
・設定⇒端末　で改行コードを　受信：AUTO　送信：CR　に設定します。
・設定⇒シリアルポート　でスピード：9600　データ：8bit　パリティ：none　ストップビット：1bit フロー制御：noneを選択します。
・これでqをタイプすると、エコーバックが戻ってくるはずです。
・書き込みはwコマンドになります。 w\<address4bite\> \<data4byte\> \<data4byte\> ... q
・wの後に16進数で8桁、4byte分アドレスを入れます。自動改行しますので、続けてデータを同じように4byteずつ入力します。終了はqで入力モードが終了します。qで終了時に最後が4byte分入力されていないと捨てられます。
・読み出しはrコマンドになります。 r\<start address 4byte\> \<end address 4byte\>
・rに続いて4byteずつ16進数でアドレスを入力します。途中ミスったら、qを入力すると、rコマンドモードから抜けます。
・もしアドレスで長いダンプをしてしまった場合もqコマンドで途中で抜けることができます。

以上の手順でDRAMへの読み書きが確認できると思います。

# 終わりに

今回は、risc-vにDRAMを実装する前段階としてDRAMおよびバスの動作確認をする実験をしました。4byteずつの書き込みですが、無事機能していることが確認できました。ACRi blogの記事は親切で図を多用してわかりやすかったのですが、必要としていたものと少し違く、改変が必要だったので、結局MIGのインターフェースから作成してみました。MIGの情報はACRi blog以外はなかなか存在しなく情報が少ないので、皆様の挑戦のための情報の足しになれば幸いです。
まずは使用方法をざっと殴り書きましたが、tiny_axiバスの詳細設計も書いていこうと思います。