diff --git a/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md b/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md index fed8a58c0b44..8f6c3d19de35 100644 --- a/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md +++ b/docs/Dialects/FIRRTL/FIRRTLIntrinsics.md @@ -298,10 +298,11 @@ This will become a SystemVerilog Interface that is driven by its arguments. This is _not_ a true SystemVerilog Interface, it is only lowered to one. -| Parameter | Type | Description | -| --------- | ------ | --------------------------------- | -| name | string | Instance name of the view. | -| info | string | JSON encoding the view structure. | +| Parameter | Type | Description | +| --------- | ------ | --------------------------------------- | +| name | string | Instance name of the view. | +| info | string | JSON encoding the view structure. | +| yaml | string | Optional path to emit YAML description. | | Argument | Type | Description | | -------- | ------ | ------------------------------- | diff --git a/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.td b/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.td index 84196b3d6438..da71f5169055 100644 --- a/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.td +++ b/include/circt/Dialect/FIRRTL/FIRRTLIntrinsics.td @@ -239,8 +239,8 @@ def ViewIntrinsicOp : FIRRTLOp<"view", []> { debugging in a waveform. This is _not_ a true SystemVerilog Interface, it is only lowered to one. }]; - let arguments = (ins StrAttr:$name, AugmentedBundleType:$augmentedType, Variadic:$inputs); - let assemblyFormat = "$name `,` $augmentedType (`,` $inputs^)? attr-dict (`:` type($inputs)^)?"; + let arguments = (ins StrAttr:$name, OptionalAttr:$yamlFile, AugmentedBundleType:$augmentedType, Variadic:$inputs); + let assemblyFormat = "$name `,` (`yaml` $yamlFile^ `,`)? $augmentedType (`,` $inputs^)? attr-dict (`:` type($inputs)^)?"; } #endif // CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_TD diff --git a/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp b/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp index b396ee9bb573..1d692509fa9a 100644 --- a/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp +++ b/lib/Dialect/FIRRTL/FIRRTLIntrinsics.cpp @@ -869,7 +869,8 @@ class ViewConverter : public IntrinsicConverter { GenericIntrinsicOpAdaptor adaptor, PatternRewriter &rewriter) override { // Check structure of the intrinsic. - if (gi.hasNoOutput() || gi.namedParam("info") || gi.namedParam("name")) + if (gi.hasNoOutput() || gi.namedParam("info") || gi.namedParam("name") || + gi.namedParam("yaml", true)) return failure(); // Check operands. @@ -944,9 +945,9 @@ class ViewConverter : public IntrinsicConverter { << numLeaves << " leaf elements"; // Check complete, convert! - + auto yaml = gi.getParamValue("yaml"); rewriter.replaceOpWithNewOp( - gi.op, nameAttr.getValue(), augmentedType, adaptor.getOperands()); + gi.op, nameAttr.getValue(), yaml, augmentedType, adaptor.getOperands()); return success(); } }; diff --git a/lib/Dialect/FIRRTL/Transforms/GrandCentral.cpp b/lib/Dialect/FIRRTL/Transforms/GrandCentral.cpp index 266fa9a90d81..cdbfad9ddf10 100644 --- a/lib/Dialect/FIRRTL/Transforms/GrandCentral.cpp +++ b/lib/Dialect/FIRRTL/Transforms/GrandCentral.cpp @@ -773,7 +773,8 @@ struct GrandCentralPass DenseMap interfaceMap; /// Emit the hierarchy yaml file. - void emitHierarchyYamlFile(SmallVectorImpl &intfs); + void emitHierarchyYamlFile(StringRef yamlPath, + SmallVectorImpl &intfs); }; } // namespace @@ -1915,6 +1916,12 @@ void GrandCentralPass::runOnOperation() { llvm::dbgs() << "\n"; }); + // per-YAML output list of interfaces. + llvm::SmallMapVector, 1> + interfaceYAMLMap; + if (maybeHierarchyFileYAML.has_value()) + interfaceYAMLMap[maybeHierarchyFileYAML.value()] = {}; + // Scan entire design for View operations. SmallVector views; circuitOp.walk([&views](ViewIntrinsicOp view) { views.push_back(view); }); @@ -1923,8 +1930,8 @@ void GrandCentralPass::runOnOperation() { // built exist. However, still generate the YAML file if the annotation for // this was passed in because some flows expect this. if (worklist.empty() && views.empty()) { - SmallVector interfaceVec; - emitHierarchyYamlFile(interfaceVec); + for (auto &[yamlPath, intfs] : interfaceYAMLMap) + emitHierarchyYamlFile(yamlPath.getValue(), intfs); return markAllAnalysesPreserved(); } @@ -2254,8 +2261,8 @@ void GrandCentralPass::runOnOperation() { mod->erase(); } - SmallVector interfaceVec; - emitHierarchyYamlFile(interfaceVec); + for (auto &[yamlPath, intfs] : interfaceYAMLMap) + emitHierarchyYamlFile(yamlPath.getValue(), intfs); return; } @@ -2311,7 +2318,6 @@ void GrandCentralPass::runOnOperation() { // will use XMRs to drive the interface. If extraction info is available, // then the top-level instantiate interface will be marked for extraction via // a SystemVerilog bind. - SmallVector interfaceVec; SmallDenseMap> companionToInterfaceMap; auto compareInterfaceSignal = [&](InterfaceElemsBuilder &lhs, @@ -2481,7 +2487,8 @@ void GrandCentralPass::runOnOperation() { ++numViews; - interfaceVec.push_back(topIface); + if (maybeHierarchyFileYAML.has_value()) + interfaceYAMLMap[maybeHierarchyFileYAML.value()].push_back(topIface); // Instantiate the interface inside the companion. builder.setInsertionPointToStart(companionModule.getBodyBlock()); @@ -2567,6 +2574,7 @@ void GrandCentralPass::runOnOperation() { sv::InterfaceOp topIface; auto containingOutputFileAttr = viewParentMod->getAttrOfType("output_file"); + auto yamlPath = view.getYamlFileAttr(); for (const auto &ifaceBuilder : interfaceBuilder) { auto builder = OpBuilder::atBlockEnd(getOperation().getBodyBlock()); auto loc = getOperation().getLoc(); @@ -2599,7 +2607,7 @@ void GrandCentralPass::runOnOperation() { // If we need to generate a YAML representation of this interface, // then add an attribute indicating that this `sv::VerbatimOp` is // actually a description. - if (maybeHierarchyFileYAML) + if (yamlPath) descriptionOp->setAttr("firrtl.grandcentral.yaml.type", builder.getStringAttr("description")); } @@ -2609,7 +2617,7 @@ void GrandCentralPass::runOnOperation() { // If we need to generate a YAML representation of the interface, then // add attributes that describe what this `sv::VerbatimOp` is. - if (maybeHierarchyFileYAML) { + if (yamlPath) { if (str->instantiation) instanceOp->setAttr("firrtl.grandcentral.yaml.type", builder.getStringAttr("instance")); @@ -2634,7 +2642,8 @@ void GrandCentralPass::runOnOperation() { ++numViews; - interfaceVec.push_back(topIface); + if (yamlPath) + interfaceYAMLMap[yamlPath].push_back(topIface); // Instantiate the interface before the view and the XMR's we inserted // above. @@ -2646,7 +2655,8 @@ void GrandCentralPass::runOnOperation() { view.erase(); } - emitHierarchyYamlFile(interfaceVec); + for (auto &[yamlPath, intfs] : interfaceYAMLMap) + emitHierarchyYamlFile(yamlPath.getValue(), intfs); // Signal pass failure if any errors were found while examining circuit // annotations. @@ -2656,13 +2666,7 @@ void GrandCentralPass::runOnOperation() { } void GrandCentralPass::emitHierarchyYamlFile( - SmallVectorImpl &intfs) { - // If a `GrandCentralHierarchyFileAnnotation` was passed in, generate a YAML - // representation of the interfaces that we produced with the filename that - // that annotation provided. - if (!maybeHierarchyFileYAML) - return; - + StringRef yamlPath, SmallVectorImpl &intfs) { CircuitOp circuitOp = getOperation(); std::string yamlString; @@ -2673,10 +2677,9 @@ void GrandCentralPass::emitHierarchyYamlFile( auto builder = OpBuilder::atBlockBegin(circuitOp.getBodyBlock()); builder.create(builder.getUnknownLoc(), yamlString) - ->setAttr("output_file", - hw::OutputFileAttr::getFromFilename( - &getContext(), maybeHierarchyFileYAML->getValue(), - /*excludeFromFileList=*/true)); + ->setAttr("output_file", hw::OutputFileAttr::getFromFilename( + &getContext(), yamlPath, + /*excludeFromFileList=*/true)); LLVM_DEBUG({ llvm::dbgs() << "Generated YAML:" << yamlString << "\n"; }); } diff --git a/test/Dialect/FIRRTL/grand-central-view.mlir b/test/Dialect/FIRRTL/grand-central-view.mlir index 0fa56e6138d7..32d6efbd7379 100644 --- a/test/Dialect/FIRRTL/grand-central-view.mlir +++ b/test/Dialect/FIRRTL/grand-central-view.mlir @@ -4,19 +4,7 @@ // types. All the interfaces share a common, simple circuit that provides two // signals, "foo" and "bar". -firrtl.circuit "InterfaceGroundType" attributes { - annotations = [ - { - class = "sifive.enterprise.grandcentral.ExtractGrandCentralAnnotation", - directory = "gct-dir", - filename = "bindings.sv" - }, - { - class = "sifive.enterprise.grandcentral.GrandCentralHierarchyFileAnnotation", - filename = "gct.yaml" - } - ] -} { +firrtl.circuit "InterfaceGroundType" { firrtl.module @Companion() { // These are dummy references created for the purposes of the test. %_ui0 = firrtl.verbatim.expr "???" : () -> !firrtl.uint<0> @@ -38,7 +26,7 @@ firrtl.circuit "InterfaceGroundType" attributes { %c0_ui1 = firrtl.constant 0 : !firrtl.uint<1> %c-1_si2 = firrtl.constant -1 : !firrtl.sint<2> - firrtl.view "GroundView", <{ + firrtl.view "GroundView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "GroundView", elements = [ @@ -55,7 +43,7 @@ firrtl.circuit "InterfaceGroundType" attributes { ] }>, %foo, %bar : !firrtl.uint<1>, !firrtl.uint<2> - firrtl.view "VectorView", <{ + firrtl.view "VectorView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "VectorView", elements = [ @@ -77,7 +65,7 @@ firrtl.circuit "InterfaceGroundType" attributes { }>, %foo, %foo : !firrtl.uint<1>, !firrtl.uint<1> - firrtl.view "BundleView", <{ + firrtl.view "BundleView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "BundleView", elements = [ @@ -99,7 +87,7 @@ firrtl.circuit "InterfaceGroundType" attributes { ] }>, %foo, %bar : !firrtl.uint<1>, !firrtl.uint<2> - firrtl.view "VectorOfBundleView", <{ + firrtl.view "VectorOfBundleView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "VectorOfBundleView", elements = [ @@ -127,7 +115,7 @@ firrtl.circuit "InterfaceGroundType" attributes { ] }>, %foo, %bar : !firrtl.uint<1>, !firrtl.uint<2> - firrtl.view "VectorOfVectorView", <{ + firrtl.view "VectorOfVectorView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "VectorOfVectorView", elements = [ @@ -178,7 +166,7 @@ firrtl.circuit "InterfaceGroundType" attributes { ] }>, %bar, %bar, %bar, %bar, %bar, %bar : !firrtl.uint<2>, !firrtl.uint<2>, !firrtl.uint<2>, !firrtl.uint<2>, !firrtl.uint<2>, !firrtl.uint<2> - firrtl.view "ConstantView", <{ + firrtl.view "ConstantView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "ConstantView", elements = [ @@ -194,7 +182,7 @@ firrtl.circuit "InterfaceGroundType" attributes { ] }>, %c0_ui1, %c-1_si2 : !firrtl.uint<1>, !firrtl.sint<2> - firrtl.view "ZeroWidthView", <{ + firrtl.view "ZeroWidthView", yaml "gct.yaml", <{ class = "sifive.enterprise.grandcentral.AugmentedBundleType", defName = "ZeroWidthView", elements = [ @@ -210,13 +198,6 @@ firrtl.circuit "InterfaceGroundType" attributes { } } -// All AugmentedBundleType annotations are removed from the circuit. -// -// CHECK-LABEL: firrtl.circuit "InterfaceGroundType" {{.+}} {annotations = -// CHECK-SAME: class = "sifive.enterprise.grandcentral.ExtractGrandCentralAnnotation" -// CHECK-NOT: class = "sifive.enterprise.grandcentral.AugmentedBundleType" -// CHECK-SAME: { - // Check YAML Output. // // Note: Built-in vector serialization works slightly differently than @@ -420,15 +401,7 @@ firrtl.circuit "InterfaceGroundType" attributes { // ----- -firrtl.circuit "Top" attributes { - annotations = [ - { - class = "sifive.enterprise.grandcentral.ExtractGrandCentralAnnotation", - directory = ".", - filename = "bindings.sv" - } - ] -} { +firrtl.circuit "Top" { firrtl.module private @Companion_w1(in %_gen_uint: !firrtl.uint<1>) { %view_uintrefPort = firrtl.node %_gen_uint : !firrtl.uint<1> firrtl.view "View_w1", <{ @@ -501,19 +474,6 @@ firrtl.circuit "Top" attributes { // ----- -firrtl.circuit "NoInterfaces" attributes { - annotations = [ - {class = "sifive.enterprise.grandcentral.GrandCentralHierarchyFileAnnotation", - filename = "gct.yaml"}]} { - firrtl.module @NoInterfaces() {} -} - -// CHECK-LABEL: module { -// CHECK: sv.verbatim -// CHECK-SAME: [] - -// ----- - firrtl.circuit "SetOutputDir" { firrtl.module @SetOutputDir() attributes {output_file = #hw.output_file<"path/">} { firrtl.view "view", <{ diff --git a/test/Dialect/FIRRTL/lower-intrinsics.mlir b/test/Dialect/FIRRTL/lower-intrinsics.mlir index 3735abc889ba..885be41a2851 100644 --- a/test/Dialect/FIRRTL/lower-intrinsics.mlir +++ b/test/Dialect/FIRRTL/lower-intrinsics.mlir @@ -228,5 +228,9 @@ firrtl.circuit "Foo" { // CHECK-SAME: }>, // Check operands and types. // CHECK-SAME: %4, %3, %2, %1, %0 : !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1>, !firrtl.uint<1> + + firrtl.int.generic "circt_view" : () -> () + + // CHECK: firrtl.view "view2", yaml "views.yml", <{ } } diff --git a/test/firtool/views-directories-yaml.fir b/test/firtool/views-directories-yaml.fir new file mode 100644 index 000000000000..20ee8a19d8f6 --- /dev/null +++ b/test/firtool/views-directories-yaml.fir @@ -0,0 +1,49 @@ +; RUN: firtool %s | FileCheck %s +; RUN: firtool %s | FileCheck %s --check-prefix=YAML + +FIRRTL version 4.2.0 +circuit ViewInLayer: + layer Views, bind, "views/": + layer Other, bind, "other/": + layer A, bind, "other/A/": + layer B, inline: + + public module ViewInLayer: + input x : UInt<1> + input y : UInt<1> + intrinsic(circt_view, x) + + layerblock Views: + intrinsic(circt_view, x) + + layerblock Other: + node n = and(x, y) + layerblock A: + ; TODO: Maybe the YAML path should be relative to governing output directory? + intrinsic(circt_view, n) + layerblock B: + intrinsic(circt_view, n) + +; CHECK-NOT: FILE +; CHECK: module ViewInLayer +; CHECK-NOT: FILE +; CHECK: interface Root + +; CHECK-DAG: FILE "views{{[/\]}}MyView.sv" +; CHECK-DAG: FILE "other{{[/\]}}A{{[/\]}}AView.sv" +; CHECK-DAG: FILE "other{{[/\]}}BView.sv" +; CHECK-DAG: FILE "other{{[/\]}}views.yml" + +; YAML: FILE "other{{[/\]}}views.yml" +; YAML: - name: AView +; YAML-NEXT: fields: +; YAML-NEXT: - name: foo +; YAML-NEXT: dimensions: [ ] +; YAML-NEXT: width: 1 +; YAML-NEXT: instances: [] +; YAML-NEXT: - name: BView +; YAML-NEXT: fields: +; YAML-NEXT: - name: foo +; YAML-NEXT: dimensions: [ ] +; YAML-NEXT: width: 1 +; YAML-NEXT: instances: [] diff --git a/test/firtool/views-directories.fir b/test/firtool/views-directories.fir deleted file mode 100644 index 3dc96555d093..000000000000 --- a/test/firtool/views-directories.fir +++ /dev/null @@ -1,32 +0,0 @@ -; RUN: firtool %s | FileCheck %s - -FIRRTL version 4.2.0 -circuit ViewInLayer: - layer Views, bind, "views/": - layer Other, bind, "other/": - layer A, bind, "other/A/": - layer B, inline: - - public module ViewInLayer: - input x : UInt<1> - input y : UInt<1> - intrinsic(circt_view, x) - - layerblock Views: - intrinsic(circt_view, x) - - layerblock Other: - node n = and(x, y) - layerblock A: - intrinsic(circt_view, n) - layerblock B: - intrinsic(circt_view, n) - -; CHECK-NOT: FILE -; CHECK: module ViewInLayer -; CHECK-NOT: FILE -; CHECK: interface Root - -; CHECK-DAG: FILE "views{{[/\]}}MyView.sv" -; CHECK-DAG: FILE "other{{[/\]}}A{{[/\]}}AView.sv" -; CHECK-DAG: FILE "other{{[/\]}}BView.sv"