uisrc 发表于 2024-1-7 13:29:50

12 Verilog语法_仿真文件设计

软件版本:无操作系统:WIN10 64bit硬件平台:适用所有系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!1概述本小节讲解Verilog语法的仿真文件设计,需要掌握testbench的建立方法。2仿真文件设计当完成verilog工程设计后,首先需要进行就是仿真文件的设计,仿真文件又称为testbench,测试激励。Testbench文件内容往往包含以下几种:
[*]信号变量声明。

[*]时钟与复位信号的生成。

[*]被测试模块接口信号的波形激励生成。

[*]被测试模块的例化。

[*]被测试模块接口数据的校验模块。

[*]打印仿真信息。

例:
module top(    input   wire                i_clk,   //输入时钟    input   wire                i_rst_n,   //输入复位    outputwire                o_gray_hsyn,   //输出hs信号    outputwire                o_gray_vsyn,   //输出vs信号    outputwire           o_gray_data,   //输出data数据信号    outputwire                o_gray_de //输出de像素有效信号);wire                i_hsyn;wire                i_vsyn;wire           i_r;wire           i_g;wire           i_b;    wire                i_de;
sim_image_tpg u_tpg(    .i_clk          (i_clk          ),    .o_hsyn         (i_hsyn         ),    .o_vsyn         (i_vsyn         ),    .o_en         (i_de         ),    .o_r            (i_r            ),    .o_g            (i_g            ),    .o_b            (i_b            ));
gray2binary_algorithm u_algorithm(    .i_clk          (i_clk          ),          .i_hsyn         (i_hsyn         ),          .i_vsyn         (i_vsyn         ),          .i_r            (i_r            ),    .i_g            (i_g            ),    .i_b            (i_b            ),    .i_de         (i_de         ),          .o_gray_hsyn    (o_gray_hsyn    ),    .o_gray_vsyn    (o_gray_vsyn    ),    .o_gray_data    (o_gray_data    ),    .o_gray_de      (o_gray_de      ));endmodulemodule gray2binary_algorithm(    input   wire                i_clk,          input   wire                i_hsyn,        input   wire                i_vsyn,        input   wire           i_r,    input   wire           i_g,//don't care    input   wire           i_b,//don't care    input   wire                i_de,          outputwire                o_gray_hsyn,        outputwire                o_gray_vsyn,        outputwire           o_gray_data,        outputwire                o_gray_de);
//Binarizationassign o_gray_data= i_r >= 75 ? 255 : 0;
assign o_gray_hsyn= i_hsyn;assign o_gray_vsyn= i_vsyn;assign o_gray_de    = i_de;
endmodule// `define VIDEO_1920_1080// `define VIDEO_1680_1050// `define VIDEO_1280_1024`define VIDEO_1280_720 //选择分辨率// `define VIDEO_1024_768// `define VIDEO_800_600// `define VIDEO_640_480module sim_image_tpg(    input   wire      i_clk,    outputreg         o_hsyn,    outputreg         o_vsyn,    outputreg         o_en,    outputreg    o_r,    outputreg    o_g,    outputreg    o_b);
//1920x1080 148.5Mhz`ifdefVIDEO_1920_1080parameterH_ACTIVE         = 1920;// 行数据有效时间parameterH_FRONT_PORCH    = 88;// 行消隐前肩时间parameterH_SYNC_TIME      = 44;// 行同步信号时间parameterH_BACK_PORCH   = 148; // 行消隐后肩时间
parameterV_ACTIVE         = 1080;// 列数据有效时间parameterV_FRONT_PORCH    = 4;   // 列消隐前肩时间parameterV_SYNC_TIME      = 5;   // 列同步信号时间parameterV_BACK_PORCH   = 36;// 列消隐后肩时间`endif
//1680x1050 119Mhz`ifdefVIDEO_1680_1050parameterH_ACTIVE         = 1680;// 行数据有效时间parameterH_FRONT_PORCH    = 48;// 行消隐前肩时间parameterH_SYNC_TIME      = 32;// 行同步信号时间parameterH_BACK_PORCH   = 80;// 行消隐后肩时间
parameterV_ACTIVE         = 1050;// 列数据有效时间parameterV_FRONT_PORCH    = 3;   // 列消隐前肩时间parameterV_SYNC_TIME      = 6;   // 列同步信号时间parameterV_BACK_PORCH   = 21;// 列消隐后肩时间`endif
//1280x1024 108Mhz`ifdefVIDEO_1280_1024parameterH_ACTIVE         = 1280;// 行数据有效时间parameterH_FRONT_PORCH    = 48;// 行消隐前肩时间parameterH_SYNC_TIME      = 112; // 行同步信号时间parameterH_BACK_PORCH   = 248; // 行消隐后肩时间
parameterV_ACTIVE         = 1024;// 列数据有效时间parameterV_FRONT_PORCH    = 1;   // 列消隐前肩时间parameterV_SYNC_TIME      = 3;   // 列同步信号时间parameterV_BACK_PORCH   = 38;// 列消隐后肩时间`endif
//1280X720 74.25MHZ`ifdefVIDEO_1280_720parameterH_ACTIVE         = 1280;// 行数据有效时间parameterH_FRONT_PORCH    = 110; // 行消隐前肩时间parameterH_SYNC_TIME      = 40;// 行同步信号时间parameterH_BACK_PORCH   = 220; // 行消隐后肩时间   
parameterV_ACTIVE         = 720; // 列数据有效时间parameterV_FRONT_PORCH    = 5;   // 列消隐前肩时间parameterV_SYNC_TIME      = 5;   // 列同步信号时间parameterV_BACK_PORCH   = 20;// 列消隐后肩时间`endif
//1024x768 65Mhz`ifdefVIDEO_1024_768parameterH_ACTIVE         = 1024;// 行数据有效时间parameterH_FRONT_PORCH    = 24;// 行消隐前肩时间parameterH_SYNC_TIME      = 136; // 行同步信号时间parameterH_BACK_PORCH   = 160; // 行消隐后肩时间
parameterV_ACTIVE         = 768; // 列数据有效时间parameterV_FRONT_PORCH    = 3;   // 列消隐前肩时间parameterV_SYNC_TIME      = 6;   // 列同步信号时间parameterV_BACK_PORCH   = 29;// 列消隐后肩时间
`endif
//800x600 40Mhz`ifdefVIDEO_800_600parameterH_ACTIVE         = 800;// 行数据有效时间parameterH_FRONT_PORCH    = 40 ;// 行消隐前肩时间parameterH_SYNC_TIME      = 128;// 行同步信号时间parameterH_BACK_PORCH   = 88 ;// 行消隐后肩时间   
parameterV_ACTIVE         = 600;// 列数据有效时间parameterV_FRONT_PORCH    = 1;// 列消隐前肩时间parameterV_SYNC_TIME      = 4;// 列同步信号时间parameterV_BACK_PORCH   = 23 ;// 列消隐后肩时间
`endif
//640x480 25.175Mhz`ifdefVIDEO_640_480parameter H_ACTIVE          = 640; // 行数据有效时间parameter H_FRONT_PORCH   = 16 ; // 行消隐前肩时间parameter H_SYNC_TIME       = 96 ; // 行同步信号时间parameter H_BACK_PORCH      = 48 ; // 行消隐后肩时间
parameter V_ACTIVE          = 480; // 列数据有效时间parameter V_FRONT_PORCH   = 10 ; // 列消隐前肩时间parameter V_SYNC_TIME       = 2; // 列同步信号时间parameter V_BACK_PORCH      = 33 ; // 列消隐后肩时间`endif
parameterH_TOTAL_TIME   = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH; // 计算参数H_TOTAL_TIME的值parameterV_TOTAL_TIME   = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH; // 计算参数 V_TOTAL_TIME 的值
reg         en;reg h_syn_cnt = 'd0;reg v_syn_cnt = 'd0;reg [ 7:0]image ;reg image_cnt = 'd0;
// 行扫描计数器always@(posedge i_clk)begin    if(h_syn_cnt == H_TOTAL_TIME-1)      h_syn_cnt <= 0;    else      h_syn_cnt <= h_syn_cnt + 1;end
always@(posedge i_clk) // 列扫描计数器begin    if(h_syn_cnt == H_TOTAL_TIME-1) //h_syn_cnt计数达到设定值 H_TOTAL_TIME进入执行语句    begin      if(v_syn_cnt == V_TOTAL_TIME-1) //v_syn_cnt判断,目标值 V_TOTAL_TIM            v_syn_cnt <= 0; //达到目标,数值清零      else            v_syn_cnt <= v_syn_cnt + 1; //否则v_syn_cnt+1    endend
always@(posedge i_clk) // 行同步控制begin    if(h_syn_cnt < H_SYNC_TIME) // h_syn_cnt未达到H_SYNC_TIME计数值      o_hsyn <= 0; // o_hsyn信号控制置0    else      o_hsyn <= 1; // o_hsyn信号控制置1End
always@(posedge i_clk) // 场同步控制begin    if(v_syn_cnt < V_SYNC_TIME) // v_syn_cnt未达到V_SYNC_TIME计数值      o_vsyn <= 0; // o_vsyn信号控制置0    else      o_vsyn <= 1; // o_vsyn信号控制置1end
always@(posedge i_clk) // 坐标使能.begin    if(v_syn_cnt >= V_SYNC_TIME + V_BACK_PORCH && v_syn_cnt < V_SYNC_TIME + V_BACK_PORCH + V_ACTIVE)    begin      if(h_syn_cnt >= H_SYNC_TIME + H_BACK_PORCH && h_syn_cnt < H_SYNC_TIME + H_BACK_PORCH + H_ACTIVE)            en <= 1;      else            en <= 0;    end    else      en <= 0;end
//读取txt文件到image数组中initial begin    $readmemh("../matlab_src/image_720_1280_1.txt", image);end
always@(posedge i_clk)begin    if(en)    begin      o_r         <= image; // image中存储的图像数据依次写入o_r      image_cnt   <= image_cnt + 1; // 输出一个像素数据image_cnt+1,输入下一个    end    else if(image_cnt == H_ACTIVE*V_ACTIVE) // image_cnt的值增加到H_ACTIVE*V_ACTIVE时为一帧图像    begin      o_r         <= 8'h00; //o_r数据清零      image_cnt   <= 'd0; // image_cnt计数清零    end    else    begin      o_r         <= 8'h00;      image_cnt   <= image_cnt;    endend
always@(posedge i_clk)begin    o_en <= en;endendmodule
module top_tb;
reg             clk;reg             rst_n;
integer         image_txt;
reg       pixel_cnt;wire       data;wire            de;
top u_top(    .i_clk               (clk                ),    .i_rst_n             (rst_n            ),    .o_gray_data         (data               ),    .o_gray_de         (de               ));
always #(1) clk = ~clk;
initialbegin    clk   = 1;    rst_n = 0;    #100    rst_n = 1;
end
initialbegin    image_txt = $fopen("../matlab_src/image_720_1280_3_out.txt"); //打开存有图像数据的.txt文件end
always@(posedge clk or negedge rst_n) //敏感列表begin    if(!rst_n)    begin      pixel_cnt <= 0; //pixel_cnt计数清零    end    else if(de) //像素有效信号拉高时,pixel_cnt+1    begin      pixel_cnt = pixel_cnt + 1;      $fwrite(image_txt,"%h\n",data);    endend
always@(posedge clk )begin    if(pixel_cnt == 720*1280)    begin      $display("*******************************************************************************");            $display("*** Success:image_720_1280_3_out.txt is output complete! %t", $realtime, "ps***");      $display("*******************************************************************************");            $fclose(image_txt);      $stop;    endendendmodule


2.1信号声明testbench 模块声明时,一般不需要声明端口。因为激励信号一般都在 testbench 模块内部,没有外部信号。声明的变量应该能全部对应被测试模块的端口。当然,变量不一定要与被测试模块端口名字一样。但是被测试模块输入端对应的变量应该声明为 reg 型,如 时钟,复位等,输出端对应的变量应该声明为 wire 型,如 data,de。2.2时钟生成生成时钟的方式有很多种,举例以下这种生成方式可以借鉴。例:
always #(1) clk = ~clk; //时钟翻转,前面的时钟周期可以根据情况自行调整initialbegin    clk   = 1; //时钟赋初值    rst_n = 0;   //复位赋初值    #100    rst_n = 1; //复位赋完成,恢复高电平
end


需要注意的是,利用取反方法产生时钟时,一定要给 clk 寄存器赋初值。2.3复位生成复位逻辑比较简单,一般赋初值为 0,再经过一段小延迟后,复位为 1 即可。例:
initialbegin    clk   = 1;    rst_n = 0;    #100    rst_n = 1;end


2.4激励部分激励部分该产生怎样的输入信号,是根据被测模块的需要来设计的。本例中采用读取已有的图像数据,按照时序要求读到程序中,生成激励波形。
initial begin    $readmemh("../matlab_src/image_720_1280_1.txt", image);end


2.5模块例化利用 testbench 开始声明的信号变量,对被测试模块进行例化连接。
top u_top(    .i_clk                   (clk                ),    .i_rst_n               (rst_n            ),    .o_gray_data             (data               ),    .o_gray_de               (de               ));


2.6打印信息
always@(posedge clk )begin    if(pixel_cnt == 720*1280)    begin      $display("*******************************************************************************");            $display("*** Success:image_720_1280_3_out.txt is output complete! %t", $realtime, "ps***");      $display("*******************************************************************************");            $fclose(image_txt);      $stop;    endend



通过打印关键仿真信息,能让我们自动化操作仿真过程。
页: [1]
查看完整版本: 12 Verilog语法_仿真文件设计