Skip to content
Draft
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
82 changes: 82 additions & 0 deletions xls/public/c_api_vast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,18 @@ struct xls_vast_statement* xls_vast_verilog_file_make_nonblocking_assignment(
return reinterpret_cast<xls_vast_statement*>(cpp_assignment);
}

struct xls_vast_statement* xls_vast_verilog_file_make_blocking_assignment(
struct xls_vast_verilog_file* f, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs) {
auto* cpp_file = reinterpret_cast<xls::verilog::VerilogFile*>(f);
auto* cpp_lhs = reinterpret_cast<xls::verilog::Expression*>(lhs);
auto* cpp_rhs = reinterpret_cast<xls::verilog::Expression*>(rhs);
xls::verilog::BlockingAssignment* cpp_assignment =
cpp_file->Make<xls::verilog::BlockingAssignment>(xls::SourceInfo(),
cpp_lhs, cpp_rhs);
return reinterpret_cast<xls_vast_statement*>(cpp_assignment);
}

struct xls_vast_statement_block* xls_vast_always_base_get_statement_block(
struct xls_vast_always_base* always_base) {
auto* cpp_always_base =
Expand All @@ -674,6 +686,76 @@ struct xls_vast_statement* xls_vast_statement_block_add_nonblocking_assignment(
return reinterpret_cast<xls_vast_statement*>(cpp_assignment);
}

struct xls_vast_statement* xls_vast_statement_block_add_blocking_assignment(
struct xls_vast_statement_block* block, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs) {
auto* cpp_block = reinterpret_cast<xls::verilog::StatementBlock*>(block);
auto* cpp_lhs = reinterpret_cast<xls::verilog::Expression*>(lhs);
auto* cpp_rhs = reinterpret_cast<xls::verilog::Expression*>(rhs);
xls::verilog::BlockingAssignment* cpp_assignment =
cpp_block->Add<xls::verilog::BlockingAssignment>(xls::SourceInfo(),
cpp_lhs, cpp_rhs);
return reinterpret_cast<xls_vast_statement*>(cpp_assignment);
}

struct xls_vast_conditional* xls_vast_statement_block_add_conditional(
struct xls_vast_statement_block* block, struct xls_vast_expression* cond) {
auto* cpp_block = reinterpret_cast<xls::verilog::StatementBlock*>(block);
auto* cpp_cond_expr = reinterpret_cast<xls::verilog::Expression*>(cond);
xls::verilog::Conditional* cpp_cond =
cpp_block->Add<xls::verilog::Conditional>(xls::SourceInfo(),
cpp_cond_expr);
return reinterpret_cast<xls_vast_conditional*>(cpp_cond);
}

struct xls_vast_statement_block* xls_vast_conditional_get_then_block(
struct xls_vast_conditional* cond) {
auto* cpp_cond = reinterpret_cast<xls::verilog::Conditional*>(cond);
return reinterpret_cast<xls_vast_statement_block*>(cpp_cond->consequent());
}

struct xls_vast_statement_block* xls_vast_conditional_add_else_if(
struct xls_vast_conditional* cond, struct xls_vast_expression* expr_cond) {
auto* cpp_cond = reinterpret_cast<xls::verilog::Conditional*>(cond);
auto* cpp_cond_expr = reinterpret_cast<xls::verilog::Expression*>(expr_cond);
xls::verilog::StatementBlock* block = cpp_cond->AddAlternate(cpp_cond_expr);
return reinterpret_cast<xls_vast_statement_block*>(block);
}

struct xls_vast_statement_block* xls_vast_conditional_add_else(
struct xls_vast_conditional* cond) {
auto* cpp_cond = reinterpret_cast<xls::verilog::Conditional*>(cond);
xls::verilog::StatementBlock* block = cpp_cond->AddAlternate(nullptr);
return reinterpret_cast<xls_vast_statement_block*>(block);
}

struct xls_vast_case_statement* xls_vast_statement_block_add_case(
struct xls_vast_statement_block* block,
struct xls_vast_expression* selector) {
auto* cpp_block = reinterpret_cast<xls::verilog::StatementBlock*>(block);
auto* cpp_selector = reinterpret_cast<xls::verilog::Expression*>(selector);
xls::verilog::Case* cpp_case =
cpp_block->Add<xls::verilog::Case>(xls::SourceInfo(), cpp_selector);
return reinterpret_cast<xls_vast_case_statement*>(cpp_case);
}

struct xls_vast_statement_block* xls_vast_case_statement_add_item(
struct xls_vast_case_statement* case_stmt,
struct xls_vast_expression* match_expr) {
auto* cpp_case = reinterpret_cast<xls::verilog::Case*>(case_stmt);
auto* cpp_match = reinterpret_cast<xls::verilog::Expression*>(match_expr);
xls::verilog::StatementBlock* block = cpp_case->AddCaseArm(cpp_match);
return reinterpret_cast<xls_vast_statement_block*>(block);
}

struct xls_vast_statement_block* xls_vast_case_statement_add_default(
struct xls_vast_case_statement* case_stmt) {
auto* cpp_case = reinterpret_cast<xls::verilog::Case*>(case_stmt);
xls::verilog::StatementBlock* block =
cpp_case->AddCaseArm(xls::verilog::DefaultSentinel{});
return reinterpret_cast<xls_vast_statement_block*>(block);
}

struct xls_vast_module_port** xls_vast_verilog_module_get_ports(
struct xls_vast_verilog_module* m, size_t* out_count) {
CHECK(out_count != nullptr);
Expand Down
49 changes: 49 additions & 0 deletions xls/public/c_api_vast.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ struct xls_vast_statement_block;
struct xls_vast_module_port;
struct xls_vast_def;
struct xls_vast_parameter_ref;
struct xls_vast_conditional;
struct xls_vast_case_statement;

// Note: We define the enum with a fixed width integer type for clarity of the
// exposed ABI.
Expand Down Expand Up @@ -324,6 +326,12 @@ struct xls_vast_statement* xls_vast_statement_block_add_nonblocking_assignment(
struct xls_vast_statement_block* block, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs);

// Adds a blocking assignment statement (lhs = rhs) to a statement block and
// returns a pointer to the created statement.
struct xls_vast_statement* xls_vast_statement_block_add_blocking_assignment(
struct xls_vast_statement_block* block, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs);

// Emits/formats the contents of the given verilog file to a string.
//
// Note: caller owns the returned string, to be freed by `xls_c_str_free`.
Expand Down Expand Up @@ -370,6 +378,47 @@ struct xls_vast_statement* xls_vast_verilog_file_make_nonblocking_assignment(
struct xls_vast_verilog_file* f, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs);

// Creates a blocking assignment statement (lhs = rhs).
struct xls_vast_statement* xls_vast_verilog_file_make_blocking_assignment(
struct xls_vast_verilog_file* f, struct xls_vast_expression* lhs,
struct xls_vast_expression* rhs);

// Adds a conditional (if) with the given condition to a statement block and
// returns a handle to the created conditional.
struct xls_vast_conditional* xls_vast_statement_block_add_conditional(
struct xls_vast_statement_block* block, struct xls_vast_expression* cond);

// Returns the 'then' statement block of the given conditional.
struct xls_vast_statement_block* xls_vast_conditional_get_then_block(
struct xls_vast_conditional* cond);

// Adds an else-if clause to the given conditional with the provided
// condition and returns the associated statement block.
struct xls_vast_statement_block* xls_vast_conditional_add_else_if(
struct xls_vast_conditional* cond, struct xls_vast_expression* expr_cond);

// Adds an else clause (no condition) to the given conditional and returns the
// associated statement block. Must be called at most once.
struct xls_vast_statement_block* xls_vast_conditional_add_else(
struct xls_vast_conditional* cond);

// Adds a case statement with the given selector to a statement block and
// returns a handle to the created case statement.
struct xls_vast_case_statement* xls_vast_statement_block_add_case(
struct xls_vast_statement_block* block,
struct xls_vast_expression* selector);

// Adds a case item with the given match expression to the case statement and
// returns the associated statement block for that item.
struct xls_vast_statement_block* xls_vast_case_statement_add_item(
struct xls_vast_case_statement* case_stmt,
struct xls_vast_expression* match_expr);

// Adds a default case item to the case statement and returns the associated
// statement block. Must be called at most once.
struct xls_vast_statement_block* xls_vast_case_statement_add_default(
struct xls_vast_case_statement* case_stmt);

} // extern "C"

#endif // XLS_PUBLIC_C_API_VAST_H_
180 changes: 180 additions & 0 deletions xls/public/c_api_vast_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1163,3 +1163,183 @@ TEST(XlsCApiTest, VastDataTypeAccessors) {
absl::Cleanup free_name([&] { xls_c_str_free(def_name); });
EXPECT_EQ(std::string_view{def_name}, "arr");
}

TEST(XlsCApiTest, VastProceduralControlAndBlocking) {
const std::string_view kWantEmitted = R"XLS(module pc_block(
input wire clk,
input wire pred1,
input wire pred2,
input wire sel,
input wire a_in,
input wire b_in
);
reg a;
reg b;
always @ (posedge clk) begin
a = b;
if (pred1) begin
a = 1;
end else if (pred1 & pred2) begin
a = 0;
end else begin
a = b;
end
case (sel)
1: begin
a = b;
end
default: begin
a = 0;
end
endcase
b <= a_in;
end
endmodule
)XLS";

