0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

图像处理:HDMI显示代码的UVM仿真

电子设计 来源:AI加速 作者:AI加速 2020-11-10 15:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本篇完成对HDMI显示代码的UVM仿真,梳理一下在windows-modelsim工具下UVM仿真环境的建立,调试以及遇到的问题。

仿真架构

仿真的架构在上一篇已经做了简要介绍,这部分做重点讲解。整体结构包括五个功能模块:image图像的随机化和驱动,软件端配置,图像监测,以及设计部分。如图1.1所示。

图1.1 UVM仿真验证架构

图1.1 UVM仿真验证架构

img_seq

这部分主要是生成image数据,并发送给img_drv,由img_drv驱动给到DUT。Image的随机化定义在img_trans中,这个类继承了uvm_sequence_item,定义了img数组,这是一个随机化的8bit数据组成的数组。在img_seq中通过randomize函数就可以产生随机化数据。

class img_trans extends uvm_sequence_item;

rand logic[7:0] img[3*`MAX_RESLUTN_H*`MAX_RESLUTN_V];

Endclass

Img_seq中对整个仿真的启动和结束做了控制,在这部分实现的原因是保证一帧图像在仿真过程中的完整性。通过设置run_time来控制可以发送多少帧图像,这个变量从命令行传进去。Starting_phase可以使得在uvm_sequence中来启动和终止仿真过程,只要指定了相应的sequence是某个sequencer的default_sequence,以及在sequencer中设置seq的starting_phase为sequencer的phase,这样就可以用sequence来启动仿真了。

if(starting_phase != null)
starting_phase.raise_objection(this);
else
`uvm_error(get_type_name(), "cannot start phase");

for(int i=0;i `uvm_create(trans)
if(trans.randomize() != 1)begin
`uvm_info(get_type_name(), "Failed to randomize image transaction", UVM_NONE)
end
trans.print();
`uvm_send(trans)
`uvm_info(get_type_name(), "one image have been recived", UVM_NONE)
wait(sw_inf_i.intr == 1);

end

#50;
starting_phase.drop_objection(this);

img_sqr.sv中:

virtual task main_phase(uvm_phase phase);
img_seq seq;
seq = img_seq::type_id::create("img_seq");
seq.starting_phase = phase;
seq.start(this);
endtask

img_drv

这个模块是通过img_sqr从img_seq中获得img的数据,然后通过axi接口发送给DUT。这部分主要是如何对接DUT的AXI接口,DUT通过AXI接口读取image数据,因此接口功能只实现了读操作。用一个task来实现axi_read,主要包括三个并行进程:一个是获取axi读指令,另一个是根据获得的axi读指令来发送数据,最后增加一个计数器用于处理axi等待时间过长的问题,如果超过一定时间,就报错。指令获取和发送数据的交互通过mailbox来实现,只要收到的axi指令不大于AXI接口可接收的最大transactions,就可以继续接收,否则就不接受。然后发送数据进程从mailbox中获得指令,根据指令发送对应的数据。

task img_drv::axi_read();

int abs_araddr;
int arlen_cnt;
ar_trans ar_req;
ar_trans ar_rep;
int ar_timer;
int i_size = img_size;

fork: AXI_READ_CTRL

forever begin: AR
if(ar_mbx.num() axi.s_axi_arready = 1'b1;
else
axi.s_axi_arready = 1'b0;

if(axi.s_axi_arready & axi.s_axi_arvalid)begin
ar_req = new("ar_trans");
ar_req.araddr = axi.s_axi_araddr;
ar_req.arlen = axi.s_axi_arlen;
ar_req.arid = axi.s_axi_arid;

ar_mbx.put(ar_req);
end

@(posedge axi.clk);
end

forever begin: RDATA
ar_timer = $urandom_range(`AXI_WAIT_TIMER, 0);
while(ar_timer--)
@(posedge axi.clk);

if(ar_mbx.num() == 0)begin
axi.s_axi_rvalid = 1'b0;
@(posedge axi.clk);
wait(ar_mbx.num() > 0);
end
else begin
while(!axi.s_axi_rready)
@(posedge axi.clk);

axi.s_axi_rvalid = 1'b1;

ar_mbx.get(ar_rep);
abs_araddr = ar_rep.araddr - img_start_addr;
arlen_cnt = ar_rep.arlen + 1;

