[FIRRTL][LowerLayers] Update rwprobe operations if possible. (#7369)

Fixes first example in #7365 .

Add error path to LowerLayers so anything that goes wrong
can fail the pass.
This commit is contained in:
Will Dietz 2024-08-22 08:37:01 -05:00 committed by GitHub
parent eef76ca7e3
commit 062ea0331a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 120 additions and 0 deletions

View File

@ -465,6 +465,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
};
SmallVector<hw::InnerSymAttr> innerSyms;
SmallVector<RWProbeOp> rwprobes;
for (auto &op : llvm::make_early_inc_range(*body)) {
// Record any operations inside the layer block which have inner symbols.
// Theses may have symbol users which need to be updated.
@ -550,6 +551,11 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
continue;
}
if (auto rwprobe = dyn_cast<RWProbeOp>(op)) {
rwprobes.push_back(rwprobe);
continue;
}
if (auto connect = dyn_cast<FConnectLike>(op)) {
auto src = connect.getSrc();
auto dst = connect.getDest();
@ -664,6 +670,34 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp,
<< splice.second << "\n";);
}
// Update RWProbe operations.
for (auto rwprobe : rwprobes) {
auto targetRef = rwprobe.getTarget();
auto mapped = innerRefMap.find(targetRef);
if (mapped == innerRefMap.end()) {
assert(targetRef.getModule() == moduleOp.getNameAttr());
auto ist = hw::InnerSymbolTable::get(moduleOp);
if (failed(ist))
return WalkResult::interrupt();
auto target = ist->lookup(targetRef.getName());
assert(target);
auto fieldref = getFieldRefForTarget(target);
rwprobe
.emitError(
"rwprobe capture not supported with bind convention layer")
.attachNote(fieldref.getLoc())
.append("rwprobe target outside of bind layer");
return WalkResult::interrupt();
}
if (mapped->second.second != newModule.getModuleNameAttr())
return rwprobe.emitError("rwprobe target refers to different module"),
WalkResult::interrupt();
rwprobe.setTargetAttr(
hw::InnerRefAttr::get(mapped->second.second, targetRef.getName()));
}
// Connect instance ports to values.
assert(ports.size() == connectValues.size() &&
"the number of instance ports and values to connect to them must be "

View File

@ -14,3 +14,19 @@ firrtl.circuit "NonPassiveSubaccess" {
}
}
}
// -----
firrtl.circuit "RWProbeCantMove" {
firrtl.layer @A bind { }
firrtl.module @RWProbeCantMove() attributes {layers = [@A]} {
%z = firrtl.constant 0 : !firrtl.uint<5>
// expected-note @below {{rwprobe target outside of bind layer}}
%w = firrtl.node sym @sym %z : !firrtl.uint<5>
firrtl.layerblock @A {
// expected-error @below {{rwprobe capture not supported with bind convention layer}}
%rw = firrtl.ref.rwprobe <@RWProbeCantMove::@sym> : !firrtl.rwprobe<uint<5>>
}
}
}

View File

@ -736,3 +736,34 @@ firrtl.circuit "Foo" {
// CHECK: }
// CHECK: sv.verbatim "`endif // layers_Foo_B" {output_file = #hw.output_file<"layers_Foo_B.sv", excludeFromFileList>}
// CHECK: }
// -----
// Check rwprobe ops are updated.
// CHECK-LABEL: circuit "RWTH"
firrtl.circuit "RWTH" {
firrtl.layer @T bind { }
firrtl.module @RWTH() attributes {convention = #firrtl<convention scalarized>, layers = [@T]} {
%d_p = firrtl.instance d @DUT(out p: !firrtl.rwprobe<uint<1>, @T>)
%one = firrtl.constant 1 : !firrtl.uint<1>
firrtl.ref.force_initial %one, %d_p, %one: !firrtl.uint<1>, !firrtl.rwprobe<uint<1>, @T>, !firrtl.uint<1>
}
// CHECK: firrtl.module private @DUT_T(out %p: !firrtl.rwprobe<uint<1>>) {
// CHECK-NEXT: %w = firrtl.wire sym @[[SYM:.+]] : !firrtl.uint<1>
// CHECK-NEXT: %0 = firrtl.ref.rwprobe <@DUT_T::@[[SYM]]> : !firrtl.rwprobe<uint<1>>
// CHECK-NEXT: firrtl.ref.define %p, %0 : !firrtl.rwprobe<uint<1>>
// CHECK-NEXT: }
// CHECK-NEXT: firrtl.module @DUT(out %p: !firrtl.rwprobe<uint<1>>) attributes {convention = #firrtl<convention scalarized>} {
// CHECK-NEXT: %t_p = firrtl.instance t sym @t {lowerToBind, output_file = #hw.output_file<"layers_RWTH_T.sv", excludeFromFileList>} @DUT_T(out p: !firrtl.rwprobe<uint<1>>)
// CHECK-NEXT: firrtl.ref.define %p, %t_p : !firrtl.rwprobe<uint<1>>
// CHECK-NEXT: }
firrtl.module @DUT(out %p: !firrtl.rwprobe<uint<1>, @T>) attributes {convention = #firrtl<convention scalarized>} {
firrtl.layerblock @T {
%w = firrtl.wire sym @sym : !firrtl.uint<1>
%0 = firrtl.ref.rwprobe <@DUT::@sym> : !firrtl.rwprobe<uint<1>>
%1 = firrtl.ref.cast %0 : (!firrtl.rwprobe<uint<1>>) -> !firrtl.rwprobe<uint<1>, @T>
firrtl.ref.define %p, %1 : !firrtl.rwprobe<uint<1>, @T>
}
}
}

View File

@ -0,0 +1,39 @@
; RUN: firtool %s | FileCheck %s
FIRRTL version 4.0.0
; Check use of colored rwprobe in enablelayers.
; Check rwprobe of hardware in a layer.
; Order isn't critical, but for simplicity just check lines.
; CHECK: module TH();
; CHECK-NEXT: `ifndef SYNTHESIS
; CHECK-NEXT: initial
; CHECK-NEXT: force TH.d.t.w = 1'h1;
; CHECK-NEXT: `endif // not def SYNTHESIS
; CHECK-NEXT: DUT d ();
; CHECK-NEXT: endmodule
; CHECK: module DUT_T();
; CHECK-NEXT: wire w = 1'h0;
; CHECK-NEXT: endmodule
;
; CHECK: module DUT();
; CHECK-NEXT: endmodule
circuit TH:
layer T, bind:
public module TH enablelayer T:
inst d of DUT
force_initial(d.p, UInt<1>(1))
public module DUT:
output p : RWProbe<UInt<1>, T>
layerblock T:
wire w : UInt<1>
connect w, UInt<1>(0)
define p = rwprobe(w)