xls_vast_verilog_file* f =
xls_vast_make_verilog_file(xls_vast_file_type_verilog);
ASSERT_NE(f, nullptr);
absl::Cleanup free_file([&] { xls_vast_verilog_file_free(f); });

xls_vast_verilog_module* m = xls_vast_verilog_file_add_module(f, "pc_block");
ASSERT_NE(m, nullptr);

xls_vast_data_type* scalar = xls_vast_verilog_file_make_scalar_type(f);
ASSERT_NE(scalar, nullptr);

xls_vast_logic_ref* clk = xls_vast_verilog_module_add_input(m, "clk", scalar);
xls_vast_logic_ref* pred1 =
xls_vast_verilog_module_add_input(m, "pred1", scalar);
xls_vast_logic_ref* pred2 =
xls_vast_verilog_module_add_input(m, "pred2", scalar);
xls_vast_logic_ref* sel = xls_vast_verilog_module_add_input(m, "sel", scalar);
xls_vast_logic_ref* a_in =
xls_vast_verilog_module_add_input(m, "a_in", scalar);
xls_vast_logic_ref* b_in =
xls_vast_verilog_module_add_input(m, "b_in", scalar);
ASSERT_NE(clk, nullptr);
ASSERT_NE(pred1, nullptr);
ASSERT_NE(pred2, nullptr);
ASSERT_NE(sel, nullptr);
ASSERT_NE(a_in, nullptr);
ASSERT_NE(b_in, nullptr);

