问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 38 人浏览分享

开启左侧

第十二课 Verilog 语法_仿真文件设计

[复制链接]
38 0
AMD-FPGA课程
AMD课程: 04-FPGA语法和硬件基础 » X
1 概述
       本小节讲解 Verilog 语法的仿真文件设计,需要掌握 testbench 的建立方法。

2 仿真文件设计
       当完成 verilog 工程设计后,首先需要进行就是仿真文件的设计,仿真文件又称为 testbench,测试激励。
       Testbench 文件内容往往包含以下几种:
       (1) 信号变量声明。
       (2) 时钟与复位信号的生成。
       (3) 被测试模块接口信号的波形激励生成。
       (4) 被测试模块的例化。
       (5) 被测试模块接口数据的校验模块。
       (6) 打印仿真信息。
       例:
module top(
input wirei_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 型,如 datade


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
       通过打印关键仿真信息,能让我们自动化操作仿真过程。




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

本版积分规则

0

关注

10

粉丝

114

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版