Digital IC tearing code--MediaTek (bus access arbitration)

topic description

When the signals of groups A and B request access to a certain module, in order to ensure correct access, these signals need to be arbitrated. Please use Verilog to implement an arbiter to arbitrate two sets of request signals, requiring:

The protocol is shown in the figure. The requester sends a req (request) signal of 1 to indicate that there is a request to the arbitrator, and the arbitrator responds with a grant signal of 1 to indicate that the request is successful:

Define the ratio of response A/B in conflict situations by parameters

(For example, within a period of time, there are several A requests and several B requests, among which A&B conflicts N times, among the N times, A is responded to 3 times, and then B is responded to 1 time, and the cycle is repeated. 3 and 1 in the example are configurable.);

Add necessary comments to increase code readability.

problem solving ideas

According to the title description, it is easy to think that the port of the module arbiter should be as follows:

module arbiter (
    input wire clk,         // 时钟信号
    input wire rst,         // 复位信号
    input wire reqA,        // A组请求信号
    input wire reqB,        // B组请求信号
    output reg grantA,      // A组响应信号
    output reg grantB       // B组响应信号
);

Clock, reset signal. Two request signals and two corresponding response signals. Only when there is a conflict, the AB conflict response ratio is 3:1. In other cases, respond normally. So it is possible to write a counter that is incremented by 1 only on collisions. When the counter = 0, 1, 2, it responds to A, when the counter = 3, it responds to B, and at the same time, set the counter to 0.

For the arbitration part, the request signals reqA and reqB of the bus can be spliced ​​into a 2-bit signal, so that the use of case statements can avoid long combination logic chains caused by multi-level if-else nesting.

In the case statement, put all possible 2'b00, 2'b01, 2'b10, 2'b11 of {reqA, reqB}. It is enough to plan everything. When {reqA, reqB}==2'b11, judge the conflict counter range, if it falls in [0,A_ratio-1], A will get the bus when the conflict occurs; if the counter falls in [A_ratio,A_ratio+B_ratio-2], B will get the bus when the conflict occurs. In this way, the module can customize the conflict allocation ratio to meet the requirements of the topic.

the code

module arbiter #(
    parameter [7:0] A_ratio = 3 ,   // A grant ratio 
    parameter [7:0] B_ratio = 1     // B grant ratio
)(
    input   wire    clk     ,       // 时钟信号
    input   wire    rstn    ,       // 复位信号
    input   wire    reqA    ,       // A组请求信号
    input   wire    reqB    ,       // B组请求信号
    output          grantA  ,       // A组响应信号
    output          grantB          // B组响应信号
);

// 定义计数器和比例参数
reg [7:0] counter = 0;             // belongs to [0, A_ratio + B_ratio - 1]
reg grantA_reg,grantB_reg;

assign grantA = grantA_reg;
assign grantB = grantB_reg;

always @(posedge clk) begin
    if (!rstn) begin
        grantA_reg <= 0;
        grantB_reg <= 0;
    end 
    else begin
        case({reqA,reqB})
            2'b00:begin
                grantA_reg <= 1'b0;
                grantB_reg <= 1'b0;
            end
            2'b01:begin
                grantA_reg <= 1'b0;
                grantB_reg <= 1'b1;
            end
            2'b10:begin
                grantA_reg <= 1'b1;
                grantB_reg <= 1'b0;
            end
            default:begin
                if(counter <= (A_ratio - 1) )begin
                    grantA_reg <= 1'b1;
                    grantB_reg <= 1'b0;
                end
                else begin
                    grantA_reg <= 1'b0;
                    grantB_reg <= 1'b1;
                end
            end
        endcase
    end
end

always @(posedge clk)begin
    if(!rstn)begin
        counter <= 8'd0;
    end
    if( (reqA&&reqB) && (counter <= (A_ratio + B_ratio - 2)) )begin
        counter <= counter + 1'b1;
    end
    else 
        counter <= 8'd0;
end

endmodule

tb

module arbiter_tb;

// 定义时钟和复位信号
reg clk;
reg rstn;

// 定义A组和B组请求信号
reg reqA;
reg reqB;

// 定义A组和B组响应信号
wire grantA;
wire grantB;

// 实例化被测试的模块
arbiter dut (
    .clk(clk),
    .rstn(rstn),
    .reqA(reqA),
    .reqB(reqB),
    .grantA(grantA),
    .grantB(grantB)
);

// 时钟信号发生器
always #5 clk = ~clk;

// 测试用例1:A组优先
initial begin
    // 初始化信号
    rstn = 0;
    clk  = 0;
    reqA = 0;
    reqB = 0;
    
    // 复位
    #15 rstn = 1;
    #1 
    // 发送A组请求
    #10 reqA = 1;
         
    // 发送B组请求
    #10 reqA = 0;reqB = 1;
    
    // 发送A and B组请求 eight times
    repeat(8) begin
    #10 reqA = 1;reqB = 1;
    end
    repeat(2) begin
    #10 reqA = 1;reqB = 0;
    end
    repeat(2) begin
    #10 reqA = 0;reqB = 1;
    end
    #10 reqA = 0;reqB = 0;
    // 停止测试
    #100 $finish;
end

initial begin
    $fsdbDumpfile("arbiter.fsdb");
    $fsdbDumpvars(0);
end

endmodule

Waveform

In tb, let A and B request the bus once respectively, then let them have request conflicts 8 times, and finally let A and B request the bus twice. It can be seen from the figure that when A and B request conflict, the ratio of A_grant and B_grant to get the bus is 3:1. We gave two parameters at the beginning of the module definition, and defined the ratio of A_grant and B_grant to get the bus A_ratio and B_ratio. If you want to modify the module code, modify the parameter passed in by the module The value can be.

For more tear-off code questions, you can go to Digital IC tear-off code--question bank

Guess you like

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