序文
アービター Arbiter はデジタル設計において非常に一般的なモジュールであり、幅広い用途があります。定義は、2 つ以上のモジュールが同じリソースを占有する必要がある場合、どのモジュールがリソースを占有するかを決定するアービターが必要であるということです。一般に、リソースの占有を提案するモジュールはリクエストを生成する必要があり、すべてのリクエストがアービトレータに送信された後、アービトレータは許可を返さなければなりません。
ラウンドロビン仲裁者のルール
ポーリング調停のルールは、0、1、2、、、N-1 個のデータ モジュールが同時にアービトレータにリクエストを送信する場合、最初は data_req_0 が最も優先され、アービターが data_req_0 に応答すると data_req_1 が最も優先されます。アービターが data_req_i に応答すると、data_req_(i+1) が最優先になるという法則があります (次のように仮定します)。 i は最上位ビットではありません)。
ラウンドロビンアービターの実装
ポーリングアービタの実装は、アービタの入力ポートのデータモジュールのリクエストの検出、現在のアービタの優先順位に従って対応するリクエストに応答することに分けられ、アービタグラントはデータ端末のリクエストを出力し、アービタの優先順位を更新します。
モジュールのリクエストが 8 ビットリクエストであると仮定し、各 1 ビットは最初のモジュールが開始したリクエストを表します。リクエスト内の複数のビットが同時に 1 の場合、複数のモジュールが同時にバスを申請したことを意味します。このとき、ポーリング調停ルールに従って最も優先度の高いモジュールにグラント信号を与える必要があるため、グラント信号を 8 ビット信号に設定します。
例: request = 8'b1101_0011 の場合、合計 5 つのモジュールが同時にバスを申請しますが、このとき最も優先度が高いモジュールは 0 番目のモジュールであるため、出力グラント = 8'b0000_0001 となります。そして、0 番目の信号の優先度を最も低く、最初の信号の優先度を最も高く調整します。このときの優先順位は 1>2>3>4>5>6>7>0 になります。この時点で別のリクエスト = request = 8'b1101_0101 がある場合、ビット 0 の優先順位が最も低いため、検索を続けてビット 2 の位置を見つけ、グラント = 8'b0000_0100 を出力し、2 番目の信号の優先順位が最も低く、3 番目の信号の優先順位が最も高く調整されます。つまり、出力後の優先順位は 3 になります。 >4>5>6>7>0>1>2 など、これはラウンドロビン調停です。
1.1verilogコード
module rr_arbiter(
input clk ,
input rstn ,
input [7:0] req ,
output reg [7:0] grant
);
reg [7:0] shift_req;
wire [7:0] prio_grant;
wire [2:0] shift_length;
// 根据上一周期的grant,修改request,使得最低bit位优先级最高。
always @(*)begin
case(grant) //this grant is pre-cycle request's result
8'b0000_0001:shift_req = {req[0:0],req[7:1]};
8'b0000_0010:shift_req = {req[1:0],req[7:2]};
8'b0000_0100:shift_req = {req[2:0],req[7:3]};
8'b0000_1000:shift_req = {req[3:0],req[7:4]};
8'b0001_0000:shift_req = {req[4:0],req[7:5]};
8'b0010_0000:shift_req = {req[5:0],req[7:6]};
8'b0100_0000:shift_req = {req[6:0],req[7:7]};
default:shift_req = req;
endcase
end
// 找到修改后最低位的one-hot码(参考fixed_arbiter设计)
assign prio_grant = shift_req & (~(shift_req-1));
// 如果grant信号是1,那么移动长度计算需要+1,如果grant信号是0则不+1.
// 这是因为$clog2函数,有$clog2(0)=$clog2(1)=0的缘故,所以我们需要区分grant是不是0.
assign shift_length = grant?($clog2(prio_grant) + $clog2(grant)+1):($clog2(prio_grant) + $clog2(grant));
always @(posedge clk)begin
if(!rstn)begin
grant <= 8'd0;
end
else if(req==0) // 如果输入为0,那么grant信号直接给0
grant <= 8'd0;
else
case(shift_length)
3'd0:grant <= 8'b0000_0001;
3'd1:grant <= 8'b0000_0010;
3'd2:grant <= 8'b0000_0100;
3'd3:grant <= 8'b0000_1000;
3'd4:grant <= 8'b0001_0000;
3'd5:grant <= 8'b0010_0000;
3'd6:grant <= 8'b0100_0000;
3'd7:grant <= 8'b1000_0000;
endcase
end
endmodule
1.2テストベンチ
module rr_arbiter_tb();
reg clk,rstn;
reg [7:0] req;
wire [7:0] grant;
initial begin
forever #5 clk = ~clk;
end
initial begin
clk = 0;
rstn = 0;
req = 8'd0;
#10
rstn = 1;
#5
req = #1 8'b1011_1110;
#10
req = #1 8'b0101_0010;
#10
req = #1 8'b1010_1000;
#10
req = #1 8'b1100_1000;
#10
req = #1 8'd0;
#50
$finish();
end
rr_arbiter u_rr_arbiter(
.clk (clk) ,
.rstn (rstn) ,
.req (req) ,
.grant (grant)
);
initial begin
$fsdbDumpfile("rr_arbiter.fsdb");
$fsdbDumpvars(0);
end
endmodule
1.3 波形図
シミュレーションでは、最初に 8'b0000_0000 のリクエストをモジュールに入力し、モジュールは 8'b0000_0000 の許可を返しました。
次に 8'b1011_1110 を送信すると、モジュールは Grant=8'b0000_0010 を返します。このときの優先順位は 2>3>4>5>6>7>0>1 です。
次のサイクルで request = 8'b0101_0010 を送信します。 request[1] は前サイクルで優先度が下がっているため、request[4] と一致し、grant = 8'b0001_0000 を出力します。このときの優先度は 5>6>7>0>1>2>3>4 となります。
次のサイクルで request = 8'b1010_1000 を入力します。前のラウンドの優先順位によれば、request[3] の優先順位が request[5] の優先順位よりも低いため、この時点ではグラントはリクエストの最下位ビットと一致しないことに注意してください。そのため、グラントは 8'b0010_0000 を出力します。