26 #include "mlir/IR/ImplicitLocOpBuilder.h"
27 #include "llvm/ADT/DepthFirstIterator.h"
28 #include "llvm/ADT/TypeSwitch.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/YAMLTraits.h"
33 #define DEBUG_TYPE "gct"
35 using namespace circt;
36 using namespace firrtl;
49 #define UNIMPLEMENTED_DEFAULT(clazz) \
50 llvm_unreachable("default '" clazz \
51 "' construction is an intentionally *NOT* implemented " \
52 "YAML feature (you should never be using this)");
53 #define UNIMPLEMENTED_DENORM(clazz) \
54 llvm_unreachable("conversion from YAML to a '" clazz \
55 "' is intentionally *NOT* implemented (you should not be " \
56 "converting from YAML to an interface)");
69 DenseMap<Attribute, sv::InterfaceOp> &interfaceMap;
78 struct DescribedSignal {
80 StringAttr description;
83 sv::InterfaceSignalOp signal;
91 struct DescribedInstance {
95 StringAttr description;
101 FlatSymbolRefAttr interface;
111 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedSignal)
112 LLVM_YAML_IS_SEQUENCE_VECTOR(::yaml::DescribedInstance)
113 LLVM_YAML_IS_SEQUENCE_VECTOR(sv::InterfaceOp)
121 using namespace ::
yaml;
134 std::string descriptionString;
135 llvm::raw_string_ostream stream(descriptionString);
136 SmallVector<StringRef> splits;
137 str.split(splits,
"\n");
141 substr.consume_front(
"//");
142 stream << substr.drop_while([](
auto c) {
return c ==
' '; });
144 [&]() { stream <<
"\n"; });
145 return descriptionString;
152 struct MappingContextTraits<DescribedSignal, Context> {
170 : name(op.signal.getSymNameAttr().getValue()) {
196 auto tpe = op.signal.getType();
197 while (
auto vector = tpe.dyn_cast<hw::UnpackedArrayType>()) {
198 dimensions.push_back(vector.getNumElements());
199 tpe = vector.getElementType();
201 dimensions = SmallVector<unsigned>(llvm::reverse(dimensions));
206 assert(isa<IntegerType>(tpe));
207 width = type_cast<IntegerType>(tpe).getWidth();
219 static void mapping(IO &io, DescribedSignal &op, Context &ctx) {
220 MappingNormalization<Field, DescribedSignal> keys(io, op);
221 io.mapRequired(
"name", keys->name);
222 io.mapOptional(
"description", keys->description);
223 io.mapRequired(
"dimensions", keys->dimensions);
224 io.mapRequired(
"width", keys->width);
233 struct MappingContextTraits<DescribedInstance, Context> {
240 std::optional<std::string> description = std::nullopt;
249 : name(op.name.getValue()), interface(op.interface) {
257 for (
auto &d : op.dimensions) {
258 auto dimension = dyn_cast<IntegerAttr>(d);
259 dimensions.push_back(dimension.getInt());
270 static void mapping(IO &io, DescribedInstance &op, Context &ctx) {
271 MappingNormalization<Instance, DescribedInstance> keys(io, op);
272 io.mapRequired(
"name", keys->name);
273 io.mapOptional(
"description", keys->description);
274 io.mapRequired(
"dimensions", keys->dimensions);
275 io.mapRequired(
"interface", ctx.interfaceMap[keys->interface], ctx);
283 struct MappingContextTraits<
sv::InterfaceOp, Context> {
325 StringAttr description = {};
327 for (
auto &op : op.getBodyBlock()->getOperations()) {
328 TypeSwitch<Operation *>(&op)
331 .Case<sv::VerbatimOp>([&](sv::VerbatimOp op) {
332 auto tpe = op->getAttrOfType<StringAttr>(
333 "firrtl.grandcentral.yaml.type");
337 if (tpe.getValue() ==
"description") {
338 description = op.getFormatStringAttr();
343 if (tpe.getValue() ==
"unsupported") {
350 auto name = op->getAttrOfType<StringAttr>(
351 "firrtl.grandcentral.yaml.name");
352 auto dimensions = op->getAttrOfType<ArrayAttr>(
353 "firrtl.grandcentral.yaml.dimensions");
354 auto symbol = op->getAttrOfType<FlatSymbolRefAttr>(
355 "firrtl.grandcentral.yaml.symbol");
357 DescribedInstance({name, description, dimensions, symbol}));
361 .Case<sv::InterfaceSignalOp>([&](sv::InterfaceSignalOp op) {
362 fields.push_back(DescribedSignal({description, op}));
377 static void mapping(IO &io, sv::InterfaceOp &op, Context &ctx) {
378 MappingNormalization<Interface, sv::InterfaceOp> keys(io, op);
379 io.mapRequired(
"name", keys->name);
380 io.mapRequired(
"fields", keys->fields, ctx);
381 io.mapRequired(
"instances", keys->instances, ctx);
411 struct VerbatimBuilder {
413 SmallString<128> string;
414 SmallVector<Attribute> symbols;
415 VerbatimBuilder
builder() {
return VerbatimBuilder(*
this); }
416 operator VerbatimBuilder() {
return builder(); }
421 VerbatimBuilder(Base &base)
422 : base(base), stringBaseSize(base.string.size()),
423 symbolsBaseSize(base.symbols.size()) {}
428 base.string.resize(stringBaseSize);
429 base.symbols.resize(symbolsBaseSize);
433 VerbatimBuilder(
const VerbatimBuilder &) =
delete;
434 VerbatimBuilder &operator=(
const VerbatimBuilder &) =
delete;
439 VerbatimBuilder snapshot() {
return VerbatimBuilder(base); }
442 StringRef getString()
const {
return base.string; }
444 ArrayRef<Attribute> getSymbols()
const {
return base.symbols; }
447 VerbatimBuilder &
append(
char c) {
448 base.string.push_back(c);
453 VerbatimBuilder &
append(
const Twine &twine) {
454 twine.toVector(base.string);
459 VerbatimBuilder &
append(Attribute symbol) {
460 unsigned id = base.symbols.size();
461 base.symbols.push_back(symbol);
462 append(
"{{" + Twine(
id) +
"}}");
466 VerbatimBuilder &operator+=(
char c) {
return append(c); }
467 VerbatimBuilder &operator+=(
const Twine &twine) {
return append(twine); }
468 VerbatimBuilder &operator+=(Attribute symbol) {
return append(symbol); }
472 size_t stringBaseSize;
473 size_t symbolsBaseSize;
480 struct VerbatimType {
489 SmallVector<int32_t, 4> dimensions = {};
492 std::string toStr(StringRef name) {
493 SmallString<64> stringType(str);
494 stringType.append(
" ");
495 stringType.append(name);
496 for (
auto d : llvm::reverse(dimensions)) {
497 stringType.append(
"[");
498 stringType.append(Twine(d).str());
499 stringType.append(
"]");
502 stringType.append(
"()");
503 stringType.append(
";");
504 return std::string(stringType);
510 typedef std::variant<VerbatimType, Type> TypeSum;
513 struct ExtractionInfo {
516 StringAttr directory = {};
521 StringAttr bindFilename = {};
525 struct CompanionInfo {
536 FlatSymbolRefAttr nlaSym;
540 struct VerbatimXMRbuilder {
544 FModuleOp companionMod;
545 VerbatimXMRbuilder(Value val, StringAttr str, ArrayAttr syms,
546 FModuleOp companionMod)
547 : val(val), str(str), syms(syms), companionMod(companionMod) {}
552 struct InterfaceElemsBuilder {
553 StringAttr iFaceName;
556 StringAttr description;
559 Properties(StringAttr des, StringAttr name, TypeSum &elemType)
560 : description(des), elemName(name), elemType(elemType) {}
562 SmallVector<Properties> elementsList;
563 InterfaceElemsBuilder(StringAttr iFaceName, IntegerAttr
id)
564 : iFaceName(iFaceName), id(id) {}
579 struct GrandCentralPass :
public GrandCentralBase<GrandCentralPass> {
580 using GrandCentralBase::companionMode;
582 void runOnOperation()
override;
588 std::optional<Attribute> fromAttr(Attribute attr);
592 DenseMap<Attribute, FieldAndNLA> leafMap;
595 DenseMap<Attribute, CompanionInfo> companionIDMap;
599 StringRef interfacePrefix;
610 StringAttr testbenchDir;
614 std::string getInterfaceName(StringAttr prefix,
615 AugmentedBundleTypeAttr bundleType) {
618 return (prefix.getValue() + interfacePrefix +
619 bundleType.getDefName().getValue())
621 return (interfacePrefix + bundleType.getDefName().getValue()).str();
626 bool traverseField(Attribute field, IntegerAttr
id, VerbatimBuilder &path,
627 SmallVector<VerbatimXMRbuilder> &xmrElems,
628 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
633 std::optional<TypeSum>
634 computeField(Attribute field, IntegerAttr
id, StringAttr prefix,
635 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
636 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
641 std::optional<StringAttr>
642 traverseBundle(AugmentedBundleTypeAttr bundle, IntegerAttr
id,
643 StringAttr prefix, VerbatimBuilder &path,
644 SmallVector<VerbatimXMRbuilder> &xmrElems,
645 SmallVector<InterfaceElemsBuilder> &interfaceBuilder);
648 igraph::ModuleOpInterface getEnclosingModule(Value
value,
649 FlatSymbolRefAttr sym = {});
653 std::optional<ExtractionInfo> maybeExtractInfo = std::nullopt;
657 std::optional<StringAttr> maybeHierarchyFileYAML = std::nullopt;
659 StringAttr getOutputDirectory() {
660 if (maybeExtractInfo)
661 return maybeExtractInfo->directory;
675 std::optional<CircuitNamespace> circuitNamespace;
679 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
684 if (!circuitNamespace)
686 return *circuitNamespace;
690 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
691 return moduleNamespaces.try_emplace(module, module).first->second;
696 std::optional<SymbolTable *> symbolTable;
700 SymbolTable &getSymbolTable() {
702 symbolTable = &getAnalysis<SymbolTable>();
703 return **symbolTable;
710 InFlightDiagnostic emitCircuitError(StringRef message = {}) {
711 return emitError(getOperation().getLoc(),
"'firrtl.circuit' op " + message);
719 std::string cleanupDescription(StringRef description) {
723 std::tie(head, description) = description.split(
"\n");
725 if (!description.empty())
727 }
while (!description.empty());
728 return std::string(out);
732 DenseMap<Attribute, sv::InterfaceOp> interfaceMap;
735 void emitHierarchyYamlFile(SmallVectorImpl<sv::InterfaceOp> &intfs);
749 static std::optional<DictionaryAttr>
751 DictionaryAttr root, StringRef companion, StringAttr name,
752 StringAttr defName, std::optional<IntegerAttr>
id,
753 std::optional<StringAttr> description, Twine clazz,
754 StringAttr companionAttr, Twine path = {}) {
756 auto *context = state.
circuit.getContext();
757 auto loc = state.
circuit.getLoc();
774 [&](DictionaryAttr refTarget) -> std::optional<std::string> {
776 tryGetAs<StringAttr>(refTarget, refTarget,
"circuit", loc, clazz, path);
778 tryGetAs<StringAttr>(refTarget, refTarget,
"module", loc, clazz, path);
780 tryGetAs<ArrayAttr>(refTarget, refTarget,
"path", loc, clazz, path);
781 auto componentAttr = tryGetAs<ArrayAttr>(refTarget, refTarget,
"component",
783 if (!circuitAttr || !moduleAttr || !pathAttr || !componentAttr)
787 SmallString<32> strpath;
788 for (
auto p : pathAttr) {
789 auto dict = dyn_cast_or_null<DictionaryAttr>(p);
791 mlir::emitError(loc,
"annotation '" + clazz +
792 " has invalid type (expected DictionaryAttr)");
796 tryGetAs<DictionaryAttr>(dict, dict,
"_1", loc, clazz, path);
798 tryGetAs<DictionaryAttr>(dict, dict,
"_2", loc, clazz, path);
799 if (!instHolder || !modHolder) {
800 mlir::emitError(loc,
"annotation '" + clazz +
801 " has invalid type (expected DictionaryAttr)");
804 auto inst = tryGetAs<StringAttr>(instHolder, instHolder,
"value", loc,
807 tryGetAs<StringAttr>(modHolder, modHolder,
"value", loc, clazz, path);
809 mlir::emitError(loc,
"annotation '" + clazz +
810 " has invalid type (expected DictionaryAttr)");
813 strpath +=
"/" + inst.getValue().str() +
":" + mod.getValue().str();
816 SmallVector<Attribute> componentAttrs;
817 SmallString<32> componentStr;
818 for (
size_t i = 0, e = componentAttr.size(); i != e; ++i) {
819 auto cPath = (path +
".component[" + Twine(i) +
"]").str();
820 auto component = componentAttr[i];
821 auto dict = dyn_cast_or_null<DictionaryAttr>(component);
823 mlir::emitError(loc,
"annotation '" + clazz +
"' with path '" + cPath +
824 " has invalid type (expected DictionaryAttr)");
828 tryGetAs<StringAttr>(dict, refTarget,
"class", loc, clazz, cPath);
832 auto value = dict.get(
"value");
835 if (
auto field = dyn_cast<StringAttr>(
value)) {
836 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Field" &&
837 "A StringAttr target token must be found with a subfield target "
839 componentStr.append((Twine(
".") + field.getValue()).str());
844 if (
auto index = dyn_cast<IntegerAttr>(
value)) {
845 assert(classAttr.getValue() ==
"firrtl.annotations.TargetToken$Index" &&
846 "An IntegerAttr target token must be found with a subindex "
849 (Twine(
"[") + Twine(index.getValue().getZExtValue()) +
"]").str());
854 "Annotation '" + clazz +
"' with path '" + cPath +
855 ".value has unexpected type (should be StringAttr "
856 "for subfield or IntegerAttr for subindex).")
858 <<
"The value received was: " <<
value <<
"\n";
863 tryGetAs<StringAttr>(refTarget, refTarget,
"ref", loc, clazz, path);
865 return (Twine(
"~" + circuitAttr.getValue() +
"|" + moduleAttr.getValue() +
866 strpath +
">" + refAttr.getValue()) +
872 tryGetAs<StringAttr>(augmentedType, root,
"class", loc, clazz, path);
875 StringRef classBase = classAttr.getValue();
876 if (!classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented")) {
878 "the 'class' was expected to start with "
879 "'sifive.enterprise.grandCentral.Augmented*', but was '" +
880 classAttr.getValue() +
"' (Did you misspell it?)")
882 <<
"see annotation: " << augmentedType;
889 if (classBase ==
"BundleType") {
891 tryGetAs<StringAttr>(augmentedType, root,
"defName", loc, clazz, path);
899 SmallVector<Attribute> elements;
901 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
904 for (
size_t i = 0, e = elementsAttr.size(); i != e; ++i) {
905 auto field = dyn_cast_or_null<DictionaryAttr>(elementsAttr[i]);
909 "Annotation '" + Twine(clazz) +
"' with path '.elements[" +
911 "]' contained an unexpected type (expected a DictionaryAttr).")
913 <<
"The received element was: " << elementsAttr[i] <<
"\n";
916 auto ePath = (path +
".elements[" + Twine(i) +
"]").str();
917 auto name = tryGetAs<StringAttr>(field, root,
"name", loc, clazz, ePath);
919 tryGetAs<DictionaryAttr>(field, root,
"tpe", loc, clazz, ePath);
920 std::optional<StringAttr> description;
921 if (
auto maybeDescription = field.get(
"description"))
922 description = cast<StringAttr>(maybeDescription);
924 state, tpe, root, companion, name, defName, std::nullopt, description,
925 clazz, companionAttr, path +
"_" + name.getValue());
926 if (!name || !tpe || !eltAttr)
932 if (
auto maybeDescription = field.get(
"description"))
933 attrs.append(
"description", cast<StringAttr>(maybeDescription));
934 attrs.append(
"name", name);
935 attrs.append(
"tpe", tpe.getAs<StringAttr>(
"class"));
936 elements.push_back(*eltAttr);
942 attrs.append(
"class", classAttr);
943 attrs.append(
"defName", defName);
945 attrs.append(
"description", *description);
948 attrs.append(
"id", *
id);
949 attrs.append(
"name", name);
950 return DictionaryAttr::getWithSorted(context, attrs);
959 if (classBase ==
"GroundType") {
960 auto maybeTarget = refToTarget(augmentedType.getAs<DictionaryAttr>(
"ref"));
962 mlir::emitError(loc,
"Failed to parse ReferenceTarget").attachNote()
963 <<
"See the full Annotation here: " << root;
967 auto id = state.
newID();
969 auto target = *maybeTarget;
971 NamedAttrList elementIface, elementScattered;
974 elementIface.append(
"class", classAttr);
976 elementIface.append(
"description", *description);
977 elementIface.append(
"id",
id);
978 elementIface.append(
"name", name);
980 elementScattered.append(
"class", classAttr);
981 elementScattered.append(
"id",
id);
987 mlir::emitError(loc,
"Failed to resolve target ") << targetAttr;
994 auto sourceRef = xmrSrcTarget->ref;
995 ImplicitLocOpBuilder
builder(sourceRef.getOp()->getLoc(), context);
996 std::optional<Value> source =
997 TypeSwitch<Operation *, std::optional<Value>>(sourceRef.getOp())
1000 .Case<FExtModuleOp>([&](FExtModuleOp extMod)
1001 -> std::optional<Value> {
1002 auto portNo = sourceRef.getImpl().getPortNo();
1003 if (xmrSrcTarget->instances.empty()) {
1005 if (paths.size() > 1) {
1007 "cannot resolve a unique instance path from the "
1008 "external module '")
1009 << targetAttr <<
"'";
1010 return std::nullopt;
1012 auto *it = xmrSrcTarget->instances.begin();
1013 for (
auto inst : paths.back()) {
1014 xmrSrcTarget->instances.insert(it, cast<InstanceOp>(inst));
1018 auto lastInst = xmrSrcTarget->instances.pop_back_val();
1019 builder.setInsertionPointAfter(lastInst);
1021 xmrSrcTarget->fieldIdx);
1025 .Case<FModuleOp>([&](FModuleOp module) -> std::optional<Value> {
1026 builder.setInsertionPointToEnd(module.getBodyBlock());
1027 auto portNum = sourceRef.getImpl().getPortNo();
1029 xmrSrcTarget->fieldIdx);
1032 .Default([&](Operation *op) -> std::optional<Value> {
1033 auto module = cast<FModuleOp>(sourceRef.getModule());
1034 builder.setInsertionPointToEnd(module.getBodyBlock());
1035 auto is = dyn_cast<hw::InnerSymbolOpInterface>(op);
1037 if (is && is.getTargetResult())
1039 xmrSrcTarget->fieldIdx);
1040 if (sourceRef.getOp()->getNumResults() != 1) {
1042 <<
"cannot be used as a target of the Grand Central View \""
1043 << defName.getValue()
1044 <<
"\" because it does not have exactly one result";
1045 return std::nullopt;
1048 xmrSrcTarget->fieldIdx);
1053 return std::nullopt;
1065 builder.setInsertionPointToEnd(companionMod.getBodyBlock());
1066 auto sink =
builder.create<WireOp>(source->getType(), name);
1069 annotations.addAnnotations(
1070 {DictionaryAttr::getWithSorted(context, elementScattered)});
1071 annotations.applyToOperation(sink);
1076 (path +
"__bore").str(),
1079 return DictionaryAttr::getWithSorted(context, elementIface);
1084 if (classBase ==
"VectorType") {
1086 tryGetAs<ArrayAttr>(augmentedType, root,
"elements", loc, clazz, path);
1088 return std::nullopt;
1089 SmallVector<Attribute> elements;
1090 for (
auto [i, elt] : llvm::enumerate(elementsAttr)) {
1092 state, cast<DictionaryAttr>(elt), root, companion, name,
1094 path +
"_" + Twine(i));
1096 return std::nullopt;
1097 elements.push_back(*eltAttr);
1099 NamedAttrList attrs;
1100 attrs.append(
"class", classAttr);
1102 attrs.append(
"description", *description);
1104 attrs.append(
"name", name);
1105 return DictionaryAttr::getWithSorted(context, attrs);
1115 llvm::StringSwitch<bool>(classBase)
1116 .Cases(
"StringType",
"BooleanType",
"IntegerType",
"DoubleType",
true)
1119 NamedAttrList attrs;
1120 attrs.append(
"class", classAttr);
1121 attrs.append(
"name", name);
1123 tryGetAs<Attribute>(augmentedType, root,
"value", loc, clazz, path);
1125 return std::nullopt;
1126 attrs.append(
"value",
value);
1127 return DictionaryAttr::getWithSorted(context, attrs);
1132 mlir::emitError(loc,
"found unknown AugmentedType '" + classAttr.getValue() +
1133 "' (Did you misspell it?)")
1135 <<
"see annotation: " << augmentedType;
1136 return std::nullopt;
1140 DictionaryAttr anno,
1143 auto id = state.
newID();
1144 auto *context = state.
circuit.getContext();
1145 auto loc = state.
circuit.getLoc();
1146 NamedAttrList companionAttrs;
1148 companionAttrs.append(
"id",
id);
1150 tryGetAs<DictionaryAttr>(anno, anno,
"view", loc,
viewAnnoClass);
1153 auto name = tryGetAs<StringAttr>(anno, anno,
"name", loc,
viewAnnoClass);
1156 companionAttrs.append(
"name", name);
1157 auto companionAttr =
1158 tryGetAs<StringAttr>(anno, anno,
"companion", loc,
viewAnnoClass);
1161 companionAttrs.append(
"target", companionAttr);
1181 std::optional<Attribute> GrandCentralPass::fromAttr(Attribute attr) {
1182 auto dict = dyn_cast<DictionaryAttr>(attr);
1184 emitCircuitError() <<
"attribute is not a dictionary: " << attr <<
"\n";
1185 return std::nullopt;
1188 auto clazz = dict.getAs<StringAttr>(
"class");
1190 emitCircuitError() <<
"missing 'class' key in " << dict <<
"\n";
1191 return std::nullopt;
1194 auto classBase = clazz.getValue();
1195 classBase.consume_front(
"sifive.enterprise.grandcentral.Augmented");
1197 if (classBase ==
"BundleType") {
1198 if (dict.getAs<StringAttr>(
"defName") && dict.getAs<ArrayAttr>(
"elements"))
1200 emitCircuitError() <<
"has an invalid AugmentedBundleType that does not "
1201 "contain 'defName' and 'elements' fields: "
1203 }
else if (classBase ==
"VectorType") {
1204 if (dict.getAs<StringAttr>(
"name") && dict.getAs<ArrayAttr>(
"elements"))
1206 emitCircuitError() <<
"has an invalid AugmentedVectorType that does not "
1207 "contain 'name' and 'elements' fields: "
1209 }
else if (classBase ==
"GroundType") {
1210 auto id = dict.getAs<IntegerAttr>(
"id");
1211 auto name = dict.getAs<StringAttr>(
"name");
1212 if (
id && leafMap.count(
id) && name)
1215 emitCircuitError() <<
"has an invalid AugmentedGroundType that does not "
1216 "contain 'id' and 'name' fields: "
1218 if (
id && !leafMap.count(
id))
1219 emitCircuitError() <<
"has an AugmentedGroundType with 'id == "
1220 <<
id.getValue().getZExtValue()
1221 <<
"' that does not have a scattered leaf to connect "
1222 "to in the circuit "
1223 "(was the leaf deleted or constant prop'd away?)";
1224 }
else if (classBase ==
"StringType") {
1225 if (
auto name = dict.getAs<StringAttr>(
"name"))
1227 }
else if (classBase ==
"BooleanType") {
1228 if (
auto name = dict.getAs<StringAttr>(
"name"))
1230 }
else if (classBase ==
"IntegerType") {
1231 if (
auto name = dict.getAs<StringAttr>(
"name"))
1233 }
else if (classBase ==
"DoubleType") {
1234 if (
auto name = dict.getAs<StringAttr>(
"name"))
1236 }
else if (classBase ==
"LiteralType") {
1237 if (
auto name = dict.getAs<StringAttr>(
"name"))
1239 }
else if (classBase ==
"DeletedType") {
1240 if (
auto name = dict.getAs<StringAttr>(
"name"))
1243 emitCircuitError() <<
"has an invalid AugmentedType";
1245 return std::nullopt;
1248 bool GrandCentralPass::traverseField(
1249 Attribute field, IntegerAttr
id, VerbatimBuilder &path,
1250 SmallVector<VerbatimXMRbuilder> &xmrElems,
1251 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1252 return TypeSwitch<Attribute, bool>(field)
1253 .Case<AugmentedGroundTypeAttr>([&](AugmentedGroundTypeAttr ground) {
1254 auto [fieldRef, sym] = leafMap.lookup(ground.getID());
1257 nla = nlaTable->
getNLA(sym.getAttr());
1258 Value leafValue = fieldRef.getValue();
1259 assert(leafValue &&
"leafValue not found");
1261 auto companionModule = companionIDMap.lookup(
id).companion;
1262 igraph::ModuleOpInterface enclosing =
1263 getEnclosingModule(leafValue, sym);
1265 auto tpe = type_cast<FIRRTLBaseType>(leafValue.getType());
1268 if (!tpe.getBitWidthOrSentinel())
1280 auto *nodeOp = leafValue.getDefiningOp();
1281 if (companionModule != enclosing) {
1282 auto diag = companionModule->emitError()
1283 <<
"Grand Central View \""
1284 << companionIDMap.lookup(
id).name
1285 <<
"\" is invalid because a leaf is not inside the "
1287 diag.attachNote(leafValue.getLoc())
1288 <<
"the leaf value is declared here";
1290 auto leafModule = nodeOp->getParentOfType<FModuleOp>();
1291 diag.attachNote(leafModule.getLoc())
1292 <<
"the leaf value is inside this module";
1297 if (!isa<NodeOp>(nodeOp)) {
1298 emitError(leafValue.getLoc())
1299 <<
"Grand Central View \"" << companionIDMap.lookup(
id).name
1300 <<
"\" has an invalid leaf value (this must be a node)";
1307 auto getStrAndIncrementIds = [&](StringRef base) -> StringAttr {
1308 SmallString<128> replStr;
1309 StringRef begin =
"{{";
1310 StringRef
end =
"}}";
1313 while (from < base.size()) {
1315 size_t beginAt = base.find(begin, from);
1316 size_t endAt = base.find(end, from);
1318 if (beginAt == StringRef::npos || endAt == StringRef::npos ||
1319 (beginAt > endAt)) {
1320 replStr.append(base.substr(from));
1324 replStr.append(base.substr(from, beginAt - from));
1327 auto idChar = base.substr(beginAt + 2, endAt - beginAt - 2);
1329 bool failed = idChar.getAsInteger(10, idNum);
1331 assert(!failed &&
"failed to parse integer from verbatim string");
1333 replStr.append(
"{{");
1334 Twine(idNum + 1).toVector(replStr);
1335 replStr.append(
"}}");
1344 path +=
" = {{-1}}";
1347 xmrElems.emplace_back(
1348 nodeOp->getOperand(0), getStrAndIncrementIds(path.getString()),
1349 ArrayAttr::get(&getContext(), path.getSymbols()), companionModule);
1352 .Case<AugmentedVectorTypeAttr>([&](
auto vector) {
1353 bool notFailed =
true;
1354 auto elements = vector.getElements();
1355 for (
size_t i = 0, e = elements.size(); i != e; ++i) {
1356 auto field = fromAttr(elements[i]);
1359 notFailed &= traverseField(
1360 *field,
id, path.snapshot().append(
"[" + Twine(i) +
"]"),
1361 xmrElems, interfaceBuilder);
1365 .Case<AugmentedBundleTypeAttr>([&](AugmentedBundleTypeAttr bundle) {
1366 bool anyFailed =
true;
1367 for (
auto element : bundle.getElements()) {
1368 auto field = fromAttr(element);
1371 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1373 name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"defName");
1374 anyFailed &= traverseField(
1375 *field,
id, path.snapshot().append(
"." + name.getValue()),
1376 xmrElems, interfaceBuilder);
1381 .Case<AugmentedStringTypeAttr>([&](
auto a) {
return false; })
1382 .Case<AugmentedBooleanTypeAttr>([&](
auto a) {
return false; })
1383 .Case<AugmentedIntegerTypeAttr>([&](
auto a) {
return false; })
1384 .Case<AugmentedDoubleTypeAttr>([&](
auto a) {
return false; })
1385 .Case<AugmentedLiteralTypeAttr>([&](
auto a) {
return false; })
1386 .Case<AugmentedDeletedTypeAttr>([&](
auto a) {
return false; })
1387 .Default([](
auto a) {
return true; });
1390 std::optional<TypeSum> GrandCentralPass::computeField(
1391 Attribute field, IntegerAttr
id, StringAttr prefix, VerbatimBuilder &path,
1392 SmallVector<VerbatimXMRbuilder> &xmrElems,
1393 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1395 auto unsupported = [&](StringRef name, StringRef kind) {
1396 return VerbatimType({(
"// <unsupported " + kind +
" type>").str(),
false});
1399 return TypeSwitch<Attribute, std::optional<TypeSum>>(field)
1400 .Case<AugmentedGroundTypeAttr>(
1401 [&](AugmentedGroundTypeAttr ground) -> std::optional<TypeSum> {
1403 if (!traverseField(field,
id, path, xmrElems, interfaceBuilder))
1404 return std::nullopt;
1405 FieldRef fieldRef = leafMap.lookup(ground.getID()).field;
1408 auto tpe = firrtl::type_cast<FIRRTLBaseType>(
1411 if (!tpe.isGround()) {
1412 value.getDefiningOp()->emitOpError()
1413 <<
"cannot be added to interface with id '"
1414 <<
id.getValue().getZExtValue()
1415 <<
"' because it is not a ground type";
1416 return std::nullopt;
1419 tpe.getBitWidthOrSentinel()));
1421 .Case<AugmentedVectorTypeAttr>(
1422 [&](AugmentedVectorTypeAttr vector) -> std::optional<TypeSum> {
1423 auto elements = vector.getElements();
1424 auto firstElement = fromAttr(elements[0]);
1426 computeField(*firstElement,
id, prefix,
1427 path.snapshot().append(
"[" + Twine(0) +
"]"),
1428 xmrElems, interfaceBuilder);
1430 return std::nullopt;
1432 for (
size_t i = 1, e = elements.size(); i != e; ++i) {
1433 auto subField = fromAttr(elements[i]);
1435 return std::nullopt;
1436 (void)traverseField(*subField,
id,
1437 path.snapshot().append(
"[" + Twine(i) +
"]"),
1438 xmrElems, interfaceBuilder);
1445 str.dimensions.push_back(elements.getValue().size());
1446 return TypeSum(str);
1448 .Case<AugmentedBundleTypeAttr>(
1449 [&](AugmentedBundleTypeAttr bundle) -> TypeSum {
1450 auto ifaceName = traverseBundle(bundle,
id, prefix, path, xmrElems,
1452 assert(ifaceName && *ifaceName);
1453 return VerbatimType({ifaceName->str(),
true});
1455 .Case<AugmentedStringTypeAttr>([&](
auto field) -> TypeSum {
1456 return unsupported(field.getName().getValue(),
"string");
1458 .Case<AugmentedBooleanTypeAttr>([&](
auto field) -> TypeSum {
1459 return unsupported(field.getName().getValue(),
"boolean");
1461 .Case<AugmentedIntegerTypeAttr>([&](
auto field) -> TypeSum {
1462 return unsupported(field.getName().getValue(),
"integer");
1464 .Case<AugmentedDoubleTypeAttr>([&](
auto field) -> TypeSum {
1465 return unsupported(field.getName().getValue(),
"double");
1467 .Case<AugmentedLiteralTypeAttr>([&](
auto field) -> TypeSum {
1468 return unsupported(field.getName().getValue(),
"literal");
1470 .Case<AugmentedDeletedTypeAttr>([&](
auto field) -> TypeSum {
1471 return unsupported(field.getName().getValue(),
"deleted");
1481 std::optional<StringAttr> GrandCentralPass::traverseBundle(
1482 AugmentedBundleTypeAttr bundle, IntegerAttr
id, StringAttr prefix,
1483 VerbatimBuilder &path, SmallVector<VerbatimXMRbuilder> &xmrElems,
1484 SmallVector<InterfaceElemsBuilder> &interfaceBuilder) {
1486 unsigned lastIndex = interfaceBuilder.size();
1488 &getContext(), getNamespace().newName(getInterfaceName(prefix, bundle)));
1489 interfaceBuilder.emplace_back(iFaceName,
id);
1491 for (
auto element : bundle.getElements()) {
1492 auto field = fromAttr(element);
1494 return std::nullopt;
1496 auto name = cast<DictionaryAttr>(element).getAs<StringAttr>(
"name");
1507 *field,
id, prefix, path.snapshot().append(
".").append(name.getValue()),
1508 xmrElems, interfaceBuilder);
1510 return std::nullopt;
1511 StringAttr description =
1512 cast<DictionaryAttr>(element).getAs<StringAttr>(
"description");
1513 interfaceBuilder[lastIndex].elementsList.emplace_back(description, name,
1521 igraph::ModuleOpInterface
1522 GrandCentralPass::getEnclosingModule(Value
value, FlatSymbolRefAttr sym) {
1523 if (
auto blockArg = dyn_cast<BlockArgument>(
value))
1524 return cast<igraph::ModuleOpInterface>(blockArg.getOwner()->getParentOp());
1526 auto *op =
value.getDefiningOp();
1527 if (InstanceOp instance = dyn_cast<InstanceOp>(op))
1528 return getSymbolTable().lookup<igraph::ModuleOpInterface>(
1529 instance.getModuleNameAttr().getValue());
1531 return op->getParentOfType<igraph::ModuleOpInterface>();
1535 void GrandCentralPass::runOnOperation() {
1536 LLVM_DEBUG(
llvm::dbgs() <<
"===- Running Grand Central Views/Interface Pass "
1537 "-----------------------------===\n");
1539 CircuitOp circuitOp = getOperation();
1548 SmallVector<Annotation> worklist;
1549 bool removalError =
false;
1558 if (companionMode != CompanionMode::Instantiate)
1559 worklist.push_back(anno);
1564 if (maybeExtractInfo) {
1565 emitCircuitError(
"more than one 'ExtractGrandCentralAnnotation' was "
1566 "found, but exactly one must be provided");
1567 removalError = true;
1571 auto directory = anno.
getMember<StringAttr>(
"directory");
1572 auto filename = anno.
getMember<StringAttr>(
"filename");
1573 if (!directory || !filename) {
1575 <<
"contained an invalid 'ExtractGrandCentralAnnotation' that does "
1576 "not contain 'directory' and 'filename' fields: "
1578 removalError =
true;
1581 if (directory.getValue().empty())
1584 maybeExtractInfo = {directory, filename};
1589 if (maybeHierarchyFileYAML) {
1590 emitCircuitError(
"more than one 'GrandCentralHierarchyFileAnnotation' "
1591 "was found, but zero or one may be provided");
1592 removalError =
true;
1596 auto filename = anno.
getMember<StringAttr>(
"filename");
1599 <<
"contained an invalid 'GrandCentralHierarchyFileAnnotation' "
1600 "that does not contain 'directory' and 'filename' fields: "
1602 removalError =
true;
1606 maybeHierarchyFileYAML = filename;
1611 if (!interfacePrefix.empty()) {
1612 emitCircuitError(
"more than one 'PrefixInterfacesAnnotation' was "
1613 "found, but zero or one may be provided");
1614 removalError =
true;
1618 auto prefix = anno.
getMember<StringAttr>(
"prefix");
1621 <<
"contained an invalid 'PrefixInterfacesAnnotation' that does "
1622 "not contain a 'prefix' field: "
1624 removalError =
true;
1628 interfacePrefix = prefix.getValue();
1633 testbenchDir = anno.
getMember<StringAttr>(
"dirname");
1641 for (
auto mod : circuitOp.getOps<FModuleOp>()) {
1643 removalError =
true;
1647 return signalPassFailure();
1651 if (maybeExtractInfo)
1652 llvm::dbgs() <<
" directory: " << maybeExtractInfo->directory <<
"\n"
1653 <<
" filename: " << maybeExtractInfo->bindFilename <<
"\n";
1662 <<
"Prefix Info (from PrefixInterfacesAnnotation):\n"
1663 <<
" prefix: " << interfacePrefix <<
"\n"
1664 <<
"Hierarchy File Info (from GrandCentralHierarchyFileAnnotation):\n"
1666 if (maybeHierarchyFileYAML)
1676 if (worklist.empty()) {
1677 SmallVector<sv::InterfaceOp, 0> interfaceVec;
1678 emitHierarchyYamlFile(interfaceVec);
1679 return markAllAnalysesPreserved();
1686 auto builder = OpBuilder::atBlockEnd(circuitOp.getBodyBlock());
1690 auto getID = [&](Operation *op,
1691 Annotation annotation) -> std::optional<IntegerAttr> {
1692 auto id = annotation.getMember<IntegerAttr>(
"id");
1695 <<
"contained a malformed "
1696 "'sifive.enterprise.grandcentral.AugmentedGroundType' annotation "
1697 "that did not contain an 'id' field";
1698 removalError =
true;
1699 return std::nullopt;
1706 instancePaths = &instancePathCache;
1713 DenseSet<igraph::ModuleOpInterface> dutModules;
1714 FModuleOp effectiveDUT = dut;
1716 effectiveDUT = cast<FModuleOp>(
1720 for (
auto i = dfRange.begin(), e = dfRange.end(); i != e;) {
1721 auto module = cast<FModuleLike>(*i->getModule());
1726 dutModules.insert(i->getModule<igraph::ModuleOpInterface>());
1734 auto exactlyOneInstance = [&](FModuleOp op,
1735 StringRef msg) -> std::optional<InstanceOp> {
1738 switch (node->getNumUses()) {
1740 op->emitOpError() <<
"is marked as a GrandCentral '" << msg
1741 <<
"', but is never instantiated";
1742 return std::nullopt;
1744 return cast<InstanceOp>(*(*node->uses().begin())->getInstance());
1746 auto diag = op->emitOpError()
1747 <<
"is marked as a GrandCentral '" << msg
1748 <<
"', but it is instantiated more than once";
1749 for (
auto *instance : node->uses())
1750 diag.attachNote(instance->getInstance()->getLoc())
1751 <<
"it is instantiated here";
1752 return std::nullopt;
1756 nlaTable = &getAnalysis<NLATable>();
1762 DenseSet<Operation *> modulesToDelete;
1763 removalError =
false;
1764 circuitOp.walk([&](Operation *op) {
1765 TypeSwitch<Operation *>(op)
1766 .Case<RegOp, RegResetOp, WireOp, NodeOp>([&](
auto op) {
1770 auto maybeID = getID(op, annotation);
1774 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1775 leafMap[*maybeID] = {{op.getResult(), annotation.
getFieldID()},
1782 .Case<InstanceOp>([&](
auto op) {
1788 <<
"is marked as an interface element, but this should be "
1789 "impossible due to how the Chisel Grand Central API works";
1790 removalError =
true;
1794 .Case<MemOp>([&](
auto op) {
1799 <<
"is marked as an interface element, but this does not make "
1800 "sense (is there a scattering bug or do you have a "
1801 "malformed hand-crafted MLIR circuit?)";
1802 removalError =
true;
1810 <<
"has port '" << i
1811 <<
"' marked as an interface element, but this does not "
1812 "make sense (is there a scattering bug or do you have a "
1813 "malformed hand-crafted MLIR circuit?)";
1814 removalError =
true;
1818 .Case<FModuleOp>([&](FModuleOp op) {
1824 auto maybeID = getID(op, annotation);
1828 annotation.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
1829 leafMap[*maybeID] = {{op.getArgument(i), annotation.
getFieldID()},
1839 auto isNonlocal = annotation.
getMember<FlatSymbolRefAttr>(
1840 "circt.nonlocal") !=
nullptr;
1841 auto name = annotation.
getMember<StringAttr>(
"name");
1842 auto id = annotation.
getMember<IntegerAttr>(
"id");
1845 <<
"has a malformed "
1846 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1847 "not contain an 'id' field with an 'IntegerAttr' value";
1848 goto FModuleOp_error;
1852 <<
"has a malformed "
1853 "'sifive.enterprise.grandcentral.ViewAnnotation' that did "
1854 "not contain a 'name' field with a 'StringAttr' value";
1855 goto FModuleOp_error;
1868 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
1870 companionIDMap[id] = {name.getValue(), op, isNonlocal};
1873 auto instance = exactlyOneInstance(op,
"companion");
1875 goto FModuleOp_error;
1878 for (
auto [i, result] : llvm::enumerate(instance->getResults())) {
1879 if (instance->getPortDirection(i) == Direction::In)
1882 auto ty = result.getType();
1883 if (ty.isa<RefType>() && companionMode != CompanionMode::Drop)
1886 <<
"companion instance cannot have output ports";
1887 goto FModuleOp_error;
1892 if (!maybeExtractInfo) {
1912 <<
"Found companion module: "
1913 << companionNode->getModule().getModuleName() <<
"\n"
1914 <<
" submodules exclusively instantiated "
1915 "(including companion):\n";
1920 OpBuilder
builder(&getContext());
1921 for (
auto port : instance->getResults()) {
1922 builder.setInsertionPointAfterValue(port);
1924 builder.create<WireOp>(port.getLoc(), port.getType());
1925 port.replaceAllUsesWith(wire.getResult());
1932 (*instance)->setAttr(
"lowerToBind",
builder.getUnitAttr());
1934 (*instance)->setAttr(
1936 hw::OutputFileAttr::getFromFilename(
1938 maybeExtractInfo->bindFilename.getValue(),
1942 for (
auto &node : llvm::depth_first(companionNode)) {
1943 auto mod = node->getModule();
1950 SmallVector<InstanceRecord *> instances(modNode->uses());
1951 if (modNode != companionNode &&
1953 modNode->getModule<igraph::ModuleOpInterface>()))
1958 <<
" - module: " << mod.getModuleName() <<
"\n";
1961 if (
auto extmodule = dyn_cast<FExtModuleOp>(*mod)) {
1964 modulesToDelete.insert(mod);
1970 if (extmodule->hasAttr(
"output_file"))
1974 hw::OutputFileAttr::getAsDirectory(
1976 maybeExtractInfo->directory.getValue()));
1983 modulesToDelete.insert(mod);
1987 if (!mod->hasAttr(
"output_file")) {
1988 mod->setAttr(
"output_file",
1989 hw::OutputFileAttr::getAsDirectory(
1991 maybeExtractInfo->directory.getValue(),
1994 mod->setAttr(
"comment",
builder.getStringAttr(
1995 "VCS coverage exclude_file"));
2005 <<
"unknown annotation class: " << annotation.
getDict();
2008 removalError =
true;
2015 return signalPassFailure();
2017 if (companionMode == CompanionMode::Drop) {
2018 for (
auto *mod : modulesToDelete) {
2019 auto name = cast<FModuleLike>(mod).getModuleNameAttr();
2021 DenseSet<hw::HierPathOp> nlas;
2024 for (
auto nla : nlas) {
2025 if (nla.root() == name)
2032 SmallVector<sv::InterfaceOp, 0> interfaceVec;
2033 emitHierarchyYamlFile(interfaceVec);
2040 SmallVector<IntegerAttr> ids;
2041 auto sort = [&ids]() {
2042 llvm::sort(ids, [](IntegerAttr a, IntegerAttr b) {
2043 return a.getValue().getZExtValue() < b.getValue().getZExtValue();
2046 for (
auto tuple : companionIDMap)
2047 ids.push_back(cast<IntegerAttr>(tuple.first));
2050 for (
auto id : ids) {
2051 auto value = companionIDMap.lookup(
id);
2052 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2053 <<
value.companion.getName() <<
" -> " <<
value.name <<
"\n";
2056 for (
auto tuple : leafMap)
2057 ids.push_back(cast<IntegerAttr>(tuple.first));
2060 for (
auto id : ids) {
2061 auto fieldRef = leafMap.lookup(
id).field;
2064 if (
auto blockArg = dyn_cast<BlockArgument>(
value)) {
2065 FModuleOp module = cast<FModuleOp>(blockArg.getOwner()->getParentOp());
2066 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2067 << module.getName() +
">" +
2068 module.getPortName(blockArg.getArgNumber());
2073 llvm::dbgs() <<
" - " <<
id.getValue() <<
": "
2074 <<
value.getDefiningOp()
2091 SmallVector<sv::InterfaceOp, 2> interfaceVec;
2093 companionToInterfaceMap;
2094 auto compareInterfaceSignal = [&](InterfaceElemsBuilder &lhs,
2095 InterfaceElemsBuilder &rhs) {
2096 auto compareProps = [&](InterfaceElemsBuilder::Properties &lhs,
2097 InterfaceElemsBuilder::Properties &rhs) {
2101 if (lhs.elemType.index() == 0 && rhs.elemType.index() == 0)
2103 if (std::get<Type>(lhs.elemType) == std::get<Type>(rhs.elemType))
2107 return std::equal(lhs.elementsList.begin(), lhs.elementsList.end(),
2108 rhs.elementsList.begin(), compareProps);
2110 for (
auto anno : worklist) {
2115 if (!bundle.isRoot()) {
2116 emitCircuitError() <<
"missing 'id' in root-level BundleType: "
2118 removalError =
true;
2122 if (companionIDMap.count(bundle.getID()) == 0) {
2123 emitCircuitError() <<
"no companion found with 'id' value '"
2124 << bundle.getID().getValue().getZExtValue() <<
"'\n";
2125 removalError =
true;
2131 auto companionIter = companionIDMap.lookup(bundle.getID());
2132 auto companionModule = companionIter.companion;
2133 auto symbolName = getNamespace().newName(
2134 "__" + companionIDMap.lookup(bundle.getID()).name +
"_" +
2135 getInterfaceName(bundle.getPrefix(), bundle) +
"__");
2141 auto instanceSymbol =
2144 VerbatimBuilder::Base verbatimData;
2145 VerbatimBuilder verbatim(verbatimData);
2146 verbatim += instanceSymbol;
2149 SmallVector<VerbatimXMRbuilder> xmrElems;
2150 SmallVector<InterfaceElemsBuilder> interfaceBuilder;
2152 auto ifaceName = traverseBundle(bundle, bundle.getID(), bundle.getPrefix(),
2153 verbatim, xmrElems, interfaceBuilder);
2155 removalError =
true;
2159 if (companionIter.isNonlocal) {
2163 auto viewMapIter = companionToInterfaceMap.find(companionModule);
2164 if (viewMapIter != companionToInterfaceMap.end())
2165 if (std::equal(interfaceBuilder.begin(), interfaceBuilder.end(),
2166 viewMapIter->getSecond().begin(),
2167 compareInterfaceSignal)) {
2171 companionToInterfaceMap[companionModule] = interfaceBuilder;
2174 if (interfaceBuilder.empty())
2176 auto companionBuilder =
2177 OpBuilder::atBlockEnd(companionModule.getBodyBlock());
2180 for (
auto xmrElem : xmrElems) {
2181 auto uloc = companionBuilder.getUnknownLoc();
2182 companionBuilder.create<sv::VerbatimOp>(uloc, xmrElem.str, xmrElem.val,
2185 numXMRs += xmrElems.size();
2187 sv::InterfaceOp topIface;
2188 for (
const auto &ifaceBuilder : interfaceBuilder) {
2189 auto builder = OpBuilder::atBlockEnd(getOperation().getBodyBlock());
2190 auto loc = getOperation().getLoc();
2191 sv::InterfaceOp iface =
2192 builder.create<sv::InterfaceOp>(loc, ifaceBuilder.iFaceName);
2198 companionIDMap[ifaceBuilder.id].companion, dut) &&
2200 iface->setAttr(
"output_file",
2201 hw::OutputFileAttr::getAsDirectory(
2202 &getContext(), testbenchDir.getValue(),
2204 else if (maybeExtractInfo)
2205 iface->setAttr(
"output_file",
2206 hw::OutputFileAttr::getAsDirectory(
2207 &getContext(), getOutputDirectory().getValue(),
2209 iface.setCommentAttr(
builder.getStringAttr(
"VCS coverage exclude_file"));
2210 builder.setInsertionPointToEnd(
2211 cast<sv::InterfaceOp>(iface).getBodyBlock());
2213 ifaceBuilder.iFaceName)] = iface;
2214 for (
auto elem : ifaceBuilder.elementsList) {
2216 auto uloc =
builder.getUnknownLoc();
2218 auto description = elem.description;
2221 auto descriptionOp =
builder.create<sv::VerbatimOp>(
2222 uloc, (
"// " + cleanupDescription(description.getValue())));
2227 if (maybeHierarchyFileYAML)
2228 descriptionOp->setAttr(
"firrtl.grandcentral.yaml.type",
2229 builder.getStringAttr(
"description"));
2231 if (
auto *str = std::get_if<VerbatimType>(&elem.elemType)) {
2232 auto instanceOp =
builder.create<sv::VerbatimOp>(
2233 uloc, str->toStr(elem.elemName.getValue()));
2237 if (maybeHierarchyFileYAML) {
2238 if (str->instantiation)
2239 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2240 builder.getStringAttr(
"instance"));
2242 instanceOp->setAttr(
"firrtl.grandcentral.yaml.type",
2243 builder.getStringAttr(
"unsupported"));
2244 instanceOp->setAttr(
"firrtl.grandcentral.yaml.name", elem.elemName);
2245 instanceOp->setAttr(
"firrtl.grandcentral.yaml.dimensions",
2246 builder.getI32ArrayAttr(str->dimensions));
2247 instanceOp->setAttr(
2248 "firrtl.grandcentral.yaml.symbol",
2254 auto tpe = std::get<Type>(elem.elemType);
2255 builder.create<sv::InterfaceSignalOp>(uloc, elem.elemName.getValue(),
2262 interfaceVec.push_back(topIface);
2265 builder.setInsertionPointToStart(companionModule.getBodyBlock());
2266 builder.create<sv::InterfaceInstanceOp>(
2267 getOperation().getLoc(), topIface.getInterfaceType(),
2268 companionIDMap.lookup(bundle.getID()).name,
2273 if (!maybeExtractInfo)
2279 companionIDMap[bundle.getID()].companion, dut))
2283 emitHierarchyYamlFile(interfaceVec);
2288 return signalPassFailure();
2289 markAnalysesPreserved<NLATable>();
2292 void GrandCentralPass::emitHierarchyYamlFile(
2293 SmallVectorImpl<sv::InterfaceOp> &intfs) {
2297 if (!maybeHierarchyFileYAML)
2300 CircuitOp circuitOp = getOperation();
2302 std::string yamlString;
2303 llvm::raw_string_ostream stream(yamlString);
2304 ::yaml::Context yamlContext({interfaceMap});
2306 yamlize(yout, intfs,
true, yamlContext);
2308 auto builder = OpBuilder::atBlockBegin(circuitOp.getBodyBlock());
2309 builder.create<sv::VerbatimOp>(
builder.getUnknownLoc(), yamlString)
2310 ->setAttr(
"output_file",
2311 hw::OutputFileAttr::getFromFilename(
2312 &getContext(), maybeHierarchyFileYAML->getValue(),
2314 LLVM_DEBUG({
llvm::dbgs() <<
"Generated YAML:" << yamlString <<
"\n"; });
2321 std::unique_ptr<mlir::Pass>
2323 auto pass = std::make_unique<GrandCentralPass>();
2324 pass->companionMode = companionMode;
assert(baseType &&"element must be base type")
#define UNIMPLEMENTED_DENORM(clazz)
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...
#define UNIMPLEMENTED_DEFAULT(clazz)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
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.
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.
auto getModule()
Get the module that this node is tracking.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
bool isAncestor(ModuleOpInterface child, ModuleOpInterface parent)
Check if child is instantiated by a parent.
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
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 dimnensionality of the interface.
static void mapping(IO &io, DescribedInstance &op, Context &ctx)
DescribedSignal denormalize(IO &)
This cannot be denomralized 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 denomralized 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)