Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions include/circt/Dialect/HW/HWStructure.td
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,17 @@ def HWModuleExternOp : HWModuleOpBase<"module.extern"> {
module name in Verilog we can use. TODO: This is a hack because we don't
have proper parameterization in the hw.dialect. We need a way to represent
parameterized types instead of just concrete types.

The 'files' attribute (when present) contains references to emit.file
ops that provide the implementation for this external module.
}];
let arguments = (ins SymbolNameAttr:$sym_name,
TypeAttrOf<ModuleType>:$module_type,
OptionalAttr<DictArrayAttr>:$per_port_attrs,
OptionalAttr<LocationArrayAttr>:$port_locs,
ParamDeclArrayAttr:$parameters,
OptionalAttr<StrAttr>:$verilogName);
OptionalAttr<StrAttr>:$verilogName,
OptionalAttr<FlatSymbolRefArrayAttr>:$files);
let results = (outs);
let regions = (region AnyRegion:$body);

Expand All @@ -266,7 +270,12 @@ def HWModuleExternOp : HWModuleOpBase<"module.extern"> {
OpBuilder<(ins "StringAttr":$name, "const ModulePortInfo &":$ports,
CArg<"StringRef", "StringRef()">:$verilogName,
CArg<"ArrayAttr", "{}">:$parameters,
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes)>,
OpBuilder<(ins "StringAttr":$name, "const ModulePortInfo &":$ports,
CArg<"StringRef", "StringRef()">:$verilogName,
CArg<"ArrayAttr", "{}">:$parameters,
CArg<"ArrayRef<NamedAttribute>", "{}">:$attributes,
CArg<"ArrayAttr", "{}">:$files)>
];

