Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion lib/Conversion/SimToSV/SimToSV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/ImplicitLocOpBuilder.h"
#include "mlir/IR/Threading.h"
#include "mlir/IR/Visitors.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/DialectConversion.h"
#include "mlir/Transforms/RegionUtils.h"
Expand All @@ -40,6 +41,7 @@ namespace circt {

using namespace circt;
using namespace sim;
using namespace mlir;

/// Check whether an op should be placed inside an ifdef guard that prevents it
/// from affecting synthesis runs.
Expand Down Expand Up @@ -267,6 +269,40 @@ static LogicalResult convert(PauseOp op, PatternRewriter &rewriter) {
return success();
}

class TriggeredLowering : public SimConversionPattern<TriggeredOp> {
public:
using SimConversionPattern<TriggeredOp>::SimConversionPattern;

LogicalResult
matchAndRewrite(TriggeredOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const final {
auto loc = op.getLoc();
state.usedSynthesisMacro = true;

sv::IfDefOp::create(
rewriter, loc, "SYNTHESIS", [] {},
[&] {
auto trigger =
seq::FromClockOp::create(rewriter, loc, adaptor.getClock());
auto alwaysOp = sv::AlwaysOp::create(
rewriter, loc,
ArrayRef<sv::EventControl>{sv::EventControl::AtPosEdge},
ArrayRef<Value>{trigger});

Block *destination = alwaysOp.getBodyBlock();
if (auto condition = adaptor.getCondition()) {
rewriter.setInsertionPointToStart(destination);
destination = sv::IfOp::create(rewriter, loc, condition, [] {
}).getThenBlock();
}

rewriter.mergeBlocks(op.getBodyBlock(), destination);
});
rewriter.eraseOp(op);
return success();
}
};

class DPICallLowering : public SimConversionPattern<DPICallOp> {
public:
using SimConversionPattern<DPICallOp>::SimConversionPattern;
Expand Down Expand Up @@ -434,7 +470,13 @@ addFragments(hw::HWModuleOp module,
static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) {
bool usedSynthesisMacro = false;

rootOp->walk([&](Operation *op) {
rootOp->walk<WalkOrder::PreOrder>([&](Operation *op) {
// `sim.triggered` is lowered as a whole later on. Do not pre-wrap the
// ops nested inside it here, or we may create redundant/invalid
// structure.
if (isa<TriggeredOp>(op))
return WalkResult::skip();

auto loc = op->getLoc();

// Move the op into an ifdef guard if needed.
Expand Down Expand Up @@ -516,6 +558,7 @@ static bool moveOpsIntoIfdefGuardsAndProcesses(Operation *rootOp) {
// Move the op into the if body.
op->moveBefore(block, block->end());
}
return WalkResult::advance();
});

return usedSynthesisMacro;
Expand Down Expand Up @@ -843,6 +886,7 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase<SimToSVPass> {
patterns.add<ClockedPauseOp>(convert);
patterns.add<TerminateOp>(convert);
patterns.add<PauseOp>(convert);
patterns.add<TriggeredLowering>(context, state);
patterns.add<DPICallLowering>(context, state);
auto result = applyPartialConversion(module, target, std::move(patterns));

Expand Down
80 changes: 80 additions & 0 deletions test/Conversion/SimToSV/triggered.mlir
Comment thread
nanjo712 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// RUN: circt-opt --lower-sim-to-sv --allow-unregistered-dialect %s | FileCheck %s

// CHECK-LABEL: hw.module @simple_triggered
hw.module @simple_triggered(in %clock : !seq.clock) {
sim.triggered %clock {
"some.user"() : () -> ()
}

// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock
// CHECK-NEXT: sv.always posedge %[[CLOCK]] {
// CHECK-NEXT: "some.user"() : () -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
}

// CHECK-LABEL: hw.module @conditional_triggered
hw.module @conditional_triggered(
in %clock : !seq.clock, in %en : i1) {
sim.triggered %clock if %en {
"some.user"() : () -> ()
}

// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock
// CHECK-NEXT: sv.always posedge %[[CLOCK]] {
// CHECK-NEXT: sv.if %en {
// CHECK-NEXT: "some.user"() : () -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
}

// CHECK-LABEL: hw.module @multiple_triggered
hw.module @multiple_triggered(
in %clock : !seq.clock, in %en : i1) {

sim.triggered %clock {
"some.user"() : () -> ()
}

sim.triggered %clock if %en {
"some.user"() : () -> ()
}

// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[CLOCK0:.*]] = seq.from_clock %clock
// CHECK-NEXT: sv.always posedge %[[CLOCK0]] {
// CHECK-NEXT: "some.user"() : () -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[CLOCK1:.*]] = seq.from_clock %clock
// CHECK-NEXT: sv.always posedge %[[CLOCK1]] {
// CHECK-NEXT: sv.if %en {
// CHECK-NEXT: "some.user"() : () -> ()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
}

// CHECK-LABEL: hw.module @triggered_with_pause
hw.module @triggered_with_pause(in %clock : !seq.clock) {
sim.triggered %clock {
sim.pause quiet
}

// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NOT: sv.ifdef.procedural @SYNTHESIS
// CHECK-NEXT: } else {
// CHECK-NEXT: %[[CLOCK:.*]] = seq.from_clock %clock
// CHECK-NEXT: sv.always posedge %[[CLOCK]] {
// CHECK-NEXT: sv.stop 0
// CHECK-NEXT: }
// CHECK-NEXT: }
}
Loading