diff --git a/xls/public/c_api.cc b/xls/public/c_api.cc index dcb2f70224..8f404b1763 100644 --- a/xls/public/c_api.cc +++ b/xls/public/c_api.cc @@ -75,6 +75,9 @@ bool ReturnStringHelper(absl::StatusOr& to_return, return false; } +// Converts a C-API-given format preference value into the XLS internal enum -- +// since these values can be out of normal enum class range when passed to the +// API, we validate here. bool FormatPreferenceFromC(xls_format_preference c_pref, xls::FormatPreference* cpp_pref, char** error_out) { switch (c_pref) { @@ -187,6 +190,25 @@ bool xls_parse_typed_value(const char* input, char** error_out, return false; } +bool xls_value_get_bits(const struct xls_value* value, char** error_out, + struct xls_bits** bits_out) { + CHECK(value != nullptr); + CHECK(error_out != nullptr); + CHECK(bits_out != nullptr); + + const auto* cpp_value = reinterpret_cast(value); + absl::StatusOr bits_or = cpp_value->GetBitsWithStatus(); + if (bits_or.ok()) { + xls::Bits* heap_bits = new xls::Bits(std::move(bits_or).value()); + *bits_out = reinterpret_cast(heap_bits); + return true; + } + + *bits_out = nullptr; + *error_out = ToOwnedCString(bits_or.status().ToString()); + return false; +} + struct xls_value* xls_value_make_token() { auto* value = new xls::Value(xls::Value::Token()); return reinterpret_cast(value); @@ -202,6 +224,8 @@ struct xls_value* xls_value_make_false() { return reinterpret_cast(value); } +void xls_bits_free(xls_bits* b) { delete reinterpret_cast(b); } + void xls_value_free(xls_value* v) { delete reinterpret_cast(v); } @@ -540,6 +564,24 @@ struct xls_vast_literal* xls_vast_verilog_file_make_plain_literal( return reinterpret_cast(cpp_literal); } +bool xls_vast_verilog_file_make_literal(struct xls_vast_verilog_file* f, + struct xls_bits* bits, + xls_format_preference format_preference, + bool emit_bit_count, char** error_out, + struct xls_vast_literal** literal_out) { + auto* cpp_file = reinterpret_cast(f); + auto* cpp_bits = reinterpret_cast(bits); + xls::FormatPreference cpp_pref; + if (!FormatPreferenceFromC(format_preference, &cpp_pref, error_out)) { + return false; + } + xls::verilog::Literal* cpp_literal = cpp_file->Make( + xls::SourceInfo(), *cpp_bits, cpp_pref, emit_bit_count); + *error_out = nullptr; + *literal_out = reinterpret_cast(cpp_literal); + return true; +} + struct xls_vast_continuous_assignment* xls_vast_verilog_file_make_continuous_assignment( struct xls_vast_verilog_file* f, struct xls_vast_expression* lhs, diff --git a/xls/public/c_api.h b/xls/public/c_api.h index 7512d62f6a..28d4346add 100644 --- a/xls/public/c_api.h +++ b/xls/public/c_api.h @@ -75,6 +75,14 @@ struct xls_value* xls_value_make_token(); // Returns a new `bits[1]:1` XLS value which the caller must free. struct xls_value* xls_value_make_true(); +// Attempts to extract a "bits" value from the given XLS value -- the resulting +// `bits_out` is owned by the caller and must be freed via `xls_bits_free()` on +// success. +bool xls_value_get_bits(const struct xls_value* value, char** error_out, + struct xls_bits** bits_out); + +void xls_bits_free(struct xls_bits* bits); + // Returns a new `bits[1]:0` XLS value which the caller must free. struct xls_value* xls_value_make_false(); @@ -269,6 +277,15 @@ struct xls_vast_slice* xls_vast_verilog_file_make_slice_i64( struct xls_vast_literal* xls_vast_verilog_file_make_plain_literal( struct xls_vast_verilog_file* f, int32_t value); +// Creates a VAST literal with an arbitrary bit count. +// +// Returns an error if the given format preference is invalid. +bool xls_vast_verilog_file_make_literal(struct xls_vast_verilog_file* f, + struct xls_bits* bits, + xls_format_preference format_preference, + bool emit_bit_count, char** error_out, + struct xls_vast_literal** literal_out); + // Casts to turn the given node to an expression, where possible. struct xls_vast_expression* xls_vast_literal_as_expression( struct xls_vast_literal* v); diff --git a/xls/public/c_api_test.cc b/xls/public/c_api_test.cc index 6067f9a012..cc8b34b6b5 100644 --- a/xls/public/c_api_test.cc +++ b/xls/public/c_api_test.cc @@ -426,4 +426,61 @@ endmodule EXPECT_EQ(std::string_view{emitted}, kWant); } +// Tests that we can assign a 128-bit output wire using a 128-bit literal +// value. +TEST(XlsCApiTest, ContinuousAssignmentOf128BitLiteral) { + 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, "my_module"); + ASSERT_NE(m, nullptr); + + xls_vast_data_type* u128 = + xls_vast_verilog_file_make_bit_vector_type(f, 128, false); + xls_vast_logic_ref* output_ref = + xls_vast_verilog_module_add_output(m, "my_output", u128); + + char* error_out = nullptr; + struct xls_value* value = nullptr; + ASSERT_TRUE(xls_parse_typed_value( + "bits[128]:" + "0b1001001000110100010101100111100010010000101010111100110111101111000100" + "1000110100010101100111100010010000101010111100110111101111", + &error_out, &value)); + ASSERT_EQ(error_out, nullptr); + absl::Cleanup free_value([value] { xls_value_free(value); }); + + struct xls_bits* bits = nullptr; + ASSERT_TRUE(xls_value_get_bits(value, &error_out, &bits)); + ASSERT_EQ(error_out, nullptr); + absl::Cleanup free_bits([bits] { xls_bits_free(bits); }); + + xls_vast_literal* literal_128b = nullptr; + ASSERT_TRUE(xls_vast_verilog_file_make_literal( + f, bits, xls_format_preference_binary, /*emit_bit_count=*/true, + &error_out, &literal_128b)); + ASSERT_EQ(error_out, nullptr); + ASSERT_NE(literal_128b, nullptr); + + xls_vast_continuous_assignment* assignment = + xls_vast_verilog_file_make_continuous_assignment( + f, xls_vast_logic_ref_as_expression(output_ref), + xls_vast_literal_as_expression(literal_128b)); + + xls_vast_verilog_module_add_member_continuous_assignment(m, assignment); + + char* emitted = xls_vast_verilog_file_emit(f); + ASSERT_NE(emitted, nullptr); + absl::Cleanup free_emitted([&] { xls_c_str_free(emitted); }); + const std::string_view kWant = R"(module my_module( + output wire [127:0] my_output +); + assign my_output = 128'b1001_0010_0011_0100_0101_0110_0111_1000_1001_0000_1010_1011_1100_1101_1110_1111_0001_0010_0011_0100_0101_0110_0111_1000_1001_0000_1010_1011_1100_1101_1110_1111; +endmodule +)"; + EXPECT_EQ(std::string_view{emitted}, kWant); +} + } // namespace