mirror of https://github.com/YosysHQ/yosys.git
Fix access to whole sub-structs (#3086)
* Add support for accessing whole struct * Update tests Signed-off-by: Kamil Rakoczy <krakoczy@antmicro.com>
This commit is contained in:
parent
59738c09be
commit
68c67c40ec
|
@ -11,6 +11,9 @@ Yosys 0.14 .. Yosys 0.14-dev
|
||||||
- Fixed elaboration of dynamic range assignments where the vector is
|
- Fixed elaboration of dynamic range assignments where the vector is
|
||||||
reversed or is not zero-indexed
|
reversed or is not zero-indexed
|
||||||
|
|
||||||
|
* SystemVerilog
|
||||||
|
- Added support for accessing whole sub-structures in expressions
|
||||||
|
|
||||||
Yosys 0.13 .. Yosys 0.14
|
Yosys 0.13 .. Yosys 0.14
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
|
|
|
@ -877,7 +877,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
||||||
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
|
||||||
if (children.size() > 1)
|
if (children.size() > 1)
|
||||||
range = children[1];
|
range = children[1];
|
||||||
} else if (id_ast->type == AST_STRUCT_ITEM) {
|
} else if (id_ast->type == AST_STRUCT_ITEM || id_ast->type == AST_STRUCT) {
|
||||||
AstNode *tmp_range = make_struct_member_range(this, id_ast);
|
AstNode *tmp_range = make_struct_member_range(this, id_ast);
|
||||||
this_width = tmp_range->range_left - tmp_range->range_right + 1;
|
this_width = tmp_range->range_left - tmp_range->range_right + 1;
|
||||||
delete tmp_range;
|
delete tmp_range;
|
||||||
|
|
|
@ -307,6 +307,10 @@ static int size_packed_struct(AstNode *snode, int base_offset)
|
||||||
if (node->type == AST_STRUCT || node->type == AST_UNION) {
|
if (node->type == AST_STRUCT || node->type == AST_UNION) {
|
||||||
// embedded struct or union
|
// embedded struct or union
|
||||||
width = size_packed_struct(node, base_offset + offset);
|
width = size_packed_struct(node, base_offset + offset);
|
||||||
|
// set range of struct
|
||||||
|
node->range_right = base_offset + offset;
|
||||||
|
node->range_left = base_offset + offset + width - 1;
|
||||||
|
node->range_valid = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log_assert(node->type == AST_STRUCT_ITEM);
|
log_assert(node->type == AST_STRUCT_ITEM);
|
||||||
|
@ -493,14 +497,12 @@ static void add_members_to_scope(AstNode *snode, std::string name)
|
||||||
// in case later referenced in assignments
|
// in case later referenced in assignments
|
||||||
log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION);
|
log_assert(snode->type==AST_STRUCT || snode->type==AST_UNION);
|
||||||
for (auto *node : snode->children) {
|
for (auto *node : snode->children) {
|
||||||
|
auto member_name = name + "." + node->str;
|
||||||
|
current_scope[member_name] = node;
|
||||||
if (node->type != AST_STRUCT_ITEM) {
|
if (node->type != AST_STRUCT_ITEM) {
|
||||||
// embedded struct or union
|
// embedded struct or union
|
||||||
add_members_to_scope(node, name + "." + node->str);
|
add_members_to_scope(node, name + "." + node->str);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
auto member_name = name + "." + node->str;
|
|
||||||
current_scope[member_name] = node;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1341,6 +1343,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
|
|
||||||
case AST_PARAMETER:
|
case AST_PARAMETER:
|
||||||
case AST_LOCALPARAM:
|
case AST_LOCALPARAM:
|
||||||
|
// if parameter is implicit type which is the typename of a struct or union,
|
||||||
|
// save information about struct in wiretype attribute
|
||||||
|
if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) {
|
||||||
|
auto item_node = current_scope[children[0]->str];
|
||||||
|
if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) {
|
||||||
|
attributes[ID::wiretype] = item_node->clone();
|
||||||
|
size_packed_struct(attributes[ID::wiretype], 0);
|
||||||
|
add_members_to_scope(attributes[ID::wiretype], str);
|
||||||
|
}
|
||||||
|
}
|
||||||
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true)
|
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true)
|
||||||
did_something = true;
|
did_something = true;
|
||||||
children[0]->detectSignWidth(width_hint, sign_hint);
|
children[0]->detectSignWidth(width_hint, sign_hint);
|
||||||
|
@ -2018,7 +2030,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
if (name_has_dot(str, sname)) {
|
if (name_has_dot(str, sname)) {
|
||||||
if (current_scope.count(str) > 0) {
|
if (current_scope.count(str) > 0) {
|
||||||
auto item_node = current_scope[str];
|
auto item_node = current_scope[str];
|
||||||
if (item_node->type == AST_STRUCT_ITEM) {
|
if (item_node->type == AST_STRUCT_ITEM || item_node->type == AST_STRUCT) {
|
||||||
// structure member, rewrite this node to reference the packed struct wire
|
// structure member, rewrite this node to reference the packed struct wire
|
||||||
auto range = make_struct_member_range(this, item_node);
|
auto range = make_struct_member_range(this, item_node);
|
||||||
newNode = new AstNode(AST_IDENTIFIER, range);
|
newNode = new AstNode(AST_IDENTIFIER, range);
|
||||||
|
|
|
@ -41,8 +41,7 @@ always_comb begin
|
||||||
assert(j == 1'b1);
|
assert(j == 1'b1);
|
||||||
assert(k == 1'b0);
|
assert(k == 1'b0);
|
||||||
assert(l == 3'b111);
|
assert(l == 3'b111);
|
||||||
// TODO: support access to whole sub-structs and unions
|
assert(m == 2'b10);
|
||||||
// assert(m == 2'b10);
|
|
||||||
assert(u == 5'b11001);
|
assert(u == 5'b11001);
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
module dut();
|
||||||
|
typedef struct packed {
|
||||||
|
logic a;
|
||||||
|
logic b;
|
||||||
|
} sub_sub_struct_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
sub_sub_struct_t c;
|
||||||
|
} sub_struct_t;
|
||||||
|
|
||||||
|
typedef struct packed {
|
||||||
|
sub_struct_t d;
|
||||||
|
sub_struct_t e;
|
||||||
|
} struct_t;
|
||||||
|
|
||||||
|
parameter struct_t P = 4'b1100;
|
||||||
|
|
||||||
|
localparam sub_struct_t f = P.d;
|
||||||
|
localparam sub_struct_t g = P.e;
|
||||||
|
localparam sub_sub_struct_t h = f.c;
|
||||||
|
localparam logic i = P.d.c.a;
|
||||||
|
localparam logic j = P.d.c.b;
|
||||||
|
localparam x = P.e;
|
||||||
|
localparam y = x.c;
|
||||||
|
localparam z = y.a;
|
||||||
|
localparam q = P.d;
|
||||||
|
localparam n = q.c.a;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
assert(P == 4'b1100);
|
||||||
|
assert(f == 2'b11);
|
||||||
|
assert(g == 2'b00);
|
||||||
|
assert(h == 2'b11);
|
||||||
|
assert(i == 1'b1);
|
||||||
|
assert(j == 1'b1);
|
||||||
|
assert(x == 2'b00);
|
||||||
|
assert(y == 2'b00);
|
||||||
|
assert(x.c == 2'b00);
|
||||||
|
assert(y.b == 1'b0);
|
||||||
|
assert(n == 1'b1);
|
||||||
|
assert(z == 1'b0);
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,5 @@
|
||||||
|
read_verilog -sv struct_access.sv
|
||||||
|
hierarchy
|
||||||
|
proc
|
||||||
|
opt
|
||||||
|
sat -verify -seq 1 -prove-asserts -show-all
|
|
@ -77,9 +77,8 @@ module top;
|
||||||
`CHECK(s.y.a, 1, 0)
|
`CHECK(s.y.a, 1, 0)
|
||||||
`CHECK(s.y.b, 1, 1)
|
`CHECK(s.y.b, 1, 1)
|
||||||
|
|
||||||
// TODO(zachjs): support access to whole sub-structs and unions
|
`CHECK(s.x, 2, 0)
|
||||||
// `CHECK(s.x, 2, 0)
|
`CHECK(s.y, 2, 1)
|
||||||
// `CHECK(s.y, 2, 1)
|
|
||||||
|
|
||||||
assert (fail === 0);
|
assert (fail === 0);
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue