Skip to content

Commit fa875f7

Browse files
committed
[sim] Add emission for plusargs for UPF simulations
For UPF simulations, we want to disable plusargs but drive the output wires with 0 instead of z. We want this to be able to enable this mode of operation while also enabling assertions, so we add another macro UPF_SIM to control this behaviour.
1 parent 3a4eb3a commit fa875f7

File tree

3 files changed

+76
-23
lines changed

3 files changed

+76
-23
lines changed

lib/Conversion/SimToSV/SimToSV.cpp

+51-12
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace {
4141
struct SimConversionState {
4242
hw::HWModuleOp module;
4343
bool usedSynthesisMacro = false;
44+
bool usedUPFSimMacro = false;
4445
SetVector<StringAttr> dpiCallees;
4546
};
4647

@@ -99,6 +100,7 @@ class PlusArgsValueLowering : public SimConversionPattern<PlusArgsValueOp> {
99100
rewriter.getStringAttr("_pargs_f"));
100101

101102
state.usedSynthesisMacro = true;
103+
state.usedUPFSimMacro = true;
102104
rewriter.create<sv::IfDefOp>(
103105
loc, "SYNTHESIS",
104106
[&]() {
@@ -115,18 +117,38 @@ class PlusArgsValueLowering : public SimConversionPattern<PlusArgsValueOp> {
115117
rewriter.create<sv::AssignOp>(loc, regf, cstFalse);
116118
},
117119
[&]() {
118-
rewriter.create<sv::InitialOp>(loc, [&] {
119-
auto zero32 = rewriter.create<hw::ConstantOp>(loc, APInt(32, 0));
120-
auto tmpResultType = rewriter.getIntegerType(32);
121-
auto str =
122-
rewriter.create<sv::ConstantStrOp>(loc, op.getFormatString());
123-
auto call = rewriter.create<sv::SystemFunctionOp>(
124-
loc, tmpResultType, "value$plusargs",
125-
ArrayRef<Value>{str, regv});
126-
auto test = rewriter.create<comb::ICmpOp>(
127-
loc, comb::ICmpPredicate::ne, call, zero32, true);
128-
rewriter.create<sv::BPAssignOp>(loc, regf, test);
129-
});
120+
rewriter.create<sv::IfDefOp>(
121+
loc, "UPF_SIMULATION",
122+
[&]() {
123+
auto zero = rewriter.create<hw::ConstantOp>(
124+
loc, APInt(type.getIntOrFloatBitWidth(), 0));
125+
auto assign = rewriter.create<sv::AssignOp>(loc, regv, zero);
126+
circt::sv::setSVAttributes(
127+
assign,
128+
sv::SVAttributeAttr::get(
129+
rewriter.getContext(),
130+
"This dummy assignment exists to avoid undriven lint "
131+
"warnings (e.g., Verilator UNDRIVEN).",
132+
/*emitAsComment=*/true));
133+
auto cstFalse =
134+
rewriter.create<hw::ConstantOp>(loc, APInt(1, 0));
135+
rewriter.create<sv::AssignOp>(loc, regf, cstFalse);
136+
},
137+
[&]() {
138+
rewriter.create<sv::InitialOp>(loc, [&] {
139+
auto zero32 =
140+
rewriter.create<hw::ConstantOp>(loc, APInt(32, 0));
141+
auto tmpResultType = rewriter.getIntegerType(32);
142+
auto str = rewriter.create<sv::ConstantStrOp>(
143+
loc, op.getFormatString());
144+
auto call = rewriter.create<sv::SystemFunctionOp>(
145+
loc, tmpResultType, "value$plusargs",
146+
ArrayRef<Value>{str, regv});
147+
auto test = rewriter.create<comb::ICmpOp>(
148+
loc, comb::ICmpPredicate::ne, call, zero32, true);
149+
rewriter.create<sv::BPAssignOp>(loc, regf, test);
150+
});
151+
});
130152
});
131153

132154
auto readf = rewriter.create<sv::ReadInOutOp>(loc, regf);
@@ -316,6 +338,7 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase<SimToSVPass> {
316338
lowerDPIFunc.lower(func);
317339

318340
std::atomic<bool> usedSynthesisMacro = false;
341+
std::atomic<bool> usedUPFSimMacro = false;
319342
auto lowerModule = [&](hw::HWModuleOp module) {
320343
SimConversionState state;
321344
ConversionTarget target(*context);
@@ -343,6 +366,8 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase<SimToSVPass> {
343366

344367
if (state.usedSynthesisMacro)
345368
usedSynthesisMacro = true;
369+
if (state.usedUPFSimMacro)
370+
usedUPFSimMacro = true;
346371
return result;
347372
};
348373

@@ -363,6 +388,20 @@ struct SimToSVPass : public circt::impl::LowerSimToSVBase<SimToSVPass> {
363388
builder.create<sv::MacroDeclOp>("SYNTHESIS");
364389
}
365390
}
391+
392+
if (usedUPFSimMacro) {
393+
Operation *op = circuit.lookupSymbol("UPF_SIMULATION");
394+
if (op) {
395+
if (!isa<sv::MacroDeclOp>(op)) {
396+
op->emitOpError("should be a macro declaration");
397+
return signalPassFailure();
398+
}
399+
} else {
400+
auto builder = ImplicitLocOpBuilder::atBlockBegin(
401+
UnknownLoc::get(context), circuit.getBody());
402+
builder.create<sv::MacroDeclOp>("UPF_SIMULATION");
403+
}
404+
}
366405
}
367406
};
368407
} // anonymous namespace

