从零开始 verilog 以太网交换机(二)MAC接收控制器的设计与实现

news2024/11/14 20:23:11

从零开始 verilog 以太网交换机(二)MAC接收控制器的设计与实现



🔈声明:
😃博主主页:王_嘻嘻的CSDN主页
🧨 从零开始 verilog 以太网交换机系列专栏:点击这里
🔑未经作者允许,禁止转载,侵权必删
🚩关注本专题的朋友们可以收获一个经典交换机设计的全流程,包括设计与验证(FPGA);以太网MAC的基础知识。新手朋友们还将获得一个具有竞争力的项目经历,后续整个工程和代码下载链接也都会放在csdn和公众号内

  本章进行MAC控制器的设计与实现,共分为两个部分:接收控制器和发送控制器。整体架构可以参考:从零开始 verilog 以太网交换机(一)架构分析,本文将首先分析MAC接收控制器的设计。


1、MAC接收控制器功能

  MAC控制器负责以太网的MAC层和PHY层之间的数据交换,主要是根据MII标准接口规范进行数据收发
  对于本章的MAC接收控制器而言,其功能包括以下4点:

  • 识别接收数据帧的起始符;
  • 识别数据帧的字节边界,将半字节的数据转换为字节流;
  • 对数据帧长度进行计数,检测帧长度是否符合规范,CRC校验,并上报错误标识;
  • 存储数据帧的指针信息(规范标志、帧长度等);

2、MAC接收控制器接口

  MAC接收控制器一端连接标准MII接口,另一端连接交换机内部的数据帧处理单元。因为在本级就要完成数据帧的检错,而后级的数据处理单元、队列管理器可能出现满载,来不及处理接收的数据,所以在MAC接收器内部,我们设计一个同步FIFO,以完成数据缓冲的作用,另一方面FIFO也可以完成握手信号的逻辑。

  所以,MAC接收控制器的输入为MII接口,输出为FIFO接口形式,由于FIFO比较基础,下面就仅罗列MII接口。


