10G MAC层设计系列-(2)MAC RX模块
一、概述
MAC RX模块的需要进行解码、对齐、CRC校验。
因为在空闲的时候10G PCS/PMA会一直向外吐空闲符(x07)所以需要根据开始符、结束符将有效数据从码流中截取,也就是解码。
因为开始字符的所在位置有两种形式,而结束字符的位置不确定,所以需要根据开始字符、结束字符的位置将数据进行对齐。
在将数据对齐的同时,还需要将获取到的有效数据进行CRC校验,这里就需要设计64bit CRC-32校验。

二、具体实现
1、检测开始、结束字符的位置
assign w_sof = (ri_xgmii_rxc[7] && ri_xgmii_rxd[63:56] == 8'hFB) ||(ri_xgmii_rxc[3] && ri_xgmii_rxd[31:24] == 8'hFB) ;
assign w_sof_local = (ri_xgmii_rxc[7] && ri_xgmii_rxd[63:56] == 8'hFB) ? 0: 1;
assign w_eof = (ri_xgmii_rxc[0] && ri_xgmii_rxd[7: 0] == 8'hFE) ||(ri_xgmii_rxc[1] && ri_xgmii_rxd[15: 8] == 8'hFE) ||(ri_xgmii_rxc[2] && ri_xgmii_rxd[23:16] == 8'hFE) ||(ri_xgmii_rxc[3] && ri_xgmii_rxd[31:24] == 8'hFE) ||(ri_xgmii_rxc[4] && ri_xgmii_rxd[39:32] == 8'hFE) ||(ri_xgmii_rxc[5] && ri_xgmii_rxd[47:40] == 8'hFE) ||(ri_xgmii_rxc[6] && ri_xgmii_rxd[55:48] == 8'hFE) ||(ri_xgmii_rxc[7] && ri_xgmii_rxd[63:56] == 8'hFE) ;assign w_eof_local = (ri_xgmii_rxc[1] && ri_xgmii_rxd[15: 8] == 8'hFE) ? 6 :(ri_xgmii_rxc[2] && ri_xgmii_rxd[23:16] == 8'hFE) ? 5 :(ri_xgmii_rxc[3] && ri_xgmii_rxd[31:24] == 8'hFE) ? 4 :(ri_xgmii_rxc[4] && ri_xgmii_rxd[39:32] == 8'hFE) ? 3 :(ri_xgmii_rxc[5] && ri_xgmii_rxd[47:40] == 8'hFE) ? 2 :(ri_xgmii_rxc[6] && ri_xgmii_rxd[55:48] == 8'hFE) ? 1 :(ri_xgmii_rxc[7] && ri_xgmii_rxd[63:56] == 8'hFE) ? 0 :7;
2、获取目的MAC、源MAC、帧类型
//获取目的MAC
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_target_mac <= 'd0; elseif(r_sof_local == 0 && r_cnt == 1)r_target_mac <= ri_xgmii_rxd_ff1[55:8];else if(r_sof_local == 1 && r_cnt == 1)r_target_mac <= {ri_xgmii_rxd_ff1[23:0],ri_xgmii_rxd[63:40]};elser_target_mac <= r_target_mac;
end
//获取源MAC
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_source_mac <= 'd0;elseif(r_sof_local == 0 && r_cnt == 1)r_source_mac <= {ri_xgmii_rxd_ff1[7:0],ri_xgmii_rxd[63:24]};else if(r_sof_local == 1 && r_cnt == 2)r_source_mac <= {ri_xgmii_rxd_ff1[39:0],ri_xgmii_rxd[63:56]};elser_source_mac <= r_source_mac;
end
//获取帧类型
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_type <= 'd0; elseif(r_sof_local == 0 && r_cnt == 2)r_type <= ri_xgmii_rxd_ff1[23:8];else if(r_sof_local == 1 && r_cnt == 3)r_type <= ri_xgmii_rxd_ff1[55:40];elser_type <= r_type;
end
这里需要了解一下标准以太网帧的帧格式
在提取MAC字段之前需要去除前导码:56‘h55555555_555555,SFD:8‘hD5。
3、对齐数据
根据开始字符的位置对齐数据
always@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_data <= 'd0;elseif(r_sof_local == 0 && r_run)rm_axis_data <= {ri_xgmii_rxd_ff1[7:0],ri_xgmii_rxd[63:8]};else if(r_sof_local == 1 && r_run)rm_axis_data <= {ri_xgmii_rxd_ff1[39:0],ri_xgmii_rxd[63:40]};elserm_axis_data <= 'd0;
end
因为使用的AXI-Stream接口,所以需要根据结束字符的位置处理最后一次传输的KEEP信号、Valid信号、Last信号
//keep信号处理!!!!
always@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_keep <= 'd0;elseif(r_run && !r_run_ff1)rm_axis_keep <= 8'b1111_1111;else if(rm_axis_last)rm_axis_keep <= 'd0;else if(r_sof_local == 0 && w_eof)case(w_eof_local)0 : rm_axis_keep <= 8'b1000_0000;1 : rm_axis_keep <= 8'b1100_0000;2 : rm_axis_keep <= 8'b1110_0000;3 : rm_axis_keep <= 8'b1111_0000;4 : rm_axis_keep <= 8'b1111_1000;5 : rm_axis_keep <= 8'b1111_1100;6 : rm_axis_keep <= 8'b1111_1110;7 : rm_axis_keep <= 8'b1111_1111;default : rm_axis_keep <= 8'b1111_1111;endcaseelse if(r_sof_local == 1 && w_eof && w_eof_local <= 3)case(w_eof_local)0 : rm_axis_keep <= 8'b1111_1000;1 : rm_axis_keep <= 8'b1111_1100;2 : rm_axis_keep <= 8'b1111_1110;3 : rm_axis_keep <= 8'b1111_1111;4 : rm_axis_keep <= 8'b1000_0000;5 : rm_axis_keep <= 8'b1100_0000;6 : rm_axis_keep <= 8'b1110_0000;7 : rm_axis_keep <= 8'b1111_0000;default : rm_axis_keep <= 8'b1111_1111;endcase else if(r_sof_local == 1 && r_eof && r_eof_local >= 4)case(r_eof_local)0 : rm_axis_keep <= 8'b1111_1000;1 : rm_axis_keep <= 8'b1111_1100;2 : rm_axis_keep <= 8'b1111_1110;3 : rm_axis_keep <= 8'b1111_1111;4 : rm_axis_keep <= 8'b1000_0000;5 : rm_axis_keep <= 8'b1100_0000;6 : rm_axis_keep <= 8'b1110_0000;7 : rm_axis_keep <= 8'b1111_0000;default : rm_axis_keep <= 8'b1111_1111;endcase elserm_axis_keep <= rm_axis_keep;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_last <= 1'b0;elseif(r_sof_local == 0 && w_eof)rm_axis_last <= 1'b1;else if(r_sof_local == 1 && w_eof && w_eof_local <= 3)rm_axis_last <= 1'b1;else if(r_sof_local == 1 && r_eof && r_eof_local >= 4)rm_axis_last <= 1'b1;else rm_axis_last <= 1'b0;end
///valid信号,用r_run的上升沿判断数据开始
always@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_valid <= 1'b0;else if(rm_axis_last)rm_axis_valid <= 1'b0;else if(r_run && !r_run_ff1)rm_axis_valid <= 1'b1;elserm_axis_valid <= rm_axis_valid;
end
4、CRC校验
在进行字节对齐的过程中,需要进行CRC校验,在此过程中使用的标准以太网的CRC-32校验。
因为校验开始的位置是从目的MAC开始的,因此需要从目的MAC字段对齐数据。
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_crc_data <= 'd0;elseif(r_sof_local == 0)if(r_sof_ff2)r_crc_data <= {ri_xgmii_rxd_ff2[55:0],ri_xgmii_rxd_ff1[63:56]};else if(r_eof || r_eof_ff1)r_crc_data <= {ri_xgmii_rxd_ff2[55:0],ri_xgmii_rxd_ff1[63:56]};else if(r_run_ff1)r_crc_data <= {ri_xgmii_rxd_ff2[55:0],ri_xgmii_rxd_ff1[63:56]};else r_crc_data <= 'd0; else if(r_sof_ff2)r_crc_data <= {ri_xgmii_rxd_ff2[23:0],ri_xgmii_rxd_ff1[63:24]};else if(r_eof || r_eof_ff1)r_crc_data <= {ri_xgmii_rxd_ff2[23:0],ri_xgmii_rxd_ff1[63:24]};else if(r_run)r_crc_data <= {ri_xgmii_rxd_ff2[23:0],ri_xgmii_rxd_ff1[63:24]};elser_crc_data <= 'd0;
end
在此过程中需要一个使能信号,指示需要对当前的数据进行CRC校验
//CRC_en控制
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_crc_en <= 'd0;elseif(r_sof_local == 0)if(r_sof_ff2)r_crc_en <= 1'b1;else if(r_eof)r_crc_en <= 1'b1;else if(r_eof_ff1)case(r_eof_local)0 :r_crc_en <= 1'b0;1 :r_crc_en <= 1'b0;2 :r_crc_en <= 1'b0;3 :r_crc_en <= 1'b0;4 :r_crc_en <= 1'b0;5 :r_crc_en <= 1'b0;6 :r_crc_en <= 1'b1;//剩余一个数据,需要再次拉高crc_en7 :r_crc_en <= 1'b1;//剩余两个数据,需要再次拉高crc_endefault :r_crc_en <= 1'b0;endcase else if(r_eof_ff2)r_crc_en <= 1'b0;else r_crc_en <= r_crc_en; else if(r_sof_ff2)r_crc_en <= 1'b1;else if(w_eof)r_crc_en <= 1'b1; else if(r_eof)case(r_eof_local)0 :r_crc_en <= 1'b0;//1 :r_crc_en <= 1'b0;2 :r_crc_en <= 1'b1;3 :r_crc_en <= 1'b1;4 :r_crc_en <= 1'b1;5 :r_crc_en <= 1'b1;6 :r_crc_en <= 1'b1;7 :r_crc_en <= 1'b1;default :r_crc_en <= 1'b0;endcaseelse if(r_eof_ff1)r_crc_en <= 1'b0;elser_crc_en <= r_crc_en;
end
最后也需要对CRC数据的最后一次传输的有效数据进行指示,这里加入一个CRC_KEEP信号,指示最后一次传输的有效数据。
//CRC_KEEP处理!!!!
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_crc_keep <= 'd0;elseif(r_sof_ff2)r_crc_keep <= 8'b1111_1111;// else if((!r_crc_en && r_crc_en_ff1) || r_eof_ff2)// r_crc_keep <= 8'b0000_0000;else if(r_sof_local == 0 && r_eof)case(r_eof_local)0 : r_crc_keep <= 8'b1110_0000;1 : r_crc_keep <= 8'b1111_0000;2 : r_crc_keep <= 8'b1111_1000;3 : r_crc_keep <= 8'b1111_1100;4 : r_crc_keep <= 8'b1111_1110;5 : r_crc_keep <= 8'b1111_1111;default : r_crc_keep <= 8'b1111_1111;endcaseelse if(r_sof_local == 0 && r_eof_ff1)case(r_eof_local)6 : r_crc_keep <= 8'b1000_0000;7 : r_crc_keep <= 8'b1100_0000;default : r_crc_keep <= r_crc_keep;endcase else if(r_sof_local == 1 && w_eof)case(w_eof_local)0 : r_crc_keep <= 8'b1111_1110;1 : r_crc_keep <= 8'b1111_1111;2 : r_crc_keep <= 8'b1111_1111;3 : r_crc_keep <= 8'b1111_1111;4 : r_crc_keep <= 8'b1111_1111;5 : r_crc_keep <= 8'b1111_1111;6 : r_crc_keep <= 8'b1111_1111;7 : r_crc_keep <= 8'b1111_1111;default : r_crc_keep <= 8'b1111_1111;endcase else if(r_sof_local == 1 && r_eof)case(r_eof_local)// 0 : r_crc_keep <= 8'b1111_1000;// 1 : r_crc_keep <= 8'b1111_1100;2 : r_crc_keep <= 8'b1000_0000;3 : r_crc_keep <= 8'b1100_0000;4 : r_crc_keep <= 8'b1110_0000;5 : r_crc_keep <= 8'b1111_0000;6 : r_crc_keep <= 8'b1111_1000;7 : r_crc_keep <= 8'b1111_1100;default : r_crc_keep <= r_crc_keep;endcase // else if(r_sof_local == 1 && r_eof && r_eof_local >= 4)// case(r_eof_local)// 0 : r_crc_keep <= 8'b1111_1000;// 1 : r_crc_keep <= 8'b1111_1100;// 2 : r_crc_keep <= 8'b1111_1110;// 3 : r_crc_keep <= 8'b1111_1111;// 4 : r_crc_keep <= 8'b1000_0000;// 5 : r_crc_keep <= 8'b1100_0000;// 6 : r_crc_keep <= 8'b1110_0000;// 7 : r_crc_keep <= 8'b1111_0000;// default : r_crc_keep <= 8'b1111_1111;// endcase elser_crc_keep <= r_crc_keep;
end
5、CRC模块
CRC的生成公式采用的标准以太网的CRC-32的公式,这里可以参考此篇文章。
三、总结
MAC RX模块主要的难点就在于数据KEEP信号的处理以及相应的64bit的 CRC-32模块的实现。KEEP信号要考虑到开始、结束字符的位置,因此需要处理多种情况。而CEC模块的那点主要在于对于多Bytw数据,一次输入的数据可能不是全部有效的,所以也是需要考虑多种情况。
相关文章:

10G MAC层设计系列-(2)MAC RX模块
一、概述 MAC RX模块的需要进行解码、对齐、CRC校验。 因为在空闲的时候10G PCS/PMA会一直向外吐空闲符(x07)所以需要根据开始符、结束符将有效数据从码流中截取,也就是解码。 因为开始字符的所在位置有两种形式,而结束字符的位…...

解码Starknet Verifier:深入逆向工程之旅
1. 引言 Sandstorm为: 能提交独立proof给StarkWare的Ethereum Verifier,的首个开源的STARK prover。 开源代码见: https://github.com/andrewmilson/sandstorm(Rust) L2Beat 提供了以太坊上Starknet的合约架构图&…...

【C++语言】类和对象--默认成员函数 (中)
文章目录 前言类的六个默认成员函数:1. 构造函数概念特性做了什么?易错注意:显式定义和默认构造函数 2. 析构函数概念特征做了什么?注意事项: 3.拷贝构造函数概念特征做了什么?注意事项: 4.赋值运算符重载…...
前端递归常见应用
概览 在 JavaScript 中,递归是一种编程技术,指的是函数直接或间接调用自身的过程。 递归通常用于解决可以分解为相同子问题的问题。通过不断地将问题分解成更小的、相似的子问题,直到达到某种基本情况(不再需要进一步递归的简单情…...
AI工具如何改变我们的工作与生活
AI工具在当今社会中扮演着越来越重要的角色,它们已经开始改变着我们的工作方式和生活方式。在接下来的2000字篇幅中,我将详细探讨AI工具如何影响我们的工作和生活。 AI工具在工作中的影响: 自动化和智能化生产流程: AI工具可以通…...

深入了解C/C++的内存区域划分
🔥个人主页:北辰水墨 🔥专栏:C学习仓 本节我们来讲解C/C的内存区域划分,文末会附加一道题目来检验成果(有参考答案) 一、大体有哪些区域?分别存放什么变量开辟的空间? …...

C++构造函数和析构函数的调用顺序
一般情况下,调用析构函数的次序正好与调用构造函数的次序相反,也就是最先被调用的构造函数,其对应的析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。 当然对象的构造函数和析构函数调用时机和…...

智能家居1 -- 实现语音模块
项目整体框架: 监听线程4: 1. 语音监听线程:用于监听语音指令, 当有语音指令过来后, 通过消息队列的方式给消息处理线程发送指令 2. 网络监听线程:用于监听网络指令,当有网络指令过来后, 通过消息队列的方…...
Leetcode 3139. Minimum Cost to Equalize Array
Leetcode 3139. Minimum Cost to Equalize Array 1. 解题思路2. 代码实现 题目链接:3139. Minimum Cost to Equalize Array 1. 解题思路 这一题是一道hard的题目,而且看了一下答出率低的离谱,就一开始被吓到了,不过实际做了一下…...
【element-ui】el-table横向滚动后,通过is-scrolling-left获取滚动高度失效的问题
el-table横向滚动后,通过is-scrolling-left获取滚动高度失效的问题 需求 现在有一个需求,需要监听el-table的纵向滚动,当滚动高度达到特定值时进行一些操作。 代码如下: methods:{throttledHandleScroll() {// 如果已经有定时器…...
JAVA中的日期
获取当前的日期 LocalDate LocalDate today LocalDate.now();System.out.println("今天是:"today);//今天是:2024-05-06String format today.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));System.out.println("今天是:"…...

一起了解开源自定义表单的优势表现
随着社会的进步和科技的发展,越来越多的中小企业希望采用更为先进的软件平台,助力企业实现高效率的流程化管理。低代码技术平台、开源自定义表单已经慢慢走入大众视野,成为一款灵活、高效的数字化转型工具。流辰信息专注于低代码技术平台的研…...

体育老师工资高吗,奖金有吗
教师的薪资水平与多种因素相关,包括教育经验、工作地点、学校类型以及个人的教学成果等。在讨论体育教师的工资问题时,不能仅仅关注数字,更应了解教育价值和个人发展。 初中体育教师的工资水平受多种因素影响。根据网络统计的数据,…...

Linux驱动开发——(十一)INPUT子系统
目录 一、input子系统简介 二、input驱动API 2.1 input字符设备 2.2 input_dev结构体 2.3 上报输入事件 2.4 input_event结构体 三、代码 3.1 驱动代码 3.2 测试代码 四、平台测试 一、input子系统简介 input子系统是管理输入的子系统,和pinctrl、gpio子…...

大数据毕业设计Python+Django旅游景点评论数据采集分析可视化系统 NLP情感分析 LDA主题分析 bayes分类 旅游爬虫 旅游景点评论爬虫 机器学习 深度学习 人工智能 计算机毕业设计
毕业论文(设计)开题报告 学生姓名 学 号 所在学院 信息工程学院 专 业 指导教师姓名 指导教师职称 工程师 助教 指导教师单位 论文(设计)题目 基于朴素贝叶斯算法旅游景点线上评价情感分析 开 题 报 告…...

FSNotes for Mac v6.7.1中文激活版:强大的笔记管理工具
FSNotes for Mac是一款功能强大的文本处理与笔记管理工具,为Mac用户提供了一个直观、高效的笔记记录和整理平台。 FSNotes for Mac v6.7.1中文激活版下载 FSNotes支持Markdown语法,使用户能够轻松设置笔记格式并添加链接、图像等元素,实现笔记…...
课程34:Windows Docker部署.Net Core项目
这里写目录标题 🚀前言一、安装Docker Desktop1.1 官网下载Docker1.2 安装Docker1.2.1 选择配置,默认都勾选1.2.2 安装中1.2.3 安装成功1.2.4 启动1.2.5 启动成功二、.Net Core 项目发布与部署2.1 修改Dockerfile文件2.2 Web项目发布2.3 修改配置2.3.1 修改dockerfile<...

分布式与一致性协议之ZAB协议(四)
ZAB协议 ZooKeeper是如何选举领导者的。 首先我们来看看ZooKeeper是如何实现成员身份的? 在ZooKeeper中,成员状态是在QuorumPeer.java中实现的,为枚举型变量 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING }其实&…...

在M1芯片安装鸿蒙闪退解决方法
在M1芯片安装鸿蒙闪退解决方法 前言下载鸿蒙系统安装完成后,在M1 Macos14上打开闪退解决办法接下来就是按照提示一步一步安装。 前言 重新安装macos系统后,再次下载鸿蒙开发软件,竟然发现打不开。 下载鸿蒙系统 下载地址:http…...

Linux基础-socket详解、TCP/UDP
文章目录 一、Socket 介绍二、Socket 通信模型三、Socket 常用函数1 创建套接字2 绑定套接字3、监听连接4、接受连接5、接收和发送数据接收数据发送数据 6、关闭套接字 四、Socket编程试验1、源码server.cclient.c 2、编译:3、执行结果 五、补充TCP和UDP协议的Socke…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
面试高频问题
文章目录 🚀 消息队列核心技术揭秘:从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"?性能背后的秘密1.1 顺序写入与零拷贝:性能的双引擎1.2 分区并行:数据的"八车道高速公路"1.3 页缓存与批量处理…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...