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)begin
    if(i_rst)
        r_target_mac <= 'd0;  
    else
        if(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]};
        else
            r_target_mac <= r_target_mac;
end
//获取源MAC
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_source_mac <= 'd0;
    else
        if(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]};
        else
            r_source_mac <= r_source_mac;
end
//获取帧类型
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_type <= 'd0; 
    else
        if(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];
        else
            r_type <= r_type;
end

这里需要了解一下标准以太网帧的帧格式

 在提取MAC字段之前需要去除前导码:56‘h55555555_555555,SFD:8‘hD5。

3、对齐数据

根据开始字符的位置对齐数据

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_data <= 'd0;
    else
        if(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]};
        else
            rm_axis_data <= 'd0;
end

因为使用的AXI-Stream接口,所以需要根据结束字符的位置处理最后一次传输的KEEP信号、Valid信号、Last信号

//keep信号处理!!!!
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_keep <= 'd0;
    else
        if(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;
            endcase
        else 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         
        else
            rm_axis_keep <= rm_axis_keep;
end

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        rm_axis_last <= 1'b0;
    else
        if(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)begin
    if(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;
        else
            rm_axis_valid <= rm_axis_valid;
end

4、CRC校验

在进行字节对齐的过程中,需要进行CRC校验,在此过程中使用的标准以太网的CRC-32校验。

因为校验开始的位置是从目的MAC开始的,因此需要从目的MAC字段对齐数据。

always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_crc_data <= 'd0;
    else
        if(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]};
            else
                r_crc_data <= 'd0;
end

在此过程中需要一个使能信号,指示需要对当前的数据进行CRC校验

//CRC_en控制
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_crc_en <= 'd0;
    else
        if(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_en
                    7           :r_crc_en <= 1'b1;//剩余两个数据,需要再次拉高crc_en
                    default     :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;
                endcase
            else if(r_eof_ff1)
                r_crc_en <= 1'b0;
            else
                r_crc_en <= r_crc_en;
end

最后也需要对CRC数据的最后一次传输的有效数据进行指示,这里加入一个CRC_KEEP信号,指示最后一次传输的有效数据。

//CRC_KEEP处理!!!!
always@(posedge i_clk,posedge i_rst)begin
    if(i_rst)
        r_crc_keep <= 'd0;
    else
        if(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;
            endcase
        else 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         
        else
            r_crc_keep <= r_crc_keep;
end

 5、CRC模块

CRC的生成公式采用的标准以太网的CRC-32的公式,这里可以参考此篇文章。

三、总结

MAC RX模块主要的难点就在于数据KEEP信号的处理以及相应的64bit的 CRC-32模块的实现。KEEP信号要考虑到开始、结束字符的位置,因此需要处理多种情况。而CEC模块的那点主要在于对于多Bytw数据,一次输入的数据可能不是全部有效的,所以也是需要考虑多种情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/583849.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大数据学习笔记14-Hive基础2

一、数据字段类型 数据类型 &#xff1a;LanguageManual Types - Apache Hive - Apache Software Foundation 基本数据类型 数值相关类型 整数 tinyint smallint int bigint 小数 float double decimal 精度最高 日期类型 date 日期 timestamps 日期时间 字符串类型 s…

UE C++ 链表

目录 概要单链表双向链表头插入尾插入中间插入删除查找 小结 概要 链表 简单说明&#xff0c;链表有单链表&#xff0c;双向链表&#xff0c;循环链表(本篇文章以UE c代码说明)。链表的操作&#xff0c;插入&#xff0c;删除&#xff0c;查找。插入&#xff0c;删除效率高&…

练习题(2024/4/29)

在深度优先遍历中&#xff1a;有三个顺序&#xff0c;前中后序遍历 这里前中后&#xff0c;其实指的就是中间节点的遍历顺序&#xff0c;只要记住 前中后序指的就是中间节点的位置就可以了。 如图 1二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前…

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器(Http测试板块)

【项目】仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器&#xff08;Http测试板块&#xff09; 一、使用Http网页界面1、main.cc原码和index.html原码2、运行结果&#xff08;1&#xff09;测试结果1&#xff1a;用index.html内部的代码&#xff08;2&#xf…

《HelloGitHub》第 97 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

win下vscode的vim切换模式的中英文切换

问题描述 在vscode中安装vim插件后&#xff0c;如果insert模式下完成输入后&#xff0c;在中文输入方式下按esc会发生无效输入&#xff0c;需要手动切换到英文。 解决方法 下载完成vscode并在其中配置vim插件下载github—im-select.exe插件&#xff08;注意很多博文中的gitcod…

Microsoft Threat Modeling Tool 使用(二)

主界面 翻译 详细描述 选择了 “SDL TM Knowledge Base (Core)” 模板并打开了一个新的威胁模型。这个界面主要用于绘制数据流图&#xff08;Data Flow Diagram, DFD&#xff09;&#xff0c;它帮助您可视化系统的组成部分和它们之间的交互。以下是界面中各个部分的功能介绍&a…

软件设计师-重点的行为型设计模式

一、命令模式&#xff08;Command&#xff09;&#xff1a; 意图&#xff1a;&#xff08;上午题&#xff09; 将一个请求封装为一个对象&#xff0c;从而使得可以用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 结构…

Django-基础篇

Django是一个开放源代码的Web应用框架&#xff0c;由Python语言编写。它遵循MVC&#xff08;Model-View-Controller&#xff09;的软件设计模式&#xff0c;使开发者能够以高效、可扩展和安全的方式构建Web应用程序。 Django具有以下特点和优势&#xff1a; 强大的功能&#x…

[技术小技巧] 可视化分析:在jupyter中使用d3可视化树形结构

首先在python中定义一个字符串&#xff0c;记录d3.js绘制属性图的js脚本代码模版。其中{{data}}就是将来要被替换的内容。 d3_code_template """ // 创建树状结构数据 var treeData {{data}};// 创建d3树布局 var margin { top: 20, right: 90, bottom: 30,…

行业推荐:数据防泄漏软件首先解决方案

随着信息时代的快速发展&#xff0c;数据安全已成为企业经营的关键之一。然而&#xff0c;数据泄漏事件时有发生&#xff0c;不仅可能导致巨大的经济损失&#xff0c;更会损害企业的声誉和客户信任。 为了帮助企业有效地保护数据安全&#xff0c;Ping32 数据防泄漏系统应运而生…

【跟我学RISC-V】认识RISC-V指令集并搭建实验环境

写在前面 现在计算机的体系架构正是发展得如火如荼的时候&#xff0c;占领桌面端市场的x86架构、占领移动端市场的arm架构、在服务器市场仍有一定地位的mips架构、国产自研的指令集loongarch架构、还有我现在要讲到的新型开源开放的RISC-V指令集架构。 我先说一说我的学习经历…

Facebook的语言学:社交媒体如何影响我们的沟通方式

1. 引言 社交媒体已经成为人们日常生活中不可或缺的一部分&#xff0c;而Facebook作为其中最具影响力的平台之一&#xff0c;不仅改变了人们之间的社交方式&#xff0c;也对我们的语言学产生了深远的影响。本文将深入探讨Facebook的语言学特点&#xff0c;以及它如何塑造和改变…

【C++题解】1608. 三位数运算

问题&#xff1a;1608. 三位数运算 类型&#xff1a;基本运算、拆位求解 题目描述&#xff1a; 小丽在编程课上学会了拆位运算&#xff0c;她已经可以拆出一个三位整数的百位、十位和个位了&#xff0c;她想知道这个整数的&#xff08;百位 十位&#xff09; / &#xff08;…

Web3与智能合约:科技革新下的新金融时代

在当今数字化时代&#xff0c;Web3和智能合约正在共同塑造着金融领域的未来。Web3作为下一代互联网的重要组成部分&#xff0c;以其去中心化、安全性和透明性为核心特点&#xff0c;正推动着金融行业向着数字化和去中心化的方向发展。而智能合约作为Web3技术的关键应用之一&…

虚拟机网络桥接模式无法通信,获取到的ip为169.254.X.X

原因&#xff1a;VMware自动选择的网卡可能不对 解决&#xff1a;编辑-虚拟网络编辑器-更改桥接模式-选择宿主机物理网卡&#xff0c;断开虚拟机网络连接后重新连接即可

Docker(Docker的安装和介绍,常用命令,镜像制作,服务编排,docker私服)

目录 一、简介 1. docker简介 1 什么是docker 2 容器和虚拟机对比 2. 安装docker 1 docker相关概念 2 安装docker 1 安装docker 2 设置注册中心(仓库) 3. 小结 二、常用命令【重点】 1. 服务管理 2. 镜像管理 1 语法说明 2 使用练习 3. 容器管理 1 容器介绍 2…

2024.4.25 LoadRunner 测试工具详解 —— Controller Analysis

目录 Controller 的使用 创建场景 Controller 快捷方式创建场景 VUG 针对写好脚本创建场景 场景设计 设计初始化 设计启动机制 设计性能测试脚本的执行时间 设计虚拟用户退出机制 场景运行 添加监控指标至图标格区域 Analysis 的使用 汇总报告 测试报表 吞吐量图 …

Dockerfile实战---构建SSH、Tomcat、MySQL、Nginx镜像

目录 引言 一、安装docker程序 二、构建SSH镜像 1.创建镜像 2.基于sshd镜像创建容器 三、构建tomcat镜像 1.创建镜像 2.基于tomcat镜像创建容器 四、构建MySQL镜像 1.创建镜像 2.基于mysqld镜像创建容器 五、构建nginx镜像 1.创建镜像 2.基于nginx镜像创建容器 引…

用Stream流方式合并两个list集合(部分对象属性重合)

一、合并出共有部分 package com.xu.demo.test;import java.util.Arrays; import java.util.List; import java.util.stream.Collectors;public class ListMergeTest1 {public static void main(String[] args) {List<User> list1 Arrays.asList(new User(1, "Alic…