esiaccel 0.0.17.dev447__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 (54) 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 +7 -0
  12. esiaccel/cares.dll +0 -0
  13. esiaccel/cmake/esiaccelConfig.cmake +1 -1
  14. esiaccel/cosim/Cosim_DpiPkg.sv +85 -0
  15. esiaccel/cosim/Cosim_Endpoint.sv +218 -0
  16. esiaccel/cosim/Cosim_Manifest.sv +32 -0
  17. esiaccel/cosim/driver.cpp +131 -0
  18. esiaccel/cosim/driver.sv +74 -0
  19. esiaccel/cosim/questa.py +141 -0
  20. esiaccel/cosim/simulator.py +382 -0
  21. esiaccel/cosim/verilator.py +92 -0
  22. esiaccel/esi-cosim.py +104 -0
  23. esiaccel/esiCppAccel.cp310-win_amd64.pyd +0 -0
  24. esiaccel/esiquery.exe +0 -0
  25. esiaccel/include/esi/Accelerator.h +31 -15
  26. esiaccel/include/esi/CLI.h +77 -0
  27. esiaccel/include/esi/Common.h +32 -3
  28. esiaccel/include/esi/Context.h +1 -1
  29. esiaccel/include/esi/Design.h +11 -4
  30. esiaccel/include/esi/Engines.h +124 -0
  31. esiaccel/include/esi/Logging.h +57 -7
  32. esiaccel/include/esi/Manifest.h +0 -2
  33. esiaccel/include/esi/Ports.h +47 -6
  34. esiaccel/include/esi/Services.h +144 -41
  35. esiaccel/include/esi/Types.h +103 -5
  36. esiaccel/include/esi/Values.h +313 -0
  37. esiaccel/include/esi/backends/Cosim.h +85 -0
  38. esiaccel/include/esi/backends/RpcServer.h +55 -0
  39. esiaccel/include/esi/backends/Trace.h +5 -6
  40. esiaccel/libcrypto-3-x64.dll +0 -0
  41. esiaccel/libprotobuf.dll +0 -0
  42. esiaccel/libssl-3-x64.dll +0 -0
  43. esiaccel/re2.dll +0 -0
  44. esiaccel/types.py +132 -26
  45. esiaccel/utils.py +21 -3
  46. esiaccel/zlib1.dll +0 -0
  47. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/METADATA +3 -3
  48. esiaccel-0.1.5.dev406.dist-info/RECORD +54 -0
  49. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/WHEEL +1 -1
  50. esiaccel/bin/esiquery.exe +0 -0
  51. esiaccel-0.0.17.dev447.dist-info/RECORD +0 -28
  52. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info}/entry_points.txt +0 -0
  53. {esiaccel-0.0.17.dev447.dist-info → esiaccel-0.1.5.dev406.dist-info/licenses}/LICENSE +0 -0
  54. {esiaccel-0.0.17.dev447.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 --
@@ -96,6 +99,24 @@ private:
96
99
  volatile bool connected = false;
97
100
  };
98
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
+
99
120
  /// A ChannelPort which reads data from the accelerator. It has two modes:
100
121
  /// Callback and Polling which cannot be used at the same time. The mode is set
101
122
  /// at connect() time. To change the mode, disconnect() and then connect()
@@ -178,6 +199,27 @@ protected:
178
199
  std::queue<std::promise<MessageData>> promiseQueue;
179
200
  };
180
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
+
181
223
  /// Services provide connections to 'bundles' -- collections of named,
182
224
  /// unidirectional communication channels. This class provides access to those
183
225
  /// ChannelPorts.
@@ -190,7 +232,7 @@ public:
190
232
  }
191
233
 
192
234
  /// Construct a port.
193
- BundlePort(AppID id, std::map<std::string, ChannelPort &> channels);
235
+ BundlePort(AppID id, const BundleType *type, PortMap channels);
194
236
  virtual ~BundlePort() = default;
195
237
 
196
238
  /// Get the ID of the port.
@@ -202,9 +244,7 @@ public:
202
244
  /// ordinary users should not use. You have been warned.
203
245
  WriteChannelPort &getRawWrite(const std::string &name) const;
204
246
  ReadChannelPort &getRawRead(const std::string &name) const;
205
- const std::map<std::string, ChannelPort &> &getChannels() const {
206
- return channels;
207
- }
247
+ const PortMap &getChannels() const { return channels; }
208
248
 
209
249
  /// Cast this Bundle port to a subclass which is actually useful. Returns
210
250
  /// nullptr if the cast fails.
@@ -224,9 +264,10 @@ public:
224
264
  return result;
225
265
  }
226
266
 
227
- private:
267
+ protected:
228
268
  AppID id;
229
- std::map<std::string, ChannelPort &> channels;
269
+ const BundleType *type;
270
+ PortMap channels;
230
271
  };
231
272
 
232
273
  } // namespace esi
@@ -25,9 +25,21 @@
25
25
  #include "esi/Ports.h"
26
26
 
