mirror of https://github.com/llvm/circt.git
Support a generalized freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation in ExtractTestCode (#1956)
Covert freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation annotations to a generalized set of annotations that works not just for cover, but assert and assume extraction too. Process those annotations in ExtractTestCode.
This commit is contained in:
parent
061a0f300f
commit
e6cde1f094
|
@ -926,3 +926,8 @@ modules' bind file. This attribute has type OutputFileAttr.
|
|||
|
||||
Used by SVExtractTestCode. Specifies the output file for extracted
|
||||
modules' bind file. This attribute has type OutputFileAttr.
|
||||
|
||||
### firrtl.extract.[cover|assume|assert].extra
|
||||
|
||||
Used by SVExtractTestCode. Indicates a module whose instances should be
|
||||
extracted from the circuit in the indicated extraction type.
|
||||
|
|
|
@ -180,6 +180,7 @@ public:
|
|||
/// removed, false otherwise.
|
||||
bool removeAnnotation(Annotation anno);
|
||||
bool removeAnnotation(Attribute anno);
|
||||
bool removeAnnotation(StringRef className);
|
||||
|
||||
/// Remove all annotations from this annotation set for which `predicate`
|
||||
/// returns true. The predicate is guaranteed to be called on every
|
||||
|
|
|
@ -41,9 +41,11 @@ static const char assumeAnnoClass[] =
|
|||
static const char coverAnnoClass[] =
|
||||
"sifive.enterprise.firrtl.ExtractCoverageAnnotation";
|
||||
static const char dutAnnoClass[] = "sifive.enterprise.firrtl.MarkDUTAnnotation";
|
||||
static const char verifBBClass[] =
|
||||
"freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation";
|
||||
|
||||
/// Attribute that indicates that the module hierarchy starting at the annotated
|
||||
/// module should be dumped to a file.
|
||||
/// Attribute that indicates that the module hierarchy starting at the
|
||||
/// annotated module should be dumped to a file.
|
||||
static const char moduleHierarchyFileAttrName[] = "firrtl.moduleHierarchyFile";
|
||||
|
||||
/// Attribute that indicates where some json files should be dumped.
|
||||
|
@ -872,8 +874,6 @@ FIRRTLModuleLowering::lowerExtModule(FExtModuleOp oldModule,
|
|||
if (auto defName = oldModule.defname())
|
||||
verilogName = defName.getValue();
|
||||
|
||||
loweringState.processRemainingAnnotations(oldModule,
|
||||
AnnotationSet(oldModule));
|
||||
// Build the new hw.module op.
|
||||
auto builder = OpBuilder::atBlockEnd(topLevelModule);
|
||||
auto nameAttr = builder.getStringAttr(oldModule.getName());
|
||||
|
@ -881,8 +881,14 @@ FIRRTLModuleLowering::lowerExtModule(FExtModuleOp oldModule,
|
|||
// no known default values in the extmodule. This ensures that the
|
||||
// hw.instance will print all the parameters when generating verilog.
|
||||
auto parameters = getHWParameters(oldModule, /*ignoreValues=*/true);
|
||||
return builder.create<hw::HWModuleExternOp>(oldModule.getLoc(), nameAttr,
|
||||
ports, verilogName, parameters);
|
||||
auto newModule = builder.create<hw::HWModuleExternOp>(
|
||||
oldModule.getLoc(), nameAttr, ports, verilogName, parameters);
|
||||
// Transform module annotations
|
||||
AnnotationSet annos(oldModule);
|
||||
if (annos.removeAnnotation(verifBBClass))
|
||||
newModule->setAttr("firrtl.extract.cover.extra", builder.getUnitAttr());
|
||||
loweringState.processRemainingAnnotations(oldModule, annos);
|
||||
return newModule;
|
||||
}
|
||||
|
||||
/// Run on each firrtl.module, transforming it from an firrtl.module into an
|
||||
|
@ -903,9 +909,12 @@ FIRRTLModuleLowering::lowerModule(FModuleOp oldModule, Block *topLevelModule,
|
|||
builder.create<hw::HWModuleOp>(oldModule.getLoc(), nameAttr, ports);
|
||||
if (auto outputFile = oldModule->getAttr("output_file"))
|
||||
newModule->setAttr("output_file", outputFile);
|
||||
|
||||
// Transform module annotations
|
||||
AnnotationSet annos(oldModule);
|
||||
// Mark the design under test as a module of interest for exporting module
|
||||
// hierarchy information.
|
||||
if (AnnotationSet::removeAnnotations(oldModule, dutAnnoClass))
|
||||
if (annos.removeAnnotation(dutAnnoClass))
|
||||
newModule->setAttr(
|
||||
moduleHierarchyFileAttrName,
|
||||
hw::OutputFileAttr::getFromDirectoryAndFilename(
|
||||
|
@ -913,8 +922,9 @@ FIRRTLModuleLowering::lowerModule(FModuleOp oldModule, Block *topLevelModule,
|
|||
getMetadataDir(oldModule->getParentOfType<CircuitOp>()).getValue(),
|
||||
"module_hier.json",
|
||||
/*excludeFromFileList=*/true));
|
||||
loweringState.processRemainingAnnotations(oldModule,
|
||||
AnnotationSet(oldModule));
|
||||
if (annos.removeAnnotation(verifBBClass))
|
||||
newModule->setAttr("firrtl.extract.cover.extra", builder.getUnitAttr());
|
||||
loweringState.processRemainingAnnotations(oldModule, annos);
|
||||
return newModule;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,6 +272,13 @@ bool AnnotationSet::removeAnnotation(Attribute anno) {
|
|||
[&](Annotation other) { return other.getDict() == anno; });
|
||||
}
|
||||
|
||||
/// Remove an annotation from this annotation set. Returns true if any were
|
||||
/// removed, false otherwise.
|
||||
bool AnnotationSet::removeAnnotation(StringRef className) {
|
||||
return removeAnnotations(
|
||||
[&](Annotation other) { return other.getClass() == className; });
|
||||
}
|
||||
|
||||
/// Remove all annotations from this annotation set for which `predicate`
|
||||
/// returns true.
|
||||
bool AnnotationSet::removeAnnotations(
|
||||
|
|
|
@ -312,13 +312,25 @@ void SVExtractTestCodeImplPass::runOnOperation() {
|
|||
top->getAttrOfType<hw::OutputFileAttr>("firrtl.extract.cover.bindfile");
|
||||
|
||||
auto isAssert = [](Operation *op) -> bool {
|
||||
if (auto inst = dyn_cast<hw::InstanceOp>(op))
|
||||
if (auto mod = inst.getReferencedModule())
|
||||
if (mod->getAttr("firrtl.extract.assert.extra"))
|
||||
return true;
|
||||
return isa<AssertOp>(op) || isa<FinishOp>(op) || isa<FWriteOp>(op) ||
|
||||
isa<AssertConcurrentOp>(op);
|
||||
};
|
||||
auto isAssume = [](Operation *op) -> bool {
|
||||
if (auto inst = dyn_cast<hw::InstanceOp>(op))
|
||||
if (auto mod = inst.getReferencedModule())
|
||||
if (mod->getAttr("firrtl.extract.assume.extra"))
|
||||
return true;
|
||||
return isa<AssumeOp>(op) || isa<AssumeConcurrentOp>(op);
|
||||
};
|
||||
auto isCover = [](Operation *op) -> bool {
|
||||
if (auto inst = dyn_cast<hw::InstanceOp>(op))
|
||||
if (auto mod = inst.getReferencedModule())
|
||||
if (mod->getAttr("firrtl.extract.cover.extra"))
|
||||
return true;
|
||||
return isa<CoverOp>(op) || isa<CoverConcurrentOp>(op);
|
||||
};
|
||||
|
||||
|
@ -331,6 +343,14 @@ void SVExtractTestCodeImplPass::runOnOperation() {
|
|||
doModule(rtlmod, isCover, "_cover", coverDir, coverBindFile);
|
||||
}
|
||||
}
|
||||
// We have to wait until all the instances are processed to clean up the
|
||||
// annotations.
|
||||
for (auto &op : topLevelModule->getOperations())
|
||||
if (isa<hw::HWModuleOp, hw::HWModuleExternOp>(op)) {
|
||||
op.removeAttr("firrtl.extract.assert.extra");
|
||||
op.removeAttr("firrtl.extract.cover.extra");
|
||||
op.removeAttr("firrtl.extract.assume.extra");
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Pass> circt::sv::createSVExtractTestCodePass() {
|
||||
|
|
|
@ -1074,4 +1074,6 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
|
|||
%b = firrtl.bitcast %a : (!firrtl.bundle<valid: uint<2>, ready: uint<1>, data: uint<3>>) -> (!firrtl.vector<uint<2>, 3>)
|
||||
// CHECK: hw.bitcast %0 : (!hw.struct<valid: i2, ready: i1, data: i3>) -> !hw.array<3xi2>
|
||||
}
|
||||
|
||||
firrtl.extmodule @chkcoverAnno(in %clock: !firrtl.clock) attributes {annotations = [{class = "freechips.rocketchip.annotations.InternalVerifBlackBoxAnnotation"}]}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,36 @@
|
|||
// RUN: circt-opt --sv-extract-test-code %s | FileCheck %s
|
||||
// CHECK-LABEL: hw.module @issue1246_assert(%clock: i1) attributes {output_file = #hw.output_file<"dir3/", excludeFromFileList, includeReplicatedOps>}
|
||||
// CHECK-LABEL: module attributes {firrtl.extract.assert = #hw.output_file<"dir3/"
|
||||
// CHECK-NEXT: hw.module.extern @foo_cover
|
||||
// CHECK-NOT: attributes
|
||||
// CHECK-NEXT: hw.module.extern @foo_assume
|
||||
// CHECK-NOT: attributes
|
||||
// CHECK-NEXT: hw.module.extern @foo_assert
|
||||
// CHECK-NOT: attributes
|
||||
// CHECK: hw.module @issue1246_assert(%clock: i1) attributes {output_file = #hw.output_file<"dir3/", excludeFromFileList, includeReplicatedOps>}
|
||||
// CHECK: sv.assert
|
||||
// CHECK: foo_assert
|
||||
// CHECK: hw.module @issue1246_assume(%clock: i1)
|
||||
// CHECK-NOT: attributes
|
||||
// CHECK: sv.assume
|
||||
// CHECK: foo_assume
|
||||
// CHECK: hw.module @issue1246_cover(%clock: i1)
|
||||
// CHECK-NOT: attributes
|
||||
// CHECK: sv.cover
|
||||
// CHECK: foo_cover
|
||||
// CHECK: hw.module @issue1246
|
||||
// CHECK-NOT: sv.assert
|
||||
// CHECK-NOT: sv.assume
|
||||
// CHECK-NOT: sv.cover
|
||||
// CHECK-NOT: foo_assert
|
||||
// CHECK-NOT: foo_assume
|
||||
// CHECK-NOT: foo_cover
|
||||
// CHECK: sv.bind @__ETC_issue1246_assert in @issue1246
|
||||
// CHECK: sv.bind @__ETC_issue1246_assume in @issue1246 {output_file = #hw.output_file<"file4", excludeFromFileList>}
|
||||
// CHECK: sv.bind @__ETC_issue1246_cover in @issue1246
|
||||
module attributes {firrtl.extract.assert = #hw.output_file<"dir3/", excludeFromFileList, includeReplicatedOps>, firrtl.extract.assume.bindfile = #hw.output_file<"file4", excludeFromFileList>} {
|
||||
hw.module.extern @foo_cover(%a : i1) attributes {"firrtl.extract.cover.extra"}
|
||||
hw.module.extern @foo_assume(%a : i1) attributes {"firrtl.extract.assume.extra"}
|
||||
hw.module.extern @foo_assert(%a : i1) attributes {"firrtl.extract.assert.extra"}
|
||||
hw.module @issue1246(%clock: i1) -> () {
|
||||
sv.always posedge %clock {
|
||||
sv.ifdef.procedural "SYNTHESIS" {
|
||||
|
@ -14,10 +38,14 @@ module attributes {firrtl.extract.assert = #hw.output_file<"dir3/", excludeFrom
|
|||
sv.if %2937 {
|
||||
sv.assert %clock : i1
|
||||
sv.assume %clock : i1
|
||||
sv.cover %clock : i1
|
||||
}
|
||||
}
|
||||
}
|
||||
%2937 = hw.constant 0 : i1
|
||||
hw.instance "bar_cover" @foo_cover(a: %clock : i1) -> ()
|
||||
hw.instance "bar_assume" @foo_assume(a: %clock : i1) -> ()
|
||||
hw.instance "bar_assert" @foo_assert(a: %clock : i1) -> ()
|
||||
hw.output
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue