|
16 |
BSVとAXIのバックプレッシャ (2) |
接続法 1、EN/RDY を mkConnection でつなぐ
BSV流のEN/RDYによる接続を図1121.1に示します。

図1121.1 EN/RDY の接続
送り手 mkProducer は FIFO からの取り出しを Get で、受け手 mkConsumer は FIFO への書き込みを Put で公開し、最上位 mkTop が mkConnection でつなぎます。
package EnRdy;
import GetPut :: *;
import FIFOF :: *;
import Connectable :: *;
// 送り手 : FIFO から取り出す Get
(* synthesize *)
module mkProducer (Get #(Bit #(8)));
FIFOF #(Bit #(8)) q <- mkFIFOF;
Reg #(Bit #(8)) cnt <- mkReg (0);
rule fill;
q.enq (cnt);
cnt <= cnt + 1;
endrule
method ActionValue #(Bit #(8)) get;
q.deq;
return q.first;
endmethod
endmodule
// 受け手 : FIFO に入れる Put
(* synthesize *)
module mkConsumer (Put #(Bit #(8)));
FIFOF #(Bit #(8)) q <- mkFIFOF;
rule drain;
q.deq;
endrule
method Action put (Bit #(8) x);
q.enq (x);
endmethod
endmodule
// 最上位 : mkConnection でつなぐ
(* synthesize *)
module mkTop (Empty);
Get #(Bit #(8)) p <- mkProducer;
Put #(Bit #(8)) c <- mkConsumer;
mkConnection (p, c);
endmodule
endpackage
bsc が生成した mkTop.v のモジュール本体です。
module mkTop(CLK,
RST_N);
input CLK;
input RST_N;
// ports of submodule c
wire [7 : 0] c$put;
wire c$EN_put, c$RDY_put;
// ports of submodule p
wire [7 : 0] p$get;
wire p$EN_get, p$RDY_get;
// submodule c
mkConsumer c(.CLK(CLK),
.RST_N(RST_N),
.put(c$put),
.EN_put(c$EN_put),
.RDY_put(c$RDY_put));
// submodule p
mkProducer p(.CLK(CLK),
.RST_N(RST_N),
.EN_get(p$EN_get),
.get(p$get),
.RDY_get(p$RDY_get));
// submodule c
assign c$put = p$get ;
assign c$EN_put = p$RDY_get && c$RDY_put ;
// submodule p
assign p$EN_get = p$RDY_get && c$RDY_put ;
endmodule // mkTop
mkConnection は Connectable 型クラスのメソッドで、インタフェースの組ごとにインスタンスが定義されています。Get と Put の組のインスタンスは、本質的に次のルール一つです。
instance Connectable #(Get #(a), Put #(a));
module mkConnection #(Get #(a) g, Put #(a) p) (Empty);
rule connect;
let x <- g.get;
p.put (x);
endrule
endmodule
endinstance
ルールの発火条件は、呼んでいるメソッド全部の RDY の AND です。get と put は RDY を持つ普通のメソッドなので、この接続ルールは mkTop の中の AND ゲート一つになりました。両端の RDY を集めて AND を取り、その結果を EN として両端に返しています。両端の中では、RDY は FIFO の状態そのもので、EN はそのまま FIFO の制御になります。mkProducer.v と mkConsumer.v の該当行です。
// mkProducer.v
assign get = q$D_OUT ;
assign RDY_get = q$EMPTY_N ;
assign q$DEQ = EN_get ;
// mkConsumer.v
assign RDY_put = q$FULL_N ;
assign q$D_IN = put ;
assign q$ENQ = EN_put ;
両端の判断は外の EN に委ねられ、EN で「今回は転送」と言われて動きます。