Merge pull request #478 from antmicro/kr/unlock_surelog
systemverilog-plugin: unlock surelog version
diff --git a/systemverilog-plugin/UhdmAst.cc b/systemverilog-plugin/UhdmAst.cc
index a3484d6..7bc62bf 100644
--- a/systemverilog-plugin/UhdmAst.cc
+++ b/systemverilog-plugin/UhdmAst.cc
@@ -137,6 +137,8 @@
node->children.clear();
}
+static void simplify(AST::AstNode *current_node, AST::AstNode *parent_node);
+
static void sanitize_symbol_name(std::string &name)
{
if (!name.empty()) {
@@ -274,17 +276,21 @@
if (ranges[i]->children.size() == 1) {
ranges[i]->children.push_back(ranges[i]->children[0]->clone());
}
+ simplify(ranges[i], wire_node);
while (ranges[i]->simplify(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(ranges[i]->children[0]->id2ast, ranges[i]->children[0]);
while (ranges[i]->children[0]->id2ast->simplify(true, false, false, 1, -1, false, false)) {
}
}
if (ranges[i]->children[1]->id2ast) {
+ simplify(ranges[i]->children[1]->id2ast, ranges[i]->children[1]);
while (ranges[i]->children[1]->id2ast->simplify(true, false, false, 1, -1, false, false)) {
}
}
+ simplify(ranges[i], wire_node);
while (ranges[i]->simplify(true, false, false, 1, -1, false, false)) {
}
log_assert(ranges[i]->children[0]->type == AST::AST_CONSTANT);
@@ -407,7 +413,9 @@
// needs to have access to all already defined ids
while (wire_node->simplify(true, false, false, 1, -1, false, false)) {
}
- if (wiretype_ast->children[0]->type == AST::AST_STRUCT && wire_node->type == AST::AST_WIRE) {
+ log_assert(!wiretype_ast->children.empty());
+ if ((wiretype_ast->children[0]->type == AST::AST_STRUCT || wiretype_ast->children[0]->type == AST::AST_UNION) &&
+ wire_node->type == AST::AST_WIRE) {
auto struct_width = get_max_offset_struct(wiretype_ast->children[0]);
wire_node->range_left = struct_width;
wire_node->children[0]->range_left = struct_width;
@@ -670,26 +678,6 @@
}
current_struct_elem = *struct_elem_it;
- AST::AstNode *left = nullptr, *right = nullptr;
- if (current_struct_elem->type == AST::AST_STRUCT_ITEM) {
- left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true);
- right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true);
- } else if (current_struct_elem->type == AST::AST_STRUCT) {
- // Struct can have multiple range, so to get size of 1 struct,
- // we get left range for first children, and right range for last children
- left = AST::AstNode::mkconst_int(current_struct_elem->children.front()->range_left, true);
- right = AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right, true);
- } else if (current_struct_elem->type == AST::AST_UNION) {
- left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true);
- right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true);
- } else {
- // Structs currently can only have AST_STRUCT, AST_STRUCT_ITEM, or AST_UNION.
- log_file_error(current_struct_elem->filename, current_struct_elem->location.first_line,
- "Accessing struct member of type %s is unsupported.\n", type2str(current_struct_elem->type).c_str());
- }
-
- auto elem_size =
- new AST::AstNode(AST::AST_ADD, new AST::AstNode(AST::AST_SUB, left->clone(), right->clone()), AST::AstNode::mkconst_int(1, true));
AST::AstNode *sub_dot = nullptr;
AST::AstNode *struct_range = nullptr;
@@ -701,10 +689,46 @@
}
if (c->type == AST::AST_RANGE) {
// Currently supporting only 1 range
- log_assert(!struct_range);
+ if (struct_range) {
+ log_file_error(struct_range->filename, struct_range->location.first_line,
+ "Currently support for dot-access is limited to single range\n");
+ }
struct_range = c;
}
}
+ AST::AstNode *left = nullptr, *right = nullptr;
+ switch (current_struct_elem->type) {
+ case AST::AST_STRUCT_ITEM:
+ left = AST::AstNode::mkconst_int(current_struct_elem->range_left, true);
+ right = AST::AstNode::mkconst_int(current_struct_elem->range_right, true);
+ break;
+ case AST::AST_STRUCT:
+ case AST::AST_UNION:
+ // TODO(krak): add proper support for accessing struct/union elements
+ // with multirange
+ // Currently support only special access to 2 dimensional packed element
+ // when selecting single range
+ log_assert(current_struct_elem->multirange_dimensions.size() % 2 == 0);
+ if (struct_range && (current_struct_elem->multirange_dimensions.size() / 2) == 2) {
+ // get element size in number of bits
+ const int single_elem_size = current_struct_elem->children.front()->range_left + 1;
+ left = AST::AstNode::mkconst_int(single_elem_size * current_struct_elem->multirange_dimensions.back(), true);
+ right =
+ AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right * current_struct_elem->multirange_dimensions.back(), true);
+ } else {
+ left = AST::AstNode::mkconst_int(current_struct_elem->children.front()->range_left, true);
+ right = AST::AstNode::mkconst_int(current_struct_elem->children.back()->range_right, true);
+ }
+ break;
+ default:
+ // Structs currently can only have AST_STRUCT, AST_STRUCT_ITEM, or AST_UNION.
+ log_file_error(current_struct_elem->filename, current_struct_elem->location.first_line,
+ "Accessing struct member of type %s is unsupported.\n", type2str(current_struct_elem->type).c_str());
+ };
+
+ auto elem_size =
+ new AST::AstNode(AST::AST_ADD, new AST::AstNode(AST::AST_SUB, left->clone(), right->clone()), AST::AstNode::mkconst_int(1, true));
+
if (sub_dot) {
// First select correct element in first struct
std::swap(left, sub_dot->children[0]);
@@ -882,10 +906,6 @@
std::vector<AST::AstNode *> ranges(it, snode->children.end());
snode->children.erase(it, snode->children.end());
if (!ranges.empty()) {
- if (ranges.size() > 1) {
- log_file_error(ranges[1]->filename, ranges[1]->location.first_line,
- "Currently support for custom-type with range is limited to single range\n");
- }
for (auto range : ranges) {
snode->multirange_dimensions.push_back(min(range->range_left, range->range_right));
snode->multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
@@ -901,9 +921,11 @@
// embedded struct or union
width = simplify_struct(node, base_offset + offset, parent_node);
if (!node->multirange_dimensions.empty()) {
- int number_of_structs = 1;
- number_of_structs = node->multirange_dimensions.back();
- width *= number_of_structs;
+ // Multiply widths of all dimensions.
+ // `multirange_dimensions` stores (repeating) pairs of [offset, width].
+ for (size_t i = 1; i < node->multirange_dimensions.size(); i += 2) {
+ width *= node->multirange_dimensions[i];
+ }
}
// set range of struct
node->range_right = base_offset + offset;
@@ -1901,7 +1923,31 @@
});
}
// first apply custom simplification step if needed
- simplify(parameter, nullptr);
+ simplify(parameter, module_node);
+ // workaround for yosys sometimes not simplifying parameters children
+ // parameters can have 2 children:
+ // first child should be parameter value
+ // second child should be parameter range (optional)
+ log_assert(!parameter->children.empty());
+ simplify(parameter->children[0], parameter);
+ while (parameter->children[0]->simplify(true, false, false, 1, -1, false, false)) {
+ }
+ // follow id2ast as yosys doesn't do it by default
+ if (parameter->children[0]->id2ast) {
+ simplify(parameter->children[0]->id2ast, parameter);
+ while (parameter->children[0]->id2ast->simplify(true, false, false, 1, -1, false, false)) {
+ }
+ }
+ if (parameter->children.size() > 1) {
+ simplify(parameter->children[1], parameter);
+ while (parameter->children[1]->simplify(true, false, false, 1, -1, false, false)) {
+ }
+ if (parameter->children[1]->id2ast) {
+ simplify(parameter->children[1]->id2ast, parameter);
+ while (parameter->children[1]->id2ast->simplify(true, false, false, 1, -1, false, false)) {
+ }
+ }
+ }
// then simplify parameter to AST_CONSTANT or AST_REALVALUE
while (parameter->simplify(true, false, false, 1, -1, false, false)) {
}