let extraModuleClassDeclaration = [{
Expand Down
21 changes: 17 additions & 4 deletions lib/Conversion/FIRRTLToHW/LowerToHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -850,8 +850,7 @@ void FIRRTLModuleLowering::lowerFileHeader(CircuitOp op,

// Helper function to emit #ifndef guard.
auto emitGuard = [&](const char *guard, llvm::function_ref<void(void)> body) {
sv::IfDefOp::create(
b, guard, [] {}, body);
sv::IfDefOp::create(b, guard, [] {}, body);
};

if (state.usedFileDescriptorLib) {
Expand Down Expand Up @@ -1178,6 +1177,21 @@ FIRRTLModuleLowering::lowerExtModule(FExtModuleOp oldModule,
if (handleForceNameAnnos(oldModule, annos, loweringState))
return {};

ArrayAttr files;
annos.removeAnnotations([&](Annotation anno) {
if (anno.isClass("circt.ModuleExternFilesAnno")) {
if (auto fileRefs = anno.getMember<ArrayAttr>("files")) {
files = fileRefs;
}
return true;
}
return false;
});

if (files) {
newModule->setAttr("files", files);
}

loweringState.processRemainingAnnotations(oldModule, annos);
return newModule;
}
Expand Down Expand Up @@ -2895,8 +2909,7 @@ void FIRRTLLowering::addToAlwaysBlock(
auto createIfOp = [&]() {
// It is weird but intended. Here we want to create an empty sv.if
// with an else block.
insideIfOp = sv::IfOp::create(
builder, reset, [] {}, [] {});
insideIfOp = sv::IfOp::create(builder, reset, [] {}, [] {});
};
if (resetStyle == sv::ResetType::AsyncReset) {
sv::EventControl events[] = {clockEdge, resetEdge};
Expand Down
27 changes: 27 additions & 0 deletions lib/Dialect/FIRRTL/Transforms/BlackBoxReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ struct AnnotationInfo {
hw::OutputFileAttr outputFileAttr;
/// The body of the BlackBox. (This should be Verilog text.)
StringAttr inlineText;
/// The extmodule operation.
Operation *extmodule;

#if !defined(NDEBUG)
/// Pretty print the AnnotationInfo in a YAML-esque format.
Expand Down Expand Up @@ -117,6 +119,9 @@ struct BlackBoxReaderPass
/// written to the DUT directory and not the TestHarness directory), then this
/// will map will be updated.
llvm::MapVector<StringAttr, AnnotationInfo> emittedFileMap;

/// A map from extmodule operations to emit.file ops that implement them.
DenseMap<Operation *, SmallVector<emit::FileOp>> moduleToFilesMap;
};
} // end anonymous namespace

Expand Down Expand Up @@ -197,6 +202,7 @@ void BlackBoxReaderPass::runOnOperation() {
bool foundBBoxAnno = false;
annotations.removeAnnotations([&](Annotation anno) {
AnnotationInfo annotationInfo;
annotationInfo.extmodule = extmoduleOp;
if (!runOnAnnotation(extmoduleOp, anno, builder, isCover, annotationInfo))
return false;

Expand Down Expand Up @@ -251,6 +257,10 @@ void BlackBoxReaderPass::runOnOperation() {
emit::VerbatimOp::create(builder, loc, text);
});

if (annotationInfo.extmodule) {
moduleToFilesMap[annotationInfo.extmodule].push_back(fileOp);
}

if (!annotationInfo.outputFileAttr.getExcludeFromFilelist().getValue())
fileListFiles.push_back(fileOp);
}
Expand All @@ -271,6 +281,22 @@ void BlackBoxReaderPass::runOnOperation() {
symbols.push_back(FlatSymbolRefAttr::get(file.getSymNameAttr()));
}

for (auto &[extmodule, fileOps] : moduleToFilesMap) {
SmallVector<Attribute> fileRefs;
for (auto fileOp : fileOps) {
fileRefs.push_back(FlatSymbolRefAttr::get(fileOp.getSymNameAttr()));
}
if (!fileRefs.empty()) {
auto inlineFilesAttr = builder.getArrayAttr(fileRefs);
AnnotationSet annotations(extmodule);
annotations.addAnnotations({builder.getDictionaryAttr(
{{builder.getStringAttr("class"),
builder.getStringAttr("circt.ModuleExternFilesAnno")},
{builder.getStringAttr("files"), inlineFilesAttr}})});
annotations.applyToOperation(extmodule);
}
}

// If nothing has changed we can preserve the analysis.
if (!anythingChanged)
markAllAnalysesPreserved();
Expand All @@ -279,6 +305,7 @@ void BlackBoxReaderPass::runOnOperation() {
// Clean up.
emittedFileMap.clear();
fileListFiles.clear();
moduleToFilesMap.clear();
}

/// Run on an operation-annotation pair. The annotation need not be a black box
Expand Down
20 changes: 12 additions & 8 deletions lib/Dialect/HW/HWOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,9 +823,18 @@ StringAttr HWModuleGeneratedOp::getVerilogModuleNameAttr() {
}

void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
StringAttr name, const ModulePortInfo &ports,
StringAttr name, ArrayRef<PortInfo> ports,
StringRef verilogName, ArrayAttr parameters,
ArrayRef<NamedAttribute> attributes) {
build(builder, result, name, ModulePortInfo(ports), verilogName, parameters,
attributes);
}

void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
StringAttr name, const ModulePortInfo &ports,
StringRef verilogName, ArrayAttr parameters,
ArrayRef<NamedAttribute> attributes,
ArrayAttr files) {
buildModule<HWModuleExternOp>(builder, result, name, ports, parameters,
attributes, {});

Expand All @@ -838,14 +847,9 @@ void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,

if (!verilogName.empty())
result.addAttribute("verilogName", builder.getStringAttr(verilogName));
}

void HWModuleExternOp::build(OpBuilder &builder, OperationState &result,
StringAttr name, ArrayRef<PortInfo> ports,
StringRef verilogName, ArrayAttr parameters,
ArrayRef<NamedAttribute> attributes) {
build(builder, result, name, ModulePortInfo(ports), verilogName, parameters,
attributes);
if (files)
result.addAttribute("files", files);
}

void HWModuleExternOp::modifyPorts(
Expand Down
22 changes: 22 additions & 0 deletions test/Conversion/FIRRTLToHW/lower-to-hw.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -1900,3 +1900,25 @@ firrtl.circuit "Foo" {
dbg.variable "d", %d : !firrtl.uint<1337>
}
}

// -----

// Test that circt.ModuleExternFilesAnno is properly converted to files attribute
firrtl.circuit "InlineFilesConversion" {
// CHECK-LABEL: hw.module.extern @ExtWithInlineFiles()
// CHECK-SAME: files = [@file1, @file2]
firrtl.extmodule @ExtWithInlineFiles() attributes {annotations = [
{class = "circt.ModuleExternFilesAnno", files = [@file1, @file2]}
]}

// CHECK-LABEL: hw.module.extern @ExtWithoutInlineFiles()
// CHECK-NOT: files
firrtl.extmodule @ExtWithoutInlineFiles() attributes {annotations = [
{class = "firrtl.transforms.BlackBox"}
]}

firrtl.module @InlineFilesConversion() {
firrtl.instance ext1 @ExtWithInlineFiles()
firrtl.instance ext2 @ExtWithoutInlineFiles()
}
}
46 changes: 46 additions & 0 deletions test/Dialect/FIRRTL/blackbox-reader.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// RUN: cd %t
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-blackbox-reader))' Foo.mlir | FileCheck Foo.mlir
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-blackbox-reader))' NoDUT.mlir | FileCheck NoDUT.mlir
// RUN: circt-opt --pass-pipeline='builtin.module(firrtl.circuit(firrtl-blackbox-reader),lower-firrtl-to-hw)' InlineFiles.mlir | FileCheck InlineFiles.mlir

