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, //输入复位 output wire o_gray_hsyn, //输出hs信号 output wire o_gray_vsyn, //输出vs信号 output wire [7:0] o_gray_data, //输出data数据信号 output wire o_gray_de //输出de像素有效信号 ); wire i_hsyn; wire i_vsyn; wire [7:0] i_r; wire [7:0] i_g; wire [7:0] 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 ) ); endmodule module gray2binary_algorithm ( input wire i_clk, input wire i_hsyn, input wire i_vsyn, input wire [7:0] i_r, input wire [7:0] i_g,//don't care input wire [7:0] i_b,//don't care input wire i_de, output wire o_gray_hsyn, output wire o_gray_vsyn, output wire [7:0] o_gray_data, output wire o_gray_de );
//Binarization assign 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_480 module sim_image_tpg( input wire i_clk, output reg o_hsyn, output reg o_vsyn, output reg o_en, output reg [7:0] o_r, output reg [7:0] o_g, output reg [7:0] o_b );
//1920x1080 148.5Mhz `ifdef VIDEO_1920_1080 parameter H_ACTIVE = 1920;// 行数据有效时间 parameter H_FRONT_PORCH = 88; // 行消隐前肩时间 parameter H_SYNC_TIME = 44; // 行同步信号时间 parameter H_BACK_PORCH = 148; // 行消隐后肩时间
parameter V_ACTIVE = 1080;// 列数据有效时间 parameter V_FRONT_PORCH = 4; // 列消隐前肩时间 parameter V_SYNC_TIME = 5; // 列同步信号时间 parameter V_BACK_PORCH = 36; // 列消隐后肩时间 `endif
//1680x1050 119Mhz `ifdef VIDEO_1680_1050 parameter H_ACTIVE = 1680;// 行数据有效时间 parameter H_FRONT_PORCH = 48; // 行消隐前肩时间 parameter H_SYNC_TIME = 32; // 行同步信号时间 parameter H_BACK_PORCH = 80; // 行消隐后肩时间
parameter V_ACTIVE = 1050;// 列数据有效时间 parameter V_FRONT_PORCH = 3; // 列消隐前肩时间 parameter V_SYNC_TIME = 6; // 列同步信号时间 parameter V_BACK_PORCH = 21; // 列消隐后肩时间 `endif
//1280x1024 108Mhz `ifdef VIDEO_1280_1024 parameter H_ACTIVE = 1280;// 行数据有效时间 parameter H_FRONT_PORCH = 48; // 行消隐前肩时间 parameter H_SYNC_TIME = 112; // 行同步信号时间 parameter H_BACK_PORCH = 248; // 行消隐后肩时间
parameter V_ACTIVE = 1024;// 列数据有效时间 parameter V_FRONT_PORCH = 1; // 列消隐前肩时间 parameter V_SYNC_TIME = 3; // 列同步信号时间 parameter V_BACK_PORCH = 38; // 列消隐后肩时间 `endif
//1280X720 74.25MHZ `ifdef VIDEO_1280_720 parameter H_ACTIVE = 1280;// 行数据有效时间 parameter H_FRONT_PORCH = 110; // 行消隐前肩时间 parameter H_SYNC_TIME = 40; // 行同步信号时间 parameter H_BACK_PORCH = 220; // 行消隐后肩时间
parameter V_ACTIVE = 720; // 列数据有效时间 parameter V_FRONT_PORCH = 5; // 列消隐前肩时间 parameter V_SYNC_TIME = 5; // 列同步信号时间 parameter V_BACK_PORCH = 20; // 列消隐后肩时间 `endif
//1024x768 65Mhz `ifdef VIDEO_1024_768 parameter H_ACTIVE = 1024;// 行数据有效时间 parameter H_FRONT_PORCH = 24; // 行消隐前肩时间 parameter H_SYNC_TIME = 136; // 行同步信号时间 parameter H_BACK_PORCH = 160; // 行消隐后肩时间
parameter V_ACTIVE = 768; // 列数据有效时间 parameter V_FRONT_PORCH = 3; // 列消隐前肩时间 parameter V_SYNC_TIME = 6; // 列同步信号时间 parameter V_BACK_PORCH = 29; // 列消隐后肩时间
`endif
//800x600 40Mhz `ifdef VIDEO_800_600 parameter H_ACTIVE = 800;// 行数据有效时间 parameter H_FRONT_PORCH = 40 ;// 行消隐前肩时间 parameter H_SYNC_TIME = 128;// 行同步信号时间 parameter H_BACK_PORCH = 88 ;// 行消隐后肩时间
parameter V_ACTIVE = 600;// 列数据有效时间 parameter V_FRONT_PORCH = 1 ;// 列消隐前肩时间 parameter V_SYNC_TIME = 4 ;// 列同步信号时间 parameter V_BACK_PORCH = 23 ;// 列消隐后肩时间
`endif
//640x480 25.175Mhz `ifdef VIDEO_640_480 parameter 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
parameter H_TOTAL_TIME = H_ACTIVE + H_FRONT_PORCH + H_SYNC_TIME + H_BACK_PORCH; // 计算参数H_TOTAL_TIME的值 parameter V_TOTAL_TIME = V_ACTIVE + V_FRONT_PORCH + V_SYNC_TIME + V_BACK_PORCH; // 计算参数 V_TOTAL_TIME 的值
reg en; reg [12:0] h_syn_cnt = 'd0; reg [12:0] v_syn_cnt = 'd0; reg [ 7:0] image [0 : H_ACTIVE*V_ACTIVE-1]; reg [31:0] 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 end end
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信号控制置1 End
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信号控制置1 end
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_cnt]; // 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; end end
always@(posedge i_clk) begin o_en <= en; end endmodule
module top_tb;
reg clk; reg rst_n;
integer image_txt;
reg [31:0] pixel_cnt; wire[7:0] 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;
initial begin clk = 1; rst_n = 0; #100 rst_n = 1;
end
initial begin 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); end end
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; end end endmodule |
2.1信号声明
testbench 模块声明时,一般不需要声明端口。因为激励信号一般都在 testbench 模块内部,没有外部信号。
声明的变量应该能全部对应被测试模块的端口。当然,变量不一定要与被测试模块端口名字一样。但是被测试模块输入端对应的变量应该声明为 reg 型,如 时钟,复位等,输出端对应的变量应该声明为 wire 型,如 data,de。
2.2时钟生成
生成时钟的方式有很多种,举例以下这种生成方式可以借鉴。
例:
always #(1) clk = ~clk; //时钟翻转,前面的时钟周期可以根据情况自行调整 initial begin clk = 1; //时钟赋初值 rst_n = 0; //复位赋初值 #100 rst_n = 1; //复位赋完成,恢复高电平
end |
需要注意的是,利用取反方法产生时钟时,一定要给 clk 寄存器赋初值。
2.3复位生成
复位逻辑比较简单,一般赋初值为 0,再经过一段小延迟后,复位为 1 即可。
例:
initial begin 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; end end |
通过打印关键仿真信息,能让我们自动化操作仿真过程。
本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/17950375