CIRCT 23.0.0git
Loading...
Searching...
No Matches
Xrt.cpp
Go to the documentation of this file.
1//===- Xrt.cpp - ESI XRT device backend -------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// DO NOT EDIT!
10// This file is distributed as part of an ESI package. The source for this file
11// should always be modified within CIRCT
12// (lib/dialect/ESI/runtime/cpp/lib/backends/Cosim.cpp).
13//
14//===----------------------------------------------------------------------===//
15
16#include "esi/backends/Xrt.h"
17#include "esi/Services.h"
18
19// XRT includes
20#include "experimental/xrt_bo.h"
21#include "experimental/xrt_device.h"
22#include "experimental/xrt_ip.h"
23#include "experimental/xrt_xclbin.h"
24
25#include <fstream>
26#include <iostream>
27#include <set>
28
29using namespace esi;
30using namespace esi::services;
31using namespace esi::backends::xrt;
32
33/// Parse the connection std::string and instantiate the accelerator. Connection
34/// std::string format:
35/// <xclbin>[SEP<device_id>]
36/// wherein <device_id> is in BDF format (e.g. "0000:3b:00.1").
37/// SEP is ':' on Unix and ';' on Windows to avoid conflicts with Windows drive
38/// letters (e.g. "C:\path\to.xclbin") and BDF colons.
39std::unique_ptr<AcceleratorConnection>
40XrtAccelerator::connect(Context &ctxt, std::string connectionString) {
41 std::string xclbin;
42 std::string device_id;
43
44#ifdef _WIN32
45 constexpr char SEP = ';';
46#else
47 constexpr char SEP = ':';
48#endif
49
50 size_t sep = connectionString.find(SEP);
51 if (sep == std::string::npos) {
52 xclbin = connectionString;
53 } else {
54 xclbin = connectionString.substr(0, sep);
55 device_id = connectionString.substr(sep + 1);
56 }
57
58 // Validate that both parts are non-empty when present.
59 if (xclbin.empty())
60 throw std::runtime_error(
61 std::string("connection string must be of the form ") + "'<xclbin>[" +
62 SEP + "<device_id>]': xclbin path cannot be empty");
63 if (sep != std::string::npos && device_id.empty())
64 throw std::runtime_error(
65 std::string("connection string must be of the form ") + "'<xclbin>[" +
66 SEP + "<device_id>]': device_id cannot be empty");
67
68 return make_unique<XrtAccelerator>(ctxt, xclbin, device_id);
69}
70
72 constexpr static char kernel_name[] = "esi_kernel";
73
74 Impl(std::string xclbin, std::string device_id) {
75 if (device_id.empty())
76 device = ::xrt::device(0);
77 else
78 device = ::xrt::device(device_id);
79
80 // Find memory group for the host.
81 ::xrt::xclbin xcl(xclbin);
82 std::optional<::xrt::xclbin::mem> host_mem;
83 for (auto mem : xcl.get_mems()) {
84 // The host memory is tagged with "HOST[0]". Memory type is wrong --
85 // reports as DRAM rather than host memory so we can't filter on that.
86 if (mem.get_tag().starts_with("HOST")) {
87 if (host_mem.has_value())
88 throw std::runtime_error("Multiple host memories found in xclbin");
89 else
90 host_mem = mem;
91 }
92 }
93 if (!host_mem)
94 throw std::runtime_error("No host memory found in xclbin");
95 memoryGroup = host_mem->get_index();
96
97 // Load the xclbin and instantiate the IP.
98 auto uuid = device.load_xclbin(xcl);
99 ip = ::xrt::ip(device, uuid, kernel_name);
100 }
101
102 ::xrt::device device;
103 ::xrt::ip ip;
104 int32_t memoryGroup;
105};
106
107/// Construct and connect to a cosim server.
108XrtAccelerator::XrtAccelerator(Context &ctxt, std::string xclbin,
109 std::string device_id)
110 : AcceleratorConnection(ctxt) {
111 impl = make_unique<Impl>(xclbin, device_id);
112}
114
115namespace {
116/// Implementation of MMIO for XRT. Uses an indirect register to access a
117/// virtual MMIO space since Vivado/Vitis don't support large enough MMIO
118/// spaces.
119class XrtMMIO : public MMIO {
120
121 // Physical register to write the virtual address.
122 constexpr static uint32_t IndirectLocation = 0x18;
123 // Physical register to read/write the virtual MMIO address stored at
124 // `IndirectLocation`.
125 constexpr static uint32_t IndirectMMIOReg = 0x20;
126
127public:
128 XrtMMIO(XrtAccelerator &conn, ::xrt::ip &ip, const AppIDPath &idPath,
129 const HWClientDetails &clients)
130 : MMIO(conn, idPath, clients), ip(ip) {}
131
132 uint64_t read(uint32_t addr) const override {
133 std::lock_guard<std::mutex> lock(m);
134
135 // Write the address to the indirect location register.
136 xrt_write(IndirectLocation, addr);
137 // Read from the indirect register.
138 uint64_t ret = xrt_read(IndirectMMIOReg);
139
140 getConnection().getLogger().debug(
141 [addr, ret](std::string &subsystem, std::string &msg,
142 std::unique_ptr<std::map<std::string, std::any>> &details) {
143 subsystem = "xrt_mmio";
144 msg = "MMIO[0x" + toHex(addr) + "] = 0x" + toHex(ret);
145 });
146 return ret;
147 }
148 void write(uint32_t addr, uint64_t data) override {
149 std::lock_guard<std::mutex> lock(m);
150
151 // Write the address to the indirect location register.
152 xrt_write(IndirectLocation, addr);
153 // Write to the indirect register.
154 xrt_write(IndirectMMIOReg, data);
155
156 conn.getLogger().debug(
157 [addr,
158 data](std::string &subsystem, std::string &msg,
159 std::unique_ptr<std::map<std::string, std::any>> &details) {
160 subsystem = "xrt_mmio";
161 msg = "MMIO[0x" + toHex(addr) + "] <- 0x" + toHex(data);
162 });
163 }
164
165 /// Read a physical register.
166 uint64_t xrt_read(uint32_t addr) const {
167 auto lo = static_cast<uint64_t>(ip.read_register(addr));
168 auto hi = static_cast<uint64_t>(ip.read_register(addr + 0x4));
169 return (hi << 32) | lo;
170 }
171 /// Write a physical register.
172 void xrt_write(uint32_t addr, uint64_t data) const {
173 ip.write_register(addr, data);
174 ip.write_register(addr + 0x4, data >> 32);
175 }
176
177private:
178 ::xrt::ip &ip;
179 mutable std::mutex m;
180};
181} // namespace
182
183namespace {
184/// Host memory service specialized to XRT.
185class XrtHostMem : public HostMem {
186public:
187 XrtHostMem(XrtAccelerator &conn, ::xrt::device &device, int32_t memoryGroup)
188 : HostMem(conn), device(device), memoryGroup(memoryGroup) {}
189
190 struct XrtHostMemRegion : public HostMemRegion {
191 XrtHostMemRegion(::xrt::device &device, std::size_t size,
192 HostMem::Options opts, int32_t memoryGroup) {
193 bo = ::xrt::bo(device, size, ::xrt::bo::flags::host_only, memoryGroup);
194 // Map the buffer into application memory space so that the application
195 // can use it just like any memory -- no need to use bo::write.
196 ptr = bo.map();
197 }
198 virtual void *getPtr() const override { return ptr; }
199 /// On XRT platforms, the pointer which the device sees is different from
200 /// the pointer the user application sees.
201 virtual void *getDevicePtr() const override { return (void *)bo.address(); }
202 virtual std::size_t getSize() const override { return bo.size(); }
203 /// It is required to use 'sync' to flush the caches before executing any
204 /// DMA.
205 virtual void flush() override { bo.sync(XCL_BO_SYNC_BO_TO_DEVICE); }
206
207 private:
208 ::xrt::bo bo;
209 void *ptr;
210 };
211
212 std::unique_ptr<HostMemRegion>
213 allocate(std::size_t size, HostMem::Options opts) const override {
214 return std::unique_ptr<HostMemRegion>(
215 new XrtHostMemRegion(device, size, opts, memoryGroup));
216 }
217
218private:
219 ::xrt::device &device;
220 int32_t memoryGroup;
221};
222} // namespace
223
225 std::string implName,
226 const ServiceImplDetails &details,
227 const HWClientDetails &clients) {
228 if (svcType == typeid(MMIO))
229 return new XrtMMIO(*this, impl->ip, id, clients);
230 else if (svcType == typeid(HostMem))
231 return new XrtHostMem(*this, impl->device, impl->memoryGroup);
232 else if (svcType == typeid(SysInfo))
233 return new MMIOSysInfo(getService<MMIO>());
234 return nullptr;
235}
236
#define REGISTER_ACCELERATOR(Name, TAccelerator)
Abstract class representing a connection to an accelerator.
Definition Accelerator.h:89
Context & ctxt
ESI accelerator context.
virtual void disconnect()
Disconnect from the accelerator cleanly.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition Context.h:34
Connect to an ESI simulation.
Definition Xrt.h:31
XrtAccelerator(Context &, std::string xclbin, std::string kernelName)
Construct and connect to a cosim server.
Definition Xrt.cpp:108
static std::unique_ptr< AcceleratorConnection > connect(Context &, std::string connectionString)
Parse the connection std::string and instantiate the accelerator.
Definition Xrt.cpp:40
std::unique_ptr< Impl > impl
Definition Xrt.h:47
virtual Service * createService(Service::Type service, AppIDPath path, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients) override
Called by getServiceImpl exclusively.
Definition Xrt.cpp:224
Implement the SysInfo API for a standard MMIO protocol.
Definition Services.h:207
Parent class of all APIs modeled as 'services'.
Definition Services.h:59
const std::type_info & Type
Definition Services.h:61
Information about the Accelerator system.
Definition Services.h:113
Definition esi.py:1
std::map< std::string, std::any > ServiceImplDetails
Definition Common.h:108
std::string toHex(void *val)
Definition Common.cpp:37
std::vector< HWClientDetail > HWClientDetails
Definition Common.h:107
static constexpr char kernel_name[]
Definition Xrt.cpp:72
Impl(std::string xclbin, std::string device_id)
Definition Xrt.cpp:74
Options for allocating host memory.
Definition Services.h:255