esiaccel 0.1.5.dev205__cp39-cp39-win_amd64.whl → 0.1.5.dev533__cp39-cp39-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.
Files changed (45) 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 +12 -3
  10. esiaccel/abseil_dll.dll +0 -0
  11. esiaccel/accelerator.py +37 -5
  12. esiaccel/cares.dll +0 -0
  13. esiaccel/codegen.py +3 -3
  14. esiaccel/cosim/Cosim_Endpoint.sv +0 -18
  15. esiaccel/cosim/driver.cpp +6 -6
  16. esiaccel/cosim/driver.sv +14 -0
  17. esiaccel/cosim/questa.py +67 -4
  18. esiaccel/cosim/simulator.py +185 -38
  19. esiaccel/cosim/verilator.py +36 -5
  20. esiaccel/esiCppAccel.cp312-win_amd64.pyd +0 -0
  21. esiaccel/esiquery.exe +0 -0
  22. esiaccel/include/esi/Accelerator.h +3 -16
  23. esiaccel/include/esi/CLI.h +5 -5
  24. esiaccel/include/esi/Common.h +11 -1
  25. esiaccel/include/esi/Context.h +17 -9
  26. esiaccel/include/esi/Design.h +9 -4
  27. esiaccel/include/esi/Manifest.h +0 -2
  28. esiaccel/include/esi/Ports.h +72 -15
  29. esiaccel/include/esi/Services.h +50 -18
  30. esiaccel/include/esi/Types.h +108 -31
  31. esiaccel/include/esi/Values.h +313 -0
  32. esiaccel/libcrypto-3-x64.dll +0 -0
  33. esiaccel/libprotobuf.dll +0 -0
  34. esiaccel/libssl-3-x64.dll +0 -0
  35. esiaccel/re2.dll +0 -0
  36. esiaccel/types.py +6 -4
  37. esiaccel/zlib1.dll +0 -0
  38. {esiaccel-0.1.5.dev205.dist-info → esiaccel-0.1.5.dev533.dist-info}/METADATA +1 -1
  39. esiaccel-0.1.5.dev533.dist-info/RECORD +54 -0
  40. esiaccel/esiCppAccel.cp39-win_amd64.pyd +0 -0
  41. esiaccel-0.1.5.dev205.dist-info/RECORD +0 -46
  42. {esiaccel-0.1.5.dev205.dist-info → esiaccel-0.1.5.dev533.dist-info}/WHEEL +0 -0
  43. {esiaccel-0.1.5.dev205.dist-info → esiaccel-0.1.5.dev533.dist-info}/entry_points.txt +0 -0
  44. {esiaccel-0.1.5.dev205.dist-info → esiaccel-0.1.5.dev533.dist-info}/licenses/LICENSE +0 -0
  45. {esiaccel-0.1.5.dev205.dist-info → esiaccel-0.1.5.dev533.dist-info}/top_level.txt +0 -0
@@ -4,7 +4,7 @@
4
4
 
5
5
  import os
6
6
  from pathlib import Path
7
- from typing import List
7
+ from typing import List, Optional, Callable, Dict
8
8
 
9
9
  from .simulator import CosimCollateralDir, Simulator, SourceFiles
10
10
 
@@ -14,9 +14,29 @@ class Verilator(Simulator):
14
14
 
15
15
  DefaultDriver = CosimCollateralDir / "driver.cpp"
16
16
 
17
- def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
18
- super().__init__(sources, run_dir, debug)
19
-
17
+ def __init__(
18
+ self,
19
+ sources: SourceFiles,
20
+ run_dir: Path,
21
+ debug: bool,
22
+ run_stdout_callback: Optional[Callable[[str], None]] = None,
23
+ run_stderr_callback: Optional[Callable[[str], None]] = None,
24
+ compile_stdout_callback: Optional[Callable[[str], None]] = None,
25
+ compile_stderr_callback: Optional[Callable[[str], None]] = None,
26
+ make_default_logs: bool = True,
27
+ macro_definitions: Optional[Dict[str, str]] = None,
28
+ ):
29
+ super().__init__(
30
+ sources=sources,
31
+ run_dir=run_dir,
32
+ debug=debug,
33
+ run_stdout_callback=run_stdout_callback,
34
+ run_stderr_callback=run_stderr_callback,
35
+ compile_stdout_callback=compile_stdout_callback,
36
+ compile_stderr_callback=compile_stderr_callback,
37
+ make_default_logs=make_default_logs,
38
+ macro_definitions=macro_definitions,
39
+ )
20
40
  self.verilator = "verilator"
