[FIRRTL] Allow layers under when and match. (#7234)

Behavior is same as-if the contained operations were
not under a layer.
This commit is contained in:
Will Dietz 2024-06-26 08:35:10 -05:00 committed by GitHub
parent 03626d4a93
commit 3f0dcf4405
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 54 additions and 3 deletions

View File

@ -374,7 +374,9 @@ def VerifCoverIntrinsicOp : VerifIntrinsicOp<"cover">;
def LayerBlockOp : FIRRTLOp<
"layerblock",
[SingleBlock, NoTerminator, NoRegionArguments,
ParentOneOf<["firrtl::FModuleOp", "firrtl::LayerBlockOp"]>,
ParentOneOf<[
"firrtl::FModuleOp", "firrtl::LayerBlockOp",
"firrtl::WhenOp", "firrtl::MatchOp"]>,
DeclareOpInterfaceMethods<SymbolUserOpInterface>]
> {
let summary = "A definition of a layer block";

View File

@ -6171,6 +6171,10 @@ LogicalResult LayerBlockOp::verify() {
auto layerName = getLayerName();
auto *parentOp = (*this)->getParentOp();
// Get parent operation that isn't a when or match.
while (isa<WhenOp, MatchOp>(parentOp))
parentOp = parentOp->getParentOp();
// Verify the correctness of the symbol reference. Only verify that this
// layer block makes sense in its parent module or layer block.
auto nestedReferences = layerName.getNestedReferences();

View File

@ -533,6 +533,7 @@ public:
void visitStmt(PrintFOp op);
void visitStmt(StopOp op);
void visitStmt(WhenOp op);
void visitStmt(LayerBlockOp op);
void visitStmt(RefForceOp op);
void visitStmt(RefForceInitialOp op);
void visitStmt(RefReleaseOp op);
@ -619,6 +620,11 @@ void WhenOpVisitor::visitStmt(WhenOp whenOp) {
processWhenOp(whenOp, condition);
}
// NOLINTNEXTLINE(misc-no-recursion)
void WhenOpVisitor::visitStmt(LayerBlockOp layerBlockOp) {
process(*layerBlockOp.getBody());
}
void WhenOpVisitor::visitStmt(RefForceOp op) {
op.getPredicateMutable().assign(andWithCondition(op, op.getPredicate()));
}

View File

@ -589,6 +589,20 @@ firrtl.module @WhenInGroup(in %cond : !firrtl.uint<1>) {
}
}
// Check that expand whens works for layers under when's.
firrtl.layer @Layer bind {}
// CHECK-LABEL: firrtl.module @LayerUnderWhen(
// CHECK-NEXT: firrtl.layerblock @Layer
// CHECK: firrtl.printf %clock, %cond
firrtl.module @LayerUnderWhen(in %cond : !firrtl.uint<1>, in %clock : !firrtl.clock) {
firrtl.when %cond : !firrtl.uint<1> {
firrtl.layerblock @Layer {
%c1_ui1 = firrtl.constant 1 : !firrtl.uint<1>
firrtl.printf %clock, %c1_ui1, "Condition is true" : !firrtl.clock, !firrtl.uint<1>
}
}
}
// CHECK: firrtl.class @ClassWithInput(in %in: !firrtl.string)
firrtl.class @ClassWithInput(in %in: !firrtl.string) {}

View File

@ -9,6 +9,10 @@ circuit Foo: %[[
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~Foo|Foo>y"
},
{
"class": "firrtl.transforms.DontTouchAnnotation",
"target": "~Foo|Foo>z"
}
]]
layer A, bind:
@ -17,16 +21,34 @@ circuit Foo: %[[
public module Foo:
input in: UInt<1>
input clock: Clock
input cond: UInt<1>
input enable: UInt<1>
layerblock A:
node x = in
layerblock B:
node y = x
when cond:
layerblock B:
when x:
node z = x
assert(clock, cond, enable, "Test")
; CHECK-LABEL: module Foo_A_B(
; CHECK-NEXT: input x
; CHECK-NEXT: input x,
; CHECK-NEXT: cond,
; CHECK-NEXT: enable,
; CHECK-NEXT: clock
; CHECK-NEXT: );
; CHECK: wire y = x;
; CHECK: wire z = x;
; CHECK: always @(posedge clock) begin
; CHECK-NEXT: if (cond & x & enable)
; CHECK-NEXT: assert(cond) else $error("Test");
; CHECK-NEXT: end // always @(posedge)
; CHECK-NEXT: endmodule
; CHECK-LABEL: module Foo_A(
@ -40,7 +62,10 @@ circuit Foo: %[[
; CHECK-NEXT: `ifndef layers_Foo_A_B
; CHECK-NEXT: `define layers_Foo_A_B
; CHECK-NEXT: bind Foo Foo_A_B a_b (
; CHECK-NEXT: x (Foo.a.x_probe)
; CHECK-NEXT: .x (Foo.a.x_probe),
; CHECK-NEXT: .cond (cond),
; CHECK-NEXT: .enable (enable),
; CHECK-NEXT: .clock (clock)
; CHECK-NEXT: );
; CHECK-NEXT: `endif // layers_Foo_A_B