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
50 changes: 50 additions & 0 deletions xls/codegen/vast/vast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,56 @@ std::string ModulePort::ToString() const {
xls::verilog::ToString(direction), name());
}

// Returns true if the given string looks like an identifier or keyword. Escaped
// identifiers are not handled.
static bool IsDigitsOrIdentifier(std::string_view s) {
if (s.empty()) {
return false;
}

bool all_digits = true;
for (char ch : s) {
if (!absl::ascii_isdigit(ch)) {
all_digits = false;
break;
}
}
if (all_digits) {
return true;
}

const char first = s.front();
if (!absl::ascii_isalpha(first) && first != '_') {
return false;
}
for (char ch : s.substr(1)) {
if (!absl::ascii_isalnum(ch) && ch != '_' && ch != '$') {
return false;
}
}
return true;
}

std::string WidthCast::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
LineInfoEnd(line_info, this);
std::string width_expr = width_->Emit(line_info);
if (IsDigitsOrIdentifier(width_expr)) {
// Parentheses are not needed for digits or identifiers. This is purely
// cosmetic as parentheses are always correct to emit.
return absl::StrFormat("%s'(%s)", width_expr, value_->Emit(line_info));
}
return absl::StrFormat("(%s)'(%s)", width_expr, value_->Emit(line_info));
}

std::string TypeCast::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
LineInfoEnd(line_info, this);
// Unlike WidthCast, the type must never be wrapped in parentheses.
return absl::StrFormat("%s'(%s)", type_->Emit(line_info),
value_->Emit(line_info));
}

VerilogFunction::VerilogFunction(std::string_view name, DataType* result_type,
VerilogFile* file, const SourceInfo& loc)
: VastNode(file, loc),
Expand Down
38 changes: 38 additions & 0 deletions xls/codegen/vast/vast.h
Original file line number Diff line number Diff line change
Expand Up @@ -2159,6 +2159,44 @@ class UnsignedCast final : public SystemFunctionCall {
: SystemFunctionCall("unsigned", {value}, file, loc) {}
};

// A SystemVerilog cast-to-width expression. Examples:
// 17'(42)
// MyParam'(MyOtherParam + 2)
// (MyParam + 1)'(x)
class WidthCast final : public Expression {
public:
WidthCast(Expression* width, Expression* value, VerilogFile* file,
const SourceInfo& loc)
: Expression(file, loc), width_(width), value_(value) {}

std::string Emit(LineInfo* line_info) const final;

Expression* width() const { return width_; }
Expression* value() const { return value_; }

private:
Expression* width_;
Expression* value_;
};

// A SystemVerilog cast-to-type expression. Examples:
// int'(42)
// my_pkg::my_type_t'(MyOtherParam + 2)
class TypeCast final : public Expression {
public:
TypeCast(DataType* type, Expression* value, VerilogFile* file,
const SourceInfo& loc)
: Expression(file, loc), type_(type), value_(value) {}

std::string Emit(LineInfo* line_info) const final;
DataType* type() const { return type_; }
Expression* value() const { return value_; }

private:
DataType* type_;
Expression* value_;
};

// Represents the definition of a Verilog function.
class VerilogFunction final : public VastNode {
public:
Expand Down
92 changes: 90 additions & 2 deletions xls/codegen/vast/vast_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
#include <utility>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/types/span.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "xls/common/status/matchers.h"
#include "xls/ir/bits.h"
#include "xls/ir/fileno.h"
Expand Down Expand Up @@ -1768,6 +1768,94 @@ TEST_P(VastTest, SignedOperation) {
endmodule)");
}

TEST_P(VastTest, WidthCastEmission) {
const SourceInfo si;
VerilogFile f(GetFileType());
Module* m = f.AddModule("top", si);
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * a,
m->AddInput("a", f.BitVectorType(8, si), si));
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * b,
m->AddInput("b", f.BitVectorType(4, si), si));
XLS_ASSERT_OK_AND_ASSIGN(
LogicRef * out_literal,
m->AddOutput("out_literal", f.BitVectorType(8, si), si));
XLS_ASSERT_OK_AND_ASSIGN(
LogicRef * out_param,
m->AddOutput("out_param", f.BitVectorType(12, si), si));
XLS_ASSERT_OK_AND_ASSIGN(
LogicRef * out_expr,
m->AddOutput("out_expr", f.BitVectorType(16, si), si));

