一种Axi stream数据流可自动切换的IP模块

一、摘要

        在设计verilogHDL 程序架构时,为了提高fpga资源利用率,有些模块要被其它不同模块分时利用,经常采用Axi stream 数据总线作为这些模块的接口,模块输入接口对应两个模块的stream数据流输入,输出接口也同样对应两个模块,这就要设计两种数据流切换模块,一种2选一模块,另一种是1分2模块。

        下面所述的数据流都是指Axi stream 数据总线中的数据流。

二、数据流可自动切换的IP模块功能价绍

        

        对于模块A、B来说 流出的数据流不需要知道2先一模块的工作原理,只管输出各自的数据就行。模块A、B知道在一分二模块的指定端口接收模块C处理过的数据流中的数据就行。也就是说模块A从2选一的模块0号端口输入的数据,肯定是从一分二模块的0号端口输出相对应的处理过的数据返回给模块A。

三、用这两种模块可以组合成树形结构

     注意:图中的pipe模块是指上面所两种数据流切换模块。

多个这样的数据流切换模块组成的树形结构,有以下优点:

1、有寄存器打拍,隆低了fanout,提高了工作频率;

2、对于模块Bn,不需要管理各自的地址。地址管理完全交给数据流切换模块。

        

四、2合一数据切换模块SystemVerilog部分代码

//
// Company: 杭州幻智星科技有限公司
// Engineer: 俞工
// email: yupc123@qq.com
// Create Date: 01/25/2021 03:45:32 PM
// Design Name: 数据流切换
// Module Name: tree_packet_arb_n_to_1 
// Revision 0.01

module tree_packet_arb_n_to_1 # (
  parameter DAT_BYTS = 8,
  parameter DAT_BITS = DAT_BYTS*8,
  parameter CTL_BITS = 8,
  parameter NUM_IN = 8,
  parameter LOG2_NUM_IN = NUM_IN == 1 ? 1 : $clog2(NUM_IN),
  parameter OVR_WRT_BIT = CTL_BITS - LOG2_NUM_IN, // What bits in ctl are overwritten with channel id
  parameter N = 2, //  log n-tree
  parameter MAX = NUM_IN // Don't change
) (
  input i_clk, i_rst,

  if_axi_stream.sink   i_n_axi [NUM_IN-1:0], 
  if_axi_stream.source o_axi
);

localparam MOD_BITS = $clog2(DAT_BYTS);

// Instantiate the level of arbitrators, we build a tree
generate
  genvar g, h;
  // i_n_axi -> o_axi
  localparam NUM_IN_GRP = (NUM_IN+N-1)/N; 
    
  if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) o_axi_int [NUM_IN_GRP-1:0] (i_clk);
    
  for (g = 0; g < NUM_IN_GRP; g++) begin: GEN_TREE
    localparam NUM_IN_INT = (g+1)*N <= NUM_IN ? N : (NUM_IN % N);
    
    if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) i_axi_int [NUM_IN_INT-1:0] (i_clk);
    for (h = 0; h < NUM_IN_INT; h++) begin
      always_comb begin
        i_axi_int[h].copy_if_comb(i_n_axi[g*N + h].dat, i_n_axi[g*N + h].val, i_n_axi[g*N + h].sop, i_n_axi[g*N + h].eop, i_n_axi[g*N + h].err, i_n_axi[g*N + h].mod, i_n_axi[g*N + h].ctl);
        i_n_axi[g*N + h].rdy = i_axi_int[h].rdy;
        if (MAX == NUM_IN)
          i_axi_int[h].ctl[OVR_WRT_BIT +: LOG2_NUM_IN] = g*N + h;
      end
    end
    
    packet_arb_bp # (
      .DAT_BYTS     ( DAT_BYTS    ),
      .DAT_BITS     ( DAT_BITS    ),
      .CTL_BITS     ( CTL_BITS    ),
      .NUM_IN       ( NUM_IN_INT  ),
      .OVR_WRT_BIT  ( OVR_WRT_BIT ),
      .PIPELINE     ( 1           ),
      .PRIORITY_IN  ( 0           ),
      .OVERRIDE_CTL ( 0           )
    )
    packet_arb_bp (
      .i_clk ( i_clk ), 
      .i_rst ( i_rst ),
      .i_axi ( i_axi_int    ), 
      .o_axi ( o_axi_int[g] )
    );
  end
    
  if (NUM_IN_GRP > 1) begin
    tree_packet_arb_n_to_1 # (
      .DAT_BYTS     ( DAT_BYTS    ),
      .DAT_BITS     ( DAT_BITS    ),
      .CTL_BITS     ( CTL_BITS    ),
      .NUM_IN       ( NUM_IN_GRP  ),
      .OVR_WRT_BIT  ( OVR_WRT_BIT ),
      .N            ( N           ),
      .MAX          ( MAX         )
    ) 
    tree_packet_arb_n_to_1 (
      .i_clk ( i_clk ), 
      .i_rst ( i_rst ),
      .i_n_axi ( o_axi_int ), 
      .o_axi ( o_axi )
    );
  end else begin
    always_comb begin
      o_axi.copy_if_comb(o_axi_int[0].dat, o_axi_int[0].val, o_axi_int[0].sop, o_axi_int[0].eop, o_axi_int[0].err, o_axi_int[0].mod, o_axi_int[0].ctl);
      o_axi_int[0].rdy = o_axi.rdy;
    end
  end
    