test/Conversion/SimToSV/plusargs.mlir

+15-6
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,21 @@ hw.module @plusargs_value(out test: i1, out value: i5) {
2626
// CHECK-SAME: emitAsComment
2727
// CHECK-NEXT: sv.assign [[BAR_FOUND_DECL]], %false
2828
// CHECK-NEXT: } else {
29-
// CHECK-NEXT: sv.initial {
30-
// CHECK-NEXT: %c0_i32 = hw.constant 0 : i32
31-
// CHECK-NEXT: [[BAR_STR:%.*]] = sv.constantStr "bar"
32-
// CHECK-NEXT: [[TMP:%.*]] = sv.system "value$plusargs"([[BAR_STR]], [[BAR_VALUE_DECL]])
33-
// CHECK-NEXT: [[TMP2:%.*]] = comb.icmp bin ne [[TMP]], %c0_i32
34-
// CHECK-NEXT: sv.bpassign [[BAR_FOUND_DECL]], [[TMP2]]
29+
// CHECK-NEXT: sv.ifdef @UPF_SIMULATION {
30+
// CHECK-NEXT: %c0_i5 = hw.constant 0 : i5
31+
// CHECK-NEXT: sv.assign [[BAR_VALUE_DECL]], %c0_i5 {sv.attributes = [
32+
// CHECK-SAME: #sv.attribute<"This dummy assignment exists to avoid undriven lint warnings
33+
// CHECK-SAME: emitAsComment
34+
// CHECK-NEXT: %false = hw.constant false
35+
// CHECK-NEXT: sv.assign [[BAR_FOUND_DECL]], %false
36+
// CHECK-NEXT: } else {
37+
// CHECK-NEXT: sv.initial {
38+
// CHECK-NEXT: %c0_i32 = hw.constant 0 : i32
39+
// CHECK-NEXT: [[BAR_STR:%.*]] = sv.constantStr "bar"
40+
// CHECK-NEXT: [[TMP:%.*]] = sv.system "value$plusargs"([[BAR_STR]], [[BAR_VALUE_DECL]])
41+
// CHECK-NEXT: [[TMP2:%.*]] = comb.icmp bin ne [[TMP]], %c0_i32
42+
// CHECK-NEXT: sv.bpassign [[BAR_FOUND_DECL]], [[TMP2]]
43+
// CHECK-NEXT: }
3544
// CHECK-NEXT: }
3645
// CHECK-NEXT: }
3746
// CHECK-NEXT: [[BAR_FOUND:%.*]] = sv.read_inout [[BAR_FOUND_DECL]]

test/firtool/plusargs.fir

+10-5
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,16 @@ circuit PlusArgTest:
2929
; CHECK-NEXT: sv.assign [[RESULT_BAR_REG]], %z_i32 {sv.attributes = [#sv.attribute<"This dummy assignment exists to avoid undriven lint warnings (e.g., Verilator UNDRIVEN).", emitAsComment>]} : i32
3030
; CHECK-NEXT: sv.assign [[FOUND_BAR_REG]], %false : i1
3131
; CHECK-NEXT: } else {
32-
; CHECK-NEXT: sv.initial {
33-
; CHECK-NEXT: [[FORMAT_BAR:%.+]] = sv.constantStr "foo=%d"
34-
; CHECK-NEXT: [[TMP_BAR:%.+]] = sv.system "value$plusargs"([[FORMAT_BAR]], [[RESULT_BAR_REG]]) : (!hw.string, !hw.inout<i32>) -> i32
35-
; CHECK-NEXT: [[FOUND_BAR_VAL:%.+]] = comb.icmp bin ne [[TMP_BAR]], %c0_i32 : i32
36-
; CHECK-NEXT: sv.bpassign [[FOUND_BAR_REG]], [[FOUND_BAR_VAL]] : i1
32+
; CHECK-NEXT: sv.ifdef @UPF_SIMULATION {
33+
; CHECK-NEXT: sv.assign [[RESULT_BAR_REG]], %c0_i32 {sv.attributes = [#sv.attribute<"This dummy assignment exists to avoid undriven lint warnings (e.g., Verilator UNDRIVEN).", emitAsComment>]} : i32
34+
; CHECK-NEXT: sv.assign [[FOUND_BAR_REG]], %false : i1
35+
; CHECK-NEXT: } else {
36+
; CHECK-NEXT: sv.initial {
37+
; CHECK-NEXT: [[FORMAT_BAR:%.+]] = sv.constantStr "foo=%d"
38+
; CHECK-NEXT: [[TMP_BAR:%.+]] = sv.system "value$plusargs"([[FORMAT_BAR]], [[RESULT_BAR_REG]]) : (!hw.string, !hw.inout<i32>) -> i32
39+
; CHECK-NEXT: [[FOUND_BAR_VAL:%.+]] = comb.icmp bin ne [[TMP_BAR]], %c0_i32 : i32
40+
; CHECK-NEXT: sv.bpassign [[FOUND_BAR_REG]], [[FOUND_BAR_VAL]] : i1
41+
; CHECK-NEXT: }
3742
; CHECK-NEXT: }
3843
; CHECK-NEXT: }
3944
; CHECK-NEXT: [[FOUND_BAR:%.+]] = sv.read_inout [[FOUND_BAR_REG]] : !hw.inout<i1>

0 commit comments

Comments
 (0)