esiaccel 0.0.10__cp310-cp310-win_amd64.whl → 0.1.5.dev406__cp310-cp310-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of esiaccel might be problematic. Click here for more details.

Files changed (58) hide show
  1. esiaccel/CosimBackend.dll +0 -0
  2. esiaccel/CosimBackend.lib +0 -0
  3. esiaccel/ESICppRuntime.dll +0 -0
  4. esiaccel/ESICppRuntime.lib +0 -0
  5. esiaccel/EsiCosimDpiServer.dll +0 -0
  6. esiaccel/EsiCosimDpiServer.lib +0 -0
  7. esiaccel/MtiPli.dll +0 -0
  8. esiaccel/MtiPli.lib +0 -0
  9. esiaccel/__init__.py +10 -1
  10. esiaccel/abseil_dll.dll +0 -0
  11. esiaccel/accelerator.py +15 -1
  12. esiaccel/cares.dll +0 -0
  13. esiaccel/cmake/esiaccelConfig.cmake +1 -1
  14. esiaccel/codegen.py +197 -0
  15. esiaccel/cosim/Cosim_DpiPkg.sv +85 -0
  16. esiaccel/cosim/Cosim_Endpoint.sv +218 -0
  17. esiaccel/cosim/Cosim_Manifest.sv +32 -0
  18. esiaccel/cosim/driver.cpp +131 -0
  19. esiaccel/cosim/driver.sv +74 -0
  20. esiaccel/cosim/questa.py +141 -0
  21. esiaccel/cosim/simulator.py +382 -0
  22. esiaccel/cosim/verilator.py +92 -0
  23. esiaccel/esi-cosim.py +104 -0
  24. esiaccel/esiCppAccel.cp310-win_amd64.pyd +0 -0
  25. esiaccel/esiquery.exe +0 -0
  26. esiaccel/include/esi/Accelerator.h +33 -9
  27. esiaccel/include/esi/CLI.h +77 -0
  28. esiaccel/include/esi/Common.h +59 -10
  29. esiaccel/include/esi/Context.h +21 -1
  30. esiaccel/include/esi/Design.h +14 -3
  31. esiaccel/include/esi/Engines.h +124 -0
  32. esiaccel/include/esi/Logging.h +231 -0
  33. esiaccel/include/esi/Manifest.h +0 -2
  34. esiaccel/include/esi/Ports.h +54 -7
  35. esiaccel/include/esi/Services.h +225 -22
  36. esiaccel/include/esi/Types.h +103 -5
  37. esiaccel/include/esi/Utils.h +5 -0
  38. esiaccel/include/esi/Values.h +313 -0
  39. esiaccel/include/esi/backends/Cosim.h +85 -0
  40. esiaccel/include/esi/backends/RpcServer.h +55 -0
  41. esiaccel/include/esi/backends/Trace.h +8 -5
  42. esiaccel/libcrypto-3-x64.dll +0 -0
  43. esiaccel/libprotobuf.dll +0 -0
  44. esiaccel/libssl-3-x64.dll +0 -0
  45. esiaccel/re2.dll +0 -0
  46. esiaccel/types.py +174 -33
  47. esiaccel/utils.py +27 -3
  48. esiaccel/zlib1.dll +0 -0
  49. {esiaccel-0.0.10.dist-info → esiaccel-0.1.5.dev406.dist-info}/METADATA +3 -3
  50. esiaccel-0.1.5.dev406.dist-info/RECORD +54 -0
  51. {esiaccel-0.0.10.dist-info → esiaccel-0.1.5.dev406.dist-info}/WHEEL +1 -1
  52. {esiaccel-0.0.10.dist-info → esiaccel-0.1.5.dev406.dist-info}/entry_points.txt +1 -0
  53. esiaccel/bin/ESICppRuntime.dll +0 -0
  54. esiaccel/bin/esiquery.exe +0 -0
  55. esiaccel/bin/zlib1.dll +0 -0
  56. esiaccel-0.0.10.dist-info/RECORD +0 -28
  57. {esiaccel-0.0.10.dist-info → esiaccel-0.1.5.dev406.dist-info/licenses}/LICENSE +0 -0
  58. {esiaccel-0.0.10.dist-info → esiaccel-0.1.5.dev406.dist-info}/top_level.txt +0 -0
