Skip to content

Commit

Permalink
[ExportVerilog] Add a lowering option to fix up empty modules (#7454)
Browse files Browse the repository at this point in the history
This commit adds a new lowering option to sanitize empty modules by
creating a dummy wire in it.
  • Loading branch information
uenoku authored Aug 8, 2024
1 parent 1d417e2 commit a943626
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/VerilogGeneration.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ The current set of "lint warnings fix" Lowering Options is:
collisions with Verilog keywords insensitively. E.g., this will treat a
variable called `WIRE` as a collision with the keyword and rename it to
`WIRE_0` (or similar). When set to `false`, then `WIRE` will not be renamed.
* `fixUpEmptyModules` (default=`false`). If true, then add a dummy wire to
empty modules since some vendor tools consider empty modules as a blackbox and
raise synthesis errors.

## Recommended `LoweringOptions` by Target

Expand Down
4 changes: 4 additions & 0 deletions include/circt/Support/LoweringOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ struct LoweringOptions {

/// If true, then update the the mlir to include output verilog locations.
bool emitVerilogLocations = false;

/// If true, add a dummy wire to empty modules to prevent tools from regarding
/// the module as blackbox.
bool fixUpEmptyModules = false;
};
} // namespace circt

Expand Down
22 changes: 22 additions & 0 deletions lib/Conversion/ExportVerilog/PrepareForEmission.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,24 @@ static LogicalResult legalizeHWModule(Block &block,
return success();
}

static void fixUpEmptyModules(hw::HWEmittableModuleLike module) {
auto outputOp = dyn_cast<hw::OutputOp>(module.getBodyBlock()->begin());
if (!outputOp || outputOp->getNumOperands() > 0)
return; // Not empty so no need to fix up.
OpBuilder builder(module->getContext());
builder.setInsertionPoint(outputOp);
auto constant = builder.create<hw::ConstantOp>(module.getLoc(),
builder.getBoolAttr(true));
auto wire = builder.create<sv::WireOp>(module.getLoc(), builder.getI1Type());
sv::setSVAttributes(wire,
sv::SVAttributeAttr::get(
builder.getContext(),
"This wire is added to avoid emitting empty modules. "
"See `fixUpEmptyModules` lowering option in CIRCT.",
/*emitAsComment=*/true));
builder.create<sv::AssignOp>(module.getLoc(), wire, constant);
}

// NOLINTNEXTLINE(misc-no-recursion)
LogicalResult ExportVerilog::prepareHWModule(hw::HWEmittableModuleLike module,
const LoweringOptions &options) {
Expand All @@ -1325,6 +1343,10 @@ LogicalResult ExportVerilog::prepareHWModule(hw::HWEmittableModuleLike module,
// Zero-valued logic pruning.
pruneZeroValuedLogic(module);

// Fix up empty modules if necessary.
if (options.fixUpEmptyModules)
fixUpEmptyModules(module);

// Legalization.
if (failed(legalizeHWModule(*module.getBodyBlock(), options)))
return failure();
Expand Down
4 changes: 4 additions & 0 deletions lib/Support/LoweringOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ void LoweringOptions::parse(StringRef text, ErrorHandlerT errorHandler) {
caseInsensitiveKeywords = true;
} else if (option == "emitVerilogLocations") {
emitVerilogLocations = true;
} else if (option == "fixUpEmptyModules") {
fixUpEmptyModules = true;
} else {
errorHandler(llvm::Twine("unknown style option \'") + option + "\'");
// We continue parsing options after a failure.
Expand Down Expand Up @@ -180,6 +182,8 @@ std::string LoweringOptions::toString() const {
options += "caseInsensitiveKeywords,";
if (emitVerilogLocations)
options += "emitVerilogLocations,";
if (fixUpEmptyModules)
options += "fixUpEmptyModules,";

// Remove a trailing comma if present.
if (!options.empty()) {
Expand Down
19 changes: 19 additions & 0 deletions test/Conversion/ExportVerilog/fixup-empty-modules.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: circt-opt --test-apply-lowering-options='options=fixUpEmptyModules' --export-verilog %s | FileCheck %s --check-prefixes=CHECK

// CHECK-LABEL: module empty1
hw.module @empty1() {
// CHECK-NEXT: /* This wire is added to avoid emitting empty modules. See `fixUpEmptyModules` lowering option in CIRCT. */
// CHECK-NEXT: wire _GEN = 1'h1;
}

// CHECK-LABEL: module empty2
hw.module @empty2(in %in: i1, in %in2: i32) {
// CHECK: /* This wire is added to avoid emitting empty modules. See `fixUpEmptyModules` lowering option in CIRCT. */
// CHECK-NEXT: wire _GEN = 1'h1;
}

// CHECK-LABEL: module not_empty
hw.module @not_empty(in %in: i1, out out: i1) {
// CHECK: assign out = in;
hw.output %in : i1
}

0 comments on commit a943626

Please sign in to comment.