xls_vast_logic_ref* a_reg = nullptr;
char* error_out = nullptr;
ASSERT_TRUE(
xls_vast_verilog_module_add_reg(m, "a", scalar, &a_reg, &error_out));
ASSERT_EQ(error_out, nullptr);
ASSERT_NE(a_reg, nullptr);
xls_vast_logic_ref* b_reg = nullptr;
ASSERT_TRUE(
xls_vast_verilog_module_add_reg(m, "b", scalar, &b_reg, &error_out));
ASSERT_EQ(error_out, nullptr);
ASSERT_NE(b_reg, nullptr);

xls_vast_expression* clk_expr = xls_vast_logic_ref_as_expression(clk);
xls_vast_expression* pos_clk =
xls_vast_verilog_file_make_pos_edge(f, clk_expr);
xls_vast_expression* sens_list[] = {pos_clk};
xls_vast_always_base* always_block = nullptr;
ASSERT_TRUE(xls_vast_verilog_module_add_always_at(m, sens_list, 1,
&always_block, &error_out));
ASSERT_EQ(error_out, nullptr);
ASSERT_NE(always_block, nullptr);

xls_vast_statement_block* block =
xls_vast_always_base_get_statement_block(always_block);
ASSERT_NE(block, nullptr);

// blocking: a = b;
xls_vast_expression* a_expr = xls_vast_logic_ref_as_expression(a_reg);
xls_vast_expression* b_expr = xls_vast_logic_ref_as_expression(b_reg);
ASSERT_NE(a_expr, nullptr);
ASSERT_NE(b_expr, nullptr);
ASSERT_NE(
xls_vast_statement_block_add_blocking_assignment(block, a_expr, b_expr),
nullptr);