@@ -25,6 +25,9 @@
25
25
 
26
26
  namespace esi {
27
27
 
28
+ class ChannelPort;
29
+ using PortMap = std::map<std::string, ChannelPort &>;
30
+
28
31
  /// Unidirectional channels are the basic communication primitive between the
29
32
  /// host and accelerator. A 'ChannelPort' is the host side of a channel. It can
30
33
  /// be either read or write but not both. At this level, channels are untyped --
@@ -83,13 +86,37 @@ public:
83
86
  virtual void disconnect() override { connected = false; }
84
87
  virtual bool isConnected() const override { return connected; }
85
88
 
86
- /// A very basic write API. Will likely change for performance reasons.
89
+ /// A very basic blocking write API. Will likely change for performance
90
+ /// reasons.
87
91
  virtual void write(const MessageData &) = 0;
88
92
 
93
+ /// A basic non-blocking write API. Returns true if the data was written.
94
+ /// It is invalid for backends to always return false (i.e. backends must
95
+ /// eventually ensure that writes may succeed).
96
+ virtual bool tryWrite(const MessageData &data) = 0;
97
+
89
98
  private:
90
99
  volatile bool connected = false;
91
100
  };
92
101
 
102
+ /// Instantiated when a backend does not know how to create a write channel.
103
+ class UnknownWriteChannelPort : public WriteChannelPort {
104
+ public:
105
+ UnknownWriteChannelPort(const Type *type, std::string errmsg)
106
+ : WriteChannelPort(type), errmsg(errmsg) {}
107
+
108
+ void connect(std::optional<unsigned> bufferSize = std::nullopt) override {
109
+ throw std::runtime_error(errmsg);
110
+ }
111
+ void write(const MessageData &) override { throw std::runtime_error(errmsg); }
112
+ bool tryWrite(const MessageData &) override {
113
+ throw std::runtime_error(errmsg);
114
+ }
115
+
116
+ protected:
117
+ std::string errmsg;
118
+ };
119
+
93
120
  /// A ChannelPort which reads data from the accelerator. It has two modes:
94
121
  /// Callback and Polling which cannot be used at the same time. The mode is set
95
122
  /// at connect() time. To change the mode, disconnect() and then connect()
@@ -172,6 +199,27 @@ protected:
172
199
  std::queue<std::promise<MessageData>> promiseQueue;
173
200
  };
174
201
 
202
+ /// Instantiated when a backend does not know how to create a read channel.
203
+ class UnknownReadChannelPort : public ReadChannelPort {
204
+ public:
205
+ UnknownReadChannelPort(const Type *type, std::string errmsg)
206
+ : ReadChannelPort(type), errmsg(errmsg) {}
207
+
208
+ void connect(std::function<bool(MessageData)> callback,
209
+ std::optional<unsigned> bufferSize = std::nullopt) override {
210
+ throw std::runtime_error(errmsg);
211
+ }
212
+ void connect(std::optional<unsigned> bufferSize = std::nullopt) override {
213
+ throw std::runtime_error(errmsg);
214
+ }
215
+ std::future<MessageData> readAsync() override {
216
+ throw std::runtime_error(errmsg);
217
+ }
218
+
219
+ protected:
220
+ std::string errmsg;
221
+ };
222
+
175
223
  /// Services provide connections to 'bundles' -- collections of named,
176
224
  /// unidirectional communication channels. This class provides access to those
177
225
  /// ChannelPorts.
@@ -184,7 +232,7 @@ public:
184
232
  }
185
233
 
186
234
  /// Construct a port.
187
- BundlePort(AppID id, std::map<std::string, ChannelPort &> channels);
235
+ BundlePort(AppID id, const BundleType *type, PortMap channels);
188
236
  virtual ~BundlePort() = default;
189
237
 
190
238
  /// Get the ID of the port.
@@ -196,9 +244,7 @@ public:
196
244
  /// ordinary users should not use. You have been warned.
197
245
  WriteChannelPort &getRawWrite(const std::string &name) const;
198
246
  ReadChannelPort &getRawRead(const std::string &name) const;
199
- const std::map<std::string, ChannelPort &> &getChannels() const {
200
- return channels;
201
- }
247
+ const PortMap &getChannels() const { return channels; }
202
248
 
