27 #include "mlir/IR/ImplicitLocOpBuilder.h"
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;
613 StringRef interfacePrefix;
624 StringAttr testbenchDir;
628 std::string getInterfaceName(StringAttr prefix,
629 AugmentedBundleTypeAttr bundleType) {
632 return (prefix.getValue() + interfacePrefix +
633 bundleType.getDefName().getValue())
635 return (interfacePrefix + bundleType.getDefName().getValue()).str();
640 bool traverseField(Attribute field, IntegerAttr
id, VerbatimBuilder &path,
641 SmallVector<VerbatimXMRbuilder> &xmrElems,
642 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
647 std::optional<TypeSum>
648 computeField(Attribute field, IntegerAttr
id, StringAttr prefix,
649 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
650 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
655 std::optional<StringAttr>
656 traverseBundle(AugmentedBundleTypeAttr bundle, IntegerAttr
id,
657 StringAttr prefix, VerbatimBuilder &path,
658 SmallVector<VerbatimXMRbuilder> &xmrElems,
659 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
662 igraph::ModuleOpInterface getEnclosingModule(Value value,
663 FlatSymbolRefAttr sym = {});
667 std::optional<ExtractionInfo> maybeExtractInfo = std::nullopt;
671 std::optional<StringAttr> maybeHierarchyFileYAML = std::nullopt;
673 StringAttr getOutputDirectory() {
674 if (maybeExtractInfo)
675 return maybeExtractInfo->directory;
689 std::optional<CircuitNamespace> circuitNamespace;
693 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
698 if (!circuitNamespace)
700 return *circuitNamespace;
704 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
705 return moduleNamespaces.try_emplace(module, module).first->second;
710 std::optional<SymbolTable *> symbolTable;
714 SymbolTable &getSymbolTable() {
716 symbolTable = &getAnalysis<SymbolTable>();
717 return **symbolTable;
724 InFlightDiagnostic emitCircuitError(StringRef message = {}) {
725 return emitError(getOperation().getLoc(),
"'firrtl.circuit' op " + message);
733 std::string cleanupDescription(StringRef description) {
737 std::tie(head, description) = description.split(
"\n");
739 if (!description.empty())
741 }
while (!description.empty());
742 return std::string(out);
746 DenseMap<Attribute, sv::InterfaceOp> interfaceMap;
749 void emitHierarchyYamlFile(SmallVectorImpl<sv::InterfaceOp> &intfs);
763 static std::optional<DictionaryAttr>
765 DictionaryAttr root, StringRef companion, StringAttr name,
766 StringAttr defName, std::optional<IntegerAttr>
id,
767 std::optional<StringAttr> description, Twine clazz,
768 StringAttr companionAttr, Twine path = {}) {
770 auto *context = state.
circuit.getContext();
771 auto loc = state.
circuit.getLoc();
788 [&](DictionaryAttr refTarget) -> std::optional<std::string> {
790 tryGetAs<StringAttr>(refTarget, refTarget,
"circuit", loc, clazz, path);
792 tryGetAs<StringAttr>(refTarget, refTarget,
"module", loc, clazz, path);
794 tryGetAs<ArrayAttr>(refTarget, refTarget,
"path", loc, clazz, path);
795 auto componentAttr = tryGetAs<ArrayAttr>(refTarget, refTarget,
"component",
797 if (!circuitAttr || !moduleAttr || !pathAttr || !componentAttr)
801 SmallString<32> strpath;
802 for (
auto p : pathAttr) {
803 auto dict = dyn_cast_or_null<DictionaryAttr>(p);
805 mlir::emitError(loc,
"annotation '" + clazz +
806 " has invalid type (expected DictionaryAttr)");
810 tryGetAs<DictionaryAttr>(dict, dict,
"_1", loc, clazz, path);
812 tryGetAs<DictionaryAttr>(dict, dict,
"_2", loc, clazz, path);
813 if (!instHolder || !modHolder) {
814 mlir::emitError(loc,
"annotation '" + clazz +
815 " has invalid type (expected DictionaryAttr)");
818 auto inst = tryGetAs<StringAttr>(instHolder, instHolder,
"value", loc,
821 tryGetAs<StringAttr>(modHolder, modHolder,
"value", loc, clazz, path);
823 mlir::emitError(loc,
"annotation '" + clazz +
824 " has invalid type (expected DictionaryAttr)");
827 strpath +=
"/" + inst.getValue().str() +
":" + mod.getValue().str();
830 SmallVector<Attribute> componentAttrs;
831 SmallString<32> componentStr;
832 for (
size_t i = 0, e = componentAttr.size(); i != e; ++i) {
833 auto cPath = (path +
".component[" + Twine(i) +
"]").str();
834 auto component = componentAttr[i];
835 auto dict = dyn_cast_or_null<DictionaryAttr>(component);
837 mlir::emitError(loc,
"annotation '" + clazz +
"' with path '" + cPath +
838 " has invalid type (expected DictionaryAttr)");
842 tryGetAs<StringAttr>(dict, refTarget,
"class", loc, clazz, cPath);
846 auto value = dict.get(
"value");
849 if (
auto field = dyn_cast<StringAttr>(value)) {
850 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Field" &&
851 "A StringAttr target token must be found with a subfield target "
853 componentStr.append((Twine(
".") + field.getValue()).str());
858 if (
auto index = dyn_cast<IntegerAttr>(value)) {
859 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Index" &&
860 "An IntegerAttr target token must be found with a subindex "
863 (Twine(
"[") + Twine(index.getValue().getZExtValue()) +
"]").str());
868 "Annotation '" + clazz +
"' with path '" + cPath +
869 ".value has unexpected type (should be StringAttr "
870 "for subfield or IntegerAttr for subindex).")
872 <<
"The value received was: " << value <<
"\n";
877 tryGetAs<StringAttr>(refTarget, refTarget,
"ref", loc, clazz, path);
881 return (Twine(
"~" + circuitAttr.getValue() +
"|" + moduleAttr.getValue() +
882 strpath +
">" + refAttr.getValue()) +
888 tryGetAs<StringAttr>(augmentedType, root,
"class", loc, clazz, path);
891 StringRef classBase = classAttr.getValue();
892 if (!classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented")) {
894 "the 'class' was expected to start with "
895 "'sifive.enterprise.grandCentral.Augmented*', but was '" +
896 classAttr.getValue() +
"' (Did you misspell it?)")
898 <<
"see annotation: " << augmentedType;
905 if (classBase ==
"BundleType") {
907 tryGetAs<StringAttr>(augmentedType, root,
"defName", loc, clazz, path);
915 SmallVector<Attribute> elements;
917 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
920 for (
size_t i = 0, e = elementsAttr.size(); i != e; ++i) {
921 auto field = dyn_cast_or_null<DictionaryAttr>(elementsAttr[i]);
925 "Annotation '" + Twine(clazz) +
"' with path '.elements[" +
927 "]' contained an unexpected type (expected a DictionaryAttr).")
929 <<
"The received element was: " << elementsAttr[i] <<
"\n";
932 auto ePath = (path +
".elements[" + Twine(i) +
"]").str();
933 auto name = tryGetAs<StringAttr>(field, root,
"name", loc, clazz, ePath);
935 tryGetAs<DictionaryAttr>(field, root,
"tpe", loc, clazz, ePath);
938 std::optional<StringAttr> description;
939 if (
auto maybeDescription = field.get(
"description"))
940 description = cast<StringAttr>(maybeDescription);
942 state, tpe, root, companion, name, defName, std::nullopt, description,
943 clazz, companionAttr, path +
"_" + name.getValue());
950 if (
auto maybeDescription = field.get(
"description"))
951 attrs.append(
"description", cast<StringAttr>(maybeDescription));
952 attrs.append(
"name", name);
953 auto tpeClass = tpe.getAs<StringAttr>(
"class");
955 mlir::emitError(loc,
"missing 'class' key in") << tpe;
958 attrs.append(
"tpe", tpeClass);
959 elements.push_back(*eltAttr);
965 attrs.append(
"class", classAttr);
966 attrs.append(
"defName", defName);
968 attrs.append(
"description", *description);
971 attrs.append(
"id", *
id);
972 attrs.append(
"name", name);
973 return DictionaryAttr::getWithSorted(context, attrs);
982 if (classBase ==
"GroundType") {
983 auto augRef = augmentedType.getAs<DictionaryAttr>(
"ref");
985 mlir::emitError(loc,
"missing 'ref' key in ") << augmentedType;
988 auto maybeTarget = refToTarget(augRef);
990 mlir::emitError(loc,
"Failed to parse ReferenceTarget").attachNote()
991 <<
"See the full Annotation here: " << root;
995 auto id = state.
newID();
997 auto target = *maybeTarget;
999 NamedAttrList elementIface, elementScattered;
1002 elementIface.append(
"class", classAttr);
1004 elementIface.append(
"description", *description);
1005 elementIface.append(
"id",
id);
1006 elementIface.append(
"name", name);
1008 elementScattered.append(
"class", classAttr);
1009 elementScattered.append(
"id",
id);
1014 if (!xmrSrcTarget) {
1015 mlir::emitError(loc,
"Failed to resolve target ") << targetAttr;
1016 return std::nullopt;
1022 auto sourceRef = xmrSrcTarget->ref;
1023 ImplicitLocOpBuilder builder(sourceRef.getOp()->getLoc(), context);
1024 std::optional<Value> source =
1025 TypeSwitch<Operation *, std::optional<Value>>(sourceRef.getOp())
1028 .Case<FExtModuleOp>([&](FExtModuleOp extMod)
1029 -> std::optional<Value> {
1030 auto portNo = sourceRef.getImpl().getPortNo();
1031 if (xmrSrcTarget->instances.empty()) {
1033 if (paths.size() > 1) {
1035 "cannot resolve a unique instance path from the "
1036 "external module '")
1037 << targetAttr <<
"'";
1038 return std::nullopt;
1040 auto *it = xmrSrcTarget->instances.begin();
1041 for (
auto inst : paths.back()) {
1042 xmrSrcTarget->instances.insert(it, cast<InstanceOp>(inst));
1046 auto lastInst = xmrSrcTarget->instances.pop_back_val();
1047 builder.setInsertionPointAfter(lastInst);
1049 xmrSrcTarget->fieldIdx);
1053 .Case<FModuleOp>([&](FModuleOp module) -> std::optional<Value> {
1054 builder.setInsertionPointToEnd(module.getBodyBlock());
1055 auto portNum = sourceRef.getImpl().getPortNo();
1057 xmrSrcTarget->fieldIdx);
1060 .Default([&](Operation *op) -> std::optional<Value> {
1061 auto module = cast<FModuleOp>(sourceRef.getModule());
1062 builder.setInsertionPointToEnd(module.getBodyBlock());
1063 auto is = dyn_cast<hw::InnerSymbolOpInterface>(op);
1065 if (is && is.getTargetResult())
1067 xmrSrcTarget->fieldIdx);
1068 if (sourceRef.getOp()->getNumResults() != 1) {
1070 <<
"cannot be used as a target of the Grand Central View \""
1071 << defName.getValue()
1072 <<
"\" because it does not have exactly one result";
1073 return std::nullopt;
1076 xmrSrcTarget->fieldIdx);
1081 return std::nullopt;
1093 builder.setInsertionPointToEnd(companionMod.getBodyBlock());
1097 auto sinkType = source->getType();
1098 if (
auto baseSinkType = type_dyn_cast<FIRRTLBaseType>(sinkType))
1099 sinkType = baseSinkType.getPassiveType();
1100 auto sink = builder.create<WireOp>(sinkType, name);
1103 annotations.addAnnotations(
1104 {DictionaryAttr::getWithSorted(context, elementScattered)});
1105 annotations.applyToOperation(sink);
1110 (path +
"__bore").str(),
1113 return DictionaryAttr::getWithSorted(context, elementIface);
1118 if (classBase ==
"VectorType") {
1120 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
1122 return std::nullopt;
1123 SmallVector<Attribute> elements;
1124 for (
auto [i, elt] : llvm::enumerate(elementsAttr)) {
1126 state, cast<DictionaryAttr>(elt), root, companion, name,
1128 path +
"_" + Twine(i));
1130 return std::nullopt;
1131 elements.push_back(*eltAttr);
1133 NamedAttrList attrs;
1134 attrs.append(
"class", classAttr);
1136 attrs.append(
"description", *description);
1138 attrs.append(
"name", name);
1139 return DictionaryAttr::getWithSorted(context, attrs);
1144 mlir::emitError(loc,
"found unknown AugmentedType '" + classAttr.getValue() +
1145 "' (Did you misspell it?)")
1147 <<
"see annotation: " << augmentedType;
1148 return std::nullopt;
1152 DictionaryAttr anno,
1155 auto id = state.
newID();
1156 auto *context = state.
circuit.getContext();
1157 auto loc = state.
circuit.getLoc();
1158 NamedAttrList companionAttrs;
1160 companionAttrs.append(
"id",
id);
1162 tryGetAs<DictionaryAttr>(anno, anno,
"view", loc,
viewAnnoClass);
1165 auto name = tryGetAs<StringAttr>(anno, anno,
"name", loc,
viewAnnoClass);
1168 companionAttrs.append(
"name", name);
1169 auto companionAttr =
1170 tryGetAs<StringAttr>(anno, anno,
"companion", loc,
viewAnnoClass);
1173 companionAttrs.append(
"target", companionAttr);
1193 std::optional<Attribute> GrandCentralPass::fromAttr(Attribute attr) {
1194 auto dict = dyn_cast<DictionaryAttr>(attr);
1196 emitCircuitError() <<
"attribute is not a dictionary: " << attr <<
"\n";
1197 return std::nullopt;
1200 auto clazz = dict.getAs<StringAttr>(
"class");
1202 emitCircuitError() <<
"missing 'class' key in " << dict <<
"\n";
1203 return std::nullopt;
1206 auto classBase = clazz.getValue();
1207 classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented");
1209 if (classBase ==
"BundleType") {
1210 if (dict.getAs<StringAttr>(
"defName") && dict.getAs<ArrayAttr>(
"elements"))
1212 emitCircuitError() <<
"has an invalid AugmentedBundleType that does not "
1213 "contain 'defName' and 'elements' fields: "
1215 }
else if (classBase ==
"VectorType") {
1216 if (dict.getAs<StringAttr>(
"name") && dict.getAs<ArrayAttr>(
"elements"))
1218 emitCircuitError() <<
"has an invalid AugmentedVectorType that does not "
1219 "contain 'name' and 'elements' fields: "
1221 }
else if (classBase ==
"GroundType") {
1222 auto id = dict.getAs<IntegerAttr>(
"id");
1223 auto name = dict.getAs<StringAttr>(
"name");
1224 if (
id && leafMap.count(
id) && name)
1227 emitCircuitError() <<
"has an invalid AugmentedGroundType that does not "
1228 "contain 'id' and 'name' fields: "
1230 if (
id && !leafMap.count(
id))
1231 emitCircuitError() <<
"has an AugmentedGroundType with 'id == "
1232 <<
id.getValue().getZExtValue()
1233 <<
"' that does not have a scattered leaf to connect "
1234 "to in the circuit "
1235 "(was the leaf deleted or constant prop'd away?)";
1237 emitCircuitError() <<
"has an invalid AugmentedType";
1239 return std::nullopt;
1242 bool GrandCentralPass::traverseField(
1243 Attribute field, IntegerAttr
id, VerbatimBuilder &path,
1244 SmallVector<VerbatimXMRbuilder> &xmrElems,
1245 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1246 return TypeSwitch<Attribute, bool>(field)
1247 .Case<AugmentedGroundTypeAttr>([&](AugmentedGroundTypeAttr ground) {
1248 auto [fieldRef, sym] = leafMap.lookup(ground.getID());
1251 nla = nlaTable->
getNLA(sym.getAttr());
1252 Value leafValue = fieldRef.getValue();
1253 assert(leafValue &&
"leafValue not found");
1255 auto companionModule = companionIDMap.lookup(
id).companion;
1256 igraph::ModuleOpInterface enclosing =
1257 getEnclosingModule(leafValue, sym);
1259 auto tpe = type_cast<FIRRTLBaseType>(leafValue.getType());
1262 if (!tpe.getBitWidthOrSentinel())
1274 auto *nodeOp = leafValue.getDefiningOp();
1275 if (companionModule != enclosing) {
1276 auto diag = companionModule->emitError()
1277 <<
"Grand Central View \""
1278 << companionIDMap.lookup(
id).name
1279 <<
"\" is invalid because a leaf is not inside the "
1281 diag.attachNote(leafValue.getLoc())
1282 <<
"the leaf value is declared here";
1284 auto leafModule = nodeOp->getParentOfType<FModuleOp>();
1285 diag.attachNote(leafModule.getLoc())
1286 <<
"the leaf value is inside this module";
1291 if (!isa<NodeOp>(nodeOp)) {
1292 emitError(leafValue.getLoc())
1293 <<
"Grand Central View \"" << companionIDMap.lookup(
id).name
1294 <<
"\" has an invalid leaf value (this must be a node)";
1301 auto getStrAndIncrementIds = [&](StringRef base) -> StringAttr {
1302 SmallString<128> replStr;
1303 StringRef begin =
"{{";
1304 StringRef
end =
"}}";
1307 while (from < base.size()) {
1309 size_t beginAt = base.find(begin, from);
1310 size_t endAt = base.find(end, from);
1312 if (beginAt == StringRef::npos || endAt == StringRef::npos ||
1313 (beginAt > endAt)) {
1314 replStr.append(base.substr(from));
1318 replStr.append(base.substr(from, beginAt - from));
1321 auto idChar = base.substr(beginAt + 2, endAt - beginAt - 2);
1323 bool failed = idChar.getAsInteger(10, idNum);
1325 assert(!failed &&
"failed to parse integer from verbatim string");
1327 replStr.append(
"{{");
1328 Twine(idNum + 1).toVector(replStr);
1329 replStr.append(
"}}");
1338 path +=
" = {{-1}}";
1341 xmrElems.emplace_back(
1342 nodeOp->getOperand(0), getStrAndIncrementIds(path.getString()),
1343 ArrayAttr::get(&getContext(), path.getSymbols()), companionModule);
1346 .Case<AugmentedVectorTypeAttr>([&](
auto vector) {
1347 bool notFailed =
true;
1348 auto elements = vector.getElements();
1349 for (
size_t i = 0, e = elements.size(); i != e; ++i) {
1350 auto field = fromAttr(elements[i]);
1353 notFailed &= traverseField(
1354 *field,
id, path.snapshot().append(
"[" + Twine(i) +
"]"),
1355 xmrElems, interfaceBuilder);
1359 .Case<AugmentedBundleTypeAttr>([&](AugmentedBundleTypeAttr bundle) {
1360 bool anyFailed =
true;
1361 for (
auto element : bundle.getElements()) {
1362 auto field = fromAttr(element);
1365 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1367 name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"defName");
1368 anyFailed &= traverseField(
1369 *field,
id, path.snapshot().append(
"." + name.getValue()),
1370 xmrElems, interfaceBuilder);
1375 .Default([](
auto a) {
return true; });
1378 std::optional<TypeSum> GrandCentralPass::computeField(
1379 Attribute field, IntegerAttr
id, StringAttr prefix, VerbatimBuilder &path,
1380 SmallVector<VerbatimXMRbuilder> &xmrElems,
1381 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1382 return TypeSwitch<Attribute, std::optional<TypeSum>>(field)
1383 .Case<AugmentedGroundTypeAttr>(
1384 [&](AugmentedGroundTypeAttr ground) -> std::optional<TypeSum> {
1386 if (!traverseField(field,
id, path, xmrElems, interfaceBuilder))
1387 return std::nullopt;
1388 FieldRef fieldRef = leafMap.lookup(ground.getID()).field;
1391 auto tpe = firrtl::type_cast<FIRRTLBaseType>(
1394 if (!tpe.isGround()) {
1395 value.getDefiningOp()->emitOpError()
1396 <<
"cannot be added to interface with id '"
1397 <<
id.getValue().getZExtValue()
1398 <<
"' because it is not a ground type";
1399 return std::nullopt;
1402 tpe.getBitWidthOrSentinel()));
1404 .Case<AugmentedVectorTypeAttr>(
1405 [&](AugmentedVectorTypeAttr vector) -> std::optional<TypeSum> {
1406 auto elements = vector.getElements();
1407 if (elements.empty())
1408 llvm::report_fatal_error(
1409 "unexpected empty augmented vector in GrandCentral View");
1410 auto firstElement = fromAttr(elements[0]);
1412 return std::nullopt;
1414 computeField(*firstElement,
id, prefix,
1415 path.snapshot().append(
"[" + Twine(0) +
"]"),
1416 xmrElems, interfaceBuilder);
1418 return std::nullopt;
1420 for (
size_t i = 1, e = elements.size(); i != e; ++i) {
1421 auto subField = fromAttr(elements[i]);
1423 return std::nullopt;
1424 (void)traverseField(*subField,
id,
1425 path.snapshot().append(
"[" + Twine(i) +
"]"),
1426 xmrElems, interfaceBuilder);
1433 str.dimensions.push_back(elements.getValue().size());
1434 return TypeSum(str);
1436 .Case<AugmentedBundleTypeAttr>(
1437 [&](AugmentedBundleTypeAttr bundle) -> TypeSum {
1438 auto ifaceName = traverseBundle(bundle,
id, prefix, path, xmrElems,
1440 assert(ifaceName && *ifaceName);
1441 return VerbatimType({ifaceName->str(),
true});
1451 std::optional<StringAttr> GrandCentralPass::traverseBundle(
1452 AugmentedBundleTypeAttr bundle, IntegerAttr
id, StringAttr prefix,
1453 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
1454 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1456 unsigned lastIndex = interfaceBuilder.size();
1458 &getContext(), getNamespace().newName(getInterfaceName(prefix, bundle)));
1459 interfaceBuilder.emplace_back(iFaceName,
id);
1461 for (
auto element : bundle.getElements()) {
1462 auto field = fromAttr(element);
1464 return std::nullopt;
1466 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1477 *field,
id, prefix, path.snapshot().append(
".").append(name.getValue()),
1478 xmrElems, interfaceBuilder);
1480 return std::nullopt;
1481 StringAttr description =
1482 cast<DictionaryAttr>(element).getAs<StringAttr>(
"description");
1483 interfaceBuilder[lastIndex].elementsList.emplace_back(description, name,
1491 igraph::ModuleOpInterface
1492 GrandCentralPass::getEnclosingModule(Value value, FlatSymbolRefAttr sym) {
1493 if (
auto blockArg = dyn_cast<BlockArgument>(value))
1494 return cast<igraph::ModuleOpInterface>(blockArg.getOwner()->getParentOp());
1496 auto *op = value.getDefiningOp();
1497 if (InstanceOp instance = dyn_cast<InstanceOp>(op))
1498 return getSymbolTable().lookup<igraph::ModuleOpInterface>(
1499 instance.getModuleNameAttr().getValue());
1501 return op->getParentOfType<igraph::ModuleOpInterface>();
1505 void GrandCentralPass::runOnOperation() {
1508 CircuitOp circuitOp = getOperation();
1517 SmallVector<Annotation> worklist;
1518 bool removalError =
false;
1527 if (companionMode != CompanionMode::Instantiate)
1528 worklist.push_back(anno);
1533 if (maybeExtractInfo) {
1534 emitCircuitError(
"more than one 'ExtractGrandCentralAnnotation' was "
1535 "found, but exactly one must be provided");
1536 removalError = true;
1540 auto directory = anno.
getMember<StringAttr>(
"directory");
1541 auto filename = anno.
getMember<StringAttr>(
"filename");
1542 if (!directory || !filename) {
1544 <<
"contained an invalid 'ExtractGrandCentralAnnotation' that does "
1545 "not contain 'directory' and 'filename' fields: "
1547 removalError =
true;
1550 if (directory.getValue().empty())
1553 maybeExtractInfo = {directory, filename};
1558 if (maybeHierarchyFileYAML) {
1559 emitCircuitError(
"more than one 'GrandCentralHierarchyFileAnnotation' "
1560 "was found, but zero or one may be provided");
1561 removalError =
true;
1565 auto filename = anno.
getMember<StringAttr>(
"filename");
1568 <<
"contained an invalid 'GrandCentralHierarchyFileAnnotation' "
1569 "that does not contain 'directory' and 'filename' fields: "
1571 removalError =
true;
1575 maybeHierarchyFileYAML = filename;
1580 if (!interfacePrefix.empty()) {
1581 emitCircuitError(
"more than one 'PrefixInterfacesAnnotation' was "
1582 "found, but zero or one may be provided");
1583 removalError =
true;
1587 auto prefix = anno.
getMember<StringAttr>(
"prefix");
1590 <<
"contained an invalid 'PrefixInterfacesAnnotation' that does "
1591 "not contain a 'prefix' field: "
1593 removalError =
true;
1597 interfacePrefix = prefix.getValue();
1602 testbenchDir = anno.
getMember<StringAttr>(
"dirname");
1610 for (
auto mod : circuitOp.getOps<FModuleOp>()) {
1612 removalError =
true;
1616 return signalPassFailure();
1619 llvm::dbgs() <<
"Extraction Info:\n";
1620 if (maybeExtractInfo)
1621 llvm::dbgs() <<
" directory: " << maybeExtractInfo->directory <<
"\n"
1622 <<
" filename: " << maybeExtractInfo->bindFilename <<
"\n";
1624 llvm::dbgs() <<
" <none>\n";
1625 llvm::dbgs() <<
"DUT: ";
1627 llvm::dbgs() << dut.getModuleName() <<
"\n";
1629 llvm::dbgs() <<
"<none>\n";
1631 <<
"Prefix Info (from PrefixInterfacesAnnotation):\n"
1632 <<
" prefix: " << interfacePrefix <<
"\n"
1633 <<
"Hierarchy File Info (from GrandCentralHierarchyFileAnnotation):\n"
1635 if (maybeHierarchyFileYAML)
1636 llvm::dbgs() << *maybeHierarchyFileYAML;
1638 llvm::dbgs() <<
"<none>";
1639 llvm::dbgs() <<
"\n";
1645 if (worklist.empty()) {
1646 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1647 emitHierarchyYamlFile(interfaceVec);
1648 return markAllAnalysesPreserved();
1655 auto builder = OpBuilder::atBlockEnd(circuitOp.getBodyBlock());
1659 auto getID = [&](Operation *op,
1660 Annotation annotation) -> std::optional<IntegerAttr> {
1661 auto id = annotation.getMember<IntegerAttr>(
"id");
1664 <<
"contained a malformed "
1665 "'sifive.enterprise.grandcentral.AugmentedGroundType' annotation "
1666 "that did not contain an 'id' field";
1667 removalError =
true;
1668 return std::nullopt;
1675 instancePaths = &instancePathCache;
1683 DenseSet<InstanceGraphNode *> dutModules;
1690 SmallVector<InstanceGraphNode *> modules({effectiveDUT});
1691 while (!modules.empty()) {
1692 auto *m = modules.pop_back_val();
1694 auto *mod = a->getTarget();
1697 if (
auto block = a->getInstance()->getParentOfType<LayerBlockOp>()) {
1698 auto diag = a->getInstance().emitOpError()
1699 <<
"is instantiated under a '" << block.getOperationName()
1700 <<
"' op which is unexpected by GrandCentral (did you "
1701 "forget to run the LowerLayers pass?)";
1702 diag.attachNote(block.getLoc())
1703 <<
"the '" << block.getOperationName() <<
"' op is here";
1704 removalError =
true;
1706 auto instOp = dyn_cast<InstanceOp>(*a->getInstance());
1707 if (dutModules.contains(mod) ||
1710 (instOp && instOp.getLowerToBind()))
1712 modules.push_back(mod);
1713 dutModules.insert(mod);
1720 auto exactlyOneInstance = [&](FModuleOp op,
1721 StringRef msg) -> std::optional<InstanceOp> {
1724 switch (node->getNumUses()) {
1726 op->emitOpError() <<
"is marked as a GrandCentral '" << msg
1727 <<
"', but is never instantiated";
1728 return std::nullopt;
1730 return cast<InstanceOp>(*(*node->uses().begin())->getInstance());
1732 auto diag = op->emitOpError()
1733 <<
"is marked as a GrandCentral '" << msg
1734 <<
"', but it is instantiated more than once";
1735 for (
auto *instance : node->uses())
1736 diag.attachNote(instance->getInstance()->getLoc())
1737 <<
"it is instantiated here";
1738 return std::nullopt;
1742 nlaTable = &getAnalysis<NLATable>();
1748 DenseSet<Operation *> modulesToDelete;
1749 circuitOp.walk([&](Operation *op) {
1750 TypeSwitch<Operation *>(op)
1751 .Case<RegOp, RegResetOp, WireOp, NodeOp>([&](
auto op) {
1755 auto maybeID = getID(op, annotation);
1759 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1760 leafMap[*maybeID] = {{op.getResult(), annotation.
getFieldID()},
1767 .Case<InstanceOp>([&](
auto op) {
1773 <<
"is marked as an interface element, but this should be "
1774 "impossible due to how the Chisel Grand Central API works";
1775 removalError =
true;
1779 .Case<MemOp>([&](
auto op) {
1784 <<
"is marked as an interface element, but this does not make "
1785 "sense (is there a scattering bug or do you have a "
1786 "malformed hand-crafted MLIR circuit?)";
1787 removalError =
true;
1795 <<
"has port '" << i
1796 <<
"' marked as an interface element, but this does not "
1797 "make sense (is there a scattering bug or do you have a "
1798 "malformed hand-crafted MLIR circuit?)";
1799 removalError =
true;
1803 .Case<FModuleOp>([&](FModuleOp op) {
1809 auto maybeID = getID(op, annotation);
1813 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1814 leafMap[*maybeID] = {{op.getArgument(i), annotation.
getFieldID()},
1824 auto isNonlocal = annotation.
getMember<FlatSymbolRefAttr>(
1825 "circt.nonlocal") !=
nullptr;
1826 auto name = annotation.
getMember<StringAttr>(
"name");
1827 auto id = annotation.
getMember<IntegerAttr>(
"id");
1830 <<
"has a malformed "
1831 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1832 "not contain an 'id' field with an 'IntegerAttr' value";
1833 goto FModuleOp_error;
1837 <<
"has a malformed "
1838 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1839 "not contain a 'name' field with a 'StringAttr' value";
1840 goto FModuleOp_error;
1853 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
1855 companionIDMap[id] = {name.getValue(), op, isNonlocal};
1858 auto instance = exactlyOneInstance(op,
"companion");
1860 goto FModuleOp_error;
1863 for (
auto [i, result] : llvm::enumerate(instance->getResults())) {
1864 if (instance->getPortDirection(i) == Direction::In)
1867 auto ty = result.getType();
1868 if (isa<RefType>(ty) && companionMode != CompanionMode::Drop)
1871 <<
"companion instance cannot have output ports";
1872 goto FModuleOp_error;
1877 if (!maybeExtractInfo) {
1897 <<
"Found companion module: "
1898 << companionNode->getModule().getModuleName() <<
"\n"
1899 <<
" submodules exclusively instantiated "
1900 "(including companion):\n";
1905 OpBuilder builder(&getContext());
1906 for (
auto port : instance->getResults()) {
1907 builder.setInsertionPointAfterValue(port);
1909 builder.create<WireOp>(port.getLoc(), port.getType());
1910 port.replaceAllUsesWith(wire.getResult());
1917 (*instance)->setAttr(
"lowerToBind", builder.getUnitAttr());
1919 (*instance)->setAttr(
1921 hw::OutputFileAttr::getFromFilename(
1923 maybeExtractInfo->bindFilename.getValue(),
1927 for (
auto &node : llvm::depth_first(companionNode)) {
1928 auto mod = node->getModule();
1936 SmallVector<InstanceRecord *> instances(modNode->uses());
1937 if (modNode != companionNode && dutModules.count(modNode))
1942 <<
" - module: " << mod.getModuleName() <<
"\n";
1945 if (
auto extmodule = dyn_cast<FExtModuleOp>(*mod)) {
1948 modulesToDelete.insert(mod);
1954 if (extmodule->hasAttr(
"output_file"))
1958 hw::OutputFileAttr::getAsDirectory(
1960 maybeExtractInfo->directory.getValue()));
1967 modulesToDelete.insert(mod);
1971 if (!mod->hasAttr(
"output_file")) {
1972 mod->setAttr(
"output_file",
1973 hw::OutputFileAttr::getAsDirectory(
1975 maybeExtractInfo->directory.getValue(),
1978 mod->setAttr(
"comment", builder.getStringAttr(
1979 "VCS coverage exclude_file"));
1989 <<
"unknown annotation class: " << annotation.
getDict();
1992 removalError =
true;
1999 return signalPassFailure();
2001 if (companionMode == CompanionMode::Drop) {
2002 for (
auto *mod : modulesToDelete) {
2003 auto name = cast<FModuleLike>(mod).getModuleNameAttr();
2005 DenseSet<hw::HierPathOp> nlas;
2008 for (
auto nla : nlas) {
2009 if (nla.root() == name)
2016 SmallVector<sv::InterfaceOp, 0> interfaceVec;
2017 emitHierarchyYamlFile(interfaceVec);
2024 SmallVector<IntegerAttr> ids;
2025 auto sort = [&ids]() {
2026 llvm::sort(ids, [](IntegerAttr a, IntegerAttr b) {
2027 return a.getValue().getZExtValue() < b.getValue().getZExtValue();
2030 for (
auto tuple : companionIDMap)
2031 ids.push_back(cast<IntegerAttr>(tuple.first));
2033 llvm::dbgs() <<
"companionIDMap:\n";
2034 for (
auto id : ids) {
2035 auto value = companionIDMap.lookup(
id);
2036 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2037 << value.companion.getName() <<
" -> " << value.name <<
"\n";
2040 for (
auto tuple : leafMap)
2041 ids.push_back(cast<IntegerAttr>(tuple.first));
2043 llvm::dbgs() <<
"leafMap:\n";
2044 for (
auto id : ids) {
2045 auto fieldRef = leafMap.lookup(
id).field;
2048 if (
auto blockArg = dyn_cast<BlockArgument>(value)) {
2049 FModuleOp module = cast<FModuleOp>(blockArg.getOwner()->getParentOp());
2050 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2051 << module.getName() +
">" +
2052 module.getPortName(blockArg.getArgNumber());
2054 llvm::dbgs() <<
", fieldID=" << fieldID;
2055 llvm::dbgs() <<
"\n";
2057 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2058 << cast<StringAttr>(value.getDefiningOp()->getAttr(
"name"))
2061 llvm::dbgs() <<
", fieldID=" << fieldID;
2062 llvm::dbgs() <<
"\n";
2073 SmallVector<sv::InterfaceOp, 2> interfaceVec;
2075 companionToInterfaceMap;
2076 auto compareInterfaceSignal = [&](InterfaceElemsBuilder &lhs,
2077 InterfaceElemsBuilder &rhs) {
2078 auto compareProps = [&](InterfaceElemsBuilder::Properties &lhs,
2079 InterfaceElemsBuilder::Properties &rhs) {
2083 if (lhs.elemType.index() == 0 && rhs.elemType.index() == 0)
2085 if (std::get<Type>(lhs.elemType) == std::get<Type>(rhs.elemType))
2089 return std::equal(lhs.elementsList.begin(), lhs.elementsList.end(),
2090 rhs.elementsList.begin(), compareProps);
2092 for (
auto anno : worklist) {
2097 if (!bundle.isRoot()) {
2098 emitCircuitError() <<
"missing 'id' in root-level BundleType: "
2100 removalError =
true;
2104 if (companionIDMap.count(bundle.getID()) == 0) {
2105 emitCircuitError() <<
"no companion found with 'id' value '"
2106 << bundle.getID().getValue().getZExtValue() <<
"'\n";
2107 removalError =
true;
2113 auto companionIter = companionIDMap.lookup(bundle.getID());
2114 auto companionModule = companionIter.companion;
2115 auto symbolName = getNamespace().newName(
2116 "__" + companionIDMap.lookup(bundle.getID()).name +
"_" +
2117 getInterfaceName(bundle.getPrefix(), bundle) +
"__");
2123 auto instanceSymbol =
2126 VerbatimBuilder::Base verbatimData;
2127 VerbatimBuilder verbatim(verbatimData);
2128 verbatim += instanceSymbol;
2131 SmallVector<VerbatimXMRbuilder> xmrElems;
2132 SmallVector<InterfaceElemsBuilder> interfaceBuilder;
2134 auto ifaceName = traverseBundle(bundle, bundle.getID(), bundle.getPrefix(),
2135 verbatim, xmrElems, interfaceBuilder);
2137 removalError =
true;
2141 if (companionIter.isNonlocal) {
2145 auto viewMapIter = companionToInterfaceMap.find(companionModule);
2146 if (viewMapIter != companionToInterfaceMap.end())
2147 if (std::equal(interfaceBuilder.begin(), interfaceBuilder.end(),
2148 viewMapIter->getSecond().begin(),
2149 compareInterfaceSignal)) {
2153 companionToInterfaceMap[companionModule] = interfaceBuilder;
2156 if (interfaceBuilder.empty())
2158 auto companionBuilder =
2159 OpBuilder::atBlockEnd(companionModule.getBodyBlock());
2162 for (
auto xmrElem : xmrElems) {
2163 auto uloc = companionBuilder.getUnknownLoc();
2164 companionBuilder.create<sv::VerbatimOp>(uloc, xmrElem.str, xmrElem.val,
2167 numXMRs += xmrElems.size();
2169 sv::InterfaceOp topIface;
2170 for (
const auto &ifaceBuilder : interfaceBuilder) {
2171 auto builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
2172 auto loc = getOperation().getLoc();
2173 sv::InterfaceOp iface =
2174 builder.create<sv::InterfaceOp>(loc, ifaceBuilder.iFaceName);
2180 companionIDMap[ifaceBuilder.id].companion, dut) &&
2182 iface->setAttr(
"output_file",
2183 hw::OutputFileAttr::getAsDirectory(
2184 &getContext(), testbenchDir.getValue(),
2186 else if (maybeExtractInfo)
2187 iface->setAttr(
"output_file",
2188 hw::OutputFileAttr::getAsDirectory(
2189 &getContext(), getOutputDirectory().getValue(),
2191 iface.setCommentAttr(builder.getStringAttr(
"VCS coverage exclude_file"));
2192 builder.setInsertionPointToEnd(
2193 cast<sv::InterfaceOp>(iface).getBodyBlock());
2195 ifaceBuilder.iFaceName)] = iface;
2196 for (
auto elem : ifaceBuilder.elementsList) {
2198 auto uloc = builder.getUnknownLoc();
2200 auto description = elem.description;
2203 auto descriptionOp = builder.create<sv::VerbatimOp>(
2204 uloc, (
"// " + cleanupDescription(description.getValue())));
2209 if (maybeHierarchyFileYAML)
2210 descriptionOp->setAttr(
"firrtl.grandcentral.yaml.type",
2211 builder.getStringAttr(
"description"));
2213 if (
auto *str = std::get_if<VerbatimType>(&elem.elemType)) {
2214 auto instanceOp = builder.create<sv::VerbatimOp>(
2215 uloc, str->toStr(elem.elemName.getValue()));
2219 if (maybeHierarchyFileYAML) {
2220 if (str->instantiation)
2221 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2222 builder.getStringAttr(
"instance"));
2224 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2225 builder.getStringAttr(
"unsupported"));
2226 instanceOp->setAttr(
"firrtl.grandcentral.yaml.name", elem.elemName);
2227 instanceOp->setAttr(
"firrtl.grandcentral.yaml.dimensions",
2228 builder.getI32ArrayAttr(str->dimensions));
2229 instanceOp->setAttr(
2230 "firrtl.grandcentral.yaml.symbol",
2236 auto tpe = std::get<Type>(elem.elemType);
2237 builder.create<sv::InterfaceSignalOp>(uloc, elem.elemName.getValue(),
2244 interfaceVec.push_back(topIface);
2247 builder.setInsertionPointToStart(companionModule.getBodyBlock());
2248 builder.create<sv::InterfaceInstanceOp>(
2249 getOperation().getLoc(), topIface.getInterfaceType(),
2250 companionIDMap.lookup(bundle.getID()).name,
2255 if (!maybeExtractInfo)
2261 companionIDMap[bundle.getID()].companion, dut))
2265 emitHierarchyYamlFile(interfaceVec);
2270 return signalPassFailure();
2271 markAnalysesPreserved<NLATable>();
2274 void GrandCentralPass::emitHierarchyYamlFile(
2275 SmallVectorImpl<sv::InterfaceOp> &intfs) {
2279 if (!maybeHierarchyFileYAML)
2282 CircuitOp circuitOp = getOperation();
2284 std::string yamlString;
2285 llvm::raw_string_ostream stream(yamlString);
2286 ::yaml::Context yamlContext({interfaceMap});
2288 yamlize(yout, intfs,
true, yamlContext);
2290 auto builder = OpBuilder::atBlockBegin(circuitOp.getBodyBlock());
2291 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), yamlString)
2292 ->setAttr(
"output_file",
2293 hw::OutputFileAttr::getFromFilename(
2294 &getContext(), maybeHierarchyFileYAML->getValue(),
2296 LLVM_DEBUG({ llvm::dbgs() <<
"Generated YAML:" << yamlString <<
"\n"; });
2303 std::unique_ptr<mlir::Pass>
2305 auto pass = std::make_unique<GrandCentralPass>();
2306 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.
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
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.
igraph::InstanceGraphNode * getTopLevelNode() override
Get the node corresponding to the top-level module of a circuit.
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.
This is an edge in the InstanceGraph.
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
LogicalResult extractDUT(FModuleOp mod, FModuleOp &dut)
Utility that searches for a MarkDUTAnnotation on a specific module, mod, and tries to update a design...
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
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 * prefixInterfacesAnnoClass
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)