mirror of https://github.com/YosysHQ/yosys.git
Resolve multiple dimensions defined in stages with typedef
This commit is contained in:
parent
e0d3977e19
commit
03f35c3def
|
@ -554,6 +554,22 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de
|
||||||
return wnode;
|
return wnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void prepend_ranges(AstNode *&range, AstNode *range_add)
|
||||||
|
{
|
||||||
|
// Convert range to multirange.
|
||||||
|
if (range->type == AST_RANGE)
|
||||||
|
range = new AstNode(AST_MULTIRANGE, range);
|
||||||
|
|
||||||
|
// Add range or ranges.
|
||||||
|
if (range_add->type == AST_RANGE)
|
||||||
|
range->children.insert(range->children.begin(), range_add->clone());
|
||||||
|
else {
|
||||||
|
int i = 0;
|
||||||
|
for (auto child : range_add->children)
|
||||||
|
range->children.insert(range->children.begin() + i++, child->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check if a node or its children contains an assignment to the given variable
|
// check if a node or its children contains an assignment to the given variable
|
||||||
static bool node_contains_assignment_to(const AstNode* node, const AstNode* var)
|
static bool node_contains_assignment_to(const AstNode* node, const AstNode* var)
|
||||||
{
|
{
|
||||||
|
@ -1879,8 +1895,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
log_assert(resolved_type_node->children.size() == 1);
|
log_assert(resolved_type_node->children.size() == 1);
|
||||||
AstNode *template_node = resolved_type_node->children[0];
|
AstNode *template_node = resolved_type_node->children[0];
|
||||||
|
|
||||||
// Ensure typedef itself is fully simplified
|
// Resolve the typedef from the bottom up, recursing within the current
|
||||||
while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {};
|
// block of code. Defer further simplification until the complete type is
|
||||||
|
// resolved.
|
||||||
|
while (template_node->is_custom_type && template_node->simplify(const_fold, stage, width_hint, sign_hint)) {};
|
||||||
|
|
||||||
if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) {
|
if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) {
|
||||||
// replace instance with wire representing the packed structure
|
// replace instance with wire representing the packed structure
|
||||||
|
@ -1893,90 +1911,68 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
|
||||||
goto apply_newNode;
|
goto apply_newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove type reference
|
// Prepare replacement node.
|
||||||
delete children[0];
|
newNode = template_node->clone();
|
||||||
children.erase(children.begin());
|
newNode->str = str;
|
||||||
|
newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
||||||
if (type == AST_WIRE)
|
newNode->is_input = is_input;
|
||||||
type = template_node->type;
|
newNode->is_output = is_output;
|
||||||
is_reg = template_node->is_reg;
|
newNode->is_wand = is_wand;
|
||||||
is_logic = template_node->is_logic;
|
newNode->is_wor = is_wor;
|
||||||
is_signed = template_node->is_signed;
|
for (auto &pair : attributes)
|
||||||
is_string = template_node->is_string;
|
newNode->set_attribute(pair.first, pair.second->clone());
|
||||||
is_custom_type = template_node->is_custom_type;
|
|
||||||
|
|
||||||
range_valid = template_node->range_valid;
|
|
||||||
range_swapped = template_node->range_swapped;
|
|
||||||
range_left = template_node->range_left;
|
|
||||||
range_right = template_node->range_right;
|
|
||||||
|
|
||||||
set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
|
||||||
|
|
||||||
// if an enum then add attributes to support simulator tracing
|
// if an enum then add attributes to support simulator tracing
|
||||||
annotateTypedEnums(template_node);
|
newNode->annotateTypedEnums(template_node);
|
||||||
|
|
||||||
// Insert clones children from template at beginning
|
bool add_packed_dimensions = (type == AST_WIRE && GetSize(children) > 1) || (type == AST_MEMORY && GetSize(children) > 2);
|
||||||
for (int i = 0; i < GetSize(template_node->children); i++)
|
|
||||||
children.insert(children.begin() + i, template_node->children[i]->clone());
|
|
||||||
|
|
||||||
if (type == AST_MEMORY && GetSize(children) == 1) {
|
// Cannot add packed dimensions if unpacked dimensions are already specified.
|
||||||
// Single-bit memories must have [0:0] range
|
if (add_packed_dimensions && newNode->type == AST_MEMORY)
|
||||||
AstNode *rng = make_range(0, 0);
|
input_error("Cannot extend unpacked type `%s' with packed dimensions\n", type_name.c_str());
|
||||||
children.insert(children.begin(), rng);
|
|
||||||
|
// Add packed dimensions.
|
||||||
|
if (add_packed_dimensions) {
|
||||||
|
AstNode *packed = children[1];
|
||||||
|
if (newNode->children.empty())
|
||||||
|
newNode->children.insert(newNode->children.begin(), packed->clone());
|
||||||
|
else
|
||||||
|
prepend_ranges(newNode->children[0], packed);
|
||||||
}
|
}
|
||||||
fixup_hierarchy_flags();
|
|
||||||
did_something = true;
|
// Add unpacked dimensions.
|
||||||
|
if (type == AST_MEMORY) {
|
||||||
|
AstNode *unpacked = children.back();
|
||||||
|
if (GetSize(newNode->children) < 2)
|
||||||
|
newNode->children.push_back(unpacked->clone());
|
||||||
|
else
|
||||||
|
prepend_ranges(newNode->children[1], unpacked);
|
||||||
|
newNode->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare to generate dimensions metadata for the resolved type.
|
||||||
|
newNode->dimensions.clear();
|
||||||
|
newNode->unpacked_dimensions = 0;
|
||||||
|
|
||||||
|
goto apply_newNode;
|
||||||
}
|
}
|
||||||
log_assert(!is_custom_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve types of parameters
|
// resolve types of parameters
|
||||||
if (type == AST_LOCALPARAM || type == AST_PARAMETER) {
|
if (type == AST_LOCALPARAM || type == AST_PARAMETER) {
|
||||||
if (is_custom_type) {
|
if (is_custom_type) {
|
||||||
log_assert(children.size() == 2);
|
log_assert(children.size() >= 2);
|
||||||
log_assert(children[1]->type == AST_WIRETYPE);
|
log_assert(children[1]->type == AST_WIRETYPE);
|
||||||
auto type_name = children[1]->str;
|
// Pretend it's a wire in order to resolve the type in the code block above.
|
||||||
if (!current_scope.count(type_name)) {
|
AstNodeType param_type = type;
|
||||||
input_error("Unknown identifier `%s' used as type name\n", type_name.c_str());
|
type = AST_WIRE;
|
||||||
}
|
AstNode *expr = children[0];
|
||||||
AstNode *resolved_type_node = current_scope.at(type_name);
|
children.erase(children.begin());
|
||||||
if (resolved_type_node->type != AST_TYPEDEF)
|
while (simplify(const_fold, stage, width_hint, sign_hint)) {};
|
||||||
input_error("`%s' does not name a type\n", type_name.c_str());
|
type = param_type;
|
||||||
log_assert(resolved_type_node->children.size() == 1);
|
children.insert(children.begin(), expr);
|
||||||
AstNode *template_node = resolved_type_node->children[0];
|
if (children[1]->type == AST_MEMORY)
|
||||||
|
|
||||||
// Ensure typedef itself is fully simplified
|
|
||||||
while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {};
|
|
||||||
|
|
||||||
if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
|
|
||||||
// replace with wire representing the packed structure
|
|
||||||
newNode = make_packed_struct(template_node, str, attributes);
|
|
||||||
newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
|
||||||
newNode->type = type;
|
|
||||||
current_scope[str] = this;
|
|
||||||
// copy param value, it needs to be 1st value
|
|
||||||
delete children[1];
|
|
||||||
children.pop_back();
|
|
||||||
newNode->children.insert(newNode->children.begin(), children[0]->clone());
|
|
||||||
goto apply_newNode;
|
|
||||||
}
|
|
||||||
delete children[1];
|
|
||||||
children.pop_back();
|
|
||||||
|
|
||||||
if (template_node->type == AST_MEMORY)
|
|
||||||
input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());
|
input_error("unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());
|
||||||
is_signed = template_node->is_signed;
|
|
||||||
is_string = template_node->is_string;
|
|
||||||
is_custom_type = template_node->is_custom_type;
|
|
||||||
|
|
||||||
range_valid = template_node->range_valid;
|
|
||||||
range_swapped = template_node->range_swapped;
|
|
||||||
range_left = template_node->range_left;
|
|
||||||
range_right = template_node->range_right;
|
|
||||||
|
|
||||||
set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str));
|
|
||||||
for (auto template_child : template_node->children)
|
|
||||||
children.push_back(template_child->clone());
|
|
||||||
fixup_hierarchy_flags();
|
fixup_hierarchy_flags();
|
||||||
did_something = true;
|
did_something = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2122,7 +2122,7 @@ typedef_decl:
|
||||||
astbuf1->children.push_back(astbuf2);
|
astbuf1->children.push_back(astbuf2);
|
||||||
|
|
||||||
if ($5 != NULL) {
|
if ($5 != NULL) {
|
||||||
if (!astbuf2) {
|
if (!astbuf2 && !astbuf1->is_custom_type) {
|
||||||
addRange(astbuf1, 0, 0, false);
|
addRange(astbuf1, 0, 0, false);
|
||||||
}
|
}
|
||||||
rewriteAsMemoryNode(astbuf1, $5);
|
rewriteAsMemoryNode(astbuf1, $5);
|
||||||
|
|
Loading…
Reference in New Issue