澳门永利的所有网址是多少


Produced By 中国煤炭开发有限责任公司
主页 > 公司要闻 >

FPGA设计案例:数据缓存模块设计与验证实验

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

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

`ti澳门永利的所有网址是多少mescale 1ns / 1ps

澳门永利的所有网址是多少// Description: MAC IP TX方向用户数据缓存及位宽转换模块

澳门永利的所有网址是多少// 整体功能:将TX方向用户32bit位宽的数据包转换成8bit位宽数据包

澳门永利的所有网址是多少//用户侧时钟100MHZ,MAC侧125MHZ

澳门永利的所有网址是多少//缓存深度:保证能缓存4个最长数据包,TX方向用户数据包包括

//目的MAC地址 源MAC地址 类型/长度 数据 最长1514byte

module tx_buffer#(parameter DATA_W = 32)//位宽不能改动

(

//全局信号

input rs澳门永利的所有网址是多少t_n,//保证拉低三个时钟周期,否则FIF可能不会正确复位

//用户侧信号

澳门永利的所有网址是多少input user_clk,

澳门永利的所有网址是多少input [DATA_W-1:0] din,

澳门永利的所有网址是多少input din_vld,

input din_sop,

澳门永利的所有网址是多少input din_eop,

澳门永利的所有网址是多少input [2-1:0] din_mod,

output rdy,

//MAC侧信号

澳门永利的所有网址是多少input eth_tx_clk,

output reg [8-1:0] dout,

澳门永利的所有网址是多少output reg dout_sop,

output reg dout_eop,

澳门永利的所有网址是多少output reg dout_vld

);

澳门永利的所有网址是多少reg wr_en = 0;

reg [DATA_W+4-1:0] fifo_din = 0;

reg [ (2-1):0] rd_cnt = 0 ;

澳门永利的所有网址是多少wire add_rd_cnt ;

澳门永利的所有网址是多少wire end_rd_cnt ;

澳门永利的所有网址是多少wire rd_en;

澳门永利的所有网址是多少wire [DATA_W+4-1:0] fifo_dout;

wire rst;

reg [ (2-1):0] rst_cnt =0 ;

澳门永利的所有网址是多少wire add_rst_cnt ;

澳门永利的所有网址是多少wire end_rst_cnt ;

reg rst_flag = 0;

wire [11 : 0] wr_data_count;

澳门永利的所有网址是多少wire empty;

wire full;

/****************************************写侧*************************************************/

always @(posedge user_clk or negedge rst_n)begin

澳门永利的所有网址是多少if(rst_n==1'b0)begin

wr_en end

澳门永利的所有网址是多少else if(rdy)

wr_en end

澳门永利的所有网址是多少always @(posedge user_clk or negedge rst_n)begin

澳门永利的所有网址是多少if(rst_n==1'b0)begin

fifo_din end

else begin//[35] din_sop [34] din_eop [33:32] din_mod [31:0] din

澳门永利的所有网址是多少fifo_din end

end

assign rdy = wr_data_count

澳门永利的所有网址是多少/****************************************读侧*************************************************/

澳门永利的所有网址是多少always @(posedge eth_tx_clk or negedge rst_n) begin

if (rst_n==0) begin

rd_cnt end

澳门永利的所有网址是多少else if(add_rd_cnt) begin

澳门永利的所有网址是多少if(end_rd_cnt)

rd_cnt else

rd_cnt end

end

澳门永利的所有网址是多少assign add_rd_cnt = (!empty);

assign end_rd_cnt = add_rd_cnt && rd_cnt == (4)-1 ;

澳门永利的所有网址是多少assign rd_en = end_rd_cnt;

always @(posedge eth_tx_clk or negedge rst_n)begin

if(rst_n==1'b0)begin

dout end

else if(add_rd_cnt)begin

dout end

end

澳门永利的所有网址是多少always @(posedge eth_tx_clk or negedge rst_n)begin

if(rst_n==1'b0)begin

dout_vld end

else if(add_rd_cnt && ((rd_cnt dout_vld end

else

dout_vld end

always @(posedge eth_tx_clk or negedge rst_n)begin

if(rst_n==1'b0)begin

dout_sop end

澳门永利的所有网址是多少else if(add_rd_cnt && rd_cnt == 0 && fifo_dout[35])begin

dout_sop end

else

澳门永利的所有网址是多少dout_sop end

澳门永利的所有网址是多少always @(posedge eth_tx_clk or negedge rst_n)begin

澳门永利的所有网址是多少if(rst_n==1'b0)begin

dout_eop end

else if(add_rd_cnt && rd_cnt == 3 - fifo_dout[33:32] && fifo_dout[34])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==0) begin

澳门永利的所有网址是多少rst_cnt end

else if(add_rst_cnt) begin

if(end_rst_cnt)

澳门永利的所有网址是多少rst_cnt else

澳门永利的所有网址是多少rst_cnt end

end

澳门永利的所有网址是多少assign add_rst_cnt = (rst_flag);

assign end_rst_cnt = add_rst_cnt && rst_cnt == (3)-1 ;

//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 = 10,

ETH_CLK_CYC = 8,

RST_TIM = 3;

parameter SIM_TIM = 10_000;

reg user_clk;

reg rst_n;

reg [32-1:0] din;

澳门永利的所有网址是多少reg din_vld,din_sop,din_eop;

澳门永利的所有网址是多少reg [2-1:0] din_mod;

wire rdy;

reg eth_tx_clk;

wire [8-1:0] dout;

wire dout_sop,dout_eop,dout_vld;

reg [8-1:0] dout_buf [0:1024-1];

澳门永利的所有网址是多少reg [16-1:0] len [0:100-1];

澳门永利的所有网址是多少reg [2-1:0] mod [0:100-1];

澳门永利的所有网址是多少reg err_flag = 0;

tx_buffer#(.DATA_W(32))//位宽不能改动

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 = 1;

forever #(USER_CLK_CYC/2) user_clk = ~user_clk;

end

澳门永利的所有网址是多少initial begin

eth_tx_clk = 1;

forever #(ETH_CLK_CYC/2) eth_tx_clk = ~eth_tx_clk;

end

/***********************************复位逻辑******************************************/

澳门永利的所有网址是多少initial begin

rst_n = 1;

#1;

rst_n = 0;

#(RST_TIM*USER_CLK_CYC);

rst_n = 1;

end

/***********************************输入激励******************************************/

澳门永利的所有网址是多少integer gen_time = 0;

澳门永利的所有网址是多少initial begin

#1;

packet_initial;

澳门永利的所有网址是多少#(RST_TIM*USER_CLK_CYC);

packet_gen(20,2);

澳门永利的所有网址是多少#(USER_CLK_CYC*10);

packet_gen(30,1);

end

澳门永利的所有网址是多少/***********************************输出缓存与检测******************************************/

integer j = 0;

integer chk_time = 0;

initial begin

forever begin

@(posedge eth_tx_clk)

澳门永利的所有网址是多少if(dout_vld)begin

if(dout_sop)begin

dout_buf[0] = dout;

j = 1;

end

else if(dout_eop)begin

dout_buf[j] = dout;

j = j+1;

packet_check;

end

else begin

澳门永利的所有网址是多少dout_buf[j] = dout;

j = j+1;

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 [16-1:0] length;

澳门永利的所有网址是多少input [2-1:0] invalid_byte;

integer i;

begin

len[gen_time] = length;

澳门永利的所有网址是多少mod[gen_time] = invalid_byte;

for(i = 1;i if(rdy == 1)begin

din_vld = 1;

if(i==1)

din_sop = 1;

澳门永利的所有网址是多少else if(i == length)begin

澳门永利的所有网址是多少din_eop = 1;

din_mod = invalid_byte;

end

else begin

din_sop = 0;

din_eop = 0;

din_mod = 0;

end

din = i ;

end

else begin

din_sop = din_sop;

澳门永利的所有网址是多少din_eop = din_eop;

澳门永利的所有网址是多少din_vld = 0;

澳门永利的所有网址是多少din_mod = din_mod;

din = din;

i = i - 1;

end

#(USER_CLK_CYC*1);

end

packet_initial;

gen_time = gen_time + 1;

end

endtask

task packet_initial;

begin

din_sop = 0;

din_eop = 0;

din_vld = 0;

din = 0;

澳门永利的所有网址是多少din_mod = 0;

end

endtask

//包检测子任务

澳门永利的所有网址是多少task packet_check;

integer k;

integer num,packet_len;

begin

num = 1;

$fdisplay(fid,"%dth:Packet checking.../n",chk_time);

packet_len = 4*len[chk_time]-mod[chk_time];

if(j != packet_len)begin

$fdisplay(fid,"Length of the packet is wrong./n");

err_flag = 1;

澳门永利的所有网址是多少disable packet_check;

end

for(k=0;k

澳门永利的所有网址是多少if(k%4 == 3)begin

澳门永利的所有网址是多少if(dout_buf[k] != num)begin

$fdisplay(fid,"Data of the packet is wrong!/n");

澳门永利的所有网址是多少err_flag = 1;

end

澳门永利的所有网址是多少num = num+1;

end

else if(dout_buf[k] != 0)begin

$fdisplay(fid,"Data of the packet is wrong,it should be zero!/n");

err_flag = 1;

end

end

澳门永利的所有网址是多少chk_time = chk_time + 1;

end

endtask

endmodule

tx_buffer_tb

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

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

Produced By 中国煤炭开发有限责任公司