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]