Skip to content

Commit ec313d3

Browse files
committed
[Moore][Sim][SV] Add \$strobe[boh] lowering via sim.defer
Implement the SV `\$strobe[boh]`system tasks. - Add `moore.builtin.strobe` op in the Moore dialect to represent `$strobe[boh] - Add `sim.defer`op in the Sim dialect: a procedural region who schedules its body in the postponed region. Underlying primitive for `$strobe`, `$fstrobe`, `$monitor`, and VHDL postponed processes. - Add `StrobeBIOpConverion` in MooreTocore lowering. - Add `sv.strobe` op to SV dialect, analogous to `sv.write` and wire it in SVVisitors.h and ExportVerilog to emit `$strove(...)` - Extend `lowerPrintFormattedProcToSV`in SimToSV to detect `sim.proc.print` inside `sim.defer`, and emit `sv.strobe`. - Add tests for each stage of the pipeline.
1 parent 3e54636 commit ec313d3

12 files changed

Lines changed: 199 additions & 3 deletions

File tree

include/circt/Dialect/Moore/MooreOps.td

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,6 +3039,23 @@ def DisplayBIOp : Builtin<"display"> {
30393039
let assemblyFormat = "$message attr-dict";
30403040
}
30413041

3042+
def StrobeBIOp : Builtin<"strobe"> {
3043+
let summary = "Display formatted values at end of simulation timestep";
3044+
let description = [{
3045+
Schedules a display of the formatted message in the Postponed region of the
3046+
current simulation time, after all Active and NBA updates have settled.
3047+
The format string is evaluated at the time the body execute,
3048+
not at the time `$strobe` is called.
3049+
Corresponds to `$strobe[boh]` system task.
3050+
Message formatting is handled by `moore.fmt.*` ops.
3051+
3052+
See IEEE 1800-2017 § 21.2.2 "Strobed monitoring".
3053+
}];
3054+
let arguments = (ins FormatStringType:$message);
3055+
let results = (outs);
3056+
let assemblyFormat = "$message attr-dict";
3057+
}
3058+
30423059
def SeverityInfo : I32EnumAttrCase<"Info", 0, "info">;
30433060
def SeverityWarning : I32EnumAttrCase<"Warning", 1, "warning">;
30443061
def SeverityError : I32EnumAttrCase<"Error", 2, "error">;

include/circt/Dialect/SV/SVStatements.td

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,17 @@ def WriteOp : SVOp<"write", [ProceduralOp]> {
528528
}];
529529
}
530530

531+
def StrobeOp : SVOp<"strobe", [ProceduralOp]> {
532+
let summary = "'$strobe' statement";
533+
let arguments = (ins StrAttr:$format_string,
534+
Variadic<AnyType>:$substitutions);
535+
let results = (outs);
536+
let assemblyFormat = [{
537+
$format_string attr-dict (`(` $substitutions^ `)` `:`
538+
qualified(type($substitutions)))?
539+
}];
540+
}
541+
531542
def FWriteOp : SVOp<"fwrite", [ProceduralOp]> {
532543
let summary = "'$fwrite' statement";
533544

include/circt/Dialect/SV/SVVisitors.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Visitor {
4040
AlwaysCombOp, AlwaysFFOp, InitialOp, CaseOp,
4141
// Other Statements.
4242
AssignOp, BPAssignOp, PAssignOp, ForceOp, ReleaseOp, AliasOp,
43-
WriteOp, FWriteOp, FFlushOp, SystemFunctionOp, VerbatimOp,
43+
WriteOp, StrobeOp, FWriteOp, FFlushOp, SystemFunctionOp, VerbatimOp,
4444
MacroRefOp, FuncCallOp, FuncCallProceduralOp, ReturnOp, IncludeOp,
4545
MacroErrorOp,
4646
// Type declarations.
@@ -137,6 +137,7 @@ class Visitor {
137137
HANDLE(ReleaseOp, Unhandled);
138138
HANDLE(AliasOp, Unhandled);
139139
HANDLE(WriteOp, Unhandled);
140+
HANDLE(StrobeOp, Unhandled);
140141
HANDLE(FWriteOp, Unhandled);
141142
HANDLE(FFlushOp, Unhandled);
142143
HANDLE(SystemFunctionOp, Unhandled);

include/circt/Dialect/Sim/SimOps.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,20 @@ def TriggeredOp : SimOp<"triggered", [
12121212
];
12131213
}
12141214

1215+
def DeferOp : SimOp<"defer", [
1216+
SingleBlock, NoTerminator, ProceduralOp, ProceduralRegion]> {
1217+
let summary = "Execute a region at the end of the current simulation time";
1218+
let description = [{
1219+
Schedules its body for execution in the Postponed region of the current
1220+
simulation time.
1221+
}];
1222+
let regions = (region SizedRegion<1>:$body);
1223+
let assemblyFormat = "$body attr-dict";
1224+
let extraClassDeclaration = [{
1225+
Block *getBodyBlock() { return &getBody().front(); }
1226+
}];
1227+
}
1228+
12151229
//===----------------------------------------------------------------------===//
12161230
// File I/O
12171231
//===----------------------------------------------------------------------===//

lib/Conversion/ExportVerilog/ExportVerilog.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4113,6 +4113,7 @@ class StmtEmitter : public EmitterBase,
41134113
emitFormattedWriteLikeOp(OpTy op, StringRef callee, StringRef formatString,
41144114
ValueRange substitutions, EmitPrefixFn emitPrefix);
41154115
LogicalResult visitSV(WriteOp op);
4116+
LogicalResult visitSV(StrobeOp op);
41164117
LogicalResult visitSV(FWriteOp op);
41174118
LogicalResult visitSV(FFlushOp op);
41184119
LogicalResult visitSV(VerbatimOp op);
@@ -4682,6 +4683,12 @@ LogicalResult StmtEmitter::visitSV(WriteOp op) {
46824683
[&](SmallPtrSetImpl<Operation *> &) {});
46834684
}
46844685

4686+
LogicalResult StmtEmitter::visitSV(StrobeOp op) {
4687+
return emitFormattedWriteLikeOp(op, "$strobe(", op.getFormatString(),
4688+
op.getSubstitutions(),
4689+
[&](SmallPtrSetImpl<Operation *> &) {});
4690+
}
4691+
46854692
LogicalResult StmtEmitter::visitSV(FWriteOp op) {
46864693
return emitFormattedWriteLikeOp(op, "$fwrite(", op.getFormatString(),
46874694
op.getSubstitutions(),

lib/Conversion/ImportVerilog/Statements.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,11 +1006,12 @@ struct StmtVisitor {
10061006
}
10071007

10081008
// Display and Write Tasks (`$display[boh]?` or `$write[boh]?` or
1009-
// `$fdisplay[boh]?` or `$fwrite[boh]?`)
1009+
// `$fdisplay[boh]?` or `$fwrite[boh]? or `$strobe[boh]?`)
10101010

