Zynq学习笔记--AXI4-Stream 图像数据从仿真输出到图像文件

发布时间:2026/8/7 18:00:43
Zynq学习笔记--AXI4-Stream 图像数据从仿真输出到图像文件 目录1. 简介2. 构建工程2.1 Vivado 工程2.2 TestBench 代码2.3 关键代码分析3. VPG Background Pattern ID (0x0020) Register4. 总结1. 简介使用 SystemVerilog 将 AXI4-Stream 图像数据从仿真输出到图像文件 (PPM)。用到的函数包括 $fopen、$fwrite 和 $fclose。PPM 格式PPM (Portable Pixmap Format) 是一种简单的图像文件格式用于存储彩色图像。PPM 格式很简单主要用于科研或某些需要图像处理但不需要复杂图像格式的场合。PPM 文件通常较大因为它们不使用压缩。一个 PPM 文件由一个文件头和图像数据体组成。文件头指定了图像的宽度、高度和最大颜色值而数据体则包含按顺序排列的像素颜色值每个像素颜色通常由红、绿、蓝三个颜色分量组成。2. 构建工程2.1 Vivado 工程2.2 TestBench 代码timescale 1ns / 1ps import axi_vip_pkg::*; import design_1_axi_vip_0_0_pkg::*; module tb_tpg(); bit aclk 0, aresetn 0; xil_axi_resp_t resp; bit tpg_tready 1, tpg_tuser, tpg_tvalid, tpg_tlast; bit [23:0] tpg_tdata; integer counter_width 0, counter_height 0; integer final_width 0, final_height 0; integer output_file; integer img_writing 1, img_start 0; parameter integer tpg_base_address 12h000; parameter integer TPG_CONTROL_REG tpg_base_address; parameter integer TPG_ACTIVE_H_REG tpg_base_address 8h10; parameter integer TPG_ACTIVE_W_REG tpg_base_address 8h18; parameter integer TPG_BG_PATTERN_REG tpg_base_address 8h20; integer height400, width640; integer pattern_id 8h09; always #10ns aclk ~aclk; design_1_wrapper UUT ( .aclk_50MHz (aclk ), .aresetn_0 (aresetn ), .tpg_tdata (tpg_tdata ), .tpg_tlast (tpg_tlast ), .tpg_tready (tpg_tready), .tpg_tuser (tpg_tuser ), .tpg_tvalid (tpg_tvalid)); initial begin #350ns aresetn 1; (posedge tpg_tuser); // Start of the first frame (posedge tpg_tuser); // Start of the second frame, stop the simulation wait (tpg_tuser 1b0); #20ns; if((final_height height)(final_height height)) $display(Resolution match, test succeeded); else $display(Resolution do not match, test failed); $finish; end design_1_axi_vip_0_0_mst_t master_agent; initial begin master_agent new(master vip agent,UUT.design_1_i.axi_vip_0.inst.IF); master_agent.start_master(); wait (aresetn 1b1); #200ns master_agent.AXI4LITE_WRITE_BURST(TPG_ACTIVE_H_REG, 0, height, resp); master_agent.AXI4LITE_WRITE_BURST(TPG_ACTIVE_W_REG, 0, width, resp); master_agent.AXI4LITE_WRITE_BURST(TPG_BG_PATTERN_REG, 0, pattern_id, resp); #200ns master_agent.AXI4LITE_WRITE_BURST(TPG_CONTROL_REG, 0, 8h81, resp); end always (posedge aclk) begin if((tpg_tvalid 1) (tpg_tready 1)) begin if(tpg_tlast 1) begin final_width counter_width 1; counter_width 0; end else counter_width counter_width 1; end end always (posedge aclk) begin if((tpg_tvalid 1) (tpg_tready 1)) begin if(tpg_tuser 1) begin final_height counter_height; counter_height 0; end else if(tpg_tlast 1) counter_height counter_height 1; end end initial begin output_file $fopen(image_out_1.ppm, w); $fwrite(output_file, P3\n); $fwrite(output_file, %0d %0d\n, width, height); $fwrite(output_file, %0d\n, 2**8-1); while(img_writing 1) begin (posedge aclk) #1ns; if ((tpg_tvalid 1) (tpg_tready 1)) begin if((tpg_tuser 1) (img_start 1)) img_writing 0; else begin if(tpg_tuser 1) img_start 1; $fwrite(output_file, %0d\n%0d\n%0d\n, int(tpg_tdata[23:16]), int(tpg_tdata[7:0]), int(tpg_tdata[15:8])); end end end $fclose(output_file); $display(Image written); end endmodule2.3 关键代码分析initial begin output_file $fopen(image_out_1.ppm, w); $fwrite(output_file, P3\n); $fwrite(output_file, %0d %0d\n, width, height); $fwrite(output_file, %0d\n, 2**8-1); while(img_writing 1) begin (posedge aclk); #1ns; if ((tpg_tvalid 1) (tpg_tready 1)) begin if((tpg_tuser 1) (img_start 1)) img_writing 0; else begin if(tpg_tuser 1) img_start 1; $fwrite(output_file, %0d\n%0d\n%0d\n, int(tpg_tdata[23:16]), int(tpg_tdata[ 7: 0]), int(tpg_tdata[15:8])); end end end $fclose(output_file); $display(Image written); end文件创建与头信息写入使用 $fopen 函数打开或创建一个新的文件image_out_1.ppm用于写入模式w。利用 $fwrite 函数向文件写入PPM图像的头信息P3\nPPM文件的格式标识表示该文件是一个ASCII编码的彩色PPM图像。%0d %0d\n接下来写入图像的宽度width和高度height这两个数值应该在代码的其他部分定义。%0d\n写入颜色的最大值这里是2**8-1即255表示每个颜色通道红、绿、蓝的最大值。图像数据写入代码进入一个while循环循环条件是 img_writing 等于1这意味着将在满足某些条件时写入图像数据。在每个时钟周期的上升沿(posedge aclk)并在等待1纳秒#1ns;后检查tpg_tvalid和tpg_tready信号。只有当这两个信号都为1时才会执行数据写入的逻辑。如果tpg_tuser信号为1且img_start也为1这表示图像数据的结束将img_writing设置为0退出循环。如果仅tpg_tuser为1这意味着图像数据的开始设置img_start为1。在其他情况下使用$fwrite函数将图像数据tpg_tdata写入文件。这里的数据被分解为红、蓝、绿三个颜色通道并按顺序写入文件。文件关闭与信息显示使用$fclose函数关闭文件。通过$display函数在仿真控制台显示“Image written”信息表示图像数据已成功写入文件。if ((tpg_tvalid 1) (tpg_tready 1)) begin if((tpg_tuser 1) (img_start 1)) img_writing 0; // 第二帧开始后img_writing标记为0 else begin if(tpg_tuser 1) img_start 1; // 第一帧开始img_start标记为1 $fwrite(output_file, %0d\n%0d\n%0d\n, xxx); // 第一、二帧之间逐个像素写入 end end3. VPG Background Pattern ID (0x0020) Register背景模式 ID 寄存器控制 TPG Core 生成的模式操作。该寄存器根据以下值控制核心输出的模式0x00 - 直接将视频输入传递到视频输出0x1 - 水平坡道每个分量RGB或Y水平增加10x2 - 垂直坡道每个分量RGB或Y垂直增加10x3 - 时间坡道根据运动速度寄存器设置的值每帧逐像素增加0x4 - 纯红色输出0x5 - 纯绿色输出0x6 - 纯蓝色输出0x7 - 纯黑色输出0x8 - 纯白色输出0x9 - 色条0xA - 区域板输出产生一个基于ROM的正弦模式。此选项依赖于运动速度、zplate水平起点、zplate水平增量、zplate垂直起点和zplate垂直增量寄存器。0xB - 方格色条0xC - 绘制十字交叉线模式0xD - 色彩扫描模式0xE - 组合的垂直和水平坡道0xF - 黑白棋盘0x10 - 伪随机模式0x11 - DisplayPort颜色坡道0x12 - DisplayPort黑白垂直线0x13 - DisplayPort彩色方块4. 总结本文介绍了如何使用 SystemVerilog 将 AXI4-Stream 图像数据输出到 PPM 格式的图像文件中。通过使用 $fopen、$fwrite 和 $fclose 函数成功地将仿真生成的图像数据写入到文件中实现了图像数据的输出。在 TestBench 代码中设置了图像的分辨率和颜色模式并通过循环逐像素地写入数据。通过这种方式我们可以将仿真生成的图像数据保存为 PPM 格式的文件方便后续的图像处理和分析。这种方法可以帮助开发人员在仿真过程中方便地将图像数据输出到文件中以便进行后续的验证和分析工作。