本文设计思想采用明德扬至简设计法。上一篇博文中定制了自定义MAC IP的结构,在用户侧需要位宽转换及数据缓存。本文以TX方向为例,设计并验证发送缓存模块。这里定义该模块可缓存4个最大长度数据包,用户根据需求改动即可。

  该模块核心是利用异步FIFO进行跨时钟域处理,位宽转换由VerilogHDL实现。需要注意的是用户数据包位宽32bit,因此包尾可能有无效字节,而转换为8bit位宽数据帧后是要丢弃无效字节的。内部逻辑非常简单,直接上代码:

 `timescale 1ns / 1ps

 // Description: MAC IP TX方向用户数据缓存及位宽转换模块
// 整体功能:将TX方向用户32bit位宽的数据包转换成8bit位宽数据包
//用户侧时钟100MHZ,MAC侧125MHZ
//缓存深度:保证能缓存4个最长数据包,TX方向用户数据包包括
//目的MAC地址 源MAC地址 类型/长度 数据 最长1514byte module tx_buffer#(parameter DATA_W = )//位宽不能改动
( //全局信号
input rst_n,//保证拉低三个时钟周期,否则FIF可能不会正确复位 //用户侧信号
input user_clk,
input [DATA_W-:] din,
input din_vld,
input din_sop,
input din_eop,
input [-:] din_mod,
output rdy, //MAC侧信号
input eth_tx_clk,
output reg [-:] dout,
output reg dout_sop,
output reg dout_eop,
output reg dout_vld
); reg wr_en = ;
reg [DATA_W+-:] fifo_din = ;
reg [ (-):] rd_cnt = ;
wire add_rd_cnt ;
wire end_rd_cnt ;
wire rd_en;
wire [DATA_W+-:] fifo_dout;
wire rst;
reg [ (-):] rst_cnt = ;
wire add_rst_cnt ;
wire end_rst_cnt ;
reg rst_flag = ;
wire [ : ] wr_data_count;
wire empty;
wire full; /****************************************写侧*************************************************/
always @(posedge user_clk or negedge rst_n)begin
if(rst_n=='b0)begin
wr_en <= ;
end
else if(rdy)
wr_en <= din_vld;
end always @(posedge user_clk or negedge rst_n)begin
if(rst_n=='b0)begin
fifo_din <= ;
end
else begin//[35] din_sop [34] din_eop [33:32] din_mod [31:0] din
fifo_din <= {din_sop,din_eop,din_mod,din};
end
end assign rdy = wr_data_count <= && !rst && !rst_flag && !full; /****************************************读侧*************************************************/ always @(posedge eth_tx_clk or negedge rst_n) begin
if (rst_n==) begin
rd_cnt <= ;
end
else if(add_rd_cnt) begin
if(end_rd_cnt)
rd_cnt <= ;
else
rd_cnt <= rd_cnt+ ;
end
end
assign add_rd_cnt = (!empty);
assign end_rd_cnt = add_rd_cnt && rd_cnt == ()- ; assign rd_en = end_rd_cnt; always @(posedge eth_tx_clk or negedge rst_n)begin
if(rst_n=='b0)begin
dout <= ;
end
else if(add_rd_cnt)begin
dout <= fifo_dout[DATA_W--rd_cnt* -:];
end
end always @(posedge eth_tx_clk or negedge rst_n)begin
if(rst_n=='b0)begin
dout_vld <= ;
end
else if(add_rd_cnt && ((rd_cnt <= - fifo_dout[:] && fifo_dout[]) || !fifo_dout[]))begin
dout_vld <= ;
end
else
dout_vld <= ;
end always @(posedge eth_tx_clk or negedge rst_n)begin
if(rst_n=='b0)begin
dout_sop <= ;
end
else if(add_rd_cnt && rd_cnt == && fifo_dout[])begin
dout_sop <= ;
end
else
dout_sop <= ;
end always @(posedge eth_tx_clk or negedge rst_n)begin
if(rst_n=='b0)begin
dout_eop <= ;
end
else if(add_rd_cnt && rd_cnt == - fifo_dout[:] && fifo_dout[])begin
dout_eop <= ;
end
else
dout_eop <= ;
end /******************************FIFO复位逻辑****************************************/
assign rst = !rst_n || rst_flag; always @(posedge user_clk or negedge rst_n)begin
if(!rst_n)begin
rst_flag <= ;
end
else if(end_rst_cnt)
rst_flag <= ;
end always @(posedge user_clk or negedge rst_n) begin
if (rst_n==) begin
rst_cnt <= ;
end
else if(add_rst_cnt) begin
if(end_rst_cnt)
rst_cnt <= ;
else
rst_cnt <= rst_cnt+ ;
end
end
assign add_rst_cnt = (rst_flag);
assign end_rst_cnt = add_rst_cnt && rst_cnt == ()- ; //FIFO位宽32bit 一帧数据最长1514byte,即379个16bit数据
//FIFO深度:379*4 = 1516 需要2048
//异步FIFO例化
fifo_generator_0 fifo (
.rst(rst), // input wire rst
.wr_clk(user_clk), // input wire wr_clk 100MHZ
.rd_clk(eth_tx_clk), // input wire rd_clk 125MHZ
.din(fifo_din), // input wire [33 : 0] din
.wr_en(wr_en), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(fifo_dout), // output wire [33 : 0] dout
.full(full), // output wire full
.empty(empty), // output wire empty
.wr_data_count(wr_data_count) // output wire [11 : 0] wr_data_count
); endmodule

tx_buffer

  接下来是验证部分,也就是本文的重点。以下的testbench包含了最基本的测试思想:发送测试激励给UUT,将UUT输出与黄金参考值进行比较,通过记分牌输出比较结果。

 `timescale 1ns / 1ps

 module tx_buffer_tb( );

 parameter USER_CLK_CYC = ,
