Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
9 changes: 9 additions & 0 deletions include/circt/Dialect/SV/SVOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ bool isExpression(Operation *op);
/// Returns if the expression is known to be 2-state (binary)
bool is2StateExpression(Value v);

/// Resolve the symbol name to use for the `sv.macro.decl` referenced by macro
/// users. Returns the existing decl's sym_name if a `sv.macro.decl` whose
/// Verilog identifier matches `verilogName` already exists in `symbolTableOp`;
/// otherwise returns a fresh sym_name that does not collide with any existing
/// symbol in `symbolTableOp`. `created` is set to true iff the returned name
/// belongs to a decl that the caller still needs to materialize.
StringAttr resolveMacroSymName(Operation *symbolTableOp, StringRef verilogName,
bool &created);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: naming this getOrCreate may be clearer:

Suggested change
StringAttr resolveMacroSymName(Operation *symbolTableOp, StringRef verilogName,
bool &created);
StringAttr getOrcreate(Operation *symbolTableOp, StringRef verilogName,
bool &created);

Copy link
Copy Markdown
Contributor Author

@nanjo712 nanjo712 May 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function doesn't actually create anything; it just checks if a symbol already exists or generates a usable symbol name. Perhaps it could be replaced with lookupOrGenerateMacroSymName?


//===----------------------------------------------------------------------===//
// CaseOp Support
//===----------------------------------------------------------------------===//
Expand Down
63 changes: 29 additions & 34 deletions lib/Conversion/FIRRTLToHW/LowerToHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2963,43 +2963,38 @@ FIRRTLLowering::lowerSimFormatString(StringRef originalFormatString,
LogicalResult FIRRTLLowering::lowerStatementWithFd(
const FileDescriptorInfo &fileDescriptor, Value clock, Value cond,
const std::function<LogicalResult(Value)> &fn, bool usePrintfCond) {
// Emit an "#ifndef SYNTHESIS" guard into the always block.
bool failed = false;
circuitState.addMacroDecl(builder.getStringAttr("SYNTHESIS"));
addToIfDefBlock("SYNTHESIS", std::function<void()>(), [&]() {
addToAlwaysBlock(clock, [&]() {
// TODO: This is not printf specific anymore. Replace "Printf" with "FD"
// or similar but be aware that changing macro name breaks existing uses.
circuitState.usedPrintf = true;
if (usePrintfCond)
circuitState.addFragment(theModule, "PRINTF_COND_FRAGMENT");

// Emit an "sv.if '`PRINTF_COND_ & cond' into the #ifndef.
Value ifCond = cond;
if (usePrintfCond) {
ifCond =
sv::MacroRefExprOp::create(builder, cond.getType(), "PRINTF_COND_");
ifCond = builder.createOrFold<comb::AndOp>(ifCond, cond, true);
}
addToAlwaysBlock(clock, [&]() {
// TODO: This is not printf specific anymore. Replace "Printf" with "FD"
// or similar but be aware that changing macro name breaks existing uses.
circuitState.usedPrintf = true;
if (usePrintfCond)
circuitState.addFragment(theModule, "PRINTF_COND_FRAGMENT");

Value ifCond = cond;
if (usePrintfCond) {
ifCond =
sv::MacroRefExprOp::create(builder, cond.getType(), "PRINTF_COND_");
ifCond = builder.createOrFold<comb::AndOp>(ifCond, cond, true);
}

addIfProceduralBlock(ifCond, [&]() {
// `fd`represents a file decriptor. Use the stdout or the one opened
// using $fopen.
Value fd;
if (fileDescriptor.isDefaultFd()) {
// Emit the sv.fwrite, writing to stderr by default.
fd = hw::ConstantOp::create(builder, APInt(32, 0x80000002));
} else {
// Call the library function to get the FD.
auto fdOrError = callFileDescriptorLib(fileDescriptor);
if (llvm::failed(fdOrError)) {
failed = true;
return;
}
fd = *fdOrError;
addIfProceduralBlock(ifCond, [&]() {
// `fd`represents a file decriptor. Use the stdout or the one opened
// using $fopen.
Value fd;
if (fileDescriptor.isDefaultFd()) {
// Emit the sv.fwrite, writing to stderr by default.
fd = hw::ConstantOp::create(builder, APInt(32, 0x80000002));
} else {
// Call the library function to get the FD.
auto fdOrError = callFileDescriptorLib(fileDescriptor);
if (llvm::failed(fdOrError)) {
failed = true;
return;
}
failed = llvm::failed(fn(fd));
});
fd = *fdOrError;
}
failed = llvm::failed(fn(fd));
});
});
return failure(failed);
Expand Down
32 changes: 26 additions & 6 deletions lib/Conversion/Utils/SVLoweringUtils.cpp
Comment thread
nanjo712 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,15 @@ void sv::emitFileDescriptorRuntime(Operation *fileScopeOp,
auto getterSymName = ::getFileDescriptorGetterSymName(builder.getContext());
auto fragmentSymName =
::getFileDescriptorFragmentSymName(builder.getContext());
auto macroSymName = builder.getStringAttr(kFileDescriptorMacroName);
bool fileDescriptorMacroNeedsCreation = false;
auto macroSymName = sv::resolveMacroSymName(
fileScopeOp, kFileDescriptorMacroName, fileDescriptorMacroNeedsCreation);
bool synthesisMacroNeedsCreation = false;
auto synthesisSymName = sv::resolveMacroSymName(fileScopeOp, "SYNTHESIS",
synthesisMacroNeedsCreation);
SymbolTable symbolTable(fileScopeOp);

auto emitGuard = [&](StringRef guard, llvm::function_ref<void(void)> body) {
auto emitGuard = [&](StringAttr guard, llvm::function_ref<void(void)> body) {
sv::IfDefOp::create(
builder, guard, [] {}, body);
};
Expand Down Expand Up @@ -95,15 +100,30 @@ void sv::emitFileDescriptorRuntime(Operation *fileScopeOp,
symbolTable.insert(func);
}

if (!symbolTable.lookup(macroSymName))
symbolTable.insert(sv::MacroDeclOp::create(builder, macroSymName));
if (synthesisMacroNeedsCreation) {
auto verilogName = synthesisSymName.getValue() == "SYNTHESIS"
? StringAttr{}
: builder.getStringAttr("SYNTHESIS");
symbolTable.insert(
sv::MacroDeclOp::create(builder, builder.getLoc(), synthesisSymName,
/*args=*/ArrayAttr{}, verilogName));
Comment thread
nanjo712 marked this conversation as resolved.
Outdated
}

if (fileDescriptorMacroNeedsCreation) {
auto verilogName = macroSymName.getValue() == kFileDescriptorMacroName
? StringAttr{}
: builder.getStringAttr(kFileDescriptorMacroName);
symbolTable.insert(
sv::MacroDeclOp::create(builder, builder.getLoc(), macroSymName,
/*args=*/ArrayAttr{}, verilogName));
}

if (symbolTable.lookup(fragmentSymName))
return;

auto fragment = emit::FragmentOp::create(builder, fragmentSymName, [&] {
emitGuard("SYNTHESIS", [&]() {
emitGuard(kFileDescriptorMacroName, [&]() {
emitGuard(synthesisSymName, [&]() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we remove this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be more cautious about removing this. We could simply remove the synthesis guard for print operations, mainly because Chisel places these operations in a separate layer, which are then output to separate files. These separate files themselves have macro guard, and also it's easy to disable it by not including these separate files in the synthesis.

As far as I know, there doesn't seem to be a similar mechanism for this part; it outputs separately to each file used, unlike print operations which are separated from the design code.

We might be able to improve it further, but I think this might require another evaluation.

emitGuard(macroSymName, [&]() {
sv::VerbatimOp::create(builder, R"(// CIRCT Logging Library
package __circt_lib_logging;
class FileDescriptor;
Expand Down
31 changes: 31 additions & 0 deletions lib/Dialect/SV/SVOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "circt/Dialect/HW/ModuleImplementation.h"
#include "circt/Dialect/SV/SVAttributes.h"
#include "circt/Support/CustomDirectiveImpl.h"
#include "circt/Support/Namespace.h"
#include "circt/Support/ProceduralRegionTrait.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
Expand Down Expand Up @@ -56,6 +57,36 @@ bool sv::isExpression(Operation *op) {
MacroRefExprOp, MacroRefExprSEOp>(op);
}

StringAttr sv::resolveMacroSymName(Operation *symbolTableOp,
StringRef verilogName, bool &created) {
assert(symbolTableOp && "expected symbol table op");
assert(symbolTableOp->hasTrait<mlir::OpTrait::SymbolTable>() &&
"expected symbolTableOp to define a symbol table");
assert(symbolTableOp->getNumRegions() == 1 &&
"expected single-region symbol table op");
assert(!symbolTableOp->getRegion(0).empty() &&
"expected non-empty symbol table region");
Comment thread
nanjo712 marked this conversation as resolved.
Outdated

for (auto decl :
symbolTableOp->getRegion(0).front().getOps<sv::MacroDeclOp>()) {
if (decl.getMacroIdentifier() == verilogName) {
created = false;
return decl.getSymNameAttr();
}
}

Namespace ns;
auto symbolNameId = StringAttr::get(symbolTableOp->getContext(),
SymbolTable::getSymbolAttrName());
for (auto &op : symbolTableOp->getRegion(0).front()) {
if (auto symbol = op.getAttrOfType<StringAttr>(symbolNameId))
ns.add(symbol.getValue());
}

created = true;
return StringAttr::get(symbolTableOp->getContext(), ns.newName(verilogName));
}
Comment on lines +70 to +82
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand it existed before, but could you consider using SymbolTable::insert instead (as SymbolTable is MLIR proper)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have misunderstood. I think SymbolTable::insert is not quite appropriate here because this helper simply selects a symbol name and intentionally postpones the creation of the decl opeartion.


/// Returns the operation registered with the given symbol name with the regions
/// of 'symbolTableOp'. recurse through nested regions which don't contain the
/// symboltable trait. Returns nullptr if no valid symbol was found.
Expand Down
24 changes: 0 additions & 24 deletions lib/Dialect/SV/Transforms/SVMaskNonSynthesizable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "circt/Dialect/SV/SVAttributes.h"
#include "circt/Dialect/SV/SVOps.h"
#include "circt/Dialect/SV/SVPasses.h"
#include "circt/Support/Namespace.h"
#include "circt/Support/ProceduralRegionTrait.h"
#include "circt/Support/Utils.h"
#include "mlir/IR/Builders.h"
Expand Down Expand Up @@ -64,29 +63,6 @@ static Region *getMatchingIfDefElseRegion(Operation *op,
.Default(static_cast<Region *>(nullptr));
}

/// Resolve the symbol name to use for the `sv.macro.decl` referenced by
/// `ifdef` mode's `sv.ifdef` ops. Returns the existing decl's sym_name if a
/// `sv.macro.decl` whose Verilog identifier matches `verilogName` already
/// exists at top level; otherwise returns a fresh sym_name that does not
/// collide with any existing top-level symbol (which may differ from
/// `verilogName` if a non-`sv.macro.decl` symbol of that name is present).
/// `created` is set to true iff the returned name belongs to a decl that
/// the caller still needs to materialize.
static StringAttr resolveMacroSymName(mlir::ModuleOp moduleOp,
StringRef verilogName, bool &created) {
for (auto decl : moduleOp.getOps<sv::MacroDeclOp>()) {
if (decl.getMacroIdentifier() == verilogName) {
created = false;
return decl.getSymNameAttr();
}
}
Namespace ns;
ns.add(moduleOp);
StringRef name = ns.newName(verilogName);
created = true;
return StringAttr::get(moduleOp.getContext(), name);
}

/// `delete` mode: walk the block and erase every masked op.
static void processBlockDelete(Block &block) {
block.walk([&](Operation *op) {
Expand Down
116 changes: 57 additions & 59 deletions test/Conversion/FIRRTLToHW/lower-to-hw.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -362,65 +362,63 @@ firrtl.circuit "Simple" attributes {annotations = [{class =

// CHECK: [[ADDSIGNED:%.+]] = comb.add

// CHECK: sv.ifdef @SYNTHESIS {
// CHECK-NEXT: } else {
// CHECK-NEXT: sv.always posedge [[CLOCK]] {
// CHECK-NEXT: %[[PRINTF_COND:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND]], %reset
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "No operands and literal: %%\0A"
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Binary: %b %0b %4b\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Decimal: %d %0d %4d\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Hexadecimal: %x %0x %4x\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "ASCII Character: %c\0A"([[ADD]]) : i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: [[SUMSIGNED:%.+]] = sv.system "signed"([[ADDSIGNED]])
// CHECK-NEXT: [[DSIGNED:%.+]] = sv.system "signed"(%d)
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Hi signed %d %d\0A"([[SUMSIGNED]], [[DSIGNED]]) : i5, i4
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: sv.fwrite %[[STDERR]], "[%0t]: %d %m"([[TIME]], %a) : i64, i4
// CHECK-NEXT: }
// CHECK-NEXT: sv.if %reset {
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: [[STR:%.+]] = sv.sformatf "%0t%d.txt"([[TIME]], %a) : i64, i4
// CHECK-NEXT: [[FD:%.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"([[STR]]) : (!hw.string) -> i32
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: sv.fwrite [[FD]], "[%0t]: dynamic file name\0A"([[TIME]]) : i64
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: [[STR:%.+]] = sv.sformatf "%0t%d.txt"([[TIME]], %a) : i64, i4
// CHECK-NEXT: [[FD:%.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"([[STR]]) : (!hw.string) -> i32
// CHECK-NEXT: sv.fflush fd [[FD]]
// CHECK-NEXT: }
// CHECK: sv.always posedge [[CLOCK]] {
// CHECK-NEXT: %[[PRINTF_COND:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND]], %reset
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "No operands and literal: %%\0A"
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Binary: %b %0b %4b\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Decimal: %d %0d %4d\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Hexadecimal: %x %0x %4x\0A"([[ADD]], %b, [[ADD]]) : i5, i4, i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: sv.fwrite %[[STDERR]], "ASCII Character: %c\0A"([[ADD]]) : i5
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: [[SUMSIGNED:%.+]] = sv.system "signed"([[ADDSIGNED]])
// CHECK-NEXT: [[DSIGNED:%.+]] = sv.system "signed"(%d)
// CHECK-NEXT: sv.fwrite %[[STDERR]], "Hi signed %d %d\0A"([[SUMSIGNED]], [[DSIGNED]]) : i5, i4
// CHECK-NEXT: }
// CHECK-NEXT: %[[PRINTF_COND_:.+]] = sv.macro.ref.expr @PRINTF_COND_() : () -> i1
// CHECK-NEXT: [[AND:%.+]] = comb.and bin %[[PRINTF_COND_]], %reset : i1
// CHECK-NEXT: sv.if [[AND]] {
// CHECK-NEXT: %[[STDERR:.+]] = hw.constant -2147483646 : i32
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: sv.fwrite %[[STDERR]], "[%0t]: %d %m"([[TIME]], %a) : i64, i4
// CHECK-NEXT: }
// CHECK-NEXT: sv.if %reset {
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: [[STR:%.+]] = sv.sformatf "%0t%d.txt"([[TIME]], %a) : i64, i4
// CHECK-NEXT: [[FD:%.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"([[STR]]) : (!hw.string) -> i32
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: sv.fwrite [[FD]], "[%0t]: dynamic file name\0A"([[TIME]]) : i64
// CHECK-NEXT: [[TIME:%.+]] = sv.system.time : i64
// CHECK-NEXT: [[STR:%.+]] = sv.sformatf "%0t%d.txt"([[TIME]], %a) : i64, i4
// CHECK-NEXT: [[FD:%.+]] = sv.func.call.procedural @"__circt_lib_logging::FileDescriptor::get"([[STR]]) : (!hw.string) -> i32
// CHECK-NEXT: sv.fflush fd [[FD]]
// CHECK-NEXT: }
firrtl.printf %clock, %reset, "No operands and literal: %%\0A" : !firrtl.clock, !firrtl.uint<1>

%0 = firrtl.add %a, %a : (!firrtl.uint<4>, !firrtl.uint<4>) -> !firrtl.uint<5>
Expand Down
10 changes: 4 additions & 6 deletions test/firtool/lower-layers.fir
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,10 @@ circuit TestHarness:
define trace = x

; CHECK: module TestHarness_Verification()
; CHECK: `ifndef SYNTHESIS
; CHECK: always @(posedge TestHarness.clock) begin
; CHECK: if ((`PRINTF_COND_) & TestHarness.reset)
; CHECK: $fwrite(32'h80000002, "The last PC was: %x", TestHarness.dut.verification.pc_d);
; CHECK: end // always @(posedge)
; CHECK: `endif // not def SYNTHESIS
; CHECK: always @(posedge TestHarness.clock) begin
; CHECK: if ((`PRINTF_COND_) & TestHarness.reset)
; CHECK: $fwrite(32'h80000002, "The last PC was: %x", TestHarness.dut.verification.pc_d);
; CHECK: end // always @(posedge)
; CHECK: endmodule

; CHECK: module TestHarness(
Expand Down
2 changes: 2 additions & 0 deletions unittests/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
add_subdirectory(Utils)

if(CIRCT_SLANG_FRONTEND_ENABLED)
add_subdirectory(ImportVerilog)
endif()
11 changes: 11 additions & 0 deletions unittests/Conversion/Utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
add_circt_unittest(CIRCTConversionUtilsTests
SVLoweringUtilsTest.cpp
)

target_link_libraries(CIRCTConversionUtilsTests
PRIVATE
CIRCTEmit
CIRCTHW
CIRCTSV
CIRCTSVLoweringUtils
)
Loading
Loading