Checkpoint JPEG-LS hardening and logs

Bundle SCAN_ROWS=64 RTL updates, refreshed CharLS reference streams, and a tracked checkpoint log with regression and quick-synth results.

Includes FSM safe-state hardening, control-path cleanup, and the latest quick synthesis snapshot on xc7vx690tffg1761-2.
This commit is contained in:
2026-04-17 18:05:48 +08:00
parent 50539f4abb
commit 9ace25b62b
93 changed files with 1005 additions and 392 deletions

View File

@@ -4,12 +4,12 @@
// Table : N/A
// Pseudocode : RANGE, qbpp, and LIMIT derivation from MAXVAL and NEAR
// Trace : docs/jls_traceability.md#jls-coding-parameters
// Example : PIX_WIDTH=8,NEAR=0 gives RANGE=256,qbpp=8,LIMIT=32.
// Example : PIX_WIDTH=16 and NEAR=64 gives RANGE=510, qbpp=9, LIMIT=64.
//
// JPEG-LS coding parameter helper. RANGE depends on NEAR through
// RANGE = floor((MAXVAL + 2*NEAR)/(2*NEAR+1)) + 1. This is a strip-level
// control path, so the generic arithmetic is acceptable here and keeps the
// pixel pipeline free from runtime division logic.
// JPEG-LS coding parameter helper. The project NEAR controller only emits a
// discrete ladder {0,1,2,4,8,16,32,64,127,255}. A direct table lookup keeps
// strip-start timing shallow and removes the long carry-chain path that the
// generic Annex G.2 arithmetic created in synthesis.
`default_nettype none
@@ -26,126 +26,352 @@ module jls_coding_params #(
// JPEG-LS quantized bits per sample, ceil(log2(RANGE)).
output logic [4:0] qbpp,
// Precomputed RANGE * (2*NEAR+1) used by Annex A.5 reconstruction wrap.
output logic [16:0] RANGE_SCALE,
// JPEG-LS LIMIT parameter used by regular-mode Golomb coding.
output logic [6:0] LIMIT
);
integer maximum_sample_value_int;
integer maximum_near_int;
integer near_clamped_int;
integer denominator_int;
integer range_int;
integer qbpp_int;
integer limit_int;
always_comb begin
maximum_sample_value_int = 65535;
limit_int = 64;
RANGE = 17'd65536;
qbpp = 5'd16;
RANGE_SCALE = 17'd65536;
LIMIT = 7'd64;
case (PIX_WIDTH)
8: begin
maximum_sample_value_int = 255;
limit_int = 32;
LIMIT = 7'd32;
case (NEAR)
8'd0: begin
RANGE = 17'd256;
qbpp = 5'd8;
RANGE_SCALE = 17'd256;
end
8'd1: begin
RANGE = 17'd86;
qbpp = 5'd7;
RANGE_SCALE = 17'd258;
end
8'd2: begin
RANGE = 17'd52;
qbpp = 5'd6;
RANGE_SCALE = 17'd260;
end
8'd4: begin
RANGE = 17'd30;
qbpp = 5'd5;
RANGE_SCALE = 17'd270;
end
8'd8: begin
RANGE = 17'd16;
qbpp = 5'd4;
RANGE_SCALE = 17'd272;
end
8'd16: begin
RANGE = 17'd9;
qbpp = 5'd4;
RANGE_SCALE = 17'd297;
end
8'd31: begin
RANGE = 17'd6;
qbpp = 5'd3;
RANGE_SCALE = 17'd378;
end
8'd32: begin
RANGE = 17'd5;
qbpp = 5'd3;
RANGE_SCALE = 17'd325;
end
8'd63: begin
RANGE = 17'd4;
qbpp = 5'd2;
RANGE_SCALE = 17'd508;
end
8'd64: begin
RANGE = 17'd3;
qbpp = 5'd2;
RANGE_SCALE = 17'd387;
end
8'd127: begin
RANGE = 17'd2;
qbpp = 5'd1;
RANGE_SCALE = 17'd510;
end
default: begin
RANGE = 17'd2;
qbpp = 5'd1;
RANGE_SCALE = 17'd510;
end
endcase
end
10: begin
maximum_sample_value_int = 1023;
limit_int = 40;
LIMIT = 7'd40;
case (NEAR)
8'd0: begin
RANGE = 17'd1024;
qbpp = 5'd10;
RANGE_SCALE = 17'd1024;
end
8'd1: begin
RANGE = 17'd342;
qbpp = 5'd9;
RANGE_SCALE = 17'd1026;
end
8'd2: begin
RANGE = 17'd206;
qbpp = 5'd8;
RANGE_SCALE = 17'd1030;
end
8'd4: begin
RANGE = 17'd115;
qbpp = 5'd7;
RANGE_SCALE = 17'd1035;
end
8'd8: begin
RANGE = 17'd62;
qbpp = 5'd6;
RANGE_SCALE = 17'd1054;
end
8'd16: begin
RANGE = 17'd32;
qbpp = 5'd5;
RANGE_SCALE = 17'd1056;
end
8'd31: begin
RANGE = 17'd18;
qbpp = 5'd5;
RANGE_SCALE = 17'd1134;
end
8'd32: begin
RANGE = 17'd17;
qbpp = 5'd5;
RANGE_SCALE = 17'd1105;
end
8'd63: begin
RANGE = 17'd10;
qbpp = 5'd4;
RANGE_SCALE = 17'd1270;
end
8'd64: begin
RANGE = 17'd9;
qbpp = 5'd4;
RANGE_SCALE = 17'd1161;
end
8'd127: begin
RANGE = 17'd6;
qbpp = 5'd3;
RANGE_SCALE = 17'd1530;
end
default: begin
RANGE = 17'd4;
qbpp = 5'd2;
RANGE_SCALE = 17'd2044;
end
endcase
end
12: begin
maximum_sample_value_int = 4095;
limit_int = 48;
LIMIT = 7'd48;
case (NEAR)
8'd0: begin
RANGE = 17'd4096;
qbpp = 5'd12;
RANGE_SCALE = 17'd4096;
end
8'd1: begin
RANGE = 17'd1366;
qbpp = 5'd11;
RANGE_SCALE = 17'd4098;
end
8'd2: begin
RANGE = 17'd820;
qbpp = 5'd10;
RANGE_SCALE = 17'd4100;
end
8'd4: begin
RANGE = 17'd456;
qbpp = 5'd9;
RANGE_SCALE = 17'd4104;
end
8'd8: begin
RANGE = 17'd242;
qbpp = 5'd8;
RANGE_SCALE = 17'd4114;
end
8'd16: begin
RANGE = 17'd126;
qbpp = 5'd7;
RANGE_SCALE = 17'd4158;
end
8'd31: begin
RANGE = 17'd66;
qbpp = 5'd7;
RANGE_SCALE = 17'd4158;
end
8'd32: begin
RANGE = 17'd64;
qbpp = 5'd6;
RANGE_SCALE = 17'd4160;
end
8'd63: begin
RANGE = 17'd34;
qbpp = 5'd6;
RANGE_SCALE = 17'd4318;
end
8'd64: begin
RANGE = 17'd33;
qbpp = 5'd6;
RANGE_SCALE = 17'd4257;
end
8'd127: begin
RANGE = 17'd18;
qbpp = 5'd5;
RANGE_SCALE = 17'd4590;
end
default: begin
RANGE = 17'd10;
qbpp = 5'd4;
RANGE_SCALE = 17'd5110;
end
endcase
end
14: begin
maximum_sample_value_int = 16383;
limit_int = 56;
LIMIT = 7'd56;
case (NEAR)
8'd0: begin
RANGE = 17'd16384;
qbpp = 5'd14;
RANGE_SCALE = 17'd16384;
end
8'd1: begin
RANGE = 17'd5462;
qbpp = 5'd13;
RANGE_SCALE = 17'd16386;
end
8'd2: begin
RANGE = 17'd3278;
qbpp = 5'd12;
RANGE_SCALE = 17'd16390;
end
8'd4: begin
RANGE = 17'd1822;
qbpp = 5'd11;
RANGE_SCALE = 17'd16398;
end
8'd8: begin
RANGE = 17'd965;
qbpp = 5'd10;
RANGE_SCALE = 17'd16405;
end
8'd16: begin
RANGE = 17'd498;
qbpp = 5'd9;
RANGE_SCALE = 17'd16434;
end
8'd31: begin
RANGE = 17'd262;
qbpp = 5'd9;
RANGE_SCALE = 17'd16506;
end
8'd32: begin
RANGE = 17'd254;
qbpp = 5'd8;
RANGE_SCALE = 17'd16510;
end
8'd63: begin
RANGE = 17'd130;
qbpp = 5'd8;
RANGE_SCALE = 17'd16510;
end
8'd64: begin
RANGE = 17'd128;
qbpp = 5'd7;
RANGE_SCALE = 17'd16512;
end
8'd127: begin
RANGE = 17'd66;
qbpp = 5'd7;
RANGE_SCALE = 17'd16830;
end
default: begin
RANGE = 17'd34;
qbpp = 5'd6;
RANGE_SCALE = 17'd17374;
end
endcase
end
default: begin
maximum_sample_value_int = 65535;
limit_int = 64;
LIMIT = 7'd64;
case (NEAR)
8'd0: begin
RANGE = 17'd65536;
qbpp = 5'd16;
RANGE_SCALE = 17'd65536;
end
8'd1: begin
RANGE = 17'd21846;
qbpp = 5'd15;
RANGE_SCALE = 17'd65538;
end
8'd2: begin
RANGE = 17'd13108;
qbpp = 5'd14;
RANGE_SCALE = 17'd65540;
end
8'd4: begin
RANGE = 17'd7283;
qbpp = 5'd13;
RANGE_SCALE = 17'd65547;
end
8'd8: begin
RANGE = 17'd3856;
qbpp = 5'd12;
RANGE_SCALE = 17'd65552;
end
8'd16: begin
RANGE = 17'd1987;
qbpp = 5'd11;
RANGE_SCALE = 17'd65571;
end
8'd31: begin
RANGE = 17'd1042;
qbpp = 5'd11;
RANGE_SCALE = 17'd65646;
end
8'd32: begin
RANGE = 17'd1010;
qbpp = 5'd10;
RANGE_SCALE = 17'd65650;
end
8'd63: begin
RANGE = 17'd518;
qbpp = 5'd10;
RANGE_SCALE = 17'd65786;
end
8'd64: begin
RANGE = 17'd510;
qbpp = 5'd9;
RANGE_SCALE = 17'd65790;
end
8'd127: begin
RANGE = 17'd258;
qbpp = 5'd9;
RANGE_SCALE = 17'd65790;
end
default: begin
RANGE = 17'd130;
qbpp = 5'd8;
RANGE_SCALE = 17'd66430;
end
endcase
end
endcase
end
always_comb begin
maximum_near_int = maximum_sample_value_int / 2;
if (maximum_near_int > 255) begin
maximum_near_int = 255;
end
end
always_comb begin
near_clamped_int = NEAR;
if (near_clamped_int > maximum_near_int) begin
near_clamped_int = maximum_near_int;
end
end
always_comb begin
denominator_int = (2 * near_clamped_int) + 1;
range_int = ((maximum_sample_value_int + (2 * near_clamped_int)) / denominator_int) + 1;
end
always_comb begin
qbpp_int = 0;
if (range_int > 1) begin
qbpp_int = 1;
if (range_int > 2) begin
qbpp_int = 2;
end
if (range_int > 4) begin
qbpp_int = 3;
end
if (range_int > 8) begin
qbpp_int = 4;
end
if (range_int > 16) begin
qbpp_int = 5;
end
if (range_int > 32) begin
qbpp_int = 6;
end
if (range_int > 64) begin
qbpp_int = 7;
end
if (range_int > 128) begin
qbpp_int = 8;
end
if (range_int > 256) begin
qbpp_int = 9;
end
if (range_int > 512) begin
qbpp_int = 10;
end
if (range_int > 1024) begin
qbpp_int = 11;
end
if (range_int > 2048) begin
qbpp_int = 12;
end
if (range_int > 4096) begin
qbpp_int = 13;
end
if (range_int > 8192) begin
qbpp_int = 14;
end
if (range_int > 16384) begin
qbpp_int = 15;
end
if (range_int > 32768) begin
qbpp_int = 16;
end
end
end
always_comb begin
RANGE = range_int[16:0];
qbpp = qbpp_int[4:0];
LIMIT = limit_int[6:0];
end
endmodule
`default_nettype wire