//--- Baz.sv
/* Baz */
Expand All @@ -14,12 +15,18 @@ firrtl.circuit "Foo" attributes {annotations = [
// CHECK-LABEL: firrtl.extmodule @ExtFoo()
// CHECK-NOT: class = "firrtl.transforms.BlackBoxInlineAnno"
// CHECK-SAME: class = "firrtl.transforms.BlackBox"
// CHECK-SAME: class = "circt.ModuleExternFilesAnno"
// CHECK-SAME: files = [@blackbox_hello.v]
firrtl.extmodule @ExtFoo() attributes {annotations = [{class = "firrtl.transforms.BlackBoxInlineAnno", name = "hello.v", text = "// world"}]}
// CHECK-LABEL: firrtl.extmodule @ExtFoo2()
// CHECK-NOT: class = "firrtl.transforms.BlackBoxInlineAnno"
// CHECK-SAME: class = "circt.ModuleExternFilesAnno"
// CHECK-SAME: files = [@blackbox_hello2.v]
firrtl.extmodule @ExtFoo2() attributes {annotations = [{class = "firrtl.transforms.BlackBoxInlineAnno", name = "hello2.v", text = "// world"}, {class = "freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation"}]}
// CHECK-LABEL: firrtl.extmodule @ExtFoo3()
// CHECK-NOT: class = "firrtl.transforms.BlackBoxInlineAnno"
// CHECK-SAME: class = "circt.ModuleExternFilesAnno"
// CHECK-SAME: files = [@blackbox_hello3.v]
firrtl.extmodule @ExtFoo3() attributes {annotations = [{class = "firrtl.transforms.BlackBoxInlineAnno", name = "hello3.v", text = "// world"}, {class = "freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation"}]}
// CHECK-LABEL: firrtl.module @DUTBlackboxes
firrtl.module @DUTBlackboxes() attributes {annotations = [
Expand Down Expand Up @@ -83,3 +90,42 @@ firrtl.circuit "NoDUT" attributes {annotations = [
// CHECK-NEXT: emit.verbatim "module NoDUTBlackBox();\0Aendmodule\0A"
// CHECK-NEXT: }
}

//--- InlineFiles.mlir
// Test that inline files are properly linked to hw.module.extern operations
// after FIRRTL-to-HW lowering.
//
firrtl.circuit "InlineFilesTest" {
// CHECK-LABEL: hw.module.extern @ExtWithInline()
// CHECK-SAME: files = [@blackbox_inline1.v, @blackbox_inline2.sv]
firrtl.extmodule @ExtWithInline() attributes {annotations = [
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "inline1.v", text = "module ExtWithInline(); endmodule"},
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "inline2.sv", text = "// Another file"}
]}

// CHECK-LABEL: hw.module.extern @ExtWithoutInline()
// CHECK-NOT: files
firrtl.extmodule @ExtWithoutInline()

// CHECK-LABEL: hw.module.extern @ExtWithSingleInline()
// CHECK-SAME: files = [@blackbox_single.v]
firrtl.extmodule @ExtWithSingleInline() attributes {annotations = [
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "single.v", text = "// Single inline file"}
]}

firrtl.module @InlineFilesTest() {
firrtl.instance ext1 @ExtWithInline()
firrtl.instance ext2 @ExtWithoutInline()
firrtl.instance ext3 @ExtWithSingleInline()
}

// CHECK: emit.file ".{{/|\\\\}}inline1.v" sym @blackbox_inline1.v {
// CHECK-NEXT: emit.verbatim "module ExtWithInline(); endmodule"
// CHECK-NEXT: }
// CHECK: emit.file ".{{/|\\\\}}inline2.sv" sym @blackbox_inline2.sv {
// CHECK-NEXT: emit.verbatim "// Another file"
// CHECK-NEXT: }
// CHECK: emit.file ".{{/|\\\\}}single.v" sym @blackbox_single.v {
// CHECK-NEXT: emit.verbatim "// Single inline file"
// CHECK-NEXT: }
}
41 changes: 41 additions & 0 deletions test/firtool/blackbox-inline-files.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Test that inline files are properly linked to hw.module.extern operations
// RUN: firtool %s --ir-hw | FileCheck %s

firrtl.circuit "InlineFilesTest" {
// CHECK-LABEL: hw.module.extern @ExtWithMultipleInlines()
// CHECK-SAME: files = [@blackbox_inline1.v, @blackbox_inline2.sv]
firrtl.extmodule @ExtWithMultipleInlines() attributes {annotations = [
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "inline1.v", text = "module ExtWithMultipleInlines(); endmodule"},
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "inline2.sv", text = "// Another inline file"}
]}

// CHECK-LABEL: hw.module.extern @ExtWithSingleInline()
// CHECK-SAME: files = [@blackbox_single.v]
firrtl.extmodule @ExtWithSingleInline() attributes {annotations = [
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "single.v", text = "// Single inline file"}
]}

