File: ../../Sources/line_buffer.vhd
0: ----------------------------------------------------------------------------------
1: -- Engineer: Vitor Mendes Camilo
2: --
3: -- Module Name: line_buffer - Behavioral
4: --
5: -- Notes:
6: -- Stores one row of pixels on FIFO and provides the four T.87 causal
7: -- context neighbors for each pixel, where x is the current pixel:
8: --
9: -- c b d
10: -- a x
11: --
12: -- a = left neighbor (same row, col-1)
13: -- b = upper neighbor (previous row, col)
14: -- c = upper-left neighbor (previous row, col-1)
15: -- d = upper-right neighbor (previous row, col+1)
16: --
17: -- Border conditions (T.87 A.2.1):
18: -- First row : b = c = d = 0
19: -- Col 0 (rows>0) : a = Rb = first pixel of previous row
20: -- c = Ra from start of previous row
21: -- = first pixel of the row before that
22: -- Col W-1 : d = b (replicate last pixel of previous row)
23: --
24: -- Assumptions:
25: -- iImageWidth >= 3, iImageHeight >= 1.
26: -- iImageWidth and iImageHeight are stable for the entire image.
27: --
28: ----------------------------------------------------------------------------------
29:
30: library ieee;
31: use ieee.std_logic_1164.all;
32: use ieee.numeric_std.all;
33: use work.openjls_pkg.all;
34:
35: library work;
36: use work.olo_base_pkg_math.log2ceil;
37:
38: entity line_buffer is
39: generic (
40: MAX_IMAGE_WIDTH : positive range 3 to integer'high;
41: MAX_IMAGE_HEIGHT : positive;
42: BITNESS : natural := CO_BITNESS_STD
43: );
44: port (
45: iClk : in std_logic;
46: iRst : in std_logic;
47: iImageWidth : in unsigned(log2ceil(MAX_IMAGE_WIDTH + 1) - 1 downto 0);
48: iImageHeight : in unsigned(log2ceil(MAX_IMAGE_HEIGHT + 1) - 1 downto 0);
49: iValid : in std_logic;
50: iPixel : in unsigned(BITNESS - 1 downto 0);
51: oA : out unsigned(BITNESS - 1 downto 0);
52: oB : out unsigned(BITNESS - 1 downto 0);
53: oC : out unsigned(BITNESS - 1 downto 0);
54: oD : out unsigned(BITNESS - 1 downto 0);
55: oValid : out std_logic;
56: oEol : out std_logic; -- end of line
57: oEoi : out std_logic -- end of image
58: );
59: end entity line_buffer;
60:
61: architecture behavioral of line_buffer is
62:
63: constant COL_WIDTH : natural := log2ceil(MAX_IMAGE_WIDTH + 1);
64: constant ROW_WIDTH : natural := log2ceil(MAX_IMAGE_HEIGHT + 1);
65:
66: type fifo_state_t is (preload, wait_end_first_row, nominal);
67:
68: signal sFifoState : fifo_state_t;
69:
70: signal sFifoOutReady : std_logic;
71: signal sFifoOutValid : std_logic;
72: signal sFifoOutData : std_logic_vector(BITNESS - 1 downto 0);
73: signal sFifoFull : std_logic;
74: signal sFifoEmpty : std_logic;
75: signal sD : unsigned(BITNESS - 1 downto 0); -- d: upper-right
76: signal sB : unsigned(BITNESS - 1 downto 0); -- b: upper
77: signal sC : unsigned(BITNESS - 1 downto 0); -- c: upper-left
78: signal sA : unsigned(BITNESS - 1 downto 0); -- a: left
79: signal sBorderC : unsigned(BITNESS - 1 downto 0); -- c at col 0: sB captured at col 0 of previous row
80: signal sColCounter : unsigned(COL_WIDTH - 1 downto 0);
81: signal sRowCounter : unsigned(ROW_WIDTH - 1 downto 0);
82: signal sIsLastCol : boolean;
83: signal sIsLastRow : boolean;
84: signal sIsEoi : boolean;
85: signal sIsEol : boolean;
86: signal sIsFifoOutHandshake : boolean;
87: signal sIsFirstCol : boolean;
88: signal sPreloadCounter : unsigned(1 downto 0);
89: signal sFifoInValid : std_logic;
90:
91: begin
92:
93: -- Combinatorial process ----------------------------------------------------------------
94: comb_proc : process (iValid, iImageWidth, iImageHeight, sFifoState,
95: sFifoOutReady, sFifoOutValid, sColCounter, sRowCounter,
96: sIsLastCol, sIsLastRow, sIsFirstCol, sIsEol, sIsEoi,
97: sA, sB, sC, sD, sBorderC) is
98: begin
99:
100: oValid <= iValid;
101: sIsLastCol <= sColCounter = iImageWidth - 1;
102: sIsLastRow <= sRowCounter = iImageHeight - 1;
103: sIsFirstCol <= sColCounter = 0;
104: sIsEol <= sIsLastCol and iValid = '1';
105: sIsEoi <= sIsLastCol and sIsLastRow and iValid = '1';
106: oEoi <= bool2bit(sIsEoi);
107: oEol <= bool2bit(sIsEol);
108: sIsFifoOutHandshake <= (sFifoOutReady and sFifoOutValid) = '1';
109:
110: -- Read FIFO logic ------------------------------------------------------
111: if (sFifoState = preload) then
112: sFifoOutReady <= '1';
113: elsif (sFifoState = nominal) then
114: sFifoOutReady <= iValid;
115: else
116: sFifoOutReady <= '0';
117: end if;
118:
119: -- Corner case handling for border conditions (T.87 A.2.1) --------------
120: if (sRowCounter = 0) then -- First row: b = c = d = 0
121: oB <= (others => '0');
122: oC <= (others => '0');
123: oD <= (others => '0');
124: else
125: oB <= sB;
126: if (sIsFirstCol) then
127: oC <= sBorderC; -- Col 0: c = Ra from start of previous row
128: else
129: oC <= sC;
130: end if;
131:
132: if (sIsLastCol) then
133: oD <= sB; -- Last col: replicate last pixel of previous row (= b)
134: else
135: oD <= sD;
136: end if;
137: end if;
138:
139: if (sIsFirstCol) then
140: oA <= sB; -- First col: replicate first pixel of previous row (= b)
141: else
142: oA <= sA;
143: end if;
144:
145: end process comb_proc; ----------------------------------------------------------------------------
146:
147: -- Clocked Process ----------------------------------------------------------------------
148: clocked_proc : process (iClk) is
149: begin
150:
151: if rising_edge(iClk) then
152: if (iRst = '1') then
153: sPreloadCounter <= (others => '0');
154: sFifoState <= preload;
155:
156: sColCounter <= (others => '0');
157: sRowCounter <= (others => '0');
158:
159: sB <= (others => '0');
160: sC <= (others => '0');
161: sD <= (others => '0');
162: sA <= (others => '0');
163: sBorderC <= (others => '0');
164: else
165: -- FIFO control FSM ----------------------------
166: -- sFifoOutReady is controlled combinationally using these states
167: case sFifoState is
168:
169: when preload =>
170:
171: -- When FIFO receives the first pixels it loads them into registers, preparing for nominal operation
172: -- Only loads b and d, since c is out of image
173:
174: if (sIsFifoOutHandshake) then
175: sPreloadCounter <= sPreloadCounter + 1;
176: if (sPreloadCounter = 1) then
177: sFifoState <= wait_end_first_row;
178:
179: if (sIsEol) then -- needs this check to work with images with width=4 (Annex H.3 test image)
180: sFifoState <= nominal;
181: end if;
182: end if;
183: end if;
184:
185: when wait_end_first_row =>
186:
187: -- Nominal operation starts only on second row, since first row has no valid context
188: if (sIsEol) then
189: sFifoState <= nominal;
190: end if;
191:
192: when nominal =>
193:
194: -- On valid operation, every new pixel steps the context window by reading a new neighbor pixels and shifting the current ones
195:
196: if (sIsEoi) then
197: sFifoState <= preload;
198: sPreloadCounter <= (others => '0');
199: end if;
200:
201: end case;
202:
203: -- Counters -------------------------------------
204: if (iValid = '1') then
205: if (sIsLastCol) then
206: sColCounter <= (others => '0');
207: if (sIsLastRow) then
208: sRowCounter <= (others => '0');
209: else
210: sRowCounter <= sRowCounter + 1;
211: end if;
212: else
213: sColCounter <= sColCounter + 1;
214: end if;
215: end if;
216:
217: -- Output control -------------------------------
218: -- Shift context window
219: if (sIsFifoOutHandshake) then
220: sC <= sB;
221: sB <= sD;
222: sD <= unsigned(sFifoOutData);
223: elsif (sFifoState = nominal and iValid = '1') then
224: -- FIFO empty (last row, end of row): sD has no new data but sB/sC still step
225: sC <= sB;
226: sB <= sD;
227: end if;
228:
229: if (iValid = '1') then
230: -- Store last pixel
231: sA <= iPixel;
232:
233: if (sIsFirstCol) then
234: sBorderC <= sB; -- Capture sB at col 0 for use as c border at col 0 of next ro
235: end if;
236: end if;
237:
238: if (sIsEoi) then
239: sB <= (others => '0');
240: sC <= (others => '0');
241: sD <= (others => '0');
242: sA <= (others => '0');
243: sBorderC <= (others => '0');
244: end if;
245: end if;
246: end if;
247:
248: end process clocked_proc; -----------------------------------------------------------------------------
249:
250: -- Instance FIFO -------------------------------------------------------------------------
251: sFifoInValid <= iValid and not bool2bit(sIsLastRow);
252:
253: fifo_inst : entity work.olo_base_fifo_sync(rtl)
254: generic map (
255: WIDTH_G => BITNESS,
256: DEPTH_G => MAX_IMAGE_WIDTH,
257: RAMBEHAVIOR_G => "RBW"
258: )
259: port map (
260: Clk => iClk,
261: Rst => iRst,
262: In_Data => std_logic_vector(iPixel),
263: In_Valid => sFifoInValid,
264: Out_Ready => sFifoOutReady,
265: Out_Data => sFifoOutData,
266: Out_Valid => sFifoOutValid,
267: Full => sFifoFull,
268: Empty => sFifoEmpty
269: );
270:
271: end architecture behavioral;