ETH_CLK_CYC = ,
RST_TIM = ; parameter SIM_TIM = 10_000; reg user_clk;
reg rst_n;
reg [-:] din;
reg din_vld,din_sop,din_eop;
reg [-:] din_mod;
wire rdy;
reg eth_tx_clk;
wire [-:] dout;
wire dout_sop,dout_eop,dout_vld;
reg [-:] dout_buf [:-];
reg [-:] len [:-];
reg [-:] mod [:-];
reg err_flag = ; tx_buffer#(.DATA_W())//位宽不能改动
dut
( //全局信号
.rst_n (rst_n) ,//保证拉低三个时钟周期,否则FIF可能不会正确复位
.user_clk (user_clk) ,
.din (din) ,
.din_vld (din_vld) ,
.din_sop (din_sop) ,
.din_eop (din_eop) ,
.din_mod (din_mod) ,
.rdy (rdy) ,
.eth_tx_clk (eth_tx_clk) ,
.dout (dout) ,
.dout_sop (dout_sop) ,
.dout_eop (dout_eop) ,
.dout_vld (dout_vld)
); /***********************************时钟******************************************/
initial begin
user_clk = ;
forever #(USER_CLK_CYC/) user_clk = ~user_clk;
end initial begin
eth_tx_clk = ;
forever #(ETH_CLK_CYC/) eth_tx_clk = ~eth_tx_clk;
end
/***********************************复位逻辑******************************************/
initial begin
rst_n = ;
#;
rst_n = ;
#(RST_TIM*USER_CLK_CYC);
rst_n = ;
end /***********************************输入激励******************************************/
integer gen_time = ;
initial begin
#;
packet_initial;
#(RST_TIM*USER_CLK_CYC);
packet_gen(,);
#(USER_CLK_CYC*);
packet_gen(,);
end /***********************************输出缓存与检测******************************************/
integer j = ;
integer chk_time = ;
initial begin
forever begin
@(posedge eth_tx_clk)
if(dout_vld)begin
if(dout_sop)begin
dout_buf[] = dout;
j = ;
end
else if(dout_eop)begin
dout_buf[j] = dout;
j = j+;
packet_check;
end
else begin
dout_buf[j] = dout;
j = j+;
end
end
end
end /***********************************score board******************************************/
integer fid;
initial begin
fid = $fopen("test.txt");
$fdisplay(fid," Start testing \n");
#SIM_TIM;
if(err_flag)
$fdisplay(fid,"Check is failed\n");
else
$fdisplay(fid,"Check is successful\n");
$fdisplay(fid," Testing is finished \n");
$fclose(fid);
$stop;
end /***********************************子任务******************************************/
//包生成子任务
task packet_gen;
input [-:] length;
input [-:] invalid_byte;
integer i;
begin
len[gen_time] = length;
mod[gen_time] = invalid_byte; for(i = ;i<=length;i=i+)begin
if(rdy == )begin
din_vld = ;
if(i==)
din_sop = ;
else if(i == length)begin
din_eop = ;
din_mod = invalid_byte;
end
else begin
din_sop = ;
din_eop = ;
din_mod = ;
end
din = i ;
end else begin
din_sop = din_sop;
din_eop = din_eop;
din_vld = ;
din_mod = din_mod;
din = din;
i = i - ;
end #(USER_CLK_CYC*);
end
packet_initial;
gen_time = gen_time + ;
end
endtask task packet_initial;
begin
din_sop = ;
din_eop = ;
din_vld = ;
din = ;
din_mod = ;
end
endtask //包检测子任务
task packet_check;
integer k;
integer num,packet_len;
begin
num = ;
$fdisplay(fid,"%dth:Packet checking...\n",chk_time);
packet_len = *len[chk_time]-mod[chk_time];
if(j != packet_len)begin
$fdisplay(fid,"Length of the packet is wrong.\n");
err_flag = ;
disable packet_check;
end for(k=;k<packet_len;k=k+)begin
if(k% == )begin
if(dout_buf[k] != num)begin
$fdisplay(fid,"Data of the packet is wrong!\n");
err_flag = ;
end
num = num+;
end
else if(dout_buf[k] != )begin
$fdisplay(fid,"Data of the packet is wrong,it should be zero!\n");
err_flag = ;
end
end
chk_time = chk_time + ;
end
endtask endmodule

