はじめに
Karutaは筆者が開発している高位合成の処理系で、FPGAの開発等に使うことを想定しています。
高位合成についてご存知ない方は論理回路の高位合成について https://qiita.com/nekoaddict/items/cddde13a1322e94f44b8
KarutaについてはFPGA向け論理回路設計のためのプログラミング言語処理系 Karuta の紹介 https://qiita.com/nekoaddict/items/be418e1eba7eb27264fc
もしくはhttps://github.com/nlsynth/karutaをご覧ください。
開発の大きな目標として演算回路の入ったプロセスの複雑なネットワークをわかりやすく記述し、高性能な回路を生成することを目指してますが、この記事ではちょっとした雑用をこなす機能を紹介します。
Ubuntuをお使いの方は $ sudo snap install karuta
でインストールできるので試してみてください。(WSL2の場合はsnapを動かすための追加設定が必要です)
SRAMの作成
FPGAでSRAMを作る時はIPマクロのジェネレーター的なツール(ASIC開発の場面ではメモリコンパイラと呼ばれることがあります)を使う方法とHDLでメモリの動作を記述して合成ツールに推定させる方法がありますが、ここでは後者の方法を前提とします。
まず、次のようなコードを書いてa.karuta
という名前で保存します。
module {
@SramIf
ram s int[16]
}
Karutaコマンドの実行は次のような感じです。
$ karuta compile a.karuta
するとカレントディレクトリにa.v
というVerilogのファイルが出力されて、色々なモジュールが含まれていますが、トップのモジュールはこんな感じです。
module a(
input clk,
input rst,
input [3:0] s_addr,
input s_wen,
output [31:0] s_rdata,
input [31:0] s_wdata);
…中略
endmodule
s_addr
, s_wen
, s_rdata
, s_wdata
経由で外部からアクセスすると普通にSRAMとして使えます。
メソッドの追加
いちいちKarutaなんて変なツールを使わなくてもSRAMを推定するモジュールを書くなんて簡単だし、必要なら自分で適当なスクリプトを書いてなんとかするよって場合もあるかと思いますが、もう少し頑張ってみます。
Karutaはオブジェクト指向言語なので、次のようなメソッドを追加してみます。メソッドの中身はメモリを0クリアするというもので、ExtEntry
というアノテーションを付けることでメソッドを外部から呼べるようにします。
module {
@SramIf
shared s int[16]
@ExtEntry
func clear() {
for var i int = 0; i < 16; ++i {
s[i] = 0
}
}
}
再びVerilogを出してみると
module a(
input clk,
input rst,
input [3:0] s_addr,
input s_wen,
output [31:0] s_rdata,
input [31:0] s_wdata,
input clear_req_valid,
output clear_req_ready,
output clear_req_busy,
output clear_res_valid,
input clear_res_ready);
…中略
endmodule
SRAMアクセスのためのI/Oの他にハンドシェイクっぽい信号が追加されているのが見えます。こんな感じで0クリアの機能を持ったSRAMモジュールが簡単に作れました(内部的にはdual portのSRAMを生成して片方のportに0クリア用のステートマシンが付きます)。
req側のハンドシェイクでclear()メソッドを起動し、res側のハンドシェイクでメソッドの終了を待つという動作をします。プロトコルについては @ikwzmさんのmethod-interfaceについてのドキュメント https://gist.github.com/ikwzm/bab67c180f2f1f3291998fc7dbb5fbf0
を参考にしてください。
必要ならメソッドには引数や返り値も追加することができるので、0クリア以外の動作を実装することも簡単だと思います。
最後に
Karutaを使ってちょっとした用事をこなす回路を作る方法を説明してみました。
多くの場合、高位合成は解きたい問題のコア部分を良い感じに扱えるという期待を持って導入されますが、脇役的な雑用をとりあえず解決する手段という方向性も価値があるのではないかと考えています。
ここで作れる回路の品質は必ずしもベストなものではありませんが(将来的にある程度までは改善するつもりですが…)、こういった手抜きをすることで本質的に頑張りたい重要な部分に取り組む時間が稼げるかもしれません。
ソフトウェアの開発で例えるなら、アプリの多くの部分をスクリプト言語等で書き、パフォーマンス上重要な部分をCやアセンブラで書くという選択でトータルの開発コストと性能を最適化するみたいなイメージを想定しています。
(ディープラーニングの計算を記述したらありとあらゆる最適化が適用されて……みたいな野心も無いわけではないのですが、まあ、今回のAIブームが終わった後とかになる?……)