10111011
using moore::IntFormat;
10121012
bool isDisplay = false;
10131013
bool isFDisplay = false;
1014+
bool isStrobe = false;
10141015
bool appendNewline = false;
10151016
IntFormat defaultFormat = IntFormat::Decimal;
10161017
switch (nameId) {
@@ -1082,6 +1083,25 @@ struct StmtVisitor {
10821083
isFDisplay = true;
10831084
defaultFormat = IntFormat::HexLower;
10841085
break;
1086+
case ksn::Strobe:
1087+
isStrobe = true;
1088+
appendNewline = true;
1089+
break;
1090+
case ksn::StrobeB:
1091+
isStrobe = true;
1092+
appendNewline = true;
1093+
defaultFormat = IntFormat::Binary;
1094+
break;
1095+
case ksn::StrobeO:
1096+
isStrobe = true;
1097+
appendNewline = true;
1098+
defaultFormat = IntFormat::Octal;
1099+
break;
1100+
case ksn::StrobeH:
1101+
isStrobe = true;
1102+
appendNewline = true;
1103+
defaultFormat = IntFormat::HexLower;
1104+
break;
10851105
default:
10861106
break;
10871107
}
@@ -1116,6 +1136,17 @@ struct StmtVisitor {
11161136
return true;
11171137
}
11181138

1139+
if (isStrobe) {
1140+
auto message =
1141+
context.convertFormatString(args, loc, defaultFormat, appendNewline);
1142+
if (failed(message))
1143+
return failure();
1144+
if (*message == Value{})
1145+
return true;
1146+
moore::StrobeBIOp::create(builder, loc, *message);
1147+
return true;
1148+
}
1149+
11191150
// Severity Tasks
11201151
using moore::Severity;
11211152
std::optional<Severity> severity;

lib/Conversion/MooreToCore/MooreToCore.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2966,6 +2966,21 @@ struct FDisplayBIOpConversion : public OpConversionPattern<FDisplayBIOp> {
29662966
}
29672967
};
29682968

