162def XrtBSP(user_module):
163 """Use the Xilinx RunTime (XRT) shell to implement ESI services and build an
164 image or emulation package.
166 - Wrap your top PyCDE module in `XrtBSP`.
167 - Run your script. This BSP will write a 'build package' to the output dir.
168 This package contains a Makefile.xrt.mk which (given a proper Vitis dev
169 environment) will compile a hw image or hw_emu image. It is a free-standing
170 build package -- you do not need PyCDE installed on the same machine as you
171 want to do the image build.
172 - To build the `hw` image, run 'make -f Makefile.xrt TARGET=hw'. If you want
173 an image which runs on an Azure NP-series instance, run the 'azure' target
174 (requires an Azure subscription set up with as per
175 https://learn.microsoft.com/en-us/azure/virtual-machines/field-programmable-gate-arrays-attestation).
176 This target requires a few environment variables to be set (which the Makefile
177 will tell you about).
178 - To build a hw emulation image, run make with TARGET=hw_emu.
179 - At "runtime" set XCL_EMULATION_MODE=hw_emu.
180 - Validated ONLY on Vitis 2023.1. Known to NOT work with Vitis <2022.1.
181 - Vitis spins up a number of jobs and can easily consume all available memory.
182 - Specify the JOBS make variable to limit the number of jobs.
183 - To adjust the desired clock frequency, set the FREQ (in MHz) make variable.
186 class XrtTop(Module):
188 ap_resetn = Input(Bits(1))
190 HostMemAddressWidth = 64
192 HostMemDataWidth = 512
198 s_axi_control_AWVALID = Input(Bits(1))
199 s_axi_control_AWREADY = Output(Bits(1))
200 s_axi_control_AWADDR = Input(Bits(20))
201 s_axi_control_WVALID = Input(Bits(1))
202 s_axi_control_WREADY = Output(Bits(1))
203 s_axi_control_WDATA = Input(Bits(32))
204 s_axi_control_WSTRB = Input(Bits(32 // 8))
205 s_axi_control_ARVALID = Input(Bits(1))
206 s_axi_control_ARREADY = Output(Bits(1))
207 s_axi_control_ARADDR = Input(Bits(20))
208 s_axi_control_RVALID = Output(Bits(1))
209 s_axi_control_RREADY = Input(Bits(1))
210 s_axi_control_RDATA = Output(Bits(32))
211 s_axi_control_RRESP = Output(Bits(2))
212 s_axi_control_BVALID = Output(Bits(1))
213 s_axi_control_BREADY = Input(Bits(1))
214 s_axi_control_BRESP = Output(Bits(2))
222 m_axi_gmem_AWVALID = Output(Bits(1))
223 m_axi_gmem_AWREADY = Input(Bits(1))
224 m_axi_gmem_AWADDR = Output(Bits(HostMemAddressWidth))
225 m_axi_gmem_AWID = Output(Bits(HostMemIdWidth))
226 m_axi_gmem_AWLEN = Output(Bits(8))
227 m_axi_gmem_AWSIZE = Output(Bits(3))
228 m_axi_gmem_AWBURST = Output(Bits(2))
231 m_axi_gmem_WVALID = Output(Bits(1))
232 m_axi_gmem_WREADY = Input(Bits(1))
233 m_axi_gmem_WDATA = Output(Bits(HostMemDataWidth))
234 m_axi_gmem_WSTRB = Output(Bits(HostMemDataWidth // 8))
235 m_axi_gmem_WLAST = Output(Bits(1))
238 m_axi_gmem_BVALID = Input(Bits(1))
239 m_axi_gmem_BREADY = Output(Bits(1))
240 m_axi_gmem_BRESP = Input(Bits(2))
241 m_axi_gmem_BID = Input(Bits(HostMemIdWidth))
245 m_axi_gmem_ARVALID = Output(Bits(1))
246 m_axi_gmem_ARREADY = Input(Bits(1))
247 m_axi_gmem_ARADDR = Output(UInt(HostMemAddressWidth))
248 m_axi_gmem_ARID = Output(UInt(HostMemIdWidth))
249 m_axi_gmem_ARLEN = Output(UInt(8))
250 m_axi_gmem_ARSIZE = Output(Bits(3))
251 m_axi_gmem_ARBURST = Output(Bits(2))
254 m_axi_gmem_RVALID = Input(Bits(1))
255 m_axi_gmem_RREADY = Output(Bits(1))
256 m_axi_gmem_RDATA = Input(Bits(HostMemDataWidth))
257 m_axi_gmem_RLAST = Input(Bits(1))
258 m_axi_gmem_RID = Input(UInt(HostMemIdWidth))
259 m_axi_gmem_RRESP = Input(Bits(2))
262 def construct(ports):
263 System.current().platform =
"fpga"
265 rst = ~ports.ap_resetn
267 ChannelEngineService(OneItemBuffersToHost, OneItemBuffersFromHost)(
268 None, appid=
esi.AppID(
"__channel_engines"), clk=clk, rst=rst)
271 read_address, arready = Channel(ports.s_axi_control_ARADDR.type).
wrap(
272 ports.s_axi_control_ARADDR, ports.s_axi_control_ARVALID)
273 ports.s_axi_control_ARREADY = arready
274 write_address, awready = Channel(ports.s_axi_control_AWADDR.type).
wrap(
275 ports.s_axi_control_AWADDR, ports.s_axi_control_AWVALID)
276 ports.s_axi_control_AWREADY = awready
277 write_data, wready = Channel(ports.s_axi_control_WDATA.type).
wrap(
278 ports.s_axi_control_WDATA, ports.s_axi_control_WVALID)
279 ports.s_axi_control_WREADY = wready
281 user_module(clk=clk, rst=rst)
282 esi.TelemetryMMIO(esi.Telemetry,
287 data = Wire(Channel(esi.MMIODataType))
290 read_address=read_address,
291 write_address=write_address,
292 write_data=write_data)
293 sel = rw_mux.sel.buffer(clk, rst, 1)
296 cmd, froms = esi.MMIO.read_write.type.pack(cmd=rw_mux.cmd)
297 data.assign(froms[
"data"])
304 cmd=indirect_mmio.downstream)
306 rdata, rvalid = rw_demux.read_data.unwrap(ports.s_axi_control_RREADY)
307 ports.s_axi_control_RVALID = rvalid
308 ports.s_axi_control_RDATA = rdata.data
309 ports.s_axi_control_RRESP = rdata.resp
311 wrresp_data, wrresp_valid = rw_mux.write_resp.unwrap(
312 ports.s_axi_control_BREADY)
313 ports.s_axi_control_BVALID = wrresp_valid
314 ports.s_axi_control_BRESP = wrresp_data
317 XrtTop.construct_hostmem(ports)
320 sys = System.current()
321 sys.add_packaging_step(XrtTop.package)
324 def construct_hostmem(ports):
325 """Construct the host memory interface"""
326 rst = ~ports.ap_resetn
330 HostMemDataWidthBytes = XrtTop.HostMemDataWidth // 8
331 hostmem = ChannelHostMem(read_width=XrtTop.HostMemDataWidth,
332 write_width=XrtTop.HostMemDataWidth)(
342 read_resp_data_type = hostmem.read.type.resp.inner
343 read_resp_wire = Wire(Channel(read_resp_data_type))
344 read_req = hostmem.read.unpack(resp=read_resp_wire)[
'req']
347 read_req_data, read_req_valid = read_req.unwrap(ports.m_axi_gmem_ARREADY)
348 ports.m_axi_gmem_ARVALID = read_req_valid
349 ports.m_axi_gmem_ARADDR = read_req_data.address
350 ports.m_axi_gmem_ARID = read_req_data.tag
353 ports.m_axi_gmem_ARSIZE = clog2(HostMemDataWidthBytes)
354 ports.m_axi_gmem_ARLEN = ((read_req_data.length - 1) /
355 HostMemDataWidthBytes).as_uint(8)
356 ports.m_axi_gmem_ARBURST = Bits(2)(1)
359 read_resp_data = read_resp_data_type({
360 "tag": ports.m_axi_gmem_RID,
361 "data": ports.m_axi_gmem_RDATA,
363 read_resp, read_resp_ready = read_resp_wire.type.wrap(
364 read_resp_data, ports.m_axi_gmem_RVALID)
365 ports.m_axi_gmem_RREADY = read_resp_ready
366 read_resp_wire.assign(read_resp)
372 write_ack_wire = Wire(Channel(esi.HostMem.TagType))
373 write_req = hostmem.write.unpack(ackTag=write_ack_wire)[
'req']
374 address_req, data_req = write_req.fork(ports.ap_clk, rst)
377 address_req_data, address_req_valid = address_req.unwrap(
378 ports.m_axi_gmem_AWREADY)
379 ports.m_axi_gmem_AWVALID = address_req_valid
380 ports.m_axi_gmem_AWADDR = address_req_data.address.as_bits()
381 ports.m_axi_gmem_AWID = address_req_data.tag.as_bits()
382 ports.m_axi_gmem_AWLEN = Bits(8)(0)
383 ports.m_axi_gmem_AWSIZE = clog2(HostMemDataWidthBytes)
384 ports.m_axi_gmem_AWBURST = Bits(2)(1)
387 data_req_data, data_req_valid = data_req.unwrap(ports.m_axi_gmem_WREADY)
388 ports.m_axi_gmem_WVALID = data_req_valid
389 ports.m_axi_gmem_WDATA = data_req_data.data
391 wstrb_lookup_table_len = HostMemDataWidthBytes + 1
392 wstrb_lookup_table = Array(Bits(HostMemDataWidthBytes),
393 wstrb_lookup_table_len)([
394 Bits(HostMemDataWidthBytes)(2**vb - 1)
395 for vb
in range(wstrb_lookup_table_len)
401 ports.m_axi_gmem_WSTRB = wstrb_lookup_table[
402 data_req_data.valid_bytes.as_uint(clog2(wstrb_lookup_table_len))]
403 ports.m_axi_gmem_WLAST = Bits(1)(1)
406 write_ack, write_ack_ready = Channel(esi.HostMem.TagType).
wrap(
407 ports.m_axi_gmem_BID.as_uint(), ports.m_axi_gmem_BVALID)
408 write_ack_wire.assign(write_ack)
409 ports.m_axi_gmem_BREADY = write_ack_ready
412 def package(sys: System):
413 """Assemble a 'build' package which includes all the necessary build
414 collateral (about which we are aware), build/debug scripts, and the
415 generated runtime."""
417 sv_sources = glob.glob(str(__dir__ /
'*.sv'))
418 tcl_sources = glob.glob(str(__dir__ /
'*.tcl'))
419 for source
in sv_sources + tcl_sources:
420 shutil.copy(source, sys.hw_output_dir)
422 shutil.copy(__dir__ /
"Makefile.xrt.mk",
423 sys.output_directory /
"Makefile.xrt.mk")
424 shutil.copy(__dir__ /
"xrt_package.tcl",
425 sys.output_directory /
"xrt_package.tcl")
426 shutil.copy(__dir__ /
"xrt.ini", sys.output_directory /
"xrt.ini")
427 shutil.copy(__dir__ /
"xrt_vitis.cfg",
428 sys.output_directory /
"xrt_vitis.cfg")
429 shutil.copy(__dir__ /
"xsim.tcl", sys.output_directory /
"xsim.tcl")