esiaccel 0.1.5.dev66__cp39-cp39-win_amd64.whl → 0.1.5.dev450__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 (44) 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 +22 -4
  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 +61 -32
  15. esiaccel/cosim/driver.cpp +6 -6
  16. esiaccel/cosim/driver.sv +14 -0
  17. esiaccel/cosim/questa.py +141 -0
  18. esiaccel/cosim/simulator.py +382 -0
  19. esiaccel/cosim/verilator.py +92 -0
  20. esiaccel/esi-cosim.py +3 -322
  21. esiaccel/esiCppAccel.cp39-win_amd64.pyd +0 -0
  22. esiaccel/esiquery.exe +0 -0
  23. esiaccel/include/esi/Accelerator.h +1 -14
  24. esiaccel/include/esi/CLI.h +5 -5
  25. esiaccel/include/esi/Common.h +17 -1
  26. esiaccel/include/esi/Context.h +17 -9
  27. esiaccel/include/esi/Manifest.h +0 -2
  28. esiaccel/include/esi/Services.h +60 -22
  29. esiaccel/include/esi/Types.h +107 -10
  30. esiaccel/include/esi/Values.h +313 -0
  31. esiaccel/libcrypto-3-x64.dll +0 -0
  32. esiaccel/libprotobuf.dll +0 -0
  33. esiaccel/libssl-3-x64.dll +0 -0
  34. esiaccel/re2.dll +0 -0
  35. esiaccel/types.py +13 -5
  36. esiaccel/utils.py +11 -1
  37. esiaccel/zlib1.dll +0 -0
  38. {esiaccel-0.1.5.dev66.dist-info → esiaccel-0.1.5.dev450.dist-info}/METADATA +1 -1
  39. esiaccel-0.1.5.dev450.dist-info/RECORD +54 -0
  40. esiaccel-0.1.5.dev66.dist-info/RECORD +0 -43
  41. {esiaccel-0.1.5.dev66.dist-info → esiaccel-0.1.5.dev450.dist-info}/WHEEL +0 -0
  42. {esiaccel-0.1.5.dev66.dist-info → esiaccel-0.1.5.dev450.dist-info}/entry_points.txt +0 -0
  43. {esiaccel-0.1.5.dev66.dist-info → esiaccel-0.1.5.dev450.dist-info}/licenses/LICENSE +0 -0
  44. {esiaccel-0.1.5.dev66.dist-info → esiaccel-0.1.5.dev450.dist-info}/top_level.txt +0 -0
esiaccel/esi-cosim.py CHANGED
@@ -14,333 +14,14 @@
14
14
  # ===----------------------------------------------------------------------===//
15
15
 
16
16
  import argparse
17
- import os
18
17
  from pathlib import Path
19
- import re
20
- import signal
21
- import socket
22
- import subprocess
23
18
  import sys
24
19
  import textwrap
25
- import time
26
20
  from typing import Dict, List
27
21
 
