CIRCT 20.0.0git
Loading...
Searching...
No Matches
Cosim.cpp
Go to the documentation of this file.
1//===- Cosim.cpp - Connection to ESI simulation via GRPC ------------------===//
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/Cosim.h"
17#include "esi/Services.h"
18#include "esi/Utils.h"
19
20#include "cosim.grpc.pb.h"
21
22#include <grpc/grpc.h>
23#include <grpcpp/channel.h>
24#include <grpcpp/client_context.h>
25#include <grpcpp/create_channel.h>
26#include <grpcpp/security/credentials.h>
27
28#include <fstream>
29#include <iostream>
30#include <set>
31
32using namespace esi;
33using namespace esi::cosim;
34using namespace esi::services;
35using namespace esi::backends::cosim;
36
37using grpc::Channel;
38using grpc::ClientContext;
39using grpc::ClientReader;
40using grpc::ClientReaderWriter;
41using grpc::ClientWriter;
42using grpc::Status;
43
44static void checkStatus(Status s, const std::string &msg) {
45 if (!s.ok())
46 throw std::runtime_error(msg + ". Code " + to_string(s.error_code()) +
47 ": " + s.error_message() + " (" +
48 s.error_details() + ")");
49}
50
51/// Hack around C++ not having a way to forward declare a nested class.
53 StubContainer(std::unique_ptr<ChannelServer::Stub> stub)
54 : stub(std::move(stub)) {}
55 std::unique_ptr<ChannelServer::Stub> stub;
56
57 /// Get the type ID for a channel name.
58 bool getChannelDesc(const std::string &channelName,
59 esi::cosim::ChannelDesc &desc);
60};
62
63/// Parse the connection std::string and instantiate the accelerator. Support
64/// the traditional 'host:port' syntax and a path to 'cosim.cfg' which is output
65/// by the cosimulation when it starts (which is useful when it chooses its own
66/// port).
67std::unique_ptr<AcceleratorConnection>
68CosimAccelerator::connect(Context &ctxt, std::string connectionString) {
69 std::string portStr;
70 std::string host = "localhost";
71
72 size_t colon;
73 if ((colon = connectionString.find(':')) != std::string::npos) {
74 portStr = connectionString.substr(colon + 1);
75 host = connectionString.substr(0, colon);
76 } else if (connectionString.ends_with("cosim.cfg")) {
77 std::ifstream cfg(connectionString);
78 std::string line, key, value;
79
80 while (getline(cfg, line))
81 if ((colon = line.find(":")) != std::string::npos) {
82 key = line.substr(0, colon);
83 value = line.substr(colon + 1);
84 if (key == "port")
85 portStr = value;
86 else if (key == "host")
87 host = value;
88 }
89
90 if (portStr.size() == 0)
91 throw std::runtime_error("port line not found in file");
92 } else if (connectionString == "env") {
93 char *hostEnv = getenv("ESI_COSIM_HOST");
94 if (hostEnv)
95 host = hostEnv;
96 else
97 host = "localhost";
98 char *portEnv = getenv("ESI_COSIM_PORT");
99 if (portEnv)
100 portStr = portEnv;
101 else
102 throw std::runtime_error("ESI_COSIM_PORT environment variable not set");
103 } else {
104 throw std::runtime_error("Invalid connection std::string '" +
105 connectionString + "'");
106 }
107 uint16_t port = stoul(portStr);
108 auto conn = make_unique<CosimAccelerator>(ctxt, host, port);
109
110 // Using the MMIO manifest method is really only for internal debugging, so it
111 // doesn't need to be part of the connection string.
112 char *manifestMethod = getenv("ESI_COSIM_MANIFEST_MMIO");
113 if (manifestMethod != nullptr)
114 conn->setManifestMethod(ManifestMethod::MMIO);
115
116 return conn;
117}
118
119/// Construct and connect to a cosim server.
120CosimAccelerator::CosimAccelerator(Context &ctxt, std::string hostname,
121 uint16_t port)
122 : AcceleratorConnection(ctxt) {
123 // Connect to the simulation.
124 auto channel = grpc::CreateChannel(hostname + ":" + std::to_string(port),
125 grpc::InsecureChannelCredentials());
126 rpcClient = new StubContainer(ChannelServer::NewStub(channel));
127}
129 disconnect();
130 if (rpcClient)
131 delete rpcClient;
132 channels.clear();
133}
134
135namespace {
136class CosimSysInfo : public SysInfo {
137public:
138 CosimSysInfo(ChannelServer::Stub *rpcClient) : rpcClient(rpcClient) {}
139
140 uint32_t getEsiVersion() const override {
141 ::esi::cosim::Manifest response = getManifest();
142 return response.esi_version();
143 }
144
145 std::vector<uint8_t> getCompressedManifest() const override {
146 ::esi::cosim::Manifest response = getManifest();
147 std::string compressedManifestStr = response.compressed_manifest();
148 return std::vector<uint8_t>(compressedManifestStr.begin(),
149 compressedManifestStr.end());
150 }
151
152private:
153 ::esi::cosim::Manifest getManifest() const {
154 ::esi::cosim::Manifest response;
155 // To get around the a race condition where the manifest may not be set yet,
156 // loop until it is. TODO: fix this with the DPI API change.
157 do {
158 ClientContext context;
159 VoidMessage arg;
160 Status s = rpcClient->GetManifest(&context, arg, &response);
161 checkStatus(s, "Failed to get manifest");
162 std::this_thread::sleep_for(std::chrono::milliseconds(10));
163 } while (response.esi_version() < 0);
164 return response;
165 }
166
167 esi::cosim::ChannelServer::Stub *rpcClient;
168};
169} // namespace
170
171namespace {
172/// Cosim client implementation of a write channel port.
173class WriteCosimChannelPort : public WriteChannelPort {
174public:
175 WriteCosimChannelPort(ChannelServer::Stub *rpcClient, const ChannelDesc &desc,
176 const Type *type, std::string name)
177 : WriteChannelPort(type), rpcClient(rpcClient), desc(desc), name(name) {}
178 ~WriteCosimChannelPort() = default;
179
180 void connectImpl(std::optional<unsigned> bufferSize) override {
181 if (desc.type() != getType()->getID())
182 throw std::runtime_error("Channel '" + name +
183 "' has wrong type. Expected " +
184 getType()->getID() + ", got " + desc.type());
185 if (desc.dir() != ChannelDesc::Direction::ChannelDesc_Direction_TO_SERVER)
186 throw std::runtime_error("Channel '" + name +
187 "' is not a to server channel");
188 assert(desc.name() == name);
189 }
190
191 /// Send a write message to the server.
192 void write(const MessageData &data) override {
193 ClientContext context;
194 AddressedMessage msg;
195 msg.set_channel_name(name);
196 msg.mutable_message()->set_data(data.getBytes(), data.getSize());
197 VoidMessage response;
198 grpc::Status sendStatus = rpcClient->SendToServer(&context, msg, &response);
199 if (!sendStatus.ok())
200 throw std::runtime_error("Failed to write to channel '" + name +
201 "': " + std::to_string(sendStatus.error_code()) +
202 " " + sendStatus.error_message() +
203 ". Details: " + sendStatus.error_details());
204 }
205
206 bool tryWrite(const MessageData &data) override {
207 write(data);
208 return true;
209 }
210
211protected:
212 ChannelServer::Stub *rpcClient;
213 /// The channel description as provided by the server.
214 ChannelDesc desc;
215 /// The name of the channel from the manifest.
216 std::string name;
217};
218} // namespace
219
220namespace {
221/// Cosim client implementation of a read channel port. Since gRPC read protocol
222/// streams messages back, this implementation is quite complex.
223class ReadCosimChannelPort
224 : public ReadChannelPort,
225 public grpc::ClientReadReactor<esi::cosim::Message> {
226public:
227 ReadCosimChannelPort(ChannelServer::Stub *rpcClient, const ChannelDesc &desc,
228 const Type *type, std::string name)
229 : ReadChannelPort(type), rpcClient(rpcClient), desc(desc), name(name),
230 context(nullptr) {}
231 virtual ~ReadCosimChannelPort() { disconnect(); }
232
233 void connectImpl(std::optional<unsigned> bufferSize) override {
234 // Sanity checking.
235 if (desc.type() != getType()->getID())
236 throw std::runtime_error("Channel '" + name +
237 "' has wrong type. Expected " +
238 getType()->getID() + ", got " + desc.type());
239 if (desc.dir() != ChannelDesc::Direction::ChannelDesc_Direction_TO_CLIENT)
240 throw std::runtime_error("Channel '" + name +
241 "' is not a to client channel");
242 assert(desc.name() == name);
243
244 // Initiate a stream of messages from the server.
245 context = std::make_unique<ClientContext>();
246 rpcClient->async()->ConnectToClientChannel(context.get(), &desc, this);
247 StartCall();
248 StartRead(&incomingMessage);
249 }
250
251 /// Gets called when there's a new message from the server. It'll be stored in
252 /// `incomingMessage`.
253 void OnReadDone(bool ok) override {
254 if (!ok)
255 // This happens when we are disconnecting since we are canceling the call.
256 return;
257
258 // Read the delivered message and push it onto the queue.
259 const std::string &messageString = incomingMessage.data();
260 MessageData data(reinterpret_cast<const uint8_t *>(messageString.data()),
261 messageString.size());
262 while (!callback(data))
263 // Blocking here could cause deadlocks in specific situations.
264 // TODO: Implement a way to handle this better.
265 std::this_thread::sleep_for(std::chrono::milliseconds(10));
266
267 // Initiate the next read.
268 StartRead(&incomingMessage);
269 }
270
271 /// Disconnect this channel from the server.
272 void disconnect() override {
273 if (!context)
274 return;
275 context->TryCancel();
276 context.reset();
278 }
279
280protected:
281 ChannelServer::Stub *rpcClient;
282 /// The channel description as provided by the server.
283 ChannelDesc desc;
284 /// The name of the channel from the manifest.
285 std::string name;
286
287 std::unique_ptr<ClientContext> context;
288 /// Storage location for the incoming message.
289 esi::cosim::Message incomingMessage;
290};
291
292} // namespace
293
294std::map<std::string, ChannelPort &> CosimAccelerator::requestChannelsFor(
295 AppIDPath idPath, const BundleType *bundleType, const ServiceTable &) {
296 std::map<std::string, ChannelPort &> channelResults;
297
298 // Find the client details for the port at 'fullPath'.
299 auto f = clientChannelAssignments.find(idPath);
300 if (f == clientChannelAssignments.end())
301 return channelResults;
302 const std::map<std::string, std::string> &channelAssignments = f->second;
303
304 // Each channel in a bundle has a separate cosim endpoint. Find them all.
305 for (auto [name, dir, type] : bundleType->getChannels()) {
306 auto f = channelAssignments.find(name);
307 if (f == channelAssignments.end())
308 throw std::runtime_error("Could not find channel assignment for '" +
309 idPath.toStr() + "." + name + "'");
310 std::string channelName = f->second;
311
312 // Get the endpoint, which may or may not exist. Construct the port.
313 // Everything is validated when the client calls 'connect()' on the port.
314 ChannelDesc chDesc;
315 if (!rpcClient->getChannelDesc(channelName, chDesc))
316 throw std::runtime_error("Could not find channel '" + channelName +
317 "' in cosimulation");
318
319 ChannelPort *port;
320 if (BundlePort::isWrite(dir)) {
321 port = new WriteCosimChannelPort(rpcClient->stub.get(), chDesc, type,
322 channelName);
323 } else {
324 port = new ReadCosimChannelPort(rpcClient->stub.get(), chDesc, type,
325 channelName);
326 }
327 channels.emplace(port);
328 channelResults.emplace(name, *port);
329 }
330 return channelResults;
331}
332
333/// Get the channel description for a channel name. Iterate through the list
334/// each time. Since this will only be called a small number of times on a small
335/// list, it's not worth doing anything fancy.
336bool StubContainer::getChannelDesc(const std::string &channelName,
337 ChannelDesc &desc) {
338 ClientContext context;
339 VoidMessage arg;
340 ListOfChannels response;
341 Status s = stub->ListChannels(&context, arg, &response);
342 checkStatus(s, "Failed to list channels");
343 for (const auto &channel : response.channels())
344 if (channel.name() == channelName) {
345 desc = channel;
346 return true;
347 }
348 return false;
349}
350
351namespace {
352class CosimMMIO : public MMIO {
353public:
354 CosimMMIO(Context &ctxt, StubContainer *rpcClient) {
355 // We have to locate the channels ourselves since this service might be used
356 // to retrieve the manifest.
357 ChannelDesc cmdArg, cmdResp;
358 if (!rpcClient->getChannelDesc("__cosim_mmio_read_write.arg", cmdArg) ||
359 !rpcClient->getChannelDesc("__cosim_mmio_read_write.result", cmdResp))
360 throw std::runtime_error("Could not find MMIO channels");
361
362 const esi::Type *i64Type = getType(ctxt, new UIntType(cmdResp.type(), 64));
363 const esi::Type *cmdType =
364 getType(ctxt, new StructType(cmdArg.type(),
365 {{"write", new BitsType("i1", 1)},
366 {"offset", new UIntType("ui32", 32)},
367 {"data", new BitsType("i64", 64)}}));
368
369 // Get ports, create the function, then connect to it.
370 cmdArgPort = std::make_unique<WriteCosimChannelPort>(
371 rpcClient->stub.get(), cmdArg, cmdType, "__cosim_mmio_read_write.arg");
372 cmdRespPort = std::make_unique<ReadCosimChannelPort>(
373 rpcClient->stub.get(), cmdResp, i64Type,
374 "__cosim_mmio_read_write.result");
375 cmdMMIO.reset(FuncService::Function::get(AppID("__cosim_mmio"), *cmdArgPort,
376 *cmdRespPort));
377 cmdMMIO->connect();
378 }
379
380#pragma pack(push, 1)
381 struct MMIOCmd {
382 uint64_t data;
383 uint32_t offset;
384 bool write;
385 };
386#pragma pack(pop)
387
388 // Call the read function and wait for a response.
389 uint64_t read(uint32_t addr) const override {
390 MMIOCmd cmd{.offset = addr, .write = false};
391 auto arg = MessageData::from(cmd);
392 std::future<MessageData> result = cmdMMIO->call(arg);
393 result.wait();
394 return *result.get().as<uint64_t>();
395 }
396
397 void write(uint32_t addr, uint64_t data) override {
398 MMIOCmd cmd{.data = data, .offset = addr, .write = true};
399 auto arg = MessageData::from(cmd);
400 std::future<MessageData> result = cmdMMIO->call(arg);
401 result.wait();
402 }
403
404private:
405 const esi::Type *getType(Context &ctxt, esi::Type *type) {
406 if (auto t = ctxt.getType(type->getID())) {
407 delete type;
408 return *t;
409 }
410 ctxt.registerType(type);
411 return type;
412 }
413 std::unique_ptr<WriteCosimChannelPort> cmdArgPort;
414 std::unique_ptr<ReadCosimChannelPort> cmdRespPort;
415 std::unique_ptr<FuncService::Function> cmdMMIO;
416};
417
418#pragma pack(push, 1)
419struct HostMemReadReq {
420 uint8_t tag;
421 uint32_t length;
422 uint64_t address;
423};
424
425struct HostMemReadResp {
426 uint64_t data;
427 uint8_t tag;
428};
429
430struct HostMemWriteReq {
431 uint64_t data;
432 uint8_t tag;
433 uint64_t address;
434};
435
436using HostMemWriteResp = uint8_t;
437#pragma pack(pop)
438
439class CosimHostMem : public HostMem {
440public:
441 CosimHostMem(AcceleratorConnection &acc, Context &ctxt,
442 StubContainer *rpcClient)
443 : acc(acc), ctxt(ctxt), rpcClient(rpcClient) {}
444
445 void start() override {
446 // We have to locate the channels ourselves since this service might be used
447 // to retrieve the manifest.
448
449 // TODO: The types here are WRONG. They need to be wrapped in Channels! Fix
450 // this in a subsequent PR.
451
452 // Setup the read side callback.
453 ChannelDesc readArg, readResp;
454 if (!rpcClient->getChannelDesc("__cosim_hostmem_read_req.data", readArg) ||
455 !rpcClient->getChannelDesc("__cosim_hostmem_read_resp.data", readResp))
456 throw std::runtime_error("Could not find HostMem read channels");
457
458 const esi::Type *readRespType =
459 getType(ctxt, new StructType(readResp.type(),
460 {{"tag", new UIntType("ui8", 8)},
461 {"data", new BitsType("i64", 64)}}));
462 const esi::Type *readReqType =
463 getType(ctxt, new StructType(readArg.type(),
464 {{"address", new UIntType("ui64", 64)},
465 {"length", new UIntType("ui32", 32)},
466 {"tag", new UIntType("ui8", 8)}}));
467
468 // Get ports. Unfortunately, we can't model this as a callback since there
469 // will sometimes be multiple responses per request.
470 readRespPort = std::make_unique<WriteCosimChannelPort>(
471 rpcClient->stub.get(), readResp, readRespType,
472 "__cosim_hostmem_read_resp.data");
473 readReqPort = std::make_unique<ReadCosimChannelPort>(
474 rpcClient->stub.get(), readArg, readReqType,
475 "__cosim_hostmem_read_req.data");
476 readReqPort->connect(
477 [this](const MessageData &req) { return serviceRead(req); });
478
479 // Setup the write side callback.
480 ChannelDesc writeArg, writeResp;
481 if (!rpcClient->getChannelDesc("__cosim_hostmem_write.arg", writeArg) ||
482 !rpcClient->getChannelDesc("__cosim_hostmem_write.result", writeResp))
483 throw std::runtime_error("Could not find HostMem write channels");
484
485 const esi::Type *writeRespType =
486 getType(ctxt, new UIntType(writeResp.type(), 8));
487 const esi::Type *writeReqType =
488 getType(ctxt, new StructType(writeArg.type(),
489 {{"address", new UIntType("ui64", 64)},
490 {"tag", new UIntType("ui8", 8)},
491 {"data", new BitsType("i64", 64)}}));
492
493 // Get ports, create the function, then connect to it.
494 writeRespPort = std::make_unique<WriteCosimChannelPort>(
495 rpcClient->stub.get(), writeResp, writeRespType,
496 "__cosim_hostmem_write.result");
497 writeReqPort = std::make_unique<ReadCosimChannelPort>(
498 rpcClient->stub.get(), writeArg, writeReqType,
499 "__cosim_hostmem_write.arg");
500 write.reset(CallService::Callback::get(acc, AppID("__cosim_hostmem_write"),
501 *writeRespPort, *writeReqPort));
502 write->connect([this](const MessageData &req) { return serviceWrite(req); },
503 true);
504 }
505
506 // Service the read request as a callback. Simply reads the data from the
507 // location specified. TODO: check that the memory has been mapped.
508 bool serviceRead(const MessageData &reqBytes) {
509 const HostMemReadReq *req = reqBytes.as<HostMemReadReq>();
510 acc.getLogger().debug(
511 [&](std::string &subsystem, std::string &msg,
512 std::unique_ptr<std::map<std::string, std::any>> &details) {
513 subsystem = "HostMem";
514 msg = "Read request: addr=0x" + toHex(req->address) +
515 " len=" + std::to_string(req->length) +
516 " tag=" + std::to_string(req->tag);
517 });
518 // Send one response per 8 bytes.
519 uint64_t *dataPtr = reinterpret_cast<uint64_t *>(req->address);
520 for (uint32_t i = 0, e = (req->length + 7) / 8; i < e; ++i) {
521 HostMemReadResp resp{.data = dataPtr[i], .tag = req->tag};
522 acc.getLogger().debug(
523 [&](std::string &subsystem, std::string &msg,
524 std::unique_ptr<std::map<std::string, std::any>> &details) {
525 subsystem = "HostMem";
526 msg = "Read result: data=0x" + toHex(resp.data) +
527 " tag=" + std::to_string(resp.tag);
528 });
529 readRespPort->write(MessageData::from(resp));
530 }
531 return true;
532 }
533
534 // Service a write request as a callback. Simply write the data to the
535 // location specified. TODO: check that the memory has been mapped.
536 MessageData serviceWrite(const MessageData &reqBytes) {
537 const HostMemWriteReq *req = reqBytes.as<HostMemWriteReq>();
538 acc.getLogger().debug(
539 [&](std::string &subsystem, std::string &msg,
540 std::unique_ptr<std::map<std::string, std::any>> &details) {
541 subsystem = "HostMem";
542 msg = "Write request: addr=0x" + toHex(req->address) + " data=0x" +
543 toHex(req->data) + " tag=" + std::to_string(req->tag);
544 });
545 uint64_t *dataPtr = reinterpret_cast<uint64_t *>(req->address);
546 *dataPtr = req->data;
547 HostMemWriteResp resp = req->tag;
548 return MessageData::from(resp);
549 }
550
551 struct CosimHostMemRegion : public HostMemRegion {
552 CosimHostMemRegion(std::size_t size) {
553 ptr = malloc(size);
554 this->size = size;
555 }
556 virtual ~CosimHostMemRegion() { free(ptr); }
557 virtual void *getPtr() const override { return ptr; }
558 virtual std::size_t getSize() const override { return size; }
559
560 private:
561 void *ptr;
562 std::size_t size;
563 };
564
565 virtual std::unique_ptr<HostMemRegion>
566 allocate(std::size_t size, HostMem::Options opts) const override {
567 return std::unique_ptr<HostMemRegion>(new CosimHostMemRegion(size));
568 }
569 virtual bool mapMemory(void *ptr, std::size_t size,
570 HostMem::Options opts) const override {
571 return true;
572 }
573 virtual void unmapMemory(void *ptr) const override {}
574
575private:
576 const esi::Type *getType(Context &ctxt, esi::Type *type) {
577 if (auto t = ctxt.getType(type->getID())) {
578 delete type;
579 return *t;
580 }
581 ctxt.registerType(type);
582 return type;
583 }
585 Context &ctxt;
586 StubContainer *rpcClient;
587 std::unique_ptr<WriteCosimChannelPort> readRespPort;
588 std::unique_ptr<ReadCosimChannelPort> readReqPort;
589 std::unique_ptr<CallService::Callback> read;
590 std::unique_ptr<WriteCosimChannelPort> writeRespPort;
591 std::unique_ptr<ReadCosimChannelPort> writeReqPort;
592 std::unique_ptr<CallService::Callback> write;
593};
594
595} // namespace
596
598 AppIDPath idPath, std::string implName,
599 const ServiceImplDetails &details,
600 const HWClientDetails &clients) {
601 // Compute our parents idPath path.
602 AppIDPath prefix = std::move(idPath);
603 if (prefix.size() > 0)
604 prefix.pop_back();
605
606 // Get the channel assignments for each client.
607 for (auto client : clients) {
608 AppIDPath fullClientPath = prefix + client.relPath;
609 std::map<std::string, std::string> channelAssignments;
610 for (auto assignment : client.channelAssignments)
611 if (assignment.second.type == "cosim")
612 channelAssignments[assignment.first] = std::any_cast<std::string>(
613 assignment.second.implOptions.at("name"));
614 clientChannelAssignments[fullClientPath] = std::move(channelAssignments);
615 }
616
617 if (svcType == typeid(services::MMIO)) {
618 return new CosimMMIO(getCtxt(), rpcClient);
619 } else if (svcType == typeid(services::HostMem)) {
620 return new CosimHostMem(*this, getCtxt(), rpcClient);
621 } else if (svcType == typeid(SysInfo)) {
622 switch (manifestMethod) {
624 return new CosimSysInfo(rpcClient->stub.get());
626 return new MMIOSysInfo(getService<services::MMIO>());
627 }
628 } else if (svcType == typeid(CustomService) && implName == "cosim") {
629 return new CustomService(idPath, details, clients);
630 }
631 return nullptr;
632}
633
637
#define REGISTER_ACCELERATOR(Name, TAccelerator)
assert(baseType &&"element must be base type")
static void checkStatus(Status s, const std::string &msg)
Definition Cosim.cpp:44
Abstract class representing a connection to an accelerator.
Definition Accelerator.h:78
virtual void disconnect()
Disconnect from the accelerator cleanly.
Context & getCtxt() const
Definition Accelerator.h:82
std::map< std::string, services::Service * > ServiceTable
Definition Accelerator.h:93
Context & ctxt
ESI accelerator context.
std::string toStr() const
Definition Manifest.cpp:708
static bool isWrite(BundleType::Direction bundleDir)
Compute the direction of a channel given the bundle direction and the bundle port's direction.
Definition Ports.h:188
Bundles represent a collection of channels.
Definition Types.h:44
const ChannelVector & getChannels() const
Definition Types.h:54
Unidirectional channels are the basic communication primitive between the host and accelerator.
Definition Ports.h:33
AcceleratorConnections, Accelerators, and Manifests must all share a context.
Definition Context.h:31
A logical chunk of data representing serialized data.
Definition Common.h:103
const T * as() const
Cast to a type.
Definition Common.h:119
static MessageData from(T &t)
Cast from a type to its raw bytes.
Definition Common.h:129
A ChannelPort which reads data from the accelerator.
Definition Ports.h:103
virtual void disconnect() override
Definition Ports.h:108
Structs are an ordered collection of fields, each with a name and a type.
Definition Types.h:130
Root class of the ESI type system.
Definition Types.h:27
ID getID() const
Definition Types.h:33
Unsigned integer.
Definition Types.h:124
A ChannelPort which sends data to the accelerator.
Definition Ports.h:74
Connect to an ESI simulation.
Definition Cosim.h:37
std::map< AppIDPath, std::map< std::string, std::string > > clientChannelAssignments
Definition Cosim.h:79
void setManifestMethod(ManifestMethod method)
Definition Cosim.cpp:634
static std::unique_ptr< AcceleratorConnection > connect(Context &, std::string connectionString)
Parse the connection std::string and instantiate the accelerator.
Definition Cosim.cpp:68
virtual Service * createService(Service::Type service, AppIDPath path, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients) override
Called by getServiceImpl exclusively.
Definition Cosim.cpp:597
CosimAccelerator(Context &, std::string hostname, uint16_t port)
Construct and connect to a cosim server.
Definition Cosim.cpp:120
std::set< std::unique_ptr< ChannelPort > > channels
Definition Cosim.h:76
virtual std::map< std::string, ChannelPort & > requestChannelsFor(AppIDPath, const BundleType *, const ServiceTable &) override
Request the host side channel ports for a particular instance (identified by the AppID path).
Definition Cosim.cpp:294
static Callback * get(AcceleratorConnection &acc, AppID id, WriteChannelPort &result, ReadChannelPort &arg)
Definition Services.cpp:264
A service for which there are no standard services registered.
Definition Services.h:77
static Function * get(AppID id, WriteChannelPort &arg, ReadChannelPort &result)
Definition Services.cpp:204
Implement the SysInfo API for a standard MMIO protocol.
Definition Services.h:180
Parent class of all APIs modeled as 'services'.
Definition Services.h:45
const std::type_info & Type
Definition Services.h:47
Information about the Accelerator system.
Definition Services.h:93
Definition esi.py:1
std::map< std::string, std::any > ServiceImplDetails
Definition Common.h:98
std::string toHex(uint32_t val)
Definition Common.cpp:37
std::vector< HWClientDetail > HWClientDetails
Definition Common.h:97
Hack around C++ not having a way to forward declare a nested class.
Definition Cosim.cpp:52
std::unique_ptr< ChannelServer::Stub > stub
Definition Cosim.cpp:55
bool getChannelDesc(const std::string &channelName, esi::cosim::ChannelDesc &desc)
Get the type ID for a channel name.
Definition Cosim.cpp:336
StubContainer(std::unique_ptr< ChannelServer::Stub > stub)
Definition Cosim.cpp:53
Options for allocating host memory.
Definition Services.h:209