CIRCT 23.0.0git
Loading...
Searching...
No Matches
ModelInstance.cpp
Go to the documentation of this file.
1//===- ModelInstance.cpp - Instance of a model in the ArcRuntime ----------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This implements the context for a model instance in the ArcRuntime library.
10//
11//===----------------------------------------------------------------------===//
12
14
17#ifdef CIRCT_LIBFST_ENABLED
19#endif
20
21#include <cassert>
22#include <cctype>
23#include <iostream>
24#include <string_view>
25#include <vector>
26
27using namespace circt::arc::runtime;
28
30
31// Global counter for instances
32static uint64_t instanceIDsGlobal = 0;
33
35 const char *args, ArcState *mutableState)
36 : instanceID(instanceIDsGlobal++), modelInfo(modelInfo),
37 state(mutableState) {
38 bool hasTraceInstrumentation = !!modelInfo->traceInfo;
40 parseArgs(args);
41
42 if (verbose) {
43 std::cout << "[ArcRuntime] "
44 << "Created instance"
45 << " of model \"" << getModelName() << "\""
46 << " with ID " << instanceID << std::endl;
47 std::cout << "[ArcRuntime] Model \"" << getModelName() << "\"";
48 if (hasTraceInstrumentation)
49 std::cout << " has trace instrumentation." << std::endl;
50 else
51 std::cout << " does not have trace instrumentation." << std::endl;
52 }
53
54 if (!hasTraceInstrumentation && traceMode != TraceMode::DUMMY)
55 std::cerr
56 << "[ArcRuntime] WARNING: "
57 << "Tracing has been requested but model \"" << getModelName()
58 << "\" contains no instrumentation."
59 << " No trace will be produced.\n\t\tMake sure to compile the model"
60 " with tracing enabled and that it contains observed signals."
61 << std::endl;
62
63 if (hasTraceInstrumentation) {
64 switch (traceMode) {
67 std::make_unique<DummyTraceEncoder>(modelInfo, mutableState);
68 break;
69 case TraceMode::VCD:
70 traceEncoder = std::make_unique<VCDTraceEncoder>(
71 modelInfo, mutableState, getTraceFilePath(".vcd"), verbose);
72 break;
73 case TraceMode::FST:
74#ifdef CIRCT_LIBFST_ENABLED
75 traceEncoder = std::make_unique<FSTTraceEncoder>(
76 modelInfo, mutableState, getTraceFilePath(".fst"), verbose);
77#else
78 std::cerr << "[ArcRuntime] ERROR: FST tracing was requested but CIRCT "
79 "was not built with FST support (CIRCT_LIBFST_ENABLED=OFF)."
80 << std::endl;
82 std::make_unique<DummyTraceEncoder>(modelInfo, mutableState);
83#endif
84 break;
85 }
86 } else {
87 traceEncoder = {};
88 }
89}
90
92 if (verbose) {
93 std::cout << "[ArcRuntime] "
94 << "Deleting instance"
95 << " of model \"" << getModelName() << "\""
96 << " with ID " << instanceID << " after " << stepCounter
97 << " step(s)" << std::endl;
98 }
99 assert(state->impl == static_cast<void *>(this) && "Inconsistent ArcState");
100 if (traceEncoder)
101 traceEncoder->finish(state);
102}
103
104std::filesystem::path
105ModelInstance::getTraceFilePath(const std::string &suffix) {
106 auto it = arguments.find("traceFile");
107 if (it != arguments.end() && it->second.has_value())
108 return std::filesystem::path(*it->second);
109
110 std::string saneName;
111 if (modelInfo->modelName)
112 saneName = std::string(modelInfo->modelName);
113 for (auto &c : saneName) {
114 if (c == ' ' || c == '/' || c == '\\')
115 c = '_';
116 }
117 saneName += '_';
118 saneName += std::to_string(instanceID);
119 saneName += suffix;
120 return std::filesystem::current_path() / std::filesystem::path(saneName);
121}
122
123void ModelInstance::onEval(ArcState *mutableState) {
124 assert(mutableState == state);
125 ++stepCounter;
126 if (traceEncoder)
127 traceEncoder->step(state);
128}
129
131 assert(mutableState == state);
132 if (traceEncoder)
133 traceEncoder->run(mutableState);
134
135 if (verbose) {
136 std::cout << "[ArcRuntime] "
137 << "Instance with ID " << instanceID << " initialized"
138 << std::endl;
139 }
140}
141
143 if (!traceEncoder)
145 "swapTraceBuffer called on model without trace instrumentation");
146 if (verbose)
147 std::cout << "[ArcRuntime] Consuming trace buffer of size "
148 << state->traceBufferSize << " for instance ID " << instanceID
149 << std::endl;
150 return traceEncoder->dispatch(state->traceBufferSize);
151}
152
153// Parse the argument string into a map of key to optional value.
154// Flags (bare keys without '=') map to std::nullopt. Keys occurring later
155// override identical earlier keys. Quoted values (key="...") may contain ';'
156// and support \" and \\ escape sequences. Malformed tokens are warned and
157// skipped.
158static std::map<std::string, std::optional<std::string>>
159parseArgsToMap(std::string_view argStr) {
160 std::map<std::string, std::optional<std::string>> result;
161
162 enum class State { Key, AfterEq, Unquoted, Quoted, Escape, AfterQuote, Skip };
163 State state = State::Key;
164
165 std::string key;
166 std::string value;
167 bool hasValue = false;
168
169 auto warn = [&](const char *msg) {
170 std::cerr << "[ArcRuntime] WARNING: Malformed runtime argument: " << msg;
171 if (!key.empty())
172 std::cerr << " for key \"" << key << "\"";
173 std::cerr << ", ignoring\n";
174 };
175
176 auto commit = [&] {
177 result[std::move(key)] =
178 hasValue ? std::optional(std::move(value)) : std::nullopt;
179 key.clear();
180 value.clear();
181 hasValue = false;
182 state = State::Key;
183 };
184
185 auto skipToNext = [&] {
186 key.clear();
187 value.clear();
188 hasValue = false;
189 state = State::Skip;
190 };
191
192 for (size_t i = 0; i <= argStr.size(); ++i) {
193 const bool atEnd = (i == argStr.size());
194 const char c = atEnd ? '\0' : argStr[i];
195
196 switch (state) {
197 case State::Key:
198 if (atEnd || c == ';') {
199 if (!key.empty())
200 commit();
201 } else if (std::isgraph(static_cast<unsigned char>(c)) && c != '"' &&
202 c != '=') {
203 key += c;
204 } else if (c == '=' && !key.empty()) {
205 hasValue = true;
206 state = State::AfterEq;
207 } else {
208 warn("Invalid key");
209 skipToNext();
210 }
211 break;
212
213 case State::AfterEq:
214 if (c == '"' && !atEnd) {
215 state = State::Quoted;
216 } else if (atEnd || c == ';') {
217 commit(); // empty value
218 } else {
219 value += c;
220 state = State::Unquoted;
221 }
222 break;
223
224 case State::Unquoted:
225 if (atEnd || c == ';') {
226 commit();
227 } else if (c == '"') {
228 warn("Unquoted value contains forbidden character '\"'");
229 skipToNext();
230 } else {
231 value += c;
232 }
233 break;
234
235 case State::Quoted:
236 if (atEnd) {
237 warn("Unterminated quoted value");
238 skipToNext();
239 } else if (c == '"') {
240 state = State::AfterQuote;
241 } else if (c == '\\') {
242 state = State::Escape;
243 } else {
244 value += c;
245 }
246 break;
247
248 case State::Escape:
249 if (atEnd) {
250 warn("Truncated escape sequence in quoted value");
251 skipToNext();
252 } else if (c == '"' || c == '\\') {
253 value += c;
254 state = State::Quoted;
255 } else {
256 warn("Invalid escape sequence in quoted value");
257 skipToNext();
258 }
259 break;
260
261 case State::AfterQuote:
262 if (atEnd || c == ';') {
263 commit();
264 } else {
265 warn("Unexpected content after closing quote");
266 skipToNext();
267 }
268 break;
269
270 case State::Skip:
271 if (!atEnd && c == ';')
272 state = State::Key;
273 break;
274 }
275 }
276
277 return result;
278}
279
280void ModelInstance::parseArgs(const char *args) {
281 if (!args)
282 return;
283 auto argStr = std::string_view(args);
284 arguments = parseArgsToMap(argStr);
285
286 if (arguments.count("debug"))
287 verbose = true;
288 if (arguments.count("vcd"))
290 if (arguments.count("fst"))
292
293 // Dump arguments
294 if (verbose) {
295 std::cout << "[ArcRuntime] Argument string for instance ID " << instanceID
296 << ": " << argStr << std::endl;
297 std::cout << "[ArcRuntime] Parsed argument(s):" << std::endl;
298 for (const auto &[key, value] : arguments) {
299 std::cout << "[ArcRuntime] " << key;
300 if (value.has_value())
301 std::cout << " = \"" << *value << "\"";
302 std::cout << std::endl;
303 }
304 }
305}
306
307} // namespace circt::arc::runtime::impl
assert(baseType &&"element must be base type")
std::filesystem::path getTraceFilePath(const std::string &suffix)
void onEval(ArcState *mutableState)
std::unique_ptr< TraceEncoder > traceEncoder
std::map< std::string, std::optional< std::string > > arguments
void onInitialized(ArcState *mutableState)
const ArcRuntimeModelInfo *const modelInfo
static std::map< std::string, std::optional< std::string > > parseArgsToMap(std::string_view argStr)
static void fatalError(const char *message)
Raise an irrecoverable error.
Definition Internal.h:23
static uint64_t instanceIDsGlobal
Static information for a compiled hardware model, generated by the MLIR lowering.
Definition Common.h:70
struct ArcModelTraceInfo * traceInfo
Signal tracing information. NULL iff the model is not trace instrumented.
Definition Common.h:78
const char * modelName
Name of the compiled model.
Definition Common.h:76
Combined runtime and model state for a hardware model instance.
Definition Common.h:44
void * impl
Runtime implementation specific data. Usually points to a custom struct.
Definition Common.h:46
uint32_t traceBufferSize
Number of valid elements in the active trace buffer.
Definition Common.h:52