Skip to content
Open
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
90 changes: 48 additions & 42 deletions lib/Conversion/ImportVerilog/Statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,47 +222,6 @@ struct StmtVisitor {
if (handled == true)
return success();
}

// According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a
// string" the first argument of $sformat/$swrite is its output; the
// other arguments work like a FormatString.
// In Moore we only support writing to a location if it is a reference;
// However, Section 21.3.3 explains that the output of $sformat/$swrite
// is assigned as if it were cast from a string literal (Section 5.9),
// so this implementation casts the string to the target value.
if (!call->getSubroutineName().compare("$sformat") ||
!call->getSubroutineName().compare("$swrite")) {

// Use the first argument as the output location
auto *lhsExpr = call->arguments().front();
// Format the second and all later arguments as a string
auto fmtValue =
context.convertFormatString(call->arguments().subspan(1), loc,
moore::IntFormat::Decimal, false);
if (failed(fmtValue))
return failure();
// Convert the FormatString to a StringType
auto strValue = moore::FormatStringToStringOp::create(builder, loc,
fmtValue.value());
// The Slang AST produces a `AssignmentExpression` for the first
// argument; the RHS of this expression is invalid though
// (`EmptyArgument`), so we only use the LHS of the
// `AssignmentExpression` and plug in the formatted string for the RHS.
if (auto assignExpr =
lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
auto lhs = context.convertLvalueExpression(assignExpr->left());
if (!lhs)
return failure();

auto convertedValue = context.materializeConversion(
cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
false, loc);
moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
return success();
} else {
return failure();
}
}
}

auto value = context.convertRvalueExpression(stmt.expr);
Expand Down Expand Up @@ -1006,11 +965,12 @@ struct StmtVisitor {
}

// Display and Write Tasks (`$display[boh]?` or `$write[boh]?` or
// `$fdisplay[boh]?` or `$fwrite[boh]?`)
// `$fdisplay[boh]?` or `$fwrite[boh]?` or `$swrite[boh]` or `$sformat`)

using moore::IntFormat;
bool isDisplay = false;
bool isFDisplay = false;
bool isSWrite = false;
bool appendNewline = false;
IntFormat defaultFormat = IntFormat::Decimal;
switch (nameId) {
Expand Down Expand Up @@ -1082,6 +1042,22 @@ struct StmtVisitor {
isFDisplay = true;
defaultFormat = IntFormat::HexLower;
break;
case ksn::SWrite:
case ksn::SFormat:
isSWrite = true;
break;
case ksn::SWriteB:
isSWrite = true;
defaultFormat = IntFormat::Binary;
break;
case ksn::SWriteO:
isSWrite = true;
defaultFormat = IntFormat::Octal;
break;
case ksn::SWriteH:
isSWrite = true;
defaultFormat = IntFormat::HexLower;
break;
default:
break;
}
Expand Down Expand Up @@ -1116,6 +1092,36 @@ struct StmtVisitor {
return true;
}

// According to IEEE 1800-2023 Section 21.3.3 "Formatting data to a
// string" the first argument of $sformat/$swrite is its output; the
// other arguments work like a FormatString.
// In Moore we only support writing to a location if it is a reference;
// However, Section 21.3.3 explains that the output of $sformat/$swrite
// is assigned as if it were cast from a string literal (Section 5.9),
// so this implementation casts the string to the target value.
if (isSWrite) {
auto fmtValue =
context.convertFormatString(args.subspan(1), loc, defaultFormat,
/*appendNewline=*/false);
if (failed(fmtValue))
return failure();
auto strValue =
moore::FormatStringToStringOp::create(builder, loc, *fmtValue);
auto *lhsExpr = args[0];
if (auto *assignExpr =
lhsExpr->as_if<slang::ast::AssignmentExpression>()) {
auto lhs = context.convertLvalueExpression(assignExpr->left());
if (!lhs)
return failure();
auto convertedValue = context.materializeConversion(
cast<moore::RefType>(lhs.getType()).getNestedType(), strValue,
false, loc);
moore::BlockingAssignOp::create(builder, loc, lhs, convertedValue);
return true;
}
return failure();
}

// Severity Tasks
using moore::Severity;
std::optional<Severity> severity;
Expand Down
20 changes: 20 additions & 0 deletions test/Conversion/ImportVerilog/basic.sv
Original file line number Diff line number Diff line change
Expand Up @@ -3632,6 +3632,26 @@ function automatic void Swrite(string testStr, string otherString, ref string ou
$swrite(logicVector, "%s %s", testStr, otherString);
endfunction

// CHECK-LABEL: func.func private @SwriteVariants(
// CHECK-SAME: [[X:%[^,]+]]: !moore.i32
// CHECK-SAME: [[OUT:%[^,]+]]: !moore.ref<string>
function automatic void SwriteVariants(int x, ref string outputString);
// CHECK: [[FMT1:%.+]] = moore.fmt.int binary [[X]], align right, pad zero : i32
// CHECK-NEXT: [[STR1:%.+]] = moore.fstring_to_string [[FMT1]]
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR1]] : string
$swriteb(outputString, x);

// CHECK: [[FMT2:%.+]] = moore.fmt.int octal [[X]], align right, pad zero : i32
// CHECK-NEXT: [[STR2:%.+]] = moore.fstring_to_string [[FMT2]]
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR2]] : string
$swriteo(outputString, x);

// CHECK: [[FMT3:%.+]] = moore.fmt.int hex_lower [[X]], align right, pad zero : i32
// CHECK-NEXT: [[STR3:%.+]] = moore.fstring_to_string [[FMT3]]
// CHECK-NEXT: moore.blocking_assign [[OUT]], [[STR3]] : string
$swriteh(outputString, x);
endfunction

// CHECK-LABEL: moore.module @ContinuousAssignment(
module ContinuousAssignment;
// CHECK-NEXT: [[A:%.+]] = moore.variable
Expand Down
Loading