[X]关闭

12 Verilog语法_仿真文件设计

文档创建者:uisrc
浏览次数:318
最后更新:2024-01-07
FPGA基础知识
FPGA基础: FPGA编程语言 » 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



通过打印关键仿真信息,能让我们自动化操作仿真过程。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则