Skip to content

Commit 81e6674

Browse files
committed
Add WidthCast operation to VAST.
Examples: 14'(42), MyWidth'(x), (MyWidth+1)'(100)
1 parent 7e73796 commit 81e6674

File tree

7 files changed

+278
-0
lines changed

7 files changed

+278
-0
lines changed

xls/codegen/vast/vast.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,48 @@ 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+
676718
VerilogFunction::VerilogFunction(std::string_view name, DataType* result_type,
677719
VerilogFile* file, const SourceInfo& loc)
678720
: VastNode(file, loc),

xls/codegen/vast/vast.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,26 @@ 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+
21622182
// Represents the definition of a Verilog function.
21632183
class VerilogFunction final : public VastNode {
21642184
public:

xls/codegen/vast/vast_test.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,55 @@ 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+
17711820
TEST_P(VastTest, ComplexConditional) {
17721821
VerilogFile f(GetFileType());
17731822
Module* m = f.AddModule("top", SourceInfo());

xls/public/c_api_symbols.txt

Lines changed: 2 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
@@ -351,6 +352,7 @@ xls_vast_verilog_file_make_unary
351352
xls_vast_verilog_file_make_unsized_one_literal
352353
xls_vast_verilog_file_make_unsized_x_literal
353354
xls_vast_verilog_file_make_unsized_zero_literal
355+
xls_vast_verilog_file_make_width_cast
354356
xls_vast_verilog_module_add_always_at
355357
xls_vast_verilog_module_add_always_comb
356358
xls_vast_verilog_module_add_always_ff

xls/public/c_api_vast.cc

Lines changed: 18 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,17 @@ 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+
630648
struct xls_vast_concat* xls_vast_verilog_file_make_concat(
631649
struct xls_vast_verilog_file* f, struct xls_vast_expression** elements,
632650
size_t element_count) {

xls/public/c_api_vast.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ 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+
308312
struct xls_vast_index* xls_vast_verilog_file_make_index_i64(
309313
struct xls_vast_verilog_file* f,
310314
struct xls_vast_indexable_expression* subject, int64_t index);
@@ -349,6 +353,8 @@ struct xls_vast_expression* xls_vast_parameter_ref_as_expression(
349353
struct xls_vast_parameter_ref* v);
350354
struct xls_vast_expression* xls_vast_localparam_ref_as_expression(
351355
struct xls_vast_localparam_ref* v);
356+
struct xls_vast_expression* xls_vast_indexable_expression_as_expression(
357+
struct xls_vast_indexable_expression* v);
352358

353359
struct xls_vast_indexable_expression*
354360
xls_vast_logic_ref_as_indexable_expression(

xls/public/c_api_vast_test.cc

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,147 @@ endmodule
389389
EXPECT_EQ(std::string_view{emitted}, kWantEmitted);
390390
}
391391

392+
TEST(XlsCApiTest, VastWidthCast) {
393+
const std::string_view kWantEmitted = R"(module top(
394+
input wire [7:0] a,
395+
input wire [3:0] b,
396+
output wire [7:0] out_literal,
397+
output wire [11:0] out_param,
398+
output wire [15:0] out_expr
399+
);
400+
parameter WidthParam = 12;
401+
assign out_literal = 8'(a + 1);
402+
assign out_param = WidthParam'({a, b});
403+
assign out_expr = (WidthParam + 4)'(a ^ {b, 2'h3});
404+
endmodule
405+
)";
406+
407+
xls_vast_verilog_file* f =
408+
xls_vast_make_verilog_file(xls_vast_file_type_verilog);
409+
ASSERT_NE(f, nullptr);
410+
absl::Cleanup free_file([&] { xls_vast_verilog_file_free(f); });
411+
412+
xls_vast_verilog_module* m = xls_vast_verilog_file_add_module(f, "top");
413+
ASSERT_NE(m, nullptr);
414+
415+
xls_vast_data_type* u8 =
416+
xls_vast_verilog_file_make_bit_vector_type(f, 8, /*is_signed=*/false);
417+
xls_vast_data_type* u4 =
418+
xls_vast_verilog_file_make_bit_vector_type(f, 4, /*is_signed=*/false);
419+
xls_vast_data_type* u12 =
420+
xls_vast_verilog_file_make_bit_vector_type(f, 12, /*is_signed=*/false);
421+
xls_vast_data_type* u16 =
422+
xls_vast_verilog_file_make_bit_vector_type(f, 16, /*is_signed=*/false);
423+
424+
xls_vast_logic_ref* a_ref = xls_vast_verilog_module_add_input(m, "a", u8);
425+
ASSERT_NE(a_ref, nullptr);
426+
xls_vast_logic_ref* b_ref = xls_vast_verilog_module_add_input(m, "b", u4);
427+
ASSERT_NE(b_ref, nullptr);
428+
xls_vast_logic_ref* out_literal_ref =
429+
xls_vast_verilog_module_add_output(m, "out_literal", u8);
430+
ASSERT_NE(out_literal_ref, nullptr);
431+
xls_vast_logic_ref* out_param_ref =
432+
xls_vast_verilog_module_add_output(m, "out_param", u12);
433+
ASSERT_NE(out_param_ref, nullptr);
434+
xls_vast_logic_ref* out_expr_ref =
435+
xls_vast_verilog_module_add_output(m, "out_expr", u16);
436+
ASSERT_NE(out_expr_ref, nullptr);
437+
438+
xls_vast_literal* literal_12 =
439+
xls_vast_verilog_file_make_plain_literal(f, 12);
440+
ASSERT_NE(literal_12, nullptr);
441+
xls_vast_parameter_ref* width_param = xls_vast_verilog_module_add_parameter(
442+
m, "WidthParam", xls_vast_literal_as_expression(literal_12));
443+
ASSERT_NE(width_param, nullptr);
444+
xls_vast_expression* width_param_expr =
445+
xls_vast_parameter_ref_as_expression(width_param);
446+
447+
xls_vast_literal* literal_8 = xls_vast_verilog_file_make_plain_literal(f, 8);
448+
ASSERT_NE(literal_8, nullptr);
449+
xls_vast_literal* literal_1 = xls_vast_verilog_file_make_plain_literal(f, 1);
450+
ASSERT_NE(literal_1, nullptr);
451+
xls_vast_expression* a_expr = xls_vast_logic_ref_as_expression(a_ref);
452+
ASSERT_NE(a_expr, nullptr);
453+
xls_vast_expression* a_plus_one = xls_vast_verilog_file_make_binary(
454+
f, a_expr, xls_vast_literal_as_expression(literal_1),
455+
xls_vast_operator_kind_add);
456+
ASSERT_NE(a_plus_one, nullptr);
457+
458+
xls_vast_expression* width_cast_literal =
459+
xls_vast_verilog_file_make_width_cast(
460+
f, xls_vast_literal_as_expression(literal_8), a_plus_one);
461+
ASSERT_NE(width_cast_literal, nullptr);
462+
xls_vast_continuous_assignment* assign_literal =
463+
xls_vast_verilog_file_make_continuous_assignment(
464+
f, xls_vast_logic_ref_as_expression(out_literal_ref),
465+
width_cast_literal);
466+
ASSERT_NE(assign_literal, nullptr);
467+
xls_vast_verilog_module_add_member_continuous_assignment(m, assign_literal);
468+
469+
std::vector<xls_vast_expression*> param_concat_args = {
470+
xls_vast_logic_ref_as_expression(a_ref),
471+
xls_vast_logic_ref_as_expression(b_ref)};
472+
xls_vast_concat* param_concat = xls_vast_verilog_file_make_concat(
473+
f, param_concat_args.data(), param_concat_args.size());
474+
ASSERT_NE(param_concat, nullptr);
475+
xls_vast_expression* width_cast_param = xls_vast_verilog_file_make_width_cast(
476+
f, width_param_expr, xls_vast_concat_as_expression(param_concat));
477+
ASSERT_NE(width_cast_param, nullptr);
478+
xls_vast_continuous_assignment* assign_param =
479+
xls_vast_verilog_file_make_continuous_assignment(
480+
f, xls_vast_logic_ref_as_expression(out_param_ref), width_cast_param);
481+
ASSERT_NE(assign_param, nullptr);
482+
xls_vast_verilog_module_add_member_continuous_assignment(m, assign_param);
483+
484+
xls_vast_literal* literal_4 = xls_vast_verilog_file_make_plain_literal(f, 4);
485+
ASSERT_NE(literal_4, nullptr);
486+
xls_vast_expression* complex_width = xls_vast_verilog_file_make_binary(
487+
f, width_param_expr, xls_vast_literal_as_expression(literal_4),
488+
xls_vast_operator_kind_add);
489+
ASSERT_NE(complex_width, nullptr);
490+
491+
struct xls_bits* bits = nullptr;
492+
char* error_out = nullptr;
493+
ASSERT_TRUE(
494+
xls_bits_make_ubits(/*bit_count=*/2, /*value=*/3, &error_out, &bits));
495+
ASSERT_EQ(error_out, nullptr);
496+
absl::Cleanup free_bits([&] { xls_bits_free(bits); });
497+
498+
xls_vast_literal* literal_2h3 = nullptr;
499+
ASSERT_TRUE(xls_vast_verilog_file_make_literal(
500+
f, bits, xls_format_preference_hex, /*emit_bit_count=*/true, &error_out,
501+
&literal_2h3));
502+
ASSERT_EQ(error_out, nullptr);
503+
ASSERT_NE(literal_2h3, nullptr);
504+
505+
std::vector<xls_vast_expression*> tail_concat_args = {
506+
xls_vast_logic_ref_as_expression(b_ref),
507+
xls_vast_literal_as_expression(literal_2h3)};
508+
xls_vast_concat* tail_concat = xls_vast_verilog_file_make_concat(
509+
f, tail_concat_args.data(), tail_concat_args.size());
510+
ASSERT_NE(tail_concat, nullptr);
511+
512+
xls_vast_expression* complex_value = xls_vast_verilog_file_make_binary(
513+
f, a_expr, xls_vast_concat_as_expression(tail_concat),
514+
xls_vast_operator_kind_bitwise_xor);
515+
ASSERT_NE(complex_value, nullptr);
516+
517+
xls_vast_expression* width_cast_complex =
518+
xls_vast_verilog_file_make_width_cast(f, complex_width, complex_value);
519+
ASSERT_NE(width_cast_complex, nullptr);
520+
xls_vast_continuous_assignment* assign_complex =
521+
xls_vast_verilog_file_make_continuous_assignment(
522+
f, xls_vast_logic_ref_as_expression(out_expr_ref),
523+
width_cast_complex);
524+
ASSERT_NE(assign_complex, nullptr);
525+
xls_vast_verilog_module_add_member_continuous_assignment(m, assign_complex);
526+
527+
char* emitted = xls_vast_verilog_file_emit(f);
528+
ASSERT_NE(emitted, nullptr);
529+
absl::Cleanup free_emitted([&] { xls_c_str_free(emitted); });
530+
EXPECT_EQ(std::string_view{emitted}, kWantEmitted);
531+
}
532+
392533
TEST(XlsCApiTest, VastUnsizedLiteralsParameters) {
393534
const std::string_view kWantEmitted = R"(module top;
394535
parameter P0 = '0;

0 commit comments

Comments
 (0)