Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for packed multidimensional arrays #4100

Merged
merged 9 commits into from
Feb 11, 2024
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,13 @@ from SystemVerilog:
- enums are supported (including inside packages)
- but are currently not strongly typed

- packed structs and unions are supported.
- packed structs and unions are supported
- arrays of packed structs/unions are currently not supported
- structure literals are currently not supported

- multidimensional arrays are supported
- array assignment of unpacked arrays is currently not supported
- array literals are currently not supported

- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
ports are inputs or outputs are supported.
Expand Down
48 changes: 36 additions & 12 deletions frontends/ast/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
port_id = 0;
range_left = -1;
range_right = 0;
unpacked_dimensions = 0;
integer = 0;
realvalue = 0;
id2ast = NULL;
Expand Down Expand Up @@ -349,17 +350,15 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
fprintf(f, " int=%u", (int)integer);
if (realvalue != 0)
fprintf(f, " real=%e", realvalue);
if (!multirange_dimensions.empty()) {
fprintf(f, " multirange=[");
for (int v : multirange_dimensions)
fprintf(f, " %d", v);
fprintf(f, " ]");
}
if (!multirange_swapped.empty()) {
fprintf(f, " multirange_swapped=[");
for (bool v : multirange_swapped)
fprintf(f, " %d", v);
fprintf(f, " ]");
if (!dimensions.empty()) {
fprintf(f, " dimensions=");
for (auto &dim : dimensions) {
int left = dim.range_right + dim.range_width - 1;
int right = dim.range_right;
if (dim.range_swapped)
std::swap(left, right);
fprintf(f, "[%d:%d]", left, right);
}
}
if (is_enum) {
fprintf(f, " type=enum");
Expand Down Expand Up @@ -489,6 +488,20 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
fprintf(f, ";\n");
break;

if (0) { case AST_MEMRD: txt = "@memrd@"; }
if (0) { case AST_MEMINIT: txt = "@meminit@"; }
if (0) { case AST_MEMWR: txt = "@memwr@"; }
fprintf(f, "%s%s", indent.c_str(), txt.c_str());
for (auto child : children) {
fprintf(f, first ? "(" : ", ");
child->dumpVlog(f, "");
first = false;
}
fprintf(f, ")");
if (type != AST_MEMRD)
fprintf(f, ";\n");
break;

case AST_RANGE:
if (range_valid) {
if (range_swapped)
Expand All @@ -505,6 +518,11 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
}
break;

case AST_MULTIRANGE:
for (auto child : children)
child->dumpVlog(f, "");
break;

case AST_ALWAYS:
fprintf(f, "%s" "always @", indent.c_str());
for (auto child : children) {
Expand Down Expand Up @@ -542,7 +560,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const

case AST_IDENTIFIER:
{
AST::AstNode *member_node = AST::get_struct_member(this);
AstNode *member_node = get_struct_member();
if (member_node)
fprintf(f, "%s[%d:%d]", id2vl(str).c_str(), member_node->range_left, member_node->range_right);
else
Expand All @@ -552,6 +570,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
child->dumpVlog(f, "");
break;

case AST_STRUCT:
case AST_UNION:
case AST_STRUCT_ITEM:
fprintf(f, "%s", id2vl(str).c_str());
break;

case AST_CONSTANT:
if (!str.empty())
fprintf(f, "\"%s\"", str.c_str());
Expand Down
22 changes: 15 additions & 7 deletions frontends/ast/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,17 @@ namespace AST
// set for IDs typed to an enumeration, not used
bool is_enum;

// if this is a multirange memory then this vector contains offset and length of each dimension
std::vector<int> multirange_dimensions;
std::vector<bool> multirange_swapped; // true if range is swapped
// Declared range for array dimension.
struct dimension_t {
int range_right; // lsb in [msb:lsb]
int range_width; // msb - lsb + 1
bool range_swapped; // if the declared msb < lsb, msb and lsb above are swapped
};
// Packed and unpacked dimensions for arrays.
// Unpacked dimensions go first, to follow the order of indexing.
std::vector<dimension_t> dimensions;
// Number of unpacked dimensions.
int unpacked_dimensions;

// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
Expand Down Expand Up @@ -371,6 +379,10 @@ namespace AST
// localized fixups after modifying children/attributes of a particular node
void fixup_hierarchy_flags(bool force_descend = false);

// helpers for indexing
AstNode *make_index_range(AstNode *node, bool unpacked_range = false);
AstNode *get_struct_member() const;

// helper to print errors from simplify/genrtlil code
[[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3));
};
Expand Down Expand Up @@ -416,10 +428,6 @@ namespace AST
// Helper for setting the src attribute.
void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);

// struct helper exposed from simplify for genrtlil
AstNode *make_struct_member_range(AstNode *node, AstNode *member_node);
AstNode *get_struct_member(const AstNode *node);

// generate standard $paramod... derived module name; parameters should be
// in the order they are declared in the instantiated module
std::string derived_module_name(std::string stripped_name, const std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> &parameters);
Expand Down
4 changes: 2 additions & 2 deletions frontends/ast/genrtlil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (children.size() > 1)
range = children[1];
} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT || id_ast->type == AST_UNION) {
AstNode *tmp_range = make_struct_member_range(this, id_ast);
AstNode *tmp_range = make_index_range(id_ast);
this_width = tmp_range->range_left - tmp_range->range_right + 1;
delete tmp_range;
} else
Expand Down Expand Up @@ -1521,7 +1521,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.width = wire->width;
chunk.offset = 0;

if ((member_node = get_struct_member(this))) {
if ((member_node = get_struct_member())) {
// Clamp wire chunk to range of member within struct/union.
chunk.width = member_node->range_left - member_node->range_right + 1;
chunk.offset = member_node->range_right;
Expand Down
Loading