ParameterRef* width_param =
m->AddParameter("WidthParam", f.PlainLiteral(12, si), si);

m->Add<ContinuousAssignment>(
si, out_literal,
f.Make<WidthCast>(si, f.PlainLiteral(8, si),
f.Add(a, f.PlainLiteral(1, si), si)));
m->Add<ContinuousAssignment>(
si, out_param, f.Make<WidthCast>(si, width_param, f.Concat({a, b}, si)));

Expression* complex_width = f.Add(width_param, f.PlainLiteral(4, si), si);
Expression* complex_value =
f.BitwiseXor(a, f.Concat({b, f.Literal(3, 2, si)}, si), si);
m->Add<ContinuousAssignment>(
si, out_expr, f.Make<WidthCast>(si, complex_width, complex_value));

EXPECT_EQ(m->Emit(nullptr),
R"(module top(
input wire [7:0] a,
input wire [3:0] b,
output wire [7:0] out_literal,
output wire [11:0] out_param,
output wire [15:0] out_expr
);
parameter WidthParam = 12;
assign out_literal = 8'(a + 1);
assign out_param = WidthParam'({a, b});
assign out_expr = (WidthParam + 4)'(a ^ {b, 2'h3});
endmodule)");
}

TEST_P(VastTest, TypeCastEmission) {
const SourceInfo si;
VerilogFile f(GetFileType());
Module* m = f.AddModule("top", si);
XLS_ASSERT_OK_AND_ASSIGN(LogicRef * a,
m->AddInput("a", f.BitVectorType(8, si), si));
XLS_ASSERT_OK_AND_ASSIGN(
LogicRef * out_foo,
m->AddOutput("out_foo",
f.Make<ExternType>(si, f.BitVectorType(8, si), "foobar"),
si));
XLS_ASSERT_OK_AND_ASSIGN(
LogicRef * out_pkg,
m->AddOutput("out_pkg",
f.Make<ExternPackageType>(si, "my_pkg", "my_type_t"), si));

// assign out_foo = foobar'(a + 1);
m->Add<ContinuousAssignment>(
si, out_foo,
f.Make<TypeCast>(si,
f.Make<ExternType>(si, f.BitVectorType(8, si), "foobar"),
f.Add(a, f.PlainLiteral(1, si), si)));
// assign out_pkg = my_pkg::my_type_t'(a);
m->Add<ContinuousAssignment>(
si, out_pkg,
f.Make<TypeCast>(si, f.Make<ExternPackageType>(si, "my_pkg", "my_type_t"),
a));

EXPECT_EQ(m->Emit(nullptr),
R"(module top(
input wire [7:0] a,
output foobar out_foo,
output my_pkg::my_type_t out_pkg
);
assign out_foo = foobar'(a + 1);
assign out_pkg = my_pkg::my_type_t'(a);
endmodule)");
}

