round robin arbiter polling arbitrator design

foreword

The arbiter Arbiter is a very common module in digital design and has a wide range of applications. The definition is that when two or more modules need to occupy the same resource , we need the arbiter to decide which module will occupy the resource. Generally speaking, the module that proposes to occupy resources needs to generate a request, and after all the requests are sent to the arbitrator, the arbitrator must return a grant.

Round Robin Arbitrator Rules

The rule of polling arbitration is that when 0, 1, 2,,, N-1 data modules send requests to the arbitrator at the same time, initially data_req_0 has the highest priority, and when the arbiter responds to data_req_0, data_req_1 has the highest priority. There is a law: when the arbiter responds to data_req_i, make data_req_(i+1) the highest priority (assuming that i is not the highest bit ) .

Round Robin Arbitrator Implementation

The implementation of the polling arbiter is divided into detecting the request of the data module of the input port of the arbiter, responding to the corresponding request according to the priority of the current arbiter, and the arbiter grant outputs the request of the data terminal, and updates the priority of the arbiter.

Assume that the module’s request is an 8-bit request, and each 1 bit represents the request initiated by the first module. When multiple bits in the request are 1 at the same time, it means that multiple modules apply for the bus at the same time. At this time, we need to give a grant signal to the module with the highest priority according to the polling arbitration rule, so we set the grant signal to an 8-bit signal.

For example: when request = 8'b1101_0011, a total of five modules apply for the bus at the same time. At this time, the module with the highest priority is the 0th module, so the output grant = 8'b0000_0001. And adjust the priority of the 0th signal to the lowest, and the priority of the first signal to the highest. At this time, the priority order is 1>2>3>4>5>6>7>0. If there is another request = request = 8'b1101_0101 at this time, since bit 0 has the lowest priority, continue to search and find bit 2, so output grant = 8'b0000_0100, the second signal priority is adjusted to the lowest, and the third signal priority is adjusted to the highest, that is, the priority order after output becomes: 3>4> 5>6>7>0>1>2, and so on, this is round-robin arbitration.

1.1verilog code

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.2testbench

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 Waveform diagram

  • In the simulation, we first input a request of 8'b0000_0000 to the module, and the module returned us a grant of 8'b0000_0000.

  • Then send 8'b1011_1110, the module returns grant=8'b0000_0010, at this time the priority is: 2>3>4>5>6>7>0>1.

  • Send request = 8'b0101_0010 in the next cycle. Since the priority of request[1] has been lowered in the previous cycle, it matches request[4] and outputs grant = 8'b0001_0000. At this time, the priority is: 5>6>7>0>1>2>3>4.

  • Input request = 8'b1010_1000 in the next cycle. Note that the grant does not match the lowest bit of the request at this time, because according to the priority order of the previous round, the priority of request[3] is lower than that of request[5], so grant outputs 8'b0010_0000.

Guess you like

Origin blog.csdn.net/qq_57502075/article/details/129764974