Verilog——一个简单仲裁器的实现

Verilog——一个简单仲裁器的实现

仲裁器基本功能

仲裁器(arbiter) 的主要功能是,多个source源同时发出请求时,根据当前的优先级来判断应响应哪一个source。

仲裁器分为轮询优先级仲裁器(Round-Robiin)和固定优先级仲裁器(Fixed-Priority)。轮询仲裁器对各个source的响应优先级随各个source请求轮询变化,最终对各个source的优先级是较为均衡的。

  • 轮询仲裁器的规则是:当0、1、2、、、N-1个source信号源同时向仲裁器发出请求时,初始情况下source 0的优先级最高,当仲裁器响应了source0后,source1的优先级最高,依次类推。

  • 固定优先级仲裁器规则是:当0、1、2、、、N-1个source同时发起request,Source 0的优先级最高,即便source0被相应完后,仍为最高优先级,其中优先级按照序号逐渐降低。

轮询仲裁器和固定优先级仲裁器在FPGA实现的类似,唯一不同的是轮询仲裁在每次响应完request后会对优先级进行更新,而固定优先级则不需要此步骤。

下面是一个简单轮询仲裁器模块的实现方案。该实现方案的关键点是:

  • 根据当前优先级变量prrty的数值来决定响应优先级;
  • 响应结束后更改优先级prrty。
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

仿真代码如下:

//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

仿真结果:
Verilog——一个简单仲裁器的实现_第1张图片

你可能感兴趣的:(Verilog,硬件,仲裁器,Verilog,FPGA)