203
249
  /// Cast this Bundle port to a subclass which is actually useful. Returns
204
250
  /// nullptr if the cast fails.
@@ -218,9 +264,10 @@ public:
218
264
  return result;
219
265
  }
220
266
 
221
- private:
267
+ protected:
222
268
  AppID id;
223
- std::map<std::string, ChannelPort &> channels;
269
+ const BundleType *type;
270
+ PortMap channels;
224
271
  };
225
272
 
226
273
  } // namespace esi
@@ -21,12 +21,25 @@
21
21
  #define ESI_RUNTIME_SERVICES_H
22
22
 
23
23
  #include "esi/Common.h"
24
+ #include "esi/Context.h"
24
25
  #include "esi/Ports.h"
25
26
 
26
27
  #include <cstdint>
28
+ #include <list>
27
29
 
28
30
  namespace esi {
29
31
  class AcceleratorConnection;
32
+ class Engine;
33
+ namespace services {
34
+ class Service;
35
+ }
36
+
37
+ // While building the design, keep around a std::map of active services indexed
38
+ // by the service name. When a new service is encountered during descent, add it
39
+ // to the table (perhaps overwriting one). Modifications to the table only apply
40
+ // to the current branch, so copy this and update it at each level of the tree.
41
+ using ServiceTable = std::map<std::string, services::Service *>;
42
+
30
43
  namespace services {
31
44
 
32
45
  /// Add a custom interface to a service client at a particular point in the
@@ -35,6 +48,8 @@ class ServicePort : public BundlePort {
35
48
  public:
36
49
  using BundlePort::BundlePort;
37
50
  virtual ~ServicePort() = default;
51
+ // Get a description of the service port.
52
+ virtual std::optional<std::string> toString() const { return std::nullopt; }
38
53
  };
39
54
 
40
55
  /// Parent class of all APIs modeled as 'services'. May or may not map to a
@@ -42,17 +57,33 @@ public:
42
57
  class Service {
43
58
  public:
44
59
  using Type = const std::type_info &;
60
+ Service(AcceleratorConnection &conn) : conn(conn) {}
45
61
  virtual ~Service() = default;
46
62
 
47
63
  virtual std::string getServiceSymbol() const = 0;
48
64
 
65
+ /// Create a "child" service of this service. Does not have to be the same
66
+ /// service type, but typically is. Used when a service already exists in the
67
+ /// active services table, but a new one wants to replace it. Useful for cases
68
+ /// where the child service needs to use the parent service. Defaults to
69
+ /// calling the `getService` method on `AcceleratorConnection` to get the
70
+ /// global service, implying that the child service does not need to use the
71
+ /// service it is replacing.
72
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
73
+ std::string implName = {},
74
+ ServiceImplDetails details = {},
75
+ HWClientDetails clients = {});
76
+
49
77
  /// Get specialized port for this service to attach to the given appid path.
50
78
  /// Null returns mean nothing to attach.
51
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
52
- const std::map<std::string, ChannelPort &> &,
53
- AcceleratorConnection &) const {
79
+ virtual BundlePort *getPort(AppIDPath id, const BundleType *type) const {
54
80
  return nullptr;
55
81
  }
82
+
83
+ AcceleratorConnection &getConnection() const { return conn; }
84
+
85
+ protected:
86
+ AcceleratorConnection &conn;
56
87
  };
57
88
 
58
89
  /// A service for which there are no standard services registered. Requires
@@ -60,13 +91,16 @@ public:
60
91
  /// the ones in StdServices.h.
61
92
  class CustomService : public Service {
62
93
  public:
63
- CustomService(AppIDPath idPath, const ServiceImplDetails &details,
94
+ CustomService(AppIDPath idPath, AcceleratorConnection &,
95
+ const ServiceImplDetails &details,
64
96
  const HWClientDetails &clients);
65
97
  virtual ~CustomService() = default;
66
98
 
67
99
  virtual std::string getServiceSymbol() const override {
68
100
  return serviceSymbol;
69
101
  }
102
+ virtual BundlePort *getPort(AppIDPath id,
103
+ const BundleType *type) const override;
70
104
 
71
105
  protected:
72
106
  std::string serviceSymbol;
@@ -76,6 +110,7 @@ protected:
76
110
  /// Information about the Accelerator system.
77
111
  class SysInfo : public Service {
78
112
  public:
113
+ using Service::Service;
79
114
  virtual ~SysInfo() = default;
80
115
 
81
116
  virtual std::string getServiceSymbol() const override;
@@ -92,10 +127,69 @@ public:
92
127
 
93
128
  class MMIO : public Service {
94
129
  public:
130
+ static constexpr std::string_view StdName = "esi.service.std.mmio";
131
+
132
+ /// Describe a region (slice) of MMIO space.
133
+ struct RegionDescriptor {
134
+ uint32_t base;
135
+ uint32_t size;
136
+ };
137
+
138
+ MMIO(AcceleratorConnection &, const AppIDPath &idPath,
139
+ const HWClientDetails &clients);
95
140
  virtual ~MMIO() = default;
141
+
142
+ /// Read a 64-bit value from the global MMIO space.
96
143
  virtual uint64_t read(uint32_t addr) const = 0;
144
+ /// Write a 64-bit value to the global MMIO space.
97
145
  virtual void write(uint32_t addr, uint64_t data) = 0;
146
+ /// Get the regions of MMIO space that this service manages. Otherwise known
147
+ /// as the base address table.
148
+ const std::map<AppIDPath, RegionDescriptor> &getRegions() const {
149
+ return regions;
150
+ }
151
+
152
+ /// If the service is a MMIO service, return a region of the MMIO space which
153
+ /// peers into ours.
154
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
155
+ std::string implName = {},
156
+ ServiceImplDetails details = {},
157
+ HWClientDetails clients = {}) override;
158
+
98
159
  virtual std::string getServiceSymbol() const override;
160
+
161
+ /// Get a MMIO region port for a particular region descriptor.
162
+ virtual BundlePort *getPort(AppIDPath id,
163
+ const BundleType *type) const override;
164
+
165
+ private:
166
+ /// MMIO base address table.
167
+ std::map<AppIDPath, RegionDescriptor> regions;
168
+
169
+ public:
170
+ /// A "slice" of some parent MMIO space.
171
+ class MMIORegion : public ServicePort {
172
+ friend class MMIO;
173
+ MMIORegion(AppID id, MMIO *parent, RegionDescriptor desc);
174
+
175
+ public:
176
+ /// Get the offset (and size) of the region in the parent (usually global)
177
+ /// MMIO address space.
178
+ virtual RegionDescriptor getDescriptor() const { return desc; };
179
+ /// Read a 64-bit value from this region, not the global address space.
180
+ virtual uint64_t read(uint32_t addr) const;
181
+ /// Write a 64-bit value to this region, not the global address space.
182
+ virtual void write(uint32_t addr, uint64_t data);
183
+
184
+ virtual std::optional<std::string> toString() const override {
185
+ return "MMIO region " + toHex(desc.base) + " - " +
186
+ toHex(desc.base + desc.size);
187
+ }
188
+
189
+ private:
190
+ MMIO *parent;
191
+ RegionDescriptor desc;
192
+ };
99
193
  };
100
194
 
101
195
  /// Implement the SysInfo API for a standard MMIO protocol.
@@ -115,6 +209,9 @@ private:
115
209
 
116
210
  class HostMem : public Service {
117
211
  public:
212
+ static constexpr std::string_view StdName = "esi.service.std.hostmem";
213
+
214
+ using Service::Service;
118
215
  virtual ~HostMem() = default;
119
216
  virtual std::string getServiceSymbol() const override;
120
217
 
@@ -122,9 +219,19 @@ public:
122
219
  /// deconstructed.
123
220
  struct HostMemRegion {
124
221
  virtual ~HostMemRegion() = default;
222
+ /// Get a pointer to the host memory.
125
223
  virtual void *getPtr() const = 0;
224
+ /// Sometimes the pointer the device sees is different from the pointer the
225
+ /// host sees. Call this functon to get the device pointer.
226
+ virtual void *getDevicePtr() const { return getPtr(); }
126
227
  operator void *() const { return getPtr(); }
127
228
  virtual std::size_t getSize() const = 0;
229
+ /// Flush the memory region to ensure that the device sees the latest
230
+ /// contents. Because some platforms require it before DMA transactions, it
231
+ /// is recommended to call this before any DMA on all platforms. On
232
+ /// platforms which don't require it, it is a cheap no-op virtual method
233
+ /// call.
234
+ virtual void flush() {}
128
235
  };
129
236
 
130
237
  /// Options for allocating host memory.
@@ -133,6 +240,9 @@ public:
133
240
  bool useLargePages = false;
134
241
  };
135
242
 
243
+ /// In cases where necessary, enable host memory services.
244
+ virtual void start() {}
245
+
136
246
  /// Allocate a region of host memory in accelerator accessible address space.
137
247
  virtual std::unique_ptr<HostMemRegion> allocate(std::size_t size,
138
248
  Options opts) const = 0;
@@ -153,31 +263,47 @@ public:
153
263
  /// Service for calling functions.
154
264
  class FuncService : public Service {
155
265
  public:
156
- FuncService(AcceleratorConnection *acc, AppIDPath id,
157
- const std::string &implName, ServiceImplDetails details,
266
+ FuncService(AppIDPath id, AcceleratorConnection &, ServiceImplDetails details,
158
267
  HWClientDetails clients);
159
268
 
160
269
  virtual std::string getServiceSymbol() const override;
161
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
162
- const std::map<std::string, ChannelPort &> &,
163
- AcceleratorConnection &) const override;
270
+ virtual BundlePort *getPort(AppIDPath id,
271
+ const BundleType *type) const override;
164
272
 
165
273
  /// A function call which gets attached to a service port.
166
274
  class Function : public ServicePort {
167
275
  friend class FuncService;
168
- Function(AppID id, const std::map<std::string, ChannelPort &> &channels);
276
+ using ServicePort::ServicePort;
169
277
 
170
278
  public:
171
- static Function *get(AppID id, WriteChannelPort &arg,
279
+ static Function *get(AppID id, BundleType *type, WriteChannelPort &arg,
172
280
  ReadChannelPort &result);
173
281
 
174
282
  void connect();
175
283
  std::future<MessageData> call(const MessageData &arg);
176
284
 
285
+ const esi::Type *getArgType() const {
286
+ return dynamic_cast<const ChannelType *>(type->findChannel("arg").first)
287
+ ->getInner();
288
+ }
289
+
290
+ const esi::Type *getResultType() const {
291
+ return dynamic_cast<const ChannelType *>(
292
+ type->findChannel("result").first)
293
+ ->getInner();
294
+ }
295
+
296
+ virtual std::optional<std::string> toString() const override {
297
+ const esi::Type *argType = getArgType();
298
+ const esi::Type *resultType = getResultType();
299
+ return "function " + resultType->getID() + "(" + argType->getID() + ")";
300
+ }
301
+
177
302
  private:
178
303
  std::mutex callMutex;
179
- WriteChannelPort &arg;
180
- ReadChannelPort &result;
304
+ WriteChannelPort *arg;
305
+ ReadChannelPort *result;
306
+ bool connected = false;
181
307
  };
182
308
 
183
309
  private:
@@ -187,21 +313,24 @@ private:
187
313
  /// Service for servicing function calls from the accelerator.
188
314
  class CallService : public Service {
189
315
  public:
190
- CallService(AcceleratorConnection *acc, AppIDPath id, std::string implName,
191
- ServiceImplDetails details, HWClientDetails clients);
316
+ CallService(AcceleratorConnection &acc, AppIDPath id,
317
+ ServiceImplDetails details);
192
318
 
193
319
  virtual std::string getServiceSymbol() const override;
194
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
195
- const std::map<std::string, ChannelPort &> &,
196
- AcceleratorConnection &) const override;
320
+ virtual BundlePort *getPort(AppIDPath id,
321
+ const BundleType *type) const override;
197
322
 
198
323
  /// A function call which gets attached to a service port.
199
324
  class Callback : public ServicePort {
200
325
  friend class CallService;
201
- Callback(AcceleratorConnection &acc, AppID id,
202
- const std::map<std::string, ChannelPort &> &channels);
326
+ Callback(AcceleratorConnection &acc, AppID id, const BundleType *,
327
+ PortMap channels);
203
328
 
204
329
  public:
330
+ static Callback *get(AcceleratorConnection &acc, AppID id,
331
+ const BundleType *type, WriteChannelPort &result,
332
+ ReadChannelPort &arg);
333
+
205
334
  /// Connect a callback to code which will be executed when the accelerator
206
335
  /// invokes the callback. The 'quick' flag indicates that the callback is
207
336
  /// sufficiently fast that it could be called in the same thread as the
@@ -209,9 +338,26 @@ public:
209
338
  void connect(std::function<MessageData(const MessageData &)> callback,
210
339
  bool quick = false);
211
340
 
341
+ const esi::Type *getArgType() const {
342
+ return dynamic_cast<const ChannelType *>(type->findChannel("arg").first)
343
+ ->getInner();
344
+ }
345
+
346
+ const esi::Type *getResultType() const {
347
+ return dynamic_cast<const ChannelType *>(
348
+ type->findChannel("result").first)
349
+ ->getInner();
350
+ }
351
+
352
+ virtual std::optional<std::string> toString() const override {
353
+ const esi::Type *argType = getArgType();
354
+ const esi::Type *resultType = getResultType();
355
+ return "callback " + resultType->getID() + "(" + argType->getID() + ")";
356
+ }
357
+
212
358
  private:
213
- ReadChannelPort &arg;
214
- WriteChannelPort &result;
359
+ ReadChannelPort *arg;
360
+ WriteChannelPort *result;
215
361
  AcceleratorConnection &acc;
216
362
  };
217
363
 
@@ -219,6 +365,63 @@ private:
219
365
  std::string symbol;
220
366
  };
221
367
 
368
+ /// Service for retrieving telemetry data from the accelerator.
369
+ class TelemetryService : public Service {
370
+ public:
371
+ static constexpr std::string_view StdName = "esi.service.std.telemetry";
372
+
373
+ TelemetryService(AppIDPath id, AcceleratorConnection &,
374
+ ServiceImplDetails details, HWClientDetails clients);
375
+
376
+ virtual std::string getServiceSymbol() const override;
377
+ virtual BundlePort *getPort(AppIDPath id,
378
+ const BundleType *type) const override;
379
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
380
+ std::string implName = {},
381
+ ServiceImplDetails details = {},
382
+ HWClientDetails clients = {}) override;
383
+ MMIO::MMIORegion *getMMIORegion() const;
384
+
385
+ /// A telemetry port which gets attached to a service port.
386
+ class Metric : public ServicePort {
387
+ friend class TelemetryService;
388
+ Metric(AppID id, const BundleType *type, PortMap channels,
389
+ const TelemetryService *telemetryService,
390
+ std::optional<uint64_t> offset);
391
+
392
+ public:
393
+ void connect();
394
+ std::future<MessageData> read();
395
+ uint64_t readInt();
396
+
397
+ virtual std::optional<std::string> toString() const override {
398
+ const esi::Type *dataType =
399
+ dynamic_cast<const ChannelType *>(type->findChannel("data").first)
400
+ ->getInner();
401
+ return "telemetry " + dataType->getID();
402
+ }
403
+
404
+ private:
405
+ const TelemetryService *telemetryService;
406
+ MMIO::MMIORegion *mmio;
407
+ std::optional<uint64_t> offset;
408
+ };
409
+
410
+ std::map<AppIDPath, Metric *> getTelemetryPorts() {
411
+ std::map<AppIDPath, Metric *> ports;
412
+ getTelemetryPorts(ports);
413
+ return ports;
414
+ }
415
+ void getTelemetryPorts(std::map<AppIDPath, Metric *> &ports);
416
+
417
+ private:
418
+ AppIDPath id;
419
+ mutable MMIO::MMIORegion *mmio;
420
+ std::map<AppIDPath, uint64_t> portAddressAssignments;
421
+ mutable std::map<AppIDPath, Metric *> telemetryPorts;
422
+ std::list<TelemetryService *> children;
423
+ };
424
+
222
425
  /// Registry of services which can be instantiated directly by the Accelerator
223
426
  /// class if the backend doesn't do anything special with a service.
224
427
  class ServiceRegistry {
@@ -16,11 +16,18 @@
16
16
  #ifndef ESI_TYPES_H
17
17
  #define ESI_TYPES_H
18
18
 
19
- #include <map>
19
+ #include <algorithm>
20
+ #include <any>
20
21
  #include <cstdint>
22
+ #include <map>
23
+ #include <span>
24
+ #include <stdexcept>
21
25
  #include <string>
22
26
  #include <vector>
23
27
 
28
+ #include "esi/Common.h"
29
+ #include "esi/Values.h" // For BitVector / Int / UInt
30
+
24
31
  namespace esi {
25
32
 
26
33
  /// Root class of the ESI type system.
@@ -33,6 +40,46 @@ public:
33
40
  ID getID() const { return id; }
34
41
  virtual std::ptrdiff_t getBitWidth() const { return -1; }
35
42
 
43
+ /// Serialize an object to a MutableBitVector (LSB-first stream). The object
44
+ /// should be passed via std::any. Implementations append fields in the order
45
+ /// they are iterated (the first serialized field occupies the
46
+ /// least-significant bits of the result).
47
+ virtual MutableBitVector serialize(const std::any &obj) const {
48
+ throw std::runtime_error("Serialization not implemented for type " + id);
49
+ }
50
+
51
+ /// Deserialize from a BitVector stream (LSB-first). Implementations consume
52
+ /// bits from 'data' in-place (via logical right shifts) and return the
53
+ /// reconstructed value. Remaining bits stay in 'data'.
54
+ virtual std::any deserialize(BitVector &data) const {
55
+ throw std::runtime_error("Deserialization not implemented for type " + id);
56
+ }
57
+
58
+ // Deserialize from a MessageData buffer. Maps the MessageData onto a
59
+ // MutableBitVector, and proceeds with regular MutableBitVector
60
+ // deserialization.
61
+ std::any deserialize(const MessageData &data) const {
62
+ auto bv = MutableBitVector(std::vector<uint8_t>(data.getData()));
63
+ return deserialize(bv);
64
+ }
65
+
66
+ /// Ensure that a std::any object is valid for this type. Throws
67
+ /// std::runtime_error if the object is not valid.
68
+ virtual void ensureValid(const std::any &obj) const {
69
+ throw std::runtime_error("Validation not implemented for type " + id);
70
+ }
71
+
72
+ // Check if a std::any object is valid for this type. Returns an optional
73
+ // error message if the object is not valid, else, std::nullopt.
74
+ std::optional<std::string> isValid(const std::any &obj) const {
75
+ try {
76
+ ensureValid(obj);
77
+ return std::nullopt;
78
+ } catch (const std::runtime_error &e) {
79
+ return e.what();
80
+ }
81
+ }
82
+
36
83
  protected:
37
84
  ID id;
38
85
  };
@@ -54,6 +101,8 @@ public:
54
101
  const ChannelVector &getChannels() const { return channels; }
55
102
  std::ptrdiff_t getBitWidth() const override { return -1; };
56
103
 
104
+ std::pair<const Type *, Direction> findChannel(std::string name) const;
105
+
57
106
  protected:
58
107
  ChannelVector channels;
59
108
  };
@@ -62,10 +111,15 @@ protected:
62
111
  /// carry one values of one type.
63
112
  class ChannelType : public Type {
64
113
  public:
114
+ using Type::deserialize;
65
115
  ChannelType(const ID &id, const Type *inner) : Type(id), inner(inner) {}
66
116
  const Type *getInner() const { return inner; }
67
117
  std::ptrdiff_t getBitWidth() const override { return inner->getBitWidth(); };
68
118
 
119
+ void ensureValid(const std::any &obj) const override;
120
+ MutableBitVector serialize(const std::any &obj) const override;
121
+ std::any deserialize(BitVector &data) const override;
122
+
69
123
  private:
70
124
  const Type *inner;
71
125
  };
@@ -73,9 +127,14 @@ private:
73
127
  /// The "void" type is a special type which can be used to represent no type.
74
128
  class VoidType : public Type {
75
129
  public:
130
+ using Type::deserialize;
76
131
  VoidType(const ID &id) : Type(id) {}
77
132
  // 'void' is 1 bit by convention.
78
133
  std::ptrdiff_t getBitWidth() const override { return 1; };
134
+
135
+ void ensureValid(const std::any &obj) const override;
136
+ MutableBitVector serialize(const std::any &obj) const override;
137
+ std::any deserialize(BitVector &data) const override;
79
138
  };
80
139
 
81
140
  /// The "any" type is a special type which can be used to represent any type, as
@@ -105,6 +164,11 @@ private:
105
164
  class BitsType : public BitVectorType {
106
165
  public:
107
166
  using BitVectorType::BitVectorType;
167
+ using Type::deserialize;
168
+
169
+ void ensureValid(const std::any &obj) const override;
170
+ MutableBitVector serialize(const std::any &obj) const override;
171
+ std::any deserialize(BitVector &data) const override;
108
172
  };
109
173
 
110
174
  /// Integers are bit vectors which may be signed or unsigned and are interpreted
@@ -118,21 +182,32 @@ public:
118
182
  class SIntType : public IntegerType {
119
183
  public:
120
184
  using IntegerType::IntegerType;
185
+ using Type::deserialize;
186
+
187
+ void ensureValid(const std::any &obj) const override;
188
+ MutableBitVector serialize(const std::any &obj) const override;
189
+ std::any deserialize(BitVector &data) const override;
121
190
  };
122
191
 
123
192
  /// Unsigned integer.
124
193
  class UIntType : public IntegerType {
125
194
  public:
126
195
  using IntegerType::IntegerType;
196
+ using Type::deserialize;
197
+
198
+ void ensureValid(const std::any &obj) const override;
199
+ MutableBitVector serialize(const std::any &obj) const override;
200
+ std::any deserialize(BitVector &data) const override;
127
201
  };
128
202
 
129
203
  /// Structs are an ordered collection of fields, each with a name and a type.
130
204
  class StructType : public Type {
131
205
  public:
132
206
  using FieldVector = std::vector<std::pair<std::string, const Type *>>;
207
+ using Type::deserialize;
133
208
 
134
- StructType(const ID &id, const FieldVector &fields)
135
- : Type(id), fields(fields) {}
209
+ StructType(const ID &id, const FieldVector &fields, bool reverse = true)
210
+ : Type(id), fields(fields), reverse(reverse) {}
136
211
 
137
212
  const FieldVector &getFields() const { return fields; }
138
213
  std::ptrdiff_t getBitWidth() const override {
@@ -146,18 +221,33 @@ public:
146
221
  return size;
147
222
  }
148
223
 
224
+ void ensureValid(const std::any &obj) const override;
225
+ MutableBitVector serialize(const std::any &obj) const override;
226
+ std::any deserialize(BitVector &data) const override;
227
+
228
+ // Returns whether this struct type should be reversed when
229
+ // serializing/deserializing.
230
+ // By default, a truthy value here makes StructType's compatible with system
231
+ // verilog, which has reversed struct field ordering, wrt. C/software struct
232
+ // ordering.
233
+ bool isReverse() const { return reverse; }
234
+
149
235
  private:
150
236
  FieldVector fields;
237
+ bool reverse;
151
238
  };
152
239
 
153
240
  /// Arrays have a compile time specified (static) size and an element type.
154
241
  class ArrayType : public Type {
155
242
  public:
156
- ArrayType(const ID &id, const Type *elementType, uint64_t size)
157
- : Type(id), elementType(elementType), size(size) {}
243
+ ArrayType(const ID &id, const Type *elementType, uint64_t size,
244
+ bool reverse = true)
245
+ : Type(id), elementType(elementType), size(size), reverse(reverse) {}
246
+ using Type::deserialize;
158
247
 
159
248
  const Type *getElementType() const { return elementType; }
160
249
  uint64_t getSize() const { return size; }
250
+ bool isReverse() const { return reverse; }
161
251
  std::ptrdiff_t getBitWidth() const override {
162
252
  std::ptrdiff_t elementSize = elementType->getBitWidth();
163
253
  if (elementSize < 0)
@@ -165,9 +255,17 @@ public:
165
255
  return elementSize * size;
166
256
  }
167
257
 
258
+ void ensureValid(const std::any &obj) const override;
259
+ MutableBitVector serialize(const std::any &obj) const override;
260
+ std::any deserialize(BitVector &data) const override;
261
+
168
262
  private:
169
263
  const Type *elementType;
170
264
  uint64_t size;
265
+ // 'reverse' controls whether array elements are reversed during
266
+ // serialization/deserialization (to match SystemVerilog/Python ordering
267
+ // expectations).
268
+ bool reverse;
171
269
  };
172
270
 
173
271
  } // namespace esi