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
77 changes: 49 additions & 28 deletions include/circt/Dialect/SV/SVStatements.td
Original file line number Diff line number Diff line change
Expand Up @@ -708,14 +708,9 @@ def ExitOp : SVOp<"exit", [ProceduralOp]> {
// Severity Message Tasks
//===----------------------------------------------------------------------===//

def FatalOp : SVOp<"fatal", [ProceduralOp]> {
let summary = "`$fatal` severity message task";
let description = [{
Generates a run-time fatal error which terminates the simulation with an
error code. Makes an implicit call to `$finish`, forwarding the `verbosity`
operand. If present, the optional message is printed with any additional
operands interpolated into the message string.
}];
/// Base class for fatal message operations
class FatalMessageOp<string mnemonic, list<Trait> traits = []> :
SVOp<mnemonic, traits> {
let arguments = (ins
VerbosityIntAttr:$verbosity,
OptionalAttr<StrAttr>:$message, Variadic<AnyType>:$substitutions);
Expand All @@ -733,9 +728,31 @@ def FatalOp : SVOp<"fatal", [ProceduralOp]> {
];
}

def FatalProceduralOp : FatalMessageOp<"fatal.procedural", [ProceduralOp]> {
let summary = "`$fatal` severity message task (run-time)";
let description = [{
Generates a run-time fatal error which terminates the simulation with an
error code. Makes an implicit call to `$finish`, forwarding the `verbosity`
operand. See IEEE 1800-2023 section 20.10 for more information.
If present, the optional message is printed with any additional
operands interpolated into the message string.
}];
}

def FatalOp : FatalMessageOp<"fatal", [NonProceduralOp]> {
let summary = "`$fatal` severity message task (elaboration-time)";
let description = [{
Generates an elaboration-time fatal error which terminates the elaboration
with an error code. Makes an implicit call to `$finish`, forwarding the
`verbosity` operand. See IEEE 1800-2023 section 20.11 for more information.
If present, the optional message is printed with any additional
operands interpolated into the message string.
}];
}

/// Commonalities between `ErrorOp`, `WarningOp`, and `InfoOp`.
class NonfatalMessageOp<string mnemonic, list<Trait> traits = []> :
SVOp<mnemonic, [ProceduralOp] # traits> {
SVOp<mnemonic, traits> {
string messageDescription = [{
If present, the optional message is printed with any additional operands
interpolated into the message string.
Expand All @@ -754,25 +771,29 @@ class NonfatalMessageOp<string mnemonic, list<Trait> traits = []> :
];
}

def ErrorOp : NonfatalMessageOp<"error"> {
let summary = "`$error` severity message task";
let description = [{
This system task indicates a run-time error.
}] # messageDescription;
}

def WarningOp : NonfatalMessageOp<"warning"> {
let summary = "`$warning` severity message task";
let description = [{
This system task indicates a run-time warning.
}] # messageDescription;
}

def InfoOp : NonfatalMessageOp<"info"> {
let summary = "`$info` severity message task";
let description = [{
This system task indicates a message with no specific severity.
}] # messageDescription;
foreach severity = ["Error", "Warning", "Info"] in {
defvar severityLower = !tolower(severity);

// Define procedural (run-time) severity message operations
def severity # "ProceduralOp" : NonfatalMessageOp<
severityLower # ".procedural", [ProceduralOp]> {
let summary = "`$" # severityLower # "` severity message task (run-time)";
let description = [{
This system task indicates a run-time }] # severityLower # [{. It must be
used within a procedural region (e.g., `initial`, `always` blocks).
Copy link
Member

Choose a reason for hiding this comment

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

Nit, can you include an 1800-2024 section citation for this and the other op?

See IEEE 1800-2023 section 20.10 for more information.
}] # messageDescription;
}

// Define non-procedural (elaboration-time) severity message operations
def severity # "Op" : NonfatalMessageOp<severityLower, [NonProceduralOp]> {
let summary = "`$" # severityLower # "` severity message task (elaboration-time)";
let description = [{
This system task indicates an elaboration-time }] # severityLower # [{. It must
be used outside of procedural regions and will be executed during elaboration.
See IEEE 1800-2023 section 20.11 for more information.
}] # messageDescription;
}
}

