Skip to content

Commit

Permalink
Merge pull request #521 from antmicro/wsip/duplicated_ranges
Browse files Browse the repository at this point in the history
duplicated ranges
  • Loading branch information
Mariusz Glebocki authored Aug 19, 2023
2 parents f8daf6d + ef52253 commit 17519a6
Showing 1 changed file with 49 additions and 44 deletions.
93 changes: 49 additions & 44 deletions systemverilog-plugin/UhdmAst.cc
Original file line number Diff line number Diff line change
Expand Up @@ -309,51 +309,58 @@ static void add_multirange_wire(AST::AstNode *node, std::vector<AST::AstNode *>
}
}

static size_t add_multirange_attribute(AST::AstNode *wire_node, const std::vector<AST::AstNode *> ranges)
// Sets the `wire_node->multirange_dimensions` attribute and returns the total sizes of packed and unpacked ranges.
static std::pair<size_t, size_t> set_multirange_dimensions(AST::AstNode *wire_node, const std::vector<AST::AstNode *> packed_ranges,
const std::vector<AST::AstNode *> unpacked_ranges)
{
// node->multirange_dimensions stores dimensions' offsets and widths.
// It shall have even number of elements.
// For a range of [A:B] it should be appended with {min(A,B)} and {max(A,B)-min(A,B)+1}
// For a range of [A] it should be appended with {0} and {A}

size_t size = 1;
for (size_t i = 0; i < ranges.size(); i++) {
log_assert(AST_INTERNAL::current_ast_mod);
if (ranges[i]->children.size() == 1) {
ranges[i]->children.push_back(ranges[i]->children[0]->clone());
}
simplify_sv(ranges[i], wire_node);
while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
}
// this workaround case, where yosys doesn't follow id2ast and simplifies it to resolve constant
if (ranges[i]->children[0]->id2ast) {
simplify_sv(ranges[i]->children[0]->id2ast, ranges[i]->children[0]);
while (simplify(ranges[i]->children[0]->id2ast, true, false, false, 1, -1, false, false)) {
auto calc_range_size = [wire_node](const std::vector<AST::AstNode *> &ranges) -> size_t {
size_t size = 1;
for (size_t i = 0; i < ranges.size(); i++) {
log_assert(AST_INTERNAL::current_ast_mod);
simplify_sv(ranges[i], wire_node);
// If it's a range of [A], make it [A:A].
if (ranges[i]->children.size() == 1) {
ranges[i]->children.push_back(ranges[i]->children[0]->clone());
}
}
if (ranges[i]->children[1]->id2ast) {
simplify_sv(ranges[i]->children[1]->id2ast, ranges[i]->children[1]);
while (simplify(ranges[i]->children[1]->id2ast, true, false, false, 1, -1, false, false)) {
while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
}
}
simplify_sv(ranges[i], wire_node);
while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
}
log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
log_assert(ranges[i]->children[1]->type == AST::AST_CONSTANT);
// this workaround case, where yosys doesn't follow id2ast and simplifies it to resolve constant
if (ranges[i]->children[0]->id2ast) {
simplify_sv(ranges[i]->children[0]->id2ast, ranges[i]->children[0]);
while (simplify(ranges[i]->children[0]->id2ast, true, false, false, 1, -1, false, false)) {
}
}
if (ranges[i]->children[1]->id2ast) {
simplify_sv(ranges[i]->children[1]->id2ast, ranges[i]->children[1]);
while (simplify(ranges[i]->children[1]->id2ast, true, false, false, 1, -1, false, false)) {
}
}
simplify_sv(ranges[i], wire_node);
while (simplify(ranges[i], true, false, false, 1, -1, false, false)) {
}
log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
log_assert(ranges[i]->children[1]->type == AST::AST_CONSTANT);

const auto low = min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
const auto high = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
const auto elem_size = high - low + 1;
const auto low = min(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
const auto high = max(ranges[i]->children[0]->integer, ranges[i]->children[1]->integer);
const auto elem_size = high - low + 1;

wire_node->multirange_dimensions.push_back(low);
wire_node->multirange_dimensions.push_back(elem_size);
wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
size *= elem_size;
}
wire_node->multirange_dimensions.push_back(low);
wire_node->multirange_dimensions.push_back(elem_size);
wire_node->multirange_swapped.push_back(ranges[i]->range_swapped);
size *= elem_size;
}
return size;
};
size_t packed_size = calc_range_size(packed_ranges);
size_t unpacked_size = calc_range_size(unpacked_ranges);
log_assert(wire_node->multirange_dimensions.size() % 2 == 0);

return size;
return {packed_size, unpacked_size};
}

static AST::AstNode *convert_range(AST::AstNode *id, int packed_ranges_size, int unpacked_ranges_size, int i)
Expand Down Expand Up @@ -669,8 +676,7 @@ static void convert_packed_unpacked_range(AST::AstNode *wire_node)
if (convert_node) {
// if not already converted
if (wire_node->multirange_dimensions.empty()) {
const size_t packed_size = add_multirange_attribute(wire_node, packed_ranges);
const size_t unpacked_size = add_multirange_attribute(wire_node, unpacked_ranges);
const auto [packed_size, unpacked_size] = set_multirange_dimensions(wire_node, packed_ranges, unpacked_ranges);
if (packed_ranges.size() == 1 && unpacked_ranges.empty()) {
ranges.push_back(packed_ranges[0]->clone());
} else if (unpacked_ranges.size() == 1 && packed_ranges.empty()) {
Expand Down Expand Up @@ -4762,28 +4768,27 @@ void UhdmAst::process_port()
void UhdmAst::process_net()
{
current_node = make_ast_node(AST::AST_WIRE);
std::vector<AST::AstNode *> packed_ranges; // comes before wire name
std::vector<AST::AstNode *> unpacked_ranges; // comes after wire name
auto net_type = vpi_get(vpiNetType, obj_h);
current_node->is_reg = net_type == vpiReg;
current_node->is_output = net_type == vpiOutput;
current_node->is_logic = !current_node->is_reg;
current_node->is_signed = vpi_get(vpiSigned, obj_h);
visit_one_to_one({vpiTypespec}, obj_h, [&](AST::AstNode *node) {
if (node && !node->str.empty()) {
if (!node)
return;
if (!node->str.empty()) {
auto wiretype_node = new AST::AstNode(AST::AST_WIRETYPE);
wiretype_node->str = node->str;
// wiretype needs to be 1st node
current_node->children.insert(current_node->children.begin(), wiretype_node);
current_node->is_custom_type = true;
} else {
// Ranges from the typespec are copied to the current node as attributes.
// So that multiranges can be replaced with a single range as a node later.
copy_packed_unpacked_attribute(node, current_node);
}
delete node;
});
if (vpiHandle typespec_h = vpi_handle(vpiTypespec, obj_h)) {
visit_one_to_many({vpiRange}, typespec_h, [&](AST::AstNode *node) { packed_ranges.push_back(node); });
vpi_release_handle(typespec_h);
}
add_multirange_wire(current_node, packed_ranges, unpacked_ranges);
}

void UhdmAst::process_parameter()
Expand Down

0 comments on commit 17519a6

Please sign in to comment.