10G MAC层设计系列-(3)CRC Process 模块

一、前言

前面已经讲述了在Xilinx 10G PCS/PMA IP核的基础上设计的PHY层,已经xgmii接口的MAC_RX模块,本节主要描述MAC_RX之后的CRC_Process模块。

CRC_Prcess的主要作用就是利用RAM地址"返回初始状态"的方式将crc错误的帧丢掉,并将正确的传递到上级。

二、模块设计

首先,将数据帧、最后一次传输的KEEP信号存入RAM

BRAM_DATA_64X512 u_BRAM_DATA_64X512 (
  .clka     (i_clk                  ),    // input wire clka
  .wea      (rs_axis_valid          ),      // input wire [0 : 0] wea
  .addra    (r_bram_wdata_addr      ),  // input wire [8 : 0] addra
  .dina     (rs_axis_data           ),    // input wire [63 : 0] dina
  .clkb     (i_clk                  ),    // input wire clkb
  .enb      (r_bram_data_rden       ),      // input wire enb
  .addrb    (r_bram_rdata_addr      ),  // input wire [8 : 0] addrb
  .doutb    (w_bram_data_out        )  // output wire [63 : 0] doutb
);

//将每一帧的最后一次传输的KEEP信号存入到RAM
BRAM_KEEP_8X128 your_instance_name (
  .clka     (i_clk                  ),    // input wire clka
  .wea      (rs_axis_last           ),      // input wire [0 : 0] wea
  .addra    (r_bram_wkeep_addr      ),  // input wire [6 : 0] addra
  .dina     (rs_axis_keep           ),    // input wire [7 : 0] dina
  .clkb     (i_clk                  ),    // input wire clkb
  .enb      (r_bram_keep_rden       ),      // input wire enb
  .addrb    (r_bram_rkeep_addr      ),  // input wire [6 : 0] addrb
  .doutb    (w_bram_rkeep           )  // output wire [7 : 0] doutb
);

在此过程中存在一个初始化的地址信号,只有检测到CRC校验正确之后才会更新初始的地址信号。

//写数据初始化地址,当CRC校验正确的时候才会改变
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_init_wdata_addr <= 'd0;
    else 
        if(w_crc_correct)
            r_init_wdata_addr <= r_bram_wdata_addr + 1;
        else
            r_init_wdata_addr <= r_init_wdata_addr;
end
//写数据地址
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_wdata_addr <= 'd0;
    else
        if(s_axis_valid && !rs_axis_valid)
            r_bram_wdata_addr <= r_init_wdata_addr;
        else if(rs_axis_valid && !rs_axis_last)
            r_bram_wdata_addr <= r_bram_wdata_addr + 1;
        else
            r_bram_wdata_addr <= r_bram_wdata_addr;
end
//写KEEP信号的初始化地址,当CRC校验正确的时候才会改变
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_init_wkeep_addr <= 'd0;
    else
        if(w_crc_correct)
            r_init_wkeep_addr <= r_bram_wkeep_addr + 1;
        else
            r_init_wkeep_addr <= r_init_wkeep_addr;        
end
//写KEEP信号地址
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_wkeep_addr <= 'd0;
    else
        if(s_axis_last)
            r_bram_wkeep_addr <= r_init_wkeep_addr;
        else
            r_bram_wkeep_addr <= r_bram_wkeep_addr;
end

最后的帧长等信息只有在CRC校验正确之后存入FIFO,用FIFO的empty信号判断RAM中是否有正确的数据。

FIFO_USER_INFO_80X128 u_FIFO_USER_INFO_80X128 (
  .clk      (i_clk                  ),      // input wire clk
  .srst     (i_rst                  ),    // input wire srst
  .din      (r_user_info            ),      // input wire [79 : 0] din
  .wr_en    (w_crc_correct          ),  // input wire wr_en
  .rd_en    (r_fifo_user_info_rden  ),  // input wire rd_en
  .dout     (w_fifo_user_out        ),    // output wire [79 : 0] dout
  .full     (w_fifo_user_info_full  ),    // output wire full
  .empty    (w_fifo_user_info_empty )  // output wire empty
);

在读数据的过程中,便是根据FIFO是否为空判断是否有有效数据,之后读出FIFO帧长等信息,根据帧长去读取RAM中的数据。

//读取USER_INFO FIFO中的信息
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_user_info_rden <= 'd0;
    else
        if(!w_fifo_user_info_empty && !r_fifo_rden_lock)
            r_fifo_user_info_rden <= 1'b1;
        else
            r_fifo_user_info_rden <= 1'b0;
