|
17 |
BSVとAXIのバックプレッシャ (3) |
接続法 2、valid/ready をつなぐ
AXI流のvalid/readyによる接続を図1122.1に示します。

図1122.1 valid/ready の接続
AXI4-Lite の書き込みアドレスチャネルを例にします。スレーブ側のインタフェースは、メソッドに always_ready と always_enabled を付けて EN と RDY を消し、Bool の引数と返り値をそのまま valid と ready の線にします。
interface AxiLiteAW #(numeric type wd_addr);
(* always_ready, always_enabled, prefix="" *)
method Action awvalid (Bool awvalid, Bit #(wd_addr) awaddr, Bit #(3) awprot);
(* always_ready *)
method Bool awready;
endinterface
マスタとスレーブをつなぐ mkConnection も、接続法 1 と同じく Connectable のインスタンスが定義するルールです。valid とアドレスをスレーブに渡し、ready をマスタに返しています。
(* fire_when_enabled, no_implicit_conditions *)
rule rl_aw;
s.aw.awvalid (m.m_awvalid, m.m_awaddr, m.m_awprot);
m.m_awready (s.aw.awready);
endrule
接続法 1 との違いは、呼んでいるメソッドの側にあります。always_ready は RDY が定数 1 であること、always_enabled は EN が定数 1 で毎サイクル必ず呼ばれることを意味します。発火条件は定数 1 の AND なので定数 1 になり、ルールは毎サイクル無条件に発火します。fire_when_enabled と no_implicit_conditions の属性は、発火条件が本当に定数であることをコンパイラに検査させるためのもので、RDY を持つメソッドが混じっていればコンパイルエラーになります。生成された mkTb.v で、この接続は assign だけになります。mkConnection に AXI 用の特別な動作があるのではなく、接続法 1 と同じ機構で AND を計算した結果、その AND が定数になって消えたものです。
assign dut$awaddr = master_f_wr_addr$D_OUT[10:3] ;
assign dut$awprot = master_f_wr_addr$D_OUT[2:0] ;
assign dut$awvalid = master_f_wr_addr$EMPTY_N ;
AND は両端の中に現れます。マスタ側の FIFO の DEQ と、スレーブ側の FIFO の ENQ です。
// mkTb.v : マスタ側の xactor
assign master_f_wr_addr$DEQ = master_f_wr_addr$EMPTY_N && dut$awready ;
// mkAxiRegs.v : スレーブ側の xactor
assign awready = xactor_f_wr_addr$FULL_N ;
assign xactor_f_wr_addr$D_IN = { awaddr, awprot } ;
assign xactor_f_wr_addr$ENQ = awvalid && xactor_f_wr_addr$FULL_N ;
接続法 1 で mkTop にあった AND が、接続法 2 では両端の内側に一つずつ複製されています。それ以外は同じで、valid は送り手の FIFO の EMPTY_N、ready は受け手の FIFO の FULL_N です。
この変換を行っているのが bsc-contrib のトランザクタです。外側のメソッドを always_ready と always_enabled にして EN/RDY を消し、内側で FIFO の ENQ を valid && FULL_N と書いて AND を自分の中に置きます。BSV の内部は EN/RDY のまま、境界だけを valid/ready にする、というアダプタです。