28 #include "mlir/Pass/Pass.h"
29 #include "llvm/ADT/DepthFirstIterator.h"
30 #include "llvm/ADT/TypeSwitch.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/YAMLTraits.h"
35 #define DEBUG_TYPE "gct"
39 #define GEN_PASS_DEF_GRANDCENTRAL
40 #include "circt/Dialect/FIRRTL/Passes.h.inc"
44 using namespace circt;
45 using namespace firrtl;
58 [[maybe_unused]]
static std::string noDefault(StringRef clazz) {
59 return (
"default '" + clazz +
60 "' construction is an intentionally *NOT* implemented "
61 "YAML feature (you should never be using this)")
65 [[maybe_unused]]
static std::string deNorm(StringRef clazz) {
66 return (
"conversion from YAML to a '" + clazz +
67 "' is intentionally *NOT* implemented (you should not be "
68 "converting from YAML to an interface)")
83 DenseMap<Attribute, sv::InterfaceOp> &interfaceMap;
92 struct DescribedSignal {
94 StringAttr description;
97 sv::InterfaceSignalOp signal;
105 struct DescribedInstance {
109 StringAttr description;
112 ArrayAttr dimensions;
115 FlatSymbolRefAttr interface;
125 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedSignal)
126 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedInstance)
127 LLVM_YAML_IS_SEQUENCE_VECTOR(sv::InterfaceOp)
135 using namespace ::
yaml;
148 std::string descriptionString;
149 llvm::raw_string_ostream stream(descriptionString);
150 SmallVector<StringRef> splits;
151 str.split(splits,
"\n");
155 substr.consume_front(
"//");
156 stream << substr.drop_while([](
auto c) {
return c ==
' '; });
158 [&]() { stream <<
"\n"; });
159 return descriptionString;
166 struct MappingContextTraits<DescribedSignal, Context> {
184 : name(op.signal.getSymNameAttr().getValue()) {
210 auto tpe = op.signal.getType();
211 while (
auto vector = dyn_cast<hw::UnpackedArrayType>(tpe)) {
212 dimensions.push_back(vector.getNumElements());
213 tpe = vector.getElementType();
215 dimensions = SmallVector<unsigned>(llvm::reverse(dimensions));
220 assert(isa<IntegerType>(tpe));
221 width = type_cast<IntegerType>(tpe).getWidth();
225 Field(IO &io) { llvm_unreachable(noDefault(
"Field").c_str()); }
229 llvm_unreachable(deNorm(
"DescribedSignal").c_str());
233 static void mapping(IO &io, DescribedSignal &op, Context &ctx) {
234 MappingNormalization<Field, DescribedSignal> keys(io, op);
235 io.mapRequired(
"name", keys->name);
236 io.mapOptional(
"description", keys->description);
237 io.mapRequired(
"dimensions", keys->dimensions);
238 io.mapRequired(
"width", keys->width);
247 struct MappingContextTraits<DescribedInstance, Context> {
254 std::optional<std::string> description = std::nullopt;
263 : name(op.name.getValue()), interface(op.interface) {
271 for (
auto &d : op.dimensions) {
272 auto dimension = dyn_cast<IntegerAttr>(d);
273 dimensions.push_back(dimension.getInt());
277 Instance(IO &io) { llvm_unreachable(noDefault(
"Instance").c_str()); }
280 llvm_unreachable(deNorm(
"DescribedInstance").c_str());
284 static void mapping(IO &io, DescribedInstance &op, Context &ctx) {
285 MappingNormalization<Instance, DescribedInstance> keys(io, op);
286 io.mapRequired(
"name", keys->name);
287 io.mapOptional(
"description", keys->description);
288 io.mapRequired(
"dimensions", keys->dimensions);
289 io.mapRequired(
"interface", ctx.interfaceMap[keys->interface], ctx);
297 struct MappingContextTraits<
sv::InterfaceOp, Context> {
339 StringAttr description = {};
341 for (
auto &op : op.getBodyBlock()->getOperations()) {
342 TypeSwitch<Operation *>(&op)
345 .Case<sv::VerbatimOp>([&](sv::VerbatimOp op) {
346 auto tpe = op->getAttrOfType<StringAttr>(
347 "firrtl.grandcentral.yaml.type");
351 if (tpe.getValue() ==
"description") {
352 description = op.getFormatStringAttr();
357 if (tpe.getValue() ==
"unsupported") {
364 auto name = op->getAttrOfType<StringAttr>(
365 "firrtl.grandcentral.yaml.name");
366 auto dimensions = op->getAttrOfType<ArrayAttr>(
367 "firrtl.grandcentral.yaml.dimensions");
368 auto symbol = op->getAttrOfType<FlatSymbolRefAttr>(
369 "firrtl.grandcentral.yaml.symbol");
371 DescribedInstance({name, description, dimensions, symbol}));
375 .Case<sv::InterfaceSignalOp>([&](sv::InterfaceSignalOp op) {
376 fields.push_back(DescribedSignal({description, op}));
383 Interface(IO &io) { llvm_unreachable(noDefault(
"Interface").c_str()); }
387 llvm_unreachable(deNorm(
"sv::InterfaceOp").c_str());
391 static void mapping(IO &io, sv::InterfaceOp &op, Context &ctx) {
392 MappingNormalization<Interface, sv::InterfaceOp> keys(io, op);
393 io.mapRequired(
"name", keys->name);
394 io.mapRequired(
"fields", keys->fields, ctx);
395 io.mapRequired(
"instances", keys->instances, ctx);
425 struct VerbatimBuilder {
427 SmallString<128> string;
428 SmallVector<Attribute> symbols;
429 VerbatimBuilder builder() {
return VerbatimBuilder(*
this); }
430 operator VerbatimBuilder() {
return builder(); }
435 VerbatimBuilder(Base &base)
436 : base(base), stringBaseSize(base.string.size()),
437 symbolsBaseSize(base.symbols.size()) {}
442 base.string.resize(stringBaseSize);
443 base.symbols.resize(symbolsBaseSize);
447 VerbatimBuilder(
const VerbatimBuilder &) =
delete;
448 VerbatimBuilder &operator=(
const VerbatimBuilder &) =
delete;
453 VerbatimBuilder snapshot() {
return VerbatimBuilder(base); }
456 StringRef getString()
const {
return base.string; }
458 ArrayRef<Attribute> getSymbols()
const {
return base.symbols; }
461 VerbatimBuilder &
append(
char c) {
462 base.string.push_back(c);
467 VerbatimBuilder &
append(
const Twine &twine) {
468 twine.toVector(base.string);
473 VerbatimBuilder &
append(Attribute symbol) {
474 unsigned id = base.symbols.size();
475 base.symbols.push_back(symbol);
476 append(
"{{" + Twine(
id) +
"}}");
480 VerbatimBuilder &operator+=(
char c) {
return append(c); }
481 VerbatimBuilder &operator+=(
const Twine &twine) {
return append(twine); }
482 VerbatimBuilder &operator+=(Attribute symbol) {
return append(symbol); }
486 size_t stringBaseSize;
487 size_t symbolsBaseSize;
493 struct VerbatimType {
502 SmallVector<int32_t, 4> dimensions = {};
505 std::string toStr(StringRef name) {
506 SmallString<64> stringType(str);
507 stringType.append(
" ");
508 stringType.append(name);
509 for (
auto d : llvm::reverse(dimensions)) {
510 stringType.append(
"[");
511 stringType.append(Twine(d).str());
512 stringType.append(
"]");
515 stringType.append(
"()");
516 stringType.append(
";");
517 return std::string(stringType);
523 typedef std::variant<VerbatimType, Type> TypeSum;
526 struct ExtractionInfo {
529 StringAttr directory = {};
534 StringAttr bindFilename = {};
538 struct CompanionInfo {
549 FlatSymbolRefAttr nlaSym;
553 struct VerbatimXMRbuilder {
557 FModuleOp companionMod;
558 VerbatimXMRbuilder(Value val, StringAttr str, ArrayAttr syms,
559 FModuleOp companionMod)
560 : val(val), str(str), syms(syms), companionMod(companionMod) {}
565 struct InterfaceElemsBuilder {
566 StringAttr iFaceName;
569 StringAttr description;
572 Properties(StringAttr des, StringAttr name, TypeSum &elemType)
573 : description(des), elemName(name), elemType(elemType) {}
575 SmallVector<Properties> elementsList;
576 InterfaceElemsBuilder(StringAttr iFaceName, IntegerAttr
id)
577 : iFaceName(iFaceName), id(id) {}
592 struct GrandCentralPass
593 :
public circt::firrtl::impl::GrandCentralBase<GrandCentralPass> {
594 using GrandCentralBase::companionMode;
596 void runOnOperation()
override;
602 std::optional<Attribute> fromAttr(Attribute attr);
606 DenseMap<Attribute, FieldAndNLA> leafMap;
609 DenseMap<Attribute, CompanionInfo> companionIDMap;
620 StringAttr testbenchDir;
623 std::string getInterfaceName(AugmentedBundleTypeAttr bundleType) {
624 return (bundleType.getDefName().getValue()).str();
629 bool traverseField(Attribute field, IntegerAttr
id, VerbatimBuilder &path,
630 SmallVector<VerbatimXMRbuilder> &xmrElems,
631 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
636 std::optional<TypeSum>
637 computeField(Attribute field, IntegerAttr
id, VerbatimBuilder &path,
638 SmallVector<VerbatimXMRbuilder> &xmrElems,
639 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
644 std::optional<StringAttr>
645 traverseBundle(AugmentedBundleTypeAttr bundle, IntegerAttr
id,
646 VerbatimBuilder &path,
647 SmallVector<VerbatimXMRbuilder> &xmrElems,
648 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
651 igraph::ModuleOpInterface getEnclosingModule(Value value,
652 FlatSymbolRefAttr sym = {});
656 std::optional<ExtractionInfo> maybeExtractInfo = std::nullopt;
660 std::optional<StringAttr> maybeHierarchyFileYAML = std::nullopt;
662 StringAttr getOutputDirectory() {
663 if (maybeExtractInfo)
664 return maybeExtractInfo->directory;
682 std::optional<CircuitNamespace> circuitNamespace;
686 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
691 if (!circuitNamespace)
693 return *circuitNamespace;
697 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
698 return moduleNamespaces.try_emplace(module, module).first->second;
703 std::optional<SymbolTable *> symbolTable;
707 SymbolTable &getSymbolTable() {
709 symbolTable = &getAnalysis<SymbolTable>();
710 return **symbolTable;
717 InFlightDiagnostic emitCircuitError(StringRef message = {}) {
718 return emitError(getOperation().getLoc(),
"'firrtl.circuit' op " + message);
726 std::string cleanupDescription(StringRef description) {
730 std::tie(head, description) = description.split(
"\n");
732 if (!description.empty())
734 }
while (!description.empty());
735 return std::string(out);
739 DenseMap<Attribute, sv::InterfaceOp> interfaceMap;
742 void emitHierarchyYamlFile(SmallVectorImpl<sv::InterfaceOp> &intfs);
756 static std::optional<DictionaryAttr>
758 DictionaryAttr root, StringRef companion, StringAttr name,
759 StringAttr defName, std::optional<IntegerAttr>
id,
760 std::optional<StringAttr> description, Twine clazz,
761 StringAttr companionAttr, Twine path = {}) {
763 auto *context = state.
circuit.getContext();
764 auto loc = state.
circuit.getLoc();
781 [&](DictionaryAttr refTarget) -> std::optional<std::string> {
783 tryGetAs<StringAttr>(refTarget, refTarget,
"circuit", loc, clazz, path);
785 tryGetAs<StringAttr>(refTarget, refTarget,
"module", loc, clazz, path);
787 tryGetAs<ArrayAttr>(refTarget, refTarget,
"path", loc, clazz, path);
788 auto componentAttr = tryGetAs<ArrayAttr>(refTarget, refTarget,
"component",
790 if (!circuitAttr || !moduleAttr || !pathAttr || !componentAttr)
794 SmallString<32> strpath;
795 for (
auto p : pathAttr) {
796 auto dict = dyn_cast_or_null<DictionaryAttr>(p);
798 mlir::emitError(loc,
"annotation '" + clazz +
799 " has invalid type (expected DictionaryAttr)");
803 tryGetAs<DictionaryAttr>(dict, dict,
"_1", loc, clazz, path);
805 tryGetAs<DictionaryAttr>(dict, dict,
"_2", loc, clazz, path);
806 if (!instHolder || !modHolder) {
807 mlir::emitError(loc,
"annotation '" + clazz +
808 " has invalid type (expected DictionaryAttr)");
811 auto inst = tryGetAs<StringAttr>(instHolder, instHolder,
"value", loc,
814 tryGetAs<StringAttr>(modHolder, modHolder,
"value", loc, clazz, path);
816 mlir::emitError(loc,
"annotation '" + clazz +
817 " has invalid type (expected DictionaryAttr)");
820 strpath +=
"/" + inst.getValue().str() +
":" + mod.getValue().str();
823 SmallVector<Attribute> componentAttrs;
824 SmallString<32> componentStr;
825 for (
size_t i = 0, e = componentAttr.size(); i != e; ++i) {
826 auto cPath = (path +
".component[" + Twine(i) +
"]").str();
827 auto component = componentAttr[i];
828 auto dict = dyn_cast_or_null<DictionaryAttr>(component);
830 mlir::emitError(loc,
"annotation '" + clazz +
"' with path '" + cPath +
831 " has invalid type (expected DictionaryAttr)");
835 tryGetAs<StringAttr>(dict, refTarget,
"class", loc, clazz, cPath);
839 auto value = dict.get(
"value");
842 if (
auto field = dyn_cast<StringAttr>(value)) {
843 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Field" &&
844 "A StringAttr target token must be found with a subfield target "
846 componentStr.append((Twine(
".") + field.getValue()).str());
851 if (
auto index = dyn_cast<IntegerAttr>(value)) {
852 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Index" &&
853 "An IntegerAttr target token must be found with a subindex "
856 (Twine(
"[") + Twine(index.getValue().getZExtValue()) +
"]").str());
861 "Annotation '" + clazz +
"' with path '" + cPath +
862 ".value has unexpected type (should be StringAttr "
863 "for subfield or IntegerAttr for subindex).")
865 <<
"The value received was: " << value <<
"\n";
870 tryGetAs<StringAttr>(refTarget, refTarget,
"ref", loc, clazz, path);
874 return (Twine(
"~" + circuitAttr.getValue() +
"|" + moduleAttr.getValue() +
875 strpath +
">" + refAttr.getValue()) +
881 tryGetAs<StringAttr>(augmentedType, root,
"class", loc, clazz, path);
884 StringRef classBase = classAttr.getValue();
885 if (!classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented")) {
887 "the 'class' was expected to start with "
888 "'sifive.enterprise.grandCentral.Augmented*', but was '" +
889 classAttr.getValue() +
"' (Did you misspell it?)")
891 <<
"see annotation: " << augmentedType;
898 if (classBase ==
"BundleType") {
900 tryGetAs<StringAttr>(augmentedType, root,
"defName", loc, clazz, path);
908 SmallVector<Attribute> elements;
910 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
913 for (
size_t i = 0, e = elementsAttr.size(); i != e; ++i) {
914 auto field = dyn_cast_or_null<DictionaryAttr>(elementsAttr[i]);
918 "Annotation '" + Twine(clazz) +
"' with path '.elements[" +
920 "]' contained an unexpected type (expected a DictionaryAttr).")
922 <<
"The received element was: " << elementsAttr[i] <<
"\n";
925 auto ePath = (path +
".elements[" + Twine(i) +
"]").str();
926 auto name = tryGetAs<StringAttr>(field, root,
"name", loc, clazz, ePath);
928 tryGetAs<DictionaryAttr>(field, root,
"tpe", loc, clazz, ePath);
931 std::optional<StringAttr> description;
932 if (
auto maybeDescription = field.get(
"description"))
933 description = cast<StringAttr>(maybeDescription);
935 state, tpe, root, companion, name, defName, std::nullopt, description,
936 clazz, companionAttr, path +
"_" + name.getValue());
943 if (
auto maybeDescription = field.get(
"description"))
944 attrs.append(
"description", cast<StringAttr>(maybeDescription));
945 attrs.append(
"name", name);
946 auto tpeClass = tpe.getAs<StringAttr>(
"class");
948 mlir::emitError(loc,
"missing 'class' key in") << tpe;
951 attrs.append(
"tpe", tpeClass);
952 elements.push_back(*eltAttr);
958 attrs.append(
"class", classAttr);
959 attrs.append(
"defName", defName);
961 attrs.append(
"description", *description);
964 attrs.append(
"id", *
id);
965 attrs.append(
"name", name);
966 return DictionaryAttr::getWithSorted(context, attrs);
975 if (classBase ==
"GroundType") {
976 auto augRef = augmentedType.getAs<DictionaryAttr>(
"ref");
978 mlir::emitError(loc,
"missing 'ref' key in ") << augmentedType;
981 auto maybeTarget = refToTarget(augRef);
983 mlir::emitError(loc,
"Failed to parse ReferenceTarget").attachNote()
984 <<
"See the full Annotation here: " << root;
988 auto id = state.
newID();
990 auto target = *maybeTarget;
992 NamedAttrList elementIface, elementScattered;
995 elementIface.append(
"class", classAttr);
997 elementIface.append(
"description", *description);
998 elementIface.append(
"id",
id);
999 elementIface.append(
"name", name);
1001 elementScattered.append(
"class", classAttr);
1002 elementScattered.append(
"id",
id);
1007 if (!xmrSrcTarget) {
1008 mlir::emitError(loc,
"Failed to resolve target ") << targetAttr;
1009 return std::nullopt;
1015 auto sourceRef = xmrSrcTarget->ref;
1016 ImplicitLocOpBuilder builder(sourceRef.getOp()->getLoc(), context);
1017 std::optional<Value> source =
1018 TypeSwitch<Operation *, std::optional<Value>>(sourceRef.getOp())
1021 .Case<FExtModuleOp>([&](FExtModuleOp extMod)
1022 -> std::optional<Value> {
1023 auto portNo = sourceRef.getImpl().getPortNo();
1024 if (xmrSrcTarget->instances.empty()) {
1026 if (paths.size() > 1) {
1028 "cannot resolve a unique instance path from the "
1029 "external module '")
1030 << targetAttr <<
"'";
1031 return std::nullopt;
1033 auto *it = xmrSrcTarget->instances.begin();
1034 for (
auto inst : paths.back()) {
1035 xmrSrcTarget->instances.insert(it, cast<InstanceOp>(inst));
1039 auto lastInst = xmrSrcTarget->instances.pop_back_val();
1040 builder.setInsertionPointAfter(lastInst);
1042 xmrSrcTarget->fieldIdx);
1046 .Case<FModuleOp>([&](FModuleOp module) -> std::optional<Value> {
1047 builder.setInsertionPointToEnd(module.getBodyBlock());
1048 auto portNum = sourceRef.getImpl().getPortNo();
1050 xmrSrcTarget->fieldIdx);
1053 .Default([&](Operation *op) -> std::optional<Value> {
1054 auto module = cast<FModuleOp>(sourceRef.getModule());
1055 builder.setInsertionPointToEnd(module.getBodyBlock());
1056 auto is = dyn_cast<hw::InnerSymbolOpInterface>(op);
1058 if (is && is.getTargetResult())
1060 xmrSrcTarget->fieldIdx);
1061 if (sourceRef.getOp()->getNumResults() != 1) {
1063 <<
"cannot be used as a target of the Grand Central View \""
1064 << defName.getValue()
1065 <<
"\" because it does not have exactly one result";
1066 return std::nullopt;
1069 xmrSrcTarget->fieldIdx);
1074 return std::nullopt;
1086 builder.setInsertionPointToEnd(companionMod.getBodyBlock());
1090 auto sinkType = source->getType();
1091 if (
auto baseSinkType = type_dyn_cast<FIRRTLBaseType>(sinkType))
1092 sinkType = baseSinkType.getPassiveType();
1093 auto sink = builder.create<WireOp>(sinkType, name);
1096 annotations.addAnnotations(
1097 {DictionaryAttr::getWithSorted(context, elementScattered)});
1098 annotations.applyToOperation(sink);
1103 (path +
"__bore").str(),
1106 return DictionaryAttr::getWithSorted(context, elementIface);
1111 if (classBase ==
"VectorType") {
1113 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
1115 return std::nullopt;
1116 SmallVector<Attribute> elements;
1117 for (
auto [i, elt] : llvm::enumerate(elementsAttr)) {
1119 state, cast<DictionaryAttr>(elt), root, companion, name,
1121 path +
"_" + Twine(i));
1123 return std::nullopt;
1124 elements.push_back(*eltAttr);
1126 NamedAttrList attrs;
1127 attrs.append(
"class", classAttr);
1129 attrs.append(
"description", *description);
1131 attrs.append(
"name", name);
1132 return DictionaryAttr::getWithSorted(context, attrs);
1137 mlir::emitError(loc,
"found unknown AugmentedType '" + classAttr.getValue() +
1138 "' (Did you misspell it?)")
1140 <<
"see annotation: " << augmentedType;
1141 return std::nullopt;
1145 DictionaryAttr anno,
1148 auto id = state.
newID();
1149 auto *context = state.
circuit.getContext();
1150 auto loc = state.
circuit.getLoc();
1151 NamedAttrList companionAttrs;
1153 companionAttrs.append(
"id",
id);
1155 tryGetAs<DictionaryAttr>(anno, anno,
"view", loc,
viewAnnoClass);
1158 auto name = tryGetAs<StringAttr>(anno, anno,
"name", loc,
viewAnnoClass);
1161 companionAttrs.append(
"name", name);
1162 auto companionAttr =
1163 tryGetAs<StringAttr>(anno, anno,
"companion", loc,
viewAnnoClass);
1166 companionAttrs.append(
"target", companionAttr);
1186 std::optional<Attribute> GrandCentralPass::fromAttr(Attribute attr) {
1187 auto dict = dyn_cast<DictionaryAttr>(attr);
1189 emitCircuitError() <<
"attribute is not a dictionary: " << attr <<
"\n";
1190 return std::nullopt;
1193 auto clazz = dict.getAs<StringAttr>(
"class");
1195 emitCircuitError() <<
"missing 'class' key in " << dict <<
"\n";
1196 return std::nullopt;
1199 auto classBase = clazz.getValue();
1200 classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented");
1202 if (classBase ==
"BundleType") {
1203 if (dict.getAs<StringAttr>(
"defName") && dict.getAs<ArrayAttr>(
"elements"))
1205 emitCircuitError() <<
"has an invalid AugmentedBundleType that does not "
1206 "contain 'defName' and 'elements' fields: "
1208 }
else if (classBase ==
"VectorType") {
1209 if (dict.getAs<StringAttr>(
"name") && dict.getAs<ArrayAttr>(
"elements"))
1211 emitCircuitError() <<
"has an invalid AugmentedVectorType that does not "
1212 "contain 'name' and 'elements' fields: "
1214 }
else if (classBase ==
"GroundType") {
1215 auto id = dict.getAs<IntegerAttr>(
"id");
1216 auto name = dict.getAs<StringAttr>(
"name");
1217 if (
id && leafMap.count(
id) && name)
1220 emitCircuitError() <<
"has an invalid AugmentedGroundType that does not "
1221 "contain 'id' and 'name' fields: "
1223 if (
id && !leafMap.count(
id))
1224 emitCircuitError() <<
"has an AugmentedGroundType with 'id == "
1225 <<
id.getValue().getZExtValue()
1226 <<
"' that does not have a scattered leaf to connect "
1227 "to in the circuit "
1228 "(was the leaf deleted or constant prop'd away?)";
1230 emitCircuitError() <<
"has an invalid AugmentedType";
1232 return std::nullopt;
1235 bool GrandCentralPass::traverseField(
1236 Attribute field, IntegerAttr
id, VerbatimBuilder &path,
1237 SmallVector<VerbatimXMRbuilder> &xmrElems,
1238 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1239 return TypeSwitch<Attribute, bool>(field)
1240 .Case<AugmentedGroundTypeAttr>([&](AugmentedGroundTypeAttr ground) {
1241 auto [fieldRef, sym] = leafMap.lookup(ground.getID());
1244 nla = nlaTable->
getNLA(sym.getAttr());
1245 Value leafValue = fieldRef.getValue();
1246 assert(leafValue &&
"leafValue not found");
1248 auto companionModule = companionIDMap.lookup(
id).companion;
1249 igraph::ModuleOpInterface enclosing =
1250 getEnclosingModule(leafValue, sym);
1252 auto tpe = type_cast<FIRRTLBaseType>(leafValue.getType());
1255 if (!tpe.getBitWidthOrSentinel())
1267 auto *nodeOp = leafValue.getDefiningOp();
1268 if (companionModule != enclosing) {
1269 auto diag = companionModule->emitError()
1270 <<
"Grand Central View \""
1271 << companionIDMap.lookup(
id).name
1272 <<
"\" is invalid because a leaf is not inside the "
1274 diag.attachNote(leafValue.getLoc())
1275 <<
"the leaf value is declared here";
1277 auto leafModule = nodeOp->getParentOfType<FModuleOp>();
1278 diag.attachNote(leafModule.getLoc())
1279 <<
"the leaf value is inside this module";
1284 if (!isa<NodeOp>(nodeOp)) {
1285 emitError(leafValue.getLoc())
1286 <<
"Grand Central View \"" << companionIDMap.lookup(
id).name
1287 <<
"\" has an invalid leaf value (this must be a node)";
1294 auto getStrAndIncrementIds = [&](StringRef base) -> StringAttr {
1295 SmallString<128> replStr;
1296 StringRef begin =
"{{";
1297 StringRef
end =
"}}";
1300 while (from < base.size()) {
1302 size_t beginAt = base.find(begin, from);
1303 size_t endAt = base.find(end, from);
1305 if (beginAt == StringRef::npos || endAt == StringRef::npos ||
1306 (beginAt > endAt)) {
1307 replStr.append(base.substr(from));
1311 replStr.append(base.substr(from, beginAt - from));
1314 auto idChar = base.substr(beginAt + 2, endAt - beginAt - 2);
1316 bool failed = idChar.getAsInteger(10, idNum);
1318 assert(!failed &&
"failed to parse integer from verbatim string");
1320 replStr.append(
"{{");
1321 Twine(idNum + 1).toVector(replStr);
1322 replStr.append(
"}}");
1331 path +=
" = {{-1}}";
1334 xmrElems.emplace_back(
1335 nodeOp->getOperand(0), getStrAndIncrementIds(path.getString()),
1336 ArrayAttr::get(&getContext(), path.getSymbols()), companionModule);
1339 .Case<AugmentedVectorTypeAttr>([&](
auto vector) {
1340 bool notFailed =
true;
1341 auto elements = vector.getElements();
1342 for (
size_t i = 0, e = elements.size(); i != e; ++i) {
1343 auto field = fromAttr(elements[i]);
1346 notFailed &= traverseField(
1347 *field,
id, path.snapshot().append(
"[" + Twine(i) +
"]"),
1348 xmrElems, interfaceBuilder);
1352 .Case<AugmentedBundleTypeAttr>([&](AugmentedBundleTypeAttr bundle) {
1353 bool anyFailed =
true;
1354 for (
auto element : bundle.getElements()) {
1355 auto field = fromAttr(element);
1358 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1360 name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"defName");
1361 anyFailed &= traverseField(
1362 *field,
id, path.snapshot().append(
"." + name.getValue()),
1363 xmrElems, interfaceBuilder);
1368 .Default([](
auto a) {
return true; });
1371 std::optional<TypeSum> GrandCentralPass::computeField(
1372 Attribute field, IntegerAttr
id, VerbatimBuilder &path,
1373 SmallVector<VerbatimXMRbuilder> &xmrElems,
1374 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1375 return TypeSwitch<Attribute, std::optional<TypeSum>>(field)
1376 .Case<AugmentedGroundTypeAttr>(
1377 [&](AugmentedGroundTypeAttr ground) -> std::optional<TypeSum> {
1379 if (!traverseField(field,
id, path, xmrElems, interfaceBuilder))
1380 return std::nullopt;
1381 FieldRef fieldRef = leafMap.lookup(ground.getID()).field;
1384 auto tpe = firrtl::type_cast<FIRRTLBaseType>(
1387 if (!tpe.isGround()) {
1388 value.getDefiningOp()->emitOpError()
1389 <<
"cannot be added to interface with id '"
1390 <<
id.getValue().getZExtValue()
1391 <<
"' because it is not a ground type";
1392 return std::nullopt;
1395 tpe.getBitWidthOrSentinel()));
1397 .Case<AugmentedVectorTypeAttr>(
1398 [&](AugmentedVectorTypeAttr vector) -> std::optional<TypeSum> {
1399 auto elements = vector.getElements();
1400 if (elements.empty())
1401 llvm::report_fatal_error(
1402 "unexpected empty augmented vector in GrandCentral View");
1403 auto firstElement = fromAttr(elements[0]);
1405 return std::nullopt;
1407 *firstElement,
id, path.snapshot().append(
"[" + Twine(0) +
"]"),
1408 xmrElems, interfaceBuilder);
1410 return std::nullopt;
1412 for (
size_t i = 1, e = elements.size(); i != e; ++i) {
1413 auto subField = fromAttr(elements[i]);
1415 return std::nullopt;
1416 (void)traverseField(*subField,
id,
1417 path.snapshot().append(
"[" + Twine(i) +
"]"),
1418 xmrElems, interfaceBuilder);
1425 str.dimensions.push_back(elements.getValue().size());
1426 return TypeSum(str);
1428 .Case<AugmentedBundleTypeAttr>(
1429 [&](AugmentedBundleTypeAttr bundle) -> TypeSum {
1431 traverseBundle(bundle,
id, path, xmrElems, interfaceBuilder);
1432 assert(ifaceName && *ifaceName);
1433 return VerbatimType({ifaceName->str(),
true});
1443 std::optional<StringAttr> GrandCentralPass::traverseBundle(
1444 AugmentedBundleTypeAttr bundle, IntegerAttr
id, VerbatimBuilder &path,
1445 SmallVector<VerbatimXMRbuilder> &xmrElems,
1446 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1448 unsigned lastIndex = interfaceBuilder.size();
1450 &getContext(), getNamespace().newName(getInterfaceName(bundle)));
1451 interfaceBuilder.emplace_back(iFaceName,
id);
1453 for (
auto element : bundle.getElements()) {
1454 auto field = fromAttr(element);
1456 return std::nullopt;
1458 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1469 *field,
id, path.snapshot().append(
".").append(name.getValue()),
1470 xmrElems, interfaceBuilder);
1472 return std::nullopt;
1473 StringAttr description =
1474 cast<DictionaryAttr>(element).getAs<StringAttr>(
"description");
1475 interfaceBuilder[lastIndex].elementsList.emplace_back(description, name,
1483 igraph::ModuleOpInterface
1484 GrandCentralPass::getEnclosingModule(Value value, FlatSymbolRefAttr sym) {
1485 if (
auto blockArg = dyn_cast<BlockArgument>(value))
1486 return cast<igraph::ModuleOpInterface>(blockArg.getOwner()->getParentOp());
1488 auto *op = value.getDefiningOp();
1489 if (InstanceOp instance = dyn_cast<InstanceOp>(op))
1490 return getSymbolTable().lookup<igraph::ModuleOpInterface>(
1491 instance.getModuleNameAttr().getValue());
1493 return op->getParentOfType<igraph::ModuleOpInterface>();
1497 void GrandCentralPass::runOnOperation() {
1500 CircuitOp circuitOp = getOperation();
1509 SmallVector<Annotation> worklist;
1510 bool removalError =
false;
1519 if (companionMode != CompanionMode::Instantiate)
1520 worklist.push_back(anno);
1525 if (maybeExtractInfo) {
1526 emitCircuitError(
"more than one 'ExtractGrandCentralAnnotation' was "
1527 "found, but exactly one must be provided");
1528 removalError = true;
1532 auto directory = anno.
getMember<StringAttr>(
"directory");
1533 auto filename = anno.
getMember<StringAttr>(
"filename");
1534 if (!directory || !filename) {
1536 <<
"contained an invalid 'ExtractGrandCentralAnnotation' that does "
1537 "not contain 'directory' and 'filename' fields: "
1539 removalError =
true;
1542 if (directory.getValue().empty())
1545 maybeExtractInfo = {directory, filename};
1550 if (maybeHierarchyFileYAML) {
1551 emitCircuitError(
"more than one 'GrandCentralHierarchyFileAnnotation' "
1552 "was found, but zero or one may be provided");
1553 removalError =
true;
1557 auto filename = anno.
getMember<StringAttr>(
"filename");
1560 <<
"contained an invalid 'GrandCentralHierarchyFileAnnotation' "
1561 "that does not contain 'directory' and 'filename' fields: "
1563 removalError =
true;
1567 maybeHierarchyFileYAML = filename;
1572 testbenchDir = anno.
getMember<StringAttr>(
"dirname");
1580 for (
auto mod : circuitOp.getOps<FModuleLike>()) {
1582 removalError =
true;
1586 return signalPassFailure();
1589 llvm::dbgs() <<
"Extraction Info:\n";
1590 if (maybeExtractInfo)
1591 llvm::dbgs() <<
" directory: " << maybeExtractInfo->directory <<
"\n"
1592 <<
" filename: " << maybeExtractInfo->bindFilename <<
"\n";
1594 llvm::dbgs() <<
" <none>\n";
1595 llvm::dbgs() <<
"DUT: ";
1597 llvm::dbgs() << dut.getModuleName() <<
"\n";
1599 llvm::dbgs() <<
"<none>\n";
1601 <<
"Hierarchy File Info (from GrandCentralHierarchyFileAnnotation):\n"
1603 if (maybeHierarchyFileYAML)
1604 llvm::dbgs() << *maybeHierarchyFileYAML;
1606 llvm::dbgs() <<
"<none>";
1607 llvm::dbgs() <<
"\n";
1613 if (worklist.empty()) {
1614 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1615 emitHierarchyYamlFile(interfaceVec);
1616 return markAllAnalysesPreserved();
1623 auto builder = OpBuilder::atBlockEnd(circuitOp.getBodyBlock());
1627 auto getID = [&](Operation *op,
1628 Annotation annotation) -> std::optional<IntegerAttr> {
1629 auto id = annotation.getMember<IntegerAttr>(
"id");
1632 <<
"contained a malformed "
1633 "'sifive.enterprise.grandcentral.AugmentedGroundType' annotation "
1634 "that did not contain an 'id' field";
1635 removalError =
true;
1636 return std::nullopt;
1643 instancePaths = &instancePathCache;
1644 instanceInfo = &getAnalysis<InstanceInfo>();
1648 auto exactlyOneInstance = [&](FModuleOp op,
1649 StringRef msg) -> std::optional<InstanceOp> {
1652 switch (node->getNumUses()) {
1654 op->emitOpError() <<
"is marked as a GrandCentral '" << msg
1655 <<
"', but is never instantiated";
1656 return std::nullopt;
1658 return cast<InstanceOp>(*(*node->uses().begin())->getInstance());
1660 auto diag = op->emitOpError()
1661 <<
"is marked as a GrandCentral '" << msg
1662 <<
"', but it is instantiated more than once";
1663 for (
auto *instance : node->uses())
1664 diag.attachNote(instance->getInstance()->getLoc())
1665 <<
"it is instantiated here";
1666 return std::nullopt;
1670 nlaTable = &getAnalysis<NLATable>();
1676 DenseSet<Operation *> modulesToDelete;
1677 circuitOp.walk([&](Operation *op) {
1678 TypeSwitch<Operation *>(op)
1679 .Case<RegOp, RegResetOp, WireOp, NodeOp>([&](
auto op) {
1683 auto maybeID = getID(op, annotation);
1687 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1688 leafMap[*maybeID] = {{op.getResult(), annotation.
getFieldID()},
1695 .Case<InstanceOp>([&](
auto op) {
1701 <<
"is marked as an interface element, but this should be "
1702 "impossible due to how the Chisel Grand Central API works";
1703 removalError =
true;
1707 .Case<MemOp>([&](
auto op) {
1712 <<
"is marked as an interface element, but this does not make "
1713 "sense (is there a scattering bug or do you have a "
1714 "malformed hand-crafted MLIR circuit?)";
1715 removalError =
true;
1723 <<
"has port '" << i
1724 <<
"' marked as an interface element, but this does not "
1725 "make sense (is there a scattering bug or do you have a "
1726 "malformed hand-crafted MLIR circuit?)";
1727 removalError =
true;
1731 .Case<FModuleOp>([&](FModuleOp op) {
1737 auto maybeID = getID(op, annotation);
1741 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1742 leafMap[*maybeID] = {{op.getArgument(i), annotation.
getFieldID()},
1752 auto isNonlocal = annotation.
getMember<FlatSymbolRefAttr>(
1753 "circt.nonlocal") !=
nullptr;
1754 auto name = annotation.
getMember<StringAttr>(
"name");
1755 auto id = annotation.
getMember<IntegerAttr>(
"id");
1758 <<
"has a malformed "
1759 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1760 "not contain an 'id' field with an 'IntegerAttr' value";
1761 goto FModuleOp_error;
1765 <<
"has a malformed "
1766 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1767 "not contain a 'name' field with a 'StringAttr' value";
1768 goto FModuleOp_error;
1781 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
1783 companionIDMap[id] = {name.getValue(), op, isNonlocal};
1786 auto instance = exactlyOneInstance(op,
"companion");
1788 goto FModuleOp_error;
1791 for (
auto [i, result] : llvm::enumerate(instance->getResults())) {
1792 if (instance->getPortDirection(i) == Direction::In)
1795 auto ty = result.getType();
1796 if (isa<RefType>(ty) && companionMode != CompanionMode::Drop)
1799 <<
"companion instance cannot have output ports";
1800 goto FModuleOp_error;
1805 if (!maybeExtractInfo) {
1825 <<
"Found companion module: "
1826 << companionNode->getModule().getModuleName() <<
"\n"
1827 <<
" submodules exclusively instantiated "
1828 "(including companion):\n";
1833 OpBuilder builder(&getContext());
1834 for (
auto port : instance->getResults()) {
1835 builder.setInsertionPointAfterValue(port);
1837 builder.create<WireOp>(port.getLoc(), port.getType());
1838 port.replaceAllUsesWith(wire.getResult());
1845 (*instance)->setAttr(
"lowerToBind", builder.getUnitAttr());
1847 (*instance)->setAttr(
1849 hw::OutputFileAttr::getFromFilename(
1851 maybeExtractInfo->bindFilename.getValue(),
1855 for (
auto &node : llvm::depth_first(companionNode)) {
1856 auto mod = node->getModule();
1864 if (modNode != companionNode &&
1866 modNode->getModule()))
1871 <<
" - module: " << mod.getModuleName() <<
"\n";
1874 if (
auto extmodule = dyn_cast<FExtModuleOp>(*mod)) {
1877 modulesToDelete.insert(mod);
1883 if (extmodule->hasAttr(
"output_file"))
1887 hw::OutputFileAttr::getAsDirectory(
1889 maybeExtractInfo->directory.getValue()));
1896 modulesToDelete.insert(mod);
1900 if (!mod->hasAttr(
"output_file")) {
1901 mod->setAttr(
"output_file",
1902 hw::OutputFileAttr::getAsDirectory(
1904 maybeExtractInfo->directory.getValue(),
1907 mod->setAttr(
"comment", builder.getStringAttr(
1908 "VCS coverage exclude_file"));
1918 <<
"unknown annotation class: " << annotation.
getDict();
1921 removalError =
true;
1928 return signalPassFailure();
1930 if (companionMode == CompanionMode::Drop) {
1931 for (
auto *mod : modulesToDelete) {
1932 auto name = cast<FModuleLike>(mod).getModuleNameAttr();
1934 DenseSet<hw::HierPathOp> nlas;
1937 for (
auto nla : nlas) {
1938 if (nla.root() == name)
1945 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1946 emitHierarchyYamlFile(interfaceVec);
1953 SmallVector<IntegerAttr> ids;
1954 auto sort = [&ids]() {
1955 llvm::sort(ids, [](IntegerAttr a, IntegerAttr b) {
1956 return a.getValue().getZExtValue() < b.getValue().getZExtValue();
1959 for (
auto tuple : companionIDMap)
1960 ids.push_back(cast<IntegerAttr>(tuple.first));
1962 llvm::dbgs() <<
"companionIDMap:\n";
1963 for (
auto id : ids) {
1964 auto value = companionIDMap.lookup(
id);
1965 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
1966 << value.companion.getName() <<
" -> " << value.name <<
"\n";
1969 for (
auto tuple : leafMap)
1970 ids.push_back(cast<IntegerAttr>(tuple.first));
1972 llvm::dbgs() <<
"leafMap:\n";
1973 for (
auto id : ids) {
1974 auto fieldRef = leafMap.lookup(
id).field;
1977 if (
auto blockArg = dyn_cast<BlockArgument>(value)) {
1978 FModuleOp module = cast<FModuleOp>(blockArg.getOwner()->getParentOp());
1979 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
1980 << module.getName() +
">" +
1981 module.getPortName(blockArg.getArgNumber());
1983 llvm::dbgs() <<
", fieldID=" << fieldID;
1984 llvm::dbgs() <<
"\n";
1986 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
1987 << cast<StringAttr>(value.getDefiningOp()->getAttr(
"name"))
1990 llvm::dbgs() <<
", fieldID=" << fieldID;
1991 llvm::dbgs() <<
"\n";
2002 SmallVector<sv::InterfaceOp, 2> interfaceVec;
2004 companionToInterfaceMap;
2005 auto compareInterfaceSignal = [&](InterfaceElemsBuilder &lhs,
2006 InterfaceElemsBuilder &rhs) {
2007 auto compareProps = [&](InterfaceElemsBuilder::Properties &lhs,
2008 InterfaceElemsBuilder::Properties &rhs) {
2012 if (lhs.elemType.index() == 0 && rhs.elemType.index() == 0)
2014 if (std::get<Type>(lhs.elemType) == std::get<Type>(rhs.elemType))
2018 return std::equal(lhs.elementsList.begin(), lhs.elementsList.end(),
2019 rhs.elementsList.begin(), compareProps);
2021 for (
auto anno : worklist) {
2026 if (!bundle.isRoot()) {
2027 emitCircuitError() <<
"missing 'id' in root-level BundleType: "
2029 removalError =
true;
2033 if (companionIDMap.count(bundle.getID()) == 0) {
2034 emitCircuitError() <<
"no companion found with 'id' value '"
2035 << bundle.getID().getValue().getZExtValue() <<
"'\n";
2036 removalError =
true;
2042 auto companionIter = companionIDMap.lookup(bundle.getID());
2043 auto companionModule = companionIter.companion;
2044 auto symbolName = getNamespace().newName(
2045 "__" + companionIDMap.lookup(bundle.getID()).name +
"_" +
2046 getInterfaceName(bundle) +
"__");
2052 auto instanceSymbol =
2055 VerbatimBuilder::Base verbatimData;
2056 VerbatimBuilder verbatim(verbatimData);
2057 verbatim += instanceSymbol;
2060 SmallVector<VerbatimXMRbuilder> xmrElems;
2061 SmallVector<InterfaceElemsBuilder> interfaceBuilder;
2063 auto ifaceName = traverseBundle(bundle, bundle.getID(), verbatim, xmrElems,
2066 removalError =
true;
2070 if (companionIter.isNonlocal) {
2074 auto viewMapIter = companionToInterfaceMap.find(companionModule);
2075 if (viewMapIter != companionToInterfaceMap.end())
2076 if (std::equal(interfaceBuilder.begin(), interfaceBuilder.end(),
2077 viewMapIter->getSecond().begin(),
2078 compareInterfaceSignal)) {
2082 companionToInterfaceMap[companionModule] = interfaceBuilder;
2085 if (interfaceBuilder.empty())
2087 auto companionBuilder =
2088 OpBuilder::atBlockEnd(companionModule.getBodyBlock());
2091 for (
auto xmrElem : xmrElems) {
2092 auto uloc = companionBuilder.getUnknownLoc();
2093 companionBuilder.create<sv::VerbatimOp>(uloc, xmrElem.str, xmrElem.val,
2096 numXMRs += xmrElems.size();
2098 sv::InterfaceOp topIface;
2099 for (
const auto &ifaceBuilder : interfaceBuilder) {
2100 auto builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
2101 auto loc = getOperation().getLoc();
2102 sv::InterfaceOp iface =
2103 builder.create<sv::InterfaceOp>(loc, ifaceBuilder.iFaceName);
2109 companionIDMap[ifaceBuilder.id].companion, dut) &&
2111 iface->setAttr(
"output_file",
2112 hw::OutputFileAttr::getAsDirectory(
2113 &getContext(), testbenchDir.getValue(),
2115 else if (maybeExtractInfo)
2116 iface->setAttr(
"output_file",
2117 hw::OutputFileAttr::getAsDirectory(
2118 &getContext(), getOutputDirectory().getValue(),
2120 iface.setCommentAttr(builder.getStringAttr(
"VCS coverage exclude_file"));
2121 builder.setInsertionPointToEnd(
2122 cast<sv::InterfaceOp>(iface).getBodyBlock());
2124 ifaceBuilder.iFaceName)] = iface;
2125 for (
auto elem : ifaceBuilder.elementsList) {
2127 auto uloc = builder.getUnknownLoc();
2129 auto description = elem.description;
2132 auto descriptionOp = builder.create<sv::VerbatimOp>(
2133 uloc, (
"// " + cleanupDescription(description.getValue())));
2138 if (maybeHierarchyFileYAML)
2139 descriptionOp->setAttr(
"firrtl.grandcentral.yaml.type",
2140 builder.getStringAttr(
"description"));
2142 if (
auto *str = std::get_if<VerbatimType>(&elem.elemType)) {
2143 auto instanceOp = builder.create<sv::VerbatimOp>(
2144 uloc, str->toStr(elem.elemName.getValue()));
2148 if (maybeHierarchyFileYAML) {
2149 if (str->instantiation)
2150 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2151 builder.getStringAttr(
"instance"));
2153 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2154 builder.getStringAttr(
"unsupported"));
2155 instanceOp->setAttr(
"firrtl.grandcentral.yaml.name", elem.elemName);
2156 instanceOp->setAttr(
"firrtl.grandcentral.yaml.dimensions",
2157 builder.getI32ArrayAttr(str->dimensions));
2158 instanceOp->setAttr(
2159 "firrtl.grandcentral.yaml.symbol",
2165 auto tpe = std::get<Type>(elem.elemType);
2166 builder.create<sv::InterfaceSignalOp>(uloc, elem.elemName.getValue(),
2173 interfaceVec.push_back(topIface);
2176 builder.setInsertionPointToStart(companionModule.getBodyBlock());
2177 builder.create<sv::InterfaceInstanceOp>(
2178 getOperation().getLoc(), topIface.getInterfaceType(),
2179 companionIDMap.lookup(bundle.getID()).name,
2184 if (!maybeExtractInfo)
2190 companionIDMap[bundle.getID()].companion, dut))
2194 emitHierarchyYamlFile(interfaceVec);
2199 return signalPassFailure();
2200 markAnalysesPreserved<NLATable>();
2203 void GrandCentralPass::emitHierarchyYamlFile(
2204 SmallVectorImpl<sv::InterfaceOp> &intfs) {
2208 if (!maybeHierarchyFileYAML)
2211 CircuitOp circuitOp = getOperation();
2213 std::string yamlString;
2214 llvm::raw_string_ostream stream(yamlString);
2215 ::yaml::Context yamlContext({interfaceMap});
2217 yamlize(yout, intfs,
true, yamlContext);
2219 auto builder = OpBuilder::atBlockBegin(circuitOp.getBodyBlock());
2220 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), yamlString)
2221 ->setAttr(
"output_file",
2222 hw::OutputFileAttr::getFromFilename(
2223 &getContext(), maybeHierarchyFileYAML->getValue(),
2225 LLVM_DEBUG({ llvm::dbgs() <<
"Generated YAML:" << yamlString <<
"\n"; });
2232 std::unique_ptr<mlir::Pass>
2234 auto pass = std::make_unique<GrandCentralPass>();
2235 pass->companionMode = companionMode;
assert(baseType &&"element must be base type")
static std::optional< DictionaryAttr > parseAugmentedType(ApplyState &state, DictionaryAttr augmentedType, DictionaryAttr root, StringRef companion, StringAttr name, StringAttr defName, std::optional< IntegerAttr > id, std::optional< StringAttr > description, Twine clazz, StringAttr companionAttr, Twine path={})
Recursively walk a sifive.enterprise.grandcentral.AugmentedType to extract any annotations it may con...
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static Block * getBodyBlock(FModuleLike mod)
This class represents a reference to a specific field or element of an aggregate value.
unsigned getFieldID() const
Get the field ID of this FieldRef, which is a unique identifier mapped to a specific field in a bundl...
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
void addAnnotations(ArrayRef< Annotation > annotations)
Add more annotations to this annotation set.
static bool removePortAnnotations(Operation *module, llvm::function_ref< bool(unsigned, Annotation)> predicate)
Remove all port annotations from a module or extmodule for which predicate returns true.
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
unsigned getFieldID() const
Get the field id this attribute targets.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
StringRef getClass() const
Return the 'class' that this annotation is representing.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
bool anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the effective design.
This table tracks nlas and what modules participate in them.
void removeNLAsfromModule(const DenseSet< hw::HierPathOp > &nlas, StringAttr mod)
Remove all the nlas in the set nlas from the module.
void getNLAsInModule(StringAttr modName, DenseSet< hw::HierPathOp > &nlas)
Get the NLAs that the module modName particiaptes in, and insert them into the DenseSet nlas.
hw::HierPathOp getNLA(StringAttr name)
Resolve a symbol to an NLA.
This is a Node in the InstanceGraph.
bool isAncestor(ModuleOpInterface child, ModuleOpInterface parent, llvm::function_ref< bool(InstanceRecord *)> skipInstance=[](InstanceRecord *_) { return false;})
Check if child is instantiated by a parent.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
constexpr const char * augmentedBundleTypeClass
igraph::InstancePathCache InstancePathCache
constexpr const char * extractGrandCentralClass
constexpr const char * testBenchDirAnnoClass
constexpr const char * augmentedGroundTypeClass
std::unique_ptr< mlir::Pass > createGrandCentralPass(CompanionMode companionMode=CompanionMode::Bind)
constexpr const char * viewAnnoClass
constexpr const char * blackBoxPathAnnoClass
LogicalResult extractDUT(FModuleLike mod, FModuleLike &dut)
Utility that searches for a MarkDUTAnnotation on a specific module, mod, and tries to update a design...
Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value, unsigned fieldID)
This gets the value targeted by a field id.
constexpr const char * companionAnnoClass
constexpr const char * blackBoxInlineAnnoClass
std::optional< AnnoPathValue > resolvePath(StringRef rawPath, CircuitOp circuit, SymbolTable &symTbl, CircuitTargetCache &cache)
Resolve a string path to a named item inside a circuit.
LogicalResult applyGCTView(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
constexpr const char * grandCentralHierarchyFileAnnoClass
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
static std::string stripComment(StringRef str)
Convert newlines and comments to remove the comments.
State threaded through functions for resolving and applying annotations.
SmallVector< WiringProblem > wiringProblems
AddToWorklistFn addToWorklistFn
InstancePathCache & instancePathCache
CircuitTargetCache targetCaches
The namespace of a CircuitOp, generally inhabited by modules.
void insertOp(Operation *op)
Add a new op to the target cache.
A data structure that caches and provides absolute paths to module instances in the IR.
ArrayRef< InstancePath > getAbsolutePaths(ModuleOpInterface op)
InstanceGraph & instanceGraph
The instance graph of the IR.
StringRef name
The name of the interface.
FlatSymbolRefAttr interface
The underlying interface.
Instance(IO &io, DescribedInstance &op)
DescribedInstance denormalize(IO &)
SmallVector< int64_t, 2 > dimensions
An array describing the dimensionality of the interface.
static void mapping(IO &io, DescribedInstance &op, Context &ctx)
DescribedSignal denormalize(IO &)
This cannot be denormalized back to an interface op.
StringRef name
The name of the field.
std::optional< std::string > description
An optional, textual description of what the field is.
Field(IO &io)
A no-argument constructor is necessary to work with LLVM's YAML library.
unsigned width
The width of the underlying type.
Field(IO &io, DescribedSignal &op)
Construct a Field from a DescribedSignal (an sv::InterfaceSignalOp with an optional description).
SmallVector< unsigned, 2 > dimensions
The dimensions of the field.
static void mapping(IO &io, DescribedSignal &op, Context &ctx)
Interface(IO &io)
A no-argument constructor is necessary to work with LLVM's YAML library.
std::vector< DescribedInstance > instances
Instantiations of other interfaces.
StringRef name
The name of the interface.
Interface(IO &io, sv::InterfaceOp &op)
Construct an Interface from an sv::InterfaceOp.
sv::InterfaceOp denormalize(IO &)
This cannot be denormalized back to an interface op.
std::vector< DescribedSignal > fields
All ground or vectors that make up the interface.
static void mapping(IO &io, sv::InterfaceOp &op, Context &ctx)