心跳包的发送模块
发送模块的工作时钟也为125MHz,组帧的数据流如下:

首先产生没有校验位数据的帧,将其缓存到一个buffer,一边缓存一边算它的ip和udp校验和,算完了在把数据读出来,读到响应的位置就填计算结果进去,然后在添加crc的帧尾发送出去
心跳包的产生
自定义心跳包,数据部分为64byte的0。产生计数器,隔1s产生一个标志信号,标志信号为1时,开始组帧,组帧用case+cnt来组帧,如果觉得case太长,就打断分成两个部分来写,时序会好一些
64byte的0填在用户数据部分,在组建心跳包的时候,ip检验和和udp校验和字段先不计算,先填0,然后把组建好的包传到校验和计算模块
校验和计算模块
ip的校验和
先来的ip头行ip的校验和计算,即计算 Ip_check_sum 计算就是把 IP 首部 20byte 按 2byte 即 16bit 分开分别相加,累加结束后,将累加结果存储到的udp_sum中,其位宽为32bit(为了实现高16bit+低16bit),如果得出的结果的高16bit有数(得出来的相加结果如果大于 16’hffff) , 那么就将udp_sum 32位的寄存器拆分为高16bit与低16bit,然后高16bit与低16bit进行相加(即将超出 16’hffff 的部分与相加结果的低16位相加),直到最终结果小于 16’hffff 为止(udp_sum 32位的寄存器的高16bit全为0)。最后把最终结果取反作为ip_checksum, ip_checksum 的高字节在前,低字节在后,将之前填充在千兆以太网协议中的0进行替换即可.
udp的校验和
udp除了对udp头udp数据进行校验,还要对ip伪头部进行校验,校验规则和ip的一样
校验结果的填充
ip校验的结果比udp校验结果出来的早,udp校验结果出来就启动ram读数据,并根据读出数据的具体的位置(读出地址来判断)将校验结果填充进去。
CRC 发送校验模块
CRC 进行校验时不对千兆以太网帧头计算,即7个0x55和1个0xd5不参与CRC校验,将推导出的32bit的crc校验码分成4个字节填充到 checksum_ctrl 模块传输来的没有CRC校验的千兆以太网UDP协议包后面,即可组成完整的千兆以太网UDP包。(就是ba)
遵循以下3个原则:
- CRC 计算模块初始值为 0xffffffff
- CRC 计算结果需要高低位对调, 因为我们输入是先从高位输入计算的 CRC,
所以高低位要需要对调。 - CRC 最后结果需要取反, 对调完成的代码需要取反操作才能正确。
oddr
iddr是将数据从双沿变成单沿,把双沿的使能信号和纠错信号变成单沿的使能信号,纠错信号就不管了。
oddr是把数据从单沿变成双沿传出去,并且要把时钟传出去,传出去的时钟相移一下,能让更好的传到下一个模块的时钟和数据对齐。具体调相多少,可以用wireshark抓一下,验证一下
先上板
ila抓一下心跳包出来后的最后4个字节,看看对不对
是对的,然后用wireshark抓一下包
ila抓包是对的,那么就是oddr出错了,估计是相位调错了,我现在调的90度,改成45度看看,改一下
先把ip和udp的checksum勾上,设置改下
发现还是有错误,把相位改成0度康康
可以看到收到的NTP包(也是udp的一种)时间,数据什么的都对了
双击一个包看看ip的校验和和udp的校验和都是正确的,时间也是每隔一秒发一个包
所以最佳的相位肯定在0到45之间,可以去找一下具体值是多少