28
- _thisdir = Path(__file__).parent
29
- CosimCollateralDir = _thisdir.parent / "cosim"
30
-
31
-
32
- def is_port_open(port) -> bool:
33
- """Check if a TCP port is open locally."""
34
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35
- result = sock.connect_ex(('127.0.0.1', port))
36
- sock.close()
37
- return True if result == 0 else False
38
-
39
-
40
- class SourceFiles:
41
-
42
- def __init__(self, top: str) -> None:
43
- # User source files.
44
- self.user: List[Path] = []
45
- # DPI shared objects.
46
- self.dpi_so: List[str] = ["EsiCosimDpiServer"]
47
- # DPI SV files.
48
- self.dpi_sv: List[Path] = [
49
- CosimCollateralDir / "Cosim_DpiPkg.sv",
50
- CosimCollateralDir / "Cosim_Endpoint.sv",
51
- CosimCollateralDir / "Cosim_Manifest.sv",
52
- ]
53
- # Name of the top module.
54
- self.top = top
55
-
56
- def add_dir(self, dir: Path):
57
- """Add all the RTL files in a directory to the source list."""
58
- for file in sorted(dir.iterdir()):
59
- if file.is_file() and (file.suffix == ".sv" or file.suffix == ".v"):
60
- self.user.append(file)
61
- elif file.is_dir():
62
- self.add_dir(file)
63
-
64
- def dpi_so_paths(self) -> List[Path]:
65
- """Return a list of all the DPI shared object files."""
66
-
67
- def find_so(name: str) -> Path:
68
- for path in Simulator.get_env().get("LD_LIBRARY_PATH", "").split(":"):
69
- if os.name == "nt":
70
- so = Path(path) / f"{name}.dll"
71
- else:
72
- so = Path(path) / f"lib{name}.so"
73
- if so.exists():
74
- return so
75
- raise FileNotFoundError(f"Could not find {name}.so in LD_LIBRARY_PATH")
76
-
77
- return [find_so(name) for name in self.dpi_so]
78
-
79
- @property
80
- def rtl_sources(self) -> List[Path]:
81
- """Return a list of all the RTL source files."""
82
- return self.dpi_sv + self.user
83
-
84
-
85
- class Simulator:
86
-
87
- # Some RTL simulators don't use stderr for error messages. Everything goes to
88
- # stdout. Boo! They should feel bad about this. Also, they can specify that
89
- # broken behavior by overriding this.
90
- UsesStderr = True
91
-
92
- def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
93
- self.sources = sources
94
- self.run_dir = run_dir
95
- self.debug = debug
96
-
97
- @staticmethod
98
- def get_env() -> Dict[str, str]:
99
- """Get the environment variables to locate shared objects."""
100
-
101
- env = os.environ.copy()
102
- env["LIBRARY_PATH"] = env.get("LIBRARY_PATH", "") + ":" + str(
103
- _thisdir.parent / "lib")
104
- env["LD_LIBRARY_PATH"] = env.get("LD_LIBRARY_PATH", "") + ":" + str(
105
- _thisdir.parent / "lib")
106
- return env
107
-
108
- def compile_commands(self) -> List[List[str]]:
109
- """Compile the sources. Returns the exit code of the simulation compiler."""
110
- assert False, "Must be implemented by subclass"
111
-
112
- def compile(self) -> int:
113
- cmds = self.compile_commands()
114
- self.run_dir.mkdir(parents=True, exist_ok=True)
115
- with (self.run_dir / "compile_stdout.log").open("w") as stdout, (
116
- self.run_dir / "compile_stderr.log").open("w") as stderr:
117
- for cmd in cmds:
118
- stderr.write(" ".join(cmd) + "\n")
119
- cp = subprocess.run(cmd,
120
- env=Simulator.get_env(),
121
- capture_output=True,
122
- text=True)
123
- stdout.write(cp.stdout)
124
- stderr.write(cp.stderr)
125
- if cp.returncode != 0:
126
- print("====== Compilation failure:")
127
- if self.UsesStderr:
128
- print(cp.stderr)
129
- else:
130
- print(cp.stdout)
131
- return cp.returncode
132
- return 0
133
-
134
- def run_command(self, gui: bool) -> List[str]:
135
- """Return the command to run the simulation."""
136
- assert False, "Must be implemented by subclass"
137
-
138
- def run(self,
139
- inner_command: str,
140
- gui: bool = False,
141
- server_only: bool = False) -> int:
142
- """Start the simulation then run the command specified. Kill the simulation
143
- when the command exits."""
144
-
145
- # 'simProc' is accessed in the finally block. Declare it here to avoid
146
- # syntax errors in that block.
147
- simProc = None
148
- try:
149
- # Open log files
150
- self.run_dir.mkdir(parents=True, exist_ok=True)
151
- simStdout = open(self.run_dir / "sim_stdout.log", "w")
152
- simStderr = open(self.run_dir / "sim_stderr.log", "w")
153
-
154
- # Erase the config file if it exists. We don't want to read
155
- # an old config.
156
- portFileName = self.run_dir / "cosim.cfg"
157
- if os.path.exists(portFileName):
158
- os.remove(portFileName)
159
-
160
- # Run the simulation.
161
- simEnv = Simulator.get_env()
162
- if self.debug:
163
- simEnv["COSIM_DEBUG_FILE"] = "cosim_debug.log"
164
- if "DEBUG_PERIOD" not in simEnv:
165
- # Slow the simulation down to one tick per millisecond.
166
- simEnv["DEBUG_PERIOD"] = "1"
167
- simProc = subprocess.Popen(self.run_command(gui),
168
- stdout=simStdout,
169
- stderr=simStderr,
170
- env=simEnv,
171
- cwd=self.run_dir,
172
- preexec_fn=os.setsid)
173
- simStderr.close()
174
- simStdout.close()
175
-
176
- # Get the port which the simulation RPC selected.
177
- checkCount = 0
178
- while (not os.path.exists(portFileName)) and \
179
- simProc.poll() is None:
180
- time.sleep(0.1)
181
- checkCount += 1
182
- if checkCount > 200 and not gui:
183
- raise Exception(f"Cosim never wrote cfg file: {portFileName}")
184
- port = -1
185
- while port < 0:
186
- portFile = open(portFileName, "r")
187
- for line in portFile.readlines():
188
- m = re.match("port: (\\d+)", line)
189
- if m is not None:
190
- port = int(m.group(1))
191
- portFile.close()
192
-
193
- # Wait for the simulation to start accepting RPC connections.
194
- checkCount = 0
195
- while not is_port_open(port):
196
- checkCount += 1
197
- if checkCount > 200:
198
- raise Exception(f"Cosim RPC port ({port}) never opened")
199
- if simProc.poll() is not None:
200
- raise Exception("Simulation exited early")
201
- time.sleep(0.05)
202
-
203
- if server_only:
204
- # wait for user input to kill the server
205
- input(
206
- f"Running in server-only mode on port {port} - Press anything to kill the server..."
207
- )
208
- return 0
209
- else:
210
- # Run the inner command, passing the connection info via environment vars.
211
- testEnv = os.environ.copy()
212
- testEnv["ESI_COSIM_PORT"] = str(port)
213
- testEnv["ESI_COSIM_HOST"] = "localhost"
214
- return subprocess.run(inner_command, cwd=os.getcwd(),
215
- env=testEnv).returncode
216
- finally:
217
- # Make sure to stop the simulation no matter what.
218
- if simProc:
219
- os.killpg(os.getpgid(simProc.pid), signal.SIGINT)
220
- # Allow the simulation time to flush its outputs.
221
- try:
222
- simProc.wait(timeout=1.0)
223
- except subprocess.TimeoutExpired:
224
- # If the simulation doesn't exit of its own free will, kill it.
225
- simProc.kill()
226
-
227
-
228
- class Verilator(Simulator):
229
- """Run and compile funcs for Verilator."""
230
-
231
- DefaultDriver = CosimCollateralDir / "driver.cpp"
232
-
233
- def __init__(self, sources: SourceFiles, run_dir: Path, debug: bool):
234
- super().__init__(sources, run_dir, debug)
235
-
236
- self.verilator = "verilator"
237
- if "VERILATOR_PATH" in os.environ:
238
- self.verilator = os.environ["VERILATOR_PATH"]
239
-
240
- def compile_commands(self) -> List[List[str]]:
241
- cmd: List[str] = [
242
- self.verilator,
243
- "--cc",
244
- "--top-module",
245
- self.sources.top,
246
- "-DSIMULATION",
247
- "-Wno-TIMESCALEMOD",
248
- "-Wno-fatal",
249
- "-sv",
250
- "--build",
251
- "--exe",
252
- "--assert",
253
- str(Verilator.DefaultDriver),
254
- ]
255
- cflags = [
256
- "-DTOP_MODULE=" + self.sources.top,
257
- ]
258
- if self.debug:
259
- cmd += [
260
- "--trace", "--trace-params", "--trace-structs", "--trace-underscore"
261
- ]
262
- cflags.append("-DTRACE")
263
- if len(cflags) > 0:
264
- cmd += ["-CFLAGS", " ".join(cflags)]
265
- if len(self.sources.dpi_so) > 0:
266
- cmd += ["-LDFLAGS", " ".join(["-l" + so for so in self.sources.dpi_so])]
267
- cmd += [str(p) for p in self.sources.rtl_sources]
268
- return [cmd]
269
-
270
- def run_command(self, gui: bool):
271
- if gui:
272
- raise RuntimeError("Verilator does not support GUI mode.")
273
- exe = Path.cwd() / "obj_dir" / ("V" + self.sources.top)
274
- return [str(exe)]
275
-
276
-
277
- class Questa(Simulator):
278
- """Run and compile funcs for Questasim."""
279
-
280
- DefaultDriver = CosimCollateralDir / "driver.sv"
281
-
282
- # Questa doesn't use stderr for error messages. Everything goes to stdout.
283
- UsesStderr = False
284
-
285
- def internal_compile_commands(self) -> List[str]:
286
- cmds = [
287
- "onerror { quit -f -code 1 }",
288
- ]
289
- sources = self.sources.rtl_sources
290
- sources.append(Questa.DefaultDriver)
291
- for src in sources:
292
- cmds.append(f"vlog -incr +acc -sv +define+TOP_MODULE={self.sources.top}"
293
- f" +define+SIMULATION {str(src)}")
294
- cmds.append(f"vopt -incr driver -o driver_opt +acc")
295
- return cmds
296
-
297
- def compile_commands(self) -> List[List[str]]:
298
- with open("compile.do", "w") as f:
299
- for cmd in self.internal_compile_commands():
300
- f.write(cmd)
301
- f.write("\n")
302
- f.write("quit\n")
303
- return [
304
- ["vsim", "-batch", "-do", "compile.do"],
305
- ]
306
-
307
- def run_command(self, gui: bool) -> List[str]:
308
- vsim = "vsim"
309
- # Note: vsim exit codes say nothing about the test run's pass/fail even
310
- # if $fatal is encountered in the simulation.
311
- if gui:
312
- cmd = [
313
- vsim,
314
- "driver_opt",
315
- ]
316
- else:
317
- cmd = [
318
- vsim,
319
- "driver_opt",
320
- "-batch",
321
- "-do",
322
- "run -all",
323
- ]
324
- for lib in self.sources.dpi_so_paths():
325
- svLib = os.path.splitext(lib)[0]
326
- cmd.append("-sv_lib")
327
- cmd.append(svLib)
328
- return cmd
329
-
330
- def run(self,
331
- inner_command: str,
332
- gui: bool = False,
333
- server_only: bool = False) -> int:
334
- """Override the Simulator.run() to add a soft link in the run directory (to
335
- the work directory) before running vsim the usual way."""
336
-
337
- # Create a soft link to the work directory.
338
- workDir = self.run_dir / "work"
339
- if not workDir.exists():
340
- os.symlink(Path(os.getcwd()) / "work", workDir)
341
-
342
- # Run the simulation.
343
- return super().run(inner_command, gui, server_only=server_only)
22
+ from esiaccel.cosim.questa import Questa
23
+ from esiaccel.cosim.verilator import Verilator
24
+ from esiaccel.cosim.simulator import SourceFiles
344
25
 
