天天看點

數字IC手撕代碼--聯發科(總線通路仲裁)題目描述解題思路代碼tb波形圖

題目描述

當A、B兩組的信号請求通路某個子產品時,為了保證正确的通路,需要對這些信号進行仲裁。請用Verilog實作一個仲裁器,對兩組請求信号進行仲後,要求:

協定如圖所示,請求方發送req(request)信号1表示有請求給仲裁器,仲裁器響應grant信号為1表示請求成功:

數字IC手撕代碼--聯發科(總線通路仲裁)題目描述解題思路代碼tb波形圖

通過參數定義在沖突情形下,響應A/B的比例

(舉例,一段時間内,有若幹次A請求和若幹次B請求,其中A&B發生沖突的有N次,這N次中先響應A 3次,後響應B 1次,循環反複。舉例中的3和1可配置。);

添加必要的注釋,增加代碼可讀性。

解題思路

根據題目描述,很容易想到子產品arbiter的端口應該如下:

module arbiter (
    input wire clk,         // 時鐘信号
    input wire rst,         // 複位信号
    input wire reqA,        // A組請求信号
    input wire reqB,        // B組請求信号
    output reg grantA,      // A組響應信号
    output reg grantB       // B組響應信号
);
           

時鐘、複位信号。兩個請求信号和兩個相應響應信号。隻有在沖突時,AB沖突響應比為3:1。其他情況下,正常響應。是以可以寫一個計數器,僅在沖突時加1。計數器=0,1,2時響應A,計數器=3時響應B,于此同時将計數器置0。

對于仲裁部分,可以将總線的請求信号reqA和reqB拼接成一個2bit信号,這樣使用case語句就能避免多級if-else嵌套導緻的長組合邏輯鍊。

在case語句中,把{reqA, reqB}的所有可能2'b00,2'b01,2'b10,2'b11。全都規劃到就行,當{reqA, reqB}==2'b11時,判斷沖突計數器範圍,落在[0,A_ratio-1],則沖突時A獲得總線;若counter落在[A_ratio,A_ratio+B_ratio-2]時,沖突時B獲得總線。這樣子產品滿足題目要求可自定義沖突配置設定比例。

代碼

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
           

波形圖

數字IC手撕代碼--聯發科(總線通路仲裁)題目描述解題思路代碼tb波形圖

在tb裡,先分别讓A、B各請求總線一次,然後讓他們出現請求沖突8次,最後再讓A、B分别請求總線兩次,從圖中可以看到,在A、B請求沖突的時候,A_grant、B_grant拿到總線的比例是3:1,我們在module定義開頭給了兩個parameter,定義了A_grant、B_grant拿到總線的比例A_ratio和B_ratio,如果要修改子產品代碼,修改module傳入的parameter的值即可。

更多手撕代碼題可以前往 數字IC手撕代碼--題庫

繼續閱讀