Verilog - implementation of a simple arbiter

Verilog - implementation of a simple arbiter

Arbiter basic functions

The main function of the arbiter is to determine which source should respond based on the current priority when multiple sources send requests at the same time.

Arbiters are divided into round-robin arbiters and fixed-priority arbiters. The priority of the polling arbiter's response to each source changes with each source's request polling, and ultimately the priority of each source is relatively balanced.

  • The rules of the polling arbiter are: when 0, 1, 2, and N-1 source signal sources send requests to the arbiter at the same time, source 0 has the highest priority initially. When the arbiter responds to source 0, source1 has the highest priority, and so on.

  • The fixed priority arbiter rule is: when 0, 1, 2, and N-1 sources initiate requests at the same time, Source 0 has the highest priority. Even after source 0 is responded to, it is still the highest priority. The priority is according to The serial number gradually decreases.

The polling arbiter and the fixed priority arbiter are implemented similarly in FPGA. The only difference is that the polling arbiter updates the priority after each response to the request, while the fixed priority does not require this step.

The following is an implementation of a simple polling arbiter module. The key points of this implementation are:

  • The response priority is determined based on the value of the current priority variable prrty;
  • Change the priority prrty after the response is completed.
module arbiter(
    input           clk             ,//时钟
    input           rst_n           ,//复位
    input           request0        ,//请求0
    input           request1        ,//请求1
    input           request2        ,//请求2
    input           request3        ,//请求3
    input           end_transaction0,//请求0结束标志
    input           end_transaction1,//请求1结束标志
    input           end_transaction2,//请求2结束标志
    input           end_transaction3,//请求3结束标志
    output          grant0          ,//响应请求0
    output          grant1          ,//响应请求1
    output          grant2          ,//响应请求2
    output          grant3           //响应请求3
);

localparam          S_IDLE = 4'b0000;
localparam          S_GNT0 = 4'b0001;
localparam          S_GNT1 = 4'b0010;
localparam          S_GNT2 = 4'b0100;
localparam          S_GNT3 = 4'b1000;

reg [3:0]           state           ;
reg [3:0]           grant           ;
reg [3:0]           prrty           ;//优先级  

//grant3, grant2, grant1, grant0
assign {grant3, grant2, grant1, grant0} = grant;

//state
always @(posedge clk or negedge rst_n) begin
    if(~rst_n) begin
        state <= S_IDLE;
        prrty <= 4'b1000;
    end
    else
        case(state)
            S_IDLE: 
                case(1'b1)
                    prrty[3]: begin
                        if(request0)
                            state <= S_GNT0;
                        else if(request1)
                            state <= S_GNT1;
                        else if(request2)
                            state <= S_GNT2;
                        else if(request3)
                            state <= S_GNT3;
                    end
                    prrty[0]: begin
                        if(request1)
                            state <= S_GNT1;
                        else if(request2)
                            state <= S_GNT2;
                        else if(request3)
                            state <= S_GNT3;
                        else if(request0)
                            state <= S_GNT0;
                    end
                    prrty[1]: begin
                        if(request2)
                            state <= S_GNT2;
                        else if(request3)
                            state <= S_GNT3;
                        else if(request0)
                            state <= S_GNT0;
                        else if(request1)
                            state <= S_GNT1;
                    end
                    prrty[2]: begin
                        if(request3)
                            state <= S_GNT3;
                        else if(request0)
                            state <= S_GNT0;
                        else if(request1)
                            state <= S_GNT1;
                        else if(request2)
                            state <= S_GNT2;
                    end
                endcase
            S_GNT0: 
                if(end_transaction0) begin
                    prrty <= 4'b0001;
                    state <= S_IDLE;
                end
            S_GNT1: 
                if(end_transaction1) begin
                    prrty <= 4'b0010;
                    state <= S_IDLE;
                end
            S_GNT2: 
                if(end_transaction2) begin
                    prrty <= 4'b0100;
                    state <= S_IDLE;
                end
            S_GNT3: 
                if(end_transaction3) begin
                    prrty <= 4'b1000;
                    state <= S_IDLE;
                end
        endcase
end
//grant
always @(*) begin
    case(state) 
        S_IDLE:
            grant <= 4'b0000;
        S_GNT0:
            grant <= 4'b0001;
        S_GNT1:
            grant <= 4'b0010;
        S_GNT2:
            grant <= 4'b0100;
        S_GNT3:
            grant <= 4'b1000;
        default: 
            grant <= 4'b0000;
    endcase
        
end

endmodule

The simulation code is as follows:

//tb_arbiter.v

module tb_arbiter();

reg     clk             ;
reg     rst_n           ;
reg     request0        ;
reg     request1        ;
reg     request2        ;
reg     request3        ;
reg     end_transaction0;
reg     end_transaction1;
reg     end_transaction2;
reg     end_transaction3;
wire    grant0          ;          
wire    grant1          ;          
wire    grant2          ;          
wire    grant3          ;          

arbiter arbiter_inst(
    .clk                (clk                ),
    .rst_n              (rst_n               ),
    .request0           (request0           ),
    .request1           (request1           ),
    .request2           (request2           ),
    .request3           (request3           ),
    .end_transaction0   (end_transaction0   ),
    .end_transaction1   (end_transaction1   ),
    .end_transaction2   (end_transaction2   ),
    .end_transaction3   (end_transaction3   ),
    .grant0             (grant0             ),
    .grant1             (grant1             ),
    .grant2             (grant2             ),
    .grant3             (grant3             )
);

initial begin
    clk = 1'b0;             
    rst_n = 1'b0;           //复位操作
    request0 = 1'b0;       
    request1 = 1'b0;       
    request2 = 1'b0;       
    request3 = 1'b0;       
    end_transaction0 = 1'b0;
    end_transaction1 = 1'b0;
    end_transaction2 = 1'b0;
    end_transaction3 = 1'b0;

    #100;
    rst_n = 1'b1;           //复位完成

    #100;

    bus_request();
    #100
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
    #100;
    bus_request();
end

always #10 clk = ~clk;

task bus_request();
begin
    request0 = 1'b1;       
    request1 = 1'b1;       
    request2 = 1'b1;       
    request3 = 1'b1;       
    #20;
    request0 = 1'b0;       
    request1 = 1'b0;       
    request2 = 1'b0;       
    request3 = 1'b0; 
    #200;
    if(grant0 == 1'b1)
        end_transaction0 = 1'b1;
    else if(grant1 == 1'b1)
        end_transaction1 = 1'b1;
    else if(grant2 == 1'b1) 
        end_transaction2 = 1'b1;
    else if(grant3 == 1'b1)
        end_transaction3 = 1'b1;
    #20;
    end_transaction0 = 1'b0;
    end_transaction1 = 1'b0;
    end_transaction2 = 1'b0;
    end_transaction3 = 1'b0;
end  
endtask

endmodule

Simulation results:
Insert image description here

Guess you like

Origin blog.csdn.net/family5love/article/details/124123924
Recommended