345
26
 
346
27
  def __main__(args):
Binary file
esiaccel/esiquery.exe CHANGED
Binary file
@@ -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;
@@ -20,6 +20,7 @@
20
20
  #include <cstdint>
21
21
  #include <map>
22
22
  #include <optional>
23
+ #include <span>
23
24
  #include <stdexcept>
24
25
  #include <string>
25
26
  #include <vector>
@@ -42,6 +43,13 @@ struct AppID {
42
43
  return name == other.name && idx == other.idx;
43
44
  }
44
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
+ }
45
53
  };
46
54
  bool operator<(const AppID &a, const AppID &b);
47
55
 
@@ -52,6 +60,7 @@ public:
52
60
  AppIDPath operator+(const AppIDPath &b) const;
53
61
  AppIDPath parent() const;
54
62
  std::string toStr() const;
63
+ friend std::ostream &operator<<(std::ostream &os, const AppIDPath &path);
55
64
  };
56
65
  bool operator<(const AppIDPath &a, const AppIDPath &b);
57
66
 
@@ -105,6 +114,8 @@ class MessageData {
105
114
  public:
106
115
  /// Adopts the data vector buffer.
107
116
  MessageData() = default;
117
+ MessageData(std::span<const uint8_t> data)
118
+ : data(data.data(), data.data() + data.size()) {}
108
119
  MessageData(std::vector<uint8_t> &data) : data(std::move(data)) {}
109
120
  MessageData(std::vector<uint8_t> &&data) : data(std::move(data)) {}
110
121
  MessageData(const uint8_t *data, size_t size) : data(data, data + size) {}
@@ -115,11 +126,17 @@ public:
115
126
  /// Get the data as a vector of bytes.
116
127
  const std::vector<uint8_t> &getData() const { return data; }
117
128
 
129
+ /// Implicit conversion to a vector/span of bytes, to play nice with other
130
+ /// APIs that accept bytearray-like things.
131
+ operator const std::vector<uint8_t> &() const { return data; }
132
+ operator std::span<const uint8_t>() const { return data; }
133
+
118
134
  /// Move the data out of this object.
119
135
  std::vector<uint8_t> takeData() { return std::move(data); }
120
136
 
121
137
  /// Get the size of the data in bytes.
122
138
  size_t getSize() const { return data.size(); }
139
+ size_t size() const { return getSize(); }
123
140
 
124
141
  /// Returns true if this message contains no data.
125
142
  bool empty() const { return data.empty(); }
@@ -152,7 +169,6 @@ private:
152
169
  } // namespace esi
