Skip to content

Commit 465281f

Browse files
authored
[FIRRTL] Improvements to XMRRefOp and XMRDerefOp (#8570)
- Adds a description to the ops - Marks the ops as pure - Adds the symbol user trait - Ensures that the symbol op is a hierarchical path.
1 parent eaa1d6b commit 465281f

File tree

7 files changed

+159
-4
lines changed

7 files changed

+159
-4
lines changed

include/circt/Dialect/FIRRTL/FIRRTLExpressions.td

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,15 +1582,28 @@ def RWProbeOp : FIRRTLOp<"ref.rwprobe",
15821582
let assemblyFormat = "$target attr-dict `:` type($result)";
15831583
}
15841584

1585-
def XMRRefOp : FIRRTLOp<"xmr.ref"> {
1585+
def XMRRefOp : FIRRTLOp<"xmr.ref", [
1586+
Pure,
1587+
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
15861588
let summary = "FIRRTL XMR operation, targetable by ref ops.";
1589+
let description = [{
1590+
Takes a (symbol-ref to a) hierarchical path and returns a reference to
1591+
the target. Through this reference, the target can be read or written
1592+
"at a distance".
1593+
}];
15871594
let arguments = (ins FlatSymbolRefAttr:$ref, DefaultValuedAttr<StrAttr, "{}">:$verbatimSuffix);
15881595
let results = (outs RefType:$dest);
15891596
let assemblyFormat = "$ref (`,` $verbatimSuffix^)? attr-dict `:` qualified(type($dest))";
15901597
}
15911598

1592-
def XMRDerefOp : FIRRTLOp<"xmr.deref"> {
1599+
def XMRDerefOp : FIRRTLOp<"xmr.deref", [
1600+
Pure,
1601+
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
15931602
let summary = "FIRRTL XMR operation, reading an XMR target.";
1603+
let description = [{
1604+
A "read at a distance", taking a (symbol-ref to a) hierarchical path,
1605+
returning the value of the target.
1606+
}];
15941607
let arguments = (ins FlatSymbolRefAttr:$ref, DefaultValuedAttr<StrAttr, "{}">:$verbatimSuffix);
15951608
let results = (outs PassiveType:$dest);
15961609
let assemblyFormat = "$ref (`,` $verbatimSuffix^)? attr-dict `:` qualified(type($dest))";

lib/Dialect/FIRRTL/FIRRTLOps.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6269,6 +6269,30 @@ LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
62696269
return checks(symOp.getTargetResult().getType(), symOp.getLoc());
62706270
}
62716271

6272+
LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6273+
auto *target = symbolTable.lookupNearestSymbolFrom(*this, getRefAttr());
6274+
if (!target)
6275+
return emitOpError("has an invalid symbol reference");
6276+
6277+
if (!isa<hw::HierPathOp>(target))
6278+
return emitOpError("does not target a hierpath op");
6279+
6280+
// TODO: Verify that the target's type matches the type of this op.
6281+
return success();
6282+
}
6283+
6284+
LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6285+
auto *target = symbolTable.lookupNearestSymbolFrom(*this, getRefAttr());
6286+
if (!target)
6287+
return emitOpError("has an invalid symbol reference");
6288+
6289+
if (!isa<hw::HierPathOp>(target))
6290+
return emitOpError("does not target a hierpath op");
6291+
6292+
// TODO: Verify that the target's type matches the type of this op.
6293+
return success();
6294+
}
6295+
62726296
//===----------------------------------------------------------------------===//
62736297
// Layer Block Operations
62746298
//===----------------------------------------------------------------------===//

