Files
retroSoC/tests/rtl/jpeg_encode_core_tb.sv
T
maksyuki 2840d22e96 feat: enhance JPEG processing modules and tests
- Updated  to integrate a coefficient engine and additional signals for coefficient handling.
- Modified  to include a coefficient engine, enhancing the encoding process with new signals.
- Improved  to validate generated blocks against expected values and added timeout handling.
- Introduced  for testing SRAM wrappers in JPEG workspace.
- Enhanced test coverage in  to reject invalid STA net drivers.
- Updated  to ensure proper coverage of canonical domains in timing contracts.
- Added a new test for JPEG coefficient engine in .
- Improved memory map tests in  to validate public active MMIO regions.
- Enhanced management core specification tests in  to verify high-performance core specifications.
- Added behavioral-only checks in  to exclude synthesis and netlist consumers.
- Updated SDRAM tests in  to track active firmware memory.
- Enhanced STA constraints tests in  to cover current clock domains and net drivers.
2026-09-01 22:33:35 +08:00

262 lines
9.8 KiB
Systemverilog

`timescale 1ns / 1ps
module jpeg_encode_core_tb;
logic clk = 1'b0;
logic rst_n = 1'b0;
logic start;
logic [ 511:0] luma_quant;
logic [1599:0] luma_reciprocal;
logic [ 191:0] luma_dc_code;
logic [ 59:0] luma_dc_length;
logic [4095:0] luma_ac_code;
logic [1279:0] luma_ac_length;
logic [ 511:0] chroma_quant;
logic [1599:0] chroma_reciprocal;
logic [ 191:0] chroma_dc_code;
logic [ 59:0] chroma_dc_length;
logic [4095:0] chroma_ac_code;
logic [1279:0] chroma_ac_length;
logic busy;
logic done;
logic error_flag;
logic coefficient_start;
logic [1535:0] coefficient_block;
logic [ 511:0] coefficient_quant;
logic [1599:0] coefficient_reciprocal;
logic coefficient_start_ready;
logic [1535:0] coefficient_result;
logic coefficient_result_valid;
logic coefficient_result_ready;
logic coefficient_table_err;
logic coefficient_overflow;
logic [ 7:0] expected [0:2047];
logic [ 7:0] luma_quant_values [ 0:63];
logic [ 7:0] chroma_quant_values [ 0:63];
logic [ 31:0] luma_dc_entries [ 0:11];
logic [ 31:0] chroma_dc_entries [ 0:11];
logic [ 31:0] luma_ac_entries [ 0:255];
logic [ 31:0] chroma_ac_entries [ 0:255];
integer expected_size;
integer output_index;
integer input_beats;
integer expected_input_beats;
integer test_width;
integer test_height;
integer cycle_count;
integer timeout_cycles;
string expected_path;
string luma_quant_path;
string chroma_quant_path;
string luma_dc_path;
string chroma_dc_path;
string luma_ac_path;
string chroma_ac_path;
axi4_stream_if #(
.DATA_WIDTH(64)
) pixel_axis (
.aclk (clk),
.aresetn(rst_n)
);
axi4_stream_if #(
.DATA_WIDTH(64)
) bitstream_axis (
.aclk (clk),
.aresetn(rst_n)
);
always #5 clk = ~clk;
jpeg_coefficient_engine u_coefficient_engine (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (coefficient_start),
.decode_i (1'b0),
.block_i (coefficient_block),
.quant_i (coefficient_quant),
.reciprocal_i (coefficient_reciprocal),
.start_ready_o (coefficient_start_ready),
.block_o (coefficient_result),
.result_valid_o(coefficient_result_valid),
.result_ready_i(coefficient_result_ready),
.table_err_o (coefficient_table_err),
.overflow_o (coefficient_overflow)
);
jpeg_encode_core #(
.ExternalCoefficientEngine(1'b1)
) u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (start),
.width_i (test_width[15:0]),
.height_i (test_height[15:0]),
.sampling_i (2'd3),
.input_format_i (3'd2),
.restart_interval_i (16'd0),
.luma_quant_i (luma_quant),
.luma_reciprocal_i (luma_reciprocal),
.luma_dc_code_i (luma_dc_code),
.luma_dc_length_i (luma_dc_length),
.luma_ac_code_i (luma_ac_code),
.luma_ac_length_i (luma_ac_length),
.chroma_quant_i (chroma_quant),
.chroma_reciprocal_i (chroma_reciprocal),
.chroma_dc_code_i (chroma_dc_code),
.chroma_dc_length_i (chroma_dc_length),
.chroma_ac_code_i (chroma_ac_code),
.chroma_ac_length_i (chroma_ac_length),
.coefficient_start_o (coefficient_start),
.coefficient_block_o (coefficient_block),
.coefficient_quant_o (coefficient_quant),
.coefficient_reciprocal_o (coefficient_reciprocal),
.coefficient_start_ready_i (coefficient_start_ready),
.coefficient_result_i (coefficient_result),
.coefficient_result_valid_i(coefficient_result_valid),
.coefficient_result_ready_o(coefficient_result_ready),
.coefficient_table_err_i (coefficient_table_err),
.coefficient_overflow_i (coefficient_overflow),
.pixel_axis (pixel_axis),
.bitstream_axis (bitstream_axis),
.start_ready_o (),
.busy_o (busy),
.done_o (done),
.error_o (error_flag)
);
always @(posedge clk) begin
if (rst_n && u_dut.s_builder_block_valid && (u_dut.s_builder_block !== {64{8'd128}})) begin
$fatal(1, "MCU builder output changed under block backpressure: block=%0d data=%h",
u_dut.u_mcu_builder.s_block_cnt_q, u_dut.s_builder_block);
end
if (rst_n && busy) begin
cycle_count <= cycle_count + 1;
end
if (rst_n && pixel_axis.tvalid && pixel_axis.tready) begin
input_beats <= input_beats + 1;
end
if (rst_n && bitstream_axis.tvalid && bitstream_axis.tready) begin
for (int lane = 0; lane < 8; lane++) begin
if (bitstream_axis.tkeep[lane]) begin
if (bitstream_axis.tdata[lane*8+:8] != expected[output_index]) begin
$fatal(1, "encoded byte mismatch at %0d: got=%h expected=%h", output_index,
bitstream_axis.tdata[lane*8+:8], expected[output_index]);
end
output_index = output_index + 1;
end
end
if (bitstream_axis.tlast != (output_index == expected_size)) begin
$fatal(1, "encoded TLAST mismatch");
end
end
end
initial begin
if (!$value$plusargs(
"expected_hex=%s", expected_path
) || !$value$plusargs(
"expected_size=%d", expected_size
) || !$value$plusargs(
"luma_quant_hex=%s", luma_quant_path
) || !$value$plusargs(
"chroma_quant_hex=%s", chroma_quant_path
) || !$value$plusargs(
"luma_dc_hex=%s", luma_dc_path
) || !$value$plusargs(
"chroma_dc_hex=%s", chroma_dc_path
) || !$value$plusargs(
"luma_ac_hex=%s", luma_ac_path
) || !$value$plusargs(
"chroma_ac_hex=%s", chroma_ac_path
)) begin
$fatal(1, "encode core test requires JPEG and table plusargs");
end
test_width = 16;
test_height = 16;
expected_input_beats = 96;
void'($value$plusargs("test_width=%d", test_width));
void'($value$plusargs("test_height=%d", test_height));
void'($value$plusargs("input_beats=%d", expected_input_beats));
$readmemh(expected_path, expected);
$readmemh(luma_quant_path, luma_quant_values);
$readmemh(chroma_quant_path, chroma_quant_values);
$readmemh(luma_dc_path, luma_dc_entries);
$readmemh(chroma_dc_path, chroma_dc_entries);
$readmemh(luma_ac_path, luma_ac_entries);
$readmemh(chroma_ac_path, chroma_ac_entries);
luma_quant = '0;
luma_reciprocal = '0;
chroma_quant = '0;
chroma_reciprocal = '0;
luma_dc_code = '0;
luma_dc_length = '0;
chroma_dc_code = '0;
chroma_dc_length = '0;
luma_ac_code = '0;
luma_ac_length = '0;
chroma_ac_code = '0;
chroma_ac_length = '0;
for (int index = 0; index < 64; index++) begin
luma_quant[index*8+:8] = luma_quant_values[index];
chroma_quant[index*8+:8] = chroma_quant_values[index];
luma_reciprocal[index*25+:25] =
(25'd16777216 + luma_quant_values[index] - 1'b1) / luma_quant_values[index];
chroma_reciprocal[index*25+:25] =
(25'd16777216 + chroma_quant_values[index] - 1'b1) / chroma_quant_values[index];
end
for (int index = 0; index < 12; index++) begin
luma_dc_code[index*16+:16] = luma_dc_entries[index][15:0];
luma_dc_length[index*5+:5] = luma_dc_entries[index][20:16];
chroma_dc_code[index*16+:16] = chroma_dc_entries[index][15:0];
chroma_dc_length[index*5+:5] = chroma_dc_entries[index][20:16];
end
for (int index = 0; index < 256; index++) begin
luma_ac_code[index*16+:16] = luma_ac_entries[index][15:0];
luma_ac_length[index*5+:5] = luma_ac_entries[index][20:16];
chroma_ac_code[index*16+:16] = chroma_ac_entries[index][15:0];
chroma_ac_length[index*5+:5] = chroma_ac_entries[index][20:16];
end
start = 1'b0;
pixel_axis.tdata = {8{8'd128}};
pixel_axis.tkeep = 8'hff;
pixel_axis.tstrb = 8'hff;
pixel_axis.tlast = 1'b0;
pixel_axis.tid = '0;
pixel_axis.tdest = '0;
pixel_axis.tuser = '0;
pixel_axis.tvalid = 1'b0;
bitstream_axis.tready = 1'b1;
output_index = 0;
input_beats = 0;
cycle_count = 0;
repeat (3) @(posedge clk);
rst_n = 1'b1;
@(negedge clk);
start = 1'b1;
@(negedge clk);
start = 1'b0;
pixel_axis.tvalid = 1'b1;
while (input_beats < expected_input_beats) begin
@(negedge clk);
pixel_axis.tlast = input_beats + 1 == expected_input_beats;
end
pixel_axis.tvalid = 1'b0;
pixel_axis.tlast = 1'b0;
timeout_cycles = 10000;
while (!done && (timeout_cycles > 0)) begin
@(negedge clk);
timeout_cycles--;
end
if (timeout_cycles == 0) begin
$fatal(1, "encode timeout: core=%0d builder=%0d block=%0d", u_dut.s_state_q,
u_dut.u_mcu_builder.s_state_q, u_dut.u_block_encoder.s_state_q);
end
if (error_flag || output_index != expected_size) begin
$fatal(1, "encode completion mismatch: err=%0d bytes=%0d expected=%0d", error_flag,
output_index, expected_size);
end
$display("JPEG encode core tests passed cycles=%0d", cycle_count);
$finish;
end
endmodule