153
170
 
154
171
  std::ostream &operator<<(std::ostream &, const esi::ModuleInfo &);
155
- std::ostream &operator<<(std::ostream &, const esi::AppID &);
156
172
 
157
173
  //===----------------------------------------------------------------------===//
158
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>>;
@@ -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
@@ -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
@@ -271,13 +282,20 @@ public:
271
282
  void connect();
272
283
  std::future<MessageData> call(const MessageData &arg);
273
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
+
274
296
  virtual std::optional<std::string> toString() const override {
275
- const esi::Type *argType =
276
- dynamic_cast<const ChannelType *>(type->findChannel("arg").first)
277
- ->getInner();
278
- const esi::Type *resultType =
279
- dynamic_cast<const ChannelType *>(type->findChannel("result").first)
280
- ->getInner();
297
+ const esi::Type *argType = getArgType();
298
+ const esi::Type *resultType = getResultType();
281
299
  return "function " + resultType->getID() + "(" + argType->getID() + ")";
282
300
  }
283
301
 
@@ -320,13 +338,20 @@ public:
320
338
  void connect(std::function<MessageData(const MessageData &)> callback,
321
339
  bool quick = false);
322
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
+
323
352
  virtual std::optional<std::string> toString() const override {
324
- const esi::Type *argType =
325
- dynamic_cast<const ChannelType *>(type->findChannel("arg").first)
326
- ->getInner();
327
- const esi::Type *resultType =
328
- dynamic_cast<const ChannelType *>(type->findChannel("result").first)
329
- ->getInner();
353
+ const esi::Type *argType = getArgType();
354
+ const esi::Type *resultType = getResultType();
330
355
  return "callback " + resultType->getID() + "(" + argType->getID() + ")";
331
356
  }
