[FIRRTL] Support MarkDUTAnnotation on extmodules. (#8001)

In some cases, the "DUT" might be an extmodule from a separate
compilation unit, and we still want all the old legacy "is DUT" logic
to work. To support this, we need applyDUTAnno to allow the annotation
to be applied to an extmodule, and we need extractDUT and its users to
work with FModuleLikes instead of FModuleOp. The only other thing that
appears to be using this "is DUT" logic is the newer InstanceInfo
helper, which already works with igraph::ModuleOpInterfaces and seems
to work fine with extmodules as the "DUT".
This commit is contained in:
Mike Urbach 2024-12-17 13:11:34 -07:00 committed by GitHub
parent 50e3f9faff
commit 9775df2cb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 75 additions and 8 deletions

View File

@ -448,7 +448,7 @@ struct PortAnnoTarget : public AnnoTarget {
/// found or if the DUT was found and a previous DUT was not set (if `dut` is
/// null). This returns failure if a DUT was found and a previous DUT was set.
/// This function generates an error message in the failure case.
LogicalResult extractDUT(FModuleOp mod, FModuleOp &dut);
LogicalResult extractDUT(FModuleLike mod, FModuleLike &dut);
} // namespace firrtl
} // namespace circt

View File

@ -564,7 +564,8 @@ FIRRTLType PortAnnoTarget::getType() const {
// TODO: Remove these in favor of first-class annotations.
//===----------------------------------------------------------------------===//
LogicalResult circt::firrtl::extractDUT(const FModuleOp mod, FModuleOp &dut) {
LogicalResult circt::firrtl::extractDUT(const FModuleLike mod,
FModuleLike &dut) {
if (!AnnotationSet(mod).hasAnnotation(dutAnnoClass))
return success();

View File

@ -104,7 +104,7 @@ private:
/// The design-under-test (DUT) as indicated by the presence of a
/// "sifive.enterprise.firrtl.MarkDUTAnnotation". This will be null if no
/// annotation is present.
FModuleOp dut;
FModuleLike dut;
/// The file list file name (sic) for black boxes. If set, generates a file
/// that lists all non-header source files for black boxes. Can be changed
@ -207,7 +207,7 @@ void BlackBoxReaderPass::runOnOperation() {
// Do a shallow walk of the circuit to collect information necessary before we
// do real work.
for (auto &op : *circuitOp.getBodyBlock()) {
FModuleOp module = dyn_cast<FModuleOp>(op);
FModuleLike module = dyn_cast<FModuleLike>(op);
// Find the DUT if it exists or error if there are multiple DUTs.
if (module)
if (failed(extractDUT(module, dut)))

View File

@ -613,7 +613,7 @@ private:
/// The design-under-test (DUT) as determined by the presence of a
/// "sifive.enterprise.firrtl.MarkDUTAnnotation". This will be null if no DUT
/// was found.
FModuleOp dut;
FModuleLike dut;
/// An optional directory for testbench-related files. This is null if no
/// "TestBenchDirAnnotation" is found.
@ -1577,7 +1577,7 @@ void GrandCentralPass::runOnOperation() {
// Find the DUT if it exists. This needs to be known before the circuit is
// walked.
for (auto mod : circuitOp.getOps<FModuleOp>()) {
for (auto mod : circuitOp.getOps<FModuleLike>()) {
if (failed(extractDUT(mod, dut)))
removalError = true;
}

View File

@ -246,10 +246,10 @@ static LogicalResult applyDUTAnno(const AnnoPathValue &target,
if (!target.isLocal())
return mlir::emitError(loc) << "must be local";
if (!isa<OpAnnoTarget>(target.ref) || !isa<FModuleOp>(op))
if (!isa<OpAnnoTarget>(target.ref) || !isa<FModuleLike>(op))
return mlir::emitError(loc) << "can only target to a module";
auto moduleOp = cast<FModuleOp>(op);
auto moduleOp = cast<FModuleLike>(op);
// DUT has public visibility.
moduleOp.setPublic();

View File

@ -487,3 +487,40 @@ firrtl.circuit "Foo" {
firrtl.instance a {lowerToBind} @Foo_A()
}
}
// -----
// Test that the DUT can be an extmodule
// CHECK: - operation: firrtl.circuit "Testharness"
// CHECK-NEXT: hasDut: true
// CHECK-NEXT: dut: firrtl.extmodule private @DUT
// CHECK-NEXT: effectiveDut: firrtl.extmodule private @DUT
firrtl.circuit "Testharness" {
// CHECK: - operation: firrtl.module @Testharness
// CHECK-NEXT: isDut: false
// CHECK-NEXT: anyInstanceUnderDut: false
// CHECK-NEXT: allInstancesUnderDut: false
firrtl.module @Testharness() {
firrtl.instance dut @DUT()
firrtl.instance foo @Foo()
}
// CHECK: - operation: firrtl.extmodule private @DUT
// CHECK-NEXT: isDut: true
// CHECK-NEXT: anyInstanceUnderDut: true
// CHECK-NEXT: allInstancesUnderDut: true
firrtl.extmodule private @DUT() attributes {
annotations = [
{
class = "sifive.enterprise.firrtl.MarkDUTAnnotation"
}
]
}
// CHECK: - operation: firrtl.module private @Foo
// CHECK-NEXT: isDut: false
// CHECK-NEXT: anyInstanceUnderDut: false
// CHECK-NEXT: allInstancesUnderDut: false
firrtl.module private @Foo() {
}
}

29
test/firtool/mark-dut.fir Normal file
View File

@ -0,0 +1,29 @@
; RUN: firtool %s -ir-verilog | FileCheck %s
FIRRTL version 4.1.0
; COM: Check that we can even target an extmodule.
circuit Test : %[[
{
"class": "sifive.enterprise.firrtl.MarkDUTAnnotation",
"target": "~Test|DUT"
}
]]
; CHECK: hw.hierpath private [[DUT_NLA:@.+]] [@Test::[[DUT_SYM:@.+]]]
public module Test :
input in : UInt<1>
output out : UInt<1>
; CHECK: hw.instance "dut" sym [[DUT_SYM]]
inst dut of DUT
connect dut.in, in
connect out, dut.out
extmodule DUT :
input in : UInt<1>
output out : UInt<1>
; COM: Check that metadata includes the dutModulePath pointing to Test::dut.
; CHECK: om.class @SiFive_Metadata(%basepath: !om.basepath) -> (dutModulePath
; CHECK-NEXT: om.path_create instance %basepath [[DUT_NLA]]