end
//锁存信号
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_fifo_rden_lock <= 'd0;
    else 
        if(!w_fifo_user_info_empty)
            r_fifo_rden_lock <= 1'b1;
        else if(rm_axis_last)
            r_fifo_rden_lock <= 1'b0;
        else
            r_fifo_rden_lock <= r_fifo_rden_lock; 
end
//读USER INFO
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_user <= 'd0;
    else
        rm_axis_user <= w_fifo_user_out;
end

//读数据的使能慢读USER INFO的使能一拍
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_data_rden <= 'd0;
    else
        if(r_fifo_user_info_rden)
            r_bram_data_rden <= 1'b1;
        else if(r_data_cnt == w_fifo_user_out[79:64])
            r_bram_data_rden <= 'd0;
        else
            r_bram_data_rden <= r_bram_data_rden;
end
//读数据地址
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_rdata_addr <= 'd0;
    else
        if(r_fifo_user_info_rden)
            r_bram_rdata_addr <= r_init_rdata_addr;
        else if((r_data_cnt < w_fifo_user_out[79:64]) && r_data_cnt)
            r_bram_rdata_addr <= r_bram_rdata_addr + 1;
        else
            r_bram_rdata_addr <= r_bram_rdata_addr ;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_init_rdata_addr <= 'd0;
    else    
        if((r_data_cnt == w_fifo_user_out[79:64]) && r_bram_data_rden)
            r_init_rdata_addr <= r_bram_rdata_addr + 1;
        else
            r_init_rdata_addr <= r_init_rdata_addr;
end


always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_data_rden_ff1 <= 'd0; 
    else
        r_bram_data_rden_ff1 <= r_bram_data_rden;
end
//读keep使能
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_keep_rden <= 1'b0;
    else
        if(r_data_cnt == w_fifo_user_out[79:64] -1)
            r_bram_keep_rden <= 1'b1;
        else 
            r_bram_keep_rden <= 1'b0;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_bram_rkeep_addr <= 'd0;
    else    
        if(r_data_cnt == w_fifo_user_out[79:64] -1)
            r_bram_rkeep_addr <= r_init_rkeep_addr;
        else 
            r_bram_rkeep_addr <= r_bram_rkeep_addr;        
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_init_rkeep_addr <= 'd0;
    else    
        if((r_data_cnt == w_fifo_user_out[79:64]) && r_data_cnt)
            r_init_rkeep_addr <= r_bram_rkeep_addr + 1;
        else 
            r_init_rkeep_addr <= r_init_rkeep_addr;        
end

//寻找上升沿
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_data_rden_pos <= 'd0; 
    else
        if(r_bram_data_rden && !r_bram_data_rden_ff1)
            r_data_rden_pos <= 1'b1;
        else
            r_data_rden_pos <= 1'b0;
end
//寻找下降沿
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_data_rden_nge <= 'd0; 
    else
        if(!r_bram_data_rden && r_bram_data_rden_ff1)
            r_data_rden_nge <= 1'b1;
        else
            r_data_rden_nge <= 1'b0;
end
//读数据计数
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_data_cnt <= 'd0;
    else
        if(r_fifo_user_info_rden || r_bram_data_rden)
            r_data_cnt <= r_data_cnt + 1;
        else
            r_data_cnt <= 'd0;
end
//数据转换成AXIS接口输出
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_data <= 'd0;
    else
        rm_axis_data <= w_bram_data_out;
end
//Valid信号
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_valid <= 1'b0;
    else
        if(rm_axis_last)
            rm_axis_valid <= 1'b0;
        else if(r_data_rden_pos)
            rm_axis_valid <= 1'b1;
        else
            rm_axis_valid <= rm_axis_valid;
end
//Last信号
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_last <= 'd0;
    else
        if(!r_bram_data_rden && r_bram_data_rden_ff1)
            rm_axis_last <= 1'b1;
        else
            rm_axis_last <= 1'b0;
end
//KEEP信号
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_keep <= 'd0;
    else
        if(w_fifo_user_out[79:64] == 1 && r_data_rden_pos)
            rm_axis_keep <= w_bram_rkeep;
        else if(w_fifo_user_out[79:64] > 1 && r_data_rden_pos)
            rm_axis_keep <= 8'hff;
        else if(!r_bram_data_rden && r_bram_data_rden_ff1)
            rm_axis_keep <= w_bram_rkeep;
        else
            rm_axis_keep <= rm_axis_keep;
end

三、总结

CRC Process模块比较简单,就是实现丢掉CRC错误帧的功能

相关推荐
DS小龙哥7 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师17 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战18 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发