File: ../../Sources/Xilinx/openjls_axis_regs.vhd
0: -------------------------------------------------------------------------------------------------------------
1: -- Engineer: Vitor Mendes Camilo
2: --
3: -- Module Name: openjls_axis_regs - rtl
4: -- Description: AXI4-Stream + AXI4-Lite wrapper around openjls_top (flavor B).
5: --
6: -- Instantiates openjls_axis (flavor A) and adds an AXI4-Lite register
7: -- bank plus a reset controller. The core samples iImageWidth/
8: -- iImageHeight only while its synchronous reset is high, so
9: -- reconfiguration is expressed as: write WIDTH/HEIGHT, set CTRL.APPLY.
10: -- APPLY pulses the core reset for one clock while the
11: -- registers are held stable; the AXI-Lite endpoint itself stays on
12: -- aresetn only, so the bus never disappears mid-reconfigure.
13: -- Back-to-back images of unchanged dimensions need no APPLY.
14: --
15: -- While the pulse is active STATUS.BUSY reads 1 and the core holds
16: -- s_axis_pixel_tready low, so a stream started too early stalls
17: -- instead of losing pixels. Writes to WIDTH/HEIGHT/CTRL while BUSY
18: -- are dropped (responded OKAY, not applied).
19: --
20: -- WIDTH/HEIGHT writes are clamped to the core's rule (out-of-range
21: -- values become the MAX generic), so a readback always returns the
22: -- value the core will actually use.
23: --
24: --------------------------------------------------------------------------------------------
25: -- REGISTER MAP (word-aligned offsets, 32-bit)
26: --------------------------------------------------------------------------------------------
27: --
28: -- 0x00 ID RO ASCII "OJLS" (0x4F4A4C53)
29: -- 0x04 VERSION RO 0x00MMmmpp (major/minor/patch)
30: -- 0x08 CAPS RO [7:0] BITNESS, [15:8] output bytes per beat (OUT_WIDTH/8)
31: -- 0x0C MAXDIM RO [15:0] MAX_IMAGE_WIDTH, [31:16] MAX_IMAGE_HEIGHT
32: -- 0x10 WIDTH RW [15:0] image width (clamped on write)
33: -- 0x14 HEIGHT RW [15:0] image height (clamped on write)
34: -- 0x18 CTRL WO [0] APPLY — self-clearing, pulses the core reset
35: -- 0x1C STATUS RO [0] BUSY (reset pulse active), [1] s_axis_pixel TREADY mirror
36: --
37: -------------------------------------------------------------------------------------------------------------
38:
39: library ieee;
40: use ieee.std_logic_1164.all;
41: use ieee.numeric_std.all;
42: use work.openjls_pkg.all;
43:
44: -- AXI port names must keep the <prefix>_* suffix convention (lowercase,
45: -- underscores) for Vivado IP integrator interface inference; the prefix
46: -- becomes the interface name in the block diagram.
47: -- vsg_off port_010 port_map_002
48:
49: entity openjls_axis_regs is
50: generic (
51: BITNESS : positive range 8 to 16 := 12;
52: MAX_IMAGE_WIDTH : positive range 4 to 65535 := 4096;
53: MAX_IMAGE_HEIGHT : positive range 1 to 65535 := 4096;
54: OUT_WIDTH : positive range 48 to 1024 := CO_OUT_WIDTH_STD
55: );
56: port (
57: aclk : in std_logic;
58: aresetn : in std_logic;
59: -- AXI4-Lite slave — configuration and status
60: s_axi_ctrl_awaddr : in std_logic_vector(7 downto 0);
61: s_axi_ctrl_awprot : in std_logic_vector(2 downto 0);
62: s_axi_ctrl_awvalid : in std_logic;
63: s_axi_ctrl_awready : out std_logic;
64: s_axi_ctrl_wdata : in std_logic_vector(31 downto 0);
65: s_axi_ctrl_wstrb : in std_logic_vector(3 downto 0);
66: s_axi_ctrl_wvalid : in std_logic;
67: s_axi_ctrl_wready : out std_logic;
68: s_axi_ctrl_bresp : out std_logic_vector(1 downto 0);
69: s_axi_ctrl_bvalid : out std_logic;
70: s_axi_ctrl_bready : in std_logic;
71: s_axi_ctrl_araddr : in std_logic_vector(7 downto 0);
72: s_axi_ctrl_arprot : in std_logic_vector(2 downto 0);
73: s_axi_ctrl_arvalid : in std_logic;
74: s_axi_ctrl_arready : out std_logic;
75: s_axi_ctrl_rdata : out std_logic_vector(31 downto 0);
76: s_axi_ctrl_rresp : out std_logic_vector(1 downto 0);
77: s_axi_ctrl_rvalid : out std_logic;
78: s_axi_ctrl_rready : in std_logic;
79: -- AXI4-Stream slave — one pixel per beat, right-justified
80: s_axis_pixel_tdata : in std_logic_vector(8 * ((BITNESS + 7) / 8) - 1 downto 0);
81: s_axis_pixel_tvalid : in std_logic;
82: s_axis_pixel_tlast : in std_logic;
83: s_axis_pixel_tready : out std_logic;
84: -- AXI4-Stream master — encoded .jls byte stream
85: m_axis_jls_tdata : out std_logic_vector(OUT_WIDTH - 1 downto 0);
86: m_axis_jls_tkeep : out std_logic_vector(OUT_WIDTH / 8 - 1 downto 0);
87: m_axis_jls_tvalid : out std_logic;
88: m_axis_jls_tlast : out std_logic;
89: m_axis_jls_tready : in std_logic
90: );
91:
92: -- Vivado IP integrator interface inference
93: attribute x_interface_info : string;
94: attribute x_interface_parameter : string;
95: attribute x_interface_info of aclk : signal is "xilinx.com:signal:clock:1.0 aclk CLK";
96: -- aresetn is auto-associated with aclk by Vivado (standard name/polarity)
97: attribute x_interface_parameter of aclk : signal is "ASSOCIATED_BUSIF s_axi_ctrl:s_axis_pixel:m_axis_jls";
98: attribute x_interface_info of aresetn : signal is "xilinx.com:signal:reset:1.0 aresetn RST";
99: attribute x_interface_parameter of aresetn : signal is "POLARITY ACTIVE_LOW";
100: end entity openjls_axis_regs;
101:
102: architecture rtl of openjls_axis_regs is
103:
104: constant VERSION : std_logic_vector(31 downto 0) := x"00010000"; -- 1.0.0
105:
106: -- Word-address decode (byte offset / 4)
107: constant REG_ID : natural := 0;
108: constant REG_VERSION : natural := 1;
109: constant REG_CAPS : natural := 2;
110: constant REG_MAXDIM : natural := 3;
111: constant REG_WIDTH : natural := 4;
112: constant REG_HEIGHT : natural := 5;
113: constant REG_CTRL : natural := 6;
114: constant REG_STATUS : natural := 7;
115:
116: -- Configuration registers
117: signal sWidth : unsigned(15 downto 0);
118: signal sHeight : unsigned(15 downto 0);
119:
120: -- Reset controller
121: signal sSoftRst : std_logic;
122: signal sCoreRst : std_logic;
123:
124: -- AXI-Lite handshake state (single outstanding transaction per channel)
125: signal sWrHandshake : std_logic;
126: signal sRdHandshake : std_logic;
127: signal sBValid : std_logic;
128: signal sRValid : std_logic;
129: signal sRData : std_logic_vector(31 downto 0);
130:
131: signal sReadyMirror : std_logic;
132:
133: -- Merge an AXI-Lite write into the low 16 bits of a register, honoring
134: -- WSTRB, then clamp to the core's sample-time rule (out-of-range -> MAX)
135: -- so readback always reports the value the core will actually use.
136:
137: function merge_clamp_dim (
138: vcur : unsigned(15 downto 0);
139: vwdata : std_logic_vector(31 downto 0);
140: vwstrb : std_logic_vector(3 downto 0);
141: vmindim : natural;
142: vmaxdim : natural
143: ) return unsigned is
144:
145: variable vNew : unsigned(15 downto 0);
146:
147: begin
148:
149: vNew := vcur;
150:
151: if (vwstrb(0) = '1') then
152: vNew(7 downto 0) := unsigned(vwdata(7 downto 0));
153: end if;
154:
155: if (vwstrb(1) = '1') then
156: vNew(15 downto 8) := unsigned(vwdata(15 downto 8));
157: end if;
158:
159: if (vNew < vmindim or vNew > vmaxdim) then
160: vNew := to_unsigned(vmaxdim, vNew'length);
161: end if;
162:
163: return vNew;
164:
165: end function merge_clamp_dim;
166:
167: begin
168:
169: -------------------------------------------------------------------------------------------------------------
170: -- AXI4-Lite WRITE CHANNEL
171: -------------------------------------------------------------------------------------------------------------
172: -- Address and data are accepted in the same cycle (ready waits for both
173: -- valids — legal: ready may depend on valid, not vice versa). Single
174: -- outstanding transaction; next one is accepted after BREADY.
175:
176: sWrHandshake <= '1' when s_axi_ctrl_awvalid = '1' and s_axi_ctrl_wvalid = '1' and sBValid = '0' else
177: '0';
178:
179: s_axi_ctrl_awready <= sWrHandshake;
180: s_axi_ctrl_wready <= sWrHandshake;
181: s_axi_ctrl_bresp <= "00"; -- OKAY; RO/unmapped writes are silently dropped
182: s_axi_ctrl_bvalid <= sBValid;
183:
184: p_axi_write : process (aclk) is
185:
186: variable vAddrWord : natural;
187:
188: begin
189:
190: if rising_edge(aclk) then
191: if (aresetn = '0') then
192: sBValid <= '0';
193: sWidth <= to_unsigned(MAX_IMAGE_WIDTH, sWidth'length);
194: sHeight <= to_unsigned(MAX_IMAGE_HEIGHT, sHeight'length);
195: sSoftRst <= '0';
196: else
197: -- Soft-reset pulse is a single clock: every synchronous element in
198: -- the core resets in one cycle (see openjls_top). Default-clear here,
199: -- set on an APPLY write below (last assignment wins).
200: sSoftRst <= '0';
201:
202: if (sBValid = '1' and s_axi_ctrl_bready = '1') then
203: sBValid <= '0';
204: end if;
205:
206: if (sWrHandshake = '1') then
207: sBValid <= '1';
208: vAddrWord := to_integer(unsigned(s_axi_ctrl_awaddr(7 downto 2)));
209:
210: -- Configuration writes are dropped while the reset pulse is live:
211: -- the core is sampling these registers right now.
212: if (sSoftRst = '0') then
213:
214: case vAddrWord is
215:
216: when REG_WIDTH =>
217:
218: sWidth <= merge_clamp_dim(sWidth, s_axi_ctrl_wdata, s_axi_ctrl_wstrb, CO_MIN_IMAGE_WIDTH, MAX_IMAGE_WIDTH);
219:
220: when REG_HEIGHT =>
221:
222: sHeight <= merge_clamp_dim(sHeight, s_axi_ctrl_wdata, s_axi_ctrl_wstrb, CO_MIN_IMAGE_HEIGHT, MAX_IMAGE_HEIGHT);
223:
224: when REG_CTRL =>
225:
226: if (s_axi_ctrl_wstrb(0) = '1' and s_axi_ctrl_wdata(0) = '1') then
227: sSoftRst <= '1';
228: end if;
229:
230: when others =>
231:
232: null; -- RO / unmapped: dropped
233:
234: end case;
235:
236: end if;
237: end if;
238: end if;
239: end if;
240:
241: end process p_axi_write;
242:
243: -------------------------------------------------------------------------------------------------------------
244: -- AXI4-Lite READ CHANNEL
245: -------------------------------------------------------------------------------------------------------------
246:
247: sRdHandshake <= '1' when s_axi_ctrl_arvalid = '1' and sRValid = '0' else
248: '0';
249:
250: s_axi_ctrl_arready <= sRdHandshake;
251: s_axi_ctrl_rresp <= "00"; -- OKAY; unmapped reads return zero
252: s_axi_ctrl_rvalid <= sRValid;
253: s_axi_ctrl_rdata <= sRData;
254:
255: p_axi_read : process (aclk) is
256:
257: variable vAddrWord : natural;
258:
259: begin
260:
261: if rising_edge(aclk) then
262: if (aresetn = '0') then
263: sRValid <= '0';
264: sRData <= (others => '0');
265: else
266: if (sRValid = '1' and s_axi_ctrl_rready = '1') then
267: sRValid <= '0';
268: elsif (sRdHandshake = '1') then
269: sRValid <= '1';
270: vAddrWord := to_integer(unsigned(s_axi_ctrl_araddr(7 downto 2)));
271: sRData <= (others => '0');
272:
273: case vAddrWord is
274:
275: when REG_ID =>
276:
277: sRData <= x"4F4A4C53"; -- "OJLS"
278:
279: when REG_VERSION =>
280:
281: sRData <= VERSION;
282:
283: when REG_CAPS =>
284:
285: sRData(7 downto 0) <= std_logic_vector(to_unsigned(BITNESS, 8));
286: sRData(15 downto 8) <= std_logic_vector(to_unsigned(OUT_WIDTH / 8, 8));
287:
288: when REG_MAXDIM =>
289:
290: sRData(15 downto 0) <= std_logic_vector(to_unsigned(MAX_IMAGE_WIDTH, 16));
291: sRData(31 downto 16) <= std_logic_vector(to_unsigned(MAX_IMAGE_HEIGHT, 16));
292:
293: when REG_WIDTH =>
294:
295: sRData(15 downto 0) <= std_logic_vector(sWidth);
296:
297: when REG_HEIGHT =>
298:
299: sRData(15 downto 0) <= std_logic_vector(sHeight);
300:
301: when REG_STATUS =>
302:
303: sRData(0) <= sSoftRst;
304: sRData(1) <= sReadyMirror;
305:
306: when others =>
307:
308: -- REG_CTRL reads as zero (write-only), unmapped reads zero
309: null;
310:
311: end case;
312:
313: end if;
314: end if;
315: end if;
316:
317: end process p_axi_read;
318:
319: -------------------------------------------------------------------------------------------------------------
320: -- RESET CONTROLLER + CORE
321: -------------------------------------------------------------------------------------------------------------
322:
323: sCoreRst <= (not aresetn) or sSoftRst;
324:
325: s_axis_pixel_tready <= sReadyMirror;
326:
327: u_openjls_axis : entity work.openjls_axis(rtl)
328: generic map (
329: BITNESS => BITNESS,
330: MAX_IMAGE_WIDTH => MAX_IMAGE_WIDTH,
331: MAX_IMAGE_HEIGHT => MAX_IMAGE_HEIGHT,
332: OUT_WIDTH => OUT_WIDTH
333: )
334: port map (
335: iClk => aclk,
336: iRst => sCoreRst,
337: iImageWidth => std_logic_vector(sWidth),
338: iImageHeight => std_logic_vector(sHeight),
339: s_axis_pixel_tdata => s_axis_pixel_tdata,
340: s_axis_pixel_tvalid => s_axis_pixel_tvalid,
341: s_axis_pixel_tlast => s_axis_pixel_tlast,
342: s_axis_pixel_tready => sReadyMirror,
343: m_axis_jls_tdata => m_axis_jls_tdata,
344: m_axis_jls_tkeep => m_axis_jls_tkeep,
345: m_axis_jls_tvalid => m_axis_jls_tvalid,
346: m_axis_jls_tlast => m_axis_jls_tlast,
347: m_axis_jls_tready => m_axis_jls_tready
348: );
349:
350: end architecture rtl;