tx_buffer_tb

  可见主要是task编写及文件读写操作帮了大忙,如果都用眼睛看波形来验证设计正确性,真的是要搞到眼瞎。为保证测试完备性,测试包生成task可通过输入接口产生不同长度和无效字节数的递增数据包。testbench中每检测到输出包尾指示信号eop即调用packet_check task对数值进行检测。本文的testbench结构较具通用性,可以用来验证任意对数据包进行处理的逻辑单元。

  之前Modelsim独立仿真带有IP核的Vivado工程时经常报错,只好使用Vivado自带的仿真工具。一直很头痛这个问题,这次终于有了进展!首先按照常规流程使用Vivado调用Modelsim进行行为仿真,启动后会在工程目录下产生些有用的文件,帮助我们脱离Vivado进行独立仿真。

  在新建Modelsim工程时,在红框内选择Vivado工程中<project>.sim -> sim_1 -> behav下的modelsim.ini文件。之后添加文件包括:待测试设计文件、testbench以及IP核可综合文件。第三个文件在<project>.srcs -> sources_1 -> ip -> <ip_name> -> synth下。

  现在可以顺利启动仿真了。我们来看下仿真结果:

  文件中信息打印情况:

  从波形和打印信息的结果来看,基本可以证明数据缓存及位宽转换模块逻辑功能无误。为充分验证要进一步给出覆盖率较高的测试数据集,后期通过编写do文件批量仿真实现。在FPGA或IC设计中,验证占据大半开发周期,可见VerilogHDL的非综合子集也是至关重要的,今后会多总结高效的验证方法!

