diff --git a/lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp b/lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp index 96b91a8ec3..2112394a4b 100644 --- a/lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp +++ b/lib/Dialect/FIRRTL/Transforms/LowerLayers.cpp @@ -465,6 +465,7 @@ LogicalResult LowerLayersPass::runOnModuleBody(FModuleOp moduleOp, }; SmallVector innerSyms; + SmallVector 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(op)) { + rwprobes.push_back(rwprobe); + continue; + } + if (auto connect = dyn_cast(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 " diff --git a/test/Dialect/FIRRTL/lower-layers-errors.mlir b/test/Dialect/FIRRTL/lower-layers-errors.mlir index 5d8e45986a..62448de2e6 100644 --- a/test/Dialect/FIRRTL/lower-layers-errors.mlir +++ b/test/Dialect/FIRRTL/lower-layers-errors.mlir @@ -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> + } + } +} + diff --git a/test/Dialect/FIRRTL/lower-layers.mlir b/test/Dialect/FIRRTL/lower-layers.mlir index 74b6f7af71..2f59969633 100644 --- a/test/Dialect/FIRRTL/lower-layers.mlir +++ b/test/Dialect/FIRRTL/lower-layers.mlir @@ -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, layers = [@T]} { + %d_p = firrtl.instance d @DUT(out p: !firrtl.rwprobe, @T>) + %one = firrtl.constant 1 : !firrtl.uint<1> + firrtl.ref.force_initial %one, %d_p, %one: !firrtl.uint<1>, !firrtl.rwprobe, @T>, !firrtl.uint<1> + } +// CHECK: firrtl.module private @DUT_T(out %p: !firrtl.rwprobe>) { +// CHECK-NEXT: %w = firrtl.wire sym @[[SYM:.+]] : !firrtl.uint<1> +// CHECK-NEXT: %0 = firrtl.ref.rwprobe <@DUT_T::@[[SYM]]> : !firrtl.rwprobe> +// CHECK-NEXT: firrtl.ref.define %p, %0 : !firrtl.rwprobe> +// CHECK-NEXT: } +// CHECK-NEXT: firrtl.module @DUT(out %p: !firrtl.rwprobe>) attributes {convention = #firrtl} { +// 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>) +// CHECK-NEXT: firrtl.ref.define %p, %t_p : !firrtl.rwprobe> +// CHECK-NEXT: } + + firrtl.module @DUT(out %p: !firrtl.rwprobe, @T>) attributes {convention = #firrtl} { + firrtl.layerblock @T { + %w = firrtl.wire sym @sym : !firrtl.uint<1> + %0 = firrtl.ref.rwprobe <@DUT::@sym> : !firrtl.rwprobe> + %1 = firrtl.ref.cast %0 : (!firrtl.rwprobe>) -> !firrtl.rwprobe, @T> + firrtl.ref.define %p, %1 : !firrtl.rwprobe, @T> + } + } +} diff --git a/test/firtool/layers-rwprobe.fir b/test/firtool/layers-rwprobe.fir new file mode 100644 index 0000000000..9e675687d5 --- /dev/null +++ b/test/firtool/layers-rwprobe.fir @@ -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, T> + + layerblock T: + wire w : UInt<1> + connect w, UInt<1>(0) + define p = rwprobe(w) +