30#include <initializer_list>
57 WriteCosimChannelPort(
58 AcceleratorConnection &conn, RpcClient &client,
59 const RpcClient::ChannelDesc &desc,
const Type *type, std::string name,
61 : WriteChannelPort(type), conn(conn), client(client), desc(desc),
62 name(std::move(name)), defaultMaxInFlight(defaultMaxInFlight) {}
63 ~WriteCosimChannelPort() =
default;
65 void connectImpl(
const ChannelPort::ConnectOptions &options)
override {
66 if (desc.dir != RpcClient::ChannelDirection::ToServer)
67 throw std::runtime_error(
"Channel '" + name +
68 "' is not a to server channel");
69 client.setToServerMaxInFlight(
70 name, options.
bufferSize.value_or(defaultMaxInFlight));
74 void traceWrite(
const MessageData &data) {
75 conn.getLogger().trace(
77 &data](std::string &subsystem, std::string &msg,
78 std::unique_ptr<std::map<std::string, std::any>> &details) {
79 subsystem =
"cosim_write";
80 msg =
"Writing message to channel '" + name +
"'";
81 details = std::make_unique<std::map<std::string, std::any>>();
82 (*details)[
"channel"] = name;
83 (*details)[
"data_size"] =
data.getSize();
84 (*details)[
"message_data"] =
data.toHex();
88 void writeImpl(
const MessageData &data)
override {
89 auto frames = getMessageFrames(data);
90 for (
const auto &frame : frames) {
92 client.writeToServer(name, frame);
95 bool tryWriteImpl(
const MessageData &data)
override {
96 auto frames = getMessageFrames(data);
100 bool rest = translateMessages && translationBufferIdx > 0;
101 if (!client.tryWriteToServer(name, frames, rest))
103 for (
size_t i = 0; i < frames.size(); ++i)
109 AcceleratorConnection &conn;
111 RpcClient::ChannelDesc desc;
113 unsigned defaultMaxInFlight;
125 ReadCosimChannelPort(AcceleratorConnection &conn, RpcClient &client,
126 const RpcClient::ChannelDesc &desc,
const Type *type,
128 : ReadChannelPort(type), conn(conn), client(client), desc(desc),
129 name(std::move(name)) {}
131 ~ReadCosimChannelPort() =
default;
133 void connectImpl(
const ChannelPort::ConnectOptions &options)
override {
134 if (desc.dir != RpcClient::ChannelDirection::ToClient)
135 throw std::runtime_error(
"Channel '" + name +
136 "' is not a to client channel");
139 connection = client.connectClientReceiver(
141 [
this](std::unique_ptr<SegmentedMessageData> &data) {
143 conn.getLogger().trace(
145 std::string &subsystem, std::string &msg,
146 std::unique_ptr<std::map<std::string, std::any>> &details) {
147 subsystem =
"cosim_read";
148 msg =
"Received message from channel '" + name +
"'";
149 details = std::make_unique<std::map<std::string, std::any>>();
150 MessageData flat =
data->toMessageData();
151 (*details)[
"channel"] = name;
152 (*details)[
"data_size"] = flat.getSize();
153 (*details)[
"message_data"] = flat.toHex();
156 bool consumed = invokeCallback(data);
160 conn.getLogger().trace(
162 std::string &subsystem, std::string &msg,
163 std::unique_ptr<std::map<std::string, std::any>> &details) {
164 subsystem =
"cosim_read";
165 msg =
"Message from channel '" + name +
"' consumed";
174 void disconnect()
override {
175 conn.getLogger().debug(
"cosim_read",
"Disconnecting channel " + name);
177 connection->disconnect();
184 AcceleratorConnection &conn;
186 RpcClient::ChannelDesc desc;
188 std::unique_ptr<RpcClient::ReadChannelConnection> connection;
201std::unique_ptr<AcceleratorConnection>
204 std::string host =
"localhost";
207 if ((colon = connectionString.find(
':')) != std::string::npos) {
208 portStr = connectionString.substr(colon + 1);
209 host = connectionString.substr(0, colon);
210 }
else if (connectionString.ends_with(
"cosim.cfg")) {
211 std::ifstream cfg(connectionString);
212 std::string line, key, value;
214 while (getline(cfg, line))
215 if ((colon = line.find(
":")) != std::string::npos) {
216 key = line.substr(0, colon);
217 value = line.substr(colon + 1);
220 else if (key ==
"host")
224 if (portStr.size() == 0)
225 throw std::runtime_error(
"port line not found in file");
226 }
else if (connectionString ==
"env") {
227 char *hostEnv = getenv(
"ESI_COSIM_HOST");
232 char *portEnv = getenv(
"ESI_COSIM_PORT");
236 throw std::runtime_error(
"ESI_COSIM_PORT environment variable not set");
238 throw std::runtime_error(
"Invalid connection std::string '" +
239 connectionString +
"'");
241 uint16_t port = stoul(portStr);
242 auto conn = make_unique<CosimAccelerator>(
ctxt, host, port);
267class CosimSysInfo :
public SysInfo {
277 :
SysInfo(conn), rpcClient(rpcClient) {
281 if (!rpcClient->
getChannelDesc(
"__cosim_cycle_count.arg", argDesc) ||
282 !rpcClient->
getChannelDesc(
"__cosim_cycle_count.result", resultDesc))
285 Context &ctxt = conn.getCtxt();
290 {{
"cycle", i64Type}, {
"freq", i64Type}}));
292 reqPort = std::make_unique<WriteCosimChannelPort>(
293 conn, *rpcClient, argDesc, i1Type,
"__cosim_cycle_count.arg");
294 respPort = std::make_unique<ReadCosimChannelPort>(
295 conn, *rpcClient, resultDesc, resultType,
"__cosim_cycle_count.result");
301 bundleType, *reqPort, *respPort));
305 uint32_t getEsiVersion()
const override {
return rpcClient->
getEsiVersion(); }
306 std::optional<uint64_t> getCycleCount()
const override {
309 return getCycleInfo().cycle;
311 std::optional<uint64_t> getCoreClockFrequency()
const override {
314 return getCycleInfo().freq;
317 std::vector<uint8_t> getCompressedManifest()
const override {
322 const esi::Type *getType(Context &ctxt, esi::Type *type) {
332 std::unique_ptr<WriteCosimChannelPort> reqPort;
333 std::unique_ptr<ReadCosimChannelPort> respPort;
334 std::unique_ptr<FuncService::Function> func;
336 CycleInfo getCycleInfo()
const {
337 MessageData arg({1});
338 std::future<MessageData> result = func->call(arg);
340 MessageData respMsg = result.get();
341 return *respMsg.
as<CycleInfo>();
347class CosimMMIO :
public MMIO {
349 CosimMMIO(CosimAccelerator &conn, Context &ctxt,
const AppIDPath &idPath,
354 RpcClient::ChannelDesc cmdArg, cmdResp;
355 if (!rpcClient->
getChannelDesc(
"__cosim_mmio_read_write.arg", cmdArg) ||
356 !rpcClient->
getChannelDesc(
"__cosim_mmio_read_write.result", cmdResp))
357 throw std::runtime_error(
"Could not find MMIO channels");
359 const esi::Type *i64Type = getType(ctxt,
new UIntType(cmdResp.
type, 64));
360 const esi::Type *cmdType = getType(
361 ctxt,
new StructType(cmdArg.
type, {{
"write", new BitsType(
"i1", 1)},
362 {
"offset", new UIntType(
"ui32", 32)},
363 {
"data", new BitsType(
"i64", 64)}}));
366 cmdArgPort = std::make_unique<WriteCosimChannelPort>(
367 conn, *rpcClient, cmdArg, cmdType,
"__cosim_mmio_read_write.arg");
368 cmdRespPort = std::make_unique<ReadCosimChannelPort>(
369 conn, *rpcClient, cmdResp, i64Type,
"__cosim_mmio_read_write.result");
370 auto *bundleType =
new BundleType(
371 "cosimMMIO", {{
"arg", BundleType::Direction::To, cmdType},
372 {
"result", BundleType::Direction::From, i64Type}});
374 *cmdArgPort, *cmdRespPort));
387 uint64_t
read(uint32_t addr)
const override {
388 MMIOCmd cmd{.data = 0, .offset =
addr, .write =
false};
390 std::lock_guard<std::mutex> g(mmioCmdLock);
391 std::future<MessageData> result = cmdMMIO->call(arg);
393 uint64_t ret = *result.get().as<uint64_t>();
394 conn.getLogger().trace(
395 [addr, ret](std::string &subsystem, std::string &msg,
396 std::unique_ptr<std::map<std::string, std::any>> &details) {
397 subsystem =
"cosim_mmio";
398 msg =
"MMIO[0x" +
toHex(addr) +
"] = 0x" +
toHex(ret);
403 void write(uint32_t addr, uint64_t data)
override {
404 conn.getLogger().trace(
406 data](std::string &subsystem, std::string &msg,
407 std::unique_ptr<std::map<std::string, std::any>> &details) {
408 subsystem =
"cosim_mmio";
409 msg =
"MMIO[0x" +
toHex(addr) +
"] <- 0x" +
toHex(data);
411 MMIOCmd cmd{.data =
data, .offset =
addr, .write =
true};
413 std::lock_guard<std::mutex> g(mmioCmdLock);
414 std::future<MessageData> result = cmdMMIO->call(arg);
419 const esi::Type *getType(Context &ctxt, esi::Type *type) {
427 std::unique_ptr<WriteCosimChannelPort> cmdArgPort;
428 std::unique_ptr<ReadCosimChannelPort> cmdRespPort;
429 std::unique_ptr<FuncService::Function> cmdMMIO;
433struct HostMemReadReq {
439using HostMemWriteResp = uint8_t;
450void putBits(uint8_t *buf,
size_t bitOff,
size_t width, uint64_t val) {
451 for (
size_t i = 0; i < width; ++i)
452 if ((val >> i) & 1ULL)
453 buf[(bitOff + i) >> 3] |=
static_cast<uint8_t
>(1u << ((bitOff + i) & 7));
455uint64_t getBits(
const uint8_t *buf,
size_t bitOff,
size_t width) {
457 for (
size_t i = 0; i < width; ++i)
458 if (buf[(bitOff + i) >> 3] & (1u << ((bitOff + i) & 7)))
463const StructType &getHostMemPayload(
const Type *type,
464 std::string_view direction) {
467 throw std::runtime_error(
468 std::format(
"Invalid HostMem {} channel layout", direction));
472size_t getHostMemDataBytes(
const StructType &payload,
473 std::string_view direction) {
474 const auto &fields = payload.
getFields();
475 auto data = std::find_if(fields.begin(), fields.end(), [](
const auto &field) {
476 return field.first ==
"data";
478 if (data == fields.end() ||
479 !
dynamic_cast<const BitVectorType *
>(
data->second))
480 throw std::runtime_error(
481 std::format(
"Invalid HostMem {} field: data", direction));
482 auto width =
data->second->getBitWidth();
483 if (width < 8 || !std::has_single_bit(
static_cast<uint64_t
>(width)))
484 throw std::runtime_error(std::format(
485 "HostMem {} width must be a power of two and at least 8", direction));
489void validateHostMemFields(
490 const StructType &payload,
491 std::initializer_list<std::pair<std::string_view, size_t>> expected,
492 std::string_view direction) {
493 if (payload.
getFields().size() != expected.size())
494 throw std::runtime_error(
495 std::format(
"Invalid HostMem {} channel layout", direction));
496 auto field = payload.
getFields().begin();
497 for (
auto [name, width] : expected) {
498 if (field->first != name ||
499 (!
dynamic_cast<const BitVectorType *
>(field->second) &&
500 !(width == 0 &&
dynamic_cast<const VoidType *
>(field->second))) ||
501 field->second->getBitWidth() !=
static_cast<std::ptrdiff_t
>(width))
502 throw std::runtime_error(
503 std::format(
"Invalid HostMem {} field: {}", direction, field->first));
510class HostMemReadRespFrame {
512 HostMemReadRespFrame(uint8_t tag,
const uint8_t *data,
size_t validBytes,
513 size_t wordBytes,
bool last)
514 : bytes(wordBytes + 2, 0) {
515 putBits(bytes.data(), 0, 1, last);
516 for (
size_t i = 0; i < validBytes; ++i)
517 putBits(bytes.data(), 1 + i * 8, 8, data[i]);
518 putBits(bytes.data(), 1 + wordBytes * 8, 8, tag);
521 MessageData toMessage()
const {
522 return MessageData(bytes.data(), bytes.size());
526 std::vector<uint8_t> bytes;
533class HostMemWriteReqFrame {
535 HostMemWriteReqFrame(
const uint8_t *raw,
size_t dataBytes,
size_t sizeWidth)
536 : bytes(raw), sizeWidth(sizeWidth), dataOff(1 + sizeWidth),
537 tagOff(dataOff + dataBytes * 8), addrOff(tagOff + 8) {}
539 uint64_t address()
const {
return getBits(bytes, addrOff, 64); }
540 uint8_t tag()
const {
return getBits(bytes, tagOff, 8); }
541 uint8_t dataByte(
size_t i)
const {
542 return getBits(bytes, dataOff + 8 * i, 8);
545 size_t validBytes()
const {
return getBits(bytes, 1, sizeWidth) + 1; }
546 bool last()
const {
return getBits(bytes, 0, 1) != 0; }
549 const uint8_t *bytes;
550 size_t sizeWidth, dataOff, tagOff, addrOff;
557static constexpr uint32_t kPcieMaxReadRequestBytes = 64 * 4;
559class CosimHostMem :
public HostMem {
561 CosimHostMem(AcceleratorConnection &acc, Context &ctxt, RpcClient *rpcClient)
562 : HostMem(
acc),
acc(
acc), ctxt(ctxt), rpcClient(rpcClient) {}
564 void start()
override {
571 RpcClient::ChannelDesc writeArg, writeResp;
572 if (!rpcClient->
getChannelDesc(
"__cosim_hostmem_write.arg", writeArg) ||
573 !rpcClient->
getChannelDesc(
"__cosim_hostmem_write.result", writeResp))
574 throw std::runtime_error(
"Could not find HostMem write channels");
576 RpcClient::ChannelDesc readArg, readResp;
577 if (!rpcClient->
getChannelDesc(
"__cosim_hostmem_read_req.data", readArg) ||
578 !rpcClient->
getChannelDesc(
"__cosim_hostmem_read_resp.data", readResp))
579 throw std::runtime_error(
"Could not find HostMem read channels");
583 Manifest manifest(ctxt,
acc.getService<SysInfo>()->getJsonManifest());
584 auto channelType = [
this](
const RpcClient::ChannelDesc &desc) {
585 auto type = ctxt.
getType(desc.type);
587 throw std::runtime_error(
"HostMem channel type not in manifest: " +
591 const esi::Type *writeReqType = channelType(writeArg);
592 const auto &writePayload = getHostMemPayload(writeReqType,
"write");
593 writeDataBytes = getHostMemDataBytes(writePayload,
"write");
594 writeSizeWidth = std::countr_zero(writeDataBytes);
595 validateHostMemFields(writePayload,
598 {
"data", writeDataBytes * 8},
599 {
"data_size", writeSizeWidth},
603 (64 + 8 + writeDataBytes * 8 + writeSizeWidth + 1 + 7) / 8;
606 const esi::Type *readRespType = channelType(readResp);
607 const auto &readPayload = getHostMemPayload(readRespType,
"read");
608 readDataBytes = getHostMemDataBytes(readPayload,
"read");
609 validateHostMemFields(
610 readPayload, {{
"tag", 8}, {
"data", readDataBytes * 8}, {
"last", 1}},
612 const esi::Type *readReqType = channelType(readArg);
618 readRespPort = std::make_unique<WriteCosimChannelPort>(
619 conn, *rpcClient, readResp, readRespType,
620 "__cosim_hostmem_read_resp.data", 0);
621 readRespPort->connect();
622 readReqPort = std::make_unique<ReadCosimChannelPort>(
623 conn, *rpcClient, readArg, readReqType,
624 "__cosim_hostmem_read_req.data");
625 readReqPort->connect(
626 [
this](
const MessageData &req) {
return serviceRead(req); });
629 const esi::Type *writeRespType = channelType(writeResp);
633 writeRespPort = std::make_unique<WriteCosimChannelPort>(
634 conn, *rpcClient, writeResp, writeRespType,
635 "__cosim_hostmem_write.result", 0);
636 writeReqPort = std::make_unique<ReadCosimChannelPort>(
637 conn, *rpcClient, writeArg, writeReqType,
"__cosim_hostmem_write.arg");
638 auto *bundleType =
new BundleType(
640 {{
"arg", BundleType::Direction::To, writeReqType},
641 {
"result", BundleType::Direction::From, writeRespType}});
643 bundleType, *writeRespPort,
645 write->connect([
this](
const MessageData &req) {
return serviceWrite(req); },
651 bool serviceRead(
const MessageData &reqBytes) {
652 const HostMemReadReq *req = reqBytes.
as<HostMemReadReq>();
653 acc.getLogger().trace(
654 [&](std::string &subsystem, std::string &msg,
655 std::unique_ptr<std::map<std::string, std::any>> &details) {
656 subsystem =
"hostmem";
657 msg =
"Read request: addr=0x" +
toHex(req->address) +
658 " len=" + std::to_string(req->length) +
659 " tag=" + std::to_string(req->tag);
664 const auto *dataPtr =
reinterpret_cast<const uint8_t *
>(req->address);
665 size_t numDataResps =
666 req->length == 0 ? 0 : 1 + (req->length - 1) / readDataBytes;
667 if (numDataResps == 0)
668 acc.getLogger().error(
670 std::format(
"Read request with length=0 from addr=0x{} tag={}. "
671 "Reads of length 0 are not valid and indicate a bug "
673 toHex(req->address), req->tag));
674 size_t maxReadBytes =
675 std::max<size_t>(kPcieMaxReadRequestBytes, readDataBytes);
676 if (req->length > maxReadBytes)
677 acc.getLogger().error(
679 std::format(
"Read request length={} from addr=0x{} tag={} exceeds "
680 "the cosim maximum read request size ({} bytes). The "
681 "requester must split reads larger than this into "
682 "multiple requests.",
683 req->length,
toHex(req->address), req->tag,
685 size_t numResps = std::max<size_t>(numDataResps, 1);
686 for (
size_t i = 0; i < numResps; ++i) {
687 size_t offset = i * readDataBytes;
688 size_t validBytes = std::min<size_t>(req->length - offset, readDataBytes);
689 bool last = i + 1 == numResps;
690 HostMemReadRespFrame frame(req->tag,
691 validBytes ? dataPtr + offset :
nullptr,
692 validBytes, readDataBytes, last);
693 acc.getLogger().trace(
694 [&](std::string &subsystem, std::string &msg,
695 std::unique_ptr<std::map<std::string, std::any>> &details) {
696 subsystem =
"HostMem";
697 msg = std::format(
"Read result: valid_bytes={} tag={} last={:d}",
698 validBytes, req->tag, last);
700 readRespPort->write(frame.toMessage());
707 MessageData serviceWrite(
const MessageData &reqBytes) {
708 if (reqBytes.
getSize() != writeFrameBytes)
709 throw std::runtime_error(
"HostMem write frame size mismatch. Size is " +
710 std::to_string(reqBytes.
getSize()) +
711 ", expected " + std::to_string(writeFrameBytes) +
713 HostMemWriteReqFrame req(reqBytes.
getBytes(), writeDataBytes,
715 acc.getLogger().trace(
716 [&](std::string &subsystem, std::string &msg,
717 std::unique_ptr<std::map<std::string, std::any>> &details) {
718 subsystem =
"hostmem";
719 msg =
"Write request: addr=0x" +
toHex(req.address()) +
720 " valid_bytes=" + std::to_string(req.validBytes()) +
721 " tag=" + std::to_string(req.tag()) +
722 " last=" + std::to_string(req.last());
724 uint8_t *dataPtr =
reinterpret_cast<uint8_t *
>(req.address());
725 size_t validBytes = req.validBytes();
726 for (
size_t i = 0; i < validBytes; ++i)
727 dataPtr[i] = req.dataByte(i);
728 HostMemWriteResp resp = req.tag();
732 struct CosimHostMemRegion :
public HostMemRegion {
733 CosimHostMemRegion(std::size_t size) : ptr(malloc(size)), size(size) {
735 memset(ptr, 0xFF, size);
737 virtual ~CosimHostMemRegion() { free(ptr); }
738 virtual void *getPtr()
const override {
return ptr; }
739 virtual std::size_t getSize()
const override {
return size; }
746 virtual std::unique_ptr<HostMemRegion>
747 allocate(std::size_t size, HostMem::Options opts)
const override {
750 std::unique_ptr<HostMemRegion> ret(
new (std::nothrow)
751 CosimHostMemRegion(size));
752 if (!ret || !ret->getPtr())
754 acc.getLogger().debug(
755 [&](std::string &subsystem, std::string &msg,
756 std::unique_ptr<std::map<std::string, std::any>> &details) {
757 subsystem =
"HostMem";
758 msg =
"Allocated host memory region at 0x" +
toHex(ret->getPtr()) +
759 " of size " + std::to_string(size);
763 virtual bool mapMemory(
void *ptr, std::size_t size,
764 HostMem::Options opts)
const override {
767 virtual void unmapMemory(
void *ptr)
const override {}
770 AcceleratorConnection &
acc;
772 RpcClient *rpcClient;
773 size_t readDataBytes = 0;
774 size_t writeDataBytes = 0;
775 size_t writeSizeWidth = 0;
776 size_t writeFrameBytes = 0;
777 std::unique_ptr<WriteCosimChannelPort> readRespPort;
778 std::unique_ptr<ReadCosimChannelPort> readReqPort;
779 std::unique_ptr<CallService::Callback>
read;
780 std::unique_ptr<WriteCosimChannelPort> writeRespPort;
781 std::unique_ptr<ReadCosimChannelPort> writeReqPort;
782 std::unique_ptr<CallService::Callback>
write;
786namespace esi::backends::cosim {
795 if (prefix.size() > 0)
798 for (
auto client : clients) {
799 AppIDPath fullClientPath = prefix + client.relPath;
800 std::map<std::string, std::string> channelAssignments;
801 for (
auto assignment : client.channelAssignments)
802 if (assignment.second.type ==
"cosim")
803 channelAssignments[assignment.first] = std::any_cast<std::string>(
804 assignment.second.implOptions.at(
"name"));
810 const std::string &channelName,
812 const Type *type)
override;
816 std::map<AppIDPath, std::map<std::string, std::string>>
821std::unique_ptr<ChannelPort>
828 throw std::runtime_error(
"Could not find port for '" + idPath.
toStr() +
829 "." + channelName +
"'");
830 const std::map<std::string, std::string> &channelAssignments = f->second;
831 auto cosimChannelNameIter = channelAssignments.find(channelName);
832 if (cosimChannelNameIter == channelAssignments.end())
833 throw std::runtime_error(
"Could not find channel '" + idPath.
toStr() +
"." +
834 channelName +
"' in cosimulation");
839 if (!
conn.rpcClient->getChannelDesc(cosimChannelNameIter->second, chDesc))
840 throw std::runtime_error(
"Could not find channel '" + idPath.
toStr() +
"." +
841 channelName +
"' in cosimulation");
843 std::unique_ptr<ChannelPort> port;
844 std::string fullChannelName = idPath.
toStr() +
"." + channelName;
846 port = std::make_unique<WriteCosimChannelPort>(
847 conn, *
conn.rpcClient, chDesc, type, fullChannelName);
849 port = std::make_unique<ReadCosimChannelPort>(
conn, *
conn.rpcClient, chDesc,
850 type, fullChannelName);
859 std::unique_ptr<Engine> engine =
nullptr;
860 if (engineTypeName ==
"cosim")
861 engine = std::make_unique<CosimEngine>(*
this, idPath, details, clients);
875 }
else if (svcType ==
typeid(
SysInfo)) {
878 return new CosimSysInfo(*
this,
rpcClient.get());
#define REGISTER_ACCELERATOR(Name, TAccelerator)
static constexpr unsigned DefaultToClientMaxInFlight
Default maximum number of frames in flight (queued in the simulator or sent but not yet consumed by t...
static constexpr unsigned DefaultToServerMaxInFlight
Default maximum number of frames sent to a server-bound channel which the simulation has not yet cons...
services::Service Service
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
Context & getCtxt() const
void clearOwnedObjects()
Drop accelerator-owned objects before a derived backend destroys resources that those objects may ref...
Context & ctxt
ESI accelerator context.
void registerEngine(AppIDPath idPath, std::unique_ptr< Engine > engine, const HWClientDetails &clients)
If createEngine is overridden, this method should be called to register the engine and all of the cha...
virtual void disconnect()
Disconnect from the accelerator cleanly.
Logger & getLogger() const
AcceleratorConnection(Context &ctxt)
std::string toStr() const
Bits are just an array of bits.
static bool isWrite(BundleType::Direction bundleDir)
Compute the direction of a channel given the bundle direction and the bundle port's direction.
Bundles represent a collection of channels.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
std::optional< const Type * > getType(Type::ID id) const
Resolve a type id to the type.
void registerType(Type *type)
Register a type with the context. Takes ownership of the pointer type.
Engine(AcceleratorConnection &conn)
const uint8_t * getBytes() const
const T * as() const
Cast to a type.
size_t getSize() const
Get the size of the data in bytes.
static MessageData from(T &t)
Cast from a type to its raw bytes.
A ChannelPort which reads data from the accelerator.
virtual void disconnect() override
Disconnect the channel.
Structs are an ordered collection of fields, each with a name and a type.
const FieldVector & getFields() const
Root class of the ESI type system.
A ChannelPort which sends data to the accelerator.
Connect to an ESI simulation.
void createEngine(const std::string &engineTypeName, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients) override
Create a new engine for channel communication with the accelerator.
std::unique_ptr< RpcClient > rpcClient
void setManifestMethod(ManifestMethod method)
static std::unique_ptr< AcceleratorConnection > connect(Context &, std::string connectionString)
Parse the connection std::string and instantiate the accelerator.
virtual Service * createService(Service::Type service, AppIDPath path, std::string implName, const ServiceImplDetails &details, const HWClientDetails &clients) override
Called by getServiceImpl exclusively.
ManifestMethod manifestMethod
CosimAccelerator(Context &, std::string hostname, uint16_t port)
Construct and connect to a cosim server.
std::set< std::unique_ptr< ChannelPort > > channels
CosimEngine(CosimAccelerator &conn, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients)
std::map< AppIDPath, std::map< std::string, std::string > > clientChannelAssignments
std::unique_ptr< ChannelPort > createPort(AppIDPath idPath, const std::string &channelName, BundleType::Direction dir, const Type *type) override
Each engine needs to know how to create a ports.
A client for the cosim RPC server.
std::vector< uint8_t > getCompressedManifest() const
Get the compressed manifest from the server.
uint32_t getEsiVersion() const
Get the ESI version from the manifest.
bool getChannelDesc(const std::string &channelName, ChannelDesc &desc) const
Get the channel description for a channel name.
static Callback * get(AcceleratorConnection &acc, AppID id, const BundleType *type, WriteChannelPort &result, ReadChannelPort &arg)
static Function * get(AppID id, BundleType *type, WriteChannelPort &arg, ReadChannelPort &result)
Implement the SysInfo API for a standard MMIO protocol.
const std::type_info & Type
Information about the Accelerator system.
std::unique_ptr< Engine > createEngine(AcceleratorConnection &conn, const std::string &dmaEngineName, AppIDPath idPath, const ServiceImplDetails &details, const HWClientDetails &clients)
Create an engine by name.
std::string toHex(void *val)
std::vector< HWClientDetail > HWClientDetails
std::map< std::string, std::any > ServiceImplDetails
const T * getUnwrappedAs(const Type *type)
Unwrap aliases and channels, then cast the payload to T.
Description of a channel from the server.
std::optional< unsigned > bufferSize
The buffer size is optional and should be considered merely a hint.
Description of a channel from the server.