2969+
struct StrobeBIOpConversion : public OpConversionPattern<StrobeBIOp> {
2970+
using OpConversionPattern::OpConversionPattern;
2971+
2972+
LogicalResult
2973+
matchAndRewrite(StrobeBIOp op, OpAdaptor adaptor,
2974+
ConversionPatternRewriter &rewriter) const override {
2975+
auto loc = op.getLoc();
2976+
auto deferOp = sim::DeferOp::create(rewriter, loc);
2977+
rewriter.createBlock(&deferOp.getBody());
2978+
sim::PrintFormattedProcOp::create(rewriter, loc, adaptor.getMessage());
2979+
rewriter.eraseOp(op);
2980+
return success();
2981+
}
2982+
};
2983+
29692984
struct FOpenBIOpConversion : public OpConversionPattern<FOpenBIOp> {
29702985
using OpConversionPattern::OpConversionPattern;
29712986
LogicalResult
@@ -3575,6 +3590,7 @@ static void populateOpConversion(ConversionPatternSet &patterns,
35753590
FormatRealOpConversion,
35763591
DisplayBIOpConversion,
35773592
FDisplayBIOpConversion,
3593+
StrobeBIOpConversion,
35783594

35793595
// File I/O operations
35803596
FOpenBIOpConversion,

lib/Conversion/SimToSV/SimToSV.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,7 @@ LogicalResult lowerPrintFormattedProcToSV(hw::HWModuleOp module,
815815
SmallVector<GetFileOp> getFileOps;
816816
SmallVector<PrintFormattedProcOp> printOps;
817817
SmallVector<Operation *, 8> cleanupSeeds;
818+
llvm::SetVector<sim::DeferOp> deferOpsToInline;
818819
module.walk([&](Operation *op) {
819820
if (auto getFileOp = dyn_cast<GetFileOp>(op))
820821
getFileOps.push_back(getFileOp);
@@ -848,8 +849,12 @@ LogicalResult lowerPrintFormattedProcToSV(hw::HWModuleOp module,
848849
<< "while lowering format string";
849850
return failure();
850851
}
852+
bool isDeferred = isa<sim::DeferOp>(printOp->getParentOp());
851853
auto stream = printOp.getStream();
852-
if (!stream) {
854+
if (isDeferred) {
855+
sv::StrobeOp::create(builder, printOp.getLoc(), formatString, args);
856+
deferOpsToInline.insert(cast<sim::DeferOp>(printOp->getParentOp()));
857+
} else if (!stream) {
853858
// no stream is specified, emit sv.write.
854859
sv::WriteOp::create(builder, printOp.getLoc(), formatString, args);
855860
} else {
@@ -865,6 +870,14 @@ LogicalResult lowerPrintFormattedProcToSV(hw::HWModuleOp module,
865870

866871
cleanupDeadSimFmtOps(cleanupSeeds);
867872

873+
for (auto deferOp : deferOpsToInline) {
874+
auto *body = deferOp.getBodyBlock();
875+
auto *parentBlock = deferOp->getBlock();
876+
parentBlock->getOperations().splice(Block::iterator(deferOp),
877+
body->getOperations());
878+
deferOp.erase();
879+
}
880+
868881
return success();
869882
}
870883

test/Conversion/ExportVerilog/sv-dialect.mlir

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,23 @@ hw.module @write_task_test(in %clock : i1) {
19981998
}
19991999
}
20002000

2001+
// CHECK-LABEL: module strobe_task_test(
2002+
// CHECK: always_ff @(posedge clock) begin
2003+
// CHECK-NEXT: $strobe("stdout");
2004+
// CHECK-NEXT: $strobe("%d", 32'h2A);
2005+
// CHECK-NEXT: $strobe("%d %d", 32'h80000001, 32'h80000002);
2006+
// CHECK-NEXT: end
2007+
hw.module @strobe_task_test(in %clock : i1) {
2008+
sv.alwaysff(posedge %clock) {
2009+
%c0 = hw.constant 42 : i32
2010+
%c1 = hw.constant 0x80000001 : i32
2011+
%c2 = hw.constant 0x80000002 : i32
2012+
sv.strobe "stdout"
2013+
sv.strobe "%d"(%c0) : i32
2014+
sv.strobe "%d %d"(%c1, %c2) : i32, i32
2015+
}
2016+
}
2017+
20012018
// CHECK-LABEL: module fwrite_task_test(
20022019
// CHECK: always_ff @(posedge clock) begin
20032020
// CHECK-NEXT: $fwrite(32'h80000001, "stdout");

test/Conversion/ImportVerilog/builtins.sv

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,3 +846,42 @@ function void FileDisplayBuiltins(int fd, int x);
846846
$fdisplayh(fd, x);
847847

848848
endfunction
849+
850+
// IEEE 1800-2017 § 21.2.2 "Strobed monitoring"
851+
// CHECK-LABEL: func.func private @StrobeBuiltins(
852+
// CHECK-SAME: [[X:%.+]]: !moore.i32
853+
function void StrobeBuiltins(int x);
854+
// CHECK: [[TMP:%.+]] = moore.fmt.literal "\0A"
855+
// CHECK: moore.builtin.strobe [[TMP]]
856+
$strobe;
857+
858+
// CHECK: [[TMP1:%.+]] = moore.fmt.literal "hello"
859+
// CHECK: [[TMP2:%.+]] = moore.fmt.literal "\0A"
860+
// CHECK: [[TMP3:%.+]] = moore.fmt.concat ([[TMP1]], [[TMP2]])
861+
// CHECK: moore.builtin.strobe [[TMP3]]
862+
$strobe("hello");
863+
864+
// CHECK: [[TMP1:%.+]] = moore.fmt.int decimal [[X]], align right, pad space signed : i32
865+
// CHECK: [[TMP2:%.+]] = moore.fmt.literal "\0A"
866+
// CHECK: [[TMP3:%.+]] = moore.fmt.concat ([[TMP1]], [[TMP2]])
867+
// CHECK: moore.builtin.strobe [[TMP3]]
868+
$strobe(x);
869+
870+
// CHECK: [[TMP1:%.+]] = moore.fmt.int binary [[X]], align right, pad zero : i32
871+
// CHECK: [[TMP2:%.+]] = moore.fmt.literal "\0A"
872+
// CHECK: [[TMP3:%.+]] = moore.fmt.concat ([[TMP1]], [[TMP2]])
873+
// CHECK: moore.builtin.strobe [[TMP3]]
874+
$strobeb(x);
875+
876+
// CHECK: [[TMP1:%.+]] = moore.fmt.int octal [[X]], align right, pad zero : i32
877+
// CHECK: [[TMP2:%.+]] = moore.fmt.literal "\0A"
878+
// CHECK: [[TMP3:%.+]] = moore.fmt.concat ([[TMP1]], [[TMP2]])
879+
// CHECK: moore.builtin.strobe [[TMP3]]
880+
$strobeo(x);
881+
882+
// CHECK: [[TMP1:%.+]] = moore.fmt.int hex_lower [[X]], align right, pad zero : i32
883+
// CHECK: [[TMP2:%.+]] = moore.fmt.literal "\0A"
884+
// CHECK: [[TMP3:%.+]] = moore.fmt.concat ([[TMP1]], [[TMP2]])
885+
// CHECK: moore.builtin.strobe [[TMP3]]
886+
$strobeh(x);
887+
endfunction

0 commit comments

Comments
 (0)