Skip to content

Commit 5a6a561

Browse files
authored
[FIRRTL][ProbesToSignals] RWProbe support (#7706)
* Define type conversion mapping rwprobe<T> -> passive(T) * Forceable support (passive read of data result) * RWProbeOp support (materialize target, to passive) * Reject {force,release}{,_initial} Add some basic tests.
1 parent dce37cc commit 5a6a561

File tree

3 files changed

+152
-35
lines changed

3 files changed

+152
-35
lines changed

lib/Dialect/FIRRTL/Transforms/ProbesToSignals.cpp

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
// * Inference passes, especially width inference. Probes infer slightly
2424
// differently than non-probes do (must have same width along the chain).
2525
//
26-
// Forceable and colored probes are not supported.
26+
// Colored probes are not supported.
2727
// Specialize layers on or off to remove colored probes first.
2828
//
2929
// Debug ports on FIRRTL memories are not currently supported,
@@ -66,7 +66,7 @@ namespace {
6666

6767
class ProbeVisitor : public FIRRTLVisitor<ProbeVisitor, LogicalResult> {
6868
public:
69-
ProbeVisitor() = default;
69+
ProbeVisitor(hw::InnerRefNamespace &irn) : irn(irn) {}
7070

7171
/// Entrypoint.
7272
LogicalResult visit(FModuleLike mod);
@@ -91,9 +91,6 @@ class ProbeVisitor : public FIRRTLVisitor<ProbeVisitor, LogicalResult> {
9191
if (!refType)
9292
return Type();
9393

94-
if (refType.getForceable())
95-
return err("rwprobe not supported");
96-
9794
if (refType.getLayer())
9895
return err("layer-colored probes not supported");
9996

@@ -141,39 +138,58 @@ class ProbeVisitor : public FIRRTLVisitor<ProbeVisitor, LogicalResult> {
141138

142139
/// Check declarations specifically before forwarding to unhandled.
143140
LogicalResult visitUnhandledDecl(Operation *op) {
144-
// Check for and reject forceable declarations explicitly.
141+
// Check for and handle active forceable declarations.
145142
if (auto fop = dyn_cast<Forceable>(op); fop && fop.isForceable())
146-
return fop.emitError("forceable declaration not supported");
143+
return visitActiveForceableDecl(fop);
147144
return visitUnhandledOp(op);
148145
}
149146

150147
// Declarations
151148

152149
LogicalResult visitDecl(MemOp op);
153150
LogicalResult visitDecl(WireOp op);
151+
LogicalResult visitActiveForceableDecl(Forceable fop);
154152

155153
LogicalResult visitInstanceLike(Operation *op);
156154
LogicalResult visitDecl(InstanceOp op) { return visitInstanceLike(op); }
157155
LogicalResult visitDecl(InstanceChoiceOp op) { return visitInstanceLike(op); }
158156

159157
// Probe operations.
160158

161-
LogicalResult visitExpr(RWProbeOp op) {
162-
return op.emitError("rwprobe not supported");
163-
}
159+
LogicalResult visitExpr(RWProbeOp op);
164160
LogicalResult visitExpr(RefCastOp op);
165161
LogicalResult visitExpr(RefResolveOp op);
166162
LogicalResult visitExpr(RefSendOp op);
167163
LogicalResult visitExpr(RefSubOp op);
168164

169165
LogicalResult visitStmt(RefDefineOp op);
170166

167+
// Force and release operations: reject as unsupported.
168+
LogicalResult visitStmt(RefForceOp op) {
169+
return op.emitError("force not supported");
170+
}
171+
LogicalResult visitStmt(RefForceInitialOp op) {
172+
return op.emitError("force_initial not supported");
173+
}
174+
LogicalResult visitStmt(RefReleaseOp op) {
175+
return op.emitError("release not supported");
176+
}
177+
LogicalResult visitStmt(RefReleaseInitialOp op) {
178+
return op.emitError("release_initial not supported");
179+
}
180+
171181
private:
172182
/// Map from probe-typed Value's to their non-probe equivalent.
173183
DenseMap<Value, Value> probeToHWMap;
174184

185+
/// Forceable operations to demote.
186+
SmallVector<Forceable> forceables;
187+
175188
/// Operations to delete.
176189
SmallVector<Operation *> toDelete;
190+
191+
/// Read-only copy of inner-ref namespace for resolving inner refs.
192+
hw::InnerRefNamespace &irn;
177193
};
178194

179195
} // end namespace
@@ -260,6 +276,10 @@ LogicalResult ProbeVisitor::visit(FModuleLike mod) {
260276
for (auto *op : llvm::reverse(toDelete))
261277
op->erase();
262278

279+
// Demote forceable's.
280+
for (auto fop : forceables)
281+
firrtl::detail::replaceWithNewForceability(fop, false);
282+
263283
return success();
264284
}
265285

@@ -384,7 +404,7 @@ LogicalResult ProbeVisitor::visitDecl(MemOp op) {
384404

385405
LogicalResult ProbeVisitor::visitDecl(WireOp op) {
386406
if (op.isForceable())
387-
return op.emitError("forceable declaration not supported");
407+
return visitActiveForceableDecl(op);
388408

389409
auto conv = convertType(op.getDataRaw().getType(), op.getLoc());
390410
if (failed(conv))
@@ -402,6 +422,28 @@ LogicalResult ProbeVisitor::visitDecl(WireOp op) {
402422
return success();
403423
}
404424

425+
LogicalResult ProbeVisitor::visitActiveForceableDecl(Forceable fop) {
426+
assert(fop.isForceable() && "must be called on active forceables");
427+
// Map rw ref result to normal result.
428+
auto data = fop.getData();
429+
auto conv = mapType(fop.getDataRef().getType(), fop.getLoc());
430+
if (failed(conv))
431+
return failure();
432+
auto newType = *conv;
433+
forceables.push_back(fop);
434+
435+
assert(newType == data.getType().getPassiveType());
436+
if (newType != data.getType()) {
437+
ImplicitLocOpBuilder builder(fop.getLoc(), fop);
438+
builder.setInsertionPointAfterValue(data);
439+
auto wire = builder.create<WireOp>(newType);
440+
emitConnect(builder, wire.getData(), data);
441+
data = wire.getData();
442+
}
443+
probeToHWMap[fop.getDataRef()] = data;
444+
return success();
445+
}
446+
405447
LogicalResult ProbeVisitor::visitInstanceLike(Operation *op) {
406448
SmallVector<Type> newTypes;
407449
auto needsConv = mapRange(op->getResultTypes(), op->getLoc(), newTypes);
@@ -461,6 +503,33 @@ LogicalResult ProbeVisitor::visitStmt(RefDefineOp op) {
461503
return success();
462504
}
463505

506+
LogicalResult ProbeVisitor::visitExpr(RWProbeOp op) {
507+
// Handle similar to ref.send but lookup the target
508+
// and materialize a value for it (indexing).
509+
auto conv = mapType(op.getType(), op.getLoc());
510+
if (failed(conv))
511+
return failure();
512+
auto newType = *conv;
513+
toDelete.push_back(op);
514+
515+
auto ist = irn.lookup(op.getTarget());
516+
assert(ist);
517+
auto ref = getFieldRefForTarget(ist);
518+
519+
ImplicitLocOpBuilder builder(op.getLoc(), op);
520+
builder.setInsertionPointAfterValue(ref.getValue());
521+
auto data = getValueByFieldID(builder, ref.getValue(), ref.getFieldID());
522+
assert(cast<FIRRTLBaseType>(data.getType()).getPassiveType() ==
523+
op.getType().getType());
524+
if (newType != data.getType()) {
525+
auto wire = builder.create<WireOp>(newType);
526+
emitConnect(builder, wire.getData(), data);
527+
data = wire.getData();
528+
}
529+
probeToHWMap[op.getResult()] = data;
530+
return success();
531+
}
532+
464533
LogicalResult ProbeVisitor::visitExpr(RefCastOp op) {
465534
auto input = probeToHWMap.at(op.getInput());
466535
// Insert wire of the new type, and connect to it.
@@ -546,8 +615,11 @@ void ProbesToSignalsPass::runOnOperation() {
546615

547616
SmallVector<Operation *, 0> ops(getOperation().getOps<FModuleLike>());
548617

618+
hw::InnerRefNamespace irn{getAnalysis<SymbolTable>(),
619+
getAnalysis<hw::InnerSymbolTableCollection>()};
620+
549621
auto result = failableParallelForEach(&getContext(), ops, [&](Operation *op) {
550-
ProbeVisitor visitor;
622+
ProbeVisitor visitor(irn);
551623
return visitor.visit(cast<FModuleLike>(op));
552624
});
553625

test/Dialect/FIRRTL/probes-to-signals-errors.mlir

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
// RUN: circt-opt --firrtl-probes-to-signals --verify-diagnostics --split-input-file %s
22

3-
// CHECK-LABEL: "ProbeAndRWProbe"
4-
firrtl.circuit "ProbeAndRWProbe" {
5-
// expected-error @below {{rwprobe not supported, cannot convert type '!firrtl.rwprobe<uint<2>>'}}
6-
firrtl.extmodule private @Probes(out ro : !firrtl.probe<uint<1>>, out rw : !firrtl.rwprobe<uint<2>>)
7-
firrtl.module @ProbeAndRWProbe() {}
8-
}
9-
10-
// -----
11-
123
firrtl.circuit "InternalPath" {
134
// expected-error @below {{cannot convert module with internal path}}
145
firrtl.extmodule @InternalPath(
@@ -37,20 +28,13 @@ firrtl.circuit "RefProducer" {
3728

3829
// -----
3930

40-
firrtl.circuit "Forceable" {
41-
firrtl.module @Forceable() {
42-
// expected-error @below {{forceable declaration not supported}}
43-
%w, %w_f = firrtl.wire forceable : !firrtl.uint<2>, !firrtl.rwprobe<uint<2>>
44-
}
45-
}
46-
47-
// -----
48-
49-
firrtl.circuit "RWProbeOp" {
50-
firrtl.module @RWProbeOp() {
31+
firrtl.circuit "RejectForce" {
32+
firrtl.module @RejectForce(in %clock: !firrtl.clock, in %val : !firrtl.uint<2>, out %p : !firrtl.rwprobe<uint<2>>) {
5133
%w = firrtl.wire sym @sym : !firrtl.uint<2>
52-
// expected-error @below {{rwprobe not supported}}
53-
%rwprobe = firrtl.ref.rwprobe <@RWProbeOp::@sym> : !firrtl.rwprobe<uint<2>>
34+
%rwprobe = firrtl.ref.rwprobe <@RejectForce::@sym> : !firrtl.rwprobe<uint<2>>
35+
%c1_ui1 = firrtl.constant 1 : !firrtl.const.uint<1>
36+
// expected-error @below {{force not supported}}
37+
firrtl.ref.force %clock, %c1_ui1, %rwprobe, %val : !firrtl.clock, !firrtl.const.uint<1>, !firrtl.rwprobe<uint<2>>, !firrtl.uint<2>
5438
}
5539
}
5640

test/Dialect/FIRRTL/probes-to-signals.mlir

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ firrtl.circuit "TestP" {
6565

6666
// -----
6767

68-
// Extmodule
68+
// Extmodule using alias
6969

7070
// CHECK-LABEL: "ExtModule"
7171
firrtl.circuit "ExtModule" {
@@ -75,6 +75,17 @@ firrtl.circuit "ExtModule" {
7575

7676
// -----
7777

78+
// Extmodule using rwprobe
79+
80+
// CHECK-LABEL: "ExtModuleRW"
81+
firrtl.circuit "ExtModuleRW" {
82+
// CHECK: out ro: !firrtl.uint<1>
83+
// CHECK-SAME: out rw: !firrtl.uint<2>
84+
firrtl.extmodule @ExtModuleRW(out ro: !firrtl.probe<uint<1>>, out rw: !firrtl.rwprobe<uint<2>>)
85+
}
86+
87+
// -----
88+
7889
// CHIRRTL debug port
7990

8091
// CHECK-LABEL: "DbgsMemPort"
@@ -109,3 +120,53 @@ firrtl.circuit "DbgsMemPort" {
109120
// CHECK: matchingconnect %_a, %[[W]]
110121
}
111122
}
123+
124+
// -----
125+
// RWProbe exported out top should be supported.
126+
127+
// CHECK-LABEL: "ForceableRWProbeExport"
128+
firrtl.circuit "ForceableRWProbeExport" {
129+
// CHECK: @ForceableRWProbeExport(out %p: !firrtl.uint<2>)
130+
firrtl.module @ForceableRWProbeExport(out %p : !firrtl.rwprobe<uint<2>>) {
131+
// CHECK-NEXT: %w = firrtl.wire : !firrtl.uint<2>
132+
// CHECK-NEXT: firrtl.matchingconnect %p, %w
133+
// CHECK-NEXT: }
134+
%w, %w_f = firrtl.wire forceable : !firrtl.uint<2>, !firrtl.rwprobe<uint<2>>
135+
firrtl.ref.define %p, %w_f : !firrtl.rwprobe<uint<2>>
136+
}
137+
}
138+
139+
// -----
140+
141+
// Test use of forceable + rwprobe + read works.
142+
// Forceable is handled by using passive copy of data result.
143+
144+
// CHECK-LABEL: "ForceableToRead"
145+
firrtl.circuit "ForceableToRead" {
146+
// CHECK: @ForceableToRead(
147+
firrtl.module @ForceableToRead(out %r : !firrtl.uint<2>) {
148+
// CHECK-NEXT: %w = firrtl.wire : !firrtl.uint<2>
149+
// CHECK-NEXT: firrtl.matchingconnect %r, %w
150+
%w, %w_f = firrtl.wire forceable : !firrtl.uint<2>, !firrtl.rwprobe<uint<2>>
151+
%data = firrtl.ref.resolve %w_f : !firrtl.rwprobe<uint<2>>
152+
firrtl.matchingconnect %r, %data : !firrtl.uint<2>
153+
}
154+
}
155+
156+
// -----
157+
158+
// Check rwprobe operation.
159+
160+
// CHECK-LABEL: "RWProbeOp"
161+
firrtl.circuit "RWProbeOp" {
162+
// CHECK: @RWProbeOp(out %p: !firrtl.uint<2>)
163+
firrtl.module @RWProbeOp(out %p: !firrtl.rwprobe<uint<2>>) {
164+
// CHECK-NEXT: %w = firrtl.wire sym @sym
165+
// CHECK-NEXT: firrtl.matchingconnect %p, %w
166+
// CHECK-NEXT: }
167+
%w = firrtl.wire sym @sym : !firrtl.uint<2>
168+
%rwprobe = firrtl.ref.rwprobe <@RWProbeOp::@sym> : !firrtl.rwprobe<uint<2>>
169+
firrtl.ref.define %p, %rwprobe : !firrtl.rwprobe<uint<2>>
170+
}
171+
}
172+

0 commit comments

Comments
 (0)