当前位置:   article > 正文

万兆以太网MAC设计(4)CRC_process模块

万兆以太网MAC设计(4)CRC_process模块

前言

上文介绍的MAC_RX模块当中增加了CRC校验和比对的功能,本文将根据CRC校验的结果,来决定将数据输出到上层用户还是丢弃。

一、模块功能

  1. 接收MAC_RX模块输出的AXIS数据,存入本地环形RAM当中
  2. 根据MAC_RX模块给出的CRC校验结果,来决定是否输出数据,只有正确的情况下才会从RAM当中将数据吐出,否则不输出,下一帧数据将会直接覆盖错误数据。
module CRC_process(
    input           i_clk               ,
    input           i_rst               ,

    input  [63:0]   s_axis_rdata        ,
    input  [79:0]   s_axis_ruser        ,
    input  [7 :0]   s_axis_rkeep        ,
    input           s_axis_rlast        ,
    input           s_axis_rvalid       ,
    input           i_crc_error         ,
    input           i_crc_valid         ,
    
    output [63:0]   m_axis_rdata        ,
    output [79:0]   m_axis_ruser        ,
    output [7 :0]   m_axis_rkeep        ,
    output          m_axis_rlast        ,
    output          m_axis_rvalid       
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

二、实现过程

BRAM_SD_64X256 BRAM_SD_64X256_data (
  .clka         (i_clk              ), // input wire clka
  .ena          (rs_axis_rvalid     ), // input wire ena
  .wea          (rs_axis_rvalid     ), // input wire [0 : 0] wea
  .addra        (r_ram_data_addra   ), // input wire [7 : 0] addra
  .dina         (rs_axis_rdata      ), // input wire [63 : 0] dina
  .clkb         (i_clk              ), // input wire clkb
  .enb          (r_ram_data_enb     ), // input wire enb
  .addrb        (r_ram_data_addrb   ), // input wire [7 : 0] addrb
  .doutb        (w_ram_data_doutb   )  // output wire [63 : 0] doutb
);
  
BRAM_SD_16X32 BRAM_SD_16X32_len (
  .clka         (i_clk              ), // input wire clka             
  .ena          (rs_axis_rlast      ), // input wire ena              
  .wea          (rs_axis_rlast      ), // input wire [0 : 0] wea      
  .addra        (r_ram_len_addra    ), // input wire [4 : 0] addra    
  .dina         (rs_axis_ruser[79:64]), // input wire [15 : 0] dina    
  .clkb         (i_clk              ), // input wire clkb             
  .enb          (r_ram_len_enb      ), // input wire enb              
  .addrb        (r_ram_len_addrb    ), // input wire [4 : 0] addrb    
  .doutb        (w_ram_len_doutb    )  // output wire [15 : 0] doutb  
);

BRAM_SD_8X32 BRAM_SD_8X32_keep (
  .clka         (i_clk              ),  // input wire clka            
  .ena          (rs_axis_rlast      ),  // input wire ena             
  .wea          (rs_axis_rlast      ),  // input wire [0 : 0] wea     
  .addra        (r_ram_keep_addra   ),  // input wire [4 : 0] addra   
  .dina         (rs_axis_rkeep      ),  // input wire [7 : 0] dina    
  .clkb         (i_clk              ),  // input wire clkb            
  .enb          (r_ram_keep_enb     ),  // input wire enb             
  .addrb        (r_ram_keep_addrb   ),  // input wire [4 : 0] addrb   
  .doutb        (w_ram_keep_doutb   )   // output wire [7 : 0] doutb  
);

BRAM_SD_64X32 BRAM_SD_64X32_user (
  .clka         (i_clk              ),  // input wire clka
  .ena          (rs_axis_rlast      ),  // input wire ena
  .wea          (rs_axis_rlast      ),  // input wire [0 : 0] wea
  .addra        (r_ram_user_addra   ),  // input wire [4 : 0] addra
  .dina         (rs_axis_ruser[63:0]),  // input wire [63 : 0] dina
  .clkb         (i_clk              ),  // input wire clkb
  .enb          (r_ram_user_enb     ),  // input wire enb
  .addrb        (r_ram_user_addrb   ),  // input wire [4 : 0] addrb
  .doutb        (w_ram_user_doutb   )   // output wire [63 : 0] doutb
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

通过4个简单双端口的BRAM实现:

  1. 数据、长度信息(在axis_user当中)、尾端keep以及user数据分别存入对应RAM当中。
  2. 当CRC正确时,各个RAM的地址保持不变,下一帧数据紧随其后被填充进RAM,如果CRC错误,则地址回退到上一次结束的地址,即丢弃刚刚写入的错误数据。
  3. 得到一次CRC正确数据r_recv_flag加1,输出一次数据r_send_flag加1,俩者不相等说明此时RAM里存在数据,拉高r_run
  4. r_run被拉高表示需要开始输出RAM当中的各种信息,并且通过AXIS接口形式传递给上层模块。

该部分核心代码:

//输入数据进如ram,起始地址由r_data_start_addra决定,len和keep同理
always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_ram_data_addra <= 'd0;
    else if(ri_crc_valid_1d && ri_crc_error_1d)
        r_ram_data_addra <= r_data_start_addra;//crc错误则回退到上次起始地址写入新数据
    else if(rs_axis_rvalid)
        r_ram_data_addra <= r_ram_data_addra + 1;
    else
        r_ram_data_addra <= r_ram_data_addra;
end

always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_ram_len_addra <= 'd0;
    else if(ri_crc_valid_1d && ri_crc_error_1d)
        r_ram_len_addra <= r_len_start_addra;//crc错误则回退到上次起始地址写入新数据
    else if(rs_axis_rlast)
        r_ram_len_addra <= r_ram_len_addra + 1;
    else
        r_ram_len_addra <= r_ram_len_addra;
end

always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_ram_keep_addra <= 'd0;
    else if(ri_crc_valid_1d && ri_crc_error_1d)
        r_ram_keep_addra <= r_keep_start_addra;//crc错误则回退到上次起始地址写入新数据
    else if(rs_axis_rlast)
        r_ram_keep_addra <= r_ram_keep_addra + 1;
    else
        r_ram_keep_addra <= r_ram_keep_addra;
end

always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_ram_user_addra <= 'd0;
    else if(ri_crc_valid_1d && ri_crc_error_1d)
        r_ram_user_addra <= r_user_start_addra;//crc错误则回退到上次起始地址写入新数据
    else if(rs_axis_rlast)
        r_ram_user_addra <= r_ram_user_addra + 1;
    else
        r_ram_user_addra <= r_ram_user_addra;
end

// 当数据CRC正确,那么记录此时地址,作为下一帧数据的开始地址,否则保持不变,
// 下一帧数据进来后依旧从上上帧数据结束位置开始写入,即覆盖(丢掉了)CRC错误数据
always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)begin
        r_data_start_addra <= 'd0;
        r_len_start_addra  <= 'd0;
        r_keep_start_addra <= 'd0;
        r_user_start_addra <= 'd0;
    end
    else if(ri_crc_valid && !ri_crc_error)begin
        r_data_start_addra <= r_ram_data_addra;
        r_len_start_addra  <= r_ram_len_addra ;
        r_keep_start_addra <= r_ram_keep_addra;
        r_user_start_addra <= r_ram_user_addra;
    end
    else begin
        r_data_start_addra <= r_data_start_addra;
        r_len_start_addra  <= r_len_start_addra ;
        r_keep_start_addra <= r_keep_start_addra;
        r_user_start_addra <= r_user_start_addra;
    end
end

//得到一次正确数据r_recv_flag加1,输出一次数据r_send_flag加1
//俩者不相等说明此时ram里存在数据,拉高r_run
always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_recv_flag <= 'd0;
    else if(ri_crc_valid && !ri_crc_error)
        r_recv_flag <= r_recv_flag + 'd1;
    else
        r_recv_flag <= r_recv_flag;
end

always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_send_flag <= 'd0;
    else if(rm_axis_rlast)
        r_send_flag <= r_send_flag + 'd1;
    else
        r_send_flag <= r_send_flag;
end

//r_run指示当前正在输出数据
always @(posedge i_clk or posedge i_rst)begin
    if(i_rst)
        r_run <= 'd0;
    else if(rm_axis_rlast)
        r_run <= 'd0;
    else if((r_recv_flag != r_send_flag) && !rm_axis_rvalid)
        r_run <= 'd1;
    else
        r_run <= r_run;
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

三、仿真

黄线时刻CRC发生错误,因此并没有向上层输出AIS数据,并且地址会回退到上一次正确数据输入结束的地址,重新写入新的数据并且进行CRC判断。,
在这里插入图片描述

总结

完整代码参考:https://github.com/shun6-6/Ten_gig_eth_design

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/432894
推荐阅读
相关标签
  

闽ICP备14008679号