21
41
  if "VERILATOR_PATH" in os.environ:
22
42
  self.verilator = os.environ["VERILATOR_PATH"]
@@ -25,6 +45,15 @@ class Verilator(Simulator):
25
45
  cmd: List[str] = [
26
46
  self.verilator,
27
47
  "--cc",
48
+ ]
49
+
50
+ if self.macro_definitions:
51
+ cmd += [
52
+ f"+define+{k}={v}" if v is not None else f"+define+{k}"
53
+ for k, v in self.macro_definitions.items()
54
+ ]
55
+
56
+ cmd += [
28
57
  "--top-module",
29
58
  self.sources.top,
30
59
  "-DSIMULATION",
@@ -36,6 +65,7 @@ class Verilator(Simulator):
36
65
  "-j",
37
66
  "0",
38
67
  "--output-split",
68
+ "--autoflush",
39
69
  "--assert",
40
70
  str(Verilator.DefaultDriver),
41
71
  ]
@@ -44,7 +74,8 @@ class Verilator(Simulator):
44
74
  ]
45
75
  if self.debug:
46
76
  cmd += [
47
- "--trace", "--trace-params", "--trace-structs", "--trace-underscore"
77
+ "--trace-fst", "--trace-params", "--trace-structs",
78
+ "--trace-underscore"
48
79
  ]
49
80
  cflags.append("-DTRACE")
50
81
  if len(cflags) > 0:
Binary file
esiaccel/esiquery.exe CHANGED
Binary file
@@ -65,8 +65,8 @@ public:
65
65
  Accelerator(std::optional<ModuleInfo> info,
66
66
  std::vector<std::unique_ptr<Instance>> children,
67
67
  std::vector<services::Service *> services,
68
- std::vector<std::unique_ptr<BundlePort>> &ports)
69
- : HWModule(info, std::move(children), services, ports) {}
68
+ std::vector<std::unique_ptr<BundlePort>> &&ports)
69
+ : HWModule(info, std::move(children), services, std::move(ports)) {}
70
70
  };
71
71
 
72
72
  //===----------------------------------------------------------------------===//
@@ -86,13 +86,6 @@ public:
86
86
  /// Disconnect from the accelerator cleanly.
87
87
  virtual void disconnect();
88
88
 
89
- // While building the design, keep around a std::map of active services
90
- // indexed by the service name. When a new service is encountered during
91
- // descent, add it to the table (perhaps overwriting one). Modifications to
92
- // the table only apply to the current branch, so copy this and update it at
93
- // each level of the tree.
94
- using ServiceTable = std::map<std::string, services::Service *>;
95
-
96
89
  /// Return a pointer to the accelerator 'service' thread (or threads). If the
97
90
  /// thread(s) are not running, they will be started when this method is
98
91
  /// called. `std::thread` is used. If users don't want the runtime to spin up
@@ -165,7 +158,7 @@ private:
165
158
 
166
159
  /// Cache services via a unique_ptr so they get free'd automatically when
167
160
  /// Accelerator objects get deconstructed.
168
- using ServiceCacheKey = std::tuple<const std::type_info *, AppIDPath>;
161
+ using ServiceCacheKey = std::tuple<std::string, AppIDPath>;
169
162
  std::map<ServiceCacheKey, std::unique_ptr<Service>> serviceCache;
170
163
 
171
164
  std::unique_ptr<AcceleratorServiceThread> serviceThread;
@@ -176,12 +169,6 @@ private:
176
169
 