3、MAC接收控制器实现细节

  根据以太网MAC层的规范,控制器还需要对数据帧进行CRC-32校验,由于CRC本质就是反馈多项式,和LFSR类似,在本专题就不展开介绍了,通常CRC的多项式公式可以直接通过生成器来生成。(CRC生成器将放在本号的资源栏中,有需要的可以下载,或者关注博主的公众号,也有下载链接

  综合上述FIFO和CRC的需求,最后MAC接收控制器的整体架构图如下:


3.1、功能细节分析

  1. 传递正确的帧信息给后级,例如是错误帧,就可以直接读出并丢掉;这就需要2个FIFO一个存放数据,一个存放帧信息,两者并不是一 一对应的关系,一个帧信息可能对应多字节的数据帧
  2. 根据MII数据格式识别帧开始标志帧起始符帧结束标志
  3. 检测数据帧长度是否符合规范(64 bytes < length < 1518 bytes),否则都为错误帧;
  4. 检测数据帧是否byte对齐,如果从MII收到的数据量为奇数则为错误帧;
  5. CRC校验错误,标记为错误帧;

3.2、SFIFO设计

  MAC接收控制器中有两个FIFO,我们将存放数据的FIFO称作data_fifo,将存放状态的称作state_fifo。

  • 为了后级模块更为简单高效的处理数据,MAC控制器需要以字节的形式传递数据,故data_fifo的位宽为8-bits,具体深度一般会根据要求的性能进行设置,本项目中暂时将深度设为4k,能正好存放2个最长帧。
  • 而state_fifo需要记录数据帧的帧长度(以便后级模块知道帧的边界)以及帧的错误信息,所以宽度设置为16-bits,具体格式如下图。考虑到data_fifo深度为4k,若全是最小帧可以存放64个,所以state_fifo的深度设置为16


3.3、MAC接收器核心电路设计

  由于在发送端每个数据帧的末尾会插入CRC-32的计算值,这会使得在接收端每一个正确的数据帧的CRC校验值为一固定值,当不为此值时,即代表发生CRC error。在设计中,我们可以将该固定值设置为一个parameter,以便大家使用不同的多项式实现CRC。

  此外,我们通过检查数据帧的起始标志和结束标志,来判断帧边界,并不断记录数据帧的字节数,当到达结束标志后,检查数据长度是否合规,数据是否是字节对齐的,若发生错误则在state_fifo中记录,这样就完成了MAC接收控制器的所有功能。

  需要注意的是数据帧的开始符按照MAC帧格式来看是0x10101011,其中前6位的101010是MAC前导符的延申。前导符是比特‘10’的集合,用于PHY serdes做时钟恢复用(因为serdes的时钟和数据合并在一根数据线上,所以接收端需要做时钟恢复)。所以接收到0x1011即代表接收到有效数据帧(SFD,start frame describe)。

  另一点是MAC帧要求在帧与帧之间必须存在间隔,即一个数据帧发送完毕后rx_dv必定存在低电平时刻,所以在设计中,我们使用一个状态机来表示数据帧处于的不同状态,并用于控制各个变量,状态跳转图如下:



  将状态机共分为4个状态:ST_SOF、ST_WAIT、ST_EOF、ST_DONE,分别对应等待MAC帧开始、等待帧起始符、等待MAC结束、将各信息传递至fifo

  • 当MAC帧开始,没有接收到SFD时,状态进入ST_WAIT,直到接收到SFD进入ST_EOF,或者rx_dv拉低,该帧为错误帧,回到ST_SOF。此外当data_fifo空间不足以容纳一个最大帧时,会停止接收任何帧,该帧会被丢弃;
  • 进入ST_EOF后,接收的数据都为有效数据,需要不断记录接收的字节数,且每收够1字节数据,就写入data_fifo中,直到接收到eof信号,数据帧结束,进入ST_DONE状态,进行数据帧的各类检错;
  • ST_DONE内,需要检查帧长度、byte align、CRC error,并将状态写入state_fifo中,下一拍回到ST_SOF,等待下一数据帧。

3.4、MAC接收器代码

  控制器的设计并不复杂,Verilog代码将放在下面,Testbench就不展示了,有需要的可以等专题结束后在资源中下载,或者去我的公众号获得链接。


module mac_r(
//system interface
input           clk,
input           rst_n,
//MII interface
input           rx_clk,
input           rx_dv,
input   [3:0]   rx_d,
//mac-r - interface mux
input           data_fifo_rd,
output  [7:0]   data_fifo_dout,
input           state_fifo_rd,
output  [15:0]  state_fifo_dout,
output          state_fifo_empty
    );
    
parameter   CRC_RESULT = 32'hc704dd7b;
parameter   ST_SOF      = 4'b0001;
parameter   ST_WAIT     = 4'b0010;
parameter   ST_EOF      = 4'b0100;    
parameter   ST_DONE     = 4'b1000;

parameter   BCNT_MAX    = 1518;
parameter   BCNT_MIN    = 64;

reg             rx_dv_dly0;  //用于输入数据有效的采样    
reg             rx_dv_dly1;
reg     [3:0]   rx_d_dly0;
reg     [3:0]   rx_d_dly1;

//信号有效信号的上升沿表示帧开始,下降沿则表示帧结束
wire            sof;  //start of frame  帧开始标志    只能表示有MAC帧来了
wire            eof;  //end of frame    帧结束标志
wire            sfd;  //start frame decribe 帧起始符  sof不代表真正数据帧的开始,sdf才代表!
wire            mac_r_rdy; //表示mac_r当前有接收能力
//控制状态机
reg     [3:0]   cur_state;
reg     [3:0]   next_state;
//byte cnt变量
wire            bcnt_clr;   //清零信号
reg     [11:0]  bcnt;

reg             frame_vld;  //数据帧有效信号

//fifo
wire    [7:0]   data_fifo_din;     
wire            data_fifo_wr;
wire    [11:0]  data_fifo_wr_cnt;

reg     [15:0]  state_fifo_din;
reg             state_fifo_wr;
wire            state_fifo_full;

wire    [31:0]  crc_reg;

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)begin
        rx_dv_dly0 <= 1'b0;
        rx_dv_dly1 <= 1'b0;
        rx_d_dly0[3:0] <= 4'b0;
        rx_d_dly1[3:0] <= 4'b0;
    end
    else begin
        rx_dv_dly0 <= rx_dv;
        rx_dv_dly1 <= rx_dv_dly0;
        rx_d_dly0[3:0] <= rx_d[3:0];
        rx_d_dly1[3:0] <= rx_d_dly0[3:0];
    end
