File: ../../Sources/openjls_top.vhd
0: -------------------------------------------------------------------------------------------------------------
1: -- Engineer: Vitor Mendes Camilo
2: --
3: -- Module Name: openjls_top - rtl
4: -- Description: JPEG-LS T.87 lossless encoder top level.
5: --
6: -- The architecture is a 14 stage pipeline with:
7: -- 1 input stage + 6 processing stages + 7 output stages.
8: -- The output stages are internally registered in the IPs, while the processing
9: -- stages are purely combinational and the inter-stage registers are placed in
10: -- this top-level wrapper
11: --
12: --------------------------------------------------------------------------------------------
13: -- PIPELINE
14: --------------------------------------------------------------------------------------------
15: --
16: -- Input Stage : Wire
17: --
18: -- RegInput -------
19: --
20: -- Stage 1 : A.1 gradients + A.3 mode select
21: -- line_buffer
22: --
23: -- Reg1 -----------
24: --
25: -- Stage 2 : regular {A.4, A.4.1, A.4.2} | run {A.14, A.15/16, A.17, A.18}
26: -- context_ram
27: --
28: -- Reg2 -----------
29: --
30: -- Stage 3 : regular {A.5, speculative 3×{A.6..A.9}} | RI {A.19, A.20}
31: -- feed-forward logic for speculation and Q3==Q4 forwarding
32: --
33: -- Reg3 -----------
34: --
35: -- Stage 4 : shared {A.10} | regular {A.12, A.13} | RI {A.23};
36: -- context writeback
37: --
38: -- Reg4 -----------
39: --
40: -- Stage 5 : regular {A.11} | RI {A.21, A.22};
41: -- mux select mapped errval
42: --
43: -- Reg5 -----------
44: --
45: -- Stage 6 : A.11.1 Golomb encoder
46: --
47: -- Reg6 -----------
48: --
49: -- Output Stages (internally registered):
50: --
51: -- bit_packer
52: -- byte_stuffer
53: -- jls_framer
54: --
55: -------------------------------------------------------------------------------------------------------------
56:
57: library ieee;
58: use ieee.std_logic_1164.all;
59: use ieee.numeric_std.all;
60: use work.openjls_pkg.all;
61:
62: library work;
63: use work.olo_base_pkg_math.log2ceil;
64:
65: entity openjls_top is
66: generic (
67: BITNESS : positive range 8 to 16 := 12;
68: MAX_IMAGE_WIDTH : positive range 4 to 65535 := 4096;
69: MAX_IMAGE_HEIGHT : positive range 1 to 65535 := 4096;
70: OUT_WIDTH : positive range 48 to 1024 := CO_OUT_WIDTH_STD
71: );
72: port (
73: iClk : in std_logic;
74: iRst : in std_logic;
75: iValid : in std_logic;
76: iPixel : in std_logic_vector(BITNESS - 1 downto 0);
77: oReady : out std_logic;
78: -- Fixed 16-bit (not log2ceil-sized): Vivado's block-design port-width
79: -- evaluator only handles literal arithmetic in port expressions. Values
80: -- above MAX_IMAGE_WIDTH/HEIGHT are clamped at sample time as before.
81: iImageWidth : in std_logic_vector(15 downto 0);
82: iImageHeight : in std_logic_vector(15 downto 0);
83: oData : out std_logic_vector(OUT_WIDTH - 1 downto 0);
84: oValid : out std_logic;
85: oKeep : out std_logic_vector(OUT_WIDTH / 8 - 1 downto 0);
86: oLast : out std_logic;
87: iReady : in std_logic
88: );
89: end entity openjls_top;
90:
91: architecture rtl of openjls_top is
92:
93: constant DEBUG_MODE : boolean := false;
94:
95: -------------------------------------------------------------------------------------------------------------
96: -- ENCODER PARAMETERS
97: -------------------------------------------------------------------------------------------------------------
98: -- Derived constants
99: constant MAX_VAL : natural := 2 ** BITNESS - 1;
100: constant RANGE_P : natural := MAX_VAL + 1;
101: constant QBPP : natural := log2ceil(RANGE_P);
102: constant BPP : natural := math_max(2, log2ceil(MAX_VAL + 1));
103: constant LIMIT : natural := 2 * (BPP + math_max(8, BPP));
104:
105: -- Widths computed locally from generics
106: constant ERROR_WIDTH : natural := BITNESS + 1;
107: constant MAPPED_ERROR_VAL_WIDTH : natural := BITNESS + 2;
108: constant RAM_DEPTH : positive := 367; -- 365 contexts + 2 RI-specific contexts
109: constant RESET : natural := 64; -- T.87
110: constant MAX_C : integer := 127; -- T.87
111: constant MIN_C : integer := - 128; -- T.87
112: constant ABS_MIN_C : natural := - MIN_C;
113: constant ABS_MAX_C : natural := MAX_C;
114:
115: --------------------------------------------------------------------------------------------
116: -- Context-variable widths.
117: --------------------------------------------------------------------------------------------
118: -- Two tiers:
119: -- _STORED : packed BRAM width (Murat 2018 Table I, "Optimal Bits to
120: -- Represent"). Encoding tricks applied at the BRAM boundary.
121: -- _WIDTH : pipeline arithmetic width (mid-update headroom for A.12/A.13).
122: -- Needed to compute intermediary values without overflow.
123: --
124: --------------------------------------------------------------------------------------------
125: -- Var Stored Encoding @ BRAM Pipeline width
126: --------------------------------------------------------------------------------------------
127: -- A bpp - 1 + ⌈log2(RESET)⌉ zero-extend on read _STORED + 1
128: -- B ⌈log2(RESET)⌉ (mag only) B = -unsigned(stored) BPP + 1 (signed)
129: -- C ⌈log2(max|MIN_C|,|MAX_C|)⌉+1 signed cast = _STORED
130: -- N ⌈log2(RESET)⌉ (RESET↦0) 0 ⇒ RESET log2ceil(RESET+1)
131: -- Nn ⌈log2(RESET)⌉ direct = _STORED
132:
133: constant A_STORED : natural := BPP - 1 + log2ceil(RESET);
134: constant B_STORED : natural := log2ceil(RESET);
135: constant C_STORED : natural := log2ceil(math_max(ABS_MIN_C, ABS_MAX_C)) + 1;
136: constant N_STORED : natural := log2ceil(RESET);
137: constant NN_STORED : natural := log2ceil(RESET);
138: constant A_WIDTH : natural := A_STORED + 1;
139: constant B_WIDTH : natural := BPP + 1;
140: constant C_WIDTH : natural := C_STORED;
141: constant N_WIDTH : natural := log2ceil(RESET + 1);
142: constant NN_WIDTH : natural := NN_STORED;
143: constant MAX_K : natural := A_WIDTH; -- A10 saturates Golomb k here (max k = bit-width of A)
144: constant K_WIDTH : natural := log2ceil(MAX_K + 1); -- holds k in [0, MAX_K]
145: constant TOTAL_WIDTH : natural := A_STORED + B_STORED + C_STORED + N_STORED;
146:
147: --------------------------------------------------------------------------------------------
148: -- Golomb / Raw suffix output widths.
149: --------------------------------------------------------------------------------------------
150: -- Raw : oRawSuffixVal up to RUN_CNT_WIDTH bits, oRawSuffixLen up to
151: -- J_MAX+1 = 16 distinct values (vJ+1, vJ ∈ [0..15] from T.87 J).
152: -- Gol. : regular suffix = k low bits (k <= MAX_K), escape suffix = QBPP bits;
153: -- both fit in MAX_K. Unary zeros <= LIMIT - QBPP - 1 (escape
154: -- threshold; regular quotient is strictly smaller).
155:
156: -- Run length bounded by image width (run cannot cross EOL).
157: constant RUN_CNT_WIDTH : natural := log2ceil(MAX_IMAGE_WIDTH + 1);
158: constant J_MAX_BITS : natural := 15; -- T.87 A.2.1, J[31] = 15
159: constant UNARY_WIDTH : natural := log2ceil(LIMIT - QBPP); -- regular quotient / escape threshold; max = LIMIT-QBPP-1
160: constant SUFFIX_WIDTH : natural := math_max(MAX_K, RUN_CNT_WIDTH); -- regular k bits / escape QBPP bits, both <= MAX_K
161: constant SUFFIXLEN_WIDTH : natural := math_max(K_WIDTH, log2ceil(J_MAX_BITS + 2)); -- regular k / escape QBPP, both <= K_WIDTH
162:
163: --------------------------------------------------------------------------------------------
164: -- Bit packer / byte stuffer / framer interface widths.
165: -- byte_stuffer is sized for AVERAGE rate; bursts absorbed by its buffer, which
166: -- asserts oAlmostFull and stalls upstream near full. OUT_BYTES_PER_CYCLE trades
167: -- fmax vs throughput; BURST_DEPTH=64 covers natural images with margin.
168: --------------------------------------------------------------------------------------------
169: constant BYTE_STUFFER_OUT_BYTES_PER_CYCLE : natural := 4; -- Hardcoded, fixed
170: constant BYTE_STUFFER_BURST_DEPTH : natural := 64; -- Can be tuned
171: constant BYTE_STUFFER_OUT_WIDTH : natural := BYTE_STUFFER_OUT_BYTES_PER_CYCLE * 8;
172:
173: --------------------------------------------------------------------------------------------
174: -- Packed context RAM word slicing
175: --------------------------------------------------------------------------------------------
176: -- Regular mode: (A | B | C | N)
177: -- Run mode: (A | NN | 0 | N)
178: constant CTX_A_HI : natural := TOTAL_WIDTH - 1;
179: constant CTX_A_LO : natural := TOTAL_WIDTH - A_STORED;
180: constant CTX_B_HI : natural := CTX_A_LO - 1;
181: constant CTX_B_LO : natural := CTX_A_LO - B_STORED;
182: constant CTX_C_HI : natural := CTX_B_LO - 1;
183: constant CTX_C_LO : natural := CTX_B_LO - C_STORED;
184: constant CTX_N_HI : natural := CTX_C_LO - 1;
185: constant CTX_N_LO : natural := 0;
186: constant CTX_NN_HI : natural := CTX_B_LO + NN_STORED - 1;
187: constant CTX_NN_LO : natural := CTX_B_LO;
188:
189: -------------------------------------------------------------------------------------------------------------
190: -- PIPELINE TOKEN RECORD
191: -------------------------------------------------------------------------------------------------------------
192: -- Fields cross inter-stage register boundaries;
193: -- combinational stage-local wires are NOT in the record.
194: --
195: -- Mode tag:
196: -- TOKEN_NONE : pipeline bubble — downstream stages NOP
197: -- TOKEN_REGULAR : regular-mode sample (Golomb only)
198: -- TOKEN_RUN_INTERRUPTION : run break (Golomb + A.16 raw prefix)
199: -- TOKEN_RAW : mid-run boundary emit (raw only)
200:
201: type t_token_mode is (token_none, token_regular, token_run, token_run_interruption, token_raw);
202:
203: type t_pipeline_token is record
204: mode : t_token_mode;
205: Ix : unsigned(BITNESS - 1 downto 0);
206: Ra : unsigned(BITNESS - 1 downto 0);
207: Rb : unsigned(BITNESS - 1 downto 0);
208: Rc : unsigned(BITNESS - 1 downto 0);
209: Q : unsigned(8 downto 0);
210: Sign : std_logic;
211: RiType : std_logic;
212: Aq : unsigned(A_WIDTH - 1 downto 0);
213: Bq : signed(B_WIDTH - 1 downto 0);
214: Cq : signed(C_WIDTH - 1 downto 0);
215: Nq : unsigned(N_WIDTH - 1 downto 0);
216: Nn : unsigned(NN_WIDTH - 1 downto 0);
217: Temp : unsigned(A_WIDTH - 1 downto 0);
218: Errval : signed(ERROR_WIDTH - 1 downto 0);
219: k : unsigned(K_WIDTH - 1 downto 0);
220: RawLen : unsigned(SUFFIXLEN_WIDTH - 1 downto 0);
221: RawVal : unsigned(SUFFIX_WIDTH - 1 downto 0);
222: RiRunIndex : unsigned(4 downto 0);
223: end record t_pipeline_token;
224:
225: constant CO_TOKEN_NONE : t_pipeline_token :=
226: (
227: mode => token_none,
228: Ix => (others => '0'),
229: Ra => (others => '0'),
230: Rb => (others => '0'),
231: Rc => (others => '0'),
232: Q => (others => '0'),
233: Sign => '0',
234: RiType => '0',
235: Aq => (others => '0'),
236: Bq => (others => '0'),
237: Cq => (others => '0'),
238: Nq => (others => '0'),
239: Nn => (others => '0'),
240: Temp => (others => '0'),
241: Errval => (others => '0'),
242: k => (others => '0'),
243: RawLen => (others => '0'),
244: RawVal => (others => '0'),
245: RiRunIndex => (others => '0')
246: );
247: -------------------------------------------------------------------------------------------------------------
248:
249: -- Backpressure / clock-enable. sStall drives a single coarse pipeline freeze
250: -- when the framer FIFO is approaching its nominal capacity. It also doubles
251: -- as the idle-power gate together with each stage's valid bits: a register
252: -- only updates when (NOT sStall) AND (current_valid OR upstream_valid), so a
253: -- bubble propagates exactly once and then the register stops toggling.
254: signal sFramerReady : std_logic;
255: signal sBsAlmostFullReg : std_logic;
256: signal sStall : std_logic;
257: signal sStallDelay : std_logic;
258: signal sStallUpstream : std_logic;
259: signal sStallLogic : std_logic;
260: signal sCE1 : std_logic;
261: signal sCE2 : std_logic;
262: signal sCE3 : std_logic;
263: signal sCE4 : std_logic;
264: signal sCE5, sCE6 : std_logic;
265:
266: -- Pipeline tokens + sideband
267: signal sReg1 : t_pipeline_token;
268: signal sReg2 : t_pipeline_token;
269: signal sReg3 : t_pipeline_token;
270: signal sReg4 : t_pipeline_token;
271: signal sReg1V : std_logic;
272: signal sReg2V : std_logic;
273: signal sReg3V : std_logic;
274: signal sReg4V : std_logic;
275: signal sReg1Eol : std_logic;
276: signal sReg1Eoi : std_logic;
277: signal sReg2Eoi : std_logic;
278: signal sReg3Eoi : std_logic;
279: signal sReg4Eoi : std_logic;
280:
281: -- Per-image parity bit: 1 bit assigned at Reg1, flipped at each EOI,
282: -- carried to the writeback stage. Avoid old image writing values into
283: -- the context ram that belongs to the new image.
284: signal sGenPar : std_logic;
285: signal sReg1Par : std_logic;
286: signal sReg2Par : std_logic;
287: signal sReg3Par : std_logic;
288: signal sCtxOwnerPar : std_logic; -- sticky: parity owning the ctx RAM (held thru bubbles)
289: signal sCtxRdPar : std_logic; -- effective owner this cycle (combinational)
290: signal sReg1ModeRun : std_logic;
291: signal sReg1D1 : signed(BITNESS downto 0);
292: signal sReg1D2 : signed(BITNESS downto 0);
293: signal sReg1D3 : signed(BITNESS downto 0);
294:
295: -- Input stage
296: signal sPixel : unsigned(BITNESS - 1 downto 0);
297: signal sImageWidth : unsigned(log2ceil(MAX_IMAGE_WIDTH + 1) - 1 downto 0);
298: signal sImageHeight : unsigned(log2ceil(MAX_IMAGE_HEIGHT + 1) - 1 downto 0);
299: signal sValid : std_logic; -- iValid & sReady
300: signal sLbRa : unsigned(BITNESS - 1 downto 0);
301: signal sLbRb : unsigned(BITNESS - 1 downto 0);
302: signal sLbRc : unsigned(BITNESS - 1 downto 0);
303: signal sLbRd : unsigned(BITNESS - 1 downto 0);
304: signal sLbValid : std_logic;
305: signal sLbEol : std_logic;
306: signal sLbEoi : std_logic;
307:
308: -- Stage 1 combinational
309: signal sS1D1 : signed(BITNESS downto 0);
310: signal sS1D2 : signed(BITNESS downto 0);
311: signal sS1D3 : signed(BITNESS downto 0);
312: signal sS1ModeRun : std_logic;
313: -- Sticky run flag: A15_16's next-state sInRun, fed back to stage 1 so the
314: -- pixel currently in stage 1 inherits "still in run" from the prior pixel
315: -- in stage 2. Without it, A.3's gradient-based decision can break runs.
316: signal sS1InRunNext : std_logic;
317:
318: -- Stage 2 — regular
319: signal sS2Q1 : signed(3 downto 0);
320: signal sS2Q2 : signed(3 downto 0);
321: signal sS2Q3 : signed(3 downto 0);
322: signal sS2MQ1 : signed(3 downto 0);
323: signal sS2MQ2 : signed(3 downto 0);
324: signal sS2MQ3 : signed(3 downto 0);
325: signal sS2MSign : std_logic;
326: signal sS2QReg : unsigned(8 downto 0);
327:
328: -- Stage 2 — run
329: signal sRunCntReg : unsigned(RUN_CNT_WIDTH - 1 downto 0);
330: signal sS2RunCnt : unsigned(RUN_CNT_WIDTH - 1 downto 0);
331: signal sS2RunHit : std_logic;
332: signal sS2RunContinue : std_logic;
333: signal sS2RItype : std_logic;
334: signal sS2RawValid : std_logic;
335: signal sS2RawLen : unsigned(4 downto 0);
336: signal sS2RawVal : unsigned(RUN_CNT_WIDTH - 1 downto 0);
337: signal sS2RiValid : std_logic;
338: signal sS2RiIx : unsigned(BITNESS - 1 downto 0);
339: signal sS2RiRa : unsigned(BITNESS - 1 downto 0);
340: signal sS2RiRb : unsigned(BITNESS - 1 downto 0);
341: signal sS2RiRunIndex : unsigned(4 downto 0);
342: signal sS2RiErr18 : signed(BITNESS downto 0);
343:
344: -- Stage 2 — muxed
345: signal sS2Q : unsigned(8 downto 0);
346: signal sS2TokenMode : t_token_mode;
347:
348: signal sS2Px : unsigned(BITNESS - 1 downto 0);
349: signal sReg2Px : unsigned(BITNESS - 1 downto 0);
350:
351: -- context_ram packed I/O
352: signal sCtxRdData : std_logic_vector(TOTAL_WIDTH - 1 downto 0);
353: signal sCtxWrData : std_logic_vector(TOTAL_WIDTH - 1 downto 0);
354: signal sCtxWrEn : std_logic;
355:
356: -- Stage 3 context (mux between BRAM regular read and RI cluster read)
357: signal sS3Aq : unsigned(A_WIDTH - 1 downto 0);
358: signal sS3Bq : signed(B_WIDTH - 1 downto 0);
359: signal sS3Cq : signed(C_WIDTH - 1 downto 0);
360: signal sS3Nq : unsigned(N_WIDTH - 1 downto 0);
361: signal sS3Nn : unsigned(NN_WIDTH - 1 downto 0);
362:
363: -- Stage 3 — regular prediction (speculative 3-chain)
364: signal sS3Px : unsigned(BITNESS - 1 downto 0);
365: signal sS3CqBase : signed(C_WIDTH - 1 downto 0);
366: signal sS3CqP1 : signed(C_WIDTH - 1 downto 0);
367: signal sS3CqM1 : signed(C_WIDTH - 1 downto 0);
368: signal sS3PxC : unsigned(BITNESS - 1 downto 0);
369: signal sS3PxP : unsigned(BITNESS - 1 downto 0);
370: signal sS3PxM : unsigned(BITNESS - 1 downto 0);
371: signal sS3Err7C : signed(BITNESS downto 0);
372: signal sS3Err7P : signed(BITNESS downto 0);
373: signal sS3Err7M : signed(BITNESS downto 0);
374: signal sS3Err9C : signed(BITNESS downto 0);
375: signal sS3Err9P : signed(BITNESS downto 0);
376: signal sS3Err9M : signed(BITNESS downto 0);
377: signal sS3Err9Sel : signed(BITNESS downto 0);
378:
379: -- Q3==Q4 forwarding: one flag per mode. Q ranges are disjoint (regular
380: -- 0..364, RI 365,366), so a Q match + the Stage-4 mode uniquely identifies
381: -- which writeback path is live; Stage-2 mode is implied.
382: signal sFwdRegHit : std_logic;
383: signal sFwdRiHit : std_logic;
384:
385: -- Speculation control (Cq only)
386: signal sDeltaCq : signed(C_WIDTH - 1 downto 0);
387: signal sSpecUseM : std_logic;
388: signal sSpecUseP : std_logic;
389:
390: -- Stage 3 — RI path
391: signal sS3RiSign : std_logic;
392: signal sS3RiErr19 : signed(BITNESS downto 0);
393: signal sS3RiTemp : unsigned(A_WIDTH - 1 downto 0);
394:
395: -- Stage 4
396: signal sS4K : unsigned(K_WIDTH - 1 downto 0);
397: signal sS4AqSel : unsigned(A_WIDTH - 1 downto 0); -- iAq mux for shared A.10
398: signal sS4AqNew : unsigned(A_WIDTH - 1 downto 0);
399: signal sS4BqMid : signed(B_WIDTH - 1 downto 0);
400: signal sS4NqNew : unsigned(N_WIDTH - 1 downto 0);
401: signal sS4BqNew : signed(B_WIDTH - 1 downto 0);
402: signal sS4CqNew : signed(C_WIDTH - 1 downto 0);
403: signal sS4RiAqNew : unsigned(A_WIDTH - 1 downto 0);
404: signal sS4RiNqNew : unsigned(N_WIDTH - 1 downto 0);
405: signal sS4RiNnNew : unsigned(NN_WIDTH - 1 downto 0);
406: -- BRAM-side encode helpers for the N 0↔RESET trick.
407: signal sNqEncReg : unsigned(N_STORED - 1 downto 0);
408: signal sNqEncRi : unsigned(N_STORED - 1 downto 0);
409:
410: -- Stage 5
411: signal sS5MErrval : unsigned(MAPPED_ERROR_VAL_WIDTH - 1 downto 0);
412: signal sS5RiMap : std_logic;
413: signal sS5RiEmErrval : unsigned(MAPPED_ERROR_VAL_WIDTH - 1 downto 0);
414: signal sS5GolMErr : unsigned(MAPPED_ERROR_VAL_WIDTH - 1 downto 0);
415:
416: signal sS5Unary : unsigned(UNARY_WIDTH - 1 downto 0);
417: signal sS5SufLen : unsigned(SUFFIXLEN_WIDTH - 1 downto 0);
418: signal sS5SufVal : unsigned(SUFFIX_WIDTH - 1 downto 0);
419:
420: -- Stage 5 inter-stage registers: Reg5 in front of A.11_1, Reg6 after.
421: signal sReg5, sReg6 : t_pipeline_token;
422: signal sReg5V, sReg6V : std_logic;
423: signal sReg5Eoi, sReg6Eoi : std_logic;
424: signal sReg5GolMErr : unsigned(MAPPED_ERROR_VAL_WIDTH - 1 downto 0);
425: signal sReg6Unary : unsigned(UNARY_WIDTH - 1 downto 0);
426: signal sReg6SufLen : unsigned(SUFFIXLEN_WIDTH - 1 downto 0);
427: signal sReg6SufVal : unsigned(SUFFIX_WIDTH - 1 downto 0);
428:
429: -- Output
430: signal sBpRawV, sBpGolV : std_logic;
431: signal sBpWord : std_logic_vector(LIMIT - 1 downto 0);
432: signal sBpWordV : std_logic;
433: signal sBpValidLen : unsigned(log2ceil(LIMIT + 1) - 1 downto 0);
434: signal sBsWord : std_logic_vector(BYTE_STUFFER_OUT_WIDTH - 1 downto 0);
435: signal sBsWordV : std_logic;
436: signal sBsValidB : unsigned(log2ceil(BYTE_STUFFER_OUT_WIDTH / 8 + 1) - 1 downto 0);
437: signal sFramerVBytes : unsigned(log2ceil(OUT_WIDTH / 8 + 1) - 1 downto 0);
438:
439: -- Flush / framer control
440: signal sBsFlush : std_logic;
441: signal sBsAlmostFull : std_logic;
442: signal sBsFlushDone : std_logic;
443: signal sFramerEoi : std_logic;
444: signal sFirstPixel : std_logic;
445: signal sFramerStart : std_logic;
446: signal sReadyOut : std_logic;
447:
448: begin
449:
450: -------------------------------------------------------------------------------------------------------------
451: -- ASSERTIONS
452: -------------------------------------------------------------------------------------------------------------
453:
454: assert B_WIDTH >= BITNESS + 1 -- for a single sum
455: report "A12: B_WIDTH must be >= BITNESS + 1 to avoid truncation"
456: severity failure;
457:
458: assert A_WIDTH >= BITNESS + 1 -- for a single sum
459: report "A12: A_WIDTH must be >= BITNESS + 1 to avoid truncation"
460: severity failure;
461:
462: assert B_WIDTH >= N_WIDTH
463: report "A11 & A13: B_WIDTH must be >= N_WIDTH to avoid truncation"
464: severity failure;
465:
466: -------------------------------------------------------------------------------------------------------------
467: -- STALL, CLOCK-ENABLE, AND READY LOGIC
468: -------------------------------------------------------------------------------------------------------------
469: p_stall_control : process (iClk) is
470: begin
471:
472: if rising_edge(iClk) then
473: if (iRst = '1') then
474: sBsAlmostFullReg <= '0';
475: sStallDelay <= '0';
476: sStallLogic <= '0';
477: else
478: sBsAlmostFullReg <= sBsAlmostFull;
479: sStallDelay <= sStall;
480: if (sStallDelay = '1' and sStall = '1') then
481: sStallLogic <= '1';
482: else
483: sStallLogic <= '0';
484: end if;
485: end if;
486: end if;
487:
488: end process p_stall_control;
489:
490: -- Pipeline stall is sourced only from byte_stuffer's FIFO (the main design
491: -- buffer). Framer back-pressure is absorbed by the byte_stuffer FIFO via a
492: -- local ready/valid handshake (sFramerReady -> byte_stuffer.iReady).
493: sStall <= sBsAlmostFullReg;
494: -- Gating oReady on sStall alone leaves a one-cycle window where oReady='1'
495: -- but the latch is still frozen, which silently drops the pixel handshaken
496: -- in that cycle. OR-ing both keeps oReady low until acceptance is truly
497: -- re-enabled.
498: sStallUpstream <= sStall or sStallLogic;
499:
500: -- Per-stage clock-enable: update register only when not stalled AND there
501: -- is a real token to load OR a real token to retire (transition to bubble).
502: -- Once the register is sitting on a bubble with no upstream valid, CE=0
503: -- holds it frozen so its combinational fan-out stops toggling.
504:
505: sCE1 <= '1' when sStallLogic = '0' and (sReg1V = '1' or sValid = '1') else
506: '0';
507: sCE2 <= '1' when sStallLogic = '0' and (sReg2V = '1' or sReg1V = '1') else
508: '0';
509: sCE3 <= '1' when sStallLogic = '0' and (sReg3V = '1' or sReg2V = '1') else
510: '0';
511: sCE4 <= '1' when sStallLogic = '0' and (sReg4V = '1' or sReg3V = '1') else
512: '0';
513: sCE5 <= '1' when sStallLogic = '0' and (sReg5V = '1' or sReg4V = '1') else
514: '0';
515: sCE6 <= '1' when sStallLogic = '0' and (sReg6V = '1' or sReg5V = '1') else
516: '0';
517:
518: sReadyOut <= not iRst and not sStallUpstream; -- Stalls upstream
519: oReady <= sReadyOut;
520:
521: -- Input-port AXI4-Stream slave contract (iValid/iPixel/oReady).
522: -- psl default clock is rising_edge(iClk);
523: -- psl assert always (iRst = '1' -> oReady = '0') report "openjls_top: reset must hold oReady low";
524: -- psl assert always ((iRst = '0' and sStallLogic = '1') -> oReady = '0') report "openjls_top: oReady must stay low while the input latch is frozen (no dropped beat)";
525: -- psl assert always ((iRst = '0' and iValid = '1' and oReady = '1') -> next (sValid = '1')) report "openjls_top: an accepted pixel (iValid and oReady) must be committed next cycle";
526:
527: -------------------------------------------------------------------------------------------------------------
528: -- Input Stage — Input register
529: -------------------------------------------------------------------------------------------------------------
530: p_input_reg : process (iClk) is
531:
532: variable vImageWidthUnsi : unsigned (iImageWidth'range);
533: variable vImageHeightUnsi : unsigned (iImageHeight'range);
534:
535: begin
536:
537: if rising_edge(iClk) then
538: if (iRst = '1') then
539: sValid <= '0';
540: sPixel <= (others => '0');
541:
542: vImageWidthUnsi := unsigned(iImageWidth);
543: vImageHeightUnsi := unsigned(iImageHeight);
544:
545: -- Image resolution set to max value if invalid input
546: -- if the user wants MAX_IMAGE_WIDTH/HEIGHT he can leave the inputs unwired (set to 0)
547: if (vImageWidthUnsi < CO_MIN_IMAGE_WIDTH) then
548: assert false
549: report "iImageWidth smaller than the minimum allowed: " & integer'image(CO_MIN_IMAGE_WIDTH) & ", using max value instead: " & integer'image(MAX_IMAGE_WIDTH)
550: severity warning;
551:
552: sImageWidth <= to_unsigned(MAX_IMAGE_WIDTH, sImageWidth'length);
553: elsif (vImageWidthUnsi > MAX_IMAGE_WIDTH) then
554: assert false
555: report "iImageWidth larger than the maximum allowed: " & integer'image(MAX_IMAGE_WIDTH) & ", using max value instead: " & integer'image(MAX_IMAGE_WIDTH)
556: severity warning;
557:
558: sImageWidth <= to_unsigned(MAX_IMAGE_WIDTH, sImageWidth'length);
559: else
560: sImageWidth <= resize(vImageWidthUnsi, sImageWidth'length);
561: end if;
562:
563: if (vImageHeightUnsi < CO_MIN_IMAGE_HEIGHT) then
564: assert false
565: report "iImageHeight smaller than the minimum allowed: " & integer'image(CO_MIN_IMAGE_HEIGHT) & ", using max value instead: " & integer'image(MAX_IMAGE_HEIGHT)
566: severity warning;
567:
568: sImageHeight <= to_unsigned(MAX_IMAGE_HEIGHT, sImageHeight'length);
569: elsif (vImageHeightUnsi > MAX_IMAGE_HEIGHT) then
570: assert false
571: report "iImageHeight larger than the maximum allowed: " & integer'image(MAX_IMAGE_HEIGHT) & ", using max value instead: " & integer'image(MAX_IMAGE_HEIGHT)
572: severity warning;
573:
574: sImageHeight <= to_unsigned(MAX_IMAGE_HEIGHT, sImageHeight'length);
575: else
576: sImageHeight <= resize(vImageHeightUnsi, sImageHeight'length);
577: end if;
578: else
579: if (iValid = '1' and sReadyOut = '1' and sStallLogic = '0') then -- handshake
580: sPixel <= unsigned(iPixel);
581: sValid <= '1';
582: else
583: sPixel <= (others => '0');
584: sValid <= '0';
585: end if;
586: end if;
587: end if;
588:
589: end process p_input_reg;
590:
591: -------------------------------------------------------------------------------------------------------------
592: -- Stage 1 — Line buffer + A.1 gradients + A.3 mode selection
593: -------------------------------------------------------------------------------------------------------------
594: u_line_buffer : entity work.line_buffer(behavioral)
595: generic map (
596: MAX_IMAGE_WIDTH => MAX_IMAGE_WIDTH,
597: MAX_IMAGE_HEIGHT => MAX_IMAGE_HEIGHT,
598: BITNESS => BITNESS
599: )
600: port map (
601: iClk => iClk,
602: iRst => iRst,
603: iImageWidth => sImageWidth,
604: iImageHeight => sImageHeight,
605: iValid => sValid,
606: iPixel => sPixel,
607: oA => sLbRa,
608: oB => sLbRb,
609: oC => sLbRc,
610: oD => sLbRd,
611: oValid => sLbValid,
612: oEol => sLbEol,
613: oEoi => sLbEoi
614: );
615:
616: u_a1 : entity work.a1_gradient_comp(behavioral)
617: generic map (
618: BITNESS => BITNESS
619: )
620: port map (
621: iA => sLbRa,
622: iB => sLbRb,
623: iC => sLbRc,
624: iD => sLbRd,
625: oD1 => sS1D1,
626: oD2 => sS1D2,
627: oD3 => sS1D3
628: );
629:
630: u_a3 : entity work.a3_mode_selection(behavioral)
631: generic map (
632: BITNESS => BITNESS
633: )
634: port map (
635: iD1 => sS1D1,
636: iD2 => sS1D2,
637: iD3 => sS1D3,
638: oModeRun => sS1ModeRun
639: );
640:
641: -------------------------------------------------------------------------------------------------------------
642: -- Register 1 (Stage 1 → Stage 2)
643: -------------------------------------------------------------------------------------------------------------
644: p_reg1 : process (iClk) is
645:
646: variable v : t_pipeline_token;
647:
648: begin
649:
650: if rising_edge(iClk) then
651: if (iRst = '1') then
652: sReg1 <= CO_TOKEN_NONE;
653: sReg1V <= '0';
654: sReg1Eol <= '0';
655: sReg1Eoi <= '0';
656: sReg1D1 <= (others => '0');
657: sReg1D2 <= (others => '0');
658: sReg1D3 <= (others => '0');
659: sGenPar <= '0';
660: sReg1Par <= '0';
661: elsif (sCE1 = '1') then
662: if (sLbValid = '1' and (sS1ModeRun = '1' or sS1InRunNext = '1')) then
663: v.mode := token_run;
664: elsif (sLbValid = '1') then
665: v.mode := token_regular;
666: else
667: v := CO_TOKEN_NONE;
668: end if;
669:
670: if (sLbValid = '1') then
671: v.Ix := sPixel;
672: v.Ra := sLbRa;
673: v.Rb := sLbRb;
674: v.Rc := sLbRc;
675: end if;
676:
677: sReg1 <= v;
678: sReg1V <= sValid;
679: sReg1Eol <= sLbValid and sLbEol;
680: sReg1Eoi <= sLbValid and sLbEoi;
681: -- Tag this token with the current parity; flip after an EOI so the next
682: -- image's first token (and onward) carries the opposite parity.
683: sReg1Par <= sGenPar;
684: if (sLbValid = '1' and sLbEoi = '1') then
685: sGenPar <= not sGenPar;
686: end if;
687: sReg1D1 <= sS1D1;
688: sReg1D2 <= sS1D2;
689: sReg1D3 <= sS1D3;
690: end if;
691: end if;
692:
693: end process p_reg1;
694:
695: -------------------------------------------------------------------------------------------------------------
696: -- Stage 2 — Regular: A.4 → A.4.1 → A.4.2
697: -------------------------------------------------------------------------------------------------------------
698: u_a4 : entity work.a4_quantization_gradients(behavioral)
699: generic map (
700: BITNESS => BITNESS,
701: MAX_VAL => MAX_VAL
702: )
703: port map (
704: iD1 => sReg1D1,
705: iD2 => sReg1D2,
706: iD3 => sReg1D3,
707: oQ1 => sS2Q1,
708: oQ2 => sS2Q2,
709: oQ3 => sS2Q3
710: );
711:
712: u_a4_1 : entity work.a4_1_quant_gradient_merging(behavioral)
713: port map (
714: iQ1 => sS2Q1,
715: iQ2 => sS2Q2,
716: iQ3 => sS2Q3,
717: oQ1 => sS2MQ1,
718: oQ2 => sS2MQ2,
719: oQ3 => sS2MQ3,
720: oSign => sS2MSign
721: );
722:
723: u_a4_2 : entity work.a4_2_q_mapping(behavioral)
724: port map (
725: iQ1 => sS2MQ1,
726: iQ2 => sS2MQ2,
727: iQ3 => sS2MQ3,
728: oQ => sS2QReg
729: );
730:
731: -------------------------------------------------------------------------------------------------------------
732: -- Stage 2 — Run: A.14, A.15/A.16 (FSM), A.17
733: -------------------------------------------------------------------------------------------------------------
734: u_a14 : entity work.a14_run_length_determination(behavioral)
735: generic map (
736: BITNESS => BITNESS,
737: RUN_CNT_WIDTH => RUN_CNT_WIDTH
738: )
739: port map (
740: iRa => sReg1.Ra(BITNESS - 1 downto 0),
741: iIx => sReg1.Ix(BITNESS - 1 downto 0),
742: iRunCnt => sRunCntReg,
743: iEol => sReg1Eol,
744: oRunCnt => sS2RunCnt,
745: oRunHit => sS2RunHit,
746: oRunContinue => sS2RunContinue
747: );
748:
749: sReg1ModeRun <= '1' when sReg1.mode = token_run else
750: '0';
751:
752: u_a15_16 : entity work.a15_a16_encode_run(behavioral)
753: generic map (
754: BITNESS => BITNESS,
755: RUN_CNT_WIDTH => RUN_CNT_WIDTH
756: )
757: port map (
758: iClk => iClk,
759: iRst => iRst,
760: iCE => not sStallLogic,
761: iEoi => sReg1Eoi,
762: iRunCnt => sS2RunCnt,
763: iRunHit => sS2RunHit,
764: iRunContinue => sS2RunContinue,
765: iModeIsRun => sReg1ModeRun,
766: iIx => sReg1.Ix(BITNESS - 1 downto 0),
767: iRa => sReg1.Ra(BITNESS - 1 downto 0),
768: iRb => sReg1.Rb(BITNESS - 1 downto 0),
769: oRawValid => sS2RawValid,
770: oRawSuffixLen => sS2RawLen,
771: oRawSuffixVal => sS2RawVal,
772: oRiValid => sS2RiValid,
773: oRiIx => sS2RiIx,
774: oRiRa => sS2RiRa,
775: oRiRb => sS2RiRb,
776: oRiRunIndex => sS2RiRunIndex,
777: oInRunNext => sS1InRunNext
778: );
779:
780: u_a17 : entity work.a17_run_interruption_index(behavioral)
781: generic map (
782: BITNESS => BITNESS
783: )
784: port map (
785: iRa => sReg1.Ra(BITNESS - 1 downto 0),
786: iRb => sReg1.Rb(BITNESS - 1 downto 0),
787: oRItype => sS2RItype
788: );
789:
790: u_a18 : entity work.a18_run_interruption_prediction_error(behavioral)
791: generic map (
792: BITNESS => BITNESS
793: )
794: port map (
795: iRItype => sS2RItype,
796: iRa => sS2RiRa,
797: iRb => sS2RiRb,
798: iIx => sS2RiIx,
799: oErrval => sS2RiErr18
800: );
801:
802: p_run_cnt : process (iClk) is
803: begin
804:
805: if rising_edge(iClk) then
806: if (iRst = '1') then
807: sRunCntReg <= (others => '0');
808: elsif (sStallLogic = '0' and sReg1.mode = token_run) then
809: if (sS2RunContinue = '1') then
810: sRunCntReg <= sS2RunCnt;
811: else
812: sRunCntReg <= (others => '0');
813: end if;
814: end if;
815: end if;
816:
817: end process p_run_cnt;
818:
819: -- Stage 2 mode selection. Precedence: RI break (Golomb+raw) > raw-only.
820: sS2TokenMode <= token_regular when sReg1.mode = token_regular else
821: token_run_interruption when sS2RiValid = '1' else
822: token_raw when sS2RawValid = '1' else
823: token_none;
824:
825: -- A.20.1 inline: regular Q from A.4.2; run Q = 366 if RItype else 365
826: sS2Q <= sS2QReg when sReg1.mode = token_regular else
827: to_unsigned(366, 9) when sS2RItype = '1' else
828: to_unsigned(365, 9);
829:
830: -- Sticky context-RAM owner: parity of the last valid token that issued a read,
831: -- held across read bubbles. Effective owner = live Reg1 parity, else held.
832: p_ctx_owner : process (iClk) is
833: begin
834:
835: if rising_edge(iClk) then
836: if (iRst = '1') then
837: sCtxOwnerPar <= '0';
838: elsif (sReg1V = '1') then
839: sCtxOwnerPar <= sReg1Par;
840: end if;
841: end if;
842:
843: end process p_ctx_owner;
844:
845: sCtxRdPar <= sReg1Par when sReg1V = '1' else
846: sCtxOwnerPar;
847:
848: -- Refuse a writeback whose parity no longer owns the context RAM: it is a
849: -- straggler from a finished image and would corrupt the next image's contexts.
850: sCtxWrEn <= sReg3V and
851: bool2bit(sReg3Par = sCtxRdPar) and
852: (bool2bit(sReg3.mode = token_regular) or
853: bool2bit(sReg3.mode = token_run_interruption));
854:
855: -- Pack writeback word by mode (Murat BRAM encoding):
856: -- A : A_WIDTH → A_STORED (A.12 output fits; the iNq=RESET-1→RESET halving caps it).
857: -- B : magnitude only (Bq ≤ 0 after A.13 clamp). N : 0 ⇔ RESET.
858: sCtxWrData <= std_logic_vector(resize(sS4AqNew, A_STORED)) &
859: std_logic_vector(resize(unsigned(-sS4BqNew), B_STORED)) &
860: std_logic_vector(sS4CqNew) &
861: std_logic_vector(sNqEncReg)
862: when sReg3.mode = token_regular else
863: std_logic_vector(resize(sS4RiAqNew, A_STORED)) &
864: std_logic_vector(sS4RiNnNew) &
865: std_logic_vector(to_signed(0, C_STORED)) &
866: std_logic_vector(sNqEncRi);
867:
868: sNqEncReg <= (others => '0') when sS4NqNew = to_unsigned(RESET, N_WIDTH) else
869: resize(sS4NqNew, N_STORED);
870:
871: sNqEncRi <= (others => '0') when sS4RiNqNew = to_unsigned(RESET, N_WIDTH) else
872: resize(sS4RiNqNew, N_STORED);
873:
874: u_ctx_ram : entity work.context_ram(behavioral)
875: generic map (
876: RANGE_P => RANGE_P,
877: RAM_DEPTH => RAM_DEPTH,
878: A_WIDTH => A_STORED,
879: B_WIDTH => B_STORED,
880: C_WIDTH => C_STORED,
881: N_WIDTH => N_STORED,
882: TOTAL_WIDTH => TOTAL_WIDTH
883: )
884: port map (
885: iClk => iClk,
886: iRst => iRst,
887: iWrAddr => std_logic_vector(sReg3.Q),
888: iWrEn => sCtxWrEn and sCE3,
889: iWrData => sCtxWrData,
890: iRdAddr => std_logic_vector(sS2Q),
891: iRdEn => sReg1V and sCE1 and (bool2bit(sS2TokenMode = TOKEN_REGULAR) or
892: bool2bit(sS2TokenMode = TOKEN_RUN_INTERRUPTION)),
893: iEndOfImage => sReg1Eoi,
894: oRdData => sCtxRdData
895: );
896:
897: -- Unpack read port (RdLatency=1 → valid at Stage 3). Q3==Q4 forwarding: when
898: -- Stage 4 writes back the Q Stage 3 is reading, use the live update outputs
899: -- (BRAM read is stale). Decode mirrors encode: A zero-extend, B = -stored, N 0 ⇒ RESET.
900: sS3Aq <= sS4AqNew when sFwdRegHit = '1' else
901: sS4RiAqNew when sFwdRiHit = '1' else
902: resize(unsigned(sCtxRdData(CTX_A_HI downto CTX_A_LO)), A_WIDTH);
903:
904: -- Bq is regular-only (the B slot carries Nn for RI, handled below).
905: sS3Bq <= sS4BqNew when sFwdRegHit = '1' else
906: - signed(resize(unsigned(sCtxRdData(CTX_B_HI downto CTX_B_LO)), B_WIDTH));
907:
908: -- Cq forwarding is handled by the speculative 3-chain via sS3CqBase.
909: sS3Cq <= sS4CqNew when sFwdRegHit = '1' else
910: signed(sCtxRdData(CTX_C_HI downto CTX_C_LO));
911:
912: sS3Nq <= sS4NqNew when sFwdRegHit = '1' else
913: sS4RiNqNew when sFwdRiHit = '1' else
914: to_unsigned(RESET, N_WIDTH) when unsigned(sCtxRdData(CTX_N_HI downto CTX_N_LO)) = 0 else
915: resize(unsigned(sCtxRdData(CTX_N_HI downto CTX_N_LO)), N_WIDTH);
916:
917: -- Nn is only meaningful for RI; mask to zero for regular so downstream
918: -- doesn't see Bq LSBs misinterpreted as Nn.
919: sS3Nn <= sS4RiNnNew when sFwdRiHit = '1' else
920: (others => '0') when sReg2.mode = token_regular else
921: unsigned(sCtxRdData(CTX_NN_HI downto CTX_NN_LO));
922:
923: u_a5 : entity work.a5_edge_detecting_predictor(behavioral)
924: generic map (
925: BITNESS => BITNESS
926: )
927: port map (
928: iA => sReg1.Ra(BITNESS - 1 downto 0),
929: iB => sReg1.Rb(BITNESS - 1 downto 0),
930: iC => sReg1.Rc(BITNESS - 1 downto 0),
931: oPx => sS2Px
932: );
933:
934: -------------------------------------------------------------------------------------------------------------
935: -- Register 2 (Stage 2 → Stage 3)
936: -------------------------------------------------------------------------------------------------------------
937: p_reg2 : process (iClk) is
938:
939: variable v : t_pipeline_token;
940:
941: begin
942:
943: if rising_edge(iClk) then
944: if (iRst = '1') then
945: sReg2 <= CO_TOKEN_NONE;
946: sReg2V <= '0';
947: sReg2Eoi <= '0';
948: sReg2Px <= (others => '0');
949: sReg2Par <= '0';
950: elsif (sCE2 = '1') then
951: -- Build Reg2 per mode; unused fields stay at CO_TOKEN_NONE defaults so
952: -- downstream never sees stale values.
953: v := CO_TOKEN_NONE;
954: v.mode := sS2TokenMode;
955: v.Q := sS2Q;
956:
957: case sS2TokenMode is
958:
959: when token_regular =>
960:
961: v.Ix := sReg1.Ix;
962: v.Ra := sReg1.Ra;
963: v.Rb := sReg1.Rb;
964: v.Rc := sReg1.Rc;
965: v.Sign := sS2MSign;
966:
967: when token_run_interruption =>
968:
969: v.Ix := sS2RiIx;
970: v.Ra := sS2RiRa;
971: v.Rb := sS2RiRb;
972: v.RiType := sS2RItype;
973: v.Errval := resize(sS2RiErr18, v.Errval'length);
974: v.RawLen := resize(sS2RawLen, v.RawLen'length);
975: v.RawVal := resize(sS2RawVal, v.RawVal'length);
976: v.RiRunIndex := sS2RiRunIndex;
977:
978: when token_raw =>
979:
980: v.RawLen := resize(sS2RawLen, v.RawLen'length);
981: v.RawVal := resize(sS2RawVal, v.RawVal'length);
982:
983: when others =>
984:
985: v := CO_TOKEN_NONE;
986:
987: end case;
988:
989: if (sReg1V = '0' or sS2TokenMode = token_none) then
990: v := CO_TOKEN_NONE;
991: end if;
992:
993: sReg2 <= v;
994: sReg2V <= sReg1V and bool2bit(sS2TokenMode /= token_none);
995: sReg2Eoi <= sReg1Eoi;
996: sReg2Px <= sS2Px;
997: sReg2Par <= sReg1Par;
998: end if;
999: end if;
1000:
1001: end process p_reg2;
1002:
1003: -------------------------------------------------------------------------------------------------------------
1004: -- Stage 3 — Regular: A.5 + speculative 3-chain A.6..A.9
1005: -------------------------------------------------------------------------------------------------------------
1006:
1007: sS3Px <= sReg2Px;
1008:
1009: -- Forwarding hits: Stage 2 read Q matches Stage 4 writeback Q.
1010: -- Stage-4 mode selects which update output to forward; Stage-2 mode is
1011: -- implied by the Q match (regular Q < 365, RI Q ∈ {365,366}).
1012: -- Same-parity guard: never forward an update across an image boundary (the
1013: -- two tokens can alias on the same Q — e.g. the run contexts — when one is a
1014: -- straggler from the previous image).
1015: sFwdRegHit <= '1' when sReg2V = '1' and sReg3V = '1'
1016: and sReg2Par = sReg3Par
1017: and sReg2.Q = sReg3.Q
1018: and sReg3.mode = token_regular else
1019: '0';
1020:
1021: sFwdRiHit <= '1' when sReg2V = '1' and sReg3V = '1'
1022: and sReg2Par = sReg3Par
1023: and sReg2.Q = sReg3.Q
1024: and sReg3.mode = token_run_interruption else
1025: '0';
1026:
1027: -- Speculative-chain Cq base: on a hit use the pre-update sReg3.Cq (DeltaCq picks
1028: -- the ±1/0 candidate matching sS4CqNew); on a miss the BRAM read is already correct.
1029: sS3CqBase <= sReg3.Cq when sFwdRegHit = '1' else
1030: sS3Cq;
1031:
1032: -- Clamped ±1 variants
1033: sS3CqP1 <= to_signed(MAX_C, C_WIDTH) when sS3CqBase = to_signed(MAX_C, C_WIDTH) else
1034: sS3CqBase + 1;
1035: sS3CqM1 <= to_signed(MIN_C, C_WIDTH) when sS3CqBase = to_signed(MIN_C, C_WIDTH) else
1036: sS3CqBase - 1;
1037:
1038: -- Central chain (DeltaCq = 0)
1039: u_a6_c : entity work.a6_prediction_correction(behavioral)
1040: generic map (
1041: BITNESS => BITNESS, MAX_VAL => MAX_VAL
1042: )
1043: port map (
1044: iPx => sS3Px,
1045: iSign => sReg2.Sign,
1046: iCq => sS3CqBase,
1047: oPx => sS3PxC
1048: );
1049:
1050: u_a7_c : entity work.a7_prediction_error(behavioral)
1051: generic map (
1052: BITNESS => BITNESS
1053: )
1054: port map (
1055: iIx => sReg2.Ix(BITNESS - 1 downto 0),
1056: iPx => sS3PxC,
1057: iSign => sReg2.Sign,
1058: oErrorVal => sS3Err7C
1059: );
1060:
1061: u_a9_c : entity work.a9_modulo_reduction(behavioral)
1062: generic map (
1063: BITNESS => BITNESS, RANGE_P => RANGE_P
1064: )
1065: port map (
1066: iErrorVal => sS3Err7C,
1067: oErrorVal => sS3Err9C
1068: );
1069:
1070: -- +1 chain (DeltaCq = +1)
1071: u_a6_p : entity work.a6_prediction_correction(behavioral)
1072: generic map (
1073: BITNESS => BITNESS, MAX_VAL => MAX_VAL
1074: )
1075: port map (
1076: iPx => sS3Px,
1077: iSign => sReg2.Sign,
1078: iCq => sS3CqP1,
1079: oPx => sS3PxP
1080: );
1081:
1082: u_a7_p : entity work.a7_prediction_error(behavioral)
1083: generic map (
1084: BITNESS => BITNESS
1085: )
1086: port map (
1087: iIx => sReg2.Ix(BITNESS - 1 downto 0),
1088: iPx => sS3PxP,
1089: iSign => sReg2.Sign,
1090: oErrorVal => sS3Err7P
1091: );
1092:
1093: u_a9_p : entity work.a9_modulo_reduction(behavioral)
1094: generic map (
1095: BITNESS => BITNESS, RANGE_P => RANGE_P
1096: )
1097: port map (
1098: iErrorVal => sS3Err7P,
1099: oErrorVal => sS3Err9P
1100: );
1101:
1102: -- −1 chain (DeltaCq = −1)
1103: u_a6_m : entity work.a6_prediction_correction(behavioral)
1104: generic map (
1105: BITNESS => BITNESS, MAX_VAL => MAX_VAL
1106: )
1107: port map (
1108: iPx => sS3Px,
1109: iSign => sReg2.Sign,
1110: iCq => sS3CqM1,
1111: oPx => sS3PxM
1112: );
1113:
1114: u_a7_m : entity work.a7_prediction_error(behavioral)
1115: generic map (
1116: BITNESS => BITNESS
1117: )
1118: port map (
1119: iIx => sReg2.Ix(BITNESS - 1 downto 0),
1120: iPx => sS3PxM,
1121: iSign => sReg2.Sign,
1122: oErrorVal => sS3Err7M
1123: );
1124:
1125: u_a9_m : entity work.a9_modulo_reduction(behavioral)
1126: generic map (
1127: BITNESS => BITNESS, RANGE_P => RANGE_P
1128: )
1129: port map (
1130: iErrorVal => sS3Err7M,
1131: oErrorVal => sS3Err9M
1132: );
1133:
1134: -- DeltaCq from live Stage-4 A.13. On miss, sDeltaCq is irrelevant (sFwdRegHit=0).
1135: sDeltaCq <= sS4CqNew - sReg3.Cq;
1136:
1137: sSpecUseM <= '1' when sFwdRegHit = '1' and sDeltaCq < 0 else
1138: '0';
1139: sSpecUseP <= '1' when sFwdRegHit = '1' and sDeltaCq > 0 else
1140: '0';
1141:
1142: sS3Err9Sel <= sS3Err9M when sSpecUseM = '1' else
1143: sS3Err9P when sSpecUseP = '1' else
1144: sS3Err9C;
1145:
1146: -------------------------------------------------------------------------------------------------------------
1147: -- Stage 3 — RI: A.19, A.20
1148: -------------------------------------------------------------------------------------------------------------
1149: u_a19 : entity work.a19_run_interruption_error(behavioral)
1150: generic map (
1151: BITNESS => BITNESS,
1152: RANGE_P => RANGE_P
1153: )
1154: port map (
1155: iErrval => sReg2.Errval(BITNESS downto 0),
1156: iRItype => sReg2.RiType,
1157: iRa => sReg2.Ra(BITNESS - 1 downto 0),
1158: iRb => sReg2.Rb(BITNESS - 1 downto 0),
1159: oErrval => sS3RiErr19,
1160: oSign => sS3RiSign
1161: );
1162:
1163: -- A.20: single context read returns (Aq, Nq) for Q ∈ {365, 366}.
1164: u_a20 : entity work.a20_compute_temp(behavioral)
1165: generic map (
1166: A_WIDTH => A_WIDTH,
1167: N_WIDTH => N_WIDTH
1168: )
1169: port map (
1170: iRItype => sReg2.RiType,
1171: iAq => sS3Aq,
1172: iNq => sS3Nq,
1173: oTemp => sS3RiTemp
1174: );
1175:
1176: -------------------------------------------------------------------------------------------------------------
1177: -- Register 3 (Stage 3 → Stage 4) — carry per-mode Errval / Temp / Sign
1178: -------------------------------------------------------------------------------------------------------------
1179: p_reg3 : process (iClk) is
1180:
1181: variable v : t_pipeline_token;
1182:
1183: begin
1184:
1185: if rising_edge(iClk) then
1186: if (iRst = '1') then
1187: sReg3 <= CO_TOKEN_NONE;
1188: sReg3V <= '0';
1189: sReg3Eoi <= '0';
1190: sReg3Par <= '0';
1191: elsif (sCE3 = '1') then
1192: v := sReg2;
1193: v.Aq := sS3Aq;
1194: v.Bq := sS3Bq;
1195: v.Cq := sS3Cq;
1196: v.Nq := sS3Nq;
1197: v.Nn := sS3Nn;
1198: v.Temp := (others => '0');
1199:
1200: case sReg2.mode is
1201:
1202: when token_regular =>
1203:
1204: v.Errval := resize(sS3Err9Sel, v.Errval'length);
1205:
1206: when token_run_interruption =>
1207:
1208: v.Errval := resize(sS3RiErr19, v.Errval'length);
1209: v.Sign := sS3RiSign;
1210: v.Temp := sS3RiTemp;
1211:
1212: when others =>
1213:
1214: null;
1215:
1216: end case;
1217:
1218: if (sReg2V = '0') then
1219: v := CO_TOKEN_NONE;
1220: end if;
1221: sReg3 <= v;
1222: sReg3V <= sReg2V;
1223: sReg3Eoi <= sReg2Eoi;
1224: sReg3Par <= sReg2Par;
1225: end if;
1226: end if;
1227:
1228: end process p_reg3;
1229:
1230: -------------------------------------------------------------------------------------------------------------
1231: -- Stage 4 — Shared A.10; regular A.12 + A.13; RI A.23
1232: -- A.10's iAq is muxed: regular → Aq, RI → Temp.
1233: -------------------------------------------------------------------------------------------------------------
1234: sS4AqSel <= sReg3.Temp when sReg3.mode = token_run_interruption else
1235: sReg3.Aq;
1236:
1237: u_a10 : entity work.a10_compute_k(behavioral)
1238: generic map (
1239: A_WIDTH => A_WIDTH,
1240: K_WIDTH => K_WIDTH,
1241: N_WIDTH => N_WIDTH
1242: )
1243: port map (
1244: iNq => sReg3.Nq,
1245: iAq => sS4AqSel,
1246: oK => sS4K
1247: );
1248:
1249: u_a12 : entity work.a12_variables_update(rtl)
1250: generic map (
1251: ERROR_WIDTH => ERROR_WIDTH,
1252: A_WIDTH => A_WIDTH,
1253: B_WIDTH => B_WIDTH,
1254: N_WIDTH => N_WIDTH,
1255: RESET => RESET
1256: )
1257: port map (
1258: iErrorVal => sReg3.Errval(BITNESS downto 0),
1259: iAq => sReg3.Aq,
1260: iBq => sReg3.Bq,
1261: iNq => sReg3.Nq,
1262: oAq => sS4AqNew,
1263: oBq => sS4BqMid,
1264: oNq => sS4NqNew
1265: );
1266:
1267: u_a13 : entity work.a13_update_bias(rtl)
1268: generic map (
1269: B_WIDTH => B_WIDTH,
1270: N_WIDTH => N_WIDTH,
1271: C_WIDTH => C_WIDTH,
1272: MIN_C => MIN_C,
1273: MAX_C => MAX_C
1274: )
1275: port map (
1276: iBq => sS4BqMid,
1277: iNq => sS4NqNew,
1278: iCq => sReg3.Cq,
1279: oBq => sS4BqNew,
1280: oCq => sS4CqNew
1281: );
1282:
1283: u_a23 : entity work.a23_run_interruption_update(behavioral)
1284: generic map (
1285: A_WIDTH => A_WIDTH,
1286: N_WIDTH => N_WIDTH,
1287: NN_WIDTH => NN_WIDTH,
1288: ERROR_WIDTH => ERROR_WIDTH,
1289: RESET => RESET
1290: )
1291: port map (
1292: iErrVal => sReg3.Errval(BITNESS downto 0),
1293: iRItype => sReg3.RiType,
1294: iAq => sReg3.Aq,
1295: iNq => sReg3.Nq,
1296: iNn => sReg3.Nn,
1297: oAq => sS4RiAqNew,
1298: oNq => sS4RiNqNew,
1299: oNn => sS4RiNnNew
1300: );
1301:
1302: -------------------------------------------------------------------------------------------------------------
1303: -- Register 4 (Stage 4 → Stage 5)
1304: -------------------------------------------------------------------------------------------------------------
1305: p_reg4 : process (iClk) is
1306:
1307: variable v : t_pipeline_token;
1308:
1309: begin
1310:
1311: if rising_edge(iClk) then
1312: if (iRst = '1') then
1313: sReg4 <= CO_TOKEN_NONE;
1314: sReg4V <= '0';
1315: sReg4Eoi <= '0';
1316: elsif (sCE4 = '1') then
1317: v := sReg3;
1318: v.k := resize(sS4K, K_WIDTH);
1319: if (sReg3V = '0') then
1320: v := CO_TOKEN_NONE;
1321: end if;
1322: sReg4 <= v;
1323: sReg4V <= sReg3V;
1324: sReg4Eoi <= sReg3Eoi;
1325: end if;
1326: end if;
1327:
1328: end process p_reg4;
1329:
1330: -------------------------------------------------------------------------------------------------------------
1331: -- Stage 5 — Regular: A.11; RI: A.21 + A.22;
1332: -------------------------------------------------------------------------------------------------------------
1333: u_a11 : entity work.a11_error_mapping(behavioral)
1334: generic map (
1335: N_WIDTH => N_WIDTH,
1336: B_WIDTH => B_WIDTH,
1337: K_WIDTH => K_WIDTH,
1338: ERROR_WIDTH => ERROR_WIDTH,
1339: MAPPED_ERROR_VAL_WIDTH => MAPPED_ERROR_VAL_WIDTH
1340: )
1341: port map (
1342: iK => sReg4.k,
1343: iBq => sReg4.Bq,
1344: iNq => sReg4.Nq,
1345: iErrorVal => sReg4.Errval(BITNESS downto 0),
1346: oMappedErrorVal => sS5MErrval
1347: );
1348:
1349: u_a21 : entity work.a21_compute_map(behavioral)
1350: generic map (
1351: K_WIDTH => K_WIDTH,
1352: N_WIDTH => N_WIDTH,
1353: ERROR_WIDTH => ERROR_WIDTH
1354: )
1355: port map (
1356: iK => sReg4.k,
1357: iErrval => sReg4.Errval(BITNESS downto 0),
1358: iNn => resize(sReg4.Nn, N_WIDTH),
1359: iNq => sReg4.Nq,
1360: oMap => sS5RiMap
1361: );
1362:
1363: u_a22 : entity work.a22_errval_mapping(behavioral)
1364: generic map (
1365: ERROR_WIDTH => ERROR_WIDTH,
1366: MAPPED_ERRVAL_WIDTH => MAPPED_ERROR_VAL_WIDTH
1367: )
1368: port map (
1369: iErrval => sReg4.Errval(BITNESS downto 0),
1370: iRItype => sReg4.RiType,
1371: iMap => sS5RiMap,
1372: oEmErrVal => sS5RiEmErrval
1373: );
1374:
1375: sS5GolMErr <= sS5MErrval when sReg4.mode = token_regular else
1376: sS5RiEmErrval;
1377:
1378: -------------------------------------------------------------------------------------------------------------
1379: -- Register 5 (Stage 5 mapping → A.11_1 golomb encoder)
1380: -------------------------------------------------------------------------------------------------------------
1381: p_reg5 : process (iClk) is
1382:
1383: variable v : t_pipeline_token;
1384:
1385: begin
1386:
1387: if rising_edge(iClk) then
1388: if (iRst = '1') then
1389: sReg5 <= CO_TOKEN_NONE;
1390: sReg5V <= '0';
1391: sReg5Eoi <= '0';
1392: sReg5GolMErr <= (others => '0');
1393: elsif (sCE5 = '1') then
1394: v := sReg4;
1395: if (sReg4V = '0') then
1396: v := CO_TOKEN_NONE;
1397: end if;
1398: sReg5 <= v;
1399: sReg5V <= sReg4V;
1400: sReg5Eoi <= sReg4Eoi;
1401: sReg5GolMErr <= sS5GolMErr;
1402: end if;
1403: end if;
1404:
1405: end process p_reg5;
1406:
1407: u_a11_1 : entity work.a11_1_golomb_encoder(behavioral)
1408: generic map (
1409: K_WIDTH => K_WIDTH,
1410: QBPP => QBPP,
1411: LIMIT => LIMIT,
1412: UNARY_WIDTH => UNARY_WIDTH,
1413: SUFFIX_WIDTH => SUFFIX_WIDTH,
1414: SUFFIXLEN_WIDTH => SUFFIXLEN_WIDTH,
1415: MAPPED_ERROR_VAL_WIDTH => MAPPED_ERROR_VAL_WIDTH
1416: )
1417: port map (
1418: iK => sReg5.k,
1419: iMappedErrorVal => sReg5GolMErr,
1420: iRiMode => bool2bit(sReg5.mode = TOKEN_RUN_INTERRUPTION),
1421: iRunIndex => sReg5.RiRunIndex,
1422: oUnaryZeros => sS5Unary,
1423: oSuffixLen => sS5SufLen,
1424: oSuffixVal => sS5SufVal
1425: );
1426:
1427: -------------------------------------------------------------------------------------------------------------
1428: -- Register 6 (golomb encoder → bit packer)
1429: -------------------------------------------------------------------------------------------------------------
1430: p_reg6 : process (iClk) is
1431:
1432: variable v : t_pipeline_token;
1433:
1434: begin
1435:
1436: if rising_edge(iClk) then
1437: if (iRst = '1') then
1438: sReg6 <= CO_TOKEN_NONE;
1439: sReg6V <= '0';
1440: sReg6Eoi <= '0';
1441: sReg6Unary <= (others => '0');
1442: sReg6SufLen <= (others => '0');
1443: sReg6SufVal <= (others => '0');
1444: elsif (sCE6 = '1') then
1445: v := sReg5;
1446: if (sReg5V = '0') then
1447: v := CO_TOKEN_NONE;
1448: end if;
1449: sReg6 <= v;
1450: sReg6V <= sReg5V;
1451: sReg6Eoi <= sReg5Eoi;
1452: sReg6Unary <= sS5Unary;
1453: sReg6SufLen <= sS5SufLen;
1454: sReg6SufVal <= sS5SufVal;
1455: end if;
1456: end if;
1457:
1458: end process p_reg6;
1459:
1460: -------------------------------------------------------------------------------------------------------------
1461: -- Output — bit packer → byte stuffer → framer
1462: -- internally registered in the IPs
1463: -------------------------------------------------------------------------------------------------------------
1464: sBpRawV <= '1' when sReg6V = '1' and sStallLogic = '0'
1465: and (sReg6.mode = token_run_interruption or sReg6.mode = token_raw) else
1466: '0';
1467: sBpGolV <= '1' when sReg6V = '1' and sStallLogic = '0'
1468: and (sReg6.mode = token_regular or sReg6.mode = token_run_interruption) else
1469: '0';
1470:
1471: u_bit_packer : entity work.a11_2_bit_packer(behavioral)
1472: generic map (
1473: LIMIT => LIMIT,
1474: OUT_WIDTH => LIMIT,
1475: UNARY_WIDTH => UNARY_WIDTH,
1476: SUFFIX_WIDTH => SUFFIX_WIDTH,
1477: SUFFIXLEN_WIDTH => SUFFIXLEN_WIDTH
1478: )
1479: port map (
1480: iClk => iClk,
1481: iRst => iRst,
1482: iStall => sStallLogic,
1483: iRawValid => sBpRawV,
1484: iRawLen => sReg6.RawLen,
1485: iRawVal => sReg6.RawVal,
1486: iGolombValid => sBpGolV,
1487: iUnaryZeros => sReg6Unary,
1488: iSuffixLen => sReg6SufLen,
1489: iSuffixVal => sReg6SufVal,
1490: oWord => sBpWord,
1491: oWordValid => sBpWordV,
1492: oValidLen => sBpValidLen
1493: );
1494:
1495: u_byte_stuffer : entity work.byte_stuffer(behavioral)
1496: generic map (
1497: IN_WIDTH => LIMIT,
1498: OUT_BYTES_PER_CYCLE => BYTE_STUFFER_OUT_BYTES_PER_CYCLE,
1499: BURST_DEPTH => BYTE_STUFFER_BURST_DEPTH
1500: )
1501: port map (
1502: iClk => iClk,
1503: iRst => iRst,
1504: iStall => sStallLogic,
1505: iWord => sBpWord,
1506: iWordValid => sBpWordV,
1507: iWordValidLen => sBpValidLen,
1508: iFlush => sBsFlush,
1509: oWord => sBsWord,
1510: oWordValid => sBsWordV,
1511: oValidBytes => sBsValidB,
1512: iReady => sFramerReady,
1513: oAlmostFull => sBsAlmostFull,
1514: oFlushDone => sBsFlushDone
1515: );
1516:
1517: u_framer : entity work.jls_framer(behavioral)
1518: generic map (
1519: BITNESS => BITNESS,
1520: IN_WIDTH => BYTE_STUFFER_OUT_WIDTH,
1521: OUT_WIDTH => OUT_WIDTH,
1522: MAX_IMAGE_WIDTH => MAX_IMAGE_WIDTH,
1523: MAX_IMAGE_HEIGHT => MAX_IMAGE_HEIGHT
1524: )
1525: port map (
1526: iClk => iClk,
1527: iRst => iRst,
1528: iStart => sFramerStart,
1529: iImageWidth => sImageWidth,
1530: iImageHeight => sImageHeight,
1531: iEoi => sFramerEoi,
1532: iWord => sBsWord,
1533: iValid => sBsWordV,
1534: iByteEnable => sBsValidB,
1535: oReady => sFramerReady,
1536: iReady => iReady,
1537: oWord => oData,
1538: oValid => oValid,
1539: oByteEnable => sFramerVBytes,
1540: oLast => oLast
1541: );
1542:
1543: -- AXI-Stream tkeep: one bit per byte
1544:
1545: gen_keep : for i in 0 to OUT_WIDTH / 8 - 1 generate
1546: oKeep(OUT_WIDTH / 8 - 1 - i) <= '1' when sFramerVBytes > i else
1547: '0';
1548: end generate gen_keep;
1549:
1550: -------------------------------------------------------------------------------------------------------------
1551: -- Flush / framer control
1552: -------------------------------------------------------------------------------------------------------------
1553:
1554: -- Pass the flush control from the EOI pipeline to the output stages
1555: p_flush_control : process (iClk) is
1556: begin
1557:
1558: if rising_edge(iClk) then
1559: if (iRst = '1') then
1560: sBsFlush <= '0';
1561: elsif (sStallLogic = '0') then
1562: sBsFlush <= sReg6Eoi;
1563: end if;
1564: end if;
1565:
1566: end process p_flush_control;
1567:
1568: sFramerEoi <= sBsFlushDone;
1569:
1570: -- First-pixel tracker. line_buffer flags EOI combinationally on the image's
1571: -- last accepted pixel, so the next accepted pixel starts the following image
1572: p_first_pixel : process (iClk) is
1573: begin
1574:
1575: if rising_edge(iClk) then
1576: if (iRst = '1') then
1577: sFirstPixel <= '1';
1578: elsif (sValid = '1') then
1579: sFirstPixel <= sLbEoi;
1580: end if;
1581: end if;
1582:
1583: end process p_first_pixel;
1584:
1585: sFramerStart <= sValid and sFirstPixel;
1586:
1587: end architecture rtl;