Skip to content

Commit c726a7f

Browse files
Merge pull request #3279 from xlsynth:meheff/2025-10-31-vast
PiperOrigin-RevId: 828612807
2 parents 113a1ee + b21dc67 commit c726a7f

File tree

7 files changed

+431
-0
lines changed

7 files changed

+431
-0
lines changed

xls/codegen/vast/vast.cc

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,56 @@ std::string ModulePort::ToString() const {
673673
xls::verilog::ToString(direction), name());
674674
}
675675

676+
// Returns true if the given string looks like an identifier or keyword. Escaped
677+
// identifiers are not handled.
678+
static bool IsDigitsOrIdentifier(std::string_view s) {
679+
if (s.empty()) {
680+
return false;
681+
}
682+
683+
bool all_digits = true;
684+
for (char ch : s) {
685+
if (!absl::ascii_isdigit(ch)) {
686+
all_digits = false;
687+
break;
688+
}
689+
}
690+
if (all_digits) {
691+
return true;
692+
}
693+
694+
const char first = s.front();
695+
if (!absl::ascii_isalpha(first) && first != '_') {
696+
return false;
697+
}
698+
for (char ch : s.substr(1)) {
699+
if (!absl::ascii_isalnum(ch) && ch != '_' && ch != '$') {
700+
return false;
701+
}
702+
}
703+
return true;
704+
}
705+
706+
std::string WidthCast::Emit(LineInfo* line_info) const {
707+
LineInfoStart(line_info, this);
708+
LineInfoEnd(line_info, this);
709+
std::string width_expr = width_->Emit(line_info);
710+
if (IsDigitsOrIdentifier(width_expr)) {
711+
// Parentheses are not needed for digits or identifiers. This is purely
712+
// cosmetic as parentheses are always correct to emit.
713+
return absl::StrFormat("%s'(%s)", width_expr, value_->Emit(line_info));
714+
}
715+
return absl::StrFormat("(%s)'(%s)", width_expr, value_->Emit(line_info));
716+
}
717+
718+
std::string TypeCast::Emit(LineInfo* line_info) const {
719+
LineInfoStart(line_info, this);
720+
LineInfoEnd(line_info, this);
721+
// Unlike WidthCast, the type must never be wrapped in parentheses.
722+
return absl::StrFormat("%s'(%s)", type_->Emit(line_info),
723+
value_->Emit(line_info));
724+
}
725+
676726
VerilogFunction::VerilogFunction(std::string_view name, DataType* result_type,
677727
VerilogFile* file, const SourceInfo& loc)
678728
: VastNode(file, loc),

xls/codegen/vast/vast.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,44 @@ class UnsignedCast final : public SystemFunctionCall {
21592159
: SystemFunctionCall("unsigned", {value}, file, loc) {}
21602160
};
21612161

2162+
// A SystemVerilog cast-to-width expression. Examples:
2163+
// 17'(42)
2164+
// MyParam'(MyOtherParam + 2)
2165+
// (MyParam + 1)'(x)
2166+
class WidthCast final : public Expression {
2167+
public:
2168+
WidthCast(Expression* width, Expression* value, VerilogFile* file,
2169+
const SourceInfo& loc)
2170+
: Expression(file, loc), width_(width), value_(value) {}
2171+
2172+
std::string Emit(LineInfo* line_info) const final;
2173+
2174+
Expression* width() const { return width_; }
2175+
Expression* value() const { return value_; }
2176+
2177+
private:
2178+
Expression* width_;
2179+
Expression* value_;
2180+
};
2181+
2182+
// A SystemVerilog cast-to-type expression. Examples:
2183+
// int'(42)
2184+
// my_pkg::my_type_t'(MyOtherParam + 2)
2185+
class TypeCast final : public Expression {
2186+
public:
2187+
TypeCast(DataType* type, Expression* value, VerilogFile* file,
2188+
const SourceInfo& loc)
2189+
: Expression(file, loc), type_(type), value_(value) {}
2190+
2191+
std::string Emit(LineInfo* line_info) const final;
2192+
DataType* type() const { return type_; }
2193+
Expression* value() const { return value_; }
2194+
2195+
private:
2196+
DataType* type_;
2197+
Expression* value_;
2198+
};
2199+
21622200
// Represents the definition of a Verilog function.
21632201
class VerilogFunction final : public VastNode {
21642202
public:

xls/codegen/vast/vast_test.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,94 @@ TEST_P(VastTest, SignedOperation) {
17681768
endmodule)");
17691769
}
17701770

