32 return conn.getService(service,
id, implName, details, clients);
45 uncompress(dst.data(), &dstSize, compressed.data(), compressed.size());
47 throw std::runtime_error(
"zlib uncompress failed with rc=" +
49 return std::string(
reinterpret_cast<char *
>(dst.data()), dstSize);
61 auto offsetIter = client.implOptions.find(
"offset");
62 if (offsetIter == client.implOptions.end())
63 throw std::runtime_error(
"MMIO client missing 'offset' option");
64 const Constant *offset = std::any_cast<Constant>(&offsetIter->second);
66 throw std::runtime_error(
67 "MMIO client 'offset' option must be a constant");
68 const uint64_t *offsetVal = std::any_cast<uint64_t>(&offset->
value);
70 throw std::runtime_error(
71 "MMIO client 'offset' option must be an integer");
72 if (*offsetVal >= 1ull << 32)
73 throw std::runtime_error(
"MMIO client offset mustn't exceed 32 bits");
75 auto sizeIter = client.implOptions.find(
"size");
76 if (sizeIter == client.implOptions.end())
77 throw std::runtime_error(
"MMIO client missing 'size' option");
78 const Constant *size = std::any_cast<Constant>(&sizeIter->second);
80 throw std::runtime_error(
"MMIO client 'size' option must be a constant");
81 const uint64_t *sizeVal = std::any_cast<uint64_t>(&size->
value);
83 throw std::runtime_error(
"MMIO client 'size' option must be an integer");
84 if (*sizeVal >= 1ull << 32)
85 throw std::runtime_error(
"MMIO client size mustn't exceed 32 bits");
87 static_cast<uint32_t
>(*offsetVal),
static_cast<uint32_t
>(*sizeVal)};
95 auto regionIter =
regions.find(
id);
96 if (regionIter ==
regions.end())
103class MMIOPassThrough :
public MMIO {
107 :
MMIO(parent->getConnection(), idPath, clients), parent(parent) {}
108 uint64_t read(uint32_t addr)
const override {
return parent->read(addr); }
109 void write(uint32_t addr, uint64_t data)
override {
110 parent->write(addr, data);
121 if (service !=
typeid(
MMIO))
123 return new MMIOPassThrough(clients,
id,
this);
131 :
ServicePort(
id, nullptr, {}), parent(parent), desc(desc) {}
133 if (addr >=
desc.size)
134 throw std::runtime_error(
"MMIO read out of bounds: " +
toHex(addr));
138 if (addr >=
desc.size)
139 throw std::runtime_error(
"MMIO write out of bounds: " +
toHex(addr));
149 throw std::runtime_error(
"Invalid magic number: " +
toHex(reg));
167 throw std::runtime_error(
"Unsupported ESI header version: " +
168 std::to_string(version));
170 uint64_t size =
mmio->read(manifestPtr);
171 uint64_t numWords = (size + 7) / 8;
172 std::vector<uint64_t> manifestWords(numWords);
173 for (
size_t i = 0; i < numWords; ++i)
174 manifestWords[i] =
mmio->read(manifestPtr + 8 + (i * 8));
176 std::vector<uint8_t> manifest;
177 for (
size_t i = 0; i < size; ++i) {
178 uint64_t word = manifestWords[i / 8];
179 manifest.push_back(word >> (8 * (i % 8)));
186std::optional<uint64_t>
190 uintptr_t base =
reinterpret_cast<uintptr_t
>(
getPtr());
191 uintptr_t p =
reinterpret_cast<uintptr_t
>(ptr);
192 std::size_t regionSize =
getSize();
196 uintptr_t offset = p - base;
197 if (offset >= regionSize || size > regionSize - offset)
199 uint64_t devBase =
reinterpret_cast<uintptr_t
>(
getDevicePtr());
202 uint64_t devHeadroom = UINT64_MAX - devBase;
203 if (offset > devHeadroom || size - 1 > devHeadroom - offset)
205 return devBase + offset;
212 if (
auto f = details.find(
"service"); f != details.end()) {
213 serviceSymbol = std::any_cast<std::string>(f->second);
215 serviceSymbol = serviceSymbol.substr(1);
221 conn.getEngineMapFor(
id).requestPorts(
id, type));
228 if (
auto f = details.find(
"service"); f != details.end())
230 symbol = std::any_cast<std::string>(f->second).substr(1);
238 PortMap ports =
conn.getEngineMapFor(
id).requestPorts(
id, type);
240 return new ToHost(
id.back(), type, ports);
241 return new FromHost(
id.back(), type, ports);
247 return new ToHost(
id,
type, {{std::string(
"data"), data}});
252 throw std::runtime_error(
"ToHost channel is already connected");
254 throw std::runtime_error(
"ChannelService ToHost must have exactly one "
263 throw std::runtime_error(
264 "ToHost channel must be 'connect'ed before reading");
271 return new FromHost(
id,
type, {{std::string(
"data"), data}});
276 throw std::runtime_error(
"FromHost channel is already connected");
278 throw std::runtime_error(
"ChannelService FromHost must have exactly one "
287 throw std::runtime_error(
288 "FromHost channel must be 'connect'ed before writing");
296 if (
auto f = details.find(
"service"); f != details.end())
298 symbol = std::any_cast<std::string>(f->second).substr(1);
304 return new Function(
id.back(), type,
305 conn.getEngineMapFor(
id).requestPorts(
id, type));
312 id,
type, {{std::string(
"arg"),
arg}, {std::string(
"result"),
result}});
319 throw std::runtime_error(
"Function is already connected");
321 throw std::runtime_error(
"FuncService must have exactly two channels");
323 arg->connect(options);
329std::future<MessageData>
332 throw std::runtime_error(
"Function must be 'connect'ed before calling");
333 std::scoped_lock<std::mutex> lock(
callMutex);
335 return result->readAsync();
341 if (
auto f = details.find(
"service"); f != details.end())
343 symbol = std::any_cast<std::string>(f->second).substr(1);
350 conn.getEngineMapFor(
id).requestPorts(
id, type));
369 throw std::runtime_error(
"CallService must have exactly two channels");
376 MessageData resultMsg = callback(std::move(argMsg));
377 this->
result->write(std::move(resultMsg));
382 arg->connect(options);
383 acc.getServiceThread()->addListener(
385 MessageData resultMsg = callback(std::move(argMsg));
386 this->
result->write(std::move(resultMsg));
398 if (prefix.size() > 0)
401 if (client.implOptions.contains(
"type") &&
402 std::any_cast<std::string>(client.implOptions.at(
"type")) !=
"mmio")
404 AppIDPath fullClientPath = prefix + client.relPath;
405 auto offsetIter = client.implOptions.find(
"offset");
406 if (offsetIter == client.implOptions.end()) {
407 conn.getLogger().warning(
"Telemetry",
408 "mmio client " + fullClientPath.
toStr() +
409 " missing 'offset' option, skipping");
412 const Constant *offset = std::any_cast<Constant>(&offsetIter->second);
413 if (offset ==
nullptr) {
414 conn.getLogger().warning(
415 "Telemetry",
"mmio client " + fullClientPath.
toStr() +
416 " 'offset' option must be a constant, skipping");
419 const uint64_t *offsetVal = std::any_cast<uint64_t>(&offset->
value);
420 if (offsetVal ==
nullptr) {
421 conn.getLogger().warning(
422 "Telemetry",
"mmio client " + fullClientPath.
toStr() +
423 " 'offset' option must be an integer, skipping");
439 mmioPath.push_back(
AppID(
"__telemetry_mmio"));
440 auto port =
conn.getAccelerator().resolvePort(mmioPath, lastPath);
442 throw std::runtime_error(
"TelemetryService: could not resolve port " +
443 id.toStr() +
". Got as far as " +
447 throw std::runtime_error(
"TelemetryService: port " +
id.toStr() +
448 " is not a MMIO region");
456 auto *port =
new Metric(
id.back(), type, {},
this,
458 ? std::optional<uint64_t>(offsetIter->second)
465 std::string implName,
476 std::optional<uint64_t>
offset)
483 throw std::runtime_error(
"Telemetry offset not found for " +
id.
toString());
485 assert(
mmio &&
"TelemetryService: MMIO region not found");
489 return std::async(std::launch::async, [
this]() {
497 "Telemetry offset must be set. Checked in connect().");
498 assert(
mmio &&
"TelemetryService: MMIO region not set");
504 ports[entry.first] = entry.second;
506 child->getTelemetryPorts(ports);
511 std::string implName,
516 return new FuncService(
id, *acc, details, clients);
530 if (svcName ==
"esi.service.std.func")
532 if (svcName ==
"esi.service.std.call")
534 if (svcName ==
"esi.service.std.channel")
assert(baseType &&"element must be base type")
constexpr uint32_t MAX_MANIFEST_SIZE
Abstract class representing a connection to an accelerator.
std::string toStr() const
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
ReadChannelPort & getRawRead(const std::string &name) const
WriteChannelPort & getRawWrite(const std::string &name) const
Get access to the raw byte streams of a channel.
Bundles represent a collection of channels.
std::pair< const Type *, Direction > findChannel(std::string name) const
A concrete flat message backed by a single vector of bytes.
static MessageData from(T &t)
Cast from a type to its raw bytes.
A ChannelPort which reads data from the accelerator.
A ChannelPort which sends data to the accelerator.
A function call which gets attached to a service port.
static Callback * get(AcceleratorConnection &acc, AppID id, const BundleType *type, WriteChannelPort &result, ReadChannelPort &arg)
WriteChannelPort * result
Callback(AcceleratorConnection &acc, AppID id, const BundleType *, PortMap channels)
AcceleratorConnection & acc
void connect(std::function< MessageData(const MessageData &)> callback, bool quick=false, const ChannelPort::ConnectOptions &options={})
Connect a callback to code which will be executed when the accelerator invokes the callback.
Service for servicing function calls from the accelerator.
virtual std::string getServiceSymbol() const override
CallService(AcceleratorConnection &acc, AppIDPath id, ServiceImplDetails details)
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get specialized port for this service to attach to the given appid path.
A port which writes data to the accelerator (from_host).
WriteChannelPort * dataPort
static FromHost * get(AppID id, const BundleType *type, WriteChannelPort &dataPort)
void write(const MessageData &data)
A port which reads data from the accelerator (to_host).
std::future< MessageData > read()
static ToHost * get(AppID id, const BundleType *type, ReadChannelPort &dataPort)
ReadChannelPort * dataPort
Service for raw communication channels to/from the accelerator.
virtual std::string getServiceSymbol() const override
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get specialized port for this service to attach to the given appid path.
ChannelService(AppIDPath id, AcceleratorConnection &, ServiceImplDetails details, HWClientDetails clients)
A service for which there are no standard services registered.
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get specialized port for this service to attach to the given appid path.
CustomService(AppIDPath idPath, AcceleratorConnection &, const ServiceImplDetails &details, const HWClientDetails &clients)
A function call which gets attached to a service port.
std::future< MessageData > call(const MessageData &arg)
static Function * get(AppID id, BundleType *type, WriteChannelPort &arg, ReadChannelPort &result)
void connect(const ChannelPort::ConnectOptions &options={})
Service for calling functions.
virtual std::string getServiceSymbol() const override
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get specialized port for this service to attach to the given appid path.
FuncService(AppIDPath id, AcceleratorConnection &, ServiceImplDetails details, HWClientDetails clients)
virtual std::string getServiceSymbol() const override
static constexpr std::string_view StdName
std::optional< uint64_t > getCycleCount() const override
Get the current cycle count of the accelerator system's core clock.
virtual std::vector< uint8_t > getCompressedManifest() const override
Return the zlib compressed JSON system manifest.
std::optional< uint64_t > getCoreClockFrequency() const override
Get the "core" clock frequency of the accelerator system in Hz.
uint32_t getEsiVersion() const override
Get the ESI version number to check version compatibility.
MMIOSysInfo(const MMIO *)
A "slice" of some parent MMIO space.
virtual uint64_t read(uint32_t addr) const
Read a 64-bit value from this region, not the global address space.
MMIORegion(AppID id, MMIO *parent, RegionDescriptor desc)
virtual void write(uint32_t addr, uint64_t data)
Write a 64-bit value to this region, not the global address space.
MMIO(AcceleratorConnection &, const AppIDPath &idPath, const HWClientDetails &clients)
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get a MMIO region port for a particular region descriptor.
std::map< AppIDPath, RegionDescriptor > regions
MMIO base address table.
static constexpr std::string_view StdName
virtual Service * getChildService(Service::Type service, AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={}) override
If the service is a MMIO service, return a region of the MMIO space which peers into ours.
virtual std::string getServiceSymbol() const override
Add a custom interface to a service client at a particular point in the design hierarchy.
static Service::Type lookupServiceType(const std::string &)
Resolve a service type from a string.
static Service * createService(AcceleratorConnection *acc, Service::Type svcType, AppIDPath id, std::string implName, ServiceImplDetails details, HWClientDetails clients)
Create a service instance from the given details.
Parent class of all APIs modeled as 'services'.
AcceleratorConnection & getConnection() const
const std::type_info & Type
virtual Service * getChildService(Service::Type service, AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Create a "child" service of this service.
Service(AcceleratorConnection &conn)
AcceleratorConnection & conn
Information about the Accelerator system.
virtual std::string getJsonManifest() const
Return the JSON-formatted system manifest.
virtual std::vector< uint8_t > getCompressedManifest() const =0
Return the zlib compressed JSON system manifest.
virtual std::string getServiceSymbol() const override
A telemetry port which gets attached to a service port.
std::optional< uint64_t > offset
friend class TelemetryService
void connect()
Connect to a particular telemetry port. Offset should be non-nullopt.
std::future< MessageData > read()
Metric(AppID id, const BundleType *type, PortMap channels, const TelemetryService *telemetryService, std::optional< uint64_t > offset)
const TelemetryService * telemetryService
Service for retrieving telemetry data from the accelerator.
std::list< TelemetryService * > children
std::map< AppIDPath, Metric * > getTelemetryPorts()
MMIO::MMIORegion * getMMIORegion() const
std::map< AppIDPath, Metric * > telemetryPorts
std::map< AppIDPath, uint64_t > portAddressAssignments
static constexpr std::string_view StdName
TelemetryService(AppIDPath id, AcceleratorConnection &, ServiceImplDetails details, HWClientDetails clients)
virtual std::string getServiceSymbol() const override
virtual BundlePort * getPort(AppIDPath id, const BundleType *type) const override
Get specialized port for this service to attach to the given appid path.
virtual Service * getChildService(Service::Type service, AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={}) override
Create a "child" service of this service.
std::string toString(const std::any &a)
'Stringify' a std::any. This is used to log std::any values by some loggers.
constexpr uint32_t CoreFreqOffset
constexpr uint64_t MagicNumber
std::string toHex(void *val)
std::map< std::string, ChannelPort & > PortMap
std::vector< HWClientDetail > HWClientDetails
constexpr uint32_t ExpectedVersionNumber
Keep in sync with circt::esi::esiApiVersion and the PyCDE BSP.
constexpr uint64_t MagicNumberOffset
constexpr uint32_t MetadataOffset
std::map< std::string, std::any > ServiceImplDetails
constexpr uint32_t CycleCountOffset
constexpr uint32_t ManifestPtrOffset
constexpr uint64_t VersionNumberOffset
A description of a hardware client.
virtual std::size_t getSize() const =0
virtual void * getPtr() const =0
Get a pointer to the host memory.
std::optional< uint64_t > getDeviceAddress(const void *ptr, std::size_t size) const
Device address of the host range [ptr, ptr + size) if that range lies entirely inside this region; st...
virtual void * getDevicePtr() const
Sometimes the pointer the device sees is different from the pointer the host sees.
Describe a region (slice) of MMIO space.