Skip to content

Commit 5568cd3

Browse files
committed
Add WidthCast operation to VAST.
Examples: 14'(42), MyWidth'(x), (MyWidth+1)'(100)
1 parent 299880f commit 5568cd3

File tree

7 files changed

+266
-0
lines changed

7 files changed

+266
-0
lines changed

xls/codegen/vast/vast.cc

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

675+
static bool IsDigitsOrIdentifier(std::string_view s) {
676+
if (s.empty()) {
677+
return false;
678+
}
679+
680+
bool all_digits = true;
681+
for (char ch : s) {
682+
if (!absl::ascii_isdigit(ch)) {
683+
all_digits = false;
684+
break;
685+
}
686+
}
687+
if (all_digits) {
688+
return true;
689+
}
690+
691+
const char first = s.front();
692+
if (!absl::ascii_isalpha(first) && first != '_') {
693+
return false;
694+
}
695+
for (char ch : s.substr(1)) {
696+
if (!absl::ascii_isalnum(ch) && ch != '_') {
697+
return false;
698+
}
699+
}
700+
return true;
701+
}
702+
703+
std::string WidthCast::Emit(LineInfo* line_info) const {
704+
LineInfoStart(line_info, this);
705+
LineInfoEnd(line_info, this);
706+
std::string width_expr = width_->Emit(line_info);
707+
if (IsDigitsOrIdentifier(width_expr)) {
708+
// Parentheses are not needed for digits or identifiers.
709+
return absl::StrFormat("%s'(%s)", width_expr, value_->Emit(line_info));
710+
} else {
711+
return absl::StrFormat("(%s)'(%s)", width_expr, value_->Emit(line_info));
712+
}
713+
}
714+
675715
VerilogFunction::VerilogFunction(std::string_view name, DataType* result_type,
676716
VerilogFile* file, const SourceInfo& loc)
677717
: 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
@@ -1740,6 +1740,55 @@ TEST_P(VastTest, SignedOperation) {
17401740
endmodule)");
17411741
}
17421742

1743+
TEST_P(VastTest, WidthCastEmission) {
1744+
const SourceInfo si;
1745+
VerilogFile f(GetFileType());
1746+
Module* m = f.AddModule("top", si);
1747+
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * a,
1748+
m->AddInput("a", f.BitVectorType(8, si), si));
1749+
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * b,
1750+
m->AddInput("b", f.BitVectorType(4, si), si));
1751+
XLS_ASSERT_OK_AND_ASSIGN(
1752+
LogicRef * out_literal,
1753+
m->AddOutput("out_literal", f.BitVectorType(8, si), si));
1754+
XLS_ASSERT_OK_AND_ASSIGN(
1755+
LogicRef * out_param,
1756+
m->AddOutput("out_param", f.BitVectorType(12, si), si));
1757+
XLS_ASSERT_OK_AND_ASSIGN(
1758+
LogicRef * out_expr,
1759+
m->AddOutput("out_expr", f.BitVectorType(16, si), si));
1760+
1761+
ParameterRef* width_param =
1762+
m->AddParameter("WidthParam", f.PlainLiteral(12, si), si);
1763+
1764+
m->Add<ContinuousAssignment>(
1765+
si, out_literal,
1766+
f.Make<WidthCast>(si, f.PlainLiteral(8, si),
1767+
f.Add(a, f.PlainLiteral(1, si), si)));
1768+
m->Add<ContinuousAssignment>(
1769+
si, out_param, f.Make<WidthCast>(si, width_param, f.Concat({a, b}, si)));
1770+
1771+
Expression* complex_width = f.Add(width_param, f.PlainLiteral(4, si), si);
1772+
Expression* complex_value =
1773+
f.BitwiseXor(a, f.Concat({b, f.Literal(3, 2, si)}, si), si);
1774+
m->Add<ContinuousAssignment>(
1775+
si, out_expr, f.Make<WidthCast>(si, complex_width, complex_value));
1776+
1777+
EXPECT_EQ(m->Emit(nullptr),
1778+
R"(module top(
1779+
input wire [7:0] a,
1780+
input wire [3:0] b,
1781+
output wire [7:0] out_literal,
1782+
output wire [11:0] out_param,
1783+
output wire [15:0] out_expr
1784+
);
1785+
parameter WidthParam = 12;
1786+
assign out_literal = 8'(a + 1);
1787+
assign out_param = WidthParam'({a, b});
1788+
assign out_expr = (WidthParam + 4)'(a ^ {b, 2'h3});
1789+
endmodule)");
1790+
}
1791+
17431792
TEST_P(VastTest, ComplexConditional) {
17441793
VerilogFile f(GetFileType());
17451794
Module* m = f.AddModule("top", SourceInfo());

xls/public/c_api_symbols.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ xls_vast_verilog_file_make_unary
350350
xls_vast_verilog_file_make_unsized_one_literal
351351
xls_vast_verilog_file_make_unsized_x_literal
352352
xls_vast_verilog_file_make_unsized_zero_literal
353+
xls_vast_verilog_file_make_width_cast
353354
xls_vast_verilog_module_add_always_at
354355
xls_vast_verilog_module_add_always_ff
355356
xls_vast_verilog_module_add_input

xls/public/c_api_vast.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,17 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
605605
return reinterpret_cast<xls_vast_expression*>(result);
606606
}
607607

608+
struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
609+
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
610+
struct xls_vast_expression* value) {
611+
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
612+
auto* cpp_width = reinterpret_cast<xls::verilog::Expression*>(width);
613+
auto* cpp_value = reinterpret_cast<xls::verilog::Expression*>(value);
614+
xls::verilog::Expression* result = cpp_file->Make<xls::verilog::WidthCast>(
615+
xls::SourceInfo(), cpp_width, cpp_value);
616+
return reinterpret_cast<xls_vast_expression*>(result);
617+
}
618+
608619
struct xls_vast_concat* xls_vast_verilog_file_make_concat(
609620
struct xls_vast_verilog_file* f, struct xls_vast_expression** elements,
610621
size_t element_count) {

xls/public/c_api_vast.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
298298
struct xls_vast_expression* consequent,
299299
struct xls_vast_expression* alternate);
300300

301+
struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
302+
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
303+
struct xls_vast_expression* value);
304+
301305
struct xls_vast_index* xls_vast_verilog_file_make_index_i64(
302306
struct xls_vast_verilog_file* f,
303307
struct xls_vast_indexable_expression* subject, int64_t index);

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)