基于Modelsim的视频流仿真
一、前言
最近在看牟新刚写的《基于FPGA的数字图像处理原理及应用》,书中关于FPGA数字图像处理的原理的原理写的非常透彻,在网上寻找了很久都没有找到完整的源代码工程,因此尝试自己做了补充/仿真,并与书中结果进行了比对。2020-02-16 15:40:21
二、视频时序模拟
如图一所示,为参考书中的代码及说明整理出来的时序图,其中仿真视频图像宽度(IW=640),高度(IH=512),sync_b为场前肩参数,sync_e为场同步脉冲参数,vld为场后肩参数。从时序图中可以看出dvsync标记了一副新图像的起始点,书中并没有标记图像传输结束到下一帧图像开始(图像的场前肩)需要多少时间,通过v_total可以计算出有23行图像的时间(不知道实际场景下这个参数是否也是按照v_total来换算)。同理书中也没有标注sync_h(行消隐脉冲的时间),通过计算可知为(h_total-640)=800个像素时钟。
三、代码注解与分析
(1)image_src.v文件分析,该部分代码主要用于实现图一中视频流的模拟时序包括行/场信号的生成及像素数据的生成。
/*
***********************************************************************************************************
** Input file: None
** Component name: image_src.v
** Author: zhengXiaoliang
** Company: WHUT
** Description: to simulate dvd stream
***********************************************************************************************************
*/ `timescale 1ns/1ns `define SEEK_SET 0
`define SEEK_CUR
`define SEEK_END module image_src(
reset_l, //全局复位
clk, //同步时钟
src_sel, //数据源通道选择
test_vsync, //场同步输出
test_dvalid, //像素有效输出
test_data, //像素数据输出
clk_out //像素时钟输出
); parameter iw = ; //默认视频宽度
parameter ih = ; //默认视频高度
parameter dw = ; //默认像素数据位宽 parameter h_total = ; //行总数
parameter v_total = ; //垂直总数 parameter sync_b = ; //场前肩
parameter sync_e = ; //场同步脉冲
parameter vld_b = ; //场后肩 //port decleared
input reset_l,clk;
input [:] src_sel; //to select the input file
output test_vsync, test_dvalid,clk_out;
output [dw-:] test_data; //variable decleared
reg [dw-:] test_data_reg;
reg test_vsync_temp;
reg test_dvalid_tmp;
reg [:] test_dvalid_r; reg [:] h_cnt;
reg [:] v_cnt; integer fp_r;
integer cnt = ; //输出像素时钟
assign clk_out = clk; //output the dv clk //输出像素数据
assign test_data = test_data_reg; //test data output //当行同步有效时,从文件读取像素数据输出到数据线上
always@(posedge clk or posedge test_vsync_temp)begin
if(((~(test_vsync_temp))) == 'b0) //场同步清零文件指针
cnt <= ; //clear file pointer when a new frame comes
else begin
if(test_dvalid_tmp == 'b1)begin //行同步有效,说明当前时钟数据有效
case(src_sel) //选择不同的数据源
'b0000: fp_r = $fopen("E:/Modelsim/image_src/txt_source/test_src3.txt","r");
'b0001: fp_r = $fopen("txt_source/test_scr1.txt","r");
'b0010: fp_r = $fopen("txt_source/test_scr2.txt","r");
'b0011: fp_r = $fopen("txt_source/test_scr3.txt","r");
'b0100: fp_r = $fopen("txt_source/test_scr4.txt","r");
'b0101: fp_r = $fopen("txt_source/test_scr5.txt","r");
'b0110: fp_r = $fopen("txt_source/test_scr6.txt","r");
'b0111: fp_r = $fopen("txt_source/test_scr7.txt","r");
'b1000: fp_r = $fopen("txt_source/test_scr8.txt","r");
'b1001: fp_r = $fopen("txt_source/test_scr9.txt","r");
'b1010: fp_r = $fopen("txt_source/test_scr10.txt","r");
'b1011: fp_r = $fopen("txt_source/test_scr11.txt","r");
'b1100: fp_r = $fopen("txt_source/test_scr12.txt","r");
'b1101: fp_r = $fopen("txt_source/test_scr13.txt","r");
'b1110: fp_r = $fopen("txt_source/test_scr14.txt","r");
'b1111: fp_r = $fopen("txt_source/test_scr15.txt","r");
default: fp_r = $fopen("txt_source/test_src3.txt","r");
endcase $fseek(fp_r,cnt,`SEEK_SET); //查找当前需要读取的文件位置
$fscanf(fp_r,"%02x\n",test_data_reg); //将数据按指定格式读入test_data_reg寄存器 cnt <= cnt + ; //移动文件指针到下一个数据
$fclose(fp_r); //关闭文件
$display("h_cnt = %d,v_cnt = %d, pixdata = %d",h_cnt,v_cnt,test_data_reg); //for debug use
end
end
end //水平计数器,每来一个时钟就+1,加到h_total置零重新计数
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
h_cnt <= # {{'b0}};
else begin
if(h_cnt == ((h_total -)))
h_cnt <= # {{'b0}};
else
h_cnt <= # h_cnt + 'b00000000001;
end
end //垂直计数器:水平计数器计满后+1,计满后清零
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
v_cnt <= # {{'b0}};
else begin
if(h_cnt == ((h_total - )))begin
if(v_cnt == ((v_total - )))
v_cnt <= # {{'b0}};
else
v_cnt <= # v_cnt + 'b00000000001;
end
end
end //场同步信号生成
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_vsync_temp <= # 'b1;
else begin
if(v_cnt >= sync_b & v_cnt <= sync_e)
test_vsync_temp <= # 'b1;
else
test_vsync_temp <= # 'b0;
end
end assign test_vsync = (~test_vsync_temp); //水平同步信号生成
always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_dvalid_tmp <= # 'b0;
else begin
if(v_cnt >= vld_b & v_cnt < ((vld_b + ih)))begin
if(h_cnt == 'b0000000000)
test_dvalid_tmp <= # 'b1;
else if(h_cnt == iw)
test_dvalid_tmp <= # 'b0;
end
else
test_dvalid_tmp <= # 'b0;
end
end //水平同步信号输出
assign test_dvalid = test_dvalid_tmp; always@(posedge clk or negedge reset_l)begin
if(((~(reset_l))) == 'b1)
test_dvalid_r <= # 'b00;
else
test_dvalid_r <= # ({test_dvalid_r[],test_dvalid_tmp});
end endmodule
(2)视频流仿真代码image_src_tb.v的补充编写。
`timescale 1ns/1ns module image_src_tb; parameter iw = ; //图像宽度
parameter ih = ; //图像高度
parameter dvd_dw = ; //数据位宽 //视频时序参数
parameter h_total = ;
parameter v_total = ;
parameter sync_b = ;
parameter sync_e = ;
parameter vld_b = ; reg clk;
reg reset_l; wire dv_clk;
wire dvsyn;
wire dhsyn;
wire [dvd_dw-:] dvd; /*根据时序参数例化一个视频源*/
image_src #(iw,ih,dvd_dw,h_total,v_total,sync_b,sync_e,vld_b)
image_src_ins(
.clk(clk),
.reset_l(reset_l),
.src_sel('b0000),
.test_data(dvd),
.test_dvalid(dhsyn),
.test_vsync(dvsyn),
.clk_out(dv_clk)
); initial begin
clk = ;
reset_l = ;
#;
reset_l = ;
#;
reset_l = ;
end //时钟产生:≈51.84MHz
always@(reset_l or clk)begin
if((~(reset_l)) == 'b1)
clk <= 'b0;
else
clk <= # (~(clk));
end endmodule
(3)视频码流文件的生成,由于书中并没有描述如何生成视频码流的文件,因此用Maltab编写了一个rgb2txt文件,生成了一份码流文件经过测试可用。
%将256位的BMP灰度图像128*128大小生成TXT文档;
clc
close all I_rgb = imread('lena_512x512.jpg');
subplot(1,3,1),imshow(I_rgb),title('lena-rgb') I_gray = rgb2gray(I_rgb);
subplot(1,3,2),imshow(I_gray),title('lena-gray') %% 改变图像尺寸
I_resize = imresize(I_gray,[640 512],'nearest');%nearest(默认值) 最近邻插值 ‘bilinear’双线性插值 ‘bicubic’ 双三次插值
% I = imresize(I_gray,0.25);
% subplot(1,3,3),imshow(I),title('lena-qtr') fid = fopen('./lena_640x512_hex.txt','wt');
for i = 1:size(I_resize,1)
for j = 1:size(I_resize,2)
fprintf(fid,'%2x\n',I_resize(i,j));%每个数据之间用空格分开
end
%fprintf(fid,'\n');
end fid = fclose(fid);
I_data = load('./lena_640x512.txt');
(4)用于Modelsim仿真的.do文件的编写,image_src.do代码如下:
#切换至工程目录
cd E:/Modelsim/image_src #打开工程
project open E:/Modelsim/image_src #编译相关文件(一般情况下为频繁改动的文件)
vlog E:/Modelsim/image_src/image_src.v
vlog E:/Modelsim/image_src/image_src_tb.v #开始仿真
vsim -novopt -L altera_lib work.image_src_tb #添加顶层所有的信号
add wave * #取消警告
set StdArithNoWarnings #开始运行
run -all
四、仿真结果
如图二所示,为测试仿真结果与书中仿真结果图像一致。
基于Modelsim的视频流仿真的更多相关文章
- 基于Modelsim的直方图统计算法仿真
一.前言 本篇主要针对牟新刚编著<基于FPGA的数字图像处理及应用>第六章第五节中直方图统计相关类容进行总结,包括代码实现及 基于Modelsim的仿真.书读百遍,其意自现. 2020-0 ...
- Modelsim使用流程---基于TCL命令的仿真
Modelsim使用流程---基于TCL命令的仿真 本文使用的Modelsim版本为Modelsim SE-64 10.1.c 1.File -> new -> Project 2.添加或 ...
- 基于modelsim-SE的简单仿真流程—下
基于modelsim-SE的简单仿真流程—下 编译 在 WorkSpace 窗口的 counter_tst.v上点击右键,如果选择Compile selected 则编译选中的文件,Compile A ...
- 基于modelsim-SE的简单仿真流程—上
基于modelsim-SE的简单仿真流程 编写RTL功能代码 要进行功能仿真,首先得用需要仿真的模块,也就是RTL功能代码,简称待测试的模块,该模块也就是在设计下载到FPGA的电路.一个电路模块想要有 ...
- 通过文件读写方式实现Matlab和Modelsim的联合仿真
虽然Modelsim的功能非常强大,仿真的波形可以以多种形式进行显示,但是当涉及到数字信号处理的算法的仿真验证的时候,则显得有点不足.而进行数字信号处理是Matlab的强项,不但有大量的关于数字信号处 ...
- vivado和modelsim联合调试仿真
vivado和modelsim联合调试仿真 0赞 发表于 2017/5/10 19:10:59 阅读(881) 评论(0) 使用vivado和modelsim联合调试仿真时,在破解完modelsim后 ...
- Modelsim SE自动化仿真——如何将.do文件中自定义的库链接到testbench顶层模块
我们用Modelsim SE进行仿真时,为了方便,一般会编写.do文件来启动当前仿真.关于.do文件的编写,一般网上都有成型的模板,我们只要稍微改几个参数,就可以符合我们的仿真需求了.但是如果仿真时需 ...
- 用Modelsim SE 直接仿真 Altera(Intel PSG) IP核 需要注意的问题
如果我们直接用Modelsim SE仿真 Altera IP核,首先会进入Quartus II目录下找到IP核对应的仿真库源文件,然后在Modelsim SE中进行编译,添加到Modelsim SE的 ...
- vivado与modelsim的联合仿真(二)
最近在做Zynq的项目,曾经尝试使用ISE+PlanAhead+XPS+SDK组合和Vivado+SDK来搭建工程,使用中发现前者及其不方便后者有诸多不稳定.近期得闻Xilinx退出Vivado20 ...
随机推荐
- python 的头文件包含问题
一个python项目中一个文件需要引用另一个文件中的类,遇到的几个问题,总结如下: 0x01 情况一:在同一目录下 project |--a.py |--b.py |--main.py 在main.p ...
- js和jsp中怎么去获取后台 model.addAttribute()存入的list<。。。>对象
java 后台List productionGroupList =getProductionGroupList(); model.addAttribute("productionGroupL ...
- HttpClient的CircularRedirectException解决办法
解决方法: HttpGet httpGet = new HttpGet(" http://XXXX.XXX"); httpGet.getParams().setParameter( ...
- python基础之函数,递归,内置函数
一.数学定义的函数与python中的函数 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因 ...
- Python函数基础进阶
函数参数的另一种使用方式 def print_info(name,age): print("Name: %s" %name) print("age: %d" % ...
- MAC Address-Table Move Update Feature
MAC Address-Table Move Update The MAC address-table move update feature allows the switch to provide ...
- PS绘制Logo
1. 2. 3. 4. 5. 6. 第2步点击“圆1”应点击图层左边的缩览图才能获取选区 7. 8. 9. 10. 11. 12.
- POJ 1061 青蛙的约会(exgcd)
嗯... 题目链接:http://poj.org/problem?id=1061 两只青蛙相遇时肯定满足:x+k*m≡y+k*n(mod L) x+k*m-(y+k*n)=L*s k*(n-m)-s* ...
- 页面弹窗toast和加载loading
create-at 2019-04-04 都采用单例模式,原生js实现 兼容老版本浏览器内核,请将用es6语法的地方作修改 loading 加载 代码: 样式全部通过js创建style标签注入head ...
- 实现一个简易的Unity网络同步引擎——netgo
实现一个简易的Unity网络同步引擎Netgo 目前GOLANG有大行其道的趋势,尤其是在网络编程方面.因为和c/c++比较起来,虽然GC占用了一部分机器性能,但是出错概率小了,开发效率大大提升,而且 ...