// CHECK-LABEL: hw.module.extern @ExtWithPathOnly()
// CHECK-NOT: files
firrtl.extmodule @ExtWithPathOnly()

// CHECK-LABEL: hw.module.extern @ExtWithMixedAnnotations()
// CHECK-SAME: files = [@blackbox_mixed.v]
firrtl.extmodule @ExtWithMixedAnnotations() attributes {annotations = [
{class = "firrtl.transforms.BlackBoxInlineAnno", name = "mixed.v", text = "// Mixed annotations"},
{class = "freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation"}
]}

firrtl.module @InlineFilesTest() {
firrtl.instance ext1 @ExtWithMultipleInlines()
firrtl.instance ext2 @ExtWithSingleInline()
firrtl.instance ext3 @ExtWithPathOnly()
firrtl.instance ext4 @ExtWithMixedAnnotations()
}

// Verify that emit.file operations are created with the correct symbols
// CHECK: emit.file ".{{/|\\\\}}inline1.v" sym @blackbox_inline1.v
// CHECK: emit.file ".{{/|\\\\}}inline2.sv" sym @blackbox_inline2.sv
// CHECK: emit.file ".{{/|\\\\}}single.v" sym @blackbox_single.v
// CHECK: emit.file ".{{/|\\\\}}mixed.v" sym @blackbox_mixed.v
}
Loading