View File

@@ -100,7 +100,6 @@ module jls_context_model #(
logic pending_strip_first_pixel;
logic pending_strip_last_pixel;
logic [PIX_WIDTH-1:0] pending_Px;
logic [8:0] pending_context_index;
logic pending_context_negative;
logic pending_run_mode_context;
@@ -693,7 +692,6 @@ module jls_context_model #(
pending_strip_first_pixel <= 1'b0;
pending_strip_last_pixel <= 1'b0;
pending_Px <= {PIX_WIDTH{1'b0}};
pending_context_index <= 9'd0;
pending_context_negative <= 1'b0;
pending_run_mode_context <= 1'b0;
pending_bypass_valid <= 1'b0;
@@ -737,7 +735,6 @@ module jls_context_model #(
pending_strip_first_pixel <= issue_slot_strip_first_pixel;
pending_strip_last_pixel <= issue_slot_strip_last_pixel;
pending_Px <= issue_slot_Px;
pending_context_index <= issue_slot_context_index;
pending_context_negative <= issue_slot_context_negative;
pending_run_mode_context <= issue_slot_run_mode_context;
pending_bypass_valid <= issue_slot_bypass_valid;

View File

@@ -83,11 +83,11 @@ module jls_context_update (
// Signed and absolute forms of Errval.
logic signed [32:0] Errval_ext;
logic [32:0] abs_Errval_ext;
logic [31:0] abs_Errval_ext;
// Stage-1 update terms from Annex A.6.
logic signed [9:0] near_scale;
logic signed [40:0] B_delta;
(* use_dsp = "yes" *) logic signed [40:0] B_delta;
logic [31:0] A_accum_next;
logic signed [40:0] B_accum_next;
logic [15:0] N_halved_plus_one_next;
@@ -287,21 +287,16 @@ module jls_context_update (
logic result_promote_next;
// Shared narrow-scale multiplier for Annex A.6 Errval*(2*NEAR+1).
jls_near_scale_mul #(
.INPUT_WIDTH(33),
.OUTPUT_WIDTH(41)
) context_update_near_scale_mul_i (
.multiplicand_i(s1_Errval_ext),
.near_scale_i(s1_near_scale[8:0]),
.product_o(B_delta)
);
always_comb begin
B_delta = s1_Errval_ext * $signed(s1_near_scale[8:0]);
end
always_comb begin
Errval_ext = {s0_Errval[31], s0_Errval};
end
always_comb begin
abs_Errval_ext = Errval_ext[32:0];
abs_Errval_ext = Errval_ext[31:0];
if (Errval_ext < 33'sd0) begin
abs_Errval_ext = -Errval_ext;
end

View File

@@ -64,9 +64,9 @@ module jls_error_mapper (
// Source value after optional context correction.
logic signed [31:0] corrected_Errval;
logic signed [32:0] corrected_Errval_ext;
logic signed [32:0] abs_Errval_ext;
logic [32:0] MErrval_ext;
logic signed [31:0] corrected_Errval_ext;
logic [31:0] abs_Errval_ext;
logic [31:0] MErrval_ext;
// Handshake terms.
logic slot_open;
@@ -80,7 +80,7 @@ module jls_error_mapper (
end
always_comb begin
corrected_Errval_ext = {corrected_Errval[31], corrected_Errval};
corrected_Errval_ext = corrected_Errval;
end
always_comb begin
@@ -91,9 +91,9 @@ module jls_error_mapper (
end
always_comb begin
MErrval_ext = abs_Errval_ext[32:0] << 1;
if (corrected_Errval_ext < 33'sd0) begin
MErrval_ext = (abs_Errval_ext[32:0] << 1) - 33'd1;
MErrval_ext = abs_Errval_ext << 1;
if (corrected_Errval_ext < 32'sd0) begin
MErrval_ext = (abs_Errval_ext << 1) - 32'd1;
end
end
@@ -130,7 +130,7 @@ module jls_error_mapper (
if (accept_err) begin
mapped_valid <= 1'b1;
MErrval <= MErrval_ext[31:0];
MErrval <= MErrval_ext;
mapped_k <= k;
mapped_limit <= limit;
mapped_qbpp <= qbpp;

View File

@@ -78,7 +78,7 @@ module jls_golomb_encoder #(
localparam logic [6:0] MAX_CODE_BITS_VALUE = MAX_CODE_BITS;
// Current state.
golomb_state_e state;
(* fsm_safe_state = "reset_state" *) golomb_state_e state;
// Latched coding parameters for the active mapped-error event.
logic [6:0] prefix_remaining;

View File

@@ -98,7 +98,7 @@ module jls_header_writer #(
} header_state_e;
// Current and next state for marker emission.
header_state_e state;
(* fsm_safe_state = "reset_state" *) header_state_e state;
header_state_e state_next;
// Byte indexes inside the header and EOI byte sequences.
@@ -202,7 +202,7 @@ module jls_header_writer #(
always_comb begin
header_byte_index = header_index;
if (state == STATE_IDLE && accept_start) begin
if (state == STATE_HEADER && !byte_valid) begin
header_byte_index = 6'd0;
end else if (state == STATE_HEADER && output_fire && header_index != HEADER_LAST_INDEX) begin
header_byte_index = header_index + 6'd1;
@@ -337,18 +337,22 @@ module jls_header_writer #(
byte_valid_next = 1'b0;
byte_data_next = 8'h00;
original_image_start_next = 1'b0;
if (accept_start) begin
byte_valid_next = 1'b1;
byte_data_next = header_byte;
original_image_start_next = original_image_first_strip;
end else if (accept_finish) begin
if (accept_finish) begin
byte_valid_next = 1'b1;
byte_data_next = eoi_byte;
end
end
STATE_HEADER: begin
if (output_fire) begin
if (!byte_valid) begin
byte_valid_next = 1'b1;
byte_data_next = header_byte;
if (latched_original_image_first_strip) begin
original_image_start_next = 1'b1;
end else begin
original_image_start_next = 1'b0;
end
end else if (output_fire) begin
if (header_index == HEADER_LAST_INDEX) begin
byte_valid_next = 1'b0;
byte_data_next = 8'h00;

View File

@@ -29,7 +29,7 @@ module jls_input_ctrl #(
parameter int MAX_PIC_ROW = 4096,
// Number of original-image rows in one standalone JPEG-LS strip frame.
parameter int SCAN_ROWS = 16,
parameter int SCAN_ROWS = 64,
// Packed input FIFO width: one SOF sideband bit per input byte lane.
parameter int IFIFO_DATA_WIDTH = ((PIX_WIDTH + 7) / 8) * 9
@@ -149,6 +149,7 @@ module jls_input_ctrl #(
// Decoded fields from the FIFO data word.
logic fifo_word_sof;
logic [PIX_WIDTH-1:0] fifo_word_sample;
(* keep = "true" *) logic fifo_word_spare_observed;
// Coordinate boundary signals for the next accepted in-frame pixel.
logic [12:0] active_pic_col_last;
@@ -165,6 +166,13 @@ module jls_input_ctrl #(
assign fifo_word_sof = ififo_rdata[SOF_BIT_INDEX];
assign fifo_word_sample = ififo_rdata[PIX_WIDTH-1:0];
always_comb begin
fifo_word_spare_observed = 1'b0;
if (PIX_WIDTH != 8) begin
fifo_word_spare_observed = ififo_rdata[16];
end
end
always_comb begin
cfg_col_in_range = 1'b0;
if (cfg_pic_col >= MIN_PIC_COL_VALUE && cfg_pic_col <= MAX_PIC_COL_VALUE) begin

View File

@@ -102,7 +102,7 @@ module jls_mode_router #(
EVENT_INTERRUPT = 2'd3
} event_kind_e;
router_state_e state;
(* fsm_safe_state = "reset_state" *) router_state_e state;
event_kind_e event_kind;
event_kind_e event_kind_next;

View File

@@ -84,7 +84,7 @@ module jls_near_ctrl #(
logic [3:0] current_near_level;
// Strip-level source and target bit calculations.
logic [47:0] strip_pixel_count_ext;
logic [43:0] strip_pixel_count_ext;
logic [47:0] strip_source_bits;
logic [47:0] strip_target_bits;
logic [47:0] strip_actual_bits;
@@ -189,38 +189,38 @@ module jls_near_ctrl #(
end
always_comb begin
strip_pixel_count_ext = {16'd0, strip_pixel_count};
strip_pixel_count_ext = {12'd0, strip_pixel_count};
end
always_comb begin
strip_source_bits = {48{1'b0}};
case (PIX_WIDTH)
8: begin
strip_source_bits = {strip_pixel_count_ext[44:0], 3'b000};
strip_source_bits = {strip_pixel_count_ext, 4'd0};
end
10: begin
strip_source_bits = {strip_pixel_count_ext[44:0], 3'b000} +
{strip_pixel_count_ext[46:0], 1'b0};
strip_source_bits = {strip_pixel_count_ext, 4'd0} +
{2'd0, strip_pixel_count_ext, 2'd0};
end
12: begin
strip_source_bits = {strip_pixel_count_ext[44:0], 3'b000} +
{strip_pixel_count_ext[45:0], 2'b00};
strip_source_bits = {strip_pixel_count_ext, 4'd0} +
{1'd0, strip_pixel_count_ext, 3'd0};
end
14: begin
strip_source_bits = {strip_pixel_count_ext[44:0], 3'b000} +
{strip_pixel_count_ext[45:0], 2'b00} +
{strip_pixel_count_ext[46:0], 1'b0};
strip_source_bits = {strip_pixel_count_ext, 4'd0} +
{1'd0, strip_pixel_count_ext, 3'd0} +
{2'd0, strip_pixel_count_ext, 2'd0};
end
16: begin
strip_source_bits = {strip_pixel_count_ext[43:0], 4'b0000};
strip_source_bits = {strip_pixel_count_ext, 4'd0};
end
default: begin
strip_source_bits = {strip_pixel_count_ext[43:0], 4'b0000};
strip_source_bits = {strip_pixel_count_ext, 4'd0};
end
endcase
end

View File

@@ -84,10 +84,9 @@ module jls_neighbor_provider #(
// This provider is waiting for the current reconstructed sample.
output logic recon_ready,
// Reconstructed sample Rx and its coordinate.
// Reconstructed sample Rx and its x coordinate.
input var logic [PIX_WIDTH-1:0] recon_sample,
input var logic [12:0] recon_x,
input var logic [12:0] recon_y
input var logic [12:0] recon_x
);
// Two line banks implement previous/current reconstructed rows. The active
@@ -105,8 +104,6 @@ module jls_neighbor_provider #(
// One outstanding pixel is held until its reconstructed sample returns when
// NEAR>0. The NEAR=0 path does not use this bubble because Rx == X.
logic waiting_reconstruct;
logic [12:0] outstanding_x;
logic [12:0] outstanding_y;
logic outstanding_row_last;
// Left reconstructed neighbor for non-left-edge pixels in the current row.
@@ -150,6 +147,10 @@ module jls_neighbor_provider #(
logic line_write_bank;
logic [12:0] line_write_addr;
logic [PIX_WIDTH-1:0] line_write_sample;
logic line_write_pending_valid;
logic line_write_pending_bank;
logic [12:0] line_write_pending_addr;
logic [PIX_WIDTH-1:0] line_write_pending_sample;
// Handshake terms.
logic neigh_slot_open;
@@ -161,7 +162,6 @@ module jls_neighbor_provider #(
logic recon_bypass_not_row_last;
logic recon_bypass_strip_ok;
logic recon_bypass_x_matches;
logic recon_bypass_y_matches;
logic same_row_recon_bypass_ready;
always_comb begin
@@ -369,20 +369,13 @@ module jls_neighbor_provider #(
end
end
always_comb begin
recon_bypass_y_matches = 1'b0;
if (pixel_y == recon_y) begin
recon_bypass_y_matches = 1'b1;
end
end
always_comb begin
// Diagnostic decode for the previous same-row bypass condition. The
// timing path now waits one clock after Rx writeback instead of using this
// condition in pixel_ready.
same_row_recon_bypass_ready = 1'b0;
if (accept_recon_write && recon_bypass_not_row_last && recon_bypass_strip_ok &&
recon_bypass_x_matches && recon_bypass_y_matches) begin
recon_bypass_x_matches) begin
same_row_recon_bypass_ready = 1'b1;
end
end
@@ -392,8 +385,6 @@ module jls_neighbor_provider #(
read_bank <= 1'b0;
top_row_active <= 1'b1;
waiting_reconstruct <= 1'b0;
outstanding_x <= 13'd0;
outstanding_y <= 13'd0;
outstanding_row_last <= 1'b0;
left_Ra <= {PIX_WIDTH{1'b0}};
left_edge_Rc <= {PIX_WIDTH{1'b0}};
@@ -408,7 +399,32 @@ module jls_neighbor_provider #(
Rb <= {PIX_WIDTH{1'b0}};
Rc <= {PIX_WIDTH{1'b0}};
Rd <= {PIX_WIDTH{1'b0}};
line_write_pending_valid <= 1'b0;
line_write_pending_bank <= 1'b0;
line_write_pending_addr <= 13'd0;
line_write_pending_sample <= {PIX_WIDTH{1'b0}};
end else begin
if (line_write_pending_valid) begin
case (line_write_pending_bank)
1'b0: begin
line_bank0[line_write_pending_addr] <= line_write_pending_sample;
end
default: begin
line_bank1[line_write_pending_addr] <= line_write_pending_sample;
end
endcase
end
if (line_write_valid) begin
line_write_pending_valid <= 1'b1;
line_write_pending_bank <= line_write_bank;
line_write_pending_addr <= line_write_addr;
line_write_pending_sample <= line_write_sample;
end else begin
line_write_pending_valid <= 1'b0;
end
if (neigh_valid && neigh_ready && !accept_pixel) begin
neigh_valid <= 1'b0;
end
@@ -425,8 +441,6 @@ module jls_neighbor_provider #(
Rc <= Rc_next;
Rd <= Rd_next;
waiting_reconstruct <= accept_pixel_needs_recon;
outstanding_x <= pixel_x;
outstanding_y <= pixel_y;
outstanding_row_last <= pixel_x_is_right_edge;
if (strip_first_pixel) begin
@@ -466,17 +480,6 @@ module jls_neighbor_provider #(
end
end
if (line_write_valid) begin
case (line_write_bank)
1'b0: begin
line_bank0[line_write_addr] <= line_write_sample;
end
default: begin
line_bank1[line_write_addr] <= line_write_sample;
end
endcase
end
end
end

View File

@@ -6,9 +6,7 @@
// Trace : docs/jls_traceability.md#jls-output-buffer
// Example : A byte event {start=1, byte=8'hFF} becomes ofifo_wdata=9'h1FF.
//
// Internal output buffer for the 9-bit output FIFO interface. The external
// ofifo_full/ofifo_alfull inputs are intentionally ignored by RTL behavior per
// the SRS; simulation reports an error if a write happens while ofifo_full=1.
// Internal output buffer for the 9-bit output FIFO interface.
`default_nettype none
@@ -54,13 +52,7 @@ module jls_output_buffer #(
output logic ofifo_wr,
// Output FIFO data. Bit 8 marks original-image start; bits 7:0 carry bytes.
output logic [8:0] ofifo_wdata,
// Reserved output FIFO full flag. RTL ignores this input for flow control.
input var logic ofifo_full,
// Reserved output FIFO almost-full flag. RTL ignores this input.
input var logic ofifo_alfull
output logic [8:0] ofifo_wdata
);
// Pointer width for the circular byte buffer.
@@ -97,10 +89,6 @@ module jls_output_buffer #(
// Packed byte event stored in the internal buffer.
logic [8:0] buffer_write_word;
// Reserved input observation signal keeps intent explicit without changing
// flow control behavior.
logic ofifo_alfull_ignored;
assign ofifo_wclk = clk;
always_comb begin
@@ -171,10 +159,6 @@ module jls_output_buffer #(
end
end
always_comb begin
ofifo_alfull_ignored = ofifo_alfull;
end
always_ff @(posedge clk) begin
if (rst) begin
write_ptr <= {PTR_WIDTH{1'b0}};

View File

@@ -92,7 +92,7 @@ module jls_predictor #(
logic [PIX_WIDTH:0] rc_ext;
logic [PIX_WIDTH:0] neighbor_min_ext;
logic [PIX_WIDTH:0] neighbor_max_ext;
logic [PIX_WIDTH:0] med_sum_ext;
logic [PIX_WIDTH-1:0] med_sum_ext;
logic [PIX_WIDTH-1:0] med_selected;
// Split comparison terms. This mirrors the standard if/else decision while

View File

@@ -4,13 +4,12 @@
// Table : Table C.1 valid preset parameters, Table C.2 RESET, Table C.3 defaults
// Pseudocode : Default threshold calculation with MAXVAL and NEAR
// Trace : docs/jls_traceability.md#jls-preset-defaults
// Example : PIX_WIDTH=8, NEAR=0 gives MAXVAL=255, T1=3, T2=7, T3=21.
// Example : PIX_WIDTH=16 and NEAR=64 gives T1/T2/T3 = 210/387/724.
//
// JPEG-LS default preset coding parameter helper. This version follows the
// full CharLS/ISO formula and supports NEAR up to min(255, MAXVAL/2). The
// work is strip-level control, not per-pixel, so one combinational divide is
// acceptable here and keeps the pixel pipeline independent of the wider NEAR
// range.
// JPEG-LS default preset coding parameter helper. The project NEAR controller
// only emits a discrete ladder {0,1,2,4,8,16,32,64,127,255}. Direct table
// lookup keeps strip-start timing shallow and avoids the long threshold
// arithmetic carry chains from the generic Annex C.2.4.1.1 formula.
`default_nettype none
@@ -18,7 +17,7 @@ module jls_preset_defaults #(
// Compile-time grayscale sample precision. Legal values: 8, 10, 12, 14, 16.
parameter int PIX_WIDTH = 16
) (
// Requested NEAR value. Values above min(255, MAXVAL/2) are clamped.
// Requested NEAR value.
input var logic [7:0] near,
// JPEG-LS LSE MAXVAL preset coding parameter.
@@ -37,139 +36,338 @@ module jls_preset_defaults #(
output logic [15:0] preset_reset
);
localparam int DEFAULT_RESET_VALUE = 64;
localparam int BASIC_T1 = 3;
localparam int BASIC_T2 = 7;
localparam int BASIC_T3 = 21;
integer maximum_sample_value_int;
integer maximum_near_int;
integer near_clamped_int;
integer factor_int;
integer threshold1_candidate;
integer threshold2_candidate;
integer threshold3_candidate;
integer threshold1_int;
integer threshold2_int;
integer threshold3_int;
localparam logic [15:0] DEFAULT_RESET_VALUE = 16'd64;
always_comb begin
maximum_sample_value_int = 65535;
preset_maxval = 16'd65535;
preset_t1 = 16'd18;
preset_t2 = 16'd67;
preset_t3 = 16'd276;
preset_reset = DEFAULT_RESET_VALUE;
case (PIX_WIDTH)
8: begin
maximum_sample_value_int = 255;
preset_maxval = 16'd255;
case (near)
8'd0: begin
preset_t1 = 16'd3;
preset_t2 = 16'd7;
preset_t3 = 16'd21;
end
8'd1: begin
preset_t1 = 16'd6;
preset_t2 = 16'd12;
preset_t3 = 16'd28;
end
8'd2: begin
preset_t1 = 16'd9;
preset_t2 = 16'd17;
preset_t3 = 16'd35;
end
8'd4: begin
preset_t1 = 16'd15;
preset_t2 = 16'd27;
preset_t3 = 16'd49;
end
8'd8: begin
preset_t1 = 16'd27;
preset_t2 = 16'd47;
preset_t3 = 16'd77;
end
8'd16: begin
preset_t1 = 16'd51;
preset_t2 = 16'd87;
preset_t3 = 16'd133;
end
8'd31: begin
preset_t1 = 16'd96;
preset_t2 = 16'd162;
preset_t3 = 16'd238;
end
8'd32: begin
preset_t1 = 16'd99;
preset_t2 = 16'd167;
preset_t3 = 16'd245;
end
8'd63: begin
preset_t1 = 16'd192;
preset_t2 = 16'd255;
preset_t3 = 16'd255;
end
default: begin
preset_t1 = 16'd255;
preset_t2 = 16'd255;
preset_t3 = 16'd255;
end
endcase
end
10: begin
maximum_sample_value_int = 1023;
preset_maxval = 16'd1023;
case (near)
8'd0: begin
preset_t1 = 16'd6;
preset_t2 = 16'd19;
preset_t3 = 16'd72;
end
8'd1: begin
preset_t1 = 16'd9;
preset_t2 = 16'd24;
preset_t3 = 16'd79;
end
8'd2: begin
preset_t1 = 16'd12;
preset_t2 = 16'd29;
preset_t3 = 16'd86;
end
8'd4: begin
preset_t1 = 16'd18;
preset_t2 = 16'd39;
preset_t3 = 16'd100;
end
8'd8: begin
preset_t1 = 16'd30;
preset_t2 = 16'd59;
preset_t3 = 16'd128;
end
8'd16: begin
preset_t1 = 16'd54;
preset_t2 = 16'd99;
preset_t3 = 16'd184;
end
8'd31: begin
preset_t1 = 16'd99;
preset_t2 = 16'd174;
preset_t3 = 16'd289;
end
8'd32: begin
preset_t1 = 16'd102;
preset_t2 = 16'd179;
preset_t3 = 16'd296;
end
8'd63: begin
preset_t1 = 16'd195;
preset_t2 = 16'd334;
preset_t3 = 16'd513;
end
8'd64: begin
preset_t1 = 16'd198;
preset_t2 = 16'd339;
preset_t3 = 16'd520;
end
8'd127: begin
preset_t1 = 16'd387;
preset_t2 = 16'd654;
preset_t3 = 16'd961;
end
default: begin
preset_t1 = 16'd771;
preset_t2 = 16'd1023;
preset_t3 = 16'd1023;
end
endcase
end
12: begin
maximum_sample_value_int = 4095;
preset_maxval = 16'd4095;
case (near)
8'd0: begin
preset_t1 = 16'd18;
preset_t2 = 16'd67;
preset_t3 = 16'd276;
end
8'd1: begin
preset_t1 = 16'd21;
preset_t2 = 16'd72;
preset_t3 = 16'd283;
end
8'd2: begin
preset_t1 = 16'd24;
preset_t2 = 16'd77;
preset_t3 = 16'd290;
end
8'd4: begin
preset_t1 = 16'd30;
preset_t2 = 16'd87;
preset_t3 = 16'd304;
end
8'd8: begin
preset_t1 = 16'd42;
preset_t2 = 16'd107;
preset_t3 = 16'd332;
end
8'd16: begin
preset_t1 = 16'd66;
preset_t2 = 16'd147;
preset_t3 = 16'd388;
end
8'd31: begin
preset_t1 = 16'd111;
preset_t2 = 16'd222;
preset_t3 = 16'd493;
end
8'd32: begin
preset_t1 = 16'd114;
preset_t2 = 16'd227;
preset_t3 = 16'd500;
end
8'd63: begin
preset_t1 = 16'd207;
preset_t2 = 16'd382;
preset_t3 = 16'd717;
end
8'd64: begin
preset_t1 = 16'd210;
preset_t2 = 16'd387;
preset_t3 = 16'd724;
end
8'd127: begin
preset_t1 = 16'd399;
preset_t2 = 16'd702;
preset_t3 = 16'd1165;
end
default: begin
preset_t1 = 16'd783;
preset_t2 = 16'd1342;
preset_t3 = 16'd2061;
end
endcase
end
14: begin
maximum_sample_value_int = 16383;
preset_maxval = 16'd16383;
case (near)
8'd0: begin
preset_t1 = 16'd18;
preset_t2 = 16'd67;
preset_t3 = 16'd276;
end
8'd1: begin
preset_t1 = 16'd21;
preset_t2 = 16'd72;
preset_t3 = 16'd283;
end
8'd2: begin
preset_t1 = 16'd24;
preset_t2 = 16'd77;
preset_t3 = 16'd290;
end
8'd4: begin
preset_t1 = 16'd30;
preset_t2 = 16'd87;
preset_t3 = 16'd304;
end
8'd8: begin
preset_t1 = 16'd42;
preset_t2 = 16'd107;
preset_t3 = 16'd332;
end
8'd16: begin
preset_t1 = 16'd66;
preset_t2 = 16'd147;
preset_t3 = 16'd388;
end
8'd31: begin
preset_t1 = 16'd111;
preset_t2 = 16'd222;
preset_t3 = 16'd493;
end
8'd32: begin
preset_t1 = 16'd114;
preset_t2 = 16'd227;
preset_t3 = 16'd500;
end
8'd63: begin
preset_t1 = 16'd207;
preset_t2 = 16'd382;
preset_t3 = 16'd717;
end
8'd64: begin
preset_t1 = 16'd210;
preset_t2 = 16'd387;
preset_t3 = 16'd724;
end
8'd127: begin
preset_t1 = 16'd399;
preset_t2 = 16'd702;
preset_t3 = 16'd1165;
end
default: begin
preset_t1 = 16'd783;
preset_t2 = 16'd1342;
preset_t3 = 16'd2061;
end
endcase
end
default: begin
maximum_sample_value_int = 65535;
preset_maxval = 16'd65535;
case (near)
8'd0: begin
preset_t1 = 16'd18;
preset_t2 = 16'd67;
preset_t3 = 16'd276;
end
8'd1: begin
preset_t1 = 16'd21;
preset_t2 = 16'd72;
preset_t3 = 16'd283;
end
8'd2: begin
preset_t1 = 16'd24;
preset_t2 = 16'd77;
preset_t3 = 16'd290;
end
8'd4: begin
preset_t1 = 16'd30;
preset_t2 = 16'd87;
preset_t3 = 16'd304;
end
8'd8: begin
preset_t1 = 16'd42;
preset_t2 = 16'd107;
preset_t3 = 16'd332;
end
8'd16: begin
preset_t1 = 16'd66;
preset_t2 = 16'd147;
preset_t3 = 16'd388;
end
8'd31: begin
preset_t1 = 16'd111;
preset_t2 = 16'd222;
preset_t3 = 16'd493;
end
8'd32: begin
preset_t1 = 16'd114;
preset_t2 = 16'd227;
preset_t3 = 16'd500;
end
8'd63: begin
preset_t1 = 16'd207;
preset_t2 = 16'd382;
preset_t3 = 16'd717;
end
8'd64: begin
preset_t1 = 16'd210;
preset_t2 = 16'd387;
preset_t3 = 16'd724;
end
8'd127: begin
preset_t1 = 16'd399;
preset_t2 = 16'd702;
preset_t3 = 16'd1165;
end
default: begin
preset_t1 = 16'd783;
preset_t2 = 16'd1342;
preset_t3 = 16'd2061;
end
endcase
end
endcase
end
always_comb begin
maximum_near_int = maximum_sample_value_int / 2;
if (maximum_near_int > 255) begin
maximum_near_int = 255;
end
end
always_comb begin
near_clamped_int = near;
if (near_clamped_int > maximum_near_int) begin
near_clamped_int = maximum_near_int;
end
end
always_comb begin
factor_int = 1;
if (maximum_sample_value_int >= 128) begin
factor_int = maximum_sample_value_int;
if (factor_int > 4095) begin
factor_int = 4095;
end
factor_int = (factor_int + 128) / 256;
threshold1_candidate = (factor_int * (BASIC_T1 - 2)) + 2 + (3 * near_clamped_int);
if ((threshold1_candidate > maximum_sample_value_int) ||
(threshold1_candidate < (near_clamped_int + 1))) begin
threshold1_int = near_clamped_int + 1;
end else begin
threshold1_int = threshold1_candidate;
end
threshold2_candidate = (factor_int * (BASIC_T2 - 3)) + 3 + (5 * near_clamped_int);
if ((threshold2_candidate > maximum_sample_value_int) ||
(threshold2_candidate < threshold1_int)) begin
threshold2_int = threshold1_int;
end else begin
threshold2_int = threshold2_candidate;
end
threshold3_candidate = (factor_int * (BASIC_T3 - 4)) + 4 + (7 * near_clamped_int);
if ((threshold3_candidate > maximum_sample_value_int) ||
(threshold3_candidate < threshold2_int)) begin
threshold3_int = threshold2_int;
end else begin
threshold3_int = threshold3_candidate;
end
end else begin
factor_int = 256 / (maximum_sample_value_int + 1);
threshold1_candidate = (BASIC_T1 / factor_int) + (3 * near_clamped_int);
if (threshold1_candidate < 2) begin
threshold1_candidate = 2;
end
if ((threshold1_candidate > maximum_sample_value_int) ||
(threshold1_candidate < (near_clamped_int + 1))) begin
threshold1_int = near_clamped_int + 1;
end else begin
threshold1_int = threshold1_candidate;
end
threshold2_candidate = (BASIC_T2 / factor_int) + (5 * near_clamped_int);
if (threshold2_candidate < 3) begin
threshold2_candidate = 3;
end
if ((threshold2_candidate > maximum_sample_value_int) ||
(threshold2_candidate < threshold1_int)) begin
threshold2_int = threshold1_int;
end else begin
threshold2_int = threshold2_candidate;
end
threshold3_candidate = (BASIC_T3 / factor_int) + (7 * near_clamped_int);
if (threshold3_candidate < 4) begin
threshold3_candidate = 4;
end
if ((threshold3_candidate > maximum_sample_value_int) ||
(threshold3_candidate < threshold2_int)) begin
threshold3_int = threshold2_int;
end else begin
threshold3_int = threshold3_candidate;
end
end
end
always_comb begin
preset_maxval = maximum_sample_value_int[15:0];
preset_t1 = threshold1_int[15:0];
preset_t2 = threshold2_int[15:0];
preset_t3 = threshold3_int[15:0];
preset_reset = DEFAULT_RESET_VALUE[15:0];
end
endmodule
`default_nettype wire

View File

@@ -58,6 +58,7 @@ module jls_regular_error_quantizer #(
// Coding parameters for the current strip frame.
input var logic [16:0] RANGE,
input var logic [4:0] qbpp,
input var logic [16:0] RANGE_SCALE,
input var logic [6:0] LIMIT,
input var logic [7:0] NEAR,
@@ -121,7 +122,7 @@ module jls_regular_error_quantizer #(
// One-hot state decode keeps per-stage enables shallow. This is important
// when explicit timing-boundary registers below are preserved for 250 MHz.
(* fsm_encoding = "one_hot" *) quant_state_e state;
(* fsm_encoding = "one_hot", fsm_safe_state = "reset_state" *) quant_state_e state;
// Latched event fields.
logic [PIX_WIDTH-1:0] sample_latched;
@@ -138,6 +139,7 @@ module jls_regular_error_quantizer #(
logic signed [8:0] C_latched;
logic [15:0] N_latched;
logic [16:0] RANGE_latched;
logic [16:0] RANGE_SCALE_latched;
logic [4:0] qbpp_latched;
logic [6:0] LIMIT_latched;
logic [7:0] NEAR_latched;
@@ -197,7 +199,6 @@ module jls_regular_error_quantizer #(
logic signed [40:0] reconstruction_base_latched;
logic signed [40:0] reconstruction_sum;
logic signed [40:0] reconstruction_sum_latched;
logic signed [40:0] range_scaled;
logic signed [40:0] range_scaled_latched;
logic signed [40:0] reconstruction_fixed;
logic signed [40:0] reconstruction_fixed_latched;
@@ -224,15 +225,6 @@ module jls_regular_error_quantizer #(
.product_o(dequantized_error)
);
jls_near_scale_mul #(
.INPUT_WIDTH(18),
.OUTPUT_WIDTH(41)
) regular_recon_range_mul_i (
.multiplicand_i($signed({1'b0, RANGE_latched})),
.near_scale_i(near_scale_latched[8:0]),
.product_o(range_scaled)
);
jls_near_reciprocal_magic_lut regular_err_recip_magic_lut_i (
.near_i(NEAR_latched),
.reciprocal_magic_o(reciprocal_magic_next)
@@ -412,6 +404,7 @@ module jls_regular_error_quantizer #(
C_latched <= 9'sd0;
N_latched <= 16'd0;
RANGE_latched <= 17'd0;
RANGE_SCALE_latched <= 17'd0;
qbpp_latched <= 5'd0;
LIMIT_latched <= 7'd0;
NEAR_latched <= 8'd0;
@@ -478,6 +471,7 @@ module jls_regular_error_quantizer #(
C_latched <= corrected_C;
N_latched <= corrected_N;
RANGE_latched <= RANGE;
RANGE_SCALE_latched <= RANGE_SCALE;
qbpp_latched <= qbpp;
LIMIT_latched <= LIMIT;
NEAR_latched <= NEAR;
@@ -601,7 +595,7 @@ module jls_regular_error_quantizer #(
// NEAR-to-Rx combinational depth at the 250 MHz target.
dequantized_error_latched <= dequantized_error;
reconstruction_base_latched <= reconstruction_base;
range_scaled_latched <= range_scaled;
range_scaled_latched <= $signed({24'd0, RANGE_SCALE_latched});
maxval_ext_latched <= maxval_ext;
near_ext_latched <= near_ext;
state <= STATE_RECON_SUM;

View File

@@ -128,7 +128,7 @@ module jls_run_mode #(
STATE_ERRVAL_PREP = 5'd22
} run_state_e;
run_state_e state;
(* fsm_safe_state = "reset_state" *) run_state_e state;
run_state_e state_after_run_code;
// Standard RUNindex and run-interruption contexts. Context 0 is RItype=0,
@@ -238,7 +238,7 @@ module jls_run_mode #(
logic signed [32:0] modulo_Errval_after_add_latched;
logic signed [32:0] modulo_Errval;
logic signed [32:0] modulo_Errval_latched;
logic [32:0] abs_Errval_ext;
logic [30:0] abs_Errval_ext;
logic signed [32:0] sign_restored_Errval;
// Pipeline register between modulo/sign restoration and the run-interruption
// odd-scale reconstruction multiply.
@@ -298,7 +298,7 @@ module jls_run_mode #(
logic [4:0] k_latched;
logic [16:0] two_Nn_ext;
logic run_map_next;
logic [32:0] MErrval_ext;
logic [31:0] MErrval_ext;
logic [31:0] MErrval_latched;
logic [31:0] A_update_delta;
logic [31:0] A_update_delta_latched;
@@ -622,7 +622,7 @@ module jls_run_mode #(
end
always_comb begin
abs_Errval_ext = modulo_Errval_latched[32:0];
abs_Errval_ext = modulo_Errval_latched[30:0];
if (modulo_Errval_latched < 33'sd0) begin
abs_Errval_ext = -modulo_Errval_latched;
end
@@ -809,8 +809,8 @@ module jls_run_mode #(
end
always_comb begin
MErrval_ext = {abs_Errval_ext[31:0], 1'b0} - {32'd0, RItype_latched} -
{32'd0, run_map_next};
MErrval_ext = {abs_Errval_ext, 1'b0} - {31'd0, RItype_latched} -
{31'd0, run_map_next};
end
always_comb begin
@@ -1133,7 +1133,23 @@ module jls_run_mode #(
STATE_RUN_CODE_WAIT: begin
if (!run_code_valid) begin
state <= state_after_run_code;
case (state_after_run_code)
STATE_DONE: begin
state <= STATE_DONE;
end
STATE_ERRVAL_PREP: begin
state <= STATE_ERRVAL_PREP;
end
STATE_DIV_MUL: begin
state <= STATE_DIV_MUL;
end
default: begin
state <= STATE_IDLE;
end
endcase
end
end

View File

@@ -20,7 +20,7 @@ module jls_scan_ctrl #(
parameter int PIX_WIDTH = 16,
// Number of original-image rows in one standalone JPEG-LS strip frame.
parameter int SCAN_ROWS = 16
parameter int SCAN_ROWS = 64
) (
// Main 250 MHz clock.
input var logic clk,
@@ -256,7 +256,11 @@ module jls_scan_ctrl #(
always_comb begin
strip_start_valid = 1'b0;
if (slot_valid && slot_strip_first_pixel && finish_path_ready && enc_pixel_ready) begin
// Strip-start command may launch one cycle earlier than the first pixel
// forward. This cuts the downstream enc_pixel_ready chain out of the
// header/context start path while the slot still holds the first pixel
// until enc_pixel_ready eventually goes high.
if (slot_valid && slot_strip_first_pixel && finish_path_ready) begin
strip_start_valid = 1'b1;
end
end

View File

@@ -28,7 +28,7 @@ module jpeg_ls_encoder_top #(
parameter int MAX_PIC_ROW = 4096,
// Number of original-image rows in one standalone JPEG-LS strip frame.
parameter int SCAN_ROWS = 16,
parameter int SCAN_ROWS = 64,
// Maximum dynamic NEAR value.
parameter int MAX_NEAR = 255,
@@ -150,6 +150,12 @@ module jpeg_ls_encoder_top #(
logic strip_finish_accepted;
logic [7:0] active_strip_near;
logic [31:0] active_strip_pixel_count;
logic start_stage_valid;
logic [12:0] start_stage_strip_width;
logic [12:0] start_stage_strip_height;
logic start_stage_original_image_first_strip;
logic [7:0] start_stage_near;
logic start_stage_lossless_fast;
// Preset and coding parameters for strip-start header and active pipeline.
logic [15:0] start_preset_maxval;
@@ -158,8 +164,17 @@ module jpeg_ls_encoder_top #(
logic [15:0] start_preset_t3;
logic [15:0] start_preset_reset;
logic [16:0] start_RANGE;
(* keep = "true" *) logic [16:0] start_RANGE_SCALE_unused;
logic [4:0] start_qbpp;
logic [6:0] start_LIMIT;
logic [15:0] start_stage_preset_maxval;
logic [15:0] start_stage_preset_t1;
logic [15:0] start_stage_preset_t2;
logic [15:0] start_stage_preset_t3;
logic [15:0] start_stage_preset_reset;
logic [16:0] start_stage_RANGE;
logic [4:0] start_stage_qbpp;
logic [6:0] start_stage_LIMIT;
logic [15:0] active_preset_maxval;
logic [15:0] active_preset_t1;
logic [15:0] active_preset_t2;
@@ -167,6 +182,7 @@ module jpeg_ls_encoder_top #(
logic [15:0] active_preset_reset;
logic [16:0] active_RANGE;
logic [4:0] active_qbpp;
logic [16:0] active_RANGE_SCALE;
logic [6:0] active_LIMIT;
// Header writer and output byte arbitration.
@@ -188,6 +204,7 @@ module jpeg_ls_encoder_top #(
logic [7:0] arb_byte_data;
logic arb_original_image_start;
logic arb_byte_accepted;
(* keep = "true" *) logic reserved_ofifo_flags_observed;
logic output_pause_req;
logic [$clog2(OUT_BUF_BYTES + 1)-1:0] output_buffer_level;
@@ -207,7 +224,6 @@ module jpeg_ls_encoder_top #(
logic recon_ready_from_neighbor;
logic [PIX_WIDTH-1:0] recon_sample_to_neighbor;
logic [12:0] recon_x_to_neighbor;
logic [12:0] recon_y_to_neighbor;
logic scan_strip_lossless_fast;
logic active_strip_lossless_fast;
logic neighbor_lossless_fast;
@@ -428,7 +444,6 @@ module jpeg_ls_encoder_top #(
logic regular_recon_ready;
logic [PIX_WIDTH-1:0] regular_recon_sample_latched;
logic [12:0] regular_recon_x_latched;
logic [12:0] regular_recon_y_latched;
// Reconstructed-sample feedback queue. JPEG-LS Annex A.4/A.5 requires the
// next neighborhood to use encoder-side Rx history. This two-entry queue is
// a 250 MHz timing boundary between regular/run reconstruction sources and
@@ -444,13 +459,10 @@ module jpeg_ls_encoder_top #(
logic recon_feedback_load_next;
logic [PIX_WIDTH-1:0] recon_feedback_source_sample;
logic [12:0] recon_feedback_source_x;
logic [12:0] recon_feedback_source_y;
logic [PIX_WIDTH-1:0] recon_feedback_sample;
logic [12:0] recon_feedback_x;
logic [12:0] recon_feedback_y;
logic [PIX_WIDTH-1:0] recon_feedback_next_sample;
logic [12:0] recon_feedback_next_x;
logic [12:0] recon_feedback_next_y;
logic code_valid;
logic code_ready;
logic [MAX_CODE_BITS-1:0] code_bits;
@@ -472,12 +484,13 @@ module jpeg_ls_encoder_top #(
CLOSE_EOI_WAIT = 3'd4
} close_state_e;
close_state_e close_state;
(* fsm_safe_state = "reset_state", fsm_encoding = "one_hot" *) close_state_e close_state;
logic payload_flush_valid;
logic payload_flush_ready;
logic payload_flush_done;
logic [31:0] strip_output_byte_count;
logic [31:0] strip_output_byte_count_after_accept;
logic start_stage_capture;
always_comb begin
strip_start_accepted = 1'b0;
@@ -495,10 +508,19 @@ module jpeg_ls_encoder_top #(
always_comb begin
scan_strip_start_ready = 1'b0;
if (header_strip_start_ready && context_init_ready &&
run_strip_init_ready_q && !strip_open_active && close_state == CLOSE_IDLE &&
if (!strip_open_active && close_state == CLOSE_IDLE &&
!near_update_pending && !near_update_busy) begin
scan_strip_start_ready = 1'b1;
if (start_stage_valid) begin
if (header_strip_start_ready && context_init_ready &&
run_strip_init_ready_q) begin
scan_strip_start_ready = 1'b1;
end
end else if (!scan_strip_start_valid) begin
// Let the first strip pixel enter the scan-control holding slot. The
// next cycle captures NEAR/preset/coding params into start-stage
// registers, and only then releases strip_start_ready for launch.
scan_strip_start_ready = 1'b1;
end
end
end
@@ -506,6 +528,15 @@ module jpeg_ls_encoder_top #(
scan_strip_finish_ready = 1'b1;
end
always_comb begin
start_stage_capture = 1'b0;
if (scan_strip_start_valid && !start_stage_valid &&
!strip_open_active && close_state == CLOSE_IDLE &&
!near_update_pending && !near_update_busy) begin
start_stage_capture = 1'b1;
end
end
always_comb begin
// Fan out strip-start only after all start-side consumers are ready; this
// keeps header/context/run initialization atomic across strip boundaries.
@@ -573,18 +604,15 @@ module jpeg_ls_encoder_top #(
recon_feedback_source_valid = 1'b0;
recon_feedback_source_sample = regular_recon_sample_latched;
recon_feedback_source_x = regular_recon_x_latched;
recon_feedback_source_y = regular_recon_y_latched;
if (run_interruption_recon_valid) begin
recon_feedback_source_valid = 1'b1;
recon_feedback_source_sample = run_interruption_recon_sample;
recon_feedback_source_x = run_interruption_recon_x;
recon_feedback_source_y = run_interruption_recon_y;
end
if (mode_run_recon_valid && (!mode_run_segment_valid || mode_run_segment_ready)) begin
recon_feedback_source_valid = 1'b1;
recon_feedback_source_sample = mode_run_recon_sample;
recon_feedback_source_x = mode_run_recon_x;
recon_feedback_source_y = mode_run_recon_y;
end else if (regular_recon_valid && !run_interruption_recon_valid) begin
recon_feedback_source_valid = 1'b1;
end
@@ -629,7 +657,6 @@ module jpeg_ls_encoder_top #(
always_comb begin
recon_sample_to_neighbor = recon_feedback_sample;
recon_x_to_neighbor = recon_feedback_x;
recon_y_to_neighbor = recon_feedback_y;
end
always_comb begin
@@ -666,17 +693,14 @@ module jpeg_ls_encoder_top #(
recon_feedback_next_valid <= 1'b0;
recon_feedback_sample <= {PIX_WIDTH{1'b0}};
recon_feedback_x <= 13'd0;
recon_feedback_y <= 13'd0;
recon_feedback_next_sample <= {PIX_WIDTH{1'b0}};
recon_feedback_next_x <= 13'd0;
recon_feedback_next_y <= 13'd0;
end else begin
if (recon_feedback_to_neighbor) begin
if (recon_feedback_next_valid) begin
recon_feedback_valid <= 1'b1;
recon_feedback_sample <= recon_feedback_next_sample;
recon_feedback_x <= recon_feedback_next_x;
recon_feedback_y <= recon_feedback_next_y;
recon_feedback_next_valid <= 1'b0;
end else begin
recon_feedback_valid <= 1'b0;
@@ -687,14 +711,12 @@ module jpeg_ls_encoder_top #(
recon_feedback_valid <= 1'b1;
recon_feedback_sample <= recon_feedback_source_sample;
recon_feedback_x <= recon_feedback_source_x;
recon_feedback_y <= recon_feedback_source_y;
end
if (recon_feedback_load_next) begin
recon_feedback_next_valid <= 1'b1;
recon_feedback_next_sample <= recon_feedback_source_sample;
recon_feedback_next_x <= recon_feedback_source_x;
recon_feedback_next_y <= recon_feedback_source_y;
end
end
end
@@ -722,11 +744,11 @@ module jpeg_ls_encoder_top #(
run_mode_NEAR = active_strip_near;
run_mode_RESET = active_preset_reset;
if (run_strip_init_valid) begin
run_mode_RANGE = start_RANGE;
run_mode_qbpp = start_qbpp;
run_mode_LIMIT = start_LIMIT;
run_mode_NEAR = scan_strip_near;
run_mode_RESET = start_preset_reset;
run_mode_RANGE = start_stage_RANGE;
run_mode_qbpp = start_stage_qbpp;
run_mode_LIMIT = start_stage_LIMIT;
run_mode_NEAR = start_stage_near;
run_mode_RESET = start_stage_preset_reset;
end
end
@@ -1000,6 +1022,10 @@ module jpeg_ls_encoder_top #(
.near_image_ratio(near_image_ratio)
);
always_comb begin
reserved_ofifo_flags_observed = ofifo_full | ofifo_alfull;
end
always_comb begin
input_pixel_ready = scan_pixel_ready;
end
@@ -1021,6 +1047,7 @@ module jpeg_ls_encoder_top #(
.NEAR(scan_strip_near),
.RANGE(start_RANGE),
.qbpp(start_qbpp),
.RANGE_SCALE(start_RANGE_SCALE_unused),
.LIMIT(start_LIMIT)
);
@@ -1041,6 +1068,7 @@ module jpeg_ls_encoder_top #(
.NEAR(active_strip_near),
.RANGE(active_RANGE),
.qbpp(active_qbpp),
.RANGE_SCALE(active_RANGE_SCALE),
.LIMIT(active_LIMIT)
);
@@ -1051,15 +1079,15 @@ module jpeg_ls_encoder_top #(
.rst(rst),
.strip_start_valid(header_strip_start_valid),
.strip_start_ready(header_strip_start_ready),
.original_image_first_strip(scan_original_image_first_strip),
.strip_width(scan_strip_width),
.strip_height(scan_strip_height),
.near(scan_strip_near),
.preset_maxval(start_preset_maxval),
.preset_t1(start_preset_t1),
.preset_t2(start_preset_t2),
.preset_t3(start_preset_t3),
.preset_reset(start_preset_reset),
.original_image_first_strip(start_stage_original_image_first_strip),
.strip_width(start_stage_strip_width),
.strip_height(start_stage_strip_height),
.near(start_stage_near),
.preset_maxval(start_stage_preset_maxval),
.preset_t1(start_stage_preset_t1),
.preset_t2(start_stage_preset_t2),
.preset_t3(start_stage_preset_t3),
.preset_reset(start_stage_preset_reset),
.strip_finish_valid(header_strip_finish_valid),
.strip_finish_ready(header_strip_finish_ready),
.byte_valid(header_byte_valid),
@@ -1099,8 +1127,7 @@ module jpeg_ls_encoder_top #(
.recon_valid(recon_valid_to_neighbor),
.recon_ready(recon_ready_from_neighbor),
.recon_sample(recon_sample_to_neighbor),
.recon_x(recon_x_to_neighbor),
.recon_y(recon_y_to_neighbor)
.recon_x(recon_x_to_neighbor)
);
jls_mode_router #(
@@ -1230,7 +1257,7 @@ module jpeg_ls_encoder_top #(
.rst(rst),
.init_valid(context_init_valid),
.init_ready(context_init_ready),
.init_RANGE(start_RANGE),
.init_RANGE(start_stage_RANGE),
.init_busy(context_init_busy),
.init_done(context_init_done),
.context_valid(context_valid),
@@ -1327,6 +1354,7 @@ module jpeg_ls_encoder_top #(
.corrected_N(corrected_N),
.RANGE(active_RANGE),
.qbpp(active_qbpp),
.RANGE_SCALE(active_RANGE_SCALE),
.LIMIT(active_LIMIT),
.NEAR(active_strip_near),
.err_valid(regular_err_valid),
@@ -1512,9 +1540,7 @@ module jpeg_ls_encoder_top #(
.buffer_level(output_buffer_level),
.ofifo_wclk(ofifo_wclk),
.ofifo_wr(ofifo_wr),
.ofifo_wdata(ofifo_wdata),
.ofifo_full(ofifo_full),
.ofifo_alfull(ofifo_alfull)
.ofifo_wdata(ofifo_wdata)
);
always_ff @(posedge clk) begin
@@ -1523,6 +1549,20 @@ module jpeg_ls_encoder_top #(
active_strip_near <= 8'd0;
active_strip_lossless_fast <= 1'b1;
active_strip_pixel_count <= 32'd0;
start_stage_valid <= 1'b0;
start_stage_strip_width <= 13'd0;
start_stage_strip_height <= 13'd0;
start_stage_original_image_first_strip <= 1'b0;
start_stage_near <= 8'd0;
start_stage_lossless_fast <= 1'b1;
start_stage_preset_maxval <= 16'd0;
start_stage_preset_t1 <= 16'd0;
start_stage_preset_t2 <= 16'd0;
start_stage_preset_t3 <= 16'd0;
start_stage_preset_reset <= 16'd0;
start_stage_RANGE <= 17'd0;
start_stage_qbpp <= 5'd0;
start_stage_LIMIT <= 7'd0;
near_update_pending <= 1'b0;
near_strip_pixel_count_latched <= 32'd0;
near_strip_output_bytes_latched <= 32'd0;
@@ -1532,7 +1572,6 @@ module jpeg_ls_encoder_top #(
regular_recon_valid <= 1'b0;
regular_recon_sample_latched <= {PIX_WIDTH{1'b0}};
regular_recon_x_latched <= 13'd0;
regular_recon_y_latched <= 13'd0;
run_core_done_pending <= 1'b0;
run_core_last_pending <= 1'b0;
run_golomb_busy <= 1'b0;
@@ -1557,7 +1596,6 @@ module jpeg_ls_encoder_top #(
regular_recon_valid <= 1'b1;
regular_recon_sample_latched <= regular_reconstructed_sample;
regular_recon_x_latched <= regular_err_x;
regular_recon_y_latched <= regular_err_y;
end
if (regular_recon_valid && regular_recon_ready) begin
@@ -1614,10 +1652,28 @@ module jpeg_ls_encoder_top #(
end
endcase
if (start_stage_capture) begin
start_stage_valid <= 1'b1;
start_stage_strip_width <= scan_strip_width;
start_stage_strip_height <= scan_strip_height;
start_stage_original_image_first_strip <= scan_original_image_first_strip;
start_stage_near <= scan_strip_near;
start_stage_lossless_fast <= scan_strip_lossless_fast;
start_stage_preset_maxval <= start_preset_maxval;
start_stage_preset_t1 <= start_preset_t1;
start_stage_preset_t2 <= start_preset_t2;
start_stage_preset_t3 <= start_preset_t3;
start_stage_preset_reset <= start_preset_reset;
start_stage_RANGE <= start_RANGE;
start_stage_qbpp <= start_qbpp;
start_stage_LIMIT <= start_LIMIT;
end
if (strip_start_accepted) begin
strip_open_active <= 1'b1;
active_strip_near <= scan_strip_near;
active_strip_lossless_fast <= scan_strip_lossless_fast;
active_strip_near <= start_stage_near;
active_strip_lossless_fast <= start_stage_lossless_fast;
start_stage_valid <= 1'b0;
strip_output_byte_count <= 32'd0;
end else begin
strip_output_byte_count <= strip_output_byte_count_after_accept;