332
357
 
@@ -351,18 +376,23 @@ public:
351
376
  virtual std::string getServiceSymbol() const override;
352
377
  virtual BundlePort *getPort(AppIDPath id,
353
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;
354
384
 
355
385
  /// A telemetry port which gets attached to a service port.
356
- class Telemetry : public ServicePort {
386
+ class Metric : public ServicePort {
357
387
  friend class TelemetryService;
358
- Telemetry(AppID id, const BundleType *type, PortMap channels);
388
+ Metric(AppID id, const BundleType *type, PortMap channels,
389
+ const TelemetryService *telemetryService,
390
+ std::optional<uint64_t> offset);
359
391
 
360
392
  public:
361
- static Telemetry *get(AppID id, BundleType *type, WriteChannelPort &get,
362
- ReadChannelPort &data);
363
-
364
393
  void connect();
365
394
  std::future<MessageData> read();
395
+ uint64_t readInt();
366
396
 
367
397
  virtual std::optional<std::string> toString() const override {
368
398
  const esi::Type *dataType =
@@ -372,16 +402,24 @@ public:
372
402
  }
373
403
 
374
404
  private:
375
- WriteChannelPort *get_req;
376
- ReadChannelPort *data;
405
+ const TelemetryService *telemetryService;
406
+ MMIO::MMIORegion *mmio;
407
+ std::optional<uint64_t> offset;
377
408
  };
378
409
 
379
- const std::map<AppIDPath, Telemetry *> &getTelemetryPorts() {
380
- return telemetryPorts;
410
+ std::map<AppIDPath, Metric *> getTelemetryPorts() {
411
+ std::map<AppIDPath, Metric *> ports;
412
+ getTelemetryPorts(ports);
413
+ return ports;
381
414
  }
415
+ void getTelemetryPorts(std::map<AppIDPath, Metric *> &ports);
382
416
 
383
417
  private:
384
- mutable std::map<AppIDPath, Telemetry *> telemetryPorts;
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;
385
423
  };
386
424
 
387
425
  /// Registry of services which can be instantiated directly by the Accelerator