end
    
assign sof = !rx_dv_dly1 & rx_dv_dly0;
assign eof = rx_dv_dly1 & !rx_dv_dly0;
assign sfd = rx_dv_dly0 & (rx_d_dly0[3:0]==4'b1011);

//三段式状态机
always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        cur_state[3:0] <= ST_SOF;
    else
        cur_state[3:0] <= next_state[3:0];
end

always @(*)begin
    case(cur_state[3:0])
        ST_SOF:     next_state[3:0] = (sof & mac_r_rdy) ? !sfd ? ST_WAIT : ST_EOF : ST_SOF;
        ST_WAIT:    next_state[3:0] = rx_dv_dly0 ? sfd ? ST_EOF : ST_WAIT : ST_SOF;
        ST_EOF:     next_state[3:0] = eof ? ST_DONE : ST_EOF;
        ST_DONE:    next_state[3:0] = ST_SOF;
        default:    next_state[3:0] = ST_SOF;
    endcase        
end

assign bcnt_clr = (sof & sfd) | (cur_state[3:0]==ST_WAIT & sfd);

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        bcnt[11:0] <= 12'b0;
    else if(bcnt_clr)
        bcnt[11:0] <= 12'b0;
    else
        bcnt[11:0] <= bcnt[11:0] + 12'b1;
end

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        frame_vld <= 1'b0;
    else if(cur_state[3:0]==ST_EOF & eof)
        frame_vld <= 1'b0;
    else if( (cur_state[3:0]==ST_SOF & sof & sfd) | (cur_state[3:0]==ST_WAIT & rx_dv_dly0 & sfd))
        frame_vld <= 1'b1;
end


assign data_fifo_wr = frame_vld & bcnt[0] & rx_dv_dly0; //当存够两个rx_data时,且帧有效时,向data_fifo中存一次数据
assign data_fifo_din = {rx_d_dly0,rx_d_dly1};


assign mac_r_rdy = (data_fifo_wr_cnt[11:0]> 4096 - BCNT_MAX);

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        state_fifo_wr <= 1'b0;
    else if(cur_state[3:0]==ST_EOF & eof)
        state_fifo_wr <= 1'b1;
    else
        state_fifo_wr <= 1'b0;
end

always @(posedge rx_clk or negedge rst_n)begin
    if(!rst_n)
        state_fifo_din[15:0] <= 16'b0;
    else if(cur_state[3:0]==ST_EOF & eof)begin
        state_fifo_din[10:0] <= bcnt[11:1];
        state_fifo_din[14] <=( (bcnt[11:1] > BCNT_MAX) | (bcnt[11:1] < BCNT_MIN) | bcnt[0] ) ? 1'b1 :1'b0;
        state_fifo_din[15] <= (crc_reg[31:0]==CRC_RESULT) ? 1'b0 : 1'b1;
    end
end


data_fifo x_data_fifo(
    .rst(~rst_n),
    .wr_clk(rx_clk),
    .rd_clk(clk),
    .din(data_fifo_din[7:0]),
    .wr_en(data_fifo_wr),
    .rd_en(data_fifo_rd),
    .dout(data_fifo_dout[7:0]),
    .full(),
    .empty(),
    .rd_data_count(),
    .wr_data_count(data_fifo_wr_cnt[11:0])
  );
  
state_fifo x_state_fifo(
    .rst(~rst_n),
    .wr_clk(rx_clk),
    .rd_clk(clk),
    .din(state_fifo_din[15:0]),
    .wr_en(state_fifo_wr),
    .rd_en(state_fifo_rd),
    .dout(state_fifo_dout[15:0]),
    .full(state_fifo_full),
    .empty(state_fifo_empty)
  );  

crc32 x_crc32(
    .clk(clk),
    .rst_n(rst_n),
    .data(data_fifo_din[7:0]),
    .init(sof),
    .cal(data_fifo_wr),
    .vld(data_fifo_wr),
    .crc_reg(crc_reg[31:0]),
    .crc()                //大端输出
    );

endmodule




搜索关注我的微信公众号【IC墨鱼仔】,获取我的更多IC干货分享!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

plt绘制点线图 点(marker)过密的解决办法

设置 markevery10 plt.plot(x, y, markero, markevery10) import matplotlib.pyplot as plt import numpy as npxnp.arange(0,2*np.pi,0.01) ynp.sin(x)fig, ax plt.subplots(constrained_layoutTrue)plt.title(markevery10)ax.plot(x, y, markero, markevery50, mfcr,mecr)…

(小甲鱼python)函数笔记合集四 函数(IV)总结 函数中参数的作用域 局部作用域 全局作用域 global语句 嵌套函数 nonlocal语句等详解

一、基础复习 函数的基本用法 创建和调用函数 函数的形参与实参等等函数的几种参数 位置参数、关键字参数、默认参数等函数的收集参数*args **args 解包参数详解 二、函数中参数的作用域 作用域&#xff1a;一个变量可以被访问的范围&#xff0c;一个变量的作用域总是由它在代…

jQuery学习-01jQuery下载安装

1 jQuery的介绍 jQuery就是js函数库&#xff0c;里面有大量的js函数库&#xff0c;使用这些函数操作dom对象&#xff0c;做事件&#xff0c;动画&#xff0c;ajax处理&#xff1b; 地址&#xff1a;https://jquery.com/ 2下载 地址&#xff1a;https://jquery.com/download/…

Apache Solr 9.1-(一)初体验单机模式运行

Apache Solr 9.1-&#xff08;一&#xff09;初体验单机模式运行 Solr是一个基于Apache Lucene的搜索服务器&#xff0c;Apache Lucene是开源的、基于Java的信息检索库&#xff0c;Solr能为用户提供无论在任何时候都可以根据用户的查询请求返回结果&#xff0c;它被设计为一个强…

day12-继承

1. 继承 1.1 继承的实现&#xff08;掌握&#xff09; 继承的概念 继承是面向对象三大特征之一&#xff0c;可以使得子类具有父类的属性和方法&#xff0c;还可以在子类中重新定义&#xff0c;以及追加属性和方法 实现继承的格式 继承通过extends实现格式&#xff1a;class 子…

【算法题】1318. 或运算的最小翻转次数

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 题目&#xff1a; 给你三个正整数 a、b 和 c。 你可…

Webpack:HTML Webpack Plugin插件

HTML Webpack Plugin插件&#xff0c;在Webpack构建的前端项目中&#xff0c;用于简化index.html文件的创建&#xff0c;以免除项目打包之后手动创建/拷贝index.html到打包目录下的繁琐步骤。以下&#xff0c;从一个已构建好的Vue项目中的一个现象谈起&#xff0c;逐步深入了解…

vs code中的platformIO插件,完成Arduino的程序编写,导入,安装开发板管理库

准备工作 vs code已经安装好&#xff0c;扩展插件plateformIO也安装好。&#xff08;下图是platformIO安装方式&#xff09; platformIO界面功能介绍和简单使用 新建Arduino项目 选择正确的开发板型号&#xff0c;和自己习惯的编译框架。打开后有一个.ini的配置文件&#x…

MySQL表的增删改查(初级)

MySQL数据库最核心的内容就是增删改查&#xff08;即CURD&#xff09;,看了这篇初级增删改查的博客之后可以解决以后工作中百分之80-90的内容&#xff0c;这部分的知识并不是很难&#xff0c;但是需要一定的熟练程度&#xff1b;C&#xff1a;create--新增U&#xff1a;update-…

设计模式_行为型模式 -《策略模式》

设计模式_行为型模式 -《策略模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 先看下面的图片&#xff0c;我们去旅游选择出行模式有很多种&#xff0c;可以骑自行车、可以坐汽车、可以坐火车、…

Nginx应用场景

Nginx应用场景 Nginx配置文件说明 Nginx 的配置文件位置 1、文件位置 安装目录\conf\nginx.conf 安装目录\nginx.conf 2、两个文件是一样的 3、使用 /usr/local/nginx/sbin/nginx 启动 Nginx &#xff0c;默认用的是 安装目录 \nginx.conf 配置文件 4、作用&#xff1a;完…

三、命令行工具cmder的安装

1、cmder安装 1.1、cmder简介 cmder是一个增强型命令工具&#xff0c;不仅可以使用Windows下的所有命令&#xff0c;并且还可以使用Linux和shell命令。 1.2、cmder下载 (1)cmder的官方网站提供的下载地址实在是太慢了基本是下载不下来&#xff0c;建议到清华大学的镜像站去…

SELECT必知必会_引擎,PROCEDURE,事务处理

书接上文&#xff0c;之前说了Mysql的SELECT部分&#xff0c;本片文章会重点介绍关于MySql的其他一些知识&#xff0c;也会是MySql必知必会的最后一篇。 首先&#xff0c;是Mysql中的增删改操作&#xff0c;对于测试岗来说&#xff0c;这部分知识相对来说不是那么重要&#xf…

案例分享 | AI助力肯尼亚“Sheng”语研究

你听说过一种叫做“Sheng”的语言吗&#xff1f;这是一种斯瓦希里语-英语俚语&#xff0c;主要使用者为肯尼亚内罗毕等城市地区的青年。近年来&#xff0c;随着“Sheng”的使用量不断增加&#xff0c;一家非盈利组织正在帮助更新该地区的社区信息资源&#xff0c;随时根据词汇中…

【6s965-fall2022】深度学习的效率指标

两个核心指标是计算和内存(Computation and Memory)。需要考虑的三个维度是存储、延迟和能耗(Storage, Latency, and Energy)。 延迟 Latency Latency max(Toperation,Tmemory)max(T_{operation}, T_{memory})max(Toperation​,Tmemory​) 能耗 Energy 内存访问比计算更消耗…

Softmax Loss、AAM-Softmax(ArcFace)、Sub-center ArcFace的PyTorch实现与代码解读

概述 说话人识别中的损失函数分为基于多类别分类的损失函数&#xff0c;和端到端的损失函数&#xff08;也叫基于度量学习的损失函数&#xff09;&#xff0c;关于这些损失函数的理论部分&#xff0c;可参考说话人识别中的损失函数本文主要关注这些损失函数的实现&#xff0c;…

开源PPP软件PRIDE-PPPAR使用记录(二)解算网友发来的GNSS观测文件

最近有个网友发来了几个GNSS原始观测文件&#xff0c;想使用TerraPos处理一下看看结果。 TerraPos打开这几个文件&#xff0c;都报一个格式错误&#xff0c;见下图&#xff1a; 正在上传…重新上传取消​ 这个问题不难&#xff0c;解决之道就是按照上一篇文章的方法&#xf…

杭州到温州老家自驾路线优化与整理

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 背景及义意义 背景 考虑到后续经常回老家&#xff0c;需要提前熟悉回家的路线。杭州和温州有很多快速路和国道与高速是基本相伴而行的&#xff0c;可以利用这些道路取…

在项目管理中,甘特图是最常用的工具之一

在项目管理中&#xff0c;为了能对项目过程进行监控&#xff0c;可视化进度管理&#xff0c;需要使用辅助工具来帮助我们管理项目&#xff0c;而甘特图则是其中最经常使用的工具之一。 甘特图更够清晰的反映项目各个阶段的计划&#xff0c;任务由谁负责&#xff0c;计划与实际…

mysql性能优化二

1 mysql 基本功能 1.1、mysql连接器的工作流程: 1.2、查看连接状态: show processlist; Note:客户端太长时间没动静 就自动断开 这个时间是由wait_timeout参数控制的,默认8h 长连接短链接 长连接是链接成功后,如果客户端持续有请求,则使用同一个链接[尽量使用长连接,因为每次…