177
170
  namespace registry {
178
171
 
179
- // Connect to an ESI accelerator given a backend name and connection specifier.
180
- // Alternatively, instantiate the backend directly (if you're using C++).
181
- std::unique_ptr<AcceleratorConnection> connect(Context &ctxt,
182
- const std::string &backend,
183
- const std::string &connection);
184
-
185
172
  namespace internal {
186
173
 
187
174
  /// Backends can register themselves to be connected via a connection string.
@@ -51,19 +51,19 @@ public:
51
51
  ctxt = Context::withLogger<ConsoleLogger>(Logger::Level::Debug);
52
52
  else if (verbose)
53
53
  ctxt = Context::withLogger<ConsoleLogger>(Logger::Level::Info);
54
+ else
55
+ ctxt = Context::withLogger<ConsoleLogger>(Logger::Level::Warning);
54
56
  return 0;
55
57
  }
56
58
 
57
59
  /// Connect to the accelerator using the specified backend and connection.
58
- std::unique_ptr<AcceleratorConnection> connect() {
59
- return ctxt.connect(backend, connStr);
60
- }
60
+ AcceleratorConnection *connect() { return ctxt->connect(backend, connStr); }
61
61
 
62
62
  /// Get the context.
63
- Context &getContext() { return ctxt; }
63
+ Context &getContext() { return *ctxt; }
64
64
 
65
65
  protected:
66
- Context ctxt;
66
+ std::unique_ptr<Context> ctxt;
67
67
 
68
68
  std::string backend;
69
69
  std::string connStr;
@@ -43,6 +43,13 @@ struct AppID {
43
43
  return name == other.name && idx == other.idx;
44
44
  }
45
45
  bool operator!=(const AppID &other) const { return !(*this == other); }
46
+ friend std::ostream &operator<<(std::ostream &os, const AppID &id);
47
+
48
+ std::string toString() const {
49
+ if (idx.has_value())
50
+ return name + "[" + std::to_string(idx.value()) + "]";
51
+ return name;
52
+ }
46
53
  };
47
54
  bool operator<(const AppID &a, const AppID &b);
48
55
 
@@ -53,6 +60,7 @@ public:
53
60
  AppIDPath operator+(const AppIDPath &b) const;
54
61
  AppIDPath parent() const;
55
62
  std::string toStr() const;
63
+ friend std::ostream &operator<<(std::ostream &os, const AppIDPath &path);
56
64
  };
57
65
  bool operator<(const AppIDPath &a, const AppIDPath &b);
58
66
 
@@ -106,6 +114,8 @@ class MessageData {
106
114
  public:
107
115
  /// Adopts the data vector buffer.
108
116
  MessageData() = default;
117
+ MessageData(std::span<const uint8_t> data)
118
+ : data(data.data(), data.data() + data.size()) {}
109
119
  MessageData(std::vector<uint8_t> &data) : data(std::move(data)) {}
110
120
  MessageData(std::vector<uint8_t> &&data) : data(std::move(data)) {}
111
121
  MessageData(const uint8_t *data, size_t size) : data(data, data + size) {}
@@ -126,6 +136,7 @@ public:
126
136
 
127
137
  /// Get the size of the data in bytes.
128
138
  size_t getSize() const { return data.size(); }
139
+ size_t size() const { return getSize(); }
129
140
 
130
141
  /// Returns true if this message contains no data.
131
142
  bool empty() const { return data.empty(); }
@@ -158,7 +169,6 @@ private:
158
169
  } // namespace esi
159
170
 
160
171
  std::ostream &operator<<(std::ostream &, const esi::ModuleInfo &);
161
- std::ostream &operator<<(std::ostream &, const esi::AppID &);
162
172
 
163
173
  //===----------------------------------------------------------------------===//
164
174
  // Functions which should be in the standard library.
@@ -20,23 +20,30 @@
20
20
  #include "esi/Types.h"
21
21
 
22
22
  #include <exception>
23
+ #include <map>
23
24
  #include <memory>
24
- #include <optional>
25
+ #include <vector>
25
26
 
