21 #include "CosimDpi.capnp.h"
22 #include <capnp/ez-rpc.h>
30 using namespace capnp;
38 class EndpointServer final :
public EsiDpiEndpoint::Server {
51 EndpointServer(
const EndpointServer &) =
delete;
54 kj::Promise<void> sendFromHost(SendFromHostContext)
override;
55 kj::Promise<void> recvToHost(RecvToHostContext)
override;
56 kj::Promise<void> close(CloseContext)
override;
60 class LowLevelServer final :
public EsiLowLevel::Server {
69 kj::Promise<void> pollReadResp(ReadMMIOContext context);
70 kj::Promise<void> pollWriteResp(WriteMMIOContext context);
78 LowLevelServer(
const LowLevelServer &) =
delete;
81 kj::Promise<void> readMMIO(ReadMMIOContext)
override;
82 kj::Promise<void> writeMMIO(WriteMMIOContext)
override;
86 class CosimServer final :
public CosimDpiServer::Server {
90 const unsigned int &esiVersion;
91 const std::vector<uint8_t> &compressedManifest;
95 const unsigned int &esiVersion,
96 const std::vector<uint8_t> &compressedManifest);
99 kj::Promise<void> list(ListContext
ctxt)
override;
101 kj::Promise<void> open(OpenContext
ctxt)
override;
104 getCompressedManifest(GetCompressedManifestContext)
override;
106 kj::Promise<void> openLowLevel(OpenLowLevelContext
ctxt)
override;
112 EndpointServer::EndpointServer(
Endpoint &ep) : endpoint(ep), open(true) {}
113 EndpointServer::~EndpointServer() {
115 endpoint.returnForUse();
120 kj::Promise<void> EndpointServer::recvToHost(RecvToHostContext context) {
121 KJ_REQUIRE(open,
"EndPoint closed already");
125 auto msgPresent = endpoint.getMessageToClient(blob);
126 context.getResults().setHasData(msgPresent);
128 Data::Builder
data(blob->data(), blob->size());
129 context.getResults().setResp(
data.asReader());
131 return kj::READY_NOW;
138 kj::Promise<void> EndpointServer::sendFromHost(SendFromHostContext context) {
139 KJ_REQUIRE(open,
"EndPoint closed already");
140 KJ_REQUIRE(context.getParams().hasMsg(),
"Send request must have a message.");
141 kj::ArrayPtr<const kj::byte>
data = context.getParams().getMsg().asBytes();
143 std::make_unique<Endpoint::Blob>(
data.begin(),
data.end());
144 endpoint.pushMessageToSim(std::move(blob));
145 return kj::READY_NOW;
148 kj::Promise<void> EndpointServer::close(CloseContext context) {
149 KJ_REQUIRE(open,
"EndPoint closed already");
151 endpoint.returnForUse();
152 return kj::READY_NOW;
157 LowLevelServer::LowLevelServer(
LowLevel &bridge) : bridge(bridge) {}
158 LowLevelServer::~LowLevelServer() {}
160 kj::Promise<void> LowLevelServer::pollReadResp(ReadMMIOContext context) {
162 if (!respMaybe.has_value()) {
164 [
this, KJ_CPCAP(context)]()
mutable {
return pollReadResp(context); });
166 auto resp = respMaybe.value();
167 KJ_REQUIRE(resp.second == 0,
"Read MMIO register encountered an error");
168 context.getResults().setData(resp.first);
169 return kj::READY_NOW;
172 kj::Promise<void> LowLevelServer::readMMIO(ReadMMIOContext context) {
173 bridge.readReqs.push(context.getParams().getAddress());
175 [
this, KJ_CPCAP(context)]()
mutable {
return pollReadResp(context); });
178 kj::Promise<void> LowLevelServer::pollWriteResp(WriteMMIOContext context) {
179 auto respMaybe = bridge.writeResps.pop();
180 if (!respMaybe.has_value()) {
182 [
this, KJ_CPCAP(context)]()
mutable {
return pollWriteResp(context); });
184 auto resp = respMaybe.value();
185 KJ_REQUIRE(resp == 0,
"write MMIO register encountered an error");
186 return kj::READY_NOW;
189 kj::Promise<void> LowLevelServer::writeMMIO(WriteMMIOContext context) {
190 bridge.writeReqs.push(context.getParams().getAddress(),
191 context.getParams().getData());
193 [
this, KJ_CPCAP(context)]()
mutable {
return pollWriteResp(context); });
199 const unsigned int &esiVersion,
200 const std::vector<uint8_t> &compressedManifest)
201 :
reg(
reg), lowLevelBridge(lowLevelBridge), esiVersion(esiVersion),
202 compressedManifest(compressedManifest) {
203 printf(
"version: %d\n", esiVersion);
206 kj::Promise<void> CosimServer::list(ListContext context) {
207 auto ifaces = context.getResults().initIfaces((
unsigned int)
reg.size());
208 unsigned int ctr = 0u;
209 reg.iterateEndpoints([&](std::string
id,
const Endpoint &ep) {
210 ifaces[ctr].setEndpointID(
id);
215 return kj::READY_NOW;
218 kj::Promise<void> CosimServer::open(OpenContext
ctxt) {
220 KJ_REQUIRE(ep !=
nullptr,
"Could not find endpoint");
223 KJ_REQUIRE(gotLock,
"Endpoint in use");
225 ctxt.getResults().setEndpoint(
226 EsiDpiEndpoint::Client(kj::heap<EndpointServer>(*ep)));
227 return kj::READY_NOW;
231 CosimServer::getCompressedManifest(GetCompressedManifestContext
ctxt) {
232 ctxt.getResults().setVersion(esiVersion);
233 ctxt.getResults().setCompressedManifest(
234 Data::Reader(compressedManifest.data(), compressedManifest.size()));
235 return kj::READY_NOW;
238 kj::Promise<void> CosimServer::openLowLevel(OpenLowLevelContext
ctxt) {
239 ctxt.getResults().setLowLevel(kj::heap<LowLevelServer>(lowLevelBridge));
240 return kj::READY_NOW;
245 RpcServer::RpcServer() : mainThread(nullptr), stopSig(false) {}
253 FILE *fd = fopen(
"cosim.cfg",
"w");
254 fprintf(fd,
"port: %u\n", (
unsigned int)port);
263 auto &waitScope = rpcServer.getWaitScope();
266 auto portPromise = rpcServer.getPort();
267 port = portPromise.wait(waitScope);
270 printf(
"[COSIM] Listening on port: %u\n", (
unsigned int)port);
284 std::this_thread::sleep_for(std::chrono::milliseconds(10));
294 fprintf(stderr,
"Warning: cannot Run() RPC server more than once!");
302 fprintf(stderr,
"RpcServer not Run()\n");
static void writePort(uint16_t port)
Write the port number to a file.
The Endpoint registry is where Endpoints report their existence (register) and they are looked up by ...
Implements a bi-directional, thread-safe bridge between the RPC server and DPI functions.
std::string getSendTypeId() const
bool setInUse()
These two are used to set and unset the inUse flag, to ensure that an open endpoint is not opened aga...
std::string getRecvTypeId() const
std::unique_ptr< Blob > BlobPtr
TSQueue< std::pair< uint64_t, uint8_t > > readResps
void mainLoop(uint16_t port)
The thread's main loop function. Exits on shutdown.
EndpointRegistry endpoints
std::vector< uint8_t > compressedManifest
void stop()
Signal the RPC server thread to stop. Wait for it to exit.
std::lock_guard< std::mutex > Lock
void run(uint16_t port)
Start and stop the server thread.
std::optional< T > pop()
Pop something off the queue but return nullopt if the queue is empty.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)