test/Dialect/FIRRTL/advanced-layer-sink.mlir

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,3 +769,23 @@ firrtl.circuit "DoNotSinkInstanceOfModuleWithPortAnno" {
769769
}
770770
}
771771
}
772+
773+
// CHECK-LABEL: firrtl.circuit "SinkXMRs"
774+
firrtl.circuit "SinkXMRs" {
775+
firrtl.layer @A bind {}
776+
777+
hw.hierpath @xmr [@SinkXMRs::@target]
778+
779+
firrtl.module public @SinkXMRs() {
780+
%target = firrtl.wire sym @target : !firrtl.uint<1>
781+
%0 = firrtl.xmr.deref @xmr : !firrtl.uint<1>
782+
%1 = firrtl.xmr.ref @xmr : !firrtl.ref<uint<1>>
783+
784+
// CHECK: firrtl.layerblock @A
785+
firrtl.layerblock @A {
786+
// CHECK-NEXT: %0 = firrtl.xmr.deref @xmr : !firrtl.uint<1>
787+
// CHECK-NEXT: %1 = firrtl.xmr.ref @xmr : !firrtl.probe<uint<1>>
788+
"unknown"(%0, %1) : (!firrtl.uint<1>, !firrtl.ref<uint<1>>) -> ()
789+
}
790+
}
791+
}

test/Dialect/FIRRTL/canonicalization.mlir

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3635,4 +3635,17 @@ firrtl.module @name_prop(in %clock: !firrtl.clock, in %next: !firrtl.uint<8>, ou
36353635
%m = firrtl.node %wire : !firrtl.uint<8>
36363636
firrtl.connect %out_b, %m : !firrtl.uint<8>, !firrtl.uint<8>
36373637
}
3638+
3639+
hw.hierpath @xmr [@XMRTest::@target]
3640+
3641+
// CHECK-LABEL: firrtl.module private @XMRTest
3642+
firrtl.module private @XMRTest() {
3643+
%target = firrtl.wire sym @target : !firrtl.uint<1>
3644+
3645+
// CHECK-NOT: firrtl.xmr.deref
3646+
%0 = firrtl.xmr.deref @xmr : !firrtl.uint<1>
3647+
3648+
// CHECK-NOT: firrtl.xmr.ref
3649+
%1 = firrtl.xmr.ref @xmr : !firrtl.ref<uint<1>>
3650+
}
36383651
}

test/Dialect/FIRRTL/errors.mlir

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2925,3 +2925,41 @@ firrtl.circuit "BindTargetMissingDoNotPrintFlag" {
29252925
// expected-error @below {{target #hw.innerNameRef<@BindTargetMissingDoNotPrintFlag::@target> is not marked doNotPrint}}
29262926
firrtl.bind <@BindTargetMissingDoNotPrintFlag::@target>
29272927
}
2928+
2929+
// -----
2930+
2931+
firrtl.circuit "XMRRefOpMissingTarget" {
2932+
firrtl.module @XMRRefOpMissingTarget() {
2933+
// expected-error @below {{op has an invalid symbol reference}}
2934+
%0 = firrtl.xmr.ref @MissingTarget : !firrtl.ref<uint<1>>
2935+
}
2936+
}
2937+
2938+
// -----
2939+
2940+
firrtl.circuit "XMRRefOpTargetsNonHierPath" {
2941+
firrtl.extmodule @Target()
2942+
firrtl.module @XMRRefOpMissingTarget() {
2943+
// expected-error @below {{op does not target a hierpath op}}
2944+
%0 = firrtl.xmr.ref @Target : !firrtl.ref<uint<1>>
2945+
}
2946+
}
2947+
2948+
// -----
2949+
2950+
firrtl.circuit "XMRDerefOpMissingTarget" {
2951+
firrtl.module @XMRDerefOpMissingTarget() {
2952+
// expected-error @below {{op has an invalid symbol reference}}
2953+
%0 = firrtl.xmr.deref @MissingTarget : !firrtl.uint<1>
2954+
}
2955+
}
2956+
2957+
// -----
2958+
2959+
firrtl.circuit "XMRDerefOpTargetsNonHierPath" {
2960+
firrtl.extmodule @Target()
2961+
firrtl.module @XMRDerefOpTargetsNonHierPath() {
2962+
// expected-error @below {{op does not target a hierpath op}}
2963+
%0 = firrtl.xmr.deref @Target : !firrtl.uint<1>
2964+
}
2965+
}

