19 #include <nlohmann/json.hpp>
39 friend class ::esi::Manifest;
44 auto at(
const string &key)
const {
return manifestJson.at(key); }
47 optional<ModuleInfo> getModInfo(
const nlohmann::json &)
const;
57 const nlohmann::json &,
62 vector<services::Service *> getServices(
AppIDPath idPath,
64 const nlohmann::json &,
69 vector<std::unique_ptr<BundlePort>>
72 const nlohmann::json &instJson)
const;
76 vector<unique_ptr<Instance>>
79 const nlohmann::json &instJson)
const;
83 unique_ptr<Instance> getChildInstance(
AppIDPath idPath,
86 const nlohmann::json &childJson)
const;
89 void populateTypes(
const nlohmann::json &typesJson);
92 const vector<const Type *> &
getTypeTable()
const {
return _typeTable; }
117 optional<uint32_t> idx;
118 if (jsonID.contains(
"index"))
119 idx = jsonID.at(
"index").get<uint32_t>();
120 return AppID(jsonID.at(
"name").get<
string>(), idx);
125 for (
auto &
id : jsonIDPath)
132 jsonPort.at(
"inner").get<
string>()};
137 static any
getAny(
const nlohmann::json &value) {
138 auto getObject = [](
const nlohmann::json &
json) {
139 map<string, any> ret;
140 for (
auto &e :
json.items())
141 ret[e.key()] =
getAny(e.value());
145 auto getArray = [](
const nlohmann::json &
json) {
152 if (value.is_string())
153 return value.get<
string>();
154 else if (value.is_number_integer())
155 return value.get<int64_t>();
156 else if (value.is_number_unsigned())
157 return value.get<uint64_t>();
158 else if (value.is_number_float())
159 return value.get<
double>();
160 else if (value.is_boolean())
161 return value.get<
bool>();
162 else if (value.is_null())
163 return value.get<nullptr_t>();
164 else if (value.is_object())
165 return getObject(value);
166 else if (value.is_array())
167 return getArray(value);
169 throw runtime_error(
"Unknown type in manifest: " + value.dump(2));
174 map<string, any> extras;
175 for (
auto &extra : mod.items())
176 if (extra.key() !=
"name" && extra.key() !=
"summary" &&
177 extra.key() !=
"version" && extra.key() !=
"repo" &&
178 extra.key() !=
"commitHash" && extra.key() !=
"symbolRef")
179 extras[extra.key()] =
getAny(extra.value());
181 auto value = [&](
const string &key) -> optional<string> {
182 auto f = mod.find(key);
187 return ModuleInfo{value(
"name"), value(
"summary"), value(
"version"),
188 value(
"repo"), value(
"commitHash"), extras};
196 manifestJson = nlohmann::ordered_json::parse(manifestStr);
204 unique_ptr<Accelerator>
209 auto svcDecls = manifestJson.at(
"service_decls");
210 scanServiceDecls(acc, svcDecls, activeSvcs);
213 auto designJson = manifestJson.at(
"design");
214 vector<services::Service *> services =
215 getServices({}, acc, designJson, activeSvcs);
218 auto ports = getBundlePorts(acc, {}, activeSvcs, designJson);
220 return make_unique<Accelerator>(
221 getModInfo(designJson),
222 getChildInstances({}, acc, activeSvcs, designJson), services, ports);
227 auto instOfIter =
json.find(
"inst_of");
228 if (instOfIter ==
json.end())
230 auto f = symbolInfoCache.find(instOfIter.value());
231 if (f != symbolInfoCache.end())
237 const nlohmann::json &svcDecls,
239 for (
auto &svcDecl : svcDecls) {
240 if (
auto f = svcDecl.find(
"type_name"); f != svcDecl.end()) {
243 for (
auto &
detail : svcDecl.items())
248 services::ServiceRegistry::lookupServiceType(f.value());
252 activeServices[svcDecl.at(
"symbol")] = svc;
257 vector<unique_ptr<Instance>>
260 const nlohmann::json &instJson)
const {
261 vector<unique_ptr<Instance>> ret;
262 auto childrenIter = instJson.find(
"children");
263 if (childrenIter == instJson.end())
265 for (
auto &child : childrenIter.value())
266 ret.emplace_back(getChildInstance(idPath, acc, activeServices, child));
273 const nlohmann::json &child)
const {
275 idPath.push_back(childID);
277 vector<services::Service *> services =
278 getServices(idPath, acc, child, activeServices);
280 auto children = getChildInstances(idPath, acc, activeServices, child);
281 auto ports = getBundlePorts(acc, idPath, activeServices, child);
282 return make_unique<Instance>(
parseID(child.at(
"app_id")), getModInfo(child),
283 std::move(children), services, ports);
288 const nlohmann::json &svcJson,
292 idPath.push_back(
id);
296 for (
auto &client : svcJson.at(
"client_details")) {
298 for (
auto &
detail : client.items()) {
299 if (
detail.key() ==
"relAppIDPath")
301 else if (
detail.key() ==
"port")
306 clientDetails.push_back(clientDetail);
311 std::string implName;
313 for (
auto &
detail : svcJson.items()) {
314 if (
detail.key() ==
"appID" ||
detail.key() ==
"client_details")
316 if (
detail.key() ==
"serviceImplName")
317 implName =
detail.value();
318 else if (
detail.key() ==
"service")
319 service =
detail.value().get<std::string>().substr(1);
327 services::ServiceRegistry::lookupServiceType(service);
329 acc.
getService(svcType, idPath, implName, svcDetails, clientDetails);
332 activeServices[service] = svc;
336 vector<services::Service *>
338 const nlohmann::json &svcsJson,
340 vector<services::Service *> ret;
341 auto contentsIter = svcsJson.find(
"contents");
342 if (contentsIter == svcsJson.end())
345 for (
auto &content : contentsIter.value())
346 if (content.at(
"class") ==
"service")
347 ret.emplace_back(getService(idPath, acc, content, activeServices));
351 vector<std::unique_ptr<BundlePort>>
354 const nlohmann::json &instJson)
const {
355 vector<std::unique_ptr<BundlePort>> ret;
356 auto contentsIter = instJson.find(
"contents");
357 if (contentsIter == instJson.end())
360 for (
auto &content : contentsIter.value()) {
361 if (content.at(
"class") !=
"client_port")
365 std::string serviceName =
"";
366 if (
auto f = content.find(
"servicePort"); f != content.end())
368 auto svcIter = activeServices.find(serviceName);
369 if (svcIter == activeServices.end()) {
372 if (svcIter = activeServices.find(
""); svcIter == activeServices.end())
374 "Malformed manifest: could not find active service '" +
379 string typeName = content.at(
"bundleType").at(
"circt_name");
380 auto type = getType(typeName);
382 throw runtime_error(
"Malformed manifest: could not find port type '" +
386 throw runtime_error(
"Malformed manifest: type '" + typeName +
387 "' is not a bundle type");
389 idPath.push_back(
parseID(content.at(
"appID")));
390 map<string, ChannelPort &> portChannels =
394 svc->
getPort(idPath, bundleType, portChannels, acc);
396 ret.emplace_back(svcPort);
398 ret.emplace_back(
new BundlePort(idPath.back(), portChannels));
410 assert(typeJson.at(
"mnemonic") ==
"bundle");
412 vector<tuple<string, BundleType::Direction, const Type *>> channels;
413 for (
auto &chanJson : typeJson[
"channels"]) {
414 string dirStr = chanJson.at(
"direction");
417 dir = BundleType::Direction::To;
418 else if (dirStr ==
"from")
419 dir = BundleType::Direction::From;
421 throw runtime_error(
"Malformed manifest: unknown direction '" + dirStr +
423 channels.emplace_back(chanJson.at(
"name"), dir,
426 return new BundleType(typeJson.at(
"circt_name"), channels);
430 assert(typeJson.at(
"mnemonic") ==
"channel");
435 Type *parseInt(
const nlohmann::json &typeJson,
Context &cache) {
436 assert(typeJson.at(
"mnemonic") ==
"int");
437 std::string sign = typeJson.at(
"signedness");
438 uint64_t
width = typeJson.at(
"hw_bitwidth");
439 Type::ID
id = typeJson.at(
"circt_name");
441 if (sign ==
"signed")
443 else if (sign ==
"unsigned")
445 else if (sign ==
"signless" &&
width == 0)
448 else if (sign ==
"signless" &&
width > 0)
451 throw runtime_error(
"Malformed manifest: unknown sign '" + sign +
"'");
455 assert(typeJson.at(
"mnemonic") ==
"struct");
456 vector<pair<string, const Type *>> fields;
457 for (
auto &fieldJson : typeJson[
"fields"])
458 fields.emplace_back(fieldJson.at(
"name"),
460 return new StructType(typeJson.at(
"circt_name"), fields);
464 assert(typeJson.at(
"mnemonic") ==
"array");
465 uint64_t size = typeJson.at(
"size");
466 return new ArrayType(typeJson.at(
"circt_name"),
467 parseType(typeJson.at(
"element"), cache), size);
470 using TypeParser = std::function<
Type *(
const nlohmann::json &,
Context &)>;
471 const std::map<std::string_view, TypeParser> typeParsers = {
472 {
"bundle", parseBundleType},
473 {
"channel", parseChannelType},
475 [](
const nlohmann::json &typeJson,
Context &cache) {
476 return new AnyType(typeJson.at(
"circt_name"));
479 {
"struct", parseStruct},
487 string circt_name = typeJson.at(
"circt_name");
488 if (optional<const Type *> t = cache.
getType(circt_name))
491 string mnemonic = typeJson.at(
"mnemonic");
493 auto f = typeParsers.find(mnemonic);
494 if (f != typeParsers.end())
495 t = f->second(typeJson, cache);
498 t =
new Type(circt_name);
511 for (
auto &typeJson : typesJson)
512 _typeTable.push_back(
parseType(typeJson));
519 Manifest::Manifest(
Context &
ctxt,
const string &jsonManifest)
520 : impl(new
Impl(
ctxt, jsonManifest)) {}
522 Manifest::~Manifest() {
delete impl; }
524 uint32_t Manifest::getApiVersion()
const {
525 return impl->at(
"api_version").get<uint32_t>();
528 vector<ModuleInfo> Manifest::getModuleInfos()
const {
529 vector<ModuleInfo> ret;
530 for (
auto &mod : impl->at(
"symbols"))
535 unique_ptr<Accelerator>
537 return impl->buildAccelerator(acc);
540 const vector<const Type *> &Manifest::getTypeTable()
const {
541 return impl->getTypeTable();
550 auto printAny = [&os](any a) {
551 const type_info &t = a.type();
552 if (t ==
typeid(
string))
553 os << any_cast<string>(a);
554 else if (t ==
typeid(int64_t))
555 os << any_cast<int64_t>(a);
556 else if (t ==
typeid(uint64_t))
557 os << any_cast<uint64_t>(a);
558 else if (t ==
typeid(
double))
559 os << any_cast<double>(a);
560 else if (t ==
typeid(
bool))
561 os << any_cast<bool>(a);
562 else if (t ==
typeid(nullptr_t))
569 os << *m.
name <<
" ";
584 if (!m.
extra.empty()) {
585 os <<
" Extra metadata:\n";
586 for (
auto &e : m.
extra) {
587 os <<
" " << e.first <<
": ";
598 ret.insert(ret.end(), b.begin(), b.end());
602 string AppIDPath::toStr()
const {
614 if (a.size() != b.size())
615 return a.size() < b.size();
616 for (
size_t i = 0, e = a.size(); i < e; ++i)
626 os <<
"[" << *
id.idx <<
"]";
630 for (
size_t i = 0, e = path.size(); i < e; ++i) {
assert(baseType &&"element must be base type")
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static LogicalResult parseArray(AsmParser &p, Attribute &dim, Type &inner)
static any getAny(const nlohmann::json &value)
Convert the json value to a 'any', which can be exposed outside of this file.
ostream & operator<<(ostream &os, const ModuleInfo &m)
static AppIDPath parseIDPath(const nlohmann::json &jsonIDPath)
static ModuleInfo parseModuleInfo(const nlohmann::json &mod)
static ServicePortDesc parseServicePort(const nlohmann::json &jsonPort)
static AppID parseID(const nlohmann::json &jsonID)
map< string, services::Service * > ServiceTable
vector< services::Service * > getServices(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices) const
Get all the services in the description of an instance.
const vector< const Type * > & getTypeTable() const
Get the ordered list of types from the manifest.
auto at(const string &key) const
optional< ModuleInfo > getModInfo(const nlohmann::json &) const
optional< const Type * > getType(Type::ID id) const
nlohmann::json manifestJson
const Type * parseType(const nlohmann::json &typeJson)
unique_ptr< Accelerator > buildAccelerator(AcceleratorConnection &acc) const
Build a dynamic API for the Accelerator connection 'acc' based on the manifest stored herein.
services::Service * getService(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices) const
Get a Service for the service specified in 'json'.
vector< const Type * > _typeTable
vector< unique_ptr< Instance > > getChildInstances(AppIDPath idPath, AcceleratorConnection &acc, const ServiceTable &activeServices, const nlohmann::json &instJson) const
Build the set of child instances (recursively) for the module instance description.
map< string, ModuleInfo > symbolInfoCache
void scanServiceDecls(AcceleratorConnection &, const nlohmann::json &, ServiceTable &) const
Go through the "service_decls" section of the manifest and populate the services table as appropriate...
unique_ptr< Instance > getChildInstance(AppIDPath idPath, AcceleratorConnection &acc, ServiceTable activeServices, const nlohmann::json &childJson) const
Get a single child instance.
vector< std::unique_ptr< BundlePort > > getBundlePorts(AcceleratorConnection &acc, AppIDPath idPath, const ServiceTable &activeServices, const nlohmann::json &instJson) const
Get the bundle ports for the instance at 'idPath' and specified in 'instJson'.
Impl(Context &ctxt, const string &jsonManifest)
void populateTypes(const nlohmann::json &typesJson)
Parse all the types and populate the types table.
Abstract class representing a connection to an accelerator.
ServiceClass * getService(AppIDPath id={}, std::string implName={}, ServiceImplDetails details={}, HWClientDetails clients={})
Get a typed reference to a particular service type.
virtual std::map< std::string, ChannelPort & > requestChannelsFor(AppIDPath, const BundleType *)=0
Request the host side channel ports for a particular instance (identified by the AppID path).
The "any" type is a special type which can be used to represent any type, as identified by the type i...
Arrays have a compile time specified (static) size and an element type.
Bits are just an array of bits.
Services provide connections to 'bundles' – collections of named, unidirectional communication channe...
Bundles represent a collection of channels.
Channels are the basic communication primitives.
AcceleratorConnections, Accelerators, and Manifests must all share a context.
std::optional< const Type * > getType(Type::ID id) const
Resolve a type id to the type.
void registerType(Type *type)
Register a type with the context.
Structs are an ordered collection of fields, each with a name and a type.
Root class of the ESI type system.
The "void" type is a special type which can be used to represent no type.
Add a custom interface to a service client at a particular point in the design hierarchy.
Parent class of all APIs modeled as 'services'.
const std::type_info & Type
virtual ServicePort * getPort(AppIDPath id, const BundleType *type, const std::map< std::string, ChannelPort & > &, AcceleratorConnection &) const
Get specialized port for this service to attach to the given appid path.
std::map< std::string, std::any > ServiceImplDetails
bool operator<(const AppID &a, const AppID &b)
std::vector< HWClientDetail > HWClientDetails
std::optional< uint32_t > idx
A description of a hardware client.
std::map< std::string, std::any > implOptions
const std::optional< std::string > commitHash
const std::optional< std::string > repo
const std::optional< std::string > version
const std::optional< std::string > summary
const std::map< std::string, std::any > extra
const std::optional< std::string > name
A description of a service port.