[FIRRTL] Add force operation

Add a `firrtl.force` operation which properly lowers to the
corresponding `sv.force` operation. There is additional discussion in
PR #1665 regarding the proliferation of these operations. If we end up
replicating a lot of the SV ops in the FIRRTL dialect, we might want to
look into ways to use casts and a general scheme to reuse the SV ops to
work with the FIRRTL-typed values directly.

This change unblocks work on the Grand Central signal driving PR for
now, but we'll have to revisit these ops likely in the future.
This commit is contained in:
Fabian Schuiki 2021-09-09 19:32:26 +02:00
parent 4fd92559b0
commit 3628ee5f8e
No known key found for this signature in database
GPG Key ID: C42F5825FC5275E6
4 changed files with 39 additions and 2 deletions

View File

@ -184,3 +184,12 @@ def WhenOp : FIRRTLOp<"when", [SingleBlock, NoTerminator, NoRegionArguments,
}
}];
}
def ForceOp : FIRRTLOp<"force", [SameTypeOperands]> {
let summary = "Force procedural statement";
let description = "Maps to the corresponding `sv.force` operation.";
let arguments = (ins FIRRTLType:$dest, FIRRTLType:$src);
let results = (outs);
let assemblyFormat =
"$dest `,` $src attr-dict `:` type($dest) `,` type($src)";
}

View File

@ -157,8 +157,8 @@ public:
auto *thisCast = static_cast<ConcreteType *>(this);
return TypeSwitch<Operation *, ResultType>(op)
.template Case<AttachOp, ConnectOp, MemoryPortOp, MemoryPortAccessOp,
PartialConnectOp, PrintFOp, SkipOp, StopOp, WhenOp,
AssertOp, AssumeOp, CoverOp>(
PartialConnectOp, ForceOp, PrintFOp, SkipOp, StopOp,
WhenOp, AssertOp, AssumeOp, CoverOp>(
[&](auto opNode) -> ResultType {
return thisCast->visitStmt(opNode, args...);
})
@ -189,6 +189,7 @@ public:
HANDLE(MemoryPortOp);
HANDLE(MemoryPortAccessOp);
HANDLE(PartialConnectOp);
HANDLE(ForceOp);
HANDLE(PrintFOp);
HANDLE(SkipOp);
HANDLE(StopOp);

View File

@ -1141,6 +1141,7 @@ struct FIRRTLLowering : public FIRRTLVisitor<FIRRTLLowering, LogicalResult> {
LogicalResult visitStmt(SkipOp op);
LogicalResult visitStmt(ConnectOp op);
LogicalResult visitStmt(PartialConnectOp op);
LogicalResult visitStmt(ForceOp op);
LogicalResult visitStmt(PrintFOp op);
LogicalResult visitStmt(StopOp op);
LogicalResult visitStmt(AssertOp op);
@ -2672,6 +2673,22 @@ LogicalResult FIRRTLLowering::visitStmt(PartialConnectOp op) {
return success();
}
LogicalResult FIRRTLLowering::visitStmt(ForceOp op) {
auto srcVal = getLoweredValue(op.src());
if (!srcVal)
return failure();
auto destVal = getPossiblyInoutLoweredValue(op.dest());
if (!destVal)
return failure();
if (!destVal.getType().isa<hw::InOutType>())
return op.emitError("destination isn't an inout type");
addToInitialBlock([&]() { builder.create<sv::ForceOp>(destVal, srcVal); });
return success();
}
// Printf is a macro op that lowers to an sv.ifdef.procedural, an sv.if,
// and an sv.fwrite all nested together.
LogicalResult FIRRTLLowering::visitStmt(PrintFOp op) {

View File

@ -845,4 +845,14 @@ firrtl.circuit "Simple" attributes {annotations = [{class =
// CHECK: hw.output
}
// CHECK-LABEL: hw.module @Force
firrtl.module @Force(in %in: !firrtl.uint<42>) {
// CHECK: %out = sv.wire : !hw.inout<i42>
// CHECK: sv.initial {
// CHECK: sv.force %out, %in : i42
// CHECK: }
%out = firrtl.wire : !firrtl.uint<42>
firrtl.force %out, %in : !firrtl.uint<42>, !firrtl.uint<42>
}
}