def DepositOp : SVOp<"nonstandard.deposit",
Expand Down
7 changes: 6 additions & 1 deletion include/circt/Dialect/SV/SVVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class Visitor {
// Simulator control tasks
StopOp, FinishOp, ExitOp,
// Severity message tasks
FatalOp, ErrorOp, WarningOp, InfoOp,
FatalProceduralOp, FatalOp, ErrorProceduralOp, WarningProceduralOp,
InfoProceduralOp, ErrorOp, WarningOp, InfoOp,
// Memory loading tasks
ReadMemOp,
// Generate statements
Expand Down Expand Up @@ -179,7 +180,11 @@ class Visitor {
HANDLE(ExitOp, Unhandled);

// Severity message tasks
HANDLE(FatalProceduralOp, Unhandled);
HANDLE(FatalOp, Unhandled);
HANDLE(ErrorProceduralOp, Unhandled);
HANDLE(WarningProceduralOp, Unhandled);
HANDLE(InfoProceduralOp, Unhandled);
HANDLE(ErrorOp, Unhandled);
HANDLE(WarningOp, Unhandled);
HANDLE(InfoOp, Unhandled);
Expand Down
47 changes: 39 additions & 8 deletions lib/Conversion/ExportVerilog/ExportVerilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4088,7 +4088,26 @@ class StmtEmitter : public EmitterBase,
std::optional<unsigned> verbosity,
StringAttr message,
ValueRange operands);

// Helper template for nonfatal message operations
template <typename OpTy>
LogicalResult emitNonfatalMessageOp(OpTy op, const char *taskName) {
return emitSeverityMessageTask(op, PPExtString(taskName), {},
op.getMessageAttr(), op.getSubstitutions());
}

// Helper template for fatal message operations
template <typename OpTy>
LogicalResult emitFatalMessageOp(OpTy op) {
return emitSeverityMessageTask(op, PPExtString("$fatal"), op.getVerbosity(),
op.getMessageAttr(), op.getSubstitutions());
}

LogicalResult visitSV(FatalProceduralOp op);
LogicalResult visitSV(FatalOp op);
LogicalResult visitSV(ErrorProceduralOp op);
LogicalResult visitSV(WarningProceduralOp op);
LogicalResult visitSV(InfoProceduralOp op);
LogicalResult visitSV(ErrorOp op);
LogicalResult visitSV(WarningOp op);
LogicalResult visitSV(InfoOp op);
Expand Down Expand Up @@ -4770,24 +4789,36 @@ StmtEmitter::emitSeverityMessageTask(Operation *op, PPExtString taskName,
return success();
}

LogicalResult StmtEmitter::visitSV(FatalProceduralOp op) {
return emitFatalMessageOp(op);
}

LogicalResult StmtEmitter::visitSV(FatalOp op) {
return emitSeverityMessageTask(op, PPExtString("$fatal"), op.getVerbosity(),
op.getMessageAttr(), op.getSubstitutions());
return emitFatalMessageOp(op);
}

LogicalResult StmtEmitter::visitSV(ErrorProceduralOp op) {
return emitNonfatalMessageOp(op, "$error");
}

LogicalResult StmtEmitter::visitSV(WarningProceduralOp op) {
return emitNonfatalMessageOp(op, "$warning");
}

LogicalResult StmtEmitter::visitSV(InfoProceduralOp op) {
return emitNonfatalMessageOp(op, "$info");
}

LogicalResult StmtEmitter::visitSV(ErrorOp op) {
return emitSeverityMessageTask(op, PPExtString("$error"), {},
op.getMessageAttr(), op.getSubstitutions());
return emitNonfatalMessageOp(op, "$error");
}

LogicalResult StmtEmitter::visitSV(WarningOp op) {
return emitSeverityMessageTask(op, PPExtString("$warning"), {},
op.getMessageAttr(), op.getSubstitutions());
return emitNonfatalMessageOp(op, "$warning");
}

LogicalResult StmtEmitter::visitSV(InfoOp op) {
return emitSeverityMessageTask(op, PPExtString("$info"), {},
op.getMessageAttr(), op.getSubstitutions());
return emitNonfatalMessageOp(op, "$info");
}

LogicalResult StmtEmitter::visitSV(ReadMemOp op) {
Expand Down
6 changes: 4 additions & 2 deletions lib/Conversion/FIRRTLToHW/LowerToHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5357,10 +5357,12 @@ LogicalResult FIRRTLLowering::lowerVerificationStatement(
addIfProceduralBlock(
sv::MacroRefExprOp::create(builder, boolType,
"ASSERT_VERBOSE_COND_"),
[&]() { sv::ErrorOp::create(builder, message, messageOps); });
[&]() {
sv::ErrorProceduralOp::create(builder, message, messageOps);
});
addIfProceduralBlock(
sv::MacroRefExprOp::create(builder, boolType, "STOP_COND_"),
[&]() { sv::FatalOp::create(builder); });
[&]() { sv::FatalProceduralOp::create(builder); });
});
});
});
Expand Down
4 changes: 2 additions & 2 deletions lib/Conversion/SimToSV/SimToSV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ static LogicalResult convert(ClockedTerminateOp op, PatternRewriter &rewriter) {
if (op.getSuccess())
rewriter.replaceOpWithNewOp<sv::FinishOp>(op, op.getVerbose());
else
rewriter.replaceOpWithNewOp<sv::FatalOp>(op, op.getVerbose());
rewriter.replaceOpWithNewOp<sv::FatalProceduralOp>(op, op.getVerbose());
return success();
}