1771+
TEST_P(VastTest, WidthCastEmission) {
1772+
const SourceInfo si;
1773+
VerilogFile f(GetFileType());
1774+
Module* m = f.AddModule("top", si);
1775+
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * a,
1776+
m->AddInput("a", f.BitVectorType(8, si), si));
1777+
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * b,
1778+
m->AddInput("b", f.BitVectorType(4, si), si));
1779+
XLS_ASSERT_OK_AND_ASSIGN(
1780+
LogicRef * out_literal,
1781+
m->AddOutput("out_literal", f.BitVectorType(8, si), si));
1782+
XLS_ASSERT_OK_AND_ASSIGN(
1783+
LogicRef * out_param,
1784+
m->AddOutput("out_param", f.BitVectorType(12, si), si));
1785+
XLS_ASSERT_OK_AND_ASSIGN(
1786+
LogicRef * out_expr,
1787+
m->AddOutput("out_expr", f.BitVectorType(16, si), si));
1788+
1789+
ParameterRef* width_param =
1790+
m->AddParameter("WidthParam", f.PlainLiteral(12, si), si);
1791+
1792+
m->Add<ContinuousAssignment>(
1793+
si, out_literal,
1794+
f.Make<WidthCast>(si, f.PlainLiteral(8, si),
1795+
f.Add(a, f.PlainLiteral(1, si), si)));
1796+
m->Add<ContinuousAssignment>(
1797+
si, out_param, f.Make<WidthCast>(si, width_param, f.Concat({a, b}, si)));
1798+
1799+
Expression* complex_width = f.Add(width_param, f.PlainLiteral(4, si), si);
1800+
Expression* complex_value =
1801+
f.BitwiseXor(a, f.Concat({b, f.Literal(3, 2, si)}, si), si);
1802+
m->Add<ContinuousAssignment>(
1803+
si, out_expr, f.Make<WidthCast>(si, complex_width, complex_value));
1804+
1805+
EXPECT_EQ(m->Emit(nullptr),
1806+
R"(module top(
1807+
input wire [7:0] a,
1808+
input wire [3:0] b,
1809+
output wire [7:0] out_literal,
1810+
output wire [11:0] out_param,
1811+
output wire [15:0] out_expr
1812+
);
1813+
parameter WidthParam = 12;
1814+
assign out_literal = 8'(a + 1);
1815+
assign out_param = WidthParam'({a, b});
1816+
assign out_expr = (WidthParam + 4)'(a ^ {b, 2'h3});
1817+
endmodule)");
1818+
}
1819+
1820+
TEST_P(VastTest, TypeCastEmission) {
1821+
const SourceInfo si;
1822+
VerilogFile f(GetFileType());
1823+
Module* m = f.AddModule("top", si);
1824+
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * a,
1825+
m->AddInput("a", f.BitVectorType(8, si), si));
1826+
XLS_ASSERT_OK_AND_ASSIGN(
1827+
LogicRef * out_foo,
1828+
m->AddOutput("out_foo",
1829+
f.Make<ExternType>(si, f.BitVectorType(8, si), "foobar"),
1830+
si));
1831+
XLS_ASSERT_OK_AND_ASSIGN(
1832+
LogicRef * out_pkg,
1833+
m->AddOutput("out_pkg",
1834+
f.Make<ExternPackageType>(si, "my_pkg", "my_type_t"), si));
1835+
1836+
// assign out_foo = foobar'(a + 1);
1837+
m->Add<ContinuousAssignment>(
1838+
si, out_foo,
1839+
f.Make<TypeCast>(si,
1840+
f.Make<ExternType>(si, f.BitVectorType(8, si), "foobar"),
1841+
f.Add(a, f.PlainLiteral(1, si), si)));
1842+
// assign out_pkg = my_pkg::my_type_t'(a);
1843+
m->Add<ContinuousAssignment>(
1844+
si, out_pkg,
1845+
f.Make<TypeCast>(si, f.Make<ExternPackageType>(si, "my_pkg", "my_type_t"),
1846+
a));
1847+
1848+
EXPECT_EQ(m->Emit(nullptr),
1849+
R"(module top(
1850+
input wire [7:0] a,
1851+
output foobar out_foo,
1852+
output my_pkg::my_type_t out_pkg
1853+
);
1854+
assign out_foo = foobar'(a + 1);
1855+
assign out_pkg = my_pkg::my_type_t'(a);
1856+
endmodule)");
1857+
}
1858+
17711859
TEST_P(VastTest, ComplexConditional) {
17721860
VerilogFile f(GetFileType());
17731861
Module* m = f.AddModule("top", SourceInfo());

xls/public/c_api_symbols.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ xls_vast_def_get_data_type
309309
xls_vast_def_get_name
310310
xls_vast_index_as_expression
311311
xls_vast_index_as_indexable_expression
312+
xls_vast_indexable_expression_as_expression
312313
xls_vast_literal_as_expression
313314
xls_vast_localparam_ref_as_expression
314315
xls_vast_logic_ref_as_expression
@@ -347,10 +348,12 @@ xls_vast_verilog_file_make_scalar_type
347348
xls_vast_verilog_file_make_slice
348349
xls_vast_verilog_file_make_slice_i64
349350
xls_vast_verilog_file_make_ternary
351+
xls_vast_verilog_file_make_type_cast
350352
xls_vast_verilog_file_make_unary
351353
xls_vast_verilog_file_make_unsized_one_literal
352354
xls_vast_verilog_file_make_unsized_x_literal
353355
xls_vast_verilog_file_make_unsized_zero_literal
356+
xls_vast_verilog_file_make_width_cast
354357
xls_vast_verilog_module_add_always_at
355358
xls_vast_verilog_module_add_always_comb
356359
xls_vast_verilog_module_add_always_ff

xls/public/c_api_vast.cc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,13 @@ struct xls_vast_expression* xls_vast_localparam_ref_as_expression(
543543
return reinterpret_cast<xls_vast_expression*>(cpp_expression);
544544
}
545545

546+
struct xls_vast_expression* xls_vast_indexable_expression_as_expression(
547+
struct xls_vast_indexable_expression* v) {
548+
auto* cpp_v = reinterpret_cast<xls::verilog::IndexableExpression*>(v);
549+
auto* cpp_expression = static_cast<xls::verilog::Expression*>(cpp_v);
550+
return reinterpret_cast<xls_vast_expression*>(cpp_expression);
551+
}
552+
546553
struct xls_vast_indexable_expression*
547554
xls_vast_logic_ref_as_indexable_expression(
548555
struct xls_vast_logic_ref* logic_ref) {
@@ -627,6 +634,28 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
627634
return reinterpret_cast<xls_vast_expression*>(result);
628635
}
629636

637+
struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
638+
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
639+
struct xls_vast_expression* value) {
640+
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
641+
auto* cpp_width = reinterpret_cast<xls::verilog::Expression*>(width);
642+
auto* cpp_value = reinterpret_cast<xls::verilog::Expression*>(value);
643+
xls::verilog::Expression* result = cpp_file->Make<xls::verilog::WidthCast>(
644+
xls::SourceInfo(), cpp_width, cpp_value);
645+
return reinterpret_cast<xls_vast_expression*>(result);
646+
}
647+
648+
struct xls_vast_expression* xls_vast_verilog_file_make_type_cast(
649+
struct xls_vast_verilog_file* f, struct xls_vast_data_type* type,
650+
struct xls_vast_expression* value) {
651+
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
652+
auto* cpp_type = reinterpret_cast<xls::verilog::DataType*>(type);
653+
auto* cpp_value = reinterpret_cast<xls::verilog::Expression*>(value);
654+
xls::verilog::Expression* result = cpp_file->Make<xls::verilog::TypeCast>(
655+
xls::SourceInfo(), cpp_type, cpp_value);
656+
return reinterpret_cast<xls_vast_expression*>(result);
657+
}
658+
630659
struct xls_vast_concat* xls_vast_verilog_file_make_concat(
631660
struct xls_vast_verilog_file* f, struct xls_vast_expression** elements,
632661
size_t element_count) {

xls/public/c_api_vast.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,15 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
305305
struct xls_vast_expression* consequent,
306306
struct xls_vast_expression* alternate);
307307

308+
struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
309+
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
310+
struct xls_vast_expression* value);
311+
312+
// Creates a SystemVerilog type cast expression: <type>'(<value>)
313+
struct xls_vast_expression* xls_vast_verilog_file_make_type_cast(
314+
struct xls_vast_verilog_file* f, struct xls_vast_data_type* type,
315+
struct xls_vast_expression* value);
316+
308317
struct xls_vast_index* xls_vast_verilog_file_make_index_i64(
309318
struct xls_vast_verilog_file* f,
310319
struct xls_vast_indexable_expression* subject, int64_t index);
@@ -349,6 +358,8 @@ struct xls_vast_expression* xls_vast_parameter_ref_as_expression(
349358
struct xls_vast_parameter_ref* v);
350359
struct xls_vast_expression* xls_vast_localparam_ref_as_expression(
351360
struct xls_vast_localparam_ref* v);
361+
struct xls_vast_expression* xls_vast_indexable_expression_as_expression(
362+
struct xls_vast_indexable_expression* v);
352363

353364
struct xls_vast_indexable_expression*
354365
xls_vast_logic_ref_as_indexable_expression(

0 commit comments

Comments
 (0)