天天看點

蜂鳥e203 module解讀 之 sirv_icb1to16_bus sirv_gnrl_buffer sirv_gnrl_fifo1 fifo解讀sirv_gnrl_buffer 解讀sirv_icb1to16_bus

1 fifo解讀

module位置:sirv_gnrl_bufs.v

sirv_gnrl_fifo

基于vivado軟體進行測試:

sirv_gnrl_fifo.v

`define FPGA_SOURCE
//=====================================================================
//
// Designer   : Bob Hu
//
// Description:
//  The general sync FIFO module
//
// ====================================================================

module sirv_gnrl_fifo # (
  // When the depth is 1, the ready signal may relevant to next stage's ready, hence become logic
  // chains. Use CUT_READY to control it
  // When fifo depth is 1, the fifo is a signle stage
       // if CUT_READY is set, then the back-pressure ready signal will be cut
       //      off, and it can only pass 1 data every 2 cycles
  // When fifo depth is > 1, then it is actually a really fifo
       //      The CUT_READY parameter have no impact to any logics
  parameter CUT_READY = 0,
  parameter MSKO = 0,// Mask out the data with valid or not
  parameter DP   = 8,// FIFO depth
  parameter DW   = 32// FIFO width
) (

  input           i_vld, 
  output          i_rdy, 
  input  [DW-1:0] i_dat,
  output          o_vld, 
  input           o_rdy, 
  output [DW-1:0] o_dat,

  input           clk,
  input           rst_n
);

genvar i;
generate //{

  if(DP == 0) begin: dp_eq1//{ pass through when it is 0 entries

     assign o_vld = i_vld;
     assign i_rdy = o_rdy;
     assign o_dat = i_dat;

  end//}
  else begin: dp_gt0//{

    // FIFO registers
    wire [DW-1:0] fifo_rf_r [DP-1:0];
    wire [DP-1:0] fifo_rf_en;

    // read/write enable
    wire wen = i_vld & i_rdy;
    wire ren = o_vld & o_rdy;
    
    
    / Read-Pointer and Write-Pointer
    wire [DP-1:0] rptr_vec_nxt; 
    wire [DP-1:0] rptr_vec_r;
    wire [DP-1:0] wptr_vec_nxt; 
    wire [DP-1:0] wptr_vec_r;

    if(DP == 1) begin:rptr_dp_1
      assign rptr_vec_nxt = 1'b1; 
    end
    else begin:rptr_dp_not_1
      assign rptr_vec_nxt = 
          rptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
                          (rptr_vec_r << 1);
    end

    if(DP == 1) begin:wptr_dp_1
      assign wptr_vec_nxt = 1'b1; 
    end
    else begin:wptr_dp_not_1
      assign wptr_vec_nxt =
          wptr_vec_r[DP-1] ? {{DP-1{1'b0}}, 1'b1} :
                          (wptr_vec_r << 1);
    end

    sirv_gnrl_dfflrs #(1)    rptr_vec_0_dfflrs  (ren, rptr_vec_nxt[0]     , rptr_vec_r[0]     , clk, rst_n);  // default reset to 1
    sirv_gnrl_dfflrs #(1)    wptr_vec_0_dfflrs  (wen, wptr_vec_nxt[0]     , wptr_vec_r[0]     , clk, rst_n);
    if(DP > 1) begin:dp_gt1
    sirv_gnrl_dfflr  #(DP-1) rptr_vec_31_dfflr  (ren, rptr_vec_nxt[DP-1:1], rptr_vec_r[DP-1:1], clk, rst_n);
    sirv_gnrl_dfflr  #(DP-1) wptr_vec_31_dfflr  (wen, wptr_vec_nxt[DP-1:1], wptr_vec_r[DP-1:1], clk, rst_n);
    end

    
    / Vec register to easy full and empty and the o_vld generation with flop-clean
    wire [DP:0] i_vec;
    wire [DP:0] o_vec;
    wire [DP:0] vec_nxt; 
    wire [DP:0] vec_r;

    wire vec_en = (ren ^ wen );
    assign vec_nxt = wen ? {vec_r[DP-1:0], 1'b1} : (vec_r >> 1);  
    
    sirv_gnrl_dfflrs #(1)  vec_0_dfflrs     (vec_en, vec_nxt[0]     , vec_r[0]     ,     clk, rst_n);
    sirv_gnrl_dfflr  #(DP) vec_31_dfflr     (vec_en, vec_nxt[DP:1], vec_r[DP:1],     clk, rst_n);
    
    assign i_vec = {1'b0,vec_r[DP:1]};
    assign o_vec = {1'b0,vec_r[DP:1]};

    if(DP == 1) begin:cut_dp_eq1//{
        if(CUT_READY == 1) begin:cut_ready//{
          // If cut ready, then only accept when fifo is not full
          assign i_rdy = (~i_vec[DP-1]);
        end//}
        else begin:no_cut_ready//{
          // If not cut ready, then can accept when fifo is not full or it is popping 
          assign i_rdy = (~i_vec[DP-1]) | ren;
        end//}
    end//}
    else begin : no_cut_dp_gt1//}{
      assign i_rdy = (~i_vec[DP-1]);
    end//}


    / write fifo
    for (i=0; i<DP; i=i+1) begin:fifo_rf//{
      assign fifo_rf_en[i] = wen & wptr_vec_r[i];
      // Write the FIFO registers
      sirv_gnrl_dffl  #(DW) fifo_rf_dffl (fifo_rf_en[i], i_dat, fifo_rf_r[i], clk);
    end//}

    /One-Hot Mux as the read path
    integer j;
    reg [DW-1:0] mux_rdat;
    always @*
    begin : rd_port_PROC//{
      mux_rdat = {DW{1'b0}};
      for(j=0; j<DP; j=j+1) begin
        mux_rdat = mux_rdat | ({DW{rptr_vec_r[j]}} & fifo_rf_r[j]);
      end
    end//}
    
    if(MSKO == 1) begin:mask_output//{
        // Mask the data with valid since the FIFO register is not reset and as X 
        assign o_dat = {DW{o_vld}} & mux_rdat;
    end//}
    else begin:no_mask_output//{
        // Not Mask the data with valid since no care with X for datapth
        assign o_dat = mux_rdat;
    end//}
    
    // o_vld as flop-clean
    assign o_vld = (o_vec[0]);
    
  end//}
endgenerate//}

endmodule 
           

tb_sirv_gnrl_fifo.v測試檔案:

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 04/08/2021 03:18:51 PM
// Design Name: 
// Module Name: tb_sirv_gnrl_dffs
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module tb_sirv_gnrl_dffs(
);

print_task print();

reg         i_vld;
wire        i_rdy;
reg [9:0]   i_dat;
wire        o_vld;
reg         o_rdy;
wire [9:0]  o_dat;

reg clk;
reg rst_n;

// clk init
parameter PERIOD = 2;

always begin
    #(PERIOD/2) clk = 1;
    #(PERIOD/2) clk = 0;
end

 reset task
task reset_task;
input [15:0] reset_time;
begin
    rst_n = 0;
    #reset_time;
    rst_n = 1;
end

endtask


sirv_gnrl_fifo # (
    .CUT_READY (0),
    .MSKO      (0),
    .DP  (2),
    .DW  (10)
) u_sirv_gnrl_dffs(
    .i_vld (i_vld), 
    .i_rdy (i_rdy), 
    .i_dat (i_dat),
    .o_vld (o_vld), 
    .o_rdy (o_rdy), 
    .o_dat (o_dat),
    
    .clk   (clk),
    .rst_n (rst_n)  
);


initial begin
    reset_task(20);
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 11;
    i_vld = 1'b1;
    i_dat = 10'hf8;
    o_rdy = 1'b1;
    # 2;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 10;
    i_vld = 1'b1;
    i_dat = 10'h3d;
    o_rdy = 1'b0;
    # 2;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 2;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 10;
    i_vld = 1'b1;
    i_dat = 10'hd8;
    o_rdy = 1'b1;
    # 2;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 20;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b1;
    # 2;
    i_vld = 1'b0;
    i_dat = 10'h00;
    o_rdy = 1'b0;
    # 20;
    
    print.terminate;
    

end

endmodule
           

還需要單獨拷貝蜂鳥工程中的 sirv_gnrl_dffs.v檔案.

測試後得到測試波形,結合波形和代碼進行分析,關鍵點:

  • fifo實作的功能: 将icb總線的cmd輸入信号打包成一個package壓入FIFO, FIFO的深度設定為2,寬度為packge對應的資料寬度. 當FIFO未被壓滿時, i_rdy 信号一直保持高電平有效; 當FIFO壓滿後i_rdy拉低, 告知icb總線的master不可以壓入了. 當FIFO有資料時, o_vld保持高電平,告知icb總線的slave目前master有請求.
  • 為什麼vec_r寄存器的長度為 DP+1, 比如當FIFO深度為2時,為什麼vec_r是3?

sirv_gnrl_buffer 解讀

主要由兩個fifo組成,分别處理icb_cmd 和 icb_rsq, 指令通道和回報通道的分别對應兩個fifo

sirv_icb1to16_bus

首先設定一個 sirv_gnrl_buffer對輸入的cmd和回報的rsq進行fifo狀态存儲, 然後使用sirv_gnrl_icb_splt 對sirv_gnrl_buffer 處理後的的cmd和rsq進行出去, 将其split

繼續閱讀