28 #include "mlir/IR/ImplicitLocOpBuilder.h"
29 #include "mlir/Pass/Pass.h"
30 #include "llvm/ADT/DepthFirstIterator.h"
31 #include "llvm/ADT/TypeSwitch.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/YAMLTraits.h"
36 #define DEBUG_TYPE "gct"
40 #define GEN_PASS_DEF_GRANDCENTRAL
41 #include "circt/Dialect/FIRRTL/Passes.h.inc"
45 using namespace circt;
46 using namespace firrtl;
59 [[maybe_unused]]
static std::string noDefault(StringRef clazz) {
60 return (
"default '" + clazz +
61 "' construction is an intentionally *NOT* implemented "
62 "YAML feature (you should never be using this)")
66 [[maybe_unused]]
static std::string deNorm(StringRef clazz) {
67 return (
"conversion from YAML to a '" + clazz +
68 "' is intentionally *NOT* implemented (you should not be "
69 "converting from YAML to an interface)")
84 DenseMap<Attribute, sv::InterfaceOp> &interfaceMap;
93 struct DescribedSignal {
95 StringAttr description;
98 sv::InterfaceSignalOp signal;
106 struct DescribedInstance {
110 StringAttr description;
113 ArrayAttr dimensions;
116 FlatSymbolRefAttr interface;
126 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedSignal)
127 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedInstance)
128 LLVM_YAML_IS_SEQUENCE_VECTOR(sv::InterfaceOp)
136 using namespace ::
yaml;
149 std::string descriptionString;
150 llvm::raw_string_ostream stream(descriptionString);
151 SmallVector<StringRef> splits;
152 str.split(splits,
"\n");
156 substr.consume_front(
"//");
157 stream << substr.drop_while([](
auto c) {
return c ==
' '; });
159 [&]() { stream <<
"\n"; });
160 return descriptionString;
167 struct MappingContextTraits<DescribedSignal, Context> {
185 : name(op.signal.getSymNameAttr().getValue()) {
211 auto tpe = op.signal.getType();
212 while (
auto vector = dyn_cast<hw::UnpackedArrayType>(tpe)) {
213 dimensions.push_back(vector.getNumElements());
214 tpe = vector.getElementType();
216 dimensions = SmallVector<unsigned>(llvm::reverse(dimensions));
221 assert(isa<IntegerType>(tpe));
222 width = type_cast<IntegerType>(tpe).getWidth();
226 Field(IO &io) { llvm_unreachable(noDefault(
"Field").c_str()); }
230 llvm_unreachable(deNorm(
"DescribedSignal").c_str());
234 static void mapping(IO &io, DescribedSignal &op, Context &ctx) {
235 MappingNormalization<Field, DescribedSignal> keys(io, op);
236 io.mapRequired(
"name", keys->name);
237 io.mapOptional(
"description", keys->description);
238 io.mapRequired(
"dimensions", keys->dimensions);
239 io.mapRequired(
"width", keys->width);
248 struct MappingContextTraits<DescribedInstance, Context> {
255 std::optional<std::string> description = std::nullopt;
264 : name(op.name.getValue()), interface(op.interface) {
272 for (
auto &d : op.dimensions) {
273 auto dimension = dyn_cast<IntegerAttr>(d);
274 dimensions.push_back(dimension.getInt());
278 Instance(IO &io) { llvm_unreachable(noDefault(
"Instance").c_str()); }
281 llvm_unreachable(deNorm(
"DescribedInstance").c_str());
285 static void mapping(IO &io, DescribedInstance &op, Context &ctx) {
286 MappingNormalization<Instance, DescribedInstance> keys(io, op);
287 io.mapRequired(
"name", keys->name);
288 io.mapOptional(
"description", keys->description);
289 io.mapRequired(
"dimensions", keys->dimensions);
290 io.mapRequired(
"interface", ctx.interfaceMap[keys->interface], ctx);
298 struct MappingContextTraits<
sv::InterfaceOp, Context> {
340 StringAttr description = {};
342 for (
auto &op : op.getBodyBlock()->getOperations()) {
343 TypeSwitch<Operation *>(&op)
346 .Case<sv::VerbatimOp>([&](sv::VerbatimOp op) {
347 auto tpe = op->getAttrOfType<StringAttr>(
348 "firrtl.grandcentral.yaml.type");
352 if (tpe.getValue() ==
"description") {
353 description = op.getFormatStringAttr();
358 if (tpe.getValue() ==
"unsupported") {
365 auto name = op->getAttrOfType<StringAttr>(
366 "firrtl.grandcentral.yaml.name");
367 auto dimensions = op->getAttrOfType<ArrayAttr>(
368 "firrtl.grandcentral.yaml.dimensions");
369 auto symbol = op->getAttrOfType<FlatSymbolRefAttr>(
370 "firrtl.grandcentral.yaml.symbol");
372 DescribedInstance({name, description, dimensions, symbol}));
376 .Case<sv::InterfaceSignalOp>([&](sv::InterfaceSignalOp op) {
377 fields.push_back(DescribedSignal({description, op}));
384 Interface(IO &io) { llvm_unreachable(noDefault(
"Interface").c_str()); }
388 llvm_unreachable(deNorm(
"sv::InterfaceOp").c_str());
392 static void mapping(IO &io, sv::InterfaceOp &op, Context &ctx) {
393 MappingNormalization<Interface, sv::InterfaceOp> keys(io, op);
394 io.mapRequired(
"name", keys->name);
395 io.mapRequired(
"fields", keys->fields, ctx);
396 io.mapRequired(
"instances", keys->instances, ctx);
426 struct VerbatimBuilder {
428 SmallString<128> string;
429 SmallVector<Attribute> symbols;
430 VerbatimBuilder builder() {
return VerbatimBuilder(*
this); }
431 operator VerbatimBuilder() {
return builder(); }
436 VerbatimBuilder(Base &base)
437 : base(base), stringBaseSize(base.string.size()),
438 symbolsBaseSize(base.symbols.size()) {}
443 base.string.resize(stringBaseSize);
444 base.symbols.resize(symbolsBaseSize);
448 VerbatimBuilder(
const VerbatimBuilder &) =
delete;
449 VerbatimBuilder &operator=(
const VerbatimBuilder &) =
delete;
454 VerbatimBuilder snapshot() {
return VerbatimBuilder(base); }
457 StringRef getString()
const {
return base.string; }
459 ArrayRef<Attribute> getSymbols()
const {
return base.symbols; }
462 VerbatimBuilder &
append(
char c) {
463 base.string.push_back(c);
468 VerbatimBuilder &
append(
const Twine &twine) {
469 twine.toVector(base.string);
474 VerbatimBuilder &
append(Attribute symbol) {
475 unsigned id = base.symbols.size();
476 base.symbols.push_back(symbol);
477 append(
"{{" + Twine(
id) +
"}}");
481 VerbatimBuilder &operator+=(
char c) {
return append(c); }
482 VerbatimBuilder &operator+=(
const Twine &twine) {
return append(twine); }
483 VerbatimBuilder &operator+=(Attribute symbol) {
return append(symbol); }
487 size_t stringBaseSize;
488 size_t symbolsBaseSize;
494 struct VerbatimType {
503 SmallVector<int32_t, 4> dimensions = {};
506 std::string toStr(StringRef name) {
507 SmallString<64> stringType(str);
508 stringType.append(
" ");
509 stringType.append(name);
510 for (
auto d : llvm::reverse(dimensions)) {
511 stringType.append(
"[");
512 stringType.append(Twine(d).str());
513 stringType.append(
"]");
516 stringType.append(
"()");
517 stringType.append(
";");
518 return std::string(stringType);
524 typedef std::variant<VerbatimType, Type> TypeSum;
527 struct ExtractionInfo {
530 StringAttr directory = {};
535 StringAttr bindFilename = {};
539 struct CompanionInfo {
550 FlatSymbolRefAttr nlaSym;
554 struct VerbatimXMRbuilder {
558 FModuleOp companionMod;
559 VerbatimXMRbuilder(Value val, StringAttr str, ArrayAttr syms,
560 FModuleOp companionMod)
561 : val(val), str(str), syms(syms), companionMod(companionMod) {}
566 struct InterfaceElemsBuilder {
567 StringAttr iFaceName;
570 StringAttr description;
573 Properties(StringAttr des, StringAttr name, TypeSum &elemType)
574 : description(des), elemName(name), elemType(elemType) {}
576 SmallVector<Properties> elementsList;
577 InterfaceElemsBuilder(StringAttr iFaceName, IntegerAttr
id)
578 : iFaceName(iFaceName), id(id) {}
593 struct GrandCentralPass
594 :
public circt::firrtl::impl::GrandCentralBase<GrandCentralPass> {
595 using GrandCentralBase::companionMode;
597 void runOnOperation()
override;
603 std::optional<Attribute> fromAttr(Attribute attr);
607 DenseMap<Attribute, FieldAndNLA> leafMap;
610 DenseMap<Attribute, CompanionInfo> companionIDMap;
614 StringRef interfacePrefix;
625 StringAttr testbenchDir;
629 std::string getInterfaceName(StringAttr prefix,
630 AugmentedBundleTypeAttr bundleType) {
633 return (prefix.getValue() + interfacePrefix +
634 bundleType.getDefName().getValue())
636 return (interfacePrefix + bundleType.getDefName().getValue()).str();
641 bool traverseField(Attribute field, IntegerAttr
id, VerbatimBuilder &path,
642 SmallVector<VerbatimXMRbuilder> &xmrElems,
643 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
648 std::optional<TypeSum>
649 computeField(Attribute field, IntegerAttr
id, StringAttr prefix,
650 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
651 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
656 std::optional<StringAttr>
657 traverseBundle(AugmentedBundleTypeAttr bundle, IntegerAttr
id,
658 StringAttr prefix, VerbatimBuilder &path,
659 SmallVector<VerbatimXMRbuilder> &xmrElems,
660 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
663 igraph::ModuleOpInterface getEnclosingModule(Value value,
664 FlatSymbolRefAttr sym = {});
668 std::optional<ExtractionInfo> maybeExtractInfo = std::nullopt;
672 std::optional<StringAttr> maybeHierarchyFileYAML = std::nullopt;
674 StringAttr getOutputDirectory() {
675 if (maybeExtractInfo)
676 return maybeExtractInfo->directory;
694 std::optional<CircuitNamespace> circuitNamespace;
698 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
703 if (!circuitNamespace)
705 return *circuitNamespace;
709 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
710 return moduleNamespaces.try_emplace(module, module).first->second;
715 std::optional<SymbolTable *> symbolTable;
719 SymbolTable &getSymbolTable() {
721 symbolTable = &getAnalysis<SymbolTable>();
722 return **symbolTable;
729 InFlightDiagnostic emitCircuitError(StringRef message = {}) {
730 return emitError(getOperation().getLoc(),
"'firrtl.circuit' op " + message);
738 std::string cleanupDescription(StringRef description) {
742 std::tie(head, description) = description.split(
"\n");
744 if (!description.empty())
746 }
while (!description.empty());
747 return std::string(out);
751 DenseMap<Attribute, sv::InterfaceOp> interfaceMap;
754 void emitHierarchyYamlFile(SmallVectorImpl<sv::InterfaceOp> &intfs);
768 static std::optional<DictionaryAttr>
770 DictionaryAttr root, StringRef companion, StringAttr name,
771 StringAttr defName, std::optional<IntegerAttr>
id,
772 std::optional<StringAttr> description, Twine clazz,
773 StringAttr companionAttr, Twine path = {}) {
775 auto *context = state.
circuit.getContext();
776 auto loc = state.
circuit.getLoc();
793 [&](DictionaryAttr refTarget) -> std::optional<std::string> {
795 tryGetAs<StringAttr>(refTarget, refTarget,
"circuit", loc, clazz, path);
797 tryGetAs<StringAttr>(refTarget, refTarget,
"module", loc, clazz, path);
799 tryGetAs<ArrayAttr>(refTarget, refTarget,
"path", loc, clazz, path);
800 auto componentAttr = tryGetAs<ArrayAttr>(refTarget, refTarget,
"component",
802 if (!circuitAttr || !moduleAttr || !pathAttr || !componentAttr)
806 SmallString<32> strpath;
807 for (
auto p : pathAttr) {
808 auto dict = dyn_cast_or_null<DictionaryAttr>(p);
810 mlir::emitError(loc,
"annotation '" + clazz +
811 " has invalid type (expected DictionaryAttr)");
815 tryGetAs<DictionaryAttr>(dict, dict,
"_1", loc, clazz, path);
817 tryGetAs<DictionaryAttr>(dict, dict,
"_2", loc, clazz, path);
818 if (!instHolder || !modHolder) {
819 mlir::emitError(loc,
"annotation '" + clazz +
820 " has invalid type (expected DictionaryAttr)");
823 auto inst = tryGetAs<StringAttr>(instHolder, instHolder,
"value", loc,
826 tryGetAs<StringAttr>(modHolder, modHolder,
"value", loc, clazz, path);
828 mlir::emitError(loc,
"annotation '" + clazz +
829 " has invalid type (expected DictionaryAttr)");
832 strpath +=
"/" + inst.getValue().str() +
":" + mod.getValue().str();
835 SmallVector<Attribute> componentAttrs;
836 SmallString<32> componentStr;
837 for (
size_t i = 0, e = componentAttr.size(); i != e; ++i) {
838 auto cPath = (path +
".component[" + Twine(i) +
"]").str();
839 auto component = componentAttr[i];
840 auto dict = dyn_cast_or_null<DictionaryAttr>(component);
842 mlir::emitError(loc,
"annotation '" + clazz +
"' with path '" + cPath +
843 " has invalid type (expected DictionaryAttr)");
847 tryGetAs<StringAttr>(dict, refTarget,
"class", loc, clazz, cPath);
851 auto value = dict.get(
"value");
854 if (
auto field = dyn_cast<StringAttr>(value)) {
855 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Field" &&
856 "A StringAttr target token must be found with a subfield target "
858 componentStr.append((Twine(
".") + field.getValue()).str());
863 if (
auto index = dyn_cast<IntegerAttr>(value)) {
864 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Index" &&
865 "An IntegerAttr target token must be found with a subindex "
868 (Twine(
"[") + Twine(index.getValue().getZExtValue()) +
"]").str());
873 "Annotation '" + clazz +
"' with path '" + cPath +
874 ".value has unexpected type (should be StringAttr "
875 "for subfield or IntegerAttr for subindex).")
877 <<
"The value received was: " << value <<
"\n";
882 tryGetAs<StringAttr>(refTarget, refTarget,
"ref", loc, clazz, path);
886 return (Twine(
"~" + circuitAttr.getValue() +
"|" + moduleAttr.getValue() +
887 strpath +
">" + refAttr.getValue()) +
893 tryGetAs<StringAttr>(augmentedType, root,
"class", loc, clazz, path);
896 StringRef classBase = classAttr.getValue();
897 if (!classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented")) {
899 "the 'class' was expected to start with "
900 "'sifive.enterprise.grandCentral.Augmented*', but was '" +
901 classAttr.getValue() +
"' (Did you misspell it?)")
903 <<
"see annotation: " << augmentedType;
910 if (classBase ==
"BundleType") {
912 tryGetAs<StringAttr>(augmentedType, root,
"defName", loc, clazz, path);
920 SmallVector<Attribute> elements;
922 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
925 for (
size_t i = 0, e = elementsAttr.size(); i != e; ++i) {
926 auto field = dyn_cast_or_null<DictionaryAttr>(elementsAttr[i]);
930 "Annotation '" + Twine(clazz) +
"' with path '.elements[" +
932 "]' contained an unexpected type (expected a DictionaryAttr).")
934 <<
"The received element was: " << elementsAttr[i] <<
"\n";
937 auto ePath = (path +
".elements[" + Twine(i) +
"]").str();
938 auto name = tryGetAs<StringAttr>(field, root,
"name", loc, clazz, ePath);
940 tryGetAs<DictionaryAttr>(field, root,
"tpe", loc, clazz, ePath);
943 std::optional<StringAttr> description;
944 if (
auto maybeDescription = field.get(
"description"))
945 description = cast<StringAttr>(maybeDescription);
947 state, tpe, root, companion, name, defName, std::nullopt, description,
948 clazz, companionAttr, path +
"_" + name.getValue());
955 if (
auto maybeDescription = field.get(
"description"))
956 attrs.append(
"description", cast<StringAttr>(maybeDescription));
957 attrs.append(
"name", name);
958 auto tpeClass = tpe.getAs<StringAttr>(
"class");
960 mlir::emitError(loc,
"missing 'class' key in") << tpe;
963 attrs.append(
"tpe", tpeClass);
964 elements.push_back(*eltAttr);
970 attrs.append(
"class", classAttr);
971 attrs.append(
"defName", defName);
973 attrs.append(
"description", *description);
976 attrs.append(
"id", *
id);
977 attrs.append(
"name", name);
978 return DictionaryAttr::getWithSorted(context, attrs);
987 if (classBase ==
"GroundType") {
988 auto augRef = augmentedType.getAs<DictionaryAttr>(
"ref");
990 mlir::emitError(loc,
"missing 'ref' key in ") << augmentedType;
993 auto maybeTarget = refToTarget(augRef);
995 mlir::emitError(loc,
"Failed to parse ReferenceTarget").attachNote()
996 <<
"See the full Annotation here: " << root;
1000 auto id = state.
newID();
1002 auto target = *maybeTarget;
1004 NamedAttrList elementIface, elementScattered;
1007 elementIface.append(
"class", classAttr);
1009 elementIface.append(
"description", *description);
1010 elementIface.append(
"id",
id);
1011 elementIface.append(
"name", name);
1013 elementScattered.append(
"class", classAttr);
1014 elementScattered.append(
"id",
id);
1019 if (!xmrSrcTarget) {
1020 mlir::emitError(loc,
"Failed to resolve target ") << targetAttr;
1021 return std::nullopt;
1027 auto sourceRef = xmrSrcTarget->ref;
1028 ImplicitLocOpBuilder builder(sourceRef.getOp()->getLoc(), context);
1029 std::optional<Value> source =
1030 TypeSwitch<Operation *, std::optional<Value>>(sourceRef.getOp())
1033 .Case<FExtModuleOp>([&](FExtModuleOp extMod)
1034 -> std::optional<Value> {
1035 auto portNo = sourceRef.getImpl().getPortNo();
1036 if (xmrSrcTarget->instances.empty()) {
1038 if (paths.size() > 1) {
1040 "cannot resolve a unique instance path from the "
1041 "external module '")
1042 << targetAttr <<
"'";
1043 return std::nullopt;
1045 auto *it = xmrSrcTarget->instances.begin();
1046 for (
auto inst : paths.back()) {
1047 xmrSrcTarget->instances.insert(it, cast<InstanceOp>(inst));
1051 auto lastInst = xmrSrcTarget->instances.pop_back_val();
1052 builder.setInsertionPointAfter(lastInst);
1054 xmrSrcTarget->fieldIdx);
1058 .Case<FModuleOp>([&](FModuleOp module) -> std::optional<Value> {
1059 builder.setInsertionPointToEnd(module.getBodyBlock());
1060 auto portNum = sourceRef.getImpl().getPortNo();
1062 xmrSrcTarget->fieldIdx);
1065 .Default([&](Operation *op) -> std::optional<Value> {
1066 auto module = cast<FModuleOp>(sourceRef.getModule());
1067 builder.setInsertionPointToEnd(module.getBodyBlock());
1068 auto is = dyn_cast<hw::InnerSymbolOpInterface>(op);
1070 if (is && is.getTargetResult())
1072 xmrSrcTarget->fieldIdx);
1073 if (sourceRef.getOp()->getNumResults() != 1) {
1075 <<
"cannot be used as a target of the Grand Central View \""
1076 << defName.getValue()
1077 <<
"\" because it does not have exactly one result";
1078 return std::nullopt;
1081 xmrSrcTarget->fieldIdx);
1086 return std::nullopt;
1098 builder.setInsertionPointToEnd(companionMod.getBodyBlock());
1102 auto sinkType = source->getType();
1103 if (
auto baseSinkType = type_dyn_cast<FIRRTLBaseType>(sinkType))
1104 sinkType = baseSinkType.getPassiveType();
1105 auto sink = builder.create<WireOp>(sinkType, name);
1108 annotations.addAnnotations(
1109 {DictionaryAttr::getWithSorted(context, elementScattered)});
1110 annotations.applyToOperation(sink);
1115 (path +
"__bore").str(),
1118 return DictionaryAttr::getWithSorted(context, elementIface);
1123 if (classBase ==
"VectorType") {
1125 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
1127 return std::nullopt;
1128 SmallVector<Attribute> elements;
1129 for (
auto [i, elt] : llvm::enumerate(elementsAttr)) {
1131 state, cast<DictionaryAttr>(elt), root, companion, name,
1133 path +
"_" + Twine(i));
1135 return std::nullopt;
1136 elements.push_back(*eltAttr);
1138 NamedAttrList attrs;
1139 attrs.append(
"class", classAttr);
1141 attrs.append(
"description", *description);
1143 attrs.append(
"name", name);
1144 return DictionaryAttr::getWithSorted(context, attrs);
1149 mlir::emitError(loc,
"found unknown AugmentedType '" + classAttr.getValue() +
1150 "' (Did you misspell it?)")
1152 <<
"see annotation: " << augmentedType;
1153 return std::nullopt;
1157 DictionaryAttr anno,
1160 auto id = state.
newID();
1161 auto *context = state.
circuit.getContext();
1162 auto loc = state.
circuit.getLoc();
1163 NamedAttrList companionAttrs;
1165 companionAttrs.append(
"id",
id);
1167 tryGetAs<DictionaryAttr>(anno, anno,
"view", loc,
viewAnnoClass);
1170 auto name = tryGetAs<StringAttr>(anno, anno,
"name", loc,
viewAnnoClass);
1173 companionAttrs.append(
"name", name);
1174 auto companionAttr =
1175 tryGetAs<StringAttr>(anno, anno,
"companion", loc,
viewAnnoClass);
1178 companionAttrs.append(
"target", companionAttr);
1198 std::optional<Attribute> GrandCentralPass::fromAttr(Attribute attr) {
1199 auto dict = dyn_cast<DictionaryAttr>(attr);
1201 emitCircuitError() <<
"attribute is not a dictionary: " << attr <<
"\n";
1202 return std::nullopt;
1205 auto clazz = dict.getAs<StringAttr>(
"class");
1207 emitCircuitError() <<
"missing 'class' key in " << dict <<
"\n";
1208 return std::nullopt;
1211 auto classBase = clazz.getValue();
1212 classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented");
1214 if (classBase ==
"BundleType") {
1215 if (dict.getAs<StringAttr>(
"defName") && dict.getAs<ArrayAttr>(
"elements"))
1217 emitCircuitError() <<
"has an invalid AugmentedBundleType that does not "
1218 "contain 'defName' and 'elements' fields: "
1220 }
else if (classBase ==
"VectorType") {
1221 if (dict.getAs<StringAttr>(
"name") && dict.getAs<ArrayAttr>(
"elements"))
1223 emitCircuitError() <<
"has an invalid AugmentedVectorType that does not "
1224 "contain 'name' and 'elements' fields: "
1226 }
else if (classBase ==
"GroundType") {
1227 auto id = dict.getAs<IntegerAttr>(
"id");
1228 auto name = dict.getAs<StringAttr>(
"name");
1229 if (
id && leafMap.count(
id) && name)
1232 emitCircuitError() <<
"has an invalid AugmentedGroundType that does not "
1233 "contain 'id' and 'name' fields: "
1235 if (
id && !leafMap.count(
id))
1236 emitCircuitError() <<
"has an AugmentedGroundType with 'id == "
1237 <<
id.getValue().getZExtValue()
1238 <<
"' that does not have a scattered leaf to connect "
1239 "to in the circuit "
1240 "(was the leaf deleted or constant prop'd away?)";
1242 emitCircuitError() <<
"has an invalid AugmentedType";
1244 return std::nullopt;
1247 bool GrandCentralPass::traverseField(
1248 Attribute field, IntegerAttr
id, VerbatimBuilder &path,
1249 SmallVector<VerbatimXMRbuilder> &xmrElems,
1250 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1251 return TypeSwitch<Attribute, bool>(field)
1252 .Case<AugmentedGroundTypeAttr>([&](AugmentedGroundTypeAttr ground) {
1253 auto [fieldRef, sym] = leafMap.lookup(ground.getID());
1256 nla = nlaTable->
getNLA(sym.getAttr());
1257 Value leafValue = fieldRef.getValue();
1258 assert(leafValue &&
"leafValue not found");
1260 auto companionModule = companionIDMap.lookup(
id).companion;
1261 igraph::ModuleOpInterface enclosing =
1262 getEnclosingModule(leafValue, sym);
1264 auto tpe = type_cast<FIRRTLBaseType>(leafValue.getType());
1267 if (!tpe.getBitWidthOrSentinel())
1279 auto *nodeOp = leafValue.getDefiningOp();
1280 if (companionModule != enclosing) {
1281 auto diag = companionModule->emitError()
1282 <<
"Grand Central View \""
1283 << companionIDMap.lookup(
id).name
1284 <<
"\" is invalid because a leaf is not inside the "
1286 diag.attachNote(leafValue.getLoc())
1287 <<
"the leaf value is declared here";
1289 auto leafModule = nodeOp->getParentOfType<FModuleOp>();
1290 diag.attachNote(leafModule.getLoc())
1291 <<
"the leaf value is inside this module";
1296 if (!isa<NodeOp>(nodeOp)) {
1297 emitError(leafValue.getLoc())
1298 <<
"Grand Central View \"" << companionIDMap.lookup(
id).name
1299 <<
"\" has an invalid leaf value (this must be a node)";
1306 auto getStrAndIncrementIds = [&](StringRef base) -> StringAttr {
1307 SmallString<128> replStr;
1308 StringRef begin =
"{{";
1309 StringRef
end =
"}}";
1312 while (from < base.size()) {
1314 size_t beginAt = base.find(begin, from);
1315 size_t endAt = base.find(end, from);
1317 if (beginAt == StringRef::npos || endAt == StringRef::npos ||
1318 (beginAt > endAt)) {
1319 replStr.append(base.substr(from));
1323 replStr.append(base.substr(from, beginAt - from));
1326 auto idChar = base.substr(beginAt + 2, endAt - beginAt - 2);
1328 bool failed = idChar.getAsInteger(10, idNum);
1330 assert(!failed &&
"failed to parse integer from verbatim string");
1332 replStr.append(
"{{");
1333 Twine(idNum + 1).toVector(replStr);
1334 replStr.append(
"}}");
1343 path +=
" = {{-1}}";
1346 xmrElems.emplace_back(
1347 nodeOp->getOperand(0), getStrAndIncrementIds(path.getString()),
1348 ArrayAttr::get(&getContext(), path.getSymbols()), companionModule);
1351 .Case<AugmentedVectorTypeAttr>([&](
auto vector) {
1352 bool notFailed =
true;
1353 auto elements = vector.getElements();
1354 for (
size_t i = 0, e = elements.size(); i != e; ++i) {
1355 auto field = fromAttr(elements[i]);
1358 notFailed &= traverseField(
1359 *field,
id, path.snapshot().append(
"[" + Twine(i) +
"]"),
1360 xmrElems, interfaceBuilder);
1364 .Case<AugmentedBundleTypeAttr>([&](AugmentedBundleTypeAttr bundle) {
1365 bool anyFailed =
true;
1366 for (
auto element : bundle.getElements()) {
1367 auto field = fromAttr(element);
1370 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1372 name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"defName");
1373 anyFailed &= traverseField(
1374 *field,
id, path.snapshot().append(
"." + name.getValue()),
1375 xmrElems, interfaceBuilder);
1380 .Default([](
auto a) {
return true; });
1383 std::optional<TypeSum> GrandCentralPass::computeField(
1384 Attribute field, IntegerAttr
id, StringAttr prefix, VerbatimBuilder &path,
1385 SmallVector<VerbatimXMRbuilder> &xmrElems,
1386 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1387 return TypeSwitch<Attribute, std::optional<TypeSum>>(field)
1388 .Case<AugmentedGroundTypeAttr>(
1389 [&](AugmentedGroundTypeAttr ground) -> std::optional<TypeSum> {
1391 if (!traverseField(field,
id, path, xmrElems, interfaceBuilder))
1392 return std::nullopt;
1393 FieldRef fieldRef = leafMap.lookup(ground.getID()).field;
1396 auto tpe = firrtl::type_cast<FIRRTLBaseType>(
1399 if (!tpe.isGround()) {
1400 value.getDefiningOp()->emitOpError()
1401 <<
"cannot be added to interface with id '"
1402 <<
id.getValue().getZExtValue()
1403 <<
"' because it is not a ground type";
1404 return std::nullopt;
1407 tpe.getBitWidthOrSentinel()));
1409 .Case<AugmentedVectorTypeAttr>(
1410 [&](AugmentedVectorTypeAttr vector) -> std::optional<TypeSum> {
1411 auto elements = vector.getElements();
1412 if (elements.empty())
1413 llvm::report_fatal_error(
1414 "unexpected empty augmented vector in GrandCentral View");
1415 auto firstElement = fromAttr(elements[0]);
1417 return std::nullopt;
1419 computeField(*firstElement,
id, prefix,
1420 path.snapshot().append(
"[" + Twine(0) +
"]"),
1421 xmrElems, interfaceBuilder);
1423 return std::nullopt;
1425 for (
size_t i = 1, e = elements.size(); i != e; ++i) {
1426 auto subField = fromAttr(elements[i]);
1428 return std::nullopt;
1429 (void)traverseField(*subField,
id,
1430 path.snapshot().append(
"[" + Twine(i) +
"]"),
1431 xmrElems, interfaceBuilder);
1438 str.dimensions.push_back(elements.getValue().size());
1439 return TypeSum(str);
1441 .Case<AugmentedBundleTypeAttr>(
1442 [&](AugmentedBundleTypeAttr bundle) -> TypeSum {
1443 auto ifaceName = traverseBundle(bundle,
id, prefix, path, xmrElems,
1445 assert(ifaceName && *ifaceName);
1446 return VerbatimType({ifaceName->str(),
true});
1456 std::optional<StringAttr> GrandCentralPass::traverseBundle(
1457 AugmentedBundleTypeAttr bundle, IntegerAttr
id, StringAttr prefix,
1458 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
1459 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1461 unsigned lastIndex = interfaceBuilder.size();
1463 &getContext(), getNamespace().newName(getInterfaceName(prefix, bundle)));
1464 interfaceBuilder.emplace_back(iFaceName,
id);
1466 for (
auto element : bundle.getElements()) {
1467 auto field = fromAttr(element);
1469 return std::nullopt;
1471 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1482 *field,
id, prefix, path.snapshot().append(
".").append(name.getValue()),
1483 xmrElems, interfaceBuilder);
1485 return std::nullopt;
1486 StringAttr description =
1487 cast<DictionaryAttr>(element).getAs<StringAttr>(
"description");
1488 interfaceBuilder[lastIndex].elementsList.emplace_back(description, name,
1496 igraph::ModuleOpInterface
1497 GrandCentralPass::getEnclosingModule(Value value, FlatSymbolRefAttr sym) {
1498 if (
auto blockArg = dyn_cast<BlockArgument>(value))
1499 return cast<igraph::ModuleOpInterface>(blockArg.getOwner()->getParentOp());
1501 auto *op = value.getDefiningOp();
1502 if (InstanceOp instance = dyn_cast<InstanceOp>(op))
1503 return getSymbolTable().lookup<igraph::ModuleOpInterface>(
1504 instance.getModuleNameAttr().getValue());
1506 return op->getParentOfType<igraph::ModuleOpInterface>();
1510 void GrandCentralPass::runOnOperation() {
1513 CircuitOp circuitOp = getOperation();
1522 SmallVector<Annotation> worklist;
1523 bool removalError =
false;
1532 if (companionMode != CompanionMode::Instantiate)
1533 worklist.push_back(anno);
1538 if (maybeExtractInfo) {
1539 emitCircuitError(
"more than one 'ExtractGrandCentralAnnotation' was "
1540 "found, but exactly one must be provided");
1541 removalError = true;
1545 auto directory = anno.
getMember<StringAttr>(
"directory");
1546 auto filename = anno.
getMember<StringAttr>(
"filename");
1547 if (!directory || !filename) {
1549 <<
"contained an invalid 'ExtractGrandCentralAnnotation' that does "
1550 "not contain 'directory' and 'filename' fields: "
1552 removalError =
true;
1555 if (directory.getValue().empty())
1558 maybeExtractInfo = {directory, filename};
1563 if (maybeHierarchyFileYAML) {
1564 emitCircuitError(
"more than one 'GrandCentralHierarchyFileAnnotation' "
1565 "was found, but zero or one may be provided");
1566 removalError =
true;
1570 auto filename = anno.
getMember<StringAttr>(
"filename");
1573 <<
"contained an invalid 'GrandCentralHierarchyFileAnnotation' "
1574 "that does not contain 'directory' and 'filename' fields: "
1576 removalError =
true;
1580 maybeHierarchyFileYAML = filename;
1585 if (!interfacePrefix.empty()) {
1586 emitCircuitError(
"more than one 'PrefixInterfacesAnnotation' was "
1587 "found, but zero or one may be provided");
1588 removalError =
true;
1592 auto prefix = anno.
getMember<StringAttr>(
"prefix");
1595 <<
"contained an invalid 'PrefixInterfacesAnnotation' that does "
1596 "not contain a 'prefix' field: "
1598 removalError =
true;
1602 interfacePrefix = prefix.getValue();
1607 testbenchDir = anno.
getMember<StringAttr>(
"dirname");
1615 for (
auto mod : circuitOp.getOps<FModuleOp>()) {
1617 removalError =
true;
1621 return signalPassFailure();
1624 llvm::dbgs() <<
"Extraction Info:\n";
1625 if (maybeExtractInfo)
1626 llvm::dbgs() <<
" directory: " << maybeExtractInfo->directory <<
"\n"
1627 <<
" filename: " << maybeExtractInfo->bindFilename <<
"\n";
1629 llvm::dbgs() <<
" <none>\n";
1630 llvm::dbgs() <<
"DUT: ";
1632 llvm::dbgs() << dut.getModuleName() <<
"\n";
1634 llvm::dbgs() <<
"<none>\n";
1636 <<
"Prefix Info (from PrefixInterfacesAnnotation):\n"
1637 <<
" prefix: " << interfacePrefix <<
"\n"
1638 <<
"Hierarchy File Info (from GrandCentralHierarchyFileAnnotation):\n"
1640 if (maybeHierarchyFileYAML)
1641 llvm::dbgs() << *maybeHierarchyFileYAML;
1643 llvm::dbgs() <<
"<none>";
1644 llvm::dbgs() <<
"\n";
1650 if (worklist.empty()) {
1651 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1652 emitHierarchyYamlFile(interfaceVec);
1653 return markAllAnalysesPreserved();
1660 auto builder = OpBuilder::atBlockEnd(circuitOp.getBodyBlock());
1664 auto getID = [&](Operation *op,
1665 Annotation annotation) -> std::optional<IntegerAttr> {
1666 auto id = annotation.getMember<IntegerAttr>(
"id");
1669 <<
"contained a malformed "
1670 "'sifive.enterprise.grandcentral.AugmentedGroundType' annotation "
1671 "that did not contain an 'id' field";
1672 removalError =
true;
1673 return std::nullopt;
1680 instancePaths = &instancePathCache;
1681 instanceInfo = &getAnalysis<InstanceInfo>();
1685 auto exactlyOneInstance = [&](FModuleOp op,
1686 StringRef msg) -> std::optional<InstanceOp> {
1689 switch (node->getNumUses()) {
1691 op->emitOpError() <<
"is marked as a GrandCentral '" << msg
1692 <<
"', but is never instantiated";
1693 return std::nullopt;
1695 return cast<InstanceOp>(*(*node->uses().begin())->getInstance());
1697 auto diag = op->emitOpError()
1698 <<
"is marked as a GrandCentral '" << msg
1699 <<
"', but it is instantiated more than once";
1700 for (
auto *instance : node->uses())
1701 diag.attachNote(instance->getInstance()->getLoc())
1702 <<
"it is instantiated here";
1703 return std::nullopt;
1707 nlaTable = &getAnalysis<NLATable>();
1713 DenseSet<Operation *> modulesToDelete;
1714 circuitOp.walk([&](Operation *op) {
1715 TypeSwitch<Operation *>(op)
1716 .Case<RegOp, RegResetOp, WireOp, NodeOp>([&](
auto op) {
1720 auto maybeID = getID(op, annotation);
1724 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1725 leafMap[*maybeID] = {{op.getResult(), annotation.
getFieldID()},
1732 .Case<InstanceOp>([&](
auto op) {
1738 <<
"is marked as an interface element, but this should be "
1739 "impossible due to how the Chisel Grand Central API works";
1740 removalError =
true;
1744 .Case<MemOp>([&](
auto op) {
1749 <<
"is marked as an interface element, but this does not make "
1750 "sense (is there a scattering bug or do you have a "
1751 "malformed hand-crafted MLIR circuit?)";
1752 removalError =
true;
1760 <<
"has port '" << i
1761 <<
"' marked as an interface element, but this does not "
1762 "make sense (is there a scattering bug or do you have a "
1763 "malformed hand-crafted MLIR circuit?)";
1764 removalError =
true;
1768 .Case<FModuleOp>([&](FModuleOp op) {
1774 auto maybeID = getID(op, annotation);
1778 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1779 leafMap[*maybeID] = {{op.getArgument(i), annotation.
getFieldID()},
1789 auto isNonlocal = annotation.
getMember<FlatSymbolRefAttr>(
1790 "circt.nonlocal") !=
nullptr;
1791 auto name = annotation.
getMember<StringAttr>(
"name");
1792 auto id = annotation.
getMember<IntegerAttr>(
"id");
1795 <<
"has a malformed "
1796 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1797 "not contain an 'id' field with an 'IntegerAttr' value";
1798 goto FModuleOp_error;
1802 <<
"has a malformed "
1803 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1804 "not contain a 'name' field with a 'StringAttr' value";
1805 goto FModuleOp_error;
1818 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
1820 companionIDMap[id] = {name.getValue(), op, isNonlocal};
1823 auto instance = exactlyOneInstance(op,
"companion");
1825 goto FModuleOp_error;
1828 for (
auto [i, result] : llvm::enumerate(instance->getResults())) {
1829 if (instance->getPortDirection(i) == Direction::In)
1832 auto ty = result.getType();
1833 if (isa<RefType>(ty) && companionMode != CompanionMode::Drop)
1836 <<
"companion instance cannot have output ports";
1837 goto FModuleOp_error;
1842 if (!maybeExtractInfo) {
1862 <<
"Found companion module: "
1863 << companionNode->getModule().getModuleName() <<
"\n"
1864 <<
" submodules exclusively instantiated "
1865 "(including companion):\n";
1870 OpBuilder builder(&getContext());
1871 for (
auto port : instance->getResults()) {
1872 builder.setInsertionPointAfterValue(port);
1874 builder.create<WireOp>(port.getLoc(), port.getType());
1875 port.replaceAllUsesWith(wire.getResult());
1882 (*instance)->setAttr(
"lowerToBind", builder.getUnitAttr());
1884 (*instance)->setAttr(
1886 hw::OutputFileAttr::getFromFilename(
1888 maybeExtractInfo->bindFilename.getValue(),
1892 for (
auto &node : llvm::depth_first(companionNode)) {
1893 auto mod = node->getModule();
1901 if (modNode != companionNode &&
1903 modNode->getModule()))
1908 <<
" - module: " << mod.getModuleName() <<
"\n";
1911 if (
auto extmodule = dyn_cast<FExtModuleOp>(*mod)) {
1914 modulesToDelete.insert(mod);
1920 if (extmodule->hasAttr(
"output_file"))
1924 hw::OutputFileAttr::getAsDirectory(
1926 maybeExtractInfo->directory.getValue()));
1933 modulesToDelete.insert(mod);
1937 if (!mod->hasAttr(
"output_file")) {
1938 mod->setAttr(
"output_file",
1939 hw::OutputFileAttr::getAsDirectory(
1941 maybeExtractInfo->directory.getValue(),
1944 mod->setAttr(
"comment", builder.getStringAttr(
1945 "VCS coverage exclude_file"));
1955 <<
"unknown annotation class: " << annotation.
getDict();
1958 removalError =
true;
1965 return signalPassFailure();
1967 if (companionMode == CompanionMode::Drop) {
1968 for (
auto *mod : modulesToDelete) {
1969 auto name = cast<FModuleLike>(mod).getModuleNameAttr();
1971 DenseSet<hw::HierPathOp> nlas;
1974 for (
auto nla : nlas) {
1975 if (nla.root() == name)
1982 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1983 emitHierarchyYamlFile(interfaceVec);
1990 SmallVector<IntegerAttr> ids;
1991 auto sort = [&ids]() {
1992 llvm::sort(ids, [](IntegerAttr a, IntegerAttr b) {
1993 return a.getValue().getZExtValue() < b.getValue().getZExtValue();
1996 for (
auto tuple : companionIDMap)
1997 ids.push_back(cast<IntegerAttr>(tuple.first));
1999 llvm::dbgs() <<
"companionIDMap:\n";
2000 for (
auto id : ids) {
2001 auto value = companionIDMap.lookup(
id);
2002 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2003 << value.companion.getName() <<
" -> " << value.name <<
"\n";
2006 for (
auto tuple : leafMap)
2007 ids.push_back(cast<IntegerAttr>(tuple.first));
2009 llvm::dbgs() <<
"leafMap:\n";
2010 for (
auto id : ids) {
2011 auto fieldRef = leafMap.lookup(
id).field;
2014 if (
auto blockArg = dyn_cast<BlockArgument>(value)) {
2015 FModuleOp module = cast<FModuleOp>(blockArg.getOwner()->getParentOp());
2016 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2017 << module.getName() +
">" +
2018 module.getPortName(blockArg.getArgNumber());
2020 llvm::dbgs() <<
", fieldID=" << fieldID;
2021 llvm::dbgs() <<
"\n";
2023 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2024 << cast<StringAttr>(value.getDefiningOp()->getAttr(
"name"))
2027 llvm::dbgs() <<
", fieldID=" << fieldID;
2028 llvm::dbgs() <<
"\n";
2039 SmallVector<sv::InterfaceOp, 2> interfaceVec;
2041 companionToInterfaceMap;
2042 auto compareInterfaceSignal = [&](InterfaceElemsBuilder &lhs,
2043 InterfaceElemsBuilder &rhs) {
2044 auto compareProps = [&](InterfaceElemsBuilder::Properties &lhs,
2045 InterfaceElemsBuilder::Properties &rhs) {
2049 if (lhs.elemType.index() == 0 && rhs.elemType.index() == 0)
2051 if (std::get<Type>(lhs.elemType) == std::get<Type>(rhs.elemType))
2055 return std::equal(lhs.elementsList.begin(), lhs.elementsList.end(),
2056 rhs.elementsList.begin(), compareProps);
2058 for (
auto anno : worklist) {
2063 if (!bundle.isRoot()) {
2064 emitCircuitError() <<
"missing 'id' in root-level BundleType: "
2066 removalError =
true;
2070 if (companionIDMap.count(bundle.getID()) == 0) {
2071 emitCircuitError() <<
"no companion found with 'id' value '"
2072 << bundle.getID().getValue().getZExtValue() <<
"'\n";
2073 removalError =
true;
2079 auto companionIter = companionIDMap.lookup(bundle.getID());
2080 auto companionModule = companionIter.companion;
2081 auto symbolName = getNamespace().newName(
2082 "__" + companionIDMap.lookup(bundle.getID()).name +
"_" +
2083 getInterfaceName(bundle.getPrefix(), bundle) +
"__");
2089 auto instanceSymbol =
2092 VerbatimBuilder::Base verbatimData;
2093 VerbatimBuilder verbatim(verbatimData);
2094 verbatim += instanceSymbol;
2097 SmallVector<VerbatimXMRbuilder> xmrElems;
2098 SmallVector<InterfaceElemsBuilder> interfaceBuilder;
2100 auto ifaceName = traverseBundle(bundle, bundle.getID(), bundle.getPrefix(),
2101 verbatim, xmrElems, interfaceBuilder);
2103 removalError =
true;
2107 if (companionIter.isNonlocal) {
2111 auto viewMapIter = companionToInterfaceMap.find(companionModule);
2112 if (viewMapIter != companionToInterfaceMap.end())
2113 if (std::equal(interfaceBuilder.begin(), interfaceBuilder.end(),
2114 viewMapIter->getSecond().begin(),
2115 compareInterfaceSignal)) {
2119 companionToInterfaceMap[companionModule] = interfaceBuilder;
2122 if (interfaceBuilder.empty())
2124 auto companionBuilder =
2125 OpBuilder::atBlockEnd(companionModule.getBodyBlock());
2128 for (
auto xmrElem : xmrElems) {
2129 auto uloc = companionBuilder.getUnknownLoc();
2130 companionBuilder.create<sv::VerbatimOp>(uloc, xmrElem.str, xmrElem.val,
2133 numXMRs += xmrElems.size();
2135 sv::InterfaceOp topIface;
2136 for (
const auto &ifaceBuilder : interfaceBuilder) {
2137 auto builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
2138 auto loc = getOperation().getLoc();
2139 sv::InterfaceOp iface =
2140 builder.create<sv::InterfaceOp>(loc, ifaceBuilder.iFaceName);
2146 companionIDMap[ifaceBuilder.id].companion, dut) &&
2148 iface->setAttr(
"output_file",
2149 hw::OutputFileAttr::getAsDirectory(
2150 &getContext(), testbenchDir.getValue(),
2152 else if (maybeExtractInfo)
2153 iface->setAttr(
"output_file",
2154 hw::OutputFileAttr::getAsDirectory(
2155 &getContext(), getOutputDirectory().getValue(),
2157 iface.setCommentAttr(builder.getStringAttr(
"VCS coverage exclude_file"));
2158 builder.setInsertionPointToEnd(
2159 cast<sv::InterfaceOp>(iface).getBodyBlock());
2161 ifaceBuilder.iFaceName)] = iface;
2162 for (
auto elem : ifaceBuilder.elementsList) {
2164 auto uloc = builder.getUnknownLoc();
2166 auto description = elem.description;
2169 auto descriptionOp = builder.create<sv::VerbatimOp>(
2170 uloc, (
"// " + cleanupDescription(description.getValue())));
2175 if (maybeHierarchyFileYAML)
2176 descriptionOp->setAttr(
"firrtl.grandcentral.yaml.type",
2177 builder.getStringAttr(
"description"));
2179 if (
auto *str = std::get_if<VerbatimType>(&elem.elemType)) {
2180 auto instanceOp = builder.create<sv::VerbatimOp>(
2181 uloc, str->toStr(elem.elemName.getValue()));
2185 if (maybeHierarchyFileYAML) {
2186 if (str->instantiation)
2187 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2188 builder.getStringAttr(
"instance"));
2190 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2191 builder.getStringAttr(
"unsupported"));
2192 instanceOp->setAttr(
"firrtl.grandcentral.yaml.name", elem.elemName);
2193 instanceOp->setAttr(
"firrtl.grandcentral.yaml.dimensions",
2194 builder.getI32ArrayAttr(str->dimensions));
2195 instanceOp->setAttr(
2196 "firrtl.grandcentral.yaml.symbol",
2202 auto tpe = std::get<Type>(elem.elemType);
2203 builder.create<sv::InterfaceSignalOp>(uloc, elem.elemName.getValue(),
2210 interfaceVec.push_back(topIface);
2213 builder.setInsertionPointToStart(companionModule.getBodyBlock());
2214 builder.create<sv::InterfaceInstanceOp>(
2215 getOperation().getLoc(), topIface.getInterfaceType(),
2216 companionIDMap.lookup(bundle.getID()).name,
2221 if (!maybeExtractInfo)
2227 companionIDMap[bundle.getID()].companion, dut))
2231 emitHierarchyYamlFile(interfaceVec);
2236 return signalPassFailure();
2237 markAnalysesPreserved<NLATable>();
2240 void GrandCentralPass::emitHierarchyYamlFile(
2241 SmallVectorImpl<sv::InterfaceOp> &intfs) {
2245 if (!maybeHierarchyFileYAML)
2248 CircuitOp circuitOp = getOperation();
2250 std::string yamlString;
2251 llvm::raw_string_ostream stream(yamlString);
2252 ::yaml::Context yamlContext({interfaceMap});
2254 yamlize(yout, intfs,
true, yamlContext);
2256 auto builder = OpBuilder::atBlockBegin(circuitOp.getBodyBlock());
2257 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), yamlString)
2258 ->setAttr(
"output_file",
2259 hw::OutputFileAttr::getFromFilename(
2260 &getContext(), maybeHierarchyFileYAML->getValue(),
2262 LLVM_DEBUG({ llvm::dbgs() <<
"Generated YAML:" << yamlString <<
"\n"; });
2269 std::unique_ptr<mlir::Pass>
2271 auto pass = std::make_unique<GrandCentralPass>();
2272 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
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)