test/Dialect/FIRRTL/lower-layers.mlir

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ firrtl.circuit "Test" {
138138
// CHECK-NEXT: %w_probe = firrtl.node sym @sym interesting_name %w : !firrtl.uint<1>
139139
// CHECK-NEXT: firrtl.instance {{.+}} {doNotPrint, output_file = #hw.output_file<"layers-CaptureProbeSrc-A.sv", excludeFromFileList>} @CaptureProbeSrc_A
140140
// CHECK-NEXT: }
141+
hw.hierpath private @xmrPath [@CaptureProbeSrc::@sym]
141142
firrtl.module @CaptureProbeSrc() {
142143
%w = firrtl.wire : !firrtl.uint<1>
143144
%w_probe = firrtl.node sym @sym interesting_name %w : !firrtl.uint<1>
@@ -310,13 +311,13 @@ firrtl.circuit "Test" {
310311
// XMR Ref ops used by force_initial are cloned.
311312
//
312313
// CHECK: firrtl.module private @XmrRef_A()
313-
// CHECK-NEXT: %0 = firrtl.xmr.ref @RefXmrRef_path : !firrtl.rwprobe<uint<1>, @A>
314+
// CHECK-NEXT: %0 = firrtl.xmr.ref @XmrRef_path : !firrtl.rwprobe<uint<1>, @A>
314315
// CHECK-NEXT: %a = firrtl.wire
315316
// CHECK-NEXT: %c1_ui1 = firrtl.constant 1
316317
// CHECK-NEXT: firrtl.ref.force_initial %c1_ui1, %0, %c1_ui1
317318
hw.hierpath private @XmrRef_path [@XmrRef::@a]
318319
firrtl.module @XmrRef() {
319-
%0 = firrtl.xmr.ref @RefXmrRef_path : !firrtl.rwprobe<uint<1>, @A>
320+
%0 = firrtl.xmr.ref @XmrRef_path : !firrtl.rwprobe<uint<1>, @A>
320321
firrtl.layerblock @A {
321322
%a = firrtl.wire sym @a : !firrtl.uint<1>
322323
%c1_ui1 = firrtl.constant 1 : !firrtl.const.uint<1>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
; RUN: firtool --disable-all-randomization --advanced-layer-sink %s | FileCheck %s
2+
3+
; Check that the probes are correctly sunk into the layer, and there are
4+
; no bare probes left in the design.
5+
6+
; Check the probes are inlined into the assertions:
7+
8+
; CHECK-LABEL: module Foo_A();
9+
; CHECK-NEXT: always @(posedge Foo.clock) begin
10+
; CHECK-NEXT: assert(Foo.bar.`ref_Bar_probe) else $error("message");
11+
; CHECK-NEXT: assert(Foo.bar.`ref_Bar_probe) else $error("message");
12+
; CHECK-NEXT: end // always @(posedge)
13+
; CHECK-NEXT: `ifndef SYNTHESIS
14+
; CHECK-NEXT: initial
15+
; CHECK-NEXT: force Foo.bar.`ref_Bar_rwprobe = 1'h1;
16+
; CHECK-NEXT: `endif // not def SYNTHESIS
17+
; CHECK-NEXT: endmodule
18+
19+
; Check that there are no probes in the top level module:
20+
21+
; CHECK-LABEL: module Foo(
22+
; CHECK-NEXT: input clock
23+
; CHECK-NEXT: );
24+
; CHECK-EMPTY:
25+
; CHECK-NEXT: Bar bar ();
26+
; CHECK-NEXT: endmodule
27+
28+
FIRRTL version 4.0.0
29+
30+
circuit Foo:
31+
layer A, bind:
32+
33+
public module Foo:
34+
input clock: Clock
35+
36+
inst bar of Bar
37+
node cond = read(bar.probe)
38+
39+
layerblock A:
40+
assert(clock, cond, UInt<1>(1), "message")
41+
assert(clock, cond, UInt<1>(1), "message")
42+
force_initial(bar.rwprobe, UInt<1>(1))
43+
44+
extmodule Bar:
45+
output probe : Probe<UInt<1>>
46+
output rwprobe : RWProbe<UInt<1>>

0 commit comments

Comments
 (0)