FPGA设计千兆以太网MAC(3)——数据缓存及位宽转换模块设计与验证的更多相关文章

  1. 【重新发布,代码开源】FPGA设计千兆以太网MAC(1)——通过MDIO接口配置与检测PHY芯片

    原创博客,转载请注明出处:[重新发布,代码开源]FPGA设计千兆以太网MAC(1)——通过MDIO接口配置与检测PHY芯片 - 没落骑士 - 博客园 https://www.cnblogs.com/m ...

  2. FPGA设计千兆以太网MAC(2)——以太网协议及设计规划

    上篇该系列博文中通过MDIO接口实现了PHY芯片的状态检测,验证其已处于1000M 全双工工作模式.在设计MAC逻辑之前,要先清楚MAC与PHY之间的接口以及以太网协议细节,这样才能保证网络的兼容性. ...

  3. 【转】简谈基于FPGA的千兆以太网

    原文地址: http://blog.chinaaet.com/luhui/p/5100052903 大家好,又到了学习时间了,学习使人快乐.今天我们来简单的聊一聊以太网,以太网在FPGA学习中属于比较 ...

  4. 【小梅哥FPGA进阶学习之旅】基于Altera FPGA 的DDR2+千兆以太网电路设计

    DDR2电路设计 在高速大数据的应用中,高速大容量缓存是必不可少的硬件.当前在FPGA系统中使用较为广泛的高速大容量存储器有经典速度较低的单数据速率的SDRAM存储器,以及速度较高的双速率DDR.DD ...

  5. 千兆以太网TCP协议的FPGA实现

    转自https://blog.csdn.net/zhipao6108/article/details/82386355 千兆以太网TCP协议的FPGA实现 Lzx 2017/4/20 写在前面,这应该 ...

  6. 237-基于Xilinx Kintex-7 XC7K325T 的FMC/千兆以太网/SATA/四路光纤数据转发卡

    基于Xilinx Kintex-7 XC7K325T 的FMC/千兆以太网/SATA/四路光纤数据转发卡 一. 板卡概述  本板卡基于Xilinx公司的FPGAXC7K325T-2FFG900 芯片, ...

  7. AC6102 开发板千兆以太网UDP传输实验2

    AC6102 开发板千兆以太网UDP传输实验 在芯航线AC6102开发板上,设计了一路GMII接口的千兆以太网电路,通过该以太网电路,用户可以将FPGA采集或运算得到的数据传递给其他设备如PC或服务器 ...

  8. AC6102 开发板千兆以太网UDP传输实验

    AC6102 开发板千兆以太网UDP传输实验 在芯航线AC6102开发板上,设计了一路GMII接口的千兆以太网电路,通过该以太网电路,用户可以将FPGA采集或运算得到的数据传递给其他设备如PC或服务器 ...

  9. 迅为IMX6开发板支持全网通4G模块丨GPS模块丨WIFI蓝牙丨千兆以太网

    迅为i.MX6开发板丨迅为i.MX6Q开发板丨四核imx6开发板丨Cortec-A9开发板丨资料介绍: 特点: 处理器:Freescale Cortex-A9四核i.MX6Q主频1GHz 核心板配置: ...

随机推荐

  1. js初级入门

    javascript的数据类型 (symbol)一.原始数据类型 或 基本数据类型 6种 1,undefined (1,申明未赋值,2,函数没有返回值)2,null (空,不存在)3,number ( ...

  2. Challenges-XSS

    https://alf.nu/alert1 warmup adobe JSON

  3. 历经15个小时,终于评出这8本最受欢迎的SQL书籍

    文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 来源 | 程序员书库(ID:OpenSourceTop) 原文链接 | https://www.lif ...

  4. Android-----Intent中通过startActivity(Intent intent )隐式启动新的Activity

    显式Intent我已经简单使用过了,也介绍过概念,现在来说一说隐式Intent: 隐式Intent:就是只在Intent中设置要进行的动作,可以用setAction()和setData()来填入要执行 ...

  5. 安卓开发笔记(二十二):读取本地(内置)html文件并实现和Javascript交互

    实际上我们通常是使用WebView控件对本地html进行读取,这样就可以体会类似web app和安卓原生混合开发的乐趣了.在读取本地html并展示在前台的时候,并不需要在Androidmenifast ...

  6. Windows系统桌面右击反应变慢、卡顿问题解决方法

    博主的电脑是Win10系统,在修改完系统的用户文件夹名后,桌面右击出现了反应卡顿的现象,并且点击输入法,也变得卡顿.问题解决后,于是想简单记录一下. 还是注册表的问题,使用Win+R快捷键,打开运行, ...

  7. 开源干货!!!.NET Core + JWT令牌认证 + Vue.js(iview-admin) 通用动态权限(RBAC)管理系统框架[DncZeus]开源啦!!!

    DncZeus 前言 关于 DncZeus DncZeus = Dnc + Zeus "Dnc"--.Net Core 的缩写: "Zeus"--中文译为宙斯, ...

  8. 多标签分类的结果评估---macro-average和micro-average介绍

    一,多分类的混淆矩阵 多分类混淆矩阵是二分类混淆矩阵的扩展 祭出代码,画线的那两行就是关键啦: 二,查看多分类的评估报告 祭出代码,使用了classicfication_report() 三,宏平均与 ...

  9. 解决MUI阻止a标签默认跳转事件—方法总结

    用过mui的小伙伴们一定不会陌生,有时候真的很烦mui本身会阻止a标签默认跳转.一般只要用了mui的ui组件,比如头部,底部或者弹框,你就不能在用a标签进行跳转了. 注:项目中引用了mui后,可能也会 ...

  10. C/C++性能测试工具GNU gprof

    代码剖析(Code profiling)程序员在优化软件性能时要注意应尽量优化软件中被频繁调用的部分,这样才能对程序进行有效优化.使用真实的数据,精确的分析应用程序在时间上的花费的行为就成为_代码剖析 ...