// if (pred1) { a = 1; } else if (pred1 & pred2) { a = 0; } else { a = b; }
xls_vast_conditional* cond = xls_vast_statement_block_add_conditional(
block, xls_vast_logic_ref_as_expression(pred1));
ASSERT_NE(cond, nullptr);
xls_vast_statement_block* then_block =
xls_vast_conditional_get_then_block(cond);
ASSERT_NE(then_block, nullptr);
xls_vast_statement* then_assign =
xls_vast_statement_block_add_blocking_assignment(
then_block, a_expr,
xls_vast_literal_as_expression(
xls_vast_verilog_file_make_plain_literal(f, 1)));
ASSERT_NE(then_assign, nullptr);

xls_vast_expression* and_expr = xls_vast_verilog_file_make_binary(
f, xls_vast_logic_ref_as_expression(pred1),
xls_vast_logic_ref_as_expression(pred2),
xls_vast_operator_kind_bitwise_and);
xls_vast_statement_block* elseif_block =
xls_vast_conditional_add_else_if(cond, and_expr);
ASSERT_NE(elseif_block, nullptr);
ASSERT_NE(xls_vast_statement_block_add_blocking_assignment(
elseif_block, a_expr,
xls_vast_literal_as_expression(
xls_vast_verilog_file_make_plain_literal(f, 0))),
nullptr);

xls_vast_statement_block* else_block = xls_vast_conditional_add_else(cond);
ASSERT_NE(else_block, nullptr);
ASSERT_NE(xls_vast_statement_block_add_blocking_assignment(else_block, a_expr,
b_expr),
nullptr);

// case (sel) 1: a = b; default: a = 0; endcase
xls_vast_case_statement* case_stmt = xls_vast_statement_block_add_case(
block, xls_vast_logic_ref_as_expression(sel));
ASSERT_NE(case_stmt, nullptr);
xls_vast_statement_block* item_block = xls_vast_case_statement_add_item(
case_stmt, xls_vast_literal_as_expression(
xls_vast_verilog_file_make_plain_literal(f, 1)));
ASSERT_NE(item_block, nullptr);
ASSERT_NE(xls_vast_statement_block_add_blocking_assignment(item_block, a_expr,
b_expr),
nullptr);
xls_vast_statement_block* default_block =
xls_vast_case_statement_add_default(case_stmt);
ASSERT_NE(default_block, nullptr);
ASSERT_NE(xls_vast_statement_block_add_blocking_assignment(
default_block, a_expr,
xls_vast_literal_as_expression(
xls_vast_verilog_file_make_plain_literal(f, 0))),
nullptr);

// nonblocking: b <= a_in;
ASSERT_NE(xls_vast_statement_block_add_nonblocking_assignment(
block, xls_vast_logic_ref_as_expression(b_reg),
xls_vast_logic_ref_as_expression(a_in)),
nullptr);

char* emitted = xls_vast_verilog_file_emit(f);
ASSERT_NE(emitted, nullptr);
absl::Cleanup free_emitted([&] { xls_c_str_free(emitted); });
EXPECT_EQ(std::string_view{emitted}, kWantEmitted);
}

// Covers the file-level factory path for blocking assignments.
// The grouped procedural test exercises only the block-level adder.
// Context/rationale: parity with the existing nonblocking factory; supports
// prebuild-and-pass of a Statement* for APIs that may accept statements; and
// validates allocation/identity when creating a statement owned by the file
// before insertion. This path is not exercised elsewhere.
TEST(XlsCApiTest, VastMakeBlockingAssignmentFactorySmoke) {
xls_vast_verilog_file* f =
xls_vast_make_verilog_file(xls_vast_file_type_verilog);
ASSERT_NE(f, nullptr);
absl::Cleanup free_file([&] { xls_vast_verilog_file_free(f); });

xls_vast_literal* lit0 = xls_vast_verilog_file_make_plain_literal(f, 0);
xls_vast_statement* stmt = xls_vast_verilog_file_make_blocking_assignment(
f, xls_vast_literal_as_expression(lit0),
xls_vast_literal_as_expression(lit0));
ASSERT_NE(stmt, nullptr);
}
Loading