TEST_P(VastTest, ComplexConditional) {
VerilogFile f(GetFileType());
Module* m = f.AddModule("top", SourceInfo());
Expand Down
3 changes: 3 additions & 0 deletions xls/public/c_api_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ xls_vast_def_get_data_type
xls_vast_def_get_name
xls_vast_index_as_expression
xls_vast_index_as_indexable_expression
xls_vast_indexable_expression_as_expression
xls_vast_literal_as_expression
xls_vast_localparam_ref_as_expression
xls_vast_logic_ref_as_expression
Expand Down Expand Up @@ -347,10 +348,12 @@ xls_vast_verilog_file_make_scalar_type
xls_vast_verilog_file_make_slice
xls_vast_verilog_file_make_slice_i64
xls_vast_verilog_file_make_ternary
xls_vast_verilog_file_make_type_cast
xls_vast_verilog_file_make_unary
xls_vast_verilog_file_make_unsized_one_literal
xls_vast_verilog_file_make_unsized_x_literal
xls_vast_verilog_file_make_unsized_zero_literal
xls_vast_verilog_file_make_width_cast
xls_vast_verilog_module_add_always_at
xls_vast_verilog_module_add_always_comb
xls_vast_verilog_module_add_always_ff
Expand Down
29 changes: 29 additions & 0 deletions xls/public/c_api_vast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,13 @@ struct xls_vast_expression* xls_vast_localparam_ref_as_expression(
return reinterpret_cast<xls_vast_expression*>(cpp_expression);
}

struct xls_vast_expression* xls_vast_indexable_expression_as_expression(
struct xls_vast_indexable_expression* v) {
auto* cpp_v = reinterpret_cast<xls::verilog::IndexableExpression*>(v);
auto* cpp_expression = static_cast<xls::verilog::Expression*>(cpp_v);
return reinterpret_cast<xls_vast_expression*>(cpp_expression);
}

struct xls_vast_indexable_expression*
xls_vast_logic_ref_as_indexable_expression(
struct xls_vast_logic_ref* logic_ref) {
Expand Down Expand Up @@ -627,6 +634,28 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
return reinterpret_cast<xls_vast_expression*>(result);
}

struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
struct xls_vast_expression* value) {
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
auto* cpp_width = reinterpret_cast<xls::verilog::Expression*>(width);
auto* cpp_value = reinterpret_cast<xls::verilog::Expression*>(value);
xls::verilog::Expression* result = cpp_file->Make<xls::verilog::WidthCast>(
xls::SourceInfo(), cpp_width, cpp_value);
return reinterpret_cast<xls_vast_expression*>(result);
}

struct xls_vast_expression* xls_vast_verilog_file_make_type_cast(
struct xls_vast_verilog_file* f, struct xls_vast_data_type* type,
struct xls_vast_expression* value) {
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
auto* cpp_type = reinterpret_cast<xls::verilog::DataType*>(type);
auto* cpp_value = reinterpret_cast<xls::verilog::Expression*>(value);
xls::verilog::Expression* result = cpp_file->Make<xls::verilog::TypeCast>(
xls::SourceInfo(), cpp_type, cpp_value);
return reinterpret_cast<xls_vast_expression*>(result);
}

struct xls_vast_concat* xls_vast_verilog_file_make_concat(
struct xls_vast_verilog_file* f, struct xls_vast_expression** elements,
size_t element_count) {
Expand Down
11 changes: 11 additions & 0 deletions xls/public/c_api_vast.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,15 @@ struct xls_vast_expression* xls_vast_verilog_file_make_ternary(
struct xls_vast_expression* consequent,
struct xls_vast_expression* alternate);

struct xls_vast_expression* xls_vast_verilog_file_make_width_cast(
struct xls_vast_verilog_file* f, struct xls_vast_expression* width,
struct xls_vast_expression* value);

// Creates a SystemVerilog type cast expression: <type>'(<value>)
struct xls_vast_expression* xls_vast_verilog_file_make_type_cast(
struct xls_vast_verilog_file* f, struct xls_vast_data_type* type,
struct xls_vast_expression* value);

struct xls_vast_index* xls_vast_verilog_file_make_index_i64(
struct xls_vast_verilog_file* f,
struct xls_vast_indexable_expression* subject, int64_t index);
Expand Down Expand Up @@ -349,6 +358,8 @@ struct xls_vast_expression* xls_vast_parameter_ref_as_expression(
struct xls_vast_parameter_ref* v);
struct xls_vast_expression* xls_vast_localparam_ref_as_expression(
struct xls_vast_localparam_ref* v);
struct xls_vast_expression* xls_vast_indexable_expression_as_expression(
struct xls_vast_indexable_expression* v);

struct xls_vast_indexable_expression*
xls_vast_logic_ref_as_indexable_expression(
Expand Down
Loading