endgenerate

endmodule

五、一分二数据切换模块SystemVerilog部分代码

//
// Company: 杭州幻智星科技有限公司
// Engineer: 俞工
// email: yupc123@qq.com
// Create Date: 01/25/2021 03:45:32 PM
// Design Name: 数据流切换
// Module Name: tree_packet_arb_1_to_n 
// Revision 0.01

module tree_packet_arb_1_to_n # (
  parameter DAT_BYTS = 8,
  parameter DAT_BITS = DAT_BYTS*8,
  parameter CTL_BITS = 8,
  parameter NUM_OUT = 8,
  parameter LOG2_NUM_OUT = NUM_OUT == 1 ? 1 : $clog2(NUM_OUT),
  parameter OVR_WRT_BIT = CTL_BITS - LOG2_NUM_OUT, // What bits in ctl are overwritten with channel id
  parameter N = 2, //  log n-tree
  parameter MAX = NUM_OUT // Don't change this
) (
  input i_clk, i_rst,

  if_axi_stream.sink   i_axi, 
  if_axi_stream.source o_n_axi[NUM_OUT-1:0]
);

localparam LOG2_MAX = MAX == 1 ? 1 : $clog2(MAX);

// This uses pipeline stages
generate
  genvar g, h;
  localparam NUM_OUT_GRP = (NUM_OUT+N-1)/N;
  
  if (NUM_OUT_GRP == 1) begin: FIRST_STAGE_GEN
    logic [NUM_OUT-1:0] rdy_i; 
    always_comb i_axi.rdy = |rdy_i;
    
    for (h = 0; h < NUM_OUT; h++) begin: FINAL_GEN
      logic in_range_i;
      always_comb rdy_i[h] = o_n_axi[h].rdy && in_range_i;
      always_comb in_range_i = i_axi.ctl[OVR_WRT_BIT +: LOG2_MAX] / (MAX/NUM_OUT) == h;
      always_comb begin
        o_n_axi[h].copy_if_comb(i_axi.dat, i_axi.val && in_range_i, i_axi.sop, i_axi.eop, i_axi.err, i_axi.mod, i_axi.ctl);
      end
    end
        
  end else begin
  
      if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) i_pipe [NUM_OUT_GRP-1:0] (i_clk);
  
      tree_packet_arb_1_to_n # (
        .DAT_BYTS     ( DAT_BYTS    ),
        .DAT_BITS     ( DAT_BITS    ),
        .CTL_BITS     ( CTL_BITS    ),
        .NUM_OUT      ( NUM_OUT_GRP ),
        .OVR_WRT_BIT  ( OVR_WRT_BIT ),
        .N            ( N           ),
        .MAX          ( MAX         )
      ) 
      tree_packet_arb_1_to_n (
        .i_clk ( i_clk ), 
        .i_rst ( i_rst ),
        .i_axi ( i_axi ), 
        .o_n_axi ( i_pipe )
      );  

    for (g = 0; g < NUM_OUT_GRP; g++) begin: GEN_TREE
        localparam NUM_OUT_INT = N;
        if_axi_stream #(.DAT_BYTS(DAT_BYTS), .DAT_BITS(DAT_BITS), .CTL_BITS(CTL_BITS)) o_pipe (i_clk);
        logic [NUM_OUT_INT-1:0] rdy_o;
        
        always_comb o_pipe.rdy = |rdy_o;
        
        pipeline_bp_if  #(
          .DAT_BITS   ( DAT_BITS ),
          .CTL_BITS   ( CTL_BITS ),
          .NUM_STAGES ( 1        )
        )
        pipeline_bp_if_in (
          .i_rst ( i_rst  ),
          .i_clk ( i_clk  ),
          .i_if  ( i_pipe[g] ),
          .o_if  ( o_pipe )
        );
        
        for (h = 0; h < NUM_OUT_INT; h++) begin: FINAL_GEN
          logic in_range_o;
          always_comb in_range_o = o_pipe.ctl[OVR_WRT_BIT +: LOG2_MAX] / (MAX/NUM_OUT) == g*N + h;
          always_comb begin
            rdy_o[h] = o_n_axi[g*N + h].rdy && in_range_o;
            o_n_axi[g*N + h].copy_if_comb(o_pipe.dat, o_pipe.val && in_range_o, o_pipe.sop, o_pipe.eop, o_pipe.err, o_pipe.mod, o_pipe.ctl);
          end
        end

      end
  end
    
endgenerate

endmodule

六、完整源代码

        下载地址:https://download.csdn.net/download/weixin_46897017/89584087

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值