26
27
  namespace esi {
27
28
  class AcceleratorConnection;
28
29
 
29
30
  /// AcceleratorConnections, Accelerators, and Manifests must all share a
30
- /// context. It owns all the types, uniquifying them.
31
+ /// context. It owns all the types, uniquifying them. It also owns the
32
+ /// connections (which own the Accelerators). When it is destroyed, all
33
+ /// connections are disconnected and the objects are destroyed.
31
34
  class Context {
32
35
  public:
33
- Context() : logger(std::make_unique<ConsoleLogger>(Logger::Level::Warning)) {}
34
- Context(std::unique_ptr<Logger> logger) : logger(std::move(logger)) {}
36
+ Context();
37
+ Context(std::unique_ptr<Logger> logger);
38
+ ~Context();
39
+
40
+ /// Disconnect from all accelerators associated with this context.
41
+ void disconnectAll();
35
42
 
36
43
  /// Create a context with a specific logger type.
37
44
  template <typename T, typename... Args>
38
- static Context withLogger(Args &&...args) {
39
- return Context(std::make_unique<T>(args...));
45
+ static std::unique_ptr<Context> withLogger(Args &&...args) {
46
+ return std::make_unique<Context>(std::make_unique<T>(args...));
40
47
  }
41
48
 
42
49
  /// Resolve a type id to the type.
@@ -49,9 +56,9 @@ public:
49
56
  /// Register a type with the context. Takes ownership of the pointer type.
50
57
  void registerType(Type *type);
51
58
 
52
- /// Connect to an accelerator backend.
53
- std::unique_ptr<AcceleratorConnection> connect(std::string backend,
54
- std::string connection);
59
+ /// Connect to an accelerator backend. Retains ownership internally and
60
+ /// returns a non-owning pointer.
61
+ AcceleratorConnection *connect(std::string backend, std::string connection);
55
62
 
56
63
  /// Register a logger with the accelerator. Assumes ownership of the logger.
57
64
  void setLogger(std::unique_ptr<Logger> logger) {
@@ -63,6 +70,7 @@ public:
63
70
 
64
71
  private:
65
72
  std::unique_ptr<Logger> logger;
73
+ std::vector<std::unique_ptr<AcceleratorConnection>> connections;
66
74
 
67
75
  private:
68
76
  using TypeCache = std::map<Type::ID, std::unique_ptr<Type>>;
@@ -45,11 +45,15 @@ class Service;
45
45
 
46
46
  /// Represents either the top level or an instance of a hardware module.
47
47
  class HWModule {
48
+ public:
49
+ HWModule(const HWModule &) = delete;
50
+ HWModule &operator=(const HWModule &) = delete;
51
+
48
52
  protected:
49
53
  HWModule(std::optional<ModuleInfo> info,
50
54
  std::vector<std::unique_ptr<Instance>> children,
51
55
  std::vector<services::Service *> services,
52
- std::vector<std::unique_ptr<BundlePort>> &ports);
56
+ std::vector<std::unique_ptr<BundlePort>> &&ports);
53
57
 
54
58
  public:
55
59
  virtual ~HWModule() = default;
@@ -112,11 +116,12 @@ public:
112
116
  Instance(AppID id, std::optional<ModuleInfo> info,
113
117
  std::vector<std::unique_ptr<Instance>> children,
114
118
  std::vector<services::Service *> services,
115
- std::vector<std::unique_ptr<BundlePort>> &ports)
116
- : HWModule(info, std::move(children), services, ports), id(id) {}
119
+ std::vector<std::unique_ptr<BundlePort>> &&ports)
120
+ : HWModule(info, std::move(children), services, std::move(ports)),
121
+ id(id) {}
117
122
 
118
123
  /// Get the instance's ID, which it will always have.
119
- const AppID getID() const { return id; }
124
+ AppID getID() const { return id; }
120
125
 
121
126
  protected:
122
127
  const AppID id;
@@ -65,8 +65,6 @@ private:
65
65
 
66
66
  } // namespace esi
67
67
 
68
- std::ostream &operator<<(std::ostream &os, const esi::AppID &id);
69
- std::ostream &operator<<(std::ostream &, const esi::AppIDPath &);
70
68
  std::ostream &operator<<(std::ostream &, const esi::ModuleInfo &);
71
69
 
72
70
  #endif // ESI_MANIFEST_H
@@ -35,13 +35,63 @@ using PortMap = std::map<std::string, ChannelPort &>;
35
35
  /// but used by higher level APIs which add types.
36
36
  class ChannelPort {
37
37
  public:
38
- ChannelPort(const Type *type) : type(type) {}
38
+ ChannelPort(const Type *type);
39
39
  virtual ~ChannelPort() {}
40
40
 
41
- /// Set up a connection to the accelerator. The buffer size is optional and
42
- /// should be considered merely a hint. Individual implementations use it
43
- /// however they like. The unit is number of messages of the port type.
44
- virtual void connect(std::optional<unsigned> bufferSize = std::nullopt) = 0;
41
+ struct ConnectOptions {
42
+ /// The buffer size is optional and should be considered merely a hint.
43
+ /// Individual implementations use it however they like. The unit is number
44
+ /// of messages of the port type.
45
+ std::optional<unsigned> bufferSize = std::nullopt;
46
+
47
+ /// If the type of this port is a window, translate the incoming/outgoing
48
+ /// data into its underlying ('into') type. For 'into' types without lists,
49
+ /// just re-arranges the data fields from the lowered type to the 'into'
50
+ /// type.
51
+ ///
52
+ /// If this option is false, no translation is done and the data is
53
+ /// passed through as-is. Same is true for non-windowed types.
54
+ ///
55
+ /// For messages with lists, only two types are supported:
56
+ /// 1) Parallel encoding includes any 'header' data with each frame. Said
57
+ /// header data is the same across all frames, so this encoding is
58
+ /// inefficient but is commonly used for on-chip streaming interfaces.
59
+ /// Each frame contains a 'last' field to indicate the end of the list.
60
+ /// In cases where 'numItems' is greater than 1, a field named
61
+ /// '<listField>_size' indicates the number of valid items in that
62
+ /// frame.
63
+ /// 2) Serial (bulk transfer) encoding, where a 'header' frame precedes
64
+ /// the list data frame. Said header frame contains a 'count' field
65
+ /// indicating the number of items in the list. Importantly, the
66
+ /// header frame is always re-transmitted after the specified number of
67
+ /// list items have been sent. If the 'count' field is zero, the end of
68
+ /// the list has been reached. If it is non-zero, the message has not
69
+ /// been completely transmitted and reading should continue until a
70
+ /// 'count' of zero is received.
71
+ ///
72
+ /// In both cases, the returned MessageData contains the complete header
73
+ /// followed by the list data. In other words, header data is not duplicated
74
+ /// in the returned message.
75
+ ///
76
+ /// Important note: for consistency, preserves SystemVerilog struct field
77
+ /// ordering! So it's the opposite of C struct ordering.
78
+ ///
79
+ /// Implementation status:
80
+ /// - Lists are not yet supported.
81
+ /// - Write ports are not yet supported.
82
+ /// - Fields must be byte-aligned.
83
+ ///
84
+ /// See the CIRCT documentation (or td files) for more details on windowed
85
+ /// messages.
86
+ bool translateMessage = true;
87
+
88
+ ConnectOptions(std::optional<unsigned> bufferSize = std::nullopt,
89
+ bool translateMessage = true)
90
+ : bufferSize(bufferSize), translateMessage(translateMessage) {}
91
+ };
92
+
93
+ /// Set up a connection to the accelerator.
94
+ virtual void connect(const ConnectOptions &options = ConnectOptions()) = 0;
45
95
  virtual void disconnect() = 0;
46
96
  virtual bool isConnected() const = 0;
47
97
 
@@ -63,6 +113,7 @@ public:
63
113
 
64
114
  protected:
65
115
  const Type *type;
116
+ const WindowType *translationType;
66
117
 
67
118
  /// Method called by poll() to actually poll the channel if the channel is
68
119
  /// connected.
@@ -70,7 +121,7 @@ protected:
70
121
 
71
122
  /// Called by all connect methods to let backends initiate the underlying
72
123
  /// connections.
73
- virtual void connectImpl(std::optional<unsigned> bufferSize) {}
124
+ virtual void connectImpl(const ConnectOptions &options) {}
74
125
  };
75
126
 
76
127
  /// A ChannelPort which sends data to the accelerator.
@@ -78,9 +129,8 @@ class WriteChannelPort : public ChannelPort {
78
129
  public:
79
130
  using ChannelPort::ChannelPort;
80
131
 
81
- virtual void
82
- connect(std::optional<unsigned> bufferSize = std::nullopt) override {
83
- connectImpl(bufferSize);
132
+ virtual void connect(const ConnectOptions &options = {}) override {
133
+ connectImpl(options);
84
134
  connected = true;
85
135
  }
86
136
  virtual void disconnect() override { connected = false; }
@@ -105,7 +155,7 @@ public:
105
155
  UnknownWriteChannelPort(const Type *type, std::string errmsg)
106
156
  : WriteChannelPort(type), errmsg(errmsg) {}
107
157
 
108
- void connect(std::optional<unsigned> bufferSize = std::nullopt) override {
158
+ void connect(const ConnectOptions &options = {}) override {
109
159
  throw std::runtime_error(errmsg);
110
160
  }
111
161
  void write(const MessageData &) override { throw std::runtime_error(errmsg); }
@@ -143,7 +193,7 @@ public:
143
193
  //===--------------------------------------------------------------------===//
144
194
 
145
195
  virtual void connect(std::function<bool(MessageData)> callback,
146
- std::optional<unsigned> bufferSize = std::nullopt);
196
+ const ConnectOptions &options = {});
147
197
 
148
198
  //===--------------------------------------------------------------------===//
149
199
  // Polling mode methods: To use futures or blocking reads, connect without any
@@ -154,8 +204,7 @@ public:
154
204
  static constexpr uint64_t DefaultMaxDataQueueMsgs = 32;
155
205
 
156
206
  /// Connect to the channel in polling mode.
157
- virtual void
158
- connect(std::optional<unsigned> bufferSize = std::nullopt) override;
207
+ virtual void connect(const ConnectOptions &options = {}) override;
159
208
 
160
209
  /// Asynchronous read.
161
210
  virtual std::future<MessageData> readAsync();
@@ -184,6 +233,14 @@ protected:
184
233
  /// Backends call this callback when new data is available.
185
234
  std::function<bool(MessageData)> callback;
186
235
 
236
+ /// Window translation support.
237
+ std::vector<uint8_t> translationBuffer;
238
+ /// Index of the next expected frame (for multi-frame windows).
239
+ size_t nextFrameIndex = 0;
240
+ /// Translate incoming data if the port type is a window type. Returns true if
241
+ /// the message has been completely received.
242
+ bool translateIncoming(MessageData &data);
243
+
187
244
  //===--------------------------------------------------------------------===//
188
245
  // Polling mode members.
189
246
  //===--------------------------------------------------------------------===//
@@ -206,10 +263,10 @@ public:
206
263
  : ReadChannelPort(type), errmsg(errmsg) {}
207
264
 
208
265
  void connect(std::function<bool(MessageData)> callback,
209
- std::optional<unsigned> bufferSize = std::nullopt) override {
266
+ const ConnectOptions &options = ConnectOptions()) override {
210
267
  throw std::runtime_error(errmsg);
211
268
  }
212
- void connect(std::optional<unsigned> bufferSize = std::nullopt) override {
269
+ void connect(const ConnectOptions &options = ConnectOptions()) override {
213
270
  throw std::runtime_error(errmsg);
214
271
  }
215
272
  std::future<MessageData> readAsync() override {
@@ -25,10 +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;
31
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
+
32
43
  namespace services {
33
44
 
34
45
  /// Add a custom interface to a service client at a particular point in the
@@ -38,7 +49,9 @@ public:
38
49
  using BundlePort::BundlePort;
39
50
  virtual ~ServicePort() = default;
40
51
  // Get a description of the service port.
41
- virtual std::optional<std::string> toString() const { return std::nullopt; }
52
+ virtual std::optional<std::string> toString(bool oneLine = false) const {
53
+ return std::nullopt;
54
+ }
42
55
  };
43
56
 
44
57
  /// Parent class of all APIs modeled as 'services'. May or may not map to a
@@ -170,7 +183,8 @@ public:
170
183
  /// Write a 64-bit value to this region, not the global address space.
171
184
  virtual void write(uint32_t addr, uint64_t data);
172
185
 
173
- virtual std::optional<std::string> toString() const override {
186
+ virtual std::optional<std::string>
187
+ toString(bool oneLine = false) const override {
174
188
  return "MMIO region " + toHex(desc.base) + " - " +
175
189
  toHex(desc.base + desc.size);
176
190
  }
@@ -282,10 +296,12 @@ public:
282
296
  ->getInner();
283
297
  }
284
298
 
285
- virtual std::optional<std::string> toString() const override {
299
+ virtual std::optional<std::string>
300
+ toString(bool oneLine = false) const override {
286
301
  const esi::Type *argType = getArgType();
287
302
  const esi::Type *resultType = getResultType();
288
- return "function " + resultType->getID() + "(" + argType->getID() + ")";
303
+ return "function " + resultType->toString(oneLine) + "(" +
304
+ argType->toString(oneLine) + ")";
289
305
  }
290
306
 
291
307
  private:
@@ -338,10 +354,12 @@ public:
338
354
  ->getInner();
339
355
  }
340
356
 
341
- virtual std::optional<std::string> toString() const override {
357
+ virtual std::optional<std::string>
358
+ toString(bool oneLine = false) const override {
342
359
  const esi::Type *argType = getArgType();
343
360
  const esi::Type *resultType = getResultType();
344
- return "callback " + resultType->getID() + "(" + argType->getID() + ")";
361
+ return "callback " + resultType->toString(oneLine) + "(" +
362
+ argType->toString(oneLine) + ")";
345
363
  }
346
364
 
347
365
  private:
@@ -365,37 +383,51 @@ public:
365
383
  virtual std::string getServiceSymbol() const override;
366
384
  virtual BundlePort *getPort(AppIDPath id,
367
385
  const BundleType *type) const override;
386
+ virtual Service *getChildService(Service::Type service, AppIDPath id = {},
387
+ std::string implName = {},
388
+ ServiceImplDetails details = {},
389
+ HWClientDetails clients = {}) override;
390
+ MMIO::MMIORegion *getMMIORegion() const;
368
391
 
369
392
  /// A telemetry port which gets attached to a service port.
370
- class Telemetry : public ServicePort {
393
+ class Metric : public ServicePort {
371
394
  friend class TelemetryService;
372
- Telemetry(AppID id, const BundleType *type, PortMap channels);
395
+ Metric(AppID id, const BundleType *type, PortMap channels,
396
+ const TelemetryService *telemetryService,
397
+ std::optional<uint64_t> offset);
373
398
 
374
399
  public:
375
- static Telemetry *get(AppID id, BundleType *type, WriteChannelPort &get,
376
- ReadChannelPort &data);
377
-
378
400
  void connect();
379
401
  std::future<MessageData> read();
402
+ uint64_t readInt();
380
403
 
381
- virtual std::optional<std::string> toString() const override {
404
+ virtual std::optional<std::string>
405
+ toString(bool oneLine = false) const override {
382
406
  const esi::Type *dataType =
383
407
  dynamic_cast<const ChannelType *>(type->findChannel("data").first)
384
408
  ->getInner();
385
- return "telemetry " + dataType->getID();
409
+ return "telemetry " + dataType->toString(oneLine);
386
410
  }
387
411
 
388
412
  private:
389
- WriteChannelPort *get_req;
390
- ReadChannelPort *data;
413
+ const TelemetryService *telemetryService;
414
+ MMIO::MMIORegion *mmio;
415
+ std::optional<uint64_t> offset;
391
416
  };
392
417
 
393
- const std::map<AppIDPath, Telemetry *> &getTelemetryPorts() {
394
- return telemetryPorts;
418
+ std::map<AppIDPath, Metric *> getTelemetryPorts() {
419
+ std::map<AppIDPath, Metric *> ports;
420
+ getTelemetryPorts(ports);
421
+ return ports;
395
422
  }
423
+ void getTelemetryPorts(std::map<AppIDPath, Metric *> &ports);
396
424
 
397
425
  private:
398
- mutable std::map<AppIDPath, Telemetry *> telemetryPorts;
426
+ AppIDPath id;
427
+ mutable MMIO::MMIORegion *mmio;
428
+ std::map<AppIDPath, uint64_t> portAddressAssignments;
429
+ mutable std::map<AppIDPath, Metric *> telemetryPorts;
430
+ std::list<TelemetryService *> children;
399
431
  };
400
432
 
401
433
  /// Registry of services which can be instantiated directly by the Accelerator