Expand All @@ -180,7 +180,7 @@ static LogicalResult convert(TerminateOp op, PatternRewriter &rewriter) {
if (op.getSuccess())
rewriter.replaceOpWithNewOp<sv::FinishOp>(op, op.getVerbose());
else
rewriter.replaceOpWithNewOp<sv::FatalOp>(op, op.getVerbose());
rewriter.replaceOpWithNewOp<sv::FatalProceduralOp>(op, op.getVerbose());
return success();
}

Expand Down
9 changes: 5 additions & 4 deletions lib/Dialect/SV/Transforms/SVExtractTestCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,9 +550,9 @@ static bool isAssertOp(hw::HWSymbolCache &symCache, Operation *op) {
return true;

// If the format of assert is "ifElseFatal", PrintOp is lowered into
// ErrorOp. So we have to check message contents whether they encode
// verifications. See FIRParserAsserts for more details.
if (auto error = dyn_cast<ErrorOp>(op)) {
// ErrorOp or ErrorProceduralOp. So we have to check message contents whether
// they encode verifications. See FIRParserAsserts for more details.
if (auto error = dyn_cast<ErrorProceduralOp>(op)) {
if (auto message = error.getMessage())
return message->starts_with("assert:") ||
message->starts_with("assert failed (verification library)") ||
Expand All @@ -563,7 +563,8 @@ static bool isAssertOp(hw::HWSymbolCache &symCache, Operation *op) {
}

return isa<AssertOp, FinishOp, FWriteOp, FFlushOp, AssertConcurrentOp,
FatalOp, verif::AssertOp, verif::ClockedAssertOp>(op);
FatalProceduralOp, FatalOp, verif::AssertOp,
verif::ClockedAssertOp>(op);
}

static bool isCoverOp(hw::HWSymbolCache &symCache, Operation *op) {
Expand Down
12 changes: 6 additions & 6 deletions test/Conversion/ExportVerilog/disallow-local-vars.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ hw.module @side_effect_expr(in %clock: i1, out a: i1, out a2: i1) {
// CHECK: if (INLINE_OK)
// DISALLOW: if (INLINE_OK)
sv.if %0 {
sv.fatal 1
sv.fatal.procedural 1
}

// This should go through a reg when in "disallow" mode.
Expand All @@ -36,7 +36,7 @@ hw.module @side_effect_expr(in %clock: i1, out a: i1, out a2: i1) {
// DISALLOW: if ([[SE_REG]])
%1 = sv.verbatim.expr.se "SIDE_EFFECT" : () -> i1
sv.if %1 {
sv.fatal 1
sv.fatal.procedural 1
}
}
}
Expand Down Expand Up @@ -75,7 +75,7 @@ hw.module @hoist_expressions(in %clock: i1, in %x: i8, in %y: i8, in %z: i8) {
// DISALLOW: $fwrite(32'h80000002, "Hi %x\n", _GEN * z);
%2 = comb.mul %0, %z : i8
sv.fwrite %fd, "Hi %x\0A"(%2) : i8
sv.fatal 1
sv.fatal.procedural 1
}
}

Expand All @@ -94,7 +94,7 @@ hw.module @hoist_expressions(in %clock: i1, in %x: i8, in %y: i8, in %z: i8) {
// CHECK: if (x + myWire == z)
// DISALLOW: if (x + myWire == z)
sv.if %4 {
sv.fatal 1
sv.fatal.procedural 1
}
}

Expand Down Expand Up @@ -188,7 +188,7 @@ hw.module @DefinedInDifferentBlock(in %a: i1, in %b: i1) {
%0 = comb.icmp eq %a, %b : i1
sv.initial {
sv.if %0 {
sv.error "error"
sv.error.procedural "error"
}
}
}
Expand All @@ -208,7 +208,7 @@ hw.module @TemporaryWireAtDifferentBlock(in %a: i1, out b: i1) {
%1 = comb.add %0, %0 : i1
sv.initial {
sv.if %0 {
sv.error "error"
sv.error.procedural "error"
}
}
%0 = comb.shl %a, %a : i1
Expand Down
Loading