27
27
  #include <cstdint>
28
+ #include <list>
28
29
 
29
30
  namespace esi {
30
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
+
31
43
  namespace services {
32
44
 
33
45
  /// Add a custom interface to a service client at a particular point in the
@@ -45,6 +57,7 @@ public:
45
57
  class Service {
46
58
  public:
47
59
  using Type = const std::type_info &;
60
+ Service(AcceleratorConnection &conn) : conn(conn) {}
48
61
  virtual ~Service() = default;
49
62
 
50
63
  virtual std::string getServiceSymbol() const = 0;
@@ -56,19 +69,21 @@ public:
56
69
  /// calling the `getService` method on `AcceleratorConnection` to get the
57
70
  /// global service, implying that the child service does not need to use the
58
71
  /// service it is replacing.
59
- virtual Service *getChildService(AcceleratorConnection *conn,
60
- Service::Type service, AppIDPath id = {},
72
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
61
73
  std::string implName = {},
62
74
  ServiceImplDetails details = {},
63
75
  HWClientDetails clients = {});
64
76
 
65
77
  /// Get specialized port for this service to attach to the given appid path.
66
78
  /// Null returns mean nothing to attach.
67
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
68
- const std::map<std::string, ChannelPort &> &,
69
- AcceleratorConnection &) const {
79
+ virtual BundlePort *getPort(AppIDPath id, const BundleType *type) const {
70
80
  return nullptr;
71
81
  }
82
+
83
+ AcceleratorConnection &getConnection() const { return conn; }
84
+
85
+ protected:
86
+ AcceleratorConnection &conn;
72
87
  };
73
88
 
74
89
  /// A service for which there are no standard services registered. Requires
@@ -76,13 +91,16 @@ public:
76
91
  /// the ones in StdServices.h.
77
92
  class CustomService : public Service {
78
93
  public:
79
- CustomService(AppIDPath idPath, const ServiceImplDetails &details,
94
+ CustomService(AppIDPath idPath, AcceleratorConnection &,
95
+ const ServiceImplDetails &details,
80
96
  const HWClientDetails &clients);
81
97
  virtual ~CustomService() = default;
82
98
 
83
99
  virtual std::string getServiceSymbol() const override {
84
100
  return serviceSymbol;
85
101
  }
102
+ virtual BundlePort *getPort(AppIDPath id,
103
+ const BundleType *type) const override;
86
104
 
87
105
  protected:
88
106
  std::string serviceSymbol;
@@ -92,6 +110,7 @@ protected:
92
110
  /// Information about the Accelerator system.
93
111
  class SysInfo : public Service {
94
112
  public:
113
+ using Service::Service;
95
114
  virtual ~SysInfo() = default;
96
115
 
97
116
  virtual std::string getServiceSymbol() const override;
@@ -116,9 +135,8 @@ public:
116
135
  uint32_t size;
117
136
  };
118
137
 
119
- MMIO(Context &ctxt, AppIDPath idPath, std::string implName,
120
- const ServiceImplDetails &details, const HWClientDetails &clients);
121
- MMIO() = default;
138
+ MMIO(AcceleratorConnection &, const AppIDPath &idPath,
139
+ const HWClientDetails &clients);
122
140
  virtual ~MMIO() = default;
123
141
 
124
142
  /// Read a 64-bit value from the global MMIO space.
@@ -133,8 +151,7 @@ public:
133
151
 
134
152
  /// If the service is a MMIO service, return a region of the MMIO space which
135
153
  /// peers into ours.
136
- virtual Service *getChildService(AcceleratorConnection *conn,
137
- Service::Type service, AppIDPath id = {},
154
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
138
155
  std::string implName = {},
139
156
  ServiceImplDetails details = {},
140
157
  HWClientDetails clients = {}) override;
@@ -142,9 +159,8 @@ public:
142
159
  virtual std::string getServiceSymbol() const override;
143
160
 
144
161
  /// Get a MMIO region port for a particular region descriptor.
145
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
146
- const std::map<std::string, ChannelPort &> &,
147
- AcceleratorConnection &) const override;
162
+ virtual BundlePort *getPort(AppIDPath id,
163
+ const BundleType *type) const override;
148
164
 
149
165
  private:
150
166
  /// MMIO base address table.
@@ -193,6 +209,9 @@ private:
193
209
 
194
210
  class HostMem : public Service {
195
211
  public:
212
+ static constexpr std::string_view StdName = "esi.service.std.hostmem";
213
+
214
+ using Service::Service;
196
215
  virtual ~HostMem() = default;
197
216
  virtual std::string getServiceSymbol() const override;
198
217
 
@@ -200,9 +219,19 @@ public:
200
219
  /// deconstructed.
201
220
  struct HostMemRegion {
202
221
  virtual ~HostMemRegion() = default;
222
+ /// Get a pointer to the host memory.
203
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(); }
204
227
  operator void *() const { return getPtr(); }
205
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() {}
206
235
  };
207
236
 
208
237
  /// Options for allocating host memory.
@@ -234,39 +263,47 @@ public:
234
263
  /// Service for calling functions.
235
264
  class FuncService : public Service {
236
265
  public:
237
- FuncService(AcceleratorConnection *acc, AppIDPath id,
238
- const std::string &implName, ServiceImplDetails details,
266
+ FuncService(AppIDPath id, AcceleratorConnection &, ServiceImplDetails details,
239
267
  HWClientDetails clients);
240
268
 
241
269
  virtual std::string getServiceSymbol() const override;
242
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
243
- const std::map<std::string, ChannelPort &> &,
244
- AcceleratorConnection &) const override;
270
+ virtual BundlePort *getPort(AppIDPath id,
271
+ const BundleType *type) const override;
245
272
 
246
273
  /// A function call which gets attached to a service port.
247
274
  class Function : public ServicePort {
248
275
  friend class FuncService;
249
- Function(AppID id, const std::map<std::string, ChannelPort &> &channels);
276
+ using ServicePort::ServicePort;
250
277
 
251
278
  public:
252
- static Function *get(AppID id, WriteChannelPort &arg,
279
+ static Function *get(AppID id, BundleType *type, WriteChannelPort &arg,
253
280
  ReadChannelPort &result);
254
281
 
255
282
  void connect();
256
283
  std::future<MessageData> call(const MessageData &arg);
257
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
+
258
296
  virtual std::optional<std::string> toString() const override {
259
- const esi::Type *argType =
260
- dynamic_cast<const ChannelType *>(arg.getType())->getInner();
261
- const esi::Type *resultType =
262
- dynamic_cast<const ChannelType *>(result.getType())->getInner();
297
+ const esi::Type *argType = getArgType();
298
+ const esi::Type *resultType = getResultType();
263
299
  return "function " + resultType->getID() + "(" + argType->getID() + ")";
264
300
  }
265
301
 
266
302
  private:
267
303
  std::mutex callMutex;
268
- WriteChannelPort &arg;
269
- ReadChannelPort &result;
304
+ WriteChannelPort *arg;
305
+ ReadChannelPort *result;
306
+ bool connected = false;
270
307
  };
271
308
 
272
309
  private:
@@ -276,23 +313,23 @@ private:
276
313
  /// Service for servicing function calls from the accelerator.
277
314
  class CallService : public Service {
278
315
  public:
279
- CallService(AcceleratorConnection *acc, AppIDPath id, std::string implName,
280
- ServiceImplDetails details, HWClientDetails clients);
316
+ CallService(AcceleratorConnection &acc, AppIDPath id,
317
+ ServiceImplDetails details);
281
318
 
282
319
  virtual std::string getServiceSymbol() const override;
283
- virtual ServicePort *getPort(AppIDPath id, const BundleType *type,
284
- const std::map<std::string, ChannelPort &> &,
285
- AcceleratorConnection &) const override;
320
+ virtual BundlePort *getPort(AppIDPath id,
321
+ const BundleType *type) const override;
286
322
 
287
323
  /// A function call which gets attached to a service port.
288
324
  class Callback : public ServicePort {
289
325
  friend class CallService;
290
- Callback(AcceleratorConnection &acc, AppID id,
291
- const std::map<std::string, ChannelPort &> &channels);
326
+ Callback(AcceleratorConnection &acc, AppID id, const BundleType *,
327
+ PortMap channels);
292
328
 
293
329
  public:
294
330
  static Callback *get(AcceleratorConnection &acc, AppID id,
295
- WriteChannelPort &result, ReadChannelPort &arg);
331
+ const BundleType *type, WriteChannelPort &result,
332
+ ReadChannelPort &arg);
296
333
 
297
334
  /// Connect a callback to code which will be executed when the accelerator
298
335
  /// invokes the callback. The 'quick' flag indicates that the callback is
@@ -301,17 +338,26 @@ public:
301
338
  void connect(std::function<MessageData(const MessageData &)> callback,
302
339
  bool quick = false);
303
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
+
304
352
  virtual std::optional<std::string> toString() const override {
305
- const esi::Type *argType =
306
- dynamic_cast<const ChannelType *>(arg.getType())->getInner();
307
- const esi::Type *resultType =
308
- dynamic_cast<const ChannelType *>(result.getType())->getInner();
353
+ const esi::Type *argType = getArgType();
354
+ const esi::Type *resultType = getResultType();
309
355
  return "callback " + resultType->getID() + "(" + argType->getID() + ")";
310
356
  }
311
357
 
312
358
  private:
313
- ReadChannelPort &arg;
314
- WriteChannelPort &result;
359
+ ReadChannelPort *arg;
360
+ WriteChannelPort *result;
315
361
  AcceleratorConnection &acc;
316
362
  };
317
363
 
@@ -319,6 +365,63 @@ private:
319
365
  std::string symbol;
320
366
  };
321
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
+
322
425
  /// Registry of services which can be instantiated directly by the Accelerator
323
426
  /// class if the backend doesn't do anything special with a service.
324
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