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.
This commit is contained in:
maksyuki committed 2026-09-01 22:33:35 +08:00
1 parent 39bc1c84b4
commit 2840d22e96
50 files changed
+2640 -1278

No files matched your search

+7 -7
View File
@@ -146,13 +146,13 @@ module apb4_jpeg_ring_tb;
memory[index] = 64'd0;
end
memory[32'h1000>>3] = 64'h0000000000000001;
apb4.paddr = '0;
apb4.pprot = '0;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pwdata = '0;
apb4.pstrb = '0;
apb4.paddr = '0;
apb4.pprot = '0;
apb4.psel = 1'b0;
apb4.penable = 1'b0;
apb4.pwrite = 1'b0;
apb4.pwdata = '0;
apb4.pstrb = '0;
repeat (3) @(posedge clk);
rst_n = 1'b1;
+151
View File
@@ -0,0 +1,151 @@
`timescale 1ns / 1ps
module jpeg_coefficient_engine_tb;
logic clk = 1'b0;
logic rst_n = 1'b0;
logic start;
logic decode;
logic [1535:0] block_in;
logic [ 511:0] quant;
logic [1599:0] reciprocal;
logic start_ready;
logic [1535:0] block_out;
logic result_valid;
logic result_ready;
logic table_err;
logic overflow;
always #5 clk = ~clk;
jpeg_coefficient_engine u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (start),
.decode_i (decode),
.block_i (block_in),
.quant_i (quant),
.reciprocal_i (reciprocal),
.start_ready_o (start_ready),
.block_o (block_out),
.result_valid_o(result_valid),
.result_ready_i(result_ready),
.table_err_o (table_err),
.overflow_o (overflow)
);
function automatic logic [7:0] luma_quant(input int index_i);
logic [7:0] values[0:63];
begin
values = '{
16,
11,
10,
16,
24,
40,
51,
61,
12,
12,
14,
19,
26,
58,
60,
55,
14,
13,
16,
24,
40,
57,
69,
56,
14,
17,
22,
29,
51,
87,
80,
62,
18,
22,
37,
56,
68,
109,
103,
77,
24,
35,
55,
64,
81,
104,
113,
92,
49,
64,
78,
87,
103,
121,
120,
101,
72,
92,
95,
98,
112,
100,
103,
99
};
return values[index_i];
end
endfunction
function automatic logic signed [23:0] expected_quantized(input int index_i);
begin
unique case (index_i)
1: return -24'sd2;
8: return -24'sd12;
24: return -24'sd1;
default: return 24'sd0;
endcase
end
endfunction
initial begin
start = 1'b0;
decode = 1'b0;
block_in = '0;
quant = '0;
reciprocal = '0;
result_ready = 1'b0;
for (int index = 0; index < 64; index++) begin
block_in[index*24+:24] = 24'(index - 32);
quant[index*8+:8] = luma_quant(index);
reciprocal[index*25+:25] = (25'd16777216 + luma_quant(index) - 1'b1) / luma_quant(index);
end
repeat (3) @(negedge clk);
rst_n = 1'b1;
@(negedge clk);
if (!start_ready) $fatal(1, "coefficient engine not ready");
start = 1'b1;
@(negedge clk);
start = 1'b0;
while (!result_valid) @(negedge clk);
if (table_err || overflow) $fatal(1, "unexpected coefficient engine error");
for (int index = 0; index < 64; index++) begin
if ($signed(block_out[index*24+:24]) != expected_quantized(index)) begin
$fatal(1, "coefficient mismatch at %0d: %0d", index, $signed(block_out[index*24+:24]));
end
end
result_ready = 1'b1;
@(negedge clk);
$display("JPEG coefficient engine test passed");
$finish;
end
endmodule
+74 -35
View File
@@ -1,23 +1,33 @@
`timescale 1ns / 1ps
module jpeg_decode_core_tb;
logic clk = 1'b0;
logic rst_n = 1'b0;
logic start;
logic busy;
logic done;
logic [15:0] width;
logic [15:0] height;
logic [ 1:0] sampling;
logic error_flag;
logic [ 4:0] error_code;
logic [ 7:0] input_bytes [0:2047];
logic [ 7:0] expected_rgb [0:4095];
integer input_size;
integer expected_size;
integer output_index;
string input_path;
string expected_path;
logic clk = 1'b0;
logic rst_n = 1'b0;
logic start;
logic busy;
logic done;
logic [ 15:0] width;
logic [ 15:0] height;
logic [ 1:0] sampling;
logic error_flag;
logic [ 4:0] error_code;
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] input_bytes [0:2047];
logic [ 7:0] expected_rgb [0:4095];
integer input_size;
integer expected_size;
integer output_index;
string input_path;
string expected_path;
axi4_stream_if #(
.DATA_WIDTH(64)
@@ -34,21 +44,49 @@ module jpeg_decode_core_tb;
always #5 clk = ~clk;
jpeg_decode_core u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (start),
.output_format_i(3'd2),
.bitstream_axis (bitstream_axis),
.pixel_axis (pixel_axis),
.start_ready_o (),
.busy_o (busy),
.done_o (done),
.width_o (width),
.height_o (height),
.sampling_o (sampling),
.error_o (error_flag),
.error_code_o (error_code)
jpeg_coefficient_engine u_coefficient_engine (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (coefficient_start),
.decode_i (1'b1),
.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_decode_core #(
.ExternalCoefficientEngine(1'b1)
) u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
.start_i (start),
.output_format_i (3'd2),
.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),
.bitstream_axis (bitstream_axis),
.pixel_axis (pixel_axis),
.start_ready_o (),
.busy_o (busy),
.done_o (done),
.width_o (width),
.height_o (height),
.sampling_o (sampling),
.error_o (error_flag),
.error_code_o (error_code)
);
task automatic send_input_beat(input integer offset_i);
@@ -129,9 +167,10 @@ module jpeg_decode_core_tb;
end
if (error_flag || !done || width != 16'd16 || height != 16'd16 || sampling != 2'd3 ||
output_index != expected_size) begin
$fatal(1,
"decode completion mismatch: done=%0d err=%0d code=%0d size=%0dx%0d sampling=%0d bytes=%0d expected=%0d",
done, error_flag, error_code, width, height, sampling, output_index, expected_size);
$fatal(
1,
"decode completion mismatch: done=%0d err=%0d code=%0d size=%0dx%0d sampling=%0d bytes=%0d expected=%0d",
done, error_flag, error_code, width, height, sampling, output_index, expected_size);
end
$display("JPEG decode core tests passed");
$finish;
+80 -38
View File
@@ -19,13 +19,23 @@ module jpeg_encode_core_tb;
logic busy;
logic done;
logic error_flag;
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];
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;
@@ -57,36 +67,68 @@ module jpeg_encode_core_tb;
always #5 clk = ~clk;
jpeg_encode_core 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),
.pixel_axis (pixel_axis),
.bitstream_axis (bitstream_axis),
.start_ready_o (),
.busy_o (busy),
.done_o (done),
.error_o (error_flag)
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
@@ -129,8 +171,8 @@ module jpeg_encode_core_tb;
)) begin
$fatal(1, "encode core test requires JPEG and table plusargs");
end
test_width = 16;
test_height = 16;
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));
@@ -199,8 +241,8 @@ module jpeg_encode_core_tb;
pixel_axis.tlast = input_beats + 1 == expected_input_beats;
end
pixel_axis.tvalid = 1'b0;
pixel_axis.tlast = 1'b0;
timeout_cycles = 3000;
pixel_axis.tlast = 1'b0;
timeout_cycles = 10000;
while (!done && (timeout_cycles > 0)) begin
@(negedge clk);
timeout_cycles--;
+30 -4
View File
@@ -9,8 +9,10 @@ module jpeg_mcu_builder_tb;
logic block_last;
logic done;
logic error_flag;
logic [511:0] expected_block;
int input_beats;
int output_blocks;
int timeout_cycles;
axi4_stream_if #(
.DATA_WIDTH(64)
@@ -21,6 +23,16 @@ module jpeg_mcu_builder_tb;
always #5 clk = ~clk;
always_comb begin
expected_block = {64{8'd128}};
if (output_blocks < 4) begin
for (int sample = 0; sample < 64; sample ++) begin
expected_block[sample*8+:8] = 8'((((output_blocks >> 1) * 8 + (sample >> 3)) * 16) +
((output_blocks & 1) * 8) + (sample & 7));
end
end
end
jpeg_mcu_builder u_dut (
.clk_i (clk),
.rst_n_i (rst_n),
@@ -44,8 +56,8 @@ module jpeg_mcu_builder_tb;
input_beats <= input_beats + 1;
end
if (rst_n && block_valid) begin
if (block_data != {64{8'd128}} || (block_last != (output_blocks == 5))) begin
$fatal(1, "generated block mismatch at %0d", output_blocks);
if (block_data !== expected_block || (block_last != (output_blocks == 5))) begin
$fatal(1, "generated block mismatch at %0d: %h", output_blocks, block_data);
end
output_blocks <= output_blocks + 1;
end
@@ -53,7 +65,7 @@ module jpeg_mcu_builder_tb;
initial begin
start = 1'b0;
pixel_axis.tdata = {8{8'd128}};
pixel_axis.tdata = '0;
pixel_axis.tkeep = 8'hff;
pixel_axis.tstrb = 8'hff;
pixel_axis.tlast = 1'b0;
@@ -70,13 +82,27 @@ module jpeg_mcu_builder_tb;
@(negedge clk);
start = 1'b0;
pixel_axis.tvalid = 1'b1;
for (int lane = 0; lane < 8; lane++) begin
pixel_axis.tdata[lane*8+:8] = 8'(lane / 3);
end
while (input_beats < 96) begin
@(negedge clk);
pixel_axis.tlast = input_beats == 95;
for (int lane = 0; lane < 8; lane++) begin
pixel_axis.tdata[lane*8+:8] = 8'(((input_beats * 8) + lane) / 3);
end
end
pixel_axis.tvalid = 1'b0;
pixel_axis.tlast = 1'b0;
while (!done) @(negedge clk);
timeout_cycles = 2000;
while (!done && (timeout_cycles > 0)) begin
@(negedge clk);
timeout_cycles--;
end
if (timeout_cycles == 0) begin
$fatal(1, "MCU builder timeout: state=%0d block=%0d sample=%0d", u_dut.s_state_q,
u_dut.s_block_cnt_q, u_dut.s_sample_cnt_q);
end
if (error_flag || output_blocks != 6) begin
$fatal(1, "MCU builder completion mismatch: err=%0d blocks=%0d", error_flag, output_blocks);
end
+90
View File
@@ -0,0 +1,90 @@
`timescale 1ns / 1ps
module tc_sram_jpeg_workspace_tb;
logic clk = 1'b0;
logic row_cs;
logic [ 5:0] row_addr;
logic [63:0] row_data_i;
logic row_wren;
logic [63:0] row_data_o;
logic coeff_a_cs;
logic [ 5:0] coeff_a_addr;
logic [31:0] coeff_a_data_i;
logic coeff_a_wren;
logic [31:0] coeff_a_data_o;
logic coeff_b_cs;
logic [ 5:0] coeff_b_addr;
logic [31:0] coeff_b_data_i;
logic coeff_b_wren;
logic [31:0] coeff_b_data_o;
always #5 clk = ~clk;
tc_sram_64x64 u_row_sram (
.clk_i (clk),
.cs_i (row_cs),
.addr_i(row_addr),
.data_i(row_data_i),
.wren_i(row_wren),
.data_o(row_data_o)
);
tc_sram_64x32_2p u_coeff_sram (
.clk_i (clk),
.a_cs_i (coeff_a_cs),
.a_addr_i(coeff_a_addr),
.a_data_i(coeff_a_data_i),
.a_wren_i(coeff_a_wren),
.a_data_o(coeff_a_data_o),
.b_cs_i (coeff_b_cs),
.b_addr_i(coeff_b_addr),
.b_data_i(coeff_b_data_i),
.b_wren_i(coeff_b_wren),
.b_data_o(coeff_b_data_o)
);
initial begin
row_cs = 1'b0;
row_addr = '0;
row_data_i = '0;
row_wren = 1'b0;
coeff_a_cs = 1'b0;
coeff_a_addr = '0;
coeff_a_data_i = '0;
coeff_a_wren = 1'b0;
coeff_b_cs = 1'b0;
coeff_b_addr = '0;
coeff_b_data_i = '0;
coeff_b_wren = 1'b0;
@(negedge clk);
row_cs = 1'b1;
row_wren = 1'b1;
row_addr = 6'd47;
row_data_i = 64'h0123_4567_89ab_cdef;
coeff_a_cs = 1'b1;
coeff_a_wren = 1'b1;
coeff_a_addr = 6'd3;
coeff_a_data_i = 32'h1122_3344;
coeff_b_cs = 1'b1;
coeff_b_wren = 1'b1;
coeff_b_addr = 6'd61;
coeff_b_data_i = 32'haabb_ccdd;
@(negedge clk);
row_wren = 1'b0;
coeff_a_wren = 1'b0;
coeff_b_wren = 1'b0;
@(negedge clk);
if (row_data_o !== 64'h0123_4567_89ab_cdef || coeff_a_data_o !== 32'h1122_3344 ||
coeff_b_data_o !== 32'haabb_ccdd) begin
$fatal(1, "JPEG SRAM wrapper data mismatch");
end
row_cs = 1'b0;
coeff_a_cs = 1'b0;
coeff_b_cs = 1'b0;
$display("JPEG SRAM workspace wrapper test passed");
$finish;
end
endmodule