Hello everyone, not sure if this is a valid question for this forum but I will ask anyway. If you think I should ask somewhere else, let me know.
I have a testcase for an image_reader module that reads data out of DDR via a MM axi-full interface, and outputs that data on a axi-stream interface. We are using this VIP to simulate ddr and to simulate the axi read and writes:
https://docs.xilinx.com/v/u/en-US/ds940-zynq-vip
I am prefilling the DDR with a raw video file that is 160x120. There are 4 frames and each frame is stored in a different DDR buffer. I am using backdoor access to fill DDR at the start of the testcase. I can dump the contents back to a another file and I can verify the data is correct, so I am fairly confident in that part.
My testcase reads the data out of the PS doing bursts with a size of 16 transactions. My issue is that the very last burst never arrives. I get 599 bursts and the 600th burst never gets read out. On the address lines, I can see that the last address is correctly received by the PS, but it never asserts RVALID data for that address. The assert statement error message I am getting is:
ncsim: *W,WARSEV (/tools/Xilinx/Vivado/2018.2/data/xilinx_vip/hdl/axi_vip_axi4pc.sv,1623): (time 213765 NS).
tb_fpga.a0_fpga_zynq.processing_system7_0.inst.S_AXI_GP0.slave.IF.PC
XILINX_RECS_CONTINUOUS_RTRANSFERS_MAX_WAIT: RVALID should be asserted within MAXWAITS cycles of AR Command being accepted.
The SystemVerilog code for the testcase is below. Any advice on debugging this is appreciated!
// Local Parameters
localparam BUFF0_ADDR = 32'h2E000000;
localparam BUFF1_ADDR = 32'h2F000000;
localparam BUFF2_ADDR = 32'h2A000000;
localparam BUFF3_ADDR = 32'h2B000000;
//--------------------------------------------------------------------------------
// Testcase image_memory_read_GP
// Description: Reads a YUV 4:2:2 video from a file into PS VIP DDR
// then the image_reader_GP reads it out and it gets written
// to a file for comparison with the original file
//--------------------------------------------------------------------------------
task file_memory_read_GP(
input [1024*8-1:0] input_file_name,
input [31:0] i_frame_width,
input [31:0] i_frame_height,
input [31:0] num_frames,
output error
);
int input_file_handler;
int output_file_handler;
int frame_counter = 0;
string output_file_name = "DDR_video_dump.yuv";
string scrb_message;
logic [0:76800][31:0] video_data; //size = i_frame_width*i_frame_height*num_frames
logic [31:0] status_reg;
logic [31:0] control_reg;
logic [31:0] frame_delay = 500; // number of clock cycles delay between frame reads
logic [1:0] num_buff;
begin
$display("[%0t]: Starting GP_image_reader testcase", $time);
if(num_frames <= 4) begin
num_buff = 2'b11;
end else begin
num_buff = num_frames - 1;
end
// Read an input file into DDR
input_file_handler = $fopen (input_file_name, "rb");
if(input_file_handler == 0) begin
$display("Failed to open file: %0s", input_file_name);
error = 1;
$stop;
end
// Fill 4 seperate buffers with 1 frame each:
for(int frame_index = 0; frame_index < num_frames; frame_index++) begin // loop through all the frames
for(int i = 0; i < (i_frame_width*i_frame_height/2 + 1); i++) begin // loop through all the pixels in the frame
$fscanf(input_file_handler, "%u", video_data[frame_index*i_frame_width*i_frame_height + i]);
case (frame_index)
0: ps_vif.task_write_mem(video_data[frame_index*i_frame_width*i_frame_height + i], BUFF0_ADDR + i*4, 4);
1: ps_vif.task_write_mem(video_data[frame_index*i_frame_width*i_frame_height + i], BUFF1_ADDR + i*4, 4);
2: ps_vif.task_write_mem(video_data[frame_index*i_frame_width*i_frame_height + i], BUFF2_ADDR + i*4, 4);
3: ps_vif.task_write_mem(video_data[frame_index*i_frame_width*i_frame_height + i], BUFF3_ADDR + i*4, 4);
default: begin $display("frame_index error"); $stop; end
endcase
end
end
// Enable the GP Image Reader and set force_read bit:
hdcs_tools.task_config_gp_rmem(BUFF0_ADDR, BUFF1_ADDR, BUFF2_ADDR, BUFF3_ADDR, 1'b1, 1'b1, num_buff, i_frame_width, i_frame_height);
// set delay between frames
this.ps_vif.task_write_data(`S_AXI_GP_READER_OFFSET, `GP_READER_FRAME_DELAY_OFFSET, frame_delay);
// Dump M_AXI-Stream (YUV 16-bit) to file
output_file_handler = $fopen(output_file_name, "wb");
if(output_file_handler == 0) begin
error = 1;
$sformat(scrb_message, "Video output: Failed to open file: %0s", output_file_name);
scrb.task_validate_result(!error, scrb_message);
end else begin
this.image_reader_gp_vif.M_AXIS_tready = 1'b1; // set the interface TREADY once the file is open
end
fork
forever @(posedge this.image_reader_gp_vif.CLK) begin
if (image_reader_gp_vif.M_AXIS_tready == 1'b1 && image_reader_gp_vif.M_AXIS_tvalid == 1'b1 && frame_counter < num_frames) begin
$fwrite(output_file_handler, "%c%c", image_reader_gp_vif.M_AXIS_tdata[7:0], image_reader_gp_vif.M_AXIS_tdata[15:8]);
end
end
join_none
$display("[%0t]: Writing AXI-stream output to file and polling status register for frame_done flag...", $time);
// Poll the status_reg for the frame_done bit:
forever @(posedge this.image_reader_gp_vif.CLK) begin
this.ps_vif.task_read_data(`S_AXI_GP_READER_OFFSET, 15*4, status_reg);
if (status_reg[9] == 1) begin
frame_counter = frame_counter + 1;
$display("[%0t]: Frame %0d of %0d complete", $time, frame_counter, num_frames);
// clear the frame_done bit:
control_reg = 0;
this.ps_vif.task_read_data(`S_AXI_GP_READER_OFFSET, 0*4, control_reg);
control_reg[11] = 1; // this is a self clearing bit
this.ps_vif.task_write_data(`S_AXI_GP_READER_OFFSET, 0*4, control_reg);
end;
if (frame_counter == num_frames) begin
image_reader_gp_vif.M_AXIS_tready = 1'b0;
// Disable the GP reader
hdcs_tools.task_config_gp_rmem(BUFF0_ADDR, BUFF1_ADDR, BUFF2_ADDR, BUFF3_ADDR, 1'b0, 1'b0, num_buff, i_frame_width, i_frame_height);
$fclose(output_file_handler);
break;
end
end
// Compare input and output files
hdcs_tools.compare_video_files(error, input_file_name, output_file_name, num_frames, i_frame_width, i_frame_height);
scrb.task_validate_result(!error, "INPUT AND OUTPUT VIDEO FILES MATCH");
$display("[%0t]: Completed GP_image_reader testcase", $time);
end
endtask