一、摘要
在设计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