10G_ethernet学习记录(6):arbiter仲裁模块

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值