ちょっとパラメタライズのやり方を検討したかったので、ものすごく簡単なデータ用のインターコネクト的なやつをChiselで書いてみたのでそれについてをまとめておく。 今回の記事は全体の仕様について。
NICの仕様
自分で作ったRISC-VにメモリとUARTを繋いで動かしたいなーと考えた時に、なんかしらの形でメモリアクセス要求を捌かなあかん!!ということに気づいたのでNICを作ってみようと考えた。
手始めにChiselの文法とか後はutilのモジュールとかを使ってどんな感じにすればいいかを試そうと思う。
今回のネタで作ったモジュールは「パラメタライズでどれくらいのことが出来そうか」という部分に重きをおいてます。モジュールのソースコード自体は全部載せる気でいますが、基本的な試験しかしてないのでどっかしらバグってるかも。
「こんな感じに作れるのかー」くらいな気持ちでご一読ください。(後ほど後自分のgithubリポジトリには動作確認のテスト込みで公開します)
バスの仕様
実際に作ろうとしているのは「接続したMasterからのアドレスに応じて、適切なスレーブにデータアクセスを流す」という処理なのだが、ひとまずどんなことが出来そうかを把握したかったので、以下のような仕様のバスを定義してみた。
信号名 | ビット幅 | 方向 | 説明 |
---|---|---|---|
valid | 1 | Output | アクセス要求を示す信号。Highで要求あり |
ready | 1 | Input | スレーブ側の状態を示す信号。Highで要求を処理可能 |
dst | 可変 | Output | 宛先を示す信号(いわゆるアドレス、名前アドレスにしとけばよかった) |
data | 32 | Output | 転送データ |
上記の表を書いてから思ったけど、要はread-validのハンドシェイクを使ったライトだけ出来るバスって感じ。
波形書くのが面倒だったので、実際に動かした際の波形を。下記の波形は4入力-3出力で動かしたもの。twitterに載っけたやつなので見た人いるかも。
NIC_INPUTと書いたブロックが入力側の処理要求で、各々入力ポートが4回処理要求を出しています。その4回の処理要求は出力側の0-3にそれぞれ一回ずつ流れていく感じでそれがNIC_OUTPUTと書いたブロック以下の信号です。
パラメタライズについて
とりあえず以下の部分はいじれるようにしておこうと思う。
- Masterポートの数
- Slaveポートの数
- タイミングケアのためのレジスタスライスの挿入の可否
ブロック図
パラメタライズ可能にするので、きちんとは決まらないが何となく図にすると以下のような感じになる。
Decoder
もう単純にデコーダーで、やることは以下のひとつのみ。
- ready-validのハンドシェイクが成立した時のdstの示すSlvaeポートにアクセスを転送する
一応、入力部分にレジスタスライスを入れて、パラメータでON/OFFが出来る仕組みを入れてみる。
Arbiter
こちらもやることはシンプル。
- Masterからの送信要求に従って、選択した一つのアクセス要求を出力ポートに転送
- 要求が競合した場合はインデックスの小さいポートが優先
Top
NICの最上位階層モジュール。書いてないけど、上記図の外側の四角がこれに相当するもの。この階層でパラメータのMasterポート数分のDecoder/Slaveポート数分のArbiterをインスタンスして、DecoderとAribter間を適切に接続する。
仕様の説明だけでかなり薄味だけど、ひとまずここで区切ります。