0,原理
因为以太协议的传输可以看做下图:
在接受数据时,我们根据报文中携带的信息,
- 0806:ARP,0800:IP,
- portal:1 表示为 ICMP 协议, 2 表示为 IGMP 协议, 6 表示为 TCP 协议, 17表示为 UDP 协议
可以轻松的在对应模块进行报文的解析与数据提取。但是在发送的时候,比如ICMP,与UDP层。它们两都需要将发送报文传递给IP_TX进行ip层的组装,但是如果同时发送两个模块的报文,那么必然会引起冲突,造成数据的丢失,所以构建了一个2输入1输出的arbiter仲裁模块,进行报文优先级的选择实现报文的完整传输。
因为在实际运用中,icmp相对于udp,使用量偏少;arp相对于ip,使用量偏少。故在同一层当中,数据量少的优先级高(这里的弯弯需要绕一下,思考一波)。
1,代码编写
输入输出:
module arbiter_2_channel
(
input i_clk ,
input i_rst ,
//c1
input [ 63:0] s_c1_axis_data ,
input [ 79:0] s_c1_axis_user ,//len(16)+source_mac(48)+type(16)
input [ 7:0] s_c1_axis_keep ,
input s_c1_axis_last ,
input s_c1_axis_valid ,
output s_c1_axis_ready ,//
//c2
input [ 63:0] s_c2_axis_data ,
input [ 79:0] s_c2_axis_user ,//len(16)+source_mac(48)+type(16)
input [ 7:0] s_c2_axis_keep ,
input s_c2_axis_last ,
input s_c2_axis_valid ,
output s_c2_axis_ready ,//
//arbiter
//c1
output [ 63:0] m_axis_data ,
output [ 79:0] m_axis_user ,
output [ 7:0] m_axis_keep ,
output m_axis_last ,
output m_axis_valid
);
使用axi数据流接口构造,在user接口中传递长度。类型等信息。(如果感觉在64编码中,数据的长度不好确定,因为需要经过一个8bit->8byte的转换,可以单独设定一个信号用于存储输入数据的长度)。c1为优先级高的数据输入通道,c2为优先级低的数据输入通道。
代码的核心是利用多个fifo来存储两个通道的数据,user,last_keep,数据长度。
//channel_1
FIFO_ARBITER_2_CHANNEL_64X256 FIFO_data_c1_u0 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c1_axis_data ),// input wire [63 : 0] din
.wr_en (r_s_c1_axis_valid ),// input wire wr_en
.rd_en (r_fifo_c1_data_u0_rd_en ),// input wire rd_en
.dout (w_fifo_c1_data_u0_dout ),// output wire [63 : 0] dout
.full (w_fifo_c1_data_u0_full ),// output wire full
.empty (w_fifo_c1_data_u0_empty ),// output wire empty
.wr_rst_busy (w_fifo_c1_data_u0_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c1_data_u0_rd_rst_busy) // output wire rd_rst_busy
);
FIFO_ARBITER_2_CHANNEL_80X32 FIFO_user_c1_u1 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c1_axis_user ),// input wire [79 : 0] din
.wr_en (r_s_c1_axis_valid && r_s_c1_axis_last),// input wire wr_en
.rd_en (r_fifo_c1_user_u1_rd_en ),// input wire rd_en
.dout (w_fifo_c1_user_u1_dout ),// output wire [79 : 0] dout
.full (w_fifo_c1_user_u1_full ),// output wire full
.empty (w_fifo_c1_user_u1_empty ),// output wire empty
.wr_rst_busy (w_fifo_c1_user_u1_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c1_user_u1_rd_rst_busy) // output wire rd_rst_busy
);
//last_keep
FIFO_ARBITER_2_CHANNEL_8X32 FIFO_keep_c1_u2 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c1_axis_keep ),// input wire [7 : 0] din
.wr_en (r_s_c1_axis_valid && r_s_c1_axis_last),// input wire wr_en
.rd_en (r_fifo_c1_keep_u2_rd_en ),// input wire rd_en
.dout (w_fifo_c1_keep_u2_dout ),// output wire [7 : 0] dout
.full (w_fifo_c1_keep_u2_full ),// output wire full
.empty (w_fifo_c1_keep_u2_empty ),// output wire empty
.wr_rst_busy (w_fifo_c1_keep_u2_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c1_keep_u2_rd_rst_busy) // output wire rd_rst_busy
);
FIFO_ARBITER_2_CHANNEL_16X32 FIFO_len_c1_u3 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_wr_c1_cnt ),// input wire [7 : 0] din
.wr_en (r_s_c1_axis_valid && r_s_c1_axis_last),// input wire wr_en
.rd_en (r_fifo_c1_len_u3_rd_en ),// input wire rd_en
.dout (w_fifo_c1_len_u3_dout ),// output wire [7 : 0] dout
.full (w_fifo_c1_len_u3_full ),// output wire full
.empty (w_fifo_c1_len_u3_empty ),// output wire empty
.wr_rst_busy (w_fifo_c1_len_u3_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c1_len_u3_rd_rst_busy) // output wire rd_rst_busy
);
//channel_2
FIFO_ARBITER_2_CHANNEL_64X256 FIFO_data_c2_u0 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c2_axis_data ),// input wire [63 : 0] din
.wr_en (r_s_c2_axis_valid ),// input wire wr_en
.rd_en (r_fifo_c2_data_u0_rd_en ),// input wire rd_en
.dout (w_fifo_c2_data_u0_dout ),// output wire [63 : 0] dout
.full (w_fifo_c2_data_u0_full ),// output wire full
.empty (w_fifo_c2_data_u0_empty ),// output wire empty
.wr_rst_busy (w_fifo_c2_data_u0_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c2_data_u0_rd_rst_busy) // output wire rd_rst_busy
);
FIFO_ARBITER_2_CHANNEL_80X32 FIFO_user_c2_u1 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c2_axis_user ),// input wire [79 : 0] din
.wr_en (r_s_c2_axis_valid && r_s_c2_axis_last),// input wire wr_en
.rd_en (r_fifo_c2_user_u1_rd_en ),// input wire rd_en
.dout (w_fifo_c2_user_u1_dout ),// output wire [79 : 0] dout
.full (w_fifo_c2_user_u1_full ),// output wire full
.empty (w_fifo_c2_user_u1_empty ),// output wire empty
.wr_rst_busy (w_fifo_c2_user_u1_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c2_user_u1_rd_rst_busy) // output wire rd_rst_busy
);
FIFO_ARBITER_2_CHANNEL_8X32 FIFO_keep_c2_u2 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_s_c2_axis_keep ),// input wire [7 : 0] din
.wr_en (r_s_c2_axis_valid && r_s_c2_axis_last),// input wire wr_en
.rd_en (r_fifo_c2_keep_u2_rd_en ),// input wire rd_en
.dout (w_fifo_c2_keep_u2_dout ),// output wire [7 : 0] dout
.full (w_fifo_c2_keep_u2_full ),// output wire full
.empty (w_fifo_c2_keep_u2_empty ),// output wire empty
.wr_rst_busy (w_fifo_c2_keep_u2_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c2_keep_u2_rd_rst_busy) // output wire rd_rst_busy
);
FIFO_ARBITER_2_CHANNEL_16X32 FIFO_len_c2_u3 (
.clk (i_clk ),// input wire clk
.srst (i_rst ),// input wire srst
.din (r_wr_c2_cnt ),// input wire [7 : 0] din
.wr_en (r_s_c2_axis_valid && r_s_c2_axis_last),// input wire wr_en
.rd_en (r_fifo_c2_len_u3_rd_en ),// input wire rd_en
.dout (w_fifo_c2_len_u3_dout ),// output wire [7 : 0] dout
.full (w_fifo_c2_len_u3_full ),// output wire full
.empty (w_fifo_c2_len_u3_empty ),// output wire empty
.wr_rst_busy (w_fifo_c2_len_u3_wr_rst_busy),// output wire wr_rst_busy
.rd_rst_busy (w_fifo_c2_len_u3_rd_rst_busy) // output wire rd_rst_busy
);
通过两个仲裁信号来进行判断当前从那个通道的fifo中读出数据。r_arbiter_flag == 0代表输出通道1的数据,r_arbiter_flag == 1 代表输出通道2的数据。
同时在有一个通道输出时,会将arbiter_lock信号拉高,对r_arbiter_flag上锁,哪怕此时有优先级高的信号到来,也会完成当前低优先级的数据的输出。
/************** 仲裁模块 *********************/
//通道优先级:c1>c2
always @(posedge i_clk) begin
if (i_rst) begin
r_arbiter_flag <= 'd0;
end
else if(r_arbiter_lock == 0 && !w_fifo_c1_len_u3_empty) begin //c1通道中有数据,立马仲裁为通道一进行输出,优先级最高
r_arbiter_flag <= 'd0;
end
else if(r_arbiter_lock == 0 && w_fifo_c1_len_u3_empty && !w_fifo_c2_len_u3_empty) begin//c1通道中的数据已经输出完毕了,才会输出通道2的数据
r_arbiter_flag <= 'd1;
end
else begin
r_arbiter_flag <= r_arbiter_flag;
end
end
always @(posedge i_clk) begin
if (i_rst) begin
r_arbiter_lock <= 'd0;
end
else if(m_axis_last) begin //当前数据输出完毕
r_arbiter_lock <= 'd0;
end
else if(r_fifo_c1_len_u3_rd_en) begin ///读取通道一的长度信息,要开始锁定
r_arbiter_lock <= 'd1;
end
else if(r_fifo_c2_len_u3_rd_en) begin
r_arbiter_lock <= 'd1;
end
else begin
r_arbiter_lock <= r_arbiter_lock;
end
end
仿真波形:
1,可以看到先输出了3个通道一的数据,再输出3个通道二的数据
2,在输出通道二的数据时,又重新输入了一个通道一的数据,会在当前通道二数据输出完毕之后,才会输出新加入的高优先级通道一的数据,再次输入完毕之后,接着输出低优先级通道二的数据。实现了优先级仲裁完整数据输出,在数据冲突时可以实现分流作用,但是数据的长度不能超过fifo的容量,不然会导师数据的丢失
仿真代码:
`timescale 1ns/1ps
module tb_arbiter();
reg i_clk ;
reg i_rst ;
always begin
i_clk <= 'd0;
#5;
i_clk <= 'd1;
#5;
end
initial begin
i_rst <= 'd1;
#100;
@(posedge i_clk);
i_rst <= 'd0;
end
logic [ 63:0] s_c1_axis_data ;
logic [ 79:0] s_c1_axis_user ;
logic [ 7:0] s_c1_axis_keep ;
logic s_c1_axis_last ;
logic s_c1_axis_valid ;
logic s_c1_axis_ready ;
logic [ 63:0] s_c2_axis_data ;
logic [ 79:0] s_c2_axis_user ;
logic [ 7:0] s_c2_axis_keep ;
logic s_c2_axis_last ;
logic s_c2_axis_valid ;
logic s_c2_axis_ready ;
wire [ 63:0] w_m_axis_data ;
wire [ 79:0] w_m_axis_user ;
wire [ 7:0] w_m_axis_keep ;
wire w_m_axis_last ;
wire w_m_axis_valid ;
arbiter_2_channel arbiter_2_channel_inst
(
.i_clk (i_clk ),
.i_rst (i_rst ),
//c1
.s_c1_axis_data (s_c1_axis_data ),
.s_c1_axis_user (s_c1_axis_user ),//len(16)+source_mac(48)+type(16)
.s_c1_axis_keep (s_c1_axis_keep ),
.s_c1_axis_last (s_c1_axis_last ),
.s_c1_axis_valid (s_c1_axis_valid ),
.s_c1_axis_ready (s_c1_axis_ready ),//
//c2
.s_c2_axis_data (s_c2_axis_data ),
.s_c2_axis_user (s_c2_axis_user ),//len(16)+source_mac(48)+type(16)
.s_c2_axis_keep (s_c2_axis_keep ),
.s_c2_axis_last (s_c2_axis_last ),
.s_c2_axis_valid (s_c2_axis_valid ),
.s_c2_axis_ready (s_c2_axis_ready ),//
//arbiter
//c1
.m_axis_data (w_m_axis_data ),
.m_axis_user (w_m_axis_user ),
.m_axis_keep (w_m_axis_keep ),
.m_axis_last (w_m_axis_last ),
.m_axis_valid (w_m_axis_valid )
);
initial begin
s_c1_axis_data <= 'd0;
s_c1_axis_user <= 'd0;
s_c1_axis_keep <= 'd0;
s_c1_axis_last <= 'd0;
s_c1_axis_valid <= 'd0;
s_c2_axis_data <= 'd0;
s_c2_axis_user <= 'd0;
s_c2_axis_keep <= 'd0;
s_c2_axis_last <= 'd0;
#1000;
send_c1_test(10,8'b1111_1111);
#200;
send_c1_test(20,8'b1111_0000);
#200;
send_c1_test(30,8'b1111_1100);
#2000;
send_c1_test(40,8'b1111_1100);
end
initial begin
s_c2_axis_data <= 'd0;
s_c2_axis_user <= 'd0;
s_c2_axis_keep <= 'd0;
s_c2_axis_last <= 'd0;
s_c2_axis_valid <= 'd0;
s_c2_axis_data <= 'd0;
s_c2_axis_user <= 'd0;
s_c2_axis_keep <= 'd0;
s_c2_axis_last <= 'd0;
#1000;
send_c2_test(100,8'b1111_1111);
#200;
send_c2_test(100,8'b1111_0000);
#200;
send_c2_test(200,8'b1111_1100);
end
task send_c1_test (input [15:0] send_len, input [7:0] last_keep);
begin:send_c1_test_task
integer i;
s_c1_axis_data <= 'd0;
s_c1_axis_user <= 'd0;
s_c1_axis_keep <= 'd0;
s_c1_axis_last <= 'd0;
s_c1_axis_valid <= 'd0;
wait(s_c1_axis_ready);
@(posedge i_clk);
for(i=0 ; i< send_len ; i = i + 1) begin
if(i == send_len - 1) begin
s_c1_axis_data <= s_c1_axis_data + 1;
s_c1_axis_user <= {send_len , 48'd0 , 16'h0806};
s_c1_axis_keep <= last_keep;
s_c1_axis_last <= 'd1;
s_c1_axis_valid <= 'd1;
end
else begin
s_c1_axis_data <= s_c1_axis_data + 1;
s_c1_axis_user <= {send_len , 48'd0 , 16'h0806};
s_c1_axis_keep <= 8'b1111_1111;
s_c1_axis_last <= 'd0;
s_c1_axis_valid <= 'd1;
end
@(posedge i_clk);
end
s_c1_axis_data <= 'd0;
s_c1_axis_user <= 'd0;
s_c1_axis_keep <= 'd0;
s_c1_axis_last <= 'd0;
s_c1_axis_valid <= 'd0;
end
endtask //send_c1_test
task send_c2_test (input [15:0] send_len, input [7:0] last_keep);
begin:send_c2_test_task
integer i;
s_c2_axis_data <= 'd0;
s_c2_axis_user <= 'd0;
s_c2_axis_keep <= 'd0;
s_c2_axis_last <= 'd0;
s_c2_axis_valid <= 'd0;
wait(s_c2_axis_ready);
@(posedge i_clk);
for(i=0 ; i< send_len ; i = i + 1) begin
if(i == send_len - 1) begin
s_c2_axis_data <= s_c2_axis_data + 1;
s_c2_axis_user <= {send_len , 48'd0 , 16'h0800};
s_c2_axis_keep <= last_keep;
s_c2_axis_last <= 'd1;
s_c2_axis_valid <= 'd1;
end
else begin
s_c2_axis_data <= s_c2_axis_data + 1;
s_c2_axis_user <= {send_len , 48'd0 , 16'h0800};
s_c2_axis_keep <= 8'b1111_1111;
s_c2_axis_last <= 'd0;
s_c2_axis_valid <= 'd1;
end
@(posedge i_clk);
end
s_c2_axis_data <= 'd0;
s_c2_axis_user <= 'd0;
s_c2_axis_keep <= 'd0;
s_c2_axis_last <= 'd0;
s_c2_axis_valid <= 'd0;
end
endtask //send_c1_test
endmodule