if(ar_rep.araddr[10:0]+arlen_cnt*(`AXI_DATA_WD/8)>4096)begin
`uvm_error(this.get_type_name(), $sformatf("cross 4KB at address: ar_rep.araddr"));
end

while(arlen_cnt)begin
if(axi.s_axi_rready)begin
for(int i=0;i axi.s_axi_rdata[i*8 +: 8] = img_req.img[abs_araddr++];
end

arlen_cnt--;
end

if(arlen_cnt == 0)begin
axi.s_axi_rlast = 1'b1;
end

@(posedge axi.clk);

end
axi.s_axi_rlast = 1'b0;
axi.s_axi_rvalid = 1'b0;
@(posedge axi.clk);
end
end//RDATA

while(i_size)begin
if(axi.s_axi_rvalid & axi.s_axi_rready)begin
i_size--;
end
@(posedge axi.clk);
end

join_any

disable AXI_READ_CTRL;

endtask

sw_config

这部分主要是涉及到软件端对寄存器的配置,包括图像的行列大小,blank的行和列大小等。这些变量在sw_trans中随机化,为了减少仿真时间,作者减小了图像的大小约束。这应该不会影响仿真验证结果。Sw_seq就是产生随机化数据,然后发送给sw_drv。Sw_driver主要是实现axi4lite接口,发送数据给DUT。Axi4lite控制比较简单,如下:

task sw_driver::axi4lite_write(logic [`AXI4LITE_DATA_WD-1:0] data, logic [`AXI4LITE_ADDR_WD-1:0] waddr);
int timer = 1000;

repeat($urandom_range(15, 5)) @(posedge vif.axi_if.clk);
fork: AXI4LITE_SEND
begin: WRITE_DATA
vif.axi_if.axi4lite_awprot = 0;
vif.axi_if.axi4lite_awaddr = waddr;
vif.axi_if.axi4lite_awvalid = 1'b1;
if(!vif.axi_if.axi4lite_awready)begin
while(!vif.axi_if.axi4lite_awready)
@(posedge vif.axi_if.clk);
end
else begin
@(posedge vif.axi_if.clk);
end
vif.axi_if.axi4lite_awvalid = 1'b0;
repeat($urandom_range(5, 0)) @(posedge vif.axi_if.clk);

vif.axi_if.axi4lite_wdata = data;
vif.axi_if.axi4lite_wstrb = {(`AXI4LITE_DATA_WD/8){1'b1}};
vif.axi_if.axi4lite_wvalid = 1'b1;
if(!vif.axi_if.axi4lite_wready)begin
while(!vif.axi_if.axi4lite_wready)
@(posedge vif.axi_if.clk);
end
else begin
@(posedge vif.axi_if.clk);
end
vif.axi_if.axi4lite_wvalid = 1'b0;
wait(vif.axi_if.axi4lite_bvalid);
repeat($urandom_range(5, 0)) @(posedge vif.axi_if.clk);
end

begin: TIMER_CNT
while(timer--)
@(posedge vif.axi_if.clk);
`uvm_error(get_type_name(), $sformatf("wait for axi ready for long: axi4lite_awaddr = %0h, axi4lite_awready = %0d",
vif.axi_if.axi4lite_awaddr, vif.axi_if.axi4lite_awready));
end
join_any

disable AXI4LITE_SEND;
`uvm_info(get_type_name(), $sformatf("have sent sw data at address: %0x", vif.axi_if.axi4lite_awaddr), UVM_MEDIUM);
Endtask

为了将sw_trans的数据发送给其他模块,在sw_driver中通过定义:

uvm_analysis_port #(sw_trans) sw_trans_port;

在需要接收这个数据的类中声明一个port:

uvm_analysis_imp_sw #(sw_trans, img_monitor) sw_imp;

并声明后缀:

`uvm_analysis_imp_decl(_sw)

然后定义一个write函数:

function void img_monitor::write_sw(sw_trans sw_req);

img_h = sw_req.resl_h;
img_v = sw_req.resl_v;

endfunction

这样就接收到了来自sw_trans的数据。

img_monitor

这部分主要是比对数据,包括两方面,一个是比对接收到的image的图像数据R,G,B。另外一个是比对经过物理编码后的10bit的R,G,B数据。

task img_monitor::comp_rgb();
localparam AXI_DATA_BW = `AXI_DATA_WD/8;

logic [8*3-1:0] ref_rgb;
int err_cnt = 0;

int pixs;
int v=0;
int h=0;

while(v != img_v)begin
if(img_inf_i.rgb_valid && img_inf_i.rgb_ready && img_inf_i.h_sync && img_inf_i.v_sync)begin
pixs = 3 * (img_h * v + h);

ref_rgb = {img_data.img[pixs+2], img_data.img[pixs+1], img_data.img[pixs]};

if(ref_rgb != img_inf_i.rgb)begin
`uvm_error(this.get_type_name(), $sformatf("ref_rgb(%h, %h, %h) is diffrent with rgb(%h, %h, %h) at (%d, %d)", ref_rgb[8*2 +: 8], ref_rgb[8*1 +: 8], ref_rgb[7:0], img_inf_i.rgb[8*2 +: 8], img_inf_i.rgb[8*1 +: 8], img_inf_i.rgb[7:0], v, h));

err_cnt++;
end
@(posedge img_inf_i.clk);
v = (h >= img_h - 1) ? v+1 : v;
h = (h >= img_h - 1) ? h-img_h+1 : h+1;

end
else begin
@(posedge img_inf_i.clk);
end
end

if(err_cnt == 0)
`uvm_info(get_type_name(), "rgb comparison passed !", UVM_LOW)

Endtask

对物理编码数据的比较,是UVM中生成对应的数据,放到队列中,然后和DUT中的相应数据进行对比。

function void img_monitor::write_img(img_trans img_req);

localparam AXI_DATA_BW = `AXI_DATA_WD/8;
int pixs = 0;
tmds tmds_obj;

img_data.copy(img_req);

for(int i=0;i for(int j=0;j tmds_obj = new("tmds");
pixs = 3 * (i * img_h + j);
tmds_obj.b = img_data.img[pixs];
tmds_obj.g = img_data.img[pixs+1];
tmds_obj.r = img_data.img[pixs+2];

tmds_obj.b = tmds_encode(tmds_obj.b, this.b_cnt);
tmds_obj.g = tmds_encode(tmds_obj.g, this.g_cnt);
tmds_obj.r = tmds_encode(tmds_obj.r, this.r_cnt);

tmds_obj.h = j;
tmds_obj.v = i;

tmds_i.push_back(tmds_obj);
end

this.b_cnt = 0;
this.g_cnt = 0;
this.r_cnt = 0;

end

endfunction

task img_monitor::comp_tmds();

localparam PREAMBLE_VIDEO = {10'b1101010100, 10'b0010101011, 10'b0101010100};//'h3542AD54
int v = 0;
int h = 0;
tmds ref_tmds_obj = new("tmds");

while(v != img_v)begin

wait(img_inf_i.tmds_valid && img_inf_i.tmds_data == PREAMBLE_VIDEO);
@(posedge img_inf_i.clk);
for(int i=0;i if(img_inf_i.tmds_data != PREAMBLE_VIDEO)
`uvm_error(get_type_name(), "video preamble is wrong!")
@(posedge img_inf_i.clk);
end
repeat(2) @(posedge img_inf_i.clk);

for(h=0;h ref_tmds_obj = tmds_i.pop_front();
if(ref_tmds_obj.b != img_inf_i.tmds_data[9:0] || ref_tmds_obj.g != img_inf_i.tmds_data[19:10] || ref_tmds_obj.r != img_inf_i.tmds_data[29:20])
`uvm_error(this.get_type_name(), $sformatf("ref_tmds ( %h, %h, %h) != tmds (%h, %h, %h) at (%d, %d)", ref_tmds_obj.r, ref_tmds_obj.g, ref_tmds_obj.b, img_inf_i.tmds_data[29:20], img_inf_i.tmds_data[19:10], img_inf_i.tmds_data[9:0], v, h));

@(posedge img_inf_i.clk);
v = (h >= img_h - 1) ? v+1 : v;
end
end

`uvm_info(get_type_name(), "tmds data is compared for one frame!", UVM_LOW)
Endtask

结果

通过打印信息来判断是否通过测试。

图2.1 仿真结果

图2.1 仿真结果

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • HDMI
    +关注

    关注

    34

    文章

    1875

    浏览量

    158873
  • 图像处理
    +关注

    关注

    28

    文章

    1340

    浏览量

    59183
  • UVM
    UVM
    +关注

    关注

    0

    文章

    183

    浏览量

    19947
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何用FPGA控制ADV7513实现HDMI画面显示和音频播放

    HDMI接口显示使用DMT时序+TMDS编码来实现。当用FPGA控制HDMI的数据传输时,通常可以采用纯RTL实现TMDS算法或者使用专门的HDMI芯片(如ADV7513)这两种方案来
    的头像 发表于 12-02 11:05 2954次阅读
    如何用FPGA控制ADV7513实现<b class='flag-5'>HDMI</b>画面<b class='flag-5'>显示</b>和音频播放

    HDMI 2.2最新显示接口标准深度解析

    本文深入探讨了HDMI 2.2 物理层演进以及这些标准如何推动下一代高分辨率、高带宽显示应用。
    的头像 发表于 10-15 15:04 1880次阅读
    <b class='flag-5'>HDMI</b> 2.2最新<b class='flag-5'>显示</b>接口标准深度解析

    NVMe高速传输之摆脱XDMA设计24: UVM 验证包设计

    UVM 验证包的主要功能是对 DUT 提供激励, 仿真验证对应的功能, 并对测试结果进行自动对比分析与统计。 验证包包含一个NoPHAE_env 验证环境, 验证环境下包含
    的头像 发表于 09-14 11:29 4511次阅读
    NVMe高速传输之摆脱XDMA设计24: <b class='flag-5'>UVM</b> 验证包设计

    NVMe高速传输之摆脱XDMA设计23:UVM验证平台

    抽象为 PCIeTLP 事务,因此为了方便的在事务层构建复杂的测试用例,项目基于 UVM 搭建验证平台进行功能验证。图1 验证平台架构图在验证平台中将 PCIE 集成块从待测试设计(Design
    发表于 08-26 09:49

    NVMe高速传输之摆脱XDMA设计18:UVM验证平台

    抽象为 PCIeTLP 事务,因此为了方便的在事务层构建复杂的测试用例,项目基于 UVM 搭建验证平台进行功能验证。图1 验证平台架构图在验证平台中将 PCIE 集成块从待测试设计(Design
    发表于 07-31 16:39

    请问在k230上怎么使用opencv的imshow显示图像呢?

    已经添加了highgui的链接,成功编译并且在板子上运行 期待结果和实际结果 在hdmi屏幕上显示图像 软硬件版本信息 错误日志 hdmi屏幕黑屏无反应
    发表于 06-11 06:01

    【高云GW5AT-LV60 开发套件试用体验】SC130GScmos模块与LVDS屏和HDMI输出例程测试报告图像显示部分细节补充

    /jishu_2491350_1_1.html] 在上篇报告中,由于帖子字节限制没有说明其具体问题解决方法,在此说明。 HDMI显示例程效果类似,其模块功能框图为: cmos数据位mipi接口,通过lvds物理差分对将图像数据化
    发表于 06-09 09:46

    K230 V3.0使用Mipi显示屏无法显示图像怎么解决?

    图像 使用hdmi的例程,hdmi显示显示图像 全是紫色画面 供电正常两根usb线,网上也去
    发表于 06-04 07:17

    4K显示屏用DP还是HDMI

    大家都知道,现在4K显示屏越来越普及,无论是玩游戏、看电影还是办公,都能带来超清视界。但在连接4K显示屏时,很多人都会纠结:到底选DP(DisplayPort)还是HDMI?今天我们就来聊聊它们各自
    的头像 发表于 04-08 16:03 2101次阅读

    图像采集卡:现代图像处理技术的关键组件

    在现代科技快速发展的背景下,图像处理技术已成为信息技术领域不可或缺的一部分。图像采集卡,作为连接计算机与各种图像采集设备的重要硬件组件,扮演着至关重要的角色。它不仅涉及
    的头像 发表于 02-20 10:42 945次阅读
    <b class='flag-5'>图像</b>采集卡:现代<b class='flag-5'>图像</b><b class='flag-5'>处理</b>技术的关键组件

    DLP4500连接HDMI进行视频流传输模式下投影图像底部出错并闪烁,怎么解决?

    进行了代码的编写,其中相关配置信息参考了开发者手册第64页的内容。测试发现,投影仪可以投影出图像并触发摄像头,但此时投影图像中大约底部1/5的区域显示不正常,是类似白色背景的图案并会发
    发表于 02-19 08:04

    DLPC3439如果给的HDMI源输出是RGB565,会在HDMI中表示它是RGB吗,光机会如何处理这16bit?

    目前是硬件方案3439+IT6801,IT6801输出RGB888信号(24bit)至双3439。 目前测试发现如下问题: 如果给光机输入的HDMI信号是RGB565(16bit),会发现图像像素
    发表于 02-19 07:46

    DLP3010 HDMI输入及输出异常的原因?

    ? 3:无论是否接入HDMI以及displayboard板,MSP430的IIC一直有读写操作,波形如下图,请问这是什么原因? 4:我尝试显示内部测试图像,测试方式是使用msp的UP按键切换
    发表于 02-19 07:27

    FPGA图像处理基础----实现缓存卷积窗口

    像素行与像素窗口 一幅图像是由一个个像素点构成的,对于一幅480*272大小的图片来说,其宽度是480,高度是272。在使用FPGA进行图像处理时,最关键的就是使用FPGA内部的存储资源对像
    的头像 发表于 02-07 10:43 1435次阅读
    FPGA<b class='flag-5'>图像</b><b class='flag-5'>处理</b>基础----实现缓存卷积窗口

    TFP401A接收DVI经过转化后的HDMI信号时,不能正常输出图像是什么原因呢?

    TFP401A直接接收HDMI信号后转化为RGB888的信号能够正常投出影像;但是接收DVI经过转化后的HDMI信号时,不能正常输出图像,请问是什么原因呢?
    发表于 01-03 07:30